[GPU] Gather eA/eM# writes in shader translator
This commit is contained in:
parent
090bf8e353
commit
73baaa8e89
|
@ -42,6 +42,8 @@ using namespace ucode;
|
||||||
// Lots of naming comes from the disassembly spit out by the XNA GS compiler
|
// Lots of naming comes from the disassembly spit out by the XNA GS compiler
|
||||||
// and dumps of d3dcompiler and games: https://pastebin.com/i4kAv7bB
|
// and dumps of d3dcompiler and games: https://pastebin.com/i4kAv7bB
|
||||||
|
|
||||||
|
constexpr uint32_t ShaderTranslator::kMaxMemExports;
|
||||||
|
|
||||||
ShaderTranslator::ShaderTranslator() = default;
|
ShaderTranslator::ShaderTranslator() = default;
|
||||||
|
|
||||||
ShaderTranslator::~ShaderTranslator() = default;
|
ShaderTranslator::~ShaderTranslator() = default;
|
||||||
|
@ -63,6 +65,9 @@ void ShaderTranslator::Reset() {
|
||||||
writes_color_targets_[i] = false;
|
writes_color_targets_[i] = false;
|
||||||
}
|
}
|
||||||
writes_depth_ = false;
|
writes_depth_ = false;
|
||||||
|
memexport_alloc_count_ = 0;
|
||||||
|
memexport_eA_written_ = 0;
|
||||||
|
std::memset(&memexport_eM_written_, 0, sizeof(memexport_eM_written_));
|
||||||
memexport_stream_constants_.clear();
|
memexport_stream_constants_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,17 +292,30 @@ void ShaderTranslator::GatherInstructionInformation(
|
||||||
writes_depth_ = true;
|
writes_depth_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Store used memexport constants because CPU code needs addresses
|
if (memexport_alloc_count_ > 0 &&
|
||||||
// and sizes. eA is (hopefully) always written to using:
|
memexport_alloc_count_ <= kMaxMemExports) {
|
||||||
|
// Store used memexport constants because CPU code needs
|
||||||
|
// addresses and sizes, and also whether there have been writes
|
||||||
|
// to eA and eM# for register allocation in shader translator
|
||||||
|
// implementations.
|
||||||
|
// eA is (hopefully) always written to using:
|
||||||
// mad eA, r#, const0100, c#
|
// mad eA, r#, const0100, c#
|
||||||
// (though there are some exceptions, shaders in Halo 3 for some
|
// (though there are some exceptions, shaders in Halo 3 for some
|
||||||
// reason set eA to zeros, but the swizzle of the constant is not
|
// reason set eA to zeros, but the swizzle of the constant is
|
||||||
// .xyzw in this case, and they don't write to eM#).
|
// not .xyzw in this case, and they don't write to eM#).
|
||||||
|
uint32_t memexport_alloc_index = memexport_alloc_count_ - 1;
|
||||||
if (op.vector_dest() == 32 &&
|
if (op.vector_dest() == 32 &&
|
||||||
op.vector_opcode() == AluVectorOpcode::kMad &&
|
op.vector_opcode() == AluVectorOpcode::kMad &&
|
||||||
op.vector_write_mask() == 0b1111 && !op.src_is_temp(3) &&
|
op.vector_write_mask() == 0b1111 && !op.src_is_temp(3) &&
|
||||||
op.src_swizzle(3) == 0) {
|
op.src_swizzle(3) == 0) {
|
||||||
|
memexport_eA_written_ |= 1u << memexport_alloc_index;
|
||||||
memexport_stream_constants_.insert(op.src_reg(3));
|
memexport_stream_constants_.insert(op.src_reg(3));
|
||||||
|
} else if (op.vector_dest() >= 33 && op.vector_dest() <= 37) {
|
||||||
|
if (memexport_eA_written_ & (1u << memexport_alloc_index)) {
|
||||||
|
memexport_eM_written_[memexport_alloc_index] |=
|
||||||
|
1 << (op.vector_dest() - 33);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (op.is_vector_dest_relative()) {
|
if (op.is_vector_dest_relative()) {
|
||||||
|
@ -320,6 +338,15 @@ void ShaderTranslator::GatherInstructionInformation(
|
||||||
writes_depth_ = true;
|
writes_depth_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (memexport_alloc_count_ > 0 &&
|
||||||
|
memexport_alloc_count_ <= kMaxMemExports &&
|
||||||
|
op.scalar_dest() >= 33 && op.scalar_dest() <= 37) {
|
||||||
|
uint32_t memexport_alloc_index = memexport_alloc_count_ - 1;
|
||||||
|
if (memexport_eA_written_ & (1u << memexport_alloc_index)) {
|
||||||
|
memexport_eM_written_[memexport_alloc_index] |=
|
||||||
|
1 << (op.scalar_dest() - 33);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (op.is_scalar_dest_relative()) {
|
if (op.is_scalar_dest_relative()) {
|
||||||
uses_register_dynamic_addressing_ = true;
|
uses_register_dynamic_addressing_ = true;
|
||||||
|
@ -329,6 +356,11 @@ void ShaderTranslator::GatherInstructionInformation(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case ControlFlowOpcode::kAlloc:
|
||||||
|
if (cf.alloc.alloc_type() == AllocType::kMemory) {
|
||||||
|
++memexport_alloc_count_;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,15 @@ class ShaderTranslator {
|
||||||
const std::vector<Shader::TextureBinding>& texture_bindings() const {
|
const std::vector<Shader::TextureBinding>& texture_bindings() const {
|
||||||
return texture_bindings_;
|
return texture_bindings_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Based on the number of AS_VS/PS_EXPORT_STREAM_* enum sets found in a game
|
||||||
|
// .pdb.
|
||||||
|
static constexpr uint32_t kMaxMemExports = 16;
|
||||||
|
// Bits indicating which eM# registers have been written to after each
|
||||||
|
// `alloc export`, for up to kMaxMemExports exports. This will contain zero
|
||||||
|
// for certain corrupt exports - that don't write to eA before writing to eM#,
|
||||||
|
// or if the write was done any way other than MAD with a stream constant.
|
||||||
|
const uint8_t* memexport_eM_written() const { return memexport_eM_written_; }
|
||||||
// All c# registers used as the addend in MAD operations to eA, populated
|
// All c# registers used as the addend in MAD operations to eA, populated
|
||||||
// before translation occurs.
|
// before translation occurs.
|
||||||
const std::set<uint32_t>& memexport_stream_constants() const {
|
const std::set<uint32_t>& memexport_stream_constants() const {
|
||||||
|
@ -236,6 +245,12 @@ class ShaderTranslator {
|
||||||
bool uses_register_dynamic_addressing_ = false;
|
bool uses_register_dynamic_addressing_ = false;
|
||||||
bool writes_color_targets_[4] = {false, false, false, false};
|
bool writes_color_targets_[4] = {false, false, false, false};
|
||||||
bool writes_depth_ = false;
|
bool writes_depth_ = false;
|
||||||
|
|
||||||
|
uint32_t memexport_alloc_count_ = 0;
|
||||||
|
// For register allocation in implementations - what was used after each
|
||||||
|
// `alloc export`.
|
||||||
|
uint32_t memexport_eA_written_ = 0;
|
||||||
|
uint8_t memexport_eM_written_[kMaxMemExports] = {0};
|
||||||
std::set<uint32_t> memexport_stream_constants_;
|
std::set<uint32_t> memexport_stream_constants_;
|
||||||
|
|
||||||
static const AluOpcodeInfo alu_vector_opcode_infos_[0x20];
|
static const AluOpcodeInfo alu_vector_opcode_infos_[0x20];
|
||||||
|
|
Loading…
Reference in New Issue