Add the webgpu.h swapchain creation path
This commit changes wgpu::Device::CreateSwapChain to take an additional wgpu::Surface argument. Passing nullptr is enough to stay on the previous swapchain implementation, until the new one is ready. In order to support both the "old" implementation-based swapchains and the "new" surface-based swapchains. SwapChainBase is now split into three abstract classes: - SwapChainBase that has a virtual method for each of the wgpu::SwapChain methods. - OldSwapChainBase that corresponds to the implementation-based swapchains. - NewSwapChainBase that will contain the surface-based swapchain implementation and will eventually just be renamed to SwapChainBase. The interaction of the surface-based swapchains with the Surface objects aren't implemented yet, neither are the swapchain methods. Only creation works. Validation tests for surface-based swapchain creation are added in the end2end test target because they need to create OS windows. Bug: dawn:269 Change-Id: I7e07d6c666479867b9a16d7b1b8c181d5dbd69a0 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/15281 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
a5a6e4f5bb
commit
d87e676845
13
BUILD.gn
13
BUILD.gn
|
@ -818,8 +818,6 @@ test("dawn_unittests") {
|
|||
"src/dawn_wire/client/ClientMemoryTransferService_mock.h",
|
||||
"src/dawn_wire/server/ServerMemoryTransferService_mock.cpp",
|
||||
"src/dawn_wire/server/ServerMemoryTransferService_mock.h",
|
||||
]
|
||||
sources += [
|
||||
"src/tests/unittests/BitSetIteratorTests.cpp",
|
||||
"src/tests/unittests/BuddyAllocatorTests.cpp",
|
||||
"src/tests/unittests/BuddyMemoryAllocatorTests.cpp",
|
||||
|
@ -950,6 +948,12 @@ source_set("dawn_end2end_tests_sources") {
|
|||
"src/tests/end2end/ViewportTests.cpp",
|
||||
]
|
||||
|
||||
# Validation tests that need OS windows live in end2end tests.
|
||||
sources += [
|
||||
"src/tests/unittests/validation/ValidationTest.cpp",
|
||||
"src/tests/unittests/validation/ValidationTest.h",
|
||||
]
|
||||
|
||||
libs = []
|
||||
|
||||
if (dawn_enable_d3d12) {
|
||||
|
@ -970,7 +974,10 @@ source_set("dawn_end2end_tests_sources") {
|
|||
}
|
||||
|
||||
if (supports_glfw_for_windowing) {
|
||||
sources += [ "src/tests/end2end/WindowSurfaceTests.cpp" ]
|
||||
sources += [
|
||||
"src/tests/end2end/SwapChainValidationTests.cpp",
|
||||
"src/tests/end2end/WindowSurfaceTests.cpp",
|
||||
]
|
||||
deps += [ ":dawn_glfw" ]
|
||||
}
|
||||
}
|
||||
|
|
15
dawn.json
15
dawn.json
|
@ -593,6 +593,7 @@
|
|||
"name": "create swap chain",
|
||||
"returns": "swap chain",
|
||||
"args": [
|
||||
{"name": "surface", "type": "surface"},
|
||||
{"name": "descriptor", "type": "swap chain descriptor", "annotation": "const*"}
|
||||
]
|
||||
},
|
||||
|
@ -859,6 +860,13 @@
|
|||
{"name": "bind group layouts", "type": "bind group layout", "annotation": "const*", "length": "bind group layout count"}
|
||||
]
|
||||
},
|
||||
"present mode": {
|
||||
"category": "enum",
|
||||
"values": [
|
||||
{"value": 0, "name": "no v sync"},
|
||||
{"value": 1, "name": "v sync"}
|
||||
]
|
||||
},
|
||||
"programmable stage descriptor": {
|
||||
"category": "structure",
|
||||
"extensible": true,
|
||||
|
@ -1347,7 +1355,12 @@
|
|||
"extensible": true,
|
||||
"members": [
|
||||
{"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true},
|
||||
{"name": "implementation", "type": "uint64_t"}
|
||||
{"name": "usage", "type": "texture usage"},
|
||||
{"name": "format", "type": "texture format"},
|
||||
{"name": "width", "type": "uint32_t"},
|
||||
{"name": "height", "type": "uint32_t"},
|
||||
{"name": "present mode", "type": "present mode"},
|
||||
{"name": "implementation", "type": "uint64_t", "default": 0}
|
||||
]
|
||||
},
|
||||
"s type": {
|
||||
|
|
|
@ -33,7 +33,7 @@ void init() {
|
|||
descriptor.nextInChain = nullptr;
|
||||
descriptor.label = nullptr;
|
||||
descriptor.implementation = GetSwapChainImplementation();
|
||||
swapchain = wgpuDeviceCreateSwapChain(device, &descriptor);
|
||||
swapchain = wgpuDeviceCreateSwapChain(device, nullptr, &descriptor);
|
||||
}
|
||||
swapChainFormat = static_cast<WGPUTextureFormat>(GetPreferredSwapChainTextureFormat());
|
||||
wgpuSwapChainConfigure(swapchain, swapChainFormat, WGPUTextureUsage_OutputAttachment, 640, 480);
|
||||
|
|
|
@ -180,7 +180,7 @@ wgpu::TextureFormat GetPreferredSwapChainTextureFormat() {
|
|||
wgpu::SwapChain GetSwapChain(const wgpu::Device& device) {
|
||||
wgpu::SwapChainDescriptor swapChainDesc;
|
||||
swapChainDesc.implementation = GetSwapChainImplementation();
|
||||
return device.CreateSwapChain(&swapChainDesc);
|
||||
return device.CreateSwapChain(nullptr, &swapChainDesc);
|
||||
}
|
||||
|
||||
wgpu::TextureView CreateDefaultDepthStencilView(const wgpu::Device& device) {
|
||||
|
|
|
@ -560,10 +560,11 @@ namespace dawn_native {
|
|||
|
||||
return result;
|
||||
}
|
||||
SwapChainBase* DeviceBase::CreateSwapChain(const SwapChainDescriptor* descriptor) {
|
||||
SwapChainBase* DeviceBase::CreateSwapChain(Surface* surface,
|
||||
const SwapChainDescriptor* descriptor) {
|
||||
SwapChainBase* result = nullptr;
|
||||
|
||||
if (ConsumedError(CreateSwapChainInternal(&result, descriptor))) {
|
||||
if (ConsumedError(CreateSwapChainInternal(&result, surface, descriptor))) {
|
||||
return SwapChainBase::MakeError(this);
|
||||
}
|
||||
|
||||
|
@ -821,12 +822,19 @@ namespace dawn_native {
|
|||
}
|
||||
|
||||
MaybeError DeviceBase::CreateSwapChainInternal(SwapChainBase** result,
|
||||
Surface* surface,
|
||||
const SwapChainDescriptor* descriptor) {
|
||||
DAWN_TRY(ValidateIsAlive());
|
||||
if (IsValidationEnabled()) {
|
||||
DAWN_TRY(ValidateSwapChainDescriptor(this, descriptor));
|
||||
DAWN_TRY(ValidateSwapChainDescriptor(this, surface, descriptor));
|
||||
}
|
||||
|
||||
if (surface == nullptr) {
|
||||
DAWN_TRY_ASSIGN(*result, CreateSwapChainImpl(descriptor));
|
||||
} else {
|
||||
ASSERT(descriptor->implementation == 0);
|
||||
DAWN_TRY_ASSIGN(*result, CreateSwapChainImpl(surface, descriptor));
|
||||
}
|
||||
DAWN_TRY_ASSIGN(*result, CreateSwapChainImpl(descriptor));
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ namespace dawn_native {
|
|||
RenderPipelineBase* CreateRenderPipeline(const RenderPipelineDescriptor* descriptor);
|
||||
SamplerBase* CreateSampler(const SamplerDescriptor* descriptor);
|
||||
ShaderModuleBase* CreateShaderModule(const ShaderModuleDescriptor* descriptor);
|
||||
SwapChainBase* CreateSwapChain(const SwapChainDescriptor* descriptor);
|
||||
SwapChainBase* CreateSwapChain(Surface* surface, const SwapChainDescriptor* descriptor);
|
||||
TextureBase* CreateTexture(const TextureDescriptor* descriptor);
|
||||
TextureViewBase* CreateTextureView(TextureBase* texture,
|
||||
const TextureViewDescriptor* descriptor);
|
||||
|
@ -224,6 +224,9 @@ namespace dawn_native {
|
|||
const ShaderModuleDescriptor* descriptor) = 0;
|
||||
virtual ResultOrError<SwapChainBase*> CreateSwapChainImpl(
|
||||
const SwapChainDescriptor* descriptor) = 0;
|
||||
virtual ResultOrError<SwapChainBase*> CreateSwapChainImpl(
|
||||
Surface* surface,
|
||||
const SwapChainDescriptor* descriptor) = 0;
|
||||
virtual ResultOrError<TextureBase*> CreateTextureImpl(
|
||||
const TextureDescriptor* descriptor) = 0;
|
||||
virtual ResultOrError<TextureViewBase*> CreateTextureViewImpl(
|
||||
|
@ -249,6 +252,7 @@ namespace dawn_native {
|
|||
MaybeError CreateShaderModuleInternal(ShaderModuleBase** result,
|
||||
const ShaderModuleDescriptor* descriptor);
|
||||
MaybeError CreateSwapChainInternal(SwapChainBase** result,
|
||||
Surface* surface,
|
||||
const SwapChainDescriptor* descriptor);
|
||||
MaybeError CreateTextureInternal(TextureBase** result, const TextureDescriptor* descriptor);
|
||||
MaybeError CreateTextureViewInternal(TextureViewBase** result,
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace dawn_native {
|
|||
class RenderPipelineBase;
|
||||
class ResourceHeapBase;
|
||||
class SamplerBase;
|
||||
class Surface;
|
||||
class ShaderModuleBase;
|
||||
class StagingBufferBase;
|
||||
class SwapChainBase;
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
|
||||
#include "dawn_native/SwapChain.h"
|
||||
|
||||
#include "common/Constants.h"
|
||||
#include "dawn_native/Device.h"
|
||||
#include "dawn_native/Surface.h"
|
||||
#include "dawn_native/Texture.h"
|
||||
#include "dawn_native/ValidationUtils_autogen.h"
|
||||
|
||||
|
@ -28,40 +30,75 @@ namespace dawn_native {
|
|||
}
|
||||
|
||||
private:
|
||||
TextureBase* GetNextTextureImpl(const TextureDescriptor*) override {
|
||||
UNREACHABLE();
|
||||
void Configure(wgpu::TextureFormat format,
|
||||
wgpu::TextureUsage allowedUsage,
|
||||
uint32_t width,
|
||||
uint32_t height) override {
|
||||
GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("error swapchain"));
|
||||
}
|
||||
|
||||
MaybeError OnBeforePresent(TextureBase* texture) override {
|
||||
UNREACHABLE();
|
||||
TextureViewBase* GetCurrentTextureView() override {
|
||||
GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("error swapchain"));
|
||||
return TextureViewBase::MakeError(GetDevice());
|
||||
}
|
||||
|
||||
void Present() override {
|
||||
GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("error swapchain"));
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
MaybeError ValidateSwapChainDescriptor(const DeviceBase* device,
|
||||
const Surface* surface,
|
||||
const SwapChainDescriptor* descriptor) {
|
||||
if (descriptor->implementation == 0) {
|
||||
return DAWN_VALIDATION_ERROR("Null implementation for the swapchain");
|
||||
}
|
||||
if (descriptor->implementation != 0) {
|
||||
if (surface != nullptr) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"Exactly one of surface or implementation must be set");
|
||||
}
|
||||
|
||||
DawnSwapChainImplementation* impl =
|
||||
reinterpret_cast<DawnSwapChainImplementation*>(descriptor->implementation);
|
||||
DawnSwapChainImplementation* impl =
|
||||
reinterpret_cast<DawnSwapChainImplementation*>(descriptor->implementation);
|
||||
|
||||
if (!impl->Init || !impl->Destroy || !impl->Configure || !impl->GetNextTexture ||
|
||||
!impl->Present) {
|
||||
return DAWN_VALIDATION_ERROR("Implementation is incomplete");
|
||||
if (!impl->Init || !impl->Destroy || !impl->Configure || !impl->GetNextTexture ||
|
||||
!impl->Present) {
|
||||
return DAWN_VALIDATION_ERROR("Implementation is incomplete");
|
||||
}
|
||||
|
||||
} else {
|
||||
if (surface == nullptr) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"At least one of surface or implementation must be set");
|
||||
}
|
||||
|
||||
DAWN_TRY(ValidatePresentMode(descriptor->presentMode));
|
||||
|
||||
// TODO(cwallez@chromium.org): Lift this restriction once
|
||||
// wgpu::Instance::GetPreferredSurfaceFormat is implemented.
|
||||
if (descriptor->format != wgpu::TextureFormat::BGRA8Unorm) {
|
||||
return DAWN_VALIDATION_ERROR("Format must (currently) be BGRA8Unorm");
|
||||
}
|
||||
|
||||
if (descriptor->usage != wgpu::TextureUsage::OutputAttachment) {
|
||||
return DAWN_VALIDATION_ERROR("Usage must (currently) be OutputAttachment");
|
||||
}
|
||||
|
||||
if (descriptor->width == 0 || descriptor->height == 0) {
|
||||
return DAWN_VALIDATION_ERROR("Swapchain size can't be empty");
|
||||
}
|
||||
|
||||
if (descriptor->width > kMaxTextureSize || descriptor->height > kMaxTextureSize) {
|
||||
return DAWN_VALIDATION_ERROR("Swapchain size too big");
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// SwapChain
|
||||
// SwapChainBase
|
||||
|
||||
SwapChainBase::SwapChainBase(DeviceBase* device, const SwapChainDescriptor* descriptor)
|
||||
: ObjectBase(device),
|
||||
mImplementation(
|
||||
*reinterpret_cast<DawnSwapChainImplementation*>(descriptor->implementation)) {
|
||||
SwapChainBase::SwapChainBase(DeviceBase* device) : ObjectBase(device) {
|
||||
}
|
||||
|
||||
SwapChainBase::SwapChainBase(DeviceBase* device, ObjectBase::ErrorTag tag)
|
||||
|
@ -69,10 +106,6 @@ namespace dawn_native {
|
|||
}
|
||||
|
||||
SwapChainBase::~SwapChainBase() {
|
||||
if (!IsError()) {
|
||||
const auto& im = GetImplementation();
|
||||
im.Destroy(im.userData);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -80,10 +113,25 @@ namespace dawn_native {
|
|||
return new ErrorSwapChain(device);
|
||||
}
|
||||
|
||||
void SwapChainBase::Configure(wgpu::TextureFormat format,
|
||||
wgpu::TextureUsage allowedUsage,
|
||||
uint32_t width,
|
||||
uint32_t height) {
|
||||
// OldSwapChainBase
|
||||
|
||||
OldSwapChainBase::OldSwapChainBase(DeviceBase* device, const SwapChainDescriptor* descriptor)
|
||||
: SwapChainBase(device),
|
||||
mImplementation(
|
||||
*reinterpret_cast<DawnSwapChainImplementation*>(descriptor->implementation)) {
|
||||
}
|
||||
|
||||
OldSwapChainBase::~OldSwapChainBase() {
|
||||
if (!IsError()) {
|
||||
const auto& im = GetImplementation();
|
||||
im.Destroy(im.userData);
|
||||
}
|
||||
}
|
||||
|
||||
void OldSwapChainBase::Configure(wgpu::TextureFormat format,
|
||||
wgpu::TextureUsage allowedUsage,
|
||||
uint32_t width,
|
||||
uint32_t height) {
|
||||
if (GetDevice()->ConsumedError(ValidateConfigure(format, allowedUsage, width, height))) {
|
||||
return;
|
||||
}
|
||||
|
@ -99,7 +147,7 @@ namespace dawn_native {
|
|||
static_cast<WGPUTextureUsage>(allowedUsage), width, height);
|
||||
}
|
||||
|
||||
TextureViewBase* SwapChainBase::GetCurrentTextureView() {
|
||||
TextureViewBase* OldSwapChainBase::GetCurrentTextureView() {
|
||||
if (GetDevice()->ConsumedError(ValidateGetCurrentTextureView())) {
|
||||
return TextureViewBase::MakeError(GetDevice());
|
||||
}
|
||||
|
@ -133,7 +181,7 @@ namespace dawn_native {
|
|||
return mCurrentTextureView.Get();
|
||||
}
|
||||
|
||||
void SwapChainBase::Present() {
|
||||
void OldSwapChainBase::Present() {
|
||||
if (GetDevice()->ConsumedError(ValidatePresent())) {
|
||||
return;
|
||||
}
|
||||
|
@ -149,15 +197,15 @@ namespace dawn_native {
|
|||
mCurrentTextureView = nullptr;
|
||||
}
|
||||
|
||||
const DawnSwapChainImplementation& SwapChainBase::GetImplementation() {
|
||||
const DawnSwapChainImplementation& OldSwapChainBase::GetImplementation() {
|
||||
ASSERT(!IsError());
|
||||
return mImplementation;
|
||||
}
|
||||
|
||||
MaybeError SwapChainBase::ValidateConfigure(wgpu::TextureFormat format,
|
||||
wgpu::TextureUsage allowedUsage,
|
||||
uint32_t width,
|
||||
uint32_t height) const {
|
||||
MaybeError OldSwapChainBase::ValidateConfigure(wgpu::TextureFormat format,
|
||||
wgpu::TextureUsage allowedUsage,
|
||||
uint32_t width,
|
||||
uint32_t height) const {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(this));
|
||||
|
||||
DAWN_TRY(ValidateTextureUsage(allowedUsage));
|
||||
|
@ -170,7 +218,7 @@ namespace dawn_native {
|
|||
return {};
|
||||
}
|
||||
|
||||
MaybeError SwapChainBase::ValidateGetCurrentTextureView() const {
|
||||
MaybeError OldSwapChainBase::ValidateGetCurrentTextureView() const {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(this));
|
||||
|
||||
if (mWidth == 0) {
|
||||
|
@ -181,7 +229,7 @@ namespace dawn_native {
|
|||
return {};
|
||||
}
|
||||
|
||||
MaybeError SwapChainBase::ValidatePresent() const {
|
||||
MaybeError OldSwapChainBase::ValidatePresent() const {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(this));
|
||||
|
||||
if (mCurrentTextureView.Get() == nullptr) {
|
||||
|
@ -192,4 +240,56 @@ namespace dawn_native {
|
|||
return {};
|
||||
}
|
||||
|
||||
// Implementation of NewSwapChainBase
|
||||
|
||||
NewSwapChainBase::NewSwapChainBase(DeviceBase* device,
|
||||
Surface* surface,
|
||||
const SwapChainDescriptor* descriptor)
|
||||
: SwapChainBase(device),
|
||||
mWidth(descriptor->width),
|
||||
mHeight(descriptor->height),
|
||||
mFormat(descriptor->format),
|
||||
mUsage(descriptor->usage),
|
||||
mSurface(surface) {
|
||||
}
|
||||
|
||||
void NewSwapChainBase::Configure(wgpu::TextureFormat format,
|
||||
wgpu::TextureUsage allowedUsage,
|
||||
uint32_t width,
|
||||
uint32_t height) {
|
||||
GetDevice()->ConsumedError(
|
||||
DAWN_VALIDATION_ERROR("Configure is invalid for surface-based swapchains"));
|
||||
}
|
||||
|
||||
TextureViewBase* NewSwapChainBase::GetCurrentTextureView() {
|
||||
GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR(
|
||||
"GetCurrentTextureView not implemented yet for surface-based swapchains"));
|
||||
return TextureViewBase::MakeError(GetDevice());
|
||||
}
|
||||
|
||||
void NewSwapChainBase::Present() {
|
||||
GetDevice()->ConsumedError(
|
||||
DAWN_VALIDATION_ERROR("Present not implemented yet for surface-based swapchains"));
|
||||
}
|
||||
|
||||
uint32_t NewSwapChainBase::GetWidth() const {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
uint32_t NewSwapChainBase::GetHeight() const {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
wgpu::TextureFormat NewSwapChainBase::GetFormat() const {
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
wgpu::TextureUsage NewSwapChainBase::GetUsage() const {
|
||||
return mUsage;
|
||||
}
|
||||
|
||||
Surface* NewSwapChainBase::GetSurface() {
|
||||
return mSurface.Get();
|
||||
}
|
||||
|
||||
} // namespace dawn_native
|
||||
|
|
|
@ -25,12 +25,33 @@
|
|||
namespace dawn_native {
|
||||
|
||||
MaybeError ValidateSwapChainDescriptor(const DeviceBase* device,
|
||||
const Surface* surface,
|
||||
const SwapChainDescriptor* descriptor);
|
||||
|
||||
class SwapChainBase : public ObjectBase {
|
||||
public:
|
||||
SwapChainBase(DeviceBase* device, const SwapChainDescriptor* descriptor);
|
||||
~SwapChainBase();
|
||||
SwapChainBase(DeviceBase* device);
|
||||
virtual ~SwapChainBase();
|
||||
|
||||
static SwapChainBase* MakeError(DeviceBase* device);
|
||||
|
||||
// Dawn API
|
||||
virtual void Configure(wgpu::TextureFormat format,
|
||||
wgpu::TextureUsage allowedUsage,
|
||||
uint32_t width,
|
||||
uint32_t height) = 0;
|
||||
virtual TextureViewBase* GetCurrentTextureView() = 0;
|
||||
virtual void Present() = 0;
|
||||
|
||||
protected:
|
||||
SwapChainBase(DeviceBase* device, ObjectBase::ErrorTag tag);
|
||||
};
|
||||
|
||||
// The base class for implementation-based SwapChains that are deprecated.
|
||||
class OldSwapChainBase : public SwapChainBase {
|
||||
public:
|
||||
OldSwapChainBase(DeviceBase* device, const SwapChainDescriptor* descriptor);
|
||||
~OldSwapChainBase();
|
||||
|
||||
static SwapChainBase* MakeError(DeviceBase* device);
|
||||
|
||||
|
@ -38,13 +59,11 @@ namespace dawn_native {
|
|||
void Configure(wgpu::TextureFormat format,
|
||||
wgpu::TextureUsage allowedUsage,
|
||||
uint32_t width,
|
||||
uint32_t height);
|
||||
TextureViewBase* GetCurrentTextureView();
|
||||
void Present();
|
||||
uint32_t height) override;
|
||||
TextureViewBase* GetCurrentTextureView() override;
|
||||
void Present() override;
|
||||
|
||||
protected:
|
||||
SwapChainBase(DeviceBase* device, ObjectBase::ErrorTag tag);
|
||||
|
||||
const DawnSwapChainImplementation& GetImplementation();
|
||||
virtual TextureBase* GetNextTextureImpl(const TextureDescriptor*) = 0;
|
||||
virtual MaybeError OnBeforePresent(TextureBase* texture) = 0;
|
||||
|
@ -66,6 +85,35 @@ namespace dawn_native {
|
|||
Ref<TextureViewBase> mCurrentTextureView;
|
||||
};
|
||||
|
||||
// The base class for surface-based SwapChains that aren't ready yet.
|
||||
class NewSwapChainBase : public SwapChainBase {
|
||||
public:
|
||||
NewSwapChainBase(DeviceBase* device,
|
||||
Surface* surface,
|
||||
const SwapChainDescriptor* descriptor);
|
||||
|
||||
void Configure(wgpu::TextureFormat format,
|
||||
wgpu::TextureUsage allowedUsage,
|
||||
uint32_t width,
|
||||
uint32_t height) override;
|
||||
TextureViewBase* GetCurrentTextureView() override;
|
||||
void Present() override;
|
||||
|
||||
uint32_t GetWidth() const;
|
||||
uint32_t GetHeight() const;
|
||||
wgpu::TextureFormat GetFormat() const;
|
||||
wgpu::TextureUsage GetUsage() const;
|
||||
Surface* GetSurface();
|
||||
|
||||
private:
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
wgpu::TextureFormat mFormat;
|
||||
wgpu::TextureUsage mUsage;
|
||||
|
||||
Ref<Surface> mSurface;
|
||||
};
|
||||
|
||||
} // namespace dawn_native
|
||||
|
||||
#endif // DAWNNATIVE_SWAPCHAIN_H_
|
||||
|
|
|
@ -254,6 +254,11 @@ namespace dawn_native { namespace d3d12 {
|
|||
const SwapChainDescriptor* descriptor) {
|
||||
return new SwapChain(this, descriptor);
|
||||
}
|
||||
ResultOrError<SwapChainBase*> Device::CreateSwapChainImpl(
|
||||
Surface* surface,
|
||||
const SwapChainDescriptor* descriptor) {
|
||||
return DAWN_VALIDATION_ERROR("New swapchains not implemented.");
|
||||
}
|
||||
ResultOrError<TextureBase*> Device::CreateTextureImpl(const TextureDescriptor* descriptor) {
|
||||
return Texture::Create(this, descriptor);
|
||||
}
|
||||
|
|
|
@ -122,6 +122,9 @@ namespace dawn_native { namespace d3d12 {
|
|||
const ShaderModuleDescriptor* descriptor) override;
|
||||
ResultOrError<SwapChainBase*> CreateSwapChainImpl(
|
||||
const SwapChainDescriptor* descriptor) override;
|
||||
ResultOrError<SwapChainBase*> CreateSwapChainImpl(
|
||||
Surface* surface,
|
||||
const SwapChainDescriptor* descriptor) override;
|
||||
ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override;
|
||||
ResultOrError<TextureViewBase*> CreateTextureViewImpl(
|
||||
TextureBase* texture,
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
namespace dawn_native { namespace d3d12 {
|
||||
|
||||
SwapChain::SwapChain(Device* device, const SwapChainDescriptor* descriptor)
|
||||
: SwapChainBase(device, descriptor) {
|
||||
: OldSwapChainBase(device, descriptor) {
|
||||
const auto& im = GetImplementation();
|
||||
DawnWSIContextD3D12 wsiContext = {};
|
||||
wsiContext.device = reinterpret_cast<WGPUDevice>(GetDevice());
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace dawn_native { namespace d3d12 {
|
|||
|
||||
class Device;
|
||||
|
||||
class SwapChain : public SwapChainBase {
|
||||
class SwapChain : public OldSwapChainBase {
|
||||
public:
|
||||
SwapChain(Device* device, const SwapChainDescriptor* descriptor);
|
||||
~SwapChain();
|
||||
|
|
|
@ -85,6 +85,9 @@ namespace dawn_native { namespace metal {
|
|||
const ShaderModuleDescriptor* descriptor) override;
|
||||
ResultOrError<SwapChainBase*> CreateSwapChainImpl(
|
||||
const SwapChainDescriptor* descriptor) override;
|
||||
ResultOrError<SwapChainBase*> CreateSwapChainImpl(
|
||||
Surface* surface,
|
||||
const SwapChainDescriptor* descriptor) override;
|
||||
ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override;
|
||||
ResultOrError<TextureViewBase*> CreateTextureViewImpl(
|
||||
TextureBase* texture,
|
||||
|
|
|
@ -116,6 +116,11 @@ namespace dawn_native { namespace metal {
|
|||
const SwapChainDescriptor* descriptor) {
|
||||
return new SwapChain(this, descriptor);
|
||||
}
|
||||
ResultOrError<SwapChainBase*> Device::CreateSwapChainImpl(
|
||||
Surface* surface,
|
||||
const SwapChainDescriptor* descriptor) {
|
||||
return DAWN_VALIDATION_ERROR("New swapchains not implemented.");
|
||||
}
|
||||
ResultOrError<TextureBase*> Device::CreateTextureImpl(const TextureDescriptor* descriptor) {
|
||||
return new Texture(this, descriptor);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
class Device;
|
||||
|
||||
class SwapChain : public SwapChainBase {
|
||||
class SwapChain : public OldSwapChainBase {
|
||||
public:
|
||||
SwapChain(Device* device, const SwapChainDescriptor* descriptor);
|
||||
~SwapChain();
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
namespace dawn_native { namespace metal {
|
||||
|
||||
SwapChain::SwapChain(Device* device, const SwapChainDescriptor* descriptor)
|
||||
: SwapChainBase(device, descriptor) {
|
||||
: OldSwapChainBase(device, descriptor) {
|
||||
const auto& im = GetImplementation();
|
||||
DawnWSIContextMetal wsiContext = {};
|
||||
wsiContext.device = ToBackend(GetDevice())->GetMTLDevice();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "dawn_native/DynamicUploader.h"
|
||||
#include "dawn_native/ErrorData.h"
|
||||
#include "dawn_native/Instance.h"
|
||||
#include "dawn_native/Surface.h"
|
||||
|
||||
#include <spirv_cross.hpp>
|
||||
|
||||
|
@ -147,7 +148,12 @@ namespace dawn_native { namespace null {
|
|||
}
|
||||
ResultOrError<SwapChainBase*> Device::CreateSwapChainImpl(
|
||||
const SwapChainDescriptor* descriptor) {
|
||||
return new SwapChain(this, descriptor);
|
||||
return new OldSwapChain(this, descriptor);
|
||||
}
|
||||
ResultOrError<SwapChainBase*> Device::CreateSwapChainImpl(
|
||||
Surface* surface,
|
||||
const SwapChainDescriptor* descriptor) {
|
||||
return new SwapChain(this, surface, descriptor);
|
||||
}
|
||||
ResultOrError<TextureBase*> Device::CreateTextureImpl(const TextureDescriptor* descriptor) {
|
||||
return new Texture(this, descriptor, TextureBase::TextureState::OwnedInternal);
|
||||
|
@ -349,20 +355,29 @@ namespace dawn_native { namespace null {
|
|||
|
||||
// SwapChain
|
||||
|
||||
SwapChain::SwapChain(Device* device, const SwapChainDescriptor* descriptor)
|
||||
: SwapChainBase(device, descriptor) {
|
||||
const auto& im = GetImplementation();
|
||||
im.Init(im.userData, nullptr);
|
||||
SwapChain::SwapChain(Device* device, Surface* surface, const SwapChainDescriptor* descriptor)
|
||||
: NewSwapChainBase(device, surface, descriptor) {
|
||||
}
|
||||
|
||||
SwapChain::~SwapChain() {
|
||||
}
|
||||
|
||||
TextureBase* SwapChain::GetNextTextureImpl(const TextureDescriptor* descriptor) {
|
||||
// OldSwapChain
|
||||
|
||||
OldSwapChain::OldSwapChain(Device* device, const SwapChainDescriptor* descriptor)
|
||||
: OldSwapChainBase(device, descriptor) {
|
||||
const auto& im = GetImplementation();
|
||||
im.Init(im.userData, nullptr);
|
||||
}
|
||||
|
||||
OldSwapChain::~OldSwapChain() {
|
||||
}
|
||||
|
||||
TextureBase* OldSwapChain::GetNextTextureImpl(const TextureDescriptor* descriptor) {
|
||||
return GetDevice()->CreateTexture(descriptor);
|
||||
}
|
||||
|
||||
MaybeError SwapChain::OnBeforePresent(TextureBase*) {
|
||||
MaybeError OldSwapChain::OnBeforePresent(TextureBase*) {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -125,6 +125,9 @@ namespace dawn_native { namespace null {
|
|||
const ShaderModuleDescriptor* descriptor) override;
|
||||
ResultOrError<SwapChainBase*> CreateSwapChainImpl(
|
||||
const SwapChainDescriptor* descriptor) override;
|
||||
ResultOrError<SwapChainBase*> CreateSwapChainImpl(
|
||||
Surface* surface,
|
||||
const SwapChainDescriptor* descriptor) override;
|
||||
ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override;
|
||||
ResultOrError<TextureViewBase*> CreateTextureViewImpl(
|
||||
TextureBase* texture,
|
||||
|
@ -197,10 +200,16 @@ namespace dawn_native { namespace null {
|
|||
MaybeError SubmitImpl(uint32_t commandCount, CommandBufferBase* const* commands) override;
|
||||
};
|
||||
|
||||
class SwapChain : public SwapChainBase {
|
||||
class SwapChain : public NewSwapChainBase {
|
||||
public:
|
||||
SwapChain(Device* device, const SwapChainDescriptor* descriptor);
|
||||
SwapChain(Device* device, Surface* surface, const SwapChainDescriptor* descriptor);
|
||||
~SwapChain();
|
||||
};
|
||||
|
||||
class OldSwapChain : public OldSwapChainBase {
|
||||
public:
|
||||
OldSwapChain(Device* device, const SwapChainDescriptor* descriptor);
|
||||
~OldSwapChain();
|
||||
|
||||
protected:
|
||||
TextureBase* GetNextTextureImpl(const TextureDescriptor* descriptor) override;
|
||||
|
|
|
@ -96,6 +96,11 @@ namespace dawn_native { namespace opengl {
|
|||
const SwapChainDescriptor* descriptor) {
|
||||
return new SwapChain(this, descriptor);
|
||||
}
|
||||
ResultOrError<SwapChainBase*> Device::CreateSwapChainImpl(
|
||||
Surface* surface,
|
||||
const SwapChainDescriptor* descriptor) {
|
||||
return DAWN_VALIDATION_ERROR("New swapchains not implemented.");
|
||||
}
|
||||
ResultOrError<TextureBase*> Device::CreateTextureImpl(const TextureDescriptor* descriptor) {
|
||||
return new Texture(this, descriptor);
|
||||
}
|
||||
|
|
|
@ -80,6 +80,9 @@ namespace dawn_native { namespace opengl {
|
|||
const ShaderModuleDescriptor* descriptor) override;
|
||||
ResultOrError<SwapChainBase*> CreateSwapChainImpl(
|
||||
const SwapChainDescriptor* descriptor) override;
|
||||
ResultOrError<SwapChainBase*> CreateSwapChainImpl(
|
||||
Surface* surface,
|
||||
const SwapChainDescriptor* descriptor) override;
|
||||
ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override;
|
||||
ResultOrError<TextureViewBase*> CreateTextureViewImpl(
|
||||
TextureBase* texture,
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
namespace dawn_native { namespace opengl {
|
||||
|
||||
SwapChain::SwapChain(Device* device, const SwapChainDescriptor* descriptor)
|
||||
: SwapChainBase(device, descriptor) {
|
||||
: OldSwapChainBase(device, descriptor) {
|
||||
const auto& im = GetImplementation();
|
||||
im.Init(im.userData, nullptr);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace dawn_native { namespace opengl {
|
|||
|
||||
class Device;
|
||||
|
||||
class SwapChain : public SwapChainBase {
|
||||
class SwapChain : public OldSwapChainBase {
|
||||
public:
|
||||
SwapChain(Device* device, const SwapChainDescriptor* descriptor);
|
||||
~SwapChain();
|
||||
|
|
|
@ -150,6 +150,11 @@ namespace dawn_native { namespace vulkan {
|
|||
const SwapChainDescriptor* descriptor) {
|
||||
return SwapChain::Create(this, descriptor);
|
||||
}
|
||||
ResultOrError<SwapChainBase*> Device::CreateSwapChainImpl(
|
||||
Surface* surface,
|
||||
const SwapChainDescriptor* descriptor) {
|
||||
return DAWN_VALIDATION_ERROR("New swapchains not implemented.");
|
||||
}
|
||||
ResultOrError<TextureBase*> Device::CreateTextureImpl(const TextureDescriptor* descriptor) {
|
||||
return Texture::Create(this, descriptor);
|
||||
}
|
||||
|
|
|
@ -119,6 +119,9 @@ namespace dawn_native { namespace vulkan {
|
|||
const ShaderModuleDescriptor* descriptor) override;
|
||||
ResultOrError<SwapChainBase*> CreateSwapChainImpl(
|
||||
const SwapChainDescriptor* descriptor) override;
|
||||
ResultOrError<SwapChainBase*> CreateSwapChainImpl(
|
||||
Surface* surface,
|
||||
const SwapChainDescriptor* descriptor) override;
|
||||
ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override;
|
||||
ResultOrError<TextureViewBase*> CreateTextureViewImpl(
|
||||
TextureBase* texture,
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace dawn_native { namespace vulkan {
|
|||
}
|
||||
|
||||
SwapChain::SwapChain(Device* device, const SwapChainDescriptor* descriptor)
|
||||
: SwapChainBase(device, descriptor) {
|
||||
: OldSwapChainBase(device, descriptor) {
|
||||
const auto& im = GetImplementation();
|
||||
DawnWSIContextVulkan wsiContext = {};
|
||||
im.Init(im.userData, &wsiContext);
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace dawn_native { namespace vulkan {
|
|||
|
||||
class Device;
|
||||
|
||||
class SwapChain : public SwapChainBase {
|
||||
class SwapChain : public OldSwapChainBase {
|
||||
public:
|
||||
static SwapChain* Create(Device* device, const SwapChainDescriptor* descriptor);
|
||||
~SwapChain();
|
||||
|
|
|
@ -49,13 +49,15 @@ namespace {
|
|||
std::string sInjectedErrorTestcaseOutDir;
|
||||
uint64_t sOutputFileNumber = 0;
|
||||
|
||||
WGPUSwapChain ErrorDeviceCreateSwapChain(WGPUDevice device, const WGPUSwapChainDescriptor*) {
|
||||
WGPUSwapChain ErrorDeviceCreateSwapChain(WGPUDevice device,
|
||||
WGPUSurface surface,
|
||||
const WGPUSwapChainDescriptor*) {
|
||||
WGPUSwapChainDescriptor desc;
|
||||
desc.nextInChain = nullptr;
|
||||
desc.label = nullptr;
|
||||
// A 0 implementation will trigger a swapchain creation error.
|
||||
desc.implementation = 0;
|
||||
return sOriginalDeviceCreateSwapChain(device, &desc);
|
||||
return sOriginalDeviceCreateSwapChain(device, surface, &desc);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -188,7 +188,7 @@ TEST_P(DeviceLostTest, CreateSwapChainFails) {
|
|||
|
||||
wgpu::SwapChainDescriptor descriptor;
|
||||
descriptor.nextInChain = nullptr;
|
||||
ASSERT_DEVICE_ERROR(device.CreateSwapChain(&descriptor));
|
||||
ASSERT_DEVICE_ERROR(device.CreateSwapChain(nullptr, &descriptor));
|
||||
}
|
||||
|
||||
// Tests that CreateTexture fails when device is lost
|
||||
|
@ -212,4 +212,4 @@ TEST_P(DeviceLostTest, TickFails) {
|
|||
ASSERT_DEVICE_ERROR(device.Tick());
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(DeviceLostTest, D3D12Backend, VulkanBackend);
|
||||
DAWN_INSTANTIATE_TEST(DeviceLostTest, D3D12Backend, VulkanBackend);
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
// Copyright 2020 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "tests/unittests/validation/ValidationTest.h"
|
||||
|
||||
#include "common/Constants.h"
|
||||
#include "common/Log.h"
|
||||
#include "utils/GLFWUtils.h"
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
class SwapChainValidationTests : public ValidationTest {
|
||||
public:
|
||||
void SetUp() override {
|
||||
glfwSetErrorCallback([](int code, const char* message) {
|
||||
dawn::ErrorLog() << "GLFW error " << code << " " << message;
|
||||
});
|
||||
glfwInit();
|
||||
|
||||
// The SwapChainValidationTests tests don't create devices so we don't need to call
|
||||
// SetupGLFWWindowHintsForBackend. Set GLFW_NO_API anyway to avoid GLFW bringing up a GL
|
||||
// context that we won't use.
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
window = glfwCreateWindow(400, 400, "SwapChainValidationTests window", nullptr, nullptr);
|
||||
|
||||
surface = utils::CreateSurfaceForWindow(instance->Get(), window);
|
||||
ASSERT_NE(surface, nullptr);
|
||||
|
||||
goodDescriptor.width = 1;
|
||||
goodDescriptor.height = 1;
|
||||
goodDescriptor.usage = wgpu::TextureUsage::OutputAttachment;
|
||||
goodDescriptor.format = wgpu::TextureFormat::BGRA8Unorm;
|
||||
goodDescriptor.presentMode = wgpu::PresentMode::VSync;
|
||||
|
||||
badDescriptor = goodDescriptor;
|
||||
badDescriptor.width = 0;
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
// Destroy the surface before the window as required by webgpu-native.
|
||||
surface = wgpu::Surface();
|
||||
glfwDestroyWindow(window);
|
||||
}
|
||||
|
||||
protected:
|
||||
GLFWwindow* window = nullptr;
|
||||
wgpu::Surface surface;
|
||||
wgpu::SwapChainDescriptor goodDescriptor;
|
||||
wgpu::SwapChainDescriptor badDescriptor;
|
||||
|
||||
// Checks that an OutputAttachment view is an error by trying to create a render pass on it.
|
||||
void CheckTextureViewIsError(wgpu::TextureView view) {
|
||||
utils::ComboRenderPassDescriptor renderPassDesc({view});
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
|
||||
pass.EndPass();
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||
}
|
||||
};
|
||||
|
||||
// Control case for a successful swapchain creation.
|
||||
TEST_F(SwapChainValidationTests, CreationSuccess) {
|
||||
device.CreateSwapChain(surface, &goodDescriptor);
|
||||
}
|
||||
|
||||
// Checks that the creation size must be a valid 2D texture size.
|
||||
TEST_F(SwapChainValidationTests, InvalidCreationSize) {
|
||||
// A width of 0 is invalid.
|
||||
{
|
||||
wgpu::SwapChainDescriptor desc = goodDescriptor;
|
||||
desc.width = 0;
|
||||
ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
|
||||
}
|
||||
// A height of 0 is invalid.
|
||||
{
|
||||
wgpu::SwapChainDescriptor desc = goodDescriptor;
|
||||
desc.height = 0;
|
||||
ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
|
||||
}
|
||||
|
||||
// A width of kMaxTextureSize is valid but kMaxTextureSize + 1 isn't.
|
||||
{
|
||||
wgpu::SwapChainDescriptor desc = goodDescriptor;
|
||||
desc.width = kMaxTextureSize;
|
||||
device.CreateSwapChain(surface, &desc);
|
||||
|
||||
desc.width = kMaxTextureSize + 1;
|
||||
ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
|
||||
}
|
||||
|
||||
// A height of kMaxTextureSize is valid but kMaxTextureSize + 1 isn't.
|
||||
{
|
||||
wgpu::SwapChainDescriptor desc = goodDescriptor;
|
||||
desc.height = kMaxTextureSize;
|
||||
device.CreateSwapChain(surface, &desc);
|
||||
|
||||
desc.height = kMaxTextureSize + 1;
|
||||
ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
|
||||
}
|
||||
}
|
||||
|
||||
// Checks that the creation usage must be OutputAttachment
|
||||
TEST_F(SwapChainValidationTests, InvalidCreationUsage) {
|
||||
wgpu::SwapChainDescriptor desc = goodDescriptor;
|
||||
desc.usage = wgpu::TextureUsage::Sampled;
|
||||
ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
|
||||
}
|
||||
|
||||
// Checks that the creation format must (currently) be BGRA8Unorm
|
||||
TEST_F(SwapChainValidationTests, InvalidCreationFormat) {
|
||||
wgpu::SwapChainDescriptor desc = goodDescriptor;
|
||||
desc.format = wgpu::TextureFormat::RGBA8Unorm;
|
||||
ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
|
||||
}
|
||||
|
||||
// Checks that the implementation must be zero.
|
||||
TEST_F(SwapChainValidationTests, InvalidWithImplementation) {
|
||||
wgpu::SwapChainDescriptor desc = goodDescriptor;
|
||||
desc.implementation = 1;
|
||||
ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &desc));
|
||||
}
|
||||
|
||||
// Check swapchain operations with an error swapchain are errors
|
||||
TEST_F(SwapChainValidationTests, OperationsOnErrorSwapChain) {
|
||||
wgpu::SwapChain swapchain;
|
||||
ASSERT_DEVICE_ERROR(swapchain = device.CreateSwapChain(surface, &badDescriptor));
|
||||
|
||||
wgpu::TextureView view;
|
||||
ASSERT_DEVICE_ERROR(view = swapchain.GetCurrentTextureView());
|
||||
CheckTextureViewIsError(view);
|
||||
|
||||
ASSERT_DEVICE_ERROR(swapchain.Present());
|
||||
}
|
|
@ -39,6 +39,8 @@
|
|||
|
||||
#include "GLFW/glfw3native.h"
|
||||
|
||||
// Test for wgpu::Surface creation that only need an instance (no devices) and don't need all the
|
||||
// complexity of DawnTest.
|
||||
class WindowSurfaceInstanceTests : public testing::Test {
|
||||
public:
|
||||
void SetUp() override {
|
||||
|
|
Loading…
Reference in New Issue