Compare commits

..

185 Commits

Author SHA1 Message Date
1367d9323a Android 266 2024-02-23 20:33:46 +00:00
7428f977c2 Merge yuzu-emu#13122 2024-02-23 20:33:46 +00:00
ea9fd436cf Merge yuzu-emu#13116 2024-02-23 20:33:46 +00:00
3bdaf0dc00 Merge yuzu-emu#13096 2024-02-23 20:33:46 +00:00
4368dc14c8 Merge yuzu-emu#13081 2024-02-23 20:33:46 +00:00
13059b300f Merge yuzu-emu#12749 2024-02-23 20:33:46 +00:00
55065f3972 Merge yuzu-emu#12461 2024-02-23 20:33:46 +00:00
975d6f1ec4 Merge pull request #13141 from liamwhite/swap
fs: fix argument order
2024-02-23 15:23:06 -05:00
7c9e2255be Merge pull request #13137 from liamwhite/mac-ci
ci: fix mac build
2024-02-23 15:21:18 -05:00
9f6818a6e5 Merge pull request #13136 from liamwhite/fs-launch
fs: add ISaveDataTransferProhibiter, stub FindSaveDataWithFilter
2024-02-23 15:21:12 -05:00
f1c16b487a fs: fix argument order 2024-02-23 15:10:35 -05:00
6512f39061 ci: fix mac build 2024-02-23 13:25:48 -05:00
22b91afa69 fs: add ISaveDataTransferProhibiter, stub FindSaveDataWithFilter 2024-02-23 12:17:24 -05:00
77107ba124 Merge pull request #13133 from liamwhite/libstdcxx-issue
vi: workaround conductor includes
2024-02-23 11:34:34 -05:00
fa4dec9fe9 Merge pull request #13115 from liamwhite/olsc-pctl
olsc, pctl: move to new ipc
2024-02-23 11:34:29 -05:00
215e887be0 Merge pull request #13100 from liamwhite/audio-ipc
audio: move to new ipc
2024-02-23 11:34:21 -05:00
0da6704fc2 Merge pull request #13073 from FearlessTobi/fsp-srv-ipc
fsp: Migrate remaining interfaces to cmif serialization
2024-02-23 11:34:06 -05:00
812754edec vi: workaround conductor includes 2024-02-23 10:34:49 -05:00
964e19ab56 oboe_sink: handle temporary stream creation failure 2024-02-23 10:30:52 -05:00
9dc624f5dc Merge pull request #13121 from german77/clean-shortcut
yuzu: Fix shortcut error message
2024-02-22 23:04:28 -05:00
dad9ea3e07 Merge pull request #13117 from liamwhite/ovln
psc: stub overlay notification channel
2024-02-22 20:26:03 -05:00
2c00599a53 audio: fix released buffer bounds check 2024-02-22 20:20:31 -05:00
864b046500 yuzu: Fix shortcut error message 2024-02-22 17:52:30 -06:00
d12d9dad40 Merge pull request #12982 from FearlessTobi/fs-rewrite-part0
fs: Add FileSystemAccessor and use cmif serialization
2024-02-22 12:34:47 -05:00
2b3f1d3fc5 Merge pull request #13000 from liamwhite/skip-null-memory
device_memory_manager: skip unregistered interfaces on invalidate
2024-02-22 11:34:23 -06:00
984396a21a Merge pull request #13001 from liamwhite/scaled-availability
vulkan_device: don't use fixed cap for memory limits
2024-02-22 11:31:17 -06:00
4f95ee5209 Merge pull request #13075 from liamwhite/mali-having-a-bad-time
shader_recompiler: throw on missing geometry streams in geometry shaders
2024-02-22 11:30:26 -06:00
c04567fad4 audio: add NotifyHeadphoneVolumeWarningDisplayedEvent 2024-02-21 23:54:10 -05:00
89c2fd3d28 pctl: rewrite IParentalControlService 2024-02-21 23:42:33 -05:00
5ab49c833d pctl: rewrite IParentalControlServiceFactory 2024-02-21 23:00:01 -05:00
0e74204aad pctl: move IParentalControlServiceFactory 2024-02-21 23:00:01 -05:00
a37bd0b9a7 pctl: move IParentalControlService 2024-02-21 23:00:01 -05:00
01d89acd13 pctl: move types and results 2024-02-21 22:58:20 -05:00
e85466c1ae psc: stub overlay notification channel 2024-02-21 22:54:05 -05:00
352297d361 psc: rewrite IPmService 2024-02-21 22:26:32 -05:00
6c2d6cff19 psc: move IPmControl, IPmModule, IPmService 2024-02-21 22:26:12 -05:00
e540757279 olsc: rewrite IOlscServiceForSystemService 2024-02-21 20:02:00 -05:00
a8bca24292 olsc: add IRemoteStorageController 2024-02-21 19:47:54 -05:00
5f3c03d6a8 olsc: add IDaemonController 2024-02-21 19:05:19 -05:00
6b956a6951 olsc: rewrite ITransferTaskListController 2024-02-21 18:36:17 -05:00
8689370830 olsc: rewrite INativeHandleHolder 2024-02-21 18:19:48 -05:00
8ffa27b311 olsc: rewrite IOlscServiceForApplication 2024-02-21 18:19:12 -05:00
6334616b44 olsc: move INativeHandleHolder, IOlscServiceForApplication, IOlscServiceForSystemService, ITransferTaskListController 2024-02-21 16:13:01 -05:00
8bbc209950 Merge pull request #13105 from t895/connection-fix
android: Misc controller fixes
2024-02-21 10:43:46 -05:00
9e1a67b950 fs: add missing mutex header for member (#13106) 2024-02-21 16:43:05 +01:00
de5422b1fd android: Connect controllers with supported styles
If you tried to connect a controller that was previously configured with an unsupported style for your game, when you try to connect that controller, it will immediately disconnect. This ensures that the controller that is being connected will be changed to the first supported style index before being connected.
2024-02-21 08:37:55 -05:00
45f450fca5 android: Add additional check for hasMapping
Controls can have no mapping if they are either "[empty]" or and empty string. This was causing an issue if you reset mapping on all controllers and then tried to play a game. The check to determine whether auto mapping was required would fail and leave you will no mapped controllers. This feels a bit like user error but it smooths things out if you forget so I see it as necessary.
2024-02-21 08:17:30 -05:00
9a3fd76b25 android: Enable all controller styles on emulation shutdown 2024-02-21 08:13:54 -05:00
60fc6df407 Merge pull request #13099 from t895/default-fix
android: Fix extra stick setting default values
2024-02-21 07:02:58 -05:00
2e4a6b7f92 audio: format 2024-02-20 22:51:39 -05:00
5f90bd88da audio: rewrite IHardwareOpusDecoder 2024-02-20 22:15:38 -05:00
c575a85233 audio: rewrite IAudioDevice 2024-02-20 22:15:38 -05:00
ea4703cb31 audio: rewrite IHardwareOpusDecoderManager 2024-02-20 22:15:38 -05:00
0471e54e5a audio: rewrite IAudioRenderer 2024-02-20 22:15:38 -05:00
6012c9fe3a audio: rewrite IAudioRendererManager 2024-02-20 22:15:37 -05:00
f65539504f audio: split IHardwarweOpusDecoder, move IHardwareOpusDecoderManager 2024-02-20 22:15:37 -05:00
62083fcafd audio: split IAudioDevice, IAudioRenderer, move IAudioRendererManager 2024-02-20 22:15:37 -05:00
2e5a9cf119 audio: move IFinalOutputRecorderManager{,ForApplet} 2024-02-20 22:15:37 -05:00
a45b8bc9bc audio: rewrite IAudioOutManager 2024-02-20 22:15:37 -05:00
a05bd3c47e audio: rewrite IAudioOut 2024-02-20 22:15:37 -05:00
2a2c92f181 audio: rewrite IAudioInManager 2024-02-20 22:15:37 -05:00
f54277364c audio: rewrite IAudioIn 2024-02-20 22:15:37 -05:00
de2d496e71 android: Fix extra stick setting default values
The default value was accidentally hardcoded for all extra stick settings
2024-02-20 22:13:59 -05:00
7b5bdd076d Merge pull request #13095 from liamwhite/ns-oops
ns: fix alignment of uid type
2024-02-20 21:19:35 -05:00
e0c17a2113 Merge pull request #10529 from liamwhite/critical-spacing
caches: make critical reclamation less eager and possible in more cases
2024-02-20 23:19:27 -03:00
b107435a3f ns: fix alignment of uid type 2024-02-20 18:43:44 -05:00
4e1fcd4a63 Merge pull request #13091 from t895/device-renaming
android: Expose device name setting
2024-02-20 18:30:54 -05:00
ea4a96b45e Merge pull request #13079 from liamwhite/vi3
vi: misc fixes
2024-02-20 18:30:47 -05:00
6a90db8c19 android: Expose device name setting 2024-02-20 08:16:38 -05:00
0e5972b0b5 android: Add StringInputSetting settings item 2024-02-20 08:06:56 -05:00
5f7608a7c6 vi: ignore shared buffer destruction failure on termination 2024-02-20 00:02:56 -05:00
668ff0db3a vi: remove superfluous locking in shared buffer manager 2024-02-19 23:59:35 -05:00
9f159dd62c nvnflinger/vi: don't recreate buffer queue on open/close 2024-02-19 23:59:35 -05:00
d1eaeeed8c Import keys from filesystem. (#13056)
* Import keys, re-initialize KeyManager, re-scan vfs, re-populate game list.

* <.< spelling.

* Update based on feedback on #13047 and this PR

* Based on feedback: Don't delete existing files. There's legitimate reasons that someone may want to keep their retail keys and title key handling is resilient to mismatches.

* Update src/yuzu/main.cpp

Co-authored-by: Tobias <thm.frey@gmail.com>

* Remove translation of literal filename/filter format.

* clang-format.

---------

Co-authored-by: Tobias <thm.frey@gmail.com>
2024-02-19 19:18:13 -05:00
10e27a2902 Merge pull request #13086 from t895/clear-button-fix
android: Fix broken clear button check
2024-02-19 19:18:05 -05:00
f567a41f53 android: Have input overlay follow player 1 style index (#13085) 2024-02-19 22:47:21 +01:00
704c62ca01 android: Fix broken clear button check 2024-02-19 15:54:52 -05:00
8d5473e67c Merge pull request #13031 from german77/btm-interfcae
service: btm: Migrate service to new IPC
2024-02-19 14:49:42 -05:00
3b1b98c645 android: Fix overlay visibility reset (#13083) 2024-02-19 19:44:42 +01:00
daf350f5d3 android: Show done button when configuring input overlay (#13082) 2024-02-19 19:26:18 +01:00
ef50277124 Address review comments pt. 2 2024-02-19 19:22:51 +01:00
ba70dc4c13 Address review comments 2024-02-19 19:20:46 +01:00
934e420e36 fs: Refactor to use cmif serialization 2024-02-19 19:20:46 +01:00
d5e4617ab5 fs: Add FileSystemAccessor classes 2024-02-19 19:20:40 +01:00
b5a17b501b Address review comments 2024-02-19 19:11:07 +01:00
2b18957365 fs: Add and use fs_save_data_types.h 2024-02-19 19:06:31 +01:00
4c71bf3d90 fsp: Migrate remaining interfaces to cmif serialization 2024-02-19 19:06:31 +01:00
fdf4a5bc90 fsp-srv: Migrate to use cmif serialization 2024-02-19 19:06:31 +01:00
b7d9eba72b fsp: Move IMultiCommitManager to a seperate file 2024-02-19 19:06:31 +01:00
380475af32 fsp: Move ISaveDataInfoReader to a seperate file 2024-02-19 19:06:31 +01:00
c9ef2e26ca Merge pull request #13080 from FearlessTobi/scope-exit
scope_exit: Make constexpr
2024-02-19 10:50:45 -05:00
310c1f50be scope_exit: Make constexpr
Allows the use of the macro in constexpr-contexts.
Also avoids some potential problems when nesting braces inside it.
2024-02-19 16:00:46 +01:00
665fce871f core/CMakeLists: Sort alphabetically 2024-02-19 15:51:02 +01:00
58c7e846cb Merge pull request #13006 from liamwhite/a-hat-in-vram
buffer_cache: use mapped range with large vertex buffer size
2024-02-18 23:37:49 -06:00
8b0fb98a11 Merge pull request #13026 from liamwhite/scale-this-mf
shader_recompiler: fix non-const offset for arrayed image types
2024-02-18 23:37:25 -06:00
8615509c40 Merge pull request #13035 from liamwhite/vi2
vi: manage resources independently of nvnflinger and refactor
2024-02-18 23:36:53 -06:00
d0af52f28e Merge pull request #13048 from liamwhite/new-shell
ns: rewrite for new IPC
2024-02-18 23:36:29 -06:00
f46dc31683 shader_recompiler: throw on missing geometry streams in geometry shaders 2024-02-19 00:34:00 -05:00
ef89b79d7e Merge pull request #13070 from liamwhite/offset
am: account for offset in transfer memory storage
2024-02-18 19:03:56 -05:00
3e41f9a673 Merge pull request #13030 from german77/audio-controller
service: audio: Rewrite IAudioController to new IPC
2024-02-18 19:03:49 -05:00
d45a12826c ns: address review comments 2024-02-18 19:02:00 -05:00
56810541f0 vulkan_device: don't use fixed cap for memory limits 2024-02-18 18:59:13 -05:00
911ee8fd1f am: account for offset in transfer memory storage 2024-02-18 14:56:48 -05:00
5361027ef0 Merge pull request #13068 from german77/no_errors
core: hid: Remove driver errors from log
2024-02-18 13:30:54 -05:00
56721517ea core: hid: Remove driver errors from log 2024-02-18 10:54:56 -06:00
940a71422e nvnflinger: check for layers before compose 2024-02-18 11:25:52 -05:00
da225d4aa1 Merge pull request #13067 from t895/xbox-automap-invert
android: Flip AB/XY for xbox controllers during auto-mapping
2024-02-18 10:48:54 -05:00
8d74c107f5 android: Flip AB/XY for xbox controllers during auto-mapping 2024-02-18 10:40:33 -05:00
1fc86b1e3a Merge pull request #13032 from german77/qlauncher
service: Implement functions needed by Qlaunch
2024-02-18 10:37:52 -05:00
4cdf18095d ns: rewrite IQueryService 2024-02-18 10:35:39 -05:00
2d43831d1f ns: rewrite IServiceGetterInterface 2024-02-18 10:35:39 -05:00
2e96921f9c ns: rewrite IApplicationManagerInterface 2024-02-18 10:35:39 -05:00
cf0de18982 ns: move IDevelopInterface 2024-02-18 10:35:37 -05:00
ae83ee28a3 ns: rewrite ISystemUpdateInterface 2024-02-18 10:32:21 -05:00
306ed4984b ns: move ISystemUpdateControl 2024-02-18 10:32:21 -05:00
626f2e65b1 ns: rewrite IVulnerabilityManagerInterface 2024-02-18 10:32:21 -05:00
2eded86b4b ns: rewrite IReadOnlyApplicationControlDataInterface 2024-02-18 10:32:21 -05:00
786fc512e2 ns: rewrite IReadOnlyApplicationRecordInterface 2024-02-18 10:32:21 -05:00
c31ac45332 ns: add IDynamicRightsInterface 2024-02-18 10:32:21 -05:00
db172ba249 ns: rewrite IDownloadTaskInterface 2024-02-18 10:32:21 -05:00
bb59940b03 ns: rewrite IDocumentInterface 2024-02-18 10:32:21 -05:00
04887953ff ns: rewrite IContentManagementInterface 2024-02-18 10:32:21 -05:00
8ea72cc99d ns: move IFactoryResetInterface 2024-02-18 10:32:21 -05:00
44d2e90217 ns: move IECommerceInterface 2024-02-18 10:32:21 -05:00
12926eb5db ns: move IApplicationVersionInterface 2024-02-18 10:32:21 -05:00
ae114d2fa1 ns: move IAccountProxyInterface 2024-02-18 10:32:21 -05:00
270d07be2f ns: rewrite IPlatformServiceManager 2024-02-18 10:32:21 -05:00
947cdbe4b1 ns: rename results header 2024-02-18 10:32:21 -05:00
5583957616 Merge pull request #13064 from t895/auto-map-fail
android: Only do first startup automapping if nothing has been mapped
2024-02-18 10:27:49 -05:00
6d731e1aa1 Merge pull request #13049 from Leystryku/master
Fix Just Dance 2023 not booting
2024-02-18 10:25:18 -05:00
839ded7d59 Merge pull request #13065 from t895/cancel-button-fail
android: Show cancel button for the content install notice
2024-02-18 10:25:04 -05:00
f57281ebc1 Merge pull request #13066 from t895/touch-fix
android: Map touches to touchscreen
2024-02-18 10:24:58 -05:00
0a3bc6c0cf android: Map touches to touchscreen
I neglected to map touches to the touchscreen when refactoring in the input mapping PR. This fixes that regression.
2024-02-18 10:00:37 -05:00
55a7815064 android: Show cancel button for the content install notice 2024-02-18 09:23:46 -05:00
a1c4f53c8c android: Only do first startup automapping if nothing has been mapped 2024-02-18 09:18:54 -05:00
8bbb44a74e service: Change unique_ptr to make_unique in GetCacheStorageMax 2024-02-18 07:03:50 +01:00
bc5ae04ea0 file_sys: Formatting changes and use unique_ptr in GetCacheStorageMax 2024-02-18 06:17:35 +01:00
4f387b0b74 file_sys: Fix nacp field cache_storage_max_index datatype 2024-02-18 06:00:42 +01:00
bdf8aca750 Merge pull request #13047 from anpilley/import-firmware
Import firmware from folder of loose NCA files
2024-02-17 23:18:00 -05:00
acfc4d6dfb Merge pull request #13054 from t895/lifecycle-utils
android: Create lifecycle utility to simplify common StateFlow operations
2024-02-17 23:17:49 -05:00
35a3c7226a android: Create lifecycle utility to simplify common StateFlow operations 2024-02-17 23:09:09 -05:00
d93fdc8a6c service: Add proper GetCacheStorageMax implementation to IApplicationFunctions 2024-02-18 05:02:35 +01:00
5d3c7433b8 Merge pull request #13050 from t895/marquee-helper
android: Use extension functions for view visibility and text marquee
2024-02-17 22:48:36 -05:00
0010d42f82 android: Use extension functions for view visibility and text marquee 2024-02-17 22:45:33 -05:00
316089c39f Merge pull request #13052 from t895/serializable-stuff
android: Move CoreErrorDialogFragment to its own file
2024-02-17 22:22:46 -05:00
5024df1925 Merge pull request #13051 from german77/cheatmiss
dmnt: cheats: Fix valid address range
2024-02-17 22:22:14 -05:00
e7146309de Merge pull request #13034 from t895/map-all-the-inputs
android: Input mapping
2024-02-17 22:22:06 -05:00
c327d2a62c android: Move CoreErrorDialogFragment to its own file 2024-02-17 21:58:25 -05:00
cb2e312f13 Add check for corrupted firmware files after install. 2024-02-18 12:31:14 +11:00
366bb52ec8 dmnt: cheats: Fix valid address range 2024-02-17 19:10:17 -06:00
82949085c0 fsp: Add FlushAccessLogOnSdCard stub 2024-02-18 00:52:22 +01:00
90c43aa2e7 service: Add GetCacheStorageMax stub to IApplicationFunctions 2024-02-18 00:49:41 +01:00
a07f0883b9 service: vi: Implement ListDisplayMode 2024-02-17 18:08:41 -05:00
812f23d05c vi: manage resources independently of nvnflinger and refactor 2024-02-17 18:08:38 -05:00
dcce9837d2 vi: move shared buffer management from nvnflinger 2024-02-17 18:01:41 -05:00
ee8eccc5fa nvnflinger: convert to process 2024-02-17 18:01:41 -05:00
7b79cddacd am: unify display layer management 2024-02-17 18:00:28 -05:00
53f8383354 Merge pull request #13017 from liamwhite/suspension
kernel: add and enable system suspend type
2024-02-17 17:00:07 -06:00
36108ce2be Merge pull request #13040 from Kelebek1/timezone_shutdown
Close reference to TimeZoneBinary on game close
2024-02-17 17:53:53 -05:00
4cbafc1ef6 service: audio: Rewrite IAudioController to new IPC 2024-02-17 15:05:13 -06:00
e31c926bf0 >.> spelling 2024-02-18 07:58:41 +11:00
59ede32f8e cleanup by clang-format. 2024-02-18 07:41:24 +11:00
9eba64adce Improve behavior when one or more firmware files can't be deleted. 2024-02-18 07:38:47 +11:00
110969e207 service: btm: Implement function needed by QLaunch 2024-02-17 12:39:36 -06:00
50ecad547e android: Input mapping 2024-02-17 12:32:33 -05:00
34fb14ec9a Close reference to TimeZoneBinary on game close 2024-02-17 16:00:14 +00:00
e2e0916100 Merge branch 'yuzu-emu:master' into import-firmware 2024-02-17 23:36:43 +11:00
501e3ae05a Implement In-app firmware installation. 2024-02-17 23:33:55 +11:00
ac33847b30 hid_core: Prevent crash if we try to iterate through empty color devices list 2024-02-16 21:11:47 -05:00
18494b0ad6 hid_core: Use dedicated "port" for android's input overlay 2024-02-16 21:09:42 -05:00
dc2c302a84 config: Reset per-game profile name on load if empty 2024-02-16 21:07:03 -05:00
a251f77556 android: Allow SettingsItems to use String or StringRes 2024-02-16 21:04:26 -05:00
ec02a1cfe5 service: erpt: Implement SubmitContext 2024-02-16 12:22:09 -06:00
39b958ab86 service: caps: Implement GetAlbumFIleList 2024-02-16 12:15:37 -06:00
9c0724b270 service: btm: Migrate service to new IPC 2024-02-16 12:15:06 -06:00
dbcc447f43 service: am: Fix GetMainAppletAvailableUsers for user creation 2024-02-16 12:13:10 -06:00
2954c01b47 service: am: Add QLaunch launcher 2024-02-16 12:13:10 -06:00
462ea921e3 shader_recompiler: fix non-const offset for arrayed image types 2024-02-15 18:49:23 -05:00
cb29aa0473 Revert "shader_recompiler: use only ConstOffset for OpImageFetch"
This reverts commit f296a9ce9a.
2024-02-15 18:38:56 -05:00
af42482565 kernel: add and enable system suspend type 2024-02-14 17:03:50 -05:00
3067bfd126 buffer_cache: use mapped range with large vertex buffer size 2024-02-13 08:27:33 -05:00
461eaca7e8 device_memory_manager: skip unregistered interfaces on invalidate 2024-02-12 20:02:59 -05:00
368bf2211f texture_cache: tweak iteration tracking change 2024-02-11 13:41:13 -05:00
de8a623932 texture_cache: avoid overestimation of ASTC texture sizes 2024-02-11 13:41:13 -05:00
865a0186b6 caches: make critical reclamation less eager and possible in more cases 2024-02-11 13:41:13 -05:00
419 changed files with 11923 additions and 9235 deletions

View File

@ -81,8 +81,7 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- name: Install dependencies - name: Install dependencies
run: | run: |
# workaround for https://github.com/actions/setup-python/issues/577 brew install autoconf automake boost ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@5 sdl2 speexdsp zlib zlib zstd
brew install autoconf automake boost@1.83 ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@5 sdl2 speexdsp zlib zlib zstd || brew link --overwrite python@3.12
- name: Build - name: Build
run: | run: |
mkdir build mkdir build

View File

@ -1,13 +1,11 @@
| Pull Request | Commit | Title | Author | Merged? | | Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----| |----|----|----|----|----|
| [10529](https://github.com/yuzu-emu/yuzu//pull/10529) | [`368bf2211`](https://github.com/yuzu-emu/yuzu//pull/10529/files) | caches: make critical reclamation less eager and possible in more cases | [liamwhite](https://github.com/liamwhite/) | Yes | | [12461](https://github.com/yuzu-emu/yuzu//pull/12461) | [`2831f5dc6`](https://github.com/yuzu-emu/yuzu//pull/12461/files) | Rework Nvdec and VIC to fix out-of-order videos, and speed up decoding. | [Kelebek1](https://github.com/Kelebek1/) | Yes |
| [12461](https://github.com/yuzu-emu/yuzu//pull/12461) | [`acc26667b`](https://github.com/yuzu-emu/yuzu//pull/12461/files) | Rework Nvdec and VIC to fix out-of-order videos, and speed up decoding. | [Kelebek1](https://github.com/Kelebek1/) | Yes |
| [12749](https://github.com/yuzu-emu/yuzu//pull/12749) | [`aad4b0d6f`](https://github.com/yuzu-emu/yuzu//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes | | [12749](https://github.com/yuzu-emu/yuzu//pull/12749) | [`aad4b0d6f`](https://github.com/yuzu-emu/yuzu//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13000](https://github.com/yuzu-emu/yuzu//pull/13000) | [`461eaca7e`](https://github.com/yuzu-emu/yuzu//pull/13000/files) | device_memory_manager: skip unregistered interfaces on invalidate | [liamwhite](https://github.com/liamwhite/) | Yes | | [13081](https://github.com/yuzu-emu/yuzu//pull/13081) | [`2786d34dd`](https://github.com/yuzu-emu/yuzu//pull/13081/files) | aoc: Migrate to use cmif serialization | [FearlessTobi](https://github.com/FearlessTobi/) | Yes |
| [13006](https://github.com/yuzu-emu/yuzu//pull/13006) | [`3067bfd12`](https://github.com/yuzu-emu/yuzu//pull/13006/files) | buffer_cache: use mapped range with large vertex buffer size | [liamwhite](https://github.com/liamwhite/) | Yes | | [13096](https://github.com/yuzu-emu/yuzu//pull/13096) | [`0a8759057`](https://github.com/yuzu-emu/yuzu//pull/13096/files) | texture_cache: use two-pass collection for costly load resources | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13017](https://github.com/yuzu-emu/yuzu//pull/13017) | [`af4248256`](https://github.com/yuzu-emu/yuzu//pull/13017/files) | kernel: add and enable system suspend type | [liamwhite](https://github.com/liamwhite/) | Yes | | [13116](https://github.com/yuzu-emu/yuzu//pull/13116) | [`54ed837ad`](https://github.com/yuzu-emu/yuzu//pull/13116/files) | android: Flip AB/XY for 8Bitdo controllers | [t895](https://github.com/t895/) | Yes |
| [13026](https://github.com/yuzu-emu/yuzu//pull/13026) | [`462ea921e`](https://github.com/yuzu-emu/yuzu//pull/13026/files) | shader_recompiler: fix non-const offset for arrayed image types | [liamwhite](https://github.com/liamwhite/) | Yes | | [13122](https://github.com/yuzu-emu/yuzu//pull/13122) | [`505b3e4a7`](https://github.com/yuzu-emu/yuzu//pull/13122/files) | vk_rasterizer: flip scissor y on lower left origin mode | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13034](https://github.com/yuzu-emu/yuzu//pull/13034) | [`50ecad547`](https://github.com/yuzu-emu/yuzu//pull/13034/files) | android: Input mapping | [t895](https://github.com/t895/) | Yes |
End of merge log. You can find the original README.md below the break. End of merge log. You can find the original README.md below the break.

View File

@ -121,6 +121,7 @@ else()
-Wno-attributes -Wno-attributes
-Wno-invalid-offsetof -Wno-invalid-offsetof
-Wno-unused-parameter -Wno-unused-parameter
-Wno-missing-field-initializers
) )
if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang

View File

@ -3,24 +3,21 @@
package org.yuzu.yuzu_emu package org.yuzu.yuzu_emu
import android.app.Dialog
import android.content.DialogInterface import android.content.DialogInterface
import android.net.Uri import android.net.Uri
import android.os.Bundle
import android.text.Html import android.text.Html
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
import android.view.Surface import android.view.Surface
import android.view.View import android.view.View
import android.widget.TextView import android.widget.TextView
import androidx.annotation.Keep import androidx.annotation.Keep
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import org.yuzu.yuzu_emu.activities.EmulationActivity import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.fragments.CoreErrorDialogFragment
import org.yuzu.yuzu_emu.utils.DocumentsTree import org.yuzu.yuzu_emu.utils.DocumentsTree
import org.yuzu.yuzu_emu.utils.FileUtil import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.Log import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable
import org.yuzu.yuzu_emu.model.InstallResult import org.yuzu.yuzu_emu.model.InstallResult
import org.yuzu.yuzu_emu.model.Patch import org.yuzu.yuzu_emu.model.Patch
import org.yuzu.yuzu_emu.model.GameVerificationResult import org.yuzu.yuzu_emu.model.GameVerificationResult
@ -184,46 +181,13 @@ object NativeLibrary {
ErrorUnknown ErrorUnknown
} }
private var coreErrorAlertResult = false var coreErrorAlertResult = false
private val coreErrorAlertLock = Object() val coreErrorAlertLock = Object()
class CoreErrorDialogFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val title = requireArguments().serializable<String>("title")
val message = requireArguments().serializable<String>("message")
return MaterialAlertDialogBuilder(requireActivity())
.setTitle(title)
.setMessage(message)
.setPositiveButton(R.string.continue_button, null)
.setNegativeButton(R.string.abort_button) { _: DialogInterface?, _: Int ->
coreErrorAlertResult = false
synchronized(coreErrorAlertLock) { coreErrorAlertLock.notify() }
}
.create()
}
override fun onDismiss(dialog: DialogInterface) {
coreErrorAlertResult = true
synchronized(coreErrorAlertLock) { coreErrorAlertLock.notify() }
}
companion object {
fun newInstance(title: String?, message: String?): CoreErrorDialogFragment {
val frag = CoreErrorDialogFragment()
val args = Bundle()
args.putString("title", title)
args.putString("message", message)
frag.arguments = args
return frag
}
}
}
private fun onCoreErrorImpl(title: String, message: String) { private fun onCoreErrorImpl(title: String, message: String) {
val emulationActivity = sEmulationActivity.get() val emulationActivity = sEmulationActivity.get()
if (emulationActivity == null) { if (emulationActivity == null) {
error("[NativeLibrary] EmulationActivity not present") Log.error("[NativeLibrary] EmulationActivity not present")
return return
} }
@ -239,7 +203,7 @@ object NativeLibrary {
fun onCoreError(error: CoreError?, details: String): Boolean { fun onCoreError(error: CoreError?, details: String): Boolean {
val emulationActivity = sEmulationActivity.get() val emulationActivity = sEmulationActivity.get()
if (emulationActivity == null) { if (emulationActivity == null) {
error("[NativeLibrary] EmulationActivity not present") Log.error("[NativeLibrary] EmulationActivity not present")
return false return false
} }
@ -270,7 +234,7 @@ object NativeLibrary {
} }
// Show the AlertDialog on the main thread. // Show the AlertDialog on the main thread.
emulationActivity.runOnUiThread(Runnable { onCoreErrorImpl(title, message) }) emulationActivity.runOnUiThread { onCoreErrorImpl(title, message) }
// Wait for the lock to notify that it is complete. // Wait for the lock to notify that it is complete.
synchronized(coreErrorAlertLock) { coreErrorAlertLock.wait() } synchronized(coreErrorAlertLock) { coreErrorAlertLock.wait() }

View File

@ -80,8 +80,14 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
InputHandler.updateControllerData() InputHandler.updateControllerData()
val playerOne = NativeConfig.getInputSettings(true)[0] val players = NativeConfig.getInputSettings(true)
if (!playerOne.hasMapping() && InputHandler.androidControllers.isNotEmpty()) { var hasConfiguredControllers = false
players.forEach {
if (it.hasMapping()) {
hasConfiguredControllers = true
}
}
if (!hasConfiguredControllers && InputHandler.androidControllers.isNotEmpty()) {
var params: ParamPackage? = null var params: ParamPackage? = null
for (controller in InputHandler.registeredControllers) { for (controller in InputHandler.registeredControllers) {
if (controller.get("port", -1) == 0) { if (controller.get("port", -1) == 0) {

View File

@ -3,15 +3,15 @@
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding
import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.model.Driver import org.yuzu.yuzu_emu.model.Driver
import org.yuzu.yuzu_emu.model.DriverViewModel import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class DriverAdapter(private val driverViewModel: DriverViewModel) : class DriverAdapter(private val driverViewModel: DriverViewModel) :
@ -44,25 +44,15 @@ class DriverAdapter(private val driverViewModel: DriverViewModel) :
} }
// Delay marquee by 3s // Delay marquee by 3s
title.postDelayed( title.marquee()
{ version.marquee()
title.isSelected = true description.marquee()
title.ellipsize = TextUtils.TruncateAt.MARQUEE
version.isSelected = true
version.ellipsize = TextUtils.TruncateAt.MARQUEE
description.isSelected = true
description.ellipsize = TextUtils.TruncateAt.MARQUEE
},
3000
)
title.text = model.title title.text = model.title
version.text = model.version version.text = model.version
description.text = model.description description.text = model.description
if (model.title != binding.root.context.getString(R.string.system_gpu_driver)) { buttonDelete.setVisible(
buttonDelete.visibility = View.VISIBLE model.title != binding.root.context.getString(R.string.system_gpu_driver)
} else { )
buttonDelete.visibility = View.GONE
}
} }
} }
} }

View File

@ -4,7 +4,6 @@
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
import android.net.Uri import android.net.Uri
import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
@ -12,6 +11,7 @@ import org.yuzu.yuzu_emu.databinding.CardFolderBinding
import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment
import org.yuzu.yuzu_emu.model.GameDir import org.yuzu.yuzu_emu.model.GameDir
import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) : class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) :
@ -29,13 +29,7 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie
override fun bind(model: GameDir) { override fun bind(model: GameDir) {
binding.apply { binding.apply {
path.text = Uri.parse(model.uriString).path path.text = Uri.parse(model.uriString).path
path.postDelayed( path.marquee()
{
path.isSelected = true
path.ellipsize = TextUtils.TruncateAt.MARQUEE
},
3000
)
buttonEdit.setOnClickListener { buttonEdit.setOnClickListener {
GameFolderPropertiesDialogFragment.newInstance(model) GameFolderPropertiesDialogFragment.newInstance(model)

View File

@ -4,7 +4,6 @@
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
import android.net.Uri import android.net.Uri
import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
@ -27,6 +26,7 @@ import org.yuzu.yuzu_emu.databinding.CardGameBinding
import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.utils.GameIconUtils import org.yuzu.yuzu_emu.utils.GameIconUtils
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class GameAdapter(private val activity: AppCompatActivity) : class GameAdapter(private val activity: AppCompatActivity) :
@ -44,14 +44,7 @@ class GameAdapter(private val activity: AppCompatActivity) :
binding.textGameTitle.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ") binding.textGameTitle.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ")
binding.textGameTitle.postDelayed( binding.textGameTitle.marquee()
{
binding.textGameTitle.ellipsize = TextUtils.TruncateAt.MARQUEE
binding.textGameTitle.isSelected = true
},
3000
)
binding.cardGame.setOnClickListener { onClick(model) } binding.cardGame.setOnClickListener { onClick(model) }
binding.cardGame.setOnLongClickListener { onLongClick(model) } binding.cardGame.setOnLongClickListener { onLongClick(model) }
} }

View File

@ -3,21 +3,18 @@
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding
import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
import org.yuzu.yuzu_emu.model.GameProperty import org.yuzu.yuzu_emu.model.GameProperty
import org.yuzu.yuzu_emu.model.InstallableProperty import org.yuzu.yuzu_emu.model.InstallableProperty
import org.yuzu.yuzu_emu.model.SubmenuProperty import org.yuzu.yuzu_emu.model.SubmenuProperty
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class GamePropertiesAdapter( class GamePropertiesAdapter(
@ -76,23 +73,15 @@ class GamePropertiesAdapter(
) )
) )
binding.details.postDelayed({ binding.details.marquee()
binding.details.isSelected = true
binding.details.ellipsize = TextUtils.TruncateAt.MARQUEE
}, 3000)
if (submenuProperty.details != null) { if (submenuProperty.details != null) {
binding.details.visibility = View.VISIBLE binding.details.setVisible(true)
binding.details.text = submenuProperty.details.invoke() binding.details.text = submenuProperty.details.invoke()
} else if (submenuProperty.detailsFlow != null) { } else if (submenuProperty.detailsFlow != null) {
binding.details.visibility = View.VISIBLE binding.details.setVisible(true)
viewLifecycle.lifecycleScope.launch { submenuProperty.detailsFlow.collect(viewLifecycle) { binding.details.text = it }
viewLifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
submenuProperty.detailsFlow.collect { binding.details.text = it }
}
}
} else { } else {
binding.details.visibility = View.GONE binding.details.setVisible(false)
} }
} }
} }
@ -112,14 +101,10 @@ class GamePropertiesAdapter(
) )
) )
if (installableProperty.install != null) { binding.buttonInstall.setVisible(installableProperty.install != null)
binding.buttonInstall.visibility = View.VISIBLE binding.buttonInstall.setOnClickListener { installableProperty.install?.invoke() }
binding.buttonInstall.setOnClickListener { installableProperty.install.invoke() } binding.buttonExport.setVisible(installableProperty.export != null)
} binding.buttonExport.setOnClickListener { installableProperty.export?.invoke() }
if (installableProperty.export != null) {
binding.buttonExport.visibility = View.VISIBLE
binding.buttonExport.setOnClickListener { installableProperty.export.invoke() }
}
} }
} }

