Skip to content

Cap StructureLayer Maximum Texture Size#3574

Merged
evanpelle merged 4 commits intoopenfrontio:mainfrom
EnderBoy9217:firefox-zoom-fix
Apr 4, 2026
Merged

Cap StructureLayer Maximum Texture Size#3574
evanpelle merged 4 commits intoopenfrontio:mainfrom
EnderBoy9217:firefox-zoom-fix

Conversation

@EnderBoy9217
Copy link
Copy Markdown
Contributor

@EnderBoy9217 EnderBoy9217 commented Apr 3, 2026

Resolves #3569

Description:

While browsers like Firefox will report their maximum texture size of 16384, going over 8192 causes extreme VRAM usage and massive FPS drops, even when no structures are actually being rendered (I experienced ~60ms rendering time on this layer with no structures present).

This PR sets the StructureLayer texture size to cap at 8192, while keeping near-exact scales. The result is increased performance, reduced VRAM Usage, (especially in larger maps), and the resolution of the unplayable performance issues when StructureLayer is present, with zero noticeable degradation.

VRAM Usage also no longer rises when zoomed in (Sitting at around a constant 40MB no matter zoom level, previously it would rise to over 160MB when StructureLayer was present).

All tested on Giant World, where the issues were first spotted, but applies to all maps.

Discord: @EnderBoy9217

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 3, 2026

Walkthrough

Changed StructureLayer.redraw() to compute a GPU-limit-aware canvas backing scale instead of always using 2×. It derives targetScale from a 8192px max-texture heuristic, clamps to ≤2, sets canvas width/height to floor(gameDim * targetScale) (min 1px), and applies context.scale(...) to preserve expected drawing coordinates.

Changes

Cohort / File(s) Summary
Canvas Buffer Scaling
src/client/graphics/layers/StructureLayer.ts
Replaced fixed 2× framebuffer allocation with computed targetScale based on maxTextureSize = 8192. Sets canvas.width/height = floor(gameDim * targetScale) (≥1px) and applies a matching context.scale(...) so drawing code that assumes 2× coordinates remains correct.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A canvas once stretched by twofold might,
Hit GPU walls and cause the night.
Scale now listens to texture bounds,
Context and pixels sing in rounds. 🎨✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly describes the main change: capping the StructureLayer maximum texture size to improve performance.
Description check ✅ Passed The description is directly related to the changeset, explaining the motivation (Firefox VRAM/FPS issues above 8192), the solution (capping at 8192), and the benefits (improved performance and VRAM usage).
Linked Issues check ✅ Passed The PR successfully addresses #3569 by implementing a GPU-limit-aware scaling strategy that caps texture size at 8192, eliminating the extreme stuttering and VRAM growth reported on Firefox.
Out of Scope Changes check ✅ Passed All changes in StructureLayer.ts are directly scoped to addressing the texture size performance issue; no unrelated modifications are present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/client/graphics/layers/StructureLayer.ts`:
- Around line 137-144: After resizing the canvas you must reapply the 2D context
smoothing settings and compute the transform from the actual integer canvas
dimensions (not the pre-truncated fractional bufferScale). Change the resize
logic around bufferScale, this.canvas.width/height and this.context.scale so
that you: compute bufferScale = Math.min(2, maxTextureSize / this.game.width(),
maxTextureSize / this.game.height()), set integerWidth =
Math.round(this.game.width() * bufferScale) and integerHeight =
Math.round(this.game.height() * bufferScale), assign those to
this.canvas.width/height, reapply this.context.imageSmoothingEnabled and
this.context.imageSmoothingQuality, then derive the final scale as actualScaleX
= integerWidth / this.game.width() and actualScaleY = integerHeight /
this.game.height() and call this.context.scale(actualScaleX, actualScaleY) (or
setTransform) instead of using the original fractional bufferScale so the
transform matches the real canvas size and smoothing is preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 29ff6a5e-15aa-4064-a901-253f9839c420

📥 Commits

Reviewing files that changed from the base of the PR and between 4a84ac2 and b30960c.

📒 Files selected for processing (1)
  • src/client/graphics/layers/StructureLayer.ts

@github-project-automation github-project-automation bot moved this from Triage to Development in OpenFront Release Management Apr 3, 2026
@VariableVince
Copy link
Copy Markdown
Contributor

@EnderBoy9217 Hi, if you'd like to join the Dev server on Discord, there's an invite link in the readme here: EnderBoy9217

@EnderBoy9217
Copy link
Copy Markdown
Contributor Author

@EnderBoy9217 Hi, if you'd like to join the Dev server on Discord, there's an invite link in the readme here: EnderBoy9217

Thanks for letting me know!

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 4, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/client/graphics/layers/StructureLayer.ts (1)

134-135: Remove redundant smoothing settings before resize.

These lines set smoothing, but lines 142-149 resize the canvas, which resets all context state. Lines 150-151 already reapply smoothing after the resize. You can safely remove lines 134-135.

♻️ Proposed cleanup
     this.context = context;

-    // Enable smooth scaling
-    this.context.imageSmoothingEnabled = true;
-    this.context.imageSmoothingQuality = "high";
-
     // Firefox's GPU limit is 8192, only known browser issue
     const maxTextureSize = 8192;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/graphics/layers/StructureLayer.ts` around lines 134 - 135, Remove
