diff --git a/src/xenia/gpu/shader.h b/src/xenia/gpu/shader.h index f0f31ef73..5653bf49e 100644 --- a/src/xenia/gpu/shader.h +++ b/src/xenia/gpu/shader.h @@ -31,8 +31,8 @@ enum class InstructionStorageTarget { kPosition, // Result is stored to the point size export (gl_PointSize). kPointSize, - // Result is stored as memexport destination address. - // [physical >> 2, ??, ??, ??] + // Result is stored as memexport destination address + // (see xenos::xe_gpu_memexport_stream_t). kExportAddress, // Result is stored to memexport destination data. kExportData, @@ -583,6 +583,11 @@ class Shader { return constant_register_map_; } + // All c# registers used as the addend in MAD operations to eA. + const std::vector& memexport_stream_constants() const { + return memexport_stream_constants_; + } + // Returns true if the given color target index [0-3]. bool writes_color_target(int i) const { return writes_color_targets_[i]; } @@ -634,6 +639,7 @@ class Shader { std::vector texture_bindings_; ConstantRegisterMap constant_register_map_ = {0}; bool writes_color_targets_[4] = {false, false, false, false}; + std::vector memexport_stream_constants_; bool is_valid_ = false; bool is_translated_ = false; diff --git a/src/xenia/gpu/shader_translator.cc b/src/xenia/gpu/shader_translator.cc index 2f9609b51..4d65a8d37 100644 --- a/src/xenia/gpu/shader_translator.cc +++ b/src/xenia/gpu/shader_translator.cc @@ -63,6 +63,7 @@ void ShaderTranslator::Reset() { writes_color_targets_[i] = false; } writes_depth_ = false; + memexport_stream_constants_.clear(); } bool ShaderTranslator::GatherAllBindingInformation(Shader* shader) { @@ -174,6 +175,10 @@ bool ShaderTranslator::TranslateInternal(Shader* shader) { for (size_t i = 0; i < xe::countof(writes_color_targets_); ++i) { shader->writes_color_targets_[i] = writes_color_targets_[i]; } + shader->memexport_stream_constants_.clear(); + for (uint32_t memexport_stream_constant : memexport_stream_constants_) { + shader->memexport_stream_constants_.push_back(memexport_stream_constant); + } shader->is_valid_ = true; shader->is_translated_ = true; @@ -282,6 +287,18 @@ void ShaderTranslator::GatherInstructionInformation( writes_depth_ = true; } } + // Store used memexport constants because CPU code needs addresses + // and sizes. eA is (hopefully) always written to using: + // mad eA, r#, const0100, c# + // (though there are some exceptions, shaders in Halo 3 for some + // reason set eA to zeros, but the swizzle of the constant is not + // .xyzw in this case, and they don't write to eM#). + if (op.vector_dest() == 32 && + op.vector_opcode() == AluVectorOpcode::kMad && + op.vector_write_mask() == 0b1111 && !op.src_is_temp(3) && + op.src_swizzle(3) == 0) { + memexport_stream_constants_.insert(op.src_reg(3)); + } } else { if (op.is_vector_dest_relative()) { uses_register_dynamic_addressing_ = true; diff --git a/src/xenia/gpu/shader_translator.h b/src/xenia/gpu/shader_translator.h index 238daea7d..b79bf2fac 100644 --- a/src/xenia/gpu/shader_translator.h +++ b/src/xenia/gpu/shader_translator.h @@ -11,6 +11,7 @@ #define XENIA_GPU_SHADER_TRANSLATOR_H_ #include +#include #include #include @@ -65,6 +66,11 @@ class ShaderTranslator { const std::vector& texture_bindings() const { return texture_bindings_; } + // All c# registers used as the addend in MAD operations to eA, populated + // before translation occurs. + const std::set& memexport_stream_constants() const { + return memexport_stream_constants_; + } // Current line number in the ucode disassembly. size_t ucode_disasm_line_number() const { return ucode_disasm_line_number_; } @@ -230,6 +236,7 @@ class ShaderTranslator { bool uses_register_dynamic_addressing_ = false; bool writes_color_targets_[4] = {false, false, false, false}; bool writes_depth_ = false; + std::set memexport_stream_constants_; static const AluOpcodeInfo alu_vector_opcode_infos_[0x20]; static const AluOpcodeInfo alu_scalar_opcode_infos_[0x40];