Pipeline caching: refactor object hashing
Dawn's object-based cache creates keys from memory
addresses. These keys cannot be used in a persistent
cache. This change modifies the keys to only
use hashes so they can be re-used for caching
pipelines.
BUG=dawn:549
Change-Id: Ica64d58ae6a3c6266435cfc3f776c820190f7895
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/30740
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Bryan Bernhart <bryan.bernhart@intel.com>
diff --git a/src/dawn_native/AttachmentState.cpp b/src/dawn_native/AttachmentState.cpp
index 77b669c..a9c23ae 100644
--- a/src/dawn_native/AttachmentState.cpp
+++ b/src/dawn_native/AttachmentState.cpp
@@ -15,8 +15,8 @@
#include "dawn_native/AttachmentState.h"
#include "common/BitSetIterator.h"
-#include "common/HashUtils.h"
#include "dawn_native/Device.h"
+#include "dawn_native/ObjectContentHasher.h"
#include "dawn_native/Texture.h"
namespace dawn_native {
@@ -130,6 +130,11 @@
GetDevice()->UncacheAttachmentState(this);
}
+ size_t AttachmentState::ComputeContentHash() {
+ // TODO(dawn:549): skip this traversal and reuse the blueprint.
+ return AttachmentStateBlueprint::HashFunc()(this);
+ }
+
ityp::bitset<ColorAttachmentIndex, kMaxColorAttachments>
AttachmentState::GetColorAttachmentsMask() const {
return mColorAttachmentsSet;
diff --git a/src/dawn_native/AttachmentState.h b/src/dawn_native/AttachmentState.h
index e332859..ce8b8aa 100644
--- a/src/dawn_native/AttachmentState.h
+++ b/src/dawn_native/AttachmentState.h
@@ -69,6 +69,8 @@
wgpu::TextureFormat GetDepthStencilFormat() const;
uint32_t GetSampleCount() const;
+ size_t ComputeContentHash() override;
+
private:
~AttachmentState() override;
};
diff --git a/src/dawn_native/BUILD.gn b/src/dawn_native/BUILD.gn
index 4d0bd76..a091a57 100644
--- a/src/dawn_native/BUILD.gn
+++ b/src/dawn_native/BUILD.gn
@@ -218,6 +218,8 @@
"InternalPipelineStore.h",
"ObjectBase.cpp",
"ObjectBase.h",
+ "ObjectContentHasher.cpp",
+ "ObjectContentHasher.h",
"PassResourceUsage.h",
"PassResourceUsageTracker.cpp",
"PassResourceUsageTracker.h",
diff --git a/src/dawn_native/BindGroupLayout.cpp b/src/dawn_native/BindGroupLayout.cpp
index 9348607..3b0a994 100644
--- a/src/dawn_native/BindGroupLayout.cpp
+++ b/src/dawn_native/BindGroupLayout.cpp
@@ -15,8 +15,8 @@
#include "dawn_native/BindGroupLayout.h"
#include "common/BitSetIterator.h"
-#include "common/HashUtils.h"
#include "dawn_native/Device.h"
+#include "dawn_native/ObjectContentHasher.h"
#include "dawn_native/PerStage.h"
#include "dawn_native/ValidationUtils_autogen.h"
@@ -152,11 +152,6 @@
namespace {
- void HashCombineBindingInfo(size_t* hash, const BindingInfo& info) {
- HashCombine(hash, info.hasDynamicOffset, info.visibility, info.type,
- info.textureComponentType, info.viewDimension, info.storageTextureFormat,
- info.minBufferBindingSize);
- }
bool operator!=(const BindingInfo& a, const BindingInfo& b) {
return a.hasDynamicOffset != b.hasDynamicOffset || //
@@ -319,15 +314,20 @@
return it->second;
}
- size_t BindGroupLayoutBase::HashFunc::operator()(const BindGroupLayoutBase* bgl) const {
- size_t hash = 0;
+ size_t BindGroupLayoutBase::ComputeContentHash() {
+ ObjectContentHasher recorder;
// std::map is sorted by key, so two BGLs constructed in different orders
- // will still hash the same.
- for (const auto& it : bgl->mBindingMap) {
- HashCombine(&hash, it.first, it.second);
- HashCombineBindingInfo(&hash, bgl->mBindingInfo[it.second]);
+ // will still record the same.
+ for (const auto& it : mBindingMap) {
+ recorder.Record(it.first, it.second);
+
+ const BindingInfo& info = mBindingInfo[it.second];
+ recorder.Record(info.hasDynamicOffset, info.visibility, info.type,
+ info.textureComponentType, info.viewDimension,
+ info.storageTextureFormat, info.minBufferBindingSize);
}
- return hash;
+
+ return recorder.GetContentHash();
}
bool BindGroupLayoutBase::EqualityFunc::operator()(const BindGroupLayoutBase* a,
diff --git a/src/dawn_native/BindGroupLayout.h b/src/dawn_native/BindGroupLayout.h
index 06a7653..113c591 100644
--- a/src/dawn_native/BindGroupLayout.h
+++ b/src/dawn_native/BindGroupLayout.h
@@ -56,10 +56,9 @@
const BindingMap& GetBindingMap() const;
BindingIndex GetBindingIndex(BindingNumber bindingNumber) const;
- // Functors necessary for the unordered_set<BGLBase*>-based cache.
- struct HashFunc {
- size_t operator()(const BindGroupLayoutBase* bgl) const;
- };
+ // Functions necessary for the unordered_set<BGLBase*>-based cache.
+ size_t ComputeContentHash() override;
+
struct EqualityFunc {
bool operator()(const BindGroupLayoutBase* a, const BindGroupLayoutBase* b) const;
};
diff --git a/src/dawn_native/CMakeLists.txt b/src/dawn_native/CMakeLists.txt
index e9b9580..a38446b 100644
--- a/src/dawn_native/CMakeLists.txt
+++ b/src/dawn_native/CMakeLists.txt
@@ -94,6 +94,8 @@
"ErrorScopeTracker.h"
"Extensions.cpp"
"Extensions.h"
+ "ObjectContentHasher.cpp"
+ "ObjectContentHasher.h"
"Fence.cpp"
"Fence.h"
"Format.cpp"
diff --git a/src/dawn_native/CachedObject.cpp b/src/dawn_native/CachedObject.cpp
index b91baed..523924d 100644
--- a/src/dawn_native/CachedObject.cpp
+++ b/src/dawn_native/CachedObject.cpp
@@ -14,6 +14,8 @@
#include "dawn_native/CachedObject.h"
+#include "common/Assert.h"
+
namespace dawn_native {
bool CachedObject::IsCachedReference() const {
@@ -24,4 +26,19 @@
mIsCachedReference = true;
}
+ size_t CachedObject::HashFunc::operator()(const CachedObject* obj) const {
+ return obj->GetContentHash();
+ }
+
+ size_t CachedObject::GetContentHash() const {
+ ASSERT(mIsContentHashInitialized);
+ return mContentHash;
+ }
+
+ void CachedObject::SetContentHash(size_t contentHash) {
+ ASSERT(!mIsContentHashInitialized);
+ mContentHash = contentHash;
+ mIsContentHashInitialized = true;
+ }
+
} // namespace dawn_native
diff --git a/src/dawn_native/CachedObject.h b/src/dawn_native/CachedObject.h
index b498b91..ec73718 100644
--- a/src/dawn_native/CachedObject.h
+++ b/src/dawn_native/CachedObject.h
@@ -29,11 +29,25 @@
bool IsCachedReference() const;
+ // Functor necessary for the unordered_set<CachedObject*>-based cache.
+ struct HashFunc {
+ size_t operator()(const CachedObject* obj) const;
+ };
+
+ size_t GetContentHash() const;
+ void SetContentHash(size_t contentHash);
+
private:
friend class DeviceBase;
void SetIsCachedReference();
bool mIsCachedReference = false;
+
+ // Called by ObjectContentHasher upon creation to record the object.
+ virtual size_t ComputeContentHash() = 0;
+
+ size_t mContentHash = 0;
+ bool mIsContentHashInitialized = false;
};
} // namespace dawn_native
diff --git a/src/dawn_native/ComputePipeline.cpp b/src/dawn_native/ComputePipeline.cpp
index 793765d..e32e62a 100644
--- a/src/dawn_native/ComputePipeline.cpp
+++ b/src/dawn_native/ComputePipeline.cpp
@@ -14,8 +14,8 @@
#include "dawn_native/ComputePipeline.h"
-#include "common/HashUtils.h"
#include "dawn_native/Device.h"
+#include "dawn_native/ObjectContentHasher.h"
namespace dawn_native {
@@ -59,10 +59,6 @@
return new ComputePipelineBase(device, ObjectBase::kError);
}
- size_t ComputePipelineBase::HashFunc::operator()(const ComputePipelineBase* pipeline) const {
- return PipelineBase::HashForCache(pipeline);
- }
-
bool ComputePipelineBase::EqualityFunc::operator()(const ComputePipelineBase* a,
const ComputePipelineBase* b) const {
return PipelineBase::EqualForCache(a, b);
diff --git a/src/dawn_native/ComputePipeline.h b/src/dawn_native/ComputePipeline.h
index c2b470a..012e5df 100644
--- a/src/dawn_native/ComputePipeline.h
+++ b/src/dawn_native/ComputePipeline.h
@@ -35,9 +35,6 @@
const EntryPointMetadata& GetMetadata() const;
// Functors necessary for the unordered_set<ComputePipelineBase*>-based cache.
- struct HashFunc {
- size_t operator()(const ComputePipelineBase* pipeline) const;
- };
struct EqualityFunc {
bool operator()(const ComputePipelineBase* a, const ComputePipelineBase* b) const;
};
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index 2c8468f..3e838ad 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -437,6 +437,9 @@
const BindGroupLayoutDescriptor* descriptor) {
BindGroupLayoutBase blueprint(this, descriptor);
+ const size_t blueprintHash = blueprint.ComputeContentHash();
+ blueprint.SetContentHash(blueprintHash);
+
Ref<BindGroupLayoutBase> result = nullptr;
auto iter = mCaches->bindGroupLayouts.find(&blueprint);
if (iter != mCaches->bindGroupLayouts.end()) {
@@ -445,6 +448,7 @@
BindGroupLayoutBase* backendObj;
DAWN_TRY_ASSIGN(backendObj, CreateBindGroupLayoutImpl(descriptor));
backendObj->SetIsCachedReference();
+ backendObj->SetContentHash(blueprintHash);
mCaches->bindGroupLayouts.insert(backendObj);
result = AcquireRef(backendObj);
}
@@ -475,6 +479,9 @@
const ComputePipelineDescriptor* descriptor) {
ComputePipelineBase blueprint(this, descriptor);
+ const size_t blueprintHash = blueprint.ComputeContentHash();
+ blueprint.SetContentHash(blueprintHash);
+
auto iter = mCaches->computePipelines.find(&blueprint);
if (iter != mCaches->computePipelines.end()) {
(*iter)->Reference();
@@ -484,6 +491,7 @@
ComputePipelineBase* backendObj;
DAWN_TRY_ASSIGN(backendObj, CreateComputePipelineImpl(descriptor));
backendObj->SetIsCachedReference();
+ backendObj->SetContentHash(blueprintHash);
mCaches->computePipelines.insert(backendObj);
return backendObj;
}
@@ -498,6 +506,9 @@
const PipelineLayoutDescriptor* descriptor) {
PipelineLayoutBase blueprint(this, descriptor);
+ const size_t blueprintHash = blueprint.ComputeContentHash();
+ blueprint.SetContentHash(blueprintHash);
+
auto iter = mCaches->pipelineLayouts.find(&blueprint);
if (iter != mCaches->pipelineLayouts.end()) {
(*iter)->Reference();
@@ -507,6 +518,7 @@
PipelineLayoutBase* backendObj;
DAWN_TRY_ASSIGN(backendObj, CreatePipelineLayoutImpl(descriptor));
backendObj->SetIsCachedReference();
+ backendObj->SetContentHash(blueprintHash);
mCaches->pipelineLayouts.insert(backendObj);
return backendObj;
}
@@ -521,6 +533,9 @@
const RenderPipelineDescriptor* descriptor) {
RenderPipelineBase blueprint(this, descriptor);
+ const size_t blueprintHash = blueprint.ComputeContentHash();
+ blueprint.SetContentHash(blueprintHash);
+
auto iter = mCaches->renderPipelines.find(&blueprint);
if (iter != mCaches->renderPipelines.end()) {
(*iter)->Reference();
@@ -530,6 +545,7 @@
RenderPipelineBase* backendObj;
DAWN_TRY_ASSIGN(backendObj, CreateRenderPipelineImpl(descriptor));
backendObj->SetIsCachedReference();
+ backendObj->SetContentHash(blueprintHash);
mCaches->renderPipelines.insert(backendObj);
return backendObj;
}
@@ -544,6 +560,9 @@
const SamplerDescriptor* descriptor) {
SamplerBase blueprint(this, descriptor);
+ const size_t blueprintHash = blueprint.ComputeContentHash();
+ blueprint.SetContentHash(blueprintHash);
+
auto iter = mCaches->samplers.find(&blueprint);
if (iter != mCaches->samplers.end()) {
(*iter)->Reference();
@@ -553,6 +572,7 @@
SamplerBase* backendObj;
DAWN_TRY_ASSIGN(backendObj, CreateSamplerImpl(descriptor));
backendObj->SetIsCachedReference();
+ backendObj->SetContentHash(blueprintHash);
mCaches->samplers.insert(backendObj);
return backendObj;
}
@@ -567,6 +587,9 @@
const ShaderModuleDescriptor* descriptor) {
ShaderModuleBase blueprint(this, descriptor);
+ const size_t blueprintHash = blueprint.ComputeContentHash();
+ blueprint.SetContentHash(blueprintHash);
+
auto iter = mCaches->shaderModules.find(&blueprint);
if (iter != mCaches->shaderModules.end()) {
(*iter)->Reference();
@@ -576,6 +599,7 @@
ShaderModuleBase* backendObj;
DAWN_TRY_ASSIGN(backendObj, CreateShaderModuleImpl(descriptor));
backendObj->SetIsCachedReference();
+ backendObj->SetContentHash(blueprintHash);
mCaches->shaderModules.insert(backendObj);
return backendObj;
}
@@ -595,6 +619,7 @@
Ref<AttachmentState> attachmentState = AcquireRef(new AttachmentState(this, *blueprint));
attachmentState->SetIsCachedReference();
+ attachmentState->SetContentHash(attachmentState->ComputeContentHash());
mCaches->attachmentStates.insert(attachmentState.Get());
return attachmentState;
}
diff --git a/src/dawn_native/ObjectContentHasher.cpp b/src/dawn_native/ObjectContentHasher.cpp
new file mode 100644
index 0000000..901e4cc
--- /dev/null
+++ b/src/dawn_native/ObjectContentHasher.cpp
@@ -0,0 +1,22 @@
+// 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.
+
+#include "dawn_native/ObjectContentHasher.h"
+
+namespace dawn_native {
+
+ size_t ObjectContentHasher::GetContentHash() const {
+ return mContentHash;
+ }
+} // namespace dawn_native
diff --git a/src/dawn_native/ObjectContentHasher.h b/src/dawn_native/ObjectContentHasher.h
new file mode 100644
index 0000000..2fed2701
--- /dev/null
+++ b/src/dawn_native/ObjectContentHasher.h
@@ -0,0 +1,81 @@
+// 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_OBJECT_CONTENT_HASHER_H_
+#define DAWNNATIVE_OBJECT_CONTENT_HASHER_H_
+
+#include "common/HashUtils.h"
+
+#include <string>
+#include <vector>
+
+namespace dawn_native {
+
+ // ObjectContentHasher records a hash that can be used as a key to lookup a cached object in a
+ // cache.
+ class ObjectContentHasher {
+ public:
+ // Record calls the appropriate record function based on the type.
+ template <typename T, typename... Args>
+ void Record(const T& value, const Args&... args) {
+ RecordImpl<T, Args...>::Call(this, value, args...);
+ }
+
+ size_t GetContentHash() const;
+
+ private:
+ template <typename T, typename... Args>
+ struct RecordImpl {
+ static constexpr void Call(ObjectContentHasher* recorder,
+ const T& value,
+ const Args&... args) {
+ HashCombine(&recorder->mContentHash, value, args...);
+ }
+ };
+
+ template <typename T>
+ struct RecordImpl<T*> {
+ static constexpr void Call(ObjectContentHasher* recorder, T* obj) {
+ // Calling Record(objPtr) is not allowed. This check exists to only prevent such
+ // mistakes.
+ static_assert(obj == nullptr, "");
+ }
+ };
+
+ template <>
+ struct RecordImpl<std::string> {
+ static constexpr void Call(ObjectContentHasher* recorder, const std::string& str) {
+ recorder->RecordIterable<std::string>(str);
+ }
+ };
+
+ template <typename T>
+ struct RecordImpl<std::vector<T>> {
+ static constexpr void Call(ObjectContentHasher* recorder, const std::vector<T>& vec) {
+ recorder->RecordIterable<std::vector<T>>(vec);
+ }
+ };
+
+ template <typename IteratorT>
+ void RecordIterable(const IteratorT& iterable) {
+ for (auto it = iterable.begin(); it != iterable.end(); ++it) {
+ Record(*it);
+ }
+ }
+
+ size_t mContentHash = 0;
+ };
+} // namespace dawn_native
+
+#endif // DAWNNATIVE_OBJECT_CONTENT_HASHER_H_
\ No newline at end of file
diff --git a/src/dawn_native/Pipeline.cpp b/src/dawn_native/Pipeline.cpp
index a006ddb..4d582e1 100644
--- a/src/dawn_native/Pipeline.cpp
+++ b/src/dawn_native/Pipeline.cpp
@@ -14,9 +14,9 @@
#include "dawn_native/Pipeline.h"
-#include "common/HashUtils.h"
#include "dawn_native/BindGroupLayout.h"
#include "dawn_native/Device.h"
+#include "dawn_native/ObjectContentHasher.h"
#include "dawn_native/PipelineLayout.h"
#include "dawn_native/ShaderModule.h"
@@ -142,21 +142,17 @@
return bgl;
}
- // static
- size_t PipelineBase::HashForCache(const PipelineBase* pipeline) {
- size_t hash = 0;
+ size_t PipelineBase::ComputeContentHash() {
+ ObjectContentHasher recorder;
+ recorder.Record(mLayout->GetContentHash());
- // The layout is deduplicated so it can be hashed by pointer.
- HashCombine(&hash, pipeline->mLayout.Get());
-
- HashCombine(&hash, pipeline->mStageMask);
- for (SingleShaderStage stage : IterateStages(pipeline->mStageMask)) {
- // The module is deduplicated so it can be hashed by pointer.
- HashCombine(&hash, pipeline->mStages[stage].module.Get());
- HashCombine(&hash, pipeline->mStages[stage].entryPoint);
+ recorder.Record(mStageMask);
+ for (SingleShaderStage stage : IterateStages(mStageMask)) {
+ recorder.Record(mStages[stage].module->GetContentHash());
+ recorder.Record(mStages[stage].entryPoint);
}
- return hash;
+ return recorder.GetContentHash();
}
// static
diff --git a/src/dawn_native/Pipeline.h b/src/dawn_native/Pipeline.h
index 395410a..cb18032 100644
--- a/src/dawn_native/Pipeline.h
+++ b/src/dawn_native/Pipeline.h
@@ -51,8 +51,8 @@
BindGroupLayoutBase* GetBindGroupLayout(uint32_t groupIndex);
- // Helper function for the functors for std::unordered_map-based pipeline caches.
- static size_t HashForCache(const PipelineBase* pipeline);
+ // Helper functions for std::unordered_map-based pipeline caches.
+ size_t ComputeContentHash() override;
static bool EqualForCache(const PipelineBase* a, const PipelineBase* b);
protected:
diff --git a/src/dawn_native/PipelineLayout.cpp b/src/dawn_native/PipelineLayout.cpp
index dedef90..75839c7 100644
--- a/src/dawn_native/PipelineLayout.cpp
+++ b/src/dawn_native/PipelineLayout.cpp
@@ -16,10 +16,10 @@
#include "common/Assert.h"
#include "common/BitSetIterator.h"
-#include "common/HashUtils.h"
#include "common/ityp_stack_vec.h"
#include "dawn_native/BindGroupLayout.h"
#include "dawn_native/Device.h"
+#include "dawn_native/ObjectContentHasher.h"
#include "dawn_native/ShaderModule.h"
namespace dawn_native {
@@ -253,14 +253,15 @@
return kMaxBindGroupsTyped;
}
- size_t PipelineLayoutBase::HashFunc::operator()(const PipelineLayoutBase* pl) const {
- size_t hash = Hash(pl->mMask);
+ size_t PipelineLayoutBase::ComputeContentHash() {
+ ObjectContentHasher recorder;
+ recorder.Record(mMask);
- for (BindGroupIndex group : IterateBitSet(pl->mMask)) {
- HashCombine(&hash, pl->GetBindGroupLayout(group));
+ for (BindGroupIndex group : IterateBitSet(mMask)) {
+ recorder.Record(GetBindGroupLayout(group)->GetContentHash());
}
- return hash;
+ return recorder.GetContentHash();
}
bool PipelineLayoutBase::EqualityFunc::operator()(const PipelineLayoutBase* a,
diff --git a/src/dawn_native/PipelineLayout.h b/src/dawn_native/PipelineLayout.h
index be8a75c..9c30274 100644
--- a/src/dawn_native/PipelineLayout.h
+++ b/src/dawn_native/PipelineLayout.h
@@ -61,10 +61,9 @@
// [0, kMaxBindGroups]
BindGroupIndex GroupsInheritUpTo(const PipelineLayoutBase* other) const;
- // Functors necessary for the unordered_set<PipelineLayoutBase*>-based cache.
- struct HashFunc {
- size_t operator()(const PipelineLayoutBase* pl) const;
- };
+ // Functions necessary for the unordered_set<PipelineLayoutBase*>-based cache.
+ size_t ComputeContentHash() override;
+
struct EqualityFunc {
bool operator()(const PipelineLayoutBase* a, const PipelineLayoutBase* b) const;
};
diff --git a/src/dawn_native/RenderPipeline.cpp b/src/dawn_native/RenderPipeline.cpp
index deb0fd3..fcdb75a 100644
--- a/src/dawn_native/RenderPipeline.cpp
+++ b/src/dawn_native/RenderPipeline.cpp
@@ -15,9 +15,9 @@
#include "dawn_native/RenderPipeline.h"
#include "common/BitSetIterator.h"
-#include "common/HashUtils.h"
#include "dawn_native/Commands.h"
#include "dawn_native/Device.h"
+#include "dawn_native/ObjectContentHasher.h"
#include "dawn_native/ValidationUtils_autogen.h"
#include <cmath>
@@ -607,63 +607,62 @@
return mAttachmentState.Get();
}
- size_t RenderPipelineBase::HashFunc::operator()(const RenderPipelineBase* pipeline) const {
- // Hash modules and layout
- size_t hash = PipelineBase::HashForCache(pipeline);
+ size_t RenderPipelineBase::ComputeContentHash() {
+ ObjectContentHasher recorder;
- // Hierarchically hash the attachment state.
+ // Record modules and layout
+ recorder.Record(PipelineBase::ComputeContentHash());
+
+ // Hierarchically record the attachment state.
// It contains the attachments set, texture formats, and sample count.
- HashCombine(&hash, pipeline->mAttachmentState.Get());
+ recorder.Record(mAttachmentState->GetContentHash());
- // Hash attachments
- for (ColorAttachmentIndex i :
- IterateBitSet(pipeline->mAttachmentState->GetColorAttachmentsMask())) {
- const ColorStateDescriptor& desc = *pipeline->GetColorStateDescriptor(i);
- HashCombine(&hash, desc.writeMask);
- HashCombine(&hash, desc.colorBlend.operation, desc.colorBlend.srcFactor,
- desc.colorBlend.dstFactor);
- HashCombine(&hash, desc.alphaBlend.operation, desc.alphaBlend.srcFactor,
- desc.alphaBlend.dstFactor);
+ // Record attachments
+ for (ColorAttachmentIndex i : IterateBitSet(mAttachmentState->GetColorAttachmentsMask())) {
+ const ColorStateDescriptor& desc = *GetColorStateDescriptor(i);
+ recorder.Record(desc.writeMask);
+ recorder.Record(desc.colorBlend.operation, desc.colorBlend.srcFactor,
+ desc.colorBlend.dstFactor);
+ recorder.Record(desc.alphaBlend.operation, desc.alphaBlend.srcFactor,
+ desc.alphaBlend.dstFactor);
}
- if (pipeline->mAttachmentState->HasDepthStencilAttachment()) {
- const DepthStencilStateDescriptor& desc = pipeline->mDepthStencilState;
- HashCombine(&hash, desc.depthWriteEnabled, desc.depthCompare);
- HashCombine(&hash, desc.stencilReadMask, desc.stencilWriteMask);
- HashCombine(&hash, desc.stencilFront.compare, desc.stencilFront.failOp,
- desc.stencilFront.depthFailOp, desc.stencilFront.passOp);
- HashCombine(&hash, desc.stencilBack.compare, desc.stencilBack.failOp,
- desc.stencilBack.depthFailOp, desc.stencilBack.passOp);
+ if (mAttachmentState->HasDepthStencilAttachment()) {
+ const DepthStencilStateDescriptor& desc = mDepthStencilState;
+ recorder.Record(desc.depthWriteEnabled, desc.depthCompare);
+ recorder.Record(desc.stencilReadMask, desc.stencilWriteMask);
+ recorder.Record(desc.stencilFront.compare, desc.stencilFront.failOp,
+ desc.stencilFront.depthFailOp, desc.stencilFront.passOp);
+ recorder.Record(desc.stencilBack.compare, desc.stencilBack.failOp,
+ desc.stencilBack.depthFailOp, desc.stencilBack.passOp);
}
- // Hash vertex state
- HashCombine(&hash, pipeline->mAttributeLocationsUsed);
- for (VertexAttributeLocation location : IterateBitSet(pipeline->mAttributeLocationsUsed)) {
- const VertexAttributeInfo& desc = pipeline->GetAttribute(location);
- HashCombine(&hash, desc.shaderLocation, desc.vertexBufferSlot, desc.offset,
- desc.format);
+ // Record vertex state
+ recorder.Record(mAttributeLocationsUsed);
+ for (VertexAttributeLocation location : IterateBitSet(mAttributeLocationsUsed)) {
+ const VertexAttributeInfo& desc = GetAttribute(location);
+ recorder.Record(desc.shaderLocation, desc.vertexBufferSlot, desc.offset, desc.format);
}
- HashCombine(&hash, pipeline->mVertexBufferSlotsUsed);
- for (VertexBufferSlot slot : IterateBitSet(pipeline->mVertexBufferSlotsUsed)) {
- const VertexBufferInfo& desc = pipeline->GetVertexBuffer(slot);
- HashCombine(&hash, desc.arrayStride, desc.stepMode);
+ recorder.Record(mVertexBufferSlotsUsed);
+ for (VertexBufferSlot slot : IterateBitSet(mVertexBufferSlotsUsed)) {
+ const VertexBufferInfo& desc = GetVertexBuffer(slot);
+ recorder.Record(desc.arrayStride, desc.stepMode);
}
- HashCombine(&hash, pipeline->mVertexState.indexFormat);
+ recorder.Record(mVertexState.indexFormat);
- // Hash rasterization state
+ // Record rasterization state
{
- const RasterizationStateDescriptor& desc = pipeline->mRasterizationState;
- HashCombine(&hash, desc.frontFace, desc.cullMode);
- HashCombine(&hash, desc.depthBias, desc.depthBiasSlopeScale, desc.depthBiasClamp);
+ const RasterizationStateDescriptor& desc = mRasterizationState;
+ recorder.Record(desc.frontFace, desc.cullMode);
+ recorder.Record(desc.depthBias, desc.depthBiasSlopeScale, desc.depthBiasClamp);
}
- // Hash other state
- HashCombine(&hash, pipeline->mPrimitiveTopology, pipeline->mSampleMask,
- pipeline->mAlphaToCoverageEnabled);
+ // Record other state
+ recorder.Record(mPrimitiveTopology, mSampleMask, mAlphaToCoverageEnabled);
- return hash;
+ return recorder.GetContentHash();
}
bool RenderPipelineBase::EqualityFunc::operator()(const RenderPipelineBase* a,
diff --git a/src/dawn_native/RenderPipeline.h b/src/dawn_native/RenderPipeline.h
index db913a2..b6f047b 100644
--- a/src/dawn_native/RenderPipeline.h
+++ b/src/dawn_native/RenderPipeline.h
@@ -91,10 +91,9 @@
const AttachmentState* GetAttachmentState() const;
- // Functors necessary for the unordered_set<RenderPipelineBase*>-based cache.
- struct HashFunc {
- size_t operator()(const RenderPipelineBase* pipeline) const;
- };
+ // Functions necessary for the unordered_set<RenderPipelineBase*>-based cache.
+ size_t ComputeContentHash() override;
+
struct EqualityFunc {
bool operator()(const RenderPipelineBase* a, const RenderPipelineBase* b) const;
};
diff --git a/src/dawn_native/Sampler.cpp b/src/dawn_native/Sampler.cpp
index 748956e..11b398a 100644
--- a/src/dawn_native/Sampler.cpp
+++ b/src/dawn_native/Sampler.cpp
@@ -14,8 +14,8 @@
#include "dawn_native/Sampler.h"
-#include "common/HashUtils.h"
#include "dawn_native/Device.h"
+#include "dawn_native/ObjectContentHasher.h"
#include "dawn_native/ValidationUtils_autogen.h"
#include <cmath>
@@ -84,20 +84,11 @@
return mCompareFunction != wgpu::CompareFunction::Undefined;
}
- size_t SamplerBase::HashFunc::operator()(const SamplerBase* module) const {
- size_t hash = 0;
-
- HashCombine(&hash, module->mAddressModeU);
- HashCombine(&hash, module->mAddressModeV);
- HashCombine(&hash, module->mAddressModeW);
- HashCombine(&hash, module->mMagFilter);
- HashCombine(&hash, module->mMinFilter);
- HashCombine(&hash, module->mMipmapFilter);
- HashCombine(&hash, module->mLodMinClamp);
- HashCombine(&hash, module->mLodMaxClamp);
- HashCombine(&hash, module->mCompareFunction);
-
- return hash;
+ size_t SamplerBase::ComputeContentHash() {
+ ObjectContentHasher recorder;
+ recorder.Record(mAddressModeU, mAddressModeV, mAddressModeW, mMagFilter, mMinFilter,
+ mMipmapFilter, mLodMinClamp, mLodMaxClamp, mCompareFunction);
+ return recorder.GetContentHash();
}
bool SamplerBase::EqualityFunc::operator()(const SamplerBase* a, const SamplerBase* b) const {
diff --git a/src/dawn_native/Sampler.h b/src/dawn_native/Sampler.h
index 3829b90..62ef4d5 100644
--- a/src/dawn_native/Sampler.h
+++ b/src/dawn_native/Sampler.h
@@ -35,10 +35,9 @@
bool HasCompareFunction() const;
- // Functors necessary for the unordered_set<SamplerBase*>-based cache.
- struct HashFunc {
- size_t operator()(const SamplerBase* module) const;
- };
+ // Functions necessary for the unordered_set<SamplerBase*>-based cache.
+ size_t ComputeContentHash() override;
+
struct EqualityFunc {
bool operator()(const SamplerBase* a, const SamplerBase* b) const;
};
diff --git a/src/dawn_native/ShaderModule.cpp b/src/dawn_native/ShaderModule.cpp
index cba7da7..e7066e2 100644
--- a/src/dawn_native/ShaderModule.cpp
+++ b/src/dawn_native/ShaderModule.cpp
@@ -14,9 +14,9 @@
#include "dawn_native/ShaderModule.h"
-#include "common/HashUtils.h"
#include "dawn_native/BindGroupLayout.h"
#include "dawn_native/Device.h"
+#include "dawn_native/ObjectContentHasher.h"
#include "dawn_native/Pipeline.h"
#include "dawn_native/PipelineLayout.h"
#include "dawn_native/SpirvUtils.h"
@@ -975,20 +975,12 @@
return *mEntryPoints.at(entryPoint);
}
- size_t ShaderModuleBase::HashFunc::operator()(const ShaderModuleBase* module) const {
- size_t hash = 0;
-
- HashCombine(&hash, module->mType);
-
- for (uint32_t word : module->mOriginalSpirv) {
- HashCombine(&hash, word);
- }
-
- for (char c : module->mWgsl) {
- HashCombine(&hash, c);
- }
-
- return hash;
+ size_t ShaderModuleBase::ComputeContentHash() {
+ ObjectContentHasher recorder;
+ recorder.Record(mType);
+ recorder.Record(mOriginalSpirv);
+ recorder.Record(mWgsl);
+ return recorder.GetContentHash();
}
bool ShaderModuleBase::EqualityFunc::operator()(const ShaderModuleBase* a,
diff --git a/src/dawn_native/ShaderModule.h b/src/dawn_native/ShaderModule.h
index 3898515..e406f49 100644
--- a/src/dawn_native/ShaderModule.h
+++ b/src/dawn_native/ShaderModule.h
@@ -105,10 +105,9 @@
// must be true.
const EntryPointMetadata& GetEntryPoint(const std::string& entryPoint) const;
- // Functors necessary for the unordered_set<ShaderModuleBase*>-based cache.
- struct HashFunc {
- size_t operator()(const ShaderModuleBase* module) const;
- };
+ // Functions necessary for the unordered_set<ShaderModuleBase*>-based cache.
+ size_t ComputeContentHash() override;
+
struct EqualityFunc {
bool operator()(const ShaderModuleBase* a, const ShaderModuleBase* b) const;
};