mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-10-04 19:18:57 +02:00
Compare commits
279
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
280c427c55 | ||
|
|
25b4892981 | ||
|
|
d16d67f7c4 | ||
|
|
e7cb0632c5 | ||
|
|
4ea8c0b280 | ||
|
|
aef309800c | ||
|
|
a008cd20f1 | ||
|
|
ec6ce46357 | ||
|
|
a7a3a17b48 | ||
|
|
94cafdd1f9 | ||
|
|
1b57022694 | ||
|
|
2bb07a4364 | ||
|
|
5e67569a6e | ||
|
|
97f0336aa2 | ||
|
|
53d32a761e | ||
|
|
02d8eeb18f | ||
|
|
54e2f79c16 | ||
|
|
77277442a9 | ||
|
|
b707c73f83 | ||
|
|
235fb5f8c2 | ||
|
|
c2cbd53235 | ||
|
|
4f3c3a7b5d | ||
|
|
2dc1894e1e | ||
|
|
db4799e7ab | ||
|
|
06f049b874 | ||
|
|
58f9b6106f | ||
|
|
5422aa35b9 | ||
|
|
8ccf83d9a3 | ||
|
|
2eecc18dc7 | ||
|
|
3ceca9c381 | ||
|
|
a4412346a7 | ||
|
|
b0eb271b5b | ||
|
|
88cef7e853 | ||
|
|
69c088004a | ||
|
|
d3bd888885 | ||
|
|
b615f50701 | ||
|
|
d5524be27a | ||
|
|
43b4f3bf12 | ||
|
|
8d7d8f344c | ||
|
|
047dbf3db7 | ||
|
|
d0f0007421 | ||
|
|
60e553bffa | ||
|
|
a8a23b6b2c | ||
|
|
e0f6e207e8 | ||
|
|
30ab86cb72 | ||
|
|
2901f9b795 | ||
|
|
b08b9eabe6 | ||
|
|
83c65c2c06 | ||
|
|
3a6ce7cd1e | ||
|
|
94cfe6930c | ||
|
|
9a4bf8f94d | ||
|
|
d69d9c3b31 | ||
|
|
d9da38c10b | ||
|
|
ac699e430b | ||
|
|
89d7a5c45e | ||
|
|
93d1eea58d | ||
|
|
ad8ab179d2 | ||
|
|
18c6ec439b | ||
|
|
f2ac50360e | ||
|
|
8c42f306dd | ||
|
|
d765d6daa6 | ||
|
|
e7c720fd2c | ||
|
|
f3a87af51d | ||
|
|
1b9615983f | ||
|
|
d040492b7a | ||
|
|
05f7878699 | ||
|
|
0d8bd2653b | ||
|
|
b7ffcb3be8 | ||
|
|
46c55ee79d | ||
|
|
6c1c05dc5d | ||
|
|
637c8130a3 | ||
|
|
7781911baa | ||
|
|
bd3d4d0566 | ||
|
|
63c7d2a0ee | ||
|
|
5f40a22b0d | ||
|
|
72955d1aa4 | ||
|
|
ce2f2a14af | ||
|
|
b4d0f10568 | ||
|
|
c2dfc93fa6 | ||
|
|
29a828c4ef | ||
|
|
9995e26ec6 | ||
|
|
59c277bc6c | ||
|
|
491fb3ccfb | ||
|
|
e96823c9a0 | ||
|
|
ad0e2c0dea | ||
|
|
59b1989b97 | ||
|
|
40c32c7a20 | ||
|
|
bfe7973d90 | ||
|
|
14c432a416 | ||
|
|
e35ac3fed0 | ||
|
|
e3e46315f0 | ||
|
|
a6cb810a92 | ||
|
|
21b2b2bc03 | ||
|
|
d3a6d02ca1 | ||
|
|
1b2d471039 | ||
|
|
890d5a6e2c | ||
|
|
79ab37f282 | ||
|
|
487ef4c163 | ||
|
|
69908d7bf1 | ||
|
|
395081ae87 | ||
|
|
1a7be99263 | ||
|
|
d7770e2582 | ||
|
|
6a59302104 | ||
|
|
e49ef8d60e | ||
|
|
6840ae0c5c | ||
|
|
6f5b351fa0 | ||
|
|
6d36f471dd | ||
|
|
2c1b7bc667 | ||
|
|
dc4a51a462 | ||
|
|
ea7d680d11 | ||
|
|
fcf1ba6b9e | ||
|
|
99435c8708 | ||
|
|
74011bbb45 | ||
|
|
066afe9407 | ||
|
|
8aa08bc64b | ||
|
|
940d78a1ad | ||
|
|
d0e82aafb1 | ||
|
|
fe7b601826 | ||
|
|
9063b4b8db | ||
|
|
e036837211 | ||
|
|
c6deb3800f | ||
|
|
75220096e7 | ||
|
|
7f805f59fd | ||
|
|
ab571e81b3 | ||
|
|
f6adcd2f65 | ||
|
|
85e05bc7b2 | ||
|
|
bb0658bba9 | ||
|
|
50b00e3827 | ||
|
|
99c2e672c3 | ||
|
|
9ea27c3318 | ||
|
|
203ac3a175 | ||
|
|
bc0c483041 | ||
|
|
dbaf317f15 | ||
|
|
9357bb1524 | ||
|
|
734aecd711 | ||
|
|
1af7ebafc8 | ||
|
|
c8a6958ef3 | ||
|
|
377805579b | ||
|
|
35bced8527 | ||
|
|
c1e24961f9 | ||
|
|
2d720fea03 | ||
|
|
65c740ec4a | ||
|
|
0b8d1d5816 | ||
|
|
78db4c365f | ||
|
|
1bb1c7bba8 | ||
|
|
e1b6cb71f8 | ||
|
|
f34ab9f043 | ||
|
|
ebdc2a9e81 | ||
|
|
ebeb6e146c | ||
|
|
28b4f45645 | ||
|
|
f3931a789a | ||
|
|
42369a22a3 | ||
|
|
7b801bb9d3 | ||
|
|
457b7e77de | ||
|
|
169712a9e8 | ||
|
|
a187ec09d7 | ||
|
|
6d9e7fea75 | ||
|
|
ea89fc28da | ||
|
|
7242cb2449 | ||
|
|
4f101170f0 | ||
|
|
fc7932ad27 | ||
|
|
0c41346400 | ||
|
|
c6230fc02e | ||
|
|
1ef09717d2 | ||
|
|
41eb6f5dc4 | ||
|
|
f47be3342f | ||
|
|
4d1620c330 | ||
|
|
7a5b5dee6a | ||
|
|
fa5b5b127e | ||
|
|
327416c967 | ||
|
|
c42663115b | ||
|
|
09bc10b15d | ||
|
|
75058d850b | ||
|
|
ab6ccb3d0b | ||
|
|
07ae239130 | ||
|
|
548ec2c175 | ||
|
|
925ffc3976 | ||
|
|
cf12e5ab82 | ||
|
|
1f283b366b | ||
|
|
e4d2dea201 | ||
|
|
0cf2b1fbda | ||
|
|
8418025b82 | ||
|
|
316dc3a9b3 | ||
|
|
d73d82fbc0 | ||
|
|
7cc28d0242 | ||
|
|
92c3b72b17 | ||
|
|
8707fd5232 | ||
|
|
c125d08636 | ||
|
|
eee4a6272c | ||
|
|
be176fd367 | ||
|
|
48ba1cc9ed | ||
|
|
a6f3f0718d | ||
|
|
9cdd9f6dbf | ||
|
|
0928851966 | ||
|
|
d773bd60f4 | ||
|
|
dfb6164ba5 | ||
|
|
5a9bc0d703 | ||
|
|
2699bcf03e | ||
|
|
f45c1e6dcb | ||
|
|
fd75b35496 | ||
|
|
3e8d562182 | ||
|
|
65caa1e3f2 | ||
|
|
e3ef1e1fde | ||
|
|
3deddbd491 | ||
|
|
ff0daa9f35 | ||
|
|
faa8fb6642 | ||
|
|
6e7d013903 | ||
|
|
5db4793c7b | ||
|
|
db8b61106d | ||
|
|
55ea9046a2 | ||
|
|
a84dd77dc2 | ||
|
|
743eef7ff9 | ||
|
|
39066b846d | ||
|
|
307d048d25 | ||
|
|
7f89429b9f | ||
|
|
6b08ba47c4 | ||
|
|
f63cb962ad | ||
|
|
2c2b37678a | ||
|
|
6fed0795b9 | ||
|
|
c5540f9541 | ||
|
|
4c7a5a7261 | ||
|
|
925610723c | ||
|
|
bdc573ab17 | ||
|
|
f61e340a58 | ||
|
|
0149b71ac9 | ||
|
|
b4eaa5f262 | ||
|
|
2f7406aaca | ||
|
|
a9954c23cc | ||
|
|
9955191651 | ||
|
|
2e0bb4ec56 | ||
|
|
c417740beb | ||
|
|
0d51f4fcb5 | ||
|
|
4626aae70e | ||
|
|
d0abbc6da3 | ||
|
|
9b6b9146e2 | ||
|
|
4605c8bbd3 | ||
|
|
18743ed661 | ||
|
|
3487c4546e | ||
|
|
c457a2470f | ||
|
|
9fb338395a | ||
|
|
ab7e27a4e9 | ||
|
|
44b6f162c1 | ||
|
|
775c7b766c | ||
|
|
3faa22b85a | ||
|
|
05c3f2a250 | ||
|
|
8611e42a2e | ||
|
|
620666909f | ||
|
|
ef6f43825d | ||
|
|
d7b797bf02 | ||
|
|
0e4f71b2f1 | ||
|
|
1c23a55937 | ||
|
|
84d7f2d113 | ||
|
|
78b00e530c | ||
|
|
b22d771cce | ||
|
|
81aa3b769c | ||
|
|
fda90239bc | ||
|
|
3af88ad2e6 | ||
|
|
d73be3b927 | ||
|
|
cc0b704d8e | ||
|
|
cdd4557343 | ||
|
|
e172bdf2eb | ||
|
|
6e7808a65a | ||
|
|
5a86fb9826 | ||
|
|
45166424fc | ||
|
|
965c18225b | ||
|
|
2ea7d32b30 | ||
|
|
40cbd19bc3 | ||
|
|
0255c1f463 | ||
|
|
3657e55c70 | ||
|
|
af3aa8f786 | ||
|
|
81728f62bb | ||
|
|
a4856f1885 | ||
|
|
8fcf430ea8 | ||
|
|
fc2f1588d5 | ||
|
|
6f13e04a24 | ||
|
|
4e669ada26 | ||
|
|
575cc233c9 | ||
|
|
7a4017d164 | ||
|
|
e8e4c5aa61 |
@@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
||||||
"extends": [
|
|
||||||
"renovate/config"
|
|
||||||
],
|
|
||||||
"enabledManagers": ["nuget"],
|
|
||||||
"packageRules": [
|
|
||||||
{
|
|
||||||
// require approval for *all* NuGet package updates, not just major versions.
|
|
||||||
"matchDepTypes": "nuget",
|
|
||||||
"dependencyDashboardApproval": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// Ignore Gommon for automatic updates. I make breaking changes on minor updates not infrequently.
|
|
||||||
"matchDepNames": "Gommon",
|
|
||||||
"matchDepTypes": "nuget",
|
|
||||||
"enabled": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "group Silk.NET packages",
|
|
||||||
"extends": ["renovate/config//groups/silkdotnet.json"],
|
|
||||||
"groupName": "Silk.NET"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "group OpenTK packages",
|
|
||||||
"extends": ["renovate/config//groups/opentk.json"],
|
|
||||||
"groupName": "OpenTK"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "group Svg.Controls packages",
|
|
||||||
"extends": ["renovate/config//groups/svgcontrols.json"],
|
|
||||||
"groupName": "Svg.Controls"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
+3
-4
@@ -16,10 +16,6 @@ x64/
|
|||||||
build/
|
build/
|
||||||
[Bb]in/
|
[Bb]in/
|
||||||
[Oo]bj/
|
[Oo]bj/
|
||||||
AppDir/
|
|
||||||
publish_appimage/
|
|
||||||
publish_ava/
|
|
||||||
publish_tmp_ava/
|
|
||||||
|
|
||||||
# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
|
# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
|
||||||
!packages/*/build/
|
!packages/*/build/
|
||||||
@@ -177,3 +173,6 @@ PublishProfiles/
|
|||||||
|
|
||||||
# Glade backup files
|
# Glade backup files
|
||||||
*.glade~
|
*.glade~
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
/logs/
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[submodule "src/KenjinxAndroid/app/src/main/cpp/libraries/adrenotools"]
|
||||||
|
path = src/KenjinxAndroid/app/src/main/cpp/libraries/adrenotools
|
||||||
|
url = https://git.ryujinx.app/kenji-nx/libadrenotools.git
|
||||||
|
[submodule "src/KenjinxAndroid/app/src/main/cpp/libraries/openal"]
|
||||||
|
path = src/KenjinxAndroid/app/src/main/cpp/libraries/openal
|
||||||
|
url = https://git.ryujinx.app/kenji-nx/openal-soft.git
|
||||||
|
[submodule "src/KenjinxAndroid/app/src/main/cpp/libraries/adrenotools/lib/linkernsbypass"]
|
||||||
|
path = src/KenjinxAndroid/app/src/main/cpp/libraries/adrenotools/lib/linkernsbypass
|
||||||
|
url = https://git.ryujinx.app/kenji-nx/liblinkernsbypass.git
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net10.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<DebugType Condition="'$(Configuration)'=='Release'">none</DebugType>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
+21
-20
@@ -3,53 +3,54 @@
|
|||||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="Avalonia" Version="11.3.16" />
|
<PackageVersion Include="Avalonia" Version="11.3.13" />
|
||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.13" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.13" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.16" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.3.13" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.16" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.13" />
|
||||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.16" />
|
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.13" />
|
||||||
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.9.5" />
|
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.9.5" />
|
||||||
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.9.5" />
|
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.9.5" />
|
||||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
|
||||||
<PackageVersion Include="Concentus" Version="2.2.2" />
|
<PackageVersion Include="Concentus" Version="2.2.2" />
|
||||||
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
|
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
|
||||||
<PackageVersion Include="DynamicData" Version="9.4.31" />
|
<PackageVersion Include="DynamicData" Version="9.4.31" />
|
||||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.5.1" />
|
<PackageVersion Include="FluentAvaloniaUI" Version="2.4.1" />
|
||||||
<PackageVersion Include="Gommon" Version="2.8.1.2" />
|
<PackageVersion Include="Gommon" Version="2.8.1.1" />
|
||||||
<PackageVersion Include="Humanizer" Version="3.0.10" />
|
<PackageVersion Include="Humanizer" Version="3.0.10" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
|
||||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.18.0" />
|
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.17.0" />
|
||||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
|
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
|
||||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||||
<PackageVersion Include="NetCoreServer" Version="8.0.7" />
|
<PackageVersion Include="NetCoreServer" Version="8.0.7" />
|
||||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
|
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
|
||||||
<PackageVersion Include="NUnit" Version="4.6.1" />
|
<PackageVersion Include="NUnit" Version="4.5.1" />
|
||||||
<PackageVersion Include="NUnit3TestAdapter" Version="6.2.0" />
|
<PackageVersion Include="NUnit3TestAdapter" Version="6.2.0" />
|
||||||
<PackageVersion Include="OpenTK.Core" Version="4.9.4" />
|
<PackageVersion Include="OpenTK.Core" Version="4.9.4" />
|
||||||
<PackageVersion Include="OpenTK.Graphics" Version="4.9.4" />
|
<PackageVersion Include="OpenTK.Graphics" Version="4.9.4" />
|
||||||
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.9.4" />
|
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.9.4" />
|
||||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.9.4" />
|
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.9.4" />
|
||||||
<PackageVersion Include="Open.NAT.Core" Version="2.1.0.5" />
|
<PackageVersion Include="Open.NAT.Core" Version="2.1.0.5" />
|
||||||
<PackageVersion Include="Ryujinx.Audio.OpenAL" Version="1.25.1" />
|
<PackageVersion Include="Ryujinx.Audio.OpenAL" Version="1.25.2" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Linux" Version="6.1.4-build6" />
|
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Linux" Version="6.1.3-build5" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.macOS" Version="5.0.3-build14" />
|
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.macOS" Version="5.0.3-build14" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Windows" Version="6.1.4-build6" />
|
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Windows" Version="6.1.3-build5" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.MoltenVK" Version="1.4.2-ryujinx.3" />
|
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.133" />
|
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.128" />
|
||||||
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.501.0" />
|
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.707.0" />
|
||||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||||
<PackageVersion Include="Silk.NET.Shaderc" Version="2.23.0" />
|
<PackageVersion Include="Silk.NET.Shaderc" Version="2.23.0" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.23.0" />
|
<PackageVersion Include="Silk.NET.Vulkan" Version="2.23.0" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.23.0" />
|
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.23.0" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.23.0" />
|
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.23.0" />
|
||||||
<PackageVersion Include="SkiaSharp" Version="3.119.2" />
|
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
||||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="3.119.2" />
|
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
|
||||||
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
||||||
<PackageVersion Include="System.IO.Hashing" Version="10.0.8" />
|
<PackageVersion Include="System.IO.Hashing" Version="9.0.12" />
|
||||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.4-a40db6c" />
|
<PackageVersion Include="System.Management" Version="9.0.12" />
|
||||||
|
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.0" />
|
||||||
|
<PackageVersion Include="Rxmxnx.PInvoke.Extensions" Version="2.9.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
+261
@@ -0,0 +1,261 @@
|
|||||||
|
|
||||||
|
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.Tests", "src\Ryujinx.Tests\Ryujinx.Tests.csproj", "{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibKenjinx", "src\LibKenjinx\LibKenjinx.csproj", "{AF58C1D5-DE16-429B-B155-7CE83B4E8FA6}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests.Unicorn", "src\Ryujinx.Tests.Unicorn\Ryujinx.Tests.Unicorn.csproj", "{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE", "src\Ryujinx.HLE\Ryujinx.HLE.csproj", "{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.ShaderTools", "src\Ryujinx.ShaderTools\Ryujinx.ShaderTools.csproj", "{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Common", "src\Ryujinx.Common\Ryujinx.Common.csproj", "{5FD4E4F6-8928-4B3C-BE07-28A675C17226}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ARMeilleure", "src\ARMeilleure\ARMeilleure.csproj", "{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Gpu", "src\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj", "{ADA7EA87-0D63-4D97-9433-922A2124401F}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.GAL", "src\Ryujinx.Graphics.GAL\Ryujinx.Graphics.GAL.csproj", "{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.OpenGL", "src\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj", "{9558FB96-075D-4219-8FFF-401979DC0B69}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Texture", "src\Ryujinx.Graphics.Texture\Ryujinx.Graphics.Texture.csproj", "{E1B1AD28-289D-47B7-A106-326972240207}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Shader", "src\Ryujinx.Graphics.Shader\Ryujinx.Graphics.Shader.csproj", "{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec", "src\Ryujinx.Graphics.Nvdec\Ryujinx.Graphics.Nvdec.csproj", "{85A0FA56-DC01-4A42-8808-70DAC76BD66D}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio", "src\Ryujinx.Audio\Ryujinx.Audio.csproj", "{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
.editorconfig = .editorconfig
|
||||||
|
Directory.Build.props = Directory.Build.props
|
||||||
|
Directory.Packages.props = Directory.Packages.props
|
||||||
|
nuget.config = nuget.config
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Memory", "src\Ryujinx.Memory\Ryujinx.Memory.csproj", "{A5E6C691-9E22-4263-8F40-42F002CE66BE}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests.Memory", "src\Ryujinx.Tests.Memory\Ryujinx.Tests.Memory.csproj", "{D1CC5322-7325-4F6B-9625-194B30BE1296}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Cpu", "src\Ryujinx.Cpu\Ryujinx.Cpu.csproj", "{3DF35E3D-D844-4399-A9A1-A9E923264C17}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Device", "src\Ryujinx.Graphics.Device\Ryujinx.Graphics.Device.csproj", "{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Host1x", "src\Ryujinx.Graphics.Host1x\Ryujinx.Graphics.Host1x.csproj", "{C35F1536-7DE5-4F9D-9604-B5B4E1561947}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.Vp9", "src\Ryujinx.Graphics.Nvdec.Vp9\Ryujinx.Graphics.Nvdec.Vp9.csproj", "{B9AECA11-E248-4886-A10B-81B631CAAF29}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vic", "src\Ryujinx.Graphics.Vic\Ryujinx.Graphics.Vic.csproj", "{81BB2C11-9408-4EA3-822E-42987AF54429}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Video", "src\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj", "{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.OpenAL", "src\Ryujinx.Audio.Backends.OpenAL\Ryujinx.Audio.Backends.OpenAL.csproj", "{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SoundIo", "src\Ryujinx.Audio.Backends.SoundIo\Ryujinx.Audio.Backends.SoundIo.csproj", "{716364DE-B988-41A6-BAB4-327964266ECC}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input", "src\Ryujinx.Input\Ryujinx.Input.csproj", "{C16F112F-38C3-40BC-9F5F-4791112063D6}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input.SDL2", "src\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj", "{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "src\Ryujinx.SDL2.Common\Ryujinx.SDL2.Common.csproj", "{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
|
||||||
|
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}"
|
||||||
|
EndProject
|
||||||
|
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
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", "src\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj", "{D4D09B08-D580-4D69-B886-C35D2853F6C8}"
|
||||||
|
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}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Common", "src\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj", "{77F96ECE-4952-42DB-A528-DED25572A573}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon", "src\Ryujinx.Horizon\Ryujinx.Horizon.csproj", "{AF34127A-3A92-43E5-8496-14960A50B1F1}"
|
||||||
|
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}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{AF58C1D5-DE16-429B-B155-7CE83B4E8FA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{AF58C1D5-DE16-429B-B155-7CE83B4E8FA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{AF58C1D5-DE16-429B-B155-7CE83B4E8FA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{AF58C1D5-DE16-429B-B155-7CE83B4E8FA6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{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
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {110169B3-3328-4730-8AB0-BA05BEF75C1A}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
<File Path="nuget.config" />
|
<File Path="nuget.config" />
|
||||||
</Folder>
|
</Folder>
|
||||||
<Project Path="src/ARMeilleure/ARMeilleure.csproj" />
|
<Project Path="src/ARMeilleure/ARMeilleure.csproj" />
|
||||||
<Project Path="src/Ryujinx.Audio.Backends.Apple/Ryujinx.Audio.Backends.Apple.csproj" />
|
<Project Path="src/LibKenjinx/LibKenjinx.csproj" />
|
||||||
<Project Path="src/Ryujinx.Audio.Backends.OpenAL/Ryujinx.Audio.Backends.OpenAL.csproj" />
|
<Project Path="src/Ryujinx.Audio.Backends.OpenAL/Ryujinx.Audio.Backends.OpenAL.csproj" />
|
||||||
<Project Path="src/Ryujinx.Audio.Backends.SDL3/Ryujinx.Audio.Backends.SDL3.csproj" />
|
<Project Path="src/Ryujinx.Audio.Backends.SDL3/Ryujinx.Audio.Backends.SDL3.csproj" />
|
||||||
<Project Path="src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj" />
|
<Project Path="src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj" />
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
SCRIPT_DIR=$(dirname "$(realpath "$0")")
|
SCRIPT_DIR=$(dirname "$(realpath "$0")")
|
||||||
|
|
||||||
|
if [ -f "$SCRIPT_DIR/Ryujinx.Headless.SDL2" ]; then
|
||||||
|
RYUJINX_BIN="Ryujinx.Headless.SDL2"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -f "$SCRIPT_DIR/Ryujinx" ]; then
|
if [ -f "$SCRIPT_DIR/Ryujinx" ]; then
|
||||||
RYUJINX_BIN="Ryujinx"
|
RYUJINX_BIN="Ryujinx"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
CURRENTDIR="$(readlink -f "$(dirname "$0")")"
|
|
||||||
exec "$CURRENTDIR"/usr/bin/Ryujinx.sh "$@"
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
ROOTDIR="$(readlink -f "$(dirname "$0")")"/../../../
|
|
||||||
cd "$ROOTDIR"
|
|
||||||
|
|
||||||
BUILDDIR=${BUILDDIR:-publish}
|
|
||||||
OUTDIR=${OUTDIR:-publish_appimage}
|
|
||||||
|
|
||||||
rm -rf AppDir
|
|
||||||
mkdir -p AppDir/usr/bin
|
|
||||||
|
|
||||||
cp distribution/linux/Ryujinx.desktop AppDir/Ryujinx.desktop
|
|
||||||
cp distribution/linux/appimage/AppRun AppDir/AppRun
|
|
||||||
cp src/Ryujinx.UI.Common/Resources/Logo_Ryujinx.png AppDir/Ryujinx.svg
|
|
||||||
|
|
||||||
|
|
||||||
cp -r "$BUILDDIR"/* AppDir/usr/bin/
|
|
||||||
|
|
||||||
# Ensure necessary bins are set as executable
|
|
||||||
chmod +x AppDir/AppRun AppDir/usr/bin/Ryujinx*
|
|
||||||
|
|
||||||
mkdir -p "$OUTDIR"
|
|
||||||
|
|
||||||
appimagetool -n --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 21 \
|
|
||||||
AppDir "$OUTDIR"/Ryujinx.AppImage
|
|
||||||
Binary file not shown.
@@ -10,8 +10,6 @@
|
|||||||
<string>Ryujinx</string>
|
<string>Ryujinx</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>Ryujinx.icns</string>
|
<string>Ryujinx.icns</string>
|
||||||
<key>CFBundleIconName</key>
|
|
||||||
<string>Ryujinx</string>
|
|
||||||
<key>CFBundleDocumentTypes</key>
|
<key>CFBundleDocumentTypes</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
@@ -42,17 +40,17 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2.0</string>
|
<string>1.1</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>2.0.0</string>
|
<string>1.1.0</string>
|
||||||
<key>NSHighResolutionCapable</key>
|
<key>NSHighResolutionCapable</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>CSResourcesFileMapped</key>
|
<key>CSResourcesFileMapped</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>Copyright © 2018 - 2024 Ryujinx Team and Contributors. Copyright © 2024 - 2025 Kenji-NX and Contributors.</string>
|
<string>Copyright © 2018 - 2023 Ryujinx Team and Contributors.</string>
|
||||||
<key>LSApplicationCategoryType</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
<string>public.app-category.games</string>
|
<string>public.app-category.games</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
|||||||
Binary file not shown.
@@ -19,7 +19,7 @@ if platform.system() == "Darwin":
|
|||||||
else:
|
else:
|
||||||
OTOOL = shutil.which("llvm-otool")
|
OTOOL = shutil.which("llvm-otool")
|
||||||
if OTOOL is None:
|
if OTOOL is None:
|
||||||
for llvm_ver in [17, 16, 15, 14, 13]:
|
for llvm_ver in [15, 14, 13]:
|
||||||
otool_path = shutil.which(f"llvm-otool-{llvm_ver}")
|
otool_path = shutil.which(f"llvm-otool-{llvm_ver}")
|
||||||
if otool_path is not None:
|
if otool_path is not None:
|
||||||
OTOOL = otool_path
|
OTOOL = otool_path
|
||||||
@@ -562,29 +562,26 @@ search_path = [
|
|||||||
|
|
||||||
|
|
||||||
for path in content_directory.rglob("**/*.dylib"):
|
for path in content_directory.rglob("**/*.dylib"):
|
||||||
if not path.name.startswith("._"):
|
current_search_path = [path.parent]
|
||||||
current_search_path = [path.parent]
|
current_search_path.extend(search_path)
|
||||||
current_search_path.extend(search_path)
|
|
||||||
|
|
||||||
print(f"Fixing path '{path}' using search path of '{current_search_path}' for context of '{content_directory}'.")
|
fixup_dylib(
|
||||||
fixup_dylib(
|
path,
|
||||||
path,
|
get_path_related_to_target_exec(content_directory, path),
|
||||||
get_path_related_to_target_exec(content_directory, path),
|
current_search_path,
|
||||||
current_search_path,
|
content_directory,
|
||||||
content_directory,
|
)
|
||||||
)
|
|
||||||
|
|
||||||
for path in content_directory.rglob("**/*.so"):
|
for path in content_directory.rglob("**/*.so"):
|
||||||
if not path.name.startswith("._"):
|
current_search_path = [path.parent]
|
||||||
current_search_path = [path.parent]
|
current_search_path.extend(search_path)
|
||||||
current_search_path.extend(search_path)
|
|
||||||
|
|
||||||
fixup_dylib(
|
fixup_dylib(
|
||||||
path,
|
path,
|
||||||
get_path_related_to_target_exec(content_directory, path),
|
get_path_related_to_target_exec(content_directory, path),
|
||||||
current_search_path,
|
current_search_path,
|
||||||
content_directory,
|
content_directory,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
with open(executable_path, "rb") as input:
|
with open(executable_path, "rb") as input:
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ else:
|
|||||||
LIPO = shutil.which("llvm-lipo")
|
LIPO = shutil.which("llvm-lipo")
|
||||||
|
|
||||||
if LIPO is None:
|
if LIPO is None:
|
||||||
for llvm_ver in [17, 16, 15, 14, 13]:
|
for llvm_ver in [15, 14, 13]:
|
||||||
lipo_path = shutil.which(f"llvm-lipo-{llvm_ver}")
|
lipo_path = shutil.which(f"llvm-lipo-{llvm_ver}")
|
||||||
if lipo_path is not None:
|
if lipo_path is not None:
|
||||||
LIPO = lipo_path
|
LIPO = lipo_path
|
||||||
@@ -47,12 +47,14 @@ def get_new_name(
|
|||||||
input_component = str(input_dylib_path).replace(str(input_directory), "")[1:]
|
input_component = str(input_dylib_path).replace(str(input_directory), "")[1:]
|
||||||
return Path(os.path.join(output_directory, input_component))
|
return Path(os.path.join(output_directory, input_component))
|
||||||
|
|
||||||
def get_archs(dylib_path: Path) -> list[str]:
|
|
||||||
res = subprocess.check_output([LIPO, "-info", str(dylib_path)]).decode("utf-8")
|
def is_fat_file(dylib_path: Path) -> str:
|
||||||
if res.startswith("Non-fat file"):
|
res = subprocess.check_output([LIPO, "-info", str(dylib_path.absolute())]).decode(
|
||||||
return [res.split(":")[-1].strip()]
|
"utf-8"
|
||||||
else:
|
)
|
||||||
return res.split("are:")[-1].strip().split()
|
|
||||||
|
return not res.split("\n")[0].startswith("Non-fat file")
|
||||||
|
|
||||||
|
|
||||||
def construct_universal_dylib(
|
def construct_universal_dylib(
|
||||||
arm64_input_dylib_path: Path, x86_64_input_dylib_path: Path, output_dylib_path: Path
|
arm64_input_dylib_path: Path, x86_64_input_dylib_path: Path, output_dylib_path: Path
|
||||||
@@ -67,12 +69,11 @@ def construct_universal_dylib(
|
|||||||
os.path.basename(arm64_input_dylib_path.resolve()), output_dylib_path
|
os.path.basename(arm64_input_dylib_path.resolve()), output_dylib_path
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
arm64_archs = get_archs(arm64_input_dylib_path)
|
if is_fat_file(arm64_input_dylib_path) or not x86_64_input_dylib_path.exists():
|
||||||
x86_64_archs = get_archs(x86_64_input_dylib_path) if x86_64_input_dylib_path.exists() else []
|
with open(output_dylib_path, "wb") as dst:
|
||||||
|
with open(arm64_input_dylib_path, "rb") as src:
|
||||||
if "arm64" in arm64_archs and "x86_64" in arm64_archs:
|
dst.write(src.read())
|
||||||
shutil.copy2(arm64_input_dylib_path, output_dylib_path)
|
else:
|
||||||
elif x86_64_archs:
|
|
||||||
subprocess.check_call(
|
subprocess.check_call(
|
||||||
[
|
[
|
||||||
LIPO,
|
LIPO,
|
||||||
|
|||||||
@@ -25,41 +25,26 @@ cp "$PUBLISH_DIRECTORY"/*.dylib "$APP_BUNDLE_DIRECTORY/Contents/Frameworks"
|
|||||||
cp Info.plist "$APP_BUNDLE_DIRECTORY/Contents"
|
cp Info.plist "$APP_BUNDLE_DIRECTORY/Contents"
|
||||||
cp Ryujinx.icns "$APP_BUNDLE_DIRECTORY/Contents/Resources/Ryujinx.icns"
|
cp Ryujinx.icns "$APP_BUNDLE_DIRECTORY/Contents/Resources/Ryujinx.icns"
|
||||||
cp updater.sh "$APP_BUNDLE_DIRECTORY/Contents/Resources/updater.sh"
|
cp updater.sh "$APP_BUNDLE_DIRECTORY/Contents/Resources/updater.sh"
|
||||||
cp Assets.car "$APP_BUNDLE_DIRECTORY/Contents/Resources/Assets.car"
|
|
||||||
cp -r "$PUBLISH_DIRECTORY/THIRDPARTY.md" "$APP_BUNDLE_DIRECTORY/Contents/Resources"
|
cp -r "$PUBLISH_DIRECTORY/THIRDPARTY.md" "$APP_BUNDLE_DIRECTORY/Contents/Resources"
|
||||||
|
|
||||||
echo -n "APPL????" > "$APP_BUNDLE_DIRECTORY/Contents/PkgInfo"
|
echo -n "APPL????" > "$APP_BUNDLE_DIRECTORY/Contents/PkgInfo"
|
||||||
|
|
||||||
# Fixup libraries and executable
|
# Fixup libraries and executable
|
||||||
echo "Running bundle fix up python script"
|
|
||||||
python3 bundle_fix_up.py "$APP_BUNDLE_DIRECTORY" MacOS/Ryujinx
|
python3 bundle_fix_up.py "$APP_BUNDLE_DIRECTORY" MacOS/Ryujinx
|
||||||
|
|
||||||
# Resign all dyplib files as ad-hoc after changing them
|
|
||||||
find "$APP_BUNDLE_DIRECTORY/Contents/Frameworks" -type f -name "*.dylib" -exec codesign --force --sign - {} \;
|
|
||||||
|
|
||||||
# Now sign it
|
# Now sign it
|
||||||
echo "Starting signing process"
|
|
||||||
if ! [ -x "$(command -v codesign)" ];
|
if ! [ -x "$(command -v codesign)" ];
|
||||||
then
|
then
|
||||||
if ! [ -x "$(command -v rcodesign)" ];
|
if ! [ -x "$(command -v rcodesign)" ];
|
||||||
then
|
then
|
||||||
echo "Cannot find rcodesign on your system, please install rcodesign and ensure it is in your search path."
|
echo "Cannot find rcodesign on your system, please install rcodesign."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Using rcodesign for ad-hoc signing"
|
# cargo install apple-codesign
|
||||||
|
echo "Usign rcodesign for ad-hoc signing"
|
||||||
echo "Resigning all frameworks dylib files as ad-hoc"
|
|
||||||
find "$APP_BUNDLE_DIRECTORY/Contents/Frameworks" -type f -name "*.dylib" -exec rcodesign sign {} \;
|
|
||||||
|
|
||||||
echo "Signing app bundle as ad-hoc"
|
|
||||||
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$APP_BUNDLE_DIRECTORY"
|
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$APP_BUNDLE_DIRECTORY"
|
||||||
else
|
else
|
||||||
echo "Using codesign for ad-hoc signing"
|
echo "Usign codesign for ad-hoc signing"
|
||||||
|
|
||||||
echo "Resigning all frameworks dylib files as ad-hoc"
|
|
||||||
find "$APP_BUNDLE_DIRECTORY/Contents/Frameworks" -type f -name "*.dylib" -exec codesign --force --sign - {} \;
|
|
||||||
|
|
||||||
echo "Signing app bundle as ad-hoc"
|
|
||||||
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$APP_BUNDLE_DIRECTORY"
|
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$APP_BUNDLE_DIRECTORY"
|
||||||
fi
|
fi
|
||||||
@@ -20,19 +20,7 @@ SOURCE_REVISION_ID=$6
|
|||||||
CONFIGURATION=$7
|
CONFIGURATION=$7
|
||||||
EXTRA_ARGS=$8
|
EXTRA_ARGS=$8
|
||||||
|
|
||||||
if [[ "$(uname)" == "Darwin" ]]; then
|
if [ "$VERSION" == "1.1.0" ];
|
||||||
echo "Clearing xattr on all dot underscore files"
|
|
||||||
find "$BASE_DIR" -type f -name "._*" -exec sh -c '
|
|
||||||
for f; do
|
|
||||||
dir=$(dirname "$f")
|
|
||||||
base=$(basename "$f")
|
|
||||||
orig="$dir/${base#._}"
|
|
||||||
[ -f "$orig" ] && xattr -c "$orig" || true
|
|
||||||
done
|
|
||||||
' sh {} +
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$VERSION" == "2.0.0" ];
|
|
||||||
then
|
then
|
||||||
RELEASE_TAR_FILE_NAME=ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar
|
RELEASE_TAR_FILE_NAME=ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar
|
||||||
else
|
else
|
||||||
@@ -78,11 +66,11 @@ python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_APP_
|
|||||||
|
|
||||||
if ! [ -x "$(command -v lipo)" ];
|
if ! [ -x "$(command -v lipo)" ];
|
||||||
then
|
then
|
||||||
if ! [ -x "$(command -v llvm-lipo-17)" ];
|
if ! [ -x "$(command -v llvm-lipo-14)" ];
|
||||||
then
|
then
|
||||||
LIPO=llvm-lipo
|
LIPO=llvm-lipo
|
||||||
else
|
else
|
||||||
LIPO=llvm-lipo-17
|
LIPO=llvm-lipo-14
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
LIPO=lipo
|
LIPO=lipo
|
||||||
@@ -121,6 +109,12 @@ python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "
|
|||||||
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
|
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
|
||||||
rm "$RELEASE_TAR_FILE_NAME"
|
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
|
popd
|
||||||
|
|
||||||
echo "Done"
|
echo "Done"
|
||||||
+111
@@ -0,0 +1,111 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$#" -lt 7 ]; then
|
||||||
|
echo "usage <BASE_DIR> <TEMP_DIRECTORY> <OUTPUT_DIRECTORY> <ENTITLEMENTS_FILE_PATH> <VERSION> <SOURCE_REVISION_ID> <CONFIGURATION> <EXTRA_ARGS>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$1"
|
||||||
|
mkdir -p "$2"
|
||||||
|
mkdir -p "$3"
|
||||||
|
|
||||||
|
BASE_DIR=$(readlink -f "$1")
|
||||||
|
TEMP_DIRECTORY=$(readlink -f "$2")
|
||||||
|
OUTPUT_DIRECTORY=$(readlink -f "$3")
|
||||||
|
ENTITLEMENTS_FILE_PATH=$(readlink -f "$4")
|
||||||
|
VERSION=$5
|
||||||
|
SOURCE_REVISION_ID=$6
|
||||||
|
CONFIGURATION=$7
|
||||||
|
EXTRA_ARGS=$8
|
||||||
|
|
||||||
|
if [ "$VERSION" == "1.1.0" ];
|
||||||
|
then
|
||||||
|
RELEASE_TAR_FILE_NAME=sdl2-ryujinx-headless-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.tar
|
||||||
|
else
|
||||||
|
RELEASE_TAR_FILE_NAME=sdl2-ryujinx-headless-$VERSION-macos_universal.tar
|
||||||
|
fi
|
||||||
|
|
||||||
|
ARM64_OUTPUT="$TEMP_DIRECTORY/publish_arm64"
|
||||||
|
X64_OUTPUT="$TEMP_DIRECTORY/publish_x64"
|
||||||
|
UNIVERSAL_OUTPUT="$OUTPUT_DIRECTORY/publish"
|
||||||
|
EXECUTABLE_SUB_PATH=Ryujinx.Headless.SDL2
|
||||||
|
|
||||||
|
rm -rf "$TEMP_DIRECTORY"
|
||||||
|
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.Headless.SDL2
|
||||||
|
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL2
|
||||||
|
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL2
|
||||||
|
|
||||||
|
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
|
||||||
|
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
|
||||||
|
|
||||||
|
# Get rid of libsoundio from arm64 builds as we don't have a arm64 variant
|
||||||
|
# TODO: remove this once done
|
||||||
|
rm -rf "$TEMP_DIRECTORY/publish_arm64/libsoundio.dylib"
|
||||||
|
|
||||||
|
rm -rf "$OUTPUT_DIRECTORY"
|
||||||
|
mkdir -p "$OUTPUT_DIRECTORY"
|
||||||
|
|
||||||
|
# Let's copy one of the two different outputs and remove the executable
|
||||||
|
cp -R "$ARM64_OUTPUT/" "$UNIVERSAL_OUTPUT"
|
||||||
|
rm "$UNIVERSAL_OUTPUT/$EXECUTABLE_SUB_PATH"
|
||||||
|
|
||||||
|
# Make it libraries universal
|
||||||
|
python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_OUTPUT" "$X64_OUTPUT" "$UNIVERSAL_OUTPUT" "**/*.dylib"
|
||||||
|
|
||||||
|
if ! [ -x "$(command -v lipo)" ];
|
||||||
|
then
|
||||||
|
if ! [ -x "$(command -v llvm-lipo-14)" ];
|
||||||
|
then
|
||||||
|
LIPO=llvm-lipo
|
||||||
|
else
|
||||||
|
LIPO=llvm-lipo-14
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
LIPO=lipo
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make the executable universal
|
||||||
|
$LIPO "$ARM64_OUTPUT/$EXECUTABLE_SUB_PATH" "$X64_OUTPUT/$EXECUTABLE_SUB_PATH" -output "$UNIVERSAL_OUTPUT/$EXECUTABLE_SUB_PATH" -create
|
||||||
|
|
||||||
|
# Now sign it
|
||||||
|
if ! [ -x "$(command -v codesign)" ];
|
||||||
|
then
|
||||||
|
if ! [ -x "$(command -v rcodesign)" ];
|
||||||
|
then
|
||||||
|
echo "Cannot find rcodesign on your system, please install rcodesign."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# NOTE: Currently require https://github.com/indygreg/apple-platform-rs/pull/44 to work on other OSes.
|
||||||
|
# cargo install --git "https://github.com/marysaka/apple-platform-rs" --branch "fix/adhoc-app-bundle" apple-codesign --bin "rcodesign"
|
||||||
|
echo "Using rcodesign for ad-hoc signing"
|
||||||
|
for FILE in "$UNIVERSAL_OUTPUT"/*; do
|
||||||
|
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
|
||||||
|
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$FILE"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "Using codesign for ad-hoc signing"
|
||||||
|
for FILE in "$UNIVERSAL_OUTPUT"/*; do
|
||||||
|
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
|
||||||
|
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$FILE"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Creating archive"
|
||||||
|
pushd "$OUTPUT_DIRECTORY"
|
||||||
|
tar --exclude "publish/Ryujinx.Headless.SDL2" -cvf "$RELEASE_TAR_FILE_NAME" publish 1> /dev/null
|
||||||
|
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "publish/Ryujinx.Headless.SDL2" "publish/Ryujinx.Headless.SDL2"
|
||||||
|
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
|
||||||
|
rm "$RELEASE_TAR_FILE_NAME"
|
||||||
|
popd
|
||||||
|
|
||||||
|
echo "Done"
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "10.0.100",
|
"version": "9.0.100",
|
||||||
"rollForward": "latestFeature"
|
"rollForward": "latestFeature"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
public static void RunPass(ControlFlowGraph cfg)
|
public static void RunPass(ControlFlowGraph cfg)
|
||||||
{
|
{
|
||||||
var constants = new Dictionary<ulong, Operand>();
|
Dictionary<ulong, Operand> constants = new();
|
||||||
|
|
||||||
Operand GetConstantCopy(BasicBlock block, Operation operation, Operand source)
|
Operand GetConstantCopy(BasicBlock block, Operation operation, Operand source)
|
||||||
{
|
{
|
||||||
// If the constant has many uses, we also force a new constant mov to be added, in order
|
// If the constant has many uses, we also force a new constant mov to be added, in order
|
||||||
// to avoid overflow of the counts field (that is limited to 16 bits).
|
// to avoid overflow of the counts field (that is limited to 16 bits).
|
||||||
if (!constants.TryGetValue(source.Value, out var constant) || constant.UsesCount > MaxConstantUses)
|
if (!constants.TryGetValue(source.Value, out Operand constant) || constant.UsesCount > MaxConstantUses)
|
||||||
{
|
{
|
||||||
constant = Local(source.Type);
|
constant = Local(source.Type);
|
||||||
|
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
public void Cset(Operand rd, ArmCondition condition)
|
public void Cset(Operand rd, ArmCondition condition)
|
||||||
{
|
{
|
||||||
var zr = Factory.Register(ZrRegister, RegisterType.Integer, rd.Type);
|
Operand zr = Factory.Register(ZrRegister, RegisterType.Integer, rd.Type);
|
||||||
Csinc(rd, zr, zr, (ArmCondition)((int)condition ^ 1));
|
Csinc(rd, zr, zr, (ArmCondition)((int)condition ^ 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
long target = _stream.Position;
|
long target = _stream.Position;
|
||||||
|
|
||||||
if (_pendingBranches.TryGetValue(block, out var list))
|
if (_pendingBranches.TryGetValue(block, out List<(ArmCondition Condition, long BranchPos)> list))
|
||||||
{
|
{
|
||||||
foreach ((ArmCondition condition, long branchPos) in list)
|
foreach ((ArmCondition condition, long branchPos) in list)
|
||||||
{
|
{
|
||||||
@@ -119,7 +119,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!_pendingBranches.TryGetValue(target, out var list))
|
if (!_pendingBranches.TryGetValue(target, out List<(ArmCondition Condition, long BranchPos)> list))
|
||||||
{
|
{
|
||||||
list = new List<(ArmCondition, long)>();
|
list = new List<(ArmCondition, long)>();
|
||||||
_pendingBranches.Add(target, list);
|
_pendingBranches.Add(target, list);
|
||||||
|
|||||||
@@ -321,7 +321,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
var cond = ((Comparison)comp.AsInt32()).ToArmCondition();
|
ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
|
||||||
|
|
||||||
GenerateCompareCommon(context, operation);
|
GenerateCompareCommon(context, operation);
|
||||||
|
|
||||||
@@ -353,7 +353,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Debug.Assert(dest.Type == OperandType.I32);
|
Debug.Assert(dest.Type == OperandType.I32);
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
var cond = ((Comparison)comp.AsInt32()).ToArmCondition();
|
ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
|
||||||
|
|
||||||
GenerateCompareCommon(context, operation);
|
GenerateCompareCommon(context, operation);
|
||||||
|
|
||||||
|
|||||||
@@ -847,7 +847,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
var compType = (Comparison)comp.AsInt32();
|
Comparison compType = (Comparison)comp.AsInt32();
|
||||||
|
|
||||||
return compType is Comparison.Equal or Comparison.NotEqual;
|
return compType is Comparison.Equal or Comparison.NotEqual;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
{
|
{
|
||||||
NumberLocals(cfg, regMasks.RegistersCount);
|
NumberLocals(cfg, regMasks.RegistersCount);
|
||||||
|
|
||||||
var context = new AllocationContext(stackAlloc, regMasks, _intervals.Count);
|
AllocationContext context = new(stackAlloc, regMasks, _intervals.Count);
|
||||||
|
|
||||||
BuildIntervals(cfg, context);
|
BuildIntervals(cfg, context);
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
{
|
{
|
||||||
if (_count + 1 > _capacity)
|
if (_count + 1 > _capacity)
|
||||||
{
|
{
|
||||||
var oldSpan = Span;
|
Span<LiveInterval> oldSpan = Span;
|
||||||
|
|
||||||
_capacity = Math.Max(4, _capacity * 2);
|
_capacity = Math.Max(4, _capacity * 2);
|
||||||
_items = Allocators.References.Allocate<LiveInterval>((uint)_capacity);
|
_items = Allocators.References.Allocate<LiveInterval>((uint)_capacity);
|
||||||
|
|
||||||
var newSpan = Span;
|
Span<LiveInterval> newSpan = Span;
|
||||||
|
|
||||||
oldSpan.CopyTo(newSpan);
|
oldSpan.CopyTo(newSpan);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||||||
{
|
{
|
||||||
if (Count + 1 > _capacity)
|
if (Count + 1 > _capacity)
|
||||||
{
|
{
|
||||||
var oldSpan = Span;
|
Span<int> oldSpan = Span;
|
||||||
|
|
||||||
_capacity = Math.Max(4, _capacity * 2);
|
_capacity = Math.Max(4, _capacity * 2);
|
||||||
_items = Allocators.Default.Allocate<int>((uint)_capacity);
|
_items = Allocators.Default.Allocate<int>((uint)_capacity);
|
||||||
|
|
||||||
var newSpan = Span;
|
Span<int> newSpan = Span;
|
||||||
|
|
||||||
oldSpan.CopyTo(newSpan);
|
oldSpan.CopyTo(newSpan);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using ARMeilleure.CodeGen.Linking;
|
using ARMeilleure.CodeGen.Linking;
|
||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
|
using Microsoft.IO;
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -1324,8 +1325,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
public (byte[], RelocInfo) GetCode()
|
public (byte[], RelocInfo) GetCode()
|
||||||
{
|
{
|
||||||
var jumps = CollectionsMarshal.AsSpan(_jumps);
|
Span<Jump> jumps = CollectionsMarshal.AsSpan(_jumps);
|
||||||
var relocs = CollectionsMarshal.AsSpan(_relocs);
|
Span<Reloc> relocs = CollectionsMarshal.AsSpan(_relocs);
|
||||||
|
|
||||||
// Write jump relative offsets.
|
// Write jump relative offsets.
|
||||||
bool modified;
|
bool modified;
|
||||||
@@ -1410,13 +1411,13 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
// Write the code, ignoring the dummy bytes after jumps, into a new stream.
|
// Write the code, ignoring the dummy bytes after jumps, into a new stream.
|
||||||
_stream.Seek(0, SeekOrigin.Begin);
|
_stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
using var codeStream = MemoryStreamManager.Shared.GetStream();
|
using RecyclableMemoryStream codeStream = MemoryStreamManager.Shared.GetStream();
|
||||||
var assembler = new Assembler(codeStream, HasRelocs);
|
Assembler assembler = new(codeStream, HasRelocs);
|
||||||
|
|
||||||
bool hasRelocs = HasRelocs;
|
bool hasRelocs = HasRelocs;
|
||||||
int relocIndex = 0;
|
int relocIndex = 0;
|
||||||
int relocOffset = 0;
|
int relocOffset = 0;
|
||||||
var relocEntries = hasRelocs
|
RelocEntry[] relocEntries = hasRelocs
|
||||||
? new RelocEntry[relocs.Length]
|
? new RelocEntry[relocs.Length]
|
||||||
: Array.Empty<RelocEntry>();
|
: Array.Empty<RelocEntry>();
|
||||||
|
|
||||||
@@ -1469,8 +1470,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
_stream.CopyTo(codeStream);
|
_stream.CopyTo(codeStream);
|
||||||
|
|
||||||
var code = codeStream.ToArray();
|
byte[] code = codeStream.ToArray();
|
||||||
var relocInfo = new RelocInfo(relocEntries);
|
RelocInfo relocInfo = new(relocEntries);
|
||||||
|
|
||||||
return (code, relocInfo);
|
return (code, relocInfo);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -622,7 +622,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
var cond = ((Comparison)comp.AsInt32()).ToX86Condition();
|
X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
|
||||||
|
|
||||||
GenerateCompareCommon(context, operation);
|
GenerateCompareCommon(context, operation);
|
||||||
|
|
||||||
@@ -660,7 +660,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Debug.Assert(dest.Type == OperandType.I32);
|
Debug.Assert(dest.Type == OperandType.I32);
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
var cond = ((Comparison)comp.AsInt32()).ToX86Condition();
|
X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
|
||||||
|
|
||||||
GenerateCompareCommon(context, operation);
|
GenerateCompareCommon(context, operation);
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
memGetXcr0.Reprotect(0, (ulong)asmGetXcr0.Length, MemoryPermission.ReadAndExecute);
|
memGetXcr0.Reprotect(0, (ulong)asmGetXcr0.Length, MemoryPermission.ReadAndExecute);
|
||||||
|
|
||||||
var fGetXcr0 = Marshal.GetDelegateForFunctionPointer<GetXcr0>(memGetXcr0.Pointer);
|
GetXcr0 fGetXcr0 = Marshal.GetDelegateForFunctionPointer<GetXcr0>(memGetXcr0.Pointer);
|
||||||
|
|
||||||
return fGetXcr0();
|
return fGetXcr0();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -759,7 +759,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||||
|
|
||||||
var compType = (Comparison)comp.AsInt32();
|
Comparison compType = (Comparison)comp.AsInt32();
|
||||||
|
|
||||||
return compType is Comparison.Equal or Comparison.NotEqual;
|
return compType is Comparison.Equal or Comparison.NotEqual;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
public static void RunPass(ControlFlowGraph cfg)
|
public static void RunPass(ControlFlowGraph cfg)
|
||||||
{
|
{
|
||||||
var constants = new Dictionary<ulong, Operand>();
|
Dictionary<ulong, Operand> constants = new();
|
||||||
|
|
||||||
Operand GetConstantCopy(BasicBlock block, Operation operation, Operand source)
|
Operand GetConstantCopy(BasicBlock block, Operation operation, Operand source)
|
||||||
{
|
{
|
||||||
// If the constant has many uses, we also force a new constant mov to be added, in order
|
// If the constant has many uses, we also force a new constant mov to be added, in order
|
||||||
// to avoid overflow of the counts field (that is limited to 16 bits).
|
// to avoid overflow of the counts field (that is limited to 16 bits).
|
||||||
if (!constants.TryGetValue(source.Value, out var constant) || constant.UsesCount > MaxConstantUses)
|
if (!constants.TryGetValue(source.Value, out Operand constant) || constant.UsesCount > MaxConstantUses)
|
||||||
{
|
{
|
||||||
constant = Local(source.Type);
|
constant = Local(source.Type);
|
||||||
|
|
||||||
|
|||||||
@@ -129,13 +129,13 @@ namespace ARMeilleure.Common
|
|||||||
|
|
||||||
if (count > _count)
|
if (count > _count)
|
||||||
{
|
{
|
||||||
var oldMask = _masks;
|
long* oldMask = _masks;
|
||||||
var oldSpan = new Span<long>(_masks, _count);
|
Span<long> oldSpan = new(_masks, _count);
|
||||||
|
|
||||||
_masks = _allocator.Allocate<long>((uint)count);
|
_masks = _allocator.Allocate<long>((uint)count);
|
||||||
_count = count;
|
_count = count;
|
||||||
|
|
||||||
var newSpan = new Span<long>(_masks, _count);
|
Span<long> newSpan = new(_masks, _count);
|
||||||
|
|
||||||
oldSpan.CopyTo(newSpan);
|
oldSpan.CopyTo(newSpan);
|
||||||
newSpan[oldSpan.Length..].Clear();
|
newSpan[oldSpan.Length..].Clear();
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ namespace ARMeilleure.Common
|
|||||||
}
|
}
|
||||||
|
|
||||||
int index = _freeHint++;
|
int index = _freeHint++;
|
||||||
var page = GetPage(index);
|
Span<TEntry> page = GetPage(index);
|
||||||
|
|
||||||
_allocated.Set(index);
|
_allocated.Set(index);
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ namespace ARMeilleure.Common
|
|||||||
throw new ArgumentException("Entry at the specified index was not allocated", nameof(index));
|
throw new ArgumentException("Entry at the specified index was not allocated", nameof(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
var page = GetPage(index);
|
Span<TEntry> page = GetPage(index);
|
||||||
|
|
||||||
return ref GetValue(page, index);
|
return ref GetValue(page, index);
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ namespace ARMeilleure.Common
|
|||||||
/// <returns>Page for the specified <see cref="index"/></returns>
|
/// <returns>Page for the specified <see cref="index"/></returns>
|
||||||
private unsafe Span<TEntry> GetPage(int index)
|
private unsafe Span<TEntry> GetPage(int index)
|
||||||
{
|
{
|
||||||
var pageIndex = (int)((uint)(index & ~(_pageCapacity - 1)) >> _pageLogCapacity);
|
int pageIndex = (int)((uint)(index & ~(_pageCapacity - 1)) >> _pageLogCapacity);
|
||||||
|
|
||||||
if (!_pages.TryGetValue(pageIndex, out nint page))
|
if (!_pages.TryGetValue(pageIndex, out nint page))
|
||||||
{
|
{
|
||||||
@@ -168,7 +168,7 @@ namespace ARMeilleure.Common
|
|||||||
{
|
{
|
||||||
_allocated.Dispose();
|
_allocated.Dispose();
|
||||||
|
|
||||||
foreach (var page in _pages.Values)
|
foreach (IntPtr page in _pages.Values)
|
||||||
{
|
{
|
||||||
NativeAllocator.Instance.Free((void*)page);
|
NativeAllocator.Instance.Free((void*)page);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
public OpCode32SimdDupElem(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
public OpCode32SimdDupElem(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
|
||||||
{
|
{
|
||||||
var opc = (opCode >> 16) & 0xf;
|
int opc = (opCode >> 16) & 0xf;
|
||||||
|
|
||||||
if ((opc & 0b1) == 1)
|
if ((opc & 0b1) == 1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace ARMeilleure.Decoders
|
|||||||
Op = (opCode >> 20) & 0x1;
|
Op = (opCode >> 20) & 0x1;
|
||||||
U = ((opCode >> 23) & 1) != 0;
|
U = ((opCode >> 23) & 1) != 0;
|
||||||
|
|
||||||
var opc = (((opCode >> 23) & 1) << 4) | (((opCode >> 21) & 0x3) << 2) | ((opCode >> 5) & 0x3);
|
int opc = (((opCode >> 23) & 1) << 4) | (((opCode >> 21) & 0x3) << 2) | ((opCode >> 5) & 0x3);
|
||||||
|
|
||||||
if ((opc & 0b01000) == 0b01000)
|
if ((opc & 0b01000) == 0b01000)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace ARMeilleure.Decoders
|
|||||||
}
|
}
|
||||||
else if (DataOp == DataOp.Logical)
|
else if (DataOp == DataOp.Logical)
|
||||||
{
|
{
|
||||||
var bm = DecoderHelper.DecodeBitMask(opCode, true);
|
DecoderHelper.BitMask bm = DecoderHelper.DecodeBitMask(opCode, true);
|
||||||
|
|
||||||
if (bm.IsUndefined)
|
if (bm.IsUndefined)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
public OpCodeBfm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeBfm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
var bm = DecoderHelper.DecodeBitMask(opCode, false);
|
DecoderHelper.BitMask bm = DecoderHelper.DecodeBitMask(opCode, false);
|
||||||
|
|
||||||
if (bm.IsUndefined)
|
if (bm.IsUndefined)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ namespace ARMeilleure.Decoders.Optimizations
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var newBlocks = new List<Block>(blocks.Count);
|
List<Block> newBlocks = new(blocks.Count);
|
||||||
|
|
||||||
// Finally, rebuild decoded block list, ignoring blocks outside the contiguous range.
|
// Finally, rebuild decoded block list, ignoring blocks outside the contiguous range.
|
||||||
for (int i = 0; i < blocks.Count; i++)
|
for (int i = 0; i < blocks.Count; i++)
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ namespace ARMeilleure.Diagnostics
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OperandKind.Memory:
|
case OperandKind.Memory:
|
||||||
var memOp = operand.GetMemory();
|
MemoryOperand memOp = operand.GetMemory();
|
||||||
|
|
||||||
_builder.Append('[');
|
_builder.Append('[');
|
||||||
|
|
||||||
@@ -284,7 +284,7 @@ namespace ARMeilleure.Diagnostics
|
|||||||
|
|
||||||
public static string GetDump(ControlFlowGraph cfg)
|
public static string GetDump(ControlFlowGraph cfg)
|
||||||
{
|
{
|
||||||
var dumper = new IRDumper(1);
|
IRDumper dumper = new(1);
|
||||||
|
|
||||||
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
|
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -415,7 +415,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
IOpCode32AluBf op = (IOpCode32AluBf)context.CurrOp;
|
IOpCode32AluBf op = (IOpCode32AluBf)context.CurrOp;
|
||||||
|
|
||||||
var msb = op.Lsb + op.Msb; // For this instruction, the msb is actually a width.
|
int msb = op.Lsb + op.Msb; // For this instruction, the msb is actually a width.
|
||||||
|
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
Operand res = context.ShiftRightSI(context.ShiftLeft(n, Const(31 - msb)), Const(31 - op.Msb));
|
Operand res = context.ShiftRightSI(context.ShiftLeft(n, Const(31 - msb)), Const(31 - op.Msb));
|
||||||
@@ -547,7 +547,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
IOpCode32AluBf op = (IOpCode32AluBf)context.CurrOp;
|
IOpCode32AluBf op = (IOpCode32AluBf)context.CurrOp;
|
||||||
|
|
||||||
var msb = op.Lsb + op.Msb; // For this instruction, the msb is actually a width.
|
int msb = op.Lsb + op.Msb; // For this instruction, the msb is actually a width.
|
||||||
|
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
Operand res = context.ShiftRightUI(context.ShiftLeft(n, Const(31 - msb)), Const(31 - op.Msb));
|
Operand res = context.ShiftRightUI(context.ShiftLeft(n, Const(31 - msb)), Const(31 - op.Msb));
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using ARMeilleure.CodeGen.Linking;
|
using ARMeilleure.CodeGen.Linking;
|
||||||
|
using ARMeilleure.Common;
|
||||||
using ARMeilleure.Decoders;
|
using ARMeilleure.Decoders;
|
||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
@@ -146,12 +147,6 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void EmitCall(ArmEmitterContext context, ulong immediate)
|
public static void EmitCall(ArmEmitterContext context, ulong immediate)
|
||||||
{
|
{
|
||||||
if (context.IsSingleStep)
|
|
||||||
{
|
|
||||||
context.Return(Const(immediate));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isRecursive = immediate == context.EntryAddress;
|
bool isRecursive = immediate == context.EntryAddress;
|
||||||
|
|
||||||
if (isRecursive)
|
if (isRecursive)
|
||||||
@@ -166,24 +161,12 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void EmitVirtualCall(ArmEmitterContext context, Operand target)
|
public static void EmitVirtualCall(ArmEmitterContext context, Operand target)
|
||||||
{
|
{
|
||||||
if (context.IsSingleStep)
|
EmitTableBranch(context, target, isJump: false);
|
||||||
{
|
|
||||||
if (target.Type == OperandType.I32)
|
|
||||||
{
|
|
||||||
target = context.ZeroExtend32(OperandType.I64, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Return(target);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EmitTableBranch(context, target, isJump: false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void EmitVirtualJump(ArmEmitterContext context, Operand target, bool isReturn)
|
public static void EmitVirtualJump(ArmEmitterContext context, Operand target, bool isReturn)
|
||||||
{
|
{
|
||||||
if (isReturn || context.IsSingleStep)
|
if (isReturn)
|
||||||
{
|
{
|
||||||
EmitReturn(context, target);
|
EmitReturn(context, target);
|
||||||
}
|
}
|
||||||
@@ -223,7 +206,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand hostAddress;
|
Operand hostAddress;
|
||||||
|
|
||||||
var table = context.FunctionTable;
|
IAddressTable<ulong> table = context.FunctionTable;
|
||||||
|
|
||||||
// If address is mapped onto the function table, we can skip the table walk. Otherwise we fallback
|
// If address is mapped onto the function table, we can skip the table walk. Otherwise we fallback
|
||||||
// onto the dispatch stub.
|
// onto the dispatch stub.
|
||||||
@@ -248,7 +231,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
for (int i = 0; i < table.Levels.Length; i++)
|
for (int i = 0; i < table.Levels.Length; i++)
|
||||||
{
|
{
|
||||||
var level = table.Levels[i];
|
AddressTableLevel level = table.Levels[i];
|
||||||
int clearBits = 64 - (level.Index + level.Length);
|
int clearBits = 64 - (level.Index + level.Length);
|
||||||
|
|
||||||
Operand index = context.ShiftLeft(
|
Operand index = context.ShiftLeft(
|
||||||
|
|||||||
@@ -143,8 +143,8 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand address = context.Copy(GetIntA32(context, op.Rn));
|
Operand address = context.Copy(GetIntA32(context, op.Rn));
|
||||||
|
|
||||||
var exclusive = (accType & AccessType.Exclusive) != 0;
|
bool exclusive = (accType & AccessType.Exclusive) != 0;
|
||||||
var ordered = (accType & AccessType.Ordered) != 0;
|
bool ordered = (accType & AccessType.Ordered) != 0;
|
||||||
|
|
||||||
if ((accType & AccessType.Load) != 0)
|
if ((accType & AccessType.Load) != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static Operand ZerosOrOnes(ArmEmitterContext context, Operand fromBool, OperandType baseType)
|
private static Operand ZerosOrOnes(ArmEmitterContext context, Operand fromBool, OperandType baseType)
|
||||||
{
|
{
|
||||||
var ones = (baseType == OperandType.I64) ? Const(-1L) : Const(-1);
|
Operand ones = (baseType == OperandType.I64) ? Const(-1L) : Const(-1);
|
||||||
|
|
||||||
return context.ConditionalSelect(fromBool, ones, Const(baseType, 0L));
|
return context.ConditionalSelect(fromBool, ones, Const(baseType, 0L));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,15 +118,15 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
OpCode32SimdCvtFFixed op = (OpCode32SimdCvtFFixed)context.CurrOp;
|
OpCode32SimdCvtFFixed op = (OpCode32SimdCvtFFixed)context.CurrOp;
|
||||||
|
|
||||||
var toFixed = op.Opc == 1;
|
bool toFixed = op.Opc == 1;
|
||||||
int fracBits = op.Fbits;
|
int fracBits = op.Fbits;
|
||||||
var unsigned = op.U;
|
bool unsigned = op.U;
|
||||||
|
|
||||||
if (toFixed) // F32 to S32 or U32 (fixed)
|
if (toFixed) // F32 to S32 or U32 (fixed)
|
||||||
{
|
{
|
||||||
EmitVectorUnaryOpF32(context, (op1) =>
|
EmitVectorUnaryOpF32(context, (op1) =>
|
||||||
{
|
{
|
||||||
var scaledValue = context.Multiply(op1, ConstF(MathF.Pow(2f, fracBits)));
|
Operand scaledValue = context.Multiply(op1, ConstF(MathF.Pow(2f, fracBits)));
|
||||||
MethodInfo info = unsigned ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)) : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32));
|
MethodInfo info = unsigned ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)) : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32));
|
||||||
|
|
||||||
return context.Call(info, scaledValue);
|
return context.Call(info, scaledValue);
|
||||||
@@ -136,7 +136,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
EmitVectorUnaryOpI32(context, (op1) =>
|
EmitVectorUnaryOpI32(context, (op1) =>
|
||||||
{
|
{
|
||||||
var floatValue = unsigned ? context.ConvertToFPUI(OperandType.FP32, op1) : context.ConvertToFP(OperandType.FP32, op1);
|
Operand floatValue = unsigned ? context.ConvertToFPUI(OperandType.FP32, op1) : context.ConvertToFP(OperandType.FP32, op1);
|
||||||
|
|
||||||
return context.Multiply(floatValue, ConstF(1f / MathF.Pow(2f, fracBits)));
|
return context.Multiply(floatValue, ConstF(1f / MathF.Pow(2f, fracBits)));
|
||||||
}, !unsigned);
|
}, !unsigned);
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
if (op.Replicate)
|
if (op.Replicate)
|
||||||
{
|
{
|
||||||
var regs = (count > 1) ? 1 : op.Increment;
|
int regs = (count > 1) ? 1 : op.Increment;
|
||||||
for (int reg = 0; reg < regs; reg++)
|
for (int reg = 0; reg < regs; reg++)
|
||||||
{
|
{
|
||||||
int dreg = reg + d;
|
int dreg = reg + d;
|
||||||
|
|||||||
@@ -1,35 +1,59 @@
|
|||||||
using System;
|
using System;
|
||||||
|
#if ANDROID
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
#else
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
static class MathHelper
|
static class MathHelper
|
||||||
{
|
{
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double Abs(double value)
|
public static double Abs(double value)
|
||||||
{
|
{
|
||||||
return Math.Abs(value);
|
return Math.Abs(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double Ceiling(double value)
|
public static double Ceiling(double value)
|
||||||
{
|
{
|
||||||
return Math.Ceiling(value);
|
return Math.Ceiling(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double Floor(double value)
|
public static double Floor(double value)
|
||||||
{
|
{
|
||||||
return Math.Floor(value);
|
return Math.Floor(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double Round(double value, int mode)
|
public static double Round(double value, int mode)
|
||||||
{
|
{
|
||||||
return Math.Round(value, (MidpointRounding)mode);
|
return Math.Round(value, (MidpointRounding)mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double Truncate(double value)
|
public static double Truncate(double value)
|
||||||
{
|
{
|
||||||
return Math.Truncate(value);
|
return Math.Truncate(value);
|
||||||
@@ -38,31 +62,51 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
static class MathHelperF
|
static class MathHelperF
|
||||||
{
|
{
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float Abs(float value)
|
public static float Abs(float value)
|
||||||
{
|
{
|
||||||
return MathF.Abs(value);
|
return MathF.Abs(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float Ceiling(float value)
|
public static float Ceiling(float value)
|
||||||
{
|
{
|
||||||
return MathF.Ceiling(value);
|
return MathF.Ceiling(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float Floor(float value)
|
public static float Floor(float value)
|
||||||
{
|
{
|
||||||
return MathF.Floor(value);
|
return MathF.Floor(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float Round(float value, int mode)
|
public static float Round(float value, int mode)
|
||||||
{
|
{
|
||||||
return MathF.Round(value, (MidpointRounding)mode);
|
return MathF.Round(value, (MidpointRounding)mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float Truncate(float value)
|
public static float Truncate(float value)
|
||||||
{
|
{
|
||||||
return MathF.Truncate(value);
|
return MathF.Truncate(value);
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ using ARMeilleure.Memory;
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using System;
|
using System;
|
||||||
|
#if ANDROID
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
#else
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
@@ -35,7 +39,11 @@ namespace ARMeilleure.Instructions
|
|||||||
Context = null;
|
Context = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void Break(ulong address, int imm)
|
public static void Break(ulong address, int imm)
|
||||||
{
|
{
|
||||||
Statistics.PauseTimer();
|
Statistics.PauseTimer();
|
||||||
@@ -45,7 +53,11 @@ namespace ARMeilleure.Instructions
|
|||||||
Statistics.ResumeTimer();
|
Statistics.ResumeTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void SupervisorCall(ulong address, int imm)
|
public static void SupervisorCall(ulong address, int imm)
|
||||||
{
|
{
|
||||||
Statistics.PauseTimer();
|
Statistics.PauseTimer();
|
||||||
@@ -55,7 +67,11 @@ namespace ARMeilleure.Instructions
|
|||||||
Statistics.ResumeTimer();
|
Statistics.ResumeTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void Undefined(ulong address, int opCode)
|
public static void Undefined(ulong address, int opCode)
|
||||||
{
|
{
|
||||||
Statistics.PauseTimer();
|
Statistics.PauseTimer();
|
||||||
@@ -66,31 +82,51 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region "System registers"
|
#region "System registers"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong GetCtrEl0()
|
public static ulong GetCtrEl0()
|
||||||
{
|
{
|
||||||
return GetContext().CtrEl0;
|
return GetContext().CtrEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong GetDczidEl0()
|
public static ulong GetDczidEl0()
|
||||||
{
|
{
|
||||||
return GetContext().DczidEl0;
|
return GetContext().DczidEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong GetCntfrqEl0()
|
public static ulong GetCntfrqEl0()
|
||||||
{
|
{
|
||||||
return GetContext().CntfrqEl0;
|
return GetContext().CntfrqEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong GetCntpctEl0()
|
public static ulong GetCntpctEl0()
|
||||||
{
|
{
|
||||||
return GetContext().CntpctEl0;
|
return GetContext().CntpctEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong GetCntvctEl0()
|
public static ulong GetCntvctEl0()
|
||||||
{
|
{
|
||||||
return GetContext().CntvctEl0;
|
return GetContext().CntvctEl0;
|
||||||
@@ -98,31 +134,51 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Read"
|
#region "Read"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static byte ReadByte(ulong address)
|
public static byte ReadByte(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadGuest<byte>(address);
|
return GetMemoryManager().ReadGuest<byte>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ushort ReadUInt16(ulong address)
|
public static ushort ReadUInt16(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadGuest<ushort>(address);
|
return GetMemoryManager().ReadGuest<ushort>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint ReadUInt32(ulong address)
|
public static uint ReadUInt32(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadGuest<uint>(address);
|
return GetMemoryManager().ReadGuest<uint>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong ReadUInt64(ulong address)
|
public static ulong ReadUInt64(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadGuest<ulong>(address);
|
return GetMemoryManager().ReadGuest<ulong>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 ReadVector128(ulong address)
|
public static V128 ReadVector128(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadGuest<V128>(address);
|
return GetMemoryManager().ReadGuest<V128>(address);
|
||||||
@@ -130,56 +186,92 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Write"
|
#region "Write"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void WriteByte(ulong address, byte value)
|
public static void WriteByte(ulong address, byte value)
|
||||||
{
|
{
|
||||||
GetMemoryManager().WriteGuest(address, value);
|
GetMemoryManager().WriteGuest(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void WriteUInt16(ulong address, ushort value)
|
public static void WriteUInt16(ulong address, ushort value)
|
||||||
{
|
{
|
||||||
GetMemoryManager().WriteGuest(address, value);
|
GetMemoryManager().WriteGuest(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void WriteUInt32(ulong address, uint value)
|
public static void WriteUInt32(ulong address, uint value)
|
||||||
{
|
{
|
||||||
GetMemoryManager().WriteGuest(address, value);
|
GetMemoryManager().WriteGuest(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void WriteUInt64(ulong address, ulong value)
|
public static void WriteUInt64(ulong address, ulong value)
|
||||||
{
|
{
|
||||||
GetMemoryManager().WriteGuest(address, value);
|
GetMemoryManager().WriteGuest(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void WriteVector128(ulong address, V128 value)
|
public static void WriteVector128(ulong address, V128 value)
|
||||||
{
|
{
|
||||||
GetMemoryManager().WriteGuest(address, value);
|
GetMemoryManager().WriteGuest(address, value);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void EnqueueForRejit(ulong address)
|
public static void EnqueueForRejit(ulong address)
|
||||||
{
|
{
|
||||||
Context.Translator.EnqueueForRejit(address, GetContext().ExecutionMode);
|
Context.Translator.EnqueueForRejit(address, GetContext().ExecutionMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void SignalMemoryTracking(ulong address, ulong size, byte write)
|
public static void SignalMemoryTracking(ulong address, ulong size, byte write)
|
||||||
{
|
{
|
||||||
GetMemoryManager().SignalMemoryTracking(address, size, write == 1);
|
GetMemoryManager().SignalMemoryTracking(address, size, write == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void ThrowInvalidMemoryAccess(ulong address)
|
public static void ThrowInvalidMemoryAccess(ulong address)
|
||||||
{
|
{
|
||||||
throw new InvalidAccessException(address);
|
throw new InvalidAccessException(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong GetFunctionAddress(ulong address)
|
public static ulong GetFunctionAddress(ulong address)
|
||||||
{
|
{
|
||||||
TranslatedFunction function = Context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
|
TranslatedFunction function = Context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
|
||||||
@@ -187,13 +279,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return (ulong)function.FuncPointer.ToInt64();
|
return (ulong)function.FuncPointer.ToInt64();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static void InvalidateCacheLine(ulong address)
|
public static void InvalidateCacheLine(ulong address)
|
||||||
{
|
{
|
||||||
Context.Translator.InvalidateJitCacheRegion(address, InstEmit.DczSizeInBytes);
|
Context.Translator.InvalidateJitCacheRegion(address, InstEmit.DczSizeInBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static byte CheckSynchronization()
|
public static byte CheckSynchronization()
|
||||||
{
|
{
|
||||||
Statistics.PauseTimer();
|
Statistics.PauseTimer();
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using System;
|
using System;
|
||||||
|
#if ANDROID
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
#else
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
static class SoftFallback
|
static class SoftFallback
|
||||||
{
|
{
|
||||||
#region "ShrImm64"
|
#region "ShrImm64"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static long SignedShrImm64(long value, long roundConst, int shift)
|
public static long SignedShrImm64(long value, long roundConst, int shift)
|
||||||
{
|
{
|
||||||
if (roundConst == 0L)
|
if (roundConst == 0L)
|
||||||
@@ -50,7 +58,11 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
|
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
|
||||||
{
|
{
|
||||||
if (roundConst == 0L)
|
if (roundConst == 0L)
|
||||||
@@ -95,7 +107,11 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Saturation"
|
#region "Saturation"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static int SatF32ToS32(float value)
|
public static int SatF32ToS32(float value)
|
||||||
{
|
{
|
||||||
if (float.IsNaN(value))
|
if (float.IsNaN(value))
|
||||||
@@ -107,7 +123,11 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= int.MinValue ? int.MinValue : (int)value;
|
value <= int.MinValue ? int.MinValue : (int)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static long SatF32ToS64(float value)
|
public static long SatF32ToS64(float value)
|
||||||
{
|
{
|
||||||
if (float.IsNaN(value))
|
if (float.IsNaN(value))
|
||||||
@@ -119,7 +139,11 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= long.MinValue ? long.MinValue : (long)value;
|
value <= long.MinValue ? long.MinValue : (long)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint SatF32ToU32(float value)
|
public static uint SatF32ToU32(float value)
|
||||||
{
|
{
|
||||||
if (float.IsNaN(value))
|
if (float.IsNaN(value))
|
||||||
@@ -131,7 +155,11 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong SatF32ToU64(float value)
|
public static ulong SatF32ToU64(float value)
|
||||||
{
|
{
|
||||||
if (float.IsNaN(value))
|
if (float.IsNaN(value))
|
||||||
@@ -143,7 +171,11 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
|
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static int SatF64ToS32(double value)
|
public static int SatF64ToS32(double value)
|
||||||
{
|
{
|
||||||
if (double.IsNaN(value))
|
if (double.IsNaN(value))
|
||||||
@@ -155,7 +187,11 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= int.MinValue ? int.MinValue : (int)value;
|
value <= int.MinValue ? int.MinValue : (int)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static long SatF64ToS64(double value)
|
public static long SatF64ToS64(double value)
|
||||||
{
|
{
|
||||||
if (double.IsNaN(value))
|
if (double.IsNaN(value))
|
||||||
@@ -167,7 +203,11 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= long.MinValue ? long.MinValue : (long)value;
|
value <= long.MinValue ? long.MinValue : (long)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint SatF64ToU32(double value)
|
public static uint SatF64ToU32(double value)
|
||||||
{
|
{
|
||||||
if (double.IsNaN(value))
|
if (double.IsNaN(value))
|
||||||
@@ -179,7 +219,11 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong SatF64ToU64(double value)
|
public static ulong SatF64ToU64(double value)
|
||||||
{
|
{
|
||||||
if (double.IsNaN(value))
|
if (double.IsNaN(value))
|
||||||
@@ -193,7 +237,11 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Count"
|
#region "Count"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
||||||
{
|
{
|
||||||
value ^= value >> 1;
|
value ^= value >> 1;
|
||||||
@@ -213,7 +261,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static ReadOnlySpan<byte> ClzNibbleTbl => [4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
|
private static ReadOnlySpan<byte> ClzNibbleTbl => [4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
||||||
{
|
{
|
||||||
if (value == 0ul)
|
if (value == 0ul)
|
||||||
@@ -237,49 +289,81 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Table"
|
#region "Table"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
|
public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
|
||||||
{
|
{
|
||||||
return TblOrTbx(default, vector, bytes, tb0);
|
return TblOrTbx(default, vector, bytes, tb0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
|
public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
|
||||||
{
|
{
|
||||||
return TblOrTbx(default, vector, bytes, tb0, tb1);
|
return TblOrTbx(default, vector, bytes, tb0, tb1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
||||||
{
|
{
|
||||||
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
|
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
|
public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
|
||||||
{
|
{
|
||||||
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3);
|
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
|
public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
|
||||||
{
|
{
|
||||||
return TblOrTbx(dest, vector, bytes, tb0);
|
return TblOrTbx(dest, vector, bytes, tb0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
|
public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
|
||||||
{
|
{
|
||||||
return TblOrTbx(dest, vector, bytes, tb0, tb1);
|
return TblOrTbx(dest, vector, bytes, tb0, tb1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
||||||
{
|
{
|
||||||
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
|
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
|
public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
|
||||||
{
|
{
|
||||||
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
|
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
|
||||||
@@ -321,22 +405,54 @@ namespace ARMeilleure.Instructions
|
|||||||
private const uint Crc32RevPoly = 0xedb88320;
|
private const uint Crc32RevPoly = 0xedb88320;
|
||||||
private const uint Crc32cRevPoly = 0x82f63b78;
|
private const uint Crc32cRevPoly = 0x82f63b78;
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
|
public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
|
public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
|
public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
|
public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
|
public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
|
public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
|
public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
|
public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
|
||||||
|
|
||||||
private static uint Crc32h(uint crc, uint poly, ushort val)
|
private static uint Crc32h(uint crc, uint poly, ushort val)
|
||||||
@@ -387,25 +503,41 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Aes"
|
#region "Aes"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Decrypt(V128 value, V128 roundKey)
|
public static V128 Decrypt(V128 value, V128 roundKey)
|
||||||
{
|
{
|
||||||
return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
|
return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Encrypt(V128 value, V128 roundKey)
|
public static V128 Encrypt(V128 value, V128 roundKey)
|
||||||
{
|
{
|
||||||
return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
|
return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 InverseMixColumns(V128 value)
|
public static V128 InverseMixColumns(V128 value)
|
||||||
{
|
{
|
||||||
return CryptoHelper.AesInvMixColumns(value);
|
return CryptoHelper.AesInvMixColumns(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 MixColumns(V128 value)
|
public static V128 MixColumns(V128 value)
|
||||||
{
|
{
|
||||||
return CryptoHelper.AesMixColumns(value);
|
return CryptoHelper.AesMixColumns(value);
|
||||||
@@ -413,7 +545,11 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Sha1"
|
#region "Sha1"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
|
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
|
||||||
{
|
{
|
||||||
for (int e = 0; e <= 3; e++)
|
for (int e = 0; e <= 3; e++)
|
||||||
@@ -434,13 +570,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return hash_abcd;
|
return hash_abcd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static uint FixedRotate(uint hash_e)
|
public static uint FixedRotate(uint hash_e)
|
||||||
{
|
{
|
||||||
return hash_e.Rol(30);
|
return hash_e.Rol(30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
|
public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
|
||||||
{
|
{
|
||||||
for (int e = 0; e <= 3; e++)
|
for (int e = 0; e <= 3; e++)
|
||||||
@@ -461,7 +605,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return hash_abcd;
|
return hash_abcd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
|
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
|
||||||
{
|
{
|
||||||
for (int e = 0; e <= 3; e++)
|
for (int e = 0; e <= 3; e++)
|
||||||
@@ -482,7 +630,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return hash_abcd;
|
return hash_abcd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
|
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
|
||||||
{
|
{
|
||||||
ulong t2 = w4_7.Extract<ulong>(0);
|
ulong t2 = w4_7.Extract<ulong>(0);
|
||||||
@@ -493,7 +645,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result ^ (w0_3 ^ w8_11);
|
return result ^ (w0_3 ^ w8_11);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
|
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
|
||||||
{
|
{
|
||||||
V128 t = tw0_3 ^ (w12_15 >> 32);
|
V128 t = tw0_3 ^ (w12_15 >> 32);
|
||||||
@@ -538,19 +694,31 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Sha256"
|
#region "Sha256"
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
||||||
{
|
{
|
||||||
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
|
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
||||||
{
|
{
|
||||||
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
|
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
|
public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
|
||||||
{
|
{
|
||||||
V128 result = new();
|
V128 result = new();
|
||||||
@@ -569,7 +737,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
|
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
|
||||||
{
|
{
|
||||||
V128 result = new();
|
V128 result = new();
|
||||||
@@ -671,7 +843,11 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static V128 PolynomialMult64_128(ulong op1, ulong op2)
|
public static V128 PolynomialMult64_128(ulong op1, ulong op2)
|
||||||
{
|
{
|
||||||
V128 result = V128.Zero;
|
V128 result = V128.Zero;
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
#if ANDROID
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
#else
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
@@ -313,7 +317,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
static class SoftFloat16_32
|
static class SoftFloat16_32
|
||||||
{
|
{
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPConvert(ushort valueBits)
|
public static float FPConvert(ushort valueBits)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -489,7 +497,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
static class SoftFloat16_64
|
static class SoftFloat16_64
|
||||||
{
|
{
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPConvert(ushort valueBits)
|
public static double FPConvert(ushort valueBits)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -665,7 +677,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
static class SoftFloat32_16
|
static class SoftFloat32_16
|
||||||
{
|
{
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ushort FPConvert(float value)
|
public static ushort FPConvert(float value)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -785,13 +801,21 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
static class SoftFloat32
|
static class SoftFloat32
|
||||||
{
|
{
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPAdd(float value1, float value2)
|
public static float FPAdd(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPAddFpscrImpl(value1, value2, false);
|
return FPAddFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPAddFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPAddFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -848,7 +872,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static int FPCompare(float value1, float value2, byte signalNaNs)
|
public static int FPCompare(float value1, float value2, byte signalNaNs)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -887,7 +915,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPCompareEQ(float value1, float value2)
|
public static float FPCompareEQ(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPCompareEQFpscrImpl(value1, value2, false);
|
return FPCompareEQFpscrImpl(value1, value2, false);
|
||||||
@@ -920,19 +952,31 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPCompareEQFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPCompareEQFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPCompareGE(float value1, float value2)
|
public static float FPCompareGE(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value1, value2, false);
|
return FPCompareGEFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPCompareGEFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPCompareGEFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -962,13 +1006,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPCompareGT(float value1, float value2)
|
public static float FPCompareGT(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPCompareGTFpscrImpl(value1, value2, false);
|
return FPCompareGTFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPCompareGTFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPCompareGTFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -998,31 +1050,51 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPCompareLE(float value1, float value2)
|
public static float FPCompareLE(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value2, value1, false);
|
return FPCompareGEFpscrImpl(value2, value1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPCompareLT(float value1, float value2)
|
public static float FPCompareLT(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPCompareGTFpscrImpl(value2, value1, false);
|
return FPCompareGTFpscrImpl(value2, value1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPCompareLEFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPCompareLEFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPCompareLTFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPCompareLTFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPDiv(float value1, float value2)
|
public static float FPDiv(float value1, float value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -1075,13 +1147,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPMax(float value1, float value2)
|
public static float FPMax(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPMaxFpscrImpl(value1, value2, false);
|
return FPMaxFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPMaxFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPMaxFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -1148,7 +1228,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPMaxNum(float value1, float value2)
|
public static float FPMaxNum(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPMaxNumFpscrImpl(value1, value2, false);
|
return FPMaxNumFpscrImpl(value1, value2, false);
|
||||||
@@ -1174,19 +1258,31 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMaxFpscrImpl(value1, value2, standardFpscr);
|
return FPMaxFpscrImpl(value1, value2, standardFpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPMaxNumFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPMaxNumFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPMin(float value1, float value2)
|
public static float FPMin(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPMinFpscrImpl(value1, value2, false);
|
return FPMinFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPMinFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPMinFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -1253,13 +1349,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPMinNum(float value1, float value2)
|
public static float FPMinNum(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPMinNumFpscrImpl(value1, value2, false);
|
return FPMinNumFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPMinNumFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPMinNumFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -1285,13 +1389,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMinFpscrImpl(value1, value2, standardFpscr);
|
return FPMinFpscrImpl(value1, value2, standardFpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPMul(float value1, float value2)
|
public static float FPMul(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPMulFpscrImpl(value1, value2, false);
|
return FPMulFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPMulFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPMulFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -1344,13 +1456,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPMulAdd(float valueA, float value1, float value2)
|
public static float FPMulAdd(float valueA, float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPMulAddFpscr(float valueA, float value1, float value2, byte standardFpscr)
|
public static float FPMulAddFpscr(float valueA, float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||||
@@ -1422,7 +1542,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPMulSub(float valueA, float value1, float value2)
|
public static float FPMulSub(float valueA, float value1, float value2)
|
||||||
{
|
{
|
||||||
value1 = value1.FPNeg();
|
value1 = value1.FPNeg();
|
||||||
@@ -1430,7 +1554,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPMulSubFpscr(float valueA, float value1, float value2, byte standardFpscr)
|
public static float FPMulSubFpscr(float valueA, float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
value1 = value1.FPNeg();
|
value1 = value1.FPNeg();
|
||||||
@@ -1438,7 +1566,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPMulX(float value1, float value2)
|
public static float FPMulX(float value1, float value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -1484,7 +1616,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPNegMulAdd(float valueA, float value1, float value2)
|
public static float FPNegMulAdd(float valueA, float value1, float value2)
|
||||||
{
|
{
|
||||||
valueA = valueA.FPNeg();
|
valueA = valueA.FPNeg();
|
||||||
@@ -1493,7 +1629,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPNegMulSub(float valueA, float value1, float value2)
|
public static float FPNegMulSub(float valueA, float value1, float value2)
|
||||||
{
|
{
|
||||||
valueA = valueA.FPNeg();
|
valueA = valueA.FPNeg();
|
||||||
@@ -1501,13 +1641,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPRecipEstimate(float value)
|
public static float FPRecipEstimate(float value)
|
||||||
{
|
{
|
||||||
return FPRecipEstimateFpscrImpl(value, false);
|
return FPRecipEstimateFpscrImpl(value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPRecipEstimateFpscr(float value, byte standardFpscr)
|
public static float FPRecipEstimateFpscr(float value, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
|
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
|
||||||
@@ -1538,7 +1686,7 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
else if (MathF.Abs(value) < MathF.Pow(2f, -128))
|
else if (MathF.Abs(value) < MathF.Pow(2f, -128))
|
||||||
{
|
{
|
||||||
var overflowToInf = fpcr.GetRoundingMode() switch
|
bool overflowToInf = fpcr.GetRoundingMode() switch
|
||||||
{
|
{
|
||||||
FPRoundingMode.ToNearest => true,
|
FPRoundingMode.ToNearest => true,
|
||||||
FPRoundingMode.TowardsPlusInfinity => !sign,
|
FPRoundingMode.TowardsPlusInfinity => !sign,
|
||||||
@@ -1600,7 +1748,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPRecipStep(float value1, float value2)
|
public static float FPRecipStep(float value1, float value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -1635,7 +1787,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPRecipStepFused(float value1, float value2)
|
public static float FPRecipStepFused(float value1, float value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -1679,7 +1835,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPRecpX(float value)
|
public static float FPRecpX(float value)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -1705,13 +1865,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPRSqrtEstimate(float value)
|
public static float FPRSqrtEstimate(float value)
|
||||||
{
|
{
|
||||||
return FPRSqrtEstimateFpscrImpl(value, false);
|
return FPRSqrtEstimateFpscrImpl(value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPRSqrtEstimateFpscr(float value, byte standardFpscr)
|
public static float FPRSqrtEstimateFpscr(float value, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
|
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
|
||||||
@@ -1831,7 +1999,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPRSqrtStep(float value1, float value2)
|
public static float FPRSqrtStep(float value1, float value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -1866,7 +2038,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPRSqrtStepFused(float value1, float value2)
|
public static float FPRSqrtStepFused(float value1, float value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -1910,7 +2086,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPSqrt(float value)
|
public static float FPSqrt(float value)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -1953,7 +2133,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static float FPSub(float value1, float value2)
|
public static float FPSub(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPSubFpscrImpl(value1, value2, false);
|
return FPSubFpscrImpl(value1, value2, false);
|
||||||
@@ -2200,7 +2384,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
static class SoftFloat64_16
|
static class SoftFloat64_16
|
||||||
{
|
{
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static ushort FPConvert(double value)
|
public static ushort FPConvert(double value)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -2320,13 +2508,21 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
static class SoftFloat64
|
static class SoftFloat64
|
||||||
{
|
{
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPAdd(double value1, double value2)
|
public static double FPAdd(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPAddFpscrImpl(value1, value2, false);
|
return FPAddFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPAddFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPAddFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -2383,7 +2579,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static int FPCompare(double value1, double value2, byte signalNaNs)
|
public static int FPCompare(double value1, double value2, byte signalNaNs)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -2422,13 +2622,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPCompareEQ(double value1, double value2)
|
public static double FPCompareEQ(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPCompareEQFpscrImpl(value1, value2, false);
|
return FPCompareEQFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPCompareEQFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPCompareEQFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -2461,13 +2669,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPCompareGE(double value1, double value2)
|
public static double FPCompareGE(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value1, value2, false);
|
return FPCompareGEFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPCompareGEFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPCompareGEFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -2497,13 +2713,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPCompareGT(double value1, double value2)
|
public static double FPCompareGT(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPCompareGTFpscrImpl(value1, value2, false);
|
return FPCompareGTFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPCompareGTFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPCompareGTFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -2533,31 +2757,51 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPCompareLE(double value1, double value2)
|
public static double FPCompareLE(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value2, value1, false);
|
return FPCompareGEFpscrImpl(value2, value1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPCompareLT(double value1, double value2)
|
public static double FPCompareLT(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPCompareGTFpscrImpl(value2, value1, false);
|
return FPCompareGTFpscrImpl(value2, value1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPCompareLEFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPCompareLEFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPCompareLTFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPCompareLTFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGTFpscrImpl(value2, value1, standardFpscr == 1);
|
return FPCompareGTFpscrImpl(value2, value1, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPDiv(double value1, double value2)
|
public static double FPDiv(double value1, double value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -2610,13 +2854,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPMax(double value1, double value2)
|
public static double FPMax(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPMaxFpscrImpl(value1, value2, false);
|
return FPMaxFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPMaxFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPMaxFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -2683,13 +2935,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPMaxNum(double value1, double value2)
|
public static double FPMaxNum(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPMaxNumFpscrImpl(value1, value2, false);
|
return FPMaxNumFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPMaxNumFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPMaxNumFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -2715,13 +2975,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMaxFpscrImpl(value1, value2, standardFpscr);
|
return FPMaxFpscrImpl(value1, value2, standardFpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPMin(double value1, double value2)
|
public static double FPMin(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPMinFpscrImpl(value1, value2, false);
|
return FPMinFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPMinFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPMinFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -2788,13 +3056,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPMinNum(double value1, double value2)
|
public static double FPMinNum(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPMinNumFpscrImpl(value1, value2, false);
|
return FPMinNumFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPMinNumFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPMinNumFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -2820,13 +3096,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMinFpscrImpl(value1, value2, standardFpscr);
|
return FPMinFpscrImpl(value1, value2, standardFpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPMul(double value1, double value2)
|
public static double FPMul(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPMulFpscrImpl(value1, value2, false);
|
return FPMulFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPMulFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPMulFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -2879,13 +3163,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPMulAdd(double valueA, double value1, double value2)
|
public static double FPMulAdd(double valueA, double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPMulAddFpscr(double valueA, double value1, double value2, byte standardFpscr)
|
public static double FPMulAddFpscr(double valueA, double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||||
@@ -2957,7 +3249,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPMulSub(double valueA, double value1, double value2)
|
public static double FPMulSub(double valueA, double value1, double value2)
|
||||||
{
|
{
|
||||||
value1 = value1.FPNeg();
|
value1 = value1.FPNeg();
|
||||||
@@ -2965,7 +3261,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPMulSubFpscr(double valueA, double value1, double value2, byte standardFpscr)
|
public static double FPMulSubFpscr(double valueA, double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
value1 = value1.FPNeg();
|
value1 = value1.FPNeg();
|
||||||
@@ -2973,7 +3273,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPMulX(double value1, double value2)
|
public static double FPMulX(double value1, double value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -3019,7 +3323,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPNegMulAdd(double valueA, double value1, double value2)
|
public static double FPNegMulAdd(double valueA, double value1, double value2)
|
||||||
{
|
{
|
||||||
valueA = valueA.FPNeg();
|
valueA = valueA.FPNeg();
|
||||||
@@ -3028,7 +3336,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPNegMulSub(double valueA, double value1, double value2)
|
public static double FPNegMulSub(double valueA, double value1, double value2)
|
||||||
{
|
{
|
||||||
valueA = valueA.FPNeg();
|
valueA = valueA.FPNeg();
|
||||||
@@ -3036,13 +3348,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPRecipEstimate(double value)
|
public static double FPRecipEstimate(double value)
|
||||||
{
|
{
|
||||||
return FPRecipEstimateFpscrImpl(value, false);
|
return FPRecipEstimateFpscrImpl(value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPRecipEstimateFpscr(double value, byte standardFpscr)
|
public static double FPRecipEstimateFpscr(double value, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
|
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
|
||||||
@@ -3073,7 +3393,7 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
else if (Math.Abs(value) < Math.Pow(2d, -1024))
|
else if (Math.Abs(value) < Math.Pow(2d, -1024))
|
||||||
{
|
{
|
||||||
var overflowToInf = fpcr.GetRoundingMode() switch
|
bool overflowToInf = fpcr.GetRoundingMode() switch
|
||||||
{
|
{
|
||||||
FPRoundingMode.ToNearest => true,
|
FPRoundingMode.ToNearest => true,
|
||||||
FPRoundingMode.TowardsPlusInfinity => !sign,
|
FPRoundingMode.TowardsPlusInfinity => !sign,
|
||||||
@@ -3135,7 +3455,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPRecipStep(double value1, double value2)
|
public static double FPRecipStep(double value1, double value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -3170,7 +3494,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPRecipStepFused(double value1, double value2)
|
public static double FPRecipStepFused(double value1, double value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -3214,7 +3542,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPRecpX(double value)
|
public static double FPRecpX(double value)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -3240,13 +3572,21 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPRSqrtEstimate(double value)
|
public static double FPRSqrtEstimate(double value)
|
||||||
{
|
{
|
||||||
return FPRSqrtEstimateFpscrImpl(value, false);
|
return FPRSqrtEstimateFpscrImpl(value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPRSqrtEstimateFpscr(double value, byte standardFpscr)
|
public static double FPRSqrtEstimateFpscr(double value, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
|
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
|
||||||
@@ -3366,7 +3706,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPRSqrtStep(double value1, double value2)
|
public static double FPRSqrtStep(double value1, double value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -3401,7 +3745,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPRSqrtStepFused(double value1, double value2)
|
public static double FPRSqrtStepFused(double value1, double value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -3445,7 +3793,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPSqrt(double value)
|
public static double FPSqrt(double value)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -3488,7 +3840,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
#else
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
|
#endif
|
||||||
public static double FPSub(double value1, double value2)
|
public static double FPSub(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPSubFpscr(value1, value2, false);
|
return FPSubFpscr(value1, value2, false);
|
||||||
|
|||||||
@@ -304,7 +304,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
ushort newCount = checked((ushort)(count + 1));
|
ushort newCount = checked((ushort)(count + 1));
|
||||||
ushort newCapacity = (ushort)Math.Min(capacity * 2, ushort.MaxValue);
|
ushort newCapacity = (ushort)Math.Min(capacity * 2, ushort.MaxValue);
|
||||||
|
|
||||||
var oldSpan = new Span<T>(data, count);
|
Span<T> oldSpan = new(data, count);
|
||||||
|
|
||||||
capacity = newCapacity;
|
capacity = newCapacity;
|
||||||
data = Allocators.References.Allocate<T>(capacity);
|
data = Allocators.References.Allocate<T>(capacity);
|
||||||
@@ -338,7 +338,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
throw new OverflowException();
|
throw new OverflowException();
|
||||||
}
|
}
|
||||||
|
|
||||||
var oldSpan = new Span<T>(data, (int)count);
|
Span<T> oldSpan = new(data, (int)count);
|
||||||
|
|
||||||
capacity = newCapacity;
|
capacity = newCapacity;
|
||||||
data = Allocators.References.Allocate<T>(capacity);
|
data = Allocators.References.Allocate<T>(capacity);
|
||||||
@@ -352,7 +352,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
|
|
||||||
private static void Remove<T>(in T item, ref T* data, ref ushort count) where T : unmanaged
|
private static void Remove<T>(in T item, ref T* data, ref ushort count) where T : unmanaged
|
||||||
{
|
{
|
||||||
var span = new Span<T>(data, count);
|
Span<T> span = new(data, count);
|
||||||
|
|
||||||
for (int i = 0; i < span.Length; i++)
|
for (int i = 0; i < span.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -372,7 +372,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
|
|
||||||
private static void Remove<T>(in T item, ref T* data, ref uint count) where T : unmanaged
|
private static void Remove<T>(in T item, ref T* data, ref uint count) where T : unmanaged
|
||||||
{
|
{
|
||||||
var span = new Span<T>(data, (int)count);
|
Span<T> span = new(data, (int)count);
|
||||||
|
|
||||||
for (int i = 0; i < span.Length; i++)
|
for (int i = 0; i < span.Length; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,11 +8,13 @@ namespace ARMeilleure
|
|||||||
// low-core count PPTC
|
// low-core count PPTC
|
||||||
public static bool EcoFriendly { get; set; } = false;
|
public static bool EcoFriendly { get; set; } = false;
|
||||||
|
|
||||||
|
// Jit cache eviction
|
||||||
|
public static bool CacheEviction { get; set; } = false;
|
||||||
|
|
||||||
public static bool FastFP { get; set; } = true;
|
public static bool FastFP { get; set; } = true;
|
||||||
|
|
||||||
public static bool AllowLcqInFunctionTable { get; set; } = true;
|
public static bool AllowLcqInFunctionTable { get; set; } = true;
|
||||||
public static bool UseUnmanagedDispatchLoop { get; set; } = true;
|
public static bool UseUnmanagedDispatchLoop { get; set; } = true;
|
||||||
public static bool EnableDebugging { get; set; } = false;
|
|
||||||
public static bool EnableDeepCallRecursionProtection { get; set; } = true;
|
public static bool EnableDeepCallRecursionProtection { get; set; } = true;
|
||||||
|
|
||||||
public static bool UseAdvSimdIfAvailable { get; set; } = true;
|
public static bool UseAdvSimdIfAvailable { get; set; } = true;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace ARMeilleure.Signal
|
|||||||
{
|
{
|
||||||
public static class NativeSignalHandlerGenerator
|
public static class NativeSignalHandlerGenerator
|
||||||
{
|
{
|
||||||
public const int MaxTrackedRanges = 16;
|
public const int MaxTrackedRanges = 8;
|
||||||
|
|
||||||
private const int StructAddressOffset = 0;
|
private const int StructAddressOffset = 0;
|
||||||
private const int StructWriteOffset = 4;
|
private const int StructWriteOffset = 4;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace ARMeilleure.Signal
|
|||||||
{
|
{
|
||||||
EmitterContext context = new();
|
EmitterContext context = new();
|
||||||
|
|
||||||
var result = WindowsPartialUnmapHandler.EmitRetryFromAccessViolation(context);
|
Operand result = WindowsPartialUnmapHandler.EmitRetryFromAccessViolation(context);
|
||||||
|
|
||||||
context.Return(result);
|
context.Return(result);
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ namespace ARMeilleure.Signal
|
|||||||
{
|
{
|
||||||
EmitterContext context = new();
|
EmitterContext context = new();
|
||||||
|
|
||||||
var result = WindowsPartialUnmapHandler.EmitThreadLocalMapIntGetOrReserve(context, structPtr, context.LoadArgument(OperandType.I32, 0), context.LoadArgument(OperandType.I32, 1));
|
Operand result = WindowsPartialUnmapHandler.EmitThreadLocalMapIntGetOrReserve(context, structPtr, context.LoadArgument(OperandType.I32, 0), context.LoadArgument(OperandType.I32, 1));
|
||||||
|
|
||||||
context.Return(result);
|
context.Return(result);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace ARMeilleure.State
|
namespace ARMeilleure.State
|
||||||
{
|
{
|
||||||
@@ -11,7 +10,7 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
internal nint NativeContextPtr => _nativeContext.BasePtr;
|
internal nint NativeContextPtr => _nativeContext.BasePtr;
|
||||||
|
|
||||||
internal bool Interrupted { get; private set; }
|
private bool _interrupted;
|
||||||
|
|
||||||
private readonly ICounter _counter;
|
private readonly ICounter _counter;
|
||||||
|
|
||||||
@@ -68,8 +67,6 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
public bool IsAarch32 { get; set; }
|
public bool IsAarch32 { get; set; }
|
||||||
|
|
||||||
public ulong ThreadUid { get; set; }
|
|
||||||
|
|
||||||
internal ExecutionMode ExecutionMode
|
internal ExecutionMode ExecutionMode
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -95,19 +92,14 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
||||||
private readonly ExceptionCallback _breakCallback;
|
private readonly ExceptionCallback _breakCallback;
|
||||||
private readonly ExceptionCallbackNoArgs _stepCallback;
|
|
||||||
private readonly ExceptionCallback _supervisorCallback;
|
private readonly ExceptionCallback _supervisorCallback;
|
||||||
private readonly ExceptionCallback _undefinedCallback;
|
private readonly ExceptionCallback _undefinedCallback;
|
||||||
|
|
||||||
internal int ShouldStep;
|
|
||||||
public ulong DebugPc { get; set; }
|
|
||||||
|
|
||||||
public ExecutionContext(
|
public ExecutionContext(
|
||||||
IJitMemoryAllocator allocator,
|
IJitMemoryAllocator allocator,
|
||||||
ICounter counter,
|
ICounter counter,
|
||||||
ExceptionCallbackNoArgs interruptCallback = null,
|
ExceptionCallbackNoArgs interruptCallback = null,
|
||||||
ExceptionCallback breakCallback = null,
|
ExceptionCallback breakCallback = null,
|
||||||
ExceptionCallbackNoArgs stepCallback = null,
|
|
||||||
ExceptionCallback supervisorCallback = null,
|
ExceptionCallback supervisorCallback = null,
|
||||||
ExceptionCallback undefinedCallback = null)
|
ExceptionCallback undefinedCallback = null)
|
||||||
{
|
{
|
||||||
@@ -115,7 +107,6 @@ namespace ARMeilleure.State
|
|||||||
_counter = counter;
|
_counter = counter;
|
||||||
_interruptCallback = interruptCallback;
|
_interruptCallback = interruptCallback;
|
||||||
_breakCallback = breakCallback;
|
_breakCallback = breakCallback;
|
||||||
_stepCallback = stepCallback;
|
|
||||||
_supervisorCallback = supervisorCallback;
|
_supervisorCallback = supervisorCallback;
|
||||||
_undefinedCallback = undefinedCallback;
|
_undefinedCallback = undefinedCallback;
|
||||||
|
|
||||||
@@ -143,9 +134,9 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
internal void CheckInterrupt()
|
internal void CheckInterrupt()
|
||||||
{
|
{
|
||||||
if (Interrupted)
|
if (_interrupted)
|
||||||
{
|
{
|
||||||
Interrupted = false;
|
_interrupted = false;
|
||||||
|
|
||||||
_interruptCallback?.Invoke(this);
|
_interruptCallback?.Invoke(this);
|
||||||
}
|
}
|
||||||
@@ -155,37 +146,16 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
public void RequestInterrupt()
|
public void RequestInterrupt()
|
||||||
{
|
{
|
||||||
Interrupted = true;
|
_interrupted = true;
|
||||||
}
|
|
||||||
|
|
||||||
public void StepHandler()
|
|
||||||
{
|
|
||||||
_stepCallback?.Invoke(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RequestDebugStep()
|
|
||||||
{
|
|
||||||
Interlocked.Exchange(ref ShouldStep, 1);
|
|
||||||
RequestInterrupt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnBreak(ulong address, int imm)
|
internal void OnBreak(ulong address, int imm)
|
||||||
{
|
{
|
||||||
if (Optimizations.EnableDebugging)
|
|
||||||
{
|
|
||||||
DebugPc = Pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
_breakCallback?.Invoke(this, address, imm);
|
_breakCallback?.Invoke(this, address, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnSupervisorCall(ulong address, int imm)
|
internal void OnSupervisorCall(ulong address, int imm)
|
||||||
{
|
{
|
||||||
if (Optimizations.EnableDebugging)
|
|
||||||
{
|
|
||||||
DebugPc = Pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
_supervisorCallback?.Invoke(this, address, imm);
|
_supervisorCallback?.Invoke(this, address, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,12 +23,6 @@ namespace ARMeilleure.State
|
|||||||
public int Running;
|
public int Running;
|
||||||
public int CallDepth;
|
public int CallDepth;
|
||||||
public long Tpidr2El0;
|
public long Tpidr2El0;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Precise PC value used for debugging.
|
|
||||||
/// This will only be set when Optimizations.EnableDebugging is true.
|
|
||||||
/// </summary>
|
|
||||||
public ulong DebugPrecisePc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static NativeCtxStorage _dummyStorage = new();
|
private static NativeCtxStorage _dummyStorage = new();
|
||||||
@@ -46,11 +40,6 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
public ulong GetPc()
|
public ulong GetPc()
|
||||||
{
|
{
|
||||||
if (Optimizations.EnableDebugging)
|
|
||||||
{
|
|
||||||
return GetStorage().DebugPrecisePc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: More precise tracking of PC value.
|
// TODO: More precise tracking of PC value.
|
||||||
return GetStorage().DispatchAddress;
|
return GetStorage().DispatchAddress;
|
||||||
}
|
}
|
||||||
@@ -280,11 +269,6 @@ namespace ARMeilleure.State
|
|||||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Running);
|
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Running);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetDebugPrecisePcOffset()
|
|
||||||
{
|
|
||||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.DebugPrecisePc);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int GetCallDepthOffset()
|
public static int GetCallDepthOffset()
|
||||||
{
|
{
|
||||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.CallDepth);
|
return StorageOffset(ref _dummyStorage, ref _dummyStorage.CallDepth);
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ namespace ARMeilleure.Translation
|
|||||||
public bool HighCq { get; }
|
public bool HighCq { get; }
|
||||||
public bool HasPtc { get; }
|
public bool HasPtc { get; }
|
||||||
public Aarch32Mode Mode { get; }
|
public Aarch32Mode Mode { get; }
|
||||||
public bool IsSingleStep { get; }
|
|
||||||
|
|
||||||
private int _ifThenBlockStateIndex = 0;
|
private int _ifThenBlockStateIndex = 0;
|
||||||
private Condition[] _ifThenBlockState = [];
|
private Condition[] _ifThenBlockState = [];
|
||||||
@@ -67,8 +66,7 @@ namespace ARMeilleure.Translation
|
|||||||
ulong entryAddress,
|
ulong entryAddress,
|
||||||
bool highCq,
|
bool highCq,
|
||||||
bool hasPtc,
|
bool hasPtc,
|
||||||
Aarch32Mode mode,
|
Aarch32Mode mode)
|
||||||
bool isSingleStep)
|
|
||||||
{
|
{
|
||||||
Memory = memory;
|
Memory = memory;
|
||||||
CountTable = countTable;
|
CountTable = countTable;
|
||||||
@@ -78,7 +76,6 @@ namespace ARMeilleure.Translation
|
|||||||
HighCq = highCq;
|
HighCq = highCq;
|
||||||
HasPtc = hasPtc;
|
HasPtc = hasPtc;
|
||||||
Mode = mode;
|
Mode = mode;
|
||||||
IsSingleStep = isSingleStep;
|
|
||||||
|
|
||||||
_labels = new Dictionary<ulong, Operand>();
|
_labels = new Dictionary<ulong, Operand>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ using ARMeilleure.CodeGen;
|
|||||||
using ARMeilleure.CodeGen.Unwinding;
|
using ARMeilleure.CodeGen.Unwinding;
|
||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using ARMeilleure.Native;
|
using ARMeilleure.Native;
|
||||||
using Humanizer;
|
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -19,20 +19,49 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
private static readonly int _pageSize = (int)MemoryBlock.GetPageSize();
|
private static readonly int _pageSize = (int)MemoryBlock.GetPageSize();
|
||||||
private static readonly int _pageMask = _pageSize - 1;
|
private static readonly int _pageMask = _pageSize - 1;
|
||||||
|
|
||||||
private const int CodeAlignment = 4; // Bytes.
|
private const int CodeAlignment = 4;
|
||||||
private const int CacheSize = 256 * 1024 * 1024;
|
private const int FullCacheSize = 2047 * 1024 * 1024;
|
||||||
|
private const int ReducedCacheSize = FullCacheSize / 8;
|
||||||
|
|
||||||
|
private const float EvictionTargetPercentage = 0.20f;
|
||||||
|
private const int MaxEntriesToEvictAtOnce = 100;
|
||||||
|
|
||||||
|
// Simple logging configuration
|
||||||
|
private const int LogInterval = 5000; // Log every 5000 allocations
|
||||||
|
|
||||||
|
private static ReservedRegion _jitRegion;
|
||||||
private static JitCacheInvalidation _jitCacheInvalidator;
|
private static JitCacheInvalidation _jitCacheInvalidator;
|
||||||
|
|
||||||
private static List<CacheMemoryAllocator> _cacheAllocators = [];
|
private static CacheMemoryAllocator _cacheAllocator;
|
||||||
|
|
||||||
private static readonly List<CacheEntry> _cacheEntries = [];
|
private static readonly List<CacheEntry> _cacheEntries = [];
|
||||||
|
private static readonly Dictionary<int, EntryUsageStats> _entryUsageStats = [];
|
||||||
|
|
||||||
private static readonly Lock _lock = new();
|
private static readonly Lock _lock = new();
|
||||||
private static bool _initialized;
|
private static bool _initialized;
|
||||||
|
private static int _cacheSize;
|
||||||
|
|
||||||
private static readonly List<ReservedRegion> _jitRegions = [];
|
// Basic statistics
|
||||||
private static int _activeRegionIndex = 0;
|
private static int _totalAllocations = 0;
|
||||||
|
private static int _totalEvictions = 0;
|
||||||
|
|
||||||
|
private class EntryUsageStats
|
||||||
|
{
|
||||||
|
public long LastAccessTime { get; private set; }
|
||||||
|
public int UsageCount { get; private set; }
|
||||||
|
|
||||||
|
public EntryUsageStats()
|
||||||
|
{
|
||||||
|
LastAccessTime = DateTime.UtcNow.Ticks;
|
||||||
|
UsageCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateUsage()
|
||||||
|
{
|
||||||
|
LastAccessTime = DateTime.UtcNow.Ticks;
|
||||||
|
UsageCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||||
@@ -40,48 +69,35 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
|
|
||||||
public static void Initialize(IJitMemoryAllocator allocator)
|
public static void Initialize(IJitMemoryAllocator allocator)
|
||||||
{
|
{
|
||||||
|
if (_initialized)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (_initialized)
|
if (_initialized)
|
||||||
{
|
{
|
||||||
if (OperatingSystem.IsWindows())
|
return;
|
||||||
{
|
|
||||||
JitUnwindWindows.RemoveFunctionTableHandler(
|
|
||||||
_jitRegions[0].Pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < _jitRegions.Count; i++)
|
|
||||||
{
|
|
||||||
_jitRegions[i].Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
_jitRegions.Clear();
|
|
||||||
_cacheAllocators.Clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_initialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_activeRegionIndex = 0;
|
_cacheSize = Optimizations.CacheEviction ? ReducedCacheSize : FullCacheSize;
|
||||||
|
_jitRegion = new ReservedRegion(allocator, (ulong)_cacheSize);
|
||||||
var firstRegion = new ReservedRegion(allocator, CacheSize);
|
|
||||||
_jitRegions.Add(firstRegion);
|
|
||||||
|
|
||||||
CacheMemoryAllocator firstCacheAllocator = new(CacheSize);
|
|
||||||
_cacheAllocators.Add(firstCacheAllocator);
|
|
||||||
|
|
||||||
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
|
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
_jitCacheInvalidator = new JitCacheInvalidation(allocator);
|
_jitCacheInvalidator = new JitCacheInvalidation(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_cacheAllocator = new CacheMemoryAllocator(_cacheSize);
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
JitUnwindWindows.InstallFunctionTableHandler(
|
JitUnwindWindows.InstallFunctionTableHandler(_jitRegion.Pointer, (uint)_cacheSize, _jitRegion.Pointer + Allocate(_pageSize));
|
||||||
firstRegion.Pointer, CacheSize, firstRegion.Pointer + Allocate(_pageSize)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Info?.Print(LogClass.Cpu, $"JIT Cache initialized: Size={_cacheSize / (1024 * 1024)} MB, Eviction={Optimizations.CacheEviction}");
|
||||||
|
_initialized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,10 +108,34 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
Debug.Assert(_initialized);
|
Debug.Assert(_initialized);
|
||||||
|
_totalAllocations++;
|
||||||
|
|
||||||
int funcOffset = Allocate(code.Length);
|
int funcOffset;
|
||||||
ReservedRegion targetRegion = _jitRegions[_activeRegionIndex];
|
|
||||||
nint funcPtr = targetRegion.Pointer + funcOffset;
|
if (Optimizations.CacheEviction)
|
||||||
|
{
|
||||||
|
int codeSize = AlignCodeSize(code.Length);
|
||||||
|
funcOffset = _cacheAllocator.Allocate(codeSize);
|
||||||
|
|
||||||
|
if (funcOffset < 0)
|
||||||
|
{
|
||||||
|
EvictEntries(codeSize);
|
||||||
|
funcOffset = _cacheAllocator.Allocate(codeSize);
|
||||||
|
|
||||||
|
if (funcOffset < 0)
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException("JIT Cache exhausted even after eviction.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_jitRegion.ExpandIfNeeded((ulong)funcOffset + (ulong)codeSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
funcOffset = Allocate(code.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
nint funcPtr = _jitRegion.Pointer + funcOffset;
|
||||||
|
|
||||||
if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||||
{
|
{
|
||||||
@@ -109,9 +149,9 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ReprotectAsWritable(targetRegion, funcOffset, code.Length);
|
ReprotectAsWritable(funcOffset, code.Length);
|
||||||
Marshal.Copy(code, 0, funcPtr, 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)
|
if (OperatingSystem.IsWindows() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||||
{
|
{
|
||||||
@@ -125,6 +165,12 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
|
|
||||||
Add(funcOffset, code.Length, func.UnwindInfo);
|
Add(funcOffset, code.Length, func.UnwindInfo);
|
||||||
|
|
||||||
|
// Simple periodic logging
|
||||||
|
if (_totalAllocations % LogInterval == 0)
|
||||||
|
{
|
||||||
|
LogCacheStatus();
|
||||||
|
}
|
||||||
|
|
||||||
return funcPtr;
|
return funcPtr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -135,74 +181,55 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
{
|
{
|
||||||
Debug.Assert(_initialized);
|
Debug.Assert(_initialized);
|
||||||
|
|
||||||
foreach (var region in _jitRegions)
|
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() ||
|
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
|
||||||
pointer.ToInt64() >= (region.Pointer + CacheSize).ToInt64())
|
_cacheEntries.RemoveAt(entryIndex);
|
||||||
|
|
||||||
|
if (Optimizations.CacheEviction)
|
||||||
{
|
{
|
||||||
continue;
|
_entryUsageStats.Remove(funcOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReprotectAsWritable(ReservedRegion region, int offset, int size)
|
private static void ReprotectAsWritable(int offset, int size)
|
||||||
{
|
{
|
||||||
int endOffs = offset + size;
|
int endOffs = offset + size;
|
||||||
|
|
||||||
int regionStart = offset & ~_pageMask;
|
int regionStart = offset & ~_pageMask;
|
||||||
int regionEnd = (endOffs + _pageMask) & ~_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 endOffs = offset + size;
|
||||||
|
|
||||||
int regionStart = offset & ~_pageMask;
|
int regionStart = offset & ~_pageMask;
|
||||||
int regionEnd = (endOffs + _pageMask) & ~_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)
|
private static int Allocate(int codeSize)
|
||||||
{
|
{
|
||||||
codeSize = AlignCodeSize(codeSize);
|
codeSize = AlignCodeSize(codeSize);
|
||||||
|
|
||||||
int allocOffset = _cacheAllocators[_activeRegionIndex].Allocate(codeSize);
|
int allocOffset = _cacheAllocator.Allocate(codeSize);
|
||||||
|
|
||||||
if (allocOffset >= 0)
|
if (allocOffset < 0)
|
||||||
{
|
{
|
||||||
_jitRegions[_activeRegionIndex].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
|
throw new OutOfMemoryException("JIT Cache exhausted.");
|
||||||
return allocOffset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int exhaustedRegion = _activeRegionIndex;
|
_jitRegion.ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
|
||||||
var newRegion = new ReservedRegion(_jitRegions[0].Allocator, CacheSize);
|
|
||||||
_jitRegions.Add(newRegion);
|
|
||||||
_activeRegionIndex = _jitRegions.Count - 1;
|
|
||||||
|
|
||||||
Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {_activeRegionIndex} ({((long)(_activeRegionIndex + 1) * CacheSize).Bytes()} Total Allocation).");
|
return allocOffset;
|
||||||
|
|
||||||
_cacheAllocators.Add(new CacheMemoryAllocator(CacheSize));
|
|
||||||
|
|
||||||
int allocOffsetNew = _cacheAllocators[_activeRegionIndex].Allocate(codeSize);
|
|
||||||
if (allocOffsetNew < 0)
|
|
||||||
{
|
|
||||||
throw new OutOfMemoryException("Failed to allocate in new Cache Region!");
|
|
||||||
}
|
|
||||||
|
|
||||||
newRegion.ExpandIfNeeded((ulong)allocOffsetNew + (ulong)codeSize);
|
|
||||||
return allocOffsetNew;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int AlignCodeSize(int codeSize)
|
private static int AlignCodeSize(int codeSize)
|
||||||
@@ -222,27 +249,35 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
}
|
}
|
||||||
|
|
||||||
_cacheEntries.Insert(index, entry);
|
_cacheEntries.Insert(index, entry);
|
||||||
|
|
||||||
|
if (Optimizations.CacheEviction)
|
||||||
|
{
|
||||||
|
_entryUsageStats[offset] = new EntryUsageStats();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryFind(int offset, out CacheEntry entry, out int entryIndex)
|
public static bool TryFind(int offset, out CacheEntry entry, out int entryIndex)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
foreach (var region in _jitRegions)
|
int index = _cacheEntries.BinarySearch(new CacheEntry(offset, 0, default));
|
||||||
|
|
||||||
|
if (index < 0)
|
||||||
{
|
{
|
||||||
int index = _cacheEntries.BinarySearch(new CacheEntry(offset, 0, default));
|
index = ~index - 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (index < 0)
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
entry = _cacheEntries[index];
|
||||||
|
|
||||||
|
if (Optimizations.CacheEviction && _entryUsageStats.TryGetValue(offset, out EntryUsageStats stats))
|
||||||
{
|
{
|
||||||
index = ~index - 1;
|
stats.UpdateUsage();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index >= 0)
|
entryIndex = index;
|
||||||
{
|
return true;
|
||||||
entry = _cacheEntries[index];
|
|
||||||
entryIndex = index;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,5 +285,83 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
entryIndex = 0;
|
entryIndex = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EvictEntries(int requiredSize)
|
||||||
|
{
|
||||||
|
if (!Optimizations.CacheEviction)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
int targetSpace = Math.Max(requiredSize, (int)(_cacheSize * EvictionTargetPercentage));
|
||||||
|
int freedSpace = 0;
|
||||||
|
int evictedCount = 0;
|
||||||
|
|
||||||
|
var entriesWithStats = _cacheEntries
|
||||||
|
.Where(e => _entryUsageStats.ContainsKey(e.Offset))
|
||||||
|
.Select(e => new {
|
||||||
|
Entry = e,
|
||||||
|
Stats = _entryUsageStats[e.Offset],
|
||||||
|
Score = CalculateEvictionScore(_entryUsageStats[e.Offset])
|
||||||
|
})
|
||||||
|
.OrderBy(x => x.Score)
|
||||||
|
.Take(MaxEntriesToEvictAtOnce)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var item in entriesWithStats)
|
||||||
|
{
|
||||||
|
int entrySize = AlignCodeSize(item.Entry.Size);
|
||||||
|
|
||||||
|
int entryIndex = _cacheEntries.BinarySearch(item.Entry);
|
||||||
|
if (entryIndex >= 0)
|
||||||
|
{
|
||||||
|
_cacheAllocator.Free(item.Entry.Offset, entrySize);
|
||||||
|
_cacheEntries.RemoveAt(entryIndex);
|
||||||
|
_entryUsageStats.Remove(item.Entry.Offset);
|
||||||
|
|
||||||
|
freedSpace += entrySize;
|
||||||
|
evictedCount++;
|
||||||
|
|
||||||
|
if (freedSpace >= targetSpace)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_totalEvictions += evictedCount;
|
||||||
|
|
||||||
|
Logger.Info?.Print(LogClass.Cpu, $"JIT Cache: Evicted {evictedCount} entries, freed {freedSpace / (1024 * 1024.0):F2} MB");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double CalculateEvictionScore(EntryUsageStats stats)
|
||||||
|
{
|
||||||
|
long currentTime = DateTime.UtcNow.Ticks;
|
||||||
|
long ageInTicks = currentTime - stats.LastAccessTime;
|
||||||
|
|
||||||
|
double ageInSeconds = ageInTicks / 10_000_000.0;
|
||||||
|
|
||||||
|
const double usageWeight = 1.0;
|
||||||
|
const double ageWeight = 2.0;
|
||||||
|
|
||||||
|
double usageScore = Math.Log10(stats.UsageCount + 1) * usageWeight;
|
||||||
|
double ageScore = (10.0 / (ageInSeconds + 1.0)) * ageWeight;
|
||||||
|
|
||||||
|
return usageScore + ageScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LogCacheStatus()
|
||||||
|
{
|
||||||
|
int estimatedUsedSize = _cacheEntries.Sum(e => AlignCodeSize(e.Size));
|
||||||
|
double usagePercentage = 100.0 * estimatedUsedSize / _cacheSize;
|
||||||
|
|
||||||
|
Logger.Info?.Print(LogClass.Cpu,
|
||||||
|
$"JIT Cache status: entries={_cacheEntries.Count}, " +
|
||||||
|
$"est. used={estimatedUsedSize / (1024 * 1024.0):F2} MB ({usagePercentage:F1}%), " +
|
||||||
|
$"evictions={_totalEvictions}, allocations={_totalAllocations}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,13 +122,13 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
return null; // Not found.
|
return null; // Not found.
|
||||||
}
|
}
|
||||||
|
|
||||||
var unwindInfo = funcEntry.UnwindInfo;
|
CodeGen.Unwinding.UnwindInfo unwindInfo = funcEntry.UnwindInfo;
|
||||||
|
|
||||||
int codeIndex = 0;
|
int codeIndex = 0;
|
||||||
|
|
||||||
for (int index = unwindInfo.PushEntries.Length - 1; index >= 0; index--)
|
for (int index = unwindInfo.PushEntries.Length - 1; index >= 0; index--)
|
||||||
{
|
{
|
||||||
var entry = unwindInfo.PushEntries[index];
|
UnwindPushEntry entry = unwindInfo.PushEntries[index];
|
||||||
|
|
||||||
switch (entry.PseudoOp)
|
switch (entry.PseudoOp)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
RemoveUnreachableBlocks(Blocks);
|
RemoveUnreachableBlocks(Blocks);
|
||||||
|
|
||||||
var visited = new HashSet<BasicBlock>();
|
HashSet<BasicBlock> visited = new();
|
||||||
var blockStack = new Stack<BasicBlock>();
|
Stack<BasicBlock> blockStack = new();
|
||||||
|
|
||||||
Array.Resize(ref _postOrderBlocks, Blocks.Count);
|
Array.Resize(ref _postOrderBlocks, Blocks.Count);
|
||||||
Array.Resize(ref _postOrderMap, Blocks.Count);
|
Array.Resize(ref _postOrderMap, Blocks.Count);
|
||||||
@@ -88,8 +88,8 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
private void RemoveUnreachableBlocks(IntrusiveList<BasicBlock> blocks)
|
private void RemoveUnreachableBlocks(IntrusiveList<BasicBlock> blocks)
|
||||||
{
|
{
|
||||||
var visited = new HashSet<BasicBlock>();
|
HashSet<BasicBlock> visited = new();
|
||||||
var workQueue = new Queue<BasicBlock>();
|
Queue<BasicBlock> workQueue = new();
|
||||||
|
|
||||||
visited.Add(Entry);
|
visited.Add(Entry);
|
||||||
workQueue.Enqueue(Entry);
|
workQueue.Enqueue(Entry);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.Translation
|
namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
class DelegateInfo
|
public class DelegateInfo
|
||||||
{
|
{
|
||||||
public nint FuncPtr { get; }
|
public nint FuncPtr { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,358 @@ using ARMeilleure.Instructions;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
#if ANDROID
|
||||||
|
using ARMeilleure.State;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ARMeilleure.Translation
|
namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
static class Delegates
|
static class Delegates
|
||||||
{
|
{
|
||||||
|
#if ANDROID
|
||||||
|
// MathHelper delegates
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double MathHelperAbsDelegate(double value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double MathHelperCeilingDelegate(double value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double MathHelperFloorDelegate(double value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double MathHelperRoundDelegate(double value, int mode);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double MathHelperTruncateDelegate(double value);
|
||||||
|
|
||||||
|
// MathHelperF delegates
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float MathHelperFAbsDelegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float MathHelperFCeilingDelegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float MathHelperFFloorDelegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float MathHelperFRoundDelegate(float value, int mode);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float MathHelperFTruncateDelegate(float value);
|
||||||
|
|
||||||
|
// NativeInterface delegates
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceBreakDelegate(ulong address, int imm);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate byte NativeInterfaceCheckSynchronizationDelegate();
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceEnqueueForRejitDelegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong NativeInterfaceGetCntfrqEl0Delegate();
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong NativeInterfaceGetCntpctEl0Delegate();
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong NativeInterfaceGetCntvctEl0Delegate();
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong NativeInterfaceGetCtrEl0Delegate();
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong NativeInterfaceGetDczidEl0Delegate();
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong NativeInterfaceGetFunctionAddressDelegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceInvalidateCacheLineDelegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate byte NativeInterfaceReadByteDelegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ushort NativeInterfaceReadUInt16Delegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint NativeInterfaceReadUInt32Delegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong NativeInterfaceReadUInt64Delegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 NativeInterfaceReadVector128Delegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceSignalMemoryTrackingDelegate(ulong address, ulong size, byte write);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceSupervisorCallDelegate(ulong address, int imm);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceThrowInvalidMemoryAccessDelegate(ulong address);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceUndefinedDelegate(ulong address, int opCode);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceWriteByteDelegate(ulong address, byte value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceWriteUInt16Delegate(ulong address, ushort value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceWriteUInt32Delegate(ulong address, uint value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceWriteUInt64Delegate(ulong address, ulong value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate void NativeInterfaceWriteVector128Delegate(ulong address, V128 value);
|
||||||
|
|
||||||
|
// SoftFallback delegates
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong SoftFallbackCountLeadingSignsDelegate(ulong value, int size);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong SoftFallbackCountLeadingZerosDelegate(ulong value, int size);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32bDelegate(uint crc, byte val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32cbDelegate(uint crc, byte val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32chDelegate(uint crc, ushort val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32cwDelegate(uint crc, uint val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32cxDelegate(uint crc, ulong val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32hDelegate(uint crc, ushort val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32wDelegate(uint crc, uint val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackCrc32xDelegate(uint crc, ulong val);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackDecryptDelegate(V128 value, V128 roundKey);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackEncryptDelegate(V128 value, V128 roundKey);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackFixedRotateDelegate(uint hash_e);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackHashChooseDelegate(V128 hash_abcd, uint hash_e, V128 wk);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackHashLowerDelegate(V128 hash_abcd, V128 hash_efgh, V128 wk);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackHashMajorityDelegate(V128 hash_abcd, uint hash_e, V128 wk);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackHashParityDelegate(V128 hash_abcd, uint hash_e, V128 wk);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackHashUpperDelegate(V128 hash_abcd, V128 hash_efgh, V128 wk);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackInverseMixColumnsDelegate(V128 value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackMixColumnsDelegate(V128 value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackPolynomialMult64_128Delegate(ulong op1, ulong op2);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate int SoftFallbackSatF32ToS32Delegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate long SoftFallbackSatF32ToS64Delegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackSatF32ToU32Delegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong SoftFallbackSatF32ToU64Delegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate int SoftFallbackSatF64ToS32Delegate(double value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate long SoftFallbackSatF64ToS64Delegate(double value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate uint SoftFallbackSatF64ToU32Delegate(double value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong SoftFallbackSatF64ToU64Delegate(double value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackSha1SchedulePart1Delegate(V128 w0_3, V128 w4_7, V128 w8_11);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackSha1SchedulePart2Delegate(V128 tw0_3, V128 w12_15);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackSha256SchedulePart1Delegate(V128 w0_3, V128 w4_7);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackSha256SchedulePart2Delegate(V128 w0_3, V128 w8_11, V128 w12_15);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate long SoftFallbackSignedShrImm64Delegate(long value, long roundConst, int shift);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbl1Delegate(V128 vector, int bytes, V128 table);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbl2Delegate(V128 vector, int bytes, V128 table0, V128 table1);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbl3Delegate(V128 vector, int bytes, V128 table0, V128 table1, V128 table2);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbl4Delegate(V128 vector, int bytes, V128 table0, V128 table1, V128 table2, V128 table3);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbx1Delegate(V128 dest, V128 vector, int bytes, V128 table);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbx2Delegate(V128 dest, V128 vector, int bytes, V128 table0, V128 table1);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbx3Delegate(V128 dest, V128 vector, int bytes, V128 table0, V128 table1, V128 table2);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate V128 SoftFallbackTbx4Delegate(V128 dest, V128 vector, int bytes, V128 table0, V128 table1, V128 table2, V128 table3);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ulong SoftFallbackUnsignedShrImm64Delegate(ulong value, long roundConst, int shift);
|
||||||
|
|
||||||
|
// SoftFloat delegates
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat16_32FPConvertDelegate(ushort value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat16_64FPConvertDelegate(ushort value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPAddDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPAddFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate int SoftFloat32FPCompareDelegate(float a, float b, byte signalNaNs);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareEQDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareEQFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareGEDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareGEFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareGTDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareGTFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareLEDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareLEFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareLTDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPCompareLTFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPDivDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMaxDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMaxFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMaxNumDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMaxNumFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMinDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMinFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMinNumDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMinNumFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMulDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMulFpscrDelegate(float a, float b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMulAddDelegate(float a, float b, float c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMulAddFpscrDelegate(float a, float b, float c, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMulSubDelegate(float a, float b, float c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMulSubFpscrDelegate(float a, float b, float c, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPMulXDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPNegMulAddDelegate(float a, float b, float c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPNegMulSubDelegate(float a, float b, float c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRecipEstimateDelegate(float a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRecipEstimateFpscrDelegate(float a, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRecipStepDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRecipStepFusedDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRecpXDelegate(float a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRSqrtEstimateDelegate(float a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRSqrtEstimateFpscrDelegate(float a, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRSqrtStepDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPRSqrtStepFusedDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPSqrtDelegate(float a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate float SoftFloat32FPSubDelegate(float a, float b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ushort SoftFloat32_16FPConvertDelegate(float value);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPAddDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPAddFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate int SoftFloat64FPCompareDelegate(double a, double b, byte signalNaNs);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareEQDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareEQFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareGEDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareGEFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareGTDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareGTFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareLEDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareLEFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareLTDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPCompareLTFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPDivDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMaxDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMaxFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMaxNumDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMaxNumFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMinDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMinFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMinNumDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMinNumFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMulDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMulFpscrDelegate(double a, double b, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMulAddDelegate(double a, double b, double c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMulAddFpscrDelegate(double a, double b, double c, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMulSubDelegate(double a, double b, double c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMulSubFpscrDelegate(double a, double b, double c, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPMulXDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPNegMulAddDelegate(double a, double b, double c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPNegMulSubDelegate(double a, double b, double c);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRecipEstimateDelegate(double a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRecipEstimateFpscrDelegate(double a, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRecipStepDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRecipStepFusedDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRecpXDelegate(double a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRSqrtEstimateDelegate(double a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRSqrtEstimateFpscrDelegate(double a, byte standardFpscr);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRSqrtStepDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPRSqrtStepFusedDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPSqrtDelegate(double a);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate double SoftFloat64FPSubDelegate(double a, double b);
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
public delegate ushort SoftFloat64_16FPConvertDelegate(double value);
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, Delegate> _androidDelegates;
|
||||||
|
#endif
|
||||||
public static bool TryGetDelegateFuncPtrByIndex(int index, out nint funcPtr)
|
public static bool TryGetDelegateFuncPtrByIndex(int index, out nint funcPtr)
|
||||||
{
|
{
|
||||||
if (index >= 0 && index < _delegates.Count)
|
if (index >= 0 && index < _delegates.Count)
|
||||||
@@ -53,7 +400,32 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
string key = GetKey(method);
|
string key = GetKey(method);
|
||||||
|
|
||||||
_delegates.Add(key, new DelegateInfo(method.MethodHandle.GetFunctionPointer())); // ArgumentException (key).
|
#if ANDROID
|
||||||
|
if (_androidDelegates.TryGetValue(key, out Delegate del))
|
||||||
|
{
|
||||||
|
nint funcPtr = Marshal.GetFunctionPointerForDelegate(del);
|
||||||
|
_delegates.Add(key, new DelegateInfo(funcPtr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_delegates.Add(key, new DelegateInfo(method.MethodHandle.GetFunctionPointer()));
|
||||||
|
}
|
||||||
|
catch (NotSupportedException) when (IsRunningOnAndroid())
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException($"Cannot obtain function pointer {key}: it must be registered.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsRunningOnAndroid()
|
||||||
|
{
|
||||||
|
#if ANDROID
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetKey(MethodInfo info)
|
private static string GetKey(MethodInfo info)
|
||||||
@@ -67,6 +439,190 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
_delegates = new SortedList<string, DelegateInfo>();
|
_delegates = new SortedList<string, DelegateInfo>();
|
||||||
|
|
||||||
|
#if ANDROID
|
||||||
|
_androidDelegates = new Dictionary<string, Delegate>
|
||||||
|
{
|
||||||
|
// MathHelper delegates
|
||||||
|
{ "MathHelper.Abs", new MathHelperAbsDelegate(Math.Abs) },
|
||||||
|
{ "MathHelper.Ceiling", new MathHelperCeilingDelegate(Math.Ceiling) },
|
||||||
|
{ "MathHelper.Floor", new MathHelperFloorDelegate(Math.Floor) },
|
||||||
|
{ "MathHelper.Round", new MathHelperRoundDelegate((value, mode) => Math.Round(value, (MidpointRounding)mode)) },
|
||||||
|
{ "MathHelper.Truncate", new MathHelperTruncateDelegate(Math.Truncate) },
|
||||||
|
|
||||||
|
// MathHelperF delegates
|
||||||
|
{ "MathHelperF.Abs", new MathHelperFAbsDelegate(MathF.Abs) },
|
||||||
|
{ "MathHelperF.Ceiling", new MathHelperFCeilingDelegate(MathF.Ceiling) },
|
||||||
|
{ "MathHelperF.Floor", new MathHelperFFloorDelegate(MathF.Floor) },
|
||||||
|
{ "MathHelperF.Round", new MathHelperFRoundDelegate((value, mode) => MathF.Round(value, (MidpointRounding)mode)) },
|
||||||
|
{ "MathHelperF.Truncate", new MathHelperFTruncateDelegate(MathF.Truncate) },
|
||||||
|
|
||||||
|
// NativeInterface delegates
|
||||||
|
{ "NativeInterface.Break", new NativeInterfaceBreakDelegate(NativeInterface.Break) },
|
||||||
|
{ "NativeInterface.CheckSynchronization", new NativeInterfaceCheckSynchronizationDelegate(NativeInterface.CheckSynchronization) },
|
||||||
|
{ "NativeInterface.EnqueueForRejit", new NativeInterfaceEnqueueForRejitDelegate(NativeInterface.EnqueueForRejit) },
|
||||||
|
{ "NativeInterface.GetCntfrqEl0", new NativeInterfaceGetCntfrqEl0Delegate(NativeInterface.GetCntfrqEl0) },
|
||||||
|
{ "NativeInterface.GetCntpctEl0", new NativeInterfaceGetCntpctEl0Delegate(NativeInterface.GetCntpctEl0) },
|
||||||
|
{ "NativeInterface.GetCntvctEl0", new NativeInterfaceGetCntvctEl0Delegate(NativeInterface.GetCntvctEl0) },
|
||||||
|
{ "NativeInterface.GetCtrEl0", new NativeInterfaceGetCtrEl0Delegate(NativeInterface.GetCtrEl0) },
|
||||||
|
{ "NativeInterface.GetDczidEl0", new NativeInterfaceGetDczidEl0Delegate(NativeInterface.GetDczidEl0) },
|
||||||
|
{ "NativeInterface.GetFunctionAddress", new NativeInterfaceGetFunctionAddressDelegate(NativeInterface.GetFunctionAddress) },
|
||||||
|
{ "NativeInterface.InvalidateCacheLine", new NativeInterfaceInvalidateCacheLineDelegate(NativeInterface.InvalidateCacheLine) },
|
||||||
|
{ "NativeInterface.ReadByte", new NativeInterfaceReadByteDelegate(NativeInterface.ReadByte) },
|
||||||
|
{ "NativeInterface.ReadUInt16", new NativeInterfaceReadUInt16Delegate(NativeInterface.ReadUInt16) },
|
||||||
|
{ "NativeInterface.ReadUInt32", new NativeInterfaceReadUInt32Delegate(NativeInterface.ReadUInt32) },
|
||||||
|
{ "NativeInterface.ReadUInt64", new NativeInterfaceReadUInt64Delegate(NativeInterface.ReadUInt64) },
|
||||||
|
{ "NativeInterface.ReadVector128", new NativeInterfaceReadVector128Delegate(NativeInterface.ReadVector128) },
|
||||||
|
{ "NativeInterface.SignalMemoryTracking", new NativeInterfaceSignalMemoryTrackingDelegate(NativeInterface.SignalMemoryTracking) },
|
||||||
|
{ "NativeInterface.SupervisorCall", new NativeInterfaceSupervisorCallDelegate(NativeInterface.SupervisorCall) },
|
||||||
|
{ "NativeInterface.ThrowInvalidMemoryAccess", new NativeInterfaceThrowInvalidMemoryAccessDelegate(NativeInterface.ThrowInvalidMemoryAccess) },
|
||||||
|
{ "NativeInterface.Undefined", new NativeInterfaceUndefinedDelegate(NativeInterface.Undefined) },
|
||||||
|
{ "NativeInterface.WriteByte", new NativeInterfaceWriteByteDelegate(NativeInterface.WriteByte) },
|
||||||
|
{ "NativeInterface.WriteUInt16", new NativeInterfaceWriteUInt16Delegate(NativeInterface.WriteUInt16) },
|
||||||
|
{ "NativeInterface.WriteUInt32", new NativeInterfaceWriteUInt32Delegate(NativeInterface.WriteUInt32) },
|
||||||
|
{ "NativeInterface.WriteUInt64", new NativeInterfaceWriteUInt64Delegate(NativeInterface.WriteUInt64) },
|
||||||
|
{ "NativeInterface.WriteVector128", new NativeInterfaceWriteVector128Delegate(NativeInterface.WriteVector128) },
|
||||||
|
|
||||||
|
// SoftFallback delegates
|
||||||
|
{ "SoftFallback.CountLeadingSigns", new SoftFallbackCountLeadingSignsDelegate(SoftFallback.CountLeadingSigns) },
|
||||||
|
{ "SoftFallback.CountLeadingZeros", new SoftFallbackCountLeadingZerosDelegate(SoftFallback.CountLeadingZeros) },
|
||||||
|
{ "SoftFallback.Crc32b", new SoftFallbackCrc32bDelegate(SoftFallback.Crc32b) },
|
||||||
|
{ "SoftFallback.Crc32cb", new SoftFallbackCrc32cbDelegate(SoftFallback.Crc32cb) },
|
||||||
|
{ "SoftFallback.Crc32ch", new SoftFallbackCrc32chDelegate(SoftFallback.Crc32ch) },
|
||||||
|
{ "SoftFallback.Crc32cw", new SoftFallbackCrc32cwDelegate(SoftFallback.Crc32cw) },
|
||||||
|
{ "SoftFallback.Crc32cx", new SoftFallbackCrc32cxDelegate(SoftFallback.Crc32cx) },
|
||||||
|
{ "SoftFallback.Crc32h", new SoftFallbackCrc32hDelegate(SoftFallback.Crc32h) },
|
||||||
|
{ "SoftFallback.Crc32w", new SoftFallbackCrc32wDelegate(SoftFallback.Crc32w) },
|
||||||
|
{ "SoftFallback.Crc32x", new SoftFallbackCrc32xDelegate(SoftFallback.Crc32x) },
|
||||||
|
{ "SoftFallback.Decrypt", new SoftFallbackDecryptDelegate(SoftFallback.Decrypt) },
|
||||||
|
{ "SoftFallback.Encrypt", new SoftFallbackEncryptDelegate(SoftFallback.Encrypt) },
|
||||||
|
{ "SoftFallback.FixedRotate", new SoftFallbackFixedRotateDelegate(SoftFallback.FixedRotate) },
|
||||||
|
{ "SoftFallback.HashChoose", new SoftFallbackHashChooseDelegate(SoftFallback.HashChoose) },
|
||||||
|
{ "SoftFallback.HashLower", new SoftFallbackHashLowerDelegate(SoftFallback.HashLower) },
|
||||||
|
{ "SoftFallback.HashMajority", new SoftFallbackHashMajorityDelegate(SoftFallback.HashMajority) },
|
||||||
|
{ "SoftFallback.HashParity", new SoftFallbackHashParityDelegate(SoftFallback.HashParity) },
|
||||||
|
{ "SoftFallback.HashUpper", new SoftFallbackHashUpperDelegate(SoftFallback.HashUpper) },
|
||||||
|
{ "SoftFallback.InverseMixColumns", new SoftFallbackInverseMixColumnsDelegate(SoftFallback.InverseMixColumns) },
|
||||||
|
{ "SoftFallback.MixColumns", new SoftFallbackMixColumnsDelegate(SoftFallback.MixColumns) },
|
||||||
|
{ "SoftFallback.PolynomialMult64_128", new SoftFallbackPolynomialMult64_128Delegate(SoftFallback.PolynomialMult64_128) },
|
||||||
|
{ "SoftFallback.SatF32ToS32", new SoftFallbackSatF32ToS32Delegate(SoftFallback.SatF32ToS32) },
|
||||||
|
{ "SoftFallback.SatF32ToS64", new SoftFallbackSatF32ToS64Delegate(SoftFallback.SatF32ToS64) },
|
||||||
|
{ "SoftFallback.SatF32ToU32", new SoftFallbackSatF32ToU32Delegate(SoftFallback.SatF32ToU32) },
|
||||||
|
{ "SoftFallback.SatF32ToU64", new SoftFallbackSatF32ToU64Delegate(SoftFallback.SatF32ToU64) },
|
||||||
|
{ "SoftFallback.SatF64ToS32", new SoftFallbackSatF64ToS32Delegate(SoftFallback.SatF64ToS32) },
|
||||||
|
{ "SoftFallback.SatF64ToS64", new SoftFallbackSatF64ToS64Delegate(SoftFallback.SatF64ToS64) },
|
||||||
|
{ "SoftFallback.SatF64ToU32", new SoftFallbackSatF64ToU32Delegate(SoftFallback.SatF64ToU32) },
|
||||||
|
{ "SoftFallback.SatF64ToU64", new SoftFallbackSatF64ToU64Delegate(SoftFallback.SatF64ToU64) },
|
||||||
|
{ "SoftFallback.Sha1SchedulePart1", new SoftFallbackSha1SchedulePart1Delegate(SoftFallback.Sha1SchedulePart1) },
|
||||||
|
{ "SoftFallback.Sha1SchedulePart2", new SoftFallbackSha1SchedulePart2Delegate(SoftFallback.Sha1SchedulePart2) },
|
||||||
|
{ "SoftFallback.Sha256SchedulePart1", new SoftFallbackSha256SchedulePart1Delegate(SoftFallback.Sha256SchedulePart1) },
|
||||||
|
{ "SoftFallback.Sha256SchedulePart2", new SoftFallbackSha256SchedulePart2Delegate(SoftFallback.Sha256SchedulePart2) },
|
||||||
|
{ "SoftFallback.SignedShrImm64", new SoftFallbackSignedShrImm64Delegate(SoftFallback.SignedShrImm64) },
|
||||||
|
{ "SoftFallback.Tbl1", new SoftFallbackTbl1Delegate(SoftFallback.Tbl1) },
|
||||||
|
{ "SoftFallback.Tbl2", new SoftFallbackTbl2Delegate(SoftFallback.Tbl2) },
|
||||||
|
{ "SoftFallback.Tbl3", new SoftFallbackTbl3Delegate(SoftFallback.Tbl3) },
|
||||||
|
{ "SoftFallback.Tbl4", new SoftFallbackTbl4Delegate(SoftFallback.Tbl4) },
|
||||||
|
{ "SoftFallback.Tbx1", new SoftFallbackTbx1Delegate(SoftFallback.Tbx1) },
|
||||||
|
{ "SoftFallback.Tbx2", new SoftFallbackTbx2Delegate(SoftFallback.Tbx2) },
|
||||||
|
{ "SoftFallback.Tbx3", new SoftFallbackTbx3Delegate(SoftFallback.Tbx3) },
|
||||||
|
{ "SoftFallback.Tbx4", new SoftFallbackTbx4Delegate(SoftFallback.Tbx4) },
|
||||||
|
{ "SoftFallback.UnsignedShrImm64", new SoftFallbackUnsignedShrImm64Delegate(SoftFallback.UnsignedShrImm64) },
|
||||||
|
|
||||||
|
// SoftFloat delegates
|
||||||
|
{ "SoftFloat16_32.FPConvert", new SoftFloat16_32FPConvertDelegate(SoftFloat16_32.FPConvert) },
|
||||||
|
{ "SoftFloat16_64.FPConvert", new SoftFloat16_64FPConvertDelegate(SoftFloat16_64.FPConvert) },
|
||||||
|
|
||||||
|
{ "SoftFloat32.FPAdd", new SoftFloat32FPAddDelegate(SoftFloat32.FPAdd) },
|
||||||
|
{ "SoftFloat32.FPAddFpscr", new SoftFloat32FPAddFpscrDelegate(SoftFloat32.FPAddFpscr) },
|
||||||
|
{ "SoftFloat32.FPCompare", new SoftFloat32FPCompareDelegate(SoftFloat32.FPCompare) },
|
||||||
|
{ "SoftFloat32.FPCompareEQ", new SoftFloat32FPCompareEQDelegate(SoftFloat32.FPCompareEQ) },
|
||||||
|
{ "SoftFloat32.FPCompareEQFpscr", new SoftFloat32FPCompareEQFpscrDelegate(SoftFloat32.FPCompareEQFpscr) },
|
||||||
|
{ "SoftFloat32.FPCompareGE", new SoftFloat32FPCompareGEDelegate(SoftFloat32.FPCompareGE) },
|
||||||
|
{ "SoftFloat32.FPCompareGEFpscr", new SoftFloat32FPCompareGEFpscrDelegate(SoftFloat32.FPCompareGEFpscr) },
|
||||||
|
{ "SoftFloat32.FPCompareGT", new SoftFloat32FPCompareGTDelegate(SoftFloat32.FPCompareGT) },
|
||||||
|
{ "SoftFloat32.FPCompareGTFpscr", new SoftFloat32FPCompareGTFpscrDelegate(SoftFloat32.FPCompareGTFpscr) },
|
||||||
|
{ "SoftFloat32.FPCompareLE", new SoftFloat32FPCompareLEDelegate(SoftFloat32.FPCompareLE) },
|
||||||
|
{ "SoftFloat32.FPCompareLEFpscr", new SoftFloat32FPCompareLEFpscrDelegate(SoftFloat32.FPCompareLEFpscr) },
|
||||||
|
{ "SoftFloat32.FPCompareLT", new SoftFloat32FPCompareLTDelegate(SoftFloat32.FPCompareLT) },
|
||||||
|
{ "SoftFloat32.FPCompareLTFpscr", new SoftFloat32FPCompareLTFpscrDelegate(SoftFloat32.FPCompareLTFpscr) },
|
||||||
|
{ "SoftFloat32.FPDiv", new SoftFloat32FPDivDelegate(SoftFloat32.FPDiv) },
|
||||||
|
{ "SoftFloat32.FPMax", new SoftFloat32FPMaxDelegate(SoftFloat32.FPMax) },
|
||||||
|
{ "SoftFloat32.FPMaxFpscr", new SoftFloat32FPMaxFpscrDelegate(SoftFloat32.FPMaxFpscr) },
|
||||||
|
{ "SoftFloat32.FPMaxNum", new SoftFloat32FPMaxNumDelegate(SoftFloat32.FPMaxNum) },
|
||||||
|
{ "SoftFloat32.FPMaxNumFpscr", new SoftFloat32FPMaxNumFpscrDelegate(SoftFloat32.FPMaxNumFpscr) },
|
||||||
|
{ "SoftFloat32.FPMin", new SoftFloat32FPMinDelegate(SoftFloat32.FPMin) },
|
||||||
|
{ "SoftFloat32.FPMinFpscr", new SoftFloat32FPMinFpscrDelegate(SoftFloat32.FPMinFpscr) },
|
||||||
|
{ "SoftFloat32.FPMinNum", new SoftFloat32FPMinNumDelegate(SoftFloat32.FPMinNum) },
|
||||||
|
{ "SoftFloat32.FPMinNumFpscr", new SoftFloat32FPMinNumFpscrDelegate(SoftFloat32.FPMinNumFpscr) },
|
||||||
|
{ "SoftFloat32.FPMul", new SoftFloat32FPMulDelegate(SoftFloat32.FPMul) },
|
||||||
|
{ "SoftFloat32.FPMulFpscr", new SoftFloat32FPMulFpscrDelegate(SoftFloat32.FPMulFpscr) },
|
||||||
|
{ "SoftFloat32.FPMulAdd", new SoftFloat32FPMulAddDelegate(SoftFloat32.FPMulAdd) },
|
||||||
|
{ "SoftFloat32.FPMulAddFpscr", new SoftFloat32FPMulAddFpscrDelegate(SoftFloat32.FPMulAddFpscr) },
|
||||||
|
{ "SoftFloat32.FPMulSub", new SoftFloat32FPMulSubDelegate(SoftFloat32.FPMulSub) },
|
||||||
|
{ "SoftFloat32.FPMulSubFpscr", new SoftFloat32FPMulSubFpscrDelegate(SoftFloat32.FPMulSubFpscr) },
|
||||||
|
{ "SoftFloat32.FPMulX", new SoftFloat32FPMulXDelegate(SoftFloat32.FPMulX) },
|
||||||
|
{ "SoftFloat32.FPNegMulAdd", new SoftFloat32FPNegMulAddDelegate(SoftFloat32.FPNegMulAdd) },
|
||||||
|
{ "SoftFloat32.FPNegMulSub", new SoftFloat32FPNegMulSubDelegate(SoftFloat32.FPNegMulSub) },
|
||||||
|
{ "SoftFloat32.FPRecipEstimate", new SoftFloat32FPRecipEstimateDelegate(SoftFloat32.FPRecipEstimate) },
|
||||||
|
{ "SoftFloat32.FPRecipEstimateFpscr", new SoftFloat32FPRecipEstimateFpscrDelegate(SoftFloat32.FPRecipEstimateFpscr) },
|
||||||
|
{ "SoftFloat32.FPRecipStep", new SoftFloat32FPRecipStepDelegate(SoftFloat32.FPRecipStep) },
|
||||||
|
{ "SoftFloat32.FPRecipStepFused", new SoftFloat32FPRecipStepFusedDelegate(SoftFloat32.FPRecipStepFused) },
|
||||||
|
{ "SoftFloat32.FPRecpX", new SoftFloat32FPRecpXDelegate(SoftFloat32.FPRecpX) },
|
||||||
|
{ "SoftFloat32.FPRSqrtEstimate", new SoftFloat32FPRSqrtEstimateDelegate(SoftFloat32.FPRSqrtEstimate) },
|
||||||
|
{ "SoftFloat32.FPRSqrtEstimateFpscr", new SoftFloat32FPRSqrtEstimateFpscrDelegate(SoftFloat32.FPRSqrtEstimateFpscr) },
|
||||||
|
{ "SoftFloat32.FPRSqrtStep", new SoftFloat32FPRSqrtStepDelegate(SoftFloat32.FPRSqrtStep) },
|
||||||
|
{ "SoftFloat32.FPRSqrtStepFused", new SoftFloat32FPRSqrtStepFusedDelegate(SoftFloat32.FPRSqrtStepFused) },
|
||||||
|
{ "SoftFloat32.FPSqrt", new SoftFloat32FPSqrtDelegate(SoftFloat32.FPSqrt) },
|
||||||
|
{ "SoftFloat32.FPSub", new SoftFloat32FPSubDelegate(SoftFloat32.FPSub) },
|
||||||
|
|
||||||
|
{ "SoftFloat32_16.FPConvert", new SoftFloat32_16FPConvertDelegate(SoftFloat32_16.FPConvert) },
|
||||||
|
|
||||||
|
{ "SoftFloat64.FPAdd", new SoftFloat64FPAddDelegate(SoftFloat64.FPAdd) },
|
||||||
|
{ "SoftFloat64.FPAddFpscr", new SoftFloat64FPAddFpscrDelegate(SoftFloat64.FPAddFpscr) },
|
||||||
|
{ "SoftFloat64.FPCompare", new SoftFloat64FPCompareDelegate(SoftFloat64.FPCompare) },
|
||||||
|
{ "SoftFloat64.FPCompareEQ", new SoftFloat64FPCompareEQDelegate(SoftFloat64.FPCompareEQ) },
|
||||||
|
{ "SoftFloat64.FPCompareEQFpscr", new SoftFloat64FPCompareEQFpscrDelegate(SoftFloat64.FPCompareEQFpscr) },
|
||||||
|
{ "SoftFloat64.FPCompareGE", new SoftFloat64FPCompareGEDelegate(SoftFloat64.FPCompareGE) },
|
||||||
|
{ "SoftFloat64.FPCompareGEFpscr", new SoftFloat64FPCompareGEFpscrDelegate(SoftFloat64.FPCompareGEFpscr) },
|
||||||
|
{ "SoftFloat64.FPCompareGT", new SoftFloat64FPCompareGTDelegate(SoftFloat64.FPCompareGT) },
|
||||||
|
{ "SoftFloat64.FPCompareGTFpscr", new SoftFloat64FPCompareGTFpscrDelegate(SoftFloat64.FPCompareGTFpscr) },
|
||||||
|
{ "SoftFloat64.FPCompareLE", new SoftFloat64FPCompareLEDelegate(SoftFloat64.FPCompareLE) },
|
||||||
|
{ "SoftFloat64.FPCompareLEFpscr", new SoftFloat64FPCompareLEFpscrDelegate(SoftFloat64.FPCompareLEFpscr) },
|
||||||
|
{ "SoftFloat64.FPCompareLT", new SoftFloat64FPCompareLTDelegate(SoftFloat64.FPCompareLT) },
|
||||||
|
{ "SoftFloat64.FPCompareLTFpscr", new SoftFloat64FPCompareLTFpscrDelegate(SoftFloat64.FPCompareLTFpscr) },
|
||||||
|
{ "SoftFloat64.FPDiv", new SoftFloat64FPDivDelegate(SoftFloat64.FPDiv) },
|
||||||
|
{ "SoftFloat64.FPMax", new SoftFloat64FPMaxDelegate(SoftFloat64.FPMax) },
|
||||||
|
{ "SoftFloat64.FPMaxFpscr", new SoftFloat64FPMaxFpscrDelegate(SoftFloat64.FPMaxFpscr) },
|
||||||
|
{ "SoftFloat64.FPMaxNum", new SoftFloat64FPMaxNumDelegate(SoftFloat64.FPMaxNum) },
|
||||||
|
{ "SoftFloat64.FPMaxNumFpscr", new SoftFloat64FPMaxNumFpscrDelegate(SoftFloat64.FPMaxNumFpscr) },
|
||||||
|
{ "SoftFloat64.FPMin", new SoftFloat64FPMinDelegate(SoftFloat64.FPMin) },
|
||||||
|
{ "SoftFloat64.FPMinFpscr", new SoftFloat64FPMinFpscrDelegate(SoftFloat64.FPMinFpscr) },
|
||||||
|
{ "SoftFloat64.FPMinNum", new SoftFloat64FPMinNumDelegate(SoftFloat64.FPMinNum) },
|
||||||
|
{ "SoftFloat64.FPMinNumFpscr", new SoftFloat64FPMinNumFpscrDelegate(SoftFloat64.FPMinNumFpscr) },
|
||||||
|
{ "SoftFloat64.FPMul", new SoftFloat64FPMulDelegate(SoftFloat64.FPMul) },
|
||||||
|
{ "SoftFloat64.FPMulFpscr", new SoftFloat64FPMulFpscrDelegate(SoftFloat64.FPMulFpscr) },
|
||||||
|
{ "SoftFloat64.FPMulAdd", new SoftFloat64FPMulAddDelegate(SoftFloat64.FPMulAdd) },
|
||||||
|
{ "SoftFloat64.FPMulAddFpscr", new SoftFloat64FPMulAddFpscrDelegate(SoftFloat64.FPMulAddFpscr) },
|
||||||
|
{ "SoftFloat64.FPMulSub", new SoftFloat64FPMulSubDelegate(SoftFloat64.FPMulSub) },
|
||||||
|
{ "SoftFloat64.FPMulSubFpscr", new SoftFloat64FPMulSubFpscrDelegate(SoftFloat64.FPMulSubFpscr) },
|
||||||
|
{ "SoftFloat64.FPMulX", new SoftFloat64FPMulXDelegate(SoftFloat64.FPMulX) },
|
||||||
|
{ "SoftFloat64.FPNegMulAdd", new SoftFloat64FPNegMulAddDelegate(SoftFloat64.FPNegMulAdd) },
|
||||||
|
{ "SoftFloat64.FPNegMulSub", new SoftFloat64FPNegMulSubDelegate(SoftFloat64.FPNegMulSub) },
|
||||||
|
{ "SoftFloat64.FPRecipEstimate", new SoftFloat64FPRecipEstimateDelegate(SoftFloat64.FPRecipEstimate) },
|
||||||
|
{ "SoftFloat64.FPRecipEstimateFpscr", new SoftFloat64FPRecipEstimateFpscrDelegate(SoftFloat64.FPRecipEstimateFpscr) },
|
||||||
|
{ "SoftFloat64.FPRecipStep", new SoftFloat64FPRecipStepDelegate(SoftFloat64.FPRecipStep) },
|
||||||
|
{ "SoftFloat64.FPRecipStepFused", new SoftFloat64FPRecipStepFusedDelegate(SoftFloat64.FPRecipStepFused) },
|
||||||
|
{ "SoftFloat64.FPRecpX", new SoftFloat64FPRecpXDelegate(SoftFloat64.FPRecpX) },
|
||||||
|
{ "SoftFloat64.FPRSqrtEstimate", new SoftFloat64FPRSqrtEstimateDelegate(SoftFloat64.FPRSqrtEstimate) },
|
||||||
|
{ "SoftFloat64.FPRSqrtEstimateFpscr", new SoftFloat64FPRSqrtEstimateFpscrDelegate(SoftFloat64.FPRSqrtEstimateFpscr) },
|
||||||
|
{ "SoftFloat64.FPRSqrtStep", new SoftFloat64FPRSqrtStepDelegate(SoftFloat64.FPRSqrtStep) },
|
||||||
|
{ "SoftFloat64.FPRSqrtStepFused", new SoftFloat64FPRSqrtStepFusedDelegate(SoftFloat64.FPRSqrtStepFused) },
|
||||||
|
{ "SoftFloat64.FPSqrt", new SoftFloat64FPSqrtDelegate(SoftFloat64.FPSqrt) },
|
||||||
|
{ "SoftFloat64.FPSub", new SoftFloat64FPSubDelegate(SoftFloat64.FPSub) },
|
||||||
|
|
||||||
|
{ "SoftFloat64_16.FPConvert", new SoftFloat64_16FPConvertDelegate(SoftFloat64_16.FPConvert) }
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Abs)));
|
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Abs)));
|
||||||
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Ceiling)));
|
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Ceiling)));
|
||||||
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Floor)));
|
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Floor)));
|
||||||
@@ -152,44 +708,44 @@ namespace ARMeilleure.Translation
|
|||||||
SetDelegateInfo(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)));
|
SetDelegateInfo(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)));
|
||||||
|
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQ)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQ)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGE)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGE)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGT)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGT)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGTFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGTFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLE)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLE)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLT)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLT)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLTFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLTFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPDiv)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPDiv)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMul)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMul)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAdd)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSub)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSub)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSubFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSubFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulX)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulX)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulAdd)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSub)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSub)));
|
||||||
@@ -197,44 +753,44 @@ namespace ARMeilleure.Translation
|
|||||||
SetDelegateInfo(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)));
|
SetDelegateInfo(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)));
|
||||||
|
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAdd)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAddFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAddFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQ)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQ)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGE)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGE)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGT)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGT)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGTFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGTFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLE)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLE)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLT)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLT)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLTFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLTFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPDiv)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPDiv)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMax)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMax)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNum)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNum)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMin)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMin)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNum)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNum)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMul)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMul)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAdd)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSub)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSub)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSubFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSubFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulX)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulX)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulAdd)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep))); // A32 only.
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub)));
|
||||||
|
|||||||
@@ -97,7 +97,14 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
public virtual Operand Call(MethodInfo info, params Operand[] callArgs)
|
public virtual Operand Call(MethodInfo info, params Operand[] callArgs)
|
||||||
{
|
{
|
||||||
|
#if ANDROID
|
||||||
|
// For Android, use the Delegates class to get the function pointer
|
||||||
|
int index = Delegates.GetDelegateIndex(info);
|
||||||
|
nint funcPtr = Delegates.GetDelegateFuncPtrByIndex(index);
|
||||||
|
#else
|
||||||
|
// For other platforms, use direct method handle approach
|
||||||
nint funcPtr = info.MethodHandle.GetFunctionPointer();
|
nint funcPtr = info.MethodHandle.GetFunctionPointer();
|
||||||
|
#endif
|
||||||
|
|
||||||
OperandType returnType = GetOperandType(info.ReturnType);
|
OperandType returnType = GetOperandType(info.ReturnType);
|
||||||
|
|
||||||
|
|||||||
@@ -359,7 +359,10 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
IntervalTreeNode<TK, TV> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
IntervalTreeNode<TK, TV> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
||||||
|
|
||||||
tmp?.Parent = ParentOf(replacementNode);
|
if (tmp != null)
|
||||||
|
{
|
||||||
|
tmp.Parent = ParentOf(replacementNode);
|
||||||
|
}
|
||||||
|
|
||||||
if (ParentOf(replacementNode) == null)
|
if (ParentOf(replacementNode) == null)
|
||||||
{
|
{
|
||||||
@@ -567,7 +570,10 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
IntervalTreeNode<TK, TV> right = RightOf(node);
|
IntervalTreeNode<TK, TV> right = RightOf(node);
|
||||||
node.Right = LeftOf(right);
|
node.Right = LeftOf(right);
|
||||||
node.Right?.Parent = node;
|
if (node.Right != null)
|
||||||
|
{
|
||||||
|
node.Right.Parent = node;
|
||||||
|
}
|
||||||
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
|
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
|
||||||
right.Parent = nodeParent;
|
right.Parent = nodeParent;
|
||||||
if (nodeParent == null)
|
if (nodeParent == null)
|
||||||
@@ -595,7 +601,10 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
IntervalTreeNode<TK, TV> left = LeftOf(node);
|
IntervalTreeNode<TK, TV> left = LeftOf(node);
|
||||||
node.Left = RightOf(left);
|
node.Left = RightOf(left);
|
||||||
node.Left?.Parent = node;
|
if (node.Left != null)
|
||||||
|
{
|
||||||
|
node.Left.Parent = node;
|
||||||
|
}
|
||||||
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
|
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
|
||||||
left.Parent = nodeParent;
|
left.Parent = nodeParent;
|
||||||
if (nodeParent == null)
|
if (nodeParent == null)
|
||||||
@@ -642,7 +651,10 @@ namespace ARMeilleure.Translation
|
|||||||
/// <param name="color">Color (Boolean)</param>
|
/// <param name="color">Color (Boolean)</param>
|
||||||
private static void SetColor(IntervalTreeNode<TK, TV> node, bool color)
|
private static void SetColor(IntervalTreeNode<TK, TV> node, bool color)
|
||||||
{
|
{
|
||||||
node?.Color = color;
|
if (node != null)
|
||||||
|
{
|
||||||
|
node.Color = color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using Ryujinx.Common.Logging;
|
|||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -30,14 +31,11 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 7010; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 7031; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
|
||||||
private const string TitleIdTextDefault = "0000000000000000";
|
|
||||||
private const string DisplayVersionDefault = "0";
|
|
||||||
|
|
||||||
public static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1);
|
public static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1);
|
||||||
public static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2);
|
public static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2);
|
||||||
public static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
|
public static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
|
||||||
@@ -63,8 +61,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
public string TitleIdText { get; private set; }
|
public PtcCacheInfo CacheInfo { get; private set; }
|
||||||
public string DisplayVersion { get; private set; }
|
|
||||||
|
|
||||||
private MemoryManagerType _memoryMode;
|
private MemoryManagerType _memoryMode;
|
||||||
|
|
||||||
@@ -91,8 +88,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
_disposed = false;
|
_disposed = false;
|
||||||
|
|
||||||
TitleIdText = TitleIdTextDefault;
|
CacheInfo = new PtcCacheInfo(0, null, null, 0, null, "Unknown", "default");
|
||||||
DisplayVersion = DisplayVersionDefault;
|
|
||||||
|
|
||||||
CachePathActual = string.Empty;
|
CachePathActual = string.Empty;
|
||||||
CachePathBackup = string.Empty;
|
CachePathBackup = string.Empty;
|
||||||
@@ -100,20 +96,24 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
Disable();
|
Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize(string titleIdText, string displayVersion, bool enabled, MemoryManagerType memoryMode, string cacheSelector)
|
public void Initialize(PtcCacheInfo cacheInfo, bool enabled, MemoryManagerType memoryMode)
|
||||||
{
|
{
|
||||||
Wait();
|
Wait();
|
||||||
|
|
||||||
Profiler.Wait();
|
Profiler.Wait();
|
||||||
Profiler.ClearEntries();
|
Profiler.ClearEntries();
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Ptc, $"Initializing Profiled Persistent Translation Cache v{InternalVersion}\n\t\t (title: {titleIdText}, version: '{displayVersion}', selector: '{cacheSelector}', enabled: {enabled}).");
|
CacheInfo = cacheInfo;
|
||||||
|
|
||||||
if (!enabled || string.IsNullOrEmpty(titleIdText) || titleIdText == TitleIdTextDefault)
|
Logger.Info?.Print(
|
||||||
|
LogClass.Ptc,
|
||||||
|
$"Initializing Profiled Persistent Translation Cache v{InternalVersion}\n\t\t " +
|
||||||
|
$"(pid: {cacheInfo.ProcessId}, title: {cacheInfo.TitleIdText}, application: {cacheInfo.ApplicationIdText}, " +
|
||||||
|
$"programIndex: {cacheInfo.ProgramIndex}, version: '{cacheInfo.DisplayVersion}', kind: {cacheInfo.ProcessKind}, " +
|
||||||
|
$"selector: '{cacheInfo.CacheSelector}', key: '{cacheInfo.CacheKey}', enabled: {enabled}).");
|
||||||
|
|
||||||
|
if (!enabled || cacheInfo.TitleIdText == PtcCacheInfo.TitleIdTextDefault)
|
||||||
{
|
{
|
||||||
TitleIdText = TitleIdTextDefault;
|
|
||||||
DisplayVersion = DisplayVersionDefault;
|
|
||||||
|
|
||||||
CachePathActual = string.Empty;
|
CachePathActual = string.Empty;
|
||||||
CachePathBackup = string.Empty;
|
CachePathBackup = string.Empty;
|
||||||
|
|
||||||
@@ -122,12 +122,10 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TitleIdText = titleIdText;
|
|
||||||
DisplayVersion = !string.IsNullOrEmpty(displayVersion) ? displayVersion : DisplayVersionDefault;
|
|
||||||
_memoryMode = memoryMode;
|
_memoryMode = memoryMode;
|
||||||
|
|
||||||
string workPathActual = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", ActualDir);
|
string workPathActual = Path.Combine(AppDataManager.GamesDirPath, CacheInfo.TitleIdText, "cache", "cpu", ActualDir);
|
||||||
string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", BackupDir);
|
string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, CacheInfo.TitleIdText, "cache", "cpu", BackupDir);
|
||||||
|
|
||||||
if (!Directory.Exists(workPathActual))
|
if (!Directory.Exists(workPathActual))
|
||||||
{
|
{
|
||||||
@@ -139,8 +137,14 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
Directory.CreateDirectory(workPathBackup);
|
Directory.CreateDirectory(workPathBackup);
|
||||||
}
|
}
|
||||||
|
|
||||||
CachePathActual = Path.Combine(workPathActual, DisplayVersion) + "-" + cacheSelector;
|
CachePathActual = Path.Combine(workPathActual, CacheInfo.DisplayVersion) + "-" + CacheInfo.CacheSelector;
|
||||||
CachePathBackup = Path.Combine(workPathBackup, DisplayVersion) + "-" + cacheSelector;
|
CachePathBackup = Path.Combine(workPathBackup, CacheInfo.DisplayVersion) + "-" + CacheInfo.CacheSelector;
|
||||||
|
|
||||||
|
Logger.Info?.Print(
|
||||||
|
LogClass.Ptc,
|
||||||
|
$"PPTC cache owner selected (pid: {CacheInfo.ProcessId}, title: {CacheInfo.TitleIdText}, application: {CacheInfo.ApplicationIdText}, " +
|
||||||
|
$"version: '{CacheInfo.DisplayVersion}', kind: {CacheInfo.ProcessKind}, selector: '{CacheInfo.CacheSelector}', " +
|
||||||
|
$"key: '{CacheInfo.CacheKey}', path: '{CachePathActual}').");
|
||||||
|
|
||||||
PreLoad();
|
PreLoad();
|
||||||
Profiler.PreLoad();
|
Profiler.PreLoad();
|
||||||
@@ -249,8 +253,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
outerHeader.FeatureInfo != GetFeatureInfo() ||
|
outerHeader.FeatureInfo != GetFeatureInfo() ||
|
||||||
outerHeader.MemoryManagerMode != GetMemoryManagerMode() ||
|
outerHeader.MemoryManagerMode != GetMemoryManagerMode() ||
|
||||||
outerHeader.OSPlatform != GetOSPlatform() ||
|
outerHeader.OSPlatform != GetOSPlatform() ||
|
||||||
outerHeader.Architecture != (uint)RuntimeInformation.ProcessArchitecture ||
|
outerHeader.Architecture != (uint)RuntimeInformation.ProcessArchitecture)
|
||||||
outerHeader.DebuggerMode != Optimizations.EnableDebugging)
|
|
||||||
{
|
{
|
||||||
InvalidateCompressedStream(compressedStream);
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
@@ -364,7 +367,12 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
long fileSize = new FileInfo(fileName).Length;
|
long fileSize = new FileInfo(fileName).Length;
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Ptc, $"{(isBackup ? "Loaded Backup Translation Cache" : "Loaded Translation Cache")} (size: {fileSize} bytes, translated functions: {GetEntriesCount()}).");
|
Logger.Info?.Print(
|
||||||
|
LogClass.Ptc,
|
||||||
|
$"{(isBackup ? "Loaded Backup Translation Cache" : "Loaded Translation Cache")} " +
|
||||||
|
$"(pid: {CacheInfo.ProcessId}, title: {CacheInfo.TitleIdText}, version: '{CacheInfo.DisplayVersion}', kind: {CacheInfo.ProcessKind}, " +
|
||||||
|
$"selector: '{CacheInfo.CacheSelector}', key: '{CacheInfo.CacheKey}', path: '{fileName}', " +
|
||||||
|
$"size: {fileSize} bytes, translated functions: {GetEntriesCount()}).");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -426,7 +434,6 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
MemoryManagerMode = GetMemoryManagerMode(),
|
MemoryManagerMode = GetMemoryManagerMode(),
|
||||||
OSPlatform = GetOSPlatform(),
|
OSPlatform = GetOSPlatform(),
|
||||||
Architecture = (uint)RuntimeInformation.ProcessArchitecture,
|
Architecture = (uint)RuntimeInformation.ProcessArchitecture,
|
||||||
DebuggerMode = Optimizations.EnableDebugging,
|
|
||||||
|
|
||||||
UncompressedStreamSize =
|
UncompressedStreamSize =
|
||||||
(long)Unsafe.SizeOf<InnerHeader>() +
|
(long)Unsafe.SizeOf<InnerHeader>() +
|
||||||
@@ -544,7 +551,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
bool isEntryChanged = infoEntry.Hash != ComputeHash(translator.Memory, infoEntry.Address, infoEntry.GuestSize);
|
bool isEntryChanged = infoEntry.Hash != ComputeHash(translator.Memory, infoEntry.Address, infoEntry.GuestSize);
|
||||||
|
|
||||||
if (isEntryChanged || (!infoEntry.HighCq && Profiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) && value.HighCq))
|
if (isEntryChanged || (!infoEntry.HighCq && Profiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out PtcProfiler.FuncProfile value) && value.HighCq))
|
||||||
{
|
{
|
||||||
infoEntry.Stubbed = true;
|
infoEntry.Stubbed = true;
|
||||||
infoEntry.CodeLength = 0;
|
infoEntry.CodeLength = 0;
|
||||||
@@ -731,8 +738,8 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
UnwindInfo unwindInfo,
|
UnwindInfo unwindInfo,
|
||||||
bool highCq)
|
bool highCq)
|
||||||
{
|
{
|
||||||
var cFunc = new CompiledFunction(code, unwindInfo, RelocInfo.Empty);
|
CompiledFunction cFunc = new(code, unwindInfo, RelocInfo.Empty);
|
||||||
var gFunc = cFunc.MapWithPointer<GuestFunction>(out nint gFuncPointer);
|
GuestFunction gFunc = cFunc.MapWithPointer<GuestFunction>(out nint gFuncPointer);
|
||||||
|
|
||||||
return new TranslatedFunction(gFunc, gFuncPointer, callCounter, guestSize, highCq);
|
return new TranslatedFunction(gFunc, gFuncPointer, callCounter, guestSize, highCq);
|
||||||
}
|
}
|
||||||
@@ -769,7 +776,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
public void MakeAndSaveTranslations(Translator translator)
|
public void MakeAndSaveTranslations(Translator translator)
|
||||||
{
|
{
|
||||||
var profiledFuncsToTranslate = Profiler.GetProfiledFuncsToTranslate(translator.Functions);
|
ConcurrentQueue<(ulong address, PtcProfiler.FuncProfile funcProfile)> profiledFuncsToTranslate = Profiler.GetProfiledFuncsToTranslate(translator.Functions);
|
||||||
|
|
||||||
_translateCount = 0;
|
_translateCount = 0;
|
||||||
_translateTotalCount = profiledFuncsToTranslate.Count;
|
_translateTotalCount = profiledFuncsToTranslate.Count;
|
||||||
@@ -813,7 +820,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
void TranslateFuncs()
|
void TranslateFuncs()
|
||||||
{
|
{
|
||||||
while (profiledFuncsToTranslate.TryDequeue(out var item))
|
while (profiledFuncsToTranslate.TryDequeue(out (ulong address, PtcProfiler.FuncProfile funcProfile) item))
|
||||||
{
|
{
|
||||||
ulong address = item.address;
|
ulong address = item.address;
|
||||||
ExecutionMode executionMode = item.funcProfile.Mode;
|
ExecutionMode executionMode = item.funcProfile.Mode;
|
||||||
@@ -858,11 +865,11 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
Stopwatch sw = Stopwatch.StartNew();
|
Stopwatch sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
foreach (var thread in threads)
|
foreach (Thread thread in threads)
|
||||||
{
|
{
|
||||||
thread.Start();
|
thread.Start();
|
||||||
}
|
}
|
||||||
foreach (var thread in threads)
|
foreach (Thread thread in threads)
|
||||||
{
|
{
|
||||||
thread.Join();
|
thread.Join();
|
||||||
}
|
}
|
||||||
@@ -942,7 +949,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
WriteCode(code.AsSpan());
|
WriteCode(code.AsSpan());
|
||||||
|
|
||||||
// WriteReloc.
|
// WriteReloc.
|
||||||
using var relocInfoWriter = new BinaryWriter(_relocsStream, EncodingCache.UTF8NoBOM, true);
|
using BinaryWriter relocInfoWriter = new(_relocsStream, EncodingCache.UTF8NoBOM, true);
|
||||||
|
|
||||||
foreach (RelocEntry entry in relocInfo.Entries)
|
foreach (RelocEntry entry in relocInfo.Entries)
|
||||||
{
|
{
|
||||||
@@ -952,7 +959,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteUnwindInfo.
|
// WriteUnwindInfo.
|
||||||
using var unwindInfoWriter = new BinaryWriter(_unwindInfosStream, EncodingCache.UTF8NoBOM, true);
|
using BinaryWriter unwindInfoWriter = new(_unwindInfosStream, EncodingCache.UTF8NoBOM, true);
|
||||||
|
|
||||||
unwindInfoWriter.Write(unwindInfo.PushEntries.Length);
|
unwindInfoWriter.Write(unwindInfo.PushEntries.Length);
|
||||||
|
|
||||||
@@ -1023,7 +1030,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return osPlatform;
|
return osPlatform;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 87*/)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 86*/)]
|
||||||
private struct OuterHeader
|
private struct OuterHeader
|
||||||
{
|
{
|
||||||
public ulong Magic;
|
public ulong Magic;
|
||||||
@@ -1035,7 +1042,6 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
public byte MemoryManagerMode;
|
public byte MemoryManagerMode;
|
||||||
public uint OSPlatform;
|
public uint OSPlatform;
|
||||||
public uint Architecture;
|
public uint Architecture;
|
||||||
public bool DebuggerMode;
|
|
||||||
|
|
||||||
public long UncompressedStreamSize;
|
public long UncompressedStreamSize;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
namespace ARMeilleure.Translation.PTC
|
||||||
|
{
|
||||||
|
public readonly struct PtcCacheInfo
|
||||||
|
{
|
||||||
|
public const string TitleIdTextDefault = "0000000000000000";
|
||||||
|
public const string ApplicationIdTextDefault = "0000000000000000";
|
||||||
|
public const string DisplayVersionDefault = "0";
|
||||||
|
|
||||||
|
public ulong ProcessId { get; }
|
||||||
|
public string TitleIdText { get; }
|
||||||
|
public string ApplicationIdText { get; }
|
||||||
|
public byte ProgramIndex { get; }
|
||||||
|
public string DisplayVersion { get; }
|
||||||
|
public string ProcessKind { get; }
|
||||||
|
public string CacheSelector { get; }
|
||||||
|
|
||||||
|
public string CacheKey => $"{DisplayVersion}-{CacheSelector}";
|
||||||
|
|
||||||
|
public PtcCacheInfo(
|
||||||
|
ulong processId,
|
||||||
|
string titleIdText,
|
||||||
|
string applicationIdText,
|
||||||
|
byte programIndex,
|
||||||
|
string displayVersion,
|
||||||
|
string processKind,
|
||||||
|
string cacheSelector)
|
||||||
|
{
|
||||||
|
ProcessId = processId;
|
||||||
|
TitleIdText = !string.IsNullOrEmpty(titleIdText) ? titleIdText : TitleIdTextDefault;
|
||||||
|
ApplicationIdText = !string.IsNullOrEmpty(applicationIdText) ? applicationIdText : ApplicationIdTextDefault;
|
||||||
|
ProgramIndex = programIndex;
|
||||||
|
DisplayVersion = !string.IsNullOrEmpty(displayVersion) ? displayVersion : DisplayVersionDefault;
|
||||||
|
ProcessKind = processKind ?? string.Empty;
|
||||||
|
CacheSelector = string.IsNullOrEmpty(cacheSelector) ? "default" : cacheSelector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,13 +9,13 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
using static ARMeilleure.Translation.PTC.PtcFormatter;
|
using static ARMeilleure.Translation.PTC.PtcFormatter;
|
||||||
using Timer = System.Timers.Timer;
|
using Timer = System.Timers.Timer;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace ARMeilleure.Translation.PTC
|
namespace ARMeilleure.Translation.PTC
|
||||||
{
|
{
|
||||||
@@ -23,7 +23,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
private const string OuterHeaderMagicString = "Pohd\0\0\0\0";
|
private const string OuterHeaderMagicString = "Pohd\0\0\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 6698; //! Not to be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 7031; //! Not to be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private static readonly uint[] _migrateInternalVersions =
|
private static readonly uint[] _migrateInternalVersions =
|
||||||
[
|
[
|
||||||
@@ -119,9 +119,9 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
public ConcurrentQueue<(ulong address, FuncProfile funcProfile)> GetProfiledFuncsToTranslate(TranslatorCache<TranslatedFunction> funcs)
|
public ConcurrentQueue<(ulong address, FuncProfile funcProfile)> GetProfiledFuncsToTranslate(TranslatorCache<TranslatedFunction> funcs)
|
||||||
{
|
{
|
||||||
var profiledFuncsToTranslate = new ConcurrentQueue<(ulong address, FuncProfile funcProfile)>();
|
ConcurrentQueue<(ulong address, FuncProfile funcProfile)> profiledFuncsToTranslate = new();
|
||||||
|
|
||||||
foreach (var profiledFunc in ProfiledFuncs)
|
foreach (KeyValuePair<ulong, FuncProfile> profiledFunc in ProfiledFuncs)
|
||||||
{
|
{
|
||||||
if (!funcs.ContainsKey(profiledFunc.Key) && !profiledFunc.Value.Blacklist)
|
if (!funcs.ContainsKey(profiledFunc.Key) && !profiledFunc.Value.Blacklist)
|
||||||
{
|
{
|
||||||
@@ -142,7 +142,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
List<ulong> funcs = [];
|
List<ulong> funcs = [];
|
||||||
|
|
||||||
foreach (var profiledFunc in ProfiledFuncs)
|
foreach (KeyValuePair<ulong, FuncProfile> profiledFunc in ProfiledFuncs)
|
||||||
{
|
{
|
||||||
if (profiledFunc.Value.Blacklist)
|
if (profiledFunc.Value.Blacklist)
|
||||||
{
|
{
|
||||||
@@ -254,7 +254,12 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
long fileSize = new FileInfo(fileName).Length;
|
long fileSize = new FileInfo(fileName).Length;
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Ptc, $"{(isBackup ? "Loaded Backup Profiling Info" : "Loaded Profiling Info")} (size: {fileSize} bytes, profiled functions: {ProfiledFuncs.Count}).");
|
Logger.Info?.Print(
|
||||||
|
LogClass.Ptc,
|
||||||
|
$"{(isBackup ? "Loaded Backup Profiling Info" : "Loaded Profiling Info")} " +
|
||||||
|
$"(pid: {_ptc.CacheInfo.ProcessId}, title: {_ptc.CacheInfo.TitleIdText}, version: '{_ptc.CacheInfo.DisplayVersion}', " +
|
||||||
|
$"kind: {_ptc.CacheInfo.ProcessKind}, selector: '{_ptc.CacheInfo.CacheSelector}', key: '{_ptc.CacheInfo.CacheKey}', " +
|
||||||
|
$"path: '{fileName}', size: {fileSize} bytes, profiled functions: {ProfiledFuncs.Count}).");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -375,7 +380,11 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
if (fileSize != 0L)
|
if (fileSize != 0L)
|
||||||
{
|
{
|
||||||
Logger.Info?.Print(LogClass.Ptc, $"Saved Profiling Info (size: {fileSize} bytes, profiled functions: {profiledFuncsCount}).");
|
Logger.Info?.Print(
|
||||||
|
LogClass.Ptc,
|
||||||
|
$"Saved Profiling Info (pid: {_ptc.CacheInfo.ProcessId}, title: {_ptc.CacheInfo.TitleIdText}, version: '{_ptc.CacheInfo.DisplayVersion}', " +
|
||||||
|
$"kind: {_ptc.CacheInfo.ProcessKind}, selector: '{_ptc.CacheInfo.CacheSelector}', key: '{_ptc.CacheInfo.CacheKey}', " +
|
||||||
|
$"path: '{fileName}', size: {fileSize} bytes, profiled functions: {profiledFuncsCount}).");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
public static void Construct(ControlFlowGraph cfg)
|
public static void Construct(ControlFlowGraph cfg)
|
||||||
{
|
{
|
||||||
var globalDefs = new DefMap[cfg.Blocks.Count];
|
DefMap[] globalDefs = new DefMap[cfg.Blocks.Count];
|
||||||
var localDefs = new Operand[cfg.LocalsCount + RegisterConsts.TotalCount];
|
Operand[] localDefs = new Operand[cfg.LocalsCount + RegisterConsts.TotalCount];
|
||||||
|
|
||||||
var dfPhiBlocks = new Queue<BasicBlock>();
|
Queue<BasicBlock> dfPhiBlocks = new();
|
||||||
|
|
||||||
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
|
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -57,9 +57,9 @@ namespace ARMeilleure.Translation
|
|||||||
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled, string cacheSelector)
|
public IPtcLoadState LoadDiskCache(PtcCacheInfo cacheInfo, bool enabled)
|
||||||
{
|
{
|
||||||
_ptc.Initialize(titleIdText, displayVersion, enabled, Memory.Type, cacheSelector);
|
_ptc.Initialize(cacheInfo, enabled, Memory.Type);
|
||||||
return _ptc;
|
return _ptc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,25 +119,7 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
NativeInterface.RegisterThread(context, Memory, this);
|
NativeInterface.RegisterThread(context, Memory, this);
|
||||||
|
|
||||||
if (Optimizations.EnableDebugging)
|
if (Optimizations.UseUnmanagedDispatchLoop)
|
||||||
{
|
|
||||||
context.DebugPc = address;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (Interlocked.CompareExchange(ref context.ShouldStep, 0, 1) == 1)
|
|
||||||
{
|
|
||||||
context.DebugPc = Step(context, context.DebugPc);
|
|
||||||
context.StepHandler();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
context.DebugPc = ExecuteSingle(context, context.DebugPc);
|
|
||||||
}
|
|
||||||
context.CheckInterrupt();
|
|
||||||
}
|
|
||||||
while (context.Running && context.DebugPc != 0);
|
|
||||||
}
|
|
||||||
else if (Optimizations.UseUnmanagedDispatchLoop)
|
|
||||||
{
|
{
|
||||||
Stubs.DispatchLoop(context.NativeContextPtr, address);
|
Stubs.DispatchLoop(context.NativeContextPtr, address);
|
||||||
}
|
}
|
||||||
@@ -194,7 +176,7 @@ namespace ARMeilleure.Translation
|
|||||||
return nextAddr;
|
return nextAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ulong Step(State.ExecutionContext context, ulong address)
|
public ulong Step(State.ExecutionContext context, ulong address)
|
||||||
{
|
{
|
||||||
TranslatedFunction func = Translate(address, context.ExecutionMode, highCq: false, singleStep: true);
|
TranslatedFunction func = Translate(address, context.ExecutionMode, highCq: false, singleStep: true);
|
||||||
|
|
||||||
@@ -205,8 +187,6 @@ namespace ARMeilleure.Translation
|
|||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
internal TranslatedFunction GetOrTranslate(ulong address, ExecutionMode mode)
|
internal TranslatedFunction GetOrTranslate(ulong address, ExecutionMode mode)
|
||||||
{
|
{
|
||||||
if (!Functions.TryGetValue(address, out TranslatedFunction func))
|
if (!Functions.TryGetValue(address, out TranslatedFunction func))
|
||||||
@@ -242,7 +222,7 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
internal TranslatedFunction Translate(ulong address, ExecutionMode mode, bool highCq, bool singleStep = false, bool pptcTranslation = false)
|
internal TranslatedFunction Translate(ulong address, ExecutionMode mode, bool highCq, bool singleStep = false, bool pptcTranslation = false)
|
||||||
{
|
{
|
||||||
var context = new ArmEmitterContext(
|
ArmEmitterContext context = new(
|
||||||
Memory,
|
Memory,
|
||||||
CountTable,
|
CountTable,
|
||||||
FunctionTable,
|
FunctionTable,
|
||||||
@@ -250,8 +230,7 @@ namespace ARMeilleure.Translation
|
|||||||
address,
|
address,
|
||||||
highCq,
|
highCq,
|
||||||
_ptc.State != PtcState.Disabled,
|
_ptc.State != PtcState.Disabled,
|
||||||
mode: Aarch32Mode.User,
|
mode: Aarch32Mode.User);
|
||||||
isSingleStep: singleStep);
|
|
||||||
|
|
||||||
Logger.StartPass(PassName.Decoding);
|
Logger.StartPass(PassName.Decoding);
|
||||||
|
|
||||||
@@ -286,10 +265,10 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
Logger.EndPass(PassName.RegisterUsage);
|
Logger.EndPass(PassName.RegisterUsage);
|
||||||
|
|
||||||
var retType = OperandType.I64;
|
OperandType retType = OperandType.I64;
|
||||||
var argTypes = new OperandType[] { OperandType.I64 };
|
OperandType[] argTypes = new OperandType[] { OperandType.I64 };
|
||||||
|
|
||||||
var options = highCq ? CompilerOptions.HighCq : CompilerOptions.None;
|
CompilerOptions options = highCq ? CompilerOptions.HighCq : CompilerOptions.None;
|
||||||
|
|
||||||
if (context.HasPtc && !singleStep)
|
if (context.HasPtc && !singleStep)
|
||||||
{
|
{
|
||||||
@@ -390,13 +369,9 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
if (block.Exit)
|
if (block.Exit)
|
||||||
{
|
{
|
||||||
// Return to managed rather than tail call.
|
// Left option here as it may be useful if we need to return to managed rather than tail call in
|
||||||
bool useReturns = Optimizations.EnableDebugging;
|
// future. (eg. for debug)
|
||||||
|
bool useReturns = false;
|
||||||
if (Optimizations.EnableDebugging)
|
|
||||||
{
|
|
||||||
EmitDebugPrecisePcUpdate(context, block.Address);
|
|
||||||
}
|
|
||||||
|
|
||||||
InstEmitFlowHelper.EmitVirtualJump(context, Const(block.Address), isReturn: useReturns);
|
InstEmitFlowHelper.EmitVirtualJump(context, Const(block.Address), isReturn: useReturns);
|
||||||
}
|
}
|
||||||
@@ -420,11 +395,6 @@ namespace ARMeilleure.Translation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Optimizations.EnableDebugging)
|
|
||||||
{
|
|
||||||
EmitDebugPrecisePcUpdate(context, opCode.Address);
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand lblPredicateSkip = default;
|
Operand lblPredicateSkip = default;
|
||||||
|
|
||||||
if (context.IsInIfThenBlock && context.CurrentIfThenBlockCond != Condition.Al)
|
if (context.IsInIfThenBlock && context.CurrentIfThenBlockCond != Condition.Al)
|
||||||
@@ -521,14 +491,6 @@ namespace ARMeilleure.Translation
|
|||||||
context.MarkLabel(lblExit);
|
context.MarkLabel(lblExit);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void EmitDebugPrecisePcUpdate(EmitterContext context, ulong address)
|
|
||||||
{
|
|
||||||
long debugPrecisePcOffs = NativeContext.GetDebugPrecisePcOffset();
|
|
||||||
|
|
||||||
Operand debugPrecisePcAddr = context.Add(context.LoadArgument(OperandType.I64, 0), Const(debugPrecisePcOffs));
|
|
||||||
context.Store(debugPrecisePcAddr, Const(address));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void InvalidateJitCacheRegion(ulong address, ulong size)
|
public void InvalidateJitCacheRegion(ulong address, ulong size)
|
||||||
{
|
{
|
||||||
ulong[] overlapAddresses = [];
|
ulong[] overlapAddresses = [];
|
||||||
@@ -574,7 +536,7 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
List<TranslatedFunction> functions = Functions.AsList();
|
List<TranslatedFunction> functions = Functions.AsList();
|
||||||
|
|
||||||
foreach (var func in functions)
|
foreach (TranslatedFunction func in functions)
|
||||||
{
|
{
|
||||||
JitCache.Unmap(func.FuncPointer);
|
JitCache.Unmap(func.FuncPointer);
|
||||||
|
|
||||||
@@ -583,7 +545,7 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
Functions.Clear();
|
Functions.Clear();
|
||||||
|
|
||||||
while (_oldFuncs.TryDequeue(out var kv))
|
while (_oldFuncs.TryDequeue(out KeyValuePair<ulong, TranslatedFunction> kv))
|
||||||
{
|
{
|
||||||
JitCache.Unmap(kv.Value.FuncPointer);
|
JitCache.Unmap(kv.Value.FuncPointer);
|
||||||
|
|
||||||
@@ -604,7 +566,7 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
while (Queue.Count > 0 && Queue.TryDequeue(out RejitRequest request))
|
while (Queue.Count > 0 && Queue.TryDequeue(out RejitRequest request))
|
||||||
{
|
{
|
||||||
if (Functions.TryGetValue(request.Address, out var func) && func.CallCounter != null)
|
if (Functions.TryGetValue(request.Address, out TranslatedFunction func) && func.CallCounter != null)
|
||||||
{
|
{
|
||||||
Volatile.Write(ref func.CallCounter.Value, 0);
|
Volatile.Write(ref func.CallCounter.Value, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ namespace ARMeilleure.Translation
|
|||||||
/// <returns>Generated <see cref="DispatchStub"/></returns>
|
/// <returns>Generated <see cref="DispatchStub"/></returns>
|
||||||
private nint GenerateDispatchStub()
|
private nint GenerateDispatchStub()
|
||||||
{
|
{
|
||||||
var context = new EmitterContext();
|
EmitterContext context = new();
|
||||||
|
|
||||||
Operand lblFallback = Label();
|
Operand lblFallback = Label();
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
@@ -160,7 +160,7 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
for (int i = 0; i < _functionTable.Levels.Length; i++)
|
for (int i = 0; i < _functionTable.Levels.Length; i++)
|
||||||
{
|
{
|
||||||
ref var level = ref _functionTable.Levels[i];
|
ref AddressTableLevel level = ref _functionTable.Levels[i];
|
||||||
|
|
||||||
// level.Mask is not used directly because it is more often bigger than 32-bits, so it will not
|
// level.Mask is not used directly because it is more often bigger than 32-bits, so it will not
|
||||||
// be encoded as an immediate on x86's bitwise and operation.
|
// be encoded as an immediate on x86's bitwise and operation.
|
||||||
@@ -184,11 +184,11 @@ namespace ARMeilleure.Translation
|
|||||||
hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
|
hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
|
||||||
context.Tailcall(hostAddress, nativeContext);
|
context.Tailcall(hostAddress, nativeContext);
|
||||||
|
|
||||||
var cfg = context.GetControlFlowGraph();
|
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||||
var retType = OperandType.I64;
|
OperandType retType = OperandType.I64;
|
||||||
var argTypes = new[] { OperandType.I64 };
|
OperandType[] argTypes = new[] { OperandType.I64 };
|
||||||
|
|
||||||
var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<GuestFunction>();
|
GuestFunction func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<GuestFunction>();
|
||||||
|
|
||||||
return Marshal.GetFunctionPointerForDelegate(func);
|
return Marshal.GetFunctionPointerForDelegate(func);
|
||||||
}
|
}
|
||||||
@@ -199,7 +199,7 @@ namespace ARMeilleure.Translation
|
|||||||
/// <returns>Generated <see cref="SlowDispatchStub"/></returns>
|
/// <returns>Generated <see cref="SlowDispatchStub"/></returns>
|
||||||
private nint GenerateSlowDispatchStub()
|
private nint GenerateSlowDispatchStub()
|
||||||
{
|
{
|
||||||
var context = new EmitterContext();
|
EmitterContext context = new();
|
||||||
|
|
||||||
// Load the target guest address from the native context.
|
// Load the target guest address from the native context.
|
||||||
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||||
@@ -209,11 +209,11 @@ namespace ARMeilleure.Translation
|
|||||||
Operand hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
|
Operand hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
|
||||||
context.Tailcall(hostAddress, nativeContext);
|
context.Tailcall(hostAddress, nativeContext);
|
||||||
|
|
||||||
var cfg = context.GetControlFlowGraph();
|
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||||
var retType = OperandType.I64;
|
OperandType retType = OperandType.I64;
|
||||||
var argTypes = new[] { OperandType.I64 };
|
OperandType[] argTypes = new[] { OperandType.I64 };
|
||||||
|
|
||||||
var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<GuestFunction>();
|
GuestFunction func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<GuestFunction>();
|
||||||
|
|
||||||
return Marshal.GetFunctionPointerForDelegate(func);
|
return Marshal.GetFunctionPointerForDelegate(func);
|
||||||
}
|
}
|
||||||
@@ -250,7 +250,7 @@ namespace ARMeilleure.Translation
|
|||||||
/// <returns><see cref="DispatchLoop"/> function</returns>
|
/// <returns><see cref="DispatchLoop"/> function</returns>
|
||||||
private DispatcherFunction GenerateDispatchLoop()
|
private DispatcherFunction GenerateDispatchLoop()
|
||||||
{
|
{
|
||||||
var context = new EmitterContext();
|
EmitterContext context = new();
|
||||||
|
|
||||||
Operand beginLbl = Label();
|
Operand beginLbl = Label();
|
||||||
Operand endLbl = Label();
|
Operand endLbl = Label();
|
||||||
@@ -286,9 +286,9 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
context.Return();
|
context.Return();
|
||||||
|
|
||||||
var cfg = context.GetControlFlowGraph();
|
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||||
var retType = OperandType.None;
|
OperandType retType = OperandType.None;
|
||||||
var argTypes = new[] { OperandType.I64, OperandType.I64 };
|
OperandType[] argTypes = new[] { OperandType.I64, OperandType.I64 };
|
||||||
|
|
||||||
return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DispatcherFunction>();
|
return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DispatcherFunction>();
|
||||||
}
|
}
|
||||||
@@ -299,7 +299,7 @@ namespace ARMeilleure.Translation
|
|||||||
/// <returns><see cref="ContextWrapper"/> function</returns>
|
/// <returns><see cref="ContextWrapper"/> function</returns>
|
||||||
private WrapperFunction GenerateContextWrapper()
|
private WrapperFunction GenerateContextWrapper()
|
||||||
{
|
{
|
||||||
var context = new EmitterContext();
|
EmitterContext context = new();
|
||||||
|
|
||||||
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||||
Operand guestMethod = context.LoadArgument(OperandType.I64, 1);
|
Operand guestMethod = context.LoadArgument(OperandType.I64, 1);
|
||||||
@@ -310,9 +310,9 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
context.Return(returnValue);
|
context.Return(returnValue);
|
||||||
|
|
||||||
var cfg = context.GetControlFlowGraph();
|
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||||
var retType = OperandType.I64;
|
OperandType retType = OperandType.I64;
|
||||||
var argTypes = new[] { OperandType.I64, OperandType.I64 };
|
OperandType[] argTypes = new[] { OperandType.I64, OperandType.I64 };
|
||||||
|
|
||||||
return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<WrapperFunction>();
|
return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<WrapperFunction>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
.gradle
|
||||||
|
local.properties
|
||||||
|
.DS_Store
|
||||||
|
build/
|
||||||
|
captures
|
||||||
|
.externalNativeBuild
|
||||||
|
.cxx/
|
||||||
|
|
||||||
|
app/src/main/jniLibs/arm64-v8a/**
|
||||||
|
!app/src/main/jniLibs/arm64-v8a/.gitkeep
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
plugins {
|
||||||
|
id 'com.android.application'
|
||||||
|
id 'org.jetbrains.kotlin.plugin.compose'
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = 'org.kenjinx.android'
|
||||||
|
compileSdk 37
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "org.kenjinx.android"
|
||||||
|
minSdk 29
|
||||||
|
targetSdk 37
|
||||||
|
versionCode 20100
|
||||||
|
versionName '2.1.0-pr.2'
|
||||||
|
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
|
ndk {
|
||||||
|
//noinspection ChromeOsAbiSupport
|
||||||
|
abiFilters 'arm64-v8a'
|
||||||
|
}
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
cppFlags "-std=c++20 -O3",
|
||||||
|
"-fno-math-errno -fno-trapping-math -fno-signed-zeros -ffinite-math-only"
|
||||||
|
arguments "-DANDROID_STL=c++_shared",
|
||||||
|
"-DCMAKE_BUILD_TYPE=Release",
|
||||||
|
"-DANDROID_ARM_NEON=TRUE",
|
||||||
|
"-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
// minifyEnabled false
|
||||||
|
// proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
signingConfig = signingConfigs.debug
|
||||||
|
debuggable false
|
||||||
|
jniDebuggable false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def deviceFlavors = [
|
||||||
|
armv8 : "-march=armv8-a",
|
||||||
|
armv82 : "-march=armv8.2-a",
|
||||||
|
armv87 : "-march=armv8.7-a",
|
||||||
|
sd8eg5 : "-march=armv8.7-a+sve+sve2",
|
||||||
|
]
|
||||||
|
|
||||||
|
flavorDimensions "appid", "device"
|
||||||
|
productFlavors {
|
||||||
|
mainline {
|
||||||
|
dimension "appid"
|
||||||
|
applicationId "org.kenjinx.android"
|
||||||
|
manifestPlaceholders = [applicationLabel: "@string/app_name"]
|
||||||
|
}
|
||||||
|
optimized {
|
||||||
|
dimension "appid"
|
||||||
|
applicationId "com.garena.game.codm"
|
||||||
|
manifestPlaceholders = [applicationLabel: "@string/app_name_optimized"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceFlavors.each { name, flags ->
|
||||||
|
productFlavors.create(name) {
|
||||||
|
dimension "device"
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
cppFlags flags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
androidComponents {
|
||||||
|
onVariants(selector().withBuildType("debug")) {
|
||||||
|
packaging.dex.useLegacyPackaging.set(false)
|
||||||
|
}
|
||||||
|
beforeVariants(selector().all()) { variant ->
|
||||||
|
def flavors = variant.productFlavors.collect { it.second }.toSet()
|
||||||
|
|
||||||
|
def invalidCombos = [
|
||||||
|
["optimized", "armv8"],
|
||||||
|
["optimized", "armv87"],
|
||||||
|
["optimized", "sd8eg5"]
|
||||||
|
]
|
||||||
|
|
||||||
|
if (invalidCombos.any { combo -> flavors.containsAll(combo) }) {
|
||||||
|
enable = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_21
|
||||||
|
targetCompatibility JavaVersion.VERSION_21
|
||||||
|
}
|
||||||
|
|
||||||
|
buildFeatures {
|
||||||
|
compose = true
|
||||||
|
prefab = true
|
||||||
|
buildConfig = true
|
||||||
|
}
|
||||||
|
|
||||||
|
packagingOptions {
|
||||||
|
jniLibs {
|
||||||
|
keepDebugSymbols += '**/libkenjinx.so'
|
||||||
|
useLegacyPackaging true
|
||||||
|
}
|
||||||
|
dex {
|
||||||
|
useLegacyPackaging true
|
||||||
|
}
|
||||||
|
resources {
|
||||||
|
excludes += '/META-INF/{AL2.0,LGPL2.1}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
path file('src/main/cpp/CMakeLists.txt')
|
||||||
|
version = '4.1.2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
jniLibs.srcDirs = ['src/main/extLibs', 'src/main/jniLibs']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named("preBuild") {
|
||||||
|
dependsOn ':libkenjinx:assemble'
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
runtimeOnly project(":libkenjinx")
|
||||||
|
implementation 'androidx.activity:activity-compose:1.13.0'
|
||||||
|
implementation 'androidx.appcompat:appcompat:1.8.0'
|
||||||
|
implementation 'androidx.compose.material3:material3'
|
||||||
|
implementation 'androidx.compose.material:material-icons-extended:1.7.8'
|
||||||
|
implementation 'androidx.compose.ui:ui'
|
||||||
|
implementation 'androidx.compose.ui:ui-graphics'
|
||||||
|
implementation 'androidx.compose.ui:ui-tooling-preview'
|
||||||
|
implementation 'androidx.constraintlayout:constraintlayout:2.2.2'
|
||||||
|
implementation 'androidx.core:core-ktx:1.19.0'
|
||||||
|
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.11.0'
|
||||||
|
implementation 'androidx.navigation:navigation-compose:2.9.8'
|
||||||
|
implementation 'androidx.preference:preference-ktx:1.2.1'
|
||||||
|
implementation 'br.com.devsrsouza.compose.icons:css-gg:1.1.1'
|
||||||
|
implementation 'com.anggrayudi:storage:2.2.0'
|
||||||
|
implementation 'com.github.swordfish90:radialgamepad:2.0.0'
|
||||||
|
implementation 'com.google.android.material:material:1.14.0'
|
||||||
|
implementation 'com.google.code.gson:gson:2.14.0'
|
||||||
|
implementation 'com.halilibo.compose-richtext:richtext-commonmark:0.20.0'
|
||||||
|
implementation 'com.halilibo.compose-richtext:richtext-ui-material3:0.20.0'
|
||||||
|
implementation 'com.halilibo.compose-richtext:richtext-ui:0.20.0'
|
||||||
|
implementation 'io.coil-kt:coil-compose:2.7.0'
|
||||||
|
implementation 'net.java.dev.jna:jna:5.19.1@aar'
|
||||||
|
implementation 'net.lingala.zip4j:zip4j:2.11.6'
|
||||||
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.11.0'
|
||||||
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0'
|
||||||
|
implementation platform('androidx.compose:compose-bom:2026.08.00')
|
||||||
|
implementation platform('org.jetbrains.kotlin:kotlin-bom:2.3.10')
|
||||||
|
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
|
||||||
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0'
|
||||||
|
androidTestImplementation 'androidx.test.ext:junit:1.3.0'
|
||||||
|
androidTestImplementation platform('androidx.compose:compose-bom:2026.08.00')
|
||||||
|
testImplementation 'junit:junit:4.13.2'
|
||||||
|
debugImplementation 'androidx.compose.ui:ui-test-manifest'
|
||||||
|
debugImplementation 'androidx.compose.ui:ui-tooling'
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
-optimizationpasses 5
|
||||||
|
-optimizations !code/simplification/arithmetic
|
||||||
|
-optimizations !code/simplification/cast
|
||||||
|
-optimizations !field/*
|
||||||
|
-optimizations !class/merging/*
|
||||||
|
-optimizations !method/inlining/short
|
||||||
|
-optimizations !method/inlining/unique
|
||||||
|
-optimizations method/inlining/tailrecursion
|
||||||
|
-optimizations method/removal/parameter
|
||||||
|
-optimizations code/merging
|
||||||
|
-optimizations code/simplification/variable
|
||||||
|
-allowaccessmodification
|
||||||
|
-repackageclasses ''
|
||||||
|
-keepattributes Exceptions,InnerClasses,Signature,*Annotation*
|
||||||
|
-dontpreverify
|
||||||
|
-keep public class * extends android.app.Activity
|
||||||
|
-keep public class * extends android.app.Application
|
||||||
|
-keep public class * extends android.app.Service
|
||||||
|
-keep public class * extends android.content.BroadcastReceiver
|
||||||
|
-keep public class * extends android.content.ContentProvider
|
||||||
|
-keep public class * extends androidx.fragment.app.Fragment
|
||||||
|
-dontwarn java.awt.Component
|
||||||
|
-dontwarn java.awt.GraphicsEnvironment
|
||||||
|
-dontwarn java.awt.HeadlessException
|
||||||
|
-dontwarn java.awt.Window
|
||||||
|
-dontwarn javax.lang.model.element.Modifier
|
||||||
|
-assumenosideeffects class java.lang.Math {
|
||||||
|
public static double random();
|
||||||
|
public static double sin(...);
|
||||||
|
public static double cos(...);
|
||||||
|
public static double sqrt(...);
|
||||||
|
}
|
||||||
|
-assumenosideeffects public class ** {
|
||||||
|
public boolean is*();
|
||||||
|
public boolean get*();
|
||||||
|
public boolean has*();
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!-- Android 11+ Package Visibility: What this app is allowed to see/access -->
|
||||||
|
<queries>
|
||||||
|
<!-- If other flavors/starters are involved, make them visible here -->
|
||||||
|
<package android:name="org.kenjinx.android"/>
|
||||||
|
|
||||||
|
<!-- General: Make LAUNCHER activities and ACTION_VIEW files resolvable -->
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent>
|
||||||
|
</queries>
|
||||||
|
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.audio.output"
|
||||||
|
android:required="true" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
|
<uses-permission
|
||||||
|
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
||||||
|
tools:ignore="ScopedStorage" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
<!-- Notifications + special-use Foreground Service (Android 14+) -->
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
<!-- Required for startForeground() -->
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
|
||||||
|
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:name=".KenjinxApplication"
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:appCategory="game"
|
||||||
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:isGame="true"
|
||||||
|
android:label="${applicationLabel}"
|
||||||
|
android:supportsRtl="true"
|
||||||
|
android:theme="@style/Theme.KenjinxAndroid"
|
||||||
|
android:largeHeap="true"
|
||||||
|
android:requestLegacyExternalStorage="true"
|
||||||
|
tools:targetApi="31">
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:launchMode="singleTop"
|
||||||
|
android:exported="true"
|
||||||
|
android:screenOrientation="unspecified"
|
||||||
|
android:resizeableActivity="true"
|
||||||
|
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|uiMode"
|
||||||
|
android:hardwareAccelerated="true"
|
||||||
|
android:theme="@style/Theme.KenjinxAndroid">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="org.kenjinx.android.LAUNCH_GAME" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<!--
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="org.kenji.android.action.CREATE_SHORTCUT" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Shortcut Wizard Activity (transparent, freely rotatable) -->
|
||||||
|
<activity
|
||||||
|
android:name=".ShortcutWizardActivity"
|
||||||
|
android:exported="false"
|
||||||
|
android:theme="@style/Theme.KenjinxAndroid.Transparent"
|
||||||
|
android:screenOrientation="unspecified"
|
||||||
|
android:configChanges="orientation|screenSize|keyboardHidden|uiMode" />
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/provider_paths" />
|
||||||
|
</provider>
|
||||||
|
<provider
|
||||||
|
android:name=".providers.DocumentProvider"
|
||||||
|
android:authorities="${applicationId}.providers"
|
||||||
|
android:exported="true"
|
||||||
|
android:grantUriPermissions="true"
|
||||||
|
android:permission="android.permission.MANAGE_DOCUMENTS">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
|
||||||
|
</intent-filter>
|
||||||
|
</provider>
|
||||||
|
<service
|
||||||
|
android:name=".service.EmulationService"
|
||||||
|
android:exported="false"
|
||||||
|
android:stopWithTask="true"
|
||||||
|
android:foregroundServiceType="mediaPlayback" />
|
||||||
|
|
||||||
|
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
# For more information about using CMake with Android Studio, read the
|
||||||
|
# documentation: https://d.android.com/studio/projects/add-native-code.html
|
||||||
|
|
||||||
|
# Sets the minimum version of CMake required to build the native library.
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.31.5)
|
||||||
|
|
||||||
|
# Declares and names the project.
|
||||||
|
|
||||||
|
project("kenjinxjni")
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
adrenotools
|
||||||
|
GIT_REPOSITORY https://github.com/bylaws/libadrenotools.git
|
||||||
|
GIT_TAG 8fae8ce254dfc1344527e05301e43f37dea2df80
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(adrenotools)
|
||||||
|
|
||||||
|
# Creates and names a library, sets it as either STATIC
|
||||||
|
# or SHARED, and provides the relative paths to its source code.
|
||||||
|
# You can define multiple libraries, and CMake builds them for you.
|
||||||
|
# Gradle automatically packages shared libraries with your APK.
|
||||||
|
|
||||||
|
add_library( # Sets the name of the library.
|
||||||
|
kenjinxjni
|
||||||
|
|
||||||
|
# Sets the library as a shared library.
|
||||||
|
SHARED
|
||||||
|
|
||||||
|
# Provides a relative path to your source file(s).
|
||||||
|
vulkan_wrapper.cpp
|
||||||
|
kenjinx.cpp)
|
||||||
|
|
||||||
|
# Searches for a specified prebuilt library and stores the path as a
|
||||||
|
# variable. Because CMake includes system libraries in the search path by
|
||||||
|
# default, you only need to specify the name of the public NDK library
|
||||||
|
# you want to add. CMake verifies that the library exists before
|
||||||
|
# completing its build.
|
||||||
|
|
||||||
|
find_library( # Sets the name of the path variable.
|
||||||
|
log-lib
|
||||||
|
|
||||||
|
# Specifies the name of the NDK library that
|
||||||
|
# you want CMake to locate.
|
||||||
|
log )
|
||||||
|
|
||||||
|
# Specifies libraries CMake should link to your target library. You
|
||||||
|
# can link multiple libraries, such as libraries you define in this
|
||||||
|
# build script, prebuilt third-party libraries, or system libraries.
|
||||||
|
|
||||||
|
target_link_libraries( # Specifies the target library.
|
||||||
|
kenjinxjni
|
||||||
|
# Links the target library to the log library
|
||||||
|
# included in the NDK.
|
||||||
|
${log-lib}
|
||||||
|
-lvulkan
|
||||||
|
-landroid
|
||||||
|
adrenotools
|
||||||
|
)
|
||||||
|
|
||||||
|
# Build external libraries if prebuilt files don't exist
|
||||||
|
set(JNI_PATH ../jniLibs/${CMAKE_ANDROID_ARCH_ABI})
|
||||||
|
cmake_path(ABSOLUTE_PATH JNI_PATH NORMALIZE)
|
||||||
|
|
||||||
|
cmake_path(APPEND JNI_PATH libcrypto.so OUTPUT_VARIABLE LIBCRYPTO_JNI_PATH)
|
||||||
|
cmake_path(APPEND JNI_PATH libssl.so OUTPUT_VARIABLE LIBSSL_JNI_PATH)
|
||||||
|
|
||||||
|
# Add OpenAL
|
||||||
|
add_subdirectory(libraries/openal)
|
||||||
|
set_target_properties(OpenAL PROPERTIES
|
||||||
|
LIBRARY_OUTPUT_DIRECTORY ${JNI_PATH}
|
||||||
|
ARCHIVE_OUTPUT_DIRECTORY ${JNI_PATH}
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY ${JNI_PATH}
|
||||||
|
)
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
// Write C++ code here.
|
||||||
|
//
|
||||||
|
// Do not forget to dynamically load the C++ library into your application.
|
||||||
|
//
|
||||||
|
// For instance,
|
||||||
|
//
|
||||||
|
// In MainActivity.java:
|
||||||
|
// static {
|
||||||
|
// System.loadLibrary("kenjinxjni");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Or, in MainActivity.kt:
|
||||||
|
// companion object {
|
||||||
|
// init {
|
||||||
|
// System.loadLibrary("kenjinxjni")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
#include "kenjinx.h"
|
||||||
|
#include "pthread.h"
|
||||||
|
#include <chrono>
|
||||||
|
#include <csignal>
|
||||||
|
|
||||||
|
|
||||||
|
std::chrono::time_point<std::chrono::steady_clock, std::chrono::nanoseconds> _currentTimePoint;
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
JNIEXPORT jlong JNICALL
|
||||||
|
Java_org_kenjinx_android_NativeHelpers_getNativeWindow(
|
||||||
|
JNIEnv *env,
|
||||||
|
jobject instance,
|
||||||
|
jobject surface) {
|
||||||
|
auto nativeWindow = ANativeWindow_fromSurface(env, surface);
|
||||||
|
return nativeWindow == nullptr ? -1 : (jlong) nativeWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_kenjinx_android_NativeHelpers_releaseNativeWindow(
|
||||||
|
JNIEnv *env,
|
||||||
|
jobject instance,
|
||||||
|
jlong window) {
|
||||||
|
auto nativeWindow = (ANativeWindow *) window;
|
||||||
|
|
||||||
|
if (nativeWindow != nullptr)
|
||||||
|
ANativeWindow_release(nativeWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
long createSurface(long native_surface, long instance) {
|
||||||
|
auto nativeWindow = (ANativeWindow *) native_surface;
|
||||||
|
VkSurfaceKHR surface;
|
||||||
|
auto vkInstance = (VkInstance) instance;
|
||||||
|
auto fpCreateAndroidSurfaceKHR =
|
||||||
|
reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>(vkGetInstanceProcAddr(vkInstance,
|
||||||
|
"vkCreateAndroidSurfaceKHR"));
|
||||||
|
if (fpCreateAndroidSurfaceKHR == nullptr)
|
||||||
|
LOGE("Could not get function pointer to CreateAndroidSurfaceKHR");
|
||||||
|
|
||||||
|
VkAndroidSurfaceCreateInfoKHR info;
|
||||||
|
info.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
|
||||||
|
info.pNext = nullptr;
|
||||||
|
info.flags = 0;
|
||||||
|
info.window = nativeWindow;
|
||||||
|
VK_CHECK(fpCreateAndroidSurfaceKHR(vkInstance, &info, nullptr, &surface));
|
||||||
|
return (long) surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jlong JNICALL
|
||||||
|
Java_org_kenjinx_android_NativeHelpers_getCreateSurfacePtr(
|
||||||
|
JNIEnv *env,
|
||||||
|
jobject instance) {
|
||||||
|
return (jlong) createSurface;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *getStringPointer(
|
||||||
|
JNIEnv *env,
|
||||||
|
jstring jS) {
|
||||||
|
const char *cparam = env->GetStringUTFChars(jS, nullptr);
|
||||||
|
auto len = env->GetStringUTFLength(jS);
|
||||||
|
char *s = new char[len + 1]; //null terminator
|
||||||
|
strcpy(s, cparam);
|
||||||
|
env->ReleaseStringUTFChars(jS, cparam);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
jstring createString(
|
||||||
|
JNIEnv *env,
|
||||||
|
char *ch) {
|
||||||
|
auto str = env->NewStringUTF(ch);
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
jstring createStringFromStdString(
|
||||||
|
JNIEnv *env,
|
||||||
|
std::string s) {
|
||||||
|
auto str = env->NewStringUTF(s.c_str());
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
extern "C"
|
||||||
|
void setRenderingThread() {
|
||||||
|
auto currentId = pthread_self();
|
||||||
|
|
||||||
|
_renderingThreadId = currentId;
|
||||||
|
|
||||||
|
_currentTimePoint = std::chrono::high_resolution_clock::now();
|
||||||
|
}
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_kenjinx_android_MainActivity_initVm(JNIEnv *env, jobject thiz) {
|
||||||
|
JavaVM *vm = nullptr;
|
||||||
|
env->GetJavaVM(&vm);
|
||||||
|
_vm = vm;
|
||||||
|
_mainActivity = thiz;
|
||||||
|
_mainActivityClass = env->GetObjectClass(thiz);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isInitialOrientationFlipped = true;
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
void setCurrentTransform(long native_window, int transform) {
|
||||||
|
if (native_window == 0 || native_window == -1)
|
||||||
|
return;
|
||||||
|
auto nativeWindow = (ANativeWindow *) native_window;
|
||||||
|
|
||||||
|
auto nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_IDENTITY;
|
||||||
|
|
||||||
|
transform = transform >> 1;
|
||||||
|
|
||||||
|
// transform is a valid VkSurfaceTransformFlagBitsKHR
|
||||||
|
switch (transform) {
|
||||||
|
case 0x1:
|
||||||
|
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_IDENTITY;
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_ROTATE_90;
|
||||||
|
break;
|
||||||
|
case 0x4:
|
||||||
|
nativeTransform = isInitialOrientationFlipped
|
||||||
|
? ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_IDENTITY
|
||||||
|
: ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_ROTATE_180;
|
||||||
|
break;
|
||||||
|
case 0x8:
|
||||||
|
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_ROTATE_270;
|
||||||
|
break;
|
||||||
|
case 0x10:
|
||||||
|
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL;
|
||||||
|
break;
|
||||||
|
case 0x20:
|
||||||
|
nativeTransform = static_cast<ANativeWindowTransform>(
|
||||||
|
ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_MIRROR_HORIZONTAL |
|
||||||
|
ANATIVEWINDOW_TRANSFORM_ROTATE_90);
|
||||||
|
break;
|
||||||
|
case 0x40:
|
||||||
|
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL;
|
||||||
|
break;
|
||||||
|
case 0x80:
|
||||||
|
nativeTransform = static_cast<ANativeWindowTransform>(
|
||||||
|
ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_MIRROR_VERTICAL |
|
||||||
|
ANATIVEWINDOW_TRANSFORM_ROTATE_90);
|
||||||
|
break;
|
||||||
|
case 0x100:
|
||||||
|
nativeTransform = ANativeWindowTransform::ANATIVEWINDOW_TRANSFORM_IDENTITY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nativeWindow->perform(nativeWindow, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM,
|
||||||
|
static_cast<int32_t>(nativeTransform));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jlong JNICALL
|
||||||
|
Java_org_kenjinx_android_NativeHelpers_loadDriver(JNIEnv *env, jobject thiz,
|
||||||
|
jstring native_lib_path,
|
||||||
|
jstring private_apps_path,
|
||||||
|
jstring driver_name) {
|
||||||
|
auto libPath = getStringPointer(env, native_lib_path);
|
||||||
|
auto privateAppsPath = getStringPointer(env, private_apps_path);
|
||||||
|
auto driverName = getStringPointer(env, driver_name);
|
||||||
|
|
||||||
|
auto handle = adrenotools_open_libvulkan(
|
||||||
|
RTLD_NOW,
|
||||||
|
ADRENOTOOLS_DRIVER_CUSTOM,
|
||||||
|
nullptr,
|
||||||
|
libPath,
|
||||||
|
privateAppsPath,
|
||||||
|
driverName,
|
||||||
|
nullptr,
|
||||||
|
nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
delete libPath;
|
||||||
|
delete privateAppsPath;
|
||||||
|
delete driverName;
|
||||||
|
|
||||||
|
return (jlong) handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
void debug_break(int code) {
|
||||||
|
if (code >= 3)
|
||||||
|
int r = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_kenjinx_android_NativeHelpers_setTurboMode(JNIEnv *env, jobject thiz, jboolean enable) {
|
||||||
|
adrenotools_set_turbo(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_org_kenjinx_android_NativeHelpers_getMaxSwapInterval(JNIEnv *env, jobject thiz,
|
||||||
|
jlong native_window) {
|
||||||
|
auto nativeWindow = (ANativeWindow *) native_window;
|
||||||
|
|
||||||
|
return nativeWindow->maxSwapInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_org_kenjinx_android_NativeHelpers_getMinSwapInterval(JNIEnv *env, jobject thiz,
|
||||||
|
jlong native_window) {
|
||||||
|
auto nativeWindow = (ANativeWindow *) native_window;
|
||||||
|
|
||||||
|
return nativeWindow->minSwapInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jint JNICALL
|
||||||
|
Java_org_kenjinx_android_NativeHelpers_setSwapInterval(JNIEnv *env, jobject thiz,
|
||||||
|
jlong native_window, jint swap_interval) {
|
||||||
|
auto nativeWindow = (ANativeWindow *) native_window;
|
||||||
|
|
||||||
|
return nativeWindow->setSwapInterval(nativeWindow, swap_interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT jstring JNICALL
|
||||||
|
Java_org_kenjinx_android_NativeHelpers_getStringJava(JNIEnv *env, jobject thiz, jlong ptr) {
|
||||||
|
return createString(env, (char*)ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_kenjinx_android_NativeHelpers_setIsInitialOrientationFlipped(JNIEnv *env, jobject thiz,
|
||||||
|
jboolean is_flipped) {
|
||||||
|
isInitialOrientationFlipped = is_flipped;
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
//
|
||||||
|
// Created by Emmanuel Hansen on 6/19/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef KENJINXNATIVE_KENJINX_H
|
||||||
|
#define KENJINXNATIVE_KENJINX_H
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <exception>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <jni.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <android/log.h>
|
||||||
|
#include <android/native_window.h>
|
||||||
|
#include <android/native_window_jni.h>
|
||||||
|
|
||||||
|
#include "vulkan_wrapper.h"
|
||||||
|
#include <vulkan/vulkan_android.h>
|
||||||
|
#include "adrenotools/driver.h"
|
||||||
|
#include "native_window.h"
|
||||||
|
|
||||||
|
// Android log function wrappers
|
||||||
|
static const char* TAG = "Kenjinx";
|
||||||
|
#define LOGI(...) \
|
||||||
|
((void)__android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__))
|
||||||
|
#define LOGW(...) \
|
||||||
|
((void)__android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__))
|
||||||
|
#define LOGE(...) \
|
||||||
|
((void)__android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__))
|
||||||
|
|
||||||
|
// A macro to pass call to Vulkan and check for return value for success
|
||||||
|
#define CALL_VK(func) \
|
||||||
|
if (VK_SUCCESS != (func)) { \
|
||||||
|
__android_log_print(ANDROID_LOG_ERROR, "Tutorial ", \
|
||||||
|
"Vulkan error. File[%s], line[%d]", __FILE__, \
|
||||||
|
__LINE__); \
|
||||||
|
assert(false); \
|
||||||
|
}
|
||||||
|
|
||||||
|
// A macro to check value is VK_SUCCESS
|
||||||
|
// Used also for non-vulkan functions but return VK_SUCCESS
|
||||||
|
#define VK_CHECK(x) CALL_VK(x)
|
||||||
|
|
||||||
|
#define LoadLib(a) dlopen(a, RTLD_NOW)
|
||||||
|
|
||||||
|
void *_kenjinxNative = nullptr;
|
||||||
|
|
||||||
|
// Kenjinx imported functions
|
||||||
|
bool (*initialize)(char *) = nullptr;
|
||||||
|
|
||||||
|
long _renderingThreadId = 0;
|
||||||
|
JavaVM *_vm = nullptr;
|
||||||
|
jobject _mainActivity = nullptr;
|
||||||
|
jclass _mainActivityClass = nullptr;
|
||||||
|
|
||||||
|
#endif //KENJINXNATIVE_KENJINX_H
|
||||||
Submodule src/KenjinxAndroid/app/src/main/cpp/libraries/adrenotools added at 8fae8ce254
+1
Submodule src/KenjinxAndroid/app/src/main/cpp/libraries/openal added at c41d64c6a3
@@ -0,0 +1,305 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
// Copyright © 2021 The Android Open Source Project
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/* A collection of various types from AOSP that allow us to access private APIs for Native Window which we utilize for emulating the guest SF more accurately */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @url https://cs.android.com/android/platform/superproject/+/android11-release:frameworks/native/libs/nativebase/include/nativebase/nativebase.h;l=29;drc=cb496acbe593326e8d5d563847067d02b2df40ec
|
||||||
|
*/
|
||||||
|
#define ANDROID_NATIVE_UNSIGNED_CAST(x) static_cast<unsigned int>(x)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @url https://cs.android.com/android/platform/superproject/+/android11-release:frameworks/native/libs/nativebase/include/nativebase/nativebase.h;l=34-38;drc=cb496acbe593326e8d5d563847067d02b2df40ec
|
||||||
|
*/
|
||||||
|
#define ANDROID_NATIVE_MAKE_CONSTANT(a, b, c, d) \
|
||||||
|
((ANDROID_NATIVE_UNSIGNED_CAST(a) << 24) | \
|
||||||
|
(ANDROID_NATIVE_UNSIGNED_CAST(b) << 16) | \
|
||||||
|
(ANDROID_NATIVE_UNSIGNED_CAST(c) << 8) | \
|
||||||
|
(ANDROID_NATIVE_UNSIGNED_CAST(d)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @url https://cs.android.com/android/platform/superproject/+/android11-release:frameworks/native/libs/nativewindow/include/system/window.h;l=60;drc=401cda638e7d17f6697b5a65c9a5ad79d056202d
|
||||||
|
*/
|
||||||
|
#define ANDROID_NATIVE_WINDOW_MAGIC ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d')
|
||||||
|
|
||||||
|
constexpr int AndroidNativeWindowMagic{ANDROID_NATIVE_WINDOW_MAGIC};
|
||||||
|
|
||||||
|
#undef ANDROID_NATIVE_WINDOW_MAGIC
|
||||||
|
#undef ANDROID_NATIVE_MAKE_CONSTANT
|
||||||
|
#undef ANDROID_NATIVE_UNSIGNED_CAST
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @url https://cs.android.com/android/platform/superproject/+/android11-release:frameworks/native/libs/nativewindow/include/system/window.h;l=325-331;drc=401cda638e7d17f6697b5a65c9a5ad79d056202d
|
||||||
|
*/
|
||||||
|
constexpr int64_t NativeWindowTimestampAuto{-9223372036854775807LL - 1};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @url https://cs.android.com/android/platform/superproject/+/android11-release:frameworks/native/libs/nativewindow/include/system/window.h;l=198-259;drc=401cda638e7d17f6697b5a65c9a5ad79d056202d
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
NATIVE_WINDOW_CONNECT = 1, /* deprecated */
|
||||||
|
NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
|
||||||
|
NATIVE_WINDOW_SET_CROP = 3, /* private */
|
||||||
|
NATIVE_WINDOW_SET_BUFFER_COUNT = 4,
|
||||||
|
NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6,
|
||||||
|
NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7,
|
||||||
|
NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8,
|
||||||
|
NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */
|
||||||
|
NATIVE_WINDOW_LOCK = 11, /* private */
|
||||||
|
NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */
|
||||||
|
NATIVE_WINDOW_API_CONNECT = 13, /* private */
|
||||||
|
NATIVE_WINDOW_API_DISCONNECT = 14, /* private */
|
||||||
|
NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
|
||||||
|
NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */
|
||||||
|
NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */
|
||||||
|
NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
|
||||||
|
NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19,
|
||||||
|
NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
|
||||||
|
NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21,
|
||||||
|
NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
|
||||||
|
NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23,
|
||||||
|
NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24,
|
||||||
|
NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25,
|
||||||
|
NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26,
|
||||||
|
NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
|
||||||
|
NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
|
||||||
|
NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
|
||||||
|
NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31,
|
||||||
|
NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32,
|
||||||
|
NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33,
|
||||||
|
NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34,
|
||||||
|
NATIVE_WINDOW_SET_AUTO_PREROTATION = 35,
|
||||||
|
NATIVE_WINDOW_GET_LAST_DEQUEUE_START = 36, /* private */
|
||||||
|
NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT = 37, /* private */
|
||||||
|
NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION = 38, /* private */
|
||||||
|
NATIVE_WINDOW_GET_LAST_QUEUE_DURATION = 39, /* private */
|
||||||
|
NATIVE_WINDOW_SET_FRAME_RATE = 40,
|
||||||
|
NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR = 41, /* private */
|
||||||
|
NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR = 42, /* private */
|
||||||
|
NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR = 43, /* private */
|
||||||
|
NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR = 44, /* private */
|
||||||
|
NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, /* private */
|
||||||
|
NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */
|
||||||
|
NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */
|
||||||
|
NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2 = 50, /* private */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @url https://cs.android.com/android/platform/superproject/+/android11-release:frameworks/native/libs/nativebase/include/nativebase/nativebase.h;l=43-56;drc=cb496acbe593326e8d5d563847067d02b2df40ec
|
||||||
|
*/
|
||||||
|
struct android_native_base_t {
|
||||||
|
int magic;
|
||||||
|
int version;
|
||||||
|
void *reserved[4];
|
||||||
|
|
||||||
|
void (*incRef)(android_native_base_t *);
|
||||||
|
|
||||||
|
void (*decRef)(android_native_base_t *);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @url https://cs.android.com/android/platform/superproject/+/android11-release:frameworks/native/libs/nativewindow/include/system/window.h;l=341-560;drc=401cda638e7d17f6697b5a65c9a5ad79d056202d
|
||||||
|
*/
|
||||||
|
struct ANativeWindow {
|
||||||
|
struct android_native_base_t common;
|
||||||
|
|
||||||
|
/* flags describing some attributes of this surface or its updater */
|
||||||
|
const uint32_t flags;
|
||||||
|
|
||||||
|
/* min swap interval supported by this updated */
|
||||||
|
const int minSwapInterval;
|
||||||
|
|
||||||
|
/* max swap interval supported by this updated */
|
||||||
|
const int maxSwapInterval;
|
||||||
|
|
||||||
|
/* horizontal and vertical resolution in DPI */
|
||||||
|
const float xdpi;
|
||||||
|
const float ydpi;
|
||||||
|
|
||||||
|
/* Some storage reserved for the OEM's driver. */
|
||||||
|
intptr_t oem[4];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the swap interval for this surface.
|
||||||
|
*
|
||||||
|
* Returns 0 on success or -errno on error.
|
||||||
|
*/
|
||||||
|
int (*setSwapInterval)(struct ANativeWindow *window,
|
||||||
|
int interval);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hook called by EGL to acquire a buffer. After this call, the buffer
|
||||||
|
* is not locked, so its content cannot be modified. This call may block if
|
||||||
|
* no buffers are available.
|
||||||
|
*
|
||||||
|
* The window holds a reference to the buffer between dequeueBuffer and
|
||||||
|
* either queueBuffer or cancelBuffer, so clients only need their own
|
||||||
|
* reference if they might use the buffer after queueing or canceling it.
|
||||||
|
* Holding a reference to a buffer after queueing or canceling it is only
|
||||||
|
* allowed if a specific buffer count has been set.
|
||||||
|
*
|
||||||
|
* Returns 0 on success or -errno on error.
|
||||||
|
*
|
||||||
|
* XXX: This function is deprecated. It will continue to work for some
|
||||||
|
* time for binary compatibility, but the new dequeueBuffer function that
|
||||||
|
* outputs a fence file descriptor should be used in its place.
|
||||||
|
*/
|
||||||
|
int (*dequeueBuffer_DEPRECATED)(struct ANativeWindow *window,
|
||||||
|
struct ANativeWindowBuffer **buffer);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hook called by EGL to lock a buffer. This MUST be called before modifying
|
||||||
|
* the content of a buffer. The buffer must have been acquired with
|
||||||
|
* dequeueBuffer first.
|
||||||
|
*
|
||||||
|
* Returns 0 on success or -errno on error.
|
||||||
|
*
|
||||||
|
* XXX: This function is deprecated. It will continue to work for some
|
||||||
|
* time for binary compatibility, but it is essentially a no-op, and calls
|
||||||
|
* to it should be removed.
|
||||||
|
*/
|
||||||
|
int (*lockBuffer_DEPRECATED)(struct ANativeWindow *window,
|
||||||
|
struct ANativeWindowBuffer *buffer);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hook called by EGL when modifications to the render buffer are done.
|
||||||
|
* This unlocks and post the buffer.
|
||||||
|
*
|
||||||
|
* The window holds a reference to the buffer between dequeueBuffer and
|
||||||
|
* either queueBuffer or cancelBuffer, so clients only need their own
|
||||||
|
* reference if they might use the buffer after queueing or canceling it.
|
||||||
|
* Holding a reference to a buffer after queueing or canceling it is only
|
||||||
|
* allowed if a specific buffer count has been set.
|
||||||
|
*
|
||||||
|
* Buffers MUST be queued in the same order than they were dequeued.
|
||||||
|
*
|
||||||
|
* Returns 0 on success or -errno on error.
|
||||||
|
*
|
||||||
|
* XXX: This function is deprecated. It will continue to work for some
|
||||||
|
* time for binary compatibility, but the new queueBuffer function that
|
||||||
|
* takes a fence file descriptor should be used in its place (pass a value
|
||||||
|
* of -1 for the fence file descriptor if there is no valid one to pass).
|
||||||
|
*/
|
||||||
|
int (*queueBuffer_DEPRECATED)(struct ANativeWindow *window,
|
||||||
|
struct ANativeWindowBuffer *buffer);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hook used to retrieve information about the native window.
|
||||||
|
*
|
||||||
|
* Returns 0 on success or -errno on error.
|
||||||
|
*/
|
||||||
|
int (*query)(const struct ANativeWindow *window,
|
||||||
|
int what, int *value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hook used to perform various operations on the surface.
|
||||||
|
* (*perform)() is a generic mechanism to add functionality to
|
||||||
|
* ANativeWindow while keeping backward binary compatibility.
|
||||||
|
*
|
||||||
|
* DO NOT CALL THIS HOOK DIRECTLY. Instead, use the helper functions
|
||||||
|
* defined below.
|
||||||
|
*
|
||||||
|
* (*perform)() returns -ENOENT if the 'what' parameter is not supported
|
||||||
|
* by the surface's implementation.
|
||||||
|
*
|
||||||
|
* See above for a list of valid operations, such as
|
||||||
|
* NATIVE_WINDOW_SET_USAGE or NATIVE_WINDOW_CONNECT
|
||||||
|
*/
|
||||||
|
int (*perform)(struct ANativeWindow *window,
|
||||||
|
int operation, ...);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hook used to cancel a buffer that has been dequeued.
|
||||||
|
* No synchronization is performed between dequeue() and cancel(), so
|
||||||
|
* either external synchronization is needed, or these functions must be
|
||||||
|
* called from the same thread.
|
||||||
|
*
|
||||||
|
* The window holds a reference to the buffer between dequeueBuffer and
|
||||||
|
* either queueBuffer or cancelBuffer, so clients only need their own
|
||||||
|
* reference if they might use the buffer after queueing or canceling it.
|
||||||
|
* Holding a reference to a buffer after queueing or canceling it is only
|
||||||
|
* allowed if a specific buffer count has been set.
|
||||||
|
*
|
||||||
|
* XXX: This function is deprecated. It will continue to work for some
|
||||||
|
* time for binary compatibility, but the new cancelBuffer function that
|
||||||
|
* takes a fence file descriptor should be used in its place (pass a value
|
||||||
|
* of -1 for the fence file descriptor if there is no valid one to pass).
|
||||||
|
*/
|
||||||
|
int (*cancelBuffer_DEPRECATED)(struct ANativeWindow *window,
|
||||||
|
struct ANativeWindowBuffer *buffer);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hook called by EGL to acquire a buffer. This call may block if no
|
||||||
|
* buffers are available.
|
||||||
|
*
|
||||||
|
* The window holds a reference to the buffer between dequeueBuffer and
|
||||||
|
* either queueBuffer or cancelBuffer, so clients only need their own
|
||||||
|
* reference if they might use the buffer after queueing or canceling it.
|
||||||
|
* Holding a reference to a buffer after queueing or canceling it is only
|
||||||
|
* allowed if a specific buffer count has been set.
|
||||||
|
*
|
||||||
|
* The libsync fence file descriptor returned in the int pointed to by the
|
||||||
|
* fenceFd argument will refer to the fence that must signal before the
|
||||||
|
* dequeued buffer may be written to. A value of -1 indicates that the
|
||||||
|
* caller may access the buffer immediately without waiting on a fence. If
|
||||||
|
* a valid file descriptor is returned (i.e. any value except -1) then the
|
||||||
|
* caller is responsible for closing the file descriptor.
|
||||||
|
*
|
||||||
|
* Returns 0 on success or -errno on error.
|
||||||
|
*/
|
||||||
|
int (*dequeueBuffer)(struct ANativeWindow *window,
|
||||||
|
struct ANativeWindowBuffer **buffer, int *fenceFd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hook called by EGL when modifications to the render buffer are done.
|
||||||
|
* This unlocks and post the buffer.
|
||||||
|
*
|
||||||
|
* The window holds a reference to the buffer between dequeueBuffer and
|
||||||
|
* either queueBuffer or cancelBuffer, so clients only need their own
|
||||||
|
* reference if they might use the buffer after queueing or canceling it.
|
||||||
|
* Holding a reference to a buffer after queueing or canceling it is only
|
||||||
|
* allowed if a specific buffer count has been set.
|
||||||
|
*
|
||||||
|
* The fenceFd argument specifies a libsync fence file descriptor for a
|
||||||
|
* fence that must signal before the buffer can be accessed. If the buffer
|
||||||
|
* can be accessed immediately then a value of -1 should be used. The
|
||||||
|
* caller must not use the file descriptor after it is passed to
|
||||||
|
* queueBuffer, and the ANativeWindow implementation is responsible for
|
||||||
|
* closing it.
|
||||||
|
*
|
||||||
|
* Returns 0 on success or -errno on error.
|
||||||
|
*/
|
||||||
|
int (*queueBuffer)(struct ANativeWindow *window,
|
||||||
|
struct ANativeWindowBuffer *buffer, int fenceFd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hook used to cancel a buffer that has been dequeued.
|
||||||
|
* No synchronization is performed between dequeue() and cancel(), so
|
||||||
|
* either external synchronization is needed, or these functions must be
|
||||||
|
* called from the same thread.
|
||||||
|
*
|
||||||
|
* The window holds a reference to the buffer between dequeueBuffer and
|
||||||
|
* either queueBuffer or cancelBuffer, so clients only need their own
|
||||||
|
* reference if they might use the buffer after queueing or canceling it.
|
||||||
|
* Holding a reference to a buffer after queueing or canceling it is only
|
||||||
|
* allowed if a specific buffer count has been set.
|
||||||
|
*
|
||||||
|
* The fenceFd argument specifies a libsync fence file decsriptor for a
|
||||||
|
* fence that must signal before the buffer can be accessed. If the buffer
|
||||||
|
* can be accessed immediately then a value of -1 should be used.
|
||||||
|
*
|
||||||
|
* Note that if the client has not waited on the fence that was returned
|
||||||
|
* from dequeueBuffer, that same fence should be passed to cancelBuffer to
|
||||||
|
* ensure that future uses of the buffer are preceded by a wait on that
|
||||||
|
* fence. The caller must not use the file descriptor after it is passed
|
||||||
|
* to cancelBuffer, and the ANativeWindow implementation is responsible for
|
||||||
|
* closing it.
|
||||||
|
*
|
||||||
|
* Returns 0 on success or -errno on error.
|
||||||
|
*/
|
||||||
|
int (*cancelBuffer)(struct ANativeWindow *window,
|
||||||
|
struct ANativeWindowBuffer *buffer, int fenceFd);
|
||||||
|
};
|
||||||
@@ -0,0 +1,404 @@
|
|||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// This file is generated.
|
||||||
|
#include "vulkan_wrapper.h"
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
int InitVulkan(void) {
|
||||||
|
void* libvulkan = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
|
||||||
|
if (!libvulkan)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Vulkan supported, set function addresses
|
||||||
|
vkCreateInstance = reinterpret_cast<PFN_vkCreateInstance>(dlsym(libvulkan, "vkCreateInstance"));
|
||||||
|
vkDestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(dlsym(libvulkan, "vkDestroyInstance"));
|
||||||
|
vkEnumeratePhysicalDevices = reinterpret_cast<PFN_vkEnumeratePhysicalDevices>(dlsym(libvulkan, "vkEnumeratePhysicalDevices"));
|
||||||
|
vkGetPhysicalDeviceFeatures = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures>(dlsym(libvulkan, "vkGetPhysicalDeviceFeatures"));
|
||||||
|
vkGetPhysicalDeviceFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties>(dlsym(libvulkan, "vkGetPhysicalDeviceFormatProperties"));
|
||||||
|
vkGetPhysicalDeviceImageFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceImageFormatProperties>(dlsym(libvulkan, "vkGetPhysicalDeviceImageFormatProperties"));
|
||||||
|
vkGetPhysicalDeviceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(dlsym(libvulkan, "vkGetPhysicalDeviceProperties"));
|
||||||
|
vkGetPhysicalDeviceQueueFamilyProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties>(dlsym(libvulkan, "vkGetPhysicalDeviceQueueFamilyProperties"));
|
||||||
|
vkGetPhysicalDeviceMemoryProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(dlsym(libvulkan, "vkGetPhysicalDeviceMemoryProperties"));
|
||||||
|
vkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(dlsym(libvulkan, "vkGetInstanceProcAddr"));
|
||||||
|
vkGetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(dlsym(libvulkan, "vkGetDeviceProcAddr"));
|
||||||
|
vkCreateDevice = reinterpret_cast<PFN_vkCreateDevice>(dlsym(libvulkan, "vkCreateDevice"));
|
||||||
|
vkDestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(dlsym(libvulkan, "vkDestroyDevice"));
|
||||||
|
vkEnumerateInstanceExtensionProperties = reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(dlsym(libvulkan, "vkEnumerateInstanceExtensionProperties"));
|
||||||
|
vkEnumerateDeviceExtensionProperties = reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(dlsym(libvulkan, "vkEnumerateDeviceExtensionProperties"));
|
||||||
|
vkEnumerateInstanceLayerProperties = reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(dlsym(libvulkan, "vkEnumerateInstanceLayerProperties"));
|
||||||
|
vkEnumerateDeviceLayerProperties = reinterpret_cast<PFN_vkEnumerateDeviceLayerProperties>(dlsym(libvulkan, "vkEnumerateDeviceLayerProperties"));
|
||||||
|
vkGetDeviceQueue = reinterpret_cast<PFN_vkGetDeviceQueue>(dlsym(libvulkan, "vkGetDeviceQueue"));
|
||||||
|
vkQueueSubmit = reinterpret_cast<PFN_vkQueueSubmit>(dlsym(libvulkan, "vkQueueSubmit"));
|
||||||
|
vkQueueWaitIdle = reinterpret_cast<PFN_vkQueueWaitIdle>(dlsym(libvulkan, "vkQueueWaitIdle"));
|
||||||
|
vkDeviceWaitIdle = reinterpret_cast<PFN_vkDeviceWaitIdle>(dlsym(libvulkan, "vkDeviceWaitIdle"));
|
||||||
|
vkAllocateMemory = reinterpret_cast<PFN_vkAllocateMemory>(dlsym(libvulkan, "vkAllocateMemory"));
|
||||||
|
vkFreeMemory = reinterpret_cast<PFN_vkFreeMemory>(dlsym(libvulkan, "vkFreeMemory"));
|
||||||
|
vkMapMemory = reinterpret_cast<PFN_vkMapMemory>(dlsym(libvulkan, "vkMapMemory"));
|
||||||
|
vkUnmapMemory = reinterpret_cast<PFN_vkUnmapMemory>(dlsym(libvulkan, "vkUnmapMemory"));
|
||||||
|
vkFlushMappedMemoryRanges = reinterpret_cast<PFN_vkFlushMappedMemoryRanges>(dlsym(libvulkan, "vkFlushMappedMemoryRanges"));
|
||||||
|
vkInvalidateMappedMemoryRanges = reinterpret_cast<PFN_vkInvalidateMappedMemoryRanges>(dlsym(libvulkan, "vkInvalidateMappedMemoryRanges"));
|
||||||
|
vkGetDeviceMemoryCommitment = reinterpret_cast<PFN_vkGetDeviceMemoryCommitment>(dlsym(libvulkan, "vkGetDeviceMemoryCommitment"));
|
||||||
|
vkBindBufferMemory = reinterpret_cast<PFN_vkBindBufferMemory>(dlsym(libvulkan, "vkBindBufferMemory"));
|
||||||
|
vkBindImageMemory = reinterpret_cast<PFN_vkBindImageMemory>(dlsym(libvulkan, "vkBindImageMemory"));
|
||||||
|
vkGetBufferMemoryRequirements = reinterpret_cast<PFN_vkGetBufferMemoryRequirements>(dlsym(libvulkan, "vkGetBufferMemoryRequirements"));
|
||||||
|
vkGetImageMemoryRequirements = reinterpret_cast<PFN_vkGetImageMemoryRequirements>(dlsym(libvulkan, "vkGetImageMemoryRequirements"));
|
||||||
|
vkGetImageSparseMemoryRequirements = reinterpret_cast<PFN_vkGetImageSparseMemoryRequirements>(dlsym(libvulkan, "vkGetImageSparseMemoryRequirements"));
|
||||||
|
vkGetPhysicalDeviceSparseImageFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceSparseImageFormatProperties>(dlsym(libvulkan, "vkGetPhysicalDeviceSparseImageFormatProperties"));
|
||||||
|
vkQueueBindSparse = reinterpret_cast<PFN_vkQueueBindSparse>(dlsym(libvulkan, "vkQueueBindSparse"));
|
||||||
|
vkCreateFence = reinterpret_cast<PFN_vkCreateFence>(dlsym(libvulkan, "vkCreateFence"));
|
||||||
|
vkDestroyFence = reinterpret_cast<PFN_vkDestroyFence>(dlsym(libvulkan, "vkDestroyFence"));
|
||||||
|
vkResetFences = reinterpret_cast<PFN_vkResetFences>(dlsym(libvulkan, "vkResetFences"));
|
||||||
|
vkGetFenceStatus = reinterpret_cast<PFN_vkGetFenceStatus>(dlsym(libvulkan, "vkGetFenceStatus"));
|
||||||
|
vkWaitForFences = reinterpret_cast<PFN_vkWaitForFences>(dlsym(libvulkan, "vkWaitForFences"));
|
||||||
|
vkCreateSemaphore = reinterpret_cast<PFN_vkCreateSemaphore>(dlsym(libvulkan, "vkCreateSemaphore"));
|
||||||
|
vkDestroySemaphore = reinterpret_cast<PFN_vkDestroySemaphore>(dlsym(libvulkan, "vkDestroySemaphore"));
|
||||||
|
vkCreateEvent = reinterpret_cast<PFN_vkCreateEvent>(dlsym(libvulkan, "vkCreateEvent"));
|
||||||
|
vkDestroyEvent = reinterpret_cast<PFN_vkDestroyEvent>(dlsym(libvulkan, "vkDestroyEvent"));
|
||||||
|
vkGetEventStatus = reinterpret_cast<PFN_vkGetEventStatus>(dlsym(libvulkan, "vkGetEventStatus"));
|
||||||
|
vkSetEvent = reinterpret_cast<PFN_vkSetEvent>(dlsym(libvulkan, "vkSetEvent"));
|
||||||
|
vkResetEvent = reinterpret_cast<PFN_vkResetEvent>(dlsym(libvulkan, "vkResetEvent"));
|
||||||
|
vkCreateQueryPool = reinterpret_cast<PFN_vkCreateQueryPool>(dlsym(libvulkan, "vkCreateQueryPool"));
|
||||||
|
vkDestroyQueryPool = reinterpret_cast<PFN_vkDestroyQueryPool>(dlsym(libvulkan, "vkDestroyQueryPool"));
|
||||||
|
vkGetQueryPoolResults = reinterpret_cast<PFN_vkGetQueryPoolResults>(dlsym(libvulkan, "vkGetQueryPoolResults"));
|
||||||
|
vkCreateBuffer = reinterpret_cast<PFN_vkCreateBuffer>(dlsym(libvulkan, "vkCreateBuffer"));
|
||||||
|
vkDestroyBuffer = reinterpret_cast<PFN_vkDestroyBuffer>(dlsym(libvulkan, "vkDestroyBuffer"));
|
||||||
|
vkCreateBufferView = reinterpret_cast<PFN_vkCreateBufferView>(dlsym(libvulkan, "vkCreateBufferView"));
|
||||||
|
vkDestroyBufferView = reinterpret_cast<PFN_vkDestroyBufferView>(dlsym(libvulkan, "vkDestroyBufferView"));
|
||||||
|
vkCreateImage = reinterpret_cast<PFN_vkCreateImage>(dlsym(libvulkan, "vkCreateImage"));
|
||||||
|
vkDestroyImage = reinterpret_cast<PFN_vkDestroyImage>(dlsym(libvulkan, "vkDestroyImage"));
|
||||||
|
vkGetImageSubresourceLayout = reinterpret_cast<PFN_vkGetImageSubresourceLayout>(dlsym(libvulkan, "vkGetImageSubresourceLayout"));
|
||||||
|
vkCreateImageView = reinterpret_cast<PFN_vkCreateImageView>(dlsym(libvulkan, "vkCreateImageView"));
|
||||||
|
vkDestroyImageView = reinterpret_cast<PFN_vkDestroyImageView>(dlsym(libvulkan, "vkDestroyImageView"));
|
||||||
|
vkCreateShaderModule = reinterpret_cast<PFN_vkCreateShaderModule>(dlsym(libvulkan, "vkCreateShaderModule"));
|
||||||
|
vkDestroyShaderModule = reinterpret_cast<PFN_vkDestroyShaderModule>(dlsym(libvulkan, "vkDestroyShaderModule"));
|
||||||
|
vkCreatePipelineCache = reinterpret_cast<PFN_vkCreatePipelineCache>(dlsym(libvulkan, "vkCreatePipelineCache"));
|
||||||
|
vkDestroyPipelineCache = reinterpret_cast<PFN_vkDestroyPipelineCache>(dlsym(libvulkan, "vkDestroyPipelineCache"));
|
||||||
|
vkGetPipelineCacheData = reinterpret_cast<PFN_vkGetPipelineCacheData>(dlsym(libvulkan, "vkGetPipelineCacheData"));
|
||||||
|
vkMergePipelineCaches = reinterpret_cast<PFN_vkMergePipelineCaches>(dlsym(libvulkan, "vkMergePipelineCaches"));
|
||||||
|
vkCreateGraphicsPipelines = reinterpret_cast<PFN_vkCreateGraphicsPipelines>(dlsym(libvulkan, "vkCreateGraphicsPipelines"));
|
||||||
|
vkCreateComputePipelines = reinterpret_cast<PFN_vkCreateComputePipelines>(dlsym(libvulkan, "vkCreateComputePipelines"));
|
||||||
|
vkDestroyPipeline = reinterpret_cast<PFN_vkDestroyPipeline>(dlsym(libvulkan, "vkDestroyPipeline"));
|
||||||
|
vkCreatePipelineLayout = reinterpret_cast<PFN_vkCreatePipelineLayout>(dlsym(libvulkan, "vkCreatePipelineLayout"));
|
||||||
|
vkDestroyPipelineLayout = reinterpret_cast<PFN_vkDestroyPipelineLayout>(dlsym(libvulkan, "vkDestroyPipelineLayout"));
|
||||||
|
vkCreateSampler = reinterpret_cast<PFN_vkCreateSampler>(dlsym(libvulkan, "vkCreateSampler"));
|
||||||
|
vkDestroySampler = reinterpret_cast<PFN_vkDestroySampler>(dlsym(libvulkan, "vkDestroySampler"));
|
||||||
|
vkCreateDescriptorSetLayout = reinterpret_cast<PFN_vkCreateDescriptorSetLayout>(dlsym(libvulkan, "vkCreateDescriptorSetLayout"));
|
||||||
|
vkDestroyDescriptorSetLayout = reinterpret_cast<PFN_vkDestroyDescriptorSetLayout>(dlsym(libvulkan, "vkDestroyDescriptorSetLayout"));
|
||||||
|
vkCreateDescriptorPool = reinterpret_cast<PFN_vkCreateDescriptorPool>(dlsym(libvulkan, "vkCreateDescriptorPool"));
|
||||||
|
vkDestroyDescriptorPool = reinterpret_cast<PFN_vkDestroyDescriptorPool>(dlsym(libvulkan, "vkDestroyDescriptorPool"));
|
||||||
|
vkResetDescriptorPool = reinterpret_cast<PFN_vkResetDescriptorPool>(dlsym(libvulkan, "vkResetDescriptorPool"));
|
||||||
|
vkAllocateDescriptorSets = reinterpret_cast<PFN_vkAllocateDescriptorSets>(dlsym(libvulkan, "vkAllocateDescriptorSets"));
|
||||||
|
vkFreeDescriptorSets = reinterpret_cast<PFN_vkFreeDescriptorSets>(dlsym(libvulkan, "vkFreeDescriptorSets"));
|
||||||
|
vkUpdateDescriptorSets = reinterpret_cast<PFN_vkUpdateDescriptorSets>(dlsym(libvulkan, "vkUpdateDescriptorSets"));
|
||||||
|
vkCreateFramebuffer = reinterpret_cast<PFN_vkCreateFramebuffer>(dlsym(libvulkan, "vkCreateFramebuffer"));
|
||||||
|
vkDestroyFramebuffer = reinterpret_cast<PFN_vkDestroyFramebuffer>(dlsym(libvulkan, "vkDestroyFramebuffer"));
|
||||||
|
vkCreateRenderPass = reinterpret_cast<PFN_vkCreateRenderPass>(dlsym(libvulkan, "vkCreateRenderPass"));
|
||||||
|
vkDestroyRenderPass = reinterpret_cast<PFN_vkDestroyRenderPass>(dlsym(libvulkan, "vkDestroyRenderPass"));
|
||||||
|
vkGetRenderAreaGranularity = reinterpret_cast<PFN_vkGetRenderAreaGranularity>(dlsym(libvulkan, "vkGetRenderAreaGranularity"));
|
||||||
|
vkCreateCommandPool = reinterpret_cast<PFN_vkCreateCommandPool>(dlsym(libvulkan, "vkCreateCommandPool"));
|
||||||
|
vkDestroyCommandPool = reinterpret_cast<PFN_vkDestroyCommandPool>(dlsym(libvulkan, "vkDestroyCommandPool"));
|
||||||
|
vkResetCommandPool = reinterpret_cast<PFN_vkResetCommandPool>(dlsym(libvulkan, "vkResetCommandPool"));
|
||||||
|
vkAllocateCommandBuffers = reinterpret_cast<PFN_vkAllocateCommandBuffers>(dlsym(libvulkan, "vkAllocateCommandBuffers"));
|
||||||
|
vkFreeCommandBuffers = reinterpret_cast<PFN_vkFreeCommandBuffers>(dlsym(libvulkan, "vkFreeCommandBuffers"));
|
||||||
|
vkBeginCommandBuffer = reinterpret_cast<PFN_vkBeginCommandBuffer>(dlsym(libvulkan, "vkBeginCommandBuffer"));
|
||||||
|
vkEndCommandBuffer = reinterpret_cast<PFN_vkEndCommandBuffer>(dlsym(libvulkan, "vkEndCommandBuffer"));
|
||||||
|
vkResetCommandBuffer = reinterpret_cast<PFN_vkResetCommandBuffer>(dlsym(libvulkan, "vkResetCommandBuffer"));
|
||||||
|
vkCmdBindPipeline = reinterpret_cast<PFN_vkCmdBindPipeline>(dlsym(libvulkan, "vkCmdBindPipeline"));
|
||||||
|
vkCmdSetViewport = reinterpret_cast<PFN_vkCmdSetViewport>(dlsym(libvulkan, "vkCmdSetViewport"));
|
||||||
|
vkCmdSetScissor = reinterpret_cast<PFN_vkCmdSetScissor>(dlsym(libvulkan, "vkCmdSetScissor"));
|
||||||
|
vkCmdSetLineWidth = reinterpret_cast<PFN_vkCmdSetLineWidth>(dlsym(libvulkan, "vkCmdSetLineWidth"));
|
||||||
|
vkCmdSetDepthBias = reinterpret_cast<PFN_vkCmdSetDepthBias>(dlsym(libvulkan, "vkCmdSetDepthBias"));
|
||||||
|
vkCmdSetBlendConstants = reinterpret_cast<PFN_vkCmdSetBlendConstants>(dlsym(libvulkan, "vkCmdSetBlendConstants"));
|
||||||
|
vkCmdSetDepthBounds = reinterpret_cast<PFN_vkCmdSetDepthBounds>(dlsym(libvulkan, "vkCmdSetDepthBounds"));
|
||||||
|
vkCmdSetStencilCompareMask = reinterpret_cast<PFN_vkCmdSetStencilCompareMask>(dlsym(libvulkan, "vkCmdSetStencilCompareMask"));
|
||||||
|
vkCmdSetStencilWriteMask = reinterpret_cast<PFN_vkCmdSetStencilWriteMask>(dlsym(libvulkan, "vkCmdSetStencilWriteMask"));
|
||||||
|
vkCmdSetStencilReference = reinterpret_cast<PFN_vkCmdSetStencilReference>(dlsym(libvulkan, "vkCmdSetStencilReference"));
|
||||||
|
vkCmdBindDescriptorSets = reinterpret_cast<PFN_vkCmdBindDescriptorSets>(dlsym(libvulkan, "vkCmdBindDescriptorSets"));
|
||||||
|
vkCmdBindIndexBuffer = reinterpret_cast<PFN_vkCmdBindIndexBuffer>(dlsym(libvulkan, "vkCmdBindIndexBuffer"));
|
||||||
|
vkCmdBindVertexBuffers = reinterpret_cast<PFN_vkCmdBindVertexBuffers>(dlsym(libvulkan, "vkCmdBindVertexBuffers"));
|
||||||
|
vkCmdDraw = reinterpret_cast<PFN_vkCmdDraw>(dlsym(libvulkan, "vkCmdDraw"));
|
||||||
|
vkCmdDrawIndexed = reinterpret_cast<PFN_vkCmdDrawIndexed>(dlsym(libvulkan, "vkCmdDrawIndexed"));
|
||||||
|
vkCmdDrawIndirect = reinterpret_cast<PFN_vkCmdDrawIndirect>(dlsym(libvulkan, "vkCmdDrawIndirect"));
|
||||||
|
vkCmdDrawIndexedIndirect = reinterpret_cast<PFN_vkCmdDrawIndexedIndirect>(dlsym(libvulkan, "vkCmdDrawIndexedIndirect"));
|
||||||
|
vkCmdDispatch = reinterpret_cast<PFN_vkCmdDispatch>(dlsym(libvulkan, "vkCmdDispatch"));
|
||||||
|
vkCmdDispatchIndirect = reinterpret_cast<PFN_vkCmdDispatchIndirect>(dlsym(libvulkan, "vkCmdDispatchIndirect"));
|
||||||
|
vkCmdCopyBuffer = reinterpret_cast<PFN_vkCmdCopyBuffer>(dlsym(libvulkan, "vkCmdCopyBuffer"));
|
||||||
|
vkCmdCopyImage = reinterpret_cast<PFN_vkCmdCopyImage>(dlsym(libvulkan, "vkCmdCopyImage"));
|
||||||
|
vkCmdBlitImage = reinterpret_cast<PFN_vkCmdBlitImage>(dlsym(libvulkan, "vkCmdBlitImage"));
|
||||||
|
vkCmdCopyBufferToImage = reinterpret_cast<PFN_vkCmdCopyBufferToImage>(dlsym(libvulkan, "vkCmdCopyBufferToImage"));
|
||||||
|
vkCmdCopyImageToBuffer = reinterpret_cast<PFN_vkCmdCopyImageToBuffer>(dlsym(libvulkan, "vkCmdCopyImageToBuffer"));
|
||||||
|
vkCmdUpdateBuffer = reinterpret_cast<PFN_vkCmdUpdateBuffer>(dlsym(libvulkan, "vkCmdUpdateBuffer"));
|
||||||
|
vkCmdFillBuffer = reinterpret_cast<PFN_vkCmdFillBuffer>(dlsym(libvulkan, "vkCmdFillBuffer"));
|
||||||
|
vkCmdClearColorImage = reinterpret_cast<PFN_vkCmdClearColorImage>(dlsym(libvulkan, "vkCmdClearColorImage"));
|
||||||
|
vkCmdClearDepthStencilImage = reinterpret_cast<PFN_vkCmdClearDepthStencilImage>(dlsym(libvulkan, "vkCmdClearDepthStencilImage"));
|
||||||
|
vkCmdClearAttachments = reinterpret_cast<PFN_vkCmdClearAttachments>(dlsym(libvulkan, "vkCmdClearAttachments"));
|
||||||
|
vkCmdResolveImage = reinterpret_cast<PFN_vkCmdResolveImage>(dlsym(libvulkan, "vkCmdResolveImage"));
|
||||||
|
vkCmdSetEvent = reinterpret_cast<PFN_vkCmdSetEvent>(dlsym(libvulkan, "vkCmdSetEvent"));
|
||||||
|
vkCmdResetEvent = reinterpret_cast<PFN_vkCmdResetEvent>(dlsym(libvulkan, "vkCmdResetEvent"));
|
||||||
|
vkCmdWaitEvents = reinterpret_cast<PFN_vkCmdWaitEvents>(dlsym(libvulkan, "vkCmdWaitEvents"));
|
||||||
|
vkCmdPipelineBarrier = reinterpret_cast<PFN_vkCmdPipelineBarrier>(dlsym(libvulkan, "vkCmdPipelineBarrier"));
|
||||||
|
vkCmdBeginQuery = reinterpret_cast<PFN_vkCmdBeginQuery>(dlsym(libvulkan, "vkCmdBeginQuery"));
|
||||||
|
vkCmdEndQuery = reinterpret_cast<PFN_vkCmdEndQuery>(dlsym(libvulkan, "vkCmdEndQuery"));
|
||||||
|
vkCmdResetQueryPool = reinterpret_cast<PFN_vkCmdResetQueryPool>(dlsym(libvulkan, "vkCmdResetQueryPool"));
|
||||||
|
vkCmdWriteTimestamp = reinterpret_cast<PFN_vkCmdWriteTimestamp>(dlsym(libvulkan, "vkCmdWriteTimestamp"));
|
||||||
|
vkCmdCopyQueryPoolResults = reinterpret_cast<PFN_vkCmdCopyQueryPoolResults>(dlsym(libvulkan, "vkCmdCopyQueryPoolResults"));
|
||||||
|
vkCmdPushConstants = reinterpret_cast<PFN_vkCmdPushConstants>(dlsym(libvulkan, "vkCmdPushConstants"));
|
||||||
|
vkCmdBeginRenderPass = reinterpret_cast<PFN_vkCmdBeginRenderPass>(dlsym(libvulkan, "vkCmdBeginRenderPass"));
|
||||||
|
vkCmdNextSubpass = reinterpret_cast<PFN_vkCmdNextSubpass>(dlsym(libvulkan, "vkCmdNextSubpass"));
|
||||||
|
vkCmdEndRenderPass = reinterpret_cast<PFN_vkCmdEndRenderPass>(dlsym(libvulkan, "vkCmdEndRenderPass"));
|
||||||
|
vkCmdExecuteCommands = reinterpret_cast<PFN_vkCmdExecuteCommands>(dlsym(libvulkan, "vkCmdExecuteCommands"));
|
||||||
|
vkDestroySurfaceKHR = reinterpret_cast<PFN_vkDestroySurfaceKHR>(dlsym(libvulkan, "vkDestroySurfaceKHR"));
|
||||||
|
vkGetPhysicalDeviceSurfaceSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceSupportKHR>(dlsym(libvulkan, "vkGetPhysicalDeviceSurfaceSupportKHR"));
|
||||||
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(dlsym(libvulkan, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
|
||||||
|
vkGetPhysicalDeviceSurfaceFormatsKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(dlsym(libvulkan, "vkGetPhysicalDeviceSurfaceFormatsKHR"));
|
||||||
|
vkGetPhysicalDeviceSurfacePresentModesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(dlsym(libvulkan, "vkGetPhysicalDeviceSurfacePresentModesKHR"));
|
||||||
|
vkCreateSwapchainKHR = reinterpret_cast<PFN_vkCreateSwapchainKHR>(dlsym(libvulkan, "vkCreateSwapchainKHR"));
|
||||||
|
vkDestroySwapchainKHR = reinterpret_cast<PFN_vkDestroySwapchainKHR>(dlsym(libvulkan, "vkDestroySwapchainKHR"));
|
||||||
|
vkGetSwapchainImagesKHR = reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(dlsym(libvulkan, "vkGetSwapchainImagesKHR"));
|
||||||
|
vkAcquireNextImageKHR = reinterpret_cast<PFN_vkAcquireNextImageKHR>(dlsym(libvulkan, "vkAcquireNextImageKHR"));
|
||||||
|
vkQueuePresentKHR = reinterpret_cast<PFN_vkQueuePresentKHR>(dlsym(libvulkan, "vkQueuePresentKHR"));
|
||||||
|
vkGetPhysicalDeviceDisplayPropertiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPropertiesKHR>(dlsym(libvulkan, "vkGetPhysicalDeviceDisplayPropertiesKHR"));
|
||||||
|
vkGetPhysicalDeviceDisplayPlanePropertiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR>(dlsym(libvulkan, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR"));
|
||||||
|
vkGetDisplayPlaneSupportedDisplaysKHR = reinterpret_cast<PFN_vkGetDisplayPlaneSupportedDisplaysKHR>(dlsym(libvulkan, "vkGetDisplayPlaneSupportedDisplaysKHR"));
|
||||||
|
vkGetDisplayModePropertiesKHR = reinterpret_cast<PFN_vkGetDisplayModePropertiesKHR>(dlsym(libvulkan, "vkGetDisplayModePropertiesKHR"));
|
||||||
|
vkCreateDisplayModeKHR = reinterpret_cast<PFN_vkCreateDisplayModeKHR>(dlsym(libvulkan, "vkCreateDisplayModeKHR"));
|
||||||
|
vkGetDisplayPlaneCapabilitiesKHR = reinterpret_cast<PFN_vkGetDisplayPlaneCapabilitiesKHR>(dlsym(libvulkan, "vkGetDisplayPlaneCapabilitiesKHR"));
|
||||||
|
vkCreateDisplayPlaneSurfaceKHR = reinterpret_cast<PFN_vkCreateDisplayPlaneSurfaceKHR>(dlsym(libvulkan, "vkCreateDisplayPlaneSurfaceKHR"));
|
||||||
|
vkCreateSharedSwapchainsKHR = reinterpret_cast<PFN_vkCreateSharedSwapchainsKHR>(dlsym(libvulkan, "vkCreateSharedSwapchainsKHR"));
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||||
|
vkCreateXlibSurfaceKHR = reinterpret_cast<PFN_vkCreateXlibSurfaceKHR>(dlsym(libvulkan, "vkCreateXlibSurfaceKHR"));
|
||||||
|
vkGetPhysicalDeviceXlibPresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR>(dlsym(libvulkan, "vkGetPhysicalDeviceXlibPresentationSupportKHR"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||||
|
vkCreateXcbSurfaceKHR = reinterpret_cast<PFN_vkCreateXcbSurfaceKHR>(dlsym(libvulkan, "vkCreateXcbSurfaceKHR"));
|
||||||
|
vkGetPhysicalDeviceXcbPresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR>(dlsym(libvulkan, "vkGetPhysicalDeviceXcbPresentationSupportKHR"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||||
|
vkCreateWaylandSurfaceKHR = reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>(dlsym(libvulkan, "vkCreateWaylandSurfaceKHR"));
|
||||||
|
vkGetPhysicalDeviceWaylandPresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR>(dlsym(libvulkan, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_MIR_KHR
|
||||||
|
vkCreateMirSurfaceKHR = reinterpret_cast<PFN_vkCreateMirSurfaceKHR>(dlsym(libvulkan, "vkCreateMirSurfaceKHR"));
|
||||||
|
vkGetPhysicalDeviceMirPresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceMirPresentationSupportKHR>(dlsym(libvulkan, "vkGetPhysicalDeviceMirPresentationSupportKHR"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_ANDROID_KHR
|
||||||
|
vkCreateAndroidSurfaceKHR = reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>(dlsym(libvulkan, "vkCreateAndroidSurfaceKHR"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||||
|
vkCreateWin32SurfaceKHR = reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>(dlsym(libvulkan, "vkCreateWin32SurfaceKHR"));
|
||||||
|
vkGetPhysicalDeviceWin32PresentationSupportKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR>(dlsym(libvulkan, "vkGetPhysicalDeviceWin32PresentationSupportKHR"));
|
||||||
|
#endif
|
||||||
|
#ifdef USE_DEBUG_EXTENTIONS
|
||||||
|
vkCreateDebugReportCallbackEXT = reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>(dlsym(libvulkan, "vkCreateDebugReportCallbackEXT"));
|
||||||
|
vkDestroyDebugReportCallbackEXT = reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>(dlsym(libvulkan, "vkDestroyDebugReportCallbackEXT"));
|
||||||
|
vkDebugReportMessageEXT = reinterpret_cast<PFN_vkDebugReportMessageEXT>(dlsym(libvulkan, "vkDebugReportMessageEXT"));
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No Vulkan support, do not set function addresses
|
||||||
|
PFN_vkCreateInstance vkCreateInstance;
|
||||||
|
PFN_vkDestroyInstance vkDestroyInstance;
|
||||||
|
PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
|
||||||
|
PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures;
|
||||||
|
PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties;
|
||||||
|
PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties;
|
||||||
|
PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
|
||||||
|
PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
|
||||||
|
PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
|
||||||
|
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
|
||||||
|
PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
|
||||||
|
PFN_vkCreateDevice vkCreateDevice;
|
||||||
|
PFN_vkDestroyDevice vkDestroyDevice;
|
||||||
|
PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
|
||||||
|
PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
|
||||||
|
PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties;
|
||||||
|
PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties;
|
||||||
|
PFN_vkGetDeviceQueue vkGetDeviceQueue;
|
||||||
|
PFN_vkQueueSubmit vkQueueSubmit;
|
||||||
|
PFN_vkQueueWaitIdle vkQueueWaitIdle;
|
||||||
|
PFN_vkDeviceWaitIdle vkDeviceWaitIdle;
|
||||||
|
PFN_vkAllocateMemory vkAllocateMemory;
|
||||||
|
PFN_vkFreeMemory vkFreeMemory;
|
||||||
|
PFN_vkMapMemory vkMapMemory;
|
||||||
|
PFN_vkUnmapMemory vkUnmapMemory;
|
||||||
|
PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges;
|
||||||
|
PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges;
|
||||||
|
PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment;
|
||||||
|
PFN_vkBindBufferMemory vkBindBufferMemory;
|
||||||
|
PFN_vkBindImageMemory vkBindImageMemory;
|
||||||
|
PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
|
||||||
|
PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
|
||||||
|
PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements;
|
||||||
|
PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties;
|
||||||
|
PFN_vkQueueBindSparse vkQueueBindSparse;
|
||||||
|
PFN_vkCreateFence vkCreateFence;
|
||||||
|
PFN_vkDestroyFence vkDestroyFence;
|
||||||
|
PFN_vkResetFences vkResetFences;
|
||||||
|
PFN_vkGetFenceStatus vkGetFenceStatus;
|
||||||
|
PFN_vkWaitForFences vkWaitForFences;
|
||||||
|
PFN_vkCreateSemaphore vkCreateSemaphore;
|
||||||
|
PFN_vkDestroySemaphore vkDestroySemaphore;
|
||||||
|
PFN_vkCreateEvent vkCreateEvent;
|
||||||
|
PFN_vkDestroyEvent vkDestroyEvent;
|
||||||
|
PFN_vkGetEventStatus vkGetEventStatus;
|
||||||
|
PFN_vkSetEvent vkSetEvent;
|
||||||
|
PFN_vkResetEvent vkResetEvent;
|
||||||
|
PFN_vkCreateQueryPool vkCreateQueryPool;
|
||||||
|
PFN_vkDestroyQueryPool vkDestroyQueryPool;
|
||||||
|
PFN_vkGetQueryPoolResults vkGetQueryPoolResults;
|
||||||
|
PFN_vkCreateBuffer vkCreateBuffer;
|
||||||
|
PFN_vkDestroyBuffer vkDestroyBuffer;
|
||||||
|
PFN_vkCreateBufferView vkCreateBufferView;
|
||||||
|
PFN_vkDestroyBufferView vkDestroyBufferView;
|
||||||
|
PFN_vkCreateImage vkCreateImage;
|
||||||
|
PFN_vkDestroyImage vkDestroyImage;
|
||||||
|
PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout;
|
||||||
|
PFN_vkCreateImageView vkCreateImageView;
|
||||||
|
PFN_vkDestroyImageView vkDestroyImageView;
|
||||||
|
PFN_vkCreateShaderModule vkCreateShaderModule;
|
||||||
|
PFN_vkDestroyShaderModule vkDestroyShaderModule;
|
||||||
|
PFN_vkCreatePipelineCache vkCreatePipelineCache;
|
||||||
|
PFN_vkDestroyPipelineCache vkDestroyPipelineCache;
|
||||||
|
PFN_vkGetPipelineCacheData vkGetPipelineCacheData;
|
||||||
|
PFN_vkMergePipelineCaches vkMergePipelineCaches;
|
||||||
|
PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
|
||||||
|
PFN_vkCreateComputePipelines vkCreateComputePipelines;
|
||||||
|
PFN_vkDestroyPipeline vkDestroyPipeline;
|
||||||
|
PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
|
||||||
|
PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout;
|
||||||
|
PFN_vkCreateSampler vkCreateSampler;
|
||||||
|
PFN_vkDestroySampler vkDestroySampler;
|
||||||
|
PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout;
|
||||||
|
PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout;
|
||||||
|
PFN_vkCreateDescriptorPool vkCreateDescriptorPool;
|
||||||
|
PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool;
|
||||||
|
PFN_vkResetDescriptorPool vkResetDescriptorPool;
|
||||||
|
PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets;
|
||||||
|
PFN_vkFreeDescriptorSets vkFreeDescriptorSets;
|
||||||
|
PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
|
||||||
|
PFN_vkCreateFramebuffer vkCreateFramebuffer;
|
||||||
|
PFN_vkDestroyFramebuffer vkDestroyFramebuffer;
|
||||||
|
PFN_vkCreateRenderPass vkCreateRenderPass;
|
||||||
|
PFN_vkDestroyRenderPass vkDestroyRenderPass;
|
||||||
|
PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity;
|
||||||
|
PFN_vkCreateCommandPool vkCreateCommandPool;
|
||||||
|
PFN_vkDestroyCommandPool vkDestroyCommandPool;
|
||||||
|
PFN_vkResetCommandPool vkResetCommandPool;
|
||||||
|
PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
|
||||||
|
PFN_vkFreeCommandBuffers vkFreeCommandBuffers;
|
||||||
|
PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
|
||||||
|
PFN_vkEndCommandBuffer vkEndCommandBuffer;
|
||||||
|
PFN_vkResetCommandBuffer vkResetCommandBuffer;
|
||||||
|
PFN_vkCmdBindPipeline vkCmdBindPipeline;
|
||||||
|
PFN_vkCmdSetViewport vkCmdSetViewport;
|
||||||
|
PFN_vkCmdSetScissor vkCmdSetScissor;
|
||||||
|
PFN_vkCmdSetLineWidth vkCmdSetLineWidth;
|
||||||
|
PFN_vkCmdSetDepthBias vkCmdSetDepthBias;
|
||||||
|
PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants;
|
||||||
|
PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds;
|
||||||
|
PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask;
|
||||||
|
PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask;
|
||||||
|
PFN_vkCmdSetStencilReference vkCmdSetStencilReference;
|
||||||
|
PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets;
|
||||||
|
PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer;
|
||||||
|
PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers;
|
||||||
|
PFN_vkCmdDraw vkCmdDraw;
|
||||||
|
PFN_vkCmdDrawIndexed vkCmdDrawIndexed;
|
||||||
|
PFN_vkCmdDrawIndirect vkCmdDrawIndirect;
|
||||||
|
PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect;
|
||||||
|
PFN_vkCmdDispatch vkCmdDispatch;
|
||||||
|
PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect;
|
||||||
|
PFN_vkCmdCopyBuffer vkCmdCopyBuffer;
|
||||||
|
PFN_vkCmdCopyImage vkCmdCopyImage;
|
||||||
|
PFN_vkCmdBlitImage vkCmdBlitImage;
|
||||||
|
PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage;
|
||||||
|
PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer;
|
||||||
|
PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer;
|
||||||
|
PFN_vkCmdFillBuffer vkCmdFillBuffer;
|
||||||
|
PFN_vkCmdClearColorImage vkCmdClearColorImage;
|
||||||
|
PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage;
|
||||||
|
PFN_vkCmdClearAttachments vkCmdClearAttachments;
|
||||||
|
PFN_vkCmdResolveImage vkCmdResolveImage;
|
||||||
|
PFN_vkCmdSetEvent vkCmdSetEvent;
|
||||||
|
PFN_vkCmdResetEvent vkCmdResetEvent;
|
||||||
|
PFN_vkCmdWaitEvents vkCmdWaitEvents;
|
||||||
|
PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
|
||||||
|
PFN_vkCmdBeginQuery vkCmdBeginQuery;
|
||||||
|
PFN_vkCmdEndQuery vkCmdEndQuery;
|
||||||
|
PFN_vkCmdResetQueryPool vkCmdResetQueryPool;
|
||||||
|
PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp;
|
||||||
|
PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults;
|
||||||
|
PFN_vkCmdPushConstants vkCmdPushConstants;
|
||||||
|
PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
|
||||||
|
PFN_vkCmdNextSubpass vkCmdNextSubpass;
|
||||||
|
PFN_vkCmdEndRenderPass vkCmdEndRenderPass;
|
||||||
|
PFN_vkCmdExecuteCommands vkCmdExecuteCommands;
|
||||||
|
PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
|
||||||
|
PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR;
|
||||||
|
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
|
||||||
|
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
|
||||||
|
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
|
||||||
|
PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR;
|
||||||
|
PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
|
||||||
|
PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
|
||||||
|
PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
|
||||||
|
PFN_vkQueuePresentKHR vkQueuePresentKHR;
|
||||||
|
PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR;
|
||||||
|
PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR;
|
||||||
|
PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR;
|
||||||
|
PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR;
|
||||||
|
PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR;
|
||||||
|
PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR;
|
||||||
|
PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR;
|
||||||
|
PFN_vkCreateSharedSwapchainsKHR vkCreateSharedSwapchainsKHR;
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||||
|
PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR;
|
||||||
|
PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||||
|
PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR;
|
||||||
|
PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||||
|
PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR;
|
||||||
|
PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_MIR_KHR
|
||||||
|
PFN_vkCreateMirSurfaceKHR vkCreateMirSurfaceKHR;
|
||||||
|
PFN_vkGetPhysicalDeviceMirPresentationSupportKHR vkGetPhysicalDeviceMirPresentationSupportKHR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_ANDROID_KHR
|
||||||
|
PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||||
|
PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR;
|
||||||
|
PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR;
|
||||||
|
#endif
|
||||||
|
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT;
|
||||||
|
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT;
|
||||||
|
PFN_vkDebugReportMessageEXT vkDebugReportMessageEXT;
|
||||||
|
|
||||||
@@ -0,0 +1,236 @@
|
|||||||
|
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// This file is generated.
|
||||||
|
#ifndef VULKAN_WRAPPER_H
|
||||||
|
#define VULKAN_WRAPPER_H
|
||||||
|
|
||||||
|
#define VK_NO_PROTOTYPES 1
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
/* Initialize the Vulkan function pointer variables declared in this header.
|
||||||
|
* Returns 0 if vulkan is not available, non-zero if it is available.
|
||||||
|
*/
|
||||||
|
int InitVulkan(void);
|
||||||
|
|
||||||
|
// VK_core
|
||||||
|
extern PFN_vkCreateInstance vkCreateInstance;
|
||||||
|
extern PFN_vkDestroyInstance vkDestroyInstance;
|
||||||
|
extern PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
|
||||||
|
extern PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures;
|
||||||
|
extern PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties;
|
||||||
|
extern PFN_vkGetPhysicalDeviceImageFormatProperties vkGetPhysicalDeviceImageFormatProperties;
|
||||||
|
extern PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
|
||||||
|
extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
|
||||||
|
extern PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
|
||||||
|
extern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
|
||||||
|
extern PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
|
||||||
|
extern PFN_vkCreateDevice vkCreateDevice;
|
||||||
|
extern PFN_vkDestroyDevice vkDestroyDevice;
|
||||||
|
extern PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
|
||||||
|
extern PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
|
||||||
|
extern PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties;
|
||||||
|
extern PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties;
|
||||||
|
extern PFN_vkGetDeviceQueue vkGetDeviceQueue;
|
||||||
|
extern PFN_vkQueueSubmit vkQueueSubmit;
|
||||||
|
extern PFN_vkQueueWaitIdle vkQueueWaitIdle;
|
||||||
|
extern PFN_vkDeviceWaitIdle vkDeviceWaitIdle;
|
||||||
|
extern PFN_vkAllocateMemory vkAllocateMemory;
|
||||||
|
extern PFN_vkFreeMemory vkFreeMemory;
|
||||||
|
extern PFN_vkMapMemory vkMapMemory;
|
||||||
|
extern PFN_vkUnmapMemory vkUnmapMemory;
|
||||||
|
extern PFN_vkFlushMappedMemoryRanges vkFlushMappedMemoryRanges;
|
||||||
|
extern PFN_vkInvalidateMappedMemoryRanges vkInvalidateMappedMemoryRanges;
|
||||||
|
extern PFN_vkGetDeviceMemoryCommitment vkGetDeviceMemoryCommitment;
|
||||||
|
extern PFN_vkBindBufferMemory vkBindBufferMemory;
|
||||||
|
extern PFN_vkBindImageMemory vkBindImageMemory;
|
||||||
|
extern PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
|
||||||
|
extern PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
|
||||||
|
extern PFN_vkGetImageSparseMemoryRequirements vkGetImageSparseMemoryRequirements;
|
||||||
|
extern PFN_vkGetPhysicalDeviceSparseImageFormatProperties vkGetPhysicalDeviceSparseImageFormatProperties;
|
||||||
|
extern PFN_vkQueueBindSparse vkQueueBindSparse;
|
||||||
|
extern PFN_vkCreateFence vkCreateFence;
|
||||||
|
extern PFN_vkDestroyFence vkDestroyFence;
|
||||||
|
extern PFN_vkResetFences vkResetFences;
|
||||||
|
extern PFN_vkGetFenceStatus vkGetFenceStatus;
|
||||||
|
extern PFN_vkWaitForFences vkWaitForFences;
|
||||||
|
extern PFN_vkCreateSemaphore vkCreateSemaphore;
|
||||||
|
extern PFN_vkDestroySemaphore vkDestroySemaphore;
|
||||||
|
extern PFN_vkCreateEvent vkCreateEvent;
|
||||||
|
extern PFN_vkDestroyEvent vkDestroyEvent;
|
||||||
|
extern PFN_vkGetEventStatus vkGetEventStatus;
|
||||||
|
extern PFN_vkSetEvent vkSetEvent;
|
||||||
|
extern PFN_vkResetEvent vkResetEvent;
|
||||||
|
extern PFN_vkCreateQueryPool vkCreateQueryPool;
|
||||||
|
extern PFN_vkDestroyQueryPool vkDestroyQueryPool;
|
||||||
|
extern PFN_vkGetQueryPoolResults vkGetQueryPoolResults;
|
||||||
|
extern PFN_vkCreateBuffer vkCreateBuffer;
|
||||||
|
extern PFN_vkDestroyBuffer vkDestroyBuffer;
|
||||||
|
extern PFN_vkCreateBufferView vkCreateBufferView;
|
||||||
|
extern PFN_vkDestroyBufferView vkDestroyBufferView;
|
||||||
|
extern PFN_vkCreateImage vkCreateImage;
|
||||||
|
extern PFN_vkDestroyImage vkDestroyImage;
|
||||||
|
extern PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout;
|
||||||
|
extern PFN_vkCreateImageView vkCreateImageView;
|
||||||
|
extern PFN_vkDestroyImageView vkDestroyImageView;
|
||||||
|
extern PFN_vkCreateShaderModule vkCreateShaderModule;
|
||||||
|
extern PFN_vkDestroyShaderModule vkDestroyShaderModule;
|
||||||
|
extern PFN_vkCreatePipelineCache vkCreatePipelineCache;
|
||||||
|
extern PFN_vkDestroyPipelineCache vkDestroyPipelineCache;
|
||||||
|
extern PFN_vkGetPipelineCacheData vkGetPipelineCacheData;
|
||||||
|
extern PFN_vkMergePipelineCaches vkMergePipelineCaches;
|
||||||
|
extern PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
|
||||||
|
extern PFN_vkCreateComputePipelines vkCreateComputePipelines;
|
||||||
|
extern PFN_vkDestroyPipeline vkDestroyPipeline;
|
||||||
|
extern PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
|
||||||
|
extern PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout;
|
||||||
|
extern PFN_vkCreateSampler vkCreateSampler;
|
||||||
|
extern PFN_vkDestroySampler vkDestroySampler;
|
||||||
|
extern PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout;
|
||||||
|
extern PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout;
|
||||||
|
extern PFN_vkCreateDescriptorPool vkCreateDescriptorPool;
|
||||||
|
extern PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool;
|
||||||
|
extern PFN_vkResetDescriptorPool vkResetDescriptorPool;
|
||||||
|
extern PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets;
|
||||||
|
extern PFN_vkFreeDescriptorSets vkFreeDescriptorSets;
|
||||||
|
extern PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
|
||||||
|
extern PFN_vkCreateFramebuffer vkCreateFramebuffer;
|
||||||
|
extern PFN_vkDestroyFramebuffer vkDestroyFramebuffer;
|
||||||
|
extern PFN_vkCreateRenderPass vkCreateRenderPass;
|
||||||
|
extern PFN_vkDestroyRenderPass vkDestroyRenderPass;
|
||||||
|
extern PFN_vkGetRenderAreaGranularity vkGetRenderAreaGranularity;
|
||||||
|
extern PFN_vkCreateCommandPool vkCreateCommandPool;
|
||||||
|
extern PFN_vkDestroyCommandPool vkDestroyCommandPool;
|
||||||
|
extern PFN_vkResetCommandPool vkResetCommandPool;
|
||||||
|
extern PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
|
||||||
|
extern PFN_vkFreeCommandBuffers vkFreeCommandBuffers;
|
||||||
|
extern PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
|
||||||
|
extern PFN_vkEndCommandBuffer vkEndCommandBuffer;
|
||||||
|
extern PFN_vkResetCommandBuffer vkResetCommandBuffer;
|
||||||
|
extern PFN_vkCmdBindPipeline vkCmdBindPipeline;
|
||||||
|
extern PFN_vkCmdSetViewport vkCmdSetViewport;
|
||||||
|
extern PFN_vkCmdSetScissor vkCmdSetScissor;
|
||||||
|
extern PFN_vkCmdSetLineWidth vkCmdSetLineWidth;
|
||||||
|
extern PFN_vkCmdSetDepthBias vkCmdSetDepthBias;
|
||||||
|
extern PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants;
|
||||||
|
extern PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds;
|
||||||
|
extern PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask;
|
||||||
|
extern PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask;
|
||||||
|
extern PFN_vkCmdSetStencilReference vkCmdSetStencilReference;
|
||||||
|
extern PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets;
|
||||||
|
extern PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer;
|
||||||
|
extern PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers;
|
||||||
|
extern PFN_vkCmdDraw vkCmdDraw;
|
||||||
|
extern PFN_vkCmdDrawIndexed vkCmdDrawIndexed;
|
||||||
|
extern PFN_vkCmdDrawIndirect vkCmdDrawIndirect;
|
||||||
|
extern PFN_vkCmdDrawIndexedIndirect vkCmdDrawIndexedIndirect;
|
||||||
|
extern PFN_vkCmdDispatch vkCmdDispatch;
|
||||||
|
extern PFN_vkCmdDispatchIndirect vkCmdDispatchIndirect;
|
||||||
|
extern PFN_vkCmdCopyBuffer vkCmdCopyBuffer;
|
||||||
|
extern PFN_vkCmdCopyImage vkCmdCopyImage;
|
||||||
|
extern PFN_vkCmdBlitImage vkCmdBlitImage;
|
||||||
|
extern PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage;
|
||||||
|
extern PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer;
|
||||||
|
extern PFN_vkCmdUpdateBuffer vkCmdUpdateBuffer;
|
||||||
|
extern PFN_vkCmdFillBuffer vkCmdFillBuffer;
|
||||||
|
extern PFN_vkCmdClearColorImage vkCmdClearColorImage;
|
||||||
|
extern PFN_vkCmdClearDepthStencilImage vkCmdClearDepthStencilImage;
|
||||||
|
extern PFN_vkCmdClearAttachments vkCmdClearAttachments;
|
||||||
|
extern PFN_vkCmdResolveImage vkCmdResolveImage;
|
||||||
|
extern PFN_vkCmdSetEvent vkCmdSetEvent;
|
||||||
|
extern PFN_vkCmdResetEvent vkCmdResetEvent;
|
||||||
|
extern PFN_vkCmdWaitEvents vkCmdWaitEvents;
|
||||||
|
extern PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
|
||||||
|
extern PFN_vkCmdBeginQuery vkCmdBeginQuery;
|
||||||
|
extern PFN_vkCmdEndQuery vkCmdEndQuery;
|
||||||
|
extern PFN_vkCmdResetQueryPool vkCmdResetQueryPool;
|
||||||
|
extern PFN_vkCmdWriteTimestamp vkCmdWriteTimestamp;
|
||||||
|
extern PFN_vkCmdCopyQueryPoolResults vkCmdCopyQueryPoolResults;
|
||||||
|
extern PFN_vkCmdPushConstants vkCmdPushConstants;
|
||||||
|
extern PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
|
||||||
|
extern PFN_vkCmdNextSubpass vkCmdNextSubpass;
|
||||||
|
extern PFN_vkCmdEndRenderPass vkCmdEndRenderPass;
|
||||||
|
extern PFN_vkCmdExecuteCommands vkCmdExecuteCommands;
|
||||||
|
|
||||||
|
// VK_KHR_surface
|
||||||
|
extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
|
||||||
|
extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR;
|
||||||
|
extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
|
||||||
|
extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
|
||||||
|
extern PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
|
||||||
|
|
||||||
|
// VK_KHR_swapchain
|
||||||
|
extern PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR;
|
||||||
|
extern PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
|
||||||
|
extern PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
|
||||||
|
extern PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
|
||||||
|
extern PFN_vkQueuePresentKHR vkQueuePresentKHR;
|
||||||
|
|
||||||
|
// VK_KHR_display
|
||||||
|
extern PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR;
|
||||||
|
extern PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR;
|
||||||
|
extern PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR;
|
||||||
|
extern PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR;
|
||||||
|
extern PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR;
|
||||||
|
extern PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR;
|
||||||
|
extern PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR;
|
||||||
|
|
||||||
|
// VK_KHR_display_swapchain
|
||||||
|
extern PFN_vkCreateSharedSwapchainsKHR vkCreateSharedSwapchainsKHR;
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||||
|
// VK_KHR_xlib_surface
|
||||||
|
extern PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR;
|
||||||
|
extern PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||||
|
// VK_KHR_xcb_surface
|
||||||
|
extern PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR;
|
||||||
|
extern PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||||
|
// VK_KHR_wayland_surface
|
||||||
|
extern PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR;
|
||||||
|
extern PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR vkGetPhysicalDeviceWaylandPresentationSupportKHR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_MIR_KHR
|
||||||
|
// VK_KHR_mir_surface
|
||||||
|
extern PFN_vkCreateMirSurfaceKHR vkCreateMirSurfaceKHR;
|
||||||
|
extern PFN_vkGetPhysicalDeviceMirPresentationSupportKHR vkGetPhysicalDeviceMirPresentationSupportKHR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_ANDROID_KHR
|
||||||
|
// VK_KHR_android_surface
|
||||||
|
extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||||
|
// VK_KHR_win32_surface
|
||||||
|
extern PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR;
|
||||||
|
extern PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_DEBUG_EXTENTIONS
|
||||||
|
#include <vulkan/vk_sdk_platform.h>
|
||||||
|
// VK_EXT_debug_report
|
||||||
|
extern PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT;
|
||||||
|
extern PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT;
|
||||||
|
extern PFN_vkDebugReportMessageEXT vkDebugReportMessageEXT;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // VULKAN_WRAPPER_H
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,7 @@
|
|||||||
|
package org.kenjinx.android
|
||||||
|
|
||||||
|
enum class BackendThreading {
|
||||||
|
Auto,
|
||||||
|
Off,
|
||||||
|
On
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.kenjinx.android
|
||||||
|
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
|
||||||
|
abstract class BaseActivity : ComponentActivity() {
|
||||||
|
companion object {
|
||||||
|
val crashHandler = CrashHandler()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package org.kenjinx.android
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import java.io.File
|
||||||
|
import java.io.PrintWriter
|
||||||
|
import java.io.StringWriter
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
|
import java.lang.Thread.UncaughtExceptionHandler
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles uncaught exceptions in the application and logs them to a file
|
||||||
|
* Location: src/main/java/org/kenjinx/android/CrashHandler.kt
|
||||||
|
*/
|
||||||
|
class CrashHandler : UncaughtExceptionHandler {
|
||||||
|
private var crashLog: StringBuilder = StringBuilder()
|
||||||
|
private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val LOG_FOLDER = "Logs"
|
||||||
|
private const val CRASH_LOG_FILE = "crash.log"
|
||||||
|
private const val MAX_LOG_SIZE = 5 * 1024 * 1024 // 5MB
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun uncaughtException(t: Thread, e: Throwable) {
|
||||||
|
try {
|
||||||
|
generateCrashLog(t, e)
|
||||||
|
saveCrashLog()
|
||||||
|
} catch (writeError: Exception) {
|
||||||
|
// If we can't write to the crash log, print to system log as fallback
|
||||||
|
writeError.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateCrashLog(thread: Thread, throwable: Throwable) {
|
||||||
|
crashLog.apply {
|
||||||
|
append("\n=== Crash Report ===\n")
|
||||||
|
append("Date: ${dateFormat.format(Date())}\n")
|
||||||
|
|
||||||
|
// Device Information
|
||||||
|
append("\n=== Device Info ===\n")
|
||||||
|
append("Device: ${Build.MANUFACTURER} ${Build.MODEL}\n")
|
||||||
|
append("Android Version: ${Build.VERSION.RELEASE} (SDK ${Build.VERSION.SDK_INT})\n")
|
||||||
|
append("Device Fingerprint: ${Build.FINGERPRINT}\n")
|
||||||
|
|
||||||
|
// Thread Information
|
||||||
|
append("\n=== Thread Info ===\n")
|
||||||
|
append("Thread Name: ${thread.name}\n")
|
||||||
|
append("Thread ID: ${thread.id}\n")
|
||||||
|
append("Thread Priority: ${thread.priority}\n")
|
||||||
|
append("Thread State: ${thread.state}\n")
|
||||||
|
|
||||||
|
// Exception Details
|
||||||
|
append("\n=== Exception Info ===\n")
|
||||||
|
append("Exception Class: ${throwable.javaClass.name}\n")
|
||||||
|
append("Exception Message: ${throwable.message}\n")
|
||||||
|
|
||||||
|
// Stack Trace
|
||||||
|
append("\n=== Stack Trace ===\n")
|
||||||
|
val sw = StringWriter()
|
||||||
|
throwable.printStackTrace(PrintWriter(sw))
|
||||||
|
append(sw.toString())
|
||||||
|
|
||||||
|
// Cause (if any)
|
||||||
|
throwable.cause?.let { cause ->
|
||||||
|
append("\n=== Cause ===\n")
|
||||||
|
val causeSw = StringWriter()
|
||||||
|
cause.printStackTrace(PrintWriter(causeSw))
|
||||||
|
append(causeSw.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
append("\n=== End of Crash Report ===\n")
|
||||||
|
append("----------------------------------------\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveCrashLog() {
|
||||||
|
val logDir = File(MainActivity.AppPath, LOG_FOLDER).apply {
|
||||||
|
if (!exists()) mkdirs()
|
||||||
|
}
|
||||||
|
|
||||||
|
val crashLogFile = File(logDir, CRASH_LOG_FILE)
|
||||||
|
|
||||||
|
// Rotate log if it's too large
|
||||||
|
if (crashLogFile.exists() && crashLogFile.length() > MAX_LOG_SIZE) {
|
||||||
|
val backupFile = File(logDir, "${CRASH_LOG_FILE}.old")
|
||||||
|
if (backupFile.exists()) backupFile.delete()
|
||||||
|
crashLogFile.renameTo(backupFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the crash log
|
||||||
|
crashLogFile.appendText(crashLog.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,436 @@
|
|||||||
|
package org.kenjinx.android
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import androidx.core.math.MathUtils
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.swordfish.radialgamepad.library.RadialGamePad
|
||||||
|
import com.swordfish.radialgamepad.library.config.ButtonConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.CrossConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.CrossContentDescription
|
||||||
|
import com.swordfish.radialgamepad.library.config.PrimaryDialConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.RadialGamePadConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.SecondaryDialConfig
|
||||||
|
import com.swordfish.radialgamepad.library.event.Event
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.catch
|
||||||
|
import kotlinx.coroutines.flow.merge
|
||||||
|
import kotlinx.coroutines.flow.shareIn
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.kenjinx.android.viewmodels.MainViewModel
|
||||||
|
import org.kenjinx.android.viewmodels.QuickSettings
|
||||||
|
|
||||||
|
typealias GamePad = RadialGamePad
|
||||||
|
typealias GamePadConfig = RadialGamePadConfig
|
||||||
|
|
||||||
|
// --- Dummy IDs to disconnect legacy L3/R3 (stick double tap/tap) ---
|
||||||
|
private const val DUMMY_LEFT_STICK_PRESS_ID = 10001
|
||||||
|
private const val DUMMY_RIGHT_STICK_PRESS_ID = 10002
|
||||||
|
|
||||||
|
class GameController(var activity: Activity) : IGameController {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private fun init(context: Context, controller: GameController): View {
|
||||||
|
val inflater = LayoutInflater.from(context)
|
||||||
|
val parent = FrameLayout(context)
|
||||||
|
val view = inflater.inflate(R.layout.game_layout, parent, false)
|
||||||
|
|
||||||
|
val leftContainer = view.findViewById<FrameLayout>(R.id.leftcontainer)!!
|
||||||
|
val rightContainer = view.findViewById<FrameLayout>(R.id.rightcontainer)!!
|
||||||
|
|
||||||
|
leftContainer.addView(controller.leftGamePad)
|
||||||
|
rightContainer.addView(controller.rightGamePad)
|
||||||
|
|
||||||
|
leftContainer.addOnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
|
||||||
|
val scale = QuickSettings(controller.activity).controllerScale.coerceIn(0.5f, 1.5f)
|
||||||
|
v.pivotX = 0f
|
||||||
|
v.pivotY = v.height.toFloat()
|
||||||
|
v.scaleX = scale
|
||||||
|
v.scaleY = scale
|
||||||
|
}
|
||||||
|
rightContainer.addOnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
|
||||||
|
val scale = QuickSettings(controller.activity).controllerScale.coerceIn(0.5f, 1.5f)
|
||||||
|
v.pivotX = v.width.toFloat()
|
||||||
|
v.pivotY = v.height.toFloat()
|
||||||
|
v.scaleX = scale
|
||||||
|
v.scaleY = scale
|
||||||
|
}
|
||||||
|
|
||||||
|
leftContainer.post { leftContainer.requestLayout() }
|
||||||
|
rightContainer.post { rightContainer.requestLayout() }
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Compose(viewModel: MainViewModel) {
|
||||||
|
AndroidView(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
factory = { context ->
|
||||||
|
val controller = GameController(viewModel.activity)
|
||||||
|
val c = init(context, controller)
|
||||||
|
viewModel.activity.lifecycleScope.apply {
|
||||||
|
viewModel.activity.lifecycleScope.launch {
|
||||||
|
val events = merge(
|
||||||
|
controller.leftGamePad.events(),
|
||||||
|
controller.rightGamePad.events()
|
||||||
|
).shareIn(viewModel.activity.lifecycleScope, SharingStarted.Lazily)
|
||||||
|
events.safeCollect {
|
||||||
|
controller.handleEvent(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
controller.controllerView = c
|
||||||
|
viewModel.setGameController(controller)
|
||||||
|
controller.setVisible(QuickSettings(viewModel.activity).useVirtualController)
|
||||||
|
c
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private var controllerView: View? = null
|
||||||
|
var leftGamePad: GamePad
|
||||||
|
var rightGamePad: GamePad
|
||||||
|
var controllerId: Int = -1
|
||||||
|
override val isVisible: Boolean
|
||||||
|
get() = controllerView?.isVisible ?: false
|
||||||
|
|
||||||
|
init {
|
||||||
|
val useSwitchLayout = QuickSettings(activity).useSwitchLayout
|
||||||
|
leftGamePad = GamePad(generateConfig(true, useSwitchLayout), 16f, activity)
|
||||||
|
rightGamePad = GamePad(generateConfig(false, useSwitchLayout), 16f, activity)
|
||||||
|
|
||||||
|
leftGamePad.primaryDialMaxSizeDp = 200f
|
||||||
|
rightGamePad.primaryDialMaxSizeDp = 200f
|
||||||
|
|
||||||
|
leftGamePad.gravityX = -1f
|
||||||
|
leftGamePad.gravityY = 1f
|
||||||
|
rightGamePad.gravityX = 1f
|
||||||
|
rightGamePad.gravityY = 1f
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setVisible(isVisible: Boolean) {
|
||||||
|
controllerView?.apply {
|
||||||
|
this.isVisible = isVisible
|
||||||
|
if (isVisible) connect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun connect() {
|
||||||
|
if (controllerId == -1)
|
||||||
|
controllerId = KenjinxNative.inputConnectGamepad(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleEvent(ev: Event) {
|
||||||
|
if (controllerId == -1)
|
||||||
|
controllerId = KenjinxNative.inputConnectGamepad(0)
|
||||||
|
|
||||||
|
controllerId.apply {
|
||||||
|
when (ev) {
|
||||||
|
is Event.Button -> {
|
||||||
|
// Ignore legacy L3/R3 via stick press (double tap)
|
||||||
|
if (ev.id == DUMMY_LEFT_STICK_PRESS_ID || ev.id == DUMMY_RIGHT_STICK_PRESS_ID) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
when (ev.action) {
|
||||||
|
KeyEvent.ACTION_UP -> KenjinxNative.inputSetButtonReleased(ev.id, this)
|
||||||
|
KeyEvent.ACTION_DOWN -> KenjinxNative.inputSetButtonPressed(ev.id, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is Event.Direction -> {
|
||||||
|
when (ev.id) {
|
||||||
|
GamePadButtonInputId.DpadUp.ordinal -> {
|
||||||
|
// Horizontal
|
||||||
|
if (ev.xAxis > 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
} else if (ev.xAxis < 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
} else {
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
}
|
||||||
|
// Vertical
|
||||||
|
if (ev.yAxis < 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
} else if (ev.yAxis > 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
} else {
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GamePadButtonInputId.LeftStick.ordinal -> {
|
||||||
|
val setting = QuickSettings(activity)
|
||||||
|
val x = MathUtils.clamp(ev.xAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
val y = MathUtils.clamp(ev.yAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
KenjinxNative.inputSetStickAxis(1, x, -y, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
GamePadButtonInputId.RightStick.ordinal -> {
|
||||||
|
val setting = QuickSettings(activity)
|
||||||
|
val x = MathUtils.clamp(ev.xAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
val y = MathUtils.clamp(ev.yAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
KenjinxNative.inputSetStickAxis(2, x, -y, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun <T> Flow<T>.safeCollect(block: suspend (T) -> Unit) {
|
||||||
|
this.catch { }
|
||||||
|
.collect { block(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateConfig(isLeft: Boolean, useSwitchLayout: Boolean): GamePadConfig {
|
||||||
|
val distance = 0.3f
|
||||||
|
val buttonScale = 1f
|
||||||
|
|
||||||
|
if (isLeft) {
|
||||||
|
return GamePadConfig(
|
||||||
|
/* ringSegments = */ 12,
|
||||||
|
/* Primary (Stick) */
|
||||||
|
// IMPORTANT: pressButtonId -> DUMMY_LEFT_STICK_PRESS_ID, so that double tap does not trigger L3
|
||||||
|
PrimaryDialConfig.Stick(
|
||||||
|
GamePadButtonInputId.LeftStick.ordinal,
|
||||||
|
DUMMY_LEFT_STICK_PRESS_ID,
|
||||||
|
setOf(),
|
||||||
|
"LeftStick",
|
||||||
|
null
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
// D-Pad
|
||||||
|
SecondaryDialConfig.Cross(
|
||||||
|
/* sector */ 10,
|
||||||
|
/* size */ 3,
|
||||||
|
/* gap */ 2.5f,
|
||||||
|
distance,
|
||||||
|
CrossConfig(
|
||||||
|
GamePadButtonInputId.DpadUp.ordinal,
|
||||||
|
CrossConfig.Shape.STANDARD,
|
||||||
|
null,
|
||||||
|
setOf(),
|
||||||
|
CrossContentDescription(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// Minus
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 1,
|
||||||
|
buttonScale,
|
||||||
|
distance,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.Minus.ordinal,
|
||||||
|
"-",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"Minus",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// L Bumper
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 2,
|
||||||
|
distance,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftShoulder.ordinal,
|
||||||
|
"L",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftBumper",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// ZL Trigger
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 9,
|
||||||
|
buttonScale,
|
||||||
|
distance,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftTrigger.ordinal,
|
||||||
|
"ZL",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftTrigger",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// L3 as a separate button
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 1,
|
||||||
|
buttonScale,
|
||||||
|
1.5f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftStickButton.ordinal,
|
||||||
|
"L3",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftStickButton",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return GamePadConfig(
|
||||||
|
/* ringSegments = */ 12,
|
||||||
|
/* Primary (ABXY) */
|
||||||
|
PrimaryDialConfig.PrimaryButtons(
|
||||||
|
if (useSwitchLayout) {
|
||||||
|
// Switch/Nintendo: A=Right, X=Top, Y=Left, B=Bottom
|
||||||
|
listOf(
|
||||||
|
ButtonConfig(GamePadButtonInputId.A.ordinal, "A", true, null, "A", setOf(), true, null), // Right
|
||||||
|
ButtonConfig(GamePadButtonInputId.X.ordinal, "X", true, null, "X", setOf(), true, null), // Top
|
||||||
|
ButtonConfig(GamePadButtonInputId.Y.ordinal, "Y", true, null, "Y", setOf(), true, null), // Left
|
||||||
|
ButtonConfig(GamePadButtonInputId.B.ordinal, "B", true, null, "B", setOf(), true, null) // Bottom
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Xbox Style: B=Right, Y=Top, X=Left, A=Bottom
|
||||||
|
listOf(
|
||||||
|
ButtonConfig(GamePadButtonInputId.B.ordinal, "B", true, null, "B", setOf(), true, null), // Right
|
||||||
|
ButtonConfig(GamePadButtonInputId.Y.ordinal, "Y", true, null, "Y", setOf(), true, null), // Top
|
||||||
|
ButtonConfig(GamePadButtonInputId.X.ordinal, "X", true, null, "X", setOf(), true, null), // Left
|
||||||
|
ButtonConfig(GamePadButtonInputId.A.ordinal, "A", true, null, "A", setOf(), true, null) // Bottom
|
||||||
|
)
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
0f,
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
// Right stick (unchanged)
|
||||||
|
// IMPORTANT: pressButtonId -> DUMMY_RIGHT_STICK_PRESS_ID, so that double tap does not trigger R3
|
||||||
|
SecondaryDialConfig.Stick(
|
||||||
|
/* sector */ 7,
|
||||||
|
/* size */ 2,
|
||||||
|
/* gap */ 2f,
|
||||||
|
distance,
|
||||||
|
GamePadButtonInputId.RightStick.ordinal,
|
||||||
|
DUMMY_RIGHT_STICK_PRESS_ID,
|
||||||
|
null,
|
||||||
|
setOf(),
|
||||||
|
"RightStick",
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// Plus
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 6,
|
||||||
|
buttonScale,
|
||||||
|
distance,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.Plus.ordinal,
|
||||||
|
"+",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"Plus",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// R Bumper
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 3,
|
||||||
|
distance,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightShoulder.ordinal,
|
||||||
|
"R",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightBumper",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// ZR Trigger
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 9,
|
||||||
|
buttonScale,
|
||||||
|
distance,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightTrigger.ordinal,
|
||||||
|
"ZR",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightTrigger",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// R3 as a separate button
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 5,
|
||||||
|
buttonScale,
|
||||||
|
1.5f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightStickButton.ordinal,
|
||||||
|
"R3",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightStickButton",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,420 @@
|
|||||||
|
package org.kenjinx.android
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import androidx.core.math.MathUtils
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.swordfish.radialgamepad.library.RadialGamePad
|
||||||
|
import com.swordfish.radialgamepad.library.config.ButtonConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.CrossConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.CrossContentDescription
|
||||||
|
import com.swordfish.radialgamepad.library.config.PrimaryDialConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.SecondaryDialConfig
|
||||||
|
import com.swordfish.radialgamepad.library.event.Event
|
||||||
|
import kotlinx.coroutines.flow.merge
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.kenjinx.android.viewmodels.MainViewModel
|
||||||
|
import org.kenjinx.android.viewmodels.QuickSettings
|
||||||
|
|
||||||
|
// --- Dummy IDs to disconnect legacy L3/R3 (stick double tap/tap) ---
|
||||||
|
private const val DUMMY_LEFT_STICK_PRESS_ID = 10001
|
||||||
|
private const val DUMMY_RIGHT_STICK_PRESS_ID = 10002
|
||||||
|
|
||||||
|
class GameController2(var activity: Activity) : IGameController {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private fun init(context: Context, controller: GameController2): View {
|
||||||
|
val inflater = LayoutInflater.from(context)
|
||||||
|
val parent = FrameLayout(context)
|
||||||
|
val view = inflater.inflate(R.layout.game_layout, parent, false)
|
||||||
|
|
||||||
|
val leftContainer = view.findViewById<FrameLayout>(R.id.leftcontainer)!!
|
||||||
|
val rightContainer = view.findViewById<FrameLayout>(R.id.rightcontainer)!!
|
||||||
|
|
||||||
|
leftContainer.addView(controller.leftGamePad)
|
||||||
|
rightContainer.addView(controller.rightGamePad)
|
||||||
|
|
||||||
|
leftContainer.addOnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
|
||||||
|
val scale = QuickSettings(controller.activity).controllerScale.coerceIn(0.5f, 1.5f)
|
||||||
|
v.pivotX = 0f
|
||||||
|
v.pivotY = v.height.toFloat()
|
||||||
|
v.scaleX = scale
|
||||||
|
v.scaleY = scale
|
||||||
|
}
|
||||||
|
rightContainer.addOnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
|
||||||
|
val scale = QuickSettings(controller.activity).controllerScale.coerceIn(0.5f, 1.5f)
|
||||||
|
v.pivotX = v.width.toFloat()
|
||||||
|
v.pivotY = v.height.toFloat()
|
||||||
|
v.scaleX = scale
|
||||||
|
v.scaleY = scale
|
||||||
|
}
|
||||||
|
|
||||||
|
leftContainer.post { leftContainer.requestLayout() }
|
||||||
|
rightContainer.post { rightContainer.requestLayout() }
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Compose(viewModel: MainViewModel) {
|
||||||
|
AndroidView(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
factory = { context ->
|
||||||
|
val controller = GameController2(viewModel.activity)
|
||||||
|
val c = init(context, controller)
|
||||||
|
|
||||||
|
viewModel.activity.lifecycleScope.launch {
|
||||||
|
val events = merge(
|
||||||
|
controller.leftGamePad.events(),
|
||||||
|
controller.rightGamePad.events()
|
||||||
|
)
|
||||||
|
events.safeCollect { controller.handleEvent(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.controllerView = c
|
||||||
|
viewModel.setGameController(controller)
|
||||||
|
controller.setVisible(QuickSettings(viewModel.activity).useVirtualController)
|
||||||
|
c
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private var controllerView: View? = null
|
||||||
|
var leftGamePad: RadialGamePad
|
||||||
|
var rightGamePad: RadialGamePad
|
||||||
|
var controllerId: Int = -1
|
||||||
|
override val isVisible: Boolean
|
||||||
|
get() = controllerView?.isVisible ?: false
|
||||||
|
|
||||||
|
init {
|
||||||
|
val useSwitchLayout = QuickSettings(activity).useSwitchLayout
|
||||||
|
leftGamePad = RadialGamePad(generateConfig2(true, useSwitchLayout), 16f, activity)
|
||||||
|
rightGamePad = RadialGamePad(generateConfig2(false, useSwitchLayout), 16f, activity)
|
||||||
|
|
||||||
|
leftGamePad.primaryDialMaxSizeDp = 200f
|
||||||
|
rightGamePad.primaryDialMaxSizeDp = 200f
|
||||||
|
|
||||||
|
leftGamePad.gravityX = -1f
|
||||||
|
leftGamePad.gravityY = 1f
|
||||||
|
rightGamePad.gravityX = 1f
|
||||||
|
rightGamePad.gravityY = 1f
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setVisible(isVisible: Boolean) {
|
||||||
|
controllerView?.apply {
|
||||||
|
this.isVisible = isVisible
|
||||||
|
if (isVisible) connect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun connect() {
|
||||||
|
if (controllerId == -1)
|
||||||
|
controllerId = KenjinxNative.inputConnectGamepad(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleEvent(ev: Event) {
|
||||||
|
if (controllerId == -1)
|
||||||
|
controllerId = KenjinxNative.inputConnectGamepad(0)
|
||||||
|
|
||||||
|
controllerId.apply {
|
||||||
|
when (ev) {
|
||||||
|
is Event.Button -> {
|
||||||
|
// Ignore legacy L3/R3 via stick press (double tap)
|
||||||
|
if (ev.id == DUMMY_LEFT_STICK_PRESS_ID || ev.id == DUMMY_RIGHT_STICK_PRESS_ID) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
when (ev.action) {
|
||||||
|
KeyEvent.ACTION_UP -> KenjinxNative.inputSetButtonReleased(ev.id, this)
|
||||||
|
KeyEvent.ACTION_DOWN -> KenjinxNative.inputSetButtonPressed(ev.id, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is Event.Direction -> {
|
||||||
|
when (ev.id) {
|
||||||
|
GamePadButtonInputId.DpadUp.ordinal -> {
|
||||||
|
// Horizontal
|
||||||
|
if (ev.xAxis > 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
} else if (ev.xAxis < 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
} else {
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
}
|
||||||
|
// Vertical
|
||||||
|
if (ev.yAxis < 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
} else if (ev.yAxis > 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
} else {
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GamePadButtonInputId.LeftStick.ordinal -> {
|
||||||
|
val setting = QuickSettings(activity)
|
||||||
|
val x = MathUtils.clamp(ev.xAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
val y = MathUtils.clamp(ev.yAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
KenjinxNative.inputSetStickAxis(1, x, -y, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
GamePadButtonInputId.RightStick.ordinal -> {
|
||||||
|
val setting = QuickSettings(activity)
|
||||||
|
val x = MathUtils.clamp(ev.xAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
val y = MathUtils.clamp(ev.yAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
KenjinxNative.inputSetStickAxis(2, x, -y, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Local copy of the config generation (name = generateConfig2, to avoid conflicts) ---
|
||||||
|
private fun generateConfig2(isLeft: Boolean, useSwitchLayout: Boolean): GamePadConfig {
|
||||||
|
val distance = 0.3f
|
||||||
|
val buttonScale = 1f
|
||||||
|
|
||||||
|
if (isLeft) {
|
||||||
|
return GamePadConfig(
|
||||||
|
/* ringSegments = */ 12,
|
||||||
|
/* Primary (Stick) */
|
||||||
|
// IMPORTANT: pressButtonId -> DUMMY_LEFT_STICK_PRESS_ID, so that double tap does not trigger L3
|
||||||
|
PrimaryDialConfig.Stick(
|
||||||
|
GamePadButtonInputId.LeftStick.ordinal,
|
||||||
|
DUMMY_LEFT_STICK_PRESS_ID,
|
||||||
|
setOf(),
|
||||||
|
"LeftStick",
|
||||||
|
null
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
// D-Pad
|
||||||
|
SecondaryDialConfig.Cross(
|
||||||
|
/* sector */ 10,
|
||||||
|
/* size */ 3,
|
||||||
|
/* gap */ 2.1f,
|
||||||
|
distance,
|
||||||
|
CrossConfig(
|
||||||
|
GamePadButtonInputId.DpadUp.ordinal,
|
||||||
|
CrossConfig.Shape.STANDARD,
|
||||||
|
null,
|
||||||
|
setOf(),
|
||||||
|
CrossContentDescription(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// Minus
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 9,
|
||||||
|
buttonScale,
|
||||||
|
0.3f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.Minus.ordinal,
|
||||||
|
"-",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"Minus",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// L Bumper
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 2,
|
||||||
|
0.2f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftShoulder.ordinal,
|
||||||
|
"L",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftBumper",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// ZL Trigger
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 2,
|
||||||
|
1f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftTrigger.ordinal,
|
||||||
|
"ZL",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftTrigger",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// L3 as a separate button
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 1,
|
||||||
|
buttonScale,
|
||||||
|
1.0f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftStickButton.ordinal,
|
||||||
|
"L3",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftStickButton",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return GamePadConfig(
|
||||||
|
/* ringSegments = */ 12,
|
||||||
|
/* Primary (ABXY) */
|
||||||
|
PrimaryDialConfig.PrimaryButtons(
|
||||||
|
if (useSwitchLayout) {
|
||||||
|
// Switch/Nintendo: A=Right, X=Top, Y=Left, B=Bottom
|
||||||
|
listOf(
|
||||||
|
ButtonConfig(GamePadButtonInputId.A.ordinal, "A", true, null, "A", setOf(), true, null), // Right
|
||||||
|
ButtonConfig(GamePadButtonInputId.X.ordinal, "X", true, null, "X", setOf(), true, null), // Top
|
||||||
|
ButtonConfig(GamePadButtonInputId.Y.ordinal, "Y", true, null, "Y", setOf(), true, null), // Left
|
||||||
|
ButtonConfig(GamePadButtonInputId.B.ordinal, "B", true, null, "B", setOf(), true, null) // Bottom
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Xbox Style: B=Right, Y=Top, X=Left, A=Bottom
|
||||||
|
listOf(
|
||||||
|
ButtonConfig(GamePadButtonInputId.B.ordinal, "B", true, null, "B", setOf(), true, null), // Right
|
||||||
|
ButtonConfig(GamePadButtonInputId.Y.ordinal, "Y", true, null, "Y", setOf(), true, null), // Top
|
||||||
|
ButtonConfig(GamePadButtonInputId.X.ordinal, "X", true, null, "X", setOf(), true, null), // Left
|
||||||
|
ButtonConfig(GamePadButtonInputId.A.ordinal, "A", true, null, "A", setOf(), true, null) // Bottom
|
||||||
|
)
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
0f,
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
// Right stick
|
||||||
|
// IMPORTANT: pressButtonId -> DUMMY_RIGHT_STICK_PRESS_ID, so that double tap does not trigger R3
|
||||||
|
SecondaryDialConfig.Stick(
|
||||||
|
/* sector */ 6,
|
||||||
|
/* size */ 3,
|
||||||
|
/* gap */ 2.7f,
|
||||||
|
distance,
|
||||||
|
GamePadButtonInputId.RightStick.ordinal,
|
||||||
|
DUMMY_RIGHT_STICK_PRESS_ID,
|
||||||
|
null,
|
||||||
|
setOf(),
|
||||||
|
"RightStick",
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// Plus
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 9,
|
||||||
|
buttonScale,
|
||||||
|
0.3f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.Plus.ordinal,
|
||||||
|
"+",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"Plus",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// R Bumper
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 3,
|
||||||
|
0.2f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightShoulder.ordinal,
|
||||||
|
"R",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightBumper",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// ZR Trigger
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 3,
|
||||||
|
1f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightTrigger.ordinal,
|
||||||
|
"ZR",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightTrigger",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// R3 as a separate button
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 5,
|
||||||
|
buttonScale,
|
||||||
|
1.0f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightStickButton.ordinal,
|
||||||
|
"R3",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightStickButton",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,413 @@
|
|||||||
|
package org.kenjinx.android
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import androidx.core.math.MathUtils
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.swordfish.radialgamepad.library.RadialGamePad
|
||||||
|
import com.swordfish.radialgamepad.library.config.ButtonConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.CrossConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.CrossContentDescription
|
||||||
|
import com.swordfish.radialgamepad.library.config.PrimaryDialConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.SecondaryDialConfig
|
||||||
|
import com.swordfish.radialgamepad.library.event.Event
|
||||||
|
import kotlinx.coroutines.flow.merge
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.kenjinx.android.viewmodels.MainViewModel
|
||||||
|
import org.kenjinx.android.viewmodels.QuickSettings
|
||||||
|
|
||||||
|
// --- Dummy IDs to disconnect legacy L3/R3 (stick double tap/tap) ---
|
||||||
|
private const val DUMMY_LEFT_STICK_PRESS_ID = 10001
|
||||||
|
private const val DUMMY_RIGHT_STICK_PRESS_ID = 10002
|
||||||
|
|
||||||
|
class GameController3(var activity: Activity) : IGameController {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private fun init(context: Context, controller: GameController3): View {
|
||||||
|
val inflater = LayoutInflater.from(context)
|
||||||
|
val parent = FrameLayout(context)
|
||||||
|
val view = inflater.inflate(R.layout.game_layout, parent, false)
|
||||||
|
|
||||||
|
val leftContainer = view.findViewById<FrameLayout>(R.id.leftcontainer)!!
|
||||||
|
val rightContainer = view.findViewById<FrameLayout>(R.id.rightcontainer)!!
|
||||||
|
|
||||||
|
leftContainer.addView(controller.leftGamePad)
|
||||||
|
rightContainer.addView(controller.rightGamePad)
|
||||||
|
|
||||||
|
leftContainer.addOnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
|
||||||
|
val scale = QuickSettings(controller.activity).controllerScale.coerceIn(0.5f, 1.5f)
|
||||||
|
v.pivotX = 0f
|
||||||
|
v.pivotY = v.height.toFloat()
|
||||||
|
v.scaleX = scale
|
||||||
|
v.scaleY = scale
|
||||||
|
}
|
||||||
|
rightContainer.addOnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
|
||||||
|
val scale = QuickSettings(controller.activity).controllerScale.coerceIn(0.5f, 1.5f)
|
||||||
|
v.pivotX = v.width.toFloat()
|
||||||
|
v.pivotY = v.height.toFloat()
|
||||||
|
v.scaleX = scale
|
||||||
|
v.scaleY = scale
|
||||||
|
}
|
||||||
|
|
||||||
|
leftContainer.post { leftContainer.requestLayout() }
|
||||||
|
rightContainer.post { rightContainer.requestLayout() }
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Compose(viewModel: MainViewModel) {
|
||||||
|
AndroidView(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
factory = { context ->
|
||||||
|
val controller = GameController3(viewModel.activity)
|
||||||
|
val c = init(context, controller)
|
||||||
|
|
||||||
|
viewModel.activity.lifecycleScope.launch {
|
||||||
|
val events = merge(
|
||||||
|
controller.leftGamePad.events(),
|
||||||
|
controller.rightGamePad.events()
|
||||||
|
)
|
||||||
|
events.safeCollect { controller.handleEvent(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.controllerView = c
|
||||||
|
viewModel.setGameController(controller)
|
||||||
|
controller.setVisible(QuickSettings(viewModel.activity).useVirtualController)
|
||||||
|
c
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var controllerView: View? = null
|
||||||
|
var leftGamePad: RadialGamePad
|
||||||
|
var rightGamePad: RadialGamePad
|
||||||
|
var controllerId: Int = -1
|
||||||
|
override val isVisible: Boolean
|
||||||
|
get() = controllerView?.isVisible ?: false
|
||||||
|
|
||||||
|
init {
|
||||||
|
val useSwitchLayout = QuickSettings(activity).useSwitchLayout
|
||||||
|
leftGamePad = RadialGamePad(generateConfig3(true, useSwitchLayout), 16f, activity)
|
||||||
|
rightGamePad = RadialGamePad(generateConfig3(false, useSwitchLayout), 16f, activity)
|
||||||
|
|
||||||
|
leftGamePad.primaryDialMaxSizeDp = 200f
|
||||||
|
rightGamePad.primaryDialMaxSizeDp = 200f
|
||||||
|
|
||||||
|
leftGamePad.gravityX = -1f
|
||||||
|
leftGamePad.gravityY = 1f
|
||||||
|
rightGamePad.gravityX = 1f
|
||||||
|
rightGamePad.gravityY = 1f
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setVisible(isVisible: Boolean) {
|
||||||
|
controllerView?.apply {
|
||||||
|
this.isVisible = isVisible
|
||||||
|
if (isVisible) connect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun connect() {
|
||||||
|
if (controllerId == -1)
|
||||||
|
controllerId = KenjinxNative.inputConnectGamepad(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleEvent(ev: Event) {
|
||||||
|
if (controllerId == -1)
|
||||||
|
controllerId = KenjinxNative.inputConnectGamepad(0)
|
||||||
|
|
||||||
|
controllerId.apply {
|
||||||
|
when (ev) {
|
||||||
|
is Event.Button -> {
|
||||||
|
// Ignore legacy L3/R3 via stick press (double tap)
|
||||||
|
if (ev.id == DUMMY_LEFT_STICK_PRESS_ID || ev.id == DUMMY_RIGHT_STICK_PRESS_ID) return
|
||||||
|
when (ev.action) {
|
||||||
|
KeyEvent.ACTION_UP -> KenjinxNative.inputSetButtonReleased(ev.id, this)
|
||||||
|
KeyEvent.ACTION_DOWN -> KenjinxNative.inputSetButtonPressed(ev.id, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Event.Direction -> {
|
||||||
|
when (ev.id) {
|
||||||
|
GamePadButtonInputId.DpadUp.ordinal -> {
|
||||||
|
// Horizontal
|
||||||
|
if (ev.xAxis > 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
} else if (ev.xAxis < 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
} else {
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
}
|
||||||
|
// Vertical
|
||||||
|
if (ev.yAxis < 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
} else if (ev.yAxis > 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
} else {
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GamePadButtonInputId.LeftStick.ordinal -> {
|
||||||
|
val setting = QuickSettings(activity)
|
||||||
|
val x = MathUtils.clamp(ev.xAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
val y = MathUtils.clamp(ev.yAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
KenjinxNative.inputSetStickAxis(1, x, -y, this)
|
||||||
|
}
|
||||||
|
GamePadButtonInputId.RightStick.ordinal -> {
|
||||||
|
val setting = QuickSettings(activity)
|
||||||
|
val x = MathUtils.clamp(ev.xAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
val y = MathUtils.clamp(ev.yAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
KenjinxNative.inputSetStickAxis(2, x, -y, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateConfig3(isLeft: Boolean, useSwitchLayout: Boolean): GamePadConfig {
|
||||||
|
val distance = 0.3f
|
||||||
|
val buttonScale = 1f
|
||||||
|
|
||||||
|
if (isLeft) {
|
||||||
|
return GamePadConfig(
|
||||||
|
/* ringSegments = */ 12,
|
||||||
|
/* Primary (D-Pad) */
|
||||||
|
PrimaryDialConfig.Cross(
|
||||||
|
CrossConfig(
|
||||||
|
GamePadButtonInputId.DpadUp.ordinal,
|
||||||
|
CrossConfig.Shape.STANDARD,
|
||||||
|
null,
|
||||||
|
setOf(),
|
||||||
|
CrossContentDescription(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
// Left stick
|
||||||
|
// IMPORTANT: pressButtonId -> DUMMY_LEFT_STICK_PRESS_ID, so that double tap does not trigger L3
|
||||||
|
SecondaryDialConfig.Stick(
|
||||||
|
/* sector */ 10,
|
||||||
|
/* size */ 3,
|
||||||
|
/* gap */ 2.7f,
|
||||||
|
distance,
|
||||||
|
GamePadButtonInputId.LeftStick.ordinal,
|
||||||
|
DUMMY_LEFT_STICK_PRESS_ID,
|
||||||
|
null,
|
||||||
|
setOf(),
|
||||||
|
"LeftStick",
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// Minus
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 9,
|
||||||
|
buttonScale,
|
||||||
|
0.3f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.Minus.ordinal,
|
||||||
|
"-",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"Minus",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// L Bumper
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 2,
|
||||||
|
0.2f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftShoulder.ordinal,
|
||||||
|
"L",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftBumper",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// ZL Trigger
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 2,
|
||||||
|
1f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftTrigger.ordinal,
|
||||||
|
"ZL",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftTrigger",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// L3 as a separate button
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 1,
|
||||||
|
buttonScale,
|
||||||
|
1.0f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftStickButton.ordinal,
|
||||||
|
"L3",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftStickButton",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return GamePadConfig(
|
||||||
|
/* ringSegments = */ 12,
|
||||||
|
/* Primary (ABXY) */
|
||||||
|
PrimaryDialConfig.PrimaryButtons(
|
||||||
|
if (useSwitchLayout) {
|
||||||
|
// Switch/Nintendo: A=Right, X=Top, Y=Left, B=Bottom
|
||||||
|
listOf(
|
||||||
|
ButtonConfig(GamePadButtonInputId.A.ordinal, "A", true, null, "A", setOf(), true, null), // Right
|
||||||
|
ButtonConfig(GamePadButtonInputId.X.ordinal, "X", true, null, "X", setOf(), true, null), // Top
|
||||||
|
ButtonConfig(GamePadButtonInputId.Y.ordinal, "Y", true, null, "Y", setOf(), true, null), // Left
|
||||||
|
ButtonConfig(GamePadButtonInputId.B.ordinal, "B", true, null, "B", setOf(), true, null) // Bottom
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Xbox Style: B=Right, Y=Top, X=Left, A=Bottom
|
||||||
|
listOf(
|
||||||
|
ButtonConfig(GamePadButtonInputId.B.ordinal, "B", true, null, "B", setOf(), true, null), // Right
|
||||||
|
ButtonConfig(GamePadButtonInputId.Y.ordinal, "Y", true, null, "Y", setOf(), true, null), // Top
|
||||||
|
ButtonConfig(GamePadButtonInputId.X.ordinal, "X", true, null, "X", setOf(), true, null), // Left
|
||||||
|
ButtonConfig(GamePadButtonInputId.A.ordinal, "A", true, null, "A", setOf(), true, null) // Bottom
|
||||||
|
)
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
0f,
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
// Right stick
|
||||||
|
// IMPORTANT: pressButtonId -> DUMMY_RIGHT_STICK_PRESS_ID, so that double tap does not trigger R3
|
||||||
|
SecondaryDialConfig.Stick(
|
||||||
|
/* sector */ 6,
|
||||||
|
/* size */ 3,
|
||||||
|
/* gap */ 2.7f,
|
||||||
|
distance,
|
||||||
|
GamePadButtonInputId.RightStick.ordinal,
|
||||||
|
DUMMY_RIGHT_STICK_PRESS_ID,
|
||||||
|
null,
|
||||||
|
setOf(),
|
||||||
|
"RightStick",
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// Plus
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 9,
|
||||||
|
buttonScale,
|
||||||
|
0.3f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.Plus.ordinal,
|
||||||
|
"+",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"Plus",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// R Bumper
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 3,
|
||||||
|
0.2f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightShoulder.ordinal,
|
||||||
|
"R",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightBumper",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// ZR Trigger
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 3,
|
||||||
|
1f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightTrigger.ordinal,
|
||||||
|
"ZR",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightTrigger",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// R3 as a separate button
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 5,
|
||||||
|
buttonScale,
|
||||||
|
1.0f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightStickButton.ordinal,
|
||||||
|
"R3",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightStickButton",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,410 @@
|
|||||||
|
package org.kenjinx.android
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import androidx.core.math.MathUtils
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.swordfish.radialgamepad.library.RadialGamePad
|
||||||
|
import com.swordfish.radialgamepad.library.config.ButtonConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.CrossConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.CrossContentDescription
|
||||||
|
import com.swordfish.radialgamepad.library.config.PrimaryDialConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.SecondaryDialConfig
|
||||||
|
import com.swordfish.radialgamepad.library.event.Event
|
||||||
|
import kotlinx.coroutines.flow.merge
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.kenjinx.android.viewmodels.MainViewModel
|
||||||
|
import org.kenjinx.android.viewmodels.QuickSettings
|
||||||
|
|
||||||
|
private const val DUMMY_LEFT_STICK_PRESS_ID = 10001
|
||||||
|
private const val DUMMY_RIGHT_STICK_PRESS_ID = 10002
|
||||||
|
|
||||||
|
class GameController4(var activity: Activity) : IGameController {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private fun init(context: Context, controller: GameController4): View {
|
||||||
|
val inflater = LayoutInflater.from(context)
|
||||||
|
val parent = FrameLayout(context)
|
||||||
|
val view = inflater.inflate(R.layout.game_layout, parent, false)
|
||||||
|
|
||||||
|
val leftContainer = view.findViewById<FrameLayout>(R.id.leftcontainer)!!
|
||||||
|
val rightContainer = view.findViewById<FrameLayout>(R.id.rightcontainer)!!
|
||||||
|
|
||||||
|
leftContainer.addView(controller.leftGamePad)
|
||||||
|
rightContainer.addView(controller.rightGamePad)
|
||||||
|
|
||||||
|
leftContainer.addOnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
|
||||||
|
val scale = QuickSettings(controller.activity).controllerScale.coerceIn(0.5f, 1.5f)
|
||||||
|
v.pivotX = 0f
|
||||||
|
v.pivotY = v.height.toFloat()
|
||||||
|
v.scaleX = scale
|
||||||
|
v.scaleY = scale
|
||||||
|
}
|
||||||
|
rightContainer.addOnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
|
||||||
|
val scale = QuickSettings(controller.activity).controllerScale.coerceIn(0.5f, 1.5f)
|
||||||
|
v.pivotX = v.width.toFloat()
|
||||||
|
v.pivotY = v.height.toFloat()
|
||||||
|
v.scaleX = scale
|
||||||
|
v.scaleY = scale
|
||||||
|
}
|
||||||
|
|
||||||
|
leftContainer.post { leftContainer.requestLayout() }
|
||||||
|
rightContainer.post { rightContainer.requestLayout() }
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Compose(viewModel: MainViewModel) {
|
||||||
|
AndroidView(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
factory = { context ->
|
||||||
|
val controller = GameController4(viewModel.activity)
|
||||||
|
val c = init(context, controller)
|
||||||
|
|
||||||
|
viewModel.activity.lifecycleScope.launch {
|
||||||
|
val events = merge(
|
||||||
|
controller.leftGamePad.events(),
|
||||||
|
controller.rightGamePad.events()
|
||||||
|
)
|
||||||
|
events.safeCollect { controller.handleEvent(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.controllerView = c
|
||||||
|
viewModel.setGameController(controller)
|
||||||
|
controller.setVisible(QuickSettings(viewModel.activity).useVirtualController)
|
||||||
|
c
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var controllerView: View? = null
|
||||||
|
var leftGamePad: RadialGamePad
|
||||||
|
var rightGamePad: RadialGamePad
|
||||||
|
var controllerId: Int = -1
|
||||||
|
override val isVisible: Boolean
|
||||||
|
get() = controllerView?.isVisible ?: false
|
||||||
|
|
||||||
|
init {
|
||||||
|
val useSwitchLayout = QuickSettings(activity).useSwitchLayout
|
||||||
|
leftGamePad = RadialGamePad(generateConfig4(true, useSwitchLayout), 16f, activity)
|
||||||
|
rightGamePad = RadialGamePad(generateConfig4(false, useSwitchLayout), 16f, activity)
|
||||||
|
|
||||||
|
leftGamePad.primaryDialMaxSizeDp = 200f
|
||||||
|
rightGamePad.primaryDialMaxSizeDp = 200f
|
||||||
|
|
||||||
|
leftGamePad.gravityX = -1f
|
||||||
|
leftGamePad.gravityY = 1f
|
||||||
|
rightGamePad.gravityX = 1f
|
||||||
|
rightGamePad.gravityY = 1f
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setVisible(isVisible: Boolean) {
|
||||||
|
controllerView?.apply {
|
||||||
|
this.isVisible = isVisible
|
||||||
|
if (isVisible) connect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun connect() {
|
||||||
|
if (controllerId == -1)
|
||||||
|
controllerId = KenjinxNative.inputConnectGamepad(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleEvent(ev: Event) {
|
||||||
|
if (controllerId == -1)
|
||||||
|
controllerId = KenjinxNative.inputConnectGamepad(0)
|
||||||
|
|
||||||
|
controllerId.apply {
|
||||||
|
when (ev) {
|
||||||
|
is Event.Button -> {
|
||||||
|
if (ev.id == DUMMY_LEFT_STICK_PRESS_ID || ev.id == DUMMY_RIGHT_STICK_PRESS_ID) return
|
||||||
|
when (ev.action) {
|
||||||
|
KeyEvent.ACTION_UP -> KenjinxNative.inputSetButtonReleased(ev.id, this)
|
||||||
|
KeyEvent.ACTION_DOWN -> KenjinxNative.inputSetButtonPressed(ev.id, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Event.Direction -> {
|
||||||
|
when (ev.id) {
|
||||||
|
GamePadButtonInputId.DpadUp.ordinal -> {
|
||||||
|
if (ev.xAxis > 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
} else if (ev.xAxis < 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
} else {
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
}
|
||||||
|
if (ev.yAxis < 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
} else if (ev.yAxis > 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
} else {
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GamePadButtonInputId.LeftStick.ordinal -> {
|
||||||
|
val setting = QuickSettings(activity)
|
||||||
|
val x = MathUtils.clamp(ev.xAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
val y = MathUtils.clamp(ev.yAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
KenjinxNative.inputSetStickAxis(1, x, -y, this)
|
||||||
|
}
|
||||||
|
GamePadButtonInputId.RightStick.ordinal -> {
|
||||||
|
val setting = QuickSettings(activity)
|
||||||
|
val x = MathUtils.clamp(ev.xAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
val y = MathUtils.clamp(ev.yAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
KenjinxNative.inputSetStickAxis(2, x, -y, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateConfig4(isLeft: Boolean, useSwitchLayout: Boolean): GamePadConfig {
|
||||||
|
val distance = 0.3f
|
||||||
|
val buttonScale = 1f
|
||||||
|
|
||||||
|
if (isLeft) {
|
||||||
|
return GamePadConfig(
|
||||||
|
/* ringSegments = */ 12,
|
||||||
|
/* Primary (Stick) */
|
||||||
|
// IMPORTANT: pressButtonId -> DUMMY_LEFT_STICK_PRESS_ID, so that double tap does not trigger L3
|
||||||
|
PrimaryDialConfig.Stick(
|
||||||
|
GamePadButtonInputId.LeftStick.ordinal,
|
||||||
|
DUMMY_LEFT_STICK_PRESS_ID,
|
||||||
|
setOf(),
|
||||||
|
"LeftStick",
|
||||||
|
null
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
// D-Pad
|
||||||
|
SecondaryDialConfig.Cross(
|
||||||
|
/* sector */ 10,
|
||||||
|
/* size */ 3,
|
||||||
|
/* gap */ 2.1f,
|
||||||
|
distance,
|
||||||
|
CrossConfig(
|
||||||
|
GamePadButtonInputId.DpadUp.ordinal,
|
||||||
|
CrossConfig.Shape.STANDARD,
|
||||||
|
null,
|
||||||
|
setOf(),
|
||||||
|
CrossContentDescription(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// Minus
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 9,
|
||||||
|
buttonScale,
|
||||||
|
0.3f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.Minus.ordinal,
|
||||||
|
"-",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"Minus",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// L-Bumper
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 2,
|
||||||
|
1.2f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftShoulder.ordinal,
|
||||||
|
"L",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftBumper",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// ZL-Trigger
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 2,
|
||||||
|
2f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftTrigger.ordinal,
|
||||||
|
"ZL",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftTrigger",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return GamePadConfig(
|
||||||
|
/* ringSegments = */ 12,
|
||||||
|
/* Primary (ABXY) */
|
||||||
|
PrimaryDialConfig.PrimaryButtons(
|
||||||
|
if (useSwitchLayout) {
|
||||||
|
// Switch/Nintendo: A=Right, X=Top, Y=Left, B=Bottom
|
||||||
|
listOf(
|
||||||
|
ButtonConfig(GamePadButtonInputId.A.ordinal, "A", true, null, "A", setOf(), true, null), // Right
|
||||||
|
ButtonConfig(GamePadButtonInputId.X.ordinal, "X", true, null, "X", setOf(), true, null), // Top
|
||||||
|
ButtonConfig(GamePadButtonInputId.Y.ordinal, "Y", true, null, "Y", setOf(), true, null), // Left
|
||||||
|
ButtonConfig(GamePadButtonInputId.B.ordinal, "B", true, null, "B", setOf(), true, null) // Bottom
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Xbox-Stil: B=Right, Y=Top, X=Left, A=Bottom
|
||||||
|
listOf(
|
||||||
|
ButtonConfig(GamePadButtonInputId.B.ordinal, "B", true, null, "B", setOf(), true, null), // Right
|
||||||
|
ButtonConfig(GamePadButtonInputId.Y.ordinal, "Y", true, null, "Y", setOf(), true, null), // Top
|
||||||
|
ButtonConfig(GamePadButtonInputId.X.ordinal, "X", true, null, "X", setOf(), true, null), // Left
|
||||||
|
ButtonConfig(GamePadButtonInputId.A.ordinal, "A", true, null, "A", setOf(), true, null) // Bottom
|
||||||
|
)
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
0f,
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
// Right stick
|
||||||
|
// IMPORTANT: pressButtonId -> DUMMY_RIGHT_STICK_PRESS_ID, so that double tap does not trigger R3
|
||||||
|
SecondaryDialConfig.Stick(
|
||||||
|
/* sector */ 6,
|
||||||
|
/* size */ 3,
|
||||||
|
/* gap */ 2.7f,
|
||||||
|
distance,
|
||||||
|
GamePadButtonInputId.RightStick.ordinal,
|
||||||
|
DUMMY_RIGHT_STICK_PRESS_ID,
|
||||||
|
null,
|
||||||
|
setOf(),
|
||||||
|
"RightStick",
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// Plus
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 9,
|
||||||
|
buttonScale,
|
||||||
|
0.3f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.Plus.ordinal,
|
||||||
|
"+",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"Plus",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// R-Bumper
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 3,
|
||||||
|
1.2f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightShoulder.ordinal,
|
||||||
|
"R",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightBumper",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// ZR-Trigger
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 3,
|
||||||
|
2f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightTrigger.ordinal,
|
||||||
|
"ZR",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightTrigger",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// R3 separat
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 3,
|
||||||
|
buttonScale,
|
||||||
|
0f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightStickButton.ordinal,
|
||||||
|
"R3",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightStickButton",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// L3 separat
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 4,
|
||||||
|
buttonScale,
|
||||||
|
0f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftStickButton.ordinal,
|
||||||
|
"L3",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftStickButton",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,414 @@
|
|||||||
|
package org.kenjinx.android
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import androidx.core.math.MathUtils
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.swordfish.radialgamepad.library.RadialGamePad
|
||||||
|
import com.swordfish.radialgamepad.library.config.ButtonConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.CrossConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.CrossContentDescription
|
||||||
|
import com.swordfish.radialgamepad.library.config.PrimaryDialConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.SecondaryDialConfig
|
||||||
|
import com.swordfish.radialgamepad.library.event.Event
|
||||||
|
import kotlinx.coroutines.flow.merge
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.kenjinx.android.viewmodels.MainViewModel
|
||||||
|
import org.kenjinx.android.viewmodels.QuickSettings
|
||||||
|
|
||||||
|
private const val DUMMY_LEFT_STICK_PRESS_ID = 10001
|
||||||
|
private const val DUMMY_RIGHT_STICK_PRESS_ID = 10002
|
||||||
|
|
||||||
|
class GameController5(var activity: Activity) : IGameController {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private fun init(context: Context, controller: GameController5): View {
|
||||||
|
val inflater = LayoutInflater.from(context)
|
||||||
|
val parent = FrameLayout(context)
|
||||||
|
val view = inflater.inflate(R.layout.game_layout, parent, false)
|
||||||
|
|
||||||
|
val leftContainer = view.findViewById<FrameLayout>(R.id.leftcontainer)!!
|
||||||
|
val rightContainer = view.findViewById<FrameLayout>(R.id.rightcontainer)!!
|
||||||
|
|
||||||
|
leftContainer.addView(controller.leftGamePad)
|
||||||
|
rightContainer.addView(controller.rightGamePad)
|
||||||
|
|
||||||
|
leftContainer.addOnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
|
||||||
|
val scale = QuickSettings(controller.activity).controllerScale.coerceIn(0.5f, 1.5f)
|
||||||
|
v.pivotX = 0f
|
||||||
|
v.pivotY = v.height.toFloat()
|
||||||
|
v.scaleX = scale
|
||||||
|
v.scaleY = scale
|
||||||
|
}
|
||||||
|
rightContainer.addOnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
|
||||||
|
val scale = QuickSettings(controller.activity).controllerScale.coerceIn(0.5f, 1.5f)
|
||||||
|
v.pivotX = v.width.toFloat()
|
||||||
|
v.pivotY = v.height.toFloat()
|
||||||
|
v.scaleX = scale
|
||||||
|
v.scaleY = scale
|
||||||
|
}
|
||||||
|
|
||||||
|
leftContainer.post { leftContainer.requestLayout() }
|
||||||
|
rightContainer.post { rightContainer.requestLayout() }
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Compose(viewModel: MainViewModel) {
|
||||||
|
AndroidView(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
factory = { context ->
|
||||||
|
val controller = GameController5(viewModel.activity)
|
||||||
|
val c = init(context, controller)
|
||||||
|
|
||||||
|
viewModel.activity.lifecycleScope.launch {
|
||||||
|
val events = merge(
|
||||||
|
controller.leftGamePad.events(),
|
||||||
|
controller.rightGamePad.events()
|
||||||
|
)
|
||||||
|
events.safeCollect { controller.handleEvent(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.controllerView = c
|
||||||
|
viewModel.setGameController(controller)
|
||||||
|
controller.setVisible(QuickSettings(viewModel.activity).useVirtualController)
|
||||||
|
c
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var controllerView: View? = null
|
||||||
|
var leftGamePad: RadialGamePad
|
||||||
|
var rightGamePad: RadialGamePad
|
||||||
|
var controllerId: Int = -1
|
||||||
|
override val isVisible: Boolean
|
||||||
|
get() = controllerView?.isVisible ?: false
|
||||||
|
|
||||||
|
init {
|
||||||
|
val useSwitchLayout = QuickSettings(activity).useSwitchLayout
|
||||||
|
leftGamePad = RadialGamePad(generateConfig5(true, useSwitchLayout), 16f, activity)
|
||||||
|
rightGamePad = RadialGamePad(generateConfig5(false, useSwitchLayout), 16f, activity)
|
||||||
|
|
||||||
|
leftGamePad.primaryDialMaxSizeDp = 200f
|
||||||
|
rightGamePad.primaryDialMaxSizeDp = 200f
|
||||||
|
|
||||||
|
leftGamePad.gravityX = -1f
|
||||||
|
leftGamePad.gravityY = 1f
|
||||||
|
rightGamePad.gravityX = 1f
|
||||||
|
rightGamePad.gravityY = 1f
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setVisible(isVisible: Boolean) {
|
||||||
|
controllerView?.apply {
|
||||||
|
this.isVisible = isVisible
|
||||||
|
if (isVisible) connect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun connect() {
|
||||||
|
if (controllerId == -1)
|
||||||
|
controllerId = KenjinxNative.inputConnectGamepad(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleEvent(ev: Event) {
|
||||||
|
if (controllerId == -1)
|
||||||
|
controllerId = KenjinxNative.inputConnectGamepad(0)
|
||||||
|
|
||||||
|
controllerId.apply {
|
||||||
|
when (ev) {
|
||||||
|
is Event.Button -> {
|
||||||
|
if (ev.id == DUMMY_LEFT_STICK_PRESS_ID || ev.id == DUMMY_RIGHT_STICK_PRESS_ID) return
|
||||||
|
when (ev.action) {
|
||||||
|
KeyEvent.ACTION_UP -> KenjinxNative.inputSetButtonReleased(ev.id, this)
|
||||||
|
KeyEvent.ACTION_DOWN -> KenjinxNative.inputSetButtonPressed(ev.id, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Event.Direction -> {
|
||||||
|
when (ev.id) {
|
||||||
|
GamePadButtonInputId.DpadUp.ordinal -> {
|
||||||
|
if (ev.xAxis > 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
} else if (ev.xAxis < 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
} else {
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
}
|
||||||
|
if (ev.yAxis < 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
} else if (ev.yAxis > 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
} else {
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GamePadButtonInputId.LeftStick.ordinal -> {
|
||||||
|
val setting = QuickSettings(activity)
|
||||||
|
val x = MathUtils.clamp(ev.xAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
val y = MathUtils.clamp(ev.yAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
KenjinxNative.inputSetStickAxis(1, x, -y, this)
|
||||||
|
}
|
||||||
|
GamePadButtonInputId.RightStick.ordinal -> {
|
||||||
|
val setting = QuickSettings(activity)
|
||||||
|
val x = MathUtils.clamp(ev.xAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
val y = MathUtils.clamp(ev.yAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
KenjinxNative.inputSetStickAxis(2, x, -y, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateConfig5(isLeft: Boolean, useSwitchLayout: Boolean): GamePadConfig {
|
||||||
|
val distance = 0.3f
|
||||||
|
val buttonScale = 1f
|
||||||
|
|
||||||
|
if (isLeft) {
|
||||||
|
return GamePadConfig(
|
||||||
|
/* ringSegments = */ 12,
|
||||||
|
/* Primary (Stick) */
|
||||||
|
// IMPORTANT: pressButtonId -> DUMMY_LEFT_STICK_PRESS_ID, so that double tap does not trigger L3
|
||||||
|
PrimaryDialConfig.Stick(
|
||||||
|
GamePadButtonInputId.LeftStick.ordinal,
|
||||||
|
DUMMY_LEFT_STICK_PRESS_ID,
|
||||||
|
setOf(),
|
||||||
|
"LeftStick",
|
||||||
|
null
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
// D-Pad
|
||||||
|
SecondaryDialConfig.Cross(
|
||||||
|
/* sector */ 10,
|
||||||
|
/* size */ 3,
|
||||||
|
/* gap */ 2.1f,
|
||||||
|
distance,
|
||||||
|
CrossConfig(
|
||||||
|
GamePadButtonInputId.DpadUp.ordinal,
|
||||||
|
CrossConfig.Shape.STANDARD,
|
||||||
|
null,
|
||||||
|
setOf(),
|
||||||
|
CrossContentDescription(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// Minus
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 9,
|
||||||
|
buttonScale,
|
||||||
|
0.3f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.Minus.ordinal,
|
||||||
|
"-",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"Minus",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// L Bumper
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 3,
|
||||||
|
1.5f,
|
||||||
|
1.0f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftShoulder.ordinal,
|
||||||
|
"L",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftBumper",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// ZL Trigger
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 2,
|
||||||
|
1.5f,
|
||||||
|
1.1f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftTrigger.ordinal,
|
||||||
|
"ZL",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftTrigger",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return GamePadConfig(
|
||||||
|
/* ringSegments = */ 12,
|
||||||
|
/* Primary (ABXY) */
|
||||||
|
PrimaryDialConfig.PrimaryButtons(
|
||||||
|
if (useSwitchLayout) {
|
||||||
|
// Switch/Nintendo: A=Right, X=Top, Y=Left, B=Bottom
|
||||||
|
listOf(
|
||||||
|
ButtonConfig(GamePadButtonInputId.A.ordinal, "A", true, null, "A", setOf(), true, null), // Right
|
||||||
|
ButtonConfig(GamePadButtonInputId.X.ordinal, "X", true, null, "X", setOf(), true, null), // Top
|
||||||
|
ButtonConfig(GamePadButtonInputId.Y.ordinal, "Y", true, null, "Y", setOf(), true, null), // Left
|
||||||
|
ButtonConfig(GamePadButtonInputId.B.ordinal, "B", true, null, "B", setOf(), true, null) // Bottom
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Xbox-Stil: B=Right, Y=Top, X=Left, A=Bottom
|
||||||
|
listOf(
|
||||||
|
ButtonConfig(GamePadButtonInputId.B.ordinal, "B", true, null, "B", setOf(), true, null), // Right
|
||||||
|
ButtonConfig(GamePadButtonInputId.Y.ordinal, "Y", true, null, "Y", setOf(), true, null), // Top
|
||||||
|
ButtonConfig(GamePadButtonInputId.X.ordinal, "X", true, null, "X", setOf(), true, null), // Left
|
||||||
|
ButtonConfig(GamePadButtonInputId.A.ordinal, "A", true, null, "A", setOf(), true, null) // Bottom
|
||||||
|
)
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
0f,
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
// Right stick
|
||||||
|
// IMPORTANT: pressButtonId -> DUMMY_RIGHT_STICK_PRESS_ID, so that double tap does not trigger R3
|
||||||
|
SecondaryDialConfig.Stick(
|
||||||
|
/* sector */ 6,
|
||||||
|
/* size */ 3,
|
||||||
|
/* gap */ 2.7f,
|
||||||
|
distance,
|
||||||
|
GamePadButtonInputId.RightStick.ordinal,
|
||||||
|
DUMMY_RIGHT_STICK_PRESS_ID,
|
||||||
|
null,
|
||||||
|
setOf(),
|
||||||
|
"RightStick",
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// Plus
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 9,
|
||||||
|
buttonScale,
|
||||||
|
0.3f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.Plus.ordinal,
|
||||||
|
"+",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"Plus",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// R Bumper
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 3,
|
||||||
|
1.5f,
|
||||||
|
1.0f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightShoulder.ordinal,
|
||||||
|
"R",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightBumper",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// ZR Trigger
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 4,
|
||||||
|
1.5f,
|
||||||
|
1.1f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightTrigger.ordinal,
|
||||||
|
"ZR",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightTrigger",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// R3 as a separate button
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 3,
|
||||||
|
1.1f,
|
||||||
|
0f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightStickButton.ordinal,
|
||||||
|
"R3",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightStickButton",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// L3 as a separate button
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 4,
|
||||||
|
1.1f,
|
||||||
|
0f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftStickButton.ordinal,
|
||||||
|
"L3",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftStickButton",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,411 @@
|
|||||||
|
package org.kenjinx.android
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import androidx.core.math.MathUtils
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.swordfish.radialgamepad.library.RadialGamePad
|
||||||
|
import com.swordfish.radialgamepad.library.config.ButtonConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.CrossConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.CrossContentDescription
|
||||||
|
import com.swordfish.radialgamepad.library.config.PrimaryDialConfig
|
||||||
|
import com.swordfish.radialgamepad.library.config.SecondaryDialConfig
|
||||||
|
import com.swordfish.radialgamepad.library.event.Event
|
||||||
|
import kotlinx.coroutines.flow.merge
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.kenjinx.android.viewmodels.MainViewModel
|
||||||
|
import org.kenjinx.android.viewmodels.QuickSettings
|
||||||
|
|
||||||
|
private const val DUMMY_LEFT_STICK_PRESS_ID = 10001
|
||||||
|
private const val DUMMY_RIGHT_STICK_PRESS_ID = 10002
|
||||||
|
|
||||||
|
class GameController6(var activity: Activity) : IGameController {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private fun init(context: Context, controller: GameController6): View {
|
||||||
|
val inflater = LayoutInflater.from(context)
|
||||||
|
val parent = FrameLayout(context)
|
||||||
|
val view = inflater.inflate(R.layout.game_layout, parent, false)
|
||||||
|
|
||||||
|
val leftContainer = view.findViewById<FrameLayout>(R.id.leftcontainer)!!
|
||||||
|
val rightContainer = view.findViewById<FrameLayout>(R.id.rightcontainer)!!
|
||||||
|
|
||||||
|
leftContainer.addView(controller.leftGamePad)
|
||||||
|
rightContainer.addView(controller.rightGamePad)
|
||||||
|
|
||||||
|
leftContainer.addOnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
|
||||||
|
val scale = QuickSettings(controller.activity).controllerScale.coerceIn(0.5f, 1.5f)
|
||||||
|
v.pivotX = 0f
|
||||||
|
v.pivotY = v.height.toFloat()
|
||||||
|
v.scaleX = scale
|
||||||
|
v.scaleY = scale
|
||||||
|
}
|
||||||
|
rightContainer.addOnLayoutChangeListener { v, _, _, _, _, _, _, _, _ ->
|
||||||
|
val scale = QuickSettings(controller.activity).controllerScale.coerceIn(0.5f, 1.5f)
|
||||||
|
v.pivotX = v.width.toFloat()
|
||||||
|
v.pivotY = v.height.toFloat()
|
||||||
|
v.scaleX = scale
|
||||||
|
v.scaleY = scale
|
||||||
|
}
|
||||||
|
|
||||||
|
leftContainer.post { leftContainer.requestLayout() }
|
||||||
|
rightContainer.post { rightContainer.requestLayout() }
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Compose(viewModel: MainViewModel) {
|
||||||
|
AndroidView(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
factory = { context ->
|
||||||
|
val controller = GameController6(viewModel.activity)
|
||||||
|
val c = init(context, controller)
|
||||||
|
|
||||||
|
viewModel.activity.lifecycleScope.launch {
|
||||||
|
val events = merge(
|
||||||
|
controller.leftGamePad.events(),
|
||||||
|
controller.rightGamePad.events()
|
||||||
|
)
|
||||||
|
events.safeCollect { controller.handleEvent(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.controllerView = c
|
||||||
|
viewModel.setGameController(controller)
|
||||||
|
controller.setVisible(QuickSettings(viewModel.activity).useVirtualController)
|
||||||
|
c
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var controllerView: View? = null
|
||||||
|
var leftGamePad: RadialGamePad
|
||||||
|
var rightGamePad: RadialGamePad
|
||||||
|
var controllerId: Int = -1
|
||||||
|
override val isVisible: Boolean
|
||||||
|
get() = controllerView?.isVisible ?: false
|
||||||
|
|
||||||
|
init {
|
||||||
|
val useSwitchLayout = QuickSettings(activity).useSwitchLayout
|
||||||
|
leftGamePad = RadialGamePad(generateConfig6(true, useSwitchLayout), 16f, activity)
|
||||||
|
rightGamePad = RadialGamePad(generateConfig6(false, useSwitchLayout), 16f, activity)
|
||||||
|
|
||||||
|
leftGamePad.primaryDialMaxSizeDp = 200f
|
||||||
|
rightGamePad.primaryDialMaxSizeDp = 200f
|
||||||
|
|
||||||
|
leftGamePad.gravityX = -1f
|
||||||
|
leftGamePad.gravityY = 1f
|
||||||
|
rightGamePad.gravityX = 1f
|
||||||
|
rightGamePad.gravityY = 1f
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setVisible(isVisible: Boolean) {
|
||||||
|
controllerView?.apply {
|
||||||
|
this.isVisible = isVisible
|
||||||
|
if (isVisible) connect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun connect() {
|
||||||
|
if (controllerId == -1)
|
||||||
|
controllerId = KenjinxNative.inputConnectGamepad(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleEvent(ev: Event) {
|
||||||
|
if (controllerId == -1)
|
||||||
|
controllerId = KenjinxNative.inputConnectGamepad(0)
|
||||||
|
|
||||||
|
controllerId.apply {
|
||||||
|
when (ev) {
|
||||||
|
is Event.Button -> {
|
||||||
|
if (ev.id == DUMMY_LEFT_STICK_PRESS_ID || ev.id == DUMMY_RIGHT_STICK_PRESS_ID) return
|
||||||
|
when (ev.action) {
|
||||||
|
KeyEvent.ACTION_UP -> KenjinxNative.inputSetButtonReleased(ev.id, this)
|
||||||
|
KeyEvent.ACTION_DOWN -> KenjinxNative.inputSetButtonPressed(ev.id, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Event.Direction -> {
|
||||||
|
when (ev.id) {
|
||||||
|
GamePadButtonInputId.DpadUp.ordinal -> {
|
||||||
|
if (ev.xAxis > 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
} else if (ev.xAxis < 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
} else {
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, this)
|
||||||
|
}
|
||||||
|
if (ev.yAxis < 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
} else if (ev.yAxis > 0) {
|
||||||
|
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
} else {
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, this)
|
||||||
|
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GamePadButtonInputId.LeftStick.ordinal -> {
|
||||||
|
val setting = QuickSettings(activity)
|
||||||
|
val x = MathUtils.clamp(ev.xAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
val y = MathUtils.clamp(ev.yAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
KenjinxNative.inputSetStickAxis(1, x, -y, this)
|
||||||
|
}
|
||||||
|
GamePadButtonInputId.RightStick.ordinal -> {
|
||||||
|
val setting = QuickSettings(activity)
|
||||||
|
val x = MathUtils.clamp(ev.xAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
val y = MathUtils.clamp(ev.yAxis * setting.controllerStickSensitivity, -1f, 1f)
|
||||||
|
KenjinxNative.inputSetStickAxis(2, x, -y, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateConfig6(isLeft: Boolean, useSwitchLayout: Boolean): GamePadConfig {
|
||||||
|
val distance = 0.3f
|
||||||
|
val buttonScale = 1f
|
||||||
|
|
||||||
|
if (isLeft) {
|
||||||
|
return GamePadConfig(
|
||||||
|
/* ringSegments = */ 12,
|
||||||
|
/* Primary (Stick) */
|
||||||
|
// IMPORTANT: pressButtonId -> DUMMY_LEFT_STICK_PRESS_ID, so that double tap does not trigger L3
|
||||||
|
PrimaryDialConfig.Stick(
|
||||||
|
GamePadButtonInputId.LeftStick.ordinal,
|
||||||
|
DUMMY_LEFT_STICK_PRESS_ID,
|
||||||
|
setOf(),
|
||||||
|
"LeftStick",
|
||||||
|
null
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
// D-Pad
|
||||||
|
SecondaryDialConfig.Cross(
|
||||||
|
/* sector */ 10,
|
||||||
|
/* size */ 3,
|
||||||
|
/* gap */ 2.5f,
|
||||||
|
distance,
|
||||||
|
CrossConfig(
|
||||||
|
GamePadButtonInputId.DpadUp.ordinal,
|
||||||
|
CrossConfig.Shape.STANDARD,
|
||||||
|
null,
|
||||||
|
setOf(),
|
||||||
|
CrossContentDescription(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// Minus
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 1,
|
||||||
|
buttonScale,
|
||||||
|
2f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.Minus.ordinal,
|
||||||
|
"-",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"Minus",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// L Bumper
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 2,
|
||||||
|
distance,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftShoulder.ordinal,
|
||||||
|
"L",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftBumper",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// ZL Trigger
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 9,
|
||||||
|
buttonScale,
|
||||||
|
distance,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftTrigger.ordinal,
|
||||||
|
"ZL",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftTrigger",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return GamePadConfig(
|
||||||
|
/* ringSegments = */ 12,
|
||||||
|
/* Primary (ABXY) */
|
||||||
|
PrimaryDialConfig.PrimaryButtons(
|
||||||
|
if (useSwitchLayout) {
|
||||||
|
// Switch/Nintendo: A=Right, X=Top, Y=Left, B=Bottom
|
||||||
|
listOf(
|
||||||
|
ButtonConfig(GamePadButtonInputId.A.ordinal, "A", true, null, "A", setOf(), true, null), // Right
|
||||||
|
ButtonConfig(GamePadButtonInputId.X.ordinal, "X", true, null, "X", setOf(), true, null), // Top
|
||||||
|
ButtonConfig(GamePadButtonInputId.Y.ordinal, "Y", true, null, "Y", setOf(), true, null), // Left
|
||||||
|
ButtonConfig(GamePadButtonInputId.B.ordinal, "B", true, null, "B", setOf(), true, null) // Bottom
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Xbox Style: B=Right, Y=Top, X=Left, A=Bottom
|
||||||
|
listOf(
|
||||||
|
ButtonConfig(GamePadButtonInputId.B.ordinal, "B", true, null, "B", setOf(), true, null), // Right
|
||||||
|
ButtonConfig(GamePadButtonInputId.Y.ordinal, "Y", true, null, "Y", setOf(), true, null), // Top
|
||||||
|
ButtonConfig(GamePadButtonInputId.X.ordinal, "X", true, null, "X", setOf(), true, null), // Left
|
||||||
|
ButtonConfig(GamePadButtonInputId.A.ordinal, "A", true, null, "A", setOf(), true, null) // Bottom
|
||||||
|
)
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
0f,
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
listOf(
|
||||||
|
// Right stick (unchanged)
|
||||||
|
// IMPORTANT: pressButtonId -> DUMMY_RIGHT_STICK_PRESS_ID, so that double tap does not trigger R3
|
||||||
|
SecondaryDialConfig.Stick(
|
||||||
|
/* sector */ 6,
|
||||||
|
/* size */ 3,
|
||||||
|
/* gap */ 2.5f,
|
||||||
|
0.7f,
|
||||||
|
GamePadButtonInputId.RightStick.ordinal,
|
||||||
|
DUMMY_RIGHT_STICK_PRESS_ID,
|
||||||
|
null,
|
||||||
|
setOf(),
|
||||||
|
"RightStick",
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// Plus
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 5,
|
||||||
|
buttonScale,
|
||||||
|
2f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.Plus.ordinal,
|
||||||
|
"+",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"Plus",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// R Bumper
|
||||||
|
SecondaryDialConfig.DoubleButton(
|
||||||
|
/* sector */ 3,
|
||||||
|
distance,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightShoulder.ordinal,
|
||||||
|
"R",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightBumper",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// ZR Trigger
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 9,
|
||||||
|
buttonScale,
|
||||||
|
distance,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightTrigger.ordinal,
|
||||||
|
"ZR",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightTrigger",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
|
||||||
|
// R3 as a separate button
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 5,
|
||||||
|
buttonScale,
|
||||||
|
0.0f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.RightStickButton.ordinal,
|
||||||
|
"R3",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"RightStickButton",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
// L3 as a separate button
|
||||||
|
SecondaryDialConfig.SingleButton(
|
||||||
|
/* sector */ 6,
|
||||||
|
buttonScale,
|
||||||
|
0.0f,
|
||||||
|
ButtonConfig(
|
||||||
|
GamePadButtonInputId.LeftStickButton.ordinal,
|
||||||
|
"L3",
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
"LeftStickButton",
|
||||||
|
setOf(),
|
||||||
|
true,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
null,
|
||||||
|
SecondaryDialConfig.RotationProcessor()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,510 @@
|
|||||||
|
package org.kenjinx.android
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.ServiceConnection
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.IBinder
|
||||||
|
import android.os.Looper
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.SurfaceHolder
|
||||||
|
import android.view.SurfaceView
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import org.kenjinx.android.service.EmulationService
|
||||||
|
import org.kenjinx.android.viewmodels.GameModel
|
||||||
|
import org.kenjinx.android.viewmodels.MainViewModel
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
@SuppressLint("ViewConstructor")
|
||||||
|
class GameHost(context: Context?, private val mainViewModel: MainViewModel) : SurfaceView(context),
|
||||||
|
SurfaceHolder.Callback {
|
||||||
|
|
||||||
|
private var isProgressHidden: Boolean = false
|
||||||
|
private var progress: MutableState<String>? = null
|
||||||
|
private var progressValue: MutableState<Float>? = null
|
||||||
|
private var showLoading: MutableState<Boolean>? = null
|
||||||
|
private var game: GameModel? = null
|
||||||
|
|
||||||
|
private var _isClosed: Boolean = false
|
||||||
|
private var _renderingThreadWatcher: Thread? = null
|
||||||
|
private var _height: Int = 0
|
||||||
|
private var _width: Int = 0
|
||||||
|
private var _updateThread: Thread? = null
|
||||||
|
private var _guestThread: Thread? = null
|
||||||
|
private var _isInit: Boolean = false
|
||||||
|
private var _isStarted: Boolean = false
|
||||||
|
private val _nativeWindow: NativeWindow
|
||||||
|
|
||||||
|
private val mainHandler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
// ---- Foreground service binding ----
|
||||||
|
private var emuBound = false
|
||||||
|
private var emuBinder: EmulationService.LocalBinder? = null
|
||||||
|
private var _startedViaService = false
|
||||||
|
private var _inputInitialized: Boolean = false
|
||||||
|
|
||||||
|
private val emuConn = object : ServiceConnection {
|
||||||
|
override fun onServiceConnected(name: ComponentName, service: IBinder) {
|
||||||
|
emuBinder = service as EmulationService.LocalBinder
|
||||||
|
emuBound = true
|
||||||
|
ghLog("EmulationService bound")
|
||||||
|
|
||||||
|
// If the start has already been prepared and no loop is currently running → start it in the service now
|
||||||
|
if (_isStarted && !_startedViaService && _guestThread == null) {
|
||||||
|
startRunLoopInService()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onServiceDisconnected(name: ComponentName) {
|
||||||
|
ghLog("EmulationService unbound")
|
||||||
|
emuBound = false
|
||||||
|
emuBinder = null
|
||||||
|
_startedViaService = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize Stabilizer
|
||||||
|
private var stabilizerActive = false
|
||||||
|
|
||||||
|
// last known Android rotation (0,1,2,3)
|
||||||
|
private var lastRotation: Int? = null
|
||||||
|
|
||||||
|
// Debounce for resize kick
|
||||||
|
private var lastKickAt = 0L
|
||||||
|
|
||||||
|
var currentSurface: Long = -1
|
||||||
|
private set
|
||||||
|
|
||||||
|
val currentWindowHandle: Long
|
||||||
|
get() = _nativeWindow.nativePointer
|
||||||
|
|
||||||
|
init {
|
||||||
|
holder.addCallback(this)
|
||||||
|
_nativeWindow = NativeWindow(this)
|
||||||
|
mainViewModel.gameHost = this
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ghLog(msg: String) {
|
||||||
|
val enabled = BuildConfig.DEBUG && org.kenjinx.android.viewmodels.QuickSettings(mainViewModel.activity).enableDebugLogs
|
||||||
|
if (enabled) Log.d("GameHost", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Re)bind the current ANativeWindow to the renderer.
|
||||||
|
* Forces a fresh native pointer and passes it to C#.
|
||||||
|
*/
|
||||||
|
fun rebindNativeWindow(force: Boolean = false) {
|
||||||
|
if (_isClosed) return
|
||||||
|
try {
|
||||||
|
currentSurface = _nativeWindow.requeryWindowHandle()
|
||||||
|
_nativeWindow.swapInterval = 0
|
||||||
|
KenjinxNative.deviceSetWindowHandle(currentWindowHandle)
|
||||||
|
|
||||||
|
val w = if (holder.surfaceFrame.width() > 0) holder.surfaceFrame.width() else width
|
||||||
|
val h = if (holder.surfaceFrame.height() > 0) holder.surfaceFrame.height() else height
|
||||||
|
if (w > 0 && h > 0) {
|
||||||
|
if (MainActivity.mainViewModel?.rendererReady == true) {
|
||||||
|
try { KenjinxNative.graphicsRendererSetSize(w, h) } catch (_: Throwable) {}
|
||||||
|
}
|
||||||
|
if (_inputInitialized) {
|
||||||
|
try { KenjinxNative.inputSetClientSize(w, h) } catch (_: Throwable) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_: Throwable) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After a successful reattachment, safely "wake up" the swapchain/viewport:
|
||||||
|
* - Set rotation
|
||||||
|
* - Two consecutive resize kicks
|
||||||
|
*/
|
||||||
|
fun postReattachKicks(rotation: Int?) {
|
||||||
|
if (_isClosed) return
|
||||||
|
try {
|
||||||
|
KenjinxNative.setSurfaceRotationByAndroidRotation(rotation ?: 0)
|
||||||
|
val w = if (holder.surfaceFrame.width() > 0) holder.surfaceFrame.width() else width
|
||||||
|
val h = if (holder.surfaceFrame.height() > 0) holder.surfaceFrame.height() else height
|
||||||
|
if (w > 0 && h > 0 &&
|
||||||
|
MainActivity.mainViewModel?.rendererReady == true &&
|
||||||
|
_isStarted && _inputInitialized
|
||||||
|
) {
|
||||||
|
try { KenjinxNative.resizeRendererAndInput(w, h) } catch (_: Throwable) {}
|
||||||
|
mainHandler.postDelayed({
|
||||||
|
try { KenjinxNative.resizeRendererAndInput(w, h) } catch (_: Throwable) {}
|
||||||
|
}, 32)
|
||||||
|
}
|
||||||
|
} catch (_: Throwable) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------- Surface Lifecycle --------
|
||||||
|
|
||||||
|
override fun surfaceCreated(holder: SurfaceHolder) {
|
||||||
|
ghLog("surfaceCreated")
|
||||||
|
// Bind early so that the service is already in place before we start
|
||||||
|
ensureServiceStartedAndBound()
|
||||||
|
rebindNativeWindow(force = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
||||||
|
ghLog("surfaceChanged ${width}x$height")
|
||||||
|
if (_isClosed) return
|
||||||
|
|
||||||
|
// Always rebind – even if the size remains the same
|
||||||
|
rebindNativeWindow(force = true)
|
||||||
|
|
||||||
|
val sizeChanged = (_width != width || _height != height)
|
||||||
|
_width = width
|
||||||
|
_height = height
|
||||||
|
|
||||||
|
// Ensure service availability & start rendering
|
||||||
|
ensureServiceStartedAndBound()
|
||||||
|
start(holder)
|
||||||
|
|
||||||
|
// Stabilize resizing (adopts a plausible final size setting)
|
||||||
|
startStabilizedResize(expectedRotation = lastRotation)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
||||||
|
ghLog("surfaceDestroyed → shutdownBinding()")
|
||||||
|
try { KenjinxNative.detachWindow() } catch (_: Throwable) {}
|
||||||
|
// Always bind and unbind (prevents leaks when swiping away tasks)
|
||||||
|
shutdownBinding()
|
||||||
|
// The actual emulator termination happens via close() / Exit Game
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onWindowVisibilityChanged(visibility: Int) {
|
||||||
|
super.onWindowVisibilityChanged(visibility)
|
||||||
|
if (visibility != VISIBLE) {
|
||||||
|
ghLog("window not visible → shutdownBinding()")
|
||||||
|
try { KenjinxNative.detachWindow() } catch (_: Throwable) {}
|
||||||
|
shutdownBinding()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------- UI Progress --------
|
||||||
|
|
||||||
|
fun setProgress(info: String, progressVal: Float) {
|
||||||
|
showLoading?.apply {
|
||||||
|
progressValue?.apply { this.value = progressVal }
|
||||||
|
progress?.apply { this.value = info }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setProgressStates(
|
||||||
|
showLoading: MutableState<Boolean>?,
|
||||||
|
progressValue: MutableState<Float>?,
|
||||||
|
progress: MutableState<String>?
|
||||||
|
) {
|
||||||
|
this.showLoading = showLoading
|
||||||
|
this.progressValue = progressValue
|
||||||
|
this.progress = progress
|
||||||
|
showLoading?.apply { value = !isProgressHidden }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hideProgressIndicator() {
|
||||||
|
isProgressHidden = true
|
||||||
|
showLoading?.apply {
|
||||||
|
if (value == isProgressHidden) value = !isProgressHidden
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------- Start/Stop Emulation --------
|
||||||
|
|
||||||
|
private fun start(surfaceHolder: SurfaceHolder) {
|
||||||
|
if (_isStarted) return
|
||||||
|
|
||||||
|
// Do NOT set _isStarted = true immediately → first prepare everything
|
||||||
|
rebindNativeWindow(force = true)
|
||||||
|
|
||||||
|
game = if (mainViewModel.isMiiEditorLaunched) null else mainViewModel.gameModel
|
||||||
|
|
||||||
|
// Input initialize
|
||||||
|
KenjinxNative.inputInitialize(width, height)
|
||||||
|
_inputInitialized = true
|
||||||
|
|
||||||
|
val id = mainViewModel.physicalControllerManager?.connect()
|
||||||
|
mainViewModel.motionSensorManager?.setControllerId(id ?: -1)
|
||||||
|
|
||||||
|
val currentRot = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
mainViewModel.activity.display?.rotation
|
||||||
|
} else null
|
||||||
|
lastRotation = currentRot
|
||||||
|
|
||||||
|
try {
|
||||||
|
KenjinxNative.setSurfaceRotationByAndroidRotation(currentRot ?: 0)
|
||||||
|
try { KenjinxNative.deviceSetWindowHandle(currentWindowHandle) } catch (_: Throwable) {}
|
||||||
|
|
||||||
|
// Gentle kick only when renderer is READY **and** input is initialized
|
||||||
|
if (width > 0 && height > 0 &&
|
||||||
|
MainActivity.mainViewModel?.rendererReady == true &&
|
||||||
|
_inputInitialized
|
||||||
|
) {
|
||||||
|
try { KenjinxNative.resizeRendererAndInput(width, height) } catch (_: Throwable) {}
|
||||||
|
}
|
||||||
|
} catch (_: Throwable) {}
|
||||||
|
|
||||||
|
val qs = org.kenjinx.android.viewmodels.QuickSettings(mainViewModel.activity)
|
||||||
|
try { KenjinxNative.graphicsSetFullscreenStretch(qs.stretchToFullscreen) } catch (_: Throwable) {}
|
||||||
|
|
||||||
|
// The host is now considered "started".
|
||||||
|
_isStarted = true
|
||||||
|
|
||||||
|
// Always try starting with the service first; if binding is not yet complete → wait briefly, then fall back
|
||||||
|
if (emuBound) {
|
||||||
|
startRunLoopInService()
|
||||||
|
} else {
|
||||||
|
ghLog("Service not yet bound → delayed runloop start")
|
||||||
|
mainHandler.postDelayed({
|
||||||
|
if (!_isStarted) return@postDelayed
|
||||||
|
if (emuBound) {
|
||||||
|
startRunLoopInService()
|
||||||
|
} else {
|
||||||
|
// Fallback: Local thread (this should rarely happen)
|
||||||
|
ghLog("Fallback: starting RunLoop in local thread")
|
||||||
|
_guestThread = thread(start = true, name = "KenjinxGuest") { runGame() }
|
||||||
|
}
|
||||||
|
}, 150)
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateThread = thread(start = true, name = "KenjinxInput/Stats") {
|
||||||
|
var c = 0
|
||||||
|
while (_isStarted) {
|
||||||
|
KenjinxNative.inputUpdate()
|
||||||
|
Thread.sleep(1)
|
||||||
|
if (++c >= 1000) {
|
||||||
|
if (progressValue?.value == -1f) {
|
||||||
|
progress?.apply {
|
||||||
|
this.value = "Loading ${if (mainViewModel.isMiiEditorLaunched) "Mii Editor" else game?.titleName ?: ""}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c = 0
|
||||||
|
mainViewModel.updateStats(
|
||||||
|
KenjinxNative.deviceGetGameFifo(),
|
||||||
|
KenjinxNative.deviceGetGameFrameRate(),
|
||||||
|
KenjinxNative.deviceGetGameFrameTime()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun runGame() {
|
||||||
|
mainViewModel.onEmulationStarted()
|
||||||
|
try {
|
||||||
|
KenjinxNative.graphicsRendererRunLoop()
|
||||||
|
} finally {
|
||||||
|
mainViewModel.onEmulationStopped()
|
||||||
|
}
|
||||||
|
game?.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun close() {
|
||||||
|
ghLog("close()")
|
||||||
|
_isClosed = true
|
||||||
|
_isInit = false
|
||||||
|
_isStarted = false
|
||||||
|
_inputInitialized = false
|
||||||
|
|
||||||
|
KenjinxNative.uiHandlerSetResponse(false, "")
|
||||||
|
|
||||||
|
// Stop emulation in the service (if it was started there)
|
||||||
|
try {
|
||||||
|
if (emuBound && _startedViaService) {
|
||||||
|
emuBinder?.stopEmulation {
|
||||||
|
// Close is handled in the service hard-close path.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_: Throwable) { }
|
||||||
|
|
||||||
|
// Fallback: Terminate local thread
|
||||||
|
try { _updateThread?.join(200) } catch (_: Throwable) {}
|
||||||
|
try { _renderingThreadWatcher?.join(200) } catch (_: Throwable) {}
|
||||||
|
try { _guestThread?.join(1000) } catch (_: Throwable) {}
|
||||||
|
|
||||||
|
if (!(emuBound && _startedViaService)) {
|
||||||
|
try { KenjinxNative.deviceCloseEmulation() } catch (_: Throwable) {}
|
||||||
|
mainViewModel.onEmulationStopped()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the bond
|
||||||
|
shutdownBinding()
|
||||||
|
|
||||||
|
// Explicitly terminate the service (if it is still running)
|
||||||
|
try {
|
||||||
|
mainViewModel.activity.stopService(Intent(mainViewModel.activity, EmulationService::class.java))
|
||||||
|
} catch (_: Throwable) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------- Orientation / Resize --------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Securely setting the renderer/input size
|
||||||
|
*/
|
||||||
|
@Synchronized
|
||||||
|
private fun safeSetSize(w: Int, h: Int) {
|
||||||
|
if (_isClosed || w <= 0 || h <= 0) return
|
||||||
|
try {
|
||||||
|
ghLog("safeSetSize: ${w}x$h (started=$_isStarted, inputInit=$_inputInitialized)")
|
||||||
|
KenjinxNative.graphicsRendererSetSize(w, h)
|
||||||
|
if (_isStarted && _inputInitialized) {
|
||||||
|
KenjinxNative.inputSetClientSize(w, h)
|
||||||
|
}
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
Log.e("GameHost", "safeSetSize failed: ${t.message}", t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the activity when the rotation/layout changes.
|
||||||
|
* Detects 90°↔270° and forces (debounces) a requery/resize.
|
||||||
|
*/
|
||||||
|
fun onOrientationOrSizeChanged(rotation: Int? = null) {
|
||||||
|
if (_isClosed) return
|
||||||
|
|
||||||
|
val old = lastRotation
|
||||||
|
lastRotation = rotation
|
||||||
|
|
||||||
|
val isSideFlip = (old == 1 && rotation == 3) || (old == 3 && rotation == 1)
|
||||||
|
|
||||||
|
if (isSideFlip) {
|
||||||
|
try { KenjinxNative.setSurfaceRotationByAndroidRotation(rotation) } catch (_: Throwable) {}
|
||||||
|
rebindNativeWindow(force = true)
|
||||||
|
val now = android.os.SystemClock.uptimeMillis()
|
||||||
|
if (now - lastKickAt >= 300L && _inputInitialized && MainActivity.mainViewModel?.rendererReady == true) {
|
||||||
|
lastKickAt = now
|
||||||
|
val w = if (holder.surfaceFrame.width() > 0) holder.surfaceFrame.width() else width
|
||||||
|
val h = if (holder.surfaceFrame.height() > 0) holder.surfaceFrame.height() else height
|
||||||
|
if (w > 0 && h > 0) {
|
||||||
|
try { KenjinxNative.resizeRendererAndInput(w, h) } catch (_: Throwable) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
startStabilizedResize(rotation)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait a moment until the surface has its final dimensions after rotation,
|
||||||
|
* checks plausibility (portrait/landscape) and only then sets the size.
|
||||||
|
*/
|
||||||
|
private fun startStabilizedResize(expectedRotation: Int?) {
|
||||||
|
if (_isClosed) return
|
||||||
|
|
||||||
|
// Restart if already active
|
||||||
|
if (stabilizerActive) {
|
||||||
|
stabilizerActive = false
|
||||||
|
}
|
||||||
|
stabilizerActive = true
|
||||||
|
|
||||||
|
var attempts = 0
|
||||||
|
var stableCount = 0
|
||||||
|
var lastW = -1
|
||||||
|
var lastH = -1
|
||||||
|
|
||||||
|
val task = object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
if (!_isStarted || _isClosed) {
|
||||||
|
stabilizerActive = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prefer real frame size
|
||||||
|
var w = holder.surfaceFrame.width()
|
||||||
|
var h = holder.surfaceFrame.height()
|
||||||
|
|
||||||
|
// Fallbacks
|
||||||
|
if (w <= 0 || h <= 0) {
|
||||||
|
w = width
|
||||||
|
h = height
|
||||||
|
}
|
||||||
|
|
||||||
|
// If rotation is known: Force plausibility (Landscape ↔ Portrait)
|
||||||
|
expectedRotation?.let { rot ->
|
||||||
|
val landscape = (rot == 1 || rot == 3) // ROTATION_90/270
|
||||||
|
if (landscape && h > w) {
|
||||||
|
val t = w; w = h; h = t
|
||||||
|
} else if (!landscape && w > h) {
|
||||||
|
val t = w; w = h; h = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stability test
|
||||||
|
if (w == lastW && h == lastH && w > 0 && h > 0) {
|
||||||
|
stableCount++
|
||||||
|
} else {
|
||||||
|
stableCount = 0
|
||||||
|
lastW = w
|
||||||
|
lastH = h
|
||||||
|
}
|
||||||
|
|
||||||
|
attempts++
|
||||||
|
|
||||||
|
// 1 stable tick or a maximum of 12 attempts
|
||||||
|
if ((stableCount >= 1 || attempts >= 12) && w > 0 && h > 0) {
|
||||||
|
ghLog("resize stabilized after $attempts ticks → ${w}x$h")
|
||||||
|
safeSetSize(w, h)
|
||||||
|
stabilizerActive = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stabilizerActive) {
|
||||||
|
mainHandler.postDelayed(this, 16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mainHandler.post(task)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== Service helpers =====
|
||||||
|
|
||||||
|
/** Callable from Activity/Surface lifecycle to ensure FGS is running */
|
||||||
|
fun ensureServiceStartedAndBound() {
|
||||||
|
val act = mainViewModel.activity
|
||||||
|
val intent = Intent(act, EmulationService::class.java)
|
||||||
|
try {
|
||||||
|
act.startForegroundService(intent)
|
||||||
|
} catch (_: Throwable) { }
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!emuBound) {
|
||||||
|
act.bindService(intent, emuConn, Context.BIND_AUTO_CREATE)
|
||||||
|
}
|
||||||
|
} catch (_: Throwable) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Call this from the Activity in onPause/onStop/onDestroy (and internally in surfaceDestroyed/onWindowVisibilityChanged) */
|
||||||
|
fun shutdownBinding() {
|
||||||
|
if (emuBound) {
|
||||||
|
try {
|
||||||
|
mainViewModel.activity.unbindService(emuConn)
|
||||||
|
} catch (_: Throwable) { }
|
||||||
|
emuBound = false
|
||||||
|
emuBinder = null
|
||||||
|
_startedViaService = false
|
||||||
|
ghLog("shutdownBinding() → unbound")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startRunLoopInService() {
|
||||||
|
if (!emuBound) return
|
||||||
|
if (_startedViaService) return
|
||||||
|
_startedViaService = true
|
||||||
|
|
||||||
|
emuBinder?.startEmulation {
|
||||||
|
try {
|
||||||
|
mainViewModel.onEmulationStarted()
|
||||||
|
KenjinxNative.graphicsRendererRunLoop()
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
Log.e("GameHost", "RunLoop crash in service", t)
|
||||||
|
} finally {
|
||||||
|
_startedViaService = false
|
||||||
|
mainViewModel.onEmulationStopped()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ghLog("RunLoop started in EmulationService")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package org.kenjinx.android
|
||||||
|
|
||||||
|
enum class GamePadButtonInputId {
|
||||||
|
None,
|
||||||
|
|
||||||
|
// Buttons
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
LeftStickButton,
|
||||||
|
RightStickButton,
|
||||||
|
LeftShoulder,
|
||||||
|
RightShoulder,
|
||||||
|
LeftTrigger,
|
||||||
|
RightTrigger,
|
||||||
|
DpadUp,
|
||||||
|
DpadDown,
|
||||||
|
DpadLeft,
|
||||||
|
DpadRight,
|
||||||
|
Minus,
|
||||||
|
Plus,
|
||||||
|
|
||||||
|
// Stick
|
||||||
|
LeftStick,
|
||||||
|
RightStick
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user