Skip to content

Commit

Permalink
spirv-val: Add support for SPV_AMD_shader_image_load_store_lod
Browse files Browse the repository at this point in the history
According to SPV_AMD_shader_image_load_store_lod spec, Lod operand is
valid with OpImageRead, OpImageWrite, or OpImageSparseRead if the
extension is enabled.
  • Loading branch information
samuelig committed Feb 12, 2020
1 parent 6c218ec commit a2845c2
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 1 deletion.
14 changes: 13 additions & 1 deletion source/val/validate_image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,17 @@ bool IsExplicitLod(SpvOp opcode) {
return false;
}

bool IsValidLodOperand(const ValidationState_t& _, SpvOp opcode) {
switch (opcode) {
case SpvOpImageRead:
case SpvOpImageWrite:
case SpvOpImageSparseRead:
return _.features().lod_image_operand_read_write_sparseread_AMD;
default:
return IsExplicitLod(opcode);
}
}

// Returns true if the opcode is a Image instruction which applies
// homogenous projection to the coordinates.
bool IsProj(SpvOp opcode) {
Expand Down Expand Up @@ -248,6 +259,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,

const bool is_implicit_lod = IsImplicitLod(opcode);
const bool is_explicit_lod = IsExplicitLod(opcode);
const bool is_valid_lod_operand = IsValidLodOperand(_, opcode);

// The checks should be done in the order of definition of OperandImage.

Expand Down Expand Up @@ -277,7 +289,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _,
}

if (mask & SpvImageOperandsLodMask) {
if (!is_explicit_lod && opcode != SpvOpImageFetch &&
if (!is_valid_lod_operand && opcode != SpvOpImageFetch &&
opcode != SpvOpImageSparseFetch) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Image Operand Lod can only be used with ExplicitLod opcodes "
Expand Down
2 changes: 2 additions & 0 deletions source/val/validation_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,8 @@ void ValidationState_t::RegisterCapability(SpvCapability cap) {
case SpvCapabilityVariablePointersStorageBuffer:
features_.variable_pointers_storage_buffer = true;
break;
case SpvCapabilityImageReadWriteLodAMD:
features_.lod_image_operand_read_write_sparseread_AMD = true;
default:
break;
}
Expand Down
4 changes: 4 additions & 0 deletions source/val/validation_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ class ValidationState_t {

// SPIR-V 1.4 allows Function and Private variables to be NonWritable
bool nonwritable_var_in_function_or_private = false;

// Allow Lod image operand to OpImageRead, OpImageWrite, or
// OpImageSparseRead. See SPV_AMD_shader_image_load_store_lod.
bool lod_image_operand_read_write_sparseread_AMD = false;
};

ValidationState_t(const spv_const_context context,
Expand Down
130 changes: 130 additions & 0 deletions test/val/val_image_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4841,6 +4841,136 @@ TEST_F(ValidateImage, ZeroExtendVectorSIntTexelV14Good) {
EXPECT_THAT(getDiagnosticString(), Eq(""));
}

TEST_F(ValidateImage, ReadLodAMDSuccess1) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
%res1 = OpImageRead %u32vec4 %img %u32vec2_01 Lod %u32_0
)";

const std::string extra =
"\nOpCapability StorageImageReadWithoutFormat\n"
"OpCapability ImageReadWriteLodAMD\n"
"OpExtension \"SPV_AMD_shader_image_load_store_lod\"\n";
CompileSuccessfully(
GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_1),
SPV_ENV_UNIVERSAL_1_1);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
}

TEST_F(ValidateImage, ReadLodAMDSuccess2) {
const std::string body = R"(
%img = OpLoad %type_image_f32_1d_0002_rgba32f %uniform_image_f32_1d_0002_rgba32f
%res1 = OpImageRead %f32vec4 %img %u32vec2_01 Lod %u32_0
)";

const std::string extra =
"\nOpCapability Image1D\n"
"OpCapability ImageReadWriteLodAMD\n"
"OpExtension \"SPV_AMD_shader_image_load_store_lod\"\n";
CompileSuccessfully(
GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_1),
SPV_ENV_UNIVERSAL_1_1);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
}

