diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 81b406770..e38a07337 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -62,7 +62,7 @@ jobs: name: ${{ env.OS }}-${{ env.TARGET }} path: artifacts/ macos: - runs-on: ${{ (matrix.target == 'x86_64' && 'macos-13') || 'macos-14' }} + runs-on: ${{ (matrix.target == 'x86_64' && 'macos-15-intel') || 'macos-15' }} strategy: fail-fast: false matrix: @@ -103,7 +103,7 @@ jobs: name: ${{ env.OS }}-${{ env.TARGET }} path: artifacts/ macos-universal: - runs-on: macos-14 + runs-on: macos-15 needs: macos env: OS: macos diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a736eaac..324ddf1d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,15 @@ if (APPLE) else() # Minimum macOS 13 set(CMAKE_OSX_DEPLOYMENT_TARGET "13.4") + + # Catch compiler issue on AppleClang versions below 15.0 + # TODO: Remove this check when we drop macOS 13 Ventura + if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND + CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0) + message(FATAL_ERROR "AppleClang 15.0 or later is required due to a compiler bug in earlier versions.\n" + "Current version: ${CMAKE_CXX_COMPILER_VERSION}\n" + "After updating, delete 'CMakeCache.txt' in the build directory.") + endif() endif() endif() @@ -299,7 +308,7 @@ find_package(Threads REQUIRED) if (ENABLE_QT) if (NOT USE_SYSTEM_QT) - download_qt(6.7.2) + download_qt(6.9.2) endif() find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent) diff --git a/CMakeModules/DownloadExternals.cmake b/CMakeModules/DownloadExternals.cmake index fc8ec6089..a76d95ae1 100644 --- a/CMakeModules/DownloadExternals.cmake +++ b/CMakeModules/DownloadExternals.cmake @@ -20,9 +20,9 @@ function(determine_qt_parameters target host_out type_out arch_out arch_path_out set(arch_path "mingw_64") elseif (MSVC) if ("arm64" IN_LIST ARCHITECTURE) - set(arch_path "msvc2019_arm64") + set(arch_path "msvc2022_arm64") elseif ("x86_64" IN_LIST ARCHITECTURE) - set(arch_path "msvc2019_64") + set(arch_path "msvc2022_64") else() message(FATAL_ERROR "Unsupported bundled Qt architecture. Enable USE_SYSTEM_QT and provide your own.") endif() @@ -30,12 +30,13 @@ function(determine_qt_parameters target host_out type_out arch_out arch_path_out # In case we're cross-compiling, prepare to also fetch the correct host Qt tools. if (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64") - set(host_arch_path "msvc2019_64") + set(host_arch_path "msvc2022_64") elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "ARM64") # TODO: msvc2019_arm64 doesn't include some of the required tools for some reason, # TODO: so until it does, just use msvc2019_64 under x86_64 emulation. + # TODO: ^ Is this still true with msvc2022? # set(host_arch_path "msvc2019_arm64") - set(host_arch_path "msvc2019_64") + set(host_arch_path "msvc2022_64") endif() set(host_arch "win64_${host_arch_path}") else() @@ -105,7 +106,7 @@ function(download_qt_configuration prefix_out target host type arch arch_path ba if (NOT EXISTS "${prefix}") message(STATUS "Downloading Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path}") - set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.1.18") + set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.3.0") if (WIN32) set(aqt_path "${base_path}/aqt.exe") if (NOT EXISTS "${aqt_path}") diff --git a/dist/apple/Info.plist.in b/dist/apple/Info.plist.in index d12a21f8e..2feacd1b6 100644 --- a/dist/apple/Info.plist.in +++ b/dist/apple/Info.plist.in @@ -75,6 +75,9 @@ NSHighResolutionCapable True + UIDesignRequiresCompatibility + UIFileSharingEnabled UILaunchStoryboardName diff --git a/dist/compatibility_list b/dist/compatibility_list index 4f3904169..a36decbe4 160000 --- a/dist/compatibility_list +++ b/dist/compatibility_list @@ -1 +1 @@ -Subproject commit 4f39041699412873d0afcec89a9313148a192647 +Subproject commit a36decbe43d0e5a570ac3d3ba9a0b226dc832a17 diff --git a/dist/languages/ca_ES_valencia.ts b/dist/languages/ca_ES_valencia.ts index 65ef0ca2a..bc138e02f 100644 --- a/dist/languages/ca_ES_valencia.ts +++ b/dist/languages/ca_ES_valencia.ts @@ -27,7 +27,7 @@ <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> - + <html><head/><body><p><img src=":/icons/default/256x256/azahar.png"/></p></body></html> @@ -725,7 +725,7 @@ Desitja ignorar l'error i continuar? Show log output in console - + Mostrar l'eixida del registre en la consola @@ -2275,7 +2275,7 @@ Desitja ignorar l'error i continuar? <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Learn More</span></a> - + <a href='https://web.archive.org/web/20240301211230/https://citra-emu.org/wiki/using-a-controller-or-android-phone-for-motion-or-touch-input'><span style="text-decoration: underline; color:#039be5;">Més Informació</span></a> @@ -2494,12 +2494,12 @@ Desitja ignorar l'error i continuar? Compress installed CIA content - + Comprimir el contingut de CIAs instal·lats Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled. - + Comprimix el contingut de fitxers CIA quan són instal·lats a la SD emulada. Només afecta contingut CIA instal·lat amb esta opció activada. @@ -4431,7 +4431,7 @@ Vols reinstal·lar els arxius de totes maneres? 3DS Installation File (*.cia *.zcia) - + Fitxers d'Instalació de 3DS (*.cia *.zcia) @@ -4510,24 +4510,24 @@ Vols reinstal·lar els arxius de totes maneres? Error compressing file - + Error al comprimir el fitxer File compress operation failed, check log for details. - + Operació de compressió fallida, mira el registre per a més detalls. Error decompressing file - + Error de descompressió del fitxer File decompress operation failed, check log for details. - + Operació de descompressió fallida, mira el registre per a més detalls. @@ -4663,62 +4663,62 @@ Per a veure una guia sobre com instal·lar FFmpeg, polsa Ajuda. Load 3DS ROM File - + Carregar ROM de 3DS 3DS ROM Files (*.cia *cci *3dsx *cxi) - + Fitxers ROM 3DS (*.cia *cci *3dsx *cxi) The selected file is not a compatible 3DS ROM format. Make sure you have chosen the right file, and that it is not encrypted. - + El fitxer seleccionat no és un ROM de 3DS compatible. Assegura't que has triat el fitxer correcte i que no estiga xifrat. The selected file is already compressed. - + El fitxer seleccionat ja està comprimit. 3DS Compressed ROM File (*.%1) - + Fitxer ROM 3DS comprimit (*.%1) Save 3DS Compressed ROM File - + Desar fitxer 3DS comprimit Load 3DS Compressed ROM File - + Carregar fitxer 3DS comprimit 3DS Compressed ROM Files (*.zcia *zcci *z3dsx *zcxi) - + Fitxer ROM 3DS comprimit (*.zcia *zcci *z3dsx *zcxi) The selected file is not a compatible compressed 3DS ROM format. Make sure you have chosen the right file. - + El fitxer seleccionat no és un format de ROM 3DS comprimit compatible. Assegura't d'haver triat l'arxiu correcte. The selected file is already decompressed. - + El fitxer seleccionat ja està descomprimit. 3DS ROM File (*.%1) - + Fitxer ROM 3DS (*.%1) Save 3DS ROM File - + Desar fitxer ROM 3DS @@ -4818,7 +4818,7 @@ Per a veure una guia sobre com instal·lar FFmpeg, polsa Ajuda. Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) - + Frame: %1 ms (GPU: [CMD: %2 ms, SWP: %3 ms], IPC: %4 ms, SVC: %5 ms, Rem: %6 ms) @@ -4839,7 +4839,7 @@ Per a veure una guia sobre com instal·lar FFmpeg, polsa Ajuda. %1 is missing. Please <a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>dump your system archives</a>.<br/>Continuing emulation may result in crashes and bugs. - + Falta %1 . Per favor,<a href='https://web.archive.org/web/20240304201103/https://citra-emu.org/wiki/dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>bolca els teus arxius de sistema</a>.<br/>Continuar l'emulació pot resultar en penges i errors. @@ -4869,7 +4869,7 @@ Per a veure una guia sobre com instal·lar FFmpeg, polsa Ajuda. A fatal error occurred. <a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Check the log</a> for details.<br/>Continuing emulation may result in crashes and bugs. - + Error fatal.<a href='https://web.archive.org/web/20240228001712/https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>Mira el log</a>per a més detalls.<br/>Continuar l'emulació pot resultar en penges i errors. @@ -6387,12 +6387,12 @@ Missatge de depuració: Compress ROM File... - + Comprimir fitxer ROM... Decompress ROM File... - + Descomprimir fitxer ROM... diff --git a/dist/languages/es_ES.ts b/dist/languages/es_ES.ts index b872896e8..a8126d7c9 100644 --- a/dist/languages/es_ES.ts +++ b/dist/languages/es_ES.ts @@ -4517,7 +4517,7 @@ Reinstall the files anyway? File compress operation failed, check log for details. - Operación de comprensión fallida, mira el registro para más detalles. + Operación de compresión fallida, mira el registro para más detalles. @@ -4529,7 +4529,7 @@ Reinstall the files anyway? File decompress operation failed, check log for details. - Operación de descomprensión fallida, mira el registro para más detalles. + Operación de descompresión fallida, mira el registro para más detalles. diff --git a/dist/languages/ru_RU.ts b/dist/languages/ru_RU.ts index f5a4a9b3c..1dcb9ad96 100644 --- a/dist/languages/ru_RU.ts +++ b/dist/languages/ru_RU.ts @@ -3894,7 +3894,7 @@ Drag points to change position, or double-click table cells to edit values. Show current application in your Discord status - + Показывать текущее приложение в статусе Discord @@ -4027,7 +4027,7 @@ Drag points to change position, or double-click table cells to edit values. Azahar - Azahar + Azahar @@ -4170,7 +4170,7 @@ Please check your FFmpeg installation used for compilation. GBA Virtual Console is not supported by Azahar. - + Azahar не поддерживает GBA Virtual Console. @@ -4315,7 +4315,7 @@ Please check your FFmpeg installation used for compilation. Azahar - Azahar + Azahar @@ -4523,7 +4523,7 @@ Reinstall the files anyway? Error decompressing file - + Ошибра при разжатии файла @@ -5036,7 +5036,7 @@ Would you like to download it? Don't show again - + Не показывать снова @@ -7383,7 +7383,8 @@ They may have left the room. Azahar has detected user data for Citra. - + Azahar обнаружил файлы пользователя Citra. + diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 66cbbd52e..aa6e6c84b 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -1,24 +1,37 @@ # Definitions for all external bundled libraries # Suppress warnings from external libraries -if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") +if (MSVC) add_compile_options(/W0) else() add_compile_options(-w) endif() +function(target_disable_warnings target) + if (MSVC) + target_compile_options(${target} INTERFACE /W0) + else() + target_compile_options(${target} INTERFACE -w) + endif() +endfunction() + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) include(DownloadExternals) include(ExternalProject) # Boost -if (NOT USE_SYSTEM_BOOST) +if (USE_SYSTEM_BOOST) + unset(BOOST_ROOT CACHE) + unset(Boost_INCLUDE_DIR CACHE) + set(Boost_NO_SYSTEM_PATHS OFF CACHE BOOL "" FORCE) +else() message(STATUS "Including vendored Boost library") set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "") set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost" CACHE STRING "") set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "") add_library(boost INTERFACE) - target_include_directories(boost SYSTEM INTERFACE ${Boost_INCLUDE_DIR}) + target_include_directories(boost INTERFACE ${Boost_INCLUDE_DIR}) + target_disable_warnings(boost) # Boost::serialization file(GLOB boost_serialization_SRC "${CMAKE_SOURCE_DIR}/externals/boost/libs/serialization/src/*.cpp") @@ -33,11 +46,7 @@ if (NOT USE_SYSTEM_BOOST) ${CMAKE_SOURCE_DIR}/externals/boost/libs/iostreams/src/mapped_file.cpp ) target_link_libraries(boost_iostreams PUBLIC boost) -# Add additional boost libs here; remember to ALIAS them in the root CMakeLists! -else() - unset(BOOST_ROOT CACHE) - unset(Boost_INCLUDE_DIR CACHE) - set(Boost_NO_SYSTEM_PATHS OFF CACHE BOOL "" FORCE) + # Add additional boost libs here; remember to ALIAS them in the root CMakeLists! endif() # Catch2 @@ -73,6 +82,7 @@ endif() # dds-ktx add_library(dds-ktx INTERFACE) target_include_directories(dds-ktx INTERFACE ./dds-ktx) +target_disable_warnings(dds-ktx) # fmt and Xbyak need to be added before dynarmic # libfmt @@ -137,7 +147,8 @@ endif() # MicroProfile add_library(microprofile INTERFACE) -target_include_directories(microprofile SYSTEM INTERFACE ./microprofile) +target_include_directories(microprofile INTERFACE ./microprofile) +target_disable_warnings(microprofile) if (ENABLE_MICROPROFILE) target_compile_definitions(microprofile INTERFACE MICROPROFILE_ENABLED=1) else() @@ -146,10 +157,11 @@ endif() # Nihstro add_library(nihstro-headers INTERFACE) -target_include_directories(nihstro-headers SYSTEM INTERFACE ./nihstro/include) -if (MSVC) - # TODO: For some reason MSVC still applies this warning even with /W0 for externals. - target_compile_options(nihstro-headers INTERFACE /wd4715) +target_include_directories(nihstro-headers INTERFACE ./nihstro/include) +target_disable_warnings(nihstro-headers) +if (NOT MSVC) + # TODO: For some reason MSYS2 still applied this warnin even with -w + target_compile_options(nihstro-headers INTERFACE -Wno-invalid-specialization) endif() # Open Source Archives @@ -173,7 +185,8 @@ if (USE_SYSTEM_FFMPEG_HEADERS) endif() if (NOT FOUND_FFMPEG_HEADERS) message(STATUS "Using bundled ffmpeg headers.") - target_include_directories(library-headers SYSTEM INTERFACE ./library-headers/ffmpeg/include) + target_include_directories(library-headers INTERFACE ./library-headers/ffmpeg/include) + target_disable_warnings(library-headers) endif() # SoundTouch @@ -294,7 +307,8 @@ if (USE_SYSTEM_JSON) # Citra uses "#include " so we have to add this manually target_include_directories(json-headers SYSTEM INTERFACE "${NLOHMANN_PREFIX}/nlohmann") else() - target_include_directories(json-headers SYSTEM INTERFACE ./json) + target_include_directories(json-headers INTERFACE ./json) + target_disable_warnings(json-headers) endif() # OpenSSL @@ -310,7 +324,8 @@ if (NOT OPENSSL_FOUND) set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "") set(OPENSSLDIR "/etc/ssl/") add_subdirectory(libressl EXCLUDE_FROM_ALL) - target_include_directories(ssl SYSTEM INTERFACE ./libressl/include) + target_include_directories(ssl INTERFACE ./libressl/include) + target_disable_warnings(ssl) target_compile_definitions(ssl PRIVATE -DHAVE_INET_NTOP) get_directory_property(OPENSSL_LIBRARIES DIRECTORY libressl @@ -327,17 +342,20 @@ if(USE_SYSTEM_CPP_HTTPLIB) get_target_property(HTTP_LIBS httplib::httplib INTERFACE_LINK_LIBRARIES) if(HTTP_LIBS) message(WARNING "Shared cpp-http (${HTTP_LIBS}) not supported. Falling back to bundled...") - target_include_directories(httplib SYSTEM INTERFACE ./httplib) + target_include_directories(httplib INTERFACE ./httplib) + target_disable_warnings(httplib) else() if(CppHttp_FOUND) target_link_libraries(httplib INTERFACE httplib::httplib) else() message(STATUS "Cpp-httplib not found or not suitable version! Falling back to bundled...") - target_include_directories(httplib SYSTEM INTERFACE ./httplib) - endif() + target_include_directories(httplib INTERFACE ./httplib) + target_disable_warnings(httplib) + endif() endif() else() - target_include_directories(httplib SYSTEM INTERFACE ./httplib) + target_include_directories(httplib INTERFACE ./httplib) + target_disable_warnings(httplib) endif() target_compile_options(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT) target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES}) @@ -354,7 +372,8 @@ if (ENABLE_WEB_SERVICE) target_link_libraries(cpp-jwt INTERFACE cpp-jwt::cpp-jwt) else() add_library(cpp-jwt INTERFACE) - target_include_directories(cpp-jwt SYSTEM INTERFACE ./cpp-jwt/include) + target_include_directories(cpp-jwt INTERFACE ./cpp-jwt/include) + target_disable_warnings(cpp-jwt) target_compile_definitions(cpp-jwt INTERFACE CPP_JWT_USE_VENDORED_NLOHMANN_JSON) endif() endif() @@ -453,7 +472,8 @@ if (ENABLE_VULKAN) endif() else() add_library(vma INTERFACE) - target_include_directories(vma SYSTEM INTERFACE ./vma/include) + target_include_directories(vma INTERFACE ./vma/include) + target_disable_warnings(vma) endif() # vulkan-headers @@ -465,7 +485,8 @@ if (ENABLE_VULKAN) target_link_libraries(vulkan-headers INTERFACE Vulkan::Headers) endif() else() - target_include_directories(vulkan-headers SYSTEM INTERFACE ./vulkan-headers/include) + target_include_directories(vulkan-headers INTERFACE ./vulkan-headers/include) + target_disable_warnings(vulkan-headers) endif() # adrenotools diff --git a/externals/fmt b/externals/fmt index 123913715..e424e3f2e 160000 --- a/externals/fmt +++ b/externals/fmt @@ -1 +1 @@ -Subproject commit 123913715afeb8a437e6388b4473fcc4753e1c9a +Subproject commit e424e3f2e607da02742f73db84873b8084fc714c diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 84006116f..e4aff1c8b 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -186,7 +186,7 @@ dependencies { // Download Vulkan Validation Layers from the KhronosGroup GitHub. val downloadVulkanValidationLayers = tasks.register("downloadVulkanValidationLayers") { - src("https://github.com/KhronosGroup/Vulkan-ValidationLayers/releases/download/vulkan-sdk-1.4.304.1/android-binaries-1.4.304.1.zip") + src("https://github.com/KhronosGroup/Vulkan-ValidationLayers/releases/download/vulkan-sdk-1.4.313.0/android-binaries-1.4.313.0.zip") dest(file("${layout.buildDirectory.get().asFile.path}/tmp/Vulkan-ValidationLayers.zip")) onlyIfModified(true) } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt index eec388463..e53354dc9 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/NativeLibrary.kt @@ -96,6 +96,24 @@ object NativeLibrary { */ external fun onTouchMoved(xAxis: Float, yAxis: Float) + /** + * Handles touch events on the secondary display. + * + * @param xAxis The value of the x-axis. + * @param yAxis The value of the y-axis. + * @param pressed To identify if the touch held down or released. + * @return true if the pointer is within the touchscreen + */ + external fun onSecondaryTouchEvent(xAxis: Float, yAxis: Float, pressed: Boolean): Boolean + + /** + * Handles touch movement on the secondary display. + * + * @param xAxis The value of the instantaneous x-axis. + * @param yAxis The value of the instantaneous y-axis. + */ + external fun onSecondaryTouchMoved(xAxis: Float, yAxis: Float) + external fun reloadSettings() external fun getTitleId(filename: String): Long diff --git a/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt index 3ff594ce9..f23147dd8 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/activities/EmulationActivity.kt @@ -60,7 +60,15 @@ class EmulationActivity : AppCompatActivity() { private lateinit var binding: ActivityEmulationBinding private lateinit var screenAdjustmentUtil: ScreenAdjustmentUtil private lateinit var hotkeyUtility: HotkeyUtility - private lateinit var secondaryDisplay: SecondaryDisplay; + private lateinit var secondaryDisplay: SecondaryDisplay + + private val onShutdown = Runnable { + if (intent.getBooleanExtra("launched_from_shortcut", false)) { + finishAffinity() + } else { + this.finish() + } + } private val emulationFragment: EmulationFragment get() { @@ -77,8 +85,8 @@ class EmulationActivity : AppCompatActivity() { ThemeUtil.setTheme(this) settingsViewModel.settings.loadSettings() super.onCreate(savedInstanceState) - secondaryDisplay = SecondaryDisplay(this); - secondaryDisplay.updateDisplay(); + secondaryDisplay = SecondaryDisplay(this) + secondaryDisplay.updateDisplay() binding = ActivityEmulationBinding.inflate(layoutInflater) screenAdjustmentUtil = ScreenAdjustmentUtil(this, windowManager, settingsViewModel.settings) @@ -101,13 +109,7 @@ class EmulationActivity : AppCompatActivity() { windowManager.defaultDisplay.rotation ) - EmulationLifecycleUtil.addShutdownHook(hook = { - if (intent.getBooleanExtra("launched_from_shortcut", false)) { - finishAffinity() - } else { - this.finish() - } - }) + EmulationLifecycleUtil.addShutdownHook(onShutdown) isEmulationRunning = true instance = this @@ -165,12 +167,12 @@ class EmulationActivity : AppCompatActivity() { } override fun onDestroy() { - EmulationLifecycleUtil.clear() + EmulationLifecycleUtil.removeHook(onShutdown) NativeLibrary.playTimeManagerStop() isEmulationRunning = false instance = null secondaryDisplay.releasePresentation() - secondaryDisplay.releaseVD(); + secondaryDisplay.releaseVD() super.onDestroy() } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/display/SecondaryDisplay.kt b/src/android/app/src/main/java/org/citra/citra_emu/display/SecondaryDisplay.kt index 4af42792c..b44929c9d 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/display/SecondaryDisplay.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/display/SecondaryDisplay.kt @@ -11,29 +11,30 @@ import android.hardware.display.DisplayManager import android.hardware.display.VirtualDisplay import android.os.Bundle import android.view.Display +import android.view.MotionEvent import android.view.Surface import android.view.SurfaceHolder import android.view.SurfaceView -import org.citra.citra_emu.NativeLibrary +import android.view.WindowManager import org.citra.citra_emu.features.settings.model.IntSetting +import org.citra.citra_emu.display.SecondaryDisplayLayout +import org.citra.citra_emu.NativeLibrary -class SecondaryDisplay(val context: Context) { +class SecondaryDisplay(val context: Context) : DisplayManager.DisplayListener { private var pres: SecondaryDisplayPresentation? = null private val displayManager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager private val vd: VirtualDisplay init { - val st = SurfaceTexture(0) - st.setDefaultBufferSize(1920, 1080) - val vdSurface = Surface(st) vd = displayManager.createVirtualDisplay( "HiddenDisplay", 1920, 1080, 320, - vdSurface, + null, DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION ) + displayManager.registerDisplayListener(this, null) } fun updateSurface() { @@ -44,16 +45,23 @@ class SecondaryDisplay(val context: Context) { NativeLibrary.secondarySurfaceDestroyed() } + private fun getExternalDisplay(context: Context): Display? { + val dm = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager + val internalId = context.display.displayId ?: Display.DEFAULT_DISPLAY + val displays = dm.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION) + return displays.firstOrNull { it.displayId != internalId && it.name != "HiddenDisplay" } + } + fun updateDisplay() { // decide if we are going to the external display or the internal one - var display = getCustomerDisplay() + var display = getExternalDisplay(context) if (display == null || IntSetting.SECONDARY_DISPLAY_LAYOUT.int == SecondaryDisplayLayout.NONE.int) { display = vd.display } // if our presentation is already on the right display, ignore - if (pres?.display == display) return; + if (pres?.display == display) return // otherwise, make a new presentation releasePresentation() @@ -61,29 +69,41 @@ class SecondaryDisplay(val context: Context) { pres?.show() } - private fun getCustomerDisplay(): Display? { - val displays = displayManager.displays - // code taken from MelonDS dual screen - should fix odin 2 detection bug - return displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION) - .firstOrNull { it.displayId != Display.DEFAULT_DISPLAY && it.name != "Built-in Screen" && it.name != "HiddenDisplay"} - } - fun releasePresentation() { pres?.dismiss() pres = null } fun releaseVD() { + displayManager.unregisterDisplayListener(this) vd.release() } + + override fun onDisplayAdded(displayId: Int) { + updateDisplay() + } + + override fun onDisplayRemoved(displayId: Int) { + updateDisplay() + } + override fun onDisplayChanged(displayId: Int) { + updateDisplay() + } } class SecondaryDisplayPresentation( context: Context, display: Display, val parent: SecondaryDisplay ) : Presentation(context, display) { private lateinit var surfaceView: SurfaceView + private var touchscreenPointerId = -1 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + window?.setFlags( + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + ) // Initialize SurfaceView surfaceView = SurfaceView(context) @@ -103,6 +123,42 @@ class SecondaryDisplayPresentation( } }) + this.surfaceView.setOnTouchListener { _, event -> + + val pointerIndex = event.actionIndex + val pointerId = event.getPointerId(pointerIndex) + when (event.actionMasked) { + MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> { + if (touchscreenPointerId == -1) { + touchscreenPointerId = pointerId + NativeLibrary.onSecondaryTouchEvent( + event.getX(pointerIndex), + event.getY(pointerIndex), + true + ) + } + } + + MotionEvent.ACTION_MOVE -> { + val index = event.findPointerIndex(touchscreenPointerId) + if (index != -1) { + NativeLibrary.onSecondaryTouchMoved( + event.getX(index), + event.getY(index) + ) + } + } + + MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP, MotionEvent.ACTION_CANCEL -> { + if (pointerId == touchscreenPointerId) { + NativeLibrary.onSecondaryTouchEvent(0f, 0f, false) + touchscreenPointerId = -1 + } + } + } + true + } + setContentView(surfaceView) // Set SurfaceView as content } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SliderSetting.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SliderSetting.kt index 79406594e..46ed42905 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SliderSetting.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SliderSetting.kt @@ -1,4 +1,4 @@ -// Copyright Citra Emulator Project / Lime3DS Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -10,7 +10,6 @@ import org.citra.citra_emu.features.settings.model.AbstractSetting import org.citra.citra_emu.features.settings.model.FloatSetting import org.citra.citra_emu.features.settings.model.ScaledFloatSetting import org.citra.citra_emu.utils.Log -import kotlin.math.roundToInt class SliderSetting( setting: AbstractSetting?, @@ -27,7 +26,8 @@ class SliderSetting( val selectedFloat: Float get() { val setting = setting ?: return defaultValue!!.toFloat() - return when (setting) { + + val ret = when (setting) { is AbstractIntSetting -> setting.int.toFloat() is FloatSetting -> setting.float is ScaledFloatSetting -> setting.float @@ -36,8 +36,8 @@ class SliderSetting( -1f } } + return ret.coerceIn(min.toFloat(), max.toFloat()) } - /** * Write a value to the backing int. If that int was previously null, * initializes a new one and returns it, so it can be added to the Hashmap. diff --git a/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt index fbf3e5525..d3625693c 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/fragments/EmulationFragment.kt @@ -101,6 +101,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram private val emulationViewModel: EmulationViewModel by activityViewModels() private val settingsViewModel: SettingsViewModel by viewModels() + private val onPause = Runnable{ togglePause() } + private val onShutdown = Runnable{ emulationState.stop() } + override fun onAttach(context: Context) { super.onAttach(context) if (context is EmulationActivity) { @@ -156,8 +159,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram emulationState = EmulationState(game.path) emulationActivity = requireActivity() as EmulationActivity screenAdjustmentUtil = ScreenAdjustmentUtil(requireContext(), requireActivity().windowManager, settingsViewModel.settings) - EmulationLifecycleUtil.addShutdownHook(hook = { emulationState.stop() }) - EmulationLifecycleUtil.addPauseResumeHook(hook = { togglePause() }) + EmulationLifecycleUtil.addPauseResumeHook(onPause) + EmulationLifecycleUtil.addShutdownHook(onShutdown) } override fun onCreateView( @@ -507,6 +510,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram super.onDetach() } + override fun onDestroy() { + EmulationLifecycleUtil.removeHook(onPause) + EmulationLifecycleUtil.removeHook(onShutdown) + super.onDestroy() + } + private fun setupCitraDirectoriesThenStartEmulation() { val directoryInitializationState = DirectoryInitialization.start() if (directoryInitializationState === diff --git a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt index 9828dd046..f7519bb81 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/overlay/InputOverlay.kt @@ -153,8 +153,7 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex if (isActionMove) { NativeLibrary.onTouchMoved(xPosition.toFloat(), yPosition.toFloat()) continue - } - else if (isActionUp) { + } else if (isActionUp) { NativeLibrary.onTouchEvent(0f, 0f, false) break // Up and down actions shouldn't loop } diff --git a/src/android/app/src/main/java/org/citra/citra_emu/utils/EmulationLifecycleUtil.kt b/src/android/app/src/main/java/org/citra/citra_emu/utils/EmulationLifecycleUtil.kt index 8f3b5dc07..5fafb7bed 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/utils/EmulationLifecycleUtil.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/utils/EmulationLifecycleUtil.kt @@ -1,4 +1,4 @@ -// Copyright 2023 Citra Emulator Project +// Copyright Citra Emulator Project / Azahar Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -18,15 +18,27 @@ object EmulationLifecycleUtil { } fun addShutdownHook(hook: Runnable) { - shutdownHooks.add(hook) + if (shutdownHooks.contains(hook)) { + Log.warning("[EmulationLifecycleUtil] Tried to add shutdown hook for function that already existed. Skipping.") + } else { + shutdownHooks.add(hook) + } } fun addPauseResumeHook(hook: Runnable) { - pauseResumeHooks.add(hook) + if (pauseResumeHooks.contains(hook)) { + Log.warning("[EmulationLifecycleUtil] Tried to add pause resume hook for function that already existed. Skipping.") + } else { + pauseResumeHooks.add(hook) + } } - fun clear() { - pauseResumeHooks.clear() - shutdownHooks.clear() + fun removeHook(hook: Runnable) { + if (pauseResumeHooks.contains(hook)) { + pauseResumeHooks.remove(hook) + } + if (shutdownHooks.contains(hook)) { + shutdownHooks.remove(hook) + } } } diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 2cb34cbd0..a2880d6dc 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -657,6 +657,25 @@ void Java_org_citra_citra_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEn window->OnTouchMoved((int)x, (int)y); } +jboolean Java_org_citra_citra_1emu_NativeLibrary_onSecondaryTouchEvent([[maybe_unused]] JNIEnv* env, + [[maybe_unused]] jobject obj, + jfloat x, jfloat y, + jboolean pressed) { + if (!secondary_window) { + return JNI_FALSE; + } + return static_cast(secondary_window->OnTouchEvent( + static_cast(x + 0.5), static_cast(y + 0.5), pressed)); +} + +void Java_org_citra_citra_1emu_NativeLibrary_onSecondaryTouchMoved([[maybe_unused]] JNIEnv* env, + [[maybe_unused]] jobject obj, + jfloat x, jfloat y) { + if (secondary_window) { + secondary_window->OnTouchMoved((int)x, (int)y); + } +} + jlong Java_org_citra_citra_1emu_NativeLibrary_getTitleId(JNIEnv* env, [[maybe_unused]] jobject obj, jstring j_filename) { std::string filepath = GetJString(env, j_filename); diff --git a/src/android/app/src/main/res/values-b+ca+ES+valencia/strings.xml b/src/android/app/src/main/res/values-b+ca+ES+valencia/strings.xml index eb3beaa25..0f0e3e978 100644 --- a/src/android/app/src/main/res/values-b+ca+ES+valencia/strings.xml +++ b/src/android/app/src/main/res/values-b+ca+ES+valencia/strings.xml @@ -193,6 +193,10 @@ Advertiment Regió No Vàlida La configuració del país no és vàlida per a la regió emulada seleccionada. La configuració del país no és vàlida per a la consola vinculada actual. + Emmagatzematge + Comprimir el contingut de CIAs instal·lats + Comprimix el contingut de fitxers CIA quan són instal·lats a la SD emulada. Només afecta contingut CIA instal·lat amb esta opció activada. + Càmera interior Càmera esquerra externa @@ -397,6 +401,10 @@ S\'esperen errors gràfics temporals quan estigue activat. Configurar Controls Editar Estil Fet + Lliscament de botons + Mantindre el botó pressionat originalment + Mantindre el botó pressionat actualment + Mantindre el botó original i actualment pressionat Activar Controls Ajustar Escala Escala Global @@ -409,6 +417,8 @@ S\'esperen errors gràfics temporals quan estigue activat. Relació d\'Aspecte Estil de Pantalla Apaïsada Estil de Pantalla de Perfil + Estil de Pantalla Secundària + La disposició de la pantalla secundària connectada, amb cable o sense fil (Chromecast, Miracast) Pantalla amplia Vertical Pantalla Única @@ -416,6 +426,7 @@ S\'esperen errors gràfics temporals quan estigue activat. Pantalles híbrides Original Per omissió + Per defecte del sistema (espill) Estil Personalitzat Posició de Pantalla Xicoteta On hauria d\'aparéixer la pantalla xicoteta en relació amb la gran en Proporció de Pantalla Gran? @@ -536,6 +547,10 @@ S\'esperen errors gràfics temporals quan estigue activat. Crear drecera El nom de la drecera no pot estar buit Allargar per a ajustar la imatge + ID: + Fitxer: + Tipus: + Mostrar informació de rendiment Informació de rendiment diff --git a/src/android/app/src/main/res/values-b+es+ES/strings.xml b/src/android/app/src/main/res/values-b+es+ES/strings.xml index d0c9496bf..f2232f9f9 100644 --- a/src/android/app/src/main/res/values-b+es+ES/strings.xml +++ b/src/android/app/src/main/res/values-b+es+ES/strings.xml @@ -194,7 +194,7 @@ La configuración del país no es válida para la región emulada seleccionada. La configuración del país no es válida para la consola vinculada actual. Almacenamiento - Comprimir el contenido CIA instalado + Comprimir el contenido de CIAs instalados Comprime el contenido de archivos CIA cuando son instalados a la SD emulada. Solo afecta contenido CIA instalado con esta opción activada. @@ -402,9 +402,9 @@ Se esperan fallos gráficos temporales cuando ésta esté activado. Editar Estilo Hecho Deslizamiento de botones - Mantenga el botón presionado originalmente - Mantenga el botón presionado actualmente - Mantenga el botón original y actualmente presionado + Mantener el botón presionado originalmente + Mantener el botón presionado actualmente + Mantener el botón original y actualmente presionado Activar Controles Ajustar Escala Escala Global @@ -417,6 +417,8 @@ Se esperan fallos gráficos temporales cuando ésta esté activado. Relación de Aspecto Estilo de Pantalla Apaisada Estilo de Pantalla de Perfil + Estilo de Pantalla Secundaria + El estilo de la pantalla secundaria conectada, con cable o inalámbrica (Chromecast, Miracast) Pantalla amplia Retrato Pantalla Única @@ -424,6 +426,7 @@ Se esperan fallos gráficos temporales cuando ésta esté activado. Pantallas híbridas Original Por defecto + Por defecto del sistema (espejo) Estilo personalizado Posición Pantalla Pequeña ¿Dónde debería aparecer la pantalla pequeña en relación con la grande en Disposicion de Pantalla Grande? diff --git a/src/android/app/src/main/res/values-b+pl+PL/strings.xml b/src/android/app/src/main/res/values-b+pl+PL/strings.xml index 29e2aabd2..17a1fbbca 100644 --- a/src/android/app/src/main/res/values-b+pl+PL/strings.xml +++ b/src/android/app/src/main/res/values-b+pl+PL/strings.xml @@ -417,6 +417,7 @@ Geometryczny Układ Ekranu Pionowy Układ Ekranu Układ ekranu wyświetlacza dodatkowego + Układ używany przez podłączony dodatkowy ekran, przewodowy lub bezprzewodowy (Chromecast, Miracast) Duży Ekran Ekran Pojedynczy ekran @@ -424,6 +425,7 @@ Hybrydowy Ekran Oryginalny Domyślny + Ustawienia domyślne systemu (mirror) Niestandardowy Układ Pozycja małego ekranu Gdzie powinien być wyświetlany mały ekran względem dużego w układzie dużego ekranu? diff --git a/src/citra_meta/CMakeLists.txt b/src/citra_meta/CMakeLists.txt index 9f9dcd574..182423a2b 100644 --- a/src/citra_meta/CMakeLists.txt +++ b/src/citra_meta/CMakeLists.txt @@ -60,6 +60,10 @@ if (ENABLE_QT AND UNIX AND NOT APPLE) target_link_libraries(citra_meta PRIVATE Qt6::DBus gamemode) endif() +if (ENABLE_QT AND APPLE) + target_link_libraries(citra_meta PRIVATE Qt6::GuiPrivate) +endif() + if (ENABLE_QT AND USE_DISCORD_PRESENCE) target_link_libraries(citra_meta PRIVATE discord-rpc) endif() diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index a36d40a4d..4796fc922 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -172,12 +172,12 @@ add_library(citra_qt STATIC EXCLUDE_FROM_ALL multiplayer/state.h multiplayer/validation.h precompiled_headers.h + qt_image_interface.cpp + qt_image_interface.h uisettings.cpp uisettings.h user_data_migration.cpp user_data_migration.h - qt_image_interface.cpp - qt_image_interface.h util/clickable_label.cpp util/clickable_label.h util/graphics_device_info.cpp @@ -190,6 +190,13 @@ add_library(citra_qt STATIC EXCLUDE_FROM_ALL util/util.h ) +if (APPLE) + target_sources(citra_qt PUBLIC + qt_swizzle.h + qt_swizzle.mm + ) +endif() + file(GLOB COMPAT_LIST ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) @@ -275,6 +282,10 @@ if (NOT WIN32) target_include_directories(citra_qt PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS}) endif() +if (APPLE) + target_link_libraries(citra_qt PRIVATE Qt6::GuiPrivate) +endif() + if (UNIX AND NOT APPLE) target_link_libraries(citra_qt PRIVATE Qt6::DBus gamemode) endif() diff --git a/src/citra_qt/citra_qt.cpp b/src/citra_qt/citra_qt.cpp index bc9b85661..523c3a3be 100644 --- a/src/citra_qt/citra_qt.cpp +++ b/src/citra_qt/citra_qt.cpp @@ -69,6 +69,7 @@ #include "citra_qt/movie/movie_record_dialog.h" #include "citra_qt/multiplayer/state.h" #include "citra_qt/qt_image_interface.h" +#include "citra_qt/qt_swizzle.h" #include "citra_qt/uisettings.h" #include "common/play_time_manager.h" #ifdef ENABLE_QT_UPDATE_CHECKER @@ -4112,6 +4113,11 @@ static Qt::HighDpiScaleFactorRoundingPolicy GetHighDpiRoundingPolicy() { } void LaunchQtFrontend(int argc, char* argv[]) { +#ifdef __APPLE__ + // Ensure that the linker doesn't optimize qt_swizzle.mm out of existence. + QtSwizzle::Dummy(); +#endif + Common::DetachedTasks detached_tasks; #if MICROPROFILE_ENABLED diff --git a/src/citra_qt/qt_swizzle.h b/src/citra_qt/qt_swizzle.h new file mode 100644 index 000000000..25c396b79 --- /dev/null +++ b/src/citra_qt/qt_swizzle.h @@ -0,0 +1,9 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +namespace QtSwizzle { + +void Dummy(); + +} // namespace QtSwizzle diff --git a/src/citra_qt/qt_swizzle.mm b/src/citra_qt/qt_swizzle.mm new file mode 100644 index 000000000..46acdad8f --- /dev/null +++ b/src/citra_qt/qt_swizzle.mm @@ -0,0 +1,48 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#import +#import + +namespace QtSwizzle { + +void Dummy() { + // Call this anywhere to make sure that qt_swizzle.mm is linked. + // noop +} + +} // namespace QtSwizzle + +@implementation QMetalLayer (AzaharPatch) + ++ (void)load { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Class targetClass = [self class]; + + // Get the original and swizzled methods + Method originalMethod = + class_getInstanceMethod(targetClass, @selector(setNeedsDisplayInRect:)); + Method swizzledMethod = + class_getInstanceMethod(targetClass, @selector(swizzled_setNeedsDisplayInRect:)); + + // Swap the implementations + method_exchangeImplementations(originalMethod, swizzledMethod); + }); +} + +- (void)swizzled_setNeedsDisplayInRect:(CGRect)rect { + constexpr auto tooBig = 1e10; // Arbitrary large number + + // Check for problematic huge rectangles + if ((!self.needsDisplay) && (rect.size.width > tooBig || rect.size.height > tooBig || + rect.origin.x < -tooBig || rect.origin.y < -tooBig)) { + return; + } + + // Call the original implementation + [self swizzled_setNeedsDisplayInRect:rect]; +} + +@end \ No newline at end of file diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index c352dbdf0..ee81b177e 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -66,6 +66,10 @@ bool EmuWindow::IsWithinTouchscreen(const Layout::FramebufferLayout& layout, uns } #endif + if (!layout.bottom_screen_enabled) { + return false; + } + Settings::StereoRenderOption render_3d_mode = Settings::values.render_3d.GetValue(); if (render_3d_mode == Settings::StereoRenderOption::SideBySide || diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 7dd42cecc..1b8c97bae 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -864,8 +864,10 @@ bool CIAFile::Close() { if (!complete) { LOG_ERROR(Service_AM, "CIAFile closed prematurely, aborting install..."); if (!is_additional_content) { - FileUtil::DeleteDirRecursively( - GetTitlePath(media_type, container.GetTitleMetadata().GetTitleID())); + // Only delete the content folder as there may be user save data in the title folder. + const std::string title_content_path = + GetTitlePath(media_type, container.GetTitleMetadata().GetTitleID()) + "content/"; + FileUtil::DeleteDirRecursively(title_content_path); } return true; } diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 1ff478984..3a730ab5f 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -556,12 +556,15 @@ bool PipelineCache::EnsureDirectories() const { }; return create_dir(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir)) && - create_dir(GetPipelineCacheDir()); + create_dir(GetVulkanDir()) && create_dir(GetPipelineCacheDir()); +} + +std::string PipelineCache::GetVulkanDir() const { + return FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir) + "vulkan" + DIR_SEP; } std::string PipelineCache::GetPipelineCacheDir() const { - return FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir) + "vulkan" + DIR_SEP + "pipeline" + - DIR_SEP; + return GetVulkanDir() + "pipeline" + DIR_SEP; } void PipelineCache::SwitchPipelineCache(u64 title_id, const std::atomic_bool& stop_loading, diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index 650df5680..c4f2ea062 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h @@ -108,6 +108,9 @@ private: /// Create pipeline cache directories. Returns true on success. bool EnsureDirectories() const; + /// Returns the Vulkan shader directory + std::string GetVulkanDir() const; + /// Returns the pipeline cache storage dir std::string GetPipelineCacheDir() const; diff --git a/tools/README.md b/tools/README.md index c654936af..b4db3f866 100644 --- a/tools/README.md +++ b/tools/README.md @@ -7,7 +7,7 @@ The scripts in this directory assume that your current working directory is the ## Pre-release checklist - [ ] Update compatibility list -- [ ] Update translations +- [ ] If this is a major release (2123.1 -> major.minor), update translations ### Note: diff --git a/tools/purge-github-cache.sh b/tools/purge-github-cache.sh new file mode 100755 index 000000000..01fdb2fed --- /dev/null +++ b/tools/purge-github-cache.sh @@ -0,0 +1,6 @@ +#!/bin/bash -ex + +# This script assumes that the Github CLI is installed and that +# the authenticated user has appropriate authorization. + +gh cache delete --all \ No newline at end of file