Return an error surface if surface creation fails

Fixes an ASSERT checking the created surface is non-null.

Fixed: chromium:1330113
Change-Id: Iebbcd6e69042abea5b424953d78e294a92ce5c82
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/92140
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Loko Kung <lokokung@google.com>
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Austin Eng 2022-05-31 20:55:39 +00:00 committed by Dawn LUCI CQ
parent 8bd5fec482
commit 6b52f9d1d4
10 changed files with 63 additions and 15 deletions

View File

@ -253,6 +253,8 @@ struct DAWN_NATIVE_EXPORT ExternalImageExportInfo {
ExternalImageType mType; ExternalImageType mType;
}; };
DAWN_NATIVE_EXPORT bool CheckIsErrorForTesting(void* objectHandle);
DAWN_NATIVE_EXPORT const char* GetObjectLabelForTesting(void* objectHandle); DAWN_NATIVE_EXPORT const char* GetObjectLabelForTesting(void* objectHandle);
DAWN_NATIVE_EXPORT uint64_t GetAllocatedSizeForTesting(WGPUBuffer buffer); DAWN_NATIVE_EXPORT uint64_t GetAllocatedSizeForTesting(WGPUBuffer buffer);

View File

@ -300,6 +300,10 @@ ExternalImageType ExternalImageExportInfo::GetType() const {
return mType; return mType;
} }
bool CheckIsErrorForTesting(void* objectHandle) {
return reinterpret_cast<ErrorMonad*>(objectHandle)->IsError();
}
const char* GetObjectLabelForTesting(void* objectHandle) { const char* GetObjectLabelForTesting(void* objectHandle) {
ApiObjectBase* object = reinterpret_cast<ApiObjectBase*>(objectHandle); ApiObjectBase* object = reinterpret_cast<ApiObjectBase*>(objectHandle);
return object->GetLabel().c_str(); return object->GetLabel().c_str();

View File

@ -466,7 +466,7 @@ const XlibXcbFunctions* InstanceBase::GetOrCreateXlibXcbFunctions() {
Surface* InstanceBase::APICreateSurface(const SurfaceDescriptor* descriptor) { Surface* InstanceBase::APICreateSurface(const SurfaceDescriptor* descriptor) {
if (ConsumedError(ValidateSurfaceDescriptor(this, descriptor))) { if (ConsumedError(ValidateSurfaceDescriptor(this, descriptor))) {
return nullptr; return Surface::MakeError(this);
} }
return new Surface(this, descriptor); return new Surface(this, descriptor);

View File

@ -22,18 +22,21 @@ namespace dawn::native {
static constexpr uint64_t kErrorPayload = 0; static constexpr uint64_t kErrorPayload = 0;
static constexpr uint64_t kNotErrorPayload = 1; static constexpr uint64_t kNotErrorPayload = 1;
ObjectBase::ObjectBase(DeviceBase* device) : RefCounted(kNotErrorPayload), mDevice(device) {} ErrorMonad::ErrorMonad() : RefCounted(kNotErrorPayload) {}
ErrorMonad::ErrorMonad(ErrorTag) : RefCounted(kErrorPayload) {}
ObjectBase::ObjectBase(DeviceBase* device, ErrorTag) : RefCounted(kErrorPayload), mDevice(device) {} bool ErrorMonad::IsError() const {
return GetRefCountPayload() == kErrorPayload;
}
ObjectBase::ObjectBase(DeviceBase* device) : ErrorMonad(), mDevice(device) {}
ObjectBase::ObjectBase(DeviceBase* device, ErrorTag) : ErrorMonad(kError), mDevice(device) {}
DeviceBase* ObjectBase::GetDevice() const { DeviceBase* ObjectBase::GetDevice() const {
return mDevice.Get(); return mDevice.Get();
} }
bool ObjectBase::IsError() const {
return GetRefCountPayload() == kErrorPayload;
}
ApiObjectBase::ApiObjectBase(DeviceBase* device, const char* label) : ObjectBase(device) { ApiObjectBase::ApiObjectBase(DeviceBase* device, const char* label) : ObjectBase(device) {
if (label) { if (label) {
mLabel = label; mLabel = label;

View File

@ -25,16 +25,23 @@ namespace dawn::native {
class DeviceBase; class DeviceBase;
class ObjectBase : public RefCounted { class ErrorMonad : public RefCounted {
public: public:
struct ErrorTag {}; struct ErrorTag {};
static constexpr ErrorTag kError = {}; static constexpr ErrorTag kError = {};
ErrorMonad();
explicit ErrorMonad(ErrorTag tag);
bool IsError() const;
};
class ObjectBase : public ErrorMonad {
public:
explicit ObjectBase(DeviceBase* device); explicit ObjectBase(DeviceBase* device);
ObjectBase(DeviceBase* device, ErrorTag tag); ObjectBase(DeviceBase* device, ErrorTag tag);
DeviceBase* GetDevice() const; DeviceBase* GetDevice() const;
bool IsError() const;
private: private:
// Ref to owning device. // Ref to owning device.

View File

@ -150,8 +150,15 @@ MaybeError ValidateSurfaceDescriptor(const InstanceBase* instance,
return DAWN_FORMAT_VALIDATION_ERROR("Unsupported sType (%s)", descriptor->nextInChain->sType); return DAWN_FORMAT_VALIDATION_ERROR("Unsupported sType (%s)", descriptor->nextInChain->sType);
} }
// static
Surface* Surface::MakeError(InstanceBase* instance) {
return new Surface(instance, ErrorMonad::kError);
}
Surface::Surface(InstanceBase* instance, ErrorTag tag) : ErrorMonad(tag), mInstance(instance) {}
Surface::Surface(InstanceBase* instance, const SurfaceDescriptor* descriptor) Surface::Surface(InstanceBase* instance, const SurfaceDescriptor* descriptor)
: mInstance(instance) { : ErrorMonad(), mInstance(instance) {
ASSERT(descriptor->nextInChain != nullptr); ASSERT(descriptor->nextInChain != nullptr);
const SurfaceDescriptorFromAndroidNativeWindow* androidDesc = nullptr; const SurfaceDescriptorFromAndroidNativeWindow* androidDesc = nullptr;
const SurfaceDescriptorFromMetalLayer* metalDesc = nullptr; const SurfaceDescriptorFromMetalLayer* metalDesc = nullptr;
@ -202,41 +209,49 @@ Surface::~Surface() {
} }
NewSwapChainBase* Surface::GetAttachedSwapChain() { NewSwapChainBase* Surface::GetAttachedSwapChain() {
ASSERT(!IsError());
return mSwapChain.Get(); return mSwapChain.Get();
} }
void Surface::SetAttachedSwapChain(NewSwapChainBase* swapChain) { void Surface::SetAttachedSwapChain(NewSwapChainBase* swapChain) {
ASSERT(!IsError());
mSwapChain = swapChain; mSwapChain = swapChain;
} }
InstanceBase* Surface::GetInstance() { InstanceBase* Surface::GetInstance() const {
return mInstance.Get(); return mInstance.Get();
} }
Surface::Type Surface::GetType() const { Surface::Type Surface::GetType() const {
ASSERT(!IsError());
return mType; return mType;
} }
void* Surface::GetAndroidNativeWindow() const { void* Surface::GetAndroidNativeWindow() const {
ASSERT(!IsError());
ASSERT(mType == Type::AndroidWindow); ASSERT(mType == Type::AndroidWindow);
return mAndroidNativeWindow; return mAndroidNativeWindow;
} }
void* Surface::GetMetalLayer() const { void* Surface::GetMetalLayer() const {
ASSERT(!IsError());
ASSERT(mType == Type::MetalLayer); ASSERT(mType == Type::MetalLayer);
return mMetalLayer; return mMetalLayer;
} }
void* Surface::GetHInstance() const { void* Surface::GetHInstance() const {
ASSERT(!IsError());
ASSERT(mType == Type::WindowsHWND); ASSERT(mType == Type::WindowsHWND);
return mHInstance; return mHInstance;
} }
void* Surface::GetHWND() const { void* Surface::GetHWND() const {
ASSERT(!IsError());
ASSERT(mType == Type::WindowsHWND); ASSERT(mType == Type::WindowsHWND);
return mHWND; return mHWND;
} }
IUnknown* Surface::GetCoreWindow() const { IUnknown* Surface::GetCoreWindow() const {
ASSERT(!IsError());
ASSERT(mType == Type::WindowsCoreWindow); ASSERT(mType == Type::WindowsCoreWindow);
#if defined(DAWN_PLATFORM_WINDOWS) #if defined(DAWN_PLATFORM_WINDOWS)
return mCoreWindow.Get(); return mCoreWindow.Get();
@ -246,6 +261,7 @@ IUnknown* Surface::GetCoreWindow() const {
} }
IUnknown* Surface::GetSwapChainPanel() const { IUnknown* Surface::GetSwapChainPanel() const {
ASSERT(!IsError());
ASSERT(mType == Type::WindowsSwapChainPanel); ASSERT(mType == Type::WindowsSwapChainPanel);
#if defined(DAWN_PLATFORM_WINDOWS) #if defined(DAWN_PLATFORM_WINDOWS)
return mSwapChainPanel.Get(); return mSwapChainPanel.Get();
@ -255,10 +271,12 @@ IUnknown* Surface::GetSwapChainPanel() const {
} }
void* Surface::GetXDisplay() const { void* Surface::GetXDisplay() const {
ASSERT(!IsError());
ASSERT(mType == Type::XlibWindow); ASSERT(mType == Type::XlibWindow);
return mXDisplay; return mXDisplay;
} }
uint32_t Surface::GetXWindow() const { uint32_t Surface::GetXWindow() const {
ASSERT(!IsError());
ASSERT(mType == Type::XlibWindow); ASSERT(mType == Type::XlibWindow);
return mXWindow; return mXWindow;
} }

View File

@ -15,9 +15,9 @@
#ifndef SRC_DAWN_NATIVE_SURFACE_H_ #ifndef SRC_DAWN_NATIVE_SURFACE_H_
#define SRC_DAWN_NATIVE_SURFACE_H_ #define SRC_DAWN_NATIVE_SURFACE_H_
#include "dawn/common/RefCounted.h"
#include "dawn/native/Error.h" #include "dawn/native/Error.h"
#include "dawn/native/Forward.h" #include "dawn/native/Forward.h"
#include "dawn/native/ObjectBase.h"
#include "dawn/native/dawn_platform.h" #include "dawn/native/dawn_platform.h"
@ -42,8 +42,10 @@ MaybeError ValidateSurfaceDescriptor(const InstanceBase* instance,
// ObjectiveC). // ObjectiveC).
// The surface is also used to store the current swapchain so that we can detach it when it is // The surface is also used to store the current swapchain so that we can detach it when it is
// replaced. // replaced.
class Surface final : public RefCounted { class Surface final : public ErrorMonad {
public: public:
static Surface* MakeError(InstanceBase* instance);
Surface(InstanceBase* instance, const SurfaceDescriptor* descriptor); Surface(InstanceBase* instance, const SurfaceDescriptor* descriptor);
void SetAttachedSwapChain(NewSwapChainBase* swapChain); void SetAttachedSwapChain(NewSwapChainBase* swapChain);
@ -59,7 +61,7 @@ class Surface final : public RefCounted {
XlibWindow, XlibWindow,
}; };
Type GetType() const; Type GetType() const;
InstanceBase* GetInstance(); InstanceBase* GetInstance() const;
// Valid to call if the type is MetalLayer // Valid to call if the type is MetalLayer
void* GetMetalLayer() const; void* GetMetalLayer() const;
@ -82,6 +84,7 @@ class Surface final : public RefCounted {
uint32_t GetXWindow() const; uint32_t GetXWindow() const;
private: private:
Surface(InstanceBase* instance, ErrorMonad::ErrorTag tag);
~Surface() override; ~Surface() override;
Ref<InstanceBase> mInstance; Ref<InstanceBase> mInstance;

View File

@ -66,6 +66,7 @@ MaybeError ValidateSwapChainDescriptor(const DeviceBase* device,
} else { } else {
DAWN_INVALID_IF(surface == nullptr, DAWN_INVALID_IF(surface == nullptr,
"At least one of surface or implementation must be set"); "At least one of surface or implementation must be set");
DAWN_INVALID_IF(surface->IsError(), "[Surface] is invalid.");
DAWN_TRY(ValidatePresentMode(descriptor->presentMode)); DAWN_TRY(ValidatePresentMode(descriptor->presentMode));

View File

@ -109,6 +109,15 @@ TEST_P(SwapChainValidationTests, CreationSuccess) {
swapchain.Present(); swapchain.Present();
} }
// Test that creating a swapchain with an invalid surface is an error.
TEST_P(SwapChainValidationTests, InvalidSurface) {
wgpu::SurfaceDescriptor surface_desc = {};
wgpu::Surface surface = GetInstance().CreateSurface(&surface_desc);
ASSERT_DEVICE_ERROR_MSG(device.CreateSwapChain(surface, &goodDescriptor),
testing::HasSubstr("[Surface] is invalid"));
}
// Checks that the creation size must be a valid 2D texture size. // Checks that the creation size must be a valid 2D texture size.
TEST_P(SwapChainValidationTests, InvalidCreationSize) { TEST_P(SwapChainValidationTests, InvalidCreationSize) {
wgpu::Limits supportedLimits = GetSupportedLimits().limits; wgpu::Limits supportedLimits = GetSupportedLimits().limits;

View File

@ -63,7 +63,8 @@ class WindowSurfaceInstanceTests : public testing::Test {
} }
void AssertSurfaceCreation(const wgpu::SurfaceDescriptor* descriptor, bool succeeds) { void AssertSurfaceCreation(const wgpu::SurfaceDescriptor* descriptor, bool succeeds) {
ASSERT_EQ(mInstance.CreateSurface(descriptor).Get() != nullptr, succeeds); wgpu::Surface surface = mInstance.CreateSurface(descriptor);
ASSERT_EQ(dawn::native::CheckIsErrorForTesting(surface.Get()), !succeeds);
} }
GLFWwindow* CreateWindow() { GLFWwindow* CreateWindow() {