@@ -1778,6 +1778,136 @@ TEST_P(ExternalTextureTests, SampleDifferentKindsDifferentBindGroups) {
17781778 }
17791779}
17801780
1781+ // Test using a pipeline with two external textures in the layout, one of which is unused.
1782+ TEST_P (ExternalTextureTests, LayoutWithUnusedExternalTexture) {
1783+ // Make the two external textures.
1784+ wgpu::ExternalTexture usedET = utils::MakePassthroughExternalTexture (
1785+ device, MakeTestTexture (wgpu::TextureFormat::RGBA8Unorm, 1 , 1 ,
1786+ {1.0 / 255.0 , 2.0 / 255.0 , 3.0 / 255.0 , 4.0 / 255.0 }));
1787+
1788+ wgpu::ExternalTexture unusedET = utils::MakePassthroughExternalTexture (
1789+ device, MakeTestTexture (wgpu::TextureFormat::RGBA8Unorm, 1 , 1 ,
1790+ {2.0 / 255.0 , 4.0 / 255.0 , 6.0 / 255.0 , 8.0 / 255.0 }));
1791+
1792+ // Create the layout using both external textures.
1793+ wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout (
1794+ device, {
1795+ {0 , wgpu::ShaderStage::Compute, wgpu::SamplerBindingType::Filtering},
1796+ {1 , wgpu::ShaderStage::Compute, wgpu::BufferBindingType::Storage},
1797+ {2 , wgpu::ShaderStage::Compute, &utils::kExternalTextureBindingLayout },
1798+ {3 , wgpu::ShaderStage::Compute, &utils::kExternalTextureBindingLayout },
1799+ });
1800+
1801+ wgpu::PipelineLayout pl = utils::MakePipelineLayout (device, {bgl});
1802+
1803+ // Create the pipeline that samples only one of the external textures that's in the layout.
1804+ wgpu::ComputePipelineDescriptor csDesc;
1805+ csDesc.compute .module = utils::CreateShaderModule (device, R"(
1806+ @group(0) @binding(0) var s : sampler;
1807+ @group(0) @binding(1) var<storage, read_write> results : u32;
1808+ @group(0) @binding(2) var t : texture_external;
1809+
1810+ @compute @workgroup_size(1) fn main() {
1811+ results = pack4x8unorm(textureSampleBaseClampToEdge(t, s, vec2(0)));
1812+ }
1813+ )" );
1814+ csDesc.layout = pl;
1815+ wgpu::ComputePipeline pipeline = device.CreateComputePipeline (&csDesc);
1816+
1817+ // Run the pipeline and check the results.
1818+ wgpu::BufferDescriptor resultDesc = {
1819+ .usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc,
1820+ .size = sizeof (uint32_t ),
1821+ };
1822+ wgpu::Buffer resultBuffer = device.CreateBuffer (&resultDesc);
1823+
1824+ wgpu::BindGroup bg = utils::MakeBindGroup (device, pipeline.GetBindGroupLayout (0 ),
1825+ {
1826+ {0 , device.CreateSampler ()},
1827+ {1 , resultBuffer},
1828+ {2 , usedET},
1829+ {3 , unusedET},
1830+ });
1831+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder ();
1832+ wgpu::ComputePassEncoder pass = encoder.BeginComputePass ();
1833+ pass.SetBindGroup (0 , bg);
1834+ pass.SetPipeline (pipeline);
1835+ pass.DispatchWorkgroups (1 );
1836+ pass.End ();
1837+
1838+ wgpu::CommandBuffer commands = encoder.Finish ();
1839+ queue.Submit (1 , &commands);
1840+
1841+ EXPECT_BUFFER_RGBA8_EQ (utils::RGBA8 (1 , 2 , 3 , 4 ), resultBuffer, 0 );
1842+ }
1843+
1844+ // Test that using a dynamic offset works when there is an external texture in the same
1845+ // BindGroupLayout
1846+ TEST_P (ExternalTextureTests, UseExternalTextureWithDynamicOffset) {
1847+ // TODO(42242119): fail on Qualcomm Adreno X1.
1848+ DAWN_SUPPRESS_TEST_IF (IsD3D11 () && IsQualcomm ());
1849+
1850+ // Make the two external textures.
1851+ wgpu::ExternalTexture et = utils::MakePassthroughExternalTexture (
1852+ device, MakeTestTexture (wgpu::TextureFormat::RGBA8Unorm, 1 , 1 ,
1853+ {1.0 / 255.0 , 2.0 / 255.0 , 3.0 / 255.0 , 4.0 / 255.0 }));
1854+
1855+ // Create the layout using both external textures.
1856+ wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout (
1857+ device, {
1858+ {0 , wgpu::ShaderStage::Compute, wgpu::SamplerBindingType::Filtering},
1859+ {1 , wgpu::ShaderStage::Compute, wgpu::BufferBindingType::Storage, true },
1860+ {2 , wgpu::ShaderStage::Compute, &utils::kExternalTextureBindingLayout },
1861+ });
1862+
1863+ wgpu::PipelineLayout pl = utils::MakePipelineLayout (device, {bgl});
1864+
1865+ // Create the pipeline that samples only one of the external textures that's in the layout.
1866+ wgpu::ComputePipelineDescriptor csDesc;
1867+ csDesc.compute .module = utils::CreateShaderModule (device, R"(
1868+ @group(0) @binding(0) var s : sampler;
1869+ @group(0) @binding(1) var<storage, read_write> results : u32;
1870+ @group(0) @binding(2) var t : texture_external;
1871+
1872+ @compute @workgroup_size(1) fn main() {
1873+ results = pack4x8unorm(textureSampleBaseClampToEdge(t, s, vec2(0)));
1874+ }
1875+ )" );
1876+ csDesc.layout = pl;
1877+ wgpu::ComputePipeline pipeline = device.CreateComputePipeline (&csDesc);
1878+
1879+ for (uint32_t offset : {0 , 256 }) {
1880+ // Run the pipeline and check the results.
1881+ wgpu::BufferDescriptor resultDesc = {
1882+ .usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc,
1883+ .size = sizeof (uint32_t ) + 256 ,
1884+ };
1885+ wgpu::Buffer resultBuffer = device.CreateBuffer (&resultDesc);
1886+
1887+ wgpu::BindGroup bg = utils::MakeBindGroup (device, pipeline.GetBindGroupLayout (0 ),
1888+ {
1889+ {0 , device.CreateSampler ()},
1890+ {1 , resultBuffer, 0 , 4 },
1891+ {2 , et},
1892+ });
1893+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder ();
1894+ wgpu::ComputePassEncoder pass = encoder.BeginComputePass ();
1895+ pass.SetBindGroup (0 , bg, 1 , &offset);
1896+ pass.SetPipeline (pipeline);
1897+ pass.DispatchWorkgroups (1 );
1898+ pass.End ();
1899+
1900+ wgpu::CommandBuffer commands = encoder.Finish ();
1901+ queue.Submit (1 , &commands);
1902+
1903+ EXPECT_BUFFER_RGBA8_EQ (utils::RGBA8 (1 , 2 , 3 , 4 ), resultBuffer, offset);
1904+ EXPECT_BUFFER_RGBA8_EQ (utils::RGBA8 (0 , 0 , 0 , 0 ), resultBuffer, 256 - offset);
1905+ }
1906+ }
1907+
1908+ // TODO(https://crbug.com/468988322): Add tests of ExternalTextures being used with a resource table
1909+ // and with Vulkan's extended dynamic state as these are other interactions that could easily break.
1910+
17811911DAWN_INSTANTIATE_TEST (ExternalTextureTests,
17821912 D3D11Backend (),
17831913 D3D12Backend(),
0 commit comments