diff --git a/CMakeLists.txt b/CMakeLists.txt index 099ad0be0..081b61112 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -227,6 +227,8 @@ find_package(fmt 10.2.0 CONFIG) find_package(glslang 15 CONFIG) find_package(half 1.12.0 MODULE) find_package(magic_enum 0.9.7 CONFIG) +find_package(miniz 3.1 CONFIG) +find_package(nlohmann_json 3.12 CONFIG) find_package(PNG 1.6 MODULE) find_package(OpenAL CONFIG) find_package(RenderDoc 1.6.0 MODULE) @@ -1120,7 +1122,7 @@ create_target_directory_groups(shadps4) target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half ZLIB::ZLIB PNG::PNG) target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 SDL3_mixer::SDL3_mixer pugixml::pugixml) -target_link_libraries(shadps4 PRIVATE stb::headers libusb::usb lfreist-hwinfo::hwinfo nlohmann_json::nlohmann_json miniz fdk-aac CLI11::CLI11 OpenAL::OpenAL Cpp_Httplib) +target_link_libraries(shadps4 PRIVATE stb::headers libusb::usb lfreist-hwinfo::hwinfo nlohmann_json::nlohmann_json miniz::miniz fdk-aac CLI11::CLI11 OpenAL::OpenAL Cpp_Httplib) target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h") target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h") diff --git a/documents/Debugging/Debugging.md b/documents/Debugging/Debugging.md index 8bb4b8fbd..013ca15fb 100644 --- a/documents/Debugging/Debugging.md +++ b/documents/Debugging/Debugging.md @@ -73,6 +73,8 @@ You can configure the emulator by editing the `config.toml` file found in the `u - Examples: - If the log is being spammed with messages coming from Lib.Pad, you can use `Lib.Pad:Critical` to only log critical-level messages. - If you'd like to mute everything, but still want to receive messages from Vulkan rendering: `*:Critical Render.Vulkan:Info` + - `isIdenticalLogGrouped`: Group same logs in one line with a counter (`true`/`false`) + - By default, the emulator will not rewrite the same line, and instead add a counter. - `Fullscreen`: Display the game in a full screen borderless window. diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 7f6e6ec4e..41a0f71c7 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -259,16 +259,19 @@ if (WIN32) add_subdirectory(ext-wepoll) endif() -if (NOT TARGET fdk-aac) add_subdirectory(aacdec) -endif() #nlohmann json +if (NOT TARGET nlohmann_json::nlohmann_json) set(JSON_BuildTests OFF CACHE INTERNAL "") add_subdirectory(json) +endif() # miniz +if (NOT TARGET miniz::miniz) add_subdirectory(miniz) +add_library(miniz::miniz ALIAS miniz) +endif() # cli11 if (NOT TARGET CLI11::CLI11) diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 0abc831fc..048f27314 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -211,41 +211,62 @@ public: } } - std::unique_lock entry_loc(_mutex); - - if (_last_entry.message == message) { - ++_last_entry.counter; - return; - } - - if (_last_entry.counter >= 2) { - _last_entry.message += " x" + std::to_string(_last_entry.counter); - } - - if (_last_entry.counter >= 1) { - if (EmulatorSettings::GetInstance()->GetLogType() == "async") { - message_queue.EmplaceWait(_last_entry); - } else { - ForEachBackend([this](auto& backend) { backend.Write(this->_last_entry); }); - std::fflush(stdout); - } - } - using std::chrono::duration_cast; using std::chrono::microseconds; using std::chrono::steady_clock; - this->_last_entry = { - .timestamp = duration_cast(steady_clock::now() - time_origin), - .log_class = log_class, - .log_level = log_level, - .filename = filename, - .line_num = line_num, - .function = function, - .message = message, - .thread = Common::GetCurrentThreadName(), - .counter = 1, - }; + if (Config::groupIdenticalLogs()) { + std::unique_lock entry_loc(_mutex); + + if (_last_entry.message == message) { + ++_last_entry.counter; + return; + } + + if (_last_entry.counter >= 2) { + _last_entry.message += " x" + std::to_string(_last_entry.counter); + } + + if (_last_entry.counter >= 1) { + if (Config::getLogType() == "async") { + message_queue.EmplaceWait(_last_entry); + } else { + ForEachBackend([this](auto& backend) { backend.Write(this->_last_entry); }); + std::fflush(stdout); + } + } + + this->_last_entry = { + .timestamp = duration_cast(steady_clock::now() - time_origin), + .log_class = log_class, + .log_level = log_level, + .filename = filename, + .line_num = line_num, + .function = function, + .message = message, + .thread = Common::GetCurrentThreadName(), + .counter = 1, + }; + } else { + const Entry entry = { + .timestamp = duration_cast(steady_clock::now() - time_origin), + .log_class = log_class, + .log_level = log_level, + .filename = filename, + .line_num = line_num, + .function = function, + .message = message, + .thread = Common::GetCurrentThreadName(), + .counter = 1, + }; + + if (Config::getLogType() == "async") { + message_queue.EmplaceWait(entry); + } else { + ForEachBackend([&entry](auto& backend) { backend.Write(entry); }); + std::fflush(stdout); + } + } } private: @@ -277,21 +298,23 @@ private: } void StopBackendThread() { - // log last message - if (_last_entry.counter >= 2) { - _last_entry.message += " x" + std::to_string(_last_entry.counter); - } - - if (_last_entry.counter >= 1) { - if (EmulatorSettings::GetInstance()->GetLogType() == "async") { - message_queue.EmplaceWait(_last_entry); - } else { - ForEachBackend([this](auto& backend) { backend.Write(this->_last_entry); }); - std::fflush(stdout); + if (Config::groupIdenticalLogs()) { + // log last message + if (_last_entry.counter >= 2) { + _last_entry.message += " x" + std::to_string(_last_entry.counter); } - } - this->_last_entry = {}; + if (_last_entry.counter >= 1) { + if (Config::getLogType() == "async") { + message_queue.EmplaceWait(_last_entry); + } else { + ForEachBackend([this](auto& backend) { backend.Write(this->_last_entry); }); + std::fflush(stdout); + } + } + + this->_last_entry = {}; + } backend_thread.request_stop(); if (backend_thread.joinable()) { diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp index 0ecd0bb1a..c5b18fd90 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.cpp +++ b/src/core/libraries/gnmdriver/gnmdriver.cpp @@ -2053,7 +2053,7 @@ int PS4_SYSV_ABI sceGnmSqttWaitForEvent() { } static inline s32 PatchFlipRequest(u32* cmdbuf, u32 size, u32 vo_handle, u32 buf_idx, u32 flip_mode, - u32 flip_arg, void* unk) { + s64 flip_arg, void* unk) { // check for `prepareFlip` packet cmdbuf += size - 64; ASSERT_MSG(cmdbuf[0] == 0xc03e1000, "Can't find `prepareFlip` packet"); @@ -2139,7 +2139,7 @@ static inline s32 PatchFlipRequest(u32* cmdbuf, u32 size, u32 vo_handle, u32 buf s32 PS4_SYSV_ABI sceGnmSubmitAndFlipCommandBuffers(u32 count, u32* dcb_gpu_addrs[], u32* dcb_sizes_in_bytes, u32* ccb_gpu_addrs[], u32* ccb_sizes_in_bytes, u32 vo_handle, - u32 buf_idx, u32 flip_mode, u32 flip_arg) { + u32 buf_idx, u32 flip_mode, s64 flip_arg) { return sceGnmSubmitAndFlipCommandBuffersForWorkload( count, count, dcb_gpu_addrs, dcb_sizes_in_bytes, ccb_gpu_addrs, ccb_sizes_in_bytes, vo_handle, buf_idx, flip_mode, flip_arg); @@ -2147,7 +2147,7 @@ s32 PS4_SYSV_ABI sceGnmSubmitAndFlipCommandBuffers(u32 count, u32* dcb_gpu_addrs s32 PS4_SYSV_ABI sceGnmSubmitAndFlipCommandBuffersForWorkload( u32 workload, u32 count, u32* dcb_gpu_addrs[], u32* dcb_sizes_in_bytes, u32* ccb_gpu_addrs[], - u32* ccb_sizes_in_bytes, u32 vo_handle, u32 buf_idx, u32 flip_mode, u32 flip_arg) { + u32* ccb_sizes_in_bytes, u32 vo_handle, u32 buf_idx, u32 flip_mode, s64 flip_arg) { LOG_DEBUG(Lib_GnmDriver, "called [buf = {}]", buf_idx); auto* cmdbuf = dcb_gpu_addrs[count - 1]; diff --git a/src/core/libraries/gnmdriver/gnmdriver.h b/src/core/libraries/gnmdriver/gnmdriver.h index 4001f4661..5f3462dd9 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.h +++ b/src/core/libraries/gnmdriver/gnmdriver.h @@ -211,10 +211,10 @@ int PS4_SYSV_ABI sceGnmSqttWaitForEvent(); s32 PS4_SYSV_ABI sceGnmSubmitAndFlipCommandBuffers(u32 count, u32* dcb_gpu_addrs[], u32* dcb_sizes_in_bytes, u32* ccb_gpu_addrs[], u32* ccb_sizes_in_bytes, u32 vo_handle, - u32 buf_idx, u32 flip_mode, u32 flip_arg); + u32 buf_idx, u32 flip_mode, s64 flip_arg); int PS4_SYSV_ABI sceGnmSubmitAndFlipCommandBuffersForWorkload( u32 workload, u32 count, u32* dcb_gpu_addrs[], u32* dcb_sizes_in_bytes, u32* ccb_gpu_addrs[], - u32* ccb_sizes_in_bytes, u32 vo_handle, u32 buf_idx, u32 flip_mode, u32 flip_arg); + u32* ccb_sizes_in_bytes, u32 vo_handle, u32 buf_idx, u32 flip_mode, s64 flip_arg); s32 PS4_SYSV_ABI sceGnmSubmitCommandBuffers(u32 count, const u32* dcb_gpu_addrs[], u32* dcb_sizes_in_bytes, const u32* ccb_gpu_addrs[], u32* ccb_sizes_in_bytes); diff --git a/src/core/libraries/kernel/equeue.cpp b/src/core/libraries/kernel/equeue.cpp index 2190f2533..72e38b265 100644 --- a/src/core/libraries/kernel/equeue.cpp +++ b/src/core/libraries/kernel/equeue.cpp @@ -32,6 +32,14 @@ bool EqueueInternal::AddEvent(EqueueEvent& event) { event.timer_interval = std::chrono::microseconds(event.event.data - offset); } + // Remove add flag from event + event.event.flags &= ~SceKernelEvent::Flags::Add; + + // Clear flag is appended to most event types internally. + if (event.event.filter != SceKernelEvent::Filter::User) { + event.event.flags |= SceKernelEvent::Flags::Clear; + } + const auto& it = std::ranges::find(m_events, event); if (it != m_events.cend()) { *it = std::move(event); @@ -165,10 +173,6 @@ int EqueueInternal::GetTriggeredEvents(SceKernelEvent* ev, int num) { for (auto it = m_events.begin(); it != m_events.end();) { if (it->IsTriggered()) { ev[count++] = it->event; - - // Event should not trigger again - it->ResetTriggerState(); - if (it->event.flags & SceKernelEvent::Flags::Clear) { it->Clear(); } diff --git a/src/core/libraries/kernel/equeue.h b/src/core/libraries/kernel/equeue.h index e933f80d1..06b667008 100644 --- a/src/core/libraries/kernel/equeue.h +++ b/src/core/libraries/kernel/equeue.h @@ -84,11 +84,8 @@ struct EqueueEvent { std::chrono::microseconds timer_interval; std::unique_ptr timer; - void ResetTriggerState() { - is_triggered = false; - } - void Clear() { + is_triggered = false; event.fflags = 0; event.data = 0; } @@ -101,14 +98,13 @@ struct EqueueEvent { void TriggerUser(void* data) { is_triggered = true; - event.fflags++; event.udata = data; } void TriggerDisplay(void* data) { is_triggered = true; if (data != nullptr) { - auto event_data = static_cast(event.data); + auto event_data = std::bit_cast(event.data); auto event_hint_raw = reinterpret_cast(data); auto event_hint = static_cast(event_hint_raw); if (event_hint.event_id == event.ident && event.ident != 0xfe) { diff --git a/src/core/libraries/videoout/video_out.cpp b/src/core/libraries/videoout/video_out.cpp index ab697592a..7817c7770 100644 --- a/src/core/libraries/videoout/video_out.cpp +++ b/src/core/libraries/videoout/video_out.cpp @@ -218,7 +218,7 @@ s32 PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, s64* } auto event_data = ev->data >> 0x10; - if (ev->ident != static_cast(OrbisVideoOutInternalEventId::Flip) || ev->data == 0) { + if (ev->ident != static_cast(OrbisVideoOutInternalEventId::Flip) || ev->data >= 0) { *data = event_data; } else { *data = event_data | 0xffff000000000000; @@ -339,7 +339,7 @@ s32 PS4_SYSV_ABI sceVideoOutGetBufferLabelAddress(s32 handle, uintptr_t* label_a return 16; } -s32 sceVideoOutSubmitEopFlip(s32 handle, u32 buf_id, u32 mode, u32 arg, void** unk) { +s32 sceVideoOutSubmitEopFlip(s32 handle, u32 buf_id, u32 mode, s64 flip_arg, void** unk) { auto* port = driver->GetPort(handle); if (!port) { return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE; @@ -349,7 +349,7 @@ s32 sceVideoOutSubmitEopFlip(s32 handle, u32 buf_id, u32 mode, u32 arg, void** u Platform::InterruptId::GfxFlip, [=](Platform::InterruptId irq) { ASSERT_MSG(irq == Platform::InterruptId::GfxFlip, "An unexpected IRQ occured"); ASSERT_MSG(port->buffer_labels[buf_id] == 1, "Out of order flip IRQ"); - const auto result = driver->SubmitFlip(port, buf_id, arg, true); + const auto result = driver->SubmitFlip(port, buf_id, flip_arg, true); ASSERT_MSG(result, "EOP flip submission failed"); }); diff --git a/src/core/libraries/videoout/video_out.h b/src/core/libraries/videoout/video_out.h index ba2732ff7..2c99a4d1c 100644 --- a/src/core/libraries/videoout/video_out.h +++ b/src/core/libraries/videoout/video_out.h @@ -139,7 +139,7 @@ s32 PS4_SYSV_ABI sceVideoOutColorSettingsSetGamma(SceVideoOutColorSettings* sett s32 PS4_SYSV_ABI sceVideoOutAdjustColor(s32 handle, const SceVideoOutColorSettings* settings); // Internal system functions -s32 sceVideoOutSubmitEopFlip(s32 handle, u32 buf_id, u32 mode, u32 arg, void** unk); +s32 sceVideoOutSubmitEopFlip(s32 handle, u32 buf_id, u32 mode, s64 flip_arg, void** unk); void RegisterLib(Core::Loader::SymbolsResolver* sym); diff --git a/src/core/tls.h b/src/core/tls.h index 83940be7a..27de518ea 100644 --- a/src/core/tls.h +++ b/src/core/tls.h @@ -61,7 +61,10 @@ template ReturnType ExecuteGuest(PS4_SYSV_ABI ReturnType (*func)(FuncArgs...), CallArgs&&... args) { EnsureThreadInitialized(); // clear stack to avoid trash from EnsureThreadInitialized - ClearStack<12_KB>(); + auto* tcb = GetTcbBase(); + if (tcb != nullptr && tcb->tcb_fiber == nullptr) { + ClearStack<12_KB>(); + } return func(std::forward(args)...); } diff --git a/src/emulator.cpp b/src/emulator.cpp index 3d4f4980e..341718ece 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -240,6 +240,7 @@ void Emulator::Run(std::filesystem::path file, std::vector args, LOG_INFO(Config, "Game-specific config exists: {}", has_game_config); LOG_INFO(Config, "General LogType: {}", EmulatorSettings::GetInstance()->GetLogType()); + LOG_INFO(Config, "General isIdenticalLogGrouped: {}", Config::groupIdenticalLogs()); LOG_INFO(Config, "General isNeo: {}", EmulatorSettings::GetInstance()->IsNeo()); LOG_INFO(Config, "General isDevKit: {}", EmulatorSettings::GetInstance()->IsDevKit()); LOG_INFO(Config, "General isConnectedToNetwork: {}",