diff --git a/rpcs3/Emu/RSX/Program/CgBinaryProgram.h b/rpcs3/Emu/RSX/Program/CgBinaryProgram.h index 880389477..3095964cb 100644 --- a/rpcs3/Emu/RSX/Program/CgBinaryProgram.h +++ b/rpcs3/Emu/RSX/Program/CgBinaryProgram.h @@ -6,21 +6,23 @@ #include "Emu/RSX/Program/ProgramStateCache.h" #include "Emu/RSX/Program/ShaderParam.h" #include "util/File.h" +#include +#include #ifndef WITHOUT_OPENGL #include "Emu/RSX/GL/GLVertexProgram.h" #include "Emu/RSX/GL/GLFragmentProgram.h" #endif -using CGprofile = u32; -using CGbool = s32; -using CGresource = u32; -using CGenum = u32; -using CGtype = u32; -using CGbitfield = u32; -using CGbitfield16 = u16; -using CGint = s32; -using CGuint = u32; +using CGprofile = be_t; +using CGbool = be_t; +using CGresource = be_t; +using CGenum = be_t; +using CGtype = be_t; +using CGbitfield = be_t; +using CGbitfield16 = be_t; +using CGint = be_t; +using CGuint = be_t; using CgBinaryOffset = CGuint; using CgBinarySize = CgBinaryOffset; @@ -29,12 +31,6 @@ using CgBinaryFloatOffset = CgBinaryOffset; using CgBinaryStringOffset = CgBinaryOffset; using CgBinaryParameterOffset = CgBinaryOffset; -using CgBinaryParameter = struct CgBinaryParameter; -using CgBinaryEmbeddedConstant = struct CgBinaryEmbeddedConstant; -using CgBinaryVertexProgram = struct CgBinaryVertexProgram; -using CgBinaryFragmentProgram = struct CgBinaryFragmentProgram; -using CgBinaryProgram = struct CgBinaryProgram; - // fragment programs have their constants embedded in the microcode struct CgBinaryEmbeddedConstant { @@ -70,12 +66,12 @@ struct CgBinaryVertexProgram CGbitfield userClipMask; // user clip plane enables (for SET_USER_CLIP_PLANE_CONTROL) }; -typedef enum +enum CgBinaryPartialTexType { CgBinaryPTTNone = 0, CgBinaryPTT2x16 = 1, CgBinaryPTT1x32 = 2 -} CgBinaryPartialTexType; +}; // attributes needed for pshaders struct CgBinaryFragmentProgram @@ -118,6 +114,55 @@ struct CgBinaryProgram u8 data[1]; }; +inline std::size_t validateCgBinaryProgram(std::span data) +{ + if (data.size() <= sizeof(CgBinaryProgram)) + { + return 0; + } + + CgBinaryProgram header; + std::memcpy(&header, data.data(), sizeof(header)); + + if (header.profile != 7004 && header.profile != 7003) + { + return 0; + } + + auto totalSize = header.totalSize.value(); + if (sizeof(header) >= totalSize) + { + return 0; + } + + if (header.ucode + header.ucodeSize > totalSize) + { + return 0; + } + + if (header.program >= totalSize) + { + return 0; + } + + if (header.profile == 7004) + { + if (header.program + sizeof(CgBinaryFragmentProgram) > totalSize) + { + return 0; + } + } + else + { + if (header.program + sizeof(CgBinaryVertexProgram) > totalSize) + { + return 0; + } + } + + return totalSize; +} + class CgBinaryDisasm { OPDEST dst; @@ -131,8 +176,6 @@ class CgBinaryDisasm D3 d3; SRC src[3]; - std::string m_path; // used for FP decompiler thread, delete this later - u8* m_buffer = nullptr; usz m_buffer_size = 0; std::string m_arb_shader; @@ -197,7 +240,6 @@ public: void SetDSTScaDisasm(const std::string& code); CgBinaryDisasm(const std::string& path) - : m_path(path) { fs::file f(path); if (!f) @@ -269,71 +311,24 @@ public: } template - T& GetCgRef(const u32 offset) + T readData(const u32 offset) { - return reinterpret_cast(m_buffer[offset]); - } - - void ConvertToLE(CgBinaryProgram& prog) - { - // BE payload, requires that data be swapped - const auto be_profile = prog.profile; - - auto swap_be32 = [&](u32 start_offset, size_t size_bytes) - { - auto start = reinterpret_cast(m_buffer + start_offset); - auto end = reinterpret_cast(m_buffer + start_offset + size_bytes); - - for (auto data = start; data < end; ++data) - { - *data = std::bit_cast>(*data); - } - }; - - // 1. Swap the header - swap_be32(0, sizeof(CgBinaryProgram)); - - // 2. Swap parameters - swap_be32(prog.parameterArray, sizeof(CgBinaryParameter) * prog.parameterCount); - - // 3. Swap the ucode - swap_be32(prog.ucode, m_buffer_size - prog.ucode); - - // 4. Swap the domain header - if (be_profile == 7004u) - { - // Need to swap each field individually - auto& fprog = GetCgRef(prog.program); - fprog.instructionCount = std::bit_cast>(fprog.instructionCount); - fprog.attributeInputMask = std::bit_cast>(fprog.attributeInputMask); - fprog.partialTexType = std::bit_cast>(fprog.partialTexType); - fprog.texCoordsInputMask = std::bit_cast>(fprog.texCoordsInputMask); - fprog.texCoords2D = std::bit_cast>(fprog.texCoords2D); - fprog.texCoordsCentroid = std::bit_cast>(fprog.texCoordsCentroid); - } - else - { - // Swap entire header block as all fields are u32 - swap_be32(prog.program, sizeof(CgBinaryVertexProgram)); - } + T result; + std::memcpy(&result, m_buffer + offset, sizeof(result)); + return result; } void BuildShaderBody() { ParamArray param_array; - auto& prog = GetCgRef(0); + auto prog = readData(0); - if (const u32 be_profile = std::bit_cast>(prog.profile); - be_profile == 7003u || be_profile == 7004u) - { - ConvertToLE(prog); - ensure(be_profile == prog.profile); - } + ensure(prog.profile == 7003u || prog.profile == 7004u); if (prog.profile == 7004u) { - auto& fprog = GetCgRef(prog.program); + auto fprog = readData(prog.program); m_arb_shader += "\n"; fmt::append(m_arb_shader, "# binaryFormatRevision 0x%x\n", prog.binaryFormatRevision); fmt::append(m_arb_shader, "# profile sce_fp_rsx\n"); @@ -345,7 +340,7 @@ public: CgBinaryParameterOffset offset = prog.parameterArray; for (u32 i = 0; i < prog.parameterCount; i++) { - auto& fparam = GetCgRef(offset); + auto fparam = readData(offset); std::string param_type = GetCgParamType(fparam.type) + " "; std::string param_name = GetCgParamName(fparam.name) + " "; @@ -362,7 +357,6 @@ public: m_offset = prog.ucode; TaskFP(); - u32 unused; std::vector be_data; // Swap bytes. FP decompiler expects input in BE @@ -383,13 +377,14 @@ public: for (u32 i = 0; i < 16; ++i) prog.texture_state.set_dimension(rsx::texture_dimension_extended::texture_dimension_2d, i); #ifndef WITHOUT_OPENGL + u32 unused; GLFragmentDecompilerThread(m_glsl_shader, param_array, prog, unused).Task(); #endif } else { - const auto& vprog = GetCgRef(prog.program); + const auto vprog = readData(prog.program); m_arb_shader += "\n"; fmt::append(m_arb_shader, "# binaryFormatRevision 0x%x\n", prog.binaryFormatRevision); fmt::append(m_arb_shader, "# profile sce_vp_rsx\n"); @@ -402,10 +397,10 @@ public: CgBinaryParameterOffset offset = prog.parameterArray; for (u32 i = 0; i < prog.parameterCount; i++) { - auto& vparam = GetCgRef(offset); + auto vparam = readData(offset); std::string param_type = GetCgParamType(vparam.type) + " "; - std::string param_name = GetCgParamName(vparam.name) + " "; + std::string param_name = GetCgParamName(vparam.name.get()) + " "; std::string param_res = GetCgParamRes(vparam.res) + " "; std::string param_semantic = GetCgParamSemantic(vparam.semantic) + " "; std::string param_const = GetCgParamValue(vparam.embeddedConst, vparam.name); @@ -419,13 +414,16 @@ public: m_offset = prog.ucode; ensure((m_buffer_size - m_offset) % sizeof(u32) == 0); - u32* vdata = reinterpret_cast(&m_buffer[m_offset]); + auto vdata = reinterpret_cast*>(&m_buffer[m_offset]); m_data.resize(prog.ucodeSize / sizeof(u32)); - std::memcpy(m_data.data(), vdata, prog.ucodeSize); + for (std::size_t i = 0; i < m_data.size(); ++i) + { + m_data[i] = vdata[i]; + } TaskVP(); RSXVertexProgram prog; - program_hash_util::vertex_program_utils::analyse_vertex_program(vdata, 0, prog); + program_hash_util::vertex_program_utils::analyse_vertex_program(m_data.data(), 0, prog); for (u32 i = 0; i < 4; ++i) prog.texture_state.set_dimension(rsx::texture_dimension_extended::texture_dimension_2d, i); #ifndef WITHOUT_OPENGL