Implement CallbackTaskManager for Create*PipelineAsync

This patch implements CallbackTask and CallbackTaskManager to store
the callbacks of Create*PipelineAsync().

In the futureCallbackTaskManager will manage all the callbacks that
should be called in Device.Tick().

BUG=dawn:529

Change-Id: I6ad4352371eb44515bc2d85cdc68220c9b758b8e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/49060
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
Jiawei Shao 2021-05-02 03:22:30 +00:00 committed by Commit Bot service account
parent 321c900c6b
commit c74af70378
9 changed files with 209 additions and 174 deletions

View File

@ -184,6 +184,8 @@ source_set("dawn_native_sources") {
"Buffer.h", "Buffer.h",
"CachedObject.cpp", "CachedObject.cpp",
"CachedObject.h", "CachedObject.h",
"CallbackTaskManager.cpp",
"CallbackTaskManager.h",
"CommandAllocator.cpp", "CommandAllocator.cpp",
"CommandAllocator.h", "CommandAllocator.h",
"CommandBuffer.cpp", "CommandBuffer.cpp",
@ -204,8 +206,8 @@ source_set("dawn_native_sources") {
"ComputePipeline.h", "ComputePipeline.h",
"CopyTextureForBrowserHelper.cpp", "CopyTextureForBrowserHelper.cpp",
"CopyTextureForBrowserHelper.h", "CopyTextureForBrowserHelper.h",
"CreatePipelineAsyncTracker.cpp", "CreatePipelineAsyncTask.cpp",
"CreatePipelineAsyncTracker.h", "CreatePipelineAsyncTask.h",
"Device.cpp", "Device.cpp",
"Device.h", "Device.h",
"DynamicUploader.cpp", "DynamicUploader.cpp",

View File

@ -50,6 +50,8 @@ target_sources(dawn_native PRIVATE
"Buffer.h" "Buffer.h"
"CachedObject.cpp" "CachedObject.cpp"
"CachedObject.h" "CachedObject.h"
"CallbackTaskManager.cpp"
"CallbackTaskManager.h"
"CommandAllocator.cpp" "CommandAllocator.cpp"
"CommandAllocator.h" "CommandAllocator.h"
"CommandBuffer.cpp" "CommandBuffer.cpp"
@ -70,8 +72,8 @@ target_sources(dawn_native PRIVATE
"ComputePipeline.h" "ComputePipeline.h"
"CopyTextureForBrowserHelper.cpp" "CopyTextureForBrowserHelper.cpp"
"CopyTextureForBrowserHelper.h" "CopyTextureForBrowserHelper.h"
"CreatePipelineAsyncTracker.cpp" "CreatePipelineAsyncTask.cpp"
"CreatePipelineAsyncTracker.h" "CreatePipelineAsyncTask.h"
"Device.cpp" "Device.cpp"
"Device.h" "Device.h"
"DynamicUploader.cpp" "DynamicUploader.cpp"

View File

@ -0,0 +1,37 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_native/CallbackTaskManager.h"
namespace dawn_native {
bool CallbackTaskManager::IsEmpty() {
std::lock_guard<std::mutex> lock(mCallbackTaskQueueMutex);
return mCallbackTaskQueue.empty();
}
std::vector<std::unique_ptr<CallbackTask>> CallbackTaskManager::AcquireCallbackTasks() {
std::lock_guard<std::mutex> lock(mCallbackTaskQueueMutex);
std::vector<std::unique_ptr<CallbackTask>> allTasks;
allTasks.swap(mCallbackTaskQueue);
return allTasks;
}
void CallbackTaskManager::AddCallbackTask(std::unique_ptr<CallbackTask> callbackTask) {
std::lock_guard<std::mutex> lock(mCallbackTaskQueueMutex);
mCallbackTaskQueue.push_back(std::move(callbackTask));
}
} // namespace dawn_native

View File

@ -0,0 +1,47 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNNATIVE_CALLBACK_TASK_MANAGER_H_
#define DAWNNATIVE_CALLBACK_TASK_MANAGER_H_
#include <memory>
#include <mutex>
#include <vector>
namespace dawn_native {
class CallbackTaskManager;
struct CallbackTask {
public:
virtual ~CallbackTask() = default;
virtual void Finish() = 0;
virtual void HandleShutDown() = 0;
virtual void HandleDeviceLoss() = 0;
};
class CallbackTaskManager {
public:
void AddCallbackTask(std::unique_ptr<CallbackTask> callbackTask);
bool IsEmpty();
std::vector<std::unique_ptr<CallbackTask>> AcquireCallbackTasks();
private:
std::mutex mCallbackTaskQueueMutex;
std::vector<std::unique_ptr<CallbackTask>> mCallbackTaskQueue;
};
} // namespace dawn_native
#endif

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "dawn_native/CreatePipelineAsyncTracker.h" #include "dawn_native/CreatePipelineAsyncTask.h"
#include "dawn_native/ComputePipeline.h" #include "dawn_native/ComputePipeline.h"
#include "dawn_native/Device.h" #include "dawn_native/Device.h"
@ -20,25 +20,23 @@
namespace dawn_native { namespace dawn_native {
CreatePipelineAsyncTaskBase::CreatePipelineAsyncTaskBase(std::string errorMessage, CreatePipelineAsyncCallbackTaskBase::CreatePipelineAsyncCallbackTaskBase(
std::string errorMessage,
void* userdata) void* userdata)
: mErrorMessage(errorMessage), mUserData(userdata) { : mErrorMessage(errorMessage), mUserData(userdata) {
} }
CreatePipelineAsyncTaskBase::~CreatePipelineAsyncTaskBase() { CreateComputePipelineAsyncCallbackTask::CreateComputePipelineAsyncCallbackTask(
}
CreateComputePipelineAsyncTask::CreateComputePipelineAsyncTask(
Ref<ComputePipelineBase> pipeline, Ref<ComputePipelineBase> pipeline,
std::string errorMessage, std::string errorMessage,
WGPUCreateComputePipelineAsyncCallback callback, WGPUCreateComputePipelineAsyncCallback callback,
void* userdata) void* userdata)
: CreatePipelineAsyncTaskBase(errorMessage, userdata), : CreatePipelineAsyncCallbackTaskBase(errorMessage, userdata),
mPipeline(std::move(pipeline)), mPipeline(std::move(pipeline)),
mCreateComputePipelineAsyncCallback(callback) { mCreateComputePipelineAsyncCallback(callback) {
} }
void CreateComputePipelineAsyncTask::Finish() { void CreateComputePipelineAsyncCallbackTask::Finish() {
ASSERT(mCreateComputePipelineAsyncCallback != nullptr); ASSERT(mCreateComputePipelineAsyncCallback != nullptr);
if (mPipeline.Get() != nullptr) { if (mPipeline.Get() != nullptr) {
@ -51,31 +49,31 @@ namespace dawn_native {
} }
} }
void CreateComputePipelineAsyncTask::HandleShutDown() { void CreateComputePipelineAsyncCallbackTask::HandleShutDown() {
ASSERT(mCreateComputePipelineAsyncCallback != nullptr); ASSERT(mCreateComputePipelineAsyncCallback != nullptr);
mCreateComputePipelineAsyncCallback(WGPUCreatePipelineAsyncStatus_DeviceDestroyed, nullptr, mCreateComputePipelineAsyncCallback(WGPUCreatePipelineAsyncStatus_DeviceDestroyed, nullptr,
"Device destroyed before callback", mUserData); "Device destroyed before callback", mUserData);
} }
void CreateComputePipelineAsyncTask::HandleDeviceLoss() { void CreateComputePipelineAsyncCallbackTask::HandleDeviceLoss() {
ASSERT(mCreateComputePipelineAsyncCallback != nullptr); ASSERT(mCreateComputePipelineAsyncCallback != nullptr);
mCreateComputePipelineAsyncCallback(WGPUCreatePipelineAsyncStatus_DeviceLost, nullptr, mCreateComputePipelineAsyncCallback(WGPUCreatePipelineAsyncStatus_DeviceLost, nullptr,
"Device lost before callback", mUserData); "Device lost before callback", mUserData);
} }
CreateRenderPipelineAsyncTask::CreateRenderPipelineAsyncTask( CreateRenderPipelineAsyncCallbackTask::CreateRenderPipelineAsyncCallbackTask(
Ref<RenderPipelineBase> pipeline, Ref<RenderPipelineBase> pipeline,
std::string errorMessage, std::string errorMessage,
WGPUCreateRenderPipelineAsyncCallback callback, WGPUCreateRenderPipelineAsyncCallback callback,
void* userdata) void* userdata)
: CreatePipelineAsyncTaskBase(errorMessage, userdata), : CreatePipelineAsyncCallbackTaskBase(errorMessage, userdata),
mPipeline(std::move(pipeline)), mPipeline(std::move(pipeline)),
mCreateRenderPipelineAsyncCallback(callback) { mCreateRenderPipelineAsyncCallback(callback) {
} }
void CreateRenderPipelineAsyncTask::Finish() { void CreateRenderPipelineAsyncCallbackTask::Finish() {
ASSERT(mCreateRenderPipelineAsyncCallback != nullptr); ASSERT(mCreateRenderPipelineAsyncCallback != nullptr);
if (mPipeline.Get() != nullptr) { if (mPipeline.Get() != nullptr) {
@ -88,62 +86,18 @@ namespace dawn_native {
} }
} }
void CreateRenderPipelineAsyncTask::HandleShutDown() { void CreateRenderPipelineAsyncCallbackTask::HandleShutDown() {
ASSERT(mCreateRenderPipelineAsyncCallback != nullptr); ASSERT(mCreateRenderPipelineAsyncCallback != nullptr);
mCreateRenderPipelineAsyncCallback(WGPUCreatePipelineAsyncStatus_DeviceDestroyed, nullptr, mCreateRenderPipelineAsyncCallback(WGPUCreatePipelineAsyncStatus_DeviceDestroyed, nullptr,
"Device destroyed before callback", mUserData); "Device destroyed before callback", mUserData);
} }
void CreateRenderPipelineAsyncTask::HandleDeviceLoss() { void CreateRenderPipelineAsyncCallbackTask::HandleDeviceLoss() {
ASSERT(mCreateRenderPipelineAsyncCallback != nullptr); ASSERT(mCreateRenderPipelineAsyncCallback != nullptr);
mCreateRenderPipelineAsyncCallback(WGPUCreatePipelineAsyncStatus_DeviceLost, nullptr, mCreateRenderPipelineAsyncCallback(WGPUCreatePipelineAsyncStatus_DeviceLost, nullptr,
"Device lost before callback", mUserData); "Device lost before callback", mUserData);
} }
CreatePipelineAsyncTracker::CreatePipelineAsyncTracker(DeviceBase* device) : mDevice(device) {
}
CreatePipelineAsyncTracker::~CreatePipelineAsyncTracker() {
ASSERT(mCreatePipelineAsyncTasksInFlight.Empty());
}
void CreatePipelineAsyncTracker::TrackTask(std::unique_ptr<CreatePipelineAsyncTaskBase> task,
ExecutionSerial serial) {
mCreatePipelineAsyncTasksInFlight.Enqueue(std::move(task), serial);
mDevice->AddFutureSerial(serial);
}
void CreatePipelineAsyncTracker::Tick(ExecutionSerial finishedSerial) {
// If a user calls Queue::Submit inside Create*PipelineAsync, then the device will be
// ticked, which in turns ticks the tracker, causing reentrance here. To prevent the
// reentrant call from invalidating mCreatePipelineAsyncTasksInFlight while in use by the
// first call, we remove the tasks to finish from the queue, update
// mCreatePipelineAsyncTasksInFlight, then run the callbacks.
std::vector<std::unique_ptr<CreatePipelineAsyncTaskBase>> tasks;
for (auto& task : mCreatePipelineAsyncTasksInFlight.IterateUpTo(finishedSerial)) {
tasks.push_back(std::move(task));
}
mCreatePipelineAsyncTasksInFlight.ClearUpTo(finishedSerial);
for (auto& task : tasks) {
task->Finish();
}
}
void CreatePipelineAsyncTracker::ClearForShutDown() {
for (auto& task : mCreatePipelineAsyncTasksInFlight.IterateAll()) {
task->HandleShutDown();
}
mCreatePipelineAsyncTasksInFlight.Clear();
}
void CreatePipelineAsyncTracker::ClearForDeviceLoss() {
for (auto& task : mCreatePipelineAsyncTasksInFlight.IterateAll()) {
task->HandleDeviceLoss();
}
mCreatePipelineAsyncTasksInFlight.Clear();
}
} // namespace dawn_native } // namespace dawn_native

View File

@ -0,0 +1,68 @@
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNNATIVE_CREATEPIPELINEASYNCTASK_H_
#define DAWNNATIVE_CREATEPIPELINEASYNCTASK_H_
#include "common/RefCounted.h"
#include "dawn/webgpu.h"
#include "dawn_native/CallbackTaskManager.h"
namespace dawn_native {
class ComputePipelineBase;
class DeviceBase;
class RenderPipelineBase;
struct CreatePipelineAsyncCallbackTaskBase : CallbackTask {
CreatePipelineAsyncCallbackTaskBase(std::string errorMessage, void* userData);
protected:
std::string mErrorMessage;
void* mUserData;
};
struct CreateComputePipelineAsyncCallbackTask final : CreatePipelineAsyncCallbackTaskBase {
CreateComputePipelineAsyncCallbackTask(Ref<ComputePipelineBase> pipeline,
std::string errorMessage,
WGPUCreateComputePipelineAsyncCallback callback,
void* userdata);
void Finish() final;
void HandleShutDown() final;
void HandleDeviceLoss() final;
private:
Ref<ComputePipelineBase> mPipeline;
WGPUCreateComputePipelineAsyncCallback mCreateComputePipelineAsyncCallback;
};
struct CreateRenderPipelineAsyncCallbackTask final : CreatePipelineAsyncCallbackTaskBase {
CreateRenderPipelineAsyncCallbackTask(Ref<RenderPipelineBase> pipeline,
std::string errorMessage,
WGPUCreateRenderPipelineAsyncCallback callback,
void* userdata);
void Finish() final;
void HandleShutDown() final;
void HandleDeviceLoss() final;
private:
Ref<RenderPipelineBase> mPipeline;
WGPUCreateRenderPipelineAsyncCallback mCreateRenderPipelineAsyncCallback;
};
} // namespace dawn_native
#endif // DAWNNATIVE_CREATEPIPELINEASYNCTASK_H_

View File

@ -1,93 +0,0 @@
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNNATIVE_CREATEPIPELINEASYNCTRACKER_H_
#define DAWNNATIVE_CREATEPIPELINEASYNCTRACKER_H_
#include "common/RefCounted.h"
#include "common/SerialQueue.h"
#include "dawn/webgpu.h"
#include "dawn_native/IntegerTypes.h"
#include <memory>
#include <string>
namespace dawn_native {
class ComputePipelineBase;
class DeviceBase;
class RenderPipelineBase;
struct CreatePipelineAsyncTaskBase {
CreatePipelineAsyncTaskBase(std::string errorMessage, void* userData);
virtual ~CreatePipelineAsyncTaskBase();
virtual void Finish() = 0;
virtual void HandleShutDown() = 0;
virtual void HandleDeviceLoss() = 0;
protected:
std::string mErrorMessage;
void* mUserData;
};
struct CreateComputePipelineAsyncTask final : public CreatePipelineAsyncTaskBase {
CreateComputePipelineAsyncTask(Ref<ComputePipelineBase> pipeline,
std::string errorMessage,
WGPUCreateComputePipelineAsyncCallback callback,
void* userdata);
void Finish() final;
void HandleShutDown() final;
void HandleDeviceLoss() final;
private:
Ref<ComputePipelineBase> mPipeline;
WGPUCreateComputePipelineAsyncCallback mCreateComputePipelineAsyncCallback;
};
struct CreateRenderPipelineAsyncTask final : public CreatePipelineAsyncTaskBase {
CreateRenderPipelineAsyncTask(Ref<RenderPipelineBase> pipeline,
std::string errorMessage,
WGPUCreateRenderPipelineAsyncCallback callback,
void* userdata);
void Finish() final;
void HandleShutDown() final;
void HandleDeviceLoss() final;
private:
Ref<RenderPipelineBase> mPipeline;
WGPUCreateRenderPipelineAsyncCallback mCreateRenderPipelineAsyncCallback;
};
class CreatePipelineAsyncTracker {
public:
explicit CreatePipelineAsyncTracker(DeviceBase* device);
~CreatePipelineAsyncTracker();
void TrackTask(std::unique_ptr<CreatePipelineAsyncTaskBase> task, ExecutionSerial serial);
void Tick(ExecutionSerial finishedSerial);
void ClearForShutDown();
void ClearForDeviceLoss();
private:
DeviceBase* mDevice;
SerialQueue<ExecutionSerial, std::unique_ptr<CreatePipelineAsyncTaskBase>>
mCreatePipelineAsyncTasksInFlight;
};
} // namespace dawn_native
#endif // DAWNNATIVE_CREATEPIPELINEASYNCTRACKER_H_

View File

@ -20,11 +20,12 @@
#include "dawn_native/BindGroup.h" #include "dawn_native/BindGroup.h"
#include "dawn_native/BindGroupLayout.h" #include "dawn_native/BindGroupLayout.h"
#include "dawn_native/Buffer.h" #include "dawn_native/Buffer.h"
#include "dawn_native/CallbackTaskManager.h"
#include "dawn_native/CommandBuffer.h" #include "dawn_native/CommandBuffer.h"
#include "dawn_native/CommandEncoder.h" #include "dawn_native/CommandEncoder.h"
#include "dawn_native/CompilationMessages.h" #include "dawn_native/CompilationMessages.h"
#include "dawn_native/ComputePipeline.h" #include "dawn_native/ComputePipeline.h"
#include "dawn_native/CreatePipelineAsyncTracker.h" #include "dawn_native/CreatePipelineAsyncTask.h"
#include "dawn_native/DynamicUploader.h" #include "dawn_native/DynamicUploader.h"
#include "dawn_native/ErrorData.h" #include "dawn_native/ErrorData.h"
#include "dawn_native/ErrorScope.h" #include "dawn_native/ErrorScope.h"
@ -125,7 +126,7 @@ namespace dawn_native {
mCaches = std::make_unique<DeviceBase::Caches>(); mCaches = std::make_unique<DeviceBase::Caches>();
mErrorScopeStack = std::make_unique<ErrorScopeStack>(); mErrorScopeStack = std::make_unique<ErrorScopeStack>();
mDynamicUploader = std::make_unique<DynamicUploader>(this); mDynamicUploader = std::make_unique<DynamicUploader>(this);
mCreatePipelineAsyncTracker = std::make_unique<CreatePipelineAsyncTracker>(this); mCallbackTaskManager = std::make_unique<CallbackTaskManager>();
mDeprecationWarnings = std::make_unique<DeprecationWarnings>(); mDeprecationWarnings = std::make_unique<DeprecationWarnings>();
mInternalPipelineStore = std::make_unique<InternalPipelineStore>(); mInternalPipelineStore = std::make_unique<InternalPipelineStore>();
mPersistentCache = std::make_unique<PersistentCache>(this); mPersistentCache = std::make_unique<PersistentCache>(this);
@ -142,8 +143,11 @@ namespace dawn_native {
void DeviceBase::ShutDownBase() { void DeviceBase::ShutDownBase() {
// Skip handling device facilities if they haven't even been created (or failed doing so) // Skip handling device facilities if they haven't even been created (or failed doing so)
if (mState != State::BeingCreated) { if (mState != State::BeingCreated) {
// Reject all async pipeline creations. // Call all the callbacks immediately as the device is about to shut down.
mCreatePipelineAsyncTracker->ClearForShutDown(); auto callbackTasks = mCallbackTaskManager->AcquireCallbackTasks();
for (std::unique_ptr<CallbackTask>& callbackTask : callbackTasks) {
callbackTask->HandleShutDown();
}
} }
// Disconnect the device, depending on which state we are currently in. // Disconnect the device, depending on which state we are currently in.
@ -188,7 +192,7 @@ namespace dawn_native {
mState = State::Disconnected; mState = State::Disconnected;
mDynamicUploader = nullptr; mDynamicUploader = nullptr;
mCreatePipelineAsyncTracker = nullptr; mCallbackTaskManager = nullptr;
mPersistentCache = nullptr; mPersistentCache = nullptr;
mEmptyBindGroupLayout = nullptr; mEmptyBindGroupLayout = nullptr;
@ -238,7 +242,10 @@ namespace dawn_native {
} }
mQueue->HandleDeviceLoss(); mQueue->HandleDeviceLoss();
mCreatePipelineAsyncTracker->ClearForDeviceLoss(); auto callbackTasks = mCallbackTaskManager->AcquireCallbackTasks();
for (std::unique_ptr<CallbackTask>& callbackTask : callbackTasks) {
callbackTask->HandleDeviceLoss();
}
// Still forward device loss errors to the error scopes so they all reject. // Still forward device loss errors to the error scopes so they all reject.
mErrorScopeStack->HandleError(ToWGPUErrorType(type), message); mErrorScopeStack->HandleError(ToWGPUErrorType(type), message);
@ -766,10 +773,10 @@ namespace dawn_native {
} }
Ref<RenderPipelineBase> result = maybeResult.AcquireSuccess(); Ref<RenderPipelineBase> result = maybeResult.AcquireSuccess();
std::unique_ptr<CreateRenderPipelineAsyncTask> request = std::unique_ptr<CreateRenderPipelineAsyncCallbackTask> callbackTask =
std::make_unique<CreateRenderPipelineAsyncTask>(std::move(result), "", callback, std::make_unique<CreateRenderPipelineAsyncCallbackTask>(std::move(result), "", callback,
userdata); userdata);
mCreatePipelineAsyncTracker->TrackTask(std::move(request), GetPendingCommandSerial()); mCallbackTaskManager->AddCallbackTask(std::move(callbackTask));
} }
RenderBundleEncoder* DeviceBase::APICreateRenderBundleEncoder( RenderBundleEncoder* DeviceBase::APICreateRenderBundleEncoder(
const RenderBundleEncoderDescriptor* descriptor) { const RenderBundleEncoderDescriptor* descriptor) {
@ -951,8 +958,19 @@ namespace dawn_native {
// reclaiming resources one tick earlier. // reclaiming resources one tick earlier.
mDynamicUploader->Deallocate(mCompletedSerial); mDynamicUploader->Deallocate(mCompletedSerial);
mQueue->Tick(mCompletedSerial); mQueue->Tick(mCompletedSerial);
}
mCreatePipelineAsyncTracker->Tick(mCompletedSerial); // We have to check mCallbackTaskManager in every Tick because it is not related to any
// global serials.
if (!mCallbackTaskManager->IsEmpty()) {
// If a user calls Queue::Submit inside the callback, then the device will be ticked,
// which in turns ticks the tracker, causing reentrance and dead lock here. To prevent
// such reentrant call, we remove all the callback tasks from mCallbackTaskManager,
// update mCallbackTaskManager, then call all the callbacks.
auto callbackTasks = mCallbackTaskManager->AcquireCallbackTasks();
for (std::unique_ptr<CallbackTask>& callbackTask : callbackTasks) {
callbackTask->Finish();
}
} }
return {}; return {};
@ -1158,10 +1176,10 @@ namespace dawn_native {
result = AddOrGetCachedPipeline(resultOrError.AcquireSuccess(), blueprintHash); result = AddOrGetCachedPipeline(resultOrError.AcquireSuccess(), blueprintHash);
} }
std::unique_ptr<CreateComputePipelineAsyncTask> request = std::unique_ptr<CreateComputePipelineAsyncCallbackTask> callbackTask =
std::make_unique<CreateComputePipelineAsyncTask>(result, errorMessage, callback, std::make_unique<CreateComputePipelineAsyncCallbackTask>(
userdata); std::move(result), errorMessage, callback, userdata);
mCreatePipelineAsyncTracker->TrackTask(std::move(request), GetPendingCommandSerial()); mCallbackTaskManager->AddCallbackTask(std::move(callbackTask));
} }
ResultOrError<Ref<PipelineLayoutBase>> DeviceBase::CreatePipelineLayout( ResultOrError<Ref<PipelineLayoutBase>> DeviceBase::CreatePipelineLayout(

View File

@ -34,7 +34,7 @@ namespace dawn_native {
class AttachmentState; class AttachmentState;
class AttachmentStateBlueprint; class AttachmentStateBlueprint;
class BindGroupLayoutBase; class BindGroupLayoutBase;
class CreatePipelineAsyncTracker; class CallbackTaskManager;
class DynamicUploader; class DynamicUploader;
class ErrorScopeStack; class ErrorScopeStack;
class ExternalTextureBase; class ExternalTextureBase;
@ -402,7 +402,7 @@ namespace dawn_native {
Ref<BindGroupLayoutBase> mEmptyBindGroupLayout; Ref<BindGroupLayoutBase> mEmptyBindGroupLayout;
std::unique_ptr<DynamicUploader> mDynamicUploader; std::unique_ptr<DynamicUploader> mDynamicUploader;
std::unique_ptr<CreatePipelineAsyncTracker> mCreatePipelineAsyncTracker; std::unique_ptr<CallbackTaskManager> mCallbackTaskManager;
Ref<QueueBase> mQueue; Ref<QueueBase> mQueue;
struct DeprecationWarnings; struct DeprecationWarnings;