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/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" ]
}
}

View File

@ -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": {

View File

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

View File

@ -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) {

View File

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

View File

@ -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,

View File

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

View File

@ -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,21 +30,32 @@ 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 =
@ -53,15 +66,39 @@ namespace dawn_native {
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,7 +113,22 @@ namespace dawn_native {
return new ErrorSwapChain(device);
}
void SwapChainBase::Configure(wgpu::TextureFormat format,
// 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) {
@ -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,12 +197,12 @@ namespace dawn_native {
mCurrentTextureView = nullptr;
}
const DawnSwapChainImplementation& SwapChainBase::GetImplementation() {
const DawnSwapChainImplementation& OldSwapChainBase::GetImplementation() {
ASSERT(!IsError());
return mImplementation;
}
MaybeError SwapChainBase::ValidateConfigure(wgpu::TextureFormat format,
MaybeError OldSwapChainBase::ValidateConfigure(wgpu::TextureFormat format,
wgpu::TextureUsage allowedUsage,
uint32_t width,
uint32_t height) const {
@ -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

View File

@ -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_

View File

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

View File

@ -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,

View File

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

View File

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

View File

@ -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,

View File

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

View File

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

View File

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

View File

@ -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 {};
}

View File

@ -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;

View File

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

View File

@ -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,

View File

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

View File

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

View File

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

View File

@ -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,

View File

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

View File

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

View File

@ -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

View File

@ -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

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"
// 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 {