Reland "Remove SwapChain from the API"
This is a reland of commit 966c91706b9a39c30bd3fc24f9f776a02cda8aaf
Reland with:
- Missing length fields added in dawn.json
- A blocklisting of Surface::GetCurrentTexture for the LPM fuzzer
- Minor changes to comments
Original change's description:
> Remove SwapChain from the API
>
> This applies the switch from manipulating a SwapChain object to calling
> Surface::configure that was brung to the standard webgpu.h a couple of
> months ago.
>
> I believe this needs a bit of extra work, but at this stage I need a
> review from people more familiar with the codebase to tell me if I am
> going in the right direction.
>
> The SwapChain object is still here, but no longer present in the API.
> Instances of the swap chain are now owned by the surface object. The
> test for surface capabilities is partly calling a method of the
> PhysicalDevice in order to have backend-specific capabilities.
>
> So far I mostly tested with the Vulkan backend, though I tried to
> provide a valid implementation for all backends.
>
> Reland changes:
> This fixes commit 167600, which was causing lock issues because the
> surface was failing at locking the device before calling it's internal
> SwapChain's methods like Present and GetTexture.
>
> Bug: dawn:2320
> Change-Id: I6773c9de069ad4f4f93ad47ace6a5773665f4e92
> Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/179580
> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
> Reviewed-by: Austin Eng <enga@chromium.org>
> Commit-Queue: Élie Michel <elie.michel.fr@gmail.com>
Bug: dawn:2320
Change-Id: I02800d940d374c57237839c651ce26725b17928f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/182560
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/generator/templates/dawn/wire/WireCmd.cpp b/generator/templates/dawn/wire/WireCmd.cpp
index a62906e..ec1faaa 100644
--- a/generator/templates/dawn/wire/WireCmd.cpp
+++ b/generator/templates/dawn/wire/WireCmd.cpp
@@ -220,7 +220,7 @@
//* Structures might contain more pointers so we need to add their extra size as well.
{% if member.type.category == "structure" %}
for (decltype(memberLength) i = 0; i < memberLength; ++i) {
- {% do assert(member.annotation == "const*", "unhandled annotation: " + member.annotation) %}
+ {% do assert(member.annotation == "const*" or member.annotation == "*", "unhandled annotation: " + member.annotation)%}
result += {{as_cType(member.type.name)}}GetExtraRequiredSize(record.{{as_varName(member.name)}}[i]);
}
{% endif %}
diff --git a/src/dawn/dawn.json b/src/dawn/dawn.json
index d226e01..e891705 100644
--- a/src/dawn/dawn.json
+++ b/src/dawn/dawn.json
@@ -408,15 +408,14 @@
},
"surface capabilities": {
"category": "structure",
- "tags": ["upstream"],
"extensible": "out",
"members": [
{"name": "format count", "type": "size_t"},
- {"name": "formats", "type": "texture format", "annotation": "*"},
+ {"name": "formats", "type": "texture format", "annotation": "const*", "length": "format count"},
{"name": "present mode count", "type": "size_t"},
- {"name": "present modes", "type": "present mode", "annotation": "*"},
+ {"name": "present modes", "type": "present mode", "annotation": "const*", "length": "present mode count"},
{"name": "alpha mode count", "type": "size_t"},
- {"name": "alpha modes", "type": "composite alpha mode", "annotation": "*"}
+ {"name": "alpha modes", "type": "composite alpha mode", "annotation": "const*", "length": "alpha mode count"}
],
"methods": [
{
@@ -428,18 +427,17 @@
},
"surface configuration": {
"category": "structure",
- "tags": ["upstream"],
"extensible": "in",
"members": [
{"name": "device", "type": "device"},
{"name": "format", "type": "texture format"},
- {"name": "usage", "type": "texture usage"},
- {"name": "view format count", "type": "size_t"},
- {"name": "view formats", "type": "texture format", "annotation": "const*"},
- {"name": "alpha mode", "type": "composite alpha mode"},
+ {"name": "usage", "type": "texture usage", "default": "render attachment"},
+ {"name": "view format count", "type": "size_t", "default": 0},
+ {"name": "view formats", "type": "texture format", "annotation": "const*", "length": "view format count"},
+ {"name": "alpha mode", "type": "composite alpha mode", "default": "opaque"},
{"name": "width", "type": "uint32_t"},
{"name": "height", "type": "uint32_t"},
- {"name": "present mode", "type": "present mode"}
+ {"name": "present mode", "type": "present mode", "default": "fifo"}
]
},
"external texture binding entry": {
@@ -1037,7 +1035,6 @@
},
"composite alpha mode": {
"category": "enum",
- "tags": ["upstream"],
"values": [
{"value": 0, "name": "auto"},
{"value": 1, "name": "opaque"},
@@ -3497,7 +3494,6 @@
{
"name": "configure",
"returns": "void",
- "tags": ["upstream"],
"args": [
{"name": "config", "type": "surface configuration", "annotation": "const*"}
]
@@ -3505,7 +3501,6 @@
{
"name": "get capabilities",
"returns": "void",
- "tags": ["upstream"],
"args": [
{"name": "adapter", "type": "adapter"},
{"name": "capabilities", "type": "surface capabilities", "annotation": "*"}
@@ -3514,7 +3509,6 @@
{
"name": "get current texture",
"returns": "void",
- "tags": ["upstream"],
"args": [
{"name": "surface texture", "type": "surface texture", "annotation": "*"}
]
@@ -3529,14 +3523,20 @@
{
"name": "present",
"returns": "void",
- "tags": ["upstream"],
"args": []
},
{
"name": "unconfigure",
"returns": "void",
- "tags": ["upstream"],
"args": []
+ },
+ {
+ "name": "set label",
+ "tags": [],
+ "returns": "void",
+ "args": [
+ {"name": "label", "type": "char", "annotation": "const*", "length": "strlen"}
+ ]
}
]
},
@@ -3655,7 +3655,6 @@
},
"surface texture": {
"category": "structure",
- "tags": ["upstream"],
"members": [
{"name": "texture", "type": "texture"},
{"name": "suboptimal", "type": "bool"},
@@ -3803,7 +3802,6 @@
},
"surface get current texture status": {
"category": "enum",
- "tags": ["upstream"],
"values": [
{"value": 0, "name": "success"},
{"value": 1, "name": "timeout"},
diff --git a/src/dawn/dawn_wire.json b/src/dawn/dawn_wire.json
index f87a712..3f3c7d0e 100644
--- a/src/dawn/dawn_wire.json
+++ b/src/dawn/dawn_wire.json
@@ -243,6 +243,7 @@
"QueueOnSubmittedWorkDoneF",
"QueueWriteBuffer",
"QueueWriteTexture",
+ "SurfaceGetCapabilities",
"SurfaceGetPreferredFormat",
"TextureGetWidth",
"TextureGetHeight",
@@ -263,6 +264,8 @@
"DeviceInjectError",
"InstanceProcessEvents",
"InstanceWaitAny",
+ "SurfaceConfigure",
+ "SurfaceGetCurrentTexture",
"SwapChainGetCurrentTexture"
],
"client_special_objects": [
@@ -274,6 +277,7 @@
"Queue",
"ShaderModule",
"Surface",
+ "SurfaceCapabilities",
"SwapChain",
"Texture"
],
diff --git a/src/dawn/fuzzers/lpmfuzz/dawn_lpm.json b/src/dawn/fuzzers/lpmfuzz/dawn_lpm.json
index 7869115..f039498 100644
--- a/src/dawn/fuzzers/lpmfuzz/dawn_lpm.json
+++ b/src/dawn/fuzzers/lpmfuzz/dawn_lpm.json
@@ -38,7 +38,8 @@
"blocklisted_cmds": [
"surface descriptor from windows core window",
"surface descriptor from windows swap chain panel",
- "surface descriptor from canvas html selector"
+ "surface descriptor from canvas html selector",
+ "surface get current texture"
],
"lpm_info": {
@@ -58,4 +59,4 @@
"invalid object id": 2147483647
}
-}
\ No newline at end of file
+}
diff --git a/src/dawn/native/Adapter.cpp b/src/dawn/native/Adapter.cpp
index 6441adc..5ae7d47 100644
--- a/src/dawn/native/Adapter.cpp
+++ b/src/dawn/native/Adapter.cpp
@@ -75,6 +75,10 @@
return mPhysicalDevice.Get();
}
+const PhysicalDeviceBase* AdapterBase::GetPhysicalDevice() const {
+ return mPhysicalDevice.Get();
+}
+
InstanceBase* AdapterBase::APIGetInstance() const {
InstanceBase* instance = mPhysicalDevice->GetInstance();
DAWN_ASSERT(instance != nullptr);
@@ -379,6 +383,10 @@
return mFeatureLevel;
}
+const std::string& AdapterBase::GetName() const {
+ return mPhysicalDevice->GetName();
+}
+
std::vector<Ref<AdapterBase>> SortAdapters(std::vector<Ref<AdapterBase>> adapters,
const RequestAdapterOptions* options) {
const bool highPerformance =
diff --git a/src/dawn/native/Adapter.h b/src/dawn/native/Adapter.h
index 038de4b..ed2797e 100644
--- a/src/dawn/native/Adapter.h
+++ b/src/dawn/native/Adapter.h
@@ -28,11 +28,13 @@
#ifndef SRC_DAWN_NATIVE_ADAPTER_H_
#define SRC_DAWN_NATIVE_ADAPTER_H_
+#include <string>
#include <utility>
#include <vector>
#include "dawn/common/Ref.h"
#include "dawn/common/RefCounted.h"
+#include "dawn/common/WeakRefSupport.h"
#include "dawn/native/DawnNative.h"
#include "dawn/native/Device.h"
#include "dawn/native/PhysicalDevice.h"
@@ -44,7 +46,7 @@
class TogglesState;
struct SupportedLimits;
-class AdapterBase : public RefCounted {
+class AdapterBase : public RefCounted, public WeakRefSupport<AdapterBase> {
public:
AdapterBase(Ref<PhysicalDeviceBase> physicalDevice,
FeatureLevel featureLevel,
@@ -72,12 +74,16 @@
// Return the underlying PhysicalDevice.
PhysicalDeviceBase* GetPhysicalDevice();
+ const PhysicalDeviceBase* GetPhysicalDevice() const;
// Get the actual toggles state of the adapter.
const TogglesState& GetTogglesState() const;
FeatureLevel GetFeatureLevel() const;
+ // Get a human readable label for the adapter (in practice, the physical device name)
+ const std::string& GetName() const;
+
private:
std::pair<Ref<DeviceBase::DeviceLostEvent>, ResultOrError<Ref<DeviceBase>>> CreateDevice(
const DeviceDescriptor* rawDescriptor);
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp
index 46957d0..bf98503 100644
--- a/src/dawn/native/Device.cpp
+++ b/src/dawn/native/Device.cpp
@@ -1510,7 +1510,18 @@
Ref<SwapChainBase> result;
if (ConsumedError(CreateSwapChain(surface, descriptor), &result,
"calling %s.CreateSwapChain(%s).", this, descriptor)) {
- result = SwapChainBase::MakeError(this, descriptor);
+ SurfaceConfiguration config;
+ config.nextInChain = descriptor->nextInChain;
+ config.device = this;
+ config.width = descriptor->width;
+ config.height = descriptor->height;
+ config.format = descriptor->format;
+ config.usage = descriptor->usage;
+ config.presentMode = descriptor->presentMode;
+ config.viewFormatCount = 0;
+ config.viewFormats = nullptr;
+ config.alphaMode = wgpu::CompositeAlphaMode::Opaque;
+ result = SwapChainBase::MakeError(this, &config);
}
return ReturnToAPI(std::move(result));
}
@@ -2205,15 +2216,31 @@
ResultOrError<Ref<SwapChainBase>> DeviceBase::CreateSwapChain(
Surface* surface,
const SwapChainDescriptor* descriptor) {
+ EmitDeprecationWarning(
+ "The explicit creation of a SwapChain object is deprecated and should be replaced by "
+ "Surface configuration.");
+
DAWN_TRY(ValidateIsAlive());
if (IsValidationEnabled()) {
DAWN_TRY_CONTEXT(ValidateSwapChainDescriptor(this, surface, descriptor), "validating %s",
descriptor);
}
+ SurfaceConfiguration config;
+ config.nextInChain = descriptor->nextInChain;
+ config.device = this;
+ config.width = descriptor->width;
+ config.height = descriptor->height;
+ config.format = descriptor->format;
+ config.usage = descriptor->usage;
+ config.presentMode = descriptor->presentMode;
+ config.viewFormatCount = 0;
+ config.viewFormats = nullptr;
+ config.alphaMode = wgpu::CompositeAlphaMode::Opaque;
+
SwapChainBase* previousSwapChain = surface->GetAttachedSwapChain();
ResultOrError<Ref<SwapChainBase>> maybeNewSwapChain =
- CreateSwapChainImpl(surface, previousSwapChain, descriptor);
+ CreateSwapChainImpl(surface, previousSwapChain, &config);
if (previousSwapChain != nullptr) {
previousSwapChain->DetachFromSurface();
@@ -2227,6 +2254,13 @@
return newSwapChain;
}
+ResultOrError<Ref<SwapChainBase>> DeviceBase::CreateSwapChain(Surface* surface,
+ SwapChainBase* previousSwapChain,
+ const SurfaceConfiguration* config) {
+ // Nothing to validate here as it is done in Surface::Configure
+ return CreateSwapChainImpl(surface, previousSwapChain, config);
+}
+
ResultOrError<Ref<TextureBase>> DeviceBase::CreateTexture(const TextureDescriptor* descriptorOrig) {
DAWN_TRY(ValidateIsAlive());
diff --git a/src/dawn/native/Device.h b/src/dawn/native/Device.h
index 715767e..36334ed 100644
--- a/src/dawn/native/Device.h
+++ b/src/dawn/native/Device.h
@@ -228,8 +228,13 @@
ResultOrError<Ref<ShaderModuleBase>> CreateShaderModule(
const ShaderModuleDescriptor* descriptor,
std::unique_ptr<OwnedCompilationMessages>* compilationMessages = nullptr);
+ // Deprecated: this was the way to create a SwapChain when it was explicitly manipulated by the
+ // end user.
ResultOrError<Ref<SwapChainBase>> CreateSwapChain(Surface* surface,
const SwapChainDescriptor* descriptor);
+ ResultOrError<Ref<SwapChainBase>> CreateSwapChain(Surface* surface,
+ SwapChainBase* previousSwapChain,
+ const SurfaceConfiguration* config);
ResultOrError<Ref<TextureBase>> CreateTexture(const TextureDescriptor* rawDescriptor);
ResultOrError<Ref<TextureViewBase>> CreateTextureView(TextureBase* texture,
const TextureViewDescriptor* descriptor);
@@ -268,6 +273,7 @@
ShaderModuleBase* APICreateShaderModule(const ShaderModuleDescriptor* descriptor);
ShaderModuleBase* APICreateErrorShaderModule(const ShaderModuleDescriptor* descriptor,
const char* errorMessage);
+ // TODO(crbug.com/dawn/2320): Remove after deprecation.
SwapChainBase* APICreateSwapChain(Surface* surface, const SwapChainDescriptor* descriptor);
TextureBase* APICreateTexture(const TextureDescriptor* descriptor);
@@ -480,7 +486,7 @@
virtual ResultOrError<Ref<SwapChainBase>> CreateSwapChainImpl(
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) = 0;
+ const SurfaceConfiguration* config) = 0;
virtual ResultOrError<Ref<TextureBase>> CreateTextureImpl(
const UnpackedPtr<TextureDescriptor>& descriptor) = 0;
virtual ResultOrError<Ref<TextureViewBase>> CreateTextureViewImpl(
diff --git a/src/dawn/native/PhysicalDevice.h b/src/dawn/native/PhysicalDevice.h
index 2c1861f..68494b7 100644
--- a/src/dawn/native/PhysicalDevice.h
+++ b/src/dawn/native/PhysicalDevice.h
@@ -49,6 +49,13 @@
class DeviceBase;
+// Structure that holds surface capabilities for a (Surface, PhysicalDevice) pair.
+struct PhysicalDeviceSurfaceCapabilities {
+ std::vector<wgpu::TextureFormat> formats;
+ std::vector<wgpu::PresentMode> presentModes;
+ std::vector<wgpu::CompositeAlphaMode> alphaModes;
+};
+
struct FeatureValidationResult {
// Constructor of successful result
FeatureValidationResult();
@@ -118,6 +125,9 @@
wgpu::TextureFormat format,
UnpackedPtr<FormatCapabilities>& capabilities) const;
+ virtual ResultOrError<PhysicalDeviceSurfaceCapabilities> GetSurfaceCapabilities(
+ const Surface* surface) const = 0;
+
protected:
uint32_t mVendorId = 0xFFFFFFFF;
std::string mVendorName;
diff --git a/src/dawn/native/Surface.cpp b/src/dawn/native/Surface.cpp
index 8929dd6..b1ea52c 100644
--- a/src/dawn/native/Surface.cpp
+++ b/src/dawn/native/Surface.cpp
@@ -27,10 +27,17 @@
#include "dawn/native/Surface.h"
+#include <memory>
+#include <string>
+#include <utility>
+
#include "dawn/common/Platform.h"
#include "dawn/native/ChainUtils.h"
+#include "dawn/native/Device.h"
#include "dawn/native/Instance.h"
#include "dawn/native/SwapChain.h"
+#include "dawn/native/ValidationUtils_autogen.h"
+#include "dawn/native/utils/WGPUHelpers.h"
#if defined(DAWN_USE_WINDOWS_UI)
#include <windows.ui.core.h>
@@ -186,6 +193,111 @@
}
}
+MaybeError ValidateSurfaceConfiguration(DeviceBase* device,
+ const PhysicalDeviceSurfaceCapabilities& capabilities,
+ const SurfaceConfiguration* config,
+ const Surface* surface) {
+ UnpackedPtr<SurfaceConfiguration> unpacked;
+ DAWN_TRY_ASSIGN(unpacked, ValidateAndUnpack(config));
+
+ DAWN_TRY(config->device->ValidateIsAlive());
+
+ const Format* format = nullptr;
+ DAWN_TRY_ASSIGN(format, device->GetInternalFormat(config->format));
+ DAWN_ASSERT(format != nullptr);
+
+ // TODO(crbug.com/dawn/160): Lift this restriction once
+ // wgpu::Instance::GetPreferredSurfaceFormat is implemented.
+ // TODO(dawn:286):
+#if DAWN_PLATFORM_IS(ANDROID)
+ constexpr wgpu::TextureFormat kRequireSwapChainFormat = wgpu::TextureFormat::RGBA8Unorm;
+#else
+ constexpr wgpu::TextureFormat kRequireSwapChainFormat = wgpu::TextureFormat::BGRA8Unorm;
+#endif // !DAWN_PLATFORM_IS(ANDROID)
+ DAWN_INVALID_IF(config->format != kRequireSwapChainFormat,
+ "Format (%s) is not %s, which is (currently) the only accepted format.",
+ config->format, kRequireSwapChainFormat);
+
+ if (device->HasFeature(Feature::SurfaceCapabilities)) {
+ wgpu::TextureUsage validUsage;
+ DAWN_TRY_ASSIGN(validUsage, device->GetSupportedSurfaceUsage(surface));
+ DAWN_INVALID_IF(
+ !IsSubset(config->usage, validUsage),
+ "Usage (%s) is not supported, %s are (currently) the only accepted usage flags.",
+ config->usage, validUsage);
+ } else {
+ DAWN_INVALID_IF(config->usage != wgpu::TextureUsage::RenderAttachment,
+ "Usage (%s) is not %s, which is (currently) the only accepted usage. Other "
+ "usage flags require enabling %s",
+ config->usage, wgpu::TextureUsage::RenderAttachment,
+ wgpu::FeatureName::SurfaceCapabilities);
+ }
+
+ for (size_t i = 0; i < config->viewFormatCount; ++i) {
+ const wgpu::TextureFormat apiViewFormat = config->viewFormats[i];
+ const Format* viewFormat = nullptr;
+ DAWN_TRY_ASSIGN(viewFormat, device->GetInternalFormat(apiViewFormat));
+ DAWN_ASSERT(viewFormat != nullptr);
+
+ DAWN_INVALID_IF(std::find(capabilities.formats.begin(), capabilities.formats.end(),
+ apiViewFormat) == capabilities.formats.end(),
+ "View format (%s) is not supported by the adapter (%s) for this surface.",
+ apiViewFormat, device->GetAdapter());
+ }
+
+ DAWN_TRY(ValidatePresentMode(config->presentMode));
+
+ // Check that config matches capabilities
+ auto formatIt =
+ std::find(capabilities.formats.begin(), capabilities.formats.end(), config->format);
+ DAWN_INVALID_IF(formatIt == capabilities.formats.end(),
+ "Format (%s) is not supported by the adapter (%s) for this surface.",
+ config->format, config->device->GetAdapter());
+
+ auto presentModeIt = std::find(capabilities.presentModes.begin(),
+ capabilities.presentModes.end(), config->presentMode);
+ DAWN_INVALID_IF(presentModeIt == capabilities.presentModes.end(),
+ "Present mode (%s) is not supported by the adapter (%s) for this surface.",
+ config->format, config->device->GetAdapter());
+
+ auto alphaModeIt = std::find(capabilities.alphaModes.begin(), capabilities.alphaModes.end(),
+ config->alphaMode);
+ DAWN_INVALID_IF(alphaModeIt == capabilities.alphaModes.end(),
+ "Alpha mode (%s) is not supported by the adapter (%s) for this surface.",
+ config->format, config->device->GetAdapter());
+
+ DAWN_INVALID_IF(config->width == 0 || config->height == 0,
+ "Surface configuration size (width: %u, height: %u) is empty.", config->width,
+ config->height);
+
+ DAWN_INVALID_IF(
+ config->width > device->GetLimits().v1.maxTextureDimension2D ||
+ config->height > device->GetLimits().v1.maxTextureDimension2D,
+ "Surface configuration size (width: %u, height: %u) is greater than the maximum 2D texture "
+ "size (width: %u, height: %u).",
+ config->width, config->height, device->GetLimits().v1.maxTextureDimension2D,
+ device->GetLimits().v1.maxTextureDimension2D);
+
+ return {};
+}
+
+class AdapterSurfaceCapCache {
+ public:
+ template <typename F>
+ MaybeError WithAdapterCapabilities(AdapterBase* adapter, const Surface* surface, F f) {
+ if (mCachedCapabilitiesAdapter.Promote().Get() != adapter) {
+ const PhysicalDeviceBase* physicalDevice = adapter->GetPhysicalDevice();
+ DAWN_TRY_ASSIGN(mCachedCapabilities, physicalDevice->GetSurfaceCapabilities(surface));
+ mCachedCapabilitiesAdapter = GetWeakRef(adapter);
+ }
+ return f(mCachedCapabilities);
+ }
+
+ private:
+ WeakRef<AdapterBase> mCachedCapabilitiesAdapter = nullptr;
+ PhysicalDeviceSurfaceCapabilities mCachedCapabilities;
+};
+
// static
Ref<Surface> Surface::MakeError(InstanceBase* instance) {
return AcquireRef(new Surface(instance, ErrorMonad::kError));
@@ -194,7 +306,13 @@
Surface::Surface(InstanceBase* instance, ErrorTag tag) : ErrorMonad(tag), mInstance(instance) {}
Surface::Surface(InstanceBase* instance, const UnpackedPtr<SurfaceDescriptor>& descriptor)
- : ErrorMonad(), mInstance(instance) {
+ : ErrorMonad(),
+ mInstance(instance),
+ mCapabilityCache(std::make_unique<AdapterSurfaceCapCache>()) {
+ if (descriptor->label != nullptr && strlen(descriptor->label) != 0) {
+ mLabel = descriptor->label;
+ }
+
// Type is validated in validation, otherwise this may crash with an assert failure.
wgpu::SType type = descriptor
.ValidateBranches<Branch<SurfaceDescriptorFromAndroidNativeWindow>,
@@ -260,18 +378,29 @@
Surface::~Surface() {
if (mSwapChain != nullptr) {
- mSwapChain->DetachFromSurface();
- mSwapChain = nullptr;
+ [[maybe_unused]] bool error = mInstance->ConsumedError(Unconfigure());
+ }
+
+ if (mRecycledSwapChain != nullptr) {
+ mRecycledSwapChain->DetachFromSurface();
+ mRecycledSwapChain = nullptr;
}
}
SwapChainBase* Surface::GetAttachedSwapChain() {
DAWN_ASSERT(!IsError());
+ DAWN_ASSERT(mIsSwapChainManagedBySurface == ManagesSwapChain::Unknown ||
+ mIsSwapChainManagedBySurface == ManagesSwapChain::No);
+ mIsSwapChainManagedBySurface = ManagesSwapChain::No;
+
return mSwapChain.Get();
}
-
void Surface::SetAttachedSwapChain(SwapChainBase* swapChain) {
DAWN_ASSERT(!IsError());
+ DAWN_ASSERT(mIsSwapChainManagedBySurface == ManagesSwapChain::Unknown ||
+ mIsSwapChainManagedBySurface == ManagesSwapChain::No);
+ mIsSwapChainManagedBySurface = ManagesSwapChain::No;
+
mSwapChain = swapChain;
}
@@ -279,6 +408,10 @@
return mInstance.Get();
}
+DeviceBase* Surface::GetCurrentDevice() const {
+ return mCurrentDevice.Get();
+}
+
Surface::Type Surface::GetType() const {
DAWN_ASSERT(!IsError());
return mType;
@@ -348,13 +481,203 @@
return mXWindow;
}
+MaybeError Surface::Configure(const SurfaceConfiguration* config) {
+ DAWN_INVALID_IF(IsError(), "%s is invalid.", this);
+ mCurrentDevice = config->device; // next errors are routed to the new device
+ DAWN_INVALID_IF(mIsSwapChainManagedBySurface == ManagesSwapChain::No,
+ "%s cannot be configured because it is used by legacy swapchain %s.", this,
+ mSwapChain.Get());
+
+ mIsSwapChainManagedBySurface = ManagesSwapChain::Yes;
+
+ DAWN_TRY(mCapabilityCache->WithAdapterCapabilities(
+ GetCurrentDevice()->GetAdapter(), this,
+ [&](const PhysicalDeviceSurfaceCapabilities& caps) -> MaybeError {
+ return ValidateSurfaceConfiguration(GetCurrentDevice(), caps, config, this);
+ }));
+
+ // Reuse either the current swapchain, or the recycled swap chain
+ SwapChainBase* previousSwapChain = mSwapChain.Get();
+ if (previousSwapChain == nullptr && mRecycledSwapChain != nullptr &&
+ mRecycledSwapChain->GetDevice() == config->device) {
+ previousSwapChain = mRecycledSwapChain.Get();
+ }
+
+ {
+ auto deviceLock(GetCurrentDevice()->GetScopedLock());
+ ResultOrError<Ref<SwapChainBase>> maybeNewSwapChain =
+ GetCurrentDevice()->CreateSwapChain(this, previousSwapChain, config);
+
+ // Don't keep swap chains older than 1 call to Configure
+ if (mRecycledSwapChain) {
+ mRecycledSwapChain->DetachFromSurface();
+ mRecycledSwapChain = nullptr;
+ }
+
+ if (mSwapChain && maybeNewSwapChain.IsSuccess()) {
+ mSwapChain->DetachFromSurface();
+ }
+ DAWN_TRY_ASSIGN(mSwapChain, std::move(maybeNewSwapChain));
+
+ mSwapChain->SetIsAttached();
+ }
+
+ return {};
+}
+
+MaybeError Surface::Unconfigure() {
+ DAWN_INVALID_IF(IsError(), "%s is invalid.", this);
+ DAWN_INVALID_IF(!mSwapChain.Get(), "%s is not configured.", this);
+
+ if (mSwapChain != nullptr) {
+ if (mIsSwapChainManagedBySurface == ManagesSwapChain::Yes) {
+ if (mRecycledSwapChain != nullptr) {
+ mRecycledSwapChain->DetachFromSurface();
+ mRecycledSwapChain = nullptr;
+ }
+ mRecycledSwapChain = mSwapChain;
+ } else {
+ mSwapChain->DetachFromSurface();
+ }
+ mSwapChain = nullptr;
+ }
+
+ return {};
+}
+
+MaybeError Surface::GetCapabilities(AdapterBase* adapter, SurfaceCapabilities* capabilities) const {
+ DAWN_INVALID_IF(IsError(), "%s is invalid.", this);
+
+ DAWN_TRY(mCapabilityCache->WithAdapterCapabilities(
+ adapter, this,
+ [&capabilities](const PhysicalDeviceSurfaceCapabilities& caps) -> MaybeError {
+ capabilities->nextInChain = nullptr;
+ DAWN_TRY(utils::AllocateApiSeqFromStdVector(capabilities->formats,
+ capabilities->formatCount, caps.formats));
+ DAWN_TRY(utils::AllocateApiSeqFromStdVector(
+ capabilities->presentModes, capabilities->presentModeCount, caps.presentModes));
+ DAWN_TRY(utils::AllocateApiSeqFromStdVector(
+ capabilities->alphaModes, capabilities->alphaModeCount, caps.alphaModes));
+ return {};
+ }));
+
+ return {};
+}
+
+void APISurfaceCapabilitiesFreeMembers(WGPUSurfaceCapabilities capabilities) {
+ utils::FreeApiSeq(capabilities.formats, capabilities.formatCount);
+ utils::FreeApiSeq(capabilities.presentModes, capabilities.presentModeCount);
+ utils::FreeApiSeq(capabilities.alphaModes, capabilities.alphaModeCount);
+}
+
+MaybeError Surface::GetCurrentTexture(SurfaceTexture* surfaceTexture) const {
+ DAWN_INVALID_IF(IsError(), "%s is invalid.", this);
+ DAWN_INVALID_IF(!mSwapChain.Get(), "%s is not configured.", this);
+
+ auto deviceLock(GetCurrentDevice()->GetScopedLock());
+ DAWN_TRY_ASSIGN(*surfaceTexture, mSwapChain->GetCurrentTexture());
+
+ return {};
+}
+
+ResultOrError<wgpu::TextureFormat> Surface::GetPreferredFormat(AdapterBase* adapter) const {
+ wgpu::TextureFormat format = wgpu::TextureFormat::Undefined;
+
+ DAWN_TRY(mCapabilityCache->WithAdapterCapabilities(
+ adapter, this, [&](const PhysicalDeviceSurfaceCapabilities& caps) -> MaybeError {
+ DAWN_INVALID_IF(caps.formats.empty(), "No format is supported by %s for %s.", adapter,
+ this);
+ format = caps.formats.front();
+ return {};
+ }));
+
+ return format;
+}
+
+MaybeError Surface::Present() {
+ DAWN_INVALID_IF(IsError(), "%s is invalid.", this);
+ DAWN_INVALID_IF(!mSwapChain.Get(), "%s is not configured.", this);
+
+ auto deviceLock(GetCurrentDevice()->GetScopedLock());
+ mSwapChain->APIPresent();
+
+ return {};
+}
+
+const std::string& Surface::GetLabel() const {
+ return mLabel;
+}
+
+void Surface::APIConfigure(const SurfaceConfiguration* config) {
+ MaybeError maybeError = Configure(config);
+ if (!GetCurrentDevice()) {
+ [[maybe_unused]] bool error = mInstance->ConsumedError(std::move(maybeError));
+ } else {
+ [[maybe_unused]] bool error = GetCurrentDevice()->ConsumedError(
+ std::move(maybeError), "calling %s.Configure().", this);
+ }
+}
+
+void Surface::APIGetCapabilities(AdapterBase* adapter, SurfaceCapabilities* capabilities) const {
+ MaybeError maybeError = GetCapabilities(adapter, capabilities);
+ if (!GetCurrentDevice()) {
+ [[maybe_unused]] bool error = mInstance->ConsumedError(std::move(maybeError));
+ } else {
+ [[maybe_unused]] bool error = GetCurrentDevice()->ConsumedError(
+ std::move(maybeError), "calling %s.Configure().", this);
+ }
+}
+
+void Surface::APIGetCurrentTexture(SurfaceTexture* surfaceTexture) const {
+ MaybeError maybeError = GetCurrentTexture(surfaceTexture);
+ if (!GetCurrentDevice()) {
+ if (mInstance->ConsumedError(std::move(maybeError))) {
+ // TODO(dawn:2320): This is the closest status to "surface was not configured so there
+ // is no associated device" but SurfaceTexture may change soon upstream.
+ surfaceTexture->status = wgpu::SurfaceGetCurrentTextureStatus::DeviceLost;
+ surfaceTexture->suboptimal = true;
+ surfaceTexture->texture = nullptr;
+ }
+ } else {
+ [[maybe_unused]] bool error = GetCurrentDevice()->ConsumedError(std::move(maybeError));
+ }
+}
+
wgpu::TextureFormat Surface::APIGetPreferredFormat(AdapterBase* adapter) const {
- // This is the only supported format in native mode (see crbug.com/dawn/160).
-#if DAWN_PLATFORM_IS(ANDROID)
- return wgpu::TextureFormat::RGBA8Unorm;
-#else
- return wgpu::TextureFormat::BGRA8Unorm;
-#endif // !DAWN_PLATFORM_IS(ANDROID)
+ ResultOrError<wgpu::TextureFormat> resultOrError = GetPreferredFormat(adapter);
+ wgpu::TextureFormat format;
+ if (!GetCurrentDevice()) {
+ if (mInstance->ConsumedError(std::move(resultOrError), &format)) {
+ return wgpu::TextureFormat::Undefined;
+ }
+ } else if (GetCurrentDevice()->ConsumedError(std::move(resultOrError), &format,
+ "calling %s.GetPreferredFormat(%s).", this,
+ adapter)) {
+ return wgpu::TextureFormat::Undefined;
+ }
+ return format;
+}
+
+void Surface::APIPresent() {
+ MaybeError maybeError = Present();
+ if (!GetCurrentDevice()) {
+ [[maybe_unused]] bool error = mInstance->ConsumedError(std::move(maybeError));
+ } else {
+ [[maybe_unused]] bool error = GetCurrentDevice()->ConsumedError(std::move(maybeError));
+ }
+}
+
+void Surface::APIUnconfigure() {
+ MaybeError maybeError = Unconfigure();
+ if (!GetCurrentDevice()) {
+ [[maybe_unused]] bool error = mInstance->ConsumedError(std::move(maybeError));
+ } else {
+ [[maybe_unused]] bool error = GetCurrentDevice()->ConsumedError(std::move(maybeError));
+ }
+}
+
+void Surface::APISetLabel(const char* label) {
+ mLabel = label;
}
} // namespace dawn::native
diff --git a/src/dawn/native/Surface.h b/src/dawn/native/Surface.h
index 71abec4..f31d908 100644
--- a/src/dawn/native/Surface.h
+++ b/src/dawn/native/Surface.h
@@ -28,6 +28,9 @@
#ifndef SRC_DAWN_NATIVE_SURFACE_H_
#define SRC_DAWN_NATIVE_SURFACE_H_
+#include <memory>
+#include <string>
+
#include "dawn/native/Error.h"
#include "dawn/native/Forward.h"
#include "dawn/native/ObjectBase.h"
@@ -48,10 +51,20 @@
namespace dawn::native {
+struct PhysicalDeviceSurfaceCapabilities;
+
+// Adapter surface capabilities are cached by the surface
+class AdapterSurfaceCapCache;
+
ResultOrError<UnpackedPtr<SurfaceDescriptor>> ValidateSurfaceDescriptor(
InstanceBase* instance,
const SurfaceDescriptor* rawDescriptor);
+MaybeError ValidateSurfaceConfiguration(DeviceBase* device,
+ const PhysicalDeviceSurfaceCapabilities& capabilities,
+ const SurfaceConfiguration* config,
+ const Surface* surface);
+
// A surface is a sum types of all the kind of windows Dawn supports. The OS-specific types
// aren't used because they would cause compilation errors on other OSes (or require
// ObjectiveC).
@@ -63,9 +76,6 @@
Surface(InstanceBase* instance, const UnpackedPtr<SurfaceDescriptor>& descriptor);
- void SetAttachedSwapChain(SwapChainBase* swapChain);
- SwapChainBase* GetAttachedSwapChain();
-
// These are valid to call on all Surfaces.
enum class Type {
AndroidWindow,
@@ -78,6 +88,7 @@
};
Type GetType() const;
InstanceBase* GetInstance() const;
+ DeviceBase* GetCurrentDevice() const;
// Valid to call if the type is MetalLayer
void* GetMetalLayer() const;
@@ -103,19 +114,61 @@
void* GetXDisplay() const;
uint32_t GetXWindow() const;
+ // TODO(dawn:2320): Remove these 2 accessors once the deprecation period is finished and
+ // Device::APICreateSwapChain gets dropped
+ SwapChainBase* GetAttachedSwapChain();
+ void SetAttachedSwapChain(SwapChainBase* swapChain);
+
+ const std::string& GetLabel() const;
+
// Dawn API
+ void APIConfigure(const SurfaceConfiguration* config);
+ void APIGetCapabilities(AdapterBase* adapter, SurfaceCapabilities* capabilities) const;
+ void APIGetCurrentTexture(SurfaceTexture* surfaceTexture) const;
wgpu::TextureFormat APIGetPreferredFormat(AdapterBase* adapter) const;
+ void APIPresent();
+ void APIUnconfigure();
+ void APISetLabel(const char* label);
private:
Surface(InstanceBase* instance, ErrorMonad::ErrorTag tag);
~Surface() override;
+ MaybeError Configure(const SurfaceConfiguration* config);
+ MaybeError Unconfigure();
+
+ MaybeError GetCapabilities(AdapterBase* adapter, SurfaceCapabilities* capabilities) const;
+ MaybeError GetCurrentTexture(SurfaceTexture* surfaceTexture) const;
+ ResultOrError<wgpu::TextureFormat> GetPreferredFormat(AdapterBase* adapter) const;
+ MaybeError Present();
+
Ref<InstanceBase> mInstance;
Type mType;
+ std::string mLabel;
- // The swapchain will set this to null when it is destroyed.
+ // The surface has an associated device only when it is configured
+ Ref<DeviceBase> mCurrentDevice;
+
+ // The swapchain is created when configuring the surface.
Ref<SwapChainBase> mSwapChain;
+ // We keep on storing the previous swap chain after Unconfigure in case we could reuse it
+ Ref<SwapChainBase> mRecycledSwapChain;
+
+ // This ensures that the user does not mix the legacy API (ManagesSwapChain::No, i.e., explicit
+ // call to CreateSwapChain) with the new API (ManagesSwapChain::Yes, i.e., surface.configure).
+ // TODO(dawn:2320): Remove and consider it is always Yes once Device::APICreateSwapChain gets
+ // dropped
+ enum class ManagesSwapChain {
+ Yes,
+ No,
+ Unknown,
+ };
+ ManagesSwapChain mIsSwapChainManagedBySurface = ManagesSwapChain::Unknown;
+
+ // A cache is mutable because potentially modified in const-qualified getters
+ std::unique_ptr<AdapterSurfaceCapCache> mCapabilityCache;
+
// MetalLayer
raw_ptr<void> mMetalLayer = nullptr;
diff --git a/src/dawn/native/SwapChain.cpp b/src/dawn/native/SwapChain.cpp
index 3c00d47..8f76306 100644
--- a/src/dawn/native/SwapChain.cpp
+++ b/src/dawn/native/SwapChain.cpp
@@ -28,6 +28,7 @@
#include "dawn/native/SwapChain.h"
#include <utility>
+#include <vector>
#include "dawn/common/Constants.h"
#include "dawn/native/Device.h"
@@ -43,11 +44,11 @@
class ErrorSwapChain final : public SwapChainBase {
public:
- explicit ErrorSwapChain(DeviceBase* device, const SwapChainDescriptor* desc)
- : SwapChainBase(device, desc, ObjectBase::kError) {}
+ explicit ErrorSwapChain(DeviceBase* device, const SurfaceConfiguration* config)
+ : SwapChainBase(device, config, ObjectBase::kError) {}
private:
- ResultOrError<Ref<TextureBase>> GetCurrentTextureImpl() override { DAWN_UNREACHABLE(); }
+ ResultOrError<SwapChainTextureInfo> GetCurrentTextureImpl() override { DAWN_UNREACHABLE(); }
MaybeError PresentImpl() override { DAWN_UNREACHABLE(); }
void DetachFromSurfaceImpl() override { DAWN_UNREACHABLE(); }
};
@@ -109,6 +110,8 @@
desc.dimension = wgpu::TextureDimension::e2D;
desc.size = {swapChain->GetWidth(), swapChain->GetHeight(), 1};
desc.format = swapChain->GetFormat();
+ desc.viewFormatCount = swapChain->GetViewFormats().size();
+ desc.viewFormats = swapChain->GetViewFormats().data();
desc.mipLevelCount = 1;
desc.sampleCount = 1;
@@ -117,38 +120,56 @@
SwapChainBase::SwapChainBase(DeviceBase* device,
Surface* surface,
- const SwapChainDescriptor* descriptor)
+ const SurfaceConfiguration* config)
: ApiObjectBase(device, kLabelNotImplemented),
- mWidth(descriptor->width),
- mHeight(descriptor->height),
- mFormat(descriptor->format),
- mUsage(descriptor->usage),
- mPresentMode(descriptor->presentMode),
+ mWidth(config->width),
+ mHeight(config->height),
+ mFormat(config->format),
+ mUsage(config->usage),
+ mPresentMode(config->presentMode),
+ mAlphaMode(config->alphaMode),
mSurface(surface) {
GetObjectTrackingList()->Track(this);
+ for (uint32_t i = 0; i < config->viewFormatCount; ++i) {
+ if (config->viewFormats[i] == config->format) {
+ // Skip our own format, like texture creations does.
+ continue;
+ }
+ mViewFormats.push_back(config->viewFormats[i]);
+ }
+}
+
+FormatSet SwapChainBase::ComputeViewFormatSet() const {
+ FormatSet viewFormatSet;
+ for (wgpu::TextureFormat format : mViewFormats) {
+ viewFormatSet[GetDevice()->GetValidInternalFormat(format)] = true;
+ }
+ return viewFormatSet;
}
SwapChainBase::~SwapChainBase() {
- if (mCurrentTexture != nullptr) {
- DAWN_ASSERT(mCurrentTexture->IsDestroyed());
+ if (mCurrentTextureInfo.texture != nullptr) {
+ DAWN_ASSERT(mCurrentTextureInfo.texture->IsDestroyed());
}
DAWN_ASSERT(!mAttached);
}
SwapChainBase::SwapChainBase(DeviceBase* device,
- const SwapChainDescriptor* descriptor,
+ const SurfaceConfiguration* config,
ObjectBase::ErrorTag tag)
: ApiObjectBase(device, tag),
- mWidth(descriptor->width),
- mHeight(descriptor->height),
- mFormat(descriptor->format),
- mUsage(descriptor->usage),
- mPresentMode(descriptor->presentMode) {}
+ mWidth(config->width),
+ mHeight(config->height),
+ mFormat(config->format),
+ mUsage(config->usage),
+ mPresentMode(config->presentMode),
+ mAlphaMode(config->alphaMode) {}
// static
-Ref<SwapChainBase> SwapChainBase::MakeError(DeviceBase* device, const SwapChainDescriptor* desc) {
- return AcquireRef(new ErrorSwapChain(device, desc));
+Ref<SwapChainBase> SwapChainBase::MakeError(DeviceBase* device,
+ const SurfaceConfiguration* config) {
+ return AcquireRef(new ErrorSwapChain(device, config));
}
void SwapChainBase::DestroyImpl() {}
@@ -178,14 +199,15 @@
}
TextureBase* SwapChainBase::APIGetCurrentTexture() {
- Ref<TextureBase> result;
+ SurfaceTexture result;
if (GetDevice()->ConsumedError(GetCurrentTexture(), &result, "calling %s.GetCurrentTexture()",
this)) {
TextureDescriptor desc = GetSwapChainBaseTextureDescriptor(this);
- result = TextureBase::MakeError(GetDevice(), &desc);
- SetChildLabel(result.Get());
+ Ref<TextureBase> errorTexture = TextureBase::MakeError(GetDevice(), &desc);
+ SetChildLabel(errorTexture.Get());
+ result.texture = ReturnToAPI(std::move(errorTexture));
}
- return ReturnToAPI(std::move(result));
+ return result.texture;
}
TextureViewBase* SwapChainBase::APIGetCurrentTextureView() {
@@ -198,33 +220,36 @@
return ReturnToAPI(std::move(result));
}
-ResultOrError<Ref<TextureBase>> SwapChainBase::GetCurrentTexture() {
+ResultOrError<SurfaceTexture> SwapChainBase::GetCurrentTexture() {
DAWN_TRY(ValidateGetCurrentTexture());
+ SurfaceTexture surfaceTexture;
- if (mCurrentTexture != nullptr) {
- // Calling GetCurrentTexture always returns a new reference.
- return mCurrentTexture;
+ if (mCurrentTextureInfo.texture == nullptr) {
+ DAWN_TRY_ASSIGN(mCurrentTextureInfo, GetCurrentTextureImpl());
+ SetChildLabel(mCurrentTextureInfo.texture.Get());
+
+ // Check that the return texture matches exactly what was given for this descriptor.
+ DAWN_ASSERT(mCurrentTextureInfo.texture->GetFormat().format == mFormat);
+ DAWN_ASSERT(IsSubset(mUsage, mCurrentTextureInfo.texture->GetUsage()));
+ DAWN_ASSERT(mCurrentTextureInfo.texture->GetDimension() == wgpu::TextureDimension::e2D);
+ DAWN_ASSERT(mCurrentTextureInfo.texture->GetWidth(Aspect::Color) == mWidth);
+ DAWN_ASSERT(mCurrentTextureInfo.texture->GetHeight(Aspect::Color) == mHeight);
+ DAWN_ASSERT(mCurrentTextureInfo.texture->GetNumMipLevels() == 1);
+ DAWN_ASSERT(mCurrentTextureInfo.texture->GetArrayLayers() == 1);
+ DAWN_ASSERT(mCurrentTextureInfo.texture->GetViewFormats() == ComputeViewFormatSet());
}
- DAWN_TRY_ASSIGN(mCurrentTexture, GetCurrentTextureImpl());
- SetChildLabel(mCurrentTexture.Get());
-
- // Check that the return texture matches exactly what was given for this descriptor.
- DAWN_ASSERT(mCurrentTexture->GetFormat().format == mFormat);
- DAWN_ASSERT(IsSubset(mUsage, mCurrentTexture->GetUsage()));
- DAWN_ASSERT(mCurrentTexture->GetDimension() == wgpu::TextureDimension::e2D);
- DAWN_ASSERT(mCurrentTexture->GetWidth(Aspect::Color) == mWidth);
- DAWN_ASSERT(mCurrentTexture->GetHeight(Aspect::Color) == mHeight);
- DAWN_ASSERT(mCurrentTexture->GetNumMipLevels() == 1);
- DAWN_ASSERT(mCurrentTexture->GetArrayLayers() == 1);
-
- return mCurrentTexture;
+ // Calling GetCurrentTexture always returns a new reference.
+ surfaceTexture.texture = Ref<TextureBase>(mCurrentTextureInfo.texture).Detach();
+ surfaceTexture.suboptimal = mCurrentTextureInfo.suboptimal;
+ surfaceTexture.status = mCurrentTextureInfo.status;
+ return surfaceTexture;
}
ResultOrError<Ref<TextureViewBase>> SwapChainBase::GetCurrentTextureView() {
- Ref<TextureBase> currentTexture;
- DAWN_TRY_ASSIGN(currentTexture, GetCurrentTexture());
- return currentTexture->CreateView();
+ SurfaceTexture surfaceTexture;
+ DAWN_TRY_ASSIGN(surfaceTexture, GetCurrentTexture());
+ return surfaceTexture.texture->CreateView();
}
void SwapChainBase::APIPresent() {
@@ -236,8 +261,8 @@
return;
}
- DAWN_ASSERT(mCurrentTexture->IsDestroyed());
- mCurrentTexture = nullptr;
+ DAWN_ASSERT(mCurrentTextureInfo.texture->IsDestroyed());
+ mCurrentTextureInfo.texture = nullptr;
}
uint32_t SwapChainBase::GetWidth() const {
@@ -252,6 +277,10 @@
return mFormat;
}
+const std::vector<wgpu::TextureFormat>& SwapChainBase::GetViewFormats() const {
+ return mViewFormats;
+}
+
wgpu::TextureUsage SwapChainBase::GetUsage() const {
return mUsage;
}
@@ -260,6 +289,10 @@
return mPresentMode;
}
+wgpu::CompositeAlphaMode SwapChainBase::GetAlphaMode() const {
+ return mAlphaMode;
+}
+
Surface* SwapChainBase::GetSurface() const {
return mSurface;
}
@@ -278,7 +311,7 @@
DAWN_INVALID_IF(!mAttached, "Cannot call Present called on detached %s.", this);
- DAWN_INVALID_IF(mCurrentTexture == nullptr,
+ DAWN_INVALID_IF(mCurrentTextureInfo.texture == nullptr,
"GetCurrentTexture was not called on %s this frame prior to calling Present.",
this);
diff --git a/src/dawn/native/SwapChain.h b/src/dawn/native/SwapChain.h
index 20f9ae3..86460d1 100644
--- a/src/dawn/native/SwapChain.h
+++ b/src/dawn/native/SwapChain.h
@@ -28,7 +28,10 @@
#ifndef SRC_DAWN_NATIVE_SWAPCHAIN_H_
#define SRC_DAWN_NATIVE_SWAPCHAIN_H_
+#include <vector>
+
#include "dawn/native/Error.h"
+#include "dawn/native/Format.h"
#include "dawn/native/Forward.h"
#include "dawn/native/ObjectBase.h"
#include "dawn/native/dawn_platform.h"
@@ -36,17 +39,25 @@
namespace dawn::native {
+// TODO(dawn:2320): Remove the SwapChainDescriptor once the deprecation period is finished and
+// APICreateSwapChain gets dropped
MaybeError ValidateSwapChainDescriptor(const DeviceBase* device,
const Surface* surface,
const SwapChainDescriptor* descriptor);
TextureDescriptor GetSwapChainBaseTextureDescriptor(SwapChainBase* swapChain);
+struct SwapChainTextureInfo {
+ Ref<TextureBase> texture;
+ wgpu::Bool suboptimal;
+ wgpu::SurfaceGetCurrentTextureStatus status;
+};
+
class SwapChainBase : public ApiObjectBase {
public:
- SwapChainBase(DeviceBase* device, Surface* surface, const SwapChainDescriptor* descriptor);
+ SwapChainBase(DeviceBase* device, Surface* surface, const SurfaceConfiguration* config);
- static Ref<SwapChainBase> MakeError(DeviceBase* device, const SwapChainDescriptor* descriptor);
+ static Ref<SwapChainBase> MakeError(DeviceBase* device, const SurfaceConfiguration* config);
ObjectType GetType() const override;
// This is called when the swapchain is detached when one of the following happens:
@@ -88,19 +99,27 @@
uint32_t GetWidth() const;
uint32_t GetHeight() const;
wgpu::TextureFormat GetFormat() const;
+ const std::vector<wgpu::TextureFormat>& GetViewFormats() const;
wgpu::TextureUsage GetUsage() const;
wgpu::PresentMode GetPresentMode() const;
+ wgpu::CompositeAlphaMode GetAlphaMode() const;
Surface* GetSurface() const;
bool IsAttached() const;
wgpu::BackendType GetBackendType() const;
+ // The returned texture must match the swapchain descriptor exactly.
+ ResultOrError<SurfaceTexture> GetCurrentTexture();
+
protected:
- SwapChainBase(DeviceBase* device, const SwapChainDescriptor* desc, ObjectBase::ErrorTag tag);
+ SwapChainBase(DeviceBase* device, const SurfaceConfiguration* config, ObjectBase::ErrorTag tag);
~SwapChainBase() override;
void DestroyImpl() override;
private:
void SetChildLabel(ApiObjectBase* child) const;
+ // Get a format set from mViewFormats (equivalent information, but easier to validate the
+ // current texture)
+ FormatSet ComputeViewFormatSet() const;
bool mAttached = false;
uint32_t mWidth;
@@ -108,11 +127,15 @@
wgpu::TextureFormat mFormat;
wgpu::TextureUsage mUsage;
wgpu::PresentMode mPresentMode;
+ // This is not stored as a FormatSet so that it can hold the data pointed to by the
+ // descriptor returned by GetSwapChainBaseTextureDescriptor():
+ std::vector<wgpu::TextureFormat> mViewFormats;
+ wgpu::CompositeAlphaMode mAlphaMode;
// This is a weak reference to the surface. If the surface is destroyed it will call
// DetachFromSurface and mSurface will be updated to nullptr.
raw_ptr<Surface> mSurface = nullptr;
- Ref<TextureBase> mCurrentTexture;
+ SwapChainTextureInfo mCurrentTextureInfo;
MaybeError ValidatePresent() const;
MaybeError ValidateGetCurrentTexture() const;
@@ -120,9 +143,7 @@
// GetCurrentTextureImpl and PresentImpl are guaranteed to be called in an interleaved manner,
// starting with GetCurrentTextureImpl.
- // The returned texture must match the swapchain descriptor exactly.
- ResultOrError<Ref<TextureBase>> GetCurrentTexture();
- virtual ResultOrError<Ref<TextureBase>> GetCurrentTextureImpl() = 0;
+ virtual ResultOrError<SwapChainTextureInfo> GetCurrentTextureImpl() = 0;
ResultOrError<Ref<TextureViewBase>> GetCurrentTextureView();
diff --git a/src/dawn/native/d3d/PhysicalDeviceD3D.cpp b/src/dawn/native/d3d/PhysicalDeviceD3D.cpp
index 926ef45..c9e2753 100644
--- a/src/dawn/native/d3d/PhysicalDeviceD3D.cpp
+++ b/src/dawn/native/d3d/PhysicalDeviceD3D.cpp
@@ -52,6 +52,34 @@
return mBackend;
}
+ResultOrError<PhysicalDeviceSurfaceCapabilities> PhysicalDevice::GetSurfaceCapabilities(
+ const Surface*) const {
+ PhysicalDeviceSurfaceCapabilities capabilities;
+
+ // Formats
+
+ // This is the only supported format in native mode (see crbug.com/dawn/160).
+ capabilities.formats.push_back(wgpu::TextureFormat::BGRA8Unorm);
+
+ // Present Modes
+
+ capabilities.presentModes = {
+ wgpu::PresentMode::Fifo,
+ wgpu::PresentMode::Immediate,
+ wgpu::PresentMode::Mailbox,
+ };
+
+ // Alpha Modes
+
+ capabilities.alphaModes = {
+ wgpu::CompositeAlphaMode::Opaque,
+ wgpu::CompositeAlphaMode::Premultiplied,
+ wgpu::CompositeAlphaMode::Auto,
+ };
+
+ return capabilities;
+}
+
MaybeError PhysicalDevice::InitializeImpl() {
DXGI_ADAPTER_DESC1 adapterDesc;
GetHardwareAdapter()->GetDesc1(&adapterDesc);
diff --git a/src/dawn/native/d3d/PhysicalDeviceD3D.h b/src/dawn/native/d3d/PhysicalDeviceD3D.h
index 6f73b8d..4d69d184 100644
--- a/src/dawn/native/d3d/PhysicalDeviceD3D.h
+++ b/src/dawn/native/d3d/PhysicalDeviceD3D.h
@@ -47,6 +47,9 @@
IDXGIAdapter3* GetHardwareAdapter() const;
Backend* GetBackend() const;
+ ResultOrError<PhysicalDeviceSurfaceCapabilities> GetSurfaceCapabilities(
+ const Surface* surface) const override;
+
protected:
MaybeError InitializeImpl() override;
diff --git a/src/dawn/native/d3d11/DeviceD3D11.cpp b/src/dawn/native/d3d11/DeviceD3D11.cpp
index c673c0d..8262ca0 100644
--- a/src/dawn/native/d3d11/DeviceD3D11.cpp
+++ b/src/dawn/native/d3d11/DeviceD3D11.cpp
@@ -214,11 +214,10 @@
return ShaderModule::Create(this, descriptor, parseResult, compilationMessages);
}
-ResultOrError<Ref<SwapChainBase>> Device::CreateSwapChainImpl(
- Surface* surface,
- SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) {
- return SwapChain::Create(this, surface, previousSwapChain, descriptor);
+ResultOrError<Ref<SwapChainBase>> Device::CreateSwapChainImpl(Surface* surface,
+ SwapChainBase* previousSwapChain,
+ const SurfaceConfiguration* config) {
+ return SwapChain::Create(this, surface, previousSwapChain, config);
}
ResultOrError<Ref<TextureBase>> Device::CreateTextureImpl(
diff --git a/src/dawn/native/d3d11/DeviceD3D11.h b/src/dawn/native/d3d11/DeviceD3D11.h
index b9bc161..a74a559 100644
--- a/src/dawn/native/d3d11/DeviceD3D11.h
+++ b/src/dawn/native/d3d11/DeviceD3D11.h
@@ -129,7 +129,7 @@
ResultOrError<Ref<SwapChainBase>> CreateSwapChainImpl(
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) override;
+ const SurfaceConfiguration* config) override;
ResultOrError<Ref<TextureBase>> CreateTextureImpl(
const UnpackedPtr<TextureDescriptor>& descriptor) override;
ResultOrError<Ref<TextureViewBase>> CreateTextureViewImpl(
diff --git a/src/dawn/native/d3d11/SwapChainD3D11.cpp b/src/dawn/native/d3d11/SwapChainD3D11.cpp
index 8100240..6d2d621 100644
--- a/src/dawn/native/d3d11/SwapChainD3D11.cpp
+++ b/src/dawn/native/d3d11/SwapChainD3D11.cpp
@@ -45,8 +45,8 @@
ResultOrError<Ref<SwapChain>> SwapChain::Create(Device* device,
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) {
- Ref<SwapChain> swapchain = AcquireRef(new SwapChain(device, surface, descriptor));
+ const SurfaceConfiguration* config) {
+ Ref<SwapChain> swapchain = AcquireRef(new SwapChain(device, surface, config));
DAWN_TRY(swapchain->Initialize(previousSwapChain));
return swapchain;
}
@@ -84,12 +84,17 @@
return {};
}
-ResultOrError<Ref<TextureBase>> SwapChain::GetCurrentTextureImpl() {
+ResultOrError<SwapChainTextureInfo> SwapChain::GetCurrentTextureImpl() {
// Create the API side objects for this use of the swapchain's buffer.
TextureDescriptor descriptor = GetSwapChainBaseTextureDescriptor(this);
DAWN_TRY_ASSIGN(mApiTexture,
Texture::Create(ToBackend(GetDevice()), Unpack(&descriptor), mBuffer));
- return mApiTexture;
+ SwapChainTextureInfo info;
+ info.texture = mApiTexture;
+ info.status = wgpu::SurfaceGetCurrentTextureStatus::Success;
+ // TODO(dawn:2320): Check for optimality
+ info.suboptimal = false;
+ return info;
}
MaybeError SwapChain::DetachAndWaitForDeallocation() {
diff --git a/src/dawn/native/d3d11/SwapChainD3D11.h b/src/dawn/native/d3d11/SwapChainD3D11.h
index 58a7d4c..501183d 100644
--- a/src/dawn/native/d3d11/SwapChainD3D11.h
+++ b/src/dawn/native/d3d11/SwapChainD3D11.h
@@ -44,7 +44,7 @@
static ResultOrError<Ref<SwapChain>> Create(Device* device,
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor);
+ const SurfaceConfiguration* config);
private:
using Base = d3d::SwapChain;
@@ -53,7 +53,7 @@
// SwapChainBase implementation
MaybeError PresentImpl() override;
- ResultOrError<Ref<TextureBase>> GetCurrentTextureImpl() override;
+ ResultOrError<SwapChainTextureInfo> GetCurrentTextureImpl() override;
void DetachFromSurfaceImpl() override;
// d3d::SwapChain implementation
diff --git a/src/dawn/native/d3d12/DeviceD3D12.cpp b/src/dawn/native/d3d12/DeviceD3D12.cpp
index 5aea624..90d6ab7 100644
--- a/src/dawn/native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn/native/d3d12/DeviceD3D12.cpp
@@ -400,11 +400,10 @@
OwnedCompilationMessages* compilationMessages) {
return ShaderModule::Create(this, descriptor, parseResult, compilationMessages);
}
-ResultOrError<Ref<SwapChainBase>> Device::CreateSwapChainImpl(
- Surface* surface,
- SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) {
- return SwapChain::Create(this, surface, previousSwapChain, descriptor);
+ResultOrError<Ref<SwapChainBase>> Device::CreateSwapChainImpl(Surface* surface,
+ SwapChainBase* previousSwapChain,
+ const SurfaceConfiguration* config) {
+ return SwapChain::Create(this, surface, previousSwapChain, config);
}
ResultOrError<Ref<TextureBase>> Device::CreateTextureImpl(
const UnpackedPtr<TextureDescriptor>& descriptor) {
diff --git a/src/dawn/native/d3d12/DeviceD3D12.h b/src/dawn/native/d3d12/DeviceD3D12.h
index c34751eb..6024775 100644
--- a/src/dawn/native/d3d12/DeviceD3D12.h
+++ b/src/dawn/native/d3d12/DeviceD3D12.h
@@ -209,7 +209,7 @@
ResultOrError<Ref<SwapChainBase>> CreateSwapChainImpl(
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) override;
+ const SurfaceConfiguration* config) override;
ResultOrError<Ref<TextureBase>> CreateTextureImpl(
const UnpackedPtr<TextureDescriptor>& descriptor) override;
ResultOrError<Ref<TextureViewBase>> CreateTextureViewImpl(
diff --git a/src/dawn/native/d3d12/SwapChainD3D12.cpp b/src/dawn/native/d3d12/SwapChainD3D12.cpp
index 0892149..1e98730 100644
--- a/src/dawn/native/d3d12/SwapChainD3D12.cpp
+++ b/src/dawn/native/d3d12/SwapChainD3D12.cpp
@@ -46,8 +46,8 @@
ResultOrError<Ref<SwapChain>> SwapChain::Create(Device* device,
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) {
- Ref<SwapChain> swapchain = AcquireRef(new SwapChain(device, surface, descriptor));
+ const SurfaceConfiguration* config) {
+ Ref<SwapChain> swapchain = AcquireRef(new SwapChain(device, surface, config));
DAWN_TRY(swapchain->Initialize(previousSwapChain));
return swapchain;
}
@@ -105,7 +105,7 @@
return {};
}
-ResultOrError<Ref<TextureBase>> SwapChain::GetCurrentTextureImpl() {
+ResultOrError<SwapChainTextureInfo> SwapChain::GetCurrentTextureImpl() {
Queue* queue = ToBackend(GetDevice()->GetQueue());
// Synchronously wait until previous operations on the next swapchain buffer are finished.
@@ -119,7 +119,13 @@
TextureDescriptor descriptor = GetSwapChainBaseTextureDescriptor(this);
DAWN_TRY_ASSIGN(mApiTexture, Texture::Create(ToBackend(GetDevice()), Unpack(&descriptor),
mBuffers[mCurrentBuffer]));
- return mApiTexture;
+
+ SwapChainTextureInfo info;
+ info.texture = mApiTexture;
+ info.status = wgpu::SurfaceGetCurrentTextureStatus::Success;
+ // TODO(dawn:2320): Check for optimality
+ info.suboptimal = false;
+ return info;
}
MaybeError SwapChain::DetachAndWaitForDeallocation() {
diff --git a/src/dawn/native/d3d12/SwapChainD3D12.h b/src/dawn/native/d3d12/SwapChainD3D12.h
index eb0569b..b3ecedf 100644
--- a/src/dawn/native/d3d12/SwapChainD3D12.h
+++ b/src/dawn/native/d3d12/SwapChainD3D12.h
@@ -45,7 +45,7 @@
static ResultOrError<Ref<SwapChain>> Create(Device* device,
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor);
+ const SurfaceConfiguration* config);
private:
using Base = d3d::SwapChain;
@@ -54,7 +54,7 @@
// SwapChainBase implementation
MaybeError PresentImpl() override;
- ResultOrError<Ref<TextureBase>> GetCurrentTextureImpl() override;
+ ResultOrError<SwapChainTextureInfo> GetCurrentTextureImpl() override;
void DetachFromSurfaceImpl() override;
// d3d::SwapChain implementation
diff --git a/src/dawn/native/metal/BackendMTL.mm b/src/dawn/native/metal/BackendMTL.mm
index 672d705..de9968a 100644
--- a/src/dawn/native/metal/BackendMTL.mm
+++ b/src/dawn/native/metal/BackendMTL.mm
@@ -303,6 +303,34 @@
bool SupportsFeatureLevel(FeatureLevel) const override { return true; }
+ ResultOrError<PhysicalDeviceSurfaceCapabilities> GetSurfaceCapabilities(
+ const Surface*) const override {
+ PhysicalDeviceSurfaceCapabilities capabilities;
+
+ // Formats
+
+ // This is the only supported format in native mode (see crbug.com/dawn/160).
+ capabilities.formats.push_back(wgpu::TextureFormat::BGRA8Unorm);
+
+ // Present Modes
+
+ capabilities.presentModes = {
+ wgpu::PresentMode::Fifo,
+ wgpu::PresentMode::Immediate,
+ wgpu::PresentMode::Mailbox,
+ };
+
+ // Alpha Modes
+
+ capabilities.alphaModes = {
+ wgpu::CompositeAlphaMode::Opaque,
+ wgpu::CompositeAlphaMode::Premultiplied,
+ wgpu::CompositeAlphaMode::Auto,
+ };
+
+ return capabilities;
+ }
+
private:
ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(
AdapterBase* adapter,
diff --git a/src/dawn/native/metal/DeviceMTL.h b/src/dawn/native/metal/DeviceMTL.h
index 2c8df01..a47ea80 100644
--- a/src/dawn/native/metal/DeviceMTL.h
+++ b/src/dawn/native/metal/DeviceMTL.h
@@ -115,7 +115,7 @@
ResultOrError<Ref<SwapChainBase>> CreateSwapChainImpl(
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) override;
+ const SurfaceConfiguration* config) override;
ResultOrError<Ref<TextureBase>> CreateTextureImpl(
const UnpackedPtr<TextureDescriptor>& descriptor) override;
ResultOrError<Ref<TextureViewBase>> CreateTextureViewImpl(
diff --git a/src/dawn/native/metal/DeviceMTL.mm b/src/dawn/native/metal/DeviceMTL.mm
index 10e9fbb..0a555bf 100644
--- a/src/dawn/native/metal/DeviceMTL.mm
+++ b/src/dawn/native/metal/DeviceMTL.mm
@@ -227,11 +227,10 @@
OwnedCompilationMessages* compilationMessages) {
return ShaderModule::Create(this, descriptor, parseResult, compilationMessages);
}
-ResultOrError<Ref<SwapChainBase>> Device::CreateSwapChainImpl(
- Surface* surface,
- SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) {
- return SwapChain::Create(this, surface, previousSwapChain, descriptor);
+ResultOrError<Ref<SwapChainBase>> Device::CreateSwapChainImpl(Surface* surface,
+ SwapChainBase* previousSwapChain,
+ const SurfaceConfiguration* config) {
+ return SwapChain::Create(this, surface, previousSwapChain, config);
}
ResultOrError<Ref<TextureBase>> Device::CreateTextureImpl(
const UnpackedPtr<TextureDescriptor>& descriptor) {
diff --git a/src/dawn/native/metal/SwapChainMTL.h b/src/dawn/native/metal/SwapChainMTL.h
index 3bf596c..7786310 100644
--- a/src/dawn/native/metal/SwapChainMTL.h
+++ b/src/dawn/native/metal/SwapChainMTL.h
@@ -45,9 +45,9 @@
static ResultOrError<Ref<SwapChain>> Create(Device* device,
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor);
+ const SurfaceConfiguration* config);
- SwapChain(DeviceBase* device, Surface* surface, const SwapChainDescriptor* descriptor);
+ SwapChain(DeviceBase* device, Surface* surface, const SurfaceConfiguration* config);
~SwapChain() override;
private:
@@ -62,7 +62,7 @@
Ref<Texture> mTexture;
MaybeError PresentImpl() override;
- ResultOrError<Ref<TextureBase>> GetCurrentTextureImpl() override;
+ ResultOrError<SwapChainTextureInfo> GetCurrentTextureImpl() override;
void DetachFromSurfaceImpl() override;
};
diff --git a/src/dawn/native/metal/SwapChainMTL.mm b/src/dawn/native/metal/SwapChainMTL.mm
index 981d415..478f726 100644
--- a/src/dawn/native/metal/SwapChainMTL.mm
+++ b/src/dawn/native/metal/SwapChainMTL.mm
@@ -40,14 +40,14 @@
ResultOrError<Ref<SwapChain>> SwapChain::Create(Device* device,
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) {
- Ref<SwapChain> swapchain = AcquireRef(new SwapChain(device, surface, descriptor));
+ const SurfaceConfiguration* config) {
+ Ref<SwapChain> swapchain = AcquireRef(new SwapChain(device, surface, config));
DAWN_TRY(swapchain->Initialize(previousSwapChain));
return swapchain;
}
-SwapChain::SwapChain(DeviceBase* dev, Surface* sur, const SwapChainDescriptor* desc)
- : SwapChainBase(dev, sur, desc) {}
+SwapChain::SwapChain(DeviceBase* dev, Surface* sur, const SurfaceConfiguration* config)
+ : SwapChainBase(dev, sur, config) {}
SwapChain::~SwapChain() = default;
@@ -82,6 +82,9 @@
[*mLayer setDevice:ToBackend(GetDevice())->GetMTLDevice()];
[*mLayer setPixelFormat:MetalPixelFormat(GetDevice(), GetFormat())];
+ // TODO(dawn:2320): Check that this behaves as expected by the spec
+ [*mLayer setOpaque:(GetAlphaMode() != wgpu::CompositeAlphaMode::Premultiplied)];
+
#if DAWN_PLATFORM_IS(MACOS)
[*mLayer setDisplaySyncEnabled:(GetPresentMode() != wgpu::PresentMode::Immediate)];
#endif // DAWN_PLATFORM_IS(MACOS)
@@ -103,7 +106,7 @@
return {};
}
-ResultOrError<Ref<TextureBase>> SwapChain::GetCurrentTextureImpl() {
+ResultOrError<SwapChainTextureInfo> SwapChain::GetCurrentTextureImpl() {
@autoreleasepool {
DAWN_ASSERT(mCurrentDrawable == nullptr);
mCurrentDrawable = [*mLayer nextDrawable];
@@ -112,7 +115,13 @@
mTexture = Texture::CreateWrapping(ToBackend(GetDevice()), Unpack(&textureDesc),
NSPRef<id<MTLTexture>>([*mCurrentDrawable texture]));
- return mTexture;
+
+ SwapChainTextureInfo info;
+ info.texture = mTexture;
+ info.status = wgpu::SurfaceGetCurrentTextureStatus::Success;
+ // TODO(dawn:2320): Check for optimality
+ info.suboptimal = false;
+ return info;
}
}
diff --git a/src/dawn/native/null/DeviceNull.cpp b/src/dawn/native/null/DeviceNull.cpp
index adfc7be..db967bb 100644
--- a/src/dawn/native/null/DeviceNull.cpp
+++ b/src/dawn/native/null/DeviceNull.cpp
@@ -66,6 +66,15 @@
return true;
}
+ResultOrError<PhysicalDeviceSurfaceCapabilities> PhysicalDevice::GetSurfaceCapabilities(
+ const Surface* surface) const {
+ PhysicalDeviceSurfaceCapabilities capabilities;
+ capabilities.formats = {wgpu::TextureFormat::BGRA8Unorm};
+ capabilities.presentModes = {wgpu::PresentMode::Fifo};
+ capabilities.alphaModes = {wgpu::CompositeAlphaMode::Auto};
+ return capabilities;
+}
+
MaybeError PhysicalDevice::InitializeImpl() {
return {};
}
@@ -226,11 +235,10 @@
DAWN_TRY(module->Initialize(parseResult, compilationMessages));
return module;
}
-ResultOrError<Ref<SwapChainBase>> Device::CreateSwapChainImpl(
- Surface* surface,
- SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) {
- return SwapChain::Create(this, surface, previousSwapChain, descriptor);
+ResultOrError<Ref<SwapChainBase>> Device::CreateSwapChainImpl(Surface* surface,
+ SwapChainBase* previousSwapChain,
+ const SurfaceConfiguration* config) {
+ return SwapChain::Create(this, surface, previousSwapChain, config);
}
ResultOrError<Ref<TextureBase>> Device::CreateTextureImpl(
const UnpackedPtr<TextureDescriptor>& descriptor) {
@@ -510,8 +518,8 @@
ResultOrError<Ref<SwapChain>> SwapChain::Create(Device* device,
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) {
- Ref<SwapChain> swapchain = AcquireRef(new SwapChain(device, surface, descriptor));
+ const SurfaceConfiguration* config) {
+ Ref<SwapChain> swapchain = AcquireRef(new SwapChain(device, surface, config));
DAWN_TRY(swapchain->Initialize(previousSwapChain));
return swapchain;
}
@@ -536,10 +544,14 @@
return {};
}
-ResultOrError<Ref<TextureBase>> SwapChain::GetCurrentTextureImpl() {
+ResultOrError<SwapChainTextureInfo> SwapChain::GetCurrentTextureImpl() {
TextureDescriptor textureDesc = GetSwapChainBaseTextureDescriptor(this);
mTexture = AcquireRef(new Texture(GetDevice(), Unpack(&textureDesc)));
- return mTexture;
+ SwapChainTextureInfo info;
+ info.texture = mTexture;
+ info.status = wgpu::SurfaceGetCurrentTextureStatus::Success;
+ info.suboptimal = false;
+ return info;
}
void SwapChain::DetachFromSurfaceImpl() {
diff --git a/src/dawn/native/null/DeviceNull.h b/src/dawn/native/null/DeviceNull.h
index 694e049..b497460 100644
--- a/src/dawn/native/null/DeviceNull.h
+++ b/src/dawn/native/null/DeviceNull.h
@@ -165,7 +165,7 @@
ResultOrError<Ref<SwapChainBase>> CreateSwapChainImpl(
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) override;
+ const SurfaceConfiguration* config) override;
ResultOrError<Ref<TextureBase>> CreateTextureImpl(
const UnpackedPtr<TextureDescriptor>& descriptor) override;
ResultOrError<Ref<TextureViewBase>> CreateTextureViewImpl(
@@ -195,6 +195,9 @@
bool SupportsFeatureLevel(FeatureLevel featureLevel) const override;
+ ResultOrError<PhysicalDeviceSurfaceCapabilities> GetSurfaceCapabilities(
+ const Surface* surface) const override;
+
// Used for the tests that intend to use an adapter without all features enabled.
using PhysicalDeviceBase::SetSupportedFeaturesForTesting;
@@ -324,7 +327,7 @@
static ResultOrError<Ref<SwapChain>> Create(Device* device,
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor);
+ const SurfaceConfiguration* config);
~SwapChain() override;
private:
@@ -334,7 +337,7 @@
Ref<Texture> mTexture;
MaybeError PresentImpl() override;
- ResultOrError<Ref<TextureBase>> GetCurrentTextureImpl() override;
+ ResultOrError<SwapChainTextureInfo> GetCurrentTextureImpl() override;
void DetachFromSurfaceImpl() override;
};
diff --git a/src/dawn/native/opengl/DeviceGL.cpp b/src/dawn/native/opengl/DeviceGL.cpp
index 7293d47..691b9e4 100644
--- a/src/dawn/native/opengl/DeviceGL.cpp
+++ b/src/dawn/native/opengl/DeviceGL.cpp
@@ -261,10 +261,9 @@
OwnedCompilationMessages* compilationMessages) {
return ShaderModule::Create(this, descriptor, parseResult, compilationMessages);
}
-ResultOrError<Ref<SwapChainBase>> Device::CreateSwapChainImpl(
- Surface* surface,
- SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) {
+ResultOrError<Ref<SwapChainBase>> Device::CreateSwapChainImpl(Surface* surface,
+ SwapChainBase* previousSwapChain,
+ const SurfaceConfiguration* config) {
return DAWN_VALIDATION_ERROR("New swapchains not implemented.");
}
ResultOrError<Ref<TextureBase>> Device::CreateTextureImpl(
diff --git a/src/dawn/native/opengl/DeviceGL.h b/src/dawn/native/opengl/DeviceGL.h
index 1302ef7..0e312ca 100644
--- a/src/dawn/native/opengl/DeviceGL.h
+++ b/src/dawn/native/opengl/DeviceGL.h
@@ -132,7 +132,7 @@
ResultOrError<Ref<SwapChainBase>> CreateSwapChainImpl(
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) override;
+ const SurfaceConfiguration* config) override;
ResultOrError<Ref<TextureBase>> CreateTextureImpl(
const UnpackedPtr<TextureDescriptor>& descriptor) override;
ResultOrError<Ref<TextureViewBase>> CreateTextureViewImpl(
diff --git a/src/dawn/native/opengl/PhysicalDeviceGL.cpp b/src/dawn/native/opengl/PhysicalDeviceGL.cpp
index b9a14a7..147c1a7 100644
--- a/src/dawn/native/opengl/PhysicalDeviceGL.cpp
+++ b/src/dawn/native/opengl/PhysicalDeviceGL.cpp
@@ -452,6 +452,37 @@
return featureLevel == FeatureLevel::Compatibility;
}
+ResultOrError<PhysicalDeviceSurfaceCapabilities> PhysicalDevice::GetSurfaceCapabilities(
+ const Surface*) const {
+ PhysicalDeviceSurfaceCapabilities capabilities;
+
+ // Formats
+
+ // This is the only supported format in native mode (see crbug.com/dawn/160).
+#if DAWN_PLATFORM_IS(ANDROID)
+ capabilities.formats.push_back(wgpu::TextureFormat::RGBA8Unorm);
+#else
+ capabilities.formats.push_back(wgpu::TextureFormat::BGRA8Unorm);
+#endif // !DAWN_PLATFORM_IS(ANDROID)
+
+ // Present Modes
+
+ capabilities.presentModes = {
+ wgpu::PresentMode::Fifo,
+ wgpu::PresentMode::Immediate,
+ wgpu::PresentMode::Mailbox,
+ };
+
+ // Alpha Modes
+
+ capabilities.alphaModes = {
+ wgpu::CompositeAlphaMode::Opaque,
+ wgpu::CompositeAlphaMode::Auto,
+ };
+
+ return capabilities;
+}
+
FeatureValidationResult PhysicalDevice::ValidateFeatureSupportedWithTogglesImpl(
wgpu::FeatureName feature,
const TogglesState& toggles) const {
diff --git a/src/dawn/native/opengl/PhysicalDeviceGL.h b/src/dawn/native/opengl/PhysicalDeviceGL.h
index 2dda6e9..ac0fa7a 100644
--- a/src/dawn/native/opengl/PhysicalDeviceGL.h
+++ b/src/dawn/native/opengl/PhysicalDeviceGL.h
@@ -46,6 +46,8 @@
// PhysicalDeviceBase Implementation
bool SupportsExternalImages() const override;
bool SupportsFeatureLevel(FeatureLevel featureLevel) const override;
+ ResultOrError<PhysicalDeviceSurfaceCapabilities> GetSurfaceCapabilities(
+ const Surface* surface) const override;
private:
PhysicalDevice(InstanceBase* instance, wgpu::BackendType backendType, EGLDisplay display);
diff --git a/src/dawn/native/utils/WGPUHelpers.h b/src/dawn/native/utils/WGPUHelpers.h
index 376f774..5790df7 100644
--- a/src/dawn/native/utils/WGPUHelpers.h
+++ b/src/dawn/native/utils/WGPUHelpers.h
@@ -136,6 +136,31 @@
const char* GetLabelForTrace(const char* label);
+// Given a std vector, allocate an equivalent array that can be returned in an API's foos/fooCount
+// pair of fields. The apiData must eventually be freed using FreeApiSeq.
+template <typename T>
+inline MaybeError AllocateApiSeqFromStdVector(const T*& apiData,
+ size_t& apiSize,
+ const std::vector<T>& vector) {
+ apiSize = vector.size();
+ if (apiSize > 0) {
+ T* mutableData = new T[apiSize];
+ memcpy(mutableData, vector.data(), apiSize * sizeof(T));
+ apiData = mutableData;
+ } else {
+ apiData = nullptr;
+ }
+ return {};
+}
+
+// Free an API sequence that was allocated by AllocateApiSeqFromStdVector
+template <typename T>
+inline void FreeApiSeq(T*& apiData, size_t& apiSize) {
+ delete[] apiData;
+ apiData = nullptr;
+ apiSize = 0;
+}
+
} // namespace dawn::native::utils
#endif // SRC_DAWN_NATIVE_UTILS_WGPUHELPERS_H_
diff --git a/src/dawn/native/vulkan/DeviceVk.cpp b/src/dawn/native/vulkan/DeviceVk.cpp
index 265185c..c6c96ea 100644
--- a/src/dawn/native/vulkan/DeviceVk.cpp
+++ b/src/dawn/native/vulkan/DeviceVk.cpp
@@ -215,11 +215,10 @@
OwnedCompilationMessages* compilationMessages) {
return ShaderModule::Create(this, descriptor, parseResult, compilationMessages);
}
-ResultOrError<Ref<SwapChainBase>> Device::CreateSwapChainImpl(
- Surface* surface,
- SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) {
- return SwapChain::Create(this, surface, previousSwapChain, descriptor);
+ResultOrError<Ref<SwapChainBase>> Device::CreateSwapChainImpl(Surface* surface,
+ SwapChainBase* previousSwapChain,
+ const SurfaceConfiguration* config) {
+ return SwapChain::Create(this, surface, previousSwapChain, config);
}
ResultOrError<Ref<TextureBase>> Device::CreateTextureImpl(
const UnpackedPtr<TextureDescriptor>& descriptor) {
diff --git a/src/dawn/native/vulkan/DeviceVk.h b/src/dawn/native/vulkan/DeviceVk.h
index ab716ff..57d4e76 100644
--- a/src/dawn/native/vulkan/DeviceVk.h
+++ b/src/dawn/native/vulkan/DeviceVk.h
@@ -148,7 +148,7 @@
ResultOrError<Ref<SwapChainBase>> CreateSwapChainImpl(
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) override;
+ const SurfaceConfiguration* config) override;
ResultOrError<Ref<TextureBase>> CreateTextureImpl(
const UnpackedPtr<TextureDescriptor>& descriptor) override;
ResultOrError<Ref<TextureViewBase>> CreateTextureViewImpl(
diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
index ce58ea0..7966619 100644
--- a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
+++ b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
@@ -37,8 +37,10 @@
#include "dawn/native/Limits.h"
#include "dawn/native/vulkan/BackendVk.h"
#include "dawn/native/vulkan/DeviceVk.h"
+#include "dawn/native/vulkan/SwapChainVk.h"
#include "dawn/native/vulkan/TextureVk.h"
#include "dawn/native/vulkan/UtilsVulkan.h"
+#include "dawn/native/vulkan/VulkanError.h"
#include "dawn/platform/DawnPlatform.h"
#if DAWN_PLATFORM_IS(ANDROID)
@@ -858,6 +860,81 @@
return mDefaultComputeSubgroupSize;
}
+ResultOrError<PhysicalDeviceSurfaceCapabilities> PhysicalDevice::GetSurfaceCapabilities(
+ const Surface* surface) const {
+ PhysicalDeviceSurfaceCapabilities capabilities;
+
+ // Formats
+
+ // This is the only supported format in native mode (see crbug.com/dawn/160).
+#if DAWN_PLATFORM_IS(ANDROID)
+ capabilities.formats.push_back(wgpu::TextureFormat::RGBA8Unorm);
+#else
+ capabilities.formats.push_back(wgpu::TextureFormat::BGRA8Unorm);
+#endif // !DAWN_PLATFORM_IS(ANDROID)
+
+ // Present Modes
+
+ // TODO(dawn:2320): Other present modes than Mailbox do not pass tests on Intel Graphics. Once
+ // 'surface' will actually contain a vkSurface we'll be able to test
+ // vkGetPhysicalDeviceSurfaceSupportKHR to avoid this #if.
+#if DAWN_PLATFORM_IS(LINUX)
+ capabilities.presentModes = {
+ wgpu::PresentMode::Mailbox,
+ };
+#else
+ capabilities.presentModes = {
+ wgpu::PresentMode::Fifo,
+ wgpu::PresentMode::Immediate,
+ wgpu::PresentMode::Mailbox,
+ };
+#endif // !DAWN_PLATFORM_IS(LINUX)
+
+ // Alpha Modes
+
+#if !DAWN_PLATFORM_IS(ANDROID)
+ capabilities.alphaModes.push_back(wgpu::CompositeAlphaMode::Opaque);
+#else
+ VkSurfaceKHR vkSurface;
+ DAWN_TRY_ASSIGN(vkSurface, CreateVulkanSurface(this, surface));
+
+ VkPhysicalDevice vkPhysicalDevice = GetVkPhysicalDevice();
+ const VulkanFunctions& fn = GetVulkanInstance()->GetFunctions();
+ VkInstance vkInstance = GetVulkanInstance()->GetVkInstance();
+ const VulkanFunctions& vkFunctions = GetVulkanInstance()->GetFunctions();
+
+ // Get the surface capabilities
+ VkSurfaceCapabilitiesKHR vkCapabilities;
+ DAWN_TRY_WITH_CLEANUP(CheckVkSuccess(vkFunctions.GetPhysicalDeviceSurfaceCapabilitiesKHR(
+ vkPhysicalDevice, vkSurface, &vkCapabilities),
+ "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"),
+ { fn.DestroySurfaceKHR(vkInstance, vkSurface, nullptr); });
+
+ fn.DestroySurfaceKHR(vkInstance, vkSurface, nullptr);
+
+ // TODO(dawn:286): investigate composite alpha for WebGPU native
+ struct AlphaModePairs {
+ VkCompositeAlphaFlagBitsKHR vkBit;
+ wgpu::CompositeAlphaMode webgpuEnum;
+ };
+ AlphaModePairs alphaModePairs[] = {
+ {VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, wgpu::CompositeAlphaMode::Opaque},
+ {VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, wgpu::CompositeAlphaMode::Premultiplied},
+ {VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, wgpu::CompositeAlphaMode::Unpremultiplied},
+ {VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, wgpu::CompositeAlphaMode::Inherit},
+ };
+
+ for (auto mode : alphaModePairs) {
+ if (vkCapabilities.supportedCompositeAlpha & mode.vkBit) {
+ capabilities.alphaModes.push_back(mode.webgpuEnum);
+ }
+ }
+#endif // #if !DAWN_PLATFORM_IS(ANDROID)
+ capabilities.alphaModes.push_back(wgpu::CompositeAlphaMode::Auto);
+
+ return capabilities;
+}
+
void PhysicalDevice::PopulateBackendProperties(UnpackedPtr<AdapterProperties>& properties) const {
if (auto* memoryHeapProperties = properties.Get<AdapterPropertiesMemoryHeaps>()) {
size_t count = mDeviceInfo.memoryHeaps.size();
diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.h b/src/dawn/native/vulkan/PhysicalDeviceVk.h
index b40f0b1..d4fe78a 100644
--- a/src/dawn/native/vulkan/PhysicalDeviceVk.h
+++ b/src/dawn/native/vulkan/PhysicalDeviceVk.h
@@ -61,6 +61,9 @@
uint32_t GetDefaultComputeSubgroupSize() const;
+ ResultOrError<PhysicalDeviceSurfaceCapabilities> GetSurfaceCapabilities(
+ const Surface* surface) const override;
+
private:
MaybeError InitializeImpl() override;
void InitializeSupportedFeaturesImpl() override;
diff --git a/src/dawn/native/vulkan/SwapChainVk.cpp b/src/dawn/native/vulkan/SwapChainVk.cpp
index 05191a5..bf0ea02 100644
--- a/src/dawn/native/vulkan/SwapChainVk.cpp
+++ b/src/dawn/native/vulkan/SwapChainVk.cpp
@@ -51,147 +51,6 @@
namespace {
-ResultOrError<VkSurfaceKHR> CreateVulkanSurface(const PhysicalDevice* physicalDevice,
- const Surface* surface) {
- // May not be used in the platform-specific switches below.
- [[maybe_unused]] const VulkanGlobalInfo& info =
- physicalDevice->GetVulkanInstance()->GetGlobalInfo();
- [[maybe_unused]] const VulkanFunctions& fn =
- physicalDevice->GetVulkanInstance()->GetFunctions();
- [[maybe_unused]] VkInstance instance = physicalDevice->GetVulkanInstance()->GetVkInstance();
-
- switch (surface->GetType()) {
-#if defined(DAWN_ENABLE_BACKEND_METAL)
- case Surface::Type::MetalLayer:
- if (info.HasExt(InstanceExt::MetalSurface)) {
- VkMetalSurfaceCreateInfoEXT createInfo;
- createInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
- createInfo.pNext = nullptr;
- createInfo.flags = 0;
- createInfo.pLayer = surface->GetMetalLayer();
-
- VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
- DAWN_TRY(CheckVkSuccess(
- fn.CreateMetalSurfaceEXT(instance, &createInfo, nullptr, &*vkSurface),
- "CreateMetalSurface"));
- return vkSurface;
- }
- break;
-#endif // defined(DAWN_ENABLE_BACKEND_METAL)
-
-#if DAWN_PLATFORM_IS(WINDOWS)
- case Surface::Type::WindowsHWND:
- if (info.HasExt(InstanceExt::Win32Surface)) {
- VkWin32SurfaceCreateInfoKHR createInfo;
- createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
- createInfo.pNext = nullptr;
- createInfo.flags = 0;
- createInfo.hinstance = static_cast<HINSTANCE>(surface->GetHInstance());
- createInfo.hwnd = static_cast<HWND>(surface->GetHWND());
-
- VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
- DAWN_TRY(CheckVkSuccess(
- fn.CreateWin32SurfaceKHR(instance, &createInfo, nullptr, &*vkSurface),
- "CreateWin32Surface"));
- return vkSurface;
- }
- break;
-#endif // DAWN_PLATFORM_IS(WINDOWS)
-
-#if DAWN_PLATFORM_IS(ANDROID)
- case Surface::Type::AndroidWindow: {
- if (info.HasExt(InstanceExt::AndroidSurface)) {
- DAWN_ASSERT(surface->GetAndroidNativeWindow() != nullptr);
-
- VkAndroidSurfaceCreateInfoKHR createInfo;
- createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
- createInfo.pNext = nullptr;
- createInfo.flags = 0;
- createInfo.window =
- static_cast<struct ANativeWindow*>(surface->GetAndroidNativeWindow());
-
- VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
- DAWN_TRY(CheckVkSuccess(
- fn.CreateAndroidSurfaceKHR(instance, &createInfo, nullptr, &*vkSurface),
- "CreateAndroidSurfaceKHR"));
- return vkSurface;
- }
-
- break;
- }
-
-#endif // DAWN_PLATFORM_IS(ANDROID)
-
-#if defined(DAWN_USE_WAYLAND)
- case Surface::Type::WaylandSurface: {
- if (info.HasExt(InstanceExt::XlibSurface)) {
- VkWaylandSurfaceCreateInfoKHR createInfo;
- createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
- createInfo.pNext = nullptr;
- createInfo.flags = 0;
- createInfo.display = static_cast<struct wl_display*>(surface->GetWaylandDisplay());
- createInfo.surface = static_cast<struct wl_surface*>(surface->GetWaylandSurface());
-
- VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
- DAWN_TRY(CheckVkSuccess(
- fn.CreateWaylandSurfaceKHR(instance, &createInfo, nullptr, &*vkSurface),
- "CreateWaylandSurface"));
- return vkSurface;
- }
- break;
- }
-#endif // defined(DAWN_USE_WAYLAND)
-
-#if defined(DAWN_USE_X11)
- case Surface::Type::XlibWindow: {
- if (info.HasExt(InstanceExt::XlibSurface)) {
- VkXlibSurfaceCreateInfoKHR createInfo;
- createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
- createInfo.pNext = nullptr;
- createInfo.flags = 0;
- createInfo.dpy = static_cast<Display*>(surface->GetXDisplay());
- createInfo.window = surface->GetXWindow();
-
- VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
- DAWN_TRY(CheckVkSuccess(
- fn.CreateXlibSurfaceKHR(instance, &createInfo, nullptr, &*vkSurface),
- "CreateXlibSurface"));
- return vkSurface;
- }
-
- // Fall back to using XCB surfaces if the Xlib extension isn't available.
- // See https://xcb.freedesktop.org/MixingCalls/ for more information about
- // interoperability between Xlib and XCB
- const X11Functions* x11 = physicalDevice->GetInstance()->GetOrLoadX11Functions();
- DAWN_ASSERT(x11 != nullptr);
-
- if (info.HasExt(InstanceExt::XcbSurface) && x11->IsX11XcbLoaded()) {
- VkXcbSurfaceCreateInfoKHR createInfo;
- createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
- createInfo.pNext = nullptr;
- createInfo.flags = 0;
- // The XCB connection lives as long as the X11 display.
- createInfo.connection =
- x11->xGetXCBConnection(static_cast<Display*>(surface->GetXDisplay()));
- createInfo.window = surface->GetXWindow();
-
- VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
- DAWN_TRY(CheckVkSuccess(
- fn.CreateXcbSurfaceKHR(instance, &createInfo, nullptr, &*vkSurface),
- "CreateXcbSurfaceKHR"));
- return vkSurface;
- }
- break;
- }
-#endif // defined(DAWN_USE_X11)
-
- default:
- break;
- }
-
- return DAWN_VALIDATION_ERROR("Unsupported surface type (%s) for Vulkan.", surface->GetType());
-}
-
VkPresentModeKHR ToVulkanPresentMode(wgpu::PresentMode mode) {
switch (mode) {
case wgpu::PresentMode::Fifo:
@@ -258,8 +117,8 @@
ResultOrError<Ref<SwapChain>> SwapChain::Create(Device* device,
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor) {
- Ref<SwapChain> swapchain = AcquireRef(new SwapChain(device, surface, descriptor));
+ const SurfaceConfiguration* config) {
+ Ref<SwapChain> swapchain = AcquireRef(new SwapChain(device, surface, config));
DAWN_TRY(swapchain->Initialize(previousSwapChain));
return swapchain;
}
@@ -635,12 +494,13 @@
}
}
-ResultOrError<Ref<TextureBase>> SwapChain::GetCurrentTextureImpl() {
+ResultOrError<SwapChainTextureInfo> SwapChain::GetCurrentTextureImpl() {
return GetCurrentTextureInternal();
}
-ResultOrError<Ref<TextureBase>> SwapChain::GetCurrentTextureInternal(bool isReentrant) {
+ResultOrError<SwapChainTextureInfo> SwapChain::GetCurrentTextureInternal(bool isReentrant) {
Device* device = ToBackend(GetDevice());
+ SwapChainTextureInfo swapChainTextureInfo;
// Transiently create a semaphore that will be signaled when the presentation engine is done
// with the swapchain image. Further operations on the image will wait for this semaphore.
@@ -670,14 +530,17 @@
ToBackend(GetDevice())->GetFencedDeleter()->DeleteWhenUnused(semaphore);
}
+ swapChainTextureInfo.suboptimal = false;
switch (result) {
- // TODO(crbug.com/dawn/269): Introduce a mechanism to notify the application that
- // the swapchain is in a suboptimal state?
case VK_SUBOPTIMAL_KHR:
+ swapChainTextureInfo.suboptimal = true;
+ ABSL_FALLTHROUGH_INTENDED;
case VK_SUCCESS:
+ swapChainTextureInfo.status = wgpu::SurfaceGetCurrentTextureStatus::Success;
break;
case VK_ERROR_OUT_OF_DATE_KHR: {
+ swapChainTextureInfo.status = wgpu::SurfaceGetCurrentTextureStatus::Outdated;
// Prevent infinite recursive calls to GetCurrentTextureViewInternal when the
// swapchains always return that they are out of date.
if (isReentrant) {
@@ -693,6 +556,9 @@
// TODO(crbug.com/dawn/269): Allow losing the surface at Dawn's API level?
case VK_ERROR_SURFACE_LOST_KHR:
+ swapChainTextureInfo.status = wgpu::SurfaceGetCurrentTextureStatus::Lost;
+ break;
+
default:
DAWN_TRY(CheckVkSuccess(::VkResult(result), "AcquireNextImage"));
}
@@ -708,7 +574,8 @@
// In the happy path we can use the swapchain image directly.
if (!mConfig.needsBlit) {
- return mTexture;
+ swapChainTextureInfo.texture = mTexture;
+ return swapChainTextureInfo;
}
// The blit texture always perfectly matches what the user requested for the swapchain.
@@ -716,7 +583,8 @@
TextureDescriptor desc = GetSwapChainBaseTextureDescriptor(this);
DAWN_TRY_ASSIGN(mBlitTexture,
Texture::Create(device, Unpack(&desc), VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
- return mBlitTexture;
+ swapChainTextureInfo.texture = mBlitTexture;
+ return swapChainTextureInfo;
}
void SwapChain::DetachFromSurfaceImpl() {
@@ -748,4 +616,145 @@
}
}
+ResultOrError<VkSurfaceKHR> CreateVulkanSurface(const PhysicalDevice* physicalDevice,
+ const Surface* surface) {
+ // May not be used in the platform-specific switches below.
+ [[maybe_unused]] const VulkanGlobalInfo& info =
+ physicalDevice->GetVulkanInstance()->GetGlobalInfo();
+ [[maybe_unused]] const VulkanFunctions& fn =
+ physicalDevice->GetVulkanInstance()->GetFunctions();
+ [[maybe_unused]] VkInstance instance = physicalDevice->GetVulkanInstance()->GetVkInstance();
+
+ switch (surface->GetType()) {
+#if defined(DAWN_ENABLE_BACKEND_METAL)
+ case Surface::Type::MetalLayer:
+ if (info.HasExt(InstanceExt::MetalSurface)) {
+ VkMetalSurfaceCreateInfoEXT createInfo;
+ createInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
+ createInfo.pNext = nullptr;
+ createInfo.flags = 0;
+ createInfo.pLayer = surface->GetMetalLayer();
+
+ VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
+ DAWN_TRY(CheckVkSuccess(
+ fn.CreateMetalSurfaceEXT(instance, &createInfo, nullptr, &*vkSurface),
+ "CreateMetalSurface"));
+ return vkSurface;
+ }
+ break;
+#endif // defined(DAWN_ENABLE_BACKEND_METAL)
+
+#if DAWN_PLATFORM_IS(WINDOWS)
+ case Surface::Type::WindowsHWND:
+ if (info.HasExt(InstanceExt::Win32Surface)) {
+ VkWin32SurfaceCreateInfoKHR createInfo;
+ createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
+ createInfo.pNext = nullptr;
+ createInfo.flags = 0;
+ createInfo.hinstance = static_cast<HINSTANCE>(surface->GetHInstance());
+ createInfo.hwnd = static_cast<HWND>(surface->GetHWND());
+
+ VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
+ DAWN_TRY(CheckVkSuccess(
+ fn.CreateWin32SurfaceKHR(instance, &createInfo, nullptr, &*vkSurface),
+ "CreateWin32Surface"));
+ return vkSurface;
+ }
+ break;
+#endif // DAWN_PLATFORM_IS(WINDOWS)
+
+#if DAWN_PLATFORM_IS(ANDROID)
+ case Surface::Type::AndroidWindow: {
+ if (info.HasExt(InstanceExt::AndroidSurface)) {
+ DAWN_ASSERT(surface->GetAndroidNativeWindow() != nullptr);
+
+ VkAndroidSurfaceCreateInfoKHR createInfo;
+ createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
+ createInfo.pNext = nullptr;
+ createInfo.flags = 0;
+ createInfo.window =
+ static_cast<struct ANativeWindow*>(surface->GetAndroidNativeWindow());
+
+ VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
+ DAWN_TRY(CheckVkSuccess(
+ fn.CreateAndroidSurfaceKHR(instance, &createInfo, nullptr, &*vkSurface),
+ "CreateAndroidSurfaceKHR"));
+ return vkSurface;
+ }
+
+ break;
+ }
+
+#endif // DAWN_PLATFORM_IS(ANDROID)
+
+#if defined(DAWN_USE_WAYLAND)
+ case Surface::Type::WaylandSurface: {
+ if (info.HasExt(InstanceExt::XlibSurface)) {
+ VkWaylandSurfaceCreateInfoKHR createInfo;
+ createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
+ createInfo.pNext = nullptr;
+ createInfo.flags = 0;
+ createInfo.display = static_cast<struct wl_display*>(surface->GetWaylandDisplay());
+ createInfo.surface = static_cast<struct wl_surface*>(surface->GetWaylandSurface());
+
+ VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
+ DAWN_TRY(CheckVkSuccess(
+ fn.CreateWaylandSurfaceKHR(instance, &createInfo, nullptr, &*vkSurface),
+ "CreateWaylandSurface"));
+ return vkSurface;
+ }
+ break;
+ }
+#endif // defined(DAWN_USE_WAYLAND)
+
+#if defined(DAWN_USE_X11)
+ case Surface::Type::XlibWindow: {
+ if (info.HasExt(InstanceExt::XlibSurface)) {
+ VkXlibSurfaceCreateInfoKHR createInfo;
+ createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
+ createInfo.pNext = nullptr;
+ createInfo.flags = 0;
+ createInfo.dpy = static_cast<Display*>(surface->GetXDisplay());
+ createInfo.window = surface->GetXWindow();
+
+ VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
+ DAWN_TRY(CheckVkSuccess(
+ fn.CreateXlibSurfaceKHR(instance, &createInfo, nullptr, &*vkSurface),
+ "CreateXlibSurface"));
+ return vkSurface;
+ }
+
+ // Fall back to using XCB surfaces if the Xlib extension isn't available.
+ // See https://xcb.freedesktop.org/MixingCalls/ for more information about
+ // interoperability between Xlib and XCB
+ const X11Functions* x11 = physicalDevice->GetInstance()->GetOrLoadX11Functions();
+ DAWN_ASSERT(x11 != nullptr);
+
+ if (info.HasExt(InstanceExt::XcbSurface) && x11->IsX11XcbLoaded()) {
+ VkXcbSurfaceCreateInfoKHR createInfo;
+ createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
+ createInfo.pNext = nullptr;
+ createInfo.flags = 0;
+ // The XCB connection lives as long as the X11 display.
+ createInfo.connection =
+ x11->xGetXCBConnection(static_cast<Display*>(surface->GetXDisplay()));
+ createInfo.window = surface->GetXWindow();
+
+ VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
+ DAWN_TRY(CheckVkSuccess(
+ fn.CreateXcbSurfaceKHR(instance, &createInfo, nullptr, &*vkSurface),
+ "CreateXcbSurfaceKHR"));
+ return vkSurface;
+ }
+ break;
+ }
+#endif // defined(DAWN_USE_X11)
+
+ default:
+ break;
+ }
+
+ return DAWN_VALIDATION_ERROR("Unsupported surface type (%s) for Vulkan.", surface->GetType());
+}
+
} // namespace dawn::native::vulkan
diff --git a/src/dawn/native/vulkan/SwapChainVk.h b/src/dawn/native/vulkan/SwapChainVk.h
index b0d322d..da1f7ea 100644
--- a/src/dawn/native/vulkan/SwapChainVk.h
+++ b/src/dawn/native/vulkan/SwapChainVk.h
@@ -38,6 +38,7 @@
class Device;
class Texture;
+class PhysicalDevice;
struct VulkanSurfaceInfo;
class SwapChain : public SwapChainBase {
@@ -45,7 +46,7 @@
static ResultOrError<Ref<SwapChain>> Create(Device* device,
Surface* surface,
SwapChainBase* previousSwapChain,
- const SwapChainDescriptor* descriptor);
+ const SurfaceConfiguration* config);
static ResultOrError<wgpu::TextureUsage> GetSupportedSurfaceUsage(const Device* device,
const Surface* surface);
@@ -77,11 +78,11 @@
bool needsBlit = false;
};
ResultOrError<Config> ChooseConfig(const VulkanSurfaceInfo& surfaceInfo) const;
- ResultOrError<Ref<TextureBase>> GetCurrentTextureInternal(bool isReentrant = false);
+ ResultOrError<SwapChainTextureInfo> GetCurrentTextureInternal(bool isReentrant = false);
// SwapChainBase implementation
MaybeError PresentImpl() override;
- ResultOrError<Ref<TextureBase>> GetCurrentTextureImpl() override;
+ ResultOrError<SwapChainTextureInfo> GetCurrentTextureImpl() override;
void DetachFromSurfaceImpl() override;
Config mConfig;
@@ -96,6 +97,9 @@
Ref<Texture> mTexture;
};
+ResultOrError<VkSurfaceKHR> CreateVulkanSurface(const PhysicalDevice* physicalDevice,
+ const Surface* surface);
+
} // namespace dawn::native::vulkan
#endif // SRC_DAWN_NATIVE_VULKAN_SWAPCHAINVK_H_
diff --git a/src/dawn/native/webgpu_absl_format.cpp b/src/dawn/native/webgpu_absl_format.cpp
index c8f67e5..1bc3138 100644
--- a/src/dawn/native/webgpu_absl_format.cpp
+++ b/src/dawn/native/webgpu_absl_format.cpp
@@ -31,6 +31,7 @@
#include <vector>
#include "dawn/common/MatchVariant.h"
+#include "dawn/native/Adapter.h"
#include "dawn/native/AttachmentState.h"
#include "dawn/native/BindingInfo.h"
#include "dawn/native/Device.h"
@@ -250,6 +251,23 @@
//
absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
+ const AdapterBase* value,
+ const absl::FormatConversionSpec& spec,
+ absl::FormatSink* s) {
+ if (value == nullptr) {
+ s->Append("[null]");
+ return {true};
+ }
+ s->Append("[Adapter");
+ const std::string& name = value->GetName();
+ if (!name.empty()) {
+ s->Append(absl::StrFormat(" \"%s\"", name));
+ }
+ s->Append("]");
+ return {true};
+}
+
+absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
const DeviceBase* value,
const absl::FormatConversionSpec& spec,
absl::FormatSink* s) {
@@ -346,6 +364,23 @@
return {true};
}
+absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
+ const Surface* value,
+ const absl::FormatConversionSpec& spec,
+ absl::FormatSink* s) {
+ if (value == nullptr) {
+ s->Append("[null]");
+ return {true};
+ }
+ s->Append("[Surface");
+ const std::string& label = value->GetLabel();
+ if (!label.empty()) {
+ s->Append(absl::StrFormat(" \"%s\"", label));
+ }
+ s->Append("]");
+ return {true};
+}
+
//
// Enums
//
diff --git a/src/dawn/native/webgpu_absl_format.h b/src/dawn/native/webgpu_absl_format.h
index d98e088..b23f969 100644
--- a/src/dawn/native/webgpu_absl_format.h
+++ b/src/dawn/native/webgpu_absl_format.h
@@ -148,6 +148,12 @@
class DeviceBase;
absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
+ const AdapterBase* value,
+ const absl::FormatConversionSpec& spec,
+ absl::FormatSink* s);
+
+class DeviceBase;
+absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
const DeviceBase* value,
const absl::FormatConversionSpec& spec,
absl::FormatSink* s);
@@ -164,6 +170,12 @@
const absl::FormatConversionSpec& spec,
absl::FormatSink* s);
+class Surface;
+absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
+ const Surface* value,
+ const absl::FormatConversionSpec& spec,
+ absl::FormatSink* s);
+
//
// Enums
//
diff --git a/src/dawn/tests/BUILD.gn b/src/dawn/tests/BUILD.gn
index 8333fc3..4fa91b7 100644
--- a/src/dawn/tests/BUILD.gn
+++ b/src/dawn/tests/BUILD.gn
@@ -714,6 +714,8 @@
if (dawn_supports_glfw_for_windowing) {
sources += [
+ "end2end/SurfaceConfigurationValidationTests.cpp",
+ "end2end/SurfaceTests.cpp",
"end2end/SwapChainTests.cpp",
"end2end/SwapChainValidationTests.cpp",
"end2end/WindowSurfaceTests.cpp",
diff --git a/src/dawn/tests/end2end/SurfaceConfigurationValidationTests.cpp b/src/dawn/tests/end2end/SurfaceConfigurationValidationTests.cpp
new file mode 100644
index 0000000..9fb92ae
--- /dev/null
+++ b/src/dawn/tests/end2end/SurfaceConfigurationValidationTests.cpp
@@ -0,0 +1,303 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <cmath>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "dawn/common/Constants.h"
+#include "dawn/tests/DawnTest.h"
+#include "dawn/utils/ComboRenderBundleEncoderDescriptor.h"
+#include "dawn/utils/ComboRenderPipelineDescriptor.h"
+#include "dawn/utils/WGPUHelpers.h"
+#include "webgpu/webgpu_glfw.h"
+
+#include "GLFW/glfw3.h"
+
+namespace dawn::utils {
+static constexpr std::array<wgpu::CompositeAlphaMode, 5> kAllAlphaModes = {
+ wgpu::CompositeAlphaMode::Auto, wgpu::CompositeAlphaMode::Opaque,
+ wgpu::CompositeAlphaMode::Premultiplied, wgpu::CompositeAlphaMode::Unpremultiplied,
+ wgpu::CompositeAlphaMode::Inherit,
+};
+static constexpr std::array<wgpu::PresentMode, 3> kAllPresentModes = {
+ wgpu::PresentMode::Fifo,
+ wgpu::PresentMode::Immediate,
+ wgpu::PresentMode::Mailbox,
+};
+} // namespace dawn::utils
+
+namespace dawn {
+namespace {
+
+struct GLFWindowDestroyer {
+ void operator()(GLFWwindow* ptr) { glfwDestroyWindow(ptr); }
+};
+
+class SurfaceConfigurationValidationTests : public DawnTest {
+ public:
+ void SetUp() override {
+ DawnTest::SetUp();
+ DAWN_TEST_UNSUPPORTED_IF(UsesWire());
+ DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("skip_validation"));
+
+ glfwSetErrorCallback([](int code, const char* message) {
+ ErrorLog() << "GLFW error " << code << " " << message;
+ });
+
+ // GLFW can fail to start in headless environments, in which SwapChainTests are
+ // inapplicable. Skip this cases without producing a test failure.
+ if (glfwInit() == GLFW_FALSE) {
+ GTEST_SKIP();
+ }
+
+ // Set GLFW_NO_API to avoid GLFW bringing up a GL context that we won't use.
+ glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+ window.reset(glfwCreateWindow(500, 400, "SurfaceConfigurationValidationTests window",
+ nullptr, nullptr));
+
+ int width;
+ int height;
+ glfwGetFramebufferSize(window.get(), &width, &height);
+
+ baseConfig.device = device;
+ baseConfig.width = width;
+ baseConfig.height = height;
+ baseConfig.usage = wgpu::TextureUsage::RenderAttachment;
+ baseConfig.viewFormatCount = 0;
+ baseConfig.viewFormats = nullptr;
+ }
+
+ wgpu::Surface CreateTestSurface() {
+ return wgpu::glfw::CreateSurfaceForWindow(GetInstance(), window.get());
+ }
+
+ wgpu::SurfaceConfiguration GetPreferredConfiguration(wgpu::Surface surface) {
+ wgpu::SurfaceCapabilities capabilities;
+ surface.GetCapabilities(adapter, &capabilities);
+
+ wgpu::TextureFormat preferredFormat = surface.GetPreferredFormat(adapter);
+
+ wgpu::SurfaceConfiguration config = baseConfig;
+ config.format = preferredFormat;
+ config.alphaMode = capabilities.alphaModes[0];
+ config.presentMode = capabilities.presentModes[0];
+ return config;
+ }
+
+ bool SupportsFormat(const wgpu::SurfaceCapabilities& capabilities, wgpu::TextureFormat format) {
+ for (size_t i = 0; i < capabilities.formatCount; ++i) {
+ if (capabilities.formats[i] == format) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool SupportsAlphaMode(const wgpu::SurfaceCapabilities& capabilities,
+ wgpu::CompositeAlphaMode mode) {
+ for (size_t i = 0; i < capabilities.alphaModeCount; ++i) {
+ if (capabilities.alphaModes[i] == mode) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool SupportsPresentMode(const wgpu::SurfaceCapabilities& capabilities,
+ wgpu::PresentMode mode) {
+ for (size_t i = 0; i < capabilities.presentModeCount; ++i) {
+ if (capabilities.presentModes[i] == mode) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected:
+ std::unique_ptr<GLFWwindow, GLFWindowDestroyer> window = nullptr;
+ wgpu::SurfaceConfiguration baseConfig;
+};
+
+// Using undefined format is not valid
+TEST_P(SurfaceConfigurationValidationTests, UndefinedFormat) {
+ wgpu::SurfaceConfiguration config;
+ config.device = device;
+ config.format = wgpu::TextureFormat::Undefined;
+ ASSERT_DEVICE_ERROR(CreateTestSurface().Configure(&config));
+}
+
+// Supports at least one configuration
+TEST_P(SurfaceConfigurationValidationTests, AtLeastOneSupportedConfiguration) {
+ wgpu::Surface surface = CreateTestSurface();
+
+ wgpu::SurfaceCapabilities capabilities;
+ surface.GetCapabilities(adapter, &capabilities);
+
+ ASSERT_GT(capabilities.formatCount, 0u);
+ ASSERT_GT(capabilities.alphaModeCount, 0u);
+ ASSERT_GT(capabilities.presentModeCount, 0u);
+}
+
+// Using any combination of the reported capability is ok for configuring the surface.
+TEST_P(SurfaceConfigurationValidationTests, AnyCombinationOfCapabilities) {
+ // TODO(dawn:2320): Fails with "internal drawable creation failed" on the Windows NVIDIA CQ
+ // builders but not locally. This is a similar limitation to SwapChainTests.SwitchPresentMode.
+ DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsNvidia());
+
+ wgpu::Surface surface = CreateTestSurface();
+
+ wgpu::SurfaceConfiguration config = baseConfig;
+
+ wgpu::SurfaceCapabilities capabilities;
+ surface.GetCapabilities(adapter, &capabilities);
+
+ for (wgpu::TextureFormat format : dawn::utils::kAllTextureFormats) {
+ for (wgpu::CompositeAlphaMode alphaMode : dawn::utils::kAllAlphaModes) {
+ for (wgpu::PresentMode presentMode : dawn::utils::kAllPresentModes) {
+ config.format = format;
+ config.alphaMode = alphaMode;
+ config.presentMode = presentMode;
+
+ if (!SupportsFormat(capabilities, config.format) ||
+ !SupportsAlphaMode(capabilities, config.alphaMode) ||
+ !SupportsPresentMode(capabilities, config.presentMode)) {
+ ASSERT_DEVICE_ERROR(surface.Configure(&config));
+ } else {
+ surface.Configure(&config);
+
+ // Check that we can present
+ wgpu::SurfaceTexture surfaceTexture;
+ surface.GetCurrentTexture(&surfaceTexture);
+ surface.Present();
+ }
+ device.Tick();
+ }
+ }
+ }
+}
+
+// Preferred format is always valid.
+TEST_P(SurfaceConfigurationValidationTests, PreferredFormatIsValid) {
+ wgpu::Surface surface = CreateTestSurface();
+
+ wgpu::SurfaceCapabilities capabilities;
+ surface.GetCapabilities(adapter, &capabilities);
+
+ wgpu::TextureFormat preferredFormat = surface.GetPreferredFormat(adapter);
+ bool found = false;
+ for (size_t i = 0; i < capabilities.formatCount; ++i) {
+ found = found || capabilities.formats[i] == preferredFormat;
+ }
+ ASSERT_TRUE(found);
+}
+
+// Invalid view format fails
+TEST_P(SurfaceConfigurationValidationTests, InvalidViewFormat) {
+ wgpu::Surface surface = CreateTestSurface();
+ auto invalid = wgpu::TextureFormat::R32Uint;
+
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+ config.viewFormatCount = 1;
+ config.viewFormats = &invalid;
+ ASSERT_DEVICE_ERROR(surface.Configure(&config));
+}
+
+// View format is valid when it matches the config format
+TEST_P(SurfaceConfigurationValidationTests, ValidViewFormat) {
+ wgpu::Surface surface = CreateTestSurface();
+
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+ config.viewFormatCount = 1;
+ config.viewFormats = &config.format;
+ surface.Configure(&config);
+
+ // TODO(dawn:2320): Also test the equivalent (non-)sRGB view format
+}
+
+// A width of 0 fails
+TEST_P(SurfaceConfigurationValidationTests, ZeroWidth) {
+ wgpu::Surface surface = CreateTestSurface();
+
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+ config.width = 0;
+ ASSERT_DEVICE_ERROR(surface.Configure(&config));
+}
+
+// A height of 0 fails
+TEST_P(SurfaceConfigurationValidationTests, ZeroHeight) {
+ wgpu::Surface surface = CreateTestSurface();
+
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+ config.height = 0;
+ ASSERT_DEVICE_ERROR(surface.Configure(&config));
+}
+
+// A width that exceeds the maximum texture size fails
+TEST_P(SurfaceConfigurationValidationTests, ExcessiveWidth) {
+ wgpu::Surface surface = CreateTestSurface();
+ wgpu::SupportedLimits supported;
+ device.GetLimits(&supported);
+
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+ config.width = supported.limits.maxTextureDimension1D + 1;
+ ASSERT_DEVICE_ERROR(surface.Configure(&config));
+}
+
+// A height that exceeds the maximum texture size fails
+TEST_P(SurfaceConfigurationValidationTests, ExcessiveHeight) {
+ wgpu::Surface surface = CreateTestSurface();
+ wgpu::SupportedLimits supported;
+ device.GetLimits(&supported);
+
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+ config.height = supported.limits.maxTextureDimension2D + 1;
+ ASSERT_DEVICE_ERROR(surface.Configure(&config));
+}
+
+// A surface that was not configured must not be unconfigured
+TEST_P(SurfaceConfigurationValidationTests, UnconfigureNonConfiguredSurfaceFails) {
+ // TODO(dawn:2320): With SwiftShader, this throws a device error anyways (maybe because
+ // mInstance->ConsumedError calls the device error callback?). We should have a
+ // ASSERT_INSTANCE_ERROR to fully fix this test case.
+ DAWN_SUPPRESS_TEST_IF(IsSwiftshader());
+
+ // TODO(dawn:2320): This cannot throw a device error since the surface is
+ // not aware of the device at this stage.
+ /*ASSERT_DEVICE_ERROR(*/ CreateTestSurface().Unconfigure() /*)*/;
+}
+
+DAWN_INSTANTIATE_TEST(SurfaceConfigurationValidationTests,
+ D3D11Backend(),
+ D3D12Backend(),
+ MetalBackend(),
+ NullBackend(),
+ VulkanBackend());
+
+} // anonymous namespace
+} // namespace dawn
diff --git a/src/dawn/tests/end2end/SurfaceTests.cpp b/src/dawn/tests/end2end/SurfaceTests.cpp
new file mode 100644
index 0000000..ef1fc3c
--- /dev/null
+++ b/src/dawn/tests/end2end/SurfaceTests.cpp
@@ -0,0 +1,433 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "dawn/common/Constants.h"
+#include "dawn/tests/DawnTest.h"
+#include "dawn/utils/ComboRenderBundleEncoderDescriptor.h"
+#include "dawn/utils/ComboRenderPipelineDescriptor.h"
+#include "dawn/utils/WGPUHelpers.h"
+#include "webgpu/webgpu_glfw.h"
+
+#include "GLFW/glfw3.h"
+
+namespace dawn {
+namespace {
+
+struct GLFWindowDestroyer {
+ void operator()(GLFWwindow* ptr) { glfwDestroyWindow(ptr); }
+};
+
+class SurfaceTests : public DawnTest {
+ public:
+ void SetUp() override {
+ DawnTest::SetUp();
+ DAWN_TEST_UNSUPPORTED_IF(UsesWire());
+
+ glfwSetErrorCallback([](int code, const char* message) {
+ ErrorLog() << "GLFW error " << code << " " << message;
+ });
+
+ // GLFW can fail to start in headless environments, in which SurfaceTests are
+ // inapplicable. Skip this cases without producing a test failure.
+ if (glfwInit() == GLFW_FALSE) {
+ GTEST_SKIP();
+ }
+
+ // Set GLFW_NO_API to avoid GLFW bringing up a GL context that we won't use.
+ glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+ window.reset(glfwCreateWindow(400, 500, "SurfaceTests window", nullptr, nullptr));
+
+ int width;
+ int height;
+ glfwGetFramebufferSize(window.get(), &width, &height);
+
+ baseConfig.device = device;
+ baseConfig.width = width;
+ baseConfig.height = height;
+ baseConfig.usage = wgpu::TextureUsage::RenderAttachment;
+ baseConfig.viewFormatCount = 0;
+ baseConfig.viewFormats = nullptr;
+ }
+
+ void TearDown() override {
+ // Destroy the surface before the window as required by webgpu-native.
+ window.reset();
+ DawnTest::TearDown();
+ }
+
+ wgpu::Surface CreateTestSurface() {
+ return wgpu::glfw::CreateSurfaceForWindow(GetInstance(), window.get());
+ }
+
+ wgpu::SurfaceConfiguration GetPreferredConfiguration(wgpu::Surface surface) {
+ wgpu::SurfaceCapabilities capabilities;
+ surface.GetCapabilities(adapter, &capabilities);
+
+ wgpu::TextureFormat preferredFormat = surface.GetPreferredFormat(adapter);
+
+ wgpu::SurfaceConfiguration config = baseConfig;
+ config.format = preferredFormat;
+ config.alphaMode = capabilities.alphaModes[0];
+ config.presentMode = capabilities.presentModes[0];
+ return config;
+ }
+
+ void ClearTexture(wgpu::Texture texture,
+ wgpu::Color color,
+ wgpu::Device preferredDevice = nullptr) {
+ if (preferredDevice == nullptr) {
+ preferredDevice = device;
+ }
+
+ utils::ComboRenderPassDescriptor desc({texture.CreateView()});
+ desc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
+ desc.cColorAttachments[0].clearValue = color;
+
+ wgpu::CommandEncoder encoder = preferredDevice.CreateCommandEncoder();
+ wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&desc);
+ pass.End();
+
+ wgpu::CommandBuffer commands = encoder.Finish();
+ preferredDevice.GetQueue().Submit(1, &commands);
+ }
+
+ bool SupportsPresentMode(const wgpu::SurfaceCapabilities& capabilities,
+ wgpu::PresentMode mode) {
+ for (size_t i = 0; i < capabilities.presentModeCount; ++i) {
+ if (capabilities.presentModes[i] == mode) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected:
+ std::unique_ptr<GLFWwindow, GLFWindowDestroyer> window = nullptr;
+ wgpu::SurfaceConfiguration baseConfig;
+};
+
+// Basic test for creating a swapchain and presenting one frame.
+TEST_P(SurfaceTests, Basic) {
+ wgpu::Surface surface = CreateTestSurface();
+
+ // Configure
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+ surface.Configure(&config);
+
+ // Get texture
+ wgpu::SurfaceTexture surfaceTexture;
+ surface.GetCurrentTexture(&surfaceTexture);
+ ASSERT_EQ(surfaceTexture.status, wgpu::SurfaceGetCurrentTextureStatus::Success);
+ ClearTexture(surfaceTexture.texture, {1.0, 0.0, 0.0, 1.0});
+
+ // Present
+ surface.Present();
+}
+
+// Test reconfiguring the surface
+TEST_P(SurfaceTests, ReconfigureBasic) {
+ wgpu::Surface surface = CreateTestSurface();
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+
+ surface.Configure(&config);
+
+ surface.Configure(&config);
+}
+
+// Test replacing the swapchain after GetCurrentTexture
+TEST_P(SurfaceTests, ReconfigureAfterGetCurrentTexture) {
+ wgpu::Surface surface = CreateTestSurface();
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+ wgpu::SurfaceTexture surfaceTexture;
+
+ surface.Configure(&config);
+ surface.GetCurrentTexture(&surfaceTexture);
+ ClearTexture(surfaceTexture.texture, {1.0, 0.0, 0.0, 1.0});
+
+ surface.Configure(&config);
+ surface.GetCurrentTexture(&surfaceTexture);
+ ClearTexture(surfaceTexture.texture, {0.0, 1.0, 0.0, 1.0});
+ surface.Present();
+}
+
+// Test inconfiguring then reconfiguring the surface
+TEST_P(SurfaceTests, ReconfigureAfterUnconfigure) {
+ wgpu::Surface surface = CreateTestSurface();
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+ wgpu::SurfaceTexture surfaceTexture;
+
+ surface.Configure(&config);
+ surface.GetCurrentTexture(&surfaceTexture);
+ ClearTexture(surfaceTexture.texture, {1.0, 0.0, 0.0, 1.0});
+ surface.Present();
+
+ surface.Unconfigure();
+
+ surface.Configure(&config);
+ surface.GetCurrentTexture(&surfaceTexture);
+ ClearTexture(surfaceTexture.texture, {0.0, 1.0, 0.0, 1.0});
+ surface.Present();
+}
+
+// Test destroying the swapchain after GetCurrentTexture
+TEST_P(SurfaceTests, UnconfigureAfterGet) {
+ wgpu::Surface surface = CreateTestSurface();
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+ wgpu::SurfaceTexture surfaceTexture;
+
+ surface.Configure(&config);
+ surface.GetCurrentTexture(&surfaceTexture);
+ ClearTexture(surfaceTexture.texture, {1.0, 0.0, 0.0, 1.0});
+
+ surface.Unconfigure();
+}
+// Test switching between surfaces that have different present modes.
+TEST_P(SurfaceTests, SwitchPresentMode) {
+ // Fails with "internal drawable creation failed" on the Windows NVIDIA CQ builders but not
+ // locally.
+ DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsNvidia());
+
+ // TODO(jiawei.shao@intel.com): find out why this test sometimes hangs on the latest Linux Intel
+ // Vulkan drivers.
+ DAWN_SUPPRESS_TEST_IF(IsLinux() && IsVulkan() && IsIntel());
+
+ constexpr wgpu::PresentMode kAllPresentModes[] = {
+ wgpu::PresentMode::Immediate,
+ wgpu::PresentMode::Fifo,
+ wgpu::PresentMode::Mailbox,
+ };
+
+ wgpu::Surface surface1 = CreateTestSurface();
+ wgpu::Surface surface2 = CreateTestSurface();
+ wgpu::SurfaceTexture surfaceTexture;
+
+ wgpu::SurfaceCapabilities capabilities;
+ surface1.GetCapabilities(adapter, &capabilities);
+
+ for (wgpu::PresentMode mode1 : kAllPresentModes) {
+ if (!SupportsPresentMode(capabilities, mode1)) {
+ continue;
+ }
+ for (wgpu::PresentMode mode2 : kAllPresentModes) {
+ if (!SupportsPresentMode(capabilities, mode2)) {
+ continue;
+ }
+
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface1);
+
+ config.presentMode = mode1;
+ surface1.Configure(&config);
+ surface1.GetCurrentTexture(&surfaceTexture);
+ ClearTexture(surfaceTexture.texture, {0.0, 0.0, 0.0, 1.0});
+ surface1.Present();
+ surface1.Unconfigure();
+
+ config.presentMode = mode2;
+ surface2.Configure(&config);
+ surface2.GetCurrentTexture(&surfaceTexture);
+ ClearTexture(surfaceTexture.texture, {0.0, 0.0, 0.0, 1.0});
+ surface2.Present();
+ surface2.Unconfigure();
+ }
+ }
+}
+
+// Test resizing the surface and without resizing the window.
+TEST_P(SurfaceTests, ResizingSurfaceOnly) {
+ wgpu::Surface surface = CreateTestSurface();
+ wgpu::SurfaceTexture surfaceTexture;
+
+ for (int i = 0; i < 10; i++) {
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+ config.width += i * 10;
+ config.height -= i * 10;
+
+ surface.Configure(&config);
+ surface.GetCurrentTexture(&surfaceTexture);
+ ClearTexture(surfaceTexture.texture, {0.05f * i, 0.0, 0.0, 1.0});
+ surface.Present();
+ }
+}
+
+// Test resizing the window but not the surface.
+TEST_P(SurfaceTests, ResizingWindowOnly) {
+ // TODO(crbug.com/1503912): Failing new ValidateImageAcquireWait in Vulkan Validation Layer.
+ DAWN_SUPPRESS_TEST_IF(IsBackendValidationEnabled() && IsWindows() && IsVulkan() && IsIntel());
+
+ wgpu::Surface surface = CreateTestSurface();
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+ wgpu::SurfaceTexture surfaceTexture;
+
+ surface.Configure(&config);
+
+ for (int i = 0; i < 10; i++) {
+ glfwSetWindowSize(window.get(), 400 - 10 * i, 400 + 10 * i);
+ glfwPollEvents();
+
+ surface.GetCurrentTexture(&surfaceTexture);
+ ClearTexture(surfaceTexture.texture, {0.05f * i, 0.0, 0.0, 1.0});
+ surface.Present();
+ }
+}
+
+// Test resizing both the window and the surface at the same time.
+TEST_P(SurfaceTests, ResizingWindowAndSurface) {
+ // TODO(crbug.com/dawn/1205): Currently failing on new NVIDIA GTX 1660s on Linux/Vulkan.
+ DAWN_SUPPRESS_TEST_IF(IsLinux() && IsVulkan() && IsNvidia());
+
+ wgpu::Surface surface = CreateTestSurface();
+ wgpu::SurfaceTexture surfaceTexture;
+
+ for (int i = 0; i < 10; i++) {
+ glfwSetWindowSize(window.get(), 400 - 10 * i, 400 + 10 * i);
+ glfwPollEvents();
+
+ int width;
+ int height;
+ glfwGetFramebufferSize(window.get(), &width, &height);
+
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+ config.width = width;
+ config.height = height;
+ surface.Configure(&config);
+
+ surface.GetCurrentTexture(&surfaceTexture);
+ ClearTexture(surfaceTexture.texture, {0.05f * i, 0.0, 0.0, 1.0});
+ surface.Present();
+ }
+}
+
+// Test switching devices on the same adapter.
+TEST_P(SurfaceTests, SwitchingDevice) {
+ // TODO(https://crbug.com/dawn/2116): Disabled due to new Validation Layer failures.
+ DAWN_SUPPRESS_TEST_IF(IsVulkan());
+
+ wgpu::Device device2 = CreateDevice();
+
+ wgpu::Surface surface = CreateTestSurface();
+ wgpu::SurfaceTexture surfaceTexture;
+
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+
+ for (int i = 0; i < 3; i++) {
+ wgpu::Device deviceToUse;
+ if (i % 2 == 0) {
+ deviceToUse = device;
+ } else {
+ deviceToUse = device2;
+ }
+
+ config.device = deviceToUse;
+ surface.Configure(&config);
+ surface.GetCurrentTexture(&surfaceTexture);
+ ClearTexture(surfaceTexture.texture, {0.0, 1.0, 0.0, 1.0}, deviceToUse);
+ surface.Present();
+ }
+}
+
+// Test that configuring with TextureBinding usage without enabling SurfaceCapabilities
+// feature should fail.
+TEST_P(SurfaceTests, ErrorCreateWithTextureBindingUsage) {
+ DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("skip_validation"));
+ EXPECT_FALSE(device.HasFeature(wgpu::FeatureName::SurfaceCapabilities));
+
+ wgpu::Surface surface = CreateTestSurface();
+ wgpu::SurfaceTexture surfaceTexture;
+
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+ config.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment;
+
+ ASSERT_DEVICE_ERROR_MSG(
+ { surface.Configure(&config); },
+ testing::HasSubstr("require enabling FeatureName::SurfaceCapabilities"));
+}
+
+// Getting current texture without configuring returns an invalid surface texture
+// It cannot raise a device error at this stage since it has never been configured with a device
+TEST_P(SurfaceTests, GetWithoutConfigure) {
+ wgpu::Surface surface = CreateTestSurface();
+ wgpu::SurfaceTexture surfaceTexture;
+ surface.GetCurrentTexture(&surfaceTexture);
+ EXPECT_NE(surfaceTexture.status, wgpu::SurfaceGetCurrentTextureStatus::Success);
+}
+
+// Getting current texture after unconfiguring fails
+TEST_P(SurfaceTests, GetAfterUnconfigure) {
+ wgpu::Surface surface = CreateTestSurface();
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+ wgpu::SurfaceTexture surfaceTexture;
+
+ surface.Configure(&config);
+
+ surface.Unconfigure();
+
+ ASSERT_DEVICE_ERROR(surface.GetCurrentTexture(&surfaceTexture));
+}
+
+// Presenting without configuring fails
+TEST_P(SurfaceTests, PresentWithoutConfigure) {
+ wgpu::Surface surface = CreateTestSurface();
+ // TODO(dawn:2320): This cannot throw a device error since the surface is
+ // not aware of the device at this stage.
+ /*ASSERT_DEVICE_ERROR(*/ surface.Present() /*)*/;
+}
+
+// Presenting after unconfiguring fails
+TEST_P(SurfaceTests, PresentAfterUnconfigure) {
+ wgpu::Surface surface = CreateTestSurface();
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+
+ surface.Configure(&config);
+
+ surface.Unconfigure();
+
+ ASSERT_DEVICE_ERROR(surface.Present());
+}
+
+// Presenting without getting current texture first fails
+TEST_P(SurfaceTests, PresentWithoutGet) {
+ wgpu::Surface surface = CreateTestSurface();
+ wgpu::SurfaceConfiguration config = GetPreferredConfiguration(surface);
+
+ surface.Configure(&config);
+ ASSERT_DEVICE_ERROR(surface.Present());
+}
+
+// TODO(dawn:2320): Enable D3D tests (though they are not enabled in SwapChainTests neither)
+DAWN_INSTANTIATE_TEST(SurfaceTests,
+ // D3D11Backend(),
+ // D3D12Backend(),
+ MetalBackend(),
+ NullBackend(),
+ VulkanBackend());
+
+} // anonymous namespace
+} // namespace dawn
diff --git a/src/dawn/tests/end2end/SwapChainTests.cpp b/src/dawn/tests/end2end/SwapChainTests.cpp
index e1087c0..77bfe41 100644
--- a/src/dawn/tests/end2end/SwapChainTests.cpp
+++ b/src/dawn/tests/end2end/SwapChainTests.cpp
@@ -90,6 +90,13 @@
DawnTest::TearDown();
}
+ wgpu::SwapChain CreateSwapChain(wgpu::Surface const& otherSurface,
+ wgpu::SwapChainDescriptor const* descriptor) {
+ wgpu::SwapChain swapchain;
+ EXPECT_DEPRECATION_WARNING(swapchain = device.CreateSwapChain(otherSurface, descriptor));
+ return swapchain;
+ }
+
void ClearTexture(wgpu::Texture texture, wgpu::Color color) {
utils::ComboRenderPassDescriptor desc({texture.CreateView()});
desc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
@@ -112,47 +119,47 @@
// Basic test for creating a swapchain and presenting one frame.
TEST_P(SwapChainTests, Basic) {
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &baseDescriptor);
ClearTexture(swapchain.GetCurrentTexture(), {1.0, 0.0, 0.0, 1.0});
swapchain.Present();
}
// Test replacing the swapchain
TEST_P(SwapChainTests, ReplaceBasic) {
- wgpu::SwapChain swapchain1 = device.CreateSwapChain(surface, &baseDescriptor);
+ wgpu::SwapChain swapchain1 = CreateSwapChain(surface, &baseDescriptor);
ClearTexture(swapchain1.GetCurrentTexture(), {1.0, 0.0, 0.0, 1.0});
swapchain1.Present();
- wgpu::SwapChain swapchain2 = device.CreateSwapChain(surface, &baseDescriptor);
+ wgpu::SwapChain swapchain2 = CreateSwapChain(surface, &baseDescriptor);
ClearTexture(swapchain2.GetCurrentTexture(), {0.0, 1.0, 0.0, 1.0});
swapchain2.Present();
}
// Test replacing the swapchain after GetCurrentTexture
TEST_P(SwapChainTests, ReplaceAfterGet) {
- wgpu::SwapChain swapchain1 = device.CreateSwapChain(surface, &baseDescriptor);
+ wgpu::SwapChain swapchain1 = CreateSwapChain(surface, &baseDescriptor);
ClearTexture(swapchain1.GetCurrentTexture(), {1.0, 0.0, 0.0, 1.0});
- wgpu::SwapChain swapchain2 = device.CreateSwapChain(surface, &baseDescriptor);
+ wgpu::SwapChain swapchain2 = CreateSwapChain(surface, &baseDescriptor);
ClearTexture(swapchain2.GetCurrentTexture(), {0.0, 1.0, 0.0, 1.0});
swapchain2.Present();
}
// Test destroying the swapchain after GetCurrentTexture
TEST_P(SwapChainTests, DestroyAfterGet) {
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &baseDescriptor);
ClearTexture(swapchain.GetCurrentTexture(), {1.0, 0.0, 0.0, 1.0});
}
// Test destroying the surface before the swapchain
TEST_P(SwapChainTests, DestroySurface) {
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &baseDescriptor);
surface = nullptr;
}
// Test destroying the surface before the swapchain but after GetCurrentTexture
TEST_P(SwapChainTests, DestroySurfaceAfterGet) {
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &baseDescriptor);
ClearTexture(swapchain.GetCurrentTexture(), {1.0, 0.0, 0.0, 1.0});
surface = nullptr;
}
@@ -178,12 +185,12 @@
wgpu::SwapChainDescriptor desc = baseDescriptor;
desc.presentMode = mode1;
- wgpu::SwapChain swapchain1 = device.CreateSwapChain(surface, &desc);
+ wgpu::SwapChain swapchain1 = CreateSwapChain(surface, &desc);
ClearTexture(swapchain1.GetCurrentTexture(), {0.0, 0.0, 0.0, 1.0});
swapchain1.Present();
desc.presentMode = mode2;
- wgpu::SwapChain swapchain2 = device.CreateSwapChain(surface, &desc);
+ wgpu::SwapChain swapchain2 = CreateSwapChain(surface, &desc);
ClearTexture(swapchain2.GetCurrentTexture(), {0.0, 0.0, 0.0, 1.0});
swapchain2.Present();
}
@@ -197,7 +204,7 @@
desc.width += i * 10;
desc.height -= i * 10;
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &desc);
ClearTexture(swapchain.GetCurrentTexture(), {0.05f * i, 0.0f, 0.0f, 1.0f});
swapchain.Present();
}
@@ -208,7 +215,7 @@
// TODO(crbug.com/1503912): Failing new ValidateImageAcquireWait in Vulkan Validation Layer.
DAWN_SUPPRESS_TEST_IF(IsBackendValidationEnabled() && IsWindows() && IsVulkan() && IsIntel());
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &baseDescriptor);
for (int i = 0; i < 10; i++) {
glfwSetWindowSize(window.get(), 400 - 10 * i, 400 + 10 * i);
@@ -235,7 +242,7 @@
desc.width = width;
desc.height = height;
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &desc);
ClearTexture(swapchain.GetCurrentTexture(), {0.05f * i, 0.0f, 0.0f, 1.0f});
swapchain.Present();
}
@@ -246,12 +253,13 @@
// TODO(https://crbug.com/dawn/2116): Disabled due to new Validation Layer failures.
DAWN_SUPPRESS_TEST_IF(IsVulkan());
+ wgpu::Device device1 = CreateDevice();
wgpu::Device device2 = CreateDevice();
for (int i = 0; i < 3; i++) {
wgpu::Device deviceToUse;
if (i % 2 == 0) {
- deviceToUse = device;
+ deviceToUse = device1;
} else {
deviceToUse = device2;
}
@@ -286,7 +294,7 @@
desc.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment;
ASSERT_DEVICE_ERROR_MSG(
- { auto swapchain = device.CreateSwapChain(surface, &desc); },
+ { auto swapchain = CreateSwapChain(surface, &desc); },
testing::HasSubstr("require enabling FeatureName::SurfaceCapabilities"));
}
@@ -396,7 +404,7 @@
auto desc = baseDescriptor;
desc.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment;
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &desc);
ClearTexture(swapchain.GetCurrentTexture(), {1.0, 0.0, 0.0, 1.0});
SampleTexture(swapchain.GetCurrentTexture(), utils::RGBA8::kRed);
@@ -416,7 +424,7 @@
auto desc = baseDescriptor;
desc.usage = supportedUsage | wgpu::TextureUsage::StorageBinding;
- ASSERT_DEVICE_ERROR_MSG({ auto swapchain = device.CreateSwapChain(surface, &desc); },
+ ASSERT_DEVICE_ERROR_MSG({ auto swapchain = CreateSwapChain(surface, &desc); },
testing::HasSubstr("is not supported"));
}
@@ -433,7 +441,7 @@
desc.width = 1;
desc.height = 1;
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &desc);
wgpu::Texture texture = swapchain.GetCurrentTexture();
WriteTexture(texture, utils::RGBA8::kRed);
@@ -454,7 +462,7 @@
wgpu::SwapChainDescriptor desc = baseDescriptor;
desc.usage |= wgpu::TextureUsage::CopySrc;
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &desc);
wgpu::Texture texture = swapchain.GetCurrentTexture();
ClearTexture(swapchain.GetCurrentTexture(), {1.0, 0.0, 0.0, 1.0});
diff --git a/src/dawn/tests/end2end/SwapChainValidationTests.cpp b/src/dawn/tests/end2end/SwapChainValidationTests.cpp
index a81cd26..a902e25 100644
--- a/src/dawn/tests/end2end/SwapChainValidationTests.cpp
+++ b/src/dawn/tests/end2end/SwapChainValidationTests.cpp
@@ -79,6 +79,13 @@
DawnTest::TearDown();
}
+ wgpu::SwapChain CreateSwapChain(wgpu::Surface const& otherSurface,
+ wgpu::SwapChainDescriptor const* descriptor) {
+ wgpu::SwapChain swapchain;
+ EXPECT_DEPRECATION_WARNING(swapchain = device.CreateSwapChain(otherSurface, descriptor));
+ return swapchain;
+ }
+
protected:
std::unique_ptr<GLFWwindow, GLFWindowDestroyer> window = nullptr;
wgpu::Surface surface;
@@ -136,7 +143,7 @@
// Control case for a successful swapchain creation and presenting.
TEST_P(SwapChainValidationTests, CreationSuccess) {
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &goodDescriptor);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &goodDescriptor);
swapchain.GetCurrentTexture();
swapchain.Present();
}
@@ -146,7 +153,7 @@
wgpu::SurfaceDescriptor surface_desc = {};
wgpu::Surface surface = GetInstance().CreateSurface(&surface_desc);
- ASSERT_DEVICE_ERROR_MSG(device.CreateSwapChain(surface, &goodDescriptor),
+ ASSERT_DEVICE_ERROR_MSG(CreateSwapChain(surface, &goodDescriptor),
testing::HasSubstr("[Surface] is invalid"));
}
@@ -157,33 +164,33 @@
{
wgpu::SwapChainDescriptor desc = goodDescriptor;
desc.width = 0;
- ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
+ ASSERT_DEVICE_ERROR(CreateSwapChain(surface, &desc));
}
// A height of 0 is invalid.
{
wgpu::SwapChainDescriptor desc = goodDescriptor;
desc.height = 0;
- ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
+ ASSERT_DEVICE_ERROR(CreateSwapChain(surface, &desc));
}
// A width of maxTextureDimension2D is valid but maxTextureDimension2D + 1 isn't.
{
wgpu::SwapChainDescriptor desc = goodDescriptor;
desc.width = supportedLimits.maxTextureDimension2D;
- device.CreateSwapChain(surface, &desc);
+ CreateSwapChain(surface, &desc);
desc.width = supportedLimits.maxTextureDimension2D + 1;
- ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
+ ASSERT_DEVICE_ERROR(CreateSwapChain(surface, &desc));
}
// A height of maxTextureDimension2D is valid but maxTextureDimension2D + 1 isn't.
{
wgpu::SwapChainDescriptor desc = goodDescriptor;
desc.height = supportedLimits.maxTextureDimension2D;
- device.CreateSwapChain(surface, &desc);
+ CreateSwapChain(surface, &desc);
desc.height = supportedLimits.maxTextureDimension2D + 1;
- ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
+ ASSERT_DEVICE_ERROR(CreateSwapChain(surface, &desc));
}
}
@@ -191,20 +198,20 @@
TEST_P(SwapChainValidationTests, InvalidCreationUsage) {
wgpu::SwapChainDescriptor desc = goodDescriptor;
desc.usage = wgpu::TextureUsage::TextureBinding;
- ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
+ ASSERT_DEVICE_ERROR(CreateSwapChain(surface, &desc));
}
// Checks that the creation format must (currently) be BGRA8Unorm
TEST_P(SwapChainValidationTests, InvalidCreationFormat) {
wgpu::SwapChainDescriptor desc = goodDescriptor;
desc.format = wgpu::TextureFormat::RGBA8Unorm;
- ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
+ ASSERT_DEVICE_ERROR(CreateSwapChain(surface, &desc));
}
// Check swapchain operations with an error swapchain are errors
TEST_P(SwapChainValidationTests, OperationsOnErrorSwapChain) {
wgpu::SwapChain swapchain;
- ASSERT_DEVICE_ERROR(swapchain = device.CreateSwapChain(surface, &badDescriptor));
+ ASSERT_DEVICE_ERROR(swapchain = CreateSwapChain(surface, &badDescriptor));
wgpu::Texture texture;
ASSERT_DEVICE_ERROR(texture = swapchain.GetCurrentTexture());
@@ -215,7 +222,7 @@
// Check it is invalid to call present without getting a current texture.
TEST_P(SwapChainValidationTests, PresentWithoutCurrentTexture) {
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &goodDescriptor);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &goodDescriptor);
// Check it is invalid if we never called GetCurrentTexture
ASSERT_DEVICE_ERROR(swapchain.Present());
@@ -230,7 +237,7 @@
// swapchain is kept alive by the surface. Also check after we lose all refs to the surface, the
// texture is destroyed.
TEST_P(SwapChainValidationTests, TextureValidAfterSwapChainRefLost) {
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &goodDescriptor);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &goodDescriptor);
wgpu::Texture texture = swapchain.GetCurrentTexture();
swapchain = nullptr;
@@ -242,7 +249,7 @@
// Check that the current texture is the destroyed state after present.
TEST_P(SwapChainValidationTests, TextureDestroyedAfterPresent) {
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &goodDescriptor);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &goodDescriptor);
wgpu::Texture texture = swapchain.GetCurrentTexture();
swapchain.Present();
@@ -286,7 +293,7 @@
wgpu::Texture secondTexture = device.CreateTexture(&textureDesc);
// Get the swapchain view and try to use it in the render pass to trigger all the validation.
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &goodDescriptor);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &goodDescriptor);
wgpu::TextureView view = swapchain.GetCurrentTexture().CreateView();
// Validation will also check the dimension of the view is 2D, and it's usage contains
@@ -315,7 +322,7 @@
TEST_P(SwapChainValidationTests, ReflectionValidGetCurrentTexture) {
// Check with the goodDescriptor.
{
- wgpu::SwapChain swapChain = device.CreateSwapChain(surface, &goodDescriptor);
+ wgpu::SwapChain swapChain = CreateSwapChain(surface, &goodDescriptor);
CheckTextureMatchesDescriptor(swapChain.GetCurrentTexture(), goodDescriptor);
}
// Check with properties that can be changed while keeping a valid descriptor.
@@ -323,7 +330,7 @@
wgpu::SwapChainDescriptor otherDescriptor = goodDescriptor;
otherDescriptor.width = 2;
otherDescriptor.height = 7;
- wgpu::SwapChain swapChain = device.CreateSwapChain(surface, &goodDescriptor);
+ wgpu::SwapChain swapChain = CreateSwapChain(surface, &goodDescriptor);
CheckTextureMatchesDescriptor(swapChain.GetCurrentTexture(), goodDescriptor);
}
}
@@ -331,7 +338,7 @@
// Check the reflection of textures returned by GetCurrentTexture on valid swapchain.
TEST_P(SwapChainValidationTests, ReflectionErrorGetCurrentTexture) {
wgpu::SwapChain swapChain;
- ASSERT_DEVICE_ERROR(swapChain = device.CreateSwapChain(surface, &badDescriptor));
+ ASSERT_DEVICE_ERROR(swapChain = CreateSwapChain(surface, &badDescriptor));
wgpu::Texture texture;
ASSERT_DEVICE_ERROR(texture = swapChain.GetCurrentTexture());
CheckTextureMatchesDescriptor(texture, badDescriptor);
@@ -339,8 +346,8 @@
// Check that failing to create a new swapchain doesn't replace the previous one.
TEST_P(SwapChainValidationTests, ErrorSwapChainDoesntReplacePreviousOne) {
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &goodDescriptor);
- ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &badDescriptor));
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &goodDescriptor);
+ ASSERT_DEVICE_ERROR(CreateSwapChain(surface, &badDescriptor));
swapchain.GetCurrentTexture();
swapchain.Present();
@@ -349,15 +356,15 @@
// Check that after replacement, all swapchain operations are errors and the texture is destroyed.
TEST_P(SwapChainValidationTests, ReplacedSwapChainIsInvalid) {
{
- wgpu::SwapChain replacedSwapChain = device.CreateSwapChain(surface, &goodDescriptor);
- device.CreateSwapChain(surface, &goodDescriptor);
+ wgpu::SwapChain replacedSwapChain = CreateSwapChain(surface, &goodDescriptor);
+ CreateSwapChain(surface, &goodDescriptor);
ASSERT_DEVICE_ERROR(replacedSwapChain.GetCurrentTexture());
}
{
- wgpu::SwapChain replacedSwapChain = device.CreateSwapChain(surface, &goodDescriptor);
+ wgpu::SwapChain replacedSwapChain = CreateSwapChain(surface, &goodDescriptor);
wgpu::Texture texture = replacedSwapChain.GetCurrentTexture();
- device.CreateSwapChain(surface, &goodDescriptor);
+ CreateSwapChain(surface, &goodDescriptor);
CheckTextureIsDestroyed(texture);
ASSERT_DEVICE_ERROR(replacedSwapChain.Present());
@@ -367,12 +374,12 @@
// Check that after surface destruction, all swapchain operations are errors and the texture is
// destroyed. The test is split in two to reset the wgpu::Surface in the middle.
TEST_P(SwapChainValidationTests, SwapChainIsInvalidAfterSurfaceDestruction_GetTexture) {
- wgpu::SwapChain replacedSwapChain = device.CreateSwapChain(surface, &goodDescriptor);
+ wgpu::SwapChain replacedSwapChain = CreateSwapChain(surface, &goodDescriptor);
surface = nullptr;
ASSERT_DEVICE_ERROR(replacedSwapChain.GetCurrentTexture());
}
TEST_P(SwapChainValidationTests, SwapChainIsInvalidAfterSurfaceDestruction_AfterGetTexture) {
- wgpu::SwapChain replacedSwapChain = device.CreateSwapChain(surface, &goodDescriptor);
+ wgpu::SwapChain replacedSwapChain = CreateSwapChain(surface, &goodDescriptor);
wgpu::Texture texture = replacedSwapChain.GetCurrentTexture();
surface = nullptr;
@@ -382,7 +389,7 @@
// Test that new swap chain present after device is lost
TEST_P(SwapChainValidationTests, SwapChainPresentAfterDeviceLost) {
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &goodDescriptor);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &goodDescriptor);
swapchain.GetCurrentTexture();
LoseDeviceForTesting();
@@ -391,7 +398,7 @@
// Test that new swap chain get current texture fails after device is lost
TEST_P(SwapChainValidationTests, SwapChainGetCurrentTextureFailsAfterDevLost) {
- wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &goodDescriptor);
+ wgpu::SwapChain swapchain = CreateSwapChain(surface, &goodDescriptor);
LoseDeviceForTesting();
EXPECT_TRUE(dawn::native::CheckIsErrorForTesting(swapchain.GetCurrentTexture().Get()));
@@ -400,8 +407,8 @@
// Test that creation of a new swapchain fails after device is lost
TEST_P(SwapChainValidationTests, CreateSwapChainFailsAfterDevLost) {
LoseDeviceForTesting();
- EXPECT_TRUE(dawn::native::CheckIsErrorForTesting(
- device.CreateSwapChain(surface, &goodDescriptor).Get()));
+ EXPECT_TRUE(
+ dawn::native::CheckIsErrorForTesting(CreateSwapChain(surface, &goodDescriptor).Get()));
}
DAWN_INSTANTIATE_TEST(SwapChainValidationTests, MetalBackend(), NullBackend());
diff --git a/src/dawn/tests/unittests/native/mocks/DeviceMock.h b/src/dawn/tests/unittests/native/mocks/DeviceMock.h
index 64b405b..6a6a50c 100644
--- a/src/dawn/tests/unittests/native/mocks/DeviceMock.h
+++ b/src/dawn/tests/unittests/native/mocks/DeviceMock.h
@@ -123,7 +123,7 @@
(override));
MOCK_METHOD(ResultOrError<Ref<SwapChainBase>>,
CreateSwapChainImpl,
- (Surface*, SwapChainBase*, const SwapChainDescriptor*),
+ (Surface*, SwapChainBase*, const SurfaceConfiguration*),
(override));
MOCK_METHOD(ResultOrError<Ref<TextureBase>>,
CreateTextureImpl,
diff --git a/src/dawn/tests/unittests/native/mocks/SwapChainMock.cpp b/src/dawn/tests/unittests/native/mocks/SwapChainMock.cpp
index d0c9bcc..6a459cc 100644
--- a/src/dawn/tests/unittests/native/mocks/SwapChainMock.cpp
+++ b/src/dawn/tests/unittests/native/mocks/SwapChainMock.cpp
@@ -31,8 +31,8 @@
SwapChainMock::SwapChainMock(DeviceBase* device,
Surface* surface,
- const SwapChainDescriptor* descriptor)
- : SwapChainBase(device, surface, descriptor) {
+ const SurfaceConfiguration* config)
+ : SwapChainBase(device, surface, config) {
ON_CALL(*this, DestroyImpl).WillByDefault([this] { this->SwapChainBase::DestroyImpl(); });
}
diff --git a/src/dawn/tests/unittests/native/mocks/SwapChainMock.h b/src/dawn/tests/unittests/native/mocks/SwapChainMock.h
index d1068bd..4a0ed0c 100644
--- a/src/dawn/tests/unittests/native/mocks/SwapChainMock.h
+++ b/src/dawn/tests/unittests/native/mocks/SwapChainMock.h
@@ -37,12 +37,12 @@
class SwapChainMock : public SwapChainBase {
public:
- SwapChainMock(DeviceBase* device, Surface* surface, const SwapChainDescriptor* descriptor);
+ SwapChainMock(DeviceBase* device, Surface* surface, const SurfaceConfiguration* config);
~SwapChainMock() override;
MOCK_METHOD(void, DestroyImpl, (), (override));
- MOCK_METHOD(ResultOrError<Ref<TextureBase>>, GetCurrentTextureImpl, (), (override));
+ MOCK_METHOD(ResultOrError<SwapChainTextureInfo>, GetCurrentTextureImpl, (), (override));
MOCK_METHOD(MaybeError, PresentImpl, (), (override));
MOCK_METHOD(void, DetachFromSurfaceImpl, (), (override));
};
diff --git a/src/dawn/utils/CMakeLists.txt b/src/dawn/utils/CMakeLists.txt
index b437164..11f2e0d 100644
--- a/src/dawn/utils/CMakeLists.txt
+++ b/src/dawn/utils/CMakeLists.txt
@@ -60,6 +60,9 @@
SPIRV-Tools-opt
)
+# Needed by WGPUHelpers
+target_compile_definitions(dawn_utils PUBLIC -DTINT_BUILD_SPV_READER=$<BOOL:${TINT_BUILD_SPV_READER}>)
+
if(WIN32 AND NOT WINDOWS_STORE)
target_sources(dawn_utils PRIVATE "WindowsDebugLogger.cpp")
else()
diff --git a/src/dawn/wire/client/Surface.cpp b/src/dawn/wire/client/Surface.cpp
index f54aaca..24d947e 100644
--- a/src/dawn/wire/client/Surface.cpp
+++ b/src/dawn/wire/client/Surface.cpp
@@ -27,7 +27,11 @@
#include "dawn/wire/client/Surface.h"
+#include "dawn/common/Log.h"
#include "dawn/common/Platform.h"
+#include "dawn/wire/client/Client.h"
+#include "dawn/wire/client/Device.h"
+#include "dawn/wire/client/Texture.h"
namespace dawn::wire::client {
@@ -39,9 +43,50 @@
return ObjectType::Surface;
}
+void Surface::Configure(WGPUSurfaceConfiguration const* config) {
+ mTextureDescriptor = {};
+ mTextureDescriptor.size = {config->width, config->height, 1};
+ mTextureDescriptor.format = config->format;
+ mTextureDescriptor.usage = config->usage;
+ mTextureDescriptor.dimension = WGPUTextureDimension_2D;
+ mTextureDescriptor.mipLevelCount = 1;
+ mTextureDescriptor.sampleCount = 1;
+
+ SurfaceConfigureCmd cmd;
+ cmd.self = ToAPI(this);
+ cmd.config = config;
+ GetClient()->SerializeCommand(cmd);
+}
+
WGPUTextureFormat Surface::GetPreferredFormat([[maybe_unused]] WGPUAdapter adapter) const {
+ // TODO(dawn:2320): Use the result of GetCapabilities
// This is the only supported format in native mode (see crbug.com/dawn/160).
return WGPUTextureFormat_BGRA8Unorm;
}
+void Surface::GetCapabilities(WGPUAdapter adapter, WGPUSurfaceCapabilities* capabilities) const {
+ // TODO(dawn:2320): Implement this
+ dawn::ErrorLog() << "surface.GetCapabilities not supported yet with dawn_wire.";
+}
+
+void Surface::GetCurrentTexture(WGPUSurfaceTexture* surfaceTexture) {
+ // TODO(dawn:2320): Implement this
+ dawn::ErrorLog() << "surface.GetCurrentTexture not supported yet with dawn_wire.";
+
+ Client* wireClient = GetClient();
+ Texture* texture = wireClient->Make<Texture>(&mTextureDescriptor);
+ surfaceTexture->texture = ToAPI(texture);
+
+ SurfaceGetCurrentTextureCmd cmd;
+ cmd.self = ToAPI(this);
+ cmd.selfId = GetWireId();
+ // cmd.result = texture->GetWireHandle(); // TODO(dawn:2320): Feed surfaceTexture to cmd
+ wireClient->SerializeCommand(cmd);
+}
+
+void ClientSurfaceCapabilitiesFreeMembers(WGPUSurfaceCapabilities capabilities) {
+ // TODO(dawn:2320): Implement this
+ dawn::ErrorLog() << "surfaceCapabilities.FreeMembers not supported yet with dawn_wire.";
+}
+
} // namespace dawn::wire::client
diff --git a/src/dawn/wire/client/Surface.h b/src/dawn/wire/client/Surface.h
index 08aae69..cb776ea 100644
--- a/src/dawn/wire/client/Surface.h
+++ b/src/dawn/wire/client/Surface.h
@@ -43,9 +43,20 @@
ObjectType GetObjectType() const override;
+ void Configure(WGPUSurfaceConfiguration const* config);
+
WGPUTextureFormat GetPreferredFormat(WGPUAdapter adapter) const;
+
+ void GetCapabilities(WGPUAdapter adapter, WGPUSurfaceCapabilities* capabilities) const;
+
+ void GetCurrentTexture(WGPUSurfaceTexture* surfaceTexture);
+
+ private:
+ WGPUTextureDescriptor mTextureDescriptor;
};
+void ClientSurfaceCapabilitiesFreeMembers(WGPUSurfaceCapabilities capabilities);
+
} // namespace dawn::wire::client
#endif // SRC_DAWN_WIRE_CLIENT_SURFACE_H_