UI+build: Isolate wxWidgets code from non-GUI code (#1633)

This commit is contained in:
SSimco
2025-07-15 04:28:41 +02:00
committed by GitHub
parent 5f3c2816ec
commit 67de63bed6
199 changed files with 2414 additions and 2091 deletions
+1
View File
@@ -31,6 +31,7 @@ jobs:
find src -name *.cpp -o -name *.hpp -o -name *.h |
xargs xgettext --from-code=utf-8 -w 100
--keyword="_" --keyword="wxTRANSLATE" --keyword="wxPLURAL:1,2"
--keyword="_tr" --keyword="TR_NOOP"
--check=space-ellipsis --omit-header
-o cemu.pot
-4
View File
@@ -150,7 +150,3 @@ if(UNIX AND NOT APPLE)
# most likely not helpful in debugging problems with cemu code
target_link_options(CemuBin PRIVATE "$<$<CONFIG:Release>:-Xlinker;--strip-debug>")
endif()
if (ENABLE_WXWIDGETS)
target_link_libraries(CemuBin PRIVATE wx::base wx::core)
endif()
-4
View File
@@ -597,10 +597,6 @@ else ()
target_link_libraries(CemuCafe PRIVATE libusb::libusb)
endif ()
if (ENABLE_WXWIDGETS)
target_link_libraries(CemuCafe PRIVATE wx::base wx::core)
endif()
if(WIN32)
target_link_libraries(CemuCafe PRIVATE iphlpapi)
endif()
+4 -7
View File
@@ -1,5 +1,5 @@
#include "Cafe/OS/common/OSCommon.h"
#include "gui/wxgui.h"
#include "WindowSystem.h"
#include "Cafe/OS/libs/gx2/GX2.h"
#include "Cafe/GameProfile/GameProfile.h"
#include "Cafe/HW/Espresso/Interpreter/PPCInterpreterInternal.h"
@@ -65,9 +65,6 @@
// HW interfaces
#include "Cafe/HW/SI/si.h"
// dependency to be removed
#include "gui/guiWrapper.h"
#include <time.h>
#if BOOST_OS_LINUX
@@ -172,7 +169,7 @@ void LoadMainExecutable()
applicationRPX = RPLLoader_LoadFromMemory(rpxData, rpxSize, (char*)_pathToExecutable.c_str());
if (!applicationRPX)
{
wxMessageBox(_("Failed to run this title because the executable is damaged"));
WindowSystem::ShowErrorDialog(_tr("Failed to run this title because the executable is damaged"));
cemuLog_createLogFile(false);
cemuLog_waitForFlush();
exit(0);
@@ -357,7 +354,7 @@ uint32 LoadSharedData()
void cemu_initForGame()
{
gui_updateWindowTitles(false, true, 0.0);
WindowSystem::UpdateWindowTitles(false, true, 0.0);
// input manager apply game profile
InputManager::instance().apply_game_profile();
// log info for launched title
@@ -855,7 +852,7 @@ namespace CafeSystem
PPCTimer_waitForInit();
// start system
sSystemRunning = true;
gui_notifyGameLoaded();
WindowSystem::NotifyGameLoaded();
std::thread t(_LaunchTitleThread);
t.detach();
}
+5 -5
View File
@@ -1,7 +1,7 @@
#include <wx/msgdlg.h>
#include <mutex>
#include <gui/helpers/wxHelpers.h>
#include "Cemu/Logging/CemuLogging.h"
#include "WindowSystem.h"
#include "config/ActiveSettings.h"
#include "util/crypto/aes128.h"
#include "Common/FileStream.h"
@@ -75,7 +75,7 @@ void KeyCache_Prepare()
}
else
{
wxMessageBox(_("Unable to create file keys.txt\nThis can happen if Cemu does not have write permission to its own directory, the disk is full or if anti-virus software is blocking Cemu."), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
WindowSystem::ShowErrorDialog(_tr("Unable to create file keys.txt\nThis can happen if Cemu does not have write permission to its own directory, the disk is full or if anti-virus software is blocking Cemu."), _tr("Error"), WindowSystem::ErrorCategory::KEYS_TXT_CREATION);
}
mtxKeyCache.unlock();
return;
@@ -108,8 +108,8 @@ void KeyCache_Prepare()
continue;
if( strishex(line) == false )
{
auto errorMsg = formatWxString(_("Error in keys.txt at line {}"), lineNumber);
wxMessageBox(errorMsg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
auto errorMsg = _tr("Error in keys.txt at line {}", lineNumber);
WindowSystem::ShowErrorDialog(errorMsg, WindowSystem::ErrorCategory::KEYS_TXT_CREATION);
continue;
}
if(line.size() == 32 )
+1 -1
View File
@@ -85,7 +85,7 @@ bool GraphicPack2::LoadGraphicPack(const fs::path& rulesPath, IniParser& rules)
auto gp = std::make_shared<GraphicPack2>(rulesPath, rules);
// check if enabled and preset set
const auto& config_entries = g_config.data().graphic_pack_entries;
const auto& config_entries = GetConfigHandle().data().graphic_pack_entries;
// legacy absolute path checking for not breaking compatibility
auto file = gp->GetRulesPath();
+7 -8
View File
@@ -1,13 +1,12 @@
#include "Cafe/GraphicPack/GraphicPack2.h"
#include "Cemu/Logging/CemuLogging.h"
#include "Common/FileStream.h"
#include "WindowSystem.h"
#include "util/helpers/StringParser.h"
#include "Cemu/PPCAssembler/ppcAssembler.h"
#include "Cafe/OS/RPL/rpl_structs.h"
#include "boost/algorithm/string.hpp"
#include "gui/wxgui.h" // for wxMessageBox
#include "gui/helpers/wxHelpers.h"
// error handler
void PatchErrorHandler::printError(class PatchGroup* patchGroup, sint32 lineNumber, std::string_view errorMsg)
{
@@ -40,13 +39,13 @@ void PatchErrorHandler::printError(class PatchGroup* patchGroup, sint32 lineNumb
void PatchErrorHandler::showStageErrorMessageBox()
{
wxString errorMsg;
std::string errorMsg;
if (m_gp)
{
if (m_stage == STAGE::PARSER)
errorMsg.assign(formatWxString(_("Failed to load patches for graphic pack \'{}\'"), m_gp->GetName()));
errorMsg.assign(_tr("Failed to load patches for graphic pack \'{}\'", m_gp->GetName()));
else
errorMsg.assign(formatWxString(_("Failed to apply patches for graphic pack \'{}\'"), m_gp->GetName()));
errorMsg.assign(_tr("Failed to apply patches for graphic pack \'{}\'", m_gp->GetName()));
}
else
{
@@ -55,7 +54,7 @@ void PatchErrorHandler::showStageErrorMessageBox()
if (cemuLog_isLoggingEnabled(LogType::Patches))
{
errorMsg.append("\n \n")
.append(_("Details:"))
.append(_tr("Details:"))
.append("\n");
for (auto& itr : errorMessages)
{
@@ -64,7 +63,7 @@ void PatchErrorHandler::showStageErrorMessageBox()
}
}
wxMessageBox(errorMsg, _("Graphic pack error"));
WindowSystem::ShowErrorDialog(errorMsg, _tr("Graphic pack error"), WindowSystem::ErrorCategory::GRAPHIC_PACKS);
}
// loads Cemu-style patches (patch_<anything>.asm)
+15 -14
View File
@@ -1,19 +1,20 @@
#include "gui/guiWrapper.h"
#include "Common/precompiled.h"
#include "Debugger.h"
#include "Cafe/OS/RPL/rpl_structs.h"
#include "Cemu/PPCAssembler/ppcAssembler.h"
#include "Cafe/HW/Espresso/Recompiler/PPCRecompiler.h"
#include "Cemu/ExpressionParser/ExpressionParser.h"
#include "gui/debugger/DebuggerWindow2.h"
#include "Cafe/OS/libs/coreinit/coreinit.h"
#include "OS/RPL/rpl.h"
#include "util/helpers/helpers.h"
#if BOOST_OS_WINDOWS
#include <Windows.h>
#endif
DebuggerDispatcher g_debuggerDispatcher;
debuggerState_t debuggerState{ };
DebuggerBreakpoint* debugger_getFirstBP(uint32 address)
@@ -337,7 +338,7 @@ void debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* b
{
bp->enabled = state;
debugger_updateExecutionBreakpoint(address);
debuggerWindow_updateViewThreadsafe2();
g_debuggerDispatcher.UpdateViewThreadsafe();
}
else if (bpItr->isMemBP())
{
@@ -359,7 +360,7 @@ void debugger_toggleBreakpoint(uint32 address, bool state, DebuggerBreakpoint* b
debugger_updateMemoryBreakpoint(bpItr);
else
debugger_updateMemoryBreakpoint(nullptr);
debuggerWindow_updateViewThreadsafe2();
g_debuggerDispatcher.UpdateViewThreadsafe();
}
return;
}
@@ -496,7 +497,7 @@ void debugger_stepInto(PPCInterpreter_t* hCPU, bool updateDebuggerWindow = true)
debugger_updateExecutionBreakpoint(initialIP);
debuggerState.debugSession.instructionPointer = hCPU->instructionPointer;
if(updateDebuggerWindow)
debuggerWindow_moveIP();
g_debuggerDispatcher.MoveIP();
ppcRecompilerEnabled = isRecEnabled;
}
@@ -515,7 +516,7 @@ bool debugger_stepOver(PPCInterpreter_t* hCPU)
// nothing to skip, use step-into
debugger_stepInto(hCPU);
debugger_updateExecutionBreakpoint(initialIP);
debuggerWindow_moveIP();
g_debuggerDispatcher.MoveIP();
ppcRecompilerEnabled = isRecEnabled;
return false;
}
@@ -523,7 +524,7 @@ bool debugger_stepOver(PPCInterpreter_t* hCPU)
debugger_createCodeBreakpoint(initialIP + 4, DEBUGGER_BP_T_ONE_SHOT);
// step over current instruction (to avoid breakpoint)
debugger_stepInto(hCPU);
debuggerWindow_moveIP();
g_debuggerDispatcher.MoveIP();
// restore breakpoints
debugger_updateExecutionBreakpoint(initialIP);
// run
@@ -621,8 +622,8 @@ void debugger_enterTW(PPCInterpreter_t* hCPU)
DebuggerBreakpoint* singleshotBP = debugger_getFirstBP(debuggerState.debugSession.instructionPointer, DEBUGGER_BP_T_ONE_SHOT);
if (singleshotBP)
debugger_deleteBreakpoint(singleshotBP);
debuggerWindow_notifyDebugBreakpointHit2();
debuggerWindow_updateViewThreadsafe2();
g_debuggerDispatcher.NotifyDebugBreakpointHit();
g_debuggerDispatcher.UpdateViewThreadsafe();
// reset step control
debuggerState.debugSession.stepInto = false;
debuggerState.debugSession.stepOver = false;
@@ -639,14 +640,14 @@ void debugger_enterTW(PPCInterpreter_t* hCPU)
break; // if true is returned, continue with execution
}
debugger_createPPCStateSnapshot(hCPU);
debuggerWindow_updateViewThreadsafe2();
g_debuggerDispatcher.UpdateViewThreadsafe();
debuggerState.debugSession.stepOver = false;
}
if (debuggerState.debugSession.stepInto)
{
debugger_stepInto(hCPU);
debugger_createPPCStateSnapshot(hCPU);
debuggerWindow_updateViewThreadsafe2();
g_debuggerDispatcher.UpdateViewThreadsafe();
debuggerState.debugSession.stepInto = false;
continue;
}
@@ -663,8 +664,8 @@ void debugger_enterTW(PPCInterpreter_t* hCPU)
debuggerState.debugSession.isTrapped = false;
debuggerState.debugSession.hCPU = nullptr;
debuggerWindow_updateViewThreadsafe2();
debuggerWindow_notifyRun();
g_debuggerDispatcher.UpdateViewThreadsafe();
g_debuggerDispatcher.NotifyRun();
}
void debugger_shouldBreak(PPCInterpreter_t* hCPU)
+63
View File
@@ -15,6 +15,69 @@
#define DEBUGGER_BP_T_GDBSTUB_TW 0x7C010008
#define DEBUGGER_BP_T_DEBUGGER_TW 0x7C020008
class DebuggerCallbacks
{
public:
virtual void UpdateViewThreadsafe() {}
virtual void NotifyDebugBreakpointHit() {}
virtual void NotifyRun() {}
virtual void MoveIP() {}
virtual void NotifyModuleLoaded(void* module) {}
virtual void NotifyModuleUnloaded(void* module) {}
virtual ~DebuggerCallbacks() = default;
};
class DebuggerDispatcher
{
private:
static inline class DefaultDebuggerCallbacks : public DebuggerCallbacks
{
} s_defaultDebuggerCallbacks;
DebuggerCallbacks* m_callbacks = &s_defaultDebuggerCallbacks;
public:
void SetDebuggerCallbacks(DebuggerCallbacks* debuggerCallbacks)
{
cemu_assert_debug(m_callbacks == &s_defaultDebuggerCallbacks);
m_callbacks = debuggerCallbacks;
}
void ClearDebuggerCallbacks()
{
cemu_assert_debug(m_callbacks != &s_defaultDebuggerCallbacks);
m_callbacks = &s_defaultDebuggerCallbacks;
}
void UpdateViewThreadsafe()
{
m_callbacks->UpdateViewThreadsafe();
}
void NotifyDebugBreakpointHit()
{
m_callbacks->NotifyDebugBreakpointHit();
}
void NotifyRun()
{
m_callbacks->NotifyRun();
}
void MoveIP()
{
m_callbacks->MoveIP();
}
void NotifyModuleLoaded(void* module)
{
m_callbacks->NotifyModuleLoaded(module);
}
void NotifyModuleUnloaded(void* module)
{
m_callbacks->NotifyModuleUnloaded(module);
}
} extern g_debuggerDispatcher;
struct DebuggerBreakpoint
{
+5 -5
View File
@@ -1,6 +1,6 @@
#include "Cafe/HW/Latte/Core/LatteOverlay.h"
#include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
#include "config/CemuConfig.h"
@@ -519,17 +519,17 @@ void LatteOverlay_render(bool pad_view)
return;
sint32 w = 0, h = 0;
if (pad_view && gui_isPadWindowOpen())
gui_getPadWindowPhysSize(w, h);
if (pad_view && WindowSystem::IsPadWindowOpen())
WindowSystem::GetPadWindowPhysSize(w, h);
else
gui_getWindowPhysSize(w, h);
WindowSystem::GetWindowPhysSize(w, h);
if (w == 0 || h == 0)
return;
const Vector2f window_size{ (float)w,(float)h };
float fontDPIScale = !pad_view ? gui_getWindowDPIScale() : gui_getPadDPIScale();
float fontDPIScale = !pad_view ? WindowSystem::GetWindowDPIScale() : WindowSystem::GetPadDPIScale();
float overlayFontSize = 14.0f * (float)config.overlay.text_scale / 100.0f * fontDPIScale;
@@ -1,6 +1,6 @@
#include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h"
#include "Cafe/HW/Latte/Core/LatteOverlay.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
performanceMonitor_t performanceMonitor{};
@@ -106,12 +106,12 @@ void LattePerformanceMonitor_frameEnd()
if (isFirstUpdate)
{
LatteOverlay_updateStats(0.0, 0, 0);
gui_updateWindowTitles(false, false, 0.0);
WindowSystem::UpdateWindowTitles(false, false, 0.0);
}
else
{
LatteOverlay_updateStats(fps, drawCallCounter / elapsedFrames, fastDrawCallCounter / elapsedFrames);
gui_updateWindowTitles(false, false, fps);
WindowSystem::UpdateWindowTitles(false, false, fps);
}
}
}
+6 -6
View File
@@ -11,7 +11,7 @@
#include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h"
#include "Cafe/GraphicPack/GraphicPack2.h"
#include "config/ActiveSettings.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
#include "Cafe/OS/libs/erreula/erreula.h"
#include "input/InputManager.h"
#include "Cafe/OS/libs/swkbd/swkbd.h"
@@ -838,10 +838,10 @@ sint32 _currentOutputImageHeight = 0;
void LatteRenderTarget_getScreenImageArea(sint32* x, sint32* y, sint32* width, sint32* height, sint32* fullWidth, sint32* fullHeight, bool padView)
{
int w, h;
if(padView && gui_isPadWindowOpen())
gui_getPadWindowPhysSize(w, h);
if(padView && WindowSystem::IsPadWindowOpen())
WindowSystem::GetPadWindowPhysSize(w, h);
else
gui_getWindowPhysSize(w, h);
WindowSystem::GetWindowPhysSize(w, h);
sint32 scaledOutputX;
sint32 scaledOutputY;
@@ -999,8 +999,8 @@ void LatteRenderTarget_itHLECopyColorBufferToScanBuffer(MPTR colorBufferPtr, uin
return {pressed && !toggle, pressed && toggle};
};
const bool tabPressed = gui_isKeyDown(PlatformKeyCodes::TAB);
const bool ctrlPressed = gui_isKeyDown(PlatformKeyCodes::LCONTROL);
const bool tabPressed = WindowSystem::IsKeyDown(WindowSystem::PlatformKeyCodes::TAB);
const bool ctrlPressed = WindowSystem::IsKeyDown(WindowSystem::PlatformKeyCodes::LCONTROL);
const auto [vpad0Active, vpad0Toggle] = getVPADScreenActive(0);
const auto [vpad1Active, vpad1Toggle] = getVPADScreenActive(1);
+2 -35
View File
@@ -6,7 +6,7 @@
#include "Cafe/HW/Latte/Core/FetchShader.h"
#include "Cemu/FileCache/FileCache.h"
#include "Cafe/GameProfile/GameProfile.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.h"
@@ -24,7 +24,6 @@
#include "Cafe/HW/Latte/Common/ShaderSerializer.h"
#include "util/helpers/Serializer.h"
#include <wx/msgdlg.h>
#include <audio/IAudioAPI.h>
#include <util/bootSound/BootSoundReader.h>
#include <thread>
@@ -69,8 +68,6 @@ void LatteShaderCache_LoadVulkanPipelineCache(uint64 cacheTitleId);
bool LatteShaderCache_updatePipelineLoadingProgress();
void LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateFunc, bool isPipelines);
void LatteShaderCache_handleDeprecatedCacheFiles(fs::path pathGeneric, fs::path pathGenericPre1_25_0, fs::path pathGenericPre1_16_0);
struct
{
struct
@@ -360,10 +357,7 @@ void LatteShaderCache_Load()
RendererShaderGL::ShaderCacheLoading_begin(cacheTitleId);
// get cache file name
const auto pathGeneric = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}_shaders.bin", cacheTitleId);
const auto pathGenericPre1_25_0 = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}.bin", cacheTitleId); // before 1.25.0
const auto pathGenericPre1_16_0 = ActiveSettings::GetCachePath("shaderCache/transferable/{:08x}.bin", CafeSystem::GetRPXHashBase()); // before 1.16.0
LatteShaderCache_handleDeprecatedCacheFiles(pathGeneric, pathGenericPre1_25_0, pathGenericPre1_16_0);
// calculate extraVersion for transferable and precompiled shader cache
uint32 transferableExtraVersion = SHADER_CACHE_GENERIC_EXTRA_VERSION;
s_shaderCacheGeneric = FileCache::Open(pathGeneric, false, transferableExtraVersion); // legacy extra version (1.25.0 - 1.25.1b)
@@ -511,7 +505,7 @@ void LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateF
continue;
int w, h;
gui_getWindowPhysSize(w, h);
WindowSystem::GetWindowPhysSize(w, h);
const Vector2f window_size{ (float)w,(float)h };
ImGui_GetFont(window_size.y / 32.0f); // = 24 by default
@@ -900,30 +894,3 @@ void LatteShaderCache_Close()
if (g_renderer->GetType() == RendererAPI::Vulkan)
VulkanPipelineStableCache::GetInstance().Close();
}
#include <wx/msgdlg.h>
void LatteShaderCache_handleDeprecatedCacheFiles(fs::path pathGeneric, fs::path pathGenericPre1_25_0, fs::path pathGenericPre1_16_0)
{
std::error_code ec;
bool hasOldCacheFiles = fs::exists(pathGenericPre1_25_0, ec) || fs::exists(pathGenericPre1_16_0, ec);
bool hasNewCacheFiles = fs::exists(pathGeneric, ec);
if (hasOldCacheFiles && !hasNewCacheFiles)
{
// ask user if they want to delete or keep the old cache file
auto infoMsg = _("Cemu detected that the shader cache for this game is outdated.\nOnly shader caches generated with Cemu 1.25.0 or above are supported.\n\nWe recommend deleting the outdated cache file as it will no longer be used by Cemu.");
wxMessageDialog dialog(nullptr, infoMsg, _("Outdated shader cache"),
wxYES_NO | wxCENTRE | wxICON_EXCLAMATION);
dialog.SetYesNoLabels(_("Delete outdated cache file [recommended]"), _("Keep outdated cache file"));
const auto result = dialog.ShowModal();
if (result == wxID_YES)
{
fs::remove(pathGenericPre1_16_0, ec);
fs::remove(pathGenericPre1_25_0, ec);
}
}
}
+3 -4
View File
@@ -6,7 +6,7 @@
#include "Cafe/HW/Latte/Core/LatteAsyncCommands.h"
#include "Cafe/GameProfile/GameProfile.h"
#include "Cafe/GraphicPack/GraphicPack2.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
#include "Cafe/HW/Latte/Core/LatteBufferCache.h"
@@ -115,7 +115,7 @@ int Latte_ThreadEntry()
{
SetThreadName("LatteThread");
sint32 w,h;
gui_getWindowPhysSize(w,h);
WindowSystem::GetWindowPhysSize(w,h);
// renderer
g_renderer->Initialize();
@@ -166,8 +166,7 @@ int Latte_ThreadEntry()
g_renderer->DrawEmptyFrame(true);
g_renderer->DrawEmptyFrame(false);
gui_hasScreenshotRequest(); // keep the screenshot request queue empty
g_renderer->CancelScreenshotRequest(); // keep the screenshot request queue empty
std::this_thread::sleep_for(std::chrono::milliseconds(1000/60));
}
@@ -1,5 +1,5 @@
#include "Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
#include "Cafe/HW/Latte/Core/LatteRingBuffer.h"
#include "Cafe/HW/Latte/Core/LatteDraw.h"
@@ -19,7 +19,38 @@
#include "Cafe/HW/Latte/ISA/RegDefines.h"
#include "Cafe/OS/libs/gx2/GX2.h"
#include "gui/canvas/OpenGLCanvas.h"
class DefaultOpenGLCanvasCallbacks : public OpenGLCanvasCallbacks
{
} g_defaultOpenGLCanvasCallbacks;
OpenGLCanvasCallbacks* g_openGLCanvasCallbacks = &g_defaultOpenGLCanvasCallbacks;
void SetOpenGLCanvasCallbacks(OpenGLCanvasCallbacks* callbacks)
{
cemu_assert_debug(g_openGLCanvasCallbacks == &g_defaultOpenGLCanvasCallbacks);
g_openGLCanvasCallbacks = callbacks;
}
void ClearOpenGLCanvasCallbacks()
{
cemu_assert_debug(g_openGLCanvasCallbacks != &g_defaultOpenGLCanvasCallbacks);
g_openGLCanvasCallbacks = &g_defaultOpenGLCanvasCallbacks;
}
bool GLCanvas_HasPadViewOpen()
{
return g_openGLCanvasCallbacks->HasPadViewOpen();
}
bool GLCanvas_MakeCurrent(bool padView)
{
return g_openGLCanvasCallbacks->MakeCurrent(padView);
}
void GLCanvas_SwapBuffers(bool swapTV, bool swapDRC)
{
g_openGLCanvasCallbacks->SwapBuffers(swapTV, swapDRC);
}
#define STRINGIFY2(X) #X
#define STRINGIFY(X) STRINGIFY2(X)
@@ -479,8 +510,7 @@ void OpenGLRenderer::ClearColorbuffer(bool padView)
void OpenGLRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool padView)
{
const bool hasScreenshotRequest = gui_hasScreenshotRequest();
if(!hasScreenshotRequest && m_screenshot_state == ScreenshotState::None)
if(!m_screenshot_requested && m_screenshot_state == ScreenshotState::None)
return;
if (IsPadWindowActive())
@@ -563,9 +593,9 @@ void OpenGLRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
{
int windowWidth, windowHeight;
if (padView)
gui_getPadWindowPhysSize(windowWidth, windowHeight);
WindowSystem::GetPadWindowPhysSize(windowWidth, windowHeight);
else
gui_getWindowPhysSize(windowWidth, windowHeight);
WindowSystem::GetWindowPhysSize(windowWidth, windowHeight);
g_renderer->renderTarget_setViewport(0, 0, windowWidth, windowHeight, 0.0f, 1.0f);
g_renderer->ClearColorbuffer(padView);
}
@@ -6,6 +6,28 @@
#define GPU_GL_MAX_NUM_ATTRIBUTE (16) // Wii U GPU supports more than 16 but not all desktop GPUs do. Have to keep this at 16 until we find a better solution
class OpenGLCanvasCallbacks
{
public:
virtual bool HasPadViewOpen() const
{
return false;
}
virtual bool MakeCurrent(bool padView)
{
return false;
}
virtual void SwapBuffers(bool swapTV, bool swapDRC) {}
virtual ~OpenGLCanvasCallbacks() = default;
};
void SetOpenGLCanvasCallbacks(OpenGLCanvasCallbacks* callbacks);
void ClearOpenGLCanvasCallbacks();
bool GLCanvas_HasPadViewOpen();
bool GLCanvas_MakeCurrent(bool padView);
void GLCanvas_SwapBuffers(bool swapTV, bool swapDRC);
class OpenGLRenderer : public Renderer
{
friend class OpenGLCanvas;
+25 -108
View File
@@ -1,5 +1,5 @@
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
#include "config/CemuConfig.h"
#include "Cafe/HW/Latte/Core/LatteOverlay.h"
@@ -10,11 +10,6 @@
#include "config/ActiveSettings.h"
#include <wx/image.h>
#include <wx/dataobj.h>
#include <wx/clipbrd.h>
#include <wx/log.h>
std::unique_ptr<Renderer> g_renderer;
bool Renderer::GetVRAMInfo(int& usageInMB, int& totalInMB) const
@@ -69,10 +64,10 @@ void Renderer::Shutdown()
bool Renderer::ImguiBegin(bool mainWindow)
{
sint32 w = 0, h = 0;
if(mainWindow)
gui_getWindowPhysSize(w, h);
else if(gui_isPadWindowOpen())
gui_getPadWindowPhysSize(w, h);
if (mainWindow)
WindowSystem::GetWindowPhysSize(w, h);
else if (WindowSystem::IsPadWindowOpen())
WindowSystem::GetPadWindowPhysSize(w, h);
else
return false;
@@ -82,9 +77,9 @@ bool Renderer::ImguiBegin(bool mainWindow)
// select the right context
ImGui::SetCurrentContext(mainWindow ? imguiTVContext : imguiPadContext);
const Vector2f window_size{ (float)w,(float)h };
const Vector2f window_size{(float)w, (float)h};
auto& io = ImGui::GetIO();
io.DisplaySize = { window_size.x, window_size.y }; // should be only updated in the renderer and only when needed
io.DisplaySize = {window_size.x, window_size.y}; // should be only updated in the renderer and only when needed
ImGui_PrecacheFonts();
return true;
@@ -114,107 +109,29 @@ uint8 Renderer::RGBComponentToSRGB(uint8 cli)
return (uint8)(cs * 255.0f);
}
static std::optional<fs::path> GenerateScreenshotFilename(bool isDRC)
void Renderer::RequestScreenshot(ScreenshotSaveFunction onSaveScreenshot)
{
fs::path screendir = ActiveSettings::GetUserDataPath("screenshots");
// build screenshot name with format Screenshot_YYYY-MM-DD_HH-MM-SS[_GamePad].png
// if the file already exists add a suffix counter (_2.png, _3.png etc)
std::time_t time_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::tm* tm = std::localtime(&time_t);
std::string screenshotFileName = fmt::format("Screenshot_{:04}-{:02}-{:02}_{:02}-{:02}-{:02}", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
if (isDRC)
screenshotFileName.append("_GamePad");
fs::path screenshotPath;
for(sint32 i=0; i<999; i++)
{
screenshotPath = screendir;
if (i == 0)
screenshotPath.append(fmt::format("{}.png", screenshotFileName));
else
screenshotPath.append(fmt::format("{}_{}.png", screenshotFileName, i + 1));
std::error_code ec;
bool exists = fs::exists(screenshotPath, ec);
if (!ec && !exists)
return screenshotPath;
}
return std::nullopt;
m_screenshot_requested = true;
m_on_save_screenshot = onSaveScreenshot;
}
std::mutex s_clipboardMutex;
static bool SaveScreenshotToClipboard(const wxImage &image)
void Renderer::CancelScreenshotRequest()
{
bool success = false;
s_clipboardMutex.lock();
if (wxTheClipboard->Open())
{
wxTheClipboard->SetData(new wxImageDataObject(image));
wxTheClipboard->Close();
success = true;
}
s_clipboardMutex.unlock();
return success;
m_screenshot_requested = false;
m_on_save_screenshot = {};
}
static bool SaveScreenshotToFile(const wxImage &image, bool mainWindow)
void Renderer::SaveScreenshot(const std::vector<uint8>& rgb_data, int width, int height, bool mainWindow)
{
auto path = GenerateScreenshotFilename(!mainWindow);
if (!path) return false;
std::error_code ec;
fs::create_directories(path->parent_path(), ec);
if (ec) return false;
// suspend wxWidgets logging for the lifetime this object, to prevent a message box if wxImage::SaveFile fails
wxLogNull _logNo;
return image.SaveFile(path->wstring());
}
static void ScreenshotThread(std::vector<uint8> data, bool save_screenshot, int width, int height, bool mainWindow)
{
#if BOOST_OS_WINDOWS
// on Windows wxWidgets uses OLE API for the clipboard
// to make this work we need to call OleInitialize() on the same thread
OleInitialize(nullptr);
#endif
wxImage image(width, height, data.data(), true);
if (mainWindow)
{
if(SaveScreenshotToClipboard(image))
{
if (!save_screenshot)
LatteOverlay_pushNotification("Screenshot saved to clipboard", 2500);
}
else
{
LatteOverlay_pushNotification("Failed to open clipboard", 2500);
}
}
if (save_screenshot)
{
if (SaveScreenshotToFile(image, mainWindow))
{
if (mainWindow)
LatteOverlay_pushNotification("Screenshot saved", 2500);
}
else
{
LatteOverlay_pushNotification("Failed to save screenshot to file", 2500);
}
}
}
void Renderer::SaveScreenshot(const std::vector<uint8>& rgb_data, int width, int height, bool mainWindow) const
{
const bool save_screenshot = GetConfig().save_screenshot;
std::thread(ScreenshotThread, rgb_data, save_screenshot, width, height, mainWindow).detach();
std::thread(
[=, screenshotRequested = std::exchange(m_screenshot_requested, false), onSaveScreenshot = std::exchange(m_on_save_screenshot, {})]() {
if (screenshotRequested && onSaveScreenshot)
{
auto notificationMessage = onSaveScreenshot(rgb_data, width, height, mainWindow);
if (notificationMessage.has_value())
LatteOverlay_pushNotification(notificationMessage.value(), 2500);
}
})
.detach();
}
+8 -1
View File
@@ -65,6 +65,10 @@ public:
virtual void DrawEmptyFrame(bool mainWindow) = 0;
virtual void SwapBuffers(bool swapTV, bool swapDRC) = 0;
using ScreenshotSaveFunction = std::function<std::optional<std::string>(const std::vector<uint8>&, int, int, bool)>;
void RequestScreenshot(ScreenshotSaveFunction onSaveScreenshot);
void CancelScreenshotRequest();
virtual void HandleScreenshotRequest(LatteTextureView* texView, bool padView){}
virtual void DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter,
@@ -168,7 +172,10 @@ protected:
Pad,
};
ScreenshotState m_screenshot_state = ScreenshotState::None;
void SaveScreenshot(const std::vector<uint8>& rgb_data, int width, int height, bool mainWindow) const;
bool m_screenshot_requested = false;
ScreenshotSaveFunction m_on_save_screenshot;
void SaveScreenshot(const std::vector<uint8>& rgb_data, int width, int height, bool mainWindow);
ImFontAtlas* imguiFontAtlas{};
@@ -1,7 +1,7 @@
#include "SwapchainInfoVk.h"
#include "config/CemuConfig.h"
#include "gui/guiWrapper.h"
#include "WindowSystem.h"
#include "Cafe/HW/Latte/Core/Latte.h"
#include "Cafe/HW/Latte/Core/LatteTiming.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
@@ -9,7 +9,7 @@
SwapchainInfoVk::SwapchainInfoVk(bool mainWindow, Vector2i size) : mainWindow(mainWindow), m_desiredExtent(size)
{
auto& windowHandleInfo = mainWindow ? gui_getWindowInfo().canvas_main : gui_getWindowInfo().canvas_pad;
auto& windowHandleInfo = mainWindow ? WindowSystem::GetWindowInfo().canvas_main : WindowSystem::GetWindowInfo().canvas_pad;
auto renderer = VulkanRenderer::GetInstance();
m_instance = renderer->GetVkInstance();
m_logicalDevice = renderer->GetLogicalDevice();
@@ -1,9 +1,9 @@
#include "gui/MainWindow.h"
#if BOOST_OS_WINDOWS
#include <Windows.h>
#include "WindowSystem.h"
typedef LONG NTSTATUS;
typedef UINT32 D3DKMT_HANDLE;
@@ -53,7 +53,7 @@ public:
private:
bool HasMonitorChanged()
{
HWND hWnd = (HWND)g_mainFrame->GetRenderCanvasHWND();
HWND hWnd = (HWND)WindowSystem::GetWindowInfo().canvas_main.surface;
if (hWnd == 0)
return true;
HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
@@ -71,9 +71,7 @@ private:
HRESULT GetAdapterHandleFromHwnd(D3DKMT_HANDLE* phAdapter, UINT* pOutput)
{
if (!g_mainFrame)
return E_FAIL;
HWND hWnd = (HWND)g_mainFrame->GetRenderCanvasHWND();
HWND hWnd = (HWND)WindowSystem::GetWindowInfo().canvas_main.surface;
if (hWnd == 0)
return E_FAIL;

Some files were not shown because too many files have changed in this diff Show More