summaryrefslogtreecommitdiff
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.cpp106
1 files changed, 106 insertions, 0 deletions
diff --git a/src/video_core/shader/track.cpp b/src/video_core/shader/track.cpp
index 165c79330..ea39bca54 100644
--- a/src/video_core/shader/track.cpp
+++ b/src/video_core/shader/track.cpp
@@ -8,6 +8,7 @@
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/shader/node.h" 10#include "video_core/shader/node.h"
11#include "video_core/shader/node_helper.h"
11#include "video_core/shader/shader_ir.h" 12#include "video_core/shader/shader_ir.h"
12 13
13namespace VideoCommon::Shader { 14namespace VideoCommon::Shader {
@@ -35,8 +36,113 @@ std::pair<Node, s64> FindOperation(const NodeBlock& code, s64 cursor,
35 } 36 }
36 return {}; 37 return {};
37} 38}
39
40std::optional<std::pair<Node, Node>> DecoupleIndirectRead(const OperationNode& operation) {
41 if (operation.GetCode() != OperationCode::UAdd) {
42 return std::nullopt;
43 }
44 Node gpr{};
45 Node offset{};
46 ASSERT(operation.GetOperandsCount() == 2);
47 for (std::size_t i = 0; i < operation.GetOperandsCount(); i++) {
48 Node operand = operation[i];
49 if (std::holds_alternative<ImmediateNode>(*operand)) {
50 offset = operation[i];
51 } else if (std::holds_alternative<GprNode>(*operand)) {
52 gpr = operation[i];
53 }
54 }
55 if (offset && gpr) {
56 return std::make_pair(gpr, offset);
57 }
58 return std::nullopt;
59}
60
61bool AmendNodeCv(std::size_t amend_index, Node node) {
62 if (const auto operation = std::get_if<OperationNode>(&*node)) {
63 operation->SetAmendIndex(amend_index);
64 return true;
65 } else if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
66 conditional->SetAmendIndex(amend_index);
67 return true;
68 }
69 return false;
70}
71
38} // Anonymous namespace 72} // Anonymous namespace
39 73
74std::tuple<Node, TrackSampler> ShaderIR::TrackBindlessSampler(Node tracked, const NodeBlock& code,
75 s64 cursor) {
76 if (const auto cbuf = std::get_if<CbufNode>(&*tracked)) {
77 // Constant buffer found, test if it's an immediate
78 const auto offset = cbuf->GetOffset();
79 if (const auto immediate = std::get_if<ImmediateNode>(&*offset)) {
80 auto track =
81 MakeTrackSampler<BindlessSamplerNode>(cbuf->GetIndex(), immediate->GetValue());
82 return {tracked, track};
83 } else if (const auto operation = std::get_if<OperationNode>(&*offset)) {
84 auto bound_buffer = locker.ObtainBoundBuffer();
85 if (!bound_buffer) {
86 return {};
87 }
88 if (*bound_buffer != cbuf->GetIndex()) {
89 return {};
90 }
91 auto pair = DecoupleIndirectRead(*operation);
92 if (!pair) {
93 return {};
94 }
95 auto [gpr, base_offset] = *pair;
96 const auto offset_inm = std::get_if<ImmediateNode>(&*base_offset);
97 auto gpu_driver = locker.AccessGuestDriverProfile();
98 if (gpu_driver == nullptr) {
99 return {};
100 }
101 const u32 bindless_cv = NewCustomVariable();
102 const Node op = Operation(OperationCode::UDiv, NO_PRECISE, gpr,
103 Immediate(gpu_driver->GetTextureHandlerSize()));
104
105 const Node cv_node = GetCustomVariable(bindless_cv);
106 Node amend_op = Operation(OperationCode::Assign, cv_node, std::move(op));
107 const std::size_t amend_index = DeclareAmend(amend_op);
108 AmendNodeCv(amend_index, code[cursor]);
109 // TODO Implement Bindless Index custom variable
110 auto track = MakeTrackSampler<ArraySamplerNode>(cbuf->GetIndex(),
111 offset_inm->GetValue(), bindless_cv);
112 return {tracked, track};
113 }
114 return {};
115 }
116 if (const auto gpr = std::get_if<GprNode>(&*tracked)) {
117 if (gpr->GetIndex() == Tegra::Shader::Register::ZeroIndex) {
118 return {};
119 }
120 // Reduce the cursor in one to avoid infinite loops when the instruction sets the same
121 // register that it uses as operand
122 const auto [source, new_cursor] = TrackRegister(gpr, code, cursor - 1);
123 if (!source) {
124 return {};
125 }
126 return TrackBindlessSampler(source, code, new_cursor);
127 }
128 if (const auto operation = std::get_if<OperationNode>(&*tracked)) {
129 for (std::size_t i = operation->GetOperandsCount(); i > 0; --i) {
130 if (auto found = TrackBindlessSampler((*operation)[i - 1], code, cursor);
131 std::get<0>(found)) {
132 // Cbuf found in operand.
133 return found;
134 }
135 }
136 return {};
137 }
138 if (const auto conditional = std::get_if<ConditionalNode>(&*tracked)) {
139 const auto& conditional_code = conditional->GetCode();
140 return TrackBindlessSampler(tracked, conditional_code,
141 static_cast<s64>(conditional_code.size()));
142 }
143 return {};
144}
145
40std::tuple<Node, u32, u32> ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code, 146std::tuple<Node, u32, u32> ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code,
41 s64 cursor) const { 147 s64 cursor) const {
42 if (const auto cbuf = std::get_if<CbufNode>(&*tracked)) { 148 if (const auto cbuf = std::get_if<CbufNode>(&*tracked)) {