mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-23 07:40:14 +00:00
Fix city stuttering with incremental tile finalization and GPU optimizations
Replace monolithic finalizeTile() with a phased state machine that spreads GPU upload work across multiple frames (TERRAIN→M2→WMO→WATER→AMBIENT→DONE). Each advanceFinalization() call does one bounded unit of work within the per-frame time budget, eliminating 50-300ms frame hitches when entering cities. Additional performance improvements: - Pre-allocate bone SSBOs at M2 instance creation instead of lazily during first render frame, preventing hitches when many skinned characters appear - Enable WMO distance culling (800 units) with active-group exemption so the player's current floor/neighbors are never culled - Add 4-tier adaptive M2 render distance (250/400/600/1000 based on count) - Remove dead PendingM2Upload queue code superseded by incremental system Fix tile re-enqueueing bug: keep tiles in pendingTiles until committed to loadedTiles (not when moved to finalizingTiles_) so streamTiles() doesn't re-enqueue tiles mid-finalization. Also handle unloadTile() for tiles in the finalizingTiles_ deque to prevent orphaned water/M2/WMO resources.
This commit is contained in:
parent
8fe53171eb
commit
d47ae2a110
6 changed files with 411 additions and 268 deletions
|
|
@ -1319,6 +1319,9 @@ 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];
|
||||
|
|
@ -1329,6 +1332,9 @@ 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<uint32_t> portalVisibleGroups;
|
||||
bool usePortalCulling = doPortalCull && !model.portals.empty() && !model.portalRefs.empty();
|
||||
|
|
@ -1349,11 +1355,24 @@ void WMORenderer::render(VkCommandBuffer cmd, VkDescriptorSet perFrameSet, const
|
|||
const auto& [gMin, gMax] = instance.worldGroupBounds[gi];
|
||||
|
||||
if (doDistanceCull) {
|
||||
glm::vec3 closestPoint = glm::clamp(camPos, gMin, gMax);
|
||||
float distSq = glm::dot(closestPoint - camPos, closestPoint - camPos);
|
||||
if (distSq > 250000.0f) {
|
||||
result.distanceCulled++;
|
||||
continue;
|
||||
// Never cull the group the player is standing in or its portal neighbors
|
||||
bool isExempt = false;
|
||||
if (isActiveInstance) {
|
||||
if (static_cast<int32_t>(gi) == activeGroupCopy.groupIdx) {
|
||||
isExempt = true;
|
||||
} else {
|
||||
for (uint32_t ng : activeGroupCopy.neighborGroups) {
|
||||
if (ng == static_cast<uint32_t>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue