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.cpp236
1 files changed, 0 insertions, 236 deletions
diff --git a/src/video_core/shader/track.cpp b/src/video_core/shader/track.cpp
deleted file mode 100644
index 6be3ea92b..000000000
--- a/src/video_core/shader/track.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <utility>
7#include <variant>
8
9#include "common/common_types.h"
10#include "video_core/shader/node.h"
11#include "video_core/shader/node_helper.h"
12#include "video_core/shader/shader_ir.h"
13
14namespace VideoCommon::Shader {
15
16namespace {
17
18std::pair<Node, s64> FindOperation(const NodeBlock& code, s64 cursor,
19 OperationCode operation_code) {
20 for (; cursor >= 0; --cursor) {
21 Node node = code.at(cursor);
22
23 if (const auto operation = std::get_if<OperationNode>(&*node)) {
24 if (operation->GetCode() == operation_code) {
25 return {std::move(node), cursor};
26 }
27 }
28
29 if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
30 const auto& conditional_code = conditional->GetCode();
31 auto result = FindOperation(
32 conditional_code, static_cast<s64>(conditional_code.size() - 1), operation_code);
33 auto& found = result.first;
34 if (found) {
35 return {std::move(found), cursor};
36 }
37 }
38 }
39 return {};
40}
41
42std::optional<std::pair<Node, Node>> DecoupleIndirectRead(const OperationNode& operation) {
43 if (operation.GetCode() != OperationCode::UAdd) {
44 return std::nullopt;
45 }
46 Node gpr;
47 Node offset;
48 ASSERT(operation.GetOperandsCount() == 2);
49 for (std::size_t i = 0; i < operation.GetOperandsCount(); i++) {
50 Node operand = operation[i];
51 if (std::holds_alternative<ImmediateNode>(*operand)) {
52 offset = operation[i];
53 } else if (std::holds_alternative<GprNode>(*operand)) {
54 gpr = operation[i];
55 }
56 }
57 if (offset && gpr) {
58 return std::make_pair(gpr, offset);
59 }
60 return std::nullopt;
61}
62
63bool AmendNodeCv(std::size_t amend_index, Node node) {
64 if (const auto operation = std::get_if<OperationNode>(&*node)) {
65 operation->SetAmendIndex(amend_index);
66 return true;
67 }
68 if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
69 conditional->SetAmendIndex(amend_index);
70 return true;
71 }
72 return false;
73}
74
75} // Anonymous namespace
76
77std::pair<Node, TrackSampler> ShaderIR::TrackBindlessSampler(Node tracked, const NodeBlock& code,
78 s64 cursor) {
79 if (const auto cbuf = std::get_if<CbufNode>(&*tracked)) {
80 const u32 cbuf_index = cbuf->GetIndex();
81
82 // Constant buffer found, test if it's an immediate
83 const auto& offset = cbuf->GetOffset();
84 if (const auto immediate = std::get_if<ImmediateNode>(&*offset)) {
85 auto track = MakeTrackSampler<BindlessSamplerNode>(cbuf_index, immediate->GetValue());
86 return {tracked, track};
87 }
88 if (const auto operation = std::get_if<OperationNode>(&*offset)) {
89 const u32 bound_buffer = registry.GetBoundBuffer();
90 if (bound_buffer != cbuf_index) {
91 return {};
92 }
93 if (const std::optional pair = DecoupleIndirectRead(*operation)) {
94 auto [gpr, base_offset] = *pair;
95 return HandleBindlessIndirectRead(*cbuf, *operation, gpr, base_offset, tracked,
96 code, cursor);
97 }
98 }
99 return {};
100 }
101 if (const auto gpr = std::get_if<GprNode>(&*tracked)) {
102 if (gpr->GetIndex() == Tegra::Shader::Register::ZeroIndex) {
103 return {};
104 }
105 // Reduce the cursor in one to avoid infinite loops when the instruction sets the same
106 // register that it uses as operand
107 const auto [source, new_cursor] = TrackRegister(gpr, code, cursor - 1);
108 if (!source) {
109 return {};
110 }
111 return TrackBindlessSampler(source, code, new_cursor);
112 }
113 if (const auto operation = std::get_if<OperationNode>(&*tracked)) {
114 const OperationNode& op = *operation;
115
116 const OperationCode opcode = operation->GetCode();
117 if (opcode == OperationCode::IBitwiseOr || opcode == OperationCode::UBitwiseOr) {
118 ASSERT(op.GetOperandsCount() == 2);
119 auto [node_a, index_a, offset_a] = TrackCbuf(op[0], code, cursor);
120 auto [node_b, index_b, offset_b] = TrackCbuf(op[1], code, cursor);
121 if (node_a && node_b) {
122 auto track = MakeTrackSampler<SeparateSamplerNode>(std::pair{index_a, index_b},
123 std::pair{offset_a, offset_b});
124 return {tracked, std::move(track)};
125 }
126 }
127 std::size_t i = op.GetOperandsCount();
128 while (i--) {
129 if (auto found = TrackBindlessSampler(op[i - 1], code, cursor); std::get<0>(found)) {
130 // Constant buffer found in operand.
131 return found;
132 }
133 }
134 return {};
135 }
136 if (const auto conditional = std::get_if<ConditionalNode>(&*tracked)) {
137 const auto& conditional_code = conditional->GetCode();
138 return TrackBindlessSampler(tracked, conditional_code,
139 static_cast<s64>(conditional_code.size()));
140 }
141 return {};
142}
143
144std::pair<Node, TrackSampler> ShaderIR::HandleBindlessIndirectRead(
145 const CbufNode& cbuf, const OperationNode& operation, Node gpr, Node base_offset, Node tracked,
146 const NodeBlock& code, s64 cursor) {
147 const auto offset_imm = std::get<ImmediateNode>(*base_offset);
148 const auto& gpu_driver = registry.AccessGuestDriverProfile();
149 const u32 bindless_cv = NewCustomVariable();
150 const u32 texture_handler_size = gpu_driver.GetTextureHandlerSize();
151 Node op = Operation(OperationCode::UDiv, gpr, Immediate(texture_handler_size));
152
153 Node cv_node = GetCustomVariable(bindless_cv);
154 Node amend_op = Operation(OperationCode::Assign, std::move(cv_node), std::move(op));
155 const std::size_t amend_index = DeclareAmend(std::move(amend_op));
156 AmendNodeCv(amend_index, code[cursor]);
157
158 // TODO: Implement bindless index custom variable
159 auto track =
160 MakeTrackSampler<ArraySamplerNode>(cbuf.GetIndex(), offset_imm.GetValue(), bindless_cv);
161 return {tracked, track};
162}
163
164std::tuple<Node, u32, u32> ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code,
165 s64 cursor) const {
166 if (const auto cbuf = std::get_if<CbufNode>(&*tracked)) {
167 // Constant buffer found, test if it's an immediate
168 const auto& offset = cbuf->GetOffset();
169 if (const auto immediate = std::get_if<ImmediateNode>(&*offset)) {
170 return {tracked, cbuf->GetIndex(), immediate->GetValue()};
171 }
172 return {};
173 }
174 if (const auto gpr = std::get_if<GprNode>(&*tracked)) {
175 if (gpr->GetIndex() == Tegra::Shader::Register::ZeroIndex) {
176 return {};
177 }
178 // Reduce the cursor in one to avoid infinite loops when the instruction sets the same
179 // register that it uses as operand
180 const auto [source, new_cursor] = TrackRegister(gpr, code, cursor - 1);
181 if (!source) {
182 return {};
183 }
184 return TrackCbuf(source, code, new_cursor);
185 }
186 if (const auto operation = std::get_if<OperationNode>(&*tracked)) {
187 for (std::size_t i = operation->GetOperandsCount(); i > 0; --i) {
188 if (auto found = TrackCbuf((*operation)[i - 1], code, cursor); std::get<0>(found)) {
189 // Cbuf found in operand.
190 return found;
191 }
192 }
193 return {};
194 }
195 if (const auto conditional = std::get_if<ConditionalNode>(&*tracked)) {
196 const auto& conditional_code = conditional->GetCode();
197 return TrackCbuf(tracked, conditional_code, static_cast<s64>(conditional_code.size()));
198 }
199 return {};
200}
201
202std::optional<u32> ShaderIR::TrackImmediate(Node tracked, const NodeBlock& code, s64 cursor) const {
203 // Reduce the cursor in one to avoid infinite loops when the instruction sets the same register
204 // that it uses as operand
205 const auto result = TrackRegister(&std::get<GprNode>(*tracked), code, cursor - 1);
206 const auto& found = result.first;
207 if (!found) {
208 return std::nullopt;
209 }
210 if (const auto immediate = std::get_if<ImmediateNode>(&*found)) {
211 return immediate->GetValue();
212 }
213 return std::nullopt;
214}
215
216std::pair<Node, s64> ShaderIR::TrackRegister(const GprNode* tracked, const NodeBlock& code,
217 s64 cursor) const {
218 for (; cursor >= 0; --cursor) {
219 const auto [found_node, new_cursor] = FindOperation(code, cursor, OperationCode::Assign);
220 if (!found_node) {
221 return {};
222 }
223 const auto operation = std::get_if<OperationNode>(&*found_node);
224 ASSERT(operation);
225
226 const auto& target = (*operation)[0];
227 if (const auto gpr_target = std::get_if<GprNode>(&*target)) {
228 if (gpr_target->GetIndex() == tracked->GetIndex()) {
229 return {(*operation)[1], new_cursor};
230 }
231 }
232 }
233 return {};
234}
235
236} // namespace VideoCommon::Shader