simplify defended territory rendering logic

Replace epoch-based defended texture tracking with hard-clear approach for
improved reliability and performance. Remove complex dirty state tracking
and epoch incrementing logic in favor of direct hard clears before rebuilds.

Changes:
- Remove wasDefensePostsDirty tracking from TerritoryRenderer
- Replace numUpdates > 0 checks with hasStateUpdates boolean
- Hard-clear defended texture before restamping instead of epoch management
- Mark DefendedUpdatePass as dirty when rebuilding defended state
- Rebuild bind group in DefendedUpdatePass when missing, not just on buffer change

This eliminates potential transient mismatches where defended rendering
disappeared between rebuilds and simplifies the update pipeline.
This commit is contained in:
scamiv
2026-05-26 20:17:52 +02:00
parent 44ffa96b64
commit 655bb211e1
2 changed files with 13 additions and 18 deletions
+12 -17
View File
@@ -316,18 +316,16 @@ export class TerritoryRenderer {
// Upload palette if needed // Upload palette if needed
this.resources.uploadPalette(); this.resources.uploadPalette();
// Upload defense posts if needed (tracks if it was dirty before upload) // Upload defense posts if needed
const wasDefensePostsDirty = (this.resources as any)
.needsDefensePostsUpload;
this.resources.uploadDefensePosts(); this.resources.uploadDefensePosts();
// Initial state upload // Initial state upload
this.resources.uploadState(); this.resources.uploadState();
// Check if we need to run compute passes // Check if we need to run compute passes
const numUpdates = this.stateUpdatePass const hasStateUpdates = this.stateUpdatePass
? ((this.stateUpdatePass as any).pendingTiles?.size ?? 0) ? this.stateUpdatePass.needsUpdate()
: 0; : false;
const needsTerrainCompute = this.terrainComputePass const needsTerrainCompute = this.terrainComputePass
? this.terrainComputePass.needsUpdate() ? this.terrainComputePass.needsUpdate()
: false; : false;
@@ -341,14 +339,13 @@ export class TerritoryRenderer {
// Use explicit boolean checks to satisfy linter (|| is correct for boolean OR) // Use explicit boolean checks to satisfy linter (|| is correct for boolean OR)
const shouldRebuildDefended = const shouldRebuildDefended =
this.needsDefendedRebuild === true || this.needsDefendedRebuild === true ||
wasDefensePostsDirty === true ||
rangeChanged === true || rangeChanged === true ||
countChanged === true || countChanged === true ||
(hasPosts && numUpdates > 0); (hasPosts && hasStateUpdates === true);
const needsCompute = const needsCompute =
needsTerrainCompute === true || needsTerrainCompute === true ||
numUpdates > 0 || hasStateUpdates === true ||
shouldRebuildDefended === true || shouldRebuildDefended === true ||
this.needsDefendedHardClear === true; this.needsDefendedHardClear === true;
@@ -366,15 +363,13 @@ export class TerritoryRenderer {
// Handle defended rebuild (before executing passes) // Handle defended rebuild (before executing passes)
if (shouldRebuildDefended) { if (shouldRebuildDefended) {
// Increment epoch for this rebuild // Hard-clear defended texture before restamping. This avoids relying on
const epochBefore = this.resources.getDefendedEpoch(); // epoch-stamping for correctness and prevents transient mismatches where
this.resources.incrementDefendedEpoch(); // defended rendering disappears between rebuilds.
const epochAfter = this.resources.getDefendedEpoch(); this.needsDefendedHardClear = true;
// If epoch wrapped, we need a hard clear if (this.defendedUpdatePass) {
if (epochAfter === 0 || epochAfter < epochBefore) { this.defendedUpdatePass.markDirty();
this.needsDefendedHardClear = true;
this.resources.incrementDefendedEpoch();
} }
this.needsDefendedRebuild = false; this.needsDefendedRebuild = false;
@@ -87,7 +87,7 @@ export class DefendedUpdatePass implements ComputePass {
const oldBuffer = this.resources?.defensePostsBuffer; const oldBuffer = this.resources?.defensePostsBuffer;
const bufferChanged = oldBuffer !== resources.defensePostsBuffer; const bufferChanged = oldBuffer !== resources.defensePostsBuffer;
if (bufferChanged) { if (bufferChanged || !this.bindGroup) {
this.rebuildBindGroup(); this.rebuildBindGroup();
} }