Revert "[WGPUFuture] Implement pop error scope in wire/native with Futures."
This reverts commit 97dfc182410301992db9315de11c544c4c3bf087.
Reason for revert: Breaks dawn/node - all tests fail with `endTestScope timed out`
Original change's description:
> [WGPUFuture] Implement pop error scope in wire/native with Futures.
>
> - Fixes some tests that now require us to have access to the Instance
> for calling ProcessEvents.
> - Also fixes some tests to call ProcessEvents over Tick.
>
> Bug: dawn:1987
> Change-Id: I572dc349f9c1adf9a13be267a22eaa73d69e6def
> Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/169140
> Kokoro: Kokoro <noreply+kokoro@google.com>
> Commit-Queue: Loko Kung <lokokung@google.com>
> Reviewed-by: Shrek Shao <shrekshao@google.com>
> Reviewed-by: Austin Eng <enga@chromium.org>
TBR=enga@chromium.org,shrekshao@google.com,noreply+kokoro@google.com,dawn-scoped@luci-project-accounts.iam.gserviceaccount.com,lokokung@google.com
Change-Id: I92621fb36f5e0dbaf78f914dffac5239ca59c5e1
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: dawn:1987
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/174021
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Kokoro: Ben Clayton <bclayton@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/dawn/dawn.json b/src/dawn/dawn.json
index b5c1530..7112745 100644
--- a/src/dawn/dawn.json
+++ b/src/dawn/dawn.json
@@ -1428,15 +1428,6 @@
]
},
{
- "name": "pop error scope f",
- "_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"}
- ]
- },
- {
"name": "set label",
"returns": "void",
"args": [
@@ -1487,33 +1478,6 @@
{"name": "userdata", "type": "void *"}
]
},
- "pop error scope status": {
- "category": "enum",
- "emscripten_no_enum_table": true,
- "values": [
- {"value": 0, "name": "success"},
- {"value": 1, "name": "instance dropped"}
- ]
- },
- "pop error scope callback": {
- "category": "function pointer",
- "args": [
- {"name": "status", "type": "pop error scope status"},
- {"name": "type", "type": "error type"},
- {"name": "message", "type": "char", "annotation": "const*", "length": "strlen"},
- {"name": "userdata", "type": "void *"}
- ]
- },
- "pop error scope callback info": {
- "category": "structure",
- "extensible": "in",
- "members": [
- {"name": "mode", "type": "callback mode"},
- {"name": "callback", "type": "pop error scope callback"},
- {"name": "old callback", "type": "error callback", "_comment": "TODO(crbug.com/dawn/2021) Deprecate this field once we have moved callers to use the new callback signature."},
- {"name": "userdata", "type": "void *", "default": "nullptr"}
- ]
- },
"limits": {
"category": "structure",
"members": [
diff --git a/src/dawn/dawn_wire.json b/src/dawn/dawn_wire.json
index 9365631..48c931d 100644
--- a/src/dawn/dawn_wire.json
+++ b/src/dawn/dawn_wire.json
@@ -71,8 +71,7 @@
],
"device pop error scope": [
{ "name": "device id", "type": "ObjectId", "id_type": "device" },
- { "name": "event manager handle", "type": "ObjectHandle" },
- { "name": "future", "type": "future" }
+ { "name": "request serial", "type": "uint64_t" }
],
"destroy object": [
{ "name": "object type", "type": "ObjectType" },
@@ -153,8 +152,8 @@
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
],
"device pop error scope callback": [
- { "name": "event manager", "type": "ObjectHandle" },
- { "name": "future", "type": "future" },
+ { "name": "device", "type": "ObjectHandle", "handle_type": "device" },
+ { "name": "request serial", "type": "uint64_t" },
{ "name": "type", "type": "error type" },
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
],
@@ -223,7 +222,6 @@
"DeviceHasFeature",
"DeviceEnumerateFeatures",
"DevicePopErrorScope",
- "DevicePopErrorScopeF",
"DeviceSetDeviceLostCallback",
"DeviceSetUncapturedErrorCallback",
"DeviceSetLoggingCallback",
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp
index 14e31a0..6af75e2 100644
--- a/src/dawn/native/Device.cpp
+++ b/src/dawn/native/Device.cpp
@@ -726,70 +726,25 @@
}
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);
-}
-
-Future DeviceBase::APIPopErrorScopeF(const PopErrorScopeCallbackInfo& callbackInfo) {
- struct PopErrorScopeEvent final : public EventManager::TrackedEvent {
- // TODO(crbug.com/dawn/2021) Remove the old callback type.
- WGPUPopErrorScopeCallback mCallback;
- WGPUErrorCallback mOldCallback;
- void* mUserdata;
- std::optional<ErrorScope> mScope;
-
- PopErrorScopeEvent(const PopErrorScopeCallbackInfo& callbackInfo,
- std::optional<ErrorScope>&& scope)
- : TrackedEvent(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));
- CompleteIfSpontaneous();
- }
-
- ~PopErrorScopeEvent() override { EnsureComplete(EventCompletionType::Shutdown); }
-
- void Complete(EventCompletionType completionType) override {
- WGPUPopErrorScopeStatus status = completionType == EventCompletionType::Ready
- ? WGPUPopErrorScopeStatus_Success
- : WGPUPopErrorScopeStatus_InstanceDropped;
- WGPUErrorType type;
- const char* message;
- if (mScope) {
- type = static_cast<WGPUErrorType>(mScope->GetErrorType());
- message = mScope->GetErrorMessage().c_str();
- } else {
- type = WGPUErrorType_Unknown;
- message = "No error scopes to pop";
- }
-
- if (mCallback) {
- mCallback(status, type, message, mUserdata);
- } else {
- mOldCallback(type, message, mUserdata);
- }
- }
- };
-
- std::optional<ErrorScope> scope;
- if (IsLost()) {
- scope = ErrorScope(wgpu::ErrorType::DeviceLost, "GPU device disconnected");
- } else if (!mErrorScopeStack->Empty()) {
- scope = mErrorScopeStack->Pop();
+ if (callback == nullptr) {
+ static wgpu::ErrorCallback defaultCallback = [](WGPUErrorType, char const*, void*) {};
+ callback = defaultCallback;
}
-
- FutureID futureID = GetInstance()->GetEventManager()->TrackEvent(
- callbackInfo.mode, AcquireRef(new PopErrorScopeEvent(callbackInfo, std::move(scope))));
- return {futureID};
+ if (IsLost()) {
+ mCallbackTaskManager->AddCallbackTask(
+ std::bind(callback, WGPUErrorType_DeviceLost, "GPU device disconnected", userdata));
+ return;
+ }
+ if (mErrorScopeStack->Empty()) {
+ mCallbackTaskManager->AddCallbackTask(
+ std::bind(callback, WGPUErrorType_Unknown, "No error scopes to pop", userdata));
+ return;
+ }
+ ErrorScope scope = mErrorScopeStack->Pop();
+ mCallbackTaskManager->AddCallbackTask(
+ [callback, errorType = static_cast<WGPUErrorType>(scope.GetErrorType()),
+ message = scope.GetErrorMessage(),
+ userdata] { callback(errorType, message.c_str(), userdata); });
}
BlobCache* DeviceBase::GetBlobCache() const {
@@ -1407,8 +1362,6 @@
// Returns true if future ticking is needed.
bool DeviceBase::APITick() {
- // TODO(dawn:1987) Add deprecation warning when Instance.ProcessEvents no longer calls this.
-
// Tick may trigger callbacks which drop a ref to the device itself. Hold a Ref to ourselves
// to avoid deleting |this| in the middle of this function call.
Ref<DeviceBase> self(this);
diff --git a/src/dawn/native/Device.h b/src/dawn/native/Device.h
index e833ac2..70b2df9 100644
--- a/src/dawn/native/Device.h
+++ b/src/dawn/native/Device.h
@@ -328,7 +328,6 @@
void APISetLoggingCallback(wgpu::LoggingCallback callback, void* userdata);
void APIPushErrorScope(wgpu::ErrorFilter filter);
void APIPopErrorScope(wgpu::ErrorCallback callback, void* userdata);
- Future APIPopErrorScopeF(const PopErrorScopeCallbackInfo& callbackInfo);
MaybeError ValidateIsAlive() const;
diff --git a/src/dawn/native/ErrorScope.cpp b/src/dawn/native/ErrorScope.cpp
index 63ab77d..6c21e40 100644
--- a/src/dawn/native/ErrorScope.cpp
+++ b/src/dawn/native/ErrorScope.cpp
@@ -52,9 +52,6 @@
ErrorScope::ErrorScope(wgpu::ErrorFilter errorFilter)
: mMatchedErrorType(ErrorFilterToErrorType(errorFilter)) {}
-ErrorScope::ErrorScope(wgpu::ErrorType error, std::string_view message)
- : mMatchedErrorType(error), mCapturedError(error), mErrorMessage(message) {}
-
wgpu::ErrorType ErrorScope::GetErrorType() const {
return mCapturedError;
}
diff --git a/src/dawn/native/ErrorScope.h b/src/dawn/native/ErrorScope.h
index f40934a..4032b47 100644
--- a/src/dawn/native/ErrorScope.h
+++ b/src/dawn/native/ErrorScope.h
@@ -37,8 +37,6 @@
class ErrorScope {
public:
- ErrorScope(wgpu::ErrorType error, std::string_view message);
-
wgpu::ErrorType GetErrorType() const;
const std::string& GetErrorMessage() const;
diff --git a/src/dawn/tests/DawnTest.h b/src/dawn/tests/DawnTest.h
index e625a5b..474d9e1 100644
--- a/src/dawn/tests/DawnTest.h
+++ b/src/dawn/tests/DawnTest.h
@@ -127,7 +127,7 @@
EXPECT_CALL(mDeviceErrorCallback, \
Call(testing::Ne(WGPUErrorType_NoError), matcher, device.Get())); \
statement; \
- instance.ProcessEvents(); \
+ device.Tick(); \
FlushWire(); \
testing::Mock::VerifyAndClearExpectations(&mDeviceErrorCallback); \
do { \
diff --git a/src/dawn/tests/end2end/DeviceLifetimeTests.cpp b/src/dawn/tests/end2end/DeviceLifetimeTests.cpp
index 02ce3a6..4ddb8f7 100644
--- a/src/dawn/tests/end2end/DeviceLifetimeTests.cpp
+++ b/src/dawn/tests/end2end/DeviceLifetimeTests.cpp
@@ -99,19 +99,17 @@
// Test that the device can be dropped while a popErrorScope callback is in flight.
TEST_P(DeviceLifetimeTests, DroppedWhilePopErrorScope) {
device.PushErrorScope(wgpu::ErrorFilter::Validation);
- bool done = false;
-
+ bool wire = UsesWire();
device.PopErrorScope(
[](WGPUErrorType type, const char*, void* userdata) {
- *static_cast<bool*>(userdata) = true;
- EXPECT_EQ(type, WGPUErrorType_NoError);
+ const bool wire = *static_cast<bool*>(userdata);
+ // On the wire, all callbacks get rejected immediately with once the device is deleted.
+ // In native, popErrorScope is called synchronously.
+ // TODO(crbug.com/dawn/1122): These callbacks should be made consistent.
+ EXPECT_EQ(type, wire ? WGPUErrorType_Unknown : WGPUErrorType_NoError);
},
- &done);
+ &wire);
device = nullptr;
-
- while (!done) {
- WaitABit();
- }
}
// Test that the device can be dropped inside an onSubmittedWorkDone callback.
@@ -133,6 +131,11 @@
&data);
while (!data.done) {
+ // WaitABit no longer can call tick since we've moved the device from the fixture into the
+ // userdata.
+ if (data.device) {
+ data.device.Tick();
+ }
WaitABit();
}
}
diff --git a/src/dawn/tests/end2end/EventTests.cpp b/src/dawn/tests/end2end/EventTests.cpp
index 10de0c1..d152975c 100644
--- a/src/dawn/tests/end2end/EventTests.cpp
+++ b/src/dawn/tests/end2end/EventTests.cpp
@@ -151,7 +151,7 @@
Call(WGPUDeviceLostReason_Undefined, testing::_, testing::_))
.Times(1);
testDevice.ForceLoss(wgpu::DeviceLostReason::Undefined, "Device lost for testing");
- testInstance.ProcessEvents();
+ testDevice.Tick();
}
void TrivialSubmit() {
@@ -283,6 +283,7 @@
uint64_t oldCompletionCount = mCallbacksCompletedCount;
FlushWire();
+ testDevice.Tick();
auto status = testInstance.WaitAny(mFutures.size(), mFutures.data(), 0);
if (status == wgpu::WaitStatus::TimedOut) {
continue;
@@ -304,6 +305,7 @@
ASSERT_FALSE(testTimeExceeded());
FlushWire();
+ testDevice.Tick();
testInstance.ProcessEvents();
if (loopOnlyOnce) {
@@ -356,14 +358,9 @@
TEST_P(EventCompletionTests, WorkDoneAfterDeviceLoss) {
TrivialSubmit();
LoseTestDevice();
- // Tracking and waiting need to be done together w.r.t the device error assertion because error
- // assertion in DawnTest.h currently calls ProcessEvents which will cause the work done event to
- // trigger before the TestWaitAll call.
- auto TestF = [&]() {
- TrackForTest(OnSubmittedWorkDone(WGPUQueueWorkDoneStatus_Success));
- TestWaitAll();
- };
- ASSERT_DEVICE_ERROR_ON(testDevice, TestF());
+ ASSERT_DEVICE_ERROR_ON(testDevice,
+ TrackForTest(OnSubmittedWorkDone(WGPUQueueWorkDoneStatus_Success)));
+ TestWaitAll();
}
// WorkDone event twice after submitting some trivial work.
diff --git a/src/dawn/tests/end2end/MaxLimitTests.cpp b/src/dawn/tests/end2end/MaxLimitTests.cpp
index 1a86e32..d8810bc 100644
--- a/src/dawn/tests/end2end/MaxLimitTests.cpp
+++ b/src/dawn/tests/end2end/MaxLimitTests.cpp
@@ -221,7 +221,7 @@
device.PopErrorScope([](WGPUErrorType type, const char*,
void* userdata) { *static_cast<WGPUErrorType*>(userdata) = type; },
&oomResult);
- instance.ProcessEvents();
+ device.Tick();
FlushWire();
// Max buffer size is smaller than the max buffer binding size.
DAWN_TEST_UNSUPPORTED_IF(oomResult == WGPUErrorType_OutOfMemory);
diff --git a/src/dawn/tests/end2end/MultithreadTests.cpp b/src/dawn/tests/end2end/MultithreadTests.cpp
index d1ddeef..9a938eb 100644
--- a/src/dawn/tests/end2end/MultithreadTests.cpp
+++ b/src/dawn/tests/end2end/MultithreadTests.cpp
@@ -1144,7 +1144,7 @@
*error = true;
},
&errorThrown);
- instance.ProcessEvents();
+ device.Tick();
EXPECT_TRUE(errorThrown.load());
// Second copy is valid.
diff --git a/src/dawn/tests/unittests/validation/ErrorScopeValidationTests.cpp b/src/dawn/tests/unittests/validation/ErrorScopeValidationTests.cpp
index 1f13910..8d239aa 100644
--- a/src/dawn/tests/unittests/validation/ErrorScopeValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/ErrorScopeValidationTests.cpp
@@ -60,9 +60,9 @@
class ErrorScopeValidationTest : public ValidationTest {
protected:
- void FlushWireAndProcessEvents() {
+ void FlushWireAndTick() {
FlushWire();
- instance.ProcessEvents();
+ device.Tick();
}
// Generate new void* pointer for use as `userdata` in callback. The pointer
@@ -99,7 +99,7 @@
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, userdata))
.Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata);
- FlushWireAndProcessEvents();
+ FlushWireAndTick();
}
// Test the simple case where the error scope catches an error.
@@ -114,7 +114,7 @@
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Validation, _, userdata))
.Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata);
- FlushWireAndProcessEvents();
+ FlushWireAndTick();
}
// Test that errors bubble to the parent scope if not handled by the current scope.
@@ -131,14 +131,14 @@
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, userdata_1))
.Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata_1);
- FlushWireAndProcessEvents();
+ FlushWireAndTick();
// Parent validation error scope captures the error.
void* userdata_2 = CreateUserData();
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Validation, _, userdata_2))
.Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata_2);
- FlushWireAndProcessEvents();
+ FlushWireAndTick();
}
// Test that if an error scope matches an error, it does not bubble to the parent scope.
@@ -155,14 +155,14 @@
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Validation, _, userdata_1))
.Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata_1);
- FlushWireAndProcessEvents();
+ FlushWireAndTick();
// Parent scope does not see the error.
void* userdata_2 = CreateUserData();
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, userdata_2))
.Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata_2);
- FlushWireAndProcessEvents();
+ FlushWireAndTick();
}
// Test that if no error scope handles an error, it goes to the device UncapturedError callback
@@ -177,7 +177,7 @@
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, userdata))
.Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata);
- FlushWireAndProcessEvents();
+ FlushWireAndTick();
}
// Check that push/popping error scopes must be balanced.
@@ -188,7 +188,7 @@
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Unknown, _, userdata))
.Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata);
- FlushWireAndProcessEvents();
+ FlushWireAndTick();
}
// Too many pops
{
@@ -198,13 +198,13 @@
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, userdata_1))
.Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata_1);
- FlushWireAndProcessEvents();
+ FlushWireAndTick();
void* userdata_2 = CreateUserData();
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Unknown, _, userdata_2))
.Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata_2);
- FlushWireAndProcessEvents();
+ FlushWireAndTick();
}
}
@@ -234,7 +234,8 @@
device.PopErrorScope(errorScopeCallback1.Callback(),
errorScopeCallback1.MakeUserdata(userdata_3));
- EXPECT_CALL(*mockQueueWorkDoneCallback, Call(WGPUQueueWorkDoneStatus_Success, userdata_1));
+ EXPECT_CALL(*mockQueueWorkDoneCallback, Call(WGPUQueueWorkDoneStatus_Success, userdata_1))
+ .InSequence(seq);
WaitForAllOperations(device);
}
@@ -249,14 +250,22 @@
queue.Submit(0, nullptr);
}
+ if (UsesWire()) {
+ void* userdata = CreateUserData();
+ device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata);
+
+ EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_Unknown, _, userdata))
+ .Times(1);
+ ExpectDeviceDestruction();
+ device = nullptr;
+ } else {
void* userdata = CreateUserData();
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_NoError, _, userdata))
.Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata);
ExpectDeviceDestruction();
device = nullptr;
-
- FlushWireAndProcessEvents();
+ }
}
// If the device is destroyed, pop error scope should callback with device lost.
@@ -264,13 +273,13 @@
device.PushErrorScope(wgpu::ErrorFilter::Validation);
ExpectDeviceDestruction();
device.Destroy();
- FlushWireAndProcessEvents();
+ FlushWireAndTick();
void* userdata = CreateUserData();
EXPECT_CALL(*mockDevicePopErrorScopeCallback, Call(WGPUErrorType_DeviceLost, _, userdata))
.Times(1);
device.PopErrorScope(ToMockDevicePopErrorScopeCallback, userdata);
- FlushWireAndProcessEvents();
+ FlushWireAndTick();
}
// Regression test that on device shutdown, we don't get a recursion in O(pushed error scope) that
diff --git a/src/dawn/tests/unittests/validation/ShaderModuleValidationTests.cpp b/src/dawn/tests/unittests/validation/ShaderModuleValidationTests.cpp
index 362fd83..1e6c588 100644
--- a/src/dawn/tests/unittests/validation/ShaderModuleValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/ShaderModuleValidationTests.cpp
@@ -736,7 +736,8 @@
// Create testing adapter with the AllowUnsafeAPIs toggle explicitly enabled or disabled,
// overriding the instance's toggle.
- void CreateTestAdapterWithUnsafeAPIToggle(wgpu::RequestAdapterOptions options,
+ void CreateTestAdapterWithUnsafeAPIToggle(wgpu::Instance instance,
+ wgpu::RequestAdapterOptions options,
bool allowUnsafeAPIs) {
wgpu::DawnTogglesDescriptor deviceTogglesDesc{};
options.nextInChain = &deviceTogglesDesc;
@@ -810,9 +811,9 @@
class ShaderModuleExtensionValidationTestSafeNoFeature
: public ShaderModuleExtensionValidationTestBase {
protected:
- void CreateTestAdapter(wgpu::RequestAdapterOptions options) override {
+ void CreateTestAdapter(wgpu::Instance instance, wgpu::RequestAdapterOptions options) override {
// Create a safe adapter
- CreateTestAdapterWithUnsafeAPIToggle(options, false);
+ CreateTestAdapterWithUnsafeAPIToggle(instance, options, false);
}
WGPUDevice CreateTestDevice(native::Adapter dawnAdapter,
wgpu::DeviceDescriptor descriptor) override {
@@ -842,9 +843,9 @@
class ShaderModuleExtensionValidationTestUnsafeNoFeature
: public ShaderModuleExtensionValidationTestBase {
protected:
- void CreateTestAdapter(wgpu::RequestAdapterOptions options) override {
+ void CreateTestAdapter(wgpu::Instance instance, wgpu::RequestAdapterOptions options) override {
// Create an unsafe adapter
- CreateTestAdapterWithUnsafeAPIToggle(options, true);
+ CreateTestAdapterWithUnsafeAPIToggle(instance, options, true);
}
WGPUDevice CreateTestDevice(native::Adapter dawnAdapter,
wgpu::DeviceDescriptor descriptor) override {
@@ -874,9 +875,9 @@
class ShaderModuleExtensionValidationTestSafeAllFeatures
: public ShaderModuleExtensionValidationTestBase {
protected:
- void CreateTestAdapter(wgpu::RequestAdapterOptions options) override {
+ void CreateTestAdapter(wgpu::Instance instance, wgpu::RequestAdapterOptions options) override {
// Create a safe adapter
- CreateTestAdapterWithUnsafeAPIToggle(options, false);
+ CreateTestAdapterWithUnsafeAPIToggle(instance, options, false);
}
WGPUDevice CreateTestDevice(native::Adapter dawnAdapter,
wgpu::DeviceDescriptor descriptor) override {
@@ -904,9 +905,9 @@
class ShaderModuleExtensionValidationTestUnsafeAllFeatures
: public ShaderModuleExtensionValidationTestBase {
protected:
- void CreateTestAdapter(wgpu::RequestAdapterOptions options) override {
+ void CreateTestAdapter(wgpu::Instance instance, wgpu::RequestAdapterOptions options) override {
// Create an unsafe adapter
- CreateTestAdapterWithUnsafeAPIToggle(options, true);
+ CreateTestAdapterWithUnsafeAPIToggle(instance, options, true);
}
WGPUDevice CreateTestDevice(native::Adapter dawnAdapter,
wgpu::DeviceDescriptor descriptor) override {
diff --git a/src/dawn/tests/unittests/validation/ValidationTest.cpp b/src/dawn/tests/unittests/validation/ValidationTest.cpp
index 7afa6cb..d3d65b6 100644
--- a/src/dawn/tests/unittests/validation/ValidationTest.cpp
+++ b/src/dawn/tests/unittests/validation/ValidationTest.cpp
@@ -106,11 +106,12 @@
// Forward to dawn::native instanceRequestAdapter, but save the returned adapter in
// gCurrentTest->mBackendAdapter.
- procs.instanceRequestAdapter = [](WGPUInstance i, const WGPURequestAdapterOptions* options,
+ procs.instanceRequestAdapter = [](WGPUInstance instance,
+ const WGPURequestAdapterOptions* options,
WGPURequestAdapterCallback callback, void* userdata) {
DAWN_ASSERT(gCurrentTest);
dawn::native::GetProcs().instanceRequestAdapter(
- i, options,
+ instance, options,
[](WGPURequestAdapterStatus status, WGPUAdapter cAdapter, char const* message,
void* userdata) {
gCurrentTest->mBackendAdapter = dawn::native::FromAPI(cAdapter);
@@ -141,11 +142,6 @@
}
void ValidationTest::SetUp() {
- std::string traceName =
- std::string(::testing::UnitTest::GetInstance()->current_test_info()->test_suite_name()) +
- "_" + ::testing::UnitTest::GetInstance()->current_test_info()->name();
- mWireHelper->BeginWireTrace(traceName.c_str());
-
// Create an instance with toggle AllowUnsafeAPIs enabled, which would be inherited to
// adapter and device toggles and allow us to test unsafe apis (including experimental
// features). To test device with AllowUnsafeAPIs disabled, require it in device toggles
@@ -157,7 +153,28 @@
wgpu::InstanceDescriptor instanceDesc = {};
instanceDesc.nextInChain = &instanceToggles;
- ReinitializeInstances(&instanceDesc);
+ std::tie(mInstance, mDawnInstance) = mWireHelper->CreateInstances(&instanceDesc);
+
+ std::string traceName =
+ std::string(::testing::UnitTest::GetInstance()->current_test_info()->test_suite_name()) +
+ "_" + ::testing::UnitTest::GetInstance()->current_test_info()->name();
+ mWireHelper->BeginWireTrace(traceName.c_str());
+
+ wgpu::RequestAdapterOptions options = {};
+ options.backendType = wgpu::BackendType::Null;
+ options.compatibilityMode = gCurrentTest->UseCompatibilityMode();
+
+ CreateTestAdapter(mInstance, options);
+ DAWN_ASSERT(adapter);
+
+ wgpu::DeviceDescriptor deviceDescriptor = {};
+ deviceDescriptor.deviceLostCallback = ValidationTest::OnDeviceLost;
+ deviceDescriptor.deviceLostUserdata = this;
+
+ device = RequestDeviceSync(deviceDescriptor);
+ backendDevice = mLastCreatedBackendDevice;
+
+ device.SetUncapturedErrorCallback(ValidationTest::OnDeviceError, this);
}
ValidationTest::~ValidationTest() {
@@ -165,7 +182,7 @@
// dawn*Release will call a nullptr
device = nullptr;
adapter = nullptr;
- instance = nullptr;
+ mInstance = nullptr;
mWireHelper.reset();
// Check that all devices were destructed.
@@ -231,7 +248,7 @@
// Force the currently submitted operations to completed.
while (!done) {
- instance.ProcessEvents();
+ waitDevice.Tick();
FlushWire();
}
@@ -282,7 +299,8 @@
return mBackendAdapter;
}
-void ValidationTest::CreateTestAdapter(wgpu::RequestAdapterOptions options) {
+void ValidationTest::CreateTestAdapter(wgpu::Instance instance,
+ wgpu::RequestAdapterOptions options) {
instance.RequestAdapter(
&options,
[](WGPURequestAdapterStatus, WGPUAdapter cAdapter, const char*, void* userdata) {
@@ -316,30 +334,6 @@
return dawnAdapter.CreateDevice(&deviceDescriptor);
}
-void ValidationTest::ReinitializeInstances(const wgpu::InstanceDescriptor* nativeDesc,
- const wgpu::InstanceDescriptor* wireDesc) {
- // Reinitialize the instances.
- std::tie(instance, mDawnInstance) = mWireHelper->CreateInstances(nativeDesc, wireDesc);
-
- // Reinitialize the adapter.
- wgpu::RequestAdapterOptions options = {};
- options.backendType = wgpu::BackendType::Null;
- options.compatibilityMode = gCurrentTest->UseCompatibilityMode();
-
- CreateTestAdapter(options);
- DAWN_ASSERT(adapter);
-
- // Reinitialize the device.
- mExpectDestruction = true;
- wgpu::DeviceDescriptor deviceDescriptor = {};
- deviceDescriptor.deviceLostCallback = ValidationTest::OnDeviceLost;
- deviceDescriptor.deviceLostUserdata = this;
- device = RequestDeviceSync(deviceDescriptor);
- backendDevice = mLastCreatedBackendDevice;
- device.SetUncapturedErrorCallback(ValidationTest::OnDeviceError, this);
- mExpectDestruction = false;
-}
-
bool ValidationTest::UseCompatibilityMode() const {
return false;
}
diff --git a/src/dawn/tests/unittests/validation/ValidationTest.h b/src/dawn/tests/unittests/validation/ValidationTest.h
index 8708e7a..71c1f2e 100644
--- a/src/dawn/tests/unittests/validation/ValidationTest.h
+++ b/src/dawn/tests/unittests/validation/ValidationTest.h
@@ -164,19 +164,12 @@
protected:
dawn::native::Adapter& GetBackendAdapter();
- // Helper function to create testing adapter and device during SetUp. Override these functions
- // to change the creation behavior.
- virtual void CreateTestAdapter(wgpu::RequestAdapterOptions options);
+ // Helper function to create testing adapter and store into ValidationTest::adapter during
+ // SetUp. Override this function to change the adapter creation behavior.
+ virtual void CreateTestAdapter(wgpu::Instance instance, wgpu::RequestAdapterOptions options);
virtual WGPUDevice CreateTestDevice(dawn::native::Adapter dawnAdapter,
wgpu::DeviceDescriptor descriptor);
- // Reinitializes the ValidationTest internal members given the instance descriptors.
- // Particularly useful when writing tests that may need to pass different toggles to the
- // instance. Note that this also reinitializes the adapter and device on the new instances via
- // potentially overriden CreateTest[Adapter|Device] functions above.
- void ReinitializeInstances(const wgpu::InstanceDescriptor* nativeDesc,
- const wgpu::InstanceDescriptor* wireDesc = nullptr);
-
wgpu::Device RequestDeviceSync(const wgpu::DeviceDescriptor& deviceDesc);
static void OnDeviceError(WGPUErrorType type, const char* message, void* userdata);
static void OnDeviceLost(WGPUDeviceLostReason reason, const char* message, void* userdata);
@@ -186,12 +179,12 @@
wgpu::Device device;
wgpu::Adapter adapter;
WGPUDevice backendDevice;
- wgpu::Instance instance;
size_t mLastWarningCount = 0;
private:
std::unique_ptr<dawn::native::Instance> mDawnInstance;
+ wgpu::Instance mInstance;
dawn::native::Adapter mBackendAdapter;
std::unique_ptr<dawn::utils::WireHelper> mWireHelper;
WGPUDevice mLastCreatedBackendDevice;
diff --git a/src/dawn/tests/unittests/validation/WGSLFeatureValidationTests.cpp b/src/dawn/tests/unittests/validation/WGSLFeatureValidationTests.cpp
index 526f872..61d79a6 100644
--- a/src/dawn/tests/unittests/validation/WGSLFeatureValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/WGSLFeatureValidationTests.cpp
@@ -46,7 +46,7 @@
std::vector<const char*> blocklist = {};
};
- void ReinitializeInstances(InstanceSpec spec) {
+ wgpu::Instance CreateInstance(InstanceSpec spec) {
// The blocklist that will be shared between both the native and wire descriptors.
wgpu::DawnWGSLBlocklist blocklist;
blocklist.blocklistedFeatureCount = spec.blocklist.size();
@@ -82,7 +82,45 @@
wgpu::InstanceDescriptor wireDesc;
wireDesc.nextInChain = &wgslControl;
- ValidationTest::ReinitializeInstances(&nativeDesc, &wireDesc);
+ return GetWireHelper()->CreateInstances(&nativeDesc, &wireDesc).first;
+ }
+
+ wgpu::Device CreateDeviceOnInstance(wgpu::Instance instance) {
+ // Get the adapter
+ wgpu::Adapter adapter;
+ instance.RequestAdapter(
+ nullptr,
+ [](WGPURequestAdapterStatus status, WGPUAdapter a, const char* message,
+ void* userdata) {
+ ASSERT_EQ(status, WGPURequestAdapterStatus_Success);
+ ASSERT_NE(a, nullptr);
+ *reinterpret_cast<wgpu::Adapter*>(userdata) = wgpu::Adapter::Acquire(a);
+ },
+ &adapter);
+
+ while (!adapter) {
+ FlushWire();
+ }
+ EXPECT_NE(nullptr, adapter.Get());
+
+ // Get the device
+ wgpu::Device device;
+ adapter.RequestDevice(
+ nullptr,
+ [](WGPURequestDeviceStatus status, WGPUDevice d, const char* message, void* userdata) {
+ ASSERT_EQ(status, WGPURequestDeviceStatus_Success);
+ ASSERT_NE(d, nullptr);
+ *reinterpret_cast<wgpu::Device*>(userdata) = wgpu::Device::Acquire(d);
+ },
+ &device);
+
+ while (!device) {
+ FlushWire();
+ }
+ EXPECT_NE(nullptr, device.Get());
+
+ device.SetUncapturedErrorCallback(ValidationTest::OnDeviceError, this);
+ return device;
}
};
@@ -90,7 +128,7 @@
// Check HasFeature for an Instance that doesn't have unsafe APIs.
TEST_F(WGSLFeatureValidationTest, HasFeatureDefaultInstance) {
- ReinitializeInstances({});
+ wgpu::Instance instance = CreateInstance({});
// Shipped features are present.
ASSERT_TRUE(instance.HasWGSLLanguageFeature(wgpu::WGSLFeatureName::ChromiumTestingShipped));
@@ -111,7 +149,7 @@
// Check HasFeature for an Instance that has unsafe APIs.
TEST_F(WGSLFeatureValidationTest, HasFeatureExposeExperimental) {
- ReinitializeInstances({.exposeExperimental = true});
+ wgpu::Instance instance = CreateInstance({.exposeExperimental = true});
// Shipped and experimental features are present.
ASSERT_TRUE(instance.HasWGSLLanguageFeature(wgpu::WGSLFeatureName::ChromiumTestingShipped));
@@ -132,7 +170,7 @@
// Check HasFeature for an Instance that has unsafe APIs.
TEST_F(WGSLFeatureValidationTest, HasFeatureAllowUnsafeInstance) {
- ReinitializeInstances({.allowUnsafeAPIs = true});
+ wgpu::Instance instance = CreateInstance({.allowUnsafeAPIs = true});
// Shipped and experimental features are present.
ASSERT_TRUE(instance.HasWGSLLanguageFeature(wgpu::WGSLFeatureName::ChromiumTestingShipped));
@@ -153,7 +191,7 @@
// Check HasFeature for an Instance that doesn't have the expose_wgsl_testing_features toggle.
TEST_F(WGSLFeatureValidationTest, HasFeatureWithoutExposeWGSLTestingFeatures) {
- ReinitializeInstances({.useTestingFeatures = false});
+ wgpu::Instance instance = CreateInstance({.useTestingFeatures = false});
// None of the testing features are present.
ASSERT_FALSE(instance.HasWGSLLanguageFeature(wgpu::WGSLFeatureName::ChromiumTestingShipped));
@@ -169,7 +207,7 @@
// Tests for the behavior of WGSL feature enumeration.
TEST_F(WGSLFeatureValidationTest, EnumerateFeatures) {
- ReinitializeInstances({});
+ wgpu::Instance instance = CreateInstance({});
size_t featureCount = instance.EnumerateWGSLLanguageFeatures(nullptr);
@@ -205,7 +243,8 @@
// Check that the enabled / disabled features are used to validate the WGSL shaders.
TEST_F(WGSLFeatureValidationTest, UsingFeatureInShaderModule) {
- ReinitializeInstances({});
+ wgpu::Instance instance = CreateInstance({});
+ wgpu::Device device = CreateDeviceOnInstance(instance);
utils::CreateShaderModule(device, R"(
requires chromium_testing_shipped;
@@ -227,7 +266,7 @@
// Test using DawnWGSLBlocklist to block features with a killswitch by name.
TEST_F(WGSLFeatureValidationTest, BlockListOfKillswitchedFeatures) {
- ReinitializeInstances(
+ wgpu::Instance instance = CreateInstance(
{.allowUnsafeAPIs = true, .blocklist = {"chromium_testing_shipped_with_killswitch"}});
// The blocklisted feature is not present.
@@ -242,6 +281,7 @@
instance.HasWGSLLanguageFeature(wgpu::WGSLFeatureName::ChromiumTestingUnsafeExperimental));
// Using the blocklisted extension fails.
+ wgpu::Device device = CreateDeviceOnInstance(instance);
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, R"(
requires chromium_testing_shipped_with_killswitch;
)"));
@@ -249,10 +289,10 @@
// Test that DawnWGSLBlocklist can block any feature name (even without a killswitch).
TEST_F(WGSLFeatureValidationTest, BlockListOfAnyFeature) {
- ReinitializeInstances(
- {.allowUnsafeAPIs = true,
- .blocklist = {"chromium_testing_shipped", "chromium_testing_experimental",
- "chromium_testing_unsafe_experimental"}});
+ wgpu::Instance instance =
+ CreateInstance({.allowUnsafeAPIs = true,
+ .blocklist = {"chromium_testing_shipped", "chromium_testing_experimental",
+ "chromium_testing_unsafe_experimental"}});
// All blocklisted features aren't present.
ASSERT_FALSE(instance.HasWGSLLanguageFeature(wgpu::WGSLFeatureName::ChromiumTestingShipped));
@@ -264,7 +304,7 @@
// Test that DawnWGSLBlocklist can contain garbage names without causing problems.
TEST_F(WGSLFeatureValidationTest, BlockListGarbageName) {
- ReinitializeInstances({.blocklist = {"LE_GARBAGE"}});
+ wgpu::Instance instance = CreateInstance({.blocklist = {"LE_GARBAGE"}});
ASSERT_NE(instance, nullptr);
}
diff --git a/src/dawn/tests/unittests/wire/WireErrorCallbackTests.cpp b/src/dawn/tests/unittests/wire/WireErrorCallbackTests.cpp
index 31ad03c..4bb2abd 100644
--- a/src/dawn/tests/unittests/wire/WireErrorCallbackTests.cpp
+++ b/src/dawn/tests/unittests/wire/WireErrorCallbackTests.cpp
@@ -26,9 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory>
-#include <utility>
-#include "dawn/tests/unittests/wire/WireFutureTest.h"
#include "dawn/tests/unittests/wire/WireTest.h"
#include "dawn/wire/WireClient.h"
@@ -37,7 +35,6 @@
using testing::_;
using testing::DoAll;
-using testing::InvokeWithoutArgs;
using testing::Mock;
using testing::Return;
using testing::SaveArg;
@@ -55,6 +52,16 @@
mockDeviceErrorCallback->Call(type, message, userdata);
}
+class MockDevicePopErrorScopeCallback {
+ public:
+ MOCK_METHOD(void, Call, (WGPUErrorType type, const char* message, void* userdata));
+};
+
+std::unique_ptr<StrictMock<MockDevicePopErrorScopeCallback>> mockDevicePopErrorScopeCallback;
+void ToMockDevicePopErrorScopeCallback(WGPUErrorType type, const char* message, void* userdata) {
+ mockDevicePopErrorScopeCallback->Call(type, message, userdata);
+}
+
class MockDeviceLoggingCallback {
public:
MOCK_METHOD(void, Call, (WGPULoggingType type, const char* message, void* userdata));
@@ -85,6 +92,8 @@
mockDeviceErrorCallback = std::make_unique<StrictMock<MockDeviceErrorCallback>>();
mockDeviceLoggingCallback = std::make_unique<StrictMock<MockDeviceLoggingCallback>>();
+ mockDevicePopErrorScopeCallback =
+ std::make_unique<StrictMock<MockDevicePopErrorScopeCallback>>();
mockDeviceLostCallback = std::make_unique<StrictMock<MockDeviceLostCallback>>();
}
@@ -93,6 +102,7 @@
mockDeviceErrorCallback = nullptr;
mockDeviceLoggingCallback = nullptr;
+ mockDevicePopErrorScopeCallback = nullptr;
mockDeviceLostCallback = nullptr;
}
@@ -100,6 +110,7 @@
WireTest::FlushServer();
Mock::VerifyAndClearExpectations(&mockDeviceErrorCallback);
+ Mock::VerifyAndClearExpectations(&mockDevicePopErrorScopeCallback);
}
};
@@ -177,6 +188,195 @@
FlushServer();
}
+// Test the return wire for validation error scopes.
+TEST_F(WireErrorCallbackTests, PushPopValidationErrorScopeCallback) {
+ EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(1);
+ wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
+ FlushClient();
+
+ WGPUErrorCallback callback;
+ void* userdata;
+ EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&callback), SaveArg<2>(&userdata)));
+ wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this);
+ FlushClient();
+
+ EXPECT_CALL(*mockDevicePopErrorScopeCallback,
+ Call(WGPUErrorType_Validation, StrEq("Some error message"), this))
+ .Times(1);
+ callback(WGPUErrorType_Validation, "Some error message", userdata);
+ FlushServer();
+}
+
+// Test the return wire for OOM error scopes.
+TEST_F(WireErrorCallbackTests, PushPopOOMErrorScopeCallback) {
+ EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_OutOfMemory)).Times(1);
+ wgpuDevicePushErrorScope(device, WGPUErrorFilter_OutOfMemory);
+ FlushClient();
+
+ WGPUErrorCallback callback;
+ void* userdata;
+ EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&callback), SaveArg<2>(&userdata)));
+ wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this);
+ FlushClient();
+
+ EXPECT_CALL(*mockDevicePopErrorScopeCallback,
+ Call(WGPUErrorType_OutOfMemory, StrEq("Some error message"), this))
+ .Times(1);
+ callback(WGPUErrorType_OutOfMemory, "Some error message", userdata);
+ FlushServer();
+}
+
+// Test the return wire for internal error scopes.
+TEST_F(WireErrorCallbackTests, PushPopInternalErrorScopeCallback) {
+ EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Internal)).Times(1);
+ wgpuDevicePushErrorScope(device, WGPUErrorFilter_Internal);
+ FlushClient();
+
+ WGPUErrorCallback callback;
+ void* userdata;
+ EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&callback), SaveArg<2>(&userdata)));
+ wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this);
+ FlushClient();
+
+ EXPECT_CALL(*mockDevicePopErrorScopeCallback,
+ Call(WGPUErrorType_Internal, StrEq("Some error message"), this))
+ .Times(1);
+ callback(WGPUErrorType_Internal, "Some error message", userdata);
+ FlushServer();
+}
+
+// Test the return wire for error scopes when callbacks return in a various orders.
+TEST_F(WireErrorCallbackTests, PopErrorScopeCallbackOrdering) {
+ // Two error scopes are popped, and the first one returns first.
+ {
+ EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(2);
+ wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
+ wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
+ FlushClient();
+
+ WGPUErrorCallback callback1;
+ WGPUErrorCallback callback2;
+ void* userdata1;
+ void* userdata2;
+ EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&callback1), SaveArg<2>(&userdata1)))
+ .WillOnce(DoAll(SaveArg<1>(&callback2), SaveArg<2>(&userdata2)));
+ wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this);
+ wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this + 1);
+ FlushClient();
+
+ EXPECT_CALL(*mockDevicePopErrorScopeCallback,
+ Call(WGPUErrorType_Validation, StrEq("First error message"), this))
+ .Times(1);
+ callback1(WGPUErrorType_Validation, "First error message", userdata1);
+ FlushServer();
+
+ EXPECT_CALL(*mockDevicePopErrorScopeCallback,
+ Call(WGPUErrorType_Validation, StrEq("Second error message"), this + 1))
+ .Times(1);
+ callback2(WGPUErrorType_Validation, "Second error message", userdata2);
+ FlushServer();
+ }
+
+ // Two error scopes are popped, and the second one returns first.
+ {
+ EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(2);
+ wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
+ wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
+ FlushClient();
+
+ WGPUErrorCallback callback1;
+ WGPUErrorCallback callback2;
+ void* userdata1;
+ void* userdata2;
+ EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&callback1), SaveArg<2>(&userdata1)))
+ .WillOnce(DoAll(SaveArg<1>(&callback2), SaveArg<2>(&userdata2)));
+ wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this);
+ wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this + 1);
+ FlushClient();
+
+ EXPECT_CALL(*mockDevicePopErrorScopeCallback,
+ Call(WGPUErrorType_Validation, StrEq("Second error message"), this + 1))
+ .Times(1);
+ callback2(WGPUErrorType_Validation, "Second error message", userdata2);
+ FlushServer();
+
+ EXPECT_CALL(*mockDevicePopErrorScopeCallback,
+ Call(WGPUErrorType_Validation, StrEq("First error message"), this))
+ .Times(1);
+ callback1(WGPUErrorType_Validation, "First error message", userdata1);
+ FlushServer();
+ }
+}
+
+// Test the return wire for error scopes in flight when the device is destroyed.
+TEST_F(WireErrorCallbackTests, PopErrorScopeDeviceInFlightDestroy) {
+ EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(1);
+ wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
+ FlushClient();
+
+ EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _)).Times(1);
+ wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this);
+ FlushClient();
+
+ // Incomplete callback called in Device destructor. This is resolved after the end of this
+ // test.
+ EXPECT_CALL(*mockDevicePopErrorScopeCallback,
+ Call(WGPUErrorType_Unknown, ValidStringMessage(), this))
+ .Times(1);
+}
+
+// Test that registering a callback then wire disconnect calls the callback with
+// DeviceLost.
+TEST_F(WireErrorCallbackTests, PopErrorScopeThenDisconnect) {
+ EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(1);
+ wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
+
+ EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _)).Times(1);
+ wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this);
+ FlushClient();
+
+ EXPECT_CALL(*mockDevicePopErrorScopeCallback,
+ Call(WGPUErrorType_DeviceLost, ValidStringMessage(), this))
+ .Times(1);
+ GetWireClient()->Disconnect();
+}
+
+// Test that registering a callback after wire disconnect calls the callback with
+// DeviceLost.
+TEST_F(WireErrorCallbackTests, PopErrorScopeAfterDisconnect) {
+ EXPECT_CALL(api, DevicePushErrorScope(apiDevice, WGPUErrorFilter_Validation)).Times(1);
+ wgpuDevicePushErrorScope(device, WGPUErrorFilter_Validation);
+ FlushClient();
+
+ GetWireClient()->Disconnect();
+
+ EXPECT_CALL(*mockDevicePopErrorScopeCallback,
+ Call(WGPUErrorType_DeviceLost, ValidStringMessage(), this))
+ .Times(1);
+ wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this);
+}
+
+// Empty stack (We are emulating the errors that would be callback-ed from native).
+TEST_F(WireErrorCallbackTests, PopErrorScopeEmptyStack) {
+ WGPUErrorCallback callback;
+ void* userdata;
+ EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&callback), SaveArg<2>(&userdata)));
+ wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this);
+ FlushClient();
+
+ EXPECT_CALL(*mockDevicePopErrorScopeCallback,
+ Call(WGPUErrorType_Validation, StrEq("No error scopes to pop"), this))
+ .Times(1);
+ callback(WGPUErrorType_Validation, "No error scopes to pop", userdata);
+ FlushServer();
+}
+
// Test the return wire for device lost callback
TEST_F(WireErrorCallbackTests, DeviceLostCallback) {
wgpuDeviceSetDeviceLostCallback(device, ToMockDeviceLostCallback, this);
@@ -196,161 +396,5 @@
FlushServer();
}
-class WirePopErrorScopeCallbackTests : public WireFutureTestWithParamsBase<> {
- protected:
- // Overridden version of wgpuDevicePopErrorScope that defers to the API call based on the test
- // callback mode.
- void DevicePopErrorScope(WGPUDevice d, void* userdata = nullptr) {
- if (this->IsAsync()) {
- wgpuDevicePopErrorScope(d, mMockOldCb.Callback(), mMockOldCb.MakeUserdata(userdata));
- } else {
- WGPUPopErrorScopeCallbackInfo callbackInfo = {};
- callbackInfo.mode = ToWGPUCallbackMode(GetParam().mCallbackMode);
- callbackInfo.callback = mMockCb.Callback();
- callbackInfo.userdata = mMockCb.MakeUserdata(userdata);
- this->mFutureIDs.push_back(wgpuDevicePopErrorScopeF(d, callbackInfo).id);
- }
- }
-
- void PushErrorScope(WGPUErrorFilter filter) {
- EXPECT_CALL(api, DevicePushErrorScope(apiDevice, filter)).Times(1);
- wgpuDevicePushErrorScope(device, filter);
- FlushClient();
- }
-
- void ExpectWireCallbacksWhen(
- std::function<void(testing::MockCallback<WGPUErrorCallback>&)> oldExp,
- std::function<void(testing::MockCallback<WGPUPopErrorScopeCallback>&)> exp) {
- if (IsAsync()) {
- oldExp(mMockOldCb);
- ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&mMockOldCb));
- } else {
- exp(mMockCb);
- ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&mMockCb));
- }
- }
-
- private:
- testing::MockCallback<WGPUPopErrorScopeCallback> mMockCb;
- testing::MockCallback<WGPUErrorCallback> mMockOldCb;
-};
-DAWN_INSTANTIATE_WIRE_FUTURE_TEST_P(WirePopErrorScopeCallbackTests);
-
-// Test the return wire for validation error scopes.
-TEST_P(WirePopErrorScopeCallbackTests, TypeAndFilters) {
- static constexpr std::array<std::pair<WGPUErrorType, WGPUErrorFilter>, 3> kErrorTypeAndFilters =
- {{{WGPUErrorType_Validation, WGPUErrorFilter_Validation},
- {WGPUErrorType_OutOfMemory, WGPUErrorFilter_OutOfMemory},
- {WGPUErrorType_Internal, WGPUErrorFilter_Internal}}};
-
- for (const auto& [type, filter] : kErrorTypeAndFilters) {
- PushErrorScope(filter);
-
- DevicePopErrorScope(device, this);
- EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _)).WillOnce(InvokeWithoutArgs([&] {
- api.CallDevicePopErrorScopeCallback(apiDevice, type, "Some error message");
- }));
-
- FlushClient();
- FlushFutures();
- ExpectWireCallbacksWhen(
- [&](auto& oldMockCb) {
- EXPECT_CALL(oldMockCb, Call(type, StrEq("Some error message"), this)).Times(1);
-
- FlushCallbacks();
- },
- [&](auto& mockCb) {
- EXPECT_CALL(mockCb, Call(WGPUPopErrorScopeStatus_Success, type,
- StrEq("Some error message"), this))
- .Times(1);
-
- FlushCallbacks();
- });
- }
-}
-
-// Wire disconnect before server response calls the callback with Unknown error type.
-// TODO(crbug.com/dawn/2021) When using new callback signature, check for InstanceDropped status.
-TEST_P(WirePopErrorScopeCallbackTests, DisconnectBeforeServerReply) {
- PushErrorScope(WGPUErrorFilter_Validation);
-
- DevicePopErrorScope(device, this);
- EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _)).Times(1);
-
- FlushClient();
- FlushFutures();
- ExpectWireCallbacksWhen(
- [&](auto& oldMockCb) {
- EXPECT_CALL(oldMockCb, Call(WGPUErrorType_Unknown, nullptr, this)).Times(1);
-
- GetWireClient()->Disconnect();
- },
- [&](auto& mockCb) {
- EXPECT_CALL(mockCb, Call(WGPUPopErrorScopeStatus_InstanceDropped, WGPUErrorType_Unknown,
- nullptr, this))
- .Times(1);
-
- GetWireClient()->Disconnect();
- });
-}
-
-// Wire disconnect after server response calls the callback with returned error type.
-TEST_P(WirePopErrorScopeCallbackTests, DisconnectAfterServerReply) {
- // On Async and Spontaneous mode, it is not possible to simulate this because on the server
- // reponse, the callback would also be fired.
- DAWN_SKIP_TEST_IF(IsSpontaneous());
-
- PushErrorScope(WGPUErrorFilter_Validation);
-
- DevicePopErrorScope(device, this);
- EXPECT_CALL(api, OnDevicePopErrorScope(apiDevice, _, _)).WillOnce(InvokeWithoutArgs([&] {
- api.CallDevicePopErrorScopeCallback(apiDevice, WGPUErrorType_Validation,
- "Some error message");
- }));
-
- FlushClient();
- FlushFutures();
- ExpectWireCallbacksWhen(
- [&](auto& oldMockCb) {
- EXPECT_CALL(oldMockCb, Call(WGPUErrorType_Validation, nullptr, this)).Times(1);
-
- GetWireClient()->Disconnect();
- },
- [&](auto& mockCb) {
- EXPECT_CALL(mockCb, Call(WGPUPopErrorScopeStatus_InstanceDropped,
- WGPUErrorType_Validation, nullptr, this))
- .Times(1);
-
- GetWireClient()->Disconnect();
- });
-}
-
-// 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([&] {
- api.CallDevicePopErrorScopeCallback(apiDevice, WGPUErrorType_Validation,
- "No error scopes to pop");
- }));
-
- FlushClient();
- FlushFutures();
- ExpectWireCallbacksWhen(
- [&](auto& oldMockCb) {
- EXPECT_CALL(oldMockCb,
- Call(WGPUErrorType_Validation, StrEq("No error scopes to pop"), this))
- .Times(1);
-
- FlushCallbacks();
- },
- [&](auto& mockCb) {
- EXPECT_CALL(mockCb, Call(WGPUPopErrorScopeStatus_Success, WGPUErrorType_Validation,
- StrEq("No error scopes to pop"), this))
- .Times(1);
-
- FlushCallbacks();
- });
-}
-
} // anonymous namespace
} // namespace dawn::wire
diff --git a/src/dawn/tests/unittests/wire/WireFutureTest.h b/src/dawn/tests/unittests/wire/WireFutureTest.h
index 5b26c93..042db62 100644
--- a/src/dawn/tests/unittests/wire/WireFutureTest.h
+++ b/src/dawn/tests/unittests/wire/WireFutureTest.h
@@ -85,11 +85,34 @@
, testName, testing::ValuesIn(MakeParamGenerator<testName::ParamType>(__VA_ARGS__)), \
&TestParamToString<testName::ParamType>)
-template <typename Params = WireFutureTestParam>
-class WireFutureTestWithParamsBase : public WireTest, public testing::WithParamInterface<Params> {
+template <typename Callback,
+ typename CallbackInfo,
+ auto& AsyncF,
+ auto& FutureF,
+ typename Params = WireFutureTestParam,
+ typename AsyncFT = decltype(AsyncF),
+ typename FutureFT = decltype(FutureF)>
+class WireFutureTestWithParams : public WireTest, public testing::WithParamInterface<Params> {
protected:
using testing::WithParamInterface<Params>::GetParam;
+ // Calls the actual API that the test suite is exercising given the callback mode. This should
+ // be used in favor of directly calling the API because the Async mode actually calls a
+ // different entry point.
+ template <typename... Args>
+ void CallImpl(void* userdata, Args&&... args) {
+ if (GetParam().mCallbackMode == CallbackMode::Async) {
+ mAsyncF(std::forward<Args>(args)..., mMockCb.Callback(),
+ mMockCb.MakeUserdata(userdata));
+ } else {
+ CallbackInfo callbackInfo = {};
+ callbackInfo.mode = ToWGPUCallbackMode(GetParam().mCallbackMode);
+ callbackInfo.callback = mMockCb.Callback();
+ callbackInfo.userdata = mMockCb.MakeUserdata(userdata);
+ mFutureIDs.push_back(mFutureF(std::forward<Args>(args)..., callbackInfo).id);
+ }
+ }
+
// Events are considered spontaneous if either we are using the legacy Async or the new
// Spontaneous modes.
bool IsSpontaneous() {
@@ -97,8 +120,24 @@
return callbackMode == CallbackMode::Async || callbackMode == CallbackMode::Spontaneous;
}
- // Returns true iff testing older Async entry points, i.e. not Future related entry points.
- bool IsAsync() { return GetParam().mCallbackMode == CallbackMode::Async; }
+ // In order to tightly bound when callbacks are expected to occur, test writers only have access
+ // to the mock callback via the argument passed usually via a lamdba. The 'exp' lambda should
+ // generally be a block of expectations on the mock callback followed by one statement where we
+ // expect the callbacks to be called from. If the callbacks do not occur in the scope of the
+ // lambda, the mock will fail the test.
+ //
+ // Usage:
+ // ExpectWireCallbackWhen([&](auto& mockCb) {
+ // // Set scoped expectations on the mock callback.
+ // EXPECT_CALL(mockCb, Call).Times(1);
+ //
+ // // Call the statement where we want to ensure the callbacks occur.
+ // FlushCallbacks();
+ // });
+ void ExpectWireCallbacksWhen(std::function<void(testing::MockCallback<Callback>&)> exp) {
+ exp(mMockCb);
+ ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&mMockCb));
+ }
// Future suite adds the following flush mechanics for test writers so that they can have fine
// grained control over when expectations should be set and verified.
@@ -150,57 +189,11 @@
}
}
- std::vector<FutureID> mFutureIDs;
-};
-
-template <typename Callback,
- typename CallbackInfo,
- auto& AsyncF,
- auto& FutureF,
- typename Params = WireFutureTestParam,
- typename AsyncFT = decltype(AsyncF),
- typename FutureFT = decltype(FutureF)>
-class WireFutureTestWithParams : public WireFutureTestWithParamsBase<Params> {
- protected:
- // Calls the actual API that the test suite is exercising given the callback mode. This should
- // be used in favor of directly calling the API because the Async mode actually calls a
- // different entry point.
- template <typename... Args>
- void CallImpl(void* userdata, Args&&... args) {
- if (this->IsAsync()) {
- mAsyncF(std::forward<Args>(args)..., mMockCb.Callback(),
- mMockCb.MakeUserdata(userdata));
- } else {
- CallbackInfo callbackInfo = {};
- callbackInfo.mode = ToWGPUCallbackMode(this->GetParam().mCallbackMode);
- callbackInfo.callback = mMockCb.Callback();
- callbackInfo.userdata = mMockCb.MakeUserdata(userdata);
- this->mFutureIDs.push_back(mFutureF(std::forward<Args>(args)..., callbackInfo).id);
- }
- }
-
- // In order to tightly bound when callbacks are expected to occur, test writers only have access
- // to the mock callback via the argument passed usually via a lamdba. The 'exp' lambda should
- // generally be a block of expectations on the mock callback followed by one statement where we
- // expect the callbacks to be called from. If the callbacks do not occur in the scope of the
- // lambda, the mock will fail the test.
- //
- // Usage:
- // ExpectWireCallbackWhen([&](auto& mockCb) {
- // // Set scoped expectations on the mock callback.
- // EXPECT_CALL(mockCb, Call).Times(1);
- //
- // // Call the statement where we want to ensure the callbacks occur.
- // FlushCallbacks();
- // });
- void ExpectWireCallbacksWhen(std::function<void(testing::MockCallback<Callback>&)> exp) {
- exp(mMockCb);
- ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&mMockCb));
- }
-
private:
AsyncFT mAsyncF = AsyncF;
FutureFT mFutureF = FutureF;
+ std::vector<FutureID> mFutureIDs;
+
testing::MockCallback<Callback> mMockCb;
};
diff --git a/src/dawn/wire/client/ClientDoers.cpp b/src/dawn/wire/client/ClientDoers.cpp
index ba4064d..4f0b053 100644
--- a/src/dawn/wire/client/ClientDoers.cpp
+++ b/src/dawn/wire/client/ClientDoers.cpp
@@ -77,6 +77,20 @@
return WireResult::Success;
}
+WireResult Client::DoDevicePopErrorScopeCallback(Device* device,
+ uint64_t requestSerial,
+ WGPUErrorType errorType,
+ const char* message) {
+ if (device == nullptr) {
+ // The device might have been deleted or recreated so this isn't an error.
+ return WireResult::Success;
+ }
+ if (device->OnPopErrorScopeCallback(requestSerial, errorType, message)) {
+ return WireResult::Success;
+ }
+ return WireResult::FatalError;
+}
+
WireResult Client::DoShaderModuleGetCompilationInfoCallback(ShaderModule* shaderModule,
uint64_t requestSerial,
WGPUCompilationInfoRequestStatus status,
diff --git a/src/dawn/wire/client/Device.cpp b/src/dawn/wire/client/Device.cpp
index d7d2620..68cf129 100644
--- a/src/dawn/wire/client/Device.cpp
+++ b/src/dawn/wire/client/Device.cpp
@@ -41,55 +41,6 @@
namespace dawn::wire::client {
namespace {
-class PopErrorScopeEvent final : public TrackedEvent {
- public:
- static constexpr EventType kType = EventType::PopErrorScope;
-
- explicit PopErrorScopeEvent(const WGPUPopErrorScopeCallbackInfo& 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));
- }
-
- EventType GetType() override { return kType; }
-
- WireResult ReadyHook(FutureID futureID, WGPUErrorType errorType, const char* message) {
- mType = errorType;
- if (message != nullptr) {
- mMessage = message;
- }
- return WireResult::Success;
- }
-
- private:
- void CompleteImpl(FutureID futureID, EventCompletionType completionType) override {
- if (completionType == EventCompletionType::Shutdown) {
- mStatus = WGPUPopErrorScopeStatus_InstanceDropped;
- mMessage = std::nullopt;
- }
- if (mOldCallback) {
- mOldCallback(mType, mMessage ? mMessage->c_str() : nullptr, mUserdata);
- }
- if (mCallback) {
- mCallback(mStatus, mType, mMessage ? mMessage->c_str() : nullptr, mUserdata);
- }
- }
-
- // TODO(crbug.com/dawn/2021) Remove the old callback type.
- WGPUPopErrorScopeCallback mCallback;
- WGPUErrorCallback mOldCallback;
- // TODO(https://crbug.com/dawn/2345): Investigate `DanglingUntriaged` in dawn/wire.
- raw_ptr<void, DanglingUntriaged> mUserdata;
-
- WGPUPopErrorScopeStatus mStatus = WGPUPopErrorScopeStatus_Success;
- WGPUErrorType mType = WGPUErrorType_Unknown;
- std::optional<std::string> mMessage;
-};
-
template <typename PipelineT, EventType Type, typename CallbackInfoT>
class CreatePipelineEventBase : public TrackedEvent {
public:
@@ -199,6 +150,11 @@
}
Device::~Device() {
+ mErrorScopes.CloseAll([](ErrorScopeData* request) {
+ request->callback(WGPUErrorType_Unknown, "Device destroyed before callback",
+ request->userdata);
+ });
+
if (mQueue != nullptr) {
GetProcs().queueRelease(ToAPI(mQueue));
}
@@ -248,6 +204,12 @@
}
}
+void Device::CancelCallbacksForDisconnect() {
+ mErrorScopes.CloseAll([](ErrorScopeData* request) {
+ request->callback(WGPUErrorType_DeviceLost, "Device lost", request->userdata);
+ });
+}
+
std::weak_ptr<bool> Device::GetAliveWeakPtr() {
return mIsAlive;
}
@@ -268,35 +230,41 @@
}
void Device::PopErrorScope(WGPUErrorCallback callback, void* userdata) {
- WGPUPopErrorScopeCallbackInfo callbackInfo = {};
- callbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
- callbackInfo.oldCallback = callback;
- callbackInfo.userdata = userdata;
- PopErrorScopeF(callbackInfo);
-}
-
-WGPUFuture Device::PopErrorScopeF(const WGPUPopErrorScopeCallbackInfo& callbackInfo) {
Client* client = GetClient();
- auto [futureIDInternal, tracked] =
- GetEventManager().TrackEvent(std::make_unique<PopErrorScopeEvent>(callbackInfo));
- if (!tracked) {
- return {futureIDInternal};
+ if (client->IsDisconnected()) {
+ callback(WGPUErrorType_DeviceLost, "GPU device disconnected", userdata);
+ return;
}
+ uint64_t serial = mErrorScopes.Add({callback, userdata});
DevicePopErrorScopeCmd cmd;
cmd.deviceId = GetWireId();
- cmd.eventManagerHandle = GetEventManagerHandle();
- cmd.future = {futureIDInternal};
+ cmd.requestSerial = serial;
client->SerializeCommand(cmd);
- return {futureIDInternal};
}
-WireResult Client::DoDevicePopErrorScopeCallback(ObjectHandle eventManager,
- WGPUFuture future,
- WGPUErrorType errorType,
- const char* message) {
- return GetEventManager(eventManager)
- .SetFutureReady<PopErrorScopeEvent>(future.id, errorType, message);
+bool Device::OnPopErrorScopeCallback(uint64_t requestSerial,
+ WGPUErrorType type,
+ const char* message) {
+ switch (type) {
+ case WGPUErrorType_NoError:
+ case WGPUErrorType_Validation:
+ case WGPUErrorType_OutOfMemory:
+ case WGPUErrorType_Internal:
+ case WGPUErrorType_Unknown:
+ case WGPUErrorType_DeviceLost:
+ break;
+ default:
+ return false;
+ }
+
+ ErrorScopeData request;
+ if (!mErrorScopes.Acquire(requestSerial, &request)) {
+ return false;
+ }
+
+ request.callback(type, message, request.userdata);
+ return true;
}
void Device::InjectError(WGPUErrorType type, const char* message) {
diff --git a/src/dawn/wire/client/Device.h b/src/dawn/wire/client/Device.h
index a04baf1..d9d9170 100644
--- a/src/dawn/wire/client/Device.h
+++ b/src/dawn/wire/client/Device.h
@@ -58,7 +58,6 @@
void SetDeviceLostCallback(WGPUDeviceLostCallback errorCallback, void* errorUserdata);
void InjectError(WGPUErrorType type, const char* message);
void PopErrorScope(WGPUErrorCallback callback, void* userdata);
- WGPUFuture PopErrorScopeF(const WGPUPopErrorScopeCallbackInfo& callbackInfo);
WGPUBuffer CreateBuffer(const WGPUBufferDescriptor* descriptor);
void CreateComputePipelineAsync(WGPUComputePipelineDescriptor const* descriptor,
WGPUCreateComputePipelineAsyncCallback callback,
@@ -76,6 +75,7 @@
void HandleError(WGPUErrorType errorType, const char* message);
void HandleLogging(WGPULoggingType loggingType, const char* message);
void HandleDeviceLost(WGPUDeviceLostReason reason, const char* message);
+ bool OnPopErrorScopeCallback(uint64_t requestSerial, WGPUErrorType type, const char* message);
bool GetLimits(WGPUSupportedLimits* limits) const;
bool HasFeature(WGPUFeatureName feature) const;
@@ -85,6 +85,8 @@
WGPUQueue GetQueue();
+ void CancelCallbacksForDisconnect() override;
+
std::weak_ptr<bool> GetAliveWeakPtr();
private:
@@ -95,6 +97,12 @@
WGPUFuture CreatePipelineAsyncF(Descriptor const* descriptor, const CallbackInfo& callbackInfo);
LimitsAndFeatures mLimitsAndFeatures;
+ struct ErrorScopeData {
+ WGPUErrorCallback callback = nullptr;
+ // TODO(https://crbug.com/dawn/2345): Investigate `DanglingUntriaged` in dawn/wire.
+ raw_ptr<void, DanglingUntriaged> userdata = nullptr;
+ };
+ RequestTracker<ErrorScopeData> mErrorScopes;
WGPUErrorCallback mErrorCallback = nullptr;
WGPUDeviceLostCallback mDeviceLostCallback = nullptr;
diff --git a/src/dawn/wire/client/EventManager.h b/src/dawn/wire/client/EventManager.h
index b3123ca..c9c1415 100644
--- a/src/dawn/wire/client/EventManager.h
+++ b/src/dawn/wire/client/EventManager.h
@@ -49,7 +49,6 @@
CreateComputePipeline,
CreateRenderPipeline,
MapAsync,
- PopErrorScope,
RequestAdapter,
RequestDevice,
WorkDone,
diff --git a/src/dawn/wire/server/Server.h b/src/dawn/wire/server/Server.h
index 7c74e77..d4d0ec9 100644
--- a/src/dawn/wire/server/Server.h
+++ b/src/dawn/wire/server/Server.h
@@ -117,8 +117,7 @@
using CallbackUserdata::CallbackUserdata;
ObjectHandle device;
- ObjectHandle eventManager;
- WGPUFuture future;
+ uint64_t requestSerial;
};
struct ShaderModuleGetCompilationInfoUserdata : CallbackUserdata {
diff --git a/src/dawn/wire/server/ServerDevice.cpp b/src/dawn/wire/server/ServerDevice.cpp
index 3d9fd40..aa0a27b 100644
--- a/src/dawn/wire/server/ServerDevice.cpp
+++ b/src/dawn/wire/server/ServerDevice.cpp
@@ -74,13 +74,10 @@
SerializeCommand(cmd);
}
-WireResult Server::DoDevicePopErrorScope(Known<WGPUDevice> device,
- ObjectHandle eventManager,
- WGPUFuture future) {
+WireResult Server::DoDevicePopErrorScope(Known<WGPUDevice> device, uint64_t requestSerial) {
auto userdata = MakeUserdata<ErrorScopeUserdata>();
+ userdata->requestSerial = requestSerial;
userdata->device = device.AsHandle();
- userdata->eventManager = eventManager;
- userdata->future = future;
mProcs.devicePopErrorScope(device->handle, ForwardToServer<&Server::OnDevicePopErrorScope>,
userdata.release());
@@ -91,8 +88,8 @@
WGPUErrorType type,
const char* message) {
ReturnDevicePopErrorScopeCallbackCmd cmd;
- cmd.eventManager = userdata->eventManager;
- cmd.future = userdata->future;
+ cmd.device = userdata->device;
+ cmd.requestSerial = userdata->requestSerial;
cmd.type = type;
cmd.message = message;