Remove readonly storage textures

Bug: dawn:1025

Change-Id: I1759639142589470e278b4906d9cad5cb485f9a5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/63743
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Brandon Jones <bajones@chromium.org>
This commit is contained in:
Corentin Wallez 2021-09-17 17:07:43 +00:00 committed by Dawn LUCI CQ
parent a6394ddc07
commit c389182758
22 changed files with 100 additions and 975 deletions

View File

@ -165,8 +165,7 @@
"category": "enum", "category": "enum",
"values": [ "values": [
{"value": 0, "name": "undefined", "jsrepr": "undefined", "valid": false}, {"value": 0, "name": "undefined", "jsrepr": "undefined", "valid": false},
{"value": 1, "name": "read only", "jsrepr": "readonly"}, {"value": 1, "name": "write only", "jsrepr": "writeonly"}
{"value": 2, "name": "write only", "jsrepr": "writeonly"}
] ]
}, },
"storage texture binding layout": { "storage texture binding layout": {

View File

@ -149,12 +149,6 @@ namespace dawn_native {
if (storageTexture.access == wgpu::StorageTextureAccess::WriteOnly) { if (storageTexture.access == wgpu::StorageTextureAccess::WriteOnly) {
allowedStages &= ~wgpu::ShaderStage::Vertex; allowedStages &= ~wgpu::ShaderStage::Vertex;
} }
// TODO(crbug.com/dawn/1025): Remove after the deprecation period.
if (storageTexture.access == wgpu::StorageTextureAccess::ReadOnly) {
device->EmitDeprecationWarning(
"Readonly storage textures are deprecated and will be removed.");
}
} }
const ExternalTextureBindingLayout* externalTextureBindingLayout = nullptr; const ExternalTextureBindingLayout* externalTextureBindingLayout = nullptr;

View File

@ -115,9 +115,6 @@ namespace dawn_native {
case BindingInfoType::StorageTexture: { case BindingInfoType::StorageTexture: {
TextureViewBase* view = group->GetBindingAsTextureView(bindingIndex); TextureViewBase* view = group->GetBindingAsTextureView(bindingIndex);
switch (bindingInfo.storageTexture.access) { switch (bindingInfo.storageTexture.access) {
case wgpu::StorageTextureAccess::ReadOnly:
TextureViewUsedAs(view, kReadOnlyStorageTexture);
break;
case wgpu::StorageTextureAccess::WriteOnly: case wgpu::StorageTextureAccess::WriteOnly:
TextureViewUsedAs(view, wgpu::TextureUsage::StorageBinding); TextureViewUsedAs(view, wgpu::TextureUsage::StorageBinding);
break; break;

View File

@ -319,8 +319,6 @@ namespace dawn_native {
ResultOrError<wgpu::StorageTextureAccess> TintResourceTypeToStorageTextureAccess( ResultOrError<wgpu::StorageTextureAccess> TintResourceTypeToStorageTextureAccess(
tint::inspector::ResourceBinding::ResourceType resource_type) { tint::inspector::ResourceBinding::ResourceType resource_type) {
switch (resource_type) { switch (resource_type) {
case tint::inspector::ResourceBinding::ResourceType::kReadOnlyStorageTexture:
return wgpu::StorageTextureAccess::ReadOnly;
case tint::inspector::ResourceBinding::ResourceType::kWriteOnlyStorageTexture: case tint::inspector::ResourceBinding::ResourceType::kWriteOnlyStorageTexture:
return wgpu::StorageTextureAccess::WriteOnly; return wgpu::StorageTextureAccess::WriteOnly;
default: default:

View File

@ -460,12 +460,6 @@ namespace dawn_native {
if (internalUsageDesc != nullptr) { if (internalUsageDesc != nullptr) {
mInternalUsage |= internalUsageDesc->internalUsage; mInternalUsage |= internalUsageDesc->internalUsage;
} }
// Add readonly storage usage if the texture has a storage usage. The validation rules in
// ValidateSyncScopeResourceUsage will make sure we don't use both at the same time.
if (mInternalUsage & wgpu::TextureUsage::StorageBinding) {
mInternalUsage |= kReadOnlyStorageTexture;
}
} }
static Format kUnusedFormat; static Format kUnusedFormat;

View File

@ -40,7 +40,7 @@ namespace dawn_native {
bool IsValidSampleCount(uint32_t sampleCount); bool IsValidSampleCount(uint32_t sampleCount);
static constexpr wgpu::TextureUsage kReadOnlyTextureUsages = static constexpr wgpu::TextureUsage kReadOnlyTextureUsages =
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding | kReadOnlyStorageTexture; wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::TextureBinding;
class TextureBase : public ObjectBase { class TextureBase : public ObjectBase {
public: public:

View File

@ -160,17 +160,6 @@ namespace dawn_native { namespace d3d12 {
} }
switch (bindingInfo.storageTexture.access) { switch (bindingInfo.storageTexture.access) {
case wgpu::StorageTextureAccess::ReadOnly: {
// Readonly storage is implemented as SRV so it can be used at the same
// time as a sampled texture.
auto& srv = view->GetSRVDescriptor();
d3d12Device->CreateShaderResourceView(
resource, &srv,
viewAllocation.OffsetFrom(viewSizeIncrement,
descriptorHeapOffsets[bindingIndex]));
break;
}
case wgpu::StorageTextureAccess::WriteOnly: { case wgpu::StorageTextureAccess::WriteOnly: {
D3D12_UNORDERED_ACCESS_VIEW_DESC uav = view->GetUAVDescriptor(); D3D12_UNORDERED_ACCESS_VIEW_DESC uav = view->GetUAVDescriptor();
d3d12Device->CreateUnorderedAccessView( d3d12Device->CreateUnorderedAccessView(

View File

@ -47,8 +47,6 @@ namespace dawn_native { namespace d3d12 {
case BindingInfoType::StorageTexture: case BindingInfoType::StorageTexture:
switch (bindingInfo.storageTexture.access) { switch (bindingInfo.storageTexture.access) {
case wgpu::StorageTextureAccess::ReadOnly:
return D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
case wgpu::StorageTextureAccess::WriteOnly: case wgpu::StorageTextureAccess::WriteOnly:
return D3D12_DESCRIPTOR_RANGE_TYPE_UAV; return D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
case wgpu::StorageTextureAccess::Undefined: case wgpu::StorageTextureAccess::Undefined:

View File

@ -50,7 +50,7 @@ namespace dawn_native { namespace d3d12 {
if (usage & wgpu::TextureUsage::CopyDst) { if (usage & wgpu::TextureUsage::CopyDst) {
resourceState |= D3D12_RESOURCE_STATE_COPY_DEST; resourceState |= D3D12_RESOURCE_STATE_COPY_DEST;
} }
if (usage & (wgpu::TextureUsage::TextureBinding | kReadOnlyStorageTexture)) { if (usage & (wgpu::TextureUsage::TextureBinding)) {
resourceState |= (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | resourceState |= (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE |
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
} }

View File

@ -23,12 +23,9 @@
#include <dawn_native/wgpu_structs_autogen.h> #include <dawn_native/wgpu_structs_autogen.h>
namespace dawn_native { namespace dawn_native {
// Add an extra buffer usage (readonly storage buffer usage) and an extra texture usage // Add an extra buffer usage (readonly storage buffer usage) for render pass resource tracking
// (readonly storage texture usage) for render pass resource tracking
static constexpr wgpu::BufferUsage kReadOnlyStorageBuffer = static constexpr wgpu::BufferUsage kReadOnlyStorageBuffer =
static_cast<wgpu::BufferUsage>(0x80000000); static_cast<wgpu::BufferUsage>(0x80000000);
static constexpr wgpu::TextureUsage kReadOnlyStorageTexture =
static_cast<wgpu::TextureUsage>(0x80000000);
// Internal usage to help tracking when a subresource is used as render attachment usage // Internal usage to help tracking when a subresource is used as render attachment usage
// more than once in a render pass. // more than once in a render pass.

View File

@ -339,9 +339,6 @@ namespace dawn_native { namespace opengl {
GLenum access; GLenum access;
switch (bindingInfo.storageTexture.access) { switch (bindingInfo.storageTexture.access) {
case wgpu::StorageTextureAccess::ReadOnly:
access = GL_READ_ONLY;
break;
case wgpu::StorageTextureAccess::WriteOnly: case wgpu::StorageTextureAccess::WriteOnly:
access = GL_WRITE_ONLY; access = GL_WRITE_ONLY;
break; break;

View File

@ -164,8 +164,6 @@ namespace dawn_native { namespace opengl {
spirv_cross::Bitset flags = compiler.get_decoration_bitset(resource.id); spirv_cross::Bitset flags = compiler.get_decoration_bitset(resource.id);
if (flags.get(spv::DecorationNonReadable)) { if (flags.get(spv::DecorationNonReadable)) {
info->storageTexture.access = wgpu::StorageTextureAccess::WriteOnly; info->storageTexture.access = wgpu::StorageTextureAccess::WriteOnly;
} else if (flags.get(spv::DecorationNonWritable)) {
info->storageTexture.access = wgpu::StorageTextureAccess::ReadOnly;
} else { } else {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"Read-write storage textures are not supported"); "Read-write storage textures are not supported");

View File

@ -73,9 +73,6 @@ namespace dawn_native { namespace vulkan {
if (usage & wgpu::TextureUsage::StorageBinding) { if (usage & wgpu::TextureUsage::StorageBinding) {
flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
} }
if (usage & kReadOnlyStorageTexture) {
flags |= VK_ACCESS_SHADER_READ_BIT;
}
if (usage & wgpu::TextureUsage::RenderAttachment) { if (usage & wgpu::TextureUsage::RenderAttachment) {
if (format.HasDepthOrStencil()) { if (format.HasDepthOrStencil()) {
flags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | flags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
@ -119,7 +116,7 @@ namespace dawn_native { namespace vulkan {
if (usage & (wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst)) { if (usage & (wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst)) {
flags |= VK_PIPELINE_STAGE_TRANSFER_BIT; flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
} }
if (usage & (wgpu::TextureUsage::TextureBinding | kReadOnlyStorageTexture)) { if (usage & wgpu::TextureUsage::TextureBinding) {
// TODO(crbug.com/dawn/851): Only transition to the usage we care about to avoid // TODO(crbug.com/dawn/851): Only transition to the usage we care about to avoid
// introducing FS -> VS dependencies that would prevent parallelization on tiler // introducing FS -> VS dependencies that would prevent parallelization on tiler
// GPUs // GPUs
@ -437,7 +434,7 @@ namespace dawn_native { namespace vulkan {
if (usage & wgpu::TextureUsage::TextureBinding) { if (usage & wgpu::TextureUsage::TextureBinding) {
flags |= VK_IMAGE_USAGE_SAMPLED_BIT; flags |= VK_IMAGE_USAGE_SAMPLED_BIT;
} }
if (usage & (wgpu::TextureUsage::StorageBinding | kReadOnlyStorageTexture)) { if (usage & wgpu::TextureUsage::StorageBinding) {
flags |= VK_IMAGE_USAGE_STORAGE_BIT; flags |= VK_IMAGE_USAGE_STORAGE_BIT;
} }
if (usage & wgpu::TextureUsage::RenderAttachment) { if (usage & wgpu::TextureUsage::RenderAttachment) {
@ -462,7 +459,7 @@ namespace dawn_native { namespace vulkan {
if (!wgpu::HasZeroOrOneBits(usage)) { if (!wgpu::HasZeroOrOneBits(usage)) {
// Sampled | ReadOnlyStorage is the only possible multi-bit usage, if more appear we // Sampled | ReadOnlyStorage is the only possible multi-bit usage, if more appear we
// might need additional special-casing. // might need additional special-casing.
ASSERT(usage == (wgpu::TextureUsage::TextureBinding | kReadOnlyStorageTexture)); ASSERT(usage == wgpu::TextureUsage::TextureBinding);
return VK_IMAGE_LAYOUT_GENERAL; return VK_IMAGE_LAYOUT_GENERAL;
} }
@ -495,7 +492,6 @@ namespace dawn_native { namespace vulkan {
// and store operations on storage images can only be done on the images in // and store operations on storage images can only be done on the images in
// VK_IMAGE_LAYOUT_GENERAL layout. // VK_IMAGE_LAYOUT_GENERAL layout.
case wgpu::TextureUsage::StorageBinding: case wgpu::TextureUsage::StorageBinding:
case kReadOnlyStorageTexture:
return VK_IMAGE_LAYOUT_GENERAL; return VK_IMAGE_LAYOUT_GENERAL;
case wgpu::TextureUsage::RenderAttachment: case wgpu::TextureUsage::RenderAttachment:

View File

@ -1487,12 +1487,9 @@ TEST_P(BindGroupTests, ReallyLargeBindGroup) {
bgEntries.push_back({nullptr, binding, nullptr, 0, 0, nullptr, texture.CreateView()}); bgEntries.push_back({nullptr, binding, nullptr, 0, 0, nullptr, texture.CreateView()});
interface << "[[group(0), binding(" << binding++ << ")]] " interface << "[[group(0), binding(" << binding++ << ")]] "
<< "var image" << i << " : texture_storage_2d<r32uint, read>;\n"; << "var image" << i << " : texture_storage_2d<r32uint, write>;\n";
body << "if (textureLoad(image" << i << ", vec2<i32>(0, 0)).r != " << expectedValue++ body << "ignore(image" << i << ");";
<< "u) {\n";
body << " return;\n";
body << "}\n";
} }
for (uint32_t i = 0; i < kMaxUniformBuffersPerShaderStage; ++i) { for (uint32_t i = 0; i < kMaxUniformBuffersPerShaderStage; ++i) {
@ -1547,9 +1544,7 @@ TEST_P(BindGroupTests, ReallyLargeBindGroup) {
wgpu::ComputePipelineDescriptor cpDesc; wgpu::ComputePipelineDescriptor cpDesc;
cpDesc.compute.module = utils::CreateShaderModule(device, shader.c_str()); cpDesc.compute.module = utils::CreateShaderModule(device, shader.c_str());
cpDesc.compute.entryPoint = "main"; cpDesc.compute.entryPoint = "main";
wgpu::ComputePipeline cp; wgpu::ComputePipeline cp = device.CreateComputePipeline(&cpDesc);
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is passed.
EXPECT_DEPRECATION_WARNINGS(cp = device.CreateComputePipeline(&cpDesc), 4);
wgpu::BindGroupDescriptor bgDesc = {}; wgpu::BindGroupDescriptor bgDesc = {};
bgDesc.layout = cp.GetBindGroupLayout(0); bgDesc.layout = cp.GetBindGroupLayout(0);
@ -1621,13 +1616,9 @@ TEST_P(BindGroupTests, CreateWithDestroyedResource) {
// Test a storage texture. // Test a storage texture.
{ {
wgpu::BindGroupLayout bgl; wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is device, {{0, wgpu::ShaderStage::Fragment, wgpu::StorageTextureAccess::WriteOnly,
// passed. wgpu::TextureFormat::R32Uint}});
EXPECT_DEPRECATION_WARNING(
bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::StorageTextureAccess::ReadOnly,
wgpu::TextureFormat::R32Uint}}));
wgpu::TextureDescriptor textureDesc; wgpu::TextureDescriptor textureDesc;
textureDesc.usage = wgpu::TextureUsage::StorageBinding; textureDesc.usage = wgpu::TextureUsage::StorageBinding;

View File

@ -34,19 +34,6 @@ class DeprecationTests : public DawnTest {
} }
}; };
// Test that readonly storage textures are deprecated
TEST_P(DeprecationTests, ReadOnlyStorageTextures) {
// Control case: WriteOnly storage textures are allowed.
utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::StorageTextureAccess::WriteOnly,
wgpu::TextureFormat::R32Float}});
// Error case: ReadOnly storage textures are not allowed.
EXPECT_DEPRECATION_WARNING(utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::StorageTextureAccess::ReadOnly,
wgpu::TextureFormat::R32Float}}));
}
DAWN_INSTANTIATE_TEST(DeprecationTests, DAWN_INSTANTIATE_TEST(DeprecationTests,
D3D12Backend(), D3D12Backend(),
MetalBackend(), MetalBackend(),

View File

@ -225,77 +225,6 @@ TEST_P(GpuMemorySyncTests, ComputePassToRenderPass) {
EXPECT_PIXEL_RGBA8_EQ(RGBA8(2, 0, 0, 255), renderPass.color, 0, 0); EXPECT_PIXEL_RGBA8_EQ(RGBA8(2, 0, 0, 255), renderPass.color, 0, 0);
} }
// Use an image as both sampled and readonly storage in a compute pass. This is a regression test
// for the Vulkan backend choosing different layouts for Sampled and ReadOnlyStorage.
TEST_P(GpuMemorySyncTests, SampledAndROStorageTextureInComputePass) {
// TODO(crbug.com/dawn/646): diagnose and fix this OpenGL ES backend validation failure.
// "GL_INVALID_OPERATION error generated. Image variable update is not allowed."
DAWN_SUPPRESS_TEST_IF(IsOpenGLES() && IsBackendValidationEnabled());
// Create a storage + sampled texture of one texel initialized to 1
wgpu::TextureDescriptor texDesc;
texDesc.format = wgpu::TextureFormat::R32Uint;
texDesc.size = {1, 1, 1};
texDesc.usage = wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::TextureBinding |
wgpu::TextureUsage::CopyDst;
wgpu::Texture tex = device.CreateTexture(&texDesc);
wgpu::ImageCopyTexture copyDst;
copyDst.texture = tex;
wgpu::TextureDataLayout layout;
wgpu::Extent3D copySize = {1, 1, 1};
uint32_t kOne = 1;
queue.WriteTexture(&copyDst, &kOne, sizeof(kOne), &layout, &copySize);
// Create a pipeline that loads the texture from both the sampled and storage paths.
wgpu::ComputePipelineDescriptor pipelineDesc;
pipelineDesc.compute.entryPoint = "main";
pipelineDesc.compute.module = utils::CreateShaderModule(device, R"(
[[block]] struct Output {
sampledOut: u32;
storageOut: u32;
};
[[group(0), binding(0)]] var<storage, write> output : Output;
[[group(0), binding(1)]] var sampledTex : texture_2d<u32>;
[[group(0), binding(2)]] var storageTex : texture_storage_2d<r32uint, read>;
[[stage(compute), workgroup_size(1)]] fn main() {
output.sampledOut = textureLoad(sampledTex, vec2<i32>(0, 0), 0).x;
output.storageOut = textureLoad(storageTex, vec2<i32>(0, 0)).x;
}
)");
wgpu::ComputePipeline pipeline;
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is passed.
EXPECT_DEPRECATION_WARNING(pipeline = device.CreateComputePipeline(&pipelineDesc));
// Run the compute pipeline and store the result in the buffer.
wgpu::BufferDescriptor outputDesc;
outputDesc.size = 8;
outputDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc;
wgpu::Buffer outputBuffer = device.CreateBuffer(&outputDesc);
wgpu::BindGroup bg = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
{
{0, outputBuffer},
{1, tex.CreateView()},
{2, tex.CreateView()},
});
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetBindGroup(0, bg);
pass.SetPipeline(pipeline);
pass.Dispatch(1);
pass.EndPass();
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
// Check the buffer's content is what we expect.
EXPECT_BUFFER_U32_EQ(1, outputBuffer, 0);
EXPECT_BUFFER_U32_EQ(1, outputBuffer, 4);
}
DAWN_INSTANTIATE_TEST(GpuMemorySyncTests, DAWN_INSTANTIATE_TEST(GpuMemorySyncTests,
D3D12Backend(), D3D12Backend(),
MetalBackend(), MetalBackend(),

View File

@ -746,131 +746,6 @@ fn IsEqualTo(pixel : vec4<f32>, expected : vec4<f32>) -> bool {
const char* kComputeExpectedValue = "1 + x + size.x * (y + size.y * slice)"; const char* kComputeExpectedValue = "1 + x + size.x * (y + size.y * slice)";
}; };
// Test that read-only storage textures are supported in compute shader.
TEST_P(StorageTextureTests, ReadonlyStorageTextureInComputeShader) {
for (wgpu::TextureFormat format : utils::kAllTextureFormats) {
if (!utils::TextureFormatSupportsStorageTexture(format)) {
continue;
}
if (IsOpenGLES() && !OpenGLESSupportsStorageTexture(format)) {
continue;
}
// Prepare the read-only storage texture and fill it with the expected data.
const std::vector<uint8_t> kInitialTextureData = GetExpectedData(format);
wgpu::Texture readonlyStorageTexture =
CreateTextureWithTestData(kInitialTextureData, format);
// Create a compute shader that reads the pixels from the read-only storage texture and
// writes 1 to DstBuffer if they all have the expected value.
std::ostringstream csStream;
csStream << R"(
[[block]] struct DstBuffer {
result : u32;
};
[[group(0), binding(1)]] var<storage, read_write> dstBuffer : DstBuffer;
)" << CommonReadOnlyTestCode(format)
<< R"(
[[stage(compute), workgroup_size(1)]] fn main() {
if (doTest()) {
dstBuffer.result = 1u;
} else {
dstBuffer.result = 0u;
}
})";
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is
// passed.
EXPECT_DEPRECATION_WARNING(
CheckResultInStorageBuffer(readonlyStorageTexture, csStream.str()));
}
}
// Test that read-only storage textures are supported in vertex shader.
TEST_P(StorageTextureTests, ReadonlyStorageTextureInVertexShader) {
for (wgpu::TextureFormat format : utils::kAllTextureFormats) {
if (!utils::TextureFormatSupportsStorageTexture(format)) {
continue;
}
if (IsOpenGLES() && !OpenGLESSupportsStorageTexture(format)) {
continue;
}
// Prepare the read-only storage texture and fill it with the expected data.
const std::vector<uint8_t> kInitialTextureData = GetExpectedData(format);
wgpu::Texture readonlyStorageTexture =
CreateTextureWithTestData(kInitialTextureData, format);
// Create a rendering pipeline that reads the pixels from the read-only storage texture and
// uses green as the output color, otherwise uses red instead.
std::ostringstream vsStream;
vsStream << R"(
struct VertexOut {
[[location(0)]] color : vec4<f32>;
[[builtin(position)]] position : vec4<f32>;
};
)" << CommonReadOnlyTestCode(format)
<< R"(
[[stage(vertex)]] fn main() -> VertexOut {
var output : VertexOut;
output.position = vec4<f32>(0.0, 0.0, 0.0, 1.0);
if (doTest()) {
output.color = vec4<f32>(0.0, 1.0, 0.0, 1.0);
} else {
output.color = vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
return output;
})";
const char* kFragmentShader = R"(
[[stage(fragment)]]
fn main([[location(0)]] color : vec4<f32>) -> [[location(0)]] vec4<f32> {
return color;
})";
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is
// passed.
EXPECT_DEPRECATION_WARNING(
CheckDrawsGreen(vsStream.str().c_str(), kFragmentShader, readonlyStorageTexture));
}
}
// Test that read-only storage textures are supported in fragment shader.
TEST_P(StorageTextureTests, ReadonlyStorageTextureInFragmentShader) {
// TODO(crbug.com/dawn/672): Investigate why this test fails on Linux
// NVidia OpenGLES drivers.
DAWN_SUPPRESS_TEST_IF(IsNvidia() && IsLinux() && IsOpenGLES());
for (wgpu::TextureFormat format : utils::kAllTextureFormats) {
if (!utils::TextureFormatSupportsStorageTexture(format)) {
continue;
}
if (IsOpenGLES() && !OpenGLESSupportsStorageTexture(format)) {
continue;
}
// Prepare the read-only storage texture and fill it with the expected data.
const std::vector<uint8_t> kInitialTextureData = GetExpectedData(format);
wgpu::Texture readonlyStorageTexture =
CreateTextureWithTestData(kInitialTextureData, format);
// Create a rendering pipeline that reads the pixels from the read-only storage texture and
// uses green as the output color if the pixel value is expected, otherwise uses red
// instead.
std::ostringstream fsStream;
fsStream << CommonReadOnlyTestCode(format) << R"(
[[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
if (doTest()) {
return vec4<f32>(0.0, 1.0, 0.0, 1.0);
}
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
})";
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is
// passed.
EXPECT_DEPRECATION_WARNING(
CheckDrawsGreen(kSimpleVertexShader, fsStream.str().c_str(), readonlyStorageTexture));
}
}
// Test that write-only storage textures are supported in compute shader. // Test that write-only storage textures are supported in compute shader.
TEST_P(StorageTextureTests, WriteonlyStorageTextureInComputeShader) { TEST_P(StorageTextureTests, WriteonlyStorageTextureInComputeShader) {
for (wgpu::TextureFormat format : utils::kAllTextureFormats) { for (wgpu::TextureFormat format : utils::kAllTextureFormats) {
@ -905,47 +780,6 @@ TEST_P(StorageTextureTests, WriteonlyStorageTextureInComputeShader) {
} }
} }
// Test that reading from one read-only storage texture then writing into another write-only storage
// texture in one dispatch are supported in compute shader.
TEST_P(StorageTextureTests, ReadWriteDifferentStorageTextureInOneDispatchInComputeShader) {
// TODO(crbug.com/dawn/636): diagnose and fix this failure on OpenGL ES
DAWN_SUPPRESS_TEST_IF(IsOpenGLES());
for (wgpu::TextureFormat format : utils::kAllTextureFormats) {
if (!utils::TextureFormatSupportsStorageTexture(format)) {
continue;
}
if (IsOpenGLES() && !OpenGLESSupportsStorageTexture(format)) {
continue;
}
// TODO(jiawei.shao@intel.com): investigate why this test fails with RGBA8Snorm on Linux
// Intel OpenGL driver.
if (format == wgpu::TextureFormat::RGBA8Snorm && IsIntel() && IsOpenGL() && IsLinux()) {
continue;
}
// Prepare the read-only storage texture.
const std::vector<uint8_t> kInitialTextureData = GetExpectedData(format);
wgpu::Texture readonlyStorageTexture =
CreateTextureWithTestData(kInitialTextureData, format);
// Prepare the write-only storage texture.
wgpu::Texture writeonlyStorageTexture =
CreateTexture(format, wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::CopySrc);
// Write the expected pixel values into the write-only storage texture.
const std::string computeShader = CommonReadWriteTestCode(format);
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is
// passed.
EXPECT_DEPRECATION_WARNING(ReadWriteIntoStorageTextureInComputePass(
readonlyStorageTexture, writeonlyStorageTexture, computeShader.c_str()));
// Verify the pixel data in the write-only storage texture is expected.
CheckOutputStorageTexture(writeonlyStorageTexture, format);
}
}
// Test that write-only storage textures are supported in fragment shader. // Test that write-only storage textures are supported in fragment shader.
TEST_P(StorageTextureTests, WriteonlyStorageTextureInFragmentShader) { TEST_P(StorageTextureTests, WriteonlyStorageTextureInFragmentShader) {
// TODO(crbug.com/dawn/672): Investigate why this test fails on Linux // TODO(crbug.com/dawn/672): Investigate why this test fails on Linux
@ -985,52 +819,6 @@ TEST_P(StorageTextureTests, WriteonlyStorageTextureInFragmentShader) {
} }
} }
// Verify 2D array and 3D read-only storage textures work correctly.
TEST_P(StorageTextureTests, Readonly2DArrayOr3DStorageTexture) {
// TODO(crbug.com/dawn/547): implement 3D storage texture on OpenGL and OpenGLES.
DAWN_TEST_UNSUPPORTED_IF(IsOpenGL() || IsOpenGLES());
constexpr uint32_t kSliceCount = 3u;
constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::R32Uint;
const std::vector<uint8_t> initialTextureData = GetExpectedData(kTextureFormat, kSliceCount);
wgpu::TextureViewDimension dimensions[] = {
wgpu::TextureViewDimension::e2DArray,
wgpu::TextureViewDimension::e3D,
};
for (wgpu::TextureViewDimension dimension : dimensions) {
wgpu::Texture readonlyStorageTexture =
CreateTextureWithTestData(initialTextureData, kTextureFormat, dimension);
// Create a compute shader that reads the pixels from the read-only storage texture and
// writes 1 to DstBuffer if they all have the expected value.
std::ostringstream csStream;
csStream << R"(
[[block]] struct DstBuffer {
result : u32;
};
[[group(0), binding(1)]] var<storage, read_write> dstBuffer : DstBuffer;
)" << CommonReadOnlyTestCode(kTextureFormat, dimension)
<< R"(
[[stage(compute), workgroup_size(1)]] fn main() {
if (doTest()) {
dstBuffer.result = 1u;
} else {
dstBuffer.result = 0u;
}
})";
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is
// passed.
EXPECT_DEPRECATION_WARNING(
CheckResultInStorageBuffer(readonlyStorageTexture, csStream.str(), dimension));
}
}
// Verify 2D array and 3D write-only storage textures work correctly. // Verify 2D array and 3D write-only storage textures work correctly.
TEST_P(StorageTextureTests, Writeonly2DArrayOr3DStorageTexture) { TEST_P(StorageTextureTests, Writeonly2DArrayOr3DStorageTexture) {
// TODO(crbug.com/dawn/547): implement 3D storage texture on OpenGL and OpenGLES. // TODO(crbug.com/dawn/547): implement 3D storage texture on OpenGL and OpenGLES.
@ -1062,123 +850,6 @@ TEST_P(StorageTextureTests, Writeonly2DArrayOr3DStorageTexture) {
} }
} }
// Verify 2D array and 3D read-write storage textures work correctly.
TEST_P(StorageTextureTests, ReadWrite2DArrayOr3DStorageTexture) {
// TODO(crbug.com/dawn/547): implement 3D storage texture on OpenGL and OpenGLES.
DAWN_TEST_UNSUPPORTED_IF(IsOpenGL() || IsOpenGLES());
constexpr uint32_t kSliceCount = 3u;
constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::R32Uint;
wgpu::TextureViewDimension dimensions[] = {
wgpu::TextureViewDimension::e2DArray,
wgpu::TextureViewDimension::e3D,
};
const std::vector<uint8_t> initialTextureData = GetExpectedData(kTextureFormat, kSliceCount);
for (wgpu::TextureViewDimension dimension : dimensions) {
// Prepare the read-only storage texture.
wgpu::Texture readonlyStorageTexture =
CreateTextureWithTestData(initialTextureData, kTextureFormat, dimension);
// Prepare the write-only storage texture.
wgpu::Texture writeonlyStorageTexture = CreateTexture(
kTextureFormat, wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::CopySrc,
kWidth, kHeight, kSliceCount, utils::ViewDimensionToTextureDimension(dimension));
// Read values from read-only storage texture and write into the write-only storage texture.
const std::string computeShader = CommonReadWriteTestCode(kTextureFormat, dimension);
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is
// passed.
EXPECT_DEPRECATION_WARNING(ReadWriteIntoStorageTextureInComputePass(
readonlyStorageTexture, writeonlyStorageTexture, computeShader.c_str(), dimension));
// Verify the data in the write-only storage texture is expected.
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is
// passed.
CheckOutputStorageTexture(writeonlyStorageTexture, kTextureFormat, kSliceCount);
}
}
// Test that multiple dispatches to increment values by ping-ponging between a read-only storage
// texture and a write-only storage texture are synchronized in one pass.
TEST_P(StorageTextureTests, ReadonlyAndWriteonlyStorageTexturePingPong) {
// TODO(crbug.com/dawn/636): diagnose and fix this failure on OpenGL ES
DAWN_SUPPRESS_TEST_IF(IsOpenGLES());
constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::R32Uint;
wgpu::Texture storageTexture1 = CreateTexture(
kTextureFormat, wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::CopySrc, 1u, 1u);
wgpu::Texture storageTexture2 = CreateTexture(
kTextureFormat, wgpu::TextureUsage::StorageBinding | wgpu::TextureUsage::CopySrc, 1u, 1u);
wgpu::ShaderModule module = utils::CreateShaderModule(device, R"(
[[group(0), binding(0)]] var Src : texture_storage_2d<r32uint, read>;
[[group(0), binding(1)]] var Dst : texture_storage_2d<r32uint, write>;
[[stage(compute), workgroup_size(1)]] fn main() {
var srcValue : vec4<u32> = textureLoad(Src, vec2<i32>(0, 0));
srcValue.x = srcValue.x + 1u;
textureStore(Dst, vec2<i32>(0, 0), srcValue);
}
)");
wgpu::ComputePipelineDescriptor pipelineDesc = {};
pipelineDesc.compute.module = module;
pipelineDesc.compute.entryPoint = "main";
wgpu::ComputePipeline pipeline;
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is passed.
EXPECT_DEPRECATION_WARNING(pipeline = device.CreateComputePipeline(&pipelineDesc));
// In bindGroupA storageTexture1 is bound as read-only storage texture and storageTexture2 is
// bound as write-only storage texture.
wgpu::BindGroup bindGroupA = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
{
{0, storageTexture1.CreateView()},
{1, storageTexture2.CreateView()},
});
// In bindGroupA storageTexture2 is bound as read-only storage texture and storageTexture1 is
// bound as write-only storage texture.
wgpu::BindGroup bindGroupB = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
{
{0, storageTexture2.CreateView()},
{1, storageTexture1.CreateView()},
});
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetPipeline(pipeline);
// After the first dispatch the value in storageTexture2 should be 1u.
pass.SetBindGroup(0, bindGroupA);
pass.Dispatch(1);
// After the second dispatch the value in storageTexture1 should be 2u;
pass.SetBindGroup(0, bindGroupB);
pass.Dispatch(1);
pass.EndPass();
wgpu::BufferDescriptor bufferDescriptor;
bufferDescriptor.size = sizeof(uint32_t);
bufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
wgpu::Buffer resultBuffer = device.CreateBuffer(&bufferDescriptor);
wgpu::ImageCopyTexture imageCopyTexture;
imageCopyTexture.texture = storageTexture1;
wgpu::ImageCopyBuffer imageCopyBuffer = utils::CreateImageCopyBuffer(resultBuffer, 0, 256, 1);
wgpu::Extent3D extent3D = {1, 1, 1};
encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBuffer, &extent3D);
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
constexpr uint32_t kFinalPixelValueInTexture1 = 2u;
EXPECT_BUFFER_U32_EQ(kFinalPixelValueInTexture1, resultBuffer, 0);
}
// Test that multiple dispatches to increment values by ping-ponging between a sampled texture and // Test that multiple dispatches to increment values by ping-ponging between a sampled texture and
// a write-only storage texture are synchronized in one pass. // a write-only storage texture are synchronized in one pass.
TEST_P(StorageTextureTests, SampledAndWriteonlyStorageTexturePingPong) { TEST_P(StorageTextureTests, SampledAndWriteonlyStorageTexturePingPong) {
@ -1305,58 +976,6 @@ fn doTest() -> bool {
})"; })";
}; };
// Verify that the texture is correctly cleared to 0 before its first usage as a read-only storage
// texture in a render pass.
TEST_P(StorageTextureZeroInitTests, ReadonlyStorageTextureClearsToZeroInRenderPass) {
wgpu::Texture readonlyStorageTexture =
CreateTexture(wgpu::TextureFormat::R32Uint, wgpu::TextureUsage::StorageBinding);
// Create a rendering pipeline that reads the pixels from the read-only storage texture and uses
// green as the output color, otherwise uses red instead.
const char* kVertexShader = kSimpleVertexShader;
const std::string kFragmentShader = std::string(R"(
[[group(0), binding(0)]] var srcImage : texture_storage_2d<r32uint, read>;
)") + kCommonReadOnlyZeroInitTestCode +
R"(
[[stage(fragment)]] fn main() -> [[location(0)]] vec4<f32> {
if (doTest()) {
return vec4<f32>(0.0, 1.0, 0.0, 1.0);
}
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
})";
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is passed.
EXPECT_DEPRECATION_WARNING(
CheckDrawsGreen(kVertexShader, kFragmentShader.c_str(), readonlyStorageTexture));
}
// Verify that the texture is correctly cleared to 0 before its first usage as a read-only storage
// texture in a compute pass.
TEST_P(StorageTextureZeroInitTests, ReadonlyStorageTextureClearsToZeroInComputePass) {
wgpu::Texture readonlyStorageTexture =
CreateTexture(wgpu::TextureFormat::R32Uint, wgpu::TextureUsage::StorageBinding);
// Create a compute shader that reads the pixels from the read-only storage texture and writes 1
// to DstBuffer if they all have the expected value.
const std::string kComputeShader = std::string(R"(
[[block]] struct DstBuffer {
result : u32;
};
[[group(0), binding(0)]] var srcImage : texture_storage_2d<r32uint, read>;
[[group(0), binding(1)]] var<storage, read_write> dstBuffer : DstBuffer;
)") + kCommonReadOnlyZeroInitTestCode + R"(
[[stage(compute), workgroup_size(1)]] fn main() {
if (doTest()) {
dstBuffer.result = 1u;
} else {
dstBuffer.result = 0u;
}
})";
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is passed.
EXPECT_DEPRECATION_WARNING(CheckResultInStorageBuffer(readonlyStorageTexture, kComputeShader));
}
// Verify that the texture is correctly cleared to 0 before its first usage as a write-only storage // Verify that the texture is correctly cleared to 0 before its first usage as a write-only storage
// storage texture in a render pass. // storage texture in a render pass.
TEST_P(StorageTextureZeroInitTests, WriteonlyStorageTextureClearsToZeroInRenderPass) { TEST_P(StorageTextureZeroInitTests, WriteonlyStorageTextureClearsToZeroInRenderPass) {

View File

@ -1015,78 +1015,6 @@ TEST_F(BindGroupLayoutValidationTest, PerStageLimits) {
} }
} }
// This is the same test as PerStageLimits but for the deprecated ReadOnly storage textures.
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is passed.
TEST_F(BindGroupLayoutValidationTest, PerStageLimits_ReadOnlyStorageTexture) {
uint32_t maxCount = kMaxStorageTexturesPerShaderStage;
wgpu::BindGroupLayoutEntry entry =
BGLEntryType(wgpu::StorageTextureAccess::ReadOnly, wgpu::TextureFormat::RGBA8Unorm);
wgpu::BindGroupLayoutEntry otherEntry = BGLEntryType(wgpu::BufferBindingType::Uniform);
wgpu::BindGroupLayout bgl[2];
std::vector<utils::BindingLayoutEntryInitializationHelper> maxBindings;
for (uint32_t i = 0; i < maxCount; ++i) {
entry.binding = i;
maxBindings.push_back(entry);
}
// Creating with the maxes works.
EXPECT_DEPRECATION_WARNINGS(
bgl[0] = MakeBindGroupLayout(maxBindings.data(), maxBindings.size()), maxCount);
// Adding an extra binding of a different type works.
{
std::vector<utils::BindingLayoutEntryInitializationHelper> bindings = maxBindings;
wgpu::BindGroupLayoutEntry newEntry = otherEntry;
newEntry.binding = maxCount;
bindings.push_back(newEntry);
EXPECT_DEPRECATION_WARNINGS(MakeBindGroupLayout(bindings.data(), bindings.size()),
maxCount);
}
// Adding an extra binding of the maxed type in a different stage works
{
std::vector<utils::BindingLayoutEntryInitializationHelper> bindings = maxBindings;
wgpu::BindGroupLayoutEntry newEntry = entry;
newEntry.binding = maxCount;
newEntry.visibility = wgpu::ShaderStage::Fragment;
bindings.push_back(newEntry);
EXPECT_DEPRECATION_WARNINGS(MakeBindGroupLayout(bindings.data(), bindings.size()),
maxCount + 1);
}
// Adding an extra binding of the maxed type and stage exceeds the per stage limit.
{
std::vector<utils::BindingLayoutEntryInitializationHelper> bindings = maxBindings;
wgpu::BindGroupLayoutEntry newEntry = entry;
newEntry.binding = maxCount;
bindings.push_back(newEntry);
EXPECT_DEPRECATION_WARNINGS(
ASSERT_DEVICE_ERROR(MakeBindGroupLayout(bindings.data(), bindings.size())),
maxCount + 1);
}
// Creating a pipeline layout from the valid BGL works.
TestCreatePipelineLayout(bgl, 1, true);
// Adding an extra binding of a different type in a different BGL works
bgl[1] = utils::MakeBindGroupLayout(device, {otherEntry});
TestCreatePipelineLayout(bgl, 2, true);
{
// Adding an extra binding of the maxed type in a different stage works
wgpu::BindGroupLayoutEntry newEntry = entry;
newEntry.visibility = wgpu::ShaderStage::Fragment;
EXPECT_DEPRECATION_WARNING(bgl[1] = utils::MakeBindGroupLayout(device, {newEntry}));
TestCreatePipelineLayout(bgl, 2, true);
}
// Adding an extra binding of the maxed type in a different BGL exceeds the per stage limit.
EXPECT_DEPRECATION_WARNING(bgl[1] = utils::MakeBindGroupLayout(device, {entry}));
TestCreatePipelineLayout(bgl, 2, false);
}
// External textures require multiple binding slots (3 sampled texture, 1 uniform buffer, 1 // External textures require multiple binding slots (3 sampled texture, 1 uniform buffer, 1
// sampler), so ensure that these count towards the limit when combined non-external texture // sampler), so ensure that these count towards the limit when combined non-external texture
// bindings. // bindings.

View File

@ -814,51 +814,6 @@ namespace {
} }
} }
// Test that using a single texture in multiple read usages in the same pass is allowed.
TEST_F(ResourceUsageTrackingTest, TextureWithMultipleReadUsages) {
// Create a texture that will be used as both sampled and readonly storage texture
wgpu::Texture texture =
CreateTexture(wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::StorageBinding);
wgpu::TextureView view = texture.CreateView();
// Create a bind group to use the texture as sampled and readonly storage bindings
wgpu::BindGroupLayout bgl;
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is
// passed.
EXPECT_DEPRECATION_WARNING(
bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute,
wgpu::TextureSampleType::Float},
{1, wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute,
wgpu::StorageTextureAccess::ReadOnly, kFormat}}));
wgpu::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, view}, {1, view}});
// Test render pass
{
// Use the texture as both sampled and readonly storage in the same render pass
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
DummyRenderPass dummyRenderPass(device);
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass);
pass.SetBindGroup(0, bg);
pass.EndPass();
encoder.Finish();
}
// Test compute pass
{
// Use the texture as both sampled and readonly storage in the same compute pass
wgpu::ComputePipeline cp = CreateNoOpComputePipeline({bgl});
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetBindGroup(0, bg);
pass.SetPipeline(cp);
pass.Dispatch(1);
pass.EndPass();
encoder.Finish();
}
}
// Test that it is invalid to use the same texture as both readable and writable in the same // Test that it is invalid to use the same texture as both readable and writable in the same
// render pass. It is invalid in the same dispatch in compute pass. // render pass. It is invalid in the same dispatch in compute pass.
TEST_F(ResourceUsageTrackingTest, TextureWithReadAndWriteUsage) { TEST_F(ResourceUsageTrackingTest, TextureWithReadAndWriteUsage) {
@ -1100,24 +1055,20 @@ namespace {
// Test compute pass // Test compute pass
{ {
// Create a texture that will be used storage texture // Create a texture that will be used storage texture
wgpu::Texture texture = CreateTexture(wgpu::TextureUsage::StorageBinding); wgpu::Texture texture = CreateTexture(wgpu::TextureUsage::TextureBinding |
wgpu::TextureUsage::StorageBinding);
wgpu::TextureView view = texture.CreateView(); wgpu::TextureView view = texture.CreateView();
// Create bind groups to use the texture as readonly and writeonly bindings // Create bind groups to use the texture as sampled and writeonly bindings
wgpu::BindGroupLayout readBGL; wgpu::BindGroupLayout readBGL = utils::MakeBindGroupLayout(
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is device, {{0, wgpu::ShaderStage::Compute, wgpu::TextureSampleType::Float}});
// passed.
EXPECT_DEPRECATION_WARNING(
readBGL = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::ReadOnly,
kFormat}}));
wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout( wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout(
device, device,
{{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, kFormat}}); {{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, kFormat}});
wgpu::BindGroup readBG = utils::MakeBindGroup(device, readBGL, {{0, view}}); wgpu::BindGroup readBG = utils::MakeBindGroup(device, readBGL, {{0, view}});
wgpu::BindGroup writeBG = utils::MakeBindGroup(device, writeBGL, {{0, view}}); wgpu::BindGroup writeBG = utils::MakeBindGroup(device, writeBGL, {{0, view}});
// Use the textures as both readonly and writeonly storages in different passes // Use the textures as both sampled and writeonly storages in different passes
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass0 = encoder.BeginComputePass(); wgpu::ComputePassEncoder pass0 = encoder.BeginComputePass();
@ -1134,24 +1085,20 @@ namespace {
// Test compute pass and render pass mixed together with resource dependency // Test compute pass and render pass mixed together with resource dependency
{ {
// Create a texture that will be used a storage texture // Create a texture that will be used a storage texture
wgpu::Texture texture = CreateTexture(wgpu::TextureUsage::StorageBinding); wgpu::Texture texture = CreateTexture(wgpu::TextureUsage::TextureBinding |
wgpu::TextureUsage::StorageBinding);
wgpu::TextureView view = texture.CreateView(); wgpu::TextureView view = texture.CreateView();
// Create bind groups to use the texture as readonly and writeonly bindings // Create bind groups to use the texture as sampled and writeonly bindings
wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout( wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout(
device, device,
{{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, kFormat}}); {{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, kFormat}});
wgpu::BindGroupLayout readBGL; wgpu::BindGroupLayout readBGL = utils::MakeBindGroupLayout(
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is device, {{0, wgpu::ShaderStage::Fragment, wgpu::TextureSampleType::Float}});
// passed.
EXPECT_DEPRECATION_WARNING(
readBGL = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::StorageTextureAccess::ReadOnly,
kFormat}}));
wgpu::BindGroup writeBG = utils::MakeBindGroup(device, writeBGL, {{0, view}}); wgpu::BindGroup writeBG = utils::MakeBindGroup(device, writeBGL, {{0, view}});
wgpu::BindGroup readBG = utils::MakeBindGroup(device, readBGL, {{0, view}}); wgpu::BindGroup readBG = utils::MakeBindGroup(device, readBGL, {{0, view}});
// Use the texture as writeonly and readonly storage in compute pass and render // Use the texture as writeonly and sampled storage in compute pass and render
// pass respectively // pass respectively
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
@ -1210,14 +1157,9 @@ namespace {
// Test compute pass // Test compute pass
{ {
// Create bind groups to use the texture as readonly and writeonly storage bindings // Create bind groups to use the texture as sampled and writeonly storage bindings
wgpu::BindGroupLayout readBGL; wgpu::BindGroupLayout readBGL = utils::MakeBindGroupLayout(
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is device, {{0, wgpu::ShaderStage::Compute, wgpu::TextureSampleType::Float}});
// passed.
EXPECT_DEPRECATION_WARNING(
readBGL = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::ReadOnly,
kFormat}}));
wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout( wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout(
device, device,
{{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, kFormat}}); {{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, kFormat}});
@ -1285,14 +1227,9 @@ namespace {
// Test compute pass // Test compute pass
{ {
// Create the bind group to use the texture as readonly and writeonly storage bindings // Create the bind group to use the texture as sampled and writeonly storage bindings
wgpu::BindGroupLayout readBGL; wgpu::BindGroupLayout readBGL = utils::MakeBindGroupLayout(
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is device, {{0, wgpu::ShaderStage::Compute, wgpu::TextureSampleType::Float}});
// passed.
EXPECT_DEPRECATION_WARNING(
readBGL = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::ReadOnly,
kFormat}}));
wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout( wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout(
device, device,
{{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, kFormat}}); {{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, kFormat}});
@ -1411,23 +1348,19 @@ namespace {
// Test compute pass // Test compute pass
{ {
// Create a texture that will be used both as storage texture // Create a texture that will be used both as storage texture
wgpu::Texture texture0 = CreateTexture(wgpu::TextureUsage::StorageBinding); wgpu::Texture texture0 = CreateTexture(wgpu::TextureUsage::TextureBinding |
wgpu::TextureUsage::StorageBinding);
wgpu::TextureView view0 = texture0.CreateView(); wgpu::TextureView view0 = texture0.CreateView();
wgpu::Texture texture1 = CreateTexture(wgpu::TextureUsage::StorageBinding); wgpu::Texture texture1 = CreateTexture(wgpu::TextureUsage::TextureBinding);
wgpu::TextureView view1 = texture1.CreateView(); wgpu::TextureView view1 = texture1.CreateView();
// Create the bind group to use the texture as readonly and writeonly bindings // Create the bind group to use the texture as sampled and writeonly bindings
wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout( wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout(
device, device,
{{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, kFormat}}); {{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, kFormat}});
wgpu::BindGroupLayout readBGL; wgpu::BindGroupLayout readBGL = utils::MakeBindGroupLayout(
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is device, {{0, wgpu::ShaderStage::Compute, wgpu::TextureSampleType::Float}});
// passed.
EXPECT_DEPRECATION_WARNING(
readBGL = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::ReadOnly,
kFormat}}));
wgpu::BindGroup writeBG0 = utils::MakeBindGroup(device, writeBGL, {{0, view0}}); wgpu::BindGroup writeBG0 = utils::MakeBindGroup(device, writeBGL, {{0, view0}});
wgpu::BindGroup readBG0 = utils::MakeBindGroup(device, readBGL, {{0, view0}}); wgpu::BindGroup readBG0 = utils::MakeBindGroup(device, readBGL, {{0, view0}});
@ -1437,7 +1370,7 @@ namespace {
wgpu::ComputePipeline cp = CreateNoOpComputePipeline({writeBGL, readBGL}); wgpu::ComputePipeline cp = CreateNoOpComputePipeline({writeBGL, readBGL});
// Set bind group on the same index twice. The second one overwrites the first one. // Set bind group on the same index twice. The second one overwrites the first one.
// No texture is used as both readonly and writeonly storage in the same dispatch so // No texture is used as both sampled and writeonly storage in the same dispatch so
// there are no errors. // there are no errors.
{ {
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
@ -1452,7 +1385,7 @@ namespace {
} }
// Set bind group on the same index twice. The second one overwrites the first one. // Set bind group on the same index twice. The second one overwrites the first one.
// texture0 is used as both writeonly and readonly storage in the same dispatch, which // texture0 is used as both writeonly and sampled storage in the same dispatch, which
// is an error. // is an error.
{ {
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
@ -1472,22 +1405,18 @@ namespace {
// visible to the programmable pass where it is used. // visible to the programmable pass where it is used.
TEST_F(ResourceUsageTrackingTest, TextureUsageConflictBetweenInvisibleStagesInBindGroup) { TEST_F(ResourceUsageTrackingTest, TextureUsageConflictBetweenInvisibleStagesInBindGroup) {
// Create texture and texture view // Create texture and texture view
wgpu::Texture texture = CreateTexture(wgpu::TextureUsage::StorageBinding); wgpu::Texture texture =
CreateTexture(wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::StorageBinding);
wgpu::TextureView view = texture.CreateView(); wgpu::TextureView view = texture.CreateView();
// Test render pass for bind group. The conflict of readonly storage and writeonly storage // Test render pass for bind group. The conflict of sampled storage and writeonly storage
// usage doesn't reside in render related stages at all // usage doesn't reside in render related stages at all
{ {
// Create a bind group whose bindings are not visible in render pass // Create a bind group whose bindings are not visible in render pass
wgpu::BindGroupLayout bgl; wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is
// passed.
EXPECT_DEPRECATION_WARNING(
bgl = utils::MakeBindGroupLayout(
device, device,
{{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::ReadOnly, kFormat}, {{0, wgpu::ShaderStage::Compute, wgpu::TextureSampleType::Float},
{1, wgpu::ShaderStage::None, wgpu::StorageTextureAccess::WriteOnly, {1, wgpu::ShaderStage::None, wgpu::StorageTextureAccess::WriteOnly, kFormat}});
kFormat}}));
wgpu::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, view}, {1, view}}); wgpu::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, view}, {1, view}});
// These two bindings are invisible in render pass. But we still track these bindings. // These two bindings are invisible in render pass. But we still track these bindings.
@ -1499,19 +1428,14 @@ namespace {
ASSERT_DEVICE_ERROR(encoder.Finish()); ASSERT_DEVICE_ERROR(encoder.Finish());
} }
// Test compute pass for bind group. The conflict of readonly storage and writeonly storage // Test compute pass for bind group. The conflict of sampled storage and writeonly storage
// usage doesn't reside in compute related stage at all // usage doesn't reside in compute related stage at all
{ {
// Create a bind group whose bindings are not visible in compute pass // Create a bind group whose bindings are not visible in compute pass
wgpu::BindGroupLayout bgl; wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is device,
// passed. {{0, wgpu::ShaderStage::Fragment, wgpu::TextureSampleType::Float},
EXPECT_DEPRECATION_WARNING( {1, wgpu::ShaderStage::None, wgpu::StorageTextureAccess::WriteOnly, kFormat}});
bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::StorageTextureAccess::ReadOnly,
kFormat},
{1, wgpu::ShaderStage::None, wgpu::StorageTextureAccess::WriteOnly,
kFormat}}));
wgpu::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, view}, {1, view}}); wgpu::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, view}, {1, view}});
// Create a no-op compute pipeline. // Create a no-op compute pipeline.
@ -1532,7 +1456,8 @@ namespace {
// visible to the programmable pass where it is used. // visible to the programmable pass where it is used.
TEST_F(ResourceUsageTrackingTest, TextureUsageConflictWithInvisibleStageInBindGroup) { TEST_F(ResourceUsageTrackingTest, TextureUsageConflictWithInvisibleStageInBindGroup) {
// Create texture and texture view // Create texture and texture view
wgpu::Texture texture = CreateTexture(wgpu::TextureUsage::StorageBinding | wgpu::Texture texture =
CreateTexture(wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::StorageBinding |
wgpu::TextureUsage::RenderAttachment); wgpu::TextureUsage::RenderAttachment);
wgpu::TextureView view = texture.CreateView(); wgpu::TextureView view = texture.CreateView();
@ -1541,14 +1466,9 @@ namespace {
// Create the render pass that will use the texture as an render attachment // Create the render pass that will use the texture as an render attachment
utils::ComboRenderPassDescriptor renderPass({view}); utils::ComboRenderPassDescriptor renderPass({view});
// Create a bind group which use the texture as readonly storage in compute stage // Create a bind group which use the texture as sampled storage in compute stage
wgpu::BindGroupLayout bgl; wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is device, {{0, wgpu::ShaderStage::Compute, wgpu::TextureSampleType::Float}});
// passed.
EXPECT_DEPRECATION_WARNING(
bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::ReadOnly,
kFormat}}));
wgpu::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, view}}); wgpu::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, view}});
// Texture usage in compute stage in bind group conflicts with render target. And // Texture usage in compute stage in bind group conflicts with render target. And
@ -1564,15 +1484,10 @@ namespace {
// Test compute pass // Test compute pass
{ {
// Create a bind group which contains both fragment and compute stages // Create a bind group which contains both fragment and compute stages
wgpu::BindGroupLayout bgl; wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is device,
// passed. {{0, wgpu::ShaderStage::Fragment, wgpu::TextureSampleType::Float},
EXPECT_DEPRECATION_WARNING( {1, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, kFormat}});
bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::StorageTextureAccess::ReadOnly,
kFormat},
{1, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly,
kFormat}}));
wgpu::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, view}, {1, view}}); wgpu::BindGroup bg = utils::MakeBindGroup(device, bgl, {{0, view}, {1, view}});
// Create a no-op compute pipeline. // Create a no-op compute pipeline.
@ -1595,17 +1510,14 @@ namespace {
// used in the pipeline. // used in the pipeline.
TEST_F(ResourceUsageTrackingTest, TextureUsageConflictWithUnusedPipelineBindings) { TEST_F(ResourceUsageTrackingTest, TextureUsageConflictWithUnusedPipelineBindings) {
// Create texture and texture view // Create texture and texture view
wgpu::Texture texture = CreateTexture(wgpu::TextureUsage::StorageBinding); wgpu::Texture texture =
CreateTexture(wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::StorageBinding);
wgpu::TextureView view = texture.CreateView(); wgpu::TextureView view = texture.CreateView();
// Create bind groups. // Create bind groups.
wgpu::BindGroupLayout readBGL; wgpu::BindGroupLayout readBGL = utils::MakeBindGroupLayout(
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is
// passed.
EXPECT_DEPRECATION_WARNING(
readBGL = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute, device, {{0, wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute,
wgpu::StorageTextureAccess::ReadOnly, kFormat}})); wgpu::TextureSampleType::Float}});
wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout( wgpu::BindGroupLayout writeBGL = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute, device, {{0, wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute,
wgpu::StorageTextureAccess::WriteOnly, kFormat}}); wgpu::StorageTextureAccess::WriteOnly, kFormat}});
@ -1614,14 +1526,14 @@ namespace {
// Test render pass // Test render pass
{ {
// Create a passthrough render pipeline with a readonly storage texture // Create a passthrough render pipeline with a sampled storage texture
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"( wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
[[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> { [[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
return vec4<f32>(); return vec4<f32>();
})"); })");
wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"( wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
[[group(0), binding(0)]] var tex : texture_storage_2d<rgba8unorm, read>; [[group(0), binding(0)]] var tex : texture_2d<f32>;
[[stage(fragment)]] fn main() { [[stage(fragment)]] fn main() {
})"); })");
utils::ComboRenderPipelineDescriptor pipelineDescriptor; utils::ComboRenderPipelineDescriptor pipelineDescriptor;

View File

@ -70,9 +70,6 @@ class StorageTextureValidationTests : public ValidationTest {
const char* imageTypeDeclaration = "texture_storage_2d") { const char* imageTypeDeclaration = "texture_storage_2d") {
const char* access = ""; const char* access = "";
switch (storageTextureBindingType) { switch (storageTextureBindingType) {
case wgpu::StorageTextureAccess::ReadOnly:
access = "read";
break;
case wgpu::StorageTextureAccess::WriteOnly: case wgpu::StorageTextureAccess::WriteOnly:
access = "write"; access = "write";
break; break;
@ -110,61 +107,13 @@ class StorageTextureValidationTests : public ValidationTest {
wgpu::ShaderModule mDefaultVSModule; wgpu::ShaderModule mDefaultVSModule;
wgpu::ShaderModule mDefaultFSModule; wgpu::ShaderModule mDefaultFSModule;
const std::array<wgpu::StorageTextureAccess, 2> kSupportedStorageTextureAccess = { const std::array<wgpu::StorageTextureAccess, 1> kSupportedStorageTextureAccess = {
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is wgpu::StorageTextureAccess::WriteOnly};
// passed.
wgpu::StorageTextureAccess::ReadOnly, wgpu::StorageTextureAccess::WriteOnly};
}; };
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is passed.
#define WARNING_IF_READONLY(statement, access) \
do { \
if (access == wgpu::StorageTextureAccess::ReadOnly) { \
EXPECT_DEPRECATION_WARNING(statement); \
} else { \
statement; \
} \
} while (0)
// Validate read-only storage textures can be declared in vertex and fragment shaders, while // Validate read-only storage textures can be declared in vertex and fragment shaders, while
// writeonly storage textures cannot be used in vertex shaders. // writeonly storage textures cannot be used in vertex shaders.
TEST_F(StorageTextureValidationTests, RenderPipeline) { TEST_F(StorageTextureValidationTests, RenderPipeline) {
// Readonly storage texture can be declared in a vertex shader.
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is passed.
{
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
[[group(0), binding(0)]] var image0 : texture_storage_2d<rgba8unorm, read>;
[[stage(vertex)]] fn main(
[[builtin(vertex_index)]] VertexIndex : u32
) -> [[builtin(position)]] vec4<f32> {
return textureLoad(image0, vec2<i32>(i32(VertexIndex), 0));
})");
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.layout = nullptr;
descriptor.vertex.module = vsModule;
descriptor.cFragment.module = mDefaultFSModule;
EXPECT_DEPRECATION_WARNING(device.CreateRenderPipeline(&descriptor));
}
// Read-only storage textures can be declared in a fragment shader.
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is passed.
{
wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
[[group(0), binding(0)]] var image0 : texture_storage_2d<rgba8unorm, read>;
[[stage(fragment)]] fn main(
[[builtin(position)]] FragCoord : vec4<f32>
) -> [[location(0)]] vec4<f32> {
return textureLoad(image0, vec2<i32>(FragCoord.xy));
})");
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.layout = nullptr;
descriptor.vertex.module = mDefaultVSModule;
descriptor.cFragment.module = fsModule;
EXPECT_DEPRECATION_WARNING(device.CreateRenderPipeline(&descriptor));
}
// Write-only storage textures cannot be declared in a vertex shader. // Write-only storage textures cannot be declared in a vertex shader.
{ {
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"( wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
@ -202,29 +151,6 @@ TEST_F(StorageTextureValidationTests, RenderPipeline) {
// Validate both read-only and write-only storage textures can be declared in // Validate both read-only and write-only storage textures can be declared in
// compute shaders. // compute shaders.
TEST_F(StorageTextureValidationTests, ComputePipeline) { TEST_F(StorageTextureValidationTests, ComputePipeline) {
// Read-only storage textures can be declared in a compute shader.
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is passed.
{
wgpu::ShaderModule csModule = utils::CreateShaderModule(device, R"(
[[group(0), binding(0)]] var image0 : texture_storage_2d<rgba8unorm, read>;
[[block]] struct Buf {
data : f32;
};
[[group(0), binding(1)]] var<storage, read_write> buf : Buf;
[[stage(compute), workgroup_size(1)]] fn main([[builtin(local_invocation_id)]] LocalInvocationID : vec3<u32>) {
buf.data = textureLoad(image0, vec2<i32>(LocalInvocationID.xy)).x;
})");
wgpu::ComputePipelineDescriptor descriptor;
descriptor.layout = nullptr;
descriptor.compute.module = csModule;
descriptor.compute.entryPoint = "main";
EXPECT_DEPRECATION_WARNING(device.CreateComputePipeline(&descriptor));
}
// Write-only storage textures can be declared in a compute shader. // Write-only storage textures can be declared in a compute shader.
{ {
wgpu::ShaderModule csModule = utils::CreateShaderModule(device, R"( wgpu::ShaderModule csModule = utils::CreateShaderModule(device, R"(
@ -282,11 +208,8 @@ TEST_F(StorageTextureValidationTests, BindGroupLayoutWithStorageTextureBindingTy
bool valid; bool valid;
}; };
constexpr std::array<TestSpec, 6> kTestSpecs = { constexpr std::array<TestSpec, 6> kTestSpecs = {
{{wgpu::ShaderStage::Vertex, wgpu::StorageTextureAccess::ReadOnly, true}, {{wgpu::ShaderStage::Vertex, wgpu::StorageTextureAccess::WriteOnly, false},
{wgpu::ShaderStage::Vertex, wgpu::StorageTextureAccess::WriteOnly, false},
{wgpu::ShaderStage::Fragment, wgpu::StorageTextureAccess::ReadOnly, true},
{wgpu::ShaderStage::Fragment, wgpu::StorageTextureAccess::WriteOnly, true}, {wgpu::ShaderStage::Fragment, wgpu::StorageTextureAccess::WriteOnly, true},
{wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::ReadOnly, true},
{wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, true}}}; {wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, true}}};
for (const auto& testSpec : kTestSpecs) { for (const auto& testSpec : kTestSpecs) {
@ -298,10 +221,9 @@ TEST_F(StorageTextureValidationTests, BindGroupLayoutWithStorageTextureBindingTy
descriptor.entries = &entry; descriptor.entries = &entry;
if (testSpec.valid) { if (testSpec.valid) {
WARNING_IF_READONLY(device.CreateBindGroupLayout(&descriptor), testSpec.type); device.CreateBindGroupLayout(&descriptor);
} else { } else {
WARNING_IF_READONLY(ASSERT_DEVICE_ERROR(device.CreateBindGroupLayout(&descriptor)), ASSERT_DEVICE_ERROR(device.CreateBindGroupLayout(&descriptor));
testSpec.type);
} }
} }
} }
@ -409,8 +331,6 @@ TEST_F(StorageTextureValidationTests, BindGroupLayoutEntryTypeMatchesShaderDecla
{0, wgpu::ShaderStage::Compute, wgpu::BufferBindingType::ReadOnlyStorage}, {0, wgpu::ShaderStage::Compute, wgpu::BufferBindingType::ReadOnlyStorage},
{0, wgpu::ShaderStage::Compute, wgpu::SamplerBindingType::Filtering}, {0, wgpu::ShaderStage::Compute, wgpu::SamplerBindingType::Filtering},
{0, wgpu::ShaderStage::Compute, wgpu::TextureSampleType::Float}, {0, wgpu::ShaderStage::Compute, wgpu::TextureSampleType::Float},
{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::ReadOnly,
kStorageTextureFormat},
{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, {0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly,
kStorageTextureFormat}}; kStorageTextureFormat}};
@ -431,10 +351,8 @@ TEST_F(StorageTextureValidationTests, BindGroupLayoutEntryTypeMatchesShaderDecla
defaultComputePipelineDescriptor; defaultComputePipelineDescriptor;
// Create bind group layout with different binding types. // Create bind group layout with different binding types.
wgpu::BindGroupLayout bindGroupLayout; wgpu::BindGroupLayout bindGroupLayout =
WARNING_IF_READONLY( utils::MakeBindGroupLayout(device, {bindingLayoutEntry});
bindGroupLayout = utils::MakeBindGroupLayout(device, {bindingLayoutEntry}),
bindingLayoutEntry.storageTexture.access);
computePipelineDescriptor.layout = computePipelineDescriptor.layout =
utils::MakeBasicPipelineLayout(device, &bindGroupLayout); utils::MakeBasicPipelineLayout(device, &bindGroupLayout);
@ -476,8 +394,7 @@ TEST_F(StorageTextureValidationTests, StorageTextureFormatInBindGroupLayout) {
bindGroupLayoutBinding.storageTexture.access = bindingType; bindGroupLayoutBinding.storageTexture.access = bindingType;
bindGroupLayoutBinding.storageTexture.format = textureFormat; bindGroupLayoutBinding.storageTexture.format = textureFormat;
if (utils::TextureFormatSupportsStorageTexture(textureFormat)) { if (utils::TextureFormatSupportsStorageTexture(textureFormat)) {
WARNING_IF_READONLY(utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding}), utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding});
bindingType);
} else { } else {
ASSERT_DEVICE_ERROR(utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding})); ASSERT_DEVICE_ERROR(utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding}));
} }
@ -519,10 +436,8 @@ TEST_F(StorageTextureValidationTests, BindGroupLayoutStorageTextureFormatMatches
wgpu::BindGroupLayoutEntry bindGroupLayoutBinding = defaultBindGroupLayoutEntry; wgpu::BindGroupLayoutEntry bindGroupLayoutBinding = defaultBindGroupLayoutEntry;
bindGroupLayoutBinding.storageTexture.format = bindGroupLayoutBinding.storageTexture.format =
storageTextureFormatInBindGroupLayout; storageTextureFormatInBindGroupLayout;
wgpu::BindGroupLayout bindGroupLayout; wgpu::BindGroupLayout bindGroupLayout =
WARNING_IF_READONLY( utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding});
bindGroupLayout = utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding}),
bindingType);
// Create the compute pipeline with the bind group layout. // Create the compute pipeline with the bind group layout.
wgpu::ComputePipelineDescriptor computePipelineDescriptor = wgpu::ComputePipelineDescriptor computePipelineDescriptor =
@ -570,10 +485,8 @@ TEST_F(StorageTextureValidationTests, BindGroupLayoutViewDimensionMatchesShaderD
// Create the bind group layout with the given texture view dimension. // Create the bind group layout with the given texture view dimension.
wgpu::BindGroupLayoutEntry bindGroupLayoutBinding = defaultBindGroupLayoutEntry; wgpu::BindGroupLayoutEntry bindGroupLayoutBinding = defaultBindGroupLayoutEntry;
bindGroupLayoutBinding.storageTexture.viewDimension = dimensionInBindGroupLayout; bindGroupLayoutBinding.storageTexture.viewDimension = dimensionInBindGroupLayout;
wgpu::BindGroupLayout bindGroupLayout; wgpu::BindGroupLayout bindGroupLayout =
WARNING_IF_READONLY( utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding});
bindGroupLayout = utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding}),
bindingType);
// Create the compute pipeline with the bind group layout. // Create the compute pipeline with the bind group layout.
wgpu::ComputePipelineDescriptor computePipelineDescriptor = wgpu::ComputePipelineDescriptor computePipelineDescriptor =
@ -604,10 +517,8 @@ TEST_F(StorageTextureValidationTests, StorageTextureBindingTypeInBindGroup) {
bindGroupLayoutBinding.visibility = wgpu::ShaderStage::Compute; bindGroupLayoutBinding.visibility = wgpu::ShaderStage::Compute;
bindGroupLayoutBinding.storageTexture.access = storageBindingType; bindGroupLayoutBinding.storageTexture.access = storageBindingType;
bindGroupLayoutBinding.storageTexture.format = kStorageTextureFormat; bindGroupLayoutBinding.storageTexture.format = kStorageTextureFormat;
wgpu::BindGroupLayout bindGroupLayout; wgpu::BindGroupLayout bindGroupLayout =
WARNING_IF_READONLY( utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding});
bindGroupLayout = utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding}),
storageBindingType);
// Buffers are not allowed to be used as storage textures in a bind group. // Buffers are not allowed to be used as storage textures in a bind group.
{ {
@ -650,10 +561,8 @@ TEST_F(StorageTextureValidationTests, StorageTextureUsageInBindGroup) {
bindGroupLayoutBinding.visibility = wgpu::ShaderStage::Compute; bindGroupLayoutBinding.visibility = wgpu::ShaderStage::Compute;
bindGroupLayoutBinding.storageTexture.access = storageBindingType; bindGroupLayoutBinding.storageTexture.access = storageBindingType;
bindGroupLayoutBinding.storageTexture.format = wgpu::TextureFormat::R32Float; bindGroupLayoutBinding.storageTexture.format = wgpu::TextureFormat::R32Float;
wgpu::BindGroupLayout bindGroupLayout; wgpu::BindGroupLayout bindGroupLayout =
WARNING_IF_READONLY( utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding});
bindGroupLayout = utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding}),
storageBindingType);
for (wgpu::TextureUsage usage : kTextureUsages) { for (wgpu::TextureUsage usage : kTextureUsages) {
// Create texture views with different texture usages // Create texture views with different texture usages
@ -689,10 +598,8 @@ TEST_F(StorageTextureValidationTests, StorageTextureFormatInBindGroup) {
// Create a bind group layout with given storage texture format. // Create a bind group layout with given storage texture format.
wgpu::BindGroupLayoutEntry bindGroupLayoutBinding = defaultBindGroupLayoutEntry; wgpu::BindGroupLayoutEntry bindGroupLayoutBinding = defaultBindGroupLayoutEntry;
bindGroupLayoutBinding.storageTexture.format = formatInBindGroupLayout; bindGroupLayoutBinding.storageTexture.format = formatInBindGroupLayout;
wgpu::BindGroupLayout bindGroupLayout; wgpu::BindGroupLayout bindGroupLayout =
WARNING_IF_READONLY( utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding});
bindGroupLayout = utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding}),
storageBindingType);
for (wgpu::TextureFormat textureViewFormat : utils::kAllTextureFormats) { for (wgpu::TextureFormat textureViewFormat : utils::kAllTextureFormats) {
if (!utils::TextureFormatSupportsStorageTexture(textureViewFormat)) { if (!utils::TextureFormatSupportsStorageTexture(textureViewFormat)) {
@ -747,10 +654,8 @@ TEST_F(StorageTextureValidationTests, StorageTextureViewDimensionInBindGroup) {
// Create a bind group layout with given texture view dimension. // Create a bind group layout with given texture view dimension.
wgpu::BindGroupLayoutEntry bindGroupLayoutBinding = defaultBindGroupLayoutEntry; wgpu::BindGroupLayoutEntry bindGroupLayoutBinding = defaultBindGroupLayoutEntry;
bindGroupLayoutBinding.storageTexture.viewDimension = dimensionInBindGroupLayout; bindGroupLayoutBinding.storageTexture.viewDimension = dimensionInBindGroupLayout;
wgpu::BindGroupLayout bindGroupLayout; wgpu::BindGroupLayout bindGroupLayout =
WARNING_IF_READONLY( utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding});
bindGroupLayout = utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding}),
storageBindingType);
for (wgpu::TextureViewDimension dimensionOfTextureView : kSupportedDimensions) { for (wgpu::TextureViewDimension dimensionOfTextureView : kSupportedDimensions) {
// Create a texture view with given texture view dimension. // Create a texture view with given texture view dimension.
@ -796,11 +701,8 @@ TEST_F(StorageTextureValidationTests, StorageTextureInRenderPass) {
for (wgpu::StorageTextureAccess storageTextureType : kSupportedStorageTextureAccess) { for (wgpu::StorageTextureAccess storageTextureType : kSupportedStorageTextureAccess) {
// Create a bind group that contains a storage texture. // Create a bind group that contains a storage texture.
wgpu::BindGroupLayout bindGroupLayout; wgpu::BindGroupLayout bindGroupLayout = utils::MakeBindGroupLayout(
WARNING_IF_READONLY( device, {{0, wgpu::ShaderStage::Fragment, storageTextureType, kFormat}});
bindGroupLayout = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, storageTextureType, kFormat}}),
storageTextureType);
wgpu::BindGroup bindGroupWithStorageTexture = wgpu::BindGroup bindGroupWithStorageTexture =
utils::MakeBindGroup(device, bindGroupLayout, {{0, storageTexture.CreateView()}}); utils::MakeBindGroup(device, bindGroupLayout, {{0, storageTexture.CreateView()}});
@ -830,12 +732,9 @@ TEST_F(StorageTextureValidationTests, StorageTextureAndSampledTextureInOneRender
for (wgpu::StorageTextureAccess storageTextureType : kSupportedStorageTextureAccess) { for (wgpu::StorageTextureAccess storageTextureType : kSupportedStorageTextureAccess) {
// Create a bind group that binds the same texture as both storage texture and sampled // Create a bind group that binds the same texture as both storage texture and sampled
// texture. // texture.
wgpu::BindGroupLayout bindGroupLayout; wgpu::BindGroupLayout bindGroupLayout = utils::MakeBindGroupLayout(
WARNING_IF_READONLY(
bindGroupLayout = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, storageTextureType, kFormat}, device, {{0, wgpu::ShaderStage::Fragment, storageTextureType, kFormat},
{1, wgpu::ShaderStage::Fragment, wgpu::TextureSampleType::Float}}), {1, wgpu::ShaderStage::Fragment, wgpu::TextureSampleType::Float}});
storageTextureType);
wgpu::BindGroup bindGroup = utils::MakeBindGroup( wgpu::BindGroup bindGroup = utils::MakeBindGroup(
device, bindGroupLayout, device, bindGroupLayout,
{{0, storageTexture.CreateView()}, {1, storageTexture.CreateView()}}); {{0, storageTexture.CreateView()}, {1, storageTexture.CreateView()}});
@ -848,9 +747,6 @@ TEST_F(StorageTextureValidationTests, StorageTextureAndSampledTextureInOneRender
renderPassEncoder.SetBindGroup(0, bindGroup); renderPassEncoder.SetBindGroup(0, bindGroup);
renderPassEncoder.EndPass(); renderPassEncoder.EndPass();
switch (storageTextureType) { switch (storageTextureType) {
case wgpu::StorageTextureAccess::ReadOnly:
encoder.Finish();
break;
case wgpu::StorageTextureAccess::WriteOnly: case wgpu::StorageTextureAccess::WriteOnly:
ASSERT_DEVICE_ERROR(encoder.Finish()); ASSERT_DEVICE_ERROR(encoder.Finish());
break; break;
@ -871,11 +767,8 @@ TEST_F(StorageTextureValidationTests, StorageTextureAndRenderAttachmentInOneRend
for (wgpu::StorageTextureAccess storageTextureType : kSupportedStorageTextureAccess) { for (wgpu::StorageTextureAccess storageTextureType : kSupportedStorageTextureAccess) {
// Create a bind group that contains a storage texture. // Create a bind group that contains a storage texture.
wgpu::BindGroupLayout bindGroupLayout; wgpu::BindGroupLayout bindGroupLayout = utils::MakeBindGroupLayout(
WARNING_IF_READONLY( device, {{0, wgpu::ShaderStage::Fragment, storageTextureType, kFormat}});
bindGroupLayout = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, storageTextureType, kFormat}}),
storageTextureType);
wgpu::BindGroup bindGroupWithStorageTexture = wgpu::BindGroup bindGroupWithStorageTexture =
utils::MakeBindGroup(device, bindGroupLayout, {{0, storageTexture.CreateView()}}); utils::MakeBindGroup(device, bindGroupLayout, {{0, storageTexture.CreateView()}});
@ -889,36 +782,6 @@ TEST_F(StorageTextureValidationTests, StorageTextureAndRenderAttachmentInOneRend
} }
} }
// Verify it is invalid to use a a texture as both read-only storage texture and write-only storage
// texture in one render pass.
TEST_F(StorageTextureValidationTests, ReadOnlyAndWriteOnlyStorageTextureInOneRenderPass) {
constexpr wgpu::TextureFormat kFormat = wgpu::TextureFormat::RGBA8Unorm;
wgpu::Texture storageTexture = CreateTexture(wgpu::TextureUsage::StorageBinding, kFormat);
// Create a bind group that uses the same texture as both read-only and write-only storage
// texture.
wgpu::BindGroupLayout bindGroupLayout;
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is passed.
EXPECT_DEPRECATION_WARNING(
bindGroupLayout = utils::MakeBindGroupLayout(
device,
{{0, wgpu::ShaderStage::Fragment, wgpu::StorageTextureAccess::ReadOnly, kFormat},
{1, wgpu::ShaderStage::Fragment, wgpu::StorageTextureAccess::WriteOnly, kFormat}}));
wgpu::BindGroup bindGroup =
utils::MakeBindGroup(device, bindGroupLayout,
{{0, storageTexture.CreateView()}, {1, storageTexture.CreateView()}});
// It is invalid to use a texture as both read-only storage texture and write-only storage
// texture in one render pass.
wgpu::Texture outputAttachment = CreateTexture(wgpu::TextureUsage::RenderAttachment, kFormat);
utils::ComboRenderPassDescriptor renderPassDescriptor({outputAttachment.CreateView()});
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder renderPassEncoder = encoder.BeginRenderPass(&renderPassDescriptor);
renderPassEncoder.SetBindGroup(0, bindGroup);
renderPassEncoder.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Verify it is valid to use a texture as both storage texture (read-only or write-only) and // Verify it is valid to use a texture as both storage texture (read-only or write-only) and
// sampled texture in one compute pass. // sampled texture in one compute pass.
TEST_F(StorageTextureValidationTests, StorageTextureAndSampledTextureInOneComputePass) { TEST_F(StorageTextureValidationTests, StorageTextureAndSampledTextureInOneComputePass) {
@ -929,12 +792,9 @@ TEST_F(StorageTextureValidationTests, StorageTextureAndSampledTextureInOneComput
for (wgpu::StorageTextureAccess storageTextureType : kSupportedStorageTextureAccess) { for (wgpu::StorageTextureAccess storageTextureType : kSupportedStorageTextureAccess) {
// Create a bind group that binds the same texture as both storage texture and sampled // Create a bind group that binds the same texture as both storage texture and sampled
// texture. // texture.
wgpu::BindGroupLayout bindGroupLayout; wgpu::BindGroupLayout bindGroupLayout = utils::MakeBindGroupLayout(
WARNING_IF_READONLY(
bindGroupLayout = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Compute, storageTextureType, kFormat}, device, {{0, wgpu::ShaderStage::Compute, storageTextureType, kFormat},
{1, wgpu::ShaderStage::Compute, wgpu::TextureSampleType::Float}}), {1, wgpu::ShaderStage::Compute, wgpu::TextureSampleType::Float}});
storageTextureType);
wgpu::BindGroup bindGroup = utils::MakeBindGroup( wgpu::BindGroup bindGroup = utils::MakeBindGroup(
device, bindGroupLayout, device, bindGroupLayout,
{{0, storageTexture.CreateView()}, {1, storageTexture.CreateView()}}); {{0, storageTexture.CreateView()}, {1, storageTexture.CreateView()}});
@ -948,31 +808,3 @@ TEST_F(StorageTextureValidationTests, StorageTextureAndSampledTextureInOneComput
encoder.Finish(); encoder.Finish();
} }
} }
// Verify it is valid to use a texture as both read-only storage texture and write-only storage
// texture in one compute pass.
TEST_F(StorageTextureValidationTests, ReadOnlyAndWriteOnlyStorageTextureInOneComputePass) {
constexpr wgpu::TextureFormat kFormat = wgpu::TextureFormat::RGBA8Unorm;
wgpu::Texture storageTexture = CreateTexture(wgpu::TextureUsage::StorageBinding, kFormat);
// Create a bind group that uses the same texture as both read-only and write-only storage
// texture.
wgpu::BindGroupLayout bindGroupLayout;
// TODO(crbug.com/dawn/1025): Remove once ReadOnly storage texture deprecation period is passed.
EXPECT_DEPRECATION_WARNING(
bindGroupLayout = utils::MakeBindGroupLayout(
device,
{{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::ReadOnly, kFormat},
{1, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly, kFormat}}));
wgpu::BindGroup bindGroup =
utils::MakeBindGroup(device, bindGroupLayout,
{{0, storageTexture.CreateView()}, {1, storageTexture.CreateView()}});
// It is valid to use a texture as both read-only storage texture and write-only storage
// texture in one compute pass.
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder computePassEncoder = encoder.BeginComputePass();
computePassEncoder.SetBindGroup(0, bindGroup);
computePassEncoder.EndPass();
encoder.Finish();
}

View File

@ -67,26 +67,8 @@ namespace {
encoder.Finish(); encoder.Finish();
} }
// It is valid to has multiple read from a subresource and one single write into another // It is not currently possible to test that it is valid to have multiple reads from a
// subresource // subresource while there is a single write in another subresource.
{
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, samplerView}});
wgpu::BindGroupLayout bgl1;
EXPECT_DEPRECATION_WARNING(
bgl1 = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment,
wgpu::StorageTextureAccess::ReadOnly, kFormat}}));
wgpu::BindGroup bindGroup1 = utils::MakeBindGroup(device, bgl1, {{0, samplerView}});
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassDesc);
pass.SetBindGroup(0, bindGroup);
pass.SetBindGroup(1, bindGroup1);
pass.EndPass();
encoder.Finish();
}
// It is invalid to read and write into the same subresources // It is invalid to read and write into the same subresources
{ {

View File

@ -37,18 +37,6 @@ TEST_P(InternalResourceUsageTests, InternalBufferUsage) {
ASSERT_DEVICE_ERROR(CreateBuffer(dawn_native::kInternalStorageBuffer)); ASSERT_DEVICE_ERROR(CreateBuffer(dawn_native::kInternalStorageBuffer));
} }
// Verify it is an error to create a texture with a texture usage that should only be used
// internally.
TEST_P(InternalResourceUsageTests, InternalTextureUsage) {
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("skip_validation"));
wgpu::TextureDescriptor descriptor;
descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
descriptor.size = {1, 1, 1};
descriptor.usage = dawn_native::kReadOnlyStorageTexture;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
DAWN_INSTANTIATE_TEST(InternalResourceUsageTests, NullBackend()); DAWN_INSTANTIATE_TEST(InternalResourceUsageTests, NullBackend());
class InternalBindingTypeTests : public DawnTest {}; class InternalBindingTypeTests : public DawnTest {};