• 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 "utils/ComboRenderPipelineDescriptor.h"
18 #include "utils/DawnHelpers.h"
19 
20 class TextureZeroInitTest : public DawnTest {
21   protected:
SetUp()22     void SetUp() override {
23         DawnTest::SetUp();
24     }
CreateTextureDescriptor(uint32_t mipLevelCount,uint32_t arrayLayerCount,dawn::TextureUsageBit usage,dawn::TextureFormat format)25     dawn::TextureDescriptor CreateTextureDescriptor(uint32_t mipLevelCount,
26                                                     uint32_t arrayLayerCount,
27                                                     dawn::TextureUsageBit usage,
28                                                     dawn::TextureFormat format) {
29         dawn::TextureDescriptor descriptor;
30         descriptor.dimension = dawn::TextureDimension::e2D;
31         descriptor.size.width = kSize;
32         descriptor.size.height = kSize;
33         descriptor.size.depth = 1;
34         descriptor.arrayLayerCount = arrayLayerCount;
35         descriptor.sampleCount = 1;
36         descriptor.format = format;
37         descriptor.mipLevelCount = mipLevelCount;
38         descriptor.usage = usage;
39         return descriptor;
40     }
CreateTextureViewDescriptor(uint32_t baseMipLevel,uint32_t baseArrayLayer)41     dawn::TextureViewDescriptor CreateTextureViewDescriptor(uint32_t baseMipLevel,
42                                                             uint32_t baseArrayLayer) {
43         dawn::TextureViewDescriptor descriptor;
44         descriptor.format = kColorFormat;
45         descriptor.baseArrayLayer = baseArrayLayer;
46         descriptor.arrayLayerCount = 1;
47         descriptor.baseMipLevel = baseMipLevel;
48         descriptor.mipLevelCount = 1;
49         descriptor.dimension = dawn::TextureViewDimension::e2D;
50         return descriptor;
51     }
CreatePipelineForTest()52     dawn::RenderPipeline CreatePipelineForTest() {
53         utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
54         const char* vs =
55             R"(#version 450
56             const vec2 pos[6] = vec2[6](vec2(-1.0f, -1.0f),
57                                     vec2(-1.0f,  1.0f),
58                                     vec2( 1.0f, -1.0f),
59                                     vec2( 1.0f,  1.0f),
60                                     vec2(-1.0f,  1.0f),
61                                     vec2( 1.0f, -1.0f)
62                                     );
63 
64             void main() {
65                 gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);
66             })";
67         pipelineDescriptor.cVertexStage.module =
68             utils::CreateShaderModule(device, utils::ShaderStage::Vertex, vs);
69 
70         const char* fs =
71             R"(#version 450
72             layout(location = 0) out vec4 fragColor;
73             void main() {
74                fragColor = vec4(1.0, 0.0, 0.0, 1.0);
75             })";
76         pipelineDescriptor.cFragmentStage.module =
77             utils::CreateShaderModule(device, utils::ShaderStage::Fragment, fs);
78 
79         pipelineDescriptor.cDepthStencilState.depthCompare = dawn::CompareFunction::Equal;
80         pipelineDescriptor.cDepthStencilState.stencilFront.compare = dawn::CompareFunction::Equal;
81         pipelineDescriptor.depthStencilState = &pipelineDescriptor.cDepthStencilState;
82 
83         return device.CreateRenderPipeline(&pipelineDescriptor);
84     }
85     constexpr static uint32_t kSize = 128;
86     constexpr static dawn::TextureFormat kColorFormat = dawn::TextureFormat::RGBA8Unorm;
87     constexpr static dawn::TextureFormat kDepthStencilFormat =
88         dawn::TextureFormat::Depth24PlusStencil8;
89 };
90 
91 // This tests that the code path of CopyTextureToBuffer clears correctly to Zero after first usage
TEST_P(TextureZeroInitTest,CopyTextureToBufferSource)92 TEST_P(TextureZeroInitTest, CopyTextureToBufferSource) {
93     dawn::TextureDescriptor descriptor = CreateTextureDescriptor(
94         1, 1, dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::CopySrc,
95         kColorFormat);
96     dawn::Texture texture = device.CreateTexture(&descriptor);
97 
98     // Texture's first usage is in EXPECT_PIXEL_RGBA8_EQ's call to CopyTextureToBuffer
99     RGBA8 filledWithZeros(0, 0, 0, 0);
100     EXPECT_PIXEL_RGBA8_EQ(filledWithZeros, texture, 0, 0);
101 }
102 
103 // Test that non-zero mip level clears subresource to Zero after first use
104 // This goes through the BeginRenderPass's code path
TEST_P(TextureZeroInitTest,RenderingMipMapClearsToZero)105 TEST_P(TextureZeroInitTest, RenderingMipMapClearsToZero) {
106     dawn::TextureDescriptor descriptor = CreateTextureDescriptor(
107         4, 1, dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::CopySrc,
108         kColorFormat);
109     dawn::Texture texture = device.CreateTexture(&descriptor);
110 
111     dawn::TextureViewDescriptor viewDescriptor = CreateTextureViewDescriptor(2, 0);
112     dawn::TextureView view = texture.CreateView(&viewDescriptor);
113 
114     utils::BasicRenderPass renderPass = utils::BasicRenderPass(kSize, kSize, texture, kColorFormat);
115 
116     renderPass.renderPassInfo.cColorAttachmentsInfoPtr[0]->attachment = view;
117     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
118     {
119         // Texture's first usage is in BeginRenderPass's call to RecordRenderPass
120         dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
121         pass.EndPass();
122     }
123     dawn::CommandBuffer commands = encoder.Finish();
124     queue.Submit(1, &commands);
125 
126     uint32_t mipSize = kSize >> 2;
127     std::vector<RGBA8> expected(mipSize * mipSize, {0, 0, 0, 0});
128 
129     EXPECT_TEXTURE_RGBA8_EQ(expected.data(), renderPass.color, 0, 0, mipSize, mipSize, 2, 0);
130 }
131 
132 // Test that non-zero array layers clears subresource to Zero after first use.
133 // This goes through the BeginRenderPass's code path
TEST_P(TextureZeroInitTest,RenderingArrayLayerClearsToZero)134 TEST_P(TextureZeroInitTest, RenderingArrayLayerClearsToZero) {
135     dawn::TextureDescriptor descriptor = CreateTextureDescriptor(
136         1, 4, dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::CopySrc,
137         kColorFormat);
138     dawn::Texture texture = device.CreateTexture(&descriptor);
139 
140     dawn::TextureViewDescriptor viewDescriptor = CreateTextureViewDescriptor(0, 2);
141     dawn::TextureView view = texture.CreateView(&viewDescriptor);
142 
143     utils::BasicRenderPass renderPass = utils::BasicRenderPass(kSize, kSize, texture, kColorFormat);
144 
145     renderPass.renderPassInfo.cColorAttachmentsInfoPtr[0]->attachment = view;
146     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
147     {
148         dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
149         pass.EndPass();
150     }
151     dawn::CommandBuffer commands = encoder.Finish();
152     queue.Submit(1, &commands);
153 
154     std::vector<RGBA8> expected(kSize * kSize, {0, 0, 0, 0});
155 
156     EXPECT_TEXTURE_RGBA8_EQ(expected.data(), renderPass.color, 0, 0, kSize, kSize, 0, 2);
157 }
158 
159 // This tests CopyBufferToTexture fully overwrites copy so lazy init is not needed.
160 // TODO(natlee@microsoft.com): Add backdoor to dawn native to query the number of zero-inited
161 // subresources
TEST_P(TextureZeroInitTest,CopyBufferToTexture)162 TEST_P(TextureZeroInitTest, CopyBufferToTexture) {
163     dawn::TextureDescriptor descriptor =
164         CreateTextureDescriptor(4, 1,
165                                 dawn::TextureUsageBit::CopyDst | dawn::TextureUsageBit::Sampled |
166                                     dawn::TextureUsageBit::CopySrc,
167                                 kColorFormat);
168     dawn::Texture texture = device.CreateTexture(&descriptor);
169 
170     std::vector<uint8_t> data(4 * kSize * kSize, 100);
171     dawn::Buffer stagingBuffer = utils::CreateBufferFromData(
172         device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsageBit::CopySrc);
173 
174     dawn::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(stagingBuffer, 0, 0, 0);
175     dawn::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, 0, {0, 0, 0});
176     dawn::Extent3D copySize = {kSize, kSize, 1};
177 
178     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
179     encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copySize);
180     dawn::CommandBuffer commands = encoder.Finish();
181     queue.Submit(1, &commands);
182 
183     std::vector<RGBA8> expected(kSize * kSize, {100, 100, 100, 100});
184 
185     EXPECT_TEXTURE_RGBA8_EQ(expected.data(), texture, 0, 0, kSize, kSize, 0, 0);
186 }
187 
188 // Test for a copy only to a subset of the subresource, lazy init is necessary to clear the other
189 // half.
TEST_P(TextureZeroInitTest,CopyBufferToTextureHalf)190 TEST_P(TextureZeroInitTest, CopyBufferToTextureHalf) {
191     dawn::TextureDescriptor descriptor =
192         CreateTextureDescriptor(4, 1,
193                                 dawn::TextureUsageBit::CopyDst | dawn::TextureUsageBit::Sampled |
194                                     dawn::TextureUsageBit::CopySrc,
195                                 kColorFormat);
196     dawn::Texture texture = device.CreateTexture(&descriptor);
197 
198     std::vector<uint8_t> data(4 * kSize * kSize, 100);
199     dawn::Buffer stagingBuffer = utils::CreateBufferFromData(
200         device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsageBit::CopySrc);
201 
202     dawn::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(stagingBuffer, 0, 0, 0);
203     dawn::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, 0, 0, {0, 0, 0});
204     dawn::Extent3D copySize = {kSize / 2, kSize, 1};
205 
206     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
207     encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copySize);
208     dawn::CommandBuffer commands = encoder.Finish();
209     queue.Submit(1, &commands);
210 
211     std::vector<RGBA8> expected100((kSize / 2) * kSize, {100, 100, 100, 100});
212     std::vector<RGBA8> expectedZeros((kSize / 2) * kSize, {0, 0, 0, 0});
213     // first half filled with 100, by the buffer data
214     EXPECT_TEXTURE_RGBA8_EQ(expected100.data(), texture, 0, 0, kSize / 2, kSize, 0, 0);
215     // second half should be cleared
216     EXPECT_TEXTURE_RGBA8_EQ(expectedZeros.data(), texture, kSize / 2, 0, kSize / 2, kSize, 0, 0);
217 }
218 
219 // This tests CopyTextureToTexture fully overwrites copy so lazy init is not needed.
TEST_P(TextureZeroInitTest,CopyTextureToTexture)220 TEST_P(TextureZeroInitTest, CopyTextureToTexture) {
221     dawn::TextureDescriptor srcDescriptor = CreateTextureDescriptor(
222         1, 1, dawn::TextureUsageBit::Sampled | dawn::TextureUsageBit::CopySrc, kColorFormat);
223     dawn::Texture srcTexture = device.CreateTexture(&srcDescriptor);
224 
225     dawn::TextureCopyView srcTextureCopyView =
226         utils::CreateTextureCopyView(srcTexture, 0, 0, {0, 0, 0});
227 
228     dawn::TextureDescriptor dstDescriptor =
229         CreateTextureDescriptor(1, 1,
230                                 dawn::TextureUsageBit::OutputAttachment |
231                                     dawn::TextureUsageBit::CopyDst | dawn::TextureUsageBit::CopySrc,
232                                 kColorFormat);
233     dawn::Texture dstTexture = device.CreateTexture(&dstDescriptor);
234 
235     dawn::TextureCopyView dstTextureCopyView =
236         utils::CreateTextureCopyView(dstTexture, 0, 0, {0, 0, 0});
237 
238     dawn::Extent3D copySize = {kSize, kSize, 1};
239 
240     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
241     encoder.CopyTextureToTexture(&srcTextureCopyView, &dstTextureCopyView, &copySize);
242     dawn::CommandBuffer commands = encoder.Finish();
243     queue.Submit(1, &commands);
244 
245     std::vector<RGBA8> expected(kSize * kSize, {0, 0, 0, 0});
246 
247     EXPECT_TEXTURE_RGBA8_EQ(expected.data(), srcTexture, 0, 0, kSize, kSize, 0, 0);
248     EXPECT_TEXTURE_RGBA8_EQ(expected.data(), dstTexture, 0, 0, kSize, kSize, 0, 0);
249 }
250 
251 // This Tests the CopyTextureToTexture's copy only to a subset of the subresource, lazy init is
252 // necessary to clear the other half.
TEST_P(TextureZeroInitTest,CopyTextureToTextureHalf)253 TEST_P(TextureZeroInitTest, CopyTextureToTextureHalf) {
254     dawn::TextureDescriptor srcDescriptor =
255         CreateTextureDescriptor(1, 1,
256                                 dawn::TextureUsageBit::Sampled | dawn::TextureUsageBit::CopySrc |
257                                     dawn::TextureUsageBit::CopyDst,
258                                 kColorFormat);
259     dawn::Texture srcTexture = device.CreateTexture(&srcDescriptor);
260 
261     // fill srcTexture with 100
262     {
263         std::vector<uint8_t> data(4 * kSize * kSize, 100);
264         dawn::Buffer stagingBuffer = utils::CreateBufferFromData(
265             device, data.data(), static_cast<uint32_t>(data.size()), dawn::BufferUsageBit::CopySrc);
266         dawn::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(stagingBuffer, 0, 0, 0);
267         dawn::TextureCopyView textureCopyView =
268             utils::CreateTextureCopyView(srcTexture, 0, 0, {0, 0, 0});
269         dawn::Extent3D copySize = {kSize, kSize, 1};
270         dawn::CommandEncoder encoder = device.CreateCommandEncoder();
271         encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copySize);
272         dawn::CommandBuffer commands = encoder.Finish();
273         queue.Submit(1, &commands);
274     }
275 
276     dawn::TextureCopyView srcTextureCopyView =
277         utils::CreateTextureCopyView(srcTexture, 0, 0, {0, 0, 0});
278 
279     dawn::TextureDescriptor dstDescriptor =
280         CreateTextureDescriptor(1, 1,
281                                 dawn::TextureUsageBit::OutputAttachment |
282                                     dawn::TextureUsageBit::CopyDst | dawn::TextureUsageBit::CopySrc,
283                                 kColorFormat);
284     dawn::Texture dstTexture = device.CreateTexture(&dstDescriptor);
285 
286     dawn::TextureCopyView dstTextureCopyView =
287         utils::CreateTextureCopyView(dstTexture, 0, 0, {0, 0, 0});
288     dawn::Extent3D copySize = {kSize / 2, kSize, 1};
289 
290     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
291     encoder.CopyTextureToTexture(&srcTextureCopyView, &dstTextureCopyView, &copySize);
292     dawn::CommandBuffer commands = encoder.Finish();
293     queue.Submit(1, &commands);
294 
295     std::vector<RGBA8> expectedWithZeros((kSize / 2) * kSize, {0, 0, 0, 0});
296     std::vector<RGBA8> expectedWith100(kSize * kSize, {100, 100, 100, 100});
297 
298     EXPECT_TEXTURE_RGBA8_EQ(expectedWith100.data(), srcTexture, 0, 0, kSize, kSize, 0, 0);
299     EXPECT_TEXTURE_RGBA8_EQ(expectedWith100.data(), dstTexture, 0, 0, kSize / 2, kSize, 0, 0);
300     EXPECT_TEXTURE_RGBA8_EQ(expectedWithZeros.data(), dstTexture, kSize / 2, 0, kSize / 2, kSize, 0,
301                             0);
302 }
303 
304 // This tests the texture with depth attachment and load op load will init depth stencil texture to
305 // 0s.
TEST_P(TextureZeroInitTest,RenderingLoadingDepth)306 TEST_P(TextureZeroInitTest, RenderingLoadingDepth) {
307     dawn::TextureDescriptor srcDescriptor =
308         CreateTextureDescriptor(1, 1,
309                                 dawn::TextureUsageBit::CopySrc | dawn::TextureUsageBit::CopyDst |
310                                     dawn::TextureUsageBit::OutputAttachment,
311                                 kColorFormat);
312     dawn::Texture srcTexture = device.CreateTexture(&srcDescriptor);
313 
314     dawn::TextureDescriptor depthStencilDescriptor = CreateTextureDescriptor(
315         1, 1, dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::CopySrc,
316         kDepthStencilFormat);
317     dawn::Texture depthStencilTexture = device.CreateTexture(&depthStencilDescriptor);
318 
319     utils::ComboRenderPassDescriptor renderPassDescriptor({srcTexture.CreateDefaultView()},
320                                                           depthStencilTexture.CreateDefaultView());
321     renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = dawn::LoadOp::Load;
322     renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = dawn::LoadOp::Clear;
323     renderPassDescriptor.cDepthStencilAttachmentInfo.clearStencil = 0;
324 
325     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
326     auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
327     pass.SetPipeline(CreatePipelineForTest());
328     pass.Draw(6, 1, 0, 0);
329     pass.EndPass();
330     dawn::CommandBuffer commandBuffer = encoder.Finish();
331     queue.Submit(1, &commandBuffer);
332 
333     // Expect the texture to be red because depth test passed.
334     std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
335     EXPECT_TEXTURE_RGBA8_EQ(expected.data(), srcTexture, 0, 0, kSize, kSize, 0, 0);
336 }
337 
338 // This tests the texture with stencil attachment and load op load will init depth stencil texture
339 // to 0s.
TEST_P(TextureZeroInitTest,RenderingLoadingStencil)340 TEST_P(TextureZeroInitTest, RenderingLoadingStencil) {
341     dawn::TextureDescriptor srcDescriptor =
342         CreateTextureDescriptor(1, 1,
343                                 dawn::TextureUsageBit::CopySrc | dawn::TextureUsageBit::CopyDst |
344                                     dawn::TextureUsageBit::OutputAttachment,
345                                 kColorFormat);
346     dawn::Texture srcTexture = device.CreateTexture(&srcDescriptor);
347 
348     dawn::TextureDescriptor depthStencilDescriptor = CreateTextureDescriptor(
349         1, 1, dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::CopySrc,
350         kDepthStencilFormat);
351     dawn::Texture depthStencilTexture = device.CreateTexture(&depthStencilDescriptor);
352 
353     utils::ComboRenderPassDescriptor renderPassDescriptor({srcTexture.CreateDefaultView()},
354                                                           depthStencilTexture.CreateDefaultView());
355     renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = dawn::LoadOp::Clear;
356     renderPassDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.0f;
357     renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = dawn::LoadOp::Load;
358 
359     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
360     auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
361     pass.SetPipeline(CreatePipelineForTest());
362     pass.Draw(6, 1, 0, 0);
363     pass.EndPass();
364     dawn::CommandBuffer commandBuffer = encoder.Finish();
365     queue.Submit(1, &commandBuffer);
366 
367     // Expect the texture to be red because stencil test passed.
368     std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
369     EXPECT_TEXTURE_RGBA8_EQ(expected.data(), srcTexture, 0, 0, kSize, kSize, 0, 0);
370 }
371 
372 // This tests the texture with depth stencil attachment and load op load will init depth stencil
373 // texture to 0s.
TEST_P(TextureZeroInitTest,RenderingLoadingDepthStencil)374 TEST_P(TextureZeroInitTest, RenderingLoadingDepthStencil) {
375     dawn::TextureDescriptor srcDescriptor =
376         CreateTextureDescriptor(1, 1,
377                                 dawn::TextureUsageBit::CopySrc | dawn::TextureUsageBit::CopyDst |
378                                     dawn::TextureUsageBit::OutputAttachment,
379                                 kColorFormat);
380     dawn::Texture srcTexture = device.CreateTexture(&srcDescriptor);
381 
382     dawn::TextureDescriptor depthStencilDescriptor = CreateTextureDescriptor(
383         1, 1, dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::CopySrc,
384         kDepthStencilFormat);
385     dawn::Texture depthStencilTexture = device.CreateTexture(&depthStencilDescriptor);
386 
387     utils::ComboRenderPassDescriptor renderPassDescriptor({srcTexture.CreateDefaultView()},
388                                                           depthStencilTexture.CreateDefaultView());
389     renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = dawn::LoadOp::Load;
390     renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = dawn::LoadOp::Load;
391 
392     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
393     auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
394     pass.SetPipeline(CreatePipelineForTest());
395     pass.Draw(6, 1, 0, 0);
396     pass.EndPass();
397     dawn::CommandBuffer commandBuffer = encoder.Finish();
398     queue.Submit(1, &commandBuffer);
399 
400     // Expect the texture to be red because both depth and stencil tests passed.
401     std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
402     EXPECT_TEXTURE_RGBA8_EQ(expected.data(), srcTexture, 0, 0, kSize, kSize, 0, 0);
403 }
404 
405 // This tests the color attachments clear to 0s
TEST_P(TextureZeroInitTest,ColorAttachmentsClear)406 TEST_P(TextureZeroInitTest, ColorAttachmentsClear) {
407     dawn::TextureDescriptor descriptor = CreateTextureDescriptor(
408         1, 1, dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::CopySrc,
409         kColorFormat);
410     dawn::Texture texture = device.CreateTexture(&descriptor);
411     utils::BasicRenderPass renderPass = utils::BasicRenderPass(kSize, kSize, texture, kColorFormat);
412     renderPass.renderPassInfo.cColorAttachmentsInfoPtr[0]->loadOp = dawn::LoadOp::Load;
413 
414     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
415     {
416         dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
417         pass.EndPass();
418     }
419     dawn::CommandBuffer commands = encoder.Finish();
420     queue.Submit(1, &commands);
421 
422     std::vector<RGBA8> expected(kSize * kSize, {0, 0, 0, 0});
423     EXPECT_TEXTURE_RGBA8_EQ(expected.data(), renderPass.color, 0, 0, kSize, kSize, 0, 0);
424 }
425 
426 DAWN_INSTANTIATE_TEST(
427     TextureZeroInitTest,
428     ForceWorkarounds(D3D12Backend, {"nonzero_clear_resources_on_creation_for_testing"}),
429     ForceWorkarounds(OpenGLBackend, {"nonzero_clear_resources_on_creation_for_testing"}),
430     ForceWorkarounds(VulkanBackend, {"nonzero_clear_resources_on_creation_for_testing"}));
431