[WGPUFuture] Manually scope the device lock for Future entry points.
Bug: dawn:2449 dawn:2451
Change-Id: I3cb02439c1392b7d521b5b5756facb7ae63f3edc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/177933
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Loko Kung <lokokung@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/generator/templates/dawn/native/ProcTable.cpp b/generator/templates/dawn/native/ProcTable.cpp
index 7c7931c..c3ac507 100644
--- a/generator/templates/dawn/native/ProcTable.cpp
+++ b/generator/templates/dawn/native/ProcTable.cpp
@@ -71,7 +71,7 @@
{% endif %}
{%- endfor-%}
- {% if method.autolock %}
+ {% if method.autolock and method.return_type.name.get() != 'future' %}
{% if type.name.get() != "device" %}
auto device = self->GetDevice();
{% else %}
@@ -79,7 +79,7 @@
{% endif %}
auto deviceLock(device->GetScopedLock());
{% else %}
- // This method is specified to not use AutoLock in json script.
+ // This method is specified to not use AutoLock in json script or it returns a future.
{% endif %}
{% if method.return_type.name.canonical_case() != "void" %}
diff --git a/src/dawn/dawn.json b/src/dawn/dawn.json
index fe7c864..f158f38 100644
--- a/src/dawn/dawn.json
+++ b/src/dawn/dawn.json
@@ -1443,6 +1443,7 @@
},
{
"name": "pop error scope",
+ "no autolock": true,
"args": [
{"name": "old callback", "type": "error callback"},
{"name": "userdata", "type": "void *"}
diff --git a/src/dawn/native/Buffer.cpp b/src/dawn/native/Buffer.cpp
index 2a86ad1..ec44f26 100644
--- a/src/dawn/native/Buffer.cpp
+++ b/src/dawn/native/Buffer.cpp
@@ -590,40 +590,47 @@
// (note, not raise a validation error to the device) and return the null future.
DAWN_ASSERT(callbackInfo.nextInChain == nullptr);
- // Handle the defaulting of size required by WebGPU, even if in webgpu_cpp.h it is not
- // possible to default the function argument (because there is the callback later in the
- // argument list)
- if ((size == wgpu::kWholeMapSize) && (offset <= mSize)) {
- size = mSize - offset;
- }
-
- auto earlyStatus = [&]() -> std::optional<wgpu::BufferMapAsyncStatus> {
- if (mState == BufferState::PendingMap) {
- return wgpu::BufferMapAsyncStatus::MappingAlreadyPending;
- }
- WGPUBufferMapAsyncStatus status;
- if (GetDevice()->ConsumedError(ValidateMapAsync(mode, offset, size, &status),
- "calling %s.MapAsync(%s, %u, %u, ...).", this, mode, offset,
- size)) {
- return static_cast<wgpu::BufferMapAsyncStatus>(status);
- }
- if (GetDevice()->ConsumedError(MapAsyncImpl(mode, offset, size))) {
- return wgpu::BufferMapAsyncStatus::DeviceLost;
- }
- return std::nullopt;
- }();
-
Ref<EventManager::TrackedEvent> event;
- if (earlyStatus) {
- event = AcquireRef(new MapAsyncEvent(GetDevice(), callbackInfo, *earlyStatus));
- } else {
- mMapMode = mode;
- mMapOffset = offset;
- mMapSize = size;
- mState = BufferState::PendingMap;
- mPendingMapEvent =
- AcquireRef(new MapAsyncEvent(GetDevice(), this, callbackInfo, mLastUsageSerial));
- event = mPendingMapEvent;
+ std::optional<wgpu::BufferMapAsyncStatus> earlyStatus;
+ {
+ // TODO(crbug.com/dawn/831) Manually acquire device lock instead of relying on code-gen for
+ // re-entrancy.
+ auto deviceLock(GetDevice()->GetScopedLock());
+
+ // Handle the defaulting of size required by WebGPU, even if in webgpu_cpp.h it is not
+ // possible to default the function argument (because there is the callback later in the
+ // argument list)
+ if ((size == wgpu::kWholeMapSize) && (offset <= mSize)) {
+ size = mSize - offset;
+ }
+
+ earlyStatus = [&]() -> std::optional<wgpu::BufferMapAsyncStatus> {
+ if (mState == BufferState::PendingMap) {
+ return wgpu::BufferMapAsyncStatus::MappingAlreadyPending;
+ }
+ WGPUBufferMapAsyncStatus status;
+ if (GetDevice()->ConsumedError(ValidateMapAsync(mode, offset, size, &status),
+ "calling %s.MapAsync(%s, %u, %u, ...).", this, mode,
+ offset, size)) {
+ return static_cast<wgpu::BufferMapAsyncStatus>(status);
+ }
+ if (GetDevice()->ConsumedError(MapAsyncImpl(mode, offset, size))) {
+ return wgpu::BufferMapAsyncStatus::DeviceLost;
+ }
+ return std::nullopt;
+ }();
+
+ if (earlyStatus) {
+ event = AcquireRef(new MapAsyncEvent(GetDevice(), callbackInfo, *earlyStatus));
+ } else {
+ mMapMode = mode;
+ mMapOffset = offset;
+ mMapSize = size;
+ mState = BufferState::PendingMap;
+ mPendingMapEvent =
+ AcquireRef(new MapAsyncEvent(GetDevice(), this, callbackInfo, mLastUsageSerial));
+ event = mPendingMapEvent;
+ }
}
FutureID futureID = GetInstance()->GetEventManager()->TrackEvent(std::move(event));
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp
index 93fa3b6..9606b59 100644
--- a/src/dawn/native/Device.cpp
+++ b/src/dawn/native/Device.cpp
@@ -771,10 +771,16 @@
};
std::optional<ErrorScope> scope;
- if (IsLost()) {
- scope = ErrorScope(wgpu::ErrorType::DeviceLost, "GPU device disconnected");
- } else if (!mErrorScopeStack->Empty()) {
- scope = mErrorScopeStack->Pop();
+ {
+ // TODO(crbug.com/dawn/831) Manually acquire device lock instead of relying on code-gen for
+ // re-entrancy.
+ auto deviceLock(GetScopedLock());
+
+ if (IsLost()) {
+ scope = ErrorScope(wgpu::ErrorType::DeviceLost, "GPU device disconnected");
+ } else if (!mErrorScopeStack->Empty()) {
+ scope = mErrorScopeStack->Pop();
+ }
}
FutureID futureID = GetInstance()->GetEventManager()->TrackEvent(
diff --git a/src/dawn/native/Queue.cpp b/src/dawn/native/Queue.cpp
index 98c046d..6610a3c 100644
--- a/src/dawn/native/Queue.cpp
+++ b/src/dawn/native/Queue.cpp
@@ -322,20 +322,25 @@
DAWN_ASSERT(callbackInfo.nextInChain == nullptr);
Ref<EventManager::TrackedEvent> event;
+ {
+ // TODO(crbug.com/dawn/831) Manually acquire device lock instead of relying on code-gen for
+ // re-entrancy.
+ auto deviceLock(GetDevice()->GetScopedLock());
- wgpu::QueueWorkDoneStatus validationEarlyStatus;
- if (GetDevice()->ConsumedError(ValidateOnSubmittedWorkDone(&validationEarlyStatus))) {
- // TODO(crbug.com/dawn/2021): This is here to pretend that things succeed when the device is
- // lost. When the old OnSubmittedWorkDone is removed then we can update
- // ValidateOnSubmittedWorkDone to just return the correct thing here.
- if (validationEarlyStatus == wgpu::QueueWorkDoneStatus::DeviceLost) {
- validationEarlyStatus = wgpu::QueueWorkDoneStatus::Success;
+ wgpu::QueueWorkDoneStatus validationEarlyStatus;
+ if (GetDevice()->ConsumedError(ValidateOnSubmittedWorkDone(&validationEarlyStatus))) {
+ // TODO(crbug.com/dawn/2021): This is here to pretend that things succeed when the
+ // device is lost. When the old OnSubmittedWorkDone is removed then we can update
+ // ValidateOnSubmittedWorkDone to just return the correct thing here.
+ if (validationEarlyStatus == wgpu::QueueWorkDoneStatus::DeviceLost) {
+ validationEarlyStatus = wgpu::QueueWorkDoneStatus::Success;
+ }
+
+ // Note: if the callback is spontaneous, it'll get called in here.
+ event = AcquireRef(new WorkDoneEvent(callbackInfo, this, validationEarlyStatus));
+ } else {
+ event = AcquireRef(new WorkDoneEvent(callbackInfo, this, GetScheduledWorkDoneSerial()));
}
-
- // Note: if the callback is spontaneous, it'll get called in here.
- event = AcquireRef(new WorkDoneEvent(callbackInfo, this, validationEarlyStatus));
- } else {
- event = AcquireRef(new WorkDoneEvent(callbackInfo, this, GetScheduledWorkDoneSerial()));
}
FutureID futureID = GetInstance()->GetEventManager()->TrackEvent(std::move(event));
diff --git a/src/dawn/tests/end2end/BufferTests.cpp b/src/dawn/tests/end2end/BufferTests.cpp
index d057ec6..f7da0de 100644
--- a/src/dawn/tests/end2end/BufferTests.cpp
+++ b/src/dawn/tests/end2end/BufferTests.cpp
@@ -52,12 +52,6 @@
DAWN_TEST_UNSUPPORTED_IF(UsesWire() && GetParam().mFutureCallbackMode &&
*GetParam().mFutureCallbackMode ==
wgpu::CallbackMode::WaitAnyOnly);
-
- // TODO(dawn:2449): These tests are hitting an ASSERT in Mutex.cpp on Windows with the
- // spontaneous callback mode.
- DAWN_SUPPRESS_TEST_IF(IsWindows() && GetParam().mFutureCallbackMode &&
- GetParam().mFutureCallbackMode.value() ==
- wgpu::CallbackMode::AllowSpontaneous);
}
void MapAsyncAndWait(const wgpu::Buffer& buffer,