Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions layers/gpuav/spirv/access_path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ static const Type* FindAccessType(const TypeManager& type_manager, const Functio
access_type = type_manager.FindTypeGlobal(function, inst.Operand(2));
} else if (opcode == spv::OpAtomicStore) {
access_type = type_manager.FindTypeGlobal(function, inst.Operand(3));
} else if (const uint32_t as_position = OpcodeAccelerationStructureAccessPosition(opcode); as_position != 0) {
access_type = type_manager.FindTypeGlobal(function, inst.Word(as_position));
}
}
assert(access_type);
Expand Down Expand Up @@ -97,20 +99,20 @@ static const Instruction* Unwarp(const Instruction* in_inst, const Function& fun
// This is the "hide all the ugliness here" function
// The goal is a new pass can just call this and have everything it needs to know about the memory access
AccessPath::AccessPath(const Module& module, TypeManager& type_manager, const Function& function, const Instruction& inst) {
assert(inst.IsMemoryAccess());
assert(inst.IsMemoryAccess() || OpcodeAccelerationStructureAccessPosition(inst.Opcode()) != 0);
const spv::Op opcode = (spv::Op)inst.Opcode();

// Find Access Type
{
access_type = FindAccessType(type_manager, function, inst);

const bool image_sampler_access = access_type->spv_type_ == SpvType::kImage ||
access_type->spv_type_ == SpvType::kSampledImage ||
access_type->spv_type_ == SpvType::kSampler;
const bool handle_access = access_type->spv_type_ == SpvType::kImage || access_type->spv_type_ == SpvType::kSampledImage ||
access_type->spv_type_ == SpvType::kSampler ||
access_type->spv_type_ == SpvType::kAccelerationStructureKHR;

// This is just loading the image handle, this alone is the not the access.
// There will be an access (OpImageWrite, OpImageSampleImplicitLod, etc) later which has the real access information
if (opcode == spv::OpLoad && image_sampler_access) {
// This is just loading the image (or acceleration structure) handle, this alone is the not the access.
// There will be an access (OpImageWrite, OpImageSample*, OpTraceRayKHR, etc) later which has the real access information
if (opcode == spv::OpLoad && handle_access) {
return;
}
}
Expand All @@ -121,7 +123,14 @@ AccessPath::AccessPath(const Module& module, TypeManager& type_manager, const Fu
uint32_t ptr_id = OpcodeImageAccessPosition(opcode);
const bool is_image_access = ptr_id != 0;

if (!is_image_access) {
const uint32_t as_position = OpcodeAccelerationStructureAccessPosition(opcode);
if (as_position != 0) {
const Instruction* as_load_inst = Unwarp(function.FindInstruction(inst.Word(as_position)), function);
if (!as_load_inst || as_load_inst->Opcode() != spv::OpLoad) {
return; // ex. OpConvertUToAccelerationStructureKHR
}
ptr_id = as_load_inst->Operand(0);
} else if (!is_image_access) {
ptr_id = inst.Operand(0); // Standard Store/Load
} else {
// Image access path
Expand Down
2 changes: 1 addition & 1 deletion layers/gpuav/spirv/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ const Variable& Module::GetBuiltInVariable(uint32_t built_in) {

const AccessPath* Module::GetAccessPath(const Function& function, const Instruction& inst) {
// Access path is only for memory accesses
if (!inst.IsMemoryAccess()) {
if (!inst.IsMemoryAccess() && OpcodeAccelerationStructureAccessPosition(inst.Opcode()) == 0) {
return nullptr;
}

Expand Down
14 changes: 10 additions & 4 deletions layers/gpuav/spirv/pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -849,13 +849,19 @@ InjectConditionalData Pass::InjectFunctionPre(Function& function, const BasicBlo

// When skipping some instructions, we need something valid to replace it
if (target_inst.Opcode() == spv::OpRayQueryInitializeKHR) {
// Currently assume the RayQuery and AS object were valid already
// Currently assume the RayQuery object was valid already
// The AS object is not, as it might have been loaded from an invalid descriptor, so use a null one
const Type& uvec2_type = type_manager_.GetTypeVector(type_manager_.GetTypeInt(32, false), 2);
const Constant& null_constant = type_manager_.GetConstantNull(uvec2_type);
const uint32_t null_as_id = module_.TakeNextId();
invalid_block.CreateInstruction(spv::OpConvertUToAccelerationStructureKHR,
{type_manager_.GetTypeAccelerationStructure().Id(), null_as_id, null_constant.Id()});

const uint32_t uint32_0_id = type_manager_.GetConstantZeroUint32().Id();
const uint32_t float32_0_id = type_manager_.GetConstantZeroFloat32().Id();
const uint32_t vec3_0_id = type_manager_.GetConstantZeroVec3().Id();
invalid_block.CreateInstruction(spv::OpRayQueryInitializeKHR,
{target_inst.Operand(0), target_inst.Operand(1), uint32_0_id, uint32_0_id, vec3_0_id,
float32_0_id, vec3_0_id, float32_0_id});
invalid_block.CreateInstruction(spv::OpRayQueryInitializeKHR, {target_inst.Operand(0), null_as_id, uint32_0_id, uint32_0_id,
vec3_0_id, float32_0_id, vec3_0_id, float32_0_id});
}

invalid_block.CreateInstruction(spv::OpBranch, {merge_block_label});
Expand Down
21 changes: 7 additions & 14 deletions layers/gpuav/spirv/trace_ray_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,13 @@ const static OfflineFunction kReportIntersectionValidationFunction = {"inst_repo

TraceRayPass::TraceRayPass(Module& module) : Pass(module, kOfflineModule) { module.use_bda_ = true; }

std::vector<uint32_t> TraceRayPass::GetTlasValidationFunctionCallInstructions(const Function& function, uint32_t tlas_operand_pos,
uint32_t error_sub_code, BasicBlock& block,
InstructionIt* trace_ray_inst_it) {
std::vector<uint32_t> TraceRayPass::GetTlasValidationFunctionCallInstructions(const Function& function, uint32_t error_sub_code,
BasicBlock& block, InstructionIt* trace_ray_inst_it) {
if (module_.interface_.descriptor_mode != vvl::DescriptorMode::DescriptorModeClassic) {
return {};
}

const uint32_t as_op_load_id = (*trace_ray_inst_it)->get()->Operand(tlas_operand_pos);
const Instruction* as_op_load_inst = function.FindInstruction(as_op_load_id);
if (!as_op_load_inst) {
return {};
}

const AccessPath* access_path = module_.GetAccessPath(function, *as_op_load_inst);
const AccessPath* access_path = module_.GetAccessPath(function, *(*trace_ray_inst_it)->get());
if (!access_path || !access_path->IsValidDescriptor() ||
access_path->access_type->spv_type_ != SpvType::kAccelerationStructureKHR) {
return {};
Expand Down Expand Up @@ -268,15 +261,15 @@ bool TraceRayPass::Instrument() {
};
switch (opcode) {
case spv::OpRayQueryInitializeKHR: {
add_func_call(GetTlasValidationFunctionCallInstructions(
function, 1, glsl::kErrorSubCode_RayQuery_TlasNotBuilt, current_block, &inst_it));
add_func_call(GetTlasValidationFunctionCallInstructions(function, glsl::kErrorSubCode_RayQuery_TlasNotBuilt,
current_block, &inst_it));
add_func_call(GetRayQueryInitializeValidationFunctionCallInstructions(&inst_it));
break;
}
case spv::OpTraceRayKHR: {
add_func_call(GetTraceRayValidationFunctionCallInstructions(&inst_it));
add_func_call(GetTlasValidationFunctionCallInstructions(
function, 0, glsl::kErrorSubCode_TraceRay_TlasNotBuilt, current_block, &inst_it));
add_func_call(GetTlasValidationFunctionCallInstructions(function, glsl::kErrorSubCode_TraceRay_TlasNotBuilt,
current_block, &inst_it));
break;
}
case spv::OpHitObjectSetShaderBindingTableRecordIndexEXT: {
Expand Down
5 changes: 2 additions & 3 deletions layers/gpuav/spirv/trace_ray_pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ class TraceRayPass : public Pass {
void PrintDebugInfo() const final;

private:
std::vector<uint32_t> GetTlasValidationFunctionCallInstructions(const Function& function, uint32_t tlas_operand_pos,
uint32_t error_sub_code, BasicBlock& block,
InstructionIt* trace_ray_inst_it);
std::vector<uint32_t> GetTlasValidationFunctionCallInstructions(const Function& function, uint32_t error_sub_code,
BasicBlock& block, InstructionIt* trace_ray_inst_it);
std::vector<uint32_t> GetTraceRayValidationFunctionCallInstructions(InstructionIt* trace_ray_inst_it);
std::vector<uint32_t> GetRayHitObjectValidationFunctionCallInstructions(InstructionIt* ray_hit_object_inst_it);
std::vector<uint32_t> GetRayHitObjectSbtIndexValidationFunctionCallInstructions(
Expand Down
31 changes: 31 additions & 0 deletions layers/vulkan/generated/spirv_grammar_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -1347,6 +1347,37 @@ static constexpr uint32_t OpcodeImageAccessPosition(uint32_t opcode) {
return position;
}

// Return operand position of the 'Acceleration Structure' IdRef or zero if there is none.
static constexpr uint32_t OpcodeAccelerationStructureAccessPosition(uint32_t opcode) {
uint32_t position = 0;
switch (opcode) {
case spv::OpTraceRayKHR:
case spv::OpTraceNV:
case spv::OpTraceMotionNV:
case spv::OpTraceRayMotionNV:
return 1;
case spv::OpRayQueryInitializeKHR:
case spv::OpHitObjectRecordHitMotionNV:
case spv::OpHitObjectRecordHitWithIndexMotionNV:
case spv::OpHitObjectTraceRayMotionNV:
case spv::OpHitObjectTraceRayNV:
case spv::OpHitObjectRecordHitNV:
case spv::OpHitObjectRecordHitWithIndexNV:
case spv::OpHitObjectTraceReorderExecuteEXT:
case spv::OpHitObjectTraceMotionReorderExecuteEXT:
case spv::OpHitObjectTraceRayEXT:
case spv::OpHitObjectTraceRayMotionEXT:
return 2;
case spv::OpFetchMicroTriangleVertexPositionNV:
case spv::OpFetchMicroTriangleVertexBarycentricNV:
return 3;

default:
break;
}
return position;
}

// All valid OpType*
enum class SpvType {
Empty = 0,
Expand Down
23 changes: 23 additions & 0 deletions scripts/generators/spirv_grammar_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def __init__(self,
self.executionScopePosition = [[] for i in range(4)]
self.imageOperandsPosition = [[] for i in range(8)]
self.imageAccessOperand = [[] for i in range(4)]
self.accelerationStructureAccessOperand = [[] for i in range(4)]

self.kindId = [] # "category" : "Id"
self.kindLiteral = [] # "category" : "Literal"
Expand Down Expand Up @@ -209,6 +210,9 @@ def parseGrammar(self, grammar):
self.opcodes[opcode]['imageRefPosition'] = index + 1
elif operand['name'] == 'Sampled Image':
self.opcodes[opcode]['sampledImageRefPosition'] = index + 1
# The grammar uses both names, OpConvertUToAccelerationStructureKHR also calls its uint64 input 'Accel'
elif operand['name'] in ['Accel', 'Acceleration Structure'] and opname != 'OpConvertUToAccelerationStructureKHR':
self.accelerationStructureAccessOperand[index + 1].append(opname)

if re.search(r'OpImage*', opname) is not None:
info = self.opcodes[opcode]
Expand Down Expand Up @@ -483,6 +487,25 @@ def generateHeader(self):
}
''')

out.append('''
// Return operand position of the 'Acceleration Structure' IdRef or zero if there is none.
static constexpr uint32_t OpcodeAccelerationStructureAccessPosition(uint32_t opcode) {
uint32_t position = 0;
switch (opcode) {
''')
for index, opcodes in enumerate(self.accelerationStructureAccessOperand):
for opcode in opcodes:
out.append(f' case spv::{opcode}:\n')
if len(opcodes) != 0:
out.append(f' return {index};\n')
out.append('''
default:
break;
}
return position;
}
''')

out.append('''
// All valid OpType*
enum class SpvType {
Expand Down
2 changes: 1 addition & 1 deletion tests/framework/layer_validation_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ class QueryTest : public VkLayerTest {

class RayTracingTest : public virtual VkLayerTest {
public:
void InitFrameworkForRayTracingTest(VkValidationFeaturesEXT* enabled_features = nullptr);
void InitFrameworkForRayTracingTest(VkValidationFeaturesEXT* enabled_features = nullptr, bool safe_mode = true);
};

class GpuAVRayTracingTest : public GpuAVTest, public RayTracingTest {};
Expand Down
12 changes: 6 additions & 6 deletions tests/unit/gpu_av_ray_tracing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ TEST_F(NegativeGpuAVRayTracing, ArrayOOBBufferRayGenShader) {
{
uniform_buffer_ptr[0] = 5;
SCOPED_TRACE("uninitialized");
m_errorMonitor->SetDesiredError("08114", 3);
m_errorMonitor->SetDesiredError("08114", 2);
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
Expand Down Expand Up @@ -545,7 +545,7 @@ TEST_F(NegativeGpuAVRayTracing, ArrayOOBBufferMissShader) {
{
uniform_buffer_ptr[0] = 5;
SCOPED_TRACE("uninitialized");
m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-08114", 2);
m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-08114", 1);
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
Expand Down Expand Up @@ -685,7 +685,7 @@ TEST_F(NegativeGpuAVRayTracing, ArrayOOBBufferClosetHitShader) {
{
uniform_buffer_ptr[0] = 5;
SCOPED_TRACE("uninitialized");
m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-08114", 2);
m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-08114", 1);
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
Expand Down Expand Up @@ -844,7 +844,7 @@ TEST_F(NegativeGpuAVRayTracing, ArrayOOBBufferTwoClosetHitShader) {
{
uniform_buffer_ptr[0] = 5;
SCOPED_TRACE("uninitialized");
m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-08114", 3);
m_errorMonitor->SetDesiredError("VUID-vkCmdTraceRaysKHR-None-08114", 2);
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
Expand Down Expand Up @@ -1010,7 +1010,7 @@ TEST_F(NegativeGpuAVRayTracing, ArrayOOBBufferRayGenShaderGPL) {
{
uniform_buffer_ptr[0] = 5;
SCOPED_TRACE("uninitialized");
m_errorMonitor->SetDesiredError("08114", 3);
m_errorMonitor->SetDesiredError("08114", 2);
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
Expand Down Expand Up @@ -1178,7 +1178,7 @@ TEST_F(NegativeGpuAVRayTracing, ArrayOOBBufferMissShaderGPL) {
{
uniform_buffer_ptr[0] = 5;
SCOPED_TRACE("uninitialized");
m_errorMonitor->SetDesiredError("08114", 3);
m_errorMonitor->SetDesiredError("08114", 2);
m_default_queue->SubmitAndWait(m_command_buffer);
m_errorMonitor->VerifyFound();
}
Expand Down
Loading
Loading