// Copyright 2021 The Dawn Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "dawn/tests/unittests/validation/ValidationTest.h" #include "dawn/utils/ComboRenderPipelineDescriptor.h" #include "dawn/utils/WGPUHelpers.h" namespace { class ExternalTextureTest : public ValidationTest { public: wgpu::TextureDescriptor CreateTextureDescriptor( wgpu::TextureFormat format = kDefaultTextureFormat) { wgpu::TextureDescriptor descriptor; descriptor.size.width = kWidth; descriptor.size.height = kHeight; descriptor.size.depthOrArrayLayers = kDefaultDepth; descriptor.mipLevelCount = kDefaultMipLevels; descriptor.sampleCount = kDefaultSampleCount; descriptor.dimension = wgpu::TextureDimension::e2D; descriptor.format = format; descriptor.usage = kDefaultUsage; return descriptor; } wgpu::ExternalTexture CreateDefaultExternalTexture() { wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = defaultTexture.CreateView(); return device.CreateExternalTexture(&externalDesc); } void SubmitExternalTextureInDefaultRenderPass(wgpu::ExternalTexture externalTexture, bool success) { // Create a bind group that contains the external texture. wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout( device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}}); wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, externalTexture}}); // Create another texture to use as a color attachment. wgpu::TextureDescriptor renderTextureDescriptor = CreateTextureDescriptor(); wgpu::Texture renderTexture = device.CreateTexture(&renderTextureDescriptor); wgpu::TextureView renderView = renderTexture.CreateView(); utils::ComboRenderPassDescriptor renderPass({renderView}, nullptr); wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass); pass.SetBindGroup(0, bindGroup); pass.End(); wgpu::CommandBuffer commands = encoder.Finish(); if (success) { queue.Submit(1, &commands); } else { ASSERT_DEVICE_ERROR(queue.Submit(1, &commands)); } } void SubmitExternalTextureInDefaultComputePass(wgpu::ExternalTexture externalTexture, bool success) { // Create a bind group that contains the external texture. wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout( device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}}); wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, externalTexture}}); wgpu::ComputePassDescriptor computePass; wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::ComputePassEncoder pass = encoder.BeginComputePass(&computePass); pass.SetBindGroup(0, bindGroup); pass.End(); wgpu::CommandBuffer commands = encoder.Finish(); if (success) { queue.Submit(1, &commands); } else { ASSERT_DEVICE_ERROR(queue.Submit(1, &commands)); } } protected: void SetUp() override { ValidationTest::SetUp(); queue = device.GetQueue(); wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); defaultTexture = device.CreateTexture(&textureDescriptor); } wgpu::ExternalTextureDescriptor CreateDefaultExternalTextureDescriptor() { wgpu::ExternalTextureDescriptor desc; desc.yuvToRgbConversionMatrix = mPlaceholderConstantArray.data(); desc.gamutConversionMatrix = mPlaceholderConstantArray.data(); desc.srcTransferFunctionParameters = mPlaceholderConstantArray.data(); desc.dstTransferFunctionParameters = mPlaceholderConstantArray.data(); desc.visibleSize = {kWidth, kHeight}; return desc; } static constexpr uint32_t kWidth = 32; static constexpr uint32_t kHeight = 32; static constexpr uint32_t kDefaultDepth = 1; static constexpr uint32_t kDefaultMipLevels = 1; static constexpr uint32_t kDefaultSampleCount = 1; static constexpr wgpu::TextureUsage kDefaultUsage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment; static constexpr wgpu::TextureFormat kDefaultTextureFormat = wgpu::TextureFormat::RGBA8Unorm; static constexpr wgpu::TextureFormat kBiplanarPlane0Format = wgpu::TextureFormat::R8Unorm; static constexpr wgpu::TextureFormat kBiplanarPlane1Format = wgpu::TextureFormat::RG8Unorm; std::array mPlaceholderConstantArray; wgpu::Queue queue; wgpu::Texture defaultTexture; }; TEST_F(ExternalTextureTest, CreateExternalTextureValidation) { // Creating an external texture from a 2D, single-subresource texture should succeed. { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture texture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture.CreateView(); device.CreateExternalTexture(&externalDesc); } // Creating an external texture from a non-2D texture should fail. { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); textureDescriptor.dimension = wgpu::TextureDimension::e3D; textureDescriptor.usage = wgpu::TextureUsage::TextureBinding; wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = internalTexture.CreateView(); ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } // Creating an external texture from a texture with mip count > 1 should fail. { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); textureDescriptor.mipLevelCount = 2; wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = internalTexture.CreateView(); ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } // Creating an external texture from a texture without TextureUsage::TextureBinding should // fail. { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); textureDescriptor.mipLevelCount = 2; wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = internalTexture.CreateView(); ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } // Creating an external texture with an unsupported format should fail. { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); textureDescriptor.format = wgpu::TextureFormat::R8Uint; wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = internalTexture.CreateView(); ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } // Creating an external texture with an multisampled texture should fail. { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); textureDescriptor.sampleCount = 4; wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = internalTexture.CreateView(); ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } // Creating an external texture with an error texture view should fail. { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture internalTexture = device.CreateTexture(&textureDescriptor); wgpu::TextureViewDescriptor errorViewDescriptor; errorViewDescriptor.format = kDefaultTextureFormat; errorViewDescriptor.dimension = wgpu::TextureViewDimension::e2D; errorViewDescriptor.mipLevelCount = 1; errorViewDescriptor.arrayLayerCount = 2; ASSERT_DEVICE_ERROR(wgpu::TextureView errorTextureView = internalTexture.CreateView(&errorViewDescriptor)); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = errorTextureView; ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } } TEST_F(ExternalTextureTest, CreateExternalTextureConstantValueValidation) { DAWN_SKIP_TEST_IF(UsesWire()); // Creating a single plane external texture without a YUV-to-RGB matrix should pass. { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture texture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture.CreateView(); externalDesc.yuvToRgbConversionMatrix = nullptr; device.CreateExternalTexture(&externalDesc); } // Creating a multiplanar external texture without a YUV-to-RGB matrix should fail. { wgpu::TextureDescriptor plane0TextureDescriptor = CreateTextureDescriptor(kBiplanarPlane0Format); wgpu::TextureDescriptor plane1TextureDescriptor = CreateTextureDescriptor(kBiplanarPlane1Format); wgpu::Texture texture0 = device.CreateTexture(&plane0TextureDescriptor); wgpu::Texture texture1 = device.CreateTexture(&plane1TextureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture0.CreateView(); externalDesc.plane1 = texture1.CreateView(); externalDesc.yuvToRgbConversionMatrix = nullptr; ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } // Creating an external texture without a gamut conversion matrix should fail. { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture texture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture.CreateView(); externalDesc.gamutConversionMatrix = nullptr; ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } // Creating an external texture without source transfer function constants should fail. { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture texture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture.CreateView(); externalDesc.srcTransferFunctionParameters = nullptr; ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } // Creating an external texture without destination transfer function constants should fail. { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture texture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture.CreateView(); externalDesc.dstTransferFunctionParameters = nullptr; ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } } // Test that external texture creation works as expected in multiplane scenarios. TEST_F(ExternalTextureTest, CreateMultiplanarExternalTextureValidation) { // Creating an external texture from two 2D, single-subresource textures with a biplanar // format should succeed. { wgpu::TextureDescriptor plane0TextureDescriptor = CreateTextureDescriptor(kBiplanarPlane0Format); wgpu::TextureDescriptor plane1TextureDescriptor = CreateTextureDescriptor(kBiplanarPlane1Format); wgpu::Texture texture0 = device.CreateTexture(&plane0TextureDescriptor); wgpu::Texture texture1 = device.CreateTexture(&plane1TextureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture0.CreateView(); externalDesc.plane1 = texture1.CreateView(); device.CreateExternalTexture(&externalDesc); } // Creating a multiplanar external texture with an unsupported format for plane0 should // result in an error. { wgpu::TextureDescriptor plane0TextureDescriptor = CreateTextureDescriptor(kDefaultTextureFormat); wgpu::TextureDescriptor plane1TextureDescriptor = CreateTextureDescriptor(kBiplanarPlane1Format); wgpu::Texture texture0 = device.CreateTexture(&plane0TextureDescriptor); wgpu::Texture texture1 = device.CreateTexture(&plane1TextureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture0.CreateView(); externalDesc.plane1 = texture1.CreateView(); ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } // Creating a multiplanar external texture with an unsupported format for plane1 should // result in an error. { wgpu::TextureDescriptor plane0TextureDescriptor = CreateTextureDescriptor(kBiplanarPlane0Format); wgpu::TextureDescriptor plane1TextureDescriptor = CreateTextureDescriptor(kDefaultTextureFormat); wgpu::Texture texture0 = device.CreateTexture(&plane0TextureDescriptor); wgpu::Texture texture1 = device.CreateTexture(&plane1TextureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture0.CreateView(); externalDesc.plane1 = texture1.CreateView(); ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } } // Test that refresh on an expired/active external texture. TEST_F(ExternalTextureTest, RefreshExternalTexture) { wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture(); externalTexture.Refresh(); externalTexture.Expire(); externalTexture.Refresh(); } // Test that refresh on a destroyed external texture results in an error. TEST_F(ExternalTextureTest, RefreshDestroyedExternalTexture) { wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture(); // Refresh on destroyed external texture should result in an error. externalTexture.Destroy(); ASSERT_DEVICE_ERROR(externalTexture.Refresh()); } // Test that expire on a destroyed external texture results in an error. TEST_F(ExternalTextureTest, ExpireDestroyedExternalTexture) { wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture(); externalTexture.Destroy(); ASSERT_DEVICE_ERROR(externalTexture.Expire()); } // Test that submitting a render pass that contains an active external texture. TEST_F(ExternalTextureTest, SubmitActiveExternalTextureInRenderPass) { wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture(); SubmitExternalTextureInDefaultRenderPass(externalTexture, true /* success = true */); } // Test that submitting a render pass that contains an expired external texture results in an error. TEST_F(ExternalTextureTest, SubmitExpiredExternalTextureInRenderPass) { wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture(); externalTexture.Expire(); SubmitExternalTextureInDefaultRenderPass(externalTexture, false /* success = false */); } // Test that submitting a render pass that contains an destroyed external texture results in an // error. TEST_F(ExternalTextureTest, SubmitDestroyedExternalTextureInRenderPass) { wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture(); externalTexture.Destroy(); SubmitExternalTextureInDefaultRenderPass(externalTexture, false /* success = false */); } // Test that submitting a compute pass that contains an active external. TEST_F(ExternalTextureTest, SubmitActiveExternalTextureInComputePass) { wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture(); SubmitExternalTextureInDefaultComputePass(externalTexture, true /* success = true */); } // Test that submitting a compute pass that contains an expired external texture results in an // error. TEST_F(ExternalTextureTest, SubmitExpiredExternalTextureInComputePass) { wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture(); externalTexture.Expire(); SubmitExternalTextureInDefaultComputePass(externalTexture, false /* success = false */); } // Test that submitting a compute pass that contains an active external texture should success. TEST_F(ExternalTextureTest, SubmitDestroyedExternalTextureInComputePass) { wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture(); externalTexture.Destroy(); SubmitExternalTextureInDefaultComputePass(externalTexture, false /* success = false */); } // Test that refresh an expired external texture and submit a compute pass with it. TEST_F(ExternalTextureTest, RefreshExpiredExternalTexture) { wgpu::ExternalTexture externalTexture = CreateDefaultExternalTexture(); externalTexture.Expire(); // Submit with expired external texture results in error SubmitExternalTextureInDefaultComputePass(externalTexture, false /* success = false */); externalTexture.Refresh(); // Refreshed external texture could be submitted. SubmitExternalTextureInDefaultComputePass(externalTexture, true /* success = true */); } // Test that submitting a render pass that contains a dereferenced external texture results in // success TEST_F(ExternalTextureTest, SubmitDereferencedExternalTextureInRenderPass) { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture texture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture.CreateView(); wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc); // Create a bind group that contains the external texture. wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout( device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}}); wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, externalTexture}}); // Create another texture to use as a color attachment. wgpu::TextureDescriptor renderTextureDescriptor = CreateTextureDescriptor(); wgpu::Texture renderTexture = device.CreateTexture(&renderTextureDescriptor); wgpu::TextureView renderView = renderTexture.CreateView(); utils::ComboRenderPassDescriptor renderPass({renderView}, nullptr); // Control case should succeed. { wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass); { pass.SetBindGroup(0, bindGroup); pass.End(); } wgpu::CommandBuffer commands = encoder.Finish(); queue.Submit(1, &commands); } // Dereferencing the external texture should not result in a use-after-free error. { externalTexture = nullptr; wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass); { pass.SetBindGroup(0, bindGroup); pass.End(); } wgpu::CommandBuffer commands = encoder.Finish(); queue.Submit(1, &commands); } } // Ensure that bind group validation catches external textures mimatched from the BGL. TEST_F(ExternalTextureTest, BindGroupDoesNotMatchLayout) { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture texture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture.CreateView(); wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc); // Control case should succeed. { wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout( device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}}); utils::MakeBindGroup(device, bgl, {{0, externalTexture}}); } // Bind group creation should fail when an external texture is not present in the // corresponding slot of the bind group layout. { wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout( device, {{0, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Uniform}}); ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, bgl, {{0, externalTexture}})); } } // Regression test for crbug.com/1343099 where BindGroup validation let other binding types be used // for external texture bindings. TEST_F(ExternalTextureTest, TextureViewBindingDoesntMatch) { wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout( device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}}); wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture texture = device.CreateTexture(&textureDescriptor); // The bug was that this passed validation and crashed inside the backends with a null // dereference. It passed validation because the number of bindings matched (1 == 1) and that // the validation didn't check that an external texture binding was required, fell back to // checking for the binding type of entry 0 that had been decayed to be a sampled texture view. ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, bgl, {{0, texture.CreateView()}})); } // Ensure that bind group validation catches error external textures. TEST_F(ExternalTextureTest, UseErrorExternalTextureInBindGroup) { // Control case should succeed. { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture texture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture.CreateView(); wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc); wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout( device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}}); utils::MakeBindGroup(device, bgl, {{0, externalTexture}}); } // Bind group creation should fail when an error external texture is present. { wgpu::ExternalTexture errorExternalTexture = device.CreateErrorExternalTexture(); wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout( device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}}); ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, bgl, {{0, errorExternalTexture}})); } } // Test create external texture with too large visible rect results in error. TEST_F(ExternalTextureTest, CreateExternalTextureWithErrorVisibleOriginOrSize) { // Control case should succeed. { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture texture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture.CreateView(); externalDesc.visibleOrigin = {0, 0}; externalDesc.visibleSize = {texture.GetWidth(), texture.GetHeight()}; device.CreateExternalTexture(&externalDesc); } // VisibleOrigin is OOB on x { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture texture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture.CreateView(); externalDesc.visibleOrigin = {1, 0}; externalDesc.visibleSize = {texture.GetWidth(), texture.GetHeight()}; ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } // VisibleOrigin is OOB on y { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture texture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture.CreateView(); externalDesc.visibleOrigin = {0, 1}; externalDesc.visibleSize = {texture.GetWidth(), texture.GetHeight()}; ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } // VisibleSize is OOB on width { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture texture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture.CreateView(); externalDesc.visibleOrigin = {0, 0}; externalDesc.visibleSize = {texture.GetWidth() + 1, texture.GetHeight()}; ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } // VisibleSize is OOB on height { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture texture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture.CreateView(); externalDesc.visibleOrigin = {0, 0}; externalDesc.visibleSize = {texture.GetWidth(), texture.GetHeight() + 1}; ASSERT_DEVICE_ERROR(device.CreateExternalTexture(&externalDesc)); } } // Test that submitting an external texture with a plane that is not submittable results in error. TEST_F(ExternalTextureTest, SubmitExternalTextureWithDestroyedPlane) { wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor(); wgpu::Texture texture = device.CreateTexture(&textureDescriptor); wgpu::ExternalTextureDescriptor externalDesc = CreateDefaultExternalTextureDescriptor(); externalDesc.plane0 = texture.CreateView(); wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc); // Create a bind group that contains the external texture. wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout( device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}}); wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, externalTexture}}); // Create another texture to use as a color attachment. wgpu::TextureDescriptor renderTextureDescriptor = CreateTextureDescriptor(); wgpu::Texture renderTexture = device.CreateTexture(&renderTextureDescriptor); wgpu::TextureView renderView = renderTexture.CreateView(); utils::ComboRenderPassDescriptor renderPass({renderView}, nullptr); // Control case should succeed. { wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass); { pass.SetBindGroup(0, bindGroup); pass.End(); } wgpu::CommandBuffer commands = encoder.Finish(); queue.Submit(1, &commands); } // Destroying the plane0 backed texture should result in an error. { texture.Destroy(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass); { pass.SetBindGroup(0, bindGroup); pass.End(); } wgpu::CommandBuffer commands = encoder.Finish(); ASSERT_DEVICE_ERROR(queue.Submit(1, &commands)); } } } // namespace