diff --git a/.gitmodules b/.gitmodules index 305705b06a..427c61ffbd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -106,5 +106,5 @@ ignore = dirty [submodule "3rdparty/GPUOpen/VulkanMemoryAllocator"] path = 3rdparty/GPUOpen/VulkanMemoryAllocator - url = ../../Megamouse/VulkanMemoryAllocator.git + url = ../../GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git ignore = dirty diff --git a/3rdparty/GPUOpen/VulkanMemoryAllocator b/3rdparty/GPUOpen/VulkanMemoryAllocator index 3706484339..1d8f600fd4 160000 --- a/3rdparty/GPUOpen/VulkanMemoryAllocator +++ b/3rdparty/GPUOpen/VulkanMemoryAllocator @@ -1 +1 @@ -Subproject commit 37064843398c69cc0ca7f8cf5b33128c03a2bd74 +Subproject commit 1d8f600fd424278486eade7ed3e877c99f0846b1 diff --git a/3rdparty/hidapi/hidapi b/3rdparty/hidapi/hidapi index 6bfdcf7368..f42423643e 160000 --- a/3rdparty/hidapi/hidapi +++ b/3rdparty/hidapi/hidapi @@ -1 +1 @@ -Subproject commit 6bfdcf7368169efe1b745cd4468d45cda05ef8de +Subproject commit f42423643ec9011c98cccc0bb790722bbbd3f30b 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/Cell/PPUInterpreter.cpp b/rpcs3/Emu/Cell/PPUInterpreter.cpp index 35c2ded508..69d11864d1 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/PPUInterpreter.cpp @@ -139,7 +139,7 @@ struct ppu_exec_select #define RETURN_(...) \ if constexpr (Build == 0) { \ static_cast(exec); \ - if (is_debugger_present()) return +[](ppu_thread& ppu, ppu_opcode_t op, be_t* this_op, ppu_intrp_func* next_fn) { \ + if (is_debugger_present() || g_cfg.core.ppu_debug) return +[](ppu_thread& ppu, ppu_opcode_t op, be_t* this_op, ppu_intrp_func* next_fn) { \ exec(__VA_ARGS__); \ const auto next_op = this_op + 1; \ const auto fn = atomic_storage::load(next_fn->fn); \ diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index a227480a48..dc6e6f364a 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -6181,7 +6181,7 @@ s64 spu_thread::get_ch_value(u32 ch) { if (utils::has_waitpkg()) { - __tpause(std::min(eventstat_spin_count, 10) * 500, 0x1); + __tpause(static_cast(std::min(eventstat_spin_count, 10) * 500), 0x1); } else { @@ -6194,7 +6194,7 @@ s64 spu_thread::get_ch_value(u32 ch) }; // Provide the first X64 cache line of the reservation to be tracked - __mwaitx(std::min(eventstat_spin_count, 17) * 500, 0xf0, std::addressof(*resrv_mem), +rtime, vm::reservation_acquire(raddr)); + __mwaitx(static_cast(std::min(eventstat_spin_count, 17) * 500), 0xf0, std::addressof(*resrv_mem), +rtime, vm::reservation_acquire(raddr)); } } else diff --git a/rpcs3/Emu/Io/LogitechG27.cpp b/rpcs3/Emu/Io/LogitechG27.cpp index e291117cf5..5503c606fc 100644 --- a/rpcs3/Emu/Io/LogitechG27.cpp +++ b/rpcs3/Emu/Io/LogitechG27.cpp @@ -115,12 +115,8 @@ u16 usb_device_logitech_g27::get_num_emu_devices() void usb_device_logitech_g27::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) { - transfer->fake = true; - transfer->expected_count = buf_size; - transfer->expected_result = HC_CC_NOERR; - transfer->expected_time = get_timestamp() + 100; + logitech_g27_log.todo("control transfer bmRequestType %02x, bRequest %02x, wValue %04x, wIndex %04x, wLength %04x, %s", bmRequestType, bRequest, wValue, wIndex, wLength, fmt::buf_to_hexstring(buf, buf_size)); - // Log these for now, might not need to implement anything usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer); } @@ -209,6 +205,7 @@ static inline logitech_g27_sdl_mapping get_runtime_mapping() convert_mapping(cfg.shifter_5, mapping.shifter_5); convert_mapping(cfg.shifter_6, mapping.shifter_6); convert_mapping(cfg.shifter_r, mapping.shifter_r); + convert_mapping(cfg.shifter_press, mapping.shifter_press); return mapping; } @@ -711,6 +708,7 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp const bool shifter_5 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_5); const bool shifter_6 = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_6); const bool shifter_r = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_r); + const bool shifter_press = sdl_to_logitech_g27_button(m_joysticks, m_mapping.shifter_press); m_sdl_handles_mutex.unlock(); // populate buffer @@ -749,8 +747,16 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp set_bit(buf, 82, true); // shifter connected set_bit(buf, 83, true); - // shifter stick down - set_bit(buf, 86, shifter_1 || shifter_2 || shifter_3 || shifter_4 || shifter_5 || shifter_6 || shifter_r); + /* + * shifter pressed/down bit + * mechanical references: + * - G29 shifter mechanical explanation https://youtu.be/d7qCn3o8K98?t=1124 + * - same mechanism on the G27 https://youtu.be/rdjejtIfkVA?t=760 + * - same mechanism on the G25 https://youtu.be/eCyt_4luwF0?t=130 + * on healthy G29/G27/G25 shifters, shifter is mechnically kept pressed in reverse, the bit should be set + * the shifter_press mapping alone captures instead a shifter press without going into reverse, ie. neutral press, just in case there are games using it for input + */ + set_bit(buf, 86, shifter_press | shifter_r); buf[3] = (steering << 2) | buf[3]; buf[4] = steering >> 6; @@ -758,8 +764,56 @@ void usb_device_logitech_g27::interrupt_transfer(u32 buf_size, u8* buf, u32 endp buf[6] = brake; buf[7] = clutch; - buf[8] = 0x80; // shifter x, don't own one to test gear/coord mapping - buf[9] = 0x80; // shifter y + // rough analog values recorded in https://github.com/RPCS3/rpcs3/pull/17199#issuecomment-2883934412 + // buf[8] shifter x + // buf[9] shifter y + constexpr u8 shifter_coord_center = 0x80; + constexpr u8 shifter_coord_top = 0xb7; + constexpr u8 shifter_coord_bottom = 0x32; + constexpr u8 shifter_coord_left = 0x30; + constexpr u8 shifter_coord_right = 0xb3; + constexpr u8 shifter_coord_right_reverse = 0xaa; + if (shifter_1) + { + buf[8] = shifter_coord_left; + buf[9] = shifter_coord_top; + } + else if (shifter_2) + { + buf[8] = shifter_coord_left; + buf[9] = shifter_coord_bottom; + } + else if (shifter_3) + { + buf[8] = shifter_coord_center; + buf[9] = shifter_coord_top; + } + else if (shifter_4) + { + buf[8] = shifter_coord_center; + buf[9] = shifter_coord_bottom; + } + else if (shifter_5) + { + buf[8] = shifter_coord_right; + buf[9] = shifter_coord_top; + } + else if (shifter_6) + { + buf[8] = shifter_coord_right; + buf[9] = shifter_coord_bottom; + } + else if (shifter_r) + { + buf[8] = shifter_coord_right_reverse; + buf[9] = shifter_coord_bottom; + } + else + { + buf[8] = shifter_coord_center; + buf[9] = shifter_coord_center; + } + buf[10] = buf[10] | (m_wheel_range > 360 ? 0x90 : 0x10); // logitech_g27_log.error("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10]); diff --git a/rpcs3/Emu/Io/LogitechG27.h b/rpcs3/Emu/Io/LogitechG27.h index 63c61676aa..52735a253d 100644 --- a/rpcs3/Emu/Io/LogitechG27.h +++ b/rpcs3/Emu/Io/LogitechG27.h @@ -94,6 +94,7 @@ struct logitech_g27_sdl_mapping sdl_mapping shifter_5 {}; sdl_mapping shifter_6 {}; sdl_mapping shifter_r {}; + sdl_mapping shifter_press {}; }; class usb_device_logitech_g27 : public usb_device_emulated diff --git a/rpcs3/Emu/Io/LogitechG27Config.h b/rpcs3/Emu/Io/LogitechG27Config.h index 18a4f5c9d2..82a2e89dea 100644 --- a/rpcs3/Emu/Io/LogitechG27Config.h +++ b/rpcs3/Emu/Io/LogitechG27Config.h @@ -107,6 +107,7 @@ public: emulated_logitech_g27_mapping shifter_5{this, "shifter_5", 0, sdl_mapping_type::hat, 0, hat_component::up, false}; emulated_logitech_g27_mapping shifter_6{this, "shifter_6", 0, sdl_mapping_type::hat, 0, hat_component::down, false}; emulated_logitech_g27_mapping shifter_r{this, "shifter_r", 0, sdl_mapping_type::hat, 0, hat_component::left, false}; + emulated_logitech_g27_mapping shifter_press{this, "shifter_press", 0, sdl_mapping_type::hat, 0, hat_component::right, false}; cfg::_bool reverse_effects{this, "reverse_effects", false}; cfg::uint<0, 0xFFFFFFFFFFFFFFFF> ffb_device_type_id{this, "ffb_device_type_id", 0}; diff --git a/rpcs3/Emu/NP/rpcn_client.cpp b/rpcs3/Emu/NP/rpcn_client.cpp index 7d80c361a8..8fa33a306a 100644 --- a/rpcs3/Emu/NP/rpcn_client.cpp +++ b/rpcs3/Emu/NP/rpcn_client.cpp @@ -1629,17 +1629,6 @@ namespace rpcn { flatbuffers::FlatBufferBuilder builder(1024); - flatbuffers::Offset>> final_binattrinternal_vec; - if (req->roomBinAttrInternalNum && req->roomBinAttrInternal) - { - std::vector> davec; - for (u32 i = 0; i < req->roomBinAttrInternalNum; i++) - { - auto bin = CreateBinAttr(builder, req->roomBinAttrInternal[i].id, builder.CreateVector(req->roomBinAttrInternal[i].ptr.get_ptr(), req->roomBinAttrInternal[i].size)); - davec.push_back(bin); - } - final_binattrinternal_vec = builder.CreateVector(davec); - } flatbuffers::Offset>> final_searchintattrexternal_vec; if (req->roomSearchableIntAttrExternalNum && req->roomSearchableIntAttrExternal) { @@ -1651,28 +1640,74 @@ namespace rpcn } final_searchintattrexternal_vec = builder.CreateVector(davec); } + + // WWE SmackDown vs. RAW 2009 passes roomBinAttrExternal in roomSearchableBinAttrExternal so we parse based on attribute ids + + flatbuffers::Offset>> final_binattrinternal_vec; flatbuffers::Offset>> final_searchbinattrexternal_vec; + flatbuffers::Offset>> final_binattrexternal_vec; + + std::vector> davec_binattrinternal; + std::vector> davec_searchable_binattrexternal; + std::vector> davec_binattrexternal; + + auto put_binattr = [&](SceNpMatching2AttributeId id, flatbuffers::Offset bin) + { + switch (id) + { + case SCE_NP_MATCHING2_ROOM_BIN_ATTR_INTERNAL_1_ID: + case SCE_NP_MATCHING2_ROOM_BIN_ATTR_INTERNAL_2_ID: + davec_binattrinternal.push_back(bin); + break; + case SCE_NP_MATCHING2_ROOM_BIN_ATTR_EXTERNAL_1_ID: + case SCE_NP_MATCHING2_ROOM_BIN_ATTR_EXTERNAL_2_ID: + davec_binattrexternal.push_back(bin); + break; + case SCE_NP_MATCHING2_ROOM_SEARCHABLE_BIN_ATTR_EXTERNAL_1_ID: + davec_searchable_binattrexternal.push_back(bin); + break; + default: + rpcn_log.error("Unexpected bin attribute id in createjoin_room request: 0x%x", id); + break; + } + }; + + if (req->roomBinAttrInternalNum && req->roomBinAttrInternal) + { + for (u32 i = 0; i < req->roomBinAttrInternalNum; i++) + { + auto bin = CreateBinAttr(builder, req->roomBinAttrInternal[i].id, builder.CreateVector(req->roomBinAttrInternal[i].ptr.get_ptr(), req->roomBinAttrInternal[i].size)); + put_binattr(req->roomBinAttrInternal[i].id, bin); + } + } + if (req->roomSearchableBinAttrExternalNum && req->roomSearchableBinAttrExternal) { - std::vector> davec; for (u32 i = 0; i < req->roomSearchableBinAttrExternalNum; i++) { auto bin = CreateBinAttr(builder, req->roomSearchableBinAttrExternal[i].id, builder.CreateVector(req->roomSearchableBinAttrExternal[i].ptr.get_ptr(), req->roomSearchableBinAttrExternal[i].size)); - davec.push_back(bin); + put_binattr(req->roomSearchableBinAttrExternal[i].id, bin); } - final_searchbinattrexternal_vec = builder.CreateVector(davec); } - flatbuffers::Offset>> final_binattrexternal_vec; + if (req->roomBinAttrExternalNum && req->roomBinAttrExternal) { - std::vector> davec; for (u32 i = 0; i < req->roomBinAttrExternalNum; i++) { auto bin = CreateBinAttr(builder, req->roomBinAttrExternal[i].id, builder.CreateVector(req->roomBinAttrExternal[i].ptr.get_ptr(), req->roomBinAttrExternal[i].size)); - davec.push_back(bin); + put_binattr(req->roomBinAttrExternal[i].id, bin); } - final_binattrexternal_vec = builder.CreateVector(davec); } + + if (!davec_binattrinternal.empty()) + final_binattrinternal_vec = builder.CreateVector(davec_binattrinternal); + + if (!davec_searchable_binattrexternal.empty()) + final_searchbinattrexternal_vec = builder.CreateVector(davec_searchable_binattrexternal); + + if (!davec_binattrexternal.empty()) + final_binattrexternal_vec = builder.CreateVector(davec_binattrexternal); + flatbuffers::Offset> final_roompassword; if (req->roomPassword) final_roompassword = builder.CreateVector(req->roomPassword->data, 8); @@ -1884,28 +1919,54 @@ namespace rpcn } final_searchintattrexternal_vec = builder.CreateVector(davec); } + flatbuffers::Offset>> final_searchbinattrexternal_vec; + flatbuffers::Offset>> final_binattrexternal_vec; + + std::vector> davec_searchable_binattrexternal; + std::vector> davec_binattrexternal; + + auto put_binattr = [&](SceNpMatching2AttributeId id, flatbuffers::Offset bin) + { + switch (id) + { + case SCE_NP_MATCHING2_ROOM_BIN_ATTR_EXTERNAL_1_ID: + case SCE_NP_MATCHING2_ROOM_BIN_ATTR_EXTERNAL_2_ID: + davec_binattrexternal.push_back(bin); + break; + case SCE_NP_MATCHING2_ROOM_SEARCHABLE_BIN_ATTR_EXTERNAL_1_ID: + davec_searchable_binattrexternal.push_back(bin); + break; + default: + rpcn_log.error("Unexpected bin attribute id in set_roomdata_external request: 0x%x", id); + break; + } + }; + if (req->roomSearchableBinAttrExternalNum && req->roomSearchableBinAttrExternal) { - std::vector> davec; for (u32 i = 0; i < req->roomSearchableBinAttrExternalNum; i++) { auto bin = CreateBinAttr(builder, req->roomSearchableBinAttrExternal[i].id, builder.CreateVector(req->roomSearchableBinAttrExternal[i].ptr.get_ptr(), req->roomSearchableBinAttrExternal[i].size)); - davec.push_back(bin); + put_binattr(req->roomSearchableBinAttrExternal[i].id, bin); } - final_searchbinattrexternal_vec = builder.CreateVector(davec); } - flatbuffers::Offset>> final_binattrexternal_vec; + if (req->roomBinAttrExternalNum && req->roomBinAttrExternal) { - std::vector> davec; for (u32 i = 0; i < req->roomBinAttrExternalNum; i++) { auto bin = CreateBinAttr(builder, req->roomBinAttrExternal[i].id, builder.CreateVector(req->roomBinAttrExternal[i].ptr.get_ptr(), req->roomBinAttrExternal[i].size)); - davec.push_back(bin); + put_binattr(req->roomBinAttrExternal[i].id, bin); } - final_binattrexternal_vec = builder.CreateVector(davec); } + + if (!davec_searchable_binattrexternal.empty()) + final_searchbinattrexternal_vec = builder.CreateVector(davec_searchable_binattrexternal); + + if (!davec_binattrexternal.empty()) + final_binattrexternal_vec = builder.CreateVector(davec_binattrexternal); + auto req_finished = CreateSetRoomDataExternalRequest(builder, req->roomId, final_searchintattrexternal_vec, final_searchbinattrexternal_vec, final_binattrexternal_vec); builder.Finish(req_finished); diff --git a/rpcs3/Emu/RSX/Program/CgBinaryFragmentProgram.cpp b/rpcs3/Emu/RSX/Program/CgBinaryFragmentProgram.cpp index 877e55c6af..a06818de10 100644 --- a/rpcs3/Emu/RSX/Program/CgBinaryFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/Program/CgBinaryFragmentProgram.cpp @@ -230,7 +230,7 @@ void CgBinaryDisasm::TaskFP() { m_size = 0; u32* data = reinterpret_cast(&m_buffer[m_offset]); - ensure((m_buffer_size - m_offset) % sizeof(u32) == 0); + ensure((m_buffer.size() - m_offset) % sizeof(u32) == 0); enum { 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 310be35baa..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; @@ -133,8 +128,7 @@ class CgBinaryDisasm std::string m_path; // used for FP decompiler thread, delete this later - u8* m_buffer = nullptr; - usz m_buffer_size = 0; + std::vector m_buffer; std::string m_arb_shader; std::string m_glsl_shader; std::string m_dst_reg_name; @@ -190,76 +184,17 @@ public: void SetDSTScaDisasm(const std::string& code); - CgBinaryDisasm(const std::string& path) - : m_path(path) - { - fs::file f(path); - if (!f) return; + CgBinaryDisasm(const std::string& path); - m_buffer_size = f.size(); - m_buffer = new u8[m_buffer_size]; - f.read(m_buffer, m_buffer_size); - fmt::append(m_arb_shader, "Loading... [%s]\n", path.c_str()); + template + CgBinaryDisasm(const std::span& data) + : m_path("") + { + m_buffer.resize(data.size_bytes()); + std::memcpy(m_buffer.data(), data.data(), data.size_bytes()); } - ~CgBinaryDisasm() - { - delete[] m_buffer; - } - - 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(reinterpret_cast(&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(reinterpret_cast(&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; - } + ~CgBinaryDisasm() = default; template T& GetCgRef(const u32 offset) @@ -267,163 +202,14 @@ public: 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 + 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)); - } - } - - void BuildShaderBody() - { - 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(); - - u32 unused; - std::vector be_data; - - // Swap bytes. FP decompiler expects input in BE - for (u32* ptr = reinterpret_cast(m_buffer + m_offset), - *end = reinterpret_cast(m_buffer + m_buffer_size); - ptr < end; ++ptr) - { - be_data.push_back(std::bit_cast>(*ptr)); - } - - RSXFragmentProgram prog; - auto metadata = program_hash_util::fragment_program_utils::analyse_fragment_program(be_data.data()); - prog.ctrl = (fprog.outputFromH0 ? 0 : 0x40) | (fprog.depthReplace ? 0xe : 0); - prog.offset = metadata.program_start_offset; - prog.ucode_length = metadata.program_ucode_length; - prog.total_length = metadata.program_ucode_length + metadata.program_start_offset; - prog.data = reinterpret_cast(be_data.data()) + metadata.program_start_offset; - for (u32 i = 0; i < 16; ++i) prog.texture_state.set_dimension(rsx::texture_dimension_extended::texture_dimension_2d, i); -#ifndef WITHOUT_OPENGL - GLFragmentDecompilerThread(m_glsl_shader, param_array, 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(); - - RSXVertexProgram prog; - program_hash_util::vertex_program_utils::analyse_vertex_program(vdata, 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 - GLVertexDecompilerThread(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/Emu/RSX/VK/VKMemAlloc.cpp b/rpcs3/Emu/RSX/VK/VKMemAlloc.cpp index e6cf921dc7..d90fb7936c 100644 --- a/rpcs3/Emu/RSX/VK/VKMemAlloc.cpp +++ b/rpcs3/Emu/RSX/VK/VKMemAlloc.cpp @@ -1,4 +1,5 @@ #define VMA_IMPLEMENTATION +#define VMA_VULKAN_VERSION 1000000 #include "util/atomic.hpp" #include "Utilities/mutex.h" @@ -49,11 +50,12 @@ private: #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" #ifdef __clang__ #pragma clang diagnostic ignored "-Winconsistent-missing-override" +#pragma clang diagnostic ignored "-Wnullability-completeness" #else #pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn" #endif #endif -#include "3rdparty/GPUOpen/VulkanMemoryAllocator/src/vk_mem_alloc.h" +#include "3rdparty/GPUOpen/VulkanMemoryAllocator/include/vk_mem_alloc.h" #ifdef _MSC_VER #pragma warning(pop) #else diff --git a/rpcs3/Emu/RSX/VK/vkutils/device.cpp b/rpcs3/Emu/RSX/VK/vkutils/device.cpp index 8aa6a6fed8..22c9e55eab 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/device.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/device.cpp @@ -880,7 +880,7 @@ namespace vk } else { - m_allocator = std::make_unique(*this, pdev); + m_allocator = std::make_unique(*this, pdev, pdev); } // Useful for debugging different VRAM configurations diff --git a/rpcs3/Emu/RSX/VK/vkutils/memory.cpp b/rpcs3/Emu/RSX/VK/vkutils/memory.cpp index 45237853be..c1018389e7 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/memory.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/memory.cpp @@ -153,11 +153,11 @@ namespace vk rsx_log.warning("Rebalanced memory types successfully"); } - mem_allocator_base::mem_allocator_base(const vk::render_device& dev, VkPhysicalDevice) + mem_allocator_base::mem_allocator_base(const vk::render_device& dev, VkPhysicalDevice /*pdev*/) : m_device(dev), m_allocation_flags(0) {} - mem_allocator_vma::mem_allocator_vma(const vk::render_device& dev, VkPhysicalDevice pdev) + mem_allocator_vma::mem_allocator_vma(const vk::render_device& dev, VkPhysicalDevice pdev, VkInstance inst) : mem_allocator_base(dev, pdev) { // Initialize stats pool @@ -166,6 +166,8 @@ namespace vk VmaAllocatorCreateInfo allocatorInfo = {}; allocatorInfo.physicalDevice = pdev; allocatorInfo.device = dev; + allocatorInfo.instance = inst; + allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_0; std::vector heap_limits; const auto vram_allocation_limit = g_cfg.video.vk.vram_allocation_limit * 0x100000ull; @@ -299,7 +301,7 @@ namespace vk f32 mem_allocator_vma::get_memory_usage() { - vmaGetBudget(m_allocator, stats.data()); + vmaGetHeapBudgets(m_allocator, stats.data()); float max_usage = 0.f; for (const auto& info : stats) diff --git a/rpcs3/Emu/RSX/VK/vkutils/memory.h b/rpcs3/Emu/RSX/VK/vkutils/memory.h index 9ab7d44f88..0b4186666d 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/memory.h +++ b/rpcs3/Emu/RSX/VK/vkutils/memory.h @@ -4,7 +4,15 @@ #include "../../rsx_utils.h" #include "shared.h" -#include "3rdparty/GPUOpen/VulkanMemoryAllocator/src/vk_mem_alloc.h" +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullability-completeness" +#endif +#define VMA_VULKAN_VERSION 1000000 +#include "3rdparty/GPUOpen/VulkanMemoryAllocator/include/vk_mem_alloc.h" +#ifdef __clang__ +#pragma clang diagnostic pop +#endif namespace vk { @@ -55,7 +63,7 @@ namespace vk public: using mem_handle_t = void*; - mem_allocator_base(const vk::render_device& dev, VkPhysicalDevice /*pdev*/); + mem_allocator_base(const vk::render_device& dev, VkPhysicalDevice pdev); virtual ~mem_allocator_base() = default; virtual void destroy() = 0; @@ -83,7 +91,7 @@ namespace vk class mem_allocator_vma : public mem_allocator_base { public: - mem_allocator_vma(const vk::render_device& dev, VkPhysicalDevice pdev); + mem_allocator_vma(const vk::render_device& dev, VkPhysicalDevice pdev, VkInstance inst); ~mem_allocator_vma() override = default; void destroy() override; diff --git a/rpcs3/Emu/RSX/rsx_methods.h b/rpcs3/Emu/RSX/rsx_methods.h index dbcb8bb15d..60be7ec14e 100644 --- a/rpcs3/Emu/RSX/rsx_methods.h +++ b/rpcs3/Emu/RSX/rsx_methods.h @@ -705,6 +705,11 @@ namespace rsx return decode().clip_plane5(); } + u32 clip_planes_mask() const + { + return registers[NV4097_SET_USER_CLIP_PLANE_CONTROL]; + } + front_face front_face_mode() const { return decode().front_face_mode(); diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 3fdcfae9ab..002075b5fa 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -185,13 +185,13 @@ void Emulator::CallFromMainThread(std::function&& func, atomic_t* w m_cb.call_from_main_thread(std::move(final_func), wake_up); } -void Emulator::BlockingCallFromMainThread(std::function&& func, std::source_location src_loc) const +void Emulator::BlockingCallFromMainThread(std::function&& func, bool track_emu_state, std::source_location src_loc) const { atomic_t wake_up = 0; sys_log.trace("Blocking Callback from thread '%s' at [%s] is queued", thread_ctrl::get_name(), src_loc); - CallFromMainThread(std::move(func), &wake_up, true, umax, src_loc); + CallFromMainThread(std::move(func), &wake_up, track_emu_state, umax, src_loc); bool logged = false; diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 036215870f..417bef41b8 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -210,7 +210,7 @@ public: std::source_location src_loc = std::source_location::current()) const; // Blocking call from the GUI thread - void BlockingCallFromMainThread(std::function&& func, std::source_location src_loc = std::source_location::current()) const; + void BlockingCallFromMainThread(std::function&& func, bool track_emu_state = true, std::source_location src_loc = std::source_location::current()) const; enum class stop_counter_t : u64{}; diff --git a/rpcs3/Input/ds4_pad_handler.cpp b/rpcs3/Input/ds4_pad_handler.cpp index 5ad4f8f3af..3ab7edc648 100644 --- a/rpcs3/Input/ds4_pad_handler.cpp +++ b/rpcs3/Input/ds4_pad_handler.cpp @@ -646,7 +646,7 @@ int ds4_pad_handler::send_output_report(DS4Device* device) const auto config = device->config; if (config == nullptr) - return -2; // hid_write and hid_write_control return -1 on error + return -2; // hid_write returns -1 on error // write rumble state ds4_output_report_common common{}; diff --git a/rpcs3/Input/sdl_instance.cpp b/rpcs3/Input/sdl_instance.cpp index e27ed5f8ac..879333b513 100644 --- a/rpcs3/Input/sdl_instance.cpp +++ b/rpcs3/Input/sdl_instance.cpp @@ -1,6 +1,8 @@ #ifdef HAVE_SDL3 #include "stdafx.h" +#include "sdl_instance.h" +#include "Emu/System.h" #ifndef _MSC_VER #pragma GCC diagnostic push @@ -11,10 +13,6 @@ #pragma GCC diagnostic pop #endif -#include "util/logs.hpp" - -#include "sdl_instance.h" - LOG_CHANNEL(sdl_log, "SDL"); sdl_instance::~sdl_instance() @@ -35,9 +33,12 @@ sdl_instance& sdl_instance::get_instance() void sdl_instance::pump_events() { - const std::lock_guard lock(m_instance_mutex); + std::lock_guard lock(m_instance_mutex); + if (m_initialized) + { SDL_PumpEvents(); + } } void sdl_instance::set_hint(const char* name, const char* value) @@ -50,7 +51,25 @@ void sdl_instance::set_hint(const char* name, const char* value) bool sdl_instance::initialize() { - const std::lock_guard lock(m_instance_mutex); + std::lock_guard lock(m_instance_mutex); + + if (m_initialized) + { + return true; + } + + bool instance_success = false; + + Emu.BlockingCallFromMainThread([this, &instance_success]() + { + instance_success = initialize_impl(); + }, false); + + return instance_success; +} + +bool sdl_instance::initialize_impl() +{ // Only init SDL once. SDL uses a global state internally... if (m_initialized) { diff --git a/rpcs3/Input/sdl_instance.h b/rpcs3/Input/sdl_instance.h index 9463b36900..23fc1b6d59 100644 --- a/rpcs3/Input/sdl_instance.h +++ b/rpcs3/Input/sdl_instance.h @@ -8,7 +8,7 @@ struct sdl_instance { public: sdl_instance() = default; - ~sdl_instance(); + virtual ~sdl_instance(); static sdl_instance& get_instance(); @@ -17,6 +17,7 @@ public: private: void set_hint(const char* name, const char* value); + bool initialize_impl(); bool m_initialized = false; std::mutex m_instance_mutex; diff --git a/rpcs3/Input/sdl_pad_handler.cpp b/rpcs3/Input/sdl_pad_handler.cpp index 21a59cba2c..ef73c81a20 100644 --- a/rpcs3/Input/sdl_pad_handler.cpp +++ b/rpcs3/Input/sdl_pad_handler.cpp @@ -2,10 +2,10 @@ #include "stdafx.h" #include "sdl_pad_handler.h" +#include "sdl_instance.h" #include "Emu/system_utils.hpp" #include "Emu/system_config.h" #include "Emu/System.h" -#include "sdl_instance.h" #include @@ -180,14 +180,7 @@ bool sdl_pad_handler::Init() if (m_is_init) return true; - bool instance_success; - - Emu.BlockingCallFromMainThread([&instance_success]() - { - instance_success = sdl_instance::get_instance().initialize(); - }); - - if (!instance_success) + if (!sdl_instance::get_instance().initialize()) return false; if (g_cfg.io.load_sdl_mappings) @@ -301,7 +294,7 @@ SDLDevice::sdl_info sdl_pad_handler::get_sdl_info(SDL_JoystickID id) } } - sdl_log.error("Found game pad %d: type=%d, real_type=%d, name='%s', guid='%s', path='%s', serial='%s', vid=0x%x, pid=0x%x, product_version=0x%x, firmware_version=0x%x, has_led=%d, has_player_led=%d, has_mono_led=%d, has_rumble=%d, has_rumble_triggers=%d, has_accel=%d, has_gyro=%d", + sdl_log.notice("Found game pad %d: type=%d, real_type=%d, name='%s', guid='%s', path='%s', serial='%s', vid=0x%x, pid=0x%x, product_version=0x%x, firmware_version=0x%x, has_led=%d, has_player_led=%d, has_mono_led=%d, has_rumble=%d, has_rumble_triggers=%d, has_accel=%d, has_gyro=%d", id, static_cast(info.type), static_cast(info.real_type), info.name, info.guid, info.path, info.serial, info.vid, info.pid, info.product_version, info.firmware_version, info.has_led, info.has_player_led, info.has_mono_led, info.has_rumble, info.has_rumble_triggers, info.has_accel, info.has_gyro); if (info.has_accel) 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/emulated_logitech_g27_settings_dialog.cpp b/rpcs3/rpcs3qt/emulated_logitech_g27_settings_dialog.cpp index 4ee3ca3e93..a65f62648b 100644 --- a/rpcs3/rpcs3qt/emulated_logitech_g27_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/emulated_logitech_g27_settings_dialog.cpp @@ -68,6 +68,7 @@ enum class mapping_device SHIFTER_5, SHIFTER_6, SHIFTER_R, + SHIFTER_PRESS, // Enum count COUNT @@ -109,6 +110,7 @@ QString device_name(mapping_device dev) case mapping_device::SHIFTER_5: return QObject::tr("Gear 5"); case mapping_device::SHIFTER_6: return QObject::tr("Gear 6"); case mapping_device::SHIFTER_R: return QObject::tr("Gear R"); + case mapping_device::SHIFTER_PRESS: return QObject::tr("Shifter press"); case mapping_device::COUNT: return ""; } return ""; @@ -151,6 +153,7 @@ emulated_logitech_g27_mapping& device_cfg(mapping_device dev) case mapping_device::SHIFTER_5: return cfg.shifter_5; case mapping_device::SHIFTER_6: return cfg.shifter_6; case mapping_device::SHIFTER_R: return cfg.shifter_r; + case mapping_device::SHIFTER_PRESS: return cfg.shifter_press; default: fmt::throw_exception("Unexpected mapping_device %d", static_cast(dev)); } } diff --git a/rpcs3/rpcs3qt/rsx_debugger.cpp b/rpcs3/rpcs3qt/rsx_debugger.cpp index 809ce37525..bdea183d2e 100644 --- a/rpcs3/rpcs3qt/rsx_debugger.cpp +++ b/rpcs3/rpcs3qt/rsx_debugger.cpp @@ -4,6 +4,8 @@ #include "table_item_delegate.h" #include "Emu/RSX/RSXThread.h" #include "Emu/RSX/gcm_printing.h" +#include "Emu/RSX/Common/BufferUtils.h" +#include "Emu/RSX/Program/CgBinaryProgram.h" #include "Utilities/File.h" #include @@ -123,17 +125,6 @@ rsx_debugger::rsx_debugger(std::shared_ptr gui_settings, QWidget* vbox_tools->addLayout(hbox_controls); vbox_tools->addWidget(m_tw_rsx); - // State explorer - m_text_transform_program = new QLabel(); - m_text_transform_program->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); - m_text_transform_program->setFont(mono); - m_text_transform_program->setText(""); - - m_text_shader_program = new QLabel(); - m_text_shader_program->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); - m_text_shader_program->setFont(mono); - m_text_shader_program->setText(""); - m_list_index_buffer = new QListWidget(); m_list_index_buffer->setFont(mono); @@ -208,11 +199,31 @@ rsx_debugger::rsx_debugger(std::shared_ptr gui_settings, QWidget* QWidget* buffers = new QWidget(); buffers->setLayout(buffer_layout); + auto xp_layout = new QHBoxLayout(); + m_transform_disasm = new QTextEdit(this); + m_transform_disasm->setReadOnly(true); + m_transform_disasm->setWordWrapMode(QTextOption::NoWrap); + m_transform_disasm->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); + xp_layout->addWidget(m_transform_disasm); + + auto xp_tab = new QWidget(); + xp_tab->setLayout(xp_layout); + + auto fp_layout = new QHBoxLayout(); + m_fragment_disasm = new QTextEdit(this); + m_fragment_disasm->setReadOnly(true); + m_fragment_disasm->setWordWrapMode(QTextOption::NoWrap); + m_fragment_disasm->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); + fp_layout->addWidget(m_fragment_disasm); + + auto fp_tab = new QWidget(); + fp_tab->setLayout(fp_layout); + QTabWidget* state_rsx = new QTabWidget(); state_rsx->addTab(buffers, tr("RTTs and DS")); - state_rsx->addTab(m_text_transform_program, tr("Transform program")); - state_rsx->addTab(m_text_shader_program, tr("Shader program")); - state_rsx->addTab(m_list_index_buffer, tr("Index buffer")); + state_rsx->addTab(xp_tab, tr("Vertex Program")); + state_rsx->addTab(fp_tab, tr("Fragment Program")); + state_rsx->addTab(m_list_index_buffer, tr("Index Buffer")); QHBoxLayout* main_layout = new QHBoxLayout(); main_layout->addLayout(vbox_tools, 1); @@ -592,10 +603,10 @@ void rsx_debugger::OnClickDrawCalls() } // Programs - m_text_transform_program->clear(); - m_text_transform_program->setText(qstr(frame_debug.draw_calls[draw_id].programs.first)); - m_text_shader_program->clear(); - m_text_shader_program->setText(qstr(frame_debug.draw_calls[draw_id].programs.second)); + m_transform_disasm->clear(); + m_transform_disasm->setText(qstr(frame_debug.draw_calls[draw_id].programs.first)); + m_fragment_disasm->clear(); + m_fragment_disasm->setText(qstr(frame_debug.draw_calls[draw_id].programs.second)); m_list_index_buffer->clear(); //m_list_index_buffer->insertColumn(0, "Index", 0, 700); @@ -621,6 +632,8 @@ void rsx_debugger::UpdateInformation() const { GetMemory(); GetBuffers(); + GetVertexProgram(); + GetFragmentProgram(); } void rsx_debugger::GetMemory() const @@ -1202,3 +1215,111 @@ void rsx_debugger::GetBuffers() const m_buffer_tex->showImage(QImage(m_buffer_tex->cache.data(), width, height, QImage::Format_RGB32)); } + +void rsx_debugger::GetVertexProgram() const +{ + const auto render = rsx::get_current_renderer(); + if (!render || !render->is_initialized || !render->local_mem_size || !render->is_paused()) + { + return; + } + + RSXVertexProgram vp; + vp.data.reserve(512 * 4); + + const u32 vp_entry = rsx::method_registers.transform_program_start(); + 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 + ); + + const u32 ucode_len = static_cast(vp.data.size() * sizeof(u32)); + std::vector vp_blob = { + 7003u, // Type + 6u, // Revision + 56u + ucode_len, // Total size + 0, // paramCount + 0, // paramArray + 32u, // Program header offset + ucode_len, // Ucode length + 56u, // Ucode start + + ::size32(vp.data) / 4, // Instruction count + 0, // Slot + 16u, // Registers used + rsx::method_registers.vertex_attrib_input_mask(), + rsx::method_registers.vertex_attrib_output_mask(), + rsx::method_registers.clip_planes_mask() + }; + + vp_blob.resize(vp_blob.size() + vp.data.size()); + std::copy(vp.data.begin(), vp.data.end(), vp_blob.begin() + 14); + + std::span vp_binary(vp_blob); + CgBinaryDisasm vp_disasm(vp_binary); + vp_disasm.BuildShaderBody(false); + + m_transform_disasm->clear(); + m_transform_disasm->setText(QString::fromStdString(vp_disasm.GetArbShader())); +} + +void rsx_debugger::GetFragmentProgram() const +{ + const auto render = rsx::get_current_renderer(); + if (!render || !render->is_initialized || !render->local_mem_size || !render->is_paused()) + { + return; + } + + const auto [program_offset, program_location] = rsx::method_registers.shader_program_address(); + const auto address = rsx::get_address(program_offset, program_location, 4); + if (!address) + { + m_fragment_disasm->clear(); + return; + } + + // NOTE: Reading through super ptr while crash-safe means we're probably reading incorrect bytes, but should be fine in 99% of cases + auto data_ptr = vm::get_super_ptr(address); + const auto fp_metadata = program_hash_util::fragment_program_utils::analyse_fragment_program(data_ptr); + + const bool output_h0 = rsx::method_registers.shader_control() & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? false : true; + const bool depth_replace = rsx::method_registers.shader_control() & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT ? true : false; + const u32 flags = 16u /* Reg count */ | ((output_h0 /* 16-bit exports? */ ? 1u : 0u) << 8u) | ((depth_replace /* Export depth? */ ? 1u : 0u) << 16u) | (0u /* Uses KILL? */ << 24u); + const auto ucode_len = fp_metadata.program_ucode_length; + + std::vector blob = { + 7004u, // Type + 6u, // Revision + 56u + ucode_len, // Total size + 0, // paramCount + 0, // paramArray + 32u, // Program header offset + ucode_len, // Ucode length + 56u, // Ucode start + + ucode_len / 16, // Instruction count + rsx::method_registers.vertex_attrib_output_mask(), // Slot + 0u, // Partial load + 0u | (rsx::method_registers.texcoord_control_mask() << 16u), // Texcoord input mask | tex2d control + 0u | (flags << 16u), // Centroid inputs (xor tex2d control) | flags (regs, 16-bit, fragDepth, KILL) + + 0u, // Padding + }; + + // Copy in the program bytes, swapped + const u32 start_offset_in_words = fp_metadata.program_start_offset / 4; + const u32 ucode_length_in_words = fp_metadata.program_ucode_length / 4; + blob.resize(blob.size() + ucode_length_in_words); + copy_data_swap_u32(blob.data() + 14, utils::bless(data_ptr) + start_offset_in_words, ucode_length_in_words); + //std::memcpy(blob.data() + 14, utils::bless(data_ptr) + fp_metadata.program_start_offset, fp_metadata.program_ucode_length); + + std::span fp_binary(blob); + CgBinaryDisasm fp_disasm(fp_binary); + fp_disasm.BuildShaderBody(false); + + m_fragment_disasm->clear(); + m_fragment_disasm->setText(QString::fromStdString(fp_disasm.GetArbShader())); +} diff --git a/rpcs3/rpcs3qt/rsx_debugger.h b/rpcs3/rpcs3qt/rsx_debugger.h index 95ac67ddcd..2c189c3e8a 100644 --- a/rpcs3/rpcs3qt/rsx_debugger.h +++ b/rpcs3/rpcs3qt/rsx_debugger.h @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -61,8 +62,8 @@ class rsx_debugger : public QDialog Buffer* m_buffer_tex; QLabel* m_enabled_textures_label; - QLabel* m_text_transform_program; - QLabel* m_text_shader_program; + QTextEdit* m_transform_disasm; + QTextEdit* m_fragment_disasm; u32 m_cur_texture = 0; u32 m_texture_format_override = 0; @@ -87,4 +88,7 @@ protected: private: void PerformJump(u32 address); + + void GetVertexProgram() const; + void GetFragmentProgram() const; };