mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 08:13:05 +00:00
graphics: refactoring #2
This commit is contained in:
1 parent
b51d4322cc
commit
0a5f78c727
137 files changed
+10230
-10893
No files matched your search
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter {
|
||||
|
||||
void ComputeReachableBlocks(EmitterState* state, const IR::Program& program) {
|
||||
state->reachable_blocks.assign(program.blocks.size(), false);
|
||||
void ComputeReachableBlocks(EmitterState& state, const IR::Program& program) {
|
||||
state.reachable_blocks.assign(program.blocks.size(), false);
|
||||
if (program.blocks.empty()) {
|
||||
return;
|
||||
}
|
||||
@@ -13,38 +13,38 @@ void ComputeReachableBlocks(EmitterState* state, const IR::Program& program) {
|
||||
while (!stack.empty()) {
|
||||
const auto block_id = stack.back();
|
||||
stack.pop_back();
|
||||
if (block_id >= program.blocks.size() || state->reachable_blocks[block_id]) {
|
||||
if (block_id >= program.blocks.size() || state.reachable_blocks[block_id]) {
|
||||
continue;
|
||||
}
|
||||
state->reachable_blocks[block_id] = true;
|
||||
state.reachable_blocks[block_id] = true;
|
||||
for (auto succ: program.blocks[block_id].successors) {
|
||||
if (succ < program.blocks.size() && !state->reachable_blocks[succ]) {
|
||||
if (succ < program.blocks.size() && !state.reachable_blocks[succ]) {
|
||||
stack.push_back(succ);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AllocateBlockLabels(EmitterState* state, const IR::Program& program) {
|
||||
void AllocateBlockLabels(EmitterState& state, const IR::Program& program) {
|
||||
for (const auto& block: program.blocks) {
|
||||
if (block.id < state->reachable_blocks.size() && state->reachable_blocks[block.id]) {
|
||||
state->block_labels.emplace(block.id, state->builder.AllocateId());
|
||||
if (block.id < state.reachable_blocks.size() && state.reachable_blocks[block.id]) {
|
||||
state.block_labels.emplace(block.id, state.builder.AllocateId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AllocateDispatcherState(EmitterState* state, const IR::Program& program) {
|
||||
state->dispatcher_fallback = program.dispatcher_fallback;
|
||||
if (!state->dispatcher_fallback) {
|
||||
void AllocateDispatcherState(EmitterState& state, const IR::Program& program) {
|
||||
state.dispatcher_fallback = program.dispatcher_fallback;
|
||||
if (!state.dispatcher_fallback) {
|
||||
return;
|
||||
}
|
||||
state->dispatch_pc_variable = state->builder.AllocateId();
|
||||
state->dispatch_header_label = state->builder.AllocateId();
|
||||
state->dispatch_select_label = state->builder.AllocateId();
|
||||
state->dispatch_default_label = state->builder.AllocateId();
|
||||
state->dispatch_after_switch_label = state->builder.AllocateId();
|
||||
state->dispatch_continue_label = state->builder.AllocateId();
|
||||
state->dispatch_merge_label = state->builder.AllocateId();
|
||||
state.dispatch_pc_variable = state.builder.AllocateId();
|
||||
state.dispatch_header_label = state.builder.AllocateId();
|
||||
state.dispatch_select_label = state.builder.AllocateId();
|
||||
state.dispatch_default_label = state.builder.AllocateId();
|
||||
state.dispatch_after_switch_label = state.builder.AllocateId();
|
||||
state.dispatch_continue_label = state.builder.AllocateId();
|
||||
state.dispatch_merge_label = state.builder.AllocateId();
|
||||
}
|
||||
|
||||
uint32_t BlockLabel(const EmitterState& state, uint32_t block_id) {
|
||||
@@ -52,7 +52,7 @@ uint32_t BlockLabel(const EmitterState& state, uint32_t block_id) {
|
||||
return it == state.block_labels.end() ? 0 : it->second;
|
||||
}
|
||||
|
||||
uint32_t EmitBranchCondition(EmitterState* state, CFG::BranchCondition condition) {
|
||||
uint32_t EmitBranchCondition(EmitterState& state, CFG::BranchCondition condition) {
|
||||
switch (condition) {
|
||||
case CFG::BranchCondition::SccZero: return EmitSccBool(state, false);
|
||||
case CFG::BranchCondition::SccNonZero: return EmitSccBool(state, true);
|
||||
@@ -68,29 +68,29 @@ uint32_t EmitBranchCondition(EmitterState* state, CFG::BranchCondition condition
|
||||
}
|
||||
}
|
||||
|
||||
void EmitStructuredPrefix(EmitterState* state, const CFG::Terminator& term) {
|
||||
void EmitStructuredPrefix(EmitterState& state, const CFG::Terminator& term) {
|
||||
if (term.loop_header) {
|
||||
const auto merge_label = BlockLabel(*state, term.merge_block);
|
||||
const auto continue_label = BlockLabel(*state, term.continue_block);
|
||||
const auto merge_label = BlockLabel(state, term.merge_block);
|
||||
const auto continue_label = BlockLabel(state, term.continue_block);
|
||||
if (merge_label != 0 && continue_label != 0) {
|
||||
state->builder.AddFunction({OpLoopMerge, merge_label, continue_label, LoopControlNone});
|
||||
state.builder.AddFunction({OpLoopMerge, merge_label, continue_label, LoopControlNone});
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (term.kind == CFG::TerminatorKind::ConditionalBranch && term.merge_block != UINT32_MAX) {
|
||||
const auto merge_label = BlockLabel(*state, term.merge_block);
|
||||
const auto merge_label = BlockLabel(state, term.merge_block);
|
||||
if (merge_label != 0) {
|
||||
state->builder.AddFunction({OpSelectionMerge, merge_label, SelectionControlNone});
|
||||
state.builder.AddFunction({OpSelectionMerge, merge_label, SelectionControlNone});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EmitReturn(EmitterState* state) {
|
||||
void EmitReturn(EmitterState& state) {
|
||||
EmitKillIfPixelValidMaskInactive(state);
|
||||
state->builder.AddFunction({OpReturn});
|
||||
state.builder.AddFunction({OpReturn});
|
||||
}
|
||||
|
||||
void EmitTerminator(EmitterState* state, const CFG::Terminator& term) {
|
||||
void EmitTerminator(EmitterState& state, const CFG::Terminator& term) {
|
||||
const auto condition = term.kind == CFG::TerminatorKind::ConditionalBranch
|
||||
? EmitBranchCondition(state, term.condition)
|
||||
: 0;
|
||||
@@ -98,19 +98,19 @@ void EmitTerminator(EmitterState* state, const CFG::Terminator& term) {
|
||||
|
||||
switch (term.kind) {
|
||||
case CFG::TerminatorKind::Branch: {
|
||||
const auto label = BlockLabel(*state, term.true_block);
|
||||
const auto label = BlockLabel(state, term.true_block);
|
||||
if (label != 0) {
|
||||
state->builder.AddFunction({OpBranch, label});
|
||||
state.builder.AddFunction({OpBranch, label});
|
||||
} else {
|
||||
EmitReturn(state);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CFG::TerminatorKind::ConditionalBranch: {
|
||||
const auto true_label = BlockLabel(*state, term.true_block);
|
||||
const auto false_label = BlockLabel(*state, term.false_block);
|
||||
const auto true_label = BlockLabel(state, term.true_block);
|
||||
const auto false_label = BlockLabel(state, term.false_block);
|
||||
if (true_label != 0 && false_label != 0) {
|
||||
state->builder.AddFunction(
|
||||
state.builder.AddFunction(
|
||||
{OpBranchConditional, condition, true_label, false_label});
|
||||
} else {
|
||||
EmitReturn(state);
|
||||
@@ -122,10 +122,10 @@ void EmitTerminator(EmitterState* state, const CFG::Terminator& term) {
|
||||
}
|
||||
|
||||
bool UserDataDwordIndex(const EmitterState& state, IR::Register reg, uint32_t& dword_index) {
|
||||
if (state.program == nullptr || reg.file != IR::RegisterFile::Scalar) {
|
||||
if (reg.file != IR::RegisterFile::Scalar) {
|
||||
return false;
|
||||
}
|
||||
const auto& registers = state.program->bindings.user_data_registers;
|
||||
const auto& registers = state.program.bindings.user_data_registers;
|
||||
const auto found = std::lower_bound(registers.begin(), registers.end(), reg.index);
|
||||
if (found != registers.end() && *found == reg.index) {
|
||||
dword_index = static_cast<uint32_t>(found - registers.begin());
|
||||
@@ -134,24 +134,24 @@ bool UserDataDwordIndex(const EmitterState& state, IR::Register reg, uint32_t& d
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t EmitVsharpDwordLoad(EmitterState* state, uint32_t dword_index) {
|
||||
if (state->push_constant_variable != 0) {
|
||||
const auto pointer = state->builder.AllocateId();
|
||||
const auto value = state->builder.AllocateId();
|
||||
state->builder.AddFunction({OpAccessChain, state->ptr_push_constant_uint, pointer,
|
||||
state->push_constant_variable, ConstantU32(state, 0),
|
||||
uint32_t EmitVsharpDwordLoad(EmitterState& state, uint32_t dword_index) {
|
||||
if (state.push_constant_variable != 0) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpAccessChain, state.ptr_push_constant_uint, pointer,
|
||||
state.push_constant_variable, ConstantU32(state, 0),
|
||||
ConstantU32(state, dword_index / 4u),
|
||||
ConstantU32(state, dword_index % 4u)});
|
||||
state->builder.AddFunction({OpLoad, state->uint_type, value, pointer});
|
||||
state.builder.AddFunction({OpLoad, state.uint_type, value, pointer});
|
||||
return value;
|
||||
}
|
||||
if (state->vsharp_storage_variable != 0) {
|
||||
const auto pointer = state->builder.AllocateId();
|
||||
const auto value = state->builder.AllocateId();
|
||||
state->builder.AddFunction({OpAccessChain, state->ptr_storage_buffer_uint, pointer,
|
||||
state->vsharp_storage_variable, ConstantU32(state, 0),
|
||||
if (state.vsharp_storage_variable != 0) {
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpAccessChain, state.ptr_storage_buffer_uint, pointer,
|
||||
state.vsharp_storage_variable, ConstantU32(state, 0),
|
||||
ConstantU32(state, dword_index)});
|
||||
state->builder.AddFunction({OpLoad, state->uint_type, value, pointer});
|
||||
state.builder.AddFunction({OpLoad, state.uint_type, value, pointer});
|
||||
return value;
|
||||
}
|
||||
return ConstantU32(state, 0);
|
||||
@@ -170,52 +170,52 @@ uint32_t InitialRegisterValue(const EmitterState& state, IR::Register reg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t EmitInitialRegisterValue(EmitterState* state, IR::Register reg) {
|
||||
uint32_t EmitInitialRegisterValue(EmitterState& state, IR::Register reg) {
|
||||
uint32_t dword_index = 0;
|
||||
if (UserDataDwordIndex(*state, reg, dword_index)) {
|
||||
if (UserDataDwordIndex(state, reg, dword_index)) {
|
||||
return EmitVsharpDwordLoad(state, dword_index);
|
||||
}
|
||||
return ConstantU32(state, InitialRegisterValue(*state, reg));
|
||||
return ConstantU32(state, InitialRegisterValue(state, reg));
|
||||
}
|
||||
|
||||
void EmitRegisterVariables(EmitterState* state) {
|
||||
if (state->needs_function_lds) {
|
||||
state->builder.AddFunction(
|
||||
{OpVariable, state->ptr_workgroup_array, state->lds_variable, StorageClassFunction});
|
||||
void EmitRegisterVariables(EmitterState& state) {
|
||||
if (state.needs_function_lds) {
|
||||
state.builder.AddFunction(
|
||||
{OpVariable, state.ptr_workgroup_array, state.lds_variable, StorageClassFunction});
|
||||
}
|
||||
for (const auto& binding: state->registers) {
|
||||
state->builder.AddFunction(
|
||||
{OpVariable, state->ptr_func_uint, binding.pointer_id, StorageClassFunction});
|
||||
for (const auto& binding: state.registers) {
|
||||
state.builder.AddFunction(
|
||||
{OpVariable, state.ptr_func_uint, binding.pointer_id, StorageClassFunction});
|
||||
}
|
||||
if (state->dispatcher_fallback) {
|
||||
state->builder.AddFunction(
|
||||
{OpVariable, state->ptr_func_uint, state->dispatch_pc_variable, StorageClassFunction});
|
||||
if (state.dispatcher_fallback) {
|
||||
state.builder.AddFunction(
|
||||
{OpVariable, state.ptr_func_uint, state.dispatch_pc_variable, StorageClassFunction});
|
||||
}
|
||||
if (state->pixel_valid_mask_variable != 0) {
|
||||
state->builder.AddFunction({OpVariable, state->ptr_func_uint,
|
||||
state->pixel_valid_mask_variable, StorageClassFunction});
|
||||
state->builder.AddFunction(
|
||||
{OpStore, state->pixel_valid_mask_variable, ConstantU32(state, 1)});
|
||||
if (state.pixel_valid_mask_variable != 0) {
|
||||
state.builder.AddFunction({OpVariable, state.ptr_func_uint,
|
||||
state.pixel_valid_mask_variable, StorageClassFunction});
|
||||
state.builder.AddFunction(
|
||||
{OpStore, state.pixel_valid_mask_variable, ConstantU32(state, 1)});
|
||||
}
|
||||
for (const auto& binding: state->registers) {
|
||||
state->builder.AddFunction(
|
||||
for (const auto& binding: state.registers) {
|
||||
state.builder.AddFunction(
|
||||
{OpStore, binding.pointer_id, EmitInitialRegisterValue(state, binding.reg)});
|
||||
}
|
||||
}
|
||||
|
||||
void EmitComputeInputRegisters(EmitterState* state) {
|
||||
if (state->stage != ShaderType::Compute || state->compute_input_info == nullptr) {
|
||||
void EmitComputeInputRegisters(EmitterState& state) {
|
||||
if (state.stage != ShaderType::Compute || state.compute_input_info == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* cs = state->compute_input_info;
|
||||
const auto* cs = state.compute_input_info;
|
||||
const auto thread_ids = cs->thread_ids_num > 0
|
||||
? std::min<uint32_t>(static_cast<uint32_t>(cs->thread_ids_num), 3u)
|
||||
: 0u;
|
||||
for (uint32_t i = 0; i < thread_ids; i++) {
|
||||
const auto pointer = PointerForRegister(*state, {IR::RegisterFile::Vector, i});
|
||||
const auto pointer = PointerForRegister(state, {IR::RegisterFile::Vector, i});
|
||||
if (pointer != 0) {
|
||||
state->builder.AddFunction(
|
||||
state.builder.AddFunction(
|
||||
{OpStore, pointer,
|
||||
EmitInputComponentU32(state, IR::StageInputKind::LocalInvocationId, i)});
|
||||
}
|
||||
@@ -227,10 +227,10 @@ void EmitComputeInputRegisters(EmitterState* state) {
|
||||
continue;
|
||||
}
|
||||
const auto pointer = PointerForRegister(
|
||||
*state,
|
||||
state,
|
||||
{IR::RegisterFile::Scalar, static_cast<uint32_t>(cs->workgroup_register) + reg_offset});
|
||||
if (pointer != 0) {
|
||||
state->builder.AddFunction(
|
||||
state.builder.AddFunction(
|
||||
{OpStore, pointer,
|
||||
EmitInputComponentU32(state, IR::StageInputKind::WorkgroupId, i)});
|
||||
}
|
||||
@@ -239,7 +239,7 @@ void EmitComputeInputRegisters(EmitterState* state) {
|
||||
|
||||
if (cs->tg_size_en) {
|
||||
const auto pointer = PointerForRegister(
|
||||
*state,
|
||||
state,
|
||||
{IR::RegisterFile::Scalar, static_cast<uint32_t>(cs->workgroup_register) + reg_offset});
|
||||
if (pointer != 0) {
|
||||
const uint32_t wave_size = cs->wave_size != 0 ? cs->wave_size : 64u;
|
||||
@@ -250,66 +250,66 @@ void EmitComputeInputRegisters(EmitterState* state) {
|
||||
std::min<uint32_t>((total_threads + wave_size - 1u) / wave_size, 0x3fu);
|
||||
|
||||
const auto local_index = EmitLocalInvocationIndex(state);
|
||||
const auto wave_id = state->builder.AllocateId();
|
||||
const auto wave_bits = state->builder.AllocateId();
|
||||
const auto is_first = state->builder.AllocateId();
|
||||
const auto first_bit = state->builder.AllocateId();
|
||||
const auto base = state->builder.AllocateId();
|
||||
const auto packed = state->builder.AllocateId();
|
||||
state->builder.AddFunction(
|
||||
{OpUDiv, state->uint_type, wave_id, local_index, ConstantU32(state, wave_size)});
|
||||
state->builder.AddFunction(
|
||||
{OpShiftLeftLogical, state->uint_type, wave_bits, wave_id, ConstantU32(state, 20)});
|
||||
state->builder.AddFunction(
|
||||
{OpIEqual, state->bool_type, is_first, wave_id, ConstantU32(state, 0)});
|
||||
state->builder.AddFunction({OpSelect, state->uint_type, first_bit, is_first,
|
||||
const auto wave_id = state.builder.AllocateId();
|
||||
const auto wave_bits = state.builder.AllocateId();
|
||||
const auto is_first = state.builder.AllocateId();
|
||||
const auto first_bit = state.builder.AllocateId();
|
||||
const auto base = state.builder.AllocateId();
|
||||
const auto packed = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpUDiv, state.uint_type, wave_id, local_index, ConstantU32(state, wave_size)});
|
||||
state.builder.AddFunction(
|
||||
{OpShiftLeftLogical, state.uint_type, wave_bits, wave_id, ConstantU32(state, 20)});
|
||||
state.builder.AddFunction(
|
||||
{OpIEqual, state.bool_type, is_first, wave_id, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpSelect, state.uint_type, first_bit, is_first,
|
||||
ConstantU32(state, 0x80000000u), ConstantU32(state, 0)});
|
||||
state->builder.AddFunction(
|
||||
{OpBitwiseOr, state->uint_type, base, wave_bits, ConstantU32(state, waves)});
|
||||
state->builder.AddFunction({OpBitwiseOr, state->uint_type, packed, base, first_bit});
|
||||
state->builder.AddFunction({OpStore, pointer, packed});
|
||||
state.builder.AddFunction(
|
||||
{OpBitwiseOr, state.uint_type, base, wave_bits, ConstantU32(state, waves)});
|
||||
state.builder.AddFunction({OpBitwiseOr, state.uint_type, packed, base, first_bit});
|
||||
state.builder.AddFunction({OpStore, pointer, packed});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EmitPixelFragCoordComponent(EmitterState* state, uint32_t component, uint32_t vgpr) {
|
||||
const auto input = InputVariableForKind(*state, IR::StageInputKind::FragCoord);
|
||||
const auto dst = PointerForRegister(*state, {IR::RegisterFile::Vector, vgpr});
|
||||
void EmitPixelFragCoordComponent(EmitterState& state, uint32_t component, uint32_t vgpr) {
|
||||
const auto input = InputVariableForKind(state, IR::StageInputKind::FragCoord);
|
||||
const auto dst = PointerForRegister(state, {IR::RegisterFile::Vector, vgpr});
|
||||
if (input == 0 || dst == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto pointer = state->builder.AllocateId();
|
||||
const auto value = state->builder.AllocateId();
|
||||
const auto bits = state->builder.AllocateId();
|
||||
state->builder.AddFunction(
|
||||
{OpAccessChain, state->ptr_input_float, pointer, input, ConstantU32(state, component)});
|
||||
state->builder.AddFunction({OpLoad, state->float_type, value, pointer});
|
||||
state->builder.AddFunction({OpBitcast, state->uint_type, bits, value});
|
||||
state->builder.AddFunction({OpStore, dst, bits});
|
||||
const auto pointer = state.builder.AllocateId();
|
||||
const auto value = state.builder.AllocateId();
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpAccessChain, state.ptr_input_float, pointer, input, ConstantU32(state, component)});
|
||||
state.builder.AddFunction({OpLoad, state.float_type, value, pointer});
|
||||
state.builder.AddFunction({OpBitcast, state.uint_type, bits, value});
|
||||
state.builder.AddFunction({OpStore, dst, bits});
|
||||
}
|
||||
|
||||
void EmitPixelFrontFacingRegister(EmitterState* state, uint32_t vgpr) {
|
||||
const auto input = InputVariableForKind(*state, IR::StageInputKind::FrontFacing);
|
||||
const auto dst = PointerForRegister(*state, {IR::RegisterFile::Vector, vgpr});
|
||||
void EmitPixelFrontFacingRegister(EmitterState& state, uint32_t vgpr) {
|
||||
const auto input = InputVariableForKind(state, IR::StageInputKind::FrontFacing);
|
||||
const auto dst = PointerForRegister(state, {IR::RegisterFile::Vector, vgpr});
|
||||
if (input == 0 || dst == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto value = state->builder.AllocateId();
|
||||
const auto bits = state->builder.AllocateId();
|
||||
state->builder.AddFunction({OpLoad, state->bool_type, value, input});
|
||||
state->builder.AddFunction(
|
||||
{OpSelect, state->uint_type, bits, value, ConstantU32(state, 1), ConstantU32(state, 0)});
|
||||
state->builder.AddFunction({OpStore, dst, bits});
|
||||
const auto value = state.builder.AllocateId();
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLoad, state.bool_type, value, input});
|
||||
state.builder.AddFunction(
|
||||
{OpSelect, state.uint_type, bits, value, ConstantU32(state, 1), ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpStore, dst, bits});
|
||||
}
|
||||
|
||||
void EmitPixelInputRegisters(EmitterState* state) {
|
||||
if (state->stage != ShaderType::Pixel || state->pixel_input_info == nullptr) {
|
||||
void EmitPixelInputRegisters(EmitterState& state) {
|
||||
if (state.stage != ShaderType::Pixel || state.pixel_input_info == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* ps = state->pixel_input_info;
|
||||
const auto* ps = state.pixel_input_info;
|
||||
uint32_t reg = ps->ps_system_input_base;
|
||||
if (ps->HasPositionInput()) {
|
||||
if (ps->ps_pos_x) {
|
||||
@@ -334,37 +334,37 @@ void EmitPixelInputRegisters(EmitterState* state) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t EmitInputScalarU32(EmitterState* state, IR::StageInputKind kind) {
|
||||
const auto variable = InputVariableForKind(*state, kind);
|
||||
uint32_t EmitInputScalarU32(EmitterState& state, IR::StageInputKind kind) {
|
||||
const auto variable = InputVariableForKind(state, kind);
|
||||
if (variable == 0) {
|
||||
return ConstantU32(state, 0);
|
||||
}
|
||||
const auto raw = state->builder.AllocateId();
|
||||
const auto bits = state->builder.AllocateId();
|
||||
state->builder.AddFunction({OpLoad, state->int_type, raw, variable});
|
||||
state->builder.AddFunction({OpBitcast, state->uint_type, bits, raw});
|
||||
const auto raw = state.builder.AllocateId();
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLoad, state.int_type, raw, variable});
|
||||
state.builder.AddFunction({OpBitcast, state.uint_type, bits, raw});
|
||||
return bits;
|
||||
}
|
||||
|
||||
void EmitVertexInputRegisters(EmitterState* state) {
|
||||
if (state->stage != ShaderType::Vertex) {
|
||||
void EmitVertexInputRegisters(EmitterState& state) {
|
||||
if (state.stage != ShaderType::Vertex) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto vertex_index = PointerForRegister(*state, {IR::RegisterFile::Vector, 5});
|
||||
const auto vertex_index = PointerForRegister(state, {IR::RegisterFile::Vector, 5});
|
||||
if (vertex_index != 0) {
|
||||
state->builder.AddFunction(
|
||||
state.builder.AddFunction(
|
||||
{OpStore, vertex_index, EmitInputScalarU32(state, IR::StageInputKind::VertexIndex)});
|
||||
}
|
||||
|
||||
const auto instance_index = PointerForRegister(*state, {IR::RegisterFile::Vector, 8});
|
||||
const auto instance_index = PointerForRegister(state, {IR::RegisterFile::Vector, 8});
|
||||
if (instance_index != 0) {
|
||||
state->builder.AddFunction({OpStore, instance_index,
|
||||
state.builder.AddFunction({OpStore, instance_index,
|
||||
EmitInputScalarU32(state, IR::StageInputKind::InstanceIndex)});
|
||||
}
|
||||
}
|
||||
|
||||
void EmitInstruction(EmitterState* state, const IR::Instruction& inst) {
|
||||
void EmitInstruction(EmitterState& state, const IR::Instruction& inst) {
|
||||
switch (inst.op) {
|
||||
case IR::Opcode::ControlNop: EmitControlNop(state, inst); break;
|
||||
case IR::Opcode::Waitcnt: EmitWaitcnt(state, inst); break;
|
||||
@@ -846,7 +846,7 @@ void EmitInstruction(EmitterState* state, const IR::Instruction& inst) {
|
||||
case IR::Opcode::ImageSample: EmitImageSample(state, inst); break;
|
||||
case IR::Opcode::ImageGather4: EmitImageGather4(state, inst); break;
|
||||
case IR::Opcode::Export:
|
||||
if (ExportUsesPixelValidMask(*state, inst)) {
|
||||
if (ExportUsesPixelValidMask(state, inst)) {
|
||||
EmitUpdatePixelValidMask(state);
|
||||
}
|
||||
EmitGuardedByExec(state, [&]() { EmitExport(state, inst); });
|
||||
@@ -855,16 +855,16 @@ void EmitInstruction(EmitterState* state, const IR::Instruction& inst) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DispatcherTargetValue(EmitterState* state, uint32_t block_id) {
|
||||
return BlockLabel(*state, block_id) != 0 ? block_id : UINT32_MAX;
|
||||
uint32_t DispatcherTargetValue(EmitterState& state, uint32_t block_id) {
|
||||
return BlockLabel(state, block_id) != 0 ? block_id : UINT32_MAX;
|
||||
}
|
||||
|
||||
void EmitDispatcherStoreTarget(EmitterState* state, uint32_t block_id) {
|
||||
state->builder.AddFunction({OpStore, state->dispatch_pc_variable,
|
||||
void EmitDispatcherStoreTarget(EmitterState& state, uint32_t block_id) {
|
||||
state.builder.AddFunction({OpStore, state.dispatch_pc_variable,
|
||||
ConstantU32(state, DispatcherTargetValue(state, block_id))});
|
||||
}
|
||||
|
||||
void EmitDispatcherExit(EmitterState* state);
|
||||
void EmitDispatcherExit(EmitterState& state);
|
||||
|
||||
bool RegisterForScalarCode(uint32_t code, IR::Register& reg) {
|
||||
if (code < 106u) {
|
||||
@@ -881,21 +881,21 @@ bool RegisterForScalarCode(uint32_t code, IR::Register& reg) {
|
||||
}
|
||||
}
|
||||
|
||||
bool EmitDispatcherLoadScalarCode(EmitterState* state, uint32_t code, uint32_t& value) {
|
||||
bool EmitDispatcherLoadScalarCode(EmitterState& state, uint32_t code, uint32_t& value) {
|
||||
IR::Register reg;
|
||||
if (!RegisterForScalarCode(code, reg)) {
|
||||
return false;
|
||||
}
|
||||
const auto pointer = PointerForRegister(*state, reg);
|
||||
const auto pointer = PointerForRegister(state, reg);
|
||||
if (pointer == 0) {
|
||||
return false;
|
||||
}
|
||||
value = state->builder.AllocateId();
|
||||
state->builder.AddFunction({OpLoad, state->uint_type, value, pointer});
|
||||
value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLoad, state.uint_type, value, pointer});
|
||||
return true;
|
||||
}
|
||||
|
||||
void EmitDispatcherStoreSelectorTarget(EmitterState* state, const CFG::Terminator& term) {
|
||||
void EmitDispatcherStoreSelectorTarget(EmitterState& state, const CFG::Terminator& term) {
|
||||
if (term.indirect_selector_code == UINT32_MAX || term.indirect_selector_values.empty() ||
|
||||
term.indirect_selector_values.size() != term.indirect_selector_targets.size()) {
|
||||
EmitDispatcherExit(state);
|
||||
@@ -910,21 +910,21 @@ void EmitDispatcherStoreSelectorTarget(EmitterState* state, const CFG::Terminato
|
||||
|
||||
uint32_t selected = ConstantU32(state, UINT32_MAX);
|
||||
for (uint32_t i = 0; i < term.indirect_selector_values.size(); i++) {
|
||||
const auto match = state->builder.AllocateId();
|
||||
state->builder.AddFunction({OpIEqual, state->bool_type, match, selector_value,
|
||||
const auto match = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpIEqual, state.bool_type, match, selector_value,
|
||||
ConstantU32(state, term.indirect_selector_values[i])});
|
||||
const auto next = state->builder.AllocateId();
|
||||
state->builder.AddFunction(
|
||||
{OpSelect, state->uint_type, next, match,
|
||||
const auto next = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpSelect, state.uint_type, next, match,
|
||||
ConstantU32(state, DispatcherTargetValue(state, term.indirect_selector_targets[i])),
|
||||
selected});
|
||||
selected = next;
|
||||
}
|
||||
state->builder.AddFunction({OpStore, state->dispatch_pc_variable, selected});
|
||||
state->builder.AddFunction({OpBranch, state->dispatch_after_switch_label});
|
||||
state.builder.AddFunction({OpStore, state.dispatch_pc_variable, selected});
|
||||
state.builder.AddFunction({OpBranch, state.dispatch_after_switch_label});
|
||||
}
|
||||
|
||||
void EmitDispatcherStoreIndirectTarget(EmitterState* state, const CFG::Terminator& term) {
|
||||
void EmitDispatcherStoreIndirectTarget(EmitterState& state, const CFG::Terminator& term) {
|
||||
if (term.indirect_selector_code != UINT32_MAX) {
|
||||
EmitDispatcherStoreSelectorTarget(state, term);
|
||||
return;
|
||||
@@ -936,55 +936,55 @@ void EmitDispatcherStoreIndirectTarget(EmitterState* state, const CFG::Terminato
|
||||
}
|
||||
|
||||
const auto pointer =
|
||||
PointerForRegister(*state, IR::Register {IR::RegisterFile::Scalar, term.indirect_pc_sgpr});
|
||||
PointerForRegister(state, IR::Register {IR::RegisterFile::Scalar, term.indirect_pc_sgpr});
|
||||
if (pointer == 0) {
|
||||
EmitDispatcherExit(state);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto pc_value = state->builder.AllocateId();
|
||||
state->builder.AddFunction({OpLoad, state->uint_type, pc_value, pointer});
|
||||
const auto pc_value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLoad, state.uint_type, pc_value, pointer});
|
||||
uint32_t selected = ConstantU32(state, UINT32_MAX);
|
||||
const auto count = std::min(term.indirect_target_pcs.size(), term.indirect_targets.size());
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
const auto match = state->builder.AllocateId();
|
||||
state->builder.AddFunction({OpIEqual, state->bool_type, match, pc_value,
|
||||
const auto match = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpIEqual, state.bool_type, match, pc_value,
|
||||
ConstantU32(state, term.indirect_target_pcs[i])});
|
||||
const auto next = state->builder.AllocateId();
|
||||
state->builder.AddFunction(
|
||||
{OpSelect, state->uint_type, next, match,
|
||||
const auto next = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpSelect, state.uint_type, next, match,
|
||||
ConstantU32(state, DispatcherTargetValue(state, term.indirect_targets[i])), selected});
|
||||
selected = next;
|
||||
}
|
||||
state->builder.AddFunction({OpStore, state->dispatch_pc_variable, selected});
|
||||
state->builder.AddFunction({OpBranch, state->dispatch_after_switch_label});
|
||||
state.builder.AddFunction({OpStore, state.dispatch_pc_variable, selected});
|
||||
state.builder.AddFunction({OpBranch, state.dispatch_after_switch_label});
|
||||
}
|
||||
|
||||
void EmitDispatcherExit(EmitterState* state) {
|
||||
state->builder.AddFunction(
|
||||
{OpStore, state->dispatch_pc_variable, ConstantU32(state, UINT32_MAX)});
|
||||
state->builder.AddFunction({OpBranch, state->dispatch_after_switch_label});
|
||||
void EmitDispatcherExit(EmitterState& state) {
|
||||
state.builder.AddFunction(
|
||||
{OpStore, state.dispatch_pc_variable, ConstantU32(state, UINT32_MAX)});
|
||||
state.builder.AddFunction({OpBranch, state.dispatch_after_switch_label});
|
||||
}
|
||||
|
||||
void EmitDispatcherTerminator(EmitterState* state, const CFG::Terminator& term) {
|
||||
void EmitDispatcherTerminator(EmitterState& state, const CFG::Terminator& term) {
|
||||
switch (term.kind) {
|
||||
case CFG::TerminatorKind::Branch:
|
||||
if (BlockLabel(*state, term.true_block) == 0) {
|
||||
if (BlockLabel(state, term.true_block) == 0) {
|
||||
EmitDispatcherExit(state);
|
||||
return;
|
||||
}
|
||||
EmitDispatcherStoreTarget(state, term.true_block);
|
||||
state->builder.AddFunction({OpBranch, state->dispatch_after_switch_label});
|
||||
state.builder.AddFunction({OpBranch, state.dispatch_after_switch_label});
|
||||
return;
|
||||
case CFG::TerminatorKind::ConditionalBranch: {
|
||||
const auto condition = EmitBranchCondition(state, term.condition);
|
||||
const auto selected = state->builder.AllocateId();
|
||||
state->builder.AddFunction(
|
||||
{OpSelect, state->uint_type, selected, condition,
|
||||
const auto selected = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpSelect, state.uint_type, selected, condition,
|
||||
ConstantU32(state, DispatcherTargetValue(state, term.true_block)),
|
||||
ConstantU32(state, DispatcherTargetValue(state, term.false_block))});
|
||||
state->builder.AddFunction({OpStore, state->dispatch_pc_variable, selected});
|
||||
state->builder.AddFunction({OpBranch, state->dispatch_after_switch_label});
|
||||
state.builder.AddFunction({OpStore, state.dispatch_pc_variable, selected});
|
||||
state.builder.AddFunction({OpBranch, state.dispatch_after_switch_label});
|
||||
return;
|
||||
}
|
||||
case CFG::TerminatorKind::IndirectBranch:
|
||||
@@ -994,44 +994,44 @@ void EmitDispatcherTerminator(EmitterState* state, const CFG::Terminator& term)
|
||||
}
|
||||
}
|
||||
|
||||
void EmitDispatcherSwitch(EmitterState* state, const IR::Program& program) {
|
||||
state->builder.AddFunction({OpLabel, state->dispatch_header_label});
|
||||
const auto pc_value = state->builder.AllocateId();
|
||||
state->builder.AddFunction({OpLoad, state->uint_type, pc_value, state->dispatch_pc_variable});
|
||||
const auto done = state->builder.AllocateId();
|
||||
state->builder.AddFunction(
|
||||
{OpIEqual, state->bool_type, done, pc_value, ConstantU32(state, UINT32_MAX)});
|
||||
state->builder.AddFunction({OpLoopMerge, state->dispatch_merge_label,
|
||||
state->dispatch_continue_label, LoopControlNone});
|
||||
state->builder.AddFunction(
|
||||
{OpBranchConditional, done, state->dispatch_merge_label, state->dispatch_select_label});
|
||||
void EmitDispatcherSwitch(EmitterState& state, const IR::Program& program) {
|
||||
state.builder.AddFunction({OpLabel, state.dispatch_header_label});
|
||||
const auto pc_value = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpLoad, state.uint_type, pc_value, state.dispatch_pc_variable});
|
||||
const auto done = state.builder.AllocateId();
|
||||
state.builder.AddFunction(
|
||||
{OpIEqual, state.bool_type, done, pc_value, ConstantU32(state, UINT32_MAX)});
|
||||
state.builder.AddFunction({OpLoopMerge, state.dispatch_merge_label,
|
||||
state.dispatch_continue_label, LoopControlNone});
|
||||
state.builder.AddFunction(
|
||||
{OpBranchConditional, done, state.dispatch_merge_label, state.dispatch_select_label});
|
||||
|
||||
state->builder.AddFunction({OpLabel, state->dispatch_select_label});
|
||||
state->builder.AddFunction(
|
||||
{OpSelectionMerge, state->dispatch_after_switch_label, SelectionControlNone});
|
||||
std::vector<uint32_t> switch_words = {OpSwitch, pc_value, state->dispatch_default_label};
|
||||
state.builder.AddFunction({OpLabel, state.dispatch_select_label});
|
||||
state.builder.AddFunction(
|
||||
{OpSelectionMerge, state.dispatch_after_switch_label, SelectionControlNone});
|
||||
std::vector<uint32_t> switch_words = {OpSwitch, pc_value, state.dispatch_default_label};
|
||||
for (const auto& block: program.blocks) {
|
||||
if (block.id >= state->reachable_blocks.size() || !state->reachable_blocks[block.id]) {
|
||||
if (block.id >= state.reachable_blocks.size() || !state.reachable_blocks[block.id]) {
|
||||
continue;
|
||||
}
|
||||
const auto label = BlockLabel(*state, block.id);
|
||||
const auto label = BlockLabel(state, block.id);
|
||||
if (label != 0) {
|
||||
switch_words.push_back(block.id);
|
||||
switch_words.push_back(label);
|
||||
}
|
||||
}
|
||||
state->builder.AddFunction(switch_words);
|
||||
state.builder.AddFunction(switch_words);
|
||||
|
||||
state->builder.AddFunction({OpLabel, state->dispatch_default_label});
|
||||
state.builder.AddFunction({OpLabel, state.dispatch_default_label});
|
||||
EmitDispatcherExit(state);
|
||||
}
|
||||
|
||||
void EmitDispatcherBlocks(EmitterState* state, const IR::Program& program) {
|
||||
void EmitDispatcherBlocks(EmitterState& state, const IR::Program& program) {
|
||||
for (const auto& block: program.blocks) {
|
||||
if (block.id >= state->reachable_blocks.size() || !state->reachable_blocks[block.id]) {
|
||||
if (block.id >= state.reachable_blocks.size() || !state.reachable_blocks[block.id]) {
|
||||
continue;
|
||||
}
|
||||
state->builder.AddFunction({OpLabel, BlockLabel(*state, block.id)});
|
||||
state.builder.AddFunction({OpLabel, BlockLabel(state, block.id)});
|
||||
for (const auto& inst: block.instructions) {
|
||||
EmitInstruction(state, inst);
|
||||
}
|
||||
@@ -1039,57 +1039,57 @@ void EmitDispatcherBlocks(EmitterState* state, const IR::Program& program) {
|
||||
}
|
||||
}
|
||||
|
||||
void EmitDispatcherLoopTail(EmitterState* state) {
|
||||
state->builder.AddFunction({OpLabel, state->dispatch_after_switch_label});
|
||||
state->builder.AddFunction({OpBranch, state->dispatch_continue_label});
|
||||
state->builder.AddFunction({OpLabel, state->dispatch_continue_label});
|
||||
state->builder.AddFunction({OpBranch, state->dispatch_header_label});
|
||||
state->builder.AddFunction({OpLabel, state->dispatch_merge_label});
|
||||
void EmitDispatcherLoopTail(EmitterState& state) {
|
||||
state.builder.AddFunction({OpLabel, state.dispatch_after_switch_label});
|
||||
state.builder.AddFunction({OpBranch, state.dispatch_continue_label});
|
||||
state.builder.AddFunction({OpLabel, state.dispatch_continue_label});
|
||||
state.builder.AddFunction({OpBranch, state.dispatch_header_label});
|
||||
state.builder.AddFunction({OpLabel, state.dispatch_merge_label});
|
||||
EmitReturn(state);
|
||||
}
|
||||
|
||||
void EmitDispatcherFunction(EmitterState* state, const IR::Program& program) {
|
||||
state->builder.AddFunction({OpStore, state->dispatch_pc_variable, ConstantU32(state, 0)});
|
||||
state->builder.AddFunction({OpBranch, state->dispatch_header_label});
|
||||
void EmitDispatcherFunction(EmitterState& state, const IR::Program& program) {
|
||||
state.builder.AddFunction({OpStore, state.dispatch_pc_variable, ConstantU32(state, 0)});
|
||||
state.builder.AddFunction({OpBranch, state.dispatch_header_label});
|
||||
EmitDispatcherSwitch(state, program);
|
||||
EmitDispatcherBlocks(state, program);
|
||||
EmitDispatcherLoopTail(state);
|
||||
}
|
||||
|
||||
void EmitFunction(EmitterState* state, const IR::Program& program) {
|
||||
state->builder.AddFunction(
|
||||
{OpFunction, state->void_type, state->main_func, FunctionControlNone, state->func_type});
|
||||
state->builder.AddFunction({OpLabel, state->entry_label});
|
||||
void EmitFunction(EmitterState& state, const IR::Program& program) {
|
||||
state.builder.AddFunction(
|
||||
{OpFunction, state.void_type, state.main_func, FunctionControlNone, state.func_type});
|
||||
state.builder.AddFunction({OpLabel, state.entry_label});
|
||||
|
||||
EmitRegisterVariables(state);
|
||||
EmitComputeInputRegisters(state);
|
||||
EmitPixelInputRegisters(state);
|
||||
EmitVertexInputRegisters(state);
|
||||
if (state->dispatcher_fallback) {
|
||||
if (state.dispatcher_fallback) {
|
||||
EmitDispatcherFunction(state, program);
|
||||
state->builder.AddFunction({OpFunctionEnd});
|
||||
state.builder.AddFunction({OpFunctionEnd});
|
||||
return;
|
||||
}
|
||||
|
||||
const auto entry_block_label = BlockLabel(*state, 0);
|
||||
const auto entry_block_label = BlockLabel(state, 0);
|
||||
if (entry_block_label != 0) {
|
||||
state->builder.AddFunction({OpBranch, entry_block_label});
|
||||
state.builder.AddFunction({OpBranch, entry_block_label});
|
||||
} else {
|
||||
EmitReturn(state);
|
||||
}
|
||||
|
||||
for (const auto& block: program.blocks) {
|
||||
if (block.id >= state->reachable_blocks.size() || !state->reachable_blocks[block.id]) {
|
||||
if (block.id >= state.reachable_blocks.size() || !state.reachable_blocks[block.id]) {
|
||||
continue;
|
||||
}
|
||||
state->builder.AddFunction({OpLabel, BlockLabel(*state, block.id)});
|
||||
state.builder.AddFunction({OpLabel, BlockLabel(state, block.id)});
|
||||
for (const auto& inst: block.instructions) {
|
||||
EmitInstruction(state, inst);
|
||||
}
|
||||
EmitTerminator(state, block.terminator);
|
||||
}
|
||||
|
||||
state->builder.AddFunction({OpFunctionEnd});
|
||||
state.builder.AddFunction({OpFunctionEnd});
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter
|
||||
Reference in new issue
Block a user