From aa0dad79d33f1704bcfd3cdd93e3f3f6e0d95312 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Wed, 21 May 2025 11:56:22 +0300 Subject: [PATCH] rsx: Refactor CgBinaryProgram to avoid namespace collision with X11 --- rpcs3/Emu/CMakeLists.txt | 1 + rpcs3/Emu/RSX/Program/CgBinaryProgram.cpp | 246 ++++++++++++++++++++++ rpcs3/Emu/RSX/Program/CgBinaryProgram.h | 244 +-------------------- rpcs3/emucore.vcxproj | 1 + rpcs3/emucore.vcxproj.filters | 3 + rpcs3/rpcs3qt/rsx_debugger.cpp | 6 +- 6 files changed, 262 insertions(+), 239 deletions(-) create mode 100644 rpcs3/Emu/RSX/Program/CgBinaryProgram.cpp diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 62a91d1d34..0164376dff 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -511,6 +511,7 @@ target_sources(rpcs3_emu PRIVATE RSX/Overlays/overlay_video.cpp RSX/Overlays/Shaders/shader_loading_dialog.cpp RSX/Overlays/Shaders/shader_loading_dialog_native.cpp + RSX/Program/CgBinaryProgram.cpp RSX/Program/CgBinaryFragmentProgram.cpp RSX/Program/CgBinaryVertexProgram.cpp RSX/Program/FragmentProgramDecompiler.cpp diff --git a/rpcs3/Emu/RSX/Program/CgBinaryProgram.cpp b/rpcs3/Emu/RSX/Program/CgBinaryProgram.cpp new file mode 100644 index 0000000000..d9c090addb --- /dev/null +++ b/rpcs3/Emu/RSX/Program/CgBinaryProgram.cpp @@ -0,0 +1,246 @@ +#include "stdafx.h" +#include "CgBinaryProgram.h" + +#ifndef WITHOUT_OPENGL +#include "Emu/RSX/GL/GLVertexProgram.h" +#include "Emu/RSX/GL/GLFragmentProgram.h" +#endif + +CgBinaryDisasm::CgBinaryDisasm(const std::string& path) + : m_path(path) +{ + fs::file f(path); + if (!f) + { + return; + } + + usz buffer_size = f.size(); + m_buffer.resize(buffer_size); + f.read(m_buffer, buffer_size); + fmt::append(m_arb_shader, "Loading... [%s]\n", path.c_str()); +} + +std::string CgBinaryDisasm::GetCgParamType(u32 type) +{ + switch (type) + { + case 1045: return "float"; + case 1046: + case 1047: + case 1048: return fmt::format("float%d", type - 1044); + case 1064: return "float4x4"; + case 1066: return "sampler2D"; + case 1069: return "samplerCUBE"; + case 1091: return "float1"; + + default: return fmt::format("!UnkCgType(%d)", type); + } +} + +std::string CgBinaryDisasm::GetCgParamName(u32 offset) const +{ + return std::string(&m_buffer[offset]); +} + +std::string CgBinaryDisasm::GetCgParamRes(u32 /*offset*/) const +{ + // rsx_log.warning("GetCgParamRes offset 0x%x", offset); + // TODO + return ""; +} + +std::string CgBinaryDisasm::GetCgParamSemantic(u32 offset) const +{ + return std::string(&m_buffer[offset]); +} + +std::string CgBinaryDisasm::GetCgParamValue(u32 offset, u32 end_offset) const +{ + std::string offsets = "offsets:"; + + u32 num = 0; + offset += 6; + while (offset < end_offset) + { + fmt::append(offsets, " %d,", m_buffer[offset] << 8 | m_buffer[offset + 1]); + offset += 4; + num++; + } + + if (num > 4) + { + return ""; + } + + offsets.pop_back(); + return fmt::format("num %d ", num) + offsets; +} + +void CgBinaryDisasm::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.data() + start_offset); + auto end = reinterpret_cast(m_buffer.data() + 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)); + } +} + +void CgBinaryDisasm::BuildShaderBody(bool include_glsl) +{ + ParamArray param_array; + + auto& prog = GetCgRef(0); + + if (const u32 be_profile = std::bit_cast>(prog.profile); + be_profile == 7003u || be_profile == 7004u) + { + ConvertToLE(prog); + ensure(be_profile == prog.profile); + } + + if (prog.profile == 7004u) + { + auto& fprog = GetCgRef(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"); + fmt::append(m_arb_shader, "# parameterCount %d\n", prog.parameterCount); + fmt::append(m_arb_shader, "# instructionCount %d\n", fprog.instructionCount); + fmt::append(m_arb_shader, "# attributeInputMask 0x%x\n", fprog.attributeInputMask); + fmt::append(m_arb_shader, "# registerCount %d\n\n", fprog.registerCount); + + CgBinaryParameterOffset offset = prog.parameterArray; + for (u32 i = 0; i < prog.parameterCount; i++) + { + auto& fparam = GetCgRef(offset); + + std::string param_type = GetCgParamType(fparam.type) + " "; + std::string param_name = GetCgParamName(fparam.name) + " "; + std::string param_res = GetCgParamRes(fparam.res) + " "; + std::string param_semantic = GetCgParamSemantic(fparam.semantic) + " "; + std::string param_const = GetCgParamValue(fparam.embeddedConst, fparam.name); + + fmt::append(m_arb_shader, "#%d%s%s%s%s\n", i, param_type, param_name, param_semantic, param_const); + + offset += u32{sizeof(CgBinaryParameter)}; + } + + m_arb_shader += "\n"; + m_offset = prog.ucode; + TaskFP(); + + if (!include_glsl) + { + return; + } + + u32 unused; + std::vector be_data; + + // Swap bytes. FP decompiler expects input in BE + for (u32* ptr = reinterpret_cast(m_buffer.data() + m_offset), + *end = reinterpret_cast(m_buffer.data() + m_buffer.size()); + ptr < end; ++ptr) + { + be_data.push_back(std::bit_cast>(*ptr)); + } + + RSXFragmentProgram rsx_prog; + auto metadata = program_hash_util::fragment_program_utils::analyse_fragment_program(be_data.data()); + rsx_prog.ctrl = (fprog.outputFromH0 ? 0 : 0x40) | (fprog.depthReplace ? 0xe : 0); + rsx_prog.offset = metadata.program_start_offset; + rsx_prog.ucode_length = metadata.program_ucode_length; + rsx_prog.total_length = metadata.program_ucode_length + metadata.program_start_offset; + rsx_prog.data = reinterpret_cast(be_data.data()) + metadata.program_start_offset; + for (u32 i = 0; i < 16; ++i) rsx_prog.texture_state.set_dimension(rsx::texture_dimension_extended::texture_dimension_2d, i); +#ifndef WITHOUT_OPENGL + GLFragmentDecompilerThread(m_glsl_shader, param_array, rsx_prog, unused).Task(); +#endif + } + + else + { + const auto& vprog = GetCgRef(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"); + fmt::append(m_arb_shader, "# parameterCount %d\n", prog.parameterCount); + fmt::append(m_arb_shader, "# instructionCount %d\n", vprog.instructionCount); + fmt::append(m_arb_shader, "# registerCount %d\n", vprog.registerCount); + fmt::append(m_arb_shader, "# attributeInputMask 0x%x\n", vprog.attributeInputMask); + fmt::append(m_arb_shader, "# attributeOutputMask 0x%x\n\n", vprog.attributeOutputMask); + + CgBinaryParameterOffset offset = prog.parameterArray; + for (u32 i = 0; i < prog.parameterCount; i++) + { + auto& vparam = GetCgRef(offset); + + std::string param_type = GetCgParamType(vparam.type) + " "; + std::string param_name = GetCgParamName(vparam.name) + " "; + std::string param_res = GetCgParamRes(vparam.res) + " "; + std::string param_semantic = GetCgParamSemantic(vparam.semantic) + " "; + std::string param_const = GetCgParamValue(vparam.embeddedConst, vparam.name); + + fmt::append(m_arb_shader, "#%d%s%s%s%s\n", i, param_type, param_name, param_semantic, param_const); + + offset += u32{sizeof(CgBinaryParameter)}; + } + + m_arb_shader += "\n"; + m_offset = prog.ucode; + ensure((m_buffer.size() - m_offset) % sizeof(u32) == 0); + + u32* vdata = reinterpret_cast(&m_buffer[m_offset]); + m_data.resize(prog.ucodeSize / sizeof(u32)); + std::memcpy(m_data.data(), vdata, prog.ucodeSize); + TaskVP(); + + if (!include_glsl) + { + return; + } + + RSXVertexProgram rsx_prog; + program_hash_util::vertex_program_utils::analyse_vertex_program(vdata, 0, rsx_prog); + for (u32 i = 0; i < 4; ++i) rsx_prog.texture_state.set_dimension(rsx::texture_dimension_extended::texture_dimension_2d, i); +#ifndef WITHOUT_OPENGL + GLVertexDecompilerThread(rsx_prog, m_glsl_shader, param_array).Task(); +#endif + } +} diff --git a/rpcs3/Emu/RSX/Program/CgBinaryProgram.h b/rpcs3/Emu/RSX/Program/CgBinaryProgram.h index d52190a51f..56d8f4d70b 100644 --- a/rpcs3/Emu/RSX/Program/CgBinaryProgram.h +++ b/rpcs3/Emu/RSX/Program/CgBinaryProgram.h @@ -7,11 +7,6 @@ #include "Emu/RSX/Program/ShaderParam.h" #include "Utilities/File.h" -#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; @@ -189,17 +184,7 @@ public: void SetDSTScaDisasm(const std::string& code); - CgBinaryDisasm(const std::string& path) - : m_path(path) - { - fs::file f(path); - if (!f) return; - - usz buffer_size = f.size(); - m_buffer.resize(buffer_size); - f.read(m_buffer, buffer_size); - fmt::append(m_arb_shader, "Loading... [%s]\n", path.c_str()); - } + CgBinaryDisasm(const std::string& path); template CgBinaryDisasm(const std::span& data) @@ -211,233 +196,20 @@ public: ~CgBinaryDisasm() = default; - static std::string GetCgParamType(u32 type) - { - switch (type) - { - case 1045: return "float"; - case 1046: - case 1047: - case 1048: return fmt::format("float%d", type - 1044); - case 1064: return "float4x4"; - case 1066: return "sampler2D"; - case 1069: return "samplerCUBE"; - case 1091: return "float1"; - - default: return fmt::format("!UnkCgType(%d)", type); - } - } - - std::string GetCgParamName(u32 offset) const - { - return std::string(&m_buffer[offset]); - } - - std::string GetCgParamRes(u32 /*offset*/) const - { - // rsx_log.warning("GetCgParamRes offset 0x%x", offset); - // TODO - return ""; - } - - std::string GetCgParamSemantic(u32 offset) const - { - return std::string(&m_buffer[offset]); - } - - std::string GetCgParamValue(u32 offset, u32 end_offset) const - { - std::string offsets = "offsets:"; - - u32 num = 0; - offset += 6; - while (offset < end_offset) - { - fmt::append(offsets, " %d,", m_buffer[offset] << 8 | m_buffer[offset + 1]); - offset += 4; - num++; - } - - if (num > 4) - return ""; - - offsets.pop_back(); - return fmt::format("num %d ", num) + offsets; - } - template T& GetCgRef(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; + static std::string GetCgParamType(u32 type); + std::string GetCgParamName(u32 offset) const; + std::string GetCgParamRes(u32 /*offset*/) const; + std::string GetCgParamSemantic(u32 offset) const; + std::string GetCgParamValue(u32 offset, u32 end_offset) const; - auto swap_be32 = [&](u32 start_offset, size_t size_bytes) - { - auto start = reinterpret_cast(m_buffer.data() + start_offset); - auto end = reinterpret_cast(m_buffer.data() + 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)); - } - } - - void BuildShaderBody(bool include_glsl = true) - { - ParamArray param_array; - - auto& prog = GetCgRef(0); - - if (const u32 be_profile = std::bit_cast>(prog.profile); - be_profile == 7003u || be_profile == 7004u) - { - ConvertToLE(prog); - ensure(be_profile == prog.profile); - } - - if (prog.profile == 7004u) - { - auto& fprog = GetCgRef(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"); - fmt::append(m_arb_shader, "# parameterCount %d\n", prog.parameterCount); - fmt::append(m_arb_shader, "# instructionCount %d\n", fprog.instructionCount); - fmt::append(m_arb_shader, "# attributeInputMask 0x%x\n", fprog.attributeInputMask); - fmt::append(m_arb_shader, "# registerCount %d\n\n", fprog.registerCount); - - CgBinaryParameterOffset offset = prog.parameterArray; - for (u32 i = 0; i < prog.parameterCount; i++) - { - auto& fparam = GetCgRef(offset); - - std::string param_type = GetCgParamType(fparam.type) + " "; - std::string param_name = GetCgParamName(fparam.name) + " "; - std::string param_res = GetCgParamRes(fparam.res) + " "; - std::string param_semantic = GetCgParamSemantic(fparam.semantic) + " "; - std::string param_const = GetCgParamValue(fparam.embeddedConst, fparam.name); - - fmt::append(m_arb_shader, "#%d%s%s%s%s\n", i, param_type, param_name, param_semantic, param_const); - - offset += u32{sizeof(CgBinaryParameter)}; - } - - m_arb_shader += "\n"; - m_offset = prog.ucode; - TaskFP(); - - if (!include_glsl) - { - return; - } - - u32 unused; - std::vector be_data; - - // Swap bytes. FP decompiler expects input in BE - for (u32* ptr = reinterpret_cast(m_buffer.data() + m_offset), - *end = reinterpret_cast(m_buffer.data() + m_buffer.size()); - ptr < end; ++ptr) - { - be_data.push_back(std::bit_cast>(*ptr)); - } - - RSXFragmentProgram rsx_prog; - auto metadata = program_hash_util::fragment_program_utils::analyse_fragment_program(be_data.data()); - rsx_prog.ctrl = (fprog.outputFromH0 ? 0 : 0x40) | (fprog.depthReplace ? 0xe : 0); - rsx_prog.offset = metadata.program_start_offset; - rsx_prog.ucode_length = metadata.program_ucode_length; - rsx_prog.total_length = metadata.program_ucode_length + metadata.program_start_offset; - rsx_prog.data = reinterpret_cast(be_data.data()) + metadata.program_start_offset; - for (u32 i = 0; i < 16; ++i) rsx_prog.texture_state.set_dimension(rsx::texture_dimension_extended::texture_dimension_2d, i); -#ifndef WITHOUT_OPENGL - GLFragmentDecompilerThread(m_glsl_shader, param_array, rsx_prog, unused).Task(); -#endif - } - - else - { - const auto& vprog = GetCgRef(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"); - fmt::append(m_arb_shader, "# parameterCount %d\n", prog.parameterCount); - fmt::append(m_arb_shader, "# instructionCount %d\n", vprog.instructionCount); - fmt::append(m_arb_shader, "# registerCount %d\n", vprog.registerCount); - fmt::append(m_arb_shader, "# attributeInputMask 0x%x\n", vprog.attributeInputMask); - fmt::append(m_arb_shader, "# attributeOutputMask 0x%x\n\n", vprog.attributeOutputMask); - - CgBinaryParameterOffset offset = prog.parameterArray; - for (u32 i = 0; i < prog.parameterCount; i++) - { - auto& vparam = GetCgRef(offset); - - std::string param_type = GetCgParamType(vparam.type) + " "; - std::string param_name = GetCgParamName(vparam.name) + " "; - std::string param_res = GetCgParamRes(vparam.res) + " "; - std::string param_semantic = GetCgParamSemantic(vparam.semantic) + " "; - std::string param_const = GetCgParamValue(vparam.embeddedConst, vparam.name); - - fmt::append(m_arb_shader, "#%d%s%s%s%s\n", i, param_type, param_name, param_semantic, param_const); - - offset += u32{sizeof(CgBinaryParameter)}; - } - - m_arb_shader += "\n"; - m_offset = prog.ucode; - ensure((m_buffer.size() - m_offset) % sizeof(u32) == 0); - - u32* vdata = reinterpret_cast(&m_buffer[m_offset]); - m_data.resize(prog.ucodeSize / sizeof(u32)); - std::memcpy(m_data.data(), vdata, prog.ucodeSize); - TaskVP(); - - if (!include_glsl) - { - return; - } - - RSXVertexProgram rsx_prog; - program_hash_util::vertex_program_utils::analyse_vertex_program(vdata, 0, rsx_prog); - for (u32 i = 0; i < 4; ++i) rsx_prog.texture_state.set_dimension(rsx::texture_dimension_extended::texture_dimension_2d, i); -#ifndef WITHOUT_OPENGL - GLVertexDecompilerThread(rsx_prog, m_glsl_shader, param_array).Task(); -#endif - } - } + void ConvertToLE(CgBinaryProgram& prog); + void BuildShaderBody(bool include_glsl = true); static u32 GetData(const u32 d) { return d << 16 | d >> 16; } void TaskFP(); diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 0f07b59a3f..3e623663d4 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -454,6 +454,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index ef03ca416f..94f0382bcc 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1099,6 +1099,9 @@ Emu\GPU\RSX\Program + + Emu\GPU\RSX\Program + Emu\GPU\RSX\Program diff --git a/rpcs3/rpcs3qt/rsx_debugger.cpp b/rpcs3/rpcs3qt/rsx_debugger.cpp index 0026fda959..bdea183d2e 100644 --- a/rpcs3/rpcs3qt/rsx_debugger.cpp +++ b/rpcs3/rpcs3qt/rsx_debugger.cpp @@ -1228,11 +1228,11 @@ void rsx_debugger::GetVertexProgram() const vp.data.reserve(512 * 4); const u32 vp_entry = rsx::method_registers.transform_program_start(); - const auto vp_metadata = program_hash_util::vertex_program_utils::analyse_vertex_program + program_hash_util::vertex_program_utils::analyse_vertex_program ( rsx::method_registers.transform_program.data(), // Input raw block - vp_entry, // Address of entry point - vp // [out] Program object + vp_entry, // Address of entry point + vp // [out] Program object ); const u32 ucode_len = static_cast(vp.data.size() * sizeof(u32));