From b362a55c04fe46b89de8e586dafd1a2c467ad828 Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Fri, 3 Sep 2021 11:11:46 +0200 Subject: [PATCH] ggpo: rollback glitches. win32 init. switch build. stats Block net rollbacks until the current frame has been processed to avoid glitched textures. Call WSAStartup at init on windows Display net stats when in game Switch build fix --- core/deps/ggpo/include/ggponet.h | 3 ++ core/deps/ggpo/lib/ggpo/backends/p2p.cpp | 1 + core/deps/ggpo/lib/ggpo/main.cpp | 4 ++ core/deps/ggpo/lib/ggpo/platform_linux.h | 4 ++ core/deps/ggpo/lib/ggpo/sync.h | 1 + core/hw/pvr/Renderer_if.cpp | 18 +++++++ core/hw/pvr/Renderer_if.h | 3 ++ core/hw/pvr/ta_ctx.cpp | 4 +- core/network/ggpo.cpp | 62 ++++++++++++++++++++++++ core/network/ggpo.h | 1 + core/rend/gui.cpp | 3 +- 11 files changed, 102 insertions(+), 2 deletions(-) diff --git a/core/deps/ggpo/include/ggponet.h b/core/deps/ggpo/include/ggponet.h index d25516d4d..bd82894ce 100644 --- a/core/deps/ggpo/include/ggponet.h +++ b/core/deps/ggpo/include/ggponet.h @@ -303,6 +303,9 @@ typedef struct GGPONetworkStats { int local_frames_behind; int remote_frames_behind; } timesync; + struct { + int predicted_frames; + } sync; } GGPONetworkStats; /* diff --git a/core/deps/ggpo/lib/ggpo/backends/p2p.cpp b/core/deps/ggpo/lib/ggpo/backends/p2p.cpp index c1c71b3b2..8c366d2cd 100644 --- a/core/deps/ggpo/lib/ggpo/backends/p2p.cpp +++ b/core/deps/ggpo/lib/ggpo/backends/p2p.cpp @@ -529,6 +529,7 @@ Peer2PeerBackend::GetNetworkStats(GGPONetworkStats *stats, GGPOPlayerHandle play memset(stats, 0, sizeof *stats); _endpoints[queue].GetNetworkStats(stats); + stats->sync.predicted_frames = _sync.GetPredictedFrames(); return GGPO_OK; } diff --git a/core/deps/ggpo/lib/ggpo/main.cpp b/core/deps/ggpo/lib/ggpo/main.cpp index 4da54c7e6..88dd4fa7e 100644 --- a/core/deps/ggpo/lib/ggpo/main.cpp +++ b/core/deps/ggpo/lib/ggpo/main.cpp @@ -15,6 +15,10 @@ struct Init { Init() { srand(Platform::GetCurrentTimeMS() + Platform::GetProcessID()); +#ifdef _WIN32 + WSADATA wsaData; + WSAStartup(MAKEWORD(2, 0), &wsaData); +#endif } }; static Init init; diff --git a/core/deps/ggpo/lib/ggpo/platform_linux.h b/core/deps/ggpo/lib/ggpo/platform_linux.h index 9d1c517c8..426b5b473 100644 --- a/core/deps/ggpo/lib/ggpo/platform_linux.h +++ b/core/deps/ggpo/lib/ggpo/platform_linux.h @@ -21,7 +21,11 @@ #include #include #include +#ifdef __SWITCH__ +#include "nswitch.h" +#else #include +#endif #include #include diff --git a/core/deps/ggpo/lib/ggpo/sync.h b/core/deps/ggpo/lib/ggpo/sync.h index 465ee248b..f9523cbd0 100644 --- a/core/deps/ggpo/lib/ggpo/sync.h +++ b/core/deps/ggpo/lib/ggpo/sync.h @@ -57,6 +57,7 @@ public: int GetFrameCount() { return _framecount; } bool InRollback() { return _rollingback; } + int GetPredictedFrames() { return _framecount - _last_confirmed_frame; } bool GetEvent(Event &e); diff --git a/core/hw/pvr/Renderer_if.cpp b/core/hw/pvr/Renderer_if.cpp index af4196da8..12ef4e2fb 100644 --- a/core/hw/pvr/Renderer_if.cpp +++ b/core/hw/pvr/Renderer_if.cpp @@ -27,6 +27,7 @@ cResetEvent rs, re; static bool do_swap; std::mutex swap_mutex; u32 fb_w_cur = 1; +static cResetEvent vramRollback; // direct framebuffer write detection static bool render_called = false; @@ -197,6 +198,7 @@ static bool rend_frame(TA_context* ctx) if (!proc || (!ctx->rend.isRTT && !ctx->rend.isRenderFramebuffer)) // If rendering to texture, continue locking until the frame is rendered re.Set(); + rend_allow_rollback(); return proc && renderer->Render(); } @@ -437,6 +439,7 @@ void rend_cancel_emu_wait() { FinishRender(NULL); re.Set(); + rend_allow_rollback(); } } @@ -470,3 +473,18 @@ void rend_swap_frame(u32 fb_r_sof1) } swap_mutex.unlock(); } + +void rend_disable_rollback() +{ + vramRollback.Reset(); +} + +void rend_allow_rollback() +{ + vramRollback.Set(); +} + +void rend_start_rollback() +{ + vramRollback.Wait(); +} diff --git a/core/hw/pvr/Renderer_if.h b/core/hw/pvr/Renderer_if.h index 86007f5e3..0ffc9b9c5 100644 --- a/core/hw/pvr/Renderer_if.h +++ b/core/hw/pvr/Renderer_if.h @@ -15,6 +15,9 @@ bool rend_single_frame(const bool& enabled); void rend_swap_frame(u32 fb_r_sof1); void rend_set_fb_write_addr(u32 fb_w_sof1); void rend_reset(); +void rend_disable_rollback(); +void rend_start_rollback(); +void rend_allow_rollback(); /////// extern TA_context* _pvrrc; diff --git a/core/hw/pvr/ta_ctx.cpp b/core/hw/pvr/ta_ctx.cpp index 15d7d3e45..9411bb4ca 100644 --- a/core/hw/pvr/ta_ctx.cpp +++ b/core/hw/pvr/ta_ctx.cpp @@ -4,6 +4,7 @@ #if defined(__SWITCH__) #include #endif +#include "Renderer_if.h" extern u32 fskip; extern u32 FrameCount; @@ -101,7 +102,8 @@ bool QueueRender(TA_context* ctx) fskip++; return false; } - + // disable net rollbacks until the render thread has processed the frame + rend_disable_rollback(); frame_finished.Reset(); mtx_rqueue.lock(); TA_context* old = rqueue; diff --git a/core/network/ggpo.cpp b/core/network/ggpo.cpp index ab34411c5..e90fab49d 100644 --- a/core/network/ggpo.cpp +++ b/core/network/ggpo.cpp @@ -30,6 +30,7 @@ #include #include #include +#include "imgui/imgui.h" //#define SYNC_TEST 1 @@ -59,6 +60,8 @@ struct MemPages static std::unordered_map deltaStates; static int lastSavedFrame = -1; +static int timesyncOccurred; + /* * begin_game callback - This callback has been deprecated. You must * implement it, but should ignore the 'game' parameter. @@ -99,6 +102,7 @@ static bool on_event(GGPOEvent *info) break; case GGPO_EVENTCODE_TIMESYNC: INFO_LOG(NETWORK, "Timesync: %d frames ahead", info->u.timesync.frames_ahead); + timesyncOccurred += 5; std::this_thread::sleep_for(std::chrono::milliseconds(1000 * info->u.timesync.frames_ahead / 60)); // FIXME assumes 60 FPS break; case GGPO_EVENTCODE_CONNECTION_INTERRUPTED: @@ -149,6 +153,7 @@ static bool load_game_state(unsigned char *buffer, int len) { INFO_LOG(NETWORK, "load_game_state"); + rend_start_rollback(); // FIXME will invalidate too much stuff: palette/fog textures, maple stuff // FIXME dynarecs int frame = *(u32 *)buffer; @@ -172,6 +177,7 @@ static bool load_game_state(unsigned char *buffer, int len) DEBUG_LOG(NETWORK, "Restored frame %d pages: %d ram, %d vram, %d aica ram", f, (u32)pages.ram.size(), (u32)pages.vram.size(), (u32)pages.aram.size()); } + rend_allow_rollback(); // ggpo might load another state right after this one memwatch::reset(); memwatch::protect(); return true; @@ -468,6 +474,59 @@ std::future startNetwork() }); } +void displayStats() +{ + if (!active()) + return; + GGPONetworkStats stats; + ggpo_get_network_stats(ggpoSession, remotePlayer, &stats); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0); + ImGui::SetNextWindowPos(ImVec2(10, 10)); + ImGui::SetNextWindowSize(ImVec2(95 * scaling, 0)); + ImGui::SetNextWindowBgAlpha(0.7f); + ImGui::Begin("", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration); + + ImGui::Columns(2, "cols", false); + ImGui::SetColumnWidth(0, 55 * scaling); + ImGui::SetColumnWidth(1, 40 * scaling); + ImGui::Text("Send Q"); + ImGui::NextColumn(); + ImGui::Text("%d", stats.network.send_queue_len); + ImGui::NextColumn(); + + ImGui::Text("Ping"); + ImGui::NextColumn(); + ImGui::Text("%d", stats.network.ping); + ImGui::NextColumn(); + + if (stats.sync.predicted_frames == 7) + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1, 0, 0, 1)); + ImGui::Text("Predicted"); + ImGui::NextColumn(); + ImGui::Text("%d", stats.sync.predicted_frames); + ImGui::NextColumn(); + if (stats.sync.predicted_frames == 7) + ImGui::PopStyleColor(); + + int timesync = timesyncOccurred; + if (timesync > 0) + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1, 0, 0, 1)); + ImGui::Text("Behind"); + ImGui::NextColumn(); + ImGui::Text("%d", stats.timesync.local_frames_behind); + if (timesync > 0) + { + ImGui::PopStyleColor(); + timesyncOccurred--; + } + ImGui::Columns(1); + + ImGui::End(); + ImGui::PopStyleVar(2); +} + } #else // LIBRETRO @@ -496,5 +555,8 @@ std::future startNetwork() { return std::async(std::launch::deferred, []{ return false; });; } +void displayStats() { +} + } #endif diff --git a/core/network/ggpo.h b/core/network/ggpo.h index c0f30f1da..7fad6ece2 100644 --- a/core/network/ggpo.h +++ b/core/network/ggpo.h @@ -28,5 +28,6 @@ void stopSession(); void getInput(u32 out_kcode[4]); void nextFrame(); bool active(); +void displayStats(); } diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index 711d56567..80720a024 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -2242,7 +2242,7 @@ void gui_display_osd() if (message.empty()) message = getFPSNotification(); - if (!message.empty() || config::FloatVMUs || crosshairsNeeded()) + if (!message.empty() || config::FloatVMUs || crosshairsNeeded() || ggpo::active()) { ImGui_Impl_NewFrame(); ImGui::NewFrame(); @@ -2263,6 +2263,7 @@ void gui_display_osd() if (config::FloatVMUs) display_vmus(); // gui_plot_render_time(screen_width, screen_height); + ggpo::displayStats(); ImGui::Render(); ImGui_impl_RenderDrawData(ImGui::GetDrawData());