Factor ErrorSink out of DeviceBase
ErrorSink has lots of nice error-handling niceities that would be
useful on the Instance as well.
Bug: dawn:1833
Change-Id: I2cfa20335eb6cc037d1910c190da72cdd8d8963d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/181720
Reviewed-by: Loko Kung <lokokung@google.com>
Reviewed-by: Brandon Jones <bajones@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/src/dawn/native/Adapter.cpp b/src/dawn/native/Adapter.cpp
index 801c7f6..7d19538 100644
--- a/src/dawn/native/Adapter.cpp
+++ b/src/dawn/native/Adapter.cpp
@@ -117,17 +117,17 @@
if (unpacked.Get<AdapterPropertiesMemoryHeaps>() != nullptr &&
!mSupportedFeatures.IsEnabled(wgpu::FeatureName::AdapterPropertiesMemoryHeaps)) {
- instance->ConsumedError(
+ [[maybe_unused]] bool hadError = instance->ConsumedError(
DAWN_VALIDATION_ERROR("Feature AdapterPropertiesMemoryHeaps is not available."));
}
if (unpacked.Get<AdapterPropertiesD3D>() != nullptr &&
!mSupportedFeatures.IsEnabled(wgpu::FeatureName::AdapterPropertiesD3D)) {
- instance->ConsumedError(
+ [[maybe_unused]] bool hadError = instance->ConsumedError(
DAWN_VALIDATION_ERROR("Feature AdapterPropertiesD3D is not available."));
}
if (unpacked.Get<AdapterPropertiesVk>() != nullptr &&
!mSupportedFeatures.IsEnabled(wgpu::FeatureName::AdapterPropertiesVk)) {
- instance->ConsumedError(
+ [[maybe_unused]] bool hadError = instance->ConsumedError(
DAWN_VALIDATION_ERROR("Feature AdapterPropertiesVk is not available."));
}
@@ -197,12 +197,11 @@
descriptor = &kDefaultDesc;
}
- auto result = CreateDevice(descriptor);
- if (result.IsError()) {
- mPhysicalDevice->GetInstance()->ConsumedError(result.AcquireError());
+ Ref<DeviceBase> device;
+ if (mPhysicalDevice->GetInstance()->ConsumedError(CreateDevice(descriptor), &device)) {
return nullptr;
}
- return ReturnToAPI(result.AcquireSuccess());
+ return ReturnToAPI(std::move(device));
}
ResultOrError<Ref<DeviceBase>> AdapterBase::CreateDevice(const DeviceDescriptor* rawDescriptor) {
@@ -334,7 +333,7 @@
FormatCapabilities* capabilities) {
InstanceBase* instance = mPhysicalDevice->GetInstance();
if (!mSupportedFeatures.IsEnabled(wgpu::FeatureName::FormatCapabilities)) {
- instance->ConsumedError(
+ [[maybe_unused]] bool hadError = instance->ConsumedError(
DAWN_VALIDATION_ERROR("Feature FormatCapabilities is not available."));
return false;
}
@@ -347,7 +346,7 @@
if (unpacked.Get<DrmFormatCapabilities>() != nullptr &&
!mSupportedFeatures.IsEnabled(wgpu::FeatureName::DrmFormatCapabilities)) {
- instance->ConsumedError(
+ [[maybe_unused]] bool hadError = instance->ConsumedError(
DAWN_VALIDATION_ERROR("Feature DrmFormatCapabilities is not available."));
return false;
}
diff --git a/src/dawn/native/BUILD.gn b/src/dawn/native/BUILD.gn
index d8c126c..55036fb 100644
--- a/src/dawn/native/BUILD.gn
+++ b/src/dawn/native/BUILD.gn
@@ -276,6 +276,7 @@
"ErrorInjector.h",
"ErrorScope.cpp",
"ErrorScope.h",
+ "ErrorSink.h",
"EventManager.cpp",
"EventManager.h",
"ExecutionQueue.cpp",
diff --git a/src/dawn/native/CMakeLists.txt b/src/dawn/native/CMakeLists.txt
index 9a3d8d5..325d741 100644
--- a/src/dawn/native/CMakeLists.txt
+++ b/src/dawn/native/CMakeLists.txt
@@ -131,6 +131,7 @@
"ErrorInjector.h"
"ErrorScope.cpp"
"ErrorScope.h"
+ "ErrorSink.h"
"EventManager.cpp"
"EventManager.h"
"Features.cpp"
diff --git a/src/dawn/native/Device.h b/src/dawn/native/Device.h
index 663ce83..48301a4 100644
--- a/src/dawn/native/Device.h
+++ b/src/dawn/native/Device.h
@@ -42,6 +42,7 @@
#include "dawn/native/Commands.h"
#include "dawn/native/ComputePipeline.h"
#include "dawn/native/Error.h"
+#include "dawn/native/ErrorSink.h"
#include "dawn/native/ExecutionQueue.h"
#include "dawn/native/Features.h"
#include "dawn/native/Format.h"
@@ -76,7 +77,7 @@
struct InternalPipelineStore;
struct ShaderModuleParseResult;
-class DeviceBase : public RefCountedWithExternalCount {
+class DeviceBase : public ErrorSink, public RefCountedWithExternalCount {
public:
DeviceBase(AdapterBase* adapter,
const UnpackedPtr<DeviceDescriptor>& descriptor,
@@ -93,78 +94,6 @@
InternalErrorType additionalAllowedErrors = InternalErrorType::None,
WGPUDeviceLostReason lost_reason = WGPUDeviceLostReason_Undefined);
- // Variants of ConsumedError must use the returned boolean to handle failure cases since an
- // error may cause a device loss and further execution may be undefined. This is especially
- // true for the ResultOrError variants.
- [[nodiscard]] bool ConsumedError(
- MaybeError maybeError,
- InternalErrorType additionalAllowedErrors = InternalErrorType::None) {
- if (DAWN_UNLIKELY(maybeError.IsError())) {
- ConsumeError(maybeError.AcquireError(), additionalAllowedErrors);
- return true;
- }
- return false;
- }
- template <typename... Args>
- [[nodiscard]] bool ConsumedError(MaybeError maybeError,
- InternalErrorType additionalAllowedErrors,
- const char* formatStr,
- const Args&... args) {
- if (DAWN_UNLIKELY(maybeError.IsError())) {
- std::unique_ptr<ErrorData> error = maybeError.AcquireError();
- if (error->GetType() == InternalErrorType::Validation) {
- error->AppendContext(formatStr, args...);
- }
- ConsumeError(std::move(error), additionalAllowedErrors);
- return true;
- }
- return false;
- }
- template <typename... Args>
- [[nodiscard]] bool ConsumedError(MaybeError maybeError,
- const char* formatStr,
- const Args&... args) {
- return ConsumedError(std::move(maybeError), InternalErrorType::None, formatStr, args...);
- }
-
- template <typename T>
- [[nodiscard]] bool ConsumedError(
- ResultOrError<T> resultOrError,
- T* result,
- InternalErrorType additionalAllowedErrors = InternalErrorType::None) {
- if (DAWN_UNLIKELY(resultOrError.IsError())) {
- ConsumeError(resultOrError.AcquireError(), additionalAllowedErrors);
- return true;
- }
- *result = resultOrError.AcquireSuccess();
- return false;
- }
- template <typename T, typename... Args>
- [[nodiscard]] bool ConsumedError(ResultOrError<T> resultOrError,
- T* result,
- InternalErrorType additionalAllowedErrors,
- const char* formatStr,
- const Args&... args) {
- if (DAWN_UNLIKELY(resultOrError.IsError())) {
- std::unique_ptr<ErrorData> error = resultOrError.AcquireError();
- if (error->GetType() == InternalErrorType::Validation) {
- error->AppendContext(formatStr, args...);
- }
- ConsumeError(std::move(error), additionalAllowedErrors);
- return true;
- }
- *result = resultOrError.AcquireSuccess();
- return false;
- }
- template <typename T, typename... Args>
- [[nodiscard]] bool ConsumedError(ResultOrError<T> resultOrError,
- T* result,
- const char* formatStr,
- const Args&... args) {
- return ConsumedError(std::move(resultOrError), result, InternalErrorType::None, formatStr,
- args...);
- }
-
MaybeError ValidateObject(const ApiObjectBase* object) const;
InstanceBase* GetInstance() const;
@@ -559,8 +488,9 @@
void SetWGSLExtensionAllowList();
+ // ErrorSink implementation
void ConsumeError(std::unique_ptr<ErrorData> error,
- InternalErrorType additionalAllowedErrors = InternalErrorType::None);
+ InternalErrorType additionalAllowedErrors = InternalErrorType::None) override;
bool HasPendingTasks();
bool IsDeviceIdle();
diff --git a/src/dawn/native/ErrorSink.h b/src/dawn/native/ErrorSink.h
new file mode 100644
index 0000000..325691d
--- /dev/null
+++ b/src/dawn/native/ErrorSink.h
@@ -0,0 +1,126 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_DAWN_NATIVE_ERRORSINK_H_
+#define SRC_DAWN_NATIVE_ERRORSINK_H_
+
+#include <memory>
+#include <utility>
+
+#include "dawn/native/ErrorData.h"
+
+namespace dawn::native {
+
+class ErrorSink {
+ public:
+ virtual ~ErrorSink() = default;
+
+ // Variants of ConsumedError must use the returned boolean to handle failure cases since an
+ // error may cause a fatal error and further execution may be undefined. This is especially
+ // true for the ResultOrError variants.
+ [[nodiscard]] bool ConsumedError(
+ MaybeError maybeError,
+ InternalErrorType additionalAllowedErrors = InternalErrorType::None) {
+ if (DAWN_UNLIKELY(maybeError.IsError())) {
+ ConsumeError(maybeError.AcquireError(), additionalAllowedErrors);
+ return true;
+ }
+ return false;
+ }
+
+ template <typename... Args>
+ [[nodiscard]] bool ConsumedError(MaybeError maybeError,
+ InternalErrorType additionalAllowedErrors,
+ const char* formatStr,
+ const Args&... args) {
+ if (DAWN_UNLIKELY(maybeError.IsError())) {
+ std::unique_ptr<ErrorData> error = maybeError.AcquireError();
+ if (error->GetType() == InternalErrorType::Validation) {
+ error->AppendContext(formatStr, args...);
+ }
+ ConsumeError(std::move(error), additionalAllowedErrors);
+ return true;
+ }
+ return false;
+ }
+
+ template <typename... Args>
+ [[nodiscard]] bool ConsumedError(MaybeError maybeError,
+ const char* formatStr,
+ const Args&... args) {
+ return ConsumedError(std::move(maybeError), InternalErrorType::None, formatStr, args...);
+ }
+
+ template <typename T>
+ [[nodiscard]] bool ConsumedError(
+ ResultOrError<T> resultOrError,
+ T* result,
+ InternalErrorType additionalAllowedErrors = InternalErrorType::None) {
+ if (DAWN_UNLIKELY(resultOrError.IsError())) {
+ ConsumeError(resultOrError.AcquireError(), additionalAllowedErrors);
+ return true;
+ }
+ *result = resultOrError.AcquireSuccess();
+ return false;
+ }
+
+ template <typename T, typename... Args>
+ [[nodiscard]] bool ConsumedError(ResultOrError<T> resultOrError,
+ T* result,
+ InternalErrorType additionalAllowedErrors,
+ const char* formatStr,
+ const Args&... args) {
+ if (DAWN_UNLIKELY(resultOrError.IsError())) {
+ std::unique_ptr<ErrorData> error = resultOrError.AcquireError();
+ if (error->GetType() == InternalErrorType::Validation) {
+ error->AppendContext(formatStr, args...);
+ }
+ ConsumeError(std::move(error), additionalAllowedErrors);
+ return true;
+ }
+ *result = resultOrError.AcquireSuccess();
+ return false;
+ }
+
+ template <typename T, typename... Args>
+ [[nodiscard]] bool ConsumedError(ResultOrError<T> resultOrError,
+ T* result,
+ const char* formatStr,
+ const Args&... args) {
+ return ConsumedError(std::move(resultOrError), result, InternalErrorType::None, formatStr,
+ args...);
+ }
+
+ private:
+ virtual void ConsumeError(
+ std::unique_ptr<ErrorData> error,
+ InternalErrorType additionalAllowedErrors = InternalErrorType::None) = 0;
+};
+
+} // namespace dawn::native
+
+#endif // SRC_DAWN_NATIVE_ERRORSINK_H_
diff --git a/src/dawn/native/Instance.cpp b/src/dawn/native/Instance.cpp
index 171e234..a0a7b41 100644
--- a/src/dawn/native/Instance.cpp
+++ b/src/dawn/native/Instance.cpp
@@ -478,14 +478,6 @@
return discoveredPhysicalDevices;
}
-bool InstanceBase::ConsumedError(MaybeError maybeError) {
- if (maybeError.IsError()) {
- ConsumeError(maybeError.AcquireError());
- return true;
- }
- return false;
-}
-
bool InstanceBase::ConsumedErrorAndWarnOnce(MaybeError maybeErr) {
if (!maybeErr.IsError()) {
return false;
@@ -593,7 +585,10 @@
return &mEventManager;
}
-void InstanceBase::ConsumeError(std::unique_ptr<ErrorData> error) {
+void InstanceBase::ConsumeError(std::unique_ptr<ErrorData> error,
+ InternalErrorType additionalAllowedErrors) {
+ // Note: `additionalAllowedErrors` is ignored. The instance considers every type of error to be
+ // an error that is logged.
DAWN_ASSERT(error != nullptr);
if (mLoggingCallback) {
std::string messageStr = error->GetFormattedMessage();
diff --git a/src/dawn/native/Instance.h b/src/dawn/native/Instance.h
index 1f106ed..7aeda22 100644
--- a/src/dawn/native/Instance.h
+++ b/src/dawn/native/Instance.h
@@ -42,6 +42,7 @@
#include "dawn/common/ityp_bitset.h"
#include "dawn/native/Adapter.h"
#include "dawn/native/BackendConnection.h"
+#include "dawn/native/ErrorSink.h"
#include "dawn/native/EventManager.h"
#include "dawn/native/Features.h"
#include "dawn/native/Forward.h"
@@ -72,7 +73,7 @@
// This is called InstanceBase for consistency across the frontend, even if the backends don't
// specialize this class.
-class InstanceBase final : public RefCountedWithExternalCount {
+class InstanceBase final : public ErrorSink, public RefCountedWithExternalCount {
public:
static ResultOrError<Ref<InstanceBase>> Create(const InstanceDescriptor* descriptor = nullptr);
@@ -89,19 +90,6 @@
size_t GetPhysicalDeviceCountForTesting() const;
- // Used to handle error that happen up to device creation.
- bool ConsumedError(MaybeError maybeError);
-
- template <typename T>
- bool ConsumedError(ResultOrError<T> resultOrError, T* result) {
- if (resultOrError.IsError()) {
- ConsumeError(resultOrError.AcquireError());
- return true;
- }
- *result = resultOrError.AcquireSuccess();
- return false;
- }
-
// Consume an error and log its warning at most once. This is useful for
// physical device creation errors that happen because the backend is not
// supported or doesn't meet the required capabilities.
@@ -202,7 +190,10 @@
wgpu::PowerPreference powerPreference) const;
void GatherWGSLFeatures(const DawnWGSLBlocklist* wgslBlocklist);
- void ConsumeError(std::unique_ptr<ErrorData> error);
+
+ // ErrorSink implementation
+ void ConsumeError(std::unique_ptr<ErrorData> error,
+ InternalErrorType additionalAllowedErrors = InternalErrorType::None) override;
absl::flat_hash_set<std::string> mWarningMessages;
diff --git a/src/dawn/native/PhysicalDevice.cpp b/src/dawn/native/PhysicalDevice.cpp
index 6f8bd55..b90c77c 100644
--- a/src/dawn/native/PhysicalDevice.cpp
+++ b/src/dawn/native/PhysicalDevice.cpp
@@ -200,7 +200,7 @@
}
void PhysicalDeviceBase::ResetInternalDeviceForTesting() {
- mInstance->ConsumedError(ResetInternalDeviceForTestingImpl());
+ [[maybe_unused]] bool hadError = mInstance->ConsumedError(ResetInternalDeviceForTestingImpl());
}
MaybeError PhysicalDeviceBase::ResetInternalDeviceForTestingImpl() {
diff --git a/src/dawn/native/vulkan/BackendVk.cpp b/src/dawn/native/vulkan/BackendVk.cpp
index 4dd3597..823ae86 100644
--- a/src/dawn/native/vulkan/BackendVk.cpp
+++ b/src/dawn/native/vulkan/BackendVk.cpp
@@ -573,10 +573,12 @@
if (!mVulkanInstancesCreated[icd]) {
mVulkanInstancesCreated.set(icd);
- instance->ConsumedErrorAndWarnOnce([&]() -> MaybeError {
- DAWN_TRY_ASSIGN(mVulkanInstances[icd], VulkanInstance::Create(instance, icd));
- return {};
- }());
+ [[maybe_unused]] bool hadError =
+ instance->ConsumedErrorAndWarnOnce([&]() -> MaybeError {
+ DAWN_TRY_ASSIGN(mVulkanInstances[icd],
+ VulkanInstance::Create(instance, icd));
+ return {};
+ }());
}
if (mVulkanInstances[icd] == nullptr) {