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