• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 "common/Math.h"
18 #include "utils/ComboRenderPipelineDescriptor.h"
19 #include "utils/TestUtils.h"
20 #include "utils/WGPUHelpers.h"
21 
22 #define EXPECT_LAZY_CLEAR(N, statement)                                                       \
23     do {                                                                                      \
24         if (UsesWire()) {                                                                     \
25             statement;                                                                        \
26         } else {                                                                              \
27             size_t lazyClearsBefore = dawn_native::GetLazyClearCountForTesting(device.Get()); \
28             statement;                                                                        \
29             size_t lazyClearsAfter = dawn_native::GetLazyClearCountForTesting(device.Get());  \
30             EXPECT_EQ(N, lazyClearsAfter - lazyClearsBefore);                                 \
31         }                                                                                     \
32     } while (0)
33 
34 class TextureZeroInitTest : public DawnTest {
35   protected:
SetUp()36     void SetUp() override {
37         DawnTest::SetUp();
38         DAWN_TEST_UNSUPPORTED_IF(UsesWire());
39     }
CreateTextureDescriptor(uint32_t mipLevelCount,uint32_t arrayLayerCount,wgpu::TextureUsage usage,wgpu::TextureFormat format)40     wgpu::TextureDescriptor CreateTextureDescriptor(uint32_t mipLevelCount,
41                                                     uint32_t arrayLayerCount,
42                                                     wgpu::TextureUsage usage,
43                                                     wgpu::TextureFormat format) {
44         wgpu::TextureDescriptor descriptor;
45         descriptor.dimension = wgpu::TextureDimension::e2D;
46         descriptor.size.width = kSize;
47         descriptor.size.height = kSize;
48         descriptor.size.depthOrArrayLayers = arrayLayerCount;
49         descriptor.sampleCount = 1;
50         descriptor.format = format;
51         descriptor.mipLevelCount = mipLevelCount;
52         descriptor.usage = usage;
53         return descriptor;
54     }
CreateTextureViewDescriptor(uint32_t baseMipLevel,uint32_t baseArrayLayer,wgpu::TextureFormat format=kColorFormat)55     wgpu::TextureViewDescriptor CreateTextureViewDescriptor(
56         uint32_t baseMipLevel,
57         uint32_t baseArrayLayer,
58         wgpu::TextureFormat format = kColorFormat) {
59         wgpu::TextureViewDescriptor descriptor;
60         descriptor.format = format;
61         descriptor.baseArrayLayer = baseArrayLayer;
62         descriptor.arrayLayerCount = 1;
63         descriptor.baseMipLevel = baseMipLevel;
64         descriptor.mipLevelCount = 1;
65         descriptor.dimension = wgpu::TextureViewDimension::e2D;
66         return descriptor;
67     }
CreatePipelineForTest(float depth=0.f)68     wgpu::RenderPipeline CreatePipelineForTest(float depth = 0.f) {
69         utils::ComboRenderPipelineDescriptor pipelineDescriptor;
70         pipelineDescriptor.vertex.module = CreateBasicVertexShaderForTest(depth);
71         const char* fs = R"(
72             ;
73             [[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
74                return vec4<f32>(1.0, 0.0, 0.0, 1.0);
75             }
76         )";
77         pipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, fs);
78         wgpu::DepthStencilState* depthStencil = pipelineDescriptor.EnableDepthStencil();
79         depthStencil->depthCompare = wgpu::CompareFunction::Equal;
80         depthStencil->stencilFront.compare = wgpu::CompareFunction::Equal;
81 
82         return device.CreateRenderPipeline(&pipelineDescriptor);
83     }
CreateBasicVertexShaderForTest(float depth=0.f)84     wgpu::ShaderModule CreateBasicVertexShaderForTest(float depth = 0.f) {
85         std::string source = R"(
86             [[stage(vertex)]]
87             fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
88                 var pos = array<vec2<f32>, 6>(
89                     vec2<f32>(-1.0, -1.0),
90                     vec2<f32>(-1.0,  1.0),
91                     vec2<f32>( 1.0, -1.0),
92                     vec2<f32>( 1.0,  1.0),
93                     vec2<f32>(-1.0,  1.0),
94                     vec2<f32>( 1.0, -1.0)
95                 );
96                 return vec4<f32>(pos[VertexIndex], )" +
97                              std::to_string(depth) + R"(, 1.0);
98             })";
99         return utils::CreateShaderModule(device, source.c_str());
100     }
CreateSampledTextureFragmentShaderForTest()101     wgpu::ShaderModule CreateSampledTextureFragmentShaderForTest() {
102         return utils::CreateShaderModule(device, R"(
103             [[group(0), binding(0)]] var texture0 : texture_2d<f32>;
104             struct FragmentOut {
105                 [[location(0)]] color : vec4<f32>;
106             };
107             [[stage(fragment)]]
108             fn main([[builtin(position)]] FragCoord : vec4<f32>) -> FragmentOut {
109                 var output : FragmentOut;
110                 output.color = textureLoad(texture0, vec2<i32>(FragCoord.xy), 0);
111                 return output;
112             }
113         )");
114     }
115 
116     constexpr static uint32_t kSize = 128;
117     constexpr static uint32_t kUnalignedSize = 127;
118     // All texture formats used (RGBA8Unorm, Depth24PlusStencil8, and RGBA8Snorm, BC formats)
119     // have the same block byte size of 4.
120     constexpr static uint32_t kFormatBlockByteSize = 4;
121     constexpr static wgpu::TextureFormat kColorFormat = wgpu::TextureFormat::RGBA8Unorm;
122     constexpr static wgpu::TextureFormat kDepthStencilFormat =
123         wgpu::TextureFormat::Depth24PlusStencil8;
124     constexpr static wgpu::TextureFormat kNonrenderableColorFormat =
125         wgpu::TextureFormat::RGBA8Snorm;
126 };
127 
128 // This tests that the code path of CopyTextureToBuffer clears correctly to Zero after first usage
TEST_P(TextureZeroInitTest,CopyTextureToBufferSource)129 TEST_P(TextureZeroInitTest, CopyTextureToBufferSource) {
130     wgpu::TextureDescriptor descriptor = CreateTextureDescriptor(
131         1, 1, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, kColorFormat);
132     wgpu::Texture texture = device.CreateTexture(&descriptor);
133 
134     // Texture's first usage is in EXPECT_PIXEL_RGBA8_EQ's call to CopyTextureToBuffer
135     RGBA8 filledWithZeros(0, 0, 0, 0);
136     EXPECT_LAZY_CLEAR(1u, EXPECT_PIXEL_RGBA8_EQ(filledWithZeros, texture, 0, 0));
137 
138     // Expect texture subresource initialized to be true
139     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, 1));
140 }
141 
142 // This tests that the code path of CopyTextureToBuffer with multiple texture array layers clears
143 // correctly to Zero after first usage
TEST_P(TextureZeroInitTest,CopyMultipleTextureArrayLayersToBufferSource)144 TEST_P(TextureZeroInitTest, CopyMultipleTextureArrayLayersToBufferSource) {
145     constexpr uint32_t kArrayLayers = 6u;
146 
147     const wgpu::TextureDescriptor descriptor = CreateTextureDescriptor(
148         1, kArrayLayers, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc,
149         kColorFormat);
150     wgpu::Texture texture = device.CreateTexture(&descriptor);
151 
152     const uint32_t bytesPerRow = utils::GetMinimumBytesPerRow(kColorFormat, kSize);
153     const uint32_t rowsPerImage = kSize;
154     wgpu::BufferDescriptor bufferDescriptor;
155     bufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
156     bufferDescriptor.size = utils::RequiredBytesInCopy(bytesPerRow, rowsPerImage,
157                                                        {kSize, kSize, kArrayLayers}, kColorFormat);
158     wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor);
159 
160     const wgpu::ImageCopyBuffer imageCopyBuffer =
161         utils::CreateImageCopyBuffer(buffer, 0, bytesPerRow, kSize);
162     const wgpu::ImageCopyTexture imageCopyTexture =
163         utils::CreateImageCopyTexture(texture, 0, {0, 0, 0});
164     const wgpu::Extent3D copySize = {kSize, kSize, kArrayLayers};
165 
166     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
167     encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBuffer, &copySize);
168     wgpu::CommandBuffer commandBuffer = encoder.Finish();
169 
170     // Expect texture to be lazy initialized.
171     EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commandBuffer));
172 
173     // Expect texture subresource initialized to be true
174     EXPECT_TRUE(dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, kArrayLayers));
175 
176     const std::vector<RGBA8> kExpectedAllZero(kSize * kSize, {0, 0, 0, 0});
177     for (uint32_t layer = 0; layer < kArrayLayers; ++layer) {
178         EXPECT_TEXTURE_EQ(kExpectedAllZero.data(), texture, {0, 0, layer}, {kSize, kSize});
179     }
180 }
181 
182 // Test that non-zero mip level clears subresource to Zero after first use
183 // This goes through the BeginRenderPass's code path
TEST_P(TextureZeroInitTest,RenderingMipMapClearsToZero)184 TEST_P(TextureZeroInitTest, RenderingMipMapClearsToZero) {
185     uint32_t baseMipLevel = 2;
186     uint32_t levelCount = 4;
187     uint32_t baseArrayLayer = 0;
188     uint32_t layerCount = 1;
189 
190     wgpu::TextureDescriptor descriptor = CreateTextureDescriptor(
191         levelCount, layerCount, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc,
192         kColorFormat);
193     wgpu::Texture texture = device.CreateTexture(&descriptor);
194 
195     wgpu::TextureViewDescriptor viewDescriptor =
196         CreateTextureViewDescriptor(baseMipLevel, baseArrayLayer);
197     wgpu::TextureView view = texture.CreateView(&viewDescriptor);
198 
199     utils::BasicRenderPass renderPass = utils::BasicRenderPass(kSize, kSize, texture, kColorFormat);
200 
201     // Specify loadOp Load. Clear should be used to zero-initialize.
202     renderPass.renderPassInfo.cColorAttachments[0].loadOp = wgpu::LoadOp::Load;
203     // Specify non-zero clear color. It should still be cleared to zero.
204     renderPass.renderPassInfo.cColorAttachments[0].clearColor = {0.5f, 0.5f, 0.5f, 0.5f};
205     renderPass.renderPassInfo.cColorAttachments[0].view = view;
206 
207     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
208     {
209         // Texture's first usage is in BeginRenderPass's call to RecordRenderPass
210         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
211         pass.EndPass();
212     }
213     wgpu::CommandBuffer commands = encoder.Finish();
214     EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
215 
216     uint32_t mipSize = kSize >> 2;
217     std::vector<RGBA8> expected(mipSize * mipSize, {0, 0, 0, 0});
218 
219     EXPECT_TEXTURE_EQ(expected.data(), renderPass.color, {0, 0, baseArrayLayer}, {mipSize, mipSize},
220                       baseMipLevel);
221 
222     // Expect texture subresource initialized to be true
223     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
224                         renderPass.color.Get(), baseMipLevel, 1, baseArrayLayer, 1));
225 }
226 
227 // Test that non-zero array layers clears subresource to Zero after first use.
228 // This goes through the BeginRenderPass's code path
TEST_P(TextureZeroInitTest,RenderingArrayLayerClearsToZero)229 TEST_P(TextureZeroInitTest, RenderingArrayLayerClearsToZero) {
230     uint32_t baseMipLevel = 0;
231     uint32_t levelCount = 1;
232     uint32_t baseArrayLayer = 2;
233     uint32_t layerCount = 4;
234 
235     wgpu::TextureDescriptor descriptor = CreateTextureDescriptor(
236         levelCount, layerCount, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc,
237         kColorFormat);
238     wgpu::Texture texture = device.CreateTexture(&descriptor);
239 
240     wgpu::TextureViewDescriptor viewDescriptor =
241         CreateTextureViewDescriptor(baseMipLevel, baseArrayLayer);
242     wgpu::TextureView view = texture.CreateView(&viewDescriptor);
243 
244     utils::BasicRenderPass renderPass = utils::BasicRenderPass(kSize, kSize, texture, kColorFormat);
245 
246     // Specify loadOp Load. Clear should be used to zero-initialize.
247     renderPass.renderPassInfo.cColorAttachments[0].loadOp = wgpu::LoadOp::Load;
248     // Specify non-zero clear color. It should still be cleared to zero.
249     renderPass.renderPassInfo.cColorAttachments[0].clearColor = {0.5f, 0.5f, 0.5f, 0.5f};
250     renderPass.renderPassInfo.cColorAttachments[0].view = view;
251 
252     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
253     {
254         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
255         pass.EndPass();
256     }
257     wgpu::CommandBuffer commands = encoder.Finish();
258     EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
259 
260     std::vector<RGBA8> expected(kSize * kSize, {0, 0, 0, 0});
261 
262     EXPECT_TEXTURE_EQ(expected.data(), renderPass.color, {0, 0, baseArrayLayer}, {kSize, kSize},
263                       baseMipLevel);
264 
265     // Expect texture subresource initialized to be true
266     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
267                         renderPass.color.Get(), baseMipLevel, 1, baseArrayLayer, 1));
268 }
269 
270 // This tests CopyBufferToTexture fully overwrites copy so lazy init is not needed.
TEST_P(TextureZeroInitTest,CopyBufferToTexture)271 TEST_P(TextureZeroInitTest, CopyBufferToTexture) {
272     wgpu::TextureDescriptor descriptor =
273         CreateTextureDescriptor(4, 1,
274                                 wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::TextureBinding |
275                                     wgpu::TextureUsage::CopySrc,
276                                 kColorFormat);
277     wgpu::Texture texture = device.CreateTexture(&descriptor);
278 
279     std::vector<uint8_t> data(kFormatBlockByteSize * kSize * kSize, 100);
280     wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(
281         device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
282 
283     wgpu::ImageCopyBuffer imageCopyBuffer =
284         utils::CreateImageCopyBuffer(stagingBuffer, 0, kSize * sizeof(uint32_t));
285     wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(texture, 0, {0, 0, 0});
286     wgpu::Extent3D copySize = {kSize, kSize, 1};
287 
288     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
289     encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &copySize);
290     wgpu::CommandBuffer commands = encoder.Finish();
291     EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
292 
293     std::vector<RGBA8> expected(kSize * kSize, {100, 100, 100, 100});
294 
295     EXPECT_TEXTURE_EQ(expected.data(), texture, {0, 0}, {kSize, kSize});
296 
297     // Expect texture subresource initialized to be true
298     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, 1));
299 }
300 
301 // Test for a copy only to a subset of the subresource, lazy init is necessary to clear the other
302 // half.
TEST_P(TextureZeroInitTest,CopyBufferToTextureHalf)303 TEST_P(TextureZeroInitTest, CopyBufferToTextureHalf) {
304     wgpu::TextureDescriptor descriptor =
305         CreateTextureDescriptor(4, 1,
306                                 wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::TextureBinding |
307                                     wgpu::TextureUsage::CopySrc,
308                                 kColorFormat);
309     wgpu::Texture texture = device.CreateTexture(&descriptor);
310 
311     std::vector<uint8_t> data(kFormatBlockByteSize * kSize * kSize, 100);
312     wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(
313         device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
314 
315     wgpu::ImageCopyBuffer imageCopyBuffer =
316         utils::CreateImageCopyBuffer(stagingBuffer, 0, kSize * sizeof(uint16_t));
317     wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(texture, 0, {0, 0, 0});
318     wgpu::Extent3D copySize = {kSize / 2, kSize, 1};
319 
320     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
321     encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &copySize);
322     wgpu::CommandBuffer commands = encoder.Finish();
323     EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
324 
325     std::vector<RGBA8> expected100((kSize / 2) * kSize, {100, 100, 100, 100});
326     std::vector<RGBA8> expectedZeros((kSize / 2) * kSize, {0, 0, 0, 0});
327     // first half filled with 100, by the buffer data
328     EXPECT_TEXTURE_EQ(expected100.data(), texture, {0, 0}, {kSize / 2, kSize});
329     // second half should be cleared
330     EXPECT_TEXTURE_EQ(expectedZeros.data(), texture, {kSize / 2, 0}, {kSize / 2, kSize});
331 
332     // Expect texture subresource initialized to be true
333     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, 1));
334 }
335 
336 // This tests CopyBufferToTexture fully overwrites a range of subresources, so lazy initialization
337 // is needed for neither the subresources involved in the copy nor the other subresources.
TEST_P(TextureZeroInitTest,CopyBufferToTextureMultipleArrayLayers)338 TEST_P(TextureZeroInitTest, CopyBufferToTextureMultipleArrayLayers) {
339     wgpu::TextureDescriptor descriptor = CreateTextureDescriptor(
340         1, 6, wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc, kColorFormat);
341     wgpu::Texture texture = device.CreateTexture(&descriptor);
342 
343     constexpr uint32_t kBaseArrayLayer = 2u;
344     constexpr uint32_t kCopyLayerCount = 3u;
345     std::vector<uint8_t> data(kFormatBlockByteSize * kSize * kSize * kCopyLayerCount, 100);
346     wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(
347         device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
348 
349     const wgpu::ImageCopyBuffer imageCopyBuffer =
350         utils::CreateImageCopyBuffer(stagingBuffer, 0, kSize * kFormatBlockByteSize, kSize);
351     const wgpu::ImageCopyTexture imageCopyTexture =
352         utils::CreateImageCopyTexture(texture, 0, {0, 0, kBaseArrayLayer});
353     const wgpu::Extent3D copySize = {kSize, kSize, kCopyLayerCount};
354 
355     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
356     encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &copySize);
357     wgpu::CommandBuffer commands = encoder.Finish();
358 
359     // The copy overwrites the whole subresources so we don't need to do lazy initialization on
360     // them.
361     EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
362 
363     // Expect texture subresource initialized to be true
364     EXPECT_TRUE(dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, kBaseArrayLayer,
365                                                              kCopyLayerCount));
366 
367     const std::vector<RGBA8> expected100(kSize * kSize, {100, 100, 100, 100});
368     for (uint32_t layer = kBaseArrayLayer; layer < kBaseArrayLayer + kCopyLayerCount; ++layer) {
369         EXPECT_TEXTURE_EQ(expected100.data(), texture, {0, 0, layer}, {kSize, kSize});
370     }
371 }
372 
373 // This tests CopyTextureToTexture fully overwrites copy so lazy init is not needed.
TEST_P(TextureZeroInitTest,CopyTextureToTexture)374 TEST_P(TextureZeroInitTest, CopyTextureToTexture) {
375     wgpu::TextureDescriptor srcDescriptor = CreateTextureDescriptor(
376         1, 1, wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc, kColorFormat);
377     wgpu::Texture srcTexture = device.CreateTexture(&srcDescriptor);
378 
379     wgpu::ImageCopyTexture srcImageCopyTexture =
380         utils::CreateImageCopyTexture(srcTexture, 0, {0, 0, 0});
381 
382     wgpu::TextureDescriptor dstDescriptor =
383         CreateTextureDescriptor(1, 1,
384                                 wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopyDst |
385                                     wgpu::TextureUsage::CopySrc,
386                                 kColorFormat);
387     wgpu::Texture dstTexture = device.CreateTexture(&dstDescriptor);
388 
389     wgpu::ImageCopyTexture dstImageCopyTexture =
390         utils::CreateImageCopyTexture(dstTexture, 0, {0, 0, 0});
391 
392     wgpu::Extent3D copySize = {kSize, kSize, 1};
393 
394     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
395     encoder.CopyTextureToTexture(&srcImageCopyTexture, &dstImageCopyTexture, &copySize);
396     wgpu::CommandBuffer commands = encoder.Finish();
397     EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
398 
399     std::vector<RGBA8> expected(kSize * kSize, {0, 0, 0, 0});
400 
401     EXPECT_TEXTURE_EQ(expected.data(), srcTexture, {0, 0}, {kSize, kSize});
402     EXPECT_TEXTURE_EQ(expected.data(), dstTexture, {0, 0}, {kSize, kSize});
403 
404     // Expect texture subresource initialized to be true
405     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(srcTexture.Get(), 0, 1, 0, 1));
406     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(dstTexture.Get(), 0, 1, 0, 1));
407 }
408 
409 // This Tests the CopyTextureToTexture's copy only to a subset of the subresource, lazy init is
410 // necessary to clear the other half.
TEST_P(TextureZeroInitTest,CopyTextureToTextureHalf)411 TEST_P(TextureZeroInitTest, CopyTextureToTextureHalf) {
412     wgpu::TextureDescriptor srcDescriptor =
413         CreateTextureDescriptor(1, 1,
414                                 wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc |
415                                     wgpu::TextureUsage::CopyDst,
416                                 kColorFormat);
417     wgpu::Texture srcTexture = device.CreateTexture(&srcDescriptor);
418 
419     // fill srcTexture with 100
420     {
421         std::vector<uint8_t> data(kFormatBlockByteSize * kSize * kSize, 100);
422         wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(
423             device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
424         wgpu::ImageCopyBuffer imageCopyBuffer =
425             utils::CreateImageCopyBuffer(stagingBuffer, 0, kSize * kFormatBlockByteSize);
426         wgpu::ImageCopyTexture imageCopyTexture =
427             utils::CreateImageCopyTexture(srcTexture, 0, {0, 0, 0});
428         wgpu::Extent3D copySize = {kSize, kSize, 1};
429         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
430         encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &copySize);
431         wgpu::CommandBuffer commands = encoder.Finish();
432         queue.Submit(1, &commands);
433     }
434 
435     wgpu::ImageCopyTexture srcImageCopyTexture =
436         utils::CreateImageCopyTexture(srcTexture, 0, {0, 0, 0});
437 
438     wgpu::TextureDescriptor dstDescriptor =
439         CreateTextureDescriptor(1, 1,
440                                 wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopyDst |
441                                     wgpu::TextureUsage::CopySrc,
442                                 kColorFormat);
443     wgpu::Texture dstTexture = device.CreateTexture(&dstDescriptor);
444 
445     wgpu::ImageCopyTexture dstImageCopyTexture =
446         utils::CreateImageCopyTexture(dstTexture, 0, {0, 0, 0});
447     wgpu::Extent3D copySize = {kSize / 2, kSize, 1};
448 
449     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
450     encoder.CopyTextureToTexture(&srcImageCopyTexture, &dstImageCopyTexture, &copySize);
451     wgpu::CommandBuffer commands = encoder.Finish();
452     EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
453 
454     std::vector<RGBA8> expectedWithZeros((kSize / 2) * kSize, {0, 0, 0, 0});
455     std::vector<RGBA8> expectedWith100(kSize * kSize, {100, 100, 100, 100});
456 
457     EXPECT_TEXTURE_EQ(expectedWith100.data(), srcTexture, {0, 0}, {kSize, kSize});
458     EXPECT_TEXTURE_EQ(expectedWith100.data(), dstTexture, {0, 0}, {kSize / 2, kSize});
459     EXPECT_TEXTURE_EQ(expectedWithZeros.data(), dstTexture, {kSize / 2, 0}, {kSize / 2, kSize});
460 
461     // Expect texture subresource initialized to be true
462     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(srcTexture.Get(), 0, 1, 0, 1));
463     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(dstTexture.Get(), 0, 1, 0, 1));
464 }
465 
466 // This tests the texture with depth attachment and load op load will init depth stencil texture to
467 // 0s.
TEST_P(TextureZeroInitTest,RenderingLoadingDepth)468 TEST_P(TextureZeroInitTest, RenderingLoadingDepth) {
469     wgpu::TextureDescriptor srcDescriptor =
470         CreateTextureDescriptor(1, 1,
471                                 wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
472                                     wgpu::TextureUsage::RenderAttachment,
473                                 kColorFormat);
474     wgpu::Texture srcTexture = device.CreateTexture(&srcDescriptor);
475 
476     wgpu::TextureDescriptor depthStencilDescriptor = CreateTextureDescriptor(
477         1, 1, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc,
478         kDepthStencilFormat);
479     wgpu::Texture depthStencilTexture = device.CreateTexture(&depthStencilDescriptor);
480 
481     utils::ComboRenderPassDescriptor renderPassDescriptor({srcTexture.CreateView()},
482                                                           depthStencilTexture.CreateView());
483     renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
484     // Set clearDepth to non-zero. It should still be cleared to 0 by the loadOp.
485     renderPassDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.5f;
486     renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Clear;
487     renderPassDescriptor.cDepthStencilAttachmentInfo.clearStencil = 0;
488     renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Store;
489     renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
490 
491     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
492     auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
493     pass.SetPipeline(CreatePipelineForTest());
494     pass.Draw(6);
495     pass.EndPass();
496     wgpu::CommandBuffer commandBuffer = encoder.Finish();
497     // Expect 0 lazy clears, depth stencil texture will clear using loadop
498     EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
499 
500     // Expect the texture to be red because depth test passed.
501     std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
502     EXPECT_TEXTURE_EQ(expected.data(), srcTexture, {0, 0}, {kSize, kSize});
503 
504     // Expect texture subresource initialized to be true
505     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(srcTexture.Get(), 0, 1, 0, 1));
506 }
507 
508 // This tests the texture with stencil attachment and load op load will init depth stencil texture
509 // to 0s.
TEST_P(TextureZeroInitTest,RenderingLoadingStencil)510 TEST_P(TextureZeroInitTest, RenderingLoadingStencil) {
511     wgpu::TextureDescriptor srcDescriptor =
512         CreateTextureDescriptor(1, 1,
513                                 wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
514                                     wgpu::TextureUsage::RenderAttachment,
515                                 kColorFormat);
516     wgpu::Texture srcTexture = device.CreateTexture(&srcDescriptor);
517 
518     wgpu::TextureDescriptor depthStencilDescriptor = CreateTextureDescriptor(
519         1, 1, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc,
520         kDepthStencilFormat);
521     wgpu::Texture depthStencilTexture = device.CreateTexture(&depthStencilDescriptor);
522 
523     utils::ComboRenderPassDescriptor renderPassDescriptor({srcTexture.CreateView()},
524                                                           depthStencilTexture.CreateView());
525     renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Clear;
526     renderPassDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.0f;
527     renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
528     // Set clearStencil to non-zero. It should still be cleared to 0 by the loadOp.
529     renderPassDescriptor.cDepthStencilAttachmentInfo.clearStencil = 2;
530     renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Store;
531     renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
532 
533     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
534     auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
535     pass.SetPipeline(CreatePipelineForTest());
536     pass.Draw(6);
537     pass.EndPass();
538     wgpu::CommandBuffer commandBuffer = encoder.Finish();
539     // Expect 0 lazy clears, depth stencil texture will clear using loadop
540     EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
541 
542     // Expect the texture to be red because stencil test passed.
543     std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
544     EXPECT_TEXTURE_EQ(expected.data(), srcTexture, {0, 0}, {kSize, kSize});
545 
546     // Expect texture subresource initialized to be true
547     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(srcTexture.Get(), 0, 1, 0, 1));
548 }
549 
550 // This tests the texture with depth stencil attachment and load op load will init depth stencil
551 // texture to 0s.
TEST_P(TextureZeroInitTest,RenderingLoadingDepthStencil)552 TEST_P(TextureZeroInitTest, RenderingLoadingDepthStencil) {
553     wgpu::TextureDescriptor srcDescriptor =
554         CreateTextureDescriptor(1, 1,
555                                 wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
556                                     wgpu::TextureUsage::RenderAttachment,
557                                 kColorFormat);
558     wgpu::Texture srcTexture = device.CreateTexture(&srcDescriptor);
559 
560     wgpu::TextureDescriptor depthStencilDescriptor = CreateTextureDescriptor(
561         1, 1, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc,
562         kDepthStencilFormat);
563     wgpu::Texture depthStencilTexture = device.CreateTexture(&depthStencilDescriptor);
564 
565     utils::ComboRenderPassDescriptor renderPassDescriptor({srcTexture.CreateView()},
566                                                           depthStencilTexture.CreateView());
567     renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
568     renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
569     renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Store;
570     renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
571 
572     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
573     auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
574     pass.SetPipeline(CreatePipelineForTest());
575     pass.Draw(6);
576     pass.EndPass();
577     wgpu::CommandBuffer commandBuffer = encoder.Finish();
578     // Expect 0 lazy clears, depth stencil texture will clear using loadop
579     EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
580 
581     // Expect the texture to be red because both depth and stencil tests passed.
582     std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
583     EXPECT_TEXTURE_EQ(expected.data(), srcTexture, {0, 0}, {kSize, kSize});
584 
585     // Expect texture subresource initialized to be true
586     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(srcTexture.Get(), 0, 1, 0, 1));
587 }
588 
589 // Test that clear state is tracked independently for depth/stencil textures.
TEST_P(TextureZeroInitTest,IndependentDepthStencilLoadAfterDiscard)590 TEST_P(TextureZeroInitTest, IndependentDepthStencilLoadAfterDiscard) {
591     // TODO(crbug.com/dawn/704): Readback after clear via stencil copy does not work
592     // on some Intel drivers.
593     DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel());
594 
595     // TODO(crbug.com/dawn/1151): The test started failing on Wintel Vulkan when Discard was
596     // implemented for the Vulkan backend.
597     DAWN_SUPPRESS_TEST_IF(IsVulkan() && IsWindows() && IsIntel());
598 
599     wgpu::TextureDescriptor depthStencilDescriptor = CreateTextureDescriptor(
600         1, 1, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc,
601         kDepthStencilFormat);
602     wgpu::Texture depthStencilTexture = device.CreateTexture(&depthStencilDescriptor);
603 
604     // Uninitialize only depth
605     {
606         // Clear the stencil to 2 and discard the depth
607         {
608             utils::ComboRenderPassDescriptor renderPassDescriptor({},
609                                                                   depthStencilTexture.CreateView());
610             renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Discard;
611             renderPassDescriptor.cDepthStencilAttachmentInfo.clearStencil = 2;
612             renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Store;
613 
614             wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
615             auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
616             pass.EndPass();
617             wgpu::CommandBuffer commandBuffer = encoder.Finish();
618             EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
619         }
620 
621         // "all" subresources are not initialized; Depth is not initialized
622         EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(
623                              depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_All));
624         EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(
625                              depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_DepthOnly));
626         EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
627                             depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly));
628 
629         // Now load both depth and stencil. Depth should be cleared and stencil should stay the same
630         // at 2.
631         {
632             wgpu::TextureDescriptor colorDescriptor =
633                 CreateTextureDescriptor(1, 1,
634                                         wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
635                                             wgpu::TextureUsage::RenderAttachment,
636                                         kColorFormat);
637             wgpu::Texture colorTexture = device.CreateTexture(&colorDescriptor);
638 
639             utils::ComboRenderPassDescriptor renderPassDescriptor({colorTexture.CreateView()},
640                                                                   depthStencilTexture.CreateView());
641             renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
642             renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
643 
644             wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
645             auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
646             pass.SetPipeline(CreatePipelineForTest());
647             pass.SetStencilReference(2);
648             pass.Draw(6);
649             pass.EndPass();
650             wgpu::CommandBuffer commandBuffer = encoder.Finish();
651             // No lazy clear because depth will be cleared with a loadOp
652             EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
653 
654             // Expect the texture to be red because the depth and stencil tests passed. Depth was 0
655             // and stencil was 2.
656             std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
657             EXPECT_TEXTURE_EQ(expected.data(), colorTexture, {0, 0}, {kSize, kSize});
658         }
659 
660         // Everything is initialized now
661         EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
662                             depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_All));
663         EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
664                             depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_DepthOnly));
665         EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
666                             depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly));
667 
668         // TODO(crbug.com/dawn/439): Implement stencil copies on other platforms
669         if (IsMetal() || IsVulkan() || IsD3D12()) {
670             // Check by copy that the stencil data is 2.
671             std::vector<uint8_t> expected(kSize * kSize, 2);
672             EXPECT_LAZY_CLEAR(
673                 0u, EXPECT_TEXTURE_EQ(expected.data(), depthStencilTexture, {0, 0}, {kSize, kSize},
674                                       0, wgpu::TextureAspect::StencilOnly));
675         }
676     }
677 
678     // Uninitialize only stencil
679     {
680         // Clear the depth to 0.7 and discard the stencil.
681         {
682             utils::ComboRenderPassDescriptor renderPassDescriptor({},
683                                                                   depthStencilTexture.CreateView());
684             renderPassDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.7;
685             renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Store;
686             renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp =
687                 wgpu::StoreOp::Discard;
688 
689             wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
690             auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
691             pass.EndPass();
692             wgpu::CommandBuffer commandBuffer = encoder.Finish();
693             EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
694         }
695 
696         // "all" subresources are not initialized; Stencil is not initialized
697         EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(
698                              depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_All));
699         EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
700                             depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_DepthOnly));
701         EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(
702                              depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly));
703 
704         // Now load both depth and stencil. Stencil should be cleared and depth should stay the same
705         // at 0.7.
706         {
707             wgpu::TextureDescriptor colorDescriptor =
708                 CreateTextureDescriptor(1, 1,
709                                         wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
710                                             wgpu::TextureUsage::RenderAttachment,
711                                         kColorFormat);
712             wgpu::Texture colorTexture = device.CreateTexture(&colorDescriptor);
713 
714             utils::ComboRenderPassDescriptor renderPassDescriptor({colorTexture.CreateView()},
715                                                                   depthStencilTexture.CreateView());
716             renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
717             renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
718 
719             wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
720             auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
721             pass.SetPipeline(CreatePipelineForTest(0.7));
722             pass.Draw(6);
723             pass.EndPass();
724             wgpu::CommandBuffer commandBuffer = encoder.Finish();
725             // No lazy clear because stencil will clear using a loadOp.
726             EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
727 
728             // Expect the texture to be red because both the depth a stencil tests passed.
729             // Depth was 0.7 and stencil was 0
730             std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
731             EXPECT_TEXTURE_EQ(expected.data(), colorTexture, {0, 0}, {kSize, kSize});
732         }
733 
734         // Everything is initialized now
735         EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
736                             depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_All));
737         EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
738                             depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_DepthOnly));
739         EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(
740                             depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly));
741 
742         // TODO(crbug.com/dawn/439): Implement stencil copies on other platforms
743         if (IsMetal() || IsVulkan() || IsD3D12()) {
744             // Check by copy that the stencil data is 0.
745             std::vector<uint8_t> expected(kSize * kSize, 0);
746             EXPECT_LAZY_CLEAR(
747                 0u, EXPECT_TEXTURE_EQ(expected.data(), depthStencilTexture, {0, 0}, {kSize, kSize},
748                                       0, wgpu::TextureAspect::StencilOnly));
749         }
750     }
751 }
752 
753 // Test that clear state is tracked independently for depth/stencil textures.
754 // Lazy clear of the stencil aspect via copy should not touch depth.
TEST_P(TextureZeroInitTest,IndependentDepthStencilCopyAfterDiscard)755 TEST_P(TextureZeroInitTest, IndependentDepthStencilCopyAfterDiscard) {
756     // TODO(crbug.com/dawn/439): Implement stencil copies on other platforms
757     DAWN_SUPPRESS_TEST_IF(!(IsMetal() || IsVulkan() || IsD3D12()));
758 
759     // TODO(enga): Figure out why this fails on Metal Intel.
760     DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel());
761 
762     wgpu::TextureDescriptor depthStencilDescriptor = CreateTextureDescriptor(
763         1, 1, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc,
764         kDepthStencilFormat);
765     wgpu::Texture depthStencilTexture = device.CreateTexture(&depthStencilDescriptor);
766 
767     // Clear the depth to 0.3 and discard the stencil.
768     {
769         utils::ComboRenderPassDescriptor renderPassDescriptor({}, depthStencilTexture.CreateView());
770         renderPassDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.3;
771         renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Store;
772         renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Discard;
773 
774         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
775         auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
776         pass.EndPass();
777         wgpu::CommandBuffer commandBuffer = encoder.Finish();
778         EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
779     }
780 
781     // "all" subresources are not initialized; Stencil is not initialized
782     EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1,
783                                                                   0, 1, WGPUTextureAspect_All));
784     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1, 0,
785                                                                  1, WGPUTextureAspect_DepthOnly));
786     EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(
787                          depthStencilTexture.Get(), 0, 1, 0, 1, WGPUTextureAspect_StencilOnly));
788 
789     // Check by copy that the stencil data is lazily cleared to 0.
790     std::vector<uint8_t> expected(kSize * kSize, 0);
791     EXPECT_LAZY_CLEAR(1u, EXPECT_TEXTURE_EQ(expected.data(), depthStencilTexture, {0, 0},
792                                             {kSize, kSize}, 0, wgpu::TextureAspect::StencilOnly));
793 
794     // Everything is initialized now
795     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1, 0,
796                                                                  1, WGPUTextureAspect_All));
797     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1, 0,
798                                                                  1, WGPUTextureAspect_DepthOnly));
799     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0, 1, 0,
800                                                                  1, WGPUTextureAspect_StencilOnly));
801 
802     // Now load both depth and stencil. Stencil should be cleared and depth should stay the same
803     // at 0.3.
804     {
805         wgpu::TextureDescriptor colorDescriptor =
806             CreateTextureDescriptor(1, 1,
807                                     wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
808                                         wgpu::TextureUsage::RenderAttachment,
809                                     kColorFormat);
810         wgpu::Texture colorTexture = device.CreateTexture(&colorDescriptor);
811 
812         utils::ComboRenderPassDescriptor renderPassDescriptor({colorTexture.CreateView()},
813                                                               depthStencilTexture.CreateView());
814         renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
815         renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
816 
817         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
818         auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
819         pass.SetPipeline(CreatePipelineForTest(0.3));
820         pass.Draw(6);
821         pass.EndPass();
822         wgpu::CommandBuffer commandBuffer = encoder.Finish();
823         // No lazy clear because stencil will clear using a loadOp.
824         EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
825 
826         // Expect the texture to be red because both the depth a stencil tests passed.
827         // Depth was 0.3 and stencil was 0
828         std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
829         EXPECT_TEXTURE_EQ(expected.data(), colorTexture, {0, 0}, {kSize, kSize});
830     }
831 }
832 
833 // This tests the color attachments clear to 0s
TEST_P(TextureZeroInitTest,ColorAttachmentsClear)834 TEST_P(TextureZeroInitTest, ColorAttachmentsClear) {
835     wgpu::TextureDescriptor descriptor = CreateTextureDescriptor(
836         1, 1, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, kColorFormat);
837     wgpu::Texture texture = device.CreateTexture(&descriptor);
838     utils::BasicRenderPass renderPass = utils::BasicRenderPass(kSize, kSize, texture, kColorFormat);
839     renderPass.renderPassInfo.cColorAttachments[0].loadOp = wgpu::LoadOp::Load;
840 
841     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
842     wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
843     pass.EndPass();
844 
845     wgpu::CommandBuffer commands = encoder.Finish();
846     EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
847 
848     std::vector<RGBA8> expected(kSize * kSize, {0, 0, 0, 0});
849     EXPECT_TEXTURE_EQ(expected.data(), renderPass.color, {0, 0}, {kSize, kSize});
850 
851     // Expect texture subresource initialized to be true
852     EXPECT_EQ(true,
853               dawn_native::IsTextureSubresourceInitialized(renderPass.color.Get(), 0, 1, 0, 1));
854 }
855 
856 // This tests the clearing of sampled textures in render pass
TEST_P(TextureZeroInitTest,RenderPassSampledTextureClear)857 TEST_P(TextureZeroInitTest, RenderPassSampledTextureClear) {
858     // Create needed resources
859     wgpu::TextureDescriptor descriptor =
860         CreateTextureDescriptor(1, 1, wgpu::TextureUsage::TextureBinding, kColorFormat);
861     wgpu::Texture texture = device.CreateTexture(&descriptor);
862 
863     wgpu::TextureDescriptor renderTextureDescriptor = CreateTextureDescriptor(
864         1, 1, wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment, kColorFormat);
865     wgpu::Texture renderTexture = device.CreateTexture(&renderTextureDescriptor);
866 
867     // Create render pipeline
868     utils::ComboRenderPipelineDescriptor renderPipelineDescriptor;
869     renderPipelineDescriptor.cTargets[0].format = kColorFormat;
870     renderPipelineDescriptor.vertex.module = CreateBasicVertexShaderForTest();
871     renderPipelineDescriptor.cFragment.module = CreateSampledTextureFragmentShaderForTest();
872     wgpu::RenderPipeline renderPipeline = device.CreateRenderPipeline(&renderPipelineDescriptor);
873 
874     // Create bindgroup
875     wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, renderPipeline.GetBindGroupLayout(0),
876                                                      {{0, texture.CreateView()}});
877 
878     // Encode pass and submit
879     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
880     utils::ComboRenderPassDescriptor renderPassDesc({renderTexture.CreateView()});
881     renderPassDesc.cColorAttachments[0].clearColor = {1.0, 1.0, 1.0, 1.0};
882     renderPassDesc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
883     wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
884     pass.SetPipeline(renderPipeline);
885     pass.SetBindGroup(0, bindGroup);
886     pass.Draw(6);
887     pass.EndPass();
888     wgpu::CommandBuffer commands = encoder.Finish();
889     // Expect 1 lazy clear for sampled texture
890     EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
891 
892     // Expect the rendered texture to be cleared
893     std::vector<RGBA8> expectedWithZeros(kSize * kSize, {0, 0, 0, 0});
894     EXPECT_TEXTURE_EQ(expectedWithZeros.data(), renderTexture, {0, 0}, {kSize, kSize});
895 
896     // Expect texture subresource initialized to be true
897     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(renderTexture.Get(), 0, 1, 0, 1));
898 }
899 
900 // This is a regression test for a bug where a texture wouldn't get clear for a pass if at least
901 // one of its subresources was used as an attachment. It tests that if a texture is used as both
902 // sampled and attachment (with LoadOp::Clear so the lazy clear can be skipped) then the sampled
903 // subresource is correctly cleared.
TEST_P(TextureZeroInitTest,TextureBothSampledAndAttachmentClear)904 TEST_P(TextureZeroInitTest, TextureBothSampledAndAttachmentClear) {
905     // TODO(crbug.com/dawn/593): This test uses glTextureView() which is not supported on OpenGL ES.
906     DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
907 
908     // Create a 2D array texture, layer 0 will be used as attachment, layer 1 as sampled.
909     wgpu::TextureDescriptor texDesc;
910     texDesc.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment |
911                     wgpu::TextureUsage::CopySrc;
912     texDesc.size = {1, 1, 2};
913     texDesc.format = wgpu::TextureFormat::RGBA8Unorm;
914     wgpu::Texture texture = device.CreateTexture(&texDesc);
915 
916     wgpu::TextureViewDescriptor viewDesc;
917     viewDesc.dimension = wgpu::TextureViewDimension::e2D;
918     viewDesc.arrayLayerCount = 1;
919 
920     viewDesc.baseArrayLayer = 0;
921     wgpu::TextureView attachmentView = texture.CreateView(&viewDesc);
922 
923     viewDesc.baseArrayLayer = 1;
924     wgpu::TextureView sampleView = texture.CreateView(&viewDesc);
925 
926     // Create render pipeline
927     utils::ComboRenderPipelineDescriptor renderPipelineDescriptor;
928     renderPipelineDescriptor.cTargets[0].format = wgpu::TextureFormat::RGBA8Unorm;
929     renderPipelineDescriptor.vertex.module = CreateBasicVertexShaderForTest();
930     renderPipelineDescriptor.cFragment.module = CreateSampledTextureFragmentShaderForTest();
931     wgpu::RenderPipeline renderPipeline = device.CreateRenderPipeline(&renderPipelineDescriptor);
932 
933     wgpu::BindGroup bindGroup =
934         utils::MakeBindGroup(device, renderPipeline.GetBindGroupLayout(0), {{0, sampleView}});
935 
936     // Encode pass and submit
937     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
938     utils::ComboRenderPassDescriptor renderPassDesc({attachmentView});
939     renderPassDesc.cColorAttachments[0].clearColor = {1.0, 1.0, 1.0, 1.0};
940     renderPassDesc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
941     wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
942     pass.SetPipeline(renderPipeline);
943     pass.SetBindGroup(0, bindGroup);
944     pass.Draw(6);
945     pass.EndPass();
946     wgpu::CommandBuffer commands = encoder.Finish();
947 
948     // Expect the lazy clear for the sampled subresource.
949     EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
950 
951     // Expect both subresources to be zero: the sampled one with lazy-clearing and the attachment
952     // because it sampled the lazy-cleared sampled subresource.
953     EXPECT_TEXTURE_EQ(&RGBA8::kZero, texture, {0, 0, 0}, {1, 1});
954     EXPECT_TEXTURE_EQ(&RGBA8::kZero, texture, {0, 0, 1}, {1, 1});
955 
956     // The whole texture is now initialized.
957     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, 2));
958 }
959 
960 // This tests the clearing of sampled textures during compute pass
TEST_P(TextureZeroInitTest,ComputePassSampledTextureClear)961 TEST_P(TextureZeroInitTest, ComputePassSampledTextureClear) {
962     // Create needed resources
963     wgpu::TextureDescriptor descriptor =
964         CreateTextureDescriptor(1, 1, wgpu::TextureUsage::TextureBinding, kColorFormat);
965     descriptor.size.width = 1;
966     descriptor.size.height = 1;
967     wgpu::Texture texture = device.CreateTexture(&descriptor);
968 
969     uint32_t bufferSize = kFormatBlockByteSize * sizeof(uint32_t);
970     wgpu::BufferDescriptor bufferDescriptor;
971     bufferDescriptor.size = bufferSize;
972     bufferDescriptor.usage =
973         wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopyDst;
974     wgpu::Buffer bufferTex = device.CreateBuffer(&bufferDescriptor);
975     // Add data to buffer to ensure it is initialized
976     uint32_t data = 100;
977     queue.WriteBuffer(bufferTex, 0, &data, sizeof(data));
978 
979     wgpu::Sampler sampler = device.CreateSampler();
980 
981     // Create compute pipeline
982     wgpu::ComputePipelineDescriptor computePipelineDescriptor;
983     wgpu::ProgrammableStageDescriptor compute;
984     const char* cs = R"(
985         [[group(0), binding(0)]] var tex : texture_2d<f32>;
986         [[block]] struct Result {
987             value : vec4<f32>;
988         };
989         [[group(0), binding(1)]] var<storage, read_write> result : Result;
990         [[stage(compute), workgroup_size(1)]] fn main() {
991            result.value = textureLoad(tex, vec2<i32>(0,0), 0);
992         }
993     )";
994     computePipelineDescriptor.compute.module = utils::CreateShaderModule(device, cs);
995     computePipelineDescriptor.compute.entryPoint = "main";
996     wgpu::ComputePipeline computePipeline =
997         device.CreateComputePipeline(&computePipelineDescriptor);
998 
999     // Create bindgroup
1000     wgpu::BindGroup bindGroup =
1001         utils::MakeBindGroup(device, computePipeline.GetBindGroupLayout(0),
1002                              {{0, texture.CreateView()}, {1, bufferTex, 0, bufferSize}});
1003 
1004     // Encode the pass and submit
1005     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
1006     wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
1007     pass.SetPipeline(computePipeline);
1008     pass.SetBindGroup(0, bindGroup);
1009     pass.Dispatch(1);
1010     pass.EndPass();
1011     wgpu::CommandBuffer commands = encoder.Finish();
1012     EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
1013 
1014     // Expect the buffer to be zeroed out by the compute pass
1015     std::vector<uint32_t> expectedWithZeros(bufferSize, 0);
1016     EXPECT_BUFFER_U32_RANGE_EQ(expectedWithZeros.data(), bufferTex, 0, kFormatBlockByteSize);
1017 
1018     // Expect texture subresource initialized to be true
1019     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, 1));
1020 }
1021 
1022 // This tests that the code path of CopyTextureToBuffer clears correctly for non-renderable textures
TEST_P(TextureZeroInitTest,NonRenderableTextureClear)1023 TEST_P(TextureZeroInitTest, NonRenderableTextureClear) {
1024     // TODO(crbug.com/dawn/667): Work around the fact that some platforms do not support reading
1025     // from Snorm textures.
1026     DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_snorm_read"));
1027 
1028     wgpu::TextureDescriptor descriptor =
1029         CreateTextureDescriptor(1, 1, wgpu::TextureUsage::CopySrc, kNonrenderableColorFormat);
1030     wgpu::Texture texture = device.CreateTexture(&descriptor);
1031 
1032     // Set buffer with dirty data so we know it is cleared by the lazy cleared texture copy
1033     uint32_t bytesPerRow = Align(kSize * kFormatBlockByteSize, kTextureBytesPerRowAlignment);
1034     uint32_t bufferSize = bytesPerRow * kSize;
1035     std::vector<uint8_t> data(bufferSize, 100);
1036     wgpu::Buffer bufferDst = utils::CreateBufferFromData(
1037         device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
1038 
1039     wgpu::ImageCopyBuffer imageCopyBuffer = utils::CreateImageCopyBuffer(bufferDst, 0, bytesPerRow);
1040     wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(texture, 0, {0, 0, 0});
1041     wgpu::Extent3D copySize = {kSize, kSize, 1};
1042 
1043     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
1044     encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBuffer, &copySize);
1045     wgpu::CommandBuffer commands = encoder.Finish();
1046     EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
1047 
1048     std::vector<uint32_t> expectedWithZeros(bufferSize, 0);
1049     EXPECT_BUFFER_U32_RANGE_EQ(expectedWithZeros.data(), bufferDst, 0, kSize);
1050 
1051     // Expect texture subresource initialized to be true
1052     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, 1));
1053 }
1054 
1055 // This tests that the code path of CopyTextureToBuffer clears correctly for non-renderable textures
TEST_P(TextureZeroInitTest,NonRenderableTextureClearUnalignedSize)1056 TEST_P(TextureZeroInitTest, NonRenderableTextureClearUnalignedSize) {
1057     // TODO(crbug.com/dawn/667): Work around the fact that some platforms do not support reading
1058     // from Snorm textures.
1059     DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_snorm_read"));
1060 
1061     wgpu::TextureDescriptor descriptor =
1062         CreateTextureDescriptor(1, 1, wgpu::TextureUsage::CopySrc, kNonrenderableColorFormat);
1063     descriptor.size.width = kUnalignedSize;
1064     descriptor.size.height = kUnalignedSize;
1065     wgpu::Texture texture = device.CreateTexture(&descriptor);
1066 
1067     // Set buffer with dirty data so we know it is cleared by the lazy cleared texture copy
1068     uint32_t bytesPerRow =
1069         Align(kUnalignedSize * kFormatBlockByteSize, kTextureBytesPerRowAlignment);
1070     uint32_t bufferSize = bytesPerRow * kUnalignedSize;
1071     std::vector<uint8_t> data(bufferSize, 100);
1072     wgpu::Buffer bufferDst = utils::CreateBufferFromData(
1073         device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
1074     wgpu::ImageCopyBuffer imageCopyBuffer = utils::CreateImageCopyBuffer(bufferDst, 0, bytesPerRow);
1075     wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(texture, 0, {0, 0, 0});
1076     wgpu::Extent3D copySize = {kUnalignedSize, kUnalignedSize, 1};
1077 
1078     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
1079     encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBuffer, &copySize);
1080     wgpu::CommandBuffer commands = encoder.Finish();
1081     EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
1082 
1083     std::vector<uint32_t> expectedWithZeros(bufferSize, 0);
1084     EXPECT_BUFFER_U32_RANGE_EQ(expectedWithZeros.data(), bufferDst, 0, kUnalignedSize);
1085 
1086     // Expect texture subresource initialized to be true
1087     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, 1));
1088 }
1089 
1090 // This tests that the code path of CopyTextureToBuffer clears correctly for non-renderable textures
1091 // with more than 1 array layers
TEST_P(TextureZeroInitTest,NonRenderableTextureClearWithMultiArrayLayers)1092 TEST_P(TextureZeroInitTest, NonRenderableTextureClearWithMultiArrayLayers) {
1093     // TODO(crbug.com/dawn/667): Work around the fact that some platforms do not support reading
1094     // from Snorm textures.
1095     DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_snorm_read"));
1096 
1097     wgpu::TextureDescriptor descriptor =
1098         CreateTextureDescriptor(1, 2, wgpu::TextureUsage::CopySrc, kNonrenderableColorFormat);
1099     wgpu::Texture texture = device.CreateTexture(&descriptor);
1100 
1101     // Set buffer with dirty data so we know it is cleared by the lazy cleared texture copy
1102     uint32_t bufferSize = kFormatBlockByteSize * kSize * kSize;
1103     std::vector<uint8_t> data(bufferSize, 100);
1104     wgpu::Buffer bufferDst = utils::CreateBufferFromData(
1105         device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
1106 
1107     wgpu::ImageCopyBuffer imageCopyBuffer =
1108         utils::CreateImageCopyBuffer(bufferDst, 0, kSize * kFormatBlockByteSize);
1109     wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(texture, 0, {0, 0, 1});
1110     wgpu::Extent3D copySize = {kSize, kSize, 1};
1111 
1112     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
1113     encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBuffer, &copySize);
1114     wgpu::CommandBuffer commands = encoder.Finish();
1115     EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
1116 
1117     std::vector<uint32_t> expectedWithZeros(bufferSize, 0);
1118     EXPECT_BUFFER_U32_RANGE_EQ(expectedWithZeros.data(), bufferDst, 0, 8);
1119 
1120     // Expect texture subresource initialized to be true
1121     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 1, 1));
1122 }
1123 
1124 // This tests that storeOp clear resets resource state to uninitialized.
1125 // Start with a sample texture that is initialized with data.
1126 // Then expect the render texture to not store the data from sample texture
1127 // because it will be lazy cleared by the EXPECT_TEXTURE_EQ call.
TEST_P(TextureZeroInitTest,RenderPassStoreOpClear)1128 TEST_P(TextureZeroInitTest, RenderPassStoreOpClear) {
1129     // Create needed resources
1130     wgpu::TextureDescriptor descriptor = CreateTextureDescriptor(
1131         1, 1, wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopyDst, kColorFormat);
1132     wgpu::Texture texture = device.CreateTexture(&descriptor);
1133 
1134     wgpu::TextureDescriptor renderTextureDescriptor = CreateTextureDescriptor(
1135         1, 1, wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment, kColorFormat);
1136     wgpu::Texture renderTexture = device.CreateTexture(&renderTextureDescriptor);
1137 
1138     // Fill the sample texture with data
1139     std::vector<uint8_t> data(kFormatBlockByteSize * kSize * kSize, 1);
1140     wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(
1141         device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
1142     wgpu::ImageCopyBuffer imageCopyBuffer =
1143         utils::CreateImageCopyBuffer(stagingBuffer, 0, kSize * kFormatBlockByteSize);
1144     wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(texture, 0, {0, 0, 0});
1145     wgpu::Extent3D copySize = {kSize, kSize, 1};
1146     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
1147     encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &copySize);
1148     wgpu::CommandBuffer commands = encoder.Finish();
1149     // Expect 0 lazy clears because the texture will be completely copied to
1150     EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
1151 
1152     // Create render pipeline
1153     utils::ComboRenderPipelineDescriptor renderPipelineDescriptor;
1154     renderPipelineDescriptor.vertex.module = CreateBasicVertexShaderForTest();
1155     renderPipelineDescriptor.cFragment.module = CreateSampledTextureFragmentShaderForTest();
1156     renderPipelineDescriptor.cTargets[0].format = kColorFormat;
1157     wgpu::RenderPipeline renderPipeline = device.CreateRenderPipeline(&renderPipelineDescriptor);
1158 
1159     // Create bindgroup
1160     wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, renderPipeline.GetBindGroupLayout(0),
1161                                                      {{0, texture.CreateView()}});
1162 
1163     // Encode pass and submit
1164     encoder = device.CreateCommandEncoder();
1165     utils::ComboRenderPassDescriptor renderPassDesc({renderTexture.CreateView()});
1166     renderPassDesc.cColorAttachments[0].clearColor = {0.0, 0.0, 0.0, 0.0};
1167     renderPassDesc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
1168     renderPassDesc.cColorAttachments[0].storeOp = wgpu::StoreOp::Discard;
1169     wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
1170     pass.SetPipeline(renderPipeline);
1171     pass.SetBindGroup(0, bindGroup);
1172     pass.Draw(6);
1173     pass.EndPass();
1174     commands = encoder.Finish();
1175     // Expect 0 lazy clears, sample texture is initialized by copyBufferToTexture and render texture
1176     // is cleared by loadop
1177     EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
1178 
1179     // Expect the rendered texture to be cleared
1180     std::vector<RGBA8> expectedWithZeros(kSize * kSize, {0, 0, 0, 0});
1181     EXPECT_LAZY_CLEAR(
1182         1u, EXPECT_TEXTURE_EQ(expectedWithZeros.data(), renderTexture, {0, 0}, {kSize, kSize}));
1183 
1184     // Expect texture subresource initialized to be true
1185     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, 1));
1186     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(renderTexture.Get(), 0, 1, 0, 1));
1187 }
1188 
1189 // This tests storeOp Clear on depth and stencil textures.
1190 // We put the depth stencil texture through 2 passes:
1191 // 1) LoadOp::Clear and StoreOp::Discard, fail the depth and stencil test set in the render
1192 //      pipeline. This means nothing is drawn and subresource is set as uninitialized.
1193 // 2) LoadOp::Load and StoreOp::Discard, pass the depth and stencil test set in the render pipeline.
1194 //      Because LoadOp is Load and the subresource is uninitialized, the texture will be cleared to
1195 //      0's This means the depth and stencil test will pass and the red square is drawn.
TEST_P(TextureZeroInitTest,RenderingLoadingDepthStencilStoreOpClear)1196 TEST_P(TextureZeroInitTest, RenderingLoadingDepthStencilStoreOpClear) {
1197     wgpu::TextureDescriptor srcDescriptor =
1198         CreateTextureDescriptor(1, 1,
1199                                 wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
1200                                     wgpu::TextureUsage::RenderAttachment,
1201                                 kColorFormat);
1202     wgpu::Texture srcTexture = device.CreateTexture(&srcDescriptor);
1203 
1204     wgpu::TextureDescriptor depthStencilDescriptor =
1205         CreateTextureDescriptor(1, 1,
1206                                 wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc |
1207                                     wgpu::TextureUsage::CopyDst,
1208                                 kDepthStencilFormat);
1209     wgpu::Texture depthStencilTexture = device.CreateTexture(&depthStencilDescriptor);
1210 
1211     // Setup the renderPass for the first pass.
1212     // We want to fail the depth and stencil test here so that nothing gets drawn and we can
1213     // see that the subresource correctly gets set as unintialized in the second pass
1214     utils::ComboRenderPassDescriptor renderPassDescriptor({srcTexture.CreateView()},
1215                                                           depthStencilTexture.CreateView());
1216     renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Clear;
1217     renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Clear;
1218     renderPassDescriptor.cDepthStencilAttachmentInfo.clearDepth = 1.0f;
1219     renderPassDescriptor.cDepthStencilAttachmentInfo.clearStencil = 1u;
1220     renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = wgpu::StoreOp::Discard;
1221     renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = wgpu::StoreOp::Discard;
1222     {
1223         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
1224         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor);
1225         pass.SetPipeline(CreatePipelineForTest());
1226         pass.Draw(6);
1227         pass.EndPass();
1228         wgpu::CommandBuffer commandBuffer = encoder.Finish();
1229         // Expect 0 lazy clears, depth stencil texture will clear using loadop
1230         EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
1231 
1232         // The depth stencil test should fail and not draw because the depth stencil texture is
1233         // cleared to 1's by using loadOp clear and set values from descriptor.
1234         std::vector<RGBA8> expectedBlack(kSize * kSize, {0, 0, 0, 0});
1235         EXPECT_TEXTURE_EQ(expectedBlack.data(), srcTexture, {0, 0}, {kSize, kSize});
1236 
1237         // Expect texture subresource initialized to be false since storeop is clear, sets
1238         // subresource as uninitialized
1239         EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0,
1240                                                                       1, 0, 1));
1241     }
1242 
1243     // Now we put the depth stencil texture back into renderpass, it should be cleared by loadop
1244     // because storeOp clear sets the subresource as uninitialized
1245     {
1246         renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
1247         renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
1248         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
1249         wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDescriptor);
1250         pass.SetPipeline(CreatePipelineForTest());
1251         pass.Draw(6);
1252         pass.EndPass();
1253         wgpu::CommandBuffer commandBuffer = encoder.Finish();
1254         // Expect 0 lazy clears, depth stencil texture will clear using loadop
1255         EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
1256 
1257         // Now the depth stencil test should pass since depth stencil texture is cleared to 0's by
1258         // loadop load and uninitialized subresource, so we should have a red square
1259         std::vector<RGBA8> expectedRed(kSize * kSize, {255, 0, 0, 255});
1260         EXPECT_TEXTURE_EQ(expectedRed.data(), srcTexture, {0, 0}, {kSize, kSize});
1261 
1262         // Expect texture subresource initialized to be false since storeop is clear, sets
1263         // subresource as uninitialized
1264         EXPECT_EQ(false, dawn_native::IsTextureSubresourceInitialized(depthStencilTexture.Get(), 0,
1265                                                                       1, 0, 1));
1266     }
1267 }
1268 
1269 // Test that if one mip of a texture is initialized and another is uninitialized, lazy clearing the
1270 // uninitialized mip does not clear the initialized mip.
TEST_P(TextureZeroInitTest,PreservesInitializedMip)1271 TEST_P(TextureZeroInitTest, PreservesInitializedMip) {
1272     wgpu::TextureDescriptor sampleTextureDescriptor =
1273         CreateTextureDescriptor(2, 1,
1274                                 wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
1275                                     wgpu::TextureUsage::TextureBinding,
1276                                 kColorFormat);
1277     wgpu::Texture sampleTexture = device.CreateTexture(&sampleTextureDescriptor);
1278 
1279     wgpu::TextureDescriptor renderTextureDescriptor = CreateTextureDescriptor(
1280         1, 1, wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment, kColorFormat);
1281     wgpu::Texture renderTexture = device.CreateTexture(&renderTextureDescriptor);
1282 
1283     // Fill the sample texture's second mip with data
1284     uint32_t mipSize = kSize >> 1;
1285     std::vector<uint8_t> data(kFormatBlockByteSize * mipSize * mipSize, 2);
1286     wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(
1287         device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
1288     wgpu::ImageCopyBuffer imageCopyBuffer =
1289         utils::CreateImageCopyBuffer(stagingBuffer, 0, mipSize * kFormatBlockByteSize);
1290     wgpu::ImageCopyTexture imageCopyTexture =
1291         utils::CreateImageCopyTexture(sampleTexture, 1, {0, 0, 0});
1292     wgpu::Extent3D copySize = {mipSize, mipSize, 1};
1293     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
1294     encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &copySize);
1295     wgpu::CommandBuffer commands = encoder.Finish();
1296     // Expect 0 lazy clears because the texture subresource will be completely copied to
1297     EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
1298 
1299     // Create render pipeline
1300     utils::ComboRenderPipelineDescriptor renderPipelineDescriptor;
1301     renderPipelineDescriptor.vertex.module = CreateBasicVertexShaderForTest();
1302     renderPipelineDescriptor.cFragment.module = CreateSampledTextureFragmentShaderForTest();
1303     renderPipelineDescriptor.cTargets[0].format = kColorFormat;
1304     wgpu::RenderPipeline renderPipeline = device.CreateRenderPipeline(&renderPipelineDescriptor);
1305 
1306     // Create bindgroup
1307     wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, renderPipeline.GetBindGroupLayout(0),
1308                                                      {{0, sampleTexture.CreateView()}});
1309 
1310     // Encode pass and submit
1311     encoder = device.CreateCommandEncoder();
1312     utils::ComboRenderPassDescriptor renderPassDesc({renderTexture.CreateView()});
1313     renderPassDesc.cColorAttachments[0].clearColor = {0.0, 0.0, 0.0, 0.0};
1314     renderPassDesc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
1315     renderPassDesc.cColorAttachments[0].storeOp = wgpu::StoreOp::Discard;
1316     wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
1317     pass.SetPipeline(renderPipeline);
1318     pass.SetBindGroup(0, bindGroup);
1319     pass.Draw(6);
1320     pass.EndPass();
1321     commands = encoder.Finish();
1322     // Expect 1 lazy clears, because not all mips of the sample texture are initialized by
1323     // copyBufferToTexture.
1324     EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
1325 
1326     // Expect the rendered texture to be cleared since we copied from the uninitialized first
1327     // mip.
1328     std::vector<RGBA8> expectedWithZeros(kSize * kSize, {0, 0, 0, 0});
1329     EXPECT_LAZY_CLEAR(
1330         1u, EXPECT_TEXTURE_EQ(expectedWithZeros.data(), renderTexture, {0, 0}, {kSize, kSize}, 0));
1331 
1332     // Expect the first mip to have been lazy cleared to 0.
1333     EXPECT_LAZY_CLEAR(
1334         0u, EXPECT_TEXTURE_EQ(expectedWithZeros.data(), sampleTexture, {0, 0}, {kSize, kSize}, 0));
1335 
1336     // Expect the second mip to still be filled with 2.
1337     std::vector<RGBA8> expectedWithTwos(mipSize * mipSize, {2, 2, 2, 2});
1338     EXPECT_LAZY_CLEAR(0u, EXPECT_TEXTURE_EQ(expectedWithTwos.data(), sampleTexture, {0, 0},
1339                                             {mipSize, mipSize}, 1));
1340 
1341     // Expect the whole texture to be initialized
1342     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(sampleTexture.Get(), 0, 2, 0, 1));
1343 }
1344 
1345 // Test that if one layer of a texture is initialized and another is uninitialized, lazy clearing
1346 // the uninitialized layer does not clear the initialized layer.
TEST_P(TextureZeroInitTest,PreservesInitializedArrayLayer)1347 TEST_P(TextureZeroInitTest, PreservesInitializedArrayLayer) {
1348     // TODO(crbug.com/dawn/593): This test uses glTextureView() which is not supported on OpenGL ES.
1349     DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
1350 
1351     wgpu::TextureDescriptor sampleTextureDescriptor =
1352         CreateTextureDescriptor(1, 2,
1353                                 wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
1354                                     wgpu::TextureUsage::TextureBinding,
1355                                 kColorFormat);
1356     wgpu::Texture sampleTexture = device.CreateTexture(&sampleTextureDescriptor);
1357 
1358     wgpu::TextureDescriptor renderTextureDescriptor = CreateTextureDescriptor(
1359         1, 1, wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment, kColorFormat);
1360     wgpu::Texture renderTexture = device.CreateTexture(&renderTextureDescriptor);
1361 
1362     // Fill the sample texture's second array layer with data
1363     std::vector<uint8_t> data(kFormatBlockByteSize * kSize * kSize, 2);
1364     wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(
1365         device, data.data(), static_cast<uint32_t>(data.size()), wgpu::BufferUsage::CopySrc);
1366     wgpu::ImageCopyBuffer imageCopyBuffer =
1367         utils::CreateImageCopyBuffer(stagingBuffer, 0, kSize * kFormatBlockByteSize);
1368     wgpu::ImageCopyTexture imageCopyTexture =
1369         utils::CreateImageCopyTexture(sampleTexture, 0, {0, 0, 1});
1370     wgpu::Extent3D copySize = {kSize, kSize, 1};
1371     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
1372     encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &copySize);
1373     wgpu::CommandBuffer commands = encoder.Finish();
1374     // Expect 0 lazy clears because the texture subresource will be completely copied to
1375     EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
1376 
1377     // Create render pipeline
1378     utils::ComboRenderPipelineDescriptor renderPipelineDescriptor;
1379     renderPipelineDescriptor.vertex.module = CreateBasicVertexShaderForTest();
1380     renderPipelineDescriptor.cFragment.module = CreateSampledTextureFragmentShaderForTest();
1381     renderPipelineDescriptor.cTargets[0].format = kColorFormat;
1382     wgpu::RenderPipeline renderPipeline = device.CreateRenderPipeline(&renderPipelineDescriptor);
1383 
1384     // Only sample from the uninitialized first layer.
1385     wgpu::TextureViewDescriptor textureViewDescriptor;
1386     textureViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
1387     textureViewDescriptor.arrayLayerCount = 1;
1388 
1389     // Create bindgroup
1390     wgpu::BindGroup bindGroup =
1391         utils::MakeBindGroup(device, renderPipeline.GetBindGroupLayout(0),
1392                              {{0, sampleTexture.CreateView(&textureViewDescriptor)}});
1393 
1394     // Encode pass and submit
1395     encoder = device.CreateCommandEncoder();
1396     utils::ComboRenderPassDescriptor renderPassDesc({renderTexture.CreateView()});
1397     renderPassDesc.cColorAttachments[0].clearColor = {0.0, 0.0, 0.0, 0.0};
1398     renderPassDesc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
1399     renderPassDesc.cColorAttachments[0].storeOp = wgpu::StoreOp::Discard;
1400     wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
1401     pass.SetPipeline(renderPipeline);
1402     pass.SetBindGroup(0, bindGroup);
1403     pass.Draw(6);
1404     pass.EndPass();
1405     commands = encoder.Finish();
1406     // Expect 1 lazy clears, because not all array layers of the sample texture are initialized by
1407     // copyBufferToTexture.
1408     EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
1409 
1410     // Expect the rendered texture to be cleared since we copied from the uninitialized first
1411     // array layer.
1412     std::vector<RGBA8> expectedWithZeros(kSize * kSize, {0, 0, 0, 0});
1413     EXPECT_LAZY_CLEAR(
1414         1u, EXPECT_TEXTURE_EQ(expectedWithZeros.data(), renderTexture, {0, 0, 0}, {kSize, kSize}));
1415 
1416     // Expect the first array layer to have been lazy cleared to 0.
1417     EXPECT_LAZY_CLEAR(
1418         0u, EXPECT_TEXTURE_EQ(expectedWithZeros.data(), sampleTexture, {0, 0, 0}, {kSize, kSize}));
1419 
1420     // Expect the second array layer to still be filled with 2.
1421     std::vector<RGBA8> expectedWithTwos(kSize * kSize, {2, 2, 2, 2});
1422     EXPECT_LAZY_CLEAR(
1423         0u, EXPECT_TEXTURE_EQ(expectedWithTwos.data(), sampleTexture, {0, 0, 1}, {kSize, kSize}));
1424 
1425     // Expect the whole texture to be initialized
1426     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(sampleTexture.Get(), 0, 1, 0, 2));
1427 }
1428 
1429 // This is a regression test for crbug.com/dawn/451 where the lazy texture
1430 // init path on D3D12 had a divide-by-zero exception in the copy split logic.
TEST_P(TextureZeroInitTest,CopyTextureToBufferNonRenderableUnaligned)1431 TEST_P(TextureZeroInitTest, CopyTextureToBufferNonRenderableUnaligned) {
1432     // TODO(crbug.com/dawn/667): Work around the fact that some platforms do not support reading
1433     // from Snorm textures.
1434     DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_snorm_read"));
1435 
1436     wgpu::TextureDescriptor descriptor;
1437     descriptor.size.width = kUnalignedSize;
1438     descriptor.size.height = kUnalignedSize;
1439     descriptor.size.depthOrArrayLayers = 1;
1440     descriptor.format = wgpu::TextureFormat::R8Snorm;
1441     descriptor.usage = wgpu::TextureUsage::CopySrc;
1442     wgpu::Texture texture = device.CreateTexture(&descriptor);
1443 
1444     {
1445         uint32_t bytesPerRow = Align(kUnalignedSize, kTextureBytesPerRowAlignment);
1446 
1447         // Create and initialize the destination buffer to ensure we only count the times of
1448         // texture lazy initialization in this test.
1449         const uint64_t bufferSize = kUnalignedSize * bytesPerRow;
1450         const std::vector<uint8_t> initialBufferData(bufferSize, 0u);
1451         wgpu::Buffer buffer = utils::CreateBufferFromData(device, initialBufferData.data(),
1452                                                           bufferSize, wgpu::BufferUsage::CopyDst);
1453 
1454         wgpu::ImageCopyTexture imageCopyTexture =
1455             utils::CreateImageCopyTexture(texture, 0, {0, 0, 0});
1456         wgpu::ImageCopyBuffer imageCopyBuffer =
1457             utils::CreateImageCopyBuffer(buffer, 0, bytesPerRow);
1458         wgpu::Extent3D copySize = {kUnalignedSize, kUnalignedSize, 1};
1459 
1460         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
1461         encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBuffer, &copySize);
1462 
1463         wgpu::CommandBuffer commands = encoder.Finish();
1464         EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
1465     }
1466 
1467     // Expect texture subresource initialized to be true
1468     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, 1));
1469 }
1470 
1471 // In this test WriteTexture fully overwrites a texture
TEST_P(TextureZeroInitTest,WriteWholeTexture)1472 TEST_P(TextureZeroInitTest, WriteWholeTexture) {
1473     wgpu::TextureDescriptor descriptor = CreateTextureDescriptor(
1474         1, 1, wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc, kColorFormat);
1475     wgpu::Texture texture = device.CreateTexture(&descriptor);
1476 
1477     wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(texture, 0, {0, 0, 0});
1478     wgpu::Extent3D copySize = {kSize, kSize, 1};
1479 
1480     wgpu::TextureDataLayout textureDataLayout;
1481     textureDataLayout.offset = 0;
1482     textureDataLayout.bytesPerRow = kSize * kFormatBlockByteSize;
1483     textureDataLayout.rowsPerImage = kSize;
1484 
1485     std::vector<RGBA8> data(
1486         utils::RequiredBytesInCopy(textureDataLayout.bytesPerRow, textureDataLayout.rowsPerImage,
1487                                    copySize, kColorFormat) /
1488             sizeof(RGBA8),
1489         {100, 100, 100, 100});
1490 
1491     // The write overwrites the whole texture so we don't need to do lazy initialization.
1492     EXPECT_LAZY_CLEAR(
1493         0u, queue.WriteTexture(&imageCopyTexture, data.data(), data.size() * sizeof(RGBA8),
1494                                &textureDataLayout, &copySize));
1495 
1496     // Expect texture initialized to be true
1497     EXPECT_TRUE(dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, 1));
1498 
1499     EXPECT_TEXTURE_EQ(data.data(), texture, {0, 0}, {kSize, kSize});
1500 }
1501 
1502 // Test WriteTexture to a subset of the texture, lazy init is necessary to clear the other
1503 // half.
TEST_P(TextureZeroInitTest,WriteTextureHalf)1504 TEST_P(TextureZeroInitTest, WriteTextureHalf) {
1505     wgpu::TextureDescriptor descriptor =
1506         CreateTextureDescriptor(4, 1,
1507                                 wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::TextureBinding |
1508                                     wgpu::TextureUsage::CopySrc,
1509                                 kColorFormat);
1510     wgpu::Texture texture = device.CreateTexture(&descriptor);
1511 
1512     wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(texture, 0, {0, 0, 0});
1513     wgpu::Extent3D copySize = {kSize / 2, kSize, 1};
1514 
1515     wgpu::TextureDataLayout textureDataLayout;
1516     textureDataLayout.offset = 0;
1517     textureDataLayout.bytesPerRow = kSize * kFormatBlockByteSize / 2;
1518     textureDataLayout.rowsPerImage = kSize;
1519 
1520     std::vector<RGBA8> data(
1521         utils::RequiredBytesInCopy(textureDataLayout.bytesPerRow, textureDataLayout.rowsPerImage,
1522                                    copySize, kColorFormat) /
1523             sizeof(RGBA8),
1524         {100, 100, 100, 100});
1525 
1526     EXPECT_LAZY_CLEAR(
1527         1u, queue.WriteTexture(&imageCopyTexture, data.data(), data.size() * sizeof(RGBA8),
1528                                &textureDataLayout, &copySize));
1529 
1530     // Expect texture initialized to be true
1531     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, 1));
1532 
1533     std::vector<RGBA8> expectedZeros((kSize / 2) * kSize, {0, 0, 0, 0});
1534     // first half filled with 100, by the data
1535     EXPECT_TEXTURE_EQ(data.data(), texture, {0, 0}, {kSize / 2, kSize});
1536     // second half should be cleared
1537     EXPECT_TEXTURE_EQ(expectedZeros.data(), texture, {kSize / 2, 0}, {kSize / 2, kSize});
1538 }
1539 
1540 // In this test WriteTexture fully overwrites a range of subresources, so lazy initialization
1541 // is needed for neither the subresources involved in the write nor the other subresources.
TEST_P(TextureZeroInitTest,WriteWholeTextureArray)1542 TEST_P(TextureZeroInitTest, WriteWholeTextureArray) {
1543     wgpu::TextureDescriptor descriptor = CreateTextureDescriptor(
1544         1, 6, wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc, kColorFormat);
1545     wgpu::Texture texture = device.CreateTexture(&descriptor);
1546 
1547     constexpr uint32_t kBaseArrayLayer = 2u;
1548     constexpr uint32_t kCopyLayerCount = 3u;
1549 
1550     wgpu::ImageCopyTexture imageCopyTexture =
1551         utils::CreateImageCopyTexture(texture, 0, {0, 0, kBaseArrayLayer});
1552     wgpu::Extent3D copySize = {kSize, kSize, kCopyLayerCount};
1553 
1554     wgpu::TextureDataLayout textureDataLayout;
1555     textureDataLayout.offset = 0;
1556     textureDataLayout.bytesPerRow = kSize * kFormatBlockByteSize;
1557     textureDataLayout.rowsPerImage = kSize;
1558 
1559     std::vector<RGBA8> data(
1560         utils::RequiredBytesInCopy(textureDataLayout.bytesPerRow, textureDataLayout.rowsPerImage,
1561                                    copySize, kColorFormat) /
1562             sizeof(RGBA8),
1563         {100, 100, 100, 100});
1564 
1565     // The write overwrites the whole subresources so we don't need to do lazy initialization on
1566     // them.
1567     EXPECT_LAZY_CLEAR(
1568         0u, queue.WriteTexture(&imageCopyTexture, data.data(), data.size() * sizeof(RGBA8),
1569                                &textureDataLayout, &copySize));
1570 
1571     // Expect texture subresource initialized to be true
1572     EXPECT_TRUE(dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, kBaseArrayLayer,
1573                                                              kCopyLayerCount));
1574 
1575     for (uint32_t layer = kBaseArrayLayer; layer < kBaseArrayLayer + kCopyLayerCount; ++layer) {
1576         EXPECT_TEXTURE_EQ(data.data(), texture, {0, 0, layer}, {kSize, kSize});
1577     }
1578 }
1579 
1580 // Test WriteTexture to a subset of the subresource, lazy init is necessary to clear the other
1581 // half.
TEST_P(TextureZeroInitTest,WriteTextureArrayHalf)1582 TEST_P(TextureZeroInitTest, WriteTextureArrayHalf) {
1583     wgpu::TextureDescriptor descriptor =
1584         CreateTextureDescriptor(4, 6,
1585                                 wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::TextureBinding |
1586                                     wgpu::TextureUsage::CopySrc,
1587                                 kColorFormat);
1588     wgpu::Texture texture = device.CreateTexture(&descriptor);
1589 
1590     constexpr uint32_t kBaseArrayLayer = 2u;
1591     constexpr uint32_t kCopyLayerCount = 3u;
1592 
1593     wgpu::ImageCopyTexture imageCopyTexture =
1594         utils::CreateImageCopyTexture(texture, 0, {0, 0, kBaseArrayLayer});
1595     wgpu::Extent3D copySize = {kSize / 2, kSize, kCopyLayerCount};
1596 
1597     wgpu::TextureDataLayout textureDataLayout;
1598     textureDataLayout.offset = 0;
1599     textureDataLayout.bytesPerRow = kSize * kFormatBlockByteSize / 2;
1600     textureDataLayout.rowsPerImage = kSize;
1601 
1602     std::vector<RGBA8> data(
1603         utils::RequiredBytesInCopy(textureDataLayout.bytesPerRow, textureDataLayout.rowsPerImage,
1604                                    copySize, kColorFormat) /
1605             sizeof(RGBA8),
1606         {100, 100, 100, 100});
1607 
1608     EXPECT_LAZY_CLEAR(
1609         1u, queue.WriteTexture(&imageCopyTexture, data.data(), data.size() * sizeof(RGBA8),
1610                                &textureDataLayout, &copySize));
1611 
1612     // Expect texture subresource initialized to be true
1613     EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1,
1614                                                                  kBaseArrayLayer, kCopyLayerCount));
1615 
1616     std::vector<RGBA8> expectedZeros((kSize / 2) * kSize, {0, 0, 0, 0});
1617     for (uint32_t layer = kBaseArrayLayer; layer < kBaseArrayLayer + kCopyLayerCount; ++layer) {
1618         // first half filled with 100, by the data
1619         EXPECT_TEXTURE_EQ(data.data(), texture, {0, 0, layer}, {kSize / 2, kSize});
1620         // second half should be cleared
1621         EXPECT_TEXTURE_EQ(expectedZeros.data(), texture, {kSize / 2, 0, layer}, {kSize / 2, kSize});
1622     }
1623 }
1624 
1625 // In this test WriteTexture fully overwrites a texture at mip level.
TEST_P(TextureZeroInitTest,WriteWholeTextureAtMipLevel)1626 TEST_P(TextureZeroInitTest, WriteWholeTextureAtMipLevel) {
1627     wgpu::TextureDescriptor descriptor = CreateTextureDescriptor(
1628         4, 1, wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc, kColorFormat);
1629     wgpu::Texture texture = device.CreateTexture(&descriptor);
1630 
1631     constexpr uint32_t kMipLevel = 2;
1632     constexpr uint32_t kMipSize = kSize >> kMipLevel;
1633 
1634     wgpu::ImageCopyTexture imageCopyTexture =
1635         utils::CreateImageCopyTexture(texture, kMipLevel, {0, 0, 0});
1636     wgpu::Extent3D copySize = {kMipSize, kMipSize, 1};
1637 
1638     wgpu::TextureDataLayout textureDataLayout;
1639     textureDataLayout.offset = 0;
1640     textureDataLayout.bytesPerRow = kMipSize * kFormatBlockByteSize;
1641     textureDataLayout.rowsPerImage = kMipSize;
1642 
1643     std::vector<RGBA8> data(
1644         utils::RequiredBytesInCopy(textureDataLayout.bytesPerRow, textureDataLayout.rowsPerImage,
1645                                    copySize, kColorFormat) /
1646             sizeof(RGBA8),
1647         {100, 100, 100, 100});
1648 
1649     // The write overwrites the whole texture so we don't need to do lazy initialization.
1650     EXPECT_LAZY_CLEAR(
1651         0u, queue.WriteTexture(&imageCopyTexture, data.data(), data.size() * sizeof(RGBA8),
1652                                &textureDataLayout, &copySize));
1653 
1654     // Expect texture initialized to be true
1655     EXPECT_TRUE(dawn_native::IsTextureSubresourceInitialized(texture.Get(), kMipLevel, 1, 0, 1));
1656 
1657     EXPECT_TEXTURE_EQ(data.data(), texture, {0, 0}, {kMipSize, kMipSize}, kMipLevel);
1658 }
1659 
1660 // Test WriteTexture to a subset of the texture at mip level, lazy init is necessary to clear the
1661 // other half.
TEST_P(TextureZeroInitTest,WriteTextureHalfAtMipLevel)1662 TEST_P(TextureZeroInitTest, WriteTextureHalfAtMipLevel) {
1663     wgpu::TextureDescriptor descriptor =
1664         CreateTextureDescriptor(4, 1,
1665                                 wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::TextureBinding |
1666                                     wgpu::TextureUsage::CopySrc,
1667                                 kColorFormat);
1668     wgpu::Texture texture = device.CreateTexture(&descriptor);
1669 
1670     constexpr uint32_t kMipLevel = 2;
1671     constexpr uint32_t kMipSize = kSize >> kMipLevel;
1672 
1673     wgpu::ImageCopyTexture imageCopyTexture =
1674         utils::CreateImageCopyTexture(texture, kMipLevel, {0, 0, 0});
1675     wgpu::Extent3D copySize = {kMipSize / 2, kMipSize, 1};
1676 
1677     wgpu::TextureDataLayout textureDataLayout;
1678     textureDataLayout.offset = 0;
1679     textureDataLayout.bytesPerRow = kMipSize * kFormatBlockByteSize / 2;
1680     textureDataLayout.rowsPerImage = kMipSize;
1681 
1682     std::vector<RGBA8> data(
1683         utils::RequiredBytesInCopy(textureDataLayout.bytesPerRow, textureDataLayout.rowsPerImage,
1684                                    copySize, kColorFormat) /
1685             sizeof(RGBA8),
1686         {100, 100, 100, 100});
1687 
1688     EXPECT_LAZY_CLEAR(
1689         1u, queue.WriteTexture(&imageCopyTexture, data.data(), data.size() * sizeof(RGBA8),
1690                                &textureDataLayout, &copySize));
1691 
1692     // Expect texture initialized to be true
1693     EXPECT_EQ(true,
1694               dawn_native::IsTextureSubresourceInitialized(texture.Get(), kMipLevel, 1, 0, 1));
1695 
1696     std::vector<RGBA8> expectedZeros((kMipSize / 2) * kMipSize, {0, 0, 0, 0});
1697     // first half filled with 100, by the data
1698     EXPECT_TEXTURE_EQ(data.data(), texture, {0, 0}, {kMipSize / 2, kMipSize}, kMipLevel);
1699     // second half should be cleared
1700     EXPECT_TEXTURE_EQ(expectedZeros.data(), texture, {kMipSize / 2, 0}, {kMipSize / 2, kMipSize},
1701                       kMipLevel);
1702 }
1703 
1704 DAWN_INSTANTIATE_TEST(TextureZeroInitTest,
1705                       D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"}),
1706                       D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"},
1707                                    {"use_d3d12_render_pass"}),
1708                       OpenGLBackend({"nonzero_clear_resources_on_creation_for_testing"}),
1709                       OpenGLESBackend({"nonzero_clear_resources_on_creation_for_testing"}),
1710                       MetalBackend({"nonzero_clear_resources_on_creation_for_testing"}),
1711                       VulkanBackend({"nonzero_clear_resources_on_creation_for_testing"}));
1712 
1713 class CompressedTextureZeroInitTest : public TextureZeroInitTest {
1714   protected:
SetUp()1715     void SetUp() override {
1716         DawnTest::SetUp();
1717 
1718         DAWN_TEST_UNSUPPORTED_IF(UsesWire());
1719         DAWN_TEST_UNSUPPORTED_IF(!IsBCFormatSupported());
1720     }
1721 
GetRequiredFeatures()1722     std::vector<const char*> GetRequiredFeatures() override {
1723         mIsBCFormatSupported = SupportsFeatures({"texture-compression-bc"});
1724         if (!mIsBCFormatSupported) {
1725             return {};
1726         }
1727 
1728         return {"texture-compression-bc"};
1729     }
1730 
IsBCFormatSupported() const1731     bool IsBCFormatSupported() const {
1732         return mIsBCFormatSupported;
1733     }
1734 
1735     // Copy the compressed texture data into the destination texture.
InitializeDataInCompressedTextureAndExpectLazyClear(wgpu::Texture bcCompressedTexture,wgpu::TextureDescriptor textureDescriptor,wgpu::Extent3D copyExtent3D,uint32_t viewMipmapLevel,uint32_t baseArrayLayer,size_t lazyClearCount)1736     void InitializeDataInCompressedTextureAndExpectLazyClear(
1737         wgpu::Texture bcCompressedTexture,
1738         wgpu::TextureDescriptor textureDescriptor,
1739         wgpu::Extent3D copyExtent3D,
1740         uint32_t viewMipmapLevel,
1741         uint32_t baseArrayLayer,
1742         size_t lazyClearCount) {
1743         uint32_t copyWidthInBlock = copyExtent3D.width / kFormatBlockByteSize;
1744         uint32_t copyHeightInBlock = copyExtent3D.height / kFormatBlockByteSize;
1745         uint32_t copyBytesPerRow =
1746             Align(copyWidthInBlock * utils::GetTexelBlockSizeInBytes(textureDescriptor.format),
1747                   kTextureBytesPerRowAlignment);
1748 
1749         std::vector<uint8_t> data(
1750             utils::RequiredBytesInCopy(copyBytesPerRow, copyHeightInBlock, copyExtent3D,
1751                                        textureDescriptor.format),
1752             1);
1753 
1754         // Copy texture data from a staging buffer to the destination texture.
1755         wgpu::Buffer stagingBuffer = utils::CreateBufferFromData(device, data.data(), data.size(),
1756                                                                  wgpu::BufferUsage::CopySrc);
1757         wgpu::ImageCopyBuffer imageCopyBuffer =
1758             utils::CreateImageCopyBuffer(stagingBuffer, 0, copyBytesPerRow, copyHeightInBlock);
1759 
1760         wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(
1761             bcCompressedTexture, viewMipmapLevel, {0, 0, baseArrayLayer});
1762 
1763         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
1764         encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &copyExtent3D);
1765         wgpu::CommandBuffer copy = encoder.Finish();
1766         EXPECT_LAZY_CLEAR(lazyClearCount, queue.Submit(1, &copy));
1767     }
1768 
1769     // Run the tests that copies pre-prepared BC format data into a BC texture and verifies if we
1770     // can render correctly with the pixel values sampled from the BC texture.
1771     // Expect that the texture subresource is initialized
TestCopyRegionIntoBCFormatTexturesAndCheckSubresourceIsInitialized(wgpu::TextureDescriptor textureDescriptor,wgpu::Extent3D copyExtent3D,wgpu::Extent3D nonPaddedCopyExtent,uint32_t viewMipmapLevel,uint32_t baseArrayLayer,size_t lazyClearCount,bool halfCopyTest=false)1772     void TestCopyRegionIntoBCFormatTexturesAndCheckSubresourceIsInitialized(
1773         wgpu::TextureDescriptor textureDescriptor,
1774         wgpu::Extent3D copyExtent3D,
1775         wgpu::Extent3D nonPaddedCopyExtent,
1776         uint32_t viewMipmapLevel,
1777         uint32_t baseArrayLayer,
1778         size_t lazyClearCount,
1779         bool halfCopyTest = false) {
1780         wgpu::Texture bcTexture = device.CreateTexture(&textureDescriptor);
1781         InitializeDataInCompressedTextureAndExpectLazyClear(bcTexture, textureDescriptor,
1782                                                             copyExtent3D, viewMipmapLevel,
1783                                                             baseArrayLayer, lazyClearCount);
1784 
1785         SampleCompressedTextureAndVerifyColor(bcTexture, textureDescriptor, copyExtent3D,
1786                                               nonPaddedCopyExtent, viewMipmapLevel, baseArrayLayer,
1787                                               halfCopyTest);
1788     }
1789 
SampleCompressedTextureAndVerifyColor(wgpu::Texture bcTexture,wgpu::TextureDescriptor textureDescriptor,wgpu::Extent3D copyExtent3D,wgpu::Extent3D nonPaddedCopyExtent,uint32_t viewMipmapLevel,uint32_t baseArrayLayer,bool halfCopyTest=false)1790     void SampleCompressedTextureAndVerifyColor(wgpu::Texture bcTexture,
1791                                                wgpu::TextureDescriptor textureDescriptor,
1792                                                wgpu::Extent3D copyExtent3D,
1793                                                wgpu::Extent3D nonPaddedCopyExtent,
1794                                                uint32_t viewMipmapLevel,
1795                                                uint32_t baseArrayLayer,
1796                                                bool halfCopyTest = false) {
1797         // Sample the compressed texture and verify the texture colors in the render target
1798         utils::BasicRenderPass renderPass =
1799             utils::CreateBasicRenderPass(device, textureDescriptor.size.width >> viewMipmapLevel,
1800                                          textureDescriptor.size.height >> viewMipmapLevel);
1801 
1802         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
1803         {
1804             wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
1805             utils::ComboRenderPipelineDescriptor renderPipelineDescriptor;
1806             renderPipelineDescriptor.cTargets[0].format = kColorFormat;
1807             renderPipelineDescriptor.vertex.module = CreateBasicVertexShaderForTest();
1808             renderPipelineDescriptor.cFragment.module = CreateSampledTextureFragmentShaderForTest();
1809             wgpu::RenderPipeline renderPipeline =
1810                 device.CreateRenderPipeline(&renderPipelineDescriptor);
1811             pass.SetPipeline(renderPipeline);
1812 
1813             wgpu::TextureViewDescriptor textureViewDescriptor = CreateTextureViewDescriptor(
1814                 viewMipmapLevel, baseArrayLayer, textureDescriptor.format);
1815             wgpu::BindGroup bindGroup =
1816                 utils::MakeBindGroup(device, renderPipeline.GetBindGroupLayout(0),
1817                                      {{0, bcTexture.CreateView(&textureViewDescriptor)}});
1818             pass.SetBindGroup(0, bindGroup);
1819             pass.Draw(6);
1820             pass.EndPass();
1821         }
1822 
1823         wgpu::CommandBuffer commands = encoder.Finish();
1824         queue.Submit(1, &commands);
1825 
1826         std::vector<RGBA8> expected(nonPaddedCopyExtent.width * nonPaddedCopyExtent.height,
1827                                     {0x00, 0x20, 0x08, 0xFF});
1828         EXPECT_TEXTURE_EQ(expected.data(), renderPass.color, {0, 0},
1829                           {nonPaddedCopyExtent.width, nonPaddedCopyExtent.height});
1830         EXPECT_TRUE(dawn_native::IsTextureSubresourceInitialized(bcTexture.Get(), viewMipmapLevel,
1831                                                                  1, baseArrayLayer, 1));
1832 
1833         // If we only copied to half the texture, check the other half is initialized to black
1834         if (halfCopyTest) {
1835             std::vector<RGBA8> expectBlack(nonPaddedCopyExtent.width * nonPaddedCopyExtent.height,
1836                                            {0x00, 0x00, 0x00, 0xFF});
1837             EXPECT_TEXTURE_EQ(expectBlack.data(), renderPass.color, {copyExtent3D.width, 0},
1838                               {nonPaddedCopyExtent.width, nonPaddedCopyExtent.height});
1839         }
1840     }
1841 
1842     bool mIsBCFormatSupported = false;
1843 };
1844 
1845 //  Test that the clearing is skipped when we use a full mip copy (with the physical size different
1846 //  than the virtual mip size)
TEST_P(CompressedTextureZeroInitTest,FullMipCopy)1847 TEST_P(CompressedTextureZeroInitTest, FullMipCopy) {
1848     wgpu::TextureDescriptor textureDescriptor;
1849     textureDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
1850                               wgpu::TextureUsage::TextureBinding;
1851     textureDescriptor.size = {60, 60, 1};
1852     textureDescriptor.mipLevelCount = 1;
1853     textureDescriptor.format = utils::kBCFormats[0];
1854 
1855     TestCopyRegionIntoBCFormatTexturesAndCheckSubresourceIsInitialized(
1856         textureDescriptor, textureDescriptor.size, textureDescriptor.size, 0, 0, 0u);
1857 }
1858 
1859 // Test that 1 lazy clear count happens when we copy to half the texture
TEST_P(CompressedTextureZeroInitTest,HalfCopyBufferToTexture)1860 TEST_P(CompressedTextureZeroInitTest, HalfCopyBufferToTexture) {
1861     // TODO(crbug.com/dawn/643): diagnose and fix this failure on OpenGL.
1862     DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
1863 
1864     wgpu::TextureDescriptor textureDescriptor;
1865     textureDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
1866                               wgpu::TextureUsage::TextureBinding;
1867     constexpr static uint32_t kSize = 16;
1868     textureDescriptor.size = {kSize, kSize, 1};
1869     textureDescriptor.mipLevelCount = 1;
1870     textureDescriptor.format = utils::kBCFormats[0];
1871 
1872     wgpu::Extent3D copyExtent3D = {kSize / 2, kSize, 1};
1873 
1874     TestCopyRegionIntoBCFormatTexturesAndCheckSubresourceIsInitialized(
1875         textureDescriptor, copyExtent3D, copyExtent3D, 0, 0, 1u, true);
1876 }
1877 
1878 // Test that 0 lazy clear count happens when we copy buffer to texture to a nonzero mip level
1879 // (with physical size different from the virtual mip size)
TEST_P(CompressedTextureZeroInitTest,FullCopyToNonZeroMipLevel)1880 TEST_P(CompressedTextureZeroInitTest, FullCopyToNonZeroMipLevel) {
1881     // TODO(crbug.com/dawn/593): This test uses glTextureView() which is not supported on OpenGL ES.
1882     DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
1883 
1884     wgpu::TextureDescriptor textureDescriptor;
1885     textureDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
1886                               wgpu::TextureUsage::TextureBinding;
1887     constexpr static uint32_t kSize = 60;
1888     textureDescriptor.size = {kSize, kSize, 1};
1889     textureDescriptor.mipLevelCount = 3;
1890     textureDescriptor.format = utils::kBCFormats[0];
1891     const uint32_t kViewMipLevel = 2;
1892     const uint32_t kActualSizeAtLevel = kSize >> kViewMipLevel;
1893 
1894     const uint32_t kCopySizeAtLevel = Align(kActualSizeAtLevel, kFormatBlockByteSize);
1895 
1896     wgpu::Extent3D copyExtent3D = {kCopySizeAtLevel, kCopySizeAtLevel, 1};
1897 
1898     TestCopyRegionIntoBCFormatTexturesAndCheckSubresourceIsInitialized(
1899         textureDescriptor, copyExtent3D, {kActualSizeAtLevel, kActualSizeAtLevel, 1}, kViewMipLevel,
1900         0, 0u);
1901 }
1902 
1903 // Test that 1 lazy clear count happens when we copy buffer to half texture to a nonzero mip level
1904 // (with physical size different from the virtual mip size)
TEST_P(CompressedTextureZeroInitTest,HalfCopyToNonZeroMipLevel)1905 TEST_P(CompressedTextureZeroInitTest, HalfCopyToNonZeroMipLevel) {
1906     // TODO(crbug.com/dawn/643): diagnose and fix this failure on OpenGL.
1907     DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
1908 
1909     wgpu::TextureDescriptor textureDescriptor;
1910     textureDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
1911                               wgpu::TextureUsage::TextureBinding;
1912     constexpr static uint32_t kSize = 60;
1913     textureDescriptor.size = {kSize, kSize, 1};
1914     textureDescriptor.mipLevelCount = 3;
1915     textureDescriptor.format = utils::kBCFormats[0];
1916     const uint32_t kViewMipLevel = 2;
1917     const uint32_t kActualSizeAtLevel = kSize >> kViewMipLevel;
1918 
1919     const uint32_t kCopySizeAtLevel = Align(kActualSizeAtLevel, kFormatBlockByteSize);
1920 
1921     wgpu::Extent3D copyExtent3D = {kCopySizeAtLevel / 2, kCopySizeAtLevel, 1};
1922 
1923     TestCopyRegionIntoBCFormatTexturesAndCheckSubresourceIsInitialized(
1924         textureDescriptor, copyExtent3D, {kActualSizeAtLevel / 2, kActualSizeAtLevel, 1},
1925         kViewMipLevel, 0, 1u, true);
1926 }
1927 
1928 // Test that 0 lazy clear count happens when we copy buffer to nonzero array layer
TEST_P(CompressedTextureZeroInitTest,FullCopyToNonZeroArrayLayer)1929 TEST_P(CompressedTextureZeroInitTest, FullCopyToNonZeroArrayLayer) {
1930     // TODO(crbug.com/dawn/593): This test uses glTextureView() which is not supported on OpenGL ES.
1931     DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
1932 
1933     wgpu::TextureDescriptor textureDescriptor;
1934     textureDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
1935                               wgpu::TextureUsage::TextureBinding;
1936     constexpr static uint32_t kSize = 16;
1937     constexpr static uint32_t kArrayLayers = 4;
1938     textureDescriptor.size = {kSize, kSize, kArrayLayers};
1939     textureDescriptor.mipLevelCount = 1;
1940     textureDescriptor.format = utils::kBCFormats[0];
1941 
1942     wgpu::Extent3D copyExtent3D = {kSize, kSize, 1};
1943 
1944     TestCopyRegionIntoBCFormatTexturesAndCheckSubresourceIsInitialized(
1945         textureDescriptor, copyExtent3D, copyExtent3D, 0, kArrayLayers - 2, 0u);
1946 }
1947 
1948 // Test that 1 lazy clear count happens when we copy buffer to half texture to a nonzero array layer
TEST_P(CompressedTextureZeroInitTest,HalfCopyToNonZeroArrayLayer)1949 TEST_P(CompressedTextureZeroInitTest, HalfCopyToNonZeroArrayLayer) {
1950     // TODO(crbug.com/dawn/643): diagnose and fix this failure on OpenGL.
1951     DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
1952 
1953     wgpu::TextureDescriptor textureDescriptor;
1954     textureDescriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
1955                               wgpu::TextureUsage::TextureBinding;
1956     constexpr static uint32_t kSize = 16;
1957     constexpr static uint32_t kArrayLayers = 4;
1958     textureDescriptor.size = {kSize, kSize, kArrayLayers};
1959     textureDescriptor.mipLevelCount = 3;
1960     textureDescriptor.format = utils::kBCFormats[0];
1961 
1962     wgpu::Extent3D copyExtent3D = {kSize / 2, kSize, 1};
1963 
1964     TestCopyRegionIntoBCFormatTexturesAndCheckSubresourceIsInitialized(
1965         textureDescriptor, copyExtent3D, copyExtent3D, 0, kArrayLayers - 2, 1u, true);
1966 }
1967 
1968 // full copy texture to texture, 0 lazy clears are needed
TEST_P(CompressedTextureZeroInitTest,FullCopyTextureToTextureMipLevel)1969 TEST_P(CompressedTextureZeroInitTest, FullCopyTextureToTextureMipLevel) {
1970     // TODO(crbug.com/dawn/593): This test uses glTextureView() which is not supported on OpenGL ES.
1971     DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
1972 
1973     // create srcTexture and fill it with data
1974     wgpu::TextureDescriptor srcDescriptor =
1975         CreateTextureDescriptor(3, 1,
1976                                 wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc |
1977                                     wgpu::TextureUsage::CopyDst,
1978                                 utils::kBCFormats[0]);
1979     wgpu::Texture srcTexture = device.CreateTexture(&srcDescriptor);
1980 
1981     const uint32_t kViewMipLevel = 2;
1982     const uint32_t kActualSizeAtLevel = kSize >> kViewMipLevel;
1983 
1984     const uint32_t kCopySizeAtLevel = Align(kActualSizeAtLevel, kFormatBlockByteSize);
1985 
1986     wgpu::Extent3D copyExtent3D = {kCopySizeAtLevel, kCopySizeAtLevel, 1};
1987 
1988     // fill srcTexture with data
1989     InitializeDataInCompressedTextureAndExpectLazyClear(srcTexture, srcDescriptor, copyExtent3D,
1990                                                         kViewMipLevel, 0, 0u);
1991 
1992     wgpu::ImageCopyTexture srcImageCopyTexture =
1993         utils::CreateImageCopyTexture(srcTexture, kViewMipLevel, {0, 0, 0});
1994 
1995     // create dstTexture that we will copy to
1996     wgpu::TextureDescriptor dstDescriptor =
1997         CreateTextureDescriptor(3, 1,
1998                                 wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc |
1999                                     wgpu::TextureUsage::TextureBinding,
2000                                 utils::kBCFormats[0]);
2001     wgpu::Texture dstTexture = device.CreateTexture(&dstDescriptor);
2002 
2003     wgpu::ImageCopyTexture dstImageCopyTexture =
2004         utils::CreateImageCopyTexture(dstTexture, kViewMipLevel, {0, 0, 0});
2005 
2006     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
2007     encoder.CopyTextureToTexture(&srcImageCopyTexture, &dstImageCopyTexture, &copyExtent3D);
2008     wgpu::CommandBuffer commands = encoder.Finish();
2009     // the dstTexture does not need to be lazy cleared since it's fully copied to
2010     EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
2011 
2012     SampleCompressedTextureAndVerifyColor(dstTexture, dstDescriptor, copyExtent3D,
2013                                           {kActualSizeAtLevel, kActualSizeAtLevel, 1},
2014                                           kViewMipLevel, 0);
2015 }
2016 
2017 // half copy texture to texture, lazy clears are needed for noncopied half
TEST_P(CompressedTextureZeroInitTest,HalfCopyTextureToTextureMipLevel)2018 TEST_P(CompressedTextureZeroInitTest, HalfCopyTextureToTextureMipLevel) {
2019     // TODO(crbug.com/dawn/643): diagnose and fix this failure on OpenGL.
2020     DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
2021 
2022     // create srcTexture with data
2023     wgpu::TextureDescriptor srcDescriptor =
2024         CreateTextureDescriptor(3, 1,
2025                                 wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::CopySrc |
2026                                     wgpu::TextureUsage::CopyDst,
2027                                 utils::kBCFormats[0]);
2028     wgpu::Texture srcTexture = device.CreateTexture(&srcDescriptor);
2029 
2030     const uint32_t kViewMipLevel = 2;
2031     const uint32_t kActualSizeAtLevel = kSize >> kViewMipLevel;
2032 
2033     const uint32_t kCopySizeAtLevel = Align(kActualSizeAtLevel, kFormatBlockByteSize);
2034 
2035     wgpu::Extent3D copyExtent3D = {kCopySizeAtLevel / 2, kCopySizeAtLevel, 1};
2036 
2037     // fill srcTexture with data
2038     InitializeDataInCompressedTextureAndExpectLazyClear(srcTexture, srcDescriptor, copyExtent3D,
2039                                                         kViewMipLevel, 0, 1u);
2040 
2041     wgpu::ImageCopyTexture srcImageCopyTexture =
2042         utils::CreateImageCopyTexture(srcTexture, kViewMipLevel, {0, 0, 0});
2043 
2044     // create dstTexture that we will copy to
2045     wgpu::TextureDescriptor dstDescriptor =
2046         CreateTextureDescriptor(3, 1,
2047                                 wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc |
2048                                     wgpu::TextureUsage::TextureBinding,
2049                                 utils::kBCFormats[0]);
2050     wgpu::Texture dstTexture = device.CreateTexture(&dstDescriptor);
2051 
2052     wgpu::ImageCopyTexture dstImageCopyTexture =
2053         utils::CreateImageCopyTexture(dstTexture, kViewMipLevel, {0, 0, 0});
2054 
2055     wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
2056     encoder.CopyTextureToTexture(&srcImageCopyTexture, &dstImageCopyTexture, &copyExtent3D);
2057     wgpu::CommandBuffer commands = encoder.Finish();
2058     // expect 1 lazy clear count since the dstTexture needs to be lazy cleared when we only copy to
2059     // half texture
2060     EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
2061 
2062     SampleCompressedTextureAndVerifyColor(dstTexture, dstDescriptor, copyExtent3D,
2063                                           {kActualSizeAtLevel / 2, kActualSizeAtLevel, 1},
2064                                           kViewMipLevel, 0, true);
2065 }
2066 
2067 // Test uploading then reading back from a 2D array compressed texture.
2068 // This is a regression test for a bug where the final destination buffer
2069 // was considered fully initialized even though there was a 256-byte
2070 // stride between images.
TEST_P(CompressedTextureZeroInitTest,Copy2DArrayCompressedB2T2B)2071 TEST_P(CompressedTextureZeroInitTest, Copy2DArrayCompressedB2T2B) {
2072     // TODO(crbug.com/dawn/643): diagnose and fix this failure on OpenGL.
2073     DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
2074 
2075     // create srcTexture with data
2076     wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(
2077         4, 5, wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst, utils::kBCFormats[0]);
2078     textureDescriptor.size = {8, 8, 5};
2079     wgpu::Texture srcTexture = device.CreateTexture(&textureDescriptor);
2080 
2081     uint32_t mipLevel = 2;
2082     wgpu::Extent3D copyExtent3D = {4, 4, 5};
2083 
2084     uint32_t copyWidthInBlock = copyExtent3D.width / kFormatBlockByteSize;
2085     uint32_t copyHeightInBlock = copyExtent3D.height / kFormatBlockByteSize;
2086     uint32_t copyRowsPerImage = copyHeightInBlock;
2087     uint32_t copyBytesPerRow =
2088         Align(copyWidthInBlock * utils::GetTexelBlockSizeInBytes(textureDescriptor.format),
2089               kTextureBytesPerRowAlignment);
2090 
2091     // Generate data to upload
2092     std::vector<uint8_t> data(utils::RequiredBytesInCopy(copyBytesPerRow, copyRowsPerImage,
2093                                                          copyExtent3D, textureDescriptor.format));
2094     for (size_t i = 0; i < data.size(); ++i) {
2095         data[i] = i % 255;
2096     }
2097 
2098     // Copy texture data from a staging buffer to the destination texture.
2099     wgpu::Buffer stagingBuffer =
2100         utils::CreateBufferFromData(device, data.data(), data.size(), wgpu::BufferUsage::CopySrc);
2101     wgpu::ImageCopyBuffer imageCopyBufferSrc =
2102         utils::CreateImageCopyBuffer(stagingBuffer, 0, copyBytesPerRow, copyRowsPerImage);
2103 
2104     wgpu::ImageCopyTexture imageCopyTexture =
2105         utils::CreateImageCopyTexture(srcTexture, mipLevel, {0, 0, 0});
2106 
2107     {
2108         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
2109         encoder.CopyBufferToTexture(&imageCopyBufferSrc, &imageCopyTexture, &copyExtent3D);
2110         wgpu::CommandBuffer copy = encoder.Finish();
2111         EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &copy));
2112     }
2113 
2114     // Create a buffer to read back the data. It is the same size as the upload buffer.
2115     wgpu::BufferDescriptor readbackDesc = {};
2116     readbackDesc.size = data.size();
2117     readbackDesc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
2118     wgpu::Buffer readbackBuffer = device.CreateBuffer(&readbackDesc);
2119 
2120     // Copy the texture to the readback buffer.
2121     wgpu::ImageCopyBuffer imageCopyBufferDst =
2122         utils::CreateImageCopyBuffer(readbackBuffer, 0, copyBytesPerRow, copyRowsPerImage);
2123     {
2124         wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
2125         encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBufferDst, &copyExtent3D);
2126         wgpu::CommandBuffer copy = encoder.Finish();
2127 
2128         // Expect a lazy clear because the padding in the copy is not touched.
2129         EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &copy));
2130     }
2131 
2132     // Generate expected data. It is the same as the upload data, but padding is zero.
2133     std::vector<uint8_t> expected(data.size(), 0);
2134     for (uint32_t z = 0; z < copyExtent3D.depthOrArrayLayers; ++z) {
2135         for (uint32_t y = 0; y < copyHeightInBlock; ++y) {
2136             memcpy(&expected[copyBytesPerRow * y + copyBytesPerRow * copyRowsPerImage * z],
2137                    &data[copyBytesPerRow * y + copyBytesPerRow * copyRowsPerImage * z],
2138                    copyWidthInBlock * utils::GetTexelBlockSizeInBytes(textureDescriptor.format));
2139         }
2140     }
2141     // Check final contents
2142     EXPECT_BUFFER_U8_RANGE_EQ(expected.data(), readbackBuffer, 0, expected.size());
2143 }
2144 
2145 DAWN_INSTANTIATE_TEST(CompressedTextureZeroInitTest,
2146                       D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"}),
2147                       MetalBackend({"nonzero_clear_resources_on_creation_for_testing"}),
2148                       OpenGLBackend({"nonzero_clear_resources_on_creation_for_testing"}),
2149                       OpenGLESBackend({"nonzero_clear_resources_on_creation_for_testing"}),
2150                       VulkanBackend({"nonzero_clear_resources_on_creation_for_testing"}));
2151