fix(metal): blend window-space layers instead of overwriting (#1788) - #1789
Merged
Merged
Conversation
The Metal window-space pass (XrCompositionLayerWindowSpaceDXR) drew with projection_pipeline, which has blending disabled, so a HUD overwrote its whole rectangle in the atlas, colour AND alpha, instead of compositing over the 3D content. Pick the blended projection pipeline per layer, matching the rule that D3D11/D3D12, vk_native and GL use (#1786/#1787): SOURCE_ALPHA_BIT clear means premultiplied (colour src ONE), set means straight (colour src SOURCE_ALPHA); colour dst and the alpha "over" (ONE / ONE_MINUS_SOURCE_ALPHA) are shared, so atlas alpha survives for transparent sessions (#225/#1784). proj_premult_pipeline and proj_straight_pipeline already carry exactly those factors with the same shaders and depth attachment, so no new pipeline is needed. projection_pipeline's REPLACE for the base blit is untouched. Verified on macOS (cube_handle_metal_macos, sim_display anaglyph, atlas capture): before, the HUD rect is an opaque grey panel hiding the grid and writes atlas alpha 128 over opaque content; after, the grid shows through and atlas alpha stays 255. Premultiplied (flags 0) case checked with a temporary local flag flip: translucent, no halo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Same allowance D3D11/D3D12/GL have for the Local2D / window-space channel; the #1621 guard moves Metal from 0 to 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dfattal
force-pushed
the
fix/metal-window-space-blend-1788
branch
from
October 2, 2026 07:59
aec0122 to
f3d2d37
Compare
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.
Fixes #1788
Problem
The Metal compositor's window-space pass (
XrCompositionLayerWindowSpaceDXR) boundprojection_pipeline, which has blending disabled. A window-space HUD therefore overwrote its whole rectangle in the atlas, colour and alpha both, instead of compositing over the 3D content. Every other backend blends here: D3D11/D3D12, and vk_native and GL as of #1787.Fix
The window-space draw now picks a blended pipeline per layer, using the same rule as the other backends:
SOURCE_ALPHA_BITclear (premultiplied)SOURCE_ALPHA_BITset (straight)The alpha "over" keeps atlas alpha intact for transparent sessions (#225/#1784).
proj_premult_pipelineandproj_straight_pipelinealready exist with exactly these factors, and they use the same projection shaders andDepth32Floatattachment that the window-space pass already used. So this change only swaps which pipeline is bound and creates no new pipeline state.projection_pipelineis unchanged: its REPLACE is what the base blit relies on (DP compose-under-bg likely applied per-layer instead of post-composite — desktop bleeds through semi-transparent window-space HUD over opaque content #225/CTS composition: projection layers are blitted opaque over the whole tile, wiping every layer submitted before them (QuadProjectionQuad / ProjectionQuadProjection FAIL) #1598).comp_layer_blend_mode()(CTS composition: quad with UNPREMULTIPLIED_ALPHA and no SOURCE_ALPHA flag (alpha=0 texture) is drawn far too bright instead of opaque — SourceAlphaBlending FAIL #1599). The reason is in the comment at D3D11's window-space draw.src/xrt/compositor/metal/. The shared-texture (_texture) Metal path goes through the samemetal_compositor_layer_commitpass. The other window-space consumers (compositor/multi/*) are Vulkan code and out of scope here.Testing (macOS)
Test setup:
cube_handle_metal_macos, sim_display anaglyph,/tmp/dxr_atlas_triggeratlas capture. The HUD was forced visible by a temporary local-only edit, which is not in this PR. A/B on the same build tree:DXR_ATLAS_CAPTURE_RAW_ALPHA=1, the HUD region writes atlas alpha down to 128 over opaque content. That is the DP compose-under-bg likely applied per-layer instead of post-composite — desktop bleeds through semi-transparent window-space HUD over opaque content #225-class bleed, where the DP would show the desktop through the HUD.SOURCE_ALPHA_BIT): the panel is translucent, the grid shows through, and there is no hard rectangle. Raw atlas alpha in the HUD region is 255 everywhere, so destination alpha is preserved.Not tested
DISPLAYXR_TRANSPARENT_BG) where the atlas starts with alpha < 1 under the HUD._textureMetal apps (cube_zones_texture_metal_macos) and the hosted/legacy Metal apps. They share the same draw site but were not run.disparity, and multiple window-space layers.src/xrt/.clang-formathas no Objective-C section, so the tool refuses.mfiles. Style was matched by hand.🤖 Generated with Claude Code