blob: b424eb82419035c78ae665ae578ffebf8d63bf44 [file] [log] [blame]
Austin Eng0a434272020-08-04 19:46:37 +00001// Copyright 2020 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 "tests/DawnTest.h"
16
17#include <array>
18#include "common/Constants.h"
19#include "common/Math.h"
20#include "utils/ComboRenderPipelineDescriptor.h"
Austin Engf114a682020-09-01 18:40:18 +000021#include "utils/TestUtils.h"
Austin Eng0a434272020-08-04 19:46:37 +000022#include "utils/TextureFormatUtils.h"
23#include "utils/WGPUHelpers.h"
24
25class DepthStencilCopyTests : public DawnTest {
26 protected:
27 void SetUp() override {
28 DawnTest::SetUp();
29
30 // Draw a square in the bottom left quarter of the screen.
Corentin Wallez7aec4ae2021-03-24 15:55:32 +000031 mVertexModule = utils::CreateShaderModule(device, R"(
Brandon Jonese87ea2b2021-04-14 17:05:07 +000032 [[stage(vertex)]]
33 fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
34 let pos : array<vec2<f32>, 6> = array<vec2<f32>, 6>(
Austin Eng84e1dca2020-11-30 20:33:50 +000035 vec2<f32>(-1.0, -1.0),
36 vec2<f32>( 0.0, -1.0),
37 vec2<f32>(-1.0, 0.0),
38 vec2<f32>(-1.0, 0.0),
39 vec2<f32>( 0.0, -1.0),
40 vec2<f32>( 0.0, 0.0));
Brandon Jonese87ea2b2021-04-14 17:05:07 +000041 return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
Austin Eng84e1dca2020-11-30 20:33:50 +000042 })");
Austin Eng0a434272020-08-04 19:46:37 +000043 }
44
Austin Engf114a682020-09-01 18:40:18 +000045 wgpu::Texture CreateDepthStencilTexture(uint32_t width,
46 uint32_t height,
47 wgpu::TextureUsage usage,
48 uint32_t mipLevelCount = 1) {
49 wgpu::TextureDescriptor texDescriptor = {};
50 texDescriptor.size = {width, height, 1};
51 texDescriptor.format = wgpu::TextureFormat::Depth24PlusStencil8;
52 texDescriptor.usage = usage;
53 texDescriptor.mipLevelCount = mipLevelCount;
54 return device.CreateTexture(&texDescriptor);
55 }
56
57 wgpu::Texture CreateDepthTexture(uint32_t width,
58 uint32_t height,
59 wgpu::TextureUsage usage,
60 uint32_t mipLevelCount = 1) {
61 wgpu::TextureDescriptor texDescriptor = {};
62 texDescriptor.size = {width, height, 1};
63 texDescriptor.format = wgpu::TextureFormat::Depth32Float;
64 texDescriptor.usage = usage;
65 texDescriptor.mipLevelCount = mipLevelCount;
66 return device.CreateTexture(&texDescriptor);
67 }
68
Brandon Jonesbff9d3a2021-03-18 02:54:27 +000069 void PopulatePipelineDescriptorWriteDepth(utils::ComboRenderPipelineDescriptor2* desc,
Austin Engf114a682020-09-01 18:40:18 +000070 wgpu::TextureFormat format,
71 float regionDepth) {
Brandon Jonesbff9d3a2021-03-18 02:54:27 +000072 desc->vertex.module = mVertexModule;
Austin Engf114a682020-09-01 18:40:18 +000073
74 std::string fsSource = R"(
Brandon Jonese87ea2b2021-04-14 17:05:07 +000075 [[stage(fragment)]] fn main() -> [[builtin(frag_depth)]] f32 {
76 return )" + std::to_string(regionDepth) +
Austin Engf114a682020-09-01 18:40:18 +000077 ";\n}";
78
Corentin Wallez7aec4ae2021-03-24 15:55:32 +000079 desc->cFragment.module = utils::CreateShaderModule(device, fsSource.c_str());
Brandon Jonesbff9d3a2021-03-18 02:54:27 +000080 wgpu::DepthStencilState* depthStencil = desc->EnableDepthStencil(format);
81 depthStencil->depthWriteEnabled = true;
82 desc->cFragment.targetCount = 0;
Austin Engf114a682020-09-01 18:40:18 +000083 }
84
85 // Initialize the depth/stencil values for the texture using a render pass.
86 // The texture will be cleared to the "clear" value, and then bottom left corner will
87 // be written with the "region" value.
88 void InitializeDepthTextureRegion(wgpu::Texture texture,
89 float clearDepth,
90 float regionDepth,
91 uint32_t mipLevel = 0) {
92 wgpu::TextureViewDescriptor viewDesc = {};
93 viewDesc.baseMipLevel = mipLevel;
94 viewDesc.mipLevelCount = 1;
95
96 utils::ComboRenderPassDescriptor renderPassDesc({}, texture.CreateView(&viewDesc));
97 renderPassDesc.cDepthStencilAttachmentInfo.clearDepth = clearDepth;
98
Brandon Jonesbff9d3a2021-03-18 02:54:27 +000099 utils::ComboRenderPipelineDescriptor2 renderPipelineDesc;
Austin Engf114a682020-09-01 18:40:18 +0000100 PopulatePipelineDescriptorWriteDepth(&renderPipelineDesc, wgpu::TextureFormat::Depth32Float,
101 regionDepth);
102
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000103 wgpu::RenderPipeline pipeline = device.CreateRenderPipeline2(&renderPipelineDesc);
Austin Engf114a682020-09-01 18:40:18 +0000104 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
105 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPassDesc);
106 pass.SetPipeline(pipeline);
107 pass.Draw(6);
108 pass.EndPass();
109
110 wgpu::CommandBuffer commands = commandEncoder.Finish();
111 queue.Submit(1, &commands);
112 }
113
114 // Initialize the depth/stencil values for the texture using a render pass.
115 // The texture will be cleared to the "clear" values, and then bottom left corner will
116 // be written with the "region" values.
117 void InitializeDepthStencilTextureRegion(wgpu::Texture texture,
118 float clearDepth,
119 float regionDepth,
120 uint8_t clearStencil,
121 uint8_t regionStencil,
122 uint32_t mipLevel = 0) {
123 wgpu::TextureViewDescriptor viewDesc = {};
124 viewDesc.baseMipLevel = mipLevel;
125 viewDesc.mipLevelCount = 1;
126
127 utils::ComboRenderPassDescriptor renderPassDesc({}, texture.CreateView(&viewDesc));
128 renderPassDesc.cDepthStencilAttachmentInfo.clearDepth = clearDepth;
129 renderPassDesc.cDepthStencilAttachmentInfo.clearStencil = clearStencil;
130
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000131 utils::ComboRenderPipelineDescriptor2 renderPipelineDesc;
Austin Engf114a682020-09-01 18:40:18 +0000132 PopulatePipelineDescriptorWriteDepth(&renderPipelineDesc,
133 wgpu::TextureFormat::Depth24PlusStencil8, regionDepth);
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000134 renderPipelineDesc.cDepthStencil.stencilFront.passOp = wgpu::StencilOperation::Replace;
Austin Engf114a682020-09-01 18:40:18 +0000135
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000136 wgpu::RenderPipeline pipeline = device.CreateRenderPipeline2(&renderPipelineDesc);
Austin Engf114a682020-09-01 18:40:18 +0000137
138 // Draw the quad (two triangles)
139 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
140 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPassDesc);
141 pass.SetPipeline(pipeline);
142 pass.SetStencilReference(regionStencil);
143 pass.Draw(6);
144 pass.EndPass();
145
146 wgpu::CommandBuffer commands = commandEncoder.Finish();
147 queue.Submit(1, &commands);
148 }
149
150 wgpu::Texture CreateInitializeDepthStencilTextureAndCopyT2T(float clearDepth,
151 float regionDepth,
152 uint8_t clearStencil,
153 uint8_t regionStencil,
154 uint32_t width,
155 uint32_t height,
156 wgpu::TextureUsage usage,
157 uint32_t mipLevel = 0) {
158 wgpu::Texture src = CreateDepthStencilTexture(
Corentin Wallez6b087812020-10-27 15:35:56 +0000159 width, height, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc,
Austin Engf114a682020-09-01 18:40:18 +0000160 mipLevel + 1);
161
162 wgpu::Texture dst = CreateDepthStencilTexture(
163 width, height, usage | wgpu::TextureUsage::CopyDst, mipLevel + 1);
164
165 InitializeDepthStencilTextureRegion(src, clearDepth, regionDepth, clearStencil,
166 regionStencil, mipLevel);
167
168 // Perform a T2T copy of all aspects
169 {
170 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
Corentin Wallez80915842021-03-04 18:13:45 +0000171 wgpu::ImageCopyTexture srcView =
172 utils::CreateImageCopyTexture(src, mipLevel, {0, 0, 0});
173 wgpu::ImageCopyTexture dstView =
174 utils::CreateImageCopyTexture(dst, mipLevel, {0, 0, 0});
Austin Engf114a682020-09-01 18:40:18 +0000175 wgpu::Extent3D copySize = {width >> mipLevel, height >> mipLevel, 1};
176 commandEncoder.CopyTextureToTexture(&srcView, &dstView, &copySize);
177
178 wgpu::CommandBuffer commands = commandEncoder.Finish();
179 queue.Submit(1, &commands);
180 }
181
182 return dst;
183 }
184
185 // Check depth by uploading expected data to a sampled texture, writing it out as a depth
186 // attachment, and then using the "equals" depth test to check the contents are the same.
187 void ExpectDepthData(wgpu::Texture depthTexture,
188 wgpu::TextureFormat depthFormat,
189 uint32_t width,
190 uint32_t height,
191 uint32_t mipLevel,
192 std::vector<float> expected) {
193 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
194
195 // Make the color attachment that we'll use to read back.
196 wgpu::TextureDescriptor colorTexDesc = {};
197 colorTexDesc.size = {width, height, 1};
198 colorTexDesc.format = wgpu::TextureFormat::R32Uint;
Corentin Wallez6b087812020-10-27 15:35:56 +0000199 colorTexDesc.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
Austin Engf114a682020-09-01 18:40:18 +0000200 wgpu::Texture colorTexture = device.CreateTexture(&colorTexDesc);
201
202 // Make a sampleable texture to store the depth data. We'll sample this in the
203 // shader to output depth.
204 wgpu::TextureDescriptor depthDataDesc = {};
205 depthDataDesc.size = {width, height, 1};
206 depthDataDesc.format = wgpu::TextureFormat::R32Float;
207 depthDataDesc.usage = wgpu::TextureUsage::Sampled | wgpu::TextureUsage::CopyDst;
208 wgpu::Texture depthDataTexture = device.CreateTexture(&depthDataDesc);
209
210 // Upload the depth data.
211 uint32_t bytesPerRow = utils::GetMinimumBytesPerRow(wgpu::TextureFormat::R32Float, width);
212 wgpu::BufferDescriptor uploadBufferDesc = {};
213 uploadBufferDesc.size = utils::RequiredBytesInCopy(bytesPerRow, height, depthDataDesc.size,
214 wgpu::TextureFormat::R32Float);
215 uploadBufferDesc.usage = wgpu::BufferUsage::CopySrc;
216 uploadBufferDesc.mappedAtCreation = true;
217
218 // TODO(enga): Use WriteTexture when implemented on OpenGL.
219 wgpu::Buffer uploadBuffer = device.CreateBuffer(&uploadBufferDesc);
220 uint8_t* dst = static_cast<uint8_t*>(uploadBuffer.GetMappedRange());
221 float* src = expected.data();
222 for (uint32_t y = 0; y < height; ++y) {
223 memcpy(dst, src, width * sizeof(float));
224 dst += bytesPerRow;
225 src += width;
226 }
227 uploadBuffer.Unmap();
228
Corentin Wallez80915842021-03-04 18:13:45 +0000229 wgpu::ImageCopyBuffer bufferCopy =
230 utils::CreateImageCopyBuffer(uploadBuffer, 0, bytesPerRow, height);
231 wgpu::ImageCopyTexture textureCopy =
232 utils::CreateImageCopyTexture(depthDataTexture, 0, {0, 0, 0}, wgpu::TextureAspect::All);
Austin Engf114a682020-09-01 18:40:18 +0000233 commandEncoder.CopyBufferToTexture(&bufferCopy, &textureCopy, &depthDataDesc.size);
234
235 // Pipeline for a full screen quad.
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000236 utils::ComboRenderPipelineDescriptor2 pipelineDescriptor;
Austin Engf114a682020-09-01 18:40:18 +0000237
Corentin Wallez7aec4ae2021-03-24 15:55:32 +0000238 pipelineDescriptor.vertex.module = utils::CreateShaderModule(device, R"(
Brandon Jonese87ea2b2021-04-14 17:05:07 +0000239 [[stage(vertex)]]
240 fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
241 let pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
Austin Eng84e1dca2020-11-30 20:33:50 +0000242 vec2<f32>(-1.0, -1.0),
243 vec2<f32>( 3.0, -1.0),
244 vec2<f32>(-1.0, 3.0));
Brandon Jonese87ea2b2021-04-14 17:05:07 +0000245 return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
Austin Eng84e1dca2020-11-30 20:33:50 +0000246 })");
Austin Engf114a682020-09-01 18:40:18 +0000247
248 // Sample the input texture and write out depth. |result| will only be set to 1 if we
249 // pass the depth test.
Corentin Wallez7aec4ae2021-03-24 15:55:32 +0000250 pipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, R"(
James Price7e80cce2021-02-10 20:17:14 +0000251 [[group(0), binding(0)]] var texture0 : texture_2d<f32>;
Austin Engf114a682020-09-01 18:40:18 +0000252
Brandon Jonese87ea2b2021-04-14 17:05:07 +0000253 struct FragmentOut {
254 [[location(0)]] result : u32;
255 [[builtin(frag_depth)]] fragDepth : f32;
256 };
Austin Eng02436022020-12-17 19:20:27 +0000257
Brandon Jonese87ea2b2021-04-14 17:05:07 +0000258 [[stage(fragment)]]
James Priceeae70b72021-04-19 15:29:49 +0000259 fn main([[builtin(position)]] FragCoord : vec4<f32>) -> FragmentOut {
Brandon Jonese87ea2b2021-04-14 17:05:07 +0000260 var output : FragmentOut;
261 output.result = 1u;
262 output.fragDepth = textureLoad(texture0, vec2<i32>(FragCoord.xy), 0)[0];
263 return output;
Austin Eng02436022020-12-17 19:20:27 +0000264 })");
Austin Engf114a682020-09-01 18:40:18 +0000265
266 // Pass the depth test only if the depth is equal.
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000267 pipelineDescriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
268 wgpu::DepthStencilState* depthStencil = pipelineDescriptor.EnableDepthStencil(depthFormat);
269 depthStencil->depthCompare = wgpu::CompareFunction::Equal;
270 pipelineDescriptor.cTargets[0].format = colorTexDesc.format;
Austin Engf114a682020-09-01 18:40:18 +0000271
272 // TODO(jiawei.shao@intel.com): The Intel Mesa Vulkan driver can't set gl_FragDepth unless
273 // depthWriteEnabled == true. This either needs to be fixed in the driver or restricted by
274 // the WebGPU API.
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000275 depthStencil->depthWriteEnabled = true;
Austin Engf114a682020-09-01 18:40:18 +0000276
277 wgpu::TextureViewDescriptor viewDesc = {};
278 viewDesc.baseMipLevel = mipLevel;
279 viewDesc.mipLevelCount = 1;
280
281 utils::ComboRenderPassDescriptor passDescriptor({colorTexture.CreateView()},
282 depthTexture.CreateView(&viewDesc));
283 passDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
284 passDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
285
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000286 wgpu::RenderPipeline pipeline = device.CreateRenderPipeline2(&pipelineDescriptor);
Austin Engf114a682020-09-01 18:40:18 +0000287
Austin Eng02436022020-12-17 19:20:27 +0000288 // Bind the depth data texture.
289 wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
290 {{0, depthDataTexture.CreateView()}});
Austin Engf114a682020-09-01 18:40:18 +0000291
292 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
293 pass.SetPipeline(pipeline);
294 pass.SetBindGroup(0, bindGroup);
295 pass.Draw(3);
296 pass.EndPass();
297
298 wgpu::CommandBuffer commands = commandEncoder.Finish();
299 queue.Submit(1, &commands);
300
301 std::vector<uint32_t> colorData(width * height, 1u);
Yunchao Heff55b2f2021-04-07 16:57:11 +0000302 EXPECT_TEXTURE_EQ(colorData.data(), colorTexture, {0, 0}, {width, height});
Austin Engf114a682020-09-01 18:40:18 +0000303 }
Austin Eng0a434272020-08-04 19:46:37 +0000304
305 wgpu::ShaderModule mVertexModule;
Austin Eng0a434272020-08-04 19:46:37 +0000306};
307
308// Test copying the depth-only aspect into a buffer.
309TEST_P(DepthStencilCopyTests, FromDepthAspect) {
Austin Eng0a434272020-08-04 19:46:37 +0000310 constexpr uint32_t kWidth = 4;
311 constexpr uint32_t kHeight = 4;
Austin Eng0a434272020-08-04 19:46:37 +0000312
Austin Engf114a682020-09-01 18:40:18 +0000313 wgpu::Texture depthTexture = CreateDepthTexture(
Corentin Wallez6b087812020-10-27 15:35:56 +0000314 kWidth, kHeight, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc);
Austin Eng0a434272020-08-04 19:46:37 +0000315
Austin Engf114a682020-09-01 18:40:18 +0000316 InitializeDepthTextureRegion(depthTexture, 0.f, 0.3f);
Austin Eng0a434272020-08-04 19:46:37 +0000317
Austin Engf114a682020-09-01 18:40:18 +0000318 // This expectation is the test as it performs the CopyTextureToBuffer.
319 std::vector<float> expectedData = {
Austin Eng0a434272020-08-04 19:46:37 +0000320 0.0, 0.0, 0.0, 0.0, //
321 0.0, 0.0, 0.0, 0.0, //
322 0.3, 0.3, 0.0, 0.0, //
323 0.3, 0.3, 0.0, 0.0, //
324 };
Yunchao Heff55b2f2021-04-07 16:57:11 +0000325 EXPECT_TEXTURE_EQ(expectedData.data(), depthTexture, {0, 0}, {kWidth, kHeight}, 0,
Austin Eng0a434272020-08-04 19:46:37 +0000326 wgpu::TextureAspect::DepthOnly);
327}
328
329// Test copying the stencil-only aspect into a buffer.
330TEST_P(DepthStencilCopyTests, FromStencilAspect) {
Stephen White39b478d2021-02-10 02:10:08 +0000331 // TODO(crbug.com/dawn/667): Work around the fact that some platforms are unable to read
332 // stencil.
333 DAWN_SKIP_TEST_IF(HasToggleEnabled("disable_depth_stencil_read"));
Stephen Whitef09a6702021-01-18 17:47:07 +0000334
Austin Eng0a434272020-08-04 19:46:37 +0000335 constexpr uint32_t kWidth = 4;
336 constexpr uint32_t kHeight = 4;
Austin Eng0a434272020-08-04 19:46:37 +0000337
Austin Engf114a682020-09-01 18:40:18 +0000338 wgpu::Texture depthStencilTexture = CreateDepthStencilTexture(
Corentin Wallez6b087812020-10-27 15:35:56 +0000339 kWidth, kHeight, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc);
Austin Eng0a434272020-08-04 19:46:37 +0000340
Austin Engf114a682020-09-01 18:40:18 +0000341 InitializeDepthStencilTextureRegion(depthStencilTexture, 0.f, 0.3f, 0u, 1u);
Austin Eng0a434272020-08-04 19:46:37 +0000342
Austin Engf114a682020-09-01 18:40:18 +0000343 // This expectation is the test as it performs the CopyTextureToBuffer.
344 std::vector<uint8_t> expectedData = {
Austin Eng0a434272020-08-04 19:46:37 +0000345 0u, 0u, 0u, 0u, //
346 0u, 0u, 0u, 0u, //
347 1u, 1u, 0u, 0u, //
348 1u, 1u, 0u, 0u, //
349 };
Yunchao Heff55b2f2021-04-07 16:57:11 +0000350 EXPECT_TEXTURE_EQ(expectedData.data(), depthStencilTexture, {0, 0}, {kWidth, kHeight}, 0,
Austin Engf114a682020-09-01 18:40:18 +0000351 wgpu::TextureAspect::StencilOnly);
352}
353
354// Test copying the non-zero mip, stencil-only aspect into a buffer.
355TEST_P(DepthStencilCopyTests, FromNonZeroMipStencilAspect) {
356 // TODO(enga): Figure out why this fails on MacOS Intel Iris.
357 // It passes on AMD Radeon Pro and Intel HD Graphics 630.
358 DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
359
Stephen White39b478d2021-02-10 02:10:08 +0000360 // TODO(crbug.com/dawn/667): Work around some platforms' inability to read back stencil.
361 DAWN_SKIP_TEST_IF(HasToggleEnabled("disable_depth_stencil_read"));
Stephen Whitef09a6702021-01-18 17:47:07 +0000362
Austin Engf114a682020-09-01 18:40:18 +0000363 wgpu::Texture depthStencilTexture = CreateDepthStencilTexture(
Corentin Wallez6b087812020-10-27 15:35:56 +0000364 9, 9, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, 2);
Austin Engf114a682020-09-01 18:40:18 +0000365
366 InitializeDepthStencilTextureRegion(depthStencilTexture, 0.f, 0.3f, 0u, 1u, 1u);
Austin Eng0a434272020-08-04 19:46:37 +0000367
368 // This expectation is the test as it performs the CopyTextureToBuffer.
Austin Engf114a682020-09-01 18:40:18 +0000369 std::vector<uint8_t> expectedData = {
370 0u, 0u, 0u, 0u, //
371 0u, 0u, 0u, 0u, //
372 1u, 1u, 0u, 0u, //
373 1u, 1u, 0u, 0u, //
374 };
Yunchao Heff55b2f2021-04-07 16:57:11 +0000375 EXPECT_TEXTURE_EQ(expectedData.data(), depthStencilTexture, {0, 0}, {4, 4}, 1,
Austin Engf114a682020-09-01 18:40:18 +0000376 wgpu::TextureAspect::StencilOnly);
377}
378
379// Test copying the non-zero mip, depth-only aspect into a buffer.
380TEST_P(DepthStencilCopyTests, FromNonZeroMipDepthAspect) {
381 wgpu::Texture depthTexture = CreateDepthTexture(
Corentin Wallez6b087812020-10-27 15:35:56 +0000382 9, 9, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, 2);
Austin Engf114a682020-09-01 18:40:18 +0000383
384 InitializeDepthTextureRegion(depthTexture, 0.f, 0.4f, 1);
385
386 // This expectation is the test as it performs the CopyTextureToBuffer.
387 std::vector<float> expectedData = {
388 0.0, 0.0, 0.0, 0.0, //
389 0.0, 0.0, 0.0, 0.0, //
390 0.4, 0.4, 0.0, 0.0, //
391 0.4, 0.4, 0.0, 0.0, //
392 };
Yunchao Heff55b2f2021-04-07 16:57:11 +0000393 EXPECT_TEXTURE_EQ(expectedData.data(), depthTexture, {0, 0}, {4, 4}, 1,
Austin Engf114a682020-09-01 18:40:18 +0000394 wgpu::TextureAspect::DepthOnly);
395}
396
397// Test copying both aspects in a T2T copy, then copying only stencil.
398TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyStencil) {
399 // TODO(enga): Figure out why this fails on MacOS Intel Iris.
400 // It passes on AMD Radeon Pro and Intel HD Graphics 630.
Corentin Wallez6b087812020-10-27 15:35:56 +0000401 // Maybe has to do with the RenderAttachment usage. Notably, a later test
402 // T2TBothAspectsThenCopyNonRenderableStencil does not use RenderAttachment and works correctly.
Austin Engf114a682020-09-01 18:40:18 +0000403 DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
404
Stephen White39b478d2021-02-10 02:10:08 +0000405 // TODO(crbug.com/dawn/667): Work around some platforms' inability to read back stencil.
406 DAWN_SKIP_TEST_IF(HasToggleEnabled("disable_depth_stencil_read"));
Stephen Whitef09a6702021-01-18 17:47:07 +0000407
Austin Engf114a682020-09-01 18:40:18 +0000408 constexpr uint32_t kWidth = 4;
409 constexpr uint32_t kHeight = 4;
410
411 wgpu::Texture texture = CreateInitializeDepthStencilTextureAndCopyT2T(
412 0.1f, 0.3f, 1u, 3u, kWidth, kHeight,
Corentin Wallez6b087812020-10-27 15:35:56 +0000413 wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment);
Austin Engf114a682020-09-01 18:40:18 +0000414
415 // Check the stencil
416 std::vector<uint8_t> expectedData = {
417 1u, 1u, 1u, 1u, //
418 1u, 1u, 1u, 1u, //
419 3u, 3u, 1u, 1u, //
420 3u, 3u, 1u, 1u, //
421 };
Yunchao Heff55b2f2021-04-07 16:57:11 +0000422 EXPECT_TEXTURE_EQ(expectedData.data(), texture, {0, 0}, {kWidth, kHeight}, 0,
Austin Engf114a682020-09-01 18:40:18 +0000423 wgpu::TextureAspect::StencilOnly);
424}
425
426// Test that part of a non-renderable stencil aspect can be copied. Notably,
427// this test has different behavior on some platforms than T2TBothAspectsThenCopyStencil.
428TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyNonRenderableStencil) {
Stephen White39b478d2021-02-10 02:10:08 +0000429 // TODO(crbug.com/dawn/667): Work around some platforms' inability to read back stencil.
430 DAWN_SKIP_TEST_IF(HasToggleEnabled("disable_depth_stencil_read"));
Stephen Whitef09a6702021-01-18 17:47:07 +0000431
Austin Engf114a682020-09-01 18:40:18 +0000432 constexpr uint32_t kWidth = 4;
433 constexpr uint32_t kHeight = 4;
434
435 wgpu::Texture texture = CreateInitializeDepthStencilTextureAndCopyT2T(
436 0.1f, 0.3f, 1u, 3u, kWidth, kHeight, wgpu::TextureUsage::CopySrc);
437
438 // Check the stencil
439 std::vector<uint8_t> expectedData = {
440 1u, 1u, 1u, 1u, //
441 1u, 1u, 1u, 1u, //
442 3u, 3u, 1u, 1u, //
443 3u, 3u, 1u, 1u, //
444 };
Yunchao Heff55b2f2021-04-07 16:57:11 +0000445 EXPECT_TEXTURE_EQ(expectedData.data(), texture, {0, 0}, {kWidth, kHeight}, 0,
Austin Engf114a682020-09-01 18:40:18 +0000446 wgpu::TextureAspect::StencilOnly);
447}
448
449// Test that part of a non-renderable, non-zero mip stencil aspect can be copied. Notably,
450// this test has different behavior on some platforms than T2TBothAspectsThenCopyStencil.
451TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyNonRenderableNonZeroMipStencil) {
452 // TODO(enga): Figure out why this fails on MacOS Intel Iris.
453 // It passes on AMD Radeon Pro and Intel HD Graphics 630.
454 // Maybe has to do with the non-zero mip. Notably, a previous test
455 // T2TBothAspectsThenCopyNonRenderableStencil works correctly.
456 DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
457
Stephen White39b478d2021-02-10 02:10:08 +0000458 // TODO(crbug.com/dawn/667): Work around some platforms' inability to read back stencil.
459 DAWN_SKIP_TEST_IF(HasToggleEnabled("disable_depth_stencil_read"));
Stephen Whitef09a6702021-01-18 17:47:07 +0000460
Austin Engf114a682020-09-01 18:40:18 +0000461 wgpu::Texture texture = CreateInitializeDepthStencilTextureAndCopyT2T(
462 0.1f, 0.3f, 1u, 3u, 9, 9, wgpu::TextureUsage::CopySrc, 1);
463
464 // Check the stencil
465 std::vector<uint8_t> expectedData = {
466 1u, 1u, 1u, 1u, //
467 1u, 1u, 1u, 1u, //
468 3u, 3u, 1u, 1u, //
469 3u, 3u, 1u, 1u, //
470 };
Yunchao Heff55b2f2021-04-07 16:57:11 +0000471 EXPECT_TEXTURE_EQ(expectedData.data(), texture, {0, 0}, {4, 4}, 1,
Austin Engf114a682020-09-01 18:40:18 +0000472 wgpu::TextureAspect::StencilOnly);
473}
474
475// Test copying both aspects in a T2T copy, then copying only depth.
476TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyDepth) {
477 constexpr uint32_t kWidth = 4;
478 constexpr uint32_t kHeight = 4;
479
480 wgpu::Texture texture = CreateInitializeDepthStencilTextureAndCopyT2T(
Corentin Wallez6b087812020-10-27 15:35:56 +0000481 0.1f, 0.3f, 1u, 3u, kWidth, kHeight, wgpu::TextureUsage::RenderAttachment);
Austin Engf114a682020-09-01 18:40:18 +0000482
483 // Check the depth
484 ExpectDepthData(texture, wgpu::TextureFormat::Depth24PlusStencil8, kWidth, kHeight, 0,
485 {
486 0.1, 0.1, 0.1, 0.1, //
487 0.1, 0.1, 0.1, 0.1, //
488 0.3, 0.3, 0.1, 0.1, //
489 0.3, 0.3, 0.1, 0.1, //
490 });
491}
492
493// Test copying both aspects in a T2T copy, then copying only depth at a nonzero mip.
494TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyNonZeroMipDepth) {
495 wgpu::Texture texture = CreateInitializeDepthStencilTextureAndCopyT2T(
Corentin Wallez6b087812020-10-27 15:35:56 +0000496 0.1f, 0.3f, 1u, 3u, 8, 8, wgpu::TextureUsage::RenderAttachment, 1);
Austin Engf114a682020-09-01 18:40:18 +0000497
498 // Check the depth
499 ExpectDepthData(texture, wgpu::TextureFormat::Depth24PlusStencil8, 4, 4, 1,
500 {
501 0.1, 0.1, 0.1, 0.1, //
502 0.1, 0.1, 0.1, 0.1, //
503 0.3, 0.3, 0.1, 0.1, //
504 0.3, 0.3, 0.1, 0.1, //
505 });
506}
507
508// Test copying both aspects in a T2T copy, then copying stencil, then copying depth
509TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyStencilThenDepth) {
Stephen White39b478d2021-02-10 02:10:08 +0000510 // TODO(crbug.com/dawn/667): Work around some platforms' inability to read back stencil.
511 DAWN_SKIP_TEST_IF(HasToggleEnabled("disable_depth_stencil_read"));
Stephen Whitef09a6702021-01-18 17:47:07 +0000512
Austin Engf114a682020-09-01 18:40:18 +0000513 constexpr uint32_t kWidth = 4;
514 constexpr uint32_t kHeight = 4;
515
516 wgpu::Texture texture = CreateInitializeDepthStencilTextureAndCopyT2T(
517 0.1f, 0.3f, 1u, 3u, kWidth, kHeight,
Corentin Wallez6b087812020-10-27 15:35:56 +0000518 wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment);
Austin Engf114a682020-09-01 18:40:18 +0000519
520 // Check the stencil
521 std::vector<uint8_t> expectedData = {
522 1u, 1u, 1u, 1u, //
523 1u, 1u, 1u, 1u, //
524 3u, 3u, 1u, 1u, //
525 3u, 3u, 1u, 1u, //
526 };
Yunchao Heff55b2f2021-04-07 16:57:11 +0000527 EXPECT_TEXTURE_EQ(expectedData.data(), texture, {0, 0}, {kWidth, kHeight}, 0,
Austin Engf114a682020-09-01 18:40:18 +0000528 wgpu::TextureAspect::StencilOnly);
529
530 // Check the depth
531 ExpectDepthData(texture, wgpu::TextureFormat::Depth24PlusStencil8, kWidth, kHeight, 0,
532 {
533 0.1, 0.1, 0.1, 0.1, //
534 0.1, 0.1, 0.1, 0.1, //
535 0.3, 0.3, 0.1, 0.1, //
536 0.3, 0.3, 0.1, 0.1, //
537 });
538}
539
540// Test copying both aspects in a T2T copy, then copying depth, then copying stencil
541TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyDepthThenStencil) {
542 // TODO(enga): Figure out why this fails on MacOS Intel Iris.
543 // It passes on AMD Radeon Pro and Intel HD Graphics 630.
544 // It seems like the depth readback copy mutates the stencil because the previous
545 // test T2TBothAspectsThenCopyStencil passes.
546 // T2TBothAspectsThenCopyStencilThenDepth which checks stencil first also passes.
547 DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
548
Stephen White39b478d2021-02-10 02:10:08 +0000549 // TODO(crbug.com/dawn/667): Work around the fact that some platforms are unable to read
550 // stencil.
551 DAWN_SKIP_TEST_IF(HasToggleEnabled("disable_depth_stencil_read"));
Stephen Whitef09a6702021-01-18 17:47:07 +0000552
Austin Engf114a682020-09-01 18:40:18 +0000553 constexpr uint32_t kWidth = 4;
554 constexpr uint32_t kHeight = 4;
555
556 wgpu::Texture texture = CreateInitializeDepthStencilTextureAndCopyT2T(
557 0.1f, 0.3f, 1u, 3u, kWidth, kHeight,
Corentin Wallez6b087812020-10-27 15:35:56 +0000558 wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment);
Austin Engf114a682020-09-01 18:40:18 +0000559
560 // Check the depth
561 ExpectDepthData(texture, wgpu::TextureFormat::Depth24PlusStencil8, kWidth, kHeight, 0,
562 {
563 0.1, 0.1, 0.1, 0.1, //
564 0.1, 0.1, 0.1, 0.1, //
565 0.3, 0.3, 0.1, 0.1, //
566 0.3, 0.3, 0.1, 0.1, //
567 });
568
569 // Check the stencil
570 std::vector<uint8_t> expectedData = {
571 1u, 1u, 1u, 1u, //
572 1u, 1u, 1u, 1u, //
573 3u, 3u, 1u, 1u, //
574 3u, 3u, 1u, 1u, //
575 };
Yunchao Heff55b2f2021-04-07 16:57:11 +0000576 EXPECT_TEXTURE_EQ(expectedData.data(), texture, {0, 0}, {kWidth, kHeight}, 0,
Austin Eng0a434272020-08-04 19:46:37 +0000577 wgpu::TextureAspect::StencilOnly);
578}
579
580// Test copying to the stencil-aspect of a buffer
581TEST_P(DepthStencilCopyTests, ToStencilAspect) {
Austin Engb54c82e2020-08-18 18:53:26 +0000582 // Copies to a single aspect are unsupported on OpenGL.
583 DAWN_SKIP_TEST_IF(IsOpenGL());
Stephen White6f5151f2020-12-01 21:52:37 +0000584 DAWN_SKIP_TEST_IF(IsOpenGLES());
Austin Engb54c82e2020-08-18 18:53:26 +0000585
Austin Eng0a434272020-08-04 19:46:37 +0000586 // TODO(enga): Figure out why this fails on MacOS Intel Iris.
587 // It passes on AMD Radeon Pro and Intel HD Graphics 630.
588 DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
589
590 // Create a stencil texture
591 constexpr uint32_t kWidth = 4;
592 constexpr uint32_t kHeight = 4;
Austin Eng0a434272020-08-04 19:46:37 +0000593
Austin Engf114a682020-09-01 18:40:18 +0000594 wgpu::Texture depthStencilTexture =
595 CreateDepthStencilTexture(kWidth, kHeight,
Corentin Wallez6b087812020-10-27 15:35:56 +0000596 wgpu::TextureUsage::RenderAttachment |
Austin Engf114a682020-09-01 18:40:18 +0000597 wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst);
Austin Eng0a434272020-08-04 19:46:37 +0000598
Austin Engf114a682020-09-01 18:40:18 +0000599 {
600 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
601
602 // Clear depth to 0.7, so we can check that the stencil copy doesn't mutate the depth.
603 utils::ComboRenderPassDescriptor passDescriptor({}, depthStencilTexture.CreateView());
604 passDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.7;
605
606 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
607 pass.EndPass();
608
609 wgpu::CommandBuffer commands = commandEncoder.Finish();
610 queue.Submit(1, &commands);
611 }
Austin Eng0a434272020-08-04 19:46:37 +0000612
613 std::vector<uint8_t> stencilData = {
614 1u, 2u, 3u, 4u, //
615 5u, 6u, 7u, 8u, //
616 9u, 10u, 11u, 12u, //
617 13u, 14u, 15u, 16u, //
618 };
619
620 // After copying stencil data in, we will decrement stencil values in the bottom left
621 // of the screen. This is the expected result.
622 std::vector<uint8_t> expectedStencilData = {
623 1u, 2u, 3u, 4u, //
624 5u, 6u, 7u, 8u, //
625 8u, 9u, 11u, 12u, //
626 12u, 13u, 15u, 16u, //
627 };
628
Austin Engf114a682020-09-01 18:40:18 +0000629 // Upload the stencil data.
630 wgpu::TextureDataLayout stencilDataLayout = {};
631 stencilDataLayout.bytesPerRow = kWidth * sizeof(uint8_t);
Austin Eng0a434272020-08-04 19:46:37 +0000632
Corentin Wallez80915842021-03-04 18:13:45 +0000633 wgpu::ImageCopyTexture stencilDataCopyTexture = utils::CreateImageCopyTexture(
Austin Engf114a682020-09-01 18:40:18 +0000634 depthStencilTexture, 0, {0, 0, 0}, wgpu::TextureAspect::StencilOnly);
Austin Eng0a434272020-08-04 19:46:37 +0000635
Austin Engf114a682020-09-01 18:40:18 +0000636 wgpu::Extent3D writeSize = {kWidth, kHeight, 1};
Corentin Wallez80915842021-03-04 18:13:45 +0000637 queue.WriteTexture(&stencilDataCopyTexture, stencilData.data(),
Austin Engf114a682020-09-01 18:40:18 +0000638 stencilData.size() * sizeof(uint8_t), &stencilDataLayout, &writeSize);
Austin Eng0a434272020-08-04 19:46:37 +0000639
Austin Engf114a682020-09-01 18:40:18 +0000640 // Decrement the stencil value in a render pass to ensure the data is visible to the pipeline.
Austin Eng0a434272020-08-04 19:46:37 +0000641 {
642 wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
643 // Create a render pipline which decrements the stencil value for passing fragments.
644 // A quad is drawn in the bottom left.
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000645 utils::ComboRenderPipelineDescriptor2 renderPipelineDesc;
646 renderPipelineDesc.vertex.module = mVertexModule;
Corentin Wallez7aec4ae2021-03-24 15:55:32 +0000647 renderPipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"(
Corentin Wallez21bd02b2021-04-13 09:48:24 +0000648 [[stage(fragment)]] fn main() {
Austin Eng84e1dca2020-11-30 20:33:50 +0000649 })");
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000650 wgpu::DepthStencilState* depthStencil =
651 renderPipelineDesc.EnableDepthStencil(wgpu::TextureFormat::Depth24PlusStencil8);
652 depthStencil->stencilFront.passOp = wgpu::StencilOperation::DecrementClamp;
653 renderPipelineDesc.cFragment.targetCount = 0;
Austin Eng0a434272020-08-04 19:46:37 +0000654
Brandon Jonesbff9d3a2021-03-18 02:54:27 +0000655 wgpu::RenderPipeline pipeline = device.CreateRenderPipeline2(&renderPipelineDesc);
Austin Eng0a434272020-08-04 19:46:37 +0000656
657 // Create a render pass which loads the stencil. We want to load the values we
658 // copied in. Also load the canary depth values so they're not lost.
659 utils::ComboRenderPassDescriptor passDescriptor({}, depthStencilTexture.CreateView());
660 passDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
661 passDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
662
663 // Draw the quad in the bottom left (two triangles).
664 wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
665 pass.SetPipeline(pipeline);
666 pass.Draw(6);
667 pass.EndPass();
668
669 wgpu::CommandBuffer commands = commandEncoder.Finish();
670 queue.Submit(1, &commands);
671 }
672
Austin Engf114a682020-09-01 18:40:18 +0000673 // Copy back the stencil data and check it is correct.
Yunchao He4eb40c12021-03-31 22:15:53 +0000674 EXPECT_TEXTURE_EQ(expectedStencilData.data(), depthStencilTexture, {0, 0}, {kWidth, kHeight}, 0,
Yunchao Heff55b2f2021-04-07 16:57:11 +0000675 wgpu::TextureAspect::StencilOnly);
Austin Eng0a434272020-08-04 19:46:37 +0000676
Austin Engf114a682020-09-01 18:40:18 +0000677 ExpectDepthData(depthStencilTexture, wgpu::TextureFormat::Depth24PlusStencil8, kWidth, kHeight,
678 0,
679 {
680 0.7, 0.7, 0.7, 0.7, //
681 0.7, 0.7, 0.7, 0.7, //
682 0.7, 0.7, 0.7, 0.7, //
683 0.7, 0.7, 0.7, 0.7, //
684 });
Austin Eng0a434272020-08-04 19:46:37 +0000685}
686
Austin Engb54c82e2020-08-18 18:53:26 +0000687DAWN_INSTANTIATE_TEST(DepthStencilCopyTests,
688 D3D12Backend(),
689 MetalBackend(),
690 OpenGLBackend(),
Stephen White6f5151f2020-12-01 21:52:37 +0000691 OpenGLESBackend(),
Austin Engb54c82e2020-08-18 18:53:26 +0000692 VulkanBackend());