the redundant pre-resize smoothing settings in StructureLayer: delete the calls
that set this.context.imageSmoothingEnabled and
this.context.imageSmoothingQuality before the canvas resize since the resize
resets the canvas context state and the code already re-applies smoothing after
the resize; keep only the post-resize settings (the later
this.context.imageSmoothingEnabled / this.context.imageSmoothingQuality lines)
to avoid duplicate/unused state changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/client/graphics/layers/StructureLayer.ts`:
- Around line 134-135: Remove the redundant pre-resize smoothing settings in
StructureLayer: delete the calls that set this.context.imageSmoothingEnabled and
this.context.imageSmoothingQuality before the canvas resize since the resize
resets the canvas context state and the code already re-applies smoothing after
the resize; keep only the post-resize settings (the later
this.context.imageSmoothingEnabled / this.context.imageSmoothingQuality lines)
to avoid duplicate/unused state changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 813b6c50-ede7-44cf-835a-762642a49b6a

📥 Commits

Reviewing files that changed from the base of the PR and between b30960c and 4dd8343.

📒 Files selected for processing (1)
  • src/client/graphics/layers/StructureLayer.ts

coderabbitai[bot]
coderabbitai bot previously approved these changes Apr 4, 2026
@github-project-automation github-project-automation bot moved this from Development to Final Review in OpenFront Release Management Apr 4, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/client/graphics/layers/StructureLayer.ts (1)

133-153: Implementation looks correct and addresses the Firefox texture limit issue.

The math checks out:

  • For large maps (e.g., 10000×10000), targetScale clamps to ~0.82, resulting in 8192×8192 canvas
  • The context.scale() correctly compensates so drawing code using * 2 coordinates still maps properly
  • For smaller maps, full 2× backing is preserved (targetScale = 2, scale(1, 1))

Past review concern is now fixed: smoothing settings are applied after the canvas resize (lines 148-149), so they won't be reset.

Minor clarity suggestion: The / (this.game.width() * 2) in the scale calculation might confuse future readers. A brief comment about why * 2 appears everywhere (the drawing code's coordinate system) would help.

♻️ Optional: Add explanatory comment
     // Enable smooth scaling
     this.context.imageSmoothingEnabled = true;
     this.context.imageSmoothingQuality = "high";
+    // Drawing code uses 2x game coordinates (e.g., cell.x * 2).
+    // Scale transform maps those coordinates to actual canvas pixels.
     this.context.scale(
       this.canvas.width / (this.game.width() * 2),
       this.canvas.height / (this.game.height() * 2),
     );

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/client/graphics/layers/StructureLayer.ts` around lines 133 - 153, Add a
short explanatory comment in StructureLayer near the canvas scaling logic
(around the targetScale calculation and this.context.scale call) that clarifies
why a 2× multiplier appears in drawing coordinates and therefore why the scale
uses "/ (this.game.width() * 2)" and "* 2" elsewhere; keep it concise and
mention that the drawing code uses a 2× backing coordinate system so the scale
compensates for that factor, helping future readers understand targetScale,
this.canvas.width/height, and this.context.scale relationships.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/client/graphics/layers/StructureLayer.ts`:
- Around line 133-153: Add a short explanatory comment in StructureLayer near
the canvas scaling logic (around the targetScale calculation and
this.context.scale call) that clarifies why a 2× multiplier appears in drawing
coordinates and therefore why the scale uses "/ (this.game.width() * 2)" and "*
2" elsewhere; keep it concise and mention that the drawing code uses a 2×
backing coordinate system so the scale compensates for that factor, helping
future readers understand targetScale, this.canvas.width/height, and
this.context.scale relationships.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0c3d6077-d873-4d21-8d1c-215637894c2c

📥 Commits

Reviewing files that changed from the base of the PR and between 4dd8343 and 6a72cff.

📒 Files selected for processing (1)
  • src/client/graphics/layers/StructureLayer.ts

@evanpelle evanpelle added this to the v31 milestone Apr 4, 2026
@evanpelle evanpelle merged commit 494b409 into openfrontio:main Apr 4, 2026
6 of 9 checks passed
@github-project-automation github-project-automation bot moved this from Final Review to Complete in OpenFront Release Management Apr 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Complete

Development

Successfully merging this pull request may close these issues.

Extreme Firefox Performance Issue

4 participants