Compare commits

..

200 Commits

Author SHA1 Message Date
Emmanuel Hansen
0f1b737b07 android - close file handles in performance monitor 2024-01-22 22:55:54 +00:00
Emmanuel Hansen
29332c44ab fix nce bad rebase 2024-01-22 22:55:54 +00:00
Emmanuel Hansen
e926499e32 android - add performance stats 2024-01-22 22:55:50 +00:00
Emmanuel Hansen
96c4edb697 android - set isStarted check early 2024-01-22 22:55:49 +00:00
Emmanuel Hansen
ba3438f24a fix arm jit rebase 2024-01-22 22:55:48 +00:00
Emmanuel Hansen
956c5fe4fd android - update dependencies 2024-01-22 22:55:46 +00:00
Emmanuel Hansen
15baf43a7c fix rebase 2024-01-22 22:55:45 +00:00
Emmanuel Hansen
aec0b99f8a remove dotnet previews nuget source 2024-01-22 22:55:44 +00:00
Isaac Marovitz
16f77936e0 Start GameInfoNative 2024-01-22 22:55:44 +00:00
Isaac Marovitz
5f18d19f23 Expand InitializeDeviceNative Signature 2024-01-22 22:55:44 +00:00
Isaac Marovitz
29a0c1caed Expose InstallFirmware 2024-01-22 22:55:43 +00:00
Isaac Marovitz
97e3fc60ca Expose GetInstalledFirmwareVersion 2024-01-22 22:55:43 +00:00
Isaac Marovitz
1a4f506991 Don’t crash if no firmware is installed 2024-01-22 22:55:43 +00:00
Isaac Marovitz
af4f7b9ee7 Expose Accelerometer & Gyro Functions 2024-01-22 22:55:43 +00:00
Isaac Marovitz
a6a75a4208 iOS - Disable StdErrAdapter
Enabling fills the logs with uneeded spam
2024-01-22 22:55:42 +00:00
Isaac Marovitz
d6e88e3cc9 iOS - Set Silk.NET SearchPathContainer 2024-01-22 22:55:42 +00:00
Isaac Marovitz
66e58aa6a7 iOS - Platform Checks
Co-authored-by: riperiperi <rhy3756547@hotmail.com>
2024-01-22 22:55:42 +00:00
Isaac Marovitz
5d919039d9 iOS - Linker Fixes 2024-01-22 22:55:42 +00:00
Emmanuel Hansen
cdf188a434 android - change game stats background color 2024-01-22 22:55:41 +00:00
Emmanuel Hansen
f403484276 android - move title updates support to SAF 2024-01-22 22:55:41 +00:00
Emmanuel Hansen
7955b4f287 android - fix dpad input on generic android controllers 2024-01-22 22:55:41 +00:00
Emmanuel Hansen
047ee4554e android - remote developer name from grid items 2024-01-22 22:55:41 +00:00
Emmanuel Hansen
e0c5953ce0 android - add option to disable motion 2024-01-22 22:55:41 +00:00
Emmanuel Hansen
b81643352e android - add basic software keyboard support 2024-01-22 22:55:40 +00:00
Emmanuel Hansen
c12da6d650 android - add option to swap button layouts to nintendo style 2024-01-22 22:55:40 +00:00
Emmanuel Hansen
c74ad70c3d android - set controller event as handled 2024-01-22 22:55:40 +00:00
Emmanuel Hansen
1ea1a0ba68 android - fix stick showing as dpad 2024-01-22 22:55:40 +00:00
Emmanuel Hansen
8e25994391 android - add hack to fix orientation issue 2024-01-22 22:55:40 +00:00
Emmanuel Hansen
52f5142305 android - fix settings app action buttons. fix dlc manager add button missing 2024-01-22 22:55:39 +00:00
Emmanuel Hansen
80d1ac212e android - ensure controller respects users controller visibility settings at launch 2024-01-22 22:55:39 +00:00
TSR Berry
a8fcf22b89 cmake: Use FetchContent to include adrenotools 2024-01-22 22:55:39 +00:00
Emmanuel Hansen
aa87b4abd8 android - implement firmware installation 2024-01-22 22:55:39 +00:00
Emmanuel Hansen
60f320bc07 android - add motion support 2024-01-22 22:55:38 +00:00
Emmanuel Hansen
521403b0ea android - add support for nro 2024-01-22 22:55:38 +00:00
Emmanuel Hansen
9680ecd820 android - allow sensor to change orientation during emulation 2024-01-22 22:55:38 +00:00
Emmanuel Hansen
3bc415053e android - add button to open ryujinx app folder 2024-01-22 22:55:38 +00:00
Emmanuel Hansen
e7ac8bf333 android - add log settings 2024-01-22 22:55:38 +00:00
Emmanuel Hansen
819c7671bb android - add log export, providers to browse app data 2024-01-22 22:55:37 +00:00
Emmanuel Hansen
990ad3d133 android - bump version 2024-01-22 22:55:37 +00:00
Emmanuel Hansen
923d0a5bd1 android - bump version 2024-01-22 22:55:37 +00:00
Emmanuel Hansen
024a6cdbb2 android - set nativeaot instruction set support 2024-01-22 22:55:37 +00:00
Emmanuel Hansen
5028673968 android - reload list if game folder changed, fix game updates scanning 2024-01-22 22:55:36 +00:00
Emmanuel Hansen
d7b139a4a8 update opentk packages 2024-01-22 22:55:36 +00:00
Emmanuel Hansen
9765f7a388 android - adjust grid view design, remove bottom app bar 2024-01-22 22:55:35 +00:00
Emmanuel Hansen
bc6e5de507 android - add grid list option 2024-01-22 22:55:35 +00:00
Emmanuel Hansen
e5d54d5374 rebase with upstream 2024-01-22 22:55:35 +00:00
Emmanuel Hansen
038ee1a6dd android - remove oboe 2024-01-22 22:55:34 +00:00
Emmanuel Hansen
c6e2e16e0b android - bumb version, rebase over master 2024-01-22 22:55:34 +00:00
Emmanuel Hansen
74f45c486f android - bumb version 2024-01-22 22:55:33 +00:00
Emmanuel Hansen
4fc253384b android - fixes a few crashes in the user and home views 2024-01-22 22:55:33 +00:00
Emmanuel Hansen
71f3d22db8 android - add string map 2024-01-22 22:55:33 +00:00
Emmanuel Hansen
fdb7320031 android - drop game activity, replace with compose view 2024-01-22 22:55:33 +00:00
Emmanuel Hansen
f6850bcc1a rebase fix 2024-01-22 22:55:32 +00:00
Emmanuel Hansen
946079f5e3 android - make settings view scrollable, bump version 2024-01-22 22:55:32 +00:00
Emmanuel Hansen
14d6e280f7 android - improve game update selection 2024-01-22 22:55:31 +00:00
Emmanuel Hansen
2240d87902 android - fix crash when no user is available at launch 2024-01-22 22:55:31 +00:00
Emmanuel Hansen
5b1a928e1b android - add crash handler 2024-01-22 22:55:31 +00:00
Emmanuel Hansen
04850674d0 android - fix game update icon, add app icon 2024-01-22 22:55:31 +00:00
Emmanuel Hansen
f560431792 android - fix app menu 2024-01-22 22:55:31 +00:00
Emmanuel Hansen
ba745514a1 android - add basic user management 2024-01-22 22:55:30 +00:00
Emmanuel Hansen
8e2eb5fd26 clean main ui, add option to import app data 2024-01-22 22:55:30 +00:00
Emmanuel Hansen
34e52880da load firmware version at launch 2024-01-22 22:55:30 +00:00
Emmanuel Hansen
a2b7dc5aca update to rc2, rebase update rd 2024-01-22 22:55:30 +00:00
Emmanuel Hansen
28af479e2a improve async loading. add game load progress 2024-01-22 22:55:30 +00:00
Emmanuel Hansen
c0091c838d use file descriptors to load game list 2024-01-22 22:55:30 +00:00
Emmanuel Hansen
4c0d21ede4 sanitize stick input 2024-01-22 22:55:30 +00:00
Gabriel A
e3a81cfdee Extend Adreno binding workaround to buffer textures 2024-01-22 22:55:29 +00:00
Gabriel A
698ac0413b Support ballot operations with divergent control flow on Adreno 2024-01-22 22:55:29 +00:00
Emmanuel Hansen
dca4091930 don't request storage usage for surface on bionic 2024-01-22 22:55:28 +00:00
Gabriel A
f1814ca542 Add spin lock to prevent waiting for fences on multiple threads at once on Adreno 2024-01-22 22:55:28 +00:00
Emmanuel Hansen
3e6ec4aea8 fix rd.xml 2024-01-22 22:55:28 +00:00
Emmanuel Hansen
fdc5ceea41 fix rebase 2024-01-22 22:55:28 +00:00
Emmanuel Hansen
091d9d4546 create a copy of updates when added 2024-01-22 22:55:28 +00:00
Emmanuel Hansen
7a2fadb499 some optimizations. apply current transform to native window instead of defaulting to Identity 2024-01-22 22:55:28 +00:00
Emmanuel Hansen
c732a9fbb6 enable hardware accel for activity 2024-01-22 22:55:28 +00:00
Emmanuel Hansen
6f48a6a24d reduced virtual controller deadzone 2024-01-22 22:55:27 +00:00
Emmanuel Hansen
e6ceb70114 fix manifest error 2024-01-22 22:55:27 +00:00
Emmanuel Hansen
83c9e4fcb2 move game view to new activity 2024-01-22 22:55:27 +00:00
Emmanuel Hansen
8c0bd460d9 add bottom popup ingame 2024-01-22 22:55:27 +00:00
Emmanuel Hansen
0bf93ef754 add game searching 2024-01-22 22:55:27 +00:00
Emmanuel Hansen
8f8f9e996a switch to using stream base game loading 2024-01-22 22:55:26 +00:00
TSR Berry
3f8d269719 Fix gradle build issues when multiple configurations are present 2024-01-22 22:55:26 +00:00
TSR Berry
6a8fce261e Update Android gradle plugins 2024-01-22 22:55:26 +00:00
Emmanuel Hansen
44315541c3 fix AsFlags rename conflict 2024-01-22 22:55:26 +00:00
Emmanuel Hansen
7a85dc2e76 add dlc manager 2024-01-22 22:55:26 +00:00
Emmanuel Hansen
fb562c8077 safely close audio on game exit 2024-01-22 22:55:26 +00:00
Emmanuel Hansen
2999275ed2 add closing emulation(starting a new one is still broken), disabled audio 2024-01-22 22:55:25 +00:00
Emmanuel Hansen
a050e5c6c0 separate game loading from surface creation 2024-01-22 22:55:25 +00:00
Emmanuel Hansen
398fb78a31 refactor virtual pad composition 2024-01-22 22:55:25 +00:00
Emmanuel Hansen
f0b0f3b796 fix unzip code 2024-01-22 22:55:25 +00:00
Emmanuel Hansen
7d7e1ce639 fix adreno hooking 2024-01-22 22:55:25 +00:00
Emmanuel Hansen
f8c1e745ca fix adreno hooking 2024-01-22 22:55:25 +00:00
Emmanuel Hansen
a0c9d3b7de restore driver selection 2024-01-22 22:55:24 +00:00
Emmanuel Hansen
108fb2380a test 2024-01-22 22:55:24 +00:00
Emmanuel Hansen
9b4d988d8c add adrenotools module 2024-01-22 22:55:24 +00:00
TSR Berry
fae788f698 Replace Helpers.getPath() with file.getAbsolutePath() 2024-01-22 22:55:24 +00:00
TSR Berry
fa16c9c3bd Add more debug information when loading game files 2024-01-22 22:55:23 +00:00
TSR Berry
979db1def3 Cleanup RyujinxAndroid 2024-01-22 22:55:23 +00:00
TSR Berry
300b23cf9b Cleanup LibRyujinx and add more verbose logging 2024-01-22 22:55:23 +00:00
TSR Berry
ee4e18ff0d Fix PATH variable on Windows
I spent ~7 hours debugging this.
I searched for a bug in the Exec task and found nothing.
I tried different ways to invoke the dotnet command
to make sure PATH is always set before.
I also modified Microsoft.NETCore.Native.Unix.targets to echo PATH via Exec and via Text.
But in the end I was confused about seeing two PATH variables
when checking the dotnet.exe subprocess with ProcessHacker.
This made me try setting the Path variable instead of PATH
and to my surprise this just worked.
Turns out Windows environment variables are case-sensitive and
Windows uses Path instead of PATH like Unix.

