From cebdccfdf5aec30aa2ab7c61c4720ec2191bdb8f Mon Sep 17 00:00:00 2001 From: Crementif <26669564+Crementif@users.noreply.github.com> Date: Thu, 15 Sep 2022 04:06:40 +0200 Subject: [PATCH 001/638] Update readme about matrix server Supersedes https://github.com/cemu-project/Cemu/pull/245 --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 14682b41..43b65175 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Process](https://github.com/cemu-project/Cemu/actions/workflows/build.yml/badge.svg)](https://github.com/cemu-project/Cemu/actions/workflows/build.yml) [![Discord](https://img.shields.io/discord/286429969104764928?label=Cemu&logo=discord&logoColor=FFFFFF)](https://discord.gg/5psYsup) -[![Matrix Server](https://img.shields.io/matrix/dev:cemu.info?server_fqdn=matrix.cemu.info&label=dev:cemu.info&logo=matrix&logoColor=FFFFFF)](https://matrix.to/#/#dev:cemu.info) +[![Matrix Server](https://img.shields.io/matrix/cemu:cemu.info?server_fqdn=matrix.cemu.info&label=cemu:cemu.info&logo=matrix&logoColor=FFFFFF)](https://matrix.to/#/#cemu:cemu.info) This is the code repository of Cemu, a Wii U emulator that is able to run most Wii U games and homebrew in a playable state. It's written in C/C++ and is being actively developed with new features and fixes to increase compatibility, convenience and usability. @@ -15,6 +15,7 @@ Cemu is currently only available for 64-bit Windows and Linux devices. - [Compatibility List/Wiki](https://wiki.cemu.info/wiki/Main_Page) - [Official Subreddit](https://reddit.com/r/Cemu) - [Official Discord](https://discord.gg/5psYsup) + - [Official Matrix Server](https://matrix.to/#/#cemu:cemu.info) - [Unofficial Setup Guide](https://cemu.cfw.guide) #### Other relevant repositories: @@ -27,7 +28,7 @@ You can download the latest Cemu releases from the [GitHub Releases](https://git Cemu is currently only available in a portable format so no installation is required besides extracting it in a safe place. -See [Current State Of Linux builds](https://github.com/cemu-project/Cemu/issues/1) for information on using Cemu natively on Linux. +The native Linux build is currently a work-in-progress. See [Current State Of Linux builds](https://github.com/cemu-project/Cemu/issues/107) for more information about the things to be aware of. Pre-2.0 releases can be found on Cemu's [changelog page](https://cemu.info/changelog.html). @@ -42,11 +43,11 @@ The old bug tracker can be found at [bugs.cemu.info](https://bugs.cemu.info) and ## Contributing -Pull requests are very welcome. For easier coordination you can visit the developer discussion channel on Discord: [https://discord.gg/5psYsup](https://discord.gg/5psYsup). +Pull requests are very welcome. For easier coordination you can visit the developer discussion channel on [Discord](https://discord.gg/5psYsup) or alternatively the [Matrix Server](https://matrix.to/#/#cemu:cemu.info). If coding isn't your thing, testing games and making detailed bug reports or updating the (usually outdated) compatibility wiki is also appreciated! -Questions about Cemu's software architecture can also be answered on Discord. Alternative communication channels (like IRC) are being considered. +Questions about Cemu's software architecture can also be answered on Discord (through the Matrix bridge). ## License Cemu is licensed under [Mozilla Public License 2.0](/LICENSE.txt). Exempt from this are all files in the dependencies directory for which the licenses of the original code apply as well as some individual files in the src folder, as specified in those file headers respectively. From 664d7ee902ed5300ae019e58c1cf0c1359a319d7 Mon Sep 17 00:00:00 2001 From: Francesco Saltori Date: Fri, 16 Sep 2022 13:34:41 +0200 Subject: [PATCH 002/638] Clean up more Cemuhook leftovers (#253) --- src/Cafe/GraphicPack/GraphicPack2Patches.cpp | 8 ++------ src/Cafe/HW/Espresso/PPCState.h | 1 - src/Cafe/OS/RPL/rpl.cpp | 7 ------- src/Cafe/OS/RPL/rpl_structs.h | 16 ---------------- src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp | 7 ++----- src/Cafe/OS/libs/coreinit/coreinit_DynLoad.h | 2 +- src/gui/MainWindow.cpp | 14 ++------------ 7 files changed, 7 insertions(+), 48 deletions(-) diff --git a/src/Cafe/GraphicPack/GraphicPack2Patches.cpp b/src/Cafe/GraphicPack/GraphicPack2Patches.cpp index 5a3c85b9..3910000a 100644 --- a/src/Cafe/GraphicPack/GraphicPack2Patches.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2Patches.cpp @@ -121,12 +121,8 @@ bool GraphicPack2::LoadCemuPatches() void GraphicPack2::LoadPatchFiles() { // order of loading patches: - // 1) If Cemuhook is loaded: - // 1.1) Check if patches.txt exists and if it does, stop here and do nothing (Cemuhook takes over patching) - // 1.2) Load Cemu-style patches (patch_.asm) - // 2) If Cemuhook is not loaded: - // 1.1) Load Cemu-style patches (patch_.asm), stop here if at least one patch file exists - // 1.2) Load Cemuhook patches.txt + // 1) Load Cemu-style patches (patch_.asm), stop here if at least one patch file exists + // 2) Load Cemuhook patches.txt // update: As of 1.20.2b Cemu always takes over patching since Cemuhook patching broke due to other internal changes (memory allocation changed and some reordering on when graphic packs get loaded) if (LoadCemuPatches()) diff --git a/src/Cafe/HW/Espresso/PPCState.h b/src/Cafe/HW/Espresso/PPCState.h index 540bbd4e..1e36c099 100644 --- a/src/Cafe/HW/Espresso/PPCState.h +++ b/src/Cafe/HW/Espresso/PPCState.h @@ -65,7 +65,6 @@ struct PPCInterpreter_t // LWARX and STWCX uint32 reservedMemAddr; uint32 reservedMemValue; - /* Note: Everything above is potentially hardcoded into Cemuhook. Do not touch anything or it will risk breaking compatibility */ // temporary storage for recompiler FPR_t temporaryFPR[8]; uint32 temporaryGPR[4]; diff --git a/src/Cafe/OS/RPL/rpl.cpp b/src/Cafe/OS/RPL/rpl.cpp index 90f9225b..b1af5535 100644 --- a/src/Cafe/OS/RPL/rpl.cpp +++ b/src/Cafe/OS/RPL/rpl.cpp @@ -217,7 +217,6 @@ bool RPLLoader_ProcessHeaders(std::string_view moduleName, uint8* rplData, uint3 // setup RPL info struct RPLModule* rplLoaderContext = new RPLModule(); rplLoaderContext->RPLRawData = std::span(rplData, rplSize); - rplLoaderContext->rplData_depr = rplData; rplLoaderContext->heapTrampolineArea.setBaseAllocator(&rplLoaderHeap_lowerAreaCodeMem2); // load section table if ((uint32)rplHeader->sectionTableEntrySize != sizeof(rplSectionEntryNew_t)) @@ -282,12 +281,6 @@ bool RPLLoader_ProcessHeaders(std::string_view moduleName, uint8* rplData, uint3 // convert modulename to lower-case for(auto& c : rplLoaderContext->moduleName2) c = _ansiToLower(c); - // cemuhook compatibility - rplLoaderContext->moduleNamePtr__depr = rplLoaderContext->moduleName2.data(); - rplLoaderContext->moduleNameLength__depr = rplLoaderContext->moduleName2.size(); - rplLoaderContext->moduleNameSize = 0; - rplLoaderContext->sectionAddressTable__depr = rplLoaderContext->sectionAddressTable2.data(); - rplLoaderContext->sectionAddressTableSize__depr = rplLoaderContext->sectionAddressTable2.size() * sizeof(rplSectionAddressEntry_t); // load CRC section uint32 crcTableExpectedSize = sectionCount * sizeof(uint32be); diff --git a/src/Cafe/OS/RPL/rpl_structs.h b/src/Cafe/OS/RPL/rpl_structs.h index 18413049..71be960c 100644 --- a/src/Cafe/OS/RPL/rpl_structs.h +++ b/src/Cafe/OS/RPL/rpl_structs.h @@ -144,25 +144,13 @@ struct RPLModule { uint32 ukn00; // pointer to shared memory region? (0xEFE01000) uint32 ukn04; // related to text region size? - char* moduleNamePtr__depr; // converted to lower case - uint32 moduleNameLength__depr; // length of module name - uint32 moduleNameSize; // aligned alloc size, not the same as actual length uint32 padding14; uint32 padding18; rplHeaderNew_t rplHeader; rplSectionEntryNew_t* sectionTablePtr; // copy of section table - RPLFileInfoData* fileInfoPtr__depr{}; // copy of fileinfo section - uint32 fileInfoSize__depr{}; // size of fileInfo section - uint32 fileInfoAllocSize__depr{}; // aligned alloc size - - uint32be* crcTablePtr_depr{}; // copy of CRC section - uint32 crcTableAllocSize_depr{}; - uint32 entrypoint; - uint8* rplData_depr; // Cemuhook might still read this - MPTR textRegionTemp; // temporary memory for text section? MEMPTR regionMappingBase_text; // base destination address for text region @@ -171,15 +159,11 @@ struct RPLModule uint8* tempRegionPtr; uint32 tempRegionAllocSize; - rplSectionAddressEntry_t* sectionAddressTable__depr; - uint32 sectionAddressTableSize__depr; - uint32 exportDCount; rplExportTableEntry_t* exportDDataPtr; uint32 exportFCount; rplExportTableEntry_t* exportFDataPtr; - /* above are hardcoded in Cemuhook */ std::string moduleName2; std::vector sectionAddressTable2; diff --git a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp index aae17dfe..f6559b65 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp @@ -105,15 +105,12 @@ namespace coreinit return 0; } - uint32 OSDynLoad_Release(uint32 moduleHandle) + void OSDynLoad_Release(uint32 moduleHandle) { if (moduleHandle == RPL_INVALID_HANDLE) - return 0; + return; RPLLoader_RemoveDependency(moduleHandle); RPLLoader_UpdateDependencies(); - - // this function isn't supposed to return anything, but early versions of Cemu did and Cemuhook (up to 0.5.7.6) now relies on it. We still keep the return value around for compatibility - return 0; } uint32 OSDynLoad_FindExport(uint32 moduleHandle, uint32 isData, const char* exportName, betype* addrOut) diff --git a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.h b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.h index 061be002..0be8226c 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.h @@ -11,7 +11,7 @@ namespace coreinit void OSDynLoad_AllocatorFree(void* mem); uint32 OSDynLoad_Acquire(const char* libName, uint32be* moduleHandleOut); - uint32 OSDynLoad_Release(uint32 moduleHandle); + void OSDynLoad_Release(uint32 moduleHandle); uint32 OSDynLoad_FindExport(uint32 moduleHandle, uint32 isData, const char* exportName, betype* addrOut); void InitializeDynLoad(); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 5b65c7a1..7c1ce0e4 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -66,8 +66,6 @@ wxDEFINE_EVENT(wxEVT_SET_WINDOW_TITLE, wxCommandEvent); enum { - // note - Cemuhook mirrors these ids, be careful about changing them - // ui elements MAINFRAME_GAMELIST_ID = 20000, //wxID_HIGHEST + 1, // file @@ -79,7 +77,6 @@ enum MAINFRAME_MENU_ID_FILE_RECENT_LAST = MAINFRAME_MENU_ID_FILE_RECENT_0 + 15, // options MAINFRAME_MENU_ID_OPTIONS_FULLSCREEN = 20200, - MAINFRAME_MENU_ID_OPTIONS_VSYNC, MAINFRAME_MENU_ID_OPTIONS_SECOND_WINDOW_PADVIEW, MAINFRAME_MENU_ID_OPTIONS_GRAPHIC, MAINFRAME_MENU_ID_OPTIONS_GRAPHIC_PACKS2, @@ -87,10 +84,6 @@ enum MAINFRAME_MENU_ID_OPTIONS_GENERAL2, MAINFRAME_MENU_ID_OPTIONS_AUDIO, MAINFRAME_MENU_ID_OPTIONS_INPUT, - // options -> experimental - MAINFRAME_MENU_ID_EXPERIMENTAL_BOTW_WORKAROUND = 20300, - MAINFRAME_MENU_ID_EXPERIMENTAL_SYNC_TO_GX2DRAWDONE, - MAINFRAME_MENU_ID_EXPERIMENTAL_DISABLE_PRECOMPILED, // options -> account MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_1 = 20350, MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_12 = 20350 + 11, @@ -127,8 +120,7 @@ enum MAINFRAME_MENU_ID_NFC_RECENT_0, MAINFRAME_MENU_ID_NFC_RECENT_LAST = MAINFRAME_MENU_ID_NFC_RECENT_0 + 15, // debug - MAINFRAME_MENU_ID_DEBUG_RESERVED = 21100, - MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN, + MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN = 21100, MAINFRAME_MENU_ID_DEBUG_VIEW_LOGGING_WINDOW, MAINFRAME_MENU_ID_DEBUG_VIEW_PPC_THREADS, MAINFRAME_MENU_ID_DEBUG_VIEW_PPC_DEBUGGER, @@ -139,9 +131,7 @@ enum MAINFRAME_MENU_ID_DEBUG_VK_ACCURATE_BARRIERS, // debug->logging - MAINFRAME_MENU_ID_DEBUG_LOGGING_DISABLE_ALL = 21500, - MAINFRAME_MENU_ID_DEBUG_LOGGING0, - MAINFRAME_MENU_ID_DEBUG_LOGGING20 = MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 20, + MAINFRAME_MENU_ID_DEBUG_LOGGING0 = 21500, MAINFRAME_MENU_ID_DEBUG_ADVANCED_PPC_INFO, // debug->dump MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES = 21600, From 63206eb9a81ff8ce7f3003e1804175e6930249c4 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Fri, 16 Sep 2022 14:25:38 +0200 Subject: [PATCH 003/638] coreinit: Return error code instead of success in Acquire failure (#260) Spotted by @Fs00 It's currently not known if any games are affected by this --- src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp index f6559b65..c8b05124 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp @@ -94,14 +94,13 @@ namespace coreinit RPLLoader_Link(); RPLLoader_CallEntrypoints(); rplHandle = RPLLoader_GetHandleByModuleName(libName); - if (rplHandle == RPL_INVALID_HANDLE) - rplHandle = 0; } - - *moduleHandleOut = rplHandle; - // return module not found error code if (rplHandle == RPL_INVALID_HANDLE) - return 0xFFFCFFE9; + *moduleHandleOut = 0; + else + *moduleHandleOut = rplHandle; + if (rplHandle == RPL_INVALID_HANDLE) + return 0xFFFCFFE9; // module not found return 0; } From 6ef36152c28dcd7c034f122b0af1762fa264e9bb Mon Sep 17 00:00:00 2001 From: Shoegzer Date: Fri, 16 Sep 2022 19:06:36 -0400 Subject: [PATCH 004/638] Use system color definitions for wxGameList (#241) Previously it would use hard-coded bright colors which clashed with dark themes on Linux --- src/gui/components/wxGameList.cpp | 92 ++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 33 deletions(-) diff --git a/src/gui/components/wxGameList.cpp b/src/gui/components/wxGameList.cpp index 39eeb100..6c3c4a01 100644 --- a/src/gui/components/wxGameList.cpp +++ b/src/gui/components/wxGameList.cpp @@ -71,8 +71,8 @@ wxGameList::wxGameList(wxWindow* parent, wxWindowID id) m_tooltip_window->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK)); m_tooltip_window->SetSizerAndFit(tooltip_sizer); m_tooltip_window->Hide(); - - m_tooltip_timer = new wxTimer(this); + + m_tooltip_timer = new wxTimer(this); Bind(wxEVT_CLOSE_WINDOW, &wxGameList::OnClose, this); Bind(wxEVT_MOTION, &wxGameList::OnMouseMove, this); @@ -125,16 +125,16 @@ void wxGameList::LoadConfig() { wxArrayInt order; order.reserve(ColumnFavorite); - + const auto order_string = std::string_view(config.game_list_column_order).substr(1); - + const boost::char_separator sep(","); boost::tokenizer tokens(order_string.begin(), order_string.end(), sep); for(const auto& token : tokens) { order.push_back(ConvertString(token, 10)); } - + #ifdef wxHAS_LISTCTRL_COLUMN_ORDER if(order.GetCount() == ColumnFavorite) SetColumnsOrder(order); @@ -209,10 +209,10 @@ void wxGameList::SetStyle(Style style, bool save) return; wxWindowUpdateLocker updatelock(this); - + m_style = style; SetWindowStyleFlag(GetStyleFlags(m_style)); - + uint64 selected_title_id = 0; auto selection = GetNextItem(wxNOT_FOUND, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if (selection != wxNOT_FOUND) @@ -230,7 +230,7 @@ void wxGameList::SetStyle(Style style, bool save) wxListCtrl::SetImageList(m_image_list_small, wxIMAGE_LIST_NORMAL); break; } - + ReloadGameEntries(); SortEntries(); UpdateItemColors(); @@ -269,16 +269,42 @@ long wxGameList::GetStyleFlags(Style style) const void wxGameList::UpdateItemColors(sint32 startIndex) { - wxWindowUpdateLocker lock(this); - for (int i = startIndex; i < GetItemCount(); ++i) - { - const auto titleId = (uint64)GetItemData(i); + + wxWindowUpdateLocker lock(this); + + // Get the background color so we can determine the theme in use + const wxColour bgColour = GetBackgroundColour(); + + for (int i = startIndex; i < GetItemCount(); ++i) + { + const auto titleId = (uint64)GetItemData(i); if (GetConfig().IsGameListFavorite(titleId))//entry->favorite) + { SetItemBackgroundColour(i, kFavoriteColor); + SetItemTextColour(i, 0x000000UL); + } else if ((i&1) != 0) - SetItemBackgroundColour(i, kSecondColor); + { + // Depending on the background RGB value: + // Light theme row color will be 10% darker (90) + // Dark theme row color will be 10% brighter (110) + int alpha = bgColour.GetRGB() > 0x808080 ? 90 : 110; + SetItemBackgroundColour(i, bgColour.ChangeLightness(alpha)); + + // Text can be changed to other values for alternating rows if needed + SetItemTextColour(i, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); + } else - SetItemBackgroundColour(i, 0xFFFFFFUL); + { + // Depending on the background RGB value: + // Light theme row color will be 0% darker (100) + // Dark theme row color will be 0% brighter (100) + int alpha = bgColour.GetRGB() > 0x808080 ? 100 : 100; + SetItemBackgroundColour(i, bgColour.ChangeLightness(alpha)); + + // Text color can be modified to other values for alternating rows if needed + SetItemTextColour(i, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); + } } } @@ -309,7 +335,7 @@ int wxGameList::SortFunction(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData) { const auto sort_data = (SortData*)sortData; const int dir = sort_data->dir; - + return sort_data->thisptr->SortComparator((uint64)item1, (uint64)item2, sort_data); } @@ -331,7 +357,7 @@ void wxGameList::SortEntries(int column) s_direction = 1; } } - + switch (column) { case ColumnName: @@ -349,7 +375,7 @@ void wxGameList::SortEntries(int column) void wxGameList::CreateListColumns() { DeleteAllColumns(); - + const auto& config = GetConfig(); wxListItem col0; col0.SetId(ColumnHiddenName); @@ -392,7 +418,7 @@ void wxGameList::CreateListColumns() col6.SetText(_("Last played")); col6.SetWidth(config.column_width.game_started); InsertColumn(ColumnGameStarted, col6); - + wxListItem col7; col7.SetId(ColumnRegion); col7.SetText(_("Region")); @@ -405,7 +431,7 @@ void wxGameList::OnKeyDown(wxListEvent& event) event.Skip(); if (m_style != Style::kList) return; - + const auto keycode = std::tolower(event.m_code); if (keycode == WXK_LEFT) { @@ -445,12 +471,12 @@ void wxGameList::OnKeyDown(wxListEvent& event) enum ContextMenuEntries { kContextMenuRefreshGames = wxID_HIGHEST + 1, - + kContextMenuStart, kWikiPage, kContextMenuFavorite, kContextMenuEditName, - + kContextMenuGameFolder, kContextMenuSaveFolder, kContextMenuUpdateFolder, @@ -465,10 +491,10 @@ enum ContextMenuEntries void wxGameList::OnContextMenu(wxContextMenuEvent& event) { auto& config = GetConfig(); - + wxMenu menu; menu.Bind(wxEVT_COMMAND_MENU_SELECTED, &wxGameList::OnContextMenuSelected, this); - + const auto selection = GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if (selection != wxNOT_FOUND) { @@ -486,18 +512,18 @@ void wxGameList::OnContextMenu(wxContextMenuEvent& event) menu.AppendSeparator(); menu.AppendCheckItem(kContextMenuFavorite, _("&Favorite"))->Check(isFavorite); menu.Append(kContextMenuEditName, _("&Edit name")); - + menu.AppendSeparator(); menu.Append(kWikiPage, _("&Wiki page")); menu.Append(kContextMenuGameFolder, _("&Game directory")); menu.Append(kContextMenuSaveFolder, _("&Save directory"))->Enable(fs::is_directory(gameInfo.GetSaveFolder(), ec)); menu.Append(kContextMenuUpdateFolder, _("&Update directory"))->Enable(gameInfo.HasUpdate()); menu.Append(kContextMenuDLCFolder, _("&DLC directory"))->Enable(gameInfo.HasAOC()); - + menu.AppendSeparator(); menu.Append(kContextMenuEditGraphicPacks, _("&Edit graphic packs")); menu.Append(kContextMenuEditGameProfile, _("&Edit game profile")); - + menu.AppendSeparator(); } } @@ -581,7 +607,7 @@ void wxGameList::OnContextMenuSelected(wxCommandEvent& event) } break; } - + case kContextMenuSaveFolder: { wxLaunchDefaultBrowser(wxHelper::FromUtf8(fmt::format("file:{}", _pathToUtf8(gameInfo.GetSaveFolder())))); @@ -647,7 +673,7 @@ void wxGameList::OnColumnRightClick(wxListEvent& event) { ResetWidth = wxID_HIGHEST + 1, ResetOrder, - + ShowName, ShowVersion, ShowDlc, @@ -658,10 +684,10 @@ void wxGameList::OnColumnRightClick(wxListEvent& event) const int column = event.GetColumn(); wxMenu menu; menu.SetClientObject(new wxCustomData(column)); - + menu.Append(ResetWidth, _("Reset &width")); menu.Append(ResetOrder, _("Reset &order")) ; - + menu.AppendSeparator(); menu.AppendCheckItem(ShowName, _("Show &name"))->Check(GetColumnWidth(ColumnName) > 0); menu.AppendCheckItem(ShowVersion, _("Show &version"))->Check(GetColumnWidth(ColumnVersion) > 0); @@ -758,7 +784,7 @@ void wxGameList::ApplyGameListColumnWidths() else this->SetColumnWidth(id, width); }; - + const auto& config = GetConfig(); wxWindowUpdateLocker lock(this); set_width(ColumnName, config.column_width.name); @@ -943,7 +969,7 @@ void wxGameList::OnItemActivated(wxListEvent& event) wxPostEvent(this, open_settings_event); return; } - + TitleInfo titleInfo; if (!CafeTitleList::GetFirstByTitleId(item_data, titleInfo)) return; @@ -974,7 +1000,7 @@ void wxGameList::OnTimer(wxTimerEvent& event) //} } } - + } void wxGameList::OnMouseMove(wxMouseEvent& event) From 910cdf4d5c2d1b2d1f3615ed0384900808b38dda Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sat, 17 Sep 2022 02:39:52 +0200 Subject: [PATCH 005/638] Refactor wxGameList color code and match previous style on light theme (#261) Refactored to pre-calculate the game list row colors at the beginning of the function. If the background color is almost white as it is on Windows, we'll use the previous bluish secondary color instead of grey-scale lightness adjustment. --- src/gui/components/wxGameList.cpp | 32 +++++++++++++------------------ 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/gui/components/wxGameList.cpp b/src/gui/components/wxGameList.cpp index 6c3c4a01..d4fbed52 100644 --- a/src/gui/components/wxGameList.cpp +++ b/src/gui/components/wxGameList.cpp @@ -269,40 +269,34 @@ long wxGameList::GetStyleFlags(Style style) const void wxGameList::UpdateItemColors(sint32 startIndex) { - wxWindowUpdateLocker lock(this); + // get the background color so we can determine the theme in use + wxColour bgColour = GetBackgroundColour(); + uint32 bgLightness = (bgColour.GetRed() + bgColour.GetGreen() + bgColour.GetBlue()) / 3; + bool isDarkTheme = bgLightness < 128; + wxColour bgColourPrimary = bgColour; // color for odd rows + wxColour bgColourSecondary = bgColour.ChangeLightness(isDarkTheme ? 110 : 90); // color for even rows - // Get the background color so we can determine the theme in use - const wxColour bgColour = GetBackgroundColour(); + // for very light themes we'll use a blue tint to match the older Windows Cemu look + if (bgLightness > 250) + bgColourSecondary = wxColour(bgColour.Red() - 13, bgColour.Green() - 6, bgColour.Blue() - 2); for (int i = startIndex; i < GetItemCount(); ++i) { const auto titleId = (uint64)GetItemData(i); - if (GetConfig().IsGameListFavorite(titleId))//entry->favorite) + if (GetConfig().IsGameListFavorite(titleId)) { SetItemBackgroundColour(i, kFavoriteColor); SetItemTextColour(i, 0x000000UL); } else if ((i&1) != 0) { - // Depending on the background RGB value: - // Light theme row color will be 10% darker (90) - // Dark theme row color will be 10% brighter (110) - int alpha = bgColour.GetRGB() > 0x808080 ? 90 : 110; - SetItemBackgroundColour(i, bgColour.ChangeLightness(alpha)); - - // Text can be changed to other values for alternating rows if needed + SetItemBackgroundColour(i, bgColourPrimary); SetItemTextColour(i, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); } else { - // Depending on the background RGB value: - // Light theme row color will be 0% darker (100) - // Dark theme row color will be 0% brighter (100) - int alpha = bgColour.GetRGB() > 0x808080 ? 100 : 100; - SetItemBackgroundColour(i, bgColour.ChangeLightness(alpha)); - - // Text color can be modified to other values for alternating rows if needed + SetItemBackgroundColour(i, bgColourSecondary); SetItemTextColour(i, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)); } } @@ -310,7 +304,7 @@ void wxGameList::UpdateItemColors(sint32 startIndex) static inline int strongorder_to_int(const std::strong_ordering &wo) { - /* No easy conversion seems to exists in C++20 */ + // no easy conversion seems to exists in C++20 if (wo < 0) return -1; else if (wo > 0) From 4a3d02db55f99a0510c61668fdd117fdc3d68c0a Mon Sep 17 00:00:00 2001 From: Maximilian Downey Twiss <64618338+Zopolis4@users.noreply.github.com> Date: Sat, 17 Sep 2022 11:24:57 +1000 Subject: [PATCH 006/638] Properly list files in CMakeLists instead of using GLOB (#249) --- src/Cafe/CMakeLists.txt | 476 +++++++++++++++++++++++++++++++++++++- src/Cemu/CMakeLists.txt | 38 ++- src/Common/CMakeLists.txt | 34 ++- src/audio/CMakeLists.txt | 2 - src/config/CMakeLists.txt | 19 +- src/gui/CMakeLists.txt | 135 ++++++++++- src/imgui/CMakeLists.txt | 10 +- src/input/CMakeLists.txt | 54 ++--- src/util/CMakeLists.txt | 78 ++++++- 9 files changed, 757 insertions(+), 89 deletions(-) diff --git a/src/Cafe/CMakeLists.txt b/src/Cafe/CMakeLists.txt index c012f18a..baf8fdb0 100644 --- a/src/Cafe/CMakeLists.txt +++ b/src/Cafe/CMakeLists.txt @@ -1,13 +1,473 @@ -project(CemuCafe) - -file(GLOB_RECURSE CPP_FILES *.cpp) -file(GLOB_RECURSE H_FILES *.h) +add_library(CemuCafe + Account/Account.cpp + Account/AccountError.h + Account/Account.h + CafeSystem.cpp + CafeSystem.h + Filesystem/fsc.cpp + Filesystem/fscDeviceHostFS.cpp + Filesystem/fscDeviceHostFS.h + Filesystem/fscDeviceRedirect.cpp + Filesystem/fscDeviceWua.cpp + Filesystem/fscDeviceWud.cpp + Filesystem/fsc.h + Filesystem/FST/FST.cpp + Filesystem/FST/FST.h + Filesystem/FST/fstUtil.h + Filesystem/FST/KeyCache.cpp + Filesystem/FST/KeyCache.h + Filesystem/WUD/wud.cpp + Filesystem/WUD/wud.h + GamePatch.cpp + GamePatch.h + GameProfile/GameProfile.cpp + GameProfile/GameProfile.h + GraphicPack/GraphicPack2.cpp + GraphicPack/GraphicPack2.h + GraphicPack/GraphicPack2PatchesApply.cpp + GraphicPack/GraphicPack2Patches.cpp + GraphicPack/GraphicPack2Patches.h + GraphicPack/GraphicPack2PatchesParser.cpp + GraphicPack/GraphicPackError.h + HW/ACR/ACR.cpp + HW/AI/AI.cpp + HW/AI/AI.h + HW/Common/HwReg.h + HW/Espresso/Const.h + HW/Espresso/Debugger/Debugger.cpp + HW/Espresso/Debugger/Debugger.h + HW/Espresso/Debugger/DebugSymbolStorage.cpp + HW/Espresso/Debugger/DebugSymbolStorage.h + HW/Espresso/EspressoISA.h + HW/Espresso/Interpreter/PPCInterpreterALU.hpp + HW/Espresso/Interpreter/PPCInterpreterFPU.cpp + HW/Espresso/Interpreter/PPCInterpreterHelper.h + HW/Espresso/Interpreter/PPCInterpreterHLE.cpp + HW/Espresso/Interpreter/PPCInterpreterImpl.cpp + HW/Espresso/Interpreter/PPCInterpreterInternal.h + HW/Espresso/Interpreter/PPCInterpreterLoadStore.hpp + HW/Espresso/Interpreter/PPCInterpreterMain.cpp + HW/Espresso/Interpreter/PPCInterpreterOPC.cpp + HW/Espresso/Interpreter/PPCInterpreterOPC.hpp + HW/Espresso/Interpreter/PPCInterpreterPS.cpp + HW/Espresso/Interpreter/PPCInterpreterSPR.hpp + HW/Espresso/PPCCallback.h + HW/Espresso/PPCScheduler.cpp + HW/Espresso/PPCSchedulerLLE.cpp + HW/Espresso/PPCState.h + HW/Espresso/PPCTimer.cpp + HW/Espresso/Recompiler/PPCFunctionBoundaryTracker.h + HW/Espresso/Recompiler/PPCRecompiler.cpp + HW/Espresso/Recompiler/PPCRecompiler.h + HW/Espresso/Recompiler/PPCRecompilerImlAnalyzer.cpp + HW/Espresso/Recompiler/PPCRecompilerImlGen.cpp + HW/Espresso/Recompiler/PPCRecompilerImlGenFPU.cpp + HW/Espresso/Recompiler/PPCRecompilerIml.h + HW/Espresso/Recompiler/PPCRecompilerImlOptimizer.cpp + HW/Espresso/Recompiler/PPCRecompilerImlRanges.cpp + HW/Espresso/Recompiler/PPCRecompilerImlRanges.h + HW/Espresso/Recompiler/PPCRecompilerImlRegisterAllocator2.cpp + HW/Espresso/Recompiler/PPCRecompilerImlRegisterAllocator.cpp + HW/Espresso/Recompiler/PPCRecompilerIntermediate.cpp + HW/Espresso/Recompiler/PPCRecompilerX64AVX.cpp + HW/Espresso/Recompiler/PPCRecompilerX64BMI.cpp + HW/Espresso/Recompiler/PPCRecompilerX64.cpp + HW/Espresso/Recompiler/PPCRecompilerX64FPU.cpp + HW/Espresso/Recompiler/PPCRecompilerX64Gen.cpp + HW/Espresso/Recompiler/PPCRecompilerX64GenFPU.cpp + HW/Espresso/Recompiler/PPCRecompilerX64.h + HW/Espresso/Recompiler/x64Emit.hpp + HW/Latte/Common/RegisterSerializer.cpp + HW/Latte/Common/RegisterSerializer.h + HW/Latte/Common/ShaderSerializer.cpp + HW/Latte/Common/ShaderSerializer.h + HW/Latte/Core/FetchShader.cpp + HW/Latte/Core/FetchShader.h + HW/Latte/Core/LatteAsyncCommands.cpp + HW/Latte/Core/LatteAsyncCommands.h + HW/Latte/Core/LatteBufferCache.cpp + HW/Latte/Core/LatteBufferCache.h + HW/Latte/Core/LatteBufferData.cpp + HW/Latte/Core/LatteCachedFBO.h + HW/Latte/Core/LatteCommandProcessor.cpp + HW/Latte/Core/LatteConst.h + HW/Latte/Core/LatteDefaultShaders.cpp + HW/Latte/Core/LatteDefaultShaders.h + HW/Latte/Core/LatteDraw.h + HW/Latte/Core/LatteGSCopyShaderParser.cpp + HW/Latte/Core/Latte.h + HW/Latte/Core/LatteIndices.cpp + HW/Latte/Core/LatteIndices.h + HW/Latte/Core/LatteOverlay.cpp + HW/Latte/Core/LatteOverlay.h + HW/Latte/Core/LattePerformanceMonitor.cpp + HW/Latte/Core/LattePerformanceMonitor.h + HW/Latte/Core/LattePM4.h + HW/Latte/Core/LatteQuery.cpp + HW/Latte/Core/LatteQueryObject.h + HW/Latte/Core/LatteRenderTarget.cpp + HW/Latte/Core/LatteRingBuffer.cpp + HW/Latte/Core/LatteRingBuffer.h + HW/Latte/Core/LatteShaderAssembly.h + HW/Latte/Core/LatteShaderCache.cpp + HW/Latte/Core/LatteShaderCache.h + HW/Latte/Core/LatteShader.cpp + HW/Latte/Core/LatteShaderGL.cpp + HW/Latte/Core/LatteShader.h + HW/Latte/Core/LatteSoftware.cpp + HW/Latte/Core/LatteSoftware.h + HW/Latte/Core/LatteStreamoutGPU.cpp + HW/Latte/Core/LatteSurfaceCopy.cpp + HW/Latte/Core/LatteTextureCache.cpp + HW/Latte/Core/LatteTexture.cpp + HW/Latte/Core/LatteTexture.h + HW/Latte/Core/LatteTextureLegacy.cpp + HW/Latte/Core/LatteTextureLoader.cpp + HW/Latte/Core/LatteTextureLoader.h + HW/Latte/Core/LatteTextureReadback.cpp + HW/Latte/Core/LatteTextureReadbackInfo.h + HW/Latte/Core/LatteTextureView.cpp + HW/Latte/Core/LatteTextureView.h + HW/Latte/Core/LatteThread.cpp + HW/Latte/Core/LatteTiming.cpp + HW/Latte/Core/LatteTiming.h + HW/Latte/ISA/LatteInstructions.h + HW/Latte/ISA/LatteReg.h + HW/Latte/ISA/RegDefines.h + HW/Latte/LatteAddrLib/AddrLibFastDecode.h + HW/Latte/LatteAddrLib/LatteAddrLib_Coord.cpp + HW/Latte/LatteAddrLib/LatteAddrLib.cpp + HW/Latte/LatteAddrLib/LatteAddrLib.h + HW/Latte/LegacyShaderDecompiler/LatteDecompilerAnalyzer.cpp + HW/Latte/LegacyShaderDecompiler/LatteDecompiler.cpp + HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSLAttrDecoder.cpp + HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSL.cpp + HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSLHeader.hpp + HW/Latte/LegacyShaderDecompiler/LatteDecompiler.h + HW/Latte/LegacyShaderDecompiler/LatteDecompilerInstructions.h + HW/Latte/LegacyShaderDecompiler/LatteDecompilerInternal.h + HW/Latte/LegacyShaderDecompiler/LatteDecompilerRegisterDataTypeTracker.cpp + HW/Latte/Renderer/OpenGL/CachedFBOGL.h + HW/Latte/Renderer/OpenGL/LatteTextureGL.cpp + HW/Latte/Renderer/OpenGL/LatteTextureGL.h + HW/Latte/Renderer/OpenGL/LatteTextureViewGL.cpp + HW/Latte/Renderer/OpenGL/LatteTextureViewGL.h + HW/Latte/Renderer/OpenGL/OpenGLQuery.cpp + HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp + HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp + HW/Latte/Renderer/OpenGL/OpenGLRenderer.h + HW/Latte/Renderer/OpenGL/OpenGLRendererStreamout.cpp + HW/Latte/Renderer/OpenGL/OpenGLRendererUniformData.cpp + HW/Latte/Renderer/OpenGL/OpenGLSurfaceCopy.cpp + HW/Latte/Renderer/OpenGL/OpenGLTextureReadback.h + HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp + HW/Latte/Renderer/OpenGL/RendererShaderGL.h + HW/Latte/Renderer/OpenGL/TextureReadbackGL.cpp + HW/Latte/Renderer/Renderer.cpp + HW/Latte/Renderer/Renderer.h + HW/Latte/Renderer/RendererOuputShader.cpp + HW/Latte/Renderer/RendererOuputShader.h + HW/Latte/Renderer/RendererShader.cpp + HW/Latte/Renderer/RendererShader.h + HW/Latte/Renderer/Vulkan/CachedFBOVk.cpp + HW/Latte/Renderer/Vulkan/CachedFBOVk.h + HW/Latte/Renderer/Vulkan/CocoaSurface.h + HW/Latte/Renderer/Vulkan/LatteTextureViewVk.cpp + HW/Latte/Renderer/Vulkan/LatteTextureViewVk.h + HW/Latte/Renderer/Vulkan/LatteTextureVk.cpp + HW/Latte/Renderer/Vulkan/LatteTextureVk.h + HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp + HW/Latte/Renderer/Vulkan/RendererShaderVk.h + HW/Latte/Renderer/Vulkan/TextureReadbackVk.cpp + HW/Latte/Renderer/Vulkan/VKRBase.h + HW/Latte/Renderer/Vulkan/VKRMemoryManager.cpp + HW/Latte/Renderer/Vulkan/VKRMemoryManager.h + HW/Latte/Renderer/Vulkan/VKRPipelineInfo.cpp + HW/Latte/Renderer/Vulkan/VsyncDriver.cpp + HW/Latte/Renderer/Vulkan/VsyncDriver.h + HW/Latte/Renderer/Vulkan/VulkanAPI.cpp + HW/Latte/Renderer/Vulkan/VulkanAPI.h + HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp + HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.h + HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp + HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h + HW/Latte/Renderer/Vulkan/VulkanQuery.cpp + HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp + HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp + HW/Latte/Renderer/Vulkan/VulkanRenderer.h + HW/Latte/Renderer/Vulkan/VulkanSurfaceCopy.cpp + HW/Latte/Renderer/Vulkan/VulkanTextureReadback.h + HW/Latte/ShaderInfo/ShaderDescription.cpp + HW/Latte/ShaderInfo/ShaderInfo.h + HW/Latte/ShaderInfo/ShaderInstanceInfo.cpp + HW/Latte/Transcompiler/LatteTC.cpp + HW/Latte/Transcompiler/LatteTCGenIR.cpp + HW/Latte/Transcompiler/LatteTC.h + HW/MMU/MMU.cpp + HW/MMU/MMU.h + HW/SI/SI.cpp + HW/SI/si.h + HW/VI/VI.cpp + IOSU/fsa/fsa_types.h + IOSU/fsa/iosu_fsa.cpp + IOSU/fsa/iosu_fsa.h + IOSU/iosu_ipc_common.h + IOSU/iosu_types_common.h + IOSU/kernel/iosu_kernel.cpp + IOSU/kernel/iosu_kernel.h + IOSU/legacy/iosu_acp.cpp + IOSU/legacy/iosu_acp.h + IOSU/legacy/iosu_act.cpp + IOSU/legacy/iosu_act.h + IOSU/legacy/iosu_boss.cpp + IOSU/legacy/iosu_boss.h + IOSU/legacy/iosu_crypto.cpp + IOSU/legacy/iosu_crypto.h + IOSU/legacy/iosu_fpd.cpp + IOSU/legacy/iosu_fpd.h + IOSU/legacy/iosu_ioctl.cpp + IOSU/legacy/iosu_ioctl.h + IOSU/legacy/iosu_mcp.cpp + IOSU/legacy/iosu_mcp.h + IOSU/legacy/iosu_nim.cpp + IOSU/legacy/iosu_nim.h + IOSU/nn/iosu_nn_service.cpp + IOSU/nn/iosu_nn_service.h + IOSU/PDM/iosu_pdm.cpp + IOSU/PDM/iosu_pdm.h + OS/common/OSCommon.cpp + OS/common/OSCommon.h + OS/common/OSUtil.h + OS/common/PPCConcurrentQueue.h + OS/libs/avm/avm.cpp + OS/libs/avm/avm.h + OS/libs/camera/camera.cpp + OS/libs/camera/camera.h + OS/libs/coreinit/coreinit_Alarm.cpp + OS/libs/coreinit/coreinit_Alarm.h + OS/libs/coreinit/coreinit_Atomic.cpp + OS/libs/coreinit/coreinit_Atomic.h + OS/libs/coreinit/coreinit_BSP.cpp + OS/libs/coreinit/coreinit_BSP.h + OS/libs/coreinit/coreinit_Callbacks.cpp + OS/libs/coreinit/coreinit_CodeGen.cpp + OS/libs/coreinit/coreinit_CodeGen.h + OS/libs/coreinit/coreinit_Coroutine.cpp + OS/libs/coreinit/coreinit_Coroutine.h + OS/libs/coreinit/coreinit.cpp + OS/libs/coreinit/coreinit_DynLoad.cpp + OS/libs/coreinit/coreinit_DynLoad.h + OS/libs/coreinit/coreinit_FG.cpp + OS/libs/coreinit/coreinit_FG.h + OS/libs/coreinit/coreinit_FS.cpp + OS/libs/coreinit/coreinit_FS.h + OS/libs/coreinit/coreinit_GHS.cpp + OS/libs/coreinit/coreinit_GHS.h + OS/libs/coreinit/coreinit.h + OS/libs/coreinit/coreinit_HWInterface.cpp + OS/libs/coreinit/coreinit_HWInterface.h + OS/libs/coreinit/coreinit_IM.cpp + OS/libs/coreinit/coreinit_IM.h + OS/libs/coreinit/coreinit_Init.cpp + OS/libs/coreinit/coreinit_IOS.cpp + OS/libs/coreinit/coreinit_IOS.h + OS/libs/coreinit/coreinit_IPCBuf.cpp + OS/libs/coreinit/coreinit_IPCBuf.h + OS/libs/coreinit/coreinit_IPC.cpp + OS/libs/coreinit/coreinit_IPC.h + OS/libs/coreinit/coreinit_LockedCache.cpp + OS/libs/coreinit/coreinit_LockedCache.h + OS/libs/coreinit/coreinit_MCP.cpp + OS/libs/coreinit/coreinit_MCP.h + OS/libs/coreinit/coreinit_MEM_BlockHeap.cpp + OS/libs/coreinit/coreinit_MEM_BlockHeap.h + OS/libs/coreinit/coreinit_MEM.cpp + OS/libs/coreinit/coreinit_MEM_ExpHeap.cpp + OS/libs/coreinit/coreinit_MEM_ExpHeap.h + OS/libs/coreinit/coreinit_MEM_FrmHeap.cpp + OS/libs/coreinit/coreinit_MEM_FrmHeap.h + OS/libs/coreinit/coreinit_MEM.h + OS/libs/coreinit/coreinit_Memory.cpp + OS/libs/coreinit/coreinit_Memory.h + OS/libs/coreinit/coreinit_MemoryMapping.cpp + OS/libs/coreinit/coreinit_MemoryMapping.h + OS/libs/coreinit/coreinit_MEM_UnitHeap.cpp + OS/libs/coreinit/coreinit_MEM_UnitHeap.h + OS/libs/coreinit/coreinit_MessageQueue.cpp + OS/libs/coreinit/coreinit_MessageQueue.h + OS/libs/coreinit/coreinit_Misc.cpp + OS/libs/coreinit/coreinit_Misc.h + OS/libs/coreinit/coreinit_MPQueue.cpp + OS/libs/coreinit/coreinit_MPQueue.h + OS/libs/coreinit/coreinit_OSScreen.cpp + OS/libs/coreinit/coreinit_OSScreen_font.h + OS/libs/coreinit/coreinit_OSScreen.h + OS/libs/coreinit/coreinit_OverlayArena.cpp + OS/libs/coreinit/coreinit_OverlayArena.h + OS/libs/coreinit/coreinit_Scheduler.cpp + OS/libs/coreinit/coreinit_Scheduler.h + OS/libs/coreinit/coreinit_Spinlock.cpp + OS/libs/coreinit/coreinit_Spinlock.h + OS/libs/coreinit/coreinit_Synchronization.cpp + OS/libs/coreinit/coreinit_SysHeap.cpp + OS/libs/coreinit/coreinit_SysHeap.h + OS/libs/coreinit/coreinit_SystemInfo.cpp + OS/libs/coreinit/coreinit_SystemInfo.h + OS/libs/coreinit/coreinit_Thread.cpp + OS/libs/coreinit/coreinit_Thread.h + OS/libs/coreinit/coreinit_ThreadQueue.cpp + OS/libs/coreinit/coreinit_Time.cpp + OS/libs/coreinit/coreinit_Time.h + OS/libs/dmae/dmae.cpp + OS/libs/dmae/dmae.h + OS/libs/drmapp/drmapp.cpp + OS/libs/drmapp/drmapp.h + OS/libs/erreula/erreula.cpp + OS/libs/erreula/erreula.h + OS/libs/gx2/GX2_AddrTest.cpp + OS/libs/gx2/GX2_Blit.cpp + OS/libs/gx2/GX2_Blit.h + OS/libs/gx2/GX2_Command.cpp + OS/libs/gx2/GX2_Command.h + OS/libs/gx2/GX2_ContextState.cpp + OS/libs/gx2/GX2.cpp + OS/libs/gx2/GX2_Draw.cpp + OS/libs/gx2/GX2_Draw.h + OS/libs/gx2/GX2_Event.cpp + OS/libs/gx2/GX2_Event.h + OS/libs/gx2/GX2.h + OS/libs/gx2/GX2_Memory.cpp + OS/libs/gx2/GX2_Memory.h + OS/libs/gx2/GX2_Misc.cpp + OS/libs/gx2/GX2_Misc.h + OS/libs/gx2/GX2_Query.cpp + OS/libs/gx2/GX2_Query.h + OS/libs/gx2/GX2_RenderTarget.cpp + OS/libs/gx2/GX2_Resource.cpp + OS/libs/gx2/GX2_Resource.h + OS/libs/gx2/GX2_Shader.cpp + OS/libs/gx2/GX2_Shader.h + OS/libs/gx2/GX2_shader_legacy.cpp + OS/libs/gx2/GX2_State.cpp + OS/libs/gx2/GX2_State.h + OS/libs/gx2/GX2_Streamout.cpp + OS/libs/gx2/GX2_Streamout.h + OS/libs/gx2/GX2_Surface_Copy.cpp + OS/libs/gx2/GX2_Surface_Copy.h + OS/libs/gx2/GX2_Surface.cpp + OS/libs/gx2/GX2_Surface.h + OS/libs/gx2/GX2_Texture.cpp + OS/libs/gx2/GX2_Texture.h + OS/libs/gx2/GX2_TilingAperture.cpp + OS/libs/h264_avc/H264Dec.cpp + OS/libs/h264_avc/h264dec.h + OS/libs/h264_avc/parser + OS/libs/h264_avc/parser/H264Parser.cpp + OS/libs/h264_avc/parser/H264Parser.h + OS/libs/mic/mic.cpp + OS/libs/mic/mic.h + OS/libs/nlibcurl/nlibcurl.cpp + OS/libs/nlibcurl/nlibcurlDebug.hpp + OS/libs/nlibcurl/nlibcurl.h + OS/libs/nlibnss/nlibnss.cpp + OS/libs/nlibnss/nlibnss.h + OS/libs/nn_ac/nn_ac.cpp + OS/libs/nn_ac/nn_ac.h + OS/libs/nn_acp/nn_acp.cpp + OS/libs/nn_acp/nn_acp.h + OS/libs/nn_act/nn_act.cpp + OS/libs/nn_act/nn_act.h + OS/libs/nn_aoc/nn_aoc.cpp + OS/libs/nn_aoc/nn_aoc.h + OS/libs/nn_boss/nn_boss.cpp + OS/libs/nn_boss/nn_boss.h + OS/libs/nn_ccr/nn_ccr.cpp + OS/libs/nn_ccr/nn_ccr.h + OS/libs/nn_cmpt/nn_cmpt.cpp + OS/libs/nn_cmpt/nn_cmpt.h + OS/libs/nn_common.h + OS/libs/nn_ec/nn_ec.cpp + OS/libs/nn_ec/nn_ec.h + OS/libs/nn_fp/nn_fp.cpp + OS/libs/nn_fp/nn_fp.h + OS/libs/nn_idbe/nn_idbe.cpp + OS/libs/nn_idbe/nn_idbe.h + OS/libs/nn_ndm/nn_ndm.cpp + OS/libs/nn_ndm/nn_ndm.h + OS/libs/nn_nfp/AmiiboCrypto.h + OS/libs/nn_nfp/nn_nfp.cpp + OS/libs/nn_nfp/nn_nfp.h + OS/libs/nn_nim/nn_nim.cpp + OS/libs/nn_nim/nn_nim.h + OS/libs/nn_olv/nn_olv.cpp + OS/libs/nn_olv/nn_olv.h + OS/libs/nn_pdm/nn_pdm.cpp + OS/libs/nn_pdm/nn_pdm.h + OS/libs/nn_save/nn_save.cpp + OS/libs/nn_save/nn_save.h + OS/libs/nn_temp/nn_temp.cpp + OS/libs/nn_temp/nn_temp.h + OS/libs/nn_uds/nn_uds.cpp + OS/libs/nn_uds/nn_uds.h + OS/libs/nsyshid/nsyshid.cpp + OS/libs/nsyshid/nsyshid.h + OS/libs/nsyskbd/nsyskbd.cpp + OS/libs/nsyskbd/nsyskbd.h + OS/libs/nsysnet/nsysnet.cpp + OS/libs/nsysnet/nsysnet.h + OS/libs/padscore/padscore.cpp + OS/libs/padscore/padscore.h + OS/libs/proc_ui/proc_ui.cpp + OS/libs/proc_ui/proc_ui.h + OS/libs/snd_core/ax_aux.cpp + OS/libs/snd_core/ax_exports.cpp + OS/libs/snd_core/ax.h + OS/libs/snd_core/ax_internal.h + OS/libs/snd_core/ax_ist.cpp + OS/libs/snd_core/ax_mix.cpp + OS/libs/snd_core/ax_multivoice.cpp + OS/libs/snd_core/ax_out.cpp + OS/libs/snd_core/ax_voice.cpp + OS/libs/snd_user/snd_user.cpp + OS/libs/snd_user/snd_user.h + OS/libs/swkbd/swkbd.cpp + OS/libs/swkbd/swkbd.h + OS/libs/sysapp/sysapp.cpp + OS/libs/sysapp/sysapp.h + OS/libs/TCL/TCL.cpp + OS/libs/TCL/TCL.h + OS/libs/vpad/vpad.cpp + OS/libs/vpad/vpad.h + OS/libs/zlib125 + OS/libs/zlib125/zlib125.cpp + OS/libs/zlib125/zlib125.h + OS/RPL/elf.cpp + OS/RPL/rpl.cpp + OS/RPL/rpl_debug_symbols.cpp + OS/RPL/rpl_debug_symbols.h + OS/RPL/rpl.h + OS/RPL/rpl_structs.h + OS/RPL/rpl_symbol_storage.cpp + OS/RPL/rpl_symbol_storage.h + TitleList/BaseInfo.cpp + TitleList/BaseInfo.h + TitleList/GameInfo.h + TitleList/MetaInfo.cpp + TitleList/MetaInfo.h + TitleList/ParsedMetaXml.h + TitleList/SaveInfo.cpp + TitleList/SaveInfo.h + TitleList/SaveList.cpp + TitleList/SaveList.h + TitleList/TitleId.h + TitleList/TitleInfo.cpp + TitleList/TitleInfo.h + TitleList/TitleList.cpp + TitleList/TitleList.h +) if(APPLE) - file(GLOB_RECURSE MM_FILES *.mm) - add_library(CemuCafe ${CPP_FILES} ${MM_FILES} ${H_FILES}) -else() - add_library(CemuCafe ${CPP_FILES} ${H_FILES}) + target_sources(CemuCafe"HW/Latte/Renderer/Vulkan/CocoaSurface.mm") endif() set_property(TARGET CemuCafe PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") diff --git a/src/Cemu/CMakeLists.txt b/src/Cemu/CMakeLists.txt index df0ff1d1..1fce8ec1 100644 --- a/src/Cemu/CMakeLists.txt +++ b/src/Cemu/CMakeLists.txt @@ -1,8 +1,36 @@ -project(CemuComponents) - -file(GLOB_RECURSE CPP_FILES *.cpp) -file(GLOB_RECURSE H_FILES *.h) -add_library(CemuComponents ${CPP_FILES} ${H_FILES}) +add_library(CemuComponents + DiscordPresence/DiscordPresence.cpp + DiscordPresence/DiscordPresence.h + ExpressionParser/ExpressionParser.cpp + ExpressionParser/ExpressionParser.h + FileCache/FileCache.cpp + FileCache/FileCache.h + Logging/CemuDebugLogging.h + Logging/CemuLogging.cpp + Logging/CemuLogging.h + napi/napi_act.cpp + napi/napi_ec.cpp + napi/napi.h + napi/napi_helper.cpp + napi/napi_helper.h + napi/napi_idbe.cpp + napi/napi_version.cpp + ncrypto/ncrypto.cpp + ncrypto/ncrypto.h + nex/nex.cpp + nex/nexFriends.cpp + nex/nexFriends.h + nex/nex.h + nex/nexThread.cpp + nex/nexThread.h + nex/nexTypes.h + nex/prudp.cpp + nex/prudp.h + PPCAssembler/ppcAssembler.cpp + PPCAssembler/ppcAssembler.h + Tools/DownloadManager/DownloadManager.cpp + Tools/DownloadManager/DownloadManager.h +) set_property(TARGET CemuComponents PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index f1654f31..ca7ea238 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -1,8 +1,25 @@ -project(CemuCommon) - -file(GLOB CPP_FILES *.cpp) -file(GLOB H_FILES *.h) -add_library(CemuCommon ${CPP_FILES} ${H_FILES}) +add_library(CemuCommon + betype.h + enumFlags.h + ExceptionHandler/ExceptionHandler.h + FileStream.h + GLInclude/glext.h + GLInclude/glFunctions.h + GLInclude/GLInclude.h + GLInclude/glxext.h + GLInclude/khrplatform.h + GLInclude/wglext.h + MemPtr.h + platform.h + precompiled.cpp + precompiled.h + socket.h + StackAllocator.h + SysAllocator.cpp + SysAllocator.h + version.h + zstring_view.h +) set_property(TARGET CemuCommon PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") @@ -16,17 +33,16 @@ if(WIN32) else() target_sources(CemuCommon PRIVATE + unix/date.h + unix/fast_float.h unix/platform.cpp unix/platform.h unix/FileStream_unix.cpp + unix/FileStream_unix.h ExceptionHandler/ExceptionHandler_posix.cpp ) endif() -target_sources(CemuCommon PRIVATE - ExceptionHandler/ExceptionHandler.h -) - # All the targets wanting to use the precompiled.h header # have to link to CemuCommon target_precompile_headers(CemuCommon PUBLIC precompiled.h) diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt index d27273e6..d0040185 100644 --- a/src/audio/CMakeLists.txt +++ b/src/audio/CMakeLists.txt @@ -1,5 +1,3 @@ -project(CemuAudio) - add_library(CemuAudio IAudioAPI.cpp IAudioAPI.h diff --git a/src/config/CMakeLists.txt b/src/config/CMakeLists.txt index 58008e46..c329d58b 100644 --- a/src/config/CMakeLists.txt +++ b/src/config/CMakeLists.txt @@ -1,8 +1,17 @@ -project(CemuConfig) - -file(GLOB CPP_FILES *.cpp) -file(GLOB H_FILES *.h) -add_library(CemuConfig ${CPP_FILES} ${H_FILES}) +add_library(CemuConfig + ActiveSettings.cpp + ActiveSettings.h + CemuConfig.cpp + CemuConfig.h + ConfigValue.h + LaunchSettings.cpp + LaunchSettings.h + PermanentConfig.cpp + PermanentConfig.h + PermanentStorage.cpp + PermanentStorage.h + XMLConfig.h +) set_property(TARGET CemuConfig PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index b63135f9..0a2ecc7b 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -1,17 +1,130 @@ -project(CemuGui) - -file(GLOB_RECURSE CPP_FILES *.cpp) -file(GLOB_RECURSE H_FILES *.h) -add_library(CemuGui ${CPP_FILES} ${H_FILES}) +add_library(CemuGui + canvas/IRenderCanvas.h + canvas/OpenGLCanvas.cpp + canvas/OpenGLCanvas.h + canvas/VulkanCanvas.cpp + canvas/VulkanCanvas.h + CemuApp.cpp + CemuApp.h + CemuUpdateWindow.cpp + CemuUpdateWindow.h + ChecksumTool.cpp + ChecksumTool.h + components/TextList.cpp + components/TextList.h + components/wxDownloadManagerList.cpp + components/wxDownloadManagerList.h + components/wxGameList.cpp + components/wxGameList.h + components/wxInputDraw.cpp + components/wxInputDraw.h + components/wxLogCtrl.cpp + components/wxLogCtrl.h + components/wxTitleManagerList.cpp + components/wxTitleManagerList.h + debugger/BreakpointWindow.cpp + debugger/BreakpointWindow.h + debugger/DebuggerWindow2.cpp + debugger/DebuggerWindow2.h + debugger/DisasmCtrl.cpp + debugger/DisasmCtrl.h + debugger/DumpCtrl.cpp + debugger/DumpCtrl.h + debugger/DumpWindow.cpp + debugger/DumpWindow.h + debugger/ModuleWindow.cpp + debugger/ModuleWindow.h + debugger/RegisterCtrl.cpp + debugger/RegisterCtrl.h + debugger/RegisterWindow.cpp + debugger/RegisterWindow.h + debugger/SymbolCtrl.cpp + debugger/SymbolCtrl.h + debugger/SymbolWindow.cpp + debugger/SymbolWindow.h + dialogs/CreateAccount/wxCreateAccountDialog.cpp + dialogs/CreateAccount/wxCreateAccountDialog.h + dialogs/SaveImport/SaveImportWindow.cpp + dialogs/SaveImport/SaveImportWindow.h + dialogs/SaveImport/SaveTransfer.cpp + dialogs/SaveImport/SaveTransfer.h + DownloadGraphicPacksWindow.cpp + DownloadGraphicPacksWindow.h + GameProfileWindow.cpp + GameProfileWindow.h + GameUpdateWindow.cpp + GameUpdateWindow.h + GeneralSettings2.cpp + GeneralSettings2.h + GettingStartedDialog.cpp + GettingStartedDialog.h + GraphicPacksWindow2.cpp + GraphicPacksWindow2.h + guiWrapper.cpp + guiWrapper.h + helpers/wxControlObject.h + helpers/wxCustomData.h + helpers/wxCustomEvents.cpp + helpers/wxCustomEvents.h + helpers/wxHelpers.cpp + helpers/wxHelpers.h + helpers/wxLogEvent.h + input/InputAPIAddWindow.cpp + input/InputAPIAddWindow.h + input/InputSettings2.cpp + input/InputSettings2.h + input/panels/ClassicControllerInputPanel.cpp + input/panels/ClassicControllerInputPanel.h + input/panels/InputPanel.cpp + input/panels/InputPanel.h + input/panels/ProControllerInputPanel.cpp + input/panels/ProControllerInputPanel.h + input/panels/VPADInputPanel.cpp + input/panels/VPADInputPanel.h + input/panels/WiimoteInputPanel.cpp + input/panels/WiimoteInputPanel.h + input/settings/DefaultControllerSettings.cpp + input/settings/DefaultControllerSettings.h + input/settings/WiimoteControllerSettings.cpp + input/settings/WiimoteControllerSettings.h + LoggingWindow.cpp + LoggingWindow.h + MainWindow.cpp + MainWindow.h + MemorySearcherTool.cpp + MemorySearcherTool.h + PadViewFrame.cpp + PadViewFrame.h + TitleManager.cpp + TitleManager.h + windows/PPCThreadsViewer + windows/PPCThreadsViewer/DebugPPCThreadsWindow.cpp + windows/PPCThreadsViewer/DebugPPCThreadsWindow.h + windows/TextureRelationViewer + windows/TextureRelationViewer/TextureRelationWindow.cpp + windows/TextureRelationViewer/TextureRelationWindow.h + wxcomponents/checked2.xpm + wxcomponents/checked_dis.xpm + wxcomponents/checked_d.xpm + wxcomponents/checked_ld.xpm + wxcomponents/checkedlistctrl.cpp + wxcomponents/checkedlistctrl.h + wxcomponents/checked_mo.xpm + wxcomponents/checked.xpm + wxcomponents/checktree.cpp + wxcomponents/checktree.h + wxcomponents/unchecked2.xpm + wxcomponents/unchecked_dis.xpm + wxcomponents/unchecked_d.xpm + wxcomponents/unchecked_ld.xpm + wxcomponents/unchecked_mo.xpm + wxcomponents/unchecked.xpm + wxgui.h + wxHelper.h +) set_property(TARGET CemuGui PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") -target_sources(CemuGui PRIVATE - wxcomponents/checkedlistctrl.cpp - wxcomponents/checkedlistctrl.h - wxcomponents/checktree.cpp - wxcomponents/checktree.h -) target_include_directories(CemuGui PUBLIC "../") # PUBLIC because rapidjson/document.h is included in ChecksumTool.h diff --git a/src/imgui/CMakeLists.txt b/src/imgui/CMakeLists.txt index 412330ec..97b56455 100644 --- a/src/imgui/CMakeLists.txt +++ b/src/imgui/CMakeLists.txt @@ -1,10 +1,4 @@ -project(imguiImpl) - -add_library(imguiImpl) - -set_property(TARGET imguiImpl PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") - -target_sources(imguiImpl PRIVATE +add_library(imguiImpl imgui_impl_opengl3.cpp imgui_impl_opengl3.h imgui_impl_vulkan.cpp @@ -13,6 +7,8 @@ target_sources(imguiImpl PRIVATE imgui_extension.h ) +set_property(TARGET imguiImpl PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + target_include_directories(imguiImpl PUBLIC "../") target_link_libraries(imguiImpl PRIVATE diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index 47609385..ecb88cd2 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -1,5 +1,3 @@ -project(CemuInput) - add_library(CemuInput InputManager.cpp InputManager.h @@ -11,6 +9,24 @@ add_library(CemuInput api/ControllerState.cpp api/InputAPI.h api/ControllerProvider.h + api/DSU/DSUController.h + api/DSU/DSUControllerProvider.cpp + api/DSU/DSUController.cpp + api/DSU/DSUControllerProvider.h + api/DSU/DSUMessages.h + api/DSU/DSUMessages.cpp + api/SDL/SDLController.cpp + api/SDL/SDLControllerProvider.cpp + api/SDL/SDLController.h + api/SDL/SDLControllerProvider.h + api/Keyboard/KeyboardControllerProvider.h + api/Keyboard/KeyboardControllerProvider.cpp + api/Keyboard/KeyboardController.cpp + api/Keyboard/KeyboardController.h + api/GameCube/GameCubeController.cpp + api/GameCube/GameCubeControllerProvider.h + api/GameCube/GameCubeControllerProvider.cpp + api/GameCube/GameCubeController.h emulated/ProController.cpp emulated/EmulatedController.h emulated/EmulatedController.cpp @@ -27,40 +43,6 @@ add_library(CemuInput set_property(TARGET CemuInput PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") -# SDL -target_sources(CemuInput PRIVATE - api/SDL/SDLController.cpp - api/SDL/SDLControllerProvider.cpp - api/SDL/SDLController.h - api/SDL/SDLControllerProvider.h -) - -# DSU -target_sources(CemuInput PRIVATE - api/DSU/DSUController.h - api/DSU/DSUControllerProvider.cpp - api/DSU/DSUController.cpp - api/DSU/DSUControllerProvider.h - api/DSU/DSUMessages.h - api/DSU/DSUMessages.cpp -) - -# Keyboard controller -target_sources(CemuInput PRIVATE - api/Keyboard/KeyboardControllerProvider.h - api/Keyboard/KeyboardControllerProvider.cpp - api/Keyboard/KeyboardController.cpp - api/Keyboard/KeyboardController.h -) - -# Native gamecube -target_sources(CemuInput PRIVATE - api/GameCube/GameCubeController.cpp - api/GameCube/GameCubeControllerProvider.h - api/GameCube/GameCubeControllerProvider.cpp - api/GameCube/GameCubeController.h -) - if(WIN32) # Native wiimote (Win32 only for now) target_sources(CemuInput PRIVATE diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 090b2bd1..06c8f857 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -1,9 +1,75 @@ -project(CemuUtil) - -file(GLOB_RECURSE CPP_FILES *.cpp) -file(GLOB_RECURSE H_FILES *.h) - -add_library(CemuUtil ${CPP_FILES} ${H_FILES}) +add_library(CemuUtil + boost/bluetooth.h + ChunkedHeap/ChunkedHeap.h + containers/flat_hash_map.hpp + containers/IntervalBucketContainer.h + containers/LookupTableL3.h + containers/RangeStore.h + containers/robin_hood.h + containers/SmallBitset.h + crypto/aes128.cpp + crypto/aes128.h + crypto/crc32.cpp + crypto/crc32.h + crypto/md5.cpp + crypto/md5.h + DXGIWrapper/DXGIWrapper.h + EventService.h + Fiber/Fiber.h + Fiber/FiberUnix.cpp + Fiber/FiberWin.cpp + helpers/ClassWrapper.h + helpers/ConcurrentQueue.h + helpers/enum_array.hpp + helpers/fixedSizeList.h + helpers/fspinlock.h + helpers/helpers.cpp + helpers/helpers.h + helpers/MapAdaptor.h + helpers/MemoryPool.h + helpers/ringbuffer.h + helpers/Semaphore.h + helpers/Serializer.cpp + helpers/Serializer.h + helpers/Singleton.h + helpers/StringBuf.h + helpers/StringHelpers.h + helpers/StringParser.h + helpers/SystemException.h + helpers/TempState.h + highresolutiontimer/HighResolutionTimer.cpp + highresolutiontimer/HighResolutionTimer.h + ImageWriter/bmp.h + ImageWriter/tga.h + IniParser/IniParser.cpp + IniParser/IniParser.h + libusbWrapper/libusbWrapper.cpp + libusbWrapper/libusbWrapper.h + math/glm.h + math/quaternion.h + math/vector2.h + math/vector3.h + MemMapper/MemMapper.h + MemMapper/MemMapperUnix.cpp + MemMapper/MemMapperWin.cpp + ThreadPool/ThreadPool.cpp + ThreadPool/ThreadPool.h + tinyxml2/tinyxml2.cpp + tinyxml2/tinyxml2.h + VirtualHeap/VirtualHeap.cpp + VirtualHeap/VirtualHeap.h + Zir/Core/IR.cpp + Zir/Core/IR.h + Zir/Core/ZirUtility.h + Zir/Core/ZpIRBuilder.h + Zir/Core/ZpIRDebug.h + Zir/Core/ZpIRPasses.h + Zir/Core/ZpIRScheduler.h + Zir/EmitterGLSL/ZpIREmitGLSL.cpp + Zir/EmitterGLSL/ZpIREmitGLSL.h + Zir/Passes/RegisterAllocatorForGLSL.cpp + Zir/Passes/ZpIRRegisterAllocator.cpp +) set_property(TARGET CemuUtil PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") From 03f5967408b60979745d2b79ba572ffb61c052fa Mon Sep 17 00:00:00 2001 From: Herman Semenov Date: Sat, 17 Sep 2022 04:45:18 +0300 Subject: [PATCH 007/638] Fix incorrect streamout buffer index in GS + refactor various code (#258) --- src/Cafe/CafeSystem.cpp | 2 +- src/Cafe/Filesystem/fsc.cpp | 2 +- src/Cafe/GraphicPack/GraphicPack2.cpp | 6 +++--- src/Cafe/HW/Espresso/EspressoISA.h | 2 +- .../Recompiler/PPCFunctionBoundaryTracker.h | 2 +- src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.h | 2 +- src/Cafe/HW/Latte/Core/LatteBufferCache.cpp | 2 +- .../HW/Latte/Core/LatteGSCopyShaderParser.cpp | 2 +- src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp | 5 +++-- src/Cafe/HW/Latte/Core/LatteShaderCache.cpp | 6 +++--- .../Vulkan/VulkanPipelineStableCache.cpp | 4 ++++ .../Renderer/Vulkan/VulkanPipelineStableCache.h | 2 +- src/Cafe/OS/RPL/rpl.cpp | 3 ++- src/Cafe/OS/common/PPCConcurrentQueue.h | 2 +- src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp | 6 ++---- src/Cafe/OS/libs/h264_avc/H264Dec.cpp | 7 +++++-- src/Cafe/TitleList/MetaInfo.cpp | 1 - src/Cafe/TitleList/TitleInfo.cpp | 1 - src/Cafe/TitleList/TitleList.cpp | 6 +++--- src/Cemu/FileCache/FileCache.cpp | 3 +++ .../Tools/DownloadManager/DownloadManager.cpp | 3 +-- .../Tools/DownloadManager/DownloadManager.h | 2 +- src/Cemu/napi/napi_act.cpp | 1 - src/Cemu/napi/napi_ec.cpp | 2 +- src/Cemu/nex/nex.cpp | 2 +- src/Cemu/nex/nexFriends.h | 17 ++++------------- src/Cemu/nex/nexTypes.h | 2 +- src/Common/windows/FileStream_win32.h | 2 +- src/config/CemuConfig.cpp | 2 +- src/gui/GameProfileWindow.cpp | 1 - src/gui/GameUpdateWindow.cpp | 1 - src/gui/GeneralSettings2.cpp | 4 ++-- src/gui/components/wxTitleManagerList.cpp | 4 ++-- src/gui/debugger/DumpCtrl.cpp | 2 +- src/gui/debugger/SymbolCtrl.cpp | 6 +++--- src/gui/debugger/SymbolCtrl.h | 2 +- src/gui/input/InputSettings2.cpp | 2 -- src/input/api/Controller.h | 2 +- src/input/motion/MotionSample.h | 4 +--- src/util/Zir/Core/IR.h | 6 +++--- src/util/Zir/EmitterGLSL/ZpIREmitGLSL.cpp | 4 +--- src/util/containers/IntervalBucketContainer.h | 2 +- src/util/containers/RangeStore.h | 5 +---- src/util/containers/SmallBitset.h | 2 +- src/util/containers/flat_hash_map.hpp | 16 ++++------------ 45 files changed, 70 insertions(+), 92 deletions(-) diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index 8ec6ff0a..2cadc106 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -577,7 +577,7 @@ namespace CafeSystem const auto file = fsc_open(rpxPath.c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &status); if (file) { - _pathToExecutable = rpxPath; + _pathToExecutable = std::move(rpxPath); fsc_close(file); } } diff --git a/src/Cafe/Filesystem/fsc.cpp b/src/Cafe/Filesystem/fsc.cpp index d7d9971f..71bae60e 100644 --- a/src/Cafe/Filesystem/fsc.cpp +++ b/src/Cafe/Filesystem/fsc.cpp @@ -143,7 +143,7 @@ sint32 fsc_mount(std::string_view mountPath, std::string_view targetPath, fscDev } node->device = fscDevice; node->ctx = ctx; - node->deviceTargetPath = targetPathWithSlash; + node->deviceTargetPath = std::move(targetPathWithSlash); fscLeave(); return FSC_STATUS_OK; } diff --git a/src/Cafe/GraphicPack/GraphicPack2.cpp b/src/Cafe/GraphicPack/GraphicPack2.cpp index 808536d5..959441d7 100644 --- a/src/Cafe/GraphicPack/GraphicPack2.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2.cpp @@ -1020,9 +1020,9 @@ bool GraphicPack2::Deactivate() m_upscaling_shader_ud.reset(); m_downscaling_shader_ud.reset(); - m_output_shader_source = ""; - m_upscaling_shader_source = ""; - m_downscaling_shader_source = ""; + m_output_shader_source.clear(); + m_upscaling_shader_source.clear(); + m_downscaling_shader_source.clear(); if (HasCustomVSyncFrequency()) { diff --git a/src/Cafe/HW/Espresso/EspressoISA.h b/src/Cafe/HW/Espresso/EspressoISA.h index 4c630e4c..b3ae45c3 100644 --- a/src/Cafe/HW/Espresso/EspressoISA.h +++ b/src/Cafe/HW/Espresso/EspressoISA.h @@ -101,7 +101,7 @@ namespace Espresso struct BOField { - BOField() {}; + BOField() = default; BOField(uint8 bo) : bo(bo) {}; bool conditionInverted() const diff --git a/src/Cafe/HW/Espresso/Recompiler/PPCFunctionBoundaryTracker.h b/src/Cafe/HW/Espresso/Recompiler/PPCFunctionBoundaryTracker.h index 3fc48a93..48782454 100644 --- a/src/Cafe/HW/Espresso/Recompiler/PPCFunctionBoundaryTracker.h +++ b/src/Cafe/HW/Espresso/Recompiler/PPCFunctionBoundaryTracker.h @@ -10,7 +10,7 @@ class PPCFunctionBoundaryTracker public: struct PPCRange_t { - PPCRange_t() {}; + PPCRange_t() = default; PPCRange_t(uint32 _startAddress) : startAddress(_startAddress) {}; uint32 startAddress{}; diff --git a/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.h b/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.h index ee0454ce..82fa15e6 100644 --- a/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.h +++ b/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.h @@ -197,7 +197,7 @@ struct raLivenessLocation_t bool isRead; bool isWrite; - raLivenessLocation_t() {}; + raLivenessLocation_t() = default; raLivenessLocation_t(sint32 index, bool isRead, bool isWrite) : index(index), isRead(isRead), isWrite(isWrite) {}; diff --git a/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp b/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp index b74f67b9..426568a8 100644 --- a/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp @@ -29,7 +29,7 @@ class IntervalTree2 struct InternalRange { - InternalRange() {}; + InternalRange() = default; InternalRange(TRangeData _rangeBegin, TRangeData _rangeEnd) : rangeBegin(_rangeBegin), rangeEnd(_rangeEnd) { cemu_assert_debug(_rangeBegin < _rangeEnd); }; TRangeData rangeBegin; diff --git a/src/Cafe/HW/Latte/Core/LatteGSCopyShaderParser.cpp b/src/Cafe/HW/Latte/Core/LatteGSCopyShaderParser.cpp index 7df5eecd..1c0752f1 100644 --- a/src/Cafe/HW/Latte/Core/LatteGSCopyShaderParser.cpp +++ b/src/Cafe/HW/Latte/Core/LatteGSCopyShaderParser.cpp @@ -208,7 +208,7 @@ LatteParsedGSCopyShader* LatteGSCopyShaderParser_parse(uint8* programData, uint3 uint32 bufferIndex; if (cf_inst23_7 == GPU7_CF_INST_MEM_STREAM0_WRITE) bufferIndex = 0; - else if (cf_inst23_7 == GPU7_CF_INST_MEM_STREAM0_WRITE) + else if (cf_inst23_7 == GPU7_CF_INST_MEM_STREAM1_WRITE) bufferIndex = 1; else cemu_assert_debug(false); diff --git a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp index 416245b9..11048504 100644 --- a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp +++ b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp @@ -493,17 +493,18 @@ bool LatteMRT::UpdateCurrentFBO() sint32 colorAttachmentWidth; sint32 colorAttachmentHeight; + LatteTexture_getSize(colorAttachmentView->baseTexture, &colorAttachmentWidth, &colorAttachmentHeight, nullptr, colorAttachmentView->firstMip); // set effective size sint32 effectiveWidth, effectiveHeight; LatteTexture_getEffectiveSize(colorAttachmentView->baseTexture, &effectiveWidth, &effectiveHeight, nullptr, colorAttachmentView->firstMip); - if( rtEffectiveSize->width == 0 && rtEffectiveSize->height == 0 ) + if (rtEffectiveSize->width == 0 && rtEffectiveSize->height == 0) { rtEffectiveSize->width = effectiveWidth; rtEffectiveSize->height = effectiveHeight; } - else if( rtEffectiveSize->width != effectiveWidth && rtEffectiveSize->height != effectiveHeight ) + else if (rtEffectiveSize->width != effectiveWidth && rtEffectiveSize->height != effectiveHeight) { #ifndef PUBLIC_RELEASE forceLog_printf("Color buffer size mismatch (%dx%d). Effective size: %dx%d Real size: %dx%d Mismatching texture: %08x %dx%d fmt %04x", rtEffectiveSize->width, rtEffectiveSize->height, effectiveWidth, effectiveHeight, colorAttachmentView->baseTexture->width, colorAttachmentView->baseTexture->height, colorAttachmentView->baseTexture->physAddress, colorAttachmentView->baseTexture->width, colorAttachmentView->baseTexture->height, (uint32)colorAttachmentView->baseTexture->format); diff --git a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp index ebf425bc..e39d0e86 100644 --- a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp @@ -609,7 +609,7 @@ void LatteShaderCache_loadOrCompileSeparableShader(LatteDecompilerShader* shader bool LatteShaderCache_readSeparableVertexShader(MemStreamReader& streamReader, uint8 version) { - std::unique_ptr lcr(new LatteContextRegister()); + auto lcr = std::make_unique(); if (version != 1) return false; uint64 shaderBaseHash = streamReader.readBE(); @@ -658,7 +658,7 @@ bool LatteShaderCache_readSeparableGeometryShader(MemStreamReader& streamReader, { if (version != 1) return false; - std::unique_ptr lcr(new LatteContextRegister()); + auto lcr = std::make_unique(); uint64 shaderBaseHash = streamReader.readBE(); uint64 shaderAuxHash = streamReader.readBE(); uint32 vsRingParameterCount = streamReader.readBE(); @@ -698,7 +698,7 @@ bool LatteShaderCache_readSeparablePixelShader(MemStreamReader& streamReader, ui { if (version != 1) return false; - std::unique_ptr lcr(new LatteContextRegister()); + auto lcr = std::make_unique(); uint64 shaderBaseHash = streamReader.readBE(); uint64 shaderAuxHash = streamReader.readBE(); bool usesGeometryShader = streamReader.readBE() != 0; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp index 50d5a256..bb6c966e 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp @@ -214,6 +214,10 @@ void VulkanPipelineStableCache::LoadPipelineFromCache(std::span fileData) if (!DeserializePipeline(streamReader, *cachedPipeline)) { // failed to deserialize + s_spinlockSharedInternal.acquire(); + delete lcr; + delete cachedPipeline; + s_spinlockSharedInternal.release(); return; } // restored register view from compacted state diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h index dbf64614..a18bb982 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.h @@ -3,7 +3,7 @@ struct VulkanPipelineHash { - VulkanPipelineHash() {}; + VulkanPipelineHash() = default; VulkanPipelineHash(uint64 h0, uint64 h1) : h0(h0), h1(h1) {}; uint64 h0; diff --git a/src/Cafe/OS/RPL/rpl.cpp b/src/Cafe/OS/RPL/rpl.cpp index b1af5535..1c779308 100644 --- a/src/Cafe/OS/RPL/rpl.cpp +++ b/src/Cafe/OS/RPL/rpl.cpp @@ -243,6 +243,7 @@ bool RPLLoader_ProcessHeaders(std::string_view moduleName, uint8* rplData, uint3 if (fileinfoSection->sectionSize < sizeof(RPLFileInfoData)) { cemuLog_force("RPLLoader: FILEINFO section size is below expected size"); + delete rplLoaderContext; return false; } @@ -1963,7 +1964,7 @@ void RPLLoader_AddDependency(const char* name) if (rplLoader_currentTlsModuleIndex == 0x7FFF) cemuLog_force("RPLLoader: Exhausted TLS module indices pool"); // convert name to path/filename if it isn't already one - if (strstr(name, ".")) + if (strchr(name, '.')) { strcpy_s(newDependency->filepath, name); } diff --git a/src/Cafe/OS/common/PPCConcurrentQueue.h b/src/Cafe/OS/common/PPCConcurrentQueue.h index 089515c5..3f0f9851 100644 --- a/src/Cafe/OS/common/PPCConcurrentQueue.h +++ b/src/Cafe/OS/common/PPCConcurrentQueue.h @@ -10,7 +10,7 @@ template class PPCConcurrentQueue { public: - PPCConcurrentQueue() {} + PPCConcurrentQueue() = default; PPCConcurrentQueue(const PPCConcurrentQueue&) = delete; PPCConcurrentQueue& operator=(const PPCConcurrentQueue&) = delete; diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp index e01fda73..d57580f3 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp @@ -54,9 +54,7 @@ namespace coreinit { } - ~OSHostThread() - { - } + ~OSHostThread() = default; OSThread_t* m_thread; Fiber m_fiber; @@ -1223,7 +1221,7 @@ namespace coreinit { struct DeallocatorQueueEntry { - DeallocatorQueueEntry() {}; + DeallocatorQueueEntry() = default; DeallocatorQueueEntry(OSThread_t* thread, MEMPTR stack, MEMPTR deallocatorFunc) : thread(thread), stack(stack), deallocatorFunc(deallocatorFunc) {}; OSThread_t* thread{}; diff --git a/src/Cafe/OS/libs/h264_avc/H264Dec.cpp b/src/Cafe/OS/libs/h264_avc/H264Dec.cpp index 085a2e69..8dbd8ecf 100644 --- a/src/Cafe/OS/libs/h264_avc/H264Dec.cpp +++ b/src/Cafe/OS/libs/h264_avc/H264Dec.cpp @@ -835,8 +835,11 @@ namespace H264 auto asyncTask = std::async(std::launch::async, _async_H264DECEnd, executeDoneEvent.GetPointer(), session, ctx, &results); coreinit::OSWaitEvent(executeDoneEvent); _ReleaseDecoderSession(session); - for (auto& itr : results) - H264DoFrameOutputCallback(ctx, itr); + if (!results.empty()) + { + for (auto& itr : results) + H264DoFrameOutputCallback(ctx, itr); + } return H264DEC_STATUS::SUCCESS; } diff --git a/src/Cafe/TitleList/MetaInfo.cpp b/src/Cafe/TitleList/MetaInfo.cpp index 3ae77a05..b08c4fc2 100644 --- a/src/Cafe/TitleList/MetaInfo.cpp +++ b/src/Cafe/TitleList/MetaInfo.cpp @@ -72,7 +72,6 @@ void MetaInfo::ParseDirectory(const fs::path& filename) bool MetaInfo::ParseFile(const fs::path& filename) { - const auto extension = filename.extension(); if (filename.filename() != "meta.xml") return false; diff --git a/src/Cafe/TitleList/TitleInfo.cpp b/src/Cafe/TitleList/TitleInfo.cpp index c58e1841..ef97e6eb 100644 --- a/src/Cafe/TitleList/TitleInfo.cpp +++ b/src/Cafe/TitleList/TitleInfo.cpp @@ -287,7 +287,6 @@ void TitleInfo::CalcUID() m_uid = 0; return; } - std::error_code ec; // get absolute normalized path fs::path normalizedPath; if (m_fullPath.is_relative()) diff --git a/src/Cafe/TitleList/TitleList.cpp b/src/Cafe/TitleList/TitleList.cpp index f7c1b6f8..deb4564f 100644 --- a/src/Cafe/TitleList/TitleList.cpp +++ b/src/Cafe/TitleList/TitleList.cpp @@ -78,9 +78,9 @@ void CafeTitleList::LoadCacheFile() cacheEntry.titleVersion = titleVersion; cacheEntry.titleDataFormat = format; cacheEntry.region = region; - cacheEntry.titleName = name; + cacheEntry.titleName = std::move(name); cacheEntry.path = _utf8ToPath(path); - cacheEntry.subPath = sub_path; + cacheEntry.subPath = std::move(sub_path); cacheEntry.group_id = group_id; cacheEntry.app_type = app_type; @@ -482,7 +482,7 @@ void CafeTitleList::AddTitle(TitleInfo* titleInfo) } } sTLList.emplace_back(titleInfo); - sTLMap.insert(std::pair(titleInfo->GetAppTitleId(), titleInfo)); + sTLMap.emplace(titleInfo->GetAppTitleId(), titleInfo); // send out notification CafeTitleListCallbackEvent evt; evt.eventType = CafeTitleListCallbackEvent::TYPE::TITLE_DISCOVERED; diff --git a/src/Cemu/FileCache/FileCache.cpp b/src/Cemu/FileCache/FileCache.cpp index 0165f0c4..105ee860 100644 --- a/src/Cemu/FileCache/FileCache.cpp +++ b/src/Cemu/FileCache/FileCache.cpp @@ -287,7 +287,10 @@ uint8* _fileCache_compressFileData(const uint8* fileData, uint32 fileSize, sint3 Bytef* compressedData = (Bytef*)malloc(4 + compressedLen); int zret = compress2(compressedData + 4, &compressedLen, uncompressedInput, uncompressedLen, 4); // level 4 has good compression to performance ratio if (zret != Z_OK) + { + free(compressedData); return nullptr; + } compressedData[0] = ((uint32)fileSize >> 24) & 0xFF; compressedData[1] = ((uint32)fileSize >> 16) & 0xFF; compressedData[2] = ((uint32)fileSize >> 8) & 0xFF; diff --git a/src/Cemu/Tools/DownloadManager/DownloadManager.cpp b/src/Cemu/Tools/DownloadManager/DownloadManager.cpp index 33af7433..5ede52d4 100644 --- a/src/Cemu/Tools/DownloadManager/DownloadManager.cpp +++ b/src/Cemu/Tools/DownloadManager/DownloadManager.cpp @@ -967,7 +967,7 @@ void DownloadManager::setPackageError(Package* package, std::string errorMsg) if (package->state.hasError) return; // dont overwrite already set error message package->state.hasError = true; - package->state.errorMsg = errorMsg; + package->state.errorMsg = std::move(errorMsg); reportPackageStatus(package); } @@ -1216,7 +1216,6 @@ void DownloadManager::asyncPackageDownloadContentFile(Package* package, uint16 i void DownloadManager::asyncPackageVerifyFile(Package* package, uint16 index, bool isCheckState) { uint8 tmdContentHash[32]; - std::string filePathStr; // get titleId, contentId and file path std::unique_lock _l(m_mutex); uint64 titleId = package->titleId; diff --git a/src/Cemu/Tools/DownloadManager/DownloadManager.h b/src/Cemu/Tools/DownloadManager/DownloadManager.h index fa6749b8..1693318c 100644 --- a/src/Cemu/Tools/DownloadManager/DownloadManager.h +++ b/src/Cemu/Tools/DownloadManager/DownloadManager.h @@ -446,7 +446,7 @@ public: std::unique_lock _l(m_mutex); m_packageList.clear(); m_statusCode = DLMGR_STATUS_CODE::UNINITIALIZED; - m_statusMessage = ""; + m_statusMessage.clear(); } private: diff --git a/src/Cemu/napi/napi_act.cpp b/src/Cemu/napi/napi_act.cpp index b9a9c16c..663de2c4 100644 --- a/src/Cemu/napi/napi_act.cpp +++ b/src/Cemu/napi/napi_act.cpp @@ -355,7 +355,6 @@ namespace NAPI std::string_view host = tokenNode.child_value("host"); std::string_view nex_password = tokenNode.child_value("nex_password"); - std::string_view pid = tokenNode.child_value("pid"); std::string_view port = tokenNode.child_value("port"); std::string_view token = tokenNode.child_value("token"); diff --git a/src/Cemu/napi/napi_ec.cpp b/src/Cemu/napi/napi_ec.cpp index 82ab5be4..2d559e81 100644 --- a/src/Cemu/napi/napi_ec.cpp +++ b/src/Cemu/napi/napi_ec.cpp @@ -360,7 +360,7 @@ namespace NAPI // ticketVersion starts at 0 and increments every time the ticket is updated (e.g. for AOC content, when purchasing additional DLC packages) const char* tivValue = tivNode.child_value(); const char* tivValueEnd = tivValue + strlen(tivValue); - const char* tivValueSeparator = std::strstr(tivValue, "."); + const char* tivValueSeparator = std::strchr(tivValue, '.'); if (tivValueSeparator == nullptr) tivValueSeparator = tivValueEnd; diff --git a/src/Cemu/nex/nex.cpp b/src/Cemu/nex/nex.cpp index 147d37da..010f806c 100644 --- a/src/Cemu/nex/nex.cpp +++ b/src/Cemu/nex/nex.cpp @@ -739,7 +739,7 @@ nexService* nex_establishSecureConnection(uint32 authServerIp, uint16 authServer return nullptr; } // auth info - std::unique_ptr authServerInfo(new authServerInfo_t); + auto authServerInfo = std::make_unique(); // decrypt ticket RC4Ctx_t rc4Ticket; RC4_initCtx(&rc4Ticket, kerberosKey, 16); diff --git a/src/Cemu/nex/nexFriends.h b/src/Cemu/nex/nexFriends.h index cb935068..16548bf3 100644 --- a/src/Cemu/nex/nexFriends.h +++ b/src/Cemu/nex/nexFriends.h @@ -7,10 +7,7 @@ class nexGameKey : public nexType { public: - nexGameKey() - { - - } + nexGameKey() = default; nexGameKey(uint64 titleId, uint16 ukn) { @@ -175,10 +172,9 @@ public: } nexPrincipalBasicInfo(uint32 principalId, char* nnid, const nexMiiV2& mii) + : principalId(principalId), mii(mii) { - this->principalId = principalId; strcpy(this->nnid, nnid); - this->mii = mii; } nexPrincipalBasicInfo(nexPacketBuffer* pb) @@ -218,10 +214,8 @@ public: } nexNNAInfo(uint8 countryCode, uint8 countrySubCode, const nexPrincipalBasicInfo& principalBasicInfo) + : countryCode(countryCode), countrySubCode(countrySubCode), principalInfo(principalBasicInfo) { - this->countryCode = countryCode; - this->countrySubCode = countrySubCode; - this->principalInfo = principalBasicInfo; } nexNNAInfo(nexPacketBuffer* pb) @@ -250,10 +244,7 @@ public: class nexPrincipalPreference : public nexType { public: - nexPrincipalPreference() - { - - } + nexPrincipalPreference() = default; nexPrincipalPreference(uint8 ukn0, uint8 ukn1, uint8 ukn2) { diff --git a/src/Cemu/nex/nexTypes.h b/src/Cemu/nex/nexTypes.h index 8147836c..49edd3d3 100644 --- a/src/Cemu/nex/nexTypes.h +++ b/src/Cemu/nex/nexTypes.h @@ -222,7 +222,7 @@ public: if (this->currentIndex + bufferLength > this->size) { readOutOfBounds = true; - outputStr = std::string(""); + outputStr.clear(); return 0; } sint32 copiedLength = bufferLength; diff --git a/src/Common/windows/FileStream_win32.h b/src/Common/windows/FileStream_win32.h index c7ad802a..a0b1b30a 100644 --- a/src/Common/windows/FileStream_win32.h +++ b/src/Common/windows/FileStream_win32.h @@ -43,7 +43,7 @@ class FileStream void writeLine(const char* str); ~FileStream(); - FileStream() {}; + FileStream() = default; private: FileStream(HANDLE hFile); diff --git a/src/config/CemuConfig.cpp b/src/config/CemuConfig.cpp index 31a3b3e2..f996fc94 100644 --- a/src/config/CemuConfig.cpp +++ b/src/config/CemuConfig.cpp @@ -557,7 +557,7 @@ void CemuConfig::SetGameListCustomName(uint64 titleId, std::string customName) return; gameEntry = CreateGameEntry(titleId); } - gameEntry->custom_name = customName; + gameEntry->custom_name = std::move(customName); } void CemuConfig::AddRecentlyLaunchedFile(std::wstring_view file) diff --git a/src/gui/GameProfileWindow.cpp b/src/gui/GameProfileWindow.cpp index f710988f..330e290e 100644 --- a/src/gui/GameProfileWindow.cpp +++ b/src/gui/GameProfileWindow.cpp @@ -168,7 +168,6 @@ GameProfileWindow::GameProfileWindow(wxWindow* parent, uint64_t title_id) { profile_sizer->Add(new wxStaticText(panel, wxID_ANY, fmt::format("{} {}", _("Controller").ToStdString(), (i + 1))), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - wxArrayString m_controller_profileChoices; m_controller_profile[i] = new wxComboBox(panel, wxID_ANY,"", wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_DROPDOWN| wxCB_READONLY); m_controller_profile[i]->SetMinSize(wxSize(250, -1)); m_controller_profile[i]->Bind(wxEVT_COMBOBOX_DROPDOWN, &GameProfileWindow::OnControllerProfileDropdown, this); diff --git a/src/gui/GameUpdateWindow.cpp b/src/gui/GameUpdateWindow.cpp index 3ea3f9d1..bf4cd49a 100644 --- a/src/gui/GameUpdateWindow.cpp +++ b/src/gui/GameUpdateWindow.cpp @@ -213,7 +213,6 @@ void GameUpdateWindow::ThreadWork() create_directories(targetDir); } - const auto target_path = fs::path(m_target_path); for (auto& path : m_source_paths) { if (m_thread_state == ThreadCanceled) diff --git a/src/gui/GeneralSettings2.cpp b/src/gui/GeneralSettings2.cpp index 78e1feec..41f7b4fc 100644 --- a/src/gui/GeneralSettings2.cpp +++ b/src/gui/GeneralSettings2.cpp @@ -843,7 +843,7 @@ void GeneralSettings2::StoreConfig() config.tv_volume = m_tv_volume->GetValue(); config.pad_volume = m_pad_volume->GetValue(); - config.tv_device = L""; + config.tv_device.clear(); const auto tv_device = m_tv_device->GetSelection(); if (tv_device != wxNOT_FOUND && tv_device != 0 && m_tv_device->HasClientObjectData()) { @@ -852,7 +852,7 @@ void GeneralSettings2::StoreConfig() config.tv_device = device_description->GetDescription()->GetIdentifier(); } - config.pad_device = L""; + config.pad_device.clear(); const auto pad_device = m_pad_device->GetSelection(); if (pad_device != wxNOT_FOUND && pad_device != 0 && m_pad_device->HasClientObjectData()) { diff --git a/src/gui/components/wxTitleManagerList.cpp b/src/gui/components/wxTitleManagerList.cpp index 9a8c17a3..8f43630d 100644 --- a/src/gui/components/wxTitleManagerList.cpp +++ b/src/gui/components/wxTitleManagerList.cpp @@ -343,7 +343,7 @@ void wxTitleManagerList::OnConvertToCompressedFormat(uint64 titleId) if (!GetConfig().game_paths.empty()) defaultDir = GetConfig().game_paths.front(); // get the short name, which we will use as a suggested default file name - std::string defaultFileName = shortName; + std::string defaultFileName = std::move(shortName); boost::replace_all(defaultFileName, "/", ""); boost::replace_all(defaultFileName, "\\", ""); @@ -474,7 +474,7 @@ void wxTitleManagerList::OnConvertToCompressedFormat(uint64 titleId) { std::string temporaryMountPath = TitleInfo::GetUniqueTempMountingPath(); titleInfo->Mount(temporaryMountPath.c_str(), "", FSC_PRIORITY_BASE); - bool r = RecursivelyAddFiles(fmt::format("{:016x}_v{}/", titleInfo->GetAppTitleId(), titleInfo->GetAppTitleVersion()), temporaryMountPath.c_str()); + bool r = RecursivelyAddFiles(fmt::format("{:016x}_v{}/", titleInfo->GetAppTitleId(), titleInfo->GetAppTitleVersion()), temporaryMountPath); titleInfo->Unmount(temporaryMountPath.c_str()); return r; } diff --git a/src/gui/debugger/DumpCtrl.cpp b/src/gui/debugger/DumpCtrl.cpp index d8cd6448..cc1d5fee 100644 --- a/src/gui/debugger/DumpCtrl.cpp +++ b/src/gui/debugger/DumpCtrl.cpp @@ -251,7 +251,7 @@ void DumpCtrl::GoToAddressDialog() m_lastGotoOffset = result; CenterOffset(result); } - catch (const std::exception ex) + catch (const std::exception& ex) { wxMessageBox(ex.what(), _("Error"), wxOK | wxCENTRE | wxICON_ERROR, this); } diff --git a/src/gui/debugger/SymbolCtrl.cpp b/src/gui/debugger/SymbolCtrl.cpp index d9adaa32..cb1f3b1a 100644 --- a/src/gui/debugger/SymbolCtrl.cpp +++ b/src/gui/debugger/SymbolCtrl.cpp @@ -36,7 +36,7 @@ SymbolListCtrl::SymbolListCtrl(wxWindow* parent, const wxWindowID& id, const wxP Bind(wxEVT_LIST_ITEM_ACTIVATED, &SymbolListCtrl::OnLeftDClick, this); Bind(wxEVT_LIST_ITEM_RIGHT_CLICK, &SymbolListCtrl::OnRightClick, this); - m_list_filter = ""; + m_list_filter.Clear(); OnGameLoaded(); @@ -65,7 +65,7 @@ void SymbolListCtrl::OnGameLoaded() new_entry.first->second.searchName += new_entry.first->second.libName; new_entry.first->second.searchName.MakeLower(); - if (m_list_filter == "") + if (m_list_filter.IsEmpty()) new_entry.first->second.visible = true; else if (new_entry.first->second.searchName.Contains(m_list_filter)) new_entry.first->second.visible = true; @@ -149,7 +149,7 @@ void SymbolListCtrl::ChangeListFilter(std::string filter) size_t visible_entries = m_data.size(); for (auto& [address, symbol] : m_data) { - if (m_list_filter == "") + if (m_list_filter.IsEmpty()) symbol.visible = true; else if (symbol.searchName.Contains(m_list_filter)) symbol.visible = true; diff --git a/src/gui/debugger/SymbolCtrl.h b/src/gui/debugger/SymbolCtrl.h index 9aebdedc..81ccd326 100644 --- a/src/gui/debugger/SymbolCtrl.h +++ b/src/gui/debugger/SymbolCtrl.h @@ -11,7 +11,7 @@ public: void ChangeListFilter(std::string filter); private: struct SymbolItem { - SymbolItem() {} + SymbolItem() = default; SymbolItem(wxString name, wxString libName, wxString searchName, bool visible) : name(name), libName(libName), searchName(searchName), visible(visible) {} diff --git a/src/gui/input/InputSettings2.cpp b/src/gui/input/InputSettings2.cpp index 5793cbd2..e5f4891d 100644 --- a/src/gui/input/InputSettings2.cpp +++ b/src/gui/input/InputSettings2.cpp @@ -568,8 +568,6 @@ void InputSettings2::on_profile_text_changed(wxCommandEvent& event) auto& page_data = get_current_page_data(); - const auto selection = page_data.m_emulated_controller->GetStringSelection(); - // load_bttn, save_bttn, delete_bttn, profile_status const auto text = event.GetString(); const auto text_str = from_wxString(text); diff --git a/src/input/api/Controller.h b/src/input/api/Controller.h index 29b01f28..8b1c8e62 100644 --- a/src/input/api/Controller.h +++ b/src/input/api/Controller.h @@ -189,7 +189,7 @@ public: // update provider if settings are different from default provider void update_provider(std::shared_ptr provider) { - m_provider = provider; + m_provider = std::move(provider); } protected: diff --git a/src/input/motion/MotionSample.h b/src/input/motion/MotionSample.h index f4015afb..bb47f784 100644 --- a/src/input/motion/MotionSample.h +++ b/src/input/motion/MotionSample.h @@ -104,9 +104,7 @@ struct Quat class MotionSample { public: - MotionSample() - { - } + MotionSample() = default; MotionSample(float acc[3], float accAcceleration, float gyro[3], float orientation[3], float quaternion[4] diff --git a/src/util/Zir/Core/IR.h b/src/util/Zir/Core/IR.h index 71191024..a59c7837 100644 --- a/src/util/Zir/Core/IR.h +++ b/src/util/Zir/Core/IR.h @@ -289,7 +289,7 @@ namespace ZpIR // IR register constant definition stored in basic block struct IRRegConstDef { - IRRegConstDef() {}; + IRRegConstDef() = default; // todo - support for constants with more than one element? IRRegConstDef& setU32(uint32 v) { value_u32 = v; type = DataType::U32; return *this; }; @@ -513,7 +513,7 @@ namespace ZpIR LOC_TYPE_ATTRIBUTE = 3, }; public: - ShaderImportLocation() {} + ShaderImportLocation() = default; ShaderImportLocation(LocationSymbolName loc) { uint64 v = (uint64)loc; @@ -598,7 +598,7 @@ namespace ZpIR LOC_TYPE_OUTPUT = 2, }; public: - ShaderExportLocation() {} + ShaderExportLocation() = default; ShaderExportLocation(LocationSymbolName loc) { uint64 v = (uint64)loc; diff --git a/src/util/Zir/EmitterGLSL/ZpIREmitGLSL.cpp b/src/util/Zir/EmitterGLSL/ZpIREmitGLSL.cpp index 0b0c2dc5..cb42111b 100644 --- a/src/util/Zir/EmitterGLSL/ZpIREmitGLSL.cpp +++ b/src/util/Zir/EmitterGLSL/ZpIREmitGLSL.cpp @@ -12,9 +12,7 @@ class DualStringBuffer public: DualStringBuffer() : m_offsetBegin(N / 2), m_offsetEnd(N / 2) { } - ~DualStringBuffer() - { - } + ~DualStringBuffer() = default; static_assert(sizeof(char) == sizeof(uint8)); diff --git a/src/util/containers/IntervalBucketContainer.h b/src/util/containers/IntervalBucketContainer.h index e48d305e..a85aca78 100644 --- a/src/util/containers/IntervalBucketContainer.h +++ b/src/util/containers/IntervalBucketContainer.h @@ -15,7 +15,7 @@ class IntervalBucketContainer public: - IntervalBucketContainer() {}; + IntervalBucketContainer() = default; // range is defined as inclusive rangeStart and exclusive rangeEnd void addRange(TAddr rangeStart, TAddr rangeEnd, TData* data) diff --git a/src/util/containers/RangeStore.h b/src/util/containers/RangeStore.h index d1167b29..e20688e6 100644 --- a/src/util/containers/RangeStore.h +++ b/src/util/containers/RangeStore.h @@ -13,10 +13,7 @@ public: size_t lastIterationIndex; }rangeEntry_t; - RangeStore() - { - - } + RangeStore() = default; size_t getBucket(_ADDR addr) { diff --git a/src/util/containers/SmallBitset.h b/src/util/containers/SmallBitset.h index 87fae9d8..27109183 100644 --- a/src/util/containers/SmallBitset.h +++ b/src/util/containers/SmallBitset.h @@ -6,7 +6,7 @@ template class SmallBitset { public: - SmallBitset() {}; + SmallBitset() = default; static_assert(N <= 32); bool test(size_t index) const diff --git a/src/util/containers/flat_hash_map.hpp b/src/util/containers/flat_hash_map.hpp index 3dee0b16..1eccc307 100644 --- a/src/util/containers/flat_hash_map.hpp +++ b/src/util/containers/flat_hash_map.hpp @@ -166,9 +166,7 @@ namespace ska : distance_from_desired(distance_from_desired) { } - ~sherwood_v3_entry() - { - } + ~sherwood_v3_entry() = default; static sherwood_v3_entry* empty_default_table() { static sherwood_v3_entry result[min_lookups] = { {}, {}, {}, {special_end_value} }; @@ -297,9 +295,7 @@ namespace ska using pointer = value_type*; using const_pointer = const value_type*; - sherwood_v3_table() - { - } + sherwood_v3_table() = default; explicit sherwood_v3_table(size_type bucket_count, const ArgumentHash& hash = ArgumentHash(), const ArgumentEqual& equal = ArgumentEqual(), const ArgumentAlloc& alloc = ArgumentAlloc()) : EntryAlloc(alloc), Hasher(hash), Equal(equal) { @@ -1324,9 +1320,7 @@ namespace ska using mapped_type = V; using Table::Table; - flat_hash_map() - { - } + flat_hash_map() = default; inline V& operator[](const K& key) { @@ -1442,9 +1436,7 @@ namespace ska using key_type = T; using Table::Table; - flat_hash_set() - { - } + flat_hash_set() = default; template std::pair emplace(Args &&... args) From c113565fe3171e537ff53a7660404aac609eadc1 Mon Sep 17 00:00:00 2001 From: Crementif <26669564+Crementif@users.noreply.github.com> Date: Sat, 17 Sep 2022 10:45:27 +0200 Subject: [PATCH 008/638] [deps] Update zarchive --- dependencies/ZArchive | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies/ZArchive b/dependencies/ZArchive index 48914a07..d2c71773 160000 --- a/dependencies/ZArchive +++ b/dependencies/ZArchive @@ -1 +1 @@ -Subproject commit 48914a07df3c213333c580bb5e5bb3393442ca5b +Subproject commit d2c717730092c7bf8cbb033b12fd4001b7c4d932 From 41dcd480484c9aa988aeaacdc4c05831aad6a704 Mon Sep 17 00:00:00 2001 From: Tillsunset <35825944+Tillsunset@users.noreply.github.com> Date: Sat, 17 Sep 2022 06:52:12 -0500 Subject: [PATCH 009/638] Fix a small regression when building in Macos (#262) --- src/Cafe/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cafe/CMakeLists.txt b/src/Cafe/CMakeLists.txt index baf8fdb0..6657bc9c 100644 --- a/src/Cafe/CMakeLists.txt +++ b/src/Cafe/CMakeLists.txt @@ -467,7 +467,7 @@ add_library(CemuCafe ) if(APPLE) - target_sources(CemuCafe"HW/Latte/Renderer/Vulkan/CocoaSurface.mm") + target_sources(CemuCafe PRIVATE "HW/Latte/Renderer/Vulkan/CocoaSurface.mm") endif() set_property(TARGET CemuCafe PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") From dd14778561f276d667109af0f2cb44f998207fb7 Mon Sep 17 00:00:00 2001 From: uranuspucksaxophone <84784521+uranuspucksaxophone@users.noreply.github.com> Date: Sat, 17 Sep 2022 14:53:46 +0200 Subject: [PATCH 010/638] [docs] Explain how to update local cemu repo + General fixes (#227) Co-authored-by: Crementif <26669564+Crementif@users.noreply.github.com> --- BUILD.md | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/BUILD.md b/BUILD.md index 67f55a94..6141d6a5 100644 --- a/BUILD.md +++ b/BUILD.md @@ -12,11 +12,11 @@ Instructions: 1. Run `git clone --recursive https://github.com/cemu-project/Cemu` 2. Launch `Cemu/generate_vs_solution.bat`. - - If you installed VS to a custom location or use VS 2019, you may need to manually change the path inside the .bat file -3. Wait until it's done, then open `Cemu/build/Cemu.sln` in Visual Studio + - If you installed VS to a custom location or use VS 2019, you may need to manually change the path inside the .bat file. +3. Wait until it's done, then open `Cemu/build/Cemu.sln` in Visual Studio. 4. Then build the solution and once finished you can run and debug it, or build it and check the /bin folder for the final Cemu_release.exe. -You can also skip steps 3-5 and open the root folder of the cloned repo directly in Visual Studio (as a folder) and use the built-in cmake support but be warned that cmake support in VS can be a bit finicky. +You can also skip steps 3-5 and open the root folder of the cloned repo directly in Visual Studio (as a folder) and use the built-in CMake support but be warned that cmake support in VS can be a bit finicky. ## Linux @@ -25,14 +25,15 @@ To compile Cemu, a recent enough compiler and STL with C++20 support is required ### Installing dependencies #### For Ubuntu and derivatives: -`sudo apt install -y git curl cmake ninja-build nasm libgtk-3-dev libsecret-1-dev libgcrypt20-dev libsystemd-dev freeglut3-dev libpulse-dev` -Additionally, for ubuntu 20.04 only: +`sudo apt install -y git curl cmake ninja-build nasm libgtk-3-dev libsecret-1-dev libgcrypt20-dev libsystemd-dev freeglut3-dev libpulse-dev` + +*Additionally, for Ubuntu 22.04 only:* - `sudo apt install -y clang-12` - At step 3 while building, use `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang-12 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-12 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja` #### For Arch and derivatives: -`sudo pacman -S git cmake clang ninja nasm base-devel linux-headers gtk3 libsecret libgcrypt systemd freeglut zip libpulse` +`sudo pacman -S git cmake clang ninja nasm base-devel linux-headers gtk3 libsecret libgcrypt systemd freeglut zip unzip libpulse` #### For Fedora and derivatives: `sudo dnf install git cmake clang ninja-build nasm kernel-headers gtk3-devel libsecret-devel libgcrypt-devel systemd-devel freeglut-devel perl-core zlib-devel cubeb-devel` @@ -56,4 +57,11 @@ You can use it by replacing the step 3 with the following: - If step 3 is still failing or if you're not able to find the cause, please make an issue on our Github about it! - If step 4 gives you an error that contains something like `main.cpp.o: in function 'std::__cxx11::basic_string...`, you likely are experiencing a clang-14 issue. This can only be fixed by either lowering the clang version or using GCC, see below. - If step 4 gives you a different error, you could report it to this repo or try using GCC. Just make sure your standard library and compilers are updated since Cemu uses a lot of modern features! -- If step 4 gives you undefined libdecor_xx, you are likely experiencing an issue with sdl2 package that comes with vcpkg. Delete sdl2 from vcpkg.json in source file and recompile +- If step 4 gives you undefined libdecor_xx, you are likely experiencing an issue with sdl2 package that comes with vcpkg. Delete sdl2 from vcpkg.json in source file and recompile. + +## Updating Cemu and source code +1. To update your Cemu local repository, use the command `git pull --recurse-submodules` (run this command on the Cemu root). + - This should update your local copy of Cemu and all of its dependencies. +2. Then, you can rebuild Cemu using the steps listed above, according to whether you use Linux or Windows. + +If CMake complains about Cemu already being compiled or another similar error, try deleting the `CMakeCache.txt` file inside the `build` folder and retry building. From 12b6830546e28e6a697c5dbcbc3aa24882ec7fb3 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sat, 17 Sep 2022 16:32:46 +0200 Subject: [PATCH 011/638] GX2: Add crash workaround for FFL uninitialized texture (#264) When a game tries to generate Miis without the FFL files being dumped (/sys/title/0005001b/10056000/content/) it will cause it to create and use a texture with invalid parameters. This workaround catches and replaces bad texture parameters to avoid crashing further down the line. Resolves crashes in Sonic Lost World, Super Mario 3D World and probably a few others. We had this workaround in pre-2.0 Cemu already but it was dropped during refactoring. --- src/Cafe/OS/libs/gx2/GX2_Surface.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/Cafe/OS/libs/gx2/GX2_Surface.cpp b/src/Cafe/OS/libs/gx2/GX2_Surface.cpp index 5ce8a453..1d858e18 100644 --- a/src/Cafe/OS/libs/gx2/GX2_Surface.cpp +++ b/src/Cafe/OS/libs/gx2/GX2_Surface.cpp @@ -112,8 +112,34 @@ namespace GX2 return levels; } + void _GX2CalcSurfaceSizeAndAlignmentWorkaround(GX2Surface* surface) + { + // this workaround catches an issue where the FFL (Mii) library embedded into games tries to use an uninitialized texture + // and subsequently crashes. It only happens when FFL files are not present in mlc. + // seen in Sonic Lost World and in Super Mario 3D World + if ((uint32)surface->dim.value() >= 50 || surface->aa.value() >= 0x100 || (uint32)surface->width.value() >= 0x01000000 || + (uint32)surface->height.value() >= 0x01000000 || (uint32)surface->depth.value() >= 0x01000000 || (uint32)surface->format.value() >= 0x10000) + { + cemuLog_log(LogType::Force, "GX2CalcSurfaceSizeAndAlignment(): Uninitialized surface encountered\n"); + // overwrite surface parameters with placeholder values to avoid crashing later down the line + surface->dim = Latte::E_DIM::DIM_2D; + surface->width = 8; + surface->height = 8; + surface->depth = 1; + surface->tileMode = Latte::E_GX2TILEMODE::TM_2D_TILED_THIN1; + surface->pitch = 8; + surface->numLevels = 0; + surface->imagePtr = MEMORY_TILINGAPERTURE_AREA_ADDR; + surface->swizzle = 0; + surface->aa = 0; + surface->format = Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM; + surface->alignment = 0x400; + } + } + void GX2CalcSurfaceSizeAndAlignment(GX2Surface* surface) { + _GX2CalcSurfaceSizeAndAlignmentWorkaround(surface); LatteAddrLib::AddrSurfaceInfo_OUT surfOut = { 0 }; uint32 firstMipOffset = 0; bool changeTilemode = false; From 867c0c5ca245a77122931617a67238c4d96b2929 Mon Sep 17 00:00:00 2001 From: Tillsunset <35825944+Tillsunset@users.noreply.github.com> Date: Sun, 18 Sep 2022 07:39:00 -0500 Subject: [PATCH 012/638] Fix some issues with building on macOS (#268) * fixed building on macos, needs OBJC and OBJXX to be enabled * changed to weak ordering due to string comparison not being strong ordering * Use raw PNG bytes from "resource/embedded/resources.h" in all windows too --- CMakeLists.txt | 4 ++++ src/gui/GeneralSettings2.cpp | 10 ++++------ src/gui/TitleManager.cpp | 7 +++---- src/gui/components/wxGameList.cpp | 10 +++++----- src/resource/CMakeLists.txt | 10 ++++------ 5 files changed, 20 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e9f7458e..483a9eff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,10 @@ if (MSVC) endif() endif() +if (APPLE) + enable_language(OBJC OBJCXX) +endif() + option(ENABLE_OPENGL "Enables the OpenGL backend" ON) option(ENABLE_VULKAN "Enables the Vulkan backend" ON) option(ENABLE_DISCORD_RPC "Enables the Discord Rich Presence feature" ON) diff --git a/src/gui/GeneralSettings2.cpp b/src/gui/GeneralSettings2.cpp index 41f7b4fc..f81e7364 100644 --- a/src/gui/GeneralSettings2.cpp +++ b/src/gui/GeneralSettings2.cpp @@ -39,9 +39,7 @@ #include "config/ActiveSettings.h" #include "gui/helpers/wxHelpers.h" -#if BOOST_OS_LINUX || BOOST_OS_MACOS #include "resource/embedded/resources.h" -#endif #include "Cafe/CafeSystem.h" #include "Cemu/ncrypto/ncrypto.h" @@ -630,7 +628,7 @@ wxPanel* GeneralSettings2::AddAccountPage(wxNotebook* notebook) row->SetFlexibleDirection(wxBOTH); row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); - const wxImage tmp = wxBITMAP_PNG(PNG_ERROR).ConvertToImage(); + const wxImage tmp = wxBITMAP_PNG_FROM_DATA(PNG_ERROR).ConvertToImage(); m_validate_online = new wxBitmapButton(box, wxID_ANY, tmp.Scale(16, 16)); m_validate_online->Bind(wxEVT_BUTTON, &GeneralSettings2::OnShowOnlineValidator, this); row->Add(m_validate_online, 0, wxEXPAND | wxALL, 5); @@ -1220,7 +1218,7 @@ void GeneralSettings2::UpdateAccountInformation() const auto selection = m_active_account->GetSelection(); if(selection == wxNOT_FOUND) { - m_validate_online->SetBitmap(wxBITMAP_PNG(PNG_ERROR).ConvertToImage().Scale(16, 16)); + m_validate_online->SetBitmap(wxBITMAP_PNG_FROM_DATA(PNG_ERROR).ConvertToImage().Scale(16, 16)); m_validate_online->SetWindowStyleFlag(m_validate_online->GetWindowStyleFlag() & ~wxBORDER_NONE); ResetAccountInformation(); return; @@ -1253,12 +1251,12 @@ void GeneralSettings2::UpdateAccountInformation() { m_online_status->SetLabel(_("Your account is a valid online account")); - m_validate_online->SetBitmap(wxBITMAP_PNG(PNG_CHECK_YES).ConvertToImage().Scale(16, 16)); + m_validate_online->SetBitmap(wxBITMAP_PNG_FROM_DATA(PNG_CHECK_YES).ConvertToImage().Scale(16, 16)); m_validate_online->SetWindowStyleFlag(m_validate_online->GetWindowStyleFlag() | wxBORDER_NONE); } else { - m_validate_online->SetBitmap(wxBITMAP_PNG(PNG_ERROR).ConvertToImage().Scale(16, 16)); + m_validate_online->SetBitmap(wxBITMAP_PNG_FROM_DATA(PNG_ERROR).ConvertToImage().Scale(16, 16)); m_validate_online->SetWindowStyleFlag(m_validate_online->GetWindowStyleFlag() & ~wxBORDER_NONE); } diff --git a/src/gui/TitleManager.cpp b/src/gui/TitleManager.cpp index 657fa3ce..73e9d45c 100644 --- a/src/gui/TitleManager.cpp +++ b/src/gui/TitleManager.cpp @@ -39,9 +39,8 @@ #include "Cafe/TitleList/TitleList.h" -#if BOOST_OS_LINUX || BOOST_OS_MACOS #include "resource/embedded/resources.h" -#endif + #include "Cafe/TitleList/SaveList.h" wxDEFINE_EVENT(wxEVT_TITLE_FOUND, wxCommandEvent); @@ -63,14 +62,14 @@ wxPanel* TitleManager::CreateTitleManagerPage() m_filter->Bind(wxEVT_TEXT, &TitleManager::OnFilterChanged, this); row->Add(m_filter, 1, wxALL | wxEXPAND, 5); - const wxImage refresh = wxBITMAP_PNG(PNG_REFRESH).ConvertToImage(); + const wxImage refresh = wxBITMAP_PNG_FROM_DATA(PNG_REFRESH).ConvertToImage(); m_refresh_button = new wxBitmapButton(panel, wxID_ANY, refresh.Scale(16, 16)); m_refresh_button->Disable(); m_refresh_button->Bind(wxEVT_BUTTON, &TitleManager::OnRefreshButton, this); m_refresh_button->SetToolTip(_("Refresh")); row->Add(m_refresh_button, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); - auto* help_button = new wxStaticBitmap(panel, wxID_ANY, wxBITMAP_PNG(PNG_HELP)); + auto* help_button = new wxStaticBitmap(panel, wxID_ANY, wxBITMAP_PNG_FROM_DATA(PNG_HELP)); help_button->SetToolTip(wxStringFormat2(_("The following prefixes are supported:\n{0}\n{1}\n{2}\n{3}\n{4}"), "titleid:", "name:", "type:", "version:", "region:")); row->Add(help_button, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); diff --git a/src/gui/components/wxGameList.cpp b/src/gui/components/wxGameList.cpp index d4fbed52..074722e0 100644 --- a/src/gui/components/wxGameList.cpp +++ b/src/gui/components/wxGameList.cpp @@ -302,12 +302,12 @@ void wxGameList::UpdateItemColors(sint32 startIndex) } } -static inline int strongorder_to_int(const std::strong_ordering &wo) +static inline int order_to_int(const std::weak_ordering &wo) { // no easy conversion seems to exists in C++20 - if (wo < 0) + if (wo == std::weak_ordering::less) return -1; - else if (wo > 0) + else if (wo == std::weak_ordering::greater) return 1; return 0; } @@ -320,9 +320,9 @@ int wxGameList::SortComparator(uint64 titleId1, uint64 titleId2, SortData* sortD const auto& name2 = GetNameByTitleId(titleId2); if(sortData->dir > 0) - return strongorder_to_int(std::tie(isFavoriteB, name1) <=> std::tie(isFavoriteA, name2)); + return order_to_int(std::tie(isFavoriteB, name1) <=> std::tie(isFavoriteA, name2)); else - return strongorder_to_int(std::tie(isFavoriteB, name2) <=> std::tie(isFavoriteA, name1)); + return order_to_int(std::tie(isFavoriteB, name2) <=> std::tie(isFavoriteA, name1)); } int wxGameList::SortFunction(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData) diff --git a/src/resource/CMakeLists.txt b/src/resource/CMakeLists.txt index 24eb7f4e..23296998 100644 --- a/src/resource/CMakeLists.txt +++ b/src/resource/CMakeLists.txt @@ -3,12 +3,10 @@ add_library(CemuResource) set_property(TARGET CemuResource PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") # icon resources -if(UNIX) - target_sources(CemuResource PRIVATE - embedded/resources.cpp - embedded/resources.h - ) -endif() +target_sources(CemuResource PRIVATE +embedded/resources.cpp +embedded/resources.h +) target_sources(CemuResource PRIVATE CafeDefaultFont.cpp) From 5e968eff4fee065bfc117d580d51553896cd5a88 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sun, 18 Sep 2022 15:53:10 +0200 Subject: [PATCH 013/638] Fix 1x1 symbols in debugger window + Load icons from headers on all platforms - Fixed an issue where the toolbar icons for the debugger were resized to 1x1 - On Windows we now load the PNG UI icons from the header-embedded pngs (`resource/embedded`) instead of via `cemu.rc` to match behavior of other platforms --- src/gui/debugger/DebuggerWindow2.cpp | 17 ++++++++-------- src/gui/input/InputSettings2.cpp | 8 +++----- src/resource/cemu.rc | 30 ---------------------------- 3 files changed, 11 insertions(+), 44 deletions(-) diff --git a/src/gui/debugger/DebuggerWindow2.cpp b/src/gui/debugger/DebuggerWindow2.cpp index cca9bfb8..1f6c5f79 100644 --- a/src/gui/debugger/DebuggerWindow2.cpp +++ b/src/gui/debugger/DebuggerWindow2.cpp @@ -19,9 +19,7 @@ #include "gui/debugger/ModuleWindow.h" #include "util/helpers/helpers.h" -#if BOOST_OS_LINUX #include "resource/embedded/resources.h" -#endif enum { @@ -219,26 +217,27 @@ void DebuggerModuleStorage::Save(XMLConfigParser& parser) void DebuggerWindow2::CreateToolBar() { m_toolbar = wxFrame::CreateToolBar(wxTB_HORIZONTAL, wxID_ANY); - m_toolbar->SetToolBitmapSize(wxSize(1, 1)); + m_toolbar->SetToolBitmapSize(wxSize(16, 16)); - m_toolbar->AddTool(TOOL_ID_GOTO, wxEmptyString, wxBITMAP_PNG(DEBUGGER_GOTO), wxNullBitmap, wxITEM_NORMAL, _("GoTo (CTRL + G)"), "test", NULL); + m_toolbar->AddTool(TOOL_ID_GOTO, wxEmptyString, wxBITMAP_PNG_FROM_DATA(DEBUGGER_GOTO), wxNullBitmap, wxITEM_NORMAL, _("GoTo (CTRL + G)"), "test", NULL); m_toolbar->AddSeparator(); - m_toolbar->AddTool(TOOL_ID_BP, wxEmptyString, wxBITMAP_PNG(DEBUGGER_BP_RED), wxNullBitmap, wxITEM_NORMAL, _("Toggle Breakpoint (F9)"), wxEmptyString, NULL); + m_toolbar->AddTool(TOOL_ID_BP, wxEmptyString, wxBITMAP_PNG_FROM_DATA(DEBUGGER_BP_RED), wxNullBitmap, wxITEM_NORMAL, _("Toggle Breakpoint (F9)"), wxEmptyString, NULL); m_toolbar->AddSeparator(); - m_pause = wxBITMAP_PNG(DEBUGGER_PAUSE); - m_run = wxBITMAP_PNG(DEBUGGER_PLAY); + m_pause = wxBITMAP_PNG_FROM_DATA(DEBUGGER_PAUSE); + m_run = wxBITMAP_PNG_FROM_DATA(DEBUGGER_PLAY); m_toolbar->AddTool(TOOL_ID_PAUSE, wxEmptyString, m_pause, wxNullBitmap, wxITEM_NORMAL, _("Break (F5)"), wxEmptyString, NULL); - m_toolbar->AddTool(TOOL_ID_STEP_INTO, wxEmptyString, wxBITMAP_PNG(DEBUGGER_STEP_INTO), wxNullBitmap, wxITEM_NORMAL, _("Step Into (F11)"), wxEmptyString, NULL); - m_toolbar->AddTool(TOOL_ID_STEP_OVER, wxEmptyString, wxBITMAP_PNG(DEBUGGER_STEP_OVER), wxNullBitmap, wxITEM_NORMAL, _("Step Over (F10)"), wxEmptyString, NULL); + m_toolbar->AddTool(TOOL_ID_STEP_INTO, wxEmptyString, wxBITMAP_PNG_FROM_DATA(DEBUGGER_STEP_INTO), wxNullBitmap, wxITEM_NORMAL, _("Step Into (F11)"), wxEmptyString, NULL); + m_toolbar->AddTool(TOOL_ID_STEP_OVER, wxEmptyString, wxBITMAP_PNG_FROM_DATA(DEBUGGER_STEP_OVER), wxNullBitmap, wxITEM_NORMAL, _("Step Over (F10)"), wxEmptyString, NULL); m_toolbar->AddSeparator(); m_toolbar->Realize(); m_toolbar->EnableTool(TOOL_ID_STEP_INTO, false); m_toolbar->EnableTool(TOOL_ID_STEP_OVER, false); + } void DebuggerWindow2::SaveModuleStorage(const RPLModule* module, bool delete_breakpoints) diff --git a/src/gui/input/InputSettings2.cpp b/src/gui/input/InputSettings2.cpp index e5f4891d..37bd604f 100644 --- a/src/gui/input/InputSettings2.cpp +++ b/src/gui/input/InputSettings2.cpp @@ -29,9 +29,7 @@ #include "gui/input/settings/WiimoteControllerSettings.h" #include "util/EventService.h" -#if BOOST_OS_LINUX #include "resource/embedded/resources.h" -#endif bool g_inputConfigWindowHasFocus = false; @@ -70,9 +68,9 @@ InputSettings2::InputSettings2(wxWindow* parent) g_inputConfigWindowHasFocus = true; - m_connected = wxBITMAP_PNG(INPUT_CONNECTED); - m_disconnected = wxBITMAP_PNG(INPUT_DISCONNECTED); - m_low_battery = wxBITMAP_PNG(INPUT_LOW_BATTERY); + m_connected = wxBITMAP_PNG_FROM_DATA(INPUT_CONNECTED); + m_disconnected = wxBITMAP_PNG_FROM_DATA(INPUT_DISCONNECTED); + m_low_battery = wxBITMAP_PNG_FROM_DATA(INPUT_LOW_BATTERY); auto* sizer = new wxBoxSizer(wxVERTICAL); diff --git a/src/resource/cemu.rc b/src/resource/cemu.rc index 9ff27732..860ca8fb 100644 --- a/src/resource/cemu.rc +++ b/src/resource/cemu.rc @@ -109,36 +109,6 @@ END // RCDATA // -DEBUGGER_BP RCDATA "resource\\debugger\\icons8-full-moon-filled-50.png" - -DEBUGGER_BP_RED RCDATA "resource\\debugger\\icons8-full-moon-filled-50-red.png" - -DEBUGGER_PAUSE RCDATA "resource\\debugger\\icons8-pause-filled-50.png" - -DEBUGGER_PLAY RCDATA "resource\\debugger\\icons8-play-filled-50.png" - -DEBUGGER_STEP_INTO RCDATA "resource\\debugger\\icons8-step-into-50.png" - -DEBUGGER_STEP_OUT RCDATA "resource\\debugger\\icons8-step-out-50.png" - -DEBUGGER_STEP_OVER RCDATA "resource\\debugger\\icons8-step-over-50.png" - -DEBUGGER_GOTO RCDATA "resource\\debugger\\icons8-drop-down-50.png" - -INPUT_CONNECTED RCDATA "resource\\input\\icons8-connected-50.png" - -INPUT_DISCONNECTED RCDATA "resource\\input\\icons8-disconnected-50.png" - -INPUT_LOW_BATTERY RCDATA "resource\\input\\icons8-low-battery-30.png" - -PNG_HELP RCDATA "resource\\icons8-help-24.png" - -PNG_REFRESH RCDATA "resource\\icons8-refresh-32.png" - -PNG_ERROR RCDATA "resource\\icons8-error-32.png" - -PNG_CHECK_YES RCDATA "resource\\icons8-checkmark-yes-32.png" - IDR_FONTAWESOME RCDATA "resource\\fontawesome-webfont.ttf" #endif // Neutral (Default) (unknown sub-lang: 0x8) resources From 9f02733a0dfa7f8e35bbe0ed245b443b23c6f4a8 Mon Sep 17 00:00:00 2001 From: SSimco <37044560+SSimco@users.noreply.github.com> Date: Sun, 18 Sep 2022 18:07:26 -0700 Subject: [PATCH 014/638] Use unordered_map for keydown to allow codes above 255 (#248) - Adds internal support for 32bit key codes, required for proper keyboard input on Linux - Use gdk_keyval_name to get key name on Linux --- src/gui/CemuApp.cpp | 12 +++--- src/gui/guiWrapper.cpp | 18 +++++--- src/gui/guiWrapper.h | 41 ++++++++++++++++++- src/gui/input/panels/InputPanel.cpp | 39 ++++++++++-------- src/imgui/imgui_extension.cpp | 17 ++++++-- src/input/api/Controller.cpp | 27 ++++++------ src/input/api/ControllerState.h | 3 +- src/input/api/DSU/DSUController.cpp | 6 +-- .../api/DirectInput/DirectInputController.cpp | 20 ++++----- src/input/api/Keyboard/KeyboardController.cpp | 23 ++++------- src/input/api/SDL/SDLController.cpp | 2 +- .../api/Wiimote/NativeWiimoteController.cpp | 11 +++-- src/input/api/XInput/XInputController.cpp | 3 +- src/input/emulated/EmulatedController.cpp | 4 +- 14 files changed, 143 insertions(+), 83 deletions(-) diff --git a/src/gui/CemuApp.cpp b/src/gui/CemuApp.cpp index c3270bed..de60f8bc 100644 --- a/src/gui/CemuApp.cpp +++ b/src/gui/CemuApp.cpp @@ -170,16 +170,16 @@ int CemuApp::FilterEvent(wxEvent& event) { const auto& key_event = (wxKeyEvent&)event; wxGetKeyState(wxKeyCode::WXK_F17); - uint32 keycode=fix_raw_keycode(key_event.GetRawKeyCode(), key_event.GetRawKeyFlags()); - if(keycode<256) - g_window_info.keydown[keycode] = true; + g_window_info.set_keystate(fix_raw_keycode(key_event.GetRawKeyCode(), key_event.GetRawKeyFlags()), true); } else if(event.GetEventType() == wxEVT_KEY_UP) { const auto& key_event = (wxKeyEvent&)event; - uint32 keycode=fix_raw_keycode(key_event.GetRawKeyCode(), key_event.GetRawKeyFlags()); - if(keycode<256) - g_window_info.keydown[keycode] = false; + g_window_info.set_keystate(fix_raw_keycode(key_event.GetRawKeyCode(), key_event.GetRawKeyFlags()), false); + } + else if(event.GetEventType() == wxEVT_KILL_FOCUS) + { + g_window_info.set_keystatesdown(); } return wxApp::FilterEvent(event); diff --git a/src/gui/guiWrapper.cpp b/src/gui/guiWrapper.cpp index 6c06f4f9..835dc499 100644 --- a/src/gui/guiWrapper.cpp +++ b/src/gui/guiWrapper.cpp @@ -153,6 +153,15 @@ bool gui_isPadWindowOpen() #include typedef void GdkDisplay; +namespace +{ +const char* (*gdk_keyval_name)(unsigned int keyval); +} +std::string gui_gtkRawKeyCodeToString(uint32 keyCode) +{ + return gdk_keyval_name(keyCode); +} + #endif void gui_initHandleContextFromWxWidgetsWindow(WindowHandleInfo& handleInfoOut, class wxWindow* wxw) @@ -176,9 +185,11 @@ void gui_initHandleContextFromWxWidgetsWindow(WindowHandleInfo& handleInfoOut, c Window (*dyn_gdk_x11_window_get_xid)(GdkWindow *window); dyn_gdk_x11_window_get_xid = (Window(*)(GdkWindow *window))dlsym(RTLD_NEXT, "gdk_x11_window_get_xid"); + gdk_keyval_name = (const char* (*)(unsigned int))dlsym(RTLD_NEXT, "gdk_keyval_name"); + if(!dyn_gtk_widget_realize || !dyn_gtk_widget_get_window || !dyn_gdk_window_get_display || !dyn_gdk_x11_display_get_xdisplay || - !dyn_gdk_x11_window_get_xid) + !dyn_gdk_x11_window_get_xid || !gdk_keyval_name) { cemuLog_log(LogType::Force, "Unable to load GDK symbols"); return; @@ -206,10 +217,7 @@ void gui_initHandleContextFromWxWidgetsWindow(WindowHandleInfo& handleInfoOut, c bool gui_isKeyDown(int key) { - if (key >= 256) - return false; - - return g_window_info.keydown[key]; + return g_window_info.get_keystate(key); } void gui_notifyGameLoaded() diff --git a/src/gui/guiWrapper.h b/src/gui/guiWrapper.h index a9d3e1b3..ce041efb 100644 --- a/src/gui/guiWrapper.h +++ b/src/gui/guiWrapper.h @@ -41,14 +41,48 @@ struct WindowInfo std::atomic_bool has_screenshot_request; std::atomic_bool is_fullscreen; - std::atomic_bool keydown[256]{}; - + void set_keystate(uint32 keycode, bool state) + { + const std::lock_guard lock(keycode_mutex); + m_keydown[keycode] = state; + }; + bool get_keystate(uint32 keycode) + { + const std::lock_guard lock(keycode_mutex); + auto result = m_keydown.find(keycode); + if (result == m_keydown.end()) + return false; + return result->second; + } + void get_keystates(std::unordered_map& buttons_out) + { + const std::lock_guard lock(keycode_mutex); + for (auto&& button : m_keydown) + { + buttons_out[button.first] = button.second; + } + } + void set_keystatesdown() + { + const std::lock_guard lock(keycode_mutex); + std::for_each(m_keydown.begin(), m_keydown.end(), [](std::pair& el){ el.second = false; }); + } + template + void iter_keystates(fn f) + { + const std::lock_guard lock(keycode_mutex); + std::for_each(m_keydown.cbegin(), m_keydown.cend(), f); + } WindowHandleInfo window_main; WindowHandleInfo window_pad; // canvas WindowHandleInfo canvas_main; WindowHandleInfo canvas_pad; + private: + std::mutex keycode_mutex; + // m_keydown keys must be valid ImGuiKey values + std::unordered_map m_keydown; }; void gui_create(); @@ -68,6 +102,9 @@ bool gui_isFullScreen(); void gui_initHandleContextFromWxWidgetsWindow(WindowHandleInfo& handleInfoOut, class wxWindow* wxw); +#if BOOST_OS_LINUX +std::string gui_gtkRawKeyCodeToString(uint32 keyCode); +#endif /* * Returns true if a screenshot request is queued * Once this function has returned true, it will reset back to diff --git a/src/gui/input/panels/InputPanel.cpp b/src/gui/input/panels/InputPanel.cpp index 5d07c643..b01157c8 100644 --- a/src/gui/input/panels/InputPanel.cpp +++ b/src/gui/input/panels/InputPanel.cpp @@ -41,7 +41,7 @@ void InputPanel::on_timer(const EmulatedControllerPtr& emulated_controller, cons } static bool s_was_idle = true; - if (state.buttons.none()) { + if (!std::any_of(state.buttons.begin(), state.buttons.end(), [](auto el){ return el.second; })) { s_was_idle = true; return; } @@ -49,58 +49,65 @@ void InputPanel::on_timer(const EmulatedControllerPtr& emulated_controller, cons if (!s_was_idle) { return; } - - s_was_idle = false; - for (size_t i = 0; i < state.buttons.size(); ++i) + auto get_button_state = [&](uint32 key_id) { - if (state.buttons[i]) + auto result = state.buttons.find(key_id); + if (result == state.buttons.end()) + return false; + return result->second; + }; + s_was_idle = false; + for(auto && button : state.buttons) + { + if (button.second) { + auto id=button.first; if (controller->has_axis()) { // test if one axis direction is pressed more than the other - if ((i == kAxisXP || i == kAxisXN) && (state.buttons[kAxisYP] || state.buttons[kAxisYN])) + if ((id == kAxisXP || id == kAxisXN) && (get_button_state(kAxisYP) || get_button_state(kAxisYN))) { if (std::abs(state.axis.y) > std::abs(state.axis.x)) continue; } - else if ((i == kAxisYP || i == kAxisYN) && (state.buttons[kAxisXP] || state.buttons[kAxisXN])) + else if ((id == kAxisYP || id == kAxisYN) && (get_button_state(kAxisXP) || get_button_state(kAxisXN))) { if (std::abs(state.axis.x) > std::abs(state.axis.y)) continue; } - else if ((i == kRotationXP || i == kRotationXN) && (state.buttons[kRotationYP] || state.buttons[kRotationYN])) + else if ((id == kRotationXP || id == kRotationXN) && (get_button_state(kRotationYP) || get_button_state(kRotationYN))) { if (std::abs(state.rotation.y) > std::abs(state.rotation.x)) continue; } - else if ((i == kRotationYP || i == kRotationYN) && (state.buttons[kRotationXP] || state.buttons[kRotationXN])) + else if ((id == kRotationYP || id == kRotationYN) && (get_button_state(kRotationXP) || get_button_state(kRotationXN))) { if (std::abs(state.rotation.x) > std::abs(state.rotation.y)) continue; } - else if ((i == kTriggerXP || i == kTriggerXN) && (state.buttons[kTriggerYP] || state.buttons[kTriggerYN])) + else if ((id == kTriggerXP || id == kTriggerXN) && (get_button_state(kTriggerYP) || get_button_state(kTriggerYN))) { if (std::abs(state.trigger.y) > std::abs(state.trigger.x)) continue; } - else if ((i == kTriggerYP || i == kTriggerYN) && (state.buttons[kTriggerXP] || state.buttons[kTriggerXN])) + else if ((id == kTriggerYP || id == kTriggerYN) && (get_button_state(kTriggerXP) || get_button_state(kTriggerXN))) { if (std::abs(state.trigger.x) > std::abs(state.trigger.y)) continue; } // ignore too low button values on configuration - if (i >= kButtonAxisStart) + if (id >= kButtonAxisStart) { - if (controller->get_axis_value(i) < 0.33f) { - forceLogDebug_printf("skipping since value too low %f", controller->get_axis_value(i)); + if (controller->get_axis_value(id) < 0.33f) { + forceLogDebug_printf("skipping since value too low %f", controller->get_axis_value(id)); s_was_idle = true; return; } } } - emulated_controller->set_mapping(mapping, controller, i); - element->SetValue(controller->get_button_name(i)); + emulated_controller->set_mapping(mapping, controller, id); + element->SetValue(controller->get_button_name(id)); element->SetBackgroundColour(kKeyColourNormalMode); m_color_backup[element->GetId()] = kKeyColourNormalMode; break; diff --git a/src/imgui/imgui_extension.cpp b/src/imgui/imgui_extension.cpp index 567a1e9a..c5b1a6be 100644 --- a/src/imgui/imgui_extension.cpp +++ b/src/imgui/imgui_extension.cpp @@ -110,7 +110,8 @@ ImFont* ImGui_GetFont(float size) void ImGui_UpdateWindowInformation(bool mainWindow) { extern WindowInfo g_window_info; - + static std::map keyboard_mapping; + static uint32 current_key = 0; ImGuiIO& io = ImGui::GetIO(); io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; @@ -130,9 +131,17 @@ void ImGui_UpdateWindowInformation(bool mainWindow) bool padDown; const auto pos = instance.get_left_down_mouse_info(&padDown); io.MouseDown[0] = padDown != mainWindow && pos.has_value(); - - std::fill_n(io.KeysDown, std::size(io.KeysDown), false); - std::copy(std::cbegin(g_window_info.keydown), std::cend(g_window_info.keydown), io.KeysDown); + auto get_mapping = [&](uint32 key_code) + { + auto key = keyboard_mapping.find(key_code); + if (key != keyboard_mapping.end()) + return key->second; + ImGuiKey mapped_key = current_key + ImGuiKey_NamedKey_BEGIN; + current_key = (current_key + 1) % ImGuiKey_NamedKey_COUNT ; + keyboard_mapping[key_code] = mapped_key; + return mapped_key; + }; + g_window_info.iter_keystates([&](auto&& el){ io.AddKeyEvent(get_mapping(el.first), el.second); }); // printf("%f %f %d\n", io.MousePos.x, io.MousePos.y, io.MouseDown[0]); diff --git a/src/input/api/Controller.cpp b/src/input/api/Controller.cpp index 0027392b..a75cdf57 100644 --- a/src/input/api/Controller.cpp +++ b/src/input/api/Controller.cpp @@ -15,8 +15,10 @@ const ControllerState& ControllerBase::update_state() ControllerState result = raw_state(); // ignore default buttons - result.buttons &= ~m_default_state.buttons; - + for (auto&& el : m_default_state.buttons) + { + result.buttons[el.first] = result.buttons[el.first] && !el.second; + } // apply deadzone and range and ignore default axis values apply_axis_setting(result.axis, m_default_state.axis, m_settings.axis); apply_axis_setting(result.rotation, m_default_state.rotation, m_settings.rotation); @@ -24,22 +26,22 @@ const ControllerState& ControllerBase::update_state() #define APPLY_AXIS_BUTTON(_axis_, _flag_) \ if (result._axis_.x < -ControllerState::kAxisThreshold) \ - result.buttons.set((_flag_) + (kAxisXN - kAxisXP)); \ + result.buttons[(_flag_) + (kAxisXN - kAxisXP)]=true; \ else if (result._axis_.x > ControllerState::kAxisThreshold) \ - result.buttons.set((_flag_)); \ + result.buttons[(_flag_)]=true; \ if (result._axis_.y < -ControllerState::kAxisThreshold) \ - result.buttons.set((_flag_) + 1 + (kAxisXN - kAxisXP)); \ + result.buttons[(_flag_) + 1 + (kAxisXN - kAxisXP)]=true; \ else if (result._axis_.y > ControllerState::kAxisThreshold) \ - result.buttons.set((_flag_) + 1); + result.buttons[(_flag_) + 1]=true; if (result.axis.x < -ControllerState::kAxisThreshold) - result.buttons.set((kAxisXP) + (kAxisXN - kAxisXP)); + result.buttons[(kAxisXP) + (kAxisXN - kAxisXP)]=true; else if (result.axis.x > ControllerState::kAxisThreshold) - result.buttons.set((kAxisXP)); + result.buttons[(kAxisXP)]=true; if (result.axis.y < -ControllerState::kAxisThreshold) - result.buttons.set((kAxisXP) + 1 + (kAxisXN - kAxisXP)); + result.buttons[(kAxisXP) + 1 + (kAxisXN - kAxisXP)]=true; else if (result.axis.y > ControllerState::kAxisThreshold) - result.buttons.set((kAxisXP) + 1);; + result.buttons[(kAxisXP) + 1]=true; APPLY_AXIS_BUTTON(rotation, kRotationXP); APPLY_AXIS_BUTTON(trigger, kTriggerXP); @@ -68,7 +70,7 @@ const ControllerState& ControllerBase::update_state() #undef APPLY_AXIS_BUTTON - m_last_state = result; + m_last_state = std::move(result); return m_last_state; } @@ -127,7 +129,8 @@ bool ControllerBase::operator==(const ControllerBase& c) const float ControllerBase::get_axis_value(uint64 button) const { - if (m_last_state.buttons.test(button)) + auto buttonState=m_last_state.buttons.find(button); + if (buttonState!=m_last_state.buttons.end() && buttonState->second) { if (button <= kButtonNoneAxisMAX || !has_axis()) return 1.0f; diff --git a/src/input/api/ControllerState.h b/src/input/api/ControllerState.h index 2739b2ef..a8ff6628 100644 --- a/src/input/api/ControllerState.h +++ b/src/input/api/ControllerState.h @@ -1,6 +1,5 @@ #pragma once -#include #include struct ControllerState @@ -18,7 +17,7 @@ struct ControllerState glm::vec2 rotation{ }; glm::vec2 trigger{ }; - std::bitset<256> buttons{}; + std::unordered_map buttons{}; uint64 last_state = 0; diff --git a/src/input/api/DSU/DSUController.cpp b/src/input/api/DSU/DSUController.cpp index 1a961a4a..c04c8453 100644 --- a/src/input/api/DSU/DSUController.cpp +++ b/src/input/api/DSU/DSUController.cpp @@ -137,7 +137,7 @@ ControllerState DSUController::raw_state() { if (HAS_BIT(state.data.state1, i)) { - result.buttons.set(bitindex); + result.buttons[bitindex]=true; } } @@ -145,12 +145,12 @@ ControllerState DSUController::raw_state() { if (HAS_BIT(state.data.state2, i)) { - result.buttons.set(bitindex); + result.buttons[bitindex]=true; } } if (state.data.touch) - result.buttons.set(kButton16); + result.buttons[kButton16]=true; result.axis.x = (float)state.data.lx / std::numeric_limits::max(); result.axis.x = (result.axis.x * 2.0f) - 1.0f; diff --git a/src/input/api/DirectInput/DirectInputController.cpp b/src/input/api/DirectInput/DirectInputController.cpp index 9db551ed..87bd3685 100644 --- a/src/input/api/DirectInput/DirectInputController.cpp +++ b/src/input/api/DirectInput/DirectInputController.cpp @@ -278,7 +278,7 @@ ControllerState DirectInputController::raw_state() { if (HAS_BIT(state.rgbButtons[i], 7)) { - result.buttons.set(i); + result.buttons[i]=true; } } @@ -316,19 +316,19 @@ ControllerState DirectInputController::raw_state() { switch (pov) { - case 0: result.buttons.set(kButtonUp); + case 0: result.buttons[kButtonUp]=true; break; - case 4500: result.buttons.set(kButtonUp); // up + right - case 9000: result.buttons.set(kButtonRight); + case 4500: result.buttons[kButtonUp]=true; // up + right + case 9000: result.buttons[kButtonRight]=true; break; - case 13500: result.buttons.set(kButtonRight); // right + down - case 18000: result.buttons.set(kButtonDown); + case 13500: result.buttons[kButtonRight] = true; // right + down + case 18000: result.buttons[kButtonDown] = true; break; - case 22500: result.buttons.set(kButtonDown); // down + left - case 27000: result.buttons.set(kButtonLeft); + case 22500: result.buttons[kButtonDown] = true; // down + left + case 27000: result.buttons[kButtonLeft] = true; break; - case 31500: result.buttons.set(kButtonLeft);; // left + up - result.buttons.set(kButtonUp); // left + up + case 31500: result.buttons[kButtonLeft] = true; // left + up + result.buttons[kButtonUp] = true; // left + up break; } } diff --git a/src/input/api/Keyboard/KeyboardController.cpp b/src/input/api/Keyboard/KeyboardController.cpp index d8bc0a04..0d41fe1a 100644 --- a/src/input/api/Keyboard/KeyboardController.cpp +++ b/src/input/api/Keyboard/KeyboardController.cpp @@ -35,9 +35,13 @@ std::string KeyboardController::get_button_name(uint64 button) const char key_name[128]; if (GetKeyNameTextA(scan_code, key_name, std::size(key_name)) != 0) return key_name; -#endif - + else + return fmt::format("key_{}", button); +#elif BOOST_OS_LINUX + return gui_gtkRawKeyCodeToString(button); +#else return fmt::format("key_{}", button); +#endif } extern WindowInfo g_window_info; @@ -47,20 +51,7 @@ ControllerState KeyboardController::raw_state() ControllerState result{}; if (g_window_info.app_active) { - static_assert(result.buttons.size() == std::size(g_window_info.keydown), "invalid size"); - for (uint32 i = wxKeyCode::WXK_BACK; i < result.buttons.size(); ++i) - { - if(const bool v = g_window_info.keydown[i]) - { - result.buttons.set(i, v); - } - } - // ignore generic key codes on Windows when there is also a left/right variant -#if BOOST_OS_WINDOWS - result.buttons.set(VK_SHIFT, false); - result.buttons.set(VK_CONTROL, false); - result.buttons.set(VK_MENU, false); -#endif + g_window_info.get_keystates(result.buttons); } return result; } diff --git a/src/input/api/SDL/SDLController.cpp b/src/input/api/SDL/SDLController.cpp index 0a0e3067..63f7f4d3 100644 --- a/src/input/api/SDL/SDLController.cpp +++ b/src/input/api/SDL/SDLController.cpp @@ -147,7 +147,7 @@ ControllerState SDLController::raw_state() { if (m_buttons[i] && SDL_GameControllerGetButton(m_controller, (SDL_GameControllerButton)i)) { - result.buttons.set(i); + result.buttons[i]=true; } } diff --git a/src/input/api/Wiimote/NativeWiimoteController.cpp b/src/input/api/Wiimote/NativeWiimoteController.cpp index 1396f1b4..c5059f7c 100644 --- a/src/input/api/Wiimote/NativeWiimoteController.cpp +++ b/src/input/api/Wiimote/NativeWiimoteController.cpp @@ -206,23 +206,26 @@ ControllerState NativeWiimoteController::raw_state() return result; const auto state = m_provider->get_state(m_index); - result.buttons = state.buttons; + for (int i = 0; i < std::numeric_limits::digits; i++) + result.buttons[i] = state.buttons & (1<(state.m_extension)) { const auto nunchuck = std::get(state.m_extension); if (nunchuck.c) - result.buttons.set(kWiimoteButton_C); + result.buttons[kWiimoteButton_C]=true; if (nunchuck.z) - result.buttons.set(kWiimoteButton_Z); + result.buttons[kWiimoteButton_Z]=true; result.axis = nunchuck.axis; } else if (std::holds_alternative(state.m_extension)) { const auto classic = std::get(state.m_extension); - result.buttons |= (uint64)classic.buttons << kHighestWiimote; + uint64 buttons = (uint64)classic.buttons << kHighestWiimote; + for (int i = 0; i < std::numeric_limits::digits; i++) + result.buttons[i] = result.buttons[i] || (buttons & (1 << i)); result.axis = classic.left_axis; result.rotation = classic.right_axis; diff --git a/src/input/api/XInput/XInputController.cpp b/src/input/api/XInput/XInputController.cpp index 08d6510d..e2be29b6 100644 --- a/src/input/api/XInput/XInputController.cpp +++ b/src/input/api/XInput/XInputController.cpp @@ -120,7 +120,8 @@ ControllerState XInputController::raw_state() } // Buttons - result.buttons = state.Gamepad.wButtons; + for(int i=0;i::digits;i++) + result.buttons[i] = state.Gamepad.wButtons & (1< 0) result.axis.x = (float)state.Gamepad.sThumbLX / std::numeric_limits::max(); diff --git a/src/input/emulated/EmulatedController.cpp b/src/input/emulated/EmulatedController.cpp index 69c058f7..0028db58 100644 --- a/src/input/emulated/EmulatedController.cpp +++ b/src/input/emulated/EmulatedController.cpp @@ -280,7 +280,9 @@ bool EmulatedController::is_mapping_down(uint64 mapping) const if (it != m_mappings.cend()) { if (const auto controller = it->second.controller.lock()) { - return controller->get_state().buttons.test(it->second.button); + auto& buttons=controller->get_state().buttons; + auto buttonState=buttons.find(it->second.button); + return buttonState!=buttons.end() && buttonState->second; } } From 510d80038d2adfdc47e51ae24404ec3fb5136635 Mon Sep 17 00:00:00 2001 From: Crementif <26669564+Crementif@users.noreply.github.com> Date: Mon, 19 Sep 2022 21:41:01 +0200 Subject: [PATCH 015/638] [coreinit] Add OSIsDebuggerPresent --- src/Cafe/OS/libs/coreinit/coreinit.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Cafe/OS/libs/coreinit/coreinit.cpp b/src/Cafe/OS/libs/coreinit/coreinit.cpp index 4a9f3f30..1869f55c 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit.cpp @@ -230,6 +230,11 @@ namespace coreinit return 0; } + uint32 OSIsDebuggerPresent() + { + return 0; + } + uint32 OSGetConsoleType() { return 0x03000050; @@ -295,6 +300,7 @@ namespace coreinit cafeExportRegister("coreinit", OSGetCoreId, LogType::CoreinitThread); cafeExportRegister("coreinit", OSGetCoreCount, LogType::CoreinitThread); cafeExportRegister("coreinit", OSIsDebuggerInitialized, LogType::CoreinitThread); + cafeExportRegister("coreinit", OSIsDebuggerPresent, LogType::CoreinitThread); cafeExportRegister("coreinit", OSGetConsoleType, LogType::CoreinitThread); cafeExportRegister("coreinit", OSGetMainCoreId, LogType::CoreinitThread); cafeExportRegister("coreinit", OSIsMainCore, LogType::CoreinitThread); From 6fa0ac6eaacf997cca19b7995078ff902489614f Mon Sep 17 00:00:00 2001 From: Crementif <26669564+Crementif@users.noreply.github.com> Date: Tue, 20 Sep 2022 00:04:40 +0200 Subject: [PATCH 016/638] [docs] Recommend PUBLIC_RELEASE Most people following the guide are currently not really developers and this was a fairly hidden option that's easily missed. The disabled version will later change to be an actual custom cmake target instead of a preprocessor flag, but that'll require more code to be adjusted. Not using the flag means that Cemu keeps some (performance-costing) debug checks in, alongside more logging and a debug logging console on Windows. --- BUILD.md | 6 +++--- generate_vs_solution.bat | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/BUILD.md b/BUILD.md index 6141d6a5..6bb08c71 100644 --- a/BUILD.md +++ b/BUILD.md @@ -30,7 +30,7 @@ To compile Cemu, a recent enough compiler and STL with C++20 support is required *Additionally, for Ubuntu 22.04 only:* - `sudo apt install -y clang-12` - At step 3 while building, use - `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang-12 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-12 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja` + `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DPUBLIC_RELEASE=ON -DCMAKE_C_COMPILER=/usr/bin/clang-12 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-12 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja` #### For Arch and derivatives: `sudo pacman -S git cmake clang ninja nasm base-devel linux-headers gtk3 libsecret libgcrypt systemd freeglut zip unzip libpulse` @@ -41,14 +41,14 @@ To compile Cemu, a recent enough compiler and STL with C++20 support is required ### Build Cemu using cmake and clang 1. `git clone --recursive https://github.com/cemu-project/Cemu` 2. `cd Cemu` -3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -G Ninja` +3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DPUBLIC_RELEASE=ON -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -G Ninja` 4. `cmake --build build` 5. You should now have a Cemu executable file in the /bin folder, which you can run using `./bin/Cemu_release`. #### Using GCC While we use and test Cemu using clang, using GCC might work better with your distro (they should be fairly similar performance/issues wise and should only be considered if compilation is the issue). You can use it by replacing the step 3 with the following: -`cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ -G Ninja` +`cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DPUBLIC_RELEASE=ON -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ -G Ninja` #### Troubleshooting steps - If step 3 gives you an error about not being able to find ninja, try appending `-DCMAKE_MAKE_PROGRAM=/usr/bin/ninja` to the command and running it again. diff --git a/generate_vs_solution.bat b/generate_vs_solution.bat index 21060027..dfef2e80 100644 --- a/generate_vs_solution.bat +++ b/generate_vs_solution.bat @@ -1,2 +1,2 @@ -"C:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\2022\COMMUNITY\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\CMAKE\CMake\bin\cmake.exe" -B build/ +"C:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\2022\COMMUNITY\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\CMAKE\CMake\bin\cmake.exe" -B build/ -DPUBLIC_RELEASE=ON pause \ No newline at end of file From 7864d76ecaff3ce500c6d3f09910fbb24027efd7 Mon Sep 17 00:00:00 2001 From: Tillsunset <35825944+Tillsunset@users.noreply.github.com> Date: Tue, 20 Sep 2022 07:50:34 -0500 Subject: [PATCH 017/638] fixed the string encoding issue on macOS (#277) --- src/gui/MemorySearcherTool.cpp | 4 ++-- src/gui/components/wxLogCtrl.cpp | 5 +++-- src/gui/components/wxTitleManagerList.cpp | 8 ++++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/gui/MemorySearcherTool.cpp b/src/gui/MemorySearcherTool.cpp index 3423e73b..5caa163f 100644 --- a/src/gui/MemorySearcherTool.cpp +++ b/src/gui/MemorySearcherTool.cpp @@ -300,14 +300,14 @@ void MemorySearcherTool::Load() bool found = false; for (const auto& entry : kDataTypeNames) { - if (boost::iequals(entry, *option_type)) + if (boost::iequals(entry.ToStdString(), *option_type)) { found = true; break; } } - if (!found && !boost::iequals(kDatatypeString, *option_type)) + if (!found && !boost::iequals(kDatatypeString.ToStdString(), *option_type)) continue; wxVector data; diff --git a/src/gui/components/wxLogCtrl.cpp b/src/gui/components/wxLogCtrl.cpp index 50356d29..732dd26d 100644 --- a/src/gui/components/wxLogCtrl.cpp +++ b/src/gui/components/wxLogCtrl.cpp @@ -68,7 +68,7 @@ void wxLogCtrl::PushEntry(const wxString& filter, const wxString& message) ListIt_t it = m_log_entries.back(); lock.unlock(); - if(m_active_filter.empty() || filter == m_active_filter || (m_filter_messages && boost::icontains(message, m_active_filter))) + if(m_active_filter.empty() || filter == m_active_filter || (m_filter_messages && boost::icontains(message.ToStdString(), m_active_filter))) { std::unique_lock active_lock(m_active_mutex); m_active_entries.emplace_back(std::cref(it)); @@ -149,7 +149,8 @@ void wxLogCtrl::UpdateActiveEntries() { for (const auto& it : m_log_entries) { - if(it.first == m_active_filter || (m_filter_messages && boost::icontains(it.second, m_active_filter)) ) + if(it.first == m_active_filter || + (m_filter_messages && boost::icontains(it.second.ToStdString(), m_active_filter)) ) m_active_entries.emplace_back(it); } } diff --git a/src/gui/components/wxTitleManagerList.cpp b/src/gui/components/wxTitleManagerList.cpp index 8f43630d..c00848c6 100644 --- a/src/gui/components/wxTitleManagerList.cpp +++ b/src/gui/components/wxTitleManagerList.cpp @@ -197,10 +197,10 @@ boost::optional wxTitleManagerList::GetTitleEnt boost::optional wxTitleManagerList::GetTitleEntry(const fs::path& path) const { - const auto tmp = path.generic_u8string(); + const auto tmp = _pathToUtf8(path); for (const auto& data : m_data) { - if (boost::iequals(data->entry.path.generic_u8string(), tmp)) + if (boost::iequals(_pathToUtf8(data->entry.path), tmp)) return data->entry; } @@ -208,10 +208,10 @@ boost::optional wxTitleManagerList::GetTi } boost::optional wxTitleManagerList::GetTitleEntry(const fs::path& path) { - const auto tmp = path.generic_u8string(); + const auto tmp = _pathToUtf8(path); for (const auto& data : m_data) { - if (boost::iequals(data->entry.path.generic_u8string(), tmp)) + if (boost::iequals(_pathToUtf8(data->entry.path), tmp)) return data->entry; } From 030d15900df76d20979df893483e0efcaf57866d Mon Sep 17 00:00:00 2001 From: Tillsunset <35825944+Tillsunset@users.noreply.github.com> Date: Tue, 20 Sep 2022 13:26:54 -0500 Subject: [PATCH 018/638] Add MacOS build instructions (#279) --- BUILD.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/BUILD.md b/BUILD.md index 6bb08c71..aef76a81 100644 --- a/BUILD.md +++ b/BUILD.md @@ -59,6 +59,28 @@ You can use it by replacing the step 3 with the following: - If step 4 gives you a different error, you could report it to this repo or try using GCC. Just make sure your standard library and compilers are updated since Cemu uses a lot of modern features! - If step 4 gives you undefined libdecor_xx, you are likely experiencing an issue with sdl2 package that comes with vcpkg. Delete sdl2 from vcpkg.json in source file and recompile. +## MacOS + +To compile Cemu, a recent enough compiler and STL with C++20 support is required! LLVM 13 and +below, built in LLVM, and Xcode LLVM don't support the C++20 feature set required. Currently, +LLVM 15 isn't supported due to compatibility issues with Boost dependency. The OpenGL graphics +API isn't support on MacOS, Vulkan must be used. Additionally Vulkan must be used through the +Molten-VK compatibility layer. + +### Installing dependencies +`brew install git cmake llvm@14 ninja nasm molten-vk` + +### Build Cemu using cmake and clang +1. `git clone --recursive https://github.com/cemu-project/Cemu` +2. `cd Cemu` +3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DPUBLIC_RELEASE=ON + -DCMAKE_C_COMPILER=/usr/local/opt/llvm@14/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@14/bin/clang++ -G Ninja` +4. `cmake --build build` +5. You should now have a Cemu executable file in the /bin folder, which you can run using `./bin/Cemu_release`. + +#### Troubleshooting steps +- If step 3 gives you an error about not being able to find ninja, try appending `-DCMAKE_MAKE_PROGRAM=/usr/local/bin/ninja` to the command and running it again. + ## Updating Cemu and source code 1. To update your Cemu local repository, use the command `git pull --recurse-submodules` (run this command on the Cemu root). - This should update your local copy of Cemu and all of its dependencies. From 9b76b0e2d33725d37dc8c6137d8ea2fa9b991542 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Thu, 22 Sep 2022 11:34:13 +0200 Subject: [PATCH 019/638] CI: Fix Windows build running out of disk space (#284) - Clean package temporaries during building to save disk space - Remove msvc workaround which is no longer needed --- .github/workflows/build.yml | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 362cf3bc..f97765d0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -114,35 +114,6 @@ jobs: echo "[INFO] Experimental version ${{ inputs.experimentalversion }}" echo "BUILD_FLAGS=${{ env.BUILD_FLAGS }} -DEXPERIMENTAL_VERSION=${{ inputs.experimentalversion }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - - name: Workaround - run: | - Set-Location "C:\Program Files (x86)\Microsoft Visual Studio\Installer\" - $InstallPath = "C:\Program Files\Microsoft Visual Studio\2022\Enterprise" - $componentsToRemove= @( - "Microsoft.VisualStudio.Component.VC.14.32.17.2.ARM" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.ARM.Spectre" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.ARM64" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.ARM64.Spectre" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.x86.x64" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.x86.x64.Spectre" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.ATL" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.ATL.Spectre" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.ATL.ARM" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.ATL.ARM.Spectre" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.ATL.ARM64" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.ATL.ARM64.Spectre" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.MFC" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.MFC.Spectre" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.MFC.ARM" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.MFC.ARM.Spectre" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.MFC.ARM64" - "Microsoft.VisualStudio.Component.VC.14.32.17.2.MFC.ARM64.Spectre" - ) - [string]$workloadArgs = $componentsToRemove | ForEach-Object {" --remove " + $_} - $Arguments = ('/c', "vs_installer.exe", 'modify', '--installPath', "`"$InstallPath`"",$workloadArgs, '--quiet', '--norestart', '--nocache') - # should be run twice - $process = Start-Process -FilePath cmd.exe -ArgumentList $Arguments -Wait -PassThru -WindowStyle Hidden - $process = Start-Process -FilePath cmd.exe -ArgumentList $Arguments -Wait -PassThru -WindowStyle Hidden - name: Configure MSVC uses: ilammy/msvc-dev-cmd@v1 with: @@ -174,7 +145,7 @@ jobs: cd build echo "[INFO] BUILD_FLAGS: ${{ env.BUILD_FLAGS }}" echo "[INFO] BUILD_MODE: ${{ env.BUILD_MODE }}" - cmake .. ${{ env.BUILD_FLAGS }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} + cmake .. ${{ env.BUILD_FLAGS }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} -DVCPKG_INSTALL_OPTIONS="--clean-after-build" - name: "Build Cemu" run: | From b720d17a977d4d090926ddbb6b6e6e81cb44d37e Mon Sep 17 00:00:00 2001 From: jcrm1 <52137472+jcrm1@users.noreply.github.com> Date: Fri, 23 Sep 2022 05:17:50 -0400 Subject: [PATCH 020/638] CI: Add macOS x64 to build check and releases (#274) --- .github/workflows/build.yml | 67 +++++++++++++++++++ .../workflows/deploy_experimental_release.yml | 16 ++++- .github/workflows/deploy_stable_release.yml | 16 ++++- 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f97765d0..ef9eb1a1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -162,3 +162,70 @@ jobs: with: name: cemu-bin-windows-x64 path: ./bin/Cemu.exe + build-macos: + runs-on: macos-12 + steps: + - name: "Checkout repo" + uses: actions/checkout@v3 + with: + submodules: "recursive" + - name: Setup release mode parameters (for deploy) + if: ${{ inputs.deploymode == 'release' }} + run: | + echo "BUILD_MODE=release" >> $GITHUB_ENV + echo "BUILD_FLAGS=-DPUBLIC_RELEASE=ON" >> $GITHUB_ENV + echo "Build mode is release" + - name: Setup debug mode parameters (for continous build) + if: ${{ inputs.deploymode != 'release' }} + run: | + echo "BUILD_MODE=debug" >> $GITHUB_ENV + echo "BUILD_FLAGS=" >> $GITHUB_ENV + echo "Build mode is debug" + + - name: Setup version for experimental + if: ${{ inputs.experimentalversion != '' }} + run: | + echo "[INFO] Experimental version ${{ inputs.experimentalversion }}" + echo "BUILD_FLAGS=${{ env.BUILD_FLAGS }} -DEXPERIMENTAL_VERSION=${{ inputs.experimentalversion }}" >> $GITHUB_ENV + + - name: "Install system dependencies" + run: | + brew install llvm@14 ninja nasm molten-vk + - name: "Bootstrap vcpkg" + run: | + bash ./dependencies/vcpkg/bootstrap-vcpkg.sh + + - name: 'Setup NuGet Credentials for vcpkg' + shell: 'bash' + run: | + mono `./dependencies/vcpkg/vcpkg fetch nuget | tail -n 1` \ + sources add \ + -source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" \ + -storepasswordincleartext \ + -name "GitHub" \ + -username "${{ github.repository_owner }}" \ + -password "${{ secrets.GITHUB_TOKEN }}" + mono `./dependencies/vcpkg/vcpkg fetch nuget | tail -n 1` \ + setapikey "${{ secrets.GITHUB_TOKEN }}" \ + -source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" + + - name: "cmake" + run: | + mkdir build + cd build + cmake .. ${{ env.BUILD_FLAGS }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} -DCMAKE_C_COMPILER=/usr/local/opt/llvm@14/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@14/bin/clang++ -G Ninja + + - name: "Build Cemu" + run: | + cmake --build build + + - name: Prepare artifact + if: ${{ inputs.deploymode == 'release' }} + run: chmod a+x bin/Cemu_release && mv bin/Cemu_release bin/Cemu + + - name: Upload artifact + uses: actions/upload-artifact@v3 + if: ${{ inputs.deploymode == 'release' }} + with: + name: cemu-bin-macos-x64 + path: ./bin/Cemu diff --git a/.github/workflows/deploy_experimental_release.yml b/.github/workflows/deploy_experimental_release.yml index afe3dee7..53afe4a8 100644 --- a/.github/workflows/deploy_experimental_release.yml +++ b/.github/workflows/deploy_experimental_release.yml @@ -25,6 +25,11 @@ jobs: name: cemu-bin-windows-x64 path: cemu-bin-windows-x64 + - uses: actions/download-artifact@v3 + with: + name: cemu-bin-macos-x64 + path: cemu-bin-macos-x64 + - name: Initialize run: | mkdir upload @@ -57,7 +62,16 @@ jobs: mv cemu-bin-linux-x64/Cemu ./${{ env.CEMU_FOLDER_NAME }}/Cemu zip -9 -r upload/cemu-${{ env.CEMU_VERSION }}-ubuntu-20.04-x64.zip ${{ env.CEMU_FOLDER_NAME }} rm -r ./${{ env.CEMU_FOLDER_NAME }} - + + - name: Create release from macos-bin + run: | + ls ./ + ls ./bin/ + cp -R ./bin ./${{ env.CEMU_FOLDER_NAME }} + mv cemu-bin-macos-x64/Cemu ./${{ env.CEMU_FOLDER_NAME }}/Cemu + zip -9 -r upload/cemu-${{ env.CEMU_VERSION }}-macos-12-x64.zip ${{ env.CEMU_FOLDER_NAME }} + rm -r ./${{ env.CEMU_FOLDER_NAME }} + - name: Create release run: | wget -O ghr.tar.gz https://github.com/tcnksm/ghr/releases/download/v0.15.0/ghr_v0.15.0_linux_amd64.tar.gz diff --git a/.github/workflows/deploy_stable_release.yml b/.github/workflows/deploy_stable_release.yml index 7167dcbe..e0a7ac3d 100644 --- a/.github/workflows/deploy_stable_release.yml +++ b/.github/workflows/deploy_stable_release.yml @@ -27,6 +27,11 @@ jobs: name: cemu-bin-windows-x64 path: cemu-bin-windows-x64 + - uses: actions/download-artifact@v3 + with: + name: cemu-bin-macos-x64 + path: cemu-bin-macos-x64 + - name: Initialize run: | mkdir upload @@ -61,7 +66,16 @@ jobs: mv cemu-bin-linux-x64/Cemu ./${{ env.CEMU_FOLDER_NAME }}/Cemu zip -9 -r upload/cemu-${{ env.CEMU_VERSION }}-ubuntu-20.04-x64.zip ${{ env.CEMU_FOLDER_NAME }} rm -r ./${{ env.CEMU_FOLDER_NAME }} - + + - name: Create release from macos-bin + run: | + ls ./ + ls ./bin/ + cp -R ./bin ./${{ env.CEMU_FOLDER_NAME }} + mv cemu-bin-macos-x64/Cemu ./${{ env.CEMU_FOLDER_NAME }}/Cemu + zip -9 -r upload/cemu-${{ env.CEMU_VERSION }}-macos-12-x64.zip ${{ env.CEMU_FOLDER_NAME }} + rm -r ./${{ env.CEMU_FOLDER_NAME }} + - name: Create release run: | wget -O ghr.tar.gz https://github.com/tcnksm/ghr/releases/download/v0.15.0/ghr_v0.15.0_linux_amd64.tar.gz From 3bceb39966e313795f4036d2cb241c0c78ad5b98 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sat, 24 Sep 2022 08:43:27 +0200 Subject: [PATCH 021/638] Remove PUBLIC_RELEASE flag and tie asserts to debug config (#287) Removes the -DPUBLIC_RELEASE flag. Cemu's debug asserts are now only enabled if the build configuration is Debug. Similarly, on Windows the console is only shown for Debug builds. --- .github/workflows/build.yml | 6 ++-- BUILD.md | 6 ++-- CMakeLists.txt | 17 +++++---- CMakeSettings.json | 7 ++-- generate_vs_solution.bat | 2 +- src/CMakeLists.txt | 16 +++------ src/Cafe/GamePatch.cpp | 10 +++--- .../Interpreter/PPCInterpreterALU.hpp | 2 +- .../Interpreter/PPCInterpreterImpl.cpp | 8 ++--- .../Interpreter/PPCInterpreterSPR.hpp | 8 ++--- .../Recompiler/PPCFunctionBoundaryTracker.h | 2 +- .../HW/Espresso/Recompiler/PPCRecompiler.cpp | 2 +- .../Recompiler/PPCRecompilerImlGen.cpp | 10 +++--- .../Recompiler/PPCRecompilerImlOptimizer.cpp | 2 +- .../Recompiler/PPCRecompilerImlRanges.cpp | 14 ++++---- .../PPCRecompilerImlRegisterAllocator.cpp | 10 +++--- .../PPCRecompilerImlRegisterAllocator2.cpp | 12 +++---- src/Cafe/HW/Latte/Core/FetchShader.cpp | 2 +- src/Cafe/HW/Latte/Core/LatteBufferCache.cpp | 2 +- .../HW/Latte/Core/LatteCommandProcessor.cpp | 16 ++++----- src/Cafe/HW/Latte/Core/LatteOverlay.cpp | 2 +- src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp | 2 +- src/Cafe/HW/Latte/Core/LatteRingBuffer.cpp | 2 +- src/Cafe/HW/Latte/Core/LatteShader.cpp | 4 +-- src/Cafe/HW/Latte/Core/LatteSoftware.cpp | 2 +- src/Cafe/HW/Latte/Core/LatteStreamoutGPU.cpp | 2 +- src/Cafe/HW/Latte/Core/LatteTexture.cpp | 2 +- src/Cafe/HW/Latte/Core/LatteTextureLegacy.cpp | 2 +- src/Cafe/HW/Latte/Core/LatteTextureLoader.cpp | 2 +- .../LatteDecompilerAnalyzer.cpp | 4 +-- .../LatteDecompilerEmitGLSL.cpp | 8 ++--- .../Latte/Renderer/OpenGL/LatteTextureGL.cpp | 2 +- .../Renderer/OpenGL/LatteTextureViewGL.cpp | 2 +- src/Cafe/HW/Latte/Renderer/Vulkan/VKRBase.h | 6 ++-- .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 4 +-- .../Renderer/Vulkan/VulkanRendererCore.cpp | 4 +-- src/Cafe/IOSU/fsa/iosu_fsa.cpp | 2 +- src/Cafe/IOSU/kernel/iosu_kernel.cpp | 2 +- src/Cafe/IOSU/legacy/iosu_boss.cpp | 4 +-- src/Cafe/OS/RPL/rpl.cpp | 2 +- src/Cafe/OS/libs/coreinit/coreinit.cpp | 4 +-- src/Cafe/OS/libs/coreinit/coreinit_Alarm.cpp | 2 +- src/Cafe/OS/libs/coreinit/coreinit_FS.cpp | 2 +- .../OS/libs/coreinit/coreinit_LockedCache.cpp | 4 +-- .../libs/coreinit/coreinit_MEM_BlockHeap.cpp | 2 +- .../OS/libs/coreinit/coreinit_MEM_ExpHeap.cpp | 2 +- src/Cafe/OS/libs/coreinit/coreinit_Thread.h | 2 +- src/Cafe/OS/libs/gx2/GX2_RenderTarget.cpp | 4 +-- src/Cafe/OS/libs/gx2/GX2_Surface_Copy.cpp | 4 +-- src/Cafe/OS/libs/nlibcurl/nlibcurl.cpp | 2 +- src/Cafe/OS/libs/nn_fp/nn_fp.cpp | 2 +- src/Cafe/OS/libs/nsyshid/nsyshid.cpp | 2 +- src/Cafe/OS/libs/nsysnet/nsysnet.cpp | 6 ++-- src/Cafe/OS/libs/snd_core/ax_mix.cpp | 2 +- src/Cafe/OS/libs/snd_core/ax_voice.cpp | 2 +- src/Cafe/OS/libs/sysapp/sysapp.cpp | 4 +-- src/Cemu/Logging/CemuDebugLogging.h | 2 +- src/Cemu/Logging/CemuLogging.cpp | 4 --- src/Cemu/Logging/CemuLogging.h | 4 +-- src/Cemu/PPCAssembler/ppcAssembler.cpp | 2 +- src/Cemu/nex/nex.cpp | 2 +- src/Cemu/nex/prudp.cpp | 4 +-- src/Common/precompiled.h | 2 +- src/Common/version.h | 6 ++-- src/gui/MainWindow.cpp | 12 +++---- src/main.cpp | 35 +++++++------------ src/util/Zir/EmitterGLSL/ZpIREmitGLSL.cpp | 2 +- src/util/helpers/helpers.cpp | 5 --- 68 files changed, 154 insertions(+), 186 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ef9eb1a1..ac010c8f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,7 @@ jobs: if: ${{ inputs.deploymode == 'release' }} run: | echo "BUILD_MODE=release" >> $GITHUB_ENV - echo "BUILD_FLAGS=-DPUBLIC_RELEASE=ON" >> $GITHUB_ENV + echo "BUILD_FLAGS=" >> $GITHUB_ENV echo "Build mode is release" - name: Setup debug mode parameters (for continous build) if: ${{ inputs.deploymode != 'release' }} @@ -99,7 +99,7 @@ jobs: if: ${{ inputs.deploymode == 'release' }} run: | echo "BUILD_MODE=release" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - echo "BUILD_FLAGS=-DPUBLIC_RELEASE=ON" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + echo "BUILD_FLAGS=" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append echo "Build mode is release" - name: Setup debug mode parameters (for continous build) @@ -173,7 +173,7 @@ jobs: if: ${{ inputs.deploymode == 'release' }} run: | echo "BUILD_MODE=release" >> $GITHUB_ENV - echo "BUILD_FLAGS=-DPUBLIC_RELEASE=ON" >> $GITHUB_ENV + echo "BUILD_FLAGS=" >> $GITHUB_ENV echo "Build mode is release" - name: Setup debug mode parameters (for continous build) if: ${{ inputs.deploymode != 'release' }} diff --git a/BUILD.md b/BUILD.md index aef76a81..f4d7c72e 100644 --- a/BUILD.md +++ b/BUILD.md @@ -30,7 +30,7 @@ To compile Cemu, a recent enough compiler and STL with C++20 support is required *Additionally, for Ubuntu 22.04 only:* - `sudo apt install -y clang-12` - At step 3 while building, use - `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DPUBLIC_RELEASE=ON -DCMAKE_C_COMPILER=/usr/bin/clang-12 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-12 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja` + `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang-12 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-12 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja` #### For Arch and derivatives: `sudo pacman -S git cmake clang ninja nasm base-devel linux-headers gtk3 libsecret libgcrypt systemd freeglut zip unzip libpulse` @@ -41,14 +41,14 @@ To compile Cemu, a recent enough compiler and STL with C++20 support is required ### Build Cemu using cmake and clang 1. `git clone --recursive https://github.com/cemu-project/Cemu` 2. `cd Cemu` -3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DPUBLIC_RELEASE=ON -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -G Ninja` +3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -G Ninja` 4. `cmake --build build` 5. You should now have a Cemu executable file in the /bin folder, which you can run using `./bin/Cemu_release`. #### Using GCC While we use and test Cemu using clang, using GCC might work better with your distro (they should be fairly similar performance/issues wise and should only be considered if compilation is the issue). You can use it by replacing the step 3 with the following: -`cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DPUBLIC_RELEASE=ON -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ -G Ninja` +`cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ -G Ninja` #### Troubleshooting steps - If step 3 gives you an error about not being able to find ninja, try appending `-DCMAKE_MAKE_PROGRAM=/usr/bin/ninja` to the command and running it again. diff --git a/CMakeLists.txt b/CMakeLists.txt index 483a9eff..e5ddc6fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,5 @@ cmake_minimum_required(VERSION 3.21.1) -option(PUBLIC_RELEASE "Compile with debug asserts disabled and no console" OFF) option(ENABLE_VCPKG "Enable the vcpkg package manager" ON) set(EXPERIMENTAL_VERSION "" CACHE STRING "") # used by CI script to set experimental version @@ -29,13 +28,14 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -if (PUBLIC_RELEASE) - add_compile_definitions(PUBLIC_RELEASE) - set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) # enable LTO -endif() +add_compile_definitions($<$:CEMU_DEBUG_ASSERT>) # if build type is debug, set CEMU_DEBUG_ASSERT set_property(GLOBAL PROPERTY USE_FOLDERS ON) +# enable link time optimization for release builds +set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON) +set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON) + if (MSVC) set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT CemuBin) # floating point model: precise, fiber safe optimizations @@ -48,10 +48,9 @@ if (MSVC) else() add_compile_options(/GT) endif() - if (PUBLIC_RELEASE) - message(STATUS "Using additional optimization flags for MSVC") - add_compile_options(/Oi /Ot) # enable intrinsic functions, favor speed - endif() + # enable additional optimization flags for release builds + add_compile_options($<$:/Oi>) # enable intrinsic functions + add_compile_options($<$:/Ot>) # favor speed endif() if (APPLE) diff --git a/CMakeSettings.json b/CMakeSettings.json index f7f9fe6e..3097caab 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -1,7 +1,7 @@ { "configurations": [ { - "name": "Release", + "name": "RelWithDebInfo", "configurationType": "RelWithDebInfo", "generator": "Ninja", "inheritEnvironments": [ "msvc_x64_x64" ], @@ -9,13 +9,12 @@ "installRoot": "${projectDir}\\out\\install\\${name}" }, { - "name": "Public Release", - "configurationType": "RelWithDebInfo", + "name": "Release", + "configurationType": "Release", "generator": "Ninja", "inheritEnvironments": [ "msvc_x64_x64" ], "buildRoot": "${projectDir}\\out\\build\\${name}", "installRoot": "${projectDir}\\out\\install\\${name}", - "cmakeCommandArgs": "-DPUBLIC_RELEASE=ON" }, { "name": "Debug", diff --git a/generate_vs_solution.bat b/generate_vs_solution.bat index dfef2e80..21060027 100644 --- a/generate_vs_solution.bat +++ b/generate_vs_solution.bat @@ -1,2 +1,2 @@ -"C:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\2022\COMMUNITY\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\CMAKE\CMake\bin\cmake.exe" -B build/ -DPUBLIC_RELEASE=ON +"C:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\2022\COMMUNITY\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\CMAKE\CMake\bin\cmake.exe" -B build/ pause \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d3bf8aec..024432d0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,17 +54,10 @@ add_subdirectory(imgui) add_subdirectory(resource) add_subdirectory(asm) -if(PUBLIC_RELEASE) - add_executable(CemuBin WIN32 - main.cpp - mainLLE.cpp - ) -else() - add_executable(CemuBin - main.cpp - mainLLE.cpp - ) -endif() +add_executable(CemuBin + main.cpp + mainLLE.cpp +) if(WIN32) target_sources(CemuBin PRIVATE @@ -73,6 +66,7 @@ if(WIN32) endif() set_property(TARGET CemuBin PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") +set_property(TARGET CemuBin PROPERTY WIN32_EXECUTABLE $>) set_target_properties(CemuBin PROPERTIES # multi-configuration generators will add a config subdirectory to RUNTIME_OUTPUT_DIRECTORY if no generator expression is used diff --git a/src/Cafe/GamePatch.cpp b/src/Cafe/GamePatch.cpp index e5a67d98..0d5e30ab 100644 --- a/src/Cafe/GamePatch.cpp +++ b/src/Cafe/GamePatch.cpp @@ -199,7 +199,7 @@ MPTR hle_locate(uint8* data, uint8* mask, sint32 dataLength) } else { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (mask[0] != 0xFF) assert_dbg(); #endif @@ -299,7 +299,7 @@ void GamePatch_scan() hleAddr = hle_locate(xcx_gpuHangDetection_degradeFramebuffer, NULL, sizeof(xcx_gpuHangDetection_degradeFramebuffer)); if( hleAddr ) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT forceLog_printf("HLE: XCX GPU hang detection"); #endif // remove the ADDI r25, r25, 1 instruction @@ -309,7 +309,7 @@ void GamePatch_scan() hleAddr = hle_locate(xcx_framebufferReductionSignature, xcx_framebufferReductionMask, sizeof(xcx_framebufferReductionSignature)); if( hleAddr ) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT forceLog_printf("HLE: Prevent XCX rendertarget reduction"); #endif uint32 bl = memory_readU32(hleAddr+0x14); @@ -325,7 +325,7 @@ void GamePatch_scan() hleAddr = hle_locate(botw_busyLoopSignature, botw_busyLoopMask, sizeof(botw_busyLoopSignature)); if (hleAddr) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT forceLog_printf("HLE: Patch BotW busy loop 1 at 0x%08x", hleAddr); #endif sint32 functionIndex = hleIndex_h000000001; @@ -336,7 +336,7 @@ void GamePatch_scan() hleAddr = hle_locate(botw_busyLoopSignature2, botw_busyLoopMask2, sizeof(botw_busyLoopSignature2)); if (hleAddr) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT forceLog_printf("HLE: Patch BotW busy loop 2 at 0x%08x", hleAddr); #endif sint32 functionIndex = hleIndex_h000000002; diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterALU.hpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterALU.hpp index a3e45679..dbbdb08d 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterALU.hpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterALU.hpp @@ -384,7 +384,7 @@ static void PPCInterpreter_MULHW_(PPCInterpreter_t* hCPU, uint32 opcode) hCPU->gpr[rD] = ((uint64)c) >> 32; if (opcode & PPC_OPC_RC) { // update cr0 flags -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); #endif ppc_update_cr0(hCPU, hCPU->gpr[rD]); diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterImpl.cpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterImpl.cpp index 6e3de535..8cc8a6a8 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterImpl.cpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterImpl.cpp @@ -139,7 +139,7 @@ public: return vAddr; } -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (hCPU->memoryException) assert_dbg(); // should not be set anymore #endif @@ -456,7 +456,7 @@ public: { case 0: debug_printf("ZERO[NOP] | 0x%08X\n", (unsigned int)hCPU->instructionPointer); - #ifndef PUBLIC_RELEASE + #ifdef CEMU_DEBUG_ASSERT assert_dbg(); while (true) std::this_thread::sleep_for(std::chrono::seconds(1)); #endif @@ -712,7 +712,7 @@ public: PPCInterpreter_CMP(hCPU, opcode); break; case 4: - #ifndef PUBLIC_RELEASE + #ifdef CEMU_DEBUG_ASSERT debug_printf("TW instruction executed at %08x\n", hCPU->instructionPointer); #endif PPCInterpreter_TW(hCPU, opcode); @@ -998,7 +998,7 @@ public: break; default: debug_printf("Unknown execute %04X as [31] at %08X\n", PPC_getBits(opcode, 30, 10), hCPU->instructionPointer); - #ifndef PUBLIC_RELEASE + #ifdef CEMU_DEBUG_ASSERT assert_dbg(); #endif hCPU->instructionPointer += 4; diff --git a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterSPR.hpp b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterSPR.hpp index 819f317a..2d38e728 100644 --- a/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterSPR.hpp +++ b/src/Cafe/HW/Espresso/Interpreter/PPCInterpreterSPR.hpp @@ -559,7 +559,7 @@ static void PPCSprSupervisor_set(PPCInterpreter_t* hCPU, uint32 spr, uint32 newV break; default: debug_printf("[C%d] Set unhandled SPR 0x%x to %08x (supervisor mode)\n", hCPU->spr.UPIR, spr, newValue); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); #endif break; @@ -598,7 +598,7 @@ static void PPCSpr_set(PPCInterpreter_t* hCPU, uint32 spr, uint32 newValue) break; default: debug_printf("[C%d] Set unhandled SPR %d to %08x\n", hCPU->spr.UPIR, spr, newValue); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); #endif break; @@ -782,7 +782,7 @@ static uint32 PPCSprSupervisor_get(PPCInterpreter_t* hCPU, uint32 spr) break; default: debug_printf("[C%d] Get unhandled SPR %d\n", hCPU->spr.UPIR, spr); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); #endif break; @@ -840,7 +840,7 @@ static uint32 PPCSpr_get(PPCInterpreter_t* hCPU, uint32 spr) break; default: debug_printf("[C%d] Get unhandled SPR %d\n", hCPU->spr.UPIR, spr); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); #endif break; diff --git a/src/Cafe/HW/Espresso/Recompiler/PPCFunctionBoundaryTracker.h b/src/Cafe/HW/Espresso/Recompiler/PPCFunctionBoundaryTracker.h index 48782454..e558292b 100644 --- a/src/Cafe/HW/Espresso/Recompiler/PPCFunctionBoundaryTracker.h +++ b/src/Cafe/HW/Espresso/Recompiler/PPCFunctionBoundaryTracker.h @@ -153,7 +153,7 @@ private: void checkForCollisions() { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT uint32 endOfPrevious = 0; for (auto itr : map_ranges) { diff --git a/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp b/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp index 61aa11ca..98263ff3 100644 --- a/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp @@ -78,7 +78,7 @@ void PPCRecompiler_enter(PPCInterpreter_t* hCPU, PPCREC_JUMP_ENTRY funcPtr) PPCRecompiler_enterRecompilerCode((uint64)funcPtr, (uint64)hCPU); _controlfp(prevState, _MCW_RC); // debug recompiler exit - useful to find frequently executed functions which couldn't be recompiled - #ifndef PUBLIC_RELEASE + #ifdef CEMU_DEBUG_ASSERT if (hCPU->remainingCycles > 0 && GetAsyncKeyState(VK_F4)) { auto t = std::chrono::high_resolution_clock::now(); diff --git a/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlGen.cpp b/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlGen.cpp index 7291ac41..485c85bf 100644 --- a/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlGen.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlGen.cpp @@ -415,7 +415,7 @@ uint32 PPCRecompilerImlGen_loadOverwriteFPRRegister(ppcImlGenContext_t* ppcImlGe void PPCRecompilerImlGen_TW(ppcImlGenContext_t* ppcImlGenContext, uint32 opcode) { -//#ifndef PUBLIC_RELEASE +//#ifdef CEMU_DEBUG_ASSERT // PPCRecompilerImlGen_generateNewInstruction_macro(ppcImlGenContext, PPCREC_IML_MACRO_DEBUGBREAK, ppcImlGenContext->ppcAddressOfCurrentInstruction, 0, 0); //#endif PPCRecompilerImlGen_generateNewInstruction_macro(ppcImlGenContext, PPCREC_IML_MACRO_LEAVE, ppcImlGenContext->ppcAddressOfCurrentInstruction, 0, 0); @@ -2271,7 +2271,7 @@ bool PPCRecompilerImlGen_LSWI(ppcImlGenContext_t* ppcImlGenContext, uint32 opcod // if nb == 4 this instruction immitates LWZ if( rA == 0 ) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); // special form where gpr is ignored and only imm is used #endif return false; @@ -2291,7 +2291,7 @@ bool PPCRecompilerImlGen_LSWI(ppcImlGenContext_t* ppcImlGenContext, uint32 opcod // if nb == 2 this instruction immitates a LHZ but the result is shifted left by 16 bits if( rA == 0 ) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); // special form where gpr is ignored and only imm is used #endif return false; @@ -2313,7 +2313,7 @@ bool PPCRecompilerImlGen_LSWI(ppcImlGenContext_t* ppcImlGenContext, uint32 opcod // if nb == 3 this instruction loads a 3-byte big-endian and the result is shifted left by 8 bits if( rA == 0 ) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); // special form where gpr is ignored and only imm is used #endif return false; @@ -4560,7 +4560,7 @@ bool PPCRecompiler_generateIntermediateCode(ppcImlGenContext_t& ppcImlGenContext if( ppcImlGenContext.imlList[i].type == PPCREC_IML_TYPE_JUMPMARK ) { ppcImlGenContext.imlList[i].op_jumpmark.flags |= PPCREC_IML_OP_FLAG_UNUSED; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (map_jumpMarks.find(ppcImlGenContext.imlList[i].op_jumpmark.address) != map_jumpMarks.end()) assert_dbg(); #endif diff --git a/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlOptimizer.cpp b/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlOptimizer.cpp index 1a15bd22..45e27664 100644 --- a/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlOptimizer.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlOptimizer.cpp @@ -2151,7 +2151,7 @@ void _reorderConditionModifyInstructions(PPCRecImlSegment_t* imlSegment) } // move CR setter instruction -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if ((unsafeInstructionIndex + 1) <= crSetterInstructionIndex) assert_dbg(); #endif diff --git a/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlRanges.cpp b/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlRanges.cpp index f6370d8c..d31c02d4 100644 --- a/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlRanges.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlRanges.cpp @@ -6,7 +6,7 @@ void PPCRecRARange_addLink_perVirtualGPR(raLivenessSubrange_t** root, raLivenessSubrange_t* subrange) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if ((*root) && (*root)->range->virtualRegister != subrange->range->virtualRegister) assert_dbg(); #endif @@ -35,7 +35,7 @@ void PPCRecRARange_removeLink_perVirtualGPR(raLivenessSubrange_t** root, raLiven (*root) = subrange->link_sameVirtualRegisterGPR.next; if (subrange->link_sameVirtualRegisterGPR.next) subrange->link_sameVirtualRegisterGPR.next->link_sameVirtualRegisterGPR.prev = tempPrev; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT subrange->link_sameVirtualRegisterGPR.prev = (raLivenessSubrange_t*)1; subrange->link_sameVirtualRegisterGPR.next = (raLivenessSubrange_t*)1; #endif @@ -50,7 +50,7 @@ void PPCRecRARange_removeLink_allSubrangesGPR(raLivenessSubrange_t** root, raLiv (*root) = subrange->link_segmentSubrangesGPR.next; if (subrange->link_segmentSubrangesGPR.next) subrange->link_segmentSubrangesGPR.next->link_segmentSubrangesGPR.prev = tempPrev; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT subrange->link_segmentSubrangesGPR.prev = (raLivenessSubrange_t*)1; subrange->link_segmentSubrangesGPR.next = (raLivenessSubrange_t*)1; #endif @@ -162,7 +162,7 @@ void PPCRecRA_mergeRanges(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange_ void PPCRecRA_mergeSubranges(ppcImlGenContext_t* ppcImlGenContext, raLivenessSubrange_t* subrange, raLivenessSubrange_t* absorbedSubrange) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT PPCRecRA_debugValidateSubrange(subrange); PPCRecRA_debugValidateSubrange(absorbedSubrange); if (subrange->imlSegment != absorbedSubrange->imlSegment) @@ -212,7 +212,7 @@ void PPCRecRA_explodeRange(ppcImlGenContext_t* ppcImlGenContext, raLivenessRange PPCRecRA_deleteRange(ppcImlGenContext, range); } -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT void PPCRecRA_debugValidateSubrange(raLivenessSubrange_t* subrange) { // validate subrange @@ -236,7 +236,7 @@ void PPCRecRA_debugValidateSubrange(raLivenessSubrange_t* subrange) {} raLivenessSubrange_t* PPCRecRA_splitLocalSubrange(ppcImlGenContext_t* ppcImlGenContext, raLivenessSubrange_t* subrange, sint32 splitIndex, bool trimToHole) { // validation -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (subrange->end.index == RA_INTER_RANGE_END || subrange->end.index == RA_INTER_RANGE_START) assert_dbg(); if (subrange->start.index >= splitIndex) @@ -364,7 +364,7 @@ sint32 PPCRecRARange_estimateAdditionalCostAfterRangeExplode(raLivenessRange_t* sint32 PPCRecRARange_estimateAdditionalCostAfterSplit(raLivenessSubrange_t* subrange, sint32 splitIndex) { // validation -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (subrange->end.index == RA_INTER_RANGE_END) assert_dbg(); #endif diff --git a/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlRegisterAllocator.cpp b/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlRegisterAllocator.cpp index 92fbd9b0..88d387e6 100644 --- a/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlRegisterAllocator.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlRegisterAllocator.cpp @@ -91,7 +91,7 @@ raRegisterState_t* PPCRecRA_getRegisterState(raRegisterState_t* regState, sint32 { if (regState[i].virtualRegister == virtualRegister) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (regState[i].physicalRegister < 0) assert_dbg(); #endif @@ -300,7 +300,7 @@ void _sortSegmentAllSubrangesLinkedList(PPCRecImlSegment_t* imlSegment) subrangeList[i]->link_segmentSubrangesGPR.next = subrangeList[i + 1]; } // validate list -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT sint32 count2 = 0; subrangeItr = imlSegment->raInfo.linkedList_allSubranges; sint32 currentStartIndex = RA_INTER_RANGE_START; @@ -342,7 +342,7 @@ bool PPCRecRA_assignSegmentRegisters(ppcImlGenContext_t* ppcImlGenContext, PPCRe raLivenessSubrange_t* liverange = liveInfo.liveRangeList[f]; if (liverange->end.index <= currentIndex && liverange->end.index != RA_INTER_RANGE_END) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (liverange->subrangeBranchTaken || liverange->subrangeBranchNotTaken) assert_dbg(); // infinite subranges should not expire #endif @@ -356,7 +356,7 @@ bool PPCRecRA_assignSegmentRegisters(ppcImlGenContext_t* ppcImlGenContext, PPCRe if (subrangeItr->range->physicalRegister >= 0) { // verify if register is actually available -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT for (sint32 f = 0; f < liveInfo.liveRangesCount; f++) { raLivenessSubrange_t* liverangeItr = liveInfo.liveRangeList[f]; @@ -778,7 +778,7 @@ void PPCRecRA_generateSegmentInstructions(ppcImlGenContext_t* ppcImlGenContext, { liveInfo.liveRangeList[liveInfo.liveRangesCount] = subrangeItr; liveInfo.liveRangesCount++; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT // load GPR if (subrangeItr->_noLoad == false) { diff --git a/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlRegisterAllocator2.cpp b/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlRegisterAllocator2.cpp index e2070703..0fbad0fc 100644 --- a/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlRegisterAllocator2.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerImlRegisterAllocator2.cpp @@ -105,7 +105,7 @@ void PPCRecRA_createSegmentLivenessRanges(ppcImlGenContext_t* ppcImlGenContext, for (sint32 i = 0; i < PPC_REC_MAX_VIRTUAL_GPR; i++) { vGPR2Subrange[i] = imlSegment->raInfo.linkedList_perVirtualGPR[i]; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (vGPR2Subrange[i] && vGPR2Subrange[i]->link_sameVirtualRegisterGPR.next != nullptr) assert_dbg(); #endif @@ -129,7 +129,7 @@ void PPCRecRA_createSegmentLivenessRanges(ppcImlGenContext_t* ppcImlGenContext, bool isWrite = (t == 3); // add location PPCRecRA_updateOrAddSubrangeLocation(vGPR2Subrange[virtualRegister], index, isWrite == false, isWrite); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (index < vGPR2Subrange[virtualRegister]->start.index) assert_dbg(); if (index+1 > vGPR2Subrange[virtualRegister]->end.index) @@ -172,7 +172,7 @@ void PPCRecRA_extendRangeToBeginningOfSegment(ppcImlGenContext_t* ppcImlGenConte void _PPCRecRA_connectRanges(ppcImlGenContext_t* ppcImlGenContext, sint32 vGPR, PPCRecImlSegment_t** route, sint32 routeDepth) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (routeDepth < 2) assert_dbg(); #endif @@ -226,7 +226,7 @@ void _PPCRecRA_checkAndTryExtendRange(ppcImlGenContext_t* ppcImlGenContext, PPCR void PPCRecRA_checkAndTryExtendRange(ppcImlGenContext_t* ppcImlGenContext, PPCRecImlSegment_t* currentSegment, sint32 vGPR) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (currentSegment->raDistances.reg[vGPR].usageEnd < 0) assert_dbg(); #endif @@ -239,7 +239,7 @@ void PPCRecRA_checkAndTryExtendRange(ppcImlGenContext_t* ppcImlGenContext, PPCRe else instructionsUntilEndOfSeg = currentSegment->imlListCount - currentSegment->raDistances.reg[vGPR].usageEnd; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (instructionsUntilEndOfSeg < 0) assert_dbg(); #endif @@ -269,7 +269,7 @@ void PPCRecRA_mergeCloseRangesForSegmentV2(ppcImlGenContext_t* ppcImlGenContext, // check and extend if possible PPCRecRA_checkAndTryExtendRange(ppcImlGenContext, imlSegment, i); } -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (imlSegment->list_prevSegments.empty() == false && imlSegment->isEnterable) assert_dbg(); if ((imlSegment->nextSegmentBranchNotTaken != nullptr || imlSegment->nextSegmentBranchTaken != nullptr) && imlSegment->nextSegmentIsUncertain) diff --git a/src/Cafe/HW/Latte/Core/FetchShader.cpp b/src/Cafe/HW/Latte/Core/FetchShader.cpp index 1c0a72a0..c6756f4e 100644 --- a/src/Cafe/HW/Latte/Core/FetchShader.cpp +++ b/src/Cafe/HW/Latte/Core/FetchShader.cpp @@ -505,7 +505,7 @@ LatteFetchShader* LatteFetchShader::FindByGPUState() lookupInfo->programSize = _getFSProgramSize(); lookupInfo->lastFrameAccessed = LatteGPUState.frameCounter; g_fetchShaderLookupCache.store(fsPhysAddr24, lookupInfo); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT cemu_assert_debug(g_fetchShaderLookupCache.lookup(fsPhysAddr24) == lookupInfo); #endif } diff --git a/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp b/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp index 426568a8..a70ff888 100644 --- a/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp @@ -87,7 +87,7 @@ public: return; // do nothing if added range is already covered rangeBegin = (std::min)(rangeBegin, (*itr).first.rangeBegin); // DEBUG - make sure this is the start point of the merge process (the first entry that starts below minValue) -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (itr != m_map.cbegin()) { // check previous result diff --git a/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp b/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp index b95b84d3..417e3b8c 100644 --- a/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp +++ b/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp @@ -136,7 +136,7 @@ uint32 LatteCP_readU32Deprc() } v = *(uint32*)gxRingBufferReadPtr; gxRingBufferReadPtr += 4; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (v == 0xcdcdcdcd) assert_dbg(); #endif @@ -299,7 +299,7 @@ LatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords) uint32 registerIndex = TRegisterBase + registerOffset; uint32 registerStartIndex = registerIndex; uint32 registerEndIndex = registerStartIndex + nWords; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT cemu_assert_debug((registerIndex + nWords) <= LATTE_MAX_REGISTER); #endif uint32* outputReg = (uint32*)(LatteGPUState.contextRegister + registerIndex); @@ -340,7 +340,7 @@ LatteCMDPtr LatteCP_itSetRegistersGeneric(LatteCMDPtr cmd, uint32 nWords, TRegRa uint32 registerIndex = TRegisterBase + registerOffset; uint32 registerStartIndex = registerIndex; uint32 registerEndIndex = registerStartIndex + nWords; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT cemu_assert_debug((registerIndex + nWords) <= LATTE_MAX_REGISTER); #endif cbRegRange(registerStartIndex, registerEndIndex); @@ -1069,7 +1069,7 @@ void LatteCP_processCommandBuffer(uint8* cmdBuffer, sint32 cmdSize, DrawPassCont { uint32 itCode = (itHeader >> 8) & 0xFF; uint32 nWords = ((itHeader >> 16) & 0x3FFF) + 1; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT LatteCMDPtr expectedPostCmd = cmd + nWords; #endif switch (itCode) @@ -1126,7 +1126,7 @@ void LatteCP_processCommandBuffer(uint8* cmdBuffer, sint32 cmdSize, DrawPassCont return; cemu_assert_debug(!drawPassCtx.isWithinDrawPass()); } -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT expectedPostCmd = cmd; #endif } @@ -1156,7 +1156,7 @@ void LatteCP_processCommandBuffer(uint8* cmdBuffer, sint32 cmdSize, DrawPassCont cmd = LatteCP_itDrawIndex2(cmd, nWords, drawPassCtx); cmd = LatteCP_processCommandBuffer_continuousDrawPass(cmd, cmdStart, cmdEnd, drawPassCtx); cemu_assert_debug(cmd == cmdEnd || drawPassCtx.isWithinDrawPass() == false); // draw sequence should have ended if we didn't reach the end of the command buffer -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT expectedPostCmd = cmd; #endif } @@ -1167,7 +1167,7 @@ void LatteCP_processCommandBuffer(uint8* cmdBuffer, sint32 cmdSize, DrawPassCont cmd = LatteCP_itDrawIndexAuto(cmd, nWords, drawPassCtx); cmd = LatteCP_processCommandBuffer_continuousDrawPass(cmd, cmdStart, cmdEnd, drawPassCtx); cemu_assert_debug(cmd == cmdEnd || drawPassCtx.isWithinDrawPass() == false); // draw sequence should have ended if we didn't reach the end of the command buffer -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT expectedPostCmd = cmd; #endif #ifdef FAST_DRAW_LOGGING @@ -1313,7 +1313,7 @@ void LatteCP_processCommandBuffer(uint8* cmdBuffer, sint32 cmdSize, DrawPassCont cemu_assert_debug(false); LatteSkipCMD(nWords); } -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if(cmd != expectedPostCmd) debug_printf("cmd %016p expectedPostCmd %016p\n", cmd, expectedPostCmd); cemu_assert_debug(cmd == expectedPostCmd); diff --git a/src/Cafe/HW/Latte/Core/LatteOverlay.cpp b/src/Cafe/HW/Latte/Core/LatteOverlay.cpp index cb7c9baf..2a655c18 100644 --- a/src/Cafe/HW/Latte/Core/LatteOverlay.cpp +++ b/src/Cafe/HW/Latte/Core/LatteOverlay.cpp @@ -402,7 +402,7 @@ void LatteOverlay_RenderNotifications(ImVec2& position, ImVec2& pivot, sint32 di ImRotateEnd(0.001f * ticks.time_since_epoch().count()); ImGui::SameLine(); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT uint64 totalTime = g_compiling_pipelines_syncTimeSum / 1000000ull; if (s_pipeline_count_async > 0) { diff --git a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp index 11048504..18d715d8 100644 --- a/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp +++ b/src/Cafe/HW/Latte/Core/LatteRenderTarget.cpp @@ -506,7 +506,7 @@ bool LatteMRT::UpdateCurrentFBO() } else if (rtEffectiveSize->width != effectiveWidth && rtEffectiveSize->height != effectiveHeight) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT forceLog_printf("Color buffer size mismatch (%dx%d). Effective size: %dx%d Real size: %dx%d Mismatching texture: %08x %dx%d fmt %04x", rtEffectiveSize->width, rtEffectiveSize->height, effectiveWidth, effectiveHeight, colorAttachmentView->baseTexture->width, colorAttachmentView->baseTexture->height, colorAttachmentView->baseTexture->physAddress, colorAttachmentView->baseTexture->width, colorAttachmentView->baseTexture->height, (uint32)colorAttachmentView->baseTexture->format); #endif } diff --git a/src/Cafe/HW/Latte/Core/LatteRingBuffer.cpp b/src/Cafe/HW/Latte/Core/LatteRingBuffer.cpp index 15c2b24c..22eeea4b 100644 --- a/src/Cafe/HW/Latte/Core/LatteRingBuffer.cpp +++ b/src/Cafe/HW/Latte/Core/LatteRingBuffer.cpp @@ -11,7 +11,7 @@ LatteRingBuffer_t* LatteRingBuffer_create(uint8* data, uint32 size) uint8* LatteRingBuffer_allocate(LatteRingBuffer_t* rb, sint32 size, sint32 alignment) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT cemu_assert_debug(size < rb->size); #endif // align diff --git a/src/Cafe/HW/Latte/Core/LatteShader.cpp b/src/Cafe/HW/Latte/Core/LatteShader.cpp index 5e97d485..f4dd4007 100644 --- a/src/Cafe/HW/Latte/Core/LatteShader.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShader.cpp @@ -236,7 +236,7 @@ void LatteShader_UpdatePSInputs(uint32* contextRegisters) } // semantic imports from vertex shader -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT uint8 semanticMask[256 / 8] = { 0 }; #endif cemu_assert_debug(numPSInputs <= GPU7_PS_MAX_INPUTS); @@ -273,7 +273,7 @@ void LatteShader_UpdatePSInputs(uint32* contextRegisters) } else { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (semanticMask[psSemanticId >> 3] & (1 << (psSemanticId & 7))) { forceLogDebug_printf("SemanticId already used"); diff --git a/src/Cafe/HW/Latte/Core/LatteSoftware.cpp b/src/Cafe/HW/Latte/Core/LatteSoftware.cpp index 8e5ec29b..57af8d83 100644 --- a/src/Cafe/HW/Latte/Core/LatteSoftware.cpp +++ b/src/Cafe/HW/Latte/Core/LatteSoftware.cpp @@ -252,7 +252,7 @@ float LatteSoftware_omod(uint32 omod, float f) return 0.0f; } -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT #define _clamp(__v) if(destClamp != 0) cemu_assert_unimplemented() #else #define _clamp(__v) // todo diff --git a/src/Cafe/HW/Latte/Core/LatteStreamoutGPU.cpp b/src/Cafe/HW/Latte/Core/LatteStreamoutGPU.cpp index 07e7106d..e212dd18 100644 --- a/src/Cafe/HW/Latte/Core/LatteStreamoutGPU.cpp +++ b/src/Cafe/HW/Latte/Core/LatteStreamoutGPU.cpp @@ -100,7 +100,7 @@ void LatteStreamout_PrepareDrawcall(uint32 count, uint32 instanceCount) uint32 streamoutWriteMask = 0; if (geometryShader) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT cemu_assert_debug(vertexShader->streamoutBufferWriteMask2.any() == false); #endif for (sint32 i = 0; i < LATTE_NUM_STREAMOUT_BUFFER; i++) diff --git a/src/Cafe/HW/Latte/Core/LatteTexture.cpp b/src/Cafe/HW/Latte/Core/LatteTexture.cpp index 899888de..17621c8f 100644 --- a/src/Cafe/HW/Latte/Core/LatteTexture.cpp +++ b/src/Cafe/HW/Latte/Core/LatteTexture.cpp @@ -1089,7 +1089,7 @@ LatteTextureView* LatteTexture_CreateMapping(MPTR physAddr, MPTR physMipAddr, si // for accesses to mips/slices using a physAddress offset we manually need to create a new view lookup // by default views only create a lookup for the base texture physAddress view->CreateLookupForSubTexture(relativeMipIndex, relativeSliceIndex); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT LatteTextureView* testView = LatteTextureViewLookupCache::lookup(physAddr, width, height, depth, pitch, firstMip, numMip, firstSlice, numSlice, format, dimView); cemu_assert(testView); #endif diff --git a/src/Cafe/HW/Latte/Core/LatteTextureLegacy.cpp b/src/Cafe/HW/Latte/Core/LatteTextureLegacy.cpp index 8d4c7efb..1bf17c51 100644 --- a/src/Cafe/HW/Latte/Core/LatteTextureLegacy.cpp +++ b/src/Cafe/HW/Latte/Core/LatteTextureLegacy.cpp @@ -275,7 +275,7 @@ void LatteTexture_updateTexturesForStage(LatteDecompilerShader* shaderContext, u // check for changes if (LatteTC_HasTextureChanged(textureView->baseTexture) || swizzleChanged) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT debug_printf("Reload texture 0x%08x res %dx%d memRange %08x-%08x SwizzleChange: %s\n", textureView->baseTexture->physAddress, textureView->baseTexture->width, textureView->baseTexture->height, textureView->baseTexture->texDataPtrLow, textureView->baseTexture->texDataPtrHigh, swizzleChanged ? "yes" : "no"); #endif // update swizzle / changed mip address diff --git a/src/Cafe/HW/Latte/Core/LatteTextureLoader.cpp b/src/Cafe/HW/Latte/Core/LatteTextureLoader.cpp index 5bd71e81..45e7ec46 100644 --- a/src/Cafe/HW/Latte/Core/LatteTextureLoader.cpp +++ b/src/Cafe/HW/Latte/Core/LatteTextureLoader.cpp @@ -736,7 +736,7 @@ void LatteTextureLoader_writeReadbackTextureToMemory(LatteTextureDefinition* tex LatteTextureLoaderCtx textureLoader = { 0 }; LatteTextureLoader_begin(&textureLoader, sliceIndex, mipIndex, textureData->physAddress, textureData->physMipAddress, textureData->format, textureData->dim, textureData->width, textureData->height, textureData->depth, textureData->mipLevels, textureData->pitch, textureData->tileMode, textureData->swizzle); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (textureData->depth != 1) forceLog_printf("_writeReadbackTextureToMemory(): Texture has multiple slices (not supported)"); #endif diff --git a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerAnalyzer.cpp b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerAnalyzer.cpp index 0131b34e..412f45ce 100644 --- a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerAnalyzer.cpp +++ b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerAnalyzer.cpp @@ -233,7 +233,7 @@ bool _isIntegerInstruction(const LatteDecompilerALUInstruction& aluInstruction) case ALU_OP2_INST_SETNE_DX10: return true; default: -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT debug_printf("_isIntegerInstruction(): OP3=%s opcode=%02x\n", aluInstruction.isOP3 ? "true" : "false", aluInstruction.opcode); cemu_assert_debug(false); #endif @@ -259,7 +259,7 @@ bool _isIntegerInstruction(const LatteDecompilerALUInstruction& aluInstruction) case ALU_OP3_INST_CMOVGE_INT: return true; default: -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT debug_printf("_isIntegerInstruction(): OP3=%s opcode=%02x\n", aluInstruction.isOP3?"true":"false", aluInstruction.opcode); #endif break; diff --git a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSL.cpp b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSL.cpp index 9a5107d0..97703b11 100644 --- a/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSL.cpp +++ b/src/Cafe/HW/Latte/LegacyShaderDecompiler/LatteDecompilerEmitGLSL.cpp @@ -2643,7 +2643,7 @@ void _emitTEXSampleTextureCode(LatteDecompilerShaderContext* shaderContext, Latt src->add(");"); // debug -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if(texInstruction->opcode == GPU7_TEX_INST_LD ) src->add(" // TEX_INST_LD"); else if(texInstruction->opcode == GPU7_TEX_INST_SAMPLE ) @@ -3460,7 +3460,7 @@ void _emitStreamWriteCode(LatteDecompilerShaderContext* shaderContext, LatteDeco StringBuf* src = shaderContext->shaderSource; if (shaderContext->analyzer.hasStreamoutEnable == false) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT src->add("// omitted streamout write" _CRLF); #endif return; @@ -3842,7 +3842,7 @@ void LatteDecompiler_emitGLSLHelperFunctions(LatteDecompilerShaderContext* shade void _addPixelShaderExtraDebugInfo(LatteDecompilerShaderContext* shaderContext, StringBuf* fCStr_shaderSource) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT fCStr_shaderSource->add("// Color buffers:" _CRLF); for(uint32 i=0; i<8; i++) { @@ -3958,7 +3958,7 @@ void LatteDecompiler_emitGLSLShader(LatteDecompilerShaderContext* shaderContext, // debug info src->addFmt("// shader %08x%08x" _CRLF, (uint32)(shaderContext->shaderBaseHash >> 32), (uint32)(shaderContext->shaderBaseHash & 0xFFFFFFFF)); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT src->addFmt("// usesIntegerValues: {}" _CRLF, shaderContext->analyzer.usesIntegerValues?"true":"false"); src->addFmt(_CRLF); diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.cpp index dac3c3a4..b0d0dbe9 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureGL.cpp @@ -35,7 +35,7 @@ LatteTextureGL::LatteTextureGL(uint32 textureUnit, Latte::E_DIM dim, MPTR physAd LatteTextureGL::InitTextureState(); // set debug name bool useGLDebugNames = false; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT useGLDebugNames = true; #endif if (LaunchSettings::NSightModeEnabled()) diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.cpp index fc5b5dc4..063cc17f 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/LatteTextureViewGL.cpp @@ -97,7 +97,7 @@ void LatteTextureViewGL::InitAliasView() // set debug name bool useGLDebugNames = false; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT useGLDebugNames = true; #endif if (LaunchSettings::NSightModeEnabled()) diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VKRBase.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VKRBase.h index a8a1376f..1c91207e 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VKRBase.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VKRBase.h @@ -21,7 +21,7 @@ public: cemu_assert_debug(refCount == 0); // remove references -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT for (auto itr : refs) { auto& rev = itr->ref->reverseRefs; @@ -58,7 +58,7 @@ public: this->refs.emplace_back(refTarget->selfRef); refTarget->refCount++; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT // add reverse ref refTarget->reverseRefs.emplace_back(this->selfRef); #endif @@ -80,7 +80,7 @@ protected: private: VKRMoveableRefCounterRef* selfRef; std::vector refs; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT std::vector reverseRefs; #endif diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index 7c81a3c9..338d09af 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -54,7 +54,7 @@ const std::vector kRequiredDeviceExtensions = VKAPI_ATTR VkBool32 VKAPI_CALL DebugUtilsCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (strstr(pCallbackData->pMessage, "consumes input location")) return VK_FALSE; // false means we dont care @@ -636,7 +636,7 @@ VulkanRenderer::~VulkanRenderer() VulkanRenderer* VulkanRenderer::GetInstance() { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT cemu_assert_debug(g_renderer && dynamic_cast(g_renderer.get())); // Use #if here because dynamic_casts dont get optimized away even if the result is not stored as with cemu_assert_debug #endif diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp index 2417f797..15ba3fbc 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp @@ -334,7 +334,7 @@ PipelineInfo* VulkanRenderer::draw_getOrCreateGraphicsPipeline(uint32 indexCount if (cache_object != nullptr) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT cemu_assert_debug(cache_object->vertexShader == LatteSHRC_GetActiveVertexShader()); cemu_assert_debug(cache_object->geometryShader == LatteSHRC_GetActiveGeometryShader()); cemu_assert_debug(cache_object->pixelShader == LatteSHRC_GetActivePixelShader()); @@ -1456,7 +1456,7 @@ void VulkanRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 else { pipeline_info = m_state.activePipelineInfo; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT auto pipeline_info2 = draw_getOrCreateGraphicsPipeline(count); if (pipeline_info != pipeline_info2) { diff --git a/src/Cafe/IOSU/fsa/iosu_fsa.cpp b/src/Cafe/IOSU/fsa/iosu_fsa.cpp index aa2ad553..7fd235ce 100644 --- a/src/Cafe/IOSU/fsa/iosu_fsa.cpp +++ b/src/Cafe/IOSU/fsa/iosu_fsa.cpp @@ -606,7 +606,7 @@ namespace iosu FSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle); if (!fscFile) return (FSStatus)FS_RESULT::ERR_PLACEHOLDER; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT cemuLog_force("FSAProcessCmd_appendFile(): size 0x{:08x} count 0x{:08x} (todo)\n", _swapEndianU32(cmd->cmdAppendFile.size), _swapEndianU32(cmd->cmdAppendFile.count)); #endif return _swapEndianU32(cmd->cmdAppendFile.size) * _swapEndianU32(cmd->cmdAppendFile.count); diff --git a/src/Cafe/IOSU/kernel/iosu_kernel.cpp b/src/Cafe/IOSU/kernel/iosu_kernel.cpp index fb9a0191..1a642028 100644 --- a/src/Cafe/IOSU/kernel/iosu_kernel.cpp +++ b/src/Cafe/IOSU/kernel/iosu_kernel.cpp @@ -10,7 +10,7 @@ namespace iosu static void _assume_lock() { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT cemu_assert_debug(!sInternalMutex.try_lock()); #endif } diff --git a/src/Cafe/IOSU/legacy/iosu_boss.cpp b/src/Cafe/IOSU/legacy/iosu_boss.cpp index 22c11eba..7280ac53 100644 --- a/src/Cafe/IOSU/legacy/iosu_boss.cpp +++ b/src/Cafe/IOSU/legacy/iosu_boss.cpp @@ -485,7 +485,7 @@ namespace iosu CURL* curl = it->curl.get(); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 2); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); char errbuf[CURL_ERROR_SIZE]{}; curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf); @@ -579,7 +579,7 @@ namespace iosu if (curl_result != CURLE_OK) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT forceLogDebug_printf("curl error buff: %s", errbuf); #endif it->turn_state = kError; diff --git a/src/Cafe/OS/RPL/rpl.cpp b/src/Cafe/OS/RPL/rpl.cpp index 1c779308..66d7a4ca 100644 --- a/src/Cafe/OS/RPL/rpl.cpp +++ b/src/Cafe/OS/RPL/rpl.cpp @@ -1015,7 +1015,7 @@ bool RPLLoader_FixImportSymbols(RPLModule* rplLoaderContext, sint32 symtabSectio } if (foundExport == false) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (nameOffset > 0) { forceLogDebug_printf("export not found - force lookup in function exports"); diff --git a/src/Cafe/OS/libs/coreinit/coreinit.cpp b/src/Cafe/OS/libs/coreinit/coreinit.cpp index 1869f55c..af6e78ea 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit.cpp @@ -119,7 +119,7 @@ void coreinitExport_OSPanic(PPCInterpreter_t* hCPU) debug_printf("File: %s:%d\n", memory_getPointerFromVirtualOffset(hCPU->gpr[3]), hCPU->gpr[4]); debug_printf("Msg: %s\n", memory_getPointerFromVirtualOffset(hCPU->gpr[5])); DebugLogStackTrace(coreinit::OSGetCurrentThread(), coreinit::OSGetStackPointer()); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); while (true) std::this_thread::sleep_for(std::chrono::milliseconds(100)); #endif @@ -203,7 +203,7 @@ typedef struct void coreinitExport_OSDriver_Register(PPCInterpreter_t* hCPU) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT forceLog_printf("OSDriver_Register(0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,0x%08x)", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7], hCPU->gpr[8]); #endif OSDriverCallbacks_t* driverCallbacks = (OSDriverCallbacks_t*)memory_getPointerFromVirtualOffset(hCPU->gpr[5]); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Alarm.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Alarm.cpp index a498e40a..25c142cc 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Alarm.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Alarm.cpp @@ -70,7 +70,7 @@ namespace coreinit return; // debug begin -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT uint64 prevTick = 0; auto itr = g_activeAlarmList.begin(); while (itr != g_activeAlarmList.end()) diff --git a/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp b/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp index 1598429f..c49607e1 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp @@ -349,7 +349,7 @@ namespace coreinit } if (entryFound == false) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); #endif } diff --git a/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.cpp b/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.cpp index 9ab614c3..6f202a8e 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_LockedCache.cpp @@ -99,7 +99,7 @@ namespace coreinit if (deallocAddr < lcAddr[coreIndex] || deallocAddr >= (lcAddr[coreIndex] + LC_LOCKED_CACHE_SIZE)) { // out of bounds -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT forceLog_printf("LCDealloc(): Out of bounds"); #endif osLib_returnFromFunction(hCPU, 0); @@ -198,7 +198,7 @@ namespace coreinit assert_dbg(); #endif LCIsEnabled[PPCInterpreter_getCoreIndex(hCPU)]--; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (LCIsEnabled[PPCInterpreter_getCoreIndex(hCPU)] == 0) { uint32 coreIndex = PPCInterpreter_getCoreIndex(hCPU); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_MEM_BlockHeap.cpp b/src/Cafe/OS/libs/coreinit/coreinit_MEM_BlockHeap.cpp index 33767ddf..f3d4250b 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_MEM_BlockHeap.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_MEM_BlockHeap.cpp @@ -462,7 +462,7 @@ namespace coreinit if (block != NULL) { MPTR blockMPTR = memory_getVirtualOffsetFromPointer(block); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (block->isFree != 0) assert_dbg(); _blockHeapDebugVerifyLinkOrder(blockHeapHead); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_MEM_ExpHeap.cpp b/src/Cafe/OS/libs/coreinit/coreinit_MEM_ExpHeap.cpp index c587b879..a1d03c32 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_MEM_ExpHeap.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_MEM_ExpHeap.cpp @@ -938,7 +938,7 @@ void export_MEMSetGroupIDForExpHeap(PPCInterpreter_t* hCPU) ppcDefineParamMEMPTR(heap, MEMHeapBase, 0); ppcDefineParamU16(groupId, 1); coreinitMemLog_printf("MEMSetGroupIDForExpHeap(0x%08x, %d)", heap.GetMPTR(), groupId); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); // someone test this and the entire groupId feature #endif uint16 oldGroupId = MEMSetGroupIDForExpHeap(heap.GetPtr(), groupId); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Thread.h b/src/Cafe/OS/libs/coreinit/coreinit_Thread.h index a0561f41..3c41d9dc 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Thread.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_Thread.h @@ -149,7 +149,7 @@ namespace coreinit void _debugCheckChain(OSThread_t* thread, OSThreadLink* threadLink) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT cemu_assert_debug(tail.IsNull() == head.IsNull()); size_t linkOffset = getLinkOffset(thread, threadLink); // expects thread to be in the chain diff --git a/src/Cafe/OS/libs/gx2/GX2_RenderTarget.cpp b/src/Cafe/OS/libs/gx2/GX2_RenderTarget.cpp index 1b3cc185..a31bf5bc 100644 --- a/src/Cafe/OS/libs/gx2/GX2_RenderTarget.cpp +++ b/src/Cafe/OS/libs/gx2/GX2_RenderTarget.cpp @@ -20,7 +20,7 @@ void gx2Export_GX2InitColorBufferRegs(PPCInterpreter_t* hCPU) LatteAddrLib::GX2CalculateSurfaceInfo(colorBuffer->surface.format, colorBuffer->surface.width, colorBuffer->surface.height, colorBuffer->surface.depth, colorBuffer->surface.dim, colorBuffer->surface.tileMode, colorBuffer->surface.aa, _swapEndianU32(colorBuffer->viewMip), &surfaceInfo); uint32 pitchHeight = (surfaceInfo.height * surfaceInfo.pitch) >> 6; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (colorBuffer->viewNumSlices != _swapEndianU32(1)) forceLogDebug_printf("GX2InitColorBufferRegs(): With unsupported slice count %d", _swapEndianU32(colorBuffer->viewNumSlices)); if (surfaceInfo.pitch < 7) @@ -139,7 +139,7 @@ void gx2Export_GX2SetColorBuffer(PPCInterpreter_t* hCPU) GX2ColorBuffer* colorBufferBE = (GX2ColorBuffer*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT gx2Log_printf("ColorBuffer tileMode %01x PhysAddr %08x fmt %04x res %dx%d Mip %d Slice %d", (uint32)colorBufferBE->surface.tileMode.value(), (uint32)colorBufferBE->surface.imagePtr, (uint32)colorBufferBE->surface.format.value(), (uint32)colorBufferBE->surface.width, (uint32)colorBufferBE->surface.height, _swapEndianU32(colorBufferBE->viewMip), _swapEndianU32(colorBufferBE->viewFirstSlice)); #endif diff --git a/src/Cafe/OS/libs/gx2/GX2_Surface_Copy.cpp b/src/Cafe/OS/libs/gx2/GX2_Surface_Copy.cpp index 9bbc1b80..853405a3 100644 --- a/src/Cafe/OS/libs/gx2/GX2_Surface_Copy.cpp +++ b/src/Cafe/OS/libs/gx2/GX2_Surface_Copy.cpp @@ -397,7 +397,7 @@ void gx2Export_GX2CopySurfaceEx(PPCInterpreter_t* hCPU) forceLogDebug_printf("rect left-top: %d/%d size: %d/%d", _swapEndianU32(rectSrc->left), _swapEndianU32(rectSrc->top), _swapEndianU32(rectSrc->right) - _swapEndianU32(rectSrc->left), _swapEndianU32(rectSrc->bottom) - _swapEndianU32(rectSrc->top)); } -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if( rectCount != 1 ) assert_dbg(); if( srcMip != 0 ) @@ -440,7 +440,7 @@ void gx2Export_GX2ResolveAAColorBuffer(PPCInterpreter_t* hCPU) uint32 srcSlice = _swapEndianU32(srcColorBuffer->viewFirstSlice); uint32 dstSlice = hCPU->gpr[6]; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if( _swapEndianU32(srcColorBuffer->viewMip) != 0 || _swapEndianU32(srcColorBuffer->viewFirstSlice) != 0 ) assert_dbg(); #endif diff --git a/src/Cafe/OS/libs/nlibcurl/nlibcurl.cpp b/src/Cafe/OS/libs/nlibcurl/nlibcurl.cpp index 9078ecc2..5ec75e6b 100644 --- a/src/Cafe/OS/libs/nlibcurl/nlibcurl.cpp +++ b/src/Cafe/OS/libs/nlibcurl/nlibcurl.cpp @@ -839,7 +839,7 @@ size_t header_callback(char* buffer, size_t size, size_t nitems, void* userdata) if (msg.order != QueueOrder_CBDone) cemu_assert_suspicious(); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT char debug[500]; cemu_assert_debug((size*nitems) < 500); memcpy(debug, buffer, size*nitems); diff --git a/src/Cafe/OS/libs/nn_fp/nn_fp.cpp b/src/Cafe/OS/libs/nn_fp/nn_fp.cpp index 2df51a94..db2b7401 100644 --- a/src/Cafe/OS/libs/nn_fp/nn_fp.cpp +++ b/src/Cafe/OS/libs/nn_fp/nn_fp.cpp @@ -592,7 +592,7 @@ namespace nn ppcDefineParamMPTR(funcMPTR, 1); ppcDefineParamMPTR(customParam, 2); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); #endif fpdPrepareRequest(); diff --git a/src/Cafe/OS/libs/nsyshid/nsyshid.cpp b/src/Cafe/OS/libs/nsyshid/nsyshid.cpp index d43b486e..8c390c0a 100644 --- a/src/Cafe/OS/libs/nsyshid/nsyshid.cpp +++ b/src/Cafe/OS/libs/nsyshid/nsyshid.cpp @@ -537,7 +537,7 @@ namespace nsyshid _debugPrintHex("HIDSetReport", data, dataLength); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (reportRelatedUkn != 2 || reportId != 0) assert_dbg(); #endif diff --git a/src/Cafe/OS/libs/nsysnet/nsysnet.cpp b/src/Cafe/OS/libs/nsysnet/nsysnet.cpp index b49d2e80..ade207f9 100644 --- a/src/Cafe/OS/libs/nsysnet/nsysnet.cpp +++ b/src/Cafe/OS/libs/nsysnet/nsysnet.cpp @@ -116,7 +116,7 @@ sint32 _translateError(sint32 returnCode, sint32 wsaError, sint32 mode = _ERROR_ break; case WSAECONNABORTED: debug_printf("WSAECONNABORTED\n"); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); #endif break; @@ -652,7 +652,7 @@ void nsysnetExport_inet_pton(PPCInterpreter_t* hCPU) invalidIp = true; if (d3 < 0 || d3 > 255) invalidIp = true; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (invalidIp) assert_dbg(); #endif @@ -1245,7 +1245,7 @@ void nsysnetExport_gethostbyaddr(PPCInterpreter_t* hCPU) return; } -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (he->h_addrtype != AF_INET) assert_dbg(); if (he->h_length != sizeof(in_addr)) diff --git a/src/Cafe/OS/libs/snd_core/ax_mix.cpp b/src/Cafe/OS/libs/snd_core/ax_mix.cpp index 8e959b28..fecace8e 100644 --- a/src/Cafe/OS/libs/snd_core/ax_mix.cpp +++ b/src/Cafe/OS/libs/snd_core/ax_mix.cpp @@ -692,7 +692,7 @@ namespace snd_core { if (internalShadowCopy->biquad.on == AX_BIQUAD_OFF) return; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (internalShadowCopy->biquad.on != 0x0200) { forceLogDebug_printf("AX_ApplyBiquad() with incorrect biquad.on value 0x%04x", _swapEndianU16(internalShadowCopy->biquad.on)); diff --git a/src/Cafe/OS/libs/snd_core/ax_voice.cpp b/src/Cafe/OS/libs/snd_core/ax_voice.cpp index f60e5853..746f04d3 100644 --- a/src/Cafe/OS/libs/snd_core/ax_voice.cpp +++ b/src/Cafe/OS/libs/snd_core/ax_voice.cpp @@ -702,7 +702,7 @@ namespace snd_core { AXVPBInternal_t* internal = __AXVPBInternalVoiceArray + (sint32)vpb->index; ratio *= 65536.0f; -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (ratio >= 4294967296.0f) assert_dbg(); #endif diff --git a/src/Cafe/OS/libs/sysapp/sysapp.cpp b/src/Cafe/OS/libs/sysapp/sysapp.cpp index 0085ee19..b27a7cf3 100644 --- a/src/Cafe/OS/libs/sysapp/sysapp.cpp +++ b/src/Cafe/OS/libs/sysapp/sysapp.cpp @@ -309,13 +309,13 @@ void cbDeserializeArg_MiiMaker(deserializedArg_t* deserializedArg, void* customP } else if (strcmp(deserializedArg->argument, "slot_id") == 0) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); #endif } else { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); #endif } diff --git a/src/Cemu/Logging/CemuDebugLogging.h b/src/Cemu/Logging/CemuDebugLogging.h index ac05c024..e386242e 100644 --- a/src/Cemu/Logging/CemuDebugLogging.h +++ b/src/Cemu/Logging/CemuDebugLogging.h @@ -2,7 +2,7 @@ // printf-style macros that are only active in non-release builds -#ifdef PUBLIC_RELEASE +#ifndef CEMU_DEBUG_ASSERTS #define debug_printf(...) static void debugBreakpoint() { } #else diff --git a/src/Cemu/Logging/CemuLogging.cpp b/src/Cemu/Logging/CemuLogging.cpp index f58e7984..7e6669a8 100644 --- a/src/Cemu/Logging/CemuLogging.cpp +++ b/src/Cemu/Logging/CemuLogging.cpp @@ -121,12 +121,8 @@ void cemuLog_writeLineToLog(std::string_view text, bool date, bool new_line) const auto temp_time = std::chrono::system_clock::to_time_t(now); const auto& time = *std::localtime(&temp_time); -#ifdef PUBLIC_RELEASE - auto time_str = fmt::format("[{:02d}:{:02d}:{:02d}] ", time.tm_hour, time.tm_min, time.tm_sec); -#else auto time_str = fmt::format("[{:02d}:{:02d}:{:02d}.{:03d}] ", time.tm_hour, time.tm_min, time.tm_sec, std::chrono::duration_cast(now - std::chrono::time_point_cast(now)).count()); -#endif LogContext.text_cache.emplace_back(std::move(time_str)); } diff --git a/src/Cemu/Logging/CemuLogging.h b/src/Cemu/Logging/CemuLogging.h index d89d9cec..20dba9bd 100644 --- a/src/Cemu/Logging/CemuLogging.h +++ b/src/Cemu/Logging/CemuLogging.h @@ -91,7 +91,7 @@ bool cemuLog_log(LogType type, const T* format, TArgs&&... args) template bool cemuLog_logDebug(LogType type, TFmt format, TArgs&&... args) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT return cemuLog_log(type, format, std::forward(args)...); #else return false; @@ -164,7 +164,7 @@ void cemuLog_force(TFmt format, TArgs&&... args) #define saveLog_printf(...) if( cafeLog_isLoggingFlagEnabled(LOG_TYPE_SAVE) ) cafeLog_log(LOG_TYPE_SAVE, __VA_ARGS__); #define nfpLog_printf(...) if( cafeLog_isLoggingFlagEnabled(LOG_TYPE_NFP) ) cafeLog_log(LOG_TYPE_NFP, __VA_ARGS__); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT #define forceLogDebug_printf(...) cafeLog_log(LOG_TYPE_FORCE, __VA_ARGS__); #define forceLogDebug_printfW(...) cafeLog_logW(LOG_TYPE_FORCE, __VA_ARGS__); diff --git a/src/Cemu/PPCAssembler/ppcAssembler.cpp b/src/Cemu/PPCAssembler/ppcAssembler.cpp index c8c28191..e84c9970 100644 --- a/src/Cemu/PPCAssembler/ppcAssembler.cpp +++ b/src/Cemu/PPCAssembler/ppcAssembler.cpp @@ -3497,7 +3497,7 @@ void ppcAsmTestDisassembler() void ppcAsmTest() { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT ppcAsmTestDisassembler(); #endif } diff --git a/src/Cemu/nex/nex.cpp b/src/Cemu/nex/nex.cpp index 010f806c..34c62ca0 100644 --- a/src/Cemu/nex/nex.cpp +++ b/src/Cemu/nex/nex.cpp @@ -29,7 +29,7 @@ sint32 nexService_parseResponse(uint8* data, sint32 length, nexServiceResponse_t protocolId &= 0x7F; if (isRequest) { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); // should never reach since we handle requests before this function is called #endif } diff --git a/src/Cemu/nex/prudp.cpp b/src/Cemu/nex/prudp.cpp index 7700e5eb..12e4570e 100644 --- a/src/Cemu/nex/prudp.cpp +++ b/src/Cemu/nex/prudp.cpp @@ -452,7 +452,7 @@ prudpIncomingPacket::prudpIncomingPacket(prudpStreamSettings_t* streamSettings, } else { -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT assert_dbg(); #endif } @@ -607,7 +607,7 @@ void prudpClient::sortIncomingDataPacket(prudpIncomingPacket* incomingPacket) uint16 seqDif = sequenceIdIncomingPacket - queue_incomingPackets[insertIndex]->sequenceId; if (seqDif&0x8000) break; // negative seqDif -> insert before current element -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT if (seqDif == 0) assert_dbg(); // same sequence id, sort by fragment index? #endif diff --git a/src/Common/precompiled.h b/src/Common/precompiled.h index 57f69c57..2a92ea3e 100644 --- a/src/Common/precompiled.h +++ b/src/Common/precompiled.h @@ -361,7 +361,7 @@ inline void cemu_assert(bool _condition) } } -#ifdef PUBLIC_RELEASE +#ifndef CEMU_DEBUG_ASSERT //#define cemu_assert_debug(__cond) -> Forcing __cond not to be evaluated currently has unexpected side-effects inline void cemu_assert_debug(bool _condition) diff --git a/src/Common/version.h b/src/Common/version.h index 0eff0197..74464393 100644 --- a/src/Common/version.h +++ b/src/Common/version.h @@ -7,10 +7,8 @@ // the minor version is used for experimental builds to indicate the build index. Set by command line option from CI build script // if zero, the version text will be constructed as LEAD.MAJOR, otherwise as LEAD.MAJOR-MINOR -#if !defined(PUBLIC_RELEASE) -#define EMULATOR_VERSION_SUFFIX " (dev)" -#elif defined(EMULATOR_VERSION_MINOR) && EMULATOR_VERSION_MINOR == 0 -#define EMULATOR_VERSION_SUFFIX "" // stable +#if defined(EMULATOR_VERSION_MINOR) && EMULATOR_VERSION_MINOR == 0 +#define EMULATOR_VERSION_SUFFIX "" #else #define EMULATOR_VERSION_SUFFIX " (experimental)" #endif diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 7c1ce0e4..d8caabf4 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -1375,11 +1375,7 @@ void MainWindow::OnKeyUp(wxKeyEvent& event) SetFullScreen(false); else if (code == WXK_RETURN && event.AltDown()) SetFullScreen(!IsFullScreen()); -#ifdef PUBLIC_RELEASE else if (code == WXK_F12) -#else - else if (code == WXK_F11) -#endif g_window_info.has_screenshot_request = true; // async screenshot request } @@ -2058,7 +2054,7 @@ void MainWindow::RecreateMenu() else { // add 'Stop emulation' menu entry to file menu -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_END_EMULATION, _("End emulation")); #endif } @@ -2179,7 +2175,7 @@ void MainWindow::RecreateMenu() debugLoggingMenu->AppendSeparator(); debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + LOG_TYPE_OPENGL, _("&OpenGL debug output"), wxEmptyString)->Check(cafeLog_isLoggingFlagEnabled(LOG_TYPE_OPENGL)); debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + LOG_TYPE_VULKAN_VALIDATION, _("&Vulkan validation layer (slow)"), wxEmptyString)->Check(cafeLog_isLoggingFlagEnabled(LOG_TYPE_VULKAN_VALIDATION)); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_ADVANCED_PPC_INFO, _("&Log PPC context for API"), wxEmptyString)->Check(cemuLog_advancedPPCLoggingEnabled()); #endif m_loggingSubmenu = debugLoggingMenu; @@ -2205,12 +2201,12 @@ void MainWindow::RecreateMenu() debugMenu->AppendSeparator(); -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT auto audioAuxOnly = debugMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_AUDIO_AUX_ONLY, _("&Audio AUX only"), wxEmptyString); audioAuxOnly->Check(ActiveSettings::AudioOutputOnlyAux()); #endif -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT debugMenu->Append(MAINFRAME_MENU_ID_DEBUG_VIEW_LOGGING_WINDOW, _("&Open logging window")); #endif debugMenu->Append(MAINFRAME_MENU_ID_DEBUG_VIEW_PPC_THREADS, _("&View PPC threads")); diff --git a/src/main.cpp b/src/main.cpp index 67b640b4..f782c33e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -246,7 +246,7 @@ int mainEmulatorHLE() wxMessageBox("Cemu doesn't have write access to it's own directory.\nPlease move it to a different location or run Cemu as administrator!", "Warning", wxOK|wxICON_ERROR); // todo - different error messages per OS LatteOverlay_init(); // run a couple of tests if in non-release mode -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT unitTests(); #endif // init common @@ -338,39 +338,30 @@ void ToolShaderCacheMerger(); #if BOOST_OS_WINDOWS -#ifndef PUBLIC_RELEASE -#include -int wmain(int argc, wchar_t* argv[]) -{ - SDL_SetMainReady(); - _CrtSetDbgFlag(_CRTDBG_CHECK_DEFAULT_DF); - //ToolShaderCacheMerger(); - - if (!LaunchSettings::HandleCommandline(argc, argv)) - return 0; - - ActiveSettings::LoadOnce(); - - HandlePostUpdate(); - return mainEmulatorHLE(); -} -#else +// entrypoint for release builds int wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nShowCmd) { SDL_SetMainReady(); - if (!LaunchSettings::HandleCommandline(lpCmdLine)) return 0; - ActiveSettings::LoadOnce(); - HandlePostUpdate(); return mainEmulatorHLE(); } -#endif +// entrypoint for debug builds with console +int main(int argc, char* argv[]) +{ + SDL_SetMainReady(); + if (!LaunchSettings::HandleCommandline(argc, argv)) + return 0; + ActiveSettings::LoadOnce(); + HandlePostUpdate(); + return mainEmulatorHLE(); +} #else + int main(int argc, char *argv[]) { #if BOOST_OS_LINUX diff --git a/src/util/Zir/EmitterGLSL/ZpIREmitGLSL.cpp b/src/util/Zir/EmitterGLSL/ZpIREmitGLSL.cpp index cb42111b..d20adc60 100644 --- a/src/util/Zir/EmitterGLSL/ZpIREmitGLSL.cpp +++ b/src/util/Zir/EmitterGLSL/ZpIREmitGLSL.cpp @@ -95,7 +95,7 @@ namespace ZirEmitter void GLSL::GenerateBasicBlockCode(ZpIR::ZpIRBasicBlock& basicBlock) { // init context -#ifndef PUBLIC_RELEASE +#ifdef CEMU_DEBUG_ASSERT for (auto& itr : m_blockContext.regInlinedExpression) { cemu_assert_debug(itr == nullptr); // leaked buffer diff --git a/src/util/helpers/helpers.cpp b/src/util/helpers/helpers.cpp index a52aa439..99712296 100644 --- a/src/util/helpers/helpers.cpp +++ b/src/util/helpers/helpers.cpp @@ -139,8 +139,6 @@ typedef struct tagTHREADNAME_INFO void SetThreadName(const char* name) { #if BOOST_OS_WINDOWS - -#ifndef _PUBLIC_RELEASE THREADNAME_INFO info; info.dwType = 0x1000; info.szName = name; @@ -154,9 +152,6 @@ void SetThreadName(const char* name) __except (EXCEPTION_EXECUTE_HANDLER) { } #pragma warning(pop) - -#endif - #elif BOOST_OS_MACOS pthread_setname_np(name); #else From 8e89187f958032d06cd17d28e5b397eae82d1179 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sat, 24 Sep 2022 11:11:54 +0200 Subject: [PATCH 022/638] Remove misleading link from generated experimental releases --- .github/workflows/deploy_experimental_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy_experimental_release.yml b/.github/workflows/deploy_experimental_release.yml index 53afe4a8..c7f32673 100644 --- a/.github/workflows/deploy_experimental_release.yml +++ b/.github/workflows/deploy_experimental_release.yml @@ -77,4 +77,4 @@ jobs: wget -O ghr.tar.gz https://github.com/tcnksm/ghr/releases/download/v0.15.0/ghr_v0.15.0_linux_amd64.tar.gz tar xvzf ghr.tar.gz; rm ghr.tar.gz echo "[INFO] Release tag: v${{ env.CEMU_VERSION }}" - ghr_v0.15.0_linux_amd64/ghr -prerelease -t ${{ secrets.GITHUB_TOKEN }} -n "Cemu ${{ env.CEMU_VERSION }} (Experimental)" -b "Cemu experimental release - [changelog](https://cemu.info/changelog.html)" "v${{ env.CEMU_VERSION }}" ./upload + ghr_v0.15.0_linux_amd64/ghr -prerelease -t ${{ secrets.GITHUB_TOKEN }} -n "Cemu ${{ env.CEMU_VERSION }} (Experimental)" -b "Cemu experimental release" ./upload From 9caf57c2c55e82cb5209d9a0d890fbd204f89d2c Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sat, 24 Sep 2022 11:44:44 +0200 Subject: [PATCH 023/638] Vulkan: Fix incorrect encoding for substituted R4G4 format (#288) Fixed incorrect channel order when VK_FORMAT_R4G4_UNORM_PACK8 is substituted with VK_FORMAT_R4G4B4A4_UNORM_PACK16 --- src/Cafe/HW/Latte/Core/LatteTextureLoader.h | 4 ++-- src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Cafe/HW/Latte/Core/LatteTextureLoader.h b/src/Cafe/HW/Latte/Core/LatteTextureLoader.h index 7c89a09a..25321006 100644 --- a/src/Cafe/HW/Latte/Core/LatteTextureLoader.h +++ b/src/Cafe/HW/Latte/Core/LatteTextureLoader.h @@ -612,8 +612,8 @@ public: uint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y); sint32 pixelOffset = (x + yc * textureLoader->width) * 2; uint8 v = (*(uint8*)(blockData + 0)); - *(uint8*)(outputData + pixelOffset + 1) = 0; - *(uint8*)(outputData + pixelOffset + 0) = ((v >> 4) & 0xF) | ((v << 4) & 0xF0); // todo: Is this nibble swap correct? + *(uint8*)(outputData + pixelOffset + 0) = 0; + *(uint8*)(outputData + pixelOffset + 1) = v; } } } diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index 338d09af..fbc268cb 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -2571,7 +2571,7 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD else { formatInfoOut->vkImageFormat = VK_FORMAT_R4G4_UNORM_PACK8; - formatInfoOut->decoder = TextureDecoder_R4_G4::getInstance(); // todo - verify if order of R/G matches between GX2/Vulkan + formatInfoOut->decoder = TextureDecoder_R4_G4::getInstance(); } break; // R formats From 101ff7783ea8d39bbf0d8f2ec7c3f65168870d65 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sat, 24 Sep 2022 12:55:13 +0200 Subject: [PATCH 024/638] Revert accidental removal of release tag --- .github/workflows/deploy_experimental_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy_experimental_release.yml b/.github/workflows/deploy_experimental_release.yml index c7f32673..31a661e2 100644 --- a/.github/workflows/deploy_experimental_release.yml +++ b/.github/workflows/deploy_experimental_release.yml @@ -77,4 +77,4 @@ jobs: wget -O ghr.tar.gz https://github.com/tcnksm/ghr/releases/download/v0.15.0/ghr_v0.15.0_linux_amd64.tar.gz tar xvzf ghr.tar.gz; rm ghr.tar.gz echo "[INFO] Release tag: v${{ env.CEMU_VERSION }}" - ghr_v0.15.0_linux_amd64/ghr -prerelease -t ${{ secrets.GITHUB_TOKEN }} -n "Cemu ${{ env.CEMU_VERSION }} (Experimental)" -b "Cemu experimental release" ./upload + ghr_v0.15.0_linux_amd64/ghr -prerelease -t ${{ secrets.GITHUB_TOKEN }} -n "Cemu ${{ env.CEMU_VERSION }} (Experimental)" -b "Cemu experimental release" "v${{ env.CEMU_VERSION }}" ./upload From 53c7daa603c3c4984147c3c0955a58ad4ba6424c Mon Sep 17 00:00:00 2001 From: emiyl Date: Sun, 25 Sep 2022 20:38:31 +0100 Subject: [PATCH 025/638] [docs] Add brew installation instructions for macos (#303) --- BUILD.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/BUILD.md b/BUILD.md index f4d7c72e..f180b221 100644 --- a/BUILD.md +++ b/BUILD.md @@ -65,7 +65,10 @@ To compile Cemu, a recent enough compiler and STL with C++20 support is required below, built in LLVM, and Xcode LLVM don't support the C++20 feature set required. Currently, LLVM 15 isn't supported due to compatibility issues with Boost dependency. The OpenGL graphics API isn't support on MacOS, Vulkan must be used. Additionally Vulkan must be used through the -Molten-VK compatibility layer. +Molten-VK compatibility layer. + +### Installing brew +`/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"` ### Installing dependencies `brew install git cmake llvm@14 ninja nasm molten-vk` From 25dae98ce015c18ff1ae62a19e63cf12d2ae7c9a Mon Sep 17 00:00:00 2001 From: SSimco <37044560+SSimco@users.noreply.github.com> Date: Sun, 25 Sep 2022 22:53:10 -0700 Subject: [PATCH 026/638] Fix crash on GTK when a gfx pack preset value is changed (#300) --- src/gui/GraphicPacksWindow2.cpp | 34 ++++++++++++++++++++++++++++++++- src/gui/GraphicPacksWindow2.h | 1 + 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/gui/GraphicPacksWindow2.cpp b/src/gui/GraphicPacksWindow2.cpp index 3759580e..bab55156 100644 --- a/src/gui/GraphicPacksWindow2.cpp +++ b/src/gui/GraphicPacksWindow2.cpp @@ -529,6 +529,38 @@ void GraphicPacksWindow2::OnTreeChoiceChanged(wxTreeEvent& event) m_graphic_pack_tree->SelectItem(item); } +// In some environments with GTK (e.g. a flatpak app with org.freedesktop.Platform 22.08 runtime), +// destroying the event source inside the handler crashes the app. +// As a workaround to that, the wxWindow that needs to be destroyed is hidden and then +// destroyed at a later time, outside the handler. +void GraphicPacksWindow2::ClearPresets() +{ + size_t item_count = m_preset_sizer->GetItemCount(); + std::vector sizers; + sizers.reserve(item_count); + for (size_t i = 0; i < item_count; i++) + sizers.push_back(m_preset_sizer->GetItem(i)->GetSizer()); + + for (auto&& sizer : sizers) + { + auto static_box_sizer = dynamic_cast(sizer); + if (static_box_sizer) + { + wxStaticBox* parent_window = static_box_sizer->GetStaticBox(); + if (parent_window) + { + m_preset_sizer->Detach(sizer); + parent_window->Hide(); + CallAfter([=]() + { + parent_window->DestroyChildren(); + delete static_box_sizer; + }); + } + } + } +} + void GraphicPacksWindow2::OnActivePresetChanged(wxCommandEvent& event) { if (!m_shown_graphic_pack) @@ -542,7 +574,7 @@ void GraphicPacksWindow2::OnActivePresetChanged(wxCommandEvent& event) if(m_shown_graphic_pack->SetActivePreset(string_data->GetData().c_str().AsChar(), preset)) { wxWindowUpdateLocker lock(this); - m_preset_sizer->Clear(true); + ClearPresets(); LoadPresetSelections(m_shown_graphic_pack); //m_preset_sizer->GetContainingWindow()->Layout(); //m_right_panel->FitInside(); diff --git a/src/gui/GraphicPacksWindow2.h b/src/gui/GraphicPacksWindow2.h index 82b13c72..a068f2b6 100644 --- a/src/gui/GraphicPacksWindow2.h +++ b/src/gui/GraphicPacksWindow2.h @@ -27,6 +27,7 @@ private: bool m_filter_installed_games; std::vector m_installed_games; + void ClearPresets(); void FillGraphicPackList() const; void GetChildren(const wxTreeItemId& id, std::vector& children) const; void ExpandChildren(const std::vector& ids, size_t& counter) const; From 35afb99c99ce4c08b6eb94efb3172022a121d9f8 Mon Sep 17 00:00:00 2001 From: goeiecool9999 Date: Tue, 27 Sep 2022 12:48:35 +0200 Subject: [PATCH 027/638] [docs] Add llvm as a required package for Arch Linux (#308) --- BUILD.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD.md b/BUILD.md index f180b221..daa846cb 100644 --- a/BUILD.md +++ b/BUILD.md @@ -33,7 +33,7 @@ To compile Cemu, a recent enough compiler and STL with C++20 support is required `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang-12 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-12 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja` #### For Arch and derivatives: -`sudo pacman -S git cmake clang ninja nasm base-devel linux-headers gtk3 libsecret libgcrypt systemd freeglut zip unzip libpulse` +`sudo pacman -S git cmake llvm clang ninja nasm base-devel linux-headers gtk3 libsecret libgcrypt systemd freeglut zip unzip libpulse` #### For Fedora and derivatives: `sudo dnf install git cmake clang ninja-build nasm kernel-headers gtk3-devel libsecret-devel libgcrypt-devel systemd-devel freeglut-devel perl-core zlib-devel cubeb-devel` From 6ecc4be0da18cb697fbaba1224ec871ae53a41ae Mon Sep 17 00:00:00 2001 From: goeiecool9999 Date: Tue, 27 Sep 2022 13:58:50 +0200 Subject: [PATCH 028/638] Posix/Linux: Add setting to disable coredumps --- .../ExceptionHandler_posix.cpp | 77 ++++++++++++++----- src/config/CemuConfig.cpp | 12 ++- src/config/CemuConfig.h | 27 +++++++ src/gui/GeneralSettings2.cpp | 8 ++ 4 files changed, 102 insertions(+), 22 deletions(-) diff --git a/src/Common/ExceptionHandler/ExceptionHandler_posix.cpp b/src/Common/ExceptionHandler/ExceptionHandler_posix.cpp index b9ecb782..e2ea3d33 100644 --- a/src/Common/ExceptionHandler/ExceptionHandler_posix.cpp +++ b/src/Common/ExceptionHandler/ExceptionHandler_posix.cpp @@ -1,36 +1,73 @@ #include #include +#include -void handler_SIGSEGV(int sig) +#include "config/CemuConfig.h" + +// handle signals that would dump core, print stacktrace and then dump depending on config +void handlerDumpingSignal(int sig) { - printf("SIGSEGV!\n"); + char* sigName = strsignal(sig); + if (sigName) + { + printf("%s!\n", sigName); + } + else + { + // should never be the case + printf("Unknown core dumping signal!\n"); + } - void *array[32]; - size_t size; + void *array[32]; + size_t size; - // get void*'s for all entries on the stack - size = backtrace(array, 32); + // get void*'s for all entries on the stack + size = backtrace(array, 32); - // print out all the frames to stderr - fprintf(stderr, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, STDERR_FILENO); - exit(1); + // print out all the frames to stderr + fprintf(stderr, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, STDERR_FILENO); + + if (GetConfig().crash_dump == CrashDump::Enabled) + { + // reset signal handler to default and re-raise signal to dump core + signal(sig, SIG_DFL); + raise(sig); + return; + } + // exit process ignoring all issues + _Exit(1); } void handler_SIGINT(int sig) { - /* - * Received when pressing CTRL + C in a console - * Ideally should be exiting cleanly after saving settings but currently - * there's no clean exit pathway (at least on linux) and exiting the app - * by any mean ends up with a SIGABRT from the standard library destroying - * threads. - */ - _Exit(0); + /* + * Received when pressing CTRL + C in a console + * Ideally should be exiting cleanly after saving settings but currently + * there's no clean exit pathway (at least on linux) and exiting the app + * by any mean ends up with a SIGABRT from the standard library destroying + * threads. + */ + _Exit(0); } void ExceptionHandler_init() { - signal(SIGSEGV, handler_SIGSEGV); - signal(SIGINT, handler_SIGINT); + struct sigaction action; + action.sa_flags = 0; + sigfillset(&action.sa_mask); // don't allow signals to be interrupted + + action.sa_handler = handler_SIGINT; + sigaction(SIGINT, &action, nullptr); + + action.sa_handler = handlerDumpingSignal; + sigaction(SIGABRT, &action, nullptr); + sigaction(SIGBUS, &action, nullptr); + sigaction(SIGFPE, &action, nullptr); + sigaction(SIGILL, &action, nullptr); + sigaction(SIGIOT, &action, nullptr); + sigaction(SIGQUIT, &action, nullptr); + sigaction(SIGSEGV, &action, nullptr); + sigaction(SIGSYS, &action, nullptr); + sigaction(SIGTRAP, &action, nullptr); } diff --git a/src/config/CemuConfig.cpp b/src/config/CemuConfig.cpp index f996fc94..dcd283ec 100644 --- a/src/config/CemuConfig.cpp +++ b/src/config/CemuConfig.cpp @@ -316,7 +316,11 @@ void CemuConfig::Load(XMLConfigParser& parser) // debug auto debug = parser.get("Debug"); - crash_dump = debug.get("CrashDump", crash_dump); +#if BOOST_OS_WINDOWS + crash_dump = debug.get("CrashDumpWindows", crash_dump); +#elif BOOST_OS_UNIX + crash_dump = debug.get("CrashDumpUnix", crash_dump); +#endif // input auto input = parser.get("Input"); @@ -487,7 +491,11 @@ void CemuConfig::Save(XMLConfigParser& parser) // debug auto debug = config.set("Debug"); - debug.set("CrashDump", crash_dump.GetValue()); +#if BOOST_OS_WINDOWS + debug.set("CrashDumpWindows", crash_dump.GetValue()); +#elif BOOST_OS_UNIX + debug.set("CrashDumpUnix", crash_dump.GetValue()); +#endif // input auto input = config.set("Input"); diff --git a/src/config/CemuConfig.h b/src/config/CemuConfig.h index 8c43f0a5..caabf082 100644 --- a/src/config/CemuConfig.h +++ b/src/config/CemuConfig.h @@ -172,6 +172,7 @@ enum class CafeConsoleLanguage }; ENABLE_ENUM_ITERATORS(CafeConsoleLanguage, CafeConsoleLanguage::JA, CafeConsoleLanguage::TW); +#if BOOST_OS_WINDOWS enum class CrashDump { Disabled, @@ -179,6 +180,14 @@ enum class CrashDump Full }; ENABLE_ENUM_ITERATORS(CrashDump, CrashDump::Disabled, CrashDump::Full); +#elif BOOST_OS_UNIX +enum class CrashDump +{ + Disabled, + Enabled +}; +ENABLE_ENUM_ITERATORS(CrashDump, CrashDump::Disabled, CrashDump::Enabled); +#endif template <> struct fmt::formatter : formatter { @@ -290,6 +299,7 @@ struct fmt::formatter : formatter { } }; +#if BOOST_OS_WINDOWS template <> struct fmt::formatter : formatter { template @@ -306,6 +316,23 @@ struct fmt::formatter : formatter { return formatter::format(name, ctx); } }; +#elif BOOST_OS_UNIX +template <> +struct fmt::formatter : formatter { + template + auto format(const CrashDump v, FormatContext &ctx) { + string_view name; + switch (v) + { + case CrashDump::Disabled: name = "Disabled"; break; + case CrashDump::Enabled: name = "Enabled"; break; + default: name = "unknown"; break; + + } + return formatter::format(name, ctx); + } +}; +#endif struct CemuConfig diff --git a/src/gui/GeneralSettings2.cpp b/src/gui/GeneralSettings2.cpp index f81e7364..6c4f5bbb 100644 --- a/src/gui/GeneralSettings2.cpp +++ b/src/gui/GeneralSettings2.cpp @@ -709,10 +709,18 @@ wxPanel* GeneralSettings2::AddDebugPage(wxNotebook* notebook) debug_row->Add(new wxStaticText(panel, wxID_ANY, _("Crash dump"), wxDefaultPosition, wxDefaultSize, 0), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); +#if BOOST_OS_WINDOWS wxString dump_choices[] = { _("Disabled"), _("Lite"), _("Full") }; +#elif BOOST_OS_UNIX + wxString dump_choices[] = { _("Disabled"), _("Enabled") }; +#endif m_crash_dump = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, std::size(dump_choices), dump_choices); m_crash_dump->SetSelection(0); +#if BOOST_OS_WINDOWS m_crash_dump->SetToolTip(_("Creates a dump when Cemu crashes\nOnly enable when requested by a developer!\nThe Full option will create a very large dump file (includes a full RAM dump of the Cemu process)")); +#elif BOOST_OS_UNIX + m_crash_dump->SetToolTip(_("Creates a core dump when Cemu crashes\nOnly enable when requested by a developer!")); +#endif debug_row->Add(m_crash_dump, 0, wxALL | wxEXPAND, 5); debug_panel_sizer->Add(debug_row, 0, wxALL | wxEXPAND, 5); From a28d67bafd6a7d81707064d079a8d6aeefc5e29f Mon Sep 17 00:00:00 2001 From: UltraHDR <108294295+UltraHDR@users.noreply.github.com> Date: Tue, 27 Sep 2022 21:18:35 +0100 Subject: [PATCH 029/638] Remove -DPUBLIC_RELEASE=ON from macOS command (#309) --- BUILD.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD.md b/BUILD.md index daa846cb..3dc69b18 100644 --- a/BUILD.md +++ b/BUILD.md @@ -76,7 +76,7 @@ Molten-VK compatibility layer. ### Build Cemu using cmake and clang 1. `git clone --recursive https://github.com/cemu-project/Cemu` 2. `cd Cemu` -3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DPUBLIC_RELEASE=ON +3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/local/opt/llvm@14/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@14/bin/clang++ -G Ninja` 4. `cmake --build build` 5. You should now have a Cemu executable file in the /bin folder, which you can run using `./bin/Cemu_release`. From 3fb4b5e26c0125dda68b3858e8c3d9589244c211 Mon Sep 17 00:00:00 2001 From: Tillsunset <35825944+Tillsunset@users.noreply.github.com> Date: Thu, 29 Sep 2022 04:36:27 -0500 Subject: [PATCH 030/638] MacOS+Linux: Use CLOCK_MONOTONIC_RAW over CLOCK_MONOTONIC (#313) On MacOS this fixes the framerate being too high due to discontinuities in the timer that drives the emulated vsync. It also fixes behavior of the GetTickCount() wrapper. --- src/Common/unix/platform.cpp | 2 +- src/util/highresolutiontimer/HighResolutionTimer.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Common/unix/platform.cpp b/src/Common/unix/platform.cpp index d97f4e65..a111a625 100644 --- a/src/Common/unix/platform.cpp +++ b/src/Common/unix/platform.cpp @@ -4,6 +4,6 @@ uint32_t GetTickCount() { struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); return (1000 * ts.tv_sec + ts.tv_nsec / 1000000); } \ No newline at end of file diff --git a/src/util/highresolutiontimer/HighResolutionTimer.cpp b/src/util/highresolutiontimer/HighResolutionTimer.cpp index 21cabff5..510fdfa5 100644 --- a/src/util/highresolutiontimer/HighResolutionTimer.cpp +++ b/src/util/highresolutiontimer/HighResolutionTimer.cpp @@ -9,7 +9,7 @@ HighResolutionTimer HighResolutionTimer::now() return HighResolutionTimer(pc.QuadPart); #else timespec pc; - clock_gettime(CLOCK_MONOTONIC, &pc); + clock_gettime(CLOCK_MONOTONIC_RAW, &pc); uint64 nsec = (uint64)pc.tv_sec * (uint64)1000000000 + (uint64)pc.tv_nsec; return HighResolutionTimer(nsec); #endif @@ -28,7 +28,7 @@ uint64 HighResolutionTimer::m_freq = []() -> uint64 { return (uint64)(freq.QuadPart); #else timespec pc; - clock_getres(CLOCK_MONOTONIC, &pc); + clock_getres(CLOCK_MONOTONIC_RAW, &pc); return (uint64)1000000000 / (uint64)pc.tv_nsec; #endif }(); From 37672572204230a2c4cd6d1282ccf48b51afb259 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Thu, 29 Sep 2022 06:00:46 -0500 Subject: [PATCH 031/638] nfp: Fix corruption, correct structs and use write counters (#310) --- src/Cafe/OS/libs/nn_nfp/AmiiboCrypto.h | 4 +- src/Cafe/OS/libs/nn_nfp/nn_nfp.cpp | 116 +++++++++++++++++-------- 2 files changed, 82 insertions(+), 38 deletions(-) diff --git a/src/Cafe/OS/libs/nn_nfp/AmiiboCrypto.h b/src/Cafe/OS/libs/nn_nfp/AmiiboCrypto.h index 1c918e1e..9a326237 100644 --- a/src/Cafe/OS/libs/nn_nfp/AmiiboCrypto.h +++ b/src/Cafe/OS/libs/nn_nfp/AmiiboCrypto.h @@ -261,7 +261,7 @@ void amiiboEncrypt(AmiiboRawNFCData* nfcOutput) amiiboCrypto_internalToNfcFormat(&internalCopy, nfcOutput); // restore NFC values that aren't part of the internal representation - memcpy(nfcOutput->lockBytes, nfp_data.amiiboNFCData.lockBytes, 4); + memcpy(nfcOutput->dynamicLock, nfp_data.amiiboNFCData.dynamicLock, 4); memcpy(nfcOutput->cfg0, nfp_data.amiiboNFCData.cfg0, 4); memcpy(nfcOutput->cfg1, nfp_data.amiiboNFCData.cfg1, 4); -} \ No newline at end of file +} diff --git a/src/Cafe/OS/libs/nn_nfp/nn_nfp.cpp b/src/Cafe/OS/libs/nn_nfp/nn_nfp.cpp index 0c567b5a..faeed95c 100644 --- a/src/Cafe/OS/libs/nn_nfp/nn_nfp.cpp +++ b/src/Cafe/OS/libs/nn_nfp/nn_nfp.cpp @@ -25,16 +25,20 @@ void nnNfpUnlock() struct AmiiboInternal { - /* +0x000 */ uint32 ukn000; - /* +0x004 */ uint32 ukn004; + /* +0x000 */ uint16 lockBytes; + /* +0x002 */ uint16 staticLock; + /* +0x004 */ uint32 cc; /* +0x008 */ uint8 dataHMAC[32]; - /* +0x028 */ uint32 ukn028; + /* +0x028 */ uint8 ukn_A5; // always 0xA5 + /* +0x029 */ uint8 writeCounterHigh; + /* +0x029 */ uint8 writeCounterLow; + /* +0x02B */ uint8 unk02B; /* encrypted region starts here */ - struct + struct { /* +0x02C */ uint8 flags; /* +0x02D */ uint8 countryCode; - /* +0x02E */ uint16be writeCounter; + /* +0x02E */ uint16be crcWriteCounter; /* +0x030 */ uint16be date1; /* +0x032 */ uint16be date2; /* +0x034 */ uint32be crc; @@ -42,7 +46,7 @@ struct AmiiboInternal /* +0x04C */ uint8 mii[0x60]; /* +0x0AC */ uint32be appDataTitleIdHigh; /* +0x0B0 */ uint32be appDataTitleIdLow; - /* +0x0B4 */ uint16be writeCounter2; + /* +0x0B4 */ uint16be appWriteCounter; /* +0x0B6 */ uint16be appDataIdHigh; /* +0x0B8 */ uint16be appDataIdLow; /* +0x0BA */ uint16be ukn0BA; @@ -70,11 +74,19 @@ struct AmiiboInternal /* +0x0DC */ uint8 applicationData[0xD8]; /* encrypted region ends here */ /* +0x1B4 */ uint8 tagHMAC[32]; - /* +0x1D4 */ uint32 ukn1D4; - /* +0x1D8 */ uint32 ukn1D8; - /* +0x1DC */ uint32 ukn1DC; - /* +0x1E0 */ uint8 ukn1E0[0x20]; - /* +0x200 */ uint8 ukn200[0x8]; + /* +0x1D4 */ uint8 ntagSerial[7]; + /* +0x1DB */ uint8 nintendoId; + struct + { + /* +0x1DC */ uint8 gameAndCharacterId[2]; + /* +0x1DE */ uint8 characterVariation; + /* +0x1DF */ uint8 amiiboFigureType; + /* +0x1E0 */ uint8 amiiboModelNumber[2]; + /* +0x1E2 */ uint8 amiiboSeries; + /* +0x1E3 */ uint8 ukn_02; // always 0x02 ? + /* +0x1E4 */ uint8 ukn5C[4]; + }amiiboIdentificationBlock; + /* +0x1E8 */ uint8 keygenSalt[32]; }; static_assert(sizeof(AmiiboInternal) == 0x208); @@ -87,7 +99,7 @@ static_assert(offsetof(AmiiboInternal, tagHMAC) == 0x1B4); union AmiiboRawNFCData { // each page is 4 bytes - struct + struct { uint8 page0[4]; uint8 page1[4]; @@ -107,21 +119,24 @@ union AmiiboRawNFCData uint8 page15[4]; uint8 page16[4]; }; - struct + struct { - uint8 rawByte[16*4]; + uint8 rawByte[16 * 4]; }; - struct + struct { - /*+0x000 */ uint8 ntagSerial[9]; - /*+0x009 */ uint8 ukn009; - /*+0x00A */ uint8 lockBytes[2]; - /*+0x00C */ uint8 cc[4]; - /*+0x010 */ uint8 ukn010[4]; - /*+0x014 */ uint8 ukn014[32]; // crypto related? - /*+0x034 */ uint8 tagHMAC[32]; // data hmac - /*+0x054 */ - struct + /* +0x000 */ uint8 ntagSerial[7]; + /* +0x007 */ uint8 nintendoId; + /* +0x008 */ uint8 lockBytes[2]; + /* +0x00A */ uint8 staticLock[2]; + /* +0x00C */ uint8 cc[4]; // compatibility container + /* +0x010 */ uint8 ukn_A5; // always 0xA5 + /* +0x011 */ uint8 writeCounter[2]; + /* +0x013 */ uint8 unk013; + /* +0x014 */ uint8 encryptedSettings[32]; + /* +0x034 */ uint8 tagHMAC[32]; // data hmac + /* +0x054 */ + struct { /* +0x54 */ uint8 gameAndCharacterId[2]; /* +0x56 */ uint8 characterVariation; @@ -129,15 +144,20 @@ union AmiiboRawNFCData /* +0x58 */ uint8 amiiboModelNumber[2]; /* +0x5A */ uint8 amiiboSeries; /* +0x5B */ uint8 ukn_02; // always 0x02 ? - - /* +0x5C */ uint8 ukn00[0x80-0x5C]; // not part of identification block? + /* +0x5C */ uint8 ukn5C[4]; }amiiboIdentificationBlock; - /*+0x080 */ uint8 dataHMAC[32]; - /*+0x0A0 */ uint8 ukn0A0[0x114]; - /*+0x1B4 */ uint8 ukn1B4[0x54]; - /*+0x208 */ uint8 lockBytes208[4]; - /*+0x20C */ uint8 cfg0[4]; - /*+0x210 */ uint8 cfg1[4]; + /* +0x060 */ uint8 keygenSalt[32]; + /* +0x080 */ uint8 dataHMAC[32]; + /* +0x0A0 */ uint8 encryptedMii[0x60]; + /* +0x100 */ uint8 encryptedTitleId[8]; + /* +0x108 */ uint8 encryptedApplicationWriteCounter[2]; + /* +0x10A */ uint8 encryptedApplicationAreaId[4]; + /* +0x10E */ uint8 ukn10E[2]; + /* +0x110 */ uint8 unk110[32]; + /* +0x130 */ uint8 encryptedApplicationArea[0xD8]; + /* +0x208 */ uint8 dynamicLock[4]; + /* +0x20C */ uint8 cfg0[4]; + /* +0x210 */ uint8 cfg1[4]; }; }; @@ -400,7 +420,7 @@ typedef struct typedef struct { /* +0x00 */ nfpDate_t date; - /* +0x04 */ uint16be writeCount; + /* +0x04 */ uint8 writeCount[2]; /* +0x06 */ uint8 characterId[3]; /* +0x09 */ uint8 amiiboSeries; /* +0x0A */ uint16be number; @@ -435,6 +455,9 @@ void nnNfpExport_GetNfpCommonInfo(PPCInterpreter_t* hCPU) forceLogDebug_printf("GetNfpCommonInfo(0x%08x)"); + commonInfo->writeCount[0] = nfp_data.amiiboNFCData.writeCounter[0]; + commonInfo->writeCount[1] = nfp_data.amiiboNFCData.writeCounter[1]; + commonInfo->characterId[0] = nfp_data.amiiboNFCData.amiiboIdentificationBlock.gameAndCharacterId[0]; commonInfo->characterId[1] = nfp_data.amiiboNFCData.amiiboIdentificationBlock.gameAndCharacterId[1]; commonInfo->characterId[2] = nfp_data.amiiboNFCData.amiiboIdentificationBlock.characterVariation; @@ -590,6 +613,8 @@ void nnNfpExport_WriteApplicationArea(PPCInterpreter_t* hCPU) for (uint32 i = len; i < sizeof(nfp_data.amiiboInternal.applicationData); i++) nfp_data.amiiboInternal.applicationData[i] = rand() & 0xFF; + nfp_data.amiiboInternal.amiiboSettings.appWriteCounter = nfp_data.amiiboInternal.amiiboSettings.appWriteCounter + 1; + osLib_returnFromFunction(hCPU, BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_NFP, 0)); } @@ -629,6 +654,7 @@ void nnNfpExport_CreateApplicationArea(PPCInterpreter_t* hCPU) nfp_data.amiiboInternal.amiiboSettings.setAppDataAppId(createInfo->appAreaId); nfp_data.amiiboInternal.amiiboSettings.flags |= 0x20; // set application data exists bit + nfp_data.amiiboInternal.amiiboSettings.appWriteCounter = nfp_data.amiiboInternal.amiiboSettings.appWriteCounter + 1; nfp_data.hasOpenApplicationArea = false; @@ -666,6 +692,7 @@ void nnNfpExport_DeleteApplicationArea(PPCInterpreter_t* hCPU) nfp_data.amiiboInternal.amiiboSettings.setAppDataAppId(0); nfp_data.amiiboInternal.amiiboSettings.flags &= ~0x20; + nfp_data.amiiboInternal.amiiboSettings.appWriteCounter = nfp_data.amiiboInternal.amiiboSettings.appWriteCounter + 1; // this API forces a flush if (!nnNfp_writeCurrentAmiibo()) @@ -760,6 +787,17 @@ bool nnNfp_touchNfcTagFromFile(const wchar_t* filePath, uint32* nfcError) memcpy(&rawData, nfcData->data(), sizeof(AmiiboRawNFCData)); // verify if the file is a valid ntag215/amiibo file + if (rawData.dynamicLock[0] != 0x01 || rawData.dynamicLock[1] != 0x00 || rawData.dynamicLock[2] != 0x0F || rawData.dynamicLock[3] != 0xBD) + { + // Temporary workaround to fix corrupted files by old cemu versions + rawData.dynamicLock[0] = 0x01; + rawData.dynamicLock[1] = 0x00; + rawData.dynamicLock[2] = 0x0F; + rawData.dynamicLock[3] = 0xBD; + + // *nfcError = NFC_ERROR_INVALID_FILE_FORMAT; + // return false; + } if (rawData.cfg0[0] != 0x00 || rawData.cfg0[1] != 0x00 || rawData.cfg0[2] != 0x00 || rawData.cfg0[3] != 0x04) { *nfcError = NFC_ERROR_INVALID_FILE_FORMAT; @@ -770,7 +808,7 @@ bool nnNfp_touchNfcTagFromFile(const wchar_t* filePath, uint32* nfcError) *nfcError = NFC_ERROR_INVALID_FILE_FORMAT; return false; } - if (rawData.lockBytes[0] != 0x0F || rawData.lockBytes[1] != 0xE0 ) + if (rawData.staticLock[0] != 0x0F || rawData.staticLock[1] != 0xE0) { *nfcError = NFC_ERROR_INVALID_FILE_FORMAT; return false; @@ -789,10 +827,10 @@ bool nnNfp_touchNfcTagFromFile(const wchar_t* filePath, uint32* nfcError) serialNumber[3] = rawData.ntagSerial[4]; serialNumber[4] = rawData.ntagSerial[5]; serialNumber[5] = rawData.ntagSerial[6]; - serialNumber[6] = rawData.ntagSerial[7]; + serialNumber[6] = rawData.nintendoId; uint8 serialCheckByte0 = rawData.ntagSerial[3]; - uint8 serialCheckByte1 = rawData.ntagSerial[8]; + uint8 serialCheckByte1 = rawData.lockBytes[0]; uint8 bcc0 = serialNumber[0] ^ serialNumber[1] ^ serialNumber[2] ^ 0x88; uint8 bcc1 = serialNumber[3] ^ serialNumber[4] ^ serialNumber[5] ^ serialNumber[6]; @@ -830,6 +868,12 @@ bool nnNfp_writeCurrentAmiibo() nnNfpUnlock(); return false; } + + uint16 writeCounter = nfp_data.amiiboInternal.writeCounterLow + (nfp_data.amiiboInternal.writeCounterHigh << 8); + writeCounter++; + nfp_data.amiiboInternal.writeCounterLow = writeCounter & 0xFF; + nfp_data.amiiboInternal.writeCounterHigh = (writeCounter >> 8) & 0xFF; + // open file for writing FileStream* fs = FileStream::openFile2(nfp_data.amiiboPath, true); if (!fs) From ecfbbd4e265f1b58618fa2f7770951956d9a553f Mon Sep 17 00:00:00 2001 From: emiyl Date: Fri, 30 Sep 2022 14:28:56 +0100 Subject: [PATCH 032/638] MoltenVK: Workaround for unsupported formats (#315) --- .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 60 +++++++++++++++---- .../HW/Latte/Renderer/Vulkan/VulkanRenderer.h | 2 + 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index fbc268cb..03ffb7f5 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -1929,6 +1929,20 @@ void VulkanRenderer::QueryAvailableFormats() { m_supportedFormatInfo.fmt_r4g4_unorm_pack = true; } + // R4G4B4A4 + fmtProp = {}; + vkGetPhysicalDeviceFormatProperties(m_physical_device, VK_FORMAT_R4G4B4A4_UNORM_PACK16, &fmtProp); + if (fmtProp.optimalTilingFeatures != 0) + { + m_supportedFormatInfo.fmt_r4g4b4a4_unorm_pack = true; + } + // A1R5G5B5 + fmtProp = {}; + vkGetPhysicalDeviceFormatProperties(m_physical_device, VK_FORMAT_A1R5G5B5_UNORM_PACK16, &fmtProp); + if (fmtProp.optimalTilingFeatures != 0) + { + m_supportedFormatInfo.fmt_a1r5g5b5_unorm_pack = true; + } // print info about unsupported formats to log for (auto& it : requestedFormatList) { @@ -2565,8 +2579,14 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD case Latte::E_GX2SURFFMT::R4_G4_UNORM: if (m_supportedFormatInfo.fmt_r4g4_unorm_pack == false) { - formatInfoOut->vkImageFormat = VK_FORMAT_R4G4B4A4_UNORM_PACK16; - formatInfoOut->decoder = TextureDecoder_R4_G4_UNORM_toRGBA4444_vk::getInstance(); + if (m_supportedFormatInfo.fmt_r4g4b4a4_unorm_pack == false) { + formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM; + formatInfoOut->decoder = nullptr; + } + else { + formatInfoOut->vkImageFormat = VK_FORMAT_R4G4B4A4_UNORM_PACK16; + formatInfoOut->decoder = TextureDecoder_R4_G4_UNORM_toRGBA4444_vk::getInstance(); + } } else { @@ -2618,23 +2638,41 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD formatInfoOut->decoder = TextureDecoder_R5_G6_B5_swappedRB::getInstance(); break; case Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM: - // used in Super Mario 3D World for the hidden Luigi sprites - // since order of channels is reversed in Vulkan compared to GX2 the format we need is A1B5G5R5 - formatInfoOut->vkImageFormat = VK_FORMAT_A1R5G5B5_UNORM_PACK16; - formatInfoOut->decoder = TextureDecoder_R5_G5_B5_A1_UNORM_swappedRB::getInstance(); + if (m_supportedFormatInfo.fmt_a1r5g5b5_unorm_pack == false) { + formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM; + formatInfoOut->decoder = nullptr; + } + else { + // used in Super Mario 3D World for the hidden Luigi sprites + // since order of channels is reversed in Vulkan compared to GX2 the format we need is A1B5G5R5 + formatInfoOut->vkImageFormat = VK_FORMAT_A1R5G5B5_UNORM_PACK16; + formatInfoOut->decoder = TextureDecoder_R5_G5_B5_A1_UNORM_swappedRB::getInstance(); + } break; case Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM: - // used by VC64 (e.g. Ocarina of Time) - formatInfoOut->vkImageFormat = VK_FORMAT_A1R5G5B5_UNORM_PACK16; // A 15 R 10..14, G 5..9 B 0..4 - formatInfoOut->decoder = TextureDecoder_A1_B5_G5_R5_UNORM_vulkan::getInstance(); + if (m_supportedFormatInfo.fmt_a1r5g5b5_unorm_pack == false) { + formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM; + formatInfoOut->decoder = nullptr; + } + else { + // used by VC64 (e.g. Ocarina of Time) + formatInfoOut->vkImageFormat = VK_FORMAT_A1R5G5B5_UNORM_PACK16; // A 15 R 10..14, G 5..9 B 0..4 + formatInfoOut->decoder = TextureDecoder_A1_B5_G5_R5_UNORM_vulkan::getInstance(); + } break; case Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT: formatInfoOut->vkImageFormat = VK_FORMAT_B10G11R11_UFLOAT_PACK32; // verify if order of channels is still the same as GX2 formatInfoOut->decoder = TextureDecoder_R11_G11_B10_FLOAT::getInstance(); break; case Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM: - formatInfoOut->vkImageFormat = VK_FORMAT_R4G4B4A4_UNORM_PACK16; // verify order of channels - formatInfoOut->decoder = TextureDecoder_R4_G4_B4_A4_UNORM::getInstance(); + if (m_supportedFormatInfo.fmt_r4g4b4a4_unorm_pack == false) { + formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM; + formatInfoOut->decoder = nullptr; + } + else { + formatInfoOut->vkImageFormat = VK_FORMAT_R4G4B4A4_UNORM_PACK16; + formatInfoOut->decoder = TextureDecoder_R4_G4_B4_A4_UNORM::getInstance(); + } break; // special formats - R10G10B10_A2 case Latte::E_GX2SURFFMT::R10_G10_B10_A2_UNORM: diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h index 6b6abf7a..a1f878e8 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h @@ -15,6 +15,8 @@ struct VkSupportedFormatInfo_t { bool fmt_d24_unorm_s8_uint{}; bool fmt_r4g4_unorm_pack{}; + bool fmt_r4g4b4a4_unorm_pack{}; + bool fmt_a1r5g5b5_unorm_pack{}; }; struct VkDescriptorSetInfo From cceb4f6d0ea20f5616998be3760615559a155523 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Fri, 30 Sep 2022 15:59:16 +0200 Subject: [PATCH 033/638] Vulkan: Always disable blending for integer formats (#317) Should fix a warning in the Vulkan validation layer and avoid a sigtrap in MoltenVk --- src/Cafe/HW/Latte/Renderer/Vulkan/VKRBase.h | 19 +++++++++-- .../Vulkan/VulkanPipelineCompiler.cpp | 32 +++++++++++++++++-- .../Renderer/Vulkan/VulkanPipelineCompiler.h | 2 +- .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 8 +++-- 4 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VKRBase.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VKRBase.h index 1c91207e..f79bd2dc 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VKRBase.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VKRBase.h @@ -1,4 +1,5 @@ #pragma once +#include "Cafe/HW/Latte/ISA/LatteReg.h" #include "util/math/vector2.h" class VKRMoveableRefCounterRef @@ -150,14 +151,28 @@ public: struct AttachmentInfo_t { - AttachmentEntryColor_t colorAttachment[8]; + AttachmentEntryColor_t colorAttachment[Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS]; AttachmentEntryDepth_t depthAttachment; }; + VkFormat GetColorFormat(size_t index) + { + if (index >= Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS) + return VK_FORMAT_UNDEFINED; + return m_colorAttachmentFormat[index]; + } + + VkFormat GetDepthFormat() + { + return m_depthAttachmentFormat; + } + public: - VKRObjectRenderPass(AttachmentInfo_t& attachmentInfo, sint32 colorAttachmentCount = 8); + VKRObjectRenderPass(AttachmentInfo_t& attachmentInfo, sint32 colorAttachmentCount = Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS); ~VKRObjectRenderPass() override; VkRenderPass m_renderPass{ VK_NULL_HANDLE }; + VkFormat m_colorAttachmentFormat[Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS]; + VkFormat m_depthAttachmentFormat; uint64 m_hashForPipeline; // helper var. Holds hash of all the renderpass creation parameters (mainly the formats) that affect the pipeline state }; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp index 7fb506b7..0deacddd 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.cpp @@ -609,7 +609,29 @@ void PipelineCompiler::InitRasterizerState(const LatteContextRegister& latteRegi multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; } -void PipelineCompiler::InitBlendState(const LatteContextRegister& latteRegister, PipelineInfo* pipelineInfo, bool& usesBlendConstants) +bool _IsVkIntegerFormat(VkFormat fmt) +{ + return + // 8bit integer formats + fmt == VK_FORMAT_R8_UINT || fmt == VK_FORMAT_R8_SINT || + fmt == VK_FORMAT_R8G8_UINT || fmt == VK_FORMAT_R8G8_SINT || + fmt == VK_FORMAT_R8G8B8_UINT || fmt == VK_FORMAT_R8G8B8_SINT || + fmt == VK_FORMAT_R8G8B8A8_UINT || fmt == VK_FORMAT_R8G8B8A8_SINT || + fmt == VK_FORMAT_B8G8R8A8_UINT || fmt == VK_FORMAT_B8G8R8A8_SINT || + // 16bit integer formats + fmt == VK_FORMAT_R16_UINT || fmt == VK_FORMAT_R16_SINT || + fmt == VK_FORMAT_R16G16_UINT || fmt == VK_FORMAT_R16G16_SINT || + fmt == VK_FORMAT_R16G16B16_UINT || fmt == VK_FORMAT_R16G16B16_SINT || + fmt == VK_FORMAT_R16G16B16A16_UINT || fmt == VK_FORMAT_R16G16B16A16_SINT || + // 32bit integer formats + fmt == VK_FORMAT_R32_UINT || fmt == VK_FORMAT_R32_SINT || + fmt == VK_FORMAT_R32G32_UINT || fmt == VK_FORMAT_R32G32_SINT || + fmt == VK_FORMAT_R32G32B32_UINT || fmt == VK_FORMAT_R32G32B32_SINT || + fmt == VK_FORMAT_R32G32B32A32_UINT || fmt == VK_FORMAT_R32G32B32A32_SINT; +} + + +void PipelineCompiler::InitBlendState(const LatteContextRegister& latteRegister, PipelineInfo* pipelineInfo, bool& usesBlendConstants, VKRObjectRenderPass* renderPassObj) { const Latte::LATTE_CB_COLOR_CONTROL& colorControlReg = latteRegister.CB_COLOR_CONTROL; uint32 blendEnableMask = colorControlReg.get_BLEND_MASK(); @@ -625,6 +647,12 @@ void PipelineCompiler::InitBlendState(const LatteContextRegister& latteRegister, else entry.blendEnable = VK_FALSE; + if (entry.blendEnable != VK_FALSE && _IsVkIntegerFormat(renderPassObj->GetColorFormat(i))) + { + // force-disable blending for integer formats + entry.blendEnable = VK_FALSE; + } + const auto& blendControlReg = latteRegister.CB_BLENDN_CONTROL[i]; entry.colorWriteMask = (renderTargetMask >> (i * 4)) & 0xF; @@ -873,7 +901,7 @@ bool PipelineCompiler::InitFromCurrentGPUState(PipelineInfo* pipelineInfo, const bool usesDepthBias = false; InitRasterizerState(latteRegister, vkRenderer, isPrimitiveRect, usesDepthBias); bool usesBlendConstants = false; - InitBlendState(latteRegister, pipelineInfo, usesBlendConstants); + InitBlendState(latteRegister, pipelineInfo, usesBlendConstants, renderPassObj); InitDescriptorSetLayouts(vkRenderer, pipelineInfo, pipelineInfo->vertexShader, pipelineInfo->pixelShader, pipelineInfo->geometryShader); // ########################################################################################################################################## diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.h index 4020b27e..304a7b31 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineCompiler.h @@ -23,7 +23,7 @@ private: void InitInputAssemblyState(const Latte::LATTE_VGT_PRIMITIVE_TYPE::E_PRIMITIVE_TYPE primitiveMode); void InitViewportState(); void InitRasterizerState(const LatteContextRegister& latteRegister, VulkanRenderer* vkRenderer, bool isPrimitiveRect, bool& usesDepthBias); - void InitBlendState(const LatteContextRegister& latteRegister, PipelineInfo* pipelineInfo, bool& usesBlendConstants); + void InitBlendState(const LatteContextRegister& latteRegister, PipelineInfo* pipelineInfo, bool& usesBlendConstants, VKRObjectRenderPass* renderPassObj); void InitDescriptorSetLayouts(VulkanRenderer* vkRenderer, PipelineInfo* vkrPipelineInfo, LatteDecompilerShader* vertexShader, LatteDecompilerShader* pixelShader, LatteDecompilerShader* geometryShader); void InitDepthStencilState(); void InitDynamicState(PipelineInfo* pipelineInfo, bool usesBlendConstants, bool usesDepthBias); diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index 03ffb7f5..8d352654 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -4085,7 +4085,7 @@ VKRObjectRenderPass::VKRObjectRenderPass(AttachmentInfo_t& attachmentInfo, sint3 { // generate helper hash for pipeline state uint64 stateHash = 0; - for (int i = 0; i < 8; ++i) + for (int i = 0; i < Latte::GPU_LIMITS::NUM_COLOR_ATTACHMENTS; ++i) { if (attachmentInfo.colorAttachment[i].isPresent || attachmentInfo.colorAttachment[i].viewObj) { @@ -4102,7 +4102,7 @@ VKRObjectRenderPass::VKRObjectRenderPass(AttachmentInfo_t& attachmentInfo, sint3 // setup Vulkan renderpass std::vector attachments_descriptions; - std::array color_attachments_references{}; + std::array color_attachments_references{}; cemu_assert(colorAttachmentCount <= color_attachments_references.size()); sint32 numColorAttachments = 0; for (int i = 0; i < 8; ++i) @@ -4110,8 +4110,10 @@ VKRObjectRenderPass::VKRObjectRenderPass(AttachmentInfo_t& attachmentInfo, sint3 if (attachmentInfo.colorAttachment[i].viewObj == nullptr && attachmentInfo.colorAttachment[i].isPresent == false) { color_attachments_references[i].attachment = VK_ATTACHMENT_UNUSED; + m_colorAttachmentFormat[i] = VK_FORMAT_UNDEFINED; continue; } + m_colorAttachmentFormat[i] = attachmentInfo.colorAttachment[i].format; color_attachments_references[i].attachment = (uint32)attachments_descriptions.size(); color_attachments_references[i].layout = VK_IMAGE_LAYOUT_GENERAL; @@ -4135,12 +4137,14 @@ VKRObjectRenderPass::VKRObjectRenderPass(AttachmentInfo_t& attachmentInfo, sint3 if (attachmentInfo.depthAttachment.viewObj == nullptr && attachmentInfo.depthAttachment.isPresent == false) { depth_stencil_attachments_references.attachment = VK_ATTACHMENT_UNUSED; + m_depthAttachmentFormat = VK_FORMAT_UNDEFINED; } else { hasDepthStencilAttachment = true; depth_stencil_attachments_references.attachment = (uint32)attachments_descriptions.size(); depth_stencil_attachments_references.layout = VK_IMAGE_LAYOUT_GENERAL; + m_depthAttachmentFormat = attachmentInfo.depthAttachment.format; VkAttachmentDescription entry{}; entry.format = attachmentInfo.depthAttachment.format; From 9541c8ae8556ffd72aab4e9eb092ec45eeceaf22 Mon Sep 17 00:00:00 2001 From: emiyl Date: Fri, 30 Sep 2022 17:07:00 +0100 Subject: [PATCH 034/638] MoltenVk: Workaround for unsupported format R5_G6_B5_UNORM (#318) --- .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 19 ++++++++++++++++--- .../HW/Latte/Renderer/Vulkan/VulkanRenderer.h | 1 + 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index 8d352654..cf5fc72b 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -1929,6 +1929,13 @@ void VulkanRenderer::QueryAvailableFormats() { m_supportedFormatInfo.fmt_r4g4_unorm_pack = true; } + // R5G6B5 + fmtProp = {}; + vkGetPhysicalDeviceFormatProperties(m_physical_device, VK_FORMAT_R5G6B5_UNORM_PACK16, &fmtProp); + if (fmtProp.optimalTilingFeatures != 0) + { + m_supportedFormatInfo.fmt_r5g6b5_unorm_pack = true; + } // R4G4B4A4 fmtProp = {}; vkGetPhysicalDeviceFormatProperties(m_physical_device, VK_FORMAT_R4G4B4A4_UNORM_PACK16, &fmtProp); @@ -2633,9 +2640,15 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD break; // special formats case Latte::E_GX2SURFFMT::R5_G6_B5_UNORM: - // Vulkan has R in MSB, GPU7 has it in LSB - formatInfoOut->vkImageFormat = VK_FORMAT_R5G6B5_UNORM_PACK16; - formatInfoOut->decoder = TextureDecoder_R5_G6_B5_swappedRB::getInstance(); + if (m_supportedFormatInfo.fmt_r5g6b5_unorm_pack == false) { + formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM; + formatInfoOut->decoder = nullptr; + } + else { + // Vulkan has R in MSB, GPU7 has it in LSB + formatInfoOut->vkImageFormat = VK_FORMAT_R5G6B5_UNORM_PACK16; + formatInfoOut->decoder = TextureDecoder_R5_G6_B5_swappedRB::getInstance(); + } break; case Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM: if (m_supportedFormatInfo.fmt_a1r5g5b5_unorm_pack == false) { diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h index a1f878e8..af597bf9 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h @@ -15,6 +15,7 @@ struct VkSupportedFormatInfo_t { bool fmt_d24_unorm_s8_uint{}; bool fmt_r4g4_unorm_pack{}; + bool fmt_r5g6b5_unorm_pack{}; bool fmt_r4g4b4a4_unorm_pack{}; bool fmt_a1r5g5b5_unorm_pack{}; }; From 11f6e2b7ee7af5327527301b6612dd520f7eb67d Mon Sep 17 00:00:00 2001 From: Tillsunset <35825944+Tillsunset@users.noreply.github.com> Date: Sat, 1 Oct 2022 18:48:13 -0500 Subject: [PATCH 035/638] Vulkan: Implement texture decoder for R5G6B5_UNORM to R8G8B8A8_UNORM (#320) --- src/Cafe/HW/Latte/Core/LatteTextureLoader.h | 51 +++++++++++++++++++ .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/Cafe/HW/Latte/Core/LatteTextureLoader.h b/src/Cafe/HW/Latte/Core/LatteTextureLoader.h index 25321006..82144f3a 100644 --- a/src/Cafe/HW/Latte/Core/LatteTextureLoader.h +++ b/src/Cafe/HW/Latte/Core/LatteTextureLoader.h @@ -978,6 +978,57 @@ public: } }; +class TextureDecoder_R5G6B5_UNORM_To_R8G8B8A8_UNORM : public TextureDecoder, public SingletonClass +{ +public: + sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override + { + return 4; + } + + void decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override + { + for (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY) + { + sint32 yc = y; + for (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX) + { + uint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y); + sint32 pixelOffset = (x + yc * textureLoader->width) * 4; + uint16 v0 = (*(uint16*)(blockData + 0)); + + uint8 c0 = (v0 & 0x1F); + uint8 c1 = (v0 >> 5) & 0x3F; + uint8 c2 = (v0 >> 11) & 0x1F; + + c0 = (c0 << 3) | c0 >> 3;// blue + c1 = (c1 << 2) | c1 >> 4;// green + c2 = (c2 << 3) | c2 >> 3;// red + + *(uint8*)(outputData + pixelOffset + 0) = c0;// blue + *(uint8*)(outputData + pixelOffset + 1) = c1;// green + *(uint8*)(outputData + pixelOffset + 2) = c2;// red + *(uint8*)(outputData + pixelOffset + 3) = 255;//alpha + } + } + } + + void decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override + { + uint16 v0 = *(uint16*)(blockData + 0); + uint8 c0 = (v0 & 0x1F);// red + uint8 c1 = (v0 >> 5) & 0x3F;// green + uint8 c2 = (v0 >> 11) & 0x1F; // blue + c0 = (c0 << 3) | c0 >> 3; + c1 = (c1 << 2) | c1 >> 4; + c2 = (c2 << 3) | c2 >> 3; + *(outputPixel + 0) = c0;// red + *(outputPixel + 1) = c1;// green + *(outputPixel + 2) = c2;// blue + *(outputPixel + 3) = 255;// alpha + } +}; + class TextureDecoder_R5_G5_B5_A1_UNORM : public TextureDecoder, public SingletonClass { public: diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index cf5fc72b..33cdbd0e 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -2642,7 +2642,7 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD case Latte::E_GX2SURFFMT::R5_G6_B5_UNORM: if (m_supportedFormatInfo.fmt_r5g6b5_unorm_pack == false) { formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM; - formatInfoOut->decoder = nullptr; + formatInfoOut->decoder = TextureDecoder_R5G6B5_UNORM_To_R8G8B8A8_UNORM::getInstance(); } else { // Vulkan has R in MSB, GPU7 has it in LSB From fb5ecca1577c06d853f71b311bca5165eae9ff31 Mon Sep 17 00:00:00 2001 From: Tillsunset <35825944+Tillsunset@users.noreply.github.com> Date: Sun, 2 Oct 2022 12:18:35 -0500 Subject: [PATCH 036/638] Vulkan: Use correct texture clear in LatteDraw_handleSpecialState8_clearAsDepth (#321) --- src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp index f9f61646..91a1f9a6 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp @@ -580,7 +580,10 @@ void LatteDraw_handleSpecialState8_clearAsDepth() } else { - g_renderer->texture_clearColorSlice(view->baseTexture, sliceIndex + view->firstSlice, mipIndex + view->firstMip, clearColor[0], clearColor[1], clearColor[2], clearColor[3]); + if (view->baseTexture->isDepth) + g_renderer->texture_clearDepthSlice(view->baseTexture, sliceIndex + view->firstSlice, mipIndex + view->firstMip, true, view->baseTexture->hasStencil, 0.0f, 0); + else + g_renderer->texture_clearColorSlice(view->baseTexture, sliceIndex + view->firstSlice, mipIndex + view->firstMip, clearColor[0], clearColor[1], clearColor[2], clearColor[3]); } } } From 8a0fe21589767eed5c3118f11168b3c18f4bd92c Mon Sep 17 00:00:00 2001 From: purofle Date: Mon, 3 Oct 2022 19:05:42 +0800 Subject: [PATCH 037/638] [docs] add `--needed` in ArchLinux dependencies (#324) --- BUILD.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD.md b/BUILD.md index 3dc69b18..08c6d64d 100644 --- a/BUILD.md +++ b/BUILD.md @@ -33,7 +33,7 @@ To compile Cemu, a recent enough compiler and STL with C++20 support is required `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang-12 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-12 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja` #### For Arch and derivatives: -`sudo pacman -S git cmake llvm clang ninja nasm base-devel linux-headers gtk3 libsecret libgcrypt systemd freeglut zip unzip libpulse` +`sudo pacman -S --needed git cmake llvm clang ninja nasm base-devel linux-headers gtk3 libsecret libgcrypt systemd freeglut zip unzip libpulse` #### For Fedora and derivatives: `sudo dnf install git cmake clang ninja-build nasm kernel-headers gtk3-devel libsecret-devel libgcrypt-devel systemd-devel freeglut-devel perl-core zlib-devel cubeb-devel` From 4519a59d746dc0eb2a427c0f379c6c4c600d89dd Mon Sep 17 00:00:00 2001 From: emiyl Date: Tue, 4 Oct 2022 14:24:14 +0100 Subject: [PATCH 038/638] [ih264] per-function target attribute on clang and GCC (#328) --- dependencies/ih264d/CMakeLists.txt | 4 --- .../ih264_chroma_intra_pred_filters_ssse3.c | 11 ++++++++ .../common/x86/ih264_deblk_chroma_ssse3.c | 18 ++++++++++++ .../common/x86/ih264_deblk_luma_ssse3.c | 12 ++++++++ .../x86/ih264_ihadamard_scaling_sse42.c | 8 ++++++ .../x86/ih264_ihadamard_scaling_ssse3.c | 7 +++++ .../x86/ih264_inter_pred_filters_ssse3.c | 16 +++++++++++ .../x86/ih264_iquant_itrans_recon_dc_ssse3.c | 9 ++++++ .../x86/ih264_iquant_itrans_recon_sse42.c | 8 ++++++ .../x86/ih264_iquant_itrans_recon_ssse3.c | 8 ++++++ .../x86/ih264_luma_intra_pred_filters_ssse3.c | 28 +++++++++++++++++++ .../ih264d/common/x86/ih264_mem_fns_ssse3.c | 8 ++++++ .../ih264d/common/x86/ih264_padding_ssse3.c | 10 +++++++ .../common/x86/ih264_resi_trans_quant_sse42.c | 10 +++++++ .../common/x86/ih264_weighted_pred_sse42.c | 12 ++++++++ .../x86/ih264d_function_selector_sse42.c | 7 +++++ .../x86/ih264d_function_selector_ssse3.c | 7 +++++ 17 files changed, 179 insertions(+), 4 deletions(-) diff --git a/dependencies/ih264d/CMakeLists.txt b/dependencies/ih264d/CMakeLists.txt index 4f538f69..295b028a 100644 --- a/dependencies/ih264d/CMakeLists.txt +++ b/dependencies/ih264d/CMakeLists.txt @@ -6,10 +6,6 @@ set(LIBAVCDEC_X86_INCLUDES "common/x86" "decoder/x86") include_directories("common/" "decoder/" ${LIBAVCDEC_X86_INCLUDES}) -if((CMAKE_C_COMPILER_ID MATCHES "GNU") OR (CMAKE_C_COMPILER_ID MATCHES "Clang")) - add_compile_options(-mssse3 -mavx2) -endif() - add_library (ih264d "common/ih264_buf_mgr.c" "common/ih264_buf_mgr.h" diff --git a/dependencies/ih264d/common/x86/ih264_chroma_intra_pred_filters_ssse3.c b/dependencies/ih264d/common/x86/ih264_chroma_intra_pred_filters_ssse3.c index d43ce207..502420b1 100644 --- a/dependencies/ih264d/common/x86/ih264_chroma_intra_pred_filters_ssse3.c +++ b/dependencies/ih264d/common/x86/ih264_chroma_intra_pred_filters_ssse3.c @@ -56,6 +56,11 @@ #include "ih264_platform_macros.h" #include "ih264_intra_pred_filters.h" +#ifdef __GNUC__ +#define ATTRIBUTE_SSSE3 __attribute__((target("ssse3"))) +#else +#define ATTRIBUTE_SSSE3 +#endif /*****************************************************************************/ /* Chroma Intra prediction 8x8 filters */ @@ -93,6 +98,8 @@ * ****************************************************************************** */ + +ATTRIBUTE_SSSE3 void ih264_intra_pred_chroma_8x8_mode_horz_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -169,6 +176,8 @@ void ih264_intra_pred_chroma_8x8_mode_horz_ssse3(UWORD8 *pu1_src, * ******************************************************************************* */ + +ATTRIBUTE_SSSE3 void ih264_intra_pred_chroma_8x8_mode_vert_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -237,6 +246,8 @@ void ih264_intra_pred_chroma_8x8_mode_vert_ssse3(UWORD8 *pu1_src, * ****************************************************************************** */ + +ATTRIBUTE_SSSE3 void ih264_intra_pred_chroma_8x8_mode_plane_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, diff --git a/dependencies/ih264d/common/x86/ih264_deblk_chroma_ssse3.c b/dependencies/ih264d/common/x86/ih264_deblk_chroma_ssse3.c index a36447a2..d73d9d35 100644 --- a/dependencies/ih264d/common/x86/ih264_deblk_chroma_ssse3.c +++ b/dependencies/ih264d/common/x86/ih264_deblk_chroma_ssse3.c @@ -53,6 +53,12 @@ #include "ih264_deblk_edge_filters.h" #include "ih264_macros.h" +#ifdef __GNUC__ +#define ATTRIBUTE_SSSE3 __attribute__((target("ssse3"))) +#else +#define ATTRIBUTE_SSSE3 +#endif + /*****************************************************************************/ /* Function Definitions */ /*****************************************************************************/ @@ -91,6 +97,8 @@ /* 12 02 2015 Naveen Kumar P Initial version */ /* */ /*****************************************************************************/ + +ATTRIBUTE_SSSE3 void ih264_deblk_chroma_vert_bs4_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 alpha_cb, @@ -274,6 +282,8 @@ void ih264_deblk_chroma_vert_bs4_ssse3(UWORD8 *pu1_src, /* 12 02 2015 Naveen Kumar P Initial version */ /* */ /*****************************************************************************/ + +ATTRIBUTE_SSSE3 void ih264_deblk_chroma_horz_bs4_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 alpha_cb, @@ -424,6 +434,8 @@ void ih264_deblk_chroma_horz_bs4_ssse3(UWORD8 *pu1_src, /* 12 02 2015 Naveen Kumar P Initial version */ /* */ /*****************************************************************************/ + +ATTRIBUTE_SSSE3 void ih264_deblk_chroma_vert_bslt4_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 alpha_cb, @@ -645,6 +657,8 @@ void ih264_deblk_chroma_vert_bslt4_ssse3(UWORD8 *pu1_src, /* 12 02 2015 Naveen Kumar P Initial version */ /* */ /*****************************************************************************/ + +ATTRIBUTE_SSSE3 void ih264_deblk_chroma_horz_bslt4_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 alpha_cb, @@ -829,6 +843,8 @@ void ih264_deblk_chroma_horz_bslt4_ssse3(UWORD8 *pu1_src, /* 12 02 2015 Naveen Kumar P Initial version */ /* */ /*****************************************************************************/ + +ATTRIBUTE_SSSE3 void ih264_deblk_chroma_vert_bs4_mbaff_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 alpha_cb, @@ -963,6 +979,8 @@ void ih264_deblk_chroma_vert_bs4_mbaff_ssse3(UWORD8 *pu1_src, /* 12 02 2015 Naveen Kumar P Initial version */ /* */ /*****************************************************************************/ + +ATTRIBUTE_SSSE3 void ih264_deblk_chroma_vert_bslt4_mbaff_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 alpha_cb, diff --git a/dependencies/ih264d/common/x86/ih264_deblk_luma_ssse3.c b/dependencies/ih264d/common/x86/ih264_deblk_luma_ssse3.c index e29bebbe..c135f6b6 100644 --- a/dependencies/ih264d/common/x86/ih264_deblk_luma_ssse3.c +++ b/dependencies/ih264d/common/x86/ih264_deblk_luma_ssse3.c @@ -53,6 +53,12 @@ #include "ih264_deblk_edge_filters.h" #include "ih264_macros.h" +#ifdef __GNUC__ +#define ATTRIBUTE_SSSE3 __attribute__((target("ssse3"))) +#else +#define ATTRIBUTE_SSSE3 +#endif + /*****************************************************************************/ /* Function Definitions */ /*****************************************************************************/ @@ -87,6 +93,7 @@ /* 12 02 2015 Naveen Kumar P Initial version */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_deblk_luma_vert_bs4_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 alpha, @@ -508,6 +515,7 @@ void ih264_deblk_luma_vert_bs4_ssse3(UWORD8 *pu1_src, /* 12 02 2015 Naveen Kumar P Initial version */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_deblk_luma_horz_bs4_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 alpha, @@ -847,6 +855,7 @@ void ih264_deblk_luma_horz_bs4_ssse3(UWORD8 *pu1_src, /* 12 02 2015 Naveen Kumar P Initial version */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_deblk_luma_vert_bslt4_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 alpha, @@ -1142,6 +1151,7 @@ void ih264_deblk_luma_vert_bslt4_ssse3(UWORD8 *pu1_src, /* 12 02 2015 Naveen Kumar P Initial version */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_deblk_luma_horz_bslt4_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 alpha, @@ -1439,6 +1449,7 @@ void ih264_deblk_luma_horz_bslt4_ssse3(UWORD8 *pu1_src, /* 12 02 2015 Naveen Kumar P Initial version */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_deblk_luma_vert_bs4_mbaff_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 alpha, @@ -1758,6 +1769,7 @@ void ih264_deblk_luma_vert_bs4_mbaff_ssse3(UWORD8 *pu1_src, /* 12 02 2015 Naveen Kumar P Initial version */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_deblk_luma_vert_bslt4_mbaff_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 alpha, diff --git a/dependencies/ih264d/common/x86/ih264_ihadamard_scaling_sse42.c b/dependencies/ih264d/common/x86/ih264_ihadamard_scaling_sse42.c index 3c4bb1c6..bf8e88ed 100644 --- a/dependencies/ih264d/common/x86/ih264_ihadamard_scaling_sse42.c +++ b/dependencies/ih264d/common/x86/ih264_ihadamard_scaling_sse42.c @@ -52,6 +52,12 @@ #include #include +#ifdef __GNUC__ +#define ATTRIBUTE_SSE42 __attribute__((target("sse4.2"))) +#else +#define ATTRIBUTE_SSE42 +#endif + /* ******************************************************************************** * @@ -87,6 +93,7 @@ * ******************************************************************************* */ +ATTRIBUTE_SSE42 void ih264_ihadamard_scaling_4x4_sse42(WORD16* pi2_src, WORD16* pi2_out, const UWORD16 *pu2_iscal_mat, @@ -202,6 +209,7 @@ void ih264_ihadamard_scaling_4x4_sse42(WORD16* pi2_src, _mm_storeu_si128((__m128i *) (&pi2_out[8]), src_r2_r3); } +ATTRIBUTE_SSE42 void ih264_ihadamard_scaling_2x2_uv_sse42(WORD16* pi2_src, WORD16* pi2_out, const UWORD16 *pu2_iscal_mat, diff --git a/dependencies/ih264d/common/x86/ih264_ihadamard_scaling_ssse3.c b/dependencies/ih264d/common/x86/ih264_ihadamard_scaling_ssse3.c index b4d483f1..4dc6d827 100644 --- a/dependencies/ih264d/common/x86/ih264_ihadamard_scaling_ssse3.c +++ b/dependencies/ih264d/common/x86/ih264_ihadamard_scaling_ssse3.c @@ -50,6 +50,12 @@ #include "ih264_trans_quant_itrans_iquant.h" #include +#ifdef __GNUC__ +#define ATTRIBUTE_SSSE3 __attribute__((target("ssse3"))) +#else +#define ATTRIBUTE_SSSE3 +#endif + /* ******************************************************************************** * @@ -85,6 +91,7 @@ * ******************************************************************************* */ +ATTRIBUTE_SSSE3 void ih264_ihadamard_scaling_4x4_ssse3(WORD16* pi2_src, WORD16* pi2_out, const UWORD16 *pu2_iscal_mat, diff --git a/dependencies/ih264d/common/x86/ih264_inter_pred_filters_ssse3.c b/dependencies/ih264d/common/x86/ih264_inter_pred_filters_ssse3.c index 480a8c7c..7927eeb6 100644 --- a/dependencies/ih264d/common/x86/ih264_inter_pred_filters_ssse3.c +++ b/dependencies/ih264d/common/x86/ih264_inter_pred_filters_ssse3.c @@ -54,6 +54,12 @@ #include "ih264_platform_macros.h" #include "ih264_inter_pred_filters.h" +#ifdef __GNUC__ +#define ATTRIBUTE_SSSE3 __attribute__((target("ssse3"))) +#else +#define ATTRIBUTE_SSSE3 +#endif + /*****************************************************************************/ /* Constant Data variables */ /*****************************************************************************/ @@ -87,6 +93,7 @@ /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_inter_pred_luma_copy_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -213,6 +220,7 @@ void ih264_inter_pred_luma_copy_ssse3(UWORD8 *pu1_src, /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_inter_pred_luma_horz_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -478,6 +486,7 @@ void ih264_inter_pred_luma_horz_ssse3(UWORD8 *pu1_src, /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_inter_pred_luma_vert_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -764,6 +773,7 @@ void ih264_inter_pred_luma_vert_ssse3(UWORD8 *pu1_src, /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_inter_pred_luma_horz_hpel_vert_hpel_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -1488,6 +1498,7 @@ void ih264_inter_pred_luma_horz_hpel_vert_hpel_ssse3(UWORD8 *pu1_src, /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_inter_pred_luma_horz_qpel_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -1782,6 +1793,7 @@ void ih264_inter_pred_luma_horz_qpel_ssse3(UWORD8 *pu1_src, /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_inter_pred_luma_vert_qpel_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -2107,6 +2119,7 @@ void ih264_inter_pred_luma_vert_qpel_ssse3(UWORD8 *pu1_src, /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_inter_pred_luma_horz_qpel_vert_qpel_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -2675,6 +2688,7 @@ void ih264_inter_pred_luma_horz_qpel_vert_qpel_ssse3(UWORD8 *pu1_src, /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_inter_pred_luma_horz_qpel_vert_hpel_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -3285,6 +3299,7 @@ void ih264_inter_pred_luma_horz_qpel_vert_hpel_ssse3(UWORD8 *pu1_src, /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_inter_pred_luma_horz_hpel_vert_qpel_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -3991,6 +4006,7 @@ void ih264_inter_pred_luma_horz_hpel_vert_qpel_ssse3(UWORD8 *pu1_src, /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_inter_pred_chroma_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, diff --git a/dependencies/ih264d/common/x86/ih264_iquant_itrans_recon_dc_ssse3.c b/dependencies/ih264d/common/x86/ih264_iquant_itrans_recon_dc_ssse3.c index bcfe503f..10dd2647 100644 --- a/dependencies/ih264d/common/x86/ih264_iquant_itrans_recon_dc_ssse3.c +++ b/dependencies/ih264d/common/x86/ih264_iquant_itrans_recon_dc_ssse3.c @@ -50,6 +50,12 @@ #include "ih264_trans_quant_itrans_iquant.h" #include +#ifdef __GNUC__ +#define ATTRIBUTE_SSSE3 __attribute__((target("ssse3"))) +#else +#define ATTRIBUTE_SSSE3 +#endif + /* ******************************************************************************** * @@ -98,6 +104,7 @@ * ******************************************************************************* */ +ATTRIBUTE_SSSE3 void ih264_iquant_itrans_recon_4x4_dc_ssse3(WORD16 *pi2_src, UWORD8 *pu1_pred, UWORD8 *pu1_out, @@ -224,6 +231,7 @@ void ih264_iquant_itrans_recon_4x4_dc_ssse3(WORD16 *pi2_src, ******************************************************************************* */ +ATTRIBUTE_SSSE3 void ih264_iquant_itrans_recon_8x8_dc_ssse3 (WORD16 *pi2_src, UWORD8 *pu1_pred, UWORD8 *pu1_out, @@ -385,6 +393,7 @@ void ih264_iquant_itrans_recon_8x8_dc_ssse3 (WORD16 *pi2_src, * ******************************************************************************* */ +ATTRIBUTE_SSSE3 void ih264_iquant_itrans_recon_chroma_4x4_dc_ssse3(WORD16 *pi2_src, UWORD8 *pu1_pred, UWORD8 *pu1_out, diff --git a/dependencies/ih264d/common/x86/ih264_iquant_itrans_recon_sse42.c b/dependencies/ih264d/common/x86/ih264_iquant_itrans_recon_sse42.c index a7b9e824..e97ca4d0 100644 --- a/dependencies/ih264d/common/x86/ih264_iquant_itrans_recon_sse42.c +++ b/dependencies/ih264d/common/x86/ih264_iquant_itrans_recon_sse42.c @@ -50,6 +50,12 @@ #include "ih264_trans_quant_itrans_iquant.h" #include +#ifdef __GNUC__ +#define ATTRIBUTE_SSE42 __attribute__((target("sse4.2"))) +#else +#define ATTRIBUTE_SSE42 +#endif + /* ******************************************************************************** * @@ -97,6 +103,7 @@ * ******************************************************************************* */ +ATTRIBUTE_SSE42 void ih264_iquant_itrans_recon_4x4_sse42(WORD16 *pi2_src, UWORD8 *pu1_pred, UWORD8 *pu1_out, @@ -348,6 +355,7 @@ void ih264_iquant_itrans_recon_4x4_sse42(WORD16 *pi2_src, * ******************************************************************************* */ +ATTRIBUTE_SSE42 void ih264_iquant_itrans_recon_chroma_4x4_sse42(WORD16 *pi2_src, UWORD8 *pu1_pred, UWORD8 *pu1_out, diff --git a/dependencies/ih264d/common/x86/ih264_iquant_itrans_recon_ssse3.c b/dependencies/ih264d/common/x86/ih264_iquant_itrans_recon_ssse3.c index 506be495..96773253 100644 --- a/dependencies/ih264d/common/x86/ih264_iquant_itrans_recon_ssse3.c +++ b/dependencies/ih264d/common/x86/ih264_iquant_itrans_recon_ssse3.c @@ -50,6 +50,12 @@ #include "ih264_trans_quant_itrans_iquant.h" #include +#ifdef __GNUC__ +#define ATTRIBUTE_SSSE3 __attribute__((target("ssse3"))) +#else +#define ATTRIBUTE_SSSE3 +#endif + /* ******************************************************************************** * @@ -97,6 +103,7 @@ * ******************************************************************************* */ +ATTRIBUTE_SSSE3 void ih264_iquant_itrans_recon_4x4_ssse3(WORD16 *pi2_src, UWORD8 *pu1_pred, UWORD8 *pu1_out, @@ -366,6 +373,7 @@ void ih264_iquant_itrans_recon_4x4_ssse3(WORD16 *pi2_src, ******************************************************************************* */ +ATTRIBUTE_SSSE3 void ih264_iquant_itrans_recon_8x8_ssse3(WORD16 *pi2_src, UWORD8 *pu1_pred, UWORD8 *pu1_out, diff --git a/dependencies/ih264d/common/x86/ih264_luma_intra_pred_filters_ssse3.c b/dependencies/ih264d/common/x86/ih264_luma_intra_pred_filters_ssse3.c index a1721d52..417e986b 100644 --- a/dependencies/ih264d/common/x86/ih264_luma_intra_pred_filters_ssse3.c +++ b/dependencies/ih264d/common/x86/ih264_luma_intra_pred_filters_ssse3.c @@ -75,6 +75,12 @@ #include "ih264_platform_macros.h" #include "ih264_intra_pred_filters.h" +#ifdef __GNUC__ +#define ATTRIBUTE_SSSE3 __attribute__((target("ssse3"))) +#else +#define ATTRIBUTE_SSSE3 +#endif + /******************* LUMA INTRAPREDICTION *******************/ @@ -114,6 +120,7 @@ * ******************************************************************************* */ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_4x4_mode_vert_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -173,6 +180,7 @@ void ih264_intra_pred_luma_4x4_mode_vert_ssse3(UWORD8 *pu1_src, * ******************************************************************************* */ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_4x4_mode_horz_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -238,6 +246,7 @@ void ih264_intra_pred_luma_4x4_mode_horz_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_4x4_mode_dc_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -316,6 +325,7 @@ void ih264_intra_pred_luma_4x4_mode_dc_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_4x4_mode_diag_dl_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -400,6 +410,7 @@ void ih264_intra_pred_luma_4x4_mode_diag_dl_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_4x4_mode_diag_dr_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -487,6 +498,7 @@ void ih264_intra_pred_luma_4x4_mode_diag_dr_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_4x4_mode_vert_r_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -579,6 +591,7 @@ void ih264_intra_pred_luma_4x4_mode_vert_r_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_4x4_mode_horz_d_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -675,6 +688,7 @@ void ih264_intra_pred_luma_4x4_mode_horz_d_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_4x4_mode_vert_l_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -764,6 +778,7 @@ void ih264_intra_pred_luma_4x4_mode_vert_l_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_4x4_mode_horz_u_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -864,6 +879,7 @@ void ih264_intra_pred_luma_4x4_mode_horz_u_ssse3(UWORD8 *pu1_src, * ******************************************************************************* */ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_8x8_mode_vert_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -921,6 +937,7 @@ void ih264_intra_pred_luma_8x8_mode_vert_ssse3(UWORD8 *pu1_src, * ******************************************************************************* */ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_8x8_mode_horz_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -985,6 +1002,7 @@ void ih264_intra_pred_luma_8x8_mode_horz_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_8x8_mode_dc_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -1078,6 +1096,7 @@ void ih264_intra_pred_luma_8x8_mode_dc_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_8x8_mode_diag_dl_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -1176,6 +1195,7 @@ void ih264_intra_pred_luma_8x8_mode_diag_dl_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_8x8_mode_diag_dr_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -1278,6 +1298,7 @@ void ih264_intra_pred_luma_8x8_mode_diag_dr_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_8x8_mode_vert_r_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -1398,6 +1419,7 @@ void ih264_intra_pred_luma_8x8_mode_vert_r_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_8x8_mode_horz_d_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -1502,6 +1524,7 @@ void ih264_intra_pred_luma_8x8_mode_horz_d_ssse3(UWORD8 *pu1_src, * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_8x8_mode_vert_l_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -1598,6 +1621,7 @@ void ih264_intra_pred_luma_8x8_mode_vert_l_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_8x8_mode_horz_u_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -1699,6 +1723,7 @@ void ih264_intra_pred_luma_8x8_mode_horz_u_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_16x16_mode_vert_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -1778,6 +1803,7 @@ void ih264_intra_pred_luma_16x16_mode_vert_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_16x16_mode_horz_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -1875,6 +1901,7 @@ void ih264_intra_pred_luma_16x16_mode_horz_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_16x16_mode_dc_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -1998,6 +2025,7 @@ void ih264_intra_pred_luma_16x16_mode_dc_ssse3(UWORD8 *pu1_src, * None * *******************************************************************************/ +ATTRIBUTE_SSSE3 void ih264_intra_pred_luma_16x16_mode_plane_ssse3(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, diff --git a/dependencies/ih264d/common/x86/ih264_mem_fns_ssse3.c b/dependencies/ih264d/common/x86/ih264_mem_fns_ssse3.c index 8ca1f3e5..be3d622c 100644 --- a/dependencies/ih264d/common/x86/ih264_mem_fns_ssse3.c +++ b/dependencies/ih264d/common/x86/ih264_mem_fns_ssse3.c @@ -50,6 +50,12 @@ #include +#ifdef __GNUC__ +#define ATTRIBUTE_SSSE3 __attribute__((target("ssse3"))) +#else +#define ATTRIBUTE_SSSE3 +#endif + /** ******************************************************************************* * @@ -78,6 +84,7 @@ +ATTRIBUTE_SSSE3 void ih264_memcpy_mul_8_ssse3(UWORD8 *pu1_dst, UWORD8 *pu1_src, UWORD32 num_bytes) { int col; @@ -117,6 +124,7 @@ void ih264_memcpy_mul_8_ssse3(UWORD8 *pu1_dst, UWORD8 *pu1_src, UWORD32 num_byte */ +ATTRIBUTE_SSSE3 void ih264_memset_mul_8_ssse3(UWORD8 *pu1_dst, UWORD8 value, UWORD32 num_bytes) { int col; diff --git a/dependencies/ih264d/common/x86/ih264_padding_ssse3.c b/dependencies/ih264d/common/x86/ih264_padding_ssse3.c index 43ded8e7..d2aa368a 100644 --- a/dependencies/ih264d/common/x86/ih264_padding_ssse3.c +++ b/dependencies/ih264d/common/x86/ih264_padding_ssse3.c @@ -49,6 +49,12 @@ #include +#ifdef __GNUC__ +#define ATTRIBUTE_SSSE3 __attribute__((target("ssse3"))) +#else +#define ATTRIBUTE_SSSE3 +#endif + /** ******************************************************************************* @@ -89,6 +95,7 @@ ******************************************************************************* */ +ATTRIBUTE_SSSE3 void ih264_pad_left_luma_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 ht, @@ -156,6 +163,7 @@ void ih264_pad_left_luma_ssse3(UWORD8 *pu1_src, ******************************************************************************* */ +ATTRIBUTE_SSSE3 void ih264_pad_left_chroma_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 ht, @@ -222,6 +230,7 @@ void ih264_pad_left_chroma_ssse3(UWORD8 *pu1_src, ******************************************************************************* */ +ATTRIBUTE_SSSE3 void ih264_pad_right_luma_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 ht, @@ -289,6 +298,7 @@ void ih264_pad_right_luma_ssse3(UWORD8 *pu1_src, ******************************************************************************* */ +ATTRIBUTE_SSSE3 void ih264_pad_right_chroma_ssse3(UWORD8 *pu1_src, WORD32 src_strd, WORD32 ht, diff --git a/dependencies/ih264d/common/x86/ih264_resi_trans_quant_sse42.c b/dependencies/ih264d/common/x86/ih264_resi_trans_quant_sse42.c index f4f5cbfa..fa3442f0 100644 --- a/dependencies/ih264d/common/x86/ih264_resi_trans_quant_sse42.c +++ b/dependencies/ih264d/common/x86/ih264_resi_trans_quant_sse42.c @@ -51,6 +51,12 @@ #include "ih264_structs.h" #include "ih264_trans_quant_itrans_iquant.h" #include + +#ifdef __GNUC__ +#define ATTRIBUTE_SSE42 __attribute__((target("sse4.2"))) +#else +#define ATTRIBUTE_SSE42 +#endif /** ******************************************************************************* * @@ -103,6 +109,7 @@ * ******************************************************************************* */ +ATTRIBUTE_SSE42 void ih264_resi_trans_quant_4x4_sse42(UWORD8 *pu1_src, UWORD8 *pu1_pred, WORD16 *pi2_out, WORD32 src_strd, WORD32 pred_strd, const UWORD16 *pu2_scale_matrix, const UWORD16 *pu2_threshold_matrix, @@ -376,6 +383,7 @@ void ih264_resi_trans_quant_4x4_sse42(UWORD8 *pu1_src, UWORD8 *pu1_pred, * ******************************************************************************* */ +ATTRIBUTE_SSE42 void ih264_resi_trans_quant_chroma_4x4_sse42(UWORD8 *pu1_src,UWORD8 *pu1_pred,WORD16 *pi2_out, WORD32 src_strd,WORD32 pred_strd, const UWORD16 *pu2_scale_matrix, @@ -663,6 +671,7 @@ void ih264_resi_trans_quant_chroma_4x4_sse42(UWORD8 *pu1_src,UWORD8 *pu1_pred,WO * */ +ATTRIBUTE_SSE42 void ih264_hadamard_quant_4x4_sse42(WORD16 *pi2_src, WORD16 *pi2_dst, const UWORD16 *pu2_scale_matrix, const UWORD16 *pu2_threshold_matrix, UWORD32 u4_qbits, @@ -892,6 +901,7 @@ void ih264_hadamard_quant_4x4_sse42(WORD16 *pi2_src, WORD16 *pi2_dst, * */ +ATTRIBUTE_SSE42 void ih264_hadamard_quant_2x2_uv_sse42(WORD16 *pi2_src, WORD16 *pi2_dst, const UWORD16 *pu2_scale_matrix, const UWORD16 *pu2_threshold_matrix, UWORD32 u4_qbits, diff --git a/dependencies/ih264d/common/x86/ih264_weighted_pred_sse42.c b/dependencies/ih264d/common/x86/ih264_weighted_pred_sse42.c index 48f1f542..8e10db28 100644 --- a/dependencies/ih264d/common/x86/ih264_weighted_pred_sse42.c +++ b/dependencies/ih264d/common/x86/ih264_weighted_pred_sse42.c @@ -50,6 +50,12 @@ #include "ih264_platform_macros.h" #include "ih264_weighted_pred.h" +#ifdef __GNUC__ +#define ATTRIBUTE_SSE42 __attribute__((target("sse4.2"))) +#else +#define ATTRIBUTE_SSE42 +#endif + /*****************************************************************************/ /* Function definitions . */ /*****************************************************************************/ @@ -82,6 +88,7 @@ /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSE42 void ih264_default_weighted_pred_luma_sse42(UWORD8 *pu1_src1, UWORD8 *pu1_src2, UWORD8 *pu1_dst, @@ -245,6 +252,7 @@ void ih264_default_weighted_pred_luma_sse42(UWORD8 *pu1_src1, /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSE42 void ih264_default_weighted_pred_chroma_sse42(UWORD8 *pu1_src1, UWORD8 *pu1_src2, UWORD8 *pu1_dst, @@ -375,6 +383,7 @@ void ih264_default_weighted_pred_chroma_sse42(UWORD8 *pu1_src1, /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSE42 void ih264_weighted_pred_luma_sse42(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -605,6 +614,7 @@ void ih264_weighted_pred_luma_sse42(UWORD8 *pu1_src, /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSE42 void ih264_weighted_pred_chroma_sse42(UWORD8 *pu1_src, UWORD8 *pu1_dst, WORD32 src_strd, @@ -814,6 +824,7 @@ void ih264_weighted_pred_chroma_sse42(UWORD8 *pu1_src, /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSE42 void ih264_weighted_bi_pred_luma_sse42(UWORD8 *pu1_src1, UWORD8 *pu1_src2, UWORD8 *pu1_dst, @@ -1101,6 +1112,7 @@ void ih264_weighted_bi_pred_luma_sse42(UWORD8 *pu1_src1, /* Senthoor */ /* */ /*****************************************************************************/ +ATTRIBUTE_SSE42 void ih264_weighted_bi_pred_chroma_sse42(UWORD8 *pu1_src1, UWORD8 *pu1_src2, UWORD8 *pu1_dst, diff --git a/dependencies/ih264d/decoder/x86/ih264d_function_selector_sse42.c b/dependencies/ih264d/decoder/x86/ih264d_function_selector_sse42.c index 0c493d22..c7636f38 100644 --- a/dependencies/ih264d/decoder/x86/ih264d_function_selector_sse42.c +++ b/dependencies/ih264d/decoder/x86/ih264d_function_selector_sse42.c @@ -60,6 +60,12 @@ #include "ih264d_structs.h" +#ifdef __GNUC__ +#define ATTRIBUTE_SSE42 __attribute__((target("sse4.2"))) +#else +#define ATTRIBUTE_SSE42 +#endif + /** ******************************************************************************* @@ -79,6 +85,7 @@ * ******************************************************************************* */ +ATTRIBUTE_SSE42 void ih264d_init_function_ptr_sse42(dec_struct_t *ps_codec) { ps_codec->pf_default_weighted_pred_luma = ih264_default_weighted_pred_luma_sse42; diff --git a/dependencies/ih264d/decoder/x86/ih264d_function_selector_ssse3.c b/dependencies/ih264d/decoder/x86/ih264d_function_selector_ssse3.c index 17862139..cd8043c6 100644 --- a/dependencies/ih264d/decoder/x86/ih264d_function_selector_ssse3.c +++ b/dependencies/ih264d/decoder/x86/ih264d_function_selector_ssse3.c @@ -60,6 +60,12 @@ #include "ih264d_structs.h" +#ifdef __GNUC__ +#define ATTRIBUTE_SSSE3 __attribute__((target("ssse3"))) +#else +#define ATTRIBUTE_SSSE3 +#endif + /** ******************************************************************************* @@ -79,6 +85,7 @@ * ******************************************************************************* */ +ATTRIBUTE_SSSE3 void ih264d_init_function_ptr_ssse3(dec_struct_t *ps_codec) { From 00968acc1d095324888e95e65275bdd2513156fb Mon Sep 17 00:00:00 2001 From: emiyl Date: Fri, 7 Oct 2022 01:39:06 +0100 Subject: [PATCH 039/638] dedicated decoder for R4G4 and R4G4B4A4 to R8G8B8A8 (#331) --- src/Cafe/HW/Latte/Core/LatteTextureLoader.h | 117 +++++++++++++++++- .../Latte/Renderer/OpenGL/OpenGLRenderer.cpp | 6 +- .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 12 +- 3 files changed, 121 insertions(+), 14 deletions(-) diff --git a/src/Cafe/HW/Latte/Core/LatteTextureLoader.h b/src/Cafe/HW/Latte/Core/LatteTextureLoader.h index 82144f3a..353ea924 100644 --- a/src/Cafe/HW/Latte/Core/LatteTextureLoader.h +++ b/src/Cafe/HW/Latte/Core/LatteTextureLoader.h @@ -556,7 +556,7 @@ public: } }; -class TextureDecoder_R4_G4_UNORM_toRGBA4444 : public TextureDecoder, public SingletonClass +class TextureDecoder_R4_G4_UNORM_To_RGBA4 : public TextureDecoder, public SingletonClass { public: sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override @@ -594,7 +594,7 @@ public: } }; -class TextureDecoder_R4_G4_UNORM_toRGBA4444_vk : public TextureDecoder, public SingletonClass +class TextureDecoder_R4_G4_UNORM_To_RGBA4_vk : public TextureDecoder, public SingletonClass { public: sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override @@ -632,6 +632,52 @@ public: } }; +class TextureDecoder_R4G4_UNORM_To_RGBA8 : public TextureDecoder, public SingletonClass +{ +public: + sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override + { + return 4; + } + + void decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override + { + for (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY) + { + sint32 yc = y; + for (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX) + { + uint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y); + sint32 pixelOffset = (x + yc * textureLoader->width) * 4; + uint8 v0 = (*(uint8*)(blockData + 0)); + + uint8 red4 = (v0 >> 4) & 0xF; + uint8 green4 = (v0 & 0xF); + + red4 = (red4 << 4) | red4; + green4 = (green4 << 4) | green4; + + *(uint8*)(outputData + pixelOffset + 0) = red4; + *(uint8*)(outputData + pixelOffset + 1) = green4; + *(uint8*)(outputData + pixelOffset + 2) = 0; + *(uint8*)(outputData + pixelOffset + 3) = 255; + } + } + } + + void decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override + { + uint8 v0 = *(blockData + 0); + uint8 red4 = (v0 >> 4) & 0xF; + uint8 green4 = (v0 & 0xF); + red4 = (red4 << 4) | red4; + green4 = (green4 << 4) | green4; + *(outputPixel + 0) = red4; + *(outputPixel + 1) = green4; + *(outputPixel + 2) = 0; + *(outputPixel + 3) = 255; + } +}; class TextureDecoder_R4_G4_B4_A4_UNORM : public TextureDecoder, public SingletonClass { @@ -677,6 +723,67 @@ public: } }; + +class TextureDecoder_R4G4B4A4_UNORM_To_RGBA8 : public TextureDecoder, public SingletonClass +{ +public: + sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override + { + return 4; + } + + void decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override + { + for (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY) + { + sint32 yc = y; + for (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX) + { + uint8* blockData = LatteTextureLoader_GetInput(textureLoader, x, y); + sint32 pixelOffset = (x + yc * textureLoader->width) * 4; + uint8 v0 = (*(uint8*)(blockData + 0)); + uint8 v1 = (*(uint8*)(blockData + 1)); + + uint8 red4 = (v0 & 0xF); + uint8 green4 = (v0 >> 4) & 0xF; + uint8 blue4 = (v1) & 0xF; + uint8 alpha4 = (v1 >> 4) & 0xF; + + red4 = (red4 << 4) | red4; + green4 = (green4 << 4) | green4; + blue4 = (blue4 << 4) | blue4; + alpha4 = (alpha4 << 4) | alpha4; + + *(uint8*)(outputData + pixelOffset + 0) = red4; + *(uint8*)(outputData + pixelOffset + 1) = green4; + *(uint8*)(outputData + pixelOffset + 2) = blue4; + *(uint8*)(outputData + pixelOffset + 3) = alpha4; + } + } + } + + void decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override + { + uint8 v0 = *(blockData + 0); + uint8 v1 = *(blockData + 1); + + uint8 red4 = (v0 & 0xF); + uint8 green4 = (v0 >> 4) & 0xF; + uint8 blue4 = (v1) & 0xF; + uint8 alpha4 = (v1 >> 4) & 0xF; + + red4 = (red4 << 4) | red4; + green4 = (green4 << 4) | green4; + blue4 = (blue4 << 4) | blue4; + alpha4 = (alpha4 << 4) | alpha4; + + *(outputPixel + 0) = red4; + *(outputPixel + 1) = green4; + *(outputPixel + 2) = blue4; + *(outputPixel + 3) = alpha4; + } +}; + class TextureDecoder_R8_G8_B8_A8 : public TextureDecoder, public SingletonClass { public: @@ -978,7 +1085,7 @@ public: } }; -class TextureDecoder_R5G6B5_UNORM_To_R8G8B8A8_UNORM : public TextureDecoder, public SingletonClass +class TextureDecoder_R5G6B5_UNORM_To_RGBA8 : public TextureDecoder, public SingletonClass { public: sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override @@ -1236,7 +1343,7 @@ public: } }; -class TextureDecoder_R10_G10_B10_A2_SNORM_toRGBA16 : public TextureDecoder, public SingletonClass +class TextureDecoder_R10_G10_B10_A2_SNORM_To_RGBA16 : public TextureDecoder, public SingletonClass { public: sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override @@ -1281,7 +1388,7 @@ public: } }; -class TextureDecoder_A2_B10_G10_R10_UNORM_toRGBA16 : public TextureDecoder, public SingletonClass +class TextureDecoder_A2_B10_G10_R10_UNORM_To_RGBA16 : public TextureDecoder, public SingletonClass { public: sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp index 269f30e8..c72d52ca 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.cpp @@ -878,7 +878,7 @@ TextureDecoder* OpenGLRenderer::texture_chooseDecodedFormat(Latte::E_GX2SURFFMT } if (format == Latte::E_GX2SURFFMT::R4_G4_UNORM) - texDecoder = TextureDecoder_R4_G4_UNORM_toRGBA4444::getInstance(); + texDecoder = TextureDecoder_R4_G4_UNORM_To_RGBA4::getInstance(); else if (format == Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM) texDecoder = TextureDecoder_R4_G4_B4_A4_UNORM::getInstance(); else if (format == Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT) @@ -964,9 +964,9 @@ TextureDecoder* OpenGLRenderer::texture_chooseDecodedFormat(Latte::E_GX2SURFFMT else if (format == Latte::E_GX2SURFFMT::R10_G10_B10_A2_UNORM) texDecoder = TextureDecoder_R10_G10_B10_A2_UNORM::getInstance(); else if (format == Latte::E_GX2SURFFMT::A2_B10_G10_R10_UNORM) - texDecoder = TextureDecoder_A2_B10_G10_R10_UNORM_toRGBA16::getInstance(); + texDecoder = TextureDecoder_A2_B10_G10_R10_UNORM_To_RGBA16::getInstance(); else if (format == Latte::E_GX2SURFFMT::R10_G10_B10_A2_SNORM) - texDecoder = TextureDecoder_R10_G10_B10_A2_SNORM_toRGBA16::getInstance(); + texDecoder = TextureDecoder_R10_G10_B10_A2_SNORM_To_RGBA16::getInstance(); else if (format == Latte::E_GX2SURFFMT::R10_G10_B10_A2_SRGB) texDecoder = TextureDecoder_R10_G10_B10_A2_UNORM::getInstance(); else if (format == Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT) diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index 33cdbd0e..759dac59 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -2588,11 +2588,11 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD { if (m_supportedFormatInfo.fmt_r4g4b4a4_unorm_pack == false) { formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM; - formatInfoOut->decoder = nullptr; + formatInfoOut->decoder = TextureDecoder_R4G4_UNORM_To_RGBA8::getInstance(); } else { formatInfoOut->vkImageFormat = VK_FORMAT_R4G4B4A4_UNORM_PACK16; - formatInfoOut->decoder = TextureDecoder_R4_G4_UNORM_toRGBA4444_vk::getInstance(); + formatInfoOut->decoder = TextureDecoder_R4_G4_UNORM_To_RGBA4_vk::getInstance(); } } else @@ -2642,7 +2642,7 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD case Latte::E_GX2SURFFMT::R5_G6_B5_UNORM: if (m_supportedFormatInfo.fmt_r5g6b5_unorm_pack == false) { formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM; - formatInfoOut->decoder = TextureDecoder_R5G6B5_UNORM_To_R8G8B8A8_UNORM::getInstance(); + formatInfoOut->decoder = TextureDecoder_R5G6B5_UNORM_To_RGBA8::getInstance(); } else { // Vulkan has R in MSB, GPU7 has it in LSB @@ -2680,7 +2680,7 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD case Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM: if (m_supportedFormatInfo.fmt_r4g4b4a4_unorm_pack == false) { formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM; - formatInfoOut->decoder = nullptr; + formatInfoOut->decoder = TextureDecoder_R4G4B4A4_UNORM_To_RGBA8::getInstance(); } else { formatInfoOut->vkImageFormat = VK_FORMAT_R4G4B4A4_UNORM_PACK16; @@ -2694,11 +2694,11 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD break; case Latte::E_GX2SURFFMT::R10_G10_B10_A2_SNORM: formatInfoOut->vkImageFormat = VK_FORMAT_R16G16B16A16_SNORM; // Vulkan has VK_FORMAT_A2R10G10B10_SNORM_PACK32 but it doesnt work? - formatInfoOut->decoder = TextureDecoder_R10_G10_B10_A2_SNORM_toRGBA16::getInstance(); + formatInfoOut->decoder = TextureDecoder_R10_G10_B10_A2_SNORM_To_RGBA16::getInstance(); break; case Latte::E_GX2SURFFMT::R10_G10_B10_A2_SRGB: //formatInfoOut->vkImageFormat = VK_FORMAT_R16G16B16A16_SNORM; // Vulkan has no uncompressed SRGB format with more than 8 bits per channel - //formatInfoOut->decoder = TextureDecoder_R10_G10_B10_A2_SNORM_toRGBA16::getInstance(); + //formatInfoOut->decoder = TextureDecoder_R10_G10_B10_A2_SNORM_To_RGBA16::getInstance(); //break; formatInfoOut->vkImageFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32; // todo - verify formatInfoOut->decoder = TextureDecoder_R10_G10_B10_A2_UNORM::getInstance(); From 551f82110974b515f07c58130dd29447e305e1b1 Mon Sep 17 00:00:00 2001 From: bslhq Date: Fri, 7 Oct 2022 20:30:06 +0800 Subject: [PATCH 040/638] Auto resize last column (#265) --- src/config/CemuConfig.cpp | 21 ++- src/config/CemuConfig.h | 17 +- src/gui/TitleManager.cpp | 2 +- src/gui/components/wxGameList.cpp | 249 ++++++++++++++++++------------ src/gui/components/wxGameList.h | 9 +- 5 files changed, 185 insertions(+), 113 deletions(-) diff --git a/src/config/CemuConfig.cpp b/src/config/CemuConfig.cpp index dcd283ec..b257ead3 100644 --- a/src/config/CemuConfig.cpp +++ b/src/config/CemuConfig.cpp @@ -89,12 +89,21 @@ void CemuConfig::Load(XMLConfigParser& parser) auto gamelist = parser.get("GameList"); game_list_style = gamelist.get("style", 0); game_list_column_order = gamelist.get("order", ""); - column_width.name = gamelist.get("name_width", -3); - column_width.version = gamelist.get("version_width", -3); - column_width.dlc = gamelist.get("dlc_width", -3); - column_width.game_time = gamelist.get("game_time_width", -3); - column_width.game_started = gamelist.get("game_started_width", -3); - column_width.region = gamelist.get("region_width", -3); + + // return default width if value in config file out of range + auto loadColumnSize = [&gamelist] (const char *name, uint32 defaultWidth) + { + sint64 val = gamelist.get(name, DefaultColumnSize::name); + if (val < 0 || val > (sint64) std::numeric_limits::max) + return defaultWidth; + return static_cast(val); + }; + column_width.name = loadColumnSize("name_width", DefaultColumnSize::name); + column_width.version = loadColumnSize("version_width", DefaultColumnSize::version); + column_width.dlc = loadColumnSize("dlc_width", DefaultColumnSize::dlc); + column_width.game_time = loadColumnSize("game_time_width", DefaultColumnSize::game_time); + column_width.game_started = loadColumnSize("game_started_width", DefaultColumnSize::game_started); + column_width.region = loadColumnSize("region_width", DefaultColumnSize::region); recent_launch_files.clear(); auto launch_parser = parser.get("RecentLaunchFiles"); diff --git a/src/config/CemuConfig.h b/src/config/CemuConfig.h index caabf082..e7cb1ca5 100644 --- a/src/config/CemuConfig.h +++ b/src/config/CemuConfig.h @@ -334,6 +334,16 @@ struct fmt::formatter : formatter { }; #endif +namespace DefaultColumnSize { + enum : uint32 { + name = 500u, + version = 60u, + dlc = 50u, + game_time = 140u, + game_started = 160u, + region = 80u, + }; +}; struct CemuConfig { @@ -402,7 +412,12 @@ struct CemuConfig std::string game_list_column_order; struct { - int name = -3, version = -3, dlc = -3, game_time = -3, game_started = -3, region = -3; + uint32 name = DefaultColumnSize::name; + uint32 version = DefaultColumnSize::version; + uint32 dlc = DefaultColumnSize::dlc; + uint32 game_time = DefaultColumnSize::game_time; + uint32 game_started = DefaultColumnSize::game_started; + uint32 region = DefaultColumnSize::region; } column_width{}; // graphics diff --git a/src/gui/TitleManager.cpp b/src/gui/TitleManager.cpp index 73e9d45c..519faf2b 100644 --- a/src/gui/TitleManager.cpp +++ b/src/gui/TitleManager.cpp @@ -219,7 +219,7 @@ wxPanel* TitleManager::CreateDownloadManagerPage() } TitleManager::TitleManager(wxWindow* parent, TitleManagerPage default_page) - : wxFrame(parent, wxID_ANY, _("Title manager"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL) + : wxFrame(parent, wxID_ANY, _("Title Manager"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE | wxTAB_TRAVERSAL) { SetIcon(wxICON(X_BOX)); diff --git a/src/gui/components/wxGameList.cpp b/src/gui/components/wxGameList.cpp index 074722e0..904fd5b7 100644 --- a/src/gui/components/wxGameList.cpp +++ b/src/gui/components/wxGameList.cpp @@ -50,7 +50,16 @@ void _stripPathFilename(fs::path& path) wxGameList::wxGameList(wxWindow* parent, wxWindowID id) : wxListCtrl(parent, id, wxDefaultPosition, wxDefaultSize, GetStyleFlags(Style::kList)), m_style(Style::kList) { - CreateListColumns(); + const auto& config = GetConfig(); + + InsertColumn(ColumnHiddenName, "", wxLIST_FORMAT_LEFT, 0); + InsertColumn(ColumnIcon, "", wxLIST_FORMAT_LEFT, kListIconWidth); + InsertColumn(ColumnName, _("Game"), wxLIST_FORMAT_LEFT, config.column_width.name); + InsertColumn(ColumnVersion, _("Version"), wxLIST_FORMAT_RIGHT, config.column_width.version); + InsertColumn(ColumnDLC, _("DLC"), wxLIST_FORMAT_RIGHT, config.column_width.dlc); + InsertColumn(ColumnGameTime, _("You've played"), wxLIST_FORMAT_LEFT, config.column_width.game_time); + InsertColumn(ColumnGameStarted, _("Last played"), wxLIST_FORMAT_LEFT, config.column_width.game_started); + InsertColumn(ColumnRegion, _("Region"), wxLIST_FORMAT_LEFT, config.column_width.region); const char transparent_bitmap[kIconWidth * kIconWidth * 4] = {0}; wxBitmap blank(transparent_bitmap, kIconWidth, kIconWidth); @@ -87,6 +96,7 @@ wxGameList::wxGameList(wxWindow* parent, wxWindowID id) Bind(wxEVT_LIST_COL_BEGIN_DRAG, &wxGameList::OnColumnBeginResize, this); Bind(wxEVT_LIST_COL_END_DRAG, &wxGameList::OnColumnResize, this); Bind(wxEVT_LIST_COL_RIGHT_CLICK, &wxGameList::OnColumnRightClick, this); + Bind(wxEVT_SIZE, &wxGameList::OnGameListSize, this); m_callbackIdTitleList = CafeTitleList::RegisterCallback([](CafeTitleListCallbackEvent* evt, void* ctx) { ((wxGameList*)ctx)->HandleTitleListCallback(evt); }, this); @@ -124,7 +134,7 @@ void wxGameList::LoadConfig() if (!config.game_list_column_order.empty()) { wxArrayInt order; - order.reserve(ColumnFavorite); + order.reserve(ColumnCounts); const auto order_string = std::string_view(config.game_list_column_order).substr(1); @@ -135,10 +145,88 @@ void wxGameList::LoadConfig() order.push_back(ConvertString(token, 10)); } - #ifdef wxHAS_LISTCTRL_COLUMN_ORDER - if(order.GetCount() == ColumnFavorite) +#ifdef wxHAS_LISTCTRL_COLUMN_ORDER + if(order.GetCount() == ColumnCounts) SetColumnsOrder(order); - #endif +#endif + } +} + +void wxGameList::OnGameListSize(wxSizeEvent &event) +{ + event.Skip(); + + // when using a sizer-based layout, do not change the size of the wxComponent in its own wxSizeEvent handler to avoid some UI issues. + int last_col_index = 0; + for(int i = GetColumnCount() - 1; i > 0; i--) + { +#ifdef wxHAS_LISTCTRL_COLUMN_ORDER + if(GetColumnWidth(GetColumnIndexFromOrder(i)) > 0) + { + last_col_index = GetColumnIndexFromOrder(i); + break; + } +#else + if(GetColumnWidth(i) > 0) + { + last_col_index = i; + break; + } +#endif + } + wxListEvent column_resize_event(wxEVT_LIST_COL_END_DRAG); + column_resize_event.SetColumn(last_col_index); + wxPostEvent(this, column_resize_event); +} + +void wxGameList::AdjustLastColumnWidth() +{ + wxWindowUpdateLocker windowlock(this); + int last_col_index = 0; + int last_col_width = GetClientSize().GetWidth(); + for (int i = 1; i < GetColumnCount(); i++) + { +#ifdef wxHAS_LISTCTRL_COLUMN_ORDER + if (GetColumnWidth(GetColumnIndexFromOrder(i)) > 0) + { + last_col_index = GetColumnIndexFromOrder(i); + last_col_width -= GetColumnWidth(last_col_index); + } +#else + if (GetColumnWidth(i) > 0) + { + last_col_index = i; + last_col_width -= GetColumnWidth(i); + } +#endif + } + last_col_width += GetColumnWidth(last_col_index); + if (last_col_width < GetColumnDefaultWidth(last_col_index)) // keep a minimum width + last_col_width = GetColumnDefaultWidth(last_col_index); + SetColumnWidth(last_col_index, last_col_width); +} + +// todo: scale all columns using a ratio instead of hardcoding exact widths +int wxGameList::GetColumnDefaultWidth(int column) +{ + switch (column) + { + case ColumnIcon: + return kListIconWidth; + case ColumnName: + return DefaultColumnSize::name; + case ColumnVersion: + return DefaultColumnSize::version; + case ColumnDLC: + return DefaultColumnSize::dlc; + case ColumnGameTime: + return DefaultColumnSize::game_time; + case ColumnGameStarted: + return DefaultColumnSize::game_started; + case ColumnRegion: + return DefaultColumnSize::region; + default: + return 80; } } @@ -339,7 +427,6 @@ void wxGameList::SortEntries(int column) column = s_last_column; else { - if (s_last_column == column) { s_last_column = 0; @@ -366,60 +453,6 @@ void wxGameList::SortEntries(int column) } } -void wxGameList::CreateListColumns() -{ - DeleteAllColumns(); - - const auto& config = GetConfig(); - wxListItem col0; - col0.SetId(ColumnHiddenName); - col0.SetWidth(0); - InsertColumn(ColumnHiddenName, col0); - - wxListItem col1; - col1.SetId(ColumnIcon); - col1.SetWidth(kListIconWidth); - InsertColumn(ColumnIcon, col1); - - wxListItem col2; - col2.SetId(ColumnName); - col2.SetText(_("Game")); - col2.SetWidth(config.column_width.name); - InsertColumn(ColumnName, col2); - - wxListItem col3; - col3.SetId(ColumnVersion); - col3.SetText(_("Version")); - col3.SetWidth(config.column_width.version); - col3.SetAlign(wxLIST_FORMAT_RIGHT); - InsertColumn(ColumnVersion, col3); - - wxListItem col4; - col4.SetId(ColumnDLC); - col4.SetText(_("DLC")); - col4.SetWidth(config.column_width.dlc); - col4.SetAlign(wxLIST_FORMAT_RIGHT); - InsertColumn(ColumnDLC, col4); - - wxListItem col5; - col5.SetId(ColumnGameTime); - col5.SetText(_("You've played")); - col5.SetWidth(config.column_width.game_time); - InsertColumn(ColumnGameTime, col5); - - wxListItem col6; - col6.SetId(ColumnGameStarted); - col6.SetText(_("Last played")); - col6.SetWidth(config.column_width.game_started); - InsertColumn(ColumnGameStarted, col6); - - wxListItem col7; - col7.SetId(ColumnRegion); - col7.SetText(_("Region")); - col7.SetWidth(config.column_width.region); - InsertColumn(ColumnRegion, col7); -} - void wxGameList::OnKeyDown(wxListEvent& event) { event.Skip(); @@ -688,9 +721,7 @@ void wxGameList::OnColumnRightClick(wxListEvent& event) menu.AppendCheckItem(ShowDlc, _("Show &dlc"))->Check(GetColumnWidth(ColumnDLC) > 0); menu.AppendCheckItem(ShowGameTime, _("Show &game time"))->Check(GetColumnWidth(ColumnGameTime) > 0); menu.AppendCheckItem(ShowLastPlayed, _("Show &last played"))->Check(GetColumnWidth(ColumnGameStarted) > 0); - menu.AppendCheckItem(ColumnRegion, _("Show ®ion"))->Check(GetColumnWidth(ColumnRegion) > 0); - //menu.AppendSeparator(); - //menu.Append(ResetOrder, _("&Reset order")); + menu.AppendCheckItem(ShowRegion, _("Show ®ion"))->Check(GetColumnWidth(ColumnRegion) > 0); menu.Bind(wxEVT_COMMAND_MENU_SELECTED, [this](wxCommandEvent& event) { @@ -703,44 +734,46 @@ void wxGameList::OnColumnRightClick(wxListEvent& event) switch (event.GetId()) { case ShowName: - config.column_width.name = menu->IsChecked(ShowName) ? 500 : 0; + config.column_width.name = menu->IsChecked(ShowName) ? DefaultColumnSize::name : 0; break; case ShowVersion: - config.column_width.version = menu->IsChecked(ShowVersion) ? 60 : 0; + config.column_width.version = menu->IsChecked(ShowVersion) ? DefaultColumnSize::version : 0; break; case ShowDlc: - config.column_width.dlc = menu->IsChecked(ShowDlc) ? 50 : 0; + config.column_width.dlc = menu->IsChecked(ShowDlc) ? DefaultColumnSize::dlc : 0; break; case ShowGameTime: - config.column_width.game_time = menu->IsChecked(ShowGameTime) ? 140 : 0; + config.column_width.game_time = menu->IsChecked(ShowGameTime) ? DefaultColumnSize::game_time : 0; break; case ShowLastPlayed: - config.column_width.game_started = menu->IsChecked(ShowLastPlayed) ? 160 : 0; + config.column_width.game_started = menu->IsChecked(ShowLastPlayed) ? DefaultColumnSize::game_started : 0; break; - case ColumnRegion: - config.column_width.region = menu->IsChecked(ColumnRegion) ? 80 : 0; + case ShowRegion: + config.column_width.region = menu->IsChecked(ShowRegion) ? DefaultColumnSize::region : 0; break; case ResetWidth: { switch (column) { + case ColumnIcon: + break; case ColumnName: - config.column_width.name = 500; + config.column_width.name = DefaultColumnSize::name; break; case ColumnVersion: - config.column_width.version = 60; + config.column_width.version = DefaultColumnSize::version; break; case ColumnDLC: - config.column_width.dlc = 50; + config.column_width.dlc = DefaultColumnSize::dlc; break; case ColumnGameTime: - config.column_width.game_time = 140; + config.column_width.game_time = DefaultColumnSize::game_time; break; case ColumnGameStarted: - config.column_width.game_started = 160; + config.column_width.game_started = DefaultColumnSize::game_started; break; case ColumnRegion: - config.column_width.region = 80; + config.column_width.region = DefaultColumnSize::region; break; default: return; @@ -751,13 +784,14 @@ void wxGameList::OnColumnRightClick(wxListEvent& event) case ResetOrder: { config.game_list_column_order.clear(); - wxArrayInt order(ColumnFavorite); + wxArrayInt order(ColumnCounts); std::iota(order.begin(), order.end(), 0); #ifdef wxHAS_LISTCTRL_COLUMN_ORDER SetColumnsOrder(order); #endif - Refresh(); - return; + //ApplyGameListColumnWidths(); + //Refresh(); + //return; } } @@ -771,33 +805,46 @@ void wxGameList::OnColumnRightClick(wxListEvent& event) void wxGameList::ApplyGameListColumnWidths() { - auto set_width = [this](int id, int width) - { - if (width == -3) - wxAutosizeColumn(this, id); - else - this->SetColumnWidth(id, width); - }; - const auto& config = GetConfig(); wxWindowUpdateLocker lock(this); - set_width(ColumnName, config.column_width.name); - set_width(ColumnVersion, config.column_width.version); - set_width(ColumnDLC, config.column_width.dlc); - set_width(ColumnGameTime, config.column_width.game_time); - set_width(ColumnGameStarted, config.column_width.game_started); - set_width(ColumnRegion, config.column_width.region); + SetColumnWidth(ColumnIcon, kListIconWidth); + SetColumnWidth(ColumnName, config.column_width.name); + SetColumnWidth(ColumnVersion, config.column_width.version); + SetColumnWidth(ColumnDLC, config.column_width.dlc); + SetColumnWidth(ColumnGameTime, config.column_width.game_time); + SetColumnWidth(ColumnGameStarted, config.column_width.game_started); + SetColumnWidth(ColumnRegion, config.column_width.region); + + AdjustLastColumnWidth(); } void wxGameList::OnColumnBeginResize(wxListEvent& event) { const int column = event.GetColumn(); const int width = GetColumnWidth(column); - if (width == 0) + int last_col_index = 0; + for(int i = GetColumnCount() - 1; i > 0; i--) + { +#ifdef wxHAS_LISTCTRL_COLUMN_ORDER + if(GetColumnWidth(GetColumnIndexFromOrder(i)) > 0) + { + last_col_index = GetColumnIndexFromOrder(i); + break; + } +#else + if(GetColumnWidth(i) > 0) + { + last_col_index = i; + break; + } +#endif + } + if (width == 0 || column == ColumnIcon || column == last_col_index) // dont resize hidden name, icon, and last column event.Veto(); else event.Skip(); } + void wxGameList::OnColumnResize(wxListEvent& event) { event.Skip(); @@ -823,19 +870,15 @@ void wxGameList::OnColumnResize(wxListEvent& event) case ColumnGameStarted: config.column_width.game_started = width; break; + case ColumnRegion: + config.column_width.region = width; + break; default: - return; + break; } g_config.Save(); -} - -void wxGameList::OnColumnDrag(wxListEvent& event) -{ - const auto column = event.GetColumn(); - const auto width = GetColumnWidth(column); - if (column == ColumnHiddenName || width == 0) - event.Veto(); + AdjustLastColumnWidth(); } void wxGameList::OnClose(wxCloseEvent& event) diff --git a/src/gui/components/wxGameList.h b/src/gui/components/wxGameList.h index 1f422585..2cf9f6b7 100644 --- a/src/gui/components/wxGameList.h +++ b/src/gui/components/wxGameList.h @@ -53,7 +53,7 @@ public: long FindListItemByTitleId(uint64 title_id) const; void OnClose(wxCloseEvent& event); - + private: std::atomic_bool m_exit = false; Style m_style; @@ -74,7 +74,8 @@ private: ColumnGameTime, ColumnGameStarted, ColumnRegion, - ColumnFavorite + //ColumnFavorite, + ColumnCounts }; int s_last_column = ColumnName; @@ -143,6 +144,10 @@ private: void OnMouseMove(wxMouseEvent& event); void OnLeaveWindow(wxMouseEvent& event); + void OnGameListSize(wxSizeEvent& event); + void AdjustLastColumnWidth(); + int GetColumnDefaultWidth(int column); + static inline std::once_flag s_launch_file_once; }; From b724a657e6b33e011808dbc4a398a344c4f7593d Mon Sep 17 00:00:00 2001 From: Tillsunset <35825944+Tillsunset@users.noreply.github.com> Date: Sat, 8 Oct 2022 08:07:54 -0500 Subject: [PATCH 041/638] MoltenVk: Add missing texture decoders (#332) --- src/Cafe/HW/Latte/Core/LatteTextureLoader.h | 102 ++++++++++++++++++ .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 4 +- 2 files changed, 104 insertions(+), 2 deletions(-) diff --git a/src/Cafe/HW/Latte/Core/LatteTextureLoader.h b/src/Cafe/HW/Latte/Core/LatteTextureLoader.h index 353ea924..f6de57d6 100644 --- a/src/Cafe/HW/Latte/Core/LatteTextureLoader.h +++ b/src/Cafe/HW/Latte/Core/LatteTextureLoader.h @@ -1203,6 +1203,58 @@ public: } }; +class TextureDecoder_R5_G5_B5_A1_UNORM_swappedRB_To_RGBA8 : public TextureDecoder, public SingletonClass +{ +public: +//2656 + sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override + { + return 4; + } + + void decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override + { + for (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY) + { + sint32 yc = y; + for (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX) + { + uint16* blockData = (uint16*)LatteTextureLoader_GetInput(textureLoader, x, y); + sint32 pixelOffset = (x + yc * textureLoader->width) * 4; + uint32 colorData = (*(uint16*)(blockData + 0)); + // swap order of components + uint8 red = (colorData >> 0) & 0x1F; + uint8 green = (colorData >> 5) & 0x1F; + uint8 blue = (colorData >> 10) & 0x1F; + uint8 alpha = (colorData >> 15) & 0x1; + + red = red << 3 | red >> 2; + green = green << 3 | green >> 2; + blue = blue << 3 | blue >> 2; + alpha = alpha * 0xff; + + // MSB...LSB : ABGR + colorData = (alpha << 24) | (blue << 16) | (green << 8) | red; + *(uint32*)(outputData + pixelOffset + 0) = colorData; + } + } + } + + void decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override + { + uint16 colorData = (*(uint16*)blockData); + uint8 red = (colorData >> 0) & 0x1F; + uint8 green = (colorData >> 5) & 0x1F; + uint8 blue = (colorData >> 10) & 0x1F; + uint8 alpha = (colorData >> 15) & 0x1; + *(outputPixel + 0) = (red << 3) | (red >> 2); + *(outputPixel + 1) = (green << 3) | (green >> 2); + *(outputPixel + 2) = (blue << 3) | (blue >> 2); + *(outputPixel + 3) = alpha * 0xff; + } + +}; + class uint16_R5_G5_B5_A1_swapOpenGL { public: @@ -1316,6 +1368,56 @@ public: } }; +class TextureDecoder_A1_B5_G5_R5_UNORM_vulkan_To_RGBA8 : public TextureDecoder, public SingletonClass +{ +public: + sint32 getBytesPerTexel(LatteTextureLoaderCtx* textureLoader) override + { + return 4; + } + + void decode(LatteTextureLoaderCtx* textureLoader, uint8* outputData) override + { + for (sint32 y = 0; y < textureLoader->height; y += textureLoader->stepY) + { + sint32 yc = y; + for (sint32 x = 0; x < textureLoader->width; x += textureLoader->stepX) + { + uint16* blockData = (uint16*)LatteTextureLoader_GetInput(textureLoader, x, y); + sint32 pixelOffset = (x + yc * textureLoader->width) * 4; + uint32 colorData = (*(uint16*)(blockData + 0)); + // swap order of components + uint8 red = (colorData >> 11) & 0x1F; + uint8 green = (colorData >> 6) & 0x1F; + uint8 blue = (colorData >> 1) & 0x1F; + uint8 alpha = (colorData >> 0) & 0x1; + + red = red << 3 | red >> 2; + green = green << 3 | green >> 2; + blue = blue << 3 | blue >> 2; + alpha = alpha * 0xff; + + // MSB...LSB ABGR + colorData = red | (green << 8) | (blue << 16) | (alpha << 24); + *(uint32*)(outputData + pixelOffset + 0) = colorData; + } + } + } + + void decodePixelToRGBA(uint8* blockData, uint8* outputPixel, uint8 blockOffsetX, uint8 blockOffsetY) override + { + uint16 colorData = (*(uint16*)blockData); + uint8 red5 = (colorData >> 11) & 0x1F; + uint8 green5 = (colorData >> 6) & 0x1F; + uint8 blue5 = (colorData >> 1) & 0x1F; + uint8 alpha1 = (colorData >> 0) & 0x1; + *(outputPixel + 0) = (red5 << 3) | (red5 >> 2); + *(outputPixel + 1) = (green5 << 3) | (green5 >> 2); + *(outputPixel + 2) = (blue5 << 3) | (blue5 >> 2); + *(outputPixel + 3) = (alpha1 << 3); + } +}; + class TextureDecoder_R10_G10_B10_A2_UNORM : public TextureDecoder, public SingletonClass { diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index 759dac59..249d06b7 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -2653,7 +2653,7 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD case Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM: if (m_supportedFormatInfo.fmt_a1r5g5b5_unorm_pack == false) { formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM; - formatInfoOut->decoder = nullptr; + formatInfoOut->decoder = TextureDecoder_R5_G5_B5_A1_UNORM_swappedRB_To_RGBA8::getInstance(); } else { // used in Super Mario 3D World for the hidden Luigi sprites @@ -2665,7 +2665,7 @@ void VulkanRenderer::GetTextureFormatInfoVK(Latte::E_GX2SURFFMT format, bool isD case Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM: if (m_supportedFormatInfo.fmt_a1r5g5b5_unorm_pack == false) { formatInfoOut->vkImageFormat = VK_FORMAT_R8G8B8A8_UNORM; - formatInfoOut->decoder = nullptr; + formatInfoOut->decoder = TextureDecoder_A1_B5_G5_R5_UNORM_vulkan_To_RGBA8::getInstance(); } else { // used by VC64 (e.g. Ocarina of Time) From 638e9e1f87d3ee279c1247969e9fd59065be492e Mon Sep 17 00:00:00 2001 From: Tillsunset <35825944+Tillsunset@users.noreply.github.com> Date: Sun, 9 Oct 2022 01:45:26 -0500 Subject: [PATCH 042/638] Workaround for the h264 video crash on macOS (#348) --- src/Cafe/OS/libs/h264_avc/H264Dec.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Cafe/OS/libs/h264_avc/H264Dec.cpp b/src/Cafe/OS/libs/h264_avc/H264Dec.cpp index 8dbd8ecf..1441f343 100644 --- a/src/Cafe/OS/libs/h264_avc/H264Dec.cpp +++ b/src/Cafe/OS/libs/h264_avc/H264Dec.cpp @@ -194,6 +194,7 @@ namespace H264 #ifdef _WIN32 return _aligned_malloc(size, alignment); #else + size += ((size % alignment) == 0) ? 0 : alignment - (size % alignment); return aligned_alloc(alignment, size); #endif } From 0c9fb3143f491d60959b3f2ca0aa8a04ab38b47c Mon Sep 17 00:00:00 2001 From: Tillsunset <35825944+Tillsunset@users.noreply.github.com> Date: Sun, 9 Oct 2022 03:43:45 -0500 Subject: [PATCH 043/638] memory optimization, using posix_memalign (#350) --- src/Cafe/OS/libs/h264_avc/H264Dec.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Cafe/OS/libs/h264_avc/H264Dec.cpp b/src/Cafe/OS/libs/h264_avc/H264Dec.cpp index 1441f343..e9b8ec8b 100644 --- a/src/Cafe/OS/libs/h264_avc/H264Dec.cpp +++ b/src/Cafe/OS/libs/h264_avc/H264Dec.cpp @@ -194,8 +194,22 @@ namespace H264 #ifdef _WIN32 return _aligned_malloc(size, alignment); #else - size += ((size % alignment) == 0) ? 0 : alignment - (size % alignment); - return aligned_alloc(alignment, size); + // alignment is atleast sizeof(void*) + alignment = std::max(alignment, sizeof(void*)); + + //smallest multiple of 2 at least as large as alignment + alignment--; + alignment |= alignment << 1; + alignment |= alignment >> 1; + alignment |= alignment >> 2; + alignment |= alignment >> 4; + alignment |= alignment >> 8; + alignment |= alignment >> 16; + alignment ^= (alignment >> 1); + + void* temp; + posix_memalign(&temp, (size_t)alignment, (size_t)size); + return temp; #endif } From 431c5a101f7f3806aea67d234177bd5de57aaf9f Mon Sep 17 00:00:00 2001 From: goeiecool9999 <7033575+goeiecool9999@users.noreply.github.com> Date: Mon, 10 Oct 2022 02:35:04 +0200 Subject: [PATCH 044/638] Linux: Print demangled symbols on backtrace (#312) --- src/CMakeLists.txt | 4 ++ src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h | 6 +-- .../ExceptionHandler_posix.cpp | 51 +++++++++++++++++-- src/Common/precompiled.h | 6 +++ 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 024432d0..32d6fe60 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -35,6 +35,10 @@ elseif(UNIX) add_compile_options(-Wno-ambiguous-reversed-operator) endif() + if(NOT APPLE) + add_link_options(-rdynamic) + endif() + add_compile_options(-Wno-multichar -Wno-invalid-offsetof -Wno-switch -Wno-ignored-attributes -Wno-deprecated-enum-enum-conversion) endif() diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h index c1f2dee6..437f00b1 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h @@ -15,9 +15,9 @@ extern bool g_vulkan_available; #endif #ifdef VKFUNC_DEFINE - #define VKFUNC(__FUNC__) PFN_##__FUNC__ __FUNC__ = nullptr - #define VKFUNC_INSTANCE(__FUNC__) PFN_##__FUNC__ __FUNC__ = nullptr - #define VKFUNC_DEVICE(__FUNC__) PFN_##__FUNC__ __FUNC__ = nullptr + #define VKFUNC(__FUNC__) NOEXPORT PFN_##__FUNC__ __FUNC__ = nullptr + #define VKFUNC_INSTANCE(__FUNC__) NOEXPORT PFN_##__FUNC__ __FUNC__ = nullptr + #define VKFUNC_DEVICE(__FUNC__) NOEXPORT PFN_##__FUNC__ __FUNC__ = nullptr #else #if defined(VKFUNC_INIT) #if BOOST_OS_WINDOWS diff --git a/src/Common/ExceptionHandler/ExceptionHandler_posix.cpp b/src/Common/ExceptionHandler/ExceptionHandler_posix.cpp index e2ea3d33..86d83bb3 100644 --- a/src/Common/ExceptionHandler/ExceptionHandler_posix.cpp +++ b/src/Common/ExceptionHandler/ExceptionHandler_posix.cpp @@ -1,9 +1,43 @@ #include #include #include +#include #include "config/CemuConfig.h" +void demangleAndPrintBacktrace(char** backtrace, size_t size) +{ + for (char** i = backtrace; i < backtrace + size; i++) + { + std::string traceLine{*i}; + size_t parenthesesOpen = traceLine.find_last_of('('); + size_t parenthesesClose = traceLine.find_last_of(')'); + size_t offsetPlus = traceLine.find_last_of('+'); + if (!parenthesesOpen || !parenthesesClose || !offsetPlus || + offsetPlus < parenthesesOpen || offsetPlus > parenthesesClose) + { + // something unexpected was read. fall back to default string + std::cerr << traceLine << std::endl; + continue; + } + + std::string symbolName = traceLine.substr(parenthesesOpen+1,offsetPlus-parenthesesOpen-1); + int status = -1; + char* demangled = abi::__cxa_demangle(symbolName.c_str(), nullptr, nullptr, &status); + if (demangled) + { + std::cerr << traceLine.substr(0, parenthesesOpen+1); + std::cerr << demangled; + std::cerr << traceLine.substr(offsetPlus) << std::endl; + free(demangled); + } + else + { + std::cerr << traceLine << std::endl; + } + } +} + // handle signals that would dump core, print stacktrace and then dump depending on config void handlerDumpingSignal(int sig) { @@ -18,15 +52,26 @@ void handlerDumpingSignal(int sig) printf("Unknown core dumping signal!\n"); } - void *array[32]; + void *array[128]; size_t size; // get void*'s for all entries on the stack - size = backtrace(array, 32); + size = backtrace(array, 128); // print out all the frames to stderr fprintf(stderr, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, STDERR_FILENO); + + char** symbol_trace = backtrace_symbols(array, size); + + if (symbol_trace) + { + demangleAndPrintBacktrace(symbol_trace, size); + free(symbol_trace); + } + else + { + std::cerr << "Failed to read backtrace" << std::endl; + } if (GetConfig().crash_dump == CrashDump::Enabled) { diff --git a/src/Common/precompiled.h b/src/Common/precompiled.h index 2a92ea3e..bd956657 100644 --- a/src/Common/precompiled.h +++ b/src/Common/precompiled.h @@ -246,6 +246,12 @@ inline uint64 _udiv128(uint64 highDividend, uint64 lowDividend, uint64 divisor, #error No definition for DLLEXPORT #endif +#if BOOST_OS_WINDOWS + #define NOEXPORT +#elif defined(__GNUC__) + #define NOEXPORT __attribute__ ((visibility ("hidden"))) +#endif + #ifdef __GNUC__ #include #endif From 52cc7c59964c72240874dc5e9c9178523df81404 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Tue, 11 Oct 2022 01:43:15 +0200 Subject: [PATCH 045/638] Follow imgui recommendation and streamline build dependencies (#355) --- .gitmodules | 3 +++ CMakeLists.txt | 1 - dependencies/imgui | 1 + src/Cafe/CMakeLists.txt | 1 - .../HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp | 14 -------------- src/imgui/CMakeLists.txt | 11 ++++++++++- src/imgui/imgui_extension.cpp | 4 ++-- vcpkg.json | 1 - 8 files changed, 16 insertions(+), 20 deletions(-) create mode 160000 dependencies/imgui diff --git a/.gitmodules b/.gitmodules index dd32088b..f352d478 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "dependencies/Vulkan-Headers"] path = dependencies/Vulkan-Headers url = https://github.com/KhronosGroup/Vulkan-Headers +[submodule "dependencies/imgui"] + path = dependencies/imgui + url = https://github.com/ocornut/imgui diff --git a/CMakeLists.txt b/CMakeLists.txt index e5ddc6fd..76dcd33a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,7 +83,6 @@ find_package(Threads REQUIRED) find_package(SDL2 REQUIRED) find_package(CURL REQUIRED) find_package(pugixml REQUIRED) -find_package(imgui REQUIRED) find_package(RapidJSON REQUIRED) find_package(Boost COMPONENTS program_options filesystem nowide REQUIRED) find_package(libzip REQUIRED) diff --git a/dependencies/imgui b/dependencies/imgui new file mode 160000 index 00000000..8a44c31c --- /dev/null +++ b/dependencies/imgui @@ -0,0 +1 @@ +Subproject commit 8a44c31c95c8e0217f6e1fc814cbbbcca4981f14 diff --git a/src/Cafe/CMakeLists.txt b/src/Cafe/CMakeLists.txt index 6657bc9c..c4f9ce30 100644 --- a/src/Cafe/CMakeLists.txt +++ b/src/Cafe/CMakeLists.txt @@ -491,7 +491,6 @@ target_link_libraries(CemuCafe PRIVATE fmt::fmt glslang::SPIRV ih264d - imgui::imgui OpenSSL::Crypto OpenSSL::SSL PNG::PNG diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp index 7af5204b..e6677576 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp @@ -1,25 +1,11 @@ #include "Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h" -#if __has_include() -#include -#else -#define GLSLANG_VERSION_LESS_OR_EQUAL_TO (false) -#endif - #include -#if GLSLANG_VERSION_LESS_OR_EQUAL_TO(11, 0, 0) #include -#else -#include -#include -#endif - #include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h" #include "Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h" -#include - #include "config/ActiveSettings.h" #include "config/CemuConfig.h" #include "util/helpers/ConcurrentQueue.h" diff --git a/src/imgui/CMakeLists.txt b/src/imgui/CMakeLists.txt index 97b56455..db7686bd 100644 --- a/src/imgui/CMakeLists.txt +++ b/src/imgui/CMakeLists.txt @@ -11,6 +11,16 @@ set_property(TARGET imguiImpl PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$second; - ImGuiKey mapped_key = current_key + ImGuiKey_NamedKey_BEGIN; - current_key = (current_key + 1) % ImGuiKey_NamedKey_COUNT ; + ImGuiKey mapped_key = (ImGuiKey)((uint32)current_key + ImGuiKey_NamedKey_BEGIN); + current_key = (current_key + 1) % (uint32)ImGuiKey_NamedKey_COUNT; keyboard_mapping[key_code] = mapped_key; return mapped_key; }; diff --git a/vcpkg.json b/vcpkg.json index 519a5618..33587607 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -3,7 +3,6 @@ "version-string": "1.0", "builtin-baseline": "1b0252ca70ca2244a711535462c7f981eb439e83", "dependencies": [ - "imgui", "pugixml", "zlib", "libpng", From b07e9efba4e9c1f952f14c99ebd529f71bfe630b Mon Sep 17 00:00:00 2001 From: MythicalPlayz <57963367+MythicalPlayz@users.noreply.github.com> Date: Tue, 11 Oct 2022 04:04:47 +0200 Subject: [PATCH 046/638] Add support for choosing network service (incl Pretendo+Custom) (#302) --- .gitignore | 1 + src/Cafe/IOSU/legacy/iosu_boss.cpp | 22 ++++++++- src/Cemu/napi/napi_ec.cpp | 67 ++++++++++++++++++++++++-- src/Cemu/napi/napi_helper.cpp | 12 +++-- src/Cemu/napi/napi_idbe.cpp | 35 +++++++++++++- src/Cemu/napi/napi_version.cpp | 19 +++++++- src/config/ActiveSettings.cpp | 6 ++- src/config/ActiveSettings.h | 3 +- src/config/CMakeLists.txt | 2 + src/config/CemuConfig.cpp | 4 +- src/config/CemuConfig.h | 1 + src/config/LaunchSettings.cpp | 24 ++++++++++ src/config/LaunchSettings.h | 5 +- src/config/NetworkSettings.cpp | 43 +++++++++++++++++ src/config/NetworkSettings.h | 77 ++++++++++++++++++++++++++++++ src/gui/GeneralSettings2.cpp | 23 +++++++++ src/gui/GeneralSettings2.h | 2 + src/gui/guiWrapper.cpp | 14 +++++- src/main.cpp | 7 ++- 19 files changed, 345 insertions(+), 22 deletions(-) create mode 100644 src/config/NetworkSettings.cpp create mode 100644 src/config/NetworkSettings.h diff --git a/.gitignore b/.gitignore index 293864a8..e252f4cb 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ bin/Cemu_*.ilk bin/Cemu.exe.backup bin/mlc01/* bin/settings.xml +bin/network_services.xml bin/title_list_cache.xml bin/debugger/* bin/sdcard/* diff --git a/src/Cafe/IOSU/legacy/iosu_boss.cpp b/src/Cafe/IOSU/legacy/iosu_boss.cpp index 7280ac53..d93d7284 100644 --- a/src/Cafe/IOSU/legacy/iosu_boss.cpp +++ b/src/Cafe/IOSU/legacy/iosu_boss.cpp @@ -10,6 +10,7 @@ #include #include "config/ActiveSettings.h" +#include "config/NetworkSettings.h" #include "curl/curl.h" #include "openssl/bn.h" #include "openssl/x509.h" @@ -497,9 +498,13 @@ namespace iosu curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, task_header_callback); curl_easy_setopt(curl, CURLOPT_HEADERDATA, &(*it)); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 0x3C); + if (GetNetworkConfig().disablesslver.GetValue() && ActiveSettings::GetNetworkService() == NetworkService::Custom || ActiveSettings::GetNetworkService() == NetworkService::Pretendo){ //Remove Pretendo Function once SSL is in the Service + curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,0L); + } else { curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, task_sslctx_function); curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, &it->task_settings); curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0); + } char url[512]; if(it->task_settings.taskType == kRawDlTaskSetting) @@ -561,8 +566,21 @@ namespace iosu char boss_code[0x20]; strncpy(boss_code, (char*)&it->task_settings.settings[TaskSetting::kBossCode], TaskSetting::kBossCodeLen); - - sprintf(url, "https://npts.app.nintendo.net/p01/tasksheet/%s/%s/%s?c=%s&l=%s", "1", boss_code, it->task_id, countryCode, languageCode); + switch (ActiveSettings::GetNetworkService()) + { + case NetworkService::Nintendo: + sprintf(url, NintendoURLs::BOSSURL.append("/%s/%s/%s?c=%s&l=%s").c_str(), "1", boss_code, it->task_id, countryCode, languageCode); + break; + case NetworkService::Pretendo: + sprintf(url, PretendoURLs::BOSSURL.append("/%s/%s/%s?c=%s&l=%s").c_str(), "1", boss_code, it->task_id, countryCode, languageCode); + break; + case NetworkService::Custom: + sprintf(url, GetNetworkConfig().urls.BOSS.GetValue().append("/%s/%s/%s?c=%s&l=%s").c_str(), "1", boss_code, it->task_id, countryCode, languageCode); + break; + default: + sprintf(url, NintendoURLs::BOSSURL.append("/%s/%s/%s?c=%s&l=%s").c_str(), "1", boss_code, it->task_id, countryCode, languageCode); + break; + } } curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list_headerParam); diff --git a/src/Cemu/napi/napi_ec.cpp b/src/Cemu/napi/napi_ec.cpp index 2d559e81..c355da4f 100644 --- a/src/Cemu/napi/napi_ec.cpp +++ b/src/Cemu/napi/napi_ec.cpp @@ -8,7 +8,8 @@ #include "Cemu/ncrypto/ncrypto.h" #include "util/crypto/md5.h" #include "config/LaunchSettings.h" - +#include "config/ActiveSettings.h" +#include "config/NetworkSettings.h" #include "pugixml.hpp" #include @@ -26,14 +27,42 @@ namespace NAPI { if (!s_serviceURL_NusURL.empty()) return s_serviceURL_NusURL; - return "https://nus.wup.shop.nintendo.net/nus/services/NetUpdateSOAP"; + switch (ActiveSettings::GetNetworkService()) + { + case NetworkService::Nintendo: + return NintendoURLs::NUSURL; + break; + case NetworkService::Pretendo: + return PretendoURLs::NUSURL; + break; + case NetworkService::Custom: + return GetNetworkConfig().urls.NUS; + break; + default: + return NintendoURLs::NUSURL; + break; + } } std::string _getIASUrl() { if (!s_serviceURL_IasURL.empty()) return s_serviceURL_IasURL; - return "https://ias.wup.shop.nintendo.net/ias/services/IdentityAuthenticationSOAP"; + switch (ActiveSettings::GetNetworkService()) + { + case NetworkService::Nintendo: + return NintendoURLs::IASURL; + break; + case NetworkService::Pretendo: + return PretendoURLs::IASURL; + break; + case NetworkService::Custom: + return GetNetworkConfig().urls.IAS; + break; + default: + return NintendoURLs::IASURL; + break; + } } std::string _getECSUrl() @@ -48,14 +77,42 @@ namespace NAPI { if (!s_serviceURL_UncachedContentPrefixURL.empty()) return s_serviceURL_UncachedContentPrefixURL; - return "https://ccs.wup.shop.nintendo.net/ccs/download"; + switch (ActiveSettings::GetNetworkService()) + { + case NetworkService::Nintendo: + return NintendoURLs::CCSUURL; + break; + case NetworkService::Pretendo: + return PretendoURLs::CCSUURL; + break; + case NetworkService::Custom: + return GetNetworkConfig().urls.CCSU; + break; + default: + return NintendoURLs::CCSUURL; + break; + } } std::string _getCCSUrl() // used for game data downloads { if (!s_serviceURL_ContentPrefixURL.empty()) return s_serviceURL_ContentPrefixURL; - return "http://ccs.cdn.wup.shop.nintendo.net/ccs/download"; + switch (ActiveSettings::GetNetworkService()) + { + case NetworkService::Nintendo: + return NintendoURLs::CCSURL; + break; + case NetworkService::Pretendo: + return PretendoURLs::CCSURL; + break; + case NetworkService::Custom: + return GetNetworkConfig().urls.CCS; + break; + default: + return NintendoURLs::CCSURL; + break; + } } /* NUS */ diff --git a/src/Cemu/napi/napi_helper.cpp b/src/Cemu/napi/napi_helper.cpp index 188c8840..016fc597 100644 --- a/src/Cemu/napi/napi_helper.cpp +++ b/src/Cemu/napi/napi_helper.cpp @@ -7,7 +7,9 @@ #include "Cemu/ncrypto/ncrypto.h" #include "napi_helper.h" #include "util/highresolutiontimer/HighResolutionTimer.h" - +#include "config/ActiveSettings.h" +#include "config/NetworkSettings.h" +#include "config/LaunchSettings.h" #include "pugixml.hpp" #include @@ -97,7 +99,10 @@ void CurlRequestHelper::initate(std::string url, SERVER_SSL_CONTEXT sslContext) curl_easy_setopt(m_curl, CURLOPT_TIMEOUT, 60); // SSL - if (sslContext == SERVER_SSL_CONTEXT::ACT || sslContext == SERVER_SSL_CONTEXT::TAGAYA) + if (GetNetworkConfig().disablesslver.GetValue() && ActiveSettings::GetNetworkService() == NetworkService::Custom || ActiveSettings::GetNetworkService() == NetworkService::Pretendo){ //Remove once Pretendo has SSL + curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L); + } + else if (sslContext == SERVER_SSL_CONTEXT::ACT || sslContext == SERVER_SSL_CONTEXT::TAGAYA) { curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_FUNCTION, _sslctx_function_NUS); curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_DATA, NULL); @@ -219,9 +224,10 @@ CurlSOAPHelper::CurlSOAPHelper() curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, this); // SSL + if (!GetNetworkConfig().disablesslver.GetValue() && ActiveSettings::GetNetworkService() != NetworkService::Pretendo && ActiveSettings::GetNetworkService() != NetworkService::Custom) { //Remove once Pretendo has SSL curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_FUNCTION, _sslctx_function_SOAP); curl_easy_setopt(m_curl, CURLOPT_SSL_CTX_DATA, NULL); - + } if(GetConfig().proxy_server.GetValue() != "") { curl_easy_setopt(m_curl, CURLOPT_PROXY, GetConfig().proxy_server.GetValue().c_str()); diff --git a/src/Cemu/napi/napi_idbe.cpp b/src/Cemu/napi/napi_idbe.cpp index 90c9c2f2..6832bf73 100644 --- a/src/Cemu/napi/napi_idbe.cpp +++ b/src/Cemu/napi/napi_idbe.cpp @@ -10,6 +10,8 @@ #include "openssl/sha.h" #include "util/crypto/aes128.h" #include "util/helpers/StringHelpers.h" +#include "config/ActiveSettings.h" +#include "config/NetworkSettings.h" namespace NAPI { @@ -55,7 +57,21 @@ namespace NAPI std::vector IDBE_RequestRawEncrypted(uint64 titleId) { CurlRequestHelper req; - req.initate(fmt::format("https://idbe-wup.cdn.nintendo.net/icondata/{0:02X}/{1:016X}.idbe", (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); + switch (ActiveSettings::GetNetworkService()) + { + case NetworkService::Nintendo: + req.initate(fmt::format(fmt::runtime(NintendoURLs::IDBEURL + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); + break; + case NetworkService::Pretendo: + req.initate(fmt::format(fmt::runtime(PretendoURLs::IDBEURL + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); + break; + case NetworkService::Custom: + req.initate(fmt::format(fmt::runtime(GetNetworkConfig().urls.IDBE.GetValue() + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); + break; + default: + req.initate(fmt::format(fmt::runtime(NintendoURLs::IDBEURL + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); + break; + } if (!req.submitRequest(false)) { cemuLog_log(LogType::Force, fmt::format("Failed to request IDBE icon for title {0:016X}", titleId)); @@ -84,7 +100,22 @@ namespace NAPI } CurlRequestHelper req; - req.initate(fmt::format("https://idbe-wup.cdn.nintendo.net/icondata/{0:02X}/{1:016X}.idbe", (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); + switch (ActiveSettings::GetNetworkService()) + { + case NetworkService::Nintendo: + req.initate(fmt::format(fmt::runtime(NintendoURLs::IDBEURL + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); + break; + case NetworkService::Pretendo: + req.initate(fmt::format(fmt::runtime(PretendoURLs::IDBEURL + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); + break; + case NetworkService::Custom: + req.initate(fmt::format(fmt::runtime(GetNetworkConfig().urls.IDBE.GetValue() + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); + break; + default: + req.initate(fmt::format(fmt::runtime(NintendoURLs::IDBEURL + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); + break; + } + if (!req.submitRequest(false)) { cemuLog_log(LogType::Force, fmt::format("Failed to request IDBE icon for title {0:016X}", titleId)); diff --git a/src/Cemu/napi/napi_version.cpp b/src/Cemu/napi/napi_version.cpp index f1c1b171..73dd68cf 100644 --- a/src/Cemu/napi/napi_version.cpp +++ b/src/Cemu/napi/napi_version.cpp @@ -7,6 +7,8 @@ #include "Cemu/ncrypto/ncrypto.h" #include +#include "config/ActiveSettings.h" +#include "config/NetworkSettings.h" namespace NAPI { @@ -14,7 +16,22 @@ namespace NAPI { NAPI_VersionListVersion_Result result; CurlRequestHelper req; - req.initate(fmt::format("https://tagaya.wup.shop.nintendo.net/tagaya/versionlist/{}/{}/latest_version", NCrypto::GetRegionAsString(authInfo.region), authInfo.country), CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA); + switch (ActiveSettings::GetNetworkService()) + { + case NetworkService::Nintendo: + req.initate(fmt::format(fmt::runtime(NintendoURLs::TAGAYAURL + "/{}/{}/latest_version"), NCrypto::GetRegionAsString(authInfo.region), authInfo.country), CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA); + break; + case NetworkService::Pretendo: + req.initate(fmt::format(fmt::runtime(PretendoURLs::TAGAYAURL + "/{}/{}/latest_version"), NCrypto::GetRegionAsString(authInfo.region), authInfo.country), CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA); + break; + case NetworkService::Custom: + req.initate(fmt::format(fmt::runtime(GetNetworkConfig().urls.TAGAYA.GetValue() + "/{}/{}/latest_version"), NCrypto::GetRegionAsString(authInfo.region), authInfo.country), CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA); + break; + default: + req.initate(fmt::format(fmt::runtime(NintendoURLs::TAGAYAURL + "/{}/{}/latest_version"), NCrypto::GetRegionAsString(authInfo.region), authInfo.country), CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA); + break; + } + if (!req.submitRequest(false)) { cemuLog_log(LogType::Force, fmt::format("Failed to request version of update list")); diff --git a/src/config/ActiveSettings.cpp b/src/config/ActiveSettings.cpp index c7ff4fe6..16119725 100644 --- a/src/config/ActiveSettings.cpp +++ b/src/config/ActiveSettings.cpp @@ -20,7 +20,7 @@ void ActiveSettings::LoadOnce() g_config.SetFilename(GetPath("settings.xml").generic_wstring()); g_config.Load(); - + LaunchSettings::ChangeNetworkServiceURL(GetConfig().account.active_service); std::wstring additionalErrorInfo; s_has_required_online_files = iosuCrypt_checkRequirementsForOnlineMode(additionalErrorInfo) == IOS_CRYPTO_ONLINE_REQ_OK; } @@ -121,6 +121,10 @@ bool ActiveSettings::HasRequiredOnlineFiles() return s_has_required_online_files; } +NetworkService ActiveSettings::GetNetworkService() { + return static_cast(GetConfig().account.active_service.GetValue()); +} + bool ActiveSettings::DumpShadersEnabled() { return s_dump_shaders; diff --git a/src/config/ActiveSettings.h b/src/config/ActiveSettings.h index 69f6d34a..ae3feb94 100644 --- a/src/config/ActiveSettings.h +++ b/src/config/ActiveSettings.h @@ -1,6 +1,7 @@ #pragma once #include "config/CemuConfig.h" +#include "config/NetworkSettings.h" // global active settings for fast access (reflects settings from command line and game profile) class ActiveSettings @@ -92,7 +93,7 @@ public: [[nodiscard]] static uint32 GetPersistentId(); [[nodiscard]] static bool IsOnlineEnabled(); [[nodiscard]] static bool HasRequiredOnlineFiles(); - + [[nodiscard]] static NetworkService GetNetworkService(); // dump options [[nodiscard]] static bool DumpShadersEnabled(); [[nodiscard]] static bool DumpTexturesEnabled(); diff --git a/src/config/CMakeLists.txt b/src/config/CMakeLists.txt index c329d58b..f02b95d4 100644 --- a/src/config/CMakeLists.txt +++ b/src/config/CMakeLists.txt @@ -6,6 +6,8 @@ add_library(CemuConfig ConfigValue.h LaunchSettings.cpp LaunchSettings.h + NetworkSettings.cpp + NetworkSettings.h PermanentConfig.cpp PermanentConfig.h PermanentStorage.cpp diff --git a/src/config/CemuConfig.cpp b/src/config/CemuConfig.cpp index b257ead3..84324418 100644 --- a/src/config/CemuConfig.cpp +++ b/src/config/CemuConfig.cpp @@ -322,7 +322,7 @@ void CemuConfig::Load(XMLConfigParser& parser) auto acc = parser.get("Account"); account.m_persistent_id = acc.get("PersistentId", account.m_persistent_id); account.online_enabled = acc.get("OnlineEnabled", account.online_enabled); - + account.active_service = acc.get("ActiveService",account.active_service); // debug auto debug = parser.get("Debug"); #if BOOST_OS_WINDOWS @@ -497,7 +497,7 @@ void CemuConfig::Save(XMLConfigParser& parser) auto acc = config.set("Account"); acc.set("PersistentId", account.m_persistent_id.GetValue()); acc.set("OnlineEnabled", account.online_enabled.GetValue()); - + acc.set("ActiveService",account.active_service.GetValue()); // debug auto debug = config.set("Debug"); #if BOOST_OS_WINDOWS diff --git a/src/config/CemuConfig.h b/src/config/CemuConfig.h index e7cb1ca5..0dc0843b 100644 --- a/src/config/CemuConfig.h +++ b/src/config/CemuConfig.h @@ -471,6 +471,7 @@ struct CemuConfig { ConfigValueBounds m_persistent_id{ Account::kMinPersistendId, Account::kMinPersistendId, 0xFFFFFFFF }; ConfigValue online_enabled{false}; + ConfigValue active_service{0}; }account{}; // input diff --git a/src/config/LaunchSettings.cpp b/src/config/LaunchSettings.cpp index 7d7c0c98..06d9a5a3 100644 --- a/src/config/LaunchSettings.cpp +++ b/src/config/LaunchSettings.cpp @@ -9,6 +9,7 @@ #include #include "config/ActiveSettings.h" +#include "config/NetworkSettings.h" #include "util/crypto/aes128.h" #include "Cafe/Filesystem/FST/FST.h" @@ -265,3 +266,26 @@ bool LaunchSettings::ExtractorTool(std::wstring_view wud_path, std::string_view } +void LaunchSettings::ChangeNetworkServiceURL(int ID){ + NetworkService Network = static_cast(ID); + switch (Network) + { + case NetworkService::Nintendo: + serviceURL_ACT = NintendoURLs::ACTURL; + serviceURL_ECS = NintendoURLs::ECSURL; + break; + case NetworkService::Pretendo: + serviceURL_ACT = PretendoURLs::ACTURL; + serviceURL_ECS = PretendoURLs::ECSURL; + break; + case NetworkService::Custom: + serviceURL_ACT = GetNetworkConfig().urls.ACT.GetValue(); + serviceURL_ECS = GetNetworkConfig().urls.ECS.GetValue(); + break; + default: + serviceURL_ACT = NintendoURLs::ACTURL; + serviceURL_ECS = NintendoURLs::ECSURL; + break; + } + +} \ No newline at end of file diff --git a/src/config/LaunchSettings.h b/src/config/LaunchSettings.h index 299dd72c..b42523ca 100644 --- a/src/config/LaunchSettings.h +++ b/src/config/LaunchSettings.h @@ -30,6 +30,7 @@ public: static std::string GetActURLPrefix() { return serviceURL_ACT; } static std::string GetServiceURL_ecs() { return serviceURL_ECS; } + static void ChangeNetworkServiceURL(int ID); private: inline static std::optional s_load_game_file{}; @@ -46,8 +47,8 @@ private: inline static std::optional s_persistent_id{}; // service URLS - inline static std::string serviceURL_ACT = "https://account.nintendo.net"; - inline static std::string serviceURL_ECS = "https://ecs.wup.shop.nintendo.net/ecs/services/ECommerceSOAP"; + inline static std::string serviceURL_ACT; + inline static std::string serviceURL_ECS; // todo - npts and other boss urls diff --git a/src/config/NetworkSettings.cpp b/src/config/NetworkSettings.cpp new file mode 100644 index 00000000..f3a3b8b6 --- /dev/null +++ b/src/config/NetworkSettings.cpp @@ -0,0 +1,43 @@ +#include "NetworkSettings.h" +#include "LaunchSettings.h" +#include "CemuConfig.h" +#include +#include "Common/FileStream.h" +XMLNetworkConfig_t n_config(L"network_services.xml"); + +void NetworkConfig::LoadOnce() { + s_full_path = boost::dll::program_location().generic_wstring(); + s_path = s_full_path.parent_path(); + n_config.SetFilename(GetPath("network_services.xml").generic_wstring()); + if(XMLExists()) { + n_config.Load(); + } +} + +void NetworkConfig::Load(XMLConfigParser& parser){ + auto config = parser.get("content"); + networkname = config.get("networkname","[Nintendo]"); + disablesslver = config.get("disablesslverification",disablesslver); + auto u = config.get("urls"); + urls.ACT = u.get("act",NintendoURLs::ACTURL); + urls.ECS = u.get("ecs",NintendoURLs::ECSURL); + urls.NUS = u.get("nus",NintendoURLs::NUSURL); + urls.IAS = u.get("ias",NintendoURLs::IASURL); + urls.CCSU = u.get("ccsu",NintendoURLs::CCSUURL); + urls.CCS = u.get("ccs",NintendoURLs::CCSURL); + urls.IDBE = u.get("idbe",NintendoURLs::IDBEURL); + urls.BOSS = u.get("boss",NintendoURLs::BOSSURL); + urls.TAGAYA = u.get("tagaya",NintendoURLs::TAGAYAURL); + if (static_cast(GetConfig().account.active_service.GetValue()) == NetworkService::Custom) { + LaunchSettings::ChangeNetworkServiceURL(2); + } +} +bool NetworkConfig::XMLExists() { + if (!fs::exists(GetPath("network_services.xml"))) { + if (static_cast(GetConfig().account.active_service.GetValue()) == NetworkService::Custom) { + LaunchSettings::ChangeNetworkServiceURL(0); + GetConfig().account.active_service = 0; + } + return false; + } else {return true;} +} \ No newline at end of file diff --git a/src/config/NetworkSettings.h b/src/config/NetworkSettings.h new file mode 100644 index 00000000..e65da8ab --- /dev/null +++ b/src/config/NetworkSettings.h @@ -0,0 +1,77 @@ +#pragma once + +#include "ConfigValue.h" +#include "XMLConfig.h" + + +enum class NetworkService { +Nintendo, +Pretendo, +Custom, +}; +struct NetworkConfig { + NetworkConfig() + { + + }; + + NetworkConfig(const NetworkConfig&) = delete; + + ConfigValue networkname; + ConfigValue disablesslver = false; + struct + { + ConfigValue ACT; + ConfigValue ECS; + ConfigValue NUS; + ConfigValue IAS; + ConfigValue CCSU; + ConfigValue CCS; + ConfigValue IDBE; + ConfigValue BOSS; + ConfigValue TAGAYA; + }urls{}; + + public: + static void LoadOnce(); + void Load(XMLConfigParser& parser); + void Save(XMLConfigParser& parser); + + static bool XMLExists(); + private: + inline static fs::path s_path; + inline static fs::path s_full_path; + [[nodiscard]] static fs::path GetPath(std::string_view p) + { + std::basic_string_view s((const char8_t*)p.data(), p.size()); + return s_path / fs::path(s); + } +}; + +struct NintendoURLs { + inline static std::string ACTURL = "https://account.nintendo.net"; + inline static std::string ECSURL = "https://ecs.wup.shop.nintendo.net/ecs/services/ECommerceSOAP"; + inline static std::string NUSURL = "https://nus.wup.shop.nintendo.net/nus/services/NetUpdateSOAP"; + inline static std::string IASURL = "https://ias.wup.shop.nintendo.net/ias/services/IdentityAuthenticationSOAP"; + inline static std::string CCSUURL = "https://ccs.wup.shop.nintendo.net/ccs/download"; + inline static std::string CCSURL = "http://ccs.cdn.wup.shop.nintendo.net/ccs/download"; + inline static std::string IDBEURL = "https://idbe-wup.cdn.nintendo.net/icondata"; + inline static std::string BOSSURL = "https://npts.app.nintendo.net/p01/tasksheet"; + inline static std::string TAGAYAURL = "https://tagaya.wup.shop.nintendo.net/tagaya/versionlist"; +}; + +struct PretendoURLs { + inline static std::string ACTURL = "https://account.pretendo.cc"; + inline static std::string ECSURL = "https://ecs.wup.shop.pretendo.cc/ecs/services/ECommerceSOAP"; + inline static std::string NUSURL = "https://nus.c.shop.pretendo.cc/nus/services/NetUpdateSOAP"; + inline static std::string IASURL = "https://ias.c.shop.pretendo.cc/ias/services/IdentityAuthenticationSOAP"; + inline static std::string CCSUURL = "https://ccs.c.shop.pretendo.cc/ccs/download"; + inline static std::string CCSURL = "http://ccs.cdn.c.shop.pretendo.cc/ccs/download"; + inline static std::string IDBEURL = "https://idbe-wup.cdn.pretendo.cc/icondata"; + inline static std::string BOSSURL = "https://npts.app.pretendo.cc/p01/tasksheet"; + inline static std::string TAGAYAURL = "https://tagaya.wup.shop.pretendo.cc/tagaya/versionlist"; +}; + +typedef XMLDataConfig XMLNetworkConfig_t; +extern XMLNetworkConfig_t n_config; +inline NetworkConfig& GetNetworkConfig() { return n_config.data();}; \ No newline at end of file diff --git a/src/gui/GeneralSettings2.cpp b/src/gui/GeneralSettings2.cpp index 6c4f5bbb..ffb58e48 100644 --- a/src/gui/GeneralSettings2.cpp +++ b/src/gui/GeneralSettings2.cpp @@ -14,6 +14,7 @@ #include #include "config/CemuConfig.h" +#include "config/NetworkSettings.h" #include "audio/IAudioAPI.h" #if BOOST_OS_WINDOWS @@ -604,6 +605,18 @@ wxPanel* GeneralSettings2::AddAccountPage(wxNotebook* notebook) content->Add(m_delete_account, 0, wxEXPAND | wxALL | wxALIGN_RIGHT, 5); m_delete_account->Bind(wxEVT_BUTTON, &GeneralSettings2::OnAccountDelete, this); + if (NetworkConfig::XMLExists()) { + wxString choices[] = { _("Nintendo"), _("Pretendo"), _("Custom") }; + m_active_service= new wxRadioBox(online_panel, wxID_ANY, _("Network Service"), wxDefaultPosition, wxDefaultSize, std::size(choices), choices, 3, wxRA_SPECIFY_COLS); + } + else { + wxString choices[] = { _("Nintendo"), _("Pretendo") }; + m_active_service= new wxRadioBox(online_panel, wxID_ANY, _("Network Service"), wxDefaultPosition, wxDefaultSize, std::size(choices), choices, 2, wxRA_SPECIFY_COLS); + } + m_active_service->SetToolTip(_("Connect to which Network Service")); + m_active_service->Bind(wxEVT_RADIOBOX, &GeneralSettings2::OnAccountServiceChanged,this); + content->Add(m_active_service, 0, wxEXPAND | wxALL, 5); + box_sizer->Add(content, 1, wxEXPAND, 5); online_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5); @@ -613,6 +626,7 @@ wxPanel* GeneralSettings2::AddAccountPage(wxNotebook* notebook) m_active_account->Enable(false); m_create_account->Enable(false); m_delete_account->Enable(false); + m_active_service->Enable(false); } } @@ -919,6 +933,7 @@ void GeneralSettings2::StoreConfig() config.account.m_persistent_id = dynamic_cast(m_active_account->GetClientObject(active_account))->GetAccount().GetPersistentId(); config.account.online_enabled = m_online_enabled->GetValue(); + config.account.active_service = m_active_service->GetSelection(); // debug config.crash_dump = (CrashDump)m_crash_dump->GetSelection(); @@ -1488,6 +1503,7 @@ void GeneralSettings2::ApplyConfig() } m_online_enabled->SetValue(config.account.online_enabled); + m_active_service->SetSelection(config.account.active_service); UpdateAccountInformation(); // debug @@ -1722,6 +1738,13 @@ void GeneralSettings2::OnActiveAccountChanged(wxCommandEvent& event) m_has_account_change = true; } +void GeneralSettings2::OnAccountServiceChanged(wxCommandEvent& event) +{ + LaunchSettings::ChangeNetworkServiceURL(m_active_service->GetSelection()); + + UpdateAccountInformation(); +} + void GeneralSettings2::OnMLCPathSelect(wxCommandEvent& event) { if (!CemuApp::SelectMLCPath(this)) diff --git a/src/gui/GeneralSettings2.h b/src/gui/GeneralSettings2.h index ed326d5a..fb3e8092 100644 --- a/src/gui/GeneralSettings2.h +++ b/src/gui/GeneralSettings2.h @@ -65,6 +65,7 @@ private: // Account wxButton* m_create_account, * m_delete_account; wxChoice* m_active_account; + wxRadioBox* m_active_service; wxCheckBox* m_online_enabled; wxCollapsiblePane* m_account_information; wxPropertyGrid* m_account_grid; @@ -93,6 +94,7 @@ private: void OnMLCPathChar(wxKeyEvent& event); void OnShowOnlineValidator(wxCommandEvent& event); void OnOnlineEnable(wxCommandEvent& event); + void OnAccountServiceChanged(wxCommandEvent& event); // updates cemu audio devices void UpdateAudioDevice(); diff --git a/src/gui/guiWrapper.cpp b/src/gui/guiWrapper.cpp index 835dc499..2a1598c0 100644 --- a/src/gui/guiWrapper.cpp +++ b/src/gui/guiWrapper.cpp @@ -5,6 +5,7 @@ #include "gui/debugger/DebuggerWindow2.h" #include "Cafe/HW/Latte/Core/Latte.h" #include "config/ActiveSettings.h" +#include "config/NetworkSettings.h" #include "config/CemuConfig.h" #include "Cafe/HW/Latte/Renderer/Renderer.h" #include "Cafe/CafeSystem.h" @@ -96,9 +97,18 @@ void gui_updateWindowTitles(bool isIdle, bool isLoading, double fps) const uint64 titleId = CafeSystem::GetForegroundTitleId(); windowText.append(fmt::format(" - FPS: {:.2f} {} {} [TitleId: {:08x}-{:08x}]", (double)fps, renderer, graphicMode, (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF))); - if (ActiveSettings::IsOnlineEnabled()) + if (ActiveSettings::IsOnlineEnabled()){ windowText.append(" [Online]"); - + if (ActiveSettings::GetNetworkService() == NetworkService::Nintendo) { + windowText.append("[Nintendo]"); + } + else if (ActiveSettings::GetNetworkService() == NetworkService::Pretendo) { + windowText.append("[Pretendo]"); + } + else if (ActiveSettings::GetNetworkService() == NetworkService::Custom) { + windowText.append("[" + GetNetworkConfig().networkname.GetValue() + "]"); + } + } windowText.append(" "); windowText.append(CafeSystem::GetForegroundTitleName()); // append region diff --git a/src/main.cpp b/src/main.cpp index f782c33e..87243bb8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,6 +8,7 @@ #include "Cafe/GameProfile/GameProfile.h" #include "Cafe/GraphicPack/GraphicPack2.h" #include "config/CemuConfig.h" +#include "config/NetworkSettings.h" #include "gui/CemuApp.h" #include "Cafe/HW/Latte/Core/LatteOverlay.h" #include "config/LaunchSettings.h" @@ -216,6 +217,8 @@ void mainEmulatorCommonInit() ExceptionHandler_init(); // read config g_config.Load(); + if (NetworkConfig::XMLExists()) + n_config.Load(); // symbol storage rplSymbolStorage_init(); // static initialization @@ -345,6 +348,7 @@ int wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ L if (!LaunchSettings::HandleCommandline(lpCmdLine)) return 0; ActiveSettings::LoadOnce(); + NetworkConfig::LoadOnce(); HandlePostUpdate(); return mainEmulatorHLE(); } @@ -356,6 +360,7 @@ int main(int argc, char* argv[]) if (!LaunchSettings::HandleCommandline(argc, argv)) return 0; ActiveSettings::LoadOnce(); + NetworkConfig::LoadOnce(); HandlePostUpdate(); return mainEmulatorHLE(); } @@ -371,7 +376,7 @@ int main(int argc, char *argv[]) return 0; ActiveSettings::LoadOnce(); - + NetworkConfig::LoadOnce(); HandlePostUpdate(); return mainEmulatorHLE(); } From 2b9edced8144c885e5b3b14d3e3a75217e2065ec Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Tue, 11 Oct 2022 09:17:34 +0200 Subject: [PATCH 047/638] Minor tweaks and code clean up (#357) --- .gitignore | 1 + src/Cafe/IOSU/legacy/iosu_boss.cpp | 33 +++++++------ src/Cemu/napi/napi_idbe.cpp | 75 ++++++++++-------------------- src/Cemu/napi/napi_version.cpp | 14 +++--- src/config/LaunchSettings.cpp | 10 +--- src/config/NetworkSettings.cpp | 69 +++++++++++++++------------ src/gui/GeneralSettings2.cpp | 14 +++--- src/gui/guiWrapper.cpp | 19 ++++---- 8 files changed, 105 insertions(+), 130 deletions(-) diff --git a/.gitignore b/.gitignore index e252f4cb..0f5e5a69 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ bin/network_services.xml bin/title_list_cache.xml bin/debugger/* bin/sdcard/* +bin/screenshots/* !bin/shaderCache/info.txt bin/shaderCache/* diff --git a/src/Cafe/IOSU/legacy/iosu_boss.cpp b/src/Cafe/IOSU/legacy/iosu_boss.cpp index d93d7284..acf8a99d 100644 --- a/src/Cafe/IOSU/legacy/iosu_boss.cpp +++ b/src/Cafe/IOSU/legacy/iosu_boss.cpp @@ -498,23 +498,27 @@ namespace iosu curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, task_header_callback); curl_easy_setopt(curl, CURLOPT_HEADERDATA, &(*it)); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 0x3C); - if (GetNetworkConfig().disablesslver.GetValue() && ActiveSettings::GetNetworkService() == NetworkService::Custom || ActiveSettings::GetNetworkService() == NetworkService::Pretendo){ //Remove Pretendo Function once SSL is in the Service + if (GetNetworkConfig().disablesslver.GetValue() && ActiveSettings::GetNetworkService() == NetworkService::Custom || ActiveSettings::GetNetworkService() == NetworkService::Pretendo) // remove Pretendo Function once SSL is in the Service + { curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,0L); - } else { - curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, task_sslctx_function); - curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, &it->task_settings); - curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0); + } + else + { + curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, task_sslctx_function); + curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, &it->task_settings); + curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0); } - char url[512]; + std::string requestUrl; if(it->task_settings.taskType == kRawDlTaskSetting) { char serviceToken[TaskSetting::kServiceTokenLen]; strncpy(serviceToken, (char*)&it->task_settings.settings[TaskSetting::kServiceToken], TaskSetting::kServiceTokenLen); list_headerParam = append_header_param(list_headerParam, "X-Nintendo-ServiceToken: {}", serviceToken); + char url[TaskSetting::kURLLen + 1]{}; strncpy(url, (char*)&it->task_settings.settings[TaskSetting::kURL], TaskSetting::kURLLen); - forceLogDebug_printf("\tserviceToken: %s", serviceToken); + requestUrl.assign(url); } else { @@ -566,26 +570,25 @@ namespace iosu char boss_code[0x20]; strncpy(boss_code, (char*)&it->task_settings.settings[TaskSetting::kBossCode], TaskSetting::kBossCodeLen); + switch (ActiveSettings::GetNetworkService()) { - case NetworkService::Nintendo: - sprintf(url, NintendoURLs::BOSSURL.append("/%s/%s/%s?c=%s&l=%s").c_str(), "1", boss_code, it->task_id, countryCode, languageCode); - break; case NetworkService::Pretendo: - sprintf(url, PretendoURLs::BOSSURL.append("/%s/%s/%s?c=%s&l=%s").c_str(), "1", boss_code, it->task_id, countryCode, languageCode); + requestUrl = PretendoURLs::BOSSURL; break; case NetworkService::Custom: - sprintf(url, GetNetworkConfig().urls.BOSS.GetValue().append("/%s/%s/%s?c=%s&l=%s").c_str(), "1", boss_code, it->task_id, countryCode, languageCode); + requestUrl = GetNetworkConfig().urls.BOSS.GetValue(); break; + case NetworkService::Nintendo: default: - sprintf(url, NintendoURLs::BOSSURL.append("/%s/%s/%s?c=%s&l=%s").c_str(), "1", boss_code, it->task_id, countryCode, languageCode); + requestUrl = NintendoURLs::BOSSURL; break; } + requestUrl.append(fmt::format(fmt::runtime("/{}/{}/{}?c={}&l={}"), "1", boss_code, it->task_id, countryCode, languageCode)); } curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list_headerParam); - curl_easy_setopt(curl, CURLOPT_URL, url); - forceLogDebug_printf("task_run url %s", url); + curl_easy_setopt(curl, CURLOPT_URL, requestUrl.c_str()); int curl_result = curl_easy_perform(curl); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &it->http_status_code); diff --git a/src/Cemu/napi/napi_idbe.cpp b/src/Cemu/napi/napi_idbe.cpp index 6832bf73..6644eb06 100644 --- a/src/Cemu/napi/napi_idbe.cpp +++ b/src/Cemu/napi/napi_idbe.cpp @@ -57,21 +57,23 @@ namespace NAPI std::vector IDBE_RequestRawEncrypted(uint64 titleId) { CurlRequestHelper req; - switch (ActiveSettings::GetNetworkService()) - { - case NetworkService::Nintendo: - req.initate(fmt::format(fmt::runtime(NintendoURLs::IDBEURL + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); - break; - case NetworkService::Pretendo: - req.initate(fmt::format(fmt::runtime(PretendoURLs::IDBEURL + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); - break; - case NetworkService::Custom: - req.initate(fmt::format(fmt::runtime(GetNetworkConfig().urls.IDBE.GetValue() + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); - break; - default: - req.initate(fmt::format(fmt::runtime(NintendoURLs::IDBEURL + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); - break; - } + std::string requestUrl; + switch (ActiveSettings::GetNetworkService()) + { + case NetworkService::Pretendo: + requestUrl = PretendoURLs::IDBEURL; + break; + case NetworkService::Custom: + requestUrl = GetNetworkConfig().urls.IDBE.GetValue(); + break; + case NetworkService::Nintendo: + default: + requestUrl = NintendoURLs::IDBEURL; + break; + } + requestUrl.append(fmt::format(fmt::runtime("/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId)); + req.initate(requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); + if (!req.submitRequest(false)) { cemuLog_log(LogType::Force, fmt::format("Failed to request IDBE icon for title {0:016X}", titleId)); @@ -99,59 +101,30 @@ namespace NAPI return std::nullopt; } - CurlRequestHelper req; - switch (ActiveSettings::GetNetworkService()) - { - case NetworkService::Nintendo: - req.initate(fmt::format(fmt::runtime(NintendoURLs::IDBEURL + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); - break; - case NetworkService::Pretendo: - req.initate(fmt::format(fmt::runtime(PretendoURLs::IDBEURL + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); - break; - case NetworkService::Custom: - req.initate(fmt::format(fmt::runtime(GetNetworkConfig().urls.IDBE.GetValue() + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); - break; - default: - req.initate(fmt::format(fmt::runtime(NintendoURLs::IDBEURL + "/{0:02X}/{1:016X}.idbe"), (uint32)((titleId >> 8) & 0xFF), titleId), CurlRequestHelper::SERVER_SSL_CONTEXT::IDBE); - break; - } - - if (!req.submitRequest(false)) - { - cemuLog_log(LogType::Force, fmt::format("Failed to request IDBE icon for title {0:016X}", titleId)); + std::vector idbeData = IDBE_RequestRawEncrypted(titleId); + if (idbeData.size() < 0x22) return std::nullopt; - } - /* - format: - +0x00 uint8 version (0) - +0x01 uint8 keyIndex - +0x02 uint8[32] hashSHA256 - +0x22 uint8[] EncryptedIconData - */ - auto& receivedData = req.getReceivedData(); - if (receivedData.size() < 0x22) - return std::nullopt; - if (receivedData[0] != 0) + if (idbeData[0] != 0) { cemuLog_log(LogType::Force, "IDBE_Request: File has invalid version"); return std::nullopt; } - uint8 keyIndex = receivedData[1]; + uint8 keyIndex = idbeData[1]; if (keyIndex >= 4) { cemuLog_log(LogType::Force, "IDBE_Request: Key index out of range"); return std::nullopt; } - if (receivedData.size() < (0x22 + sizeof(IDBEIconDataV0))) + if (idbeData.size() < (0x22 + sizeof(IDBEIconDataV0))) { cemuLog_log(LogType::Force, "IDBE_Request: File size does not match"); return std::nullopt; } // extract hash and encrypted icon data uint8 hash[32]; - std::memcpy(hash, receivedData.data() + 0x2, 32); + std::memcpy(hash, idbeData.data() + 0x2, 32); IDBEIconDataV0 iconDataV0; - std::memcpy(&iconDataV0, receivedData.data() + 0x22, sizeof(IDBEIconDataV0)); + std::memcpy(&iconDataV0, idbeData.data() + 0x22, sizeof(IDBEIconDataV0)); // decrypt icon data and hash _decryptIDBEAndHash(&iconDataV0, hash, keyIndex); // verify hash of decrypted data diff --git a/src/Cemu/napi/napi_version.cpp b/src/Cemu/napi/napi_version.cpp index 73dd68cf..1979b822 100644 --- a/src/Cemu/napi/napi_version.cpp +++ b/src/Cemu/napi/napi_version.cpp @@ -16,21 +16,23 @@ namespace NAPI { NAPI_VersionListVersion_Result result; CurlRequestHelper req; + + std::string requestUrl; switch (ActiveSettings::GetNetworkService()) { - case NetworkService::Nintendo: - req.initate(fmt::format(fmt::runtime(NintendoURLs::TAGAYAURL + "/{}/{}/latest_version"), NCrypto::GetRegionAsString(authInfo.region), authInfo.country), CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA); - break; case NetworkService::Pretendo: - req.initate(fmt::format(fmt::runtime(PretendoURLs::TAGAYAURL + "/{}/{}/latest_version"), NCrypto::GetRegionAsString(authInfo.region), authInfo.country), CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA); + requestUrl = PretendoURLs::TAGAYAURL; break; case NetworkService::Custom: - req.initate(fmt::format(fmt::runtime(GetNetworkConfig().urls.TAGAYA.GetValue() + "/{}/{}/latest_version"), NCrypto::GetRegionAsString(authInfo.region), authInfo.country), CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA); + requestUrl = GetNetworkConfig().urls.TAGAYA.GetValue(); break; + case NetworkService::Nintendo: default: - req.initate(fmt::format(fmt::runtime(NintendoURLs::TAGAYAURL + "/{}/{}/latest_version"), NCrypto::GetRegionAsString(authInfo.region), authInfo.country), CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA); + requestUrl = NintendoURLs::TAGAYAURL; break; } + requestUrl.append(fmt::format(fmt::runtime("/{}/{}/latest_version"), NCrypto::GetRegionAsString(authInfo.region), authInfo.country)); + req.initate(requestUrl, CurlRequestHelper::SERVER_SSL_CONTEXT::TAGAYA); if (!req.submitRequest(false)) { diff --git a/src/config/LaunchSettings.cpp b/src/config/LaunchSettings.cpp index 06d9a5a3..4447f9bc 100644 --- a/src/config/LaunchSettings.cpp +++ b/src/config/LaunchSettings.cpp @@ -196,8 +196,6 @@ bool LaunchSettings::HandleCommandline(const std::vector& args) errorMsg.append("Error while trying to parse command line parameter:\n"); errorMsg.append(ex.what()); wxMessageBox(errorMsg, wxT("Parameter error"), wxICON_ERROR); - //cemuLog_log(LogType::Force, ex.what()); - //std::cout << "Command line parameter error: " << ex.what() << std::endl; return false; } @@ -270,10 +268,6 @@ void LaunchSettings::ChangeNetworkServiceURL(int ID){ NetworkService Network = static_cast(ID); switch (Network) { - case NetworkService::Nintendo: - serviceURL_ACT = NintendoURLs::ACTURL; - serviceURL_ECS = NintendoURLs::ECSURL; - break; case NetworkService::Pretendo: serviceURL_ACT = PretendoURLs::ACTURL; serviceURL_ECS = PretendoURLs::ECSURL; @@ -282,10 +276,10 @@ void LaunchSettings::ChangeNetworkServiceURL(int ID){ serviceURL_ACT = GetNetworkConfig().urls.ACT.GetValue(); serviceURL_ECS = GetNetworkConfig().urls.ECS.GetValue(); break; + case NetworkService::Nintendo: default: serviceURL_ACT = NintendoURLs::ACTURL; serviceURL_ECS = NintendoURLs::ECSURL; break; } - -} \ No newline at end of file +} diff --git a/src/config/NetworkSettings.cpp b/src/config/NetworkSettings.cpp index f3a3b8b6..210263ef 100644 --- a/src/config/NetworkSettings.cpp +++ b/src/config/NetworkSettings.cpp @@ -3,41 +3,48 @@ #include "CemuConfig.h" #include #include "Common/FileStream.h" + XMLNetworkConfig_t n_config(L"network_services.xml"); -void NetworkConfig::LoadOnce() { - s_full_path = boost::dll::program_location().generic_wstring(); +void NetworkConfig::LoadOnce() +{ + s_full_path = boost::dll::program_location().generic_wstring(); s_path = s_full_path.parent_path(); - n_config.SetFilename(GetPath("network_services.xml").generic_wstring()); - if(XMLExists()) { - n_config.Load(); - } + n_config.SetFilename(GetPath("network_services.xml").generic_wstring()); + if (XMLExists()) + n_config.Load(); } -void NetworkConfig::Load(XMLConfigParser& parser){ - auto config = parser.get("content"); - networkname = config.get("networkname","[Nintendo]"); - disablesslver = config.get("disablesslverification",disablesslver); - auto u = config.get("urls"); - urls.ACT = u.get("act",NintendoURLs::ACTURL); - urls.ECS = u.get("ecs",NintendoURLs::ECSURL); - urls.NUS = u.get("nus",NintendoURLs::NUSURL); - urls.IAS = u.get("ias",NintendoURLs::IASURL); - urls.CCSU = u.get("ccsu",NintendoURLs::CCSUURL); - urls.CCS = u.get("ccs",NintendoURLs::CCSURL); - urls.IDBE = u.get("idbe",NintendoURLs::IDBEURL); - urls.BOSS = u.get("boss",NintendoURLs::BOSSURL); - urls.TAGAYA = u.get("tagaya",NintendoURLs::TAGAYAURL); - if (static_cast(GetConfig().account.active_service.GetValue()) == NetworkService::Custom) { - LaunchSettings::ChangeNetworkServiceURL(2); - } +void NetworkConfig::Load(XMLConfigParser& parser) +{ + auto config = parser.get("content"); + networkname = config.get("networkname", "Custom"); + disablesslver = config.get("disablesslverification", disablesslver); + auto u = config.get("urls"); + urls.ACT = u.get("act", NintendoURLs::ACTURL); + urls.ECS = u.get("ecs", NintendoURLs::ECSURL); + urls.NUS = u.get("nus", NintendoURLs::NUSURL); + urls.IAS = u.get("ias", NintendoURLs::IASURL); + urls.CCSU = u.get("ccsu", NintendoURLs::CCSUURL); + urls.CCS = u.get("ccs", NintendoURLs::CCSURL); + urls.IDBE = u.get("idbe", NintendoURLs::IDBEURL); + urls.BOSS = u.get("boss", NintendoURLs::BOSSURL); + urls.TAGAYA = u.get("tagaya", NintendoURLs::TAGAYAURL); + if (static_cast(GetConfig().account.active_service.GetValue()) == NetworkService::Custom) + LaunchSettings::ChangeNetworkServiceURL(2); } -bool NetworkConfig::XMLExists() { - if (!fs::exists(GetPath("network_services.xml"))) { - if (static_cast(GetConfig().account.active_service.GetValue()) == NetworkService::Custom) { - LaunchSettings::ChangeNetworkServiceURL(0); - GetConfig().account.active_service = 0; - } - return false; - } else {return true;} + +bool NetworkConfig::XMLExists() +{ + std::error_code ec; + if (!fs::exists(GetPath("network_services.xml"), ec)) + { + if (static_cast(GetConfig().account.active_service.GetValue()) == NetworkService::Custom) + { + LaunchSettings::ChangeNetworkServiceURL(0); + GetConfig().account.active_service = 0; + } + return false; + } + return true; } \ No newline at end of file diff --git a/src/gui/GeneralSettings2.cpp b/src/gui/GeneralSettings2.cpp index ffb58e48..776afc2e 100644 --- a/src/gui/GeneralSettings2.cpp +++ b/src/gui/GeneralSettings2.cpp @@ -605,14 +605,12 @@ wxPanel* GeneralSettings2::AddAccountPage(wxNotebook* notebook) content->Add(m_delete_account, 0, wxEXPAND | wxALL | wxALIGN_RIGHT, 5); m_delete_account->Bind(wxEVT_BUTTON, &GeneralSettings2::OnAccountDelete, this); - if (NetworkConfig::XMLExists()) { - wxString choices[] = { _("Nintendo"), _("Pretendo"), _("Custom") }; - m_active_service= new wxRadioBox(online_panel, wxID_ANY, _("Network Service"), wxDefaultPosition, wxDefaultSize, std::size(choices), choices, 3, wxRA_SPECIFY_COLS); - } - else { - wxString choices[] = { _("Nintendo"), _("Pretendo") }; - m_active_service= new wxRadioBox(online_panel, wxID_ANY, _("Network Service"), wxDefaultPosition, wxDefaultSize, std::size(choices), choices, 2, wxRA_SPECIFY_COLS); - } + wxString choices[] = { _("Nintendo"), _("Pretendo"), _("Custom") }; + m_active_service = new wxRadioBox(online_panel, wxID_ANY, _("Network Service"), wxDefaultPosition, wxDefaultSize, std::size(choices), choices, 3, wxRA_SPECIFY_COLS); + if (!NetworkConfig::XMLExists()) + m_active_service->Enable(2, false); + + m_active_service->SetToolTip(_("Connect to which Network Service")); m_active_service->Bind(wxEVT_RADIOBOX, &GeneralSettings2::OnAccountServiceChanged,this); content->Add(m_active_service, 0, wxEXPAND | wxALL, 5); diff --git a/src/gui/guiWrapper.cpp b/src/gui/guiWrapper.cpp index 2a1598c0..4d840cf4 100644 --- a/src/gui/guiWrapper.cpp +++ b/src/gui/guiWrapper.cpp @@ -97,17 +97,14 @@ void gui_updateWindowTitles(bool isIdle, bool isLoading, double fps) const uint64 titleId = CafeSystem::GetForegroundTitleId(); windowText.append(fmt::format(" - FPS: {:.2f} {} {} [TitleId: {:08x}-{:08x}]", (double)fps, renderer, graphicMode, (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF))); - if (ActiveSettings::IsOnlineEnabled()){ - windowText.append(" [Online]"); - if (ActiveSettings::GetNetworkService() == NetworkService::Nintendo) { - windowText.append("[Nintendo]"); - } - else if (ActiveSettings::GetNetworkService() == NetworkService::Pretendo) { - windowText.append("[Pretendo]"); - } - else if (ActiveSettings::GetNetworkService() == NetworkService::Custom) { - windowText.append("[" + GetNetworkConfig().networkname.GetValue() + "]"); - } + if (ActiveSettings::IsOnlineEnabled()) + { + if (ActiveSettings::GetNetworkService() == NetworkService::Nintendo) + windowText.append(" [Online]"); + else if (ActiveSettings::GetNetworkService() == NetworkService::Pretendo) + windowText.append(" [Online-Pretendo]"); + else if (ActiveSettings::GetNetworkService() == NetworkService::Custom) + windowText.append(" [Online-" + GetNetworkConfig().networkname.GetValue() + "]"); } windowText.append(" "); windowText.append(CafeSystem::GetForegroundTitleName()); From d6ba61cf6435a163bf6aea17de32c19d1e61e456 Mon Sep 17 00:00:00 2001 From: SSimco <37044560+SSimco@users.noreply.github.com> Date: Tue, 11 Oct 2022 23:03:26 -0700 Subject: [PATCH 048/638] Add support for non portable mode (#356) --- CMakeLists.txt | 5 ++ src/Cafe/Account/Account.cpp | 4 +- src/Cafe/CafeSystem.cpp | 6 +- src/Cafe/Filesystem/FST/KeyCache.cpp | 2 +- src/Cafe/GameProfile/GameProfile.cpp | 11 ++- src/Cafe/GraphicPack/GraphicPack2.cpp | 4 +- src/Cafe/HW/Latte/Core/LatteShaderCache.cpp | 10 +-- .../Renderer/OpenGL/RendererShaderGL.cpp | 2 +- src/Cafe/HW/Latte/Renderer/Renderer.cpp | 2 +- .../Renderer/Vulkan/RendererShaderVk.cpp | 2 +- .../Vulkan/VulkanPipelineStableCache.cpp | 4 +- .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 4 +- src/Cafe/HW/MMU/MMU.cpp | 2 +- src/Cafe/IOSU/legacy/iosu_crypto.cpp | 8 +- src/Cafe/OS/RPL/rpl.cpp | 2 +- src/Cafe/OS/libs/coreinit/coreinit_FS.cpp | 4 +- src/Cafe/TitleList/TitleInfo.cpp | 2 +- src/Cemu/Logging/CemuLogging.cpp | 2 +- .../ExceptionHandler_win32.cpp | 6 +- src/config/ActiveSettings.cpp | 33 +++++++- src/config/ActiveSettings.h | 81 ++++++++++--------- src/config/NetworkSettings.cpp | 8 +- src/config/NetworkSettings.h | 8 -- src/gui/CemuApp.cpp | 79 ++++++++++++++---- src/gui/CemuApp.h | 8 +- src/gui/CemuUpdateWindow.cpp | 4 +- src/gui/ChecksumTool.cpp | 6 +- src/gui/DownloadGraphicPacksWindow.cpp | 10 +-- src/gui/GraphicPacksWindow2.cpp | 3 +- src/gui/MainWindow.cpp | 12 +-- src/gui/MemorySearcherTool.cpp | 4 +- src/gui/debugger/DebuggerWindow2.cpp | 4 +- src/gui/input/InputSettings2.cpp | 4 +- src/input/InputManager.cpp | 16 ++-- src/main.cpp | 27 ++----- src/util/helpers/helpers.cpp | 3 +- src/util/helpers/helpers.h | 2 +- src/util/libusbWrapper/libusbWrapper.cpp | 2 +- 38 files changed, 233 insertions(+), 163 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 76dcd33a..b973a3f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 3.21.1) option(ENABLE_VCPKG "Enable the vcpkg package manager" ON) +option(PORTABLE "All data created and maintained by Cemu will be in the directory where the executable file is located" ON) set(EXPERIMENTAL_VERSION "" CACHE STRING "") # used by CI script to set experimental version if (EXPERIMENTAL_VERSION) @@ -30,6 +31,10 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) add_compile_definitions($<$:CEMU_DEBUG_ASSERT>) # if build type is debug, set CEMU_DEBUG_ASSERT +if(PORTABLE) + add_compile_definitions(PORTABLE) +endif() + set_property(GLOBAL PROPERTY USE_FOLDERS ON) # enable link time optimization for release builds diff --git a/src/Cafe/Account/Account.cpp b/src/Cafe/Account/Account.cpp index 2cf424f1..f1ce0be8 100644 --- a/src/Cafe/Account/Account.cpp +++ b/src/Cafe/Account/Account.cpp @@ -424,7 +424,7 @@ OnlineValidator Account::ValidateOnlineFiles() const { OnlineValidator result{}; - const auto otp = ActiveSettings::GetPath("otp.bin"); + const auto otp = ActiveSettings::GetUserDataPath("otp.bin"); if (!fs::exists(otp)) result.otp = OnlineValidator::FileState::Missing; else if (fs::file_size(otp) != 1024) @@ -432,7 +432,7 @@ OnlineValidator Account::ValidateOnlineFiles() const else result.otp = OnlineValidator::FileState::Ok; - const auto seeprom = ActiveSettings::GetPath("seeprom.bin"); + const auto seeprom = ActiveSettings::GetUserDataPath("seeprom.bin"); if (!fs::exists(seeprom)) result.seeprom = OnlineValidator::FileState::Missing; else if (fs::file_size(seeprom) != 512) diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index 2cadc106..e2e1c5ef 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -289,7 +289,7 @@ uint32 loadSharedData() for (sint32 i = 0; i < sizeof(shareddataDef) / sizeof(shareddataDef[0]); i++) { bool existsInMLC = fs::exists(ActiveSettings::GetMlcPath(shareddataDef[i].mlcPath)); - bool existsInResources = fs::exists(ActiveSettings::GetPath(shareddataDef[i].resourcePath)); + bool existsInResources = fs::exists(ActiveSettings::GetDataPath(shareddataDef[i].resourcePath)); if (!existsInMLC && !existsInResources) { @@ -314,7 +314,7 @@ uint32 loadSharedData() // alternatively fall back to our shared fonts if (!fontFile) { - path = ActiveSettings::GetPath(shareddataDef[i].resourcePath); + path = ActiveSettings::GetDataPath(shareddataDef[i].resourcePath); fontFile = FileStream::openFile2(path); } if (!fontFile) @@ -340,7 +340,7 @@ uint32 loadSharedData() return memory_getVirtualOffsetFromPointer(dataWritePtr); } // alternative method: load RAM dump - const auto path = ActiveSettings::GetPath("shareddata.bin"); + const auto path = ActiveSettings::GetUserDataPath("shareddata.bin"); FileStream* ramDumpFile = FileStream::openFile2(path); if (ramDumpFile) { diff --git a/src/Cafe/Filesystem/FST/KeyCache.cpp b/src/Cafe/Filesystem/FST/KeyCache.cpp index 587a5dd6..5d8d51c1 100644 --- a/src/Cafe/Filesystem/FST/KeyCache.cpp +++ b/src/Cafe/Filesystem/FST/KeyCache.cpp @@ -59,7 +59,7 @@ void KeyCache_Prepare() sKeyCachePrepared = true; g_keyCache.clear(); // load keys - auto keysPath = ActiveSettings::GetPath("keys.txt"); + auto keysPath = ActiveSettings::GetUserDataPath("keys.txt"); FileStream* fs_keys = FileStream::openFile2(keysPath); if( !fs_keys ) { diff --git a/src/Cafe/GameProfile/GameProfile.cpp b/src/Cafe/GameProfile/GameProfile.cpp index 9f2550c2..d8c735ce 100644 --- a/src/Cafe/GameProfile/GameProfile.cpp +++ b/src/Cafe/GameProfile/GameProfile.cpp @@ -180,12 +180,12 @@ void gameProfile_load() bool GameProfile::Load(uint64_t title_id) { - auto gameProfilePath = ActiveSettings::GetPath("gameProfiles/{:016x}.ini", title_id); + auto gameProfilePath = ActiveSettings::GetConfigPath("gameProfiles/{:016x}.ini", title_id); std::optional> profileContents = FileStream::LoadIntoMemory(gameProfilePath); if (!profileContents) { - gameProfilePath = ActiveSettings::GetPath("gameProfiles/default/{:016x}.ini", title_id); + gameProfilePath = ActiveSettings::GetDataPath("gameProfiles/default/{:016x}.ini", title_id); profileContents = FileStream::LoadIntoMemory(gameProfilePath); if (!profileContents) return false; @@ -276,7 +276,12 @@ bool GameProfile::Load(uint64_t title_id) void GameProfile::Save(uint64_t title_id) { - auto gameProfilePath = ActiveSettings::GetPath("gameProfiles/{:016x}.ini", title_id); + auto gameProfileDir = ActiveSettings::GetConfigPath("gameProfiles"); + if (std::error_code ex_ec; !fs::exists(gameProfileDir, ex_ec) && !ex_ec) { + std::error_code cr_ec; + fs::create_directories(gameProfileDir, cr_ec); + } + auto gameProfilePath = gameProfileDir / fmt::format("{:016x}.ini", title_id); FileStream* fs = FileStream::createFile2(gameProfilePath); if (!fs) { diff --git a/src/Cafe/GraphicPack/GraphicPack2.cpp b/src/Cafe/GraphicPack/GraphicPack2.cpp index 959441d7..a81ec03c 100644 --- a/src/Cafe/GraphicPack/GraphicPack2.cpp +++ b/src/Cafe/GraphicPack/GraphicPack2.cpp @@ -63,7 +63,7 @@ void GraphicPack2::LoadGraphicPack(fs::path graphicPackPath) void GraphicPack2::LoadAll() { std::error_code ec; - fs::path basePath = ActiveSettings::GetPath("graphicPacks"); + fs::path basePath = ActiveSettings::GetUserDataPath("graphicPacks"); for (fs::recursive_directory_iterator it(basePath, ec); it != end(it); ++it) { if (!it->is_directory(ec)) @@ -93,7 +93,7 @@ bool GraphicPack2::LoadGraphicPack(const std::wstring& filename, IniParser& rule if (it == config_entries.cend()) { // check for relative path - it = config_entries.find(MakeRelativePath(gp->GetFilename2()).lexically_normal()); + it = config_entries.find(MakeRelativePath(ActiveSettings::GetUserDataPath(), gp->GetFilename2()).lexically_normal()); } if (it != config_entries.cend()) diff --git a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp index e39d0e86..ba85898c 100644 --- a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp @@ -197,17 +197,17 @@ void LatteShaderCache_load() LatteShaderCache_initCompileQueue(); // create directories std::error_code ec; - fs::create_directories(ActiveSettings::GetPath("shaderCache/transferable"), ec); - fs::create_directories(ActiveSettings::GetPath("shaderCache/precompiled"), ec); + fs::create_directories(ActiveSettings::GetCachePath("shaderCache/transferable"), ec); + fs::create_directories(ActiveSettings::GetCachePath("shaderCache/precompiled"), ec); // initialize renderer specific caches if (g_renderer->GetType() == RendererAPI::Vulkan) RendererShaderVk::ShaderCacheLoading_begin(cacheTitleId); else if (g_renderer->GetType() == RendererAPI::OpenGL) RendererShaderGL::ShaderCacheLoading_begin(cacheTitleId); // get cache file name - const auto pathGeneric = ActiveSettings::GetPath("shaderCache/transferable/{:016x}_shaders.bin", cacheTitleId); - const auto pathGenericPre1_25_0 = ActiveSettings::GetPath("shaderCache/transferable/{:016x}.bin", cacheTitleId); // before 1.25.0 - const auto pathGenericPre1_16_0 = ActiveSettings::GetPath("shaderCache/transferable/{:08x}.bin", CafeSystem::GetRPXHashBase()); // before 1.16.0 + const auto pathGeneric = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}_shaders.bin", cacheTitleId); + const auto pathGenericPre1_25_0 = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}.bin", cacheTitleId); // before 1.25.0 + const auto pathGenericPre1_16_0 = ActiveSettings::GetCachePath("shaderCache/transferable/{:08x}.bin", CafeSystem::GetRPXHashBase()); // before 1.16.0 LatteShaderCache_handleDeprecatedCacheFiles(pathGeneric, pathGenericPre1_25_0, pathGenericPre1_16_0); // calculate extraVersion for transferable and precompiled shader cache diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp index e9e86f53..dc088ae3 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/RendererShaderGL.cpp @@ -279,7 +279,7 @@ void RendererShaderGL::ShaderCacheLoading_begin(uint64 cacheTitleId) { const uint32 cacheMagic = GeneratePrecompiledCacheId(); const std::string cacheFilename = fmt::format("{:016x}_gl.bin", cacheTitleId); - const std::wstring cachePath = ActiveSettings::GetPath("shaderCache/precompiled/{}", cacheFilename).generic_wstring(); + const std::wstring cachePath = ActiveSettings::GetCachePath("shaderCache/precompiled/{}", cacheFilename).generic_wstring(); g_programBinaryCache = FileCache::Open(cachePath, true, cacheMagic); if (g_programBinaryCache == nullptr) cemuLog_log(LogType::Force, "Unable to open OpenGL precompiled cache {}", cacheFilename); diff --git a/src/Cafe/HW/Latte/Renderer/Renderer.cpp b/src/Cafe/HW/Latte/Renderer/Renderer.cpp index c7f7b814..8f99c069 100644 --- a/src/Cafe/HW/Latte/Renderer/Renderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Renderer.cpp @@ -133,7 +133,7 @@ void Renderer::SaveScreenshot(const std::vector& rgb_data, int width, int // save to png file if (save_screenshot) { - fs::path screendir = ActiveSettings::GetPath("screenshots"); + fs::path screendir = ActiveSettings::GetUserDataPath("screenshots"); if (!fs::exists(screendir)) fs::create_directory(screendir); diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp index e6677576..7c577903 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp @@ -442,7 +442,7 @@ void RendererShaderVk::ShaderCacheLoading_begin(uint64 cacheTitleId) } uint32 spirvCacheMagic = GeneratePrecompiledCacheId(); const std::string cacheFilename = fmt::format("{:016x}_spirv.bin", cacheTitleId); - const std::wstring cachePath = ActiveSettings::GetPath("shaderCache/precompiled/{}", cacheFilename).generic_wstring(); + const std::wstring cachePath = ActiveSettings::GetCachePath("shaderCache/precompiled/{}", cacheFilename).generic_wstring(); s_spirvCache = FileCache::Open(cachePath, true, spirvCacheMagic); if (s_spirvCache == nullptr) cemuLog_log(LogType::Force, "Unable to open SPIR-V cache {}", cacheFilename); diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp index bb6c966e..38f7c882 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp @@ -32,8 +32,8 @@ VulkanPipelineStableCache& VulkanPipelineStableCache::GetInstance() uint32 VulkanPipelineStableCache::BeginLoading(uint64 cacheTitleId) { std::error_code ec; - fs::create_directories(ActiveSettings::GetPath("shaderCache/transferable"), ec); - const auto pathCacheFile = ActiveSettings::GetPath("shaderCache/transferable/{:016x}_vkpipeline.bin", cacheTitleId); + fs::create_directories(ActiveSettings::GetCachePath("shaderCache/transferable"), ec); + const auto pathCacheFile = ActiveSettings::GetCachePath("shaderCache/transferable/{:016x}_vkpipeline.bin", cacheTitleId); // init cache loader state g_vkCacheState.pipelineLoadIndex = 0; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index 249d06b7..5cbf7f94 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -2326,7 +2326,7 @@ void VulkanRenderer::WaitCommandBufferFinished(uint64 commandBufferId) void VulkanRenderer::PipelineCacheSaveThread(size_t cache_size) { - const auto dir = ActiveSettings::GetPath("shaderCache/driver/vk"); + const auto dir = ActiveSettings::GetCachePath("shaderCache/driver/vk"); if (!fs::exists(dir)) { try @@ -2403,7 +2403,7 @@ void VulkanRenderer::PipelineCacheSaveThread(size_t cache_size) void VulkanRenderer::CreatePipelineCache() { std::vector cacheData; - const auto dir = ActiveSettings::GetPath("shaderCache/driver/vk"); + const auto dir = ActiveSettings::GetCachePath("shaderCache/driver/vk"); if (fs::exists(dir)) { const auto filename = dir / fmt::format("{:016x}.bin", CafeSystem::GetForegroundTitleId()); diff --git a/src/Cafe/HW/MMU/MMU.cpp b/src/Cafe/HW/MMU/MMU.cpp index 87bf5722..9e22d907 100644 --- a/src/Cafe/HW/MMU/MMU.cpp +++ b/src/Cafe/HW/MMU/MMU.cpp @@ -409,7 +409,7 @@ void memory_writeDumpFile(uint32 startAddr, uint32 size, const fs::path& path) void memory_createDump() { const uint32 pageSize = MemMapper::GetPageSize(); - fs::path path = ActiveSettings::GetPath("dump/ramDump{:}", (uint32)time(nullptr)); + fs::path path = ActiveSettings::GetUserDataPath("dump/ramDump{:}", (uint32)time(nullptr)); fs::create_directories(path); for (auto& itr : g_mmuRanges) diff --git a/src/Cafe/IOSU/legacy/iosu_crypto.cpp b/src/Cafe/IOSU/legacy/iosu_crypto.cpp index e74a93e2..961ab70d 100644 --- a/src/Cafe/IOSU/legacy/iosu_crypto.cpp +++ b/src/Cafe/IOSU/legacy/iosu_crypto.cpp @@ -563,7 +563,7 @@ void iosuCrypto_loadSSLCertificates() void iosuCrypto_init() { // load OTP dump - if (std::ifstream otp_file(ActiveSettings::GetPath("otp.bin"), std::ifstream::in | std::ios::binary); otp_file.is_open()) + if (std::ifstream otp_file(ActiveSettings::GetUserDataPath("otp.bin"), std::ifstream::in | std::ios::binary); otp_file.is_open()) { otp_file.seekg(0, std::ifstream::end); const auto length = otp_file.tellg(); @@ -586,7 +586,7 @@ void iosuCrypto_init() hasOtpMem = false; } - if (std::ifstream seeprom_file(ActiveSettings::GetPath("seeprom.bin"), std::ifstream::in | std::ios::binary); seeprom_file.is_open()) + if (std::ifstream seeprom_file(ActiveSettings::GetUserDataPath("seeprom.bin"), std::ifstream::in | std::ios::binary); seeprom_file.is_open()) { seeprom_file.seekg(0, std::ifstream::end); const auto length = seeprom_file.tellg(); @@ -630,13 +630,13 @@ sint32 iosuCrypt_checkRequirementsForOnlineMode(std::wstring& additionalErrorInf { std::error_code ec; // check if otp.bin is present - const auto otp_file = ActiveSettings::GetPath("otp.bin"); + const auto otp_file = ActiveSettings::GetUserDataPath("otp.bin"); if(!fs::exists(otp_file, ec)) return IOS_CRYPTO_ONLINE_REQ_OTP_MISSING; if(fs::file_size(otp_file, ec) != 1024) return IOS_CRYPTO_ONLINE_REQ_OTP_CORRUPTED; // check if seeprom.bin is present - const auto seeprom_file = ActiveSettings::GetPath("seeprom.bin"); + const auto seeprom_file = ActiveSettings::GetUserDataPath("seeprom.bin"); if (!fs::exists(seeprom_file, ec)) return IOS_CRYPTO_ONLINE_REQ_SEEPROM_MISSING; if (fs::file_size(seeprom_file, ec) != 512) diff --git a/src/Cafe/OS/RPL/rpl.cpp b/src/Cafe/OS/RPL/rpl.cpp index 66d7a4ca..43e39d5b 100644 --- a/src/Cafe/OS/RPL/rpl.cpp +++ b/src/Cafe/OS/RPL/rpl.cpp @@ -2116,7 +2116,7 @@ void RPLLoader_LoadDependency(rplDependency_t* dependency) // attempt to load rpl from Cemu's /cafeLibs/ directory if (ActiveSettings::LoadSharedLibrariesEnabled()) { - const auto filePath = ActiveSettings::GetPath("cafeLibs/{}", dependency->filepath); + const auto filePath = ActiveSettings::GetUserDataPath("cafeLibs/{}", dependency->filepath); auto fileData = FileStream::LoadIntoMemory(filePath); if (fileData) { diff --git a/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp b/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp index c49607e1..1853bae8 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp @@ -107,7 +107,7 @@ namespace coreinit return; std::error_code ec; - const auto path = ActiveSettings::GetPath("sdcard/"); + const auto path = ActiveSettings::GetUserDataPath("sdcard/"); fs::create_directories(path, ec); FSCDeviceHostFS_Mount("/vol/external01", _pathToUtf8(path), FSC_PRIORITY_BASE); @@ -140,7 +140,7 @@ namespace coreinit return FS_RESULT::ERR_PLACEHOLDER; std::error_code ec; - const auto path = ActiveSettings::GetPath("sdcard/"); + const auto path = ActiveSettings::GetUserDataPath("sdcard/"); fs::create_directories(path, ec); if (!FSCDeviceHostFS_Mount(mountPathOut, _pathToUtf8(path), FSC_PRIORITY_BASE)) return FS_RESULT::ERR_PLACEHOLDER; diff --git a/src/Cafe/TitleList/TitleInfo.cpp b/src/Cafe/TitleList/TitleInfo.cpp index ef97e6eb..10710c43 100644 --- a/src/Cafe/TitleList/TitleInfo.cpp +++ b/src/Cafe/TitleList/TitleInfo.cpp @@ -291,7 +291,7 @@ void TitleInfo::CalcUID() fs::path normalizedPath; if (m_fullPath.is_relative()) { - normalizedPath = ActiveSettings::GetPath(); + normalizedPath = ActiveSettings::GetUserDataPath(); normalizedPath /= m_fullPath; } else diff --git a/src/Cemu/Logging/CemuLogging.cpp b/src/Cemu/Logging/CemuLogging.cpp index 7e6669a8..28a86427 100644 --- a/src/Cemu/Logging/CemuLogging.cpp +++ b/src/Cemu/Logging/CemuLogging.cpp @@ -98,7 +98,7 @@ void cemuLog_createLogFile(bool triggeredByCrash) if (LogContext.file_stream.is_open()) return; - const auto path = ActiveSettings::GetPath("log.txt"); + const auto path = ActiveSettings::GetUserDataPath("log.txt"); LogContext.file_stream.open(path, std::ios::out); if (LogContext.file_stream.fail()) { diff --git a/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp b/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp index 25dca26f..565f4f8f 100644 --- a/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp +++ b/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp @@ -61,7 +61,7 @@ bool CreateMiniDump(CrashDump dump, EXCEPTION_POINTERS* pep) if (dump == CrashDump::Disabled) return true; - fs::path p = ActiveSettings::GetPath("crashdump"); + fs::path p = ActiveSettings::GetUserDataPath("crashdump"); std::error_code ec; fs::create_directories(p, ec); @@ -356,11 +356,11 @@ void createCrashlog(EXCEPTION_POINTERS* e, PCONTEXT context) const auto temp_time = std::chrono::system_clock::to_time_t(now); const auto& time = *std::gmtime(&temp_time); - fs::path p = ActiveSettings::GetPath("crashdump"); + fs::path p = ActiveSettings::GetUserDataPath("crashdump"); p /= fmt::format("log_{:04d}{:02d}{:02d}_{:02d}{:02d}{:02d}.txt", 1900 + time.tm_year, time.tm_mon + 1, time.tm_mday, time.tm_year, time.tm_hour, time.tm_min, time.tm_sec); std::error_code ec; - fs::copy_file(ActiveSettings::GetPath("log.txt"), p, ec); + fs::copy_file(ActiveSettings::GetUserDataPath("log.txt"), p, ec); } exit(0); diff --git a/src/config/ActiveSettings.cpp b/src/config/ActiveSettings.cpp index 16119725..bef9cf0b 100644 --- a/src/config/ActiveSettings.cpp +++ b/src/config/ActiveSettings.cpp @@ -1,6 +1,7 @@ #include "config/ActiveSettings.h" #include "Cafe/GameProfile/GameProfile.h" +#include "Cemu/Logging/CemuLogging.h" #include "LaunchSettings.h" #include "util/helpers/helpers.h" @@ -12,17 +13,41 @@ extern bool alwaysDisplayDRC; -void ActiveSettings::LoadOnce() +std::set +ActiveSettings::LoadOnce(const fs::path& user_data_path, + const fs::path& config_path, + const fs::path& cache_path, + const fs::path& data_path) { s_full_path = boost::dll::program_location().generic_wstring(); - s_path = s_full_path.parent_path(); + + s_user_data_path = user_data_path; + s_config_path = config_path; + s_cache_path = cache_path; + s_data_path = data_path; + std::set failed_write_access; + for (auto&& path : {user_data_path, config_path, cache_path}) + { + if (!fs::exists(path)) + { + std::error_code ec; + fs::create_directories(path, ec); + } + if (!TestWriteAccess(path)) + { + cemuLog_log(LogType::Force, "Failed to write to {}", path.generic_string()); + failed_write_access.insert(path); + } + } + s_filename = s_full_path.filename(); - g_config.SetFilename(GetPath("settings.xml").generic_wstring()); + g_config.SetFilename(GetConfigPath("settings.xml").generic_wstring()); g_config.Load(); LaunchSettings::ChangeNetworkServiceURL(GetConfig().account.active_service); std::wstring additionalErrorInfo; s_has_required_online_files = iosuCrypt_checkRequirementsForOnlineMode(additionalErrorInfo) == IOS_CRYPTO_ONLINE_REQ_OK; + return failed_write_access; } bool ActiveSettings::LoadSharedLibrariesEnabled() @@ -226,6 +251,6 @@ fs::path ActiveSettings::GetMlcPath() fs::path ActiveSettings::GetDefaultMLCPath() { - return GetPath("mlc01"); + return GetUserDataPath("mlc01"); } diff --git a/src/config/ActiveSettings.h b/src/config/ActiveSettings.h index ae3feb94..9621b4d0 100644 --- a/src/config/ActiveSettings.h +++ b/src/config/ActiveSettings.h @@ -1,69 +1,70 @@ #pragma once +#include #include "config/CemuConfig.h" #include "config/NetworkSettings.h" // global active settings for fast access (reflects settings from command line and game profile) class ActiveSettings { -public: - static void LoadOnce(); - - [[nodiscard]] static fs::path GetFullPath() { return s_full_path; } - [[nodiscard]] static fs::path GetPath() { return s_path; } - [[nodiscard]] static fs::path GetFilename() { return s_filename; } - - [[nodiscard]] static fs::path GetMlcPath(); - - [[nodiscard]] static fs::path GetPath(std::string_view p) - { - std::basic_string_view s((const char8_t*)p.data(), p.size()); - return s_path / fs::path(s); - } - - [[nodiscard]] static fs::path GetMlcPath(std::string_view p) - { - std::basic_string_view s((const char8_t*)p.data(), p.size()); - return GetMlcPath() / fs::path(s); - } - +private: template - [[nodiscard]] static fs::path GetPath(std::string_view format, TArgs&&... args) + static fs::path GetPath(const fs::path& path, std::string_view format, TArgs&&... args) { cemu_assert_debug(format.empty() || (format[0] != '/' && format[0] != '\\')); std::string tmpPathStr = fmt::format(fmt::runtime(format), std::forward(args)...); - std::basic_string_view s((const char8_t*)tmpPathStr.data(), tmpPathStr.size()); - return s_path / fs::path(s); + return path / _utf8ToPath(tmpPathStr); } - + template - [[nodiscard]] static fs::path GetPath(std::wstring_view format, TArgs&&... args) + static fs::path GetPath(const fs::path& path, std::wstring_view format, TArgs&&... args) { cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); - return s_path / fmt::format(format, std::forward(args)...); + return path / fmt::format(fmt::runtime(format), std::forward(args)...); } - - template - [[nodiscard]] static fs::path GetMlcPath(std::string_view format, TArgs&&... args) + static fs::path GetPath(const fs::path& path, std::string_view p) { - cemu_assert_debug(format.empty() || (format[0] != '/' && format[0] != '\\')); - auto tmp = fmt::format(fmt::runtime(format), std::forward(args)...); - return GetMlcPath() / _utf8ToPath(tmp); + std::basic_string_view s((const char8_t*)p.data(), p.size()); + return path / fs::path(s); } - - template - [[nodiscard]] static fs::path GetMlcPath(std::wstring_view format, TArgs&&... args) + static fs::path GetPath(const fs::path& path) { - cemu_assert_debug(format.empty() || (format[0] != L'/' && format[0] != L'\\')); - return GetMlcPath() / fmt::format(fmt::runtime(format), std::forward(args)...); + return path; } - + +public: + // Set directories and return all directories that failed write access test + static std::set + LoadOnce(const fs::path& user_data_path, + const fs::path& config_path, + const fs::path& cache_path, + const fs::path& data_path); + + [[nodiscard]] static fs::path GetFullPath() { return s_full_path; } + [[nodiscard]] static fs::path GetFilename() { return s_filename; } + template + [[nodiscard]] static fs::path GetUserDataPath(TArgs&&... args){ return GetPath(s_user_data_path, std::forward(args)...); }; + template + [[nodiscard]] static fs::path GetConfigPath(TArgs&&... args){ return GetPath(s_config_path, std::forward(args)...); }; + template + [[nodiscard]] static fs::path GetCachePath(TArgs&&... args){ return GetPath(s_cache_path, std::forward(args)...); }; + template + [[nodiscard]] static fs::path GetDataPath(TArgs&&... args){ return GetPath(s_data_path, std::forward(args)...); }; + + [[nodiscard]] static fs::path GetMlcPath(); + + template + [[nodiscard]] static fs::path GetMlcPath(TArgs&&... args){ return GetPath(GetMlcPath(), std::forward(args)...); }; + // get mlc path to default cemu root dir/mlc01 [[nodiscard]] static fs::path GetDefaultMLCPath(); private: inline static fs::path s_full_path; // full filename - inline static fs::path s_path; // path + inline static fs::path s_user_data_path; + inline static fs::path s_config_path; + inline static fs::path s_cache_path; + inline static fs::path s_data_path; inline static fs::path s_filename; // cemu.exe inline static fs::path s_mlc_path; diff --git a/src/config/NetworkSettings.cpp b/src/config/NetworkSettings.cpp index 210263ef..2227b981 100644 --- a/src/config/NetworkSettings.cpp +++ b/src/config/NetworkSettings.cpp @@ -1,4 +1,5 @@ #include "NetworkSettings.h" +#include "ActiveSettings.h" #include "LaunchSettings.h" #include "CemuConfig.h" #include @@ -6,11 +7,10 @@ XMLNetworkConfig_t n_config(L"network_services.xml"); + void NetworkConfig::LoadOnce() { - s_full_path = boost::dll::program_location().generic_wstring(); - s_path = s_full_path.parent_path(); - n_config.SetFilename(GetPath("network_services.xml").generic_wstring()); + n_config.SetFilename(ActiveSettings::GetConfigPath("network_services.xml").generic_wstring()); if (XMLExists()) n_config.Load(); } @@ -37,7 +37,7 @@ void NetworkConfig::Load(XMLConfigParser& parser) bool NetworkConfig::XMLExists() { std::error_code ec; - if (!fs::exists(GetPath("network_services.xml"), ec)) + if (!fs::exists(ActiveSettings::GetConfigPath("network_services.xml"), ec)) { if (static_cast(GetConfig().account.active_service.GetValue()) == NetworkService::Custom) { diff --git a/src/config/NetworkSettings.h b/src/config/NetworkSettings.h index e65da8ab..f289e679 100644 --- a/src/config/NetworkSettings.h +++ b/src/config/NetworkSettings.h @@ -38,14 +38,6 @@ struct NetworkConfig { void Save(XMLConfigParser& parser); static bool XMLExists(); - private: - inline static fs::path s_path; - inline static fs::path s_full_path; - [[nodiscard]] static fs::path GetPath(std::string_view p) - { - std::basic_string_view s((const char8_t*)p.data(), p.size()); - return s_path / fs::path(s); - } }; struct NintendoURLs { diff --git a/src/gui/CemuApp.cpp b/src/gui/CemuApp.cpp index de60f8bc..50e9e04c 100644 --- a/src/gui/CemuApp.cpp +++ b/src/gui/CemuApp.cpp @@ -14,6 +14,7 @@ #include #include +#include #include "Cafe/TitleList/TitleList.h" #include "Cafe/TitleList/SaveList.h" @@ -24,6 +25,8 @@ wxIMPLEMENT_APP_NO_MAIN(CemuApp); extern WindowInfo g_window_info; extern std::shared_mutex g_mutex; +int mainEmulatorHLE(); +void HandlePostUpdate(); // Translation strings to extract for gettext: void unused_translation_dummy() { @@ -70,6 +73,42 @@ void unused_translation_dummy() bool CemuApp::OnInit() { + fs::path user_data_path, config_path, cache_path, data_path; + auto standardPaths = wxStandardPaths::Get(); +#ifdef PORTABLE + fs::path exePath(standardPaths.GetExecutablePath().ToStdString()); + user_data_path = config_path = cache_path = data_path = exePath.parent_path(); +#else + SetAppName("Cemu"); + wxString appName=GetAppName(); + #ifdef BOOST_OS_LINUX + standardPaths.SetFileLayout(wxStandardPaths::FileLayout::FileLayout_XDG); + auto getEnvDir = [&](const wxString& varName, const wxString& defaultValue) + { + wxString dir; + if (!wxGetEnv(varName, &dir) || dir.empty()) + return defaultValue; + return dir; + }; + wxString homeDir=wxFileName::GetHomeDir(); + user_data_path = (getEnvDir(wxS("XDG_DATA_HOME"), homeDir + wxS("/.local/share")) + "/" + appName).ToStdString(); + config_path = (getEnvDir(wxS("XDG_CONFIG_HOME"), homeDir + wxS("/.config")) + "/" + appName).ToStdString(); + #else + user_data_path = config_path = standardPaths.GetUserDataDir().ToStdString(); + #endif + data_path = standardPaths.GetDataDir().ToStdString(); + cache_path = standardPaths.GetUserDir(wxStandardPaths::Dir::Dir_Cache).ToStdString(); + cache_path /= appName.ToStdString(); +#endif + auto failed_write_access = ActiveSettings::LoadOnce(user_data_path, config_path, cache_path, data_path); + for (auto&& path : failed_write_access) + wxMessageBox(fmt::format("Cemu can't write to {} !", path.generic_string()), _("Warning"), wxOK | wxCENTRE | wxICON_EXCLAMATION, nullptr); + + NetworkConfig::LoadOnce(); + + HandlePostUpdate(); + mainEmulatorHLE(); + wxInitAllImageHandlers(); g_config.Load(); @@ -83,7 +122,7 @@ bool CemuApp::OnInit() { if (m_locale.Init(language)) { - m_locale.AddCatalogLookupPathPrefix("./resources"); + m_locale.AddCatalogLookupPathPrefix(ActiveSettings::GetDataPath("resources").generic_string()); m_locale.AddCatalog("cemu"); } } @@ -115,9 +154,6 @@ bool CemuApp::OnInit() Bind(wxEVT_ACTIVATE_APP, &CemuApp::ActivateApp, this); - if (!TestWriteAccess(ActiveSettings::GetPath())) - wxMessageBox(_("Cemu can't write to its directory.\nPlease move it to a different location or run Cemu as administrator!"), _("Warning"), wxOK | wxCENTRE | wxICON_EXCLAMATION, nullptr); - auto& config = GetConfig(); const bool first_start = !config.did_show_graphic_pack_download; @@ -187,7 +223,7 @@ int CemuApp::FilterEvent(wxEvent& event) std::vector CemuApp::GetAvailableLanguages() { - const auto path = ActiveSettings::GetPath("resources"); + const auto path = ActiveSettings::GetDataPath("resources"); if (!exists(path)) return {}; @@ -312,11 +348,11 @@ void CemuApp::CreateDefaultFiles(bool first_start) // cemu directories try { - const auto controllerProfileFolder = GetCemuPath(L"controllerProfiles").ToStdWstring(); + const auto controllerProfileFolder = GetConfigPath(L"controllerProfiles").ToStdWstring(); if (!fs::exists(controllerProfileFolder)) fs::create_directories(controllerProfileFolder); - const auto memorySearcherFolder = GetCemuPath(L"memorySearcher").ToStdWstring(); + const auto memorySearcherFolder = GetUserDataPath(L"memorySearcher").ToStdWstring(); if (!fs::exists(memorySearcherFolder)) fs::create_directories(memorySearcherFolder); } @@ -377,15 +413,6 @@ bool CemuApp::SelectMLCPath(wxWindow* parent) return false; } -wxString CemuApp::GetCemuPath() -{ - return ActiveSettings::GetPath().generic_wstring(); -} - -wxString CemuApp::GetCemuPath(const wxString& cat) -{ - return ActiveSettings::GetPath(cat.ToStdString()).generic_wstring(); -} wxString CemuApp::GetMLCPath() { @@ -397,6 +424,26 @@ wxString CemuApp::GetMLCPath(const wxString& cat) return ActiveSettings::GetMlcPath(cat.ToStdString()).generic_wstring(); } +wxString CemuApp::GetConfigPath() +{ + return ActiveSettings::GetConfigPath().generic_wstring(); +}; + +wxString CemuApp::GetConfigPath(const wxString& cat) +{ + return ActiveSettings::GetConfigPath(cat.ToStdString()).generic_wstring(); +}; + +wxString CemuApp::GetUserDataPath() +{ + return ActiveSettings::GetUserDataPath().generic_wstring(); +}; + +wxString CemuApp::GetUserDataPath(const wxString& cat) +{ + return ActiveSettings::GetUserDataPath(cat.ToStdString()).generic_wstring(); +}; + void CemuApp::ActivateApp(wxActivateEvent& event) { g_window_info.app_active = event.GetActive(); diff --git a/src/gui/CemuApp.h b/src/gui/CemuApp.h index 888293eb..32504883 100644 --- a/src/gui/CemuApp.h +++ b/src/gui/CemuApp.h @@ -19,8 +19,12 @@ public: static void CreateDefaultFiles(bool first_start = false); static bool SelectMLCPath(wxWindow* parent = nullptr); - static wxString GetCemuPath(); - static wxString GetCemuPath(const wxString& cat); + static wxString GetConfigPath(); + static wxString GetConfigPath(const wxString& cat); + + static wxString GetUserDataPath(); + static wxString GetUserDataPath(const wxString& cat); + static wxString GetMLCPath(); static wxString GetMLCPath(const wxString& cat); private: diff --git a/src/gui/CemuUpdateWindow.cpp b/src/gui/CemuUpdateWindow.cpp index ef537a58..2e2b40eb 100644 --- a/src/gui/CemuUpdateWindow.cpp +++ b/src/gui/CemuUpdateWindow.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -470,7 +471,8 @@ void CemuUpdateWindow::WorkerThread() break; // apply update - std::wstring target_directory = ActiveSettings::GetPath().generic_wstring(); + fs::path exePath = fs::path(wxStandardPaths::Get().GetExecutablePath().ToStdString()); + std::wstring target_directory = exePath.parent_path().generic_wstring(); if (target_directory[target_directory.size() - 1] == '/') target_directory = target_directory.substr(0, target_directory.size() - 1); // remove trailing / diff --git a/src/gui/ChecksumTool.cpp b/src/gui/ChecksumTool.cpp index b8393330..20e9f7ca 100644 --- a/src/gui/ChecksumTool.cpp +++ b/src/gui/ChecksumTool.cpp @@ -134,7 +134,7 @@ ChecksumTool::ChecksumTool(wxWindow* parent, wxTitleManagerList::TitleEntry& ent const auto title_id_str = fmt::format("{:016x}", m_json_entry.title_id); const auto default_file = fmt::format("{}_v{}.json", title_id_str, m_info.GetAppTitleVersion()); - const auto checksum_path = ActiveSettings::GetPath("resources/checksums/{}", default_file); + const auto checksum_path = ActiveSettings::GetUserDataPath("resources/checksums/{}", default_file); if (exists(checksum_path)) m_verify_online->Enable(); } @@ -186,7 +186,7 @@ void ChecksumTool::LoadOnlineData() const std::string latest_commit; - const auto checksum_path = ActiveSettings::GetPath("resources/checksums"); + const auto checksum_path = ActiveSettings::GetUserDataPath("resources/checksums"); if (exists(checksum_path)) { std::string current_commit; @@ -594,7 +594,7 @@ void ChecksumTool::OnVerifyOnline(wxCommandEvent& event) const auto title_id_str = fmt::format("{:016x}", m_json_entry.title_id); const auto default_file = fmt::format("{}_v{}.json", title_id_str, m_info.GetAppTitleVersion()); - const auto checksum_path = ActiveSettings::GetPath("resources/checksums/{}", default_file); + const auto checksum_path = ActiveSettings::GetUserDataPath("resources/checksums/{}", default_file); if(!exists(checksum_path)) return; diff --git a/src/gui/DownloadGraphicPacksWindow.cpp b/src/gui/DownloadGraphicPacksWindow.cpp index 973b7c57..4128cc04 100644 --- a/src/gui/DownloadGraphicPacksWindow.cpp +++ b/src/gui/DownloadGraphicPacksWindow.cpp @@ -65,7 +65,7 @@ bool DownloadGraphicPacksWindow::curlDownloadFile(const char *url, curlDownloadF bool checkGraphicPackDownloadedVersion(const char* nameVersion, bool& hasVersionFile) { hasVersionFile = false; - const auto path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks/version.txt"); + const auto path = ActiveSettings::GetUserDataPath("graphicPacks/downloadedGraphicPacks/version.txt"); std::unique_ptr file(FileStream::openFile2(path)); std::string versionInFile; @@ -78,7 +78,7 @@ bool checkGraphicPackDownloadedVersion(const char* nameVersion, bool& hasVersion void createGraphicPackDownloadedVersionFile(const char* nameVersion) { - const auto path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks/version.txt"); + const auto path = ActiveSettings::GetUserDataPath("graphicPacks/downloadedGraphicPacks/version.txt"); std::unique_ptr file(FileStream::createFile2(path)); if (file) file->writeString(nameVersion); @@ -90,7 +90,7 @@ void createGraphicPackDownloadedVersionFile(const char* nameVersion) void deleteDownloadedGraphicPacks() { - const auto path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks"); + const auto path = ActiveSettings::GetUserDataPath("graphicPacks/downloadedGraphicPacks"); std::error_code er; if (!fs::exists(path, er)) return; @@ -238,7 +238,7 @@ void DownloadGraphicPacksWindow::UpdateThread() return; } - auto path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks"); + auto path = ActiveSettings::GetUserDataPath("graphicPacks/downloadedGraphicPacks"); std::error_code er; //fs::remove_all(path, er); -> Don't delete the whole folder and recreate it immediately afterwards because sometimes it just fails deleteDownloadedGraphicPacks(); @@ -258,7 +258,7 @@ void DownloadGraphicPacksWindow::UpdateThread() std::strstr(sb.name, "..\\") != nullptr) continue; // bad path - path = ActiveSettings::GetPath("graphicPacks/downloadedGraphicPacks/{}", sb.name); + path = ActiveSettings::GetUserDataPath("graphicPacks/downloadedGraphicPacks/{}", sb.name); size_t sbNameLen = strlen(sb.name); if(sbNameLen == 0) diff --git a/src/gui/GraphicPacksWindow2.cpp b/src/gui/GraphicPacksWindow2.cpp index bab55156..e718605a 100644 --- a/src/gui/GraphicPacksWindow2.cpp +++ b/src/gui/GraphicPacksWindow2.cpp @@ -3,6 +3,7 @@ #include "gui/DownloadGraphicPacksWindow.h" #include "Cafe/GraphicPack/GraphicPack2.h" #include "config/CemuConfig.h" +#include "config/ActiveSettings.h" #include "Cafe/HW/Latte/Core/LatteAsyncCommands.h" @@ -326,7 +327,7 @@ void GraphicPacksWindow2::SaveStateToConfig() for (const auto& gp : GraphicPack2::GetGraphicPacks()) { - auto filename = MakeRelativePath(gp->GetFilename()).lexically_normal(); + auto filename = MakeRelativePath(ActiveSettings::GetUserDataPath(), gp->GetFilename()).lexically_normal(); if (gp->IsEnabled()) { data.graphic_pack_entries.try_emplace(filename); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index d8caabf4..5ebfe09d 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -989,8 +989,8 @@ void MainWindow::OnDebugSetting(wxCommandEvent& event) { try { - const auto path = CemuApp::GetCemuPath(L"dump\\curl").ToStdWstring(); - fs::create_directories(path); + const fs::path path(CemuApp::GetUserDataPath().ToStdString()); + fs::create_directories(path / "dump" / "curl"); } catch (const std::exception& ex) { @@ -1046,8 +1046,8 @@ void MainWindow::OnDebugDumpUsedTextures(wxCommandEvent& event) try { // create directory - const auto path = CemuApp::GetCemuPath(L"dump\\textures"); - fs::create_directories(path.ToStdWstring()); + const fs::path path(CemuApp::GetUserDataPath().ToStdString()); + fs::create_directories(path / "dump" / "textures"); } catch (const std::exception& ex) { @@ -1067,8 +1067,8 @@ void MainWindow::OnDebugDumpUsedShaders(wxCommandEvent& event) try { // create directory - const auto path = CemuApp::GetCemuPath(L"dump\\shaders"); - fs::create_directories(path.ToStdWstring()); + const fs::path path(CemuApp::GetUserDataPath().ToStdString()); + fs::create_directories(path / "dump" / "shaders"); } catch (const std::exception & ex) { diff --git a/src/gui/MemorySearcherTool.cpp b/src/gui/MemorySearcherTool.cpp index 5caa163f..093f7ffe 100644 --- a/src/gui/MemorySearcherTool.cpp +++ b/src/gui/MemorySearcherTool.cpp @@ -270,7 +270,7 @@ void MemorySearcherTool::OnFilter(wxCommandEvent& event) void MemorySearcherTool::Load() { - const auto memorySearcherPath = ActiveSettings::GetPath("memorySearcher/{:016x}.ini", CafeSystem::GetForegroundTitleId()); + const auto memorySearcherPath = ActiveSettings::GetUserDataPath("memorySearcher/{:016x}.ini", CafeSystem::GetForegroundTitleId()); auto memSearcherIniContents = FileStream::LoadIntoMemory(memorySearcherPath); if (!memSearcherIniContents) return; @@ -322,7 +322,7 @@ void MemorySearcherTool::Load() void MemorySearcherTool::Save() { - const auto memorySearcherPath = ActiveSettings::GetPath("memorySearcher/{:016x}.ini", CafeSystem::GetForegroundTitleId()); + const auto memorySearcherPath = ActiveSettings::GetUserDataPath("memorySearcher/{:016x}.ini", CafeSystem::GetForegroundTitleId()); FileStream* fs = FileStream::createFile2(memorySearcherPath); if (fs) { diff --git a/src/gui/debugger/DebuggerWindow2.cpp b/src/gui/debugger/DebuggerWindow2.cpp index 1f6c5f79..6263f0b7 100644 --- a/src/gui/debugger/DebuggerWindow2.cpp +++ b/src/gui/debugger/DebuggerWindow2.cpp @@ -271,7 +271,7 @@ DebuggerWindow2::DebuggerWindow2(wxFrame& parent, const wxRect& display_size) { this->wxWindowBase::SetBackgroundColour(*wxWHITE); - const auto file = ActiveSettings::GetPath("debugger/config.xml"); + const auto file = ActiveSettings::GetConfigPath("debugger/config.xml"); m_config.SetFilename(file.generic_wstring()); m_config.Load(); @@ -471,7 +471,7 @@ bool DebuggerWindow2::Show(bool show) std::wstring DebuggerWindow2::GetModuleStoragePath(std::string module_name, uint32_t crc_hash) const { if (module_name.empty() || crc_hash == 0) return std::wstring(); - return ActiveSettings::GetPath("debugger/{}_{:#10x}.xml", module_name, crc_hash).generic_wstring(); + return ActiveSettings::GetConfigPath("debugger/{}_{:#10x}.xml", module_name, crc_hash).generic_wstring(); } void DebuggerWindow2::OnBreakpointHit(wxCommandEvent& event) diff --git a/src/gui/input/InputSettings2.cpp b/src/gui/input/InputSettings2.cpp index 37bd604f..095aa52a 100644 --- a/src/gui/input/InputSettings2.cpp +++ b/src/gui/input/InputSettings2.cpp @@ -665,10 +665,10 @@ void InputSettings2::on_profile_delete(wxCommandEvent& event) } try { - const fs::path old_path = ActiveSettings::GetPath(fmt::format("controllerProfiles/{}.txt", selection)); + const fs::path old_path = ActiveSettings::GetConfigPath("controllerProfiles/{}.txt", selection); fs::remove(old_path); - const fs::path path = ActiveSettings::GetPath(fmt::format("controllerProfiles/{}.xml", selection)); + const fs::path path = ActiveSettings::GetConfigPath("controllerProfiles/{}.xml", selection); fs::remove(path); profile_names->ChangeValue(kDefaultProfileName); diff --git a/src/input/InputManager.cpp b/src/input/InputManager.cpp index 4ae43ce3..0861ba28 100644 --- a/src/input/InputManager.cpp +++ b/src/input/InputManager.cpp @@ -76,9 +76,9 @@ bool InputManager::load(size_t player_index, std::string_view filename) { fs::path file_path; if (filename.empty()) - file_path = ActiveSettings::GetPath(fmt::format("controllerProfiles/controller{}", player_index)); + file_path = ActiveSettings::GetConfigPath("controllerProfiles/controller{}", player_index); else - file_path = ActiveSettings::GetPath(fmt::format("controllerProfiles/{}", filename)); + file_path = ActiveSettings::GetConfigPath("controllerProfiles/{}", filename); auto old_file = file_path; old_file.replace_extension(".txt"); // test .txt extension @@ -448,7 +448,7 @@ bool InputManager::save(size_t player_index, std::string_view filename) if (!emulated_controller) return false; - fs::path file_path = ActiveSettings::GetPath("controllerProfiles"); + fs::path file_path = ActiveSettings::GetConfigPath("controllerProfiles"); fs::create_directories(file_path); const auto is_default_file = filename.empty(); @@ -664,8 +664,8 @@ EmulatedControllerPtr InputManager::delete_controller(size_t player_index, bool if(delete_profile) { std::error_code ec{}; - fs::remove(ActiveSettings::GetPath(fmt::format("controllerProfiles/controller{}.xml", player_index)), ec); - fs::remove(ActiveSettings::GetPath(fmt::format("controllerProfiles/controller{}.txt", player_index)), ec); + fs::remove(ActiveSettings::GetConfigPath("controllerProfiles/controller{}.xml", player_index), ec); + fs::remove(ActiveSettings::GetConfigPath("controllerProfiles/controller{}.txt", player_index), ec); } return result; @@ -680,8 +680,8 @@ EmulatedControllerPtr InputManager::delete_controller(size_t player_index, bool controller = {}; std::error_code ec{}; - fs::remove(ActiveSettings::GetPath(fmt::format("controllerProfiles/controller{}.xml", player_index)), ec); - fs::remove(ActiveSettings::GetPath(fmt::format("controllerProfiles/controller{}.txt", player_index)), ec); + fs::remove(ActiveSettings::GetConfigPath("controllerProfiles/controller{}.xml", player_index), ec); + fs::remove(ActiveSettings::GetConfigPath("controllerProfiles/controller{}.txt", player_index), ec); return result; } @@ -782,7 +782,7 @@ void InputManager::apply_game_profile() std::vector InputManager::get_profiles() { - const auto path = ActiveSettings::GetPath("controllerProfiles"); + const auto path = ActiveSettings::GetConfigPath("controllerProfiles"); if (!exists(path)) return {}; diff --git a/src/main.cpp b/src/main.cpp index 87243bb8..e1c8ca49 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -161,7 +161,7 @@ void _putenvSafe(const char* c) void reconfigureGLDrivers() { // reconfigure GL drivers to store - const fs::path nvCacheDir = ActiveSettings::GetPath("shaderCache/driver/nvidia/"); + const fs::path nvCacheDir = ActiveSettings::GetCachePath("shaderCache/driver/nvidia/"); std::error_code err; fs::create_directories(nvCacheDir, err); @@ -245,8 +245,6 @@ void unitTests() int mainEmulatorHLE() { - if (!TestWriteAccess(ActiveSettings::GetPath())) - wxMessageBox("Cemu doesn't have write access to it's own directory.\nPlease move it to a different location or run Cemu as administrator!", "Warning", wxOK|wxICON_ERROR); // todo - different error messages per OS LatteOverlay_init(); // run a couple of tests if in non-release mode #ifdef CEMU_DEBUG_ASSERT @@ -267,7 +265,7 @@ int mainEmulatorHLE() // init Cafe system (todo - the stuff above should be part of this too) CafeSystem::Initialize(); // init title list - CafeTitleList::Initialize(ActiveSettings::GetPath("title_list_cache.xml")); + CafeTitleList::Initialize(ActiveSettings::GetUserDataPath("title_list_cache.xml")); for (auto& it : GetConfig().game_paths) CafeTitleList::AddScanPath(it); fs::path mlcPath = ActiveSettings::GetMlcPath(); @@ -281,8 +279,6 @@ int mainEmulatorHLE() CafeSaveList::SetMLCPath(mlcPath); CafeSaveList::Refresh(); } - // Create UI - gui_create(); return 0; } @@ -347,10 +343,8 @@ int wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ L SDL_SetMainReady(); if (!LaunchSettings::HandleCommandline(lpCmdLine)) return 0; - ActiveSettings::LoadOnce(); - NetworkConfig::LoadOnce(); - HandlePostUpdate(); - return mainEmulatorHLE(); + gui_create(); + return 0; } // entrypoint for debug builds with console @@ -359,10 +353,8 @@ int main(int argc, char* argv[]) SDL_SetMainReady(); if (!LaunchSettings::HandleCommandline(argc, argv)) return 0; - ActiveSettings::LoadOnce(); - NetworkConfig::LoadOnce(); - HandlePostUpdate(); - return mainEmulatorHLE(); + gui_create(); + return 0; } #else @@ -374,11 +366,8 @@ int main(int argc, char *argv[]) #endif if (!LaunchSettings::HandleCommandline(argc, argv)) return 0; - - ActiveSettings::LoadOnce(); - NetworkConfig::LoadOnce(); - HandlePostUpdate(); - return mainEmulatorHLE(); + gui_create(); + return 0; } #endif diff --git a/src/util/helpers/helpers.cpp b/src/util/helpers/helpers.cpp index 99712296..fefe7985 100644 --- a/src/util/helpers/helpers.cpp +++ b/src/util/helpers/helpers.cpp @@ -306,11 +306,10 @@ bool TestWriteAccess(const fs::path& p) } // make path relative to Cemu directory -fs::path MakeRelativePath(const fs::path& path) +fs::path MakeRelativePath(const fs::path& base, const fs::path& path) { try { - const fs::path base = ActiveSettings::GetPath(); return fs::relative(path, base); } catch (const std::exception&) diff --git a/src/util/helpers/helpers.h b/src/util/helpers/helpers.h index 6240d56a..f81e5964 100644 --- a/src/util/helpers/helpers.h +++ b/src/util/helpers/helpers.h @@ -52,7 +52,7 @@ uint32_t GetPhysicalCoreCount(); // Creates a temporary file to test for write access bool TestWriteAccess(const fs::path& p); -fs::path MakeRelativePath(const fs::path& path); +fs::path MakeRelativePath(const fs::path& base, const fs::path& path); #ifdef HAS_DIRECTINPUT bool GUIDFromString(const char* string, GUID& guid); diff --git a/src/util/libusbWrapper/libusbWrapper.cpp b/src/util/libusbWrapper/libusbWrapper.cpp index e1d72985..8420216d 100644 --- a/src/util/libusbWrapper/libusbWrapper.cpp +++ b/src/util/libusbWrapper/libusbWrapper.cpp @@ -18,7 +18,7 @@ void libusbWrapper::init() m_module = LoadLibraryW(L"libusb-1.0.dll"); if (!m_module) { - const auto path = ActiveSettings::GetPath("resources/libusb-1.0.dll"); + const auto path = ActiveSettings::GetDataPath("resources/libusb-1.0.dll"); m_module = LoadLibraryW(path.generic_wstring().c_str()); if (!m_module) { From 8b3f36ad50372feb7b62e5efd70a697beed9c6eb Mon Sep 17 00:00:00 2001 From: SSimco <37044560+SSimco@users.noreply.github.com> Date: Wed, 12 Oct 2022 04:10:57 -0700 Subject: [PATCH 049/638] Use correct preprocessor check for Linux (#360) --- src/gui/CemuApp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/CemuApp.cpp b/src/gui/CemuApp.cpp index 50e9e04c..2c766f5b 100644 --- a/src/gui/CemuApp.cpp +++ b/src/gui/CemuApp.cpp @@ -81,7 +81,7 @@ bool CemuApp::OnInit() #else SetAppName("Cemu"); wxString appName=GetAppName(); - #ifdef BOOST_OS_LINUX + #if BOOST_OS_LINUX standardPaths.SetFileLayout(wxStandardPaths::FileLayout::FileLayout_XDG); auto getEnvDir = [&](const wxString& varName, const wxString& defaultValue) { From f65dbe84372c2f50eb236a366d2cfe13409b1857 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Wed, 12 Oct 2022 14:18:24 +0200 Subject: [PATCH 050/638] Fix encoding error in input profile filenames - Controller profile filenames now encode unicode characters correctly - Removed dependency on boost::filesystem. There is still an indirect dependency on it from another boost module it seems - Refactored some code to use FileStream instead of ifstream/ofstream --- src/Cafe/GameProfile/GameProfile.cpp | 11 ++------ src/Common/precompiled.h | 1 - src/input/InputManager.cpp | 41 +++++++++++++++------------- src/util/helpers/helpers.h | 20 ++++++++++++++ 4 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/Cafe/GameProfile/GameProfile.cpp b/src/Cafe/GameProfile/GameProfile.cpp index d8c735ce..a1184362 100644 --- a/src/Cafe/GameProfile/GameProfile.cpp +++ b/src/Cafe/GameProfile/GameProfile.cpp @@ -277,10 +277,8 @@ bool GameProfile::Load(uint64_t title_id) void GameProfile::Save(uint64_t title_id) { auto gameProfileDir = ActiveSettings::GetConfigPath("gameProfiles"); - if (std::error_code ex_ec; !fs::exists(gameProfileDir, ex_ec) && !ex_ec) { - std::error_code cr_ec; - fs::create_directories(gameProfileDir, cr_ec); - } + if (std::error_code ex_ec; !fs::exists(gameProfileDir, ex_ec)) + fs::create_directories(gameProfileDir, ex_ec); auto gameProfilePath = gameProfileDir / fmt::format("{:016x}.ini", title_id); FileStream* fs = FileStream::createFile2(gameProfilePath); if (!fs) @@ -309,16 +307,11 @@ void GameProfile::Save(uint64_t title_id) fs->writeLine(""); fs->writeLine("[Graphics]"); - //WRITE_OPTIONAL_ENTRY(gpuBufferCacheAccuracy); WRITE_ENTRY(accurateShaderMul); WRITE_OPTIONAL_ENTRY(precompiledShaders); WRITE_OPTIONAL_ENTRY(graphics_api); fs->writeLine(""); - /*stream_writeLine(stream_gameProfile, "[Audio]"); - WRITE_ENTRY(disableAudio); - stream_writeLine(stream_gameProfile, "");*/ - fs->writeLine("[Controller]"); for (int i = 0; i < 8; ++i) { diff --git a/src/Common/precompiled.h b/src/Common/precompiled.h index bd956657..898a6883 100644 --- a/src/Common/precompiled.h +++ b/src/Common/precompiled.h @@ -69,7 +69,6 @@ #include #include #include -#include #include #include diff --git a/src/input/InputManager.cpp b/src/input/InputManager.cpp index 0861ba28..5d775c74 100644 --- a/src/input/InputManager.cpp +++ b/src/input/InputManager.cpp @@ -92,12 +92,12 @@ bool InputManager::load(size_t player_index, std::string_view filename) try { - std::ifstream file(file_path); - if (!file.is_open()) + auto xmlData = FileStream::LoadIntoMemory(file_path); + if (!xmlData || xmlData->empty()) return false; - + pugi::xml_document doc; - if (!doc.load(file)) + if (!doc.load_buffer(xmlData->data(), xmlData->size())) return false; const pugi::xml_node root = doc.document_element(); @@ -216,12 +216,15 @@ bool InputManager::migrate_config(const fs::path& file_path) { try { - std::ifstream file(file_path); - if (!file.is_open()) + auto xmlData = FileStream::LoadIntoMemory(file_path); + if (!xmlData || xmlData->empty()) return false; + std::string iniDataStr((const char*)xmlData->data(), xmlData->size()); + + std::stringstream iniData(iniDataStr); boost::property_tree::ptree m_data; - read_ini(file, m_data); + read_ini(iniData, m_data); const auto emulate_string = m_data.get("General.emulate"); const auto api_string = m_data.get("General.api"); @@ -455,7 +458,7 @@ bool InputManager::save(size_t player_index, std::string_view filename) if (is_default_file) file_path /= fmt::format("controller{}", player_index); else - file_path /= filename; + file_path /= _utf8ToPath(filename); file_path.replace_extension(".xml"); // force .xml extension @@ -540,15 +543,15 @@ bool InputManager::save(size_t player_index, std::string_view filename) } } } - - - std::ofstream file(file_path, std::ios::out | std::ios::trunc); - if (file.is_open()) - { - doc.save(file); - return true; - } - return false; + FileStream* fs = FileStream::createFile2(file_path); + if (!fs) + return false; + std::stringstream xmlData; + doc.save(xmlData); + std::string xmlStr = xmlData.str(); + fs->writeData(xmlStr.data(), xmlStr.size()); + delete fs; + return true; } bool InputManager::is_gameprofile_set(size_t player_index) const @@ -792,7 +795,7 @@ std::vector InputManager::get_profiles() const auto& p = entry.path(); if (p.has_extension() && (p.extension() == ".xml" || p.extension() == ".txt")) { - auto stem = p.filename().stem().string(); + auto stem = _pathToUtf8(p.filename().stem()); if (is_valid_profilename(stem)) { tmp.emplace(stem); @@ -808,7 +811,7 @@ std::vector InputManager::get_profiles() bool InputManager::is_valid_profilename(const std::string& name) { - if (!boost::filesystem::windows_name(name)) + if (!IsValidFilename(name)) return false; // dont allow default profile names diff --git a/src/util/helpers/helpers.h b/src/util/helpers/helpers.h index f81e5964..09b80fed 100644 --- a/src/util/helpers/helpers.h +++ b/src/util/helpers/helpers.h @@ -231,6 +231,26 @@ inline uint64 MakeU64(uint32 high, uint32 low) return ((uint64)high << 32) | ((uint64)low); } +static bool IsValidFilename(std::string_view sv) +{ + for (auto& it : sv) + { + uint8 c = (uint8)it; + if (c < 0x20) + return false; + if (c == '.' || c == '#' || c == '/' || c == '\\' || + c == '<' || c == '>' || c == '|' || c == ':' || + c == '\"') + return false; + } + if (!sv.empty()) + { + if (sv.back() == ' ' || sv.back() == '.') + return false; + } + return true; +} + // MAJOR; MINOR std::pair GetWindowsVersion(); bool IsWindows81OrGreater(); From 0412dec07852837b37c658e6b8240be1415a84fd Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Wed, 12 Oct 2022 15:23:04 +0200 Subject: [PATCH 051/638] Fix metainfo Comment out vcs-browser url type for now. It's a pretty recent addition to the standard and is considered an error by some older utilities --- dist/linux/info.cemu.Cemu.metainfo.xml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dist/linux/info.cemu.Cemu.metainfo.xml b/dist/linux/info.cemu.Cemu.metainfo.xml index d270a8ab..b93e572f 100644 --- a/dist/linux/info.cemu.Cemu.metainfo.xml +++ b/dist/linux/info.cemu.Cemu.metainfo.xml @@ -60,14 +60,11 @@ https://github.com/cemu-project/Cemu/issues https://cemu.info/faq.html https://wiki.cemu.info - https://github.com/cemu-project/Cemu + Game Emulator - - 4096 - 8192 From d251ce07e0cbbe8a85a4013fbfb15efa0f422b76 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Thu, 13 Oct 2022 12:18:34 +0200 Subject: [PATCH 052/638] XAudio2: Don't quit on failed CoInitializeEx() It returns an error code when already initialized --- src/audio/XAudio2API.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/audio/XAudio2API.cpp b/src/audio/XAudio2API.cpp index 795a0ebe..fd0a305b 100644 --- a/src/audio/XAudio2API.cpp +++ b/src/audio/XAudio2API.cpp @@ -187,7 +187,8 @@ const std::vector& XAudio2API::RefreshDevices( // this function must be called from the same thread as we called CoInitializeEx s_devices.clear(); - if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE))) + HRESULT r = CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE); + if (r != RPC_E_CHANGED_MODE && FAILED(r)) return s_devices; try From a19ed46b2a55dc93e5792c84e57a7c45b89f97a0 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Fri, 14 Oct 2022 12:49:41 +0200 Subject: [PATCH 053/638] Windows: Fix file and folder dialog freeze (#369) Initializing the COM library immediately seems to be more robust than doing it on demand --- src/audio/CubebAPI.cpp | 18 ------------------ src/audio/CubebAPI.h | 1 - src/audio/XAudio27API.cpp | 9 --------- src/audio/XAudio27API.h | 1 - src/audio/XAudio2API.cpp | 14 -------------- src/audio/XAudio2API.h | 1 - src/main.cpp | 10 +++++++--- 7 files changed, 7 insertions(+), 47 deletions(-) diff --git a/src/audio/CubebAPI.cpp b/src/audio/CubebAPI.cpp index c40e0f55..8b2a235f 100644 --- a/src/audio/CubebAPI.cpp +++ b/src/audio/CubebAPI.cpp @@ -167,25 +167,11 @@ void CubebAPI::SetVolume(sint32 volume) bool CubebAPI::InitializeStatic() { -#if BOOST_OS_WINDOWS - s_com_initialized = (SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))); -#endif - if (cubeb_init(&s_context, "Cemu Cubeb", nullptr)) { cemuLog_force("can't create cubeb audio api"); - -#if BOOST_OS_WINDOWS - if (s_com_initialized) - { - CoUninitialize(); - s_com_initialized = false; - } -#endif - return false; } - return true; } @@ -193,10 +179,6 @@ void CubebAPI::Destroy() { if (s_context) cubeb_destroy(s_context); -#if BOOST_OS_WINDOWS - if (s_com_initialized) - CoUninitialize(); -#endif } std::vector CubebAPI::GetDevices() diff --git a/src/audio/CubebAPI.h b/src/audio/CubebAPI.h index a828ce0d..2dce9374 100644 --- a/src/audio/CubebAPI.h +++ b/src/audio/CubebAPI.h @@ -41,7 +41,6 @@ public: static void Destroy(); private: - inline static bool s_com_initialized = false; inline static cubeb* s_context = nullptr; cubeb_stream* m_stream = nullptr; diff --git a/src/audio/XAudio27API.cpp b/src/audio/XAudio27API.cpp index 4a99bfa2..fadd02f8 100644 --- a/src/audio/XAudio27API.cpp +++ b/src/audio/XAudio27API.cpp @@ -5,7 +5,6 @@ static_assert(IAudioAPI::kBlockCount < XAUDIO2_MAX_QUEUED_BUFFERS, "too many xaudio2 buffers"); HMODULE XAudio27API::s_xaudio_dll = nullptr; -bool XAudio27API::s_com_initialized = false; std::unique_ptr XAudio27API::s_xaudio; XAudio27API::XAudio27API(uint32 device_id, uint32 samplerate, uint32 channels, uint32 samples_per_block, uint32 bits_per_sample) @@ -115,8 +114,6 @@ bool XAudio27API::InitializeStatic() if (s_xaudio) return true; - s_com_initialized = (SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE))); - #ifdef _DEBUG s_xaudio_dll = LoadLibraryExW(L"XAudioD2_7.DLL", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); if(!s_xaudio_dll) @@ -142,9 +139,6 @@ bool XAudio27API::InitializeStatic() if (s_xaudio_dll) FreeLibrary(s_xaudio_dll); - if (s_com_initialized) - CoUninitialize(); - return false; } } @@ -155,9 +149,6 @@ void XAudio27API::Destroy() if (s_xaudio_dll) FreeLibrary(s_xaudio_dll); - - if (s_com_initialized) - CoUninitialize(); } std::vector XAudio27API::GetDevices() diff --git a/src/audio/XAudio27API.h b/src/audio/XAudio27API.h index 80e423a3..badab8f6 100644 --- a/src/audio/XAudio27API.h +++ b/src/audio/XAudio27API.h @@ -58,7 +58,6 @@ private: }; static HMODULE s_xaudio_dll; - static bool s_com_initialized; static std::unique_ptr s_xaudio; std::unique_ptr m_xaudio; diff --git a/src/audio/XAudio2API.cpp b/src/audio/XAudio2API.cpp index fd0a305b..9759210d 100644 --- a/src/audio/XAudio2API.cpp +++ b/src/audio/XAudio2API.cpp @@ -23,7 +23,6 @@ static const GUID DEVINTERFACE_AUDIO_RENDER_GUID = { 0xe6327cad, 0xdcec, 0x4949, static_assert(IAudioAPI::kBlockCount < XAUDIO2_MAX_QUEUED_BUFFERS, "too many xaudio2 buffers"); HMODULE XAudio2API::s_xaudio_dll = nullptr; -bool XAudio2API::s_com_initialized = false; std::vector XAudio2API::s_devices; XAudio2API::XAudio2API(std::wstring device_id, uint32 samplerate, uint32 channels, uint32 samples_per_block, uint32 bits_per_sample) @@ -143,8 +142,6 @@ bool XAudio2API::InitializeStatic() { if (s_xaudio_dll) return true; - - s_com_initialized = (SUCCEEDED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))); // win 10 s_xaudio_dll = LoadLibraryEx(XAUDIO2_DLL, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); @@ -166,9 +163,6 @@ bool XAudio2API::InitializeStatic() if (s_xaudio_dll) FreeLibrary(s_xaudio_dll); - if (s_com_initialized) - CoUninitialize(); - return false; } } @@ -177,20 +171,12 @@ void XAudio2API::Destroy() { if (s_xaudio_dll) FreeLibrary(s_xaudio_dll); - - if (s_com_initialized) - CoUninitialize(); } const std::vector& XAudio2API::RefreshDevices() { - // this function must be called from the same thread as we called CoInitializeEx s_devices.clear(); - HRESULT r = CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE); - if (r != RPC_E_CHANGED_MODE && FAILED(r)) - return s_devices; - try { struct IWbemLocator *wbem_locator = nullptr; diff --git a/src/audio/XAudio2API.h b/src/audio/XAudio2API.h index 2b23e1cc..1f7057f0 100644 --- a/src/audio/XAudio2API.h +++ b/src/audio/XAudio2API.h @@ -59,7 +59,6 @@ private: }; static HMODULE s_xaudio_dll; - static bool s_com_initialized; static std::vector s_devices; std::unique_ptr m_xaudio; diff --git a/src/main.cpp b/src/main.cpp index e1c8ca49..323494c1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -323,10 +323,10 @@ void HandlePostUpdate() fs::remove(filename, ec); } #else - while( fs::exists(filename) ) + while (fs::exists(filename)) { std::error_code ec; - fs::remove(filename, ec); + fs::remove(filename, ec); std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } #endif @@ -338,8 +338,10 @@ void ToolShaderCacheMerger(); #if BOOST_OS_WINDOWS // entrypoint for release builds -int wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nShowCmd) +int wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nShowCmd) { + if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE))) + cemuLog_log(LogType::Force, "CoInitializeEx() failed"); SDL_SetMainReady(); if (!LaunchSettings::HandleCommandline(lpCmdLine)) return 0; @@ -350,6 +352,8 @@ int wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ L // entrypoint for debug builds with console int main(int argc, char* argv[]) { + if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE))) + cemuLog_log(LogType::Force, "CoInitializeEx() failed"); SDL_SetMainReady(); if (!LaunchSettings::HandleCommandline(argc, argv)) return 0; From ada8bbb3b49622e19deccb7358b1c804a766baab Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Fri, 14 Oct 2022 13:45:40 +0200 Subject: [PATCH 054/638] Linux/MacOS: Greatly improve performance (#370) std::unordered_set is implemented as a flat hashtable on libstdc++ which makes clearing expensive due to invoking memset on the entire table. To get the best performance across all platforms this replaces the unordered_set with a custom high-performance sparse bitset --- src/Cafe/HW/Latte/Core/LatteBufferCache.cpp | 73 ++++++++++++++++++--- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp b/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp index a70ff888..1e2c43b1 100644 --- a/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp @@ -1005,8 +1005,67 @@ void LatteBufferCache_getStats(uint32& heapSize, uint32& allocationSize, uint32& } FSpinlock g_spinlockDCFlushQueue; -std::unordered_set* g_DCFlushQueue = new std::unordered_set(); // queued pages -std::unordered_set* g_DCFlushQueueAlternate = new std::unordered_set(); + +class SparseBitset +{ + static inline constexpr size_t TABLE_MASK = 0xFF; + +public: + bool Empty() const + { + return m_numNonEmptyVectors == 0; + } + + void Set(uint32 index) + { + auto& v = m_bits[index & TABLE_MASK]; + if (std::find(v.cbegin(), v.cend(), index) != v.end()) + return; + if (v.empty()) + { + m_nonEmptyVectors[m_numNonEmptyVectors] = &v; + m_numNonEmptyVectors++; + } + v.emplace_back(index); + } + + template + void ForAllAndClear(TFunc callbackFunc) + { + auto vCurrent = m_nonEmptyVectors + 0; + auto vEnd = m_nonEmptyVectors + m_numNonEmptyVectors; + while (vCurrent < vEnd) + { + std::vector* vec = *vCurrent; + vCurrent++; + for (const auto& it : *vec) + callbackFunc(it); + vec->clear(); + } + m_numNonEmptyVectors = 0; + } + + void Clear() + { + auto vCurrent = m_nonEmptyVectors + 0; + auto vEnd = m_nonEmptyVectors + m_numNonEmptyVectors; + while (vCurrent < vEnd) + { + std::vector* vec = *vCurrent; + vCurrent++; + vec->clear(); + } + m_numNonEmptyVectors = 0; + } + +private: + std::vector m_bits[TABLE_MASK + 1]; + std::vector* m_nonEmptyVectors[TABLE_MASK + 1]; + size_t m_numNonEmptyVectors{ 0 }; +}; + +SparseBitset* s_DCFlushQueue = new SparseBitset(); +SparseBitset* s_DCFlushQueueAlternate = new SparseBitset(); void LatteBufferCache_notifyDCFlush(MPTR address, uint32 size) { @@ -1017,20 +1076,18 @@ void LatteBufferCache_notifyDCFlush(MPTR address, uint32 size) uint32 lastPage = (address + size - 1) / CACHE_PAGE_SIZE; g_spinlockDCFlushQueue.acquire(); for (uint32 i = firstPage; i <= lastPage; i++) - g_DCFlushQueue->emplace(i); + s_DCFlushQueue->Set(i); g_spinlockDCFlushQueue.release(); } void LatteBufferCache_processDCFlushQueue() { - if (g_DCFlushQueue->empty()) // accessing this outside of the lock is technically undefined/unsafe behavior but on all known implementations this is fine and we can avoid the spinlock + if (s_DCFlushQueue->Empty()) // quick check to avoid locking if there is no work to do return; g_spinlockDCFlushQueue.acquire(); - std::swap(g_DCFlushQueue, g_DCFlushQueueAlternate); + std::swap(s_DCFlushQueue, s_DCFlushQueueAlternate); g_spinlockDCFlushQueue.release(); - for (auto& itr : *g_DCFlushQueueAlternate) - LatteBufferCache_invalidatePage(itr * CACHE_PAGE_SIZE); - g_DCFlushQueueAlternate->clear(); + s_DCFlushQueueAlternate->ForAllAndClear([](uint32 index) {LatteBufferCache_invalidatePage(index * CACHE_PAGE_SIZE); }); } void LatteBufferCache_notifyDrawDone() From df0e2f78818d662b90839fa46c7441777f07003c Mon Sep 17 00:00:00 2001 From: Tillsunset <35825944+Tillsunset@users.noreply.github.com> Date: Sat, 15 Oct 2022 00:20:20 -0500 Subject: [PATCH 055/638] Fix Cannot set locale to "" (#366) * Add en resource and change language selection for macos user that don't have US as their system region * default to English if the system language is unavailable --- bin/resources/en/cemu.mo | Bin 0 -> 56624 bytes src/gui/CemuApp.cpp | 20 +++++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) create mode 100644 bin/resources/en/cemu.mo diff --git a/bin/resources/en/cemu.mo b/bin/resources/en/cemu.mo new file mode 100644 index 0000000000000000000000000000000000000000..93d8f7e59bd0864234171af1e3ba46ba15c562c8 GIT binary patch literal 56624 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 literal 0 HcmV?d00001 diff --git a/src/gui/CemuApp.cpp b/src/gui/CemuApp.cpp index 2c766f5b..c7a5adaa 100644 --- a/src/gui/CemuApp.cpp +++ b/src/gui/CemuApp.cpp @@ -115,22 +115,24 @@ bool CemuApp::OnInit() m_languages = GetAvailableLanguages(); const sint32 language = GetConfig().language; - if (language != wxLANGUAGE_ENGLISH) + const auto it = std::find_if(m_languages.begin(), m_languages.end(), [language](const wxLanguageInfo* info) { return info->Language == language; }); + if (it != m_languages.end() && wxLocale::IsAvailable(language)) { - const auto it = std::find_if(m_languages.begin(), m_languages.end(), [language](const wxLanguageInfo* info) { return info->Language == language; }); - if (it != m_languages.end() && wxLocale::IsAvailable(language)) + if (m_locale.Init(language)) { - if (m_locale.Init(language)) - { - m_locale.AddCatalogLookupPathPrefix(ActiveSettings::GetDataPath("resources").generic_string()); - m_locale.AddCatalog("cemu"); - } + m_locale.AddCatalogLookupPathPrefix(ActiveSettings::GetDataPath("resources").generic_string()); + m_locale.AddCatalog("cemu"); } } if (!m_locale.IsOk()) { - m_locale.Init(wxLANGUAGE_DEFAULT); + if (!wxLocale::IsAvailable(wxLANGUAGE_DEFAULT) || !m_locale.Init(wxLANGUAGE_DEFAULT)) + { + m_locale.Init(wxLANGUAGE_ENGLISH); + m_locale.AddCatalogLookupPathPrefix(ActiveSettings::GetDataPath("resources").generic_string()); + m_locale.AddCatalog("cemu"); + } } // fill colour db From f0938e1a23f6cdd03bfd1e21d84f2c0f65aeb45f Mon Sep 17 00:00:00 2001 From: Tillsunset <35825944+Tillsunset@users.noreply.github.com> Date: Sat, 15 Oct 2022 06:38:06 -0500 Subject: [PATCH 056/638] Fix CRC errors on MacOS(/Linux?) (#375) Fixes graphic packs (like FPS++) not working even when enabled. --- src/util/crypto/crc32.cpp | 51 +++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/util/crypto/crc32.cpp b/src/util/crypto/crc32.cpp index f6e88165..65c6a8f8 100644 --- a/src/util/crypto/crc32.cpp +++ b/src/util/crypto/crc32.cpp @@ -322,29 +322,34 @@ unsigned int crc32_calc_slice_by_8(unsigned int previousCrc32, const void* data, // process eight bytes at once (Slicing-by-8) while (length >= 8) { -#if __BYTE_ORDER == __BIG_ENDIAN - uint32_t one = *current++ ^ swap(crc); - uint32_t two = *current++; - crc = Crc32Lookup[0][two & 0xFF] ^ - Crc32Lookup[1][(two >> 8) & 0xFF] ^ - Crc32Lookup[2][(two >> 16) & 0xFF] ^ - Crc32Lookup[3][(two >> 24) & 0xFF] ^ - Crc32Lookup[4][one & 0xFF] ^ - Crc32Lookup[5][(one >> 8) & 0xFF] ^ - Crc32Lookup[6][(one >> 16) & 0xFF] ^ - Crc32Lookup[7][(one >> 24) & 0xFF]; -#else - uint32_t one = *current++ ^ crc; - uint32_t two = *current++; - crc = Crc32Lookup[0][(two >> 24) & 0xFF] ^ - Crc32Lookup[1][(two >> 16) & 0xFF] ^ - Crc32Lookup[2][(two >> 8) & 0xFF] ^ - Crc32Lookup[3][two & 0xFF] ^ - Crc32Lookup[4][(one >> 24) & 0xFF] ^ - Crc32Lookup[5][(one >> 16) & 0xFF] ^ - Crc32Lookup[6][(one >> 8) & 0xFF] ^ - Crc32Lookup[7][one & 0xFF]; -#endif + if constexpr (std::endian::native == std::endian::big){ + uint32_t one = *current++ ^ swap(crc); + uint32_t two = *current++; + crc = Crc32Lookup[0][two & 0xFF] ^ + Crc32Lookup[1][(two >> 8) & 0xFF] ^ + Crc32Lookup[2][(two >> 16) & 0xFF] ^ + Crc32Lookup[3][(two >> 24) & 0xFF] ^ + Crc32Lookup[4][one & 0xFF] ^ + Crc32Lookup[5][(one >> 8) & 0xFF] ^ + Crc32Lookup[6][(one >> 16) & 0xFF] ^ + Crc32Lookup[7][(one >> 24) & 0xFF]; + } + else if constexpr (std::endian::native == std::endian::little) + { + uint32_t one = *current++ ^ crc; + uint32_t two = *current++; + crc = Crc32Lookup[0][(two >> 24) & 0xFF] ^ + Crc32Lookup[1][(two >> 16) & 0xFF] ^ + Crc32Lookup[2][(two >> 8) & 0xFF] ^ + Crc32Lookup[3][two & 0xFF] ^ + Crc32Lookup[4][(one >> 24) & 0xFF] ^ + Crc32Lookup[5][(one >> 16) & 0xFF] ^ + Crc32Lookup[6][(one >> 8) & 0xFF] ^ + Crc32Lookup[7][one & 0xFF]; + } + else { + cemu_assert(false); + } length -= 8; } From e88d20cbfbada6b1d144c4944f080f70299c1506 Mon Sep 17 00:00:00 2001 From: goeiecool9999 <7033575+goeiecool9999@users.noreply.github.com> Date: Sun, 16 Oct 2022 09:02:33 +0200 Subject: [PATCH 057/638] Fix crashes when wxWidgets tries to free stack allocated dialogs (#377) --- src/gui/MainWindow.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 5ebfe09d..3291f3bb 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -763,7 +763,6 @@ void MainWindow::OpenSettings() frame.ShowModal(); const bool paths_modified = frame.ShouldReloadGamelist(); const bool mlc_modified = frame.MLCModified(); - frame.Destroy(); if (paths_modified) m_game_list->ReloadGameEntries(false); @@ -1722,7 +1721,6 @@ void MainWindow::OnTimer(wxTimerEvent& event) { CemuUpdateWindow update_window(this); update_window.ShowModal(); - update_window.Destroy(); } } @@ -1999,7 +1997,6 @@ void MainWindow::OnHelpUpdate(wxCommandEvent& event) { CemuUpdateWindow test(this); test.ShowModal(); - test.Destroy(); } void MainWindow::OnHelpGettingStarted(wxCommandEvent& event) From 753040f73a8700d53bb742d33e428e060308bb20 Mon Sep 17 00:00:00 2001 From: MythicalPlayz <57963367+MythicalPlayz@users.noreply.github.com> Date: Mon, 17 Oct 2022 11:26:32 +0200 Subject: [PATCH 058/638] Added Boot Image for Gamepad (#372) --- src/Cafe/HW/Latte/Core/LatteShaderCache.cpp | 119 +++++++++++++++++--- 1 file changed, 103 insertions(+), 16 deletions(-) diff --git a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp index ba85898c..c8299032 100644 --- a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp @@ -43,7 +43,8 @@ struct struct { - ImTextureID textureId; + ImTextureID textureTVId; + ImTextureID textureDRCId; // shader loading sint32 loadedShaderFiles; sint32 shaderFileCount; @@ -230,12 +231,12 @@ void LatteShaderCache_load() g_shaderCacheLoaderState.loadedShaderFiles = 0; // get game background loading image - TGAFILE file{}; - g_shaderCacheLoaderState.textureId = nullptr; + TGAFILE TVfile{}; + g_shaderCacheLoaderState.textureTVId = nullptr; std::string tvTexPath = fmt::format("{}/meta/bootTvTex.tga", CafeSystem::GetMlcStoragePath(CafeSystem::GetForegroundTitleId())); - sint32 status; - auto fscfile = fsc_open(tvTexPath.c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &status); + sint32 statusTV; + auto fscfile = fsc_open(tvTexPath.c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &statusTV); if (fscfile) { uint32 size = fsc_getFileSize(fscfile); @@ -243,15 +244,35 @@ void LatteShaderCache_load() { std::vector tmpData(size); fsc_readFile(fscfile, tmpData.data(), size); - const bool backgroundLoaded = LoadTGAFile(tmpData, &file); + const bool backgroundLoaded = LoadTGAFile(tmpData, &TVfile); if (backgroundLoaded) - g_shaderCacheLoaderState.textureId = g_renderer->GenerateTexture(file.imageData, { file.imageWidth, file.imageHeight }); + g_shaderCacheLoaderState.textureTVId = g_renderer->GenerateTexture(TVfile.imageData, { TVfile.imageWidth, TVfile.imageHeight }); } fsc_close(fscfile); } + //get game background loading image for DRC + TGAFILE DRCfile{}; + g_shaderCacheLoaderState.textureDRCId = nullptr; + std::string drcTexPath = fmt::format("{}/meta/bootDRCTex.tga", CafeSystem::GetMlcStoragePath(CafeSystem::GetForegroundTitleId())); + sint32 statusDRC; + auto fscfile2 = fsc_open(drcTexPath.c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &statusDRC); + if (fscfile2) + { + uint32 size = fsc_getFileSize(fscfile2); + if (size > 0) + { + std::vector tmpData(size); + fsc_readFile(fscfile2, tmpData.data(), size); + const bool backgroundLoaded = LoadTGAFile(tmpData, &DRCfile); + + if (backgroundLoaded) + g_shaderCacheLoaderState.textureDRCId = g_renderer->GenerateTexture(DRCfile.imageData, { DRCfile.imageWidth, DRCfile.imageHeight }); + } + fsc_close(fscfile2); + } sint32 numLoadedShaders = 0; uint32 loadIndex = 0; @@ -312,7 +333,7 @@ void LatteShaderCache_load() ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 0,0 }); if (ImGui::Begin("Background texture", nullptr, kPopupFlags)) { - if (g_shaderCacheLoaderState.textureId) + if (g_shaderCacheLoaderState.textureTVId) { float imageDisplayWidth = io.DisplaySize.x; float imageDisplayHeight = 720 * imageDisplayWidth / 1280; @@ -327,19 +348,54 @@ void LatteShaderCache_load() paddingTopAndBottom = 0.0f; } - ImGui::GetWindowDrawList()->AddImage(g_shaderCacheLoaderState.textureId, ImVec2(paddingLeftAndRight, paddingTopAndBottom), ImVec2(io.DisplaySize.x-paddingLeftAndRight, io.DisplaySize.y-paddingTopAndBottom), { 0,1 }, { 1,0 }); + ImGui::GetWindowDrawList()->AddImage(g_shaderCacheLoaderState.textureTVId, ImVec2(paddingLeftAndRight, paddingTopAndBottom), ImVec2(io.DisplaySize.x-paddingLeftAndRight, io.DisplaySize.y-paddingTopAndBottom), { 0,1 }, { 1,0 }); } ImGui::End(); + ImGui::PopStyleVar(2); + g_renderer->ImguiEnd(); } - ImGui::PopStyleVar(2); - - g_renderer->ImguiEnd(); } + + g_renderer->BeginFrame(false); + if (g_renderer->ImguiBegin(false)) + { + ImGui::SetNextWindowPos({ 0,0 }, ImGuiCond_Always); + ImGui::SetNextWindowSize(io.DisplaySize, ImGuiCond_Always); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 0,0 }); + + if (ImGui::Begin("Background texture2", nullptr, kPopupFlags)) + { + if (g_shaderCacheLoaderState.textureDRCId) + { + float imageDisplayWidth = io.DisplaySize.x; + float imageDisplayHeight = 480 * imageDisplayWidth / 854; + + float paddingLeftAndRight = 0.0f; + float paddingTopAndBottom = (io.DisplaySize.y - imageDisplayHeight)/2.0f; + if (imageDisplayHeight > io.DisplaySize.y) + { + imageDisplayHeight = io.DisplaySize.y; + imageDisplayWidth = 854 * imageDisplayHeight / 480; + paddingLeftAndRight = (io.DisplaySize.x - imageDisplayWidth)/2.0f; + paddingTopAndBottom = 0.0f; + } + + ImGui::GetWindowDrawList()->AddImage(g_shaderCacheLoaderState.textureDRCId, ImVec2(paddingLeftAndRight, paddingTopAndBottom), ImVec2(io.DisplaySize.x-paddingLeftAndRight, io.DisplaySize.y-paddingTopAndBottom), { 0,1 }, { 1,0 }); + } + ImGui::End(); + ImGui::PopStyleVar(2); + g_renderer->ImguiEnd(); + } + } + g_renderer->SwapBuffers(true, true); } - if (g_shaderCacheLoaderState.textureId) - g_renderer->DeleteTexture(g_shaderCacheLoaderState.textureId); + if (g_shaderCacheLoaderState.textureTVId) + g_renderer->DeleteTexture(g_shaderCacheLoaderState.textureTVId); + if (g_shaderCacheLoaderState.textureDRCId) + g_renderer->DeleteTexture(g_shaderCacheLoaderState.textureDRCId); } void LatteShaderCache_ShowProgress(const std::function & loadUpdateFunc, bool isPipelines) @@ -374,7 +430,7 @@ void LatteShaderCache_ShowProgress(const std::function & loadUpdateF const auto progress_font = ImGui_GetFont(window_size.y / 32.0f); // = 24 by default const auto shader_count_font = ImGui_GetFont(window_size.y / 48.0f); // = 16 // render background texture - if (g_shaderCacheLoaderState.textureId) + if (g_shaderCacheLoaderState.textureTVId) { ImGui::SetNextWindowPos({ 0, 0 }, ImGuiCond_Always); ImGui::SetNextWindowSize(io.DisplaySize, ImGuiCond_Always); @@ -395,7 +451,7 @@ void LatteShaderCache_ShowProgress(const std::function & loadUpdateF paddingTopAndBottom = 0.0f; } - ImGui::GetWindowDrawList()->AddImage(g_shaderCacheLoaderState.textureId, ImVec2(paddingLeftAndRight, paddingTopAndBottom), ImVec2(io.DisplaySize.x-paddingLeftAndRight, io.DisplaySize.y-paddingTopAndBottom), { 0,1 }, { 1,0 }); + ImGui::GetWindowDrawList()->AddImage(g_shaderCacheLoaderState.textureTVId, ImVec2(paddingLeftAndRight, paddingTopAndBottom), ImVec2(io.DisplaySize.x-paddingLeftAndRight, io.DisplaySize.y-paddingTopAndBottom), { 0,1 }, { 1,0 }); ImGui::End(); } ImGui::PopStyleVar(2); @@ -484,6 +540,37 @@ void LatteShaderCache_ShowProgress(const std::function & loadUpdateF lastFrameUpdate = tick_cached(); } + g_renderer->BeginFrame(false); + if (g_renderer->ImguiBegin(false)) + { + ImGui::SetNextWindowPos({ 0,0 }, ImGuiCond_Always); + ImGui::SetNextWindowSize(io.DisplaySize, ImGuiCond_Always); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 0,0 }); + if (ImGui::Begin("Background texture2", nullptr, kPopupFlags)) + { + if (g_shaderCacheLoaderState.textureDRCId) + { + float imageDisplayWidth = io.DisplaySize.x; + float imageDisplayHeight = 480 * imageDisplayWidth / 854; + + float paddingLeftAndRight = 0.0f; + float paddingTopAndBottom = (io.DisplaySize.y - imageDisplayHeight)/2.0f; + if (imageDisplayHeight > io.DisplaySize.y) + { + imageDisplayHeight = io.DisplaySize.y; + imageDisplayWidth = 854 * imageDisplayHeight / 480; + paddingLeftAndRight = (io.DisplaySize.x - imageDisplayWidth)/2.0f; + paddingTopAndBottom = 0.0f; + } + ImGui::GetWindowDrawList()->AddImage(g_shaderCacheLoaderState.textureDRCId, ImVec2(paddingLeftAndRight, paddingTopAndBottom), ImVec2(io.DisplaySize.x-paddingLeftAndRight, io.DisplaySize.y-paddingTopAndBottom), { 0,1 }, { 1,0 }); + } + ImGui::End(); + ImGui::PopStyleVar(2); + g_renderer->ImguiEnd(); + } + } + // finish frame g_renderer->SwapBuffers(true, true); } From 665a34e51847061e31398a04506dcf2f53dd15f9 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Mon, 17 Oct 2022 13:25:49 +0200 Subject: [PATCH 059/638] Linux: Always use libpng from system (#381) * Always use system libpng on Linux * Remove dependency on boost-crc in DSU (reuse existing implementation) --- src/input/api/DSU/DSUMessages.cpp | 13 ++----------- src/main.cpp | 2 ++ src/util/crypto/crc32.cpp | 9 +++++++++ src/util/crypto/crc32.h | 7 ++++++- vcpkg.json | 8 +++++--- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/input/api/DSU/DSUMessages.cpp b/src/input/api/DSU/DSUMessages.cpp index d0ea61af..f92c1e3f 100644 --- a/src/input/api/DSU/DSUMessages.cpp +++ b/src/input/api/DSU/DSUMessages.cpp @@ -1,6 +1,5 @@ #include "input/api/DSU/DSUMessages.h" - -#include +#include "util/crypto/crc32.h" constexpr uint32_t kMagicClient = 'CUSD'; constexpr uint32_t kMagicServer = 'SUSD'; @@ -17,15 +16,7 @@ void MessageHeader::Finalize(size_t size) uint32_t MessageHeader::CRC32(size_t size) const { - const auto tmp = m_crc32; - m_crc32 = 0; - - boost::crc_32_type crc; - crc.process_bytes(this, size); - const auto result = crc.checksum(); - - m_crc32 = tmp; - return result; + return crc32_calc(this, size); } bool MessageHeader::IsClientMessage() const { return m_magic == kMagicClient; } diff --git a/src/main.cpp b/src/main.cpp index 323494c1..801683d1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -234,6 +234,7 @@ void ppcAsmTest(); void gx2CopySurfaceTest(); void ExpressionParser_test(); void FSTVolumeTest(); +void CRCTest(); void unitTests() { @@ -241,6 +242,7 @@ void unitTests() gx2CopySurfaceTest(); ppcAsmTest(); FSTVolumeTest(); + CRCTest(); } int mainEmulatorHLE() diff --git a/src/util/crypto/crc32.cpp b/src/util/crypto/crc32.cpp index 65c6a8f8..52eb8a88 100644 --- a/src/util/crypto/crc32.cpp +++ b/src/util/crypto/crc32.cpp @@ -382,4 +382,13 @@ unsigned int crc32_calc(unsigned int c, const void* data, int length) p++; } return ~c; +} + +void CRCTest() +{ + std::vector testData; + for (uint8 i = 0; i < 89; i++) + testData.emplace_back(i); + uint32 r = crc32_calc(0, testData.data(), testData.size()); + cemu_assert(r == 0x3fc61683); } \ No newline at end of file diff --git a/src/util/crypto/crc32.h b/src/util/crypto/crc32.h index 6a254433..b8002261 100644 --- a/src/util/crypto/crc32.h +++ b/src/util/crypto/crc32.h @@ -1,3 +1,8 @@ #pragma once -unsigned int crc32_calc(unsigned int c, const void* data, int length); \ No newline at end of file +unsigned int crc32_calc(unsigned int c, const void* data, int length); + +inline unsigned int crc32_calc(const void* data, int length) +{ + return crc32_calc(0, data, length); +} \ No newline at end of file diff --git a/vcpkg.json b/vcpkg.json index 33587607..e85a4311 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -5,8 +5,11 @@ "dependencies": [ "pugixml", "zlib", - "libpng", - "zstd", + "zstd", + { + "name": "libpng", + "platform": "!linux" + }, { "name": "libzip", "default-features": false @@ -23,7 +26,6 @@ "boost-dll", "boost-optional", "boost-signals2", - "boost-crc", "boost-asio", "boost-ptr-container", "boost-property-tree", From 15b3a3f77d8c0c6e3a95061ff337d61b198ff665 Mon Sep 17 00:00:00 2001 From: goeiecool9999 <7033575+goeiecool9999@users.noreply.github.com> Date: Mon, 17 Oct 2022 16:05:35 +0200 Subject: [PATCH 060/638] Linux: Remove libpng dependency from wxwidgets (#382) --- dependencies/vcpkg_overlay_ports/wxwidgets/vcpkg.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dependencies/vcpkg_overlay_ports/wxwidgets/vcpkg.json b/dependencies/vcpkg_overlay_ports/wxwidgets/vcpkg.json index 3f04aece..95b2eea5 100644 --- a/dependencies/vcpkg_overlay_ports/wxwidgets/vcpkg.json +++ b/dependencies/vcpkg_overlay_ports/wxwidgets/vcpkg.json @@ -17,7 +17,10 @@ "platform": "!windows & !osx" }, "expat", - "libpng", + { + "name": "libpng", + "platform": "!linux" + }, "tiff", { "name": "vcpkg-cmake", From 271a4e4719463ece58db74b9c390f83bf6e956cf Mon Sep 17 00:00:00 2001 From: MythicalPlayz <57963367+MythicalPlayz@users.noreply.github.com> Date: Tue, 18 Oct 2022 17:08:09 +0200 Subject: [PATCH 061/638] Fixed Discord Rich Presence not working on games that are on MLC (#383) --- src/Cafe/CafeSystem.cpp | 5 ++- src/gui/MainWindow.cpp | 76 +---------------------------------------- src/gui/MainWindow.h | 1 - 3 files changed, 3 insertions(+), 79 deletions(-) diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index e2e1c5ef..acfd1d2f 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -704,9 +704,8 @@ namespace CafeSystem std::string GetForegroundTitleName() { if (sLaunchModeIsStandalone) - return "Missing meta data"; - // todo - use language based on Cemu console language - return sGameInfo_ForegroundTitle.GetBase().GetMetaInfo()->GetShortName(CafeConsoleLanguage::EN); + return "Unknown Game"; + return sGameInfo_ForegroundTitle.GetBase().GetMetaInfo()->GetShortName(GetConfig().console_language); } std::string GetForegroundTitleArgStr() diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 3291f3bb..fb18a7de 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -543,8 +543,7 @@ bool MainWindow::FileLoad(std::wstring fileName, wxLaunchGameEvent::INITIATED_BY m_game_list = nullptr; } - const auto game_name = GetGameName(fileName); - m_launched_game_name = boost::nowide::narrow(game_name); + m_launched_game_name = CafeSystem::GetForegroundTitleName(); #ifdef ENABLE_DISCORD_RPC if (m_discord) m_discord->UpdatePresence(DiscordPresence::Playing, m_launched_game_name); @@ -1496,79 +1495,6 @@ void MainWindow::DestroyCanvas() } } - -std::wstring MainWindow::GetGameName(std::wstring_view file_name) -{ - fs::path path{ std::wstring{file_name} }; - const auto extension = path.extension(); - if (extension == ".wud" || extension == ".wux") - { - std::unique_ptr volume(FSTVolume::OpenFromDiscImage(path)); - if (!volume) - return path.filename().generic_wstring(); - - bool foundFile = false; - std::vector metaContent = volume->ExtractFile("meta/meta.xml", &foundFile); - if (!foundFile) - return path.filename().generic_wstring(); - - namespace xml = tinyxml2; - xml::XMLDocument doc; - doc.Parse((const char*)metaContent.data(), metaContent.size()); - - // parse meta.xml - xml::XMLElement* root = doc.FirstChildElement("menu"); - if (root) - { - xml::XMLElement* element = root->FirstChildElement("longname_en"); - if (element) - { - - auto game_name = boost::nowide::widen(element->GetText()); - const auto it = game_name.find(L'\n'); - if (it != std::wstring::npos) - game_name.replace(it, 1, L" - "); - - return game_name; - } - } - return path.filename().generic_wstring(); - } - else if (extension == ".rpx") - { - if (path.has_parent_path() && path.parent_path().has_parent_path()) - { - auto meta_xml = path.parent_path().parent_path() / "meta/meta.xml"; - auto metaXmlData = FileStream::LoadIntoMemory(meta_xml); - if (metaXmlData) - { - namespace xml = tinyxml2; - xml::XMLDocument doc; - if (doc.Parse((const char*)metaXmlData->data(), metaXmlData->size()) == xml::XML_SUCCESS) - { - xml::XMLElement* root = doc.FirstChildElement("menu"); - if (root) - { - xml::XMLElement* element = root->FirstChildElement("longname_en"); - if (element) - { - - auto game_name = boost::nowide::widen(element->GetText()); - const auto it = game_name.find(L'\n'); - if (it != std::wstring::npos) - game_name.replace(it, 1, L" - "); - - return game_name; - } - } - } - } - } - } - - return path.filename().generic_wstring(); -} - void MainWindow::OnSizeEvent(wxSizeEvent& event) { if (!IsMaximized() && !gui_isFullScreen()) diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index bcf1212d..faf83a99 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -130,7 +130,6 @@ public: void CreateCanvas(); void DestroyCanvas(); - std::wstring GetGameName(std::wstring_view file_name); static void ShowCursor(bool state); uintptr_t GetRenderCanvasHWND(); From 9df1325d146a601233c3549c8949d3e1349b6afe Mon Sep 17 00:00:00 2001 From: goeiecool9999 <7033575+goeiecool9999@users.noreply.github.com> Date: Thu, 20 Oct 2022 13:12:16 +0200 Subject: [PATCH 062/638] Linux: Resolve backtrace symbols directly from .symtab instead of .dynsym (#385) --- src/CMakeLists.txt | 4 - src/Common/CMakeLists.txt | 7 ++ .../ExceptionHandler/ELFSymbolTable.cpp | 108 ++++++++++++++++++ src/Common/ExceptionHandler/ELFSymbolTable.h | 32 ++++++ .../ExceptionHandler_posix.cpp | 47 ++++++-- 5 files changed, 182 insertions(+), 16 deletions(-) create mode 100644 src/Common/ExceptionHandler/ELFSymbolTable.cpp create mode 100644 src/Common/ExceptionHandler/ELFSymbolTable.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 32d6fe60..024432d0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -35,10 +35,6 @@ elseif(UNIX) add_compile_options(-Wno-ambiguous-reversed-operator) endif() - if(NOT APPLE) - add_link_options(-rdynamic) - endif() - add_compile_options(-Wno-multichar -Wno-invalid-offsetof -Wno-switch -Wno-ignored-attributes -Wno-deprecated-enum-enum-conversion) endif() diff --git a/src/Common/CMakeLists.txt b/src/Common/CMakeLists.txt index ca7ea238..7e5825f1 100644 --- a/src/Common/CMakeLists.txt +++ b/src/Common/CMakeLists.txt @@ -43,6 +43,13 @@ PRIVATE ) endif() +if(UNIX AND NOT APPLE) + target_sources(CemuCommon PRIVATE + ExceptionHandler/ELFSymbolTable.cpp + ExceptionHandler/ELFSymbolTable.h + ) +endif() + # All the targets wanting to use the precompiled.h header # have to link to CemuCommon target_precompile_headers(CemuCommon PUBLIC precompiled.h) diff --git a/src/Common/ExceptionHandler/ELFSymbolTable.cpp b/src/Common/ExceptionHandler/ELFSymbolTable.cpp new file mode 100644 index 00000000..0f297bdd --- /dev/null +++ b/src/Common/ExceptionHandler/ELFSymbolTable.cpp @@ -0,0 +1,108 @@ +#include "Common/ExceptionHandler/ELFSymbolTable.h" +#include "Common/FileStream.h" +#include +#include + +uint16 ELFSymbolTable::FindSection(int type, const std::string_view& name) +{ + if (!shTable || !shStrTable) + return 0; + + for (uint16 i = 0; i < header->e_shnum; ++i) + { + auto& entry = shTable[i]; + if(entry.sh_type == type && std::string_view{&shStrTable[entry.sh_name]} == name) + { + return i; + } + } + return 0; +} + +void* ELFSymbolTable::SectionPointer(uint16 index) +{ + return SectionPointer(shTable[index]); +} + +void* ELFSymbolTable::SectionPointer(const Elf64_Shdr& section) +{ + return (void*)(mappedExecutable + section.sh_offset); +} + +ELFSymbolTable::ELFSymbolTable() +{ + // create file handle + int fd = open("/proc/self/exe", O_RDONLY); + if (!fd) + return; + + // retrieve file size. + struct stat filestats; + if (fstat(fd, &filestats)) + { + close(fd); + return; + } + mappedExecutableSize = filestats.st_size; + + // attempt to map the file + mappedExecutable = (uint8*)(mmap(nullptr, mappedExecutableSize, PROT_READ, MAP_PRIVATE, fd, 0)); + close(fd); + if (!mappedExecutable) + return; + + // verify signature + header = (Elf64_Ehdr*)(mappedExecutable); + constexpr uint8 signature[] = {0x7f, 0x45, 0x4c, 0x46}; + for (size_t i = 0; i < 4; ++i) + { + if (signature[i] != header->e_ident[i]) + { + return; + } + } + + shTable = (Elf64_Shdr*)(mappedExecutable + header->e_shoff); + + Elf64_Shdr& shStrn = shTable[header->e_shstrndx]; + shStrTable = (char*)(mappedExecutable + shStrn.sh_offset); + + strTable = (char*)SectionPointer(FindSection(SHT_STRTAB, ".strtab")); + + Elf64_Shdr& symTabShdr = shTable[FindSection(SHT_SYMTAB, ".symtab")]; + if (symTabShdr.sh_entsize == 0) + return; + + symTableLen = symTabShdr.sh_size / symTabShdr.sh_entsize; + symTable = (Elf64_Sym*)(SectionPointer(symTabShdr)); +} + +ELFSymbolTable::~ELFSymbolTable() +{ + if (mappedExecutable) + munmap(mappedExecutable, mappedExecutableSize); +} + +std::string_view ELFSymbolTable::OffsetToSymbol(uint64 ptr, uint64& fromStart) const +{ + if(!symTable || !strTable) + { + fromStart = -1; + return {}; + } + + for (auto entry = symTable+1; entry < symTable+symTableLen; ++entry) + { + if (ELF64_ST_TYPE(entry->st_info) != STT_FUNC) + continue; + auto begin = entry->st_value; + auto size = entry->st_size; + if(ptr >= begin && ptr < begin+size) + { + fromStart = ptr-begin; + return &strTable[entry->st_name]; + } + } + fromStart = -1; + return {}; +} diff --git a/src/Common/ExceptionHandler/ELFSymbolTable.h b/src/Common/ExceptionHandler/ELFSymbolTable.h new file mode 100644 index 00000000..89248bbb --- /dev/null +++ b/src/Common/ExceptionHandler/ELFSymbolTable.h @@ -0,0 +1,32 @@ +#pragma once +#include +#include + +class ELFSymbolTable +{ +public: + std::string_view OffsetToSymbol(uint64 ptr, uint64& fromStart) const; + + ELFSymbolTable(); + ~ELFSymbolTable(); +private: + uint8* mappedExecutable = nullptr; + size_t mappedExecutableSize = 0; + + Elf64_Ehdr* header = nullptr; + + Elf64_Shdr* shTable = nullptr; + char* shStrTable = nullptr; + + Elf64_Sym* symTable = nullptr; + uint64 symTableLen = 0; + char* strTable = nullptr; + + uint16 FindSection(int type, const std::string_view& name); + + void* SectionPointer (uint16 index); + void* SectionPointer(const Elf64_Shdr& section); + + // ownership of mapped memory, cannot copy. + ELFSymbolTable(const ELFSymbolTable&) = delete; +}; diff --git a/src/Common/ExceptionHandler/ExceptionHandler_posix.cpp b/src/Common/ExceptionHandler/ExceptionHandler_posix.cpp index 86d83bb3..3a5620c2 100644 --- a/src/Common/ExceptionHandler/ExceptionHandler_posix.cpp +++ b/src/Common/ExceptionHandler/ExceptionHandler_posix.cpp @@ -2,41 +2,60 @@ #include #include #include - #include "config/CemuConfig.h" +#include "util/helpers/StringHelpers.h" +#if BOOST_OS_LINUX +#include "ELFSymbolTable.h" +#endif + +#if BOOST_OS_LINUX void demangleAndPrintBacktrace(char** backtrace, size_t size) { + ELFSymbolTable symTable; for (char** i = backtrace; i < backtrace + size; i++) { - std::string traceLine{*i}; + std::string_view traceLine{*i}; + + // basic check to see if the backtrace line matches expected format size_t parenthesesOpen = traceLine.find_last_of('('); size_t parenthesesClose = traceLine.find_last_of(')'); size_t offsetPlus = traceLine.find_last_of('+'); if (!parenthesesOpen || !parenthesesClose || !offsetPlus || offsetPlus < parenthesesOpen || offsetPlus > parenthesesClose) { - // something unexpected was read. fall back to default string + // fall back to default string std::cerr << traceLine << std::endl; continue; } - std::string symbolName = traceLine.substr(parenthesesOpen+1,offsetPlus-parenthesesOpen-1); - int status = -1; - char* demangled = abi::__cxa_demangle(symbolName.c_str(), nullptr, nullptr, &status); - if (demangled) + // attempt to resolve symbol from regular symbol table if missing from dynamic symbol table + uint64 newOffset = -1; + std::string_view symbolName = traceLine.substr(parenthesesOpen+1, offsetPlus-parenthesesOpen-1); + if (symbolName.empty()) { - std::cerr << traceLine.substr(0, parenthesesOpen+1); - std::cerr << demangled; - std::cerr << traceLine.substr(offsetPlus) << std::endl; - free(demangled); + uint64 symbolOffset = StringHelpers::ToInt64(traceLine.substr(offsetPlus+1,offsetPlus+1-parenthesesClose-1)); + symbolName = symTable.OffsetToSymbol(symbolOffset, newOffset); + } + + std::cerr << traceLine.substr(0, parenthesesOpen+1); + + std::cerr << boost::core::demangle(symbolName.empty() ? "" : symbolName.data()); + + // print relative or existing symbol offset. + std::cerr << '+'; + if (newOffset != -1) + { + std::cerr << std::hex << newOffset; + std::cerr << traceLine.substr(parenthesesClose) << std::endl; } else { - std::cerr << traceLine << std::endl; + std::cerr << traceLine.substr(offsetPlus+1) << std::endl; } } } +#endif // handle signals that would dump core, print stacktrace and then dump depending on config void handlerDumpingSignal(int sig) @@ -61,6 +80,7 @@ void handlerDumpingSignal(int sig) // print out all the frames to stderr fprintf(stderr, "Error: signal %d:\n", sig); +#if BOOST_OS_LINUX char** symbol_trace = backtrace_symbols(array, size); if (symbol_trace) @@ -72,6 +92,9 @@ void handlerDumpingSignal(int sig) { std::cerr << "Failed to read backtrace" << std::endl; } +#else + backtrace_symbols_fd(array, size, STDERR_FILENO); +#endif if (GetConfig().crash_dump == CrashDump::Enabled) { From dd1cb1cccf9ebc46f1b66b0a74d0e1ca86a0b99c Mon Sep 17 00:00:00 2001 From: goeiecool9999 <7033575+goeiecool9999@users.noreply.github.com> Date: Thu, 20 Oct 2022 13:18:44 +0200 Subject: [PATCH 063/638] Update title manager when clearing MLC path in settings (#319) --- src/gui/CemuApp.cpp | 28 ++++++++++++++++++++-------- src/gui/CemuApp.h | 1 + src/gui/GeneralSettings2.cpp | 17 ++++++++++------- src/util/helpers/helpers.cpp | 6 +++--- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/gui/CemuApp.cpp b/src/gui/CemuApp.cpp index c7a5adaa..c502e8d2 100644 --- a/src/gui/CemuApp.cpp +++ b/src/gui/CemuApp.cpp @@ -376,6 +376,24 @@ void CemuApp::CreateDefaultFiles(bool first_start) } +bool CemuApp::TrySelectMLCPath(std::wstring path) +{ + if (path.empty()) + path = ActiveSettings::GetDefaultMLCPath().wstring(); + + if (!TestWriteAccess(fs::path{ path })) + return false; + + GetConfig().SetMLCPath(path); + CemuApp::CreateDefaultFiles(); + + // update TitleList and SaveList scanner with new MLC path + CafeTitleList::SetMLCPath(path); + CafeTitleList::Refresh(); + CafeSaveList::SetMLCPath(path); + CafeSaveList::Refresh(); + return true; +} bool CemuApp::SelectMLCPath(wxWindow* parent) { @@ -394,21 +412,15 @@ bool CemuApp::SelectMLCPath(wxWindow* parent) const auto path = path_dialog.GetPath().ToStdWstring(); - if (!TestWriteAccess(fs::path{ path })) + if (!TrySelectMLCPath(path)) { const auto result = wxMessageBox(_("Cemu can't write to the selected mlc path!\nDo you want to select another path?"), _("Error"), wxYES_NO | wxCENTRE | wxICON_ERROR); if (result == wxYES) continue; - + break; } - config.SetMLCPath(path); - // update TitleList and SaveList scanner with new MLC path - CafeTitleList::SetMLCPath(path); - CafeTitleList::Refresh(); - CafeSaveList::SetMLCPath(path); - CafeSaveList::Refresh(); return true; } diff --git a/src/gui/CemuApp.h b/src/gui/CemuApp.h index 32504883..f462ec39 100644 --- a/src/gui/CemuApp.h +++ b/src/gui/CemuApp.h @@ -17,6 +17,7 @@ public: static std::vector GetAvailableLanguages(); static void CreateDefaultFiles(bool first_start = false); + static bool TrySelectMLCPath(std::wstring path); static bool SelectMLCPath(wxWindow* parent = nullptr); static wxString GetConfigPath(); diff --git a/src/gui/GeneralSettings2.cpp b/src/gui/GeneralSettings2.cpp index 776afc2e..810c147e 100644 --- a/src/gui/GeneralSettings2.cpp +++ b/src/gui/GeneralSettings2.cpp @@ -1751,7 +1751,6 @@ void GeneralSettings2::OnMLCPathSelect(wxCommandEvent& event) m_mlc_path->SetValue(ActiveSettings::GetMlcPath().generic_string()); m_reload_gamelist = true; m_mlc_modified = true; - CemuApp::CreateDefaultFiles(); } void GeneralSettings2::OnMLCPathChar(wxKeyEvent& event) @@ -1761,14 +1760,18 @@ void GeneralSettings2::OnMLCPathChar(wxKeyEvent& event) if(event.GetKeyCode() == WXK_DELETE || event.GetKeyCode() == WXK_BACK) { - m_mlc_path->SetValue(wxEmptyString); + std::wstring newPath = L""; + if(!CemuApp::TrySelectMLCPath(newPath)) + { + const auto res = wxMessageBox(_("The default MLC path is inaccessible.\nDo you want to select a different path?"), _("Error"), wxYES_NO | wxCENTRE | wxICON_ERROR); + if (res == wxYES && CemuApp::SelectMLCPath(this)) + newPath = ActiveSettings::GetMlcPath().wstring(); + else + return; + } + m_mlc_path->SetValue(newPath); m_reload_gamelist = true; - - GetConfig().mlc_path = L""; - g_config.Save(); m_mlc_modified = true; - - CemuApp::CreateDefaultFiles(); } } diff --git a/src/util/helpers/helpers.cpp b/src/util/helpers/helpers.cpp index fefe7985..b556db36 100644 --- a/src/util/helpers/helpers.cpp +++ b/src/util/helpers/helpers.cpp @@ -280,15 +280,16 @@ uint32_t GetPhysicalCoreCount() bool TestWriteAccess(const fs::path& p) { + std::error_code ec; // must be path and must exist - if (!fs::exists(p) || !fs::is_directory(p)) + if (!fs::exists(p, ec) || !fs::is_directory(p, ec)) return false; // retry 3 times for (int i = 0; i < 3; ++i) { const auto filename = p / fmt::format("_{}.tmp", GenerateRandomString(8)); - if (fs::exists(filename)) + if (fs::exists(filename, ec)) continue; std::ofstream file(filename); @@ -297,7 +298,6 @@ bool TestWriteAccess(const fs::path& p) file.close(); - std::error_code ec; fs::remove(filename, ec); return true; } From c217b3ee3231d5b7e2eed21896f72e9de05f5ea1 Mon Sep 17 00:00:00 2001 From: MythicalPlayz <57963367+MythicalPlayz@users.noreply.github.com> Date: Fri, 21 Oct 2022 00:17:11 +0200 Subject: [PATCH 064/638] GameList: Use title name based on console language (#388) --- src/Cafe/CafeSystem.cpp | 8 +++++++- src/Cafe/TitleList/TitleInfo.cpp | 10 +++++++++- src/gui/MainWindow.cpp | 2 ++ src/gui/components/wxGameList.cpp | 5 +++++ src/gui/components/wxGameList.h | 1 + 5 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index acfd1d2f..68484830 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -705,7 +705,13 @@ namespace CafeSystem { if (sLaunchModeIsStandalone) return "Unknown Game"; - return sGameInfo_ForegroundTitle.GetBase().GetMetaInfo()->GetShortName(GetConfig().console_language); + std::string applicationName; + applicationName = sGameInfo_ForegroundTitle.GetBase().GetMetaInfo()->GetShortName(GetConfig().console_language); + if (applicationName.empty()) //Try to get the English Title + applicationName = sGameInfo_ForegroundTitle.GetBase().GetMetaInfo()->GetShortName(CafeConsoleLanguage::EN); + if (applicationName.empty()) //Unknown Game + applicationName = "Unknown Game"; + return applicationName; } std::string GetForegroundTitleArgStr() diff --git a/src/Cafe/TitleList/TitleInfo.cpp b/src/Cafe/TitleList/TitleInfo.cpp index 10710c43..36814ab8 100644 --- a/src/Cafe/TitleList/TitleInfo.cpp +++ b/src/Cafe/TitleList/TitleInfo.cpp @@ -589,7 +589,15 @@ std::string TitleInfo::GetTitleName() const { cemu_assert_debug(m_isValid); if (m_parsedMetaXml) - return m_parsedMetaXml->GetShortName(CafeConsoleLanguage::EN); + { + std::string titleNameCfgLanguage; + titleNameCfgLanguage = m_parsedMetaXml->GetShortName(GetConfig().console_language); + if (titleNameCfgLanguage.empty()) //Get English Title + titleNameCfgLanguage = m_parsedMetaXml->GetShortName(CafeConsoleLanguage::EN); + if (titleNameCfgLanguage.empty()) //Unknown Title + titleNameCfgLanguage = "Unknown Title"; + return titleNameCfgLanguage; + } if (m_cachedInfo) return m_cachedInfo->titleName; cemu_assert_suspicious(); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index fb18a7de..e8d1c920 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -931,6 +931,8 @@ void MainWindow::OnConsoleLanguage(wxCommandEvent& event) default: cemu_assert_debug(false); } + m_game_list->DeleteCachedStrings(); + m_game_list->ReloadGameEntries(false); g_config.Save(); } diff --git a/src/gui/components/wxGameList.cpp b/src/gui/components/wxGameList.cpp index 904fd5b7..50a6254a 100644 --- a/src/gui/components/wxGameList.cpp +++ b/src/gui/components/wxGameList.cpp @@ -1139,3 +1139,8 @@ bool wxGameList::QueryIconForTitle(TitleId titleId, int& icon, int& iconSmall) m_icon_cache_mtx.unlock(); return true; } + +void wxGameList::DeleteCachedStrings() +{ + m_name_cache.clear(); +} \ No newline at end of file diff --git a/src/gui/components/wxGameList.h b/src/gui/components/wxGameList.h index 2cf9f6b7..f8efd5d2 100644 --- a/src/gui/components/wxGameList.h +++ b/src/gui/components/wxGameList.h @@ -50,6 +50,7 @@ public: bool IsVisible(long item) const; // only available in wxwidgets 3.1.3 void ReloadGameEntries(bool cached = false); + void DeleteCachedStrings(); long FindListItemByTitleId(uint64 title_id) const; void OnClose(wxCloseEvent& event); From ffa213c794d6c11bea370ce445f36d2ede8acf6c Mon Sep 17 00:00:00 2001 From: Squall Leonhart Date: Fri, 21 Oct 2022 21:39:26 +1100 Subject: [PATCH 065/638] Generalised game profile cleanup and corrections (#389) --- bin/gameProfiles/default/0005000010101a00.ini | 8 +------- bin/gameProfiles/default/0005000010101b00.ini | 8 +------- bin/gameProfiles/default/0005000010104d00.ini | 1 - bin/gameProfiles/default/0005000010106100.ini | 3 --- bin/gameProfiles/default/000500001010EB00.ini | 3 --- bin/gameProfiles/default/000500001010F900.ini | 8 +------- bin/gameProfiles/default/000500001010ac00.ini | 8 +------- bin/gameProfiles/default/000500001010b100.ini | 5 +---- bin/gameProfiles/default/000500001010b200.ini | 8 +------- bin/gameProfiles/default/000500001010dc00.ini | 5 +---- bin/gameProfiles/default/000500001010dd00.ini | 5 +---- bin/gameProfiles/default/000500001010e600.ini | 5 +---- bin/gameProfiles/default/000500001010e700.ini | 8 +------- bin/gameProfiles/default/000500001010ec00.ini | 3 --- bin/gameProfiles/default/000500001010ed00.ini | 3 --- bin/gameProfiles/default/000500001010ef00.ini | 5 +---- bin/gameProfiles/default/000500001010f100.ini | 8 +------- bin/gameProfiles/default/000500001010f200.ini | 8 +------- bin/gameProfiles/default/000500001010f500.ini | 5 +---- bin/gameProfiles/default/000500001011000.ini | 8 +------- bin/gameProfiles/default/0005000010110100.ini | 5 +---- bin/gameProfiles/default/0005000010110600.ini | 5 +---- bin/gameProfiles/default/0005000010110700.ini | 5 +---- bin/gameProfiles/default/0005000010110E00.ini | 1 - bin/gameProfiles/default/0005000010111400.ini | 5 +---- bin/gameProfiles/default/0005000010111600.ini | 8 +------- bin/gameProfiles/default/0005000010112000.ini | 5 +---- bin/gameProfiles/default/0005000010112300.ini | 5 +---- bin/gameProfiles/default/0005000010113000.ini | 5 +---- bin/gameProfiles/default/0005000010113300.ini | 5 +---- bin/gameProfiles/default/0005000010113d00.ini | 5 +---- bin/gameProfiles/default/0005000010115d00.ini | 5 +---- bin/gameProfiles/default/0005000010116100.ini | 1 - bin/gameProfiles/default/0005000010117200.ini | 1 - bin/gameProfiles/default/0005000010118300.ini | 1 - bin/gameProfiles/default/000500001011a600.ini | 8 +------- bin/gameProfiles/default/000500001011af00.ini | 5 +---- bin/gameProfiles/default/000500001011b200.ini | 5 +---- bin/gameProfiles/default/0005000010128600.ini | 3 +-- bin/gameProfiles/default/0005000010129000.ini | 1 - bin/gameProfiles/default/0005000010129200.ini | 1 - bin/gameProfiles/default/000500001012BC00.ini | 4 ---- bin/gameProfiles/default/000500001012BD00.ini | 4 ---- bin/gameProfiles/default/000500001012F000.ini | 3 --- bin/gameProfiles/default/000500001012b200.ini | 1 - bin/gameProfiles/default/000500001012ba00.ini | 1 - bin/gameProfiles/default/000500001012be00.ini | 3 --- bin/gameProfiles/default/000500001012c500.ini | 5 +---- bin/gameProfiles/default/000500001012da00.ini | 8 +------- bin/gameProfiles/default/0005000010131F00.ini | 5 +---- bin/gameProfiles/default/0005000010132c00.ini | 5 +---- bin/gameProfiles/default/0005000010132d00.ini | 5 +---- bin/gameProfiles/default/0005000010133b00.ini | 5 +---- bin/gameProfiles/default/0005000010134e00.ini | 5 +---- bin/gameProfiles/default/0005000010135500.ini | 8 +------- bin/gameProfiles/default/0005000010135e00.ini | 6 +----- bin/gameProfiles/default/0005000010136300.ini | 5 +---- bin/gameProfiles/default/0005000010136c00.ini | 1 - bin/gameProfiles/default/0005000010137F00.ini | 5 +---- bin/gameProfiles/default/0005000010137c00.ini | 1 - bin/gameProfiles/default/0005000010138300.ini | 5 +---- bin/gameProfiles/default/0005000010138a00.ini | 5 +---- bin/gameProfiles/default/0005000010138f00.ini | 1 - bin/gameProfiles/default/0005000010140000.ini | 5 +---- bin/gameProfiles/default/0005000010143200.ini | 1 + bin/gameProfiles/default/0005000010143500.ini | 7 +------ bin/gameProfiles/default/0005000010143600.ini | 7 +------ bin/gameProfiles/default/0005000010144800.ini | 5 +---- bin/gameProfiles/default/0005000010144f00.ini | 1 - bin/gameProfiles/default/0005000010145000.ini | 1 - bin/gameProfiles/default/0005000010145c00.ini | 5 +---- bin/gameProfiles/default/0005000010145d00.ini | 5 +---- bin/gameProfiles/default/0005000010147e00.ini | 5 +---- bin/gameProfiles/default/000500001014c100.ini | 5 +---- bin/gameProfiles/default/000500001014c600.ini | 5 +---- bin/gameProfiles/default/000500001014cb00.ini | 5 +---- bin/gameProfiles/default/000500001014d900.ini | 5 +---- bin/gameProfiles/default/0005000010154600.ini | 1 - bin/gameProfiles/default/000500001015b200.ini | 5 +---- bin/gameProfiles/default/0005000010161a00.ini | 5 +---- bin/gameProfiles/default/0005000010162200.ini | 5 +---- bin/gameProfiles/default/0005000010162a00.ini | 5 +---- bin/gameProfiles/default/0005000010162b00.ini | 7 +------ bin/gameProfiles/default/000500001016a200.ini | 5 +---- bin/gameProfiles/default/000500001016ab00.ini | 5 +---- bin/gameProfiles/default/000500001016b200.ini | 3 --- bin/gameProfiles/default/000500001016d400.ini | 5 +---- bin/gameProfiles/default/000500001016d800.ini | 5 +---- bin/gameProfiles/default/000500001016da00.ini | 3 --- bin/gameProfiles/default/000500001016e000.ini | 5 +---- bin/gameProfiles/default/000500001016e800.ini | 3 --- bin/gameProfiles/default/000500001016ea00.ini | 5 +---- bin/gameProfiles/default/000500001016fc00.ini | 3 +-- bin/gameProfiles/default/0005000010170100.ini | 5 +---- bin/gameProfiles/default/0005000010172900.ini | 3 +-- bin/gameProfiles/default/0005000010173400.ini | 5 +---- bin/gameProfiles/default/0005000010176300.ini | 3 +-- bin/gameProfiles/default/0005000010176900.ini | 7 +------ bin/gameProfiles/default/0005000010176a00.ini | 7 +------ bin/gameProfiles/default/0005000010177000.ini | 5 +---- bin/gameProfiles/default/0005000010177500.ini | 3 --- bin/gameProfiles/default/0005000010177600.ini | 1 - bin/gameProfiles/default/0005000010177700.ini | 1 - bin/gameProfiles/default/000500001017da00.ini | 5 +---- bin/gameProfiles/default/000500001017e400.ini | 5 +---- bin/gameProfiles/default/0005000010180500.ini | 3 --- bin/gameProfiles/default/0005000010180600.ini | 3 --- bin/gameProfiles/default/0005000010180700.ini | 3 --- bin/gameProfiles/default/0005000010183000.ini | 8 +------- bin/gameProfiles/default/0005000010184900.ini | 5 +---- bin/gameProfiles/default/0005000010184E00.ini | 7 +------ bin/gameProfiles/default/0005000010184d00.ini | 7 +------ bin/gameProfiles/default/0005000010185400.ini | 7 +------ bin/gameProfiles/default/0005000010189f00.ini | 3 --- bin/gameProfiles/default/000500001018ab00.ini | 5 +---- bin/gameProfiles/default/000500001018d800.ini | 5 +---- bin/gameProfiles/default/000500001018d900.ini | 3 --- bin/gameProfiles/default/000500001018f100.ini | 5 +---- bin/gameProfiles/default/000500001018f400.ini | 5 +---- bin/gameProfiles/default/000500001018fd00.ini | 5 +---- bin/gameProfiles/default/0005000010190300.ini | 5 +---- bin/gameProfiles/default/0005000010193f00.ini | 5 +---- bin/gameProfiles/default/0005000010195e00.ini | 5 +---- bin/gameProfiles/default/0005000010197300.ini | 5 +---- bin/gameProfiles/default/0005000010197800.ini | 5 +---- bin/gameProfiles/default/0005000010199e00.ini | 5 +---- bin/gameProfiles/default/000500001019ab00.ini | 5 +---- bin/gameProfiles/default/000500001019b000.ini | 5 +---- bin/gameProfiles/default/000500001019b200.ini | 5 +---- bin/gameProfiles/default/000500001019ca00.ini | 5 +---- bin/gameProfiles/default/000500001019e500.ini | 7 +------ bin/gameProfiles/default/000500001019e600.ini | 7 +------ bin/gameProfiles/default/000500001019ea00.ini | 5 +---- bin/gameProfiles/default/000500001019ee00.ini | 5 +---- bin/gameProfiles/default/00050000101C9300.ini | 1 - bin/gameProfiles/default/00050000101E4100.ini | 3 --- bin/gameProfiles/default/00050000101a1200.ini | 6 +----- bin/gameProfiles/default/00050000101a1800.ini | 5 +---- bin/gameProfiles/default/00050000101a3b00.ini | 5 +---- bin/gameProfiles/default/00050000101a4300.ini | 5 +---- bin/gameProfiles/default/00050000101a4800.ini | 3 --- bin/gameProfiles/default/00050000101a4900.ini | 5 +---- bin/gameProfiles/default/00050000101a7f00.ini | 5 +---- bin/gameProfiles/default/00050000101a9c00.ini | 5 +---- bin/gameProfiles/default/00050000101a9e00.ini | 5 +---- bin/gameProfiles/default/00050000101acc00.ini | 5 +---- bin/gameProfiles/default/00050000101b0100.ini | 5 +---- bin/gameProfiles/default/00050000101b4e00.ini | 5 +---- bin/gameProfiles/default/00050000101b9900.ini | 3 --- bin/gameProfiles/default/00050000101bc300.ini | 5 +---- bin/gameProfiles/default/00050000101c3100.ini | 5 +---- bin/gameProfiles/default/00050000101c4200.ini | 5 +---- bin/gameProfiles/default/00050000101c4300.ini | 3 --- bin/gameProfiles/default/00050000101c4c00.ini | 1 - bin/gameProfiles/default/00050000101c4d00.ini | 1 - bin/gameProfiles/default/00050000101c6c00.ini | 5 +---- bin/gameProfiles/default/00050000101c7600.ini | 5 +---- bin/gameProfiles/default/00050000101c7b00.ini | 5 +---- bin/gameProfiles/default/00050000101c7d00.ini | 5 +---- bin/gameProfiles/default/00050000101c9400.ini | 1 - bin/gameProfiles/default/00050000101c9500.ini | 1 - bin/gameProfiles/default/00050000101c9a00.ini | 3 --- bin/gameProfiles/default/00050000101cc900.ini | 5 +---- bin/gameProfiles/default/00050000101ccf00.ini | 5 +---- bin/gameProfiles/default/00050000101ce000.ini | 5 +---- bin/gameProfiles/default/00050000101ce800.ini | 5 +---- bin/gameProfiles/default/00050000101d2100.ini | 3 +-- bin/gameProfiles/default/00050000101d4500.ini | 5 +---- bin/gameProfiles/default/00050000101d4d00.ini | 5 +---- bin/gameProfiles/default/00050000101d5000.ini | 5 +---- bin/gameProfiles/default/00050000101d5500.ini | 5 +---- bin/gameProfiles/default/00050000101d6000.ini | 3 --- bin/gameProfiles/default/00050000101d6d00.ini | 8 +------- bin/gameProfiles/default/00050000101d7500.ini | 3 --- bin/gameProfiles/default/00050000101d8900.ini | 5 +---- bin/gameProfiles/default/00050000101d8d00.ini | 5 +---- bin/gameProfiles/default/00050000101d9600.ini | 5 +---- bin/gameProfiles/default/00050000101d9d00.ini | 3 --- bin/gameProfiles/default/00050000101dac00.ini | 5 +---- bin/gameProfiles/default/00050000101daf00.ini | 5 +---- bin/gameProfiles/default/00050000101db000.ini | 5 +---- bin/gameProfiles/default/00050000101dbb00.ini | 5 +---- bin/gameProfiles/default/00050000101dbc00.ini | 5 +---- bin/gameProfiles/default/00050000101dbe00.ini | 5 +---- bin/gameProfiles/default/00050000101dbf00.ini | 5 +---- bin/gameProfiles/default/00050000101dc000.ini | 5 +---- bin/gameProfiles/default/00050000101dc200.ini | 5 +---- bin/gameProfiles/default/00050000101dd000.ini | 5 +---- bin/gameProfiles/default/00050000101dd600.ini | 5 +---- bin/gameProfiles/default/00050000101dd700.ini | 8 +------- bin/gameProfiles/default/00050000101ddf00.ini | 5 +---- bin/gameProfiles/default/00050000101e0100.ini | 7 +------ bin/gameProfiles/default/00050000101e1800.ini | 5 +---- bin/gameProfiles/default/00050000101e1a00.ini | 5 +---- bin/gameProfiles/default/00050000101e1b00.ini | 3 --- bin/gameProfiles/default/00050000101e3800.ini | 8 +------- bin/gameProfiles/default/00050000101e4200.ini | 3 --- bin/gameProfiles/default/00050000101e5300.ini | 3 --- bin/gameProfiles/default/00050000101e5400.ini | 3 --- bin/gameProfiles/default/00050000101e5e00.ini | 5 +---- bin/gameProfiles/default/00050000101e7300.ini | 5 +---- bin/gameProfiles/default/00050000101e7400.ini | 5 +---- bin/gameProfiles/default/00050000101e9300.ini | 5 +---- bin/gameProfiles/default/00050000101e9400.ini | 5 +---- bin/gameProfiles/default/00050000101eb300.ini | 5 +---- bin/gameProfiles/default/00050000101ec700.ini | 5 +---- bin/gameProfiles/default/00050000101ecf00.ini | 5 +---- bin/gameProfiles/default/00050000101f1300.ini | 5 +---- bin/gameProfiles/default/00050000101f2800.ini | 3 --- bin/gameProfiles/default/00050000101f4a00.ini | 5 +---- bin/gameProfiles/default/00050000101f5700.ini | 5 +---- bin/gameProfiles/default/00050000101f6f00.ini | 5 +---- bin/gameProfiles/default/00050000101f7600.ini | 8 +------- bin/gameProfiles/default/00050000101f9700.ini | 5 +---- bin/gameProfiles/default/00050000101fa600.ini | 5 +---- bin/gameProfiles/default/00050000101fd100.ini | 5 +---- bin/gameProfiles/default/00050000101ff200.ini | 5 +---- bin/gameProfiles/default/00050000101ffc00.ini | 1 - bin/gameProfiles/default/00050000101ffe00.ini | 5 +---- bin/gameProfiles/default/0005000010200300.ini | 5 +---- bin/gameProfiles/default/0005000010200b00.ini | 5 +---- bin/gameProfiles/default/0005000010204a00.ini | 5 +---- bin/gameProfiles/default/0005000010207300.ini | 5 +---- bin/gameProfiles/default/0005000010207500.ini | 5 +---- bin/gameProfiles/default/000500001020a200.ini | 6 +----- bin/gameProfiles/default/000500001020b600.ini | 1 - bin/gameProfiles/default/0005000010211b00.ini | 5 +---- bin/gameProfiles/default/0005000C1012BC00.ini | 4 ---- bin/gameProfiles/default/0005000C1012BD00.ini | 4 ---- bin/gameProfiles/default/0005000C1012BE00.ini | 4 ---- bin/gameProfiles/default/0005000e1019c800.ini | 5 +---- 231 files changed, 174 insertions(+), 889 deletions(-) create mode 100644 bin/gameProfiles/default/0005000010143200.ini diff --git a/bin/gameProfiles/default/0005000010101a00.ini b/bin/gameProfiles/default/0005000010101a00.ini index dc63ccb5..1123343a 100644 --- a/bin/gameProfiles/default/0005000010101a00.ini +++ b/bin/gameProfiles/default/0005000010101a00.ini @@ -1,7 +1 @@ -# LEGO City Undercover (USA) - -[General] -loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# LEGO City Undercover (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010101b00.ini b/bin/gameProfiles/default/0005000010101b00.ini index 21aded1d..f3749d47 100644 --- a/bin/gameProfiles/default/0005000010101b00.ini +++ b/bin/gameProfiles/default/0005000010101b00.ini @@ -1,7 +1 @@ -# LEGO City Undercover (EUR) - -[General] -loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# LEGO City Undercover (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010104d00.ini b/bin/gameProfiles/default/0005000010104d00.ini index 50a9fa48..dc8bebaf 100644 --- a/bin/gameProfiles/default/0005000010104d00.ini +++ b/bin/gameProfiles/default/0005000010104d00.ini @@ -1,5 +1,4 @@ # Monster Hunter 3(tri-)GHD Ver. (JPN) [Graphics] -GPUBufferCacheAccuracy = 1 streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010106100.ini b/bin/gameProfiles/default/0005000010106100.ini index 77e7c399..9aa38072 100644 --- a/bin/gameProfiles/default/0005000010106100.ini +++ b/bin/gameProfiles/default/0005000010106100.ini @@ -1,7 +1,4 @@ # Super Mario 3D World (JPN) -[CPU] - [Graphics] accurateShaderMul = false -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001010EB00.ini b/bin/gameProfiles/default/000500001010EB00.ini index e4b30b16..281d21db 100644 --- a/bin/gameProfiles/default/000500001010EB00.ini +++ b/bin/gameProfiles/default/000500001010EB00.ini @@ -2,6 +2,3 @@ [CPU] cpuMode = Singlecore-Recompiler - -[Graphics] -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001010F900.ini b/bin/gameProfiles/default/000500001010F900.ini index 4772db75..e22770bf 100644 --- a/bin/gameProfiles/default/000500001010F900.ini +++ b/bin/gameProfiles/default/000500001010F900.ini @@ -1,7 +1 @@ -# Scribblenauts Unlimited (EUR) - -[General] -loadSharedLibraries = true - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Scribblenauts Unlimited (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001010ac00.ini b/bin/gameProfiles/default/000500001010ac00.ini index 7df76e2f..9852538c 100644 --- a/bin/gameProfiles/default/000500001010ac00.ini +++ b/bin/gameProfiles/default/000500001010ac00.ini @@ -1,7 +1 @@ -# Ben 10 Omniverse (USA) - -[General] -loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Ben 10 Omniverse (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001010b100.ini b/bin/gameProfiles/default/000500001010b100.ini index e2215587..0741b39f 100644 --- a/bin/gameProfiles/default/000500001010b100.ini +++ b/bin/gameProfiles/default/000500001010b100.ini @@ -1,4 +1 @@ -# Rayman Legends (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Rayman Legends (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001010b200.ini b/bin/gameProfiles/default/000500001010b200.ini index d47b4060..22d51c39 100644 --- a/bin/gameProfiles/default/000500001010b200.ini +++ b/bin/gameProfiles/default/000500001010b200.ini @@ -1,7 +1 @@ -# Scribblenauts Unlimited (US) - -[General] -loadSharedLibraries = true - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Scribblenauts Unlimited (US) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001010dc00.ini b/bin/gameProfiles/default/000500001010dc00.ini index 11d0fd68..ffed75ea 100644 --- a/bin/gameProfiles/default/000500001010dc00.ini +++ b/bin/gameProfiles/default/000500001010dc00.ini @@ -1,4 +1 @@ -# Mass Effect 3 Special Edition (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Mass Effect 3 Special Edition (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001010dd00.ini b/bin/gameProfiles/default/000500001010dd00.ini index 5a0620da..2e74d7e0 100644 --- a/bin/gameProfiles/default/000500001010dd00.ini +++ b/bin/gameProfiles/default/000500001010dd00.ini @@ -1,4 +1 @@ -# ZombiU (US) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# ZombiU (US) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001010e600.ini b/bin/gameProfiles/default/000500001010e600.ini index dc351608..01dc0e7a 100644 --- a/bin/gameProfiles/default/000500001010e600.ini +++ b/bin/gameProfiles/default/000500001010e600.ini @@ -1,4 +1 @@ -# 007 Legends (US) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# 007 Legends (US) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001010e700.ini b/bin/gameProfiles/default/000500001010e700.ini index ea118074..a926c9d4 100644 --- a/bin/gameProfiles/default/000500001010e700.ini +++ b/bin/gameProfiles/default/000500001010e700.ini @@ -1,7 +1 @@ -# Cabela's Dangerous Hunts 2013 (USA) - -[General] -loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Cabela's Dangerous Hunts 2013 (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001010ec00.ini b/bin/gameProfiles/default/000500001010ec00.ini index babaf249..697aace3 100644 --- a/bin/gameProfiles/default/000500001010ec00.ini +++ b/bin/gameProfiles/default/000500001010ec00.ini @@ -2,6 +2,3 @@ [CPU] cpuMode = Singlecore-Recompiler - -[Graphics] -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001010ed00.ini b/bin/gameProfiles/default/000500001010ed00.ini index 7935ea37..23e1dffc 100644 --- a/bin/gameProfiles/default/000500001010ed00.ini +++ b/bin/gameProfiles/default/000500001010ed00.ini @@ -2,6 +2,3 @@ [CPU] cpuMode = Singlecore-Recompiler - -[Graphics] -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001010ef00.ini b/bin/gameProfiles/default/000500001010ef00.ini index 005ba84b..dbadd2b1 100644 --- a/bin/gameProfiles/default/000500001010ef00.ini +++ b/bin/gameProfiles/default/000500001010ef00.ini @@ -1,4 +1 @@ -# ZombiU (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# ZombiU (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001010f100.ini b/bin/gameProfiles/default/000500001010f100.ini index c557498c..025e3e70 100644 --- a/bin/gameProfiles/default/000500001010f100.ini +++ b/bin/gameProfiles/default/000500001010f100.ini @@ -1,7 +1 @@ -# Rise of the Guardians: The Video Game (EUR) - -[General] -loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Rise of the Guardians: The Video Game (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001010f200.ini b/bin/gameProfiles/default/000500001010f200.ini index 055fda32..507b374b 100644 --- a/bin/gameProfiles/default/000500001010f200.ini +++ b/bin/gameProfiles/default/000500001010f200.ini @@ -1,7 +1 @@ -# Rise of the Guardians: The Video Game (USA) - -[General] -loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Rise of the Guardians: The Video Game (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001010f500.ini b/bin/gameProfiles/default/000500001010f500.ini index e1a86417..e598f517 100644 --- a/bin/gameProfiles/default/000500001010f500.ini +++ b/bin/gameProfiles/default/000500001010f500.ini @@ -1,4 +1 @@ -# Mass Effect 3 Special Edition (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Mass Effect 3 Special Edition (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001011000.ini b/bin/gameProfiles/default/000500001011000.ini index 85ebf4c6..8c34cbab 100644 --- a/bin/gameProfiles/default/000500001011000.ini +++ b/bin/gameProfiles/default/000500001011000.ini @@ -1,7 +1 @@ -# Ben 10 Omniverse (EUR) - -[General] -loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Ben 10 Omniverse (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010110100.ini b/bin/gameProfiles/default/0005000010110100.ini index 69b988cf..d46267b0 100644 --- a/bin/gameProfiles/default/0005000010110100.ini +++ b/bin/gameProfiles/default/0005000010110100.ini @@ -1,4 +1 @@ -# Nano Assault Neo (USA) - -[Graphics] -GPUBufferCacheAccuracy = 2 \ No newline at end of file +# Nano Assault Neo (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010110600.ini b/bin/gameProfiles/default/0005000010110600.ini index fb19b607..bc0a0552 100644 --- a/bin/gameProfiles/default/0005000010110600.ini +++ b/bin/gameProfiles/default/0005000010110600.ini @@ -1,4 +1 @@ -# Nano Assault Neo (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 2 \ No newline at end of file +# Nano Assault Neo (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010110700.ini b/bin/gameProfiles/default/0005000010110700.ini index e2d361c4..4e88d406 100644 --- a/bin/gameProfiles/default/0005000010110700.ini +++ b/bin/gameProfiles/default/0005000010110700.ini @@ -1,4 +1 @@ -# 007 Legends (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# 007 Legends (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010110E00.ini b/bin/gameProfiles/default/0005000010110E00.ini index 3064350f..6c56910f 100644 --- a/bin/gameProfiles/default/0005000010110E00.ini +++ b/bin/gameProfiles/default/0005000010110E00.ini @@ -5,4 +5,3 @@ cpuMode = Singlecore-Recompiler [Graphics] streamoutBufferCacheSize = 48 -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010111400.ini b/bin/gameProfiles/default/0005000010111400.ini index 7fee0ed1..baa50914 100644 --- a/bin/gameProfiles/default/0005000010111400.ini +++ b/bin/gameProfiles/default/0005000010111400.ini @@ -1,4 +1 @@ -# Rayman Legends (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Rayman Legends (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010111600.ini b/bin/gameProfiles/default/0005000010111600.ini index 6b433160..f1c13f22 100644 --- a/bin/gameProfiles/default/0005000010111600.ini +++ b/bin/gameProfiles/default/0005000010111600.ini @@ -1,7 +1 @@ -# Fast And Furious Showdown (USA) - -[General] -loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Fast And Furious Showdown (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010112000.ini b/bin/gameProfiles/default/0005000010112000.ini index 853fc36b..3c7710d9 100644 --- a/bin/gameProfiles/default/0005000010112000.ini +++ b/bin/gameProfiles/default/0005000010112000.ini @@ -1,4 +1 @@ -# The Croods: Prehistoric Party! (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# The Croods: Prehistoric Party! (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010112300.ini b/bin/gameProfiles/default/0005000010112300.ini index 5fe50f24..37d8050f 100644 --- a/bin/gameProfiles/default/0005000010112300.ini +++ b/bin/gameProfiles/default/0005000010112300.ini @@ -1,4 +1 @@ -# ZombiU (JPN) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# ZombiU (JPN) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010113000.ini b/bin/gameProfiles/default/0005000010113000.ini index 30330b89..6c023330 100644 --- a/bin/gameProfiles/default/0005000010113000.ini +++ b/bin/gameProfiles/default/0005000010113000.ini @@ -1,4 +1 @@ -# Mass Effect 3 Special Edition (JPN) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Mass Effect 3 Special Edition (JPN) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010113300.ini b/bin/gameProfiles/default/0005000010113300.ini index af55851d..5118d05f 100644 --- a/bin/gameProfiles/default/0005000010113300.ini +++ b/bin/gameProfiles/default/0005000010113300.ini @@ -1,4 +1 @@ -# The Smurfs 2 (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# The Smurfs 2 (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010113d00.ini b/bin/gameProfiles/default/0005000010113d00.ini index 51369705..afb42bf8 100644 --- a/bin/gameProfiles/default/0005000010113d00.ini +++ b/bin/gameProfiles/default/0005000010113d00.ini @@ -1,4 +1 @@ -# Rapala Pro Bass Fishing (US) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Rapala Pro Bass Fishing (US) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010115d00.ini b/bin/gameProfiles/default/0005000010115d00.ini index 5a00554b..84bb9fad 100644 --- a/bin/gameProfiles/default/0005000010115d00.ini +++ b/bin/gameProfiles/default/0005000010115d00.ini @@ -1,4 +1 @@ -# The Smurfs 2 (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# The Smurfs 2 (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010116100.ini b/bin/gameProfiles/default/0005000010116100.ini index 8f01e5fa..465d3dc3 100644 --- a/bin/gameProfiles/default/0005000010116100.ini +++ b/bin/gameProfiles/default/0005000010116100.ini @@ -5,4 +5,3 @@ cpuMode = Singlecore-Recompiler [Graphics] accurateShaderMul = false -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010117200.ini b/bin/gameProfiles/default/0005000010117200.ini index e802c38e..4000f79f 100644 --- a/bin/gameProfiles/default/0005000010117200.ini +++ b/bin/gameProfiles/default/0005000010117200.ini @@ -1,5 +1,4 @@ # Monster Hunter 3 Ultimate (EUR) [Graphics] -GPUBufferCacheAccuracy = 1 streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010118300.ini b/bin/gameProfiles/default/0005000010118300.ini index 4ba8d937..e69a6b95 100644 --- a/bin/gameProfiles/default/0005000010118300.ini +++ b/bin/gameProfiles/default/0005000010118300.ini @@ -1,5 +1,4 @@ # Monster Hunter 3 Ultimate (USA) [Graphics] -GPUBufferCacheAccuracy = 1 streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001011a600.ini b/bin/gameProfiles/default/000500001011a600.ini index 7c673d05..454aaf08 100644 --- a/bin/gameProfiles/default/000500001011a600.ini +++ b/bin/gameProfiles/default/000500001011a600.ini @@ -1,7 +1 @@ -# Cabela's Dangerous Hunts 2013 (EUR) - -[General] -loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Cabela's Dangerous Hunts 2013 (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001011af00.ini b/bin/gameProfiles/default/000500001011af00.ini index c7bc4826..73c8f567 100644 --- a/bin/gameProfiles/default/000500001011af00.ini +++ b/bin/gameProfiles/default/000500001011af00.ini @@ -1,4 +1 @@ -# BIT.TRIP Presents... Runner2: Future Legend of Rhythm Alien (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# BIT.TRIP Presents... Runner2: Future Legend of Rhythm Alien (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001011b200.ini b/bin/gameProfiles/default/000500001011b200.ini index 64edf0af..4a576434 100644 --- a/bin/gameProfiles/default/000500001011b200.ini +++ b/bin/gameProfiles/default/000500001011b200.ini @@ -1,7 +1,4 @@ # Little Inferno (US) -[CPU] -extendedTextureReadback = true - [Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +extendedTextureReadback = true \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010128600.ini b/bin/gameProfiles/default/0005000010128600.ini index 467f0014..cd6c1b18 100644 --- a/bin/gameProfiles/default/0005000010128600.ini +++ b/bin/gameProfiles/default/0005000010128600.ini @@ -1,5 +1,4 @@ # Little Inferno (EUR) -[CPU] +[Graphics] extendedTextureReadback = true -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010129000.ini b/bin/gameProfiles/default/0005000010129000.ini index e1a9d9c5..93403c3c 100644 --- a/bin/gameProfiles/default/0005000010129000.ini +++ b/bin/gameProfiles/default/0005000010129000.ini @@ -4,5 +4,4 @@ cpuMode = Singlecore-Recompiler [Graphics] -GPUBufferCacheAccuracy = 0 streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010129200.ini b/bin/gameProfiles/default/0005000010129200.ini index 33c2f21a..8705ce00 100644 --- a/bin/gameProfiles/default/0005000010129200.ini +++ b/bin/gameProfiles/default/0005000010129200.ini @@ -4,5 +4,4 @@ cpuMode = Singlecore-Recompiler [Graphics] -GPUBufferCacheAccuracy = 0 streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001012BC00.ini b/bin/gameProfiles/default/000500001012BC00.ini index c7adb846..0b4f6b6d 100644 --- a/bin/gameProfiles/default/000500001012BC00.ini +++ b/bin/gameProfiles/default/000500001012BC00.ini @@ -1,8 +1,4 @@ # Pikmin 3 (JPN) - - [Graphics] - extendedTextureReadback = true -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001012BD00.ini b/bin/gameProfiles/default/000500001012BD00.ini index 8ab10175..cd27ff77 100644 --- a/bin/gameProfiles/default/000500001012BD00.ini +++ b/bin/gameProfiles/default/000500001012BD00.ini @@ -1,8 +1,4 @@ # Pikmin 3 (USA) - - [Graphics] - extendedTextureReadback = true -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001012F000.ini b/bin/gameProfiles/default/000500001012F000.ini index af1229e6..6b1a3f95 100644 --- a/bin/gameProfiles/default/000500001012F000.ini +++ b/bin/gameProfiles/default/000500001012F000.ini @@ -2,6 +2,3 @@ [CPU] cpuMode = Singlecore-Recompiler - -[Graphics] -GPUBufferCacheAccuracy = 1 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001012b200.ini b/bin/gameProfiles/default/000500001012b200.ini index b00c1a04..9f3733ff 100644 --- a/bin/gameProfiles/default/000500001012b200.ini +++ b/bin/gameProfiles/default/000500001012b200.ini @@ -4,6 +4,5 @@ loadSharedLibraries = false [Graphics] -GPUBufferCacheAccuracy = 0 extendedTextureReadback = true streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001012ba00.ini b/bin/gameProfiles/default/000500001012ba00.ini index 7e94a7fd..efab660e 100644 --- a/bin/gameProfiles/default/000500001012ba00.ini +++ b/bin/gameProfiles/default/000500001012ba00.ini @@ -4,6 +4,5 @@ loadSharedLibraries = false [Graphics] -GPUBufferCacheAccuracy = 0 extendedTextureReadback = true streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001012be00.ini b/bin/gameProfiles/default/000500001012be00.ini index 2987dd1e..64a38b0d 100644 --- a/bin/gameProfiles/default/000500001012be00.ini +++ b/bin/gameProfiles/default/000500001012be00.ini @@ -1,7 +1,4 @@ # Pikmin 3 (EU) - - [Graphics] - extendedTextureReadback = true \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001012c500.ini b/bin/gameProfiles/default/000500001012c500.ini index 9badd49e..e4cc6690 100644 --- a/bin/gameProfiles/default/000500001012c500.ini +++ b/bin/gameProfiles/default/000500001012c500.ini @@ -1,4 +1 @@ -# The Croods: Prehistoric Party! (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# The Croods: Prehistoric Party! (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001012da00.ini b/bin/gameProfiles/default/000500001012da00.ini index 4f478ace..8812e297 100644 --- a/bin/gameProfiles/default/000500001012da00.ini +++ b/bin/gameProfiles/default/000500001012da00.ini @@ -1,7 +1 @@ -# Fast And Furious Showdown (EUR) - -[General] -loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Fast And Furious Showdown (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010131F00.ini b/bin/gameProfiles/default/0005000010131F00.ini index 9b2dde57..b484aa82 100644 --- a/bin/gameProfiles/default/0005000010131F00.ini +++ b/bin/gameProfiles/default/0005000010131F00.ini @@ -1,4 +1 @@ -# Yoshi's Woolly World (JPN) - -[Graphics] -GPUBufferCacheAccuracy = 2 \ No newline at end of file +# Yoshi's Woolly World (JPN) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010132c00.ini b/bin/gameProfiles/default/0005000010132c00.ini index 00e83b4c..ff554b6e 100644 --- a/bin/gameProfiles/default/0005000010132c00.ini +++ b/bin/gameProfiles/default/0005000010132c00.ini @@ -1,4 +1 @@ -# Scribblenauts Unmasked: A DC Comics Adventure (US) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Scribblenauts Unmasked: A DC Comics Adventure (US) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010132d00.ini b/bin/gameProfiles/default/0005000010132d00.ini index d516cd8f..3655b674 100644 --- a/bin/gameProfiles/default/0005000010132d00.ini +++ b/bin/gameProfiles/default/0005000010132d00.ini @@ -1,4 +1 @@ -# Scribblenauts Unmasked: A DC Comics Adventure (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Scribblenauts Unmasked: A DC Comics Adventure (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010133b00.ini b/bin/gameProfiles/default/0005000010133b00.ini index 465ef364..ae2c8a48 100644 --- a/bin/gameProfiles/default/0005000010133b00.ini +++ b/bin/gameProfiles/default/0005000010133b00.ini @@ -1,4 +1 @@ -# Sniper Elite V2 (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 1 \ No newline at end of file +# Sniper Elite V2 (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010134e00.ini b/bin/gameProfiles/default/0005000010134e00.ini index e04cdd74..99ff8b41 100644 --- a/bin/gameProfiles/default/0005000010134e00.ini +++ b/bin/gameProfiles/default/0005000010134e00.ini @@ -1,4 +1 @@ -# Sniper Elite V2 (USA) - -[Graphics] -GPUBufferCacheAccuracy = 1 \ No newline at end of file +# Sniper Elite V2 (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010135500.ini b/bin/gameProfiles/default/0005000010135500.ini index cc008930..71f1c152 100644 --- a/bin/gameProfiles/default/0005000010135500.ini +++ b/bin/gameProfiles/default/0005000010135500.ini @@ -1,7 +1 @@ -# LEGO Batman 2: DC Super Heroes (EUR) - -[General] -loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# LEGO Batman 2: DC Super Heroes (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010135e00.ini b/bin/gameProfiles/default/0005000010135e00.ini index ea135acc..1319dfe5 100644 --- a/bin/gameProfiles/default/0005000010135e00.ini +++ b/bin/gameProfiles/default/0005000010135e00.ini @@ -1,5 +1 @@ -# LEGO Batman 2: DC Super Heroes (USA) - -[General] -loadSharedLibraries = false -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# LEGO Batman 2: DC Super Heroes (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010136300.ini b/bin/gameProfiles/default/0005000010136300.ini index 19e3176f..b37053e0 100644 --- a/bin/gameProfiles/default/0005000010136300.ini +++ b/bin/gameProfiles/default/0005000010136300.ini @@ -1,4 +1 @@ -# BIT.TRIP Presents... Runner2: Future Legend of Rhythm Alien (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# BIT.TRIP Presents... Runner2: Future Legend of Rhythm Alien (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010136c00.ini b/bin/gameProfiles/default/0005000010136c00.ini index 8d9d5448..427a45fe 100644 --- a/bin/gameProfiles/default/0005000010136c00.ini +++ b/bin/gameProfiles/default/0005000010136c00.ini @@ -4,5 +4,4 @@ cpuMode = Singlecore-Recompiler [Graphics] -GPUBufferCacheAccuracy = 0 streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010137F00.ini b/bin/gameProfiles/default/0005000010137F00.ini index c9cddecc..151d5394 100644 --- a/bin/gameProfiles/default/0005000010137F00.ini +++ b/bin/gameProfiles/default/0005000010137F00.ini @@ -1,4 +1 @@ -# DKC: Tropical Freeze (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# DKC: Tropical Freeze (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010137c00.ini b/bin/gameProfiles/default/0005000010137c00.ini index db36989b..88fff6e7 100644 --- a/bin/gameProfiles/default/0005000010137c00.ini +++ b/bin/gameProfiles/default/0005000010137c00.ini @@ -4,5 +4,4 @@ cpuMode = Singlecore-Recompiler [Graphics] -GPUBufferCacheAccuracy = 0 streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010138300.ini b/bin/gameProfiles/default/0005000010138300.ini index 4385df2e..d992cb24 100644 --- a/bin/gameProfiles/default/0005000010138300.ini +++ b/bin/gameProfiles/default/0005000010138300.ini @@ -1,4 +1 @@ -# DKC: Tropical Freeze (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# DKC: Tropical Freeze (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010138a00.ini b/bin/gameProfiles/default/0005000010138a00.ini index 8a4f621e..26318009 100644 --- a/bin/gameProfiles/default/0005000010138a00.ini +++ b/bin/gameProfiles/default/0005000010138a00.ini @@ -1,4 +1 @@ -# Angry Birds Trilogy (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Angry Birds Trilogy (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010138f00.ini b/bin/gameProfiles/default/0005000010138f00.ini index df1f79ea..1f46d11d 100644 --- a/bin/gameProfiles/default/0005000010138f00.ini +++ b/bin/gameProfiles/default/0005000010138f00.ini @@ -1,5 +1,4 @@ # Devil's Third (JPN) [Graphics] -GPUBufferCacheAccuracy = 0 streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010140000.ini b/bin/gameProfiles/default/0005000010140000.ini index 9afff7f4..347a4481 100644 --- a/bin/gameProfiles/default/0005000010140000.ini +++ b/bin/gameProfiles/default/0005000010140000.ini @@ -1,4 +1 @@ -# Angry Birds Trilogy (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Angry Birds Trilogy (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010143200.ini b/bin/gameProfiles/default/0005000010143200.ini new file mode 100644 index 00000000..7085a558 --- /dev/null +++ b/bin/gameProfiles/default/0005000010143200.ini @@ -0,0 +1 @@ +# Cabela's Big Game Hunter: Pro Hunts (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010143500.ini b/bin/gameProfiles/default/0005000010143500.ini index a9266121..c8b93998 100644 --- a/bin/gameProfiles/default/0005000010143500.ini +++ b/bin/gameProfiles/default/0005000010143500.ini @@ -1,6 +1 @@ -# TLoZ: Wind Waker HD (USA) - -[CPU] - -[Graphics] -GPUBufferCacheAccuracy = 2 \ No newline at end of file +# TLoZ: Wind Waker HD (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010143600.ini b/bin/gameProfiles/default/0005000010143600.ini index 6ba5a4c0..6414c25d 100644 --- a/bin/gameProfiles/default/0005000010143600.ini +++ b/bin/gameProfiles/default/0005000010143600.ini @@ -1,6 +1 @@ -# TLoZ: Wind Waker HD (EUR) - -[CPU] - -[Graphics] -GPUBufferCacheAccuracy = 2 \ No newline at end of file +# TLoZ: Wind Waker HD (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010144800.ini b/bin/gameProfiles/default/0005000010144800.ini index 55a4e962..80721cd0 100644 --- a/bin/gameProfiles/default/0005000010144800.ini +++ b/bin/gameProfiles/default/0005000010144800.ini @@ -1,4 +1 @@ -# DKC: Tropical Freeze (JPN) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# DKC: Tropical Freeze (JPN) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010144f00.ini b/bin/gameProfiles/default/0005000010144f00.ini index 6bbc9e28..c2fce59a 100644 --- a/bin/gameProfiles/default/0005000010144f00.ini +++ b/bin/gameProfiles/default/0005000010144f00.ini @@ -5,4 +5,3 @@ cpuMode = Singlecore-Recompiler [Graphics] streamoutBufferCacheSize = 48 -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010145000.ini b/bin/gameProfiles/default/0005000010145000.ini index f286269f..ace52dba 100644 --- a/bin/gameProfiles/default/0005000010145000.ini +++ b/bin/gameProfiles/default/0005000010145000.ini @@ -5,4 +5,3 @@ cpuMode = Singlecore-Recompiler [Graphics] streamoutBufferCacheSize = 48 -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010145c00.ini b/bin/gameProfiles/default/0005000010145c00.ini index b82867e4..0be65fcc 100644 --- a/bin/gameProfiles/default/0005000010145c00.ini +++ b/bin/gameProfiles/default/0005000010145c00.ini @@ -1,7 +1,4 @@ # Super Mario 3D World (USA) -[CPU] - [Graphics] -accurateShaderMul = false -GPUBufferCacheAccuracy = 2 \ No newline at end of file +accurateShaderMul = false \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010145d00.ini b/bin/gameProfiles/default/0005000010145d00.ini index 99c70dfe..3525edd8 100644 --- a/bin/gameProfiles/default/0005000010145d00.ini +++ b/bin/gameProfiles/default/0005000010145d00.ini @@ -1,7 +1,4 @@ # Super Mario 3D World (EUR) -[CPU] - [Graphics] -accurateShaderMul = false -GPUBufferCacheAccuracy = 2 \ No newline at end of file +accurateShaderMul = false \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010147e00.ini b/bin/gameProfiles/default/0005000010147e00.ini index f5f73b9c..62109cc9 100644 --- a/bin/gameProfiles/default/0005000010147e00.ini +++ b/bin/gameProfiles/default/0005000010147e00.ini @@ -1,4 +1 @@ -# Hello Kitty Kruisers (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Hello Kitty Kruisers (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001014c100.ini b/bin/gameProfiles/default/000500001014c100.ini index da5f4d3a..64add666 100644 --- a/bin/gameProfiles/default/000500001014c100.ini +++ b/bin/gameProfiles/default/000500001014c100.ini @@ -1,4 +1 @@ -# Transformers: Rise of the Dark Spark (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Transformers: Rise of the Dark Spark (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001014c600.ini b/bin/gameProfiles/default/000500001014c600.ini index d83ea1d8..ff80f137 100644 --- a/bin/gameProfiles/default/000500001014c600.ini +++ b/bin/gameProfiles/default/000500001014c600.ini @@ -1,4 +1 @@ -# Giana Sisters Twisted Dreams (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Giana Sisters Twisted Dreams (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001014cb00.ini b/bin/gameProfiles/default/000500001014cb00.ini index 24e6e8d9..3ab3829e 100644 --- a/bin/gameProfiles/default/000500001014cb00.ini +++ b/bin/gameProfiles/default/000500001014cb00.ini @@ -1,4 +1 @@ -# Giana Sisters Twisted Dreams (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Giana Sisters Twisted Dreams (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001014d900.ini b/bin/gameProfiles/default/000500001014d900.ini index b3fae051..d234ff8a 100644 --- a/bin/gameProfiles/default/000500001014d900.ini +++ b/bin/gameProfiles/default/000500001014d900.ini @@ -1,4 +1 @@ -# PUYO PUYO TETRIS (JPN) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# PUYO PUYO TETRIS (JPN) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010154600.ini b/bin/gameProfiles/default/0005000010154600.ini index 8bdd8b98..d5af6dc0 100644 --- a/bin/gameProfiles/default/0005000010154600.ini +++ b/bin/gameProfiles/default/0005000010154600.ini @@ -4,5 +4,4 @@ cpuMode = Singlecore-Recompiler [Graphics] -GPUBufferCacheAccuracy = 0 streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001015b200.ini b/bin/gameProfiles/default/000500001015b200.ini index fd7aad16..a3872d6f 100644 --- a/bin/gameProfiles/default/000500001015b200.ini +++ b/bin/gameProfiles/default/000500001015b200.ini @@ -1,4 +1 @@ -# Child of Light (USA) - -[Graphics] -GPUBufferCacheAccuracy = 1 \ No newline at end of file +# Child of Light (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010161a00.ini b/bin/gameProfiles/default/0005000010161a00.ini index 8bd28664..88e02890 100644 --- a/bin/gameProfiles/default/0005000010161a00.ini +++ b/bin/gameProfiles/default/0005000010161a00.ini @@ -1,4 +1 @@ -# How to Train Your Dragon 2 (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# How to Train Your Dragon 2 (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010162200.ini b/bin/gameProfiles/default/0005000010162200.ini index 70e5edf4..66363dfe 100644 --- a/bin/gameProfiles/default/0005000010162200.ini +++ b/bin/gameProfiles/default/0005000010162200.ini @@ -1,4 +1 @@ -# Monkey Pirates (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Monkey Pirates (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010162a00.ini b/bin/gameProfiles/default/0005000010162a00.ini index e20011d0..3df87ebb 100644 --- a/bin/gameProfiles/default/0005000010162a00.ini +++ b/bin/gameProfiles/default/0005000010162a00.ini @@ -1,4 +1 @@ -# How to Train Your Dragon 2 (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# How to Train Your Dragon 2 (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010162b00.ini b/bin/gameProfiles/default/0005000010162b00.ini index 9802ca1d..8a50f6f6 100644 --- a/bin/gameProfiles/default/0005000010162b00.ini +++ b/bin/gameProfiles/default/0005000010162b00.ini @@ -1,6 +1 @@ -# Splatoon (JPN) - -[CPU] - -[Graphics] -GPUBufferCacheAccuracy = 2 \ No newline at end of file +# Splatoon (JPN) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001016a200.ini b/bin/gameProfiles/default/000500001016a200.ini index da6a7805..655bc980 100644 --- a/bin/gameProfiles/default/000500001016a200.ini +++ b/bin/gameProfiles/default/000500001016a200.ini @@ -1,4 +1 @@ -# Bombing Bastards (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Bombing Bastards (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001016ab00.ini b/bin/gameProfiles/default/000500001016ab00.ini index 0090ca58..594d783c 100644 --- a/bin/gameProfiles/default/000500001016ab00.ini +++ b/bin/gameProfiles/default/000500001016ab00.ini @@ -1,4 +1 @@ -# Bombing Bastards (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Bombing Bastards (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001016b200.ini b/bin/gameProfiles/default/000500001016b200.ini index 9dd87948..4db2bc79 100644 --- a/bin/gameProfiles/default/000500001016b200.ini +++ b/bin/gameProfiles/default/000500001016b200.ini @@ -6,6 +6,3 @@ useRDTSC = false [CPU] cpuTimer = cycleCounter cpuMode = Singlecore-Interpreter - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001016d400.ini b/bin/gameProfiles/default/000500001016d400.ini index 74f031ec..56c1c0f8 100644 --- a/bin/gameProfiles/default/000500001016d400.ini +++ b/bin/gameProfiles/default/000500001016d400.ini @@ -1,4 +1 @@ -# Stick It to the Man (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Stick It to the Man (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001016d800.ini b/bin/gameProfiles/default/000500001016d800.ini index 3cd2b3d0..6a8a95b8 100644 --- a/bin/gameProfiles/default/000500001016d800.ini +++ b/bin/gameProfiles/default/000500001016d800.ini @@ -1,4 +1 @@ -# Child of Light (JPN) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Child of Light (JPN) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001016da00.ini b/bin/gameProfiles/default/000500001016da00.ini index 105b4406..d54f4f50 100644 --- a/bin/gameProfiles/default/000500001016da00.ini +++ b/bin/gameProfiles/default/000500001016da00.ini @@ -2,6 +2,3 @@ [CPU] cpuMode = Singlecore-Interpreter - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001016e000.ini b/bin/gameProfiles/default/000500001016e000.ini index 871da06e..c9ef12e2 100644 --- a/bin/gameProfiles/default/000500001016e000.ini +++ b/bin/gameProfiles/default/000500001016e000.ini @@ -1,4 +1 @@ -# Stick It to the Man (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Stick It to the Man (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001016e800.ini b/bin/gameProfiles/default/000500001016e800.ini index 13482456..4e578c17 100644 --- a/bin/gameProfiles/default/000500001016e800.ini +++ b/bin/gameProfiles/default/000500001016e800.ini @@ -6,6 +6,3 @@ useRDTSC = false [CPU] cpuTimer = cycleCounter cpuMode = Singlecore-Interpreter - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001016ea00.ini b/bin/gameProfiles/default/000500001016ea00.ini index 6d72c2a2..50723312 100644 --- a/bin/gameProfiles/default/000500001016ea00.ini +++ b/bin/gameProfiles/default/000500001016ea00.ini @@ -1,4 +1 @@ -# Child of Light (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 1 \ No newline at end of file +# Child of Light (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001016fc00.ini b/bin/gameProfiles/default/000500001016fc00.ini index edd44103..9ac3ba4b 100644 --- a/bin/gameProfiles/default/000500001016fc00.ini +++ b/bin/gameProfiles/default/000500001016fc00.ini @@ -1,5 +1,4 @@ # Aqua Moto Racing Utopia (USA) -[GPU] -GPUBufferCacheAccuracy = 0 +[Graphics] streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010170100.ini b/bin/gameProfiles/default/0005000010170100.ini index 848f53ff..3de1dd34 100644 --- a/bin/gameProfiles/default/0005000010170100.ini +++ b/bin/gameProfiles/default/0005000010170100.ini @@ -1,4 +1 @@ -# Monkey Pirates (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Monkey Pirates (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010172900.ini b/bin/gameProfiles/default/0005000010172900.ini index 0414258a..5ed40dd0 100644 --- a/bin/gameProfiles/default/0005000010172900.ini +++ b/bin/gameProfiles/default/0005000010172900.ini @@ -1,5 +1,4 @@ # Aqua Moto Racing Utopia (EUR) -[GPU] -GPUBufferCacheAccuracy = 0 +[Graphics] streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010173400.ini b/bin/gameProfiles/default/0005000010173400.ini index 99995af4..c4062977 100644 --- a/bin/gameProfiles/default/0005000010173400.ini +++ b/bin/gameProfiles/default/0005000010173400.ini @@ -1,4 +1 @@ -# Transformers: Rise of the Dark Spark (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Transformers: Rise of the Dark Spark (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010176300.ini b/bin/gameProfiles/default/0005000010176300.ini index c8e0861c..30305418 100644 --- a/bin/gameProfiles/default/0005000010176300.ini +++ b/bin/gameProfiles/default/0005000010176300.ini @@ -1,5 +1,4 @@ # Little Inferno (JPN) -[CPU] +[Graphics] extendedTextureReadback = true -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010176900.ini b/bin/gameProfiles/default/0005000010176900.ini index d6d36fb8..852c383a 100644 --- a/bin/gameProfiles/default/0005000010176900.ini +++ b/bin/gameProfiles/default/0005000010176900.ini @@ -1,6 +1 @@ -# Splatoon (USA) - -[CPU] - -[Graphics] -GPUBufferCacheAccuracy = 2 \ No newline at end of file +# Splatoon (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010176a00.ini b/bin/gameProfiles/default/0005000010176a00.ini index f52d1658..e1dc631b 100644 --- a/bin/gameProfiles/default/0005000010176a00.ini +++ b/bin/gameProfiles/default/0005000010176a00.ini @@ -1,6 +1 @@ -# Splatoon (EUR) - -[CPU] - -[Graphics] -GPUBufferCacheAccuracy = 2 \ No newline at end of file +# Splatoon (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010177000.ini b/bin/gameProfiles/default/0005000010177000.ini index 1c47b1dc..bc7eebf4 100644 --- a/bin/gameProfiles/default/0005000010177000.ini +++ b/bin/gameProfiles/default/0005000010177000.ini @@ -1,4 +1 @@ -# Hello Kitty Kruisers (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Hello Kitty Kruisers (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010177500.ini b/bin/gameProfiles/default/0005000010177500.ini index 74a0a58e..90be1c63 100644 --- a/bin/gameProfiles/default/0005000010177500.ini +++ b/bin/gameProfiles/default/0005000010177500.ini @@ -2,6 +2,3 @@ [CPU] cpuMode = Singlecore-Interpreter - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010177600.ini b/bin/gameProfiles/default/0005000010177600.ini index 05792513..d1b955f1 100644 --- a/bin/gameProfiles/default/0005000010177600.ini +++ b/bin/gameProfiles/default/0005000010177600.ini @@ -1,5 +1,4 @@ # Devil's Third (USA) [Graphics] -GPUBufferCacheAccuracy = 0 streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010177700.ini b/bin/gameProfiles/default/0005000010177700.ini index 072db711..e311f0ba 100644 --- a/bin/gameProfiles/default/0005000010177700.ini +++ b/bin/gameProfiles/default/0005000010177700.ini @@ -1,5 +1,4 @@ # Devil's Third (EUR) [Graphics] -GPUBufferCacheAccuracy = 0 streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001017da00.ini b/bin/gameProfiles/default/000500001017da00.ini index 6fc7282a..09b07927 100644 --- a/bin/gameProfiles/default/000500001017da00.ini +++ b/bin/gameProfiles/default/000500001017da00.ini @@ -1,4 +1 @@ -# Costume Quest 2 (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Costume Quest 2 (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001017e400.ini b/bin/gameProfiles/default/000500001017e400.ini index 562aa77a..723a374c 100644 --- a/bin/gameProfiles/default/000500001017e400.ini +++ b/bin/gameProfiles/default/000500001017e400.ini @@ -1,4 +1 @@ -# Chasing Dead (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 +# Chasing Dead (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010180500.ini b/bin/gameProfiles/default/0005000010180500.ini index d9258613..87ea51b5 100644 --- a/bin/gameProfiles/default/0005000010180500.ini +++ b/bin/gameProfiles/default/0005000010180500.ini @@ -1,7 +1,4 @@ # Captain Toad: Treasure Tracker (JPN) -[CPU] - [Graphics] accurateShaderMul = false -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010180600.ini b/bin/gameProfiles/default/0005000010180600.ini index e7d7e325..8b2528e3 100644 --- a/bin/gameProfiles/default/0005000010180600.ini +++ b/bin/gameProfiles/default/0005000010180600.ini @@ -1,7 +1,4 @@ # Captain Toad: Treasure Tracker (USA) -[CPU] - [Graphics] accurateShaderMul = false -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010180700.ini b/bin/gameProfiles/default/0005000010180700.ini index d0b7d792..3a7a8fe6 100644 --- a/bin/gameProfiles/default/0005000010180700.ini +++ b/bin/gameProfiles/default/0005000010180700.ini @@ -1,7 +1,4 @@ # Captain Toad: Treasure Tracker (EUR) -[CPU] - [Graphics] accurateShaderMul = false -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010183000.ini b/bin/gameProfiles/default/0005000010183000.ini index 5b79f8a9..4b1c07cf 100644 --- a/bin/gameProfiles/default/0005000010183000.ini +++ b/bin/gameProfiles/default/0005000010183000.ini @@ -1,7 +1 @@ -# Runbow (USA) - - - -[Graphics] - -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Runbow (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010184900.ini b/bin/gameProfiles/default/0005000010184900.ini index 8c4d5b59..c3aac8e8 100644 --- a/bin/gameProfiles/default/0005000010184900.ini +++ b/bin/gameProfiles/default/0005000010184900.ini @@ -1,4 +1 @@ -# Slender: The Arrival (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Slender: The Arrival (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010184E00.ini b/bin/gameProfiles/default/0005000010184E00.ini index 3ca24eda..4b282824 100644 --- a/bin/gameProfiles/default/0005000010184E00.ini +++ b/bin/gameProfiles/default/0005000010184E00.ini @@ -1,6 +1 @@ -# Yoshi's Woolly World (EUR) - -[CPU] - -[Graphics] -GPUBufferCacheAccuracy = 2 \ No newline at end of file +# Yoshi's Woolly World (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010184d00.ini b/bin/gameProfiles/default/0005000010184d00.ini index 83a64a5e..b1bb76a7 100644 --- a/bin/gameProfiles/default/0005000010184d00.ini +++ b/bin/gameProfiles/default/0005000010184d00.ini @@ -1,6 +1 @@ -# Yoshi's Woolly World (USA) - -[CPU] - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Yoshi's Woolly World (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010185400.ini b/bin/gameProfiles/default/0005000010185400.ini index c69416ee..efd26cbb 100644 --- a/bin/gameProfiles/default/0005000010185400.ini +++ b/bin/gameProfiles/default/0005000010185400.ini @@ -1,6 +1 @@ -# TLoZ: Wind Waker HD (JPN) - -[CPU] - -[Graphics] -GPUBufferCacheAccuracy = 2 \ No newline at end of file +# TLoZ: Wind Waker HD (JPN) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010189f00.ini b/bin/gameProfiles/default/0005000010189f00.ini index a88c6891..ae998084 100644 --- a/bin/gameProfiles/default/0005000010189f00.ini +++ b/bin/gameProfiles/default/0005000010189f00.ini @@ -2,6 +2,3 @@ [CPU] cpuTimer = hostBased - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001018ab00.ini b/bin/gameProfiles/default/000500001018ab00.ini index 9eeef2ff..cd66a1a3 100644 --- a/bin/gameProfiles/default/000500001018ab00.ini +++ b/bin/gameProfiles/default/000500001018ab00.ini @@ -1,4 +1 @@ -# Affordable Space Adventures (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 +# Affordable Space Adventures (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001018d800.ini b/bin/gameProfiles/default/000500001018d800.ini index 0e311245..196b4aba 100644 --- a/bin/gameProfiles/default/000500001018d800.ini +++ b/bin/gameProfiles/default/000500001018d800.ini @@ -1,4 +1 @@ -# SteamWorld Dig (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# SteamWorld Dig (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001018d900.ini b/bin/gameProfiles/default/000500001018d900.ini index 4e8d8ead..779035e1 100644 --- a/bin/gameProfiles/default/000500001018d900.ini +++ b/bin/gameProfiles/default/000500001018d900.ini @@ -2,6 +2,3 @@ [General] loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001018f100.ini b/bin/gameProfiles/default/000500001018f100.ini index 1a3c5fba..46ffcf0e 100644 --- a/bin/gameProfiles/default/000500001018f100.ini +++ b/bin/gameProfiles/default/000500001018f100.ini @@ -1,4 +1 @@ -# SteamWorld Dig (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# SteamWorld Dig (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001018f400.ini b/bin/gameProfiles/default/000500001018f400.ini index ecf014cf..a22052e4 100644 --- a/bin/gameProfiles/default/000500001018f400.ini +++ b/bin/gameProfiles/default/000500001018f400.ini @@ -1,4 +1 @@ -# Angry Video Game Nerd Adventures (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Angry Video Game Nerd Adventures (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001018fd00.ini b/bin/gameProfiles/default/000500001018fd00.ini index 119e00c4..eaef68fe 100644 --- a/bin/gameProfiles/default/000500001018fd00.ini +++ b/bin/gameProfiles/default/000500001018fd00.ini @@ -1,4 +1 @@ -# The Penguins of Madagascar (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# The Penguins of Madagascar (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010190300.ini b/bin/gameProfiles/default/0005000010190300.ini index b9a41d4f..fe197295 100644 --- a/bin/gameProfiles/default/0005000010190300.ini +++ b/bin/gameProfiles/default/0005000010190300.ini @@ -5,7 +5,4 @@ useRDTSC = false [CPU] cpuMode = Singlecore-Recompiler -cpuTimer = cycleCounter - -[Graphics] -GPUBufferCacheAccuracy = 1 \ No newline at end of file +cpuTimer = cycleCounter \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010193f00.ini b/bin/gameProfiles/default/0005000010193f00.ini index 9d7f8a63..104a88ca 100644 --- a/bin/gameProfiles/default/0005000010193f00.ini +++ b/bin/gameProfiles/default/0005000010193f00.ini @@ -1,4 +1 @@ -# The Penguins of Madagascar (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# The Penguins of Madagascar (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010195e00.ini b/bin/gameProfiles/default/0005000010195e00.ini index 23d72923..23585737 100644 --- a/bin/gameProfiles/default/0005000010195e00.ini +++ b/bin/gameProfiles/default/0005000010195e00.ini @@ -1,4 +1 @@ -# Rock Zombie (US) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Rock Zombie (US) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010197300.ini b/bin/gameProfiles/default/0005000010197300.ini index e15f1c7d..6f2dfa48 100644 --- a/bin/gameProfiles/default/0005000010197300.ini +++ b/bin/gameProfiles/default/0005000010197300.ini @@ -1,4 +1 @@ -# Electronic Super Joy Groove City (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Electronic Super Joy Groove City (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010197800.ini b/bin/gameProfiles/default/0005000010197800.ini index 92839df2..2af2ef33 100644 --- a/bin/gameProfiles/default/0005000010197800.ini +++ b/bin/gameProfiles/default/0005000010197800.ini @@ -1,4 +1 @@ -# Costume Quest 2 (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Costume Quest 2 (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010199e00.ini b/bin/gameProfiles/default/0005000010199e00.ini index 12c31235..01e1f2d5 100644 --- a/bin/gameProfiles/default/0005000010199e00.ini +++ b/bin/gameProfiles/default/0005000010199e00.ini @@ -1,4 +1 @@ -# High Strangeness (US) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# High Strangeness (US) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001019ab00.ini b/bin/gameProfiles/default/000500001019ab00.ini index 12c31235..01e1f2d5 100644 --- a/bin/gameProfiles/default/000500001019ab00.ini +++ b/bin/gameProfiles/default/000500001019ab00.ini @@ -1,4 +1 @@ -# High Strangeness (US) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# High Strangeness (US) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001019b000.ini b/bin/gameProfiles/default/000500001019b000.ini index 23e77a87..c458883f 100644 --- a/bin/gameProfiles/default/000500001019b000.ini +++ b/bin/gameProfiles/default/000500001019b000.ini @@ -1,4 +1 @@ -# Tachyon Project (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Tachyon Project (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001019b200.ini b/bin/gameProfiles/default/000500001019b200.ini index 6790a314..3e893f12 100644 --- a/bin/gameProfiles/default/000500001019b200.ini +++ b/bin/gameProfiles/default/000500001019b200.ini @@ -1,4 +1 @@ -# Tachyon Project (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Tachyon Project (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001019ca00.ini b/bin/gameProfiles/default/000500001019ca00.ini index 9187ed88..f79dd190 100644 --- a/bin/gameProfiles/default/000500001019ca00.ini +++ b/bin/gameProfiles/default/000500001019ca00.ini @@ -1,4 +1 @@ -# Rock Zombie (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Rock Zombie (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001019e500.ini b/bin/gameProfiles/default/000500001019e500.ini index 0ee89ea1..eec28dc9 100644 --- a/bin/gameProfiles/default/000500001019e500.ini +++ b/bin/gameProfiles/default/000500001019e500.ini @@ -1,6 +1 @@ -# TLoZ: Twilight Princess (US) - -[CPU] - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# TLoZ: Twilight Princess (US) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001019e600.ini b/bin/gameProfiles/default/000500001019e600.ini index 4f3aeecb..47380cbe 100644 --- a/bin/gameProfiles/default/000500001019e600.ini +++ b/bin/gameProfiles/default/000500001019e600.ini @@ -1,6 +1 @@ -# TLoZ: Twilight Princess (EU) - -[CPU] - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# TLoZ: Twilight Princess (EU) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001019ea00.ini b/bin/gameProfiles/default/000500001019ea00.ini index f69c7740..49250a19 100644 --- a/bin/gameProfiles/default/000500001019ea00.ini +++ b/bin/gameProfiles/default/000500001019ea00.ini @@ -1,4 +1 @@ -# Zombeer (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Zombeer (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001019ee00.ini b/bin/gameProfiles/default/000500001019ee00.ini index accf6993..958d2f84 100644 --- a/bin/gameProfiles/default/000500001019ee00.ini +++ b/bin/gameProfiles/default/000500001019ee00.ini @@ -1,4 +1 @@ -# Zombie Defense (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Zombie Defense (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101C9300.ini b/bin/gameProfiles/default/00050000101C9300.ini index f3c94e8f..09f0706d 100644 --- a/bin/gameProfiles/default/00050000101C9300.ini +++ b/bin/gameProfiles/default/00050000101C9300.ini @@ -3,4 +3,3 @@ [Graphics] disableGPUFence = false accurateShaderMul = true -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101E4100.ini b/bin/gameProfiles/default/00050000101E4100.ini index 71176e83..8b8165b1 100644 --- a/bin/gameProfiles/default/00050000101E4100.ini +++ b/bin/gameProfiles/default/00050000101E4100.ini @@ -2,6 +2,3 @@ [CPU] cpuMode = Singlecore-Recompiler - -[Graphics] -GPUBufferCacheAccuracy = 1 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101a1200.ini b/bin/gameProfiles/default/00050000101a1200.ini index 76b1207a..4ff51799 100644 --- a/bin/gameProfiles/default/00050000101a1200.ini +++ b/bin/gameProfiles/default/00050000101a1200.ini @@ -1,5 +1 @@ -# Affordable Space Adventures (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 - +# Affordable Space Adventures (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101a1800.ini b/bin/gameProfiles/default/00050000101a1800.ini index 94c50e45..56dd856c 100644 --- a/bin/gameProfiles/default/00050000101a1800.ini +++ b/bin/gameProfiles/default/00050000101a1800.ini @@ -1,4 +1 @@ -# Zombie Defense (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Zombie Defense (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101a3b00.ini b/bin/gameProfiles/default/00050000101a3b00.ini index 2efa5016..44ec4fcb 100644 --- a/bin/gameProfiles/default/00050000101a3b00.ini +++ b/bin/gameProfiles/default/00050000101a3b00.ini @@ -1,4 +1 @@ -# Life of Pixel (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Life of Pixel (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101a4300.ini b/bin/gameProfiles/default/00050000101a4300.ini index 1c49a9ab..80c72ed3 100644 --- a/bin/gameProfiles/default/00050000101a4300.ini +++ b/bin/gameProfiles/default/00050000101a4300.ini @@ -1,4 +1 @@ -# Beatbuddy (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Beatbuddy (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101a4800.ini b/bin/gameProfiles/default/00050000101a4800.ini index bb446c86..64e552e9 100644 --- a/bin/gameProfiles/default/00050000101a4800.ini +++ b/bin/gameProfiles/default/00050000101a4800.ini @@ -2,6 +2,3 @@ [General] loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101a4900.ini b/bin/gameProfiles/default/00050000101a4900.ini index 74fedef3..3bb54df4 100644 --- a/bin/gameProfiles/default/00050000101a4900.ini +++ b/bin/gameProfiles/default/00050000101a4900.ini @@ -1,4 +1 @@ -# Life of Pixel (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Life of Pixel (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101a7f00.ini b/bin/gameProfiles/default/00050000101a7f00.ini index 35f91d55..be575b52 100644 --- a/bin/gameProfiles/default/00050000101a7f00.ini +++ b/bin/gameProfiles/default/00050000101a7f00.ini @@ -1,4 +1 @@ -# Shiftlings (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Shiftlings (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101a9c00.ini b/bin/gameProfiles/default/00050000101a9c00.ini index 651c8c01..6df3d13a 100644 --- a/bin/gameProfiles/default/00050000101a9c00.ini +++ b/bin/gameProfiles/default/00050000101a9c00.ini @@ -1,4 +1 @@ -# Chompy Chomp Chomp Party (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Chompy Chomp Chomp Party (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101a9e00.ini b/bin/gameProfiles/default/00050000101a9e00.ini index 5fbd157c..a8853119 100644 --- a/bin/gameProfiles/default/00050000101a9e00.ini +++ b/bin/gameProfiles/default/00050000101a9e00.ini @@ -1,4 +1 @@ -# Chompy Chomp Chomp Party (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Chompy Chomp Chomp Party (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101acc00.ini b/bin/gameProfiles/default/00050000101acc00.ini index d94071ac..6dae9607 100644 --- a/bin/gameProfiles/default/00050000101acc00.ini +++ b/bin/gameProfiles/default/00050000101acc00.ini @@ -1,4 +1 @@ -# Shiftlings (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Shiftlings (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101b0100.ini b/bin/gameProfiles/default/00050000101b0100.ini index ed2f7bf9..1599daed 100644 --- a/bin/gameProfiles/default/00050000101b0100.ini +++ b/bin/gameProfiles/default/00050000101b0100.ini @@ -1,4 +1 @@ -# Funk of Titans (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Funk of Titans (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101b4e00.ini b/bin/gameProfiles/default/00050000101b4e00.ini index 38642cbe..a0b90655 100644 --- a/bin/gameProfiles/default/00050000101b4e00.ini +++ b/bin/gameProfiles/default/00050000101b4e00.ini @@ -1,4 +1 @@ -# Funk of Titans (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Funk of Titans (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101b9900.ini b/bin/gameProfiles/default/00050000101b9900.ini index ae410226..2e83fe40 100644 --- a/bin/gameProfiles/default/00050000101b9900.ini +++ b/bin/gameProfiles/default/00050000101b9900.ini @@ -2,6 +2,3 @@ [General] loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101bc300.ini b/bin/gameProfiles/default/00050000101bc300.ini index c7ec1da5..e880a0f1 100644 --- a/bin/gameProfiles/default/00050000101bc300.ini +++ b/bin/gameProfiles/default/00050000101bc300.ini @@ -1,4 +1 @@ -# Beatbuddy (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Beatbuddy (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101c3100.ini b/bin/gameProfiles/default/00050000101c3100.ini index d7c2e293..c6f5c569 100644 --- a/bin/gameProfiles/default/00050000101c3100.ini +++ b/bin/gameProfiles/default/00050000101c3100.ini @@ -1,4 +1 @@ -# Freedom Planet (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Freedom Planet (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101c4200.ini b/bin/gameProfiles/default/00050000101c4200.ini index 203ce9a7..c12944a3 100644 --- a/bin/gameProfiles/default/00050000101c4200.ini +++ b/bin/gameProfiles/default/00050000101c4200.ini @@ -1,4 +1 @@ -# The Peanuts Movie: Snoopy's Grand Adventure (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# The Peanuts Movie: Snoopy's Grand Adventure (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101c4300.ini b/bin/gameProfiles/default/00050000101c4300.ini index a2a79f38..549984d4 100644 --- a/bin/gameProfiles/default/00050000101c4300.ini +++ b/bin/gameProfiles/default/00050000101c4300.ini @@ -2,6 +2,3 @@ [CPU] cpuMode = Singlecore-Recompiler - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101c4c00.ini b/bin/gameProfiles/default/00050000101c4c00.ini index 6e8fd71f..08ad5e5b 100644 --- a/bin/gameProfiles/default/00050000101c4c00.ini +++ b/bin/gameProfiles/default/00050000101c4c00.ini @@ -5,4 +5,3 @@ cpuMode = Singlecore-Recompiler [Graphics] accurateShaderMul = false -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101c4d00.ini b/bin/gameProfiles/default/00050000101c4d00.ini index 83301c0d..a1db58b0 100644 --- a/bin/gameProfiles/default/00050000101c4d00.ini +++ b/bin/gameProfiles/default/00050000101c4d00.ini @@ -5,4 +5,3 @@ cpuMode = Singlecore-Recompiler [Graphics] accurateShaderMul = false -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101c6c00.ini b/bin/gameProfiles/default/00050000101c6c00.ini index da9dd712..ff16d037 100644 --- a/bin/gameProfiles/default/00050000101c6c00.ini +++ b/bin/gameProfiles/default/00050000101c6c00.ini @@ -1,4 +1 @@ -# Typoman (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Typoman (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101c7600.ini b/bin/gameProfiles/default/00050000101c7600.ini index 14128c7b..599520e4 100644 --- a/bin/gameProfiles/default/00050000101c7600.ini +++ b/bin/gameProfiles/default/00050000101c7600.ini @@ -1,4 +1 @@ -# Pumped BMX + (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Pumped BMX + (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101c7b00.ini b/bin/gameProfiles/default/00050000101c7b00.ini index 7350d0b5..9b764f96 100644 --- a/bin/gameProfiles/default/00050000101c7b00.ini +++ b/bin/gameProfiles/default/00050000101c7b00.ini @@ -1,4 +1 @@ -# Chronicles of Teddy: Harmony of Exidus (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Chronicles of Teddy: Harmony of Exidus (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101c7d00.ini b/bin/gameProfiles/default/00050000101c7d00.ini index 45ce4448..60a0dd23 100644 --- a/bin/gameProfiles/default/00050000101c7d00.ini +++ b/bin/gameProfiles/default/00050000101c7d00.ini @@ -1,4 +1 @@ -# Pumped BMX + (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Pumped BMX + (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101c9400.ini b/bin/gameProfiles/default/00050000101c9400.ini index 86c1b839..585a9e6f 100644 --- a/bin/gameProfiles/default/00050000101c9400.ini +++ b/bin/gameProfiles/default/00050000101c9400.ini @@ -3,4 +3,3 @@ [Graphics] disableGPUFence = false accurateShaderMul = true -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101c9500.ini b/bin/gameProfiles/default/00050000101c9500.ini index 4f326b32..71485002 100644 --- a/bin/gameProfiles/default/00050000101c9500.ini +++ b/bin/gameProfiles/default/00050000101c9500.ini @@ -3,4 +3,3 @@ [Graphics] disableGPUFence = false accurateShaderMul = true -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101c9a00.ini b/bin/gameProfiles/default/00050000101c9a00.ini index 0cc7525b..026e593f 100644 --- a/bin/gameProfiles/default/00050000101c9a00.ini +++ b/bin/gameProfiles/default/00050000101c9a00.ini @@ -2,6 +2,3 @@ [CPU] cpuMode = Singlecore-Recompiler - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101cc900.ini b/bin/gameProfiles/default/00050000101cc900.ini index dded48b2..ceaa7e67 100644 --- a/bin/gameProfiles/default/00050000101cc900.ini +++ b/bin/gameProfiles/default/00050000101cc900.ini @@ -1,4 +1 @@ -# Freedom Planet (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Freedom Planet (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101ccf00.ini b/bin/gameProfiles/default/00050000101ccf00.ini index e71dfd8f..d3d497f1 100644 --- a/bin/gameProfiles/default/00050000101ccf00.ini +++ b/bin/gameProfiles/default/00050000101ccf00.ini @@ -1,4 +1 @@ -# Never Alone (Kisima Ingitchuna) (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Never Alone (Kisima Ingitchuna) (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101ce000.ini b/bin/gameProfiles/default/00050000101ce000.ini index 69aa9dae..30a271e8 100644 --- a/bin/gameProfiles/default/00050000101ce000.ini +++ b/bin/gameProfiles/default/00050000101ce000.ini @@ -1,4 +1 @@ -# Typoman (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Typoman (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101ce800.ini b/bin/gameProfiles/default/00050000101ce800.ini index 2cc75f8e..902e8e23 100644 --- a/bin/gameProfiles/default/00050000101ce800.ini +++ b/bin/gameProfiles/default/00050000101ce800.ini @@ -1,4 +1 @@ -# Never Alone (Kisima Ingitchuna) (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Never Alone (Kisima Ingitchuna) (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101d2100.ini b/bin/gameProfiles/default/00050000101d2100.ini index caac5cdc..830f5f81 100644 --- a/bin/gameProfiles/default/00050000101d2100.ini +++ b/bin/gameProfiles/default/00050000101d2100.ini @@ -1,5 +1,4 @@ # Little Inferno (US) -[CPU] +[Graphics] extendedTextureReadback = true -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101d4500.ini b/bin/gameProfiles/default/00050000101d4500.ini index 8ae9fc73..c8244324 100644 --- a/bin/gameProfiles/default/00050000101d4500.ini +++ b/bin/gameProfiles/default/00050000101d4500.ini @@ -1,4 +1 @@ -# Grumpy Reaper (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Grumpy Reaper (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101d4d00.ini b/bin/gameProfiles/default/00050000101d4d00.ini index 5df2ddbb..23887c1f 100644 --- a/bin/gameProfiles/default/00050000101d4d00.ini +++ b/bin/gameProfiles/default/00050000101d4d00.ini @@ -1,4 +1 @@ -# Joe's Diner (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Joe's Diner (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101d5000.ini b/bin/gameProfiles/default/00050000101d5000.ini index 2e1b8356..4cff3852 100644 --- a/bin/gameProfiles/default/00050000101d5000.ini +++ b/bin/gameProfiles/default/00050000101d5000.ini @@ -1,4 +1 @@ -# The Peanuts Movie: Snoopy's Grand Adventure (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# The Peanuts Movie: Snoopy's Grand Adventure (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101d5500.ini b/bin/gameProfiles/default/00050000101d5500.ini index 81bcef30..2e1f7542 100644 --- a/bin/gameProfiles/default/00050000101d5500.ini +++ b/bin/gameProfiles/default/00050000101d5500.ini @@ -1,4 +1 @@ -# Joe's Diner (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Joe's Diner (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101d6000.ini b/bin/gameProfiles/default/00050000101d6000.ini index 129477c2..09ff9c3c 100644 --- a/bin/gameProfiles/default/00050000101d6000.ini +++ b/bin/gameProfiles/default/00050000101d6000.ini @@ -2,6 +2,3 @@ [CPU] cpuMode = Singlecore-Recompiler - -[Graphics] -GPUBufferCacheAccuracy = 1 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101d6d00.ini b/bin/gameProfiles/default/00050000101d6d00.ini index 0bf677ba..a04e39c7 100644 --- a/bin/gameProfiles/default/00050000101d6d00.ini +++ b/bin/gameProfiles/default/00050000101d6d00.ini @@ -1,7 +1 @@ -# Runbow (EUR) - - - -[Graphics] - -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Runbow (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101d7500.ini b/bin/gameProfiles/default/00050000101d7500.ini index 8707efcd..992b00cc 100644 --- a/bin/gameProfiles/default/00050000101d7500.ini +++ b/bin/gameProfiles/default/00050000101d7500.ini @@ -2,6 +2,3 @@ [General] loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101d8900.ini b/bin/gameProfiles/default/00050000101d8900.ini index 29b9698f..aaf7d122 100644 --- a/bin/gameProfiles/default/00050000101d8900.ini +++ b/bin/gameProfiles/default/00050000101d8900.ini @@ -1,4 +1 @@ -# Slender: The Arrival (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Slender: The Arrival (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101d8d00.ini b/bin/gameProfiles/default/00050000101d8d00.ini index 864c446b..0b61b998 100644 --- a/bin/gameProfiles/default/00050000101d8d00.ini +++ b/bin/gameProfiles/default/00050000101d8d00.ini @@ -1,4 +1 @@ -# Rock 'N Racing Off Road DX (USA) - -[Graphics] -GPUBufferCacheAccuracy = 1 \ No newline at end of file +# Rock 'N Racing Off Road DX (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101d9600.ini b/bin/gameProfiles/default/00050000101d9600.ini index c2c62b6a..aa4f9a10 100644 --- a/bin/gameProfiles/default/00050000101d9600.ini +++ b/bin/gameProfiles/default/00050000101d9600.ini @@ -1,4 +1 @@ -# Rock 'N Racing Off Road DX (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 1 \ No newline at end of file +# Rock 'N Racing Off Road DX (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101d9d00.ini b/bin/gameProfiles/default/00050000101d9d00.ini index dc54dea2..30d07833 100644 --- a/bin/gameProfiles/default/00050000101d9d00.ini +++ b/bin/gameProfiles/default/00050000101d9d00.ini @@ -2,6 +2,3 @@ [General] loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101dac00.ini b/bin/gameProfiles/default/00050000101dac00.ini index 1780613f..bb988dac 100644 --- a/bin/gameProfiles/default/00050000101dac00.ini +++ b/bin/gameProfiles/default/00050000101dac00.ini @@ -1,4 +1 @@ -# Swap Fire - -[GPU] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Swap Fire \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101daf00.ini b/bin/gameProfiles/default/00050000101daf00.ini index 2c8bef7b..3ebc182e 100644 --- a/bin/gameProfiles/default/00050000101daf00.ini +++ b/bin/gameProfiles/default/00050000101daf00.ini @@ -1,4 +1 @@ -# Chronicles of Teddy: Harmony of Exidus (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Chronicles of Teddy: Harmony of Exidus (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101db000.ini b/bin/gameProfiles/default/00050000101db000.ini index 94736dbb..fafb6333 100644 --- a/bin/gameProfiles/default/00050000101db000.ini +++ b/bin/gameProfiles/default/00050000101db000.ini @@ -1,4 +1 @@ -# Oddworld New 'n' Tasty (US) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Oddworld New 'n' Tasty (US) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101dbb00.ini b/bin/gameProfiles/default/00050000101dbb00.ini index 092b54ec..7e08923d 100644 --- a/bin/gameProfiles/default/00050000101dbb00.ini +++ b/bin/gameProfiles/default/00050000101dbb00.ini @@ -1,4 +1 @@ -# Oddworld New 'n' Tasty (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Oddworld New 'n' Tasty (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101dbc00.ini b/bin/gameProfiles/default/00050000101dbc00.ini index 98c41e22..94808fc1 100644 --- a/bin/gameProfiles/default/00050000101dbc00.ini +++ b/bin/gameProfiles/default/00050000101dbc00.ini @@ -1,4 +1 @@ -# Star Ghost (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Star Ghost (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101dbe00.ini b/bin/gameProfiles/default/00050000101dbe00.ini index 66ec5de9..0145c649 100644 --- a/bin/gameProfiles/default/00050000101dbe00.ini +++ b/bin/gameProfiles/default/00050000101dbe00.ini @@ -1,7 +1,4 @@ # Minecraft: Wii U Edition (JPN) [General] -loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +loadSharedLibraries = false \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101dbf00.ini b/bin/gameProfiles/default/00050000101dbf00.ini index 6f32b59d..6cab37ad 100644 --- a/bin/gameProfiles/default/00050000101dbf00.ini +++ b/bin/gameProfiles/default/00050000101dbf00.ini @@ -1,4 +1 @@ -# Angry Video Game Nerd Adventures (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Angry Video Game Nerd Adventures (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101dc000.ini b/bin/gameProfiles/default/00050000101dc000.ini index b4b8717c..8734af28 100644 --- a/bin/gameProfiles/default/00050000101dc000.ini +++ b/bin/gameProfiles/default/00050000101dc000.ini @@ -1,4 +1 @@ -# Vektor Wars (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Vektor Wars (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101dc200.ini b/bin/gameProfiles/default/00050000101dc200.ini index 0cec8b6d..eebe3ac5 100644 --- a/bin/gameProfiles/default/00050000101dc200.ini +++ b/bin/gameProfiles/default/00050000101dc200.ini @@ -1,4 +1 @@ -# Vektor Wars (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Vektor Wars (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101dd000.ini b/bin/gameProfiles/default/00050000101dd000.ini index 8f275d8c..33caf468 100644 --- a/bin/gameProfiles/default/00050000101dd000.ini +++ b/bin/gameProfiles/default/00050000101dd000.ini @@ -1,4 +1 @@ -# Star Ghost (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Star Ghost (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101dd600.ini b/bin/gameProfiles/default/00050000101dd600.ini index 7b180555..1a17ec4b 100644 --- a/bin/gameProfiles/default/00050000101dd600.ini +++ b/bin/gameProfiles/default/00050000101dd600.ini @@ -1,4 +1 @@ -# BIT.TRIP Presents... Runner2: Future Legend of Rhythm Alien (JPN) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# BIT.TRIP Presents... Runner2: Future Legend of Rhythm Alien (JPN) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101dd700.ini b/bin/gameProfiles/default/00050000101dd700.ini index 57b3a897..fbefda0e 100644 --- a/bin/gameProfiles/default/00050000101dd700.ini +++ b/bin/gameProfiles/default/00050000101dd700.ini @@ -1,7 +1 @@ -# Runbow (JPN) - - - -[Graphics] - -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Runbow (JPN) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101ddf00.ini b/bin/gameProfiles/default/00050000101ddf00.ini index a3adf2fc..5c802484 100644 --- a/bin/gameProfiles/default/00050000101ddf00.ini +++ b/bin/gameProfiles/default/00050000101ddf00.ini @@ -1,4 +1 @@ -# Hive Jump (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Hive Jump (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101e0100.ini b/bin/gameProfiles/default/00050000101e0100.ini index 13f74180..738553d8 100644 --- a/bin/gameProfiles/default/00050000101e0100.ini +++ b/bin/gameProfiles/default/00050000101e0100.ini @@ -1,6 +1 @@ -# Minecraft: Story Mode (USA) - - - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Minecraft: Story Mode (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101e1800.ini b/bin/gameProfiles/default/00050000101e1800.ini index bf35ca87..a372c127 100644 --- a/bin/gameProfiles/default/00050000101e1800.ini +++ b/bin/gameProfiles/default/00050000101e1800.ini @@ -1,4 +1 @@ -# Human Resource Machine (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Human Resource Machine (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101e1a00.ini b/bin/gameProfiles/default/00050000101e1a00.ini index 23dca6a5..a90125c4 100644 --- a/bin/gameProfiles/default/00050000101e1a00.ini +++ b/bin/gameProfiles/default/00050000101e1a00.ini @@ -1,4 +1 @@ -# Human Resource Machine (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Human Resource Machine (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101e1b00.ini b/bin/gameProfiles/default/00050000101e1b00.ini index 5675969a..88e9b456 100644 --- a/bin/gameProfiles/default/00050000101e1b00.ini +++ b/bin/gameProfiles/default/00050000101e1b00.ini @@ -2,6 +2,3 @@ [CPU] cpuTimer = hostBased - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101e3800.ini b/bin/gameProfiles/default/00050000101e3800.ini index 4e6f4859..fdfa2cdf 100644 --- a/bin/gameProfiles/default/00050000101e3800.ini +++ b/bin/gameProfiles/default/00050000101e3800.ini @@ -1,7 +1 @@ -# Dual Core (USA) - -[General] -loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Dual Core (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101e4200.ini b/bin/gameProfiles/default/00050000101e4200.ini index 9e6a983b..ef94b291 100644 --- a/bin/gameProfiles/default/00050000101e4200.ini +++ b/bin/gameProfiles/default/00050000101e4200.ini @@ -6,6 +6,3 @@ useRDTSC = false [CPU] cpuTimer = cycleCounter cpuMode = Singlecore-Interpreter - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101e5300.ini b/bin/gameProfiles/default/00050000101e5300.ini index c6f6674a..c04cd6b6 100644 --- a/bin/gameProfiles/default/00050000101e5300.ini +++ b/bin/gameProfiles/default/00050000101e5300.ini @@ -6,6 +6,3 @@ useRDTSC = false [CPU] cpuMode = Singlecore-Recompiler cpuTimer = cycleCounter - -[Graphics] -GPUBufferCacheAccuracy = 1 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101e5400.ini b/bin/gameProfiles/default/00050000101e5400.ini index 299c9e40..221a23ed 100644 --- a/bin/gameProfiles/default/00050000101e5400.ini +++ b/bin/gameProfiles/default/00050000101e5400.ini @@ -6,6 +6,3 @@ useRDTSC = false [CPU] cpuMode = Singlecore-Recompiler cpuTimer = cycleCounter - -[Graphics] -GPUBufferCacheAccuracy = 1 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101e5e00.ini b/bin/gameProfiles/default/00050000101e5e00.ini index 2736143b..ab9fc348 100644 --- a/bin/gameProfiles/default/00050000101e5e00.ini +++ b/bin/gameProfiles/default/00050000101e5e00.ini @@ -1,4 +1 @@ -# Chasing Dead (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 +# Chasing Dead (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101e7300.ini b/bin/gameProfiles/default/00050000101e7300.ini index de2d9ace..092720b8 100644 --- a/bin/gameProfiles/default/00050000101e7300.ini +++ b/bin/gameProfiles/default/00050000101e7300.ini @@ -1,4 +1 @@ -# The Deer God (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# The Deer God (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101e7400.ini b/bin/gameProfiles/default/00050000101e7400.ini index 38a64064..e8644aa7 100644 --- a/bin/gameProfiles/default/00050000101e7400.ini +++ b/bin/gameProfiles/default/00050000101e7400.ini @@ -1,4 +1 @@ -# Grumpy Reaper (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Grumpy Reaper (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101e9300.ini b/bin/gameProfiles/default/00050000101e9300.ini index a88c29bc..24c0dad8 100644 --- a/bin/gameProfiles/default/00050000101e9300.ini +++ b/bin/gameProfiles/default/00050000101e9300.ini @@ -1,4 +1 @@ -# Gear Gauntlet (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Gear Gauntlet (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101e9400.ini b/bin/gameProfiles/default/00050000101e9400.ini index 6f914578..6b78201e 100644 --- a/bin/gameProfiles/default/00050000101e9400.ini +++ b/bin/gameProfiles/default/00050000101e9400.ini @@ -1,4 +1 @@ -# Gear Gauntlet (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Gear Gauntlet (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101eb300.ini b/bin/gameProfiles/default/00050000101eb300.ini index e5b62760..66c8dcb4 100644 --- a/bin/gameProfiles/default/00050000101eb300.ini +++ b/bin/gameProfiles/default/00050000101eb300.ini @@ -1,4 +1 @@ -# The Beggar's Ride (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# The Beggar's Ride (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101ec700.ini b/bin/gameProfiles/default/00050000101ec700.ini index 27e0f560..7dd85123 100644 --- a/bin/gameProfiles/default/00050000101ec700.ini +++ b/bin/gameProfiles/default/00050000101ec700.ini @@ -1,4 +1 @@ -# The Beggar's Ride (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# The Beggar's Ride (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101ecf00.ini b/bin/gameProfiles/default/00050000101ecf00.ini index 3191607c..e3b80181 100644 --- a/bin/gameProfiles/default/00050000101ecf00.ini +++ b/bin/gameProfiles/default/00050000101ecf00.ini @@ -1,4 +1 @@ -# Buddy & Me Dream Edition (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Buddy & Me Dream Edition (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101f1300.ini b/bin/gameProfiles/default/00050000101f1300.ini index 3b17b3a5..85683631 100644 --- a/bin/gameProfiles/default/00050000101f1300.ini +++ b/bin/gameProfiles/default/00050000101f1300.ini @@ -1,4 +1 @@ -# Armikrog (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Armikrog (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101f2800.ini b/bin/gameProfiles/default/00050000101f2800.ini index 65c08d62..a8d455dd 100644 --- a/bin/gameProfiles/default/00050000101f2800.ini +++ b/bin/gameProfiles/default/00050000101f2800.ini @@ -1,7 +1,4 @@ # 8Bit Hero (USA) -[Graphics] -GPUBufferCacheAccuracy = 0 - [CPU] cpuMode = Singlecore-Interpreter \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101f4a00.ini b/bin/gameProfiles/default/00050000101f4a00.ini index 2d9432da..e0ca60b7 100644 --- a/bin/gameProfiles/default/00050000101f4a00.ini +++ b/bin/gameProfiles/default/00050000101f4a00.ini @@ -1,4 +1 @@ -# Buddy & Me Dream Edition (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Buddy & Me Dream Edition (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101f5700.ini b/bin/gameProfiles/default/00050000101f5700.ini index a2d5119f..c0c98988 100644 --- a/bin/gameProfiles/default/00050000101f5700.ini +++ b/bin/gameProfiles/default/00050000101f5700.ini @@ -1,4 +1 @@ -# Jotun Valhalla Edition (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Jotun Valhalla Edition (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101f6f00.ini b/bin/gameProfiles/default/00050000101f6f00.ini index 92bf8b9e..4a590788 100644 --- a/bin/gameProfiles/default/00050000101f6f00.ini +++ b/bin/gameProfiles/default/00050000101f6f00.ini @@ -1,4 +1 @@ -# Jotun Valhalla Edition (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Jotun Valhalla Edition (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101f7600.ini b/bin/gameProfiles/default/00050000101f7600.ini index 88e55d2a..bbe32dff 100644 --- a/bin/gameProfiles/default/00050000101f7600.ini +++ b/bin/gameProfiles/default/00050000101f7600.ini @@ -1,7 +1 @@ -# Dual Core (EUR) - -[General] -loadSharedLibraries = false - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Dual Core (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101f9700.ini b/bin/gameProfiles/default/00050000101f9700.ini index 34c46581..a36f67a1 100644 --- a/bin/gameProfiles/default/00050000101f9700.ini +++ b/bin/gameProfiles/default/00050000101f9700.ini @@ -1,4 +1 @@ -# Darksiders Warmastered Edition (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Darksiders Warmastered Edition (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101fa600.ini b/bin/gameProfiles/default/00050000101fa600.ini index 89ab8ade..653531f9 100644 --- a/bin/gameProfiles/default/00050000101fa600.ini +++ b/bin/gameProfiles/default/00050000101fa600.ini @@ -1,4 +1 @@ -# Darksiders Warmastered Edition (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Darksiders Warmastered Edition (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101fd100.ini b/bin/gameProfiles/default/00050000101fd100.ini index 6ce5a608..a0f02db2 100644 --- a/bin/gameProfiles/default/00050000101fd100.ini +++ b/bin/gameProfiles/default/00050000101fd100.ini @@ -1,4 +1 @@ -# Grumpy Reaper (JPN) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Grumpy Reaper (JPN) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101ff200.ini b/bin/gameProfiles/default/00050000101ff200.ini index 54e13b65..13b5470b 100644 --- a/bin/gameProfiles/default/00050000101ff200.ini +++ b/bin/gameProfiles/default/00050000101ff200.ini @@ -1,4 +1 @@ -# Exile's End (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Exile's End (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101ffc00.ini b/bin/gameProfiles/default/00050000101ffc00.ini index e01c407c..4d6850ae 100644 --- a/bin/gameProfiles/default/00050000101ffc00.ini +++ b/bin/gameProfiles/default/00050000101ffc00.ini @@ -1,5 +1,4 @@ # Ghost Blade HD (USA) [Graphics] -GPUBufferCacheAccuracy = 0 streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/00050000101ffe00.ini b/bin/gameProfiles/default/00050000101ffe00.ini index 9225f393..123cc4b9 100644 --- a/bin/gameProfiles/default/00050000101ffe00.ini +++ b/bin/gameProfiles/default/00050000101ffe00.ini @@ -1,4 +1 @@ -# Tetrimos (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Tetrimos (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010200300.ini b/bin/gameProfiles/default/0005000010200300.ini index 47600923..b62d3c32 100644 --- a/bin/gameProfiles/default/0005000010200300.ini +++ b/bin/gameProfiles/default/0005000010200300.ini @@ -1,4 +1 @@ -# Armikrog (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Armikrog (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010200b00.ini b/bin/gameProfiles/default/0005000010200b00.ini index 8fc9da4b..7a6469b5 100644 --- a/bin/gameProfiles/default/0005000010200b00.ini +++ b/bin/gameProfiles/default/0005000010200b00.ini @@ -1,4 +1 @@ -# Tetrimos (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Tetrimos (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010204a00.ini b/bin/gameProfiles/default/0005000010204a00.ini index 8a0285c3..e0d9db5a 100644 --- a/bin/gameProfiles/default/0005000010204a00.ini +++ b/bin/gameProfiles/default/0005000010204a00.ini @@ -1,4 +1 @@ -# Exile's End (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Exile's End (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010207300.ini b/bin/gameProfiles/default/0005000010207300.ini index c678e7d6..56d9a42f 100644 --- a/bin/gameProfiles/default/0005000010207300.ini +++ b/bin/gameProfiles/default/0005000010207300.ini @@ -1,4 +1 @@ -# Koi DX (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Koi DX (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010207500.ini b/bin/gameProfiles/default/0005000010207500.ini index 090be3f2..1a4ab56d 100644 --- a/bin/gameProfiles/default/0005000010207500.ini +++ b/bin/gameProfiles/default/0005000010207500.ini @@ -1,4 +1 @@ -# Koi DX (USA) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Koi DX (USA) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001020a200.ini b/bin/gameProfiles/default/000500001020a200.ini index bef0c82e..6960a967 100644 --- a/bin/gameProfiles/default/000500001020a200.ini +++ b/bin/gameProfiles/default/000500001020a200.ini @@ -1,5 +1 @@ -# Minecraft: Story Mode (EUR) - - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Minecraft: Story Mode (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/000500001020b600.ini b/bin/gameProfiles/default/000500001020b600.ini index 74528c38..46e4c8da 100644 --- a/bin/gameProfiles/default/000500001020b600.ini +++ b/bin/gameProfiles/default/000500001020b600.ini @@ -1,5 +1,4 @@ # Ghost Blade HD (EUR) [Graphics] -GPUBufferCacheAccuracy = 0 streamoutBufferCacheSize = 48 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000010211b00.ini b/bin/gameProfiles/default/0005000010211b00.ini index 69534194..7e82f408 100644 --- a/bin/gameProfiles/default/0005000010211b00.ini +++ b/bin/gameProfiles/default/0005000010211b00.ini @@ -1,4 +1 @@ -# Sphere Slice (EUR) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# Sphere Slice (EUR) \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000C1012BC00.ini b/bin/gameProfiles/default/0005000C1012BC00.ini index 5c2c09d4..5f699eb6 100644 --- a/bin/gameProfiles/default/0005000C1012BC00.ini +++ b/bin/gameProfiles/default/0005000C1012BC00.ini @@ -1,8 +1,4 @@ # Pikmin 3 (JAP) - - [Graphics] - extendedTextureReadback = true -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000C1012BD00.ini b/bin/gameProfiles/default/0005000C1012BD00.ini index 8ab10175..cd27ff77 100644 --- a/bin/gameProfiles/default/0005000C1012BD00.ini +++ b/bin/gameProfiles/default/0005000C1012BD00.ini @@ -1,8 +1,4 @@ # Pikmin 3 (USA) - - [Graphics] - extendedTextureReadback = true -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000C1012BE00.ini b/bin/gameProfiles/default/0005000C1012BE00.ini index e7226ef4..6be6a929 100644 --- a/bin/gameProfiles/default/0005000C1012BE00.ini +++ b/bin/gameProfiles/default/0005000C1012BE00.ini @@ -1,8 +1,4 @@ # Pikmin 3 (EU) - - [Graphics] - extendedTextureReadback = true -GPUBufferCacheAccuracy = 2 \ No newline at end of file diff --git a/bin/gameProfiles/default/0005000e1019c800.ini b/bin/gameProfiles/default/0005000e1019c800.ini index 8c47898c..81adc4c9 100644 --- a/bin/gameProfiles/default/0005000e1019c800.ini +++ b/bin/gameProfiles/default/0005000e1019c800.ini @@ -1,4 +1 @@ -# TLoZ: Twilight Princess (JPN) - -[Graphics] -GPUBufferCacheAccuracy = 0 \ No newline at end of file +# TLoZ: Twilight Princess (JPN) \ No newline at end of file From 1bcc064593545ff3603521f24e7d32c8b8adabab Mon Sep 17 00:00:00 2001 From: Tillsunset <35825944+Tillsunset@users.noreply.github.com> Date: Sun, 23 Oct 2022 06:06:20 -0500 Subject: [PATCH 066/638] Add check for "." in FSC path (#402) --- src/Cafe/Filesystem/FST/fstUtil.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Cafe/Filesystem/FST/fstUtil.h b/src/Cafe/Filesystem/FST/fstUtil.h index 4ea9465d..01283684 100644 --- a/src/Cafe/Filesystem/FST/fstUtil.h +++ b/src/Cafe/Filesystem/FST/fstUtil.h @@ -28,6 +28,8 @@ class FSCPath { if (m_names.size() > 0xFFFF) return; + if (nameLen == 1 && *name == '.') + return; m_nodes.emplace_back((uint16)m_names.size(), nameLen); m_names.insert(m_names.end(), name, name + nameLen); } @@ -297,6 +299,12 @@ static void FSTPathUnitTest() cemu_assert_debug(p6.GetNodeCount() == 0); p6 = FSCPath("/////////////"); cemu_assert_debug(p6.GetNodeCount() == 0); + // test 7 - periods in path + FSCPath p7("/vol/content/./.."); + cemu_assert_debug(p7.GetNodeCount() == 3); + cemu_assert_debug(p7.MatchNodeName(0, "vol")); + cemu_assert_debug(p7.MatchNodeName(1, "content")); + cemu_assert_debug(p7.MatchNodeName(2, "..")); } From c40466f3a8d12a34ca1a82b596af18dd56a3ec2b Mon Sep 17 00:00:00 2001 From: Jeremy Kescher Date: Sun, 23 Oct 2022 12:03:51 +0000 Subject: [PATCH 067/638] Fix incorrect title ID (00050000-1011000? -> 00050000-10111000) (#404) --- .../default/{000500001011000.ini => 0005000010111000.ini} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename bin/gameProfiles/default/{000500001011000.ini => 0005000010111000.ini} (100%) diff --git a/bin/gameProfiles/default/000500001011000.ini b/bin/gameProfiles/default/0005000010111000.ini similarity index 100% rename from bin/gameProfiles/default/000500001011000.ini rename to bin/gameProfiles/default/0005000010111000.ini From 028b3f79926a280b1a6fc5abbd438cc875079b89 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sun, 23 Oct 2022 15:47:42 +0200 Subject: [PATCH 068/638] Make controller button code thread-safe (#405) * Refactor spinlock to meet Lockable requirements * Input: Refactor button code and make it thread-safe --- .../HW/Espresso/Debugger/DebugSymbolStorage.h | 14 +-- src/Cafe/HW/Espresso/PPCTimer.cpp | 4 +- .../HW/Espresso/Recompiler/PPCRecompiler.cpp | 36 +++--- src/Cafe/HW/Latte/Core/FetchShader.cpp | 10 +- src/Cafe/HW/Latte/Core/LatteBufferCache.cpp | 8 +- .../HW/Latte/Renderer/Vulkan/CachedFBOVk.h | 8 +- .../Latte/Renderer/Vulkan/RendererShaderVk.h | 8 +- .../Vulkan/VulkanPipelineStableCache.cpp | 24 ++-- .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 12 +- src/Cafe/IOSU/kernel/iosu_kernel.cpp | 14 +-- .../OS/libs/coreinit/coreinit_Callbacks.cpp | 18 +-- .../OS/libs/coreinit/coreinit_MPQueue.cpp | 8 +- .../coreinit/coreinit_Synchronization.cpp | 4 +- src/Cafe/OS/libs/snd_core/ax_ist.cpp | 4 +- src/Cafe/OS/libs/snd_core/ax_voice.cpp | 12 +- src/gui/guiWrapper.h | 14 +-- src/gui/input/InputSettings2.cpp | 2 +- src/gui/input/panels/InputPanel.cpp | 110 ++++++++--------- src/input/api/Controller.cpp | 24 ++-- src/input/api/ControllerState.h | 111 +++++++++++++++++- src/input/api/DSU/DSUController.cpp | 6 +- .../api/DirectInput/DirectInputController.cpp | 23 ++-- src/input/api/Keyboard/KeyboardController.cpp | 7 +- src/input/api/SDL/SDLController.cpp | 4 +- .../api/Wiimote/NativeWiimoteController.cpp | 13 +- src/input/api/XInput/XInputController.cpp | 2 +- src/input/emulated/EmulatedController.cpp | 8 +- src/util/helpers/fspinlock.h | 23 ++-- 28 files changed, 311 insertions(+), 220 deletions(-) diff --git a/src/Cafe/HW/Espresso/Debugger/DebugSymbolStorage.h b/src/Cafe/HW/Espresso/Debugger/DebugSymbolStorage.h index 0d7b7d49..aba6a9b5 100644 --- a/src/Cafe/HW/Espresso/Debugger/DebugSymbolStorage.h +++ b/src/Cafe/HW/Espresso/Debugger/DebugSymbolStorage.h @@ -24,28 +24,28 @@ class DebugSymbolStorage public: static void StoreDataType(MPTR address, DEBUG_SYMBOL_TYPE type) { - s_lock.acquire(); + s_lock.lock(); s_typeStorage[address] = type; - s_lock.release(); + s_lock.unlock(); } static DEBUG_SYMBOL_TYPE GetDataType(MPTR address) { - s_lock.acquire(); + s_lock.lock(); auto itr = s_typeStorage.find(address); if (itr == s_typeStorage.end()) { - s_lock.release(); + s_lock.unlock(); return DEBUG_SYMBOL_TYPE::UNDEFINED; } DEBUG_SYMBOL_TYPE t = itr->second; - s_lock.release(); + s_lock.unlock(); return t; } static void ClearRange(MPTR address, uint32 length) { - s_lock.acquire(); + s_lock.lock(); while (length > 0) { auto itr = s_typeStorage.find(address); @@ -54,7 +54,7 @@ public: address += 4; length -= 4; } - s_lock.release(); + s_lock.unlock(); } private: diff --git a/src/Cafe/HW/Espresso/PPCTimer.cpp b/src/Cafe/HW/Espresso/PPCTimer.cpp index 36198dac..153458d8 100644 --- a/src/Cafe/HW/Espresso/PPCTimer.cpp +++ b/src/Cafe/HW/Espresso/PPCTimer.cpp @@ -129,7 +129,7 @@ FSpinlock sTimerSpinlock; // thread safe uint64 PPCTimer_getFromRDTSC() { - sTimerSpinlock.acquire(); + sTimerSpinlock.lock(); _mm_mfence(); uint64 rdtscCurrentMeasure = __rdtsc(); uint64 rdtscDif = rdtscCurrentMeasure - _rdtscLastMeasure; @@ -165,6 +165,6 @@ uint64 PPCTimer_getFromRDTSC() _tickSummary += elapsedTick; - sTimerSpinlock.release(); + sTimerSpinlock.unlock(); return _tickSummary; } diff --git a/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp b/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp index 98263ff3..588e5397 100644 --- a/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp @@ -47,20 +47,20 @@ void PPCRecompiler_visitAddressNoBlock(uint32 enterAddress) if (ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[enterAddress / 4] != PPCRecompiler_leaveRecompilerCode_unvisited) return; // try to acquire lock - if (!PPCRecompilerState.recompilerSpinlock.tryAcquire()) + if (!PPCRecompilerState.recompilerSpinlock.try_lock()) return; auto funcPtr = ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[enterAddress / 4]; if (funcPtr != PPCRecompiler_leaveRecompilerCode_unvisited) { // was visited since previous check - PPCRecompilerState.recompilerSpinlock.release(); + PPCRecompilerState.recompilerSpinlock.unlock(); return; } // add to recompilation queue and flag as visited PPCRecompilerState.targetQueue.emplace(enterAddress); ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[enterAddress / 4] = PPCRecompiler_leaveRecompilerCode_visited; - PPCRecompilerState.recompilerSpinlock.release(); + PPCRecompilerState.recompilerSpinlock.unlock(); } void PPCRecompiler_recompileIfUnvisited(uint32 enterAddress) @@ -193,13 +193,13 @@ PPCRecFunction_t* PPCRecompiler_recompileFunction(PPCFunctionBoundaryTracker::PP bool PPCRecompiler_makeRecompiledFunctionActive(uint32 initialEntryPoint, PPCFunctionBoundaryTracker::PPCRange_t& range, PPCRecFunction_t* ppcRecFunc, std::vector>& entryPoints) { // update jump table - PPCRecompilerState.recompilerSpinlock.acquire(); + PPCRecompilerState.recompilerSpinlock.lock(); // check if the initial entrypoint is still flagged for recompilation // its possible that the range has been invalidated during the time it took to translate the function if (ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[initialEntryPoint / 4] != PPCRecompiler_leaveRecompilerCode_visited) { - PPCRecompilerState.recompilerSpinlock.release(); + PPCRecompilerState.recompilerSpinlock.unlock(); return false; } @@ -221,7 +221,7 @@ bool PPCRecompiler_makeRecompiledFunctionActive(uint32 initialEntryPoint, PPCFun PPCRecompilerState.invalidationRanges.clear(); if (isInvalidated) { - PPCRecompilerState.recompilerSpinlock.release(); + PPCRecompilerState.recompilerSpinlock.unlock(); return false; } @@ -249,7 +249,7 @@ bool PPCRecompiler_makeRecompiledFunctionActive(uint32 initialEntryPoint, PPCFun { r.storedRange = rangeStore_ppcRanges.storeRange(ppcRecFunc, r.ppcAddress, r.ppcAddress + r.ppcSize); } - PPCRecompilerState.recompilerSpinlock.release(); + PPCRecompilerState.recompilerSpinlock.unlock(); return true; @@ -272,13 +272,13 @@ void PPCRecompiler_recompileAtAddress(uint32 address) // todo - use info from previously compiled ranges to determine full size of this function (and merge all the entryAddresses) // collect all currently known entry points for this range - PPCRecompilerState.recompilerSpinlock.acquire(); + PPCRecompilerState.recompilerSpinlock.lock(); std::set entryAddresses; entryAddresses.emplace(address); - PPCRecompilerState.recompilerSpinlock.release(); + PPCRecompilerState.recompilerSpinlock.unlock(); std::vector> functionEntryPoints; auto func = PPCRecompiler_recompileFunction(range, entryAddresses, functionEntryPoints); @@ -302,10 +302,10 @@ void PPCRecompiler_thread() // 3) if yes -> calculate size, gather all entry points, recompile and update jump table while (true) { - PPCRecompilerState.recompilerSpinlock.acquire(); + PPCRecompilerState.recompilerSpinlock.lock(); if (PPCRecompilerState.targetQueue.empty()) { - PPCRecompilerState.recompilerSpinlock.release(); + PPCRecompilerState.recompilerSpinlock.unlock(); break; } auto enterAddress = PPCRecompilerState.targetQueue.front(); @@ -315,10 +315,10 @@ void PPCRecompiler_thread() if (funcPtr != PPCRecompiler_leaveRecompilerCode_visited) { // only recompile functions if marked as visited - PPCRecompilerState.recompilerSpinlock.release(); + PPCRecompilerState.recompilerSpinlock.unlock(); continue; } - PPCRecompilerState.recompilerSpinlock.release(); + PPCRecompilerState.recompilerSpinlock.unlock(); PPCRecompiler_recompileAtAddress(enterAddress); } @@ -376,7 +376,7 @@ struct ppcRecompilerFuncRange_t bool PPCRecompiler_findFuncRanges(uint32 addr, ppcRecompilerFuncRange_t* rangesOut, size_t* countInOut) { - PPCRecompilerState.recompilerSpinlock.acquire(); + PPCRecompilerState.recompilerSpinlock.lock(); size_t countIn = *countInOut; size_t countOut = 0; @@ -392,7 +392,7 @@ bool PPCRecompiler_findFuncRanges(uint32 addr, ppcRecompilerFuncRange_t* rangesO countOut++; } ); - PPCRecompilerState.recompilerSpinlock.release(); + PPCRecompilerState.recompilerSpinlock.unlock(); *countInOut = countOut; if (countOut > countIn) return false; @@ -420,7 +420,7 @@ void PPCRecompiler_invalidateTableRange(uint32 offset, uint32 size) void PPCRecompiler_deleteFunction(PPCRecFunction_t* func) { // assumes PPCRecompilerState.recompilerSpinlock is already held - cemu_assert_debug(PPCRecompilerState.recompilerSpinlock.isHolding()); + cemu_assert_debug(PPCRecompilerState.recompilerSpinlock.is_locked()); for (auto& r : func->list_ranges) { PPCRecompiler_invalidateTableRange(r.ppcAddress, r.ppcSize); @@ -439,7 +439,7 @@ void PPCRecompiler_invalidateRange(uint32 startAddr, uint32 endAddr) return; cemu_assert_debug(endAddr >= startAddr); - PPCRecompilerState.recompilerSpinlock.acquire(); + PPCRecompilerState.recompilerSpinlock.lock(); uint32 rStart; uint32 rEnd; @@ -458,7 +458,7 @@ void PPCRecompiler_invalidateRange(uint32 startAddr, uint32 endAddr) PPCRecompiler_deleteFunction(rFunc); } - PPCRecompilerState.recompilerSpinlock.release(); + PPCRecompilerState.recompilerSpinlock.unlock(); } void PPCRecompiler_init() diff --git a/src/Cafe/HW/Latte/Core/FetchShader.cpp b/src/Cafe/HW/Latte/Core/FetchShader.cpp index c6756f4e..b4beba4e 100644 --- a/src/Cafe/HW/Latte/Core/FetchShader.cpp +++ b/src/Cafe/HW/Latte/Core/FetchShader.cpp @@ -516,16 +516,16 @@ FSpinlock s_spinlockFetchShaderCache; LatteFetchShader* LatteFetchShader::RegisterInCache(CacheHash fsHash) { - s_spinlockFetchShaderCache.acquire(); + s_spinlockFetchShaderCache.lock(); auto itr = s_fetchShaderByHash.find(fsHash); if (itr != s_fetchShaderByHash.end()) { LatteFetchShader* fs = itr->second; - s_spinlockFetchShaderCache.release(); + s_spinlockFetchShaderCache.unlock(); return fs; } s_fetchShaderByHash.emplace(fsHash, this); - s_spinlockFetchShaderCache.release(); + s_spinlockFetchShaderCache.unlock(); return nullptr; } @@ -533,11 +533,11 @@ void LatteFetchShader::UnregisterInCache() { if (!m_isRegistered) return; - s_spinlockFetchShaderCache.acquire(); + s_spinlockFetchShaderCache.lock(); auto itr = s_fetchShaderByHash.find(m_cacheHash); cemu_assert(itr == s_fetchShaderByHash.end()); s_fetchShaderByHash.erase(itr); - s_spinlockFetchShaderCache.release(); + s_spinlockFetchShaderCache.unlock(); } std::unordered_map LatteFetchShader::s_fetchShaderByHash; diff --git a/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp b/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp index 1e2c43b1..b0917895 100644 --- a/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteBufferCache.cpp @@ -1074,19 +1074,19 @@ void LatteBufferCache_notifyDCFlush(MPTR address, uint32 size) uint32 firstPage = address / CACHE_PAGE_SIZE; uint32 lastPage = (address + size - 1) / CACHE_PAGE_SIZE; - g_spinlockDCFlushQueue.acquire(); + g_spinlockDCFlushQueue.lock(); for (uint32 i = firstPage; i <= lastPage; i++) s_DCFlushQueue->Set(i); - g_spinlockDCFlushQueue.release(); + g_spinlockDCFlushQueue.unlock(); } void LatteBufferCache_processDCFlushQueue() { if (s_DCFlushQueue->Empty()) // quick check to avoid locking if there is no work to do return; - g_spinlockDCFlushQueue.acquire(); + g_spinlockDCFlushQueue.lock(); std::swap(s_DCFlushQueue, s_DCFlushQueueAlternate); - g_spinlockDCFlushQueue.release(); + g_spinlockDCFlushQueue.unlock(); s_DCFlushQueueAlternate->ForAllAndClear([](uint32 index) {LatteBufferCache_invalidatePage(index * CACHE_PAGE_SIZE); }); } diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/CachedFBOVk.h b/src/Cafe/HW/Latte/Renderer/Vulkan/CachedFBOVk.h index b83bd96c..4e6be012 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/CachedFBOVk.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/CachedFBOVk.h @@ -37,16 +37,16 @@ public: void TrackDependency(class PipelineInfo* pipelineInfo) { - s_spinlockDependency.acquire(); + s_spinlockDependency.lock(); m_usedByPipelines.emplace_back(pipelineInfo); - s_spinlockDependency.release(); + s_spinlockDependency.unlock(); } void RemoveDependency(class PipelineInfo* pipelineInfo) { - s_spinlockDependency.acquire(); + s_spinlockDependency.lock(); vectorRemoveByValue(m_usedByPipelines, pipelineInfo); - s_spinlockDependency.release(); + s_spinlockDependency.unlock(); } [[nodiscard]] const VkExtent2D& GetExtend() const { return m_extend;} diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h index 5be9ce1f..b1883c3d 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h @@ -37,16 +37,16 @@ public: void TrackDependency(class PipelineInfo* p) { - s_dependencyLock.acquire(); + s_dependencyLock.lock(); list_pipelineInfo.emplace_back(p); - s_dependencyLock.release(); + s_dependencyLock.unlock(); } void RemoveDependency(class PipelineInfo* p) { - s_dependencyLock.acquire(); + s_dependencyLock.lock(); vectorRemoveByValue(list_pipelineInfo, p); - s_dependencyLock.release(); + s_dependencyLock.unlock(); } void PreponeCompilation(bool isRenderThread) override; diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp index 38f7c882..0d3ff771 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanPipelineStableCache.cpp @@ -206,18 +206,18 @@ void VulkanPipelineStableCache::LoadPipelineFromCache(std::span fileData) // deserialize file LatteContextRegister* lcr = new LatteContextRegister(); - s_spinlockSharedInternal.acquire(); + s_spinlockSharedInternal.lock(); CachedPipeline* cachedPipeline = new CachedPipeline(); - s_spinlockSharedInternal.release(); + s_spinlockSharedInternal.unlock(); MemStreamReader streamReader(fileData.data(), fileData.size()); if (!DeserializePipeline(streamReader, *cachedPipeline)) { // failed to deserialize - s_spinlockSharedInternal.acquire(); + s_spinlockSharedInternal.lock(); delete lcr; delete cachedPipeline; - s_spinlockSharedInternal.release(); + s_spinlockSharedInternal.unlock(); return; } // restored register view from compacted state @@ -264,18 +264,18 @@ void VulkanPipelineStableCache::LoadPipelineFromCache(std::span fileData) } auto renderPass = __CreateTemporaryRenderPass(pixelShader, *lcr); // create pipeline info - m_pipelineIsCachedLock.acquire(); + m_pipelineIsCachedLock.lock(); PipelineInfo* pipelineInfo = new PipelineInfo(0, 0, vertexShader->compatibleFetchShader, vertexShader, pixelShader, geometryShader); - m_pipelineIsCachedLock.release(); + m_pipelineIsCachedLock.unlock(); // compile { PipelineCompiler pp; if (!pp.InitFromCurrentGPUState(pipelineInfo, *lcr, renderPass)) { - s_spinlockSharedInternal.acquire(); + s_spinlockSharedInternal.lock(); delete lcr; delete cachedPipeline; - s_spinlockSharedInternal.release(); + s_spinlockSharedInternal.unlock(); return; } pp.Compile(true, true, false); @@ -284,16 +284,16 @@ void VulkanPipelineStableCache::LoadPipelineFromCache(std::span fileData) // on success, calculate pipeline hash and flag as present in cache uint64 pipelineBaseHash = vertexShader->baseHash; uint64 pipelineStateHash = VulkanRenderer::draw_calculateGraphicsPipelineHash(vertexShader->compatibleFetchShader, vertexShader, geometryShader, pixelShader, renderPass, *lcr); - m_pipelineIsCachedLock.acquire(); + m_pipelineIsCachedLock.lock(); m_pipelineIsCached.emplace(pipelineBaseHash, pipelineStateHash); - m_pipelineIsCachedLock.release(); + m_pipelineIsCachedLock.unlock(); // clean up - s_spinlockSharedInternal.acquire(); + s_spinlockSharedInternal.lock(); delete pipelineInfo; delete lcr; delete cachedPipeline; VulkanRenderer::GetInstance()->releaseDestructibleObject(renderPass); - s_spinlockSharedInternal.release(); + s_spinlockSharedInternal.unlock(); } bool VulkanPipelineStableCache::HasPipelineCached(uint64 baseHash, uint64 pipelineStateHash) diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index 5cbf7f94..35d81446 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -3447,14 +3447,14 @@ void VulkanRenderer::releaseDestructibleObject(VKRDestructibleObject* destructib return; } // otherwise put on queue - m_spinlockDestructionQueue.acquire(); + m_spinlockDestructionQueue.lock(); m_destructionQueue.emplace_back(destructibleObject); - m_spinlockDestructionQueue.release(); + m_spinlockDestructionQueue.unlock(); } void VulkanRenderer::ProcessDestructionQueue2() { - m_spinlockDestructionQueue.acquire(); + m_spinlockDestructionQueue.lock(); for (auto it = m_destructionQueue.begin(); it != m_destructionQueue.end();) { if ((*it)->canDestroy()) @@ -3465,7 +3465,7 @@ void VulkanRenderer::ProcessDestructionQueue2() } ++it; } - m_spinlockDestructionQueue.release(); + m_spinlockDestructionQueue.unlock(); } VkDescriptorSetInfo::~VkDescriptorSetInfo() @@ -4010,9 +4010,9 @@ void VulkanRenderer::AppendOverlayDebugInfo() ImGui::Text("ImageView %u", performanceMonitor.vk.numImageViews.get()); ImGui::Text("RenderPass %u", performanceMonitor.vk.numRenderPass.get()); ImGui::Text("Framebuffer %u", performanceMonitor.vk.numFramebuffer.get()); - m_spinlockDestructionQueue.acquire(); + m_spinlockDestructionQueue.lock(); ImGui::Text("DestructionQ %u", (unsigned int)m_destructionQueue.size()); - m_spinlockDestructionQueue.release(); + m_spinlockDestructionQueue.unlock(); ImGui::Text("BeginRP/f %u", performanceMonitor.vk.numBeginRenderpassPerFrame.get()); diff --git a/src/Cafe/IOSU/kernel/iosu_kernel.cpp b/src/Cafe/IOSU/kernel/iosu_kernel.cpp index 1a642028..680170bc 100644 --- a/src/Cafe/IOSU/kernel/iosu_kernel.cpp +++ b/src/Cafe/IOSU/kernel/iosu_kernel.cpp @@ -234,38 +234,38 @@ namespace iosu void _IPCInitDispatchablePool() { - sIPCDispatchableCommandPoolLock.acquire(); + sIPCDispatchableCommandPoolLock.lock(); while (!sIPCFreeDispatchableCommands.empty()) sIPCFreeDispatchableCommands.pop(); for (size_t i = 0; i < sIPCDispatchableCommandPool.GetCount(); i++) sIPCFreeDispatchableCommands.push(sIPCDispatchableCommandPool.GetPtr()+i); - sIPCDispatchableCommandPoolLock.release(); + sIPCDispatchableCommandPoolLock.unlock(); } IOSDispatchableCommand* _IPCAllocateDispatchableCommand() { - sIPCDispatchableCommandPoolLock.acquire(); + sIPCDispatchableCommandPoolLock.lock(); if (sIPCFreeDispatchableCommands.empty()) { cemuLog_log(LogType::Force, "IOS: Exhausted pool of dispatchable commands"); - sIPCDispatchableCommandPoolLock.release(); + sIPCDispatchableCommandPoolLock.unlock(); return nullptr; } IOSDispatchableCommand* cmd = sIPCFreeDispatchableCommands.front(); sIPCFreeDispatchableCommands.pop(); cemu_assert_debug(!cmd->isAllocated); cmd->isAllocated = true; - sIPCDispatchableCommandPoolLock.release(); + sIPCDispatchableCommandPoolLock.unlock(); return cmd; } void _IPCReleaseDispatchableCommand(IOSDispatchableCommand* cmd) { - sIPCDispatchableCommandPoolLock.acquire(); + sIPCDispatchableCommandPoolLock.lock(); cemu_assert_debug(cmd->isAllocated); cmd->isAllocated = false; sIPCFreeDispatchableCommands.push(cmd); - sIPCDispatchableCommandPoolLock.release(); + sIPCDispatchableCommandPoolLock.unlock(); } static constexpr size_t MAX_NUM_ACTIVE_DEV_HANDLES = 96; // per process diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Callbacks.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Callbacks.cpp index 403bec61..aef7e5aa 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Callbacks.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Callbacks.cpp @@ -8,27 +8,27 @@ struct CoreinitAsyncCallback static void queue(MPTR functionMPTR, uint32 numParameters, uint32 r3, uint32 r4, uint32 r5, uint32 r6, uint32 r7, uint32 r8, uint32 r9, uint32 r10) { - s_asyncCallbackSpinlock.acquire(); + s_asyncCallbackSpinlock.lock(); s_asyncCallbackQueue.emplace_back(allocateAndInitFromPool(functionMPTR, numParameters, r3, r4, r5, r6, r7, r8, r9, r10)); - s_asyncCallbackSpinlock.release(); + s_asyncCallbackSpinlock.unlock(); } static void callNextFromQueue() { - s_asyncCallbackSpinlock.acquire(); + s_asyncCallbackSpinlock.lock(); if (s_asyncCallbackQueue.empty()) { cemuLog_log(LogType::Force, "AsyncCallbackQueue is empty. Unexpected behavior"); - s_asyncCallbackSpinlock.release(); + s_asyncCallbackSpinlock.unlock(); return; } CoreinitAsyncCallback* cb = s_asyncCallbackQueue[0]; s_asyncCallbackQueue.erase(s_asyncCallbackQueue.begin()); - s_asyncCallbackSpinlock.release(); + s_asyncCallbackSpinlock.unlock(); cb->doCall(); - s_asyncCallbackSpinlock.acquire(); + s_asyncCallbackSpinlock.lock(); releaseToPool(cb); - s_asyncCallbackSpinlock.release(); + s_asyncCallbackSpinlock.unlock(); } private: @@ -39,7 +39,7 @@ private: static CoreinitAsyncCallback* allocateAndInitFromPool(MPTR functionMPTR, uint32 numParameters, uint32 r3, uint32 r4, uint32 r5, uint32 r6, uint32 r7, uint32 r8, uint32 r9, uint32 r10) { - cemu_assert_debug(s_asyncCallbackSpinlock.isHolding()); + cemu_assert_debug(s_asyncCallbackSpinlock.is_locked()); if (s_asyncCallbackPool.empty()) { CoreinitAsyncCallback* cb = new CoreinitAsyncCallback(functionMPTR, numParameters, r3, r4, r5, r6, r7, r8, r9, r10); @@ -54,7 +54,7 @@ private: static void releaseToPool(CoreinitAsyncCallback* cb) { - cemu_assert_debug(s_asyncCallbackSpinlock.isHolding()); + cemu_assert_debug(s_asyncCallbackSpinlock.is_locked()); s_asyncCallbackPool.emplace_back(cb); } diff --git a/src/Cafe/OS/libs/coreinit/coreinit_MPQueue.cpp b/src/Cafe/OS/libs/coreinit/coreinit_MPQueue.cpp index 8fc5a935..1816ef24 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_MPQueue.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_MPQueue.cpp @@ -6,8 +6,8 @@ // titles that utilize MP task queue: Yoshi's Woolly World, Fast Racing Neo, Tokyo Mirage Sessions, Mii Maker -#define AcquireMPQLock() s_workaroundSpinlock.acquire() -#define ReleaseMPQLock() s_workaroundSpinlock.release() +#define AcquireMPQLock() s_workaroundSpinlock.lock() +#define ReleaseMPQLock() s_workaroundSpinlock.unlock() namespace coreinit { @@ -35,7 +35,7 @@ namespace coreinit void MPInitTask(MPTask* task, void* func, void* data, uint32 size) { - s_workaroundSpinlock.acquire(); + s_workaroundSpinlock.lock(); task->thisptr = task; task->coreIndex = PPC_CORE_COUNT; @@ -48,7 +48,7 @@ namespace coreinit task->userdata = nullptr; task->runtime = 0; - s_workaroundSpinlock.release(); + s_workaroundSpinlock.unlock(); } bool MPTermTask(MPTask* task) diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Synchronization.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Synchronization.cpp index 84f7c5cf..bdcc531d 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Synchronization.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Synchronization.cpp @@ -465,12 +465,12 @@ namespace coreinit void _OSFastMutex_AcquireContention(OSFastMutex* fastMutex) { - g_fastMutexSpinlock.acquire(); + g_fastMutexSpinlock.lock(); } void _OSFastMutex_ReleaseContention(OSFastMutex* fastMutex) { - g_fastMutexSpinlock.release(); + g_fastMutexSpinlock.unlock(); } void OSFastMutex_LockInternal(OSFastMutex* fastMutex) diff --git a/src/Cafe/OS/libs/snd_core/ax_ist.cpp b/src/Cafe/OS/libs/snd_core/ax_ist.cpp index 26f975af..528a8302 100644 --- a/src/Cafe/OS/libs/snd_core/ax_ist.cpp +++ b/src/Cafe/OS/libs/snd_core/ax_ist.cpp @@ -778,7 +778,7 @@ namespace snd_core void AXIst_SyncVPB(AXVPBInternal_t** lastProcessedDSPShadowCopy, AXVPBInternal_t** lastProcessedPPCShadowCopy) { - __AXVoiceListSpinlock.acquire(); + __AXVoiceListSpinlock.lock(); AXVPBInternal_t* previousInternalDSP = nullptr; AXVPBInternal_t* previousInternalPPC = nullptr; @@ -869,7 +869,7 @@ namespace snd_core else *lastProcessedPPCShadowCopy = nullptr; } - __AXVoiceListSpinlock.release(); + __AXVoiceListSpinlock.unlock(); } void AXIst_HandleFrameCallbacks() diff --git a/src/Cafe/OS/libs/snd_core/ax_voice.cpp b/src/Cafe/OS/libs/snd_core/ax_voice.cpp index 746f04d3..6a599c8b 100644 --- a/src/Cafe/OS/libs/snd_core/ax_voice.cpp +++ b/src/Cafe/OS/libs/snd_core/ax_voice.cpp @@ -393,7 +393,7 @@ namespace snd_core AXVPB* AXAcquireVoiceEx(uint32 priority, MPTR callbackEx, MPTR userParam) { cemu_assert(priority != AX_PRIORITY_FREE && priority < AX_PRIORITY_MAX); - __AXVoiceListSpinlock.acquire(); + __AXVoiceListSpinlock.lock(); AXVPB* vpb = AXVoiceList_GetFreeVoice(); if (vpb != nullptr) { @@ -410,7 +410,7 @@ namespace snd_core if (droppedVoice == nullptr) { // no voice available - __AXVoiceListSpinlock.release(); + __AXVoiceListSpinlock.unlock(); return nullptr; } vpb->userParam = userParam; @@ -418,18 +418,18 @@ namespace snd_core vpb->callbackEx = callbackEx; AXVPB_SetVoiceDefault(vpb); } - __AXVoiceListSpinlock.release(); + __AXVoiceListSpinlock.unlock(); return vpb; } void AXFreeVoice(AXVPB* vpb) { cemu_assert(vpb != nullptr); - __AXVoiceListSpinlock.acquire(); + __AXVoiceListSpinlock.lock(); if (vpb->priority == (uint32be)AX_PRIORITY_FREE) { forceLog_printf("AXFreeVoice() called on free voice\n"); - __AXVoiceListSpinlock.release(); + __AXVoiceListSpinlock.unlock(); return; } AXVoiceProtection_Release(vpb); @@ -442,7 +442,7 @@ namespace snd_core vpb->callback = MPTR_NULL; vpb->callbackEx = MPTR_NULL; AXVoiceList_AddFreeVoice(vpb); - __AXVoiceListSpinlock.release(); + __AXVoiceListSpinlock.unlock(); } void AXVPBInit() diff --git a/src/gui/guiWrapper.h b/src/gui/guiWrapper.h index ce041efb..4f46f8b4 100644 --- a/src/gui/guiWrapper.h +++ b/src/gui/guiWrapper.h @@ -45,7 +45,8 @@ struct WindowInfo { const std::lock_guard lock(keycode_mutex); m_keydown[keycode] = state; - }; + } + bool get_keystate(uint32 keycode) { const std::lock_guard lock(keycode_mutex); @@ -54,25 +55,20 @@ struct WindowInfo return false; return result->second; } - void get_keystates(std::unordered_map& buttons_out) - { - const std::lock_guard lock(keycode_mutex); - for (auto&& button : m_keydown) - { - buttons_out[button.first] = button.second; - } - } + void set_keystatesdown() { const std::lock_guard lock(keycode_mutex); std::for_each(m_keydown.begin(), m_keydown.end(), [](std::pair& el){ el.second = false; }); } + template void iter_keystates(fn f) { const std::lock_guard lock(keycode_mutex); std::for_each(m_keydown.cbegin(), m_keydown.cend(), f); } + WindowHandleInfo window_main; WindowHandleInfo window_pad; diff --git a/src/gui/input/InputSettings2.cpp b/src/gui/input/InputSettings2.cpp index 095aa52a..7757a2ae 100644 --- a/src/gui/input/InputSettings2.cpp +++ b/src/gui/input/InputSettings2.cpp @@ -111,7 +111,7 @@ InputSettings2::InputSettings2(wxWindow* parent) Bind(wxEVT_TIMER, &InputSettings2::on_timer, this); m_timer = new wxTimer(this); - m_timer->Start(100); + m_timer->Start(25); m_controller_changed = EventService::instance().connect(&InputSettings2::on_controller_changed, this); } diff --git a/src/gui/input/panels/InputPanel.cpp b/src/gui/input/panels/InputPanel.cpp index b01157c8..984b46d7 100644 --- a/src/gui/input/panels/InputPanel.cpp +++ b/src/gui/input/panels/InputPanel.cpp @@ -41,77 +41,69 @@ void InputPanel::on_timer(const EmulatedControllerPtr& emulated_controller, cons } static bool s_was_idle = true; - if (!std::any_of(state.buttons.begin(), state.buttons.end(), [](auto el){ return el.second; })) { + if (state.buttons.IsIdle()) + { s_was_idle = true; return; } - if (!s_was_idle) { + if (!s_was_idle) + { return; } - auto get_button_state = [&](uint32 key_id) - { - auto result = state.buttons.find(key_id); - if (result == state.buttons.end()) - return false; - return result->second; - }; s_was_idle = false; - for(auto && button : state.buttons) + for(const auto& id : state.buttons.GetButtonList()) { - if (button.second) + if (controller->has_axis()) { - auto id=button.first; - if (controller->has_axis()) { - // test if one axis direction is pressed more than the other - if ((id == kAxisXP || id == kAxisXN) && (get_button_state(kAxisYP) || get_button_state(kAxisYN))) - { - if (std::abs(state.axis.y) > std::abs(state.axis.x)) - continue; - } - else if ((id == kAxisYP || id == kAxisYN) && (get_button_state(kAxisXP) || get_button_state(kAxisXN))) - { - if (std::abs(state.axis.x) > std::abs(state.axis.y)) - continue; - } - else if ((id == kRotationXP || id == kRotationXN) && (get_button_state(kRotationYP) || get_button_state(kRotationYN))) - { - if (std::abs(state.rotation.y) > std::abs(state.rotation.x)) - continue; - } - else if ((id == kRotationYP || id == kRotationYN) && (get_button_state(kRotationXP) || get_button_state(kRotationXN))) - { - if (std::abs(state.rotation.x) > std::abs(state.rotation.y)) - continue; - } - else if ((id == kTriggerXP || id == kTriggerXN) && (get_button_state(kTriggerYP) || get_button_state(kTriggerYN))) - { - if (std::abs(state.trigger.y) > std::abs(state.trigger.x)) - continue; - } - else if ((id == kTriggerYP || id == kTriggerYN) && (get_button_state(kTriggerXP) || get_button_state(kTriggerXN))) - { - if (std::abs(state.trigger.x) > std::abs(state.trigger.y)) - continue; - } - - // ignore too low button values on configuration - if (id >= kButtonAxisStart) - { - if (controller->get_axis_value(id) < 0.33f) { - forceLogDebug_printf("skipping since value too low %f", controller->get_axis_value(id)); - s_was_idle = true; - return; - } - } + // test if one axis direction is pressed more than the other + if ((id == kAxisXP || id == kAxisXN) && (state.buttons.GetButtonState(kAxisYP) || state.buttons.GetButtonState(kAxisYN))) + { + if (std::abs(state.axis.y) > std::abs(state.axis.x)) + continue; + } + else if ((id == kAxisYP || id == kAxisYN) && (state.buttons.GetButtonState(kAxisXP) || state.buttons.GetButtonState(kAxisXN))) + { + if (std::abs(state.axis.x) > std::abs(state.axis.y)) + continue; + } + else if ((id == kRotationXP || id == kRotationXN) && (state.buttons.GetButtonState(kRotationYP) || state.buttons.GetButtonState(kRotationYN))) + { + if (std::abs(state.rotation.y) > std::abs(state.rotation.x)) + continue; + } + else if ((id == kRotationYP || id == kRotationYN) && (state.buttons.GetButtonState(kRotationXP) || state.buttons.GetButtonState(kRotationXN))) + { + if (std::abs(state.rotation.x) > std::abs(state.rotation.y)) + continue; + } + else if ((id == kTriggerXP || id == kTriggerXN) && (state.buttons.GetButtonState(kTriggerYP) || state.buttons.GetButtonState(kTriggerYN))) + { + if (std::abs(state.trigger.y) > std::abs(state.trigger.x)) + continue; + } + else if ((id == kTriggerYP || id == kTriggerYN) && (state.buttons.GetButtonState(kTriggerXP) || state.buttons.GetButtonState(kTriggerXN))) + { + if (std::abs(state.trigger.x) > std::abs(state.trigger.y)) + continue; } - emulated_controller->set_mapping(mapping, controller, id); - element->SetValue(controller->get_button_name(id)); - element->SetBackgroundColour(kKeyColourNormalMode); - m_color_backup[element->GetId()] = kKeyColourNormalMode; - break; + // ignore too low button values on configuration + if (id >= kButtonAxisStart) + { + if (controller->get_axis_value(id) < 0.33f) { + forceLogDebug_printf("skipping since value too low %f", controller->get_axis_value(id)); + s_was_idle = true; + return; + } + } } + + emulated_controller->set_mapping(mapping, controller, id); + element->SetValue(controller->get_button_name(id)); + element->SetBackgroundColour(kKeyColourNormalMode); + m_color_backup[element->GetId()] = kKeyColourNormalMode; + break; } if (const auto sibling = get_next_sibling(element)) diff --git a/src/input/api/Controller.cpp b/src/input/api/Controller.cpp index a75cdf57..b7831def 100644 --- a/src/input/api/Controller.cpp +++ b/src/input/api/Controller.cpp @@ -15,10 +15,7 @@ const ControllerState& ControllerBase::update_state() ControllerState result = raw_state(); // ignore default buttons - for (auto&& el : m_default_state.buttons) - { - result.buttons[el.first] = result.buttons[el.first] && !el.second; - } + result.buttons.UnsetButtons(m_default_state.buttons); // apply deadzone and range and ignore default axis values apply_axis_setting(result.axis, m_default_state.axis, m_settings.axis); apply_axis_setting(result.rotation, m_default_state.rotation, m_settings.rotation); @@ -26,22 +23,22 @@ const ControllerState& ControllerBase::update_state() #define APPLY_AXIS_BUTTON(_axis_, _flag_) \ if (result._axis_.x < -ControllerState::kAxisThreshold) \ - result.buttons[(_flag_) + (kAxisXN - kAxisXP)]=true; \ + result.buttons.SetButtonState((_flag_) + (kAxisXN - kAxisXP), true); \ else if (result._axis_.x > ControllerState::kAxisThreshold) \ - result.buttons[(_flag_)]=true; \ + result.buttons.SetButtonState((_flag_), true); \ if (result._axis_.y < -ControllerState::kAxisThreshold) \ - result.buttons[(_flag_) + 1 + (kAxisXN - kAxisXP)]=true; \ + result.buttons.SetButtonState((_flag_) + 1 + (kAxisXN - kAxisXP), true); \ else if (result._axis_.y > ControllerState::kAxisThreshold) \ - result.buttons[(_flag_) + 1]=true; + result.buttons.SetButtonState((_flag_) + 1, true); if (result.axis.x < -ControllerState::kAxisThreshold) - result.buttons[(kAxisXP) + (kAxisXN - kAxisXP)]=true; + result.buttons.SetButtonState((kAxisXP) + (kAxisXN - kAxisXP), true); else if (result.axis.x > ControllerState::kAxisThreshold) - result.buttons[(kAxisXP)]=true; + result.buttons.SetButtonState((kAxisXP), true); if (result.axis.y < -ControllerState::kAxisThreshold) - result.buttons[(kAxisXP) + 1 + (kAxisXN - kAxisXP)]=true; + result.buttons.SetButtonState((kAxisXP) + 1 + (kAxisXN - kAxisXP), true); else if (result.axis.y > ControllerState::kAxisThreshold) - result.buttons[(kAxisXP) + 1]=true; + result.buttons.SetButtonState((kAxisXP) + 1, true); APPLY_AXIS_BUTTON(rotation, kRotationXP); APPLY_AXIS_BUTTON(trigger, kTriggerXP); @@ -129,8 +126,7 @@ bool ControllerBase::operator==(const ControllerBase& c) const float ControllerBase::get_axis_value(uint64 button) const { - auto buttonState=m_last_state.buttons.find(button); - if (buttonState!=m_last_state.buttons.end() && buttonState->second) + if (m_last_state.buttons.GetButtonState(button)) { if (button <= kButtonNoneAxisMAX || !has_axis()) return 1.0f; diff --git a/src/input/api/ControllerState.h b/src/input/api/ControllerState.h index a8ff6628..3e6149ab 100644 --- a/src/input/api/ControllerState.h +++ b/src/input/api/ControllerState.h @@ -1,6 +1,115 @@ #pragma once #include +#include "util/helpers/fspinlock.h" + +// helper class for storing and managing button press states in a thread-safe manner +struct ControllerButtonState +{ + ControllerButtonState() = default; + ControllerButtonState(const ControllerButtonState& other) + { + this->m_pressedButtons = other.m_pressedButtons; + } + + ControllerButtonState(ControllerButtonState&& other) + { + this->m_pressedButtons = std::move(other.m_pressedButtons); + } + + void SetButtonState(uint32 buttonId, bool isPressed) + { + std::lock_guard _l(this->m_spinlock); + if (isPressed) + { + if (std::find(m_pressedButtons.cbegin(), m_pressedButtons.cend(), buttonId) != m_pressedButtons.end()) + return; + m_pressedButtons.emplace_back(buttonId); + } + else + { + std::erase(m_pressedButtons, buttonId); + } + } + + // set multiple buttons at once within a single lock interval + void SetPressedButtons(std::span buttonList) + { + std::lock_guard _l(this->m_spinlock); + for (auto& buttonId : buttonList) + { + if (std::find(m_pressedButtons.cbegin(), m_pressedButtons.cend(), buttonId) == m_pressedButtons.end()) + m_pressedButtons.emplace_back(buttonId); + } + } + + // returns true if pressed + bool GetButtonState(uint32 buttonId) const + { + std::lock_guard _l(this->m_spinlock); + bool r = std::find(m_pressedButtons.cbegin(), m_pressedButtons.cend(), buttonId) != m_pressedButtons.cend(); + return r; + } + + // remove pressed state for all pressed buttons in buttonsToUnset + void UnsetButtons(const ControllerButtonState& buttonsToUnset) + { + std::scoped_lock _l(this->m_spinlock, buttonsToUnset.m_spinlock); + for (auto it = m_pressedButtons.begin(); it != m_pressedButtons.end();) + { + if (std::find(buttonsToUnset.m_pressedButtons.cbegin(), buttonsToUnset.m_pressedButtons.cend(), *it) == buttonsToUnset.m_pressedButtons.cend()) + { + ++it; + continue; + } + it = m_pressedButtons.erase(it); + } + } + + // returns true if no buttons are pressed + bool IsIdle() const + { + std::lock_guard _l(this->m_spinlock); + const bool r = m_pressedButtons.empty(); + return r; + } + + std::vector GetButtonList() const + { + std::lock_guard _l(this->m_spinlock); + std::vector copy = m_pressedButtons; + return copy; + } + + bool operator==(const ControllerButtonState& other) const + { + std::scoped_lock _l(this->m_spinlock, other.m_spinlock); + auto& otherButtons = other.m_pressedButtons; + if (m_pressedButtons.size() != otherButtons.size()) + { + return false; + } + for (auto& buttonId : m_pressedButtons) + { + if (std::find(otherButtons.cbegin(), otherButtons.cend(), buttonId) == otherButtons.cend()) + { + return false; + } + } + return true; + } + + ControllerButtonState& operator=(ControllerButtonState&& other) + { + cemu_assert_debug(!other.m_spinlock.is_locked()); + this->m_pressedButtons = std::move(other.m_pressedButtons); + return *this; + } + +private: + std::vector m_pressedButtons; // since only very few buttons are pressed at a time, using a vector with linear scan is more efficient than a set/map + mutable FSpinlock m_spinlock; +}; struct ControllerState { @@ -17,7 +126,7 @@ struct ControllerState glm::vec2 rotation{ }; glm::vec2 trigger{ }; - std::unordered_map buttons{}; + ControllerButtonState buttons{}; uint64 last_state = 0; diff --git a/src/input/api/DSU/DSUController.cpp b/src/input/api/DSU/DSUController.cpp index c04c8453..f134440c 100644 --- a/src/input/api/DSU/DSUController.cpp +++ b/src/input/api/DSU/DSUController.cpp @@ -137,7 +137,7 @@ ControllerState DSUController::raw_state() { if (HAS_BIT(state.data.state1, i)) { - result.buttons[bitindex]=true; + result.buttons.SetButtonState(bitindex, true); } } @@ -145,12 +145,12 @@ ControllerState DSUController::raw_state() { if (HAS_BIT(state.data.state2, i)) { - result.buttons[bitindex]=true; + result.buttons.SetButtonState(bitindex, true); } } if (state.data.touch) - result.buttons[kButton16]=true; + result.buttons.SetButtonState(kButton16, true); result.axis.x = (float)state.data.lx / std::numeric_limits::max(); result.axis.x = (result.axis.x * 2.0f) - 1.0f; diff --git a/src/input/api/DirectInput/DirectInputController.cpp b/src/input/api/DirectInput/DirectInputController.cpp index 87bd3685..dbb7c80c 100644 --- a/src/input/api/DirectInput/DirectInputController.cpp +++ b/src/input/api/DirectInput/DirectInputController.cpp @@ -245,7 +245,6 @@ ControllerState DirectInputController::raw_state() ControllerState result{}; if (!is_connected()) return result; - HRESULT hr = m_device->Poll(); if (FAILED(hr)) { @@ -277,9 +276,7 @@ ControllerState DirectInputController::raw_state() for (size_t i = 0; i < std::size(state.rgbButtons); ++i) { if (HAS_BIT(state.rgbButtons[i], 7)) - { - result.buttons[i]=true; - } + result.buttons.SetButtonState(i, true); } // axis @@ -316,19 +313,19 @@ ControllerState DirectInputController::raw_state() { switch (pov) { - case 0: result.buttons[kButtonUp]=true; + case 0: result.buttons.SetButtonState(kButtonUp, true); break; - case 4500: result.buttons[kButtonUp]=true; // up + right - case 9000: result.buttons[kButtonRight]=true; + case 4500: result.buttons.SetButtonState(kButtonUp, true); // up + right + case 9000: result.buttons.SetButtonState(kButtonRight, true); break; - case 13500: result.buttons[kButtonRight] = true; // right + down - case 18000: result.buttons[kButtonDown] = true; + case 13500: result.buttons.SetButtonState(kButtonRight, true); // right + down + case 18000: result.buttons.SetButtonState(kButtonDown, true); break; - case 22500: result.buttons[kButtonDown] = true; // down + left - case 27000: result.buttons[kButtonLeft] = true; + case 22500: result.buttons.SetButtonState(kButtonDown, true); // down + left + case 27000: result.buttons.SetButtonState(kButtonLeft, true); break; - case 31500: result.buttons[kButtonLeft] = true; // left + up - result.buttons[kButtonUp] = true; // left + up + case 31500: result.buttons.SetButtonState(kButtonLeft, true); // left + up + result.buttons.SetButtonState(kButtonUp, true); // left + up break; } } diff --git a/src/input/api/Keyboard/KeyboardController.cpp b/src/input/api/Keyboard/KeyboardController.cpp index 0d41fe1a..9cd31b4b 100644 --- a/src/input/api/Keyboard/KeyboardController.cpp +++ b/src/input/api/Keyboard/KeyboardController.cpp @@ -1,5 +1,6 @@ -#include "input/api/Keyboard/KeyboardController.h" +#include +#include "input/api/Keyboard/KeyboardController.h" #include "gui/guiWrapper.h" KeyboardController::KeyboardController() @@ -51,7 +52,9 @@ ControllerState KeyboardController::raw_state() ControllerState result{}; if (g_window_info.app_active) { - g_window_info.get_keystates(result.buttons); + boost::container::small_vector pressedKeys; + g_window_info.iter_keystates([&pressedKeys](const std::pair& keyState) { if (keyState.second) pressedKeys.emplace_back(keyState.first); }); + result.buttons.SetPressedButtons(pressedKeys); } return result; } diff --git a/src/input/api/SDL/SDLController.cpp b/src/input/api/SDL/SDLController.cpp index 63f7f4d3..a3e7eece 100644 --- a/src/input/api/SDL/SDLController.cpp +++ b/src/input/api/SDL/SDLController.cpp @@ -146,9 +146,7 @@ ControllerState SDLController::raw_state() for (int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; ++i) { if (m_buttons[i] && SDL_GameControllerGetButton(m_controller, (SDL_GameControllerButton)i)) - { - result.buttons[i]=true; - } + result.buttons.SetButtonState(i, true); } if (m_axis[SDL_CONTROLLER_AXIS_LEFTX]) diff --git a/src/input/api/Wiimote/NativeWiimoteController.cpp b/src/input/api/Wiimote/NativeWiimoteController.cpp index c5059f7c..3f9e82a5 100644 --- a/src/input/api/Wiimote/NativeWiimoteController.cpp +++ b/src/input/api/Wiimote/NativeWiimoteController.cpp @@ -207,16 +207,16 @@ ControllerState NativeWiimoteController::raw_state() const auto state = m_provider->get_state(m_index); for (int i = 0; i < std::numeric_limits::digits; i++) - result.buttons[i] = state.buttons & (1<(state.m_extension)) { const auto nunchuck = std::get(state.m_extension); if (nunchuck.c) - result.buttons[kWiimoteButton_C]=true; + result.buttons.SetButtonState(kWiimoteButton_C, true); if (nunchuck.z) - result.buttons[kWiimoteButton_Z]=true; + result.buttons.SetButtonState(kWiimoteButton_Z, true); result.axis = nunchuck.axis; } @@ -225,8 +225,11 @@ ControllerState NativeWiimoteController::raw_state() const auto classic = std::get(state.m_extension); uint64 buttons = (uint64)classic.buttons << kHighestWiimote; for (int i = 0; i < std::numeric_limits::digits; i++) - result.buttons[i] = result.buttons[i] || (buttons & (1 << i)); - + { + // OR with base buttons + if((buttons & (1 << i))) + result.buttons.SetButtonState(i, true); + } result.axis = classic.left_axis; result.rotation = classic.right_axis; result.trigger = classic.trigger; diff --git a/src/input/api/XInput/XInputController.cpp b/src/input/api/XInput/XInputController.cpp index e2be29b6..c3ab67cf 100644 --- a/src/input/api/XInput/XInputController.cpp +++ b/src/input/api/XInput/XInputController.cpp @@ -121,7 +121,7 @@ ControllerState XInputController::raw_state() // Buttons for(int i=0;i::digits;i++) - result.buttons[i] = state.Gamepad.wButtons & (1< 0) result.axis.x = (float)state.Gamepad.sThumbLX / std::numeric_limits::max(); diff --git a/src/input/emulated/EmulatedController.cpp b/src/input/emulated/EmulatedController.cpp index 0028db58..b7a4743c 100644 --- a/src/input/emulated/EmulatedController.cpp +++ b/src/input/emulated/EmulatedController.cpp @@ -279,13 +279,9 @@ bool EmulatedController::is_mapping_down(uint64 mapping) const const auto it = m_mappings.find(mapping); if (it != m_mappings.cend()) { - if (const auto controller = it->second.controller.lock()) { - auto& buttons=controller->get_state().buttons; - auto buttonState=buttons.find(it->second.button); - return buttonState!=buttons.end() && buttonState->second; - } + if (const auto controller = it->second.controller.lock()) + return controller->get_state().buttons.GetButtonState(it->second.button); } - return false; } diff --git a/src/util/helpers/fspinlock.h b/src/util/helpers/fspinlock.h index 04f761e7..4fa642f4 100644 --- a/src/util/helpers/fspinlock.h +++ b/src/util/helpers/fspinlock.h @@ -7,32 +7,33 @@ class FSpinlock { public: - void acquire() + bool is_locked() const { - while( true ) + return m_lockBool.load(std::memory_order_relaxed); + } + + // implement BasicLockable and Lockable + void lock() const + { + while (true) { - if (!m_lockBool.exchange(true, std::memory_order_acquire)) + if (!m_lockBool.exchange(true, std::memory_order_acquire)) break; while (m_lockBool.load(std::memory_order_relaxed)) _mm_pause(); } } - bool tryAcquire() + bool try_lock() const { return !m_lockBool.exchange(true, std::memory_order_acquire); } - void release() + void unlock() const { m_lockBool.store(false, std::memory_order_release); } - bool isHolding() const - { - return m_lockBool.load(std::memory_order_relaxed); - } - private: - std::atomic m_lockBool = false; + mutable std::atomic m_lockBool = false; }; \ No newline at end of file From 8f674933d2b507ce91c17b69fef2c38c6f1fbcaf Mon Sep 17 00:00:00 2001 From: emiyl Date: Sun, 23 Oct 2022 15:58:28 +0100 Subject: [PATCH 069/638] Create Cemu .app bundle for macOS (#364) --- .github/workflows/build.yml | 17 +++++++-- .../workflows/deploy_experimental_release.yml | 8 +--- .github/workflows/deploy_stable_release.yml | 8 +--- CMakeLists.txt | 1 + src/CMakeLists.txt | 29 +++++++++++++- src/gui/CemuApp.cpp | 3 ++ src/resource/MacOSXBundleInfo.plist.in | 36 ++++++++++++++++++ src/resource/cemu.icns | Bin 0 -> 817145 bytes 8 files changed, 84 insertions(+), 18 deletions(-) create mode 100644 src/resource/MacOSXBundleInfo.plist.in create mode 100644 src/resource/cemu.icns diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ac010c8f..5fc56aec 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -162,6 +162,8 @@ jobs: with: name: cemu-bin-windows-x64 path: ./bin/Cemu.exe + + build-macos: runs-on: macos-12 steps: @@ -213,7 +215,7 @@ jobs: run: | mkdir build cd build - cmake .. ${{ env.BUILD_FLAGS }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} -DCMAKE_C_COMPILER=/usr/local/opt/llvm@14/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@14/bin/clang++ -G Ninja + cmake .. ${{ env.BUILD_FLAGS }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} -DPORTABLE=OFF -DMACOS_BUNDLE=ON -DCMAKE_C_COMPILER=/usr/local/opt/llvm@14/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm@14/bin/clang++ -G Ninja - name: "Build Cemu" run: | @@ -221,11 +223,20 @@ jobs: - name: Prepare artifact if: ${{ inputs.deploymode == 'release' }} - run: chmod a+x bin/Cemu_release && mv bin/Cemu_release bin/Cemu + run: | + mkdir bin/Cemu_app + mv bin/Cemu_release.app bin/Cemu_app/Cemu.app + mv bin/Cemu_app/Cemu.app/Contents/MacOS/Cemu_release bin/Cemu_app/Cemu.app/Contents/MacOS/Cemu + sed -i '' 's/Cemu_release/Cemu/g' bin/Cemu_app/Cemu.app/Contents/Info.plist + chmod a+x bin/Cemu_app/Cemu.app/Contents/MacOS/Cemu + ln -s /Applications bin/Cemu_app/Applications + hdiutil create ./bin/tmp.dmg -ov -volname "Cemu" -fs HFS+ -srcfolder "./bin/Cemu_app" + hdiutil convert ./bin/tmp.dmg -format UDZO -o bin/Cemu.dmg + rm bin/tmp.dmg - name: Upload artifact uses: actions/upload-artifact@v3 if: ${{ inputs.deploymode == 'release' }} with: name: cemu-bin-macos-x64 - path: ./bin/Cemu + path: ./bin/Cemu.dmg \ No newline at end of file diff --git a/.github/workflows/deploy_experimental_release.yml b/.github/workflows/deploy_experimental_release.yml index 31a661e2..8a5ee0e9 100644 --- a/.github/workflows/deploy_experimental_release.yml +++ b/.github/workflows/deploy_experimental_release.yml @@ -64,13 +64,7 @@ jobs: rm -r ./${{ env.CEMU_FOLDER_NAME }} - name: Create release from macos-bin - run: | - ls ./ - ls ./bin/ - cp -R ./bin ./${{ env.CEMU_FOLDER_NAME }} - mv cemu-bin-macos-x64/Cemu ./${{ env.CEMU_FOLDER_NAME }}/Cemu - zip -9 -r upload/cemu-${{ env.CEMU_VERSION }}-macos-12-x64.zip ${{ env.CEMU_FOLDER_NAME }} - rm -r ./${{ env.CEMU_FOLDER_NAME }} + run: cp cemu-bin-macos-x64/Cemu.dmg upload/cemu-${{ env.CEMU_VERSION }}-macos-12-x64.dmg - name: Create release run: | diff --git a/.github/workflows/deploy_stable_release.yml b/.github/workflows/deploy_stable_release.yml index e0a7ac3d..9e880218 100644 --- a/.github/workflows/deploy_stable_release.yml +++ b/.github/workflows/deploy_stable_release.yml @@ -68,13 +68,7 @@ jobs: rm -r ./${{ env.CEMU_FOLDER_NAME }} - name: Create release from macos-bin - run: | - ls ./ - ls ./bin/ - cp -R ./bin ./${{ env.CEMU_FOLDER_NAME }} - mv cemu-bin-macos-x64/Cemu ./${{ env.CEMU_FOLDER_NAME }}/Cemu - zip -9 -r upload/cemu-${{ env.CEMU_VERSION }}-macos-12-x64.zip ${{ env.CEMU_FOLDER_NAME }} - rm -r ./${{ env.CEMU_FOLDER_NAME }} + run: cp cemu-bin-macos-x64/Cemu.dmg upload/cemu-${{ env.CEMU_VERSION }}-macos-12-x64.dmg - name: Create release run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index b973a3f5..ce4d444e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.21.1) option(ENABLE_VCPKG "Enable the vcpkg package manager" ON) option(PORTABLE "All data created and maintained by Cemu will be in the directory where the executable file is located" ON) +option(MACOS_BUNDLE "The executable when built on macOS will be created as an application bundle" OFF) set(EXPERIMENTAL_VERSION "" CACHE STRING "") # used by CI script to set experimental version if (EXPERIMENTAL_VERSION) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 024432d0..1679623f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -67,12 +67,39 @@ endif() set_property(TARGET CemuBin PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") set_property(TARGET CemuBin PROPERTY WIN32_EXECUTABLE $>) +set(OUTPUT_NAME "Cemu_$>") + +if (MACOS_BUNDLE) + set_property(TARGET CemuBin PROPERTY MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/resource/MacOSXBundleInfo.plist.in") + + set(RESOURCE_FILES "${CMAKE_SOURCE_DIR}/src/resource/cemu.icns") + target_sources(CemuBin PRIVATE "${RESOURCE_FILES}") + + set(MACOSX_BUNDLE_CATEGORY "public.app-category.games") + + set_target_properties(CemuBin PROPERTIES + MACOSX_BUNDLE true + RESOURCE "${RESOURCE_FILES}" + ) + + set(FOLDERS gameProfiles resources) + foreach(folder ${FOLDERS}) + add_custom_command (TARGET CemuBin POST_BUILD + COMMAND ${CMAKE_COMMAND} ARGS -E copy_directory "${CMAKE_SOURCE_DIR}/bin/${folder}" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/SharedSupport/${folder}") + endforeach(folder) + + add_custom_command (TARGET CemuBin POST_BUILD + COMMAND ${CMAKE_COMMAND} ARGS -E copy "/usr/local/lib/libMoltenVK.dylib" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/Frameworks/libMoltenVK.dylib") + + add_custom_command (TARGET CemuBin POST_BUILD + COMMAND bash -c "install_name_tool -add_rpath @executable_path/../Frameworks ${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/${OUTPUT_NAME}") +endif() set_target_properties(CemuBin PROPERTIES # multi-configuration generators will add a config subdirectory to RUNTIME_OUTPUT_DIRECTORY if no generator expression is used # to get the same behavior everywhere we append an empty generator expression RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../bin/$<1:>" - OUTPUT_NAME "Cemu_$>" + OUTPUT_NAME "${OUTPUT_NAME}" ) target_link_libraries(CemuBin PRIVATE diff --git a/src/gui/CemuApp.cpp b/src/gui/CemuApp.cpp index c502e8d2..1de007fb 100644 --- a/src/gui/CemuApp.cpp +++ b/src/gui/CemuApp.cpp @@ -77,6 +77,9 @@ bool CemuApp::OnInit() auto standardPaths = wxStandardPaths::Get(); #ifdef PORTABLE fs::path exePath(standardPaths.GetExecutablePath().ToStdString()); +#if MACOS_BUNDLE + exePath = exePath.parent_path().parent_path().parent_path(); +#endif user_data_path = config_path = cache_path = data_path = exePath.parent_path(); #else SetAppName("Cemu"); diff --git a/src/resource/MacOSXBundleInfo.plist.in b/src/resource/MacOSXBundleInfo.plist.in new file mode 100644 index 00000000..73ff737b --- /dev/null +++ b/src/resource/MacOSXBundleInfo.plist.in @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + ${MACOSX_BUNDLE_INFO_STRING} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleSignature + ???? + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + CSResourcesFileMapped + + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + LSApplicationCategoryType + ${MACOSX_BUNDLE_CATEGORY} + + \ No newline at end of file diff --git a/src/resource/cemu.icns b/src/resource/cemu.icns new file mode 100644 index 0000000000000000000000000000000000000000..c6d8c5b5088fc39792a697af8f771de09b5b61c5 GIT binary patch literal 817145 zcmb@sV{m3)5a9j9wv#8eIq}4{?M%!kP9}CHp4c`gHYc`i+t$wit+#gf!|u1Ox_$eg ztNPTfTjzBDPFtDUI|C5iU#v`7*#H2vs|Y0pNhElDcmM!^BrPST@=pu>C$P}}-sM)H z&3_8aSw&I=P(2Ae`PUIM(~>rqmj}@OYr_J-!mI$0|C#&~{C@%fK;(h}ApU8v|Hg8` z|L3ewF2w(8|7R$nEK>V#1Di3+{Rbq$5E zzX$?bNbzy-m80+r;w??02&m|kNdu|!2gRZX!)YQlMCXfHMKH@r=w$QSG0kPH!rY4I z%#yhrHh(T%yLqa*!Beh@E}Xm?AHlr-~mnssZW(g}%QRmxNfCN5ieHL3yWgk_dv0vwjz(JRhS zWoQE0EGzc1B7QU4MPOF1FwM+=2a1GO0rgU(jUb|jJMiO5%P2`rp#J78ROAV~_F&%( z*N1$zNDA@kOJdj7PV6-hvKL|wI{zgLahBtoTkvE84I54e-V|Rvlc+U6bQURS+K=L3 z`?(_b&4Ojyu9W*HzQqdKb>v6hhy3XoC9W^b?C(L7Px_zPLF!9=@q#i)Z)V8V)fduu z>EAQJ;`aPWdREZAq2MMlCNSg@aVT*y#;H6_>+aJ#D!Xd!&|G|>$|Tddry9P?TLCV8 z1zZF$>#)I@vN$){M-jO-432P}aS1#K4|wk+Mm#?FMQeBj5`5tdkU8y_N&Fq3x@wQV zBN(h;S&@L?4$0uFg=K>FQOIhcYY##>qfOJ&4kOxZvIQh*0Dq57>zrEP>d9?0J`x}{ zDId0}hfz+&s0PgeJ*)uXecQsjaU4z#3Rl$5(;VmDd|f5c>a4X24|(n4p^ejk8YXj4DdI2e%GC>vJH z$Ve#GUfw0!Oab?ow$^dsJdTVf1BwtU0%$bGUyljJLMCti*j?@`PPHead)}Vy0$%dp3Ujl`Y=yPvvnvuo^s1 z3G90-H6`Yrhz^M?d2LKc!sBsMCvymYI;+0)kU<71A0#zvE8cPOteoH9HpE*G%p&)1 z2fW>R1$5NtMyWNQM$IC559UxVqW!%UqmI%^7}$^ ziV?7z#$uTb$sD*Fk(}tK!34nNeA@D6kqa%!Y(-3Xs4)csn1xR$QA63m0Dn=@5x`M| zvDM4i{m%$VnHPRlURoz#b-lWHf^eb~ruQJ;ery!*9rOl}uJCbECNu(eauNoz#69H= zYbrY(Loz*O-uDJ~RU+44f6e`P3N86@h6XW;*bhAQjZ@m!T=4w1?6Ba3?~kf}E~jPb ziI|@tJxjGD>AP{xO|QzuxXUkA&DsTj&-PB06WkfLEax(Ff-fb_ON0Q^=s1!qMoe;Q^@CzTe!6mUB$KVlv9g@2t-LrT6gT_K4KK>IvewXimPCa*U5qe&s&o zaqzDdWpo6q&1A23L|>*6cu(-P;p`>_F>f=D??6ENMV{U51tUxm=asl45w$P|ICE?v zUpxI#Yj58ABB`hy!v5HkLrQOd0c+$@Bj;XlPv~ek0{H^Zk*ylaNs%lo@${fq;J>pb z%+{v_;220Vp6TBHscW=;YoEzY^xb(oZvC|xERAl*6n)Csz@8&-d@oAD#_7V=#wtN_ z2)@pDtvY-iQ@`p`JPDl*B(Y7LL19frRZ0bcM!Wt8sCMH#S} z#fh^BZ+9iIe%F>^cWS(U;_e4)=}n-A$t5(zXN6StH!OG z8~EFm4-X=Uy7{+{7Yc3Dc0 zhk69W(C1+55f7qa+Qrt}$oupaQjsP4SOGZhkpLEPf!m1RV92_Jz4Dj4WBF*wnH>K03%GDOY#= z=DYKoQKjKG&Y5@_u#yYnrnC?!3s)zslHcBE90;fmPTUa=sn(i<*s}OH=0Cc|VI3jH zuPNGAFYkg6^8PsKu~~N(X+%|v3VI$Rq6@a%jw#sAIo;CqnvXge)bnh@^mJkVkuT^4 zQX4|2*&o8mNcz(*3QGq}q7p-Xllx&5+^s%XR#PF$iwarbWhfMIRNG}5H`TWk%^GKW z2&!vEPDrAgp)~*Ewj%jJ4pu~)%Rx^)^DZ0?%qAC=dA1}FM2MQ7Zh6_so65_+u zkmWoaBWUKvX947|3R|HmxCLe#S#>Q1+D)-e5F)#_D`vq>I>YHibMhY^0lXCzB<@{S zP?tE2_~P;{au@i#bSYa8uz;R*WoXdf3STy*3Fv5GmYf7SKo&J@NIGr7698a&Ux`WL z84vKsTNdDFg6Nktsq^An+y6b_!Ctw`R;UahzZVZ3tUX76(9$-n>W#gEr$59t17p&J z;@*s+8HT70GTn3f;SIjW6AH%}%-P-{oYk=}tHcSgjv@wgnWu#4%`6eZZK}~riEjV5 z@7!JbK8%Xb_J$0`QhHm>YFcnlu4l%q&eRaAm%}EO>$yp|pE@;~ZG{7?j4D_1Cg-eV zUFJu96>7~9glI_gz;%k1WKmD~uJn+vdD|~XHrO-8T+s9QfIE6vCTCF zZCJUKQg!)8pQ~$u^wcly;M5=P{}9^FqS zT^Y8**EBhn1}d({&2l-l#&;4y;1Spf|3;>?mW8i+n}1dZIItQ9v2YAudMXB z50ORo44g&FjXA?7_g*m;C&jFkiDLzC>Bot@?fIbKF5k?l248xfo&M99I4++TIJ#mH$X$Gx541l^p4x0z7w}s1T6qC}?jLeT@O^eFo+sM))*38c z4fxIkppd`vMDreZiuRbh4FWB!AppfCgNTK>qZFtWv0-SrL^=-qny4MV_!8uB*g~o2 zdNhLTtbqk*M4nga0-kRn^aqtVjPr_{AmO>jnTR_6&9BV$&uw#WjCE>qalJyBWq$G_ zB>xlE9f}v%8X(gN>pJuGT!Tf0=?El=``nvNFJm|1Y;@4pZHzQ(rLBi01psonY<`7N zQ9kJ)RPbrcop_ZN=iY4;DiUY3E}Q9usZka!V}pW8@D1d2-oyIzv;p%2!#*i2<9bgT z=Cd?H(8hVmVivZ5%mRbjf1trI&t9Nk-bd^4vw&($L$SGC1sb6B+Wa2+)&o!}^`L^H zQt<==+~mrtZ2JjwTg9P4iw?LW8Sq+UT12QGa4i6km-&&q7vz9qgXbeg6MOIqgMDbFi+ zu#=O`8AQ6!WOReA{Gylu=c7T2A#z0*<~!V0@MT z9>%(6cd$D>Qc3d=Gc@L5OIDh}Yjo3$l|`^|8RcZXJj9>WTl;)*D5f?? zOx4pb05{uwr^CqD?$6R1{3c=0;~o!L1lDq6y&Ptqgmc~(|NMQ-HRxuCGfDr;>&c8WoITV3PL6DdPY z+bwVC<~JqFK@$Dnp$xnq(&gG`GmQRX_u=~v*yBT`3&ND^{wdQ7(%mGu`RvBDsj$P3 z+DluI8tGQ@_i^FnKN?$ZcmwOXstwoz%gd-e+V14LH|ABW$XGd@QpT3z!mhhTiM~!r zAqx*)r>opZQgXq+Wh&$pgXs=;5+=71 z&r%JqK(${Rt4xhp`meudpE%|3+sL`Jo<0bQ_Hu=a)=mZj^I`m!0=q%8{QN4dg)xkC z5dytYgFOI${{>`MGwx`ht9`L`g+(9YWY7zDROe^Oz96S(TkM24IPg<%oa6n_#^N;k zRbhO6Y7#w4Y63y6#mr5iTWB#;%^5x53kvcRu0C?Ogc`+Z?mx&PEv_I|En*aCWy-<@ z0I(YWA8?QVKQsUT5BKy77?1ty{6E1x{{I{9`OgDDDhAU1UqI0R|KlDXxWp_?ka?qy zb(!v|hHTxxhhc2lBVoYgx{ob501=TCk_Bj_fG$EcHqL^V3AdjqXGE0^X%5R{%snm# zJsek?YLpBxhKuCV&>bF3KJbZW99gYuTzJd4s?c>c{P_A=v-PE8Cz{$-a#hi$?s~RZ zRsQw)WVmS)zruDFpp7!_WwZ!UPn7!5Qwd}Ko#p>B^#1-c_sqinR}SAjyTxo2{{5;M zd-pPrjSK?;VNBL~q42oGk(qD5ACnKy8V0g!@^QxtC!9JxZxu1{^8uNsu zVakyQv@*dZgS`XW&QW(tesB*-r8s#^;#rK*MBMPR-%AZeKgdqq)Trd?6ot{pZNV`i z6brcWyRaVQODzf}lTV43p=PG?Ke0|bL+sg8VcCBJ^kKc_6%({Kz;V65o%)F#pb6?0 zUx8&43HZM@mr|eE4{9GYTF4nzJdC4dR2NsDp?O=Uu?G*7$69+Re37dWz3|seCC@$e z(5QLiKWwN}T+C<1U(#(qFJ*0-9h^}1JiyG&w`k`0moxF;EF0$D>V0wGY+1Y{F1uwG zC$7zO4AY;1T50wgV6(2KJvZ&4^{G}*I7W4Es>!%a@EwL4E@w~TCaO#Rpg-HMNu)#P zhBn9>Uw?4{qqpaFm27$%@hsyFu}X+W%LRfqp{cP->aomL#MXv>@k&kB{neJ^9E-<% zNOHUo(b1k>l zd8~=%1Bn~nA?YUKi`4lKT*ZzHOZ2RZjOyu2yU*-KyB1Ywtg0;ror9L%a45EQp^vh2 zMbp%jS;=qbPOHR0Z`C$>jyz}|N`V2r8qqVIRH1#erQc}O9KU_uVIyZtR?5F4LUkkh zZBeeHxa@g!d5KH%@(DtXX9-< zGQi@sZ&=uGHXi0j@{P=#H`eiXS%i}GYm-+TV!75g>_uw`h%V`z7Cf!J9Uf&#-l4<4 zc1odLb5y=p(af7!uJ3X9F~wb^v4)Vqkg!}}^-Wzir?1(;qSrbG79VvrvD(y&) ztZgOvW36C41?)p(rir$_V34^st#5T2nsrcAm5^ML0c}xzb*uYq+$0yTRtdW4(JJ}c z+w7pA;`GKbjsUf^1zr=SfW3gDQuin)`B29{f7#mWTZOm<8G9nwp5@M@f0?iP>q)FfT#Jjnw6(fts5TEwjT zee>xTI;BK)pNK;EdnwL*6h%HvuE5c_P?@CGDkN12ZJRS|w+>dW^lBw$Mt@@S~^c z`M9gSnMRaqxIKZRKfKirJjsPn_@#gKyL}TB*{xhhBBb)5z@DTAlOvOj3A z!O91fO8K7_d4W?fi#SI++*MX8HjNr(x(=woBEDK_ijXZ*T`ttjbrR-{{_LI(E9B3q z(?_JS#5Y3FQGmP^d7#gi6BQ|~JPTtOQt2YIoJPKt=bCW>C66YhO{|t7G`?uH6(cfaYp?9A{nhM1E=M<~ek<&;?{W>}zGP zb@2qHMIO11jBd8p6+2{CUS`mbVUH($dTz|lWgW8cDktojVmLW^=shAwk7ehvuDDz4 z#YFGy5B(Vvp0r~ja8!i67@pJsGqE}la64<6e>J8_0DRY_wO3p1h4-Hvsioxp+KVPe zo}HX^dpC;nT3K6Egpda=fI>*0yVj;$u2DS%%9m>`v-P^_6svVQr8t?-k{&+3*Zug^ z)ArAuGM-LPggeF)X5;5!V`^838hPw5*?;?~I2!wiG!irsY1?zPFfoU*5cs2(6>h?6a}&~{iP zZM!xDh_)7XOwiq2?dkSCm32gezvnNJcs^bVex1) z-L4DCrGE9Lw);AmVxUVqv6?n?QWYN1EgJ9PaJB1Xqdd@rR3A1d-R) z41GLr$6qJnC)IwQId0iR$X2bOEUl8dXCq|pM-(cdb_HV}?#2ldrsb#&n;v~z+30tg zA^&=@R1iuNly(9{3)7W^==M?X4zqT0E$J3Cz{ci**!xfx} zql(DLBZgbfN&&;rn~H>9=%N6>`s$BTkTD12Y&am4u>^^m(}V$Hr4=G_U9;wJSvFu zhZ=4Vk-zb25Db|%JaEekFLY`<1yl%y1Sym!>762B_mokOfgGp@BNK0>z%fC5YYtK# z8W{woh$57fksmILpT%NBtU7wPdo$S(f)Rx0g?c`dCNFzqi^HC>*_%&_tzj+J^4)q- zodaQ4tISv3ra3^OfzR9wXJPbfj-EcAdh0oSOw#g!cyQJ~Qm2LU*J`!JOGQaPHFUvH zqnMgoiVc@! zw_3vvR50n65G33Abb=3(jgZ5kPN-D=$k-h1$^mK;V-jTw@M%o);GBCrTaJF=?5v~~ zB+tYh)}0+U9VeZTBWOeMVxs*8Y#h9yT;;e}=NWBBQd{ptY8|>eV5$lau_=`Vi71`d z44!Ar#L3_Lo6tQtTqs%efow55tR=BPW<-LlqZUyNxe0C=VbKbSM#$++Uhs*2qIx}< z!Nipi&L8#MH%X16`)$PQv^lM=VYXZDh+Lzr2cF9;k4Cg< zYcT7`_||lEiB;OS_mq>3m*X}V+>5=L_5vHJQ z`QV!V^$ni{jw>S!+F>!sBl31i(V@Q7119keK}JRWrzrYLIIu@%b0Qv+3*3~-U_EQEEe4PM{@ zIi*>PHA_cRVB9-hf4ooS{v24VCcv4Df8zJ+bR5zz0utgUKl#33zf3c(9sC97C(->$ z1m4Zk`K_Yadg8hTvR%I;YVWkx2yL^?kgi05C`oanUefLSBhdSJf;okLim&1qTpg%Z z(f4T=>-OBLe2iFm#FDNyKKllI6K0KG7LIXcM+zuqaa~T>uBv&>6X^wWe-2HhyY|5HlQ@KLno|#GQ@Rs2) zY=?4T?GP;8@z{aoL~E~dQl9TDW@7UjCdZ7+jN)bCV-c`-eQp}^N?YMy>p0z}2J!C; zz7BsokqkbCII$EiSutXVMRWsEMc0=@x2uBR7ZA&Ssng>O>(XUEwN`u;Ol^?(`5f7o zRq+xi4*mHt)jy*L%KFU_~<>SmDk-9dZQbmI)leuOs zIIKi!cd(}&h1+5Gko+m(t&~p9FkRu^>W?o+sy-u_r5}_)`_?dqs>^B9;h+ii)GlS7TmsqA=18Pk&z8AUwqY1<9}-FML3Z^A{F9_VC!$Ai7@O`s1{{=NFRu z$TGUOVv=kZ^hV&R@Q=7VwyA>bfadZFfa9q3zhH05@_UPyR-KH1?^}V>(cT-qRtT}M zPMZ>w_OJb&!{2w4&XVp9lBEI&zP~zXK}#@O!qumHfbmL^nSe6fB`*52+t=w<4 zG9!B<(@V_l)Y!u%4)mYavIXi9vrFunOu8XRl-+Gb1Kx$cYLfUXjt`9y=0XPb=*QVW zv(AY&C>v%&^Um*`A6Jq1rau-k=NCowx-& zl^`5d)3U499AX25>}_m+?7no&tgK$XEE!;p#mIz`Efv3k$$aljNObQ+aDT)464D4! zXP^6l(WTsxcXvZj#w(FUwpBF1}%N?%JP=&~qs(*F&w@NqTDwzUwE|%Hio=!pIIqQmF`p}bC z>2WDp(aglG{&u4q?I^?UZUPZS#O|;UmS)#F>NL*T1`aR>@;UiV-c(=*Mg^-u&>Crf zULyCe?ER#mud9vkkn-GS!_?aqqmB*>&10)}>8><}D;F&}ope2&(TonLW&B{pBW}O?cz{bAXHhFF<7nX)@w0pH`+js+qVN9YF(eIc9P^%qtwC85^^GWLM4n4Q zoC;hCV@o5j4w#?=I_^-XbBo*clxd06G2W5b5MSZ7x7P2Nq>Ohu+n1s#X5H{bcaXU% z#Fc#jy8HwXH7LK5_1f*;IeGa*(8jD=Alt6Q7sr0sR?q{zH(W4D0wtHuk-sl@A@*8m zl%~DV5-{tAj_NT1wLC_Tw8?Z>4^`(HpQ zv8W*+CFCFw}J@2dBUXVT$F)8SN;U>TaBxQkG zB8aH&`%I!AN&4CW2yUSsW-FvVam&HN09bPiY)R3Xa8P3hO7UE)Gu@M??O731)L~znk~E;; z71r;lhp4K0+L}gXiY2mV;M@M`LZ%tqRf=DSy{A|_t=9ohW!3k8AU)Lzx*fiapn(ix zaY*m5LydJznY{Xa&=R&;?RfOjL%N=DWez?K%EF9FAw!Vr&`Y0Tksuug&S8)qBe2f1 z&T~9cqLtrFOy&cyVFMxk(OaGe|RR?_lBiJ0NNiuND~l zY_u=nYrfnG2^6?|)mpY^yxhyFBb5+P4M#FD^HyexhCn2HMtH8bup6B|ZUGV< zHakD(mfE7Y24)gYhT=R`_p@!REmHq#6qrkc<=@%#c$l&0U1*j`raN=UU{*{UuK)Q*rB8K-c4BEG$v_Usq&Qv|A%0c6& z6A%dfvH#M-@75HAcpAp)IVbj;AO$KRldE7trU2OjJ->U5LlsM$@aZ$rBEoI~3)k8Z zeJqD52M&x>@#Wc(Crr2!Plpjq&xR;CJX#5t#-l(;GRO|8fecPjtbjaK3+#Ddg3cW< zbPY9WJl`>{QiZdN@3@Tdt|Q2sU+YdMngYUoDfFc5OpBV^phlLqhzO;Edvv02?7!&; zx8WQp4#i6$@ZO=AJqrX$iGw})mJ=h{)f;=X>f^9{r;^Gc{Iz|D)CiypsrU;N*qU`(84!Moht6%^1++f=%XdFPy;K#fPQX>48KM}Hw7i+^adXB zdjX#Jk0DHv4)}3lo_dlqDgh;OF@}psX4M>Qm9^h?np#Qhwj@4PuftQ)rDschamE1J zsg+9o_j$tenX-L?uCh=&;xW)t!kdy@NJ0ly#tdc&W2Hu*mBQ%s!jC>osU`$A z!uyJBfTyjsMl1g^O>wyHnpX7xA1A9R^n7$u~Gt(2QokCDhST&8cwmf#cqDj zi~hJW8({y#b9MqcPmXCbTq!9Pg7lc-{P@L=uxn>-?og%Hfyno;2 z2?iBB0*tJmE9|_$X=OTipF{=k7r1u|(Ple|JmKUVmZx@{RA*c@r=uQnXn6+zuCKy3 zFO}avFsVD|@*$|!T%0c6G-Uy}g}!4%dxfrx#*p~u99-E>n4}aYN>=~wr-Qt?Po}5C zGyl@DO!GZ#2vH5M4tSu}6L1A_;8w5Y;@h?*+?;-SOXG%Wusf~2mR3pFPES$fW=1F7 zRMJL^`+07kpm&;8!Q#8Uj3!NnscD}UGFVd&*xmbDtNw)gm(q;RMh-T}5x7p+^H;?L z@m1He=FwENU?BE^b+kGIt{!WM{w6fh!gB>2G4<;THA0jk!ooD9XBm5~6gy*y$c?P@ zu)yPv&c#wF2A)!j9Z)63NwWO=6E$>{icW8OLD~;iB+oH#@I6;3)+YXvjSTiS*75$Q z<8lmSz^w|WD7k*El zfk}}!G2-$P#<8o(7j?l#x(KA!_onP$r5z75OxU(1Hnq`%Ym48V_m`M>RiPc<+75Ju zagQkMwS3+$JL__`aLvhtLi&E_)kP12icCn2(DzO5*X=_~dp&=h>lbM@Li*DQz?T24 z4Y9^ie#=L6bWl6>kHfr|8UpC6tvi&ZUqRam!lQ zkK;}HFn3Rn1W>1mjUKk%Xqznyn$@m)%Ol(SW@#}+^2i%Bv!hsS_BMxq3`?tZF^uFE zpC)=MU@vlXuPaW5Vt0^s>li(O^^qhzj6$;}tlCL7p{g31r^{uO28>{~EbBk_C|IoP z19YdQCU0ku%_y)(zyGTbj2Z4Kpq9$2yWf@BrnJ~oi|>|3%;H%l;-1x+x5cre z9Xr;OCw7#l6Y1KF=4GYAsln~(KC`;&qmIe`d%)O@qeRrd_9MxTMJMP&`d@Y5Jkwc_ zZN}`T7o9&^14KyxM$DrR?C@4(h?!${ZOMUm*h7)NaIi_8F2Q9v6 zQr-e$ewfZy;q~~0a~_N&^gF#>ihA4yzS%_$pnn{4giWgQB$>mA!glh;QcP=UkFqH1 z`fAAe&kLRmQV+^#LNPuh%c`_?)(3ldl-~&3NgRVMRGuZ+8Af9{mWrIb<_LI!auK z=q3KOOMX`>L7*ynI?_g?2r8hJD|E~G2PdFkjPQN4p>~bzt}Qbas?)T4(>xBmybW@^ zPdU90Y&;6n90LZ4J-mjJrg|LS`bJ(E*Hy0XrJA-=VyzWn4Jq?0XBnJp5*s)Q@_Nl7ymF|I4{L^9^%tReMZhydSl~k{Kev)bDj5Yc%VED_ZPJe^a zIj#?|5@N_BoTiDd2H&P3Qm^bpI5^A-JK%E{)I+sd@VIPa-+!uE4$fhrhhl)4iE;bB z`(fEssD%FvDmW@ZHDrX1*ORN;YTw0U>z+N>l71O|%<_`4X@L?J{9(ww8&~fVfK0L% zGzSc*4py5hR+IJ5Oq$O8O(M+2Hp|T|3lZ&;ly^Re0{Iyy#Z*ChQE7L{(&tsTXcBJ#FV zvZ0RMFks0DIZ~jwKx$E@LqDUAs>CO4{CvGjO%6b_i(V>&MM~O;!PvNQTFilODuESc zy8ZpxzY83d2^e?9?e%m-abTEhV*c<5TMt)F-G-r5 zQ3)C@j2Xx{MSsPTbB}#n$+d5jZP-;-9H1lwRbu}Oft326^CIFTtjy%-+wd)*+wx{; zT#@-jN)j~!e#R({HX3$Fhe|x3cl+$r{BopxUan{!uGd78(nR#;IetGt{{@PWd#YSCew%l`82^9FJ7t2eq{(*4&;1fpdtpAveo`kG0d~`ZY&LMuUrKf z<2-_xGcS&5Q|`fYE`I)%gAamxMC|=35fyzPCRGS8|2qn*wa|-HN>Rfbve!` zv%VW>=xe(d@fdeK!cX9)i`iGQdZ@yn;KPH~jMeSEVeG=S)NRe18~(_G@}eqAX#2CL zAxQGK3l;Yqtin=I9q0P;jHC^61*Jb8G(o^Z=ygO9G~D(P)6&JDN4x3qW**tLOMZT# zDb%)CQ6!3hhv%>}qek#r?0HJF@BP?q3XYy*%>C|GH$T=vybsI)2A6$O ztVwe>hNf4YEg=)BW7_agr*GTtTZHfGZQ(@xk)D<=R>n_=wUb~2Ih4Hu7|KuL&`s8K zneHd~S{-n$9O+Hi)N|edGjkxsqovTV*W#I97*0TpY1K4E3Zd`KPPof`)VAw(%z_x* zXM!Y#Ee<)}XW3`_15;Y`nudS04Lo+JwA*dr9!)p>@DKA4QeH3ko`!M!TuQtzn+To0 z(D*ZOd+z+zJxGJQi8CQ4d*&Xg)We{&RL2QSMrnmns@hyH!+0r;DZLg&c|VKbFNN;1 zkUn*X%Kyv%TAsNh%&M=Z(I^1j(E-h*wj%11Hk6v_n!@9;BuRNet&q=IFCDD5EJ6#dXmN*>zIE9 z6GeJZi12RMuJ@~v&>_!Z$HqweExF%(t1|Ri`@~7J|7w@{TTyX@}q0~+7Hj%Eu!(oQhWW= z+aD`>imT_ji=G1-wnm>ez_*1#VJ_G)((8k6=*CO|M-5U=nJk^~Pq?+@C(FISue-C3rNmk< za3T4W&Frcj)bfk%gt}MA_4L6%r@hoQX?nR>-X=&;&yLxXadzfBZ@d)t>Sq4z+YG@Y z?5JEiyA99#Ml|r;$?8QsM92H8S_yr;ywUQEiGR?QsO5=G1YVh~te<*<6L=4h@7?17 zhhqB#@7{bGfX}gWU#4haO{4C}zte4X6^;0`wrm|hD4?VeNK(U(ldEznMv0&2#_DyP zJ!2_3$iqorgy>$%roirtE=SjhqKw~X0;xDD)}VN+#}pTS$}eO4%bA!%U^2*w0C}1< z-87bKxx%h28{pdBa<~~8K>U}kHUw_lJt5^k~P0&zMr?D~6?#UFh{>Z76FO)apTDmwfZel~u@Ws4}WqN{aDW-JAkEGDM{ zg?OfI(~D2|NW_r;RtS~DTu|y@o>aTacd(YB^SQ8SVBi<+4iz53O8y&w7cxW?M+PFV zXCX9Wl}1K^T>a>fD_0GYjng;1S@ z*9BB*Ul_&xX?f=ctd%ue3V$+*>UHECX}*i;;5Od|m*qO-?By;r+cSa!zhFokYw~wd4|b<; zTjhR+uc$FB73-U&WEC9IbVCg@l)Snd=_>RC0e$M-zvyl~ecGhORpD}4ZO)Z2r zq(5nehQ1^c1_9T_DPeB2T~|4#OAV=hg>pP2Ymkv%Qxv4f*<&f7(TmE_Q;n08DSGsm z6Xd|RS$V-9?tDT_&|B8>C_Nuk`kFt<|M?Y&EF%e*Yl!kxx?s)!vL5i`Sr-ovf8px* ztjB&|70k|jrB^^A^$$!FkfBI)@+DX~)MKA^%~E;tVV^Vzsk*MmG>DCXN!Om*UcXv> z?btis)g!#Srpd~Jm=lYDh9I5*zxaR$TS6A5);Hxq;mwdo7_u5o^(5OHCy9;SfIY|&8OYM^ zjXmrGTsnW!o2qsGyPzrO5;sf$G*5%M=leJtaP3?Kc+I=7 zkBp=V=4%JjuH1?OjY0;-+0(mm^7Z`5;5kQqtq9iFU9fDE!^;|=dOmS|IY$b2`3U|FRCB1}TKmc=qjJg!GoEUB^iJsXb|LcL95wVbfxvT7#zWL1| zk3> z8P+NGykRf?1KBx3auE(^&myrbz@iEBd+wI>-w$BtAn`#Y*H%!^ky3NMK)^2?ydMnW z6B-M1umUa8u{GlR0+S}01M zRnfl-SvLn&-e~yc~wS@6RXeGhy z2Dd*5O!7T zPQ?zI_b|g}Q6a$Ss(Sm=0d2KXlTtI5{JzXvAj?V56O_v#&5N(F+CeIUQgI9fS#v?;jjiNF`N+Gf+DoyGmV7T z$AMuEjU53Cj3_kX-|U@1glgm#_ske#vvmU|Z+A-XeD)aG?gXSf zO>_7Tx^UM$)-i)cF|wHvW;yulUdOQDk2fZ@$Kb-c(^v;`SH~eFksRF#^zq0w>qI-Y zj<(_5wthd5@m;4!h6gf2P$ZIEKm0w>S=`~~(Gfo34&?$j()BA9!=85Trc(zd1@Bf# zM%-2Xzvp@c;#jcY&}z#BynC0}B5^Cb`(j*PT^~SSUT~dY?5;tXj0}t!j<@VdJU!+e3>Ih5i5k zMJ8_z-`?#+7VLSVez=ldwY*+r%7MZ=Mb`&+=5?s`F{<0H#jmK!_o5D7TknM zMikQFNRvCNzv~lwP6G5UN|S3b9Bo_(l}IdR8zqNWU%J==Z}T|jOVNz?=P-XFI@d7}|Gmpw613b36N zidAC}dh!vp_X8RdgN4i}OoX1Z(aSO7EQX@5+Cnh|j_@NUBSKxhS&2GP1_=&cdmbd4 z?76Pi_yn?}84+Xk+!k1@c?fi)LCb3l!cJrtgf`rP&~V#tgd`4VEka^}Cw?G7;5~H{ zS&c6#nQOxhgsA5SY}pV1W|ZKB8U>w{*L31Tv1%P@)^&Ve25H-%c_{Sih3M6EqC=^E z++#G!)m%ZGJ!m{mIRNzuIVm^xJ=cP@z9daiHRn8jFC$WEQSfO08kyWvfc%3`a6ylH z!F%f;Vas{|b4H1YQ~Ta)qaWVv0;>?t5n7as5damjA33zz4o9s5|=3^qs7Z>AIrXItI(8bI>yxRJ3NW5~=td2X;0cRxHo#DpmJ*1N2Kkeb zNrLqfWzn*2N!IUCyQ5BqM&NM9!`k~}LyT-+tRDMwS@uNN+XYvWoaL;6W25GQFz;t< zs1|Tb&)w)%2s$o=SNzifpb975QnI?m#&%Wr$Otp#YFlSX`+Tt{?&E`uKE}FKs9zc} zXzlK}jorh|S26kQN*IyCy*Qs_FSYB33(cq<+;;EF`$jS{R~;DJ7Ry3M3@T3x`(70} z_W7b<7mAehXUR^Hhu`fzl%=R@730Hk4Nf^)0Nt_Jf(q&pgMy9gP;fnld+}?ucA7uQ z%pOO7v{q`27AZS^kTB8&qTO{N8vpjH0PjT=6cjR&;u2oJkdApx%PZ9Ee4=x%^Z)XcA`^a4AgIHWU_!ukE79}Khjlw3{#ny zMJ~~9&Us?fp@hHxc5^);0w1;z_J}t$VwNlQY<`vgQ0nST_OZ7tu!)f9W4T-?2hp{w z5yqMOi){bHNtx&qKL^LF}<(tw)IR{?i zP9as8q>3^6kqtASv3IgQ=4D%2o13|gir;J*gY73;&+6y=h3iJ?(M8*z8oc7XpI^(6 zMYUTAAN`fXrb(gyCb~7>+b0lhA+>KiK6{jgw(KhZmy3^~qjvH-lA5dOr%*t4LqoGF zb2w~lvP=y$f8wTQRU*S=N4Om!G%4(MgavA)h<(q&FYp*1_0?Hol;BLD@kv+Cf)J&r zjWWYDE{jMalElLO2*fxhAZ%u~pmjmlQGXV8X z_SC!qKzsw;yX1OE@$tOz;(5!QCTefmtAN*4-2A0oaBF(Ixf)L+)T)qdrO3(mvYs<0 zRCiBAbZBHz*@~DBn1M5D33UPltppGj0GD@_)sKp>uvT=OGQ6)KOyO?*hsV_dT(|;C zmRuDwN+@T3;h`XMlOFsosV(?l#%tE-a@Y6@UGs^{#ghskcaGq+qRlgRqb zvmWbWvt@Mt#m863s+;__l0&=o)=c$9@5hJpj?2KwB{$2td#8 zn_}t?MhdQ89agyZ>UEd9D#2xK z`f`%1B`%nE*L2#ijPiyjZuGVN2+nZCWp>hZ0Fx#wx(B)HvH@~N)v#m@UVJ3G$QnhUp=w2HHji&fvZYH_0k86A{qMm#rT0sX5 z6Z4Ip@R`%GUsJ4)5sMlEpOi1@#`%_#Z7u2@tvEwsfku#~40BP}Mi+7$0Ri<*wv6ho zh3>adN!c}6`@35W(YXK%YkUuLLV&697K6_~^>^b(5%OPak-@%q?z3LeGP`ji-dM7(3?1`AfM%+~UZnuOzB!R8{{^`PgaC}mo?WrzG#+Yb}S(WlN@ z`N1?O3(4j+vzq07--hcG%FH@QyYl7H)w|z}ZeFK}d}$m%t*5G_X)eA^wgM{JCmN9V zI~5J=eXKYyT9g=oCfBAlXSpc8d<8&^@SfVaFfw5AWPUEE+HMm04_`Yo_2`oQ2&iJL zVO+st#PjT(*h!DH0$ou5$i7{kh}K2r!|)?wzV;C_VrRB&ZaUWzcAx~fYS%__(!?8m z*X;rOij_pjGn6X7Rv1|5N`uh0$Vt2YXZ+?TX(|iXKv5boe&6-B$O!IZSY1}=U7q4{ z>iAQxV%A&^_i^f3D#zeaVPrRBjmFa|*a;pNcfO^fIUtLG-qsUZREg1P0TfzJb=;9D z40V@63La!Y^SJTTW&!f9CP5lfgL=!(vfQf`A(O?qxyJG+6lz*g9Jpq`F~+FJB57t- zKj6g`Qgh8L0^oIyXFs+j9jgRX3WYM4`Q zl_xXAsD}a}SGAJL#;`LqipDI>xR7iuZ4WiJScO$PEnEQ*+BsPzzU*W%CGmD&PI z7TXUv-JdJ5a?<3fZpqbHSfyNRLfPU$ov$i$o8#^_J@UkU|y7vf*ILD zbN;^xPKd|F<3Jnf0k$D(W-F>x*2kg6fB8d`>Jk{t_WO)+2&Z^Dt8o$~t+oqf)1R zoF4h`4!XW!tks(hM-# z(Sm{P)N392luO9Yj+DQsxuoG6r)9SQp~>a_G(A8nb=JxPk;NX^5+Jj~jM>U$81Yeb?YI}D066Fe4jXOSQ@SFC2&K8}AAQOH5@HZL z3r8MR?S5;h@*ubQS8|AkiYG1Yb`BNy1Nqw|o)h99>+?aPutVX`wUvn`228CP;o+_jwYCX`;uoKtTC(5>v(6ik(dtbww zAJCW##WO}S*@}cAZ{(u5i(Yw#mq70R0a%&lPv;vi-%0S~AW!S^_VCwom)gvwHBtAf zo@rJEliX=HaqetqEJQ|UMg`ZJelB(~^F177^OrA)6QWZ)LbHbWR6CLCQh6sg zVmut&H76241hpHOthzj(xZ$=H8H^W28SGvyN2lc)Wrq8++)j3kA;VWT(J}*Bq7Q4~X<| zdZ-&IlI4JaqD_HR2H)6zVqoDQB{Ak%>nEQ+uREAcn{m2WLzv_VI2Fw$6q~VoiM%8{ zUq#I+Gj{I=Wi=9YyRVP{DZA8IA`-y~=#Et&xjxu#t23b^3fM{c;r?jlTCAYqME2bc z<@5F%9tQQjN?AdNFBHz7?AP4hpwLOwoKQE7YHtH=*oY5=H-ZG|HJf0Ke*4hN>$9>_ z?)q*|RgJ~P;W%4-bxDVfTQsjcjI^lFekG+%T6*62nBQlR#TkDuDO+bNZtATSB+47# zXDIvOl$5s-#r+q%lE9by>*6OjL|@vs{6M_U*jwjgO^uKjGa^Q5Ty zeWeVz%oKIzu-GP)N_pC!JqLy%=%|b$B(?|wn0}+sH@KI|p+p+S1ClIj*uGm)LBr|@ zGW8F0KeOR{iB8tY(-IRw?MHIQAMj#oY-q+0i?YqN>$cpdNH~vvPbC^ktKo1j<@R1D zXY{g)o_S29h$iN(@h_bteG?S-Ny3TLa2os$iBEV2zm@}wemrO8&*AFgmxKtA&Q#cH zXwRn$tCq0y>Ec<`F6ey6izLlE*pEm3ThUzFlS-siM{6b=AZ;q}c_{ZOdvN|wkYvyK z)ssatp>rs3|Q)|e~4?{0aQ453Zj zEadyRRR4~2qEoNSSVm68v!x(8P|pq9)06A+PwK2NtFsFTgqf1nfpsMlOR1(wa`w}W zZIBCdV>)q{3tL3)6vZ2IoH7Yv8lyfh3Y3#okzCyke${#Ef1IgfuBVo;5337Nqs;*E z9Ts0Dp}JP=9grydYRa(;KmI$#;*FBl(w*7{MJ2T}xH{HAzVp7!y|c{+?e}lEHWUOPZFrEq*)piU&zs zzfDltgX?IXa5AqGYJj7x#jPXy^Vc)D&MB1q-W5#-SfVM;5eg1|q16f2w7JsUC(Lp0 zqUlP67xNFnGnoHs(cnU_&LH1PZS#lG?fbaGXSWGDEG8=nkl4gNA(s$@B5E+Vq=bcV zCIzP_8HOSq^TWq#7zDw}DCt=s(u=(DL5aC<;}W}Odq&M(I7`<#(&vnS1%8qb3Uu?V zp$4EtBuFb=^K`@SNkQL=MI~hSlo{uAYe=IlwJD`8_>dAzcvpyt>2=YU62i_^;~0N# z;+`k>SI=f$4HvbMGNpdo0Sr8mrU3EalZ5EN{Kq-oP|qvYdpQc79j>2qGsKJgUJIio z{WD$S!amr4q#%t!k?bSE>ry; zB#g!n@Kk+8d>RllNj@ZEXYAw9{M1v8QwE&Gr~lHZSHiGZqPtlZ5f9{BmB=*@(=M-+x z1#-ATbD3?3$j-HvN!A-b&;k~GVb-p(=JX)C8RRKNE?_cUna~}2KdB#jcM9IF?lEdF zPCRP~Urk6sumigN;+!?7Ycx3I&Nwa6@p=EjjX$S_2j^BR*@m_a%>T{XBKv%oTc{9k zZpC=LDI8r|hD&pF{K=p^PKnoYlHo80I18%&p^ytqT4^Fgiw5Pr!KA>+vr~k~5Pu<0 z_#T5W^|etqUNIlUulZg$TxMNE5Yox+1*QcYX(6d-a?7MJid}`0GV0)FeQPE{GcOK4 zLX^V8aZrvLyi-Ys??wrv7Qgd_@pJVHxzut9`V)^3A9zOTSM}9Cq!9nm^_t5&noinl z1~ep>K9*PZ~S0himiuKK?2 zdtvf<3AWohJVn;#H_EGkoY^sX97{E`&w*U6b_?FWvL^@QML=oIyhBZ`q;io;KXyxT z)A&<~lwY6rai$W=B*QQb3xu`kW!<^^&2IsV1~y&<$P~SwYA!y_ZU2;Hl(el-9TIYV zQ-~#ImRy9cB5DTh(e&ruux}4?l?ZP68%!NZAO!t%-urCec=pGI?JC5%HGhxh_Dwr_DGw95S36Ws{A*?p7=IK_V4!#t`|`&6-vqLv0yuww zm7mc4#8Yjn@+}mR9fHh#c)V3@iF;N1v;_y1olQ=^ z`~Fv?ubB_0uc7Q9^^uL0+U=UG-<0fJr|Lb-y>Fs#yPLvwa;ZF-Lp@2D17PW#^>7TJ z0y+E~?~F0TA($C0oiNW(`fcvsXVUyO_8N4-WML3{=y7f1LBhfVEU0B?iV!&V!K@T& zB9qdG(V7(3FMP^~eUE#Y_qupI#f#{sAO1BFSlC8DeZ&`Nr63en4az$^Add>n@=&|b z!CSqO&*Dndsi0jWe2qE##T&QOCnNz#tUOW|-=%whA8kv>w34hT>H12F`!bJQDe{e& zNp_gtu*gr#=cM+pp3p&)?ATEYq}y3hXRO7o&Mz2Uk3@xQi;KaN5{hpPJl983Xy}qL zuj+J=(z%<=vhsi;BI-F?@fKt=xEPxxAJ8!*%XGqPSGt124BfVZ1lq5_A2r)wg)ijM z{f-&9Rvx0tTI%pC1@%==+6C0$!$lN1{6>~{89ll>+>u57m`{lJzk%eag$jDc3mJ=1 zm~_4gdUC$8<(d4a*Pz7Xp_wbx!25Z9Ko`wbv5laQVvMC%`^;x@SAZ$eZI=EFYWq3~ zdkUFRr#E4YM?>6aW@DgH73eB6e;ir={=WX-tEW$s5p_uRlTjLI` zE8D;F=zUN<(o_V$EiY!aSX=2>4pW1XJwacYT(9v~YbYf)wk@dUQa~}yxHBGj)CL;i z(s_n#?z?6^<0sge$H;Qa1FU{<`#RSF@aL(+KL(Ls^Tjjw+qv4^f$gBZBB#MBrJX+~ z3r)66d$udu*C0b9w=Kp+w;#|t%C*T?e!hyv%6`gsKZjJ38RN2;;wZ$wQ40HXh=rf5 zGRCE}=ZNXrc|TaTZbjsqJ^xGCIR`Rch1P@yaktdUM-thVe-_i+<9A@vQ)!F0rT4w%xUi^)se9g4O7Y!o zKVE&N9#xMQW(Rz^#MQ5x!SAJM@(~DDdJN5>#iXprR=?JXX#ROpG-Kh%1VuZHnC*vB zp3}c2s|z<%Bke00ZVh5{T@RnoE=3LZz$Ve&l5z*C8P&dc8^k*|C8cE5H+EcBRPIEs zWIzn}o9(sZa*U71LYH6cl;W~``T_<6vHJI@MAal7_c!3fa=1xx5-ugnuMzlcuOG?+ zLbJYmsofuR!)Z`rz6su=7`_s{CsrV~J?69>Q+6LIa608uL(T3u`J;AOn|DY6_F;%T zTnQ-JOcs7pM$>YQyB|R8jkZwF)oK(w{B(!qp2*p4Y2nGu@Tj9Fus&tTyLoxn z`T3GTpW6Z2?kUsiv$qQeN4alknzSBEI{op%#p*Fyeg5Qm)~S++x9VTB>`Q@-g9tdx*m{_f}J9yD=yMoxW3r;8bb*Rz+Zjta?Q0^lc&HS*pD@GFxley>Pc;ti>pz*@v*%p9_~Y!D z;ZX1}C?1z0+45Kmf4av_M#mkR?}ffH_5W==a$8`D2~;;C!W6ePC(B1FwT)*dOzE+L zHxDjqld9t<3vh|6_d&>0N3rliegt>NF)!Ar`+xXUh#fEmrmQ36WHz%FZ7Y?S9Jxr- z!LGu=5hvkI$(LiEw61Wgk_%f%yZcmcMwz817m}=Fd2~F{)lSSp5`@d7dVmzYeJvsE zNPZvw`QuO3!Z)_)KRp70=(1#AL_P%Q98kl|(+7F1w#))RqC{9rrFe$FVA2&7WGN2G zYu~!I4(ms>HY(cjQtl__>QM3C8`ij&H=T9d9m9vi@RHUL%lSL*_TClC4-5aiqG~wC zSIH$o=?~SQpQMR2jhY2W%3 zWB3BRcG)KVspDp=TWSe1MM1=FTo0J+4cJ4n^U|>Cq*gWnzvEX4Msd!^W(7e3l0_qW zqt5CeZOCbb++Q9`&fXru6fkwuRUW~x*cO-h{$Bx!1O1dzhhStn17kTe+;sped6FRj z?MZ0Meyv8s(Et1zz9LlaN6+xY>)T{uqf!hSQt9cu4x-rM-#cSkyV!JwoGss3B6c#U zIQ$>~;$M<(4Tl7@&JFC{f{R$0Am8W)zkCxn6zNo~3(Q~dBadT87Jt)2+I_qam|)sr zM9R*w%p?`|{Hfo&9f)6J?xK^!cOEsyL|*v&leaP1XT=qMJz%^e4#*ASGvPY=%VoT? z)R$R-Xn{?SlY#;nI?d>R&|jzHHpkhe`s=Hny}+DxSUyR;9}YhzYO4tuhmBtOTsQ^>@N zAlI|E#akJh)|>RL6ta{2WQRXoIp(6Kq`W}`;S(0VEYoSLev4so6SW4N-s*_1luW&+ zD4TKSJ^QU|H z4MhwCO#)VO;v;A!>O1{Ux-?R~tnY0YgLni?`-s=CT6zrG%%{0C7exyF?YN|1x7^P3}}>p6gK=$ zFT-R!A#@QlrEDTqm@jha!>&tw#Dwk-59YY(J~`~%>Goel-6`A~SW_qs=luJKHL;}W z2X{?L5;SURe>lQh(_8%+76R!a{VP6qv`s$KVI~D5N0u3F-r{=K76d~=&eDmCI>xss zh%EZiQrqWImElH(0@R+j%79M&*n$Rl1>nj~lZa7dO(6f$)3--b6K@raV1#_Qe2ZkJ z5*vF2=k&2sF&Tg|u2Wzd_y43hBmSeB`nuQvN4iOHQRegjV4Yxyn>9L87bC{-jO8%* zyrE^F-E~#wJR;DQb|I^F`+H~JpsQIw3iYg5!p$Dhsv@aP*$@4*e zzUfHdVJg>-M-7Hc-K$ZF7#dCgp~Y~s-Ka5%nF&-pVMr6@XKFxcZJbaRy0~dtEBqh6q2*ITJuIhDXC3K z{(k){JIN?Ru!oE&0Hg1Adb28NX79&!?%9BlF_C%Mv@UX#9I+0J25CI5a)RtS)aE=A za1V}TXqhxc*eOZU5t30Hy<4cBZr;A2ZQ2BKt{?cYjNUD+I&0pqc8wkHv_*7qd~d)M z)OQ)5!W}!$f>B(eQL7^tD=RT8pFvHbylRU~Cgr_Zu0AV0A?Z^q)^b)Ya+@ji&5h>b zd8KhL$^SCa*DG*{{q9GhPw&1hr;wIC*VCl;*(AHP&P2a6m%v>s-{I89bp>x;H# zx<${V?AL`SWuW>vhS*{p8PuCk^1p9WfIMF=DG(;)SSjzkl<%Zx*sNBveVdPkjz}OY zk_5SH*F}=XcIz$?QuJ^X$58a$MvM9&Eveg4LD;XI&_=xXrKW72vn1D``Y0|!%>p0) zB0ppqbEZ0`P%a!9M>Px^K;-FmWn|JG#8hB&pUwUO2@;E_?U-~vNv>H5Im@S ziz~WS%6K-$W5w?AF-U>v3O(}JV&IiaY%`$JHIw!63~76OJE8Gv?wi1bgN*mwZwr!s z4J^>?e&*Lo$dE&#FtSiA^2cB5g&luwcqUGhBMvAsF~f$Rc{;%N{#_f9@SS_uY`Clr zKMK*wg8ox;wFhPBv-6IYWIGiJIB!G+bLqSXH4vHT-#XNnL1r3UYl10JUctbxm`HtC z@oMb?D=)2{J5jSyZ~S1;m07}DE;!VKGkJ|hdW?mp#LV8inChC+ZmB2 zC~nVUmCp&`_tlQkgVR|u6j6^b zF+TuT_`^x2gGuU0XbsEJ<2*nbrahC0QpiOs^1fhl6n4{o7{hrDuMT1EnhBm-Xz2uR zq%?zOogN;`98Wn;ms~`?pHv11h4D-yj#nnasLfp+abxdc=*fO+pL5`Z+{_RbOUXF| zqlOb_%fakboq!uujw=DpaDnwXQ{Jx69cI&?A74%iSlq>Oq=$7I<9pmrj_q)s_EU{4 z^rYm6?y)PoQT`xDCzlipwoVynrYk%6*zb2=7O0^-t9j#>i#|=lZb<|s9m}+sb=C!V zDeYQr@KRWGTae+;MUputS))D+{S~e5G4trxF!Q$N6nDv;spa&_W%Rom_TP!U+9~eZ zjC5L&weW*G|B$>J$a5N!xrfBuh^b0=ul4U#$x*W2ocR9{gKy_Ktxs+^5l0~rp}K_- z_(OMN%;x9Db~3Y|kPvUTWXSlUdQ}@N6aFV^f|clW<-40*L~~pFr}3#wL3R6| zhb;FM4LiRFp;!jWCRR3Ny2^-u1Hqfb3{n{v#;E~(8;2pRHB(`MU1LK6U`Q;!9HT>e zy!wxF1vrp+j-Irg#D`y{HRmO>#pXI6Qc(fGtTF$pGdW$s6cpENm;BfaS(*pfk-_}4 z)OolP!3RvlOpE3?0-2V`6aKEML24G6rQ8U$#HNHHNNYwiM8yYTwiA=GiT-J3Ho;B}t7hJ2guShqnqYYkgPVb)*m_KsLNqL-T+syd1Nzdu(+_?5PdRL$>F0qeKDsT(f}9mA>PK0@m_Dp=~Un&!q8IQVI97&GvSJ5<03$#@fXadg&4 zw z;AMh|31WO&I5QvgU%{~R$%mS+TPQ?>BsIMY#5^ul5i4;kx~n0B>uszzNzZpm)f{WE z5u#)Y=PvPe$j7zk5rq--Q(@KB`yP`^OfBk8h*vCTHAu>J1M}bDP!#iCGUvqN-YRX+ z`G-l=y1hT&^Ifn7i^yC<;}9{R1FTcNcU9oqBI_e|BMas(0vSzYD%Hmvs|GRTVka*9EY?bwwq~LEx8Y2s6OkxRvbG>s}Jp zg0(A#sA(FOlmw)ux^fE#FUDJOQq?|-oM6tWs3QF-R!;A)rdhj-iD2vuv690`_QN(w zeEXzHyndUl0fNZL%X1@8q}qu*0iM+|`h5QUu(yMf)7{K=f!%$dsn)a^meRDY)-8Bm zi*exR-zYB$V!jWi4a&NUl{icWXrT>x(g*Nz5e7KzM>xSIw|3?wUDOe8mf-#NzP^a@ z`OXf|qEN96*4SP8UY7dP+yxbjSf15nI0jy<|d%YSmnr-rRxV)vg#J+A+~ zK>UfbXwL1lxor$ZzYkS9u~;K(G-Lji{84`2L@!nJ*1JzTvA8f}f~jj#@&e1ESCX@=+oTtwDwi?dayYS|ei8HS2>wsz1B z{j5A!=r6qYo1fP=;Ag9dC%F3A9Rxl}lZoWM-b~lLL4c;>XLQ;uA2(k9to-)k_w5(C zIP8h&fs6R`37k1P^p4Bj_h>n+4!w&((3qd-BbE1fiBz{c?#X&EtA0rYxSGkk357ST zPcQJy8!@9pohOG6vhXA|pN7_M`{CvOhyy1O%J`l4d4Qwn zD$DlvUhqtz-!hc-?Dve=#tR5hXIE4R;A=+@Rc8Bz;N40MK0%_Z7Sfg^%wf!4FnXGI z_f@6heVSN1Z}gA~A2h*z>3L2DQo_brC9gNU8@Sj_9Cde*W+M@~=`(yE-BN-J0a--i z>WdvHpK=}dq)|HGuO@=d@h8dVJ3Q>e?>rih^`L87x!sCpbbr#!EZ=lXh z&CB^nqp-+p#t48)z``dqn$e5#bwCL<|l}lVMu$(+{IVcC=yq|3|MADjYb-b1{#z2m66Q_mGU0O zZ5xj2Lg&7`9le@f^rm89KZ2zh)63eH++*56HoU9hy!E@7yM5?G!&>=I^9D zZPN898{N_otljltjd=P{MdYYiDvH@v;B~xqeb-pd7uV>4jAB9cZz05{|5L}Rf!wvt zEx!LON*40ESg!TcdS%Tv;5JufAkkxHo9;vC?sz0vu!w8QZ`&?OCdmy^&7fwgxn5AP6tH- zWr8&kgCy16c^(;K#>D8pNk$?!_oKy*i{3gW8yTY{!IrHlw=uZEnAk=!>4+?CgA)Yn z@G@=}$oK6K>HR*EaMYaW{}_9dg10_4;F)MM0Sz%y1+)L|VtZ$AT}B&Sid&USE}BgJ z{jWE%DV>r}?7vLRcf{Tom!)mi3U|>aNhC!KAB+l|1Y)I}7fl9sRsWnpylCjIG%;V( zmCx1(?03Z5$&uunY;eAHGoQRw+>y>O@RWMk0nvE9G~hDHXfc+~h& zhN(Rby^!zvv7M1Qgay5{HAfXr(7^m1#;5KZLcbtx*A1Hyqvr?b5wKZTOK=Q*Xt`SK zUUVIq1u1_K92*29c#Auc{^4!9IN^b0EZuw6Yd`6Bp09+Cy$nqWg>>Buuss5sO* z-Y$d=Vrg-nwVhYN^#pw)W3oCrPN(W25)UKs_9#mWjp;(k-+aiml^fbK<7!m|YI(ab z1%dU>gZp2l+1yL{B#(aT;^{uq=U^_r1kzzC>1yLF#WA1QG6O5K2`d<+1b6{I1X$kD z9hgR0kbu)R<1fDN*|FPuN<6vU4}{!2N?v=PvEywnYGysO9Ir)(fqXJl64-bcgA5c0 zR&^v*MrxYn+0zIz`_~XRC)kvF7sZO*#{?allOaw6yX8ZAwE-sQBGGz*IrkTFN$phP zfXRlPsTJr*`8iRz3z;gq01GVj zfZz)42z#NnPh#Du;q}jG9iewkMCZqnCuIJN4zB0*{&1}w6!&#@LH`-S%!gxEMqPXO z$LoO$Q_yv4gUHK*q=3Gi(?Sv_FLNbVhZ^Kiho4v=L%D?APnoGY&uZbKR9(O4l&^k(+JHl|4*K8tR+B1+q+#60Q)93VRwj=qa9+k3XCMC$MfDG0#}ZPw z4&{=1IP(I64RG2b@`EPbCTlj{1XAa!@s;ZJQK9n(Q>uXIl~@>pYp@Z`WRR&!GRiChc~WTt_{kbwzfv@SBBgvB9K z`@7%T!fqEP``bC(N>nF1#qY>!zigTnZjm)58a=IBjG&;yIzu8L<(x};*Xzio66jxm zyN>i`_`Mthu~x5tzM3Crm>!>My$K+xA?^O!b5BSA_R}SO2Iih z@J6m|)V8(ujl+$hnJ6g@k2#@Lq5bL?qU4ro;(&P86!U0v5#+FEWP9nlStTD&@shl8 zH%$l`B_-9i%o-*JvMnnT2x98a{_&rimI$bPQqjHF&Dj;{d{=%jS|B^**eAKVlU`Xq z+y5)Pzv;*mu&UJ)r9jng?~h2BSO&jlWS@}qmTR>n(*!&`=u#*I&!_HMm#is=EJg{^LqeZ$=aEM)fEUE2zM=nI*YPG+(9? zn%fRAF%`36V|G+iE;3K_cjj%Ml|+%O0W<@OCAF5c_*}+X3`tKdUfT z55x40R}g}F6YT9*qr}MC@v9xid3Z$M^Ruo53PNZIgGCnmPeo43^^iW;9>qEl`_rE` zOFHrTB}d~46|uITqwPjbfM?%UjZYcNp>p3!x9N(5XFf=5xquevxDXx(CM4!>!gz8x z?l9@j!Qs{4=lf${Cv$yyapTEylFUKvp>R-GG&v{%RL7#KY{nA+vn-th5)p4QMxw1k z)x*Y$Obn)`vjsM+!eg+IB=7oBic>PfcrSxP2sVk3k)DB@}h~9$^#)+Ov?JGuzO?=N>~^4lv8l+ z2IHrqX457#OlylpD(BU{a1ZlGZ*5Gv>M7zc>-EIppBF5MHbb?Chkt3e$4u?Y**s#l zb@)Z!iQ(+Lq}n;1t0D#qP#=j!S*$754)w!NcMETcVRPSdyhx1U;mQehE1;8EZs*8* zqB;$fY`kaK=7e6AST$&9Z$dr!Wp|+c;h&QGk02OpClqGRnRDyx!Pox7>03oYh2OST z<&w=GPh>D_$CNCqxgdrT_1wQ56y@IFTBR#2v+PL973*Gu{b*rs=+fDtNs!pEzhlT(%-iIN$vs2 z`p}bkX9e*g1T_Dqu*%A-V~)lUnSn5y#E+U@zx}Fxi$&Ps8v9lPQJ6b2EshAU=7u8o zY6rs|n` zL8c2dP)6LV8I+-ut&Fo8ipa6!V5*(pce>)i|HfrsAY#UIC9q^Wq6)r^|1dHcyraej zfZn>A`M>R1AQw!Y>tcyL!AZgkW)O6kGwniB?yXpnV!k^QZOBCmu1Cp2Tgja;f*3+f(F`HD%u*X@?%q;NXb|6uU+8h3u*SH zM6-k3n%J2k9NRJKyvV*KnoHWr-jt#2uGQrqF(&nE>RZK~u`vQOIpgM%zkP9}__7C3 zrffKW3*}c>o&}b3{frT@{7%jNzFhpI_Ft@$R@4k;PKhI~w5TEPi=orAprIeG-w7I( zt&;ZB_H=U+l(OHZ&U?I?AecZlWH@rn(}v(ZA&lR7Kj^rPDFsWHyfu^t#9om4-VMwH z@I-xGv0d;h+5r4pOIg1EvnJ|eq{^#PNtg$s_W8zlC&VM=`NPD5N}So3Pt<`T=BmtvpMtI2%7=H>F-*C51ymJNN=QzC6DX7cFLAKAD zeJYm&KD~xty1o2u)`jYYsnM-S<48p#yIcXPgiFv9^FRF%`|;Ka1*H!d;Qoaro?ZG^ zTYU&}a9a<_Rv@h{8Q$nGM}+@)QK8c#y$7RzUms*$@^*Uu8h2FcYdM;p95+LTZ zV_c2pW^3y2XRvRiSM?3ujLX(d#d+cvO57UjJ(*hgM&mnvIYv*2v_pY${lXJPyf=Kx z4(u90saft5T=(s}oe?5lTt`G;8l`WZy=`DE>3J=aN&0Cgx1xZN4LX{E+b2fvNQ~tq zic7by>i6|3TJ)uA{>3qW)}BiJKG<>n&BX2}-j{ETseDUP$D?Q&KYG9l8f<{-MR&i& z`XnQXoT`qqWKqcDgF*X>kc018HB3=^wIuq3NQwZ~T3R^Sa-F= zwAMbU3|p^Xy&5nXcxc_@I{9uP;BQVh^WQiT#H@*!merX~%j<7ol;8A*C;1uDYWb=Y)Ki_C(is%O@b$&D_oWL z*~w)cLL6O8a4KDMg=B1d*Q|X9L#CfL@t#wM&?VgMg=>RRG%fs%o{Fn@QJ0)J7DCJc zHe{AtylB3Y(qBcd*k%GP;a|SFHmGw_lYqw1qd^T8zVA!Fn<#F*i~IQMUq;}YD}~S6 z7?(Y`ZZW8r*Xp^w93kJuZoa?!oQ?3L&%I&nDYi!cT}FJZS(s*72Az7Yl$JwY@Zi}- z_xs$`MI!f;2)Rb2;ynb3ZWSQsc*yfoP9H6G0{>80n!E@ABCe(9O{orLl5GRD4EQxD zVgSD_;Zda>Xnk&~wM_&c4M2RGYOZJCLU{Z|u>pY6>%kZS%fbVj_R!|edo3D%_=#8t znN2VHaJ34ZcD$!)CWni`Mks>FUTFA&Q@IAZv#7tU7HS&bb1vx#saW{-A# zxGaLIS2m~_iY;qASoQu^+7j|RmUk&Us#0X;i%B|Wd-@-KOl+Wl=laZa*t!JPR|>KK zTIat=N@yr;ncugz?_b0U{|5g~!=gp@WvIlsJ|5Fsd`d=_!XX+}&5j}O#Ta1lfw2=W z#X_FVI*j}Vh4n^4+8yGAO`F9jt|B zGHwm0OYl7Mag1eN+5b5z4D#XC$o&K?8M&^ghP6>mTTmeW2LPl%TfZC!Vm9}M9C#9b zE(<`rd{z_V;9#dT$hosn_EtzbI3YO;1D}Z7GNrSKl;J<*Re9K0CpU_wna?^xAma+) z1!wOmJMouurz{`8>%nq>udeUFrLZnr$D-%H+fJP~>rA0%-`XYSn7;r3k-88!CWlUE zKJp187yCs$?Fs-mLVd;@z?6ITA>1nC*iGri4QSXI+oiE!sF$rND~jSkW%pjcIwd%_ ziOQjK*woK(%6zCqnjVaK(_S4Z4%uOqVV;W2WdZ0nj=f|-Pt;+{Rol--(zWDJH}qLa z7yg2W4~g9~-;`sq0;mOoKQ(o{Ty^%&vXQ@qKT+Xd_xbd_4`cnqnV%2C+LLRJxJP|R z2bHs#?LaqH$_{9Cr|GynfvDADOn>r0*%qIY4jroTZ@-`tP?C@D7z4DoOx4Y zY^R+0Y^TpD{pidMz#tAWH9Z3hz(|v4It2xFE=&;146dphb|#TkI3J8xZZErW@=6?2qdH=VLPe&|TK@xDj#)H=@oYPdVjnljG@L6&N$rwO`%&{Jhh zwoM@b@FbzWT`_>CZ!TG;uX2^zAsropkqJBEd_~}RvW397kg4KTW4y-HE)Ims_;8bh zT=OjejRa$BaVxL&sZ+P^)wKB*)&8Vo#Yu=jjA9kxiErzrdgSY2_%&PtgQca@RIcjC zv%a7TFzs%>3xFCP4Oair5g&A|Qy2h@MC~@Q2_xSAkqC~O3UOwGp~<>1HJSC{fA^N6 zfz)?A?H;mv`G2zD&;6Cl_D;J1>_2#<+|EDfxq(0Uffc6p%l(T3gL>Q8eu!>uQ&S-~ z`!+;(^0t?ph$E)rB!!FktZ*Jh4FaI$tOp1|0l<^GfFD!C>`;s@kGvS!T{OpI>yzwc z5Es10vGFyKe8Meya1{CZ$1Jzp6I~Vs{^)%A+9e=!=2h7rpI?CaEybG0C(XNfD3l5 z^m-{{oqo9;zx#LK7~U`7<-fl5H;fSnkDF*S4hkO^Y+n1)&j`*gGgSHMwAnTD9bzq< zTa~C-%MrOvROrcTL;T?D`GG!T8`}|j`%xxuy(n>2QyJSO)g4u*DmfYL#8r=+Q@O5a z@5LNL5s*NGu^RJuI=cB>0kF{;l<13+?T)RK`PAvt=}|91YmE^&HOW2_qUPWk`^1TI z;hxQtfBpB4M-G&OClJ4P_Gk618#!W{yipxIt*e%B?~b8CJUTO$0lGe>+!dLz)51Ko zJ3hyk`SDoGsf*$8(zIiN&JJKKA_k|=jc7AE4$CHyj^@vte`f$z1;6R&|QGYn_f<{Nl*Q@efucELWN>W+4V#WCm* zN#6x&%BmWO9nRbUFc5qB%ef>@8+JXPp5RI*q4Qe+*u2*6+@YqdW{als%fcYeFzyT< zzB#G1*R1y2BYoKD(qzIT1}Uxp&e^u9Y|@u>GU%!EJk#8dmw@#5{ICGjx_M5Dqm&cG zw*^#j6Nvi2P!3i)@d5!0!Kby{voQBtKBAn-U*DrAv0jC6-C>o!8LP6MUZZ{X3p_hR zxC&zBW;MP64D3_qrmvl|#KxVXU8mK8*4gkH%BL0Vl;HV21KcGux>1a&XZ(|xIMjZkT-u-Ltwl}AaX-!)RV|@cwUsr4D zh=x;k{kle{Asa2R|G7|dPzRtr^OOT;xK%k?4x>u6>%udN!)ibnB#LfjERfFn_H+r- zn%ZK9Z-i^=kmp6FJ+fOXqcbEe!4$BuXVww#Y57L*GE$sqG7?YwGEGn{@Hn%ws0KTcV0fBZ*dPWM&N zKu7b~D(VO6sVVdnA&=>5m}(i?X`^nX&300ku^6_^pH6#f8*T4c2dTrT&6upHLwo9Q zz=w-IQJ@gA2zNdxLO%l#Cf5`|`r*%XtwX@g6W;%`CjR-aLwpBdiRouwqra?rwCmBP zo{>7Q-(mN)s;-0>$N^XK2c#8anqq_*!&v9~vYTzxjq#ytt{Ic#%<}q(ax7O2A$?=Q z*|C$8AlAE%)0cY}SPY}Mj+d!po7$FT@H%EgmraIGNPPrN7&3=St@lK12Lf%w&Avl@ zC%1DaVtl)A~L zLr_l-p~+;t_1PApVVh=U##m7c1Ne-3Mlo<05wnZt1%Z-8##p=Cf_6v(0n` zKe^fF7^d0RylHcUqUR66$Dpt_+HpEMrz-&UELv$EM>jj=v)F0}dxG`43caIcu7`op zFk-m#W+PCSv<9v2@=1+o zteK!B3S>PaPG9D;0BE8Q8tbemS+MmmHoCKx2Qg+u;1vgW46??V$#xjxdpw0sp+gV; z(sb&m1q%M}wKGhU5Vko5V*OdBsp-s^MlU*13LW5zfgNpKfH>@+l%62-#Gyz}8cdUW zMhMZ!h9fX^Er{bdh-2h-5o5jalv8Q$jcG=HP*w|U{BM!UfY)`S+6fPJ_z?#U{oI#k z2_MNruPg`ORF&c0&1t3_yYXfQD7UB46wodc(Yf9NI0A=}B^`Jv0Wn*0}srfE{xqin9YEhB8DcXEB1_o7HRo1m8tbrN$r15o9#ux8_U$3UV zt?PRa&Y!R&C^X zN12#$i-U!Ab&#TrFBFVJ=YAYY$NA3wgk?RR{%_iVwHL1f=&Y?e>(JNB)OZ!z?cu4+ z?edi50bgCh1i>)tQ=3=r0WHY^qOedgPtDR`jj2EZ#&p%+&2Gm5V*;)-Hv2$V6)@^2 z1nTPLTs7sr8>CD7z|ujdd(r?iMovi1S3o*2p>UuN{lmArsz`>gX;D*M*hv?@ASzmr z9E=!%M5xQf&eUP_m6OnsX!2+LwETP)fYkZcJu>Q0?SRq{at}ju%MmOw3c@sfjiIEv zt{EFJ4xA}@%Mqr^P}-)L6~rg@d~Ca+6R$^VpRE%x1vo`^>OUp4Uwk^?MBUmMb z`eIBIHZ@v!>`0lL7LzhI6*B@sV|oCE0dgclC=g-+KnYzJjiViYXpRl0%Rx?a6j zu8pQvjytRv+lFZ4xcAf6&SwE=&2lHIqIM-s{)P*t4F*0HJ8m>aRb!__VW$a{ZU?MqQ;7AM*q6gi-(wJt zIhQjHqa|C_j2V7B zcFAGj$TvKzY6zh0c&2P^<|(_>D6YTaXsdBuOO=ha-EwXNb=DJ?dCJq4IWGWgY}WxM zgM(dDyi%fv9jyMHk7L@u!%NduR}DkCgLfP;V>q2fN_qV7w135x-z?m_6@LZj;oZENHA}*?qb_aoJ5J9ilrwG@-Bt*P!`E^j#y9tPE3kf|7lJn9w*}7K!9R(G8(Ox>?NZgz@pixr+QX!=sZAa2 zj>W1P-LHt1yCze2Js^{FYB$mx-~K&)1#1|D1;{?`k08)fwvD|Ij2XPvh z!CmM~IdpEI@(Eq9ufzo2b%tBTSztH-;&~J#6?;ptf7oVpu=nr)NFMW}^9WusC*I9x z0qAuq1n1IOFm;D)w@kMorZ>R@*sE)(vyn9T#+oq=UlX+lJ52hAo;<7vf!j7s^QkHC zPwP*N#R8x@*$yWm@j76krwM9ax>Df2SK5K?7|GfW{!Z86ovO#_cxNrcis0y53WcSY zgYmLF`tKH_EQc9Nryk&|XzRfe&4s=;fz?F6c}CAmXZ8%@dAKVSpZt|a$=~2+zx;S0)uWsuY`12 zT0@Tk_IN4XIi`8mnRu~HVMC(CCm&n^Jn;CTa^%>FvTf6Je-~ii?(O)IktKW(Q0uD? zt=Lqy4V`kHd}gOCbvh(Gd(?U#OsOl5B^Bekw4^~{zo<8oC3Ls5BWP_QVKQrPp`)@z zAG8>#pRA4kp7@ScBdHSiJJmSL8t=9Pp)OGmMiU)Wm+h9rR)G~4Iqk*o>0D1njOl3a z>!W9(tu{3=hZ^`OM&!w`ejID3qjOpSoD6lDf)!oMdz!U&lkr?~fV!4CiV>n2mK8I4 z7^%y8PCi@#+;iZ`auDC%+q)fqz;mK<>E4}X8{P#t8ZQ~~_Jn8mnlUsYPkc6tGTR1B zYohNeegV;Lv5%H3z%XnSC)8T*Da&j3=k zP+j|~s_vt2?xR6gGX{TE$)S`#A196zVC9;?NQ7AIe90eb#mYRxSa!%&sG6c(^0Q38 z97}nkA_EATwoG$PyF#0E5ybYhGul=F<~|BPi>tY@F*&Rn7dR(1xzy-ZfReS?G4O>m zezNNT{(A2NSOlglmz}kECA}T zSNq)2LEBSbovVh(Zs3&%;}svsl$?5&Y2Ka9K2Cgs)H=OF(7*xDGI(489K?%2{2A{l z%O3p9*kyb0Hv#Zx$JCG17uBOay78naBG}p1%t_~d3KKr^Qv@F6RcX8NG`Dzx4Mn}1 z4FLS=!VYSlIP$88e21-LRPD9hoRHqA2d~Lb%D=)yI^4KO4(%tP8sZ?g1%ds6jK*{m zI~G{BPyJUzD_`*=tN~s zw*a+uoJ#D9NbZ0-9@f=5BA?Z8usMl_QOuFR{&2QKUr>l za6g3U%FZpD$_vijUEXsyuPkbXJW%1#Z$1k^ z3|>k|J*ue>+uG9=uC2*t96hK-n@@*^FDFlHo{s{3^tY~j_JKzy{V0&XG4P@b_TqTF z3nwa^;c&lNZ#mhRdN3i88m6BGc5bBuIODq{4E!lZTZ92G zF;PJ%$0k77+u0d1ZhfxYySe<@H@>u-w|x^X0-$?Jh5fJH;?Jyo*YAI-+;AWN;?f3m z6*-Nt?6!F=0!)-v%W7bh`bSpiKplzOBx}`UUyYu%kxauHF{&1O{BO_Nc@W{R_uPcP z}Ex(9(@a?x3M4zR8~#xoZG>_9ZDopC++rH@9se@zF!(D6Ee>Oe;495*>S zt`G?w^$#3t0NNZ}3n}(QdgmjJfU6C%TA@Ur#?x69oudb8JFs7DFuNle44SUBsz8u zMT2EhY;`=jpI@2NGl1G)eP*pETh2y1w9&yB4Ie1#W%OKd@NHCrmmC=IN=+;*Ek(wd zHbXG3BI!LIraB;K$3$7?6~Oup<(7vYEB82e@mcLbpbiW)#XKM@t&VmOs|}EF#&w&z1q?BuuZtJsVT&jCn{nhl z|LmR6O;_&S|3o=_446l8eGQWB(Cc5AD=2UwR8zzxaV*)buP9pG ztO}!^I@{?KyxSOYYTS&IVUpdP767)bHaHrOpRXJ1K-Q7ZvSV16?dCykCR{?YNyi;i zkImSiBHHC)@Gu4C{W2B+UIl#c^Y`G3K}TBDDVQ&N-Ua1+JPFswfoz};LbgjAb>>Ma zkc6^FX^^opnRk%tZeUOl7uf@3KG!kIbE0dyC`vnE_3<85yd0;WKkLU|TjF0_ej#pw zrYv`10XT$DY`PVIb)#PPL+y^*)Gz8{3w0yL(%!Du6Ik{n>rjDAm4lL}J`SU5iABJ= z2x0eDRRz~J3j;s5iM9#LoE89O0;v$K3$Gi^jJXn*yJ#2^VFGlC94g^Gj)>7@!f zCZESca*$UITG=jEm3sij<%7VDo5}+RkChv4y*q=RHoqO;FL?9S7vVO5_pR92Fdsy% z!&SE&XV7*j%eDc7Uo8NGjdJssG09=e9Ty+CVV#a;jOzC)=<4 z|KsK57wxHEiDt7VD2MR?@N-xIv{-Av5!7u~PFx8ai4y&&`QzcC##dVfR9-mSGNrl7 z*|#2Q923~sXV5qiHoW~zb^Nt@G7K@aAlF!|aq2Rc1)!#dZ8rx-d~LpyfU1v7VAW3UxBzU}g!lH>l|Q@j_Hu0Ep9uTPt1c>+ z@50B6`K`bH&O2d(-{+1c0||`sfc$abero25c=)vdI9gvMEi) z1uGx(Lt1^Q?Ks!c={j4-%|;s7C@RMeF2&Go5_v8QfYX4qM!wy_+L3<3$NDkb;d-!k z*g9ktS1ajkuD=aK4hLR%>e|rN2;6g%30!pxEnX}so3@nq;|k#JN2k9Hc=Od4^gq5* z^J)v!B2Q?ku*;JWd^;m&KVsslq4vu0Y9}3{c9b@kz!Bh$Ao0WmPpbG-fw$g1nc@mX zV}=)i&fmJBTzC2T3^ZBct=ZiN@Cg9_;Hs_wqCISrH?XytWJ1jrkY};Zax+wO#lYCJ zC%NgzVnvLVFlw0V0jM655h#g~%Ue4Z(I{f7zwHqx} z-fE}PtrhffWq{u3N=q_zJ`1Boj=>%quTT+JnW(V=paZsu>xIKHXzIm*LN=*1pJN;L zr#>km5ze{rSlE&As0&~D2i81eX$z9;fXd@vrx6v?mN_i|?j##4p1a^v2c)t-(VT=( z*F@A1ia?BPF=;t+&CfgmD->Zh+yEG7*);jabAThb4fy@P{w#hU00-NIWI41RAh9(B=uN7bsz~$ z2QpETU(*lm#;!z(9}Y#xBzaQ^D0pAFep4x%x0d(Za(B7;zK2!{{*?6mneey2^2)Mz z6Y5G=0X&fF1V@{}dofT>eAZ_klrQ!xc+gHo9cM?_jWJ+A>%s22>=tnYt8k8E3R}HO z@uHC?KmG8GmkHj+A$N z^yaFcaR2%%FDPH{X92uio|#zahbACw`QDp4U^V%uZ+?RbC||~i*qRA}mruoO!9kpQ z7NtGnw74tR!54yPoxLqU41E0ebyr_l_|fN-<;Hs+EH^!XPXO?scA2+oQPd6#jYivh zeTT7uZMVaiOq(4#I=bLEj9h#z0G}8$nH|Dd${H&x=11qY0JJ_;rk%vtl~7@Bfonip zYLckVIij^H#Ko>UYrzmW+s5$O?z%n0dkp~)dYNno<-xUaGrk zOe2nL#MnRZJvm`rAKr5~7Z3mb*2^xR?8jA|`uE&?M|p(z{~Pf_6&GqWStV2RcA`9^ zgQDph6R~IuyK+f2F)WojZIY?tq2vA=OMP~0PEdmHpBQ=a{fOcJOd{_h)Xy?HMLNH{PoC zhEa{I!x!~xC}-MGaaJn?Ro-X_M<24n+MeCb2bG(3HEDA7F5ByoTqk~;{25@UiRhdb z0Q6P^k5<->x9;~6%1+QiY%UO;WcIxkVId_raoV63)((NOXdlOA%w_{Ortj>I4IDpb z-n6wGUS41R)B8VOcmPgW_;&;U{%fx;*I%?7m&{lMJb_w{IDzZNL@Z(QQ6{cZPDW42 zs&AL@?JNzuF6%pA`sl%)Vnqzaj~H5PI(^qJ*TpP2ZnP)b$9w;MJ2sZ@dF@q&KZ!nN z`NSRfm5N@~2YG?xU!~d1@NusJk9YT{T*iIp}AT>~DWv*JudDlv!pkc7yLUx{rpU(o&660<`VKy4hVe-UXtuF(&87S>}8`hI6W}P`+k8iWx z!$NFR1`k`@29&Ma%X>b1Px;eNO@9?|@t*DFpT6-$<=ib89^4Al3124~-v-n_9Tev4 z#MCDQq36O-k0SI^2_mgq#_^ur3x;kle7|pOQ2VY(2Y!sH=K=6v!UFJjUw&D6^~7g? zw)Y($zqvee7;jMGBigbKi!%%RtDVPB3Mxm+xUJ@5U~6&7*fzp5XAOZdGPG%{Pd&cu zZ`yg*ag$S5U5HbWIV}Ka9(&C`k*SnC6)06jDRX^$hpqaG7O#wEdyUC`A4_>S?Wsed zI*t#KcxOqr-Y!7Y$p<@pF{o_bR-QPquKb5T|42D-Xxgg)R`s=4?1W@Cd$bRuyPH?d11<%4jA7`RPd}%!}eo%Vd&K>Y`181by64pUVM1ffJ^`D_w6p< zd)+m-_fNTGC!c1y6Tj2=j*ov9_x^Z`l4HV;YCWi{#zwnb+$5_^ZEtj77>I&p9eHo4 z!`1Y|Wrx5wC)k)z%BIbEI%Yl#KL>;e;qq!LR=qhYk0 zXb2!yJA^gTdxS(oX!ri`Xm&6>)8MT@UIqNgjdzqk_~=bt$cZ>kmjC8UuPJYP$v%C2 zR{O|KaO0#-ymZzNCTGTTA)ucZ1W#0BEGu?kz2LMuT(2o{tP>rVKlm!>>gD{c>&uV4 z=_Tb7T-8in-i5ROjePpQ1!JN6e-DytVxv;=uzImqo0DBE`xQFdO=)O6Fy>8dp9#qY zd4MP8RJtLC^2B9M3qZ6|y+$|n&%L!R^@Ju4j;T!p7pbX3F}zA6`@r=q1Ksd&5tbMk zvXy+2c_zcdz@;tQ%aeE(@U!o}p*(m1KSech*^M6#{g+>TZFx(6L1=U$asqN9qVdfh zI?GJ1_<`P&mNqRA*`8v0QSc(sVliQiO~0svSp3Y{mUSn~|M2D4l&`^yKT{X}_{Xn& z;1lK863+a*0?>B=QY{*?G-ez>HWejE6&i%vY%y>BnB3XwjU$6u$M9pk<79iqwWiS2 zd>teE2{6fSJ_~@`%ucjx(XLPIs5+|yCiLUPsG;) zhl;h?ra<&b8;!=mZXOf|+_J6$c9i$tdT;sV_k6VPKas>U=l}loFE3wt1%5dQm(%Sm zns)Ge*O|B^h~{_tu0PgMlX)X%b<}jFFVzDX)}gvh=<2Csq}z4j8jeP6 zB1jz%ysbORvGtqF&)_QHQ+M8%e5PZs#)~sQ{nl5Nw>%#oq467od9rchvSXaork>y# z*IOijwXNq9ae51fb);SltYekXsSUJM%o1Mt{myGIF8}PSURt(qiU)JkrK9ld|MP$P z;c^I9Uwjs$`~TkUT8vYxld=oPFXXIlV{9BL`m?6Oeh+|_Nxc!GI&B>IWKrXp74zZe zv;eTN?xcEO7q|KJVQo=+gKZbLkw#uajDV_1c9{jijt7xG62#@__Fd(shn^_^_8spj zhw#1hc@!=JKl6>RDt{XjYvcdl-nR$ab=BvsgDqQ@ZOJceV+<|WB)ln<0z)uiN**Ll zr%8D=h0bJ}Ht94|CNmi(ff@LNghHlGXOc2Wng-Gk%quuRz{HIy*kA|qFb`uJV{8jy z*|Ka|e#p|*!_w*ZeZSwg_S*ZLdnK83q$_dOy=$-Ed#&|bkG=NVk5e}QS^gY=8l1pA z`0HTJf!RC5lh#Dqs5Y^q?#aTFgmf+MJeZQ!;E+2J-!%A@=UrI-+pC^m&c=_Q%p-i_ zt2dQv?!aV=$ya+ZdiqZdgY2BPP?RE8iEW8kcH;p=FGwO2M~MyT4W4F{yU3x~txQ9< z?pxU~{1>#4w?Czqq+Xd^+!>{FngFuo;oYdYJ#E(13Z$rbfZ4gImq|}WH1ZsK+(4%2 zwfFla#1@+%vh(22X9^0|epP{3cH%=J1$zPPj355;P35xdZjjk|9C$hKNB`mli1VJxJ+?I#B5olt8|Tfve{Q$d?THlpjR<5;CJ|ixWaO_@lELXPUN9mQzm{ zm*0HJMdiQ$-1E!1r(t58L)diR_VTBn{Yu%xYkzFQj`(0!eg8k(CKFBQUK!9GZbTG$ zYG75&K)u2YDM{re2J0Knl_dRPxfrzOhgfP#Hgp4QOxSwZYuL`mE>6}=lle>lDly9G zlE*#(2|97sS+U~}cJ$#kU(eBlIY8C<=q~D2w`FV7Ht1nH^Og+hE#9cI>B#E^H>X*| zGa?DDX<+$|z`FJ2k@1P;_y6|la?=mC^eoO2IpdU*%3EIX%<{fpdZBKw>3)9>R@FZT zYdj#t0Z)I$J$a^;-oP5{b->5qZl4e6+Of3*yJ?%3CH%tgAH3?h<#&JTx#g@mo%s(S zzdy&N*7ck5BG$S%`|G)k+Ais7wQ1KWgnj4Vv49?KEIgQY7 zFw6VoZ#)cPdLf~nRe%uIt0-b{Y4j-wQFYkq+jd6t8c!&ycf@1j8DRKKUZD!JAA>m*01`gZJ?2jN0fa+ zp#lxfyp*CmgVVs;V`HQxce#Md{>{H>c0hFpl|pE8#na2MbV+$Q|Vr=D9bdGa|RjmzCTmdYc0xCh}nQnKwq z39AzVX38=vBo12ml(HEqS5W|%DEPa6FMPs=^0rqzqr4Sy)}Q#!Le=Enhjx_TdjF@( zx9-7x|Mh2M`HxSEd-*Tl<6OqN5GJ69f)da6iAy^0EJIPsI!%;G5}ULE=?m&81)#G6 z5YxblJW{ad=hUUlM4&C`;5QQh@O|^k5bs08br{0uE>$wi!|b1o0ja?X1R;*} zT7>?*Np8=hz(Et)I^6`>WRljJ#HK@;kFok^fZaOSHpjWj4>HoQgi9RY3#?!&L% z{EyFETb_E}Ipvoxc>yKo7EVBCe({se#z!{KEWdj91LbdS-dsNOy{+Yr2X>XEee5?Z zqa%xv^&m)kZ6~uDpGp)5rjk2QPRFkP^Upu4y#6^CmVfn(3(FJnb>Df1eOTT6AvRe5 zA0E0Yr(y8x?2kPFT>GmEsv}B4#4ro3y#dl9jMZMoS*e6IfD;wj>qpRlS9YUP-3Y&s ztWW`9)vrnH@lqa1l%MjX#bvBkaYP+jUDIZi&Se5@U0d zF;f+sB}c5Qo2F#)C4}UHaajYq8`hp!o^s}?_g*l1xL)ZsgeL(L)ks<2UU{d`Xo^+O>Pxk0X}Y8?`qGx%)U(?m z)NlEL%Ssh;*CiqHOO_b6(Bo9ySpajH0PHh43uSllStr5i6+0*R)8+_BSctVX%#=!u zrU5)8m~xRJp)OQA6=>`a6)*`jq&gkocGUPpbWSc$F$vtheOvjhzx>E!%dK+wOm)Y{q56Jv(-TzOOut%Z1(e zA&vdq2Y?9<_R~%}p`3|Ji}OxBxjgxdb>-r-PAktkcYV1CDF^*L9_r~zKM8&L)=lN@ zAN{}OfqiiJnP=eak4b=!{rbHEwF3{131-r?W>2KeiJCggS78D<&8wl!@YL_FCe6ka zaR>GaUQU3JTUt6Ab!EE1!SMgRjaIl_(9eGAxA~5X7PC8ctd-165K16Qh$MDCPLcLDJ zz~V%}AMKp=tGg={bt>!jE%%k*{;N-y@7}kglryl;!TbJx>W>=qH`{`V4g!dX7eDt+ zSd=LTHexrZDbV$);PsW-Mi1#pJ~OkN)4o*4Z|Tl2N&t-ih|3nfResFyTqc07f~=Hk zfs5&`BBE9&^~>JpStqD6))VjOJu(mvevi%ITYi`#AFu6fh*?vtHPFJ8tHq1@e_{hB*0>}fiD^H={%HfRfjFxA1ZHt|EJ2; z-`gCUe(NxyYUz)C>xqGns?h(6YzqPol@SDusg`fKgQV&U2aypw`_?r1mNpdzk^kiJ z){D+@K|7S3AB)T!Zv(0lJa8v1b}^%3q%9L95WFfoq)kz^h*OQ+#!MZlsY|&k+uF;H zF|~h~h?E`7ov^Bt21GF@0iLl=!?G2(2d}vCj`ACS_OWuyW<0;X2rGJkJN|FRrPC+A zj<+oFduxM#4*t_IfnsBoxBSMuwI>(T?^MjRwolSRNR~Oqqd9S` z?JAZIapi3WWl~Ng<3t9rhvtQYPTeh|&C+ycYj}{xsbA%S3{RR^13<=N$(dy`p9w&P zW~mjpkjcx;tW1)VpA{U|GG(iolrFaPC#UxrVu-B1o_ z;ye>~RWJ$oy1(@;oFATU{9XCBNuK#h>&dw7E$X-#ysNYwW;Z?eDE{B)H6Ti z>1=Neb{w~|?I)+#Ni5wpSJ(=Ah;}?$^5mdRC_gHU=L0ketUt5daQF7|AO83w<$qmq z&D>rda;cA%^jjM@mtXsn50}6G%FP=5BTSehtN{4R^$0#3`FVdiJp8Q{Jn`y&!ig{; zN(UsV^F zKpoHrE8(G3c2dR^I?b?i8ses}oN~&@vqZLN+}Z>}gU%?3wWH~}FXbhM4y ztPJjY9O;Iw6B!_5M9UO(g2gd zPD}#t`TOh2H#Xi?-u}9uEw6kYzneGLMOm%sY5*SEwN(D>ifhXseCq15btfKwcj{^ zo#@;MBY3`>zMyU^ft?)%iaFG*U!(dkNI?^E3URQg4At; zH2hAQiH%$~W7uKaP%e6$q}BgGb4EQACN}m6!br`NiukX%fmCfRh$TYT<7K%D0pQ9X z29X6{2zb=}l5$my$c(~VCV=e!D55IL56r`IM5Q|AWDX^OSCSkR-tUNA zW7LL91tifvZYASklGI5KC~cW?Qc)KWof;98i}-9r*aCrPqnIqng)Aol(oR9==I_|? z))t-{xOeA{^6pPuRX+di@0B7Llno0TYvbwr(sOAiO}^6byg zS@F_<4-R3cd%Wx6a@`$U%D1sW_%qM@M){4Ozoh)cGcGD?PXhlK54-m4Eua17E#*C* z`9its=8gE6C+fW(OMc$!W90Qd{h&*vbglr!e>+MTq;6XP;+6b>`|*1WEnhx%Q9KRh&-3BXm$g0m8w066-=irOt# z^j5cpE#ErhV0`Md^0pC;6dc-UA>nmYrv^KbR{^v(%_{}e`-19Wblu%uygm` z@(;J*J^m}dgwLnng7**bO+zm8d25un`ql#Gtx{eN>8x+xF-4@W1R5VYAZ02!<*W0} zp#HRg_FxC769osS19bxH)6DOvIswQ=L$lZ*9a@YEl8XG?&opNEEWmQ*9vFR$=v*d% zfeW}E#sn}vfa~%TR6qF@QmUIP*t!KYpp$E#zU7K(0MY}b$atnLjc^m#SSU=}+>xg< zuGT}zW{I_M9|4bcDMLF zf9knEhF6RKX?fYRE-vS+$Dmo|flK`_-gH~J^y;sc&wcy0@&H~+(mN6xxXFj|GuE>{ zFN-)EW{_{-6Q`92TBr`H-MnGyjh&nEN zXni6*5J)pj#n!I#Yz?+HOqV_m?kp2B6ljTwD@naNYmu0t0sG|ygXX;K^~N9{eBld4 zOSnY9B(QzYuJTcQ1OM{tzf=CnQ!Xe!|AJ?hpT^4I8BaRDoVFISt0XMp?ZR8{-de8w z=6A{`zx-|8-PpMoeVBF8M?7$i&oe%8UF$bzeGPV01S$XO5}CfM69EwO;bCe6rbkXVLyYm|ld>P4K<_nHv4a=HNsn8U%8qSUpLc4CzY3DMZkT6AHVRta>l9a%87WB???uI`fTIYZRH$kZF1gM<(P*U1&h6N3iR0LXNLz;)@bE zV22bZ%_=z`U_KK7O3gVu3eVv)MrC*>V2oZsbeYNw=rQn8cEFS4(tDI6$l!D!-p>=v z;PVKLIs*W06f2nd1kW`yF>_VMsiA~+$wSDBL`M!%WQ4)$!c#{kLF2pbToUuT*sFoP z*b_Ph5vzf+XLs4Udw03~8@HCrzkW+O>(sU7;`7fg&wI*+h)*of#ud(!mRq^d#Zf?8 z1`>i>ixy`3W;KDNo;s;*Q5f{hR2{(ApER5FFd6y8S)#Gkn+R|w#S(hV$zUHoI=Xic z(miGSzP;ru8@HCP+;*3)Cf1*Fayet&T1*0Gm8YC{cDdlp4dwi^)|YcPtS@Jrb_!0) zr|1^r$!ku;is6L%qn-R#z&^ab%#FK8miFMorn?H?%)9Tw9cAh%WDF_gc-O;nW1K8U+gW_l<7eA>;+cJz&jf&y z7km`6JZk@A1u!ZPpmt9#`*9_}d*2FCy{=hYMW-}mI5bFM=$bU}?%0UUg2X^EXj z?(XQF%^{TKsyg7;Ng!pts;E`Sk{cJAd1+DzMobc*%Qo$T&Y1fHW3LDv#kDj)9*GH{ zU;-$QBE?sT4gh`-gZRM*m&*6=-&C%;X(Q@&0P3T{0nd+ptihl^5$$sV24$F6VNiWM zwS~xu;8A=fXfHk-vIlXWKPARxyPjR($^_T*r})kV?_OYO&*eSO^nBQf6NC0Pu##aW z3`!f=xJWo8tEL1}COky}3-!U8N6VK;bKZrKSUrH@K*KiK!h?Qi@o6d5Rlc77G|7X| z*#8h=?_reseiSSS2S9Nd4`SkQ+4GqISP}01v(&KZl5Nsb~-p7%= zdTD@x$bohM*Vq{B`hgHmto-djM#7?#hlsPv0mLN?YR0k;aW5N)o6If`P*#-(mWgL< z4tRVbtl*&~!Fpx^U4|35&iowggb`09y&3ejqcrU*Q6`Z`%R`>NM)oR*#qhE}1~|*r z*di!G+6<` zxU|vih5Kjlziqitvq|SP0hIEDllGN+me#P}vR1oLg}YS+RkA6(9hW4Jq1p(;dbbX1 zd9-8Rz@{76W35%I`7nPooZ6;@Km=Y%t$d}L+ZYguy2+~pp9Vl?8>^=a;UOaE0)Y`U z96;2aWmDZ=xc2wPT}p9xcXzj<#a)WS-o;&tyA`K+ao@NWcXxMphoa@-|KiN^70$^_ zCU=sxW|GOBtYob#*YC#1Qw%8bLu~VAG0@{BO+mirL#T*9GD3H6-HymWJJO|L<&b^P z58T^YfFm)TBIedDh*h*8Mi~7dQhGJ8iX+K|28o<3q0+T6U<=}+5VTeTozXH~DR~gg ze;J&Tz#I@^!I_&EU>9Y*3xpbyZEm`47B$9#vAGLy#Z(bhz(4J zMd`Vm9Guo7=J3H&006O~yp*^G79g_8BBE%YnB-v#f;sQ`*@{kRFXl__ES+3YVBcrG zt}FzuXTyrUa^ezzwx*W{Q*dScM$&l|yjZm!0#4jaK*LDB1xB)LhU1igv}7)&=xe@W zaFBAQ)bxzvI0c6$iQ1UJ(HN_w8k&A7VUZ0H4>v;h7QXI!=u^-|w~;!7GlfaIS}0l2 z$nXshrc_5HA?dF5v2|xs92NX`48}>0Yy>W{wQObbInh~JOzVP~{9rmq9F26EpYqRC zukutd9?{u9k-h|eX-x~{% z))k7EgS#T2sRjR-40a(C&f7(VN}&U7!qpiFnLZPwldnS+x!as6t8-ib1kjWT0qIU@ zexM@Fh$k9sipa;*_kDBtX&W+y+LAO;U|X&W^8TU+Ps?qhT?Ee2b#+KnnCNuK(`fU88u4zswub%|8pOv z5)nY?Z{b3C_sAkfcP`vi!>jKgg5^IlR9lD7J;tB7jyU3r_e!WUjhPZBnd*V&h8@Ot zJcCb%w$C6EU$^c@AOW_*{1G^{h=kHA$-hJO&A-3T9G_iH#D+s+SrzjnU^rlQrhn{t zQPCz*LMd&^=C;sagw`{69S@4H0j1PhK5rs_8x_t^LkRo@w-$Px&%3D+Mb^^wcXi{7 z53WrM*BR@e@Q8~t0Mla-L@8#_)-MpVcP(f%Zhm08fdvQy+7_*tVmZ`fLhpY2u3^I~ zSl(-CP(wMhjNSq}tr>Vr` z?;4uKPAXATCYadxSUWARuq|G9DICyUnniFm`K@Y zl(M$Sf_gv1)_NKiY8|N%6GFQgn`j801WTID=r#}kIEknH=HcmkEq-5{NlYBfwZQ=j z$hxSMwa?0SZeVVJ9f>bv+i~lvM9WQ*EOW zJe6#b9BRFhlZyZgU7}v_%2L)y7}F2_+y=o)p$bg%$3ve2NnWKo1py0n708}iyCc!C z5t%MyMznQfZC2dpcLv%01RNJcXpIGqFTsu&RGU|yqDQq=c$q|@)6^9;^jJxee+TRR zbB2olnc=Vor(+B=gKWmb`T#|_*7uidVfym^qKfeG`Bk;eVz(@7>x9oZTA!#xHfDO;zZME`?&;+0v80@F)^Ig6N266UaQ34uEirzV7pg> zTs0T70NGHdloM<2EZx&iVRG$%N$Ivgi7}6Y!wI+dIG->^)BeUDi?a1vO*{1H+VGfD z#pjldBtF1kk_t;`OhuA>2SG7bl zRwUw=`&n+SwUE<-ijg!Wx@LOk0|ov1G7ZQm`L`vCA&fv^lkAF9+QE-0xr4oJ`N4+RV9XlGTgIabe|_s7r0d<4#>aEswFA@cZMtW@SHoQ+;_B ziHX-91(KM~7Nmlxl90Xm>26oZ_RH<2z$!C7pJmxvPw!soxV~JTKq9q}JXK^E1ghq7M}PP&y5fq5hB}i+2$zb&uWfm6VJSuq$sI z_)P%tophPdIRl?kJG7jfp z#RHb#pEz(;VhasoJa8!{|78Ncv{+vBI!~kmI`vaoDui?3x2oH3>))xjnye32WnGSl z9I)5Q_BhcTXW?xctOR1X*}4fpi7=d@r6EcxYsHziP(G15C|T5ENNIA0JDL$NFk2KE zsW+cy$;~TPQ3fV7MuuU~Btif*BK}J1UvBB^Kr5^g4TI6zKR+G#5>+#ScL_#!T7w$g%RD z5sCIX5s4gyd%d5lWmLU->XTn>2k$i4vr21~pUi1%zGb1v$AI+DvWZ97;*aV&;a(n{ zbJrqS2ICGK)_-ix6=#t?(2EYT{YCV**sNwH%JbU2_N(W&;+t^Ek$q;agnHQ7#aYA3 zbvP9ktRT-ApJSW1%|*kr9iwt$stZ`_qEP2Q{t|(9h4^wX3owN%4%i+V!?N)VR-z^J z2;&i;a&lm&BadTuENWzIiOp+~tZlzK`u%`pjn0KCM4(_ede0$8m{j?KP`a6zPYjou z&p0ABhJu(+Y_j+dQibBGsZPu+Nn)be_A9boepWz1kx;%5QJT;XTDdTBGciwhnT=b` zOwx2Z-$PRCL0k?pIoRvaBz|;>;ZBB|jo3i7Sfz1Q> zF)bIJSl3v&=X5V$?JHpB=;@@ovn=SNAJl!+W5MhYI5 zXP}$Q!U4s>A!-Y0!g)zhC!(Oj5yC<5O~B+u!!fTExK16ARl$9#_J%RnDOzcG+tSn> zZ76k3vV7t!-LK$aGSNOtD^avVvXB3bW^4Wu);FOXKBpM)$r6N;rs0`4FWSiSoEfS4 z6N#$a641UqKe0T;lo!|RKwg3CCxW`AB^4X-=jei|Hh>!VbbP3Bw?FC!n+-Mq{$SAaYl#4b!k(`#kyC z)Qq^D?kDjUHtXlYI%OorV=B;c5GT(n12=HQ3M6)-__^DOv9MA6G`O6}G*rgFLyd+n zts;WFzsJ9x1}&wUgXNrzyDU1_{AJz*yCeya29zA-UAvLv%$iRd;M}You*ta@-A*aa zwD^_O^mY}nDD-k$+Q~Tm{@5afaSy-{U^vqcu{^*#=zvmP-hA?+D#28F{qVPS%ViK+ ziM*rC1<$;x`n@%FP@15#HS{Xw|>b!qr3ZKd7EOFv7~Ll~oo+(?guTX?pg0ziPcbfA7k4X8(Oh zc;2GpIlGHiyw>RD7Ep*Vv%VaJi>hLaJ){Jvnm&F^G2rq&gH7tm5!*>Qe8IHuqP4jtuzB_aBwJywvDDA^oFpwfV7VZv zoZ=NI<*WPQF)8duV&i=wA<9WPoT7oZ>I`LEipkqdM>Rkq+51QYt)YrEMVQgFX-2Jl z1PC!qutl89sQ@hN*uYnx5l#u3Z&xK0nI)7F2nBWq&k6B9pYY*osakw~Dr4rV5_;&4 zVi9ioGh0w{ydW2T9IYRo;0q8Ot9IE*l3piTCs2#!&j1&8O-Szer#Fh+2+jlx1|2T> zMx<|?vV#(WOvR^sE=JnaEmB;XVzk}txgYApOTJofeWe=zR8Q|MnZJknF%(3s3+#*> zG6_;=v*0EnG)xYQoKeZGqYCGU96<=P6+Qo@%$XqlW)pWHS8j=Ajdx7{D#tnLsKoekGAT$1>Y1}2lDFZt9lk=nW3Qo?wtRcPIc%O2|l2=DlHw(|}% zlJw^oK*OK#slwvRxg^K*R+zh7>uN(&v7hXxQ#v>E(Kc;3q?YM3d z4=@FZmJz$=2^jTTF;bzt*uvX#(eqUd;dx(Sx4=$IERQAMk<{?lf1>3epnk1X9Of~< z^~Z}@I1F`|q5BeF%R}z^DWRu;BR|WqYAB+XoWz4jJ{q-{ZA{oZy*uxOUqy|Lj}I`< zI|G9imoC6pH_^zNHP9F-+z>?Xj%N>Fz zB)~+OBW;@tTKqg?p1PZq?BW*9U5J^%Ko-W9^i=swc6;K2cz>A}j4R1@TVQx_C={_& zKcbnQH_$PPg-_}hm3#qD{-9fORcG9O*-1!W9U;CTUlYCQx;OEUDQRIBCRXS1!>GOe zjQjC77efUj$-R&(b}N=uh`0Y)fLTt+UzmlH3qYsKsES6LWDDe~fM9&3h;cmSr)SeA zd{6;Ss>94$h+LiDULJlcIhMxIG@Z@iKIY13)RRE)xsD0%ogNdQQ5t)tTxgYy`0EM1 zD7iYUM8vmeJJ%ph*q&TfTa~nmqzP?cckP)vJ$Km1Jgd?)<*qIFR31esGqVXvZ&)6; zX90}Dp^F*?UAJ-U>SSB;?+rGpnB8ANIdQG2nCPU^d&I0h1S+D*e-TFd+f0{%xqqvS z;a-M9pZqY)Lt3NJO~h`MIE080YJB+|I6pkoYiM&Xe-QBb-T!XKL|f~UnX@0h6}(e| zrw;$Y#To}Dqvq>Ad7PdjR<6u#cn(&FlNTf2NOXDmDoLS9-mg}jDnFGln_dnB6$3TZ zg8`iy5YQgV^1U zcsM~fcy<~rPo5cZadmc@qAS4!?YP%YeJ>ck2XXLz&8O(Ud%hCAj=h(h1EtP)hjP%z z8ZfXXVqHF)4%z|iC4Hc)tch6ZZGd0#455SFXehc6-PMDC!$ zCk8h&-P1oPD=0he{-#2dTD_z)+3lgo)7@&!{ zaU+gh@{hzzXrNyn2_4G1D<{@Pc*iFEkfP)BwPv`AtUkn&#y)kSH( z1d=UR;ZDP0C6SLyG)|f^Px#X)!UKE9FueJ?8r|DrI1c}}-&X#Q#oKjzfSqfwrh6d4 zpM5n&sCM!2-yy3yG8YeyF`YO+gL1Hd>QzuIQa=1Uj2JnQ%`&MN?dlM?Ybiy9SEZMJ zbHE}~54pELZz10l|CXmhT*eH3EzEj^S6gFoR z5>FlJkCW54U<9NLZM(B@_a!9)D7B&a8tk@mB9pLyw7?z}DIZJ)ZB?jzLHa`VUx%>{6)k7p}ndjg61qSt@jU5U{NE*XfobV<026=A+_ zT=Q(WPsw+L-qEl%QS|37?*2&wa6LviZ_NU<5g}KHm(W%*MSrlWAJH|`mPdVaJgIAS5b5WH*A3v;wy;!; z6$3?g&1y}tnW*0BD={<$izzhrMDJIvut zRCe@3Nx*t~`pE8sIzC*&5AzT%W6U8)@ zgy9LjdO;=?(Xp(oKh}2I&8^gN9E+)wiL|HOVb|>z=U7ruN>C;}JOe!Q2aeN8MhT8{F!$(!?_e>x!Mo;kY3H6;WNZWGqteI-1mzM&YWgq7OqmRrh|f|)4}fy|#2vLm=R7TG8l zH(2EMec@qJXlW$sBQBa&s*Ap5n{c5f@B~|*quw8#CqFWIE+MzX7sDMFV8#XzVTpB} zpLE@&;YnnBeNAy}!Nkd)#lgE`7rHV`H04b5J1goP_UATrt}9yikM@FB=F>v%qsJZ> zNkV*sz_7!(B~D>72<86!nIh4sLK{QwgtX+OEKfXwj~=7kStzJ7%9L6~#mkfmPTM%J z+UTC)=}bPWcVb*7QbuDx@-#m-kmxmBQ9>cEWFt}prGf0|G=jat(C@B{Y+hwY_i75lmVmU{gu^O9B0e_FgI@ZR~ z3FWPhzPhj`e9)3*(WrW{5uxwJw9)qh0#TKOX7H#!Q~arg)s~Gc(oqeVi>NX!J4*s6 z-Dv$*9GQ0tDa@tKpeoZ@n(FRyXO}A)Kr#sJr=#6!jd>P;O@r{4I%>gX$XZz7403>aJdfv}_a~(ZX{!;5 zx!qtIP1^F;g_%>Yc#^HIUohMw*CvZKGCGqGw9rDK!89_z?mD2yh<@1E&(p|JIz;(dHq5psU zUqP!A0{Q=OefI#K{XuNDSkxqGHXgst)n$lDq4xZo%?#veOpiu{>%mxY5nvCXp;|{h zjzim4n3b2amiTpnwvLGEqvY>nT0}kth5$J|dwM=VU^zaM0BLbwheC$p~JCwnKe z8d>xNl;Aq{&un&t!t#9_nE}~*XZJUyGBN&z_e+&gF-FP83<_7YDp~g?{fTJE>@0TM z5yZU~>llgqDj zX!&vBbGEx#Mx2G94OE+n2L~ej@Cb2XH~y|iohyTQ`yV`yQ%nzCHy}O%%y7nd$X$;G zR+}C?op7t=5W}!@=_S5xceB-S@K+ps2e@WFp@4Hg5U<$_StB9Dmw?c<{_iMm*SD)R zBftQy2L;2eaIj9Rnl)S2#vCk`%z~Pa*qoZ zKwV-^>RRDh#whCu1@!F*fE3Sn@T=hqPSYq{jVtL$sfd3cliC;XK7vY zEk%nh1cnbL?>phDAf&$%Sp1m_<1b*)@|B5$T$H#xcqiX&bHc25$Am!E(?@wZ-J zJEP7AM{aItPikJyj1aPYk-O}#rJ0jlAD3M5bJnu@&WxM-!o1&6R<+G`_1%qOLg3Lx zIfbQ;0ad8KtVOGv?Z6v)r^bk>_j|f4I@ilxaT2eR1_)bXp?>Ljpv~vAR%Q=3U&WNm zd;X_X_T|N7d$9vQwAGB7{yq1eys!8p3)KO!t+5Q0c%bt1FwLsSahcnKgH>Si@0IV0 z9Ncc$s|-a|8wgZq5Y%!wf66nVB^B6H8U;Jo!QeUs_hKZtHuB#o^d6_bwbvoW%OvgJ z@M*~d;GR348iu-6%w7Z)6cjR&;}T)IXi0bJS2+7yaVIt24F8DS-X`S0Pkq{)(|_gx z{G)C>bnTKeF9yJ8&7Do8{edSz=&Re)$YdBOJ&T5qmY}SX2veDyhbqx&%K68nOLBw# z_3y)^z|F7~zej?RF}-Z5XA{h?*HTw!LW%COfJPi#iE`Oc7TgC{>uo4bE#rYiT8%*j zn^-0OGqU@ejA(W?f}FX^;pOxewKfFvuZ7};C4wQb&0m#n%URHq_6teFL{&`SPwnWr zOuSPJ5bs*kTiq;mRs815Xuwhwp4IR9OAig=W6R(m4NhTB86-)J@t zg1d{|Jv`A?Vn^VK`O|c`HCOo|HZGd>nyH6KGPcGbKL70c`X*KS@T>8uGBwcRxtp3z zi6q^3oV|#T&n~x9WKaunEH(=_&s%uZ7iW<%tV^DTe|oZ3IM7|KBpK#$S-2vR_*U+x zAlh*rehZ5w?OV$By34RTd&nE)|?vGPowsxSbep-Z#ysqn%;e9_!7w*=3a#qd5hQ_00%~m0)1byij9tt9Y zo~_145|*Z2NusYQ8_oK1QPv52v7>6CZ>RoH=cBkya z>1QQ%J;n-9hSGQXG#a66TT*vAA)!KA z-SnH)I#SYn>q+b|P{w1xiKKSfHTt-g`F0@o7({u#+Jf+k1$xJBjHx{yDY%C@u__X( zV-6qgj75LBuJ{b?C7jUvLhYA+xU8F2^KXk~rR4yH&2jRKyy>7w8Sd;py&CnsiO>J) zE4eY%nt|QZg4Km#qtzLb$*`4QfmmW^5+hs9Km5L8p{JacJl9`!Ph8us!8rkMa)R0u z=-rfP#q(!pIZs69`#9zri#UVBb3U79iX#m%z73t1b$V+Zl>=q12C||XB`%2150pAE z#(Be&e+_i}ur5)BCHK>H0aK>yddIoy6i=`u9ecN$yPikrU3^7?AkZbcG6{qzu7qjU zo7>ac87$d~lgVC?Tn%mnz36~eqlv#+T8M5Rp_#l0sHdC@R#2{n3He4(`Yh<$Zz|Ts z2t^GJoR_cY#rc*J?k?+}t~-y$ni-EaW>^ZkHnb-+?!uMYIS5~WNbyXKI;0j8RSioS5x&JQMsUP`fq%xjhR zd>yV!EVF1Q=*X9cSMS6a+j&SAkZYK@s3WZ;Zz_IFu`yG$PckIxbt>vRl&H8aS{CVB zO{qz5%5qWscncUcM*r8whLCZUK?k}oSW?$R@aM0~I^7&e4L+ZNrn>?{ZHemt|CyiYc4ZezTs(cBHB7EMh|#*rSIKR}+xP;UkFU^bSw z0qC8Hxr;FtK&R)A@$H*dC#PzbfzD6FZ#4Ir!fwAg3bXqWtJK!53>83dD6d4R7`v66 zh2xG&rDg$4*zU^*I#ATB7*_o1FXjw_Za%(qSi^2BPWU6BG-X3Ble*4Q7fk(T=6!DecRGj5gVb9k^PJRw<4 z@^!u(9n$6JHYX-b88jZ1GtK+F;{Pl&5!lgHwtfN{ISnSxpt>fQcW*`3-gkMmS^cm6 z=HmMZ1`f-o-vY&qaWY)U#MsunM)B=3p!#B=g|tF#2RS>IgKE}m3P>2hRH&UYmB=~i z@}!SMY7C5Gu8>fs1kfLt%G{>7XN2y#4kb5HBHBI6CXv}W(H(2svS{R>b2v1Mmxq;w zq-mEyO(h%IKictQ`m(m!-($^wf$Q_9_8JqwBA>ol{Rqg5;#067Tx!ano@5>MxP9wu zB{)Vgg3WA!70Z$sT%OJ!oKhD-ptnDwjeBxRptPC5S5mG*;~VLNQ~usPJBRiKF@Q2| z=Cyq3{5*$|`?6KQr81-Ttrk2~%y;qo?TkgPXE=M8a7cFWAV#HD=j>PH>*v+2Z4>S8 zT;a-{sXBC)X|xxlFT`iyF*-=})N~EuPMP~U;}u!Twbasg5%rrEJi&s#y|f2i`P947 z{e7_?f|jC27*1<${(MtwN9p>2G_tJqC0rkvT7!*Hu=jbopfWwRtjsFhvuUl@!H3>f zxx|d#Va{TGDh%&5x@N*_^aC8_HxM?~c&K!bH_DgpZg47>FBf7MJAVT;rrP<*Naa;_ zXGnCAoRlLy{c!;njf&_~GRHYyymY_|d%3B(eGaC&iYvofny=PjepueHRg1QviUZMX zHap_;3Zt=a=a(FWp}>#_-V24ary39VOO&L|t;w=oAbhslPB+p`(<>aEk#NRHCQ}jr zD28kldl8Ihc**GVG=PzA@nW&z?z0F-4%Dn3XBT%3d#T+*dLvo4>ZMjyF#fYnBkTTN z#!_T-W>j#EX)cO0t4y(rh3`o}(+~NQI6g|XQ#jjEpK2!pJyP$K287q+=cXjAQQqCt z%R%ibbLKo{bmxOAK#H=-&)vaS+P~lajxSx^8Zj1O9Y8AKfVS;Z$MpOYq56_|;#y^D zUS~dRlM5IG@Cd)&&KO6k_B~*3QcOJbxA+3)b+c2ihBqCR<&SaoKX73U#3{07fTA6q zG#cO7UOcnHeiA&y%N8l095Fm zrn;!Z_9L9vhtFk{j9*D`CZgsXlrZhj6=mCO#U1_4f+Ts97t}d!;|Aq`{<7a! zu#Sey+E@gkC}3B~%@brJvqY$&O%6sA?r1CHlV+d};$~3GcTeJ~pZCguyG%i67OOoR zvDAM@^Veo!Pn4v_5hA--{&YW~sq5WKWuYUD5&+585GG9<($%n9tW1NGTp1=*x#$#) zJZ&KX*j}JJW}g>bLwyrwSQI$-d#Cl$2M|0On^Z8ALc`%j%ne&NXY8(untoiMh&<+# zNxbf|;g$2LAxH*r^VD7){{>9&cqFvW_R5;4*tcwE6-LwZ2 zLr{=0<1bZN-FC_f#sL-EBfVK>34z+Rl)XHHy(xsD>HcbnO1i{oI_T&I!PTDiIrR14 z5*4?^lI&*#hJ`|CXg3$C0t~O~pnXHrAcU4Dp?Bu6Nrg?6MGbjY@;z*-LnD9S$+je| zBWDtrQh^R+3&Zx*M0(s)y6g1n%sf0{=7hBadZJ0Cq_g-rN54$$pbB$i{-CWDHVZr} z3fJd2W#U|EjQQ9D{mwT8a`m>kRTs&oS<}W{FRZVqHkP8sngGK448BTywJj+7AVKDh z)H6xiMX;@)xze4r{}azs3@w_-hF9v`S1T)+iSt}iPY|uy>Abl2MyTKLfB=Q^aQ-m7eGgms{2o@j)l?-GkV!}isstkl1~D6aIt(RuSi z0Qy=iC?b8ROuL{5A&9otArZUf0)F(CuH)fR>%p%ihFz=1(FX0HU8nR`&u85a7qt@5 zrG4E8^!+19HABCd!htu-e_P-T^}J_%ktNpMXA4@G!&^S`S{f_qo$C0x1_{U5U z4GMfW@o{MS*Hw*LW;TUME!Uu5LbF_=w^J68V8*o}l4}{JLuh_DAy4L@10p@4KSZLV zh?PL~S>ic4t$Icr%tC2k{h&VwyE*0B&tW@6?A;cC=HV8c!VNn>4)<^_^Yszgxweui z`V+_6W(9KeIuKh{58S`~9HmeNbmr@mdV|C~ucg<~g@eA;Hpy_F;!Vy0i?9{Pax9 zuslwQ(|U^LB*ttWRQ*jM*DQIx5eF_Bl=tD0j+*yfaa0mdjwn$x=E>aGPTgePvL6$o zSvXu~3&9Hc!|XLc0XWqLs%WuGrqT-ChZ4~0qGf$;!iBRe4nBP*aH)Vd4FOH-dNU8D&t_Q}ddN_f5}hA@6iH`LGF4pHli(Vs%WQ_|K5J zCVw4ie~KrGc-0G4%l-?LshNLW+LI~MXn`aV?YipXm84|P!>h#R)@?&2ikFA#%L_8Iz~o4vInn`CKsD0 zu`2xnov;96qn<)0fgTbNlruKnCbS2`xj{cX_BfGPc~?$t#C%NK5V53`EhwvYc&g*0JfIzOWyI>Q~e17p!6or!NwK>*+`{t2c>A~+-bPVNEbbTk13DR@8OG;meEl_Hcw zprsFow<@@3tv4*7;JDkGgA?s3H@(SF!#}bvn+0E#0qavo?cnzk!T=2_)S);hVMV?@ zHso?dB^HN-MA7Bwrm0?_m@f5`+Ju*cwHAJFFI@w8Ah7ImYWB0{kU&op7iv#^*>Tz% z6C;`117WW@;k9lR_LY0jWY1nFvFp@Ic?yeqGCvEz+Bxg>3_uEU2%7j4V}yz|H&!}n znW6O4(!IyD=~L_j=$6jPF!sdb!OjDpfy1nzhM6vc=gbGOlCP0a%;1W`w770bDkByf z?Jf_gcp}vc_iyjbmn5^oRxGkpt^gYazPM^o-sLe-R6v%8+O017#=U$NTas=C#U>6C z;=G(UTB%P+q8Xm@NNqxg-pflg7>8~>MN8BbMvVO~k4PyJL&!8cOn+D)$of6G?ThDX zziD>tm=*AGUeFnNdH0VTLdP3!;pXyk@RW$+CqvJzkyLWZ6vX>lUEnYFMvJUGGXVkh zoZSQ~!Z|dA9egTy1kp0x@S63Gz%V1X-9VnU`vD29Hkk0GJj$OjeGkfmq**KNex;zE z>Z$Mk5X>6^MHau2wF6p@j&^q_K|lI)yrZumSu(zYu8Bh0VrV+uue_eD7+{X6Y5jU7 z4iBwdzIslXtv)?CSH)JW9^!F^Zk)LW= zv#pJ;^)T50lqcv5o$CYo282Xpd(Vn=Ar%zUgf{1aPG+bPE}mz^OI5J@Vs)gN>tnu5-Y=B)faycJF&=6gT1qST)VYr`$n2zp9}TLPI} zx56iNN@2r2Q1Eqj#oW!*jBCu)pAwuKlT)+m8rttFD)%GTGe(V$n(TGra!k&~L)W%u zcjB_Udi?tXkb4hF1=U2}j<#=xWzmx3L|jVNke)D^kY3CDL$fr!)LxD|Z^)rzzVg06 z8^H*^;3?pN&sf3Z%I+ftP8V!yu-WbBzt!$)@=mY@d}tz1*8PiiQuzNV!)d$5z4R&l znuO{SA(GAKJ+d}AbyTUV?}&N&CBRPPpVwYQRt&F(ZFV0VOJz*cC@%j{K`F|hK3PQV z-K*Dx1h-Vj)?yqx{O=jrJ&Co`+RBri=1o_hXKTiYbLZ~)kIWs70lUL$o2O)p&*8z% zK$QEomTAkGsMBvBG~_Phjdv-}%Reef=o>#EYra<={IRf-SXy9-wk0bi6J>)@J|PWr z6cmru-ZHZ=3>;>vKbyPwMe_M{TsX!}oRB?WQ2UT|HJys)rj zx*p>b3^+xISKR(;W|On;Hd)0gl!r|HJS=Z75IP!)j|^Md8>7uU=b#nM)Z;ay_;XY- zzCWIN(bGt1^;*gIGHHRJ`|=CPo^)cMr}upR(4KYk_P4WRhC{(?zi?ctX!Bdm&A%74 z6nM13#qL!Y^B+G=Mji{S5zW+%aS?^VmW27hQg8w@PHLCUO;i7}4uLvm3J;sGde10P z+88o=$hY9mIQnIX`VT6pLKOd*0g_rAR(cCt!PZidsgc`sU6d+RRAGG1)O=a`DccIS zD%r55^k=C$3z94~*^m@n>(jHzjy607{6I81)nj1v-h&9gBhgE^j6{%XAqE&e$RofE zUYbx&fXZL@nC!~(S3if%u7y8H5Epr+6x}HPO1y%YFx4St^J~ZMN!^I{c10U{>dWLp zEi5{=5yZW`@v{B->}EI&J$dtKEq~wL-n(M$b!plw3c@n6K_m+L^-4th{Z}6(s8SwN z-MQeph)94opv8`X!`{lk08wvbTtPRND>LH3_h7!i;BIrCj0!-5Fe;9)0SZ5OOdj=VF?*(8& zEM0VSxUQqd>4*w{N_m?Q$|$aL>zgGwqJrE;eI{MU;$0^Gl={*u;4U%gvl0_StiM)2?%V?vm_F6(*rb#`;y2Iz1o?TH^Wp_57|Tr~PH|5&`6v17YK-9juq z#Z7qf&6Q;#YDUZ()E7Q!<;yUezTvkV7B^XA_{UrQsUtO0|6i2d1pT4?Zn3zr&c2$E z&}*Kyk;aBsfA$S$jz{k64Rc&l*fmCt5o&Yw7=4`A_q4rF>66=v2!>i%j6`^+tCg^y z4W#tQ#kv`>?Pvozc+7k0V^abqQ8wHbvx1i3);az;u^BC^(k2Mx7jJ!_99&YLb^btH zSa&JK4mA-S<8qTSTRG}!)h!Y)rv?!By+V0L1TgwE$|d-XG^r)&OeXnmV`h|1#R~HU z?tGZ_@J{LAf7}GK{OvqH`Lo~oV;Oe8@UU-Fp){Oz=nZ*tMa%ETH8q*nxUuc^6n#^F zBPc9nw1Z$sc;R%9Xs+Et?1~6Va;#~W?Q?736%Z;*H!kW7)2bk{=v#A5k4II88!5Dz z&Z14m>dd#@RevvkH0fDyn_sCaz?d!U+d3vUGNDAnC3poL0o?CA}wkBy3H-zx1E zF``Lt5cwtEZ`CxUVnbB%M&4z~i(`Ooq7how*hp=R5Y0QX!@~QvwxLePeVOwJPe=N# zwA$m({YAr$CW9#0%VH5X`==HaQ5}-rQE3ZeR)Vi-q=qTZVlp>7j#wV%vTf*O12~9NadftFtn6CYrab(CE>zLbGI8Rt3;g6$ zpm7|vTd2NX-VrZ2eG)3yZ{Vbi+AY00YtgS}lNtS@S+IZNu+JRSbC;0H9=phZP+X!> zqbnOLEix~kK}M{+0fr(J^WG^}pBJAL^{EkRzN{8_%;fv(Mt=Lg-f)=w<1W(ID`1fM z`CFk+_Ys(tPurgD-<0>|6tlSQWUn(D&vOgc$&AF7g14`in6Og?G|L+QMIR)74u~Bp zYoj@X*N+#m&D(1Q@l^8-Fy^wedLl|)V2Y|n2I%rQDpOlHju5QjXUXdhdW|P*!JZQr zl`#{Vds0{2r_ZF`u$j%(q{Uui7Ax7BJ%-{>iVQ0&_Ufu2+zYMlQqw8>b)btGs=kds z?b43)>n|q%cxhD_eZN~#z)8%pQQrS(zLVdt=CxDoTYao_1p*j>B1Enox5*lNEeE*3 z=;0`q!RY7h4^0yVf!k?8Sp0ry13Gr8Ig{r+{sX8kiVa7rz~@Ji9~2vonRL@E=LhPt zBu0z`a&dD@2v)6{yIt#z#y`n-*3EiZz3b-U4_GQmmRW?4qF=|8)Hic+(?;1fFT?62 z4i|9P-Le3XKxkuk{eDP3E%O?F-T1fj;bfnAk7L0DJ-J!e@cP0lQtdOC+;*)-jSKYo z()G&!{{Y`WAis~pg}{Tv@$i@k8)IfYMHMr|4|O9lG5JEF`9N=8b=WuQtr8A9}SLTbdI+Gt#zC${qF(f&g7G|_0~}~&u~L~){$o!!&D1w)##i` zt;@%7lsN)8jsilEQ>DDfYckL7mWk;doC$}?|1!MB`+vUSit^?A@YRS#Sv3O}?buxY zx372}hW~TrS3kQS8OEW?PYK%bzy*N<7t!F`eI`TG#<5`uKC7%IHB6Ks>Z}Cc^9!Mw zvoVxbwOh{Y(;QXJ%+B@V0U(fbKSRvD0wkBcuMYv4X?M^)*Q9}v^I{z_#?#J7EV46} z1S--Ny6o5R^pO)mD9KOiur&x6;i*Xc;L^Tp4-Uj(U0e{3A1|*sdvp1jH$87L`IYyz z?JmIAn1Ay1SLk-29LJTw*y5UXy~UV|g2yb4i>uZ+5yG*}CB~X6n@k1k2?-=)-8G0A z(}Wqa86sY*2akAcRAj)=`KinExdP}nmWvFw=!YipurpZ}pxKIdPSsZTexL`_87*iR+ZxTBXVr6B0D4X4XyG#* zXTN6~5!Q+uag}NX|2W7yufSz^!&GH^YA-!>pwzK1dY~tM^~rzbj`iiIzT%2<-9=}9 z@^fN8`oy7f$3y$ejrTlIK6~H8<*r8_EBEbxqCE2Cp>p8R;c^&@0T%^!g%f|<=8a|7 z*3IRdo!iTWdv=z~&e>D0y6~LxqKnTf7w+9vc5aEcy1PWqox5_+w(=9NyQ2J^cimKO ze*8F&CLXpcECM5~iP6M_;ut1CoAY3pfHdLig)6Yqhk?G$$2P{xjuA&EaGH`+VyjE? zV;I&Y8oL>MHBY&p&jO&1pmXXU9{|QHjnS{1FLlNp9ri5rH4G-5R_P3igf-P5p$NZ9 zhnpHmee%Nrx)nd=_QS8bq6e1&xwYQ;tq1dPlDa`soTptKl!SPK# z$Fm(<1iC;^2uoHsWi_30?--{920(c2SZmaLx!jMeY11(dHtBAF@`o@0bt_r^Xu=z7ka+; zOZLtE9{MEC)_?W6yUNf1>0g!K`^Zh@{sVEJya|7b0cY*95tr=TxCpH0hBaST09*j# z7!!?rxG$XiTmRuo#m9>&=aw(e+2`IO!0{x| z1+wR&RiktaH>MkPhLYG+_+h%4Mk z#nQ8hsZ#RBXPS9UdLCfJl12>6cv}62i?){^e(hyA;bM}_vGCsh=iYro`K9-KwA{7- zN&M;}Cj4&v{NiSOm3$MoSO7Tr*LmV|g2Y+V3qY@p>=zZ$M=t_i2)GCw!6I|yU^#sF zVEMCK?kP8X?sv;KeCX5V2mi+F%d4)O{->*R^Y-oBQhw;wmy}Pv>*n$(ZnJa_3)B;Nk42U`-CEbo%)VG>Xrak2FH0NfHN=_fO6=Ga`4dO<<~!SQ~40u^22X^efiGU zy}WGMIHyAk&H9?>om2kS^B*cd^XZ3hb%TECY>oB}ZwGX^VCPBB{fek?K#q3oDASR*li9qD~dIB|xSUd%{?hr=^?ED5=fdiBZZbOSy`Y zd&z_?Ow}e|$B0f^HxPS%VN(#`>Ee1c$o8cn$0Ig$I^b=mo>0=UEhaxE$EM}uB@80?T@>B2n%kt16oB?;>wL;`Nid3w>?rmkDn}WS2V-%RNWjr_7_y$<``N9MQ;(Hp7y}gfmjy#f?94tvW~#6 zR4Dh^**w&aWlDwkpoTVk7keshP76S4u@1J7N!%&2kQ*}Tg=vO0bTwl$Z`Z6NuZd2Y z09n^~0E{1<{Iqk!B7jT(ue)ql`McNdbI{4@oew`&{>R_=!}6S`XpSlfad`$QqxXRd$GyfL+b|laGe7diDd-TCk4;oI4uX zPY`{?M#hEw5DS?&UV`(%A~!BTxH>rg_#@@#-}ecH`ZsTTbJ;tGD*?W=^qnuhu>9JM z50qPRCA7>d9*q^-%(lAy(RM8kp|?pQcBCwV2EJ+{QeW4_wo`ytAg*o&^N9NNJw}48 zNrkMNjx`cTlRfGo&j(?uH%N;C zJudzE)c@@-KCfJNF@MT^`ohWo4}RhIF!^t<6Mr|({CwEQvp*mBZNTKipIy+T=ENRu zJdCBoaFgoxz`9IfZ?_J_^3e_Kda|Bz)FqjV53d4vE3ymi+H-C>xpjB>#rJ=z{P^$w zdAxrxeO|6PXGi&_EAjU;_?mDYBaW5E5Oub(G(T)dIyP+5_*T4!x;OsDnZ}_aG4oW6 z$wNOk!Fth9y8Uib5A*beIV}Ke7$(P9$7XbWMPG^zHf3X~VIT$?ga&NQK9HN9Fxx28rXqd(xw0L@^XC1=exh;;<@IQQfN#(ZmbWy3Uw52{Z=0+6YeY`rsRmzj=x0HYVj`x=j;LXH&lxxr1gdd-L?Ex@t@MjA4}-rY0m`q;fWnKy%q)#O6?<@5_22BlT7Z z3L~r4vw-Nll5R&CqhaAM5_V?L_)O(Nn_YQ85K4uZN{u5mRyxXoGZi5Dw^&#NjvXu4 zowu$0%@Rz3b56$L*lP0w$X_5t! z%qG(3R9l5rT#mhppBALSBCzYMa@&EU&>1@A#_CNOO>XP%J=ij5d=*703=Owi5cczOG^7nbw3<00I{Se_gvXHEH~i$U&(Ix{@dC$1#`s|j%Z?))n*$#% zQoIt_hQ$k4FYmhXuJT(qe2R^oyu9wxv&%mG%93vb+Ss+4IF?a-99T}YyPS`)Pd2eL zz6m#DvvbAhNZuyuwbdQ$G(6lUD=A?s#%xUhBc3!i zDikB>WQ%7R#+l-h^Ht|=EpK@~{&xGsh4=kG_IvLw58~NYo&31$-;9TBe49^`EHWp8 zT};H@SwBz8u(wGqnG>AD-}(3L3?5tar%b=>6TITkg>uB^tH)chfMM}Ej9Y=9`}2>L zyB|FO(6r^!-P_8m@fV168&C%}D)5*>)Yw`LJ&VUuKAvW_2|!TYn!jTv99gEu@l4&8 z2vK7Nj<#M*>p`2J9W$2p=?ag4Ih5RRgr}$yddWHA2`?~YC6P`72OZ!th6B(__|L>5 zAjQxCgsfPJZ#cR{Jii5qv;PLXhWfS_@$5hC8-FKob@8)*@>k^pci=5If7Cae{Ol_y zT5s|~_QdmKZ1$M6I!cWr9orJtR{=d7s&yPw+g+a^i0x+r+b}tI?kOL=@3HbbAHI>+ zNy`?za((^2J@^U$9t2`+x?{)Ha9mL|-j%J#LGUr`(#`PUD=2u2#-W?dFTyoqOj9Jr zai|*dSsvO`h$-0lECBAfI$|N3Yn|1SVau|0R7xKT>!ow|Ay{q`HPt1b0A#!Lsoqu> zePL|a@Xb1W?03!XjpggFn*Qv6!>xCgUwGdq%QBzx^WLAA(K_?T#GILIJOX2r%_4L| zY?Il?WN-SBSUGm{Vd&(aF-;%s<);)Iu}I=&rQ;j6lwbbfXUYQy@V$kJ%d0QiTlU}r zsXhltW9D%sWf8$H#ExkSg9O*kCezN+x%Yq>uo}Ngz3agLwODOxeUA=}Ah(cPa;Zwg-v#xVQ~5XRy=sRbT=+r0Nz)?i%TE7Z-4od&)mieCoRuEdq=rw8&&}P{8}ALgx8qnYN+7Y zQkRX^C4CP=!FW?*S!~PtfzD#X+RwBBsOUmgX|DVEECBA0s0H`Tl={qD9_p+g#<85J zpxPlw(v!Ek=?Mu;p770XAJTMLiO-wQ!!y5cyyk*B2ie?-%3s`gJ3jKeO%sK0`z>w6 z2i$&Xhjn;fn&AY?6SH9q*~9KS?WByH=C zau|Ol?zca3Gk%tg4>+bPyYU9*i_gZ@60XkDU`GWp_(8f_J;u}|KI3$3*ds9ccjtZ7ANX(#WopL{)1;8C}OW9%Rr~t2y1yACV6JwodbAXij z5Sz-3X@*mW&8A^p($k(c;c1AC3jsg+!vm+6oQE^?goP907vKBw^5}6)BEC_Fck7q+ zk`E^zD~icQs!2yx;sr^Vh9f52n@-?RhOtfBut_$=0ZcOnI;lxx%k?NuTm|s^0(c(q zzT56EH{bUNgG^So;@gK;<0?R(1n4=yDMEW#2_vu47)ao=7>GvLXBXmzSjowdSi6nV z=0|J&3A(&~jQTtc<$M-^)>-wYCTDEI8E2}FWFO@q{DXIAdp^l#eX9?O2+7H<&r@k* za%G^s$`u!~R0Ez5|M23^Tdq8>Y{%!%Qhe6ijJ1)og$p&?n~TQS3JorVOvA;;0<7I<@98+O4_(c#NQps7F;DHo zy5vMh{9`Npz?}MN%X}69w~-xbouRTRj0if^%PC=!%w+ZwN?7;{7QA(i5jRIJcYgYI-6QL%zs~+R1auUbq76ETsWeY2!OY-54_|^BF5wwZ8{LDiz%HJB zRd?VN!oCcgc#1ta?9}lpfZtri!_AM~yT9CnUnicjT#9ko#;+=KtX$L{2p(taO?^zr zZh=PgK`q*pW$B=>j?~8uZOtH|io)6<^diu~m&cyI-rQo1VYA;;f%l|iC zehz-^1|MxrSpMYGx0Tx-!)vm8&aV@M6Ger|ip_az6BQQlHFM~K?7AqI3tAkxh9PV% zq?i?U#xekT1q!U>q>zkV#*tS}NyA1~1^tRo1nxiZc=@sa_kHDsc$fbq&)83;cu|5c ze-B_ko}U~(f?q4*vxdZ5t2Fka78c&Zebu{UvxOf5O7c;6M1}=gaZ+I5YCV<*U9r zh|n?il|_^?87tYcs;ig#M1 zuL|sS8?dDuMSp+kgLo+jKPje5_SOcsB|Io9q~iw7I<|><+lq&$XJ3eSCyY%ow5AU9 zVP2WIa!@sE=r3jGE-~ve-@(SY5p2$JO~SbA)6mXk0ch=EpL#hKs;SV@#QIE45CAn7PC{dn5uAytG8A4dJ*x|A7B)RJMwHpWxF=R*6IpB zg0w&;A7FSRSFeDHi#Uy8;HI>3GCH3Hpf#9{kHWM>dSF-VGXTypg2Qq!QX0q#f8)U;t&6r#|J)lZ#l7q16F5$U;d}AGX>gm zF4%=;0Baj)<1+?*&_PN&^(@qZX!1x=b+l72AQ^1U2aIgAXMGi^Rbfoy6pum#(VKw~ z^-D%r2=u@Xc8vw}_EVt2E`?P*_f-@|p80ttp!X-hr)me0su=cGrI~1|+tUB7K}Q1E zcrxS%enz&w8ApQ`0N1}N!2M`hfubE~VQd(7iS|L)WFP87mTiDn zT{To4jR28o@{6gw2Eukwv9=RJU2HVsQg!dfrSg*Vr(FOZdi-Gd@SP9FWWXYz*LvAr zB!l_j#%B3Ir$Tz}Sc3L2p*KW*?Vz=*4;NMV`@yPBdk2@GR4dEnI3hu}U7 zN*x=3B6G+AO$GzHoK@rG`?)Lt(Z$Hq@Qga>LmxaaLhL1HM3x6Y4HwK%o{b#A2*f6Q z@GThHj?4dLykCCBIa|twyKs*=VYvxEpMCcecxt@`zxKnkmJbf)BogEN=zwPBNw2dA zWU3m@d{QKq5meM)3z-^h0A=TeILZSICPhVKuf@wWTn*RaKphm;L6pFSKsxSfG?{w4 zaB4WzoA_SSs1JCf4PZkAZ=&m^f_yVnphRP+%J!_U@VXzz}@&b*JgLJb|dyVoZPXLD?3cxiyBNXIzV(CWZh2KmbWZK~$Z|A)Cri26DA+ zgy%M-uyCxt!g802{d#!YBVdbb22_(DIGD^{G?0?$xyU7S;ZwW5r2`K#XD);fZhSrF!J+VfZy%0)wTc(^RhN$g{qn z3NY<%z6*dF9t~Fi(GeeXty35Pj704=u?ZvI{*efdnhJ4dgQ3Z~Fg2O=;eYp*qJh+R zJnbH`dij5{;LrV)%l1yY0PH__q}1A}_o*nWs^ZBtVrH~Th3 zck;HEoQNZ);v|KO_^faqMGXR=<*Ww?K>@&%x_}>3!|YIuE|0tz*9pB3^BrO>oLiNs zSj!Q)O;qT~YeW3t>-m8`V;kEMdizl(Z@nmSRZ|(;CDk2Orz$xa?Zj1&oKv~3Xz#@w zLlKZbgRvU(csjcITmi7r8kFdZlI@PIl=;-@)9Fz!L2Hc>I5o*W5~Akd8T-VEa^arM zlYjm9jz zm-+En%c+au@Y1wnfzA$KEaYU@OF6?>hBlf2_N6VU8Iv_xNmG@praL#I#%L1zt8nOZ z#bPf8-Z_Bca%X!}1Tz2+#D1_avL3RnI5w2b@tn$h763L@2S&8o2a!7&{b8DQ1~b`mxeoF@Br}q9ox#54g8pHx^g!z z|Bs$Tf3N`f7KnXjA9b0^=H(*eu>ZJ#6ArsP5#(2+)yrgps+{}Wy6+fKUmX()^np?K zFp?;DNfsvJ%O(6Wr17vR*@5r1%M-7GD>Dpd*XA2|byK^30CvGXpz4lxgvBxF5J}$! zY09b^h#k({05A}H`OCQ^P8)VTpPt}KCZY3N0NA|N?%biKtY(X*^2@>?&M@u_9=