summaryrefslogtreecommitdiffstats
path: root/src/video_core/shader/track.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/shader/track.cpp')
-rw-r--r--src/video_core/shader/track.cpp76
1 files changed, 76 insertions, 0 deletions
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 <algorithm>
+#include <utility>
+#include <variant>
+
+#include "video_core/shader/shader_ir.h"
+
+namespace VideoCommon::Shader {
+
+namespace {
+std::pair<Node, s64> 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<OperationNode>(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<CbufNode>(tracked)) {
+ // Cbuf found, but it has to be immediate
+ return std::holds_alternative<ImmediateNode>(*cbuf->GetOffset()) ? tracked : nullptr;
+ }
+ if (const auto gpr = std::get_if<GprNode>(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<OperationNode>(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<Node, s64> 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<OperationNode>(found_node);
+ ASSERT(operation);
+
+ const auto& target = (*operation)[0];
+ if (const auto gpr_target = std::get_if<GprNode>(target)) {
+ if (gpr_target->GetIndex() == tracked->GetIndex()) {
+ return {(*operation)[1], new_cursor};
+ }
+ }
+ }
+ return {};
+}
+
+} // namespace VideoCommon::Shader