Convert StorageTextureValidationTests to WGSL
Bug: tint:140 Bug: tint:368 Change-Id: I6593e40db5db4058bf6fdf3303ec7e99c0a3df12 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/37900 Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
2231fcda56
commit
88f7f580bc
|
@ -35,20 +35,21 @@ class StorageTextureValidationTests : public ValidationTest {
|
|||
})");
|
||||
}
|
||||
|
||||
static const char* GetGLSLFloatImageTypeDeclaration(wgpu::TextureViewDimension dimension) {
|
||||
static const char* GetFloatImageTypeDeclaration(wgpu::TextureViewDimension dimension) {
|
||||
// TODO(bclayton): Support and test texture_storage_1d_array
|
||||
switch (dimension) {
|
||||
case wgpu::TextureViewDimension::e1D:
|
||||
return "image1D";
|
||||
return "texture_storage_1d";
|
||||
case wgpu::TextureViewDimension::e2D:
|
||||
return "image2D";
|
||||
return "texture_storage_2d";
|
||||
case wgpu::TextureViewDimension::e2DArray:
|
||||
return "image2DArray";
|
||||
case wgpu::TextureViewDimension::Cube:
|
||||
return "imageCube";
|
||||
case wgpu::TextureViewDimension::CubeArray:
|
||||
return "imageCubeArray";
|
||||
return "texture_storage_2d_array";
|
||||
case wgpu::TextureViewDimension::e3D:
|
||||
return "image3D";
|
||||
return "texture_storage_3d";
|
||||
case wgpu::TextureViewDimension::Cube:
|
||||
return "texture_storage_cube"; // Note: Doesn't exist in WGSL (yet)
|
||||
case wgpu::TextureViewDimension::CubeArray:
|
||||
return "texture_storage_cube_array"; // Note: Doesn't exist in WGSL (yet)
|
||||
case wgpu::TextureViewDimension::Undefined:
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
@ -60,26 +61,22 @@ class StorageTextureValidationTests : public ValidationTest {
|
|||
wgpu::StorageTextureAccess storageTextureBindingType,
|
||||
wgpu::TextureFormat textureFormat,
|
||||
wgpu::TextureViewDimension textureViewDimension = wgpu::TextureViewDimension::e2D) {
|
||||
const char* glslImageFormatQualifier = utils::GetGLSLImageFormatQualifier(textureFormat);
|
||||
const char* textureComponentTypePrefix =
|
||||
utils::GetColorTextureComponentGLSLTypePrefix(textureFormat);
|
||||
return CreateComputeShaderWithStorageTexture(
|
||||
storageTextureBindingType, glslImageFormatQualifier, textureComponentTypePrefix,
|
||||
GetGLSLFloatImageTypeDeclaration(textureViewDimension));
|
||||
storageTextureBindingType, utils::GetWGSLImageFormatQualifier(textureFormat),
|
||||
GetFloatImageTypeDeclaration(textureViewDimension));
|
||||
}
|
||||
|
||||
static std::string CreateComputeShaderWithStorageTexture(
|
||||
wgpu::StorageTextureAccess storageTextureBindingType,
|
||||
const char* glslImageFormatQualifier,
|
||||
const char* textureComponentTypePrefix,
|
||||
const char* glslImageTypeDeclaration = "image2D") {
|
||||
const char* memoryQualifier = "";
|
||||
const char* imageFormatQualifier,
|
||||
const char* imageTypeDeclaration = "texture_storage_2d") {
|
||||
const char* access = "";
|
||||
switch (storageTextureBindingType) {
|
||||
case wgpu::StorageTextureAccess::ReadOnly:
|
||||
memoryQualifier = "readonly";
|
||||
access = "read";
|
||||
break;
|
||||
case wgpu::StorageTextureAccess::WriteOnly:
|
||||
memoryQualifier = "writeonly";
|
||||
access = "write";
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
@ -87,12 +84,11 @@ class StorageTextureValidationTests : public ValidationTest {
|
|||
}
|
||||
|
||||
std::ostringstream ostream;
|
||||
ostream << "#version 450\n"
|
||||
"layout (set = 0, binding = 0, "
|
||||
<< glslImageFormatQualifier << ") uniform " << memoryQualifier << " "
|
||||
<< textureComponentTypePrefix << glslImageTypeDeclaration
|
||||
<< " image0;\n"
|
||||
"void main() {\n"
|
||||
ostream << "[[group(0), binding(0)]] var<uniform_constant> image0 : "
|
||||
<< "[[access(" << access << ")]] " << imageTypeDeclaration << "<"
|
||||
<< imageFormatQualifier
|
||||
<< ">;\n"
|
||||
"[[stage(compute)]] fn main() -> void {\n"
|
||||
"}\n";
|
||||
|
||||
return ostream.str();
|
||||
|
@ -126,7 +122,7 @@ TEST_F(StorageTextureValidationTests, RenderPipeline) {
|
|||
{
|
||||
wgpu::ShaderModule vsModule = utils::CreateShaderModuleFromWGSL(device, R"(
|
||||
[[group(0), binding(0)]] var<uniform_constant> image0 : [[access(read)]] texture_storage_2d<rgba8unorm>;
|
||||
[[builtin(vertex_idx)]] var<in> VertexIndex : u32;
|
||||
[[builtin(vertex_index)]] var<in> VertexIndex : u32;
|
||||
[[builtin(position)]] var<out> Position : vec4<f32>;
|
||||
[[stage(vertex)]] fn main() -> void {
|
||||
Position = textureLoad(image0, vec2<i32>(i32(VertexIndex), 0));
|
||||
|
@ -157,13 +153,12 @@ TEST_F(StorageTextureValidationTests, RenderPipeline) {
|
|||
}
|
||||
|
||||
// Write-only storage textures cannot be declared in a vertex shader.
|
||||
{
|
||||
wgpu::ShaderModule vsModule =
|
||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
|
||||
#version 450
|
||||
layout(set = 0, binding = 0, rgba8) uniform writeonly image2D image0;
|
||||
void main() {
|
||||
imageStore(image0, ivec2(gl_VertexIndex, 0), vec4(1.f, 0.f, 0.f, 1.f));
|
||||
if ((false) /* TODO(https://crbug.com/tint/449) */) {
|
||||
wgpu::ShaderModule vsModule = utils::CreateShaderModuleFromWGSL(device, R"(
|
||||
[[builtin(vertex_index)]] var<in> vertex_index : u32;
|
||||
[[group(0), binding(0)]] var<uniform_constant> image0 : [[access(write)]] texture_storage_2d<rgba8unorm>;
|
||||
[[stage(vertex)]] fn main() -> void {
|
||||
textureStore(image0, vec2<i32>(i32(vertex_index), 0), vec4<f32>(1.0, 0.0, 0.0, 1.0));
|
||||
})");
|
||||
|
||||
utils::ComboRenderPipelineDescriptor descriptor(device);
|
||||
|
@ -175,12 +170,11 @@ TEST_F(StorageTextureValidationTests, RenderPipeline) {
|
|||
|
||||
// Write-only storage textures can be declared in a fragment shader.
|
||||
{
|
||||
wgpu::ShaderModule fsModule =
|
||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
|
||||
#version 450
|
||||
layout(set = 0, binding = 0, rgba8) uniform writeonly image2D image0;
|
||||
void main() {
|
||||
imageStore(image0, ivec2(gl_FragCoord.xy), vec4(1.f, 0.f, 0.f, 1.f));
|
||||
wgpu::ShaderModule fsModule = utils::CreateShaderModuleFromWGSL(device, R"(
|
||||
[[builtin(frag_coord)]] var<in> frag_coord : vec4<f32>;
|
||||
[[group(0), binding(0)]] var<uniform_constant> image0 : [[access(write)]] texture_storage_2d<rgba8unorm>;
|
||||
[[stage(fragment)]] fn main() -> void {
|
||||
textureStore(image0, vec2<i32>(frag_coord.xy), vec4<f32>(1.0, 0.0, 0.0, 1.0));
|
||||
})");
|
||||
|
||||
utils::ComboRenderPipelineDescriptor descriptor(device);
|
||||
|
@ -219,12 +213,12 @@ TEST_F(StorageTextureValidationTests, ComputePipeline) {
|
|||
|
||||
// Write-only storage textures can be declared in a compute shader.
|
||||
{
|
||||
wgpu::ShaderModule csModule =
|
||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
|
||||
#version 450
|
||||
layout(set = 0, binding = 0, rgba8) uniform writeonly image2D image0;
|
||||
void main() {
|
||||
imageStore(image0, ivec2(gl_LocalInvocationID.xy), vec4(0.f, 0.f, 0.f, 0.f));
|
||||
wgpu::ShaderModule csModule = utils::CreateShaderModuleFromWGSL(device, R"(
|
||||
[[group(0), binding(0)]] var<uniform_constant> image0 : [[access(write)]] texture_storage_2d<rgba8unorm>;
|
||||
[[builtin(local_invocation_id)]] var<in> LocalInvocationID : vec3<u32>;
|
||||
|
||||
[[stage(compute)]] fn main() -> void {
|
||||
textureStore(image0, vec2<i32>(LocalInvocationID.xy), vec4<f32>(0.0, 0.0, 0.0, 0.0));
|
||||
})");
|
||||
|
||||
wgpu::ComputePipelineDescriptor descriptor;
|
||||
|
@ -236,40 +230,29 @@ TEST_F(StorageTextureValidationTests, ComputePipeline) {
|
|||
}
|
||||
}
|
||||
|
||||
// Validate read-write storage textures have not been supported yet.
|
||||
// TODO(cwallez@chromium.org): Convert them to SPIRV ASM to remove the dependency on glslang.
|
||||
// Validate read-write storage textures are not currently supported.
|
||||
TEST_F(StorageTextureValidationTests, ReadWriteStorageTexture) {
|
||||
// Read-write storage textures cannot be declared in a vertex shader by default.
|
||||
{
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
|
||||
#version 450
|
||||
layout(set = 0, binding = 0, rgba8) uniform image2D image0;
|
||||
void main() {
|
||||
vec4 pixel = imageLoad(image0, ivec2(gl_VertexIndex, 0));
|
||||
imageStore(image0, ivec2(gl_VertexIndex, 0), pixel * 2);
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModuleFromWGSL(device, R"(
|
||||
[[group(0), binding(0)]] var<uniform_constant> image0 : [[access(read_write)]] texture_storage_2d<rgba8unorm>;
|
||||
[[stage(vertex)]] fn main() -> void {
|
||||
})"));
|
||||
}
|
||||
|
||||
// Read-write storage textures cannot be declared in a fragment shader by default.
|
||||
{
|
||||
ASSERT_DEVICE_ERROR(
|
||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
|
||||
#version 450
|
||||
layout(set = 0, binding = 0, rgba8) uniform image2D image0;
|
||||
void main() {
|
||||
vec4 pixel = imageLoad(image0, ivec2(gl_FragCoord.xy));
|
||||
imageStore(image0, ivec2(gl_FragCoord.xy), pixel * 2);
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModuleFromWGSL(device, R"(
|
||||
[[group(0), binding(0)]] var<uniform_constant> image0 : [[access(read_write)]] texture_storage_2d<rgba8unorm>;
|
||||
[[stage(fragment)]] fn main() -> void {
|
||||
})"));
|
||||
}
|
||||
|
||||
// Read-write storage textures cannot be declared in a compute shader by default.
|
||||
{
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
|
||||
#version 450
|
||||
layout(set = 0, binding = 0, rgba8) uniform image2D image0;
|
||||
void main() {
|
||||
vec4 pixel = imageLoad(image0, ivec2(gl_LocalInvocationID.xy));
|
||||
imageStore(image0, ivec2(gl_LocalInvocationID.xy), pixel * 2);
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModuleFromWGSL(device, R"(
|
||||
[[group(0), binding(0)]] var<uniform_constant> image0 : [[access(read_write)]] texture_storage_2d<rgba8unorm>;
|
||||
[[stage(compute)]] fn main() -> void {
|
||||
})"));
|
||||
}
|
||||
}
|
||||
|
@ -334,11 +317,10 @@ TEST_F(StorageTextureValidationTests, StorageTextureFormatInShaders) {
|
|||
std::string computeShader =
|
||||
CreateComputeShaderWithStorageTexture(storageTextureBindingType, format);
|
||||
if (utils::TextureFormatSupportsStorageTexture(format)) {
|
||||
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute,
|
||||
computeShader.c_str());
|
||||
utils::CreateShaderModuleFromWGSL(device, computeShader.c_str());
|
||||
} else {
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(
|
||||
device, utils::SingleShaderStage::Compute, computeShader.c_str()));
|
||||
ASSERT_DEVICE_ERROR(
|
||||
utils::CreateShaderModuleFromWGSL(device, computeShader.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -346,33 +328,29 @@ TEST_F(StorageTextureValidationTests, StorageTextureFormatInShaders) {
|
|||
|
||||
// Verify that declaring a storage texture format that is not supported in WebGPU causes validation
|
||||
// error.
|
||||
TEST_F(StorageTextureValidationTests, UnsupportedSPIRVStorageTextureFormat) {
|
||||
struct TextureFormatInfo {
|
||||
const char* name;
|
||||
const char* componentTypePrefix;
|
||||
TEST_F(StorageTextureValidationTests, UnsupportedWGSLStorageTextureFormat) {
|
||||
constexpr std::array<wgpu::TextureFormat, 16> kUnsupportedTextureFormats = {
|
||||
wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::R8Snorm,
|
||||
wgpu::TextureFormat::R8Uint, wgpu::TextureFormat::R8Sint,
|
||||
wgpu::TextureFormat::R16Uint, wgpu::TextureFormat::R16Sint,
|
||||
wgpu::TextureFormat::R16Float, wgpu::TextureFormat::RG8Unorm,
|
||||
wgpu::TextureFormat::RG8Snorm, wgpu::TextureFormat::RG8Uint,
|
||||
wgpu::TextureFormat::RG8Sint, wgpu::TextureFormat::RG16Uint,
|
||||
wgpu::TextureFormat::RG16Sint, wgpu::TextureFormat::RG16Float,
|
||||
wgpu::TextureFormat::RGB10A2Unorm, wgpu::TextureFormat::RG11B10Ufloat,
|
||||
};
|
||||
|
||||
constexpr std::array<TextureFormatInfo, 7> kUnsupportedTextureFormats = {{{"rgba16", ""},
|
||||
{"rg16", ""},
|
||||
{"r16", ""},
|
||||
{"rgba16_snorm", ""},
|
||||
{"rg16_snorm", ""},
|
||||
{"r16_snorm", ""},
|
||||
{"rgb10_a2ui", "u"}}};
|
||||
|
||||
for (wgpu::StorageTextureAccess bindingType : kSupportedStorageTextureAccess) {
|
||||
for (const TextureFormatInfo& formatInfo : kUnsupportedTextureFormats) {
|
||||
std::string computeShader = CreateComputeShaderWithStorageTexture(
|
||||
bindingType, formatInfo.name, formatInfo.componentTypePrefix);
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, utils::SingleShaderStage::Compute,
|
||||
computeShader.c_str()));
|
||||
for (wgpu::TextureFormat format : kUnsupportedTextureFormats) {
|
||||
std::string computeShader = CreateComputeShaderWithStorageTexture(bindingType, format);
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModuleFromWGSL(device, computeShader.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that declaring a storage texture dimension that is not supported in WebGPU in shader
|
||||
// causes validation error at the creation of PSO. WebGPU doesn't support using cube map texture
|
||||
// views and cube map array texture views as storage textures.
|
||||
// Verify that declaring a storage texture dimension that isn't supported by
|
||||
// WebGPU causes a compile failure. WebGPU doesn't support using cube map
|
||||
// texture views and cube map array texture views as storage textures.
|
||||
TEST_F(StorageTextureValidationTests, UnsupportedTextureViewDimensionInShader) {
|
||||
constexpr std::array<wgpu::TextureViewDimension, 2> kUnsupportedTextureViewDimensions = {
|
||||
wgpu::TextureViewDimension::Cube, wgpu::TextureViewDimension::CubeArray};
|
||||
|
@ -382,14 +360,7 @@ TEST_F(StorageTextureValidationTests, UnsupportedTextureViewDimensionInShader) {
|
|||
for (wgpu::TextureViewDimension dimension : kUnsupportedTextureViewDimensions) {
|
||||
std::string computeShader =
|
||||
CreateComputeShaderWithStorageTexture(bindingType, kFormat, dimension);
|
||||
wgpu::ShaderModule csModule = utils::CreateShaderModule(
|
||||
device, utils::SingleShaderStage::Compute, computeShader.c_str());
|
||||
|
||||
wgpu::ComputePipelineDescriptor computePipelineDescriptor;
|
||||
computePipelineDescriptor.computeStage.module = csModule;
|
||||
computePipelineDescriptor.computeStage.entryPoint = "main";
|
||||
computePipelineDescriptor.layout = nullptr;
|
||||
ASSERT_DEVICE_ERROR(device.CreateComputePipeline(&computePipelineDescriptor));
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModuleFromWGSL(device, computeShader.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -431,8 +402,8 @@ TEST_F(StorageTextureValidationTests, BindGroupLayoutEntryTypeMatchesShaderDecla
|
|||
// Create the compute shader with the given binding type.
|
||||
std::string computeShader =
|
||||
CreateComputeShaderWithStorageTexture(bindingTypeInShader, kStorageTextureFormat);
|
||||
wgpu::ShaderModule csModule = utils::CreateShaderModule(
|
||||
device, utils::SingleShaderStage::Compute, computeShader.c_str());
|
||||
wgpu::ShaderModule csModule =
|
||||
utils::CreateShaderModuleFromWGSL(device, computeShader.c_str());
|
||||
|
||||
// Set common fields of compute pipeline descriptor.
|
||||
wgpu::ComputePipelineDescriptor defaultComputePipelineDescriptor;
|
||||
|
@ -508,8 +479,8 @@ TEST_F(StorageTextureValidationTests, BindGroupLayoutStorageTextureFormatMatches
|
|||
// format.
|
||||
std::string computeShader =
|
||||
CreateComputeShaderWithStorageTexture(bindingType, storageTextureFormatInShader);
|
||||
wgpu::ShaderModule csModule = utils::CreateShaderModule(
|
||||
device, utils::SingleShaderStage::Compute, computeShader.c_str());
|
||||
wgpu::ShaderModule csModule =
|
||||
utils::CreateShaderModuleFromWGSL(device, computeShader.c_str());
|
||||
|
||||
// Set common fields of compute pipeline descriptor.
|
||||
wgpu::ComputePipelineDescriptor defaultComputePipelineDescriptor;
|
||||
|
@ -565,8 +536,8 @@ TEST_F(StorageTextureValidationTests, BindGroupLayoutViewDimensionMatchesShaderD
|
|||
// Create the compute shader with the given texture view dimension.
|
||||
std::string computeShader = CreateComputeShaderWithStorageTexture(
|
||||
bindingType, kStorageTextureFormat, dimensionInShader);
|
||||
wgpu::ShaderModule csModule = utils::CreateShaderModule(
|
||||
device, utils::SingleShaderStage::Compute, computeShader.c_str());
|
||||
wgpu::ShaderModule csModule =
|
||||
utils::CreateShaderModuleFromWGSL(device, computeShader.c_str());
|
||||
|
||||
// Set common fields of compute pipeline descriptor.
|
||||
wgpu::ComputePipelineDescriptor defaultComputePipelineDescriptor;
|
||||
|
@ -797,9 +768,8 @@ TEST_F(StorageTextureValidationTests, StorageTextureViewDimensionInBindGroup) {
|
|||
TEST_F(StorageTextureValidationTests, MultisampledStorageTexture) {
|
||||
for (wgpu::StorageTextureAccess bindingType : kSupportedStorageTextureAccess) {
|
||||
std::string computeShader =
|
||||
CreateComputeShaderWithStorageTexture(bindingType, "rgba8", "", "image2DMS");
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, utils::SingleShaderStage::Compute,
|
||||
computeShader.c_str()));
|
||||
CreateComputeShaderWithStorageTexture(bindingType, "", "image2DMS");
|
||||
ASSERT_DEVICE_ERROR(utils::CreateShaderModuleFromWGSL(device, computeShader.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -516,6 +516,42 @@ namespace utils {
|
|||
return "rgba32sint";
|
||||
case wgpu::TextureFormat::RGBA32Float:
|
||||
return "rgba32float";
|
||||
|
||||
// The below do not currently exist in the WGSL spec, but are used
|
||||
// for tests that expect compilation failure.
|
||||
case wgpu::TextureFormat::R8Unorm:
|
||||
return "r8unorm";
|
||||
case wgpu::TextureFormat::R8Snorm:
|
||||
return "r8snorm";
|
||||
case wgpu::TextureFormat::R8Uint:
|
||||
return "r8uint";
|
||||
case wgpu::TextureFormat::R8Sint:
|
||||
return "r8sint";
|
||||
case wgpu::TextureFormat::R16Uint:
|
||||
return "r16uint";
|
||||
case wgpu::TextureFormat::R16Sint:
|
||||
return "r16sint";
|
||||
case wgpu::TextureFormat::R16Float:
|
||||
return "r16float";
|
||||
case wgpu::TextureFormat::RG8Unorm:
|
||||
return "rg8unorm";
|
||||
case wgpu::TextureFormat::RG8Snorm:
|
||||
return "rg8snorm";
|
||||
case wgpu::TextureFormat::RG8Uint:
|
||||
return "rg8uint";
|
||||
case wgpu::TextureFormat::RG8Sint:
|
||||
return "rg8sint";
|
||||
case wgpu::TextureFormat::RG16Uint:
|
||||
return "rg16uint";
|
||||
case wgpu::TextureFormat::RG16Sint:
|
||||
return "rg16sint";
|
||||
case wgpu::TextureFormat::RG16Float:
|
||||
return "rg16float";
|
||||
case wgpu::TextureFormat::RGB10A2Unorm:
|
||||
return "rgb10a2unorm";
|
||||
case wgpu::TextureFormat::RG11B10Ufloat:
|
||||
return "rg11b10ufloat";
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue