diff --git a/src/xenia/gpu/shader_translator.cc b/src/xenia/gpu/shader_translator.cc index 1f3e13dbc..2fffe3f0e 100644 --- a/src/xenia/gpu/shader_translator.cc +++ b/src/xenia/gpu/shader_translator.cc @@ -58,6 +58,7 @@ void ShaderTranslator::Reset() { texture_bindings_.clear(); unique_texture_bindings_ = 0; std::memset(&constant_register_map_, 0, sizeof(constant_register_map_)); + uses_register_relative_addressing_ = false; for (size_t i = 0; i < xe::countof(writes_color_targets_); ++i) { writes_color_targets_[i] = false; } @@ -85,8 +86,8 @@ bool ShaderTranslator::GatherAllBindingInformation(Shader* shader) { std::min(max_cf_dword_index, cf_b.exec.address() * 3); } - GatherBindingInformation(cf_a); - GatherBindingInformation(cf_b); + GatherInstructionInformation(cf_a); + GatherInstructionInformation(cf_b); } shader->vertex_bindings_ = std::move(vertex_bindings_); @@ -117,7 +118,8 @@ bool ShaderTranslator::TranslateInternal(Shader* shader) { ucode_dwords_ = shader->ucode_dwords(); ucode_dword_count_ = shader->ucode_dword_count(); - // Run through and gather all binding information. + // Run through and gather all binding information and to check whether + // registers are dynamically addressed. // Translators may need this before they start codegen. uint32_t max_cf_dword_index = static_cast(ucode_dword_count_); for (uint32_t i = 0; i < max_cf_dword_index; i += 3) { @@ -133,8 +135,8 @@ bool ShaderTranslator::TranslateInternal(Shader* shader) { std::min(max_cf_dword_index, cf_b.exec.address() * 3); } - GatherBindingInformation(cf_a); - GatherBindingInformation(cf_b); + GatherInstructionInformation(cf_a); + GatherInstructionInformation(cf_b); } StartTranslation(); @@ -225,7 +227,7 @@ void ShaderTranslator::EmitUnimplementedTranslationError() { errors_.push_back(std::move(error)); } -void ShaderTranslator::GatherBindingInformation( +void ShaderTranslator::GatherInstructionInformation( const ControlFlowInstruction& cf) { switch (cf.opcode()) { case ControlFlowOpcode::kExec: @@ -247,24 +249,52 @@ void ShaderTranslator::GatherBindingInformation( static_cast(ucode_dwords_[instr_offset * 3] & 0x1F); if (fetch_opcode == FetchOpcode::kVertexFetch) { assert_true(is_vertex_shader()); - GatherVertexBindingInformation( + GatherVertexFetchInformation( *reinterpret_cast( ucode_dwords_ + instr_offset * 3)); } else { - GatherTextureBindingInformation( + GatherTextureFetchInformation( *reinterpret_cast( ucode_dwords_ + instr_offset * 3)); } - } else if (is_pixel_shader()) { - // Gather up color targets written to. + } else { + // Gather up color targets written to, and check if using dynamic + // register indices. auto& op = *reinterpret_cast(ucode_dwords_ + instr_offset * 3); - if (op.is_export()) { - if (op.has_vector_op() && op.vector_dest() <= 3) { - writes_color_targets_[op.vector_dest()] = true; + if (op.has_vector_op()) { + const auto& opcode_info = + alu_vector_opcode_infos_[static_cast(op.vector_opcode())]; + for (size_t i = 0; i < opcode_info.argument_count; ++i) { + if (op.src_is_temp(i) && (op.src_reg(i) & 0x40)) { + uses_register_relative_addressing_ = true; + } } - if (op.has_scalar_op() && op.scalar_dest() <= 3) { - writes_color_targets_[op.scalar_dest()] = true; + if (op.is_export()) { + if (is_pixel_shader() && op.vector_dest() <= 3) { + writes_color_targets_[op.vector_dest()] = true; + } + } else { + if (op.is_vector_dest_relative()) { + uses_register_relative_addressing_ = true; + } + } + } + if (op.has_scalar_op()) { + const auto& opcode_info = + alu_scalar_opcode_infos_[static_cast(op.scalar_opcode())]; + if (opcode_info.argument_count == 1 && op.src_is_temp(0) && + (op.src_reg(0) & 0x40)) { + uses_register_relative_addressing_ = true; + } + if (op.is_export()) { + if (is_pixel_shader() && op.scalar_dest() <= 3) { + writes_color_targets_[op.scalar_dest()] = true; + } + } else { + if (op.is_scalar_dest_relative()) { + uses_register_relative_addressing_ = true; + } } } } @@ -275,7 +305,7 @@ void ShaderTranslator::GatherBindingInformation( } } -void ShaderTranslator::GatherVertexBindingInformation( +void ShaderTranslator::GatherVertexFetchInformation( const VertexFetchInstruction& op) { ParsedVertexFetchInstruction fetch_instr; ParseVertexFetchInstruction(op, &fetch_instr); @@ -285,6 +315,11 @@ void ShaderTranslator::GatherVertexBindingInformation( return; } + // Check if using dynamic register indices. + if (op.is_dest_relative() || op.is_src_relative()) { + uses_register_relative_addressing_ = true; + } + // Try to allocate an attribute on an existing binding. // If no binding for this fetch slot is found create it. using VertexBinding = Shader::VertexBinding; @@ -317,8 +352,13 @@ void ShaderTranslator::GatherVertexBindingInformation( GetVertexFormatSizeInWords(attrib->fetch_instr.attributes.data_format); } -void ShaderTranslator::GatherTextureBindingInformation( +void ShaderTranslator::GatherTextureFetchInformation( const TextureFetchInstruction& op) { + // Check if using dynamic register indices. + if (op.is_dest_relative() || op.is_src_relative()) { + uses_register_relative_addressing_ = true; + } + switch (op.opcode()) { case FetchOpcode::kSetTextureLod: case FetchOpcode::kSetTextureGradientsHorz: diff --git a/src/xenia/gpu/shader_translator.h b/src/xenia/gpu/shader_translator.h index 267104470..f717aa3a0 100644 --- a/src/xenia/gpu/shader_translator.h +++ b/src/xenia/gpu/shader_translator.h @@ -143,10 +143,9 @@ class ShaderTranslator { void AppendUcodeDisasmFormat(const char* format, ...); bool TranslateBlocks(); - void GatherBindingInformation(const ucode::ControlFlowInstruction& cf); - void GatherVertexBindingInformation(const ucode::VertexFetchInstruction& op); - void GatherTextureBindingInformation( - const ucode::TextureFetchInstruction& op); + void GatherInstructionInformation(const ucode::ControlFlowInstruction& cf); + void GatherVertexFetchInformation(const ucode::VertexFetchInstruction& op); + void GatherTextureFetchInformation(const ucode::TextureFetchInstruction& op); void TranslateControlFlowInstruction(const ucode::ControlFlowInstruction& cf); void TranslateControlFlowNop(const ucode::ControlFlowInstruction& cf); void TranslateControlFlowExec(const ucode::ControlFlowExecInstruction& cf); @@ -216,6 +215,7 @@ class ShaderTranslator { uint32_t unique_texture_bindings_ = 0; Shader::ConstantRegisterMap constant_register_map_ = {0}; + bool uses_register_relative_addressing_ = false; bool writes_color_targets_[4] = {false, false, false, false}; static const AluOpcodeInfo alu_vector_opcode_infos_[0x20];