You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
GL skybox/environment renders blown-out white (Newport Loft HDRI) — Vulkan renders it correctly #797
Every scene using an equirectangular HDRI environment (newport_loft.hdr: PBRReference, MaterialSpheres, Sponza*, VirtualGeometry*, SSGITest, SSRTest, ContactShadowTest, SphereAreaLightShadowTest — 13 scenes) renders the background/skybox as featureless blown-out white under OpenGL, while the Vulkan backend resolves the actual loft interior (warm wood, drapes, windows — matching the well-known Newport Loft source image).
Found by the #691 Phase 8 80-scene GL-vs-Vulkan A/B sweep; it is the dominant remaining visual divergence between the backends (mean-abs pixel diff ~170/255 on the affected scenes, ~99% of pixels).
Evidence that GL is the broken side
The Newport Loft HDRI's interior is warm brown wood — the Vulkan render matches it; GL shows uniform white in all directions, not just toward the bright windows.
Reproduced identically on a master-era build (7c514e49, the visual-scripting-634 worktree's binary) — so it predates the Phase 8 branch entirely and is not a Vulkan-parity regression.
Divergence is already present in SceneColor (pre-post-processing), so it is in the skybox/environment render, not the tonemap chain.
What was ruled out
Camera pose (olo_camera_get identical on both backends).
The env cubemap spec formats (both backends use RGBA32F specs in EnvironmentMap.cpp).
The Phase 8 shader edits (GL branches of Skybox.glsl / EquirectangularToCubemap.glsl untouched; master shows the same white).
Suspects for whoever picks this up
The GL equirect→cubemap bake output (mip/exposure/format on the GL arm of IBLPrecompute / EnvironmentMap::GenerateIBLTextures).
OloEngineImageFormatToGLInternalFormat mapping for the float formats on the cubemap path.
GL skybox sampling LOD/exposure vs the Vulkan heap-sampled path.
The reference path tracer (docs/agent-rules/reference-path-tracer.md) can arbitrate the final look once a fix is proposed.
Part of the #691 Phase 8 verification fallout; sweep artifacts and probe methodology are described in PR #794.
Root-caused and fixed (60cf190b on the #691 Phase 8 branch)
The one-line cause:OpenGLFramebuffer::Invalidate called Utils::BindTexture(id) — which is glBindTextureUnit(0, id) — on every freshly created color and depth attachment. The attachment setup is fully DSA, so the bind did nothing useful; it only replaced whatever was published on texture unit 0.
Why that whitened every HDRI sky:ConvertEquirectangularToCubemap publishes the loaded HDR pano on unit 0 (TEX_DIFFUSE), then RenderToCubemap creates its capture framebuffer — whose depth attachment landed on unit 0 — so all six face bakes sampled the depth clear value (constant 1.0) instead of the pano. White cubemap → white skybox + white-tinted IBL in all 13 HDRI scenes, on GL only. Vulkan resolves bindings at draw from published state, so it was correct all along — exactly as the sweep suggested.
The evidence ladder (all via a new env-gated OLO_ENV_BAKE_DUMP diagnostic, kept in-tree):
CPU source mean of newport_loft.hdr: (0.335, 0.236, 0.183) ✓
Uploaded-GL-texture readback: identical to source ✓ (upload exonerated)
Baked faces: uniform wrong values ✗
A uv-visualizing shader variant: per-face uv means correct ✓ (geometry/varyings exonerated — only the sample wrong)
A unit-0 occupancy probe at draw time: unit 0 held GL id 46 (the capture FB's depth attachment) where the pano (id 43) had been published — caught red-handed.
Fix: delete both Utils::BindTexture calls and the orphaned helper; hoist the cube-mesh build ahead of the publish so no future resource-creation path can slot into the same gap.
Verified: GL bake per-face means are now byte-identical to Vulkan's; PBRReference renders at a 1.18/255 mean pixel difference between backends (was ~174/255). Full suite green; the RHI boundary ratchet stays at its shrunken baseline; no goldens involved HDRI environments, so none needed rebaking.
Recommend closing once #794 merges (the fix rides that branch).
Activity
coderabbitai commentedon Aug 14, 2026
🔗 Related PRs
#404 - fix(renderer): repair reflection-probe bake (was all-black) + add vis… [merged]
#465 - Fix/flaky fog visual evidence test [merged]
#674 - fix(renderer): GTAO black-sky artifact — exact texelFetch HZB depth copy + ULP-tolerant far-plane test [merged]
#750 - feat(renderer): offline reference path tracer for ground-truth GI/BRDF validation (
#709) [merged]#794 - Vulkan Phase 8: editor-frame parity, MCP diagnostic loop, command-ordered buffers (
#691) [open]🧪 Issue enrichment is currently in open beta.
To disable automatic issue enrichment, add the following to your
.coderabbit.yaml:💬 Have feedback or questions? Drop into our discord!
fix(rhi): Renderer2D rendered vertically mirrored under Vulkan — rout…
fix(gl): framebuffer creation clobbered texture unit 0 — every GL HDR…
drsnuggles8 commentedon Aug 15, 2026
Root-caused and fixed (
60cf190bon the #691 Phase 8 branch)The one-line cause:
OpenGLFramebuffer::InvalidatecalledUtils::BindTexture(id)— which isglBindTextureUnit(0, id)— on every freshly created color and depth attachment. The attachment setup is fully DSA, so the bind did nothing useful; it only replaced whatever was published on texture unit 0.Why that whitened every HDRI sky:
ConvertEquirectangularToCubemappublishes the loaded HDR pano on unit 0 (TEX_DIFFUSE), thenRenderToCubemapcreates its capture framebuffer — whose depth attachment landed on unit 0 — so all six face bakes sampled the depth clear value (constant 1.0) instead of the pano. White cubemap → white skybox + white-tinted IBL in all 13 HDRI scenes, on GL only. Vulkan resolves bindings at draw from published state, so it was correct all along — exactly as the sweep suggested.The evidence ladder (all via a new env-gated
OLO_ENV_BAKE_DUMPdiagnostic, kept in-tree):newport_loft.hdr: (0.335, 0.236, 0.183) ✓Fix: delete both
Utils::BindTexturecalls and the orphaned helper; hoist the cube-mesh build ahead of the publish so no future resource-creation path can slot into the same gap.Verified: GL bake per-face means are now byte-identical to Vulkan's; PBRReference renders at a 1.18/255 mean pixel difference between backends (was ~174/255). Full suite green; the RHI boundary ratchet stays at its shrunken baseline; no goldens involved HDRI environments, so none needed rebaking.
Recommend closing once #794 merges (the fix rides that branch).