Opaque GPU-driven instances now render through a deferred-style path under the
new "visResolve" render-control flag (1x scene pass):
- GBuffer gains visID (R32G32UI: instance + pooled triangle base) and visBary
(R16G16F) attachments plus a vis render-pass variant and pipeline.
- The vis pass draws the cull chain's indirect commands with NO vertex input:
the vertex shader fetches position/normal/uv from new pooled buffers via
gl_VertexIndex (non-indexed draw reuses the same indirect commands), which
also makes the per-vertex barycentric constants exact (gl_VertexIndex % 3).
Triangle ids are computed in the vertex stage and passed flat, avoiding
gl_PrimitiveID in the fragment (which would require the SPIR-V Geometry
capability / geometryShader feature).
- resolve_vis.frag runs as a fullscreen triangle inside the scene color pass:
it reconstructs world pos / normal / uv from the pool using the barycentrics,
shades with the shared PBR code and writes the opaque depth (gl_FragDepth),
so later hair/transparent draws depth-test correctly.
- New vertex pool (positions/normals/uvs as vec4/vec4/vec2 SSBO arrays +
u32 index pool, host-visible, grow-by-2x with waitIdle); meshes are pooled
lazily at registerMeshRecord and GpuMeshRecord.vertexOffset/indexOffset now
point into the pool. Bindless set1 gains bindings 15/16 (vis samplers) and
18-21 (pool buffers), all rewritten per slot/frame following the safe-point
rule from 8f156a6.
- pbr_shade.glsl extracts the GPU-driven PBR/CSM/cloud/env shading so the
forward path and the resolve share one source of truth.
Verified: GpuDriven.visResolveParity passes with maxDelta=0.0 vs the forward
path (same cull, same pixels); full GpuDriven + RenderSystem3D/Shadow3D/
Lighting3D suites pass; validation shows no new VUIDs (the SPIR-V Geometry
capability error from gl_PrimitiveID was removed by the flat-triangle-base
change).