[wgpu-headers] Introduce 2nd userdata to popErrorScope callback.
- Updates the wire to use the new APIs
- Adds new infra needed for C++ lambda helpers
- Updates relevant usages to use new C++ helpers
Bug: 42241407
Change-Id: I6fcca48180bea515374a07737280bbe1d64fc66c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/186863
Reviewed-by: Shrek Shao <shrekshao@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Loko Kung <lokokung@google.com>
diff --git a/generator/templates/api_cpp.h b/generator/templates/api_cpp.h
index 2af158e..9f94756 100644
--- a/generator/templates/api_cpp.h
+++ b/generator/templates/api_cpp.h
@@ -266,6 +266,39 @@
{{as_cppType(types["callback mode"].name)}} mode, F callback, T userdata) const
{%- endmacro %}
+//* This rendering macro should ONLY be used for callback info type functions.
+{% macro render_cpp_callback_info_lambda_method_declaration(type, method, dfn=False) %}
+ {% set CppType = as_cppType(type.name) %}
+ {% set OriginalMethodName = method.name.CamelCase() %}
+ {% set MethodName = OriginalMethodName[:-1] if method.name.chunks[-1] == "2" else OriginalMethodName %}
+ {% set MethodName = CppType + "::" + MethodName if dfn else MethodName %}
+ //* Stripping the 2 at the end of the callback functions for now until we can deprecate old ones.
+ //* TODO: crbug.com/dawn/2509 - Remove name handling once old APIs are deprecated.
+ {% set CallbackInfoType = (method.arguments|last).type %}
+ {% set CallbackType = (CallbackInfoType.members|first).type %}
+ {% set SfinaeArg = " = std::enable_if_t<std::is_convertible_v<L, Cb>>" if not dfn else "" %}
+ template <typename L,
+ typename Cb
+ {%- if not dfn -%}
+ {{" "}}= std::function<void(
+ {%- for arg in CallbackType.arguments -%}
+ {%- if not loop.first %}, {% endif -%}
+ {{as_annotated_cppType(arg)}}
+ {%- endfor -%}
+ )>
+ {%- endif -%},
+ typename{{SfinaeArg}}>
+ {{as_cppType(method.return_type.name)}} {{MethodName}}(
+ {%- for arg in method.arguments if arg.type.category != "callback info" -%}
+ {%- if arg.type.category == "object" and arg.annotation == "value" -%}
+ {{as_cppType(arg.type.name)}} const& {{as_varName(arg.name)}}{{ ", "}}
+ {%- else -%}
+ {{as_annotated_cppType(arg)}}{{ ", "}}
+ {%- endif -%}
+ {%- endfor -%}
+ {{as_cppType(types["callback mode"].name)}} mode, L callback) const
+{%- endmacro %}
+
//* This rendering macro should NOT be used for callback info type functions.
{% macro render_cpp_method_declaration(type, method, dfn=False) %}
{% set CppType = as_cppType(type.name) %}
@@ -332,10 +365,71 @@
callbackInfo.userdata1 = reinterpret_cast<void*>(+callback);
callbackInfo.userdata2 = reinterpret_cast<void*>(userdata);
auto result = {{as_cMethod(type.name, method.name)}}(Get(){{", "}}
- {%- for arg in method.arguments if arg.type.category != "callback info" -%}{{render_c_actual_arg(arg)}}{{", "}}
+ {%- for arg in method.arguments if arg.type.category != "callback info" -%}
+ {{render_c_actual_arg(arg)}}{{", "}}
{%- endfor -%}
callbackInfo);
- return {{convert_cType_to_cppType(method.return_type, 'value', 'result') | indent(8)}};
+ return {{convert_cType_to_cppType(method.return_type, 'value', 'result') | indent(4)}};
+ }
+{%- endmacro %}
+
+{% macro render_cpp_callback_info_lambda_method_impl(type, method) %}
+ {{render_cpp_callback_info_lambda_method_declaration(type, method, dfn=True)}} {
+ {% set CallbackInfoType = (method.arguments|last).type %}
+ {% set CallbackType = (CallbackInfoType.members|first).type %}
+ using F = void (
+ {%- for arg in CallbackType.arguments -%}
+ {%- if not loop.first %}, {% endif -%}
+ {{as_annotated_cppType(arg)}}
+ {%- endfor -%}
+ );
+
+ {{as_cType(CallbackInfoType.name)}} callbackInfo = {};
+ callbackInfo.mode = static_cast<{{as_cType(types["callback mode"].name)}}>(mode);
+ if constexpr (std::is_convertible_v<L, F*>) {
+ callbackInfo.callback = [](
+ {%- for arg in CallbackType.arguments -%}
+ {{as_annotated_cType(arg)}}{{", "}}
+ {%- endfor -%}
+ void* callback, void*) {
+ auto cb = reinterpret_cast<F*>(callback);
+ (*cb)(
+ {%- for arg in CallbackType.arguments -%}
+ {%- if not loop.first %}, {% endif -%}
+ {{convert_cType_to_cppType(arg.type, arg.annotation, as_varName(arg.name))}}
+ {%- endfor -%});
+ };
+ callbackInfo.userdata1 = reinterpret_cast<void*>(+callback);
+ callbackInfo.userdata2 = nullptr;
+ auto result = {{as_cMethod(type.name, method.name)}}(Get(){{", "}}
+ {%- for arg in method.arguments if arg.type.category != "callback info" -%}
+ {{render_c_actual_arg(arg)}}{{", "}}
+ {%- endfor -%}
+ callbackInfo);
+ return {{convert_cType_to_cppType(method.return_type, 'value', 'result') | indent(8)}};
+ } else {
+ auto* lambda = new L(callback);
+ callbackInfo.callback = [](
+ {%- for arg in CallbackType.arguments -%}
+ {{as_annotated_cType(arg)}}{{", "}}
+ {%- endfor -%}
+ void* callback, void*) {
+ std::unique_ptr<L> lambda(reinterpret_cast<L*>(callback));
+ (*lambda)(
+ {%- for arg in CallbackType.arguments -%}
+ {%- if not loop.first %}, {% endif -%}
+ {{convert_cType_to_cppType(arg.type, arg.annotation, as_varName(arg.name))}}
+ {%- endfor -%});
+ };
+ callbackInfo.userdata1 = reinterpret_cast<void*>(lambda);
+ callbackInfo.userdata2 = nullptr;
+ auto result = {{as_cMethod(type.name, method.name)}}(Get(){{", "}}
+ {%- for arg in method.arguments if arg.type.category != "callback info" -%}
+ {{render_c_actual_arg(arg)}}{{", "}}
+ {%- endfor -%}
+ callbackInfo);
+ return {{convert_cType_to_cppType(method.return_type, 'value', 'result') | indent(8)}};
+ }
}
{%- endmacro %}
@@ -364,6 +458,7 @@
{% for method in type.methods %}
{% if has_callbackInfoStruct(method) %}
{{render_cpp_callback_info_template_method_declaration(type, method)|indent}};
+ {{render_cpp_callback_info_lambda_method_declaration(type, method)|indent}};
{% else %}
inline {{render_cpp_method_declaration(type, method)}};
{% endif %}
@@ -540,6 +635,7 @@
{% for method in type.methods %}
{% if has_callbackInfoStruct(method) %}
{{render_cpp_callback_info_template_method_impl(type, method)}}
+ {{render_cpp_callback_info_lambda_method_impl(type, method)}}
{% else %}
{{render_cpp_method_impl(type, method)}}
{% endif %}
diff --git a/src/dawn/dawn.json b/src/dawn/dawn.json
index 2acb36d..b2208f65 100644
--- a/src/dawn/dawn.json
+++ b/src/dawn/dawn.json
@@ -1491,6 +1491,15 @@
]
},
{
+ "name": "pop error scope 2",
+ "_comment": "TODO(crbug.com/dawn/2021): This is dawn/emscripten-only until we rename it to replace the old API. See bug for details.",
+ "tags": ["dawn", "emscripten"],
+ "returns": "future",
+ "args": [
+ {"name": "callback info", "type": "pop error scope callback info 2"}
+ ]
+ },
+ {
"name": "set label",
"returns": "void",
"args": [
@@ -1586,6 +1595,14 @@
{"name": "userdata", "type": "void *"}
]
},
+ "pop error scope callback 2": {
+ "category": "callback function",
+ "args": [
+ {"name": "status", "type": "pop error scope status"},
+ {"name": "type", "type": "error type"},
+ {"name": "message", "type": "char", "annotation": "const*", "length": "strlen"}
+ ]
+ },
"pop error scope callback info": {
"category": "structure",
"extensible": "in",
@@ -1596,6 +1613,12 @@
{"name": "userdata", "type": "void *", "default": "nullptr"}
]
},
+ "pop error scope callback info 2": {
+ "category": "callback info",
+ "members": [
+ {"name": "callback", "type": "pop error scope callback 2"}
+ ]
+ },
"limits": {
"category": "structure",
"members": [
diff --git a/src/dawn/dawn_wire.json b/src/dawn/dawn_wire.json
index 62d42bd..d554885 100644
--- a/src/dawn/dawn_wire.json
+++ b/src/dawn/dawn_wire.json
@@ -229,6 +229,7 @@
"DeviceEnumerateFeatures",
"DevicePopErrorScope",
"DevicePopErrorScopeF",
+ "DevicePopErrorScope2",
"DeviceSetDeviceLostCallback",
"DeviceSetUncapturedErrorCallback",
"DeviceSetLoggingCallback",
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp
index 531996c..e4bdc28 100644
--- a/src/dawn/native/Device.cpp
+++ b/src/dawn/native/Device.cpp
@@ -827,32 +827,42 @@
void DeviceBase::APIPopErrorScope(wgpu::ErrorCallback callback, void* userdata) {
static wgpu::ErrorCallback kDefaultCallback = [](WGPUErrorType, char const*, void*) {};
- PopErrorScopeCallbackInfo callbackInfo = {};
- callbackInfo.mode = wgpu::CallbackMode::AllowProcessEvents;
- callbackInfo.oldCallback = callback != nullptr ? callback : kDefaultCallback;
- callbackInfo.userdata = userdata;
- APIPopErrorScopeF(callbackInfo);
+ APIPopErrorScope2({nullptr, WGPUCallbackMode_AllowProcessEvents,
+ [](WGPUPopErrorScopeStatus, WGPUErrorType type, char const* message,
+ void* callback, void* userdata) {
+ auto cb = reinterpret_cast<wgpu::ErrorCallback>(callback);
+ cb(type, message, userdata);
+ },
+ reinterpret_cast<void*>(callback != nullptr ? callback : kDefaultCallback),
+ userdata});
}
Future DeviceBase::APIPopErrorScopeF(const PopErrorScopeCallbackInfo& callbackInfo) {
+ return APIPopErrorScope2({nullptr, ToAPI(callbackInfo.mode),
+ [](WGPUPopErrorScopeStatus status, WGPUErrorType type,
+ char const* message, void* callback, void* userdata) {
+ auto cb = reinterpret_cast<WGPUPopErrorScopeCallback>(callback);
+ cb(status, type, message, userdata);
+ },
+ reinterpret_cast<void*>(callbackInfo.callback),
+ callbackInfo.userdata});
+}
+
+Future DeviceBase::APIPopErrorScope2(const WGPUPopErrorScopeCallbackInfo2& callbackInfo) {
struct PopErrorScopeEvent final : public EventManager::TrackedEvent {
- // TODO(crbug.com/dawn/2021) Remove the old callback type.
- WGPUPopErrorScopeCallback mCallback;
- WGPUErrorCallback mOldCallback;
- void* mUserdata;
+ WGPUPopErrorScopeCallback2 mCallback;
+ raw_ptr<void> mUserdata1;
+ raw_ptr<void> mUserdata2;
std::optional<ErrorScope> mScope;
- PopErrorScopeEvent(const PopErrorScopeCallbackInfo& callbackInfo,
+ PopErrorScopeEvent(const WGPUPopErrorScopeCallbackInfo2& callbackInfo,
std::optional<ErrorScope>&& scope)
- : TrackedEvent(callbackInfo.mode, TrackedEvent::Completed{}),
+ : TrackedEvent(static_cast<wgpu::CallbackMode>(callbackInfo.mode),
+ TrackedEvent::Completed{}),
mCallback(callbackInfo.callback),
- mOldCallback(callbackInfo.oldCallback),
- mUserdata(callbackInfo.userdata),
- mScope(scope) {
- // Exactly 1 callback should be set.
- DAWN_ASSERT((mCallback != nullptr && mOldCallback == nullptr) ||
- (mCallback == nullptr && mOldCallback != nullptr));
- }
+ mUserdata1(callbackInfo.userdata1),
+ mUserdata2(callbackInfo.userdata2),
+ mScope(scope) {}
~PopErrorScopeEvent() override { EnsureComplete(EventCompletionType::Shutdown); }
@@ -870,11 +880,8 @@
message = "No error scopes to pop";
}
- if (mCallback) {
- mCallback(status, type, message, mUserdata);
- } else {
- mOldCallback(type, message, mUserdata);
- }
+ mCallback(status, type, message, mUserdata1.ExtractAsDangling(),
+ mUserdata2.ExtractAsDangling());
}
};
diff --git a/src/dawn/native/Device.h b/src/dawn/native/Device.h
index d8b014d..831d0b8 100644
--- a/src/dawn/native/Device.h
+++ b/src/dawn/native/Device.h
@@ -301,6 +301,7 @@
void APIPushErrorScope(wgpu::ErrorFilter filter);
void APIPopErrorScope(wgpu::ErrorCallback callback, void* userdata);
Future APIPopErrorScopeF(const PopErrorScopeCallbackInfo& callbackInfo);
+ Future APIPopErrorScope2(const WGPUPopErrorScopeCallbackInfo2& callbackInfo);
MaybeError ValidateIsAlive() const;
diff --git a/src/dawn/tests/MockCallback.h b/src/dawn/tests/MockCallback.h
index 81f484c..1638eb3 100644
--- a/src/dawn/tests/MockCallback.h
+++ b/src/dawn/tests/MockCallback.h
@@ -113,6 +113,23 @@
std::set<std::unique_ptr<MockAndUserdata>> mUserdatas;
};
+template <typename F>
+class MockCppCallback;
+
+// Helper wrapper class for C++ entry point callbacks.
+// Example Usage:
+// MockCppCallback<void (*)(wgpu::PopErrorScopeStatus, wgpu::ErrorType, const char*)> mock;
+//
+// device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents, mock.Callback());
+// EXPECT_CALL(mock, Call(wgpu::PopErrorScopeStatus::Success, _, _));
+template <typename R, typename... Args>
+class MockCppCallback<R (*)(Args...)> : public ::testing::MockFunction<R(Args...)> {
+ public:
+ auto Callback() {
+ return [this](Args... args) -> R { return this->Call(args...); };
+ }
+};
+
} // namespace testing
#endif // SRC_DAWN_TESTS_MOCKCALLBACK_H_
diff --git a/src/dawn/tests/end2end/DeviceLifetimeTests.cpp b/src/dawn/tests/end2end/DeviceLifetimeTests.cpp
index 170c42b..4fc14e2 100644
--- a/src/dawn/tests/end2end/DeviceLifetimeTests.cpp
+++ b/src/dawn/tests/end2end/DeviceLifetimeTests.cpp
@@ -102,9 +102,11 @@
bool done = false;
device.PopErrorScope(
- [](WGPUErrorType type, const char*, void* userdata) {
- *static_cast<bool*>(userdata) = true;
- EXPECT_EQ(type, WGPUErrorType_NoError);
+ wgpu::CallbackMode::AllowProcessEvents,
+ [](wgpu::PopErrorScopeStatus status, wgpu::ErrorType type, const char*, bool* done) {
+ *done = true;
+ EXPECT_EQ(status, wgpu::PopErrorScopeStatus::Success);
+ EXPECT_EQ(type, wgpu::ErrorType::NoError);
},
&done);
device = nullptr;
@@ -125,10 +127,13 @@
// Ask for a popErrorScope callback and drop the device inside the callback.
Userdata data = Userdata{std::move(device), false};
data.device.PopErrorScope(
- [](WGPUErrorType type, const char*, void* userdata) {
- EXPECT_EQ(type, WGPUErrorType_NoError);
- static_cast<Userdata*>(userdata)->device = nullptr;
- static_cast<Userdata*>(userdata)->done = true;
+ wgpu::CallbackMode::AllowProcessEvents,
+ [](wgpu::PopErrorScopeStatus status, wgpu::ErrorType type, const char*,
+ Userdata* userdata) {
+ EXPECT_EQ(status, wgpu::PopErrorScopeStatus::Success);
+ EXPECT_EQ(type, wgpu::ErrorType::NoError);
+ userdata->device = nullptr;
+ userdata->done = true;
},
&data);
@@ -555,9 +560,9 @@
// The following callback will drop the 2nd device. It won't be triggered until
// instance.ProcessEvents() is called.
device.PopErrorScope(
- [](WGPUErrorType type, const char*, void* userdataPtr) {
- auto userdata = static_cast<UserData*>(userdataPtr);
-
+ wgpu::CallbackMode::AllowProcessEvents,
+ [](wgpu::PopErrorScopeStatus status, wgpu::ErrorType type, const char*,
+ UserData* userdata) {
userdata->device2 = nullptr;
userdata->done = true;
},
diff --git a/src/dawn/tests/end2end/EventTests.cpp b/src/dawn/tests/end2end/EventTests.cpp
index 4f8e15a..a84f5fc 100644
--- a/src/dawn/tests/end2end/EventTests.cpp
+++ b/src/dawn/tests/end2end/EventTests.cpp
@@ -647,9 +647,8 @@
// PopErrorScope is implemented via a signal.
device.PushErrorScope(wgpu::ErrorFilter::Validation);
- device.PopErrorScope({nullptr, wgpu::CallbackMode::AllowProcessEvents,
- [](WGPUPopErrorScopeStatus, WGPUErrorType, char const*, void*) {},
- nullptr, nullptr});
+ device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents,
+ [](wgpu::PopErrorScopeStatus, wgpu::ErrorType, const char*) {});
instance.ProcessEvents();
}
diff --git a/src/dawn/tests/end2end/MaxLimitTests.cpp b/src/dawn/tests/end2end/MaxLimitTests.cpp
index 742be91..928452d 100644
--- a/src/dawn/tests/end2end/MaxLimitTests.cpp
+++ b/src/dawn/tests/end2end/MaxLimitTests.cpp
@@ -220,14 +220,14 @@
bufDesc.usage = usage | wgpu::BufferUsage::CopyDst;
wgpu::Buffer buffer = device.CreateBuffer(&bufDesc);
- WGPUErrorType oomResult;
- device.PopErrorScope([](WGPUErrorType type, const char*,
- void* userdata) { *static_cast<WGPUErrorType*>(userdata) = type; },
- &oomResult);
- instance.ProcessEvents();
+ wgpu::ErrorType oomResult;
+ device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents,
+ [&oomResult](wgpu::PopErrorScopeStatus, wgpu::ErrorType type,
+ const char*) { oomResult = type; });
FlushWire();
+ instance.ProcessEvents();
// Max buffer size is smaller than the max buffer binding size.
- DAWN_TEST_UNSUPPORTED_IF(oomResult == WGPUErrorType_OutOfMemory);
+ DAWN_TEST_UNSUPPORTED_IF(oomResult == wgpu::ErrorType::OutOfMemory);
wgpu::BufferDescriptor resultBufDesc;
resultBufDesc.size = 8;
diff --git a/src/dawn/tests/end2end/MultithreadTests.cpp b/src/dawn/tests/end2end/MultithreadTests.cpp
index cddcb36..29d18d1 100644
--- a/src/dawn/tests/end2end/MultithreadTests.cpp
+++ b/src/dawn/tests/end2end/MultithreadTests.cpp
@@ -168,30 +168,25 @@
// Create threads
utils::RunInParallel(static_cast<uint32_t>(devices.size()), [&devices, this](uint32_t index) {
auto additionalDevice = std::move(devices[index]);
- struct UserData {
- wgpu::Device device2ndRef;
- std::atomic_bool isCompleted{false};
- } userData;
-
- userData.device2ndRef = additionalDevice;
+ wgpu::Device device2ndRef = additionalDevice;
+ std::atomic_bool isCompleted{false};
// Drop the last ref inside a callback.
additionalDevice.PushErrorScope(wgpu::ErrorFilter::Validation);
additionalDevice.PopErrorScope(
- [](WGPUErrorType type, const char*, void* userdataPtr) {
- auto userdata = static_cast<UserData*>(userdataPtr);
- userdata->device2ndRef = nullptr;
- userdata->isCompleted = true;
- },
- &userData);
+ wgpu::CallbackMode::AllowProcessEvents,
+ [&device2ndRef, &isCompleted](wgpu::PopErrorScopeStatus, wgpu::ErrorType, const char*) {
+ device2ndRef = nullptr;
+ isCompleted = true;
+ });
// main ref dropped.
additionalDevice = nullptr;
do {
WaitABit();
- } while (!userData.isCompleted.load());
+ } while (!isCompleted.load());
- EXPECT_EQ(userData.device2ndRef, nullptr);
+ EXPECT_EQ(device2ndRef, nullptr);
});
}
@@ -1330,12 +1325,12 @@
std::atomic<bool> errorThrown(false);
device.PopErrorScope(
- [](WGPUErrorType type, char const* message, void* userdata) {
- EXPECT_EQ(type, WGPUErrorType_Validation);
- auto error = static_cast<std::atomic<bool>*>(userdata);
- *error = true;
- },
- &errorThrown);
+ wgpu::CallbackMode::AllowProcessEvents,
+ [&errorThrown](wgpu::PopErrorScopeStatus status, wgpu::ErrorType type, char const*) {
+ EXPECT_EQ(status, wgpu::PopErrorScopeStatus::Success);
+ EXPECT_EQ(type, wgpu::ErrorType::Validation);
+ errorThrown = true;
+ });
instance.ProcessEvents();
EXPECT_TRUE(errorThrown.load());
diff --git a/src/dawn/tests/unittests/validation/ErrorScopeValidationTests.cpp b/src/dawn/tests/unittests/validation/ErrorScopeValidationTests.cpp
index f4ae097..60ad2ac 100644
--- a/src/dawn/tests/unittests/validation/ErrorScopeValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/ErrorScopeValidationTests.cpp
@@ -33,30 +33,8 @@
#include "gmock/gmock.h"
using testing::_;
-using testing::MockCallback;
-using testing::Sequence;
-
-class MockDevicePopErrorScopeCallback {
- public:
- MOCK_METHOD(void, Call, (WGPUErrorType type, const char* message, void* userdata));
-};
-
-static std::unique_ptr<MockDevicePopErrorScopeCallback> mockDevicePopErrorScopeCallback;
-static void ToMockDevicePopErrorScopeCallback(WGPUErrorType type,
- const char* message,
- void* userdata) {
- mockDevicePopErrorScopeCallback->Call(type, message, userdata);
-}
-
-class MockQueueWorkDoneCallback {
- public:
- MOCK_METHOD(void, Call, (WGPUQueueWorkDoneStatus status, void* userdata));
-};
-
-static std::unique_ptr<MockQueueWorkDoneCallback> mockQueueWorkDoneCallback;
-static void ToMockQueueWorkDone(WGPUQueueWorkDoneStatus status, void* userdata) {
- mockQueueWorkDoneCallback->Call(status, userdata);
-}
+using testing::MockCppCallback;
+using testing::NotNull;
class ErrorScopeValidationTest : public ValidationTest {
protected:
@@ -65,40 +43,18 @@
instance.ProcessEvents();
}
- // Generate new void* pointer for use as `userdata` in callback. The pointer
- // is valid for the whole duration of the test. This avoids dangling
- // pointers checks to trigger.
- void* CreateUserData() {
- mUserData.push_back(std::make_unique<bool>());
- return reinterpret_cast<void*>(mUserData.back().get());
- }
-
- private:
- void SetUp() override {
- ValidationTest::SetUp();
- mockDevicePopErrorScopeCallback = std::make_unique<MockDevicePopErrorScopeCallback>();
- mockQueueWorkDoneCallback = std::make_unique<MockQueueWorkDoneCallback>();
- }
-
- void TearDown() override {
- ValidationTest::TearDown();
-
- // Delete mocks so that expectations are checked
- mockDevicePopErrorScopeCallback = nullptr;
- mockQueueWorkDoneCallback = nullptr;
- }
-
- std::vector<std::unique_ptr<bool>> mUserData;
+ MockCppCallback<void (*)(wgpu::PopErrorScopeStatus, wgpu::ErrorType, const char*)>
+ mPopErrorScopeCb;
};
// Test the simple success case.
TEST_F(ErrorScopeValidationTest, Success) {
device.PushErrorScope(wgpu::ErrorFilter::Validation);
- void* userdata = CreateUserData();
- EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, userdata))
+ EXPECT_CALL(mPopErrorScopeCb,
+ Call(wgpu::PopErrorScopeStatus::Success, wgpu::ErrorType::NoError, _))
.Times(1);
- device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata);
+ device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents, mPopErrorScopeCb.Callback());
FlushWireAndProcessEvents();
}
@@ -110,10 +66,10 @@
desc.usage = static_cast<wgpu::BufferUsage>(WGPUBufferUsage_Force32);
device.CreateBuffer(&desc);
- void* userdata = CreateUserData();
- EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Validation, _, userdata))
+ EXPECT_CALL(mPopErrorScopeCb,
+ Call(wgpu::PopErrorScopeStatus::Success, wgpu::ErrorType::Validation, _))
.Times(1);
- device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata);
+ device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents, mPopErrorScopeCb.Callback());
FlushWireAndProcessEvents();
}
@@ -127,17 +83,17 @@
device.CreateBuffer(&desc);
// OutOfMemory does not match Validation error.
- void* userdata_1 = CreateUserData();
- EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, userdata_1))
+ EXPECT_CALL(mPopErrorScopeCb,
+ Call(wgpu::PopErrorScopeStatus::Success, wgpu::ErrorType::NoError, _))
.Times(1);
- device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata_1);
+ device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents, mPopErrorScopeCb.Callback());
FlushWireAndProcessEvents();
// Parent validation error scope captures the error.
- void* userdata_2 = CreateUserData();
- EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Validation, _, userdata_2))
+ EXPECT_CALL(mPopErrorScopeCb,
+ Call(wgpu::PopErrorScopeStatus::Success, wgpu::ErrorType::Validation, _))
.Times(1);
- device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata_2);
+ device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents, mPopErrorScopeCb.Callback());
FlushWireAndProcessEvents();
}
@@ -151,17 +107,17 @@
device.CreateBuffer(&desc);
// Inner scope catches the error.
- void* userdata_1 = CreateUserData();
- EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Validation, _, userdata_1))
+ EXPECT_CALL(mPopErrorScopeCb,
+ Call(wgpu::PopErrorScopeStatus::Success, wgpu::ErrorType::Validation, _))
.Times(1);
- device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata_1);
+ device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents, mPopErrorScopeCb.Callback());
FlushWireAndProcessEvents();
// Parent scope does not see the error.
- void* userdata_2 = CreateUserData();
- EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, userdata_2))
+ EXPECT_CALL(mPopErrorScopeCb,
+ Call(wgpu::PopErrorScopeStatus::Success, wgpu::ErrorType::NoError, _))
.Times(1);
- device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata_2);
+ device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents, mPopErrorScopeCb.Callback());
FlushWireAndProcessEvents();
}
@@ -173,10 +129,10 @@
desc.usage = static_cast<wgpu::BufferUsage>(WGPUBufferUsage_Force32);
ASSERT_DEVICE_ERROR(device.CreateBuffer(&desc));
- void* userdata = CreateUserData();
- EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, userdata))
+ EXPECT_CALL(mPopErrorScopeCb,
+ Call(wgpu::PopErrorScopeStatus::Success, wgpu::ErrorType::NoError, _))
.Times(1);
- device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata);
+ device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents, mPopErrorScopeCb.Callback());
FlushWireAndProcessEvents();
}
@@ -184,63 +140,31 @@
TEST_F(ErrorScopeValidationTest, PushPopBalanced) {
// No error scopes to pop.
{
- void* userdata = CreateUserData();
- EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Unknown, _, userdata))
+ EXPECT_CALL(mPopErrorScopeCb,
+ Call(wgpu::PopErrorScopeStatus::Success, wgpu::ErrorType::Unknown, NotNull()))
.Times(1);
- device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata);
+ device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents, mPopErrorScopeCb.Callback());
FlushWireAndProcessEvents();
}
// Too many pops
{
device.PushErrorScope(wgpu::ErrorFilter::Validation);
- void* userdata_1 = CreateUserData();
- EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, userdata_1))
+ EXPECT_CALL(mPopErrorScopeCb,
+ Call(wgpu::PopErrorScopeStatus::Success, wgpu::ErrorType::NoError, _))
.Times(1);
- device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata_1);
+ device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents, mPopErrorScopeCb.Callback());
FlushWireAndProcessEvents();
- void* userdata_2 = CreateUserData();
- EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Unknown, _, userdata_2))
+ EXPECT_CALL(mPopErrorScopeCb,
+ Call(wgpu::PopErrorScopeStatus::Success, wgpu::ErrorType::Unknown, NotNull()))
.Times(1);
- device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata_2);
+ device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents, mPopErrorScopeCb.Callback());
FlushWireAndProcessEvents();
}
}
-// Test that parent error scopes also call their callbacks before an enclosed Queue::Submit
-// completes
-TEST_F(ErrorScopeValidationTest, EnclosedQueueSubmitNested) {
- wgpu::Queue queue = device.GetQueue();
-
- device.PushErrorScope(wgpu::ErrorFilter::OutOfMemory);
- device.PushErrorScope(wgpu::ErrorFilter::OutOfMemory);
-
- void* userdata_1 = CreateUserData();
- queue.Submit(0, nullptr);
- queue.OnSubmittedWorkDone(ToMockQueueWorkDone, userdata_1);
-
- Sequence seq;
-
- MockCallback<WGPUErrorCallback> errorScopeCallback2;
- void* userdata_2 = CreateUserData();
- EXPECT_CALL(errorScopeCallback2, Call(WGPUErrorType_NoError, _, userdata_2)).InSequence(seq);
- device.PopErrorScope(errorScopeCallback2.Callback(),
- errorScopeCallback2.MakeUserdata(userdata_2));
-
- MockCallback<WGPUErrorCallback> errorScopeCallback1;
- void* userdata_3 = CreateUserData();
- EXPECT_CALL(errorScopeCallback1, Call(WGPUErrorType_NoError, _, userdata_3)).InSequence(seq);
- device.PopErrorScope(errorScopeCallback1.Callback(),
- errorScopeCallback1.MakeUserdata(userdata_3));
-
- EXPECT_CALL(*mockQueueWorkDoneCallback, Call(WGPUQueueWorkDoneStatus_Success, userdata_1));
- WaitForAllOperations(device);
-}
-
-// Test that if the device is destroyed before the callback occurs, it is called with NoError
-// in dawn_native, but Unknown in dawn_wire because the device is destroyed before the callback
-// message happens.
+// Test that if the device is destroyed before the callback occurs, it is called with NoError.
TEST_F(ErrorScopeValidationTest, DeviceDestroyedBeforeCallback) {
device.PushErrorScope(wgpu::ErrorFilter::OutOfMemory);
{
@@ -249,10 +173,10 @@
queue.Submit(0, nullptr);
}
- void* userdata = CreateUserData();
- EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, userdata))
+ EXPECT_CALL(mPopErrorScopeCb,
+ Call(wgpu::PopErrorScopeStatus::Success, wgpu::ErrorType::NoError, _))
.Times(1);
- device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata);
+ device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents, mPopErrorScopeCb.Callback());
ExpectDeviceDestruction();
device = nullptr;
@@ -266,10 +190,10 @@
device.Destroy();
FlushWireAndProcessEvents();
- void* userdata = CreateUserData();
- EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_DeviceLost, _, userdata))
+ EXPECT_CALL(mPopErrorScopeCb,
+ Call(wgpu::PopErrorScopeStatus::Success, wgpu::ErrorType::DeviceLost, NotNull()))
.Times(1);
- device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata);
+ device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents, mPopErrorScopeCb.Callback());
FlushWireAndProcessEvents();
}
diff --git a/src/dawn/tests/unittests/wire/WireErrorCallbackTests.cpp b/src/dawn/tests/unittests/wire/WireErrorCallbackTests.cpp
index 2a91393..7fad752 100644
--- a/src/dawn/tests/unittests/wire/WireErrorCallbackTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireErrorCallbackTests.cpp
@@ -213,17 +213,6 @@
}
}
- // Overridden version of api.CallDevicePopErrorScopeCallback to defer to the correct callback
- // depending on the test callback mode. Note that currently, the ServerDevice calls the native
- // procs using the old-non-future signature. Once that changes, we can probably just inline
- // api.CallDevicePopErrorScopeCallback calls in place of this function.
- void CallDevicePopErrorScopeCallback(WGPUDevice d,
- WGPUPopErrorScopeStatus status,
- WGPUErrorType type,
- char const* message) {
- api.CallDevicePopErrorScopeOldCallback(d, type, message);
- }
-
void PushErrorScope(WGPUErrorFilter filter) {
EXPECT_CALL(api, DevicePushErrorScope(apiDevice, filter)).Times(1);
wgpuDevicePushErrorScope(device, filter);
@@ -259,9 +248,9 @@
PushErrorScope(filter);
DevicePopErrorScope(device, this);
- EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _)).WillOnce([&] {
- CallDevicePopErrorScopeCallback(apiDevice, WGPUPopErrorScopeStatus_Success, type,
- "Some error message");
+ EXPECT_CALL(api, OnDevicePopErrorScope2(apiDevice, _)).WillOnce([&] {
+ api.CallDevicePopErrorScope2Callback(apiDevice, WGPUPopErrorScopeStatus_Success, type,
+ "Some error message");
});
FlushClient();
@@ -288,7 +277,7 @@
PushErrorScope(WGPUErrorFilter_Validation);
DevicePopErrorScope(device, this);
- EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _)).Times(1);
+ EXPECT_CALL(api, OnDevicePopErrorScope2(apiDevice, _)).Times(1);
FlushClient();
FlushFutures();
@@ -316,9 +305,9 @@
PushErrorScope(WGPUErrorFilter_Validation);
DevicePopErrorScope(device, this);
- EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _)).WillOnce(InvokeWithoutArgs([&] {
- CallDevicePopErrorScopeCallback(apiDevice, WGPUPopErrorScopeStatus_Success,
- WGPUErrorType_Validation, "Some error message");
+ EXPECT_CALL(api, OnDevicePopErrorScope2(apiDevice, _)).WillOnce(InvokeWithoutArgs([&] {
+ api.CallDevicePopErrorScope2Callback(apiDevice, WGPUPopErrorScopeStatus_Success,
+ WGPUErrorType_Validation, "Some error message");
}));
FlushClient();
@@ -341,9 +330,9 @@
// Empty stack (We are emulating the errors that would be callback-ed from native).
TEST_P(WirePopErrorScopeCallbackTests, EmptyStack) {
DevicePopErrorScope(device, this);
- EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _)).WillOnce(InvokeWithoutArgs([&] {
- CallDevicePopErrorScopeCallback(apiDevice, WGPUPopErrorScopeStatus_Success,
- WGPUErrorType_Validation, "No error scopes to pop");
+ EXPECT_CALL(api, OnDevicePopErrorScope2(apiDevice, _)).WillOnce(InvokeWithoutArgs([&] {
+ api.CallDevicePopErrorScope2Callback(apiDevice, WGPUPopErrorScopeStatus_Success,
+ WGPUErrorType_Validation, "No error scopes to pop");
}));
FlushClient();
diff --git a/src/dawn/tests/white_box/SharedTextureMemoryTests.cpp b/src/dawn/tests/white_box/SharedTextureMemoryTests.cpp
index 7951b51..534487c 100644
--- a/src/dawn/tests/white_box/SharedTextureMemoryTests.cpp
+++ b/src/dawn/tests/white_box/SharedTextureMemoryTests.cpp
@@ -772,7 +772,7 @@
namespace {
using testing::HasSubstr;
-using testing::MockCallback;
+using testing::MockCppCallback;
template <typename T>
T& AsNonConst(const T& rhs) {
@@ -788,12 +788,13 @@
const auto& memories =
GetParam().mBackend->CreateSharedTextureMemories(device, GetParam().mLayerCount);
- MockCallback<WGPUErrorCallback> popErrorScopeCallback;
+ MockCppCallback<void (*)(wgpu::PopErrorScopeStatus, wgpu::ErrorType, const char*)>
+ popErrorScopeCallback;
EXPECT_CALL(popErrorScopeCallback,
- Call(WGPUErrorType_Validation, HasSubstr("is not enabled"), this));
+ Call(wgpu::PopErrorScopeStatus::Success, wgpu::ErrorType::Validation,
+ HasSubstr("is not enabled")));
- device.PopErrorScope(popErrorScopeCallback.Callback(),
- popErrorScopeCallback.MakeUserdata(this));
+ device.PopErrorScope(wgpu::CallbackMode::AllowProcessEvents, popErrorScopeCallback.Callback());
for (wgpu::SharedTextureMemory memory : memories) {
ASSERT_DEVICE_ERROR_MSG(wgpu::Texture texture = memory.CreateTexture(),
diff --git a/src/dawn/wire/client/Device.cpp b/src/dawn/wire/client/Device.cpp
index 459d7a2..6e132f3 100644
--- a/src/dawn/wire/client/Device.cpp
+++ b/src/dawn/wire/client/Device.cpp
@@ -45,15 +45,11 @@
public:
static constexpr EventType kType = EventType::PopErrorScope;
- explicit PopErrorScopeEvent(const WGPUPopErrorScopeCallbackInfo& callbackInfo)
+ explicit PopErrorScopeEvent(const WGPUPopErrorScopeCallbackInfo2& callbackInfo)
: TrackedEvent(callbackInfo.mode),
mCallback(callbackInfo.callback),
- mOldCallback(callbackInfo.oldCallback),
- mUserdata(callbackInfo.userdata) {
- // Exactly 1 callback should be set.
- DAWN_ASSERT((mCallback != nullptr && mOldCallback == nullptr) ||
- (mCallback == nullptr && mOldCallback != nullptr));
- }
+ mUserdata1(callbackInfo.userdata1),
+ mUserdata2(callbackInfo.userdata2) {}
EventType GetType() override { return kType; }
@@ -71,19 +67,16 @@
mStatus = WGPUPopErrorScopeStatus_InstanceDropped;
mMessage = std::nullopt;
}
- void* userdata = mUserdata.ExtractAsDangling();
- if (mOldCallback) {
- mOldCallback(mType, mMessage ? mMessage->c_str() : nullptr, userdata);
- }
+ void* userdata1 = mUserdata1.ExtractAsDangling();
+ void* userdata2 = mUserdata2.ExtractAsDangling();
if (mCallback) {
- mCallback(mStatus, mType, mMessage ? mMessage->c_str() : nullptr, userdata);
+ mCallback(mStatus, mType, mMessage ? mMessage->c_str() : nullptr, userdata1, userdata2);
}
}
- // TODO(crbug.com/dawn/2021) Remove the old callback type.
- WGPUPopErrorScopeCallback mCallback;
- WGPUErrorCallback mOldCallback;
- raw_ptr<void> mUserdata;
+ WGPUPopErrorScopeCallback2 mCallback;
+ raw_ptr<void> mUserdata1;
+ raw_ptr<void> mUserdata2;
WGPUPopErrorScopeStatus mStatus = WGPUPopErrorScopeStatus_Success;
WGPUErrorType mType = WGPUErrorType_Unknown;
@@ -385,14 +378,29 @@
}
void Device::PopErrorScope(WGPUErrorCallback callback, void* userdata) {
- WGPUPopErrorScopeCallbackInfo callbackInfo = {};
- callbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
- callbackInfo.oldCallback = callback;
- callbackInfo.userdata = userdata;
- PopErrorScopeF(callbackInfo);
+ static WGPUErrorCallback kDefaultCallback = [](WGPUErrorType, char const*, void*) {};
+
+ PopErrorScope2({nullptr, WGPUCallbackMode_AllowSpontaneous,
+ [](WGPUPopErrorScopeStatus, WGPUErrorType type, char const* message,
+ void* callback, void* userdata) {
+ auto cb = reinterpret_cast<WGPUErrorCallback>(callback);
+ cb(type, message, userdata);
+ },
+ reinterpret_cast<void*>(callback != nullptr ? callback : kDefaultCallback),
+ userdata});
}
WGPUFuture Device::PopErrorScopeF(const WGPUPopErrorScopeCallbackInfo& callbackInfo) {
+ return PopErrorScope2({nullptr, callbackInfo.mode,
+ [](WGPUPopErrorScopeStatus status, WGPUErrorType type,
+ char const* message, void* callback, void* userdata) {
+ auto cb = reinterpret_cast<WGPUPopErrorScopeCallback>(callback);
+ cb(status, type, message, userdata);
+ },
+ reinterpret_cast<void*>(callbackInfo.callback), callbackInfo.userdata});
+}
+
+WGPUFuture Device::PopErrorScope2(const WGPUPopErrorScopeCallbackInfo2& callbackInfo) {
Client* client = GetClient();
auto [futureIDInternal, tracked] =
GetEventManager().TrackEvent(std::make_unique<PopErrorScopeEvent>(callbackInfo));
diff --git a/src/dawn/wire/client/Device.h b/src/dawn/wire/client/Device.h
index ab07cc70..28418ba 100644
--- a/src/dawn/wire/client/Device.h
+++ b/src/dawn/wire/client/Device.h
@@ -61,6 +61,7 @@
void InjectError(WGPUErrorType type, const char* message);
void PopErrorScope(WGPUErrorCallback callback, void* userdata);
WGPUFuture PopErrorScopeF(const WGPUPopErrorScopeCallbackInfo& callbackInfo);
+ WGPUFuture PopErrorScope2(const WGPUPopErrorScopeCallbackInfo2& callbackInfo);
WGPUBuffer CreateBuffer(const WGPUBufferDescriptor* descriptor);
void CreateComputePipelineAsync(WGPUComputePipelineDescriptor const* descriptor,
WGPUCreateComputePipelineAsyncCallback callback,
diff --git a/src/dawn/wire/server/Server.h b/src/dawn/wire/server/Server.h
index a64d59f..a244b9d 100644
--- a/src/dawn/wire/server/Server.h
+++ b/src/dawn/wire/server/Server.h
@@ -250,6 +250,7 @@
WGPUDeviceLostReason reason,
const char* message);
void OnDevicePopErrorScope(ErrorScopeUserdata* userdata,
+ WGPUPopErrorScopeStatus status,
WGPUErrorType type,
const char* message);
void OnBufferMapAsyncCallback(MapUserdata* userdata, WGPUBufferMapAsyncStatus status);
diff --git a/src/dawn/wire/server/ServerDevice.cpp b/src/dawn/wire/server/ServerDevice.cpp
index e974431..1c191b7 100644
--- a/src/dawn/wire/server/ServerDevice.cpp
+++ b/src/dawn/wire/server/ServerDevice.cpp
@@ -71,12 +71,14 @@
userdata->eventManager = eventManager;
userdata->future = future;
- mProcs.devicePopErrorScope(device->handle, ForwardToServer<&Server::OnDevicePopErrorScope>,
- userdata.release());
+ mProcs.devicePopErrorScope2(device->handle, {nullptr, WGPUCallbackMode_AllowProcessEvents,
+ ForwardToServer2<&Server::OnDevicePopErrorScope>,
+ userdata.release(), nullptr});
return WireResult::Success;
}
void Server::OnDevicePopErrorScope(ErrorScopeUserdata* userdata,
+ WGPUPopErrorScopeStatus status,
WGPUErrorType type,
const char* message) {
ReturnDevicePopErrorScopeCallbackCmd cmd;