God, I love Microsoft Windows. :)
2024-01-22 22:55:22 +00:00
TSR Berry
14cf6efa60 Add toolchain path to output 2024-01-22 22:55:22 +00:00
TSR Berry
35641ee3ca Only build LibRyujinx if source or project files changed 2024-01-22 22:55:22 +00:00
TSR Berry
853ef9ff8f Fix OS detection 2024-01-22 22:55:22 +00:00
TSR Berry
03ec861e03 Make dotnet executable path configurable 2024-01-22 22:55:21 +00:00
TSR Berry
9d8e02dd0e Add toolchain path to all operating systems correctly 2024-01-22 22:55:21 +00:00
TSR Berry
733f13fe0e Add preBuild dependency on libryujinx for app 2024-01-22 22:55:21 +00:00
TSR Berry
5070e14317 Suppress Google Play permission warning 2024-01-22 22:55:21 +00:00
TSR Berry
c247830f78 Fix AndroidManifest.xml warnings 2024-01-22 22:55:21 +00:00
TSR Berry
853b6f29ce Fix file trees 2024-01-22 22:55:21 +00:00
TSR Berry
4d2add5264 Preserve other jni libraries 2024-01-22 22:55:20 +00:00
TSR Berry
4728c1e96c Make stripSymbols a gradle property 2024-01-22 22:55:20 +00:00
TSR Berry
dd31c40f4e Raise minSdk to 30 to fix linter errors 2024-01-22 22:55:20 +00:00
TSR Berry
bda6617571 Update dependencies 2024-01-22 22:55:20 +00:00
TSR Berry
7fd44e32d0 Add gradle module for libryujinx 2024-01-22 22:55:16 +00:00
TSR Berry
fb592277a7 Keep libryujinx symbols 2024-01-22 22:55:15 +00:00
TSR Berry
826c64ddfe Switch to Java 17 LTS 2024-01-22 22:55:14 +00:00
TSR Berry
beba6d1422 Cleanup gitignore and project file structure 2024-01-22 22:55:13 +00:00
Emmanuel Hansen
5708f700ec remove safe area margins 2024-01-22 22:55:11 +00:00
Emmanuel Hansen
918b0fa302 fix touch, add toggle for virtual gamepad 2024-01-22 22:55:11 +00:00
Emmanuel Hansen
ffaa4d8ac1 expand full screen to behind cutouts 2024-01-22 22:55:11 +00:00
Emmanuel Hansen
ff3099e4a1 add performance hints 2024-01-22 22:55:11 +00:00
Emmanuel Hansen
61ba5e7bff add physical controller support 2024-01-22 22:55:10 +00:00
Gabriel A
4f1bf2d0cc Rebase fix: ReplayIfDirty was being called twice 2024-01-22 22:55:10 +00:00
Gabriel A
93cf57913c Remove address space mirror and tweak address space layout when host has small adress space 2024-01-22 22:55:10 +00:00
Gabriel A
2ad3605cdb Use alternate stack for the segfault handler too 2024-01-22 22:55:09 +00:00
Gabriel A
7925581e72 Ensure we don't set graphics state if there was no graphics pipeline bound before 2024-01-22 22:55:09 +00:00
Gabriel A
2814fa60bf Work around Adreno compute dispatch crash when changing grpahics state with a compute pipeline bound 2024-01-22 22:55:09 +00:00
Emmanuel Hansen
437bfdbd5a add native helper to create jni string 2024-01-22 22:55:09 +00:00
Gabriel A
375691b0e0 Allocate NCE patch region dynamically to avoid not having enough space 2024-01-22 22:55:08 +00:00
Emmanuel Hansen
517277a11f adjust game list item margins 2024-01-22 22:55:08 +00:00
Gabriel A
8e23eb88bb Rewrite NceAsmTable using dynamic generation instead to be more robust, fix bugs 2024-01-22 22:55:08 +00:00
Gabriel A
c694d5774d Fix incorrect AslrRegionStart when using NCE 2024-01-22 22:55:07 +00:00
Emmanuel Hansen
25b31b559a fix title updates again 2024-01-22 22:55:07 +00:00
Emmanuel Hansen
f3531394d5 fix title updates data being missing 2024-01-22 22:55:07 +00:00
Emmanuel Hansen
976514fdcc drop game stats class. directly call stats methods 2024-01-22 22:55:07 +00:00
Emmanuel Hansen
953559c71c initial work on multi driver selection 2024-01-22 22:55:06 +00:00
Emmanuel Hansen
d6ba9ad8f5 move android related file to subfolder 2024-01-22 22:55:06 +00:00
Emmanuel Hansen
4eb8e27517 fix native file logs 2024-01-22 22:55:05 +00:00
Emmanuel Hansen
6262bd1730 use int game controller ids 2024-01-22 22:55:05 +00:00
Emmanuel Hansen
e9c7564a03 add more options, fix vsync option 2024-01-22 22:55:05 +00:00
Emmanuel Hansen
7b1ce437ef add settings view 2024-01-22 22:55:05 +00:00
Gabriel A
21a78f173e Add work around for Adreno batched texture + sampler descriptor updates bug 2024-01-22 22:55:05 +00:00
Emmanuel Hansen
e54e18dab8 move android kotlin project over 2024-01-22 22:55:05 +00:00
Emmanuel Hansen
2d39deba26 add more parameters to initialize device 2024-01-22 22:55:04 +00:00
Emmanuel Hansen
28eb812018 add overload for loading game info from path 2024-01-22 22:55:04 +00:00
Emmanuel Hansen
9c510fec3e add android bionic nce support 2024-01-22 22:55:03 +00:00
gdk
44551a0409 Add back IsApplication flag 2024-01-22 22:55:03 +00:00
gdk
0970972f0d Add NCE code 2024-01-22 22:55:02 +00:00
gdk
a1e34041fa Minor refactoring of KPageTableBase to make custom address space layouts easier to implement 2024-01-22 22:55:01 +00:00
Emmanuel Hansen
c5bcdc06f5 add game stats helper 2024-01-22 22:55:01 +00:00
Emmanuel Hansen
c8d6f786c5 add option to enable debug logs 2024-01-22 22:55:01 +00:00
Emmanuel Hansen
c0a2cc5f6c disable optional logs 2024-01-22 22:54:59 +00:00
Emmanuel Hansen
db9111b895 add file logs 2024-01-22 22:54:58 +00:00
Emmanuel Hansen
159d1f0eae disable network change notification on bionic 2024-01-22 22:54:57 +00:00
Emmanuel Hansen
07caf24936 add steam based loaders 2024-01-22 22:54:57 +00:00
Emmanuel Hansen
56a6ac2a65 add interface fore loading games from storage 2024-01-22 22:54:56 +00:00
Emmanuel Hansen
145cd0b2b1 fix build on newer ndk versions 2024-01-22 22:54:56 +00:00
Emmanuel Hansen
333401b71d add helper to get new surface on android, still crashes when screen resizes 2024-01-22 22:54:55 +00:00
Emmanuel Hansen
5b9b17ef24 attempt to recreate surface if lost 2024-01-22 22:54:55 +00:00
Emmanuel Hansen
ba8028d1d0 add audio support for android 2024-01-22 22:54:55 +00:00
Emmanuel Hansen
a57cad5d5e add sdl audio backend as default audio 2024-01-22 22:54:54 +00:00
Emmanuel Hansen
9bb70e5ac2 enable release optimizations on aot 2024-01-22 22:54:54 +00:00
Emmanuel Hansen
416f40bddc remove spirv compilation option from native aot project 2024-01-22 22:54:54 +00:00
Emmanuel Hansen
3af84d0715 fix release bionic crash 2024-01-22 22:54:54 +00:00
Emmanuel Hansen
d988dfa781 use procontroller as default libryujinx controller type 2024-01-22 22:54:53 +00:00
Emmanuel Hansen
fd05b76554 make applet manager reflection free 2024-01-22 22:54:53 +00:00
Emmanuel Hansen
6828fe6270 fix android bionic log 2024-01-22 22:54:53 +00:00
Emmanuel Hansen
4d06f19fe7 add bionic nativeaot support 2024-01-22 22:54:52 +00:00
Emmanuel Hansen
ad0f9a7fc7 add helper for checking bionic 2024-01-22 22:54:52 +00:00
Mary
1835e16045 armeilleure: Do not call GCSettings.LargeObjectHeapCompactionMode on Android
Mono only support Default as argument and will throw otherwise.
2024-01-22 22:54:51 +00:00
Mary
0a666d9c5b armeilleure: Add Android to GetOSPlatform for PTC 2024-01-22 22:54:51 +00:00
Mary
b7d08e5050 armeilleure: Add Android signal handler 2024-01-22 22:54:51 +00:00
Mary
8a8db6244d armeilleure: Add support for Android in HardwareCapabilities 2024-01-22 22:54:51 +00:00
Mary
0b14eb3a61 memory: Add Android support 2024-01-22 22:54:50 +00:00
Emmanuel Hansen
c27a12df2c add basic touch and button input interface 2024-01-22 22:54:50 +00:00
Emmanuel Hansen
24b8d7c981 remove armeilleire reference in rd file 2024-01-22 22:54:50 +00:00
Emmanuel Hansen
8535b6c2f6 libryujinx - disable shader cache 2024-01-22 22:54:50 +00:00
Emmanuel Hansen
cb8837e1b8 remove redundant project reference 2024-01-22 22:54:49 +00:00
gdk
0e3c224b8d Make GetFunctionPointerForDelegate as explicit as possible 2024-01-22 22:54:49 +00:00
Emmanuel Hansen
1694303e4c add nativaot libryujinx project 2024-01-22 22:54:49 +00:00
Emmanuel Hansen
cea50d80c9 remove usage of reflection in device state 2024-01-22 22:54:49 +00:00
Emmanuel Hansen
c3a3adbaeb add hle service generator 2024-01-22 22:54:49 +00:00
gdkchan
4df22eb867
Fix missing data for new copy dependency textures with mismatching size (#6161) 2024-01-22 17:42:26 -03:00
gdkchan
f241f88558
Add a separate device memory manager (#6153)
* Add a separate device memory manager

* Still need this

* Device writes are always tracked

* Device writes are always tracked (2)

* Rename more instances of gmm to mm
2024-01-22 17:14:46 -03:00
riperiperi
90455a05e6
Input: Improve controller identification (#6029)
* Input: Improve controller identification

Controllers were identified before by a combination of their _global_ index in the list of controllers and their GUID. The problem is, disconnecting and reconnecting a controller can change its global index; the controller can appear at the end. This would give it another ID, and the controller would need to be reconfigured.

This happened to me a lot with a switch pro controller and a USB game controller, it was essentially random which appeared first. Now, it consistently detects them.

This PR changes the controller identification to be a combination of an index of controllers with the same GUID (generally 0), and its GUID. It also reworks managing the list of controllers to properly consider instance IDs.

This also changes the NpadManager to attempt to reuse old controllers when refreshing input configuration, which can prevent input from going dead for seconds whenever a controller connects or disconnects (and the switch pro controller just entirely dying).

Testing with different controller types, OS and Avalonia is welcome. Remember that the target is connecting a ton of controllers, and pulling/reconnecting them.

* Remove double empty line
2024-01-22 17:02:44 -03:00
gdkchan
edc76883db
Fix integer overflow on downsample surround to stereo (#6160) 2024-01-21 21:11:46 +01:00
gdkchan
427b7d06b5
Implement a new JIT for Arm devices (#6057)
* Implement a new JIT for Arm devices

* Auto-format

* Make a lot of Assembler members read-only

* More read-only

* Fix more warnings

* ObjectDisposedException.ThrowIf

* New JIT cache for platforms that enforce W^X, currently unused

* Remove unused using

* Fix assert

* Pass memory manager type around

* Safe memory manager mode support + other improvements

* Actual safe memory manager mode masking support

* PR feedback
2024-01-20 11:11:28 -03:00
riperiperi
331c07807f
Vulkan: Use templates for descriptor updates (#6014)
* WIP: Descriptor template update

* Make configurable

* Wording

* Simplify template creation

* Whitespace

* UTF-8 whatever

* Leave only templated path, better template updater
2024-01-20 11:07:33 -03:00
Steveice10
a772b073ec
Support portable mode using the macOS app bundle. (#6147)
* Support portable mode using the macOS app bundle.

* Apply suggestion

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

---------

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
2024-01-20 03:09:51 +01:00
gdkchan
870d9599cc
Change shader cache init wait method (#6131)
* Change shader cache init wait method

* Make field readonly
2024-01-18 14:17:38 -03:00
gdkchan
2dbbc9bc05
Move most of signal handling to Ryujinx.Cpu project (#6128)
* Move most of signal handling to Ryujinx.Cpu project

* Format whitespace

* Remove unused member

* Format whitespace

* This does not need to be public anymore
2024-01-18 14:08:40 -03:00
Isaac Marovitz
72634c80f4
Ava UI: Update Ava & Friends (#6109)
* Update Ava & Friends

* FA 2.0.5

* Ava 11.0.7

* Fix
2024-01-17 23:50:31 +01:00
riperiperi
bebd8eb822
Vulkan: Cache delegate for EndRenderPass (#6132)
This prevents a small allocation each time this method is called. This is a top 3 SOH allocation during gameplay in most games, and eliminating it is pretty free.
2024-01-16 13:22:20 +01:00
gdkchan
f4b74e9ce1
Fix vertex buffer size when switching between inline and state draw parameters (#6101)
* Fix vertex buffer size when switching between inline and state draw parameters

* Format whitespace
2024-01-14 09:37:19 +01:00
Isaac Marovitz
4e19b36ad7
CI: Dependabot Groups (#6110)
* CI: Dependabot Groups

* NUnit

* Limit of 10

* Whoops

* Missing wildcard

* Remove Ryujank group
2024-01-13 15:28:57 +01:00
gdkchan
b16923a902
Revert Apple hypervisor force ordered memory change (#6068) 2024-01-13 11:58:09 +01:00
TSRBerry
7e58b21f3d
Fix Amiibo regression and some minor code improvements (#6107)
* Remove redundant code and fix small issues

* Log amiibo exceptions

* Add more checks when getting Amiibo data

* Fall back to online data if local file is inaccessible

* Make dotnet format happy
2024-01-13 11:45:38 +01:00
Isaac Marovitz
4fbc978e73
Switch to Microsoft.IdentityModel.JsonWebTokens (#6108)
* Switch to `Microsoft.IdentityModel.JsonWebTokens`

* Formatting
2024-01-13 11:39:00 +01:00
Isaac Marovitz
1a45dc8df8
Ava UI: RTL Language Support (#5619)
* Add Hebrew locale files to ItemGroups

* Align all windows RTL for testing

This should be controlled with a binding that selects the appropriate layout based on current language

* Update FlowDirection as Locale changes

* Fix Settings NavigationViewItem FlowDirection

* Fix remaining text

* Fix input menu directionality

* Fix RTL not rendering

* Fix rebase errors
2024-01-13 01:42:42 +01:00
Isaac Marovitz
f037fcba9a
Ava UI: Better Controller Applet (#5756)
* Start work on better Controller Applet

* Don’t require title

* UI improvements

* Border around TBD area

* Formatting

* Better SVGs

* Add missing margin

* Use Locale

* Rename function

* Make buttons ourselves

* Make the buttons do shit

* Formatting

* Adjust SVGs

* Fix Open Settings Window

* Make field readonly

* Final tweaks

* Update src/Ryujinx.Ava/UI/Applet/AvaHostUiHandler.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update src/Ryujinx.Ava/UI/Applet/ControllerAppletDialog.axaml.cs

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

* Update src/Ryujinx.Ava/UI/Applet/ControllerAppletDialog.axaml.cs

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

* Move icons to Ava project

* Reorder arguments

* Try to focus Settings Window

* Fix icons

Project shenangians

* Add ContentDialogHelper.ShowWindowAsync method

* Fix closed SettingsWindow reference in MainWindow

* Fix SettingsWindow dialog

* Suggestion

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
2024-01-13 01:41:57 +01:00
2079 changed files with 39626 additions and 252188 deletions

View File

@ -17,8 +17,8 @@ tab_width = 4
end_of_line = lf
insert_final_newline = true
# Markdown, JSON, YAML, props and csproj files
[*.{md,json,yml,props,csproj}]
# JSON files
[*.json]
# Indentation and spacing
indent_size = 2
@ -259,14 +259,14 @@ dotnet_diagnostic.CA1861.severity = none
# Disable "Prefer using 'string.Equals(string, StringComparison)' to perform a case-insensitive comparison, but keep in mind that this might cause subtle changes in behavior, so make sure to conduct thorough testing after applying the suggestion, or if culturally sensitive comparison is not required, consider using 'StringComparison.OrdinalIgnoreCase'"
dotnet_diagnostic.CA1862.severity = none
[src/Ryujinx/UI/ViewModels/**.cs]
# Disable "mark members as static" rule for ViewModels
dotnet_diagnostic.CA1822.severity = none
[src/Ryujinx.HLE/HOS/Services/**.cs]
# Disable "mark members as static" rule for services
dotnet_diagnostic.CA1822.severity = none
[src/Ryujinx.Ava/UI/ViewModels/**.cs]
# Disable "mark members as static" rule for ViewModels
dotnet_diagnostic.CA1822.severity = none
[src/Ryujinx.Tests/Cpu/*.cs]
# Disable naming rules for CPU tests
dotnet_diagnostic.IDE1006.severity = none

View File

@ -1,21 +0,0 @@
name: Notify API on Release
on:
release:
types: [ published ]
jobs:
notify-api:
runs-on: debian-trixie
steps:
- name: Send API Call for New Release
run: |
curl -X POST http://melonx.org/api/new_release \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${{ secrets.MELONX_GITEA_API_KEY }}" \
-d '{
"version_number": "${{ github.event.release.tag_name }}",
"download_link": "${{ github.event.release.html_url }}",
"changelog": "${{ github.event.release.body }}",
"is_latest": true
}'

View File

@ -23,7 +23,7 @@ body:
attributes:
label: Log file
description: A log file will help our developers to better diagnose and fix the issue.
placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. They can also be accessed by opening Ryujinx, then going to File > Open Logs Folder. You can drag and drop the log on to the text area (do not copy paste).
placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. You can drag and drop the log on to the text area
validations:
required: true
- type: input
@ -83,4 +83,4 @@ body:
- Additional info about your environment:
- Any other information relevant to your issue.
validations:
required: false
required: false

View File

@ -1,7 +1,6 @@
name: Feature Request
description: Suggest a new feature for Ryujinx.
title: "[Feature Request]"
labels: enhancement
body:
- type: textarea
id: overview

View File

@ -7,7 +7,7 @@ updates:
labels:
- "infra"
reviewers:
- TSRBerry
- marysaka
commit-message:
prefix: "ci"
@ -19,7 +19,7 @@ updates:
labels:
- "infra"
reviewers:
- TSRBerry
- marysaka
commit-message:
prefix: nuget
groups:

2
.github/labeler.yml vendored
View File

@ -20,7 +20,7 @@ gpu:
gui:
- changed-files:
- any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.UI.Common/**', 'src/Ryujinx.UI.LocaleGenerator/**', 'src/Ryujinx.Gtk3/**']
- any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.Ui.Common/**', 'src/Ryujinx.Ui.LocaleGenerator/**', 'src/Ryujinx.Ava/**']
horizon:
- changed-files:

View File

@ -1,24 +1,31 @@
audio:
- marysaka
cpu:
- gdkchan
- riperiperi
- marysaka
- LDj3SNuD
gpu:
- gdkchan
- riperiperi
- marysaka
gui:
- Ack77
- emmauss
- TSRBerry
- marysaka
horizon:
- gdkchan
- Ack77
- marysaka
- TSRBerry
infra:
- marysaka
- TSRBerry
default:

View File

@ -10,17 +10,28 @@ env:
jobs:
build:
name: ${{ matrix.platform.name }} (${{ matrix.configuration }})
runs-on: ${{ matrix.platform.os }}
name: ${{ matrix.OS_NAME }} (${{ matrix.configuration }})
runs-on: ${{ matrix.os }}
timeout-minutes: 45
strategy:
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest]
configuration: [Debug, Release]
platform:
- { name: win-x64, os: windows-latest, zip_os_name: win_x64 }
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 }
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 }
- { name: osx-x64, os: macos-13, zip_os_name: osx_x64 }
include:
- os: ubuntu-latest
OS_NAME: Linux x64
DOTNET_RUNTIME_IDENTIFIER: linux-x64
RELEASE_ZIP_OS_NAME: linux_x64
- os: macOS-latest
OS_NAME: macOS x64
DOTNET_RUNTIME_IDENTIFIER: osx-x64
RELEASE_ZIP_OS_NAME: osx_x64
- os: windows-latest
OS_NAME: Windows x64
DOTNET_RUNTIME_IDENTIFIER: win-x64
RELEASE_ZIP_OS_NAME: win_x64
fail-fast: false
steps:
@ -29,7 +40,7 @@ jobs:
- uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Overwrite csc problem matcher
run: echo "::add-matcher::.github/csc.json"
@ -38,16 +49,6 @@ jobs:
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Change config filename
run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
- name: Change config filename for macOS
run: sed -r -i '' 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
if: github.event_name == 'pull_request' && matrix.platform.os == 'macos-13'
- name: Build
run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER
@ -57,47 +58,46 @@ jobs:
commands: dotnet test --no-build -c "${{ matrix.configuration }}"
timeout-minutes: 10
retry-codes: 139
if: matrix.platform.name != 'linux-arm64'
- name: Publish Ryujinx
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained true
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained true
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
- name: Publish Ryujinx.Headless.SDL2
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
- name: Publish Ryujinx.Gtk3
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish_gtk -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Gtk3 --self-contained true
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
- name: Publish Ryujinx.Ava
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Ava --self-contained true
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
- name: Set executable bit
run: |
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh
chmod +x ./publish_sdl2_headless/Ryujinx.Headless.SDL2 ./publish_sdl2_headless/Ryujinx.sh
chmod +x ./publish_gtk/Ryujinx.Gtk3 ./publish_gtk/Ryujinx.sh
if: github.event_name == 'pull_request' && matrix.platform.os == 'ubuntu-latest'
chmod +x ./publish_ava/Ryujinx.Ava ./publish_ava/Ryujinx.sh
if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-latest'
- name: Upload Ryujinx artifact
uses: actions/upload-artifact@v4
with:
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
path: publish
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
- name: Upload Ryujinx.Headless.SDL2 artifact
uses: actions/upload-artifact@v4
with:
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
path: publish_sdl2_headless
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
- name: Upload Ryujinx.Gtk3 artifact
- name: Upload Ryujinx.Ava artifact
uses: actions/upload-artifact@v4
with:
name: gtk-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}
path: publish_gtk
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
path: publish_ava
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
build_macos:
name: macOS Universal (${{ matrix.configuration }})
@ -135,24 +135,19 @@ jobs:
id: git_short_hash
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
- name: Change config filename
run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
if: github.event_name == 'pull_request'
- name: Publish macOS Ryujinx
- name: Publish macOS Ryujinx.Ava
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp publish ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
- name: Publish macOS Ryujinx.Headless.SDL2
run: |
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
- name: Upload Ryujinx artifact
- name: Upload Ryujinx.Ava artifact
uses: actions/upload-artifact@v4
with:
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
path: "publish/*.tar.gz"
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
path: "publish_ava/*.tar.gz"
if: github.event_name == 'pull_request'
- name: Upload Ryujinx.Headless.SDL2 artifact

View File

@ -8,7 +8,7 @@ on:
- '!.github/**'
- '!*.yml'
- '!*.config'
- '!*.md'
- '!README.md'
- '.github/workflows/*.yml'
permissions:

View File

@ -51,76 +51,38 @@ jobs:
- name: Restore Nuget packages
# With .NET 8.0.100, Microsoft.NET.ILLink.Tasks isn't restored by default and only seems to appears when publishing.
# So we just publish to grab the dependencies
run: |
dotnet publish -c Release -r linux-x64 Ryujinx/${{ env.RYUJINX_PROJECT_FILE }} --self-contained
dotnet publish -c Release -r linux-arm64 Ryujinx/${{ env.RYUJINX_PROJECT_FILE }} --self-contained
run: dotnet publish -c Release -r linux-x64 Ryujinx/${{ env.RYUJINX_PROJECT_FILE }} --self-contained
- name: Generate nuget_sources.json
shell: python
run: |
import hashlib
from pathlib import Path
import base64
import binascii
import json
import os
import urllib.request
sources = []
for path in Path(os.environ['NUGET_PACKAGES']).glob('**/*.nupkg.sha512'):
name = path.parent.parent.name
version = path.parent.name
filename = '{}.{}.nupkg'.format(name, version)
url = 'https://api.nuget.org/v3-flatcontainer/{}/{}/{}'.format(name, version, filename)
def create_source_from_external(name, version):
full_dir_path = Path(os.environ["NUGET_PACKAGES"]).joinpath(name).joinpath(version)
os.makedirs(full_dir_path, exist_ok=True)
with path.open() as fp:
sha512 = binascii.hexlify(base64.b64decode(fp.read())).decode('ascii')
filename = "{}.{}.nupkg".format(name, version)
url = "https://api.nuget.org/v3-flatcontainer/{}/{}/{}".format(
name, version, filename
)
sources.append({
'type': 'file',
'url': url,
'sha512': sha512,
'dest': os.environ['NUGET_SOURCES_DESTDIR'],
'dest-filename': filename,
})
print(f"Processing {url}...")
response = urllib.request.urlopen(url)
sha512 = hashlib.sha512(response.read()).hexdigest()
return {
"type": "file",
"url": url,
"sha512": sha512,
"dest": os.environ["NUGET_SOURCES_DESTDIR"],
"dest-filename": filename,
}
has_added_x64_apphost = False
for path in Path(os.environ["NUGET_PACKAGES"]).glob("**/*.nupkg.sha512"):
name = path.parent.parent.name
version = path.parent.name
filename = "{}.{}.nupkg".format(name, version)
url = "https://api.nuget.org/v3-flatcontainer/{}/{}/{}".format(
name, version, filename
)
with path.open() as fp:
sha512 = binascii.hexlify(base64.b64decode(fp.read())).decode("ascii")
sources.append(
{
"type": "file",
"url": url,
"sha512": sha512,
"dest": os.environ["NUGET_SOURCES_DESTDIR"],
"dest-filename": filename,
}
)
# .NET will not add current installed application host to the list, force inject it here.
if not has_added_x64_apphost and name.startswith('microsoft.netcore.app.host'):
sources.append(create_source_from_external("microsoft.netcore.app.host.linux-x64", version))
has_added_x64_apphost = True
with open("flathub/nuget_sources.json", "w") as fp:
json.dump(sources, fp, indent=4)
with open('flathub/nuget_sources.json', 'w') as fp:
json.dump(sources, fp, indent=4)
- name: Update flatpak metadata
id: metadata

View File

@ -1,41 +0,0 @@
name: Mako
on:
discussion:
types: [created, edited, answered, unanswered, category_changed]
discussion_comment:
types: [created, edited]
gollum:
issue_comment:
types: [created, edited]
issues:
types: [opened, edited, reopened, pinned, milestoned, demilestoned, assigned, unassigned, labeled, unlabeled]
pull_request_target:
types: [opened, edited, reopened, synchronize, ready_for_review, assigned, unassigned]
jobs:
tasks:
name: Run Ryujinx tasks
permissions:
actions: read
contents: read
discussions: write
issues: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
if: github.event_name == 'pull_request_target'
with:
# Ensure we pin the source origin as pull_request_target run under forks.
fetch-depth: 0
repository: Ryujinx/Ryujinx
ref: master
- name: Run Mako command
uses: Ryujinx/Ryujinx-Mako@master
with:
command: exec-ryujinx-tasks
args: --event-name "${{ github.event_name }}" --event-path "${{ github.event_path }}" -w "${{ github.workspace }}" "${{ github.repository }}" "${{ github.run_id }}"
app_id: ${{ secrets.MAKO_APP_ID }}
private_key: ${{ secrets.MAKO_PRIVATE_KEY }}
installation_id: ${{ secrets.MAKO_INSTALLATION_ID }}

View File

@ -39,24 +39,24 @@ jobs:
return core.error(`No artifacts found`);
}
let body = `Download the artifacts for this pull request:\n`;
let hidden_gtk_artifacts = `\n\n <details><summary>Old GUI (GTK3)</summary>\n`;
let hidden_avalonia_artifacts = `\n\n <details><summary>Experimental GUI (Avalonia)</summary>\n`;
let hidden_headless_artifacts = `\n\n <details><summary>GUI-less (SDL2)</summary>\n`;
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
for (const art of artifacts) {
if(art.name.includes('Debug')) {
hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} else if(art.name.includes('gtk-ryujinx')) {
hidden_gtk_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} else if(art.name.includes('ava-ryujinx')) {
hidden_avalonia_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} else if(art.name.includes('sdl2-ryujinx-headless')) {
hidden_headless_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} else {
body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
}
}
hidden_gtk_artifacts += `\n</details>`;
hidden_avalonia_artifacts += `\n</details>`;
hidden_headless_artifacts += `\n</details>`;
hidden_debug_artifacts += `\n</details>`;
body += hidden_gtk_artifacts;
body += hidden_avalonia_artifacts;
body += hidden_headless_artifacts;
body += hidden_debug_artifacts;

View File

@ -21,8 +21,27 @@ jobs:
repository: Ryujinx/Ryujinx
ref: master
- name: Checkout Ryujinx-Mako
uses: actions/checkout@v4
with:
repository: Ryujinx/Ryujinx-Mako
ref: master
path: '.ryujinx-mako'
- name: Setup Ryujinx-Mako
uses: ./.ryujinx-mako/.github/actions/setup-mako
- name: Update labels based on changes
uses: actions/labeler@v5
with:
sync-labels: true
dot: true
- name: Assign reviewers
run: |
poetry -n -C .ryujinx-mako run ryujinx-mako update-reviewers ${{ github.repository }} ${{ github.event.pull_request.number }} .github/reviewers.yml
shell: bash
env:
MAKO_APP_ID: ${{ secrets.MAKO_APP_ID }}
MAKO_PRIVATE_KEY: ${{ secrets.MAKO_PRIVATE_KEY }}
MAKO_INSTALLATION_ID: ${{ secrets.MAKO_INSTALLATION_ID }}

View File

@ -10,7 +10,7 @@ on:
- '*.yml'
- '*.json'
- '*.config'
- '*.md'
- 'README.md'
concurrency: release
@ -44,34 +44,30 @@ jobs:
sha: context.sha
})
- name: Create release
uses: ncipollo/release-action@v1
with:
name: ${{ steps.version_info.outputs.build_version }}
tag: ${{ steps.version_info.outputs.build_version }}
body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
omitBodyDuringUpdate: true
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
token: ${{ secrets.RELEASE_TOKEN }}
release:
name: Release for ${{ matrix.platform.name }}
runs-on: ${{ matrix.platform.os }}
name: Release ${{ matrix.OS_NAME }}
runs-on: ${{ matrix.os }}
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
strategy:
matrix:
platform:
- { name: win-x64, os: windows-latest, zip_os_name: win_x64 }
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 }
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 }
os: [ ubuntu-latest, windows-latest ]
include:
- os: ubuntu-latest
OS_NAME: Linux x64
DOTNET_RUNTIME_IDENTIFIER: linux-x64
RELEASE_ZIP_OS_NAME: linux_x64
- os: windows-latest
OS_NAME: Windows x64
DOTNET_RUNTIME_IDENTIFIER: win-x64
RELEASE_ZIP_OS_NAME: win_x64
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
global-json-file: global.json
- name: Overwrite csc problem matcher
run: echo "::add-matcher::.github/csc.json"
@ -89,7 +85,6 @@ jobs:
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
- name: Create output dir
@ -97,36 +92,42 @@ jobs:
- name: Publish
run: |
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_gtk/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Ava --self-contained true
- name: Packing Windows builds
if: matrix.platform.os == 'windows-latest'
if: matrix.os == 'windows-latest'
run: |
pushd publish_ava
cp publish/Ryujinx.exe publish/Ryujinx.Ava.exe
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
pushd publish_gtk
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
popd
pushd publish_sdl2_headless
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
popd
pushd publish_ava
7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
popd
shell: bash
- name: Packing Linux builds
if: matrix.platform.os == 'ubuntu-latest'
if: matrix.os == 'ubuntu-latest'
run: |
pushd publish_ava
cp publish/Ryujinx publish/Ryujinx.Ava
chmod +x publish/Ryujinx.sh publish/Ryujinx.Ava publish/Ryujinx
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
pushd publish_gtk
chmod +x publish/Ryujinx.sh publish/Ryujinx
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
popd
pushd publish_sdl2_headless
chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
popd
pushd publish_ava
chmod +x publish/Ryujinx.sh publish/Ryujinx.Ava
tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
popd
shell: bash
@ -185,13 +186,12 @@ jobs:
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
- name: Publish macOS Ryujinx
- name: Publish macOS Ryujinx.Ava
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release
- name: Publish macOS Ryujinx.Headless.SDL2
run: |
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release

67
.gitignore vendored
View File

@ -10,8 +10,6 @@
# Build results
dotnet.xcconfig
[Dd]ebug/
[Rr]elease/
x64/
@ -47,7 +45,6 @@ build/
*.vssscc
.builds
*.pidb
*.log
*.scc
# Visual C++ cache files
@ -175,68 +172,4 @@ PublishProfiles/
# Glade backup files
*.glade~
src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/Ryujinx.Headless.SDL2.dylib
# SWIFT GITIGNORE
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## User settings
xcuserdata/
## Obj-C/Swift specific
*.hmap
## App packaging
*.ipa
*.dSYM.zip
*.dSYM
## Playgrounds
timeline.xctimeline
playground.xcworkspace
# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
# Package.resolved
# *.xcodeproj
#
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
# hence it is not needed unless you have added a package configuration file to your project
# .swiftpm
.build/
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
#
# Add this line if you want to avoid checking in source code from the Xcode workspace
# *.xcworkspace
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build/
# fastlane
#
# It is recommended to not store the screenshots in the git repo.
# Instead, use fastlane to re-generate the screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output

View File

@ -1,76 +0,0 @@
# Compiling MeloNX on macOS
## Prerequisites
Before you begin, ensure you have the following installed:
- [**.NET 8.0**](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
- [**Xcode**](https://apps.apple.com/de/app/xcode/id497799835?l=en-GB&mt=12$0)
- A Mac running **macOS**
## Compilation Steps
### 1. Clone the Repository and Build Ryujinx
Open a terminal and run (your password will not be shown in the 2nd command):
```sh
git clone https://git.743378673.xyz/MeloNX/MeloNX.git
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
```
However, if you only need to update MeloNX, make sure you have cd into the directory then run this
```
git pull
```
### 2. Open the Xcode Project
Navigate to the **Xcode project file** located at:
```
src/MeloNX/MeloNX.xcodeproj
```
Double-click to open it in **Xcode**.
### 3. Configure Signing & Capabilities
- In **Xcode**, go to **Signing & Capabilities**.
- Set the **Team** to your **Apple Developer account** (free or paid).
- Change the **Bundle Identifier** to:
```
com.<your-name>.MeloNX
```
*(Replace `<your-name>` with your actual name or identifier.)*
### 4. Connect Your Device
Ensure your **iPhone/iPad** is **connected** and **selected** (Next to MeloNX with the arrow) in Xcode.
- You may need to install the iOS SDK. it will say next to MeloNX with the arrow saying "iOS XX Not Installed (GET)"
- You will be need to press GET and wait for it to finish downloading and installing
- Then you will be able to select your device and Build and Run.
### Make Sure you do **NOT** select the Simulator. (Which is the Generic names and the ones with the non-coloured icons, e.g. "iPhone 16 Pro")
### 6. Configure the Project Settings
Click the **Run (▶️) button** in Xcode to compile MeloNX and wait it will fail with Undefined Symbol(s) the first time, Thats normal.
- When it fails the first time, do this:
- In **Xcode**, select the **MeloNX** project.
- Under the **General** tab, find `Ryujinx.Headless.SDL2.dylib`.
- Set its **Embed setting** to **"Embed & Sign"**.
### 5. Build and Run
Click the **Run (▶️) button** in Xcode to compile and launch MeloNX.
- When running on your device, Click the **Spray Can Button** below the Run button
- Right Click where it says "> MeloNX PID XXXX"
- Press Detach in the Context Menu.
---
Now you're all set! 🚀 If you encounter issues, please join the discord at https://melonx.org

View File

@ -3,28 +3,29 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Avalonia" Version="11.0.10" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.10" />
<PackageVersion Include="Avalonia.Desktop" Version="11.0.10" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.10" />
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.10" />
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.18" />
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.18" />
<PackageVersion Include="Avalonia" Version="11.0.7" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.7" />
<PackageVersion Include="Avalonia.Desktop" Version="11.0.7" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.7" />
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.7" />
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.10" />
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.10" />
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
<PackageVersion Include="Concentus" Version="2.2.0" />
<PackageVersion Include="Concentus" Version="1.1.7" />
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
<PackageVersion Include="DynamicData" Version="9.0.4" />
<PackageVersion Include="DynamicData" Version="7.14.2" />
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.3.0-beta.4" />
<PackageVersion Include="LibHac" Version="0.19.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.0.1" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.2.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
<PackageVersion Include="NetCoreServer" Version="8.0.7" />
<PackageVersion Include="NetCoreServer" Version="7.0.0" />
<PackageVersion Include="NUnit" Version="3.13.3" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
<PackageVersion Include="OpenTK.Core" Version="4.8.2" />
@ -32,21 +33,23 @@
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.8.2" />
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.8.2" />
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.3-build14" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.28.1-build28" />
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
<PackageVersion Include="shaderc.net" Version="0.1.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
<PackageVersion Include="Silk.NET.Vulkan" Version="2.21.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.21.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.21.0" />
<PackageVersion Include="SkiaSharp" Version="2.88.7" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.7" />
<PackageVersion Include="SPB" Version="0.0.4-build32" />
<PackageVersion Include="Silk.NET.Vulkan" Version="2.17.1" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.17.1" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.17.1" />
<PackageVersion Include="SixLabors.ImageSharp" Version="1.0.4" />
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
<PackageVersion Include="SPB" Version="0.0.4-build28" />
<PackageVersion Include="System.Drawing.Common" Version="8.0.0" />
<PackageVersion Include="System.IO.Hashing" Version="8.0.0" />
<PackageVersion Include="System.Management" Version="8.0.0" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
<PackageVersion Include="Rxmxnx.PInvoke.Extensions" Version="1.0.1" />
</ItemGroup>
</Project>

View File

@ -1,24 +1,9 @@
Currently licensed under the GNU AFFERO GENERAL PUBLIC LICENSE version 3, or any later version, at your choice.
You may obtain a copy of the license at <https://gnu.org/>
MIT License
Copyright (c) Rhajune Park and contributors, 2025
Copyright (c) Ryujinx Team and Contributors
For copyright infringement claims, please contact abuse@pythonplayer123.dev for expedited processing
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Previously licensed under the MeloNX License.
MeloNX License
Copyright (c) MeloNX Team and Contributors
Permission is hereby granted, free of charge, to any person (except anyone who has previously attempted or is currently attempting to merge MeloNX with Pomelo) obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Every file is under this license, and all copies must be redistributed under the same license.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Anyone who attempts or has attempted to merge MeloNX with Pomelo, or otherwise use this source code in conjunction with Pomelo, is prohibited from using, copying, modifying, or distributing the source code without first obtaining explicit, written permission from Stossy11.
Additionally, the names of the developers or contributors to this project may not be used to endorse or promote products derived from this software without specific, prior written permission from the respective developer(s).
Ryujinx is licensed under the MIT License. Copyright (c) Ryujinx contributors. All rights to Ryujinx are held by its respective copyright holders, and its use is subject to the terms of the MIT License.

View File

@ -1,46 +0,0 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>get-task-allow</key>
<true/>
<key>com.apple.developer.kernel.increased-memory-limit</key>
<true/>
<key>com.apple.developer.kernel.extended-virtual-addressing</key>
<true/>
<key>com.apple.private.iokit.IOServiceSetAuthorizationID</key>
<true/>
<key>com.apple.security.exception.iokit-user-client-class</key>
<array>
<string>AGXCommandQueue</string>
<string>AGXDevice</string>
<string>AGXDeviceUserClient</string>
<string>AGXSharedUserClient</string>
<string>AppleUSBHostDeviceUserClient</string>
<string>AppleUSBHostInterfaceUserClient</string>
<string>IOSurfaceRootUserClient</string>
<string>IOAccelContext</string>
<string>IOAccelContext2</string>
<string>IOAccelDevice</string>
<string>IOAccelDevice2</string>
<string>IOAccelSharedUserClient</string>
<string>IOAccelSharedUserClient2</string>
<string>IOAccelSubmitter2</string>
</array>
<key>com.apple.system.diagnostics.iokit-properties</key>
<true/>
<key>com.apple.vm.device-access</key>
<true/>
<key>com.apple.private.hypervisor</key>
<true/>
<key>com.apple.private.memorystatus</key>
<true/>
<key>com.apple.private.security.no-sandbox</key>
<true/>
<key>com.apple.private.security.storage.AppDataContainers</key>
<true/>
<key>com.apple.private.security.storage.MobileDocuments</key>
<true/>
<key>platform-application</key>
<true/>
</dict>
</plist>

221
README.md
View File

@ -1,171 +1,144 @@
<h1 align="center">
<br>
<a href="https://ryujinx.org/"><img src="https://i.imgur.com/WcCj6Rt.png" alt="Ryujinx" width="150"></a>
<br>
<b>Ryujinx</b>
<br>
<sub><sup><b>(REE-YOU-JINX)</b></sup></sub>
<br>
</h1>
<p align="center">
<a href="https://melonx.org">
<img src="https://melonx.org/static/imgs/MeloNX.svg" alt="MeloNX Logo" width="120">
Ryujinx is an open-source Nintendo Switch emulator, created by gdkchan, written in C#.
This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds.
It was written from scratch and development on the project began in September 2017. Ryujinx is available on Github under the <a href="https://github.com/Ryujinx/Ryujinx/blob/master/LICENSE.txt" target="_blank">MIT license</a>. <br />
</p>
<p align="center">
<a href="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml">
<img src="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml/badge.svg"
alt="">
</a>
<a href="https://crwd.in/ryujinx">
<img src="https://badges.crowdin.net/ryujinx/localized.svg"
alt="">
</a>
<a href="https://discord.com/invite/VkQYXAZ">
<img src="https://img.shields.io/discord/410208534861447168?color=5865F2&label=Ryujinx&logo=discord&logoColor=white"
alt="Discord">
</a>
<br>
<br>
<img src="https://raw.githubusercontent.com/Ryujinx/Ryujinx-Website/master/public/assets/images/shell.png">
</p>
<h1 align="center">MeloNX</h1>
<h5 align="center">
<p align="center">
MeloNX enables Nintendo Switch game emulation on iOS using the Ryujinx iOS code base.
</p>
</h5>
<p align="center">
MeloNX is an iOS Nintendo Switch emulator based on Ryujinx, written primarily in C#. Designed to bring accurate performance and a user-friendly interface to iOS, MeloNX makes Switch games accessible on Apple devices.
Developed from the ground up, MeloNX is open-source and available on Github under the <a href="https://github.com/MeloNX-Emu/MeloNX/blob/master/LICENSE.txt" target="_blank">MeloNX license (Based on MIT)</a>. <br
</p>
## Compatibility
# Compatibility
As of April 2023, Ryujinx has been tested on approximately 4,050 titles; over 4,000 boot past menus and into gameplay, with roughly 3,400 of those being considered playable.
You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
MeloNX works on iPhone XS/XR and later and iPad 8th Gen and later. Check out the Compatibility on the <a href="https://melonx.org/compatibility/" target="_blank">website</a>.
## Usage
# Usage
To run this emulator, your PC must be equipped with at least 8GiB of RAM; failing to meet this requirement may result in a poor gameplay experience or unexpected crashes.
## FAQ
- MeloNX is made for iOS 17+, on iOS 15 - 16 MeloNX can be installed but may have issues or not work at all.
- MeloNX cannot be Sideloaded normally and requires the use of the following Installation Guide(s).
- MeloNX requires JIT
- Recommended Device: iPhone 15 Pro or newer.
- Low-End Recommended Device: iPhone 13 Pro.
See our [Setup & Configuration Guide](https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide) on how to set up the emulator.
For our Local Wireless and LAN builds, see our [Multiplayer: Local Play/Local Wireless Guide
](https://github.com/Ryujinx/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide).
Avalonia UI comes with translations for various languages. See [Crowdin](https://crwd.in/ryujinx) for more information.
## Latest build
These builds are compiled automatically for each commit on the master branch. While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken.**
If you want to see details on updates to the emulator, you can visit our [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog).
The latest automatic build for Windows, macOS, and Linux can be found on the [Official Website](https://ryujinx.org/download).
## How to install
## Building
### Paid Developer Account
If you wish to build the emulator yourself, follow these steps:
1. **Sideload the App**
- Use any sideloading tool that supports Apple IDs.
### Step 1
Install the X64 version of [.NET 8.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/8.0).
2. **Enable Entitlements**
- Visit [Apple Developer Identifiers](https://developer.apple.com/account/resources/identifiers).
- Locate **MeloNX** and enable the following entitlements:
- `Increased Memory Limit`
- `Increased Debugging Memory Limit`
### Step 2
Either use `git clone https://github.com/Ryujinx/Ryujinx` on the command line to clone the repository or use Code --> Download zip button to get the files.
3. **Reinstall the App**
- Delete the existing installation.
- Sideload the app again with the updated entitlements.
### Step 3
4. **Enable JIT**
- Use your preferred method to enable Just-In-Time (JIT) compilation.
- We reccomend using [JitStreamer](https://jkcoxson.com/jitstreamer)
To build Ryujinx, open a command prompt inside the project directory. You can quickly access it on Windows by holding shift in File Explorer, then right clicking and selecting `Open command window here`. Then type the following command:
`dotnet build -c Release -o build`
the built files will be found in the newly created build directory.
5. **Add Necessary Files**
If having Issues installing firmware (Make sure your Keys are installed first)
- If needed, install firmware and keys from **Ryujinx Desktop** (or forks).
- Copy the **bis** and **system** folders
### Free Developer Account (Experimental)
1. **Sideload MeloNX**
- Use [SideStore](https://sidestore.io/) or [AltStore](https://altstore.io/) (**NOT** AltStore PAL).
2. **Sideload the Entitlement App**
- Install [this app](https://github.com/hugeBlack/GetMoreRam/releases/download/nightly/Entitlement.ipa) using [SideStore](https://sidestore.io/) or [AltStore](https://altstore.io/) (**NOT** AltStore PAL).
3. **Sign In to Your Account**
- Open **Settings** in the entitlement app and sign in with your Apple ID.
4. **Refresh App IDs**
- Navigate to the **App IDs** page.
- Tap **Refresh** to update the list.
5. **Enable Increased Memory Limit**
- Select **MeloNX** (should be like "com.stossy11.MeloNX" or some variation) from the list.
- Tap **Add Increased Memory Limit**.
6. **Reinstall MeloNX**
- Delete the existing installation.
- Sideload the app again using SideStore or AltStore.
7. **Verify Increased Memory Limit**
- Open MeloNX and check if the **Increased Memory Limit** is enabled.
8. **Add Necessary Files**
If having Issues installing firmware (Make sure your keys are installed first)
- If needed, install firmware and keys from **Ryujinx Desktop** (or forks).
- Copy the **bis** and **system** folders
9. **Enable JIT**
- Use your preferred method to enable Just-In-Time (JIT) compilation.
- We recommend using [JitStreamer](https://jkcoxson.com/jitstreamer)
### TrollStore
As Said in FAQ:
> MeloNX is made for iOS 17+, on iOS 15 - 16 MeloNX can be installed but may have issues or not work at all.
1. **Install MeloNX with TrollStore**
2. **Add Necessary Files**
3. **Enable TrollStore JIT**
- MeloNX includes automatic JIT using the TrollStore URL Scheme
- Open MeloNX Settings
- Scroll down and enable the "TrollStore JIT" toggle
- Profit
Ryujinx system files are stored in the `Ryujinx` folder. This folder is located in the user folder, which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI.
### Free Developer Account (Xcode)
**NOTE: These Xcode builds are nightly and may have unfinished features.**
1. **Compile Guide**
- Visit the [guide here](https://git.743378673.xyz/MeloNX/MeloNX/src/branch/XC-ios-ht/Compile.md).
2. **Add Necessary Files**
If having Issues installing firmware (Make sure your keys are installed first)
- If needed, install firmware and keys from **Ryujinx Desktop** (or forks).
- Copy the **bis** and **system** folders
## Features
- **Audio**
- **Audio**
Audio output is entirely supported, audio input (microphone) isn't supported.
We use C# wrappers for [OpenAL](https://openal-soft.org/), and [SDL2](https://www.libsdl.org/) & [libsoundio](http://libsound.io/) as fallbacks.
Audio output is entirely supported, audio input (microphone) isn't supported. We use C# wrappers for [OpenAL](https://openal-soft.org/), and [SDL2](https://www.libsdl.org/) & [libsoundio](http://libsound.io/) as fallbacks.
- **CPU**
The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions, including partial 32-bit support.
It translates the ARM code to a custom IR, performs a few optimizations, and turns that into x86 code.
There are three memory manager options available depending on the user's preference, leveraging both software-based (slower) and host-mapped modes (much faster).
The fastest option (host, unchecked) is set by default.
Ryujinx also features an optional Profiled Persistent Translation Cache, which essentially caches translated functions so that they do not need to be translated every time the game loads.
The net result is a significant reduction in load times (the amount of time between launching a game and arriving at the title screen) for nearly every game.
NOTE: This feature is enabled by default, You must launch the game at least twice to the title screen or beyond before performance improvements are unlocked on the third launch!
These improvements are permanent and do not require any extra launches going forward.
The CPU emulator, ARMeilleure, emulates an ARMv8 CPU and currently has support for most 64-bit ARMv8 and some of the ARMv7 (and older) instructions, including partial 32-bit support. It translates the ARM code to a custom IR, performs a few optimizations, and turns that into x86 code.
There are three memory manager options available depending on the user's preference, leveraging both software-based (slower) and host-mapped modes (much faster). The fastest option (host, unchecked) is set by default.
Ryujinx also features an optional Profiled Persistent Translation Cache, which essentially caches translated functions so that they do not need to be translated every time the game loads. The net result is a significant reduction in load times (the amount of time between launching a game and arriving at the title screen) for nearly every game. NOTE: this feature is enabled by default in the Options menu > System tab. You must launch the game at least twice to the title screen or beyond before performance improvements are unlocked on the third launch! These improvements are permanent and do not require any extra launches going forward.
- **GPU**
The GPU emulator emulates the Switch's Maxwell GPU using Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively.
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively. There are currently six graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Anti-Aliasing, Scaling Filters (including FSR), Anisotropic Filtering and Aspect Ratio Adjustment. These enhancements can be adjusted or toggled as desired in the GUI.
- **Input**
We currently have support for keyboard, touch input, JoyCon input support, and nearly all controllers.
Motion controls are natively supported in most cases.
We currently have support for keyboard, mouse, touch input, JoyCon input support, and nearly all controllers. Motion controls are natively supported in most cases; for dual-JoyCon motion support, DS4Windows or BetterJoy are currently required.
In all scenarios, you can set up everything inside the input configuration menu.
- **DLC & Modifications**
MeloNX supports DLC + Game Update Add-ons.
Mods (romfs, exefs, and runtime mods such as cheats) are supported;
Ryujinx is able to manage add-on content/downloadable content through the GUI. Mods (romfs, exefs, and runtime mods such as cheats) are also supported; the GUI contains a shortcut to open the respective mods folder for a particular game.
- **Configuration**
The emulator has settings for enabling or disabling some logging, remapping controllers, and more.
The emulator has settings for enabling or disabling some logging, remapping controllers, and more. You can configure all of them through the graphical interface or manually through the config file, `Config.json`, found in the user folder which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI.
## Contact
If you have contributions, suggestions, need emulator support or just want to get in touch with the team, join our [Discord server](https://discord.com/invite/Ryujinx). You may also review our [FAQ](https://github.com/Ryujinx/Ryujinx/wiki/Frequently-Asked-Questions).
## Donations
If you'd like to support the project financially, Ryujinx has an active Patreon campaign.
<a href="https://www.patreon.com/ryujinx">
<img src="https://images.squarespace-cdn.com/content/v1/560c1d39e4b0b4fae0c9cf2a/1567548955044-WVD994WZP76EWF15T0L3/Patreon+Button.png?format=500w" width="150">
</a>
All developers working on the project do so in their free time, but the project has several expenses:
* Hackable Nintendo Switch consoles to reverse-engineer the hardware
* Additional computer hardware for testing purposes (e.g. GPUs to diagnose graphical bugs, etc.)
* Licenses for various software development tools (e.g. Jetbrains, IDA)
* Web hosting and infrastructure maintenance (e.g. LDN servers)
All funds received through Patreon are considered a donation to support the project. Patrons receive early access to progress reports and exclusive access to developer interviews.
## License
This software is licensed under the terms of the [MeloNX license (Based on MIT License)](LICENSE.txt).
This software is licensed under the terms of the <a href="https://github.com/Ryujinx/Ryujinx/blob/master/LICENSE.txt" target="_blank">MIT license.</a></i><br />
This project makes use of code authored by the libvpx project, licensed under BSD and the ffmpeg project, licensed under LGPLv3.
See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](distribution/legal/THIRDPARTY.md) for more details.
## Credits
- [Ryujinx](https://github.com/ryujinx-mirror/ryujinx) is used for the base of this emulator. (link is to ryujinx-mirror since they were supportive)
- [LibHac](https://github.com/Thealexbarney/LibHac) is used for our file-system.
- [AmiiboAPI](https://www.amiiboapi.com) is used in our Amiibo emulation.
- [ldn_mitm](https://github.com/spacemeowx2/ldn_mitm) is used for one of our available multiplayer modes.

View File

@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.1.32228.430
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Gtk3", "src\Ryujinx.Gtk3\Ryujinx.Gtk3.csproj", "{074045D4-3ED2-4711-9169-E385F2BFB5A0}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{074045D4-3ED2-4711-9169-E385F2BFB5A0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests", "src\Ryujinx.Tests\Ryujinx.Tests.csproj", "{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}"
EndProject
@ -69,9 +69,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Headless.SDL2", "sr
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ava", "src\Ryujinx.Ava\Ryujinx.Ava.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.Common", "src\Ryujinx.UI.Common\Ryujinx.UI.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.Common", "src\Ryujinx.Ui.Common\Ryujinx.Ui.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Generators", "src\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}"
EndProject
@ -79,7 +79,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spv.Generator", "src\Spv.Generator\Spv.Generator.csproj", "{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.LocaleGenerator", "src\Ryujinx.UI.LocaleGenerator\Ryujinx.UI.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.LocaleGenerator", "src\Ryujinx.Ui.LocaleGenerator\Ryujinx.Ui.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Common", "src\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj", "{77F96ECE-4952-42DB-A528-DED25572A573}"
EndProject
@ -87,7 +87,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon", "src\Ryuj
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "src\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibRyujinx.Shared", "src\LibRyujinx\LibRyujinx.csproj", "{5BBF478C-A520-41E7-9B88-890AD26766B8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{C75176EB-C44E-449A-8077-A48AD94534EE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibRyujinx.NativeSample", "src\LibRyujinx.NativeSample\LibRyujinx.NativeSample.csproj", "{63D2C96B-5194-4592-BC91-30BEB11C06BD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -251,10 +255,18 @@ Global
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
{5BBF478C-A520-41E7-9B88-890AD26766B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5BBF478C-A520-41E7-9B88-890AD26766B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5BBF478C-A520-41E7-9B88-890AD26766B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5BBF478C-A520-41E7-9B88-890AD26766B8}.Release|Any CPU.Build.0 = Release|Any CPU
{C75176EB-C44E-449A-8077-A48AD94534EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C75176EB-C44E-449A-8077-A48AD94534EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C75176EB-C44E-449A-8077-A48AD94534EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C75176EB-C44E-449A-8077-A48AD94534EE}.Release|Any CPU.Build.0 = Release|Any CPU
{63D2C96B-5194-4592-BC91-30BEB11C06BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{63D2C96B-5194-4592-BC91-30BEB11C06BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{63D2C96B-5194-4592-BC91-30BEB11C06BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{63D2C96B-5194-4592-BC91-30BEB11C06BD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -4,8 +4,6 @@
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForOtherTypes/@EntryValue">UseExplicitType</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseExplicitType</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="I" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a0b4bc4d_002Dd13b_002D4a37_002Db37e_002Dc9c6864e4302/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"&gt;&lt;ElementKinds&gt;&lt;Kind Name="NAMESPACE" /&gt;&lt;Kind Name="CLASS" /&gt;&lt;Kind Name="STRUCT" /&gt;&lt;Kind Name="ENUM" /&gt;&lt;Kind Name="DELEGATE" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="I" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ASET/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Astc/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Luma/@EntryIndexedValue">True</s:Boolean>

View File

@ -1,17 +0,0 @@
#!/bin/bash
# Define the destination directory (hardcoded)
DESTINATION_DIR="src/MeloNX/Dependencies/Dynamic\ Libraries/Ryujinx.Headless.SDL2.dylib"
# Restore the project
dotnet restore
# Build the project with the specified version
dotnet build -c Release
# Publish the project with the specified runtime and settings
dotnet publish -c Release -r ios-arm64 -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true
# Move the published .dylib to the specified location
mv src/Ryujinx.Headless.SDL2/bin/Release/net8.0/ios-arm64/native/Ryujinx.Headless.SDL2.dylib src/MeloNX/MeloNX/Dependencies/Dynamic\ Libraries/Ryujinx.Headless.SDL2.dylib

View File

@ -1,46 +0,0 @@
#!/bin/bash
XCCONFIG_FILE="${SRCROOT}/MeloNX.xcconfig"
# Define the common paths to search for dotnet, including user-specific directories
SEARCH_PATHS=(
"/usr/local/share/dotnet"
"/usr/local/bin"
"/usr/bin"
"/bin"
"/opt"
"/Library/Frameworks"
"$HOME/.dotnet"
"$HOME/Developer"
)
# Initialize DOTNET_PATH as empty
DOTNET_PATH=""
# Search in the defined paths
for path in "${SEARCH_PATHS[@]}"; do
if [ -d "$path" ]; then
DOTNET_PATH=$(find "$path" -name dotnet -type f -print -quit 2>/dev/null)
if [ -n "$DOTNET_PATH" ]; then
break
fi
fi
done
# Check if the path was found
if [ -z "$DOTNET_PATH" ]; then
echo "Error: dotnet path not found."
exit 1
fi
echo "dotnet path: $DOTNET_PATH"
# Escape the path for sed
ESCAPED_PATH=$(echo "$DOTNET_PATH" | sed 's/\//\\\//g')
# Update the xcconfig file
sed -i '' "s/^DOTNET = .*/DOTNET = $ESCAPED_PATH/g" "$XCCONFIG_FILE"
$DOTNET_PATH clean
echo "Updated MeloNX.xcconfig with DOTNET path: $DOTNET_PATH"

View File

@ -1,38 +0,0 @@
#!/bin/bash
GITEA_URL="https://git.743378673.xyz/"
REPO="MeloNX"
XCCONFIG_FILE="${SRCROOT}/MeloNX.xcconfig"
INCREMENT_PATCH=false
# Check for --patch argument
if [[ "$1" == "--patch" ]]; then
INCREMENT_PATCH=true
fi
# Fetch latest tag from Gitea
LATEST_VERSION=$(curl -s "${GITEA_URL}/api/v1/repos/${REPO}/${REPO}/tags" | jq -r '.[].name' | sort -V | tail -n1)
if [ -z "$LATEST_VERSION" ]; then
echo "Error: Could not fetch latest tag from Gitea"
exit 1
fi
echo "Latest version: $LATEST_VERSION"
# Split version into major, minor, and patch
IFS='.' read -r MAJOR MINOR PATCH <<< "$LATEST_VERSION"
# Increment version based on argument
if $INCREMENT_PATCH; then
NEW_VERSION="$MAJOR.$MINOR.$((PATCH + 1))"
else
NEW_VERSION="$MAJOR.$((MINOR + 1)).0"
fi
echo "New version: $NEW_VERSION"
sed -i '' "s/^VERSION = $LATEST_VERSION$/VERSION = $NEW_VERSION/g" "$XCCONFIG_FILE"
echo "Updated MeloNX.xcconfig with version $NEW_VERSION"

View File

@ -4,7 +4,7 @@ Name=Ryujinx
Type=Application
Icon=Ryujinx
Exec=Ryujinx.sh %f
Comment=A Nintendo Switch Emulator
Comment=Plays Nintendo Switch applications
GenericName=Nintendo Switch Emulator
Terminal=false
Categories=Game;Emulator;

15
distribution/linux/Ryujinx.sh Executable file → Normal file
View File

@ -1,23 +1,20 @@
#!/bin/sh
SCRIPT_DIR=$(dirname "$(realpath "$0")")
RYUJINX_BIN="Ryujinx"
if [ -f "$SCRIPT_DIR/Ryujinx.Ava" ]; then
RYUJINX_BIN="Ryujinx.Ava"
fi
if [ -f "$SCRIPT_DIR/Ryujinx.Headless.SDL2" ]; then
RYUJINX_BIN="Ryujinx.Headless.SDL2"
fi
if [ -f "$SCRIPT_DIR/Ryujinx" ]; then
RYUJINX_BIN="Ryujinx"
fi
if [ -z "$RYUJINX_BIN" ]; then
exit 1
fi
COMMAND="env DOTNET_EnableAlternateStackCheck=1"
if command -v gamemoderun > /dev/null 2>&1; then
COMMAND="$COMMAND gamemoderun"
fi
exec $COMMAND "$SCRIPT_DIR/$RYUJINX_BIN" "$@"
$COMMAND "$SCRIPT_DIR/$RYUJINX_BIN" "$@"

View File

@ -14,8 +14,8 @@ mkdir "$APP_BUNDLE_DIRECTORY/Contents/Frameworks"
mkdir "$APP_BUNDLE_DIRECTORY/Contents/MacOS"
mkdir "$APP_BUNDLE_DIRECTORY/Contents/Resources"
# Copy executable and nsure executable can be executed
cp "$PUBLISH_DIRECTORY/Ryujinx" "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx"
# Copy executables first
cp "$PUBLISH_DIRECTORY/Ryujinx.Ava" "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx"
chmod u+x "$APP_BUNDLE_DIRECTORY/Contents/MacOS/Ryujinx"
# Then all libraries

View File

@ -22,9 +22,9 @@ EXTRA_ARGS=$8
if [ "$VERSION" == "1.1.0" ];
then
RELEASE_TAR_FILE_NAME=ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar
RELEASE_TAR_FILE_NAME=test-ava-ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar
else
RELEASE_TAR_FILE_NAME=ryujinx-$VERSION-macos_universal.app.tar
RELEASE_TAR_FILE_NAME=test-ava-ryujinx-$VERSION-macos_universal.app.tar
fi
ARM64_APP_BUNDLE="$TEMP_DIRECTORY/output_arm64/Ryujinx.app"
@ -38,9 +38,9 @@ mkdir -p "$TEMP_DIRECTORY"
DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS)
dotnet restore
dotnet build -c "$CONFIGURATION" src/Ryujinx
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx
dotnet build -c "$CONFIGURATION" src/Ryujinx.Ava
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Ava
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Ava
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
@ -108,13 +108,6 @@ tar --exclude "Ryujinx.app/Contents/MacOS/Ryujinx" -cvf "$RELEASE_TAR_FILE_NAME"
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "Ryujinx.app/Contents/MacOS/Ryujinx" "Ryujinx.app/Contents/MacOS/Ryujinx"
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
rm "$RELEASE_TAR_FILE_NAME"
# Create legacy update package for Avalonia to not left behind old testers.
if [ "$VERSION" != "1.1.0" ];
then
cp $RELEASE_TAR_FILE_NAME.gz test-ava-ryujinx-$VERSION-macos_universal.app.tar.gz
fi
popd
echo "Done"

View File

@ -1,8 +0,0 @@
#!/bin/sh
launch_arch="$(uname -m)"
if [ "$(sysctl -in sysctl.proc_translated)" = "1" ]
then
launch_arch="arm64"
fi
arch -$launch_arch {0} {1}

View File

@ -33,3 +33,8 @@ Project Docs
=================
To be added. Many project files will contain basic XML docs for key functions and classes in the meantime.
Other Information
=================
- N/A

View File

@ -2,6 +2,7 @@
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="nuget"
value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>

View File

@ -237,7 +237,7 @@ namespace ARMeilleure.CodeGen.Arm64
long originalPosition = _stream.Position;
_stream.Seek(0, SeekOrigin.Begin);
_stream.ReadExactly(code, 0, code.Length);
_stream.Read(code, 0, code.Length);
_stream.Seek(originalPosition, SeekOrigin.Begin);
RelocInfo relocInfo;

View File

@ -124,7 +124,7 @@ namespace ARMeilleure.CodeGen.Arm64
#endregion
#region macOS
#region Darwin
[LibraryImport("libSystem.dylib", SetLastError = true)]
private static unsafe partial int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string name, out int oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);

View File

@ -58,9 +58,9 @@ namespace ARMeilleure.CodeGen
/// <typeparam name="T">Type of delegate</typeparam>
/// <param name="codePointer">Pointer to the function code in memory</param>
/// <returns>A delegate of type <typeparamref name="T"/> pointing to the mapped function</returns>
public T MapWithPointer<T>(out IntPtr codePointer, bool deferProtect = false)
public T MapWithPointer<T>(out IntPtr codePointer)
{
codePointer = JitCache.Map(this, deferProtect);
codePointer = JitCache.Map(this);
return Marshal.GetDelegateForFunctionPointer<T>(codePointer);
}

View File

@ -251,20 +251,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
}
}
// If this is a copy destination variable, we prefer the register used for the copy source.
// If the register is available, then the copy can be eliminated later as both source
// and destination will use the same register.
int selectedReg;
if (current.TryGetCopySourceRegister(out int preferredReg) && freePositions[preferredReg] >= current.GetEnd())
{
selectedReg = preferredReg;
}
else
{
selectedReg = GetHighestValueIndex(freePositions);
}
int selectedReg = GetHighestValueIndex(freePositions);
int selectedNextUse = freePositions[selectedReg];
// Intervals starts and ends at odd positions, unless they span an entire
@ -444,7 +431,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
}
}
private static int GetHighestValueIndex(ReadOnlySpan<int> span)
private static int GetHighestValueIndex(Span<int> span)
{
int highest = int.MinValue;
@ -811,12 +798,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
// The "visited" state is stored in the MSB of the local's value.
const ulong VisitedMask = 1ul << 63;
static bool IsVisited(Operand local)
bool IsVisited(Operand local)
{
return (local.GetValueUnsafe() & VisitedMask) != 0;
}
static void SetVisited(Operand local)
void SetVisited(Operand local)
{
local.GetValueUnsafe() |= VisitedMask;
}
@ -839,25 +826,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
dest.NumberLocal(_intervals.Count);
LiveInterval interval = new LiveInterval(dest);
_intervals.Add(interval);
_intervals.Add(new LiveInterval(dest));
SetVisited(dest);
// If this is a copy (or copy-like operation), set the copy source interval as well.
// This is used for register preferencing later on, which allows the copy to be eliminated
// in some cases.
if (node.Instruction == Instruction.Copy || node.Instruction == Instruction.ZeroExtend32)
{
Operand source = node.GetSource(0);
if (source.Kind == OperandKind.LocalVariable &&
source.GetLocalNumber() > 0 &&
(node.Instruction == Instruction.Copy || source.Type == OperandType.I32))
{
interval.SetCopySource(_intervals[source.GetLocalNumber()]);
}
}
}
}
}

View File

@ -19,7 +19,6 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public LiveRange CurrRange;
public LiveInterval Parent;
public LiveInterval CopySource;
public UseList Uses;
public LiveIntervalList Children;
@ -38,7 +37,6 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private ref LiveRange CurrRange => ref _data->CurrRange;
private ref LiveRange PrevRange => ref _data->PrevRange;
private ref LiveInterval Parent => ref _data->Parent;
private ref LiveInterval CopySource => ref _data->CopySource;
private ref UseList Uses => ref _data->Uses;
private ref LiveIntervalList Children => ref _data->Children;
@ -80,25 +78,6 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
Register = register;
}
public void SetCopySource(LiveInterval copySource)
{
CopySource = copySource;
}
public bool TryGetCopySourceRegister(out int copySourceRegIndex)
{
if (CopySource._data != null)
{
copySourceRegIndex = CopySource.Register.Index;
return true;
}
copySourceRegIndex = 0;
return false;
}
public void Reset()
{
PrevRange = default;

View File

@ -1444,7 +1444,7 @@ namespace ARMeilleure.CodeGen.X86
Span<byte> buffer = new byte[jump.JumpPosition - _stream.Position];
_stream.ReadExactly(buffer);
_stream.Read(buffer);
_stream.Seek(ReservedBytesForJump, SeekOrigin.Current);
codeStream.Write(buffer);

View File

@ -517,10 +517,7 @@ namespace ARMeilleure.Decoders
SetA64("0x00111100>>>xxx100111xxxxxxxxxx", InstName.Sqrshrn_V, InstEmit.Sqrshrn_V, OpCodeSimdShImm.Create);
SetA64("0111111100>>>xxx100011xxxxxxxxxx", InstName.Sqrshrun_S, InstEmit.Sqrshrun_S, OpCodeSimdShImm.Create);
SetA64("0x10111100>>>xxx100011xxxxxxxxxx", InstName.Sqrshrun_V, InstEmit.Sqrshrun_V, OpCodeSimdShImm.Create);
SetA64("010111110>>>>xxx011101xxxxxxxxxx", InstName.Sqshl_Si, InstEmit.Sqshl_Si, OpCodeSimdShImm.Create);
SetA64("0>001110<<1xxxxx010011xxxxxxxxxx", InstName.Sqshl_V, InstEmit.Sqshl_V, OpCodeSimdReg.Create);
SetA64("0000111100>>>xxx011101xxxxxxxxxx", InstName.Sqshl_Vi, InstEmit.Sqshl_Vi, OpCodeSimdShImm.Create);
SetA64("010011110>>>>xxx011101xxxxxxxxxx", InstName.Sqshl_Vi, InstEmit.Sqshl_Vi, OpCodeSimdShImm.Create);
SetA64("0101111100>>>xxx100101xxxxxxxxxx", InstName.Sqshrn_S, InstEmit.Sqshrn_S, OpCodeSimdShImm.Create);
SetA64("0x00111100>>>xxx100101xxxxxxxxxx", InstName.Sqshrn_V, InstEmit.Sqshrn_V, OpCodeSimdShImm.Create);
SetA64("0111111100>>>xxx100001xxxxxxxxxx", InstName.Sqshrun_S, InstEmit.Sqshrun_S, OpCodeSimdShImm.Create);
@ -746,7 +743,6 @@ namespace ARMeilleure.Decoders
SetA32("<<<<01101000xxxxxxxxxxxxxx01xxxx", InstName.Pkh, InstEmit32.Pkh, OpCode32AluRsImm.Create);
SetA32("11110101xx01xxxx1111xxxxxxxxxxxx", InstName.Pld, InstEmit32.Nop, OpCode32.Create);
SetA32("11110111xx01xxxx1111xxxxxxx0xxxx", InstName.Pld, InstEmit32.Nop, OpCode32.Create);
SetA32("<<<<01100010xxxxxxxx11110001xxxx", InstName.Qadd16, InstEmit32.Qadd16, OpCode32AluReg.Create);
SetA32("<<<<011011111111xxxx11110011xxxx", InstName.Rbit, InstEmit32.Rbit, OpCode32AluReg.Create);
SetA32("<<<<011010111111xxxx11110011xxxx", InstName.Rev, InstEmit32.Rev, OpCode32AluReg.Create);
SetA32("<<<<011010111111xxxx11111011xxxx", InstName.Rev16, InstEmit32.Rev16, OpCode32AluReg.Create);
@ -823,10 +819,6 @@ namespace ARMeilleure.Decoders
SetA32("<<<<00000100xxxxxxxxxxxx1001xxxx", InstName.Umaal, InstEmit32.Umaal, OpCode32AluUmull.Create);
SetA32("<<<<0000101xxxxxxxxxxxxx1001xxxx", InstName.Umlal, InstEmit32.Umlal, OpCode32AluUmull.Create);
SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, OpCode32AluUmull.Create);
SetA32("<<<<01100110xxxxxxxx11110001xxxx", InstName.Uqadd16, InstEmit32.Uqadd16, OpCode32AluReg.Create);
SetA32("<<<<01100110xxxxxxxx11111001xxxx", InstName.Uqadd8, InstEmit32.Uqadd8, OpCode32AluReg.Create);
SetA32("<<<<01100110xxxxxxxx11110111xxxx", InstName.Uqsub16, InstEmit32.Uqsub16, OpCode32AluReg.Create);
SetA32("<<<<01100110xxxxxxxx11111111xxxx", InstName.Uqsub8, InstEmit32.Uqsub8, OpCode32AluReg.Create);
SetA32("<<<<0110111xxxxxxxxxxxxxxx01xxxx", InstName.Usat, InstEmit32.Usat, OpCode32Sat.Create);
SetA32("<<<<01101110xxxxxxxx11110011xxxx", InstName.Usat16, InstEmit32.Usat16, OpCode32Sat16.Create);
SetA32("<<<<01100101xxxxxxxx11111111xxxx", InstName.Usub8, InstEmit32.Usub8, OpCode32AluReg.Create);
@ -880,7 +872,6 @@ namespace ARMeilleure.Decoders
SetVfp("<<<<11100x10xxxxxxxx101xx1x0xxxx", InstName.Vnmul, InstEmit32.Vnmul_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32);
SetVfp("111111101x1110xxxxxx101x01x0xxxx", InstName.Vrint, InstEmit32.Vrint_RM, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
SetVfp("<<<<11101x110110xxxx101x11x0xxxx", InstName.Vrint, InstEmit32.Vrint_Z, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
SetVfp("<<<<11101x110110xxxx101x01x0xxxx", InstName.Vrintr, InstEmit32.Vrintr_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
SetVfp("<<<<11101x110111xxxx101x01x0xxxx", InstName.Vrintx, InstEmit32.Vrintx_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
SetVfp("<<<<11101x110001xxxx101x11x0xxxx", InstName.Vsqrt, InstEmit32.Vsqrt_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32);
SetVfp("111111100xxxxxxxxxxx101xx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, OpCode32SimdSel.Create, OpCode32SimdSel.CreateT32);
@ -1001,7 +992,6 @@ namespace ARMeilleure.Decoders
SetAsimd("1111001x1x000xxxxxxx<<x10x01xxxx", InstName.Vorr, InstEmit32.Vorr_II, OpCode32SimdImm.Create, OpCode32SimdImm.CreateT32);
SetAsimd("111100100x<<xxxxxxxx1011x0x1xxxx", InstName.Vpadd, InstEmit32.Vpadd_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
SetAsimd("111100110x00xxxxxxxx1101x0x0xxxx", InstName.Vpadd, InstEmit32.Vpadd_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
SetAsimd("111100111x11<<00xxxx0110xxx0xxxx", InstName.Vpadal, InstEmit32.Vpadal, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
SetAsimd("111100111x11<<00xxxx0010xxx0xxxx", InstName.Vpaddl, InstEmit32.Vpaddl, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
SetAsimd("1111001x0x<<xxxxxxxx1010x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
SetAsimd("111100110x00xxxxxxxx1111x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
@ -1012,8 +1002,6 @@ namespace ARMeilleure.Decoders
SetAsimd("111100100x10xxxxxxxx1011xxx0xxxx", InstName.Vqdmulh, InstEmit32.Vqdmulh, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
SetAsimd("111100111x11<<10xxxx00101xx0xxx0", InstName.Vqmovn, InstEmit32.Vqmovn, OpCode32SimdMovn.Create, OpCode32SimdMovn.CreateT32);
SetAsimd("111100111x11<<10xxxx001001x0xxx0", InstName.Vqmovun, InstEmit32.Vqmovun, OpCode32SimdMovn.Create, OpCode32SimdMovn.CreateT32);
SetAsimd("111100110x01xxxxxxxx1011xxx0xxxx", InstName.Vqrdmulh, InstEmit32.Vqrdmulh, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
SetAsimd("111100110x10xxxxxxxx1011xxx0xxxx", InstName.Vqrdmulh, InstEmit32.Vqrdmulh, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
SetAsimd("1111001x1x>>>xxxxxxx100101x1xxx0", InstName.Vqrshrn, InstEmit32.Vqrshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
SetAsimd("111100111x>>>xxxxxxx100001x1xxx0", InstName.Vqrshrun, InstEmit32.Vqrshrun, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
SetAsimd("1111001x1x>>>xxxxxxx100100x1xxx0", InstName.Vqshrn, InstEmit32.Vqshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
@ -1035,10 +1023,8 @@ namespace ARMeilleure.Decoders
SetAsimd("111100101x>>>xxxxxxx0101>xx1xxxx", InstName.Vshl, InstEmit32.Vshl, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
SetAsimd("1111001x0xxxxxxxxxxx0100xxx0xxxx", InstName.Vshl, InstEmit32.Vshl_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
SetAsimd("1111001x1x>>>xxxxxxx101000x1xxxx", InstName.Vshll, InstEmit32.Vshll, OpCode32SimdShImmLong.Create, OpCode32SimdShImmLong.CreateT32); // A1 encoding.
SetAsimd("111100111x11<<10xxxx001100x0xxxx", InstName.Vshll, InstEmit32.Vshll2, OpCode32SimdMovn.Create, OpCode32SimdMovn.CreateT32); // A2 encoding.
SetAsimd("1111001x1x>>>xxxxxxx0000>xx1xxxx", InstName.Vshr, InstEmit32.Vshr, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
SetAsimd("111100101x>>>xxxxxxx100000x1xxx0", InstName.Vshrn, InstEmit32.Vshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
SetAsimd("111100111x>>>xxxxxxx0101>xx1xxxx", InstName.Vsli, InstEmit32.Vsli_I, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
SetAsimd("1111001x1x>>>xxxxxxx0001>xx1xxxx", InstName.Vsra, InstEmit32.Vsra, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
SetAsimd("111101001x00xxxxxxxx0000xxx0xxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
SetAsimd("111101001x00xxxxxxxx0100xx0xxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
@ -1063,7 +1049,6 @@ namespace ARMeilleure.Decoders
SetAsimd("111100100x10xxxxxxxx1101xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
SetAsimd("1111001x1x<<xxxxxxx00010x0x0xxxx", InstName.Vsubl, InstEmit32.Vsubl_I, OpCode32SimdRegLong.Create, OpCode32SimdRegLong.CreateT32);
SetAsimd("1111001x1x<<xxxxxxx00011x0x0xxxx", InstName.Vsubw, InstEmit32.Vsubw_I, OpCode32SimdRegWide.Create, OpCode32SimdRegWide.CreateT32);
SetAsimd("111100111x110010xxxx00000xx0xxxx", InstName.Vswp, InstEmit32.Vswp, OpCode32Simd.Create, OpCode32Simd.CreateT32);
SetAsimd("111100111x11xxxxxxxx10xxxxx0xxxx", InstName.Vtbl, InstEmit32.Vtbl, OpCode32SimdTbl.Create, OpCode32SimdTbl.CreateT32);
SetAsimd("111100111x11<<10xxxx00001xx0xxxx", InstName.Vtrn, InstEmit32.Vtrn, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
SetAsimd("111100100x<<xxxxxxxx1000xxx1xxxx", InstName.Vtst, InstEmit32.Vtst, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);

View File

@ -2,8 +2,6 @@ using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using static ARMeilleure.Instructions.InstEmitAluHelper;
using static ARMeilleure.Instructions.InstEmitHelper;
@ -21,12 +19,6 @@ namespace ARMeilleure.Instructions
Operand n = GetAluN(context);
Operand m = GetAluM(context, setCarry: false);
if (op.Rn == RegisterAlias.Aarch32Pc && op is OpCodeT32AluImm12)
{
// For ADR, PC is always 4 bytes aligned, even in Thumb mode.
n = context.BitwiseAnd(n, Const(~3u));
}
Operand res = context.Add(n, m);
if (ShouldSetFlags(context))
@ -292,16 +284,6 @@ namespace ARMeilleure.Instructions
EmitAluStore(context, res);
}
public static void Qadd16(ArmEmitterContext context)
{
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
SetIntA32(context, op.Rd, EmitSigned16BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) =>
{
EmitSaturateRange(context, d, context.Add(n, m), 16, unsigned: false, setQ: false);
}));
}
public static void Rbit(ArmEmitterContext context)
{
Operand m = GetAluM(context);
@ -485,12 +467,6 @@ namespace ARMeilleure.Instructions
Operand n = GetAluN(context);
Operand m = GetAluM(context, setCarry: false);
if (op.Rn == RegisterAlias.Aarch32Pc && op is OpCodeT32AluImm12)
{
// For ADR, PC is always 4 bytes aligned, even in Thumb mode.
n = context.BitwiseAnd(n, Const(~3u));
}
Operand res = context.Subtract(n, m);
if (ShouldSetFlags(context))
@ -570,46 +546,6 @@ namespace ARMeilleure.Instructions
EmitHsub8(context, unsigned: true);
}
public static void Uqadd16(ArmEmitterContext context)
{
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
SetIntA32(context, op.Rd, EmitUnsigned16BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) =>
{
EmitSaturateUqadd(context, d, context.Add(n, m), 16);
}));
}
public static void Uqadd8(ArmEmitterContext context)
{
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
SetIntA32(context, op.Rd, EmitUnsigned8BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) =>
{
EmitSaturateUqadd(context, d, context.Add(n, m), 8);
}));
}
public static void Uqsub16(ArmEmitterContext context)
{
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
SetIntA32(context, op.Rd, EmitUnsigned16BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) =>
{
EmitSaturateUqsub(context, d, context.Subtract(n, m), 16);
}));
}
public static void Uqsub8(ArmEmitterContext context)
{
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
SetIntA32(context, op.Rd, EmitUnsigned8BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) =>
{
EmitSaturateUqsub(context, d, context.Subtract(n, m), 8);
}));
}
public static void Usat(ArmEmitterContext context)
{
OpCode32Sat op = (OpCode32Sat)context.CurrOp;
@ -986,251 +922,6 @@ namespace ARMeilleure.Instructions
}
}
private static void EmitSaturateRange(ArmEmitterContext context, Operand result, Operand value, uint saturateTo, bool unsigned, bool setQ = true)
{
Debug.Assert(saturateTo <= 32);
Debug.Assert(!unsigned || saturateTo < 32);
if (!unsigned && saturateTo == 32)
{
// No saturation possible for this case.
context.Copy(result, value);
return;
}
else if (saturateTo == 0)
{
// Result is always zero if we saturate 0 bits.
context.Copy(result, Const(0));
return;
}
Operand satValue;
if (unsigned)
{
// Negative values always saturate (to zero).
// So we must always ignore the sign bit when masking, so that the truncated value will differ from the original one.
satValue = context.BitwiseAnd(value, Const((int)(uint.MaxValue >> (32 - (int)saturateTo))));
}
else
{
satValue = context.ShiftLeft(value, Const(32 - (int)saturateTo));
satValue = context.ShiftRightSI(satValue, Const(32 - (int)saturateTo));
}
// If the result is 0, the values are equal and we don't need saturation.
Operand lblNoSat = Label();
context.BranchIfFalse(lblNoSat, context.Subtract(value, satValue));
// Saturate and set Q flag.
if (unsigned)
{
if (saturateTo == 31)
{
// Only saturation case possible when going from 32 bits signed to 32 or 31 bits unsigned
// is when the signed input is negative, as all positive values are representable on a 31 bits range.
satValue = Const(0);
}
else
{
satValue = context.ShiftRightSI(value, Const(31));
satValue = context.BitwiseNot(satValue);
satValue = context.ShiftRightUI(satValue, Const(32 - (int)saturateTo));
}
}
else
{
if (saturateTo == 1)
{
satValue = context.ShiftRightSI(value, Const(31));
}
else
{
satValue = Const(uint.MaxValue >> (33 - (int)saturateTo));
satValue = context.BitwiseExclusiveOr(satValue, context.ShiftRightSI(value, Const(31)));
}
}
if (setQ)
{
SetFlag(context, PState.QFlag, Const(1));
}
context.Copy(result, satValue);
Operand lblExit = Label();
context.Branch(lblExit);
context.MarkLabel(lblNoSat);
context.Copy(result, value);
context.MarkLabel(lblExit);
}
private static void EmitSaturateUqadd(ArmEmitterContext context, Operand result, Operand value, uint saturateTo)
{
Debug.Assert(saturateTo <= 32);
if (saturateTo == 32)
{
// No saturation possible for this case.
context.Copy(result, value);
return;
}
else if (saturateTo == 0)
{
// Result is always zero if we saturate 0 bits.
context.Copy(result, Const(0));
return;
}
// If the result is 0, the values are equal and we don't need saturation.
Operand lblNoSat = Label();
context.BranchIfFalse(lblNoSat, context.ShiftRightUI(value, Const((int)saturateTo)));
// Saturate.
context.Copy(result, Const(uint.MaxValue >> (32 - (int)saturateTo)));
Operand lblExit = Label();
context.Branch(lblExit);
context.MarkLabel(lblNoSat);
context.Copy(result, value);
context.MarkLabel(lblExit);
}
private static void EmitSaturateUqsub(ArmEmitterContext context, Operand result, Operand value, uint saturateTo)
{
Debug.Assert(saturateTo <= 32);
if (saturateTo == 32)
{
// No saturation possible for this case.
context.Copy(result, value);
return;
}
else if (saturateTo == 0)
{
// Result is always zero if we saturate 0 bits.
context.Copy(result, Const(0));
return;
}
// If the result is 0, the values are equal and we don't need saturation.
Operand lblNoSat = Label();
context.BranchIf(lblNoSat, value, Const(0), Comparison.GreaterOrEqual);
// Saturate.
// Assumes that the value can only underflow, since this is only used for unsigned subtraction.
context.Copy(result, Const(0));
Operand lblExit = Label();
context.Branch(lblExit);
context.MarkLabel(lblNoSat);
context.Copy(result, value);
context.MarkLabel(lblExit);
}
private static Operand EmitSigned16BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction)
{
Operand tempD = context.AllocateLocal(OperandType.I32);
Operand tempN = context.SignExtend16(OperandType.I32, rn);
Operand tempM = context.SignExtend16(OperandType.I32, rm);
elementAction(tempD, tempN, tempM);
Operand tempD2 = context.ZeroExtend16(OperandType.I32, tempD);
tempN = context.ShiftRightSI(rn, Const(16));
tempM = context.ShiftRightSI(rm, Const(16));
elementAction(tempD, tempN, tempM);
return context.BitwiseOr(tempD2, context.ShiftLeft(tempD, Const(16)));
}
private static Operand EmitUnsigned16BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction)
{
Operand tempD = context.AllocateLocal(OperandType.I32);
Operand tempN = context.ZeroExtend16(OperandType.I32, rn);
Operand tempM = context.ZeroExtend16(OperandType.I32, rm);
elementAction(tempD, tempN, tempM);
Operand tempD2 = context.ZeroExtend16(OperandType.I32, tempD);
tempN = context.ShiftRightUI(rn, Const(16));
tempM = context.ShiftRightUI(rm, Const(16));
elementAction(tempD, tempN, tempM);
return context.BitwiseOr(tempD2, context.ShiftLeft(tempD, Const(16)));
}
private static Operand EmitSigned8BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction)
{
return Emit8BitPair(context, rn, rm, elementAction, unsigned: false);
}
private static Operand EmitUnsigned8BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction)
{
return Emit8BitPair(context, rn, rm, elementAction, unsigned: true);
}
private static Operand Emit8BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction, bool unsigned)
{
Operand tempD = context.AllocateLocal(OperandType.I32);
Operand result = default;
for (int b = 0; b < 4; b++)
{
Operand nByte = b != 0 ? context.ShiftRightUI(rn, Const(b * 8)) : rn;
Operand mByte = b != 0 ? context.ShiftRightUI(rm, Const(b * 8)) : rm;
if (unsigned)
{
nByte = context.ZeroExtend8(OperandType.I32, nByte);
mByte = context.ZeroExtend8(OperandType.I32, mByte);
}
else
{
nByte = context.SignExtend8(OperandType.I32, nByte);
mByte = context.SignExtend8(OperandType.I32, mByte);
}
elementAction(tempD, nByte, mByte);
if (b == 0)
{
result = context.ZeroExtend8(OperandType.I32, tempD);
}
else if (b < 3)
{
result = context.BitwiseOr(result, context.ShiftLeft(context.ZeroExtend8(OperandType.I32, tempD), Const(b * 8)));
}
else
{
result = context.BitwiseOr(result, context.ShiftLeft(tempD, Const(24)));
}
}
return result;
}
private static void EmitAluStore(ArmEmitterContext context, Operand value)
{
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;

View File

@ -157,7 +157,7 @@ namespace ARMeilleure.Instructions
context.Copy(temp, value);
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMapped())
{
context.Branch(lblEnd);
@ -198,7 +198,7 @@ namespace ARMeilleure.Instructions
SetInt(context, rt, value);
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMapped())
{
context.Branch(lblEnd);
@ -265,7 +265,7 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(rt), value);
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMapped())
{
context.Branch(lblEnd);
@ -312,7 +312,7 @@ namespace ARMeilleure.Instructions
break;
}
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMapped())
{
context.Branch(lblEnd);
@ -385,7 +385,7 @@ namespace ARMeilleure.Instructions
break;
}
if (!context.Memory.Type.IsHostMappedOrTracked())
if (!context.Memory.Type.IsHostMapped())
{
context.Branch(lblEnd);
@ -403,27 +403,6 @@ namespace ARMeilleure.Instructions
{
return EmitHostMappedPointer(context, address);
}
else if (context.Memory.Type.IsHostTracked())
{
if (address.Type == OperandType.I32)
{
address = context.ZeroExtend32(OperandType.I64, address);
}
if (context.Memory.Type == MemoryManagerType.HostTracked)
{
Operand mask = Const(ulong.MaxValue >> (64 - context.Memory.AddressSpaceBits));
address = context.BitwiseAnd(address, mask);
}
Operand ptBase = !context.HasPtc
? Const(context.Memory.PageTablePointer.ToInt64())
: Const(context.Memory.PageTablePointer.ToInt64(), Ptc.PageTableSymbol);
Operand ptOffset = context.ShiftRightUI(address, Const(PageBits));
return context.Add(address, context.Load(OperandType.I64, context.Add(ptBase, context.ShiftLeft(ptOffset, Const(3)))));
}
int ptLevelBits = context.Memory.AddressSpaceBits - PageBits;
int ptLevelSize = 1 << ptLevelBits;

View File

@ -2426,11 +2426,7 @@ namespace ARMeilleure.Instructions
}
else if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0)
{
// RSQRTSS handles subnormals as zero, which differs from Arm, so we can't use it here.
Operand res = context.AddIntrinsic(Intrinsic.X86Sqrtss, GetVec(op.Rn));
res = context.AddIntrinsic(Intrinsic.X86Rcpss, res);
res = EmitSse41Round32Exp8OpF(context, res, scalar: true);
Operand res = EmitSse41Round32Exp8OpF(context, context.AddIntrinsic(Intrinsic.X86Rsqrtss, GetVec(op.Rn)), scalar: true);
context.Copy(GetVec(op.Rd), context.VectorZeroUpper96(res));
}
@ -2455,11 +2451,7 @@ namespace ARMeilleure.Instructions
}
else if (Optimizations.FastFP && Optimizations.UseSse41 && sizeF == 0)
{
// RSQRTPS handles subnormals as zero, which differs from Arm, so we can't use it here.
Operand res = context.AddIntrinsic(Intrinsic.X86Sqrtps, GetVec(op.Rn));
res = context.AddIntrinsic(Intrinsic.X86Rcpps, res);
res = EmitSse41Round32Exp8OpF(context, res, scalar: false);
Operand res = EmitSse41Round32Exp8OpF(context, context.AddIntrinsic(Intrinsic.X86Rsqrtps, GetVec(op.Rn)), scalar: false);
if (op.RegisterSize == RegisterSize.Simd64)
{

View File

@ -1115,13 +1115,6 @@ namespace ARMeilleure.Instructions
}
}
public static void Vpadal(ArmEmitterContext context)
{
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
EmitVectorPairwiseTernaryLongOpI32(context, (op1, op2, op3) => context.Add(context.Add(op1, op2), op3), op.Opc != 1);
}
public static void Vpaddl(ArmEmitterContext context)
{
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
@ -1246,33 +1239,6 @@ namespace ARMeilleure.Instructions
EmitVectorUnaryNarrowOp32(context, (op1) => EmitSatQ(context, op1, 8 << op.Size, signedSrc: true, signedDst: false), signed: true);
}
public static void Vqrdmulh(ArmEmitterContext context)
{
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
int eSize = 8 << op.Size;
EmitVectorBinaryOpI32(context, (op1, op2) =>
{
if (op.Size == 2)
{
op1 = context.SignExtend32(OperandType.I64, op1);
op2 = context.SignExtend32(OperandType.I64, op2);
}
Operand res = context.Multiply(op1, op2);
res = context.Add(res, Const(res.Type, 1L << (eSize - 2)));
res = context.ShiftRightSI(res, Const(eSize - 1));
res = EmitSatQ(context, res, eSize, signedSrc: true, signedDst: true);
if (op.Size == 2)
{
res = context.ConvertI64ToI32(res);
}
return res;
}, signed: true);
}
public static void Vqsub(ArmEmitterContext context)
{
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;

View File

@ -578,22 +578,6 @@ namespace ARMeilleure.Instructions
}
}
// VRINTR (floating-point).
public static void Vrintr_S(ArmEmitterContext context)
{
if (Optimizations.UseAdvSimd)
{
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, Intrinsic.Arm64FrintiS);
}
else
{
EmitScalarUnaryOpF32(context, (op1) =>
{
return EmitRoundByRMode(context, op1);
});
}
}
// VRINTZ (floating-point).
public static void Vrint_Z(ArmEmitterContext context)
{

View File

@ -673,35 +673,6 @@ namespace ARMeilleure.Instructions
context.Copy(GetVecA32(op.Qd), res);
}
public static void EmitVectorPairwiseTernaryLongOpI32(ArmEmitterContext context, Func3I emit, bool signed)
{
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
int elems = op.GetBytesCount() >> op.Size;
int pairs = elems >> 1;
Operand res = GetVecA32(op.Qd);
for (int index = 0; index < pairs; index++)
{
int pairIndex = index * 2;
Operand m1 = EmitVectorExtract32(context, op.Qm, op.Im + pairIndex, op.Size, signed);
Operand m2 = EmitVectorExtract32(context, op.Qm, op.Im + pairIndex + 1, op.Size, signed);
if (op.Size == 2)
{
m1 = signed ? context.SignExtend32(OperandType.I64, m1) : context.ZeroExtend32(OperandType.I64, m1);
m2 = signed ? context.SignExtend32(OperandType.I64, m2) : context.ZeroExtend32(OperandType.I64, m2);
}
Operand d1 = EmitVectorExtract32(context, op.Qd, op.Id + index, op.Size + 1, signed);
res = EmitVectorInsert(context, res, emit(m1, m2, d1), op.Id + index, op.Size + 1);
}
context.Copy(GetVecA32(op.Qd), res);
}
// Narrow
public static void EmitVectorUnaryNarrowOp32(ArmEmitterContext context, Func1I emit, bool signed = false)

View File

@ -191,26 +191,6 @@ namespace ARMeilleure.Instructions
context.Copy(GetVecA32(op.Qd), res);
}
public static void Vswp(ArmEmitterContext context)
{
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
if (op.Q)
{
Operand temp = context.Copy(GetVecA32(op.Qd));
context.Copy(GetVecA32(op.Qd), GetVecA32(op.Qm));
context.Copy(GetVecA32(op.Qm), temp);
}
else
{
Operand temp = ExtractScalar(context, OperandType.I64, op.Vd);
InsertScalar(context, op.Vd, ExtractScalar(context, OperandType.I64, op.Vm));
InsertScalar(context, op.Vm, temp);
}
}
public static void Vtbl(ArmEmitterContext context)
{
OpCode32SimdTbl op = (OpCode32SimdTbl)context.CurrOp;

View File

@ -116,7 +116,7 @@ namespace ARMeilleure.Instructions
}
else if (shift >= eSize)
{
if (op.RegisterSize == RegisterSize.Simd64)
if ((op.RegisterSize == RegisterSize.Simd64))
{
Operand res = context.VectorZeroUpper64(GetVec(op.Rd));
@ -359,16 +359,6 @@ namespace ARMeilleure.Instructions
}
}
public static void Sqshl_Si(ArmEmitterContext context)
{
EmitShlImmOp(context, signedDst: true, ShlRegFlags.Signed | ShlRegFlags.Scalar | ShlRegFlags.Saturating);
}
public static void Sqshl_Vi(ArmEmitterContext context)
{
EmitShlImmOp(context, signedDst: true, ShlRegFlags.Signed | ShlRegFlags.Saturating);
}
public static void Sqshrn_S(ArmEmitterContext context)
{
if (Optimizations.UseAdvSimd)
@ -1603,99 +1593,6 @@ namespace ARMeilleure.Instructions
Saturating = 1 << 3,
}
private static void EmitShlImmOp(ArmEmitterContext context, bool signedDst, ShlRegFlags flags = ShlRegFlags.None)
{
bool scalar = flags.HasFlag(ShlRegFlags.Scalar);
bool signed = flags.HasFlag(ShlRegFlags.Signed);
bool saturating = flags.HasFlag(ShlRegFlags.Saturating);
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
Operand res = context.VectorZero();
int elems = !scalar ? op.GetBytesCount() >> op.Size : 1;
for (int index = 0; index < elems; index++)
{
Operand ne = EmitVectorExtract(context, op.Rn, index, op.Size, signed);
Operand e = !saturating
? EmitShlImm(context, ne, GetImmShl(op), op.Size)
: EmitShlImmSatQ(context, ne, GetImmShl(op), op.Size, signed, signedDst);
res = EmitVectorInsert(context, res, e, index, op.Size);
}
context.Copy(GetVec(op.Rd), res);
}
private static Operand EmitShlImm(ArmEmitterContext context, Operand op, int shiftLsB, int size)
{
int eSize = 8 << size;
Debug.Assert(op.Type == OperandType.I64);
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
Operand res = context.AllocateLocal(OperandType.I64);
if (shiftLsB >= eSize)
{
Operand shl = context.ShiftLeft(op, Const(shiftLsB));
context.Copy(res, shl);
}
else
{
Operand zeroL = Const(0L);
context.Copy(res, zeroL);
}
return res;
}
private static Operand EmitShlImmSatQ(ArmEmitterContext context, Operand op, int shiftLsB, int size, bool signedSrc, bool signedDst)
{
int eSize = 8 << size;
Debug.Assert(op.Type == OperandType.I64);
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
Operand lblEnd = Label();
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
if (shiftLsB >= eSize)
{
context.Copy(res, signedSrc
? EmitSignedSignSatQ(context, op, size)
: EmitUnsignedSignSatQ(context, op, size));
}
else
{
Operand shl = context.ShiftLeft(op, Const(shiftLsB));
if (eSize == 64)
{
Operand sarOrShr = signedSrc
? context.ShiftRightSI(shl, Const(shiftLsB))
: context.ShiftRightUI(shl, Const(shiftLsB));
context.Copy(res, shl);
context.BranchIf(lblEnd, sarOrShr, op, Comparison.Equal);
context.Copy(res, signedSrc
? EmitSignedSignSatQ(context, op, size)
: EmitUnsignedSignSatQ(context, op, size));
}
else
{
context.Copy(res, signedSrc
? EmitSignedSrcSatQ(context, shl, size, signedDst)
: EmitUnsignedSrcSatQ(context, shl, size, signedDst));
}
}
context.MarkLabel(lblEnd);
return res;
}
private static void EmitShlRegOp(ArmEmitterContext context, ShlRegFlags flags = ShlRegFlags.None)
{
bool scalar = flags.HasFlag(ShlRegFlags.Scalar);

View File

@ -106,38 +106,6 @@ namespace ARMeilleure.Instructions
context.Copy(GetVecA32(op.Qd), res);
}
public static void Vshll2(ArmEmitterContext context)
{
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
Operand res = context.VectorZero();
int elems = op.GetBytesCount() >> op.Size;
for (int index = 0; index < elems; index++)
{
Operand me = EmitVectorExtract32(context, op.Qm, op.Im + index, op.Size, !op.U);
if (op.Size == 2)
{
if (op.U)
{
me = context.ZeroExtend32(OperandType.I64, me);
}
else
{
me = context.SignExtend32(OperandType.I64, me);
}
}
me = context.ShiftLeft(me, Const(8 << op.Size));
res = EmitVectorInsert(context, res, me, index, op.Size + 1);
}
context.Copy(GetVecA32(op.Qd), res);
}
public static void Vshr(ArmEmitterContext context)
{
OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
@ -162,36 +130,6 @@ namespace ARMeilleure.Instructions
EmitVectorUnaryNarrowOp32(context, (op1) => context.ShiftRightUI(op1, Const(shift)));
}
public static void Vsli_I(ArmEmitterContext context)
{
OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
int shift = op.Shift;
int eSize = 8 << op.Size;
ulong mask = shift != 0 ? ulong.MaxValue >> (64 - shift) : 0UL;
Operand res = GetVec(op.Qd);
int elems = op.GetBytesCount() >> op.Size;
for (int index = 0; index < elems; index++)
{
Operand me = EmitVectorExtractZx(context, op.Qm, op.Im + index, op.Size);
Operand neShifted = context.ShiftLeft(me, Const(shift));
Operand de = EmitVectorExtractZx(context, op.Qd, op.Id + index, op.Size);
Operand deMasked = context.BitwiseAnd(de, Const(mask));
Operand e = context.BitwiseOr(neShifted, deMasked);
res = EmitVectorInsert(context, res, e, op.Id + index, op.Size);
}
context.Copy(GetVec(op.Qd), res);
}
public static void Vsra(ArmEmitterContext context)
{
OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;

View File

@ -384,9 +384,7 @@ namespace ARMeilleure.Instructions
Sqrshrn_V,
Sqrshrun_S,
Sqrshrun_V,
Sqshl_Si,
Sqshl_V,
Sqshl_Vi,
Sqshrn_S,
Sqshrn_V,
Sqshrun_S,
@ -527,7 +525,6 @@ namespace ARMeilleure.Instructions
Pld,
Pop,
Push,
Qadd16,
Rev,
Revsh,
Rsb,
@ -572,10 +569,6 @@ namespace ARMeilleure.Instructions
Umaal,
Umlal,
Umull,
Uqadd16,
Uqadd8,
Uqsub16,
Uqsub8,
Usat,
Usat16,
Usub8,
@ -642,7 +635,6 @@ namespace ARMeilleure.Instructions
Vorn,
Vorr,
Vpadd,
Vpadal,
Vpaddl,
Vpmax,
Vpmin,
@ -650,7 +642,6 @@ namespace ARMeilleure.Instructions
Vqdmulh,
Vqmovn,
Vqmovun,
Vqrdmulh,
Vqrshrn,
Vqrshrun,
Vqshrn,
@ -663,7 +654,6 @@ namespace ARMeilleure.Instructions
Vrintm,
Vrintn,
Vrintp,
Vrintr,
Vrintx,
Vrshr,
Vrshrn,
@ -672,7 +662,6 @@ namespace ARMeilleure.Instructions
Vshll,
Vshr,
Vshrn,
Vsli,
Vst1,
Vst2,
Vst3,
@ -689,7 +678,6 @@ namespace ARMeilleure.Instructions
Vsub,
Vsubl,
Vsubw,
Vswp,
Vtbl,
Vtrn,
Vtst,

View File

@ -91,54 +91,54 @@ namespace ARMeilleure.Instructions
#region "Read"
public static byte ReadByte(ulong address)
{
return GetMemoryManager().ReadGuest<byte>(address);
return GetMemoryManager().ReadTracked<byte>(address);
}
public static ushort ReadUInt16(ulong address)
{
return GetMemoryManager().ReadGuest<ushort>(address);
return GetMemoryManager().ReadTracked<ushort>(address);
}
public static uint ReadUInt32(ulong address)
{
return GetMemoryManager().ReadGuest<uint>(address);
return GetMemoryManager().ReadTracked<uint>(address);
}
public static ulong ReadUInt64(ulong address)
{
return GetMemoryManager().ReadGuest<ulong>(address);
return GetMemoryManager().ReadTracked<ulong>(address);
}
public static V128 ReadVector128(ulong address)
{
return GetMemoryManager().ReadGuest<V128>(address);
return GetMemoryManager().ReadTracked<V128>(address);
}
#endregion
#region "Write"
public static void WriteByte(ulong address, byte value)
{
GetMemoryManager().WriteGuest(address, value);
GetMemoryManager().Write(address, value);
}
public static void WriteUInt16(ulong address, ushort value)
{
GetMemoryManager().WriteGuest(address, value);
GetMemoryManager().Write(address, value);
}
public static void WriteUInt32(ulong address, uint value)
{
GetMemoryManager().WriteGuest(address, value);
GetMemoryManager().Write(address, value);
}
public static void WriteUInt64(ulong address, ulong value)
{
GetMemoryManager().WriteGuest(address, value);
GetMemoryManager().Write(address, value);
}
public static void WriteVector128(ulong address, V128 value)
{
GetMemoryManager().WriteGuest(address, value);
GetMemoryManager().Write(address, value);
}
#endregion

View File

@ -28,17 +28,6 @@ namespace ARMeilleure.Memory
/// <returns>The data</returns>
T ReadTracked<T>(ulong va) where T : unmanaged;
/// <summary>
/// Reads data from CPU mapped memory, from guest code. (with read tracking)
/// </summary>
/// <typeparam name="T">Type of the data being read</typeparam>
/// <param name="va">Virtual address of the data in memory</param>
/// <returns>The data</returns>
T ReadGuest<T>(ulong va) where T : unmanaged
{
return ReadTracked<T>(va);
}
/// <summary>
/// Writes data to CPU mapped memory.
/// </summary>
@ -47,17 +36,6 @@ namespace ARMeilleure.Memory
/// <param name="value">Data to be written</param>
void Write<T>(ulong va, T value) where T : unmanaged;
/// <summary>
/// Writes data to CPU mapped memory, from guest code.
/// </summary>
/// <typeparam name="T">Type of the data being written</typeparam>
/// <param name="va">Virtual address to write the data into</param>
/// <param name="value">Data to be written</param>
void WriteGuest<T>(ulong va, T value) where T : unmanaged
{
Write(va, value);
}
/// <summary>
/// Gets a read-only span of data from CPU mapped memory.
/// </summary>

View File

@ -18,12 +18,6 @@ namespace ARMeilleure.Memory
/// </summary>
SoftwarePageTable,
/// <summary>
/// High level implementation using a software flat page table for address translation,
/// no support for handling invalid or non-contiguous memory access.
/// </summary>
HostTracked,
/// <summary>
/// High level implementation with mappings managed by the host OS, effectively using hardware
/// page tables. No address translation is performed in software and the memory is just accessed directly.
@ -35,12 +29,6 @@ namespace ARMeilleure.Memory
/// Allows invalid access from JIT code to the rest of the program, but is faster.
/// </summary>
HostMappedUnsafe,
/// <summary>
/// High level implementation using a software flat page table for address translation
/// without masking the address and no support for handling invalid or non-contiguous memory access.
/// </summary>
HostTrackedUnsafe,
}
public static class MemoryManagerTypeExtensions
@ -49,15 +37,5 @@ namespace ARMeilleure.Memory
{
return type == MemoryManagerType.HostMapped || type == MemoryManagerType.HostMappedUnsafe;
}
public static bool IsHostTracked(this MemoryManagerType type)
{
return type == MemoryManagerType.HostTracked || type == MemoryManagerType.HostTrackedUnsafe;
}
public static bool IsHostMappedOrTracked(this MemoryManagerType type)
{
return type.IsHostMapped() || type.IsHostTracked();
}
}
}

View File

@ -7,7 +7,6 @@ namespace ARMeilleure.Memory
public const int DefaultGranularity = 65536; // Mapping granularity in Windows.
public IJitMemoryBlock Block { get; }
public IJitMemoryAllocator Allocator { get; }
public IntPtr Pointer => Block.Pointer;
@ -22,7 +21,6 @@ namespace ARMeilleure.Memory
granularity = DefaultGranularity;
}
Allocator = allocator;
Block = allocator.Reserve(maxSize);
_maxSize = maxSize;
_sizeGranularity = granularity;

View File

@ -11,35 +11,4 @@ namespace ARMeilleure.Native
[LibraryImport("libarmeilleure-jitsupport", EntryPoint = "armeilleure_jit_memcpy")]
public static partial void Copy(IntPtr dst, IntPtr src, ulong n);
}
[SupportedOSPlatform("ios")]
internal static partial class JitSupportDarwinAot
{
[LibraryImport("pthread", EntryPoint = "pthread_jit_write_protect_np")]
private static partial void pthread_jit_write_protect_np(int enabled);
[LibraryImport("libc", EntryPoint = "sys_icache_invalidate")]
private static partial void sys_icache_invalidate(IntPtr start, IntPtr length);
public static unsafe void Copy(IntPtr dst, IntPtr src, ulong n) {
// When NativeAOT is in use, we can toggle per-thread write protection without worrying about breaking .NET code.
// pthread_jit_write_protect_np(0);
var srcSpan = new Span<byte>(src.ToPointer(), (int)n);
var dstSpan = new Span<byte>(dst.ToPointer(), (int)n);
srcSpan.CopyTo(dstSpan);
// pthread_jit_write_protect_np(1);
// Ensure that the instruction cache for this range is invalidated.
sys_icache_invalidate(dst, (IntPtr)n);
}
public static unsafe void Invalidate(IntPtr dst, ulong n)
{
// Ensure that the instruction cache for this range is invalidated.
sys_icache_invalidate(dst, (IntPtr)n);
}
}
}

View File

@ -21,8 +21,10 @@ namespace ARMeilleure.Signal
private const uint EXCEPTION_ACCESS_VIOLATION = 0xc0000005;
private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite, int rangeStructSize)
private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite, int rangeStructSize, ulong pageSize)
{
ulong pageMask = pageSize - 1;
Operand inRegionLocal = context.AllocateLocal(OperandType.I32);
context.Copy(inRegionLocal, Const(0));
@ -49,7 +51,7 @@ namespace ARMeilleure.Signal
// Only call tracking if in range.
context.BranchIfFalse(nextLabel, inRange, BasicBlockFrequency.Cold);
Operand offset = context.Subtract(faultAddress, rangeAddress);
Operand offset = context.BitwiseAnd(context.Subtract(faultAddress, rangeAddress), Const(~pageMask));
// Call the tracking action, with the pointer's relative offset to the base address.
Operand trackingActionPtr = context.Load(OperandType.I64, Const((ulong)signalStructPtr + rangeBaseOffset + 20));
@ -60,10 +62,8 @@ namespace ARMeilleure.Signal
// Tracking action should be non-null to call it, otherwise assume false return.
context.BranchIfFalse(skipActionLabel, trackingActionPtr);
Operand result = context.Call(trackingActionPtr, OperandType.I64, offset, Const(1UL), isWrite);
context.Copy(inRegionLocal, context.ICompareNotEqual(result, Const(0UL)));
GenerateFaultAddressPatchCode(context, faultAddress, result);
Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(pageSize), isWrite);
context.Copy(inRegionLocal, result);
context.MarkLabel(skipActionLabel);
@ -155,7 +155,7 @@ namespace ARMeilleure.Signal
throw new PlatformNotSupportedException();
}
public static byte[] GenerateUnixSignalHandler(IntPtr signalStructPtr, int rangeStructSize)
public static byte[] GenerateUnixSignalHandler(IntPtr signalStructPtr, int rangeStructSize, ulong pageSize)
{
EmitterContext context = new();
@ -168,7 +168,7 @@ namespace ARMeilleure.Signal
Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1.
Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize);
Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize, pageSize);
Operand endLabel = Label();
@ -203,7 +203,7 @@ namespace ARMeilleure.Signal
return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code;
}
public static byte[] GenerateWindowsSignalHandler(IntPtr signalStructPtr, int rangeStructSize)
public static byte[] GenerateWindowsSignalHandler(IntPtr signalStructPtr, int rangeStructSize, ulong pageSize)
{
EmitterContext context = new();
@ -232,7 +232,7 @@ namespace ARMeilleure.Signal
Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1.
Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize);
Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize, pageSize);
Operand endLabel = Label();
@ -256,86 +256,5 @@ namespace ARMeilleure.Signal
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code;
}
private static void GenerateFaultAddressPatchCode(EmitterContext context, Operand faultAddress, Operand newAddress)
{
if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
if (SupportsFaultAddressPatchingForHostOs())
{
Operand lblSkip = Label();
context.BranchIf(lblSkip, faultAddress, newAddress, Comparison.Equal);
Operand ucontextPtr = context.LoadArgument(OperandType.I64, 2);
Operand pcCtxAddress = default;
ulong baseRegsOffset = 0;
if (OperatingSystem.IsLinux())
{
pcCtxAddress = context.Add(ucontextPtr, Const(440UL));
baseRegsOffset = 184UL;
}
else if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
{
ucontextPtr = context.Load(OperandType.I64, context.Add(ucontextPtr, Const(48UL)));
pcCtxAddress = context.Add(ucontextPtr, Const(272UL));
baseRegsOffset = 16UL;
}
Operand pc = context.Load(OperandType.I64, pcCtxAddress);
Operand reg = GetAddressRegisterFromArm64Instruction(context, pc);
Operand reg64 = context.ZeroExtend32(OperandType.I64, reg);
Operand regCtxAddress = context.Add(ucontextPtr, context.Add(context.ShiftLeft(reg64, Const(3)), Const(baseRegsOffset)));
Operand regAddress = context.Load(OperandType.I64, regCtxAddress);
Operand addressDelta = context.Subtract(regAddress, faultAddress);
context.Store(regCtxAddress, context.Add(newAddress, addressDelta));
context.MarkLabel(lblSkip);
}
}
}
private static Operand GetAddressRegisterFromArm64Instruction(EmitterContext context, Operand pc)
{
Operand inst = context.Load(OperandType.I32, pc);
Operand reg = context.AllocateLocal(OperandType.I32);
Operand isSysInst = context.ICompareEqual(context.BitwiseAnd(inst, Const(0xFFF80000)), Const(0xD5080000));
Operand lblSys = Label();
Operand lblEnd = Label();
context.BranchIfTrue(lblSys, isSysInst, BasicBlockFrequency.Cold);
context.Copy(reg, context.BitwiseAnd(context.ShiftRightUI(inst, Const(5)), Const(0x1F)));
context.Branch(lblEnd);
context.MarkLabel(lblSys);
context.Copy(reg, context.BitwiseAnd(inst, Const(0x1F)));
context.MarkLabel(lblEnd);
return reg;
}
public static bool SupportsFaultAddressPatchingForHost()
{
return SupportsFaultAddressPatchingForHostArch() && SupportsFaultAddressPatchingForHostOs();
}
private static bool SupportsFaultAddressPatchingForHostArch()
{
return RuntimeInformation.ProcessArchitecture == Architecture.Arm64;
}
private static bool SupportsFaultAddressPatchingForHostOs()
{
return OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS();
}
}
}

View File

@ -30,26 +30,21 @@ namespace ARMeilleure.Translation.Cache
_blocks.Add(new MemoryBlock(0, capacity));
}
public int Allocate(ref int size, int alignment)
public int Allocate(int size)
{
int alignM1 = alignment - 1;
for (int i = 0; i < _blocks.Count; i++)
{
MemoryBlock block = _blocks[i];
int misAlignment = ((block.Offset + alignM1) & (~alignM1)) - block.Offset;
int alignedSize = size + misAlignment;
if (block.Size > alignedSize)
if (block.Size > size)
{
size = alignedSize;
_blocks[i] = new MemoryBlock(block.Offset + alignedSize, block.Size - alignedSize);
return block.Offset + misAlignment;
_blocks[i] = new MemoryBlock(block.Offset + size, block.Size - size);
return block.Offset;
}
else if (block.Size == alignedSize)
else if (block.Size == size)
{
size = alignedSize;
_blocks.RemoveAt(i);
return block.Offset + misAlignment;
return block.Offset;
}
}

View File

@ -3,9 +3,7 @@ using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.Memory;
using ARMeilleure.Native;
using Ryujinx.Memory;
using Ryujinx.Common.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
@ -16,92 +14,58 @@ namespace ARMeilleure.Translation.Cache
static partial class JitCache
{
private static readonly int _pageSize = (int)MemoryBlock.GetPageSize();
private static readonly int _pageMask = _pageSize - 4;
private static readonly int _pageMask = _pageSize - 1;
private const int CodeAlignment = 4; // Bytes.
private const int CacheSize = 128 * 1024 * 1024;
private const int CacheSizeIOS = 128 * 1024 * 1024;
private const int CacheSize = 2047 * 1024 * 1024;
private static ReservedRegion _jitRegion;
private static JitCacheInvalidation _jitCacheInvalidator;
private static List<CacheMemoryAllocator> _cacheAllocators = [];
private static CacheMemoryAllocator _cacheAllocator;
private static readonly List<CacheEntry> _cacheEntries = new();
private static readonly object _lock = new();
private static bool _initialized;
private static readonly List<ReservedRegion> _jitRegions = new();
private static int _activeRegionIndex = 0;
[SupportedOSPlatform("windows")]
[LibraryImport("kernel32.dll", SetLastError = true)]
public static partial IntPtr FlushInstructionCache(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize);
public static void Initialize(IJitMemoryAllocator allocator)
{
if (_initialized)
{
return;
}
lock (_lock)
{
if (_initialized)
{
if (OperatingSystem.IsWindows())
{
// JitUnwindWindows.RemoveFunctionTableHandler(
// _jitRegions[0].Pointer);
}
for (int i = 0; i < _jitRegions.Count; i++)
{
_jitRegions[i].Dispose();
}
_jitRegions.Clear();
_cacheAllocators.Clear();
}
else
{
_initialized = true;
return;
}
_activeRegionIndex = 0;
_jitRegion = new ReservedRegion(allocator, CacheSize);
var firstRegion = new ReservedRegion(allocator, CacheSize);
_jitRegions.Add(firstRegion);
CacheMemoryAllocator firstCacheAllocator = new(CacheSize);
_cacheAllocators.Add(firstCacheAllocator);
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS() && !OperatingSystem.IsIOS())
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
{
_jitCacheInvalidator = new JitCacheInvalidation(allocator);
}
_cacheAllocator = new CacheMemoryAllocator(CacheSize);
if (OperatingSystem.IsWindows())
{
JitUnwindWindows.InstallFunctionTableHandler(
firstRegion.Pointer, CacheSize, firstRegion.Pointer + Allocate(_pageSize)
);
JitUnwindWindows.InstallFunctionTableHandler(_jitRegion.Pointer, CacheSize, _jitRegion.Pointer + Allocate(_pageSize));
}
_initialized = true;
}
}
static ConcurrentQueue<(int funcOffset, int length)> _deferredRxProtect = new();
public static void RunDeferredRxProtects()
{
while (_deferredRxProtect.TryDequeue(out var result))
{
ReservedRegion targetRegion = _jitRegions[_activeRegionIndex];
ReprotectAsExecutable(targetRegion, result.funcOffset, result.length);
}
}
public static IntPtr Map(CompiledFunction func, bool deferProtect)
public static IntPtr Map(CompiledFunction func)
{
byte[] code = func.Code;
@ -109,25 +73,11 @@ namespace ARMeilleure.Translation.Cache
{
Debug.Assert(_initialized);
int funcOffset = Allocate(code.Length, deferProtect);
int funcOffset = Allocate(code.Length);
ReservedRegion targetRegion = _jitRegions[_activeRegionIndex];
IntPtr funcPtr = targetRegion.Pointer + funcOffset;
IntPtr funcPtr = _jitRegion.Pointer + funcOffset;
if (OperatingSystem.IsIOS())
{
Marshal.Copy(code, 0, funcPtr, code.Length);
if (deferProtect)
{
_deferredRxProtect.Enqueue((funcOffset, code.Length));
}
else
{
ReprotectAsExecutable(targetRegion, funcOffset, code.Length);
JitSupportDarwinAot.Invalidate(funcPtr, (ulong)code.Length);
}
}
else if (OperatingSystem.IsMacOS()&& RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
unsafe
{
@ -139,9 +89,9 @@ namespace ARMeilleure.Translation.Cache
}
else
{
ReprotectAsWritable(targetRegion, funcOffset, code.Length);
ReprotectAsWritable(funcOffset, code.Length);
Marshal.Copy(code, 0, funcPtr, code.Length);
ReprotectAsExecutable(targetRegion, funcOffset, code.Length);
ReprotectAsExecutable(funcOffset, code.Length);
if (OperatingSystem.IsWindows() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
@ -161,104 +111,59 @@ namespace ARMeilleure.Translation.Cache
public static void Unmap(IntPtr pointer)
{
if (OperatingSystem.IsIOS())
{
// return;
}
lock (_lock)
{
foreach (var region in _jitRegions)
Debug.Assert(_initialized);
int funcOffset = (int)(pointer.ToInt64() - _jitRegion.Pointer.ToInt64());
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
{
if (pointer.ToInt64() < region.Pointer.ToInt64() ||
pointer.ToInt64() >= (region.Pointer + CacheSize).ToInt64())
{
continue;
}
int funcOffset = (int)(pointer.ToInt64() - region.Pointer.ToInt64());
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
{
_cacheAllocators[_activeRegionIndex].Free(funcOffset, AlignCodeSize(entry.Size));
_cacheEntries.RemoveAt(entryIndex);
}
return;
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
_cacheEntries.RemoveAt(entryIndex);
}
}
}
private static void ReprotectAsWritable(ReservedRegion region, int offset, int size)
private static void ReprotectAsWritable(int offset, int size)
{
int endOffs = offset + size;
int regionStart = offset & ~_pageMask;
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
region.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
_jitRegion.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
}
private static void ReprotectAsExecutable(ReservedRegion region, int offset, int size)
private static void ReprotectAsExecutable(int offset, int size)
{
int endOffs = offset + size;
int regionStart = offset & ~_pageMask;
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
region.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
_jitRegion.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
}
private static int Allocate(int codeSize, bool deferProtect = false)
private static int Allocate(int codeSize)
{
codeSize = AlignCodeSize(codeSize, deferProtect);
codeSize = AlignCodeSize(codeSize);
int alignment = CodeAlignment;
int allocOffset = _cacheAllocator.Allocate(codeSize);
if (OperatingSystem.IsIOS() && !deferProtect)
if (allocOffset < 0)
{
alignment = 0x4000;
throw new OutOfMemoryException("JIT Cache exhausted.");
}
int allocOffset = _cacheAllocators[_activeRegionIndex].Allocate(ref codeSize, alignment);
_jitRegion.ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
if (allocOffset >= 0)
{
_jitRegions[_activeRegionIndex].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
return allocOffset;
}
int exhaustedRegion = _activeRegionIndex;
var newRegion = new ReservedRegion(_jitRegions[0].Allocator, CacheSize);
_jitRegions.Add(newRegion);
_activeRegionIndex = _jitRegions.Count - 1;
int newRegionNumber = _activeRegionIndex;
Logger.Info?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {_activeRegionIndex} ({((long)(_activeRegionIndex + 1) * CacheSize)} Total Allocation).");
_cacheAllocators.Add(new CacheMemoryAllocator(CacheSize));
int allocOffsetNew = _cacheAllocators[_activeRegionIndex].Allocate(ref codeSize, alignment);
if (allocOffsetNew < 0)
{
throw new OutOfMemoryException("Failed to allocate in new Cache Region!");
}
newRegion.ExpandIfNeeded((ulong)allocOffsetNew + (ulong)codeSize);
return allocOffsetNew;
return allocOffset;
}
private static int AlignCodeSize(int codeSize, bool deferProtect = false)
private static int AlignCodeSize(int codeSize)
{
int alignment = CodeAlignment;
if (OperatingSystem.IsIOS() && !deferProtect)
{
alignment = 0x4000;
}
return checked(codeSize + (alignment - 1)) & ~(alignment - 1);
return checked(codeSize + (CodeAlignment - 1)) & ~(CodeAlignment - 1);
}
private static void Add(int offset, int size, UnwindInfo unwindInfo)

View File

@ -114,7 +114,7 @@ namespace ARMeilleure.Translation.Cache
{
int stackOffset = entry.StackOffsetOrAllocSize;
// Debug.Assert(stackOffset % 16 == 0);
Debug.Assert(stackOffset % 16 == 0);
if (stackOffset <= 0xFFFF0)
{
@ -135,7 +135,7 @@ namespace ARMeilleure.Translation.Cache
{
int allocSize = entry.StackOffsetOrAllocSize;
// Debug.Assert(allocSize % 8 == 0);
Debug.Assert(allocSize % 8 == 0);
if (allocSize <= 128)
{

View File

@ -11,7 +11,7 @@ namespace ARMeilleure.Translation
private int[] _postOrderMap;
public int LocalsCount { get; private set; }
public BasicBlock Entry { get; private set; }
public BasicBlock Entry { get; }
public IntrusiveList<BasicBlock> Blocks { get; }
public BasicBlock[] PostOrderBlocks => _postOrderBlocks;
public int[] PostOrderMap => _postOrderMap;
@ -34,15 +34,6 @@ namespace ARMeilleure.Translation
return result;
}
public void UpdateEntry(BasicBlock newEntry)
{
newEntry.AddSuccessor(Entry);
Entry = newEntry;
Blocks.AddFirst(newEntry);
Update();
}
public void Update()
{
RemoveUnreachableBlocks(Blocks);

View File

@ -3,7 +3,6 @@ using ARMeilleure.CodeGen.Linking;
using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.Common;
using ARMeilleure.Memory;
using ARMeilleure.Translation.Cache;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
@ -30,7 +29,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0";
private const uint InternalVersion = 6950; //! To be incremented manually for each change to the ARMeilleure project.
private const uint InternalVersion = 5518; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0";
private const string BackupDir = "1";
@ -414,8 +413,6 @@ namespace ARMeilleure.Translation.PTC
finally
{
ResetCarriersIfNeeded();
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
}
_waitEvent.Set();
@ -745,7 +742,7 @@ namespace ARMeilleure.Translation.PTC
bool highCq)
{
var cFunc = new CompiledFunction(code, unwindInfo, RelocInfo.Empty);
var gFunc = cFunc.MapWithPointer<GuestFunction>(out IntPtr gFuncPointer, true);
var gFunc = cFunc.MapWithPointer<GuestFunction>(out IntPtr gFuncPointer);
return new TranslatedFunction(gFunc, gFuncPointer, callCounter, guestSize, highCq);
}
@ -791,8 +788,6 @@ namespace ARMeilleure.Translation.PTC
{
ResetCarriersIfNeeded();
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
return;
}
@ -827,7 +822,7 @@ namespace ARMeilleure.Translation.PTC
Debug.Assert(Profiler.IsAddressInStaticCodeRange(address));
TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq, deferProtect: true);
TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq);
bool isAddressUnique = translator.Functions.TryAdd(address, func.GuestSize, func);
@ -858,14 +853,8 @@ namespace ARMeilleure.Translation.PTC
Stopwatch sw = Stopwatch.StartNew();
foreach (var thread in threads)
{
thread.Start();
}
foreach (var thread in threads)
{
thread.Join();
}
threads.ForEach((thread) => thread.Start());
threads.ForEach((thread) => thread.Join());
threads.Clear();
@ -1011,7 +1000,7 @@ namespace ARMeilleure.Translation.PTC
osPlatform |= (OperatingSystem.IsLinux() ? 1u : 0u) << 1;
osPlatform |= (OperatingSystem.IsMacOS() ? 1u : 0u) << 2;
osPlatform |= (OperatingSystem.IsWindows() ? 1u : 0u) << 3;
osPlatform |= (OperatingSystem.IsIOS() ? 1u : 0u) << 4;
osPlatform |= (Ryujinx.Common.PlatformInfo.IsBionic ? 1u : 0u) << 4;
#pragma warning restore IDE0055
return osPlatform;

View File

@ -89,17 +89,6 @@ namespace ARMeilleure.Translation
public static void RunPass(ControlFlowGraph cfg, ExecutionMode mode)
{
if (cfg.Entry.Predecessors.Count != 0)
{
// We expect the entry block to have no predecessors.
// This is required because we have a implicit context load at the start of the function,
// but if there is a jump to the start of the function, the context load would trash the modified values.
// Here we insert a new entry block that will jump to the existing entry block.
BasicBlock newEntry = new BasicBlock(cfg.Blocks.Count);
cfg.UpdateEntry(newEntry);
}
// Compute local register inputs and outputs used inside blocks.
RegisterMask[] localInputs = new RegisterMask[cfg.Blocks.Count];
RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count];
@ -212,7 +201,7 @@ namespace ARMeilleure.Translation
// The only block without any predecessor should be the entry block.
// It always needs a context load as it is the first block to run.
if (block == cfg.Entry || hasContextLoad)
if (block.Predecessors.Count == 0 || hasContextLoad)
{
long vecMask = globalInputs[block.Index].VecMask;
long intMask = globalInputs[block.Index].IntMask;

View File

@ -102,8 +102,6 @@ namespace ARMeilleure.Translation
Debug.Assert(Functions.Count == 0);
_ptc.LoadTranslations(this);
_ptc.MakeAndSaveTranslations(this);
JitCache.RunDeferredRxProtects();
}
_ptc.Profiler.Start();
@ -242,7 +240,7 @@ namespace ARMeilleure.Translation
}
}
internal TranslatedFunction Translate(ulong address, ExecutionMode mode, bool highCq, bool singleStep = false, bool deferProtect = false)
internal TranslatedFunction Translate(ulong address, ExecutionMode mode, bool highCq, bool singleStep = false)
{
var context = new ArmEmitterContext(
Memory,
@ -300,7 +298,7 @@ namespace ARMeilleure.Translation
_ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
}
GuestFunction func = compiledFunc.MapWithPointer<GuestFunction>(out IntPtr funcPointer, deferProtect);
GuestFunction func = compiledFunc.MapWithPointer<GuestFunction>(out IntPtr funcPointer);
Allocators.ResetAll();

View File

@ -80,10 +80,7 @@ namespace ARMeilleure.Translation
return true;
}
if (!_disposed)
{
Monitor.Wait(Sync);
}
Monitor.Wait(Sync);
}
}

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTK" />
<PackageReference Include="Ryujinx.SDL2-CS" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,183 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace LibRyujinx.Sample
{
internal static class LibRyujinxInterop
{
private const string dll = "LibRyujinx.dll";
[DllImport(dll, EntryPoint = "initialize")]
public extern static bool Initialize(IntPtr path);
[DllImport(dll, EntryPoint = "graphics_initialize")]
public extern static bool InitializeGraphics(GraphicsConfiguration graphicsConfiguration);
[DllImport(dll, EntryPoint = "device_initialize")]
internal extern static bool InitializeDevice();
[DllImport(dll, EntryPoint = "graphics_initialize_renderer")]
internal extern static bool InitializeGraphicsRenderer(GraphicsBackend backend, NativeGraphicsInterop nativeGraphicsInterop);
[DllImport(dll, EntryPoint = "device_load")]
internal extern static bool LoadApplication(IntPtr pathPtr);
[DllImport(dll, EntryPoint = "graphics_renderer_run_loop")]
internal extern static void RunLoop();
[DllImport(dll, EntryPoint = "graphics_renderer_set_size")]
internal extern static void SetRendererSize(int width, int height);
[DllImport(dll, EntryPoint = "graphics_renderer_set_swap_buffer_callback")]
internal extern static void SetSwapBuffersCallback(IntPtr swapBuffers);
[DllImport(dll, EntryPoint = "graphics_renderer_set_vsync")]
internal extern static void SetVsyncState(bool enabled);
[DllImport(dll, EntryPoint = "input_initialize")]
internal extern static void InitializeInput(int width, int height);
[DllImport(dll, EntryPoint = "input_set_client_size")]
internal extern static void SetClientSize(int width, int height);
[DllImport(dll, EntryPoint = "input_set_touch_point")]
internal extern static void SetTouchPoint(int x, int y);
[DllImport(dll, EntryPoint = "input_release_touch_point")]
internal extern static void ReleaseTouchPoint();
[DllImport(dll, EntryPoint = "input_update")]
internal extern static void UpdateInput();
[DllImport(dll, EntryPoint = "input_set_button_pressed")]
public extern static void SetButtonPressed(GamepadButtonInputId button, IntPtr idPtr);
[DllImport(dll, EntryPoint = "input_set_button_released")]
public extern static void SetButtonReleased(GamepadButtonInputId button, IntPtr idPtr);
[DllImport(dll, EntryPoint = "input_set_stick_axis")]
public extern static void SetStickAxis(StickInputId stick, Vector2 axes, IntPtr idPtr);
[DllImport(dll, EntryPoint = "input_connect_gamepad")]
public extern static IntPtr ConnectGamepad(int index);
}
[StructLayout(LayoutKind.Sequential)]
public struct GraphicsConfiguration
{
public float ResScale = 1f;
public float MaxAnisotropy = -1;
public bool FastGpuTime = true;
public bool Fast2DCopy = true;
public bool EnableMacroJit = false;
public bool EnableMacroHLE = true;
public bool EnableShaderCache = true;
public bool EnableTextureRecompression = false;
public BackendThreading BackendThreading = BackendThreading.Auto;
public AspectRatio AspectRatio = AspectRatio.Fixed16x9;
public GraphicsConfiguration()
{
}
}
public enum GraphicsBackend
{
Vulkan,
OpenGl
}
public enum BackendThreading
{
Auto,
Off,
On
}
public struct NativeGraphicsInterop
{
public IntPtr GlGetProcAddress;
public IntPtr VkNativeContextLoader;
public IntPtr VkCreateSurface;
public IntPtr VkRequiredExtensions;
public int VkRequiredExtensionsCount;
}
public enum AspectRatio
{
Fixed4x3,
Fixed16x9,
Fixed16x10,
Fixed21x9,
Fixed32x9,
Stretched
}
/// <summary>
/// Represent a button from a gamepad.
/// </summary>
public enum GamepadButtonInputId : byte
{
Unbound,
A,
B,
X,
Y,
LeftStick,
RightStick,
LeftShoulder,
RightShoulder,
// Likely axis
LeftTrigger,
// Likely axis
RightTrigger,
DpadUp,
DpadDown,
DpadLeft,
DpadRight,
// Special buttons
Minus,
Plus,
Back = Minus,
Start = Plus,
Guide,
Misc1,
// Xbox Elite paddle
Paddle1,
Paddle2,
Paddle3,
Paddle4,
// PS5 touchpad button
Touchpad,
// Virtual buttons for single joycon
SingleLeftTrigger0,
SingleRightTrigger0,
SingleLeftTrigger1,
SingleRightTrigger1,
Count
}
public enum StickInputId : byte
{
Unbound,
Left,
Right,
Count
}
}

View File

@ -0,0 +1,249 @@
using LibRyujinx.Sample;
using OpenTK.Graphics.OpenGL;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;
using System.Runtime.InteropServices;
namespace LibRyujinx.NativeSample
{
internal class NativeWindow : OpenTK.Windowing.Desktop.NativeWindow
{
private nint del;
public delegate void SwapBuffersCallback();
public delegate IntPtr GetProcAddress(string name);
public delegate IntPtr CreateSurface(IntPtr instance);
private bool _run;
private bool _isVulkan;
private Vector2 _lastPosition;
private bool _mousePressed;
private nint _gamepadIdPtr;
private string? _gamepadId;
public NativeWindow(NativeWindowSettings nativeWindowSettings) : base(nativeWindowSettings)
{
_isVulkan = true;
}
internal unsafe void Start(string gamePath)
{
if (!_isVulkan)
{
MakeCurrent();
}
var getProcAddress = Marshal.GetFunctionPointerForDelegate<GetProcAddress>(x => GLFW.GetProcAddress(x));
var createSurface = Marshal.GetFunctionPointerForDelegate<CreateSurface>( x =>
{
VkHandle surface;
GLFW.CreateWindowSurface(new VkHandle(x) ,this.WindowPtr, null, out surface);
return surface.Handle;
});
var vkExtensions = GLFW.GetRequiredInstanceExtensions();
var pointers = new IntPtr[vkExtensions.Length];
for (int i = 0; i < vkExtensions.Length; i++)
{
pointers[i] = Marshal.StringToHGlobalAnsi(vkExtensions[i]);
}
fixed (IntPtr* ptr = pointers)
{
var nativeGraphicsInterop = new NativeGraphicsInterop()
{
GlGetProcAddress = getProcAddress,
VkRequiredExtensions = (nint)ptr,
VkRequiredExtensionsCount = pointers.Length,
VkCreateSurface = createSurface
};
var success = LibRyujinxInterop.InitializeGraphicsRenderer(_isVulkan ? GraphicsBackend.Vulkan : GraphicsBackend.OpenGl, nativeGraphicsInterop);
success = LibRyujinxInterop.InitializeDevice();
LibRyujinxInterop.InitializeInput(ClientSize.X, ClientSize.Y);
var path = Marshal.StringToHGlobalAnsi(gamePath);
var loaded = LibRyujinxInterop.LoadApplication(path);
LibRyujinxInterop.SetRendererSize(Size.X, Size.Y);
Marshal.FreeHGlobal(path);
}
_gamepadIdPtr = LibRyujinxInterop.ConnectGamepad(0);
_gamepadId = Marshal.PtrToStringAnsi(_gamepadIdPtr);
if (!_isVulkan)
{
Context.MakeNoneCurrent();
}
_run = true;
var thread = new Thread(new ThreadStart(RunLoop));
thread.Start();
UpdateLoop();
thread.Join();
foreach(var ptr in pointers)
{
Marshal.FreeHGlobal(ptr);
}
Marshal.FreeHGlobal(_gamepadIdPtr);
}
public void RunLoop()
{
del = Marshal.GetFunctionPointerForDelegate<SwapBuffersCallback>(SwapBuffers);
LibRyujinxInterop.SetSwapBuffersCallback(del);
if (!_isVulkan)
{
MakeCurrent();
Context.SwapInterval = 0;
}
/* Task.Run(async () =>
{
await Task.Delay(1000);
LibRyujinxInterop.SetVsyncState(true);
});*/
LibRyujinxInterop.RunLoop();
_run = false;
if (!_isVulkan)
{
Context.MakeNoneCurrent();
}
}
private void SwapBuffers()
{
if (!_isVulkan)
{
this.Context.SwapBuffers();
}
}
protected override void OnMouseMove(MouseMoveEventArgs e)
{
base.OnMouseMove(e);
_lastPosition = e.Position;
}
protected override void OnMouseDown(MouseButtonEventArgs e)
{
base.OnMouseDown(e);
if(e.Button == MouseButton.Left)
{
_mousePressed = true;
}
}
protected override void OnResize(ResizeEventArgs e)
{
base.OnResize(e);
if (_run)
{
LibRyujinxInterop.SetRendererSize(e.Width, e.Height);
LibRyujinxInterop.SetClientSize(e.Width, e.Height);
}
}
protected override void OnMouseUp(MouseButtonEventArgs e)
{
base.OnMouseUp(e);
if (e.Button == MouseButton.Left)
{
_mousePressed = false;
}
}
protected override void OnKeyUp(KeyboardKeyEventArgs e)
{
base.OnKeyUp(e);
if (_gamepadIdPtr != IntPtr.Zero)
{
var key = GetKeyMapping(e.Key);
LibRyujinxInterop.SetButtonReleased(key, _gamepadIdPtr);
}
}
protected override void OnKeyDown(KeyboardKeyEventArgs e)
{
base.OnKeyDown(e);
if (_gamepadIdPtr != IntPtr.Zero)
{
var key = GetKeyMapping(e.Key);
LibRyujinxInterop.SetButtonPressed(key, _gamepadIdPtr);
}
}
public void UpdateLoop()
{
while(_run)
{
ProcessWindowEvents(true);
ProcessInputEvents();
ProcessWindowEvents(IsEventDriven);
if (_mousePressed)
{
LibRyujinxInterop.SetTouchPoint((int)_lastPosition.X, (int)_lastPosition.Y);
}
else
{
LibRyujinxInterop.ReleaseTouchPoint();
}
LibRyujinxInterop.UpdateInput();
Thread.Sleep(1);
}
}
public GamepadButtonInputId GetKeyMapping(Keys key)
{
if(_keyMapping.TryGetValue(key, out var mapping))
{
return mapping;
}
return GamepadButtonInputId.Unbound;
}
private Dictionary<Keys, GamepadButtonInputId> _keyMapping = new Dictionary<Keys, GamepadButtonInputId>()
{
{Keys.A, GamepadButtonInputId.A },
{Keys.S, GamepadButtonInputId.B },
{Keys.Z, GamepadButtonInputId.X },
{Keys.X, GamepadButtonInputId.Y },
{Keys.Equal, GamepadButtonInputId.Plus },
{Keys.Minus, GamepadButtonInputId.Minus },
{Keys.Q, GamepadButtonInputId.LeftShoulder },
{Keys.D1, GamepadButtonInputId.LeftTrigger },
{Keys.W, GamepadButtonInputId.RightShoulder },
{Keys.D2, GamepadButtonInputId.RightTrigger },
{Keys.E, GamepadButtonInputId.LeftStick },
{Keys.R, GamepadButtonInputId.RightStick },
{Keys.Up, GamepadButtonInputId.DpadUp },
{Keys.Down, GamepadButtonInputId.DpadDown },
{Keys.Left, GamepadButtonInputId.DpadLeft },
{Keys.Right, GamepadButtonInputId.DpadRight },
{Keys.U, GamepadButtonInputId.SingleLeftTrigger0 },
{Keys.D7, GamepadButtonInputId.SingleLeftTrigger1 },
{Keys.O, GamepadButtonInputId.SingleRightTrigger0 },
{Keys.D9, GamepadButtonInputId.SingleRightTrigger1 }
};
}
}

View File

@ -0,0 +1,33 @@
using LibRyujinx.Sample;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
namespace LibRyujinx.NativeSample
{
internal class Program
{
static void Main(string[] args)
{
if (args.Length > 0)
{
var success = LibRyujinxInterop.Initialize(IntPtr.Zero);
success = LibRyujinxInterop.InitializeGraphics(new GraphicsConfiguration());
var nativeWindowSettings = new NativeWindowSettings()
{
Size = new Vector2i(800, 600),
Title = "Ryujinx",
API = ContextAPI.NoAPI,
IsEventDriven = false,
// This is needed to run on macos
Flags = ContextFlags.ForwardCompatible,
};
using var window = new NativeWindow(nativeWindowSettings);
window.IsVisible = true;
window.Start(args[0]);
}
}
}
}

View File

@ -0,0 +1,49 @@
using Ryujinx.Common.Logging;
using Ryujinx.Common.Logging.Formatters;
using Ryujinx.Common.Logging.Targets;
using System;
namespace LibRyujinx
{
public class AndroidLogTarget : ILogTarget
{
private readonly string _name;
private readonly DefaultLogFormatter _formatter;
string ILogTarget.Name { get => _name; }
public AndroidLogTarget(string name)
{
_name = name;
_formatter = new DefaultLogFormatter();
}
public void Log(object sender, LogEventArgs args)
{
Logcat.AndroidLogPrint(GetLogLevel(args.Level), _name, _formatter.Format(args));
}
private static Logcat.LogLevel GetLogLevel(LogLevel logLevel)
{
return logLevel switch
{
LogLevel.Debug => Logcat.LogLevel.Debug,
LogLevel.Stub => Logcat.LogLevel.Info,
LogLevel.Info => Logcat.LogLevel.Info,
LogLevel.Warning => Logcat.LogLevel.Warn,
LogLevel.Error => Logcat.LogLevel.Error,
LogLevel.Guest => Logcat.LogLevel.Info,
LogLevel.AccessLog => Logcat.LogLevel.Info,
LogLevel.Notice => Logcat.LogLevel.Info,
LogLevel.Trace => Logcat.LogLevel.Verbose,
_ => throw new NotImplementedException(),
};
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
}

View File

@ -0,0 +1,136 @@
using LibHac.Tools.Fs;
using Ryujinx.Common.Logging;
using Ryujinx.HLE;
using Ryujinx.HLE.HOS.Applets;
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
using Ryujinx.HLE.Ui;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace LibRyujinx.Android
{
internal class AndroidUiHandler : IHostUiHandler, IDisposable
{
public IHostUiTheme HostUiTheme => throw new NotImplementedException();
public ManualResetEvent _waitEvent;
public ManualResetEvent _responseEvent;
private bool _isDisposed;
private bool _isOkPressed;
private long _input;
public AndroidUiHandler()
{
_waitEvent = new ManualResetEvent(false);
_responseEvent = new ManualResetEvent(false);
}
public IDynamicTextInputHandler CreateDynamicTextInputHandler()
{
throw new NotImplementedException();
}
public bool DisplayErrorAppletDialog(string title, string message, string[] buttonsText)
{
LibRyujinx.setUiHandlerTitle(LibRyujinx.storeString(title ?? ""));
LibRyujinx.setUiHandlerMessage(LibRyujinx.storeString(message ?? ""));
LibRyujinx.setUiHandlerType(1);
_responseEvent.Reset();
Set();
_responseEvent.WaitOne();
return _isOkPressed;
}
public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText)
{
LibRyujinx.setUiHandlerTitle(LibRyujinx.storeString("Software Keyboard"));
LibRyujinx.setUiHandlerMessage(LibRyujinx.storeString(args.HeaderText ?? ""));
LibRyujinx.setUiHandlerWatermark(LibRyujinx.storeString(args.GuideText ?? ""));
LibRyujinx.setUiHandlerSubtitle(LibRyujinx.storeString(args.SubtitleText ?? ""));
LibRyujinx.setUiHandlerInitialText(LibRyujinx.storeString(args.InitialText ?? ""));
LibRyujinx.setUiHandlerMinLength(args.StringLengthMin);
LibRyujinx.setUiHandlerMaxLength(args.StringLengthMax);
LibRyujinx.setUiHandlerType(2);
LibRyujinx.setUiHandlerKeyboardMode((int)args.KeyboardMode);
_responseEvent.Reset();
Set();
_responseEvent.WaitOne();
userText = _input != -1 ? LibRyujinx.GetStoredString(_input) : "";
return _isOkPressed;
}
public bool DisplayMessageDialog(string title, string message)
{
LibRyujinx.setUiHandlerTitle(LibRyujinx.storeString(title ?? ""));
LibRyujinx.setUiHandlerMessage(LibRyujinx.storeString(message ?? ""));
LibRyujinx.setUiHandlerType(1);
_responseEvent.Reset();
Set();
_responseEvent.WaitOne();
return _isOkPressed;
}
public bool DisplayMessageDialog(ControllerAppletUiArgs args)
{
string playerCount = args.PlayerCountMin == args.PlayerCountMax ? $"exactly {args.PlayerCountMin}" : $"{args.PlayerCountMin}-{args.PlayerCountMax}";
string message = $"Application requests **{playerCount}** player(s) with:\n\n"
+ $"**TYPES:** {args.SupportedStyles}\n\n"
+ $"**PLAYERS:** {string.Join(", ", args.SupportedPlayers)}\n\n"
+ (args.IsDocked ? "Docked mode set. `Handheld` is also invalid.\n\n" : "")
+ "_Please reconfigure Input now and then press OK._";
return DisplayMessageDialog("Controller Applet", message);
}
public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value)
{
// throw new NotImplementedException();
}
internal void Wait()
{
if (_isDisposed)
return;
_waitEvent.Reset();
_waitEvent.WaitOne();
_waitEvent.Reset();
}
internal void Set()
{
if (_isDisposed)
return;
_waitEvent.Set();
}
internal void SetResponse(bool isOkPressed, long input)
{
if (_isDisposed)
return;
_isOkPressed = isOkPressed;
_input = input;
_responseEvent.Set();
}
public void Dispose()
{
_isDisposed = true;
_waitEvent.Set();
_waitEvent.Set();
_responseEvent.Dispose();
_waitEvent.Dispose();
}
}
}

View File

@ -0,0 +1,18 @@
namespace LibRyujinx.Shared.Audio.Oboe
{
internal class OboeAudioBuffer
{
public readonly ulong DriverIdentifier;
public readonly ulong SampleCount;
public readonly byte[] Data;
public ulong SamplePlayed;
public OboeAudioBuffer(ulong driverIdentifier, byte[] data, ulong sampleCount)
{
DriverIdentifier = driverIdentifier;
Data = data;
SampleCount = sampleCount;
SamplePlayed = 0;
}
}
}

View File

@ -0,0 +1,105 @@
using Ryujinx.Audio;
using Ryujinx.Audio.Common;
using Ryujinx.Audio.Integration;
using Ryujinx.Memory;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
namespace LibRyujinx.Shared.Audio.Oboe
{
internal class OboeHardwareDeviceDriver : IHardwareDeviceDriver
{
private readonly ManualResetEvent _updateRequiredEvent;
private readonly ManualResetEvent _pauseEvent;
private readonly ConcurrentDictionary<OboeHardwareDeviceSession, byte> _sessions;
public OboeHardwareDeviceDriver()
{
_updateRequiredEvent = new ManualResetEvent(false);
_pauseEvent = new ManualResetEvent(true);
_sessions = new ConcurrentDictionary<OboeHardwareDeviceSession, byte>();
}
public static bool IsSupported => true;
public ManualResetEvent GetUpdateRequiredEvent()
{
return _updateRequiredEvent;
}
public ManualResetEvent GetPauseEvent()
{
return _pauseEvent;
}
public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume)
{
if (channelCount == 0)
{
channelCount = 2;
}
if (sampleRate == 0)
{
sampleRate = Constants.TargetSampleRate;
}
if (direction != Direction.Output)
{
throw new NotImplementedException("Input direction is currently not implemented on Oboe backend!");
}
OboeHardwareDeviceSession session = new OboeHardwareDeviceSession(this, memoryManager, sampleFormat, sampleRate, channelCount, volume);
_sessions.TryAdd(session, 0);
return session;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
foreach (OboeHardwareDeviceSession session in _sessions.Keys)
{
session.Dispose();
}
_pauseEvent.Dispose();
_sessions.Clear();
}
}
public bool SupportsSampleRate(uint sampleRate)
{
return true;
}
public bool SupportsSampleFormat(SampleFormat sampleFormat)
{
return sampleFormat != SampleFormat.Adpcm;
}
public bool SupportsChannelCount(uint channelCount)
{
return channelCount == 1 || channelCount == 2 || channelCount == 4 || channelCount == 6;
}
public bool SupportsDirection(Direction direction)
{
return direction == Direction.Output;
}
}
}

View File

@ -0,0 +1,189 @@
using Ryujinx.Audio.Backends.Common;
using Ryujinx.Audio.Common;
using Ryujinx.Memory;
using System;
using System.Collections.Generic;
using System.Threading;
namespace LibRyujinx.Shared.Audio.Oboe
{
internal class OboeHardwareDeviceSession : HardwareDeviceSessionOutputBase
{
private OboeHardwareDeviceDriver _driver;
private bool _isClosed;
private bool _isWorkerActive;
private Queue<OboeAudioBuffer> _queuedBuffers;
private bool _isActive;
private ulong _playedSampleCount;
private Thread _workerThread;
private ManualResetEvent _updateRequiredEvent;
private IntPtr _session;
private object _queueLock = new object();
private object _trackLock = new object();
public OboeHardwareDeviceSession(OboeHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
{
_driver = driver;
_isActive = false;
_playedSampleCount = 0;
_isWorkerActive = true;
_queuedBuffers = new Queue<OboeAudioBuffer>();
_updateRequiredEvent = driver.GetUpdateRequiredEvent();
_session = OboeInterop.CreateSession((int)requestedSampleFormat, requestedSampleRate, requestedChannelCount);
_workerThread = new Thread(Update);
_workerThread.Name = $"HardwareDeviceSession.Android.Track";
_workerThread.Start();
SetVolume(requestedVolume);
}
public override void UnregisterBuffer(AudioBuffer buffer) { }
public unsafe void Update(object ignored)
{
while (_isWorkerActive)
{
bool needUpdate = false;
bool hasBuffer;
OboeAudioBuffer buffer;
lock (_queueLock)
{
hasBuffer = _queuedBuffers.TryPeek(out buffer);
}
while (hasBuffer)
{
StartIfNotPlaying();
if (_isClosed)
break;
fixed(byte* ptr = buffer.Data)
OboeInterop.WriteToSession(_session, (ulong)ptr, buffer.SampleCount);
lock (_queueLock)
{
_playedSampleCount += buffer.SampleCount;
_queuedBuffers.TryDequeue(out _);
}
needUpdate = true;
lock (_queueLock)
{
hasBuffer = _queuedBuffers.TryPeek(out buffer);
}
}
if (needUpdate)
{
_updateRequiredEvent.Set();
}
// No work
Thread.Sleep(5);
}
}
public override void Dispose()
{
if (_session == 0)
return;
PrepareToClose();
OboeInterop.CloseSession(_session);
_session = 0;
}
public override void PrepareToClose()
{
_isClosed = true;
_isWorkerActive = false;
_workerThread?.Join();
Stop();
}
private void StartIfNotPlaying()
{
lock (_trackLock)
{
if (_isClosed)
return;
if (OboeInterop.IsPlaying(_session) == 0)
{
Start();
}
}
}
public override void QueueBuffer(AudioBuffer buffer)
{
lock (_queueLock)
{
OboeAudioBuffer driverBuffer = new OboeAudioBuffer(buffer.DataPointer, buffer.Data, GetSampleCount(buffer));
_queuedBuffers.Enqueue(driverBuffer);
if (_isActive)
{
StartIfNotPlaying();
}
}
}
public override float GetVolume()
{
return OboeInterop.GetSessionVolume(_session);
}
public override ulong GetPlayedSampleCount()
{
lock (_queueLock)
{
return _playedSampleCount;
}
}
public override void SetVolume(float volume)
{
volume = 1;
OboeInterop.SetSessionVolume(_session, volume);
}
public override void Start()
{
if (_isClosed)
return;
OboeInterop.StartSession(_session);
}
public override void Stop()
{
OboeInterop.StopSession(_session);
}
public override bool WasBufferFullyConsumed(AudioBuffer buffer)
{
lock (_queueLock)
{
if (!_queuedBuffers.TryPeek(out OboeAudioBuffer driverBuffer))
{
return true;
}
return driverBuffer.DriverIdentifier != buffer.DataPointer;
}
}
}
}

View File

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace LibRyujinx.Shared.Audio.Oboe
{
internal static partial class OboeInterop
{
private const string InteropLib = "libryujinxjni";
[LibraryImport(InteropLib, EntryPoint = "create_session")]
public static partial IntPtr CreateSession(int sample_format,
uint sample_rate,
uint channel_count);
[LibraryImport(InteropLib, EntryPoint = "start_session")]
public static partial void StartSession(IntPtr session);
[LibraryImport(InteropLib, EntryPoint = "stop_session")]
public static partial void StopSession(IntPtr session);
[LibraryImport(InteropLib, EntryPoint = "close_session")]
public static partial void CloseSession(IntPtr session);
[LibraryImport(InteropLib, EntryPoint = "set_session_volume")]
public static partial void SetSessionVolume(IntPtr session, float volume);
[LibraryImport(InteropLib, EntryPoint = "get_session_volume")]
public static partial float GetSessionVolume(IntPtr session);
[LibraryImport(InteropLib, EntryPoint = "is_playing")]
public static partial int IsPlaying(IntPtr session);
[LibraryImport(InteropLib, EntryPoint = "write_to_session")]
public static partial void WriteToSession(IntPtr session, ulong data, ulong samples);
}
}

View File

@ -0,0 +1,799 @@
using LibRyujinx.Jni;
using LibRyujinx.Jni.Pointers;
using LibRyujinx.Jni.Primitives;
using LibRyujinx.Jni.References;
using LibRyujinx.Jni.Values;
using LibRyujinx.Shared.Audio.Oboe;
using Rxmxnx.PInvoke;
using Ryujinx.Audio.Backends.OpenAL;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Logging.Targets;
using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.Input;
using Silk.NET.Core.Loader;
using Silk.NET.Vulkan;
using Silk.NET.Vulkan.Extensions.KHR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace LibRyujinx
{
public static partial class LibRyujinx
{
private static ManualResetEvent _surfaceEvent;
private static long _surfacePtr;
private static long _window = 0;
public static VulkanLoader? VulkanLoader { get; private set; }
[DllImport("libryujinxjni")]
private extern static IntPtr getStringPointer(JEnvRef jEnv, JStringLocalRef s);
[DllImport("libryujinxjni")]
private extern static JStringLocalRef createString(JEnvRef jEnv, IntPtr ch);
[DllImport("libryujinxjni")]
internal extern static long storeString(string ch);
[DllImport("libryujinxjni")]
internal extern static IntPtr getString(long id);
[DllImport("libryujinxjni")]
internal extern static long setUiHandlerTitle(long title);
[DllImport("libryujinxjni")]
internal extern static long setUiHandlerMessage(long message);
[DllImport("libryujinxjni")]
internal extern static long setUiHandlerWatermark(long watermark);
[DllImport("libryujinxjni")]
internal extern static long setUiHandlerInitialText(long text);
[DllImport("libryujinxjni")]
internal extern static long setUiHandlerSubtitle(long text);
[DllImport("libryujinxjni")]
internal extern static long setUiHandlerType(int type);
[DllImport("libryujinxjni")]
internal extern static long setUiHandlerKeyboardMode(int mode);
[DllImport("libryujinxjni")]
internal extern static long setUiHandlerMinLength(int lenght);
[DllImport("libryujinxjni")]
internal extern static long setUiHandlerMaxLength(int lenght);
internal static string GetStoredString(long id)
{
var pointer = getString(id);
if (pointer != IntPtr.Zero)
{
var str = Marshal.PtrToStringAnsi(pointer) ?? "";
Marshal.FreeHGlobal(pointer);
return str;
}
return "";
}
[DllImport("libryujinxjni")]
internal extern static void setRenderingThread();
[DllImport("libryujinxjni")]
internal extern static void debug_break(int code);
[DllImport("libryujinxjni")]
internal extern static void onFrameEnd(double time);
[DllImport("libryujinxjni")]
internal extern static void setProgressInfo(IntPtr info, float progress);
[DllImport("libryujinxjni")]
internal extern static void setCurrentTransform(long native_window, int transform);
public delegate IntPtr JniCreateSurface(IntPtr native_surface, IntPtr instance);
[UnmanagedCallersOnly(EntryPoint = "JNI_OnLoad")]
internal static int LoadLibrary(JavaVMRef vm, IntPtr unknown)
{
return 0x00010006; //JNI_VERSION_1_6
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_initialize")]
public static JBoolean JniInitialize(JEnvRef jEnv, JObjectLocalRef jObj, JLong jpathId)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
PlatformInfo.IsBionic = true;
Logger.AddTarget(
new AsyncLogTargetWrapper(
new AndroidLogTarget("RyujinxLog"),
1000,
AsyncLogTargetOverflowAction.Block
));
var path = GetStoredString(jpathId);
var init = Initialize(path);
_surfaceEvent?.Set();
_surfaceEvent = new ManualResetEvent(false);
return init;
}
private static string? GetString(JEnvRef jEnv, JStringLocalRef jString)
{
var stringPtr = getStringPointer(jEnv, jString);
var s = Marshal.PtrToStringAnsi(stringPtr);
Marshal.FreeHGlobal(stringPtr);
return s;
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceReloadFilesystem")]
public static void JniReloadFileSystem()
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
SwitchDevice?.ReloadFileSystem();
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceInitialize")]
public static JBoolean JniInitializeDeviceNative(JEnvRef jEnv,
JObjectLocalRef jObj,
JBoolean isHostMapped,
JBoolean useNce,
JInt systemLanguage,
JInt regionCode,
JBoolean enableVsync,
JBoolean enableDockedMode,
JBoolean enablePtc,
JBoolean enableInternetAccess,
JLong timeZoneId,
JBoolean ignoreMissingServices)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
AudioDriver = new OpenALHardwareDeviceDriver();//new OboeHardwareDeviceDriver();
return InitializeDevice(isHostMapped,
useNce,
(SystemLanguage)(int)systemLanguage,
(RegionCode)(int)regionCode,
enableVsync,
enableDockedMode,
enablePtc,
enableInternetAccess,
GetStoredString(timeZoneId),
ignoreMissingServices);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetGameFifo")]
public static JDouble JniGetGameFifo(JEnvRef jEnv, JObjectLocalRef jObj)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var stats = SwitchDevice.EmulationContext?.Statistics.GetFifoPercent() ?? 0;
return stats;
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetGameFrameTime")]
public static JDouble JniGetGameFrameTime(JEnvRef jEnv, JObjectLocalRef jObj)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var stats = SwitchDevice.EmulationContext?.Statistics.GetGameFrameTime() ?? 0;
return stats;
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetGameFrameRate")]
public static JDouble JniGetGameFrameRate(JEnvRef jEnv, JObjectLocalRef jObj)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var stats = SwitchDevice.EmulationContext?.Statistics.GetGameFrameRate() ?? 0;
return stats;
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceLoad")]
public static JBoolean JniLoadApplicationNative(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef pathPtr)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
if (SwitchDevice?.EmulationContext == null)
{
return false;
}
var path = GetString(jEnv, pathPtr);
return LoadApplication(path);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceLaunchMiiEditor")]
public static JBoolean JniLaunchMiiEditApplet(JEnvRef jEnv, JObjectLocalRef jObj)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
if (SwitchDevice?.EmulationContext == null)
{
return false;
}
return LaunchMiiEditApplet();
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetDlcContentList")]
public static JArrayLocalRef JniGetDlcContentListNative(JEnvRef jEnv, JObjectLocalRef jObj, JLong pathPtr, JLong titleId)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var list = GetDlcContentList(GetStoredString(pathPtr), (ulong)(long)titleId);
debug_break(4);
return CreateStringArray(jEnv, list);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetDlcTitleId")]
public static JLong JniGetDlcTitleIdNative(JEnvRef jEnv, JObjectLocalRef jObj, JLong pathPtr, JLong ncaPath)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
return storeString(GetDlcTitleId(GetStoredString(pathPtr), GetStoredString(ncaPath)));
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceSignalEmulationClose")]
public static void JniSignalEmulationCloseNative(JEnvRef jEnv, JObjectLocalRef jObj)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
SignalEmulationClose();
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceCloseEmulation")]
public static void JniCloseEmulationNative(JEnvRef jEnv, JObjectLocalRef jObj)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
CloseEmulation();
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceLoadDescriptor")]
public static JBoolean JniLoadApplicationNative(JEnvRef jEnv, JObjectLocalRef jObj, JInt descriptor, JInt type, JInt updateDescriptor)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
if (SwitchDevice?.EmulationContext == null)
{
return false;
}
var stream = OpenFile(descriptor);
var update = updateDescriptor == -1 ? null : OpenFile(updateDescriptor);
return LoadApplication(stream, (FileType)(int)type, update);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceVerifyFirmware")]
public static JLong JniVerifyFirmware(JEnvRef jEnv, JObjectLocalRef jObj, JInt descriptor, JBoolean isXci)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var stream = OpenFile(descriptor);
long stringHandle = -1;
try
{
var version = VerifyFirmware(stream, isXci);
if (version != null)
{
stringHandle = storeString(version.VersionString);
}
}
catch(Exception _)
{
}
return stringHandle;
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceInstallFirmware")]
public static void JniInstallFirmware(JEnvRef jEnv, JObjectLocalRef jObj, JInt descriptor, JBoolean isXci)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var stream = OpenFile(descriptor);
InstallFirmware(stream, isXci);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetInstalledFirmwareVersion")]
public static JLong JniGetInstalledFirmwareVersion(JEnvRef jEnv, JObjectLocalRef jObj)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var version = GetInstalledFirmwareVersion();
long stringHandle = -1;
if (version != String.Empty)
{
stringHandle = storeString(version);
}
return stringHandle;
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsInitialize")]
public static JBoolean JniInitializeGraphicsNative(JEnvRef jEnv, JObjectLocalRef jObj, JObjectLocalRef graphicObject)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
JEnvValue value = jEnv.Environment;
ref JNativeInterface jInterface = ref value.Functions;
IntPtr getObjectClassPtr = jInterface.GetObjectClassPointer;
IntPtr getFieldIdPtr = jInterface.GetFieldIdPointer;
IntPtr getIntFieldPtr = jInterface.GetIntFieldPointer;
IntPtr getLongFieldPtr = jInterface.GetLongFieldPointer;
IntPtr getFloatFieldPtr = jInterface.GetFloatFieldPointer;
IntPtr getBooleanFieldPtr = jInterface.GetBooleanFieldPointer;
var getObjectClass = getObjectClassPtr.GetUnsafeDelegate<GetObjectClassDelegate>();
var getFieldId = getFieldIdPtr.GetUnsafeDelegate<GetFieldIdDelegate>();
var getLongField = getLongFieldPtr.GetUnsafeDelegate<GetLongFieldDelegate>();
var getIntField = getIntFieldPtr.GetUnsafeDelegate<GetIntFieldDelegate>();
var getBooleanField = getBooleanFieldPtr.GetUnsafeDelegate<GetBooleanFieldDelegate>();
var getFloatField = getFloatFieldPtr.GetUnsafeDelegate<GetFloatFieldDelegate>();
var jobject = getObjectClass(jEnv, graphicObject);
GraphicsConfiguration graphicsConfiguration = new()
{
EnableShaderCache = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("EnableShaderCache"), GetCCharSequence("Z"))),
EnableMacroHLE = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("EnableMacroHLE"), GetCCharSequence("Z"))),
EnableMacroJit = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("EnableMacroJit"), GetCCharSequence("Z"))),
EnableTextureRecompression = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("EnableTextureRecompression"), GetCCharSequence("Z"))),
Fast2DCopy = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("Fast2DCopy"), GetCCharSequence("Z"))),
FastGpuTime = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("FastGpuTime"), GetCCharSequence("Z"))),
ResScale = getFloatField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("ResScale"), GetCCharSequence("F"))),
MaxAnisotropy = getFloatField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("MaxAnisotropy"), GetCCharSequence("F"))),
BackendThreading = (BackendThreading)(int)getIntField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("BackendThreading"), GetCCharSequence("I")))
};
SearchPathContainer.Platform = UnderlyingPlatform.Android;
return InitializeGraphics(graphicsConfiguration);
}
private static CCharSequence GetCCharSequence(string s)
{
return Encoding.UTF8.GetBytes(s).AsSpan();
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsSetSurface")]
public static void JniSetSurface(JEnvRef jEnv, JObjectLocalRef jObj, JLong surfacePtr, JLong window)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
_surfacePtr = surfacePtr;
_window = window;
_surfaceEvent.Set();
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsInitializeRenderer")]
public unsafe static JBoolean JniInitializeGraphicsRendererNative(JEnvRef jEnv,
JObjectLocalRef jObj,
JArrayLocalRef extensionsArray,
JLong driverHandle)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
if (Renderer != null)
{
return false;
}
JEnvValue value = jEnv.Environment;
ref JNativeInterface jInterface = ref value.Functions;
IntPtr getObjectClassPtr = jInterface.GetObjectClassPointer;
IntPtr getFieldIdPtr = jInterface.GetFieldIdPointer;
IntPtr getLongFieldPtr = jInterface.GetLongFieldPointer;
IntPtr getArrayLengthPtr = jInterface.GetArrayLengthPointer;
IntPtr getObjectArrayElementPtr = jInterface.GetObjectArrayElementPointer;
IntPtr getObjectFieldPtr = jInterface.GetObjectFieldPointer;
var getObjectClass = getObjectClassPtr.GetUnsafeDelegate<GetObjectClassDelegate>();
var getFieldId = getFieldIdPtr.GetUnsafeDelegate<GetFieldIdDelegate>();
var getArrayLength = getArrayLengthPtr.GetUnsafeDelegate<GetArrayLengthDelegate>();
var getObjectArrayElement = getObjectArrayElementPtr.GetUnsafeDelegate<GetObjectArrayElementDelegate>();
var getLongField = getLongFieldPtr.GetUnsafeDelegate<GetLongFieldDelegate>();
var getObjectField = getObjectFieldPtr.GetUnsafeDelegate<GetObjectFieldDelegate>();
List<string?> extensions = new();
var count = getArrayLength(jEnv, extensionsArray);
for (int i = 0; i < count; i++)
{
var obj = getObjectArrayElement(jEnv, extensionsArray, i);
var ext = obj.Transform<JObjectLocalRef, JStringLocalRef>();
extensions.Add(GetString(jEnv, ext));
}
if ((long)driverHandle != 0)
{
VulkanLoader = new VulkanLoader((IntPtr)(long)driverHandle);
}
CreateSurface createSurfaceFunc = instance =>
{
_surfaceEvent.WaitOne();
_surfaceEvent.Reset();
var api = VulkanLoader?.GetApi() ?? Vk.GetApi();
if (api.TryGetInstanceExtension(new Instance(instance), out KhrAndroidSurface surfaceExtension))
{
var createInfo = new AndroidSurfaceCreateInfoKHR
{
SType = StructureType.AndroidSurfaceCreateInfoKhr,
Window = (nint*)_surfacePtr,
};
var result = surfaceExtension.CreateAndroidSurface(new Instance(instance), createInfo, null, out var surface);
return (nint)surface.Handle;
}
return IntPtr.Zero;
};
return InitializeGraphicsRenderer(GraphicsBackend.Vulkan, createSurfaceFunc, extensions.ToArray());
}
private static JArrayLocalRef CreateStringArray(JEnvRef jEnv, List<string> strings)
{
JEnvValue value = jEnv.Environment;
ref JNativeInterface jInterface = ref value.Functions;
IntPtr newObjectArrayPtr = jInterface.NewObjectArrayPointer;
IntPtr findClassPtr = jInterface.FindClassPointer;
IntPtr setObjectArrayElementPtr = jInterface.SetObjectArrayElementPointer;
var newObjectArray = newObjectArrayPtr.GetUnsafeDelegate<NewObjectArrayDelegate>();
var findClass = findClassPtr.GetUnsafeDelegate<FindClassDelegate>();
var setObjectArrayElement = setObjectArrayElementPtr.GetUnsafeDelegate<SetObjectArrayElementDelegate>();
var array = newObjectArray(jEnv, strings.Count, findClass(jEnv, GetCCharSequence("java/lang/String")), CreateString(jEnv, "")._value);
for (int i = 0; i < strings.Count; i++)
{
setObjectArrayElement(jEnv, array, i, CreateString(jEnv, strings[i])._value);
}
return array;
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsRendererSetSize")]
public static void JniSetRendererSizeNative(JEnvRef jEnv, JObjectLocalRef jObj, JInt width, JInt height)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
Renderer?.Window?.SetSize(width, height);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsRendererRunLoop")]
public static void JniRunLoopNative(JEnvRef jEnv, JObjectLocalRef jObj)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
SetSwapBuffersCallback(() =>
{
var time = SwitchDevice.EmulationContext.Statistics.GetGameFrameTime();
onFrameEnd(time);
});
RunLoop();
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_loggingSetEnabled")]
public static void JniSetLoggingEnabledNative(JEnvRef jEnv, JObjectLocalRef jObj, JInt logLevel, JBoolean enabled)
{
Logger.SetEnable((LogLevel)(int)logLevel, enabled);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetGameInfoFromPath")]
public static JObjectLocalRef JniGetGameInfo(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef path)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var info = GetGameInfo(GetString(jEnv, path));
return GetInfo(jEnv, info);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetGameInfo")]
public static JObjectLocalRef JniGetGameInfo(JEnvRef jEnv, JObjectLocalRef jObj, JInt fileDescriptor, JLong extension)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
using var stream = OpenFile(fileDescriptor);
var ext = GetStoredString(extension);
var info = GetGameInfo(stream, ext.ToLower());
return GetInfo(jEnv, info);
}
private static JObjectLocalRef GetInfo(JEnvRef jEnv, GameInfo? info)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var javaClassName = GetCCharSequence("org/ryujinx/android/viewmodels/GameInfo");
JEnvValue value = jEnv.Environment;
ref JNativeInterface jInterface = ref value.Functions;
IntPtr findClassPtr = jInterface.FindClassPointer;
IntPtr newGlobalRefPtr = jInterface.NewGlobalRefPointer;
IntPtr getFieldIdPtr = jInterface.GetFieldIdPointer;
IntPtr getMethodPtr = jInterface.GetMethodIdPointer;
IntPtr newObjectPtr = jInterface.NewObjectPointer;
IntPtr setObjectFieldPtr = jInterface.SetObjectFieldPointer;
IntPtr setDoubleFieldPtr = jInterface.SetDoubleFieldPointer;
var findClass = findClassPtr.GetUnsafeDelegate<FindClassDelegate>();
var newGlobalRef = newGlobalRefPtr.GetUnsafeDelegate<NewGlobalRefDelegate>();
var getFieldId = getFieldIdPtr.GetUnsafeDelegate<GetFieldIdDelegate>();
var getMethod = getMethodPtr.GetUnsafeDelegate<GetMethodIdDelegate>();
var newObject = newObjectPtr.GetUnsafeDelegate<NewObjectDelegate>();
var setObjectField = setObjectFieldPtr.GetUnsafeDelegate<SetObjectFieldDelegate>();
var setDoubleField = setDoubleFieldPtr.GetUnsafeDelegate<SetDoubleFieldDelegate>();
var javaClass = findClass(jEnv, javaClassName);
var newGlobal = newGlobalRef(jEnv, javaClass._value);
var constructor = getMethod(jEnv, javaClass, GetCCharSequence("<init>"), GetCCharSequence("()V"));
var newObj = newObject(jEnv, javaClass, constructor, 0);
setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("TitleName"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info?.TitleName)._value);
setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("TitleId"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info?.TitleId)._value);
setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("Developer"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info?.Developer)._value);
setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("Version"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info?.Version)._value);
setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("Icon"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, Convert.ToBase64String(info?.Icon ?? Array.Empty<byte>()))._value);
setDoubleField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("FileSize"), GetCCharSequence("D")), info?.FileSize ?? 0d);
return newObj;
}
private static JStringLocalRef CreateString(JEnvRef jEnv, string? s)
{
s ??= string.Empty;
var ptr = Marshal.StringToHGlobalAnsi(s);
var str = createString(jEnv, ptr);
Marshal.FreeHGlobal(ptr);
return str;
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsRendererSetVsync")]
public static void JniSetVsyncStateNative(JEnvRef jEnv, JObjectLocalRef jObj, JBoolean enabled)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
SetVsyncState(enabled);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsRendererSetSwapBufferCallback")]
public static void JniSetSwapBuffersCallbackNative(JEnvRef jEnv, JObjectLocalRef jObj, IntPtr swapBuffersCallback)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
_swapBuffersCallback = Marshal.GetDelegateForFunctionPointer<SwapBuffersCallback>(swapBuffersCallback);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputInitialize")]
public static void JniInitializeInput(JEnvRef jEnv, JObjectLocalRef jObj, JInt width, JInt height)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
InitializeInput(width, height);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetClientSize")]
public static void JniSetClientSize(JEnvRef jEnv, JObjectLocalRef jObj, JInt width, JInt height)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
SetClientSize(width, height);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetTouchPoint")]
public static void JniSetTouchPoint(JEnvRef jEnv, JObjectLocalRef jObj, JInt x, JInt y)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
SetTouchPoint(x, y);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputReleaseTouchPoint")]
public static void JniReleaseTouchPoint(JEnvRef jEnv, JObjectLocalRef jObj)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
ReleaseTouchPoint();
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputUpdate")]
public static void JniUpdateInput(JEnvRef jEnv, JObjectLocalRef jObj)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
UpdateInput();
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetButtonPressed")]
public static void JniSetButtonPressed(JEnvRef jEnv, JObjectLocalRef jObj, JInt button, JInt id)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
SetButtonPressed((GamepadButtonInputId)(int)button, id);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetButtonReleased")]
public static void JniSetButtonReleased(JEnvRef jEnv, JObjectLocalRef jObj, JInt button, JInt id)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
SetButtonReleased((GamepadButtonInputId)(int)button, id);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetAccelerometerData")]
public static void JniSetAccelerometerData(JEnvRef jEnv, JObjectLocalRef jObj, JFloat x, JFloat y, JFloat z, JInt id)
{
var accel = new Vector3(x, y, z);
SetAccelerometerData(accel, id);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetGyroData")]
public static void JniSetGyroData(JEnvRef jEnv, JObjectLocalRef jObj, JFloat x, JFloat y, JFloat z, JInt id)
{
var gryo = new Vector3(x, y, z);
SetGryoData(gryo, id);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetStickAxis")]
public static void JniSetStickAxis(JEnvRef jEnv, JObjectLocalRef jObj, JInt stick, JFloat x, JFloat y, JInt id)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
SetStickAxis((StickInputId)(int)stick, new Vector2(float.IsNaN(x) ? 0 : x, float.IsNaN(y) ? 0 : y), id);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputConnectGamepad")]
public static JInt JniConnectGamepad(JEnvRef jEnv, JObjectLocalRef jObj, JInt index)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
return ConnectGamepad(index);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userGetOpenedUser")]
public static JLong JniGetOpenedUser(JEnvRef jEnv, JObjectLocalRef jObj)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var userId = GetOpenedUser();
return storeString(userId);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userGetUserPicture")]
public static JLong JniGetUserPicture(JEnvRef jEnv, JObjectLocalRef jObj, JLong userIdPtr)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var userId = GetStoredString(userIdPtr) ?? "";
return storeString(GetUserPicture(userId));
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userSetUserPicture")]
public static void JniGetUserPicture(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef userIdPtr, JStringLocalRef picturePtr)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var userId = GetString(jEnv, userIdPtr) ?? "";
var picture = GetString(jEnv, picturePtr) ?? "";
SetUserPicture(userId, picture);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userGetUserName")]
public static JLong JniGetUserName(JEnvRef jEnv, JObjectLocalRef jObj, JLong userIdPtr)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var userId = GetStoredString(userIdPtr) ?? "";
return storeString(GetUserName(userId));
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userSetUserName")]
public static void JniSetUserName(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef userIdPtr, JStringLocalRef userNamePtr)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var userId = GetString(jEnv, userIdPtr) ?? "";
var userName = GetString(jEnv, userNamePtr) ?? "";
SetUserName(userId, userName);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userGetAllUsers")]
public static JArrayLocalRef JniGetAllUsers(JEnvRef jEnv, JObjectLocalRef jObj)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var users = GetAllUsers();
return CreateStringArray(jEnv, users.ToList());
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userAddUser")]
public static void JniAddUser(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef userNamePtr, JStringLocalRef picturePtr)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var userName = GetString(jEnv, userNamePtr) ?? "";
var picture = GetString(jEnv, picturePtr) ?? "";
AddUser(userName, picture);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userDeleteUser")]
public static void JniDeleteUser(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef userIdPtr)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var userId = GetString(jEnv, userIdPtr) ?? "";
DeleteUser(userId);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_uiHandlerSetup")]
public static void JniSetupUiHandler(JEnvRef jEnv, JObjectLocalRef jObj)
{
SetupUiHandler();
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_uiHandlerWait")]
public static void JniWaitUiHandler(JEnvRef jEnv, JObjectLocalRef jObj)
{
WaitUiHandler();
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_uiHandlerStopWait")]
public static void JniStopUiHandlerWait(JEnvRef jEnv, JObjectLocalRef jObj)
{
StopUiHandlerWait();
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_uiHandlerSetResponse")]
public static void JniSetUiHandlerResponse(JEnvRef jEnv, JObjectLocalRef jObj, JBoolean isOkPressed, JLong input)
{
SetUiHandlerResponse(isOkPressed, input);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userOpenUser")]
public static void JniOpenUser(JEnvRef jEnv, JObjectLocalRef jObj, JLong userIdPtr)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var userId = GetStoredString(userIdPtr) ?? "";
OpenUser(userId);
}
[UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_userCloseUser")]
public static void JniCloseUser(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef userIdPtr)
{
Logger.Trace?.Print(LogClass.Application, "Jni Function Call");
var userId = GetString(jEnv, userIdPtr) ?? "";
CloseUser(userId);
}
}
internal static partial class Logcat
{
[LibraryImport("liblog", StringMarshalling = StringMarshalling.Utf8)]
private static partial void __android_log_print(LogLevel level, string? tag, string format, string args, IntPtr ptr);
internal static void AndroidLogPrint(LogLevel level, string? tag, string message) =>
__android_log_print(level, tag, "%s", message, IntPtr.Zero);
internal enum LogLevel
{
Unknown = 0x00,
Default = 0x01,
Verbose = 0x02,
Debug = 0x03,
Info = 0x04,
Warn = 0x05,
Error = 0x06,
Fatal = 0x07,
Silent = 0x08,
}
}
}

View File

@ -0,0 +1,286 @@
using LibRyujinx.Jni.Identifiers;
using LibRyujinx.Jni.Internal.Pointers;
using LibRyujinx.Jni.Pointers;
using LibRyujinx.Jni.Primitives;
using LibRyujinx.Jni.References;
using LibRyujinx.Jni.Values;
using System;
namespace LibRyujinx.Jni
{
internal delegate Int32 GetVersionDelegate(JEnvRef env);
internal delegate JClassLocalRef DefineClassDelegate(JEnvRef env, CCharSequence name, JObjectLocalRef loader, IntPtr binaryData, Int32 len);
internal delegate JClassLocalRef FindClassDelegate(JEnvRef env, CCharSequence name);
internal delegate JMethodId FromReflectedMethodDelegate(JEnvRef env, JObjectLocalRef method);
internal delegate JFieldId FromReflectedFieldIdDelegate(JEnvRef env, JObjectLocalRef field);
internal delegate JObjectLocalRef ToReflectedMethodDelegate(JEnvRef env, JClassLocalRef jClass, JMethodId methodId, Boolean isStatic);
internal delegate JClassLocalRef GetSuperclassDelegate(JEnvRef env, JClassLocalRef sub);
internal delegate Boolean IsAssignableFromDelegate(JEnvRef env, JClassLocalRef sub, JClassLocalRef sup);
internal delegate JObjectLocalRef ToReflectedFieldIdDelegate(JEnvRef env, JClassLocalRef jClass, JFieldId fieldId, Boolean isStatic);
internal delegate JResult ThrowDelegate(JEnvRef env, JThrowableLocalRef obj);
internal delegate JResult ThrowNewDelegate(JEnvRef env, JClassLocalRef jClass, CCharSequence msg);
internal delegate JThrowableLocalRef ExceptionOccurredDelegate(JEnvRef env);
internal delegate void ExceptionDescribeDelegate(JEnvRef env);
internal delegate void ExceptionClearDelegate(JEnvRef env);
internal delegate void FatalErrorDelegate(JEnvRef env, CCharSequence msg);
internal delegate JResult PushLocalFrameDelegate(JEnvRef env, Int32 capacity);
internal delegate JObjectLocalRef PopLocalFrameDelegate(JEnvRef env, JObjectLocalRef result);
internal delegate JGlobalRef NewGlobalRefDelegate(JEnvRef env, JObjectLocalRef lref);
internal delegate void DeleteGlobalRefDelegate(JEnvRef env, JGlobalRef gref);
internal delegate void DeleteLocalRefDelegate(JEnvRef env, JObjectLocalRef lref);
internal delegate Boolean IsSameObjectDelegate(JEnvRef env, JObjectLocalRef obj1, JObjectLocalRef obj2);
internal delegate JObjectLocalRef NewLocalRefDelegate(JEnvRef env, JObjectLocalRef objRef);
internal delegate JResult EnsureLocalCapacityDelegate(JEnvRef env, Int32 capacity);
internal delegate JObjectLocalRef AllocObjectDelegate(JEnvRef env, JClassLocalRef jClass);
internal delegate JObjectLocalRef NewObjectDelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod, IntPtr args);
internal delegate JObjectLocalRef NewObjectVDelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod, ArgIterator args);
internal delegate JObjectLocalRef NewObjectADelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod, JValueSequence args);
internal delegate JClassLocalRef GetObjectClassDelegate(JEnvRef env, JObjectLocalRef obj);
internal delegate Boolean IsInstanceOfDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass);
internal delegate JMethodId GetMethodIdDelegate(JEnvRef env, JClassLocalRef jClass, CCharSequence name, CCharSequence signature);
internal delegate JObjectLocalRef CallObjectMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
internal delegate JObjectLocalRef CallObjectMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
internal delegate JObjectLocalRef CallObjectMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
internal delegate JBoolean CallBooleanMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
internal delegate JBoolean CallBooleanMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
internal delegate JBoolean CallBooleanMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
internal delegate JByte CallByteMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
internal delegate JByte CallByteMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
internal delegate JByte CallByteMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
internal delegate JChar CallCharMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
internal delegate JChar CallCharMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
internal delegate JChar CallCharMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
internal delegate JShort CallShortMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
internal delegate JShort CallShortMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
internal delegate JShort CallShortMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
internal delegate JInt CallIntMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
internal delegate JInt CallIntMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
internal delegate JInt CallIntMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
internal delegate JLong CallLongMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
internal delegate JLong CallLongMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
internal delegate JLong CallLongMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
internal delegate JFloat CallFloatMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
internal delegate JFloat CallFloatMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
internal delegate JFloat CallFloatMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
internal delegate JDouble CallDoubleMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
internal delegate JDouble CallDoubleMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
internal delegate JDouble CallDoubleMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
internal delegate void CallVoidMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
internal delegate void CallVoidMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
internal delegate void CallVoidMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
internal delegate JObjectLocalRef CallNonVirtualObjectMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JObjectLocalRef CallNonVirtualObjectMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JObjectLocalRef CallNonVirtualObjectMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JBoolean CallNonVirtualBooleanMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JBoolean CallNonVirtualBooleanMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JBoolean CallNonVirtualBooleanMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JByte CallNonVirtualByteMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JByte CallNonVirtualByteMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JByte CallNonVirtualByteMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JChar CallNonVirtualCharMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JChar CallNonVirtualCharMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JChar CallNonVirtualCharMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JShort CallNonVirtualShortMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JShort CallNonVirtualShortMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JShort CallNonVirtualShortMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JInt CallNonVirtualIntMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JInt CallNonVirtualIntMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JInt CallNonVirtualIntMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JLong CallNonVirtualLongMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JLong CallNonVirtualLongMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JLong CallNonVirtualLongMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JFloat CallNonVirtualFloatMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JFloat CallNonVirtualFloatMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JFloat CallNonVirtualFloatMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JDouble CallNonVirtualDoubleMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JDouble CallNonVirtualDoubleMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JDouble CallNonVirtualDoubleMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate void CallNonVirtualVoidMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate void CallNonVirtualVoidMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate void CallNonVirtualVoidMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JFieldId GetFieldIdDelegate(JEnvRef env, JClassLocalRef jclass, CCharSequence name, CCharSequence signature);
internal delegate JObjectLocalRef GetObjectFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
internal delegate JBoolean GetBooleanFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
internal delegate JByte GetByteFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
internal delegate JChar GetCharFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
internal delegate JShort GetShortFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
internal delegate JInt GetIntFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
internal delegate JLong GetLongFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
internal delegate JFloat GetFloatFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
internal delegate JDouble GetDoubleFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
internal delegate void SetObjectFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JObjectLocalRef value);
internal delegate void SetBooleanFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JBoolean value);
internal delegate void SetByteFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JByte value);
internal delegate void SetCharFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JChar value);
internal delegate void SetShortFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JShort value);
internal delegate void SetIntFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JInt value);
internal delegate void SetLongFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JLong value);
internal delegate void SetFloatFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JFloat value);
internal delegate void SetDoubleFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JDouble value);
internal delegate JMethodId GetStaticMethodIdDelegate(JEnvRef env, JClassLocalRef jClass, CCharSequence name, CCharSequence signature);
internal delegate JObjectLocalRef CallStaticObjectMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JObjectLocalRef CallStaticObjectMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JObjectLocalRef CallStaticObjectMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JBoolean CallStaticBooleanMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JBoolean CallStaticBooleanMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JBoolean CallStaticBooleanMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JByte CallStaticByteMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JByte CallStaticByteMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JByte CallStaticByteMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JChar CallStaticCharMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JChar CallStaticCharMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JChar CallStaticCharMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JShort CallStaticShortMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JShort CallStaticShortMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JShort CallStaticShortMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JInt CallStaticIntMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JInt CallStaticIntMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JInt CallStaticIntMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JLong CallStaticLongMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JLong CallStaticLongMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JLong CallStaticLongMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JFloat CallStaticFloatMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JFloat CallStaticFloatMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JFloat CallStaticFloatMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JDouble CallStaticDoubleMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate JDouble CallStaticDoubleMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate JDouble CallStaticDoubleMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate void CallStaticVoidMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
internal delegate void CallStaticVoidMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
internal delegate void CallStaticVoidMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
internal delegate JFieldId GetStaticFieldIdDelegate(JEnvRef env, JClassLocalRef jclass, CCharSequence name, CCharSequence signature);
internal delegate JObjectLocalRef GetStaticObjectFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
internal delegate JBoolean GetStaticBooleanFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
internal delegate JByte GetStaticByteFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
internal delegate JChar GetStaticCharFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
internal delegate JShort GetStaticShortFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
internal delegate JInt GetStaticIntFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
internal delegate JLong GetStaticLongFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
internal delegate JFloat GetStaticFloatFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
internal delegate JDouble GetStaticDoubleFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
internal delegate void SetStaticObjectFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JObjectLocalRef value);
internal delegate void SetStaticBooleanFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JBoolean value);
internal delegate void SetStaticByteFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JByte value);
internal delegate void SetStaticCharFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JChar value);
internal delegate void SetStaticShortFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JShort value);
internal delegate void SetStaticIntFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JInt value);
internal delegate void SetStaticLongFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JLong value);
internal delegate void SetStaticFloatFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JFloat value);
internal delegate void SetStaticDoubleFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JDouble value);
internal delegate JStringLocalRef NewStringDelegate(JEnvRef env, JCharSequence unicode, Int32 length);
internal delegate Int32 GetStringLengthDelegate(JEnvRef env, JStringLocalRef jString);
internal delegate JCharSequence GetStringCharsDelegate(JEnvRef env, JStringLocalRef jString, JBooleanRef isCopy);
internal delegate void ReleaseStringCharsDelegate(JEnvRef env, JStringLocalRef jString, JCharSequence chars);
internal delegate JStringLocalRef NewStringUtfDelegate(JEnvRef env, CCharSequence unicode);
internal delegate Int32 GetStringUtfLengthDelegate(JEnvRef env, JStringLocalRef jString);
internal delegate CCharSequence GetStringUtfCharsDelegate(JEnvRef env, JStringLocalRef jString, JBooleanRef isCopy);
internal delegate void ReleaseStringUtfCharsDelegate(JEnvRef env, JStringLocalRef jString, CCharSequence chars);
internal delegate Int32 GetArrayLengthDelegate(JEnvRef env, JArrayLocalRef array);
internal delegate JArrayLocalRef NewObjectArrayDelegate(JEnvRef env, Int32 length, JClassLocalRef jClass, JObjectLocalRef init);
internal delegate JObjectLocalRef GetObjectArrayElementDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 index);
internal delegate void SetObjectArrayElementDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 index, JObjectLocalRef obj);
internal delegate JArrayLocalRef NewBooleanArrayDelegate(JEnvRef env, Int32 length);
internal delegate JArrayLocalRef NewByteArrayDelegate(JEnvRef env, Int32 length);
internal delegate JArrayLocalRef NewCharArrayDelegate(JEnvRef env, Int32 length);
internal delegate JArrayLocalRef NewShortArrayDelegate(JEnvRef env, Int32 length);
internal delegate JArrayLocalRef NewIntArrayDelegate(JEnvRef env, Int32 length);
internal delegate JArrayLocalRef NewLongArrayDelegate(JEnvRef env, Int32 length);
internal delegate JArrayLocalRef NewFloatArrayDelegate(JEnvRef env, Int32 length);
internal delegate JArrayLocalRef NewDoubleArrayDelegate(JEnvRef env, Int32 length);
internal delegate IntPtr GetBooleanArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
internal delegate IntPtr GetByteArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
internal delegate IntPtr GetCharArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
internal delegate IntPtr GetShortArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
internal delegate IntPtr GetIntArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
internal delegate IntPtr GetLongArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
internal delegate IntPtr GetFloatArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
internal delegate IntPtr GetDoubleArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
internal delegate void ReleaseBooleanArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
internal delegate void ReleaseByteArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
internal delegate void ReleaseCharArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
internal delegate void ReleaseShortArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
internal delegate void ReleaseIntArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
internal delegate void ReleaseLongArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
internal delegate void ReleaseFloatArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
internal delegate void ReleaseDoubleArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
internal delegate void GetBooleanArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate void GetByteArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate void GetCharArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate void GetShortArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate void GetIntArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate void GetLongArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate void GetFloatArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate void GetDoubleArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate void SetBooleanArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate void SetByteArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate void SetCharArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate void SetShortArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate void SetIntArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate void SetLongArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate void SetFloatArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate void SetDoubleArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
internal delegate JResult RegisterNativesDelegate(JEnvRef env, JClassLocalRef jClass, JNativeMethodSequence methods);
internal delegate JResult UnregisterNativesDelegate(JEnvRef env, JClassLocalRef jClass);
internal delegate JResult MonitorEnterDelegate(JEnvRef env, JObjectLocalRef jClass);
internal delegate JResult MonitorExitDelegate(JEnvRef env, JObjectLocalRef jClass);
internal delegate JResult GetJavaVMDelegate(JEnvRef env, ref JavaVMRef jvm);
internal delegate void GetStringRegionDelegate(JEnvRef env, JStringLocalRef jString, Int32 startIndex, Int32 length, JCharSequence buffer);
internal delegate void GetStringUtfRegionDelegate(JEnvRef env, JStringLocalRef jString, Int32 startIndex, Int32 length, CCharSequence buffer);
internal delegate IntPtr GetPrimitiveArrayCriticalDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
internal delegate void ReleasePrimitiveArrayCriticalDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
internal delegate JCharSequence GetStringCriticalDelegate(JEnvRef env, JStringLocalRef jString, JBooleanRef isCopy);
internal delegate void ReleaseStringCriticalDelegate(JEnvRef env, JStringLocalRef jString, JCharSequence chars);
internal delegate JWeakRef NewWeakGlobalRefDelegate(JEnvRef env, JObjectLocalRef obj);
internal delegate void DeleteWeakGlobalRefDelegate(JEnvRef env, JWeakRef jWeak);
internal delegate Boolean ExceptionCheckDelegate(JEnvRef env);
internal delegate JObjectLocalRef NewDirectByteBufferDelegate(JEnvRef env, IntPtr address, Int64 capacity);
internal delegate IntPtr GetDirectBufferAddressDelegate(JEnvRef env, JObjectLocalRef buffObj);
internal delegate Int64 GetDirectBufferCapacityDelegate(JEnvRef env, JObjectLocalRef buffObj);
internal delegate JReferenceType GetObjectRefTypeDelegate(JEnvRef env, JObjectLocalRef obj);
internal delegate JResult DestroyJavaVMDelegate(JavaVMRef vm);
internal delegate JResult AttachCurrentThreadDelegate(JavaVMRef vm, ref JEnvRef env, in JavaVMAttachArgs args);
internal delegate JResult DetachCurrentThreadDelegate(JavaVMRef vm);
internal delegate JResult GetEnvDelegate(JavaVMRef vm, ref JEnvRef env, JInt version);
internal delegate JResult AttachCurrentThreadAsDaemonDelegate(JavaVMRef vm, ref JEnvRef env, in JavaVMAttachArgs args);
}

