diff --git a/CMake/DolphinLibraryTools.cmake b/CMake/DolphinLibraryTools.cmake index f2305d83996a..bedba9dcbd21 100644 --- a/CMake/DolphinLibraryTools.cmake +++ b/CMake/DolphinLibraryTools.cmake @@ -50,6 +50,17 @@ function(dolphin_add_bundled_library library use_system bundled_path) add_subdirectory(${bundled_path} EXCLUDE_FROM_ALL) endfunction() +function(dolphin_set_library_type library type) + if(DEFINED ${library}_TYPE AND NOT ${${library}_TYPE} STREQUAL "${type}") + message(FATAL_ERROR + "The selection for ${library} changed from '${${library}_TYPE}' to '${type}' after configuration.\n" + "Please delete the build directory (or at least CMakeCache.txt) and reconfigure." + ) + endif() + + set(${library}_TYPE "${type}" CACHE INTERNAL "") +endfunction() + function(dolphin_find_optional_system_library library bundled_path) dolphin_optional_system_library(use_system ${library}) string(TOUPPER ${library} upperlib) @@ -101,11 +112,11 @@ function(dolphin_find_optional_system_library library bundled_path) endif() endif() if(${prefix}_FOUND) + dolphin_set_library_type(${library} "System") message(STATUS "Using system ${library}") - set(${prefix}_TYPE "System" PARENT_SCOPE) else() + dolphin_set_library_type(${library} "Bundled") dolphin_add_bundled_library(${library} ${use_system} ${bundled_path}) - set(${prefix}_TYPE "Bundled" PARENT_SCOPE) endif() endfunction() @@ -119,11 +130,11 @@ function(dolphin_find_optional_system_library_pkgconfig library search alias bun endif() endif() if(${library}_FOUND) + dolphin_set_library_type(${library} "System") message(STATUS "Using system ${library}") dolphin_alias_library(${alias} PkgConfig::${library}) - set(${library}_TYPE "System" PARENT_SCOPE) else() + dolphin_set_library_type(${library} "Bundled") dolphin_add_bundled_library(${library} ${use_system} ${bundled_path}) - set(${library}_TYPE "Bundled" PARENT_SCOPE) endif() endfunction() diff --git a/CMake/FindLibUSB.cmake b/CMake/FindLibUSB.cmake index 5a6fc7197ffc..54403b7aecdc 100644 --- a/CMake/FindLibUSB.cmake +++ b/CMake/FindLibUSB.cmake @@ -11,8 +11,15 @@ if(ANDROID) set(LIBUSB_FOUND FALSE CACHE INTERNAL "libusb-1.0 found") message(STATUS "libusb-1.0 not found.") -elseif (NOT LIBUSB_FOUND) - pkg_check_modules (LIBUSB_PKG libusb-1.0) + return() +endif() + +if(TARGET LibUSB::LibUSB) + return() +endif() + +if(NOT LIBUSB_FOUND) + pkg_check_modules(LIBUSB_PKG libusb-1.0) find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h PATHS @@ -30,21 +37,19 @@ elseif (NOT LIBUSB_FOUND) /usr/local/lib ) - if(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) - set(LIBUSB_FOUND TRUE CACHE INTERNAL "libusb-1.0 found") - message(STATUS "Found libusb-1.0: ${LIBUSB_INCLUDE_DIR}, ${LIBUSB_LIBRARIES}") - else(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) - set(LIBUSB_FOUND FALSE CACHE INTERNAL "libusb-1.0 found") - message(STATUS "libusb-1.0 not found.") - endif(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) - mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES) -endif () -if(LIBUSB_FOUND AND NOT TARGET LibUSB::LibUSB) +endif() + + +if(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARIES) add_library(LibUSB::LibUSB UNKNOWN IMPORTED) set_target_properties(LibUSB::LibUSB PROPERTIES IMPORTED_LOCATION "${LIBUSB_LIBRARIES}" INTERFACE_INCLUDE_DIRECTORIES "${LIBUSB_INCLUDE_DIR}" ) + set(LIBUSB_FOUND TRUE CACHE INTERNAL "libusb-1.0 found") + message(STATUS "Found libusb-1.0: ${LIBUSB_INCLUDE_DIR}, ${LIBUSB_LIBRARIES}") +else() + set(LIBUSB_FOUND FALSE CACHE INTERNAL "libusb-1.0 found") + message(STATUS "libusb-1.0 not found.") endif() - diff --git a/CMake/ScmRevGen.cmake b/CMake/ScmRevGen.cmake index 93956b2eeda7..fbc6388982e4 100644 --- a/CMake/ScmRevGen.cmake +++ b/CMake/ScmRevGen.cmake @@ -34,7 +34,7 @@ string(TIMESTAMP DOLPHIN_WC_BUILD_DATE "%Y-%m-%d" UTC) # version number set(DOLPHIN_VERSION_MAJOR "2603") -set(DOLPHIN_VERSION_MINOR "0") +set(DOLPHIN_VERSION_MINOR "1") set(DOLPHIN_VERSION_PATCH ${DOLPHIN_WC_REVISION}) # If Dolphin is not built from a Git repository, default the version info to diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f85fc051660..ea5cd2d246b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -657,10 +657,6 @@ if(UNIX) add_definitions(-DUSE_MEMORYWATCHER=1) endif() -if(ENABLE_SDL) - dolphin_find_optional_system_library(SDL3 Externals/SDL 3.2.0) -endif() - if(ENABLE_ANALYTICS) message(STATUS "Enabling analytics collection (subject to end-user opt-in)") add_definitions(-DUSE_ANALYTICS=1) @@ -700,7 +696,7 @@ endif() add_subdirectory(Externals/cpp-optparse) dolphin_find_optional_system_library_pkgconfig(FMT - fmt>=11.0 fmt::fmt Externals/fmt + fmt>=10.1 fmt::fmt Externals/fmt ) add_subdirectory(Externals/imgui) @@ -733,6 +729,13 @@ if(NOT (WIN32 AND _M_ARM_64)) add_definitions(-DHAS_OPENGL) endif() +if(NOT WIN32) + if(ANDROID) + set(USE_SYSTEM_Iconv OFF) + endif() + dolphin_find_optional_system_library(Iconv Externals/libiconv 1.14) +endif() + dolphin_find_optional_system_library(pugixml Externals/pugixml) dolphin_find_optional_system_library_pkgconfig(ENET libenet>=1.3.18 enet::enet Externals/enet) @@ -776,12 +779,14 @@ if(ENABLE_CUBEB) endif() if(NOT ANDROID AND NOT IOS) - dolphin_find_optional_system_library_pkgconfig( - LibUSB libusb-1.0 LibUSB::LibUSB Externals/libusb - ) + dolphin_find_optional_system_library(LibUSB Externals/libusb) add_definitions(-D__LIBUSB__) endif() +if(ENABLE_SDL) + dolphin_find_optional_system_library(SDL3 Externals/SDL 3.2.0) +endif() + dolphin_find_optional_system_library(SFML Externals/SFML 3.0 COMPONENTS Network System) if(USE_UPNP) @@ -793,15 +798,6 @@ dolphin_find_optional_system_library(MBEDTLS Externals/mbedtls 2.28) dolphin_find_optional_system_library(CURL Externals/curl) -if(NOT WIN32) - if(NOT ANDROID) - dolphin_find_optional_system_library(Iconv Externals/libiconv 1.14) - else() - message(STATUS "Using static iconv from Externals") - add_subdirectory(Externals/libiconv EXCLUDE_FROM_ALL) - endif() -endif() - if(NOT ANDROID AND NOT IOS) dolphin_find_optional_system_library(HIDAPI Externals/hidapi) endif() diff --git a/Data/Sys/GameSettings/G3F.ini b/Data/Sys/GameSettings/G3F.ini index 8d1eed58ca90..a3db583a5af5 100644 --- a/Data/Sys/GameSettings/G3F.ini +++ b/Data/Sys/GameSettings/G3F.ini @@ -3,6 +3,8 @@ [Core] # Values set here will override the main Dolphin settings. MMU = True +# Fixes freeze on second loading screen +PageTableFastmem = False [OnFrame] # Add memory patches to be applied every frame here. diff --git a/Externals/SDL/CMakeLists.txt b/Externals/SDL/CMakeLists.txt index 03163602412d..6bdd6301019e 100644 --- a/Externals/SDL/CMakeLists.txt +++ b/Externals/SDL/CMakeLists.txt @@ -20,6 +20,11 @@ if(CCACHE_BIN) set(CCACHE_BINARY ${CCACHE_BIN}) endif() +if(LibUSB_TYPE STREQUAL Bundled) + set(LibUSB_FOUND TRUE) + set(SDL_HIDAPI_LIBUSB_SHARED OFF) +endif() + add_subdirectory(SDL) if (TARGET SDL3) diff --git a/Externals/curl/CMakeLists.txt b/Externals/curl/CMakeLists.txt index 55f010fb15bf..b0a7ea0d3911 100644 --- a/Externals/curl/CMakeLists.txt +++ b/Externals/curl/CMakeLists.txt @@ -13,7 +13,11 @@ set(HTTP_ONLY ON) set(CURL_USE_LIBPSL OFF) set(CURL_USE_LIBSSH2 OFF) set(CURL_ZLIB OFF CACHE BOOL "" FORCE) -set(CURL_ZSTD OFF) +set(CURL_ZSTD OFF CACHE BOOL "" FORCE) +set(CURL_BROTLI OFF CACHE BOOL "" FORCE) +set(ZLIB_FOUND FALSE) # TODO: Remove once we update to cURL >=8.17.1 https://github.com/curl/curl/pull/20147 +set(ZSTD_FOUND FALSE) # TODO: Same as above +set(BROTLI_FOUND FALSE) # TODO: Same as above set(USE_LIBIDN2 OFF) set(USE_NGHTTP2 OFF) diff --git a/Externals/libusb/CMakeLists.txt b/Externals/libusb/CMakeLists.txt index 6f3b3105f067..39c29608b399 100644 --- a/Externals/libusb/CMakeLists.txt +++ b/Externals/libusb/CMakeLists.txt @@ -125,4 +125,15 @@ check_include_files(sys/timerfd.h HAVE_TIMERFD) check_include_files(unistd.h HAVE_UNISTD_H) configure_file(config.h.in config.h) -add_library(LibUSB::LibUSB ALIAS usb) + +# We don't create an ALIAS here so that dependencies (SDL) that try_compile libusb +# don't fail due to LibUSB::LibUSB being an alias target +add_library(LibUSB::LibUSB INTERFACE IMPORTED GLOBAL) +target_link_libraries(LibUSB::LibUSB + INTERFACE + usb +) +target_include_directories(LibUSB::LibUSB + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/libusb/libusb +) diff --git a/Externals/minizip-ng/CMakeLists.txt b/Externals/minizip-ng/CMakeLists.txt index 086ffd01c1a9..9e7d41cbbf17 100644 --- a/Externals/minizip-ng/CMakeLists.txt +++ b/Externals/minizip-ng/CMakeLists.txt @@ -3,12 +3,42 @@ set(MZ_BUILD_TESTS OFF) set(MZ_BUILD_UNIT_TESTS OFF) set(MZ_BUILD_FUZZ_TESTS OFF) set(MZ_CODE_COVERAGE OFF) +set(MZ_FETCH_LIBS OFF) +set(MZ_BZIP2 OFF) +set(MZ_PKCRYPT OFF) +set(MZ_WZAES OFF) +set(MZ_OPENSSL OFF) +set(MZ_LIBBSD OFF) set(SKIP_INSTALL_ALL ON) -if (MINGW OR MSVC) - set(MZ_FETCH_LIBS OFF) - set(MZ_FORCE_FETCH_LIBS OFF) +if(Iconv_TYPE STREQUAL Bundled) + set(CMAKE_DISABLE_FIND_PACKAGE_Iconv TRUE) + set(Iconv_FOUND TRUE) + set(Iconv_LIBRARIES Iconv::Iconv) + get_target_property(Iconv_INCLUDE_DIRS ${Iconv_LIBRARIES} INTERFACE_INCLUDE_DIRECTORIES) endif() +if(LibLZMA_TYPE STREQUAL Bundled) + set(CMAKE_DISABLE_FIND_PACKAGE_LibLZMA TRUE) + set(LIBLZMA_FOUND TRUE) + set(LIBLZMA_LIBRARIES LibLZMA::LibLZMA) + get_target_property(LIBLZMA_INCLUDE_DIRS ${LIBLZMA_LIBRARIES} INTERFACE_INCLUDE_DIRECTORIES) +endif() +if(ZLIB_TYPE STREQUAL Bundled) + set(CMAKE_DISABLE_FIND_PACKAGE_ZLIB TRUE) + set(ZLIB_FOUND TRUE) + set(ZLIB_LIBRARIES ZLIB::ZLIB) + get_target_property(ZLIB_INCLUDE_DIRS ${ZLIB_LIBRARIES} INTERFACE_INCLUDE_DIRECTORIES) +endif() +if(ZSTD_TYPE STREQUAL Bundled) + set(CMAKE_DISABLE_FIND_PACKAGE_ZSTD TRUE) + set(ZSTD_FOUND TRUE) + set(ZSTD_LIBRARIES zstd::zstd) + get_target_property(ZSTD_INCLUDE_DIRS ${ZSTD_LIBRARIES} INTERFACE_INCLUDE_DIRECTORIES) +endif() + +# minizip-ng otherwise uses system libraries when we provide them above +set(CMAKE_DISABLE_FIND_PACKAGE_PkgConfig TRUE) +set(PKGCONFIG_FOUND FALSE) add_subdirectory(minizip-ng) dolphin_disable_warnings(minizip-ng) diff --git a/Source/Core/Common/TraversalServer.cpp b/Source/Core/Common/TraversalServer.cpp index 0a9b6c0d0bc7..d1a93793a23c 100644 --- a/Source/Core/Common/TraversalServer.cpp +++ b/Source/Core/Common/TraversalServer.cpp @@ -14,7 +14,7 @@ #include #include -#include +#include #ifdef HAVE_LIBSYSTEMD #include diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index cacad3f3d1f9..a88fb463e128 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -26,6 +26,7 @@ #include "Core/Config/FreeLookSettings.h" #include "Core/Config/MainSettings.h" #include "Core/ConfigLoaders/GameConfigLoader.h" +#include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/GeckoCode.h" #include "Core/HW/Memmap.h" @@ -215,6 +216,25 @@ void AchievementManager::LoadGame(const DiscIO::Volume* volume) } } +void AchievementManager::ChangeDisc(const DiscIO::Volume* volume) +{ + if (volume == nullptr) + { + INFO_LOG_FMT(ACHIEVEMENTS, "Ejecting disc."); + LoadGame(nullptr); + } + else if (volume->GetGameID() != SConfig::GetInstance().GetGameID()) + { + INFO_LOG_FMT(ACHIEVEMENTS, "Inserting disc that doesn't belong to the running game."); + LoadGame(nullptr); + } + else + { + INFO_LOG_FMT(ACHIEVEMENTS, "Inserting disc."); + LoadGame(volume); + } +} + bool AchievementManager::IsGameLoaded() const { auto* game_info = rc_client_get_game_info(m_client); diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index 2ab23a43683a..ea57ef73411c 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -121,6 +121,7 @@ class AchievementManager void Login(const std::string& password); bool HasAPIToken() const; void LoadGame(const DiscIO::Volume* volume); + void ChangeDisc(const DiscIO::Volume* volume); bool IsGameLoaded() const; void SetBackgroundExecutionAllowed(bool allowed); @@ -333,6 +334,8 @@ class AchievementManager constexpr void LoadGame(const DiscIO::Volume*) {} + constexpr void ChangeDisc(const DiscIO::Volume*) {} + constexpr void SetBackgroundExecutionAllowed(bool allowed) {} constexpr void DoFrame() {} diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 4ba59ffb95c3..12e39a56ab3c 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -537,6 +537,7 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard, NOTICE_LOG_FMT(BOOT, "Booting from disc: {}", disc.path); const DiscIO::VolumeDisc* volume = SetDisc(system.GetDVDInterface(), std::move(disc.volume), disc.auto_disc_change_paths); + AchievementManager::GetInstance().LoadGame(volume); if (!volume) return false; @@ -655,17 +656,17 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard, if (!Load_BS2(system, ipl.path)) return false; + const DiscIO::VolumeDisc* volume = nullptr; if (ipl.disc) { NOTICE_LOG_FMT(BOOT, "Inserting disc: {}", ipl.disc->path); - SetDisc(system.GetDVDInterface(), DiscIO::CreateDiscForCore(ipl.disc->path), - ipl.disc->auto_disc_change_paths); - } - else - { - AchievementManager::GetInstance().LoadGame(nullptr); + + volume = SetDisc(system.GetDVDInterface(), DiscIO::CreateDiscForCore(ipl.disc->path), + ipl.disc->auto_disc_change_paths); } + AchievementManager::GetInstance().LoadGame(volume); + SConfig::OnTitleDirectlyBooted(guard); return true; } diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 441c5dd03189..3d46d756bf48 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -44,6 +44,7 @@ const Info MAIN_CPU_CORE{{System::Main, "Core", "CPUCore"}, PowerPC::DefaultCPUCore()}; const Info MAIN_JIT_FOLLOW_BRANCH{{System::Main, "Core", "JITFollowBranch"}, true}; const Info MAIN_FASTMEM{{System::Main, "Core", "Fastmem"}, true}; +const Info MAIN_PAGE_TABLE_FASTMEM{{System::Main, "Core", "PageTableFastmem"}, true}; const Info MAIN_FASTMEM_ARENA{{System::Main, "Core", "FastmemArena"}, true}; const Info MAIN_LARGE_ENTRY_POINTS_MAP{{System::Main, "Core", "LargeEntryPointsMap"}, true}; const Info MAIN_ACCURATE_CPU_CACHE{{System::Main, "Core", "AccurateCPUCache"}, false}; diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index 7fe70cc0d675..351d720490a3 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -60,6 +60,7 @@ extern const Info MAIN_SKIP_IPL; extern const Info MAIN_CPU_CORE; extern const Info MAIN_JIT_FOLLOW_BRANCH; extern const Info MAIN_FASTMEM; +extern const Info MAIN_PAGE_TABLE_FASTMEM; extern const Info MAIN_FASTMEM_ARENA; extern const Info MAIN_LARGE_ENTRY_POINTS_MAP; extern const Info MAIN_ACCURATE_CPU_CACHE; diff --git a/Source/Core/Core/DSP/LabelMap.cpp b/Source/Core/Core/DSP/LabelMap.cpp index 1dfdfdaf6a11..3bacd6cf3561 100644 --- a/Source/Core/Core/DSP/LabelMap.cpp +++ b/Source/Core/Core/DSP/LabelMap.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include "Core/DSP/DSPTables.h" diff --git a/Source/Core/Core/FifoPlayer/FifoDataFile.cpp b/Source/Core/Core/FifoPlayer/FifoDataFile.cpp index 1e7ec5d77e63..5c30081393ec 100644 --- a/Source/Core/Core/FifoPlayer/FifoDataFile.cpp +++ b/Source/Core/Core/FifoPlayer/FifoDataFile.cpp @@ -274,7 +274,8 @@ std::unique_ptr FifoDataFile::Load(const std::string& filename, bo } else { - dataFile->m_game_id = std::string{header.gameid, DEFAULT_GAME_ID.size()}; + const size_t gameid_length = strnlen(header.gameid, DEFAULT_GAME_ID.size()); + dataFile->m_game_id = std::string{header.gameid, gameid_length}; } if (flagsOnly) diff --git a/Source/Core/Core/HW/DVD/DVDInterface.cpp b/Source/Core/Core/HW/DVD/DVDInterface.cpp index 33b0efc548f1..376aeb4addbd 100644 --- a/Source/Core/Core/HW/DVD/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVD/DVDInterface.cpp @@ -420,8 +420,6 @@ void DVDInterface::SetDisc(std::unique_ptr disc, m_auto_disc_change_index = 0; } - AchievementManager::GetInstance().LoadGame(disc.get()); - // Assume that inserting a disc requires having an empty disc before if (had_disc != has_disc) ExpansionInterface::g_rtc_flags[ExpansionInterface::RTCFlag::DiscChanged] = true; @@ -444,6 +442,7 @@ void DVDInterface::AutoChangeDiscCallback(Core::System& system, u64 userdata, s6 void DVDInterface::EjectDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate) { + AchievementManager::GetInstance().ChangeDisc(nullptr); system.GetDVDInterface().SetDisc(nullptr, {}); } @@ -454,9 +453,14 @@ void DVDInterface::InsertDiscCallback(Core::System& system, u64 userdata, s64 cy DiscIO::CreateDiscForCore(di.m_disc_path_to_insert); if (new_disc) + { + AchievementManager::GetInstance().ChangeDisc(new_disc.get()); di.SetDisc(std::move(new_disc), {}); + } else + { PanicAlertFmtT("The disc that was about to be inserted couldn't be found."); + } di.m_disc_path_to_insert.clear(); } diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp b/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp index d0ecd0a2b452..b2ff246ccedb 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp @@ -58,7 +58,7 @@ // After resetting the stack to the top, we call _resetstkoflw() to restore // the guard page at the 256kb mark. -const std::array*>, 24> JitBase::JIT_SETTINGS{{ +const std::array*>, 25> JitBase::JIT_SETTINGS{{ {&JitBase::bJITOff, &Config::MAIN_DEBUG_JIT_OFF}, {&JitBase::bJITLoadStoreOff, &Config::MAIN_DEBUG_JIT_LOAD_STORE_OFF}, {&JitBase::bJITLoadStorelXzOff, &Config::MAIN_DEBUG_JIT_LOAD_STORE_LXZ_OFF}, @@ -82,6 +82,7 @@ const std::array*>, 24> JitB {&JitBase::m_accurate_nans, &Config::MAIN_ACCURATE_NANS}, {&JitBase::m_accurate_fmadds, &Config::MAIN_ACCURATE_FMADDS}, {&JitBase::m_fastmem_enabled, &Config::MAIN_FASTMEM}, + {&JitBase::m_page_table_fastmem_enabled, &Config::MAIN_PAGE_TABLE_FASTMEM}, {&JitBase::m_accurate_cpu_cache_enabled, &Config::MAIN_ACCURATE_CPU_CACHE}, }}; @@ -145,9 +146,9 @@ void JitBase::RefreshConfig() jo.fp_exceptions = m_enable_float_exceptions; jo.div_by_zero_exceptions = m_enable_div_by_zero_exceptions; - if (!wanted_page_table_mappings && WantsPageTableMappings()) + if (wanted_page_table_mappings != WantsPageTableMappings()) { - // Mustn't call this if we're still initializing + // Mustn't call this if we're still initializing - it'll cause a crash if (Core::IsRunning(m_system)) m_system.GetMMU().PageTableUpdated(); } @@ -155,7 +156,7 @@ void JitBase::RefreshConfig() bool JitBase::WantsPageTableMappings() const { - return jo.fastmem; + return jo.fastmem && m_page_table_fastmem_enabled; } void JitBase::InitFastmemArena() diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.h b/Source/Core/Core/PowerPC/JitCommon/JitBase.h index 2f366ad07f73..612161b4926a 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBase.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.h @@ -161,13 +161,14 @@ class JitBase : public CPUCoreBase bool m_accurate_nans = false; bool m_accurate_fmadds = false; bool m_fastmem_enabled = false; + bool m_page_table_fastmem_enabled = false; bool m_accurate_cpu_cache_enabled = false; bool m_enable_blr_optimization = false; bool m_cleanup_after_stackfault = false; u8* m_stack_guard = nullptr; - static const std::array*>, 24> JIT_SETTINGS; + static const std::array*>, 25> JIT_SETTINGS; bool DoesConfigNeedRefresh() const; void RefreshConfig(); diff --git a/Source/Core/DolphinLibretro/Boot.cpp b/Source/Core/DolphinLibretro/Boot.cpp index 27496bf3023c..c41f83e30898 100644 --- a/Source/Core/DolphinLibretro/Boot.cpp +++ b/Source/Core/DolphinLibretro/Boot.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "Common/CommonPaths.h" #include "Common/FileUtil.h" @@ -14,6 +15,7 @@ #include "Core/Config/SYSCONFSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" +#include "Core/GeckoCodeConfig.h" #include "Core/HW/DVD/DVDInterface.h" #include "Core/HW/EXI/EXI_Device.h" #include "Core/HW/VideoInterface.h" @@ -23,6 +25,7 @@ #include "DolphinLibretro/Audio.h" #include "DolphinLibretro/Input.h" #include "DolphinLibretro/Log.h" +#include "DolphinLibretro/Common/Globals.h" #include "DolphinLibretro/Common/Options.h" #include "DolphinLibretro/Video.h" #include "DolphinLibretro/VideoContexts/ContextStatus.h" @@ -49,6 +52,117 @@ static std::string DenormalizePath(const std::string& path); static unsigned disk_index = 0; static bool eject_state; static std::vector disk_paths; + +// silence forward declaration warnings +void reload_cheats_from_ini(); +void generate_cht_from_ini(std::string fileName); + +void reload_cheats_from_ini() +{ + // Load Dolphin INI files + const auto& sconfig = SConfig::GetInstance(); + Common::IniFile globalIni = sconfig.LoadDefaultGameIni(); + Common::IniFile localIni = sconfig.LoadLocalGameIni(); + + // Load ActionReplay codes + Libretro::g_ar_codes = ActionReplay::LoadCodes(globalIni, localIni); + + // Load Gecko codes + Libretro::g_gecko_codes = Gecko::LoadCodes(globalIni, localIni); +} + +void generate_cht_from_ini(std::string fileName) +{ + const char* sysdir = nullptr; + + if (!Libretro::environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &sysdir) || !sysdir) + return; + + std::string base = sysdir; + size_t pos = base.find_last_of("/\\"); + if (pos != std::string::npos) + base = base.substr(0, pos); + + // Write RetroArch .cht + std::string cheatDir = base + "/cheats/dolphin-emu/"; + std::string cheatFile = cheatDir + fileName + ".cht"; + + if (File::Exists(cheatFile)) + { + INFO_LOG_FMT(BOOT, "Cheats: pre-existing cht file found: {}", cheatFile); + return; + } + + size_t total = Libretro::g_ar_codes.size() + Libretro::g_gecko_codes.size(); + if (total == 0) + { + INFO_LOG_FMT(BOOT, "Cheats: not generating cht file as no ActionReply or Gecko codes found"); + return; + } + + if (!File::CreateFullPath(cheatFile)) + return; + + std::ofstream out(cheatFile); + if (!out.is_open()) + { + ERROR_LOG_FMT(BOOT, "Cheats: unable to create a new cht file at: {}", cheatFile); + return; + } + + out << "cheats = " << total << "\n\n"; + + size_t cheat_index = 0; + + // ------------------------- + // Action Replay + // ------------------------- + for (const auto& c : Libretro::g_ar_codes) + { + std::string code; + + for (const auto& op : c.ops) + { + if (!code.empty()) + code += "+"; + + code += fmt::format("{:08X} {:08X}", op.cmd_addr, op.value); + } + + out << "cheat" << cheat_index << "_desc = \"" << c.name << "\"\n"; + out << "cheat" << cheat_index << "_code = \"" << code << "\"\n"; + out << "cheat" << cheat_index << "_enable = " << (c.enabled ? "true" : "false") << "\n\n"; + + cheat_index++; + } + + // ------------------------- + // Gecko + // ------------------------- + for (const auto& c : Libretro::g_gecko_codes) + { + std::string code; + + for (const auto& line : c.codes) + { + if (!code.empty()) + code += "+"; + + code += line.original_line; + } + + out << "cheat" << cheat_index << "_desc = \"" << c.name << "\"\n"; + out << "cheat" << cheat_index << "_code = \"" << code << "\"\n"; + out << "cheat" << cheat_index << "_enable = " << (c.enabled ? "true" : "false") << "\n\n"; + + cheat_index++; + } + + out.close(); + + INFO_LOG_FMT(BOOT, "Cheats: cht file created successfully at: {}", cheatFile); +} + } // namespace Libretro bool retro_load_game(const struct retro_game_info* game) @@ -466,6 +580,14 @@ bool retro_load_game(const struct retro_game_info* game) Libretro::Input::InitStage2(); + const bool importCheats = Libretro::GetOption(core::CHEATS_IMPORT, true); + + if (importCheats) + { + Libretro::reload_cheats_from_ini(); + Libretro::generate_cht_from_ini(filename_str); + } + return true; } diff --git a/Source/Core/DolphinLibretro/Common/Globals.cpp b/Source/Core/DolphinLibretro/Common/Globals.cpp index 368ed2062fb1..f42a07dda181 100644 --- a/Source/Core/DolphinLibretro/Common/Globals.cpp +++ b/Source/Core/DolphinLibretro/Common/Globals.cpp @@ -4,6 +4,8 @@ namespace Libretro { retro_environment_t environ_cb = nullptr; bool g_emuthread_launched = false; +std::vector g_gecko_codes; +std::vector g_ar_codes; namespace Input { diff --git a/Source/Core/DolphinLibretro/Common/Globals.h b/Source/Core/DolphinLibretro/Common/Globals.h index 90b1cdbf2f50..62e6059ce58b 100644 --- a/Source/Core/DolphinLibretro/Common/Globals.h +++ b/Source/Core/DolphinLibretro/Common/Globals.h @@ -2,12 +2,17 @@ #include #include + +#include "Core/ActionReplay.h" +#include "Core/GeckoCode.h" #include "Core/IOS/USB/Emulated/Microphone.h" namespace Libretro { extern retro_environment_t environ_cb; extern bool g_emuthread_launched; +extern std::vector g_gecko_codes; +extern std::vector g_ar_codes; namespace Input { diff --git a/Source/Core/DolphinLibretro/Common/Options.cpp b/Source/Core/DolphinLibretro/Common/Options.cpp index c49274194c7a..d02906548e00 100644 --- a/Source/Core/DolphinLibretro/Common/Options.cpp +++ b/Source/Core/DolphinLibretro/Common/Options.cpp @@ -221,7 +221,7 @@ static struct retro_core_option_v2_definition option_defs[] = { Libretro::Options::core::CHEATS_ENABLED, "Core > Internal Cheats", "Internal Cheats", - "Enable built-in cheat codes.", + "Enable built-in cheat codes. Restart core to take effect.", nullptr, CATEGORY_CORE, { @@ -231,6 +231,20 @@ static struct retro_core_option_v2_definition option_defs[] = { }, "disabled" }, + { + Libretro::Options::core::CHEATS_IMPORT, + "Core > Automatically Import Cheats into RetroArch", + "Automatically Import Cheats into RetroArch", + "Import dolphin ini files into RetroArch. Restart core to take effect.", + nullptr, + CATEGORY_CORE, + { + { "disabled", nullptr }, + { "enabled", nullptr }, + { nullptr, nullptr } + }, + "enabled" + }, { Libretro::Options::core::SKIP_GC_BIOS, "Core > Skip GameCube BIOS", diff --git a/Source/Core/DolphinLibretro/Common/Options.h b/Source/Core/DolphinLibretro/Common/Options.h index ad3071e9cfc7..cada86f14a7e 100644 --- a/Source/Core/DolphinLibretro/Common/Options.h +++ b/Source/Core/DolphinLibretro/Common/Options.h @@ -127,6 +127,7 @@ namespace core { constexpr const char FASTMEM_ARENA[] = "dolphin_fastmem_arena"; constexpr const char MAIN_ACCURATE_CPU_CACHE[] = "dolphin_main_accurate_cpu_cache"; constexpr const char CHEATS_ENABLED[] = "dolphin_cheats_enabled"; + constexpr const char CHEATS_IMPORT[] = "dolphin_cheats_import"; constexpr const char SKIP_GC_BIOS[] = "dolphin_skip_gc_bios"; constexpr const char LANGUAGE[] = "dolphin_language"; constexpr const char FAST_DISC_SPEED[] = "dolphin_fast_disc_speed"; diff --git a/Source/Core/DolphinLibretro/Main.cpp b/Source/Core/DolphinLibretro/Main.cpp index be50486fd98b..0bf3c68d6574 100644 --- a/Source/Core/DolphinLibretro/Main.cpp +++ b/Source/Core/DolphinLibretro/Main.cpp @@ -4,20 +4,28 @@ #include #include +#include +#include + #include "AudioCommon/AudioCommon.h" #include "Common/ChunkFile.h" #include "Common/Event.h" +#include "Common/IniFile.h" +#include "Common/FileUtil.h" #include "Common/GL/GLContext.h" #include "Common/Logging/LogManager.h" #include "Common/Thread.h" #include "Common/scmrev.h" #include "Common/Version.h" +#include "Core/ActionReplay.h" #include "Core/BootManager.h" #include "Core/Config/GraphicsSettings.h" #include "Core/Config/MainSettings.h" #include "Core/Config/SYSCONFSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" +#include "Core/GeckoCode.h" +#include "Core/GeckoCodeConfig.h" #include "Core/HW/CPU.h" #include "Core/HW/EXI/EXI.h" #include "Core/HW/EXI/EXI_Device.h" @@ -27,6 +35,7 @@ #include "Core/HW/VideoInterface.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" #include "Core/IOS/USB/Emulated/Microphone.h" +#include "Core/PatchEngine.h" #include "Core/State.h" #include "Core/System.h" #include "DolphinLibretro/Audio.h" @@ -37,6 +46,7 @@ #include "VideoBackends/OGL/OGLGfx.h" #include "VideoCommon/AsyncRequests.h" #include "VideoCommon/Fifo.h" +#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/TextureConfig.h" #include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" @@ -68,6 +78,7 @@ namespace Libretro extern retro_environment_t environ_cb; static bool widescreen; double g_core_refresh_rate{0}; +extern void reload_cheats_from_ini(); } // namespace Libretro extern "C" { @@ -487,11 +498,104 @@ void* retro_get_memory_data(unsigned id) return NULL; } +static void enable_cheat_by_code(bool enabled, const char* code) +{ + std::string incoming(code); + bool found = false; + + // Match Action Replay codes + for (auto& c : Libretro::g_ar_codes) + { + std::string serialized; + serialized.reserve(64); + + for (const auto& op : c.ops) + { + if (!serialized.empty()) + serialized += "+"; + + serialized += fmt::format("{:08X} {:08X}", op.cmd_addr, op.value); + } + + if (serialized == incoming) + { + c.enabled = enabled; + found = true; + break; + } + } + + // Match Gecko codes only if not already matched + if (!found) + { + for (auto& c : Libretro::g_gecko_codes) + { + std::string serialized; + serialized.reserve(64); + + for (const auto& line : c.codes) + { + if (!serialized.empty()) + serialized += "+"; + + serialized += line.original_line; + } + + if (serialized == incoming) + { + c.enabled = enabled; + found = true; + break; + } + } + } +} + +// reset cheats to off void retro_cheat_reset(void) { + const bool importCheats = Libretro::GetOption(Libretro::Options::core::CHEATS_IMPORT, true); + + if (!Config::AreCheatsEnabled() || !importCheats) + return; + + Core::RunOnCPUThread(Core::System::GetInstance(), [&] { + PatchEngine::Shutdown(); + }, true); + + Libretro::reload_cheats_from_ini(); } -void retro_cheat_set(unsigned index, bool enabled, const char* code) +// Enable/disable a cheat +void retro_cheat_set(unsigned index, bool enabled, const char *code) { + if (!Config::AreCheatsEnabled()) + { + OSD::AddMessage("You cannot apply any cheats until you have enabled the following option:\n" + "Core > Internal Cheats - set this to ON", OSD::Duration::VERY_LONG, OSD::Color::RED); + return; + } + + const bool importCheats = Libretro::GetOption(Libretro::Options::core::CHEATS_IMPORT, true); + if (!importCheats) + { + OSD::AddMessage("You cannot apply any cheats until you enabled the following option:\n" + "Core > Automatically Import Cheats into RetroArch - set this to ON", OSD::Duration::VERY_LONG, OSD::Color::RED); + return; + } + + const std::string& game_id = SConfig::GetInstance().GetGameID(); + const u16 game_revision = SConfig::GetInstance().GetRevision(); + + // Look up by code as index is unreliable + enable_cheat_by_code(enabled, code); + + Core::RunOnCPUThread(Core::System::GetInstance(), [&] { + // Apply Action Replay + ActionReplay::ApplyCodes(Libretro::g_ar_codes, game_id, game_revision); + + // Apply Gecko + Gecko::SetActiveCodes(Libretro::g_gecko_codes, game_id, game_revision); + }, true); } } // extern "C" diff --git a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp index f2004ff2c4e3..9ade7dfe0e7e 100644 --- a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp @@ -173,8 +173,20 @@ void GeneralWidget::BackendWarning() { if (Config::GetActiveLayerForConfig(Config::MAIN_GFX_BACKEND) == Config::LayerType::Base) { - auto warningMessage = VideoBackendBase::GetAvailableBackends()[m_backend_combo->currentIndex()] - ->GetWarningMessage(); + const auto& backends = VideoBackendBase::GetAvailableBackends(); + if (backends.empty()) + { + return; + } + + const int current_idx = m_backend_combo->currentIndex(); + if (current_idx == -1) + { + // Don't attempt to get the current backend if it doesn't match any available backends. + return; + } + + auto warningMessage = backends[current_idx]->GetWarningMessage(); if (warningMessage) { ModalMessageBox confirm_sw(this);