View File

@ -3,22 +3,19 @@
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.model.HomeSetting import org.yuzu.yuzu_emu.model.HomeSetting
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class HomeSettingAdapter( class HomeSettingAdapter(
@ -59,18 +56,8 @@ class HomeSettingAdapter(
binding.optionIcon.alpha = 0.5f binding.optionIcon.alpha = 0.5f
} }
viewLifecycle.lifecycleScope.launch { model.details.collect(viewLifecycle) { updateOptionDetails(it) }
viewLifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) { binding.optionDetail.marquee()
model.details.collect { updateOptionDetails(it) }
}
}
binding.optionDetail.postDelayed(
{
binding.optionDetail.ellipsize = TextUtils.TruncateAt.MARQUEE
binding.optionDetail.isSelected = true
},
3000
)
binding.root.setOnClickListener { onClick(model) } binding.root.setOnClickListener { onClick(model) }
} }
@ -90,7 +77,7 @@ class HomeSettingAdapter(
private fun updateOptionDetails(detailString: String) { private fun updateOptionDetails(detailString: String) {
if (detailString.isNotEmpty()) { if (detailString.isNotEmpty()) {
binding.optionDetail.text = detailString binding.optionDetail.text = detailString
binding.optionDetail.visibility = View.VISIBLE binding.optionDetail.setVisible(true)
} }
} }
} }

View File

@ -4,10 +4,10 @@
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import org.yuzu.yuzu_emu.databinding.CardInstallableBinding import org.yuzu.yuzu_emu.databinding.CardInstallableBinding
import org.yuzu.yuzu_emu.model.Installable import org.yuzu.yuzu_emu.model.Installable
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class InstallableAdapter(installables: List<Installable>) : class InstallableAdapter(installables: List<Installable>) :
@ -26,14 +26,10 @@ class InstallableAdapter(installables: List<Installable>) :
binding.title.setText(model.titleId) binding.title.setText(model.titleId)
binding.description.setText(model.descriptionId) binding.description.setText(model.descriptionId)
if (model.install != null) { binding.buttonInstall.setVisible(model.install != null)
binding.buttonInstall.visibility = View.VISIBLE binding.buttonInstall.setOnClickListener { model.install?.invoke() }
binding.buttonInstall.setOnClickListener { model.install.invoke() } binding.buttonExport.setVisible(model.export != null)
} binding.buttonExport.setOnClickListener { model.export?.invoke() }
if (model.export != null) {
binding.buttonExport.visibility = View.VISIBLE
binding.buttonExport.setOnClickListener { model.export.invoke() }
}
} }
} }
} }

View File

@ -4,12 +4,12 @@
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment
import org.yuzu.yuzu_emu.model.License import org.yuzu.yuzu_emu.model.License
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<License>) : class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<License>) :
@ -25,7 +25,7 @@ class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<Lic
binding.apply { binding.apply {
textSettingName.text = root.context.getString(model.titleId) textSettingName.text = root.context.getString(model.titleId)
textSettingDescription.text = root.context.getString(model.descriptionId) textSettingDescription.text = root.context.getString(model.descriptionId)
textSettingValue.visibility = View.GONE textSettingValue.setVisible(false)
root.setOnClickListener { onClick(model) } root.setOnClickListener { onClick(model) }
} }

View File

