Updated spirv-tools.

This commit is contained in:
Бранимир Караџић
2020-12-05 19:13:13 -08:00
parent ca829cf404
commit 37e50587ae
11 changed files with 771 additions and 192 deletions

View File

@@ -1,7 +1,95 @@
Revision history for SPIRV-Tools
v2020.6 2020-09-24
- Start SPIRV-Tools v2020.6
v2020.7-dev 2020-12-03
- Start v2020.7-dev
v2020.6 2020-12-02
- General
CMake: Add SPIRV_TOOLS_BUILD_STATIC flag (#3910)
- Disassembler
Add some context comments to disassembly. (#3847)
- Optimizer
- Do run DCE if SPV_KHR_ray_query is used. (#4047)
- Handle 8-bit index in elim dead member (#4043)
- Add texel buffer out-of-bounds checking instrumentation (#4038)
- Update MeshShadingNV dependencies (and land Ray tracing updates) (#4028)
- Fix buffer oob instrumentation for matrix refs (#4025)
- Fix SSA re-writing in the presence of variable pointers. (#4010)
- Add support to prevent functions from being inlined if they have
DontInline flag (#3858)
- Add SPV_EXT_shader_image_int64 (#3852)
- Support SPV_KHR_fragment_shading_rate (#3943)
- Fix use-after-move in val/validate.cpp (#3848)
- Debug Info
- properly preserve DebugValue indexes operand (#4022)
- Add DebugValue for invisible store in single_store_elim (#4002)
- Propagate OpLine to all applied instructions in spirv-opt (#3951)
- Add DebugValue for DebugDecl invisible to value assignment (#3973)
- Add DebugValue for function param regardless of scope (#3923)
- Debug info preservation in convert-local-access-chains pass (#3835)
- Debug info preservation in redundancy-elimination pass (#3839)
- Debug info preservation in if-conversion pass (#3861)
- Validator
- Add validation support for the ray tracing built-in variables (#4041)
- Use less stack space when validating Vulkan builtins (#4019)
- Fix SPV_KHR_fragment_shading_rate VUID label (#4014)
- Label Layer and ViewportIndex VUIDs (#4013)
- Allow the ViewportIndex and Layer built-ins on SPIR-V 1.5 (#3986)
- Fix validation of OpPhi instructions (#3919)
- Fuzz
- Fix facts arising from CompositeConstruct (#4034)
- Do not flatten conditionals that create synonyms (#4030)
- Add support for reining in rogue fuzzer passes (#3987)
- Fix assertion failure in FuzzerPassAddCompositeExtract (#3995)
- Fix invalid equation facts (#4009)
- Fix bugs in TransformationFlattenConditionalBranch (#4006)
- Fix bug related to transformation applicability (#3990)
- Add expand vector reduction transformation (#3869)
- Add FuzzerPassAddCompositeExtract (#3904)
- Fix mismatch with shrinker step limit (#3985)
- Fix off-by-one error in replayer (#3982)
- Get order right for OpSelect arguments (#3974)
- Do not add synonym-creating loops in dead blocks (#3975)
- Skip OpTypeSampledImage when propagating up (#3976)
- Pass OpUndef in function call if needed (#3978)
- Fix off-by-one in TransformationCompositeConstruct (#3979)
- Tolerate absent ids in data synonym fact management (#3966)
- Fix to id availability (#3971)
- Fix operand types (#3962)
- Don't flatten conditional if condition is irrelevant (#3944)
- Do not produce OpPhis of type OpTypeSampledImage (#3964)
- Restrict fuzzer pass to reachable blocks (#3970)
- Handle more types when extending OpPhi instructions (#3969)
- Skip early terminator wrappers when merging returns (#3968)
- Avoid irrelevant constants in synonym-creating loops (#3967)
- Skip dead blocks in FuzzerPassAddOpPhiSynonyms (#3965)
- Avoid the type manager when looking for struct types (#3963)
- Fix to TransformationDuplicateRegionWithSelection (#3941)
- Skip OpFunction when replacing irrelevant ids (#3932)
- Use component-wise selectors when flattening conditional branches (#3921)
- Avoid void struct member when outlining functions (#3936)
- Do not allow Block-decorated structs when adding parameters (#3931)
- Fix to operand id type (#3937)
- Handle dead blocks in TransformationEquationInstruction (#3933)
- Do not allow sampled image load when flattening conditionals (#3930)
- Take care of OpPhi instructions when inlining (#3939)
- Fix to TransformationInlineFunction (#3913)
- Wrap early terminators before merging returns (#3925)
- Lower probability of adding bit instruction synonyms (#3917)
- Fix handling of OpPhi in FlattenConditionalBranch (#3916)
- Avoid creating blocks without parents (#3908)
- Do not allow creation of constants of block-decorated structs (#3903)
- Fixes related to irrelevant ids (#3901)
- Fix to transformation that adds a synonym via a loop (#3898)
- Fix to duplicate region with selection (#3896)
- Do not expose synonym facts for non-existent ids (#3891)
- Do not add synonyms involving irrelevant ids (#3890)
- Do not replace irrelevant ids that are not in blocks (#3892)
- Wrap OpKill and similar in function calls (#3884)
- Integrate spirv-reduce with shrinker (#3849)
- Report fresh ids in transformations (#3856)
- Support OpNot bit instruction case (#3841)
- Return IR and transformation context after replay (#3846)
v2020.5 2020-09-22
- General

View File

@@ -1 +1 @@
"v2020.6", "SPIRV-Tools v2020.6 475fea23bc1061461168fd99de41ebc8ee321b3b"
"v2020.7-dev", "SPIRV-Tools v2020.7-dev c73d8d8cf8076c3848338cc5a5f63d291afa2989"

View File

@@ -171,6 +171,10 @@ static const int kInstErrorBindlessBounds = 0;
static const int kInstErrorBindlessUninit = 1;
static const int kInstErrorBuffAddrUnallocRef = 2;
static const int kInstErrorBindlessBuffOOB = 3;
static const int kInstErrorBuffOOBUniform = 4;
static const int kInstErrorBuffOOBStorage = 5;
static const int kInstErrorBuffOOBUniformTexel = 6;
static const int kInstErrorBuffOOBStorageTexel = 7;
// Direct Input Buffer Offsets
//

View File

@@ -747,12 +747,16 @@ Optimizer::PassToken CreateCombineAccessChainsPass();
// The instrumentation will read and write buffers in debug
// descriptor set |desc_set|. It will write |shader_id| in each output record
// to identify the shader module which generated the record.
// |input_length_enable| controls instrumentation of runtime descriptor array
// references, and |input_init_enable| controls instrumentation of descriptor
// initialization checking, both of which require input buffer support.
// |desc_length_enable| controls instrumentation of runtime descriptor array
// references, |desc_init_enable| controls instrumentation of descriptor
// initialization checking, and |buff_oob_enable| controls instrumentation
// of storage and uniform buffer bounds checking, all of which require input
// buffer support. |texbuff_oob_enable| controls instrumentation of texel
// buffers, which does not require input buffer support.
Optimizer::PassToken CreateInstBindlessCheckPass(
uint32_t desc_set, uint32_t shader_id, bool input_length_enable = false,
bool input_init_enable = false, bool input_buff_oob_enable = false);
uint32_t desc_set, uint32_t shader_id, bool desc_length_enable = false,
bool desc_init_enable = false, bool buff_oob_enable = false,
bool texbuff_oob_enable = false);
// Create a pass to instrument physical buffer address checking
// This pass instruments all physical buffer address references to check that

View File

@@ -991,6 +991,7 @@ void AggressiveDCEPass::InitExtensions() {
"SPV_NV_mesh_shader",
"SPV_NV_ray_tracing",
"SPV_KHR_ray_tracing",
"SPV_KHR_ray_query",
"SPV_EXT_fragment_invocation_density",
"SPV_EXT_physical_storage_buffer",
"SPV_KHR_terminate_invocation",

View File

@@ -228,15 +228,10 @@ void EliminateDeadMembersPass::MarkMembersAsLiveForAccessChain(
const_mgr->FindDeclaredConstant(inst->GetSingleWordInOperand(i))
->AsIntConstant();
assert(member_idx);
if (member_idx->type()->AsInteger()->width() == 32) {
used_members_[type_id].insert(member_idx->GetU32());
type_id = type_inst->GetSingleWordInOperand(member_idx->GetU32());
} else {
used_members_[type_id].insert(
static_cast<uint32_t>(member_idx->GetU64()));
type_id = type_inst->GetSingleWordInOperand(
static_cast<uint32_t>(member_idx->GetU64()));
}
uint32_t index =
static_cast<uint32_t>(member_idx->GetZeroExtendedValue());
used_members_[type_id].insert(index);
type_id = type_inst->GetSingleWordInOperand(index);
} break;
case SpvOpTypeArray:
case SpvOpTypeRuntimeArray:
@@ -477,12 +472,8 @@ bool EliminateDeadMembersPass::UpdateAccessChain(Instruction* inst) {
const_mgr->FindDeclaredConstant(inst->GetSingleWordInOperand(i))
->AsIntConstant();
assert(member_idx);
uint32_t orig_member_idx;
if (member_idx->type()->AsInteger()->width() == 32) {
orig_member_idx = member_idx->GetU32();
} else {
orig_member_idx = static_cast<uint32_t>(member_idx->GetU64());
}
uint32_t orig_member_idx =
static_cast<uint32_t>(member_idx->GetZeroExtendedValue());
uint32_t new_member_idx = GetNewMemberIndex(type_id, orig_member_idx);
assert(new_member_idx != kRemovedMember);
if (orig_member_idx != new_member_idx) {

View File

@@ -23,13 +23,17 @@ static const int kSpvImageSampleImageIdInIdx = 0;
static const int kSpvSampledImageImageIdInIdx = 0;
static const int kSpvSampledImageSamplerIdInIdx = 1;
static const int kSpvImageSampledImageIdInIdx = 0;
static const int kSpvCopyObjectOperandIdInIdx = 0;
static const int kSpvLoadPtrIdInIdx = 0;
static const int kSpvAccessChainBaseIdInIdx = 0;
static const int kSpvAccessChainIndex0IdInIdx = 1;
static const int kSpvTypeArrayLengthIdInIdx = 1;
static const int kSpvConstantValueInIdx = 0;
static const int kSpvVariableStorageClassInIdx = 0;
static const int kSpvTypeImageDim = 1;
static const int kSpvTypeImageDepth = 2;
static const int kSpvTypeImageArrayed = 3;
static const int kSpvTypeImageMS = 4;
} // anonymous namespace
// Avoid unused variable warning/error on Linux
@@ -75,42 +79,51 @@ uint32_t InstBindlessCheckPass::GenDebugReadInit(uint32_t var_id,
}
}
uint32_t InstBindlessCheckPass::CloneOriginalImage(
uint32_t old_image_id, InstructionBuilder* builder) {
Instruction* new_image_inst;
Instruction* old_image_inst = get_def_use_mgr()->GetDef(old_image_id);
if (old_image_inst->opcode() == SpvOpLoad) {
new_image_inst = builder->AddLoad(
old_image_inst->type_id(),
old_image_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx));
} else if (old_image_inst->opcode() == SpvOp::SpvOpSampledImage) {
uint32_t clone_id = CloneOriginalImage(
old_image_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx),
builder);
new_image_inst = builder->AddBinaryOp(
old_image_inst->type_id(), SpvOpSampledImage, clone_id,
old_image_inst->GetSingleWordInOperand(kSpvSampledImageSamplerIdInIdx));
} else if (old_image_inst->opcode() == SpvOp::SpvOpImage) {
uint32_t clone_id = CloneOriginalImage(
old_image_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx),
builder);
new_image_inst =
builder->AddUnaryOp(old_image_inst->type_id(), SpvOpImage, clone_id);
} else {
assert(old_image_inst->opcode() == SpvOp::SpvOpCopyObject &&
"expecting OpCopyObject");
uint32_t clone_id = CloneOriginalImage(
old_image_inst->GetSingleWordInOperand(kSpvCopyObjectOperandIdInIdx),
builder);
// Since we are cloning, no need to create new copy
new_image_inst = get_def_use_mgr()->GetDef(clone_id);
}
uid2offset_[new_image_inst->unique_id()] =
uid2offset_[old_image_inst->unique_id()];
uint32_t new_image_id = new_image_inst->result_id();
get_decoration_mgr()->CloneDecorations(old_image_id, new_image_id);
return new_image_id;
}
uint32_t InstBindlessCheckPass::CloneOriginalReference(
ref_analysis* ref, InstructionBuilder* builder) {
RefAnalysis* ref, InstructionBuilder* builder) {
// If original is image based, start by cloning descriptor load
uint32_t new_image_id = 0;
if (ref->desc_load_id != 0) {
Instruction* desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id);
Instruction* new_load_inst = builder->AddLoad(
desc_load_inst->type_id(),
desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx));
uid2offset_[new_load_inst->unique_id()] =
uid2offset_[desc_load_inst->unique_id()];
uint32_t new_load_id = new_load_inst->result_id();
get_decoration_mgr()->CloneDecorations(desc_load_inst->result_id(),
new_load_id);
new_image_id = new_load_id;
// Clone Image/SampledImage with new load, if needed
if (ref->image_id != 0) {
Instruction* image_inst = get_def_use_mgr()->GetDef(ref->image_id);
if (image_inst->opcode() == SpvOp::SpvOpSampledImage) {
Instruction* new_image_inst = builder->AddBinaryOp(
image_inst->type_id(), SpvOpSampledImage, new_load_id,
image_inst->GetSingleWordInOperand(kSpvSampledImageSamplerIdInIdx));
uid2offset_[new_image_inst->unique_id()] =
uid2offset_[image_inst->unique_id()];
new_image_id = new_image_inst->result_id();
} else {
assert(image_inst->opcode() == SpvOp::SpvOpImage &&
"expecting OpImage");
Instruction* new_image_inst =
builder->AddUnaryOp(image_inst->type_id(), SpvOpImage, new_load_id);
uid2offset_[new_image_inst->unique_id()] =
uid2offset_[image_inst->unique_id()];
new_image_id = new_image_inst->result_id();
}
get_decoration_mgr()->CloneDecorations(ref->image_id, new_image_id);
}
uint32_t old_image_id =
ref->ref_inst->GetSingleWordInOperand(kSpvImageSampleImageIdInIdx);
new_image_id = CloneOriginalImage(old_image_id, builder);
}
// Clone original reference
std::unique_ptr<Instruction> new_ref_inst(ref->ref_inst->Clone(context()));
@@ -179,7 +192,7 @@ Instruction* InstBindlessCheckPass::GetPointeeTypeInst(Instruction* ptr_inst) {
}
bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst,
ref_analysis* ref) {
RefAnalysis* ref) {
ref->ref_inst = ref_inst;
if (ref_inst->opcode() == SpvOpLoad || ref_inst->opcode() == SpvOpStore) {
ref->desc_load_id = 0;
@@ -220,25 +233,28 @@ bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst,
// Reference is not load or store. If not an image-based reference, return.
ref->image_id = GetImageId(ref_inst);
if (ref->image_id == 0) return false;
Instruction* image_inst = get_def_use_mgr()->GetDef(ref->image_id);
Instruction* desc_load_inst = nullptr;
if (image_inst->opcode() == SpvOp::SpvOpSampledImage) {
ref->desc_load_id =
image_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx);
desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id);
} else if (image_inst->opcode() == SpvOp::SpvOpImage) {
ref->desc_load_id =
image_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx);
desc_load_inst = get_def_use_mgr()->GetDef(ref->desc_load_id);
} else {
ref->desc_load_id = ref->image_id;
desc_load_inst = image_inst;
ref->image_id = 0;
// Search for descriptor load
uint32_t desc_load_id = ref->image_id;
Instruction* desc_load_inst;
for (;;) {
desc_load_inst = get_def_use_mgr()->GetDef(desc_load_id);
if (desc_load_inst->opcode() == SpvOp::SpvOpSampledImage)
desc_load_id =
desc_load_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx);
else if (desc_load_inst->opcode() == SpvOp::SpvOpImage)
desc_load_id =
desc_load_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx);
else if (desc_load_inst->opcode() == SpvOp::SpvOpCopyObject)
desc_load_id =
desc_load_inst->GetSingleWordInOperand(kSpvCopyObjectOperandIdInIdx);
else
break;
}
if (desc_load_inst->opcode() != SpvOp::SpvOpLoad) {
// TODO(greg-lunarg): Handle additional possibilities?
return false;
}
ref->desc_load_id = desc_load_id;
ref->ptr_id = desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx);
Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref->ptr_id);
if (ptr_inst->opcode() == SpvOp::SpvOpVariable) {
@@ -322,7 +338,7 @@ uint32_t InstBindlessCheckPass::ByteSize(uint32_t ty_id, uint32_t matrix_stride,
return size;
}
uint32_t InstBindlessCheckPass::GenLastByteIdx(ref_analysis* ref,
uint32_t InstBindlessCheckPass::GenLastByteIdx(RefAnalysis* ref,
InstructionBuilder* builder) {
// Find outermost buffer type and its access chain index
Instruction* var_inst = get_def_use_mgr()->GetDef(ref->var_id);
@@ -474,7 +490,7 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(ref_analysis* ref,
void InstBindlessCheckPass::GenCheckCode(
uint32_t check_id, uint32_t error_id, uint32_t offset_id,
uint32_t length_id, uint32_t stage_idx, ref_analysis* ref,
uint32_t length_id, uint32_t stage_idx, RefAnalysis* ref,
std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
BasicBlock* back_blk_ptr = &*new_blocks->back();
InstructionBuilder builder(
@@ -508,7 +524,7 @@ void InstBindlessCheckPass::GenCheckCode(
GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx,
{error_id, u_index_id, u_offset_id, u_length_id},
&builder);
} else if (buffer_bounds_enabled_) {
} else if (buffer_bounds_enabled_ || texel_buffer_enabled_) {
// Uninitialized Descriptor - Return additional unused zero so all error
// modes will use same debug stream write function
uint32_t u_length_id = GenUintCastCode(length_id, &builder);
@@ -551,7 +567,7 @@ void InstBindlessCheckPass::GenDescIdxCheckCode(
std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
// Look for reference through indexed descriptor. If found, analyze and
// save components. If not, return.
ref_analysis ref;
RefAnalysis ref;
if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return;
Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref.ptr_id);
if (ptr_inst->opcode() != SpvOp::SpvOpAccessChain) return;
@@ -610,7 +626,7 @@ void InstBindlessCheckPass::GenDescInitCheckCode(
UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
// Look for reference through descriptor. If not, return.
ref_analysis ref;
RefAnalysis ref;
if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return;
// Determine if we can only do initialization check
bool init_check = false;
@@ -661,12 +677,77 @@ void InstBindlessCheckPass::GenDescInitCheckCode(
MovePostludeCode(ref_block_itr, back_blk_ptr);
}
void InstBindlessCheckPass::GenTexBuffCheckCode(
BasicBlock::iterator ref_inst_itr,
UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
// Only process OpImageRead and OpImageWrite with no optional operands
Instruction* ref_inst = &*ref_inst_itr;
SpvOp op = ref_inst->opcode();
uint32_t num_in_oprnds = ref_inst->NumInOperands();
if (!((op == SpvOpImageRead && num_in_oprnds == 2) ||
(op == SpvOpImageFetch && num_in_oprnds == 2) ||
(op == SpvOpImageWrite && num_in_oprnds == 3)))
return;
// Pull components from descriptor reference
RefAnalysis ref;
if (!AnalyzeDescriptorReference(ref_inst, &ref)) return;
// Only process if image is texel buffer
Instruction* image_inst = get_def_use_mgr()->GetDef(ref.image_id);
uint32_t image_ty_id = image_inst->type_id();
Instruction* image_ty_inst = get_def_use_mgr()->GetDef(image_ty_id);
if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDim) != SpvDimBuffer)
return;
if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDepth) != 0) return;
if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageArrayed) != 0) return;
if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageMS) != 0) return;
// Enable ImageQuery Capability if not yet enabled
if (!get_feature_mgr()->HasCapability(SpvCapabilityImageQuery)) {
std::unique_ptr<Instruction> cap_image_query_inst(new Instruction(
context(), SpvOpCapability, 0, 0,
std::initializer_list<Operand>{
{SPV_OPERAND_TYPE_CAPABILITY, {SpvCapabilityImageQuery}}}));
get_def_use_mgr()->AnalyzeInstDefUse(&*cap_image_query_inst);
context()->AddCapability(std::move(cap_image_query_inst));
}
// Move original block's preceding instructions into first new block
std::unique_ptr<BasicBlock> new_blk_ptr;
MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr);
InstructionBuilder builder(
context(), &*new_blk_ptr,
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
new_blocks->push_back(std::move(new_blk_ptr));
// Get texel coordinate
uint32_t coord_id =
GenUintCastCode(ref_inst->GetSingleWordInOperand(1), &builder);
// If index id not yet set, binding is single descriptor, so set index to
// constant 0.
if (ref.desc_idx_id == 0) ref.desc_idx_id = builder.GetUintConstantId(0u);
// Get texel buffer size.
Instruction* size_inst =
builder.AddUnaryOp(GetUintId(), SpvOpImageQuerySize, ref.image_id);
uint32_t size_id = size_inst->result_id();
// Generate runtime initialization/bounds test code with true branch
// being full reference and false branch being debug output and zero
// for the referenced value.
Instruction* ult_inst =
builder.AddBinaryOp(GetBoolId(), SpvOpULessThan, coord_id, size_id);
uint32_t error_id = builder.GetUintConstantId(kInstErrorBindlessBuffOOB);
GenCheckCode(ult_inst->result_id(), error_id, coord_id, size_id, stage_idx,
&ref, new_blocks);
// Move original block's remaining code into remainder/merge block and add
// to new blocks
BasicBlock* back_blk_ptr = &*new_blocks->back();
MovePostludeCode(ref_block_itr, back_blk_ptr);
}
void InstBindlessCheckPass::InitializeInstBindlessCheck() {
// Initialize base class
InitializeInstrument();
// If runtime array length support enabled, create variable mappings. Length
// support is always enabled if descriptor init check is enabled.
if (desc_idx_enabled_ || buffer_bounds_enabled_)
// If runtime array length support or buffer bounds checking are enabled,
// create variable mappings. Length support is always enabled if descriptor
// init check is enabled.
if (desc_idx_enabled_ || buffer_bounds_enabled_ || texel_buffer_enabled_)
for (auto& anno : get_module()->annotations())
if (anno.opcode() == SpvOpDecorate) {
if (anno.GetSingleWordInOperand(1u) == SpvDecorationDescriptorSet)
@@ -689,8 +770,8 @@ Pass::Status InstBindlessCheckPass::ProcessImpl() {
};
bool modified = InstProcessEntryPointCallTree(pfn);
if (desc_init_enabled_ || buffer_bounds_enabled_) {
// Perform descriptor initialization check on each entry point function in
// module
// Perform descriptor initialization and/or buffer bounds check on each
// entry point function in module
pfn = [this](BasicBlock::iterator ref_inst_itr,
UptrVectorIterator<BasicBlock> ref_block_itr,
uint32_t stage_idx,
@@ -700,6 +781,18 @@ Pass::Status InstBindlessCheckPass::ProcessImpl() {
};
modified |= InstProcessEntryPointCallTree(pfn);
}
if (texel_buffer_enabled_) {
// Perform texel buffer bounds check on each entry point function in
// module. Generate after descriptor bounds and initialization checks.
pfn = [this](BasicBlock::iterator ref_inst_itr,
UptrVectorIterator<BasicBlock> ref_block_itr,
uint32_t stage_idx,
std::vector<std::unique_ptr<BasicBlock>>* new_blocks) {
return GenTexBuffCheckCode(ref_inst_itr, ref_block_itr, stage_idx,
new_blocks);
};
modified |= InstProcessEntryPointCallTree(pfn);
}
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}

View File

@@ -28,24 +28,16 @@ namespace opt {
// external design may change as the layer evolves.
class InstBindlessCheckPass : public InstrumentPass {
public:
// Old interface to support testing pre-buffer-overrun capability
InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id,
bool desc_idx_enable, bool desc_init_enable)
: InstrumentPass(desc_set, shader_id, kInstValidationIdBindless, false),
desc_idx_enabled_(desc_idx_enable),
desc_init_enabled_(desc_init_enable),
buffer_bounds_enabled_(false) {}
// New interface supporting buffer overrun checking
InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id,
bool desc_idx_enable, bool desc_init_enable,
bool buffer_bounds_enable)
: InstrumentPass(
desc_set, shader_id, kInstValidationIdBindless,
desc_idx_enable || desc_init_enable || buffer_bounds_enable),
bool buffer_bounds_enable, bool texel_buffer_enable,
bool opt_direct_reads)
: InstrumentPass(desc_set, shader_id, kInstValidationIdBindless,
opt_direct_reads),
desc_idx_enabled_(desc_idx_enable),
desc_init_enabled_(desc_init_enable),
buffer_bounds_enabled_(buffer_bounds_enable) {}
buffer_bounds_enabled_(buffer_bounds_enable),
texel_buffer_enabled_(texel_buffer_enable) {}
~InstBindlessCheckPass() override = default;
@@ -63,6 +55,10 @@ class InstBindlessCheckPass : public InstrumentPass {
// checks that the referenced descriptor has been initialized, if the
// SPV_EXT_descriptor_indexing extension is enabled, and initialized large
// enough to handle the reference, if RobustBufferAccess is disabled.
// GenDescInitCheckCode checks for uniform and storage buffer overrun.
// GenTexBuffCheckCode checks for texel buffer overrun and should be
// run after GenDescInitCheckCode to first make sure that the descriptor
// is initialized because it uses OpImageQuerySize on the descriptor.
//
// The functions are designed to be passed to
// InstrumentPass::InstProcessEntryPointCallTree(), which applies the
@@ -109,6 +105,11 @@ class InstBindlessCheckPass : public InstrumentPass {
UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
void GenTexBuffCheckCode(
BasicBlock::iterator ref_inst_itr,
UptrVectorIterator<BasicBlock> ref_block_itr, uint32_t stage_idx,
std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
// Generate instructions into |builder| to read length of runtime descriptor
// array |var_id| from debug input buffer and return id of value.
uint32_t GenDebugReadLength(uint32_t var_id, InstructionBuilder* builder);
@@ -122,7 +123,7 @@ class InstBindlessCheckPass : public InstrumentPass {
// Analysis data for descriptor reference components, generated by
// AnalyzeDescriptorReference. It is necessary and sufficient for further
// analysis and regeneration of the reference.
typedef struct ref_analysis {
typedef struct RefAnalysis {
uint32_t desc_load_id;
uint32_t image_id;
uint32_t load_id;
@@ -130,7 +131,7 @@ class InstBindlessCheckPass : public InstrumentPass {
uint32_t var_id;
uint32_t desc_idx_id;
Instruction* ref_inst;
} ref_analysis;
} RefAnalysis;
// Return size of type |ty_id| in bytes. Use |matrix_stride| and |col_major|
// for matrix type, or for vector type if vector is |in_matrix|.
@@ -142,11 +143,15 @@ class InstBindlessCheckPass : public InstrumentPass {
uint32_t FindStride(uint32_t ty_id, uint32_t stride_deco);
// Generate index of last byte referenced by buffer reference |ref|
uint32_t GenLastByteIdx(ref_analysis* ref, InstructionBuilder* builder);
uint32_t GenLastByteIdx(RefAnalysis* ref, InstructionBuilder* builder);
// Clone original image computation starting at |image_id| into |builder|.
// This may generate more than one instruction if neccessary.
uint32_t CloneOriginalImage(uint32_t image_id, InstructionBuilder* builder);
// Clone original original reference encapsulated by |ref| into |builder|.
// This may generate more than one instruction if neccessary.
uint32_t CloneOriginalReference(ref_analysis* ref,
uint32_t CloneOriginalReference(RefAnalysis* ref,
InstructionBuilder* builder);
// If |inst| references through an image, return the id of the image it
@@ -158,7 +163,7 @@ class InstBindlessCheckPass : public InstrumentPass {
// Analyze descriptor reference |ref_inst| and save components into |ref|.
// Return true if |ref_inst| is a descriptor reference, false otherwise.
bool AnalyzeDescriptorReference(Instruction* ref_inst, ref_analysis* ref);
bool AnalyzeDescriptorReference(Instruction* ref_inst, RefAnalysis* ref);
// Generate instrumentation code for generic test result |check_id|, starting
// with |builder| of block |new_blk_ptr|, adding new blocks to |new_blocks|.
@@ -168,7 +173,7 @@ class InstBindlessCheckPass : public InstrumentPass {
// |stage_idx|. Generate merge block for valid and invalid branches. Kill
// original reference.
void GenCheckCode(uint32_t check_id, uint32_t error_id, uint32_t offset_id,
uint32_t length_id, uint32_t stage_idx, ref_analysis* ref,
uint32_t length_id, uint32_t stage_idx, RefAnalysis* ref,
std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
// Initialize state for instrumenting bindless checking
@@ -184,9 +189,12 @@ class InstBindlessCheckPass : public InstrumentPass {
// Enable instrumentation of descriptor initialization checking
bool desc_init_enabled_;
// Enable instrumentation of buffer overrun checking
// Enable instrumentation of uniform and storage buffer overrun checking
bool buffer_bounds_enabled_;
// Enable instrumentation of texel buffer overrun checking
bool texel_buffer_enabled_;
// Mapping from variable to descriptor set
std::unordered_map<uint32_t, uint32_t> var2desc_set_;

View File

@@ -425,7 +425,7 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) {
RegisterPass(CreateBlockMergePass());
RegisterPass(CreateAggressiveDCEPass());
} else if (pass_name == "inst-buff-oob-check") {
RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, true));
RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, true, true));
RegisterPass(CreateSimplificationPass());
RegisterPass(CreateDeadBranchElimPass());
RegisterPass(CreateBlockMergePass());
@@ -892,15 +892,14 @@ Optimizer::PassToken CreateUpgradeMemoryModelPass() {
MakeUnique<opt::UpgradeMemoryModel>());
}
Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t desc_set,
uint32_t shader_id,
bool input_length_enable,
bool input_init_enable,
bool input_buff_oob_enable) {
Optimizer::PassToken CreateInstBindlessCheckPass(
uint32_t desc_set, uint32_t shader_id, bool desc_length_enable,
bool desc_init_enable, bool buff_oob_enable, bool texbuff_oob_enable) {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::InstBindlessCheckPass>(
desc_set, shader_id, input_length_enable, input_init_enable,
input_buff_oob_enable));
desc_set, shader_id, desc_length_enable, desc_init_enable,
buff_oob_enable, texbuff_oob_enable,
desc_length_enable || desc_init_enable || buff_oob_enable));
}
Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set,

View File

@@ -16,6 +16,7 @@
// Validates correctness of built-in variables.
#include <array>
#include <functional>
#include <list>
#include <map>
@@ -134,6 +135,114 @@ bool IsBuiltInValidForWebGPU(SpvBuiltIn label) {
return false;
}
typedef enum VUIDError_ {
VUIDErrorExecutionModel = 0,
VUIDErrorStorageClass = 1,
VUIDErrorType = 2,
VUIDErrorMax,
} VUIDError;
const static uint32_t NumRtBuiltins = 16;
typedef struct {
SpvBuiltIn builtIn;
uint32_t vuid[VUIDErrorMax]; // execution mode, storage class, type VUIDs
} RtBuiltinVUIDMapping;
std::array<RtBuiltinVUIDMapping, NumRtBuiltins> rtBuiltinInfo = {{
// clang-format off
{SpvBuiltInHitKindKHR, {4242, 4243, 4244}},
{SpvBuiltInHitTNV, {4245, 4246, 4247}},
{SpvBuiltInInstanceCustomIndexKHR, {4251, 4252, 4253}},
{SpvBuiltInInstanceId, {4254, 4255, 4256}},
{SpvBuiltInRayGeometryIndexKHR, {4345, 4346, 4347}},
{SpvBuiltInObjectRayDirectionKHR, {4299, 4300, 4301}},
{SpvBuiltInObjectRayOriginKHR, {4302, 4303, 4304}},
{SpvBuiltInObjectToWorldKHR, {4305, 4306, 4307}},
{SpvBuiltInWorldToObjectKHR, {4434, 4435, 4436}},
{SpvBuiltInIncomingRayFlagsKHR, {4248, 4249, 4250}},
{SpvBuiltInRayTminKHR, {4351, 4352, 4353}},
{SpvBuiltInRayTmaxKHR, {4348, 4349, 4350}},
{SpvBuiltInWorldRayDirectionKHR, {4428, 4429, 4430}},
{SpvBuiltInWorldRayOriginKHR, {4431, 4432, 4433}},
{SpvBuiltInLaunchIdKHR, {4266, 4267, 4268}},
{SpvBuiltInLaunchSizeKHR, {4269, 4270, 4271}},
// clang-format off
} };
uint32_t GetVUIDForRTBuiltin(SpvBuiltIn builtIn, VUIDError type) {
uint32_t vuid = 0;
for (const auto& iter: rtBuiltinInfo) {
if (iter.builtIn == builtIn) {
assert(type < VUIDErrorMax);
vuid = iter.vuid[type];
break;
}
}
return vuid;
}
bool IsExecutionModelValidForRtBuiltIn(SpvBuiltIn builtin,
SpvExecutionModel stage) {
switch (builtin) {
case SpvBuiltInHitKindKHR:
case SpvBuiltInHitTNV:
if (stage == SpvExecutionModelAnyHitKHR ||
stage == SpvExecutionModelClosestHitKHR) {
return true;
}
break;
case SpvBuiltInInstanceCustomIndexKHR:
case SpvBuiltInInstanceId:
case SpvBuiltInRayGeometryIndexKHR:
case SpvBuiltInObjectRayDirectionKHR:
case SpvBuiltInObjectRayOriginKHR:
case SpvBuiltInObjectToWorldKHR:
case SpvBuiltInWorldToObjectKHR:
switch (stage) {
case SpvExecutionModelIntersectionKHR:
case SpvExecutionModelAnyHitKHR:
case SpvExecutionModelClosestHitKHR:
return true;
default:
return false;
}
break;
case SpvBuiltInIncomingRayFlagsKHR:
case SpvBuiltInRayTminKHR:
case SpvBuiltInRayTmaxKHR:
case SpvBuiltInWorldRayDirectionKHR:
case SpvBuiltInWorldRayOriginKHR:
switch (stage) {
case SpvExecutionModelIntersectionKHR:
case SpvExecutionModelAnyHitKHR:
case SpvExecutionModelClosestHitKHR:
case SpvExecutionModelMissKHR:
return true;
default:
return false;
}
break;
case SpvBuiltInLaunchIdKHR:
case SpvBuiltInLaunchSizeKHR:
switch (stage) {
case SpvExecutionModelRayGenerationKHR:
case SpvExecutionModelIntersectionKHR:
case SpvExecutionModelAnyHitKHR:
case SpvExecutionModelClosestHitKHR:
case SpvExecutionModelMissKHR:
case SpvExecutionModelCallableKHR:
return true;
default:
return false;
}
break;
default:
break;
}
return false;
}
// Helper class managing validation of built-ins.
// TODO: Generic functionality of this class can be moved into
// ValidationState_t to be made available to other users.
@@ -200,8 +309,8 @@ class BuiltInsValidator {
const Instruction& inst);
spv_result_t ValidateVertexIndexAtDefinition(const Decoration& decoration,
const Instruction& inst);
spv_result_t ValidateVertexIdOrInstanceIdAtDefinition(
const Decoration& decoration, const Instruction& inst);
spv_result_t ValidateVertexIdAtDefinition(const Decoration& decoration,
const Instruction& inst);
spv_result_t ValidateLocalInvocationIndexAtDefinition(
const Decoration& decoration, const Instruction& inst);
spv_result_t ValidateWorkgroupSizeAtDefinition(const Decoration& decoration,
@@ -237,6 +346,9 @@ class BuiltInsValidator {
spv_result_t ValidateShadingRateAtDefinition(const Decoration& decoration,
const Instruction& inst);
spv_result_t ValidateRayTracingBuiltinsAtDefinition(
const Decoration& decoration, const Instruction& inst);
// The following section contains functions which are called when id defined
// by |referenced_inst| is
// 1. referenced by |referenced_from_inst|
@@ -269,11 +381,6 @@ class BuiltInsValidator {
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);
spv_result_t ValidateInstanceIdAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);
spv_result_t ValidateInstanceIndexAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
@@ -400,6 +507,11 @@ class BuiltInsValidator {
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);
spv_result_t ValidateRayTracingBuiltinsAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst);
// Validates that |built_in_inst| is not (even indirectly) referenced from
// within a function which can be called with |execution_model|.
//
@@ -476,6 +588,10 @@ class BuiltInsValidator {
uint32_t num_components,
const std::function<spv_result_t(const std::string& message)>& diag,
uint32_t underlying_type);
spv_result_t ValidateF32Mat(
const Decoration& decoration, const Instruction& inst,
uint32_t req_num_rows, uint32_t req_num_columns,
const std::function<spv_result_t(const std::string& message)>& diag);
// Generates strings like "Member #0 of struct ID <2>".
std::string GetDefinitionDesc(const Decoration& decoration,
@@ -909,6 +1025,32 @@ spv_result_t BuiltInsValidator::ValidateF32ArrHelper(
return SPV_SUCCESS;
}
spv_result_t BuiltInsValidator::ValidateF32Mat(
const Decoration& decoration, const Instruction& inst,
uint32_t req_num_rows, uint32_t req_num_columns,
const std::function<spv_result_t(const std::string& message)>& diag) {
uint32_t underlying_type = 0;
uint32_t num_rows = 0;
uint32_t num_cols = 0;
uint32_t col_type = 0;
uint32_t component_type = 0;
if (spv_result_t error =
GetUnderlyingType(_, decoration, inst, &underlying_type)) {
return error;
}
if (!_.GetMatrixTypeInfo(underlying_type, &num_rows, &num_cols, &col_type,
&component_type) ||
num_rows != req_num_rows || num_cols != req_num_columns) {
std::ostringstream ss;
ss << GetDefinitionDesc(decoration, inst) << " has columns " << num_cols
<< " and rows " << num_rows << " not equal to expected "
<< req_num_columns << "x" << req_num_rows << ".";
return diag(ss.str());
}
return ValidateF32VecHelper(decoration, inst, req_num_rows, diag, col_type);
}
spv_result_t BuiltInsValidator::ValidateNotCalledWithExecutionModel(
int vuid, const char* comment, SpvExecutionModel execution_model,
const Decoration& decoration, const Instruction& built_in_inst,
@@ -1947,6 +2089,27 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtReference(
"Fragment.",
SpvExecutionModelFragment, decoration, built_in_inst,
referenced_from_inst, std::placeholders::_1));
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
&BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
"Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
"variables with Output storage class if execution model is "
"IntersectionKHR.",
SpvExecutionModelIntersectionKHR, decoration, built_in_inst,
referenced_from_inst, std::placeholders::_1));
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
&BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
"Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
"variables with Output storage class if execution model is "
"AnyHitKHR.",
SpvExecutionModelAnyHitKHR, decoration, built_in_inst,
referenced_from_inst, std::placeholders::_1));
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
&BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4334,
"Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
"variables with Output storage class if execution model is "
"ClosestHitKHR.",
SpvExecutionModelClosestHitKHR, decoration, built_in_inst,
referenced_from_inst, std::placeholders::_1));
}
for (const SpvExecutionModel execution_model : execution_models_) {
@@ -1956,12 +2119,9 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtReference(
case SpvExecutionModelTessellationEvaluation:
case SpvExecutionModelGeometry:
case SpvExecutionModelMeshNV:
case SpvExecutionModelRayGenerationNV:
case SpvExecutionModelIntersectionNV:
case SpvExecutionModelAnyHitNV:
case SpvExecutionModelClosestHitNV:
case SpvExecutionModelMissNV:
case SpvExecutionModelCallableNV: {
case SpvExecutionModelIntersectionKHR:
case SpvExecutionModelAnyHitKHR:
case SpvExecutionModelClosestHitKHR: {
// Ok.
break;
}
@@ -1971,7 +2131,9 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtReference(
<< _.VkErrorID(4330)
<< "Vulkan spec allows BuiltIn PrimitiveId to be used only "
"with Fragment, TessellationControl, "
"TessellationEvaluation or Geometry execution models. "
"TessellationEvaluation, Geometry, MeshNV, "
"IntersectionKHR, "
"AnyHitKHR, and ClosestHitKHR execution models. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst, execution_model);
}
@@ -2372,54 +2534,13 @@ spv_result_t BuiltInsValidator::ValidateVertexIndexAtDefinition(
return ValidateVertexIndexAtReference(decoration, inst, inst, inst);
}
spv_result_t BuiltInsValidator::ValidateVertexIdOrInstanceIdAtDefinition(
spv_result_t BuiltInsValidator::ValidateVertexIdAtDefinition(
const Decoration& decoration, const Instruction& inst) {
const SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]);
bool allow_instance_id = (_.HasCapability(SpvCapabilityRayTracingNV) ||
_.HasCapability(SpvCapabilityRayTracingKHR)) &&
label == SpvBuiltInInstanceId;
if (spvIsVulkanEnv(_.context()->target_env) && !allow_instance_id) {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< "Vulkan spec doesn't allow BuiltIn VertexId/InstanceId "
"to be used.";
}
if (label == SpvBuiltInInstanceId) {
return ValidateInstanceIdAtReference(decoration, inst, inst, inst);
}
return SPV_SUCCESS;
}
spv_result_t BuiltInsValidator::ValidateInstanceIdAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
(void)decoration;
if (spvIsVulkanEnv(_.context()->target_env)) {
for (const SpvExecutionModel execution_model : execution_models_) {
switch (execution_model) {
case SpvExecutionModelIntersectionNV:
case SpvExecutionModelClosestHitNV:
case SpvExecutionModelAnyHitNV:
// Do nothing, valid stages
break;
default:
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
<< "Vulkan spec allows BuiltIn InstanceId to be used "
"only with IntersectionNV, ClosestHitNV and AnyHitNV "
"execution models. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst);
break;
}
}
}
if (function_id_ == 0) {
// Propagate this rule to all dependant ids in the global scope.
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind(
&BuiltInsValidator::ValidateInstanceIdAtReference, this, decoration,
built_in_inst, referenced_from_inst, std::placeholders::_1));
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< "Vulkan spec doesn't allow BuiltIn VertexId "
"to be used.";
}
return SPV_SUCCESS;
@@ -3474,6 +3595,174 @@ spv_result_t BuiltInsValidator::ValidateShadingRateAtReference(
return SPV_SUCCESS;
}
spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition(
const Decoration& decoration, const Instruction& inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
switch (builtin) {
case SpvBuiltInHitTNV:
case SpvBuiltInRayTminKHR:
case SpvBuiltInRayTmaxKHR:
// f32 scalar
if (spv_result_t error = ValidateF32(
decoration, inst,
[this, &inst,
builtin](const std::string& message) -> spv_result_t {
uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType);
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid)
<< "According to the Vulkan spec BuiltIn "
<< _.grammar().lookupOperandName(
SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " variable needs to be a 32-bit float scalar. "
<< message;
})) {
return error;
}
break;
case SpvBuiltInHitKindKHR:
case SpvBuiltInInstanceCustomIndexKHR:
case SpvBuiltInInstanceId:
case SpvBuiltInRayGeometryIndexKHR:
case SpvBuiltInIncomingRayFlagsKHR:
// i32 scalar
if (spv_result_t error = ValidateI32(
decoration, inst,
[this, &inst,
builtin](const std::string& message) -> spv_result_t {
uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType);
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid)
<< "According to the Vulkan spec BuiltIn "
<< _.grammar().lookupOperandName(
SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " variable needs to be a 32-bit int scalar. "
<< message;
})) {
return error;
}
break;
case SpvBuiltInObjectRayDirectionKHR:
case SpvBuiltInObjectRayOriginKHR:
case SpvBuiltInWorldRayDirectionKHR:
case SpvBuiltInWorldRayOriginKHR:
// f32 vec3
if (spv_result_t error = ValidateF32Vec(
decoration, inst, 3,
[this, &inst,
builtin](const std::string& message) -> spv_result_t {
uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType);
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid)
<< "According to the Vulkan spec BuiltIn "
<< _.grammar().lookupOperandName(
SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " variable needs to be a 3-component 32-bit float "
"vector. "
<< message;
})) {
return error;
}
break;
case SpvBuiltInLaunchIdKHR:
case SpvBuiltInLaunchSizeKHR:
// i32 vec3
if (spv_result_t error = ValidateI32Vec(
decoration, inst, 3,
[this, &inst,
builtin](const std::string& message) -> spv_result_t {
uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType);
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid)
<< "According to the Vulkan spec BuiltIn "
<< _.grammar().lookupOperandName(
SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " variable needs to be a 3-component 32-bit int "
"vector. "
<< message;
})) {
return error;
}
break;
case SpvBuiltInObjectToWorldKHR:
case SpvBuiltInWorldToObjectKHR:
// f32 mat4x3
if (spv_result_t error = ValidateF32Mat(
decoration, inst, 3, 4,
[this, &inst,
builtin](const std::string& message) -> spv_result_t {
uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorType);
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
<< _.VkErrorID(vuid)
<< "According to the Vulkan spec BuiltIn "
<< _.grammar().lookupOperandName(
SPV_OPERAND_TYPE_BUILT_IN, builtin)
<< " variable needs to be a matrix with"
<< " 4 columns of 3-component vectors of 32-bit "
"floats. "
<< message;
})) {
return error;
}
break;
default:
assert(0 && "Unexpected ray tracing builtin");
break;
}
}
// Seed at reference checks with this built-in.
return ValidateRayTracingBuiltinsAtReference(decoration, inst, inst, inst);
}
spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference(
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
if (spvIsVulkanEnv(_.context()->target_env)) {
const SpvBuiltIn builtin = SpvBuiltIn(decoration.params()[0]);
const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput) {
uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorStorageClass);
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
<< _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " to be only used for variables with Input storage class. "
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst)
<< " " << GetStorageClassDesc(referenced_from_inst);
}
for (const SpvExecutionModel execution_model : execution_models_) {
if (!IsExecutionModelValidForRtBuiltIn(builtin, execution_model)) {
uint32_t vuid = GetVUIDForRTBuiltin(builtin, VUIDErrorExecutionModel);
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
<< _.VkErrorID(vuid) << "Vulkan spec does not allow BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " to be used with the execution model "
<< _.grammar().lookupOperandName(
SPV_OPERAND_TYPE_EXECUTION_MODEL, execution_model)
<< ".\n"
<< GetReferenceDesc(decoration, built_in_inst, referenced_inst,
referenced_from_inst, execution_model);
}
}
}
if (function_id_ == 0) {
// Propagate this rule to all dependant ids in the global scope.
id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
std::bind(&BuiltInsValidator::ValidateRayTracingBuiltinsAtReference,
this, decoration, built_in_inst, referenced_from_inst,
std::placeholders::_1));
}
return SPV_SUCCESS;
}
spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
const Decoration& decoration, const Instruction& inst) {
const SpvBuiltIn label = SpvBuiltIn(decoration.params()[0]);
@@ -3596,9 +3885,8 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
case SpvBuiltInWorkgroupSize: {
return ValidateWorkgroupSizeAtDefinition(decoration, inst);
}
case SpvBuiltInVertexId:
case SpvBuiltInInstanceId: {
return ValidateVertexIdOrInstanceIdAtDefinition(decoration, inst);
case SpvBuiltInVertexId: {
return ValidateVertexIdAtDefinition(decoration, inst);
}
case SpvBuiltInLocalInvocationIndex: {
return ValidateLocalInvocationIndexAtDefinition(decoration, inst);
@@ -3622,6 +3910,27 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
case SpvBuiltInDeviceIndex: {
return ValidateDeviceIndexAtDefinition(decoration, inst);
}
// Ray tracing builtins
case SpvBuiltInHitKindKHR: // alias SpvBuiltInHitKindNV
case SpvBuiltInHitTNV: // NOT present in KHR
case SpvBuiltInInstanceId:
case SpvBuiltInLaunchIdKHR: // alias SpvBuiltInLaunchIdNV
case SpvBuiltInLaunchSizeKHR: // alias SpvBuiltInLaunchSizeNV
case SpvBuiltInWorldRayOriginKHR: // alias SpvBuiltInWorldRayOriginNV
case SpvBuiltInWorldRayDirectionKHR: // alias SpvBuiltInWorldRayDirectionNV
case SpvBuiltInObjectRayOriginKHR: // alias SpvBuiltInObjectRayOriginNV
case SpvBuiltInObjectRayDirectionKHR: // alias
// SpvBuiltInObjectRayDirectionNV
case SpvBuiltInRayTminKHR: // alias SpvBuiltInRayTminNV
case SpvBuiltInRayTmaxKHR: // alias SpvBuiltInRayTmaxNV
case SpvBuiltInInstanceCustomIndexKHR: // alias
// SpvBuiltInInstanceCustomIndexNV
case SpvBuiltInObjectToWorldKHR: // alias SpvBuiltInObjectToWorldNV
case SpvBuiltInWorldToObjectKHR: // alias SpvBuiltInWorldToObjectNV
case SpvBuiltInIncomingRayFlagsKHR: // alias SpvBuiltInIncomingRayFlagsNV
case SpvBuiltInRayGeometryIndexKHR: { // NOT present in NV
return ValidateRayTracingBuiltinsAtDefinition(decoration, inst);
}
case SpvBuiltInWorkDim:
case SpvBuiltInGlobalSize:
case SpvBuiltInEnqueuedWorkgroupSize:
@@ -3657,28 +3966,14 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
case SpvBuiltInFragmentSizeNV: // alias SpvBuiltInFragSizeEXT
case SpvBuiltInInvocationsPerPixelNV: // alias
// SpvBuiltInFragInvocationCountEXT
case SpvBuiltInLaunchIdNV:
case SpvBuiltInLaunchSizeNV:
case SpvBuiltInWorldRayOriginNV:
case SpvBuiltInWorldRayDirectionNV:
case SpvBuiltInObjectRayOriginNV:
case SpvBuiltInObjectRayDirectionNV:
case SpvBuiltInRayTminNV:
case SpvBuiltInRayTmaxNV:
case SpvBuiltInInstanceCustomIndexNV:
case SpvBuiltInObjectToWorldNV:
case SpvBuiltInWorldToObjectNV:
case SpvBuiltInHitTNV:
case SpvBuiltInHitKindNV:
case SpvBuiltInIncomingRayFlagsNV:
case SpvBuiltInRayGeometryIndexKHR: {
// No validation rules (for the moment).
break;
case SpvBuiltInPrimitiveShadingRateKHR:
return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
case SpvBuiltInShadingRateKHR:
return ValidateShadingRateAtDefinition(decoration, inst);
case SpvBuiltInPrimitiveShadingRateKHR: {
return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
}
case SpvBuiltInShadingRateKHR: {
return ValidateShadingRateAtDefinition(decoration, inst);
}
}
return SPV_SUCCESS;

View File

@@ -1363,6 +1363,36 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04240);
case 4241:
return VUID_WRAP(VUID-HelperInvocation-HelperInvocation-04241);
case 4242:
return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04242);
case 4243:
return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04243);
case 4244:
return VUID_WRAP(VUID-HitKindKHR-HitKindKHR-04244);
case 4245:
return VUID_WRAP(VUID-HitTNV-HitTNV-04245);
case 4246:
return VUID_WRAP(VUID-HitTNV-HitTNV-04246);
case 4247:
return VUID_WRAP(VUID-HitTNV-HitTNV-04247);
case 4248:
return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04248);
case 4249:
return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04249);
case 4250:
return VUID_WRAP(VUID-IncomingRayFlagsKHR-IncomingRayFlagsKHR-04250);
case 4251:
return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04251);
case 4252:
return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04252);
case 4253:
return VUID_WRAP(VUID-InstanceCustomIndexKHR-InstanceCustomIndexKHR-04253);
case 4254:
return VUID_WRAP(VUID-InstanceId-InstanceId-04254);
case 4255:
return VUID_WRAP(VUID-InstanceId-InstanceId-04255);
case 4256:
return VUID_WRAP(VUID-InstanceId-InstanceId-04256);
case 4257:
return VUID_WRAP(VUID-InvocationId-InvocationId-04257);
case 4258:
@@ -1375,6 +1405,18 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04264);
case 4265:
return VUID_WRAP(VUID-InstanceIndex-InstanceIndex-04265);
case 4266:
return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04266);
case 4267:
return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04267);
case 4268:
return VUID_WRAP(VUID-LaunchIdKHR-LaunchIdKHR-04268);
case 4269:
return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04269);
case 4270:
return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04270);
case 4271:
return VUID_WRAP(VUID-LaunchSizeKHR-LaunchSizeKHR-04271);
case 4272:
return VUID_WRAP(VUID-Layer-Layer-04272);
case 4274:
@@ -1395,6 +1437,24 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04297);
case 4298:
return VUID_WRAP(VUID-NumWorkgroups-NumWorkgroups-04298);
case 4299:
return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04299);
case 4300:
return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04300);
case 4301:
return VUID_WRAP(VUID-ObjectRayDirectionKHR-ObjectRayDirectionKHR-04301);
case 4302:
return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04302);
case 4303:
return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04303);
case 4304:
return VUID_WRAP(VUID-ObjectRayOriginKHR-ObjectRayOriginKHR-04304);
case 4305:
return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04305);
case 4306:
return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04306);
case 4307:
return VUID_WRAP(VUID-ObjectToWorldKHR-ObjectToWorldKHR-04307);
case 4308:
return VUID_WRAP(VUID-PatchVertices-PatchVertices-04308);
case 4309:
@@ -1427,6 +1487,24 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04334);
case 4337:
return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04337);
case 4345:
return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04345);
case 4346:
return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04346);
case 4347:
return VUID_WRAP(VUID-RayGeometryIndexKHR-RayGeometryIndexKHR-04347);
case 4348:
return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04348);
case 4349:
return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04349);
case 4350:
return VUID_WRAP(VUID-RayTmaxKHR-RayTmaxKHR-04350);
case 4351:
return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04351);
case 4352:
return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04352);
case 4353:
return VUID_WRAP(VUID-RayTminKHR-RayTminKHR-04353);
case 4354:
return VUID_WRAP(VUID-SampleId-SampleId-04354);
case 4355:
@@ -1491,6 +1569,24 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04426);
case 4427:
return VUID_WRAP(VUID-WorkgroupSize-WorkgroupSize-04427);
case 4428:
return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04428);
case 4429:
return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04429);
case 4430:
return VUID_WRAP(VUID-WorldRayDirectionKHR-WorldRayDirectionKHR-04430);
case 4431:
return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04431);
case 4432:
return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04432);
case 4433:
return VUID_WRAP(VUID-WorldRayOriginKHR-WorldRayOriginKHR-04433);
case 4434:
return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04434);
case 4435:
return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04435);
case 4436:
return VUID_WRAP(VUID-WorldToObjectKHR-WorldToObjectKHR-04436);
case 4484:
return VUID_WRAP(VUID-PrimitiveShadingRateKHR-PrimitiveShadingRateKHR-04484);
case 4485: