From bad8cfc2097acc544960f4ef6cec808905445c82 Mon Sep 17 00:00:00 2001 From: BearOso Date: Thu, 4 May 2023 17:36:36 -0500 Subject: [PATCH] win32: Wire imgui up to OpenGL and Vulkan. --- gfx.cpp | 3 +- gfx.h | 1 + win32/COpenGL.cpp | 27 ++++++++++++++++ win32/CVulkan.cpp | 69 +++++++++++++++++++++++++++++++++++++++++ win32/CVulkan.h | 5 ++- win32/snes9xw.vcxproj | 8 ++--- win32/win32.cpp | 2 +- win32/win32_display.cpp | 9 ++++++ win32/win32_display.h | 1 + win32/wsnes9x.cpp | 15 ++++++--- 10 files changed, 128 insertions(+), 12 deletions(-) diff --git a/gfx.cpp b/gfx.cpp index 2fb1968c..6be2fe4f 100644 --- a/gfx.cpp +++ b/gfx.cpp @@ -1790,8 +1790,7 @@ static void VariableDisplayChar(int x, int y, uint8 c, bool monospace = false, i } } -static void S9xVariableDisplayString(const char* string, int linesFromBottom, - int pixelsFromLeft, bool allowWrap, int type) +void S9xVariableDisplayString(const char* string, int linesFromBottom, int pixelsFromLeft, bool allowWrap, int type) { bool monospace = true; if (type == S9X_NO_INFO) diff --git a/gfx.h b/gfx.h index 80e76cf6..af9ea816 100644 --- a/gfx.h +++ b/gfx.h @@ -221,5 +221,6 @@ void S9xSyncSpeed (void); // called instead of S9xDisplayString if set to non-NULL extern void (*S9xCustomDisplayString) (const char *, int, int, bool, int type); +void S9xVariableDisplayString(const char* string, int linesFromBottom, int pixelsFromLeft, bool allowWrap, int type); #endif diff --git a/win32/COpenGL.cpp b/win32/COpenGL.cpp index f5ae9451..8b8ca401 100644 --- a/win32/COpenGL.cpp +++ b/win32/COpenGL.cpp @@ -15,6 +15,8 @@ #include "../filter/hq2x.h" #include "../filter/2xsai.h" +#include "snes9x_imgui.h" +#include "imgui_impl_opengl3.h" COpenGL::COpenGL(void) { @@ -133,6 +135,16 @@ bool COpenGL::Initialize(HWND hWnd) glClear(GL_COLOR_BUFFER_BIT); SwapBuffers(hDC); + if (ogl_GetMajorVersion() >= 3 && !Settings.AutoDisplayMessages) + { + auto defaults = S9xImGuiGetDefaults(); + defaults.font_size = GUI.OSDSize; + defaults.spacing = defaults.font_size / 2.4; + S9xImGuiInit(&defaults); + ImGui_ImplOpenGL3_Init(); + Settings.DisplayIndicators = true; + } + initDone = true; return true; } @@ -140,6 +152,11 @@ bool COpenGL::Initialize(HWND hWnd) void COpenGL::DeInitialize() { initDone = false; + if (S9xImGuiRunning()) + { + ImGui_ImplOpenGL3_Shutdown(); + S9xImGuiDeinit(); + } SetShaders(NULL); DestroyDrawSurface(); wglMakeCurrent(NULL,NULL); @@ -366,6 +383,16 @@ void COpenGL::Render(SSurface Src) glFlush(); + if (S9xImGuiRunning()) + { + ImGui_ImplOpenGL3_NewFrame(); + if (S9xImGuiDraw(windowSize.right, windowSize.bottom)) + { + auto* draw_data = ImGui::GetDrawData(); + ImGui_ImplOpenGL3_RenderDrawData(draw_data); + } + } + WinThrottleFramerate(); SwapBuffers(hDC); diff --git a/win32/CVulkan.cpp b/win32/CVulkan.cpp index d0d0ef1e..6880c2dd 100644 --- a/win32/CVulkan.cpp +++ b/win32/CVulkan.cpp @@ -6,6 +6,52 @@ #include "../filter/hq2x.h" #include "../filter/2xsai.h" +#include "snes9x_imgui.h" +#include "imgui_impl_vulkan.h" + +bool CVulkan::InitImGui() +{ + auto defaults = S9xImGuiGetDefaults(); + defaults.font_size = GUI.OSDSize; + defaults.spacing = defaults.font_size / 2.4; + S9xImGuiInit(&defaults); + + ImGui_ImplVulkan_LoadFunctions([](const char* function, void* instance) { + return VULKAN_HPP_DEFAULT_DISPATCHER.vkGetInstanceProcAddr(*((VkInstance*)instance), function); + }, &context->instance.get()); + + vk::DescriptorPoolSize pool_sizes[] = + { + { vk::DescriptorType::eCombinedImageSampler, 1000 }, + { vk::DescriptorType::eUniformBuffer, 1000 } + }; + auto descriptor_pool_create_info = vk::DescriptorPoolCreateInfo{} + .setPoolSizes(pool_sizes) + .setMaxSets(1000) + .setFlags(vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet); + imgui_descriptor_pool = context->device.createDescriptorPoolUnique(descriptor_pool_create_info); + + ImGui_ImplVulkan_InitInfo init_info{}; + init_info.Instance = context->instance.get(); + init_info.PhysicalDevice = context->physical_device; + init_info.Device = context->device;; + init_info.QueueFamily = context->graphics_queue_family_index; + init_info.Queue = context->queue; + init_info.DescriptorPool = imgui_descriptor_pool.get(); + init_info.Subpass = 0; + init_info.MinImageCount = context->swapchain->get_num_frames(); + init_info.ImageCount = context->swapchain->get_num_frames(); + init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; + ImGui_ImplVulkan_Init(&init_info, context->swapchain->get_render_pass()); + + auto cmd = context->begin_cmd_buffer(); + ImGui_ImplVulkan_CreateFontsTexture(cmd); + context->end_cmd_buffer(); + context->wait_idle(); + + return true; +} + bool CVulkan::Initialize(HWND hWnd) { this->hWnd = hWnd; @@ -24,6 +70,12 @@ bool CVulkan::Initialize(HWND hWnd) return false; } + if (!Settings.AutoDisplayMessages) + { + Settings.DisplayIndicators = true; + InitImGui(); + } + if (GUI.shaderEnabled && GUI.OGLshaderFileName && GUI.OGLshaderFileName[0]) { shaderchain = std::make_unique(context.get()); @@ -49,7 +101,15 @@ void CVulkan::DeInitialize() current_shadername = ""; if (context) + { context->wait_idle(); + if (ImGui::GetCurrentContext()) + { + imgui_descriptor_pool.reset(); + ImGui_ImplVulkan_Shutdown(); + ImGui::DestroyContext(); + } + } shaderchain.reset(); simple_output.reset(); filtered_image.clear(); @@ -81,6 +141,15 @@ void CVulkan::Render(SSurface Src) bool result; + if (S9xImGuiDraw(windowSize.right, windowSize.bottom)) + { + ImDrawData* draw_data = ImGui::GetDrawData(); + + context->swapchain->on_render_pass_end([&, draw_data] { + ImGui_ImplVulkan_RenderDrawData(draw_data, context->swapchain->get_cmd()); + }); + } + if (shaderchain) { result = shaderchain->do_frame_without_swap(Dst.Surface, Dst.Width, Dst.Height, Dst.Pitch, vk::Format::eR5G6B5UnormPack16, displayRect.left, displayRect.top, displayRect.right - displayRect.left, displayRect.bottom - displayRect.top); diff --git a/win32/CVulkan.h b/win32/CVulkan.h index d5875bb7..bc6cf97b 100644 --- a/win32/CVulkan.h +++ b/win32/CVulkan.h @@ -16,11 +16,14 @@ class CVulkan : public IS9xDisplayOutput std::string current_shadername; std::unique_ptr simple_output; + vk::UniqueDescriptorPool imgui_descriptor_pool; + int current_width; int current_height; public: - bool Initialize(HWND hWnd) override; + bool InitImGui(); + bool Initialize(HWND hWnd) override; void DeInitialize() override; void Render(SSurface Src) override; bool ChangeRenderSize(unsigned int newWidth, unsigned int newHeight) override; diff --git a/win32/snes9xw.vcxproj b/win32/snes9xw.vcxproj index f7e8fbc0..86347d99 100644 --- a/win32/snes9xw.vcxproj +++ b/win32/snes9xw.vcxproj @@ -117,7 +117,7 @@ Disabled - $(ProjectDir);$(ProjectDir)..\;$(ProjectDir)..\..\;$(ProjectDir)zlib\src;$(ProjectDir)..\unzip;$(ProjectDir)libpng\src;$(ProjectDir)..\apu\bapu;$(ProjectDir)..\external\glslang;$(ProjectDir)..\external\stb;$(ProjectDir)..\external\vulkan-headers\include;$(ProjectDir)..\external\VulkanMemoryAllocator-Hpp\include;$(ProjectDir)..\external\fmt\include + $(ProjectDir);$(ProjectDir)..\;$(ProjectDir)..\..\;$(ProjectDir)zlib\src;$(ProjectDir)..\unzip;$(ProjectDir)libpng\src;$(ProjectDir)..\apu\bapu;$(ProjectDir)..\external\glslang;$(ProjectDir)..\external\stb;$(ProjectDir)..\external\vulkan-headers\include;$(ProjectDir)..\external\VulkanMemoryAllocator-Hpp\include;$(ProjectDir)..\external\fmt\include;$(ProjectDir)..\external\imgui _DEBUG;ALLOW_CPU_OVERCLOCK;HAVE_LIBPNG;JMA_SUPPORT;ZLIB;UNZIP_SUPPORT;__WIN32__;NETPLAY_SUPPORT;D3D_DEBUG_INFO;DIRECTDRAW_SUPPORT;USE_SLANG;%(PreprocessorDefinitions);VK_USE_PLATFORM_WIN32_KHR;VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1;VMA_DYNAMIC_VULKAN_FUNCTIONS=1;VMA_STATIC_VULKAN_FUNCTIONS=0;VMA_USE_STL_SHARED_MUTEX=0;IMGUI_IMPL_VULKAN_NO_PROTOTYPES MultiThreadedDebug Default @@ -168,7 +168,7 @@ Disabled - $(ProjectDir);$(ProjectDir)..\;$(ProjectDir)..\..\;$(ProjectDir)zlib\src;$(ProjectDir)..\unzip;$(ProjectDir)libpng\src;$(ProjectDir)..\apu\bapu;$(ProjectDir)..\external\glslang;$(ProjectDir)..\external\stb;$(ProjectDir)..\external\vulkan-headers\include;$(ProjectDir)..\external\VulkanMemoryAllocator-Hpp\include;$(ProjectDir)..\external\fmt\include + $(ProjectDir);$(ProjectDir)..\;$(ProjectDir)..\..\;$(ProjectDir)zlib\src;$(ProjectDir)..\unzip;$(ProjectDir)libpng\src;$(ProjectDir)..\apu\bapu;$(ProjectDir)..\external\glslang;$(ProjectDir)..\external\stb;$(ProjectDir)..\external\vulkan-headers\include;$(ProjectDir)..\external\VulkanMemoryAllocator-Hpp\include;$(ProjectDir)..\external\fmt\include;$(ProjectDir)..\external\imgui _DEBUG;ALLOW_CPU_OVERCLOCK;HAVE_LIBPNG;JMA_SUPPORT;ZLIB;UNZIP_SUPPORT;__WIN32__;NETPLAY_SUPPORT;D3D_DEBUG_INFO;DIRECTDRAW_SUPPORT;USE_SLANG;%(PreprocessorDefinitions);VK_USE_PLATFORM_WIN32_KHR;VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1;VMA_DYNAMIC_VULKAN_FUNCTIONS=1;VMA_STATIC_VULKAN_FUNCTIONS=0;VMA_USE_STL_SHARED_MUTEX=0;IMGUI_IMPL_VULKAN_NO_PROTOTYPES MultiThreadedDebug Default @@ -224,7 +224,7 @@ Speed true true - $(ProjectDir);$(ProjectDir)..\;$(ProjectDir)..\..\;$(ProjectDir)zlib\src;$(ProjectDir)..\unzip;$(ProjectDir)libpng\src;$(ProjectDir)..\apu\bapu;$(ProjectDir)..\external\glslang;$(ProjectDir)..\external\stb;$(ProjectDir)..\external\vulkan-headers\include;$(ProjectDir)..\external\VulkanMemoryAllocator-Hpp\include;$(ProjectDir)..\external\fmt\include + $(ProjectDir);$(ProjectDir)..\;$(ProjectDir)..\..\;$(ProjectDir)zlib\src;$(ProjectDir)..\unzip;$(ProjectDir)libpng\src;$(ProjectDir)..\apu\bapu;$(ProjectDir)..\external\glslang;$(ProjectDir)..\external\stb;$(ProjectDir)..\external\vulkan-headers\include;$(ProjectDir)..\external\VulkanMemoryAllocator-Hpp\include;$(ProjectDir)..\external\fmt\include;$(ProjectDir)..\external\imgui NDEBUG;ALLOW_CPU_OVERCLOCK;HAVE_LIBPNG;JMA_SUPPORT;ZLIB;UNZIP_SUPPORT;__WIN32__;NETPLAY_SUPPORT;DIRECTDRAW_SUPPORT;USE_SLANG;%(PreprocessorDefinitions);VK_USE_PLATFORM_WIN32_KHR;VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1;VMA_DYNAMIC_VULKAN_FUNCTIONS=1;VMA_STATIC_VULKAN_FUNCTIONS=0;VMA_USE_STL_SHARED_MUTEX=0;IMGUI_IMPL_VULKAN_NO_PROTOTYPES true MultiThreaded @@ -279,7 +279,7 @@ Speed true true - $(ProjectDir);$(ProjectDir)..\;$(ProjectDir)..\..\;$(ProjectDir)zlib\src;$(ProjectDir)..\unzip;$(ProjectDir)libpng\src;$(ProjectDir)..\apu\bapu;$(ProjectDir)..\external\glslang;$(ProjectDir)..\external\stb;$(ProjectDir)..\external\vulkan-headers\include;$(ProjectDir)..\external\VulkanMemoryAllocator-Hpp\include;$(ProjectDir)..\external\fmt\include + $(ProjectDir);$(ProjectDir)..\;$(ProjectDir)..\..\;$(ProjectDir)zlib\src;$(ProjectDir)..\unzip;$(ProjectDir)libpng\src;$(ProjectDir)..\apu\bapu;$(ProjectDir)..\external\glslang;$(ProjectDir)..\external\stb;$(ProjectDir)..\external\vulkan-headers\include;$(ProjectDir)..\external\VulkanMemoryAllocator-Hpp\include;$(ProjectDir)..\external\fmt\include;$(ProjectDir)..\external\imgui NDEBUG;ALLOW_CPU_OVERCLOCK;HAVE_LIBPNG;JMA_SUPPORT;ZLIB;UNZIP_SUPPORT;__WIN32__;NETPLAY_SUPPORT;DIRECTDRAW_SUPPORT;USE_SLANG;%(PreprocessorDefinitions);VK_USE_PLATFORM_WIN32_KHR;VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1;VMA_DYNAMIC_VULKAN_FUNCTIONS=1;VMA_STATIC_VULKAN_FUNCTIONS=0;VMA_USE_STL_SHARED_MUTEX=0;IMGUI_IMPL_VULKAN_NO_PROTOTYPES true MultiThreaded diff --git a/win32/win32.cpp b/win32/win32.cpp index 0555ce60..28e71e8c 100644 --- a/win32/win32.cpp +++ b/win32/win32.cpp @@ -826,7 +826,7 @@ void InitSnes9x( void) // generate_offsets_h (0, NULL); // fclose (offsets_h); //#endif - + S9xCustomDisplayString = S9xWinDisplayString; Memory.Init(); extern void S9xPostRomInit(); diff --git a/win32/win32_display.cpp b/win32/win32_display.cpp index a7c4a21b..61665496 100644 --- a/win32/win32_display.cpp +++ b/win32/win32_display.cpp @@ -888,3 +888,12 @@ void ConvertDepth (SSurface *src, SSurface *dst, RECT *srect) } /* Depth conversion functions end */ +#include "snes9x_imgui.h" +void S9xWinDisplayString(const char *string, int linesFromBottom, int pixelsFromLeft, bool allowWrap, int type) +{ + if (S9xImGuiRunning() && !Settings.AutoDisplayMessages) + { + return; + } + S9xVariableDisplayString(string, linesFromBottom, pixelsFromLeft, allowWrap, type); +} diff --git a/win32/win32_display.h b/win32/win32_display.h index d4f9e871..8cbe74c1 100644 --- a/win32/win32_display.h +++ b/win32/win32_display.h @@ -36,6 +36,7 @@ void ConvertDepth (SSurface *src, SSurface *dst, RECT *srect); char *ReadShaderFileContents(const TCHAR *filename); void ReduceToPath(TCHAR *filename); double WinGetRefreshRate(); +void S9xWinDisplayString(const char*, int, int, bool, int); int WinGetAutomaticInputRate(); void WinThrottleFramerate(); std::vector *WinGetShaderParameters(); diff --git a/win32/wsnes9x.cpp b/win32/wsnes9x.cpp index a9d05cd2..2fa2c6e9 100644 --- a/win32/wsnes9x.cpp +++ b/win32/wsnes9x.cpp @@ -7922,12 +7922,22 @@ INT_PTR CALLBACK DlgFunky(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) Settings.Transparency = IsDlgButtonChecked(hDlg, IDC_TRANS); Settings.BilinearFilter = (bool)(IsDlgButtonChecked(hDlg,IDC_BILINEAR)==BST_CHECKED); Settings.ShowOverscan = IsDlgButtonChecked(hDlg, IDC_HEIGHT_EXTEND)!=0; - Settings.AutoDisplayMessages = IsDlgButtonChecked(hDlg, IDC_MESSAGES_IN_IMAGE); GUI.DoubleBuffered = (bool)(IsDlgButtonChecked(hDlg, IDC_DBLBUFFER)==BST_CHECKED); GUI.ReduceInputLag = (bool)(IsDlgButtonChecked(hDlg, IDC_REDUCEINPUTLAG) == BST_CHECKED); GUI.Vsync = (bool)(IsDlgButtonChecked(hDlg, IDC_VSYNC )==BST_CHECKED); + { + int newOSDSize = SendDlgItemMessage(hDlg, IDC_SPIN_OSD_SIZE, UDM_GETPOS, 0, 0); + bool need_reset = (Settings.AutoDisplayMessages != prevAutoDisplayMessages || newOSDSize != GUI.OSDSize); + GUI.OSDSize = newOSDSize; + if (need_reset) + { + WinDisplayReset(); + WinRefreshDisplay(); + UpdateWindow(GUI.hWnd); + } + } if(IsDlgButtonChecked(hDlg, IDC_AUTOFRAME)) { Settings.SkipFrames=AUTO_FRAMERATE; @@ -7983,11 +7993,8 @@ INT_PTR CALLBACK DlgFunky(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) ToggleFullScreen(); } - return false; - - case IDCANCEL: SelectOutputMethodInVideoDropdown(hDlg, prevOutputMethod); SendMessage(hDlg,WM_COMMAND,MAKEWPARAM(IDC_OUTPUTMETHOD,CBN_SELCHANGE),0);