Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion src/dawn/native/vulkan/SwapChainVk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,19 @@ MaybeError SwapChain::Initialize(SwapChainBase* previousSwapChain) {
createInfo.clipped = VK_FALSE;
createInfo.oldSwapchain = previousVkSwapChain;

// Create the swapchain images with VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT so they can be
// reinterpreted to the configuration's viewFormats. VK_KHR_swapchain_mutable_format
// requires the full list of formats to be provided, including the image format itself.
VkImageFormatListCreateInfo imageFormatListInfo;
if (!mConfig.viewFormats.empty()) {
createInfo.flags |= VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR;
imageFormatListInfo.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO;
imageFormatListInfo.pNext = nullptr;
imageFormatListInfo.viewFormatCount = static_cast<uint32_t>(mConfig.viewFormats.size());
imageFormatListInfo.pViewFormats = mConfig.viewFormats.data();
createInfo.pNext = &imageFormatListInfo;
}

DAWN_TRY(CheckVkSuccess(
device->fn.CreateSwapchainKHR(device->GetVkDevice(), &createInfo, nullptr, &*mSwapChain),
"CreateSwapChain"));
Expand Down Expand Up @@ -272,7 +285,13 @@ ResultOrError<SwapChain::Config> SwapChain::ChooseConfig(
VkImageUsageFlags targetUsages =
VulkanImageUsage(GetDevice(), GetUsage(), GetDevice()->GetValidInternalFormat(GetFormat()));
VkImageUsageFlags supportedUsages = surfaceInfo.capabilities.supportedUsageFlags;
if (!IsSubset(targetUsages, supportedUsages)) {
// Without VK_KHR_swapchain_mutable_format the swapchain images are created
// without VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT, so they cannot be reinterpreted
// to the configuration's viewFormats. The blit texture is a regular texture and can.
const bool viewFormatsRequireBlit =
!GetViewFormats().empty() &&
!ToBackend(GetDevice())->GetDeviceInfo().HasExt(DeviceExt::SwapchainMutableFormat);
if (!IsSubset(targetUsages, supportedUsages) || viewFormatsRequireBlit) {
config.needsBlit = true;
} else {
config.usage = targetUsages;
Expand All @@ -296,6 +315,18 @@ ResultOrError<SwapChain::Config> SwapChain::ChooseConfig(
"Vulkan SwapChain must support %s with sRGB colorspace.", config.wgpuFormat));
}

// If the swapchain images are exposed to the user directly and need to be reinterpreted
// to the configuration's viewFormats, gather the full list of formats used to create the
// swapchain with VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR.
if (!config.needsBlit && !GetViewFormats().empty()) {
DAWN_ASSERT(
ToBackend(GetDevice())->GetDeviceInfo().HasExt(DeviceExt::SwapchainMutableFormat));
config.viewFormats.push_back(config.format);
for (wgpu::TextureFormat viewFormat : GetViewFormats()) {
config.viewFormats.push_back(VulkanImageFormat(ToBackend(GetDevice()), viewFormat));
}
}

// Only the identity transform with opaque alpha is supported for now.
DAWN_INVALID_IF(
(surfaceInfo.capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) == 0,
Expand Down Expand Up @@ -551,6 +582,11 @@ ResultOrError<SwapChainTextureInfo> SwapChain::GetCurrentTextureInternal(bool is
textureDesc.size.height = mConfig.extent.height;
textureDesc.format = mConfig.wgpuFormat;
textureDesc.usage = mConfig.wgpuUsage;
if (!mConfig.needsBlit) {
// The swapchain images were created mutable so the user-facing texture supports the
// configuration's viewFormats. In the blit case they stay on the blit texture instead.
textureDesc.viewFormats = GetViewFormats();
}

mTexture = SwapChainTexture::Create(device, Unpack(&textureDesc), lastImage.image);

Expand Down
5 changes: 5 additions & 0 deletions src/dawn/native/vulkan/SwapChainVk.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ class SwapChain : public SwapChainBase {
uint32_t targetImageCount;
VkSurfaceTransformFlagBitsKHR transform;
VkCompositeAlphaFlagBitsKHR alphaMode;
// When non-empty, the swapchain is created with
// VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR and this list (which includes `format`)
// is chained as a VkImageFormatListCreateInfo so the images can be reinterpreted to
// the configuration's viewFormats.
std::vector<VkFormat> viewFormats;

// Redundant information but as WebGPU enums to create the wgpu::Texture that
// encapsulates the native swapchain texture.
Expand Down
7 changes: 7 additions & 0 deletions src/dawn/native/vulkan/VulkanExtensions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ static constexpr std::array<DeviceExtInfo, kDeviceExtCount> sDeviceExtInfos{{
{DeviceExt::DepthClipEnable, "VK_EXT_depth_clip_enable"},
{DeviceExt::ImageDrmFormatModifier, "VK_EXT_image_drm_format_modifier"},
{DeviceExt::Swapchain, "VK_KHR_swapchain"},
{DeviceExt::SwapchainMutableFormat, "VK_KHR_swapchain_mutable_format"},
{DeviceExt::QueueFamilyForeign, "VK_EXT_queue_family_foreign"},
{DeviceExt::Robustness2, "VK_EXT_robustness2"},
{DeviceExt::DisplayTiming, "VK_GOOGLE_display_timing"},
Expand Down Expand Up @@ -253,6 +254,12 @@ DeviceExtSet EnsureDependencies(const DeviceExtSet& advertisedExts,
hasDependencies = instanceExts[InstanceExt::Surface];
break;

// Also requires VK_KHR_maintenance2 which is core in Vulkan 1.1.
case DeviceExt::SwapchainMutableFormat:
hasDependencies =
HasDep(DeviceExt::Swapchain) && HasDep(DeviceExt::ImageFormatList);
break;

case DeviceExt::ExternalMemoryAndroidHardwareBuffer:
hasDependencies = HasDep(DeviceExt::QueueFamilyForeign);
break;
Expand Down
1 change: 1 addition & 0 deletions src/dawn/native/vulkan/VulkanExtensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ enum class DeviceExt : uint32_t {
DepthClipEnable,
ImageDrmFormatModifier,
Swapchain,
SwapchainMutableFormat,
QueueFamilyForeign,
Robustness2,
DisplayTiming,
Expand Down
43 changes: 43 additions & 0 deletions src/dawn/tests/end2end/SurfaceTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,49 @@ TEST_P(SurfaceTests, Storage) {
ASSERT_EQ(wgpu::Status::Success, surface.Present());
}

// Test acquiring a texture from a surface configured with viewFormats.
TEST_P(SurfaceTests, ConfigureWithViewFormats) {
wgpu::Surface surface = CreateTestSurface();
wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);

// Reinterpretation between a format and its srgb counterpart is always
// allowed; pick the counterpart of whatever the surface prefers.
wgpu::TextureFormat viewFormat;
switch (config.format) {
case wgpu::TextureFormat::BGRA8Unorm:
viewFormat = wgpu::TextureFormat::BGRA8UnormSrgb;
break;
case wgpu::TextureFormat::RGBA8Unorm:
viewFormat = wgpu::TextureFormat::RGBA8UnormSrgb;
break;
default:
GTEST_SKIP() << "Preferred surface format has no srgb counterpart";
}
config.viewFormatCount = 1;
config.viewFormats = &viewFormat;
surface.Configure(&config);

wgpu::SurfaceTexture surfaceTexture;
surface.GetCurrentTexture(&surfaceTexture); // aborts on Vulkan before the fix

// Render through a view using the reinterpreted format to check the texture really
// supports its viewFormats.
wgpu::TextureViewDescriptor viewDesc;
viewDesc.format = viewFormat;
utils::ComboRenderPassDescriptor renderPassDesc(
{surfaceTexture.texture.CreateView(&viewDesc)});
renderPassDesc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
renderPassDesc.cColorAttachments[0].clearValue = {1.0, 0.0, 0.0, 1.0};

wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
pass.End();
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);

surface.Present();
}

// TODO(crbug.com/465183957): Implement swap chain for WebGPUBackend.
DAWN_INSTANTIATE_TEST(SurfaceTests,
D3D11Backend(),
Expand Down
Loading