1#include "common/aglResShaderArchive.h"
2#include <prim/seadEndian.h>
3#include "common/aglResBinaryShaderArchive.h"
4#include "common/aglResShaderBinary.h"
5#include "common/aglResShaderSymbol.h"
6#include "common/aglResShaderVariation.h"
7#include "common/aglShader.h"
8
9#ifdef cafe
10#include <cafe/gx2.h>
11#endif // cafe
12
13static inline void swap32(void* ptr, size_t size) {
14 u32* ptr_u32 = static_cast<u32*>(ptr);
15 u32 count = size / sizeof(u32);
16
17 for (u32 i = 0; i < count; i++) {
18 *ptr_u32 = sead::Endian::swapU32(v: *ptr_u32);
19 ptr_u32++;
20 }
21}
22
23namespace {
24
25void modifyEndianResSymbolArray(bool is_le, agl::ResShaderSymbolArray symbol_array,
26 agl::ShaderSymbolType type) {
27 symbol_array.modifyEndianArray(is_le);
28
29 if (type != agl::cShaderSymbolType_UniformBlock)
30 for (agl::ResShaderSymbolArray::iterator it = symbol_array.begin(),
31 it_end = symbol_array.end();
32 it != it_end; ++it)
33 agl::ModifyEndianU32(is_le, p_data: agl::ResShaderSymbol(&(*it)).getDefaultValue(),
34 size: it->mDefaultValueSize);
35}
36
37#ifdef cafe
38
39template <typename T>
40T* modifyBinaryAndNamePtr(void* base_ptr, T* ptr, s32 num) {
41 if (!ptr)
42 return nullptr;
43
44 ptr = (T*)(uintptr_t(base_ptr) + uintptr_t(ptr));
45
46 for (s32 i = 0; i < num; i++)
47 ptr[i].name += uintptr_t(base_ptr);
48
49 return ptr;
50}
51
52void* modifyBinaryPtr(void* base_ptr, void* ptr) {
53 return (void*)(uintptr_t(base_ptr) + uintptr_t(ptr));
54}
55
56#endif // cafe
57
58} // namespace
59
60namespace agl {
61
62void ResShaderBinary::modifyBinaryEndian() {
63 size_t size = 0;
64 void* data = nullptr;
65
66#ifdef cafe
67 switch (getShaderType()) {
68 case cShaderType_Vertex: {
69 GX2VertexShader* vertex_shader = static_cast<GX2VertexShader*>(getData());
70 swap32(vertex_shader, sizeof(GX2VertexShader));
71
72 size += vertex_shader->numUniformBlocks * sizeof(GX2UniformBlock) +
73 vertex_shader->numUniforms * sizeof(GX2UniformVar) +
74 vertex_shader->numInitialValues * sizeof(GX2UniformInitialValue) +
75 vertex_shader->numSamplers * sizeof(GX2SamplerVar) +
76 vertex_shader->numAttribs * sizeof(GX2AttribVar);
77
78 data = vertex_shader + 1;
79 } break;
80 case cShaderType_Fragment: {
81 GX2PixelShader* pixel_shader = static_cast<GX2PixelShader*>(getData());
82 swap32(pixel_shader, sizeof(GX2PixelShader));
83
84 size += pixel_shader->numUniformBlocks * sizeof(GX2UniformBlock) +
85 pixel_shader->numUniforms * sizeof(GX2UniformVar) +
86 pixel_shader->numInitialValues * sizeof(GX2UniformInitialValue) +
87 pixel_shader->numSamplers * sizeof(GX2SamplerVar);
88
89 data = pixel_shader + 1;
90 } break;
91 case cShaderType_Geometry: {
92 GX2GeometryShader* geometry_shader = static_cast<GX2GeometryShader*>(getData());
93 swap32(geometry_shader, sizeof(GX2GeometryShader));
94
95 size += geometry_shader->numUniformBlocks * sizeof(GX2UniformBlock) +
96 geometry_shader->numUniforms * sizeof(GX2UniformVar) +
97 geometry_shader->numInitialValues * sizeof(GX2UniformInitialValue) +
98 geometry_shader->numSamplers * sizeof(GX2SamplerVar);
99
100 data = geometry_shader + 1;
101 } break;
102 }
103#endif // cafe
104
105 swap32(ptr: data, size);
106}
107
108// unknown state, does not exist in SMO
109void ResShaderBinary::setUp() {
110#ifdef cafe
111 switch (getShaderType()) {
112 case cShaderType_Vertex: {
113 GX2VertexShader* vertex_shader = static_cast<GX2VertexShader*>(getData());
114
115 vertex_shader->uniformBlocks = modifyBinaryAndNamePtr<GX2UniformBlock>(
116 vertex_shader, vertex_shader->uniformBlocks, vertex_shader->numUniformBlocks);
117 vertex_shader->uniformVars = modifyBinaryAndNamePtr<GX2UniformVar>(
118 vertex_shader, vertex_shader->uniformVars, vertex_shader->numUniforms);
119 vertex_shader->samplerVars = modifyBinaryAndNamePtr<GX2SamplerVar>(
120 vertex_shader, vertex_shader->samplerVars, vertex_shader->numSamplers);
121 vertex_shader->attribVars = modifyBinaryAndNamePtr<GX2AttribVar>(
122 vertex_shader, vertex_shader->attribVars, vertex_shader->numAttribs);
123
124 vertex_shader->_loopVars = modifyBinaryPtr(vertex_shader, vertex_shader->_loopVars);
125 vertex_shader->shaderPtr = modifyBinaryPtr(vertex_shader, vertex_shader->shaderPtr);
126 } break;
127 case cShaderType_Fragment: {
128 GX2PixelShader* pixel_shader = static_cast<GX2PixelShader*>(getData());
129
130 pixel_shader->uniformBlocks = modifyBinaryAndNamePtr<GX2UniformBlock>(
131 pixel_shader, pixel_shader->uniformBlocks, pixel_shader->numUniformBlocks);
132 pixel_shader->uniformVars = modifyBinaryAndNamePtr<GX2UniformVar>(
133 pixel_shader, pixel_shader->uniformVars, pixel_shader->numUniforms);
134 pixel_shader->samplerVars = modifyBinaryAndNamePtr<GX2SamplerVar>(
135 pixel_shader, pixel_shader->samplerVars, pixel_shader->numSamplers);
136
137 pixel_shader->_loopVars = modifyBinaryPtr(pixel_shader, pixel_shader->_loopVars);
138 pixel_shader->shaderPtr = modifyBinaryPtr(pixel_shader, pixel_shader->shaderPtr);
139 } break;
140 case cShaderType_Geometry: {
141 GX2GeometryShader* geometry_shader = static_cast<GX2GeometryShader*>(getData());
142
143 geometry_shader->uniformBlocks = modifyBinaryAndNamePtr<GX2UniformBlock>(
144 geometry_shader, geometry_shader->uniformBlocks, geometry_shader->numUniformBlocks);
145 geometry_shader->uniformVars = modifyBinaryAndNamePtr<GX2UniformVar>(
146 geometry_shader, geometry_shader->uniformVars, geometry_shader->numUniforms);
147 geometry_shader->samplerVars = modifyBinaryAndNamePtr<GX2SamplerVar>(
148 geometry_shader, geometry_shader->samplerVars, geometry_shader->numSamplers);
149
150 geometry_shader->_loopVars = modifyBinaryPtr(geometry_shader, geometry_shader->_loopVars);
151 geometry_shader->shaderPtr = modifyBinaryPtr(geometry_shader, geometry_shader->shaderPtr);
152 geometry_shader->copyShaderPtr =
153 modifyBinaryPtr(geometry_shader, geometry_shader->copyShaderPtr);
154 } break;
155 }
156#endif // cafe
157}
158
159const char* ResShaderVariation::getID() const {
160 const char* value = getName() + ref().mNameLen;
161
162 for (s32 i = 0, index = static_cast<s32>(ref().mValueNum);; i++) {
163 while (*value == '\0')
164 value++;
165
166 if (i == index)
167 break;
168
169 while (*value != '\0')
170 value++;
171 }
172
173 return value;
174}
175
176const char* ResShaderVariation::getValue(s32 index) const {
177 // clang-format off
178 SEAD_ASSERT(0 <= index && index < static_cast< int >( ref().mValueNum ));
179 // clang-format on
180
181 const char* value = getName() + ref().mNameLen;
182
183 for (s32 i = 0;; i++) {
184 while (*value == '\0')
185 value++;
186
187 if (i == index)
188 break;
189
190 while (*value != '\0')
191 value++;
192 }
193
194 return value;
195}
196
197// unknown state, does not exist in SMO
198ResShaderSymbol ResShaderSymbolArray::searchResShaderSymbolByID(const sead::SafeString& id) const {
199 for (constIterator it = begin(), it_end = end(); it != it_end; ++it) {
200 if (id.isEqual(str: ResShaderSymbol(&(*it)).getID()))
201 return &(*it);
202 }
203
204 return nullptr;
205}
206
207// NON_MATCHING: weird optimizations with bit magic to tell whether more than one loop iteration has
208// to be done
209ResShaderMacroArray ResShaderProgram::getResShaderMacroArray(ShaderType type) const {
210 const ResShaderMacroArrayData* macro_array;
211 {
212 const DataType* const data = ptr();
213 macro_array = (const ResShaderMacroArrayData*)((uintptr_t)(data + 1) + data->mNameLen);
214 }
215
216 for (s32 i = 0; i < type; i++)
217 macro_array = (const ResShaderMacroArrayData*)((uintptr_t)macro_array + macro_array->mSize);
218
219 return macro_array;
220}
221
222// NON_MATCHING: operand order in ADD
223ResShaderVariationArray ResShaderProgram::getResShaderVariationArray() const {
224 const ResShaderMacroArrayData* macro_array;
225 {
226 const DataType* const data = ptr();
227 macro_array = (const ResShaderMacroArrayData*)((uintptr_t)(data + 1) + data->mNameLen);
228 }
229
230 for (s32 i = 0; i < cShaderType_Num; i++)
231 macro_array = (const ResShaderMacroArrayData*)((uintptr_t)macro_array + macro_array->mSize);
232
233 return (const ResShaderVariationArrayData*)macro_array;
234}
235
236// unknown state, does not exist in SMO
237ResShaderSymbolArray ResShaderProgram::getResShaderSymbolArray(ShaderSymbolType type) const {
238 const ResShaderSymbolArrayData* symbol_array;
239 {
240 const ResShaderVariationArrayData* const data = getResShaderVariationDefaultArray().ptr();
241 symbol_array = (const ResShaderSymbolArrayData*)((uintptr_t)data + data->mSize);
242 }
243
244 for (s32 i = 0; i < type; i++)
245 symbol_array =
246 (const ResShaderSymbolArrayData*)((uintptr_t)symbol_array + symbol_array->mSize);
247
248 return symbol_array;
249}
250
251// unknown state, does not exist in SMO
252ResShaderSymbolArray ResBinaryShaderProgram::getResShaderSymbolArray(ShaderSymbolType type) const {
253 const ResShaderSymbolArrayData* symbol_array;
254 {
255 const ResShaderVariationArrayData* const data = getResShaderVariationDefaultArray().ptr();
256 symbol_array = (const ResShaderSymbolArrayData*)((uintptr_t)data + data->mSize);
257 }
258
259 for (s32 i = 0; i < type; i++)
260 symbol_array =
261 (const ResShaderSymbolArrayData*)((uintptr_t)symbol_array + symbol_array->mSize);
262
263 return symbol_array;
264}
265
266// NON_MATCHING: heavily depends on the two (mismatching) functions above, probably a lot of
267// mismatches carried over
268bool ResShaderArchive::setUp() {
269#ifdef cafe
270 SEAD_ASSERT(isValid());
271#endif
272
273 if (!isEndianResolved()) {
274#ifdef cafe
275 ModifyEndianU32(modifyEndian(), ptr(), sizeof(DataType));
276
277 verify();
278#endif
279#ifdef SWITCH
280 ModifyEndianU32(is_le: false, p_data: ptr(), size: sizeof(DataType));
281#endif
282
283 ResShaderProgramArray prog_arr = getResShaderProgramArray();
284 prog_arr.modifyEndianArray(is_le: modifyEndian());
285
286 ResShaderSourceArray source_arr = getResShaderSourceArray();
287 source_arr.modifyEndianArray(is_le: modifyEndian());
288
289 for (ResShaderProgramArray::iterator it = prog_arr.begin(), it_end = prog_arr.end();
290 it != it_end; ++it) {
291 ResShaderProgram prog(&(*it));
292
293 for (s32 type = 0; type < cShaderType_Num; type++)
294 prog.getResShaderMacroArray(type: ShaderType(type)).modifyEndianArray(is_le: modifyEndian());
295
296 prog.getResShaderVariationArray().modifyEndianArray(is_le: modifyEndian());
297 prog.getResShaderVariationDefaultArray().modifyEndianArray(is_le: modifyEndian());
298
299 for (s32 type = 0; type < cShaderSymbolType_Num; type++)
300 modifyEndianResSymbolArray(is_le: modifyEndian(),
301 symbol_array: prog.getResShaderSymbolArray(type: ShaderSymbolType(type)),
302 type: ShaderSymbolType(type));
303 }
304
305 setEndianResolved();
306 }
307#ifdef cafe
308 else {
309 verify();
310 }
311#endif
312
313 return true;
314}
315
316// NON_MATCHING: also heavily depends on the two (mismatching) functions above, probably a lot of
317// mismatches carried over
318bool ResBinaryShaderArchive::setUp(bool le_resolve_pointers) {
319 SEAD_ASSERT(isValid());
320
321 bool endian_resolved = isEndianResolved();
322
323 if (!endian_resolved)
324 ModifyEndianU32(is_le: modifyEndian(), p_data: ptr(), size: sizeof(DataType));
325
326 verify();
327
328 if (endian_resolved) {
329 if (ref().mResolved == 0) {
330 for (ResShaderBinaryArray::iterator it = getResShaderBinaryArray().begin(),
331 it_end = getResShaderBinaryArray().end();
332 it != it_end; ++it)
333 ResShaderBinary(&(*it)).setUp();
334
335 ref().mResolved = 1;
336 }
337 } else {
338 ResShaderBinaryArray binary_arr = getResShaderBinaryArray();
339 binary_arr.modifyEndianArray(is_le: modifyEndian());
340
341 ResBinaryShaderProgramArray binary_prog_arr = getResBinaryShaderProgramArray();
342 binary_prog_arr.modifyEndianArray(is_le: modifyEndian());
343
344 for (ResBinaryShaderProgramArray::iterator it = binary_prog_arr.begin(),
345 it_end = binary_prog_arr.end();
346 it != it_end; ++it) {
347 ResBinaryShaderProgram binary_prog(&(*it));
348
349 binary_prog.getResShaderVariationArray().modifyEndianArray(is_le: modifyEndian());
350 binary_prog.getResShaderVariationDefaultArray().modifyEndianArray(is_le: modifyEndian());
351
352 for (s32 type = 0; type < cShaderSymbolType_Num; type++)
353 modifyEndianResSymbolArray(
354 is_le: modifyEndian(), symbol_array: binary_prog.getResShaderSymbolArray(type: ShaderSymbolType(type)),
355 type: ShaderSymbolType(type));
356 }
357
358 for (ResShaderBinaryArray::iterator it = binary_arr.begin(), it_end = binary_arr.end();
359 it != it_end; ++it) {
360 ResShaderBinary binary(&(*it));
361 binary.modifyBinaryEndian();
362
363 if (le_resolve_pointers && ref().mResolved == 0)
364 binary.setUp();
365 }
366
367 if (le_resolve_pointers)
368 ref().mResolved = 1;
369
370 setEndianResolved();
371 }
372
373 return true;
374}
375
376const char* ResShaderArchiveData::getExtension() {
377 return "sharc";
378}
379
380const char* ResBinaryShaderArchiveData::getExtension() {
381 return "sharcfb";
382}
383
384} // namespace agl
385