Deduplicate AttachmentState shared by RenderPipeline and RenderPasses
This both deduplicates shared state by multiple passes or pipelines and
makes checking pipeline compatibility a single pointer check. It will be
useful for also checking RenderBundle compatibility.
Bug: dawn:154
Change-Id: I0fb289fab5ac76a7fbd500f64b8a6409a246ab32
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9461
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 513c74e..45b2381 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -104,6 +104,8 @@
sources += [
"src/dawn_native/Adapter.cpp",
"src/dawn_native/Adapter.h",
+ "src/dawn_native/AttachmentState.cpp",
+ "src/dawn_native/AttachmentState.h",
"src/dawn_native/BackendConnection.cpp",
"src/dawn_native/BackendConnection.h",
"src/dawn_native/BindGroup.cpp",
diff --git a/src/dawn_native/AttachmentState.cpp b/src/dawn_native/AttachmentState.cpp
new file mode 100644
index 0000000..39ddb4b
--- /dev/null
+++ b/src/dawn_native/AttachmentState.cpp
@@ -0,0 +1,146 @@
+// Copyright 2019 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/AttachmentState.h"
+
+#include "common/BitSetIterator.h"
+#include "common/HashUtils.h"
+#include "dawn_native/Device.h"
+#include "dawn_native/Texture.h"
+
+namespace dawn_native {
+
+ AttachmentStateBlueprint::AttachmentStateBlueprint(const RenderPipelineDescriptor* descriptor)
+ : mHasDepthStencilAttachment(descriptor->depthStencilState != nullptr),
+ mSampleCount(descriptor->sampleCount) {
+ for (uint32_t i = 0; i < descriptor->colorStateCount; ++i) {
+ ASSERT(descriptor->colorStates[i] != nullptr);
+ mColorAttachmentsSet.set(i);
+ mColorFormats[i] = descriptor->colorStates[i]->format;
+ }
+ if (mHasDepthStencilAttachment) {
+ mDepthStencilFormat = descriptor->depthStencilState->format;
+ }
+ }
+
+ AttachmentStateBlueprint::AttachmentStateBlueprint(const RenderPassDescriptor* descriptor)
+ : mHasDepthStencilAttachment(descriptor->depthStencilAttachment != nullptr) {
+ for (uint32_t i = 0; i < descriptor->colorAttachmentCount; ++i) {
+ TextureViewBase* attachment = descriptor->colorAttachments[i]->attachment;
+ mColorAttachmentsSet.set(i);
+ mColorFormats[i] = attachment->GetFormat().format;
+ if (mSampleCount == 0) {
+ mSampleCount = attachment->GetTexture()->GetSampleCount();
+ } else {
+ ASSERT(mSampleCount == attachment->GetTexture()->GetSampleCount());
+ }
+ }
+ if (mHasDepthStencilAttachment) {
+ TextureViewBase* attachment = descriptor->depthStencilAttachment->attachment;
+ mDepthStencilFormat = attachment->GetFormat().format;
+ if (mSampleCount == 0) {
+ mSampleCount = attachment->GetTexture()->GetSampleCount();
+ } else {
+ ASSERT(mSampleCount == attachment->GetTexture()->GetSampleCount());
+ }
+ }
+ ASSERT(mSampleCount > 0);
+ }
+
+ AttachmentStateBlueprint::AttachmentStateBlueprint(const AttachmentStateBlueprint& rhs) =
+ default;
+
+ size_t AttachmentStateBlueprint::HashFunc::operator()(
+ const AttachmentStateBlueprint* attachmentState) const {
+ size_t hash = 0;
+
+ // Hash color formats
+ HashCombine(&hash, attachmentState->mColorAttachmentsSet);
+ for (uint32_t i : IterateBitSet(attachmentState->mColorAttachmentsSet)) {
+ HashCombine(&hash, attachmentState->mColorFormats[i]);
+ }
+
+ // Hash depth stencil attachments
+ if (attachmentState->mHasDepthStencilAttachment) {
+ HashCombine(&hash, attachmentState->mDepthStencilFormat);
+ }
+
+ // Hash sample count
+ HashCombine(&hash, attachmentState->mSampleCount);
+
+ return hash;
+ }
+
+ bool AttachmentStateBlueprint::EqualityFunc::operator()(
+ const AttachmentStateBlueprint* a,
+ const AttachmentStateBlueprint* b) const {
+ // Check set attachments
+ if (a->mColorAttachmentsSet != b->mColorAttachmentsSet ||
+ a->mHasDepthStencilAttachment != b->mHasDepthStencilAttachment) {
+ return false;
+ }
+
+ // Check color formats
+ for (uint32_t i : IterateBitSet(a->mColorAttachmentsSet)) {
+ if (a->mColorFormats[i] != b->mColorFormats[i]) {
+ return false;
+ }
+ }
+
+ // Check depth stencil format
+ if (a->mHasDepthStencilAttachment) {
+ if (a->mDepthStencilFormat != b->mDepthStencilFormat) {
+ return false;
+ }
+ }
+
+ // Check sample count
+ if (a->mSampleCount != b->mSampleCount) {
+ return false;
+ }
+
+ return true;
+ }
+
+ AttachmentState::AttachmentState(DeviceBase* device, const AttachmentStateBlueprint& blueprint)
+ : AttachmentStateBlueprint(blueprint), RefCounted(), mDevice(device) {
+ }
+
+ AttachmentState::~AttachmentState() {
+ mDevice->UncacheAttachmentState(this);
+ }
+
+ std::bitset<kMaxColorAttachments> AttachmentState::GetColorAttachmentsMask() const {
+ return mColorAttachmentsSet;
+ }
+
+ dawn::TextureFormat AttachmentState::GetColorAttachmentFormat(uint32_t index) const {
+ ASSERT(mColorAttachmentsSet[index]);
+ return mColorFormats[index];
+ }
+
+ bool AttachmentState::HasDepthStencilAttachment() const {
+ return mHasDepthStencilAttachment;
+ }
+
+ dawn::TextureFormat AttachmentState::GetDepthStencilFormat() const {
+ ASSERT(mHasDepthStencilAttachment);
+ return mDepthStencilFormat;
+ }
+
+ uint32_t AttachmentState::GetSampleCount() const {
+ return mSampleCount;
+ }
+
+} // namespace dawn_native
diff --git a/src/dawn_native/AttachmentState.h b/src/dawn_native/AttachmentState.h
new file mode 100644
index 0000000..34f2c1a
--- /dev/null
+++ b/src/dawn_native/AttachmentState.h
@@ -0,0 +1,75 @@
+// Copyright 2019 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_ATTACHMENTSTATE_H_
+#define DAWNNATIVE_ATTACHMENTSTATE_H_
+
+#include "common/Constants.h"
+#include "dawn_native/RefCounted.h"
+
+#include "dawn_native/dawn_platform.h"
+
+#include <array>
+#include <bitset>
+
+namespace dawn_native {
+
+ class DeviceBase;
+
+ // AttachmentStateBlueprint and AttachmentState are separated so the AttachmentState
+ // can be constructed by copying the blueprint state instead of traversing descriptors.
+ // Also, AttachmentStateBlueprint does not need a refcount like AttachmentState.
+ class AttachmentStateBlueprint {
+ public:
+ // Note: Descriptors must be validated before the AttachmentState is constructed.
+ AttachmentStateBlueprint(const RenderPipelineDescriptor* descriptor);
+ AttachmentStateBlueprint(const RenderPassDescriptor* descriptor);
+
+ AttachmentStateBlueprint(const AttachmentStateBlueprint& rhs);
+
+ // Functors necessary for the unordered_set<AttachmentState*>-based cache.
+ struct HashFunc {
+ size_t operator()(const AttachmentStateBlueprint* attachmentState) const;
+ };
+ struct EqualityFunc {
+ bool operator()(const AttachmentStateBlueprint* a,
+ const AttachmentStateBlueprint* b) const;
+ };
+
+ protected:
+ std::bitset<kMaxColorAttachments> mColorAttachmentsSet;
+ std::array<dawn::TextureFormat, kMaxColorAttachments> mColorFormats;
+ bool mHasDepthStencilAttachment = false;
+ dawn::TextureFormat mDepthStencilFormat;
+ uint32_t mSampleCount = 0;
+ };
+
+ class AttachmentState : public AttachmentStateBlueprint, public RefCounted {
+ public:
+ AttachmentState(DeviceBase* device, const AttachmentStateBlueprint& blueprint);
+ ~AttachmentState() override;
+
+ std::bitset<kMaxColorAttachments> GetColorAttachmentsMask() const;
+ dawn::TextureFormat GetColorAttachmentFormat(uint32_t index) const;
+ bool HasDepthStencilAttachment() const;
+ dawn::TextureFormat GetDepthStencilFormat() const;
+ uint32_t GetSampleCount() const;
+
+ private:
+ DeviceBase* mDevice;
+ };
+
+} // namespace dawn_native
+
+#endif // DAWNNATIVE_ATTACHMENTSTATE_H_
diff --git a/src/dawn_native/CommandEncoder.cpp b/src/dawn_native/CommandEncoder.cpp
index c5c351a..be33223 100644
--- a/src/dawn_native/CommandEncoder.cpp
+++ b/src/dawn_native/CommandEncoder.cpp
@@ -678,22 +678,19 @@
BeginRenderPassCmd* cmd =
allocator->Allocate<BeginRenderPassCmd>(Command::BeginRenderPass);
- for (uint32_t i = 0; i < descriptor->colorAttachmentCount; ++i) {
- if (descriptor->colorAttachments[i] != nullptr) {
- cmd->colorAttachmentsSet.set(i);
- cmd->colorAttachments[i].view = descriptor->colorAttachments[i]->attachment;
- cmd->colorAttachments[i].resolveTarget =
- descriptor->colorAttachments[i]->resolveTarget;
- cmd->colorAttachments[i].loadOp = descriptor->colorAttachments[i]->loadOp;
- cmd->colorAttachments[i].storeOp = descriptor->colorAttachments[i]->storeOp;
- cmd->colorAttachments[i].clearColor =
- descriptor->colorAttachments[i]->clearColor;
- }
+ cmd->attachmentState = device->GetOrCreateAttachmentState(descriptor);
+
+ for (uint32_t i : IterateBitSet(cmd->attachmentState->GetColorAttachmentsMask())) {
+ cmd->colorAttachments[i].view = descriptor->colorAttachments[i]->attachment;
+ cmd->colorAttachments[i].resolveTarget =
+ descriptor->colorAttachments[i]->resolveTarget;
+ cmd->colorAttachments[i].loadOp = descriptor->colorAttachments[i]->loadOp;
+ cmd->colorAttachments[i].storeOp = descriptor->colorAttachments[i]->storeOp;
+ cmd->colorAttachments[i].clearColor =
+ descriptor->colorAttachments[i]->clearColor;
}
- cmd->hasDepthStencilAttachment = descriptor->depthStencilAttachment != nullptr;
- if (cmd->hasDepthStencilAttachment) {
- cmd->hasDepthStencilAttachment = true;
+ if (cmd->attachmentState->HasDepthStencilAttachment()) {
cmd->depthStencilAttachment.view =
descriptor->depthStencilAttachment->attachment;
cmd->depthStencilAttachment.clearDepth =
@@ -712,7 +709,6 @@
cmd->width = width;
cmd->height = height;
- cmd->sampleCount = sampleCount;
return {};
});
@@ -1071,7 +1067,7 @@
CommandBufferStateTracker persistentState;
// Track usage of the render pass attachments
- for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) {
+ for (uint32_t i : IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
RenderPassColorAttachmentInfo* colorAttachment = &renderPass->colorAttachments[i];
TextureBase* texture = colorAttachment->view->GetTexture();
usageTracker.TextureUsedAs(texture, dawn::TextureUsageBit::OutputAttachment);
@@ -1083,7 +1079,7 @@
}
}
- if (renderPass->hasDepthStencilAttachment) {
+ if (renderPass->attachmentState->HasDepthStencilAttachment()) {
TextureBase* texture = renderPass->depthStencilAttachment.view->GetTexture();
usageTracker.TextureUsedAs(texture, dawn::TextureUsageBit::OutputAttachment);
}
diff --git a/src/dawn_native/Commands.h b/src/dawn_native/Commands.h
index 24e4e11..442cc95 100644
--- a/src/dawn_native/Commands.h
+++ b/src/dawn_native/Commands.h
@@ -17,6 +17,7 @@
#include "common/Constants.h"
+#include "dawn_native/AttachmentState.h"
#include "dawn_native/Texture.h"
#include "dawn_native/dawn_platform.h"
@@ -80,15 +81,13 @@
};
struct BeginRenderPassCmd {
- std::bitset<kMaxColorAttachments> colorAttachmentsSet;
+ Ref<AttachmentState> attachmentState;
RenderPassColorAttachmentInfo colorAttachments[kMaxColorAttachments];
- bool hasDepthStencilAttachment;
RenderPassDepthStencilAttachmentInfo depthStencilAttachment;
- // Cache the width, height and sample count of all attachments for convenience
+ // Cache the width and height of all attachments for convenience
uint32_t width;
uint32_t height;
- uint32_t sampleCount;
};
struct BufferCopy {
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index 0901c7d..d32f02ab 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -15,6 +15,7 @@
#include "dawn_native/Device.h"
#include "dawn_native/Adapter.h"
+#include "dawn_native/AttachmentState.h"
#include "dawn_native/BindGroup.h"
#include "dawn_native/BindGroupLayout.h"
#include "dawn_native/Buffer.h"
@@ -47,6 +48,7 @@
std::unordered_set<Object*, typename Object::HashFunc, typename Object::EqualityFunc>;
struct DeviceBase::Caches {
+ ContentLessObjectCache<AttachmentStateBlueprint> attachmentStates;
ContentLessObjectCache<BindGroupLayoutBase> bindGroupLayouts;
ContentLessObjectCache<ComputePipelineBase> computePipelines;
ContentLessObjectCache<PipelineLayoutBase> pipelineLayouts;
@@ -249,6 +251,43 @@
ASSERT(removedCount == 1);
}
+ AttachmentState* DeviceBase::GetOrCreateAttachmentState(
+ const RenderPipelineDescriptor* descriptor) {
+ AttachmentStateBlueprint blueprint(descriptor);
+
+ auto iter = mCaches->attachmentStates.find(&blueprint);
+ if (iter != mCaches->attachmentStates.end()) {
+ AttachmentState* cachedState = static_cast<AttachmentState*>(*iter);
+ cachedState->Reference();
+ return cachedState;
+ }
+
+ AttachmentState* attachmentState = new AttachmentState(this, blueprint);
+ mCaches->attachmentStates.insert(attachmentState);
+ return attachmentState;
+ }
+
+ AttachmentState* DeviceBase::GetOrCreateAttachmentState(
+ const RenderPassDescriptor* descriptor) {
+ AttachmentStateBlueprint blueprint(descriptor);
+
+ auto iter = mCaches->attachmentStates.find(&blueprint);
+ if (iter != mCaches->attachmentStates.end()) {
+ AttachmentState* cachedState = static_cast<AttachmentState*>(*iter);
+ cachedState->Reference();
+ return cachedState;
+ }
+
+ AttachmentState* attachmentState = new AttachmentState(this, blueprint);
+ mCaches->attachmentStates.insert(attachmentState);
+ return attachmentState;
+ }
+
+ void DeviceBase::UncacheAttachmentState(AttachmentState* obj) {
+ size_t removedCount = mCaches->attachmentStates.erase(obj);
+ ASSERT(removedCount == 1);
+ }
+
// Object creation API methods
BindGroupBase* DeviceBase::CreateBindGroup(const BindGroupDescriptor* descriptor) {
diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h
index ad99a8f..3c3d6c7 100644
--- a/src/dawn_native/Device.h
+++ b/src/dawn_native/Device.h
@@ -32,6 +32,7 @@
using ErrorCallback = void (*)(const char* errorMessage, void* userData);
class AdapterBase;
+ class AttachmentState;
class FenceSignalTracker;
class DynamicUploader;
class StagingBufferBase;
@@ -113,6 +114,10 @@
const ShaderModuleDescriptor* descriptor);
void UncacheShaderModule(ShaderModuleBase* obj);
+ AttachmentState* GetOrCreateAttachmentState(const RenderPipelineDescriptor* descriptor);
+ AttachmentState* GetOrCreateAttachmentState(const RenderPassDescriptor* descriptor);
+ void UncacheAttachmentState(AttachmentState* obj);
+
// Dawn API
BindGroupBase* CreateBindGroup(const BindGroupDescriptor* descriptor);
BindGroupLayoutBase* CreateBindGroupLayout(const BindGroupLayoutDescriptor* descriptor);
diff --git a/src/dawn_native/RenderPipeline.cpp b/src/dawn_native/RenderPipeline.cpp
index 421abf2..db022c7 100644
--- a/src/dawn_native/RenderPipeline.cpp
+++ b/src/dawn_native/RenderPipeline.cpp
@@ -349,9 +349,8 @@
descriptor->layout,
dawn::ShaderStageBit::Vertex | dawn::ShaderStageBit::Fragment),
mVertexInput(*descriptor->vertexInput),
- mHasDepthStencilAttachment(descriptor->depthStencilState != nullptr),
+ mAttachmentState(device->GetOrCreateAttachmentState(descriptor)),
mPrimitiveTopology(descriptor->primitiveTopology),
- mSampleCount(descriptor->sampleCount),
mSampleMask(descriptor->sampleMask),
mAlphaToCoverageEnabled(descriptor->alphaToCoverageEnabled),
mVertexModule(descriptor->vertexStage->module),
@@ -385,7 +384,7 @@
mRasterizationState = RasterizationStateDescriptor();
}
- if (mHasDepthStencilAttachment) {
+ if (mAttachmentState->HasDepthStencilAttachment()) {
mDepthStencilState = *descriptor->depthStencilState;
} else {
// These default values below are useful for backends to fill information.
@@ -406,8 +405,7 @@
mDepthStencilState.stencilWriteMask = 0xff;
}
- for (uint32_t i = 0; i < descriptor->colorStateCount; ++i) {
- mColorAttachmentsSet.set(i);
+ for (uint32_t i : IterateBitSet(mAttachmentState->GetColorAttachmentsMask())) {
mColorStates[i] = *descriptor->colorStates[i];
}
@@ -487,12 +485,12 @@
std::bitset<kMaxColorAttachments> RenderPipelineBase::GetColorAttachmentsMask() const {
ASSERT(!IsError());
- return mColorAttachmentsSet;
+ return mAttachmentState->GetColorAttachmentsMask();
}
bool RenderPipelineBase::HasDepthStencilAttachment() const {
ASSERT(!IsError());
- return mHasDepthStencilAttachment;
+ return mAttachmentState->HasDepthStencilAttachment();
}
dawn::TextureFormat RenderPipelineBase::GetColorAttachmentFormat(uint32_t attachment) const {
@@ -502,49 +500,22 @@
dawn::TextureFormat RenderPipelineBase::GetDepthStencilFormat() const {
ASSERT(!IsError());
- ASSERT(mHasDepthStencilAttachment);
+ ASSERT(mAttachmentState->HasDepthStencilAttachment());
return mDepthStencilState.format;
}
uint32_t RenderPipelineBase::GetSampleCount() const {
ASSERT(!IsError());
- return mSampleCount;
+ return mAttachmentState->GetSampleCount();
}
MaybeError RenderPipelineBase::ValidateCompatibleWith(
const BeginRenderPassCmd* renderPass) const {
ASSERT(!IsError());
- // TODO(cwallez@chromium.org): This is called on every SetPipeline command. Optimize it for
- // example by caching some "attachment compatibility" object that would make the
- // compatibility check a single pointer comparison.
- if (renderPass->colorAttachmentsSet != mColorAttachmentsSet) {
+ if (renderPass->attachmentState.Get() != mAttachmentState.Get()) {
return DAWN_VALIDATION_ERROR(
- "Pipeline doesn't have same color attachments set as renderPass");
- }
-
- for (uint32_t i : IterateBitSet(mColorAttachmentsSet)) {
- if (renderPass->colorAttachments[i].view->GetFormat().format !=
- mColorStates[i].format) {
- return DAWN_VALIDATION_ERROR(
- "Pipeline color attachment format doesn't match renderPass");
- }
- }
-
- if (renderPass->hasDepthStencilAttachment != mHasDepthStencilAttachment) {
- return DAWN_VALIDATION_ERROR(
- "Pipeline depth stencil attachment doesn't match renderPass");
- }
-
- if (mHasDepthStencilAttachment &&
- (renderPass->depthStencilAttachment.view->GetFormat().format !=
- mDepthStencilState.format)) {
- return DAWN_VALIDATION_ERROR(
- "Pipeline depth stencil attachment format doesn't match renderPass");
- }
-
- if (renderPass->sampleCount != mSampleCount) {
- return DAWN_VALIDATION_ERROR("Pipeline sample count doesn't match renderPass");
+ "Pipeline attachment state is not compatible with render pass");
}
return {};
@@ -564,20 +535,23 @@
HashCombine(&hash, pipeline->mVertexModule.Get(), pipeline->mFragmentEntryPoint);
HashCombine(&hash, pipeline->mFragmentModule.Get(), pipeline->mFragmentEntryPoint);
+ // Hierarchically hash the attachment state.
+ // It contains the attachments set, texture formats, and sample count.
+ HashCombine(&hash, pipeline->mAttachmentState.Get());
+
// Hash attachments
- HashCombine(&hash, pipeline->mColorAttachmentsSet);
- for (uint32_t i : IterateBitSet(pipeline->mColorAttachmentsSet)) {
+ for (uint32_t i : IterateBitSet(pipeline->mAttachmentState->GetColorAttachmentsMask())) {
const ColorStateDescriptor& desc = *pipeline->GetColorStateDescriptor(i);
- HashCombine(&hash, desc.format, desc.writeMask);
+ 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);
}
- if (pipeline->mHasDepthStencilAttachment) {
+ if (pipeline->mAttachmentState->HasDepthStencilAttachment()) {
const DepthStencilStateDescriptor& desc = pipeline->mDepthStencilState;
- HashCombine(&hash, desc.format, desc.depthWriteEnabled, desc.depthCompare);
+ 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);
@@ -608,8 +582,8 @@
}
// Hash other state
- HashCombine(&hash, pipeline->mSampleCount, pipeline->mPrimitiveTopology,
- pipeline->mSampleMask, pipeline->mAlphaToCoverageEnabled);
+ HashCombine(&hash, pipeline->mPrimitiveTopology, pipeline->mSampleMask,
+ pipeline->mAlphaToCoverageEnabled);
return hash;
}
@@ -624,16 +598,16 @@
return false;
}
- // Check attachments
- if (a->mColorAttachmentsSet != b->mColorAttachmentsSet ||
- a->mHasDepthStencilAttachment != b->mHasDepthStencilAttachment) {
+ // Check the attachment state.
+ // It contains the attachments set, texture formats, and sample count.
+ if (a->mAttachmentState.Get() != b->mAttachmentState.Get()) {
return false;
}
- for (uint32_t i : IterateBitSet(a->mColorAttachmentsSet)) {
+ for (uint32_t i : IterateBitSet(a->mAttachmentState->GetColorAttachmentsMask())) {
const ColorStateDescriptor& descA = *a->GetColorStateDescriptor(i);
const ColorStateDescriptor& descB = *b->GetColorStateDescriptor(i);
- if (descA.format != descB.format || descA.writeMask != descB.writeMask) {
+ if (descA.writeMask != descB.writeMask) {
return false;
}
if (descA.colorBlend.operation != descB.colorBlend.operation ||
@@ -648,11 +622,10 @@
}
}
- if (a->mHasDepthStencilAttachment) {
+ if (a->mAttachmentState->HasDepthStencilAttachment()) {
const DepthStencilStateDescriptor& descA = a->mDepthStencilState;
const DepthStencilStateDescriptor& descB = b->mDepthStencilState;
- if (descA.format != descB.format ||
- descA.depthWriteEnabled != descB.depthWriteEnabled ||
+ if (descA.depthWriteEnabled != descB.depthWriteEnabled ||
descA.depthCompare != descB.depthCompare) {
return false;
}
@@ -720,8 +693,7 @@
}
// Check other state
- if (a->mSampleCount != b->mSampleCount || a->mPrimitiveTopology != b->mPrimitiveTopology ||
- a->mSampleMask != b->mSampleMask ||
+ if (a->mPrimitiveTopology != b->mPrimitiveTopology || a->mSampleMask != b->mSampleMask ||
a->mAlphaToCoverageEnabled != b->mAlphaToCoverageEnabled) {
return false;
}
diff --git a/src/dawn_native/RenderPipeline.h b/src/dawn_native/RenderPipeline.h
index dfc46f7..f8e884e 100644
--- a/src/dawn_native/RenderPipeline.h
+++ b/src/dawn_native/RenderPipeline.h
@@ -15,6 +15,7 @@
#ifndef DAWNNATIVE_RENDERPIPELINE_H_
#define DAWNNATIVE_RENDERPIPELINE_H_
+#include "dawn_native/AttachmentState.h"
#include "dawn_native/Pipeline.h"
#include "dawn_native/dawn_platform.h"
@@ -102,15 +103,13 @@
std::array<VertexBufferInfo, kMaxVertexBuffers> mInputInfos;
// Attachments
- bool mHasDepthStencilAttachment = false;
+ Ref<AttachmentState> mAttachmentState;
DepthStencilStateDescriptor mDepthStencilState;
- std::bitset<kMaxColorAttachments> mColorAttachmentsSet;
std::array<ColorStateDescriptor, kMaxColorAttachments> mColorStates;
// Other state
dawn::PrimitiveTopology mPrimitiveTopology;
RasterizationStateDescriptor mRasterizationState;
- uint32_t mSampleCount;
uint32_t mSampleMask;
bool mAlphaToCoverageEnabled;
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index 3e201e8..a70338c 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -249,8 +249,9 @@
void TrackRenderPass(const BeginRenderPassCmd* renderPass) {
DAWN_ASSERT(mRTVHeap.Get() == nullptr && mDSVHeap.Get() == nullptr);
- mNumRTVs += static_cast<uint32_t>(renderPass->colorAttachmentsSet.count());
- if (renderPass->hasDepthStencilAttachment) {
+ mNumRTVs += static_cast<uint32_t>(
+ renderPass->attachmentState->GetColorAttachmentsMask().count());
+ if (renderPass->attachmentState->HasDepthStencilAttachment()) {
++mNumDSVs;
}
}
@@ -273,9 +274,11 @@
OMSetRenderTargetArgs args = {};
unsigned int rtvIndex = 0;
- uint32_t rtvCount = static_cast<uint32_t>(renderPass->colorAttachmentsSet.count());
+ uint32_t rtvCount = static_cast<uint32_t>(
+ renderPass->attachmentState->GetColorAttachmentsMask().count());
DAWN_ASSERT(mAllocatedRTVs + rtvCount <= mNumRTVs);
- for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) {
+ for (uint32_t i :
+ IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
TextureView* view = ToBackend(renderPass->colorAttachments[i].view).Get();
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = mRTVHeap.GetCPUHandle(mAllocatedRTVs);
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = view->GetRTVDescriptor();
@@ -288,7 +291,7 @@
}
args.numRTVs = rtvIndex;
- if (renderPass->hasDepthStencilAttachment) {
+ if (renderPass->attachmentState->HasDepthStencilAttachment()) {
DAWN_ASSERT(mAllocatedDSVs < mNumDSVs);
TextureView* view = ToBackend(renderPass->depthStencilAttachment.view).Get();
D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = mDSVHeap.GetCPUHandle(mAllocatedDSVs);
@@ -372,7 +375,8 @@
BeginRenderPassCmd* renderPass) {
ASSERT(renderPass != nullptr);
- for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) {
+ for (uint32_t i :
+ IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
TextureViewBase* resolveTarget =
renderPass->colorAttachments[i].resolveTarget.Get();
if (resolveTarget == nullptr) {
@@ -759,7 +763,8 @@
// Clear framebuffer attachments as needed and transition to render target
{
- for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) {
+ for (uint32_t i :
+ IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
auto& attachmentInfo = renderPass->colorAttachments[i];
TextureView* view = ToBackend(attachmentInfo.view.Get());
@@ -785,7 +790,7 @@
}
}
- if (renderPass->hasDepthStencilAttachment) {
+ if (renderPass->attachmentState->HasDepthStencilAttachment()) {
auto& attachmentInfo = renderPass->depthStencilAttachment;
Texture* texture = ToBackend(renderPass->depthStencilAttachment.view->GetTexture());
if ((texture->GetFormat().HasDepth() &&
@@ -864,7 +869,7 @@
// TODO(brandon1.jones@intel.com): avoid calling this function and enable MSAA
// resolve in D3D12 render pass on the platforms that support this feature.
- if (renderPass->sampleCount > 1) {
+ if (renderPass->attachmentState->GetSampleCount() > 1) {
ResolveMultisampledRenderPass(commandList, renderPass);
}
return;
diff --git a/src/dawn_native/metal/CommandBufferMTL.mm b/src/dawn_native/metal/CommandBufferMTL.mm
index c6c440a..5f6331f 100644
--- a/src/dawn_native/metal/CommandBufferMTL.mm
+++ b/src/dawn_native/metal/CommandBufferMTL.mm
@@ -50,7 +50,8 @@
MTLRenderPassDescriptor* CreateMTLRenderPassDescriptor(BeginRenderPassCmd* renderPass) {
MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
- for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) {
+ for (uint32_t i :
+ IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
auto& attachmentInfo = renderPass->colorAttachments[i];
if (attachmentInfo.loadOp == dawn::LoadOp::Clear) {
@@ -83,7 +84,7 @@
}
}
- if (renderPass->hasDepthStencilAttachment) {
+ if (renderPass->attachmentState->HasDepthStencilAttachment()) {
auto& attachmentInfo = renderPass->depthStencilAttachment;
// TODO(jiawei.shao@intel.com): support rendering into a layer of a texture.
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index 8e4a3ea..c520a3f 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -283,7 +283,8 @@
GLuint readFbo = 0;
GLuint writeFbo = 0;
- for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) {
+ for (uint32_t i :
+ IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
if (renderPass->colorAttachments[i].resolveTarget.Get() != nullptr) {
if (readFbo == 0) {
ASSERT(writeFbo == 0);
@@ -590,7 +591,8 @@
// Construct GL framebuffer
unsigned int attachmentCount = 0;
- for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) {
+ for (uint32_t i :
+ IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
TextureViewBase* textureView = renderPass->colorAttachments[i].view.Get();
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
@@ -617,7 +619,7 @@
}
gl.DrawBuffers(attachmentCount, drawBuffers.data());
- if (renderPass->hasDepthStencilAttachment) {
+ if (renderPass->attachmentState->HasDepthStencilAttachment()) {
TextureViewBase* textureView = renderPass->depthStencilAttachment.view.Get();
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
const Format& format = textureView->GetTexture()->GetFormat();
@@ -660,7 +662,8 @@
// Clear framebuffer attachments as needed
{
- for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) {
+ for (uint32_t i :
+ IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
const auto& attachmentInfo = renderPass->colorAttachments[i];
// Load op - color
@@ -670,7 +673,7 @@
}
}
- if (renderPass->hasDepthStencilAttachment) {
+ if (renderPass->attachmentState->HasDepthStencilAttachment()) {
const auto& attachmentInfo = renderPass->depthStencilAttachment;
const Format& attachmentFormat = attachmentInfo.view->GetTexture()->GetFormat();
@@ -710,7 +713,7 @@
case Command::EndRenderPass: {
mCommands.NextCommand<EndRenderPassCmd>();
- if (renderPass->sampleCount > 1) {
+ if (renderPass->attachmentState->GetSampleCount() > 1) {
ResolveMultisampledRenderTargets(gl, renderPass);
}
gl.DeleteFramebuffers(1, &fbo);
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index 8f1afa3..c682a6d 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -197,7 +197,8 @@
{
RenderPassCacheQuery query;
- for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) {
+ for (uint32_t i :
+ IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
auto& attachmentInfo = renderPass->colorAttachments[i];
TextureView* view = ToBackend(attachmentInfo.view.Get());
bool hasResolveTarget = attachmentInfo.resolveTarget.Get() != nullptr;
@@ -223,7 +224,7 @@
hasResolveTarget);
}
- if (renderPass->hasDepthStencilAttachment) {
+ if (renderPass->attachmentState->HasDepthStencilAttachment()) {
auto& attachmentInfo = renderPass->depthStencilAttachment;
query.SetDepthStencil(attachmentInfo.view->GetTexture()->GetFormat().format,
attachmentInfo.depthLoadOp, attachmentInfo.stencilLoadOp);
@@ -238,7 +239,7 @@
}
}
- query.SetSampleCount(renderPass->sampleCount);
+ query.SetSampleCount(renderPass->attachmentState->GetSampleCount());
renderPassVK = device->GetRenderPassCache()->GetRenderPass(query);
}
@@ -252,7 +253,8 @@
// Fill in the attachment info that will be chained in the framebuffer create info.
std::array<VkImageView, kMaxColorAttachments * 2 + 1> attachments;
- for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) {
+ for (uint32_t i :
+ IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
auto& attachmentInfo = renderPass->colorAttachments[i];
TextureView* view = ToBackend(attachmentInfo.view.Get());
@@ -266,7 +268,7 @@
attachmentCount++;
}
- if (renderPass->hasDepthStencilAttachment) {
+ if (renderPass->attachmentState->HasDepthStencilAttachment()) {
auto& attachmentInfo = renderPass->depthStencilAttachment;
TextureView* view = ToBackend(attachmentInfo.view.Get());
@@ -278,7 +280,8 @@
attachmentCount++;
}
- for (uint32_t i : IterateBitSet(renderPass->colorAttachmentsSet)) {
+ for (uint32_t i :
+ IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
if (renderPass->colorAttachments[i].resolveTarget.Get() != nullptr) {
TextureView* view =
ToBackend(renderPass->colorAttachments[i].resolveTarget.Get());