From a57aeed9f03f87fa22e50ca0862b285c1f24973d Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Tue, 16 Mar 2021 23:59:47 -0500 Subject: [PATCH 01/17] Add Dear ImGui library --- .gitmodules | 4 ++++ CMakeLists.txt | 14 +++++++++++- import/imgui | 1 + projects/cxbx/CMakeLists.txt | 11 ++++++++++ projects/cxbxr-emu/CMakeLists.txt | 13 ++++++++++- projects/imgui/CMakeLists.txt | 36 +++++++++++++++++++++++++++++++ 6 files changed, 77 insertions(+), 2 deletions(-) create mode 160000 import/imgui create mode 100644 projects/imgui/CMakeLists.txt diff --git a/.gitmodules b/.gitmodules index 8786fa1b6..ca14d028f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,3 +31,7 @@ url = https://github.com/Cyan4973/xxHash.git branch = release shallow = true +[submodule "import/imgui"] + path = import/imgui + url = https://github.com/ocornut/imgui.git + shadow = true diff --git a/CMakeLists.txt b/CMakeLists.txt index b513d342a..06810163f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,8 +35,12 @@ add_custom_target(misc-batch WORKING_DIRECTORY ${CXBXR_ROOT_DIR} ) +# Custom CMake projects since some import libraries doesn't have it. + add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/libtom") +add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/imgui") + # Split the files into group for which project is likely # going to be used for both header and source files. # Then move only specific project files into their @@ -109,6 +113,10 @@ file (GLOB CXBXR_HEADER_GUIv1 ) # Emulator (module) +file (GLOB CXBXR_HEADER_EMU_IMPORT + "${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_dx9.h" + "${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_win32.h" +) file (GLOB CXBXR_HEADER_EMU "${CXBXR_ROOT_DIR}/src/common/AddressRanges.h" "${CXBXR_ROOT_DIR}/src/common/audio/converter.hpp" @@ -260,6 +268,10 @@ file (GLOB CXBXR_SOURCE_GUIv1 file (GLOB CXBXR_KRNL_CPP "${CXBXR_ROOT_DIR}/src/core/kernel/init/CxbxKrnl.cpp" ) +file (GLOB CXBXR_SOURCE_EMU_IMPORT + "${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_dx9.cpp" + "${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_win32.cpp" +) file (GLOB CXBXR_SOURCE_EMU "${CXBXR_KRNL_CPP}" "${CXBXR_ROOT_DIR}/src/common/AddressRanges.cpp" @@ -385,7 +397,7 @@ add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/cxbxr-emu") set(cxbxr_INSTALL_files "COPYING" "README.md") # Cxbx-Reloaded project with third-party libraries -set_target_properties(cxbx cxbxr-ldr cxbxr-emu misc-batch subhook libXbSymbolDatabase libtommath libtomcrypt +set_target_properties(cxbx cxbxr-ldr cxbxr-emu misc-batch subhook libXbSymbolDatabase libtommath libtomcrypt imgui PROPERTIES FOLDER Cxbx-Reloaded ) diff --git a/import/imgui b/import/imgui new file mode 160000 index 000000000..35b1148ef --- /dev/null +++ b/import/imgui @@ -0,0 +1 @@ +Subproject commit 35b1148efb839381b84de9290d9caf0b66ad7d03 diff --git a/projects/cxbx/CMakeLists.txt b/projects/cxbx/CMakeLists.txt index ad9dd6e11..caa11597d 100644 --- a/projects/cxbx/CMakeLists.txt +++ b/projects/cxbx/CMakeLists.txt @@ -77,12 +77,20 @@ file (GLOB RESOURCES "${CXBXR_ROOT_DIR}/src/.editorconfig" ) +source_group(TREE ${CXBXR_ROOT_DIR}/import PREFIX import FILES + ${CXBXR_HEADER_EMU_IMPORT} +) + source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX header FILES ${CXBXR_HEADER_GUIv1} ${CXBXR_HEADER_COMMON} ${CXBXR_HEADER_EMU} ) +source_group(TREE ${CXBXR_ROOT_DIR}/import PREFIX import FILES + ${CXBXR_SOURCE_EMU_IMPORT} +) + source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX source FILES ${CXBXR_SOURCE_GUIv1} ${CXBXR_SOURCE_COMMON} @@ -94,9 +102,11 @@ source_group(TREE ${CXBXR_ROOT_DIR} FILES ${RESOURCES}) add_executable(cxbx WIN32 ${RESOURCES} ${CXBXR_HEADER_GUIv1} ${CXBXR_HEADER_COMMON} + ${CXBXR_HEADER_EMU_IMPORT} ${CXBXR_HEADER_EMU} ${CXBXR_SOURCE_GUIv1} ${CXBXR_SOURCE_COMMON} + ${CXBXR_SOURCE_EMU_IMPORT} ${CXBXR_SOURCE_EMU} ${CXBXR_GIT_VERSION_H} ) @@ -181,6 +191,7 @@ target_link_libraries(cxbx subhook libtomcrypt SDL2 + imgui ${WINS_LIB} ) diff --git a/projects/cxbxr-emu/CMakeLists.txt b/projects/cxbxr-emu/CMakeLists.txt index 656554ff1..7aa1f6e98 100644 --- a/projects/cxbxr-emu/CMakeLists.txt +++ b/projects/cxbxr-emu/CMakeLists.txt @@ -68,6 +68,10 @@ file (GLOB RESOURCES "${CXBXR_ROOT_DIR}/README.md" ) +source_group(TREE ${CXBXR_ROOT_DIR}/import PREFIX import FILES + ${CXBXR_HEADER_EMU_IMPORT} +) + source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX header FILES ${CXBXR_HEADER_GUIv1} ${CXBXR_HEADER_COMMON} @@ -75,7 +79,11 @@ source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX header FILES "${CXBXR_ROOT_DIR}/src/emulator/targetver.h" ) -source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX source FILES +source_group(TREE ${CXBXR_ROOT_DIR}/import PREFIX import FILES + ${CXBXR_SOURCE_EMU_IMPORT} +) + +source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX source FILES ${CXBXR_SOURCE_GUIv1} ${CXBXR_SOURCE_COMMON} ${CXBXR_SOURCE_EMU} @@ -87,9 +95,11 @@ source_group(TREE ${CXBXR_ROOT_DIR} FILES ${RESOURCES}) add_library(cxbxr-emu SHARED ${RESOURCES} ${CXBXR_HEADER_COMMON} + ${CXBXR_HEADER_EMU_IMPORT} ${CXBXR_HEADER_EMU} "${CXBXR_ROOT_DIR}/src/emulator/targetver.h" ${CXBXR_SOURCE_COMMON} + ${CXBXR_SOURCE_EMU_IMPORT} ${CXBXR_SOURCE_EMU} ${CXBXR_GIT_VERSION_H} "${CXBXR_ROOT_DIR}/src/emulator/cxbxr-emu.cpp" @@ -157,6 +167,7 @@ target_link_libraries(cxbxr-emu subhook libtomcrypt SDL2 + imgui ${WINS_LIB} ) diff --git a/projects/imgui/CMakeLists.txt b/projects/imgui/CMakeLists.txt new file mode 100644 index 000000000..b4bda0970 --- /dev/null +++ b/projects/imgui/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required (VERSION 3.8) +project(imgui LANGUAGES CXX) +# Since imgui doesn't have CMake, we'll make an interface project here. + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + add_compile_definitions( + _CRT_SECURE_NO_WARNINGS + _CRT_NONSTDC_NO_DEPRECATE + ) +endif() + +file (GLOB HEADERS + "${CXBXR_ROOT_DIR}/import/imgui/imconfig.h" + "${CXBXR_ROOT_DIR}/import/imgui/imgui.h" + "${CXBXR_ROOT_DIR}/import/imgui/imgui_internal.h" + "${CXBXR_ROOT_DIR}/import/imgui/imstb_rectpack.h" + "${CXBXR_ROOT_DIR}/import/imgui/imstb_textedit.h" + "${CXBXR_ROOT_DIR}/import/imgui/imstb_truetype.h" +) + +file (GLOB SOURCES + "${CXBXR_ROOT_DIR}/import/imgui/imgui.cpp" + "${CXBXR_ROOT_DIR}/import/imgui/imgui_draw.cpp" + "${CXBXR_ROOT_DIR}/import/imgui/imgui_tables.cpp" + "${CXBXR_ROOT_DIR}/import/imgui/imgui_widgets.cpp" +) + +source_group(TREE ${CXBXR_ROOT_DIR}/import/imgui PREFIX header FILES ${HEADERS}) + +source_group(TREE ${CXBXR_ROOT_DIR}/import/imgui PREFIX source FILES ${SOURCES}) + +add_library(${PROJECT_NAME} ${HEADERS} ${SOURCES}) + +target_include_directories(${PROJECT_NAME} + PUBLIC "${CXBXR_ROOT_DIR}/import/imgui" +) From 611966f34ec20806bb595300e936df19dc858674 Mon Sep 17 00:00:00 2001 From: Silent Date: Tue, 16 Mar 2021 20:26:40 +0100 Subject: [PATCH 02/17] ImGui: Disabled some useless Win32 functions --- projects/imgui/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/projects/imgui/CMakeLists.txt b/projects/imgui/CMakeLists.txt index b4bda0970..3c6e0a296 100644 --- a/projects/imgui/CMakeLists.txt +++ b/projects/imgui/CMakeLists.txt @@ -9,6 +9,12 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") ) endif() +# Add any defines from imconfig.h file in here without need to use import file directly. +add_compile_definitions( + IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS + IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS +) + file (GLOB HEADERS "${CXBXR_ROOT_DIR}/import/imgui/imconfig.h" "${CXBXR_ROOT_DIR}/import/imgui/imgui.h" From 55f1228c666270c27db82df9b6c04e2786bf867f Mon Sep 17 00:00:00 2001 From: Silent Date: Tue, 16 Mar 2021 21:25:13 +0100 Subject: [PATCH 03/17] ImGui: Quick set-up --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 52 +++++++++++++++++++++++ src/core/kernel/init/CxbxKrnl.cpp | 12 ++++++ 2 files changed, 64 insertions(+) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index cf337caeb..e8e912403 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -61,6 +61,10 @@ #include "common/util/strConverter.hpp" // for utf8_to_utf16 #include "VertexShaderSource.h" +#include +#include +#include + #include #include #include @@ -181,6 +185,42 @@ float g_Xbox_BackbufferScaleY = 1; static constexpr size_t INDEX_BUFFER_CACHE_SIZE = 10000; +// ImGui +static void CxbxImGui_DrawWidgets() +{ + // Put all ImGui drawing here + + ImGui::ShowDemoWindow(); +} + +static std::mutex imGuiMutex; +static void CxbxImGui_Render(IDirect3DSurface9* renderTarget) +{ + // Some games seem to call Swap concurrently, so we need to ensure only one thread + // at a time can render ImGui + std::unique_lock lock(imGuiMutex, std::try_to_lock); + if (!lock) return; + + ImGui_ImplDX9_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + + CxbxImGui_DrawWidgets(); + + ImGui::Render(); + ImDrawData* drawData = ImGui::GetDrawData(); + if (drawData->TotalVtxCount > 0) { + IDirect3DSurface9* pExistingRenderTarget = nullptr; + if (SUCCEEDED(g_pD3DDevice->GetRenderTarget(0, &pExistingRenderTarget))) { + g_pD3DDevice->SetRenderTarget(0, renderTarget); + ImGui_ImplDX9_RenderDrawData(drawData); + g_pD3DDevice->SetRenderTarget(0, pExistingRenderTarget); + pExistingRenderTarget->Release(); + } + } +} + + /* Unused : static xbox::dword_xt *g_Xbox_D3DDevice; // TODO: This should be a D3DDevice structure */ @@ -633,6 +673,7 @@ void CxbxInitWindow(bool bFullInit) } SetFocus(g_hEmuWindow); + ImGui_ImplWin32_Init(g_hEmuWindow); } void DrawUEM(HWND hWnd) @@ -1804,11 +1845,16 @@ void ToggleFauxFullscreen(HWND hWnd) g_bIsFauxFullscreen = !g_bIsFauxFullscreen; } +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + // rendering window message procedure static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { static bool bAutoPaused = false; + const LRESULT imguiResult = ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam); + if (imguiResult != 0) return imguiResult; + switch(msg) { case WM_DESTROY: @@ -2449,6 +2495,9 @@ static void CreateDefaultD3D9Device // Set up cache g_VertexShaderSource.ResetD3DDevice(g_pD3DDevice); + + // Set up ImGui + ImGui_ImplDX9_Init(g_pD3DDevice); } @@ -5348,6 +5397,9 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(D3DDevice_Swap) } } + // Render ImGui + CxbxImGui_Render(pCurrentHostBackBuffer); + pCurrentHostBackBuffer->Release(); } diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 5bd167979..6b74f13db 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -53,6 +53,7 @@ #include "common/ReserveAddressRanges.h" #include "common/xbox/Types.hpp" #include "common/win32/WineEnv.h" +#include #include #include @@ -1157,6 +1158,17 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res g_ExceptionManager = new ExceptionManager(); // If in need to add VEHs, move this line earlier. (just in case) + // Initialize ImGui + { + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + + ImGuiIO& io = ImGui::GetIO(); + io.IniFilename = nullptr; + + ImGui::StyleColorsDark(); + } + // Launch the XBE : { // Load TLS From f68c706b1ea480fcfddafdf8816ee1c25682d10b Mon Sep 17 00:00:00 2001 From: Silent Date: Tue, 16 Mar 2021 22:15:47 +0100 Subject: [PATCH 04/17] ImGui: Improve style a bit, start hidden --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 23 ++++++++++++++++++----- src/core/hle/D3D8/XbVertexBuffer.cpp | 11 ++++++----- src/core/hle/D3D8/XbVertexBuffer.h | 2 +- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index e8e912403..e4ea32647 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -186,11 +186,22 @@ float g_Xbox_BackbufferScaleY = 1; static constexpr size_t INDEX_BUFFER_CACHE_SIZE = 10000; // ImGui +static bool imGuiShown = false; static void CxbxImGui_DrawWidgets() { + if (!imGuiShown) return; + // Put all ImGui drawing here - ImGui::ShowDemoWindow(); + constexpr float DIST_FROM_CORNER = 10.0f; + ImGui::SetNextWindowPos(ImVec2(DIST_FROM_CORNER, DIST_FROM_CORNER), ImGuiCond_Once, ImVec2(0.0f, 0.0f)); + ImGui::SetNextWindowSize(ImVec2(200, 275), ImGuiCond_Once); + if (ImGui::Begin("Debugging stats", &imGuiShown, ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_AlwaysVerticalScrollbar)) { + if (ImGui::CollapsingHeader("Vertex Buffers", ImGuiTreeNodeFlags_DefaultOpen)) { + VertexBufferConverter.ShowImGuiStats(); + } + ImGui::End(); + } } static std::mutex imGuiMutex; @@ -1946,10 +1957,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar } else if (wParam == VK_F1) { - VertexBufferConverter.PrintStats(); - - extern void DSound_PrintStats(); //TODO: move into plugin class usage. - DSound_PrintStats(); + imGuiShown = !imGuiShown; } else if (wParam == VK_F2) { @@ -1967,6 +1975,11 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar CxbxReleaseCursor(); } } + else if (wParam == VK_F4) + { + extern void DSound_PrintStats(); //TODO: move into plugin class usage. + DSound_PrintStats(); + } else if (wParam == VK_F6) { // For some unknown reason, F6 isn't handled in WndMain::WndProc diff --git a/src/core/hle/D3D8/XbVertexBuffer.cpp b/src/core/hle/D3D8/XbVertexBuffer.cpp index eb3c8d526..d4950fbf6 100644 --- a/src/core/hle/D3D8/XbVertexBuffer.cpp +++ b/src/core/hle/D3D8/XbVertexBuffer.cpp @@ -38,6 +38,8 @@ #include "core\hle\D3D8\XbVertexBuffer.h" #include "core\hle\D3D8\XbConvert.h" +#include + #include #include #include @@ -215,12 +217,11 @@ CxbxPatchedStream& CxbxVertexBufferConverter::GetPatchedStream(uint64_t dataKey, return stream; } -void CxbxVertexBufferConverter::PrintStats() +void CxbxVertexBufferConverter::ShowImGuiStats() { - printf("Vertex Buffer Cache Status: \n"); - printf("- Cache Size: %d\n", m_PatchedStreams.size()); - printf("- Hits: %d\n", m_TotalCacheHits); - printf("- Misses: %d\n", m_TotalCacheMisses); + ImGui::Text("Cache Size: %u", m_PatchedStreams.size()); + ImGui::Text("Hits: %u", std::exchange(m_TotalCacheHits, 0)); + ImGui::Text("Misses: %u", std::exchange(m_TotalCacheMisses, 0)); } void CxbxVertexBufferConverter::ConvertStream diff --git a/src/core/hle/D3D8/XbVertexBuffer.h b/src/core/hle/D3D8/XbVertexBuffer.h index cad1fd7c9..ae59c1e67 100644 --- a/src/core/hle/D3D8/XbVertexBuffer.h +++ b/src/core/hle/D3D8/XbVertexBuffer.h @@ -78,7 +78,7 @@ class CxbxVertexBufferConverter public: CxbxVertexBufferConverter() = default; void Apply(CxbxDrawContext *pPatchDesc); - void PrintStats(); + void ShowImGuiStats(); private: struct StreamKey { From 4985d9ca7ef72f76ee486129bc0646ebda5e1c39 Mon Sep 17 00:00:00 2001 From: Silent Date: Tue, 16 Mar 2021 23:12:37 +0100 Subject: [PATCH 05/17] ImGui: More detailed vertex cache statistics --- src/core/hle/D3D8/XbVertexBuffer.cpp | 16 ++++++++++++++-- src/core/hle/D3D8/XbVertexBuffer.h | 4 +++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/core/hle/D3D8/XbVertexBuffer.cpp b/src/core/hle/D3D8/XbVertexBuffer.cpp index d4950fbf6..9dbaeb48c 100644 --- a/src/core/hle/D3D8/XbVertexBuffer.cpp +++ b/src/core/hle/D3D8/XbVertexBuffer.cpp @@ -193,6 +193,7 @@ CxbxPatchedStream& CxbxVertexBufferConverter::GetPatchedStream(uint64_t dataKey, auto it = m_PatchedStreams.find(key); if (it != m_PatchedStreams.end()) { + m_TotalLookupSuccesses++; m_PatchedStreamUsageList.splice(m_PatchedStreamUsageList.begin(), m_PatchedStreamUsageList, it->second); return *it->second; } @@ -219,9 +220,16 @@ CxbxPatchedStream& CxbxVertexBufferConverter::GetPatchedStream(uint64_t dataKey, void CxbxVertexBufferConverter::ShowImGuiStats() { + const ULONG falsePositives = std::exchange(m_TotalLookupSuccesses, 0) - m_TotalCacheHits; + const ULONG totalMisses = m_VertexStreamHashMisses + m_DataNotInCacheMisses; + ImGui::Text("Cache Size: %u", m_PatchedStreams.size()); ImGui::Text("Hits: %u", std::exchange(m_TotalCacheHits, 0)); - ImGui::Text("Misses: %u", std::exchange(m_TotalCacheMisses, 0)); + ImGui::Text("Total misses: %u", totalMisses); + ImGui::Separator(); + ImGui::TextUnformatted("Cache miss details:"); + ImGui::TextWrapped("Vertex stream hash miss: %u", std::exchange(m_VertexStreamHashMisses, 0)); + ImGui::TextWrapped("Data not in cache: %u", std::exchange(m_DataNotInCacheMisses, 0)); } void CxbxVertexBufferConverter::ConvertStream @@ -340,7 +348,11 @@ void CxbxVertexBufferConverter::ConvertStream return; } - m_TotalCacheMisses++; + // Gather stats + if (patchedStream.uiVertexStreamInformationHash != pVertexShaderSteamInfoHash) + m_VertexStreamHashMisses++; + else + m_DataNotInCacheMisses++; // If execution reaches here, the cached vertex buffer was not valid and we must reconvert the data // Free the existing buffers diff --git a/src/core/hle/D3D8/XbVertexBuffer.h b/src/core/hle/D3D8/XbVertexBuffer.h index ae59c1e67..54e15c1a8 100644 --- a/src/core/hle/D3D8/XbVertexBuffer.h +++ b/src/core/hle/D3D8/XbVertexBuffer.h @@ -99,7 +99,9 @@ class CxbxVertexBufferConverter // Stack tracking ULONG m_TotalCacheHits = 0; - ULONG m_TotalCacheMisses = 0; + ULONG m_TotalLookupSuccesses = 0; + ULONG m_VertexStreamHashMisses = 0; + ULONG m_DataNotInCacheMisses = 0; const UINT m_MaxCacheSize = 10000; // Maximum number of entries in the cache const UINT m_CacheElasticity = 200; // Cache is allowed to grow this much more than maximum before being purged to maximum From 327490a8ed0e4e46966e53d6a204835b2cfac946 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Wed, 17 Mar 2021 09:30:18 -0500 Subject: [PATCH 06/17] input: fix general settings to use simplified getter/setter. --- src/common/Settings.cpp | 7 +++---- src/common/Settings.hpp | 6 ++++-- src/common/input/InputManager.cpp | 17 +++++++---------- src/common/win32/EmuShared.cpp | 1 - src/common/win32/EmuShared.h | 15 +++++---------- src/gui/DlgInputConfig.cpp | 4 +--- 6 files changed, 20 insertions(+), 30 deletions(-) diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index 29f78223c..0158a6175 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -744,7 +744,7 @@ void Settings::SyncToEmulator() // register Network settings g_EmuShared->SetNetworkSettings(&m_network); - // register Input settings + // register Input gamepad settings for (int i = 0; i < 4; i++) { g_EmuShared->SetInputDevTypeSettings(&m_input_port[i].Type, i); if (m_input_port[i].Type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { @@ -766,9 +766,8 @@ void Settings::SyncToEmulator() } } - g_EmuShared->SetInputMoAxisSettings(m_input_general.MoAxisRange); - g_EmuShared->SetInputMoWheelSettings(m_input_general.MoWheelRange); - g_EmuShared->SetInputKbMoUnfocusSettings(m_input_general.IgnoreKbMoUnfocus); + // register Input general settings + g_EmuShared->SetInputGeneralSettings(&m_input_general); // register Hacks settings g_EmuShared->SetHackSettings(&m_hacks); diff --git a/src/common/Settings.hpp b/src/common/Settings.hpp index c55c14671..8dee2ee05 100644 --- a/src/common/Settings.hpp +++ b/src/common/Settings.hpp @@ -134,12 +134,14 @@ public: } m_audio; static_assert(sizeof(s_audio) == 0x4C, assert_check_shared_memory(s_audio)); + // Input general settings struct s_input_general { long MoAxisRange; long MoWheelRange; bool IgnoreKbMoUnfocus; - }; - s_input_general m_input_general; + bool Reserved1[3]; + } m_input_general; + static_assert(sizeof(s_input_general) == 0xC, assert_check_shared_memory(s_input_general)); struct s_input_port { int Type; diff --git a/src/common/input/InputManager.cpp b/src/common/input/InputManager.cpp index bff948690..2e8540eac 100644 --- a/src/common/input/InputManager.cpp +++ b/src/common/input/InputManager.cpp @@ -706,16 +706,13 @@ std::shared_ptr InputDeviceManager::FindDevice(int usb_port, int du void InputDeviceManager::UpdateOpt(bool is_gui) { if (!is_gui) { - long axis_range, wheel_range; - bool ignore_kbmo; - g_EmuShared->GetInputMoAxisSettings(&axis_range); - g_EmuShared->GetInputMoWheelSettings(&wheel_range); - g_EmuShared->GetInputKbMoUnfocusSettings(&ignore_kbmo); - DInput::mo_axis_range_pos = axis_range; - DInput::mo_wheel_range_pos = wheel_range; - DInput::mo_axis_range_neg = -(axis_range); - DInput::mo_wheel_range_neg = -(wheel_range); - DInput::IgnoreKbMoUnfocus = ignore_kbmo; + Settings::s_input_general input_general; + g_EmuShared->GetInputGeneralSettings(&input_general); + DInput::mo_axis_range_pos = input_general.MoAxisRange; + DInput::mo_wheel_range_pos = input_general.MoWheelRange; + DInput::mo_axis_range_neg = -(input_general.MoAxisRange); + DInput::mo_wheel_range_neg = -(input_general.MoWheelRange); + DInput::IgnoreKbMoUnfocus = input_general.IgnoreKbMoUnfocus; } else { DInput::mo_axis_range_pos = g_Settings->m_input_general.MoAxisRange; diff --git a/src/common/win32/EmuShared.cpp b/src/common/win32/EmuShared.cpp index 8fa68d203..ce508ccd0 100644 --- a/src/common/win32/EmuShared.cpp +++ b/src/common/win32/EmuShared.cpp @@ -152,7 +152,6 @@ EmuShared::EmuShared() m_bEmulating_status = false; m_bFirstLaunch = false; m_bClipCursor = false; - m_bIgnoreKbMoUnfocus = true; // Reserve space (default to 0) m_bReserved4 = false; diff --git a/src/common/win32/EmuShared.h b/src/common/win32/EmuShared.h index 40d1e530c..f46a9dca0 100644 --- a/src/common/win32/EmuShared.h +++ b/src/common/win32/EmuShared.h @@ -152,12 +152,8 @@ class EmuShared : public Mutex // ****************************************************************** // * Input option Accessors // ****************************************************************** - void GetInputMoAxisSettings(long *axis) { Lock(); *axis = m_MoAxisRange; Unlock(); } - void SetInputMoAxisSettings(const long axis) { Lock(); m_MoAxisRange = axis; Unlock(); } - void GetInputMoWheelSettings(long *wheel) { Lock(); *wheel = m_MoWheelRange; Unlock(); } - void SetInputMoWheelSettings(const long wheel) { Lock(); m_MoWheelRange = wheel; Unlock(); } - void GetInputKbMoUnfocusSettings(bool *flag) { Lock(); *flag = m_bIgnoreKbMoUnfocus; Unlock(); } - void SetInputKbMoUnfocusSettings(const bool flag) { Lock(); m_bIgnoreKbMoUnfocus = flag; Unlock(); } + void GetInputGeneralSettings(Settings::s_input_general *input_general) { Lock(); *input_general = m_input_general; Unlock(); } + void SetInputGeneralSettings(const Settings::s_input_general *input_general) { Lock(); m_input_general = *input_general; Unlock(); } // ****************************************************************** // * LLE Flags Accessors @@ -301,15 +297,13 @@ class EmuShared : public Mutex #endif bool m_bFirstLaunch; bool m_bClipCursor; - bool m_bIgnoreKbMoUnfocus; + bool m_bReserved3; bool m_bReserved4; unsigned int m_dwKrnlProcID; // Only used for kernel mode level. int m_DeviceType[4]; char m_DeviceControlNames[4][HIGHEST_NUM_BUTTONS][HOST_BUTTON_NAME_LENGTH]; char m_DeviceName[4][50]; - long m_MoAxisRange; - long m_MoWheelRange; - int m_Reserved99[26]; // Reserve space + int m_Reserved99[28]; // Reserve space // Settings class in memory should not be tampered by third-party. // Third-party program should only be allow to edit settings.ini file. @@ -317,6 +311,7 @@ class EmuShared : public Mutex Settings::s_video m_video; Settings::s_audio m_audio; Settings::s_network m_network; + Settings::s_input_general m_input_general; Settings::s_hack m_hacks; }; diff --git a/src/gui/DlgInputConfig.cpp b/src/gui/DlgInputConfig.cpp index 338e3a17c..b614aa38e 100644 --- a/src/gui/DlgInputConfig.cpp +++ b/src/gui/DlgInputConfig.cpp @@ -74,9 +74,7 @@ void SyncInputSettings(int port_num, int dev_type, bool is_opt) } } else { - g_EmuShared->SetInputMoAxisSettings(g_Settings->m_input_general.MoAxisRange); - g_EmuShared->SetInputMoWheelSettings(g_Settings->m_input_general.MoWheelRange); - g_EmuShared->SetInputKbMoUnfocusSettings(g_Settings->m_input_general.IgnoreKbMoUnfocus); + g_EmuShared->SetInputGeneralSettings(&g_Settings->m_input_general); port_num = PORT_INVALID; } #if 0 // lle usb From 5c4e6945dcaaf123d0aabf973c5bd8eac73c0715 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Wed, 17 Mar 2021 09:51:27 -0500 Subject: [PATCH 07/17] input: remove unnecessary pointer since const exists in parameter. --- src/common/win32/EmuShared.h | 4 ++-- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 2 +- src/gui/WndMain.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/win32/EmuShared.h b/src/common/win32/EmuShared.h index f46a9dca0..e727a9f88 100644 --- a/src/common/win32/EmuShared.h +++ b/src/common/win32/EmuShared.h @@ -196,7 +196,7 @@ class EmuShared : public Mutex // * Debugging flag Accessors // ****************************************************************** void GetDebuggingFlag(bool *value) { Lock(); *value = m_bDebugging; Unlock(); } - void SetDebuggingFlag(const bool *value) { Lock(); m_bDebugging = *value; Unlock(); } + void SetDebuggingFlag(const bool value) { Lock(); m_bDebugging = value; Unlock(); } #ifndef CXBX_LOADER // Temporary usage for cxbx.exe's emu // ****************************************************************** // * Previous Memory Layout value Accessors @@ -246,7 +246,7 @@ class EmuShared : public Mutex // * ClipCursor flag Accessors // ****************************************************************** void GetClipCursorFlag(bool *value) { Lock(); *value = m_bClipCursor; Unlock(); } - void SetClipCursorFlag(const bool *value) { Lock(); m_bClipCursor = *value; Unlock(); } + void SetClipCursorFlag(const bool value) { Lock(); m_bClipCursor = value; Unlock(); } // ****************************************************************** // * Reset specific variables to default for kernel mode. diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index e4ea32647..9ed5c7c86 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -1966,7 +1966,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar else if (wParam == VK_F3) { g_bClipCursor = !g_bClipCursor; - g_EmuShared->SetClipCursorFlag(&g_bClipCursor); + g_EmuShared->SetClipCursorFlag(g_bClipCursor); if (g_bClipCursor) { CxbxClipCursor(hWnd); diff --git a/src/gui/WndMain.cpp b/src/gui/WndMain.cpp index 6541142f9..ce77ee43c 100644 --- a/src/gui/WndMain.cpp +++ b/src/gui/WndMain.cpp @@ -2330,7 +2330,7 @@ void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState / } bool AttachLocalDebugger = (LocalDebuggerState == debuggerOn); - g_EmuShared->SetDebuggingFlag(&AttachLocalDebugger); + g_EmuShared->SetDebuggingFlag(AttachLocalDebugger); /* Main process to generate emulation command line begin. */ // If we are adding more arguments, this is the place to do so. From 23681729a5708e009ea6825ac0ad19595a5be8cc Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Wed, 17 Mar 2021 11:50:51 -0500 Subject: [PATCH 08/17] input: fix bugged ShowCursor when redundant call occur with same value --- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 32 +++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 9ed5c7c86..cd3dc4ec6 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -761,6 +761,27 @@ void CxbxReleaseCursor() ClipCursor(nullptr); } +static void CxbxUpdateCursor(bool forceShow = false) { + // Getting cursor info is a requirement in order to prevent a bug occur with ShowCursor redundant calls. + CURSORINFO cursorInfo; + cursorInfo.cbSize = sizeof(cursorInfo); + if (!GetCursorInfo(&cursorInfo)) { + // If cursor info is not available, then ignore the cursor update. + return; + } + + if (imGuiShown || forceShow) { + if (cursorInfo.flags == 0) { + ShowCursor(TRUE); + } + } + else { + if ((cursorInfo.flags & CURSOR_SHOWING) != 0) { + ShowCursor(FALSE); + } + } +} + inline DWORD GetXboxCommonResourceType(const xbox::dword_xt XboxResource_Common) { DWORD dwCommonType = XboxResource_Common & X_D3DCOMMON_TYPE_MASK; @@ -1868,6 +1889,12 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar switch(msg) { + case WM_CREATE: + { + CxbxUpdateCursor(); + } + break; + case WM_DESTROY: { CxbxReleaseCursor(); @@ -1958,6 +1985,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar else if (wParam == VK_F1) { imGuiShown = !imGuiShown; + CxbxUpdateCursor(); } else if (wParam == VK_F2) { @@ -2066,7 +2094,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar DInput::mo_leave_wnd = true; g_bIsTrackingMoLeave = false; g_bIsTrackingMoMove = true; - ShowCursor(TRUE); + CxbxUpdateCursor(true); } break; @@ -2083,7 +2111,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar tme.dwFlags = TME_LEAVE; TrackMouseEvent(&tme); g_bIsTrackingMoLeave = true; - ShowCursor(FALSE); + CxbxUpdateCursor(); if (g_bIsTrackingMoMove) { DInput::mo_leave_wnd = false; From 9885859916dc2ffe95b31a3e5b50846cc1aeec4e Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Wed, 17 Mar 2021 13:27:28 -0500 Subject: [PATCH 09/17] ImGui: make functional imgui integration along with basic features --- CMakeLists.txt | 11 ++ projects/imgui/CMakeLists.txt | 2 +- src/common/IPCHybrid.hpp | 1 + src/common/Settings.cpp | 22 +++ src/common/Settings.hpp | 4 + src/common/input/InputManager.cpp | 4 +- src/common/win32/EmuShared.cpp | 4 + src/common/win32/EmuShared.h | 42 +++++ src/common/win32/IPCWindows.cpp | 4 + src/core/common/imgui/audio.cpp | 37 ++++ src/core/common/imgui/audio.hpp | 24 +++ src/core/common/imgui/settings.h | 53 ++++++ src/core/common/imgui/ui.cpp | 161 ++++++++++++++++++ src/core/common/imgui/ui.hpp | 67 ++++++++ src/core/common/imgui/video.cpp | 40 +++++ src/core/common/imgui/video.hpp | 23 +++ src/core/common/video/RenderBase.cpp | 31 ++++ src/core/common/video/RenderBase.hpp | 29 ++++ src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 61 +++---- .../DSOUND/DirectSound/DirectSoundGlobal.cpp | 160 +++++++++-------- src/core/kernel/init/CxbxKrnl.cpp | 11 -- src/devices/video/EmuNV2A_PGRAPH.cpp | 25 +++ src/devices/video/nv2a.cpp | 9 +- src/gui/WndMain.cpp | 3 + src/gui/resource/ResCxbx.h | 1 + 25 files changed, 708 insertions(+), 121 deletions(-) create mode 100644 src/core/common/imgui/audio.cpp create mode 100644 src/core/common/imgui/audio.hpp create mode 100644 src/core/common/imgui/settings.h create mode 100644 src/core/common/imgui/ui.cpp create mode 100644 src/core/common/imgui/ui.hpp create mode 100644 src/core/common/imgui/video.cpp create mode 100644 src/core/common/imgui/video.hpp create mode 100644 src/core/common/video/RenderBase.cpp create mode 100644 src/core/common/video/RenderBase.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 06810163f..859d76ea6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,6 +115,7 @@ file (GLOB CXBXR_HEADER_GUIv1 # Emulator (module) file (GLOB CXBXR_HEADER_EMU_IMPORT "${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_dx9.h" + "${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_opengl3.h" "${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_win32.h" ) file (GLOB CXBXR_HEADER_EMU @@ -124,6 +125,11 @@ file (GLOB CXBXR_HEADER_EMU "${CXBXR_ROOT_DIR}/src/common/util/gloffscreen/gloffscreen.h" "${CXBXR_ROOT_DIR}/src/common/audio/XADPCM.h" "${CXBXR_ROOT_DIR}/src/common/xbox/Logging.hpp" + "${CXBXR_ROOT_DIR}/src/core/common/imgui/audio.hpp" + "${CXBXR_ROOT_DIR}/src/core/common/imgui/ui.hpp" + "${CXBXR_ROOT_DIR}/src/core/common/imgui/settings.h" + "${CXBXR_ROOT_DIR}/src/core/common/imgui/video.hpp" + "${CXBXR_ROOT_DIR}/src/core/common/video/RenderBase.hpp" "${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/CxbxVertexShaderTemplate.hlsl" "${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/Direct3D9.h" "${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/FixedFunctionVertexShader.hlsl" @@ -270,6 +276,7 @@ file (GLOB CXBXR_KRNL_CPP ) file (GLOB CXBXR_SOURCE_EMU_IMPORT "${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_dx9.cpp" + "${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_opengl3.cpp" "${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_win32.cpp" ) file (GLOB CXBXR_SOURCE_EMU @@ -280,6 +287,10 @@ file (GLOB CXBXR_SOURCE_EMU "${CXBXR_ROOT_DIR}/src/common/util/gloffscreen/gloffscreen_common.cpp" "${CXBXR_ROOT_DIR}/src/common/util/gloffscreen/gloffscreen_wgl.cpp" "${CXBXR_ROOT_DIR}/src/common/xbox/Logging.cpp" + "${CXBXR_ROOT_DIR}/src/core/common/imgui/audio.cpp" + "${CXBXR_ROOT_DIR}/src/core/common/imgui/ui.cpp" + "${CXBXR_ROOT_DIR}/src/core/common/imgui/video.cpp" + "${CXBXR_ROOT_DIR}/src/core/common/video/RenderBase.cpp" "${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp" "${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/RenderStates.cpp" "${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/TextureStates.cpp" diff --git a/projects/imgui/CMakeLists.txt b/projects/imgui/CMakeLists.txt index 3c6e0a296..0e3fbb765 100644 --- a/projects/imgui/CMakeLists.txt +++ b/projects/imgui/CMakeLists.txt @@ -9,7 +9,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") ) endif() -# Add any defines from imconfig.h file in here without need to use import file directly. +# Add any defines from imconfig.h file in here without need to edit import file directly. add_compile_definitions( IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS diff --git a/src/common/IPCHybrid.hpp b/src/common/IPCHybrid.hpp index 25fea5151..079a1baaf 100644 --- a/src/common/IPCHybrid.hpp +++ b/src/common/IPCHybrid.hpp @@ -38,6 +38,7 @@ typedef enum class _IPC_UPDATE_GUI { , XBOX_LED_COLOUR , LOG_ENABLED , KRNL_IS_READY + , OVERLAY } IPC_UPDATE_GUI; void ipc_send_gui_update(IPC_UPDATE_GUI command, const unsigned int value); diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index 0158a6175..815cb4786 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -112,6 +112,12 @@ static struct { const char* RenderResolution = "RenderResolution"; } sect_video_keys; +static const char* section_overlay = "overlay"; +static struct { + const char* FPS = "FPS"; + const char* hle_lle_stats = "HLE/LLE Stats"; +} sect_overlay_keys; + static const char* section_audio = "audio"; static struct { const char* adapter = "adapter"; @@ -523,6 +529,13 @@ bool Settings::LoadConfig() // ==== Input Profile End ====== + // ==== Overlay Begin ========= + + m_overlay.fps = m_si.GetBoolValue(section_overlay, sect_overlay_keys.FPS, true); + m_overlay.hle_lle_stats = m_si.SetBoolValue(section_overlay, sect_overlay_keys.hle_lle_stats, true); + + // ==== Overlay End =========== + return true; } @@ -588,6 +601,7 @@ bool Settings::Save(std::string file_path) m_si.SetBoolValue(section_video, sect_video_keys.FullScreen, m_video.bFullScreen, nullptr, true); m_si.SetBoolValue(section_video, sect_video_keys.MaintainAspect, m_video.bMaintainAspect, nullptr, true); m_si.SetLongValue(section_video, sect_video_keys.RenderResolution, m_video.renderScaleFactor, nullptr, false, true); + // ==== Video End =========== // ==== Audio Begin ========= @@ -700,6 +714,13 @@ bool Settings::Save(std::string file_path) // ==== Input Profile End ====== + // ==== Overlay Begin ======= + + m_si.SetBoolValue(section_overlay, sect_overlay_keys.FPS, m_overlay.fps, nullptr, true); + m_si.SetBoolValue(section_overlay, sect_overlay_keys.hle_lle_stats, m_overlay.hle_lle_stats, nullptr, true); + + // ==== Overlay End ========= + // ==== Hack Begin ========== m_si.SetBoolValue(section_hack, sect_hack_keys.DisablePixelShaders, m_hacks.DisablePixelShaders, nullptr, true); @@ -737,6 +758,7 @@ void Settings::SyncToEmulator() // register Video settings g_EmuShared->SetVideoSettings(&m_video); + g_EmuShared->SetOverlaySettings(&m_overlay); // register Audio settings g_EmuShared->SetAudioSettings(&m_audio); diff --git a/src/common/Settings.hpp b/src/common/Settings.hpp index 8dee2ee05..013652272 100644 --- a/src/common/Settings.hpp +++ b/src/common/Settings.hpp @@ -34,6 +34,8 @@ #include #include +#include "core/common/imgui/settings.h" + extern std::string g_exec_filepath; // Individual library version @@ -181,6 +183,8 @@ public: } m_hacks; static_assert(sizeof(s_hack) == 0x28, assert_check_shared_memory(s_hack)); + overlay_settings m_overlay; + private: void RemoveLegacyConfigs(unsigned int CurrentRevision); std::string m_file_path = ""; diff --git a/src/common/input/InputManager.cpp b/src/common/input/InputManager.cpp index 2e8540eac..1be97c882 100644 --- a/src/common/input/InputManager.cpp +++ b/src/common/input/InputManager.cpp @@ -45,6 +45,7 @@ #include "core\kernel\exports\EmuKrnl.h" // For EmuLog #include "EmuShared.h" #include "devices\usb\OHCI.h" +#include "core/common/video/RenderBase.hpp" // hle input specific #include "core\hle\XAPI\Xapi.h" @@ -360,8 +361,9 @@ bool InputDeviceManager::UpdateXboxPortInput(int usb_port, void* Buffer, int Dir xid_type < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)); bool has_changed = false; + // First check if ImGui is focus, then ignore any input update occur. // If somebody else is currently holding the lock, we won't wait and instead report no input changes - if (m_Mtx.try_lock()) { + if (!g_renderbase->IsImGuiFocus() && m_Mtx.try_lock()) { for (auto &dev_ptr : m_Devices) { if (dev_ptr->GetPort(usb_port)) { switch (xid_type) diff --git a/src/common/win32/EmuShared.cpp b/src/common/win32/EmuShared.cpp index ce508ccd0..e3ecea7d8 100644 --- a/src/common/win32/EmuShared.cpp +++ b/src/common/win32/EmuShared.cpp @@ -161,6 +161,10 @@ EmuShared::EmuShared() std::memset(m_Reserved99, 0, sizeof(m_Reserved99)); std::memset(m_DeviceControlNames, '\0', sizeof(m_DeviceControlNames)); std::memset(m_DeviceName, '\0', sizeof(m_DeviceName)); + m_imgui_general.ini_size = IMGUI_INI_SIZE_MAX; + std::memset(&m_imgui_general.ini_settings, 0, sizeof(m_imgui_general.ini_settings)); + std::memset(&m_imgui_audio_windows, 0, sizeof(m_imgui_audio_windows)); + std::memset(&m_imgui_video_windows, 0, sizeof(m_imgui_video_windows)); for (auto& i : m_DeviceType) { i = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID); } diff --git a/src/common/win32/EmuShared.h b/src/common/win32/EmuShared.h index e727a9f88..4fcd35b70 100644 --- a/src/common/win32/EmuShared.h +++ b/src/common/win32/EmuShared.h @@ -30,6 +30,7 @@ #include "Mutex.h" #include "common\IPCHybrid.hpp" #include "common\input\Button.h" +#include "core/common/imgui/settings.h" #include @@ -248,6 +249,43 @@ class EmuShared : public Mutex void GetClipCursorFlag(bool *value) { Lock(); *value = m_bClipCursor; Unlock(); } void SetClipCursorFlag(const bool value) { Lock(); m_bClipCursor = value; Unlock(); } + // ****************************************************************** + // * ImGui Accessors + // ****************************************************************** + void GetImGuiFocusFlag(bool *value) { Lock(); *value = m_imgui_general.is_focus; Unlock(); } + void SetImGuiFocusFlag(const bool value) { Lock(); m_imgui_general.is_focus = value; Unlock(); } + + void GetImGuiIniSettings(char value[IMGUI_INI_SIZE_MAX]) { + Lock(); + if (m_imgui_general.ini_size < IMGUI_INI_SIZE_MAX) { + value = '\0'; + return; + } + strcpy_s(value, IMGUI_INI_SIZE_MAX, m_imgui_general.ini_settings); + Unlock(); + } + void SetImGuiIniSettings(const char value[IMGUI_INI_SIZE_MAX]) { + Lock(); + // Do not save if external size is less than internal limit + if (m_imgui_general.ini_size < IMGUI_INI_SIZE_MAX) { + return; + } + strcpy_s(m_imgui_general.ini_settings, IMGUI_INI_SIZE_MAX, value); + Unlock(); + } + + void GetImGuiAudioWindows(imgui_audio_windows *value) { Lock(); *value = m_imgui_audio_windows; Unlock(); } + void SetImGuiAudioWindows(const imgui_audio_windows* value) { Lock(); m_imgui_audio_windows = *value; Unlock(); } + void GetImGuiVideoWindows(imgui_video_windows*value) { Lock(); *value = m_imgui_video_windows; Unlock(); } + void SetImGuiVideoWindows(const imgui_video_windows* value) { Lock(); m_imgui_video_windows = *value; Unlock(); } + + + // ****************************************************************** + // * Overlay Accessors + // ****************************************************************** + void GetOverlaySettings(overlay_settings *value) { Lock(); *value = m_imgui_overlay_settings; Unlock(); } + void SetOverlaySettings(const overlay_settings* value) { Lock(); m_imgui_overlay_settings = *value; Unlock(); } + // ****************************************************************** // * Reset specific variables to default for kernel mode. // ****************************************************************** @@ -313,6 +351,10 @@ class EmuShared : public Mutex Settings::s_network m_network; Settings::s_input_general m_input_general; Settings::s_hack m_hacks; + imgui_general m_imgui_general; + overlay_settings m_imgui_overlay_settings; + imgui_audio_windows m_imgui_audio_windows; + imgui_video_windows m_imgui_video_windows; }; // ****************************************************************** diff --git a/src/common/win32/IPCWindows.cpp b/src/common/win32/IPCWindows.cpp index fc3c41228..f95083b6a 100644 --- a/src/common/win32/IPCWindows.cpp +++ b/src/common/win32/IPCWindows.cpp @@ -65,6 +65,10 @@ void ipc_send_gui_update(IPC_UPDATE_GUI command, const unsigned int value) cmdParam = ID_GUI_STATUS_KRNL_IS_READY; break; + case IPC_UPDATE_GUI::OVERLAY: + cmdParam = ID_GUI_STATUS_OVERLAY; + break; + default: cmdParam = 0; break; diff --git a/src/core/common/imgui/audio.cpp b/src/core/common/imgui/audio.cpp new file mode 100644 index 000000000..ba7637ca8 --- /dev/null +++ b/src/core/common/imgui/audio.cpp @@ -0,0 +1,37 @@ +// Copyright 2021 Cxbx-Reloaded Project +// Licensed under GPLv2+ +// Refer to the COPYING file included. + +#define LOG_PREFIX CXBXR_MODULE::GUI + +#include + +#include "audio.hpp" + +#include "EmuShared.h" + +bool ImGuiAudio::Initialize() +{ + g_EmuShared->GetImGuiAudioWindows(&m_windows); + return true; +} + +void ImGuiAudio::Shutdown() +{ + g_EmuShared->SetImGuiAudioWindows(&m_windows); +} + +void ImGuiAudio::DrawMenu() +{ + if (ImGui::BeginMenu("Audio")) { + ImGui::MenuItem("Debug General Cache Stats", NULL, &m_windows.cache_stats_general); + ImGui::EndMenu(); + } +} + +void ImGuiAudio::DrawWidgets(bool is_focus, ImGuiWindowFlags input_handler) +{ + //TODO: In need of make interface class to return generic info in some way. + extern void DSound_PrintStats(bool, ImGuiWindowFlags, bool m_show_audio_stats); + DSound_PrintStats(is_focus, input_handler, m_windows.cache_stats_general); +} diff --git a/src/core/common/imgui/audio.hpp b/src/core/common/imgui/audio.hpp new file mode 100644 index 000000000..90cd65935 --- /dev/null +++ b/src/core/common/imgui/audio.hpp @@ -0,0 +1,24 @@ +// Copyright 2021 Cxbx-Reloaded Project +// Licensed under GPLv2+ +// Refer to the COPYING file included. +#pragma once + +#include +#include "settings.h" + +class ImGuiAudio +{ +public: + ImGuiAudio() = default; + virtual ~ImGuiAudio() = default; + + bool Initialize(); + void Shutdown(); + + void DrawMenu(); + void DrawWidgets(bool is_focus, ImGuiWindowFlags input_handler); + +protected: + + imgui_audio_windows m_windows; +}; diff --git a/src/core/common/imgui/settings.h b/src/core/common/imgui/settings.h new file mode 100644 index 000000000..a1790545a --- /dev/null +++ b/src/core/common/imgui/settings.h @@ -0,0 +1,53 @@ +// ****************************************************************** +// * +// * This file is part of the Cxbx-Reloaded project. +// * +// * Cxbx and Cxbe are free software; you can redistribute them +// * and/or modify them under the terms of the GNU General Public +// * License as published by the Free Software Foundation; either +// * version 2 of the license, or (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU General Public License for more details. +// * +// * You should have recieved a copy of the GNU General Public License +// * along with this program; see the file COPYING. +// * If not, write to the Free Software Foundation, Inc., +// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA. +// * +// * (c) 2021 RadWolfie +// * +// * All rights reserved +// * +// ****************************************************************** +#pragma once + +// Intended to store as permanent settings + +typedef struct { + bool fps; + bool hle_lle_stats; +} overlay_settings; + +// Intended for EmuShared only below + +const int IMGUI_INI_SIZE_MAX = 1024; + +typedef struct { + bool is_focus; + bool Reserved[3]; + int ini_size; // Cannot be touch anywhere except EmuShared's constructor. + char ini_settings[IMGUI_INI_SIZE_MAX]; +} imgui_general; + +typedef struct { + bool cache_stats_general; + bool Reserved[3]; +} imgui_audio_windows; + +typedef struct { + bool cache_stats_vertex; + bool Reserved[3]; +} imgui_video_windows; diff --git a/src/core/common/imgui/ui.cpp b/src/core/common/imgui/ui.cpp new file mode 100644 index 000000000..792226ce0 --- /dev/null +++ b/src/core/common/imgui/ui.cpp @@ -0,0 +1,161 @@ +// Copyright 2021 Cxbx-Reloaded Project +// Licensed under GPLv2+ +// Refer to the COPYING file included. +// +// Copyright 2010 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the COPYING file included. + +#define LOG_PREFIX CXBXR_MODULE::GUI + +#include + +#include "ui.hpp" +#include "EmuShared.h" + +#include "core/kernel/init/CxbxKrnl.h" + +bool ImGuiUI::Initialize() +{ + IMGUI_CHECKVERSION(); + m_imgui_context = ImGui::CreateContext(); + if (!m_imgui_context) { + CxbxKrnlCleanup("Unable to create ImGui context!"); + return false; + } + + ImGuiIO& io = ImGui::GetIO(); +#if 0 // TODO: Currently most voted for memory, so this block of code is disabled. And may will add an option between file vs memory. + // May be best ideal to do manual update call than ImGui's internal auto update. + g_EmuShared->GetStorageLocation(m_file_path); + if (m_file_path[0] == '\0') { + return false; + } + strcat_s(m_file_path, "/imgui.ini"); + io.IniFilename = m_file_path; +#else + io.IniFilename = nullptr; + char temp_ini_settings[IMGUI_INI_SIZE_MAX]; + g_EmuShared->GetImGuiIniSettings(temp_ini_settings); + ImGui::LoadIniSettingsFromMemory(temp_ini_settings, IMGUI_INI_SIZE_MAX); +#endif + + ImGui::StyleColorsDark(); + g_EmuShared->GetImGuiFocusFlag(&m_is_focus); + + g_EmuShared->GetOverlaySettings(&m_settings); + g_EmuShared->GetFlagsLLE(&m_lle_flags); + m_audio.Initialize(); + m_video.Initialize(); + + return true; +} + +void ImGuiUI::Shutdown() +{ + size_t ini_size = IMGUI_INI_SIZE_MAX; + const char* temp_ini_settings = ImGui::SaveIniSettingsToMemory(&ini_size); + if (ini_size > IMGUI_INI_SIZE_MAX) { + CxbxKrnlCleanup("ImGui ini settings is too large: %d > %d (IMGUI_INI_SIZE_MAX)", ini_size, IMGUI_INI_SIZE_MAX); + } + g_EmuShared->SetImGuiIniSettings(temp_ini_settings); + g_EmuShared->SetOverlaySettings(&m_settings); + m_audio.Shutdown(); + m_video.Shutdown(); + ImGui::EndFrame(); + ImGui::DestroyContext(m_imgui_context); +} + +bool ImGuiUI::IsImGuiFocus() +{ + return m_is_focus; +} + +void ImGuiUI::ToggleImGui() +{ + m_is_focus = !m_is_focus; + g_EmuShared->SetImGuiFocusFlag(m_is_focus); +} + +void ImGuiUI::DrawMenu() +{ + if (!m_is_focus) { + return; + } + if (ImGui::BeginMainMenuBar()) { + if (ImGui::BeginMenu("Settings")) { + if (ImGui::BeginMenu("Overlay")) { + bool bChanged = false; + bChanged |= ImGui::MenuItem("Show FPS", NULL, &m_settings.fps); + bChanged |= ImGui::MenuItem("Show HLE/LLE Stats", NULL, &m_settings.hle_lle_stats); + if (bChanged) { + g_EmuShared->SetOverlaySettings(&m_settings); + ipc_send_gui_update(IPC_UPDATE_GUI::OVERLAY, 1); + } + ImGui::EndMenu(); + } + ImGui::EndMenu(); + } + + m_video.DrawMenu(); + m_audio.DrawMenu(); + ImGui::EndMainMenuBar(); + } +} + +void ImGuiUI::DrawWidgets() +{ + if (m_settings.fps || m_settings.hle_lle_stats) { + + ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x - (IMGUI_MIN_DIST_SIDE/* * m_backbuffer_scale*/), + IMGUI_MIN_DIST_TOP/* * m_backbuffer_scale*/), ImGuiCond_Always, ImVec2(1.0f, 0.0f)); + + ImGui::SetNextWindowSize(ImVec2(200.0f/* * m_backbuffer_scale*/, 0.0f)); + ImGui::SetNextWindowBgAlpha(0.5f); + if (ImGui::Begin("overlay_stats", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoNav | + ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoScrollbar | + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing)) { + + if (m_settings.fps) { + + float fps_counter; + g_EmuShared->GetCurrentFPS(&fps_counter); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "FPS: %.2f MS / F : %.2f", fps_counter, (float)(1000.0 / fps_counter)); + } + + if (m_settings.hle_lle_stats) { + std::string flagString = "LLE-"; + + // TODO: Need improvement in upstream for all of bLLE_xxx globals + // Set LLE flags string based on selected LLE flags + if (m_lle_flags & LLE_APU) { + flagString.append("A"); + } + if (m_lle_flags & LLE_GPU) { + flagString.append("G"); + } + if (m_lle_flags & LLE_USB) { + flagString.append("U"); + } + if (m_lle_flags & LLE_JIT) { + flagString.append("J"); + } + if (m_lle_flags == 0) { + flagString = "HLE"; + } + + // Align text to the right + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetWindowWidth() - ImGui::CalcTextSize(flagString.c_str()).x + - ImGui::GetScrollX() - 2 * ImGui::GetStyle().ItemSpacing.x); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), flagString.c_str()); + } + ImGui::End(); + } + } + + ImGuiWindowFlags input_handler = m_is_focus ? ImGuiWindowFlags_None : ImGuiWindowFlags_NoInputs; + + m_video.DrawWidgets(m_is_focus, input_handler); + + m_audio.DrawWidgets(m_is_focus, input_handler); +} diff --git a/src/core/common/imgui/ui.hpp b/src/core/common/imgui/ui.hpp new file mode 100644 index 000000000..931547437 --- /dev/null +++ b/src/core/common/imgui/ui.hpp @@ -0,0 +1,67 @@ +// Copyright 2021 Cxbx-Reloaded Project +// Licensed under GPLv2+ +// Refer to the COPYING file included. +// +// Copyright 2010 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the COPYING file included. + +#pragma once + +#include + +#include +#include + +#include "settings.h" +#include "audio.hpp" +#include "video.hpp" + +constexpr float IMGUI_MIN_DIST_TOP = 20.0f; +constexpr float IMGUI_MIN_DIST_SIDE = 1.0f; + +class ImGuiUI +{ +public: + ImGuiUI() = default; + virtual ~ImGuiUI() = default; + + void ToggleImGui(); + bool IsImGuiFocus(); + + void DrawMenu(); + void DrawWidgets(); + +protected: + + bool Initialize(); + void Shutdown(); + + template + void Render(C callback, T arg) + { + // Some games seem to call Swap concurrently, so we need to ensure only one thread + // at a time can render ImGui + std::unique_lock lock(m_imgui_mutex, std::try_to_lock); + if (!lock) return; + + callback(this, arg); + } + + std::mutex m_imgui_mutex; + ImGuiContext* m_imgui_context; + char m_file_path[FILENAME_MAX+1]; + bool m_is_focus; + // Using as their own member than integrate may be helpful to bind different plugin at latter change? + ImGuiAudio m_audio; + ImGuiVideo m_video; + overlay_settings m_settings; + unsigned int m_lle_flags; + // Make them as settings storage. + /*bool m_show_fps; + bool m_show_LLE_stats; + // Make them as memory storage. + bool m_show_vertex_stats; + bool m_show_audio_stats; + */ +}; diff --git a/src/core/common/imgui/video.cpp b/src/core/common/imgui/video.cpp new file mode 100644 index 000000000..f1d6e57f2 --- /dev/null +++ b/src/core/common/imgui/video.cpp @@ -0,0 +1,40 @@ +// Copyright 2021 Cxbx-Reloaded Project +// Licensed under GPLv2+ +// Refer to the COPYING file included. + +#define LOG_PREFIX CXBXR_MODULE::GUI + +#include + +#include "video.hpp" +#include "ui.hpp" + +#include "EmuShared.h" + +#include "core/kernel/init/CxbxKrnl.h" + +bool ImGuiVideo::Initialize() +{ + g_EmuShared->GetImGuiVideoWindows(&m_windows); + return true; +} + +void ImGuiVideo::Shutdown() +{ + g_EmuShared->SetImGuiVideoWindows(&m_windows); +} + +void ImGuiVideo::DrawMenu() +{ + if (ImGui::BeginMenu("Video")) { + ImGui::MenuItem("Show Vertex Stats", NULL, &m_windows.cache_stats_vertex); + ImGui::EndMenu(); + } +} + +void ImGuiVideo::DrawWidgets(bool is_focus, ImGuiWindowFlags input_handler) +{ + //TODO: move into plugin class usage. + extern void CxbxImGui_Video_DrawWidgets(bool, ImGuiWindowFlags, bool); + CxbxImGui_Video_DrawWidgets(is_focus, input_handler, m_windows.cache_stats_vertex); +} diff --git a/src/core/common/imgui/video.hpp b/src/core/common/imgui/video.hpp new file mode 100644 index 000000000..687e18055 --- /dev/null +++ b/src/core/common/imgui/video.hpp @@ -0,0 +1,23 @@ +// Copyright 2021 Cxbx-Reloaded Project +// Licensed under GPLv2+ +// Refer to the COPYING file included. +#pragma once + +#include +#include "settings.h" + +class ImGuiVideo +{ +public: + ImGuiVideo() = default; + virtual ~ImGuiVideo() = default; + + bool Initialize(); + void Shutdown(); + + void DrawMenu(); + void DrawWidgets(bool is_focus, ImGuiWindowFlags input_handler); + +protected: + imgui_video_windows m_windows; +}; diff --git a/src/core/common/video/RenderBase.cpp b/src/core/common/video/RenderBase.cpp new file mode 100644 index 000000000..288a5f5e3 --- /dev/null +++ b/src/core/common/video/RenderBase.cpp @@ -0,0 +1,31 @@ +// Copyright 2021 Cxbx-Reloaded Project +// Licensed under GPLv2+ +// Refer to the COPYING file included. +// +// Copyright 2010 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the COPYING file included. + +//#define LOG_PREFIX CXBXR_MODULE::GUI + +#include + +#include "RenderBase.hpp" + +//#include "core/kernel/init/CxbxKrnl.h" + +std::unique_ptr g_renderbase; + +bool RenderBase::Initialize() +{ + if (!ImGuiUI::Initialize()) { + return false; + } + + return true; +} + +void RenderBase::Shutdown() +{ + ImGuiUI::Shutdown(); +} diff --git a/src/core/common/video/RenderBase.hpp b/src/core/common/video/RenderBase.hpp new file mode 100644 index 000000000..062a5c65a --- /dev/null +++ b/src/core/common/video/RenderBase.hpp @@ -0,0 +1,29 @@ +// Copyright 2021 Cxbx-Reloaded Project +// Licensed under GPLv2+ +// Refer to the COPYING file included. +// +// Copyright 2010 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the COPYING file included. + +#pragma once + +#include "../imgui/ui.hpp" + +class RenderBase : public ImGuiUI +{ +public: + RenderBase() = default; + virtual ~RenderBase() = default; + + virtual bool Initialize(); + virtual void Shutdown(); + + template + void Render(std::function callback, T arg) + { + ImGuiUI::Render(callback, arg); + } +}; + +extern std::unique_ptr g_renderbase; diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index cd3dc4ec6..80dcb6f6e 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -64,6 +64,7 @@ #include #include #include +#include "core/common/video/RenderBase.hpp" #include #include @@ -186,37 +187,28 @@ float g_Xbox_BackbufferScaleY = 1; static constexpr size_t INDEX_BUFFER_CACHE_SIZE = 10000; // ImGui -static bool imGuiShown = false; -static void CxbxImGui_DrawWidgets() +void CxbxImGui_Video_DrawWidgets(bool is_focus, ImGuiWindowFlags input_handler, bool show_vertex_stats) { - if (!imGuiShown) return; - - // Put all ImGui drawing here - - constexpr float DIST_FROM_CORNER = 10.0f; - ImGui::SetNextWindowPos(ImVec2(DIST_FROM_CORNER, DIST_FROM_CORNER), ImGuiCond_Once, ImVec2(0.0f, 0.0f)); - ImGui::SetNextWindowSize(ImVec2(200, 275), ImGuiCond_Once); - if (ImGui::Begin("Debugging stats", &imGuiShown, ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_AlwaysVerticalScrollbar)) { - if (ImGui::CollapsingHeader("Vertex Buffers", ImGuiTreeNodeFlags_DefaultOpen)) { - VertexBufferConverter.ShowImGuiStats(); + if (show_vertex_stats) { + ImGui::SetNextWindowPos(ImVec2(IMGUI_MIN_DIST_SIDE, IMGUI_MIN_DIST_TOP), ImGuiCond_FirstUseEver, ImVec2(0.0f, 0.0f)); + ImGui::SetNextWindowSize(ImVec2(200, 275), ImGuiCond_FirstUseEver); + if (ImGui::Begin("Debugging stats", nullptr, input_handler | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysVerticalScrollbar)) { + if (ImGui::CollapsingHeader("Vertex Buffers", ImGuiTreeNodeFlags_DefaultOpen)) { + VertexBufferConverter.ShowImGuiStats(); + } + ImGui::End(); } - ImGui::End(); } } -static std::mutex imGuiMutex; -static void CxbxImGui_Render(IDirect3DSurface9* renderTarget) +static void CxbxImGui_RenderD3D9(ImGuiUI* m_imgui, IDirect3DSurface9* renderTarget) { - // Some games seem to call Swap concurrently, so we need to ensure only one thread - // at a time can render ImGui - std::unique_lock lock(imGuiMutex, std::try_to_lock); - if (!lock) return; - ImGui_ImplDX9_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); - CxbxImGui_DrawWidgets(); + m_imgui->DrawMenu(); + m_imgui->DrawWidgets(); ImGui::Render(); ImDrawData* drawData = ImGui::GetDrawData(); @@ -684,6 +676,8 @@ void CxbxInitWindow(bool bFullInit) } SetFocus(g_hEmuWindow); + g_renderbase = std::unique_ptr(new RenderBase()); + g_renderbase->Initialize(); ImGui_ImplWin32_Init(g_hEmuWindow); } @@ -770,7 +764,7 @@ static void CxbxUpdateCursor(bool forceShow = false) { return; } - if (imGuiShown || forceShow) { + if (g_renderbase->IsImGuiFocus() || forceShow) { if (cursorInfo.flags == 0) { ShowCursor(TRUE); } @@ -1889,16 +1883,11 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar switch(msg) { - case WM_CREATE: - { - CxbxUpdateCursor(); - } - break; - case WM_DESTROY: { CxbxReleaseCursor(); DeleteObject(g_hBgBrush); + g_renderbase->Shutdown(); // TODO: This needs a fix since it may not process correctly due to render thread did not get terminated properly. PostQuitMessage(0); return D3D_OK; // = 0 } @@ -1984,7 +1973,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar } else if (wParam == VK_F1) { - imGuiShown = !imGuiShown; + g_renderbase->ToggleImGui(); CxbxUpdateCursor(); } else if (wParam == VK_F2) @@ -2003,11 +1992,6 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar CxbxReleaseCursor(); } } - else if (wParam == VK_F4) - { - extern void DSound_PrintStats(); //TODO: move into plugin class usage. - DSound_PrintStats(); - } else if (wParam == VK_F6) { // For some unknown reason, F6 isn't handled in WndMain::WndProc @@ -2143,7 +2127,6 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar SetCursor(NULL); return S_OK; // = Is not part of D3D8 handling. } - return DefWindowProc(hWnd, msg, wParam, lParam); } break; @@ -2438,6 +2421,7 @@ static void CreateDefaultD3D9Device // Final release of IDirect3DDevice9 must be called from the window message thread // See https://docs.microsoft.com/en-us/windows/win32/direct3d9/multithreading-issues RunOnWndMsgThread([] { + ImGui_ImplDX9_Shutdown(); g_pD3DDevice->Release(); }); } @@ -2537,8 +2521,8 @@ static void CreateDefaultD3D9Device // Set up cache g_VertexShaderSource.ResetD3DDevice(g_pD3DDevice); - // Set up ImGui - ImGui_ImplDX9_Init(g_pD3DDevice); + // Set up ImGui + ImGui_ImplDX9_Init(g_pD3DDevice); } @@ -5439,7 +5423,8 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(D3DDevice_Swap) } // Render ImGui - CxbxImGui_Render(pCurrentHostBackBuffer); + static std::function internal_render = &CxbxImGui_RenderD3D9; + g_renderbase->Render(internal_render, pCurrentHostBackBuffer); pCurrentHostBackBuffer->Release(); } diff --git a/src/core/hle/DSOUND/DirectSound/DirectSoundGlobal.cpp b/src/core/hle/DSOUND/DirectSound/DirectSoundGlobal.cpp index b761090db..3e367ef68 100644 --- a/src/core/hle/DSOUND/DirectSound/DirectSoundGlobal.cpp +++ b/src/core/hle/DSOUND/DirectSound/DirectSoundGlobal.cpp @@ -26,6 +26,9 @@ // ****************************************************************** #define LOG_PREFIX CXBXR_MODULE::DSOUND +#include +#include "core/common/imgui/ui.hpp" + #include #include #include "DirectSoundGlobal.hpp" @@ -51,83 +54,102 @@ DWORD g_dwXbMemAllocated = 0; DWORD g_dwFree2DBuffers = 0; DWORD g_dwFree3DBuffers = 0; -void DSound_PrintStats() +void DSound_PrintStats(bool is_focus, ImGuiWindowFlags input_handler, bool m_show_audio_stats) { DSoundMutexGuardLock; - std::stringstream ss; - ss << "Stats:" - "\n--DirectSound Cache--"; - ss << "\n\tTotal DSBuffer cache = " << g_pDSoundBufferCache.size(); - ss << "\n\tTotal DSStream cache = " << g_pDSoundStreamCache.size(); + if (m_show_audio_stats) { - // Generate DSBuffer stats + ImGui::SetNextWindowPos(ImVec2(IMGUI_MIN_DIST_SIDE, IMGUI_MIN_DIST_TOP), ImGuiCond_FirstUseEver, ImVec2(0.0f, 0.0f)); + ImGui::SetNextWindowSize(ImVec2(200, 275), ImGuiCond_FirstUseEver); + if (ImGui::Begin("Debugging stats", nullptr, input_handler | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysVerticalScrollbar)) { + if (ImGui::CollapsingHeader("Audio Buffers", ImGuiTreeNodeFlags_DefaultOpen)) { - DWORD dwStatus; - HRESULT hRet; - unsigned index = 0, isActive = 0; + ImGui::Text("DirectSound Cache:"); + ImGui::BulletText("Total DSBuffer cache = %u", g_pDSoundBufferCache.size()); + ImGui::BulletText("Total DSStream cache = %u", g_pDSoundStreamCache.size()); + ImGui::Separator(); - ss << "\nActive DSBuffer cache:"; + // Generate DSBuffer stats - for (const auto& i : g_pDSoundBufferCache) { - const auto& buffer = i->emuDSBuffer; - hRet = buffer->EmuDirectSoundBuffer8->GetStatus(&dwStatus); - if (hRet == DS_OK && (dwStatus & DSBSTATUS_PLAYING) != 0) { - isActive++; - ss << "\n\tDSBufferCache[" << index << "] = " << reinterpret_cast(i); - ss << "\n\t\tstatus = "; - if ((dwStatus & DSBSTATUS_LOOPING) != 0) { - ss << "looping"; - } - else { - ss << "play once"; - } - ss << "\n\t\tX_BufferCacheSize = " << buffer->X_BufferCacheSize; - ss << "\n\t\tEmuFlags = " << buffer->EmuFlags; - ss << "\n\t\tEmuRegionToggle = " << buffer->EmuBufferToggle; - if (buffer->EmuBufferToggle == xbox::X_DSB_TOGGLE_PLAY) { - ss << "\n\t\t\tEmuRegionPlayStartOffset = " << buffer->EmuRegionPlayStartOffset; - ss << "\n\t\t\tEmuRegionPlayLength = " << buffer->EmuRegionPlayLength; - } - else if (buffer->EmuBufferToggle == xbox::X_DSB_TOGGLE_LOOP) { - ss << "\n\t\t\tEmuRegionLoopStartOffset = " << buffer->EmuRegionLoopStartOffset; - ss << "\n\t\t\tEmuRegionLoopLength = " << buffer->EmuRegionLoopLength; + DWORD dwStatus; + HRESULT hRet; + unsigned index = 0, isActive = 0; + + if (ImGui::CollapsingHeader("Active DSBuffer cache")) { + + for (const auto& i : g_pDSoundBufferCache) { + const auto& buffer = i->emuDSBuffer; + hRet = buffer->EmuDirectSoundBuffer8->GetStatus(&dwStatus); + if (hRet == DS_OK && (dwStatus & DSBSTATUS_PLAYING) != 0) { + if (isActive) { + ImGui::Separator(); + } + isActive++; + + ImGui::BulletText("DSBufferCache[%u] = 0x%p", index, reinterpret_cast(i)); + ImGui::Indent(); + ImGui::BulletText("status = %s", ((dwStatus & DSBSTATUS_LOOPING) != 0) ? "looping" : "play once"); + + ImGui::BulletText("X_BufferCacheSize = 0x%u", buffer->X_BufferCacheSize); + ImGui::BulletText("EmuFlags = %X", buffer->EmuFlags); + ImGui::BulletText("EmuRegionToggle = 0x%X", buffer->EmuBufferToggle); + if (buffer->EmuBufferToggle == xbox::X_DSB_TOGGLE_PLAY) { + ImGui::Indent(); + ImGui::BulletText("EmuRegionPlayStartOffset = 0x%X", buffer->EmuRegionPlayStartOffset); + ImGui::BulletText("EmuRegionPlayLength = 0x%X", buffer->EmuRegionPlayLength); + ImGui::Unindent(); + } + else if (buffer->EmuBufferToggle == xbox::X_DSB_TOGGLE_LOOP) { + ImGui::Indent(); + ImGui::BulletText("EmuRegionLoopStartOffset = 0x%X", buffer->EmuRegionLoopStartOffset); + ImGui::BulletText("EmuRegionLoopLength = 0x%X", buffer->EmuRegionLoopLength); + ImGui::Unindent(); + } + ImGui::Unindent(); + } + index++; + } + + if (isActive == 0) { + ImGui::BulletText("(none)"); + } + + ImGui::Text("Total active DSBuffer = %u", isActive); + } + // Generate DSStream stats + + index = 0; + isActive = 0; + + if (ImGui::CollapsingHeader("Active DSStream cache")) { + for (const auto& i : g_pDSoundStreamCache) { + hRet = i->EmuDirectSoundBuffer8->GetStatus(&dwStatus); + if (hRet == DS_OK && (dwStatus & DSBSTATUS_PLAYING) != 0) { + if (isActive) { + ImGui::Separator(); + } + isActive++; + ImGui::BulletText("DSStreamCache[%u] = 0x%p", index, reinterpret_cast(i)); + ImGui::Indent(); + ImGui::BulletText("Max packets allow = %u", i->X_MaxAttachedPackets); + ImGui::BulletText("Total packets = %u", i->Host_BufferPacketArray.size()); + ImGui::BulletText("is processing = %d", i->Host_isProcessing); + ImGui::BulletText("EmuFlags = %X", i->EmuFlags); + ImGui::BulletText("Xb_Status = %X", i->Xb_Status); + ImGui::Unindent(); + } + index++; + } + + if (isActive == 0) { + ImGui::BulletText("(none)"); + } + + ImGui::Text("Total active DSStream = %u", isActive); + } } + ImGui::End(); } - index++; } - - if (isActive == 0) { - ss << "\n\t(none)"; - } - - ss << "\nTotal active DSBuffer = " << isActive; - - // Generate DSStream stats - - index = 0; - isActive = 0; - - ss << "\nActive DSStream cache:"; - for (const auto& i : g_pDSoundStreamCache) { - hRet = i->EmuDirectSoundBuffer8->GetStatus(&dwStatus); - if (hRet == DS_OK && (dwStatus & DSBSTATUS_PLAYING) != 0) { - isActive++; - ss << "\n\tDSStreamCache[" << index << "] = " << reinterpret_cast(i); - ss << "\n\t\tMax packets allow = " << i->X_MaxAttachedPackets; - ss << "\n\t\tTotal packets = " << i->Host_BufferPacketArray.size(); - ss << "\n\t\tis processing = " << i->Host_isProcessing; - ss << "\n\t\tEmuFlags = " << i->EmuFlags; - ss << "\n\t\tXb_Status = " << i->Xb_Status; - } - index++; - } - - if (isActive == 0) { - ss << "\n\t(none)"; - } - - ss << "\nTotal active DSStream = " << isActive; - - EmuLog(LOG_LEVEL::INFO, ss.str().c_str()); } diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 6b74f13db..7ce11d82a 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -1158,17 +1158,6 @@ void CxbxKrnlEmulate(unsigned int reserved_systems, blocks_reserved_t blocks_res g_ExceptionManager = new ExceptionManager(); // If in need to add VEHs, move this line earlier. (just in case) - // Initialize ImGui - { - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - - ImGuiIO& io = ImGui::GetIO(); - io.IniFilename = nullptr; - - ImGui::StyleColorsDark(); - } - // Launch the XBE : { // Load TLS diff --git a/src/devices/video/EmuNV2A_PGRAPH.cpp b/src/devices/video/EmuNV2A_PGRAPH.cpp index c37eac00f..e82497f23 100644 --- a/src/devices/video/EmuNV2A_PGRAPH.cpp +++ b/src/devices/video/EmuNV2A_PGRAPH.cpp @@ -705,6 +705,23 @@ void OpenGL_draw_inline_elements(NV2AState *d) OpenGL_draw_end(d); } +static void CxbxImGui_RenderOpenGL(ImGuiUI* m_imgui, std::nullptr_t unused) +{ + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + + m_imgui->DrawMenu(); + m_imgui->DrawWidgets(); + + ImGui::Render(); + + ImDrawData* drawData = ImGui::GetDrawData(); + if (drawData->TotalVtxCount > 0) { + ImGui_ImplOpenGL3_RenderDrawData(drawData); + } +} + void OpenGL_draw_state_update(NV2AState *d) { PGRAPHState *pg = &d->pgraph; @@ -893,6 +910,10 @@ void OpenGL_draw_state_update(NV2AState *d) pg->gl_zpass_pixel_count_query_count - 1] = gl_query; glBeginQuery(GL_SAMPLES_PASSED, gl_query); } + + // Render ImGui + static std::function internal_render = &CxbxImGui_RenderOpenGL; + g_renderbase->Render(internal_render, nullptr); } void OpenGL_draw_end(NV2AState *d) @@ -2989,6 +3010,10 @@ void pgraph_init(NV2AState *d) glextensions_init(); + // ImGui + //ImGui_ImplSDL2_InitForOpenGL(window, pg->gl_context); + ImGui_ImplOpenGL3_Init(); + /* DXT textures */ assert(glo_check_extension("GL_EXT_texture_compression_s3tc")); /* Internal RGB565 texture format */ diff --git a/src/devices/video/nv2a.cpp b/src/devices/video/nv2a.cpp index 8a322312c..95ffaf842 100644 --- a/src/devices/video/nv2a.cpp +++ b/src/devices/video/nv2a.cpp @@ -37,7 +37,6 @@ #define LOG_PREFIX CXBXR_MODULE::NV2A - #include // For PKINTERRUPT, etc. #ifdef _MSC_VER // Check if MS Visual C compiler @@ -53,6 +52,9 @@ #include "core\kernel\init\CxbxKrnl.h" // For XBOX_MEMORY_SIZE, DWORD, etc #include "core\kernel\support\Emu.h" #include "core\kernel\exports\EmuKrnl.h" +#include +#include +#include "core/common/video/RenderBase.hpp" #include "core\hle\Intercept.hpp" #include "common/win32/Threads.h" #include "Logging.h" @@ -1157,6 +1159,11 @@ NV2ADevice::NV2ADevice() NV2ADevice::~NV2ADevice() { Reset(); // TODO : Review this + + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplWin32_Shutdown(); + g_renderbase->Shutdown(); + delete m_nv2a_state; } diff --git a/src/gui/WndMain.cpp b/src/gui/WndMain.cpp index ce77ee43c..2ade23ab1 100644 --- a/src/gui/WndMain.cpp +++ b/src/gui/WndMain.cpp @@ -387,6 +387,9 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP g_EmuShared->SetIsReady(true); } break; + case ID_GUI_STATUS_OVERLAY: + g_EmuShared->GetOverlaySettings(&g_Settings->m_overlay); + break; } } break; diff --git a/src/gui/resource/ResCxbx.h b/src/gui/resource/ResCxbx.h index 9574e366a..5ac15e6c9 100644 --- a/src/gui/resource/ResCxbx.h +++ b/src/gui/resource/ResCxbx.h @@ -196,6 +196,7 @@ #define ID_GUI_STATUS_LOG_ENABLED 1099 #define IDC_AC_MUTE_WHEN_UNFOCUS 1100 #define IDC_IGNORE_KBMO_UNFOCUS 1101 +#define ID_GUI_STATUS_OVERLAY 1102 #define IDC_XBOX_PORT_0 1158 #define IDC_XBOX_PORT_1 1166 #define IDC_XBOX_PORT_2 1174 From c403d6d129ba2958fb3ff0346388d0483c01f77e Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Thu, 25 Mar 2021 15:53:35 -0500 Subject: [PATCH 10/17] input: fix incorrect getter/setter when should be using boolean method than long --- src/common/Settings.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index 815cb4786..50b2ef2d8 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -458,7 +458,7 @@ bool Settings::LoadConfig() m_input_general.MoAxisRange = m_si.GetLongValue(section_input_general, sect_input_general.mo_axis_range, MO_AXIS_DEFAULT_RANGE); m_input_general.MoWheelRange = m_si.GetLongValue(section_input_general, sect_input_general.mo_wheel_range, MO_WHEEL_DEFAULT_RANGE); - m_input_general.IgnoreKbMoUnfocus = m_si.GetLongValue(section_input_general, sect_input_general.ignore_kbmo_unfocus, 1); + m_input_general.IgnoreKbMoUnfocus = m_si.GetBoolValue(section_input_general, sect_input_general.ignore_kbmo_unfocus, true); // ==== Input General End ============== @@ -631,7 +631,7 @@ bool Settings::Save(std::string file_path) m_si.SetLongValue(section_input_general, sect_input_general.mo_axis_range, m_input_general.MoAxisRange, nullptr, false, true); m_si.SetLongValue(section_input_general, sect_input_general.mo_wheel_range, m_input_general.MoWheelRange, nullptr, false, true); - m_si.SetLongValue(section_input_general, sect_input_general.ignore_kbmo_unfocus, m_input_general.IgnoreKbMoUnfocus, nullptr, false, true); + m_si.SetBoolValue(section_input_general, sect_input_general.ignore_kbmo_unfocus, m_input_general.IgnoreKbMoUnfocus, nullptr, true); // ==== Input General End ========= From e052a681bee3bba66c23f3db9daa658d0d1b6cbc Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Thu, 25 Mar 2021 15:57:01 -0500 Subject: [PATCH 11/17] D3D8: move INDEX16 to xbox's D3D8 types header file --- src/core/hle/D3D8/Direct3D9/WalkIndexBuffer.h | 2 +- src/core/hle/D3D8/XbD3D8Types.h | 2 ++ src/core/hle/D3D8/XbVertexBuffer.h | 2 +- src/core/kernel/support/Emu.h | 2 -- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/hle/D3D8/Direct3D9/WalkIndexBuffer.h b/src/core/hle/D3D8/Direct3D9/WalkIndexBuffer.h index 02623eaa9..9a16646a6 100644 --- a/src/core/hle/D3D8/Direct3D9/WalkIndexBuffer.h +++ b/src/core/hle/D3D8/Direct3D9/WalkIndexBuffer.h @@ -1,7 +1,7 @@ #ifndef WALKINDEXBUFFER_H #define WALKINDEXBUFFER_H -#include "core\kernel\support\Emu.h" +#include "core/hle/D3D8/XbD3D8Types.h" extern void(*WalkIndexBuffer) ( diff --git a/src/core/hle/D3D8/XbD3D8Types.h b/src/core/hle/D3D8/XbD3D8Types.h index c00a1fbbe..d7a468002 100644 --- a/src/core/hle/D3D8/XbD3D8Types.h +++ b/src/core/hle/D3D8/XbD3D8Types.h @@ -83,6 +83,8 @@ #define IDirect3DSwapChain IDirect3DSwapChain9 #define IDirect3DQuery IDirect3DQuery9 +typedef xbox::word_xt INDEX16; // TODO: Move INDEX16 into xbox namespace + namespace xbox { // TODO : Declare these aliasses as Xbox type diff --git a/src/core/hle/D3D8/XbVertexBuffer.h b/src/core/hle/D3D8/XbVertexBuffer.h index 54e15c1a8..5905e849a 100644 --- a/src/core/hle/D3D8/XbVertexBuffer.h +++ b/src/core/hle/D3D8/XbVertexBuffer.h @@ -40,7 +40,7 @@ typedef struct _CxbxDrawContext IN DWORD dwStartVertex; // Only D3DDevice_DrawVertices sets this (potentially higher than default 0) IN PWORD pXboxIndexData; // Set by D3DDevice_DrawIndexedVertices, D3DDevice_DrawIndexedVerticesUP and HLE_draw_inline_elements IN DWORD dwBaseVertexIndex; // Set to g_Xbox_BaseVertexIndex in D3DDevice_DrawIndexedVertices - IN INDEX16 LowIndex, HighIndex; // Set when pXboxIndexData is set + IN INDEX16 LowIndex, HighIndex; // Set when pXboxIndexData is set IN UINT NumVerticesToUse; // Set by CxbxVertexBufferConverter::Apply // Data if Draw...UP call IN PVOID pXboxVertexStreamZeroData; diff --git a/src/core/kernel/support/Emu.h b/src/core/kernel/support/Emu.h index de73b85f4..387b5fffd 100644 --- a/src/core/kernel/support/Emu.h +++ b/src/core/kernel/support/Emu.h @@ -87,8 +87,6 @@ typedef struct DUMMY_KERNEL IMAGE_SECTION_HEADER SectionHeader; } *PDUMMY_KERNEL; -typedef WORD INDEX16; - extern bool g_DisablePixelShaders; extern bool g_UseAllCores; extern bool g_SkipRdtscPatching; From 0875de0727cbe5a7e3bfa0874d9ff856d9bd2763 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Thu, 25 Mar 2021 15:59:17 -0500 Subject: [PATCH 12/17] ImGui: move generic vertex cache into ImGui's video class. --- src/core/common/imgui/video.cpp | 17 +++++++++++++---- src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 17 ----------------- src/core/hle/D3D8/XbVertexBuffer.cpp | 4 +++- src/core/hle/D3D8/XbVertexBuffer.h | 4 +++- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/core/common/imgui/video.cpp b/src/core/common/imgui/video.cpp index f1d6e57f2..027cf9a3a 100644 --- a/src/core/common/imgui/video.cpp +++ b/src/core/common/imgui/video.cpp @@ -12,6 +12,7 @@ #include "EmuShared.h" #include "core/kernel/init/CxbxKrnl.h" +#include "core/hle/D3D8/XbVertexBuffer.h" bool ImGuiVideo::Initialize() { @@ -27,14 +28,22 @@ void ImGuiVideo::Shutdown() void ImGuiVideo::DrawMenu() { if (ImGui::BeginMenu("Video")) { - ImGui::MenuItem("Show Vertex Stats", NULL, &m_windows.cache_stats_vertex); + ImGui::MenuItem("Debug Vertex Buffer Cache Stats", NULL, &m_windows.cache_stats_vertex); ImGui::EndMenu(); } } void ImGuiVideo::DrawWidgets(bool is_focus, ImGuiWindowFlags input_handler) { - //TODO: move into plugin class usage. - extern void CxbxImGui_Video_DrawWidgets(bool, ImGuiWindowFlags, bool); - CxbxImGui_Video_DrawWidgets(is_focus, input_handler, m_windows.cache_stats_vertex); + // Render vertex buffer cache stats + if (m_windows.cache_stats_vertex) { + ImGui::SetNextWindowPos(ImVec2(IMGUI_MIN_DIST_SIDE, IMGUI_MIN_DIST_TOP), ImGuiCond_FirstUseEver, ImVec2(0.0f, 0.0f)); + ImGui::SetNextWindowSize(ImVec2(200, 275), ImGuiCond_FirstUseEver); + if (ImGui::Begin("Debugging stats", nullptr, input_handler | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysVerticalScrollbar)) { + if (ImGui::CollapsingHeader("Vertex Buffer Cache", ImGuiTreeNodeFlags_DefaultOpen)) { + VertexBufferConverter.DrawCacheStats(); + } + ImGui::End(); + } + } } diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 80dcb6f6e..aef700580 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -128,8 +128,6 @@ static size_t g_QuadToTriangleHostIndexBuffer_Size = 0; // static INDEX16 *g_pQuadToTriangleIndexData = nullptr; static size_t g_QuadToTriangleIndexData_Size = 0; // = NrOfQuadIndices -static CxbxVertexBufferConverter VertexBufferConverter = {}; - struct { xbox::X_D3DSurface Surface; RECT SrcRect; @@ -186,21 +184,6 @@ float g_Xbox_BackbufferScaleY = 1; static constexpr size_t INDEX_BUFFER_CACHE_SIZE = 10000; -// ImGui -void CxbxImGui_Video_DrawWidgets(bool is_focus, ImGuiWindowFlags input_handler, bool show_vertex_stats) -{ - if (show_vertex_stats) { - ImGui::SetNextWindowPos(ImVec2(IMGUI_MIN_DIST_SIDE, IMGUI_MIN_DIST_TOP), ImGuiCond_FirstUseEver, ImVec2(0.0f, 0.0f)); - ImGui::SetNextWindowSize(ImVec2(200, 275), ImGuiCond_FirstUseEver); - if (ImGui::Begin("Debugging stats", nullptr, input_handler | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysVerticalScrollbar)) { - if (ImGui::CollapsingHeader("Vertex Buffers", ImGuiTreeNodeFlags_DefaultOpen)) { - VertexBufferConverter.ShowImGuiStats(); - } - ImGui::End(); - } - } -} - static void CxbxImGui_RenderD3D9(ImGuiUI* m_imgui, IDirect3DSurface9* renderTarget) { ImGui_ImplDX9_NewFrame(); diff --git a/src/core/hle/D3D8/XbVertexBuffer.cpp b/src/core/hle/D3D8/XbVertexBuffer.cpp index 9dbaeb48c..05391e2a6 100644 --- a/src/core/hle/D3D8/XbVertexBuffer.cpp +++ b/src/core/hle/D3D8/XbVertexBuffer.cpp @@ -46,6 +46,8 @@ #define MAX_STREAM_NOT_USED_TIME (2 * CLOCKS_PER_SEC) // TODO: Trim the not used time +CxbxVertexBufferConverter VertexBufferConverter = {}; + // Inline vertex buffer emulation xbox::X_D3DPRIMITIVETYPE g_InlineVertexBuffer_PrimitiveType = xbox::X_D3DPT_INVALID; uint32_t g_InlineVertexBuffer_WrittenRegisters = 0; // A bitmask, indicating which registers have been set in g_InlineVertexBuffer_Table @@ -218,7 +220,7 @@ CxbxPatchedStream& CxbxVertexBufferConverter::GetPatchedStream(uint64_t dataKey, return stream; } -void CxbxVertexBufferConverter::ShowImGuiStats() +void CxbxVertexBufferConverter::DrawCacheStats() { const ULONG falsePositives = std::exchange(m_TotalLookupSuccesses, 0) - m_TotalCacheHits; const ULONG totalMisses = m_VertexStreamHashMisses + m_DataNotInCacheMisses; diff --git a/src/core/hle/D3D8/XbVertexBuffer.h b/src/core/hle/D3D8/XbVertexBuffer.h index 5905e849a..45c6be246 100644 --- a/src/core/hle/D3D8/XbVertexBuffer.h +++ b/src/core/hle/D3D8/XbVertexBuffer.h @@ -78,7 +78,7 @@ class CxbxVertexBufferConverter public: CxbxVertexBufferConverter() = default; void Apply(CxbxDrawContext *pPatchDesc); - void ShowImGuiStats(); + void DrawCacheStats(); private: struct StreamKey { @@ -116,6 +116,8 @@ class CxbxVertexBufferConverter void ConvertStream(CxbxDrawContext *pPatchDesc, CxbxVertexDeclaration* pCxbxVertexDeclaration, UINT uiStream); }; +extern CxbxVertexBufferConverter VertexBufferConverter; + // Inline vertex buffer emulation extern xbox::X_D3DPRIMITIVETYPE g_InlineVertexBuffer_PrimitiveType; From c6d1ec492494849c15ea45f6d7ff4ba3199c2ad0 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Fri, 26 Mar 2021 16:44:02 -0500 Subject: [PATCH 13/17] kernel: mark as fallthrough permit to avoid warning message appear --- src/core/kernel/exports/EmuKrnlHal.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/kernel/exports/EmuKrnlHal.cpp b/src/core/kernel/exports/EmuKrnlHal.cpp index ee1282855..720842bfb 100644 --- a/src/core/kernel/exports/EmuKrnlHal.cpp +++ b/src/core/kernel/exports/EmuKrnlHal.cpp @@ -495,6 +495,7 @@ XBSYSAPI EXPORTNUM(49) xbox::void_xt DECLSPEC_NORETURN NTAPI xbox::HalReturnToFi case ReturnFirmwareReboot: LOG_UNIMPLEMENTED(); // fall through + [[fallthrough]]; case ReturnFirmwareQuickReboot: { if (xbox::LaunchDataPage == NULL) From 74df117284ef11e9e5d2b9068998c24154695767 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Fri, 26 Mar 2021 16:46:15 -0500 Subject: [PATCH 14/17] ImGui: fix crash on early terminate emulation --- src/core/common/imgui/ui.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/common/imgui/ui.cpp b/src/core/common/imgui/ui.cpp index 792226ce0..f4bf2eba4 100644 --- a/src/core/common/imgui/ui.cpp +++ b/src/core/common/imgui/ui.cpp @@ -62,7 +62,6 @@ void ImGuiUI::Shutdown() g_EmuShared->SetOverlaySettings(&m_settings); m_audio.Shutdown(); m_video.Shutdown(); - ImGui::EndFrame(); ImGui::DestroyContext(m_imgui_context); } From 000dd6c0a56bf590db76f93d551421e1f474cbe4 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Fri, 26 Mar 2021 16:49:18 -0500 Subject: [PATCH 15/17] ImGui: register functions for individual release purpose and combine them into central call purpose --- src/core/common/video/RenderBase.cpp | 4 ++++ src/core/common/video/RenderBase.hpp | 22 ++++++++++++++++++++++ src/core/hle/D3D8/Direct3D9/Direct3D9.cpp | 19 ++++++++++++++----- src/core/kernel/exports/EmuKrnlHal.cpp | 5 ++++- src/core/kernel/init/CxbxKrnl.cpp | 19 +++++++++++++------ src/core/kernel/init/CxbxKrnl.h | 2 +- src/devices/video/EmuNV2A_PGRAPH.cpp | 5 ++++- src/devices/video/nv2a.cpp | 4 +--- 8 files changed, 63 insertions(+), 17 deletions(-) diff --git a/src/core/common/video/RenderBase.cpp b/src/core/common/video/RenderBase.cpp index 288a5f5e3..0c86344e0 100644 --- a/src/core/common/video/RenderBase.cpp +++ b/src/core/common/video/RenderBase.cpp @@ -27,5 +27,9 @@ bool RenderBase::Initialize() void RenderBase::Shutdown() { + DeviceRelease(); + m_device_release = std::function{}; + WindowRelease(); + m_window_release = std::function{}; ImGuiUI::Shutdown(); } diff --git a/src/core/common/video/RenderBase.hpp b/src/core/common/video/RenderBase.hpp index 062a5c65a..a1428adbc 100644 --- a/src/core/common/video/RenderBase.hpp +++ b/src/core/common/video/RenderBase.hpp @@ -24,6 +24,28 @@ public: { ImGuiUI::Render(callback, arg); } + + // When video backends has its own class, make DeviceRelease call as virtual requirement for parent class usage. + void SetDeviceRelease(const std::function& func_register) { + m_device_release = func_register; + } + + void DeviceRelease() { + m_device_release(); + } + + void SetWindowRelease(const std::function& func_register) { + m_window_release = func_register; + } + + void WindowRelease() { + m_window_release(); + } + +protected: + + std::function m_device_release; + std::function m_window_release; }; extern std::unique_ptr g_renderbase; diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index aef700580..0fb8cf99c 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -193,6 +193,8 @@ static void CxbxImGui_RenderD3D9(ImGuiUI* m_imgui, IDirect3DSurface9* renderTarg m_imgui->DrawMenu(); m_imgui->DrawWidgets(); + ImGui::EndFrame(); + ImGui::Render(); ImDrawData* drawData = ImGui::GetDrawData(); if (drawData->TotalVtxCount > 0) { @@ -661,7 +663,11 @@ void CxbxInitWindow(bool bFullInit) SetFocus(g_hEmuWindow); g_renderbase = std::unique_ptr(new RenderBase()); g_renderbase->Initialize(); + ImGui_ImplWin32_Init(g_hEmuWindow); + g_renderbase->SetWindowRelease([] { + ImGui_ImplWin32_Shutdown(); + }); } void DrawUEM(HWND hWnd) @@ -1870,7 +1876,6 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar { CxbxReleaseCursor(); DeleteObject(g_hBgBrush); - g_renderbase->Shutdown(); // TODO: This needs a fix since it may not process correctly due to render thread did not get terminated properly. PostQuitMessage(0); return D3D_OK; // = 0 } @@ -2091,7 +2096,7 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar case WM_CLOSE: CxbxReleaseCursor(); DestroyWindow(hWnd); - CxbxKrnlShutDown(); + CxbxKrnlShutDown(); break; case WM_SETFOCUS: @@ -2404,8 +2409,8 @@ static void CreateDefaultD3D9Device // Final release of IDirect3DDevice9 must be called from the window message thread // See https://docs.microsoft.com/en-us/windows/win32/direct3d9/multithreading-issues RunOnWndMsgThread([] { - ImGui_ImplDX9_Shutdown(); - g_pD3DDevice->Release(); + // We only need to call bundled device release once here. + g_renderbase->DeviceRelease(); }); } @@ -2504,8 +2509,12 @@ static void CreateDefaultD3D9Device // Set up cache g_VertexShaderSource.ResetD3DDevice(g_pD3DDevice); - // Set up ImGui + // Set up ImGui's render backend ImGui_ImplDX9_Init(g_pD3DDevice); + g_renderbase->SetDeviceRelease([] { + ImGui_ImplDX9_Shutdown(); + g_pD3DDevice->Release(); + }); } diff --git a/src/core/kernel/exports/EmuKrnlHal.cpp b/src/core/kernel/exports/EmuKrnlHal.cpp index 720842bfb..bec4bb5f1 100644 --- a/src/core/kernel/exports/EmuKrnlHal.cpp +++ b/src/core/kernel/exports/EmuKrnlHal.cpp @@ -488,6 +488,8 @@ XBSYSAPI EXPORTNUM(49) xbox::void_xt DECLSPEC_NORETURN NTAPI xbox::HalReturnToFi { LOG_FUNC_ONE_ARG(Routine); + bool is_reboot = false; + switch (Routine) { case ReturnFirmwareHalt: CxbxKrnlCleanup("Emulated Xbox is halted"); @@ -586,6 +588,7 @@ XBSYSAPI EXPORTNUM(49) xbox::void_xt DECLSPEC_NORETURN NTAPI xbox::HalReturnToFi g_EmuShared->GetBootFlags(&QuickReboot); QuickReboot |= BOOT_QUICK_REBOOT; g_EmuShared->SetBootFlags(&QuickReboot); + is_reboot = true; g_VMManager.SavePersistentMemory(); @@ -666,7 +669,7 @@ XBSYSAPI EXPORTNUM(49) xbox::void_xt DECLSPEC_NORETURN NTAPI xbox::HalReturnToFi LOG_UNIMPLEMENTED(); } - EmuShared::Cleanup(); + CxbxKrnlShutDown(is_reboot); TerminateProcess(GetCurrentProcess(), EXIT_SUCCESS); } diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 7ce11d82a..b9e96f990 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -53,7 +53,7 @@ #include "common/ReserveAddressRanges.h" #include "common/xbox/Types.hpp" #include "common/win32/WineEnv.h" -#include +#include "core/common/video/RenderBase.hpp" #include #include @@ -1754,11 +1754,13 @@ void CxbxKrnlResume() g_bEmuSuspended = false; } -void CxbxKrnlShutDown() +void CxbxKrnlShutDown(bool is_reboot) { - // Clear all kernel boot flags. These (together with the shared memory) persist until Cxbx-Reloaded is closed otherwise. - int BootFlags = 0; - g_EmuShared->SetBootFlags(&BootFlags); + if (!is_reboot) { + // Clear all kernel boot flags. These (together with the shared memory) persist until Cxbx-Reloaded is closed otherwise. + int BootFlags = 0; + g_EmuShared->SetBootFlags(&BootFlags); + } // NOTE: This causes a hang when exiting while NV2A is processing // This is okay for now: It won't leak memory or resources since TerminateProcess will free everything @@ -1770,9 +1772,14 @@ void CxbxKrnlShutDown() // Shutdown the memory manager g_VMManager.Shutdown(); + // Shutdown the render manager + g_renderbase->Shutdown(); + g_renderbase.release(); + g_renderbase = nullptr; + CxbxUnlockFilePath(); - if (CxbxKrnl_hEmuParent != NULL) { + if (CxbxKrnl_hEmuParent != NULL && !is_reboot) { SendMessage(CxbxKrnl_hEmuParent, WM_PARENTNOTIFY, WM_DESTROY, 0); } diff --git a/src/core/kernel/init/CxbxKrnl.h b/src/core/kernel/init/CxbxKrnl.h index 55311eb2d..293b8728e 100644 --- a/src/core/kernel/init/CxbxKrnl.h +++ b/src/core/kernel/init/CxbxKrnl.h @@ -166,7 +166,7 @@ void CxbxKrnlSuspend(); void CxbxKrnlResume(); /*! terminate gracefully the emulation */ -void CxbxKrnlShutDown(); +void CxbxKrnlShutDown(bool is_reboot = false); /*! display the fatal error message*/ void CxbxKrnlPrintUEM(ULONG ErrorCode); diff --git a/src/devices/video/EmuNV2A_PGRAPH.cpp b/src/devices/video/EmuNV2A_PGRAPH.cpp index e82497f23..9e7f8acf1 100644 --- a/src/devices/video/EmuNV2A_PGRAPH.cpp +++ b/src/devices/video/EmuNV2A_PGRAPH.cpp @@ -3010,9 +3010,12 @@ void pgraph_init(NV2AState *d) glextensions_init(); - // ImGui + // Set up ImGui's render backend //ImGui_ImplSDL2_InitForOpenGL(window, pg->gl_context); ImGui_ImplOpenGL3_Init(); + g_renderbase->SetDeviceRelease([] { + ImGui_ImplOpenGL3_Shutdown(); + }); /* DXT textures */ assert(glo_check_extension("GL_EXT_texture_compression_s3tc")); diff --git a/src/devices/video/nv2a.cpp b/src/devices/video/nv2a.cpp index 95ffaf842..9ca04ef02 100644 --- a/src/devices/video/nv2a.cpp +++ b/src/devices/video/nv2a.cpp @@ -1160,9 +1160,7 @@ NV2ADevice::~NV2ADevice() { Reset(); // TODO : Review this - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplWin32_Shutdown(); - g_renderbase->Shutdown(); + g_renderbase->DeviceRelease(); delete m_nv2a_state; } From 3ba0ff084dd0a4c2dcf76284557497e640a54b8c Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Sat, 3 Apr 2021 10:18:53 -0500 Subject: [PATCH 16/17] review remarks --- src/common/Settings.cpp | 2 +- src/common/input/InputManager.cpp | 2 +- src/core/kernel/exports/EmuKrnlHal.cpp | 3 ++- src/gui/WndMain.cpp | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/common/Settings.cpp b/src/common/Settings.cpp index 50b2ef2d8..f61df681f 100644 --- a/src/common/Settings.cpp +++ b/src/common/Settings.cpp @@ -766,7 +766,7 @@ void Settings::SyncToEmulator() // register Network settings g_EmuShared->SetNetworkSettings(&m_network); - // register Input gamepad settings + // register xbox device input settings for (int i = 0; i < 4; i++) { g_EmuShared->SetInputDevTypeSettings(&m_input_port[i].Type, i); if (m_input_port[i].Type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) { diff --git a/src/common/input/InputManager.cpp b/src/common/input/InputManager.cpp index 1be97c882..69d5ea753 100644 --- a/src/common/input/InputManager.cpp +++ b/src/common/input/InputManager.cpp @@ -363,7 +363,7 @@ bool InputDeviceManager::UpdateXboxPortInput(int usb_port, void* Buffer, int Dir // First check if ImGui is focus, then ignore any input update occur. // If somebody else is currently holding the lock, we won't wait and instead report no input changes - if (!g_renderbase->IsImGuiFocus() && m_Mtx.try_lock()) { + if (static_cast(!g_renderbase->IsImGuiFocus()) & static_cast(m_Mtx.try_lock())) { for (auto &dev_ptr : m_Devices) { if (dev_ptr->GetPort(usb_port)) { switch (xid_type) diff --git a/src/core/kernel/exports/EmuKrnlHal.cpp b/src/core/kernel/exports/EmuKrnlHal.cpp index bec4bb5f1..d719bdfa5 100644 --- a/src/core/kernel/exports/EmuKrnlHal.cpp +++ b/src/core/kernel/exports/EmuKrnlHal.cpp @@ -496,8 +496,9 @@ XBSYSAPI EXPORTNUM(49) xbox::void_xt DECLSPEC_NORETURN NTAPI xbox::HalReturnToFi break; case ReturnFirmwareReboot: - LOG_UNIMPLEMENTED(); // fall through + LOG_UNIMPLEMENTED(); [[fallthrough]]; + case ReturnFirmwareQuickReboot: { if (xbox::LaunchDataPage == NULL) diff --git a/src/gui/WndMain.cpp b/src/gui/WndMain.cpp index 2ade23ab1..66b2b4326 100644 --- a/src/gui/WndMain.cpp +++ b/src/gui/WndMain.cpp @@ -387,6 +387,7 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP g_EmuShared->SetIsReady(true); } break; + case ID_GUI_STATUS_OVERLAY: g_EmuShared->GetOverlaySettings(&g_Settings->m_overlay); break; From 781b7b861889426ebbd8b13470bd2f7eb24f3e26 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Sat, 3 Apr 2021 10:19:47 -0500 Subject: [PATCH 17/17] found a hidden bug during review remark, not relative to the pr --- src/gui/WndMain.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/WndMain.cpp b/src/gui/WndMain.cpp index 66b2b4326..962e9d792 100644 --- a/src/gui/WndMain.cpp +++ b/src/gui/WndMain.cpp @@ -360,6 +360,8 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP DrawLedBitmap(hwnd, true); } } + break; + case WM_COMMAND: { switch (HIWORD(wParam)) {