Caching empty bind group layouts
Added Device::GetOrCreateEmptyBindGroupLayout which caches the result
after being run and modified PipelineBase::getBindGroupLayout to use
that instead of creating a new empty bind group layout each time.
Bug: dawn:466
Change-Id: I70a5719265784eb8f60c2eedf6db7596462b21bd
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/23980
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Tomek Ponitka <tommek@google.com>
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index 1c30cd5..b0ef00d 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -169,6 +169,8 @@
mDynamicUploader = nullptr;
mMapRequestTracker = nullptr;
+ mEmptyBindGroupLayout = nullptr;
+
AssumeCommandsComplete();
// Tell the backend that it can free all the objects now that the GPU timeline is empty.
ShutDownImpl();
@@ -411,6 +413,24 @@
ASSERT(removedCount == 1);
}
+ ResultOrError<BindGroupLayoutBase*> DeviceBase::GetOrCreateEmptyBindGroupLayout() {
+ if (!mEmptyBindGroupLayout) {
+ BindGroupLayoutDescriptor desc = {};
+ desc.entryCount = 0;
+ desc.entries = nullptr;
+
+ BindGroupLayoutBase* bgl = nullptr;
+ if (ConsumedError(GetOrCreateBindGroupLayout(&desc), &bgl)) {
+ return BindGroupLayoutBase::MakeError(this);
+ }
+ mEmptyBindGroupLayout = bgl;
+ return bgl;
+ } else {
+ mEmptyBindGroupLayout->Reference();
+ return mEmptyBindGroupLayout.Get();
+ }
+ }
+
ResultOrError<ComputePipelineBase*> DeviceBase::GetOrCreateComputePipeline(
const ComputePipelineDescriptor* descriptor) {
ComputePipelineBase blueprint(this, descriptor);
diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h
index 94d916f..f9a3b43 100644
--- a/src/dawn_native/Device.h
+++ b/src/dawn_native/Device.h
@@ -112,6 +112,8 @@
const BindGroupLayoutDescriptor* descriptor);
void UncacheBindGroupLayout(BindGroupLayoutBase* obj);
+ ResultOrError<BindGroupLayoutBase*> GetOrCreateEmptyBindGroupLayout();
+
ResultOrError<ComputePipelineBase*> GetOrCreateComputePipeline(
const ComputePipelineDescriptor* descriptor);
void UncacheComputePipeline(ComputePipelineBase* obj);
@@ -340,6 +342,8 @@
struct Caches;
std::unique_ptr<Caches> mCaches;
+ Ref<BindGroupLayoutBase> mEmptyBindGroupLayout;
+
std::unique_ptr<DynamicUploader> mDynamicUploader;
std::unique_ptr<ErrorScopeTracker> mErrorScopeTracker;
std::unique_ptr<FenceSignalTracker> mFenceSignalTracker;
diff --git a/src/dawn_native/Pipeline.cpp b/src/dawn_native/Pipeline.cpp
index df34441..15dd068 100644
--- a/src/dawn_native/Pipeline.cpp
+++ b/src/dawn_native/Pipeline.cpp
@@ -91,19 +91,10 @@
}
BindGroupIndex groupIndex(groupIndexIn);
- if (!mLayout->GetBindGroupLayoutsMask()[groupIndex]) {
- // Get or create an empty bind group layout.
- // TODO(enga): Consider caching this object on the Device and reusing it.
- // Today, this can't be done correctly because of the order of Device destruction.
- // For example, vulkan::~Device will be called before ~DeviceBase. If DeviceBase owns
- // a Ref<BindGroupLayoutBase>, then the VkDevice will be destroyed before the
- // VkDescriptorSetLayout.
- BindGroupLayoutDescriptor desc = {};
- desc.entryCount = 0;
- desc.entries = nullptr;
+ if (!mLayout->GetBindGroupLayoutsMask()[groupIndex]) {
BindGroupLayoutBase* bgl = nullptr;
- if (GetDevice()->ConsumedError(GetDevice()->GetOrCreateBindGroupLayout(&desc), &bgl)) {
+ if (GetDevice()->ConsumedError(GetDevice()->GetOrCreateEmptyBindGroupLayout(), &bgl)) {
return BindGroupLayoutBase::MakeError(GetDevice());
}
return bgl;