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
|
|
@ -478,6 +478,7 @@ private:
|
|||
// Helper to allocate descriptor sets
|
||||
VkDescriptorSet allocateMaterialSet();
|
||||
VkDescriptorSet allocateBoneSet();
|
||||
void preallocateBoneBuffers(M2Instance& instance);
|
||||
|
||||
// Helper to destroy model GPU resources
|
||||
void destroyModelGPU(M2ModelGPU& model);
|
||||
|
|
|
|||
|
|
@ -123,6 +123,41 @@ struct PendingTile {
|
|||
std::unordered_map<std::string, pipeline::BLPImage> preloadedTextures;
|
||||
};
|
||||
|
||||
/**
|
||||
* Phases for incremental tile finalization (one bounded unit of work per call)
|
||||
*/
|
||||
enum class FinalizationPhase {
|
||||
TERRAIN, // Upload terrain mesh + textures
|
||||
M2_MODELS, // Upload ONE M2 model per call
|
||||
M2_INSTANCES, // Create all M2 instances (lightweight struct allocation)
|
||||
WMO_MODELS, // Upload ONE WMO model per call
|
||||
WMO_INSTANCES, // Create all WMO instances + load WMO liquids
|
||||
WMO_DOODADS, // Upload ONE WMO doodad M2 per call
|
||||
WATER, // Upload water from terrain
|
||||
AMBIENT, // Register ambient emitters
|
||||
DONE // Commit to loadedTiles
|
||||
};
|
||||
|
||||
/**
|
||||
* In-progress tile finalization state — tracks progress across frames
|
||||
*/
|
||||
struct FinalizingTile {
|
||||
std::shared_ptr<PendingTile> pending;
|
||||
FinalizationPhase phase = FinalizationPhase::TERRAIN;
|
||||
|
||||
// Progress indices within current phase
|
||||
size_t m2ModelIndex = 0; // Next M2 model to upload
|
||||
size_t wmoModelIndex = 0; // Next WMO model to upload
|
||||
size_t wmoDoodadIndex = 0; // Next WMO doodad to upload
|
||||
|
||||
// Accumulated results (built up across phases)
|
||||
std::vector<uint32_t> m2InstanceIds;
|
||||
std::vector<uint32_t> wmoInstanceIds;
|
||||
std::vector<uint32_t> tileUniqueIds;
|
||||
std::vector<uint32_t> tileWmoUniqueIds;
|
||||
std::unordered_set<uint32_t> uploadedM2ModelIds;
|
||||
};
|
||||
|
||||
/**
|
||||
* Terrain manager for multi-tile terrain streaming
|
||||
*
|
||||
|
|
@ -219,8 +254,8 @@ public:
|
|||
int getLoadedTileCount() const { return static_cast<int>(loadedTiles.size()); }
|
||||
int getPendingTileCount() const { return static_cast<int>(pendingTiles.size()); }
|
||||
int getReadyQueueCount() const { return static_cast<int>(readyQueue.size()); }
|
||||
/** Total unfinished tiles (worker threads + ready queue) */
|
||||
int getRemainingTileCount() const { return static_cast<int>(pendingTiles.size() + readyQueue.size()); }
|
||||
/** Total unfinished tiles (worker threads + ready queue + finalizing) */
|
||||
int getRemainingTileCount() const { return static_cast<int>(pendingTiles.size() + readyQueue.size() + finalizingTiles_.size()); }
|
||||
TileCoord getCurrentTile() const { return currentTile; }
|
||||
|
||||
/** Process all ready tiles immediately (use during loading screens) */
|
||||
|
|
@ -254,9 +289,10 @@ private:
|
|||
std::shared_ptr<PendingTile> prepareTile(int x, int y);
|
||||
|
||||
/**
|
||||
* Main thread: upload prepared tile data to GPU
|
||||
* Advance incremental finalization of a tile (one bounded unit of work).
|
||||
* Returns true when the tile is fully finalized (phase == DONE).
|
||||
*/
|
||||
void finalizeTile(const std::shared_ptr<PendingTile>& pending);
|
||||
bool advanceFinalization(FinalizingTile& ft);
|
||||
|
||||
/**
|
||||
* Background worker thread loop
|
||||
|
|
@ -341,16 +377,8 @@ private:
|
|||
// Dedup set for WMO placements across tile boundaries (prevents rendering Stormwind 16x)
|
||||
std::unordered_set<uint32_t> placedWmoIds;
|
||||
|
||||
// Progressive M2 upload queue (spread heavy uploads across frames)
|
||||
struct PendingM2Upload {
|
||||
uint32_t modelId;
|
||||
pipeline::M2Model model;
|
||||
std::string path;
|
||||
};
|
||||
std::queue<PendingM2Upload> m2UploadQueue_;
|
||||
static constexpr int MAX_M2_UPLOADS_PER_FRAME = 5; // Upload up to 5 models per frame
|
||||
|
||||
void processM2UploadQueue();
|
||||
// Tiles currently being incrementally finalized across frames
|
||||
std::deque<FinalizingTile> finalizingTiles_;
|
||||
|
||||
struct GroundEffectEntry {
|
||||
std::array<uint32_t, 4> doodadIds{{0, 0, 0, 0}};
|
||||
|
|
|
|||
|
|
@ -657,9 +657,9 @@ private:
|
|||
bool wireframeMode = false;
|
||||
bool frustumCulling = true;
|
||||
bool portalCulling = false; // Disabled by default - needs debugging
|
||||
bool distanceCulling = false; // Disabled - causes ground to disappear
|
||||
float maxGroupDistance = 500.0f;
|
||||
float maxGroupDistanceSq = 250000.0f; // maxGroupDistance^2
|
||||
bool distanceCulling = true; // Enabled with active-group exemption to prevent floor disappearing
|
||||
float maxGroupDistance = 800.0f;
|
||||
float maxGroupDistanceSq = 640000.0f; // maxGroupDistance^2
|
||||
uint32_t lastDrawCalls = 0;
|
||||
mutable uint32_t lastPortalCulledGroups = 0;
|
||||
mutable uint32_t lastDistanceCulledGroups = 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue