diff --git a/src/xrt/compositor/metal/comp_metal_compositor.m b/src/xrt/compositor/metal/comp_metal_compositor.m index d261b96ecf..c20da9b87f 100644 --- a/src/xrt/compositor/metal/comp_metal_compositor.m +++ b/src/xrt/compositor/metal/comp_metal_compositor.m @@ -4018,6 +4018,21 @@ - (BOOL)wantsUpdateLayer } } + // #1788: window-space layers BLEND over the projection content, + // same rule as D3D11/D3D12, vk_native and GL (#1786/#1787): + // SOURCE_ALPHA_BIT clear means premultiplied bytes (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). + // The blended projection pipelines carry exactly those factors. + // Deliberately NOT comp_layer_blend_mode() (#1599): see the + // comment in comp_d3d11_renderer.cpp's window-space draw. And + // never projection_pipeline — its REPLACE is for the base blit. + bool ws_premultiplied = + (layer->data.flags & XRT_LAYER_COMPOSITION_BLEND_TEXTURE_SOURCE_ALPHA_BIT) == 0; + id ws_pipeline = + ws_premultiplied ? c->proj_premult_pipeline : c->proj_straight_pipeline; + // Source UV sub-rect (default to full texture if not specified) struct xrt_normalized_rect nr = ws->sub.norm_rect; if (nr.w <= 0.0f || nr.h <= 0.0f) { @@ -4060,7 +4075,7 @@ - (BOOL)wantsUpdateLayer } [encoder setViewport:vp]; - [encoder setRenderPipelineState:c->projection_pipeline]; + [encoder setRenderPipelineState:ws_pipeline]; [encoder setDepthStencilState:c->depth_stencil_state]; [encoder setFragmentTexture:src_tex atIndex:0]; [encoder setFragmentSamplerState:c->sampler_linear atIndex:0]; diff --git a/tests/tests_comp_layer_view_camera.cpp b/tests/tests_comp_layer_view_camera.cpp index 88c4f004f3..1b1c4332ff 100644 --- a/tests/tests_comp_layer_view_camera.cpp +++ b/tests/tests_comp_layer_view_camera.cpp @@ -1138,7 +1138,9 @@ TEST_CASE("comp_layer_blend_mode: no backend reimplements the blend rule (#1621) // channel D3D11's is (its own premul/straight decision, deliberately // not comp_layer_blend_mode() -- see comp_d3d11_renderer.cpp). {"gl/comp_gl_compositor.cpp", 1}, - {"metal/comp_metal_compositor.m", 0}, + // #1788: Metal's one allowance is the same Local2D / window-space + // channel as D3D11/D3D12/GL (#1581, #1786). + {"metal/comp_metal_compositor.m", 1}, // The Local2D / window-space channel, above. {"d3d11/comp_d3d11_renderer.cpp", 1}, /*