mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-15 03:41:34 +00:00
Refactor APICreateRenderPipelineAsync to support sync and async path
This patch refactors the implementation of APICreateRenderPipelineAsync as a preparation of the async path of the creation of render pipeline. Now the code path of APICreateRenderPipelineAsync() includes the following 3 parts: - When an error occurs in the front-end validations, the callback will be called at once in the main thread. - When we can find a proper render pipeline object in the cache, the callback will be called at once in the main thread. - When we cannot find the proper render pipeline object in the cache, the newly-created pipeline object, the callback and userdata will be saved into the CreatePipelineAsyncTracker, and the callback will be called in device.Tick(). All the logic mentioned in this section has been put into one function CreateRenderPipelineAsyncImpl(), which will be overridden by its asynchronous version on all the backends that support creating pipeline objects asynchronously. BUG=dawn:529 TEST=dawn_end2end_tests Change-Id: I5706224092588a8c042a952aef2591696072592d Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/62781 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:
parent
6fa34f80bd
commit
2aee6eef7f
@ -575,7 +575,23 @@ namespace dawn_native {
|
|||||||
return std::make_pair(result, blueprintHash);
|
return std::make_pair(result, blueprintHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<ComputePipelineBase> DeviceBase::AddOrGetCachedPipeline(
|
std::pair<Ref<RenderPipelineBase>, size_t> DeviceBase::GetCachedRenderPipeline(
|
||||||
|
const RenderPipelineDescriptor* descriptor) {
|
||||||
|
RenderPipelineBase blueprint(this, descriptor);
|
||||||
|
|
||||||
|
const size_t blueprintHash = blueprint.ComputeContentHash();
|
||||||
|
blueprint.SetContentHash(blueprintHash);
|
||||||
|
|
||||||
|
Ref<RenderPipelineBase> result;
|
||||||
|
auto iter = mCaches->renderPipelines.find(&blueprint);
|
||||||
|
if (iter != mCaches->renderPipelines.end()) {
|
||||||
|
result = *iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair(result, blueprintHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<ComputePipelineBase> DeviceBase::AddOrGetCachedComputePipeline(
|
||||||
Ref<ComputePipelineBase> computePipeline,
|
Ref<ComputePipelineBase> computePipeline,
|
||||||
size_t blueprintHash) {
|
size_t blueprintHash) {
|
||||||
computePipeline->SetContentHash(blueprintHash);
|
computePipeline->SetContentHash(blueprintHash);
|
||||||
@ -588,6 +604,19 @@ namespace dawn_native {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ref<RenderPipelineBase> DeviceBase::AddOrGetCachedRenderPipeline(
|
||||||
|
Ref<RenderPipelineBase> renderPipeline,
|
||||||
|
size_t blueprintHash) {
|
||||||
|
renderPipeline->SetContentHash(blueprintHash);
|
||||||
|
auto insertion = mCaches->renderPipelines.insert(renderPipeline.Get());
|
||||||
|
if (insertion.second) {
|
||||||
|
renderPipeline->SetIsCachedReference();
|
||||||
|
return renderPipeline;
|
||||||
|
} else {
|
||||||
|
return *(insertion.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DeviceBase::UncacheComputePipeline(ComputePipelineBase* obj) {
|
void DeviceBase::UncacheComputePipeline(ComputePipelineBase* obj) {
|
||||||
ASSERT(obj->IsCachedReference());
|
ASSERT(obj->IsCachedReference());
|
||||||
size_t removedCount = mCaches->computePipelines.erase(obj);
|
size_t removedCount = mCaches->computePipelines.erase(obj);
|
||||||
@ -829,19 +858,16 @@ namespace dawn_native {
|
|||||||
void DeviceBase::APICreateRenderPipelineAsync(const RenderPipelineDescriptor* descriptor,
|
void DeviceBase::APICreateRenderPipelineAsync(const RenderPipelineDescriptor* descriptor,
|
||||||
WGPUCreateRenderPipelineAsyncCallback callback,
|
WGPUCreateRenderPipelineAsyncCallback callback,
|
||||||
void* userdata) {
|
void* userdata) {
|
||||||
ResultOrError<Ref<RenderPipelineBase>> maybeResult = CreateRenderPipeline(descriptor);
|
MaybeError maybeResult = CreateRenderPipelineAsync(descriptor, callback, userdata);
|
||||||
|
|
||||||
|
// Call the callback directly when a validation error has been found in the front-end
|
||||||
|
// validations. If there is no error, then CreateRenderPipelineAsync will call the
|
||||||
|
// callback.
|
||||||
if (maybeResult.IsError()) {
|
if (maybeResult.IsError()) {
|
||||||
std::unique_ptr<ErrorData> error = maybeResult.AcquireError();
|
std::unique_ptr<ErrorData> error = maybeResult.AcquireError();
|
||||||
callback(WGPUCreatePipelineAsyncStatus_Error, nullptr, error->GetMessage().c_str(),
|
callback(WGPUCreatePipelineAsyncStatus_Error, nullptr, error->GetMessage().c_str(),
|
||||||
userdata);
|
userdata);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<RenderPipelineBase> result = maybeResult.AcquireSuccess();
|
|
||||||
std::unique_ptr<CreateRenderPipelineAsyncCallbackTask> callbackTask =
|
|
||||||
std::make_unique<CreateRenderPipelineAsyncCallbackTask>(std::move(result), "", callback,
|
|
||||||
userdata);
|
|
||||||
mCallbackTaskManager->AddCallbackTask(std::move(callbackTask));
|
|
||||||
}
|
}
|
||||||
RenderBundleEncoder* DeviceBase::APICreateRenderBundleEncoder(
|
RenderBundleEncoder* DeviceBase::APICreateRenderBundleEncoder(
|
||||||
const RenderBundleEncoderDescriptor* descriptor) {
|
const RenderBundleEncoderDescriptor* descriptor) {
|
||||||
@ -1093,7 +1119,7 @@ namespace dawn_native {
|
|||||||
Ref<ComputePipelineBase> backendObj;
|
Ref<ComputePipelineBase> backendObj;
|
||||||
DAWN_TRY_ASSIGN(backendObj, CreateComputePipelineImpl(&appliedDescriptor));
|
DAWN_TRY_ASSIGN(backendObj, CreateComputePipelineImpl(&appliedDescriptor));
|
||||||
size_t blueprintHash = pipelineAndBlueprintFromCache.second;
|
size_t blueprintHash = pipelineAndBlueprintFromCache.second;
|
||||||
return AddOrGetCachedPipeline(backendObj, blueprintHash);
|
return AddOrGetCachedComputePipeline(backendObj, blueprintHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError DeviceBase::CreateComputePipelineAsync(
|
MaybeError DeviceBase::CreateComputePipelineAsync(
|
||||||
@ -1153,6 +1179,24 @@ namespace dawn_native {
|
|||||||
return layoutRef;
|
return layoutRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResultOrError<Ref<PipelineLayoutBase>>
|
||||||
|
DeviceBase::ValidateAndGetRenderPipelineDescriptorWithDefaults(
|
||||||
|
const RenderPipelineDescriptor& descriptor,
|
||||||
|
RenderPipelineDescriptor* outDescriptor) {
|
||||||
|
Ref<PipelineLayoutBase> layoutRef;
|
||||||
|
*outDescriptor = descriptor;
|
||||||
|
|
||||||
|
if (descriptor.layout == nullptr) {
|
||||||
|
// Ref will keep the pipeline layout alive until the end of the function where
|
||||||
|
// the pipeline will take another reference.
|
||||||
|
DAWN_TRY_ASSIGN(layoutRef,
|
||||||
|
PipelineLayoutBase::CreateDefault(this, GetStages(&descriptor)));
|
||||||
|
outDescriptor->layout = layoutRef.Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return layoutRef;
|
||||||
|
}
|
||||||
|
|
||||||
// This function is overwritten with the async version on the backends
|
// This function is overwritten with the async version on the backends
|
||||||
// that supports creating compute pipeline asynchronously
|
// that supports creating compute pipeline asynchronously
|
||||||
void DeviceBase::CreateComputePipelineAsyncImpl(const ComputePipelineDescriptor* descriptor,
|
void DeviceBase::CreateComputePipelineAsyncImpl(const ComputePipelineDescriptor* descriptor,
|
||||||
@ -1167,7 +1211,7 @@ namespace dawn_native {
|
|||||||
std::unique_ptr<ErrorData> error = resultOrError.AcquireError();
|
std::unique_ptr<ErrorData> error = resultOrError.AcquireError();
|
||||||
errorMessage = error->GetMessage();
|
errorMessage = error->GetMessage();
|
||||||
} else {
|
} else {
|
||||||
result = AddOrGetCachedPipeline(resultOrError.AcquireSuccess(), blueprintHash);
|
result = AddOrGetCachedComputePipeline(resultOrError.AcquireSuccess(), blueprintHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<CreateComputePipelineAsyncCallbackTask> callbackTask =
|
std::unique_ptr<CreateComputePipelineAsyncCallbackTask> callbackTask =
|
||||||
@ -1176,6 +1220,29 @@ namespace dawn_native {
|
|||||||
mCallbackTaskManager->AddCallbackTask(std::move(callbackTask));
|
mCallbackTaskManager->AddCallbackTask(std::move(callbackTask));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function is overwritten with the async version on the backends
|
||||||
|
// that supports creating render pipeline asynchronously
|
||||||
|
void DeviceBase::CreateRenderPipelineAsyncImpl(const RenderPipelineDescriptor* descriptor,
|
||||||
|
size_t blueprintHash,
|
||||||
|
WGPUCreateRenderPipelineAsyncCallback callback,
|
||||||
|
void* userdata) {
|
||||||
|
Ref<RenderPipelineBase> result;
|
||||||
|
std::string errorMessage;
|
||||||
|
|
||||||
|
auto resultOrError = CreateRenderPipelineImpl(descriptor);
|
||||||
|
if (resultOrError.IsError()) {
|
||||||
|
std::unique_ptr<ErrorData> error = resultOrError.AcquireError();
|
||||||
|
errorMessage = error->GetMessage();
|
||||||
|
} else {
|
||||||
|
result = AddOrGetCachedRenderPipeline(resultOrError.AcquireSuccess(), blueprintHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<CreateRenderPipelineAsyncCallbackTask> callbackTask =
|
||||||
|
std::make_unique<CreateRenderPipelineAsyncCallbackTask>(std::move(result), errorMessage,
|
||||||
|
callback, userdata);
|
||||||
|
mCallbackTaskManager->AddCallbackTask(std::move(callbackTask));
|
||||||
|
}
|
||||||
|
|
||||||
ResultOrError<Ref<PipelineLayoutBase>> DeviceBase::CreatePipelineLayout(
|
ResultOrError<Ref<PipelineLayoutBase>> DeviceBase::CreatePipelineLayout(
|
||||||
const PipelineLayoutDescriptor* descriptor) {
|
const PipelineLayoutDescriptor* descriptor) {
|
||||||
DAWN_TRY(ValidateIsAlive());
|
DAWN_TRY(ValidateIsAlive());
|
||||||
@ -1235,6 +1302,38 @@ namespace dawn_native {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeError DeviceBase::CreateRenderPipelineAsync(const RenderPipelineDescriptor* descriptor,
|
||||||
|
WGPUCreateRenderPipelineAsyncCallback callback,
|
||||||
|
void* userdata) {
|
||||||
|
DAWN_TRY(ValidateIsAlive());
|
||||||
|
if (IsValidationEnabled()) {
|
||||||
|
DAWN_TRY(ValidateRenderPipelineDescriptor(this, descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ref will keep the pipeline layout alive until the end of the function where
|
||||||
|
// the pipeline will take another reference.
|
||||||
|
Ref<PipelineLayoutBase> layoutRef;
|
||||||
|
RenderPipelineDescriptor appliedDescriptor;
|
||||||
|
DAWN_TRY_ASSIGN(layoutRef, ValidateAndGetRenderPipelineDescriptorWithDefaults(
|
||||||
|
*descriptor, &appliedDescriptor));
|
||||||
|
|
||||||
|
// Call the callback directly when we can get a cached render pipeline object.
|
||||||
|
auto pipelineAndBlueprintFromCache = GetCachedRenderPipeline(&appliedDescriptor);
|
||||||
|
if (pipelineAndBlueprintFromCache.first.Get() != nullptr) {
|
||||||
|
Ref<RenderPipelineBase> result = std::move(pipelineAndBlueprintFromCache.first);
|
||||||
|
callback(WGPUCreatePipelineAsyncStatus_Success,
|
||||||
|
reinterpret_cast<WGPURenderPipeline>(result.Detach()), "", userdata);
|
||||||
|
} else {
|
||||||
|
// Otherwise we will create the pipeline object in CreateRenderPipelineAsyncImpl(),
|
||||||
|
// where the pipeline object may be created asynchronously and the result will be saved
|
||||||
|
// to mCreatePipelineAsyncTracker.
|
||||||
|
const size_t blueprintHash = pipelineAndBlueprintFromCache.second;
|
||||||
|
CreateRenderPipelineAsyncImpl(&appliedDescriptor, blueprintHash, callback, userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
ResultOrError<Ref<SamplerBase>> DeviceBase::CreateSampler(const SamplerDescriptor* descriptor) {
|
ResultOrError<Ref<SamplerBase>> DeviceBase::CreateSampler(const SamplerDescriptor* descriptor) {
|
||||||
const SamplerDescriptor defaultDescriptor = {};
|
const SamplerDescriptor defaultDescriptor = {};
|
||||||
DAWN_TRY(ValidateIsAlive());
|
DAWN_TRY(ValidateIsAlive());
|
||||||
@ -1401,7 +1500,7 @@ namespace dawn_native {
|
|||||||
void* userdata,
|
void* userdata,
|
||||||
size_t blueprintHash) {
|
size_t blueprintHash) {
|
||||||
// CreateComputePipelineAsyncWaitableCallbackTask is declared as an internal class as it
|
// CreateComputePipelineAsyncWaitableCallbackTask is declared as an internal class as it
|
||||||
// needs to call the private member function DeviceBase::AddOrGetCachedPipeline().
|
// needs to call the private member function DeviceBase::AddOrGetCachedComputePipeline().
|
||||||
struct CreateComputePipelineAsyncWaitableCallbackTask final
|
struct CreateComputePipelineAsyncWaitableCallbackTask final
|
||||||
: CreateComputePipelineAsyncCallbackTask {
|
: CreateComputePipelineAsyncCallbackTask {
|
||||||
CreateComputePipelineAsyncWaitableCallbackTask(
|
CreateComputePipelineAsyncWaitableCallbackTask(
|
||||||
@ -1418,12 +1517,12 @@ namespace dawn_native {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Finish() final {
|
void Finish() final {
|
||||||
// TODO(jiawei.shao@intel.com): call AddOrGetCachedPipeline() asynchronously in
|
// TODO(jiawei.shao@intel.com): call AddOrGetCachedComputePipeline() asynchronously
|
||||||
// CreateComputePipelineAsyncTaskImpl::Run() when the front-end pipeline cache is
|
// in CreateComputePipelineAsyncTaskImpl::Run() when the front-end pipeline cache is
|
||||||
// thread-safe.
|
// thread-safe.
|
||||||
if (mPipeline.Get() != nullptr) {
|
if (mPipeline.Get() != nullptr) {
|
||||||
mPipeline =
|
mPipeline = mPipeline->GetDevice()->AddOrGetCachedComputePipeline(
|
||||||
mPipeline->GetDevice()->AddOrGetCachedPipeline(mPipeline, mBlueprintHash);
|
mPipeline, mBlueprintHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
CreateComputePipelineAsyncCallbackTask::Finish();
|
CreateComputePipelineAsyncCallbackTask::Finish();
|
||||||
|
@ -165,6 +165,9 @@ namespace dawn_native {
|
|||||||
const RenderBundleEncoderDescriptor* descriptor);
|
const RenderBundleEncoderDescriptor* descriptor);
|
||||||
ResultOrError<Ref<RenderPipelineBase>> CreateRenderPipeline(
|
ResultOrError<Ref<RenderPipelineBase>> CreateRenderPipeline(
|
||||||
const RenderPipelineDescriptor* descriptor);
|
const RenderPipelineDescriptor* descriptor);
|
||||||
|
MaybeError CreateRenderPipelineAsync(const RenderPipelineDescriptor* descriptor,
|
||||||
|
WGPUCreateRenderPipelineAsyncCallback callback,
|
||||||
|
void* userdata);
|
||||||
ResultOrError<Ref<SamplerBase>> CreateSampler(const SamplerDescriptor* descriptor);
|
ResultOrError<Ref<SamplerBase>> CreateSampler(const SamplerDescriptor* descriptor);
|
||||||
ResultOrError<Ref<ShaderModuleBase>> CreateShaderModule(
|
ResultOrError<Ref<ShaderModuleBase>> CreateShaderModule(
|
||||||
const ShaderModuleDescriptor* descriptor,
|
const ShaderModuleDescriptor* descriptor,
|
||||||
@ -348,14 +351,26 @@ namespace dawn_native {
|
|||||||
ResultOrError<Ref<PipelineLayoutBase>> ValidateAndGetComputePipelineDescriptorWithDefaults(
|
ResultOrError<Ref<PipelineLayoutBase>> ValidateAndGetComputePipelineDescriptorWithDefaults(
|
||||||
const ComputePipelineDescriptor& descriptor,
|
const ComputePipelineDescriptor& descriptor,
|
||||||
ComputePipelineDescriptor* outDescriptor);
|
ComputePipelineDescriptor* outDescriptor);
|
||||||
|
ResultOrError<Ref<PipelineLayoutBase>> ValidateAndGetRenderPipelineDescriptorWithDefaults(
|
||||||
|
const RenderPipelineDescriptor& descriptor,
|
||||||
|
RenderPipelineDescriptor* outDescriptor);
|
||||||
std::pair<Ref<ComputePipelineBase>, size_t> GetCachedComputePipeline(
|
std::pair<Ref<ComputePipelineBase>, size_t> GetCachedComputePipeline(
|
||||||
const ComputePipelineDescriptor* descriptor);
|
const ComputePipelineDescriptor* descriptor);
|
||||||
Ref<ComputePipelineBase> AddOrGetCachedPipeline(Ref<ComputePipelineBase> computePipeline,
|
std::pair<Ref<RenderPipelineBase>, size_t> GetCachedRenderPipeline(
|
||||||
size_t blueprintHash);
|
const RenderPipelineDescriptor* descriptor);
|
||||||
|
Ref<ComputePipelineBase> AddOrGetCachedComputePipeline(
|
||||||
|
Ref<ComputePipelineBase> computePipeline,
|
||||||
|
size_t blueprintHash);
|
||||||
|
Ref<RenderPipelineBase> AddOrGetCachedRenderPipeline(Ref<RenderPipelineBase> renderPipeline,
|
||||||
|
size_t blueprintHash);
|
||||||
virtual void CreateComputePipelineAsyncImpl(const ComputePipelineDescriptor* descriptor,
|
virtual void CreateComputePipelineAsyncImpl(const ComputePipelineDescriptor* descriptor,
|
||||||
size_t blueprintHash,
|
size_t blueprintHash,
|
||||||
WGPUCreateComputePipelineAsyncCallback callback,
|
WGPUCreateComputePipelineAsyncCallback callback,
|
||||||
void* userdata);
|
void* userdata);
|
||||||
|
virtual void CreateRenderPipelineAsyncImpl(const RenderPipelineDescriptor* descriptor,
|
||||||
|
size_t blueprintHash,
|
||||||
|
WGPUCreateRenderPipelineAsyncCallback callback,
|
||||||
|
void* userdata);
|
||||||
|
|
||||||
void ApplyToggleOverrides(const DeviceDescriptor* deviceDescriptor);
|
void ApplyToggleOverrides(const DeviceDescriptor* deviceDescriptor);
|
||||||
void ApplyExtensions(const DeviceDescriptor* deviceDescriptor);
|
void ApplyExtensions(const DeviceDescriptor* deviceDescriptor);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user