@ -5,7 +5,6 @@ package org.yuzu.yuzu_emu.adapters
import android.text.Html import android.text.Html
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
@ -17,6 +16,7 @@ import org.yuzu.yuzu_emu.model.SetupCallback
import org.yuzu.yuzu_emu.model.SetupPage import org.yuzu.yuzu_emu.model.SetupPage
import org.yuzu.yuzu_emu.model.StepState import org.yuzu.yuzu_emu.model.StepState
import org.yuzu.yuzu_emu.utils.ViewUtils import org.yuzu.yuzu_emu.utils.ViewUtils
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) : class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) :
@ -30,8 +30,8 @@ class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) :
AbstractViewHolder<SetupPage>(binding), SetupCallback { AbstractViewHolder<SetupPage>(binding), SetupCallback {
override fun bind(model: SetupPage) { override fun bind(model: SetupPage) {
if (model.stepCompleted.invoke() == StepState.COMPLETE) { if (model.stepCompleted.invoke() == StepState.COMPLETE) {
binding.buttonAction.visibility = View.INVISIBLE binding.buttonAction.setVisible(visible = false, gone = false)
binding.textConfirmation.visibility = View.VISIBLE binding.textConfirmation.setVisible(true)
} }
binding.icon.setImageDrawable( binding.icon.setImageDrawable(

View File

@ -64,17 +64,17 @@ data class PlayerInput(
fun hasMapping(): Boolean { fun hasMapping(): Boolean {
var hasMapping = false var hasMapping = false
buttons.forEach { buttons.forEach {
if (it != "[empty]") { if (it != "[empty]" && it.isNotEmpty()) {
hasMapping = true hasMapping = true
} }
} }
analogs.forEach { analogs.forEach {
if (it != "[empty]") { if (it != "[empty]" && it.isNotEmpty()) {
hasMapping = true hasMapping = true
} }
} }
motions.forEach { motions.forEach {
if (it != "[empty]") { if (it != "[empty]" && it.isNotEmpty()) {
hasMapping = true hasMapping = true
} }
} }

View File

@ -6,7 +6,8 @@ package org.yuzu.yuzu_emu.features.settings.model
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
enum class StringSetting(override val key: String) : AbstractStringSetting { enum class StringSetting(override val key: String) : AbstractStringSetting {
DRIVER_PATH("driver_path"); DRIVER_PATH("driver_path"),
DEVICE_NAME("device_name");
override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal) override fun getString(needsGlobal: Boolean): String = NativeConfig.getString(key, needsGlobal)

View File

@ -16,6 +16,7 @@ import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.LongSetting import org.yuzu.yuzu_emu.features.settings.model.LongSetting
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
/** /**
@ -75,6 +76,9 @@ abstract class SettingsItem(
get() = NativeLibrary.isRunning() && !setting.global && get() = NativeLibrary.isRunning() && !setting.global &&
!NativeConfig.isPerGameConfigLoaded() !NativeConfig.isPerGameConfigLoaded()
val clearable: Boolean
get() = !setting.global && NativeConfig.isPerGameConfigLoaded()
companion object { companion object {
const val TYPE_HEADER = 0 const val TYPE_HEADER = 0
const val TYPE_SWITCH = 1 const val TYPE_SWITCH = 1
@ -87,6 +91,7 @@ abstract class SettingsItem(
const val TYPE_INPUT = 8 const val TYPE_INPUT = 8
const val TYPE_INT_SINGLE_CHOICE = 9 const val TYPE_INT_SINGLE_CHOICE = 9
const val TYPE_INPUT_PROFILE = 10 const val TYPE_INPUT_PROFILE = 10
const val TYPE_STRING_INPUT = 11
const val FASTMEM_COMBINED = "fastmem_combined" const val FASTMEM_COMBINED = "fastmem_combined"
@ -105,6 +110,7 @@ abstract class SettingsItem(
// List of all general // List of all general
val settingsItems = HashMap<String, SettingsItem>().apply { val settingsItems = HashMap<String, SettingsItem>().apply {
put(StringInputSetting(StringSetting.DEVICE_NAME, titleId = R.string.device_name))
put( put(
SwitchSetting( SwitchSetting(
BooleanSetting.RENDERER_USE_SPEED_LIMIT, BooleanSetting.RENDERER_USE_SPEED_LIMIT,

View File

@ -0,0 +1,22 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.features.settings.model.view
import androidx.annotation.StringRes
import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting
class StringInputSetting(
setting: AbstractStringSetting,
@StringRes titleId: Int = 0,
titleString: String = "",
@StringRes descriptionId: Int = 0,
descriptionString: String = ""
) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) {
override val type = TYPE_STRING_INPUT
fun getSelectedValue(needsGlobal: Boolean = false) = setting.getValueAsString(needsGlobal)
fun setSelectedValue(selection: String) =
(setting as AbstractStringSetting).setString(selection)
}

View File

@ -11,16 +11,13 @@ import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogInputProfilesBinding import org.yuzu.yuzu_emu.databinding.DialogInputProfilesBinding
import org.yuzu.yuzu_emu.features.settings.model.view.InputProfileSetting import org.yuzu.yuzu_emu.features.settings.model.view.InputProfileSetting
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.utils.collect
class InputProfileDialogFragment : DialogFragment() { class InputProfileDialogFragment : DialogFragment() {
private var position = 0 private var position = 0
@ -110,25 +107,21 @@ class InputProfileDialogFragment : DialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch { settingsViewModel.shouldShowDeleteProfileDialog.collect(viewLifecycleOwner) {
repeatOnLifecycle(Lifecycle.State.CREATED) { if (it.isNotEmpty()) {
settingsViewModel.shouldShowDeleteProfileDialog.collect { MessageDialogFragment.newInstance(
if (it.isNotEmpty()) { activity = requireActivity(),
MessageDialogFragment.newInstance( titleId = R.string.delete_input_profile,
activity = requireActivity(), descriptionId = R.string.delete_input_profile_description,
titleId = R.string.delete_input_profile, positiveAction = {
descriptionId = R.string.delete_input_profile_description, setting.deleteProfile(it)
positiveAction = { settingsViewModel.setReloadListAndNotifyDataset(true)
setting.deleteProfile(it) },
settingsViewModel.setReloadListAndNotifyDataset(true) negativeAction = {},
}, negativeButtonTitleId = android.R.string.cancel
negativeAction = {}, ).show(parentFragmentManager, MessageDialogFragment.TAG)
negativeButtonTitleId = android.R.string.cancel settingsViewModel.setShouldShowDeleteProfileDialog("")
).show(parentFragmentManager, MessageDialogFragment.TAG) dismiss()
settingsViewModel.setShouldShowDeleteProfileDialog("")
dismiss()
}
}
} }
} }
} }

View File

@ -13,14 +13,9 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.navArgs import androidx.navigation.navArgs
import com.google.android.material.color.MaterialColors import com.google.android.material.color.MaterialColors
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import java.io.IOException import java.io.IOException
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
@ -70,39 +65,23 @@ class SettingsActivity : AppCompatActivity() {
) )
} }
lifecycleScope.apply { settingsViewModel.shouldRecreate.collect(
launch { this,
repeatOnLifecycle(Lifecycle.State.CREATED) { resetState = { settingsViewModel.setShouldRecreate(false) }
settingsViewModel.shouldRecreate.collectLatest { ) { if (it) recreate() }
if (it) { settingsViewModel.shouldNavigateBack.collect(
settingsViewModel.setShouldRecreate(false) this,
recreate() resetState = { settingsViewModel.setShouldNavigateBack(false) }
} ) { if (it) navigateBack() }
} settingsViewModel.shouldShowResetSettingsDialog.collect(
} this,
} resetState = { settingsViewModel.setShouldShowResetSettingsDialog(false) }
launch { ) {
repeatOnLifecycle(Lifecycle.State.CREATED) { if (it) {
settingsViewModel.shouldNavigateBack.collectLatest { ResetSettingsDialogFragment().show(
if (it) { supportFragmentManager,
settingsViewModel.setShouldNavigateBack(false) ResetSettingsDialogFragment.TAG
navigateBack() )
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.shouldShowResetSettingsDialog.collectLatest {
if (it) {
settingsViewModel.setShouldShowResetSettingsDialog(false)
ResetSettingsDialogFragment().show(
supportFragmentManager,
ResetSettingsDialogFragment.TAG
)
}
}
}
} }
} }

View File

@ -85,6 +85,10 @@ class SettingsAdapter(
InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this) InputProfileViewHolder(ListItemSettingBinding.inflate(inflater), this)
} }
SettingsItem.TYPE_STRING_INPUT -> {
StringInputViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
else -> { else -> {
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this) HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
} }
@ -392,6 +396,15 @@ class SettingsAdapter(
popup.show() popup.show()
} }
fun onStringInputClick(item: StringInputSetting, position: Int) {
SettingsDialogFragment.newInstance(
settingsViewModel,
item,
SettingsItem.TYPE_STRING_INPUT,
position
).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
}
fun onLongClick(item: SettingsItem, position: Int): Boolean { fun onLongClick(item: SettingsItem, position: Int): Boolean {
SettingsDialogFragment.newInstance( SettingsDialogFragment.newInstance(
settingsViewModel, settingsViewModel,

View File

@ -11,13 +11,10 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider import com.google.android.material.slider.Slider
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogEditTextBinding
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
import org.yuzu.yuzu_emu.features.input.NativeInput import org.yuzu.yuzu_emu.features.input.NativeInput
import org.yuzu.yuzu_emu.features.input.model.AnalogDirection import org.yuzu.yuzu_emu.features.input.model.AnalogDirection
@ -27,8 +24,10 @@ import org.yuzu.yuzu_emu.features.settings.model.view.IntSingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
import org.yuzu.yuzu_emu.utils.ParamPackage import org.yuzu.yuzu_emu.utils.ParamPackage
import org.yuzu.yuzu_emu.utils.collect
class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener { class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener {
private var type = 0 private var type = 0
@ -40,6 +39,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
private val settingsViewModel: SettingsViewModel by activityViewModels() private val settingsViewModel: SettingsViewModel by activityViewModels()
private lateinit var sliderBinding: DialogSliderBinding private lateinit var sliderBinding: DialogSliderBinding
private lateinit var stringInputBinding: DialogEditTextBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -134,6 +134,18 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
.create() .create()
} }
SettingsItem.TYPE_STRING_INPUT -> {
stringInputBinding = DialogEditTextBinding.inflate(layoutInflater)
val item = settingsViewModel.clickedItem as StringInputSetting
stringInputBinding.editText.setText(item.getSelectedValue())
MaterialAlertDialogBuilder(requireContext())
.setTitle(item.title)
.setView(stringInputBinding.root)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, defaultCancelListener)
.create()
}
SettingsItem.TYPE_STRING_SINGLE_CHOICE -> { SettingsItem.TYPE_STRING_SINGLE_CHOICE -> {
val item = settingsViewModel.clickedItem as StringSingleChoiceSetting val item = settingsViewModel.clickedItem as StringSingleChoiceSetting
MaterialAlertDialogBuilder(requireContext()) MaterialAlertDialogBuilder(requireContext())
@ -161,6 +173,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
): View? { ): View? {
return when (type) { return when (type) {
SettingsItem.TYPE_SLIDER -> sliderBinding.root SettingsItem.TYPE_SLIDER -> sliderBinding.root
SettingsItem.TYPE_STRING_INPUT -> stringInputBinding.root
else -> super.onCreateView(inflater, container, savedInstanceState) else -> super.onCreateView(inflater, container, savedInstanceState)
} }
} }
@ -169,17 +182,11 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
when (type) { when (type) {
SettingsItem.TYPE_SLIDER -> { SettingsItem.TYPE_SLIDER -> {
viewLifecycleOwner.lifecycleScope.launch { settingsViewModel.sliderTextValue.collect(viewLifecycleOwner) {
repeatOnLifecycle(Lifecycle.State.CREATED) { sliderBinding.textValue.text = it
settingsViewModel.sliderTextValue.collect { }
sliderBinding.textValue.text = it settingsViewModel.sliderProgress.collect(viewLifecycleOwner) {
} sliderBinding.slider.value = it.toFloat()
}
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.sliderProgress.collect {
sliderBinding.slider.value = it.toFloat()
}
}
} }
} }
} }
@ -209,6 +216,13 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
val sliderSetting = settingsViewModel.clickedItem as SliderSetting val sliderSetting = settingsViewModel.clickedItem as SliderSetting
sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value) sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value)
} }
is StringInputSetting -> {
val stringInputSetting = settingsViewModel.clickedItem as StringInputSetting
stringInputSetting.setSelectedValue(
(stringInputBinding.editText.text ?: "").toString()
)
}
} }
closeDialog() closeDialog()
} }

View File

@ -13,21 +13,17 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.transition.MaterialSharedAxis import com.google.android.material.transition.MaterialSharedAxis
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding
import org.yuzu.yuzu_emu.features.input.NativeInput import org.yuzu.yuzu_emu.features.input.NativeInput
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
class SettingsFragment : Fragment() { class SettingsFragment : Fragment() {
private lateinit var presenter: SettingsFragmentPresenter private lateinit var presenter: SettingsFragmentPresenter
@ -63,8 +59,7 @@ class SettingsFragment : Fragment() {
return binding.root return binding.root
} }
// This is using the correct scope, lint is just acting up @SuppressLint("NotifyDataSetChanged")
@SuppressLint("UnsafeRepeatOnLifecycleDetector", "NotifyDataSetChanged")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
settingsAdapter = SettingsAdapter(this, requireContext()) settingsAdapter = SettingsAdapter(this, requireContext())
@ -100,65 +95,37 @@ class SettingsFragment : Fragment() {
settingsViewModel.setShouldNavigateBack(true) settingsViewModel.setShouldNavigateBack(true)
} }
viewLifecycleOwner.lifecycleScope.apply { settingsViewModel.shouldReloadSettingsList.collect(
launch { viewLifecycleOwner,
repeatOnLifecycle(Lifecycle.State.CREATED) { resetState = { settingsViewModel.setShouldReloadSettingsList(false) }
settingsViewModel.shouldReloadSettingsList.collectLatest { ) { if (it) presenter.loadSettingsList() }
if (it) { settingsViewModel.adapterItemChanged.collect(
settingsViewModel.setShouldReloadSettingsList(false) viewLifecycleOwner,
presenter.loadSettingsList() resetState = { settingsViewModel.setAdapterItemChanged(-1) }
} ) { if (it != -1) settingsAdapter?.notifyItemChanged(it) }
} settingsViewModel.datasetChanged.collect(
} viewLifecycleOwner,
} resetState = { settingsViewModel.setDatasetChanged(false) }
launch { ) { if (it) settingsAdapter?.notifyDataSetChanged() }
repeatOnLifecycle(Lifecycle.State.STARTED) { settingsViewModel.reloadListAndNotifyDataset.collect(
settingsViewModel.adapterItemChanged.collect { viewLifecycleOwner,
if (it != -1) { resetState = { settingsViewModel.setReloadListAndNotifyDataset(false) }
settingsAdapter?.notifyItemChanged(it) ) { if (it) presenter.loadSettingsList(true) }
settingsViewModel.setAdapterItemChanged(-1) settingsViewModel.shouldShowResetInputDialog.collect(
} viewLifecycleOwner,
} resetState = { settingsViewModel.setShouldShowResetInputDialog(false) }
} ) {
} if (it) {
launch { MessageDialogFragment.newInstance(
repeatOnLifecycle(Lifecycle.State.STARTED) { activity = requireActivity(),
settingsViewModel.datasetChanged.collect { titleId = R.string.reset_mapping,
if (it) { descriptionId = R.string.reset_mapping_description,
settingsAdapter?.notifyDataSetChanged() positiveAction = {
settingsViewModel.setDatasetChanged(false) NativeInput.resetControllerMappings(getPlayerIndex())
} settingsViewModel.setReloadListAndNotifyDataset(true)
} },
} negativeAction = {}
} ).show(parentFragmentManager, MessageDialogFragment.TAG)
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.reloadListAndNotifyDataset.collectLatest {
if (it) {
settingsViewModel.setReloadListAndNotifyDataset(false)
presenter.loadSettingsList(true)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
settingsViewModel.shouldShowResetInputDialog.collectLatest {
if (it) {
MessageDialogFragment.newInstance(
activity = requireActivity(),
titleId = R.string.reset_mapping,
descriptionId = R.string.reset_mapping_description,
positiveAction = {
NativeInput.resetControllerMappings(getPlayerIndex())
settingsViewModel.setReloadListAndNotifyDataset(true)
},
negativeAction = {}
).show(parentFragmentManager, MessageDialogFragment.TAG)
settingsViewModel.setShouldShowResetInputDialog(false)
}
}
}
} }
} }

View File

@ -23,6 +23,7 @@ import org.yuzu.yuzu_emu.features.settings.model.LongSetting
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.features.settings.model.view.* import org.yuzu.yuzu_emu.features.settings.model.view.*
import org.yuzu.yuzu_emu.utils.InputHandler import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
@ -153,6 +154,7 @@ class SettingsFragmentPresenter(
private fun addSystemSettings(sl: ArrayList<SettingsItem>) { private fun addSystemSettings(sl: ArrayList<SettingsItem>) {
sl.apply { sl.apply {
add(StringSetting.DEVICE_NAME.key)
add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key) add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
add(ShortSetting.RENDERER_SPEED_LIMIT.key) add(ShortSetting.RENDERER_SPEED_LIMIT.key)
add(BooleanSetting.USE_DOCKED_MODE.key) add(BooleanSetting.USE_DOCKED_MODE.key)
@ -778,7 +780,7 @@ class SettingsFragmentPresenter(
playerIndex: Int, playerIndex: Int,
paramName: String, paramName: String,
stick: NativeAnalog, stick: NativeAnalog,
defaultValue: Int defaultValue: Float
): AbstractIntSetting = ): AbstractIntSetting =
object : AbstractIntSetting { object : AbstractIntSetting {
val params get() = NativeInput.getStickParam(playerIndex, stick) val params get() = NativeInput.getStickParam(playerIndex, stick)
@ -786,7 +788,7 @@ class SettingsFragmentPresenter(
override val key = "" override val key = ""
override fun getInt(needsGlobal: Boolean): Int = override fun getInt(needsGlobal: Boolean): Int =
(params.get(paramName, 0.15f) * 100).toInt() (params.get(paramName, defaultValue) * 100).toInt()
override fun setInt(value: Int) { override fun setInt(value: Int) {
val tempParams = params val tempParams = params
@ -794,12 +796,12 @@ class SettingsFragmentPresenter(
NativeInput.setStickParam(playerIndex, stick, tempParams) NativeInput.setStickParam(playerIndex, stick, tempParams)
} }
override val defaultValue = defaultValue override val defaultValue = (defaultValue * 100).toInt()
override fun getValueAsString(needsGlobal: Boolean): String = override fun getValueAsString(needsGlobal: Boolean): String =
getInt(needsGlobal).toString() getInt(needsGlobal).toString()
override fun reset() = setInt(defaultValue) override fun reset() = setInt(this.defaultValue)
} }
private fun getExtraStickSettings( private fun getExtraStickSettings(
@ -809,11 +811,11 @@ class SettingsFragmentPresenter(
val stickIsController = val stickIsController =
NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog)) NativeInput.isController(NativeInput.getStickParam(playerIndex, nativeAnalog))
val modifierRangeSetting = val modifierRangeSetting =
getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 50) getStickIntSettingFromParam(playerIndex, "modifier_scale", nativeAnalog, 0.5f)
val stickRangeSetting = val stickRangeSetting =
getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 95) getStickIntSettingFromParam(playerIndex, "range", nativeAnalog, 0.95f)
val stickDeadzoneSetting = val stickDeadzoneSetting =
getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 15) getStickIntSettingFromParam(playerIndex, "deadzone", nativeAnalog, 0.15f)
val out = mutableListOf<SettingsItem>().apply { val out = mutableListOf<SettingsItem>().apply {
if (stickIsController) { if (stickIsController) {

View File

@ -15,19 +15,17 @@ import androidx.core.view.updatePadding
import androidx.core.widget.doOnTextChanged import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.divider.MaterialDividerItemDecoration import com.google.android.material.divider.MaterialDividerItemDecoration
import com.google.android.material.transition.MaterialSharedAxis import com.google.android.material.transition.MaterialSharedAxis
import info.debatty.java.stringsimilarity.Cosine import info.debatty.java.stringsimilarity.Cosine
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.FragmentSettingsSearchBinding import org.yuzu.yuzu_emu.databinding.FragmentSettingsSearchBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
class SettingsSearchFragment : Fragment() { class SettingsSearchFragment : Fragment() {
private var _binding: FragmentSettingsSearchBinding? = null private var _binding: FragmentSettingsSearchBinding? = null
@ -83,14 +81,10 @@ class SettingsSearchFragment : Fragment() {
search() search()
binding.settingsList.smoothScrollToPosition(0) binding.settingsList.smoothScrollToPosition(0)
} }
viewLifecycleOwner.lifecycleScope.launch { settingsViewModel.shouldReloadSettingsList.collect(viewLifecycleOwner) {
repeatOnLifecycle(Lifecycle.State.CREATED) { if (it) {
settingsViewModel.shouldReloadSettingsList.collect { settingsViewModel.setShouldReloadSettingsList(false)
if (it) { search()
settingsViewModel.setShouldReloadSettingsList(false)
search()
}
}
} }
} }
@ -106,10 +100,9 @@ class SettingsSearchFragment : Fragment() {
private fun search() { private fun search() {
val searchTerm = binding.searchText.text.toString().lowercase() val searchTerm = binding.searchText.text.toString().lowercase()
binding.clearButton.visibility = binding.clearButton.setVisible(visible = searchTerm.isNotEmpty(), gone = false)
if (searchTerm.isEmpty()) View.INVISIBLE else View.VISIBLE
if (searchTerm.isEmpty()) { if (searchTerm.isEmpty()) {
binding.noResultsView.visibility = View.VISIBLE binding.noResultsView.setVisible(visible = false, gone = false)
settingsAdapter?.submitList(emptyList()) settingsAdapter?.submitList(emptyList())
return return
} }
@ -136,8 +129,7 @@ class SettingsSearchFragment : Fragment() {
optionalSetting optionalSetting
} }
settingsAdapter?.submitList(sortedList) settingsAdapter?.submitList(sortedList)
binding.noResultsView.visibility = binding.noResultsView.setVisible(visible = sortedList.isEmpty(), gone = false)
if (sortedList.isEmpty()) View.VISIBLE else View.INVISIBLE
} }
private fun focusSearch() { private fun focusSearch() {

View File

@ -13,7 +13,7 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -22,27 +22,16 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
setting = item as DateTimeSetting setting = item as DateTimeSetting
binding.textSettingName.text = item.title binding.textSettingName.text = item.title
if (setting.description.isNotEmpty()) { binding.textSettingDescription.setVisible(item.description.isNotEmpty())
binding.textSettingDescription.text = item.description binding.textSettingDescription.text = item.description
binding.textSettingDescription.visibility = View.VISIBLE binding.textSettingValue.setVisible(true)
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.VISIBLE
val epochTime = setting.getValue() val epochTime = setting.getValue()
val instant = Instant.ofEpochMilli(epochTime * 1000) val instant = Instant.ofEpochMilli(epochTime * 1000)
val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC")) val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC"))
val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
binding.textSettingValue.text = dateFormatter.format(zonedTime) binding.textSettingValue.text = dateFormatter.format(zonedTime)
binding.buttonClear.visibility = if (setting.setting.global || binding.buttonClear.setVisible(setting.clearable)
!NativeConfig.isPerGameConfigLoaded()
) {
View.GONE
} else {
View.VISIBLE
}
binding.buttonClear.setOnClickListener { binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition) adapter.onClearClick(setting, bindingAdapterPosition)
} }

View File

@ -9,6 +9,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.InputProfileSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class InputProfileViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : class InputProfileViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -20,10 +21,10 @@ class InputProfileViewHolder(val binding: ListItemSettingBinding, adapter: Setti
binding.textSettingValue.text = binding.textSettingValue.text =
setting.getCurrentProfile().ifEmpty { binding.root.context.getString(R.string.not_set) } setting.getCurrentProfile().ifEmpty { binding.root.context.getString(R.string.not_set) }
binding.textSettingDescription.visibility = View.GONE binding.textSettingDescription.setVisible(false)
binding.buttonClear.visibility = View.GONE binding.buttonClear.setVisible(false)
binding.icon.visibility = View.GONE binding.icon.setVisible(false)
binding.buttonClear.visibility = View.GONE binding.buttonClear.setVisible(false)
} }
override fun onClick(clicked: View) = override fun onClick(clicked: View) =

View File

@ -12,6 +12,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.InputSetting
import org.yuzu.yuzu_emu.features.settings.model.view.ModifierInputSetting import org.yuzu.yuzu_emu.features.settings.model.view.ModifierInputSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class InputViewHolder(val binding: ListItemSettingInputBinding, adapter: SettingsAdapter) : class InputViewHolder(val binding: ListItemSettingInputBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -22,38 +23,26 @@ class InputViewHolder(val binding: ListItemSettingInputBinding, adapter: Setting
binding.textSettingName.text = setting.title binding.textSettingName.text = setting.title
binding.textSettingValue.text = setting.getSelectedValue() binding.textSettingValue.text = setting.getSelectedValue()
binding.buttonOptions.visibility = when (item) { when (item) {
is AnalogInputSetting -> { is AnalogInputSetting -> {
val param = NativeInput.getStickParam(item.playerIndex, item.nativeAnalog) val param = NativeInput.getStickParam(item.playerIndex, item.nativeAnalog)
if ( binding.buttonOptions.setVisible(
param.get("engine", "") == "analog_from_button" || param.get("engine", "") == "analog_from_button" ||
param.has("axis_x") || param.has("axis_y") param.has("axis_x") || param.has("axis_y")
) { )
View.VISIBLE
} else {
View.GONE
}
} }
is ButtonInputSetting -> { is ButtonInputSetting -> {
val param = NativeInput.getButtonParam(item.playerIndex, item.nativeButton) val param = NativeInput.getButtonParam(item.playerIndex, item.nativeButton)
if ( binding.buttonOptions.setVisible(
param.has("code") || param.has("button") || param.has("hat") || param.has("code") || param.has("button") || param.has("hat") ||
param.has("axis") param.has("axis")
) { )
View.VISIBLE
} else {
View.GONE
}
} }
is ModifierInputSetting -> { is ModifierInputSetting -> {
val params = NativeInput.getStickParam(item.playerIndex, item.nativeAnalog) val params = NativeInput.getStickParam(item.playerIndex, item.nativeAnalog)
if (params.has("modifier")) { binding.buttonOptions.setVisible(params.has("modifier"))
View.VISIBLE
} else {
View.GONE
}
} }
} }

View File

@ -9,6 +9,7 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.RunnableSetting import org.yuzu.yuzu_emu.features.settings.model.view.RunnableSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -16,8 +17,8 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
setting = item as RunnableSetting setting = item as RunnableSetting
binding.icon.setVisible(setting.iconId != 0)
if (setting.iconId != 0) { if (setting.iconId != 0) {
binding.icon.visibility = View.VISIBLE
binding.icon.setImageDrawable( binding.icon.setImageDrawable(
ResourcesCompat.getDrawable( ResourcesCompat.getDrawable(
binding.icon.resources, binding.icon.resources,
@ -25,19 +26,13 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
binding.icon.context.theme binding.icon.context.theme
) )
) )
} else {
binding.icon.visibility = View.GONE
} }
binding.textSettingName.text = setting.title binding.textSettingName.text = setting.title
if (setting.description.isNotEmpty()) { binding.textSettingDescription.setVisible(setting.description.isNotEmpty())
binding.textSettingDescription.setText(item.descriptionId) binding.textSettingDescription.text = item.description
binding.textSettingDescription.visibility = View.VISIBLE binding.textSettingValue.setVisible(false)
} else { binding.buttonClear.setVisible(false)
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.GONE
binding.buttonClear.visibility = View.GONE
setStyle(setting.isEditable, binding) setStyle(setting.isEditable, binding)
} }

View File

@ -10,7 +10,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -19,14 +19,10 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
setting = item setting = item
binding.textSettingName.text = setting.title binding.textSettingName.text = setting.title
if (item.description.isNotEmpty()) { binding.textSettingDescription.setVisible(item.description.isNotEmpty())
binding.textSettingDescription.text = item.description binding.textSettingDescription.text = item.description
binding.textSettingDescription.visibility = View.VISIBLE
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.VISIBLE binding.textSettingValue.setVisible(true)
when (item) { when (item) {
is SingleChoiceSetting -> { is SingleChoiceSetting -> {
val resMgr = binding.textSettingValue.context.resources val resMgr = binding.textSettingValue.context.resources
@ -48,16 +44,10 @@ class SingleChoiceViewHolder(val binding: ListItemSettingBinding, adapter: Setti
} }
} }
if (binding.textSettingValue.text.isEmpty()) { if (binding.textSettingValue.text.isEmpty()) {
binding.textSettingValue.visibility = View.GONE binding.textSettingValue.setVisible(false)
} }
binding.buttonClear.visibility = if (setting.setting.global || binding.buttonClear.setVisible(setting.clearable)
!NativeConfig.isPerGameConfigLoaded()
) {
View.GONE
} else {
View.VISIBLE
}
binding.buttonClear.setOnClickListener { binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition) adapter.onClearClick(setting, bindingAdapterPosition)
} }

View File

@ -9,7 +9,7 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -18,26 +18,16 @@ class SliderViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAda
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
setting = item as SliderSetting setting = item as SliderSetting
binding.textSettingName.text = setting.title binding.textSettingName.text = setting.title
if (item.description.isNotEmpty()) { binding.textSettingDescription.setVisible(item.description.isNotEmpty())
binding.textSettingDescription.text = setting.description binding.textSettingDescription.text = setting.description
binding.textSettingDescription.visibility = View.VISIBLE binding.textSettingValue.setVisible(true)
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.VISIBLE
binding.textSettingValue.text = String.format( binding.textSettingValue.text = String.format(
binding.textSettingValue.context.getString(R.string.value_with_units), binding.textSettingValue.context.getString(R.string.value_with_units),
setting.getSelectedValue(), setting.getSelectedValue(),
setting.units setting.units
) )
binding.buttonClear.visibility = if (setting.setting.global || binding.buttonClear.setVisible(setting.clearable)
!NativeConfig.isPerGameConfigLoaded()
) {
View.GONE
} else {
View.VISIBLE
}
binding.buttonClear.setOnClickListener { binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition) adapter.onClearClick(setting, bindingAdapterPosition)
} }

View File

@ -0,0 +1,45 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class StringInputViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
private lateinit var setting: StringInputSetting
override fun bind(item: SettingsItem) {
setting = item as StringInputSetting
binding.textSettingName.text = setting.title
binding.textSettingDescription.setVisible(setting.description.isNotEmpty())
binding.textSettingDescription.text = setting.description
binding.textSettingValue.setVisible(true)
binding.textSettingValue.text = setting.getSelectedValue()
binding.buttonClear.setVisible(setting.clearable)
binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition)
}
setStyle(setting.isEditable, binding)
}
override fun onClick(clicked: View) {
if (setting.isEditable) {
adapter.onStringInputClick(setting, bindingAdapterPosition)
}
}
override fun onLongClick(clicked: View): Boolean {
if (setting.isEditable) {
return adapter.onLongClick(setting, bindingAdapterPosition)
}
return false
}
}

View File

@ -9,6 +9,7 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -16,8 +17,8 @@ class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAd
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
setting = item as SubmenuSetting setting = item as SubmenuSetting
binding.icon.setVisible(setting.iconId != 0)
if (setting.iconId != 0) { if (setting.iconId != 0) {
binding.icon.visibility = View.VISIBLE
binding.icon.setImageDrawable( binding.icon.setImageDrawable(
ResourcesCompat.getDrawable( ResourcesCompat.getDrawable(
binding.icon.resources, binding.icon.resources,
@ -25,19 +26,13 @@ class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAd
binding.icon.context.theme binding.icon.context.theme
) )
) )
} else {
binding.icon.visibility = View.GONE
} }
binding.textSettingName.text = setting.title binding.textSettingName.text = setting.title
if (setting.description.isNotEmpty()) { binding.textSettingDescription.setVisible(setting.description.isNotEmpty())
binding.textSettingDescription.text = setting.description binding.textSettingDescription.text = setting.description
binding.textSettingDescription.visibility = View.VISIBLE binding.textSettingValue.setVisible(false)
} else { binding.buttonClear.setVisible(false)
binding.textSettingDescription.visibility = View.GONE
}
binding.textSettingValue.visibility = View.GONE
binding.buttonClear.visibility = View.GONE
} }
override fun onClick(clicked: View) { override fun onClick(clicked: View) {

View File

@ -9,7 +9,7 @@ import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) : class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) { SettingViewHolder(binding.root, adapter) {
@ -19,12 +19,8 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
setting = item as SwitchSetting setting = item as SwitchSetting
binding.textSettingName.text = setting.title binding.textSettingName.text = setting.title
if (setting.description.isNotEmpty()) { binding.textSettingDescription.setVisible(setting.description.isNotEmpty())
binding.textSettingDescription.text = setting.description binding.textSettingDescription.text = setting.description
binding.textSettingDescription.visibility = View.VISIBLE
} else {
binding.textSettingDescription.visibility = View.GONE
}
binding.switchWidget.setOnCheckedChangeListener(null) binding.switchWidget.setOnCheckedChangeListener(null)
binding.switchWidget.isChecked = setting.getIsChecked(setting.needsRuntimeGlobal) binding.switchWidget.isChecked = setting.getIsChecked(setting.needsRuntimeGlobal)
@ -32,13 +28,7 @@ class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter
adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition) adapter.onBooleanClick(setting, binding.switchWidget.isChecked, bindingAdapterPosition)
} }
binding.buttonClear.visibility = if (setting.setting.global || binding.buttonClear.setVisible(setting.clearable)
!NativeConfig.isPerGameConfigLoaded()
) {
View.GONE
} else {
View.VISIBLE
}
binding.buttonClear.setOnClickListener { binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition) adapter.onClearClick(setting, bindingAdapterPosition)
} }

View File

@ -3,7 +3,6 @@
package org.yuzu.yuzu_emu.fragments package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
@ -16,9 +15,6 @@ import androidx.core.view.updatePadding
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@ -32,6 +28,7 @@ import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.AddonUtil import org.yuzu.yuzu_emu.utils.AddonUtil
import org.yuzu.yuzu_emu.utils.FileUtil.copyFilesTo import org.yuzu.yuzu_emu.utils.FileUtil.copyFilesTo
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
import java.io.File import java.io.File
class AddonsFragment : Fragment() { class AddonsFragment : Fragment() {
@ -60,8 +57,6 @@ class AddonsFragment : Fragment() {
return binding.root return binding.root
} }
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = false, animated = false) homeViewModel.setNavigationVisibility(visible = false, animated = false)
@ -78,57 +73,41 @@ class AddonsFragment : Fragment() {
adapter = AddonAdapter(addonViewModel) adapter = AddonAdapter(addonViewModel)
} }
viewLifecycleOwner.lifecycleScope.apply { addonViewModel.addonList.collect(viewLifecycleOwner) {
launch { (binding.listAddons.adapter as AddonAdapter).submitList(it)
repeatOnLifecycle(Lifecycle.State.STARTED) { }
addonViewModel.addonList.collect { addonViewModel.showModInstallPicker.collect(
(binding.listAddons.adapter as AddonAdapter).submitList(it) viewLifecycleOwner,
} resetState = { addonViewModel.showModInstallPicker(false) }
} ) { if (it) installAddon.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) }
addonViewModel.showModNoticeDialog.collect(
viewLifecycleOwner,
resetState = { addonViewModel.showModNoticeDialog(false) }
) {
if (it) {
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.addon_notice,
descriptionId = R.string.addon_notice_description,
dismissible = false,
positiveAction = { addonViewModel.showModInstallPicker(true) },
negativeAction = {},
negativeButtonTitleId = R.string.close
).show(parentFragmentManager, MessageDialogFragment.TAG)
} }
launch { }
repeatOnLifecycle(Lifecycle.State.STARTED) { addonViewModel.addonToDelete.collect(
addonViewModel.showModInstallPicker.collect { viewLifecycleOwner,
if (it) { resetState = { addonViewModel.setAddonToDelete(null) }
installAddon.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) ) {
addonViewModel.showModInstallPicker(false) if (it != null) {
} MessageDialogFragment.newInstance(
} requireActivity(),
} titleId = R.string.confirm_uninstall,
} descriptionId = R.string.confirm_uninstall_description,
launch { positiveAction = { addonViewModel.onDeleteAddon(it) },
repeatOnLifecycle(Lifecycle.State.STARTED) { negativeAction = {}
addonViewModel.showModNoticeDialog.collect { ).show(parentFragmentManager, MessageDialogFragment.TAG)
if (it) {
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.addon_notice,
descriptionId = R.string.addon_notice_description,
dismissible = false,
positiveAction = { addonViewModel.showModInstallPicker(true) },
negativeAction = {},
negativeButtonTitleId = R.string.close
).show(parentFragmentManager, MessageDialogFragment.TAG)
addonViewModel.showModNoticeDialog(false)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
addonViewModel.addonToDelete.collect {
if (it != null) {
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.confirm_uninstall,
descriptionId = R.string.confirm_uninstall_description,
positiveAction = { addonViewModel.onDeleteAddon(it) },
negativeAction = {}
).show(parentFragmentManager, MessageDialogFragment.TAG)
addonViewModel.setAddonToDelete(null)
}
}
}
} }
} }

View File

@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.fragments
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
class CoreErrorDialogFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
MaterialAlertDialogBuilder(requireActivity())
.setTitle(requireArguments().getString(TITLE))
.setMessage(requireArguments().getString(MESSAGE))
.setPositiveButton(R.string.continue_button, null)
.setNegativeButton(R.string.abort_button) { _: DialogInterface?, _: Int ->
NativeLibrary.coreErrorAlertResult = false
synchronized(NativeLibrary.coreErrorAlertLock) {
NativeLibrary.coreErrorAlertLock.notify()
}
}
.create()
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
NativeLibrary.coreErrorAlertResult = true
synchronized(NativeLibrary.coreErrorAlertLock) { NativeLibrary.coreErrorAlertLock.notify() }
}
companion object {
const val TITLE = "Title"
const val MESSAGE = "Message"
fun newInstance(title: String, message: String): CoreErrorDialogFragment {
val frag = CoreErrorDialogFragment()
val args = Bundle()
args.putString(TITLE, title)
args.putString(MESSAGE, message)
frag.arguments = args
return frag
}
}
}

View File

@ -3,7 +3,6 @@
package org.yuzu.yuzu_emu.fragments package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -14,9 +13,6 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
@ -35,6 +31,7 @@ import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
@ -63,8 +60,6 @@ class DriverManagerFragment : Fragment() {
return binding.root return binding.root
} }
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = false, animated = true) homeViewModel.setNavigationVisibility(visible = false, animated = true)
@ -89,15 +84,8 @@ class DriverManagerFragment : Fragment() {
} }
} }
viewLifecycleOwner.lifecycleScope.apply { driverViewModel.showClearButton.collect(viewLifecycleOwner) {
launch { binding.toolbarDrivers.menu.findItem(R.id.menu_driver_use_global).isVisible = it
repeatOnLifecycle(Lifecycle.State.STARTED) {
driverViewModel.showClearButton.collect {
binding.toolbarDrivers.menu
.findItem(R.id.menu_driver_use_global).isVisible = it
}
}
}
} }
} }

View File

@ -10,14 +10,11 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
import org.yuzu.yuzu_emu.model.DriverViewModel import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.utils.collect
class DriversLoadingDialogFragment : DialogFragment() { class DriversLoadingDialogFragment : DialogFragment() {
private val driverViewModel: DriverViewModel by activityViewModels() private val driverViewModel: DriverViewModel by activityViewModels()
@ -44,13 +41,7 @@ class DriversLoadingDialogFragment : DialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.apply { driverViewModel.isInteractionAllowed.collect(viewLifecycleOwner) { if (it) dismiss() }
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
driverViewModel.isInteractionAllowed.collect { if (it) dismiss() }
}
}
}
} }
companion object { companion object {

View File

@ -32,9 +32,6 @@ import androidx.drawerlayout.widget.DrawerLayout
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import androidx.window.layout.FoldingFeature import androidx.window.layout.FoldingFeature
@ -42,9 +39,6 @@ import androidx.window.layout.WindowInfoTracker
import androidx.window.layout.WindowLayoutInfo import androidx.window.layout.WindowLayoutInfo
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider import com.google.android.material.slider.Slider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
@ -63,6 +57,7 @@ import org.yuzu.yuzu_emu.model.EmulationViewModel
import org.yuzu.yuzu_emu.overlay.model.OverlayControl import org.yuzu.yuzu_emu.overlay.model.OverlayControl
import org.yuzu.yuzu_emu.overlay.model.OverlayLayout import org.yuzu.yuzu_emu.overlay.model.OverlayLayout
import org.yuzu.yuzu_emu.utils.* import org.yuzu.yuzu_emu.utils.*
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import java.lang.NullPointerException import java.lang.NullPointerException
class EmulationFragment : Fragment(), SurfaceHolder.Callback { class EmulationFragment : Fragment(), SurfaceHolder.Callback {
@ -90,14 +85,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
if (context is EmulationActivity) { if (context is EmulationActivity) {
emulationActivity = context emulationActivity = context
NativeLibrary.setEmulationActivity(context) NativeLibrary.setEmulationActivity(context)
lifecycleScope.launch(Dispatchers.Main) {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
WindowInfoTracker.getOrCreate(context)
.windowLayoutInfo(context)
.collect { updateFoldableLayout(context, it) }
}
}
} else { } else {
throw IllegalStateException("EmulationFragment must have EmulationActivity parent") throw IllegalStateException("EmulationFragment must have EmulationActivity parent")
} }
@ -168,8 +155,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
return binding.root return binding.root
} }
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
if (requireActivity().isFinishing) { if (requireActivity().isFinishing) {
@ -350,129 +335,86 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.loadingTitle.isSelected = true binding.loadingTitle.isSelected = true
binding.loadingText.isSelected = true binding.loadingText.isSelected = true
viewLifecycleOwner.lifecycleScope.apply { WindowInfoTracker.getOrCreate(requireContext())
launch { .windowLayoutInfo(requireActivity()).collect(viewLifecycleOwner) {
repeatOnLifecycle(Lifecycle.State.STARTED) { updateFoldableLayout(requireActivity() as EmulationActivity, it)
WindowInfoTracker.getOrCreate(requireContext())
.windowLayoutInfo(requireActivity())
.collect {
updateFoldableLayout(requireActivity() as EmulationActivity, it)
}
}
} }
launch { emulationViewModel.shaderProgress.collect(viewLifecycleOwner) {
repeatOnLifecycle(Lifecycle.State.CREATED) { if (it > 0 && it != emulationViewModel.totalShaders.value) {
emulationViewModel.shaderProgress.collectLatest { binding.loadingProgressIndicator.isIndeterminate = false
if (it > 0 && it != emulationViewModel.totalShaders.value) {
binding.loadingProgressIndicator.isIndeterminate = false
if (it < binding.loadingProgressIndicator.max) { if (it < binding.loadingProgressIndicator.max) {
binding.loadingProgressIndicator.progress = it binding.loadingProgressIndicator.progress = it
} }
} }
if (it == emulationViewModel.totalShaders.value) { if (it == emulationViewModel.totalShaders.value) {
binding.loadingText.setText(R.string.loading) binding.loadingText.setText(R.string.loading)
binding.loadingProgressIndicator.isIndeterminate = true binding.loadingProgressIndicator.isIndeterminate = true
}
}
}
} }
launch { }
repeatOnLifecycle(Lifecycle.State.CREATED) { emulationViewModel.totalShaders.collect(viewLifecycleOwner) {
emulationViewModel.totalShaders.collectLatest { binding.loadingProgressIndicator.max = it
binding.loadingProgressIndicator.max = it }
} emulationViewModel.shaderMessage.collect(viewLifecycleOwner) {
} if (it.isNotEmpty()) {
binding.loadingText.text = it
} }
launch { }
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.shaderMessage.collectLatest {
if (it.isNotEmpty()) {
binding.loadingText.text = it
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
driverViewModel.isInteractionAllowed.collect {
if (it) {
startEmulation()
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
emulationViewModel.emulationStarted.collectLatest {
if (it) {
binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt())
ViewUtils.showView(binding.surfaceInputOverlay)
ViewUtils.hideView(binding.loadingIndicator)
emulationState.updateSurface() emulationViewModel.emulationStarted.collect(viewLifecycleOwner) {
if (it) {
binding.drawerLayout.setDrawerLockMode(IntSetting.LOCK_DRAWER.getInt())
ViewUtils.showView(binding.surfaceInputOverlay)
ViewUtils.hideView(binding.loadingIndicator)
// Setup overlays emulationState.updateSurface()
updateShowFpsOverlay()
updateThermalOverlay() // Setup overlays
} updateShowFpsOverlay()
} updateThermalOverlay()
}
} }
launch { }
repeatOnLifecycle(Lifecycle.State.CREATED) { emulationViewModel.isEmulationStopping.collect(viewLifecycleOwner) {
emulationViewModel.isEmulationStopping.collectLatest { if (it) {
if (it) { binding.loadingText.setText(R.string.shutting_down)
binding.loadingText.setText(R.string.shutting_down) ViewUtils.showView(binding.loadingIndicator)
ViewUtils.showView(binding.loadingIndicator) ViewUtils.hideView(binding.inputContainer)
ViewUtils.hideView(binding.inputContainer) ViewUtils.hideView(binding.showFpsText)
ViewUtils.hideView(binding.showFpsText)
}
}
}
} }
launch { }
repeatOnLifecycle(Lifecycle.State.CREATED) { emulationViewModel.drawerOpen.collect(viewLifecycleOwner) {
emulationViewModel.drawerOpen.collect { if (it) {
if (it) { binding.drawerLayout.open()
binding.drawerLayout.open() binding.inGameMenu.requestFocus()
binding.inGameMenu.requestFocus() } else {
} else { binding.drawerLayout.close()
binding.drawerLayout.close()
}
}
}
} }
launch { }
repeatOnLifecycle(Lifecycle.State.CREATED) { emulationViewModel.programChanged.collect(viewLifecycleOwner) {
emulationViewModel.programChanged.collect { if (it != 0) {
if (it != 0) { emulationViewModel.setEmulationStarted(false)
emulationViewModel.setEmulationStarted(false) binding.drawerLayout.close()
binding.drawerLayout.close() binding.drawerLayout
binding.drawerLayout .setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED) ViewUtils.hideView(binding.surfaceInputOverlay)
ViewUtils.hideView(binding.surfaceInputOverlay) ViewUtils.showView(binding.loadingIndicator)
ViewUtils.showView(binding.loadingIndicator)
}
}
}
} }
launch { }
repeatOnLifecycle(Lifecycle.State.CREATED) { emulationViewModel.emulationStopped.collect(viewLifecycleOwner) {
emulationViewModel.emulationStopped.collect { if (it && emulationViewModel.programChanged.value != -1) {
if (it && emulationViewModel.programChanged.value != -1) { if (perfStatsUpdater != null) {
if (perfStatsUpdater != null) { perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
}
emulationState.changeProgram(emulationViewModel.programChanged.value)
emulationViewModel.setProgramChanged(-1)
emulationViewModel.setEmulationStopped(false)
}
}
} }
emulationState.changeProgram(emulationViewModel.programChanged.value)
emulationViewModel.setProgramChanged(-1)
emulationViewModel.setEmulationStopped(false)
} }
} }
driverViewModel.isInteractionAllowed.collect(viewLifecycleOwner) {
if (it) startEmulation()
}
} }
private fun startEmulation(programIndex: Int = 0) { private fun startEmulation(programIndex: Int = 0) {
@ -500,14 +442,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
binding.drawerLayout.close() binding.drawerLayout.close()
} }
if (showInputOverlay) { if (showInputOverlay) {
binding.surfaceInputOverlay.visibility = View.INVISIBLE binding.surfaceInputOverlay.setVisible(visible = false, gone = false)
} }
} else { } else {
if (showInputOverlay && emulationViewModel.emulationStarted.value) { binding.surfaceInputOverlay.setVisible(
binding.surfaceInputOverlay.visibility = View.VISIBLE showInputOverlay && emulationViewModel.emulationStarted.value
} else { )
binding.surfaceInputOverlay.visibility = View.INVISIBLE
}
if (!isInFoldableLayout) { if (!isInFoldableLayout) {
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
binding.surfaceInputOverlay.layout = OverlayLayout.Portrait binding.surfaceInputOverlay.layout = OverlayLayout.Portrait
@ -544,7 +484,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
private fun updateShowFpsOverlay() { private fun updateShowFpsOverlay() {
if (BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()) { val showOverlay = BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()
binding.showFpsText.setVisible(showOverlay)
if (showOverlay) {
val SYSTEM_FPS = 0 val SYSTEM_FPS = 0
val FPS = 1 val FPS = 1
val FRAMETIME = 2 val FRAMETIME = 2
@ -564,17 +506,17 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
} }
perfStatsUpdateHandler.post(perfStatsUpdater!!) perfStatsUpdateHandler.post(perfStatsUpdater!!)
binding.showFpsText.visibility = View.VISIBLE
} else { } else {
if (perfStatsUpdater != null) { if (perfStatsUpdater != null) {
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!) perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
} }
binding.showFpsText.visibility = View.GONE
} }
} }
private fun updateThermalOverlay() { private fun updateThermalOverlay() {
if (BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean()) { val showOverlay = BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean()
binding.showThermalsText.setVisible(showOverlay)
if (showOverlay) {
thermalStatsUpdater = { thermalStatsUpdater = {
if (emulationViewModel.emulationStarted.value && if (emulationViewModel.emulationStarted.value &&
!emulationViewModel.isEmulationStopping.value !emulationViewModel.isEmulationStopping.value
@ -596,12 +538,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
} }
thermalStatsUpdateHandler.post(thermalStatsUpdater!!) thermalStatsUpdateHandler.post(thermalStatsUpdater!!)
binding.showThermalsText.visibility = View.VISIBLE
} else { } else {
if (thermalStatsUpdater != null) { if (thermalStatsUpdater != null) {
thermalStatsUpdateHandler.removeCallbacks(thermalStatsUpdater!!) thermalStatsUpdateHandler.removeCallbacks(thermalStatsUpdater!!)
} }
binding.showThermalsText.visibility = View.GONE
} }
} }
@ -870,12 +810,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
} }
} }
binding.doneControlConfig.visibility = View.VISIBLE binding.doneControlConfig.setVisible(true)
binding.surfaceInputOverlay.setIsInEditMode(true) binding.surfaceInputOverlay.setIsInEditMode(true)
} }
private fun stopConfiguringControls() { private fun stopConfiguringControls() {
binding.doneControlConfig.visibility = View.GONE binding.doneControlConfig.setVisible(false)
binding.surfaceInputOverlay.setIsInEditMode(false) binding.surfaceInputOverlay.setIsInEditMode(false)
// Unlock the orientation if it was locked for editing // Unlock the orientation if it was locked for editing
if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == EmulationOrientation.Unspecified.int) { if (IntSetting.RENDERER_SCREEN_LAYOUT.getInt() == EmulationOrientation.Unspecified.int) {

View File

@ -13,9 +13,6 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.transition.MaterialSharedAxis import com.google.android.material.transition.MaterialSharedAxis
@ -27,6 +24,7 @@ import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.ui.main.MainActivity import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
class GameFoldersFragment : Fragment() { class GameFoldersFragment : Fragment() {
private var _binding: FragmentFoldersBinding? = null private var _binding: FragmentFoldersBinding? = null
@ -70,12 +68,8 @@ class GameFoldersFragment : Fragment() {
adapter = FolderAdapter(requireActivity(), gamesViewModel) adapter = FolderAdapter(requireActivity(), gamesViewModel)
} }
viewLifecycleOwner.lifecycleScope.launch { gamesViewModel.folders.collect(viewLifecycleOwner) {
repeatOnLifecycle(Lifecycle.State.CREATED) { (binding.listFolders.adapter as FolderAdapter).submitList(it)
gamesViewModel.folders.collect {
(binding.listFolders.adapter as FolderAdapter).submitList(it)
}
}
} }
val mainActivity = requireActivity() as MainActivity val mainActivity = requireActivity() as MainActivity

View File

@ -27,6 +27,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentGameInfoBinding
import org.yuzu.yuzu_emu.model.GameVerificationResult import org.yuzu.yuzu_emu.model.GameVerificationResult
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.GameMetadata import org.yuzu.yuzu_emu.utils.GameMetadata
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class GameInfoFragment : Fragment() { class GameInfoFragment : Fragment() {
@ -85,7 +86,7 @@ class GameInfoFragment : Fragment() {
copyToClipboard(getString(R.string.developer), args.game.developer) copyToClipboard(getString(R.string.developer), args.game.developer)
} }
} else { } else {
developer.visibility = View.GONE developer.setVisible(false)
} }
version.setHint(R.string.version) version.setHint(R.string.version)

View File

@ -3,11 +3,9 @@
package org.yuzu.yuzu_emu.fragments package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.content.pm.ShortcutInfo import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager import android.content.pm.ShortcutManager
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -18,9 +16,7 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
@ -46,7 +42,9 @@ import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GameIconUtils import org.yuzu.yuzu_emu.utils.GameIconUtils
import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.MemoryUtil import org.yuzu.yuzu_emu.utils.MemoryUtil
import org.yuzu.yuzu_emu.utils.ViewUtils.marquee
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
import java.io.File import java.io.File
@ -76,8 +74,6 @@ class GamePropertiesFragment : Fragment() {
return binding.root return binding.root
} }
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = false, animated = true) homeViewModel.setNavigationVisibility(visible = false, animated = true)
@ -107,13 +103,7 @@ class GamePropertiesFragment : Fragment() {
GameIconUtils.loadGameIcon(args.game, binding.imageGameScreen) GameIconUtils.loadGameIcon(args.game, binding.imageGameScreen)
binding.title.text = args.game.title binding.title.text = args.game.title
binding.title.postDelayed( binding.title.marquee()
{
binding.title.ellipsize = TextUtils.TruncateAt.MARQUEE
binding.title.isSelected = true
},
3000
)
binding.buttonStart.setOnClickListener { binding.buttonStart.setOnClickListener {
LaunchGameDialogFragment.newInstance(args.game) LaunchGameDialogFragment.newInstance(args.game)
@ -122,28 +112,14 @@ class GamePropertiesFragment : Fragment() {
reloadList() reloadList()
viewLifecycleOwner.lifecycleScope.apply { homeViewModel.openImportSaves.collect(
launch { viewLifecycleOwner,
repeatOnLifecycle(Lifecycle.State.STARTED) { resetState = { homeViewModel.setOpenImportSaves(false) }
homeViewModel.openImportSaves.collect { ) { if (it) importSaves.launch(arrayOf("application/zip")) }
if (it) { homeViewModel.reloadPropertiesList.collect(
importSaves.launch(arrayOf("application/zip")) viewLifecycleOwner,
homeViewModel.setOpenImportSaves(false) resetState = { homeViewModel.reloadPropertiesList(false) }
} ) { if (it) reloadList() }
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
homeViewModel.reloadPropertiesList.collect {
if (it) {
reloadList()
homeViewModel.reloadPropertiesList(false)
}
}
}
}
}
setInsets() setInsets()
} }

View File

@ -14,9 +14,6 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.transition.MaterialSharedAxis import com.google.android.material.transition.MaterialSharedAxis
@ -35,6 +32,7 @@ import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.DirectoryInitialization import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.FileUtil import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
import java.io.File import java.io.File
import java.math.BigInteger import java.math.BigInteger
@ -75,14 +73,10 @@ class InstallableFragment : Fragment() {
binding.root.findNavController().popBackStack() binding.root.findNavController().popBackStack()
} }
viewLifecycleOwner.lifecycleScope.launch { homeViewModel.openImportSaves.collect(viewLifecycleOwner) {
repeatOnLifecycle(Lifecycle.State.CREATED) { if (it) {
homeViewModel.openImportSaves.collect { importSaves.launch(arrayOf("application/zip"))
if (it) { homeViewModel.setOpenImportSaves(false)
importSaves.launch(arrayOf("application/zip"))
homeViewModel.setOpenImportSaves(false)
}
}
} }
} }

View File

@ -13,15 +13,13 @@ import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
import org.yuzu.yuzu_emu.model.TaskViewModel import org.yuzu.yuzu_emu.model.TaskViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
class ProgressDialogFragment : DialogFragment() { class ProgressDialogFragment : DialogFragment() {
private val taskViewModel: TaskViewModel by activityViewModels() private val taskViewModel: TaskViewModel by activityViewModels()
@ -64,72 +62,50 @@ class ProgressDialogFragment : DialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.message.isSelected = true binding.message.isSelected = true
viewLifecycleOwner.lifecycleScope.apply { taskViewModel.isComplete.collect(viewLifecycleOwner) {
launch { if (it) {
repeatOnLifecycle(Lifecycle.State.CREATED) { dismiss()
taskViewModel.isComplete.collect { when (val result = taskViewModel.result.value) {
if (it) { is String -> Toast.makeText(
dismiss() requireContext(),
when (val result = taskViewModel.result.value) { result,
is String -> Toast.makeText( Toast.LENGTH_LONG
requireContext(), ).show()
result,
Toast.LENGTH_LONG
).show()
is MessageDialogFragment -> result.show( is MessageDialogFragment -> result.show(
requireActivity().supportFragmentManager, requireActivity().supportFragmentManager,
MessageDialogFragment.TAG MessageDialogFragment.TAG
) )
else -> { else -> {
// Do nothing // Do nothing
}
}
taskViewModel.clear()
}
} }
} }
taskViewModel.clear()
} }
launch { }
repeatOnLifecycle(Lifecycle.State.CREATED) { taskViewModel.cancelled.collect(viewLifecycleOwner) {
taskViewModel.cancelled.collect { if (it) {
if (it) { dialog?.setTitle(R.string.cancelling)
dialog?.setTitle(R.string.cancelling) }
} }
} taskViewModel.progress.collect(viewLifecycleOwner) {
} if (it != 0.0) {
} binding.progressBar.apply {
launch { isIndeterminate = false
repeatOnLifecycle(Lifecycle.State.CREATED) { progress = (
taskViewModel.progress.collect { (it / taskViewModel.maxProgress.value) *
if (it != 0.0) { PROGRESS_BAR_RESOLUTION
binding.progressBar.apply { ).toInt()
isIndeterminate = false min = 0
progress = ( max = PROGRESS_BAR_RESOLUTION
(it / taskViewModel.maxProgress.value) *
PROGRESS_BAR_RESOLUTION
).toInt()
min = 0
max = PROGRESS_BAR_RESOLUTION
}
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
taskViewModel.message.collect {
if (it.isEmpty()) {
binding.message.visibility = View.GONE
} else {
binding.message.visibility = View.VISIBLE
binding.message.text = it
}
}
} }
} }
} }
taskViewModel.message.collect(viewLifecycleOwner) {
binding.message.setVisible(it.isNotEmpty())
binding.message.text = it
}
} }
// By default, the ProgressDialog will immediately dismiss itself upon a button being pressed. // By default, the ProgressDialog will immediately dismiss itself upon a button being pressed.

View File

@ -3,7 +3,6 @@
package org.yuzu.yuzu_emu.fragments package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
@ -18,14 +17,9 @@ import androidx.core.view.updatePadding
import androidx.core.widget.doOnTextChanged import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import info.debatty.java.stringsimilarity.Jaccard import info.debatty.java.stringsimilarity.Jaccard
import info.debatty.java.stringsimilarity.JaroWinkler import info.debatty.java.stringsimilarity.JaroWinkler
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import java.util.Locale import java.util.Locale
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.YuzuApplication
@ -35,6 +29,8 @@ import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager
import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
class SearchFragment : Fragment() { class SearchFragment : Fragment() {
private var _binding: FragmentSearchBinding? = null private var _binding: FragmentSearchBinding? = null
@ -58,8 +54,6 @@ class SearchFragment : Fragment() {
return binding.root return binding.root
} }
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = true, animated = true) homeViewModel.setNavigationVisibility(visible = true, animated = true)
@ -81,42 +75,18 @@ class SearchFragment : Fragment() {
binding.chipGroup.setOnCheckedStateChangeListener { _, _ -> filterAndSearch() } binding.chipGroup.setOnCheckedStateChangeListener { _, _ -> filterAndSearch() }
binding.searchText.doOnTextChanged { text: CharSequence?, _: Int, _: Int, _: Int -> binding.searchText.doOnTextChanged { text: CharSequence?, _: Int, _: Int, _: Int ->
if (text.toString().isNotEmpty()) { binding.clearButton.setVisible(text.toString().isNotEmpty())
binding.clearButton.visibility = View.VISIBLE
} else {
binding.clearButton.visibility = View.INVISIBLE
}
filterAndSearch() filterAndSearch()
} }
viewLifecycleOwner.lifecycleScope.apply { gamesViewModel.searchFocused.collect(
launch { viewLifecycleOwner,
repeatOnLifecycle(Lifecycle.State.CREATED) { resetState = { gamesViewModel.setSearchFocused(false) }
gamesViewModel.searchFocused.collect { ) { if (it) focusSearch() }
if (it) { gamesViewModel.games.collect(viewLifecycleOwner) { filterAndSearch() }
focusSearch() gamesViewModel.searchedGames.collect(viewLifecycleOwner) {
gamesViewModel.setSearchFocused(false) (binding.gridGamesSearch.adapter as GameAdapter).submitList(it)
} binding.noResultsView.setVisible(it.isNotEmpty())
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
gamesViewModel.games.collectLatest { filterAndSearch() }
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
gamesViewModel.searchedGames.collect {
(binding.gridGamesSearch.adapter as GameAdapter).submitList(it)
if (it.isEmpty()) {
binding.noResultsView.visibility = View.VISIBLE
} else {
binding.noResultsView.visibility = View.GONE
}
}
}
}
} }
binding.clearButton.setOnClickListener { binding.searchText.setText("") } binding.clearButton.setOnClickListener { binding.searchText.setText("") }

View File

@ -4,7 +4,6 @@
package org.yuzu.yuzu_emu.fragments package org.yuzu.yuzu_emu.fragments
import android.Manifest import android.Manifest
import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
@ -23,9 +22,6 @@ import androidx.core.view.isVisible
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
@ -46,6 +42,8 @@ import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.DirectoryInitialization import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils import org.yuzu.yuzu_emu.utils.ViewUtils
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.collect
class SetupFragment : Fragment() { class SetupFragment : Fragment() {
private var _binding: FragmentSetupBinding? = null private var _binding: FragmentSetupBinding? = null
@ -77,8 +75,6 @@ class SetupFragment : Fragment() {
return binding.root return binding.root
} }
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
mainActivity = requireActivity() as MainActivity mainActivity = requireActivity() as MainActivity
@ -210,28 +206,14 @@ class SetupFragment : Fragment() {
) )
} }
viewLifecycleOwner.lifecycleScope.apply { homeViewModel.shouldPageForward.collect(
launch { viewLifecycleOwner,
repeatOnLifecycle(Lifecycle.State.CREATED) { resetState = { homeViewModel.setShouldPageForward(false) }
homeViewModel.shouldPageForward.collect { ) { if (it) pageForward() }
if (it) { homeViewModel.gamesDirSelected.collect(
pageForward() viewLifecycleOwner,
homeViewModel.setShouldPageForward(false) resetState = { homeViewModel.setGamesDirSelected(false) }
} ) { if (it) gamesDirCallback.onStepCompleted() }
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.gamesDirSelected.collect {
if (it) {
gamesDirCallback.onStepCompleted()
homeViewModel.setGamesDirSelected(false)
}
}
}
}
}
binding.viewPager2.apply { binding.viewPager2.apply {
adapter = SetupAdapter(requireActivity() as AppCompatActivity, pages) adapter = SetupAdapter(requireActivity() as AppCompatActivity, pages)
@ -292,12 +274,8 @@ class SetupFragment : Fragment() {
val backIsVisible = savedInstanceState.getBoolean(KEY_BACK_VISIBILITY) val backIsVisible = savedInstanceState.getBoolean(KEY_BACK_VISIBILITY)
hasBeenWarned = savedInstanceState.getBooleanArray(KEY_HAS_BEEN_WARNED)!! hasBeenWarned = savedInstanceState.getBooleanArray(KEY_HAS_BEEN_WARNED)!!
if (nextIsVisible) { binding.buttonNext.setVisible(nextIsVisible)
binding.buttonNext.visibility = View.VISIBLE binding.buttonBack.setVisible(backIsVisible)
}
if (backIsVisible) {
binding.buttonBack.visibility = View.VISIBLE
}
} else { } else {
hasBeenWarned = BooleanArray(pages.size) hasBeenWarned = BooleanArray(pages.size)
} }

View File

@ -28,6 +28,7 @@ import org.yuzu.yuzu_emu.features.input.NativeInput
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.features.input.model.NativeAnalog import org.yuzu.yuzu_emu.features.input.model.NativeAnalog
import org.yuzu.yuzu_emu.features.input.model.NativeButton import org.yuzu.yuzu_emu.features.input.model.NativeButton
import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.overlay.model.OverlayControl import org.yuzu.yuzu_emu.overlay.model.OverlayControl
@ -99,12 +100,10 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
} }
var shouldUpdateView = false var shouldUpdateView = false
val playerIndex = val playerIndex = when (NativeInput.getStyleIndex(0)) {
if (NativeInput.isHandheldOnly()) { NpadStyleIndex.Handheld -> 8
NativeInput.ConsoleDevice else -> 0
} else { }
NativeInput.Player1Device
}
for (button in overlayButtons) { for (button in overlayButtons) {
if (!button.updateStatus(event)) { if (!button.updateStatus(event)) {
@ -664,7 +663,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
val overlayControlData = NativeConfig.getOverlayControlData() val overlayControlData = NativeConfig.getOverlayControlData()
overlayControlData.forEach { overlayControlData.forEach {
it.enabled = OverlayControl.from(it.id)?.defaultVisibility == false it.enabled = OverlayControl.from(it.id)?.defaultVisibility == true
} }
NativeConfig.setOverlayControlData(overlayControlData) NativeConfig.setOverlayControlData(overlayControlData)

View File

@ -3,7 +3,6 @@
package org.yuzu.yuzu_emu.ui package org.yuzu.yuzu_emu.ui
import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -14,19 +13,16 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.google.android.material.color.MaterialColors import com.google.android.material.color.MaterialColors
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.adapters.GameAdapter import org.yuzu.yuzu_emu.adapters.GameAdapter
import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding
import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager
import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import org.yuzu.yuzu_emu.utils.collect
class GamesFragment : Fragment() { class GamesFragment : Fragment() {
private var _binding: FragmentGamesBinding? = null private var _binding: FragmentGamesBinding? = null
@ -44,8 +40,6 @@ class GamesFragment : Fragment() {
return binding.root return binding.root
} }
// This is using the correct scope, lint is just acting up
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
homeViewModel.setNavigationVisibility(visible = true, animated = true) homeViewModel.setNavigationVisibility(visible = true, animated = true)
@ -88,49 +82,28 @@ class GamesFragment : Fragment() {
} }
} }
viewLifecycleOwner.lifecycleScope.apply { gamesViewModel.isReloading.collect(viewLifecycleOwner) {
launch { binding.swipeRefresh.isRefreshing = it
repeatOnLifecycle(Lifecycle.State.RESUMED) { binding.noticeText.setVisible(
gamesViewModel.isReloading.collect { visible = gamesViewModel.games.value.isEmpty() && !it,
binding.swipeRefresh.isRefreshing = it gone = false
if (gamesViewModel.games.value.isEmpty() && !it) { )
binding.noticeText.visibility = View.VISIBLE }
} else { gamesViewModel.games.collect(viewLifecycleOwner) {
binding.noticeText.visibility = View.INVISIBLE (binding.gridGames.adapter as GameAdapter).submitList(it)
} }
} gamesViewModel.shouldSwapData.collect(
} viewLifecycleOwner,
} resetState = { gamesViewModel.setShouldSwapData(false) }
launch { ) {
repeatOnLifecycle(Lifecycle.State.RESUMED) { if (it) {
gamesViewModel.games.collectLatest { (binding.gridGames.adapter as GameAdapter).submitList(gamesViewModel.games.value)
(binding.gridGames.adapter as GameAdapter).submitList(it)
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
gamesViewModel.shouldSwapData.collect {
if (it) {
(binding.gridGames.adapter as GameAdapter).submitList(
gamesViewModel.games.value
)
gamesViewModel.setShouldSwapData(false)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
gamesViewModel.shouldScrollToTop.collect {
if (it) {
scrollToTop()
gamesViewModel.setShouldScrollToTop(false)
}
}
}
} }
} }
gamesViewModel.shouldScrollToTop.collect(
viewLifecycleOwner,
resetState = { gamesViewModel.setShouldScrollToTop(false) }
) { if (it) scrollToTop() }
setInsets() setInsets()
} }

View File

@ -19,9 +19,6 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
@ -30,7 +27,6 @@ import com.google.android.material.color.MaterialColors
import com.google.android.material.navigation.NavigationBarView import com.google.android.material.navigation.NavigationBarView
import java.io.File import java.io.File
import java.io.FilenameFilter import java.io.FilenameFilter
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
@ -47,6 +43,7 @@ import org.yuzu.yuzu_emu.model.InstallResult
import org.yuzu.yuzu_emu.model.TaskState import org.yuzu.yuzu_emu.model.TaskState
import org.yuzu.yuzu_emu.model.TaskViewModel import org.yuzu.yuzu_emu.model.TaskViewModel
import org.yuzu.yuzu_emu.utils.* import org.yuzu.yuzu_emu.utils.*
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
import java.io.BufferedInputStream import java.io.BufferedInputStream
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
@ -139,42 +136,23 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
// Prevents navigation from being drawn for a short time on recreation if set to hidden // Prevents navigation from being drawn for a short time on recreation if set to hidden
if (!homeViewModel.navigationVisible.value.first) { if (!homeViewModel.navigationVisible.value.first) {
binding.navigationView.visibility = View.INVISIBLE binding.navigationView.setVisible(visible = false, gone = false)
binding.statusBarShade.visibility = View.INVISIBLE binding.statusBarShade.setVisible(visible = false, gone = false)
} }
lifecycleScope.apply { homeViewModel.navigationVisible.collect(this) { showNavigation(it.first, it.second) }
launch { homeViewModel.statusBarShadeVisible.collect(this) { showStatusBarShade(it) }
repeatOnLifecycle(Lifecycle.State.CREATED) { homeViewModel.contentToInstall.collect(
homeViewModel.navigationVisible.collect { showNavigation(it.first, it.second) } this,
} resetState = { homeViewModel.setContentToInstall(null) }
} ) {
launch { if (it != null) {
repeatOnLifecycle(Lifecycle.State.CREATED) { installContent(it)
homeViewModel.statusBarShadeVisible.collect { showStatusBarShade(it) }
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.contentToInstall.collect {
if (it != null) {
installContent(it)
homeViewModel.setContentToInstall(null)
}
}
}
}
launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
homeViewModel.checkKeys.collect {
if (it) {
checkKeys()
homeViewModel.setCheckKeys(false)
}
}
}
} }
} }
homeViewModel.checkKeys.collect(this, resetState = { homeViewModel.setCheckKeys(false) }) {
if (it) checkKeys()
}
setInsets() setInsets()
} }
@ -214,18 +192,14 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
private fun showNavigation(visible: Boolean, animated: Boolean) { private fun showNavigation(visible: Boolean, animated: Boolean) {
if (!animated) { if (!animated) {
if (visible) { binding.navigationView.setVisible(visible)
binding.navigationView.visibility = View.VISIBLE
} else {
binding.navigationView.visibility = View.INVISIBLE
}
return return
} }
val smallLayout = resources.getBoolean(R.bool.small_layout) val smallLayout = resources.getBoolean(R.bool.small_layout)
binding.navigationView.animate().apply { binding.navigationView.animate().apply {
if (visible) { if (visible) {
binding.navigationView.visibility = View.VISIBLE binding.navigationView.setVisible(true)
duration = 300 duration = 300
interpolator = PathInterpolator(0.05f, 0.7f, 0.1f, 1f) interpolator = PathInterpolator(0.05f, 0.7f, 0.1f, 1f)
@ -264,7 +238,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
} }
}.withEndAction { }.withEndAction {
if (!visible) { if (!visible) {
binding.navigationView.visibility = View.INVISIBLE binding.navigationView.setVisible(visible = false, gone = false)
} }
}.start() }.start()
} }
@ -272,7 +246,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
private fun showStatusBarShade(visible: Boolean) { private fun showStatusBarShade(visible: Boolean) {
binding.statusBarShade.animate().apply { binding.statusBarShade.animate().apply {
if (visible) { if (visible) {
binding.statusBarShade.visibility = View.VISIBLE binding.statusBarShade.setVisible(true)
binding.statusBarShade.translationY = binding.statusBarShade.height.toFloat() * -2 binding.statusBarShade.translationY = binding.statusBarShade.height.toFloat() * -2
duration = 300 duration = 300
translationY(0f) translationY(0f)
@ -284,7 +258,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
} }
}.withEndAction { }.withEndAction {
if (!visible) { if (!visible) {
binding.statusBarShade.visibility = View.INVISIBLE binding.statusBarShade.setVisible(visible = false, gone = false)
} }
}.start() }.start()
} }
@ -524,7 +498,8 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
this@MainActivity, this@MainActivity,
titleId = R.string.content_install_notice, titleId = R.string.content_install_notice,
descriptionId = R.string.content_install_notice_description, descriptionId = R.string.content_install_notice_description,
positiveAction = { homeViewModel.setContentToInstall(documents) } positiveAction = { homeViewModel.setContentToInstall(documents) },
negativeAction = {}
) )
} }
}.show(supportFragmentManager, ProgressDialogFragment.TAG) }.show(supportFragmentManager, ProgressDialogFragment.TAG)

View File

@ -0,0 +1,38 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.utils
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
/**
* Collects this [Flow] with a given [LifecycleOwner].
* @param scope [LifecycleOwner] that this [Flow] will be collected with.
* @param repeatState When to repeat collection on this [Flow].
* @param resetState Optional lambda to reset state of an underlying [MutableStateFlow] after
* [stateCollector] has been run.
* @param stateCollector Lambda that receives new state.
*/
inline fun <reified T> Flow<T>.collect(
scope: LifecycleOwner,
repeatState: Lifecycle.State = Lifecycle.State.CREATED,
crossinline resetState: () -> Unit = {},
crossinline stateCollector: (state: T) -> Unit
) {
scope.apply {
lifecycleScope.launch {
repeatOnLifecycle(repeatState) {
this@collect.collect {
stateCollector(it)
resetState()
}
}
}
}
}

View File

@ -3,8 +3,10 @@
package org.yuzu.yuzu_emu.utils package org.yuzu.yuzu_emu.utils
import android.text.TextUtils
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView
object ViewUtils { object ViewUtils {
fun showView(view: View, length: Long = 300) { fun showView(view: View, length: Long = 300) {
@ -57,4 +59,35 @@ object ViewUtils {
} }
this.layoutParams = layoutParams this.layoutParams = layoutParams
} }
/**
* Shows or hides a view.
* @param visible Whether a view will be made View.VISIBLE or View.INVISIBLE/GONE.
* @param gone Optional parameter for hiding a view. Uses View.GONE if true and View.INVISIBLE otherwise.
*/
fun View.setVisible(visible: Boolean, gone: Boolean = true) {
visibility = if (visible) {
View.VISIBLE
} else {
if (gone) {
View.GONE
} else {
View.INVISIBLE
}
}
}
/**
* Starts a marquee on some text.
* @param delay Optional parameter for changing the start delay. 3 seconds of delay by default.
*/
fun TextView.marquee(delay: Long = 3000) {
ellipsize = null
marqueeRepeatLimit = -1
isSingleLine = true
postDelayed({
ellipsize = TextUtils.TruncateAt.MARQUEE
isSelected = true
}, delay)
}
} }

View File

@ -23,6 +23,22 @@ void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
window_info.render_surface = reinterpret_cast<void*>(surface); window_info.render_surface = reinterpret_cast<void*>(surface);
} }
void EmuWindow_Android::OnTouchPressed(int id, float x, float y) {
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchPressed(touch_x,
touch_y, id);
}
void EmuWindow_Android::OnTouchMoved(int id, float x, float y) {
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchMoved(touch_x,
touch_y, id);
}
void EmuWindow_Android::OnTouchReleased(int id) {
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchReleased(id);
}
void EmuWindow_Android::OnFrameDisplayed() { void EmuWindow_Android::OnFrameDisplayed() {
if (!m_first_frame) { if (!m_first_frame) {
Common::Android::RunJNIOnFiber<void>( Common::Android::RunJNIOnFiber<void>(

View File

@ -38,6 +38,10 @@ public:
void OnSurfaceChanged(ANativeWindow* surface); void OnSurfaceChanged(ANativeWindow* surface);
void OnFrameDisplayed() override; void OnFrameDisplayed() override;
void OnTouchPressed(int id, float x, float y);
void OnTouchMoved(int id, float x, float y);
void OnTouchReleased(int id);
std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override { std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override {
return {std::make_unique<GraphicsContext_Android>(m_driver_library)}; return {std::make_unique<GraphicsContext_Android>(m_driver_library)};
} }

View File

@ -292,6 +292,9 @@ void EmulationSession::ShutdownEmulation() {
// Unload user input. // Unload user input.
m_system.HIDCore().UnloadInputDevices(); m_system.HIDCore().UnloadInputDevices();
// Enable all controllers
m_system.HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
// Shutdown the main emulated process // Shutdown the main emulated process
if (m_load_result == Core::SystemResultStatus::Success) { if (m_load_result == Core::SystemResultStatus::Success) {
m_system.DetachDebugger(); m_system.DetachDebugger();
@ -404,7 +407,9 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
const size_t program_index, const size_t program_index,
const bool frontend_initiated) { const bool frontend_initiated) {
MicroProfileOnThreadCreate("EmuThread"); MicroProfileOnThreadCreate("EmuThread");
SCOPE_EXIT({ MicroProfileShutdown(); }); SCOPE_EXIT {
MicroProfileShutdown();
};
LOG_INFO(Frontend, "starting"); LOG_INFO(Frontend, "starting");
@ -413,7 +418,9 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
return Core::SystemResultStatus::ErrorLoader; return Core::SystemResultStatus::ErrorLoader;
} }
SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); }); SCOPE_EXIT {
EmulationSession::GetInstance().ShutdownEmulation();
};
jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index, jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index,
frontend_initiated); frontend_initiated);
@ -661,7 +668,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
ASSERT(user_id); ASSERT(user_id);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 1, {}, vfs_nand_dir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, 1,
user_id->AsU128(), 0); user_id->AsU128(), 0);
const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path); const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
@ -829,8 +836,8 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
FileSys::OpenMode::Read); FileSys::OpenMode::Read);
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
{}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, {}, vfsNandDir, FileSys::SaveDataSpaceId::User, FileSys::SaveDataType::Account, program_id,
program_id, user_id->AsU128(), 0); user_id->AsU128(), 0);
return Common::Android::ToJString(env, user_save_data_path); return Common::Android::ToJString(env, user_save_data_path);
} }

