Implement SPV_NV_bindless_texture related changes (#4847)

* Add validation for SPV_NV_bindless_texture
This commit is contained in:
Pankaj Mistry 2022-07-19 11:41:19 -07:00 committed by GitHub
parent 93ebf698a0
commit 60615b8ec6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 467 additions and 47 deletions

View File

@ -293,6 +293,11 @@ spv_result_t ValidateBinaryUsingContextAndValidationState(
return vstate->diag(SPV_ERROR_INVALID_LAYOUT, nullptr)
<< "Missing OpFunctionEnd at end of module.";
if (vstate->HasCapability(SpvCapabilityBindlessTextureNV) &&
!vstate->has_samplerimage_variable_address_mode_specified())
return vstate->diag(SPV_ERROR_INVALID_LAYOUT, nullptr)
<< "Missing required OpSamplerImageAddressingModeNV instruction.";
// Catch undefined forward references before performing further checks.
if (auto error = ValidateForwardDecls(*vstate)) return error;

View File

@ -66,7 +66,8 @@ spv_result_t ValidatePhi(ValidationState_t& _, const Instruction* inst) {
assert(type_inst);
const SpvOp type_opcode = type_inst->opcode();
if (!_.options()->before_hlsl_legalization) {
if (!_.options()->before_hlsl_legalization &&
!_.HasCapability(SpvCapabilityBindlessTextureNV)) {
if (type_opcode == SpvOpTypeSampledImage ||
(_.HasCapability(SpvCapabilityShader) &&
(type_opcode == SpvOpTypeImage || type_opcode == SpvOpTypeSampler))) {

View File

@ -190,6 +190,13 @@ uint32_t getBaseAlignment(uint32_t member_id, bool roundUp,
// Minimal alignment is byte-aligned.
uint32_t baseAlignment = 1;
switch (inst->opcode()) {
case SpvOpTypeSampledImage:
case SpvOpTypeSampler:
case SpvOpTypeImage:
if (vstate.HasCapability(SpvCapabilityBindlessTextureNV))
return baseAlignment = vstate.samplerimage_variable_address_mode() / 8;
assert(0);
return 0;
case SpvOpTypeInt:
case SpvOpTypeFloat:
baseAlignment = words[2] / 8;
@ -256,6 +263,13 @@ uint32_t getScalarAlignment(uint32_t type_id, ValidationState_t& vstate) {
const auto inst = vstate.FindDef(type_id);
const auto& words = inst->words();
switch (inst->opcode()) {
case SpvOpTypeSampledImage:
case SpvOpTypeSampler:
case SpvOpTypeImage:
if (vstate.HasCapability(SpvCapabilityBindlessTextureNV))
return vstate.samplerimage_variable_address_mode() / 8;
assert(0);
return 0;
case SpvOpTypeInt:
case SpvOpTypeFloat:
return words[2] / 8;
@ -296,6 +310,13 @@ uint32_t getSize(uint32_t member_id, const LayoutConstraints& inherited,
const auto inst = vstate.FindDef(member_id);
const auto& words = inst->words();
switch (inst->opcode()) {
case SpvOpTypeSampledImage:
case SpvOpTypeSampler:
case SpvOpTypeImage:
if (vstate.HasCapability(SpvCapabilityBindlessTextureNV))
return vstate.samplerimage_variable_address_mode() / 8;
assert(0);
return 0;
case SpvOpTypeInt:
case SpvOpTypeFloat:
return words[2] / 8;

View File

@ -927,7 +927,7 @@ spv_result_t ValidateTypeSampledImage(ValidationState_t& _,
return SPV_SUCCESS;
}
bool IsAllowedSampledImageOperand(SpvOp opcode) {
bool IsAllowedSampledImageOperand(SpvOp opcode, ValidationState_t& _) {
switch (opcode) {
case SpvOpSampledImage:
case SpvOpImageSampleImplicitLod:
@ -950,6 +950,9 @@ bool IsAllowedSampledImageOperand(SpvOp opcode) {
case SpvOpImageSparseDrefGather:
case SpvOpCopyObject:
return true;
case SpvOpStore:
if (_.HasCapability(SpvCapabilityBindlessTextureNV)) return true;
return false;
default:
return false;
}
@ -1035,7 +1038,7 @@ spv_result_t ValidateSampledImage(ValidationState_t& _,
<< _.getIdName(consumer_instr->id()) << "'.";
}
if (!IsAllowedSampledImageOperand(consumer_opcode)) {
if (!IsAllowedSampledImageOperand(consumer_opcode, _)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "Result <id> from OpSampledImage instruction must not appear "
"as operand for Op"

View File

@ -483,6 +483,22 @@ spv_result_t InstructionPass(ValidationState_t& _, const Instruction* inst) {
if (auto error = LimitCheckNumVars(_, inst->id(), storage_class)) {
return error;
}
} else if (opcode == SpvOpSamplerImageAddressingModeNV) {
if (!_.HasCapability(SpvCapabilityBindlessTextureNV)) {
return _.diag(SPV_ERROR_MISSING_EXTENSION, inst)
<< "OpSamplerImageAddressingModeNV supported only with extension "
"SPV_NV_bindless_texture";
}
uint32_t bitwidth = inst->GetOperandAs<uint32_t>(0);
if (_.samplerimage_variable_address_mode() != 0) {
return _.diag(SPV_ERROR_INVALID_LAYOUT, inst)
<< "OpSamplerImageAddressingModeNV should only be provided once";
}
if (bitwidth != 32 && bitwidth != 64) {
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "OpSamplerImageAddressingModeNV bitwidth should be 64 or 32";
}
_.set_samplerimage_variable_address_mode(bitwidth);
}
if (auto error = ReservedCheck(_, inst)) return error;

View File

@ -363,6 +363,7 @@ spv_result_t ModuleLayoutPass(ValidationState_t& _, const Instruction* inst) {
case kLayoutExtensions:
case kLayoutExtInstImport:
case kLayoutMemoryModel:
case kLayoutSamplerImageAddressMode:
case kLayoutEntryPoint:
case kLayoutExecutionMode:
case kLayoutDebug1:

View File

@ -170,6 +170,16 @@ spv_result_t LogicalsPass(ValidationState_t& _, const Instruction* inst) {
break;
}
case SpvOpTypeSampledImage:
case SpvOpTypeImage:
case SpvOpTypeSampler: {
if (!_.HasCapability(SpvCapabilityBindlessTextureNV))
return _.diag(SPV_ERROR_INVALID_DATA, inst)
<< "Using image/sampler with OpSelect requires capability "
<< "BindlessTextureNV";
break;
}
case SpvOpTypeVector: {
dimension = type_inst->word(3);
break;

View File

@ -306,35 +306,6 @@ spv_result_t ValidateTypeRuntimeArray(ValidationState_t& _,
return SPV_SUCCESS;
}
bool ContainsOpaqueType(ValidationState_t& _, const Instruction* str) {
const size_t elem_type_index = 1;
uint32_t elem_type_id;
Instruction* elem_type;
if (spvOpcodeIsBaseOpaqueType(str->opcode())) {
return true;
}
switch (str->opcode()) {
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
elem_type_id = str->GetOperandAs<uint32_t>(elem_type_index);
elem_type = _.FindDef(elem_type_id);
return ContainsOpaqueType(_, elem_type);
case SpvOpTypeStruct:
for (size_t member_type_index = 1;
member_type_index < str->operands().size(); ++member_type_index) {
auto member_type_id = str->GetOperandAs<uint32_t>(member_type_index);
auto member_type = _.FindDef(member_type_id);
if (ContainsOpaqueType(_, member_type)) return true;
}
break;
default:
break;
}
return false;
}
spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) {
const uint32_t struct_id = inst->GetOperandAs<uint32_t>(0);
for (size_t member_type_index = 1;
@ -425,8 +396,21 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) {
_.RegisterStructTypeWithBuiltInMember(struct_id);
}
const auto isOpaqueType = [&_](const Instruction* opaque_inst) {
auto opcode = opaque_inst->opcode();
if (_.HasCapability(SpvCapabilityBindlessTextureNV) &&
(opcode == SpvOpTypeImage || opcode == SpvOpTypeSampler ||
opcode == SpvOpTypeSampledImage)) {
return false;
} else if (spvOpcodeIsBaseOpaqueType(opcode)) {
return true;
}
return false;
};
if (spvIsVulkanEnv(_.context()->target_env) &&
!_.options()->before_hlsl_legalization && ContainsOpaqueType(_, inst)) {
!_.options()->before_hlsl_legalization &&
_.ContainsType(inst->id(), isOpaqueType)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< _.VkErrorID(4667) << "In "
<< spvLogStringForEnv(_.context()->target_env)

View File

@ -90,6 +90,8 @@ ModuleLayoutSection InstructionLayoutSection(
if (current_section == kLayoutFunctionDeclarations)
return kLayoutFunctionDeclarations;
return kLayoutFunctionDefinitions;
case SpvOpSamplerImageAddressingModeNV:
return kLayoutSamplerImageAddressMode;
default:
break;
}
@ -161,6 +163,7 @@ ValidationState_t::ValidationState_t(const spv_const_context ctx,
addressing_model_(SpvAddressingModelMax),
memory_model_(SpvMemoryModelMax),
pointer_size_and_alignment_(0),
sampler_image_addressing_mode_(0),
in_function_(false),
num_of_warnings_(0),
max_num_of_warnings_(max_warnings) {
@ -473,6 +476,15 @@ void ValidationState_t::set_memory_model(SpvMemoryModel mm) {
SpvMemoryModel ValidationState_t::memory_model() const { return memory_model_; }
void ValidationState_t::set_samplerimage_variable_address_mode(
uint32_t bit_width) {
sampler_image_addressing_mode_ = bit_width;
}
uint32_t ValidationState_t::samplerimage_variable_address_mode() const {
return sampler_image_addressing_mode_;
}
spv_result_t ValidationState_t::RegisterFunction(
uint32_t id, uint32_t ret_type_id, SpvFunctionControlMask function_control,
uint32_t function_type_id) {

View File

@ -44,19 +44,20 @@ namespace val {
/// of the SPIRV spec for additional details of the order. The enumerant values
/// are in the same order as the vector returned by GetModuleOrder
enum ModuleLayoutSection {
kLayoutCapabilities, /// < Section 2.4 #1
kLayoutExtensions, /// < Section 2.4 #2
kLayoutExtInstImport, /// < Section 2.4 #3
kLayoutMemoryModel, /// < Section 2.4 #4
kLayoutEntryPoint, /// < Section 2.4 #5
kLayoutExecutionMode, /// < Section 2.4 #6
kLayoutDebug1, /// < Section 2.4 #7 > 1
kLayoutDebug2, /// < Section 2.4 #7 > 2
kLayoutDebug3, /// < Section 2.4 #7 > 3
kLayoutAnnotations, /// < Section 2.4 #8
kLayoutTypes, /// < Section 2.4 #9
kLayoutFunctionDeclarations, /// < Section 2.4 #10
kLayoutFunctionDefinitions /// < Section 2.4 #11
kLayoutCapabilities, /// < Section 2.4 #1
kLayoutExtensions, /// < Section 2.4 #2
kLayoutExtInstImport, /// < Section 2.4 #3
kLayoutMemoryModel, /// < Section 2.4 #4
kLayoutSamplerImageAddressMode, /// < Section 2.4 #5
kLayoutEntryPoint, /// < Section 2.4 #6
kLayoutExecutionMode, /// < Section 2.4 #7
kLayoutDebug1, /// < Section 2.4 #8 > 1
kLayoutDebug2, /// < Section 2.4 #8 > 2
kLayoutDebug3, /// < Section 2.4 #8 > 3
kLayoutAnnotations, /// < Section 2.4 #9
kLayoutTypes, /// < Section 2.4 #10
kLayoutFunctionDeclarations, /// < Section 2.4 #11
kLayoutFunctionDefinitions /// < Section 2.4 #12
};
/// This class manages the state of the SPIR-V validation as it is being parsed.
@ -360,6 +361,20 @@ class ValidationState_t {
/// Returns the memory model of this module, or Simple if uninitialized.
SpvMemoryModel memory_model() const;
/// Sets the bit width for sampler/image type variables. If not set, they are
/// considered opaque
void set_samplerimage_variable_address_mode(uint32_t bit_width);
/// Get the addressing mode currently set. If 0, it means addressing mode is
/// invalid Sampler/Image type variables must be considered opaque This mode
/// is only valid after the instruction has been read
uint32_t samplerimage_variable_address_mode() const;
/// Returns true if the OpSamplerImageAddressingModeNV was found.
bool has_samplerimage_variable_address_mode_specified() const {
return sampler_image_addressing_mode_ != 0;
}
const AssemblyGrammar& grammar() const { return grammar_; }
/// Inserts the instruction into the list of ordered instructions in the file.
@ -864,7 +879,10 @@ class ValidationState_t {
// have the same pointer size (for physical pointer types).
uint32_t pointer_size_and_alignment_;
/// NOTE: See corresponding getter functions
/// bit width of sampler/image type variables. Valid values are 32 and 64
uint32_t sampler_image_addressing_mode_;
/// NOTE: See correspoding getter functions
bool in_function_;
/// The state of optional features. These are determined by capabilities

View File

@ -8695,6 +8695,47 @@ INSTANTIATE_TEST_SUITE_P(FragmentInputInterface, ValidateDecorationString,
::testing::Values("Flat", "NoPerspective", "Sample",
"Centroid"));
TEST_F(ValidateDecorations, NVBindlessSamplerArrayInBlock) {
const std::string spirv = R"(
OpCapability Shader
OpCapability BindlessTextureNV
OpExtension "SPV_NV_bindless_texture"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpSamplerImageAddressingModeNV 64
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %UBO "UBO"
OpMemberName %UBO 0 "uboSampler"
OpName %_ ""
OpDecorate %array ArrayStride 16
OpMemberDecorate %UBO 0 Offset 0
OpDecorate %UBO Block
OpDecorate %_ DescriptorSet 0
OpDecorate %_ Binding 2
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%7 = OpTypeImage %float 2D 0 0 0 1 Unknown
%8 = OpTypeSampledImage %7
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%array = OpTypeArray %8 %uint_3
%UBO = OpTypeStruct %array
%pointer = OpTypePointer Uniform %UBO
%_ = OpVariable %pointer Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
}
} // namespace
} // namespace val
} // namespace spvtools

View File

@ -6570,6 +6570,35 @@ TEST_F(ValidateIdWithMessage, MissingForwardPointer) {
"Operand 3[%_ptr_Uniform__struct_2] requires a previous definition"));
}
TEST_F(ValidateIdWithMessage, NVBindlessSamplerInStruct) {
std::string spirv = R"(
OpCapability Shader
OpCapability BindlessTextureNV
OpExtension "SPV_NV_bindless_texture"
OpMemoryModel Logical GLSL450
OpSamplerImageAddressingModeNV 64
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%7 = OpTypeImage %float 2D 0 0 0 1 Unknown
%8 = OpTypeSampledImage %7
%9 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
%10 = OpTypeSampler
%UBO = OpTypeStruct %8 %9 %10
%_ptr_Uniform_UBO = OpTypePointer Uniform %UBO
%_ = OpVariable %_ptr_Uniform_UBO Uniform
%main = OpFunction %void None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
}
} // namespace
} // namespace val
} // namespace spvtools

View File

@ -6248,6 +6248,138 @@ OpFunctionEnd
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_6));
}
TEST_F(ValidateImage, NVBindlessSamplerBuiltins) {
const std::string text = R"(
OpCapability Shader
OpCapability Int64
OpCapability Image1D
OpCapability BindlessTextureNV
OpExtension "SPV_NV_bindless_texture"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpSamplerImageAddressingModeNV 64
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %s2D "s2D"
OpName %textureHandle "textureHandle"
OpName %i1D "i1D"
OpName %s "s"
OpName %temp "temp"
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%7 = OpTypeImage %float 2D 0 0 0 1 Unknown
%8 = OpTypeSampledImage %7
%_ptr_Function_8 = OpTypePointer Function %8
%ulong = OpTypeInt 64 0
%_ptr_Private_ulong = OpTypePointer Private %ulong
%textureHandle = OpVariable %_ptr_Private_ulong Private
%16 = OpTypeImage %float 1D 0 0 0 2 Rgba32f
%_ptr_Function_16 = OpTypePointer Function %16
%21 = OpTypeSampler
%_ptr_Function_21 = OpTypePointer Function %21
%_ptr_Function_ulong = OpTypePointer Function %ulong
%main = OpFunction %void None %3
%5 = OpLabel
%s2D = OpVariable %_ptr_Function_8 Function
%i1D = OpVariable %_ptr_Function_16 Function
%s = OpVariable %_ptr_Function_21 Function
%temp = OpVariable %_ptr_Function_ulong Function
%14 = OpLoad %ulong %textureHandle
%15 = OpConvertUToSampledImageNV %8 %14
OpStore %s2D %15
%19 = OpLoad %ulong %textureHandle
%20 = OpConvertUToImageNV %16 %19
OpStore %i1D %20
%24 = OpLoad %ulong %textureHandle
%25 = OpConvertUToSamplerNV %21 %24
OpStore %s %25
%28 = OpLoad %8 %s2D
%29 = OpConvertSampledImageToUNV %ulong %28
OpStore %temp %29
%30 = OpLoad %16 %i1D
%31 = OpConvertImageToUNV %ulong %30
OpStore %temp %31
%32 = OpLoad %21 %s
%33 = OpConvertSamplerToUNV %ulong %32
OpStore %temp %33
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
}
TEST_F(ValidateImage, NVBindlessAddressingMode64) {
std::string text = R"(
OpCapability Shader
OpCapability BindlessTextureNV
OpExtension "SPV_NV_bindless_texture"
OpMemoryModel Logical GLSL450
OpSamplerImageAddressingModeNV 64
OpEntryPoint GLCompute %func "main"
%voidt = OpTypeVoid
%uintt = OpTypeInt 32 0
%funct = OpTypeFunction %voidt
%func = OpFunction %voidt None %funct
%entry = OpLabel
%udef = OpUndef %uintt
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
}
TEST_F(ValidateImage, NVBindlessAddressingMode32) {
std::string text = R"(
OpCapability Shader
OpCapability BindlessTextureNV
OpExtension "SPV_NV_bindless_texture"
OpMemoryModel Logical GLSL450
OpSamplerImageAddressingModeNV 32
OpEntryPoint GLCompute %func "main"
%voidt = OpTypeVoid
%uintt = OpTypeInt 32 0
%funct = OpTypeFunction %voidt
%func = OpFunction %voidt None %funct
%entry = OpLabel
%udef = OpUndef %uintt
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
}
TEST_F(ValidateImage, NVBindlessInvalidAddressingMode) {
std::string text = R"(
OpCapability Shader
OpCapability BindlessTextureNV
OpExtension "SPV_NV_bindless_texture"
OpMemoryModel Logical GLSL450
OpSamplerImageAddressingModeNV 0
OpEntryPoint GLCompute %func "main"
%voidt = OpTypeVoid
%uintt = OpTypeInt 32 0
%funct = OpTypeFunction %voidt
%func = OpFunction %voidt None %funct
%entry = OpLabel
%udef = OpUndef %uintt
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3);
EXPECT_EQ(SPV_ERROR_INVALID_DATA,
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("OpSamplerImageAddressingModeNV bitwidth should be 64 or 32"));
}
} // namespace
} // namespace val
} // namespace spvtools

View File

@ -667,6 +667,98 @@ TEST_F(ValidateLayout, ModuleProcessedInvalidInBasicBlock) {
// TODO(umar): Test optional instructions
TEST_F(ValidateLayout, ValidNVBindlessTexturelayout) {
std::string str = R"(
OpCapability Shader
OpCapability BindlessTextureNV
OpExtension "SPV_NV_bindless_texture"
OpMemoryModel Logical GLSL450
OpSamplerImageAddressingModeNV 64
OpEntryPoint GLCompute %func "main"
%voidt = OpTypeVoid
%uintt = OpTypeInt 32 0
%funct = OpTypeFunction %voidt
%func = OpFunction %voidt None %funct
%entry = OpLabel
%udef = OpUndef %uintt
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(str);
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
}
TEST_F(ValidateLayout, InvalidValidNVBindlessTexturelayout) {
std::string str = R"(
OpCapability Shader
OpCapability BindlessTextureNV
OpExtension "SPV_NV_bindless_texture"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "main"
OpSamplerImageAddressingModeNV 64
%voidt = OpTypeVoid
%uintt = OpTypeInt 32 0
%funct = OpTypeFunction %voidt
%func = OpFunction %voidt None %funct
%entry = OpLabel
%udef = OpUndef %uintt
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(str);
ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"SamplerImageAddressingModeNV is in an invalid layout section"));
}
TEST_F(ValidateLayout, MissingNVBindlessAddressModeFromLayout) {
std::string str = R"(
OpCapability Shader
OpCapability BindlessTextureNV
OpExtension "SPV_NV_bindless_texture"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "main"
%voidt = OpTypeVoid
%uintt = OpTypeInt 32 0
%funct = OpTypeFunction %voidt
%func = OpFunction %voidt None %funct
%entry = OpLabel
%udef = OpUndef %uintt
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(str);
ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("Missing required OpSamplerImageAddressingModeNV instruction"));
}
TEST_F(ValidateLayout, NVBindlessAddressModeFromLayoutSpecifiedTwice) {
std::string str = R"(
OpCapability Shader
OpCapability BindlessTextureNV
OpExtension "SPV_NV_bindless_texture"
OpMemoryModel Logical GLSL450
OpSamplerImageAddressingModeNV 64
OpSamplerImageAddressingModeNV 64
)";
CompileSuccessfully(str);
ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("OpSamplerImageAddressingModeNV should only be provided once"));
}
} // namespace
} // namespace val
} // namespace spvtools

View File

@ -1159,6 +1159,61 @@ OpFunctionEnd
"condition to be equal: Select"));
}
TEST_F(ValidateLogicals, SelectNVBindlessSamplers) {
const std::string spirv = R"(
OpCapability Shader
OpCapability BindlessTextureNV
OpExtension "SPV_NV_bindless_texture"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpSamplerImageAddressingModeNV 64
OpEntryPoint Fragment %main "main"
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpSourceExtension "GL_NV_bindless_texture"
OpName %main "main"
OpName %s2D "s2D"
OpName %pickhandle "pickhandle"
OpName %Sampler1 "Sampler1"
OpName %Sampler2 "Sampler2"
OpDecorate %pickhandle Flat
OpDecorate %Sampler1 DescriptorSet 0
OpDecorate %Sampler1 Binding 0
OpDecorate %Sampler1 BindlessSamplerNV
OpDecorate %Sampler2 DescriptorSet 0
OpDecorate %Sampler2 Binding 1
OpDecorate %Sampler2 BindlessSamplerNV
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%7 = OpTypeImage %float 2D 0 0 0 1 Unknown
%8 = OpTypeSampledImage %7
%_ptr_Function_8 = OpTypePointer Function %8
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_0 = OpConstant %int 0
%bool = OpTypeBool
%_ptr_UniformConstant_8 = OpTypePointer UniformConstant %8
%Sampler1 = OpVariable %_ptr_UniformConstant_8 UniformConstant
%Sampler2 = OpVariable %_ptr_UniformConstant_8 UniformConstant
%main = OpFunction %void None %3
%5 = OpLabel
%s2D = OpVariable %_ptr_Function_8 Function
%pickhandle = OpVariable %_ptr_Function_int Function
%14 = OpLoad %int %pickhandle
%17 = OpIEqual %bool %14 %int_0
%20 = OpLoad %8 %Sampler1
%22 = OpLoad %8 %Sampler2
%23 = OpSelect %8 %17 %20 %22
OpStore %s2D %23
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
}
} // namespace
} // namespace val
} // namespace spvtools