Skip to content

Commit

Permalink
Implement multi-context netImgui support
Browse files Browse the repository at this point in the history
  • Loading branch information
N7Alpha committed Jun 16, 2024
1 parent 5bdd272 commit 4734b7a
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 11 deletions.
14 changes: 14 additions & 0 deletions Source/ThirdParty/imgui/imconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,17 @@ namespace ImGui
void MyFunction(const char* name, MyMatrix44* mtx);
}
*/

// The ImGui libraries all use global state. However we want one ImGui instance per Libretro Core The hack recommended
// by imgui.h suggests using thread_local's ocornut has a plan to add this as a first-class feature in v2 eventually
#if defined(__UNREAL__)
extern thread_local struct ImGuiContext* LibretroImGuiTLS;
#define GImGui LibretroImGuiTLS

extern thread_local struct ImPlotContext* LibretroImPlotTLS;
#define GImPlot LibretroImPlotTLS

namespace NetImgui { namespace Internal { namespace Client { struct ClientInfo; } } }
extern thread_local struct NetImgui::Internal::Client::ClientInfo* LibretroNetImguiClientInfo;
#define gpClientInfo LibretroNetImguiClientInfo
#endif
30 changes: 20 additions & 10 deletions Source/UnrealLibretro/Private/LibretroContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1068,6 +1068,16 @@ FLibretroContext* FLibretroContext::Launch(ULibretroCoreInstance* LibretroCoreIn
AbsoluteCoreDirectory.Len());
};

#ifdef UNREALLIBRETRO_NETIMGUI
static ImFontAtlas* GlobalFontAtlas = nullptr;
if (GlobalFontAtlas == nullptr) {
GlobalFontAtlas = new ImFontAtlas();
ImFontConfig fontConfig;
GlobalFontAtlas->AddFontDefault(&fontConfig);
GlobalFontAtlas->Build();
}
#endif

l->netplay_session = (ulnet_session_t *) calloc(1, sizeof(ulnet_session_t));
l->netplay_session->sample_size = ULNET_MAX_SAMPLE_SIZE;

Expand Down Expand Up @@ -1158,27 +1168,20 @@ FLibretroContext* FLibretroContext::Launch(ULibretroCoreInstance* LibretroCoreIn
#if UNREALLIBRETRO_NETIMGUI
{ // Setup ImGui
IMGUI_CHECKVERSION();
ImGui::SetCurrentContext(ImGui::CreateContext());
ImGui::CreateContext(GlobalFontAtlas);
ImPlot::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.IniFilename = NULL; // Don't write an ini file that caches window positions
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
ImGui::StyleColorsDark();

// Doing font initialization manually is a special case for netImgui and using the ImGui "null" backend
// Confusingly, you don't manually set the null backend see imgui/examples/example_null/main.cpp for details
// You'll hit a variety of asserts if you don't execute the following boilerplate
io.Fonts->AddFontDefault();
io.Fonts->Build();
io.Fonts->SetTexID(0);
io.DisplaySize = ImVec2(8, 8);

if (!NetImgui::Startup()) {
UE_LOG(Libretro, Error, TEXT("Failed to initialize NetImgui. NetImgui will not be available"));
} else {
for (l->netimgui_port = 8889; l->netimgui_port < 65535; l->netimgui_port++) {
char TitleAnsi[256];
FCStringAnsi::Snprintf(TitleAnsi, sizeof(TitleAnsi), "UnrealLibretro %s (ImGui " IMGUI_VERSION ")", UnrealLibretroVersionAnsi);
FCStringAnsi::Snprintf(TitleAnsi, sizeof(TitleAnsi), "%s (UnrealLibretro %s)",
TCHAR_TO_ANSI(*FPaths::GetCleanFilename(game.IsEmpty() ? core : game)), UnrealLibretroVersionAnsi);
NetImgui::ConnectFromApp(TitleAnsi, l->netimgui_port);
if (NetImgui::IsConnectionPending()) {
UE_LOG(Libretro, Log, TEXT("NetImgui is listening on port %i"), l->netimgui_port);
Expand Down Expand Up @@ -1289,6 +1292,13 @@ FLibretroContext* FLibretroContext::Launch(ULibretroCoreInstance* LibretroCoreIn
}

cleanup:
// These ImGui routines all cleanup thread_local objects if they aren't NULL
#if UNREALLIBRETRO_NETIMGUI
NetImgui::Shutdown();
#endif
ImPlot::DestroyContext();
ImGui::DestroyContext();

if (l->CoreState.load(std::memory_order_relaxed) == ECoreState::StartFailed)
{
LoadedCallback(l, l->libretro_api);
Expand Down
4 changes: 4 additions & 0 deletions Source/UnrealLibretro/Private/LibretroContext.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#pragma once

#if PLATFORM_WINDOWS
#include "Windows/WindowsHWrapper.h"
#endif

#define SAM2_SERVER
THIRD_PARTY_INCLUDES_START
#include "sam2.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
#include "implot.cpp"
#include "implot_items.cpp"

thread_local ImGuiContext* LibretroImGuiTLS = nullptr;
thread_local ImPlotContext* LibretroImPlotTLS = nullptr;
namespace NetImgui { namespace Internal { namespace Client { struct ClientInfo; } } }
thread_local NetImgui::Internal::Client::ClientInfo* LibretroNetImguiClientInfo = nullptr;

#if PLATFORM_WINDOWS
#include "Windows/MinWindows.h"
#include "Windows/AllowWindowsPlatformTypes.h"
Expand Down
1 change: 0 additions & 1 deletion Source/UnrealLibretro/Private/sam2.h
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,6 @@ static int sam2_format_core_version(sam2_room_t *room, const char *name, const c
#define WIN32_LEAN_AND_MEAN 1
#endif
#include <io.h>
#include <windows.h>
#include <winsock2.h>
//#pragma comment(lib, "ws2_32.lib")
typedef SOCKET sam2_socket_t;
Expand Down

0 comments on commit 4734b7a

Please sign in to comment.