View File

@ -102,8 +102,50 @@ void ApplyControllerConfig(size_t player_index,
} }
} }
std::vector<s32> GetSupportedStyles(int player_index) {
auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
const auto npad_style_set = hid_core.GetSupportedStyleTag();
std::vector<s32> supported_indexes;
if (npad_style_set.fullkey == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Fullkey));
}
if (npad_style_set.joycon_dual == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconDual));
}
if (npad_style_set.joycon_left == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconLeft));
}
if (npad_style_set.joycon_right == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::JoyconRight));
}
if (player_index == 0 && npad_style_set.handheld == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::Handheld));
}
if (npad_style_set.gamecube == 1) {
supported_indexes.push_back(static_cast<s32>(Core::HID::NpadStyleIndex::GameCube));
}
return supported_indexes;
}
void ConnectController(size_t player_index, bool connected) { void ConnectController(size_t player_index, bool connected) {
auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); auto& hid_core = EmulationSession::GetInstance().System().HIDCore();
ApplyControllerConfig(player_index, [&](Core::HID::EmulatedController* controller) {
auto supported_styles = GetSupportedStyles(player_index);
auto controller_style = controller->GetNpadStyleIndex(true);
auto style = std::find(supported_styles.begin(), supported_styles.end(),
static_cast<int>(controller_style));
if (style == supported_styles.end() && !supported_styles.empty()) {
controller->SetNpadStyleIndex(
static_cast<Core::HID::NpadStyleIndex>(supported_styles[0]));
}
});
if (player_index == 0) { if (player_index == 0) {
auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); auto* player_one = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
@ -190,8 +232,7 @@ void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onTouchPressed(JNIEnv* e
jint j_id, jfloat j_x_axis, jint j_id, jfloat j_x_axis,
jfloat j_y_axis) { jfloat j_y_axis) {
if (EmulationSession::GetInstance().IsRunning()) { if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchPressed( EmulationSession::GetInstance().Window().OnTouchPressed(j_id, j_x_axis, j_y_axis);
j_id, j_x_axis, j_y_axis);
} }
} }
@ -199,15 +240,14 @@ void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onTouchMoved(JNIEnv* env
jint j_id, jfloat j_x_axis, jint j_id, jfloat j_x_axis,
jfloat j_y_axis) { jfloat j_y_axis) {
if (EmulationSession::GetInstance().IsRunning()) { if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchMoved( EmulationSession::GetInstance().Window().OnTouchMoved(j_id, j_x_axis, j_y_axis);
j_id, j_x_axis, j_y_axis);
} }
} }
void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onTouchReleased(JNIEnv* env, jobject j_obj, void Java_org_yuzu_yuzu_1emu_features_input_NativeInput_onTouchReleased(JNIEnv* env, jobject j_obj,
jint j_id) { jint j_id) {
if (EmulationSession::GetInstance().IsRunning()) { if (EmulationSession::GetInstance().IsRunning()) {
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchReleased(j_id); EmulationSession::GetInstance().Window().OnTouchReleased(j_id);
} }
} }
@ -524,36 +564,10 @@ jint Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getButtonNameImpl(JNIEnv
jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl( jintArray Java_org_yuzu_yuzu_1emu_features_input_NativeInput_getSupportedStyleTagsImpl(
JNIEnv* env, jobject j_obj, jint j_player_index) { JNIEnv* env, jobject j_obj, jint j_player_index) {
auto& hid_core = EmulationSession::GetInstance().System().HIDCore(); auto supported_styles = GetSupportedStyles(j_player_index);
const auto npad_style_set = hid_core.GetSupportedStyleTag(); jintArray j_supported_indexes = env->NewIntArray(supported_styles.size());
std::vector<s32> supported_indexes; env->SetIntArrayRegion(j_supported_indexes, 0, supported_styles.size(),
if (npad_style_set.fullkey == 1) { supported_styles.data());
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Fullkey));
}
if (npad_style_set.joycon_dual == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconDual));
}
if (npad_style_set.joycon_left == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconLeft));
}
if (npad_style_set.joycon_right == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::JoyconRight));
}
if (j_player_index == 0 && npad_style_set.handheld == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::Handheld));
}
if (npad_style_set.gamecube == 1) {
supported_indexes.push_back(static_cast<u32>(Core::HID::NpadStyleIndex::GameCube));
}
jintArray j_supported_indexes = env->NewIntArray(supported_indexes.size());
env->SetIntArrayRegion(j_supported_indexes, 0, supported_indexes.size(),
supported_indexes.data());
return j_supported_indexes; return j_supported_indexes;
} }

