Skip to content

Commit

Permalink
Implement SPV_NV_bindless_texture related changes
Browse files Browse the repository at this point in the history
  • Loading branch information
pmistryNV committed Jul 14, 2022
1 parent e2cf769 commit 0b0d975
Show file tree
Hide file tree
Showing 16 changed files with 625 additions and 48 deletions.
5 changes: 5 additions & 0 deletions source/val/validate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
3 changes: 2 additions & 1 deletion source/val/validate_cfg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))) {
Expand Down
17 changes: 17 additions & 0 deletions source/val/validate_decorations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,12 @@ 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))
baseAlignment = vstate.samplerimage_variable_address_mode()/8;
break;
case SpvOpTypeInt:
case SpvOpTypeFloat:
baseAlignment = words[2] / 8;
Expand Down Expand Up @@ -256,6 +262,12 @@ 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;
break;
case SpvOpTypeInt:
case SpvOpTypeFloat:
return words[2] / 8;
Expand Down Expand Up @@ -296,6 +308,11 @@ 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;
case SpvOpTypeInt:
case SpvOpTypeFloat:
return words[2] / 8;
Expand Down
9 changes: 7 additions & 2 deletions source/val/validate_image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -927,7 +927,8 @@ 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:
Expand All @@ -950,6 +951,10 @@ bool IsAllowedSampledImageOperand(SpvOp opcode) {
case SpvOpImageSparseDrefGather:
case SpvOpCopyObject:
return true;
case SpvOpStore:
if(_.HasCapability(SpvCapabilityBindlessTextureNV))
return true;
return false;
default:
return false;
}
Expand Down Expand Up @@ -1035,7 +1040,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"
Expand Down
15 changes: 15 additions & 0 deletions source/val/validate_instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,21 @@ 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;
Expand Down
1 change: 1 addition & 0 deletions source/val/validate_layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
10 changes: 10 additions & 0 deletions source/val/validate_logicals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
45 changes: 15 additions & 30 deletions source/val/validate_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -425,8 +396,22 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) {
_.RegisterStructTypeWithBuiltInMember(struct_id);
}

const auto isOpaqueType = [&_](const Instruction *inst) {
auto opcode = 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)
Expand Down
13 changes: 13 additions & 0 deletions source/val/validation_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ ModuleLayoutSection InstructionLayoutSection(
if (current_section == kLayoutFunctionDeclarations)
return kLayoutFunctionDeclarations;
return kLayoutFunctionDefinitions;
case SpvOpSamplerImageAddressingModeNV:
return kLayoutSamplerImageAddressMode;
default:
break;
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -473,6 +476,16 @@ 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) {
Expand Down
46 changes: 32 additions & 14 deletions source/val/validation_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -862,7 +877,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
Expand Down
41 changes: 41 additions & 0 deletions test/val/val_decoration_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
29 changes: 29 additions & 0 deletions test/val/val_id_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading

0 comments on commit 0b0d975

Please sign in to comment.