Add validation rule for depth/stencil between bundle and pass
If we use render bundle, the compability validation between
writeDepth/Stencil in DepthStencilState in render pipeline and
depth/stencilReadOnly in DepthStencilAttachment in render pass
will become two steps:
1. validation between render pipeline and render bundle during
RenderBundleEncoder's SetPipeline().
2. validation between render bundle and render pass during
RenderPassEncoder's ExecuteBundles().
So, render bundle is like a bridge for this compability validation
between pipeline and pass.
The first step has been done in previous patch. The patch does
the second step.
Bug: dawn:485
Change-Id: I1226494e901c07bdb9f565bce7b9073d420f2fe2
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/66842
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Yunchao He <yunchao.he@intel.com>
diff --git a/src/dawn_native/RenderBundle.cpp b/src/dawn_native/RenderBundle.cpp
index 8a7fe73..81c88a7 100644
--- a/src/dawn_native/RenderBundle.cpp
+++ b/src/dawn_native/RenderBundle.cpp
@@ -25,12 +25,16 @@
RenderBundleBase::RenderBundleBase(RenderBundleEncoder* encoder,
const RenderBundleDescriptor* descriptor,
Ref<AttachmentState> attachmentState,
+ bool depthReadOnly,
+ bool stencilReadOnly,
RenderPassResourceUsage resourceUsage,
IndirectDrawMetadata indirectDrawMetadata)
: ApiObjectBase(encoder->GetDevice(), kLabelNotImplemented),
mCommands(encoder->AcquireCommands()),
mIndirectDrawMetadata(std::move(indirectDrawMetadata)),
mAttachmentState(std::move(attachmentState)),
+ mDepthReadOnly(depthReadOnly),
+ mStencilReadOnly(stencilReadOnly),
mResourceUsage(std::move(resourceUsage)) {
}
@@ -60,6 +64,16 @@
return mAttachmentState.Get();
}
+ bool RenderBundleBase::IsDepthReadOnly() const {
+ ASSERT(!IsError());
+ return mDepthReadOnly;
+ }
+
+ bool RenderBundleBase::IsStencilReadOnly() const {
+ ASSERT(!IsError());
+ return mStencilReadOnly;
+ }
+
const RenderPassResourceUsage& RenderBundleBase::GetResourceUsage() const {
ASSERT(!IsError());
return mResourceUsage;
diff --git a/src/dawn_native/RenderBundle.h b/src/dawn_native/RenderBundle.h
index 37517d9..17a79af 100644
--- a/src/dawn_native/RenderBundle.h
+++ b/src/dawn_native/RenderBundle.h
@@ -38,6 +38,8 @@
RenderBundleBase(RenderBundleEncoder* encoder,
const RenderBundleDescriptor* descriptor,
Ref<AttachmentState> attachmentState,
+ bool depthReadOnly,
+ bool stencilReadOnly,
RenderPassResourceUsage resourceUsage,
IndirectDrawMetadata indirectDrawMetadata);
@@ -48,6 +50,8 @@
CommandIterator* GetCommands();
const AttachmentState* GetAttachmentState() const;
+ bool IsDepthReadOnly() const;
+ bool IsStencilReadOnly() const;
const RenderPassResourceUsage& GetResourceUsage() const;
const IndirectDrawMetadata& GetIndirectDrawMetadata();
@@ -60,6 +64,8 @@
CommandIterator mCommands;
IndirectDrawMetadata mIndirectDrawMetadata;
Ref<AttachmentState> mAttachmentState;
+ bool mDepthReadOnly;
+ bool mStencilReadOnly;
RenderPassResourceUsage mResourceUsage;
};
diff --git a/src/dawn_native/RenderBundleEncoder.cpp b/src/dawn_native/RenderBundleEncoder.cpp
index 4c68c4c..19f8c64 100644
--- a/src/dawn_native/RenderBundleEncoder.cpp
+++ b/src/dawn_native/RenderBundleEncoder.cpp
@@ -144,7 +144,8 @@
DAWN_TRY(ValidateFinish(usages));
}
- return new RenderBundleBase(this, descriptor, AcquireAttachmentState(), std::move(usages),
+ return new RenderBundleBase(this, descriptor, AcquireAttachmentState(), IsDepthReadOnly(),
+ IsStencilReadOnly(), std::move(usages),
std::move(mIndirectDrawMetadata));
}
diff --git a/src/dawn_native/RenderEncoderBase.cpp b/src/dawn_native/RenderEncoderBase.cpp
index c4ff78c..d519f0d 100644
--- a/src/dawn_native/RenderEncoderBase.cpp
+++ b/src/dawn_native/RenderEncoderBase.cpp
@@ -59,6 +59,16 @@
return mAttachmentState.Get();
}
+ bool RenderEncoderBase::IsDepthReadOnly() const {
+ ASSERT(!IsError());
+ return mDepthReadOnly;
+ }
+
+ bool RenderEncoderBase::IsStencilReadOnly() const {
+ ASSERT(!IsError());
+ return mStencilReadOnly;
+ }
+
Ref<AttachmentState> RenderEncoderBase::AcquireAttachmentState() {
return std::move(mAttachmentState);
}
diff --git a/src/dawn_native/RenderEncoderBase.h b/src/dawn_native/RenderEncoderBase.h
index bc17ba7..afed1bb 100644
--- a/src/dawn_native/RenderEncoderBase.h
+++ b/src/dawn_native/RenderEncoderBase.h
@@ -59,6 +59,8 @@
const uint32_t* dynamicOffsets = nullptr);
const AttachmentState* GetAttachmentState() const;
+ bool IsDepthReadOnly() const;
+ bool IsStencilReadOnly() const;
Ref<AttachmentState> AcquireAttachmentState();
protected:
diff --git a/src/dawn_native/RenderPassEncoder.cpp b/src/dawn_native/RenderPassEncoder.cpp
index fccf652..6cad45b 100644
--- a/src/dawn_native/RenderPassEncoder.cpp
+++ b/src/dawn_native/RenderPassEncoder.cpp
@@ -233,15 +233,32 @@
this,
[&](CommandAllocator* allocator) -> MaybeError {
if (IsValidationEnabled()) {
+ const AttachmentState* attachmentState = GetAttachmentState();
+ bool depthReadOnlyInPass = IsDepthReadOnly();
+ bool stencilReadOnlyInPass = IsStencilReadOnly();
for (uint32_t i = 0; i < count; ++i) {
DAWN_TRY(GetDevice()->ValidateObject(renderBundles[i]));
// TODO(dawn:563): Give more detail about why the states are incompatible.
DAWN_INVALID_IF(
- GetAttachmentState() != renderBundles[i]->GetAttachmentState(),
+ attachmentState != renderBundles[i]->GetAttachmentState(),
"Attachment state of renderBundles[%i] (%s) is not compatible with "
"attachment state of %s.",
i, renderBundles[i], this);
+
+ bool depthReadOnlyInBundle = renderBundles[i]->IsDepthReadOnly();
+ DAWN_INVALID_IF(
+ depthReadOnlyInPass != depthReadOnlyInBundle,
+ "DepthReadOnly (%u) of renderBundle[%i] (%s) is not compatible "
+ "with DepthReadOnly (%u) of %s.",
+ depthReadOnlyInBundle, i, renderBundles[i], depthReadOnlyInPass, this);
+
+ bool stencilReadOnlyInBundle = renderBundles[i]->IsStencilReadOnly();
+ DAWN_INVALID_IF(stencilReadOnlyInPass != stencilReadOnlyInBundle,
+ "StencilReadOnly (%u) of renderBundle[%i] (%s) is not "
+ "compatible with StencilReadOnly (%u) of %s.",
+ stencilReadOnlyInBundle, i, renderBundles[i],
+ stencilReadOnlyInPass, this);
}
}
diff --git a/src/tests/unittests/validation/PipelineAndPassCompatibilityTests.cpp b/src/tests/unittests/validation/PipelineAndPassCompatibilityTests.cpp
index e30299f..e6838fe 100644
--- a/src/tests/unittests/validation/PipelineAndPassCompatibilityTests.cpp
+++ b/src/tests/unittests/validation/PipelineAndPassCompatibilityTests.cpp
@@ -19,6 +19,9 @@
#include "tests/unittests/validation/ValidationTest.h"
constexpr static uint32_t kSize = 4;
+// Note that format Depth24PlusStencil8 has both depth and stencil aspects, so parameters
+// depthReadOnly and stencilReadOnly should be the same in render pass and render bundle.
+wgpu::TextureFormat kFormat = wgpu::TextureFormat::Depth24PlusStencil8;
namespace {
@@ -76,13 +79,9 @@
}
};
- // Test depthWrite/stencilWrite in DepthStencilState in pipeline vs
- // depthReadOnly/stencilReadOnly in DepthStencilAttachment in pass
+ // Test depthWrite/stencilWrite in DepthStencilState in render pipeline vs
+ // depthReadOnly/stencilReadOnly in DepthStencilAttachment in render pass.
TEST_F(RenderPipelineAndPassCompatibilityTests, WriteAndReadOnlyConflictForDepthStencil) {
- wgpu::TextureFormat kFormat = wgpu::TextureFormat::Depth24PlusStencil8;
- // If the format has both depth and stencil aspects, depthReadOnly and stencilReadOnly
- // should be the same. So it is not necessary to set two separate booleans like
- // depthReadOnlyInPass and stencilReadOnlyInPass.
for (bool depthStencilReadOnlyInPass : {true, false}) {
for (bool depthWriteInPipeline : {true, false}) {
for (bool stencilWriteInPipeline : {true, false}) {
@@ -106,14 +105,10 @@
}
}
- // Test depthWrite/stencilWrite in DepthStencilState in pipeline vs
- // depthReadOnly/stencilReadOnly in RenderBundleEncoderDescriptor in RenderBundle
+ // Test depthWrite/stencilWrite in DepthStencilState in render pipeline vs
+ // depthReadOnly/stencilReadOnly in RenderBundleEncoderDescriptor in render bundle.
TEST_F(RenderPipelineAndPassCompatibilityTests,
- WriteAndReadOnlyConflictForDepthStencilWithRenderBundle) {
- wgpu::TextureFormat kFormat = wgpu::TextureFormat::Depth24PlusStencil8;
- // If the format has both depth and stencil aspects, depthReadOnly and stencilReadOnly
- // should be the same. So it is not necessary to set two separate booleans like
- // depthReadOnlyInBundle and stencilReadOnlyInBundle.
+ WriteAndReadOnlyConflictForDepthStencilBetweenPipelineAndBundle) {
for (bool depthStencilReadOnlyInBundle : {true, false}) {
utils::ComboRenderBundleEncoderDescriptor desc = {};
desc.depthStencilFormat = kFormat;
@@ -139,6 +134,45 @@
}
}
+ // Test depthReadOnly/stencilReadOnly in RenderBundleEncoderDescriptor in render bundle vs
+ // depthReadOnly/stencilReadOnly in DepthStencilAttachment in render pass.
+ TEST_F(RenderPipelineAndPassCompatibilityTests,
+ WriteAndReadOnlyConflictForDepthStencilBetweenBundleAndPass) {
+ for (bool depthStencilReadOnlyInPass : {true, false}) {
+ for (bool depthStencilReadOnlyInBundle : {true, false}) {
+ for (bool emptyBundle : {true, false}) {
+ // Create render bundle, with or without a pipeline
+ utils::ComboRenderBundleEncoderDescriptor desc = {};
+ desc.depthStencilFormat = kFormat;
+ desc.depthReadOnly = depthStencilReadOnlyInBundle;
+ desc.stencilReadOnly = depthStencilReadOnlyInBundle;
+ wgpu::RenderBundleEncoder renderBundleEncoder =
+ device.CreateRenderBundleEncoder(&desc);
+ if (!emptyBundle) {
+ wgpu::RenderPipeline pipeline = CreatePipeline(
+ kFormat, !depthStencilReadOnlyInBundle, !depthStencilReadOnlyInBundle);
+ renderBundleEncoder.SetPipeline(pipeline);
+ renderBundleEncoder.Draw(3);
+ }
+ wgpu::RenderBundle bundle = renderBundleEncoder.Finish();
+
+ // Create render pass and call ExecuteBundles()
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ utils::ComboRenderPassDescriptor passDescriptor = CreateRenderPassDescriptor(
+ kFormat, depthStencilReadOnlyInPass, depthStencilReadOnlyInPass);
+ wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&passDescriptor);
+ pass.ExecuteBundles(1, &bundle);
+ pass.EndPass();
+ if (depthStencilReadOnlyInPass != depthStencilReadOnlyInBundle) {
+ ASSERT_DEVICE_ERROR(encoder.Finish());
+ } else {
+ encoder.Finish();
+ }
+ }
+ }
+ }
+ }
+
// TODO(dawn:485): add more tests. For example:
// - depth/stencil attachment should be designated if depth/stencil test is enabled.
// - pipeline and pass compatibility tests for color attachment(s).