From 3b84e04af1ce2f9e218e7bcf225dd3eff1ddc61d Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sat, 29 Dec 2018 02:44:54 -0300 Subject: shader_decode: Implement LDG and basic cbuf tracking --- src/video_core/shader/track.cpp | 76 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/video_core/shader/track.cpp (limited to 'src/video_core/shader/track.cpp') diff --git a/src/video_core/shader/track.cpp b/src/video_core/shader/track.cpp new file mode 100644 index 000000000..d6d29ee9f --- /dev/null +++ b/src/video_core/shader/track.cpp @@ -0,0 +1,76 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include + +#include "video_core/shader/shader_ir.h" + +namespace VideoCommon::Shader { + +namespace { +std::pair FindOperation(const BasicBlock& code, s64 cursor, + OperationCode operation_code) { + for (; cursor >= 0; --cursor) { + const Node node = code[cursor]; + if (const auto operation = std::get_if(node)) { + if (operation->GetCode() == operation_code) + return {node, cursor}; + } + } + return {}; +} +} // namespace + +Node ShaderIR::TrackCbuf(Node tracked, const BasicBlock& code, s64 cursor) { + if (const auto cbuf = std::get_if(tracked)) { + // Cbuf found, but it has to be immediate + return std::holds_alternative(*cbuf->GetOffset()) ? tracked : nullptr; + } + if (const auto gpr = std::get_if(tracked)) { + if (gpr->GetIndex() == Tegra::Shader::Register::ZeroIndex) { + return nullptr; + } + // Reduce the cursor in one to avoid infinite loops when the instruction sets the same + // register that it uses as operand + const auto [source, new_cursor] = TrackRegister(gpr, code, cursor - 1); + if (!source) { + return nullptr; + } + return TrackCbuf(source, code, new_cursor); + } + if (const auto operation = std::get_if(tracked)) { + for (std::size_t i = 0; i < operation->GetOperandsCount(); ++i) { + if (const auto found = TrackCbuf((*operation)[i], code, cursor)) { + // Cbuf found in operand + return found; + } + } + return nullptr; + } + return nullptr; +} + +std::pair ShaderIR::TrackRegister(const GprNode* tracked, const BasicBlock& code, + s64 cursor) { + for (; cursor >= 0; --cursor) { + const auto [found_node, new_cursor] = FindOperation(code, cursor, OperationCode::Assign); + if (!found_node) { + return {}; + } + const auto operation = std::get_if(found_node); + ASSERT(operation); + + const auto& target = (*operation)[0]; + if (const auto gpr_target = std::get_if(target)) { + if (gpr_target->GetIndex() == tracked->GetIndex()) { + return {(*operation)[1], new_cursor}; + } + } + } + return {}; +} + +} // namespace VideoCommon::Shader -- cgit v1.2.3