diff --git a/src/xenia/gpu/shader.h b/src/xenia/gpu/shader.h index ebe491d65..e3e4d7072 100644 --- a/src/xenia/gpu/shader.h +++ b/src/xenia/gpu/shader.h @@ -493,6 +493,21 @@ class Shader { ParsedTextureFetchInstruction fetch_instr; }; + struct ConstantRegisterMap { + // Bitmap of all kConstantFloat registers read by the shader. + // Any shader can only read up to 256 of the 512, and the base is dependent + // on the shader type. Each bit corresponds to a storage index from the type + // base, so bit 0 in a vertex shader is register 0, and bit 0 in a fragment + // shader is register 256. + uint64_t float_bitmap[256 / 64]; + // Bitmap of all kConstantInt registers read by the shader. + // Each bit corresponds to a storage index [0-31]. + uint32_t int_bitmap; + // Bitmap of all kConstantBool registers read by the shader. + // Each bit corresponds to a storage index [0-31]. + uint32_t bool_bitmap; + }; + Shader(ShaderType shader_type, uint64_t ucode_data_hash, const uint32_t* ucode_dwords, size_t ucode_dword_count); virtual ~Shader(); @@ -518,6 +533,11 @@ class Shader { return texture_bindings_; } + // Bitmaps of all constant registers accessed by the shader. + const ConstantRegisterMap& constant_register_map() const { + return constant_register_map_; + } + // Returns true if the given color target index [0-3]. bool writes_color_target(int i) const { return writes_color_targets_[i]; } @@ -564,6 +584,7 @@ class Shader { std::vector vertex_bindings_; std::vector texture_bindings_; + ConstantRegisterMap constant_register_map_ = {0}; bool writes_color_targets_[4] = {false, false, false, false}; bool is_valid_ = false; diff --git a/src/xenia/gpu/shader_translator.cc b/src/xenia/gpu/shader_translator.cc index 4991833ab..68a70d5fb 100644 --- a/src/xenia/gpu/shader_translator.cc +++ b/src/xenia/gpu/shader_translator.cc @@ -53,13 +53,14 @@ void ShaderTranslator::Reset() { total_attrib_count_ = 0; vertex_bindings_.clear(); texture_bindings_.clear(); + std::memset(&constant_register_map_, 0, sizeof(constant_register_map_)); for (size_t i = 0; i < xe::countof(writes_color_targets_); ++i) { writes_color_targets_[i] = false; } } bool ShaderTranslator::GatherAllBindingInformation(Shader* shader) { - // FIXME: This is kind of silly. + // DEPRECATED: remove this codepath when GL4 goes away. Reset(); shader_type_ = shader->type(); @@ -129,6 +130,7 @@ bool ShaderTranslator::Translate(Shader* shader) { shader->ucode_disassembly_ = ucode_disasm_buffer_.to_string(); shader->vertex_bindings_ = std::move(vertex_bindings_); shader->texture_bindings_ = std::move(texture_bindings_); + shader->constant_register_map_ = std::move(constant_register_map_); for (size_t i = 0; i < xe::countof(writes_color_targets_); ++i) { shader->writes_color_targets_[i] = writes_color_targets_[i]; } @@ -488,6 +490,7 @@ void ShaderTranslator::TranslateControlFlowCondExec( i.instruction_count = cf.count(); i.type = ParsedExecInstruction::Type::kConditional; i.bool_constant_index = cf.bool_address(); + constant_register_map_.bool_bitmap |= 1 << i.bool_constant_index; i.condition = cf.condition(); switch (cf.opcode()) { case ControlFlowOpcode::kCondExec: @@ -527,6 +530,7 @@ void ShaderTranslator::TranslateControlFlowLoopStart( ParsedLoopStartInstruction i; i.dword_index = cf_index_; i.loop_constant_index = cf.loop_id(); + constant_register_map_.int_bitmap |= 1 << i.loop_constant_index; i.is_repeat = cf.is_repeat(); i.loop_skip_address = cf.address(); @@ -542,6 +546,7 @@ void ShaderTranslator::TranslateControlFlowLoopEnd( i.is_predicated_break = cf.is_predicated_break(); i.predicate_condition = cf.condition(); i.loop_constant_index = cf.loop_id(); + constant_register_map_.int_bitmap |= 1 << i.loop_constant_index; i.loop_body_address = cf.address(); i.Disassemble(&ucode_disasm_buffer_); @@ -562,6 +567,7 @@ void ShaderTranslator::TranslateControlFlowCondCall( } else { i.type = ParsedCallInstruction::Type::kConditional; i.bool_constant_index = cf.bool_address(); + constant_register_map_.bool_bitmap |= 1 << i.bool_constant_index; i.condition = cf.condition(); } @@ -593,6 +599,7 @@ void ShaderTranslator::TranslateControlFlowCondJmp( } else { i.type = ParsedJumpInstruction::Type::kConditional; i.bool_constant_index = cf.bool_address(); + constant_register_map_.bool_bitmap |= 1 << i.bool_constant_index; i.condition = cf.condition(); } @@ -1150,6 +1157,14 @@ void ShaderTranslator::ParseAluVectorInstruction( for (int j = 0; j < i.operand_count; ++j) { ParseAluInstructionOperand( op, j + 1, opcode_info.src_swizzle_component_count, &i.operands[j]); + + // Track constant float register loads. + if (i.operands[j].storage_source == + InstructionStorageSource::kConstantFloat) { + auto register_index = i.operands[j].storage_index; + constant_register_map_.float_bitmap[register_index / 64] |= + 1ull << (register_index % 64); + } } i.Disassemble(&ucode_disasm_buffer_); @@ -1243,9 +1258,16 @@ void ShaderTranslator::ParseAluScalarInstruction( uint32_t reg2 = (static_cast(op.scalar_opcode()) & 1) | (src3_swizzle & 0x3C) | (op.src_is_temp(3) << 1); int const_slot = (op.src_is_temp(1) || op.src_is_temp(2)) ? 1 : 0; + ParseAluInstructionOperandSpecial( op, InstructionStorageSource::kConstantFloat, op.src_reg(3), op.src_negate(3), 0, swiz_a, &i.operands[0]); + + // Track constant float register loads. + auto register_index = i.operands[0].storage_index; + constant_register_map_.float_bitmap[register_index / 64] |= + 1ull << (register_index % 64); + ParseAluInstructionOperandSpecial(op, InstructionStorageSource::kRegister, reg2, op.src_negate(3), const_slot, swiz_b, &i.operands[1]); diff --git a/src/xenia/gpu/shader_translator.h b/src/xenia/gpu/shader_translator.h index d1d731926..8c8a8c176 100644 --- a/src/xenia/gpu/shader_translator.h +++ b/src/xenia/gpu/shader_translator.h @@ -27,8 +27,9 @@ class ShaderTranslator { virtual ~ShaderTranslator(); // Gathers all vertex/texture bindings. Implicitly called in Translate. - // TODO: Move this functionality to Shader. + // DEPRECATED(benvanik): remove this when shader cache is removed. bool GatherAllBindingInformation(Shader* shader); + bool Translate(Shader* shader); protected: @@ -191,6 +192,7 @@ class ShaderTranslator { int total_attrib_count_ = 0; std::vector vertex_bindings_; std::vector texture_bindings_; + Shader::ConstantRegisterMap constant_register_map_ = {0}; bool writes_color_targets_[4] = {false, false, false, false}; static const AluOpcodeInfo alu_vector_opcode_infos_[0x20];