fix(scene): tint sub-worldviews and stop paying per ship - #22
Open
dennisdevulder wants to merge 2 commits into
Open
fix(scene): tint sub-worldviews and stop paying per ship#22dennisdevulder wants to merge 2 commits into
dennisdevulder wants to merge 2 commits into
Conversation
Two problems with sub-worldview rendering, both visible while salvaging with other players' ships around. Other players' ships rendered in full detail. The engine puts an HSL override on each sub-worldview's own Scene (Scene.getOverrideHue / Saturation / Luminance / Amount); stock hands those four bytes to its entityTint uniform (GpuPlugin.java:833,1088, VAO.java:123) and lerps in HSL component space in vert.glsl:88, which is what turns another player's ship into a flat silhouette. We never read them. scene.vert now does the same lerp from a packed int, keeping stock's split where textured faces carry the untinted lightness and untextured faces the tinted one, so a tinted ship still shows its textures. The scene push block was already at the 128 bytes maxPushConstantsSize guarantees, so the tint needed room: the vertex stage takes 0..99 and the fragment stage 100..123, with textureLightMode, colorBlindMode, alphaMode and smoothBanding folded into one modes int. The record signature collapses to (cmd, mvp, VulkanFrameContext, SceneEntity) rather than growing an eighteenth parameter. Each sub-worldview also built a whole SceneRenderer: six pipeline compiles, a descriptor pool and set, a 12.5 MB arena and a vkDeviceWaitIdle, all inside the draw callback, every time a ship sailed into view. Pipeline state and descriptor contents never vary per scene, so both move to a device-wide ScenePipelines. The arena is seeded small and grown by the capture loop that already exists, so a rowboat does not pay a galleon's worst case. The drain is skipped until a renderer has recorded a draw, since nothing in flight can reference an arena it has never drawn from. Zone frustum and overlay loops run over the captured extent instead of the top level's 23x23 grid, which for a ship is a few zones rather than 529. Per-scene capture logging drops to debug for sub-worldviews. Assisted-by: Claude Opus 5
The renderer escape hatches (disableSubWorldViews, disableFrustumCull, fullSceneDraw, validation, modelStats) are only reachable by editing build.gradle, because JavaExec does not inherit the gradle JVM's system properties. Forward the vkgpu. prefix so they can be flipped per run. Assisted-by: Claude Opus 5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Other players' ships rendered in full detail where stock shows a flat blue silhouette. That's fixed here. The PR also cuts what a sub-worldview costs to spawn — but see the last section, that is not the fix for the salvage-area FPS complaint that prompted this.
1. The entity tint was never read
The engine puts an HSL override on each sub-worldview's own
Scene:getOverrideHue/Saturation/Luminance/Amount. Stock feeds those four bytes to itsentityTintuniform for every sub-worldview draw, static and dynamic (GpuPlugin.java:833,1088,VAO.java:123), resets it to zero for the top level (:978,1007), and lerps in HSL component space invert.glsl:88. That override is what makes another player's ship a flat silhouette. We never read it, so ships drew at full detail.scene.vertnow does the same lerp from a packed int. Two details ported deliberately from stock:hslToRgb, withamountkept as a signed byte;fHslstays untinted for textured faces (it only drives texture lighting) and tinted for untextured ones, so a tinted ship still shows its textures rather than becoming a solid block of colour.Stock also drops per-face alpha sorting for tinted scenes (
GpuPlugin.java:1101). We sort at capture rather than at draw, so there is no equivalent knob to turn off.Push constant repack
The scene push block was already at 128 bytes, which is what
maxPushConstantsSizeguarantees and what RADV and Intel actually report, so the tint had to make room. Vulkan allows one range per stage, so the split moved:0..95— mat4, fogVtx, misc0..99— mat4, fogVtx, misc,entityTint96..127—fogFragvec4,fragExtrasvec4100..123— fogR/G/B, brightness, colorBlindIntensity,modestextureLightMode,colorBlindMode,alphaModeandsmoothBandingare all small flags and now share onemodesint, replacing the previoussmoothBanding + 10 * alphaModeencoding. Offsets live inScenePipeline.VERT_PUSH_BYTES/FRAG_PUSH_BYTESso the layout has one source of truth.The record signature collapsed from seventeen parameters to
(cmd, mvp, VulkanFrameContext, SceneEntity)instead of growing an eighteenth.SceneEntitycarries the per-scene state — placement and tint — withTOP_LEVELas the identity.2. Sub-worldview spawn cost
SubWorldViewManager.preSceneconstructed aSceneRendererper worldview, lazily, inside the draw callback. Each one meant sixScenePipelineobjects (each loading the SPIR-V, creating two shader modules, a descriptor set layout, a pipeline layout and compiling a pipeline), a descriptor pool and set that only ever bind the texture array and the shared animation UBO, a 12.5 MB arena preferentially in BAR memory plus a VRAM mirror on non-ReBAR machines, and avkDeviceWaitIdlefor the first capture — all of it every time a ship sailed into view.ScenePipelinesowns the six pipelines and the descriptor set, built once per device and shared by the top level and every sub-worldview.SceneVertexBufferloses its descriptor pool entirely.captureScenealready runs, so ship size is measured rather than guessed.This removes hitches when ships spawn and a lot of memory. It is worth having on its own terms.
What this does NOT fix
The complaint that started this was FPS in a salvage area with many boats. Three-way measurement at the same spot says that is engine-side:
-Dvkgpu.disableSubWorldViews=true— engine still traverses every worldview and fires every callback, we drop all of themhideWorldEntities— engine skips the worldviews entirelyOur entire sub-worldview renderer accounts for ~15 FPS of the ~100. The rest is the engine's own per-worldview traversal, which stock pays too. Everything we ask the engine to do is identical to stock:
GPU | ZBUF | NO_VERTEX_SNAPPING(ClientRuntimeConfig.java:23-29vsGpuPlugin.java:361-364),setExpandedMapLoadingdefault 3 on both sides,scene.setDrawDistancefrom config on both sides.Testing
./gradlew buildpasses; shaders recompiled,spirv-valclean on both,checkGpuVulkanShadersFreshpasses. The-Dvkgpu.*forwarding was verified by probing the configuredruntask, not by trusting the API name.Runtime: the isolation flag has been exercised in game. The tint and the repacked push constants have not been visually confirmed yet — that needs a salvage spot with other players' ships in view, which should read as flat silhouettes.