mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-14 10:33:42 +00:00
This patch implements the asynchronous path of CreateComputePipelineAsync on D3D12 backend with the basic framework of the dawn_unittest AsyncTaskTest.Basic. 1. Call the constructor of dawn_native::d3d12::ComputePipeline in the main thread. 2. Execute dawn_native::ComputePipelineBase::Initialize() (a virtual function) asynchronously. 3. Ensure every operation in dawn_native::d3d12::ComputePipeline::Initialize() is thread-safe (PersistentCache). 4. Save all the return values (pipeline object or error message, userdata, etc) in a CreateComputePipelineAsyncWaitableCallbackTask object and insert this callback task into CallbackTaskManager. 5. In Callback.Finish(): - Insert the pipeline object into the pipeline cache if necessary - Call WGPUCreateComputePipelineAsyncCallback Note that as we always handle the front-end pipeline cache in the main thread, we don't need to make it thread-safe right now. BUG=dawn:529 TEST=dawn_end2end_tests Change-Id: I7eba2ce550b32439a94b2a4d1aa7f1b3383aa514 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/47900 Commit-Queue: Jiawei Shao <jiawei.shao@intel.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
66 lines
2.4 KiB
C++
66 lines
2.4 KiB
C++
#include "dawn_native/AsyncTask.h"
|
|
|
|
#include "dawn_platform/DawnPlatform.h"
|
|
|
|
namespace dawn_native {
|
|
|
|
AsyncTaskManager::AsyncTaskManager(dawn_platform::WorkerTaskPool* workerTaskPool)
|
|
: mWorkerTaskPool(workerTaskPool) {
|
|
}
|
|
|
|
void AsyncTaskManager::PostTask(AsyncTask asyncTask) {
|
|
// If these allocations becomes expensive, we can slab-allocate tasks.
|
|
Ref<WaitableTask> waitableTask = AcquireRef(new WaitableTask());
|
|
waitableTask->taskManager = this;
|
|
waitableTask->asyncTask = std::move(asyncTask);
|
|
|
|
{
|
|
// We insert new waitableTask objects into mPendingTasks in main thread (PostTask()),
|
|
// and we may remove waitableTask objects from mPendingTasks in either main thread
|
|
// (WaitAllPendingTasks()) or sub-thread (TaskCompleted), so mPendingTasks should be
|
|
// protected by a mutex.
|
|
std::lock_guard<std::mutex> lock(mPendingTasksMutex);
|
|
mPendingTasks.emplace(waitableTask.Get(), waitableTask);
|
|
}
|
|
|
|
// Ref the task since it is accessed inside the worker function.
|
|
// The worker function will acquire and release the task upon completion.
|
|
waitableTask->Reference();
|
|
waitableTask->waitableEvent =
|
|
mWorkerTaskPool->PostWorkerTask(DoWaitableTask, waitableTask.Get());
|
|
}
|
|
|
|
void AsyncTaskManager::HandleTaskCompletion(WaitableTask* task) {
|
|
std::lock_guard<std::mutex> lock(mPendingTasksMutex);
|
|
auto iter = mPendingTasks.find(task);
|
|
if (iter != mPendingTasks.end()) {
|
|
mPendingTasks.erase(iter);
|
|
}
|
|
}
|
|
|
|
void AsyncTaskManager::WaitAllPendingTasks() {
|
|
std::unordered_map<WaitableTask*, Ref<WaitableTask>> allPendingTasks;
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(mPendingTasksMutex);
|
|
allPendingTasks.swap(mPendingTasks);
|
|
}
|
|
|
|
for (auto& keyValue : allPendingTasks) {
|
|
keyValue.second->waitableEvent->Wait();
|
|
}
|
|
}
|
|
|
|
bool AsyncTaskManager::HasPendingTasks() {
|
|
std::lock_guard<std::mutex> lock(mPendingTasksMutex);
|
|
return !mPendingTasks.empty();
|
|
}
|
|
|
|
void AsyncTaskManager::DoWaitableTask(void* task) {
|
|
Ref<WaitableTask> waitableTask = AcquireRef(static_cast<WaitableTask*>(task));
|
|
waitableTask->asyncTask();
|
|
waitableTask->taskManager->HandleTaskCompletion(waitableTask.Get());
|
|
}
|
|
|
|
} // namespace dawn_native
|