View File

@ -0,0 +1,28 @@
using System.Diagnostics.CodeAnalysis;
using System;
namespace LibRyujinx.Jni.Identifiers
{
public readonly struct JFieldId : IEquatable<JFieldId>
{
#pragma warning disable 0649
private readonly IntPtr _value;
#pragma warning restore 0649
#region Public Methods
public Boolean Equals(JFieldId other)
=> this._value.Equals(other._value);
#endregion
#region Override Methods
public override Boolean Equals([NotNullWhen(true)] Object obj)
=> obj is JFieldId other && this.Equals(other);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
#region Operators
public static Boolean operator ==(JFieldId a, JFieldId b) => a.Equals(b);
public static Boolean operator !=(JFieldId a, JFieldId b) => !a.Equals(b);
#endregion
}
}

View File

@ -0,0 +1,28 @@
using System.Diagnostics.CodeAnalysis;
using System;
namespace LibRyujinx.Jni.Identifiers
{
public readonly struct JMethodId : IEquatable<JMethodId>
{
#pragma warning disable 0649
private readonly IntPtr _value;
#pragma warning restore 0649
#region Public Methods
public Boolean Equals(JMethodId other)
=> this._value.Equals(other._value);
#endregion
#region Override Methods
public override Boolean Equals([NotNullWhen(true)] Object obj)
=> obj is JMethodId other && this.Equals(other);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
#region Operators
public static Boolean operator ==(JMethodId a, JMethodId b) => a.Equals(b);
public static Boolean operator !=(JMethodId a, JMethodId b) => !a.Equals(b);
#endregion
}
}

