forked from RPCS3/rpcs3
-
Notifications
You must be signed in to change notification settings - Fork 16
/
FragmentProgramDecompiler.h
305 lines (260 loc) · 7.83 KB
/
FragmentProgramDecompiler.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
#pragma once
#include "ShaderParam.h"
#include "RSXFragmentProgram.h"
#include <sstream>
// Helper for GPR occupancy tracking
struct temp_register
{
bool aliased_r0 = false;
bool aliased_h0 = false;
bool aliased_h1 = false;
bool last_write_half[4] = { false, false, false, false };
u32 real_index = -1;
u32 h0_writes = 0u; // Number of writes to the first 64-bits of the register
u32 h1_writes = 0u; // Number of writes to the last 64-bits of the register
void tag(u32 index, bool half_register, bool x, bool y, bool z, bool w)
{
if (half_register)
{
if (index & 1)
{
if (x) last_write_half[2] = true;
if (y) last_write_half[2] = true;
if (z) last_write_half[3] = true;
if (w) last_write_half[3] = true;
aliased_h1 = true;
h1_writes++;
}
else
{
if (x) last_write_half[0] = true;
if (y) last_write_half[0] = true;
if (z) last_write_half[1] = true;
if (w) last_write_half[1] = true;
aliased_h0 = true;
h0_writes++;
}
}
else
{
if (x) last_write_half[0] = false;
if (y) last_write_half[1] = false;
if (z) last_write_half[2] = false;
if (w) last_write_half[3] = false;
aliased_r0 = true;
h0_writes++;
h1_writes++;
}
if (real_index == umax)
{
if (half_register)
real_index = index >> 1;
else
real_index = index;
}
}
bool requires_gather(u8 channel) const
{
//Data fetched from the single precision register requires merging of the two half registers
ensure(channel < 4);
if (aliased_h0 && channel < 2)
{
return last_write_half[channel];
}
if (aliased_h1 && channel > 1)
{
return last_write_half[channel];
}
return false;
}
bool requires_split(u32 /*index*/) const
{
//Data fetched from any of the two half registers requires sync with the full register
if (!(last_write_half[0] || last_write_half[1]) && aliased_r0)
{
//r0 has been written to
//TODO: Check for specific elements in real32 register
return true;
}
return false;
}
std::string gather_r() const
{
std::string h0 = "h" + std::to_string(real_index << 1);
std::string h1 = "h" + std::to_string(real_index << 1 | 1);
std::string reg = "r" + std::to_string(real_index);
std::string ret = "//Invalid gather";
if (aliased_h0 && aliased_h1)
ret = "(gather(" + h0 + ", " + h1 + "))";
else if (aliased_h0)
ret = "(gather(" + h0 + "), " + reg + ".zw)";
else if (aliased_h1)
ret = "(" + reg + ".xy, gather(" + h1 + "))";
return ret;
}
};
/**
* This class is used to translate RSX Fragment program to GLSL/HLSL code
* Backend with text based shader can subclass this class and implement :
* - virtual std::string getFloatTypeName(usz elementCount) = 0;
* - virtual std::string getHalfTypeName(usz elementCount) = 0;
* - virtual std::string getFunction(enum class FUNCTION) = 0;
* - virtual std::string saturate(const std::string &code) = 0;
* - virtual std::string compareFunction(enum class COMPARE, const std::string &, const std::string &) = 0;
* - virtual void insertHeader(std::stringstream &OS) = 0;
* - virtual void insertInputs(std::stringstream &OS) = 0;
* - virtual void insertOutputs(std::stringstream &OS) = 0;
* - virtual void insertConstants(std::stringstream &OS) = 0;
* - virtual void insertMainStart(std::stringstream &OS) = 0;
* - virtual void insertMainEnd(std::stringstream &OS) = 0;
*/
class FragmentProgramDecompiler
{
enum OPFLAGS
{
no_src_mask = 1,
src_cast_f32 = 2,
skip_type_cast = 4,
texture_ref = 8,
op_extern = src_cast_f32 | skip_type_cast,
};
OPDEST dst;
SRC0 src0;
SRC1 src1;
SRC2 src2;
u32 opflags;
std::string main;
u32& m_size;
u32 m_const_index = 0;
u32 m_offset;
u32 m_location = 0;
u32 m_loop_count;
int m_code_level;
std::vector<u32> m_end_offsets;
std::vector<u32> m_else_offsets;
std::array<temp_register, 64> temp_registers;
std::string GetMask() const;
void SetDst(std::string code, u32 flags = 0);
void AddCode(const std::string& code);
std::string AddReg(u32 index, bool fp16);
bool HasReg(u32 index, bool fp16);
std::string AddCond();
std::string AddConst();
std::string AddTex();
void AddFlowOp(const std::string& code);
std::string Format(const std::string& code, bool ignore_redirects = false);
//Technically a temporary workaround until we know what type3 is
std::string AddType3();
//Support the transform-2d temp result for use with TEXBEM
std::string AddX2d();
//Prevents operations from overflowing the desired range (tested with fp_dynamic3 autotest sample, DS2 for src1.input_prec_mod)
std::string ClampValue(const std::string& code, u32 precision);
/**
* Returns true if the dst set is not a vector (i.e only a single component)
*/
bool DstExpectsSca() const;
void AddCodeCond(const std::string& lhs, const std::string& rhs);
std::string GetRawCond();
std::string GetCond();
template<typename T> std::string GetSRC(T src);
std::string BuildCode();
static u32 GetData(const u32 d) { return d << 16 | d >> 16; }
/**
* Emits code if opcode is an SCT/SCB one and returns true,
* otherwise do nothing and return false.
* NOTE: What does SCT means ???
*/
bool handle_sct_scb(u32 opcode);
/**
* Emits code if opcode is an TEX SRB one and returns true,
* otherwise do nothing and return false.
* NOTE: What does TEX SRB means ???
*/
bool handle_tex_srb(u32 opcode);
protected:
const RSXFragmentProgram &m_prog;
u32 m_ctrl = 0;
/** returns the type name of float vectors.
*/
virtual std::string getFloatTypeName(usz elementCount) = 0;
/** returns the type name of half vectors.
*/
virtual std::string getHalfTypeName(usz elementCount) = 0;
/** returns string calling function where arguments are passed via
* $0 $1 $2 substring.
*/
virtual std::string getFunction(FUNCTION) = 0;
/** returns string calling comparison function on 2 args passed as strings.
*/
virtual std::string compareFunction(COMPARE, const std::string &, const std::string &) = 0;
/** Insert header of shader file (eg #version, "system constants"...)
*/
virtual void insertHeader(std::stringstream &OS) = 0;
/** Insert global declaration of fragments inputs.
*/
virtual void insertInputs(std::stringstream &OS) = 0;
/** insert global declaration of fragments outputs.
*/
virtual void insertOutputs(std::stringstream &OS) = 0;
/** insert declaration of shader constants.
*/
virtual void insertConstants(std::stringstream &OS) = 0;
/** insert helper function definitions.
*/
virtual void insertGlobalFunctions(std::stringstream &OS) = 0;
/** insert beginning of main (signature, temporary declaration...)
*/
virtual void insertMainStart(std::stringstream &OS) = 0;
/** insert end of main function (return value, output copy...)
*/
virtual void insertMainEnd(std::stringstream &OS) = 0;
public:
enum : u16
{
in_wpos = (1 << 0),
in_diff_color = (1 << 1),
in_spec_color = (1 << 2),
in_fogc = (1 << 3),
in_tc0 = (1 << 4),
in_tc1 = (1 << 5),
in_tc2 = (1 << 6),
in_tc3 = (1 << 7),
in_tc4 = (1 << 8),
in_tc5 = (1 << 9),
in_tc6 = (1 << 10),
in_tc7 = (1 << 11),
in_tc8 = (1 << 12),
in_tc9 = (1 << 13),
in_ssa = (1 << 14)
};
struct
{
u16 in_register_mask = 0;
u16 common_access_sampler_mask = 0;
u16 shadow_sampler_mask = 0;
u16 redirected_sampler_mask = 0;
bool has_lit_op = false;
bool has_gather_op = false;
bool has_no_output = false;
bool has_discard_op = false;
bool has_tex_op = false;
bool has_divsq = false;
bool has_clamp = false;
bool has_w_access = false;
bool has_exp_tex_op = false;
bool has_pkg = false;
bool has_upg = false;
}
properties;
struct
{
bool has_native_half_support = false;
bool emulate_depth_compare = false;
}
device_props;
ParamArray m_parr;
FragmentProgramDecompiler(const RSXFragmentProgram &prog, u32& size);
FragmentProgramDecompiler(const FragmentProgramDecompiler&) = delete;
FragmentProgramDecompiler(FragmentProgramDecompiler&&) = delete;
std::string Decompile();
};