View File

@ -39,10 +39,7 @@
style="@style/TextAppearance.Material3.TitleMedium" style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal" android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart" android:textAlignment="viewStart"
tools:text="@string/select_gpu_driver_default" /> tools:text="@string/select_gpu_driver_default" />
@ -52,10 +49,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="6dp" android:layout_marginTop="6dp"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal" android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart" android:textAlignment="viewStart"
tools:text="@string/install_gpu_driver_description" /> tools:text="@string/install_gpu_driver_description" />
@ -65,10 +59,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="6dp" android:layout_marginTop="6dp"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal" android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart" android:textAlignment="viewStart"
tools:text="@string/install_gpu_driver_description" /> tools:text="@string/install_gpu_driver_description" />

View File

@ -21,10 +21,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start" android:layout_gravity="center_vertical|start"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal" android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="viewStart" android:textAlignment="viewStart"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/button_layout" app:layout_constraintEnd_toStartOf="@+id/button_layout"

View File

@ -40,10 +40,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal" android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="center" android:textAlignment="center"
android:textSize="14sp" android:textSize="14sp"
app:layout_constraintEnd_toEndOf="@+id/image_game_screen" app:layout_constraintEnd_toEndOf="@+id/image_game_screen"

View File

@ -59,9 +59,6 @@
android:textAlignment="viewStart" android:textAlignment="viewStart"
android:textSize="14sp" android:textSize="14sp"
android:textStyle="bold" android:textStyle="bold"
android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
android:ellipsize="none"
android:requiresFadingEdge="horizontal" android:requiresFadingEdge="horizontal"
android:layout_marginTop="6dp" android:layout_marginTop="6dp"
android:visibility="gone" android:visibility="gone"

