mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-10-04 14:28:56 +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/
|
||||
[Bb]in/
|
||||
[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
|
||||
!packages/*/build/
|
||||
@@ -177,3 +173,6 @@ PublishProfiles/
|
||||
|
||||
# Glade backup files
|
||||
*.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>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<DebugType Condition="'$(Configuration)'=='Release'">none</DebugType>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
+21
-20
@@ -3,53 +3,54 @@
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<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.Desktop" Version="11.3.16" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.16" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.16" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.13" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.13" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.13" />
|
||||
<PackageVersion Include="Svg.Controls.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="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||
<PackageVersion Include="Concentus" Version="2.2.2" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
|
||||
<PackageVersion Include="DynamicData" Version="9.4.31" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.5.1" />
|
||||
<PackageVersion Include="Gommon" Version="2.8.1.2" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.4.1" />
|
||||
<PackageVersion Include="Gommon" Version="2.8.1.1" />
|
||||
<PackageVersion Include="Humanizer" Version="3.0.10" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.18.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.17.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
|
||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
<PackageVersion Include="NetCoreServer" Version="8.0.7" />
|
||||
<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="OpenTK.Core" Version="4.9.4" />
|
||||
<PackageVersion Include="OpenTK.Graphics" Version="4.9.4" />
|
||||
<PackageVersion Include="OpenTK.Audio.OpenAL" 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="Ryujinx.Audio.OpenAL" Version="1.25.1" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Linux" Version="6.1.4-build6" />
|
||||
<PackageVersion Include="Ryujinx.Audio.OpenAL" Version="1.25.2" />
|
||||
<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.Windows" Version="6.1.4-build6" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.MoltenVK" Version="1.4.2-ryujinx.3" />
|
||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.133" />
|
||||
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.501.0" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Windows" Version="6.1.3-build5" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.128" />
|
||||
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.707.0" />
|
||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Shaderc" 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.KHR" Version="2.23.0" />
|
||||
<PackageVersion Include="SkiaSharp" Version="3.119.2" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="3.119.2" />
|
||||
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
|
||||
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="10.0.8" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.4-a40db6c" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="9.0.12" />
|
||||
<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>
|
||||
</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" />
|
||||
</Folder>
|
||||
<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.SDL3/Ryujinx.Audio.Backends.SDL3.csproj" />
|
||||
<Project Path="src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj" />
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
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
|
||||
RYUJINX_BIN="Ryujinx"
|
||||
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>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>Ryujinx.icns</string>
|
||||
<key>CFBundleIconName</key>
|
||||
<string>Ryujinx</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -42,17 +40,17 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.0</string>
|
||||
<string>1.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2.0.0</string>
|
||||
<string>1.1.0</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
<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>
|
||||
<string>public.app-category.games</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
Binary file not shown.
@@ -19,7 +19,7 @@ if platform.system() == "Darwin":
|
||||
else:
|
||||
OTOOL = shutil.which("llvm-otool")
|
||||
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}")
|
||||
if otool_path is not None:
|
||||
OTOOL = otool_path
|
||||
@@ -562,29 +562,26 @@ search_path = [
|
||||
|
||||
|
||||
for path in content_directory.rglob("**/*.dylib"):
|
||||
if not path.name.startswith("._"):
|
||||
current_search_path = [path.parent]
|
||||
current_search_path.extend(search_path)
|
||||
current_search_path = [path.parent]
|
||||
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(
|
||||
path,
|
||||
get_path_related_to_target_exec(content_directory, path),
|
||||
current_search_path,
|
||||
content_directory,
|
||||
)
|
||||
fixup_dylib(
|
||||
path,
|
||||
get_path_related_to_target_exec(content_directory, path),
|
||||
current_search_path,
|
||||
content_directory,
|
||||
)
|
||||
|
||||
for path in content_directory.rglob("**/*.so"):
|
||||
if not path.name.startswith("._"):
|
||||
current_search_path = [path.parent]
|
||||
current_search_path.extend(search_path)
|
||||
current_search_path = [path.parent]
|
||||
current_search_path.extend(search_path)
|
||||
|
||||
fixup_dylib(
|
||||
path,
|
||||
get_path_related_to_target_exec(content_directory, path),
|
||||
current_search_path,
|
||||
content_directory,
|
||||
)
|
||||
fixup_dylib(
|
||||
path,
|
||||
get_path_related_to_target_exec(content_directory, path),
|
||||
current_search_path,
|
||||
content_directory,
|
||||
)
|
||||
|
||||
|
||||
with open(executable_path, "rb") as input:
|
||||
|
||||
@@ -26,7 +26,7 @@ else:
|
||||
LIPO = shutil.which("llvm-lipo")
|
||||
|
||||
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}")
|
||||
if lipo_path is not None:
|
||||
LIPO = lipo_path
|
||||
@@ -47,12 +47,14 @@ def get_new_name(
|
||||
input_component = str(input_dylib_path).replace(str(input_directory), "")[1:]
|
||||
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")
|
||||
if res.startswith("Non-fat file"):
|
||||
return [res.split(":")[-1].strip()]
|
||||
else:
|
||||
return res.split("are:")[-1].strip().split()
|
||||
|
||||
def is_fat_file(dylib_path: Path) -> str:
|
||||
res = subprocess.check_output([LIPO, "-info", str(dylib_path.absolute())]).decode(
|
||||
"utf-8"
|
||||
)
|
||||
|
||||
return not res.split("\n")[0].startswith("Non-fat file")
|
||||
|
||||
|
||||
def construct_universal_dylib(
|
||||
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
|
||||
)
|
||||
else:
|
||||
arm64_archs = get_archs(arm64_input_dylib_path)
|
||||
x86_64_archs = get_archs(x86_64_input_dylib_path) if x86_64_input_dylib_path.exists() else []
|
||||
|
||||
if "arm64" in arm64_archs and "x86_64" in arm64_archs:
|
||||
shutil.copy2(arm64_input_dylib_path, output_dylib_path)
|
||||
elif x86_64_archs:
|
||||
if is_fat_file(arm64_input_dylib_path) or not x86_64_input_dylib_path.exists():
|
||||
with open(output_dylib_path, "wb") as dst:
|
||||
with open(arm64_input_dylib_path, "rb") as src:
|
||||
dst.write(src.read())
|
||||
else:
|
||||
subprocess.check_call(
|
||||
[
|
||||
LIPO,
|
||||
|
||||
@@ -25,41 +25,26 @@ cp "$PUBLISH_DIRECTORY"/*.dylib "$APP_BUNDLE_DIRECTORY/Contents/Frameworks"
|
||||
cp Info.plist "$APP_BUNDLE_DIRECTORY/Contents"
|
||||
cp Ryujinx.icns "$APP_BUNDLE_DIRECTORY/Contents/Resources/Ryujinx.icns"
|
||||
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"
|
||||
|
||||
echo -n "APPL????" > "$APP_BUNDLE_DIRECTORY/Contents/PkgInfo"
|
||||
|
||||
# Fixup libraries and executable
|
||||
echo "Running bundle fix up python script"
|
||||
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
|
||||
echo "Starting signing process"
|
||||
if ! [ -x "$(command -v codesign)" ];
|
||||
then
|
||||
if ! [ -x "$(command -v rcodesign)" ];
|
||||
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
|
||||
fi
|
||||
|
||||
echo "Using 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"
|
||||
# cargo install apple-codesign
|
||||
echo "Usign rcodesign for ad-hoc signing"
|
||||
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$APP_BUNDLE_DIRECTORY"
|
||||
else
|
||||
echo "Using 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"
|
||||
echo "Usign codesign for ad-hoc signing"
|
||||
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$APP_BUNDLE_DIRECTORY"
|
||||
fi
|
||||
fi
|
||||
@@ -20,19 +20,7 @@ SOURCE_REVISION_ID=$6
|
||||
CONFIGURATION=$7
|
||||
EXTRA_ARGS=$8
|
||||
|
||||
if [[ "$(uname)" == "Darwin" ]]; then
|
||||
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" ];
|
||||
if [ "$VERSION" == "1.1.0" ];
|
||||
then
|
||||
RELEASE_TAR_FILE_NAME=ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar
|
||||
else
|
||||
@@ -78,11 +66,11 @@ python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_APP_
|
||||
|
||||
if ! [ -x "$(command -v lipo)" ];
|
||||
then
|
||||
if ! [ -x "$(command -v llvm-lipo-17)" ];
|
||||
if ! [ -x "$(command -v llvm-lipo-14)" ];
|
||||
then
|
||||
LIPO=llvm-lipo
|
||||
else
|
||||
LIPO=llvm-lipo-17
|
||||
LIPO=llvm-lipo-14
|
||||
fi
|
||||
else
|
||||
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"
|
||||
rm "$RELEASE_TAR_FILE_NAME"
|
||||
|
||||
# Create legacy update package for Avalonia to not left behind old testers.
|
||||
if [ "$VERSION" != "1.1.0" ];
|
||||
then
|
||||
cp $RELEASE_TAR_FILE_NAME.gz test-ava-ryujinx-$VERSION-macos_universal.app.tar.gz
|
||||
fi
|
||||
|
||||
popd
|
||||
|
||||
echo "Done"
|
||||
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": {
|
||||
"version": "10.0.100",
|
||||
"version": "9.0.100",
|
||||
"rollForward": "latestFeature"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,13 +13,13 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
|
||||
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)
|
||||
{
|
||||
// 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).
|
||||
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);
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -119,7 +119,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_pendingBranches.TryGetValue(target, out var list))
|
||||
if (!_pendingBranches.TryGetValue(target, out List<(ArmCondition Condition, long BranchPos)> list))
|
||||
{
|
||||
list = new List<(ArmCondition, long)>();
|
||||
_pendingBranches.Add(target, list);
|
||||
|
||||
@@ -321,7 +321,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
|
||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||
|
||||
var cond = ((Comparison)comp.AsInt32()).ToArmCondition();
|
||||
ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
|
||||
|
||||
GenerateCompareCommon(context, operation);
|
||||
|
||||
@@ -353,7 +353,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
Debug.Assert(dest.Type == OperandType.I32);
|
||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||
|
||||
var cond = ((Comparison)comp.AsInt32()).ToArmCondition();
|
||||
ArmCondition cond = ((Comparison)comp.AsInt32()).ToArmCondition();
|
||||
|
||||
GenerateCompareCommon(context, operation);
|
||||
|
||||
|
||||
@@ -847,7 +847,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
|
||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||
|
||||
var compType = (Comparison)comp.AsInt32();
|
||||
Comparison compType = (Comparison)comp.AsInt32();
|
||||
|
||||
return compType is Comparison.Equal or Comparison.NotEqual;
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
NumberLocals(cfg, regMasks.RegistersCount);
|
||||
|
||||
var context = new AllocationContext(stackAlloc, regMasks, _intervals.Count);
|
||||
AllocationContext context = new(stackAlloc, regMasks, _intervals.Count);
|
||||
|
||||
BuildIntervals(cfg, context);
|
||||
|
||||
|
||||
@@ -15,12 +15,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
if (_count + 1 > _capacity)
|
||||
{
|
||||
var oldSpan = Span;
|
||||
Span<LiveInterval> oldSpan = Span;
|
||||
|
||||
_capacity = Math.Max(4, _capacity * 2);
|
||||
_items = Allocators.References.Allocate<LiveInterval>((uint)_capacity);
|
||||
|
||||
var newSpan = Span;
|
||||
Span<LiveInterval> newSpan = Span;
|
||||
|
||||
oldSpan.CopyTo(newSpan);
|
||||
}
|
||||
|
||||
@@ -16,12 +16,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
if (Count + 1 > _capacity)
|
||||
{
|
||||
var oldSpan = Span;
|
||||
Span<int> oldSpan = Span;
|
||||
|
||||
_capacity = Math.Max(4, _capacity * 2);
|
||||
_items = Allocators.Default.Allocate<int>((uint)_capacity);
|
||||
|
||||
var newSpan = Span;
|
||||
Span<int> newSpan = Span;
|
||||
|
||||
oldSpan.CopyTo(newSpan);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using ARMeilleure.CodeGen.Linking;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using Microsoft.IO;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -1324,8 +1325,8 @@ namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
public (byte[], RelocInfo) GetCode()
|
||||
{
|
||||
var jumps = CollectionsMarshal.AsSpan(_jumps);
|
||||
var relocs = CollectionsMarshal.AsSpan(_relocs);
|
||||
Span<Jump> jumps = CollectionsMarshal.AsSpan(_jumps);
|
||||
Span<Reloc> relocs = CollectionsMarshal.AsSpan(_relocs);
|
||||
|
||||
// Write jump relative offsets.
|
||||
bool modified;
|
||||
@@ -1410,13 +1411,13 @@ namespace ARMeilleure.CodeGen.X86
|
||||
// Write the code, ignoring the dummy bytes after jumps, into a new stream.
|
||||
_stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
using var codeStream = MemoryStreamManager.Shared.GetStream();
|
||||
var assembler = new Assembler(codeStream, HasRelocs);
|
||||
using RecyclableMemoryStream codeStream = MemoryStreamManager.Shared.GetStream();
|
||||
Assembler assembler = new(codeStream, HasRelocs);
|
||||
|
||||
bool hasRelocs = HasRelocs;
|
||||
int relocIndex = 0;
|
||||
int relocOffset = 0;
|
||||
var relocEntries = hasRelocs
|
||||
RelocEntry[] relocEntries = hasRelocs
|
||||
? new RelocEntry[relocs.Length]
|
||||
: Array.Empty<RelocEntry>();
|
||||
|
||||
@@ -1469,8 +1470,8 @@ namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
_stream.CopyTo(codeStream);
|
||||
|
||||
var code = codeStream.ToArray();
|
||||
var relocInfo = new RelocInfo(relocEntries);
|
||||
byte[] code = codeStream.ToArray();
|
||||
RelocInfo relocInfo = new(relocEntries);
|
||||
|
||||
return (code, relocInfo);
|
||||
}
|
||||
|
||||
@@ -622,7 +622,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||
|
||||
var cond = ((Comparison)comp.AsInt32()).ToX86Condition();
|
||||
X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
|
||||
|
||||
GenerateCompareCommon(context, operation);
|
||||
|
||||
@@ -660,7 +660,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Debug.Assert(dest.Type == OperandType.I32);
|
||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||
|
||||
var cond = ((Comparison)comp.AsInt32()).ToX86Condition();
|
||||
X86Condition cond = ((Comparison)comp.AsInt32()).ToX86Condition();
|
||||
|
||||
GenerateCompareCommon(context, operation);
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
memGetXcr0.Reprotect(0, (ulong)asmGetXcr0.Length, MemoryPermission.ReadAndExecute);
|
||||
|
||||
var fGetXcr0 = Marshal.GetDelegateForFunctionPointer<GetXcr0>(memGetXcr0.Pointer);
|
||||
GetXcr0 fGetXcr0 = Marshal.GetDelegateForFunctionPointer<GetXcr0>(memGetXcr0.Pointer);
|
||||
|
||||
return fGetXcr0();
|
||||
}
|
||||
|
||||
@@ -759,7 +759,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||
|
||||
var compType = (Comparison)comp.AsInt32();
|
||||
Comparison compType = (Comparison)comp.AsInt32();
|
||||
|
||||
return compType is Comparison.Equal or Comparison.NotEqual;
|
||||
}
|
||||
|
||||
@@ -13,13 +13,13 @@ namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
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)
|
||||
{
|
||||
// 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).
|
||||
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);
|
||||
|
||||
|
||||
@@ -129,13 +129,13 @@ namespace ARMeilleure.Common
|
||||
|
||||
if (count > _count)
|
||||
{
|
||||
var oldMask = _masks;
|
||||
var oldSpan = new Span<long>(_masks, _count);
|
||||
long* oldMask = _masks;
|
||||
Span<long> oldSpan = new(_masks, _count);
|
||||
|
||||
_masks = _allocator.Allocate<long>((uint)count);
|
||||
_count = count;
|
||||
|
||||
var newSpan = new Span<long>(_masks, _count);
|
||||
Span<long> newSpan = new(_masks, _count);
|
||||
|
||||
oldSpan.CopyTo(newSpan);
|
||||
newSpan[oldSpan.Length..].Clear();
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace ARMeilleure.Common
|
||||
}
|
||||
|
||||
int index = _freeHint++;
|
||||
var page = GetPage(index);
|
||||
Span<TEntry> page = GetPage(index);
|
||||
|
||||
_allocated.Set(index);
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace ARMeilleure.Common
|
||||
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);
|
||||
}
|
||||
@@ -136,7 +136,7 @@ namespace ARMeilleure.Common
|
||||
/// <returns>Page for the specified <see cref="index"/></returns>
|
||||
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))
|
||||
{
|
||||
@@ -168,7 +168,7 @@ namespace ARMeilleure.Common
|
||||
{
|
||||
_allocated.Dispose();
|
||||
|
||||
foreach (var page in _pages.Values)
|
||||
foreach (IntPtr page in _pages.Values)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var opc = (opCode >> 16) & 0xf;
|
||||
int opc = (opCode >> 16) & 0xf;
|
||||
|
||||
if ((opc & 0b1) == 1)
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace ARMeilleure.Decoders
|
||||
Op = (opCode >> 20) & 0x1;
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace ARMeilleure.Decoders
|
||||
}
|
||||
else if (DataOp == DataOp.Logical)
|
||||
{
|
||||
var bm = DecoderHelper.DecodeBitMask(opCode, true);
|
||||
DecoderHelper.BitMask bm = DecoderHelper.DecodeBitMask(opCode, true);
|
||||
|
||||
if (bm.IsUndefined)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace ARMeilleure.Decoders
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
for (int i = 0; i < blocks.Count; i++)
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace ARMeilleure.Diagnostics
|
||||
break;
|
||||
|
||||
case OperandKind.Memory:
|
||||
var memOp = operand.GetMemory();
|
||||
MemoryOperand memOp = operand.GetMemory();
|
||||
|
||||
_builder.Append('[');
|
||||
|
||||
@@ -284,7 +284,7 @@ namespace ARMeilleure.Diagnostics
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -415,7 +415,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
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 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;
|
||||
|
||||
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 res = context.ShiftRightUI(context.ShiftLeft(n, Const(31 - msb)), Const(31 - op.Msb));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using ARMeilleure.CodeGen.Linking;
|
||||
using ARMeilleure.Common;
|
||||
using ARMeilleure.Decoders;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.State;
|
||||
@@ -146,12 +147,6 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void EmitCall(ArmEmitterContext context, ulong immediate)
|
||||
{
|
||||
if (context.IsSingleStep)
|
||||
{
|
||||
context.Return(Const(immediate));
|
||||
return;
|
||||
}
|
||||
|
||||
bool isRecursive = immediate == context.EntryAddress;
|
||||
|
||||
if (isRecursive)
|
||||
@@ -166,24 +161,12 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void EmitVirtualCall(ArmEmitterContext context, Operand target)
|
||||
{
|
||||
if (context.IsSingleStep)
|
||||
{
|
||||
if (target.Type == OperandType.I32)
|
||||
{
|
||||
target = context.ZeroExtend32(OperandType.I64, target);
|
||||
}
|
||||
|
||||
context.Return(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitTableBranch(context, target, isJump: false);
|
||||
}
|
||||
EmitTableBranch(context, target, isJump: false);
|
||||
}
|
||||
|
||||
public static void EmitVirtualJump(ArmEmitterContext context, Operand target, bool isReturn)
|
||||
{
|
||||
if (isReturn || context.IsSingleStep)
|
||||
if (isReturn)
|
||||
{
|
||||
EmitReturn(context, target);
|
||||
}
|
||||
@@ -223,7 +206,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
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
|
||||
// onto the dispatch stub.
|
||||
@@ -248,7 +231,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
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);
|
||||
|
||||
Operand index = context.ShiftLeft(
|
||||
|
||||
@@ -143,8 +143,8 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand address = context.Copy(GetIntA32(context, op.Rn));
|
||||
|
||||
var exclusive = (accType & AccessType.Exclusive) != 0;
|
||||
var ordered = (accType & AccessType.Ordered) != 0;
|
||||
bool exclusive = (accType & AccessType.Exclusive) != 0;
|
||||
bool ordered = (accType & AccessType.Ordered) != 0;
|
||||
|
||||
if ((accType & AccessType.Load) != 0)
|
||||
{
|
||||
|
||||
@@ -229,7 +229,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -118,15 +118,15 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCode32SimdCvtFFixed op = (OpCode32SimdCvtFFixed)context.CurrOp;
|
||||
|
||||
var toFixed = op.Opc == 1;
|
||||
bool toFixed = op.Opc == 1;
|
||||
int fracBits = op.Fbits;
|
||||
var unsigned = op.U;
|
||||
bool unsigned = op.U;
|
||||
|
||||
if (toFixed) // F32 to S32 or U32 (fixed)
|
||||
{
|
||||
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));
|
||||
|
||||
return context.Call(info, scaledValue);
|
||||
@@ -136,7 +136,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
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)));
|
||||
}, !unsigned);
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
if (op.Replicate)
|
||||
{
|
||||
var regs = (count > 1) ? 1 : op.Increment;
|
||||
int regs = (count > 1) ? 1 : op.Increment;
|
||||
for (int reg = 0; reg < regs; reg++)
|
||||
{
|
||||
int dreg = reg + d;
|
||||
|
||||
@@ -1,35 +1,59 @@
|
||||
using System;
|
||||
#if ANDROID
|
||||
using System.Runtime.CompilerServices;
|
||||
#else
|
||||
using System.Runtime.InteropServices;
|
||||
#endif
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
static class MathHelper
|
||||
{
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double Abs(double value)
|
||||
{
|
||||
return Math.Abs(value);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double Ceiling(double value)
|
||||
{
|
||||
return Math.Ceiling(value);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double Floor(double value)
|
||||
{
|
||||
return Math.Floor(value);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double Round(double value, int mode)
|
||||
{
|
||||
return Math.Round(value, (MidpointRounding)mode);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double Truncate(double value)
|
||||
{
|
||||
return Math.Truncate(value);
|
||||
@@ -38,31 +62,51 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
static class MathHelperF
|
||||
{
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float Abs(float value)
|
||||
{
|
||||
return MathF.Abs(value);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float Ceiling(float value)
|
||||
{
|
||||
return MathF.Ceiling(value);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float Floor(float value)
|
||||
{
|
||||
return MathF.Floor(value);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float Round(float value, int mode)
|
||||
{
|
||||
return MathF.Round(value, (MidpointRounding)mode);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float Truncate(float value)
|
||||
{
|
||||
return MathF.Truncate(value);
|
||||
|
||||
@@ -2,7 +2,11 @@ using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
#if ANDROID
|
||||
using System.Runtime.CompilerServices;
|
||||
#else
|
||||
using System.Runtime.InteropServices;
|
||||
#endif
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
@@ -35,7 +39,11 @@ namespace ARMeilleure.Instructions
|
||||
Context = null;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static void Break(ulong address, int imm)
|
||||
{
|
||||
Statistics.PauseTimer();
|
||||
@@ -45,7 +53,11 @@ namespace ARMeilleure.Instructions
|
||||
Statistics.ResumeTimer();
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static void SupervisorCall(ulong address, int imm)
|
||||
{
|
||||
Statistics.PauseTimer();
|
||||
@@ -55,7 +67,11 @@ namespace ARMeilleure.Instructions
|
||||
Statistics.ResumeTimer();
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static void Undefined(ulong address, int opCode)
|
||||
{
|
||||
Statistics.PauseTimer();
|
||||
@@ -66,31 +82,51 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
|
||||
#region "System registers"
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static ulong GetCtrEl0()
|
||||
{
|
||||
return GetContext().CtrEl0;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static ulong GetDczidEl0()
|
||||
{
|
||||
return GetContext().DczidEl0;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static ulong GetCntfrqEl0()
|
||||
{
|
||||
return GetContext().CntfrqEl0;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static ulong GetCntpctEl0()
|
||||
{
|
||||
return GetContext().CntpctEl0;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static ulong GetCntvctEl0()
|
||||
{
|
||||
return GetContext().CntvctEl0;
|
||||
@@ -98,31 +134,51 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Read"
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static byte ReadByte(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadGuest<byte>(address);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static ushort ReadUInt16(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadGuest<ushort>(address);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static uint ReadUInt32(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadGuest<uint>(address);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static ulong ReadUInt64(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadGuest<ulong>(address);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 ReadVector128(ulong address)
|
||||
{
|
||||
return GetMemoryManager().ReadGuest<V128>(address);
|
||||
@@ -130,56 +186,92 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Write"
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static void WriteByte(ulong address, byte value)
|
||||
{
|
||||
GetMemoryManager().WriteGuest(address, value);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static void WriteUInt16(ulong address, ushort value)
|
||||
{
|
||||
GetMemoryManager().WriteGuest(address, value);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static void WriteUInt32(ulong address, uint value)
|
||||
{
|
||||
GetMemoryManager().WriteGuest(address, value);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static void WriteUInt64(ulong address, ulong value)
|
||||
{
|
||||
GetMemoryManager().WriteGuest(address, value);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static void WriteVector128(ulong address, V128 value)
|
||||
{
|
||||
GetMemoryManager().WriteGuest(address, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static void EnqueueForRejit(ulong address)
|
||||
{
|
||||
Context.Translator.EnqueueForRejit(address, GetContext().ExecutionMode);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static void SignalMemoryTracking(ulong address, ulong size, byte write)
|
||||
{
|
||||
GetMemoryManager().SignalMemoryTracking(address, size, write == 1);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static void ThrowInvalidMemoryAccess(ulong address)
|
||||
{
|
||||
throw new InvalidAccessException(address);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static ulong GetFunctionAddress(ulong address)
|
||||
{
|
||||
TranslatedFunction function = Context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
|
||||
@@ -187,13 +279,21 @@ namespace ARMeilleure.Instructions
|
||||
return (ulong)function.FuncPointer.ToInt64();
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static void InvalidateCacheLine(ulong address)
|
||||
{
|
||||
Context.Translator.InvalidateJitCacheRegion(address, InstEmit.DczSizeInBytes);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static byte CheckSynchronization()
|
||||
{
|
||||
Statistics.PauseTimer();
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
#if ANDROID
|
||||
using System.Runtime.CompilerServices;
|
||||
#else
|
||||
using System.Runtime.InteropServices;
|
||||
#endif
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
static class SoftFallback
|
||||
{
|
||||
#region "ShrImm64"
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static long SignedShrImm64(long value, long roundConst, int shift)
|
||||
{
|
||||
if (roundConst == 0L)
|
||||
@@ -50,7 +58,11 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
|
||||
{
|
||||
if (roundConst == 0L)
|
||||
@@ -95,7 +107,11 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Saturation"
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static int SatF32ToS32(float value)
|
||||
{
|
||||
if (float.IsNaN(value))
|
||||
@@ -107,7 +123,11 @@ namespace ARMeilleure.Instructions
|
||||
value <= int.MinValue ? int.MinValue : (int)value;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static long SatF32ToS64(float value)
|
||||
{
|
||||
if (float.IsNaN(value))
|
||||
@@ -119,7 +139,11 @@ namespace ARMeilleure.Instructions
|
||||
value <= long.MinValue ? long.MinValue : (long)value;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static uint SatF32ToU32(float value)
|
||||
{
|
||||
if (float.IsNaN(value))
|
||||
@@ -131,7 +155,11 @@ namespace ARMeilleure.Instructions
|
||||
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static ulong SatF32ToU64(float value)
|
||||
{
|
||||
if (float.IsNaN(value))
|
||||
@@ -143,7 +171,11 @@ namespace ARMeilleure.Instructions
|
||||
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static int SatF64ToS32(double value)
|
||||
{
|
||||
if (double.IsNaN(value))
|
||||
@@ -155,7 +187,11 @@ namespace ARMeilleure.Instructions
|
||||
value <= int.MinValue ? int.MinValue : (int)value;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static long SatF64ToS64(double value)
|
||||
{
|
||||
if (double.IsNaN(value))
|
||||
@@ -167,7 +203,11 @@ namespace ARMeilleure.Instructions
|
||||
value <= long.MinValue ? long.MinValue : (long)value;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static uint SatF64ToU32(double value)
|
||||
{
|
||||
if (double.IsNaN(value))
|
||||
@@ -179,7 +219,11 @@ namespace ARMeilleure.Instructions
|
||||
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static ulong SatF64ToU64(double value)
|
||||
{
|
||||
if (double.IsNaN(value))
|
||||
@@ -193,7 +237,11 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Count"
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
||||
{
|
||||
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];
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
||||
{
|
||||
if (value == 0ul)
|
||||
@@ -237,49 +289,81 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Table"
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
|
||||
{
|
||||
return TblOrTbx(default, vector, bytes, tb0);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
|
||||
{
|
||||
return TblOrTbx(default, vector, bytes, tb0, tb1);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
||||
{
|
||||
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
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);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
|
||||
{
|
||||
return TblOrTbx(dest, vector, bytes, tb0);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
|
||||
{
|
||||
return TblOrTbx(dest, vector, bytes, tb0, tb1);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
||||
{
|
||||
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
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);
|
||||
@@ -321,22 +405,54 @@ namespace ARMeilleure.Instructions
|
||||
private const uint Crc32RevPoly = 0xedb88320;
|
||||
private const uint Crc32cRevPoly = 0x82f63b78;
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
|
||||
|
||||
private static uint Crc32h(uint crc, uint poly, ushort val)
|
||||
@@ -387,25 +503,41 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Aes"
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 Decrypt(V128 value, V128 roundKey)
|
||||
{
|
||||
return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 Encrypt(V128 value, V128 roundKey)
|
||||
{
|
||||
return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 InverseMixColumns(V128 value)
|
||||
{
|
||||
return CryptoHelper.AesInvMixColumns(value);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 MixColumns(V128 value)
|
||||
{
|
||||
return CryptoHelper.AesMixColumns(value);
|
||||
@@ -413,7 +545,11 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Sha1"
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
|
||||
{
|
||||
for (int e = 0; e <= 3; e++)
|
||||
@@ -434,13 +570,21 @@ namespace ARMeilleure.Instructions
|
||||
return hash_abcd;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static uint FixedRotate(uint hash_e)
|
||||
{
|
||||
return hash_e.Rol(30);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
|
||||
{
|
||||
for (int e = 0; e <= 3; e++)
|
||||
@@ -461,7 +605,11 @@ namespace ARMeilleure.Instructions
|
||||
return hash_abcd;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
|
||||
{
|
||||
for (int e = 0; e <= 3; e++)
|
||||
@@ -482,7 +630,11 @@ namespace ARMeilleure.Instructions
|
||||
return hash_abcd;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
|
||||
{
|
||||
ulong t2 = w4_7.Extract<ulong>(0);
|
||||
@@ -493,7 +645,11 @@ namespace ARMeilleure.Instructions
|
||||
return result ^ (w0_3 ^ w8_11);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
|
||||
{
|
||||
V128 t = tw0_3 ^ (w12_15 >> 32);
|
||||
@@ -538,19 +694,31 @@ namespace ARMeilleure.Instructions
|
||||
#endregion
|
||||
|
||||
#region "Sha256"
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
||||
{
|
||||
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
||||
{
|
||||
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
|
||||
{
|
||||
V128 result = new();
|
||||
@@ -569,7 +737,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
|
||||
{
|
||||
V128 result = new();
|
||||
@@ -671,7 +843,11 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
#endregion
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static V128 PolynomialMult64_128(ulong op1, ulong op2)
|
||||
{
|
||||
V128 result = V128.Zero;
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
#if ANDROID
|
||||
using System.Runtime.CompilerServices;
|
||||
#else
|
||||
using System.Runtime.InteropServices;
|
||||
#endif
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
@@ -313,7 +317,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
static class SoftFloat16_32
|
||||
{
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPConvert(ushort valueBits)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -489,7 +497,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
static class SoftFloat16_64
|
||||
{
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPConvert(ushort valueBits)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -665,7 +677,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
static class SoftFloat32_16
|
||||
{
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static ushort FPConvert(float value)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -785,13 +801,21 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
static class SoftFloat32
|
||||
{
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPAdd(float value1, float value2)
|
||||
{
|
||||
return FPAddFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPAddFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -848,7 +872,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static int FPCompare(float value1, float value2, byte signalNaNs)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -887,7 +915,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPCompareEQ(float value1, float value2)
|
||||
{
|
||||
return FPCompareEQFpscrImpl(value1, value2, false);
|
||||
@@ -920,19 +952,31 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPCompareEQFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPCompareGE(float value1, float value2)
|
||||
{
|
||||
return FPCompareGEFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPCompareGEFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -962,13 +1006,21 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPCompareGT(float value1, float value2)
|
||||
{
|
||||
return FPCompareGTFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPCompareGTFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -998,31 +1050,51 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPCompareLE(float value1, float value2)
|
||||
{
|
||||
return FPCompareGEFpscrImpl(value2, value1, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPCompareLT(float value1, float value2)
|
||||
{
|
||||
return FPCompareGTFpscrImpl(value2, value1, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPCompareLEFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPCompareLTFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPDiv(float value1, float value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1075,13 +1147,21 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPMax(float value1, float value2)
|
||||
{
|
||||
return FPMaxFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPMaxFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -1148,7 +1228,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPMaxNum(float value1, float value2)
|
||||
{
|
||||
return FPMaxNumFpscrImpl(value1, value2, false);
|
||||
@@ -1174,19 +1258,31 @@ namespace ARMeilleure.Instructions
|
||||
return FPMaxFpscrImpl(value1, value2, standardFpscr);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPMaxNumFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPMin(float value1, float value2)
|
||||
{
|
||||
return FPMinFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPMinFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -1253,13 +1349,21 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPMinNum(float value1, float value2)
|
||||
{
|
||||
return FPMinNumFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPMinNumFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -1285,13 +1389,21 @@ namespace ARMeilleure.Instructions
|
||||
return FPMinFpscrImpl(value1, value2, standardFpscr);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPMul(float value1, float value2)
|
||||
{
|
||||
return FPMulFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPMulFpscr(float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -1344,13 +1456,21 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPMulAdd(float valueA, float value1, float value2)
|
||||
{
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPMulAddFpscr(float valueA, float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||
@@ -1422,7 +1542,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPMulSub(float valueA, float value1, float value2)
|
||||
{
|
||||
value1 = value1.FPNeg();
|
||||
@@ -1430,7 +1554,11 @@ namespace ARMeilleure.Instructions
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPMulSubFpscr(float valueA, float value1, float value2, byte standardFpscr)
|
||||
{
|
||||
value1 = value1.FPNeg();
|
||||
@@ -1438,7 +1566,11 @@ namespace ARMeilleure.Instructions
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPMulX(float value1, float value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1484,7 +1616,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPNegMulAdd(float valueA, float value1, float value2)
|
||||
{
|
||||
valueA = valueA.FPNeg();
|
||||
@@ -1493,7 +1629,11 @@ namespace ARMeilleure.Instructions
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPNegMulSub(float valueA, float value1, float value2)
|
||||
{
|
||||
valueA = valueA.FPNeg();
|
||||
@@ -1501,13 +1641,21 @@ namespace ARMeilleure.Instructions
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPRecipEstimate(float value)
|
||||
{
|
||||
return FPRecipEstimateFpscrImpl(value, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPRecipEstimateFpscr(float value, byte standardFpscr)
|
||||
{
|
||||
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
|
||||
@@ -1538,7 +1686,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else if (MathF.Abs(value) < MathF.Pow(2f, -128))
|
||||
{
|
||||
var overflowToInf = fpcr.GetRoundingMode() switch
|
||||
bool overflowToInf = fpcr.GetRoundingMode() switch
|
||||
{
|
||||
FPRoundingMode.ToNearest => true,
|
||||
FPRoundingMode.TowardsPlusInfinity => !sign,
|
||||
@@ -1600,7 +1748,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPRecipStep(float value1, float value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1635,7 +1787,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPRecipStepFused(float value1, float value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1679,7 +1835,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPRecpX(float value)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1705,13 +1865,21 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPRSqrtEstimate(float value)
|
||||
{
|
||||
return FPRSqrtEstimateFpscrImpl(value, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPRSqrtEstimateFpscr(float value, byte standardFpscr)
|
||||
{
|
||||
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
|
||||
@@ -1831,7 +1999,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPRSqrtStep(float value1, float value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1866,7 +2038,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPRSqrtStepFused(float value1, float value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1910,7 +2086,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPSqrt(float value)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -1953,7 +2133,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static float FPSub(float value1, float value2)
|
||||
{
|
||||
return FPSubFpscrImpl(value1, value2, false);
|
||||
@@ -2200,7 +2384,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
static class SoftFloat64_16
|
||||
{
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static ushort FPConvert(double value)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -2320,13 +2508,21 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
static class SoftFloat64
|
||||
{
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPAdd(double value1, double value2)
|
||||
{
|
||||
return FPAddFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPAddFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -2383,7 +2579,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static int FPCompare(double value1, double value2, byte signalNaNs)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -2422,13 +2622,21 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPCompareEQ(double value1, double value2)
|
||||
{
|
||||
return FPCompareEQFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPCompareEQFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -2461,13 +2669,21 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPCompareGE(double value1, double value2)
|
||||
{
|
||||
return FPCompareGEFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPCompareGEFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -2497,13 +2713,21 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPCompareGT(double value1, double value2)
|
||||
{
|
||||
return FPCompareGTFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPCompareGTFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -2533,31 +2757,51 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPCompareLE(double value1, double value2)
|
||||
{
|
||||
return FPCompareGEFpscrImpl(value2, value1, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPCompareLT(double value1, double value2)
|
||||
{
|
||||
return FPCompareGTFpscrImpl(value2, value1, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPCompareLEFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPCompareLTFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPCompareGTFpscrImpl(value2, value1, standardFpscr == 1);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPDiv(double value1, double value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -2610,13 +2854,21 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPMax(double value1, double value2)
|
||||
{
|
||||
return FPMaxFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPMaxFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -2683,13 +2935,21 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPMaxNum(double value1, double value2)
|
||||
{
|
||||
return FPMaxNumFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPMaxNumFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -2715,13 +2975,21 @@ namespace ARMeilleure.Instructions
|
||||
return FPMaxFpscrImpl(value1, value2, standardFpscr);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPMin(double value1, double value2)
|
||||
{
|
||||
return FPMinFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPMinFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -2788,13 +3056,21 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPMinNum(double value1, double value2)
|
||||
{
|
||||
return FPMinNumFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPMinNumFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -2820,13 +3096,21 @@ namespace ARMeilleure.Instructions
|
||||
return FPMinFpscrImpl(value1, value2, standardFpscr);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPMul(double value1, double value2)
|
||||
{
|
||||
return FPMulFpscrImpl(value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPMulFpscr(double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
|
||||
@@ -2879,13 +3163,21 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPMulAdd(double valueA, double value1, double value2)
|
||||
{
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPMulAddFpscr(double valueA, double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||
@@ -2957,7 +3249,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPMulSub(double valueA, double value1, double value2)
|
||||
{
|
||||
value1 = value1.FPNeg();
|
||||
@@ -2965,7 +3261,11 @@ namespace ARMeilleure.Instructions
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPMulSubFpscr(double valueA, double value1, double value2, byte standardFpscr)
|
||||
{
|
||||
value1 = value1.FPNeg();
|
||||
@@ -2973,7 +3273,11 @@ namespace ARMeilleure.Instructions
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPMulX(double value1, double value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -3019,7 +3323,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPNegMulAdd(double valueA, double value1, double value2)
|
||||
{
|
||||
valueA = valueA.FPNeg();
|
||||
@@ -3028,7 +3336,11 @@ namespace ARMeilleure.Instructions
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPNegMulSub(double valueA, double value1, double value2)
|
||||
{
|
||||
valueA = valueA.FPNeg();
|
||||
@@ -3036,13 +3348,21 @@ namespace ARMeilleure.Instructions
|
||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPRecipEstimate(double value)
|
||||
{
|
||||
return FPRecipEstimateFpscrImpl(value, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPRecipEstimateFpscr(double value, byte standardFpscr)
|
||||
{
|
||||
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
|
||||
@@ -3073,7 +3393,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else if (Math.Abs(value) < Math.Pow(2d, -1024))
|
||||
{
|
||||
var overflowToInf = fpcr.GetRoundingMode() switch
|
||||
bool overflowToInf = fpcr.GetRoundingMode() switch
|
||||
{
|
||||
FPRoundingMode.ToNearest => true,
|
||||
FPRoundingMode.TowardsPlusInfinity => !sign,
|
||||
@@ -3135,7 +3455,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPRecipStep(double value1, double value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -3170,7 +3494,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPRecipStepFused(double value1, double value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -3214,7 +3542,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPRecpX(double value)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -3240,13 +3572,21 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPRSqrtEstimate(double value)
|
||||
{
|
||||
return FPRSqrtEstimateFpscrImpl(value, false);
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPRSqrtEstimateFpscr(double value, byte standardFpscr)
|
||||
{
|
||||
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
|
||||
@@ -3366,7 +3706,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPRSqrtStep(double value1, double value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -3401,7 +3745,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPRSqrtStepFused(double value1, double value2)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -3445,7 +3793,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPSqrt(double value)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
@@ -3488,7 +3840,11 @@ namespace ARMeilleure.Instructions
|
||||
return result;
|
||||
}
|
||||
|
||||
#if ANDROID
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
#else
|
||||
[UnmanagedCallersOnly]
|
||||
#endif
|
||||
public static double FPSub(double value1, double value2)
|
||||
{
|
||||
return FPSubFpscr(value1, value2, false);
|
||||
|
||||
@@ -304,7 +304,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
ushort newCount = checked((ushort)(count + 1));
|
||||
ushort newCapacity = (ushort)Math.Min(capacity * 2, ushort.MaxValue);
|
||||
|
||||
var oldSpan = new Span<T>(data, count);
|
||||
Span<T> oldSpan = new(data, count);
|
||||
|
||||
capacity = newCapacity;
|
||||
data = Allocators.References.Allocate<T>(capacity);
|
||||
@@ -338,7 +338,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
throw new OverflowException();
|
||||
}
|
||||
|
||||
var oldSpan = new Span<T>(data, (int)count);
|
||||
Span<T> oldSpan = new(data, (int)count);
|
||||
|
||||
capacity = newCapacity;
|
||||
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
|
||||
{
|
||||
var span = new Span<T>(data, count);
|
||||
Span<T> span = new(data, count);
|
||||
|
||||
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
|
||||
{
|
||||
var span = new Span<T>(data, (int)count);
|
||||
Span<T> span = new(data, (int)count);
|
||||
|
||||
for (int i = 0; i < span.Length; i++)
|
||||
{
|
||||
|
||||
@@ -8,11 +8,13 @@ namespace ARMeilleure
|
||||
// low-core count PPTC
|
||||
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 AllowLcqInFunctionTable { 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 UseAdvSimdIfAvailable { get; set; } = true;
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace ARMeilleure.Signal
|
||||
{
|
||||
public static class NativeSignalHandlerGenerator
|
||||
{
|
||||
public const int MaxTrackedRanges = 16;
|
||||
public const int MaxTrackedRanges = 8;
|
||||
|
||||
private const int StructAddressOffset = 0;
|
||||
private const int StructWriteOffset = 4;
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace ARMeilleure.Signal
|
||||
{
|
||||
EmitterContext context = new();
|
||||
|
||||
var result = WindowsPartialUnmapHandler.EmitRetryFromAccessViolation(context);
|
||||
Operand result = WindowsPartialUnmapHandler.EmitRetryFromAccessViolation(context);
|
||||
|
||||
context.Return(result);
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace ARMeilleure.Signal
|
||||
{
|
||||
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);
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using ARMeilleure.Memory;
|
||||
using System.Threading;
|
||||
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
@@ -11,7 +10,7 @@ namespace ARMeilleure.State
|
||||
|
||||
internal nint NativeContextPtr => _nativeContext.BasePtr;
|
||||
|
||||
internal bool Interrupted { get; private set; }
|
||||
private bool _interrupted;
|
||||
|
||||
private readonly ICounter _counter;
|
||||
|
||||
@@ -68,8 +67,6 @@ namespace ARMeilleure.State
|
||||
|
||||
public bool IsAarch32 { get; set; }
|
||||
|
||||
public ulong ThreadUid { get; set; }
|
||||
|
||||
internal ExecutionMode ExecutionMode
|
||||
{
|
||||
get
|
||||
@@ -95,19 +92,14 @@ namespace ARMeilleure.State
|
||||
|
||||
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
||||
private readonly ExceptionCallback _breakCallback;
|
||||
private readonly ExceptionCallbackNoArgs _stepCallback;
|
||||
private readonly ExceptionCallback _supervisorCallback;
|
||||
private readonly ExceptionCallback _undefinedCallback;
|
||||
|
||||
internal int ShouldStep;
|
||||
public ulong DebugPc { get; set; }
|
||||
|
||||
public ExecutionContext(
|
||||
IJitMemoryAllocator allocator,
|
||||
ICounter counter,
|
||||
ExceptionCallbackNoArgs interruptCallback = null,
|
||||
ExceptionCallback breakCallback = null,
|
||||
ExceptionCallbackNoArgs stepCallback = null,
|
||||
ExceptionCallback supervisorCallback = null,
|
||||
ExceptionCallback undefinedCallback = null)
|
||||
{
|
||||
@@ -115,7 +107,6 @@ namespace ARMeilleure.State
|
||||
_counter = counter;
|
||||
_interruptCallback = interruptCallback;
|
||||
_breakCallback = breakCallback;
|
||||
_stepCallback = stepCallback;
|
||||
_supervisorCallback = supervisorCallback;
|
||||
_undefinedCallback = undefinedCallback;
|
||||
|
||||
@@ -143,9 +134,9 @@ namespace ARMeilleure.State
|
||||
|
||||
internal void CheckInterrupt()
|
||||
{
|
||||
if (Interrupted)
|
||||
if (_interrupted)
|
||||
{
|
||||
Interrupted = false;
|
||||
_interrupted = false;
|
||||
|
||||
_interruptCallback?.Invoke(this);
|
||||
}
|
||||
@@ -155,37 +146,16 @@ namespace ARMeilleure.State
|
||||
|
||||
public void RequestInterrupt()
|
||||
{
|
||||
Interrupted = true;
|
||||
}
|
||||
|
||||
public void StepHandler()
|
||||
{
|
||||
_stepCallback?.Invoke(this);
|
||||
}
|
||||
|
||||
public void RequestDebugStep()
|
||||
{
|
||||
Interlocked.Exchange(ref ShouldStep, 1);
|
||||
RequestInterrupt();
|
||||
_interrupted = true;
|
||||
}
|
||||
|
||||
internal void OnBreak(ulong address, int imm)
|
||||
{
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
DebugPc = Pc;
|
||||
}
|
||||
|
||||
_breakCallback?.Invoke(this, address, imm);
|
||||
}
|
||||
|
||||
internal void OnSupervisorCall(ulong address, int imm)
|
||||
{
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
DebugPc = Pc;
|
||||
}
|
||||
|
||||
_supervisorCallback?.Invoke(this, address, imm);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,12 +23,6 @@ namespace ARMeilleure.State
|
||||
public int Running;
|
||||
public int CallDepth;
|
||||
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();
|
||||
@@ -46,11 +40,6 @@ namespace ARMeilleure.State
|
||||
|
||||
public ulong GetPc()
|
||||
{
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
return GetStorage().DebugPrecisePc;
|
||||
}
|
||||
|
||||
// TODO: More precise tracking of PC value.
|
||||
return GetStorage().DispatchAddress;
|
||||
}
|
||||
@@ -280,11 +269,6 @@ namespace ARMeilleure.State
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Running);
|
||||
}
|
||||
|
||||
public static int GetDebugPrecisePcOffset()
|
||||
{
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.DebugPrecisePc);
|
||||
}
|
||||
|
||||
public static int GetCallDepthOffset()
|
||||
{
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.CallDepth);
|
||||
|
||||
@@ -52,7 +52,6 @@ namespace ARMeilleure.Translation
|
||||
public bool HighCq { get; }
|
||||
public bool HasPtc { get; }
|
||||
public Aarch32Mode Mode { get; }
|
||||
public bool IsSingleStep { get; }
|
||||
|
||||
private int _ifThenBlockStateIndex = 0;
|
||||
private Condition[] _ifThenBlockState = [];
|
||||
@@ -67,8 +66,7 @@ namespace ARMeilleure.Translation
|
||||
ulong entryAddress,
|
||||
bool highCq,
|
||||
bool hasPtc,
|
||||
Aarch32Mode mode,
|
||||
bool isSingleStep)
|
||||
Aarch32Mode mode)
|
||||
{
|
||||
Memory = memory;
|
||||
CountTable = countTable;
|
||||
@@ -78,7 +76,6 @@ namespace ARMeilleure.Translation
|
||||
HighCq = highCq;
|
||||
HasPtc = hasPtc;
|
||||
Mode = mode;
|
||||
IsSingleStep = isSingleStep;
|
||||
|
||||
_labels = new Dictionary<ulong, Operand>();
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ using ARMeilleure.CodeGen;
|
||||
using ARMeilleure.CodeGen.Unwinding;
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.Native;
|
||||
using Humanizer;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
@@ -19,20 +19,49 @@ namespace ARMeilleure.Translation.Cache
|
||||
private static readonly int _pageSize = (int)MemoryBlock.GetPageSize();
|
||||
private static readonly int _pageMask = _pageSize - 1;
|
||||
|
||||
private const int CodeAlignment = 4; // Bytes.
|
||||
private const int CacheSize = 256 * 1024 * 1024;
|
||||
private const int CodeAlignment = 4;
|
||||
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 List<CacheMemoryAllocator> _cacheAllocators = [];
|
||||
private static CacheMemoryAllocator _cacheAllocator;
|
||||
|
||||
private static readonly List<CacheEntry> _cacheEntries = [];
|
||||
private static readonly Dictionary<int, EntryUsageStats> _entryUsageStats = [];
|
||||
|
||||
private static readonly Lock _lock = new();
|
||||
private static bool _initialized;
|
||||
private static int _cacheSize;
|
||||
|
||||
private static readonly List<ReservedRegion> _jitRegions = [];
|
||||
private static int _activeRegionIndex = 0;
|
||||
// Basic statistics
|
||||
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")]
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
@@ -40,48 +69,35 @@ namespace ARMeilleure.Translation.Cache
|
||||
|
||||
public static void Initialize(IJitMemoryAllocator allocator)
|
||||
{
|
||||
if (_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (_initialized)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
JitUnwindWindows.RemoveFunctionTableHandler(
|
||||
_jitRegions[0].Pointer);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _jitRegions.Count; i++)
|
||||
{
|
||||
_jitRegions[i].Dispose();
|
||||
}
|
||||
|
||||
_jitRegions.Clear();
|
||||
_cacheAllocators.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
_initialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_activeRegionIndex = 0;
|
||||
|
||||
var firstRegion = new ReservedRegion(allocator, CacheSize);
|
||||
_jitRegions.Add(firstRegion);
|
||||
|
||||
CacheMemoryAllocator firstCacheAllocator = new(CacheSize);
|
||||
_cacheAllocators.Add(firstCacheAllocator);
|
||||
_cacheSize = Optimizations.CacheEviction ? ReducedCacheSize : FullCacheSize;
|
||||
_jitRegion = new ReservedRegion(allocator, (ulong)_cacheSize);
|
||||
|
||||
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
|
||||
{
|
||||
_jitCacheInvalidator = new JitCacheInvalidation(allocator);
|
||||
}
|
||||
|
||||
_cacheAllocator = new CacheMemoryAllocator(_cacheSize);
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
JitUnwindWindows.InstallFunctionTableHandler(
|
||||
firstRegion.Pointer, CacheSize, firstRegion.Pointer + Allocate(_pageSize)
|
||||
);
|
||||
JitUnwindWindows.InstallFunctionTableHandler(_jitRegion.Pointer, (uint)_cacheSize, _jitRegion.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)
|
||||
{
|
||||
Debug.Assert(_initialized);
|
||||
_totalAllocations++;
|
||||
|
||||
int funcOffset = Allocate(code.Length);
|
||||
ReservedRegion targetRegion = _jitRegions[_activeRegionIndex];
|
||||
nint funcPtr = targetRegion.Pointer + funcOffset;
|
||||
int 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)
|
||||
{
|
||||
@@ -109,9 +149,9 @@ namespace ARMeilleure.Translation.Cache
|
||||
}
|
||||
else
|
||||
{
|
||||
ReprotectAsWritable(targetRegion, funcOffset, code.Length);
|
||||
ReprotectAsWritable(funcOffset, code.Length);
|
||||
Marshal.Copy(code, 0, funcPtr, code.Length);
|
||||
ReprotectAsExecutable(targetRegion, funcOffset, code.Length);
|
||||
ReprotectAsExecutable(funcOffset, code.Length);
|
||||
|
||||
if (OperatingSystem.IsWindows() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||
{
|
||||
@@ -125,6 +165,12 @@ namespace ARMeilleure.Translation.Cache
|
||||
|
||||
Add(funcOffset, code.Length, func.UnwindInfo);
|
||||
|
||||
// Simple periodic logging
|
||||
if (_totalAllocations % LogInterval == 0)
|
||||
{
|
||||
LogCacheStatus();
|
||||
}
|
||||
|
||||
return funcPtr;
|
||||
}
|
||||
}
|
||||
@@ -135,74 +181,55 @@ namespace ARMeilleure.Translation.Cache
|
||||
{
|
||||
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() ||
|
||||
pointer.ToInt64() >= (region.Pointer + CacheSize).ToInt64())
|
||||
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
|
||||
_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 regionStart = offset & ~_pageMask;
|
||||
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
|
||||
|
||||
region.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||
_jitRegion.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||
}
|
||||
|
||||
private static void ReprotectAsExecutable(ReservedRegion region, int offset, int size)
|
||||
private static void ReprotectAsExecutable(int offset, int size)
|
||||
{
|
||||
int endOffs = offset + size;
|
||||
|
||||
int regionStart = offset & ~_pageMask;
|
||||
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
|
||||
|
||||
region.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||
_jitRegion.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||
}
|
||||
|
||||
private static int Allocate(int codeSize)
|
||||
{
|
||||
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);
|
||||
return allocOffset;
|
||||
throw new OutOfMemoryException("JIT Cache exhausted.");
|
||||
}
|
||||
|
||||
int exhaustedRegion = _activeRegionIndex;
|
||||
var newRegion = new ReservedRegion(_jitRegions[0].Allocator, CacheSize);
|
||||
_jitRegions.Add(newRegion);
|
||||
_activeRegionIndex = _jitRegions.Count - 1;
|
||||
_jitRegion.ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
|
||||
|
||||
Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {_activeRegionIndex} ({((long)(_activeRegionIndex + 1) * CacheSize).Bytes()} Total Allocation).");
|
||||
|
||||
_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;
|
||||
return allocOffset;
|
||||
}
|
||||
|
||||
private static int AlignCodeSize(int codeSize)
|
||||
@@ -222,27 +249,35 @@ namespace ARMeilleure.Translation.Cache
|
||||
}
|
||||
|
||||
_cacheEntries.Insert(index, entry);
|
||||
|
||||
if (Optimizations.CacheEviction)
|
||||
{
|
||||
_entryUsageStats[offset] = new EntryUsageStats();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryFind(int offset, out CacheEntry entry, out int entryIndex)
|
||||
{
|
||||
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)
|
||||
{
|
||||
entry = _cacheEntries[index];
|
||||
entryIndex = index;
|
||||
return true;
|
||||
}
|
||||
entryIndex = index;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,5 +285,83 @@ namespace ARMeilleure.Translation.Cache
|
||||
entryIndex = 0;
|
||||
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.
|
||||
}
|
||||
|
||||
var unwindInfo = funcEntry.UnwindInfo;
|
||||
CodeGen.Unwinding.UnwindInfo unwindInfo = funcEntry.UnwindInfo;
|
||||
|
||||
int codeIndex = 0;
|
||||
|
||||
for (int index = unwindInfo.PushEntries.Length - 1; index >= 0; index--)
|
||||
{
|
||||
var entry = unwindInfo.PushEntries[index];
|
||||
UnwindPushEntry entry = unwindInfo.PushEntries[index];
|
||||
|
||||
switch (entry.PseudoOp)
|
||||
{
|
||||
|
||||
@@ -47,8 +47,8 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
RemoveUnreachableBlocks(Blocks);
|
||||
|
||||
var visited = new HashSet<BasicBlock>();
|
||||
var blockStack = new Stack<BasicBlock>();
|
||||
HashSet<BasicBlock> visited = new();
|
||||
Stack<BasicBlock> blockStack = new();
|
||||
|
||||
Array.Resize(ref _postOrderBlocks, Blocks.Count);
|
||||
Array.Resize(ref _postOrderMap, Blocks.Count);
|
||||
@@ -88,8 +88,8 @@ namespace ARMeilleure.Translation
|
||||
|
||||
private void RemoveUnreachableBlocks(IntrusiveList<BasicBlock> blocks)
|
||||
{
|
||||
var visited = new HashSet<BasicBlock>();
|
||||
var workQueue = new Queue<BasicBlock>();
|
||||
HashSet<BasicBlock> visited = new();
|
||||
Queue<BasicBlock> workQueue = new();
|
||||
|
||||
visited.Add(Entry);
|
||||
workQueue.Enqueue(Entry);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
class DelegateInfo
|
||||
public class DelegateInfo
|
||||
{
|
||||
public nint FuncPtr { get; }
|
||||
|
||||
|
||||
@@ -2,11 +2,358 @@ using ARMeilleure.Instructions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
#if ANDROID
|
||||
using ARMeilleure.State;
|
||||
using System.Runtime.InteropServices;
|
||||
#endif
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (index >= 0 && index < _delegates.Count)
|
||||
@@ -53,7 +400,32 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
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)
|
||||
@@ -67,6 +439,190 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
_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.Ceiling)));
|
||||
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(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.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.FPCompareGEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr)));
|
||||
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.FPCompareLEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr)));
|
||||
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.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.FPMaxNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr)));
|
||||
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.FPMinNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr)));
|
||||
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.FPMulAddFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr)));
|
||||
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.FPNegMulAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt)));
|
||||
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(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.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.FPCompareGEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr)));
|
||||
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.FPCompareLEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr)));
|
||||
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.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.FPMaxNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr)));
|
||||
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.FPMinNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr)));
|
||||
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.FPMulAddFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr)));
|
||||
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.FPNegMulAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub)));
|
||||
|
||||
@@ -97,7 +97,14 @@ namespace ARMeilleure.Translation
|
||||
|
||||
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();
|
||||
#endif
|
||||
|
||||
OperandType returnType = GetOperandType(info.ReturnType);
|
||||
|
||||
|
||||
@@ -359,7 +359,10 @@ namespace ARMeilleure.Translation
|
||||
|
||||
IntervalTreeNode<TK, TV> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
||||
|
||||
tmp?.Parent = ParentOf(replacementNode);
|
||||
if (tmp != null)
|
||||
{
|
||||
tmp.Parent = ParentOf(replacementNode);
|
||||
}
|
||||
|
||||
if (ParentOf(replacementNode) == null)
|
||||
{
|
||||
@@ -567,7 +570,10 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
IntervalTreeNode<TK, TV> right = RightOf(node);
|
||||
node.Right = LeftOf(right);
|
||||
node.Right?.Parent = node;
|
||||
if (node.Right != null)
|
||||
{
|
||||
node.Right.Parent = node;
|
||||
}
|
||||
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
|
||||
right.Parent = nodeParent;
|
||||
if (nodeParent == null)
|
||||
@@ -595,7 +601,10 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
IntervalTreeNode<TK, TV> left = LeftOf(node);
|
||||
node.Left = RightOf(left);
|
||||
node.Left?.Parent = node;
|
||||
if (node.Left != null)
|
||||
{
|
||||
node.Left.Parent = node;
|
||||
}
|
||||
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
|
||||
left.Parent = nodeParent;
|
||||
if (nodeParent == null)
|
||||
@@ -642,7 +651,10 @@ namespace ARMeilleure.Translation
|
||||
/// <param name="color">Color (Boolean)</param>
|
||||
private static void SetColor(IntervalTreeNode<TK, TV> node, bool color)
|
||||
{
|
||||
node?.Color = color;
|
||||
if (node != null)
|
||||
{
|
||||
node.Color = color;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -10,6 +10,7 @@ using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
@@ -30,14 +31,11 @@ namespace ARMeilleure.Translation.PTC
|
||||
private const string OuterHeaderMagicString = "PTCohd\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 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 CountTableSymbol = new(SymbolType.Special, 2);
|
||||
public static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
|
||||
@@ -63,8 +61,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
public string TitleIdText { get; private set; }
|
||||
public string DisplayVersion { get; private set; }
|
||||
public PtcCacheInfo CacheInfo { get; private set; }
|
||||
|
||||
private MemoryManagerType _memoryMode;
|
||||
|
||||
@@ -91,8 +88,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
_disposed = false;
|
||||
|
||||
TitleIdText = TitleIdTextDefault;
|
||||
DisplayVersion = DisplayVersionDefault;
|
||||
CacheInfo = new PtcCacheInfo(0, null, null, 0, null, "Unknown", "default");
|
||||
|
||||
CachePathActual = string.Empty;
|
||||
CachePathBackup = string.Empty;
|
||||
@@ -100,20 +96,24 @@ namespace ARMeilleure.Translation.PTC
|
||||
Disable();
|
||||
}
|
||||
|
||||
public void Initialize(string titleIdText, string displayVersion, bool enabled, MemoryManagerType memoryMode, string cacheSelector)
|
||||
public void Initialize(PtcCacheInfo cacheInfo, bool enabled, MemoryManagerType memoryMode)
|
||||
{
|
||||
Wait();
|
||||
|
||||
Profiler.Wait();
|
||||
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;
|
||||
CachePathBackup = string.Empty;
|
||||
|
||||
@@ -122,12 +122,10 @@ namespace ARMeilleure.Translation.PTC
|
||||
return;
|
||||
}
|
||||
|
||||
TitleIdText = titleIdText;
|
||||
DisplayVersion = !string.IsNullOrEmpty(displayVersion) ? displayVersion : DisplayVersionDefault;
|
||||
_memoryMode = memoryMode;
|
||||
|
||||
string workPathActual = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", ActualDir);
|
||||
string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", BackupDir);
|
||||
string workPathActual = Path.Combine(AppDataManager.GamesDirPath, CacheInfo.TitleIdText, "cache", "cpu", ActualDir);
|
||||
string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, CacheInfo.TitleIdText, "cache", "cpu", BackupDir);
|
||||
|
||||
if (!Directory.Exists(workPathActual))
|
||||
{
|
||||
@@ -139,8 +137,14 @@ namespace ARMeilleure.Translation.PTC
|
||||
Directory.CreateDirectory(workPathBackup);
|
||||
}
|
||||
|
||||
CachePathActual = Path.Combine(workPathActual, DisplayVersion) + "-" + cacheSelector;
|
||||
CachePathBackup = Path.Combine(workPathBackup, DisplayVersion) + "-" + cacheSelector;
|
||||
CachePathActual = Path.Combine(workPathActual, CacheInfo.DisplayVersion) + "-" + CacheInfo.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();
|
||||
Profiler.PreLoad();
|
||||
@@ -249,8 +253,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
outerHeader.FeatureInfo != GetFeatureInfo() ||
|
||||
outerHeader.MemoryManagerMode != GetMemoryManagerMode() ||
|
||||
outerHeader.OSPlatform != GetOSPlatform() ||
|
||||
outerHeader.Architecture != (uint)RuntimeInformation.ProcessArchitecture ||
|
||||
outerHeader.DebuggerMode != Optimizations.EnableDebugging)
|
||||
outerHeader.Architecture != (uint)RuntimeInformation.ProcessArchitecture)
|
||||
{
|
||||
InvalidateCompressedStream(compressedStream);
|
||||
|
||||
@@ -364,7 +367,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -426,7 +434,6 @@ namespace ARMeilleure.Translation.PTC
|
||||
MemoryManagerMode = GetMemoryManagerMode(),
|
||||
OSPlatform = GetOSPlatform(),
|
||||
Architecture = (uint)RuntimeInformation.ProcessArchitecture,
|
||||
DebuggerMode = Optimizations.EnableDebugging,
|
||||
|
||||
UncompressedStreamSize =
|
||||
(long)Unsafe.SizeOf<InnerHeader>() +
|
||||
@@ -544,7 +551,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
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.CodeLength = 0;
|
||||
@@ -731,8 +738,8 @@ namespace ARMeilleure.Translation.PTC
|
||||
UnwindInfo unwindInfo,
|
||||
bool highCq)
|
||||
{
|
||||
var cFunc = new CompiledFunction(code, unwindInfo, RelocInfo.Empty);
|
||||
var gFunc = cFunc.MapWithPointer<GuestFunction>(out nint gFuncPointer);
|
||||
CompiledFunction cFunc = new(code, unwindInfo, RelocInfo.Empty);
|
||||
GuestFunction gFunc = cFunc.MapWithPointer<GuestFunction>(out nint gFuncPointer);
|
||||
|
||||
return new TranslatedFunction(gFunc, gFuncPointer, callCounter, guestSize, highCq);
|
||||
}
|
||||
@@ -769,7 +776,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
public void MakeAndSaveTranslations(Translator translator)
|
||||
{
|
||||
var profiledFuncsToTranslate = Profiler.GetProfiledFuncsToTranslate(translator.Functions);
|
||||
ConcurrentQueue<(ulong address, PtcProfiler.FuncProfile funcProfile)> profiledFuncsToTranslate = Profiler.GetProfiledFuncsToTranslate(translator.Functions);
|
||||
|
||||
_translateCount = 0;
|
||||
_translateTotalCount = profiledFuncsToTranslate.Count;
|
||||
@@ -813,7 +820,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
void TranslateFuncs()
|
||||
{
|
||||
while (profiledFuncsToTranslate.TryDequeue(out var item))
|
||||
while (profiledFuncsToTranslate.TryDequeue(out (ulong address, PtcProfiler.FuncProfile funcProfile) item))
|
||||
{
|
||||
ulong address = item.address;
|
||||
ExecutionMode executionMode = item.funcProfile.Mode;
|
||||
@@ -858,11 +865,11 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
Stopwatch sw = Stopwatch.StartNew();
|
||||
|
||||
foreach (var thread in threads)
|
||||
foreach (Thread thread in threads)
|
||||
{
|
||||
thread.Start();
|
||||
}
|
||||
foreach (var thread in threads)
|
||||
foreach (Thread thread in threads)
|
||||
{
|
||||
thread.Join();
|
||||
}
|
||||
@@ -942,7 +949,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
WriteCode(code.AsSpan());
|
||||
|
||||
// WriteReloc.
|
||||
using var relocInfoWriter = new BinaryWriter(_relocsStream, EncodingCache.UTF8NoBOM, true);
|
||||
using BinaryWriter relocInfoWriter = new(_relocsStream, EncodingCache.UTF8NoBOM, true);
|
||||
|
||||
foreach (RelocEntry entry in relocInfo.Entries)
|
||||
{
|
||||
@@ -952,7 +959,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
|
||||
// WriteUnwindInfo.
|
||||
using var unwindInfoWriter = new BinaryWriter(_unwindInfosStream, EncodingCache.UTF8NoBOM, true);
|
||||
using BinaryWriter unwindInfoWriter = new(_unwindInfosStream, EncodingCache.UTF8NoBOM, true);
|
||||
|
||||
unwindInfoWriter.Write(unwindInfo.PushEntries.Length);
|
||||
|
||||
@@ -1023,7 +1030,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
return osPlatform;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 87*/)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 86*/)]
|
||||
private struct OuterHeader
|
||||
{
|
||||
public ulong Magic;
|
||||
@@ -1035,7 +1042,6 @@ namespace ARMeilleure.Translation.PTC
|
||||
public byte MemoryManagerMode;
|
||||
public uint OSPlatform;
|
||||
public uint Architecture;
|
||||
public bool DebuggerMode;
|
||||
|
||||
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.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Timers;
|
||||
using static ARMeilleure.Translation.PTC.PtcFormatter;
|
||||
using Timer = System.Timers.Timer;
|
||||
using System.Linq;
|
||||
|
||||
namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
@@ -23,7 +23,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
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 =
|
||||
[
|
||||
@@ -119,9 +119,9 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -142,7 +142,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
{
|
||||
List<ulong> funcs = [];
|
||||
|
||||
foreach (var profiledFunc in ProfiledFuncs)
|
||||
foreach (KeyValuePair<ulong, FuncProfile> profiledFunc in ProfiledFuncs)
|
||||
{
|
||||
if (profiledFunc.Value.Blacklist)
|
||||
{
|
||||
@@ -254,7 +254,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -375,7 +380,11 @@ namespace ARMeilleure.Translation.PTC
|
||||
|
||||
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)
|
||||
{
|
||||
var globalDefs = new DefMap[cfg.Blocks.Count];
|
||||
var localDefs = new Operand[cfg.LocalsCount + RegisterConsts.TotalCount];
|
||||
DefMap[] globalDefs = new DefMap[cfg.Blocks.Count];
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -57,9 +57,9 @@ namespace ARMeilleure.Translation
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -119,25 +119,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
NativeInterface.RegisterThread(context, Memory, this);
|
||||
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
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)
|
||||
if (Optimizations.UseUnmanagedDispatchLoop)
|
||||
{
|
||||
Stubs.DispatchLoop(context.NativeContextPtr, address);
|
||||
}
|
||||
@@ -194,7 +176,7 @@ namespace ARMeilleure.Translation
|
||||
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);
|
||||
|
||||
@@ -205,8 +187,6 @@ namespace ARMeilleure.Translation
|
||||
return address;
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal TranslatedFunction GetOrTranslate(ulong address, ExecutionMode mode)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var context = new ArmEmitterContext(
|
||||
ArmEmitterContext context = new(
|
||||
Memory,
|
||||
CountTable,
|
||||
FunctionTable,
|
||||
@@ -250,8 +230,7 @@ namespace ARMeilleure.Translation
|
||||
address,
|
||||
highCq,
|
||||
_ptc.State != PtcState.Disabled,
|
||||
mode: Aarch32Mode.User,
|
||||
isSingleStep: singleStep);
|
||||
mode: Aarch32Mode.User);
|
||||
|
||||
Logger.StartPass(PassName.Decoding);
|
||||
|
||||
@@ -286,10 +265,10 @@ namespace ARMeilleure.Translation
|
||||
|
||||
Logger.EndPass(PassName.RegisterUsage);
|
||||
|
||||
var retType = OperandType.I64;
|
||||
var argTypes = new OperandType[] { OperandType.I64 };
|
||||
OperandType retType = 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)
|
||||
{
|
||||
@@ -390,13 +369,9 @@ namespace ARMeilleure.Translation
|
||||
|
||||
if (block.Exit)
|
||||
{
|
||||
// Return to managed rather than tail call.
|
||||
bool useReturns = Optimizations.EnableDebugging;
|
||||
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
EmitDebugPrecisePcUpdate(context, block.Address);
|
||||
}
|
||||
// Left option here as it may be useful if we need to return to managed rather than tail call in
|
||||
// future. (eg. for debug)
|
||||
bool useReturns = false;
|
||||
|
||||
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;
|
||||
|
||||
if (context.IsInIfThenBlock && context.CurrentIfThenBlockCond != Condition.Al)
|
||||
@@ -521,14 +491,6 @@ namespace ARMeilleure.Translation
|
||||
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)
|
||||
{
|
||||
ulong[] overlapAddresses = [];
|
||||
@@ -574,7 +536,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
List<TranslatedFunction> functions = Functions.AsList();
|
||||
|
||||
foreach (var func in functions)
|
||||
foreach (TranslatedFunction func in functions)
|
||||
{
|
||||
JitCache.Unmap(func.FuncPointer);
|
||||
|
||||
@@ -583,7 +545,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
Functions.Clear();
|
||||
|
||||
while (_oldFuncs.TryDequeue(out var kv))
|
||||
while (_oldFuncs.TryDequeue(out KeyValuePair<ulong, TranslatedFunction> kv))
|
||||
{
|
||||
JitCache.Unmap(kv.Value.FuncPointer);
|
||||
|
||||
@@ -604,7 +566,7 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace ARMeilleure.Translation
|
||||
/// <returns>Generated <see cref="DispatchStub"/></returns>
|
||||
private nint GenerateDispatchStub()
|
||||
{
|
||||
var context = new EmitterContext();
|
||||
EmitterContext context = new();
|
||||
|
||||
Operand lblFallback = Label();
|
||||
Operand lblEnd = Label();
|
||||
@@ -160,7 +160,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
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
|
||||
// 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);
|
||||
context.Tailcall(hostAddress, nativeContext);
|
||||
|
||||
var cfg = context.GetControlFlowGraph();
|
||||
var retType = OperandType.I64;
|
||||
var argTypes = new[] { OperandType.I64 };
|
||||
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||
OperandType retType = 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);
|
||||
}
|
||||
@@ -199,7 +199,7 @@ namespace ARMeilleure.Translation
|
||||
/// <returns>Generated <see cref="SlowDispatchStub"/></returns>
|
||||
private nint GenerateSlowDispatchStub()
|
||||
{
|
||||
var context = new EmitterContext();
|
||||
EmitterContext context = new();
|
||||
|
||||
// Load the target guest address from the native context.
|
||||
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);
|
||||
context.Tailcall(hostAddress, nativeContext);
|
||||
|
||||
var cfg = context.GetControlFlowGraph();
|
||||
var retType = OperandType.I64;
|
||||
var argTypes = new[] { OperandType.I64 };
|
||||
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||
OperandType retType = 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);
|
||||
}
|
||||
@@ -250,7 +250,7 @@ namespace ARMeilleure.Translation
|
||||
/// <returns><see cref="DispatchLoop"/> function</returns>
|
||||
private DispatcherFunction GenerateDispatchLoop()
|
||||
{
|
||||
var context = new EmitterContext();
|
||||
EmitterContext context = new();
|
||||
|
||||
Operand beginLbl = Label();
|
||||
Operand endLbl = Label();
|
||||
@@ -286,9 +286,9 @@ namespace ARMeilleure.Translation
|
||||
|
||||
context.Return();
|
||||
|
||||
var cfg = context.GetControlFlowGraph();
|
||||
var retType = OperandType.None;
|
||||
var argTypes = new[] { OperandType.I64, OperandType.I64 };
|
||||
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||
OperandType retType = OperandType.None;
|
||||
OperandType[] argTypes = new[] { OperandType.I64, OperandType.I64 };
|
||||
|
||||
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>
|
||||
private WrapperFunction GenerateContextWrapper()
|
||||
{
|
||||
var context = new EmitterContext();
|
||||
EmitterContext context = new();
|
||||
|
||||
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||
Operand guestMethod = context.LoadArgument(OperandType.I64, 1);
|
||||
@@ -310,9 +310,9 @@ namespace ARMeilleure.Translation
|
||||
|
||||
context.Return(returnValue);
|
||||
|
||||
var cfg = context.GetControlFlowGraph();
|
||||
var retType = OperandType.I64;
|
||||
var argTypes = new[] { OperandType.I64, OperandType.I64 };
|
||||
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||
OperandType retType = OperandType.I64;
|
||||
OperandType[] argTypes = new[] { OperandType.I64, OperandType.I64 };
|
||||
|
||||
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