diff --git a/src/dawn/native/vulkan/SwapChainVk.cpp b/src/dawn/native/vulkan/SwapChainVk.cpp index 7aeb73bc475..6326d437adc 100644 --- a/src/dawn/native/vulkan/SwapChainVk.cpp +++ b/src/dawn/native/vulkan/SwapChainVk.cpp @@ -32,7 +32,6 @@ #include #include "src/dawn/common/Compiler.h" -#include "src/dawn/common/Range.h" #include "src/dawn/native/ChainUtils.h" #include "src/dawn/native/Instance.h" #include "src/dawn/native/Surface.h" @@ -296,33 +295,34 @@ ResultOrError SwapChain::ChooseConfig( "Vulkan SwapChain must support %s with sRGB colorspace.", config.wgpuFormat)); } - // Only the identity transform with opaque alpha is supported for now. + // Only the identity transform is supported for now. DAWN_INVALID_IF( (surfaceInfo.capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) == 0, "Vulkan SwapChain must support the identity transform."); config.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - config.alphaMode = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; -#if !DAWN_PLATFORM_IS(ANDROID) - DAWN_INVALID_IF( - (surfaceInfo.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) == 0, - "Vulkan SwapChain must support opaque alpha."); -#else - // TODO(dawn:286): investigate composite alpha for WebGPU native - std::array compositeAlphaFlags = { - VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, - VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, - VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, - }; - for (uint32_t i : Range(4u)) { - if (surfaceInfo.capabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) { - config.alphaMode = compositeAlphaFlags[i]; + // Choose the Vulkan alpha mode by directly converting from the WebGPU enum. PhysicalDeviceVk + // only reports the alpha modes the surface supports, Surface.cpp resolves Auto and validates + // the rest, so the mode asked for here is always available. + switch (GetAlphaMode()) { + case wgpu::CompositeAlphaMode::Opaque: + config.alphaMode = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; break; - } + case wgpu::CompositeAlphaMode::Premultiplied: + config.alphaMode = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; + break; + case wgpu::CompositeAlphaMode::Unpremultiplied: + config.alphaMode = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR; + break; + case wgpu::CompositeAlphaMode::Inherit: + config.alphaMode = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; + break; + case wgpu::CompositeAlphaMode::Auto: + default: + DAWN_UNREACHABLE(); } -#endif // #if !DAWN_PLATFORM_IS(ANDROID) + DAWN_CHECK((surfaceInfo.capabilities.supportedCompositeAlpha & config.alphaMode) != 0); // Choose the number of images for the swapchain= and clamp it to the min and max from the // surface capabilities. maxImageCount = 0 means there is no limit. diff --git a/src/dawn/samples/ManualSurfaceTest.cpp b/src/dawn/samples/ManualSurfaceTest.cpp index f2d9852a4aa..55e113678db 100644 --- a/src/dawn/samples/ManualSurfaceTest.cpp +++ b/src/dawn/samples/ManualSurfaceTest.cpp @@ -28,6 +28,7 @@ // This is an example to manually test surface code. Controls are the following, scoped to the // currently focused window: // - W: creates a new window. +// - T: creates a new window with a transparent framebuffer, to test the alpha modes. // - L: Latches the current surface, to check what happens when the window changes but not the // surface. // - R: switches the rendering mode, between "The Red Triangle" and color-cycling clears that's @@ -64,6 +65,9 @@ // - Config change tests: // - Check that cycling between present modes. // - Check that cycling between alpha modes (it sometimes produce a meaningful difference). +// - Check alpha modes on a transparent window (T) in the cycling color render mode: the clear +// is premultiplied and cycles its alpha, so Premultiplied and Unpremultiplied let the +// desktop show through and Opaque does not. // - Check that cycling between formats works and gives the same color. // // - Frame throttling: @@ -75,7 +79,6 @@ // - Check sRGB vs not sRGB gradients. // - Check wide gamut / extended color range. // - Check OpenGL rendering with extra usages / depth buffer / MRT. -// - Check with GLFW transparency on / off. #include @@ -125,6 +128,7 @@ struct WindowData { uint64_t serial = 0; float clearCycle = 1.0f; + bool transparent = false; bool latched = false; bool renderTriangle = true; uint32_t divisor = 1; @@ -200,8 +204,9 @@ void SyncFromWindow(WindowData* data) { data->targetConfig.height = std::max(1u, static_cast(height) / data->divisor); } -void AddWindow() { +void AddWindow(bool transparent = false) { glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, transparent ? GLFW_TRUE : GLFW_FALSE); GLFWwindow* window = glfwCreateWindow(400, 400, "", nullptr, nullptr); glfwSetKeyCallback(window, OnKeyPress); @@ -221,6 +226,7 @@ void AddWindow() { std::unique_ptr data = std::make_unique(); data->window = window; data->serial = windowSerial++; + data->transparent = transparent; data->surface = surface; data->currentConfig = config; data->targetConfig = config; @@ -257,10 +263,14 @@ void DoRender(WindowData* data) { data->clearCycle = 1.0f; } + // On a transparent window cycle the alpha as well, so that the alpha modes have a + // visible effect. The color channels are premultiplied so that Premultiplied is valid. + const double alpha = data->transparent ? double{data->clearCycle} : 1.0; + dawn::utils::ComboRenderPassDescriptor desc({view}); desc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear; - desc.cColorAttachments[0].clearValue = {double{data->clearCycle}, - double{1.0f - data->clearCycle}, 0.0, 1.0}; + desc.cColorAttachments[0].clearValue = { + alpha * double{data->clearCycle}, alpha * double{1.0f - data->clearCycle}, 0.0, alpha}; wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&desc); pass.End(); @@ -316,6 +326,10 @@ void OnKeyPress(GLFWwindow* window, int key, int, int action, int) { AddWindow(); break; + case GLFW_KEY_T: + AddWindow(/*transparent=*/true); + break; + case GLFW_KEY_L: data->latched = !data->latched; UpdateTitle(data);