View File

@ -76,10 +76,7 @@
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:layout_marginBottom="12dp" android:layout_marginBottom="12dp"
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
android:ellipsize="none"
android:marqueeRepeatLimit="marquee_forever"
android:requiresFadingEdge="horizontal" android:requiresFadingEdge="horizontal"
android:singleLine="true"
android:textAlignment="center" android:textAlignment="center"
tools:text="deko_basic" /> tools:text="deko_basic" />

View File

@ -209,6 +209,7 @@
<string name="value_with_units">%1$s%2$s</string> <string name="value_with_units">%1$s%2$s</string>
<!-- System settings strings --> <!-- System settings strings -->
<string name="device_name">Device name</string>
<string name="use_docked_mode">Docked Mode</string> <string name="use_docked_mode">Docked Mode</string>
<string name="use_docked_mode_description">Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance.</string> <string name="use_docked_mode_description">Increases resolution, decreasing performance. Handheld Mode is used when disabled, lowering resolution and increasing performance.</string>
<string name="emulated_region">Emulated region</string> <string name="emulated_region">Emulated region</string>

View File

@ -73,16 +73,15 @@ void Manager::BufferReleaseAndRegister() {
} }
} }
u32 Manager::GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names, u32 Manager::GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names,
[[maybe_unused]] const u32 max_count,
[[maybe_unused]] const bool filter) { [[maybe_unused]] const bool filter) {
std::scoped_lock l{mutex}; std::scoped_lock l{mutex};
LinkToManager(); LinkToManager();
auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)}; auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
if (input_devices.size() > 1) { if (!input_devices.empty() && !names.empty()) {
names.emplace_back("Uac"); names[0] = Renderer::AudioDevice::AudioDeviceName("Uac");
return 1; return 1;
} }
return 0; return 0;

View File

@ -60,13 +60,11 @@ public:
* Get a list of audio in device names. * Get a list of audio in device names.
* *
* @param names - Output container to write names to. * @param names - Output container to write names to.
* @param max_count - Maximum number of device names to write. Unused
* @param filter - Should the list be filtered? Unused. * @param filter - Should the list be filtered? Unused.
* *
* @return Number of names written. * @return Number of names written.
*/ */
u32 GetDeviceNames(std::vector<Renderer::AudioDevice::AudioDeviceName>& names, u32 max_count, u32 GetDeviceNames(std::span<Renderer::AudioDevice::AudioDeviceName> names, bool filter);
bool filter);
/// Core system /// Core system
Core::System& system; Core::System& system;

View File

@ -146,7 +146,11 @@ public:
break; break;
} }
tags[released++] = tag; if (released < tags.size()) {
tags[released] = tag;
}
released++;
if (released >= tags.size()) { if (released >= tags.size()) {
break; break;

View File

@ -28,8 +28,8 @@ OpusDecoder::~OpusDecoder() {
} }
} }
Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, Result OpusDecoder::Initialize(const OpusParametersEx& params,
u64 transfer_memory_size) { Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
auto frame_size{params.use_large_frame_size ? 5760 : 1920}; auto frame_size{params.use_large_frame_size ? 5760 : 1920};
shared_buffer_size = transfer_memory_size; shared_buffer_size = transfer_memory_size;
shared_buffer = std::make_unique<u8[]>(shared_buffer_size); shared_buffer = std::make_unique<u8[]>(shared_buffer_size);
@ -59,7 +59,7 @@ Result OpusDecoder::Initialize(OpusParametersEx& params, Kernel::KTransferMemory
R_SUCCEED(); R_SUCCEED();
} }
Result OpusDecoder::Initialize(OpusMultiStreamParametersEx& params, Result OpusDecoder::Initialize(const OpusMultiStreamParametersEx& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) { Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
auto frame_size{params.use_large_frame_size ? 5760 : 1920}; auto frame_size{params.use_large_frame_size ? 5760 : 1920};
shared_buffer_size = transfer_memory_size; shared_buffer_size = transfer_memory_size;

View File

@ -22,10 +22,10 @@ public:
explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_); explicit OpusDecoder(Core::System& system, HardwareOpus& hardware_opus_);
~OpusDecoder(); ~OpusDecoder();
Result Initialize(OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, Result Initialize(const OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory,
u64 transfer_memory_size);
Result Initialize(OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory,
u64 transfer_memory_size); u64 transfer_memory_size);
Result Initialize(const OpusMultiStreamParametersEx& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size);
Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count, Result DecodeInterleaved(u32* out_data_size, u64* out_time_taken, u32* out_sample_count,
std::span<const u8> input_data, std::span<u8> output_data, bool reset); std::span<const u8> input_data, std::span<u8> output_data, bool reset);
Result SetContext([[maybe_unused]] std::span<const u8> context); Result SetContext([[maybe_unused]] std::span<const u8> context);

View File

@ -38,7 +38,7 @@ OpusDecoderManager::OpusDecoderManager(Core::System& system_)
} }
} }
Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_size) { Result OpusDecoderManager::GetWorkBufferSize(const OpusParameters& params, u32& out_size) {
OpusParametersEx ex{ OpusParametersEx ex{
.sample_rate = params.sample_rate, .sample_rate = params.sample_rate,
.channel_count = params.channel_count, .channel_count = params.channel_count,
@ -47,11 +47,11 @@ Result OpusDecoderManager::GetWorkBufferSize(OpusParameters& params, u64& out_si
R_RETURN(GetWorkBufferSizeExEx(ex, out_size)); R_RETURN(GetWorkBufferSizeExEx(ex, out_size));
} }
Result OpusDecoderManager::GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size) { Result OpusDecoderManager::GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size) {
R_RETURN(GetWorkBufferSizeExEx(params, out_size)); R_RETURN(GetWorkBufferSizeExEx(params, out_size));
} }
Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size) { Result OpusDecoderManager::GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size) {
R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount); R_UNLESS(IsValidChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate); R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
@ -63,8 +63,8 @@ Result OpusDecoderManager::GetWorkBufferSizeExEx(OpusParametersEx& params, u64&
R_SUCCEED(); R_SUCCEED();
} }
Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params,
u64& out_size) { u32& out_size) {
OpusMultiStreamParametersEx ex{ OpusMultiStreamParametersEx ex{
.sample_rate = params.sample_rate, .sample_rate = params.sample_rate,
.channel_count = params.channel_count, .channel_count = params.channel_count,
@ -76,13 +76,13 @@ Result OpusDecoderManager::GetWorkBufferSizeForMultiStream(OpusMultiStreamParame
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size)); R_RETURN(GetWorkBufferSizeForMultiStreamExEx(ex, out_size));
} }
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamEx(
u64& out_size) { const OpusMultiStreamParametersEx& params, u32& out_size) {
R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size)); R_RETURN(GetWorkBufferSizeForMultiStreamExEx(params, out_size));
} }
Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, Result OpusDecoderManager::GetWorkBufferSizeForMultiStreamExEx(
u64& out_size) { const OpusMultiStreamParametersEx& params, u32& out_size) {
R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount); R_UNLESS(IsValidMultiStreamChannelCount(params.channel_count), ResultInvalidOpusChannelCount);
R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate); R_UNLESS(IsValidSampleRate(params.sample_rate), ResultInvalidOpusSampleRate);
R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count, R_UNLESS(IsValidStreamCount(params.channel_count, params.total_stream_count,

View File

@ -22,17 +22,19 @@ public:
return hardware_opus; return hardware_opus;
} }
Result GetWorkBufferSize(OpusParameters& params, u64& out_size); Result GetWorkBufferSize(const OpusParameters& params, u32& out_size);
Result GetWorkBufferSizeEx(OpusParametersEx& params, u64& out_size); Result GetWorkBufferSizeEx(const OpusParametersEx& params, u32& out_size);
Result GetWorkBufferSizeExEx(OpusParametersEx& params, u64& out_size); Result GetWorkBufferSizeExEx(const OpusParametersEx& params, u32& out_size);
Result GetWorkBufferSizeForMultiStream(OpusMultiStreamParameters& params, u64& out_size); Result GetWorkBufferSizeForMultiStream(const OpusMultiStreamParameters& params, u32& out_size);
Result GetWorkBufferSizeForMultiStreamEx(OpusMultiStreamParametersEx& params, u64& out_size); Result GetWorkBufferSizeForMultiStreamEx(const OpusMultiStreamParametersEx& params,
Result GetWorkBufferSizeForMultiStreamExEx(OpusMultiStreamParametersEx& params, u64& out_size); u32& out_size);
Result GetWorkBufferSizeForMultiStreamExEx(const OpusMultiStreamParametersEx& params,
u32& out_size);
private: private:
Core::System& system; Core::System& system;
HardwareOpus hardware_opus; HardwareOpus hardware_opus;
std::array<u64, MaxChannels> required_workbuffer_sizes{}; std::array<u32, MaxChannels> required_workbuffer_sizes{};
}; };
} // namespace AudioCore::OpusDecoder } // namespace AudioCore::OpusDecoder

View File

@ -42,7 +42,7 @@ HardwareOpus::HardwareOpus(Core::System& system_)
opus_decoder.SetSharedMemory(shared_memory); opus_decoder.SetSharedMemory(shared_memory);
} }
u64 HardwareOpus::GetWorkBufferSize(u32 channel) { u32 HardwareOpus::GetWorkBufferSize(u32 channel) {
if (!opus_decoder.IsRunning()) { if (!opus_decoder.IsRunning()) {
return 0; return 0;
} }
@ -55,10 +55,10 @@ u64 HardwareOpus::GetWorkBufferSize(u32 channel) {
ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg); ADSP::OpusDecoder::Message::GetWorkBufferSizeOK, msg);
return 0; return 0;
} }
return shared_memory.dsp_return_data[0]; return static_cast<u32>(shared_memory.dsp_return_data[0]);
} }
u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) { u32 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count) {
std::scoped_lock l{mutex}; std::scoped_lock l{mutex};
shared_memory.host_send_data[0] = total_stream_count; shared_memory.host_send_data[0] = total_stream_count;
shared_memory.host_send_data[1] = stereo_stream_count; shared_memory.host_send_data[1] = stereo_stream_count;
@ -70,7 +70,7 @@ u64 HardwareOpus::GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 st
ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg); ADSP::OpusDecoder::Message::GetWorkBufferSizeForMultiStreamOK, msg);
return 0; return 0;
} }
return shared_memory.dsp_return_data[0]; return static_cast<u32>(shared_memory.dsp_return_data[0]);
} }
Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer, Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
@ -94,8 +94,9 @@ Result HardwareOpus::InitializeDecodeObject(u32 sample_rate, u32 channel_count,
Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, Result HardwareOpus::InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
u32 total_stream_count, u32 total_stream_count,
u32 stereo_stream_count, void* mappings, u32 stereo_stream_count,
void* buffer, u64 buffer_size) { const void* mappings, void* buffer,
u64 buffer_size) {
std::scoped_lock l{mutex}; std::scoped_lock l{mutex};
shared_memory.host_send_data[0] = (u64)buffer; shared_memory.host_send_data[0] = (u64)buffer;
shared_memory.host_send_data[1] = buffer_size; shared_memory.host_send_data[1] = buffer_size;

View File

@ -16,14 +16,14 @@ class HardwareOpus {
public: public:
HardwareOpus(Core::System& system); HardwareOpus(Core::System& system);
u64 GetWorkBufferSize(u32 channel); u32 GetWorkBufferSize(u32 channel);
u64 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count); u32 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer, Result InitializeDecodeObject(u32 sample_rate, u32 channel_count, void* buffer,
u64 buffer_size); u64 buffer_size);
Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count, Result InitializeMultiStreamDecodeObject(u32 sample_rate, u32 channel_count,
u32 totaL_stream_count, u32 stereo_stream_count, u32 totaL_stream_count, u32 stereo_stream_count,
void* mappings, void* buffer, u64 buffer_size); const void* mappings, void* buffer, u64 buffer_size);
Result ShutdownDecodeObject(void* buffer, u64 buffer_size); Result ShutdownDecodeObject(void* buffer, u64 buffer_size);
Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size); Result ShutdownMultiStreamDecodeObject(void* buffer, u64 buffer_size);
Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size, Result DecodeInterleaved(u32& out_sample_count, void* output_data, u64 output_data_size,

View File

@ -20,7 +20,7 @@ struct OpusParametersEx {
/* 0x00 */ u32 sample_rate; /* 0x00 */ u32 sample_rate;
/* 0x04 */ u32 channel_count; /* 0x04 */ u32 channel_count;
/* 0x08 */ bool use_large_frame_size; /* 0x08 */ bool use_large_frame_size;
/* 0x09 */ INSERT_PADDING_BYTES(7); /* 0x09 */ INSERT_PADDING_BYTES_NOINIT(7);
}; // size = 0x10 }; // size = 0x10
static_assert(sizeof(OpusParametersEx) == 0x10, "OpusParametersEx has the wrong size!"); static_assert(sizeof(OpusParametersEx) == 0x10, "OpusParametersEx has the wrong size!");
@ -40,7 +40,7 @@ struct OpusMultiStreamParametersEx {
/* 0x08 */ u32 total_stream_count; /* 0x08 */ u32 total_stream_count;
/* 0x0C */ u32 stereo_stream_count; /* 0x0C */ u32 stereo_stream_count;
/* 0x10 */ bool use_large_frame_size; /* 0x10 */ bool use_large_frame_size;
/* 0x11 */ INSERT_PADDING_BYTES(7); /* 0x11 */ INSERT_PADDING_BYTES_NOINIT(7);
/* 0x18 */ std::array<u8, OpusStreamCountMax + 1> mappings; /* 0x18 */ std::array<u8, OpusStreamCountMax + 1> mappings;
}; // size = 0x118 }; // size = 0x118
static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118, static_assert(sizeof(OpusMultiStreamParametersEx) == 0x118,

View File

@ -36,8 +36,7 @@ AudioDevice::AudioDevice(Core::System& system, const u64 applet_resource_user_id
: output_sink{system.AudioCore().GetOutputSink()}, : output_sink{system.AudioCore().GetOutputSink()},
applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {} applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {}
u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, u32 AudioDevice::ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const {
const size_t max_count) const {
std::span<const AudioDeviceName> names{}; std::span<const AudioDeviceName> names{};
if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) { if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) {
@ -46,19 +45,18 @@ u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer,
names = device_names; names = device_names;
} }
const u32 out_count{static_cast<u32>(std::min(max_count, names.size()))}; const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), names.size()))};
for (u32 i = 0; i < out_count; i++) { for (u32 i = 0; i < out_count; i++) {
out_buffer.push_back(names[i]); out_buffer[i] = names[i];
} }
return out_count; return out_count;
} }
u32 AudioDevice::ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, u32 AudioDevice::ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const {
const size_t max_count) const { const u32 out_count{static_cast<u32>(std::min(out_buffer.size(), output_device_names.size()))};
const u32 out_count{static_cast<u32>(std::min(max_count, output_device_names.size()))};
for (u32 i = 0; i < out_count; i++) { for (u32 i = 0; i < out_count; i++) {
out_buffer.push_back(output_device_names[i]); out_buffer[i] = output_device_names[i];
} }
return out_count; return out_count;
} }

View File

