1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
/* Copyright (c) 2024-2025 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ray_query_pass.h"
#include "module.h"
#include <spirv/unified1/spirv.hpp>
#include <iostream>
#include "generated/gpuav_offline_spirv.h"
namespace gpuav {
namespace spirv {
const static OfflineModule kOfflineModule = {instrumentation_ray_query_comp, instrumentation_ray_query_comp_size,
UseErrorPayloadVariable};
const static OfflineFunction kOfflineFunction = {"inst_ray_query", instrumentation_ray_query_comp_function_0_offset};
RayQueryPass::RayQueryPass(Module& module) : Pass(module, kOfflineModule) { module.use_bda_ = true; }
// By appending the LinkInfo, it will attempt at linking stage to add the function.
uint32_t RayQueryPass::GetLinkFunctionId() { return GetLinkFunction(link_function_id_, kOfflineFunction); }
uint32_t RayQueryPass::CreateFunctionCall(BasicBlock& block, InstructionIt* inst_it, const InstructionMeta& meta) {
const uint32_t function_result = module_.TakeNextId();
const uint32_t function_def = GetLinkFunctionId();
const uint32_t bool_type = module_.type_manager_.GetTypeBool().Id();
const uint32_t ray_flags_id = meta.target_instruction->Operand(2);
const uint32_t ray_origin_id = meta.target_instruction->Operand(4);
const uint32_t ray_tmin_id = meta.target_instruction->Operand(5);
const uint32_t ray_direction_id = meta.target_instruction->Operand(6);
const uint32_t ray_tmax_id = meta.target_instruction->Operand(7);
const uint32_t inst_position = meta.target_instruction->GetPositionIndex();
const uint32_t inst_position_id = module_.type_manager_.CreateConstantUInt32(inst_position).Id();
block.CreateInstruction(spv::OpFunctionCall,
{bool_type, function_result, function_def, inst_position_id, ray_flags_id, ray_origin_id, ray_tmin_id,
ray_direction_id, ray_tmax_id},
inst_it);
module_.need_log_error_ = true;
return function_result;
}
bool RayQueryPass::RequiresInstrumentation(const Function& function, const Instruction& inst, InstructionMeta& meta) {
(void)function;
const uint32_t opcode = inst.Opcode();
if (opcode != spv::OpRayQueryInitializeKHR) {
return false;
}
meta.target_instruction = &inst;
return true;
}
bool RayQueryPass::Instrument() {
// Can safely loop function list as there is no injecting of new Functions until linking time
for (const auto& function : module_.functions_) {
if (function->instrumentation_added_) continue;
for (auto block_it = function->blocks_.begin(); block_it != function->blocks_.end(); ++block_it) {
BasicBlock& current_block = **block_it;
cf_.Update(current_block);
if (debug_disable_loops_ && cf_.in_loop) continue;
if (current_block.IsLoopHeader()) {
continue; // Currently can't properly handle injecting CFG logic into a loop header block
}
auto& block_instructions = current_block.instructions_;
for (auto inst_it = block_instructions.begin(); inst_it != block_instructions.end(); ++inst_it) {
InstructionMeta meta;
// Every instruction is analyzed by the specific pass and lets us know if we need to inject a function or not
if (!RequiresInstrumentation(*function, *(inst_it->get()), meta)) continue;
if (IsMaxInstrumentationsCount()) continue;
instrumentations_count_++;
if (!module_.settings_.safe_mode) {
CreateFunctionCall(current_block, &inst_it, meta);
} else {
InjectConditionalData ic_data = InjectFunctionPre(*function.get(), block_it, inst_it);
ic_data.function_result_id = CreateFunctionCall(current_block, nullptr, meta);
InjectFunctionPost(current_block, ic_data);
// Skip the newly added valid and invalid block. Start searching again from newly split merge block
block_it++;
block_it++;
break;
}
}
}
}
return instrumentations_count_ != 0;
}
void RayQueryPass::PrintDebugInfo() const {
std::cout << "RayQueryPass instrumentation count: " << instrumentations_count_ << '\n';
}
} // namespace spirv
} // namespace gpuav
|