• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "utils/ComboRenderBundleEncoderDescriptor.h"
16 #include "utils/ComboRenderPipelineDescriptor.h"
17 #include "utils/WGPUHelpers.h"
18 
19 #include "tests/unittests/validation/ValidationTest.h"
20 
21 constexpr static uint32_t kSize = 4;
22 // Note that format Depth24PlusStencil8 has both depth and stencil aspects, so parameters
23 // depthReadOnly and stencilReadOnly should be the same in render pass and render bundle.
24 wgpu::TextureFormat kFormat = wgpu::TextureFormat::Depth24PlusStencil8;
25 
26 namespace {
27 
28     class RenderPipelineAndPassCompatibilityTests : public ValidationTest {
29       public:
CreatePipeline(wgpu::TextureFormat format,bool enableDepthWrite,bool enableStencilWrite)30         wgpu::RenderPipeline CreatePipeline(wgpu::TextureFormat format,
31                                             bool enableDepthWrite,
32                                             bool enableStencilWrite) {
33             // Create a NoOp pipeline
34             utils::ComboRenderPipelineDescriptor pipelineDescriptor;
35             pipelineDescriptor.vertex.module = utils::CreateShaderModule(device, R"(
36                 [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
37                     return vec4<f32>();
38                 })");
39             pipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, R"(
40                 [[stage(fragment)]] fn main() {
41                 })");
42             pipelineDescriptor.cFragment.targets = nullptr;
43             pipelineDescriptor.cFragment.targetCount = 0;
44 
45             // Enable depth/stencil write if needed
46             wgpu::DepthStencilState* depthStencil = pipelineDescriptor.EnableDepthStencil(format);
47             if (enableDepthWrite) {
48                 depthStencil->depthWriteEnabled = true;
49             }
50             if (enableStencilWrite) {
51                 depthStencil->stencilFront.failOp = wgpu::StencilOperation::Replace;
52             }
53             return device.CreateRenderPipeline(&pipelineDescriptor);
54         }
55 
CreateRenderPassDescriptor(wgpu::TextureFormat format,bool depthReadOnly,bool stencilReadOnly)56         utils::ComboRenderPassDescriptor CreateRenderPassDescriptor(wgpu::TextureFormat format,
57                                                                     bool depthReadOnly,
58                                                                     bool stencilReadOnly) {
59             wgpu::TextureDescriptor textureDescriptor = {};
60             textureDescriptor.size = {kSize, kSize, 1};
61             textureDescriptor.format = format;
62             textureDescriptor.usage = wgpu::TextureUsage::RenderAttachment;
63             wgpu::Texture depthStencilTexture = device.CreateTexture(&textureDescriptor);
64 
65             utils::ComboRenderPassDescriptor passDescriptor({}, depthStencilTexture.CreateView());
66             if (depthReadOnly) {
67                 passDescriptor.cDepthStencilAttachmentInfo.depthReadOnly = true;
68                 passDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
69                 passDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Store;
70             }
71 
72             if (stencilReadOnly) {
73                 passDescriptor.cDepthStencilAttachmentInfo.stencilReadOnly = true;
74                 passDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
75                 passDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
76             }
77 
78             return passDescriptor;
79         }
80     };
81 
82     // Test depthWrite/stencilWrite in DepthStencilState in render pipeline vs
83     // depthReadOnly/stencilReadOnly in DepthStencilAttachment in render pass.
TEST_F(RenderPipelineAndPassCompatibilityTests,WriteAndReadOnlyConflictForDepthStencil)84     TEST_F(RenderPipelineAndPassCompatibilityTests, WriteAndReadOnlyConflictForDepthStencil) {
85         for (bool depthStencilReadOnlyInPass : {true, false}) {
86             for (bool depthWriteInPipeline : {true, false}) {
87                 for (bool stencilWriteInPipeline : {true, false}) {
88                     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
89                     utils::ComboRenderPassDescriptor passDescriptor = CreateRenderPassDescriptor(
90                         kFormat, depthStencilReadOnlyInPass, depthStencilReadOnlyInPass);
91                     wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&passDescriptor);
92                     wgpu::RenderPipeline pipeline =
93                         CreatePipeline(kFormat, depthWriteInPipeline, stencilWriteInPipeline);
94                     pass.SetPipeline(pipeline);
95                     pass.Draw(3);
96                     pass.EndPass();
97                     if (depthStencilReadOnlyInPass &&
98                         (depthWriteInPipeline || stencilWriteInPipeline)) {
99                         ASSERT_DEVICE_ERROR(encoder.Finish());
100                     } else {
101                         encoder.Finish();
102                     }
103                 }
104             }
105         }
106     }
107 
108     // Test depthWrite/stencilWrite in DepthStencilState in render pipeline vs
109     // depthReadOnly/stencilReadOnly in RenderBundleEncoderDescriptor in render bundle.
TEST_F(RenderPipelineAndPassCompatibilityTests,WriteAndReadOnlyConflictForDepthStencilBetweenPipelineAndBundle)110     TEST_F(RenderPipelineAndPassCompatibilityTests,
111            WriteAndReadOnlyConflictForDepthStencilBetweenPipelineAndBundle) {
112         for (bool depthStencilReadOnlyInBundle : {true, false}) {
113             utils::ComboRenderBundleEncoderDescriptor desc = {};
114             desc.depthStencilFormat = kFormat;
115             desc.depthReadOnly = depthStencilReadOnlyInBundle;
116             desc.stencilReadOnly = depthStencilReadOnlyInBundle;
117 
118             for (bool depthWriteInPipeline : {true, false}) {
119                 for (bool stencilWriteInPipeline : {true, false}) {
120                     wgpu::RenderBundleEncoder renderBundleEncoder =
121                         device.CreateRenderBundleEncoder(&desc);
122                     wgpu::RenderPipeline pipeline =
123                         CreatePipeline(kFormat, depthWriteInPipeline, stencilWriteInPipeline);
124                     renderBundleEncoder.SetPipeline(pipeline);
125                     renderBundleEncoder.Draw(3);
126                     if (depthStencilReadOnlyInBundle &&
127                         (depthWriteInPipeline || stencilWriteInPipeline)) {
128                         ASSERT_DEVICE_ERROR(renderBundleEncoder.Finish());
129                     } else {
130                         renderBundleEncoder.Finish();
131                     }
132                 }
133             }
134         }
135     }
136 
137     // Test depthReadOnly/stencilReadOnly in RenderBundleEncoderDescriptor in render bundle vs
138     // depthReadOnly/stencilReadOnly in DepthStencilAttachment in render pass.
TEST_F(RenderPipelineAndPassCompatibilityTests,WriteAndReadOnlyConflictForDepthStencilBetweenBundleAndPass)139     TEST_F(RenderPipelineAndPassCompatibilityTests,
140            WriteAndReadOnlyConflictForDepthStencilBetweenBundleAndPass) {
141         for (bool depthStencilReadOnlyInPass : {true, false}) {
142             for (bool depthStencilReadOnlyInBundle : {true, false}) {
143                 for (bool emptyBundle : {true, false}) {
144                     // Create render bundle, with or without a pipeline
145                     utils::ComboRenderBundleEncoderDescriptor desc = {};
146                     desc.depthStencilFormat = kFormat;
147                     desc.depthReadOnly = depthStencilReadOnlyInBundle;
148                     desc.stencilReadOnly = depthStencilReadOnlyInBundle;
149                     wgpu::RenderBundleEncoder renderBundleEncoder =
150                         device.CreateRenderBundleEncoder(&desc);
151                     if (!emptyBundle) {
152                         wgpu::RenderPipeline pipeline = CreatePipeline(
153                             kFormat, !depthStencilReadOnlyInBundle, !depthStencilReadOnlyInBundle);
154                         renderBundleEncoder.SetPipeline(pipeline);
155                         renderBundleEncoder.Draw(3);
156                     }
157                     wgpu::RenderBundle bundle = renderBundleEncoder.Finish();
158 
159                     // Create render pass and call ExecuteBundles()
160                     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
161                     utils::ComboRenderPassDescriptor passDescriptor = CreateRenderPassDescriptor(
162                         kFormat, depthStencilReadOnlyInPass, depthStencilReadOnlyInPass);
163                     wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&passDescriptor);
164                     pass.ExecuteBundles(1, &bundle);
165                     pass.EndPass();
166                     if (!depthStencilReadOnlyInPass || depthStencilReadOnlyInBundle) {
167                         encoder.Finish();
168                     } else {
169                         ASSERT_DEVICE_ERROR(encoder.Finish());
170                     }
171                 }
172             }
173         }
174     }
175 
176     // TODO(dawn:485): add more tests. For example:
177     //   - depth/stencil attachment should be designated if depth/stencil test is enabled.
178     //   - pipeline and pass compatibility tests for color attachment(s).
179     //   - pipeline and pass compatibility tests for compute.
180 
181 }  // anonymous namespace
182