@ -36,20 +36,18 @@ public:
* Get a list of the available output devices. * Get a list of the available output devices.
* *
* @param out_buffer - Output buffer to write the available device names. * @param out_buffer - Output buffer to write the available device names.
* @param max_count - Maximum number of devices to write (count of out_buffer).
* @return Number of device names written. * @return Number of device names written.
*/ */
u32 ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const; u32 ListAudioDeviceName(std::span<AudioDeviceName> out_buffer) const;
/** /**
* Get a list of the available output devices. * Get a list of the available output devices.
* Different to above somehow... * Different to above somehow...
* *
* @param out_buffer - Output buffer to write the available device names. * @param out_buffer - Output buffer to write the available device names.
* @param max_count - Maximum number of devices to write (count of out_buffer).
* @return Number of device names written. * @return Number of device names written.
*/ */
u32 ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const; u32 ListAudioOutputDeviceName(std::span<AudioDeviceName> out_buffer) const;
/** /**
* Set the volume of all streams in the backend sink. * Set the volume of all streams in the backend sink.

View File

@ -17,9 +17,8 @@ Renderer::Renderer(Core::System& system_, Manager& manager_, Kernel::KEvent* ren
Result Renderer::Initialize(const AudioRendererParameterInternal& params, Result Renderer::Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, Kernel::KTransferMemory* transfer_memory,
const u64 transfer_memory_size, const u32 process_handle, const u64 transfer_memory_size, Kernel::KProcess* process_handle,
Kernel::KProcess& process, const u64 applet_resource_user_id, const u64 applet_resource_user_id, const s32 session_id) {
const s32 session_id) {
if (params.execution_mode == ExecutionMode::Auto) { if (params.execution_mode == ExecutionMode::Auto) {
if (!manager.AddSystem(system)) { if (!manager.AddSystem(system)) {
LOG_ERROR(Service_Audio, LOG_ERROR(Service_Audio,
@ -30,7 +29,7 @@ Result Renderer::Initialize(const AudioRendererParameterInternal& params,
} }
initialized = true; initialized = true;
system.Initialize(params, transfer_memory, transfer_memory_size, process_handle, process, system.Initialize(params, transfer_memory, transfer_memory_size, process_handle,
applet_resource_user_id, session_id); applet_resource_user_id, session_id);
return ResultSuccess; return ResultSuccess;

View File

@ -38,14 +38,14 @@ public:
* @param params - Input parameters to initialize the system with. * @param params - Input parameters to initialize the system with.
* @param transfer_memory - Game-supplied memory for all workbuffers. Unused. * @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
* @param transfer_memory_size - Size of the transfer memory. Unused. * @param transfer_memory_size - Size of the transfer memory. Unused.
* @param process_handle - Process handle, also used for memory. Unused. * @param process_handle - Process handle, also used for memory.
* @param applet_resource_user_id - Applet id for this renderer. Unused. * @param applet_resource_user_id - Applet id for this renderer. Unused.
* @param session_id - Session id of this renderer. * @param session_id - Session id of this renderer.
* @return Result code. * @return Result code.
*/ */
Result Initialize(const AudioRendererParameterInternal& params, Result Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id, Kernel::KProcess* process_handle, u64 applet_resource_user_id,
s32 session_id); s32 session_id);
/** /**

View File

@ -18,7 +18,7 @@
namespace AudioCore::Renderer { namespace AudioCore::Renderer {
InfoUpdater::InfoUpdater(std::span<const u8> input_, std::span<u8> output_, InfoUpdater::InfoUpdater(std::span<const u8> input_, std::span<u8> output_,
const u32 process_handle_, BehaviorInfo& behaviour_) Kernel::KProcess* process_handle_, BehaviorInfo& behaviour_)
: input{input_.data() + sizeof(UpdateDataHeader)}, : input{input_.data() + sizeof(UpdateDataHeader)},
input_origin{input_}, output{output_.data() + sizeof(UpdateDataHeader)}, input_origin{input_}, output{output_.data() + sizeof(UpdateDataHeader)},
output_origin{output_}, in_header{reinterpret_cast<const UpdateDataHeader*>( output_origin{output_}, in_header{reinterpret_cast<const UpdateDataHeader*>(

View File

@ -8,6 +8,10 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/service/audio/errors.h" #include "core/hle/service/audio/errors.h"
namespace Kernel {
class KProcess;
}
namespace AudioCore::Renderer { namespace AudioCore::Renderer {
class BehaviorInfo; class BehaviorInfo;
class VoiceContext; class VoiceContext;
@ -39,8 +43,8 @@ class InfoUpdater {
static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has the wrong size!"); static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has the wrong size!");
public: public:
explicit InfoUpdater(std::span<const u8> input, std::span<u8> output, u32 process_handle, explicit InfoUpdater(std::span<const u8> input, std::span<u8> output,
BehaviorInfo& behaviour); Kernel::KProcess* process_handle, BehaviorInfo& behaviour);
/** /**
* Update the voice channel resources. * Update the voice channel resources.
@ -197,7 +201,7 @@ private:
/// Expected output size, see CheckConsumedSize /// Expected output size, see CheckConsumedSize
u64 expected_output_size; u64 expected_output_size;
/// Unused /// Unused
u32 process_handle; Kernel::KProcess* process_handle;
/// Behaviour /// Behaviour
BehaviorInfo& behaviour; BehaviorInfo& behaviour;
}; };

View File

@ -8,11 +8,11 @@
namespace AudioCore::Renderer { namespace AudioCore::Renderer {
PoolMapper::PoolMapper(u32 process_handle_, bool force_map_) PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, bool force_map_)
: process_handle{process_handle_}, force_map{force_map_} {} : process_handle{process_handle_}, force_map{force_map_} {}
PoolMapper::PoolMapper(u32 process_handle_, std::span<MemoryPoolInfo> pool_infos_, u32 pool_count_, PoolMapper::PoolMapper(Kernel::KProcess* process_handle_, std::span<MemoryPoolInfo> pool_infos_,
bool force_map_) u32 pool_count_, bool force_map_)
: process_handle{process_handle_}, pool_infos{pool_infos_.data()}, : process_handle{process_handle_}, pool_infos{pool_infos_.data()},
pool_count{pool_count_}, force_map{force_map_} {} pool_count{pool_count_}, force_map{force_map_} {}
@ -106,15 +106,17 @@ bool PoolMapper::IsForceMapEnabled() const {
return force_map; return force_map;
} }
u32 PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const { Kernel::KProcess* PoolMapper::GetProcessHandle(const MemoryPoolInfo* pool) const {
switch (pool->GetLocation()) { switch (pool->GetLocation()) {
case MemoryPoolInfo::Location::CPU: case MemoryPoolInfo::Location::CPU:
return process_handle; return process_handle;
case MemoryPoolInfo::Location::DSP: case MemoryPoolInfo::Location::DSP:
return Kernel::Svc::CurrentProcess; // return Kernel::Svc::CurrentProcess;
return nullptr;
} }
LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!"); LOG_WARNING(Service_Audio, "Invalid MemoryPoolInfo location!");
return Kernel::Svc::CurrentProcess; // return Kernel::Svc::CurrentProcess;
return nullptr;
} }
bool PoolMapper::Map([[maybe_unused]] const u32 handle, [[maybe_unused]] const CpuAddr cpu_addr, bool PoolMapper::Map([[maybe_unused]] const u32 handle, [[maybe_unused]] const CpuAddr cpu_addr,
@ -147,14 +149,14 @@ bool PoolMapper::Unmap([[maybe_unused]] const u32 handle, [[maybe_unused]] const
} }
bool PoolMapper::Unmap(MemoryPoolInfo& pool) const { bool PoolMapper::Unmap(MemoryPoolInfo& pool) const {
[[maybe_unused]] u32 handle{0}; [[maybe_unused]] Kernel::KProcess* handle{};
switch (pool.GetLocation()) { switch (pool.GetLocation()) {
case MemoryPoolInfo::Location::CPU: case MemoryPoolInfo::Location::CPU:
handle = process_handle; handle = process_handle;
break; break;
case MemoryPoolInfo::Location::DSP: case MemoryPoolInfo::Location::DSP:
handle = Kernel::Svc::CurrentProcess; // handle = Kernel::Svc::CurrentProcess;
break; break;
} }
// nn::audio::dsp::UnmapUserPointer(handle, pool->cpu_address, pool->size); // nn::audio::dsp::UnmapUserPointer(handle, pool->cpu_address, pool->size);

View File

@ -10,6 +10,10 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/service/audio/errors.h" #include "core/hle/service/audio/errors.h"
namespace Kernel {
class KProcess;
}
namespace AudioCore::Renderer { namespace AudioCore::Renderer {
class AddressInfo; class AddressInfo;
@ -18,9 +22,9 @@ class AddressInfo;
*/ */
class PoolMapper { class PoolMapper {
public: public:
explicit PoolMapper(u32 process_handle, bool force_map); explicit PoolMapper(Kernel::KProcess* process_handle, bool force_map);
explicit PoolMapper(u32 process_handle, std::span<MemoryPoolInfo> pool_infos, u32 pool_count, explicit PoolMapper(Kernel::KProcess* process_handle, std::span<MemoryPoolInfo> pool_infos,
bool force_map); u32 pool_count, bool force_map);
/** /**
* Clear the usage state for all given pools. * Clear the usage state for all given pools.
@ -98,7 +102,7 @@ public:
* @return CurrentProcessHandle if location == DSP, * @return CurrentProcessHandle if location == DSP,
* the PoolMapper's process_handle if location == CPU * the PoolMapper's process_handle if location == CPU
*/ */
u32 GetProcessHandle(const MemoryPoolInfo* pool) const; Kernel::KProcess* GetProcessHandle(const MemoryPoolInfo* pool) const;
/** /**
* Map the given region with the given handle. This is a no-op. * Map the given region with the given handle. This is a no-op.
@ -167,7 +171,7 @@ public:
private: private:
/// Process handle for this mapper, used when location == CPU /// Process handle for this mapper, used when location == CPU
u32 process_handle; Kernel::KProcess* process_handle{};
/// List of memory pools assigned to this mapper /// List of memory pools assigned to this mapper
MemoryPoolInfo* pool_infos{}; MemoryPoolInfo* pool_infos{};
/// The number of pools /// The number of pools

View File

@ -102,8 +102,8 @@ System::System(Core::System& core_, Kernel::KEvent* adsp_rendered_event_)
Result System::Initialize(const AudioRendererParameterInternal& params, Result System::Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
u32 process_handle_, Kernel::KProcess& process_, Kernel::KProcess* process_handle_, u64 applet_resource_user_id_,
u64 applet_resource_user_id_, s32 session_id_) { s32 session_id_) {
if (!CheckValidRevision(params.revision)) { if (!CheckValidRevision(params.revision)) {
return Service::Audio::ResultInvalidRevision; return Service::Audio::ResultInvalidRevision;
} }
@ -119,7 +119,6 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
behavior.SetUserLibRevision(params.revision); behavior.SetUserLibRevision(params.revision);
process_handle = process_handle_; process_handle = process_handle_;
process = &process_;
applet_resource_user_id = applet_resource_user_id_; applet_resource_user_id = applet_resource_user_id_;
session_id = session_id_; session_id = session_id_;
@ -132,7 +131,8 @@ Result System::Initialize(const AudioRendererParameterInternal& params,
render_device = params.rendering_device; render_device = params.rendering_device;
execution_mode = params.execution_mode; execution_mode = params.execution_mode;
process->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(), transfer_memory_size); process_handle->GetMemory().ZeroBlock(transfer_memory->GetSourceAddress(),
transfer_memory_size);
// Note: We're not actually using the transfer memory because it's a pain to code for. // Note: We're not actually using the transfer memory because it's a pain to code for.
// Allocate the memory normally instead and hope the game doesn't try to read anything back // Allocate the memory normally instead and hope the game doesn't try to read anything back
@ -616,7 +616,7 @@ void System::SendCommandToDsp() {
static_cast<u64>((time_limit_percent / 100) * 2'880'000.0 * static_cast<u64>((time_limit_percent / 100) * 2'880'000.0 *
(static_cast<f32>(render_time_limit_percent) / 100.0f))}; (static_cast<f32>(render_time_limit_percent) / 100.0f))};
audio_renderer.SetCommandBuffer(session_id, translated_addr, command_size, time_limit, audio_renderer.SetCommandBuffer(session_id, translated_addr, command_size, time_limit,
applet_resource_user_id, process, applet_resource_user_id, process_handle,
reset_command_buffers); reset_command_buffers);
reset_command_buffers = false; reset_command_buffers = false;
command_buffer_size = command_size; command_buffer_size = command_size;

View File

@ -74,14 +74,14 @@ public:
* @param params - Input parameters to initialize the system with. * @param params - Input parameters to initialize the system with.
* @param transfer_memory - Game-supplied memory for all workbuffers. Unused. * @param transfer_memory - Game-supplied memory for all workbuffers. Unused.
* @param transfer_memory_size - Size of the transfer memory. Unused. * @param transfer_memory_size - Size of the transfer memory. Unused.
* @param process_handle - Process handle, also used for memory. Unused. * @param process_handle - Process handle, also used for memory.
* @param applet_resource_user_id - Applet id for this renderer. Unused. * @param applet_resource_user_id - Applet id for this renderer. Unused.
* @param session_id - Session id of this renderer. * @param session_id - Session id of this renderer.
* @return Result code. * @return Result code.
*/ */
Result Initialize(const AudioRendererParameterInternal& params, Result Initialize(const AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size, Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
u32 process_handle, Kernel::KProcess& process, u64 applet_resource_user_id, Kernel::KProcess* process_handle, u64 applet_resource_user_id,
s32 session_id); s32 session_id);
/** /**
@ -278,9 +278,7 @@ private:
/// Does what locks do /// Does what locks do
std::mutex lock{}; std::mutex lock{};
/// Process this audio render is operating within, used for memory reads/writes. /// Process this audio render is operating within, used for memory reads/writes.
Kernel::KProcess* process{}; Kernel::KProcess* process_handle{};
/// Handle for the process for this system, unused
u32 process_handle{};
/// Applet resource id for this system, unused /// Applet resource id for this system, unused
u64 applet_resource_user_id{}; u64 applet_resource_user_id{};
/// Controls performance input and output /// Controls performance input and output

View File

@ -357,7 +357,9 @@ bool IsCubebSuitable() {
return false; return false;
} }
SCOPE_EXIT({ cubeb_destroy(ctx); }); SCOPE_EXIT {
cubeb_destroy(ctx);
};
#ifdef _WIN32 #ifdef _WIN32
if (SUCCEEDED(com_init_result)) { if (SUCCEEDED(com_init_result)) {

View File

@ -67,9 +67,13 @@ public:
oboe::AudioStreamBuilder builder; oboe::AudioStreamBuilder builder;
const auto result = ConfigureBuilder(builder, direction)->openStream(temp_stream); const auto result = ConfigureBuilder(builder, direction)->openStream(temp_stream);
ASSERT(result == oboe::Result::OK); if (result == oboe::Result::OK) {
return temp_stream->getChannelCount() >= 6 ? 6 : 2;
}
return temp_stream->getChannelCount() >= 6 ? 6 : 2; LOG_ERROR(Audio_Sink, "Failed to open {} stream. Using default channel count 2",
direction == oboe::Direction::Output ? "output" : "input");
return 2;
} }
protected: protected:

View File

@ -20,10 +20,10 @@
namespace AudioCore::Sink { namespace AudioCore::Sink {
void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) { void SinkStream::AppendBuffer(SinkBuffer& buffer, std::span<s16> samples) {
SCOPE_EXIT({ SCOPE_EXIT {
queue.enqueue(buffer); queue.enqueue(buffer);
++queued_buffers; ++queued_buffers;
}); };
if (type == StreamType::In) { if (type == StreamType::In) {
return; return;

View File

@ -20,7 +20,9 @@ std::string DemangleSymbol(const std::string& mangled) {
} }
char* demangled = nullptr; char* demangled = nullptr;
SCOPE_EXIT({ std::free(demangled); }); SCOPE_EXIT {
std::free(demangled);
};
if (is_itanium(mangled)) { if (is_itanium(mangled)) {
demangled = llvm::itaniumDemangle(mangled.c_str()); demangled = llvm::itaniumDemangle(mangled.c_str());

View File

@ -430,11 +430,11 @@ public:
explicit Impl(size_t backing_size_, size_t virtual_size_) explicit Impl(size_t backing_size_, size_t virtual_size_)
: backing_size{backing_size_}, virtual_size{virtual_size_} { : backing_size{backing_size_}, virtual_size{virtual_size_} {
bool good = false; bool good = false;
SCOPE_EXIT({ SCOPE_EXIT {
if (!good) { if (!good) {
Release(); Release();
} }
}); };
long page_size = sysconf(_SC_PAGESIZE); long page_size = sysconf(_SC_PAGESIZE);
if (page_size != 0x1000) { if (page_size != 0x1000) {

View File

@ -24,10 +24,10 @@ bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* c
out_entry->block_size = page_size; out_entry->block_size = page_size;
// Regardless of whether the page was mapped, advance on exit. // Regardless of whether the page was mapped, advance on exit.
SCOPE_EXIT({ SCOPE_EXIT {
context->next_page += 1; context->next_page += 1;
context->next_offset += page_size; context->next_offset += page_size;
}); };
// Validate that we can read the actual entry. // Validate that we can read the actual entry.
const auto page = context->next_page; const auto page = context->next_page;

View File

@ -7,29 +7,61 @@
#include "common/common_funcs.h" #include "common/common_funcs.h"
namespace detail { namespace detail {
template <typename Func> template <class F>
struct ScopeExitHelper { class ScopeGuard {
explicit ScopeExitHelper(Func&& func_) : func(std::move(func_)) {} YUZU_NON_COPYABLE(ScopeGuard);
~ScopeExitHelper() {
private:
F f;
bool active;
public:
constexpr ScopeGuard(F f_) : f(std::move(f_)), active(true) {}
constexpr ~ScopeGuard() {
if (active) { if (active) {
func(); f();
} }
} }
constexpr void Cancel() {
void Cancel() {
active = false; active = false;
} }
Func func; constexpr ScopeGuard(ScopeGuard&& rhs) : f(std::move(rhs.f)), active(rhs.active) {
bool active{true}; rhs.Cancel();
}
ScopeGuard& operator=(ScopeGuard&& rhs) = delete;
}; };
template <typename Func> template <class F>
ScopeExitHelper<Func> ScopeExit(Func&& func) { constexpr ScopeGuard<F> MakeScopeGuard(F f) {
return ScopeExitHelper<Func>(std::forward<Func>(func)); return ScopeGuard<F>(std::move(f));
} }
enum class ScopeGuardOnExit {};
template <typename F>
constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f) {
return ScopeGuard<F>(std::forward<F>(f));
}
} // namespace detail } // namespace detail
#define CONCATENATE_IMPL(s1, s2) s1##s2
#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
#ifdef __COUNTER__
#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __COUNTER__)
#else
#define ANONYMOUS_VARIABLE(pref) CONCATENATE(pref, __LINE__)
#endif
/**
* This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be
* used when the caller might want to cancel the ScopeExit.
*/
#define SCOPE_GUARD detail::ScopeGuardOnExit() + [&]()
/** /**
* This macro allows you to conveniently specify a block of code that will run on scope exit. Handy * This macro allows you to conveniently specify a block of code that will run on scope exit. Handy
* for doing ad-hoc clean-up tasks in a function with multiple returns. * for doing ad-hoc clean-up tasks in a function with multiple returns.
@ -38,7 +70,7 @@ ScopeExitHelper<Func> ScopeExit(Func&& func) {
* \code * \code
* const int saved_val = g_foo; * const int saved_val = g_foo;
* g_foo = 55; * g_foo = 55;
* SCOPE_EXIT({ g_foo = saved_val; }); * SCOPE_EXIT{ g_foo = saved_val; };
* *
* if (Bar()) { * if (Bar()) {
* return 0; * return 0;
@ -47,10 +79,4 @@ ScopeExitHelper<Func> ScopeExit(Func&& func) {
* } * }
* \endcode * \endcode
*/ */
#define SCOPE_EXIT(body) auto CONCAT2(scope_exit_helper_, __LINE__) = detail::ScopeExit([&]() body) #define SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE_) = SCOPE_GUARD
/**
* This macro is similar to SCOPE_EXIT, except the object is caller managed. This is intended to be
* used when the caller might want to cancel the ScopeExit.
*/
#define SCOPE_GUARD(body) detail::ScopeExit([&]() body)

View File

@ -384,6 +384,12 @@ struct Values {
AstcRecompression::Bc3, AstcRecompression::Bc3,
"astc_recompression", "astc_recompression",
Category::RendererAdvanced}; Category::RendererAdvanced};
SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
VramUsageMode::Conservative,
VramUsageMode::Conservative,
VramUsageMode::Aggressive,
"vram_usage_mode",
Category::RendererAdvanced};
SwitchableSetting<bool> async_presentation{linkage, SwitchableSetting<bool> async_presentation{linkage,
#ifdef ANDROID #ifdef ANDROID
true, true,

View File

@ -122,6 +122,8 @@ ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed); ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
ENUM(VramUsageMode, Conservative, Aggressive);
ENUM(RendererBackend, OpenGL, Vulkan, Null); ENUM(RendererBackend, OpenGL, Vulkan, Null);
ENUM(ShaderBackend, Glsl, Glasm, SpirV); ENUM(ShaderBackend, Glsl, Glasm, SpirV);

View File

@ -38,6 +38,10 @@ std::string StringFromBuffer(std::span<const u8> data) {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
} }
std::string StringFromBuffer(std::span<const char> data) {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
}
// Turns " hej " into "hej". Also handles tabs. // Turns " hej " into "hej". Also handles tabs.
std::string StripSpaces(const std::string& str) { std::string StripSpaces(const std::string& str) {
const std::size_t s = str.find_first_not_of(" \t\r\n"); const std::size_t s = str.find_first_not_of(" \t\r\n");

View File

@ -19,6 +19,7 @@ namespace Common {
[[nodiscard]] std::string ToUpper(std::string str); [[nodiscard]] std::string ToUpper(std::string str);
[[nodiscard]] std::string StringFromBuffer(std::span<const u8> data); [[nodiscard]] std::string StringFromBuffer(std::span<const u8> data);
[[nodiscard]] std::string StringFromBuffer(std::span<const char> data);
[[nodiscard]] std::string StripSpaces(const std::string& s); [[nodiscard]] std::string StripSpaces(const std::string& s);
[[nodiscard]] std::string StripQuotes(const std::string& s); [[nodiscard]] std::string StripQuotes(const std::string& s);

View File

@ -2,8 +2,8 @@
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
add_library(core STATIC add_library(core STATIC
arm/arm_interface.h
arm/arm_interface.cpp arm/arm_interface.cpp
arm/arm_interface.h
arm/debug.cpp arm/debug.cpp
arm/debug.h arm/debug.h
arm/exclusive_monitor.cpp arm/exclusive_monitor.cpp
@ -37,10 +37,10 @@ add_library(core STATIC
debugger/gdbstub.h debugger/gdbstub.h
debugger/gdbstub_arch.cpp debugger/gdbstub_arch.cpp
debugger/gdbstub_arch.h debugger/gdbstub_arch.h
device_memory_manager.h
device_memory_manager.inc
device_memory.cpp device_memory.cpp
device_memory.h device_memory.h
device_memory_manager.h
device_memory_manager.inc
file_sys/bis_factory.cpp file_sys/bis_factory.cpp
file_sys/bis_factory.h file_sys/bis_factory.h
file_sys/card_image.cpp file_sys/card_image.cpp
@ -58,9 +58,14 @@ add_library(core STATIC
file_sys/fs_operate_range.h file_sys/fs_operate_range.h
file_sys/fs_path.h file_sys/fs_path.h
file_sys/fs_path_utility.h file_sys/fs_path_utility.h
file_sys/fs_save_data_types.h
file_sys/fs_string_util.h file_sys/fs_string_util.h
file_sys/fsa/fs_i_directory.h
file_sys/fsa/fs_i_file.h
file_sys/fsa/fs_i_filesystem.h
file_sys/fsmitm_romfsbuild.cpp file_sys/fsmitm_romfsbuild.cpp
file_sys/fsmitm_romfsbuild.h file_sys/fsmitm_romfsbuild.h
file_sys/fssrv/fssrv_sf_path.h
file_sys/fssystem/fs_i_storage.h file_sys/fssystem/fs_i_storage.h
file_sys/fssystem/fs_types.h file_sys/fssystem/fs_types.h
file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.cpp
@ -390,6 +395,20 @@ add_library(core STATIC
hle/service/acc/errors.h hle/service/acc/errors.h
hle/service/acc/profile_manager.cpp hle/service/acc/profile_manager.cpp
hle/service/acc/profile_manager.h hle/service/acc/profile_manager.h
hle/service/am/am.cpp
hle/service/am/am.h
hle/service/am/am_results.h
hle/service/am/am_types.h
hle/service/am/applet.cpp
hle/service/am/applet.h
hle/service/am/applet_data_broker.cpp
hle/service/am/applet_data_broker.h
hle/service/am/applet_manager.cpp
hle/service/am/applet_manager.h
hle/service/am/applet_message_queue.cpp
hle/service/am/applet_message_queue.h
hle/service/am/display_layer_manager.cpp
hle/service/am/display_layer_manager.h
hle/service/am/frontend/applet_cabinet.cpp hle/service/am/frontend/applet_cabinet.cpp
hle/service/am/frontend/applet_cabinet.h hle/service/am/frontend/applet_cabinet.h
hle/service/am/frontend/applet_controller.cpp hle/service/am/frontend/applet_controller.cpp
@ -411,24 +430,10 @@ add_library(core STATIC
hle/service/am/frontend/applet_web_browser_types.h hle/service/am/frontend/applet_web_browser_types.h
hle/service/am/frontend/applets.cpp hle/service/am/frontend/applets.cpp
hle/service/am/frontend/applets.h hle/service/am/frontend/applets.h
hle/service/am/am.cpp
hle/service/am/am.h
hle/service/am/am_results.h
hle/service/am/am_types.h
hle/service/am/applet.cpp
hle/service/am/applet.h
hle/service/am/applet_manager.cpp
hle/service/am/applet_data_broker.cpp
hle/service/am/applet_data_broker.h
hle/service/am/applet_manager.h
hle/service/am/applet_message_queue.cpp
hle/service/am/applet_message_queue.h
hle/service/am/hid_registration.cpp hle/service/am/hid_registration.cpp
hle/service/am/hid_registration.h hle/service/am/hid_registration.h
hle/service/am/library_applet_storage.cpp hle/service/am/library_applet_storage.cpp
hle/service/am/library_applet_storage.h hle/service/am/library_applet_storage.h
hle/service/am/managed_layer_holder.cpp
hle/service/am/managed_layer_holder.h
hle/service/am/process.cpp hle/service/am/process.cpp
hle/service/am/process.h hle/service/am/process.h
hle/service/am/service/all_system_applet_proxies_service.cpp hle/service/am/service/all_system_applet_proxies_service.cpp
@ -441,10 +446,10 @@ add_library(core STATIC
hle/service/am/service/application_creator.h hle/service/am/service/application_creator.h
hle/service/am/service/application_functions.cpp hle/service/am/service/application_functions.cpp
hle/service/am/service/application_functions.h hle/service/am/service/application_functions.h
hle/service/am/service/application_proxy_service.cpp
hle/service/am/service/application_proxy_service.h
hle/service/am/service/application_proxy.cpp hle/service/am/service/application_proxy.cpp
hle/service/am/service/application_proxy.h hle/service/am/service/application_proxy.h
hle/service/am/service/application_proxy_service.cpp
hle/service/am/service/application_proxy_service.h
hle/service/am/service/audio_controller.cpp hle/service/am/service/audio_controller.cpp
hle/service/am/service/audio_controller.h hle/service/am/service/audio_controller.h
hle/service/am/service/common_state_getter.cpp hle/service/am/service/common_state_getter.cpp
@ -473,55 +478,53 @@ add_library(core STATIC
hle/service/am/service/process_winding_controller.h hle/service/am/service/process_winding_controller.h
hle/service/am/service/self_controller.cpp hle/service/am/service/self_controller.cpp
hle/service/am/service/self_controller.h hle/service/am/service/self_controller.h
hle/service/am/service/storage_accessor.cpp
hle/service/am/service/storage_accessor.h
hle/service/am/service/storage.cpp hle/service/am/service/storage.cpp
hle/service/am/service/storage.h hle/service/am/service/storage.h
hle/service/am/service/storage_accessor.cpp
hle/service/am/service/storage_accessor.h
hle/service/am/service/system_applet_proxy.cpp hle/service/am/service/system_applet_proxy.cpp
hle/service/am/service/system_applet_proxy.h hle/service/am/service/system_applet_proxy.h
hle/service/am/service/window_controller.cpp hle/service/am/service/window_controller.cpp
hle/service/am/service/window_controller.h hle/service/am/service/window_controller.h
hle/service/am/system_buffer_manager.cpp hle/service/aoc/addon_content_manager.cpp
hle/service/am/system_buffer_manager.h hle/service/aoc/addon_content_manager.h
hle/service/aoc/aoc_u.cpp hle/service/aoc/purchase_event_manager.cpp
hle/service/aoc/aoc_u.h hle/service/aoc/purchase_event_manager.h
hle/service/apm/apm.cpp hle/service/apm/apm.cpp
hle/service/apm/apm.h hle/service/apm/apm.h
hle/service/apm/apm_controller.cpp hle/service/apm/apm_controller.cpp
hle/service/apm/apm_controller.h hle/service/apm/apm_controller.h
hle/service/apm/apm_interface.cpp hle/service/apm/apm_interface.cpp
hle/service/apm/apm_interface.h hle/service/apm/apm_interface.h
hle/service/audio/audctl.cpp hle/service/audio/audio_controller.cpp
hle/service/audio/audctl.h hle/service/audio/audio_controller.h
hle/service/audio/audin_u.cpp hle/service/audio/audio_device.cpp
hle/service/audio/audin_u.h hle/service/audio/audio_device.h
hle/service/audio/audio_in_manager.cpp
hle/service/audio/audio_in_manager.h
hle/service/audio/audio_in.cpp
hle/service/audio/audio_in.h
hle/service/audio/audio_out_manager.cpp
hle/service/audio/audio_out_manager.h
hle/service/audio/audio_out.cpp
hle/service/audio/audio_out.h
hle/service/audio/audio_renderer_manager.cpp
hle/service/audio/audio_renderer_manager.h
hle/service/audio/audio_renderer.cpp
hle/service/audio/audio_renderer.h
hle/service/audio/audio.cpp hle/service/audio/audio.cpp
hle/service/audio/audio.h hle/service/audio/audio.h
hle/service/audio/audout_u.cpp
hle/service/audio/audout_u.h
hle/service/audio/audrec_a.cpp
hle/service/audio/audrec_a.h
hle/service/audio/audrec_u.cpp
hle/service/audio/audrec_u.h
hle/service/audio/audren_u.cpp
hle/service/audio/audren_u.h
hle/service/audio/errors.h hle/service/audio/errors.h
hle/service/audio/hwopus.cpp hle/service/audio/final_output_recorder_manager_for_applet.cpp
hle/service/audio/hwopus.h hle/service/audio/final_output_recorder_manager_for_applet.h
hle/service/audio/final_output_recorder_manager.cpp
hle/service/audio/final_output_recorder_manager.h
hle/service/audio/hardware_opus_decoder_manager.cpp
hle/service/audio/hardware_opus_decoder_manager.h
hle/service/audio/hardware_opus_decoder.cpp
hle/service/audio/hardware_opus_decoder.h
hle/service/bcat/backend/backend.cpp hle/service/bcat/backend/backend.cpp
hle/service/bcat/backend/backend.h hle/service/bcat/backend/backend.h
hle/service/bcat/news/newly_arrived_event_holder.cpp
hle/service/bcat/news/newly_arrived_event_holder.h
hle/service/bcat/news/news_data_service.cpp
hle/service/bcat/news/news_data_service.h
hle/service/bcat/news/news_database_service.cpp
hle/service/bcat/news/news_database_service.h
hle/service/bcat/news/news_service.cpp
hle/service/bcat/news/news_service.h
hle/service/bcat/news/overwrite_event_holder.cpp
hle/service/bcat/news/overwrite_event_holder.h
hle/service/bcat/news/service_creator.cpp
hle/service/bcat/news/service_creator.h
hle/service/bcat/bcat.cpp hle/service/bcat/bcat.cpp
hle/service/bcat/bcat.h hle/service/bcat/bcat.h
hle/service/bcat/bcat_result.h hle/service/bcat/bcat_result.h
@ -537,6 +540,18 @@ add_library(core STATIC
hle/service/bcat/delivery_cache_progress_service.h hle/service/bcat/delivery_cache_progress_service.h
hle/service/bcat/delivery_cache_storage_service.cpp hle/service/bcat/delivery_cache_storage_service.cpp
hle/service/bcat/delivery_cache_storage_service.h hle/service/bcat/delivery_cache_storage_service.h
hle/service/bcat/news/newly_arrived_event_holder.cpp
hle/service/bcat/news/newly_arrived_event_holder.h
hle/service/bcat/news/news_data_service.cpp
hle/service/bcat/news/news_data_service.h
hle/service/bcat/news/news_database_service.cpp
hle/service/bcat/news/news_database_service.h
hle/service/bcat/news/news_service.cpp
hle/service/bcat/news/news_service.h
hle/service/bcat/news/overwrite_event_holder.cpp
hle/service/bcat/news/overwrite_event_holder.h
hle/service/bcat/news/service_creator.cpp
hle/service/bcat/news/service_creator.h
hle/service/bcat/service_creator.cpp hle/service/bcat/service_creator.cpp
hle/service/bcat/service_creator.h hle/service/bcat/service_creator.h
hle/service/bpc/bpc.cpp hle/service/bpc/bpc.cpp
@ -545,6 +560,16 @@ add_library(core STATIC
hle/service/btdrv/btdrv.h hle/service/btdrv/btdrv.h
hle/service/btm/btm.cpp hle/service/btm/btm.cpp
hle/service/btm/btm.h hle/service/btm/btm.h
hle/service/btm/btm_debug.cpp
hle/service/btm/btm_debug.h
hle/service/btm/btm_system.cpp
hle/service/btm/btm_system.h
hle/service/btm/btm_system_core.cpp
hle/service/btm/btm_system_core.h
hle/service/btm/btm_user.cpp
hle/service/btm/btm_user.h
hle/service/btm/btm_user_core.cpp
hle/service/btm/btm_user_core.h
hle/service/caps/caps.cpp hle/service/caps/caps.cpp
hle/service/caps/caps.h hle/service/caps/caps.h
hle/service/caps/caps_a.cpp hle/service/caps/caps_a.cpp
@ -587,6 +612,10 @@ add_library(core STATIC
hle/service/filesystem/fsp/fs_i_file.h hle/service/filesystem/fsp/fs_i_file.h
hle/service/filesystem/fsp/fs_i_filesystem.cpp hle/service/filesystem/fsp/fs_i_filesystem.cpp
hle/service/filesystem/fsp/fs_i_filesystem.h hle/service/filesystem/fsp/fs_i_filesystem.h
hle/service/filesystem/fsp/fs_i_multi_commit_manager.cpp
hle/service/filesystem/fsp/fs_i_multi_commit_manager.h
hle/service/filesystem/fsp/fs_i_save_data_info_reader.cpp
hle/service/filesystem/fsp/fs_i_save_data_info_reader.h
hle/service/filesystem/fsp/fs_i_storage.cpp hle/service/filesystem/fsp/fs_i_storage.cpp
hle/service/filesystem/fsp/fs_i_storage.h hle/service/filesystem/fsp/fs_i_storage.h
hle/service/filesystem/fsp/fsp_ldr.cpp hle/service/filesystem/fsp/fsp_ldr.cpp
@ -595,13 +624,13 @@ add_library(core STATIC
hle/service/filesystem/fsp/fsp_pr.h hle/service/filesystem/fsp/fsp_pr.h
hle/service/filesystem/fsp/fsp_srv.cpp hle/service/filesystem/fsp/fsp_srv.cpp
hle/service/filesystem/fsp/fsp_srv.h hle/service/filesystem/fsp/fsp_srv.h
hle/service/filesystem/fsp/fsp_util.h hle/service/filesystem/fsp/fsp_types.h
hle/service/filesystem/fsp/save_data_transfer_prohibiter.cpp
hle/service/filesystem/fsp/save_data_transfer_prohibiter.h
hle/service/filesystem/romfs_controller.cpp hle/service/filesystem/romfs_controller.cpp
hle/service/filesystem/romfs_controller.h hle/service/filesystem/romfs_controller.h
hle/service/filesystem/save_data_controller.cpp hle/service/filesystem/save_data_controller.cpp
hle/service/filesystem/save_data_controller.h hle/service/filesystem/save_data_controller.h
hle/service/fgm/fgm.cpp
hle/service/fgm/fgm.h
hle/service/friend/friend.cpp hle/service/friend/friend.cpp
hle/service/friend/friend.h hle/service/friend/friend.h
hle/service/friend/friend_interface.cpp hle/service/friend/friend_interface.cpp
@ -739,15 +768,48 @@ add_library(core STATIC
hle/service/nim/nim.h hle/service/nim/nim.h
hle/service/npns/npns.cpp hle/service/npns/npns.cpp
hle/service/npns/npns.h hle/service/npns/npns.h
hle/service/ns/errors.h hle/service/ns/account_proxy_interface.cpp
hle/service/ns/iplatform_service_manager.cpp hle/service/ns/account_proxy_interface.h
hle/service/ns/iplatform_service_manager.h hle/service/ns/application_manager_interface.cpp
hle/service/ns/application_manager_interface.h
hle/service/ns/application_version_interface.cpp
hle/service/ns/application_version_interface.h
hle/service/ns/content_management_interface.cpp
hle/service/ns/content_management_interface.h
hle/service/ns/develop_interface.cpp
hle/service/ns/develop_interface.h
hle/service/ns/document_interface.cpp
hle/service/ns/document_interface.h
hle/service/ns/download_task_interface.cpp
hle/service/ns/download_task_interface.h
hle/service/ns/dynamic_rights_interface.cpp
hle/service/ns/dynamic_rights_interface.h
hle/service/ns/ecommerce_interface.cpp
hle/service/ns/ecommerce_interface.h
hle/service/ns/factory_reset_interface.cpp
hle/service/ns/factory_reset_interface.h
hle/service/ns/language.cpp hle/service/ns/language.cpp
hle/service/ns/language.h hle/service/ns/language.h
hle/service/ns/ns.cpp hle/service/ns/ns.cpp
hle/service/ns/ns.h hle/service/ns/ns.h
hle/service/ns/pdm_qry.cpp hle/service/ns/ns_results.h
hle/service/ns/pdm_qry.h hle/service/ns/ns_types.h
hle/service/ns/platform_service_manager.cpp
hle/service/ns/platform_service_manager.h
hle/service/ns/query_service.cpp
hle/service/ns/query_service.h
hle/service/ns/read_only_application_control_data_interface.cpp
hle/service/ns/read_only_application_control_data_interface.h
hle/service/ns/read_only_application_record_interface.cpp
hle/service/ns/read_only_application_record_interface.h
hle/service/ns/service_getter_interface.cpp
hle/service/ns/service_getter_interface.h
hle/service/ns/system_update_control.cpp
hle/service/ns/system_update_control.h
hle/service/ns/system_update_interface.cpp
hle/service/ns/system_update_interface.h
hle/service/ns/vulnerability_manager_interface.cpp
hle/service/ns/vulnerability_manager_interface.h
hle/service/nvdrv/core/container.cpp hle/service/nvdrv/core/container.cpp
hle/service/nvdrv/core/container.h hle/service/nvdrv/core/container.h
hle/service/nvdrv/core/heap_mapper.cpp hle/service/nvdrv/core/heap_mapper.cpp
@ -800,14 +862,14 @@ add_library(core STATIC
hle/service/nvnflinger/consumer_base.cpp hle/service/nvnflinger/consumer_base.cpp
hle/service/nvnflinger/consumer_base.h hle/service/nvnflinger/consumer_base.h
hle/service/nvnflinger/consumer_listener.h hle/service/nvnflinger/consumer_listener.h
hle/service/nvnflinger/fb_share_buffer_manager.cpp
hle/service/nvnflinger/fb_share_buffer_manager.h
hle/service/nvnflinger/graphic_buffer_producer.cpp hle/service/nvnflinger/graphic_buffer_producer.cpp
hle/service/nvnflinger/graphic_buffer_producer.h hle/service/nvnflinger/graphic_buffer_producer.h
hle/service/nvnflinger/hos_binder_driver_server.cpp
hle/service/nvnflinger/hos_binder_driver_server.h
hle/service/nvnflinger/hardware_composer.cpp hle/service/nvnflinger/hardware_composer.cpp
hle/service/nvnflinger/hardware_composer.h hle/service/nvnflinger/hardware_composer.h
hle/service/nvnflinger/hos_binder_driver.cpp
hle/service/nvnflinger/hos_binder_driver.h
hle/service/nvnflinger/hos_binder_driver_server.cpp
hle/service/nvnflinger/hos_binder_driver_server.h
hle/service/nvnflinger/hwc_layer.h hle/service/nvnflinger/hwc_layer.h
hle/service/nvnflinger/nvnflinger.cpp hle/service/nvnflinger/nvnflinger.cpp
hle/service/nvnflinger/nvnflinger.h hle/service/nvnflinger/nvnflinger.h
@ -815,12 +877,26 @@ add_library(core STATIC
hle/service/nvnflinger/pixel_format.h hle/service/nvnflinger/pixel_format.h
hle/service/nvnflinger/producer_listener.h hle/service/nvnflinger/producer_listener.h
hle/service/nvnflinger/status.h hle/service/nvnflinger/status.h
hle/service/nvnflinger/surface_flinger.cpp
hle/service/nvnflinger/surface_flinger.h
hle/service/nvnflinger/ui/fence.h hle/service/nvnflinger/ui/fence.h
hle/service/nvnflinger/ui/graphic_buffer.cpp hle/service/nvnflinger/ui/graphic_buffer.cpp
hle/service/nvnflinger/ui/graphic_buffer.h hle/service/nvnflinger/ui/graphic_buffer.h
hle/service/nvnflinger/window.h hle/service/nvnflinger/window.h
hle/service/olsc/daemon_controller.cpp
hle/service/olsc/daemon_controller.h
hle/service/olsc/native_handle_holder.cpp
hle/service/olsc/native_handle_holder.h
hle/service/olsc/olsc_service_for_application.cpp
hle/service/olsc/olsc_service_for_application.h
hle/service/olsc/olsc_service_for_system_service.cpp
hle/service/olsc/olsc_service_for_system_service.h
hle/service/olsc/olsc.cpp hle/service/olsc/olsc.cpp
hle/service/olsc/olsc.h hle/service/olsc/olsc.h
hle/service/olsc/remote_storage_controller.cpp
hle/service/olsc/remote_storage_controller.h
hle/service/olsc/transfer_task_list_controller.cpp
hle/service/olsc/transfer_task_list_controller.h
hle/service/omm/omm.cpp hle/service/omm/omm.cpp
hle/service/omm/omm.h hle/service/omm/omm.h
hle/service/omm/operation_mode_manager.cpp hle/service/omm/operation_mode_manager.cpp
@ -831,25 +907,44 @@ add_library(core STATIC
hle/service/omm/power_state_interface.h hle/service/omm/power_state_interface.h
hle/service/os/event.cpp hle/service/os/event.cpp
hle/service/os/event.h hle/service/os/event.h
hle/service/os/multi_wait.cpp
hle/service/os/multi_wait.h
hle/service/os/multi_wait_holder.cpp hle/service/os/multi_wait_holder.cpp
hle/service/os/multi_wait_holder.h hle/service/os/multi_wait_holder.h
hle/service/os/multi_wait_utils.h hle/service/os/multi_wait_utils.h
hle/service/os/multi_wait.cpp
hle/service/os/multi_wait.h
hle/service/os/mutex.cpp hle/service/os/mutex.cpp
hle/service/os/mutex.h hle/service/os/mutex.h
hle/service/pcie/pcie.cpp hle/service/pcie/pcie.cpp
hle/service/pcie/pcie.h hle/service/pcie/pcie.h
hle/service/pctl/parental_control_service_factory.cpp
hle/service/pctl/parental_control_service_factory.h
hle/service/pctl/parental_control_service.cpp
hle/service/pctl/parental_control_service.h
hle/service/pctl/pctl.cpp hle/service/pctl/pctl.cpp
hle/service/pctl/pctl.h hle/service/pctl/pctl.h
hle/service/pctl/pctl_module.cpp hle/service/pctl/pctl_results.h
hle/service/pctl/pctl_module.h hle/service/pctl/pctl_types.h
hle/service/pcv/pcv.cpp hle/service/pcv/pcv.cpp
hle/service/pcv/pcv.h hle/service/pcv/pcv.h
hle/service/pm/pm.cpp hle/service/pm/pm.cpp
hle/service/pm/pm.h hle/service/pm/pm.h
hle/service/prepo/prepo.cpp hle/service/prepo/prepo.cpp
hle/service/prepo/prepo.h hle/service/prepo/prepo.h
hle/service/psc/ovln/ovln_types.h
hle/service/psc/ovln/receiver_service.cpp
hle/service/psc/ovln/receiver_service.h
hle/service/psc/ovln/receiver.cpp
hle/service/psc/ovln/receiver.h
hle/service/psc/ovln/sender_service.cpp
hle/service/psc/ovln/sender_service.h
hle/service/psc/ovln/sender.cpp
hle/service/psc/ovln/sender.h
hle/service/psc/pm_control.cpp
hle/service/psc/pm_control.h
hle/service/psc/pm_module.cpp
hle/service/psc/pm_module.h
hle/service/psc/pm_service.cpp
hle/service/psc/pm_service.h
hle/service/psc/psc.cpp hle/service/psc/psc.cpp
hle/service/psc/psc.h hle/service/psc/psc.h
hle/service/psc/time/alarms.cpp hle/service/psc/time/alarms.cpp
@ -873,15 +968,17 @@ add_library(core STATIC
hle/service/psc/time/common.cpp hle/service/psc/time/common.cpp
hle/service/psc/time/common.h hle/service/psc/time/common.h
hle/service/psc/time/errors.h hle/service/psc/time/errors.h
hle/service/psc/time/shared_memory.cpp
hle/service/psc/time/shared_memory.h
hle/service/psc/time/static.cpp
hle/service/psc/time/static.h
hle/service/psc/time/manager.h hle/service/psc/time/manager.h
hle/service/psc/time/power_state_request_manager.cpp
hle/service/psc/time/power_state_request_manager.h
hle/service/psc/time/power_state_service.cpp hle/service/psc/time/power_state_service.cpp
hle/service/psc/time/power_state_service.h hle/service/psc/time/power_state_service.h
hle/service/psc/time/service_manager.cpp hle/service/psc/time/service_manager.cpp
hle/service/psc/time/service_manager.h hle/service/psc/time/service_manager.h
hle/service/psc/time/shared_memory.cpp
hle/service/psc/time/shared_memory.h
hle/service/psc/time/static.cpp
hle/service/psc/time/static.h
hle/service/psc/time/steady_clock.cpp hle/service/psc/time/steady_clock.cpp
hle/service/psc/time/steady_clock.h hle/service/psc/time/steady_clock.h
hle/service/psc/time/system_clock.cpp hle/service/psc/time/system_clock.cpp
@ -890,8 +987,6 @@ add_library(core STATIC
hle/service/psc/time/time_zone.h hle/service/psc/time/time_zone.h
hle/service/psc/time/time_zone_service.cpp hle/service/psc/time/time_zone_service.cpp
hle/service/psc/time/time_zone_service.h hle/service/psc/time/time_zone_service.h
hle/service/psc/time/power_state_request_manager.cpp
hle/service/psc/time/power_state_request_manager.h
hle/service/ptm/psm.cpp hle/service/ptm/psm.cpp
hle/service/ptm/psm.h hle/service/ptm/psm.h
hle/service/ptm/ptm.cpp hle/service/ptm/ptm.cpp
@ -908,19 +1003,21 @@ add_library(core STATIC
hle/service/server_manager.h hle/service/server_manager.h
hle/service/service.cpp hle/service/service.cpp
hle/service/service.h hle/service/service.h
hle/service/set/setting_formats/appln_settings.cpp hle/service/services.cpp
hle/service/set/setting_formats/appln_settings.h hle/service/services.h
hle/service/set/setting_formats/device_settings.cpp
hle/service/set/setting_formats/device_settings.h
hle/service/set/setting_formats/system_settings.cpp
hle/service/set/setting_formats/system_settings.h
hle/service/set/setting_formats/private_settings.cpp
hle/service/set/setting_formats/private_settings.h
hle/service/set/factory_settings_server.cpp hle/service/set/factory_settings_server.cpp
hle/service/set/factory_settings_server.h hle/service/set/factory_settings_server.h
hle/service/set/firmware_debug_settings_server.cpp hle/service/set/firmware_debug_settings_server.cpp
hle/service/set/firmware_debug_settings_server.h hle/service/set/firmware_debug_settings_server.h
hle/service/set/key_code_map.h hle/service/set/key_code_map.h
hle/service/set/setting_formats/appln_settings.cpp
hle/service/set/setting_formats/appln_settings.h
hle/service/set/setting_formats/device_settings.cpp
hle/service/set/setting_formats/device_settings.h
hle/service/set/setting_formats/private_settings.cpp
hle/service/set/setting_formats/private_settings.h
hle/service/set/setting_formats/system_settings.cpp
hle/service/set/setting_formats/system_settings.h
hle/service/set/settings.cpp hle/service/set/settings.cpp
hle/service/set/settings.h hle/service/set/settings.h
hle/service/set/settings_server.cpp hle/service/set/settings_server.cpp
@ -955,30 +1052,36 @@ add_library(core STATIC
hle/service/ssl/ssl_backend.h hle/service/ssl/ssl_backend.h
hle/service/usb/usb.cpp hle/service/usb/usb.cpp
hle/service/usb/usb.h hle/service/usb/usb.h
hle/service/vi/display/vi_display.cpp
hle/service/vi/display/vi_display.h
hle/service/vi/layer/vi_layer.cpp
hle/service/vi/layer/vi_layer.h
hle/service/vi/application_display_service.cpp hle/service/vi/application_display_service.cpp
hle/service/vi/application_display_service.h hle/service/vi/application_display_service.h
hle/service/vi/application_root_service.cpp hle/service/vi/application_root_service.cpp
hle/service/vi/application_root_service.h hle/service/vi/application_root_service.h
hle/service/vi/hos_binder_driver.cpp hle/service/vi/conductor.cpp
hle/service/vi/hos_binder_driver.h hle/service/vi/conductor.h
hle/service/vi/container.cpp
hle/service/vi/container.h
hle/service/vi/display.h
hle/service/vi/display_list.h
hle/service/vi/layer.h
hle/service/vi/layer_list.h
hle/service/vi/manager_display_service.cpp hle/service/vi/manager_display_service.cpp
hle/service/vi/manager_display_service.h hle/service/vi/manager_display_service.h
hle/service/vi/manager_root_service.cpp hle/service/vi/manager_root_service.cpp
hle/service/vi/manager_root_service.h hle/service/vi/manager_root_service.h
hle/service/vi/service_creator.cpp hle/service/vi/service_creator.cpp
hle/service/vi/service_creator.h hle/service/vi/service_creator.h
hle/service/vi/shared_buffer_manager.cpp
hle/service/vi/shared_buffer_manager.h
hle/service/vi/system_display_service.cpp hle/service/vi/system_display_service.cpp
hle/service/vi/system_display_service.h hle/service/vi/system_display_service.h
hle/service/vi/system_root_service.cpp hle/service/vi/system_root_service.cpp
hle/service/vi/system_root_service.h hle/service/vi/system_root_service.h
hle/service/vi/vi_results.h
hle/service/vi/vi_types.h
hle/service/vi/vi.cpp hle/service/vi/vi.cpp
hle/service/vi/vi.h hle/service/vi/vi.h
hle/service/vi/vi_results.h
hle/service/vi/vi_types.h
hle/service/vi/vsync_manager.cpp
hle/service/vi/vsync_manager.h
internal_network/network.cpp internal_network/network.cpp
internal_network/network.h internal_network/network.h
internal_network/network_interface.cpp internal_network/network_interface.cpp

View File

@ -47,6 +47,7 @@
#include "core/hle/service/psc/time/system_clock.h" #include "core/hle/service/psc/time/system_clock.h"
#include "core/hle/service/psc/time/time_zone_service.h" #include "core/hle/service/psc/time/time_zone_service.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/hle/service/services.h"
#include "core/hle/service/set/system_settings_server.h" #include "core/hle/service/set/system_settings_server.h"
#include "core/hle/service/sm/sm.h" #include "core/hle/service/sm/sm.h"
#include "core/internal_network/network.h" #include "core/internal_network/network.h"
@ -310,7 +311,8 @@ struct System::Impl {
audio_core = std::make_unique<AudioCore::AudioCore>(system); audio_core = std::make_unique<AudioCore::AudioCore>(system);
service_manager = std::make_shared<Service::SM::ServiceManager>(kernel); service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
services = std::make_unique<Service::Services>(service_manager, system); services =
std::make_unique<Service::Services>(service_manager, system, stop_event.get_token());
is_powered_on = true; is_powered_on = true;
exit_locked = false; exit_locked = false;
@ -458,11 +460,10 @@ struct System::Impl {
gpu_core->NotifyShutdown(); gpu_core->NotifyShutdown();
} }
stop_event.request_stop();
core_timing.SyncPause(false);
Network::CancelPendingSocketOperations(); Network::CancelPendingSocketOperations();
kernel.SuspendEmulation(true); kernel.SuspendEmulation(true);
if (services) {
services->KillNVNFlinger();
}
kernel.CloseServices(); kernel.CloseServices();
kernel.ShutdownCores(); kernel.ShutdownCores();
applet_manager.Reset(); applet_manager.Reset();
@ -480,6 +481,7 @@ struct System::Impl {
cpu_manager.Shutdown(); cpu_manager.Shutdown();
debugger.reset(); debugger.reset();
kernel.Shutdown(); kernel.Shutdown();
stop_event = {};
Network::RestartSocketOperations(); Network::RestartSocketOperations();
if (auto room_member = room_network.GetRoomMember().lock()) { if (auto room_member = room_network.GetRoomMember().lock()) {
@ -615,6 +617,7 @@ struct System::Impl {
ExecuteProgramCallback execute_program_callback; ExecuteProgramCallback execute_program_callback;
ExitCallback exit_callback; ExitCallback exit_callback;
std::stop_source stop_event;
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{}; std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};

View File

@ -199,10 +199,10 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) {
data.host_context = Common::Fiber::ThreadToFiber(); data.host_context = Common::Fiber::ThreadToFiber();
// Cleanup // Cleanup
SCOPE_EXIT({ SCOPE_EXIT {
data.host_context->Exit(); data.host_context->Exit();
MicroProfileOnThreadExit(); MicroProfileOnThreadExit();
}); };
// Running // Running
if (!gpu_barrier->Sync(token)) { if (!gpu_barrier->Sync(token)) {

View File

@ -391,12 +391,12 @@ void DeviceMemoryManager<Traits>::WalkBlock(DAddr addr, std::size_t size, auto o
std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size); std::min((next_pages << Memory::YUZU_PAGEBITS) - page_offset, remaining_size);
const auto current_vaddr = const auto current_vaddr =
static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset); static_cast<u64>((page_index << Memory::YUZU_PAGEBITS) + page_offset);
SCOPE_EXIT({ SCOPE_EXIT{
page_index += next_pages; page_index += next_pages;
page_offset = 0; page_offset = 0;
increment(copy_amount); increment(copy_amount);
remaining_size -= copy_amount; remaining_size -= copy_amount;
}); };
auto phys_addr = compressed_physical_ptr[page_index]; auto phys_addr = compressed_physical_ptr[page_index];
if (phys_addr == 0) { if (phys_addr == 0) {

View File

@ -64,8 +64,8 @@ struct RawNACP {
u64_le cache_storage_size; u64_le cache_storage_size;
u64_le cache_storage_journal_size; u64_le cache_storage_journal_size;
u64_le cache_storage_data_and_journal_max_size; u64_le cache_storage_data_and_journal_max_size;
u64_le cache_storage_max_index; u16_le cache_storage_max_index;
INSERT_PADDING_BYTES(0xE70); INSERT_PADDING_BYTES(0xE76);
}; };
static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size."); static_assert(sizeof(RawNACP) == 0x4000, "RawNACP has incorrect size.");

View File

@ -3,6 +3,10 @@
#pragma once #pragma once
#include <string_view>
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace FileSys { namespace FileSys {
constexpr inline size_t EntryNameLengthMax = 0x300; constexpr inline size_t EntryNameLengthMax = 0x300;

View File

@ -23,6 +23,8 @@ enum class OpenDirectoryMode : u64 {
File = (1 << 1), File = (1 << 1),
All = (Directory | File), All = (Directory | File),
NotRequireFileSize = (1ULL << 31),
}; };
DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode) DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode)
@ -36,4 +38,29 @@ enum class CreateOption : u8 {
BigFile = (1 << 0), BigFile = (1 << 0),
}; };
struct FileSystemAttribute {
u8 dir_entry_name_length_max_defined;
u8 file_entry_name_length_max_defined;
u8 dir_path_name_length_max_defined;
u8 file_path_name_length_max_defined;
INSERT_PADDING_BYTES_NOINIT(0x5);
u8 utf16_dir_entry_name_length_max_defined;
u8 utf16_file_entry_name_length_max_defined;
u8 utf16_dir_path_name_length_max_defined;
u8 utf16_file_path_name_length_max_defined;
INSERT_PADDING_BYTES_NOINIT(0x18);
s32 dir_entry_name_length_max;
s32 file_entry_name_length_max;
s32 dir_path_name_length_max;
s32 file_path_name_length_max;
INSERT_PADDING_WORDS_NOINIT(0x5);
s32 utf16_dir_entry_name_length_max;
s32 utf16_file_entry_name_length_max;
s32 utf16_dir_path_name_length_max;
s32 utf16_file_path_name_length_max;
INSERT_PADDING_WORDS_NOINIT(0x18);
INSERT_PADDING_WORDS_NOINIT(0x1);
};
static_assert(sizeof(FileSystemAttribute) == 0xC0, "FileSystemAttribute has incorrect size");
} // namespace FileSys } // namespace FileSys

View File

@ -10,7 +10,7 @@ namespace FileSys {
constexpr size_t RequiredAlignment = alignof(u64); constexpr size_t RequiredAlignment = alignof(u64);
void* AllocateUnsafe(size_t size) { inline void* AllocateUnsafe(size_t size) {
// Allocate // Allocate
void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment}); void* const ptr = ::operator new(size, std::align_val_t{RequiredAlignment});
@ -21,16 +21,16 @@ void* AllocateUnsafe(size_t size) {
return ptr; return ptr;
} }
void DeallocateUnsafe(void* ptr, size_t size) { inline void DeallocateUnsafe(void* ptr, size_t size) {
// Deallocate the pointer // Deallocate the pointer
::operator delete(ptr, std::align_val_t{RequiredAlignment}); ::operator delete(ptr, std::align_val_t{RequiredAlignment});
} }
void* Allocate(size_t size) { inline void* Allocate(size_t size) {
return AllocateUnsafe(size); return AllocateUnsafe(size);
} }
void Deallocate(void* ptr, size_t size) { inline void Deallocate(void* ptr, size_t size) {
// If the pointer is non-null, deallocate it // If the pointer is non-null, deallocate it
if (ptr != nullptr) { if (ptr != nullptr) {
DeallocateUnsafe(ptr, size); DeallocateUnsafe(ptr, size);

View File

@ -381,7 +381,7 @@ public:
// Check that it's possible for us to remove a child // Check that it's possible for us to remove a child
auto* p = m_write_buffer.Get(); auto* p = m_write_buffer.Get();
s32 len = std::strlen(p); s32 len = static_cast<s32>(std::strlen(p));
R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented); R_UNLESS(len != 1 || (p[0] != '/' && p[0] != '.'), ResultNotImplemented);
// Handle a trailing separator // Handle a trailing separator

Some files were not shown because too many files have changed in this diff Show More