| 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 | |
| 13 | static 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 | |
| 23 | namespace { |
| 24 | |
| 25 | void 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 | |
| 39 | template <typename T> |
| 40 | T* 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 | |
| 52 | void* 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 | |
| 60 | namespace agl { |
| 61 | |
| 62 | void 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 |
| 109 | void 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 | |
| 159 | const 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 | |
| 176 | const 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 |
| 198 | ResShaderSymbol 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 |
| 209 | ResShaderMacroArray 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 |
| 223 | ResShaderVariationArray 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 |
| 237 | ResShaderSymbolArray 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 |
| 252 | ResShaderSymbolArray 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 |
| 268 | bool 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 |
| 318 | bool 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 | |
| 376 | const char* ResShaderArchiveData::getExtension() { |
| 377 | return "sharc" ; |
| 378 | } |
| 379 | |
| 380 | const char* ResBinaryShaderArchiveData::getExtension() { |
| 381 | return "sharcfb" ; |
| 382 | } |
| 383 | |
| 384 | } // namespace agl |
| 385 | |