mirror of
https://git.suyu.dev/suyu/suyu
synced 2024-11-01 04:47:53 +00:00
shader: Allow tracking of indirect buffers without variable offset
While changing this code, simplify tracking code to allow returning the base address node, this way callers don't have to manually rebuild it on each invocation.
This commit is contained in:
parent
3477b92289
commit
afa8096df5
6 changed files with 34 additions and 33 deletions
|
@ -95,12 +95,8 @@ const Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::Image
|
||||||
const Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg,
|
const Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg,
|
||||||
Tegra::Shader::ImageType type) {
|
Tegra::Shader::ImageType type) {
|
||||||
const Node image_register{GetRegister(reg)};
|
const Node image_register{GetRegister(reg)};
|
||||||
const Node base_image{
|
const auto [base_image, cbuf_index, cbuf_offset]{
|
||||||
TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))};
|
TrackCbuf(image_register, global_code, static_cast<s64>(global_code.size()))};
|
||||||
const auto cbuf{std::get_if<CbufNode>(&*base_image)};
|
|
||||||
const auto cbuf_offset_imm{std::get_if<ImmediateNode>(&*cbuf->GetOffset())};
|
|
||||||
const auto cbuf_offset{cbuf_offset_imm->GetValue()};
|
|
||||||
const auto cbuf_index{cbuf->GetIndex()};
|
|
||||||
const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)};
|
const auto cbuf_key{(static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset)};
|
||||||
|
|
||||||
// If this image has already been used, return the existing mapping.
|
// If this image has already been used, return the existing mapping.
|
||||||
|
|
|
@ -297,18 +297,13 @@ std::tuple<Node, Node, GlobalMemoryBase> ShaderIR::TrackAndGetGlobalMemory(NodeB
|
||||||
const auto addr_register{GetRegister(instr.gmem.gpr)};
|
const auto addr_register{GetRegister(instr.gmem.gpr)};
|
||||||
const auto immediate_offset{static_cast<u32>(instr.gmem.offset)};
|
const auto immediate_offset{static_cast<u32>(instr.gmem.offset)};
|
||||||
|
|
||||||
const Node base_address{
|
const auto [base_address, index, offset] =
|
||||||
TrackCbuf(addr_register, global_code, static_cast<s64>(global_code.size()))};
|
TrackCbuf(addr_register, global_code, static_cast<s64>(global_code.size()));
|
||||||
const auto cbuf = std::get_if<CbufNode>(&*base_address);
|
ASSERT(base_address != nullptr);
|
||||||
ASSERT(cbuf != nullptr);
|
|
||||||
const auto cbuf_offset_imm = std::get_if<ImmediateNode>(&*cbuf->GetOffset());
|
|
||||||
ASSERT(cbuf_offset_imm != nullptr);
|
|
||||||
const auto cbuf_offset = cbuf_offset_imm->GetValue();
|
|
||||||
|
|
||||||
bb.push_back(
|
bb.push_back(Comment(fmt::format("Base address is c[0x{:x}][0x{:x}]", index, offset)));
|
||||||
Comment(fmt::format("Base address is c[0x{:x}][0x{:x}]", cbuf->GetIndex(), cbuf_offset)));
|
|
||||||
|
|
||||||
const GlobalMemoryBase descriptor{cbuf->GetIndex(), cbuf_offset};
|
const GlobalMemoryBase descriptor{index, offset};
|
||||||
const auto& [entry, is_new] = used_global_memory.try_emplace(descriptor);
|
const auto& [entry, is_new] = used_global_memory.try_emplace(descriptor);
|
||||||
auto& usage = entry->second;
|
auto& usage = entry->second;
|
||||||
if (is_write) {
|
if (is_write) {
|
||||||
|
|
|
@ -308,13 +308,9 @@ const Sampler& ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler, Textu
|
||||||
const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg, TextureType type,
|
const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg, TextureType type,
|
||||||
bool is_array, bool is_shadow) {
|
bool is_array, bool is_shadow) {
|
||||||
const Node sampler_register = GetRegister(reg);
|
const Node sampler_register = GetRegister(reg);
|
||||||
const Node base_sampler =
|
const auto [base_sampler, cbuf_index, cbuf_offset] =
|
||||||
TrackCbuf(sampler_register, global_code, static_cast<s64>(global_code.size()));
|
TrackCbuf(sampler_register, global_code, static_cast<s64>(global_code.size()));
|
||||||
const auto cbuf = std::get_if<CbufNode>(&*base_sampler);
|
ASSERT(base_sampler != nullptr);
|
||||||
const auto cbuf_offset_imm = std::get_if<ImmediateNode>(&*cbuf->GetOffset());
|
|
||||||
ASSERT(cbuf_offset_imm != nullptr);
|
|
||||||
const auto cbuf_offset = cbuf_offset_imm->GetValue();
|
|
||||||
const auto cbuf_index = cbuf->GetIndex();
|
|
||||||
const auto cbuf_key = (static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset);
|
const auto cbuf_key = (static_cast<u64>(cbuf_index) << 32) | static_cast<u64>(cbuf_offset);
|
||||||
|
|
||||||
// If this sampler has already been used, return the existing mapping.
|
// If this sampler has already been used, return the existing mapping.
|
||||||
|
|
|
@ -61,7 +61,16 @@ Node ShaderIR::GetConstBufferIndirect(u64 index_, u64 offset_, Node node) {
|
||||||
const auto [entry, is_new] = used_cbufs.try_emplace(index);
|
const auto [entry, is_new] = used_cbufs.try_emplace(index);
|
||||||
entry->second.MarkAsUsedIndirect();
|
entry->second.MarkAsUsedIndirect();
|
||||||
|
|
||||||
const Node final_offset = Operation(OperationCode::UAdd, NO_PRECISE, node, Immediate(offset));
|
const Node final_offset = [&]() {
|
||||||
|
// Attempt to inline constant buffer without a variable offset. This is done to allow
|
||||||
|
// tracking LDC calls.
|
||||||
|
if (const auto gpr = std::get_if<GprNode>(&*node)) {
|
||||||
|
if (gpr->GetIndex() == Register::ZeroIndex) {
|
||||||
|
return Immediate(offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Operation(OperationCode::UAdd, NO_PRECISE, node, Immediate(offset));
|
||||||
|
}();
|
||||||
return MakeNode<CbufNode>(index, final_offset);
|
return MakeNode<CbufNode>(index, final_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -316,7 +316,7 @@ private:
|
||||||
void WriteLop3Instruction(NodeBlock& bb, Tegra::Shader::Register dest, Node op_a, Node op_b,
|
void WriteLop3Instruction(NodeBlock& bb, Tegra::Shader::Register dest, Node op_a, Node op_b,
|
||||||
Node op_c, Node imm_lut, bool sets_cc);
|
Node op_c, Node imm_lut, bool sets_cc);
|
||||||
|
|
||||||
Node TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const;
|
std::tuple<Node, u32, u32> TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const;
|
||||||
|
|
||||||
std::optional<u32> TrackImmediate(Node tracked, const NodeBlock& code, s64 cursor) const;
|
std::optional<u32> TrackImmediate(Node tracked, const NodeBlock& code, s64 cursor) const;
|
||||||
|
|
||||||
|
|
|
@ -32,39 +32,44 @@ std::pair<Node, s64> FindOperation(const NodeBlock& code, s64 cursor,
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
} // namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
Node ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const {
|
std::tuple<Node, u32, u32> ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code,
|
||||||
|
s64 cursor) const {
|
||||||
if (const auto cbuf = std::get_if<CbufNode>(&*tracked)) {
|
if (const auto cbuf = std::get_if<CbufNode>(&*tracked)) {
|
||||||
// Cbuf found, but it has to be immediate
|
// Constant buffer found, test if it's an immediate
|
||||||
return std::holds_alternative<ImmediateNode>(*cbuf->GetOffset()) ? tracked : nullptr;
|
const auto offset = cbuf->GetOffset();
|
||||||
|
if (const auto immediate = std::get_if<ImmediateNode>(&*offset)) {
|
||||||
|
return {tracked, cbuf->GetIndex(), immediate->GetValue()};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
if (const auto gpr = std::get_if<GprNode>(&*tracked)) {
|
if (const auto gpr = std::get_if<GprNode>(&*tracked)) {
|
||||||
if (gpr->GetIndex() == Tegra::Shader::Register::ZeroIndex) {
|
if (gpr->GetIndex() == Tegra::Shader::Register::ZeroIndex) {
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
// Reduce the cursor in one to avoid infinite loops when the instruction sets the same
|
// Reduce the cursor in one to avoid infinite loops when the instruction sets the same
|
||||||
// register that it uses as operand
|
// register that it uses as operand
|
||||||
const auto [source, new_cursor] = TrackRegister(gpr, code, cursor - 1);
|
const auto [source, new_cursor] = TrackRegister(gpr, code, cursor - 1);
|
||||||
if (!source) {
|
if (!source) {
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
return TrackCbuf(source, code, new_cursor);
|
return TrackCbuf(source, code, new_cursor);
|
||||||
}
|
}
|
||||||
if (const auto operation = std::get_if<OperationNode>(&*tracked)) {
|
if (const auto operation = std::get_if<OperationNode>(&*tracked)) {
|
||||||
for (std::size_t i = 0; i < operation->GetOperandsCount(); ++i) {
|
for (std::size_t i = 0; i < operation->GetOperandsCount(); ++i) {
|
||||||
if (const auto found = TrackCbuf((*operation)[i], code, cursor)) {
|
if (auto found = TrackCbuf((*operation)[i], code, cursor); std::get<0>(found)) {
|
||||||
// Cbuf found in operand
|
// Cbuf found in operand.
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
if (const auto conditional = std::get_if<ConditionalNode>(&*tracked)) {
|
if (const auto conditional = std::get_if<ConditionalNode>(&*tracked)) {
|
||||||
const auto& conditional_code = conditional->GetCode();
|
const auto& conditional_code = conditional->GetCode();
|
||||||
return TrackCbuf(tracked, conditional_code, static_cast<s64>(conditional_code.size()));
|
return TrackCbuf(tracked, conditional_code, static_cast<s64>(conditional_code.size()));
|
||||||
}
|
}
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<u32> ShaderIR::TrackImmediate(Node tracked, const NodeBlock& code, s64 cursor) const {
|
std::optional<u32> ShaderIR::TrackImmediate(Node tracked, const NodeBlock& code, s64 cursor) const {
|
||||||
|
|
Loading…
Reference in a new issue