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:
Corentin Wallez 2020-01-23 17:20:38 +00:00 committed by Commit Bot service account
parent a5a6e4f5bb
commit d87e676845
31 changed files with 460 additions and 73 deletions

View File

@ -818,8 +818,6 @@ test("dawn_unittests") {
"src/dawn_wire/client/ClientMemoryTransferService_mock.h", "src/dawn_wire/client/ClientMemoryTransferService_mock.h",
"src/dawn_wire/server/ServerMemoryTransferService_mock.cpp", "src/dawn_wire/server/ServerMemoryTransferService_mock.cpp",
"src/dawn_wire/server/ServerMemoryTransferService_mock.h", "src/dawn_wire/server/ServerMemoryTransferService_mock.h",
]
sources += [
"src/tests/unittests/BitSetIteratorTests.cpp", "src/tests/unittests/BitSetIteratorTests.cpp",
"src/tests/unittests/BuddyAllocatorTests.cpp", "src/tests/unittests/BuddyAllocatorTests.cpp",
"src/tests/unittests/BuddyMemoryAllocatorTests.cpp", "src/tests/unittests/BuddyMemoryAllocatorTests.cpp",
@ -950,6 +948,12 @@ source_set("dawn_end2end_tests_sources") {
"src/tests/end2end/ViewportTests.cpp", "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 = [] libs = []
if (dawn_enable_d3d12) { if (dawn_enable_d3d12) {
@ -970,7 +974,10 @@ source_set("dawn_end2end_tests_sources") {
} }
if (supports_glfw_for_windowing) { 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" ] deps += [ ":dawn_glfw" ]
} }
} }

View File

