• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "tests/unittests/validation/ValidationTest.h"
16 
17 #include "utils/ComboRenderPipelineDescriptor.h"
18 #include "utils/WGPUHelpers.h"
19 
20 namespace {
21     class ExternalTextureTest : public ValidationTest {
22       public:
CreateDefaultTextureDescriptor()23         wgpu::TextureDescriptor CreateDefaultTextureDescriptor() {
24             wgpu::TextureDescriptor descriptor;
25             descriptor.size.width = kWidth;
26             descriptor.size.height = kHeight;
27             descriptor.size.depthOrArrayLayers = kDefaultDepth;
28             descriptor.mipLevelCount = kDefaultMipLevels;
29             descriptor.sampleCount = kDefaultSampleCount;
30             descriptor.dimension = wgpu::TextureDimension::e2D;
31             descriptor.format = kDefaultTextureFormat;
32             descriptor.usage =
33                 wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment;
34             return descriptor;
35         }
36 
37       protected:
SetUp()38         void SetUp() override {
39             ValidationTest::SetUp();
40 
41             queue = device.GetQueue();
42         }
43 
44         static constexpr uint32_t kWidth = 32;
45         static constexpr uint32_t kHeight = 32;
46         static constexpr uint32_t kDefaultDepth = 1;
47         static constexpr uint32_t kDefaultMipLevels = 1;
48         static constexpr uint32_t kDefaultSampleCount = 1;
49 
50         static constexpr wgpu::TextureFormat kDefaultTextureFormat =
51             wgpu::TextureFormat::RGBA8Unorm;
52 
53         wgpu::Queue queue;
54     };
55 
TEST_F(ExternalTextureTest,CreateExternalTextureValidation)56     TEST_F(ExternalTextureTest, CreateExternalTextureValidation) {
57         // Creating an external texture from a 2D, single-subresource texture should succeed.
58         {
59             wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
60             wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
61 
62             wgpu::ExternalTextureDescriptor externalDesc;
63             externalDesc.format = kDefaultTextureFormat;
64             externalDesc.plane0 = texture.CreateView();
65             device.CreateExternalTexture(&externalDesc);
66         }
67 
68         // Creating an external texture with a mismatched texture view format should fail.
69         {
70             wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
71             textureDescriptor.format = wgpu::TextureFormat::RGBA8Uint;
72             wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
73 
74             wgpu::ExternalTextureDescriptor externalDesc;
75             externalDesc.format = kDefaultTextureFormat;
76             externalDesc.plane0 = texture.CreateView();
77             ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
78         }
79 
80         // Creating an external texture from a non-2D texture should fail.
81         {
82             wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
83             textureDescriptor.dimension = wgpu::TextureDimension::e3D;
84             wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
85 
86             wgpu::ExternalTextureDescriptor externalDesc;
87             externalDesc.format = kDefaultTextureFormat;
88             externalDesc.plane0 = internalTexture.CreateView();
89             ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
90         }
91 
92         // Creating an external texture from a texture with mip count > 1 should fail.
93         {
94             wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
95             textureDescriptor.mipLevelCount = 2;
96             wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
97 
98             wgpu::ExternalTextureDescriptor externalDesc;
99             externalDesc.format = kDefaultTextureFormat;
100             externalDesc.plane0 = internalTexture.CreateView();
101             ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
102         }
103 
104         // Creating an external texture from a texture without TextureUsage::TextureBinding should
105         // fail.
106         {
107             wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
108             textureDescriptor.mipLevelCount = 2;
109             wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
110 
111             wgpu::ExternalTextureDescriptor externalDesc;
112             externalDesc.format = kDefaultTextureFormat;
113             externalDesc.plane0 = internalTexture.CreateView();
114             ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
115         }
116 
117         // Creating an external texture with an unsupported format should fail.
118         {
119             wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
120             textureDescriptor.format = wgpu::TextureFormat::R8Uint;
121             wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
122 
123             wgpu::ExternalTextureDescriptor externalDesc;
124             externalDesc.plane0 = internalTexture.CreateView();
125             externalDesc.format = textureDescriptor.format;
126             ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
127         }
128 
129         // Creating an external texture with an multisampled texture should fail.
130         {
131             wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
132             textureDescriptor.sampleCount = 4;
133             wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
134 
135             wgpu::ExternalTextureDescriptor externalDesc;
136             externalDesc.format = kDefaultTextureFormat;
137             externalDesc.plane0 = internalTexture.CreateView();
138             ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
139         }
140 
141         // Creating an external texture with an error texture view should fail.
142         {
143             wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
144             wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor);
145 
146             wgpu::TextureViewDescriptor errorViewDescriptor;
147             errorViewDescriptor.format = kDefaultTextureFormat;
148             errorViewDescriptor.dimension = wgpu::TextureViewDimension::e2D;
149             errorViewDescriptor.mipLevelCount = 1;
150             errorViewDescriptor.arrayLayerCount = 2;
151             ASSERT_DEVICE_ERROR(wgpu::TextureView errorTextureView =
152                                     internalTexture.CreateView(&errorViewDescriptor));
153 
154             wgpu::ExternalTextureDescriptor externalDesc;
155             externalDesc.format = kDefaultTextureFormat;
156             externalDesc.plane0 = errorTextureView;
157             externalDesc.format = kDefaultTextureFormat;
158             ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc));
159         }
160     }
161 
162     // Test that submitting a render pass that contains a destroyed external texture results in
163     // an error.
TEST_F(ExternalTextureTest,SubmitDestroyedExternalTextureInRenderPass)164     TEST_F(ExternalTextureTest, SubmitDestroyedExternalTextureInRenderPass) {
165         wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
166         wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
167 
168         wgpu::ExternalTextureDescriptor externalDesc;
169         externalDesc.format = kDefaultTextureFormat;
170         externalDesc.plane0 = texture.CreateView();
171         wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
172 
173         // Create a bind group that contains the external texture.
174         wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
175             device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}});
176         wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, externalTexture}});
177 
178         // Create another texture to use as a color attachment.
179         wgpu::TextureDescriptor renderTextureDescriptor = CreateDefaultTextureDescriptor();
180         wgpu::Texture renderTexture = device.CreateTexture(&renderTextureDescriptor);
181         wgpu::TextureView renderView = renderTexture.CreateView();
182 
183         utils::ComboRenderPassDescriptor renderPass({renderView}, nullptr);
184 
185         // Control case should succeed.
186         {
187             wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
188             wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
189             {
190                 pass.SetBindGroup(0, bindGroup);
191                 pass.EndPass();
192             }
193 
194             wgpu::CommandBuffer commands = encoder.Finish();
195 
196             queue.Submit(1, &commands);
197         }
198 
199         // Destroying the external texture should result in an error.
200         {
201             externalTexture.Destroy();
202             wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
203             wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
204             {
205                 pass.SetBindGroup(0, bindGroup);
206                 pass.EndPass();
207             }
208 
209             wgpu::CommandBuffer commands = encoder.Finish();
210             ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
211         }
212     }
213 
214     // Test that submitting a render pass that contains a destroyed external texture plane
215     // results in an error.
TEST_F(ExternalTextureTest,SubmitDestroyedExternalTexturePlaneInRenderPass)216     TEST_F(ExternalTextureTest, SubmitDestroyedExternalTexturePlaneInRenderPass) {
217         wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
218         wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
219 
220         wgpu::ExternalTextureDescriptor externalDesc;
221         externalDesc.format = kDefaultTextureFormat;
222         externalDesc.plane0 = texture.CreateView();
223         wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
224 
225         // Create a bind group that contains the external texture.
226         wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
227             device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}});
228         wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, externalTexture}});
229 
230         // Create another texture to use as a color attachment.
231         wgpu::TextureDescriptor renderTextureDescriptor = CreateDefaultTextureDescriptor();
232         wgpu::Texture renderTexture = device.CreateTexture(&renderTextureDescriptor);
233         wgpu::TextureView renderView = renderTexture.CreateView();
234 
235         utils::ComboRenderPassDescriptor renderPass({renderView}, nullptr);
236 
237         // Control case should succeed.
238         {
239             wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
240             wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
241             {
242                 pass.SetBindGroup(0, bindGroup);
243                 pass.EndPass();
244             }
245 
246             wgpu::CommandBuffer commands = encoder.Finish();
247 
248             queue.Submit(1, &commands);
249         }
250 
251         // Destroying an external texture underlying plane should result in an error.
252         {
253             texture.Destroy();
254             wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
255             wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
256             {
257                 pass.SetBindGroup(0, bindGroup);
258                 pass.EndPass();
259             }
260 
261             wgpu::CommandBuffer commands = encoder.Finish();
262             ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
263         }
264     }
265 
266     // Test that submitting a compute pass that contains a destroyed external texture results in
267     // an error.
TEST_F(ExternalTextureTest,SubmitDestroyedExternalTextureInComputePass)268     TEST_F(ExternalTextureTest, SubmitDestroyedExternalTextureInComputePass) {
269         wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
270         wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
271 
272         wgpu::ExternalTextureDescriptor externalDesc;
273         externalDesc.format = kDefaultTextureFormat;
274         externalDesc.plane0 = texture.CreateView();
275         wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
276 
277         // Create a bind group that contains the external texture.
278         wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
279             device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}});
280         wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, externalTexture}});
281 
282         wgpu::ComputePassDescriptor computePass;
283 
284         // Control case should succeed.
285         {
286             wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
287             wgpu::ComputePassEncoder pass = encoder.BeginComputePass(&computePass);
288             {
289                 pass.SetBindGroup(0, bindGroup);
290                 pass.EndPass();
291             }
292 
293             wgpu::CommandBuffer commands = encoder.Finish();
294 
295             queue.Submit(1, &commands);
296         }
297 
298         // Destroying the external texture should result in an error.
299         {
300             externalTexture.Destroy();
301             wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
302             wgpu::ComputePassEncoder pass = encoder.BeginComputePass(&computePass);
303             {
304                 pass.SetBindGroup(0, bindGroup);
305                 pass.EndPass();
306             }
307 
308             wgpu::CommandBuffer commands = encoder.Finish();
309             ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
310         }
311     }
312 
313     // Test that submitting a compute pass that contains a destroyed external texture plane
314     // results in an error.
TEST_F(ExternalTextureTest,SubmitDestroyedExternalTexturePlaneInComputePass)315     TEST_F(ExternalTextureTest, SubmitDestroyedExternalTexturePlaneInComputePass) {
316         wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
317         wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
318 
319         wgpu::ExternalTextureDescriptor externalDesc;
320         externalDesc.format = kDefaultTextureFormat;
321         externalDesc.plane0 = texture.CreateView();
322         wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
323 
324         // Create a bind group that contains the external texture.
325         wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
326             device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}});
327         wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, externalTexture}});
328 
329         wgpu::ComputePassDescriptor computePass;
330 
331         // Control case should succeed.
332         {
333             wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
334             wgpu::ComputePassEncoder pass = encoder.BeginComputePass(&computePass);
335             {
336                 pass.SetBindGroup(0, bindGroup);
337                 pass.EndPass();
338             }
339 
340             wgpu::CommandBuffer commands = encoder.Finish();
341             queue.Submit(1, &commands);
342         }
343 
344         // Destroying an external texture underlying plane should result in an error.
345         {
346             texture.Destroy();
347             wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
348             wgpu::ComputePassEncoder pass = encoder.BeginComputePass(&computePass);
349             {
350                 pass.SetBindGroup(0, bindGroup);
351                 pass.EndPass();
352             }
353 
354             wgpu::CommandBuffer commands = encoder.Finish();
355             ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
356         }
357     }
358 }  // namespace
359