Skip to content

Commit 07e6602

Browse files
committed
Honor the surface's alphaMode in the Vulkan swapchain
ChooseConfig hardcoded VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR outside of Android, so a surface configured with a transparent alphaMode was composited as opaque. Convert the WebGPU enum directly: Surface.cpp has already resolved Auto and validated the mode against the capabilities PhysicalDeviceVk reports. Add a transparent-window mode (T) to ManualSurfaceTest so the alpha modes can be checked against the desktop.
1 parent 710c330 commit 07e6602

2 files changed

Lines changed: 38 additions & 24 deletions

File tree

src/dawn/native/vulkan/SwapChainVk.cpp

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
#include <utility>
3333

3434
#include "src/dawn/common/Compiler.h"
35-
#include "src/dawn/common/Range.h"
3635
#include "src/dawn/native/ChainUtils.h"
3736
#include "src/dawn/native/Instance.h"
3837
#include "src/dawn/native/Surface.h"
@@ -296,33 +295,34 @@ ResultOrError<SwapChain::Config> SwapChain::ChooseConfig(
296295
"Vulkan SwapChain must support %s with sRGB colorspace.", config.wgpuFormat));
297296
}
298297

299-
// Only the identity transform with opaque alpha is supported for now.
298+
// Only the identity transform is supported for now.
300299
DAWN_INVALID_IF(
301300
(surfaceInfo.capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) == 0,
302301
"Vulkan SwapChain must support the identity transform.");
303302

304303
config.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
305304

306-
config.alphaMode = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
307-
#if !DAWN_PLATFORM_IS(ANDROID)
308-
DAWN_INVALID_IF(
309-
(surfaceInfo.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) == 0,
310-
"Vulkan SwapChain must support opaque alpha.");
311-
#else
312-
// TODO(dawn:286): investigate composite alpha for WebGPU native
313-
std::array<VkCompositeAlphaFlagBitsKHR, 4u> compositeAlphaFlags = {
314-
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
315-
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
316-
VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
317-
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
318-
};
319-
for (uint32_t i : Range(4u)) {
320-
if (surfaceInfo.capabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) {
321-
config.alphaMode = compositeAlphaFlags[i];
305+
// Choose the Vulkan alpha mode by directly converting from the WebGPU enum. PhysicalDeviceVk
306+
// only reports the alpha modes the surface supports, Surface.cpp resolves Auto and validates
307+
// the rest, so the mode asked for here is always available.
308+
switch (GetAlphaMode()) {
309+
case wgpu::CompositeAlphaMode::Opaque:
310+
config.alphaMode = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
322311
break;
323-
}
312+
case wgpu::CompositeAlphaMode::Premultiplied:
313+
config.alphaMode = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
314+
break;
315+
case wgpu::CompositeAlphaMode::Unpremultiplied:
316+
config.alphaMode = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
317+
break;
318+
case wgpu::CompositeAlphaMode::Inherit:
319+
config.alphaMode = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
320+
break;
321+
case wgpu::CompositeAlphaMode::Auto:
322+
default:
323+
DAWN_UNREACHABLE();
324324
}
325-
#endif // #if !DAWN_PLATFORM_IS(ANDROID)
325+
DAWN_CHECK((surfaceInfo.capabilities.supportedCompositeAlpha & config.alphaMode) != 0);
326326

327327
// Choose the number of images for the swapchain= and clamp it to the min and max from the
328328
// surface capabilities. maxImageCount = 0 means there is no limit.

src/dawn/samples/ManualSurfaceTest.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
// This is an example to manually test surface code. Controls are the following, scoped to the
2929
// currently focused window:
3030
// - W: creates a new window.
31+
// - T: creates a new window with a transparent framebuffer, to test the alpha modes.
3132
// - L: Latches the current surface, to check what happens when the window changes but not the
3233
// surface.
3334
// - R: switches the rendering mode, between "The Red Triangle" and color-cycling clears that's
@@ -64,6 +65,9 @@
6465
// - Config change tests:
6566
// - Check that cycling between present modes.
6667
// - Check that cycling between alpha modes (it sometimes produce a meaningful difference).
68+
// - Check alpha modes on a transparent window (T) in the cycling color render mode: the clear
69+
// is premultiplied and cycles its alpha, so Premultiplied and Unpremultiplied let the
70+
// desktop show through and Opaque does not.
6771
// - Check that cycling between formats works and gives the same color.
6872
//
6973
// - Frame throttling:
@@ -75,7 +79,6 @@
7579
// - Check sRGB vs not sRGB gradients.
7680
// - Check wide gamut / extended color range.
7781
// - Check OpenGL rendering with extra usages / depth buffer / MRT.
78-
// - Check with GLFW transparency on / off.
7982

8083
#include <webgpu/webgpu_cpp.h>
8184

@@ -125,6 +128,7 @@ struct WindowData {
125128
uint64_t serial = 0;
126129

127130
float clearCycle = 1.0f;
131+
bool transparent = false;
128132
bool latched = false;
129133
bool renderTriangle = true;
130134
uint32_t divisor = 1;
@@ -200,8 +204,9 @@ void SyncFromWindow(WindowData* data) {
200204
data->targetConfig.height = std::max(1u, static_cast<uint32_t>(height) / data->divisor);
201205
}
202206

203-
void AddWindow() {
207+
void AddWindow(bool transparent = false) {
204208
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
209+
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, transparent ? GLFW_TRUE : GLFW_FALSE);
205210
GLFWwindow* window = glfwCreateWindow(400, 400, "", nullptr, nullptr);
206211
glfwSetKeyCallback(window, OnKeyPress);
207212

@@ -221,6 +226,7 @@ void AddWindow() {
221226
std::unique_ptr<WindowData> data = std::make_unique<WindowData>();
222227
data->window = window;
223228
data->serial = windowSerial++;
229+
data->transparent = transparent;
224230
data->surface = surface;
225231
data->currentConfig = config;
226232
data->targetConfig = config;
@@ -257,10 +263,14 @@ void DoRender(WindowData* data) {
257263
data->clearCycle = 1.0f;
258264
}
259265

266+
// On a transparent window cycle the alpha as well, so that the alpha modes have a
267+
// visible effect. The color channels are premultiplied so that Premultiplied is valid.
268+
const double alpha = data->transparent ? double{data->clearCycle} : 1.0;
269+
260270
dawn::utils::ComboRenderPassDescriptor desc({view});
261271
desc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
262-
desc.cColorAttachments[0].clearValue = {double{data->clearCycle},
263-
double{1.0f - data->clearCycle}, 0.0, 1.0};
272+
desc.cColorAttachments[0].clearValue = {
273+
alpha * double{data->clearCycle}, alpha * double{1.0f - data->clearCycle}, 0.0, alpha};
264274

265275
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&desc);
266276
pass.End();
@@ -316,6 +326,10 @@ void OnKeyPress(GLFWwindow* window, int key, int, int action, int) {
316326
AddWindow();
317327
break;
318328

329+
case GLFW_KEY_T:
330+
AddWindow(/*transparent=*/true);
331+
break;
332+
319333
case GLFW_KEY_L:
320334
data->latched = !data->latched;
321335
UpdateTitle(data);

0 commit comments

Comments
 (0)