From 7ca9caa212ae51925d7d7a7bba51ccc0a0bee0eb Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 25 Feb 2026 03:06:06 -0800 Subject: [PATCH] Fix Windows ARM64 build: disable x86 asm in StormLib's libtomcrypt StormLib's bundled libtomcrypt uses x86 inline assembly (bswapl/movl) gated by __MINGW32__, which is defined on CLANGARM64 too. Pass -DLTC_NO_BSWAP to force portable C byte-swap fallback. --- .github/workflows/build.yml | 6 ++- .github/workflows/release.yml | 6 ++- include/rendering/m2_renderer.hpp | 1 - include/rendering/wmo_renderer.hpp | 6 +-- src/rendering/m2_renderer.cpp | 67 ++++-------------------------- src/rendering/wmo_renderer.cpp | 29 +++---------- 6 files changed, 26 insertions(+), 89 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 29a13e11..b903a442 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -195,10 +195,14 @@ jobs: shell: msys2 {0} run: | git clone --depth 1 https://github.com/ladislav-zezula/StormLib.git /tmp/StormLib + # Disable x86 inline asm in bundled libtomcrypt (bswapl/movl) — + # __MINGW32__ is defined on CLANGARM64 which incorrectly enables x86 asm cmake -S /tmp/StormLib -B /tmp/StormLib/build -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX="$MINGW_PREFIX" \ - -DBUILD_SHARED_LIBS=OFF + -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_C_FLAGS="-DLTC_NO_BSWAP" \ + -DCMAKE_CXX_FLAGS="-DLTC_NO_BSWAP" cmake --build /tmp/StormLib/build --parallel $(nproc) cmake --install /tmp/StormLib/build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 17fa8a17..0357408b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -256,10 +256,14 @@ jobs: shell: msys2 {0} run: | git clone --depth 1 https://github.com/ladislav-zezula/StormLib.git /tmp/StormLib + # Disable x86 inline asm in bundled libtomcrypt (bswapl/movl) — + # __MINGW32__ is defined on CLANGARM64 which incorrectly enables x86 asm cmake -S /tmp/StormLib -B /tmp/StormLib/build -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX="$MINGW_PREFIX" \ - -DBUILD_SHARED_LIBS=OFF + -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_C_FLAGS="-DLTC_NO_BSWAP" \ + -DCMAKE_CXX_FLAGS="-DLTC_NO_BSWAP" cmake --build /tmp/StormLib/build --parallel $(nproc) cmake --install /tmp/StormLib/build diff --git a/include/rendering/m2_renderer.hpp b/include/rendering/m2_renderer.hpp index 08be4d2b..c2a663b5 100644 --- a/include/rendering/m2_renderer.hpp +++ b/include/rendering/m2_renderer.hpp @@ -478,7 +478,6 @@ private: // Helper to allocate descriptor sets VkDescriptorSet allocateMaterialSet(); VkDescriptorSet allocateBoneSet(); - void preallocateBoneBuffers(M2Instance& instance); // Helper to destroy model GPU resources void destroyModelGPU(M2ModelGPU& model); diff --git a/include/rendering/wmo_renderer.hpp b/include/rendering/wmo_renderer.hpp index 701e74a4..9d4a62a6 100644 --- a/include/rendering/wmo_renderer.hpp +++ b/include/rendering/wmo_renderer.hpp @@ -657,9 +657,9 @@ private: bool wireframeMode = false; bool frustumCulling = true; bool portalCulling = false; // Disabled by default - needs debugging - bool distanceCulling = true; // Enabled with active-group exemption to prevent floor disappearing - float maxGroupDistance = 800.0f; - float maxGroupDistanceSq = 640000.0f; // maxGroupDistance^2 + bool distanceCulling = false; // Disabled - causes ground to disappear + float maxGroupDistance = 500.0f; + float maxGroupDistanceSq = 250000.0f; // maxGroupDistance^2 uint32_t lastDrawCalls = 0; mutable uint32_t lastPortalCulledGroups = 0; mutable uint32_t lastDistanceCulledGroups = 0; diff --git a/src/rendering/m2_renderer.cpp b/src/rendering/m2_renderer.cpp index 9a2e9705..378a7b41 100644 --- a/src/rendering/m2_renderer.cpp +++ b/src/rendering/m2_renderer.cpp @@ -767,38 +767,6 @@ VkDescriptorSet M2Renderer::allocateBoneSet() { return set; } -void M2Renderer::preallocateBoneBuffers(M2Instance& instance) { - if (!vkCtx_) return; - for (int fi = 0; fi < 2; fi++) { - if (instance.boneBuffer[fi]) continue; // already allocated - VkBufferCreateInfo bci{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; - bci.size = 128 * sizeof(glm::mat4); // max 128 bones - bci.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - VmaAllocationCreateInfo aci{}; - aci.usage = VMA_MEMORY_USAGE_CPU_TO_GPU; - aci.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT; - VmaAllocationInfo allocInfo{}; - vmaCreateBuffer(vkCtx_->getAllocator(), &bci, &aci, - &instance.boneBuffer[fi], &instance.boneAlloc[fi], &allocInfo); - instance.boneMapped[fi] = allocInfo.pMappedData; - - instance.boneSet[fi] = allocateBoneSet(); - if (instance.boneSet[fi]) { - VkDescriptorBufferInfo bufInfo{}; - bufInfo.buffer = instance.boneBuffer[fi]; - bufInfo.offset = 0; - bufInfo.range = bci.size; - VkWriteDescriptorSet write{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET}; - write.dstSet = instance.boneSet[fi]; - write.dstBinding = 0; - write.descriptorCount = 1; - write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - write.pBufferInfo = &bufInfo; - vkUpdateDescriptorSets(vkCtx_->getDevice(), 1, &write, 0, nullptr); - } - } -} - // --------------------------------------------------------------------------- // M2 collision mesh: build spatial grid + classify triangles // --------------------------------------------------------------------------- @@ -1647,11 +1615,6 @@ uint32_t M2Renderer::createInstance(uint32_t modelId, const glm::vec3& position, instance.variationTimer = 3000.0f + static_cast(rand() % 8000); } - // Pre-allocate bone SSBOs so first render frame doesn't hitch - if (mdlRef.hasAnimation && !mdlRef.disableAnimation) { - preallocateBoneBuffers(instance); - } - instances.push_back(instance); size_t idx = instances.size() - 1; instanceIndexById[instance.id] = idx; @@ -1685,8 +1648,6 @@ uint32_t M2Renderer::createInstanceWithMatrix(uint32_t modelId, const glm::mat4& } } - const auto& mdlRef = models[modelId]; - M2Instance instance; instance.id = nextInstanceId++; instance.modelId = modelId; @@ -1696,24 +1657,20 @@ uint32_t M2Renderer::createInstanceWithMatrix(uint32_t modelId, const glm::mat4& instance.modelMatrix = modelMatrix; instance.invModelMatrix = glm::inverse(modelMatrix); glm::vec3 localMin, localMax; - getTightCollisionBounds(mdlRef, localMin, localMax); + getTightCollisionBounds(models[modelId], localMin, localMax); transformAABB(instance.modelMatrix, localMin, localMax, instance.worldBoundsMin, instance.worldBoundsMax); // Initialize animation - if (mdlRef.hasAnimation && !mdlRef.disableAnimation && !mdlRef.sequences.empty()) { + const auto& mdl2 = models[modelId]; + if (mdl2.hasAnimation && !mdl2.disableAnimation && !mdl2.sequences.empty()) { instance.currentSequenceIndex = 0; instance.idleSequenceIndex = 0; - instance.animDuration = static_cast(mdlRef.sequences[0].duration); - instance.animTime = static_cast(rand() % std::max(1u, mdlRef.sequences[0].duration)); + instance.animDuration = static_cast(mdl2.sequences[0].duration); + instance.animTime = static_cast(rand() % std::max(1u, mdl2.sequences[0].duration)); instance.variationTimer = 3000.0f + static_cast(rand() % 8000); } else { instance.animTime = static_cast(rand()) / RAND_MAX * 10000.0f; } - // Pre-allocate bone SSBOs so first render frame doesn't hitch - if (mdlRef.hasAnimation && !mdlRef.disableAnimation) { - preallocateBoneBuffers(instance); - } - instances.push_back(instance); size_t idx = instances.size() - 1; instanceIndexById[instance.id] = idx; @@ -1854,11 +1811,7 @@ void M2Renderer::update(float deltaTime, const glm::vec3& cameraPos, const glm:: // Cache camera state for frustum-culling bone computation cachedCamPos_ = cameraPos; - const size_t animInstCount = instances.size(); - const float maxRenderDistance = (animInstCount > 3000) ? 600.0f - : (animInstCount > 2000) ? 800.0f - : (animInstCount > 1000) ? 1400.0f - : 2800.0f; + const float maxRenderDistance = (instances.size() > 2000) ? 800.0f : 2800.0f; cachedMaxRenderDistSq_ = maxRenderDistance * maxRenderDistance; // Build frustum for culling bones @@ -2128,12 +2081,8 @@ void M2Renderer::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const lastDrawCallCount = 0; - // Adaptive render distance: tiered for performance without excessive pop-in - const size_t instCount = instances.size(); - const float maxRenderDistance = (instCount > 3000) ? 250.0f - : (instCount > 2000) ? 400.0f - : (instCount > 1000) ? 600.0f - : 1000.0f; + // Adaptive render distance: balanced for performance without excessive pop-in + const float maxRenderDistance = (instances.size() > 2000) ? 350.0f : 1000.0f; const float maxRenderDistanceSq = maxRenderDistance * maxRenderDistance; const float fadeStartFraction = 0.75f; const glm::vec3 camPos = camera.getPosition(); diff --git a/src/rendering/wmo_renderer.cpp b/src/rendering/wmo_renderer.cpp index 3b85d94a..40338e11 100644 --- a/src/rendering/wmo_renderer.cpp +++ b/src/rendering/wmo_renderer.cpp @@ -1319,9 +1319,6 @@ void WMORenderer::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const bool doFrustumCull = false; // Temporarily disabled: can over-cull world WMOs bool doDistanceCull = distanceCulling; - // Cache active group info for distance-cull exemption (player's current WMO group) - const auto activeGroupCopy = activeGroup_; - auto cullInstance = [&](size_t instIdx) -> InstanceDrawList { if (instIdx >= instances.size()) return InstanceDrawList{}; const auto& instance = instances[instIdx]; @@ -1332,9 +1329,6 @@ void WMORenderer::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const InstanceDrawList result; result.instanceIndex = instIdx; - // Check if this instance is the one the player is standing in - bool isActiveInstance = activeGroupCopy.isValid() && activeGroupCopy.instanceIdx == instIdx; - // Portal-based visibility std::unordered_set portalVisibleGroups; bool usePortalCulling = doPortalCull && !model.portals.empty() && !model.portalRefs.empty(); @@ -1355,24 +1349,11 @@ void WMORenderer::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const const auto& [gMin, gMax] = instance.worldGroupBounds[gi]; if (doDistanceCull) { - // Never cull the group the player is standing in or its portal neighbors - bool isExempt = false; - if (isActiveInstance) { - if (static_cast(gi) == activeGroupCopy.groupIdx) { - isExempt = true; - } else { - for (uint32_t ng : activeGroupCopy.neighborGroups) { - if (ng == static_cast(gi)) { isExempt = true; break; } - } - } - } - if (!isExempt) { - glm::vec3 closestPoint = glm::clamp(camPos, gMin, gMax); - float distSq = glm::dot(closestPoint - camPos, closestPoint - camPos); - if (distSq > maxGroupDistanceSq) { - result.distanceCulled++; - continue; - } + glm::vec3 closestPoint = glm::clamp(camPos, gMin, gMax); + float distSq = glm::dot(closestPoint - camPos, closestPoint - camPos); + if (distSq > 250000.0f) { + result.distanceCulled++; + continue; } }