Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
156 commits
Select commit Hold shift + click to select a range
28fee6a
video_core: bound macro binds and discard misparsed host blocks
ZnOw01 Oct 31, 2026
fc862e1
texture_cache: reject zero-extent render targets
ZnOw01 Nov 1, 2026
52c2932
shader: FSEL sources keep .NEG/.ABS, and native array-cube vector sam…
Franseven Oct 30, 2026
792daba
core: ignore stale page runs at unmapped pages in WalkBlock
Franseven Oct 31, 2026
c520ca6
buffer_cache: never join a buffer through a stale page table entry
Duck912 Nov 1, 2026
d3fdaed
nvdrv: clear the error notifier when it is installed (from Eden-NS2 d…
Franseven Oct 30, 2026
2ce9116
shader: translate F2I to 8-bit integers (from Eden-NS2 de4f497)
Franseven Oct 30, 2026
4a497a7
shader: translate PRMT in its default mode (from Eden-NS2 de4f497)
Franseven Oct 30, 2026
73b60ac
renderer_vulkan: rotate three resource sets for the applet capture (f…
Franseven Oct 30, 2026
b6fef3d
shader_recompiler: drop unused identities at the end of the SSA rewrite
Wael3rd Oct 30, 2026
efc7298
shader_recompiler: keep SSA definitions of predicates and flags in bl…
Wael3rd Oct 30, 2026
0634367
spirv: remember the ids of scalar constants
Wael3rd Oct 30, 2026
ade6957
shader_recompiler: find the visited block containing a label by lookup
Wael3rd Oct 30, 2026
a8541bc
shader_recompiler: create SSA phis of sealed blocks only when they ar…
Wael3rd Oct 30, 2026
c2e9219
shader_environment: let graphics environments detach from the 3D engine
Wael3rd Oct 30, 2026
5720d5f
nx2: copy buffers back for titles that read GPU-written data
Franseven Oct 30, 2026
ab71d70
vk_update_descriptor: grow the descriptor payload when a frame overfl…
Nov 2, 2026
7453242
vk_pipeline_cache: translate native graphics pipelines on worker threads
Wael3rd Oct 30, 2026
e41e57b
build: define NOMINMAX for clang-cl
godpow Oct 31, 2026
2dbbdb7
android: boot loose ExeFS dumps, add a Load file option
godpow Oct 31, 2026
a231ad7
hid: ignore motion and button updates in NPad::ControllerUpdate
godpow Oct 31, 2026
dde9355
texture_cache: use the null image for textures the host cannot create
godpow Oct 31, 2026
9c2f4db
gpu_split: recover from a lost back-thread wake-up
godpow Oct 31, 2026
0f07059
texture_cache: keep the lower levels of images the host cannot create
godpow Oct 31, 2026
d19ca46
vulkan: emulate shared memory the device does not have
godpow Oct 31, 2026
1308964
vulkan: dump the SPIR-V of graphics pipelines the driver rejects
godpow Oct 31, 2026
26dbba2
vulkan: dump rejected compute shaders and emulated shared memory ones
godpow Oct 31, 2026
89c0c22
spirv: do not decorate the emulated shared memory's types twice
godpow Oct 31, 2026
50af16e
vulkan: keep presenting after the surface cannot be recreated
godpow Oct 31, 2026
6b623a4
vulkan: back large texture arrays on phones instead of leaving them b…
godpow Oct 31, 2026
6df324f
spirv: keep emulated shared memory accesses inside the buffer
godpow Oct 31, 2026
dc28663
host1x: notify syncpoint waiters only when there are some
godpow Oct 31, 2026
2f0a864
settings: build shaders asynchronously by default and for Switch 2 ti…
godpow Oct 31, 2026
163ff96
gpu_split: sleep on the back thread instead of spinning
godpow Oct 31, 2026
94df90e
vulkan: never skip draws that write memory while their pipeline builds
godpow Oct 31, 2026
3533015
vulkan: hand recorded draws to the worker every 32 draws on Android
godpow Oct 31, 2026
5bcfe3c
buffer_cache: flush the 64 KiB around a macro's memory read
godpow Oct 31, 2026
f6e1d88
buffer_cache: skip synchronizing ranges with no CPU writes since
godpow Oct 31, 2026
f89a79a
macro: compile Turing macros to ARM64
godpow Oct 31, 2026
4c820da
core: turn the GPU thread profile on with a gpu_profile file
godpow Oct 31, 2026
31fa5c1
gpu: run macros on the split GPU thread's front on ARM64 too
godpow Oct 31, 2026
067e87c
buffer_cache: take the 64 KiB around every buffer download
godpow Oct 31, 2026
c7b69d8
gpu_split: park the back thread on a futex too
godpow Oct 31, 2026
8eb764b
core: set environment variables from an env.txt
godpow Oct 31, 2026
8df24ae
gpu_split: the owner check on Android too
godpow Oct 31, 2026
9736fd3
buffer_cache: switches for the sync skip and the download window
godpow Oct 31, 2026
108507e
buffer_cache: download only the range asked for again
godpow Nov 1, 2026
1943371
vulkan: never skip draws of Switch 2 programs while their pipeline bu…
godpow Nov 1, 2026
b97f0d0
buffer_cache: download the owned, protected pages around a range
godpow Nov 1, 2026
5e59d48
memory_manager: guard the kind map in PageTableOp too
godpow Nov 1, 2026
1932cb2
buffer_cache: leave the download window off by default
godpow Nov 1, 2026
a5611ea
vulkan_device: memory use and budget without VK_EXT_memory_budget
godpow Nov 1, 2026
25e1b4c
buffer_cache: read GPU-written buffers directly on integrated GPUs
godpow Nov 1, 2026
eab768e
vulkan_device: cap an integrated GPU's memory budget at a quarter of RAM
godpow Nov 1, 2026
53dc65b
vulkan: more pipeline workers, off the background cores, for Switch 2
godpow Nov 1, 2026
af9615b
vulkan: leave a phone more memory while Switch 2 races load
godpow Nov 1, 2026
87a58ee
Add two settings that save memory for Switch 2 titles
godpow Nov 1, 2026
95a00ff
host1x: Bounds check syncpoint ids
godpow Nov 1, 2026
fdaa394
video_core: Fix two crashes in Mario Kart World
godpow Nov 1, 2026
30e775a
kernel: Give freed guest memory back to the host
godpow Nov 1, 2026
bb42be1
buffer_cache: Clamp oversized native vertex streams instead of throwing
godpow Nov 1, 2026
4d84fc0
vulkan: reduce_texture_resolution also halves texture arrays
godpow Nov 1, 2026
a383a8b
texture_cache: release_gpu_only_memory covers whole GPU-only regions
godpow Nov 1, 2026
dce1c35
texture_cache: Count what host images really take
godpow Nov 1, 2026
67c6d55
vulkan: Give staging buffers back sooner
godpow Nov 1, 2026
08ba5d7
buffer_cache: Download only the buffer's own part of a range
godpow Nov 2, 2026
e5b543d
vulkan: Keep no idle staging buffers of 16 MiB or more
godpow Nov 2, 2026
5680115
nvdrv: clear the GPU-only region registry with the sparse state
godpow Nov 3, 2026
5d554bc
vulkan: build task/mesh pipelines only with VK_EXT_mesh_shader task a…
godpow Nov 3, 2026
5c26200
buffer_cache: don't bind multi-range storage segments of deleted buffers
godpow Nov 3, 2026
63401e8
vulkan: report the skipped task/mesh pipeline once across build threads
godpow Nov 3, 2026
adfd57a
nx2: decode AV1 movies with libgav1 (Fortune's Weave)
godpow Nov 3, 2026
5fd21c1
nx2: convert video frames to RGB on four threads
godpow Nov 3, 2026
bc234e5
vulkan: sample point-light cubes from 2D array views
godpow Nov 3, 2026
7f2fd97
nx2:gsv: destroy decoder image pools on 912
godpow Nov 3, 2026
3e6d7bf
nx2:vdecsvc: answer AV1 calls as fefw does, and trace them
godpow Nov 3, 2026
cacdf1b
nx2:gsv: drop destroyed decoder images' GPU mappings a second later
godpow Nov 3, 2026
d413185
nx2: decode AV1 with FFmpeg where it has libdav1d
godpow Nov 3, 2026
4132b95
nx2: build libgav1 on Android only
godpow Nov 3, 2026
b38bb2f
video_core: run the ARM64 macro JIT on Android only
godpow Nov 3, 2026
98b9347
gpu_split: sleep in the split's waits on Android only
godpow Nov 3, 2026
2fd12be
core, settings: Android-only defaults stay on Android
godpow Nov 3, 2026
5f18af7
vulkan: phone memory changes on Android only
godpow Nov 3, 2026
f105d87
kernel: give freed guest memory back to the host on Android only
godpow Nov 3, 2026
e3acf0b
vulkan: dump rejected SPIR-V on desktop only when asked
godpow Nov 3, 2026
d52d978
video_core: keep phone rendering changes off desktop
godpow Nov 3, 2026
b29495b
qt: name the reduce_texture_resolution and release_gpu_only_memory se…
godpow Nov 3, 2026
cdcfd25
Add .nx2: a loose Switch 2 dump packed into one file
godpow Oct 31, 2026
7c815b7
nx2: Never wait on kernel locks on the GPU thread for sparse blocks
godpow Nov 3, 2026
6d12d6a
vulkan: EDEN_NX2_CUBE_VIEWS=0 turns off the cube views of 2D arrays
godpow Nov 3, 2026
504f9ce
video_core: release held writes before each command list, byte for byte
Franseven Oct 31, 2026
f5163e8
vk_staging_buffer_pool: recheck region 0 after a wrap that fell back
godpow Nov 4, 2026
536a75e
nx2: survive corrupted GPU commands
failaip12 Nov 1, 2026
f0d6032
nx2: report rejected ranges as unmapped, recreate a missing swapchain
failaip12 Nov 2, 2026
d038b32
Avoid overallocating small descriptor tables
nowhere02 Nov 2, 2026
fd286f9
shader_recompiler/spirv: emit a Phi for every IR type, not only U1 an…
CloudP4bbs Nov 3, 2026
99ee4ca
Fixed black textures on AMD
arisqz Oct 30, 2026
1bcf102
Release gathered buffers when their sources are removed
nowhere02 Nov 2, 2026
d08f980
shader: pack FP16 texture results with c0 in the low half
Franseven Oct 31, 2026
7240af4
vulkan: only attach the required subgroup size when the device suppor…
ymatrix1 Nov 4, 2026
26b0f8b
settings: the game's own DLSS network off by default on Android
godpow Nov 4, 2026
705294e
nx2:vi2: EDEN_NX2_MKW_PACING, and the Dynamic FPS check finds the game
godpow Nov 4, 2026
0de5444
loader: Mario Kart World 60 FPS mode, and both modes on Android
godpow Nov 4, 2026
3785e62
android: EDEN_ANDROID_FRAME_RATE_HINT overrides the surface frame-rat…
godpow Nov 4, 2026
282e7ff
nx2:vi2: don't pace the presents of games that wait on vsync
godpow Nov 4, 2026
8e01750
nx2:vi2: EDEN_NX2_FRAMES_AHEAD=2 never waits for the presented frame
godpow Nov 4, 2026
8ed2b94
nx2: nx2_command_lists, off by default on Android
godpow Nov 4, 2026
990c8bc
android: detect .nup files in the game list (#381)
aidankinzett Nov 3, 2026
6358be0
fix: Validate main and main.npdm on the same effective ExeFS selected…
aidankinzett Nov 3, 2026
464abfc
nx2:profile: zones for the writer waits and macro DMA-read drains, fr…
godpow Nov 4, 2026
3a1c59c
nx2:split: semaphore ledger, acquires met without draining the back
godpow Nov 4, 2026
f680fea
macro: elide same-value state writes inside the ARM64 JIT
godpow Nov 4, 2026
cbc42f3
nx2:split: wait for queued writers only with the command list series on
godpow Nov 4, 2026
04f2ce6
nx2:split: sink the state writes of front macros on the back
godpow Nov 4, 2026
fdc8231
maxwell3d: check for a deferred draw once per sink, not per sunk write
godpow Nov 4, 2026
83e8c36
nx2:profile: back entry counts, uniform buffer and update zones
godpow Nov 4, 2026
dbf8f83
nx2:profile: method histogram, sampled hot zones, dispatch and batch …
godpow Nov 4, 2026
f363208
nx2:split: send a front macro's constant buffer data as one entry per…
godpow Nov 4, 2026
bf7af93
buffer_cache: compare a small uniform buffer's bytes in place
godpow Nov 4, 2026
9411540
vulkan: EDEN_NX2_DISPATCH_DRAWS sets the draws between worker dispatches
godpow Nov 4, 2026
b9834e4
nx2:profile: count the direct and executable method calls in the hist…
godpow Nov 4, 2026
4f6560f
nx2:split: send a pushbuffer constant buffer run as one entry
godpow Nov 4, 2026
136fb40
nx2:split: don't send a constant buffer bind that changes nothing
godpow Nov 4, 2026
bd99749
loader: Mario Kart World reduced detail (mkw_reduce_detail)
godpow Nov 4, 2026
1caf393
loader: Mario Kart World detail patches as two settings
godpow Nov 4, 2026
c1a97b7
shader: array-cube TEX lowering packs FP16 results and binds its buffer
godpow Nov 4, 2026
f9a674c
vulkan: emulated shared memory within the device's storage range, one…
godpow Nov 4, 2026
5193b71
vulkan: query-result uploads count as GPU writes of their buffers
godpow Nov 4, 2026
4d67597
video_core: an illegal inline-mode header leaves no block active
godpow Nov 4, 2026
bf1aea0
macro: the ARM64 JIT records the failing PC like the x86-64 one
godpow Nov 4, 2026
17779db
vulkan: failed-pipeline SPIR-V dumps are named by the pipeline too
godpow Nov 4, 2026
7e288ae
vulkan: a Switch 2 draw waits for its asynchronous translation
godpow Nov 4, 2026
a0e8fde
vulkan: a written sparse-layers image whose layers failed is backed, …
godpow Nov 4, 2026
689ced1
video_core: the detached shader environment converts texture handles …
godpow Nov 4, 2026
bc5a221
loader: list a package's directory once for its sidecars
godpow Nov 4, 2026
b16ae17
loader: read a packed dump's RomFS version only when asked for
godpow Nov 4, 2026
e42ce2b
nx2:gsv: a retired decoder mapping is dropped only if it is the one r…
godpow Nov 4, 2026
97f658b
vulkan: back out backing a written sparse-layers image whose layers f…
godpow Nov 4, 2026
467c021
vulkan: the shared compute scratch's barrier leaves the render pass; …
godpow Nov 4, 2026
593d38f
vulkan: query-result uploads record their write tick only
godpow Nov 4, 2026
815e9ef
vulkan: Switch 2 draws wait for their translation on Android only
godpow Nov 4, 2026
8800c68
nx2:vi2: cap vsync games' presents at the swap interval instead of no…
godpow Nov 4, 2026
5f88e47
nx2:gsv: the codec-name fallback knows the AV1 names
godpow Nov 5, 2026
b0c84fb
texture_cache: no render target for a zero-sized one, not the null view
godpow Nov 5, 2026
a527132
vulkan: report a dispatch with more workgroups than emulated shared m…
godpow Nov 5, 2026
5977a9b
buffer_cache: a small uniform buffer's snapshot is the slot's copy
godpow Nov 5, 2026
4bc2c5d
macro: the front's same-value elision is cleared after each 3D macro
godpow Nov 5, 2026
a83c95f
nx2:split: the semaphore ledger and the queued words go with the split
godpow Nov 5, 2026
dd251d0
nx2:split: queued words go before the engine is compared
godpow Nov 5, 2026
a1613b2
vulkan: the submit threshold is checked at every draw
godpow Nov 5, 2026
d75a1cb
video_core: a write to a sparse block that got no memory is dropped, …
godpow Nov 5, 2026
d06e412
Merge nx2 (e736dfde9e) into android-nx2
godpow Nov 5, 2026
84a691a
cpu_manager: run NCE core threads with the PAC keys disabled
godpow Nov 5, 2026
89d68bf
video_core: drop sink writes past the engine register files
godpow Nov 5, 2026
7584d61
android: command list fixes on by default, except Mario Kart World
godpow Nov 5, 2026
5bec285
Merge remote-tracking branch 'origin/nx2' into merge/android-nx2
godpow Nov 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions externals/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,11 @@ if (ENABLE_WEB_SERVICE OR ENABLE_UPDATE_CHECKER)
AddJsonPackage(cpp-jwt)
endif()

# libgav1 (AV1 video decoding where FFmpeg has no libdav1d: Android)
if (ANDROID)
add_subdirectory(libgav1)
endif()

# FFMpeg
if (YUZU_USE_EXTERNAL_FFMPEG OR YUZU_USE_BUNDLED_FFMPEG)
add_subdirectory(ffmpeg)
Expand Down
22 changes: 22 additions & 0 deletions externals/libgav1/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later

# libgav1 decodes the AV1 movies of Switch 2 titles (nx2 video decoder) where the bundled FFmpeg
# has no libdav1d (Android's package); with libdav1d, FFmpeg decodes them.

include(FetchContent)

set(LIBGAV1_ENABLE_TESTS OFF)
set(LIBGAV1_ENABLE_EXAMPLES OFF)
# std::mutex in its thread pool: no Abseil (it is only needed for absl::Mutex, tests and examples)
set(LIBGAV1_THREADPOOL_USE_STD_MUTEX 1)
# 8 and 10-bit streams only, which leaves the 12-bit DSP code out
set(LIBGAV1_MAX_BITDEPTH 10)
FetchContent_Declare(libgav1
GIT_REPOSITORY https://chromium.googlesource.com/codecs/libgav1
GIT_TAG c1deec657b32b911920c78e078cfd089faa77200
)
FetchContent_MakeAvailable(libgav1)

set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_NAMES libgav1)
set_property(GLOBAL APPEND PROPERTY CPM_PACKAGE_URLS https://chromium.googlesource.com/codecs/libgav1)
4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ else()
$<$<COMPILE_LANGUAGE:C,CXX>:-pipe>
# Disable RTTI (C++ only)
$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>)
else()
# clang-cl: like the MSVC branch, or windows.h (included by vulkan.h) defines min/max
# macros that break std::min/std::max calls
add_compile_definitions(NOMINMAX)
endif()

if (ENABLE_WERROR)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,17 @@ object NativeLibrary {
if (DocumentsTree.isNativePath(path)) {
YuzuApplication.documentsTree!!.getParentDirectory(path)
} else {
path
FileUtil.getParentUri(path) ?: path
}

/**
* Children of a content URI directory, four strings each: "d" or "f", size (-1 if unknown),
* display name and document URI. Native code finds files next to a loose ExeFS with it.
*/
@Keep
@JvmStatic
fun listChildren(path: String): Array<String> = FileUtil.listChildren(path)

@Keep
@JvmStatic
fun getFilename(path: String): String =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
RENDERER_FORCE_MAX_CLOCK("force_max_clock"),
RENDERER_ASYNCHRONOUS_GPU_EMULATION("use_asynchronous_gpu_emulation"),
RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"),
RENDERER_REDUCE_TEXTURE_RESOLUTION("reduce_texture_resolution"),
RENDERER_RELEASE_GPU_ONLY_MEMORY("release_gpu_only_memory"),
RENDERER_NX2_COMMAND_LISTS("nx2_command_lists"),
RENDERER_MKW_30FPS("mkw_30fps"),
RENDERER_MKW_60FPS("mkw_60fps"),
RENDERER_MKW_LOD_DISTANCE("mkw_lod_distance"),
RENDERER_MKW_SHADOW_CASCADES("mkw_shadow_cascades"),
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
ENABLE_BUFFER_HISTORY("enable_buffer_history"),
USE_OPTIMIZED_VERTEX_BUFFERS("use_optimized_vertex_buffers"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,55 @@ abstract class SettingsItem(
descriptionId = R.string.renderer_asynchronous_shaders_description
)
)
put(
SwitchSetting(
BooleanSetting.RENDERER_REDUCE_TEXTURE_RESOLUTION,
titleId = R.string.renderer_reduce_texture_resolution,
descriptionId = R.string.renderer_reduce_texture_resolution_description
)
)
put(
SwitchSetting(
BooleanSetting.RENDERER_RELEASE_GPU_ONLY_MEMORY,
titleId = R.string.renderer_release_gpu_only_memory,
descriptionId = R.string.renderer_release_gpu_only_memory_description
)
)
put(
SwitchSetting(
BooleanSetting.RENDERER_NX2_COMMAND_LISTS,
titleId = R.string.renderer_nx2_command_lists,
descriptionId = R.string.renderer_nx2_command_lists_description
)
)
put(
SwitchSetting(
BooleanSetting.RENDERER_MKW_30FPS,
titleId = R.string.renderer_mkw_30fps,
descriptionId = R.string.renderer_mkw_30fps_description
)
)
put(
SwitchSetting(
BooleanSetting.RENDERER_MKW_60FPS,
titleId = R.string.renderer_mkw_60fps,
descriptionId = R.string.renderer_mkw_60fps_description
)
)
put(
SwitchSetting(
BooleanSetting.RENDERER_MKW_LOD_DISTANCE,
titleId = R.string.renderer_mkw_lod_distance,
descriptionId = R.string.renderer_mkw_lod_distance_description
)
)
put(
SwitchSetting(
BooleanSetting.RENDERER_MKW_SHADOW_CASCADES,
titleId = R.string.renderer_mkw_shadow_cascades,
descriptionId = R.string.renderer_mkw_shadow_cascades_description
)
)
put(
SingleChoiceSetting(
IntSetting.FAST_GPU_TIME,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,13 @@ class SettingsFragmentPresenter(
add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
add(BooleanSetting.EMULATE_BGR565.key)
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
add(BooleanSetting.RENDERER_REDUCE_TEXTURE_RESOLUTION.key)
add(BooleanSetting.RENDERER_RELEASE_GPU_ONLY_MEMORY.key)
add(BooleanSetting.RENDERER_NX2_COMMAND_LISTS.key)
add(BooleanSetting.RENDERER_MKW_30FPS.key)
add(BooleanSetting.RENDERER_MKW_60FPS.key)
add(BooleanSetting.RENDERER_MKW_LOD_DISTANCE.key)
add(BooleanSetting.RENDERER_MKW_SHADOW_CASCADES.key)
add(IntSetting.ANDROID_PIPELINE_WORKERS.key)
add(BooleanSetting.RENDERER_ASYNCHRONOUS_GPU_EMULATION.key)
add(SettingsItem.GPU_UNSWIZZLE_COMBINED)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
handleEmuReadyIntent(intent)
return
} else if (intentUri != null) {
intentGame = if (Game.extensions.contains(FileUtil.getExtension(intentUri))) {
intentGame = if (Game.extensions.contains(FileUtil.getExtension(intentUri)) ||
FileUtil.getFilename(intentUri) == "main" // a loose ExeFS
) {
GameHelper.getGame(requireActivity().intent.data!!, false)
} else {
null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,14 @@ class HomeSettingsFragment : Fragment() {
}
)
)
add(
HomeSetting(
R.string.load_file,
R.string.load_file_description,
R.drawable.ic_folder_open,
{ mainActivity.loadGameFile.launch(arrayOf("*/*")) }
)
)
add(
HomeSetting(
R.string.verify_installed_content,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class Game(

companion object {
val extensions: Set<String> = HashSet(
listOf("xci", "nsp", "nca", "nro", "nsz", "xcz")
listOf("xci", "nsp", "nca", "nro", "nsz", "xcz", "nx2", "nup")
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import org.yuzu.yuzu_emu.dialogs.NetPlayDialog
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.fragments.AddGameFolderDialogFragment
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.fragments.ProgressDialogFragment
import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.model.AddonViewModel
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.model.GamesViewModel
Expand Down Expand Up @@ -405,6 +407,87 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
}

// "Load file": boots a picked file without adding it to the library. A loose ExeFS main also
// needs its folder (main.npdm, sdk, subsdk*, romfs/), which picking one file does not grant:
// it boots when a granted tree holds it, else the folder is asked for.
val loadGameFile =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
if (result != null) {
processLoadGameFile(result)
}
}

val loadLooseExeFsFolder =
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result ->
if (result != null) {
processLooseExeFsFolder(result)
}
}

private fun processLoadGameFile(result: Uri) {
val filename = FileUtil.getFilename(result)
if (filename != "main" && filename != "main.npdm") {
try {
contentResolver.takePersistableUriPermission(
result,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
} catch (e: SecurityException) {
// Not persistable: the grant still lasts while the app runs
}
bootGameUri { result }
return
}

val treeUri = FileUtil.getTreeDocumentUri(result)
if (treeUri == null) {
MessageDialogFragment.newInstance(
this,
titleId = R.string.loose_exefs_folder_access,
descriptionId = R.string.loose_exefs_folder_access_description,
positiveAction = { loadLooseExeFsFolder.launch(null) }
).show(supportFragmentManager, MessageDialogFragment.TAG)
return
}
bootGameUri {
FileUtil.getParentUri(treeUri.toString())?.let {
GameHelper.findLooseExeFsMain(FileUtil.listFiles(it.toUri()))
}
}
}

private fun processLooseExeFsFolder(result: Uri) {
contentResolver.takePersistableUriPermission(
result,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
bootGameUri { GameHelper.findLooseExeFsMain(FileUtil.listFiles(result)) }
}

// Identifies the game off the main thread (a loose ExeFS indexes its whole RomFS through the
// document provider, which takes a while) and boots it.
private fun bootGameUri(findGameUri: () -> Uri?) {
ProgressDialogFragment.newInstance(this, R.string.loading_game) { _, _ ->
val gameUri = findGameUri()
?: return@newInstance MessageDialogFragment.newInstance(
titleId = R.string.load_file_failed,
descriptionId = R.string.loose_exefs_not_found
)
val game = GameHelper.getGame(gameUri, false)
?: return@newInstance MessageDialogFragment.newInstance(
titleId = R.string.load_file_failed,
descriptionId = R.string.load_file_invalid
)
withContext(Dispatchers.Main) {
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.fragment_container) as NavHostFragment
navHostFragment.navController.navigate(
HomeNavigationDirections.actionGlobalEmulationActivity(game, true)
)
}
}.show(supportFragmentManager, ProgressDialogFragment.TAG)
}

fun processGamesDir(result: Uri, calledFromGameFragment: Boolean = false) {
contentResolver.takePersistableUriPermission(
result,
Expand Down
Loading