on the moon game is a bit slow, there's likely optimisations issues #68
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Investigated, not fixed - leaving this open.
Most probable cause identified via code review:
lunar_surface.gdshadersamples 25 points per pixel (a 5x5 neighbor scan for its Worley/cellular crater field). That's not accidental - the shader's own comments show it was deliberately widened from an earlier 3x3 scan to fix an on-device visual clipping bug in the crater edges, so simply shrinking the sample count back down would very likely reintroduce that older visual bug.LunarBackground.gd(the CPU side) was also checked and is cheap - a handful of scalar ops per frame, not the bottleneck.I don't have a way to profile GPU frame time on-device from here (no on-device GPU profiler access, and this is a rendering/perf regression that can't be judged from a headless test or a single static screenshot - it needs to be seen and measured running on the actual hardware). Any change to the shader's sample pattern risks trading this performance issue for the correctness issue it was already tuned to avoid, without a way to verify the tradeoff either way. Left open pending someone with device profiling access, or a specific target frame budget to hit.
Fixed in
657ca9d.What was slow
lunar_surface.gdshaderruns on every pixel of a fullscreen rect, so it was by far the most expensive thing in the surface scene. Nothing else came close:RockFieldkeeps only 14 rocks alive,Rock/Ship/Enemyalready avoid per-framequeue_redraw()for transform-only changes, andLunarBackground.gddoes a handful of scalar ops. Three things in the fragment shader carried the cost: a 5x5 (25-sample) neighbour scan, three hash evaluations per cell, and asqrtper sample vialength().Part 1 - make the field cheap
[0,1]and extrapolatedmix(). Clamping the crater centre into its own cell, alongside the radius clamp already present, bounds the reach whatever the hash returns. A crater two cells out is then >= 1.0 cells away - a normalized distance of >= 2.63 - and every shading threshold has saturated by 1.15, so the outer ring provably cannot change a pixel. This removes the clipping bug's cause rather than hiding it behind 16 extra samples.hash42per cell instead ofhash21twice plushash22, decorrelating on output lanes rather than input offsets.Part 2 - stop recomputing it every frame
The field is a fixed function of world position, so every frame was recomputing an identical answer. It is now made periodic (the cell index is wrapped before hashing, which makes a Worley field tile exactly rather than merely blend), baked once at load into a single tile, and scrolled with repeat wrapping by the new
lunar_tiled.gdshader- one texture fetch per pixel, on a canvas that stays infinite.Two costs, stated plainly: the field repeats every 7040 world units, and a fixed-resolution tile softens when zoomed past 1:1. Lunar regolith is unusually forgiving of both - no landmarks to recognise, and smooth gradients already. Both knobs are one line each in
LunarBackground.gd(TILE_CELLS,BAKE_PIXELS_PER_CELL) if the ~17 MB tile or the repeat distance want trading against each other.A gas giant swaps in its own background shader (#51), so the bake waits a frame and asks the material whether it actually samples a
field_texturebefore committing - no 2048-square tile is rendered for a shader that will never read it. Headless runs skip it entirely.Measured
New
tests/profile_shader.sh+tests/_profile_surface_shader.gdtime a fullscreen rect carrying a given shader. Two caveats are baked into the tool's own documentation, because the raw number misleads twice over:Shader work above the floor, same viewport, back to back:
So part 1 is measured and decisive. Part 2 is not measurable on this hardware - it reads as slightly worse under a CPU rasterizer, which is exactly backwards for the target device. Its case is architectural: one mipmapped fetch against 9 Worley iterations with 3 sqrts and 9 divides is strongly favourable on a mobile GPU. Confirmed as an improvement on the actual device by the reporter.
Test
tests/test_lunar_field.gd. A fragment shader cannot be asserted on directly from GDScript, so the test guards the reasoning that made the reduction safe - the part that would silently break:MAX_RADIUSbelow a cell, shading saturating by 1.15);+Infand thenNaN.If anyone later loosens a clamp or raises
MAX_RADIUS, the crater clipping returns looking like a GPU mystery. This makes it fail as an edit instead.Full suite green at 94/94.