From 658d4fdfe4a1b2278faa3488e79f3d0f66c492ae Mon Sep 17 00:00:00 2001 From: scamiv <6170744+scamiv@users.noreply.github.com> Date: Sat, 17 Jan 2026 22:49:20 +0100 Subject: [PATCH] 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. --- .../graphics/webgpu/TerritoryRenderer.ts | 29 ++++++++----------- .../webgpu/compute/DefendedUpdatePass.ts | 2 +- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/client/graphics/webgpu/TerritoryRenderer.ts b/src/client/graphics/webgpu/TerritoryRenderer.ts index 12861303c..f5910727c 100644 --- a/src/client/graphics/webgpu/TerritoryRenderer.ts +++ b/src/client/graphics/webgpu/TerritoryRenderer.ts @@ -316,18 +316,16 @@ export class TerritoryRenderer { // Upload palette if needed this.resources.uploadPalette(); - // Upload defense posts if needed (tracks if it was dirty before upload) - const wasDefensePostsDirty = (this.resources as any) - .needsDefensePostsUpload; + // Upload defense posts if needed this.resources.uploadDefensePosts(); // Initial state upload this.resources.uploadState(); // Check if we need to run compute passes - const numUpdates = this.stateUpdatePass - ? ((this.stateUpdatePass as any).pendingTiles?.size ?? 0) - : 0; + const hasStateUpdates = this.stateUpdatePass + ? this.stateUpdatePass.needsUpdate() + : false; const needsTerrainCompute = this.terrainComputePass ? this.terrainComputePass.needsUpdate() : false; @@ -341,14 +339,13 @@ export class TerritoryRenderer { // Use explicit boolean checks to satisfy linter (|| is correct for boolean OR) const shouldRebuildDefended = this.needsDefendedRebuild === true || - wasDefensePostsDirty === true || rangeChanged === true || countChanged === true || - (hasPosts && numUpdates > 0); + (hasPosts && hasStateUpdates === true); const needsCompute = needsTerrainCompute === true || - numUpdates > 0 || + hasStateUpdates === true || shouldRebuildDefended === true || this.needsDefendedHardClear === true; @@ -366,15 +363,13 @@ export class TerritoryRenderer { // Handle defended rebuild (before executing passes) if (shouldRebuildDefended) { - // Increment epoch for this rebuild - const epochBefore = this.resources.getDefendedEpoch(); - this.resources.incrementDefendedEpoch(); - const epochAfter = this.resources.getDefendedEpoch(); + // Hard-clear defended texture before restamping. This avoids relying on + // epoch-stamping for correctness and prevents transient mismatches where + // defended rendering disappears between rebuilds. + this.needsDefendedHardClear = true; - // If epoch wrapped, we need a hard clear - if (epochAfter === 0 || epochAfter < epochBefore) { - this.needsDefendedHardClear = true; - this.resources.incrementDefendedEpoch(); + if (this.defendedUpdatePass) { + this.defendedUpdatePass.markDirty(); } this.needsDefendedRebuild = false; diff --git a/src/client/graphics/webgpu/compute/DefendedUpdatePass.ts b/src/client/graphics/webgpu/compute/DefendedUpdatePass.ts index c68d1358b..abac77c7f 100644 --- a/src/client/graphics/webgpu/compute/DefendedUpdatePass.ts +++ b/src/client/graphics/webgpu/compute/DefendedUpdatePass.ts @@ -87,7 +87,7 @@ export class DefendedUpdatePass implements ComputePass { const oldBuffer = this.resources?.defensePostsBuffer; const bufferChanged = oldBuffer !== resources.defensePostsBuffer; - if (bufferChanged) { + if (bufferChanged || !this.bindGroup) { this.rebuildBindGroup(); }