mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-10-31 13:15:33 +00:00
Updated spirv-tools.
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "inst_debug_printf_pass.h"
|
||||
|
||||
#include "source/spirv_constant.h"
|
||||
#include "source/util/string_utils.h"
|
||||
#include "spirv/unified1/NonSemanticDebugPrintf.h"
|
||||
|
||||
@@ -210,9 +211,244 @@ void InstDebugPrintfPass::GenDebugPrintfCode(
|
||||
new_blocks->push_back(std::move(new_blk_ptr));
|
||||
}
|
||||
|
||||
// Return id for output buffer
|
||||
uint32_t InstDebugPrintfPass::GetOutputBufferId() {
|
||||
if (output_buffer_id_ == 0) {
|
||||
// If not created yet, create one
|
||||
analysis::DecorationManager* deco_mgr = get_decoration_mgr();
|
||||
analysis::TypeManager* type_mgr = context()->get_type_mgr();
|
||||
analysis::RuntimeArray* reg_uint_rarr_ty = GetUintRuntimeArrayType(32);
|
||||
analysis::Integer* reg_uint_ty = GetInteger(32, false);
|
||||
analysis::Type* reg_buf_ty =
|
||||
GetStruct({reg_uint_ty, reg_uint_ty, reg_uint_rarr_ty});
|
||||
uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty);
|
||||
// By the Vulkan spec, a pre-existing struct containing a RuntimeArray
|
||||
// must be a block, and will therefore be decorated with Block. Therefore
|
||||
// the undecorated type returned here will not be pre-existing and can
|
||||
// safely be decorated. Since this type is now decorated, it is out of
|
||||
// sync with the TypeManager and therefore the TypeManager must be
|
||||
// invalidated after this pass.
|
||||
assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 &&
|
||||
"used struct type returned");
|
||||
deco_mgr->AddDecoration(obufTyId, uint32_t(spv::Decoration::Block));
|
||||
deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputFlagsOffset,
|
||||
uint32_t(spv::Decoration::Offset), 0);
|
||||
deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset,
|
||||
uint32_t(spv::Decoration::Offset), 4);
|
||||
deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset,
|
||||
uint32_t(spv::Decoration::Offset), 8);
|
||||
uint32_t obufTyPtrId_ =
|
||||
type_mgr->FindPointerToType(obufTyId, spv::StorageClass::StorageBuffer);
|
||||
output_buffer_id_ = TakeNextId();
|
||||
std::unique_ptr<Instruction> newVarOp(new Instruction(
|
||||
context(), spv::Op::OpVariable, obufTyPtrId_, output_buffer_id_,
|
||||
{{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
|
||||
{uint32_t(spv::StorageClass::StorageBuffer)}}}));
|
||||
context()->AddGlobalValue(std::move(newVarOp));
|
||||
context()->AddDebug2Inst(NewGlobalName(obufTyId, "OutputBuffer"));
|
||||
context()->AddDebug2Inst(NewMemberName(obufTyId, 0, "flags"));
|
||||
context()->AddDebug2Inst(NewMemberName(obufTyId, 1, "written_count"));
|
||||
context()->AddDebug2Inst(NewMemberName(obufTyId, 2, "data"));
|
||||
context()->AddDebug2Inst(NewGlobalName(output_buffer_id_, "output_buffer"));
|
||||
deco_mgr->AddDecorationVal(
|
||||
output_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_);
|
||||
deco_mgr->AddDecorationVal(output_buffer_id_,
|
||||
uint32_t(spv::Decoration::Binding),
|
||||
GetOutputBufferBinding());
|
||||
AddStorageBufferExt();
|
||||
if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) {
|
||||
// Add the new buffer to all entry points.
|
||||
for (auto& entry : get_module()->entry_points()) {
|
||||
entry.AddOperand({SPV_OPERAND_TYPE_ID, {output_buffer_id_}});
|
||||
context()->AnalyzeUses(&entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
return output_buffer_id_;
|
||||
}
|
||||
|
||||
uint32_t InstDebugPrintfPass::GetOutputBufferPtrId() {
|
||||
if (output_buffer_ptr_id_ == 0) {
|
||||
output_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType(
|
||||
GetUintId(), spv::StorageClass::StorageBuffer);
|
||||
}
|
||||
return output_buffer_ptr_id_;
|
||||
}
|
||||
|
||||
uint32_t InstDebugPrintfPass::GetOutputBufferBinding() {
|
||||
return kDebugOutputPrintfStream;
|
||||
}
|
||||
|
||||
void InstDebugPrintfPass::GenDebugOutputFieldCode(uint32_t base_offset_id,
|
||||
uint32_t field_offset,
|
||||
uint32_t field_value_id,
|
||||
InstructionBuilder* builder) {
|
||||
// Cast value to 32-bit unsigned if necessary
|
||||
uint32_t val_id = GenUintCastCode(field_value_id, builder);
|
||||
// Store value
|
||||
Instruction* data_idx_inst = builder->AddIAdd(
|
||||
GetUintId(), base_offset_id, builder->GetUintConstantId(field_offset));
|
||||
uint32_t buf_id = GetOutputBufferId();
|
||||
uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
|
||||
Instruction* achain_inst = builder->AddAccessChain(
|
||||
buf_uint_ptr_id, buf_id,
|
||||
{builder->GetUintConstantId(kDebugOutputDataOffset),
|
||||
data_idx_inst->result_id()});
|
||||
(void)builder->AddStore(achain_inst->result_id(), val_id);
|
||||
}
|
||||
|
||||
uint32_t InstDebugPrintfPass::GetStreamWriteFunctionId(uint32_t param_cnt) {
|
||||
enum {
|
||||
kShaderId = 0,
|
||||
kInstructionIndex = 1,
|
||||
kStageInfo = 2,
|
||||
kFirstParam = 3,
|
||||
};
|
||||
// Total param count is common params plus validation-specific
|
||||
// params
|
||||
if (param2output_func_id_[param_cnt] == 0) {
|
||||
// Create function
|
||||
param2output_func_id_[param_cnt] = TakeNextId();
|
||||
analysis::TypeManager* type_mgr = context()->get_type_mgr();
|
||||
|
||||
const analysis::Type* uint_type = GetInteger(32, false);
|
||||
const analysis::Vector v4uint(uint_type, 4);
|
||||
const analysis::Type* v4uint_type = type_mgr->GetRegisteredType(&v4uint);
|
||||
|
||||
std::vector<const analysis::Type*> param_types(kFirstParam + param_cnt,
|
||||
uint_type);
|
||||
param_types[kStageInfo] = v4uint_type;
|
||||
std::unique_ptr<Function> output_func = StartFunction(
|
||||
param2output_func_id_[param_cnt], type_mgr->GetVoidType(), param_types);
|
||||
|
||||
std::vector<uint32_t> param_ids = AddParameters(*output_func, param_types);
|
||||
|
||||
// Create first block
|
||||
auto new_blk_ptr = MakeUnique<BasicBlock>(NewLabel(TakeNextId()));
|
||||
|
||||
InstructionBuilder builder(
|
||||
context(), &*new_blk_ptr,
|
||||
IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping);
|
||||
// Gen test if debug output buffer size will not be exceeded.
|
||||
const uint32_t val_spec_offset = kInstStageOutCnt;
|
||||
const uint32_t obuf_record_sz = val_spec_offset + param_cnt;
|
||||
const uint32_t buf_id = GetOutputBufferId();
|
||||
const uint32_t buf_uint_ptr_id = GetOutputBufferPtrId();
|
||||
Instruction* obuf_curr_sz_ac_inst = builder.AddAccessChain(
|
||||
buf_uint_ptr_id, buf_id,
|
||||
{builder.GetUintConstantId(kDebugOutputSizeOffset)});
|
||||
// Fetch the current debug buffer written size atomically, adding the
|
||||
// size of the record to be written.
|
||||
uint32_t obuf_record_sz_id = builder.GetUintConstantId(obuf_record_sz);
|
||||
uint32_t mask_none_id =
|
||||
builder.GetUintConstantId(uint32_t(spv::MemoryAccessMask::MaskNone));
|
||||
uint32_t scope_invok_id =
|
||||
builder.GetUintConstantId(uint32_t(spv::Scope::Invocation));
|
||||
Instruction* obuf_curr_sz_inst = builder.AddQuadOp(
|
||||
GetUintId(), spv::Op::OpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(),
|
||||
scope_invok_id, mask_none_id, obuf_record_sz_id);
|
||||
uint32_t obuf_curr_sz_id = obuf_curr_sz_inst->result_id();
|
||||
// Compute new written size
|
||||
Instruction* obuf_new_sz_inst =
|
||||
builder.AddIAdd(GetUintId(), obuf_curr_sz_id,
|
||||
builder.GetUintConstantId(obuf_record_sz));
|
||||
// Fetch the data bound
|
||||
Instruction* obuf_bnd_inst =
|
||||
builder.AddIdLiteralOp(GetUintId(), spv::Op::OpArrayLength,
|
||||
GetOutputBufferId(), kDebugOutputDataOffset);
|
||||
// Test that new written size is less than or equal to debug output
|
||||
// data bound
|
||||
Instruction* obuf_safe_inst = builder.AddBinaryOp(
|
||||
GetBoolId(), spv::Op::OpULessThanEqual, obuf_new_sz_inst->result_id(),
|
||||
obuf_bnd_inst->result_id());
|
||||
uint32_t merge_blk_id = TakeNextId();
|
||||
uint32_t write_blk_id = TakeNextId();
|
||||
std::unique_ptr<Instruction> merge_label(NewLabel(merge_blk_id));
|
||||
std::unique_ptr<Instruction> write_label(NewLabel(write_blk_id));
|
||||
(void)builder.AddConditionalBranch(
|
||||
obuf_safe_inst->result_id(), write_blk_id, merge_blk_id, merge_blk_id,
|
||||
uint32_t(spv::SelectionControlMask::MaskNone));
|
||||
// Close safety test block and gen write block
|
||||
output_func->AddBasicBlock(std::move(new_blk_ptr));
|
||||
new_blk_ptr = MakeUnique<BasicBlock>(std::move(write_label));
|
||||
builder.SetInsertPoint(&*new_blk_ptr);
|
||||
// Generate common and stage-specific debug record members
|
||||
GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutSize,
|
||||
builder.GetUintConstantId(obuf_record_sz),
|
||||
&builder);
|
||||
// Store Shader Id
|
||||
GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutShaderId,
|
||||
param_ids[kShaderId], &builder);
|
||||
// Store Instruction Idx
|
||||
GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutInstructionIdx,
|
||||
param_ids[kInstructionIndex], &builder);
|
||||
// Store stage info. Stage Idx + 3 words of stage-specific data.
|
||||
for (uint32_t i = 0; i < 4; ++i) {
|
||||
Instruction* field =
|
||||
builder.AddCompositeExtract(GetUintId(), param_ids[kStageInfo], {i});
|
||||
GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutStageIdx + i,
|
||||
field->result_id(), &builder);
|
||||
}
|
||||
// Gen writes of validation specific data
|
||||
for (uint32_t i = 0; i < param_cnt; ++i) {
|
||||
GenDebugOutputFieldCode(obuf_curr_sz_id, val_spec_offset + i,
|
||||
param_ids[kFirstParam + i], &builder);
|
||||
}
|
||||
// Close write block and gen merge block
|
||||
(void)builder.AddBranch(merge_blk_id);
|
||||
output_func->AddBasicBlock(std::move(new_blk_ptr));
|
||||
new_blk_ptr = MakeUnique<BasicBlock>(std::move(merge_label));
|
||||
builder.SetInsertPoint(&*new_blk_ptr);
|
||||
// Close merge block and function and add function to module
|
||||
(void)builder.AddNullaryOp(0, spv::Op::OpReturn);
|
||||
|
||||
output_func->AddBasicBlock(std::move(new_blk_ptr));
|
||||
output_func->SetFunctionEnd(EndFunction());
|
||||
context()->AddFunction(std::move(output_func));
|
||||
|
||||
std::string name("stream_write_");
|
||||
name += std::to_string(param_cnt);
|
||||
|
||||
context()->AddDebug2Inst(
|
||||
NewGlobalName(param2output_func_id_[param_cnt], name));
|
||||
}
|
||||
return param2output_func_id_[param_cnt];
|
||||
}
|
||||
|
||||
void InstDebugPrintfPass::GenDebugStreamWrite(
|
||||
uint32_t shader_id, uint32_t instruction_idx_id, uint32_t stage_info_id,
|
||||
const std::vector<uint32_t>& validation_ids, InstructionBuilder* builder) {
|
||||
// Call debug output function. Pass func_idx, instruction_idx and
|
||||
// validation ids as args.
|
||||
uint32_t val_id_cnt = static_cast<uint32_t>(validation_ids.size());
|
||||
std::vector<uint32_t> args = {shader_id, instruction_idx_id, stage_info_id};
|
||||
(void)args.insert(args.end(), validation_ids.begin(), validation_ids.end());
|
||||
(void)builder->AddFunctionCall(GetVoidId(),
|
||||
GetStreamWriteFunctionId(val_id_cnt), args);
|
||||
}
|
||||
|
||||
std::unique_ptr<Instruction> InstDebugPrintfPass::NewGlobalName(
|
||||
uint32_t id, const std::string& name_str) {
|
||||
std::string prefixed_name{"inst_printf_"};
|
||||
prefixed_name += name_str;
|
||||
return NewName(id, prefixed_name);
|
||||
}
|
||||
|
||||
std::unique_ptr<Instruction> InstDebugPrintfPass::NewMemberName(
|
||||
uint32_t id, uint32_t member_index, const std::string& name_str) {
|
||||
return MakeUnique<Instruction>(
|
||||
context(), spv::Op::OpMemberName, 0, 0,
|
||||
std::initializer_list<Operand>{
|
||||
{SPV_OPERAND_TYPE_ID, {id}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {member_index}},
|
||||
{SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}});
|
||||
}
|
||||
|
||||
void InstDebugPrintfPass::InitializeInstDebugPrintf() {
|
||||
// Initialize base class
|
||||
InitializeInstrument();
|
||||
output_buffer_id_ = 0;
|
||||
output_buffer_ptr_id_ = 0;
|
||||
}
|
||||
|
||||
Pass::Status InstDebugPrintfPass::ProcessImpl() {
|
||||
|
||||
Reference in New Issue
Block a user