@ -593,6 +593,7 @@
"name": "create swap chain", "name": "create swap chain",
"returns": "swap chain", "returns": "swap chain",
"args": [ "args": [
{"name": "surface", "type": "surface"},
{"name": "descriptor", "type": "swap chain descriptor", "annotation": "const*"} {"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"} {"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": { "programmable stage descriptor": {
"category": "structure", "category": "structure",
"extensible": true, "extensible": true,
@ -1347,7 +1355,12 @@
"extensible": true, "extensible": true,
"members": [ "members": [
{"name": "label", "type": "char", "annotation": "const*", "length": "strlen", "optional": true}, {"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": { "s type": {

View File

@ -33,7 +33,7 @@ void init() {
descriptor.nextInChain = nullptr; descriptor.nextInChain = nullptr;
descriptor.label = nullptr; descriptor.label = nullptr;
descriptor.implementation = GetSwapChainImplementation(); descriptor.implementation = GetSwapChainImplementation();
swapchain = wgpuDeviceCreateSwapChain(device, &descriptor); swapchain = wgpuDeviceCreateSwapChain(device, nullptr, &descriptor);
} }
swapChainFormat = static_cast<WGPUTextureFormat>(GetPreferredSwapChainTextureFormat()); swapChainFormat = static_cast<WGPUTextureFormat>(GetPreferredSwapChainTextureFormat());
wgpuSwapChainConfigure(swapchain, swapChainFormat, WGPUTextureUsage_OutputAttachment, 640, 480); wgpuSwapChainConfigure(swapchain, swapChainFormat, WGPUTextureUsage_OutputAttachment, 640, 480);

View File

@ -180,7 +180,7 @@ wgpu::TextureFormat GetPreferredSwapChainTextureFormat() {
wgpu::SwapChain GetSwapChain(const wgpu::Device& device) { wgpu::SwapChain GetSwapChain(const wgpu::Device& device) {
wgpu::SwapChainDescriptor swapChainDesc; wgpu::SwapChainDescriptor swapChainDesc;
swapChainDesc.implementation = GetSwapChainImplementation(); swapChainDesc.implementation = GetSwapChainImplementation();
return device.CreateSwapChain(&swapChainDesc); return device.CreateSwapChain(nullptr, &swapChainDesc);
} }
wgpu::TextureView CreateDefaultDepthStencilView(const wgpu::Device& device) { wgpu::TextureView CreateDefaultDepthStencilView(const wgpu::Device& device) {

View File

@ -560,10 +560,11 @@ namespace dawn_native {
return result; return result;
} }
SwapChainBase* DeviceBase::CreateSwapChain(const SwapChainDescriptor* descriptor) { SwapChainBase* DeviceBase::CreateSwapChain(Surface* surface,
const SwapChainDescriptor* descriptor) {
SwapChainBase* result = nullptr; SwapChainBase* result = nullptr;
if (ConsumedError(CreateSwapChainInternal(&result, descriptor))) { if (ConsumedError(CreateSwapChainInternal(&result, surface, descriptor))) {
return SwapChainBase::MakeError(this); return SwapChainBase::MakeError(this);
} }
@ -821,12 +822,19 @@ namespace dawn_native {
} }
MaybeError DeviceBase::CreateSwapChainInternal(SwapChainBase** result, MaybeError DeviceBase::CreateSwapChainInternal(SwapChainBase** result,
Surface* surface,
const SwapChainDescriptor* descriptor) { const SwapChainDescriptor* descriptor) {
DAWN_TRY(ValidateIsAlive()); DAWN_TRY(ValidateIsAlive());
if (IsValidationEnabled()) { 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 {}; return {};
} }

View File

@ -151,7 +151,7 @@ namespace dawn_native {
RenderPipelineBase* CreateRenderPipeline(const RenderPipelineDescriptor* descriptor); RenderPipelineBase* CreateRenderPipeline(const RenderPipelineDescriptor* descriptor);
SamplerBase* CreateSampler(const SamplerDescriptor* descriptor); SamplerBase* CreateSampler(const SamplerDescriptor* descriptor);
ShaderModuleBase* CreateShaderModule(const ShaderModuleDescriptor* descriptor); ShaderModuleBase* CreateShaderModule(const ShaderModuleDescriptor* descriptor);
SwapChainBase* CreateSwapChain(const SwapChainDescriptor* descriptor); SwapChainBase* CreateSwapChain(Surface* surface, const SwapChainDescriptor* descriptor);
TextureBase* CreateTexture(const TextureDescriptor* descriptor); TextureBase* CreateTexture(const TextureDescriptor* descriptor);
TextureViewBase* CreateTextureView(TextureBase* texture, TextureViewBase* CreateTextureView(TextureBase* texture,
const TextureViewDescriptor* descriptor); const TextureViewDescriptor* descriptor);
@ -224,6 +224,9 @@ namespace dawn_native {
const ShaderModuleDescriptor* descriptor) = 0; const ShaderModuleDescriptor* descriptor) = 0;
virtual ResultOrError<SwapChainBase*> CreateSwapChainImpl( virtual ResultOrError<SwapChainBase*> CreateSwapChainImpl(
const SwapChainDescriptor* descriptor) = 0; const SwapChainDescriptor* descriptor) = 0;
virtual ResultOrError<SwapChainBase*> CreateSwapChainImpl(
Surface* surface,
const SwapChainDescriptor* descriptor) = 0;
virtual ResultOrError<TextureBase*> CreateTextureImpl( virtual ResultOrError<TextureBase*> CreateTextureImpl(
const TextureDescriptor* descriptor) = 0; const TextureDescriptor* descriptor) = 0;
virtual ResultOrError<TextureViewBase*> CreateTextureViewImpl( virtual ResultOrError<TextureViewBase*> CreateTextureViewImpl(
@ -249,6 +252,7 @@ namespace dawn_native {
MaybeError CreateShaderModuleInternal(ShaderModuleBase** result, MaybeError CreateShaderModuleInternal(ShaderModuleBase** result,
const ShaderModuleDescriptor* descriptor); const ShaderModuleDescriptor* descriptor);
MaybeError CreateSwapChainInternal(SwapChainBase** result, MaybeError CreateSwapChainInternal(SwapChainBase** result,
Surface* surface,
const SwapChainDescriptor* descriptor); const SwapChainDescriptor* descriptor);
MaybeError CreateTextureInternal(TextureBase** result, const TextureDescriptor* descriptor); MaybeError CreateTextureInternal(TextureBase** result, const TextureDescriptor* descriptor);
MaybeError CreateTextureViewInternal(TextureViewBase** result, MaybeError CreateTextureViewInternal(TextureViewBase** result,

View File

@ -38,6 +38,7 @@ namespace dawn_native {
class RenderPipelineBase; class RenderPipelineBase;
class ResourceHeapBase; class ResourceHeapBase;
class SamplerBase; class SamplerBase;
class Surface;
class ShaderModuleBase; class ShaderModuleBase;
class StagingBufferBase; class StagingBufferBase;
class SwapChainBase; class SwapChainBase;

View File

@ -14,7 +14,9 @@
#include "dawn_native/SwapChain.h" #include "dawn_native/SwapChain.h"
#include "common/Constants.h"
#include "dawn_native/Device.h" #include "dawn_native/Device.h"
#include "dawn_native/Surface.h"
#include "dawn_native/Texture.h" #include "dawn_native/Texture.h"
#include "dawn_native/ValidationUtils_autogen.h" #include "dawn_native/ValidationUtils_autogen.h"
@ -28,40 +30,75 @@ namespace dawn_native {
} }
private: private:
TextureBase* GetNextTextureImpl(const TextureDescriptor*) override { void Configure(wgpu::TextureFormat format,
UNREACHABLE(); wgpu::TextureUsage allowedUsage,
uint32_t width,
uint32_t height) override {
GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("error swapchain"));
} }
MaybeError OnBeforePresent(TextureBase* texture) override { TextureViewBase* GetCurrentTextureView() override {
UNREACHABLE(); GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("error swapchain"));
return TextureViewBase::MakeError(GetDevice());
}
void Present() override {
GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("error swapchain"));
} }
}; };
} // anonymous namespace } // anonymous namespace
MaybeError ValidateSwapChainDescriptor(const DeviceBase* device, MaybeError ValidateSwapChainDescriptor(const DeviceBase* device,
const Surface* surface,
const SwapChainDescriptor* descriptor) { const SwapChainDescriptor* descriptor) {
if (descriptor->implementation == 0) { if (descriptor->implementation != 0) {
return DAWN_VALIDATION_ERROR("Null implementation for the swapchain"); if (surface != nullptr) {
} return DAWN_VALIDATION_ERROR(
"Exactly one of surface or implementation must be set");
}
DawnSwapChainImplementation* impl = DawnSwapChainImplementation* impl =
reinterpret_cast<DawnSwapChainImplementation*>(descriptor->implementation); reinterpret_cast<DawnSwapChainImplementation*>(descriptor->implementation);
if (!impl->Init || !impl->Destroy || !impl->Configure || !impl->GetNextTexture || if (!impl->Init || !impl->Destroy || !impl->Configure || !impl->GetNextTexture ||
!impl->Present) { !impl->Present) {
return DAWN_VALIDATION_ERROR("Implementation is incomplete"); 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 {}; return {};
} }
// SwapChain // SwapChainBase
SwapChainBase::SwapChainBase(DeviceBase* device, const SwapChainDescriptor* descriptor) SwapChainBase::SwapChainBase(DeviceBase* device) : ObjectBase(device) {
: ObjectBase(device),
mImplementation(
*reinterpret_cast<DawnSwapChainImplementation*>(descriptor->implementation)) {
} }
SwapChainBase::SwapChainBase(DeviceBase* device, ObjectBase::ErrorTag tag) SwapChainBase::SwapChainBase(DeviceBase* device, ObjectBase::ErrorTag tag)
@ -69,10 +106,6 @@ namespace dawn_native {
} }
SwapChainBase::~SwapChainBase() { SwapChainBase::~SwapChainBase() {
if (!IsError()) {
const auto& im = GetImplementation();
im.Destroy(im.userData);
}
} }
// static // static
@ -80,10 +113,25 @@ namespace dawn_native {
return new ErrorSwapChain(device); return new ErrorSwapChain(device);
} }
void SwapChainBase::Configure(wgpu::TextureFormat format, // OldSwapChainBase
wgpu::TextureUsage allowedUsage,
uint32_t width, OldSwapChainBase::OldSwapChainBase(DeviceBase* device, const SwapChainDescriptor* descriptor)
uint32_t height) { : 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))) { if (GetDevice()->ConsumedError(ValidateConfigure(format, allowedUsage, width, height))) {
return; return;
} }
@ -99,7 +147,7 @@ namespace dawn_native {
static_cast<WGPUTextureUsage>(allowedUsage), width, height); static_cast<WGPUTextureUsage>(allowedUsage), width, height);
} }
TextureViewBase* SwapChainBase::GetCurrentTextureView() { TextureViewBase* OldSwapChainBase::GetCurrentTextureView() {
if (GetDevice()->ConsumedError(ValidateGetCurrentTextureView())) { if (GetDevice()->ConsumedError(ValidateGetCurrentTextureView())) {
return TextureViewBase::MakeError(GetDevice()); return TextureViewBase::MakeError(GetDevice());
} }
@ -133,7 +181,7 @@ namespace dawn_native {
return mCurrentTextureView.Get(); return mCurrentTextureView.Get();
} }
void SwapChainBase::Present() { void OldSwapChainBase::Present() {
if (GetDevice()->ConsumedError(ValidatePresent())) { if (GetDevice()->ConsumedError(ValidatePresent())) {
return; return;
} }
@ -149,15 +197,15 @@ namespace dawn_native {
mCurrentTextureView = nullptr; mCurrentTextureView = nullptr;
} }
const DawnSwapChainImplementation& SwapChainBase::GetImplementation() { const DawnSwapChainImplementation& OldSwapChainBase::GetImplementation() {
ASSERT(!IsError()); ASSERT(!IsError());
return mImplementation; return mImplementation;
} }
MaybeError SwapChainBase::ValidateConfigure(wgpu::TextureFormat format, MaybeError OldSwapChainBase::ValidateConfigure(wgpu::TextureFormat format,
wgpu::TextureUsage allowedUsage, wgpu::TextureUsage allowedUsage,
uint32_t width, uint32_t width,
uint32_t height) const { uint32_t height) const {
DAWN_TRY(GetDevice()->ValidateObject(this)); DAWN_TRY(GetDevice()->ValidateObject(this));
DAWN_TRY(ValidateTextureUsage(allowedUsage)); DAWN_TRY(ValidateTextureUsage(allowedUsage));
@ -170,7 +218,7 @@ namespace dawn_native {
return {}; return {};
} }
MaybeError SwapChainBase::ValidateGetCurrentTextureView() const { MaybeError OldSwapChainBase::ValidateGetCurrentTextureView() const {
DAWN_TRY(GetDevice()->ValidateObject(this)); DAWN_TRY(GetDevice()->ValidateObject(this));
if (mWidth == 0) { if (mWidth == 0) {
@ -181,7 +229,7 @@ namespace dawn_native {
return {}; return {};
} }
MaybeError SwapChainBase::ValidatePresent() const { MaybeError OldSwapChainBase::ValidatePresent() const {
DAWN_TRY(GetDevice()->ValidateObject(this)); DAWN_TRY(GetDevice()->ValidateObject(this));
if (mCurrentTextureView.Get() == nullptr) { if (mCurrentTextureView.Get() == nullptr) {
@ -192,4 +240,56 @@ namespace dawn_native {
return {}; 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 } // namespace dawn_native

View File

@ -25,12 +25,33 @@
namespace dawn_native { namespace dawn_native {
MaybeError ValidateSwapChainDescriptor(const DeviceBase* device, MaybeError ValidateSwapChainDescriptor(const DeviceBase* device,
const Surface* surface,
const SwapChainDescriptor* descriptor); const SwapChainDescriptor* descriptor);
class SwapChainBase : public ObjectBase { class SwapChainBase : public ObjectBase {
public: public:
SwapChainBase(DeviceBase* device, const SwapChainDescriptor* descriptor); SwapChainBase(DeviceBase* device);
~SwapChainBase(); 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); static SwapChainBase* MakeError(DeviceBase* device);
@ -38,13 +59,11 @@ namespace dawn_native {
void Configure(wgpu::TextureFormat format, void Configure(wgpu::TextureFormat format,
wgpu::TextureUsage allowedUsage, wgpu::TextureUsage allowedUsage,
uint32_t width, uint32_t width,
uint32_t height); uint32_t height) override;
TextureViewBase* GetCurrentTextureView(); TextureViewBase* GetCurrentTextureView() override;
void Present(); void Present() override;
protected: protected:
SwapChainBase(DeviceBase* device, ObjectBase::ErrorTag tag);
const DawnSwapChainImplementation& GetImplementation(); const DawnSwapChainImplementation& GetImplementation();
virtual TextureBase* GetNextTextureImpl(const TextureDescriptor*) = 0; virtual TextureBase* GetNextTextureImpl(const TextureDescriptor*) = 0;
virtual MaybeError OnBeforePresent(TextureBase* texture) = 0; virtual MaybeError OnBeforePresent(TextureBase* texture) = 0;
@ -66,6 +85,35 @@ namespace dawn_native {
Ref<TextureViewBase> mCurrentTextureView; 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 } // namespace dawn_native
#endif // DAWNNATIVE_SWAPCHAIN_H_ #endif // DAWNNATIVE_SWAPCHAIN_H_

View File

@ -254,6 +254,11 @@ namespace dawn_native { namespace d3d12 {
const SwapChainDescriptor* descriptor) { const SwapChainDescriptor* descriptor) {
return new SwapChain(this, 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) { ResultOrError<TextureBase*> Device::CreateTextureImpl(const TextureDescriptor* descriptor) {
return Texture::Create(this, descriptor); return Texture::Create(this, descriptor);
} }

View File

@ -122,6 +122,9 @@ namespace dawn_native { namespace d3d12 {
const ShaderModuleDescriptor* descriptor) override; const ShaderModuleDescriptor* descriptor) override;
ResultOrError<SwapChainBase*> CreateSwapChainImpl( ResultOrError<SwapChainBase*> CreateSwapChainImpl(
const SwapChainDescriptor* descriptor) override; const SwapChainDescriptor* descriptor) override;
ResultOrError<SwapChainBase*> CreateSwapChainImpl(
Surface* surface,
const SwapChainDescriptor* descriptor) override;
ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override; ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override;
ResultOrError<TextureViewBase*> CreateTextureViewImpl( ResultOrError<TextureViewBase*> CreateTextureViewImpl(
TextureBase* texture, TextureBase* texture,

View File

@ -22,7 +22,7 @@
namespace dawn_native { namespace d3d12 { namespace dawn_native { namespace d3d12 {
SwapChain::SwapChain(Device* device, const SwapChainDescriptor* descriptor) SwapChain::SwapChain(Device* device, const SwapChainDescriptor* descriptor)
: SwapChainBase(device, descriptor) { : OldSwapChainBase(device, descriptor) {
const auto& im = GetImplementation(); const auto& im = GetImplementation();
DawnWSIContextD3D12 wsiContext = {}; DawnWSIContextD3D12 wsiContext = {};
wsiContext.device = reinterpret_cast<WGPUDevice>(GetDevice()); wsiContext.device = reinterpret_cast<WGPUDevice>(GetDevice());

View File

@ -21,7 +21,7 @@ namespace dawn_native { namespace d3d12 {
class Device; class Device;
class SwapChain : public SwapChainBase { class SwapChain : public OldSwapChainBase {
public: public:
SwapChain(Device* device, const SwapChainDescriptor* descriptor); SwapChain(Device* device, const SwapChainDescriptor* descriptor);
~SwapChain(); ~SwapChain();

View File

@ -85,6 +85,9 @@ namespace dawn_native { namespace metal {
const ShaderModuleDescriptor* descriptor) override; const ShaderModuleDescriptor* descriptor) override;
ResultOrError<SwapChainBase*> CreateSwapChainImpl( ResultOrError<SwapChainBase*> CreateSwapChainImpl(
const SwapChainDescriptor* descriptor) override; const SwapChainDescriptor* descriptor) override;
ResultOrError<SwapChainBase*> CreateSwapChainImpl(
Surface* surface,
const SwapChainDescriptor* descriptor) override;
ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override; ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override;
ResultOrError<TextureViewBase*> CreateTextureViewImpl( ResultOrError<TextureViewBase*> CreateTextureViewImpl(
TextureBase* texture, TextureBase* texture,

View File

@ -116,6 +116,11 @@ namespace dawn_native { namespace metal {
const SwapChainDescriptor* descriptor) { const SwapChainDescriptor* descriptor) {
return new SwapChain(this, 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) { ResultOrError<TextureBase*> Device::CreateTextureImpl(const TextureDescriptor* descriptor) {
return new Texture(this, descriptor); return new Texture(this, descriptor);
} }

View File

@ -21,7 +21,7 @@ namespace dawn_native { namespace metal {
class Device; class Device;
class SwapChain : public SwapChainBase { class SwapChain : public OldSwapChainBase {
public: public:
SwapChain(Device* device, const SwapChainDescriptor* descriptor); SwapChain(Device* device, const SwapChainDescriptor* descriptor);
~SwapChain(); ~SwapChain();

View File

@ -22,7 +22,7 @@
namespace dawn_native { namespace metal { namespace dawn_native { namespace metal {
SwapChain::SwapChain(Device* device, const SwapChainDescriptor* descriptor) SwapChain::SwapChain(Device* device, const SwapChainDescriptor* descriptor)
: SwapChainBase(device, descriptor) { : OldSwapChainBase(device, descriptor) {
const auto& im = GetImplementation(); const auto& im = GetImplementation();
DawnWSIContextMetal wsiContext = {}; DawnWSIContextMetal wsiContext = {};
wsiContext.device = ToBackend(GetDevice())->GetMTLDevice(); wsiContext.device = ToBackend(GetDevice())->GetMTLDevice();

View File

@ -19,6 +19,7 @@
#include "dawn_native/DynamicUploader.h" #include "dawn_native/DynamicUploader.h"
#include "dawn_native/ErrorData.h" #include "dawn_native/ErrorData.h"
#include "dawn_native/Instance.h" #include "dawn_native/Instance.h"
#include "dawn_native/Surface.h"
#include <spirv_cross.hpp> #include <spirv_cross.hpp>
@ -147,7 +148,12 @@ namespace dawn_native { namespace null {
} }
ResultOrError<SwapChainBase*> Device::CreateSwapChainImpl( ResultOrError<SwapChainBase*> Device::CreateSwapChainImpl(
const SwapChainDescriptor* descriptor) { 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) { ResultOrError<TextureBase*> Device::CreateTextureImpl(const TextureDescriptor* descriptor) {
return new Texture(this, descriptor, TextureBase::TextureState::OwnedInternal); return new Texture(this, descriptor, TextureBase::TextureState::OwnedInternal);
@ -349,20 +355,29 @@ namespace dawn_native { namespace null {
// SwapChain // SwapChain
SwapChain::SwapChain(Device* device, const SwapChainDescriptor* descriptor) SwapChain::SwapChain(Device* device, Surface* surface, const SwapChainDescriptor* descriptor)
: SwapChainBase(device, descriptor) { : NewSwapChainBase(device, surface, descriptor) {
const auto& im = GetImplementation();
im.Init(im.userData, nullptr);
} }
SwapChain::~SwapChain() { 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); return GetDevice()->CreateTexture(descriptor);
} }
MaybeError SwapChain::OnBeforePresent(TextureBase*) { MaybeError OldSwapChain::OnBeforePresent(TextureBase*) {
return {}; return {};
} }

View File

@ -125,6 +125,9 @@ namespace dawn_native { namespace null {
const ShaderModuleDescriptor* descriptor) override; const ShaderModuleDescriptor* descriptor) override;
ResultOrError<SwapChainBase*> CreateSwapChainImpl( ResultOrError<SwapChainBase*> CreateSwapChainImpl(
const SwapChainDescriptor* descriptor) override; const SwapChainDescriptor* descriptor) override;
ResultOrError<SwapChainBase*> CreateSwapChainImpl(
Surface* surface,
const SwapChainDescriptor* descriptor) override;
ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override; ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override;
ResultOrError<TextureViewBase*> CreateTextureViewImpl( ResultOrError<TextureViewBase*> CreateTextureViewImpl(
TextureBase* texture, TextureBase* texture,
@ -197,10 +200,16 @@ namespace dawn_native { namespace null {
MaybeError SubmitImpl(uint32_t commandCount, CommandBufferBase* const* commands) override; MaybeError SubmitImpl(uint32_t commandCount, CommandBufferBase* const* commands) override;
}; };
class SwapChain : public SwapChainBase { class SwapChain : public NewSwapChainBase {
public: public:
SwapChain(Device* device, const SwapChainDescriptor* descriptor); SwapChain(Device* device, Surface* surface, const SwapChainDescriptor* descriptor);
~SwapChain(); ~SwapChain();
};
class OldSwapChain : public OldSwapChainBase {
public:
OldSwapChain(Device* device, const SwapChainDescriptor* descriptor);
~OldSwapChain();
protected: protected:
TextureBase* GetNextTextureImpl(const TextureDescriptor* descriptor) override; TextureBase* GetNextTextureImpl(const TextureDescriptor* descriptor) override;

View File

@ -96,6 +96,11 @@ namespace dawn_native { namespace opengl {
const SwapChainDescriptor* descriptor) { const SwapChainDescriptor* descriptor) {
return new SwapChain(this, 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) { ResultOrError<TextureBase*> Device::CreateTextureImpl(const TextureDescriptor* descriptor) {
return new Texture(this, descriptor); return new Texture(this, descriptor);
} }

View File

@ -80,6 +80,9 @@ namespace dawn_native { namespace opengl {
const ShaderModuleDescriptor* descriptor) override; const ShaderModuleDescriptor* descriptor) override;
ResultOrError<SwapChainBase*> CreateSwapChainImpl( ResultOrError<SwapChainBase*> CreateSwapChainImpl(
const SwapChainDescriptor* descriptor) override; const SwapChainDescriptor* descriptor) override;
ResultOrError<SwapChainBase*> CreateSwapChainImpl(
Surface* surface,
const SwapChainDescriptor* descriptor) override;
ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override; ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override;
ResultOrError<TextureViewBase*> CreateTextureViewImpl( ResultOrError<TextureViewBase*> CreateTextureViewImpl(
TextureBase* texture, TextureBase* texture,

View File

@ -23,7 +23,7 @@
namespace dawn_native { namespace opengl { namespace dawn_native { namespace opengl {
SwapChain::SwapChain(Device* device, const SwapChainDescriptor* descriptor) SwapChain::SwapChain(Device* device, const SwapChainDescriptor* descriptor)
: SwapChainBase(device, descriptor) { : OldSwapChainBase(device, descriptor) {
const auto& im = GetImplementation(); const auto& im = GetImplementation();
im.Init(im.userData, nullptr); im.Init(im.userData, nullptr);
} }

View File

@ -23,7 +23,7 @@ namespace dawn_native { namespace opengl {
class Device; class Device;
class SwapChain : public SwapChainBase { class SwapChain : public OldSwapChainBase {
public: public:
SwapChain(Device* device, const SwapChainDescriptor* descriptor); SwapChain(Device* device, const SwapChainDescriptor* descriptor);
~SwapChain(); ~SwapChain();

View File

@ -150,6 +150,11 @@ namespace dawn_native { namespace vulkan {
const SwapChainDescriptor* descriptor) { const SwapChainDescriptor* descriptor) {
return SwapChain::Create(this, 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) { ResultOrError<TextureBase*> Device::CreateTextureImpl(const TextureDescriptor* descriptor) {
return Texture::Create(this, descriptor); return Texture::Create(this, descriptor);
} }

View File

@ -119,6 +119,9 @@ namespace dawn_native { namespace vulkan {
const ShaderModuleDescriptor* descriptor) override; const ShaderModuleDescriptor* descriptor) override;
ResultOrError<SwapChainBase*> CreateSwapChainImpl( ResultOrError<SwapChainBase*> CreateSwapChainImpl(
const SwapChainDescriptor* descriptor) override; const SwapChainDescriptor* descriptor) override;
ResultOrError<SwapChainBase*> CreateSwapChainImpl(
Surface* surface,
const SwapChainDescriptor* descriptor) override;
ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override; ResultOrError<TextureBase*> CreateTextureImpl(const TextureDescriptor* descriptor) override;
ResultOrError<TextureViewBase*> CreateTextureViewImpl( ResultOrError<TextureViewBase*> CreateTextureViewImpl(
TextureBase* texture, TextureBase* texture,

View File

@ -25,7 +25,7 @@ namespace dawn_native { namespace vulkan {
} }
SwapChain::SwapChain(Device* device, const SwapChainDescriptor* descriptor) SwapChain::SwapChain(Device* device, const SwapChainDescriptor* descriptor)
: SwapChainBase(device, descriptor) { : OldSwapChainBase(device, descriptor) {
const auto& im = GetImplementation(); const auto& im = GetImplementation();
DawnWSIContextVulkan wsiContext = {}; DawnWSIContextVulkan wsiContext = {};
im.Init(im.userData, &wsiContext); im.Init(im.userData, &wsiContext);

View File

@ -23,7 +23,7 @@ namespace dawn_native { namespace vulkan {
class Device; class Device;
class SwapChain : public SwapChainBase { class SwapChain : public OldSwapChainBase {
public: public:
static SwapChain* Create(Device* device, const SwapChainDescriptor* descriptor); static SwapChain* Create(Device* device, const SwapChainDescriptor* descriptor);
~SwapChain(); ~SwapChain();

View File

@ -49,13 +49,15 @@ namespace {
std::string sInjectedErrorTestcaseOutDir; std::string sInjectedErrorTestcaseOutDir;
uint64_t sOutputFileNumber = 0; uint64_t sOutputFileNumber = 0;
WGPUSwapChain ErrorDeviceCreateSwapChain(WGPUDevice device, const WGPUSwapChainDescriptor*) { WGPUSwapChain ErrorDeviceCreateSwapChain(WGPUDevice device,
WGPUSurface surface,
const WGPUSwapChainDescriptor*) {
WGPUSwapChainDescriptor desc; WGPUSwapChainDescriptor desc;
desc.nextInChain = nullptr; desc.nextInChain = nullptr;
desc.label = nullptr; desc.label = nullptr;
// A 0 implementation will trigger a swapchain creation error. // A 0 implementation will trigger a swapchain creation error.
desc.implementation = 0; desc.implementation = 0;
return sOriginalDeviceCreateSwapChain(device, &desc); return sOriginalDeviceCreateSwapChain(device, surface, &desc);
} }
} // namespace } // namespace

View File

@ -188,7 +188,7 @@ TEST_P(DeviceLostTest, CreateSwapChainFails) {
wgpu::SwapChainDescriptor descriptor; wgpu::SwapChainDescriptor descriptor;
descriptor.nextInChain = nullptr; descriptor.nextInChain = nullptr;
ASSERT_DEVICE_ERROR(device.CreateSwapChain(&descriptor)); ASSERT_DEVICE_ERROR(device.CreateSwapChain(nullptr, &descriptor));
} }
// Tests that CreateTexture fails when device is lost // Tests that CreateTexture fails when device is lost
@ -212,4 +212,4 @@ TEST_P(DeviceLostTest, TickFails) {
ASSERT_DEVICE_ERROR(device.Tick()); ASSERT_DEVICE_ERROR(device.Tick());
} }
DAWN_INSTANTIATE_TEST(DeviceLostTest, D3D12Backend, VulkanBackend); DAWN_INSTANTIATE_TEST(DeviceLostTest, D3D12Backend, VulkanBackend);

View File

@ -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());
}

View File

@ -39,6 +39,8 @@
#include "GLFW/glfw3native.h" #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 { class WindowSurfaceInstanceTests : public testing::Test {
public: public:
void SetUp() override { void SetUp() override {