Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/KhronosGroup/SPIRV-Tools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPankaj Mistry <63069047+pmistryNV@users.noreply.github.com>2022-07-19 21:41:19 +0300
committerGitHub <noreply@github.com>2022-07-19 21:41:19 +0300
commit60615b8ec6f3d7d0776a97c407b77342ddad7b0b (patch)
tree849c5cdaae061f3cd78fcfb16f6d8649e5403055
parent93ebf698a0ae7ef6becc8e244e6e6046cf8ab164 (diff)
Implement SPV_NV_bindless_texture related changes (#4847)
* Add validation for SPV_NV_bindless_texture
-rw-r--r--source/val/validate.cpp5
-rw-r--r--source/val/validate_cfg.cpp3
-rw-r--r--source/val/validate_decorations.cpp21
-rw-r--r--source/val/validate_image.cpp7
-rw-r--r--source/val/validate_instruction.cpp16
-rw-r--r--source/val/validate_layout.cpp1
-rw-r--r--source/val/validate_logicals.cpp10
-rw-r--r--source/val/validate_type.cpp44
-rw-r--r--source/val/validation_state.cpp12
-rw-r--r--source/val/validation_state.h46
-rw-r--r--test/val/val_decoration_test.cpp41
-rw-r--r--test/val/val_id_test.cpp29
-rw-r--r--test/val/val_image_test.cpp132
-rw-r--r--test/val/val_layout_test.cpp92
-rw-r--r--test/val/val_logicals_test.cpp55
15 files changed, 467 insertions, 47 deletions
diff --git a/source/val/validate.cpp b/source/val/validate.cpp
index ecc9fdb63..dc6401a93 100644
--- a/source/val/validate.cpp
+++ b/source/val/validate.cpp
@@ -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;
diff --git a/source/val/validate_cfg.cpp b/source/val/validate_cfg.cpp
index d4ca20e5d..0220fcd33 100644
--- a/source/val/validate_cfg.cpp
+++ b/source/val/validate_cfg.cpp
@@ -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))) {
diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp
index 986f32953..d52d3a4fd 100644
--- a/source/val/validate_decorations.cpp
+++ b/source/val/validate_decorations.cpp
@@ -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;
diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp
index f6d7d103c..2d5e2c7c5 100644
--- a/source/val/validate_image.cpp
+++ b/source/val/validate_image.cpp
@@ -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"
diff --git a/source/val/validate_instruction.cpp b/source/val/validate_instruction.cpp
index 3edf16379..767c0cee1 100644
--- a/source/val/validate_instruction.cpp
+++ b/source/val/validate_instruction.cpp
@@ -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;
diff --git a/source/val/validate_layout.cpp b/source/val/validate_layout.cpp
index d5823219d..6f9513523 100644
--- a/source/val/validate_layout.cpp
+++ b/source/val/validate_layout.cpp
@@ -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:
diff --git a/source/val/validate_logicals.cpp b/source/val/validate_logicals.cpp
index 5307988e3..ec1e207be 100644
--- a/source/val/validate_logicals.cpp
+++ b/source/val/validate_logicals.cpp
@@ -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;
diff --git a/source/val/validate_type.cpp b/source/val/validate_type.cpp
index 2aded6165..b0b60792b 100644
--- a/source/val/validate_type.cpp
+++ b/source/val/validate_type.cpp
@@ -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)
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index 339f79aeb..adfe75bbd 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -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) {
diff --git a/source/val/validation_state.h b/source/val/validation_state.h
index 745fd0262..b4d343d94 100644
--- a/source/val/validation_state.h
+++ b/source/val/validation_state.h
@@ -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
diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp
index e117e6f8c..fd8d9cdfc 100644
--- a/test/val/val_decoration_test.cpp
+++ b/test/val/val_decoration_test.cpp
@@ -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
diff --git a/test/val/val_id_test.cpp b/test/val/val_id_test.cpp
index 69257a587..b7e504227 100644
--- a/test/val/val_id_test.cpp
+++ b/test/val/val_id_test.cpp
@@ -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
diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp
index 76af29ccb..c4de60a25 100644
--- a/test/val/val_image_test.cpp
+++ b/test/val/val_image_test.cpp
@@ -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
diff --git a/test/val/val_layout_test.cpp b/test/val/val_layout_test.cpp
index 7ebd7c008..8cca96f59 100644
--- a/test/val/val_layout_test.cpp
+++ b/test/val/val_layout_test.cpp
@@ -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
diff --git a/test/val/val_logicals_test.cpp b/test/val/val_logicals_test.cpp
index 1b76c8533..c1406728a 100644
--- a/test/val/val_logicals_test.cpp
+++ b/test/val/val_logicals_test.cpp
@@ -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