From c39e86c0c672a665027149a6796387ee19107743 Mon Sep 17 00:00:00 2001 From: BearOso Date: Sat, 4 May 2024 15:38:29 -0500 Subject: [PATCH 01/51] Qt: More built-in icons. --- qt/src/EmuMainWindow.cpp | 21 +++++++++++---------- qt/src/resources/blackicons/exit.svg | 1 + qt/src/resources/blackicons/fullscreen.svg | 1 + qt/src/resources/blackicons/open.svg | 1 + qt/src/resources/blackicons/pause.svg | 1 + qt/src/resources/blackicons/play.svg | 1 + qt/src/resources/blackicons/refresh.svg | 1 + qt/src/resources/blackicons/reset.svg | 1 + qt/src/resources/blackicons/save.svg | 1 + qt/src/resources/snes9x.qrc | 16 ++++++++++++++++ qt/src/resources/whiteicons/exit.svg | 1 + qt/src/resources/whiteicons/fullscreen.svg | 1 + qt/src/resources/whiteicons/open.svg | 1 + qt/src/resources/whiteicons/pause.svg | 1 + qt/src/resources/whiteicons/play.svg | 1 + qt/src/resources/whiteicons/refresh.svg | 1 + qt/src/resources/whiteicons/reset.svg | 1 + qt/src/resources/whiteicons/save.svg | 1 + 18 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 qt/src/resources/blackicons/exit.svg create mode 100644 qt/src/resources/blackicons/fullscreen.svg create mode 100644 qt/src/resources/blackicons/open.svg create mode 100644 qt/src/resources/blackicons/pause.svg create mode 100644 qt/src/resources/blackicons/play.svg create mode 100644 qt/src/resources/blackicons/refresh.svg create mode 100644 qt/src/resources/blackicons/reset.svg create mode 100644 qt/src/resources/blackicons/save.svg create mode 100644 qt/src/resources/whiteicons/exit.svg create mode 100644 qt/src/resources/whiteicons/fullscreen.svg create mode 100644 qt/src/resources/whiteicons/open.svg create mode 100644 qt/src/resources/whiteicons/pause.svg create mode 100644 qt/src/resources/whiteicons/play.svg create mode 100644 qt/src/resources/whiteicons/refresh.svg create mode 100644 qt/src/resources/whiteicons/reset.svg create mode 100644 qt/src/resources/whiteicons/save.svg diff --git a/qt/src/EmuMainWindow.cpp b/qt/src/EmuMainWindow.cpp index 1706c72e..b529eb5c 100644 --- a/qt/src/EmuMainWindow.cpp +++ b/qt/src/EmuMainWindow.cpp @@ -167,9 +167,11 @@ void EmuMainWindow::createWidgets() setWindowTitle("Snes9x"); setWindowIcon(QIcon(":/icons/snes9x.svg")); + auto iconset = app->iconPrefix(); + // File menu auto file_menu = new QMenu(tr("&File")); - auto open_item = file_menu->addAction(QIcon::fromTheme("document-open"), tr("&Open File...")); + auto open_item = file_menu->addAction(QIcon(iconset + "open.svg"), tr("&Open File...")); open_item->connect(open_item, &QAction::triggered, this, [&] { openFile(); }); @@ -200,7 +202,7 @@ void EmuMainWindow::createWidgets() load_state_menu->addSeparator(); - auto load_state_file_item = load_state_menu->addAction(QIcon::fromTheme("document-open"), tr("From &File...")); + auto load_state_file_item = load_state_menu->addAction(QIcon(iconset + "open.svg"), tr("From &File...")); connect(load_state_file_item, &QAction::triggered, [&] { this->chooseState(false); }); @@ -208,7 +210,7 @@ void EmuMainWindow::createWidgets() load_state_menu->addSeparator(); - auto load_state_undo_item = load_state_menu->addAction(QIcon::fromTheme("edit-undo"), tr("&Undo Load State")); + auto load_state_undo_item = load_state_menu->addAction(QIcon(iconset + "refresh.svg"), tr("&Undo Load State")); connect(load_state_undo_item, &QAction::triggered, [&] { app->loadUndoState(); }); @@ -217,14 +219,14 @@ void EmuMainWindow::createWidgets() file_menu->addMenu(load_state_menu); save_state_menu->addSeparator(); - auto save_state_file_item = save_state_menu->addAction(QIcon::fromTheme("document-save"), tr("To &File...")); + auto save_state_file_item = save_state_menu->addAction(QIcon(iconset + "save.svg"), tr("To &File...")); connect(save_state_file_item, &QAction::triggered, [&] { this->chooseState(true); }); core_actions.push_back(save_state_file_item); file_menu->addMenu(save_state_menu); - auto exit_item = new QAction(QIcon::fromTheme("application-exit"), tr("E&xit")); + auto exit_item = new QAction(QIcon(iconset + "exit.svg"), tr("E&xit")); exit_item->connect(exit_item, &QAction::triggered, this, [&](bool checked) { close(); }); @@ -245,7 +247,7 @@ void EmuMainWindow::createWidgets() }); core_actions.push_back(run_item); - auto pause_item = emulation_menu->addAction(QIcon::fromTheme("media-playback-pause"), tr("&Pause")); + auto pause_item = emulation_menu->addAction(QIcon(iconset + "pause.svg"), tr("&Pause")); connect(pause_item, &QAction::triggered, [&] { if (!manual_pause) { @@ -257,7 +259,7 @@ void EmuMainWindow::createWidgets() emulation_menu->addSeparator(); - auto reset_item = emulation_menu->addAction(QIcon::fromTheme("view-refresh"), tr("Rese&t")); + auto reset_item = emulation_menu->addAction(QIcon(iconset + "refresh.svg"), tr("Rese&t")); connect(reset_item, &QAction::triggered, [&] { app->reset(); if (manual_pause) @@ -268,7 +270,7 @@ void EmuMainWindow::createWidgets() }); core_actions.push_back(reset_item); - auto hard_reset_item = emulation_menu->addAction(QIcon::fromTheme("process-stop"), tr("&Hard Reset")); + auto hard_reset_item = emulation_menu->addAction(QIcon(iconset + "reset.svg"), tr("&Hard Reset")); connect(hard_reset_item, &QAction::triggered, [&] { app->powerCycle(); if (manual_pause) @@ -308,7 +310,7 @@ void EmuMainWindow::createWidgets() view_menu->addSeparator(); - auto fullscreen_item = new QAction(QIcon::fromTheme("view-fullscreen"), tr("&Fullscreen")); + auto fullscreen_item = new QAction(QIcon(iconset + "fullscreen.svg"), tr("&Fullscreen")); view_menu->addAction(fullscreen_item); fullscreen_item->connect(fullscreen_item, &QAction::triggered, [&](bool checked) { toggleFullscreen(); @@ -328,7 +330,6 @@ void EmuMainWindow::createWidgets() tr("&Controllers..."), tr("Shortcu&ts..."), tr("&Files...") }; - QString iconset = app->iconPrefix(); const char *setting_icons[] = { "settings.svg", "display.svg", "sound.svg", diff --git a/qt/src/resources/blackicons/exit.svg b/qt/src/resources/blackicons/exit.svg new file mode 100644 index 00000000..1b785f84 --- /dev/null +++ b/qt/src/resources/blackicons/exit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qt/src/resources/blackicons/fullscreen.svg b/qt/src/resources/blackicons/fullscreen.svg new file mode 100644 index 00000000..742640d5 --- /dev/null +++ b/qt/src/resources/blackicons/fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qt/src/resources/blackicons/open.svg b/qt/src/resources/blackicons/open.svg new file mode 100644 index 00000000..e0df5cff --- /dev/null +++ b/qt/src/resources/blackicons/open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qt/src/resources/blackicons/pause.svg b/qt/src/resources/blackicons/pause.svg new file mode 100644 index 00000000..568d723b --- /dev/null +++ b/qt/src/resources/blackicons/pause.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qt/src/resources/blackicons/play.svg b/qt/src/resources/blackicons/play.svg new file mode 100644 index 00000000..178bd3a4 --- /dev/null +++ b/qt/src/resources/blackicons/play.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qt/src/resources/blackicons/refresh.svg b/qt/src/resources/blackicons/refresh.svg new file mode 100644 index 00000000..eb0b5b1d --- /dev/null +++ b/qt/src/resources/blackicons/refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qt/src/resources/blackicons/reset.svg b/qt/src/resources/blackicons/reset.svg new file mode 100644 index 00000000..5961fe82 --- /dev/null +++ b/qt/src/resources/blackicons/reset.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qt/src/resources/blackicons/save.svg b/qt/src/resources/blackicons/save.svg new file mode 100644 index 00000000..5cb9c0fe --- /dev/null +++ b/qt/src/resources/blackicons/save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qt/src/resources/snes9x.qrc b/qt/src/resources/snes9x.qrc index 267d5359..1fd5a8a8 100644 --- a/qt/src/resources/snes9x.qrc +++ b/qt/src/resources/snes9x.qrc @@ -21,6 +21,14 @@ whiteicons/up.svg whiteicons/x.svg whiteicons/y.svg + whiteicons/open.svg + whiteicons/pause.svg + whiteicons/play.svg + whiteicons/refresh.svg + whiteicons/reset.svg + whiteicons/save.svg + whiteicons/exit.svg + whiteicons/fullscreen.svg snes9x.svg blackicons/settings.svg blackicons/folders.svg @@ -43,5 +51,13 @@ blackicons/x.svg blackicons/y.svg blackicons/shader.svg + blackicons/open.svg + blackicons/pause.svg + blackicons/play.svg + blackicons/refresh.svg + blackicons/reset.svg + blackicons/save.svg + blackicons/exit.svg + blackicons/fullscreen.svg diff --git a/qt/src/resources/whiteicons/exit.svg b/qt/src/resources/whiteicons/exit.svg new file mode 100644 index 00000000..cab9dc3f --- /dev/null +++ b/qt/src/resources/whiteicons/exit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qt/src/resources/whiteicons/fullscreen.svg b/qt/src/resources/whiteicons/fullscreen.svg new file mode 100644 index 00000000..2ce70f31 --- /dev/null +++ b/qt/src/resources/whiteicons/fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qt/src/resources/whiteicons/open.svg b/qt/src/resources/whiteicons/open.svg new file mode 100644 index 00000000..3b6037fc --- /dev/null +++ b/qt/src/resources/whiteicons/open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qt/src/resources/whiteicons/pause.svg b/qt/src/resources/whiteicons/pause.svg new file mode 100644 index 00000000..350e2b84 --- /dev/null +++ b/qt/src/resources/whiteicons/pause.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qt/src/resources/whiteicons/play.svg b/qt/src/resources/whiteicons/play.svg new file mode 100644 index 00000000..5f53dfac --- /dev/null +++ b/qt/src/resources/whiteicons/play.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qt/src/resources/whiteicons/refresh.svg b/qt/src/resources/whiteicons/refresh.svg new file mode 100644 index 00000000..bd53323a --- /dev/null +++ b/qt/src/resources/whiteicons/refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qt/src/resources/whiteicons/reset.svg b/qt/src/resources/whiteicons/reset.svg new file mode 100644 index 00000000..04efc696 --- /dev/null +++ b/qt/src/resources/whiteicons/reset.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qt/src/resources/whiteicons/save.svg b/qt/src/resources/whiteicons/save.svg new file mode 100644 index 00000000..ed967b59 --- /dev/null +++ b/qt/src/resources/whiteicons/save.svg @@ -0,0 +1 @@ + \ No newline at end of file From 51b6528224b67e1a4517044fd45f94fd29a12510 Mon Sep 17 00:00:00 2001 From: BearOso Date: Sat, 4 May 2024 15:43:54 -0500 Subject: [PATCH 02/51] Vulkan: Fix a couple of unsigned/signed warnings. --- vulkan/vulkan_context.cpp | 2 +- vulkan/vulkan_swapchain.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vulkan/vulkan_context.cpp b/vulkan/vulkan_context.cpp index 4c951cbe..f8bd76c0 100644 --- a/vulkan/vulkan_context.cpp +++ b/vulkan/vulkan_context.cpp @@ -204,7 +204,7 @@ bool Context::init_device(int preferred_device) auto device_list = instance->enumeratePhysicalDevices().value; if (preferred_device > -1 && - preferred_device < device_list.size() && + (size_t)preferred_device < device_list.size() && check_extensions(device_list[preferred_device])) { physical_device = device_list[preferred_device]; diff --git a/vulkan/vulkan_swapchain.cpp b/vulkan/vulkan_swapchain.cpp index 12fbc676..762dda15 100644 --- a/vulkan/vulkan_swapchain.cpp +++ b/vulkan/vulkan_swapchain.cpp @@ -126,7 +126,7 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width, // If extents aren't reported (Wayland), we have to rely on Wayland to report // the size, so keep current extent. - if (surface_capabilities.currentExtent.width != -1) + if (surface_capabilities.currentExtent.width != UINT32_MAX) extents = surface_capabilities.currentExtent; uint32_t graphics_queue_index = 0; From 77f86ef4b6f78169658747f6d1e47c1ed9415813 Mon Sep 17 00:00:00 2001 From: OV2 Date: Sun, 5 May 2024 19:25:47 +0200 Subject: [PATCH 03/51] win32: only deinint d3d imgui elements if they were initialized --- win32/CDirect3D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win32/CDirect3D.cpp b/win32/CDirect3D.cpp index 910d39c4..1c7558c7 100644 --- a/win32/CDirect3D.cpp +++ b/win32/CDirect3D.cpp @@ -159,7 +159,7 @@ bool CDirect3D::Initialize(HWND hWnd) void CDirect3D::DeInitialize() { - if (S9xImGuiRunning()) + if (init_done && S9xImGuiRunning()) { ImGui_ImplDX9_Shutdown(); S9xImGuiDeinit(); From 73cb8014f113c97fc1f93602d440688155beee64 Mon Sep 17 00:00:00 2001 From: BearOso Date: Tue, 7 May 2024 14:01:37 -0500 Subject: [PATCH 04/51] Win32: Show whether save state exists when slot selected. --- win32/wlanguage.h | 2 +- win32/wsnes9x.cpp | 28 +++++++++++++++++++--------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/win32/wlanguage.h b/win32/wlanguage.h index 8577f1a5..c74a64d8 100644 --- a/win32/wlanguage.h +++ b/win32/wlanguage.h @@ -360,7 +360,7 @@ Nintendo is a trademark.") // Save Messages -#define FREEZE_INFO_SET_SLOT_N "Set save slot %03d" +#define FREEZE_INFO_SET_SLOT_N "Set save slot %03d [%s]" #define FREEZE_INFO_SET_BANK_N "Set save bank %03d" // AVI Messages diff --git a/win32/wsnes9x.cpp b/win32/wsnes9x.cpp index f25d0dc8..774ff7cd 100644 --- a/win32/wsnes9x.cpp +++ b/win32/wsnes9x.cpp @@ -727,6 +727,22 @@ static char InfoString [100]; static uint32 prevPadReadFrame = (uint32)-1; static bool skipNextFrameStop = false; +static void ShowStatusSlotInfo() +{ + static char str[64]; + + char filename[_MAX_PATH + 1] + GetSlotFilename(GUI.CurrentSaveBank * SAVE_SLOTS_PER_BANK + GUI.CurrentSaveSlot, filename); + + bool exists = false; + struct stat stats; + if (stat(filename, &stats) == 0) + exists = true; + + sprintf(str, FREEZE_INFO_SET_SLOT_N, GUI.CurrentSaveSlot, exists ? "used" : "empty"); + S9xSetInfoString(str); +} + int HandleKeyMessage(WPARAM wParam, LPARAM lParam) { // update toggles @@ -889,9 +905,7 @@ int HandleKeyMessage(WPARAM wParam, LPARAM lParam) if(GUI.CurrentSaveSlot > LAST_SAVE_SLOT_IN_BANK) GUI.CurrentSaveSlot = 0; - static char str [64]; - sprintf(str, FREEZE_INFO_SET_SLOT_N, GUI.CurrentSaveSlot); - S9xSetInfoString(str); + ShowStatusSlotInfo(); hitHotKey = true; } @@ -902,9 +916,7 @@ int HandleKeyMessage(WPARAM wParam, LPARAM lParam) if(GUI.CurrentSaveSlot < 0) GUI.CurrentSaveSlot = 9; - static char str [64]; - sprintf(str, FREEZE_INFO_SET_SLOT_N, GUI.CurrentSaveSlot); - S9xSetInfoString(str); + ShowStatusSlotInfo(); hitHotKey = true; } @@ -1270,9 +1282,7 @@ int HandleKeyMessage(WPARAM wParam, LPARAM lParam) { GUI.CurrentSaveSlot = GUI.CurrentSaveBank * SAVE_SLOTS_PER_BANK + i; - static char str [64]; - sprintf(str, FREEZE_INFO_SET_SLOT_N, GUI.CurrentSaveSlot); - S9xSetInfoString(str); + ShowStatusSlotInfo(); hitHotKey = true; } From bac6798141d6ef55f8dec151b49c76d9246f1d8c Mon Sep 17 00:00:00 2001 From: BearOso Date: Tue, 7 May 2024 14:06:33 -0500 Subject: [PATCH 05/51] Win32: Fix missing semicolon. --- win32/wsnes9x.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win32/wsnes9x.cpp b/win32/wsnes9x.cpp index 774ff7cd..2732fe7c 100644 --- a/win32/wsnes9x.cpp +++ b/win32/wsnes9x.cpp @@ -731,7 +731,7 @@ static void ShowStatusSlotInfo() { static char str[64]; - char filename[_MAX_PATH + 1] + char filename[_MAX_PATH + 1]; GetSlotFilename(GUI.CurrentSaveBank * SAVE_SLOTS_PER_BANK + GUI.CurrentSaveSlot, filename); bool exists = false; From c476e4acdc132312e7154dc3bb0ff512e4577eea Mon Sep 17 00:00:00 2001 From: BearOso Date: Tue, 7 May 2024 14:18:40 -0500 Subject: [PATCH 06/51] Gtk: Show existence of save state on slot select. --- gtk/src/gtk_control.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/gtk/src/gtk_control.cpp b/gtk/src/gtk_control.cpp index e2053a76..2f24b318 100644 --- a/gtk/src/gtk_control.cpp +++ b/gtk/src/gtk_control.cpp @@ -5,8 +5,10 @@ \*****************************************************************************/ #include +#include #include "SDL_joystick.h" +#include "fscompat.h" #include "gtk_s9x.h" #include "gtk_config.h" #include "gtk_control.h" @@ -195,7 +197,15 @@ static void change_slot(int difference) if (!gui_config->rom_loaded) return; - auto info_string = "State Slot: " + std::to_string(gui_config->current_save_slot); + char extension_string[5]; + snprintf(extension_string, 5, ".%03d", gui_config->current_save_slot); + auto filename = S9xGetFilename(extension_string, SNAPSHOT_DIR); + struct stat info; + std::string exists = "empty"; + if (stat(filename.c_str(), &info) == 0) + exists = "used"; + + auto info_string = "State Slot: " + std::to_string(gui_config->current_save_slot) + " [" + exists + "]"; S9xSetInfoString(info_string.c_str()); GFX.InfoStringTimeout = 60; } From add607c38fcab21af635f039fab67ddf1f3ee3ca Mon Sep 17 00:00:00 2001 From: BearOso Date: Tue, 7 May 2024 14:27:28 -0500 Subject: [PATCH 07/51] Qt: Add save slot status info. --- qt/src/EmuApplication.cpp | 21 ++++++++++----------- qt/src/Snes9xController.cpp | 5 +++++ qt/src/Snes9xController.hpp | 3 +-- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/qt/src/EmuApplication.cpp b/qt/src/EmuApplication.cpp index 9b6668cb..b6c4a5e6 100644 --- a/qt/src/EmuApplication.cpp +++ b/qt/src/EmuApplication.cpp @@ -335,22 +335,21 @@ void EmuApplication::handleBinding(std::string name, bool pressed) window->pauseContinue(); } - else if (name == "IncreaseSlot") + else if (name == "IncreaseSlot" || name == "DecreaseSlot") { - save_slot++; + if (name == "IncreaseSlot") + save_slot++; + else + save_slot--; + if (save_slot > 999) save_slot = 0; - emu_thread->runOnThread([&] { - core->setMessage("Current slot: " + std::to_string(save_slot)); - }); - } - else if (name == "DecreaseSlot") - { - save_slot--; if (save_slot < 0) save_slot = 999; - emu_thread->runOnThread([&] { - core->setMessage("Current slot: " + std::to_string(save_slot)); + + emu_thread->runOnThread([&, slot = this->save_slot] { + std::string status = core->slotUsed(slot) ? " [used]" : " [empty]"; + core->setMessage("Current slot: " + std::to_string(save_slot) + status); }); } else if (name == "SaveState") diff --git a/qt/src/Snes9xController.cpp b/qt/src/Snes9xController.cpp index 83373e23..c006066f 100644 --- a/qt/src/Snes9xController.cpp +++ b/qt/src/Snes9xController.cpp @@ -718,6 +718,11 @@ std::string Snes9xController::getStateFolder() return S9xGetDirectory(SNAPSHOT_DIR); } +bool Snes9xController::slotUsed(int slot) +{ + return fs::exists(save_slot_path(slot)); +} + bool Snes9xController::loadState(int slot) { return loadState(save_slot_path(slot).u8string()); diff --git a/qt/src/Snes9xController.hpp b/qt/src/Snes9xController.hpp index fac58945..c69b681a 100644 --- a/qt/src/Snes9xController.hpp +++ b/qt/src/Snes9xController.hpp @@ -16,13 +16,12 @@ class Snes9xController void deinit(); void mainLoop(); bool openFile(std::string filename); + bool slotUsed(int slot); bool loadState(std::string filename); bool loadState(int slot); void loadUndoState(); bool saveState(std::string filename); bool saveState(int slot); - void increaseSaveSlot(); - void decreaseSaveSlot(); void updateSettings(const EmuConfig * const config); void updateBindings(const EmuConfig * const config); void reportBinding(EmuBinding b, bool active); From be53955553f973ad2d812e15f885d734eeb27936 Mon Sep 17 00:00:00 2001 From: OV2 Date: Wed, 8 May 2024 16:53:11 +0200 Subject: [PATCH 08/51] win32: allow multiselect in cheat dialog, handle delete and selection (#916) --- win32/rsrc/snes9x.rc | 2 +- win32/wsnes9x.cpp | 132 +++++++++++++++++++++++++++++-------------- 2 files changed, 91 insertions(+), 43 deletions(-) diff --git a/win32/rsrc/snes9x.rc b/win32/rsrc/snes9x.rc index 7753533b..bf492581 100644 --- a/win32/rsrc/snes9x.rc +++ b/win32/rsrc/snes9x.rc @@ -241,7 +241,7 @@ STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_M CAPTION "Cheat Entry and Editor" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CONTROL "List1",IDC_CHEAT_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,6,6,294,120,WS_EX_CLIENTEDGE + CONTROL "List1",IDC_CHEAT_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,6,6,294,120,WS_EX_CLIENTEDGE DEFPUSHBUTTON "&Add",IDC_ADD_CHEAT,306,6,66,14,WS_DISABLED PUSHBUTTON "&Delete",IDC_DELETE_CHEAT,306,60,66,14,WS_DISABLED PUSHBUTTON "&Update",IDC_UPDATE_CHEAT,306,24,66,14,WS_DISABLED diff --git a/win32/wsnes9x.cpp b/win32/wsnes9x.cpp index 2732fe7c..a4c2cb94 100644 --- a/win32/wsnes9x.cpp +++ b/win32/wsnes9x.cpp @@ -8669,6 +8669,25 @@ int WinSearchCheatDatabase() ListView_GetItem(GetDlgItem(hDlg, b), &a); #define CHEAT_SIZE 1024 +/* return a vector of all selected list items with their index in the listview +* as first element and their lparam as second element of a pair +*/ +static std::vector> get_all_selected_listitems(HWND lView) +{ + std::vector> result; + LVITEM lvitem = { 0 }; + lvitem.mask = LVIF_PARAM; + int index = ListView_GetNextItem(lView, -1, LVNI_SELECTED); + do + { + lvitem.iItem = index; + ListView_GetItem(lView, &lvitem); + result.push_back(std::make_pair(index, (int)lvitem.lParam)); + } while ((index = ListView_GetNextItem(lView, index, LVNI_SELECTED)) != -1); + + return result; +} + INT_PTR CALLBACK DlgCheater(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { static bool internal_change; @@ -8754,41 +8773,67 @@ INT_PTR CALLBACK DlgCheater(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch(LOWORD(wParam)) { - case IDC_CHEAT_LIST: - if(0==ListView_GetSelectedCount(GetDlgItem(hDlg, IDC_CHEAT_LIST))) - { - EnableWindow(GetDlgItem(hDlg, IDC_DELETE_CHEAT), false); - EnableWindow(GetDlgItem(hDlg, IDC_UPDATE_CHEAT), false); - has_sel=false; - sel_idx=-1; - } - else - { - EnableWindow(GetDlgItem(hDlg, IDC_DELETE_CHEAT), true); - if(!has_sel||sel_idx!=ListView_GetSelectionMark(GetDlgItem(hDlg, IDC_CHEAT_LIST))) - { - new_sel=3; - //change - TCHAR buf[CHEAT_SIZE]; - LV_ITEM lvi; + case IDC_CHEAT_LIST: + { + // react only to item changes (we are interested in selection or checkbox) + if (((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) + { + NMLISTVIEW* listview_notify = (NMLISTVIEW*)lParam; + if (listview_notify->uChanged & LVIF_STATE) + { + HWND lView = GetDlgItem(hDlg, IDC_CHEAT_LIST); + int sel_count = ListView_GetSelectedCount(lView); + // selection change, update button states and selection tracking variable + if ((listview_notify->uOldState & LVIS_SELECTED) != (listview_notify->uNewState & LVIS_SELECTED)) + { + if (0 == sel_count) + { + EnableWindow(GetDlgItem(hDlg, IDC_DELETE_CHEAT), false); + EnableWindow(GetDlgItem(hDlg, IDC_UPDATE_CHEAT), false); + has_sel = false; + sel_idx = -1; + } + else + { + EnableWindow(GetDlgItem(hDlg, IDC_DELETE_CHEAT), true); + if (!has_sel || sel_idx != ListView_GetSelectionMark(lView)) + { + new_sel = 3; + //change + TCHAR buf[CHEAT_SIZE]; + LV_ITEM lvi; - internal_change = true; // do not enable update button + internal_change = true; // do not enable update button - /* Code */ - ITEM_QUERY (lvi, IDC_CHEAT_LIST, 0, buf, CHEAT_SIZE); - SetDlgItemText(hDlg, IDC_CHEAT_CODE, lvi.pszText); + /* Code */ + ITEM_QUERY(lvi, IDC_CHEAT_LIST, 0, buf, CHEAT_SIZE); + SetDlgItemText(hDlg, IDC_CHEAT_CODE, lvi.pszText); - /* Description */ - ITEM_QUERY(lvi, IDC_CHEAT_LIST, 1, buf, CHEAT_SIZE); - SetDlgItemText(hDlg, IDC_CHEAT_DESCRIPTION, lvi.pszText); + /* Description */ + ITEM_QUERY(lvi, IDC_CHEAT_LIST, 1, buf, CHEAT_SIZE); + SetDlgItemText(hDlg, IDC_CHEAT_DESCRIPTION, lvi.pszText); - internal_change = false; - } - sel_idx=ListView_GetSelectionMark(GetDlgItem(hDlg, IDC_CHEAT_LIST)); - has_sel=true; - } + internal_change = false; + } + sel_idx = ListView_GetSelectionMark(lView); + has_sel = true; + } + } - return true; + // multi-select and change of checkbox state - set same state to all selected items + if (sel_count > 1 && (listview_notify->uOldState & LVIS_STATEIMAGEMASK) != (listview_notify->uNewState & LVIS_STATEIMAGEMASK)) + { + auto selected_items = get_all_selected_listitems(lView); + for (const auto &item : selected_items) + { + ListView_SetItemState(lView, item.first, listview_notify->uNewState, LVIS_STATEIMAGEMASK); + } + } + + return true; + } + } + } default: return false; } } @@ -8904,20 +8949,22 @@ INT_PTR CALLBACK DlgCheater(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) break; case IDC_DELETE_CHEAT: { - LVITEM lvi; + // save index, deleting item removes selection + int old_sel = sel_idx; + HWND lView = GetDlgItem(hDlg, IDC_CHEAT_LIST); + auto deleted_items = get_all_selected_listitems(lView); - // get index in internal cheat list, if present mark as deleted - memset(&lvi, 0, sizeof(LVITEM)); - lvi.mask = LVIF_PARAM; - lvi.iItem = sel_idx; - ListView_GetItem(GetDlgItem(hDlg, IDC_CHEAT_LIST), &lvi); - if (lvi.lParam >= 0) - ct.state[lvi.lParam] = Deleted; + // we delete in reverse order so that our item indexes stay valid + std::reverse(deleted_items.begin(), deleted_items.end()); + for (const auto &item : deleted_items) + { + // get index in internal cheat list, if present mark as deleted + if(item.second >= 0) + ct.state[item.second] = Deleted; + ListView_DeleteItem(lView, item.first); + } - // save index, deleting item removes selection - int old_sel = sel_idx; - ListView_DeleteItem(GetDlgItem(hDlg, IDC_CHEAT_LIST), sel_idx); - ListView_SetItemState(GetDlgItem(hDlg, IDC_CHEAT_LIST), old_sel, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); + ListView_SetItemState(lView, old_sel, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); } break; @@ -9087,6 +9134,7 @@ INT_PTR CALLBACK DlgCheater(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) return false; } } + default: return false; } } From ba6f67510ec01c8cc171219d3730a7f7fd2cb423 Mon Sep 17 00:00:00 2001 From: OV2 Date: Thu, 9 May 2024 13:35:52 +0200 Subject: [PATCH 09/51] win32: fix warnings --- win32/COpenGL.cpp | 2 +- win32/win32.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/win32/COpenGL.cpp b/win32/COpenGL.cpp index 389ff005..1d8567fd 100644 --- a/win32/COpenGL.cpp +++ b/win32/COpenGL.cpp @@ -139,7 +139,7 @@ bool COpenGL::Initialize(HWND hWnd) { auto defaults = S9xImGuiGetDefaults(); defaults.font_size = GUI.OSDSize; - defaults.spacing = defaults.font_size / 2.4; + defaults.spacing = static_cast(defaults.font_size / 2.4); S9xImGuiInit(&defaults); ImGui_ImplOpenGL3_Init(); Settings.DisplayIndicators = true; diff --git a/win32/win32.cpp b/win32/win32.cpp index 28e71e8c..682492e8 100644 --- a/win32/win32.cpp +++ b/win32/win32.cpp @@ -48,7 +48,6 @@ static int avi_image_size = 0; static uint32 avi_skip_frames = 0; static bool pre_avi_soundsync = true; static uint32 pre_avi_soundinputrate = 32000; -void DoAVIOpen(const char* filename); void DoAVIClose(int reason); void S9xWinScanJoypads (); From bf83f0f605ade9addf8368f5d82272acd6e043c0 Mon Sep 17 00:00:00 2001 From: OV2 Date: Thu, 9 May 2024 14:59:31 +0200 Subject: [PATCH 10/51] win32: add hotkey to switch aspect ratio (#912) --- win32/wconfig.cpp | 1 + win32/wlanguage.h | 2 ++ win32/wsnes9x.cpp | 43 ++++++++++++++++++++++++++++++++++++------- win32/wsnes9x.h | 4 ++++ 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/win32/wconfig.cpp b/win32/wconfig.cpp index e1977f04..319e1b6f 100644 --- a/win32/wconfig.cpp +++ b/win32/wconfig.cpp @@ -939,6 +939,7 @@ void WinRegisterConfigItems() ADD(SaveFileSelect); ADD(LoadFileSelect); ADD(Mute); ADD(ToggleBackdrop); + ADD(AspectRatio); #undef ADD #undef ADDN #undef CATEGORY diff --git a/win32/wlanguage.h b/win32/wlanguage.h index c74a64d8..46e819aa 100644 --- a/win32/wlanguage.h +++ b/win32/wlanguage.h @@ -136,6 +136,8 @@ Nintendo is a trademark.") #define HOTKEYS_LABEL_4_11 TEXT("Save to file:") #define HOTKEYS_LABEL_4_12 TEXT("Load from file:") +#define HOTKEYS_SWITCH_ASPECT_RATIO TEXT("Switch aspect Ratio:") + // gaming buttons and axes #define GAMEDEVICE_JOYNUMPREFIX "(J%x)" // don't change this #define GAMEDEVICE_JOYBUTPREFIX "#[%d]" // don't change this diff --git a/win32/wsnes9x.cpp b/win32/wsnes9x.cpp index a4c2cb94..df18000c 100644 --- a/win32/wsnes9x.cpp +++ b/win32/wsnes9x.cpp @@ -125,7 +125,8 @@ void S9xWinScanJoypads(); #define TIMER_SCANJOYPADS (99999) #define NC_SEARCHDB 0x8000 -#define MAX_SWITCHABLE_HOTKEY_DIALOG_ITEMS 14 +constexpr int MAX_SWITCHABLE_HOTKEY_DIALOG_ITEMS = 14; +constexpr int MAX_SWITCHABLE_HOTKEY_DIALOG_PAGES = 5; #ifdef UNICODE #define S9XW_SHARD_PATH SHARD_PATHW @@ -1222,6 +1223,18 @@ int HandleKeyMessage(WPARAM wParam, LPARAM lParam) FreezeUnfreezeDialog(FALSE); hitHotKey = true; } + if (wParam == CustomKeys.AspectRatio.key + && modifiers == CustomKeys.AspectRatio.modifiers) + { + if (GUI.AspectWidth == ASPECT_WIDTH_4_3) + { + GUI.AspectWidth = ASPECT_WIDTH_8_7; + } + else + { + GUI.AspectWidth = ASPECT_WIDTH_4_3; + } + } if (wParam == CustomKeys.Mute.key && modifiers == CustomKeys.Mute.modifiers) @@ -7562,10 +7575,10 @@ INT_PTR CALLBACK DlgFunky(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) SendDlgItemMessage(hDlg, IDC_ASPECTDROP, CB_ADDSTRING, 0, (LPARAM)TEXT("8:7")); SendDlgItemMessage(hDlg, IDC_ASPECTDROP, CB_ADDSTRING, 0, (LPARAM)TEXT("4:3")); switch (GUI.AspectWidth) { - case 256: + case ASPECT_WIDTH_4_3: SendDlgItemMessage(hDlg, IDC_ASPECTDROP, CB_SETCURSEL, (WPARAM)0, 0); break; - case 299: + case ASPECT_WIDTH_8_7: SendDlgItemMessage(hDlg, IDC_ASPECTDROP, CB_SETCURSEL, (WPARAM)1, 0); break; default: @@ -7731,10 +7744,10 @@ INT_PTR CALLBACK DlgFunky(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) int newsel = SendDlgItemMessage(hDlg,IDC_ASPECTDROP,CB_GETCURSEL,0,0); switch(newsel) { case 0: - GUI.AspectWidth = 256; + GUI.AspectWidth = ASPECT_WIDTH_4_3; break; case 1: - GUI.AspectWidth = 299; + GUI.AspectWidth = ASPECT_WIDTH_8_7; break; default: GUI.AspectWidth = prevAspectWidth; @@ -8301,7 +8314,7 @@ struct hotkey_dialog_item { // this structure defines the four sub pages in the hotkey config dialog // to keep an entry blank, set the SCustomKey pointer to NULL and the text to an empty string -static hotkey_dialog_item hotkey_dialog_items[4][MAX_SWITCHABLE_HOTKEY_DIALOG_ITEMS] = { +static hotkey_dialog_item hotkey_dialog_items[MAX_SWITCHABLE_HOTKEY_DIALOG_PAGES][MAX_SWITCHABLE_HOTKEY_DIALOG_ITEMS] = { { { &CustomKeys.SpeedUp, HOTKEYS_LABEL_1_1 }, { &CustomKeys.SpeedDown, HOTKEYS_LABEL_1_2 }, @@ -8366,6 +8379,22 @@ static hotkey_dialog_item hotkey_dialog_items[4][MAX_SWITCHABLE_HOTKEY_DIALOG_IT { NULL, _T("") }, { NULL, _T("") }, }, + { + { &CustomKeys.AspectRatio, HOTKEYS_SWITCH_ASPECT_RATIO }, + { NULL, _T("") }, + { NULL, _T("") }, + { NULL, _T("") }, + { NULL, _T("") }, + { NULL, _T("") }, + { NULL, _T("") }, + { NULL, _T("") }, + { NULL, _T("") }, + { NULL, _T("") }, + { NULL, _T("") }, + { NULL, _T("") }, + { NULL, _T("") }, + { NULL, _T("") }, + }, }; static void set_hotkeyinfo(HWND hDlg) @@ -8434,7 +8463,7 @@ switch(msg) SetWindowText(hDlg,HOTKEYS_TITLE); // insert hotkey page list items - for(i=1 ; i <= 4 ; i++) + for(i=1 ; i <= MAX_SWITCHABLE_HOTKEY_DIALOG_PAGES; i++) { TCHAR temp[256]; _stprintf(temp,HOTKEYS_HKCOMBO,i); diff --git a/win32/wsnes9x.h b/win32/wsnes9x.h index 2995fd16..2084ddae 100644 --- a/win32/wsnes9x.h +++ b/win32/wsnes9x.h @@ -39,6 +39,9 @@ #define NUM_SAVE_BANKS 10 #define LAST_SAVE_BANK (NUM_SAVE_BANKS - 1) +constexpr int ASPECT_WIDTH_4_3 = 256; +constexpr int ASPECT_WIDTH_8_7 = 299; + #include "_tfwopen.h" #ifdef UNICODE #define _tToChar WideToUtf8 @@ -348,6 +351,7 @@ struct SCustomKeys { SCustomKey SaveFileSelect; SCustomKey LoadFileSelect; SCustomKey Mute; + SCustomKey AspectRatio; }; struct SJoypad { From 87f050febaf2a28819061479f871724070834adb Mon Sep 17 00:00:00 2001 From: OV2 Date: Fri, 10 May 2024 00:10:13 +0200 Subject: [PATCH 11/51] win32: add cheat edit and search dialogs as hotkeys (#918) --- win32/InputCustom.cpp | 2 +- win32/rsrc/resource.h | 1 - win32/rsrc/snes9x.rc | 7 +-- win32/wconfig.cpp | 2 + win32/wlanguage.h | 2 + win32/wsnes9x.cpp | 134 +++++++++++++++++++++++++++++------------- win32/wsnes9x.h | 2 + 7 files changed, 101 insertions(+), 49 deletions(-) diff --git a/win32/InputCustom.cpp b/win32/InputCustom.cpp index 7269ac65..194d97d5 100644 --- a/win32/InputCustom.cpp +++ b/win32/InputCustom.cpp @@ -445,7 +445,7 @@ bool IsReserved (WORD Key, int modifiers) || modifiers == CUSTKEY_ALT_MASK && (Key == VK_F5 || Key == VK_F7 || Key == VK_F8 || Key == VK_F9 || Key == 'R' || Key == 'T' || Key == /*VK_OEM_4*/0xDB || Key == /*VK_OEM_6*/0xDD - || Key == 'E' || Key == 'A' || Key == VK_RETURN || Key == VK_DELETE)) + || Key == 'E' || Key == VK_RETURN || Key == VK_DELETE)) return true; return false; diff --git a/win32/rsrc/resource.h b/win32/rsrc/resource.h index e298a516..901e5555 100644 --- a/win32/rsrc/resource.h +++ b/win32/rsrc/resource.h @@ -508,7 +508,6 @@ #define ID_CHANNELS_CHANNEL7 40145 #define ID_CHANNELS_CHANNEL8 40146 #define ID_CHANNELS_ENABLEALL 40147 -#define ID_CHEAT_SEARCH_MODAL 40148 #define ID_SAVESCREENSHOT 40151 #define ID_FILE_LOAD_GAME 40152 #define ID_FILE_LOADMULTICART 40153 diff --git a/win32/rsrc/snes9x.rc b/win32/rsrc/snes9x.rc index bf492581..6c5833b9 100644 --- a/win32/rsrc/snes9x.rc +++ b/win32/rsrc/snes9x.rc @@ -802,8 +802,6 @@ IDC_CURSOR_SCOPE CURSOR "nodrop.cur" IDR_SNES9X_ACCELERATORS ACCELERATORS BEGIN - "G", ID_CHEAT_ENTER, VIRTKEY, ALT, NOINVERT - "A", ID_CHEAT_SEARCH, VIRTKEY, ALT, NOINVERT "O", ID_FILE_LOAD_GAME, VIRTKEY, CONTROL, NOINVERT VK_F5, ID_OPTIONS_DISPLAY, VIRTKEY, ALT, NOINVERT VK_F7, ID_OPTIONS_JOYPAD, VIRTKEY, ALT, NOINVERT @@ -1081,9 +1079,8 @@ BEGIN END POPUP "&Cheat", 0,MFT_STRING,MFS_ENABLED BEGIN - MENUITEM "&Game Genie, Pro-Action Replay Codes\tAlt+G", ID_CHEAT_ENTER,MFT_STRING,MFS_ENABLED - MENUITEM "&Search for New Cheats", ID_CHEAT_SEARCH_MODAL,MFT_STRING,MFS_ENABLED - MENUITEM "Search for New Cheats (active)\tAlt+A", 40064,MFT_STRING,MFS_ENABLED + MENUITEM "&Game Genie, Pro-Action Replay Codes", ID_CHEAT_ENTER,MFT_STRING,MFS_ENABLED + MENUITEM "&Search for New Cheats", ID_CHEAT_SEARCH,MFT_STRING,MFS_ENABLED MENUITEM "&Apply Cheats", ID_CHEAT_APPLY,MFT_STRING,MFS_CHECKED END POPUP "&Netplay", 0,MFT_STRING,MFS_ENABLED diff --git a/win32/wconfig.cpp b/win32/wconfig.cpp index 319e1b6f..cd11f51f 100644 --- a/win32/wconfig.cpp +++ b/win32/wconfig.cpp @@ -940,6 +940,8 @@ void WinRegisterConfigItems() ADD(Mute); ADD(ToggleBackdrop); ADD(AspectRatio); + ADD(CheatEditorDialog); + ADD(CheatSearchDialog); #undef ADD #undef ADDN #undef CATEGORY diff --git a/win32/wlanguage.h b/win32/wlanguage.h index 46e819aa..4a37ebb7 100644 --- a/win32/wlanguage.h +++ b/win32/wlanguage.h @@ -137,6 +137,8 @@ Nintendo is a trademark.") #define HOTKEYS_LABEL_4_12 TEXT("Load from file:") #define HOTKEYS_SWITCH_ASPECT_RATIO TEXT("Switch aspect Ratio:") +#define HOTKEYS_CHEAT_EDITOR_DIALOG TEXT("Cheats Editor Dialog:") +#define HOTKEYS_CHEAT_SEARCH_DIALOG TEXT("Cheats Search Dialog:") // gaming buttons and axes #define GAMEDEVICE_JOYNUMPREFIX "(J%x)" // don't change this diff --git a/win32/wsnes9x.cpp b/win32/wsnes9x.cpp index df18000c..c701631a 100644 --- a/win32/wsnes9x.cpp +++ b/win32/wsnes9x.cpp @@ -108,6 +108,8 @@ INT_PTR CALLBACK DlgCreateMovie(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara INT_PTR CALLBACK DlgOpenMovie(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); HRESULT CALLBACK EnumModesCallback( LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext); int WinSearchCheatDatabase(); +void WinShowCheatEditorDialog(); +void WinShowCheatSearchDialog(); VOID CALLBACK HotkeyTimer( UINT idEvent, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); @@ -408,11 +410,16 @@ struct SCustomKeys CustomKeys = { {0,0}}, // Select save slot 9 {'R',CUSTKEY_CTRL_MASK|CUSTKEY_ALT_MASK}, // Reset Game {0,0}, // Toggle Cheats - {0,0}, + {0,0}, // Quit {'R',0}, // Rewind + {0,0}, // Save File Select + {0,0}, // Load File Select + {0,0}, // Mute + {0,0}, // Aspect ratio + {'G', CUSTKEY_ALT_MASK}, // Cheat Editor Dialog + {'A', CUSTKEY_ALT_MASK}, // Cheat Search Dialog }; - struct SSoundRates { uint32 rate; @@ -1223,18 +1230,6 @@ int HandleKeyMessage(WPARAM wParam, LPARAM lParam) FreezeUnfreezeDialog(FALSE); hitHotKey = true; } - if (wParam == CustomKeys.AspectRatio.key - && modifiers == CustomKeys.AspectRatio.modifiers) - { - if (GUI.AspectWidth == ASPECT_WIDTH_4_3) - { - GUI.AspectWidth = ASPECT_WIDTH_8_7; - } - else - { - GUI.AspectWidth = ASPECT_WIDTH_4_3; - } - } if (wParam == CustomKeys.Mute.key && modifiers == CustomKeys.Mute.modifiers) @@ -1247,8 +1242,55 @@ int HandleKeyMessage(WPARAM wParam, LPARAM lParam) { auto cmd = S9xGetCommandT("ToggleBackdrop"); S9xApplyCommand(cmd, 1, 0); + hitHotKey = true; } + if (wParam == CustomKeys.AspectRatio.key + && modifiers == CustomKeys.AspectRatio.modifiers) + { + if (GUI.AspectWidth == ASPECT_WIDTH_4_3) + { + GUI.AspectWidth = ASPECT_WIDTH_8_7; + } + else + { + GUI.AspectWidth = ASPECT_WIDTH_4_3; + } + hitHotKey = true; + } + if (wParam == CustomKeys.CheatEditorDialog.key + && modifiers == CustomKeys.CheatEditorDialog.modifiers) + { + // update menu state + CheckMenuStates(); + // check menu state if item is enabled + MENUITEMINFO mii = { 0 }; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STATE; + GetMenuItemInfo(GUI.hMenu, ID_CHEAT_ENTER, FALSE, &mii); + if ((mii.fState & MFS_DISABLED) != MFS_DISABLED) + { + WinShowCheatEditorDialog(); + } + hitHotKey = true; + } + if (wParam == CustomKeys.CheatSearchDialog.key + && modifiers == CustomKeys.CheatSearchDialog.modifiers) + { + // update menu state + CheckMenuStates(); + // check menu state if item is enabled + MENUITEMINFO mii = { 0 }; + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STATE; + GetMenuItemInfo(GUI.hMenu, ID_CHEAT_SEARCH, FALSE, &mii); + if((mii.fState & MFS_DISABLED) != MFS_DISABLED) + { + WinShowCheatSearchDialog(); + } + hitHotKey = true; + } + //if(wParam == CustomKeys.BGLHack.key //&& modifiers == CustomKeys.BGLHack.modifiers) //{ @@ -1512,6 +1554,32 @@ static bool startingMovie = false; HWND cheatSearchHWND = NULL; +void WinShowCheatSearchDialog() +{ + RestoreGUIDisplay(); + if (!cheatSearchHWND) // create and show non-modal cheat search window + { + cheatSearchHWND = CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_CHEAT_SEARCH), GUI.hWnd, DlgCheatSearch); // non-modal/modeless + ShowWindow(cheatSearchHWND, SW_SHOW); + } + else // already open so just reactivate the window + { + SetActiveWindow(cheatSearchHWND); + } + RestoreSNESDisplay(); +} + +void WinShowCheatEditorDialog() +{ + RestoreGUIDisplay(); + while (DialogBox(g_hInst, MAKEINTRESOURCE(IDD_CHEATER), GUI.hWnd, DlgCheater) == NC_SEARCHDB) + { + WinSearchCheatDatabase(); + } + S9xSaveCheatFile(S9xGetFilename(".cht", CHEAT_DIR)); + RestoreSNESDisplay(); +} + #define MOVIE_LOCKED_SETTING if(S9xMovieActive()) {MessageBox(GUI.hWnd,TEXT("That setting is locked while a movie is active."),TEXT("Notice"),MB_OK|MB_ICONEXCLAMATION); break;} @@ -2224,32 +2292,10 @@ LRESULT CALLBACK WinProc( FreezeUnfreezeDialogPreview(TRUE); break; case ID_CHEAT_ENTER: - RestoreGUIDisplay (); - while (DialogBox(g_hInst, MAKEINTRESOURCE(IDD_CHEATER), hWnd, DlgCheater) == NC_SEARCHDB) - { - WinSearchCheatDatabase(); - } - S9xSaveCheatFile (S9xGetFilename (".cht", CHEAT_DIR)); - RestoreSNESDisplay (); + WinShowCheatEditorDialog(); break; case ID_CHEAT_SEARCH: - RestoreGUIDisplay (); - if(!cheatSearchHWND) // create and show non-modal cheat search window - { - cheatSearchHWND = CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_CHEAT_SEARCH), hWnd, DlgCheatSearch); // non-modal/modeless - ShowWindow(cheatSearchHWND, SW_SHOW); - } - else // already open so just reactivate the window - { - SetActiveWindow(cheatSearchHWND); - } - RestoreSNESDisplay (); - break; - case ID_CHEAT_SEARCH_MODAL: - RestoreGUIDisplay (); - DialogBox(g_hInst, MAKEINTRESOURCE(IDD_CHEAT_SEARCH), hWnd, DlgCheatSearch); // modal - S9xSaveCheatFile (S9xGetFilename (".cht", CHEAT_DIR)); - RestoreSNESDisplay (); + WinShowCheatSearchDialog(); break; case ID_CHEAT_APPLY: Settings.ApplyCheats = !Settings.ApplyCheats; @@ -3729,7 +3775,6 @@ static void CheckMenuStates () SetMenuItemInfo (GUI.hMenu, ID_FILE_RESET, FALSE, &mii); SetMenuItemInfo (GUI.hMenu, ID_CHEAT_ENTER, FALSE, &mii); - SetMenuItemInfo (GUI.hMenu, ID_CHEAT_SEARCH_MODAL, FALSE, &mii); SetMenuItemInfo (GUI.hMenu, IDM_ROM_INFO, FALSE, &mii); if (GUI.FullScreen) @@ -8381,8 +8426,8 @@ static hotkey_dialog_item hotkey_dialog_items[MAX_SWITCHABLE_HOTKEY_DIALOG_PAGES }, { { &CustomKeys.AspectRatio, HOTKEYS_SWITCH_ASPECT_RATIO }, - { NULL, _T("") }, - { NULL, _T("") }, + { &CustomKeys.CheatEditorDialog, HOTKEYS_CHEAT_EDITOR_DIALOG }, + { &CustomKeys.CheatSearchDialog, HOTKEYS_CHEAT_SEARCH_DIALOG }, { NULL, _T("") }, { NULL, _T("") }, { NULL, _T("") }, @@ -10124,7 +10169,12 @@ INT_PTR CALLBACK DlgCheatSearch(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPara default: break; } } - default: return false; + case WM_MENUCHAR: + // get rid of asterisk sound when pressing non existing menu hotkey - would play when opening + // with default alt + a hotkey + SetWindowLong(hDlg, DWLP_MSGRESULT, (MNC_CLOSE << 16)); + return true; + default: return false; } return false; } diff --git a/win32/wsnes9x.h b/win32/wsnes9x.h index 2084ddae..26eec1b1 100644 --- a/win32/wsnes9x.h +++ b/win32/wsnes9x.h @@ -352,6 +352,8 @@ struct SCustomKeys { SCustomKey LoadFileSelect; SCustomKey Mute; SCustomKey AspectRatio; + SCustomKey CheatEditorDialog; + SCustomKey CheatSearchDialog; }; struct SJoypad { From d62f14212eb50f6f59a1daae85fe2b5a4ff11591 Mon Sep 17 00:00:00 2001 From: OV2 Date: Fri, 10 May 2024 00:29:19 +0200 Subject: [PATCH 12/51] win32: default new cheat val to current cheat val, show error on empty new val (#918) --- win32/rsrc/snes9x.rc | 2 +- win32/wsnes9x.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/win32/rsrc/snes9x.rc b/win32/rsrc/snes9x.rc index 6c5833b9..4f52742a 100644 --- a/win32/rsrc/snes9x.rc +++ b/win32/rsrc/snes9x.rc @@ -237,7 +237,7 @@ BEGIN END IDD_CHEATER DIALOGEX 0, 0, 378, 189 -STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU CAPTION "Cheat Entry and Editor" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN diff --git a/win32/wsnes9x.cpp b/win32/wsnes9x.cpp index c701631a..56a32e95 100644 --- a/win32/wsnes9x.cpp +++ b/win32/wsnes9x.cpp @@ -10199,6 +10199,7 @@ INT_PTR CALLBACK DlgCheatSearchAdd(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP memset(buf,0,sizeof(TCHAR) * 12); _stprintf(buf, TEXT("%u"), new_cheat->new_val); SetDlgItemText(hDlg, IDC_NC_CURRVAL, buf); + SetDlgItemText(hDlg, IDC_NC_NEWVAL, buf); memset(buf,0,sizeof(TCHAR) * 12); _stprintf(buf, TEXT("%u"), new_cheat->saved_val); SetDlgItemText(hDlg, IDC_NC_PREVVAL, buf); @@ -10380,6 +10381,11 @@ INT_PTR CALLBACK DlgCheatSearchAdd(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP ret=0; } + else + { + MessageBox(hDlg, SEARCH_ERR_INVALIDNEWVALUE, SEARCH_TITLE_RANGEERROR, MB_OK); + return true; + } } case IDCANCEL: From 6dd6f1945b6a74ec9349d068725212a197dfacef Mon Sep 17 00:00:00 2001 From: BearOso Date: Fri, 10 May 2024 14:37:25 -0500 Subject: [PATCH 13/51] Update version strings from 1.62.3 to 1.63. --- appveyor.yml | 2 +- gtk/CMakeLists.txt | 2 +- gtk/po/pl.po | 2 +- gtk/po/uk.po | 2 +- macosx/Info.plist | 2 +- macosx/en.lproj/InfoPlist.strings | 4 ++-- macosx/snes9x.xcodeproj/project.pbxproj | 4 ++-- qt/CMakeLists.txt | 2 +- qt/src/resources/snes9x_win32.rc | 4 ++-- snes9x.h | 2 +- unix/configure.ac | 4 ++-- win32/rsrc/snes9x.rc | 4 ++-- 12 files changed, 17 insertions(+), 17 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index a944591d..e474790f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.62.3-{build} +version: 1.63-{build} image: Visual Studio 2022 diff --git a/gtk/CMakeLists.txt b/gtk/CMakeLists.txt index 36201b71..6d13d493 100644 --- a/gtk/CMakeLists.txt +++ b/gtk/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.18) -project(snes9x-gtk VERSION 1.62.3) +project(snes9x-gtk VERSION 1.63) option(USE_SLANG "Build support for Vulkan output and .slangp shaders" ON) option(USE_XV "Build support for XVideo output" ON) diff --git a/gtk/po/pl.po b/gtk/po/pl.po index 2f939f7a..4671159c 100644 --- a/gtk/po/pl.po +++ b/gtk/po/pl.po @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Snes9x 1.62.3\n" +"Project-Id-Version: Snes9x 1.63\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-10-29 23:56+0100\n" "PO-Revision-Date: 2023-10-30 12:00+0100\n" diff --git a/gtk/po/uk.po b/gtk/po/uk.po index f75674a2..ac72b5f9 100644 --- a/gtk/po/uk.po +++ b/gtk/po/uk.po @@ -2,7 +2,7 @@ # Stanley Kid , 2024. msgid "" msgstr "" -"Project-Id-Version: 1.62.3\n" +"Project-Id-Version: 1.63\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-10-29 23:56+0100\n" "PO-Revision-Date: 2024-02-14 15:43+0200\n" diff --git a/macosx/Info.plist b/macosx/Info.plist index a28e48bf..cd62ab10 100644 --- a/macosx/Info.plist +++ b/macosx/Info.plist @@ -162,7 +162,7 @@ CFBundleExecutable Snes9x (i386) CFBundleGetInfoString - Snes9x 1.62.3, Copyright 1996-2023 Snes9x developers. + Snes9x 1.63, Copyright 1996-2023 Snes9x developers. CFBundleHelpBookFolder Snes9x Help CFBundleHelpBookName diff --git a/macosx/en.lproj/InfoPlist.strings b/macosx/en.lproj/InfoPlist.strings index 5ab583be..fbb04e39 100644 --- a/macosx/en.lproj/InfoPlist.strings +++ b/macosx/en.lproj/InfoPlist.strings @@ -1,5 +1,5 @@ /* Localized versions of Info.plist keys */ CFBundleName = "Snes9x"; -CFBundleShortVersionString = "1.62.3"; -CFBundleGetInfoString = "Snes9x 1.62.3, Copyright 1996-2023 Snes9x developers."; +CFBundleShortVersionString = "1.63"; +CFBundleGetInfoString = "Snes9x 1.63, Copyright 1996-2023 Snes9x developers."; diff --git a/macosx/snes9x.xcodeproj/project.pbxproj b/macosx/snes9x.xcodeproj/project.pbxproj index 0220a348..20308f64 100755 --- a/macosx/snes9x.xcodeproj/project.pbxproj +++ b/macosx/snes9x.xcodeproj/project.pbxproj @@ -1501,7 +1501,7 @@ INFOPLIST_FILE = Snes9x/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.12; - MARKETING_VERSION = 1.62.3; + MARKETING_VERSION = 1.63; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.snes9x.macos.snes9x; @@ -1548,7 +1548,7 @@ INFOPLIST_FILE = Snes9x/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.12; - MARKETING_VERSION = 1.62.3; + MARKETING_VERSION = 1.63; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.snes9x.macos.snes9x; diff --git a/qt/CMakeLists.txt b/qt/CMakeLists.txt index 09090c2f..baa6104e 100644 --- a/qt/CMakeLists.txt +++ b/qt/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.20) -project(snes9x-qt VERSION 1.62) +project(snes9x-qt VERSION 1.63) include(GNUInstallDirs) diff --git a/qt/src/resources/snes9x_win32.rc b/qt/src/resources/snes9x_win32.rc index d214cd5e..18538207 100644 --- a/qt/src/resources/snes9x_win32.rc +++ b/qt/src/resources/snes9x_win32.rc @@ -13,12 +13,12 @@ BEGIN BEGIN VALUE "CompanyName", "http://www.snes9x.com" VALUE "FileDescription", "Snes9x" - VALUE "FileVersion", "1.62.3" + VALUE "FileVersion", "1.63" VALUE "InternalName", "Snes9x" VALUE "LegalCopyright", "Copyright (C) 1996-2023" VALUE "OriginalFilename", "snes9x-qt.exe" VALUE "ProductName", "Snes9x Qt Interface" - VALUE "ProductVersion", "1.62.3" + VALUE "ProductVersion", "1.63" END END diff --git a/snes9x.h b/snes9x.h index 57fab48b..658b2688 100644 --- a/snes9x.h +++ b/snes9x.h @@ -8,7 +8,7 @@ #define _SNES9X_H_ #ifndef VERSION -#define VERSION "1.62.3" +#define VERSION "1.63" #endif #include "port.h" diff --git a/unix/configure.ac b/unix/configure.ac index e6d804eb..01f149d0 100644 --- a/unix/configure.ac +++ b/unix/configure.ac @@ -1,6 +1,6 @@ AC_PREREQ([2.71]) -AC_INIT([Snes9x],[1.62.3],[],[snes9x]) -AC_REVISION([$Revision: 1.62.3 $]) +AC_INIT([Snes9x],[1.63],[],[snes9x]) +AC_REVISION([$Revision: 1.63 $]) AC_CONFIG_SRCDIR([unix.cpp]) diff --git a/win32/rsrc/snes9x.rc b/win32/rsrc/snes9x.rc index 4f52742a..d4c92627 100644 --- a/win32/rsrc/snes9x.rc +++ b/win32/rsrc/snes9x.rc @@ -883,12 +883,12 @@ BEGIN BEGIN VALUE "CompanyName", "http://www.snes9x.com" VALUE "FileDescription", "Snes9x" - VALUE "FileVersion", "1.62.3" + VALUE "FileVersion", "1.63" VALUE "InternalName", "Snes9x" VALUE "LegalCopyright", "Copyright 1996-2023" VALUE "OriginalFilename", "Snes9x.exe" VALUE "ProductName", "Snes9x SNES Emulator" - VALUE "ProductVersion", "1.62.3" + VALUE "ProductVersion", "1.63" END END BLOCK "VarFileInfo" From f62eb40ac733449758a717b4055c0f576df6d941 Mon Sep 17 00:00:00 2001 From: OV2 Date: Sun, 12 May 2024 01:20:34 +0200 Subject: [PATCH 14/51] win32: skip framerate throttling in turbo mode (#853) --- win32/win32_display.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win32/win32_display.cpp b/win32/win32_display.cpp index 61665496..c66b005e 100644 --- a/win32/win32_display.cpp +++ b/win32/win32_display.cpp @@ -706,7 +706,7 @@ void WinThrottleFramerate() static HANDLE throttle_timer = nullptr; static int64_t PCBase, PCFrameTime, PCFrameTimeNTSC, PCFrameTimePAL, PCStart, PCEnd; - if (Settings.SkipFrames != AUTO_FRAMERATE) + if (Settings.SkipFrames != AUTO_FRAMERATE || Settings.TurboMode) return; if (!throttle_timer) From 911b416d28e4bf15345f00622f33c615a645f1ea Mon Sep 17 00:00:00 2001 From: OV2 Date: Sun, 12 May 2024 01:23:23 +0200 Subject: [PATCH 15/51] win32: vulkan: apply vsync setting during init --- win32/CVulkan.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/win32/CVulkan.cpp b/win32/CVulkan.cpp index ec1a99d9..bbde45b8 100644 --- a/win32/CVulkan.cpp +++ b/win32/CVulkan.cpp @@ -91,6 +91,11 @@ bool CVulkan::Initialize(HWND hWnd) } } + if (context->swapchain->set_vsync(GUI.Vsync)) + { + context->recreate_swapchain(); + } + simple_output = std::make_unique(context.get(), vk::Format::eR5G6B5UnormPack16); return true; From cfabbd7f97c55a08215e8c3c8228109a37a60b41 Mon Sep 17 00:00:00 2001 From: BearOso Date: Sun, 12 May 2024 15:11:47 -0500 Subject: [PATCH 16/51] Qt: Prefer non-local config dir on Windows, and check for correct name. --- qt/src/EmuConfig.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qt/src/EmuConfig.cpp b/qt/src/EmuConfig.cpp index 90c420dd..7d90214e 100644 --- a/qt/src/EmuConfig.cpp +++ b/qt/src/EmuConfig.cpp @@ -144,7 +144,7 @@ std::string EmuConfig::findConfigDir() fs::path path; auto app_dir_path = QGuiApplication::applicationDirPath(); - auto config_file = QDir(app_dir_path).absoluteFilePath("snes9x.conf"); + auto config_file = QDir(app_dir_path).absoluteFilePath("snes9x-qt.conf"); if (QFile::exists(config_file)) return app_dir_path.toStdString(); @@ -164,12 +164,12 @@ std::string EmuConfig::findConfigDir() path = "./.snes9x"; } #else - if ((dir = getenv("LOCALAPPDATA"))) + if ((dir = getenv("APPDATA"))) { path = dir; path /= "Snes9x"; } - else if ((dir = getenv("APPDATA"))) + else if ((dir = getenv("LOCALAPPDATA"))) { path = dir; path /= "Snes9x"; From c9b90655bd85d7134654fbe0535ce14293ed850b Mon Sep 17 00:00:00 2001 From: BearOso Date: Mon, 13 May 2024 13:58:31 -0500 Subject: [PATCH 17/51] Qt/Windows: Match system color scheme. Use windowsvista style for light, dark fusion scheme for dark. --- qt/src/main.cpp | 60 ++++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/qt/src/main.cpp b/qt/src/main.cpp index b3b68139..58d459c9 100644 --- a/qt/src/main.cpp +++ b/qt/src/main.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #ifndef _WIN32 #include @@ -28,35 +29,42 @@ int main(int argc, char *argv[]) if (emu.qtapp->platformName() == "windows") { - emu.qtapp->setStyle("fusion"); + if (emu.qtapp->styleHints()->colorScheme() == Qt::ColorScheme::Dark) + { + emu.qtapp->setStyle("fusion"); - const QColor darkGray(53, 53, 53); - const QColor gray(128, 128, 128); - const QColor black(25, 25, 25); - const QColor blue(198, 238, 255); - const QColor blue2(0, 88, 208); + const QColor darkGray(53, 53, 53); + const QColor gray(128, 128, 128); + const QColor black(25, 25, 25); + const QColor blue(198, 238, 255); + const QColor blue2(0, 88, 208); - QPalette darkPalette; - darkPalette.setColor(QPalette::Window, darkGray); - darkPalette.setColor(QPalette::WindowText, Qt::white); - darkPalette.setColor(QPalette::Base, black); - darkPalette.setColor(QPalette::AlternateBase, darkGray); - darkPalette.setColor(QPalette::ToolTipBase, blue2); - darkPalette.setColor(QPalette::ToolTipText, Qt::white); - darkPalette.setColor(QPalette::Text, Qt::white); - darkPalette.setColor(QPalette::Button, darkGray); - darkPalette.setColor(QPalette::ButtonText, Qt::white); - darkPalette.setColor(QPalette::Link, blue); - darkPalette.setColor(QPalette::Highlight, blue2); - darkPalette.setColor(QPalette::HighlightedText, Qt::white); - darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker()); + QPalette darkPalette; + darkPalette.setColor(QPalette::Window, darkGray); + darkPalette.setColor(QPalette::WindowText, Qt::white); + darkPalette.setColor(QPalette::Base, black); + darkPalette.setColor(QPalette::AlternateBase, darkGray); + darkPalette.setColor(QPalette::ToolTipBase, blue2); + darkPalette.setColor(QPalette::ToolTipText, Qt::white); + darkPalette.setColor(QPalette::Text, Qt::white); + darkPalette.setColor(QPalette::Button, darkGray); + darkPalette.setColor(QPalette::ButtonText, Qt::white); + darkPalette.setColor(QPalette::Link, blue); + darkPalette.setColor(QPalette::Highlight, blue2); + darkPalette.setColor(QPalette::HighlightedText, Qt::white); + darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker()); - darkPalette.setColor(QPalette::Active, QPalette::Button, darkGray); - darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray); - darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray); - darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray); - darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray); - emu.qtapp->setPalette(darkPalette); + darkPalette.setColor(QPalette::Active, QPalette::Button, darkGray); + darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray); + darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray); + darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray); + darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray); + emu.qtapp->setPalette(darkPalette); + } + else + { + emu.qtapp->setStyle("windowsvista"); + } } #ifndef _WIN32 From 8f41776532c407744c41e5d08444cb2dbd492c14 Mon Sep 17 00:00:00 2001 From: BearOso Date: Mon, 13 May 2024 14:26:02 -0500 Subject: [PATCH 18/51] Qt: Hide software filter box. May remove this in the future because it's unneeded with shaders. --- qt/src/DisplayPanel.cpp | 2 ++ qt/src/DisplayPanel.ui | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/qt/src/DisplayPanel.cpp b/qt/src/DisplayPanel.cpp index f1a203ed..81ef566f 100644 --- a/qt/src/DisplayPanel.cpp +++ b/qt/src/DisplayPanel.cpp @@ -98,6 +98,8 @@ DisplayPanel::DisplayPanel(EmuApplication *app_) if (recreate) app->window->recreateUIAssets(); }); + + groupBox_software_filters->hide(); } DisplayPanel::~DisplayPanel() diff --git a/qt/src/DisplayPanel.ui b/qt/src/DisplayPanel.ui index dc44741f..49e7c0f0 100644 --- a/qt/src/DisplayPanel.ui +++ b/qt/src/DisplayPanel.ui @@ -311,7 +311,7 @@ Output directly will cause the screen to change between the two modes and look w - + Software Filters From 738e53989e29c912eba3be4656df18cecc76e69b Mon Sep 17 00:00:00 2001 From: BearOso Date: Sat, 18 May 2024 19:25:33 -0500 Subject: [PATCH 19/51] Cheats: Retain enabled state when updating existing cheat. Fix inverted logic in Qt cheat window. --- cheats2.cpp | 4 ++++ qt/src/CheatsDialog.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cheats2.cpp b/cheats2.cpp index 8f8ac473..7d2080a9 100644 --- a/cheats2.cpp +++ b/cheats2.cpp @@ -518,10 +518,14 @@ int S9xModifyCheatGroup(uint32 num, const std::string &name, const std::string & if (num >= Cheat.group.size()) return -1; + bool enabled = Cheat.group[num].enabled; S9xDisableCheatGroup(num); Cheat.group[num] = S9xCreateCheatGroup(name, cheat); + if (enabled) + S9xEnableCheatGroup(num); + return num; } diff --git a/qt/src/CheatsDialog.cpp b/qt/src/CheatsDialog.cpp index d260b1d5..7073d33d 100644 --- a/qt/src/CheatsDialog.cpp +++ b/qt/src/CheatsDialog.cpp @@ -63,7 +63,7 @@ void CheatsDialog::addCode() if (description.empty()) description = tr("No description").toStdString(); - if (app->addCheat(description, code)) + if (!app->addCheat(description, code)) { QMessageBox::information(this, tr("Invalid Cheat"), tr("The cheat you entered was not valid.")); return; From 794b4fdc728e632e00a8b190196468f51fa2107b Mon Sep 17 00:00:00 2001 From: BearOso Date: Fri, 24 May 2024 20:05:07 -0500 Subject: [PATCH 20/51] Qt: Remove debug print from hat press. --- qt/src/SDLInputManager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/qt/src/SDLInputManager.cpp b/qt/src/SDLInputManager.cpp index 7083e34d..066bd0c2 100644 --- a/qt/src/SDLInputManager.cpp +++ b/qt/src/SDLInputManager.cpp @@ -74,7 +74,6 @@ SDLInputManager::DiscretizeHatEvent(SDL_Event &event) for (auto &s : { SDL_HAT_UP, SDL_HAT_DOWN, SDL_HAT_LEFT, SDL_HAT_RIGHT }) if ((old_state & s) != (new_state & s)) { - printf(" old: %d, new: %d\n", old_state, new_state); dhe.direction = s; dhe.pressed = (new_state & s); old_state = new_state; @@ -226,4 +225,4 @@ std::vector> SDLInputManager::getXInputControllers() } return list; -} \ No newline at end of file +} From 55724eba1d44e9e488702a0495986975191ffa4e Mon Sep 17 00:00:00 2001 From: BearOso Date: Sat, 25 May 2024 12:04:58 -0500 Subject: [PATCH 21/51] Qt: Change browse button to "Open Folder" button when location isn't custom. Enables quick access to the ROM directory or the config directory. --- qt/src/EmuApplication.cpp | 5 ++++ qt/src/EmuApplication.hpp | 1 + qt/src/FoldersPanel.cpp | 56 +++++++++++++++++++++++++++---------- qt/src/Snes9xController.cpp | 6 ++++ qt/src/Snes9xController.hpp | 1 + 5 files changed, 55 insertions(+), 14 deletions(-) diff --git a/qt/src/EmuApplication.cpp b/qt/src/EmuApplication.cpp index b6c4a5e6..1a2bb8fb 100644 --- a/qt/src/EmuApplication.cpp +++ b/qt/src/EmuApplication.cpp @@ -642,6 +642,11 @@ QString EmuApplication::iconPrefix() return blackicons; } +std::string EmuApplication::getContentFolder() +{ + return core->getContentFolder(); +} + void EmuThread::runOnThread(std::function func, bool blocking) { if (QThread::currentThread() != this) diff --git a/qt/src/EmuApplication.hpp b/qt/src/EmuApplication.hpp index d23ac9e5..0936fb82 100644 --- a/qt/src/EmuApplication.hpp +++ b/qt/src/EmuApplication.hpp @@ -85,6 +85,7 @@ struct EmuApplication void stopThread(); bool isCoreActive(); QString iconPrefix(); + std::string getContentFolder(); std::vector> getCheatList(); void disableAllCheats(); diff --git a/qt/src/FoldersPanel.cpp b/qt/src/FoldersPanel.cpp index 8e3f3c0a..01c01047 100644 --- a/qt/src/FoldersPanel.cpp +++ b/qt/src/FoldersPanel.cpp @@ -3,6 +3,7 @@ #include "EmuConfig.hpp" #include #include +#include FoldersPanel::FoldersPanel(EmuApplication *app_) : app(app_) @@ -29,17 +30,6 @@ void FoldersPanel::connectEntry(QComboBox *combo, QLineEdit *lineEdit, QPushButt this->refreshEntry(combo, lineEdit, browse, location, folder); app->updateSettings(); }); - - QObject::connect(browse, &QPushButton::pressed, [=] { - QFileDialog dialog(this, tr("Select a Folder")); - dialog.setFileMode(QFileDialog::Directory); - dialog.setDirectory(QString::fromUtf8(*folder)); - if (!dialog.exec()) - return; - *folder = dialog.selectedFiles().at(0).toUtf8(); - lineEdit->setText(QString::fromUtf8(*folder)); - app->updateSettings(); - }); } void FoldersPanel::refreshData() @@ -53,18 +43,56 @@ void FoldersPanel::refreshData() void FoldersPanel::refreshEntry(QComboBox *combo, QLineEdit *lineEdit, QPushButton *browse, int *location, std::string *folder) { + QString rom_dir; bool custom = (*location == EmuConfig::eCustomDirectory); combo->setCurrentIndex(*location); if (custom) + { lineEdit->setText(QString::fromUtf8(*folder)); + } else if (*location == EmuConfig::eConfigDirectory) + { lineEdit->setText(tr("Config folder is %1").arg(app->config->findConfigDir().c_str())); - else - lineEdit->clear(); + } else + { + rom_dir = QString::fromStdString(app->getContentFolder()); + if (rom_dir.isEmpty()) + rom_dir = QString::fromStdString(app->config->last_rom_folder); + + lineEdit->setText("ROM Folder: " + rom_dir); + } lineEdit->setEnabled(custom); - browse->setEnabled(custom); + browse->disconnect(); + if (custom) + { + browse->setText(tr("Browse...")); + QObject::connect(browse, &QPushButton::pressed, [=] { + QFileDialog dialog(this, tr("Select a Folder")); + dialog.setFileMode(QFileDialog::Directory); + dialog.setDirectory(QString::fromUtf8(*folder)); + if (!dialog.exec()) + return; + *folder = dialog.selectedFiles().at(0).toUtf8(); + lineEdit->setText(QString::fromStdString(*folder)); + app->updateSettings(); + }); + } + else + { + QString dir{}; + if (*location == EmuConfig::eConfigDirectory) + dir = app->config->findConfigDir().c_str(); + else if (*location == EmuConfig::eROMDirectory) + dir = rom_dir; + + QObject::connect(browse, &QPushButton::pressed, [dir] { + QDesktopServices::openUrl(QUrl::fromLocalFile(dir)); + }); + lineEdit->setEnabled(custom); + browse->setText(tr("Open Folder...")); + } } void FoldersPanel::showEvent(QShowEvent *event) diff --git a/qt/src/Snes9xController.cpp b/qt/src/Snes9xController.cpp index c006066f..40562bed 100644 --- a/qt/src/Snes9xController.cpp +++ b/qt/src/Snes9xController.cpp @@ -1,6 +1,7 @@ #include "Snes9xController.hpp" #include "EmuConfig.hpp" #include "SoftwareScalers.hpp" +#include "fscompat.h" #include namespace fs = std::filesystem; @@ -855,3 +856,8 @@ int Snes9xController::modifyCheat(int index, std::string name, std::string code) { return S9xModifyCheatGroup(index, name, code); } + +std::string Snes9xController::getContentFolder() +{ + return S9xGetDirectory(ROMFILENAME_DIR); +} \ No newline at end of file diff --git a/qt/src/Snes9xController.hpp b/qt/src/Snes9xController.hpp index c69b681a..83814fa6 100644 --- a/qt/src/Snes9xController.hpp +++ b/qt/src/Snes9xController.hpp @@ -46,6 +46,7 @@ class Snes9xController int tryImportCheats(std::string filename); std::string validateCheat(std::string code); int modifyCheat(int index, std::string name, std::string code); + std::string getContentFolder(); std::string getStateFolder(); std::string config_folder; From a277d7f9e88fa377f9cc6f26c1f6008d0499d36e Mon Sep 17 00:00:00 2001 From: OV2 Date: Sun, 26 May 2024 17:02:43 +0200 Subject: [PATCH 22/51] win32: properly save bank+/- hotkeys (fixes #925) --- win32/wconfig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win32/wconfig.cpp b/win32/wconfig.cpp index cd11f51f..367f7b04 100644 --- a/win32/wconfig.cpp +++ b/win32/wconfig.cpp @@ -930,7 +930,7 @@ void WinRegisterConfigItems() ADDN(Save[0],SaveSlot0); ADDN(Save[1],SaveSlot1); ADDN(Save[2],SaveSlot2); ADDN(Save[3],SaveSlot3); ADDN(Save[4],SaveSlot4); ADDN(Save[5],SaveSlot5); ADDN(Save[6],SaveSlot6); ADDN(Save[7],SaveSlot7); ADDN(Save[8],SaveSlot8); ADDN(Save[9],SaveSlot9); ADDN(Load[0],LoadSlot0); ADDN(Load[1],LoadSlot1); ADDN(Load[2],LoadSlot2); ADDN(Load[3],LoadSlot3); ADDN(Load[4],LoadSlot4); ADDN(Load[5],LoadSlot5); ADDN(Load[6],LoadSlot6); ADDN(Load[7],LoadSlot7); ADDN(Load[8],LoadSlot8); ADDN(Load[9],LoadSlot9); ADDN(SelectSave[0],SelectSlot0); ADDN(SelectSave[1],SelectSlot1); ADDN(SelectSave[2],SelectSlot2); ADDN(SelectSave[3],SelectSlot3); ADDN(SelectSave[4],SelectSlot4); ADDN(SelectSave[5],SelectSlot5); ADDN(SelectSave[6],SelectSlot6); ADDN(SelectSave[7],SelectSlot7); ADDN(SelectSave[8],SelectSlot8); ADDN(SelectSave[9],SelectSlot9); - ADD(SaveScreenShot); ADD(SlotPlus); ADD(SlotMinus); ADD(SlotSave); ADD(SlotLoad); ADD(DialogSave); ADD(DialogLoad); + ADD(SaveScreenShot); ADD(SlotPlus); ADD(SlotMinus); ADD(SlotSave); ADD(SlotLoad); ADD(BankPlus); ADD(BankMinus); ADD(DialogSave); ADD(DialogLoad); ADD(BGL1); ADD(BGL2); ADD(BGL3); ADD(BGL4); ADD(BGL5); ADD(ClippingWindows); /*ADD(BGLHack);*/ ADD(Transparency); /*ADD(HDMA)*/; /*ADD(GLCube);*/ /*ADD(InterpMode7);*/ ADD(JoypadSwap); ADD(SwitchControllers); ADD(ResetGame); ADD(ToggleCheats); From c7b77d4a763e8fa3ee2c4ef63b3974527056b7ad Mon Sep 17 00:00:00 2001 From: BearOso Date: Fri, 7 Jun 2024 14:27:47 -0500 Subject: [PATCH 23/51] Win32: Throttle frame rate on alternate interlaced frames. --- win32/win32_display.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/win32/win32_display.cpp b/win32/win32_display.cpp index c66b005e..01b5eb22 100644 --- a/win32/win32_display.cpp +++ b/win32/win32_display.cpp @@ -288,6 +288,8 @@ bool8 S9xContinueUpdate(int Width, int Height) // avi writing DoAVIVideoFrame(); + WinThrottleFramerate(); + return true; } From 4f1a2d9c295f741faf4d04cb7410291b707242e1 Mon Sep 17 00:00:00 2001 From: BearOso Date: Tue, 11 Jun 2024 16:06:30 -0500 Subject: [PATCH 24/51] Vulkan: Remove exception handler/old swapchain use. Exceptions are now turned off anyway. --- vulkan/vulkan_swapchain.cpp | 41 ++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/vulkan/vulkan_swapchain.cpp b/vulkan/vulkan_swapchain.cpp index 762dda15..7c03693f 100644 --- a/vulkan/vulkan_swapchain.cpp +++ b/vulkan/vulkan_swapchain.cpp @@ -164,11 +164,21 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width, extents.height = surface_capabilities.minImageExtent.height; auto present_modes = physical_device.getSurfacePresentModesKHR(surface).value; - auto tearing_present_mode = vk::PresentModeKHR::eFifo; - if (std::find(present_modes.begin(), present_modes.end(), vk::PresentModeKHR::eImmediate) != present_modes.end()) - tearing_present_mode = vk::PresentModeKHR::eImmediate; - if (std::find(present_modes.begin(), present_modes.end(), vk::PresentModeKHR::eMailbox) != present_modes.end()) - tearing_present_mode = vk::PresentModeKHR::eMailbox; + bool mailbox_supported = + std::find(present_modes.begin(), present_modes.end(), + vk::PresentModeKHR::eMailbox) != present_modes.end(); + bool immediate_supported = + std::find(present_modes.begin(), present_modes.end(), + vk::PresentModeKHR::eImmediate) != present_modes.end(); + + vk::PresentModeKHR present_mode = vk::PresentModeKHR::eFifo; + if (mailbox_supported) + present_mode = vk::PresentModeKHR::eMailbox; + if (!vsync && immediate_supported) + present_mode = vk::PresentModeKHR::eImmediate; + + if (present_mode == vk::PresentModeKHR::eMailbox) + num_swapchain_images++; auto swapchain_create_info = vk::SwapchainCreateInfoKHR{} .setMinImageCount(num_swapchain_images) @@ -179,23 +189,20 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width, .setImageUsage(vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc) .setCompositeAlpha(vk::CompositeAlphaFlagBitsKHR::eOpaque) .setClipped(true) - .setPresentMode(vsync ? vk::PresentModeKHR::eFifo : tearing_present_mode) + .setPresentMode(present_mode) .setSurface(surface) .setPreTransform(vk::SurfaceTransformFlagBitsKHR::eIdentity) .setImageArrayLayers(1) .setQueueFamilyIndices(graphics_queue_index); - if (swapchain_object) - swapchain_create_info.setOldSwapchain(swapchain_object.get()); - - try { - swapchain_object = device.createSwapchainKHRUnique(swapchain_create_info).value; - } catch (std::exception &e) { + swapchain_object.reset(); + auto resval = device.createSwapchainKHRUnique(swapchain_create_info); + if (resval.result != vk::Result::eSuccess && resval.result != vk::Result::eSuboptimalKHR) + { swapchain_object.reset(); - } - - if (!swapchain_object) return false; + } + swapchain_object = std::move(resval.value); auto swapchain_images = device.getSwapchainImagesKHR(swapchain_object.get()).value; vk::CommandBufferAllocateInfo command_buffer_allocate_info(command_pool, vk::CommandBufferLevel::ePrimary, swapchain_images.size()); @@ -268,7 +275,7 @@ bool Swapchain::begin_frame() vk::ResultValue result_value(vk::Result::eSuccess, 0); result_value = device.acquireNextImageKHR(swapchain_object.get(), UINT64_MAX, frame.acquire.get()); - + if (result_value.result == vk::Result::eErrorOutOfDateKHR || result_value.result == vk::Result::eSuboptimalKHR) { @@ -326,7 +333,7 @@ bool Swapchain::swap() { // NVIDIA binary drivers will set OutOfDate between acquire and // present. Ignore this and fix it on the next swapchain acquire. - } + } current_frame = (current_frame + 1) % num_swapchain_images; From c02ee4373ec14afefc2b09296a12fc0aac2b6a2e Mon Sep 17 00:00:00 2001 From: BearOso Date: Tue, 11 Jun 2024 16:07:38 -0500 Subject: [PATCH 25/51] Vulkan: Refactor device acquisition for cleanness. --- vulkan/vulkan_context.cpp | 109 ++++++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 45 deletions(-) diff --git a/vulkan/vulkan_context.cpp b/vulkan/vulkan_context.cpp index f8bd76c0..d5f50084 100644 --- a/vulkan/vulkan_context.cpp +++ b/vulkan/vulkan_context.cpp @@ -183,55 +183,74 @@ bool Context::init_command_pool() return true; } -bool Context::init_device(int preferred_device) +static bool find_extension(std::vector &props, const char *extension_string) { - const char *required_extensions[] = { - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - // VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME - }; - auto check_extensions = [&](vk::PhysicalDevice &device) -> bool { - auto [retval, props] = device.enumerateDeviceExtensionProperties(); - for (const auto &extension : required_extensions) { - auto found = std::find_if( - props.begin(), props.end(), [&](vk::ExtensionProperties &ext) { - return (std::string(ext.extensionName.data()) == extension); - }); - return found != props.end(); - } - return true; - }; + return std::find_if(props.begin(), + props.end(), + [&](vk::ExtensionProperties &ext) { + return (std::string(ext.extensionName.data()) == extension_string); + }) != props.end(); +}; - auto device_list = instance->enumeratePhysicalDevices().value; - - if (preferred_device > -1 && - (size_t)preferred_device < device_list.size() && - check_extensions(device_list[preferred_device])) - { - physical_device = device_list[preferred_device]; - } - else - { - for (auto &device : device_list) - if (check_extensions(device)) - { - physical_device = device; - break; - } - } - - physical_device.getProperties(&physical_device_props); - - graphics_queue_family_index = UINT32_MAX; - auto queue_props = physical_device.getQueueFamilyProperties(); +static uint32_t find_graphics_queue(vk::PhysicalDevice &device) +{ + auto queue_props = device.getQueueFamilyProperties(); for (size_t i = 0; i < queue_props.size(); i++) { if (queue_props[i].queueFlags & vk::QueueFlagBits::eGraphics) { - graphics_queue_family_index = i; - break; + return i; } } + return UINT32_MAX; +} + +static bool check_extensions(std::vector &required_extensions, vk::PhysicalDevice &device) +{ + auto props = device.enumerateDeviceExtensionProperties().value; + for (const auto &extension : required_extensions) + { + if (!find_extension(props, extension)) + return false; + } + return true; +}; + +bool Context::init_device(int preferred_device) +{ + std::vector required_extensions; + required_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + + auto device_list = instance->enumeratePhysicalDevices().value; + physical_device = nullptr; + + if (preferred_device > -1 && + (size_t)preferred_device < device_list.size() && + check_extensions(required_extensions, device_list[preferred_device])) + { + physical_device = device_list[preferred_device]; + } + + if (physical_device != nullptr) + { + for (auto &device : device_list) + { + if (check_extensions(required_extensions, device)) + { + physical_device = device; + break; + } + } + } + + auto extension_properties = physical_device.enumerateDeviceExtensionProperties().value; + physical_device.getProperties(&physical_device_props); + + if (find_extension(extension_properties, VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME)) + required_extensions.push_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); + + graphics_queue_family_index = find_graphics_queue(physical_device); if (graphics_queue_family_index == UINT32_MAX) return false; @@ -241,11 +260,11 @@ bool Context::init_device(int preferred_device) queue = device.getQueue(graphics_queue_family_index, 0); auto surface_formats = physical_device.getSurfaceFormatsKHR(surface.get()).value; - auto format = std::find_if(surface_formats.begin(), surface_formats.end(), [](vk::SurfaceFormatKHR &f) { - return (f.format == vk::Format::eB8G8R8A8Unorm); - }); - - if (format == surface_formats.end()) + if (std::find_if(surface_formats.begin(), + surface_formats.end(), + [](vk::SurfaceFormatKHR &f) { + return (f.format == vk::Format::eB8G8R8A8Unorm); + }) == surface_formats.end()) return false; return true; From 99990af31e04629fb6798fba2723619798e94393 Mon Sep 17 00:00:00 2001 From: BearOso Date: Tue, 11 Jun 2024 18:04:09 -0500 Subject: [PATCH 26/51] Vulkan: Don't use mailbox for vsync case. --- vulkan/vulkan_swapchain.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/vulkan/vulkan_swapchain.cpp b/vulkan/vulkan_swapchain.cpp index 7c03693f..f5e288e8 100644 --- a/vulkan/vulkan_swapchain.cpp +++ b/vulkan/vulkan_swapchain.cpp @@ -172,10 +172,13 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width, vk::PresentModeKHR::eImmediate) != present_modes.end(); vk::PresentModeKHR present_mode = vk::PresentModeKHR::eFifo; - if (mailbox_supported) - present_mode = vk::PresentModeKHR::eMailbox; - if (!vsync && immediate_supported) - present_mode = vk::PresentModeKHR::eImmediate; + if (!vsync) + { + if (mailbox_supported) + present_mode = vk::PresentModeKHR::eMailbox; + if (immediate_supported) + present_mode = vk::PresentModeKHR::eImmediate; + } if (present_mode == vk::PresentModeKHR::eMailbox) num_swapchain_images++; From 5949bbab9743e615d2580db5bc6ff6d202bd3bc1 Mon Sep 17 00:00:00 2001 From: BearOso Date: Wed, 12 Jun 2024 16:51:12 -0500 Subject: [PATCH 27/51] Vulkan: Utilize VK_EXT_swapchain_maintenance1. This is core in Vulkan 1.1. We can now change vsync state without a new swapchain. A fence is signaled when image is on screen, so we can possibly be a little more precise with timing and avoid a whole device wait. --- gtk/src/gtk_display_driver_vulkan.cpp | 1 + qt/src/EmuCanvasVulkan.cpp | 6 +-- vulkan/vulkan_context.cpp | 14 ++--- vulkan/vulkan_swapchain.cpp | 73 +++++++++++++++++++-------- vulkan/vulkan_swapchain.hpp | 5 ++ 5 files changed, 66 insertions(+), 33 deletions(-) diff --git a/gtk/src/gtk_display_driver_vulkan.cpp b/gtk/src/gtk_display_driver_vulkan.cpp index c1b44f53..66e5b164 100644 --- a/gtk/src/gtk_display_driver_vulkan.cpp +++ b/gtk/src/gtk_display_driver_vulkan.cpp @@ -222,6 +222,7 @@ void S9xVulkanDisplayDriver::update(uint16_t *buffer, int width, int height, int throttle.wait_for_frame_and_rebase_time(); } + context->swapchain->set_vsync(gui_config->sync_to_vblank); context->swapchain->swap(); if (gui_config->reduce_input_lag) diff --git a/qt/src/EmuCanvasVulkan.cpp b/qt/src/EmuCanvasVulkan.cpp index 4da80e0f..12557221 100644 --- a/qt/src/EmuCanvasVulkan.cpp +++ b/qt/src/EmuCanvasVulkan.cpp @@ -178,9 +178,6 @@ void EmuCanvasVulkan::draw() if (!window->isVisible()) return; - if (context->swapchain->set_vsync(config->enable_vsync)) - context->recreate_swapchain(); - if (S9xImGuiDraw(width() * devicePixelRatioF(), height() * devicePixelRatioF())) { auto draw_data = ImGui::GetDrawData(); @@ -205,10 +202,11 @@ void EmuCanvasVulkan::draw() if (retval) { throttle(); + context->swapchain->set_vsync(config->enable_vsync); context->swapchain->swap(); if (config->reduce_input_lag) { - context->wait_idle(); + context->swapchain->wait_on_frames(); } } } diff --git a/vulkan/vulkan_context.cpp b/vulkan/vulkan_context.cpp index d5f50084..90a337ea 100644 --- a/vulkan/vulkan_context.cpp +++ b/vulkan/vulkan_context.cpp @@ -219,8 +219,9 @@ static bool check_extensions(std::vector &required_extensions, vk: bool Context::init_device(int preferred_device) { - std::vector required_extensions; - required_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + std::vector required_extensions = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + }; auto device_list = instance->enumeratePhysicalDevices().value; physical_device = nullptr; @@ -247,15 +248,14 @@ bool Context::init_device(int preferred_device) auto extension_properties = physical_device.enumerateDeviceExtensionProperties().value; physical_device.getProperties(&physical_device_props); - if (find_extension(extension_properties, VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME)) - required_extensions.push_back(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); - graphics_queue_family_index = find_graphics_queue(physical_device); if (graphics_queue_family_index == UINT32_MAX) return false; - vk::DeviceQueueCreateInfo dqci({}, graphics_queue_family_index, 1); - vk::DeviceCreateInfo dci({}, dqci, {}, required_extensions, {}); + std::vector priorities = { 1.0f }; + vk::DeviceQueueCreateInfo dqci({}, graphics_queue_family_index, priorities); + vk::DeviceCreateInfo dci({}, dqci, {}, required_extensions); + device = physical_device.createDevice(dci).value; queue = device.getQueue(graphics_queue_family_index, 0); diff --git a/vulkan/vulkan_swapchain.cpp b/vulkan/vulkan_swapchain.cpp index f5e288e8..bfee445a 100644 --- a/vulkan/vulkan_swapchain.cpp +++ b/vulkan/vulkan_swapchain.cpp @@ -1,5 +1,4 @@ #include "vulkan_swapchain.hpp" -#include namespace Vulkan { @@ -80,7 +79,9 @@ void Swapchain::create_render_pass() bool Swapchain::recreate(int new_width, int new_height) { - device.waitIdle(); + if (swapchain_object) + wait_on_frames(); + return create(num_swapchain_images, new_width, new_height); } @@ -164,24 +165,24 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width, extents.height = surface_capabilities.minImageExtent.height; auto present_modes = physical_device.getSurfacePresentModesKHR(surface).value; - bool mailbox_supported = + supports_mailbox = std::find(present_modes.begin(), present_modes.end(), vk::PresentModeKHR::eMailbox) != present_modes.end(); - bool immediate_supported = + supports_immediate = std::find(present_modes.begin(), present_modes.end(), vk::PresentModeKHR::eImmediate) != present_modes.end(); - vk::PresentModeKHR present_mode = vk::PresentModeKHR::eFifo; + auto present_mode = vk::PresentModeKHR::eFifo; if (!vsync) { - if (mailbox_supported) + if (supports_mailbox) present_mode = vk::PresentModeKHR::eMailbox; - if (immediate_supported) + if (supports_immediate) present_mode = vk::PresentModeKHR::eImmediate; } - if (present_mode == vk::PresentModeKHR::eMailbox) - num_swapchain_images++; + auto swapchain_maintenance_info = vk::SwapchainPresentModesCreateInfoEXT{} + .setPresentModes(present_modes); auto swapchain_create_info = vk::SwapchainCreateInfoKHR{} .setMinImageCount(num_swapchain_images) @@ -196,7 +197,8 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width, .setSurface(surface) .setPreTransform(vk::SurfaceTransformFlagBitsKHR::eIdentity) .setImageArrayLayers(1) - .setQueueFamilyIndices(graphics_queue_index); + .setQueueFamilyIndices(graphics_queue_index) + .setPNext(&swapchain_maintenance_info); swapchain_object.reset(); auto resval = device.createSwapchainKHRUnique(swapchain_create_info); @@ -207,12 +209,19 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width, } swapchain_object = std::move(resval.value); - auto swapchain_images = device.getSwapchainImagesKHR(swapchain_object.get()).value; - vk::CommandBufferAllocateInfo command_buffer_allocate_info(command_pool, vk::CommandBufferLevel::ePrimary, swapchain_images.size()); - auto command_buffers = device.allocateCommandBuffersUnique(command_buffer_allocate_info).value; + create_resources(); - if (imageviewfbs.size() > num_swapchain_images) - num_swapchain_images = imageviewfbs.size(); + return true; +} + +bool Swapchain::create_resources() +{ + auto swapchain_images = device.getSwapchainImagesKHR(swapchain_object.get()).value; + if (swapchain_images.size() > num_swapchain_images) + num_swapchain_images = swapchain_images.size(); + + vk::CommandBufferAllocateInfo command_buffer_allocate_info(command_pool, vk::CommandBufferLevel::ePrimary, num_swapchain_images); + auto command_buffers = device.allocateCommandBuffersUnique(command_buffer_allocate_info).value; frames.resize(num_swapchain_images); imageviewfbs.resize(num_swapchain_images); @@ -225,10 +234,10 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width, auto &frame = frames[i]; frame.command_buffer = std::move(command_buffers[i]); frame.fence = device.createFenceUnique(fence_create_info).value; + frame.freeable = device.createFenceUnique(fence_create_info).value; frame.acquire = device.createSemaphoreUnique({}).value; frame.complete = device.createSemaphoreUnique({}).value; } - current_frame = 0; for (unsigned int i = 0; i < num_swapchain_images; i++) { @@ -252,9 +261,8 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width, image.framebuffer = device.createFramebufferUnique(framebuffer_create_info).value; } - device.waitIdle(); - current_swapchain_image = 0; + current_frame = 0; return true; } @@ -269,7 +277,7 @@ bool Swapchain::begin_frame() auto &frame = frames[current_frame]; - auto result = device.waitForFences(frame.fence.get(), true, 33333333); + auto result = device.waitForFences({ frame.fence.get(), frame.freeable.get() }, true, 33333333); if (result != vk::Result::eSuccess) { printf("Timed out waiting for fence.\n"); @@ -330,8 +338,23 @@ bool Swapchain::swap() .setSwapchains(swapchain_object.get()) .setImageIndices(current_swapchain_image); - vk::Result result = vk::Result::eSuccess; - result = queue.presentKHR(present_info); + vk::SwapchainPresentModeInfoEXT present_mode_info; + vk::PresentModeKHR present_mode = vk::PresentModeKHR::eFifo; + if (!vsync) + { + if (supports_mailbox) + present_mode = vk::PresentModeKHR::eMailbox; + if (supports_immediate) + present_mode = vk::PresentModeKHR::eImmediate; + } + present_mode_info.setPresentModes(present_mode); + present_info.setPNext(&present_mode_info); + + device.resetFences(frames[current_frame].freeable.get()); + vk::SwapchainPresentFenceInfoEXT present_fence_info(frames[current_frame].freeable.get()); + present_mode_info.setPNext(&present_fence_info); + + vk::Result result = queue.presentKHR(present_info); if (result == vk::Result::eErrorOutOfDateKHR) { // NVIDIA binary drivers will set OutOfDate between acquire and @@ -389,10 +412,16 @@ void Swapchain::end_render_pass() bool Swapchain::wait_on_frame(int frame_num) { - auto result = device.waitForFences(frames[frame_num].fence.get(), true, 33000000); + auto result = device.waitForFences({ frames[frame_num].fence.get(), frames[frame_num].freeable.get() }, true, 133000000); return (result == vk::Result::eSuccess); } +void Swapchain::wait_on_frames() +{ + for (auto i = 0; i < frames.size(); i++) + wait_on_frame(i); +} + vk::Extent2D Swapchain::get_extents() { return extents; diff --git a/vulkan/vulkan_swapchain.hpp b/vulkan/vulkan_swapchain.hpp index c2ba4505..2fd65695 100644 --- a/vulkan/vulkan_swapchain.hpp +++ b/vulkan/vulkan_swapchain.hpp @@ -17,6 +17,7 @@ class Swapchain ~Swapchain(); bool create(unsigned int num_frames, int width = -1, int height = -1); bool recreate(int width = -1, int height = -1); + bool create_resources(); bool check_and_resize(int width = -1, int height = -1); bool begin_frame(); void begin_render_pass(); @@ -25,6 +26,7 @@ class Swapchain bool end_frame(); void end_frame_without_swap(); bool swap(); + void wait_on_frames(); // Returns true if vsync setting was changed, false if it was the same bool set_vsync(bool on); void on_render_pass_end(std::function function); @@ -43,6 +45,7 @@ class Swapchain struct Frame { vk::UniqueFence fence; + vk::UniqueFence freeable; vk::UniqueSemaphore acquire; vk::UniqueSemaphore complete; vk::UniqueCommandBuffer command_buffer; @@ -64,6 +67,8 @@ class Swapchain unsigned int current_swapchain_image = 0; unsigned int num_swapchain_images = 0; bool vsync = true; + bool supports_immediate = false; + bool supports_mailbox = false; std::vector frames; std::vector imageviewfbs; From 2e25b70cf0677285784c39dcfa8f1dc109d3ee36 Mon Sep 17 00:00:00 2001 From: BearOso Date: Thu, 13 Jun 2024 11:16:36 -0500 Subject: [PATCH 28/51] Vulkan: Associate new fence with swapchain image, not frame resources. --- vulkan/vulkan_swapchain.cpp | 28 ++++++++++++++++------------ vulkan/vulkan_swapchain.hpp | 6 +++--- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/vulkan/vulkan_swapchain.cpp b/vulkan/vulkan_swapchain.cpp index bfee445a..5ec08fc3 100644 --- a/vulkan/vulkan_swapchain.cpp +++ b/vulkan/vulkan_swapchain.cpp @@ -80,14 +80,16 @@ void Swapchain::create_render_pass() bool Swapchain::recreate(int new_width, int new_height) { if (swapchain_object) + { wait_on_frames(); + } return create(num_swapchain_images, new_width, new_height); } vk::Image Swapchain::get_image() { - return imageviewfbs[current_swapchain_image].image; + return image_data[current_swapchain_image].image; } bool Swapchain::check_and_resize(int width, int height) @@ -116,7 +118,7 @@ bool Swapchain::check_and_resize(int width, int height) bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width, int new_height) { frames.clear(); - imageviewfbs.clear(); + image_data.clear(); auto surface_capabilities = physical_device.getSurfaceCapabilitiesKHR(surface).value; @@ -224,7 +226,7 @@ bool Swapchain::create_resources() auto command_buffers = device.allocateCommandBuffersUnique(command_buffer_allocate_info).value; frames.resize(num_swapchain_images); - imageviewfbs.resize(num_swapchain_images); + image_data.resize(num_swapchain_images); vk::FenceCreateInfo fence_create_info(vk::FenceCreateFlagBits::eSignaled); @@ -234,7 +236,6 @@ bool Swapchain::create_resources() auto &frame = frames[i]; frame.command_buffer = std::move(command_buffers[i]); frame.fence = device.createFenceUnique(fence_create_info).value; - frame.freeable = device.createFenceUnique(fence_create_info).value; frame.acquire = device.createSemaphoreUnique({}).value; frame.complete = device.createSemaphoreUnique({}).value; } @@ -242,7 +243,7 @@ bool Swapchain::create_resources() for (unsigned int i = 0; i < num_swapchain_images; i++) { // Create resources associated with swapchain images - auto &image = imageviewfbs[i]; + auto &image = image_data[i]; image.image = swapchain_images[i]; auto image_view_create_info = vk::ImageViewCreateInfo{} .setImage(swapchain_images[i]) @@ -259,6 +260,8 @@ bool Swapchain::create_resources() .setLayers(1) .setRenderPass(render_pass.get()); image.framebuffer = device.createFramebufferUnique(framebuffer_create_info).value; + + image.fence = device.createFenceUnique(fence_create_info).value; } current_swapchain_image = 0; @@ -277,7 +280,7 @@ bool Swapchain::begin_frame() auto &frame = frames[current_frame]; - auto result = device.waitForFences({ frame.fence.get(), frame.freeable.get() }, true, 33333333); + auto result = device.waitForFences({ frame.fence.get() }, true, 33333333); if (result != vk::Result::eSuccess) { printf("Timed out waiting for fence.\n"); @@ -350,8 +353,9 @@ bool Swapchain::swap() present_mode_info.setPresentModes(present_mode); present_info.setPNext(&present_mode_info); - device.resetFences(frames[current_frame].freeable.get()); - vk::SwapchainPresentFenceInfoEXT present_fence_info(frames[current_frame].freeable.get()); + auto &present_fence = image_data[current_swapchain_image].fence.get(); + device.resetFences(present_fence); + vk::SwapchainPresentFenceInfoEXT present_fence_info(present_fence); present_mode_info.setPNext(&present_fence_info); vk::Result result = queue.presentKHR(present_info); @@ -376,7 +380,7 @@ bool Swapchain::end_frame() vk::Framebuffer Swapchain::get_framebuffer() { - return imageviewfbs[current_swapchain_image].framebuffer.get(); + return image_data[current_swapchain_image].framebuffer.get(); } vk::CommandBuffer &Swapchain::get_cmd() @@ -393,7 +397,7 @@ void Swapchain::begin_render_pass() auto render_pass_begin_info = vk::RenderPassBeginInfo{} .setRenderPass(render_pass.get()) - .setFramebuffer(imageviewfbs[current_swapchain_image].framebuffer.get()) + .setFramebuffer(image_data[current_swapchain_image].framebuffer.get()) .setRenderArea(vk::Rect2D({}, extents)) .setClearValues(value); get_cmd().beginRenderPass(render_pass_begin_info, vk::SubpassContents::eInline); @@ -412,13 +416,13 @@ void Swapchain::end_render_pass() bool Swapchain::wait_on_frame(int frame_num) { - auto result = device.waitForFences({ frames[frame_num].fence.get(), frames[frame_num].freeable.get() }, true, 133000000); + auto result = device.waitForFences({ image_data[frame_num].fence.get() }, true, 33000000); return (result == vk::Result::eSuccess); } void Swapchain::wait_on_frames() { - for (auto i = 0; i < frames.size(); i++) + for (auto i = 0; i < image_data.size(); i++) wait_on_frame(i); } diff --git a/vulkan/vulkan_swapchain.hpp b/vulkan/vulkan_swapchain.hpp index 2fd65695..8159ee73 100644 --- a/vulkan/vulkan_swapchain.hpp +++ b/vulkan/vulkan_swapchain.hpp @@ -45,15 +45,15 @@ class Swapchain struct Frame { vk::UniqueFence fence; - vk::UniqueFence freeable; vk::UniqueSemaphore acquire; vk::UniqueSemaphore complete; vk::UniqueCommandBuffer command_buffer; }; - struct ImageViewFB + struct ImageData { vk::Image image; + vk::UniqueFence fence; vk::UniqueImageView image_view; vk::UniqueFramebuffer framebuffer; }; @@ -70,7 +70,7 @@ class Swapchain bool supports_immediate = false; bool supports_mailbox = false; std::vector frames; - std::vector imageviewfbs; + std::vector image_data; vk::Device device; vk::SurfaceKHR surface; From 33e40a8f164f3589b74746d006339132814d9222 Mon Sep 17 00:00:00 2001 From: BearOso Date: Thu, 13 Jun 2024 11:37:00 -0500 Subject: [PATCH 29/51] Vulkan: Refactor present modes. Add relaxed. --- vulkan/vulkan_swapchain.cpp | 51 ++++++++++++++++++++----------------- vulkan/vulkan_swapchain.hpp | 2 ++ 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/vulkan/vulkan_swapchain.cpp b/vulkan/vulkan_swapchain.cpp index 5ec08fc3..424811f4 100644 --- a/vulkan/vulkan_swapchain.cpp +++ b/vulkan/vulkan_swapchain.cpp @@ -92,6 +92,28 @@ vk::Image Swapchain::get_image() return image_data[current_swapchain_image].image; } +template +static bool vector_find(std::vector haystack, T&& needle) +{ + for (auto &elem : haystack) + if (elem == needle) + return true; + return false; +} + +vk::PresentModeKHR Swapchain::get_present_mode() { + auto present_mode = vk::PresentModeKHR::eFifo; + if (supports_relaxed) + present_mode = vk::PresentModeKHR::eFifoRelaxed; + if (!vsync) { + if (supports_mailbox) + present_mode = vk::PresentModeKHR::eMailbox; + if (supports_immediate) + present_mode = vk::PresentModeKHR::eImmediate; + } + return present_mode; +} + bool Swapchain::check_and_resize(int width, int height) { vk::SurfaceCapabilitiesKHR surface_capabilities; @@ -167,21 +189,9 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width, extents.height = surface_capabilities.minImageExtent.height; auto present_modes = physical_device.getSurfacePresentModesKHR(surface).value; - supports_mailbox = - std::find(present_modes.begin(), present_modes.end(), - vk::PresentModeKHR::eMailbox) != present_modes.end(); - supports_immediate = - std::find(present_modes.begin(), present_modes.end(), - vk::PresentModeKHR::eImmediate) != present_modes.end(); - - auto present_mode = vk::PresentModeKHR::eFifo; - if (!vsync) - { - if (supports_mailbox) - present_mode = vk::PresentModeKHR::eMailbox; - if (supports_immediate) - present_mode = vk::PresentModeKHR::eImmediate; - } + supports_mailbox = vector_find(present_modes, vk::PresentModeKHR::eMailbox); + supports_immediate = vector_find(present_modes, vk::PresentModeKHR::eImmediate); + supports_relaxed = vector_find(present_modes, vk::PresentModeKHR::eFifoRelaxed); auto swapchain_maintenance_info = vk::SwapchainPresentModesCreateInfoEXT{} .setPresentModes(present_modes); @@ -195,7 +205,7 @@ bool Swapchain::create(unsigned int desired_num_swapchain_images, int new_width, .setImageUsage(vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc) .setCompositeAlpha(vk::CompositeAlphaFlagBitsKHR::eOpaque) .setClipped(true) - .setPresentMode(present_mode) + .setPresentMode(get_present_mode()) .setSurface(surface) .setPreTransform(vk::SurfaceTransformFlagBitsKHR::eIdentity) .setImageArrayLayers(1) @@ -342,14 +352,7 @@ bool Swapchain::swap() .setImageIndices(current_swapchain_image); vk::SwapchainPresentModeInfoEXT present_mode_info; - vk::PresentModeKHR present_mode = vk::PresentModeKHR::eFifo; - if (!vsync) - { - if (supports_mailbox) - present_mode = vk::PresentModeKHR::eMailbox; - if (supports_immediate) - present_mode = vk::PresentModeKHR::eImmediate; - } + auto present_mode = get_present_mode(); present_mode_info.setPresentModes(present_mode); present_info.setPNext(&present_mode_info); diff --git a/vulkan/vulkan_swapchain.hpp b/vulkan/vulkan_swapchain.hpp index 8159ee73..974b4f9f 100644 --- a/vulkan/vulkan_swapchain.hpp +++ b/vulkan/vulkan_swapchain.hpp @@ -31,6 +31,7 @@ class Swapchain bool set_vsync(bool on); void on_render_pass_end(std::function function); int get_num_frames() { return num_swapchain_images; } + vk::PresentModeKHR get_present_mode(); vk::Image get_image(); vk::Framebuffer get_framebuffer(); @@ -69,6 +70,7 @@ class Swapchain bool vsync = true; bool supports_immediate = false; bool supports_mailbox = false; + bool supports_relaxed = false; std::vector frames; std::vector image_data; From 5c78493f4efceb2db4748ea0a29c3af6f8e27246 Mon Sep 17 00:00:00 2001 From: BearOso Date: Thu, 13 Jun 2024 14:39:36 -0500 Subject: [PATCH 30/51] Vulkan: Add device wait back to swapchain recreation. --- vulkan/vulkan_swapchain.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/vulkan/vulkan_swapchain.cpp b/vulkan/vulkan_swapchain.cpp index 424811f4..39301a65 100644 --- a/vulkan/vulkan_swapchain.cpp +++ b/vulkan/vulkan_swapchain.cpp @@ -81,6 +81,7 @@ bool Swapchain::recreate(int new_width, int new_height) { if (swapchain_object) { + device.waitIdle(); wait_on_frames(); } From 3980a9d6d4af54627ef2f024eb2436aa65a6113b Mon Sep 17 00:00:00 2001 From: BearOso Date: Thu, 13 Jun 2024 15:56:04 -0500 Subject: [PATCH 31/51] Vulkan: Fix inverted logic. --- vulkan/vulkan_context.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vulkan/vulkan_context.cpp b/vulkan/vulkan_context.cpp index 90a337ea..3fee38a2 100644 --- a/vulkan/vulkan_context.cpp +++ b/vulkan/vulkan_context.cpp @@ -233,7 +233,7 @@ bool Context::init_device(int preferred_device) physical_device = device_list[preferred_device]; } - if (physical_device != nullptr) + if (physical_device == nullptr) { for (auto &device : device_list) { From 008cbcd1a1670d70251ec22f00bfadd56170384e Mon Sep 17 00:00:00 2001 From: BearOso Date: Thu, 13 Jun 2024 16:16:20 -0500 Subject: [PATCH 32/51] Vulkan: Simplify set_vsync. Remove relaxed fifo. It looks like relaxed fifo tears when refresh rate doesn't match because it always misses a refresh interval. --- vulkan/vulkan_swapchain.cpp | 10 +++------- vulkan/vulkan_swapchain.hpp | 3 +-- win32/CVulkan.cpp | 14 +++----------- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/vulkan/vulkan_swapchain.cpp b/vulkan/vulkan_swapchain.cpp index 39301a65..b4d2734c 100644 --- a/vulkan/vulkan_swapchain.cpp +++ b/vulkan/vulkan_swapchain.cpp @@ -18,13 +18,9 @@ Swapchain::~Swapchain() { } -bool Swapchain::set_vsync(bool new_setting) +void Swapchain::set_vsync(bool new_setting) { - if (new_setting == vsync) - return false; - vsync = new_setting; - return true; } void Swapchain::on_render_pass_end(std::function function) @@ -104,14 +100,14 @@ static bool vector_find(std::vector haystack, T&& needle) vk::PresentModeKHR Swapchain::get_present_mode() { auto present_mode = vk::PresentModeKHR::eFifo; - if (supports_relaxed) - present_mode = vk::PresentModeKHR::eFifoRelaxed; + if (!vsync) { if (supports_mailbox) present_mode = vk::PresentModeKHR::eMailbox; if (supports_immediate) present_mode = vk::PresentModeKHR::eImmediate; } + return present_mode; } diff --git a/vulkan/vulkan_swapchain.hpp b/vulkan/vulkan_swapchain.hpp index 974b4f9f..ad271e83 100644 --- a/vulkan/vulkan_swapchain.hpp +++ b/vulkan/vulkan_swapchain.hpp @@ -27,8 +27,7 @@ class Swapchain void end_frame_without_swap(); bool swap(); void wait_on_frames(); - // Returns true if vsync setting was changed, false if it was the same - bool set_vsync(bool on); + void set_vsync(bool on); void on_render_pass_end(std::function function); int get_num_frames() { return num_swapchain_images; } vk::PresentModeKHR get_present_mode(); diff --git a/win32/CVulkan.cpp b/win32/CVulkan.cpp index bbde45b8..08b408b1 100644 --- a/win32/CVulkan.cpp +++ b/win32/CVulkan.cpp @@ -70,6 +70,8 @@ bool CVulkan::Initialize(HWND hWnd) return false; } + context->swapchain->set_vsync(GUI.Vsync); + if (!Settings.AutoDisplayMessages) { Settings.DisplayIndicators = true; @@ -91,11 +93,6 @@ bool CVulkan::Initialize(HWND hWnd) } } - if (context->swapchain->set_vsync(GUI.Vsync)) - { - context->recreate_swapchain(); - } - simple_output = std::make_unique(context.get(), vk::Format::eR5G6B5UnormPack16); return true; @@ -181,8 +178,6 @@ bool CVulkan::ChangeRenderSize(unsigned int newWidth, unsigned int newHeight) if (!context) return false; - bool vsync_changed = context->swapchain->set_vsync(GUI.Vsync); - if (newWidth != current_width || newHeight != current_height || vsync_changed) { context->recreate_swapchain(newWidth, newHeight); @@ -218,10 +213,7 @@ bool CVulkan::ApplyDisplayChanges(void) current_shadername = shadername; } - if (context->swapchain->set_vsync(GUI.Vsync)) - { - context->recreate_swapchain(); - } + context->swapchain->set_vsync(GUI.Vsync); return true; } From a9e64edf73f36fb1a4ac616b11131f6380d8e968 Mon Sep 17 00:00:00 2001 From: BearOso Date: Thu, 13 Jun 2024 16:50:12 -0500 Subject: [PATCH 33/51] Vulkan/Win32: Fix compile error. --- win32/CVulkan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win32/CVulkan.cpp b/win32/CVulkan.cpp index 08b408b1..9f3a226f 100644 --- a/win32/CVulkan.cpp +++ b/win32/CVulkan.cpp @@ -178,7 +178,7 @@ bool CVulkan::ChangeRenderSize(unsigned int newWidth, unsigned int newHeight) if (!context) return false; - if (newWidth != current_width || newHeight != current_height || vsync_changed) + if (newWidth != current_width || newHeight != current_height) { context->recreate_swapchain(newWidth, newHeight); context->wait_idle(); From ed3695f7049f3506c7521fcbcb8cdb99e089f41a Mon Sep 17 00:00:00 2001 From: BearOso Date: Tue, 18 Jun 2024 15:35:05 -0500 Subject: [PATCH 34/51] Gtk: Fix config directory order. Search for XDG_CONFIG_HOME. If that exists, use $XDG_CONFIG_HOME/snes9x, otherwise use $HOME/.config/snes9x. Remove broken legacy check. --- gtk/src/gtk_config.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/gtk/src/gtk_config.cpp b/gtk/src/gtk_config.cpp index 1f03795d..21b9a367 100644 --- a/gtk/src/gtk_config.cpp +++ b/gtk/src/gtk_config.cpp @@ -33,22 +33,18 @@ std::string get_config_dir() return std::string{".snes9x"}; } - fs::path config = env_home; - fs::path legacy = config; - + fs::path config; // If XDG_CONFIG_HOME is set, use that, otherwise guess default - if (!env_xdg_config_home) - { - config /= ".config/snes9x"; - legacy /= ".snes9x"; - } - else + if (env_xdg_config_home) { config = env_xdg_config_home; config /= "snes9x"; } - if (fs::exists(legacy) && !fs::exists(config)) - return legacy; + else + { + config = env_home; + config /= ".config/snes9x"; + } return config; } From d514d135a7d3521e16e9ea599690e36e95c5c1aa Mon Sep 17 00:00:00 2001 From: BearOso Date: Tue, 18 Jun 2024 15:38:21 -0500 Subject: [PATCH 35/51] Gtk: Create config directory in get_config_dir if it doesn't exist. --- gtk/src/gtk_config.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gtk/src/gtk_config.cpp b/gtk/src/gtk_config.cpp index 21b9a367..cd3bfd40 100644 --- a/gtk/src/gtk_config.cpp +++ b/gtk/src/gtk_config.cpp @@ -46,6 +46,9 @@ std::string get_config_dir() config /= ".config/snes9x"; } + if (!fs::exists(config)) + fs::create_directories(config); + return config; } From dcd279afe0f91385105f523941cb8ee3e2c600ba Mon Sep 17 00:00:00 2001 From: BearOso Date: Sat, 6 Jul 2024 10:59:00 -0500 Subject: [PATCH 36/51] Update changes.txt. --- docs/changes.txt | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/changes.txt b/docs/changes.txt index cc78e98b..0031cb92 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -1,3 +1,28 @@ +Snes9x 1.63 +General: +- Added a shortcut to change the backdrop color for sprite extraction. +- Fixed QuickSave 0-9 slot shortcuts not working. +- Allow "Address:byte" form for cheat inputs. +- Fixed ZIP files not being closed after patch search. +- Various memmap fixes to allow unofficial mappings. +- Added usage of ImGui to draw things on top of the screen instead of inside. + +Win32: +- Fixed AVI not recording audio. +- Fixed framerate throttling in turbo mode. +- Fixed interlaced output speed being double. + +Gtk: +- Fixed config file location to never put files directly in $HOME and obey + $XDG_CONFIG_HOME. +- Updated translations from JakeSmarter and StanleyKid-22. + +Mac: +- Added a new cheat finder. +- Added MultiCart support back. +- Create a blank window when starting the program, so the global menu change + doesn't go unnoticed. + Snes9x 1.62 - Fixed SA1 division with negative dividend again. (Atari2) - Fixed timing on several instructions. (pi1541) From 921f9f7b83660eb44ad263022a57a4a029057c37 Mon Sep 17 00:00:00 2001 From: OV2 Date: Sun, 7 Jul 2024 13:48:47 +0200 Subject: [PATCH 37/51] Update changes.txt --- docs/changes.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/changes.txt b/docs/changes.txt index 0031cb92..c78f8e2f 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -9,8 +9,13 @@ General: Win32: - Fixed AVI not recording audio. -- Fixed framerate throttling in turbo mode. +- Fixed framerate throttling in turbo mode (now works during AVI recording). - Fixed interlaced output speed being double. +- Fixed command line arguments not working. +- Fixed WaveOut device name display for names longer than 31 characters. +- Fixed Bank+/- hotkey saving. +- Added hotkeys for aspect ratio, cheat edit/search. +- Added multiselect for cheat edit dialog. Gtk: - Fixed config file location to never put files directly in $HOME and obey From 18096d9f682cf1cb22c90fac349838a226a8cb1d Mon Sep 17 00:00:00 2001 From: OV2 Date: Sun, 14 Jul 2024 02:20:47 +0200 Subject: [PATCH 38/51] imgui: add movie frame count and watches display (#167) --- external/imgui/snes9x_imgui.cpp | 59 ++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/external/imgui/snes9x_imgui.cpp b/external/imgui/snes9x_imgui.cpp index 706614f1..6133ed19 100644 --- a/external/imgui/snes9x_imgui.cpp +++ b/external/imgui/snes9x_imgui.cpp @@ -12,6 +12,7 @@ #include "movie.h" #include "gfx.h" #include "ppu.h" +#include "cheats.h" namespace { @@ -115,6 +116,42 @@ static void ImGui_DrawPressedKeys(int spacing) } } +static void ImGui_GetWatchesText(std::string& osd_text) +{ + for (unsigned int i = 0; i < sizeof(watches) / sizeof(watches[0]); i++) + { + if (!watches[i].on) + break; + + int32 displayNumber = 0; + char buf[64]; + + for (int r = 0; r < watches[i].size; r++) + displayNumber += (Cheat.CWatchRAM[(watches[i].address - 0x7E0000) + r]) << (8 * r); + + if (watches[i].format == 1) + sprintf(buf, "%s,%du = %u", watches[i].desc, watches[i].size, (unsigned int)displayNumber); + else + if (watches[i].format == 3) + sprintf(buf, "%s,%dx = %X", watches[i].desc, watches[i].size, (unsigned int)displayNumber); + else // signed + { + if (watches[i].size == 1) + displayNumber = (int32)((int8)displayNumber); + else if (watches[i].size == 2) + displayNumber = (int32)((int16)displayNumber); + else if (watches[i].size == 3) + if (displayNumber >= 8388608) + displayNumber -= 16777216; + + sprintf(buf, "%s,%ds = %d", watches[i].desc, watches[i].size, (int)displayNumber); + } + + osd_text += buf; + osd_text += '\n'; + } +} + static void ImGui_DrawTextOverlay(const char *text, int x, int y, int padding, @@ -246,9 +283,29 @@ bool S9xImGuiDraw(int width, int height) } } + std::string utf8_message; + if (Settings.DisplayWatchedAddresses) + { + ImGui_GetWatchesText(utf8_message); + } + if (!GFX.InfoString.empty()) { - auto utf8_message = sjis_to_utf8(GFX.InfoString); + utf8_message += sjis_to_utf8(GFX.InfoString); + } + + if (Settings.DisplayMovieFrame && S9xMovieActive()) + { + // move movie frame count into its own line if info message is active and not already a newline at end + if (!utf8_message.empty() && utf8_message.back() != '\n') + { + utf8_message += '\n'; + } + utf8_message += GFX.FrameDisplayString; + } + + if (!utf8_message.empty()) + { ImGui_DrawTextOverlay(utf8_message.c_str(), settings.spacing, height - settings.spacing, From 43b6efb12b93d64b5cd623acc24a4dc2e18a71ef Mon Sep 17 00:00:00 2001 From: Michael Buckley Date: Sun, 14 Jul 2024 11:38:55 -0700 Subject: [PATCH 39/51] MacOS: Fix building in Xcode 15. --- macosx/Snes9x/AppDelegate.m | 3 --- 1 file changed, 3 deletions(-) diff --git a/macosx/Snes9x/AppDelegate.m b/macosx/Snes9x/AppDelegate.m index 38ce22ae..088293cb 100644 --- a/macosx/Snes9x/AppDelegate.m +++ b/macosx/Snes9x/AppDelegate.m @@ -45,7 +45,6 @@ NSWindowFrameAutosaveName const kCheatFinderWindowIdentifier = @"s9xCheatFinderW gameWindow.contentView.layer.backgroundColor = NSColor.blackColor.CGColor; gameWindow.title = @"Snes9x"; - gameWindow.restorationClass = [self class]; gameWindow.frameAutosaveName = kMainWindowIdentifier; gameWindow.releasedWhenClosed = NO; gameWindow.backgroundColor = NSColor.clearColor; @@ -660,7 +659,6 @@ NSWindowFrameAutosaveName const kCheatFinderWindowIdentifier = @"s9xCheatFinderW window = self.cheatsWindowController.window; window.title = NSLocalizedString(@"Cheats", nil); - window.restorationClass = self.class; window.frameAutosaveName = kCheatsWindowIdentifier; window.releasedWhenClosed = NO; @@ -695,7 +693,6 @@ NSWindowFrameAutosaveName const kCheatFinderWindowIdentifier = @"s9xCheatFinderW window = self.cheatFinderWindowController.window; window.title = NSLocalizedString(@"Cheat Finder", nil); - window.restorationClass = self.class; window.frameAutosaveName = kCheatFinderWindowIdentifier; window.releasedWhenClosed = NO; From 7c9c2209316a558e5d5a3b2f17a42190016a9fe5 Mon Sep 17 00:00:00 2001 From: Michael Buckley Date: Sun, 14 Jul 2024 12:27:08 -0700 Subject: [PATCH 40/51] macOS: Fix keyboard settings warning --- macosx/mac-joypad.h | 2 +- macosx/mac-joypad.mm | 47 ++++++++++++++++++++++++++++++++++++++++++-- macosx/mac-os.mm | 2 +- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/macosx/mac-joypad.h b/macosx/mac-joypad.h index 1f77a39c..366f8cf3 100755 --- a/macosx/mac-joypad.h +++ b/macosx/mac-joypad.h @@ -131,7 +131,7 @@ bool SetButtonCodeForJoypadControl(uint32 vendorID, uint32 productID, uint32 ind void ClearButtonCodeForJoypad(uint32 vendorID, uint32 productID, uint32 index, S9xButtonCode buttonCode); void ClearJoypad(uint32 vendorID, uint32 productID, uint32 index); -std::unordered_map GetJuypadButtons(uint32 vendorID, uint32 productID, uint32 index); +std::unordered_map GetJoypadButtons(uint32 vendorID, uint32 productID, uint32 index); std::string LabelForInput(uint32 vendorID, uint32 productID, uint32 cookie, int32 value); diff --git a/macosx/mac-joypad.mm b/macosx/mac-joypad.mm index 253238c8..db4ea912 100755 --- a/macosx/mac-joypad.mm +++ b/macosx/mac-joypad.mm @@ -684,7 +684,7 @@ void ClearJoypad(uint32 vendorID, uint32 productID, uint32 index) } } -std::unordered_map GetJuypadButtons(uint32 vendorID, uint32 productID, uint32 index) +std::unordered_map GetJoypadButtons(uint32 vendorID, uint32 productID, uint32 index) { struct JoypadDevice device; device.vendorID = vendorID; @@ -712,7 +712,50 @@ void SetUpHID (void) { IOHIDManagerRegisterInputValueCallback(hidManager, gamepadAction, NULL); IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode); - IOHIDManagerSetDeviceMatching(hidManager, NULL); + + CFMutableArrayRef matching = CFArrayCreateMutable(kCFAllocatorDefault, 4, &kCFTypeArrayCallBacks); + + uint32 page = kHIDPage_GenericDesktop; + uint32 usage = kHIDUsage_GD_Joystick; + CFNumberRef pageRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page); + CFNumberRef usageRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); + + CFMutableDictionaryRef entry = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(entry, CFSTR(kIOHIDDeviceUsagePageKey), (void *)pageRef); + CFDictionarySetValue(entry, CFSTR(kIOHIDDeviceUsageKey), (void *)usageRef); + CFArrayAppendValue(matching, entry); + CFRelease(usageRef); + CFRelease(entry); + + usage = kHIDUsage_GD_GamePad; + usageRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); + entry = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(entry, CFSTR(kIOHIDDeviceUsagePageKey), (void *)pageRef); + CFDictionarySetValue(entry, CFSTR(kIOHIDDeviceUsageKey), (void *)usageRef); + CFArrayAppendValue(matching, entry); + CFRelease(usageRef); + CFRelease(entry); + + usage = kHIDUsage_GD_MultiAxisController; + usageRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); + entry = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(entry, CFSTR(kIOHIDDeviceUsagePageKey), (void *)pageRef); + CFDictionarySetValue(entry, CFSTR(kIOHIDDeviceUsageKey), (void *)usageRef); + CFArrayAppendValue(matching, entry); + CFRelease(usageRef); + CFRelease(pageRef); + CFRelease(entry); + + uint32 vendor = 0x28DE; // Valve, apparently + CFNumberRef vendorRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vendor); + entry = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(entry, CFSTR(kIOHIDVendorIDKey), (void *)pageRef); + CFArrayAppendValue(matching, entry); + CFRelease(vendorRef); + CFRelease(entry); + + IOHIDManagerSetDeviceMatchingMultiple(hidManager, matching); + CFRelease(matching); ParseDefaults(); diff --git a/macosx/mac-os.mm b/macosx/mac-os.mm index 8b5a7814..7bd51581 100644 --- a/macosx/mac-os.mm +++ b/macosx/mac-os.mm @@ -3286,7 +3286,7 @@ void QuitWithFatalError ( NSString *message) { pthread_mutex_lock(&keyLock); NSMutableArray *inputs = [NSMutableArray new]; - std::unordered_map buttonCodeMap = GetJuypadButtons(vendorID, productID, index); + std::unordered_map buttonCodeMap = GetJoypadButtons(vendorID, productID, index); for (auto it = buttonCodeMap.begin(); it != buttonCodeMap.end(); ++it) { S9xJoypadInput *input = [S9xJoypadInput new]; From 881eeaed9a0d7b6ce9b16b094f25101785f0e39e Mon Sep 17 00:00:00 2001 From: BearOso Date: Sun, 14 Jul 2024 14:30:36 -0500 Subject: [PATCH 41/51] Update some version strings. --- win32/docs/readme-windows.txt | 2 +- win32/rsrc/snes9x.rc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/win32/docs/readme-windows.txt b/win32/docs/readme-windows.txt index f05c3805..af6baba2 100644 --- a/win32/docs/readme-windows.txt +++ b/win32/docs/readme-windows.txt @@ -7,7 +7,7 @@ Files included in the Snes9x archive: changes.txt snes9x-license.txt -version 1.62.3 March, 2023 +This document was last updated for version 1.63 in July 2024 Home page: http://www.snes9x.com/ Source code: https://github.com/snes9xgit/snes9x/ diff --git a/win32/rsrc/snes9x.rc b/win32/rsrc/snes9x.rc index d4c92627..6e031044 100644 --- a/win32/rsrc/snes9x.rc +++ b/win32/rsrc/snes9x.rc @@ -885,7 +885,7 @@ BEGIN VALUE "FileDescription", "Snes9x" VALUE "FileVersion", "1.63" VALUE "InternalName", "Snes9x" - VALUE "LegalCopyright", "Copyright 1996-2023" + VALUE "LegalCopyright", "Copyright 1996-2024" VALUE "OriginalFilename", "Snes9x.exe" VALUE "ProductName", "Snes9x SNES Emulator" VALUE "ProductVersion", "1.63" From 8a9b8cfcfddf9790d3869111a10c30dbfbfc0464 Mon Sep 17 00:00:00 2001 From: BearOso Date: Fri, 26 Jul 2024 15:12:58 -0500 Subject: [PATCH 42/51] SA1: Change mapping type for banks 40->4f on SA1. --- memmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/memmap.cpp b/memmap.cpp index 407f436c..1c483c6f 100644 --- a/memmap.cpp +++ b/memmap.cpp @@ -3011,7 +3011,7 @@ void CMemory::Map_SA1LoROMMap (void) // SA-1 Banks 40->4f for (int c = 0x400; c < 0x500; c++) - SA1.Map[c] = SA1.WriteMap[c] = (uint8*)MAP_HIROM_SRAM; + SA1.Map[c] = SA1.WriteMap[c] = (uint8*) MAP_SA1RAM; // SA-1 Banks 60->6f for (int c = 0x600; c < 0x700; c++) From bff02194a797b44f7d0082c4594a2c8c0381bb1b Mon Sep 17 00:00:00 2001 From: Lucas Gabriel Vuotto Date: Sun, 28 Jul 2024 20:52:20 +0000 Subject: [PATCH 43/51] Gtk: Fix build on 32-bits systems. --- gtk/src/gtk_display_driver_vulkan.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gtk/src/gtk_display_driver_vulkan.cpp b/gtk/src/gtk_display_driver_vulkan.cpp index 66e5b164..ce860e4d 100644 --- a/gtk/src/gtk_display_driver_vulkan.cpp +++ b/gtk/src/gtk_display_driver_vulkan.cpp @@ -66,12 +66,12 @@ bool S9xVulkanDisplayDriver::init_imgui() 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.DescriptorPool = static_cast(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()); + ImGui_ImplVulkan_Init(&init_info, static_cast(context->swapchain->get_render_pass())); auto cmd = context->begin_cmd_buffer(); ImGui_ImplVulkan_CreateFontsTexture(cmd); From cc49a06c77908be298059470415d731f140178db Mon Sep 17 00:00:00 2001 From: BearOso Date: Fri, 26 Jul 2024 17:06:17 -0500 Subject: [PATCH 44/51] external: Update stb_image.h to reduce warnings --- external/stb/stb_image.h | 487 +++++++++++++++++++++++---------------- 1 file changed, 289 insertions(+), 198 deletions(-) diff --git a/external/stb/stb_image.h b/external/stb/stb_image.h index d60371b9..9eedabed 100644 --- a/external/stb/stb_image.h +++ b/external/stb/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb +/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb no warranty implied; use at your own risk Do this: @@ -48,6 +48,9 @@ LICENSE RECENT REVISION HISTORY: + 2.30 (2024-05-31) avoid erroneous gcc warning + 2.29 (2023-05-xx) optimizations + 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes 2.26 (2020-07-13) many minor fixes 2.25 (2020-02-02) fix warnings @@ -108,7 +111,7 @@ RECENT REVISION HISTORY: Cass Everitt Ryamond Barbiero github:grim210 Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus - Josh Tobin Matthew Gregan github:poppolopoppo + Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo Julian Raschke Gregory Mullen Christian Floisand github:darealshinji Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 Brad Weinberger Matvey Cherevko github:mosra @@ -140,7 +143,7 @@ RECENT REVISION HISTORY: // // ... x = width, y = height, n = # 8-bit components per pixel ... // // ... replace '0' with '1'..'4' to force that many components per pixel // // ... but 'n' will always be the number that it would have been if you said 0 -// stbi_image_free(data) +// stbi_image_free(data); // // Standard parameters: // int *x -- outputs image width in pixels @@ -635,7 +638,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #endif #endif -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__SYMBIAN32__) typedef unsigned short stbi__uint16; typedef signed short stbi__int16; typedef unsigned int stbi__uint32; @@ -1063,6 +1066,23 @@ static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) } #endif +// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow. +static int stbi__addints_valid(int a, int b) +{ + if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow + if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0. + return a <= INT_MAX - b; +} + +// returns 1 if the product of two ints fits in a signed short, 0 on overflow. +static int stbi__mul2shorts_valid(int a, int b) +{ + if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow + if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid + if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN + return a >= SHRT_MIN / b; +} + // stbi__err - error // stbi__errpf - error returning pointer to float // stbi__errpuc - error returning pointer to unsigned char @@ -1985,9 +2005,12 @@ static int stbi__build_huffman(stbi__huffman *h, int *count) int i,j,k=0; unsigned int code; // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) + for (i=0; i < 16; ++i) { + for (j=0; j < count[i]; ++j) { h->size[k++] = (stbi_uc) (i+1); + if(k >= 257) return stbi__err("bad size list","Corrupt JPEG"); + } + } h->size[k] = 0; // compute actual symbols (from jpeg spec) @@ -2112,6 +2135,8 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) // convert the huffman code to the symbol id c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + if(c < 0 || c >= 256) // symbol id out of bounds! + return -1; STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); // convert the id to a symbol @@ -2130,6 +2155,7 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) unsigned int k; int sgn; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) k = stbi_lrot(j->code_buffer, n); @@ -2144,6 +2170,7 @@ stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) { unsigned int k; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing k = stbi_lrot(j->code_buffer, n); j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; @@ -2155,6 +2182,7 @@ stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) { unsigned int k; if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing k = j->code_buffer; j->code_buffer <<= 1; --j->code_bits; @@ -2192,8 +2220,10 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman memset(data,0,64*sizeof(data[0])); diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG"); dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); data[0] = (short) (dc * dequant[0]); // decode AC components, see JPEG spec @@ -2207,6 +2237,7 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); j->code_buffer <<= s; j->code_bits -= s; // decode into unzigzag'd location @@ -2246,8 +2277,10 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__ if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); data[0] = (short) (dc * (1 << j->succ_low)); } else { // refinement scan for DC coefficient @@ -2282,6 +2315,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); j->code_buffer <<= s; j->code_bits -= s; zig = stbi__jpeg_dezigzag[k++]; @@ -3102,6 +3136,7 @@ static int stbi__process_marker(stbi__jpeg *z, int m) sizes[i] = stbi__get8(z->s); n += sizes[i]; } + if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values! L -= 17; if (tc == 0) { if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; @@ -3351,6 +3386,28 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) return 1; } +static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) +{ + // some JPEGs have junk at end, skip over it but if we find what looks + // like a valid marker, resume there + while (!stbi__at_eof(j->s)) { + stbi_uc x = stbi__get8(j->s); + while (x == 0xff) { // might be a marker + if (stbi__at_eof(j->s)) return STBI__MARKER_none; + x = stbi__get8(j->s); + if (x != 0x00 && x != 0xff) { + // not a stuffed zero or lead-in to another marker, looks + // like an actual marker, return it + return x; + } + // stuffed zero has x=0 now which ends the loop, meaning we go + // back to regular scan loop. + // repeated 0xff keeps trying to read the next byte of the marker. + } + } + return STBI__MARKER_none; +} + // decode image to YCbCr format static int stbi__decode_jpeg_image(stbi__jpeg *j) { @@ -3367,25 +3424,22 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j) if (!stbi__process_scan_header(j)) return 0; if (!stbi__parse_entropy_coded_data(j)) return 0; if (j->marker == STBI__MARKER_none ) { - // handle 0s at the end of image data from IP Kamera 9060 - while (!stbi__at_eof(j->s)) { - int x = stbi__get8(j->s); - if (x == 255) { - j->marker = stbi__get8(j->s); - break; - } - } + j->marker = stbi__skip_jpeg_junk_at_end(j); // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 } + m = stbi__get_marker(j); + if (STBI__RESTART(m)) + m = stbi__get_marker(j); } else if (stbi__DNL(m)) { int Ld = stbi__get16be(j->s); stbi__uint32 NL = stbi__get16be(j->s); if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + m = stbi__get_marker(j); } else { - if (!stbi__process_marker(j, m)) return 0; + if (!stbi__process_marker(j, m)) return 1; + m = stbi__get_marker(j); } - m = stbi__get_marker(j); } if (j->progressive) stbi__jpeg_finish(j); @@ -3976,6 +4030,7 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re unsigned char* result; stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); if (!j) return stbi__errpuc("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); STBI_NOTUSED(ri); j->s = s; stbi__setup_jpeg(j); @@ -3989,6 +4044,7 @@ static int stbi__jpeg_test(stbi__context *s) int r; stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); j->s = s; stbi__setup_jpeg(j); r = stbi__decode_jpeg_header(j, STBI__SCAN_type); @@ -4014,6 +4070,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) int result; stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); j->s = s; result = stbi__jpeg_info_raw(j, x, y, comp); STBI_FREE(j); @@ -4121,6 +4178,7 @@ typedef struct { stbi_uc *zbuffer, *zbuffer_end; int num_bits; + int hit_zeof_once; stbi__uint32 code_buffer; char *zout; @@ -4187,9 +4245,20 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) int b,s; if (a->num_bits < 16) { if (stbi__zeof(a)) { - return -1; /* report error for unexpected end of data. */ + if (!a->hit_zeof_once) { + // This is the first time we hit eof, insert 16 extra padding btis + // to allow us to keep going; if we actually consume any of them + // though, that is invalid data. This is caught later. + a->hit_zeof_once = 1; + a->num_bits += 16; // add 16 implicit zero bits + } else { + // We already inserted our extra 16 padding bits and are again + // out, this stream is actually prematurely terminated. + return -1; + } + } else { + stbi__fill_bits(a); } - stbi__fill_bits(a); } b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; if (b) { @@ -4254,17 +4323,25 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) int len,dist; if (z == 256) { a->zout = zout; + if (a->hit_zeof_once && a->num_bits < 16) { + // The first time we hit zeof, we inserted 16 extra zero bits into our bit + // buffer so the decoder can just do its speculative decoding. But if we + // actually consumed any of those bits (which is the case when num_bits < 16), + // the stream actually read past the end so it is malformed. + return stbi__err("unexpected end","Corrupt PNG"); + } return 1; } + if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data z -= 257; len = stbi__zlength_base[z]; if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data dist = stbi__zdist_base[z]; if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); - if (zout + len > a->zout_end) { + if (len > a->zout_end - zout) { if (!stbi__zexpand(a, zout, len)) return 0; zout = a->zout; } @@ -4408,6 +4485,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) if (!stbi__parse_zlib_header(a)) return 0; a->num_bits = 0; a->code_buffer = 0; + a->hit_zeof_once = 0; do { final = stbi__zreceive(a,1); type = stbi__zreceive(a,2); @@ -4563,9 +4641,8 @@ enum { STBI__F_up=2, STBI__F_avg=3, STBI__F_paeth=4, - // synthetic filters used for first scanline to avoid needing a dummy row of 0s - STBI__F_avg_first, - STBI__F_paeth_first + // synthetic filter used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first }; static stbi_uc first_row_filter[5] = @@ -4574,29 +4651,56 @@ static stbi_uc first_row_filter[5] = STBI__F_sub, STBI__F_none, STBI__F_avg_first, - STBI__F_paeth_first + STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub }; static int stbi__paeth(int a, int b, int c) { - int p = a + b - c; - int pa = abs(p-a); - int pb = abs(p-b); - int pc = abs(p-c); - if (pa <= pb && pa <= pc) return a; - if (pb <= pc) return b; - return c; + // This formulation looks very different from the reference in the PNG spec, but is + // actually equivalent and has favorable data dependencies and admits straightforward + // generation of branch-free code, which helps performance significantly. + int thresh = c*3 - (a + b); + int lo = a < b ? a : b; + int hi = a < b ? b : a; + int t0 = (hi <= thresh) ? lo : c; + int t1 = (thresh <= lo) ? hi : t0; + return t1; } static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; +// adds an extra all-255 alpha channel +// dest == src is legal +// img_n must be 1 or 3 +static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n) +{ + int i; + // must process data backwards since we allow dest==src + if (img_n == 1) { + for (i=x-1; i >= 0; --i) { + dest[i*2+1] = 255; + dest[i*2+0] = src[i]; + } + } else { + STBI_ASSERT(img_n == 3); + for (i=x-1; i >= 0; --i) { + dest[i*4+3] = 255; + dest[i*4+2] = src[i*3+2]; + dest[i*4+1] = src[i*3+1]; + dest[i*4+0] = src[i*3+0]; + } + } +} + // create the png data from post-deflated data static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) { - int bytes = (depth == 16? 2 : 1); + int bytes = (depth == 16 ? 2 : 1); stbi__context *s = a->s; stbi__uint32 i,j,stride = x*out_n*bytes; stbi__uint32 img_len, img_width_bytes; + stbi_uc *filter_buf; + int all_ok = 1; int k; int img_n = s->img_n; // copy it into a local for later @@ -4608,8 +4712,11 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into if (!a->out) return stbi__err("outofmem", "Out of memory"); + // note: error exits here don't need to clean up a->out individually, + // stbi__do_png always does on error. if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); img_width_bytes = (((img_n * x * depth) + 7) >> 3); + if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG"); img_len = (img_width_bytes + 1) * y; // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, @@ -4617,189 +4724,137 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r // so just check for raw_len < img_len always. if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + // Allocate two scan lines worth of filter workspace buffer. + filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0); + if (!filter_buf) return stbi__err("outofmem", "Out of memory"); + + // Filtering for low-bit-depth images + if (depth < 8) { + filter_bytes = 1; + width = img_width_bytes; + } + for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *prior; + // cur/prior filter buffers alternate + stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes; + stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes; + stbi_uc *dest = a->out + stride*j; + int nk = width * filter_bytes; int filter = *raw++; - if (filter > 4) - return stbi__err("invalid filter","Corrupt PNG"); - - if (depth < 8) { - if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); - cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place - filter_bytes = 1; - width = img_width_bytes; + // check filter type + if (filter > 4) { + all_ok = stbi__err("invalid filter","Corrupt PNG"); + break; } - prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above // if first row, use special filter that doesn't sample previous row if (j == 0) filter = first_row_filter[filter]; - // handle first byte explicitly - for (k=0; k < filter_bytes; ++k) { - switch (filter) { - case STBI__F_none : cur[k] = raw[k]; break; - case STBI__F_sub : cur[k] = raw[k]; break; - case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; - case STBI__F_avg_first : cur[k] = raw[k]; break; - case STBI__F_paeth_first: cur[k] = raw[k]; break; - } + // perform actual filtering + switch (filter) { + case STBI__F_none: + memcpy(cur, raw, nk); + break; + case STBI__F_sub: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); + break; + case STBI__F_up: + for (k = 0; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); + break; + case STBI__F_avg: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); + break; + case STBI__F_paeth: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0) + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes])); + break; + case STBI__F_avg_first: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); + break; } - if (depth == 8) { - if (img_n != out_n) - cur[img_n] = 255; // first pixel - raw += img_n; - cur += out_n; - prior += out_n; - } else if (depth == 16) { - if (img_n != out_n) { - cur[filter_bytes] = 255; // first pixel top byte - cur[filter_bytes+1] = 255; // first pixel bottom byte - } - raw += filter_bytes; - cur += output_bytes; - prior += output_bytes; - } else { - raw += 1; - cur += 1; - prior += 1; - } + raw += nk; - // this is a little gross, so that we don't switch per-pixel or per-component - if (depth < 8 || img_n == out_n) { - int nk = (width - 1)*filter_bytes; - #define STBI__CASE(f) \ - case f: \ - for (k=0; k < nk; ++k) - switch (filter) { - // "none" filter turns into a memcpy here; make that explicit. - case STBI__F_none: memcpy(cur, raw, nk); break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; - } - #undef STBI__CASE - raw += nk; - } else { - STBI_ASSERT(img_n+1 == out_n); - #define STBI__CASE(f) \ - case f: \ - for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ - for (k=0; k < filter_bytes; ++k) - switch (filter) { - STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; - } - #undef STBI__CASE - - // the loop above sets the high byte of the pixels' alpha, but for - // 16 bit png files we also need the low byte set. we'll do that here. - if (depth == 16) { - cur = a->out + stride*j; // start at the beginning of the row again - for (i=0; i < x; ++i,cur+=output_bytes) { - cur[filter_bytes+1] = 255; - } - } - } - } - - // we make a separate pass to expand bits to pixels; for performance, - // this could run two scanlines behind the above code, so it won't - // intefere with filtering but will still be in the cache. - if (depth < 8) { - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; - // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit - // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + // expand decoded bits in cur to dest, also adding an extra alpha channel if desired + if (depth < 8) { stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + stbi_uc *in = cur; + stbi_uc *out = dest; + stbi_uc inb = 0; + stbi__uint32 nsmp = x*img_n; - // note that the final byte might overshoot and write more data than desired. - // we can allocate enough data that this never writes out of memory, but it - // could also overwrite the next scanline. can it overwrite non-empty data - // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. - // so we need to explicitly clamp the final ones - + // expand bits to bytes first if (depth == 4) { - for (k=x*img_n; k >= 2; k-=2, ++in) { - *cur++ = scale * ((*in >> 4) ); - *cur++ = scale * ((*in ) & 0x0f); + for (i=0; i < nsmp; ++i) { + if ((i & 1) == 0) inb = *in++; + *out++ = scale * (inb >> 4); + inb <<= 4; } - if (k > 0) *cur++ = scale * ((*in >> 4) ); } else if (depth == 2) { - for (k=x*img_n; k >= 4; k-=4, ++in) { - *cur++ = scale * ((*in >> 6) ); - *cur++ = scale * ((*in >> 4) & 0x03); - *cur++ = scale * ((*in >> 2) & 0x03); - *cur++ = scale * ((*in ) & 0x03); + for (i=0; i < nsmp; ++i) { + if ((i & 3) == 0) inb = *in++; + *out++ = scale * (inb >> 6); + inb <<= 2; } - if (k > 0) *cur++ = scale * ((*in >> 6) ); - if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); - if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); - } else if (depth == 1) { - for (k=x*img_n; k >= 8; k-=8, ++in) { - *cur++ = scale * ((*in >> 7) ); - *cur++ = scale * ((*in >> 6) & 0x01); - *cur++ = scale * ((*in >> 5) & 0x01); - *cur++ = scale * ((*in >> 4) & 0x01); - *cur++ = scale * ((*in >> 3) & 0x01); - *cur++ = scale * ((*in >> 2) & 0x01); - *cur++ = scale * ((*in >> 1) & 0x01); - *cur++ = scale * ((*in ) & 0x01); + } else { + STBI_ASSERT(depth == 1); + for (i=0; i < nsmp; ++i) { + if ((i & 7) == 0) inb = *in++; + *out++ = scale * (inb >> 7); + inb <<= 1; } - if (k > 0) *cur++ = scale * ((*in >> 7) ); - if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); - if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); - if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); - if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); - if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); - if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); } - if (img_n != out_n) { - int q; - // insert alpha = 255 - cur = a->out + stride*j; + + // insert alpha=255 values if desired + if (img_n != out_n) + stbi__create_png_alpha_expand8(dest, dest, x, img_n); + } else if (depth == 8) { + if (img_n == out_n) + memcpy(dest, cur, x*img_n); + else + stbi__create_png_alpha_expand8(dest, cur, x, img_n); + } else if (depth == 16) { + // convert the image data from big-endian to platform-native + stbi__uint16 *dest16 = (stbi__uint16*)dest; + stbi__uint32 nsmp = x*img_n; + + if (img_n == out_n) { + for (i = 0; i < nsmp; ++i, ++dest16, cur += 2) + *dest16 = (cur[0] << 8) | cur[1]; + } else { + STBI_ASSERT(img_n+1 == out_n); if (img_n == 1) { - for (q=x-1; q >= 0; --q) { - cur[q*2+1] = 255; - cur[q*2+0] = cur[q]; + for (i = 0; i < x; ++i, dest16 += 2, cur += 2) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = 0xffff; } } else { STBI_ASSERT(img_n == 3); - for (q=x-1; q >= 0; --q) { - cur[q*4+3] = 255; - cur[q*4+2] = cur[q*3+2]; - cur[q*4+1] = cur[q*3+1]; - cur[q*4+0] = cur[q*3+0]; + for (i = 0; i < x; ++i, dest16 += 4, cur += 6) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = (cur[2] << 8) | cur[3]; + dest16[2] = (cur[4] << 8) | cur[5]; + dest16[3] = 0xffff; } } } } - } else if (depth == 16) { - // force the image data from big-endian to platform-native. - // this is done in a separate pass due to the decoding relying - // on the data being untouched, but could probably be done - // per-line during decode if care is taken. - stbi_uc *cur = a->out; - stbi__uint16 *cur16 = (stbi__uint16*)cur; - - for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { - *cur16 = (cur[0] << 8) | cur[1]; - } } + STBI_FREE(filter_buf); + if (!all_ok) return 0; + return 1; } @@ -4955,7 +5010,7 @@ STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; -STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) { stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; stbi__unpremultiply_on_load_set = 1; @@ -5064,14 +5119,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!pal_img_n) { s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; } else { // if paletted, then pal_n is our final components, and // img_n is # components to decompress/filter. s->img_n = 1; if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS } + // even with SCAN_header, have to scan to see if we have a tRNS break; } @@ -5103,10 +5157,14 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); has_trans = 1; + // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. + if (scan == STBI__SCAN_header) { ++s->img_n; return 1; } if (z->depth == 16) { - for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + for (k = 0; k < s->img_n && k < 3; ++k) // extra loop test to suppress false GCC warning + tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is } else { - for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + for (k = 0; k < s->img_n && k < 3; ++k) + tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger } } break; @@ -5115,7 +5173,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) case STBI__PNG_TYPE('I','D','A','T'): { if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if (scan == STBI__SCAN_header) { + // header scan definitely stops at first IDAT + if (pal_img_n) + s->img_n = pal_img_n; + return 1; + } + if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); if ((int)(ioff + c.length) < (int)ioff) return 0; if (ioff + c.length > idata_limit) { stbi__uint32 idata_limit_old = idata_limit; @@ -5498,8 +5562,22 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req psize = (info.offset - info.extra_read - info.hsz) >> 2; } if (psize == 0) { - if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) { - return stbi__errpuc("bad offset", "Corrupt BMP"); + // accept some number of extra bytes after the header, but if the offset points either to before + // the header ends or implies a large amount of extra data, reject the file as malformed + int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original); + int header_limit = 1024; // max we actually read is below 256 bytes currently. + int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size. + if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) { + return stbi__errpuc("bad header", "Corrupt BMP"); + } + // we established that bytes_read_so_far is positive and sensible. + // the first half of this test rejects offsets that are either too small positives, or + // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn + // ensures the number computed in the second half of the test can't overflow. + if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } else { + stbi__skip(s, info.offset - bytes_read_so_far); } } @@ -7187,12 +7265,12 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re // Run value = stbi__get8(s); count -= 128; - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = value; } else { // Dump - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = stbi__get8(s); } @@ -7446,10 +7524,17 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8)); + if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { + STBI_FREE(out); + return stbi__errpuc("bad PNM", "PNM file truncated"); + } if (req_comp && req_comp != s->img_n) { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (ri->bits_per_channel == 16) { + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y); + } else { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + } if (out == NULL) return out; // stbi__convert_format frees input on failure } return out; @@ -7486,6 +7571,8 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c) while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { value = value*10 + (*c - '0'); *c = (char) stbi__get8(s); + if((value > 214748364) || (value == 214748364 && *c > '7')) + return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int"); } return value; @@ -7516,9 +7603,13 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) stbi__pnm_skip_whitespace(s, &c); *x = stbi__pnm_getinteger(s, &c); // read width + if(*x == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); stbi__pnm_skip_whitespace(s, &c); *y = stbi__pnm_getinteger(s, &c); // read height + if (*y == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); stbi__pnm_skip_whitespace(s, &c); maxv = stbi__pnm_getinteger(s, &c); // read max value From 5d9f5b061bba3b224927d25c58da4fa3a125b375 Mon Sep 17 00:00:00 2001 From: BearOso Date: Mon, 29 Jul 2024 15:56:13 -0500 Subject: [PATCH 45/51] Qt: Output S9xMessage to console. --- qt/src/Snes9xController.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qt/src/Snes9xController.cpp b/qt/src/Snes9xController.cpp index 40562bed..25593c50 100644 --- a/qt/src/Snes9xController.cpp +++ b/qt/src/Snes9xController.cpp @@ -532,7 +532,10 @@ void Snes9xController::clearSoundBuffer() void S9xMessage(int message_class, int type, const char *message) { - S9xSetInfoString(message); + if (type == S9X_ROM_INFO) + S9xSetInfoString(Memory.GetMultilineROMInfo().c_str()); + + printf("%s\n", message); } const char *S9xStringInput(const char *prompt) From e92b93ca9cd7936134abe0b90975bc9fc009fbf0 Mon Sep 17 00:00:00 2001 From: BearOso Date: Mon, 29 Jul 2024 15:56:32 -0500 Subject: [PATCH 46/51] libretro: Clear SRAM after loading ROM. --- libretro/libretro.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index a8ffcb12..6060767b 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -1156,6 +1156,8 @@ bool retro_load_game(const struct retro_game_info *game) if (!rom_loaded && log_cb) log_cb(RETRO_LOG_ERROR, "ROM loading failed...\n"); + Memory.ClearSRAM(); + return rom_loaded; } From 8b1d67397e3ad8d2cee9f71037f34092ad250b58 Mon Sep 17 00:00:00 2001 From: BearOso Date: Fri, 2 Aug 2024 18:10:03 -0500 Subject: [PATCH 47/51] Qt: Experiment with alternate widget while a game isn't running. --- qt/src/EmuMainWindow.cpp | 67 ++++++++++++++++++++++++++++++---------- qt/src/EmuMainWindow.hpp | 4 +-- 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/qt/src/EmuMainWindow.cpp b/qt/src/EmuMainWindow.cpp index b529eb5c..b40057b5 100644 --- a/qt/src/EmuMainWindow.cpp +++ b/qt/src/EmuMainWindow.cpp @@ -22,6 +22,27 @@ static EmuSettingsWindow *g_emu_settings_window = nullptr; +class DefaultBackground + : public QWidget +{ +public: + DefaultBackground(QWidget *parent) + : QWidget(parent) + { + } + + void paintEvent(QPaintEvent *event) override + { + QPainter paint(this); + QLinearGradient gradient(0.0, 0.0, 0.0, event->rect().toRectF().height()); + gradient.setColorAt(0.0, QColor(0, 0, 128)); + gradient.setColorAt(1.0, QColor(0, 0, 0)); + + paint.setBrush(QBrush(gradient)); + paint.drawRect(0, 0, event->rect().width(), event->rect().height()); + } +}; + EmuMainWindow::EmuMainWindow(EmuApplication *app) : app(app) { @@ -33,12 +54,11 @@ EmuMainWindow::EmuMainWindow(EmuApplication *app) mouse_timer.setTimerType(Qt::CoarseTimer); mouse_timer.setInterval(1000); mouse_timer.callOnTimeout([&] { - if (cursor_visible && isActivelyDrawing()) - { - if (canvas) - canvas->setCursor(QCursor(Qt::BlankCursor)); - cursor_visible = false; - mouse_timer.stop(); + if (cursor_visible && isActivelyDrawing()) { + if (canvas) + canvas->setCursor(QCursor(Qt::BlankCursor)); + cursor_visible = false; + mouse_timer.stop(); } }); } @@ -71,10 +91,20 @@ void EmuMainWindow::destroyCanvas() widget->deinit(); delete widget; } + canvas = nullptr; } bool EmuMainWindow::createCanvas() { + auto fallback = [this]() -> bool { + QMessageBox::warning( + this, tr("Unable to Start Display Driver"), + tr("Unable to create a %1 context. Attempting to use qt.") + .arg(QString::fromUtf8(app->config->display_driver))); + app->config->display_driver = "qt"; + return createCanvas(); + }; + if (app->config->display_driver != "vulkan" && app->config->display_driver != "opengl" && app->config->display_driver != "qt") @@ -94,7 +124,7 @@ bool EmuMainWindow::createCanvas() if (!canvas->createContext()) { delete canvas; - return false; + return fallback(); } } else if (app->config->display_driver == "opengl") @@ -121,7 +151,7 @@ bool EmuMainWindow::createCanvas() if (!canvas->createContext()) { delete canvas; - return false; + return fallback(); } } else if (app->config->display_driver == "opengl") @@ -141,17 +171,12 @@ bool EmuMainWindow::createCanvas() void EmuMainWindow::recreateCanvas() { + if (!canvas) + return; + app->suspendThread(); destroyCanvas(); - - if (!createCanvas()) - { - QMessageBox::warning(this, - tr("Unable to Start Display Driver"), - tr("Unable to create a %1 context. Attempting to use qt.").arg(QString::fromUtf8(app->config->display_driver))); - app->config->display_driver = "qt"; - createCanvas(); - } + createCanvas(); app->unsuspendThread(); } @@ -362,6 +387,8 @@ void EmuMainWindow::createWidgets() if (app->config->main_window_width != 0 && app->config->main_window_height != 0) resize(app->config->main_window_width, app->config->main_window_height); + + setCentralWidget(new DefaultBackground(this)); } void EmuMainWindow::resizeToMultiple(int multiple) @@ -453,6 +480,12 @@ bool EmuMainWindow::openFile(std::string filename) setCoreActionsEnabled(true); if (!isFullScreen() && app->config->fullscreen_on_open) toggleFullscreen(); + + if (!canvas) + if (!createCanvas()) + return false; + + QApplication::sync(); app->startGame(); mouse_timer.start(); return true; diff --git a/qt/src/EmuMainWindow.hpp b/qt/src/EmuMainWindow.hpp index 687b229b..24815039 100644 --- a/qt/src/EmuMainWindow.hpp +++ b/qt/src/EmuMainWindow.hpp @@ -39,8 +39,8 @@ class EmuMainWindow : public QMainWindow void gameChanging(); void toggleMouseGrab(); std::vector getDisplayDeviceList(); - EmuApplication *app; - EmuCanvas *canvas; + EmuApplication *app = nullptr; + EmuCanvas *canvas = nullptr; private: void idle(); From 5c7847acbb06a0d2aa94d619215071efa27973fc Mon Sep 17 00:00:00 2001 From: BearOso Date: Sat, 10 Aug 2024 17:00:40 -0500 Subject: [PATCH 48/51] Sort common OpenGL and Wayland files into folders. --- common/video/{ => opengl}/glx_context.cpp | 0 common/video/{ => opengl}/glx_context.hpp | 0 common/video/{ => opengl}/opengl_context.hpp | 0 .../video/{ => opengl}/wayland_egl_context.cpp | 0 .../video/{ => opengl}/wayland_egl_context.hpp | 2 +- common/video/{ => opengl}/wgl_context.cpp | 0 common/video/{ => opengl}/wgl_context.hpp | 0 .../video/{ => wayland}/fractional-scale-v1.c | 0 .../video/{ => wayland}/fractional-scale-v1.h | 0 .../{ => wayland}/viewporter-client-protocol.c | 0 .../{ => wayland}/viewporter-client-protocol.h | 0 .../wayland-idle-inhibit-unstable-v1.c | 0 .../wayland-idle-inhibit-unstable-v1.h | 0 common/video/{ => wayland}/wayland_surface.cpp | 0 common/video/{ => wayland}/wayland_surface.hpp | 0 gtk/CMakeLists.txt | 16 ++++++++-------- gtk/src/gtk_display_driver_opengl.h | 6 +++--- gtk/src/gtk_display_driver_vulkan.h | 2 +- qt/CMakeLists.txt | 18 ++++++++++++------ qt/src/EmuCanvasOpenGL.cpp | 6 +++--- qt/src/EmuCanvasVulkan.cpp | 2 +- qt/src/EmuCanvasVulkan.hpp | 2 +- 22 files changed, 30 insertions(+), 24 deletions(-) rename common/video/{ => opengl}/glx_context.cpp (100%) rename common/video/{ => opengl}/glx_context.hpp (100%) rename common/video/{ => opengl}/opengl_context.hpp (100%) rename common/video/{ => opengl}/wayland_egl_context.cpp (100%) rename common/video/{ => opengl}/wayland_egl_context.hpp (95%) rename common/video/{ => opengl}/wgl_context.cpp (100%) rename common/video/{ => opengl}/wgl_context.hpp (100%) rename common/video/{ => wayland}/fractional-scale-v1.c (100%) rename common/video/{ => wayland}/fractional-scale-v1.h (100%) rename common/video/{ => wayland}/viewporter-client-protocol.c (100%) rename common/video/{ => wayland}/viewporter-client-protocol.h (100%) rename common/video/{ => wayland}/wayland-idle-inhibit-unstable-v1.c (100%) rename common/video/{ => wayland}/wayland-idle-inhibit-unstable-v1.h (100%) rename common/video/{ => wayland}/wayland_surface.cpp (100%) rename common/video/{ => wayland}/wayland_surface.hpp (100%) diff --git a/common/video/glx_context.cpp b/common/video/opengl/glx_context.cpp similarity index 100% rename from common/video/glx_context.cpp rename to common/video/opengl/glx_context.cpp diff --git a/common/video/glx_context.hpp b/common/video/opengl/glx_context.hpp similarity index 100% rename from common/video/glx_context.hpp rename to common/video/opengl/glx_context.hpp diff --git a/common/video/opengl_context.hpp b/common/video/opengl/opengl_context.hpp similarity index 100% rename from common/video/opengl_context.hpp rename to common/video/opengl/opengl_context.hpp diff --git a/common/video/wayland_egl_context.cpp b/common/video/opengl/wayland_egl_context.cpp similarity index 100% rename from common/video/wayland_egl_context.cpp rename to common/video/opengl/wayland_egl_context.cpp diff --git a/common/video/wayland_egl_context.hpp b/common/video/opengl/wayland_egl_context.hpp similarity index 95% rename from common/video/wayland_egl_context.hpp rename to common/video/opengl/wayland_egl_context.hpp index 14cc9c6c..c8bc023a 100644 --- a/common/video/wayland_egl_context.hpp +++ b/common/video/opengl/wayland_egl_context.hpp @@ -8,7 +8,7 @@ #define __WAYLAND_EGL_CONTEXT_H #include "opengl_context.hpp" -#include "wayland_surface.hpp" +#include "common/video/wayland/wayland_surface.hpp" #include "glad/egl.h" #include diff --git a/common/video/wgl_context.cpp b/common/video/opengl/wgl_context.cpp similarity index 100% rename from common/video/wgl_context.cpp rename to common/video/opengl/wgl_context.cpp diff --git a/common/video/wgl_context.hpp b/common/video/opengl/wgl_context.hpp similarity index 100% rename from common/video/wgl_context.hpp rename to common/video/opengl/wgl_context.hpp diff --git a/common/video/fractional-scale-v1.c b/common/video/wayland/fractional-scale-v1.c similarity index 100% rename from common/video/fractional-scale-v1.c rename to common/video/wayland/fractional-scale-v1.c diff --git a/common/video/fractional-scale-v1.h b/common/video/wayland/fractional-scale-v1.h similarity index 100% rename from common/video/fractional-scale-v1.h rename to common/video/wayland/fractional-scale-v1.h diff --git a/common/video/viewporter-client-protocol.c b/common/video/wayland/viewporter-client-protocol.c similarity index 100% rename from common/video/viewporter-client-protocol.c rename to common/video/wayland/viewporter-client-protocol.c diff --git a/common/video/viewporter-client-protocol.h b/common/video/wayland/viewporter-client-protocol.h similarity index 100% rename from common/video/viewporter-client-protocol.h rename to common/video/wayland/viewporter-client-protocol.h diff --git a/common/video/wayland-idle-inhibit-unstable-v1.c b/common/video/wayland/wayland-idle-inhibit-unstable-v1.c similarity index 100% rename from common/video/wayland-idle-inhibit-unstable-v1.c rename to common/video/wayland/wayland-idle-inhibit-unstable-v1.c diff --git a/common/video/wayland-idle-inhibit-unstable-v1.h b/common/video/wayland/wayland-idle-inhibit-unstable-v1.h similarity index 100% rename from common/video/wayland-idle-inhibit-unstable-v1.h rename to common/video/wayland/wayland-idle-inhibit-unstable-v1.h diff --git a/common/video/wayland_surface.cpp b/common/video/wayland/wayland_surface.cpp similarity index 100% rename from common/video/wayland_surface.cpp rename to common/video/wayland/wayland_surface.cpp diff --git a/common/video/wayland_surface.hpp b/common/video/wayland/wayland_surface.hpp similarity index 100% rename from common/video/wayland_surface.hpp rename to common/video/wayland/wayland_surface.hpp diff --git a/gtk/CMakeLists.txt b/gtk/CMakeLists.txt index 6d13d493..82617b4d 100644 --- a/gtk/CMakeLists.txt +++ b/gtk/CMakeLists.txt @@ -68,7 +68,7 @@ list(APPEND ARGS ${SDL2_CFLAGS} ${GTK_CFLAGS} ${XRANDR_CFLAGS}) list(APPEND LIBS ${X11} ${XEXT} ${CMAKE_DL_LIBS} ${SDL2_LIBRARIES} ${GTK_LIBRARIES} ${XRANDR_LIBRARIES}) list(APPEND SOURCES src/gtk_display_driver_opengl.cpp - ../common/video/glx_context.cpp + ../common/video/opengl/glx_context.cpp ../shaders/glsl.cpp ../shaders/shader_helpers.cpp ../vulkan/slang_helpers.cpp @@ -154,13 +154,13 @@ list(APPEND INCLUDES ../external/imgui) if(USE_WAYLAND) pkg_check_modules(WAYLAND REQUIRED wayland-client wayland-egl) list(APPEND DEFINES "USE_WAYLAND") - list(APPEND SOURCES ../common/video/wayland_egl_context.cpp - ../common/video/wayland_egl_context.hpp - ../common/video/wayland_surface.cpp - ../common/video/wayland_surface.hpp - ../common/video/wayland-idle-inhibit-unstable-v1.c - ../common/video/viewporter-client-protocol.c - ../common/video/fractional-scale-v1.c) + list(APPEND SOURCES ../common/video/opengl/wayland_egl_context.cpp + ../common/video/opengl/wayland_egl_context.hpp + ../common/video/wayland/wayland_surface.cpp + ../common/video/wayland/wayland_surface.hpp + ../common/video/wayland/wayland-idle-inhibit-unstable-v1.c + ../common/video/wayland/viewporter-client-protocol.c + ../common/video/wayland/fractional-scale-v1.c) list(APPEND ARGS ${WAYLAND_CFLAGS}) list(APPEND LIBS ${WAYLAND_LIBRARIES}) endif() diff --git a/gtk/src/gtk_display_driver_opengl.h b/gtk/src/gtk_display_driver_opengl.h index c9f6862f..f4acd903 100644 --- a/gtk/src/gtk_display_driver_opengl.h +++ b/gtk/src/gtk_display_driver_opengl.h @@ -12,14 +12,14 @@ #include -#include "common/video/opengl_context.hpp" +#include "common/video/opengl/opengl_context.hpp" #include "gtk_compat.h" #ifdef GDK_WINDOWING_X11 -#include "common/video/glx_context.hpp" +#include "common/video/opengl/glx_context.hpp" #endif #ifdef GDK_WINDOWING_WAYLAND -#include "common/video/wayland_egl_context.hpp" +#include "common/video/opengl/wayland_egl_context.hpp" #endif #include "shaders/glsl.h" diff --git a/gtk/src/gtk_display_driver_vulkan.h b/gtk/src/gtk_display_driver_vulkan.h index dcc6567a..63945f0b 100644 --- a/gtk/src/gtk_display_driver_vulkan.h +++ b/gtk/src/gtk_display_driver_vulkan.h @@ -13,7 +13,7 @@ #include "vulkan/std_chrono_throttle.hpp" #ifdef VK_USE_PLATFORM_WAYLAND_KHR -#include "common/video/wayland_surface.hpp" +#include "common/video/wayland/wayland_surface.hpp" #endif class S9xVulkanDisplayDriver : public S9xDisplayDriver diff --git a/qt/CMakeLists.txt b/qt/CMakeLists.txt index baa6104e..efda7183 100644 --- a/qt/CMakeLists.txt +++ b/qt/CMakeLists.txt @@ -139,12 +139,18 @@ else() endif() list(APPEND PLATFORM_SOURCES - ../common/video/glx_context.cpp - ../common/video/wayland_egl_context.cpp - ../common/video/wayland_surface.cpp - ../common/video/fractional-scale-v1.c - ../common/video/viewporter-client-protocol.c - ../common/video/wayland-idle-inhibit-unstable-v1.c + ../common/video/opengl/glx_context.cpp + ../common/video/opengl/glx_context.hpp + ../common/video/opengl/wayland_egl_context.cpp + ../common/video/opengl/wayland_egl_context.hpp + ../common/video/wayland/wayland_surface.cpp + ../common/video/wayland/wayland_surface.hpp + ../common/video/wayland/fractional-scale-v1.c + ../common/video/wayland/fractional-scale-v1.h + ../common/video/wayland/viewporter-client-protocol.c + ../common/video/wayland/viewporter-client-protocol.h + ../common/video/wayland/wayland-idle-inhibit-unstable-v1.c + ../common/video/wayland/wayland-idle-inhibit-unstable-v1.h ../external/glad/src/glx.c ../external/glad/src/egl.c) endif() diff --git a/qt/src/EmuCanvasOpenGL.cpp b/qt/src/EmuCanvasOpenGL.cpp index ee3f61a5..218219b8 100644 --- a/qt/src/EmuCanvasOpenGL.cpp +++ b/qt/src/EmuCanvasOpenGL.cpp @@ -3,11 +3,11 @@ #include #include #include -#include "common/video/opengl_context.hpp" +#include "common/video/opengl/opengl_context.hpp" #ifndef _WIN32 -#include "common/video/glx_context.hpp" -#include "common/video/wayland_egl_context.hpp" +#include "common/video/opengl/glx_context.hpp" +#include "common/video/opengl/wayland_egl_context.hpp" using namespace QNativeInterface; #include #else diff --git a/qt/src/EmuCanvasVulkan.cpp b/qt/src/EmuCanvasVulkan.cpp index 12557221..3795ebba 100644 --- a/qt/src/EmuCanvasVulkan.cpp +++ b/qt/src/EmuCanvasVulkan.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/qt/src/EmuCanvasVulkan.hpp b/qt/src/EmuCanvasVulkan.hpp index 704daf86..1f269f2f 100644 --- a/qt/src/EmuCanvasVulkan.hpp +++ b/qt/src/EmuCanvasVulkan.hpp @@ -7,7 +7,7 @@ #include "../../vulkan/vulkan_shader_chain.hpp" #ifndef _WIN32 -#include "common/video/wayland_surface.hpp" +#include "common/video/wayland/wayland_surface.hpp" #endif class EmuCanvasVulkan : public EmuCanvas From 9f7173f81962a8bbc64bdcd36a71c99d3b1fb98b Mon Sep 17 00:00:00 2001 From: BearOso Date: Sat, 10 Aug 2024 17:08:57 -0500 Subject: [PATCH 49/51] Move shaders directory into common/video/opengl. --- {shaders => common/video/opengl/shaders}/glsl.cpp | 2 +- {shaders => common/video/opengl/shaders}/glsl.h | 2 +- {shaders => common/video/opengl/shaders}/shader_helpers.cpp | 0 {shaders => common/video/opengl/shaders}/shader_helpers.h | 0 {shaders => common/video/opengl/shaders}/shader_platform.h | 0 {shaders => common/video/opengl/shaders}/slang.cpp | 0 gtk/CMakeLists.txt | 6 +++--- gtk/src/gtk_display_driver_opengl.h | 2 +- gtk/src/gtk_shader_parameters.cpp | 2 +- qt/CMakeLists.txt | 6 +++--- qt/src/EmuCanvasOpenGL.cpp | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) rename {shaders => common/video/opengl/shaders}/glsl.cpp (99%) rename {shaders => common/video/opengl/shaders}/glsl.h (99%) rename {shaders => common/video/opengl/shaders}/shader_helpers.cpp (100%) rename {shaders => common/video/opengl/shaders}/shader_helpers.h (100%) rename {shaders => common/video/opengl/shaders}/shader_platform.h (100%) rename {shaders => common/video/opengl/shaders}/slang.cpp (100%) diff --git a/shaders/glsl.cpp b/common/video/opengl/shaders/glsl.cpp similarity index 99% rename from shaders/glsl.cpp rename to common/video/opengl/shaders/glsl.cpp index cabf0b82..8056ea79 100644 --- a/shaders/glsl.cpp +++ b/common/video/opengl/shaders/glsl.cpp @@ -11,7 +11,7 @@ #include #include "glsl.h" #include "shader_helpers.h" -#include "../vulkan/slang_helpers.hpp" +#include "vulkan/slang_helpers.hpp" #include "shader_platform.h" #ifndef _MSC_VER #include diff --git a/shaders/glsl.h b/common/video/opengl/shaders/glsl.h similarity index 99% rename from shaders/glsl.h rename to common/video/opengl/shaders/glsl.h index c12309f6..73669b91 100644 --- a/shaders/glsl.h +++ b/common/video/opengl/shaders/glsl.h @@ -8,7 +8,7 @@ #define __GLSL_H #include "snes9x.h" -#include "../vulkan/slang_preset_ini.hpp" +#include "vulkan/slang_preset_ini.hpp" #include "shader_platform.h" #include #include diff --git a/shaders/shader_helpers.cpp b/common/video/opengl/shaders/shader_helpers.cpp similarity index 100% rename from shaders/shader_helpers.cpp rename to common/video/opengl/shaders/shader_helpers.cpp diff --git a/shaders/shader_helpers.h b/common/video/opengl/shaders/shader_helpers.h similarity index 100% rename from shaders/shader_helpers.h rename to common/video/opengl/shaders/shader_helpers.h diff --git a/shaders/shader_platform.h b/common/video/opengl/shaders/shader_platform.h similarity index 100% rename from shaders/shader_platform.h rename to common/video/opengl/shaders/shader_platform.h diff --git a/shaders/slang.cpp b/common/video/opengl/shaders/slang.cpp similarity index 100% rename from shaders/slang.cpp rename to common/video/opengl/shaders/slang.cpp diff --git a/gtk/CMakeLists.txt b/gtk/CMakeLists.txt index 82617b4d..4bf16fb0 100644 --- a/gtk/CMakeLists.txt +++ b/gtk/CMakeLists.txt @@ -69,8 +69,8 @@ list(APPEND LIBS ${X11} ${XEXT} ${CMAKE_DL_LIBS} ${SDL2_LIBRARIES} ${GTK_LIBRARI list(APPEND SOURCES src/gtk_display_driver_opengl.cpp ../common/video/opengl/glx_context.cpp - ../shaders/glsl.cpp - ../shaders/shader_helpers.cpp + ../common/video/opengl/shaders/glsl.cpp + ../common/video/opengl/shaders/shader_helpers.cpp ../vulkan/slang_helpers.cpp ../vulkan/slang_helpers.hpp ../vulkan/slang_preset_ini.cpp @@ -84,7 +84,7 @@ list(APPEND SOURCES src/gtk_display_driver_opengl.cpp list(APPEND INCLUDES ../external/glad/include) if(USE_SLANG) - list(APPEND SOURCES ../shaders/slang.cpp) + list(APPEND SOURCES ../common/video/opengl/shaders/slang.cpp) list(APPEND INCLUDES ../external/glslang) set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS CACHE BOOL ON) diff --git a/gtk/src/gtk_display_driver_opengl.h b/gtk/src/gtk_display_driver_opengl.h index f4acd903..bd5d4d17 100644 --- a/gtk/src/gtk_display_driver_opengl.h +++ b/gtk/src/gtk_display_driver_opengl.h @@ -22,7 +22,7 @@ #include "common/video/opengl/wayland_egl_context.hpp" #endif -#include "shaders/glsl.h" +#include "common/video/opengl/shaders/glsl.h" #include "vulkan/std_chrono_throttle.hpp" #define BUFFER_OFFSET(i) ((char *)(i)) diff --git a/gtk/src/gtk_shader_parameters.cpp b/gtk/src/gtk_shader_parameters.cpp index 377167a9..7c70e427 100644 --- a/gtk/src/gtk_shader_parameters.cpp +++ b/gtk/src/gtk_shader_parameters.cpp @@ -11,7 +11,7 @@ #include "gtk_s9x.h" #include "gtk_display.h" #include "gtk_shader_parameters.h" -#include "shaders/glsl.h" +#include "common/video/opengl/shaders/glsl.h" #include "gfx.h" diff --git a/qt/CMakeLists.txt b/qt/CMakeLists.txt index efda7183..7a1fdea6 100644 --- a/qt/CMakeLists.txt +++ b/qt/CMakeLists.txt @@ -281,9 +281,9 @@ list(APPEND SOURCES ../vulkan/slang_preset_ini.cpp ../vulkan/slang_preset_ini.hpp ../external/stb/stb_image_implementation.cpp - ../shaders/glsl.cpp - ../shaders/slang.cpp - ../shaders/shader_helpers.cpp) + ../common/video/opengl/shaders/glsl.cpp + ../common/video/opengl/shaders/slang.cpp + ../common/video/opengl/shaders/shader_helpers.cpp) list(APPEND DEFINES "IMGUI_IMPL_VULKAN_NO_PROTOTYPES") list(APPEND SOURCES ../external/imgui/imgui.cpp diff --git a/qt/src/EmuCanvasOpenGL.cpp b/qt/src/EmuCanvasOpenGL.cpp index 218219b8..e2c0c7fe 100644 --- a/qt/src/EmuCanvasOpenGL.cpp +++ b/qt/src/EmuCanvasOpenGL.cpp @@ -13,7 +13,7 @@ using namespace QNativeInterface; #else #include "common/video/wgl_context.hpp" #endif -#include "shaders/glsl.h" +#include "common/video/opengl/shaders/glsl.h" #include "EmuMainWindow.hpp" #include "snes9x_imgui.h" #include "imgui_impl_opengl3.h" From 17737825757b059dff25ee1ce930a318b53e8765 Mon Sep 17 00:00:00 2001 From: BearOso Date: Sat, 10 Aug 2024 17:41:47 -0500 Subject: [PATCH 50/51] Move vulkan to common/video. --- common/video/opengl/shaders/glsl.cpp | 2 +- common/video/opengl/shaders/glsl.h | 2 +- .../video}/std_chrono_throttle.cpp | 0 .../video}/std_chrono_throttle.hpp | 0 .../video/vulkan}/slang_helpers.cpp | 0 .../video/vulkan}/slang_helpers.hpp | 0 .../video/vulkan}/slang_preset.cpp | 6 +- .../video/vulkan}/slang_preset.hpp | 0 .../video/vulkan}/slang_preset_ini.cpp | 0 .../video/vulkan}/slang_preset_ini.hpp | 0 .../video/vulkan}/slang_preset_test.cpp | 0 .../video/vulkan}/slang_shader.cpp | 6 +- .../video/vulkan}/slang_shader.hpp | 0 .../vulkan}/vk_mem_alloc_implementation.cpp | 0 .../video/vulkan}/vulkan_context.cpp | 0 .../video/vulkan}/vulkan_context.hpp | 4 +- .../video/vulkan}/vulkan_hpp_storage.cpp | 0 .../video/vulkan}/vulkan_hpp_wrapper.hpp | 0 .../video/vulkan}/vulkan_pipeline_image.cpp | 0 .../video/vulkan}/vulkan_pipeline_image.hpp | 0 .../video/vulkan}/vulkan_shader_chain.cpp | 0 .../video/vulkan}/vulkan_shader_chain.hpp | 0 .../video/vulkan}/vulkan_simple_output.cpp | 0 .../video/vulkan}/vulkan_simple_output.hpp | 0 .../video/vulkan}/vulkan_slang_pipeline.cpp | 0 .../video/vulkan}/vulkan_slang_pipeline.hpp | 2 +- .../video/vulkan}/vulkan_swapchain.cpp | 0 .../video/vulkan}/vulkan_swapchain.hpp | 2 +- .../video/vulkan}/vulkan_texture.cpp | 0 .../video/vulkan}/vulkan_texture.hpp | 0 gtk/CMakeLists.txt | 72 +++++++++---------- gtk/src/gtk_display_driver_opengl.h | 2 +- gtk/src/gtk_display_driver_vulkan.h | 8 +-- qt/CMakeLists.txt | 52 +++++++------- qt/src/EmuCanvas.hpp | 2 +- qt/src/EmuCanvasVulkan.cpp | 1 - qt/src/EmuCanvasVulkan.hpp | 4 +- 37 files changed, 82 insertions(+), 83 deletions(-) rename {vulkan => common/video}/std_chrono_throttle.cpp (100%) rename {vulkan => common/video}/std_chrono_throttle.hpp (100%) rename {vulkan => common/video/vulkan}/slang_helpers.cpp (100%) rename {vulkan => common/video/vulkan}/slang_helpers.hpp (100%) rename {vulkan => common/video/vulkan}/slang_preset.cpp (99%) rename {vulkan => common/video/vulkan}/slang_preset.hpp (100%) rename {vulkan => common/video/vulkan}/slang_preset_ini.cpp (100%) rename {vulkan => common/video/vulkan}/slang_preset_ini.hpp (100%) rename {vulkan => common/video/vulkan}/slang_preset_test.cpp (100%) rename {vulkan => common/video/vulkan}/slang_shader.cpp (97%) rename {vulkan => common/video/vulkan}/slang_shader.hpp (100%) rename {vulkan => common/video/vulkan}/vk_mem_alloc_implementation.cpp (100%) rename {vulkan => common/video/vulkan}/vulkan_context.cpp (100%) rename {vulkan => common/video/vulkan}/vulkan_context.hpp (93%) rename {vulkan => common/video/vulkan}/vulkan_hpp_storage.cpp (100%) rename {vulkan => common/video/vulkan}/vulkan_hpp_wrapper.hpp (100%) rename {vulkan => common/video/vulkan}/vulkan_pipeline_image.cpp (100%) rename {vulkan => common/video/vulkan}/vulkan_pipeline_image.hpp (100%) rename {vulkan => common/video/vulkan}/vulkan_shader_chain.cpp (100%) rename {vulkan => common/video/vulkan}/vulkan_shader_chain.hpp (100%) rename {vulkan => common/video/vulkan}/vulkan_simple_output.cpp (100%) rename {vulkan => common/video/vulkan}/vulkan_simple_output.hpp (100%) rename {vulkan => common/video/vulkan}/vulkan_slang_pipeline.cpp (100%) rename {vulkan => common/video/vulkan}/vulkan_slang_pipeline.hpp (95%) rename {vulkan => common/video/vulkan}/vulkan_swapchain.cpp (100%) rename {vulkan => common/video/vulkan}/vulkan_swapchain.hpp (97%) rename {vulkan => common/video/vulkan}/vulkan_texture.cpp (100%) rename {vulkan => common/video/vulkan}/vulkan_texture.hpp (100%) diff --git a/common/video/opengl/shaders/glsl.cpp b/common/video/opengl/shaders/glsl.cpp index 8056ea79..05a5a51a 100644 --- a/common/video/opengl/shaders/glsl.cpp +++ b/common/video/opengl/shaders/glsl.cpp @@ -11,7 +11,7 @@ #include #include "glsl.h" #include "shader_helpers.h" -#include "vulkan/slang_helpers.hpp" +#include "common/video/vulkan/slang_helpers.hpp" #include "shader_platform.h" #ifndef _MSC_VER #include diff --git a/common/video/opengl/shaders/glsl.h b/common/video/opengl/shaders/glsl.h index 73669b91..d3c612d1 100644 --- a/common/video/opengl/shaders/glsl.h +++ b/common/video/opengl/shaders/glsl.h @@ -8,7 +8,7 @@ #define __GLSL_H #include "snes9x.h" -#include "vulkan/slang_preset_ini.hpp" +#include "common/video/vulkan/slang_preset_ini.hpp" #include "shader_platform.h" #include #include diff --git a/vulkan/std_chrono_throttle.cpp b/common/video/std_chrono_throttle.cpp similarity index 100% rename from vulkan/std_chrono_throttle.cpp rename to common/video/std_chrono_throttle.cpp diff --git a/vulkan/std_chrono_throttle.hpp b/common/video/std_chrono_throttle.hpp similarity index 100% rename from vulkan/std_chrono_throttle.hpp rename to common/video/std_chrono_throttle.hpp diff --git a/vulkan/slang_helpers.cpp b/common/video/vulkan/slang_helpers.cpp similarity index 100% rename from vulkan/slang_helpers.cpp rename to common/video/vulkan/slang_helpers.cpp diff --git a/vulkan/slang_helpers.hpp b/common/video/vulkan/slang_helpers.hpp similarity index 100% rename from vulkan/slang_helpers.hpp rename to common/video/vulkan/slang_helpers.hpp diff --git a/vulkan/slang_preset.cpp b/common/video/vulkan/slang_preset.cpp similarity index 99% rename from vulkan/slang_preset.cpp rename to common/video/vulkan/slang_preset.cpp index bdb63c3e..69362ae2 100644 --- a/vulkan/slang_preset.cpp +++ b/common/video/vulkan/slang_preset.cpp @@ -1,5 +1,5 @@ #include "slang_preset.hpp" -#include "../external/SPIRV-Cross/spirv.hpp" +#include "external/SPIRV-Cross/spirv.hpp" #include "slang_helpers.hpp" #include "slang_preset_ini.hpp" @@ -12,8 +12,8 @@ #include #include #include -#include "../external/SPIRV-Cross/spirv_cross.hpp" -#include "../external/SPIRV-Cross/spirv_glsl.hpp" +#include "external/SPIRV-Cross/spirv_cross.hpp" +#include "external/SPIRV-Cross/spirv_glsl.hpp" #include "slang_shader.hpp" using std::string; diff --git a/vulkan/slang_preset.hpp b/common/video/vulkan/slang_preset.hpp similarity index 100% rename from vulkan/slang_preset.hpp rename to common/video/vulkan/slang_preset.hpp diff --git a/vulkan/slang_preset_ini.cpp b/common/video/vulkan/slang_preset_ini.cpp similarity index 100% rename from vulkan/slang_preset_ini.cpp rename to common/video/vulkan/slang_preset_ini.cpp diff --git a/vulkan/slang_preset_ini.hpp b/common/video/vulkan/slang_preset_ini.hpp similarity index 100% rename from vulkan/slang_preset_ini.hpp rename to common/video/vulkan/slang_preset_ini.hpp diff --git a/vulkan/slang_preset_test.cpp b/common/video/vulkan/slang_preset_test.cpp similarity index 100% rename from vulkan/slang_preset_test.cpp rename to common/video/vulkan/slang_preset_test.cpp diff --git a/vulkan/slang_shader.cpp b/common/video/vulkan/slang_shader.cpp similarity index 97% rename from vulkan/slang_shader.cpp rename to common/video/vulkan/slang_shader.cpp index 7a16564e..1b01cf3a 100644 --- a/vulkan/slang_shader.cpp +++ b/common/video/vulkan/slang_shader.cpp @@ -7,9 +7,9 @@ #include #include #include -#include "../external/glslang/glslang/Public/ShaderLang.h" -#include "../external/glslang/SPIRV/GlslangToSpv.h" -#include "../external/glslang/glslang/Public/ResourceLimits.h" +#include "external/glslang/glslang/Public/ShaderLang.h" +#include "external/glslang/SPIRV/GlslangToSpv.h" +#include "external/glslang/glslang/Public/ResourceLimits.h" using std::string; using std::vector; diff --git a/vulkan/slang_shader.hpp b/common/video/vulkan/slang_shader.hpp similarity index 100% rename from vulkan/slang_shader.hpp rename to common/video/vulkan/slang_shader.hpp diff --git a/vulkan/vk_mem_alloc_implementation.cpp b/common/video/vulkan/vk_mem_alloc_implementation.cpp similarity index 100% rename from vulkan/vk_mem_alloc_implementation.cpp rename to common/video/vulkan/vk_mem_alloc_implementation.cpp diff --git a/vulkan/vulkan_context.cpp b/common/video/vulkan/vulkan_context.cpp similarity index 100% rename from vulkan/vulkan_context.cpp rename to common/video/vulkan/vulkan_context.cpp diff --git a/vulkan/vulkan_context.hpp b/common/video/vulkan/vulkan_context.hpp similarity index 93% rename from vulkan/vulkan_context.hpp rename to common/video/vulkan/vulkan_context.hpp index 8ebe4b83..c15df4f8 100644 --- a/vulkan/vulkan_context.hpp +++ b/common/video/vulkan/vulkan_context.hpp @@ -8,8 +8,8 @@ #define WINVER 0x599 #endif #include -#include "vulkan/vulkan_hpp_wrapper.hpp" -#include "../external/VulkanMemoryAllocator-Hpp/include/vk_mem_alloc.hpp" +#include "vulkan_hpp_wrapper.hpp" +#include "external/VulkanMemoryAllocator-Hpp/include/vk_mem_alloc.hpp" #include "vulkan_swapchain.hpp" #include diff --git a/vulkan/vulkan_hpp_storage.cpp b/common/video/vulkan/vulkan_hpp_storage.cpp similarity index 100% rename from vulkan/vulkan_hpp_storage.cpp rename to common/video/vulkan/vulkan_hpp_storage.cpp diff --git a/vulkan/vulkan_hpp_wrapper.hpp b/common/video/vulkan/vulkan_hpp_wrapper.hpp similarity index 100% rename from vulkan/vulkan_hpp_wrapper.hpp rename to common/video/vulkan/vulkan_hpp_wrapper.hpp diff --git a/vulkan/vulkan_pipeline_image.cpp b/common/video/vulkan/vulkan_pipeline_image.cpp similarity index 100% rename from vulkan/vulkan_pipeline_image.cpp rename to common/video/vulkan/vulkan_pipeline_image.cpp diff --git a/vulkan/vulkan_pipeline_image.hpp b/common/video/vulkan/vulkan_pipeline_image.hpp similarity index 100% rename from vulkan/vulkan_pipeline_image.hpp rename to common/video/vulkan/vulkan_pipeline_image.hpp diff --git a/vulkan/vulkan_shader_chain.cpp b/common/video/vulkan/vulkan_shader_chain.cpp similarity index 100% rename from vulkan/vulkan_shader_chain.cpp rename to common/video/vulkan/vulkan_shader_chain.cpp diff --git a/vulkan/vulkan_shader_chain.hpp b/common/video/vulkan/vulkan_shader_chain.hpp similarity index 100% rename from vulkan/vulkan_shader_chain.hpp rename to common/video/vulkan/vulkan_shader_chain.hpp diff --git a/vulkan/vulkan_simple_output.cpp b/common/video/vulkan/vulkan_simple_output.cpp similarity index 100% rename from vulkan/vulkan_simple_output.cpp rename to common/video/vulkan/vulkan_simple_output.cpp diff --git a/vulkan/vulkan_simple_output.hpp b/common/video/vulkan/vulkan_simple_output.hpp similarity index 100% rename from vulkan/vulkan_simple_output.hpp rename to common/video/vulkan/vulkan_simple_output.hpp diff --git a/vulkan/vulkan_slang_pipeline.cpp b/common/video/vulkan/vulkan_slang_pipeline.cpp similarity index 100% rename from vulkan/vulkan_slang_pipeline.cpp rename to common/video/vulkan/vulkan_slang_pipeline.cpp diff --git a/vulkan/vulkan_slang_pipeline.hpp b/common/video/vulkan/vulkan_slang_pipeline.hpp similarity index 95% rename from vulkan/vulkan_slang_pipeline.hpp rename to common/video/vulkan/vulkan_slang_pipeline.hpp index b9e813a3..d4fd473c 100644 --- a/vulkan/vulkan_slang_pipeline.hpp +++ b/common/video/vulkan/vulkan_slang_pipeline.hpp @@ -1,5 +1,5 @@ #pragma once -#include "vulkan/vulkan_hpp_wrapper.hpp" +#include "vulkan_hpp_wrapper.hpp" #include "slang_shader.hpp" #include "vulkan_context.hpp" #include "vulkan_pipeline_image.hpp" diff --git a/vulkan/vulkan_swapchain.cpp b/common/video/vulkan/vulkan_swapchain.cpp similarity index 100% rename from vulkan/vulkan_swapchain.cpp rename to common/video/vulkan/vulkan_swapchain.cpp diff --git a/vulkan/vulkan_swapchain.hpp b/common/video/vulkan/vulkan_swapchain.hpp similarity index 97% rename from vulkan/vulkan_swapchain.hpp rename to common/video/vulkan/vulkan_swapchain.hpp index ad271e83..41028027 100644 --- a/vulkan/vulkan_swapchain.hpp +++ b/common/video/vulkan/vulkan_swapchain.hpp @@ -1,6 +1,6 @@ #pragma once -#include "vulkan/vulkan_hpp_wrapper.hpp" +#include "vulkan_hpp_wrapper.hpp" #include namespace Vulkan diff --git a/vulkan/vulkan_texture.cpp b/common/video/vulkan/vulkan_texture.cpp similarity index 100% rename from vulkan/vulkan_texture.cpp rename to common/video/vulkan/vulkan_texture.cpp diff --git a/vulkan/vulkan_texture.hpp b/common/video/vulkan/vulkan_texture.hpp similarity index 100% rename from vulkan/vulkan_texture.hpp rename to common/video/vulkan/vulkan_texture.hpp diff --git a/gtk/CMakeLists.txt b/gtk/CMakeLists.txt index 4bf16fb0..7c65cc5f 100644 --- a/gtk/CMakeLists.txt +++ b/gtk/CMakeLists.txt @@ -71,16 +71,16 @@ list(APPEND SOURCES src/gtk_display_driver_opengl.cpp ../common/video/opengl/glx_context.cpp ../common/video/opengl/shaders/glsl.cpp ../common/video/opengl/shaders/shader_helpers.cpp - ../vulkan/slang_helpers.cpp - ../vulkan/slang_helpers.hpp - ../vulkan/slang_preset_ini.cpp - ../vulkan/slang_preset_ini.hpp + ../common/video/vulkan/slang_helpers.cpp + ../common/video/vulkan/slang_helpers.hpp + ../common/video/vulkan/slang_preset_ini.cpp + ../common/video/vulkan/slang_preset_ini.hpp ../external/glad/src/glx.c ../external/glad/src/egl.c ../external/glad/src/gl.c src/gtk_shader_parameters.cpp - ../vulkan/std_chrono_throttle.cpp - ../vulkan/std_chrono_throttle.hpp) + ../common/video/std_chrono_throttle.cpp + ../common/video/std_chrono_throttle.hpp) list(APPEND INCLUDES ../external/glad/include) if(USE_SLANG) @@ -116,26 +116,26 @@ if(USE_SLANG) list(APPEND INCLUDES ../external/VulkanMemoryAllocator-Hpp/include) list(APPEND INCLUDES ../external/stb) list(APPEND SOURCES ../external/stb/stb_image_implementation.cpp) - list(APPEND SOURCES ../vulkan/slang_shader.cpp - ../vulkan/slang_shader.hpp - ../vulkan/slang_preset.cpp - ../vulkan/slang_preset.hpp - ../vulkan/vulkan_hpp_storage.cpp - ../vulkan/vk_mem_alloc_implementation.cpp - ../vulkan/vulkan_context.cpp - ../vulkan/vulkan_context.hpp - ../vulkan/vulkan_texture.cpp - ../vulkan/vulkan_texture.hpp - ../vulkan/vulkan_swapchain.cpp - ../vulkan/vulkan_swapchain.hpp - ../vulkan/vulkan_slang_pipeline.cpp - ../vulkan/vulkan_slang_pipeline.hpp - ../vulkan/vulkan_pipeline_image.cpp - ../vulkan/vulkan_pipeline_image.hpp - ../vulkan/vulkan_shader_chain.cpp - ../vulkan/vulkan_shader_chain.hpp - ../vulkan/vulkan_simple_output.hpp - ../vulkan/vulkan_simple_output.cpp + list(APPEND SOURCES ../common/video/vulkan/slang_shader.cpp + ../common/video/vulkan/slang_shader.hpp + ../common/video/vulkan/slang_preset.cpp + ../common/video/vulkan/slang_preset.hpp + ../common/video/vulkan/vulkan_hpp_storage.cpp + ../common/video/vulkan/vk_mem_alloc_implementation.cpp + ../common/video/vulkan/vulkan_context.cpp + ../common/video/vulkan/vulkan_context.hpp + ../common/video/vulkan/vulkan_texture.cpp + ../common/video/vulkan/vulkan_texture.hpp + ../common/video/vulkan/vulkan_swapchain.cpp + ../common/video/vulkan/vulkan_swapchain.hpp + ../common/video/vulkan/vulkan_slang_pipeline.cpp + ../common/video/vulkan/vulkan_slang_pipeline.hpp + ../common/video/vulkan/vulkan_pipeline_image.cpp + ../common/video/vulkan/vulkan_pipeline_image.hpp + ../common/video/vulkan/vulkan_shader_chain.cpp + ../common/video/vulkan/vulkan_shader_chain.hpp + ../common/video/vulkan/vulkan_simple_output.hpp + ../common/video/vulkan/vulkan_simple_output.cpp src/gtk_display_driver_vulkan.cpp src/gtk_display_driver_vulkan.h ../external/imgui/imgui_impl_vulkan.cpp) @@ -388,16 +388,16 @@ target_compile_definitions(snes9x-gtk PRIVATE ${DEFINES}) if(USE_SLANG) add_executable(slang_test EXCLUDE_FROM_ALL - ../vulkan/slang_helpers.cpp - ../vulkan/slang_helpers.hpp - ../vulkan/slang_shader.cpp - ../vulkan/slang_shader.hpp - ../vulkan/slang_preset.cpp - ../vulkan/slang_preset.hpp - ../vulkan/slang_preset_ini.cpp - ../vulkan/slang_preset_ini.hpp - ../vulkan/vulkan_hpp_storage.cpp - ../vulkan/slang_preset_test.cpp + ../common/video/vulkan/slang_helpers.cpp + ../common/video/vulkan/slang_helpers.hpp + ../common/video/vulkan/slang_shader.cpp + ../common/video/vulkan/slang_shader.hpp + ../common/video/vulkan/slang_preset.cpp + ../common/video/vulkan/slang_preset.hpp + ../common/video/vulkan/slang_preset_ini.cpp + ../common/video/vulkan/slang_preset_ini.hpp + ../common/video/vulkan/vulkan_hpp_storage.cpp + ../common/video/vulkan/slang_preset_test.cpp ../conffile.cpp ../stream.cpp) diff --git a/gtk/src/gtk_display_driver_opengl.h b/gtk/src/gtk_display_driver_opengl.h index bd5d4d17..b94fc82f 100644 --- a/gtk/src/gtk_display_driver_opengl.h +++ b/gtk/src/gtk_display_driver_opengl.h @@ -23,7 +23,7 @@ #endif #include "common/video/opengl/shaders/glsl.h" -#include "vulkan/std_chrono_throttle.hpp" +#include "common/video/std_chrono_throttle.hpp" #define BUFFER_OFFSET(i) ((char *)(i)) diff --git a/gtk/src/gtk_display_driver_vulkan.h b/gtk/src/gtk_display_driver_vulkan.h index 63945f0b..78761596 100644 --- a/gtk/src/gtk_display_driver_vulkan.h +++ b/gtk/src/gtk_display_driver_vulkan.h @@ -7,10 +7,10 @@ #pragma once #include "gtk_s9x.h" #include "gtk_display_driver.h" -#include "vulkan/vulkan_context.hpp" -#include "vulkan/vulkan_shader_chain.hpp" -#include "vulkan/vulkan_simple_output.hpp" -#include "vulkan/std_chrono_throttle.hpp" +#include "common/video/vulkan/vulkan_context.hpp" +#include "common/video/vulkan/vulkan_shader_chain.hpp" +#include "common/video/vulkan/vulkan_simple_output.hpp" +#include "common/video/std_chrono_throttle.hpp" #ifdef VK_USE_PLATFORM_WAYLAND_KHR #include "common/video/wayland/wayland_surface.hpp" diff --git a/qt/CMakeLists.txt b/qt/CMakeLists.txt index 7a1fdea6..a2205712 100644 --- a/qt/CMakeLists.txt +++ b/qt/CMakeLists.txt @@ -254,32 +254,32 @@ list(APPEND INCLUDES ../external/stb "../external/glad/include") list(APPEND SOURCES - ../vulkan/slang_shader.cpp - ../vulkan/slang_shader.hpp - ../vulkan/slang_preset.cpp - ../vulkan/slang_preset.hpp - ../vulkan/vulkan_hpp_storage.cpp - ../vulkan/vk_mem_alloc_implementation.cpp - ../vulkan/vulkan_context.cpp - ../vulkan/vulkan_context.hpp - ../vulkan/vulkan_texture.cpp - ../vulkan/vulkan_texture.hpp - ../vulkan/vulkan_swapchain.cpp - ../vulkan/vulkan_swapchain.hpp - ../vulkan/vulkan_slang_pipeline.cpp - ../vulkan/vulkan_slang_pipeline.hpp - ../vulkan/vulkan_pipeline_image.cpp - ../vulkan/vulkan_pipeline_image.hpp - ../vulkan/vulkan_shader_chain.cpp - ../vulkan/vulkan_shader_chain.hpp - ../vulkan/vulkan_simple_output.hpp - ../vulkan/vulkan_simple_output.cpp - ../vulkan/std_chrono_throttle.cpp - ../vulkan/std_chrono_throttle.hpp - ../vulkan/slang_helpers.cpp - ../vulkan/slang_helpers.hpp - ../vulkan/slang_preset_ini.cpp - ../vulkan/slang_preset_ini.hpp + ../common/video/vulkan/slang_shader.cpp + ../common/video/vulkan/slang_shader.hpp + ../common/video/vulkan/slang_preset.cpp + ../common/video/vulkan/slang_preset.hpp + ../common/video/vulkan/vulkan_hpp_storage.cpp + ../common/video/vulkan/vk_mem_alloc_implementation.cpp + ../common/video/vulkan/vulkan_context.cpp + ../common/video/vulkan/vulkan_context.hpp + ../common/video/vulkan/vulkan_texture.cpp + ../common/video/vulkan/vulkan_texture.hpp + ../common/video/vulkan/vulkan_swapchain.cpp + ../common/video/vulkan/vulkan_swapchain.hpp + ../common/video/vulkan/vulkan_slang_pipeline.cpp + ../common/video/vulkan/vulkan_slang_pipeline.hpp + ../common/video/vulkan/vulkan_pipeline_image.cpp + ../common/video/vulkan/vulkan_pipeline_image.hpp + ../common/video/vulkan/vulkan_shader_chain.cpp + ../common/video/vulkan/vulkan_shader_chain.hpp + ../common/video/vulkan/vulkan_simple_output.hpp + ../common/video/vulkan/vulkan_simple_output.cpp + ../common/video/std_chrono_throttle.cpp + ../common/video/std_chrono_throttle.hpp + ../common/video/vulkan/slang_helpers.cpp + ../common/video/vulkan/slang_helpers.hpp + ../common/video/vulkan/slang_preset_ini.cpp + ../common/video/vulkan/slang_preset_ini.hpp ../external/stb/stb_image_implementation.cpp ../common/video/opengl/shaders/glsl.cpp ../common/video/opengl/shaders/slang.cpp diff --git a/qt/src/EmuCanvas.hpp b/qt/src/EmuCanvas.hpp index 09fb398a..ef9a1138 100644 --- a/qt/src/EmuCanvas.hpp +++ b/qt/src/EmuCanvas.hpp @@ -1,7 +1,7 @@ #pragma once #include #include -#include "../../vulkan/std_chrono_throttle.hpp" +#include "common/video/std_chrono_throttle.hpp" class EmuConfig; diff --git a/qt/src/EmuCanvasVulkan.cpp b/qt/src/EmuCanvasVulkan.cpp index 3795ebba..c02788b6 100644 --- a/qt/src/EmuCanvasVulkan.cpp +++ b/qt/src/EmuCanvasVulkan.cpp @@ -4,7 +4,6 @@ #include #include #include "EmuCanvasVulkan.hpp" -#include "src/ShaderParametersDialog.hpp" #include "EmuMainWindow.hpp" #include "snes9x_imgui.h" diff --git a/qt/src/EmuCanvasVulkan.hpp b/qt/src/EmuCanvasVulkan.hpp index 1f269f2f..ec20828a 100644 --- a/qt/src/EmuCanvasVulkan.hpp +++ b/qt/src/EmuCanvasVulkan.hpp @@ -3,8 +3,8 @@ #include "EmuCanvas.hpp" #include "ShaderParametersDialog.hpp" -#include "../../vulkan/vulkan_simple_output.hpp" -#include "../../vulkan/vulkan_shader_chain.hpp" +#include "common/video/vulkan/vulkan_simple_output.hpp" +#include "common/video/vulkan/vulkan_shader_chain.hpp" #ifndef _WIN32 #include "common/video/wayland/wayland_surface.hpp" From 85591435763dede7ef111aab8070cdf2d5a7da49 Mon Sep 17 00:00:00 2001 From: BearOso Date: Sat, 10 Aug 2024 18:03:55 -0500 Subject: [PATCH 51/51] Fix compile on Windows. --- qt/CMakeLists.txt | 2 +- qt/src/EmuCanvasOpenGL.cpp | 4 +-- win32/COpenGL.h | 2 +- win32/CVulkan.h | 6 ++-- win32/snes9xw.vcxproj | 62 +++++++++++++++++------------------ win32/snes9xw.vcxproj.filters | 62 +++++++++++++++++------------------ win32/wsnes9x.cpp | 2 +- 7 files changed, 70 insertions(+), 70 deletions(-) diff --git a/qt/CMakeLists.txt b/qt/CMakeLists.txt index a2205712..4a9d4e86 100644 --- a/qt/CMakeLists.txt +++ b/qt/CMakeLists.txt @@ -115,7 +115,7 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") list(APPEND LIBS libSDL2.a libz.a opengl32 gdi32 winmm imm32 ole32 oleaut32 version uuid advapi32 setupapi shell32 dinput8) list(APPEND DEFINES SDL_MAIN_HANDLED) list(APPEND PLATFORM_SOURCES - ../common/video/wgl_context.cpp + ../common/video/opengl/wgl_context.cpp ../external/glad/src/wgl.c src/resources/snes9x_win32.rc) else() diff --git a/qt/src/EmuCanvasOpenGL.cpp b/qt/src/EmuCanvasOpenGL.cpp index e2c0c7fe..6b5d6d4f 100644 --- a/qt/src/EmuCanvasOpenGL.cpp +++ b/qt/src/EmuCanvasOpenGL.cpp @@ -11,7 +11,7 @@ using namespace QNativeInterface; #include #else -#include "common/video/wgl_context.hpp" +#include "common/video/opengl/wgl_context.hpp" #endif #include "common/video/opengl/shaders/glsl.h" #include "EmuMainWindow.hpp" @@ -303,7 +303,7 @@ void EmuCanvasOpenGL::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); - if (!context) + if (!context) return; auto g = parent->geometry(); diff --git a/win32/COpenGL.h b/win32/COpenGL.h index aa4e5ac1..3d88690d 100644 --- a/win32/COpenGL.h +++ b/win32/COpenGL.h @@ -11,7 +11,7 @@ #include "gl_core_3_1.h" #include "cgFunctions.h" #include "CGLCG.h" -#include "../shaders/glsl.h" +#include "common/video/opengl/shaders/glsl.h" #include "wglext.h" #include "IS9xDisplayOutput.h" diff --git a/win32/CVulkan.h b/win32/CVulkan.h index bc6cf97b..0dcae641 100644 --- a/win32/CVulkan.h +++ b/win32/CVulkan.h @@ -1,9 +1,9 @@ #pragma once #include "IS9xDisplayOutput.h" -#include "../vulkan/vulkan_context.hpp" -#include "../vulkan/vulkan_shader_chain.hpp" -#include "../vulkan/vulkan_simple_output.hpp" +#include "common/video/vulkan/vulkan_context.hpp" +#include "common/video/vulkan/vulkan_shader_chain.hpp" +#include "common/video/vulkan/vulkan_simple_output.hpp" #include class CVulkan : public IS9xDisplayOutput diff --git a/win32/snes9xw.vcxproj b/win32/snes9xw.vcxproj index 5a246df4..c70cb789 100644 --- a/win32/snes9xw.vcxproj +++ b/win32/snes9xw.vcxproj @@ -427,9 +427,9 @@ true - - - + + + @@ -449,17 +449,17 @@ - - - - - - - - - - - + + + + + + + + + + + @@ -575,9 +575,9 @@ - - - + + + @@ -618,20 +618,20 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/win32/snes9xw.vcxproj.filters b/win32/snes9xw.vcxproj.filters index 3c56eaaa..be988b13 100644 --- a/win32/snes9xw.vcxproj.filters +++ b/win32/snes9xw.vcxproj.filters @@ -237,13 +237,13 @@ Filter - + Shaders - + Shaders - + Shaders @@ -300,37 +300,37 @@ GUI\VideoDriver - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan @@ -665,10 +665,10 @@ GUI - + Shaders - + Shaders @@ -680,7 +680,7 @@ GUI\VideoDriver - + Shaders @@ -716,49 +716,49 @@ GUI\VideoDriver - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan GUI\VideoDriver\Vulkan - + GUI\VideoDriver\Vulkan diff --git a/win32/wsnes9x.cpp b/win32/wsnes9x.cpp index 56a32e95..e0bb5bdd 100644 --- a/win32/wsnes9x.cpp +++ b/win32/wsnes9x.cpp @@ -33,7 +33,7 @@ #include "win32_sound.h" #include "win32_display.h" #include "CCGShader.h" -#include "../shaders/glsl.h" +#include "common/video/opengl/shaders/glsl.h" #include "CShaderParamDlg.h" #include "CSaveLoadWithPreviewDlg.h" #include "../snes9x.h"