View File

@ -0,0 +1,12 @@
using System;
namespace LibRyujinx.Jni
{
public enum JReferenceType : Int32
{
InvalidRefType = 0,
LocalRefType = 1,
GlobalRefType = 2,
WeakGlobalRefType = 3
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace LibRyujinx.Jni
{
public enum JReleaseMode : Int32
{
Free = 0,
Commit = 1,
Abort = 2,
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace LibRyujinx.Jni
{
public enum JResult : Int32
{
Ok = 0,
Error = -1,
DetachedThreadError = -2,
VersionError = -3,
MemoryError = -4,
ExitingVMError = -5,
InvalidArgumentsError = -6,
}
}

View File

@ -0,0 +1,36 @@
using System.Runtime.InteropServices;
using System;
using Rxmxnx.PInvoke;
namespace LibRyujinx.Jni.Pointers
{
public readonly struct CCharSequence : IEquatable<CCharSequence>
{
private readonly IntPtr _value;
private CCharSequence(IntPtr value) => this._value = value;
#region Operators
public static implicit operator CCharSequence(IntPtr value) => new(value);
public static implicit operator CCharSequence(Span<Byte> span) => new(span.GetUnsafeIntPtr());
public static implicit operator CCharSequence(ReadOnlySpan<Byte> readonlySpan) => new(readonlySpan.GetUnsafeIntPtr());
public static CCharSequence operator ++(CCharSequence a) => new(a._value + sizeof(Byte));
public static CCharSequence operator --(CCharSequence a) => new(a._value - sizeof(Byte));
public static Boolean operator ==(CCharSequence a, CCharSequence b) => a._value.Equals(b._value);
public static Boolean operator !=(CCharSequence a, CCharSequence b) => !a._value.Equals(b._value);
#endregion
#region Public Methods
public Boolean Equals(CCharSequence other) => this._value.Equals(other._value);
public String AsString(Int32 length = 0)
=> length == 0 ? Marshal.PtrToStringUTF8(_value) : Marshal.PtrToStringUTF8(_value, length);
#endregion
#region Overrided Methods
public override Boolean Equals(Object obj) => obj is CCharSequence other && this.Equals(other);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
}
}

View File

@ -0,0 +1,30 @@
using System.Runtime.CompilerServices;
using System;
using LibRyujinx.Jni.Primitives;
using Rxmxnx.PInvoke;
namespace LibRyujinx.Jni.Pointers
{
public readonly struct JBooleanRef
{
private static readonly Int32 JBooleanResultFalse = 0;
private static readonly Int32 JBooleanResultTrue = 1;
#pragma warning disable IDE0052
private readonly IntPtr _value;
#pragma warning restore IDE0052
public JBooleanRef(JBoolean? jBoolean)
=> this._value = jBoolean.HasValue ? GetJBooleanRef(jBoolean.Value) : IntPtr.Zero;
private static IntPtr GetJBooleanRef(Boolean value)
{
// Probably gonna break stuff
var t = JBooleanResultTrue;
var f = JBooleanResultFalse;
return value ? Unsafe.AsRef(ref f).GetUnsafeIntPtr() : Unsafe.AsRef(ref t).GetUnsafeIntPtr();
}
}
}

View File

@ -0,0 +1,33 @@
using Rxmxnx.PInvoke;
using System;
namespace LibRyujinx.Jni.Pointers
{
public readonly struct JCharSequence : IEquatable<JCharSequence>
{
private readonly IntPtr _value;
private JCharSequence(IntPtr value) => this._value = value;
#region Operators
public static implicit operator JCharSequence(IntPtr value) => new(value);
public static implicit operator JCharSequence(Span<Char> span) => new(span.GetUnsafeIntPtr());
public static implicit operator JCharSequence(ReadOnlySpan<Char> readonlySpan) => new(readonlySpan.GetUnsafeIntPtr());
public static JCharSequence operator ++(JCharSequence a) => new(a._value + sizeof(Char));
public static JCharSequence operator --(JCharSequence a) => new(a._value - sizeof(Char));
public static Boolean operator ==(JCharSequence a, JCharSequence b) => a._value.Equals(b._value);
public static Boolean operator !=(JCharSequence a, JCharSequence b) => !a._value.Equals(b._value);
#endregion
#region Public Methods
public Boolean Equals(JCharSequence other) => this._value.Equals(other._value);
public String AsString(Int32 length = 0) => this._value.GetUnsafeString(length);
#endregion
#region Overrided Methods
public override Boolean Equals(Object obj) => obj is JCharSequence other && this.Equals(other);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
}
}

View File

@ -0,0 +1,32 @@
using LibRyujinx.Jni.Values;
using Rxmxnx.PInvoke;
using System;
namespace LibRyujinx.Jni.Pointers
{
public readonly struct JEnvRef : IEquatable<JEnvRef>
{
#pragma warning disable 0649
private readonly IntPtr _value;
#pragma warning restore 0649
#region Operators
public static Boolean operator ==(JEnvRef a, JEnvRef b) => a._value.Equals(b._value);
public static Boolean operator !=(JEnvRef a, JEnvRef b) => !a._value.Equals(b._value);
#endregion
#region Public Properties
internal readonly ref JEnvValue Environment => ref this._value.GetUnsafeReference<JEnvValue>();
#endregion
#region Public Methods
public Boolean Equals(JEnvRef other) => this._value.Equals(other._value);
#endregion
#region Overrided Methods
public override Boolean Equals(Object obj) => obj is JEnvRef other && this.Equals(other);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
}
}

View File

@ -0,0 +1,33 @@
using LibRyujinx.Jni.Values;
using Rxmxnx.PInvoke;
using System;
namespace LibRyujinx.Jni.Pointers
{
public readonly struct JNativeMethodSequence : IEquatable<JNativeMethodSequence>
{
private readonly IntPtr _value;
private JNativeMethodSequence(IntPtr value) => this._value = value;
#region Operators
public static implicit operator JNativeMethodSequence(IntPtr value) => new(value);
public static implicit operator JNativeMethodSequence(ReadOnlySpan<JNativeMethod> readonlySpan) => new(readonlySpan.GetUnsafeIntPtr());
public static JNativeMethodSequence operator ++(JNativeMethodSequence a) => new(a._value + JValue.Size);
public static JNativeMethodSequence operator --(JNativeMethodSequence a) => new(a._value - JValue.Size);
public static Boolean operator ==(JNativeMethodSequence a, JNativeMethodSequence b) => a._value.Equals(b._value);
public static Boolean operator !=(JNativeMethodSequence a, JNativeMethodSequence b) => !a._value.Equals(b._value);
#endregion
#region Public Methods
public Boolean Equals(JNativeMethodSequence other) => this._value.Equals(other._value);
#endregion
#region Overrided Methods
public override Boolean Equals(Object obj) => obj is JNativeMethodSequence other && this.Equals(other);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
}
}

View File

@ -0,0 +1,33 @@
using LibRyujinx.Jni.Values;
using Rxmxnx.PInvoke;
using System;
namespace LibRyujinx.Jni.Internal.Pointers
{
internal readonly struct JValueSequence : IEquatable<JValueSequence>
{
private readonly IntPtr _value;
private JValueSequence(IntPtr value) => this._value = value;
internal JValueSequence(ReadOnlySpan<JValue> readonlySpan) : this(readonlySpan.GetUnsafeIntPtr()) { }
#region Operators
public static implicit operator JValueSequence(IntPtr value) => new(value);
public static JValueSequence operator ++(JValueSequence a) => new(a._value + JValue.Size);
public static JValueSequence operator --(JValueSequence a) => new(a._value - JValue.Size);
public static Boolean operator ==(JValueSequence a, JValueSequence b) => a._value.Equals(b._value);
public static Boolean operator !=(JValueSequence a, JValueSequence b) => !a._value.Equals(b._value);
#endregion
#region Public Methods
public Boolean Equals(JValueSequence other) => this._value.Equals(other._value);
#endregion
#region Overrided Methods
public override Boolean Equals(Object obj) => obj is JValueSequence other && this.Equals(other);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
}
}

View File

@ -0,0 +1,25 @@
using System;
namespace LibRyujinx.Jni.Pointers
{
public readonly struct JavaVMRef : IEquatable<JavaVMRef>
{
#pragma warning disable 0649
private readonly IntPtr _value;
#pragma warning restore 0649
#region Operators
public static Boolean operator ==(JavaVMRef a, JavaVMRef b) => a._value.Equals(b._value);
public static Boolean operator !=(JavaVMRef a, JavaVMRef b) => !a._value.Equals(b._value);
#endregion
#region Public Methods
public Boolean Equals(JavaVMRef other) => this._value.Equals(other._value);
#endregion
#region Overrided Methods
public override Boolean Equals(Object obj) => obj is JavaVMRef other && this.Equals(other);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
}
}

View File

@ -0,0 +1,67 @@
using LibRyujinx.Jni.Pointers;
using Rxmxnx.PInvoke;
using System;
namespace LibRyujinx.Jni.Primitives
{
public readonly struct JBoolean : IComparable<Boolean>, IEquatable<Boolean>
{
internal static readonly Type Type = typeof(JBoolean);
private static readonly Byte trueByte = 1;
private static readonly Byte falseByte = 2;
public static readonly CString Signature = (CString)"Z";
private readonly Byte _value;
private Boolean Value => this._value == trueByte;
private JBoolean(Boolean value) => this._value = value ? trueByte : falseByte;
#region Operators
public static implicit operator JBoolean(Boolean value) => new(value);
public static implicit operator Boolean(JBoolean jValue) => jValue._value == 1;
public static implicit operator JBooleanRef(JBoolean? jValue) => new(jValue);
public static JBoolean operator !(JBoolean a) => new(!a.Value);
public static JBoolean operator |(JBoolean a, JBoolean b) => new(a.Value || b.Value);
public static JBoolean operator |(Boolean a, JBoolean b) => new(a || b.Value);
public static JBoolean operator |(JBoolean a, Boolean b) => new(a.Value || b);
public static JBoolean operator &(JBoolean a, JBoolean b) => new(a.Value && b.Value);
public static JBoolean operator &(Boolean a, JBoolean b) => new(a && b.Value);
public static JBoolean operator &(JBoolean a, Boolean b) => new(a.Value && b);
public static Boolean operator ==(JBoolean a, JBoolean b) => a._value.Equals(b._value);
public static Boolean operator ==(Boolean a, JBoolean b) => a.Equals(b._value);
public static Boolean operator ==(JBoolean a, Boolean b) => a._value.Equals(b);
public static Boolean operator !=(JBoolean a, JBoolean b) => !a._value.Equals(b._value);
public static Boolean operator !=(Boolean a, JBoolean b) => !a.Equals(b._value);
public static Boolean operator !=(JBoolean a, Boolean b) => !a._value.Equals(b);
public static Boolean operator >(JBoolean a, JBoolean b) => a._value.CompareTo(b._value) > 0;
public static Boolean operator >(Boolean a, JBoolean b) => a.CompareTo(b._value) > 0;
public static Boolean operator >(JBoolean a, Boolean b) => a._value.CompareTo(b) > 0;
public static Boolean operator <(JBoolean a, JBoolean b) => a._value.CompareTo(b._value) < 0;
public static Boolean operator <(Boolean a, JBoolean b) => a.CompareTo(b._value) < 0;
public static Boolean operator <(JBoolean a, Boolean b) => a._value.CompareTo(b) < 0;
public static Boolean operator >=(JBoolean a, JBoolean b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(Boolean a, JBoolean b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(JBoolean a, Boolean b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
public static Boolean operator <=(JBoolean a, JBoolean b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(Boolean a, JBoolean b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(JBoolean a, Boolean b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
#endregion
#region Public Methods
public Int32 CompareTo(Boolean other) => this._value.CompareTo(other);
public Int32 CompareTo(JBoolean other) => this._value.CompareTo(other._value);
public Int32 CompareTo(Object obj) => obj is JBoolean jvalue ? this.CompareTo(jvalue) : obj is Boolean value ? this.CompareTo(value) : this._value.CompareTo(obj);
public Boolean Equals(Boolean other) => this._value.Equals(other);
public Boolean Equals(JBoolean other) => this._value.Equals(other._value);
public String ToString(IFormatProvider formatProvider) => this._value.ToString(formatProvider);
#endregion
#region Overrided Methods
public override String ToString() => this._value.ToString();
public override Boolean Equals(Object obj) => obj is JBoolean jvalue ? this.Equals(jvalue) : obj is Boolean value ? this.Equals(value) : this._value.Equals(obj);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
}
}

View File

@ -0,0 +1,74 @@
using Rxmxnx.PInvoke;
using System;
namespace LibRyujinx.Jni.Primitives
{
public readonly struct JByte : IComparable<SByte>, IEquatable<SByte>, IFormattable
{
internal static readonly Type Type = typeof(JByte);
public static readonly CString Signature = (CString)"B";
private readonly SByte _value;
private JByte(SByte value) => this._value = value;
private JByte(Int32 value) => this._value = Convert.ToSByte(value);
#region Operators
public static implicit operator JByte(SByte value) => new(value);
public static implicit operator SByte(JByte jValue) => jValue._value;
public static JByte operator +(JByte a) => a;
public static JByte operator ++(JByte a) => new(a._value + 1);
public static JByte operator -(JByte a) => new(-a._value);
public static JByte operator --(JByte a) => new(a._value - 1);
public static JByte operator +(JByte a, JByte b) => new(a._value + b._value);
public static JByte operator +(SByte a, JByte b) => new(a + b._value);
public static JByte operator +(JByte a, SByte b) => new(a._value + b);
public static JByte operator -(JByte a, JByte b) => new(a._value - b._value);
public static JByte operator -(SByte a, JByte b) => new(a - b._value);
public static JByte operator -(JByte a, SByte b) => new(a._value - b);
public static JByte operator *(JByte a, JByte b) => new(a._value * b._value);
public static JByte operator *(SByte a, JByte b) => new(a * b._value);
public static JByte operator *(JByte a, SByte b) => new(a._value * b);
public static JByte operator /(JByte a, JByte b) => new(a._value / b._value);
public static JByte operator /(SByte a, JByte b) => new(a / b._value);
public static JByte operator /(JByte a, SByte b) => new(a._value / b);
public static JByte operator %(JByte a, JByte b) => new(a._value % b._value);
public static JByte operator %(SByte a, JByte b) => new(a % b._value);
public static JByte operator %(JByte a, SByte b) => new(a._value % b);
public static Boolean operator ==(JByte a, JByte b) => a._value.Equals(b._value);
public static Boolean operator ==(SByte a, JByte b) => a.Equals(b._value);
public static Boolean operator ==(JByte a, SByte b) => a._value.Equals(b);
public static Boolean operator !=(JByte a, JByte b) => !a._value.Equals(b._value);
public static Boolean operator !=(SByte a, JByte b) => !a.Equals(b._value);
public static Boolean operator !=(JByte a, SByte b) => !a._value.Equals(b);
public static Boolean operator >(JByte a, JByte b) => a._value.CompareTo(b._value) > 0;
public static Boolean operator >(SByte a, JByte b) => a.CompareTo(b._value) > 0;
public static Boolean operator >(JByte a, SByte b) => a._value.CompareTo(b) > 0;
public static Boolean operator <(JByte a, JByte b) => a._value.CompareTo(b._value) < 0;
public static Boolean operator <(SByte a, JByte b) => a.CompareTo(b._value) < 0;
public static Boolean operator <(JByte a, SByte b) => a._value.CompareTo(b) < 0;
public static Boolean operator >=(JByte a, JByte b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(SByte a, JByte b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(JByte a, SByte b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
public static Boolean operator <=(JByte a, JByte b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(SByte a, JByte b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(JByte a, SByte b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
#endregion
#region Public Methods
public Int32 CompareTo(SByte other) => this._value.CompareTo(other);
public Int32 CompareTo(JByte other) => this._value.CompareTo(other._value);
public Int32 CompareTo(Object obj) => obj is JByte jValue ? this.CompareTo(jValue) : obj is SByte value ? this.CompareTo(value) : this._value.CompareTo(obj);
public Boolean Equals(SByte other) => this._value.Equals(other);
public Boolean Equals(JByte other) => this._value.Equals(other._value);
public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
#endregion
#region Overrided Methods
public override String ToString() => this._value.ToString();
public override Boolean Equals(Object obj) => obj is JByte jvalue ? this.Equals(jvalue) : obj is SByte value ? this.Equals(value) : this._value.Equals(obj);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
}
}

View File

@ -0,0 +1,56 @@
using Rxmxnx.PInvoke;
using System;
namespace LibRyujinx.Jni.Primitives
{
public readonly struct JChar : IComparable<Char>, IEquatable<Char>
{
internal static readonly Type Type = typeof(JChar);
public static readonly CString Signature = (CString)"C";
private readonly Char _value;
private JChar(Char value) => this._value = value;
#region Operators
public static implicit operator JChar(Char value) => new(value);
public static explicit operator JChar(Int16 value) => new((Char)value);
public static implicit operator Char(JChar jValue) => jValue._value;
public static explicit operator Int16(JChar jValue) => (Int16)jValue._value;
public static Boolean operator ==(JChar a, JChar b) => a._value.Equals(b._value);
public static Boolean operator ==(Char a, JChar b) => a.Equals(b._value);
public static Boolean operator ==(JChar a, Char b) => a._value.Equals(b);
public static Boolean operator !=(JChar a, JChar b) => !a._value.Equals(b._value);
public static Boolean operator !=(Char a, JChar b) => !a.Equals(b._value);
public static Boolean operator !=(JChar a, Char b) => !a._value.Equals(b);
public static Boolean operator >(JChar a, JChar b) => a._value.CompareTo(b._value) > 0;
public static Boolean operator >(Char a, JChar b) => a.CompareTo(b._value) > 0;
public static Boolean operator >(JChar a, Char b) => a._value.CompareTo(b) > 0;
public static Boolean operator <(JChar a, JChar b) => a._value.CompareTo(b._value) < 0;
public static Boolean operator <(Char a, JChar b) => a.CompareTo(b._value) < 0;
public static Boolean operator <(JChar a, Char b) => a._value.CompareTo(b) < 0;
public static Boolean operator >=(JChar a, JChar b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(Char a, JChar b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(JChar a, Char b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
public static Boolean operator <=(JChar a, JChar b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(Char a, JChar b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(JChar a, Char b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
#endregion
#region Public Methods
public Int32 CompareTo(Char other) => this._value.CompareTo(other);
public Int32 CompareTo(JChar other) => this._value.CompareTo(other._value);
public Int32 CompareTo(Object obj) => obj is JChar jvalue ? this.CompareTo(jvalue) : obj is Char value ? this.CompareTo(value) : this._value.CompareTo(obj);
public Boolean Equals(Char other) => this._value.Equals(other);
public Boolean Equals(JChar other) => this._value.Equals(other._value);
public String ToString(IFormatProvider formatProvider) => this._value.ToString(formatProvider);
#endregion
#region Overrided Methods
public override String ToString() => this._value.ToString();
public override Boolean Equals(Object obj) => obj is JChar jvalue ? this.Equals(jvalue) : obj is Char value ? this.Equals(value) : this._value.Equals(obj);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
}
}

View File

@ -0,0 +1,70 @@
using Rxmxnx.PInvoke;
using System;
namespace LibRyujinx.Jni.Primitives
{
public readonly struct JDouble : IComparable<Double>, IEquatable<Double>, IFormattable
{
internal static readonly Type Type = typeof(JDouble);
public static readonly CString Signature = (CString)"D";
private readonly Double _value;
private JDouble(Double value) => this._value = value;
#region Operators
public static implicit operator JDouble(Double value) => new(value);
public static implicit operator Double(JDouble jValue) => jValue._value;
public static JDouble operator +(JDouble a) => a;
public static JDouble operator ++(JDouble a) => new(a._value + 1);
public static JDouble operator -(JDouble a) => new(-a._value);
public static JDouble operator --(JDouble a) => new(a._value - 1);
public static JDouble operator +(JDouble a, JDouble b) => new(a._value + b._value);
public static JDouble operator +(Double a, JDouble b) => new(a + b._value);
public static JDouble operator +(JDouble a, Double b) => new(a._value + b);
public static JDouble operator -(JDouble a, JDouble b) => new(a._value - b._value);
public static JDouble operator -(Double a, JDouble b) => new(a - b._value);
public static JDouble operator -(JDouble a, Double b) => new(a._value - b);
public static JDouble operator *(JDouble a, JDouble b) => new(a._value * b._value);
public static JDouble operator *(Double a, JDouble b) => new(a * b._value);
public static JDouble operator *(JDouble a, Double b) => new(a._value * b);
public static JDouble operator /(JDouble a, JDouble b) => new(a._value / b._value);
public static JDouble operator /(Double a, JDouble b) => new(a / b._value);
public static JDouble operator /(JDouble a, Double b) => new(a._value / b);
public static Boolean operator ==(JDouble a, JDouble b) => a._value.Equals(b._value);
public static Boolean operator ==(Double a, JDouble b) => a.Equals(b._value);
public static Boolean operator ==(JDouble a, Double b) => a._value.Equals(b);
public static Boolean operator !=(JDouble a, JDouble b) => !a._value.Equals(b._value);
public static Boolean operator !=(Double a, JDouble b) => !a.Equals(b._value);
public static Boolean operator !=(JDouble a, Double b) => !a._value.Equals(b);
public static Boolean operator >(JDouble a, JDouble b) => a._value.CompareTo(b._value) > 0;
public static Boolean operator >(Double a, JDouble b) => a.CompareTo(b._value) > 0;
public static Boolean operator >(JDouble a, Double b) => a._value.CompareTo(b) > 0;
public static Boolean operator <(JDouble a, JDouble b) => a._value.CompareTo(b._value) < 0;
public static Boolean operator <(Double a, JDouble b) => a.CompareTo(b._value) < 0;
public static Boolean operator <(JDouble a, Double b) => a._value.CompareTo(b) < 0;
public static Boolean operator >=(JDouble a, JDouble b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(Double a, JDouble b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(JDouble a, Double b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
public static Boolean operator <=(JDouble a, JDouble b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(Double a, JDouble b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(JDouble a, Double b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
#endregion
#region Public Methods
public Int32 CompareTo(Double other) => this._value.CompareTo(other);
public Int32 CompareTo(JDouble other) => this._value.CompareTo(other._value);
public Int32 CompareTo(Object obj) => obj is JDouble jvalue ? this.CompareTo(jvalue) : obj is Double value ? this.CompareTo(value) : this._value.CompareTo(obj);
public Boolean Equals(Double other) => this._value.Equals(other);
public Boolean Equals(JDouble other) => this._value.Equals(other._value);
public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
#endregion
#region Overrided Methods
public override String ToString() => this._value.ToString();
public override Boolean Equals(Object obj) => obj is JDouble jvalue ? this.Equals(jvalue) : obj is Double value ? this.Equals(value) : this._value.Equals(obj);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
}
}

View File

@ -0,0 +1,70 @@
using Rxmxnx.PInvoke;
using System;
namespace LibRyujinx.Jni.Primitives
{
public readonly struct JFloat : IComparable<Single>, IEquatable<Single>, IFormattable
{
internal static readonly Type Type = typeof(JFloat);
public static readonly CString Signature = (CString)"F";
private readonly Single _value;
private JFloat(Single value) => this._value = value;
#region Operators
public static implicit operator JFloat(Single value) => new(value);
public static implicit operator Single(JFloat jValue) => jValue._value;
public static JFloat operator +(JFloat a) => a;
public static JFloat operator ++(JFloat a) => new(a._value + 1);
public static JFloat operator -(JFloat a) => new(-a._value);
public static JFloat operator --(JFloat a) => new(a._value - 1);
public static JFloat operator +(JFloat a, JFloat b) => new(a._value + b._value);
public static JFloat operator +(Single a, JFloat b) => new(a + b._value);
public static JFloat operator +(JFloat a, Single b) => new(a._value + b);
public static JFloat operator -(JFloat a, JFloat b) => new(a._value - b._value);
public static JFloat operator -(Single a, JFloat b) => new(a - b._value);
public static JFloat operator -(JFloat a, Single b) => new(a._value - b);
public static JFloat operator *(JFloat a, JFloat b) => new(a._value * b._value);
public static JFloat operator *(Single a, JFloat b) => new(a * b._value);
public static JFloat operator *(JFloat a, Single b) => new(a._value * b);
public static JFloat operator /(JFloat a, JFloat b) => new(a._value / b._value);
public static JFloat operator /(Single a, JFloat b) => new(a / b._value);
public static JFloat operator /(JFloat a, Single b) => new(a._value / b);
public static Boolean operator ==(JFloat a, JFloat b) => a._value.Equals(b._value);
public static Boolean operator ==(Single a, JFloat b) => a.Equals(b._value);
public static Boolean operator ==(JFloat a, Single b) => a._value.Equals(b);
public static Boolean operator !=(JFloat a, JFloat b) => !a._value.Equals(b._value);
public static Boolean operator !=(Single a, JFloat b) => !a.Equals(b._value);
public static Boolean operator !=(JFloat a, Single b) => !a._value.Equals(b);
public static Boolean operator >(JFloat a, JFloat b) => a._value.CompareTo(b._value) > 0;
public static Boolean operator >(Single a, JFloat b) => a.CompareTo(b._value) > 0;
public static Boolean operator >(JFloat a, Single b) => a._value.CompareTo(b) > 0;
public static Boolean operator <(JFloat a, JFloat b) => a._value.CompareTo(b._value) < 0;
public static Boolean operator <(Single a, JFloat b) => a.CompareTo(b._value) < 0;
public static Boolean operator <(JFloat a, Single b) => a._value.CompareTo(b) < 0;
public static Boolean operator >=(JFloat a, JFloat b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(Single a, JFloat b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(JFloat a, Single b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
public static Boolean operator <=(JFloat a, JFloat b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(Single a, JFloat b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(JFloat a, Single b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
#endregion
#region Public Methods
public Int32 CompareTo(Single other) => this._value.CompareTo(other);
public Int32 CompareTo(JFloat other) => this._value.CompareTo(other._value);
public Int32 CompareTo(Object obj) => obj is JFloat jvalue ? this.CompareTo(jvalue) : obj is Single value ? this.CompareTo(value) : this._value.CompareTo(obj);
public Boolean Equals(Single other) => this._value.Equals(other);
public Boolean Equals(JFloat other) => this._value.Equals(other._value);
public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
#endregion
#region Overrided Methods
public override String ToString() => this._value.ToString();
public override Boolean Equals(Object obj) => obj is JFloat jvalue ? this.Equals(jvalue) : obj is Single value ? this.Equals(value) : this._value.Equals(obj);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
}
}

View File

@ -0,0 +1,73 @@
using Rxmxnx.PInvoke;
using System;
namespace LibRyujinx.Jni.Primitives
{
public readonly struct JInt : IComparable<Int32>, IEquatable<Int32>, IFormattable
{
internal static readonly Type Type = typeof(JInt);
public static readonly CString Signature = (CString)"I";
private readonly Int32 _value;
private JInt(Int32 value) => this._value = value;
#region Operators
public static implicit operator JInt(Int32 value) => new(value);
public static implicit operator Int32(JInt jValue) => jValue._value;
public static JInt operator +(JInt a) => a;
public static JInt operator ++(JInt a) => new(a._value + 1);
public static JInt operator -(JInt a) => new(-a._value);
public static JInt operator --(JInt a) => new(a._value - 1);
public static JInt operator +(JInt a, JInt b) => new(a._value + b._value);
public static JInt operator +(Int32 a, JInt b) => new(a + b._value);
public static JInt operator +(JInt a, Int32 b) => new(a._value + b);
public static JInt operator -(JInt a, JInt b) => new(a._value - b._value);
public static JInt operator -(Int32 a, JInt b) => new(a - b._value);
public static JInt operator -(JInt a, Int32 b) => new(a._value - b);
public static JInt operator *(JInt a, JInt b) => new(a._value * b._value);
public static JInt operator *(Int32 a, JInt b) => new(a * b._value);
public static JInt operator *(JInt a, Int32 b) => new(a._value * b);
public static JInt operator /(JInt a, JInt b) => new(a._value / b._value);
public static JInt operator /(Int32 a, JInt b) => new(a / b._value);
public static JInt operator /(JInt a, Int32 b) => new(a._value / b);
public static JInt operator %(JInt a, JInt b) => new(a._value % b._value);
public static JInt operator %(Int32 a, JInt b) => new(a % b._value);
public static JInt operator %(JInt a, Int32 b) => new(a._value % b);
public static Boolean operator ==(JInt a, JInt b) => a._value.Equals(b._value);
public static Boolean operator ==(Int32 a, JInt b) => a.Equals(b._value);
public static Boolean operator ==(JInt a, Int32 b) => a._value.Equals(b);
public static Boolean operator !=(JInt a, JInt b) => !a._value.Equals(b._value);
public static Boolean operator !=(Int32 a, JInt b) => !a.Equals(b._value);
public static Boolean operator !=(JInt a, Int32 b) => !a._value.Equals(b);
public static Boolean operator >(JInt a, JInt b) => a._value.CompareTo(b._value) > 0;
public static Boolean operator >(Int32 a, JInt b) => a.CompareTo(b._value) > 0;
public static Boolean operator >(JInt a, Int32 b) => a._value.CompareTo(b) > 0;
public static Boolean operator <(JInt a, JInt b) => a._value.CompareTo(b._value) < 0;
public static Boolean operator <(Int32 a, JInt b) => a.CompareTo(b._value) < 0;
public static Boolean operator <(JInt a, Int32 b) => a._value.CompareTo(b) < 0;
public static Boolean operator >=(JInt a, JInt b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(Int32 a, JInt b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(JInt a, Int32 b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
public static Boolean operator <=(JInt a, JInt b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(Int32 a, JInt b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(JInt a, Int32 b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
#endregion
#region Public Methods
public Int32 CompareTo(Int32 other) => this._value.CompareTo(other);
public Int32 CompareTo(JInt other) => this._value.CompareTo(other._value);
public Int32 CompareTo(Object obj) => obj is JInt jValue ? this.CompareTo(jValue) : obj is Int32 value ? this.CompareTo(value) : this._value.CompareTo(obj);
public Boolean Equals(Int32 other) => this._value.Equals(other);
public Boolean Equals(JInt other) => this._value.Equals(other._value);
public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
#endregion
#region Overrided Methods
public override String ToString() => this._value.ToString();
public override Boolean Equals(Object obj) => obj is JInt jvalue ? this.Equals(jvalue) : obj is Int32 value ? this.Equals(value) : this._value.Equals(obj);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
}
}

View File

@ -0,0 +1,73 @@
using Rxmxnx.PInvoke;
using System;
namespace LibRyujinx.Jni.Primitives
{
public readonly struct JLong : IComparable<Int64>, IEquatable<Int64>, IFormattable
{
internal static readonly Type Type = typeof(JLong);
public static readonly CString Signature = (CString)"J";
private readonly Int64 _value;
private JLong(Int64 value) => this._value = value;
#region Operators
public static implicit operator JLong(Int64 value) => new(value);
public static implicit operator Int64(JLong jValue) => jValue._value;
public static JLong operator +(JLong a) => a;
public static JLong operator ++(JLong a) => new(a._value + 1);
public static JLong operator -(JLong a) => new(-a._value);
public static JLong operator --(JLong a) => new(a._value - 1);
public static JLong operator +(JLong a, JLong b) => new(a._value + b._value);
public static JLong operator +(Int64 a, JLong b) => new(a + b._value);
public static JLong operator +(JLong a, Int64 b) => new(a._value + b);
public static JLong operator -(JLong a, JLong b) => new(a._value - b._value);
public static JLong operator -(Int64 a, JLong b) => new(a - b._value);
public static JLong operator -(JLong a, Int64 b) => new(a._value - b);
public static JLong operator *(JLong a, JLong b) => new(a._value * b._value);
public static JLong operator *(Int64 a, JLong b) => new(a * b._value);
public static JLong operator *(JLong a, Int64 b) => new(a._value * b);
public static JLong operator /(JLong a, JLong b) => new(a._value / b._value);
public static JLong operator /(Int64 a, JLong b) => new(a / b._value);
public static JLong operator /(JLong a, Int64 b) => new(a._value / b);
public static JLong operator %(JLong a, JLong b) => new(a._value % b._value);
public static JLong operator %(Int64 a, JLong b) => new(a % b._value);
public static JLong operator %(JLong a, Int64 b) => new(a._value % b);
public static Boolean operator ==(JLong a, JLong b) => a._value.Equals(b._value);
public static Boolean operator ==(Int64 a, JLong b) => a.Equals(b._value);
public static Boolean operator ==(JLong a, Int64 b) => a._value.Equals(b);
public static Boolean operator !=(JLong a, JLong b) => !a._value.Equals(b._value);
public static Boolean operator !=(Int64 a, JLong b) => !a.Equals(b._value);
public static Boolean operator !=(JLong a, Int64 b) => !a._value.Equals(b);
public static Boolean operator >(JLong a, JLong b) => a._value.CompareTo(b._value) > 0;
public static Boolean operator >(Int64 a, JLong b) => a.CompareTo(b._value) > 0;
public static Boolean operator >(JLong a, Int64 b) => a._value.CompareTo(b) > 0;
public static Boolean operator <(JLong a, JLong b) => a._value.CompareTo(b._value) < 0;
public static Boolean operator <(Int64 a, JLong b) => a.CompareTo(b._value) < 0;
public static Boolean operator <(JLong a, Int64 b) => a._value.CompareTo(b) < 0;
public static Boolean operator >=(JLong a, JLong b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(Int64 a, JLong b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(JLong a, Int64 b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
public static Boolean operator <=(JLong a, JLong b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(Int64 a, JLong b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(JLong a, Int64 b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
#endregion
#region Public Methods
public Int32 CompareTo(Int64 other) => this._value.CompareTo(other);
public Int32 CompareTo(JLong other) => this._value.CompareTo(other._value);
public Int32 CompareTo(Object obj) => obj is JLong jvalue ? this.CompareTo(jvalue) : obj is Int64 value ? this.CompareTo(value) : this._value.CompareTo(obj);
public Boolean Equals(Int64 other) => this._value.Equals(other);
public Boolean Equals(JLong other) => this._value.Equals(other._value);
public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
#endregion
#region Overrided Methods
public override String ToString() => this._value.ToString();
public override Boolean Equals(Object obj) => obj is JLong jvalue ? this.Equals(jvalue) : obj is Int64 value ? this.Equals(value) : this._value.Equals(obj);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
}
}

View File

@ -0,0 +1,74 @@
using Rxmxnx.PInvoke;
using System;
namespace LibRyujinx.Jni.Primitives
{
public readonly struct JShort : IComparable<Int16>, IEquatable<Int16>, IFormattable
{
internal static readonly Type Type = typeof(JShort);
public static readonly CString Signature = (CString)"S";
private readonly Int16 _value;
private JShort(Int16 value) => this._value = value;
private JShort(Int32 value) => this._value = Convert.ToInt16(value);
#region Operators
public static implicit operator JShort(Int16 value) => new(value);
public static implicit operator Int16(JShort jValue) => jValue._value;
public static JShort operator +(JShort a) => a;
public static JShort operator ++(JShort a) => new(a._value + 1);
public static JShort operator -(JShort a) => new(-a._value);
public static JShort operator --(JShort a) => new(a._value - 1);
public static JShort operator +(JShort a, JShort b) => new(a._value + b._value);
public static JShort operator +(Int16 a, JShort b) => new(a + b._value);
public static JShort operator +(JShort a, Int16 b) => new(a._value + b);
public static JShort operator -(JShort a, JShort b) => new(a._value - b._value);
public static JShort operator -(Int16 a, JShort b) => new(a - b._value);
public static JShort operator -(JShort a, Int16 b) => new(a._value - b);
public static JShort operator *(JShort a, JShort b) => new(a._value * b._value);
public static JShort operator *(Int16 a, JShort b) => new(a * b._value);
public static JShort operator *(JShort a, Int16 b) => new(a._value * b);
public static JShort operator /(JShort a, JShort b) => new(a._value / b._value);
public static JShort operator /(Int16 a, JShort b) => new(a / b._value);
public static JShort operator /(JShort a, Int16 b) => new(a._value / b);
public static JShort operator %(JShort a, JShort b) => new(a._value % b._value);
public static JShort operator %(Int16 a, JShort b) => new(a % b._value);
public static JShort operator %(JShort a, Int16 b) => new(a._value % b);
public static Boolean operator ==(JShort a, JShort b) => a._value.Equals(b._value);
public static Boolean operator ==(Int16 a, JShort b) => a.Equals(b._value);
public static Boolean operator ==(JShort a, Int16 b) => a._value.Equals(b);
public static Boolean operator !=(JShort a, JShort b) => !a._value.Equals(b._value);
public static Boolean operator !=(Int16 a, JShort b) => !a.Equals(b._value);
public static Boolean operator !=(JShort a, Int16 b) => !a._value.Equals(b);
public static Boolean operator >(JShort a, JShort b) => a._value.CompareTo(b._value) > 0;
public static Boolean operator >(Int16 a, JShort b) => a.CompareTo(b._value) > 0;
public static Boolean operator >(JShort a, Int16 b) => a._value.CompareTo(b) > 0;
public static Boolean operator <(JShort a, JShort b) => a._value.CompareTo(b._value) < 0;
public static Boolean operator <(Int16 a, JShort b) => a.CompareTo(b._value) < 0;
public static Boolean operator <(JShort a, Int16 b) => a._value.CompareTo(b) < 0;
public static Boolean operator >=(JShort a, JShort b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(Int16 a, JShort b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
public static Boolean operator >=(JShort a, Int16 b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
public static Boolean operator <=(JShort a, JShort b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(Int16 a, JShort b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
public static Boolean operator <=(JShort a, Int16 b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
#endregion
#region Public Methods
public Int32 CompareTo(Int16 other) => this._value.CompareTo(other);
public Int32 CompareTo(JShort other) => this._value.CompareTo(other._value);
public Int32 CompareTo(Object obj) => obj is JShort jvalue ? this.CompareTo(jvalue) : obj is Int16 value ? this.CompareTo(value) : this._value.CompareTo(obj);
public Boolean Equals(Int16 other) => this._value.Equals(other);
public Boolean Equals(JShort other) => this._value.Equals(other._value);
public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
#endregion
#region Overrided Methods
public override String ToString() => this._value.ToString();
public override Boolean Equals(Object obj) => obj is JShort jvalue ? this.Equals(jvalue) : obj is Int16 value ? this.Equals(value) : this._value.Equals(obj);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
}
}

View File

@ -0,0 +1,28 @@
using System.Diagnostics.CodeAnalysis;
using System;
namespace LibRyujinx.Jni.References
{
public readonly struct JArrayLocalRef : IEquatable<JArrayLocalRef>
{
#pragma warning disable 0649
private readonly JObjectLocalRef _value;
#pragma warning restore 0649
#region Public Methods
public Boolean Equals(JArrayLocalRef other)
=> this._value.Equals(other._value);
#endregion
#region Override Methods
public override Boolean Equals([NotNullWhen(true)] Object obj)
=> obj is JArrayLocalRef other && this.Equals(other);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
#region Operators
public static Boolean operator ==(JArrayLocalRef a, JArrayLocalRef b) => a.Equals(b);
public static Boolean operator !=(JArrayLocalRef a, JArrayLocalRef b) => !a.Equals(b);
#endregion
}
}

View File

@ -0,0 +1,28 @@
using System.Diagnostics.CodeAnalysis;
using System;
namespace LibRyujinx.Jni.References
{
public readonly struct JClassLocalRef : IEquatable<JClassLocalRef>
{
#pragma warning disable 0649
public readonly JObjectLocalRef _value;
#pragma warning restore 0649
#region Public Methods
public Boolean Equals(JClassLocalRef other)
=> this._value.Equals(other._value);
#endregion
#region Override Methods
public override Boolean Equals([NotNullWhen(true)] Object obj)
=> obj is JClassLocalRef other && this.Equals(other);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
#region Operators
public static Boolean operator ==(JClassLocalRef a, JClassLocalRef b) => a.Equals(b);
public static Boolean operator !=(JClassLocalRef a, JClassLocalRef b) => !a.Equals(b);
#endregion
}
}

View File

@ -0,0 +1,28 @@
using System.Diagnostics.CodeAnalysis;
using System;
namespace LibRyujinx.Jni.References
{
public readonly struct JGlobalRef : IEquatable<JGlobalRef>
{
#pragma warning disable 0649
private readonly IntPtr _value;
#pragma warning restore 0649
#region Public Methods
public Boolean Equals(JGlobalRef other)
=> this._value.Equals(other._value);
#endregion
#region Override Methods
public override Boolean Equals([NotNullWhen(true)] Object obj)
=> obj is JGlobalRef other && this.Equals(other);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
#region Operators
public static Boolean operator ==(JGlobalRef a, JGlobalRef b) => a.Equals(b);
public static Boolean operator !=(JGlobalRef a, JGlobalRef b) => !a.Equals(b);
#endregion
}
}

View File

@ -0,0 +1,28 @@
using System.Diagnostics.CodeAnalysis;
using System;
namespace LibRyujinx.Jni.References
{
public readonly struct JObjectLocalRef : IEquatable<JObjectLocalRef>
{
#pragma warning disable 0649
private readonly IntPtr _value;
#pragma warning restore 0649
#region Public Methods
public Boolean Equals(JObjectLocalRef other)
=> this._value.Equals(other._value);
#endregion
#region Override Methods
public override Boolean Equals([NotNullWhen(true)] Object obj)
=> obj is JObjectLocalRef other && this.Equals(other);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
#region Operators
public static Boolean operator ==(JObjectLocalRef a, JObjectLocalRef b) => a.Equals(b);
public static Boolean operator !=(JObjectLocalRef a, JObjectLocalRef b) => !a.Equals(b);
#endregion
}
}

View File

@ -0,0 +1,28 @@
using System.Diagnostics.CodeAnalysis;
using System;
namespace LibRyujinx.Jni.References
{
public readonly struct JStringLocalRef : IEquatable<JStringLocalRef>
{
#pragma warning disable 0649
public readonly JObjectLocalRef _value;
#pragma warning restore 0649
#region Public Methods
public Boolean Equals(JStringLocalRef other)
=> this._value.Equals(other._value);
#endregion
#region Override Methods
public override Boolean Equals([NotNullWhen(true)] Object obj)
=> obj is JStringLocalRef other && this.Equals(other);
public override Int32 GetHashCode() => this._value.GetHashCode();
#endregion
#region Operators
public static Boolean operator ==(JStringLocalRef a, JStringLocalRef b) => a.Equals(b);
public static Boolean operator !=(JStringLocalRef a, JStringLocalRef b) => !a.Equals(b);
#endregion
}
}

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