TEST_F(ValidateImage, ReadLodAMDSuccess3) {
const std::string body = R"(
%img = OpLoad %type_image_f32_cube_0102_rgba32f %uniform_image_f32_cube_0102_rgba32f
%res1 = OpImageRead %f32vec4 %img %u32vec3_012 Lod %u32_0
)";

const std::string extra =
"\nOpCapability ImageCubeArray\n"
"OpCapability ImageReadWriteLodAMD\n"
"OpExtension \"SPV_AMD_shader_image_load_store_lod\"\n";
CompileSuccessfully(
GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_1),
SPV_ENV_UNIVERSAL_1_1);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
}

TEST_F(ValidateImage, ReadLodAMDNeedCapability) {
const std::string body = R"(
%img = OpLoad %type_image_f32_cube_0102_rgba32f %uniform_image_f32_cube_0102_rgba32f
%res1 = OpImageRead %f32vec4 %img %u32vec3_012 Lod %u32_0
)";

const std::string extra = "\nOpCapability ImageCubeArray\n";
CompileSuccessfully(
GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_1),
SPV_ENV_UNIVERSAL_1_1);
ASSERT_EQ(SPV_ERROR_INVALID_DATA,
ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Image Operand Lod can only be used with ExplicitLod "
"opcodes and OpImageFetch"));
}

TEST_F(ValidateImage, WriteLodAMDSuccess1) {
const std::string body = R"(
%img = OpLoad %type_image_u32_2d_0000 %uniform_image_u32_2d_0000
OpImageWrite %img %u32vec2_01 %u32vec4_0123 Lod %u32_0
)";

const std::string extra =
"\nOpCapability StorageImageWriteWithoutFormat\n"
"OpCapability ImageReadWriteLodAMD\n"
"OpExtension \"SPV_AMD_shader_image_load_store_lod\"\n";
CompileSuccessfully(
GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_1),
SPV_ENV_UNIVERSAL_1_1);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
}

TEST_F(ValidateImage, WriteLodAMDSuccess2) {
const std::string body = R"(
%img = OpLoad %type_image_f32_1d_0002_rgba32f %uniform_image_f32_1d_0002_rgba32f
OpImageWrite %img %u32_1 %f32vec4_0000 Lod %u32_0
)";

const std::string extra =
"\nOpCapability Image1D\n"
"OpCapability ImageReadWriteLodAMD\n"
"OpExtension \"SPV_AMD_shader_image_load_store_lod\"\n";
CompileSuccessfully(
GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_1),
SPV_ENV_UNIVERSAL_1_1);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
}

TEST_F(ValidateImage, WriteLodAMDSuccess3) {
const std::string body = R"(
%img = OpLoad %type_image_f32_cube_0102_rgba32f %uniform_image_f32_cube_0102_rgba32f
OpImageWrite %img %u32vec3_012 %f32vec4_0000 Lod %u32_0
)";

const std::string extra =
"\nOpCapability ImageCubeArray\n"
"OpCapability ImageReadWriteLodAMD\n"
"OpExtension \"SPV_AMD_shader_image_load_store_lod\"\n";
CompileSuccessfully(
GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_1),
SPV_ENV_UNIVERSAL_1_1);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
}

TEST_F(ValidateImage, WriteLodAMDNeedCapability) {
const std::string body = R"(
%img = OpLoad %type_image_f32_cube_0102_rgba32f %uniform_image_f32_cube_0102_rgba32f
OpImageWrite %img %u32vec3_012 %f32vec4_0000 Lod %u32_0
)";

const std::string extra = "\nOpCapability ImageCubeArray\n";
CompileSuccessfully(
GenerateShaderCode(body, extra, "Fragment", "", SPV_ENV_UNIVERSAL_1_1),
SPV_ENV_UNIVERSAL_1_1);
ASSERT_EQ(SPV_ERROR_INVALID_DATA,
ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Image Operand Lod can only be used with ExplicitLod "
"opcodes and OpImageFetch"));
}

// No negative tests for ZeroExtend since we don't truly know the
// texel format.

Expand Down

0 comments on commit a2845c2

Please sign in to comment.