mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-09-27 17:29:00 +02:00
Compare commits
316
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bed294bb92 | ||
|
|
ed70f7921e | ||
|
|
1a1fe53535 | ||
|
|
47e55acf21 | ||
|
|
0e5fead0f9 | ||
|
|
d1fb89f746 | ||
|
|
cc1861f9bb | ||
|
|
733bd0951b | ||
|
|
087e711e44 | ||
|
|
9c46452388 | ||
|
|
0657b00622 | ||
|
|
87cf0b0cbb | ||
|
|
954332aa2a | ||
|
|
e650d3fb04 | ||
|
|
d578c5e2a9 | ||
|
|
521a18f5a7 | ||
|
|
4b255a98db | ||
|
|
8b34270a22 | ||
|
|
9580f20caa | ||
|
|
152460929d | ||
|
|
7a5554a17f | ||
|
|
d5e4dfae56 | ||
|
|
28268ef7ef | ||
|
|
6c47892b94 | ||
|
|
b362f837c5 | ||
|
|
a82a721df6 | ||
|
|
297df259c3 | ||
|
|
3ace5deadf | ||
|
|
04aacb1385 | ||
|
|
ea91841e9b | ||
|
|
5734ad9090 | ||
|
|
1486d2db40 | ||
|
|
c54ca28843 | ||
|
|
a53e691185 | ||
|
|
bf8c902d13 | ||
|
|
f4dc400a47 | ||
|
|
a36882ab51 | ||
|
|
76a123b81d | ||
|
|
9d3fecf334 | ||
|
|
31d0bc5915 | ||
|
|
30dba1ed36 | ||
|
|
0d6c0aeeab | ||
|
|
74d6b310b8 | ||
|
|
3289715b8c | ||
|
|
3a3129252a | ||
|
|
ff47cb1d66 | ||
|
|
d440ff41d2 | ||
|
|
46308c32e7 | ||
|
|
bf09e153f1 | ||
|
|
0d1eebad31 | ||
|
|
b1b260ed17 | ||
|
|
a57756f447 | ||
|
|
be405de436 | ||
|
|
e88fd3273d | ||
|
|
79f55b12bf | ||
|
|
0bc515e4ff | ||
|
|
541fa63330 | ||
|
|
55aded3a05 | ||
|
|
61e0aba325 | ||
|
|
23fb4924e3 | ||
|
|
8fcc539ed9 | ||
|
|
51e4323a73 | ||
|
|
fcd55edf93 | ||
|
|
44872f45e0 | ||
|
|
1950b34e39 | ||
|
|
4aa8e249f1 | ||
|
|
3c13bdb4af | ||
|
|
7dec9a2f09 | ||
|
|
af6dd5b64c | ||
|
|
c6fba938bb | ||
|
|
4b4fd560ed | ||
|
|
7f99e32a0a | ||
|
|
4b8c74be10 | ||
|
|
2af1bc1808 | ||
|
|
1d19b318c1 | ||
|
|
36767d7fce | ||
|
|
20a9ecaebf | ||
|
|
77c947eb88 | ||
|
|
251b65771a | ||
|
|
7aa27b2ca5 | ||
|
|
3a479a437d | ||
|
|
5359ab77e1 | ||
|
|
3d5682375e | ||
|
|
bc777e1968 | ||
|
|
e729014cfa | ||
|
|
39b7242ef7 | ||
|
|
d55c0a702b | ||
|
|
f39b53982a | ||
|
|
46a57538c6 | ||
|
|
9b93b6fe18 | ||
|
|
d207d43768 | ||
|
|
d7f90f9f1f | ||
|
|
1b714ab1aa | ||
|
|
a6af70baa1 | ||
|
|
8c9cdfe9ce | ||
|
|
5b3a620bb0 | ||
|
|
d977208b19 | ||
|
|
477be704bb | ||
|
|
5c8be1b927 | ||
|
|
adc8ed594a | ||
|
|
9104a75a48 | ||
|
|
c0ba4e64cf | ||
|
|
6cf0a413a0 | ||
|
|
caed40d99a | ||
|
|
f764ae2d58 | ||
|
|
b16f74ffd9 | ||
|
|
bd96f2f51f | ||
|
|
3bf8a17f01 | ||
|
|
d5bd8871a2 | ||
|
|
dcafe32d5c | ||
|
|
18bd84c463 | ||
|
|
9a684ff066 | ||
|
|
60c867622e | ||
|
|
3cdae775b1 | ||
|
|
061bfb4074 | ||
|
|
2b15dfc473 | ||
|
|
a948308a2f | ||
|
|
a91f60b6ad | ||
|
|
56eef239a4 | ||
|
|
bef07155dc | ||
|
|
253f47c971 | ||
|
|
7d0947cac6 | ||
|
|
0d29b77a14 | ||
|
|
2aecce018c | ||
|
|
8ac2b1e497 | ||
|
|
9a1d33dde5 | ||
|
|
899c99740d | ||
|
|
1390fd02d7 | ||
|
|
5ecdd197cd | ||
|
|
546082128f | ||
|
|
2aae771ab3 | ||
|
|
a2c53ed6cf | ||
|
|
fba786cd38 | ||
|
|
292d42d394 | ||
|
|
afa4782493 | ||
|
|
b6cd6770ff | ||
|
|
fecb02647d | ||
|
|
bf12b601b0 | ||
|
|
4a5729cc01 | ||
|
|
5a16e24450 | ||
|
|
2dfa040d92 | ||
|
|
da6b58b9fa | ||
|
|
ad516777d9 | ||
|
|
812cecd713 | ||
|
|
d00bda7e53 | ||
|
|
c70f692324 | ||
|
|
9920619ff6 | ||
|
|
2ba33ec2ef | ||
|
|
e404954f88 | ||
|
|
6b383873e8 | ||
|
|
32d1653af9 | ||
|
|
298e2cdefd | ||
|
|
5a53d36992 | ||
|
|
8c99b90926 | ||
|
|
e287c9fc85 | ||
|
|
e349ef72fb | ||
|
|
b7c13715f1 | ||
|
|
139e18a8e1 | ||
|
|
58a76a0b9f | ||
|
|
6292192cc0 | ||
|
|
a926a31133 | ||
|
|
17b7eadb91 | ||
|
|
61a783e10a | ||
|
|
9b8517caf3 | ||
|
|
457f62d773 | ||
|
|
a6c0eabf49 | ||
|
|
e3ee28605d | ||
|
|
2c50fbcc1f | ||
|
|
90cb9d42db | ||
|
|
1a3b407839 | ||
|
|
46a0783293 | ||
|
|
82ae055fe5 | ||
|
|
f98af9e175 | ||
|
|
cdbe568620 | ||
|
|
86f47b8333 | ||
|
|
2993dba583 | ||
|
|
e720e4a87b | ||
|
|
f30d832847 | ||
|
|
afa1ab95c2 | ||
|
|
52b6fcf1a4 | ||
|
|
35449846d9 | ||
|
|
5d68312b54 | ||
|
|
b8aaadac5f | ||
|
|
a369b246a3 | ||
|
|
d96e93ef0d | ||
|
|
0bfd2ad3ef | ||
|
|
df36c23652 | ||
|
|
843a7113d1 | ||
|
|
2d420ee561 | ||
|
|
b958044e4e | ||
|
|
d659bec27a | ||
|
|
107df58666 | ||
|
|
280461dc78 | ||
|
|
1724149443 | ||
|
|
b44e2a87fd | ||
|
|
b1f767b2d5 | ||
|
|
ec9713b111 | ||
|
|
a7af26bc1f | ||
|
|
91a5f69805 | ||
|
|
f908bfe150 | ||
|
|
a2c494e216 | ||
|
|
e489e0d19f | ||
|
|
f362e33293 | ||
|
|
1e2fd6f4c2 | ||
|
|
35a8116ae8 | ||
|
|
41b8b6961c | ||
|
|
42727fca07 | ||
|
|
f5822c16af | ||
|
|
66a5719e10 | ||
|
|
cc2fb8f0b6 | ||
|
|
c9c78841b9 | ||
|
|
f26bd3d321 | ||
|
|
b28f52387a | ||
|
|
83412689b7 | ||
|
|
0b5f312b20 | ||
|
|
c0b7452cb5 | ||
|
|
6ba8ae53f2 | ||
|
|
d3bce3f361 | ||
|
|
2471bb8ede | ||
|
|
c3bfce3378 | ||
|
|
88e8d1309c | ||
|
|
ebeb532099 | ||
|
|
c501fe264b | ||
|
|
61d0430006 | ||
|
|
cd477cf744 | ||
|
|
0487b781dc | ||
|
|
51b32981b6 | ||
|
|
fa682d406e | ||
|
|
503dea74c2 | ||
|
|
1f979e5c6f | ||
|
|
378dc33cca | ||
|
|
9c37a557dd | ||
|
|
6e5bd0c9f2 | ||
|
|
0f2b11d4d5 | ||
|
|
1abf5b82c5 | ||
|
|
d751cfa81a | ||
|
|
af14fadb2f | ||
|
|
4fd4e3a4ff | ||
|
|
a1834900be | ||
|
|
fe7a30c747 | ||
|
|
3a387309b4 | ||
|
|
867a92a8bc | ||
|
|
45bf443c01 | ||
|
|
a09568d1b7 | ||
|
|
dae7ae7eaf | ||
|
|
c2f54d0a5c | ||
|
|
f4dfdd35b2 | ||
|
|
c56d04a9a9 | ||
|
|
5c6175cebf | ||
|
|
9addccb50f | ||
|
|
17946c78e6 | ||
|
|
29647b6351 | ||
|
|
6e6983799e | ||
|
|
61da23cb9e | ||
|
|
a62deb8cfd | ||
|
|
8ea79ae5d5 | ||
|
|
09f3bf4b55 | ||
|
|
171624e7f0 | ||
|
|
01cb33f658 | ||
|
|
121bb5dc76 | ||
|
|
d73ef0e3fb | ||
|
|
46b2da2435 | ||
|
|
aca897c70c | ||
|
|
e7d423cd07 | ||
|
|
48c809a80d | ||
|
|
7fd01214cf | ||
|
|
ef72e9b790 | ||
|
|
d5c9bc662c | ||
|
|
3cf90e808d | ||
|
|
326f744093 | ||
|
|
6cecbaa625 | ||
|
|
1443e1a2ff | ||
|
|
12d7f95468 | ||
|
|
b59a833467 | ||
|
|
50a2caf799 | ||
|
|
7d1fd99d3d | ||
|
|
c16559f20e | ||
|
|
6ecd6111d5 | ||
|
|
0ee71fa064 | ||
|
|
6e8f7e7fcb | ||
|
|
f9780b33bb | ||
|
|
d2a532f971 | ||
|
|
a90db3464d | ||
|
|
c61d171e52 | ||
|
|
8927a78c4d | ||
|
|
aa836dd924 | ||
|
|
878ea70aa9 | ||
|
|
9f0a35ee9b | ||
|
|
ed0ebdec5b | ||
|
|
b5a1272141 | ||
|
|
6768e1fa71 | ||
|
|
5c2d710fbb | ||
|
|
d3f3eacc41 | ||
|
|
5983cb9e5f | ||
|
|
e09f16838e | ||
|
|
18f302c0b0 | ||
|
|
8f77076117 | ||
|
|
39544e323c | ||
|
|
24932b7e1b | ||
|
|
2aaf34937d | ||
|
|
bce3426d26 | ||
|
|
51ca73cb10 | ||
|
|
cd3221abdc | ||
|
|
19dd23c288 | ||
|
|
20f1cef9b2 | ||
|
|
2f400491d5 | ||
|
|
f6351e3fff | ||
|
|
f15ddcf9c4 | ||
|
|
88d904acde | ||
|
|
fbcf57bef5 | ||
|
|
8bfb670e65 | ||
|
|
e00bece65a | ||
|
|
2a03f7b1d4 | ||
|
|
6c7b7d6fc4 | ||
|
|
c43db7d5f6 | ||
|
|
cc92af12a4 |
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"$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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
+4
-3
@@ -16,6 +16,10 @@ x64/
|
|||||||
build/
|
build/
|
||||||
[Bb]in/
|
[Bb]in/
|
||||||
[Oo]bj/
|
[Oo]bj/
|
||||||
|
AppDir/
|
||||||
|
publish_appimage/
|
||||||
|
publish_ava/
|
||||||
|
publish_tmp_ava/
|
||||||
|
|
||||||
# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
|
# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
|
||||||
!packages/*/build/
|
!packages/*/build/
|
||||||
@@ -173,6 +177,3 @@ PublishProfiles/
|
|||||||
|
|
||||||
# Glade backup files
|
# Glade backup files
|
||||||
*.glade~
|
*.glade~
|
||||||
|
|
||||||
# Log files
|
|
||||||
/logs/
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
[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,6 +1,7 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
|
<DebugType Condition="'$(Configuration)'=='Release'">none</DebugType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
+21
-23
@@ -3,41 +3,41 @@
|
|||||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="Avalonia" Version="11.3.13" />
|
<PackageVersion Include="Avalonia" Version="12.1.1" />
|
||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.13" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="12.1.2" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.13" />
|
<PackageVersion Include="Avalonia.Desktop" Version="12.1.1" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.13" />
|
<PackageVersion Include="AvaloniaUI.DiagnosticsSupport" Version="2.2.3" />
|
||||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.3.13" />
|
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="12.1.1" />
|
||||||
<PackageVersion Include="Svg.Controls.Avalonia" Version="11.3.9.5" />
|
<PackageVersion Include="Svg.Controls.Avalonia" Version="12.0.0.13" />
|
||||||
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="11.3.9.5" />
|
<PackageVersion Include="Svg.Controls.Skia.Avalonia" Version="12.0.0.13" />
|
||||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||||
|
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||||
<PackageVersion Include="Concentus" Version="2.2.2" />
|
<PackageVersion Include="Concentus" Version="2.2.2" />
|
||||||
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
|
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
|
||||||
<PackageVersion Include="DynamicData" Version="9.4.31" />
|
<PackageVersion Include="DynamicData" Version="9.4.33" />
|
||||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.4.1" />
|
<PackageVersion Include="FluentAvaloniaUI" Version="3.0.2" />
|
||||||
<PackageVersion Include="Gommon" Version="2.8.1.1" />
|
<PackageVersion Include="Gommon" Version="2.8.1.2" />
|
||||||
<PackageVersion Include="Humanizer" Version="3.0.10" />
|
<PackageVersion Include="Humanizer" Version="3.0.10" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.12.0" />
|
||||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.17.0" />
|
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.21.0" />
|
||||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
|
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.8.1" />
|
||||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||||
<PackageVersion Include="NetCoreServer" Version="8.0.7" />
|
<PackageVersion Include="NetCoreServer" Version="8.0.7" />
|
||||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
|
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
|
||||||
<PackageVersion Include="NUnit" Version="4.5.1" />
|
<PackageVersion Include="NUnit" Version="4.6.1" />
|
||||||
<PackageVersion Include="NUnit3TestAdapter" Version="6.2.0" />
|
<PackageVersion Include="NUnit3TestAdapter" Version="6.2.0" />
|
||||||
<PackageVersion Include="OpenTK.Core" Version="4.9.4" />
|
<PackageVersion Include="OpenTK.Core" Version="4.9.4" />
|
||||||
<PackageVersion Include="OpenTK.Graphics" Version="4.9.4" />
|
<PackageVersion Include="OpenTK.Graphics" Version="4.9.4" />
|
||||||
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.9.4" />
|
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.9.4" />
|
||||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.9.4" />
|
|
||||||
<PackageVersion Include="Open.NAT.Core" Version="2.1.0.5" />
|
<PackageVersion Include="Open.NAT.Core" Version="2.1.0.5" />
|
||||||
<PackageVersion Include="Ryujinx.Audio.OpenAL" Version="1.25.2" />
|
<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.Linux" Version="6.1.4-build6" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.macOS" Version="5.0.3-build14" />
|
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.macOS" Version="5.0.3-build14" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Windows" Version="6.1.3-build5" />
|
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.Windows" Version="6.1.4-build6" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
<PackageVersion Include="Ryujinx.Graphics.Vulkan.MoltenVK" Version="1.4.2-ryujinx.6" />
|
||||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.128" />
|
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.133" />
|
||||||
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.707.0" />
|
<PackageVersion Include="Ryujinx.SDL3-CS" Version="2026.707.0" />
|
||||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||||
@@ -45,12 +45,10 @@
|
|||||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.23.0" />
|
<PackageVersion Include="Silk.NET.Vulkan" Version="2.23.0" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.23.0" />
|
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.23.0" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.23.0" />
|
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.23.0" />
|
||||||
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
<PackageVersion Include="SkiaSharp" Version="3.119.4" />
|
||||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
|
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="3.119.4" />
|
||||||
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
||||||
<PackageVersion Include="System.IO.Hashing" Version="9.0.12" />
|
<PackageVersion Include="System.IO.Hashing" Version="10.0.10" />
|
||||||
<PackageVersion Include="System.Management" Version="9.0.12" />
|
|
||||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.0" />
|
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.1.0" />
|
||||||
<PackageVersion Include="Rxmxnx.PInvoke.Extensions" Version="2.9.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
-261
@@ -1,261 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 17
|
|
||||||
VisualStudioVersion = 17.1.32228.430
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests", "src\Ryujinx.Tests\Ryujinx.Tests.csproj", "{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibKenjinx", "src\LibKenjinx\LibKenjinx.csproj", "{AF58C1D5-DE16-429B-B155-7CE83B4E8FA6}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests.Unicorn", "src\Ryujinx.Tests.Unicorn\Ryujinx.Tests.Unicorn.csproj", "{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE", "src\Ryujinx.HLE\Ryujinx.HLE.csproj", "{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.ShaderTools", "src\Ryujinx.ShaderTools\Ryujinx.ShaderTools.csproj", "{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Common", "src\Ryujinx.Common\Ryujinx.Common.csproj", "{5FD4E4F6-8928-4B3C-BE07-28A675C17226}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ARMeilleure", "src\ARMeilleure\ARMeilleure.csproj", "{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Gpu", "src\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj", "{ADA7EA87-0D63-4D97-9433-922A2124401F}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.GAL", "src\Ryujinx.Graphics.GAL\Ryujinx.Graphics.GAL.csproj", "{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.OpenGL", "src\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj", "{9558FB96-075D-4219-8FFF-401979DC0B69}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Texture", "src\Ryujinx.Graphics.Texture\Ryujinx.Graphics.Texture.csproj", "{E1B1AD28-289D-47B7-A106-326972240207}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Shader", "src\Ryujinx.Graphics.Shader\Ryujinx.Graphics.Shader.csproj", "{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec", "src\Ryujinx.Graphics.Nvdec\Ryujinx.Graphics.Nvdec.csproj", "{85A0FA56-DC01-4A42-8808-70DAC76BD66D}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio", "src\Ryujinx.Audio\Ryujinx.Audio.csproj", "{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
|
|
||||||
ProjectSection(SolutionItems) = preProject
|
|
||||||
.editorconfig = .editorconfig
|
|
||||||
Directory.Build.props = Directory.Build.props
|
|
||||||
Directory.Packages.props = Directory.Packages.props
|
|
||||||
nuget.config = nuget.config
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Memory", "src\Ryujinx.Memory\Ryujinx.Memory.csproj", "{A5E6C691-9E22-4263-8F40-42F002CE66BE}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests.Memory", "src\Ryujinx.Tests.Memory\Ryujinx.Tests.Memory.csproj", "{D1CC5322-7325-4F6B-9625-194B30BE1296}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Cpu", "src\Ryujinx.Cpu\Ryujinx.Cpu.csproj", "{3DF35E3D-D844-4399-A9A1-A9E923264C17}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Device", "src\Ryujinx.Graphics.Device\Ryujinx.Graphics.Device.csproj", "{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Host1x", "src\Ryujinx.Graphics.Host1x\Ryujinx.Graphics.Host1x.csproj", "{C35F1536-7DE5-4F9D-9604-B5B4E1561947}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.Vp9", "src\Ryujinx.Graphics.Nvdec.Vp9\Ryujinx.Graphics.Nvdec.Vp9.csproj", "{B9AECA11-E248-4886-A10B-81B631CAAF29}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vic", "src\Ryujinx.Graphics.Vic\Ryujinx.Graphics.Vic.csproj", "{81BB2C11-9408-4EA3-822E-42987AF54429}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Video", "src\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj", "{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.OpenAL", "src\Ryujinx.Audio.Backends.OpenAL\Ryujinx.Audio.Backends.OpenAL.csproj", "{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SoundIo", "src\Ryujinx.Audio.Backends.SoundIo\Ryujinx.Audio.Backends.SoundIo.csproj", "{716364DE-B988-41A6-BAB4-327964266ECC}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input", "src\Ryujinx.Input\Ryujinx.Input.csproj", "{C16F112F-38C3-40BC-9F5F-4791112063D6}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input.SDL2", "src\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj", "{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "src\Ryujinx.SDL2.Common\Ryujinx.SDL2.Common.csproj", "{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.Common", "src\Ryujinx.UI.Common\Ryujinx.UI.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Generators", "src\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", "src\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj", "{D4D09B08-D580-4D69-B886-C35D2853F6C8}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spv.Generator", "src\Spv.Generator\Spv.Generator.csproj", "{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.LocaleGenerator", "src\Ryujinx.UI.LocaleGenerator\Ryujinx.UI.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Common", "src\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj", "{77F96ECE-4952-42DB-A528-DED25572A573}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon", "src\Ryujinx.Horizon\Ryujinx.Horizon.csproj", "{AF34127A-3A92-43E5-8496-14960A50B1F1}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "src\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{AF58C1D5-DE16-429B-B155-7CE83B4E8FA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{AF58C1D5-DE16-429B-B155-7CE83B4E8FA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{AF58C1D5-DE16-429B-B155-7CE83B4E8FA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{AF58C1D5-DE16-429B-B155-7CE83B4E8FA6}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {110169B3-3328-4730-8AB0-BA05BEF75C1A}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
<File Path="nuget.config" />
|
<File Path="nuget.config" />
|
||||||
</Folder>
|
</Folder>
|
||||||
<Project Path="src/ARMeilleure/ARMeilleure.csproj" />
|
<Project Path="src/ARMeilleure/ARMeilleure.csproj" />
|
||||||
<Project Path="src/LibKenjinx/LibKenjinx.csproj" />
|
<Project Path="src/Ryujinx.Audio.Backends.Apple/Ryujinx.Audio.Backends.Apple.csproj" />
|
||||||
<Project Path="src/Ryujinx.Audio.Backends.OpenAL/Ryujinx.Audio.Backends.OpenAL.csproj" />
|
<Project Path="src/Ryujinx.Audio.Backends.OpenAL/Ryujinx.Audio.Backends.OpenAL.csproj" />
|
||||||
<Project Path="src/Ryujinx.Audio.Backends.SDL3/Ryujinx.Audio.Backends.SDL3.csproj" />
|
<Project Path="src/Ryujinx.Audio.Backends.SDL3/Ryujinx.Audio.Backends.SDL3.csproj" />
|
||||||
<Project Path="src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj" />
|
<Project Path="src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj" />
|
||||||
|
|||||||
@@ -2,10 +2,6 @@
|
|||||||
|
|
||||||
SCRIPT_DIR=$(dirname "$(realpath "$0")")
|
SCRIPT_DIR=$(dirname "$(realpath "$0")")
|
||||||
|
|
||||||
if [ -f "$SCRIPT_DIR/Ryujinx.Headless.SDL2" ]; then
|
|
||||||
RYUJINX_BIN="Ryujinx.Headless.SDL2"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f "$SCRIPT_DIR/Ryujinx" ]; then
|
if [ -f "$SCRIPT_DIR/Ryujinx" ]; then
|
||||||
RYUJINX_BIN="Ryujinx"
|
RYUJINX_BIN="Ryujinx"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
CURRENTDIR="$(readlink -f "$(dirname "$0")")"
|
||||||
|
exec "$CURRENTDIR"/usr/bin/Ryujinx.sh "$@"
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
#!/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,6 +10,8 @@
|
|||||||
<string>Ryujinx</string>
|
<string>Ryujinx</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>Ryujinx.icns</string>
|
<string>Ryujinx.icns</string>
|
||||||
|
<key>CFBundleIconName</key>
|
||||||
|
<string>Ryujinx</string>
|
||||||
<key>CFBundleDocumentTypes</key>
|
<key>CFBundleDocumentTypes</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
@@ -40,17 +42,17 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.1</string>
|
<string>2.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.1.0</string>
|
<string>2.0.0</string>
|
||||||
<key>NSHighResolutionCapable</key>
|
<key>NSHighResolutionCapable</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>CSResourcesFileMapped</key>
|
<key>CSResourcesFileMapped</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>Copyright © 2018 - 2023 Ryujinx Team and Contributors.</string>
|
<string>Copyright © 2018 - 2024 Ryujinx Team and Contributors. Copyright © 2024 - 2025 Kenji-NX and Contributors.</string>
|
||||||
<key>LSApplicationCategoryType</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
<string>public.app-category.games</string>
|
<string>public.app-category.games</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
|
|||||||
Binary file not shown.
@@ -19,7 +19,7 @@ if platform.system() == "Darwin":
|
|||||||
else:
|
else:
|
||||||
OTOOL = shutil.which("llvm-otool")
|
OTOOL = shutil.which("llvm-otool")
|
||||||
if OTOOL is None:
|
if OTOOL is None:
|
||||||
for llvm_ver in [15, 14, 13]:
|
for llvm_ver in [17, 16, 15, 14, 13]:
|
||||||
otool_path = shutil.which(f"llvm-otool-{llvm_ver}")
|
otool_path = shutil.which(f"llvm-otool-{llvm_ver}")
|
||||||
if otool_path is not None:
|
if otool_path is not None:
|
||||||
OTOOL = otool_path
|
OTOOL = otool_path
|
||||||
@@ -562,26 +562,29 @@ search_path = [
|
|||||||
|
|
||||||
|
|
||||||
for path in content_directory.rglob("**/*.dylib"):
|
for path in content_directory.rglob("**/*.dylib"):
|
||||||
current_search_path = [path.parent]
|
if not path.name.startswith("._"):
|
||||||
current_search_path.extend(search_path)
|
current_search_path = [path.parent]
|
||||||
|
current_search_path.extend(search_path)
|
||||||
|
|
||||||
fixup_dylib(
|
print(f"Fixing path '{path}' using search path of '{current_search_path}' for context of '{content_directory}'.")
|
||||||
path,
|
fixup_dylib(
|
||||||
get_path_related_to_target_exec(content_directory, path),
|
path,
|
||||||
current_search_path,
|
get_path_related_to_target_exec(content_directory, path),
|
||||||
content_directory,
|
current_search_path,
|
||||||
)
|
content_directory,
|
||||||
|
)
|
||||||
|
|
||||||
for path in content_directory.rglob("**/*.so"):
|
for path in content_directory.rglob("**/*.so"):
|
||||||
current_search_path = [path.parent]
|
if not path.name.startswith("._"):
|
||||||
current_search_path.extend(search_path)
|
current_search_path = [path.parent]
|
||||||
|
current_search_path.extend(search_path)
|
||||||
|
|
||||||
fixup_dylib(
|
fixup_dylib(
|
||||||
path,
|
path,
|
||||||
get_path_related_to_target_exec(content_directory, path),
|
get_path_related_to_target_exec(content_directory, path),
|
||||||
current_search_path,
|
current_search_path,
|
||||||
content_directory,
|
content_directory,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
with open(executable_path, "rb") as input:
|
with open(executable_path, "rb") as input:
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ else:
|
|||||||
LIPO = shutil.which("llvm-lipo")
|
LIPO = shutil.which("llvm-lipo")
|
||||||
|
|
||||||
if LIPO is None:
|
if LIPO is None:
|
||||||
for llvm_ver in [15, 14, 13]:
|
for llvm_ver in [17, 16, 15, 14, 13]:
|
||||||
lipo_path = shutil.which(f"llvm-lipo-{llvm_ver}")
|
lipo_path = shutil.which(f"llvm-lipo-{llvm_ver}")
|
||||||
if lipo_path is not None:
|
if lipo_path is not None:
|
||||||
LIPO = lipo_path
|
LIPO = lipo_path
|
||||||
@@ -47,14 +47,12 @@ def get_new_name(
|
|||||||
input_component = str(input_dylib_path).replace(str(input_directory), "")[1:]
|
input_component = str(input_dylib_path).replace(str(input_directory), "")[1:]
|
||||||
return Path(os.path.join(output_directory, input_component))
|
return Path(os.path.join(output_directory, input_component))
|
||||||
|
|
||||||
|
def get_archs(dylib_path: Path) -> list[str]:
|
||||||
def is_fat_file(dylib_path: Path) -> str:
|
res = subprocess.check_output([LIPO, "-info", str(dylib_path)]).decode("utf-8")
|
||||||
res = subprocess.check_output([LIPO, "-info", str(dylib_path.absolute())]).decode(
|
if res.startswith("Non-fat file"):
|
||||||
"utf-8"
|
return [res.split(":")[-1].strip()]
|
||||||
)
|
else:
|
||||||
|
return res.split("are:")[-1].strip().split()
|
||||||
return not res.split("\n")[0].startswith("Non-fat file")
|
|
||||||
|
|
||||||
|
|
||||||
def construct_universal_dylib(
|
def construct_universal_dylib(
|
||||||
arm64_input_dylib_path: Path, x86_64_input_dylib_path: Path, output_dylib_path: Path
|
arm64_input_dylib_path: Path, x86_64_input_dylib_path: Path, output_dylib_path: Path
|
||||||
@@ -69,11 +67,12 @@ def construct_universal_dylib(
|
|||||||
os.path.basename(arm64_input_dylib_path.resolve()), output_dylib_path
|
os.path.basename(arm64_input_dylib_path.resolve()), output_dylib_path
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if is_fat_file(arm64_input_dylib_path) or not x86_64_input_dylib_path.exists():
|
arm64_archs = get_archs(arm64_input_dylib_path)
|
||||||
with open(output_dylib_path, "wb") as dst:
|
x86_64_archs = get_archs(x86_64_input_dylib_path) if x86_64_input_dylib_path.exists() else []
|
||||||
with open(arm64_input_dylib_path, "rb") as src:
|
|
||||||
dst.write(src.read())
|
if "arm64" in arm64_archs and "x86_64" in arm64_archs:
|
||||||
else:
|
shutil.copy2(arm64_input_dylib_path, output_dylib_path)
|
||||||
|
elif x86_64_archs:
|
||||||
subprocess.check_call(
|
subprocess.check_call(
|
||||||
[
|
[
|
||||||
LIPO,
|
LIPO,
|
||||||
|
|||||||
@@ -25,26 +25,41 @@ cp "$PUBLISH_DIRECTORY"/*.dylib "$APP_BUNDLE_DIRECTORY/Contents/Frameworks"
|
|||||||
cp Info.plist "$APP_BUNDLE_DIRECTORY/Contents"
|
cp Info.plist "$APP_BUNDLE_DIRECTORY/Contents"
|
||||||
cp Ryujinx.icns "$APP_BUNDLE_DIRECTORY/Contents/Resources/Ryujinx.icns"
|
cp Ryujinx.icns "$APP_BUNDLE_DIRECTORY/Contents/Resources/Ryujinx.icns"
|
||||||
cp updater.sh "$APP_BUNDLE_DIRECTORY/Contents/Resources/updater.sh"
|
cp updater.sh "$APP_BUNDLE_DIRECTORY/Contents/Resources/updater.sh"
|
||||||
|
cp Assets.car "$APP_BUNDLE_DIRECTORY/Contents/Resources/Assets.car"
|
||||||
cp -r "$PUBLISH_DIRECTORY/THIRDPARTY.md" "$APP_BUNDLE_DIRECTORY/Contents/Resources"
|
cp -r "$PUBLISH_DIRECTORY/THIRDPARTY.md" "$APP_BUNDLE_DIRECTORY/Contents/Resources"
|
||||||
|
|
||||||
echo -n "APPL????" > "$APP_BUNDLE_DIRECTORY/Contents/PkgInfo"
|
echo -n "APPL????" > "$APP_BUNDLE_DIRECTORY/Contents/PkgInfo"
|
||||||
|
|
||||||
# Fixup libraries and executable
|
# Fixup libraries and executable
|
||||||
|
echo "Running bundle fix up python script"
|
||||||
python3 bundle_fix_up.py "$APP_BUNDLE_DIRECTORY" MacOS/Ryujinx
|
python3 bundle_fix_up.py "$APP_BUNDLE_DIRECTORY" MacOS/Ryujinx
|
||||||
|
|
||||||
|
# Resign all dyplib files as ad-hoc after changing them
|
||||||
|
find "$APP_BUNDLE_DIRECTORY/Contents/Frameworks" -type f -name "*.dylib" -exec codesign --force --sign - {} \;
|
||||||
|
|
||||||
# Now sign it
|
# Now sign it
|
||||||
|
echo "Starting signing process"
|
||||||
if ! [ -x "$(command -v codesign)" ];
|
if ! [ -x "$(command -v codesign)" ];
|
||||||
then
|
then
|
||||||
if ! [ -x "$(command -v rcodesign)" ];
|
if ! [ -x "$(command -v rcodesign)" ];
|
||||||
then
|
then
|
||||||
echo "Cannot find rcodesign on your system, please install rcodesign."
|
echo "Cannot find rcodesign on your system, please install rcodesign and ensure it is in your search path."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# cargo install apple-codesign
|
echo "Using rcodesign for ad-hoc signing"
|
||||||
echo "Usign rcodesign for ad-hoc signing"
|
|
||||||
|
echo "Resigning all frameworks dylib files as ad-hoc"
|
||||||
|
find "$APP_BUNDLE_DIRECTORY/Contents/Frameworks" -type f -name "*.dylib" -exec rcodesign sign {} \;
|
||||||
|
|
||||||
|
echo "Signing app bundle as ad-hoc"
|
||||||
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$APP_BUNDLE_DIRECTORY"
|
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$APP_BUNDLE_DIRECTORY"
|
||||||
else
|
else
|
||||||
echo "Usign codesign for ad-hoc signing"
|
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"
|
||||||
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$APP_BUNDLE_DIRECTORY"
|
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$APP_BUNDLE_DIRECTORY"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -20,7 +20,19 @@ SOURCE_REVISION_ID=$6
|
|||||||
CONFIGURATION=$7
|
CONFIGURATION=$7
|
||||||
EXTRA_ARGS=$8
|
EXTRA_ARGS=$8
|
||||||
|
|
||||||
if [ "$VERSION" == "1.1.0" ];
|
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" ];
|
||||||
then
|
then
|
||||||
RELEASE_TAR_FILE_NAME=ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar
|
RELEASE_TAR_FILE_NAME=ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar
|
||||||
else
|
else
|
||||||
@@ -66,11 +78,11 @@ python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_APP_
|
|||||||
|
|
||||||
if ! [ -x "$(command -v lipo)" ];
|
if ! [ -x "$(command -v lipo)" ];
|
||||||
then
|
then
|
||||||
if ! [ -x "$(command -v llvm-lipo-14)" ];
|
if ! [ -x "$(command -v llvm-lipo-17)" ];
|
||||||
then
|
then
|
||||||
LIPO=llvm-lipo
|
LIPO=llvm-lipo
|
||||||
else
|
else
|
||||||
LIPO=llvm-lipo-14
|
LIPO=llvm-lipo-17
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
LIPO=lipo
|
LIPO=lipo
|
||||||
@@ -109,12 +121,6 @@ python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "
|
|||||||
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
|
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
|
||||||
rm "$RELEASE_TAR_FILE_NAME"
|
rm "$RELEASE_TAR_FILE_NAME"
|
||||||
|
|
||||||
# Create legacy update package for Avalonia to not left behind old testers.
|
|
||||||
if [ "$VERSION" != "1.1.0" ];
|
|
||||||
then
|
|
||||||
cp $RELEASE_TAR_FILE_NAME.gz test-ava-ryujinx-$VERSION-macos_universal.app.tar.gz
|
|
||||||
fi
|
|
||||||
|
|
||||||
popd
|
popd
|
||||||
|
|
||||||
echo "Done"
|
echo "Done"
|
||||||
|
|||||||
@@ -1,111 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [ "$#" -lt 7 ]; then
|
|
||||||
echo "usage <BASE_DIR> <TEMP_DIRECTORY> <OUTPUT_DIRECTORY> <ENTITLEMENTS_FILE_PATH> <VERSION> <SOURCE_REVISION_ID> <CONFIGURATION> <EXTRA_ARGS>"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p "$1"
|
|
||||||
mkdir -p "$2"
|
|
||||||
mkdir -p "$3"
|
|
||||||
|
|
||||||
BASE_DIR=$(readlink -f "$1")
|
|
||||||
TEMP_DIRECTORY=$(readlink -f "$2")
|
|
||||||
OUTPUT_DIRECTORY=$(readlink -f "$3")
|
|
||||||
ENTITLEMENTS_FILE_PATH=$(readlink -f "$4")
|
|
||||||
VERSION=$5
|
|
||||||
SOURCE_REVISION_ID=$6
|
|
||||||
CONFIGURATION=$7
|
|
||||||
EXTRA_ARGS=$8
|
|
||||||
|
|
||||||
if [ "$VERSION" == "1.1.0" ];
|
|
||||||
then
|
|
||||||
RELEASE_TAR_FILE_NAME=sdl2-ryujinx-headless-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.tar
|
|
||||||
else
|
|
||||||
RELEASE_TAR_FILE_NAME=sdl2-ryujinx-headless-$VERSION-macos_universal.tar
|
|
||||||
fi
|
|
||||||
|
|
||||||
ARM64_OUTPUT="$TEMP_DIRECTORY/publish_arm64"
|
|
||||||
X64_OUTPUT="$TEMP_DIRECTORY/publish_x64"
|
|
||||||
UNIVERSAL_OUTPUT="$OUTPUT_DIRECTORY/publish"
|
|
||||||
EXECUTABLE_SUB_PATH=Ryujinx.Headless.SDL2
|
|
||||||
|
|
||||||
rm -rf "$TEMP_DIRECTORY"
|
|
||||||
mkdir -p "$TEMP_DIRECTORY"
|
|
||||||
|
|
||||||
DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS)
|
|
||||||
|
|
||||||
dotnet restore
|
|
||||||
dotnet build -c "$CONFIGURATION" src/Ryujinx.Headless.SDL2
|
|
||||||
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL2
|
|
||||||
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL2
|
|
||||||
|
|
||||||
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
|
|
||||||
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
|
|
||||||
|
|
||||||
# Get rid of libsoundio from arm64 builds as we don't have a arm64 variant
|
|
||||||
# TODO: remove this once done
|
|
||||||
rm -rf "$TEMP_DIRECTORY/publish_arm64/libsoundio.dylib"
|
|
||||||
|
|
||||||
rm -rf "$OUTPUT_DIRECTORY"
|
|
||||||
mkdir -p "$OUTPUT_DIRECTORY"
|
|
||||||
|
|
||||||
# Let's copy one of the two different outputs and remove the executable
|
|
||||||
cp -R "$ARM64_OUTPUT/" "$UNIVERSAL_OUTPUT"
|
|
||||||
rm "$UNIVERSAL_OUTPUT/$EXECUTABLE_SUB_PATH"
|
|
||||||
|
|
||||||
# Make it libraries universal
|
|
||||||
python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_OUTPUT" "$X64_OUTPUT" "$UNIVERSAL_OUTPUT" "**/*.dylib"
|
|
||||||
|
|
||||||
if ! [ -x "$(command -v lipo)" ];
|
|
||||||
then
|
|
||||||
if ! [ -x "$(command -v llvm-lipo-14)" ];
|
|
||||||
then
|
|
||||||
LIPO=llvm-lipo
|
|
||||||
else
|
|
||||||
LIPO=llvm-lipo-14
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
LIPO=lipo
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Make the executable universal
|
|
||||||
$LIPO "$ARM64_OUTPUT/$EXECUTABLE_SUB_PATH" "$X64_OUTPUT/$EXECUTABLE_SUB_PATH" -output "$UNIVERSAL_OUTPUT/$EXECUTABLE_SUB_PATH" -create
|
|
||||||
|
|
||||||
# Now sign it
|
|
||||||
if ! [ -x "$(command -v codesign)" ];
|
|
||||||
then
|
|
||||||
if ! [ -x "$(command -v rcodesign)" ];
|
|
||||||
then
|
|
||||||
echo "Cannot find rcodesign on your system, please install rcodesign."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# NOTE: Currently require https://github.com/indygreg/apple-platform-rs/pull/44 to work on other OSes.
|
|
||||||
# cargo install --git "https://github.com/marysaka/apple-platform-rs" --branch "fix/adhoc-app-bundle" apple-codesign --bin "rcodesign"
|
|
||||||
echo "Using rcodesign for ad-hoc signing"
|
|
||||||
for FILE in "$UNIVERSAL_OUTPUT"/*; do
|
|
||||||
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
|
|
||||||
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$FILE"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
else
|
|
||||||
echo "Using codesign for ad-hoc signing"
|
|
||||||
for FILE in "$UNIVERSAL_OUTPUT"/*; do
|
|
||||||
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
|
|
||||||
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$FILE"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Creating archive"
|
|
||||||
pushd "$OUTPUT_DIRECTORY"
|
|
||||||
tar --exclude "publish/Ryujinx.Headless.SDL2" -cvf "$RELEASE_TAR_FILE_NAME" publish 1> /dev/null
|
|
||||||
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "publish/Ryujinx.Headless.SDL2" "publish/Ryujinx.Headless.SDL2"
|
|
||||||
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
|
|
||||||
rm "$RELEASE_TAR_FILE_NAME"
|
|
||||||
popd
|
|
||||||
|
|
||||||
echo "Done"
|
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "9.0.100",
|
"version": "10.0.100",
|
||||||
"rollForward": "latestFeature"
|
"rollForward": "latestFeature"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace ARMeilleure.CodeGen
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a compiled function.
|
/// Represents a compiled function.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
readonly struct CompiledFunction
|
public readonly struct CompiledFunction
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the machine code of the <see cref="CompiledFunction"/>.
|
/// Gets the machine code of the <see cref="CompiledFunction"/>.
|
||||||
@@ -44,10 +44,11 @@ namespace ARMeilleure.CodeGen
|
|||||||
/// <typeparamref name="T"/> pointing to the mapped function.
|
/// <typeparamref name="T"/> pointing to the mapped function.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Type of delegate</typeparam>
|
/// <typeparam name="T">Type of delegate</typeparam>
|
||||||
|
/// <param name="jitCache">The jit cache to map the function into</param>
|
||||||
/// <returns>A delegate of type <typeparamref name="T"/> pointing to the mapped function</returns>
|
/// <returns>A delegate of type <typeparamref name="T"/> pointing to the mapped function</returns>
|
||||||
public T Map<T>()
|
public T Map<T>(JitCache jitCache)
|
||||||
{
|
{
|
||||||
return MapWithPointer<T>(out _);
|
return MapWithPointer<T>(jitCache, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -55,11 +56,12 @@ namespace ARMeilleure.CodeGen
|
|||||||
/// <typeparamref name="T"/> pointing to the mapped function.
|
/// <typeparamref name="T"/> pointing to the mapped function.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Type of delegate</typeparam>
|
/// <typeparam name="T">Type of delegate</typeparam>
|
||||||
|
/// <param name="jitCache">The jit cache to map the function into</param>
|
||||||
/// <param name="codePointer">Pointer to the function code in memory</param>
|
/// <param name="codePointer">Pointer to the function code in memory</param>
|
||||||
/// <returns>A delegate of type <typeparamref name="T"/> pointing to the mapped function</returns>
|
/// <returns>A delegate of type <typeparamref name="T"/> pointing to the mapped function</returns>
|
||||||
public T MapWithPointer<T>(out nint codePointer)
|
public T MapWithPointer<T>(JitCache jitCache, out nint codePointer)
|
||||||
{
|
{
|
||||||
codePointer = JitCache.Map(this);
|
codePointer = jitCache.Map(this);
|
||||||
|
|
||||||
return Marshal.GetDelegateForFunctionPointer<T>(codePointer);
|
return Marshal.GetDelegateForFunctionPointer<T>(codePointer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ namespace ARMeilleure.CodeGen.Linking
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a relocation.
|
/// Represents a relocation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
readonly struct RelocEntry
|
public readonly struct RelocEntry
|
||||||
{
|
{
|
||||||
public const int Stride = 13; // Bytes.
|
public const int Stride = 13; // Bytes.
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace ARMeilleure.CodeGen.Linking
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents relocation information about a <see cref="CompiledFunction"/>.
|
/// Represents relocation information about a <see cref="CompiledFunction"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
readonly struct RelocInfo
|
public readonly struct RelocInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets an empty <see cref="RelocInfo"/>.
|
/// Gets an empty <see cref="RelocInfo"/>.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace ARMeilleure.CodeGen.Linking
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a symbol.
|
/// Represents a symbol.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
readonly struct Symbol
|
public readonly struct Symbol
|
||||||
{
|
{
|
||||||
private readonly ulong _value;
|
private readonly ulong _value;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ namespace ARMeilleure.CodeGen.Linking
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Types of <see cref="Symbol"/>.
|
/// Types of <see cref="Symbol"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
enum SymbolType : byte
|
public enum SymbolType : byte
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Refers to nothing, i.e no symbol.
|
/// Refers to nothing, i.e no symbol.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.CodeGen.Unwinding
|
namespace ARMeilleure.CodeGen.Unwinding
|
||||||
{
|
{
|
||||||
struct UnwindInfo
|
public struct UnwindInfo
|
||||||
{
|
{
|
||||||
public const int Stride = 4; // Bytes.
|
public const int Stride = 4; // Bytes.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.CodeGen.Unwinding
|
namespace ARMeilleure.CodeGen.Unwinding
|
||||||
{
|
{
|
||||||
enum UnwindPseudoOp
|
public enum UnwindPseudoOp
|
||||||
{
|
{
|
||||||
PushReg = 0,
|
PushReg = 0,
|
||||||
SetFrame = 1,
|
SetFrame = 1,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.CodeGen.Unwinding
|
namespace ARMeilleure.CodeGen.Unwinding
|
||||||
{
|
{
|
||||||
struct UnwindPushEntry
|
public struct UnwindPushEntry
|
||||||
{
|
{
|
||||||
public const int Stride = 16; // Bytes.
|
public const int Stride = 16; // Bytes.
|
||||||
|
|
||||||
|
|||||||
@@ -20,45 +20,21 @@ namespace ARMeilleure.Common
|
|||||||
new( 1, 6)
|
new( 1, 6)
|
||||||
];
|
];
|
||||||
|
|
||||||
private static readonly AddressTableLevel[] _levels64BitSparseTiny =
|
private static readonly AddressTableLevel[] _levels64BitMono =
|
||||||
[
|
[
|
||||||
new( 11, 28),
|
new( 2, 37)
|
||||||
new( 2, 9)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
private static readonly AddressTableLevel[] _levels32BitSparseTiny =
|
private static readonly AddressTableLevel[] _levels32BitMono =
|
||||||
[
|
[
|
||||||
new( 10, 22),
|
new( 1, 31)
|
||||||
new( 1, 9)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
private static readonly AddressTableLevel[] _levels64BitSparseGiant =
|
public static AddressTableLevel[] GetArmPreset(bool for64Bits, bool mono)
|
||||||
[
|
|
||||||
new( 38, 1),
|
|
||||||
new( 2, 36)
|
|
||||||
];
|
|
||||||
|
|
||||||
private static readonly AddressTableLevel[] _levels32BitSparseGiant =
|
|
||||||
[
|
|
||||||
new( 31, 1),
|
|
||||||
new( 1, 30)
|
|
||||||
];
|
|
||||||
|
|
||||||
//high power will run worse on DDR3 systems and some DDR4 systems due to the higher ram utilization
|
|
||||||
//low power will never run worse than non-sparse, but for most systems it won't be necessary
|
|
||||||
//high power is always used, but I've left low power in here for future reference
|
|
||||||
public static AddressTableLevel[] GetArmPreset(bool for64Bits, bool sparse, bool lowPower = false)
|
|
||||||
{
|
{
|
||||||
if (sparse)
|
if (mono)
|
||||||
{
|
{
|
||||||
if (lowPower)
|
return for64Bits ? _levels64BitMono : _levels32BitMono;
|
||||||
{
|
|
||||||
return for64Bits ? _levels64BitSparseTiny : _levels32BitSparseTiny;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return for64Bits ? _levels64BitSparseGiant : _levels32BitSparseGiant;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace ARMeilleure.Common
|
||||||
|
{
|
||||||
|
public enum AddressTableType
|
||||||
|
{
|
||||||
|
Default,
|
||||||
|
Sparse
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,5 +53,14 @@ namespace ARMeilleure.Common
|
|||||||
{
|
{
|
||||||
return (bits >> shift) | (bits << (size - shift));
|
return (bits >> shift) | (bits << (size - shift));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static T AlignUp<T>(T value, T size) where T : IBinaryInteger<T>
|
||||||
|
=> (value + (size - T.One)) & -size;
|
||||||
|
|
||||||
|
public static T AlignDown<T>(T value, T size) where T : IBinaryInteger<T>
|
||||||
|
=> value & -size;
|
||||||
|
|
||||||
|
public static T DivRoundUp<T>(T value, T dividend) where T : IBinaryInteger<T>
|
||||||
|
=> (value + (dividend - T.One)) / dividend;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,10 @@ namespace ARMeilleure.Common
|
|||||||
public interface IAddressTable<TEntry> : IDisposable where TEntry : unmanaged
|
public interface IAddressTable<TEntry> : IDisposable where TEntry : unmanaged
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// True if the address table's bottom level is sparsely mapped.
|
/// Gets the <see cref="AddressTableType"/> of the <see cref="IAddressTable{TEntry}"/> instance.
|
||||||
/// This also ensures the second bottom level is filled with a dummy page rather than 0.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool Sparse { get; }
|
AddressTableType TableType { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the bits used by the <see cref="Levels"/> of the <see cref="IAddressTable{TEntry}"/> instance.
|
/// Gets the bits used by the <see cref="Levels"/> of the <see cref="IAddressTable{TEntry}"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -31,6 +30,13 @@ namespace ARMeilleure.Common
|
|||||||
/// <exception cref="ObjectDisposedException"><see cref="EntryTable{TEntry}"/> instance was disposed</exception>
|
/// <exception cref="ObjectDisposedException"><see cref="EntryTable{TEntry}"/> instance was disposed</exception>
|
||||||
nint Base { get; }
|
nint Base { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Signal that the given code range exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="address">Guest code range address</param>
|
||||||
|
/// <param name="size">Guest code range size</param>
|
||||||
|
void SignalCodeRange(ulong address, ulong size);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines if the specified <paramref name="address"/> is in the range of the
|
/// Determines if the specified <paramref name="address"/> is in the range of the
|
||||||
/// <see cref="IAddressTable{TEntry}"/>.
|
/// <see cref="IAddressTable{TEntry}"/>.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using ARMeilleure.IntermediateRepresentation;
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using ARMeilleure.Translation.PTC;
|
using ARMeilleure.Translation.PTC;
|
||||||
|
using System.Linq;
|
||||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||||
|
|
||||||
@@ -147,6 +147,12 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void EmitCall(ArmEmitterContext context, ulong immediate)
|
public static void EmitCall(ArmEmitterContext context, ulong immediate)
|
||||||
{
|
{
|
||||||
|
if (context.IsSingleStep)
|
||||||
|
{
|
||||||
|
context.Return(Const(immediate));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool isRecursive = immediate == context.EntryAddress;
|
bool isRecursive = immediate == context.EntryAddress;
|
||||||
|
|
||||||
if (isRecursive)
|
if (isRecursive)
|
||||||
@@ -161,12 +167,24 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void EmitVirtualCall(ArmEmitterContext context, Operand target)
|
public static void EmitVirtualCall(ArmEmitterContext context, Operand target)
|
||||||
{
|
{
|
||||||
EmitTableBranch(context, target, isJump: false);
|
if (context.IsSingleStep)
|
||||||
|
{
|
||||||
|
if (target.Type == OperandType.I32)
|
||||||
|
{
|
||||||
|
target = context.ZeroExtend32(OperandType.I64, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Return(target);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitTableBranch(context, target, isJump: false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void EmitVirtualJump(ArmEmitterContext context, Operand target, bool isReturn)
|
public static void EmitVirtualJump(ArmEmitterContext context, Operand target, bool isReturn)
|
||||||
{
|
{
|
||||||
if (isReturn)
|
if (isReturn || context.IsSingleStep)
|
||||||
{
|
{
|
||||||
EmitReturn(context, target);
|
EmitReturn(context, target);
|
||||||
}
|
}
|
||||||
@@ -218,9 +236,9 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
hostAddress = context.Load(OperandType.I64, hostAddressAddr);
|
hostAddress = context.Load(OperandType.I64, hostAddressAddr);
|
||||||
}
|
}
|
||||||
else if (table.Sparse)
|
else if (table.TableType == AddressTableType.Sparse)
|
||||||
{
|
{
|
||||||
// Inline table lookup. Only enabled when the sparse function table is enabled with 2 levels.
|
// Inline table lookup. Only enabled when the sparse function table is enabled with 1 level.
|
||||||
// Deliberately attempts to avoid branches.
|
// Deliberately attempts to avoid branches.
|
||||||
|
|
||||||
Operand tableBase = !context.HasPtc ?
|
Operand tableBase = !context.HasPtc ?
|
||||||
@@ -229,24 +247,21 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
hostAddress = tableBase;
|
hostAddress = tableBase;
|
||||||
|
|
||||||
for (int i = 0; i < table.Levels.Length; i++)
|
AddressTableLevel level = table.Levels.Last();
|
||||||
{
|
int clearBits = 64 - (level.Index + level.Length);
|
||||||
AddressTableLevel level = table.Levels[i];
|
|
||||||
int clearBits = 64 - (level.Index + level.Length);
|
|
||||||
|
|
||||||
Operand index = context.ShiftLeft(
|
Operand index = context.ShiftLeft(
|
||||||
context.ShiftRightUI(context.ShiftLeft(guestAddress, Const(clearBits)), Const(clearBits + level.Index)),
|
context.ShiftRightUI(context.ShiftLeft(guestAddress, Const(clearBits)), Const(clearBits + level.Index)),
|
||||||
Const(3)
|
Const(3)
|
||||||
);
|
);
|
||||||
|
|
||||||
hostAddress = context.Load(OperandType.I64, context.Add(hostAddress, index));
|
hostAddress = context.Load(OperandType.I64, context.Add(hostAddress, index));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hostAddress = !context.HasPtc ?
|
hostAddress = !context.HasPtc ?
|
||||||
Const((long)context.Stubs.DispatchStub) :
|
Const(context.Stubs.DispatchStub) :
|
||||||
Const((long)context.Stubs.DispatchStub, Ptc.DispatchStubSymbol);
|
Const(context.Stubs.DispatchStub, Ptc.DispatchStubSymbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isJump)
|
if (isJump)
|
||||||
|
|||||||
@@ -1,59 +1,35 @@
|
|||||||
using System;
|
using System;
|
||||||
#if ANDROID
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
#else
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
static class MathHelper
|
static class MathHelper
|
||||||
{
|
{
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double Abs(double value)
|
public static double Abs(double value)
|
||||||
{
|
{
|
||||||
return Math.Abs(value);
|
return Math.Abs(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double Ceiling(double value)
|
public static double Ceiling(double value)
|
||||||
{
|
{
|
||||||
return Math.Ceiling(value);
|
return Math.Ceiling(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double Floor(double value)
|
public static double Floor(double value)
|
||||||
{
|
{
|
||||||
return Math.Floor(value);
|
return Math.Floor(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double Round(double value, int mode)
|
public static double Round(double value, int mode)
|
||||||
{
|
{
|
||||||
return Math.Round(value, (MidpointRounding)mode);
|
return Math.Round(value, (MidpointRounding)mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double Truncate(double value)
|
public static double Truncate(double value)
|
||||||
{
|
{
|
||||||
return Math.Truncate(value);
|
return Math.Truncate(value);
|
||||||
@@ -62,51 +38,31 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
static class MathHelperF
|
static class MathHelperF
|
||||||
{
|
{
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float Abs(float value)
|
public static float Abs(float value)
|
||||||
{
|
{
|
||||||
return MathF.Abs(value);
|
return MathF.Abs(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float Ceiling(float value)
|
public static float Ceiling(float value)
|
||||||
{
|
{
|
||||||
return MathF.Ceiling(value);
|
return MathF.Ceiling(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float Floor(float value)
|
public static float Floor(float value)
|
||||||
{
|
{
|
||||||
return MathF.Floor(value);
|
return MathF.Floor(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float Round(float value, int mode)
|
public static float Round(float value, int mode)
|
||||||
{
|
{
|
||||||
return MathF.Round(value, (MidpointRounding)mode);
|
return MathF.Round(value, (MidpointRounding)mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float Truncate(float value)
|
public static float Truncate(float value)
|
||||||
{
|
{
|
||||||
return MathF.Truncate(value);
|
return MathF.Truncate(value);
|
||||||
|
|||||||
@@ -2,11 +2,7 @@ using ARMeilleure.Memory;
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using System;
|
using System;
|
||||||
#if ANDROID
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
#else
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
@@ -39,11 +35,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Context = null;
|
Context = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static void Break(ulong address, int imm)
|
public static void Break(ulong address, int imm)
|
||||||
{
|
{
|
||||||
Statistics.PauseTimer();
|
Statistics.PauseTimer();
|
||||||
@@ -53,11 +45,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Statistics.ResumeTimer();
|
Statistics.ResumeTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static void SupervisorCall(ulong address, int imm)
|
public static void SupervisorCall(ulong address, int imm)
|
||||||
{
|
{
|
||||||
Statistics.PauseTimer();
|
Statistics.PauseTimer();
|
||||||
@@ -67,11 +55,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Statistics.ResumeTimer();
|
Statistics.ResumeTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static void Undefined(ulong address, int opCode)
|
public static void Undefined(ulong address, int opCode)
|
||||||
{
|
{
|
||||||
Statistics.PauseTimer();
|
Statistics.PauseTimer();
|
||||||
@@ -82,51 +66,31 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region "System registers"
|
#region "System registers"
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static ulong GetCtrEl0()
|
public static ulong GetCtrEl0()
|
||||||
{
|
{
|
||||||
return GetContext().CtrEl0;
|
return GetContext().CtrEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static ulong GetDczidEl0()
|
public static ulong GetDczidEl0()
|
||||||
{
|
{
|
||||||
return GetContext().DczidEl0;
|
return GetContext().DczidEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static ulong GetCntfrqEl0()
|
public static ulong GetCntfrqEl0()
|
||||||
{
|
{
|
||||||
return GetContext().CntfrqEl0;
|
return GetContext().CntfrqEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static ulong GetCntpctEl0()
|
public static ulong GetCntpctEl0()
|
||||||
{
|
{
|
||||||
return GetContext().CntpctEl0;
|
return GetContext().CntpctEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static ulong GetCntvctEl0()
|
public static ulong GetCntvctEl0()
|
||||||
{
|
{
|
||||||
return GetContext().CntvctEl0;
|
return GetContext().CntvctEl0;
|
||||||
@@ -134,51 +98,31 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Read"
|
#region "Read"
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static byte ReadByte(ulong address)
|
public static byte ReadByte(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadGuest<byte>(address);
|
return GetMemoryManager().ReadGuest<byte>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static ushort ReadUInt16(ulong address)
|
public static ushort ReadUInt16(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadGuest<ushort>(address);
|
return GetMemoryManager().ReadGuest<ushort>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static uint ReadUInt32(ulong address)
|
public static uint ReadUInt32(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadGuest<uint>(address);
|
return GetMemoryManager().ReadGuest<uint>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static ulong ReadUInt64(ulong address)
|
public static ulong ReadUInt64(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadGuest<ulong>(address);
|
return GetMemoryManager().ReadGuest<ulong>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 ReadVector128(ulong address)
|
public static V128 ReadVector128(ulong address)
|
||||||
{
|
{
|
||||||
return GetMemoryManager().ReadGuest<V128>(address);
|
return GetMemoryManager().ReadGuest<V128>(address);
|
||||||
@@ -186,92 +130,56 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Write"
|
#region "Write"
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static void WriteByte(ulong address, byte value)
|
public static void WriteByte(ulong address, byte value)
|
||||||
{
|
{
|
||||||
GetMemoryManager().WriteGuest(address, value);
|
GetMemoryManager().WriteGuest(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static void WriteUInt16(ulong address, ushort value)
|
public static void WriteUInt16(ulong address, ushort value)
|
||||||
{
|
{
|
||||||
GetMemoryManager().WriteGuest(address, value);
|
GetMemoryManager().WriteGuest(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static void WriteUInt32(ulong address, uint value)
|
public static void WriteUInt32(ulong address, uint value)
|
||||||
{
|
{
|
||||||
GetMemoryManager().WriteGuest(address, value);
|
GetMemoryManager().WriteGuest(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static void WriteUInt64(ulong address, ulong value)
|
public static void WriteUInt64(ulong address, ulong value)
|
||||||
{
|
{
|
||||||
GetMemoryManager().WriteGuest(address, value);
|
GetMemoryManager().WriteGuest(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static void WriteVector128(ulong address, V128 value)
|
public static void WriteVector128(ulong address, V128 value)
|
||||||
{
|
{
|
||||||
GetMemoryManager().WriteGuest(address, value);
|
GetMemoryManager().WriteGuest(address, value);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static void EnqueueForRejit(ulong address)
|
public static void EnqueueForRejit(ulong address)
|
||||||
{
|
{
|
||||||
Context.Translator.EnqueueForRejit(address, GetContext().ExecutionMode);
|
Context.Translator.EnqueueForRejit(address, GetContext().ExecutionMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static void SignalMemoryTracking(ulong address, ulong size, byte write)
|
public static void SignalMemoryTracking(ulong address, ulong size, byte write)
|
||||||
{
|
{
|
||||||
GetMemoryManager().SignalMemoryTracking(address, size, write == 1);
|
GetMemoryManager().SignalMemoryTracking(address, size, write == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static void ThrowInvalidMemoryAccess(ulong address)
|
public static void ThrowInvalidMemoryAccess(ulong address)
|
||||||
{
|
{
|
||||||
throw new InvalidAccessException(address);
|
throw new InvalidAccessException(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static ulong GetFunctionAddress(ulong address)
|
public static ulong GetFunctionAddress(ulong address)
|
||||||
{
|
{
|
||||||
TranslatedFunction function = Context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
|
TranslatedFunction function = Context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
|
||||||
@@ -279,21 +187,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return (ulong)function.FuncPointer.ToInt64();
|
return (ulong)function.FuncPointer.ToInt64();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static void InvalidateCacheLine(ulong address)
|
public static void InvalidateCacheLine(ulong address)
|
||||||
{
|
{
|
||||||
Context.Translator.InvalidateJitCacheRegion(address, InstEmit.DczSizeInBytes);
|
Context.Translator.InvalidateJitCacheRegion(address, InstEmit.DczSizeInBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static byte CheckSynchronization()
|
public static byte CheckSynchronization()
|
||||||
{
|
{
|
||||||
Statistics.PauseTimer();
|
Statistics.PauseTimer();
|
||||||
|
|||||||
@@ -1,21 +1,13 @@
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using System;
|
using System;
|
||||||
#if ANDROID
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
#else
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
static class SoftFallback
|
static class SoftFallback
|
||||||
{
|
{
|
||||||
#region "ShrImm64"
|
#region "ShrImm64"
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static long SignedShrImm64(long value, long roundConst, int shift)
|
public static long SignedShrImm64(long value, long roundConst, int shift)
|
||||||
{
|
{
|
||||||
if (roundConst == 0L)
|
if (roundConst == 0L)
|
||||||
@@ -58,11 +50,7 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
|
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
|
||||||
{
|
{
|
||||||
if (roundConst == 0L)
|
if (roundConst == 0L)
|
||||||
@@ -107,11 +95,7 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Saturation"
|
#region "Saturation"
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static int SatF32ToS32(float value)
|
public static int SatF32ToS32(float value)
|
||||||
{
|
{
|
||||||
if (float.IsNaN(value))
|
if (float.IsNaN(value))
|
||||||
@@ -123,11 +107,7 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= int.MinValue ? int.MinValue : (int)value;
|
value <= int.MinValue ? int.MinValue : (int)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static long SatF32ToS64(float value)
|
public static long SatF32ToS64(float value)
|
||||||
{
|
{
|
||||||
if (float.IsNaN(value))
|
if (float.IsNaN(value))
|
||||||
@@ -139,11 +119,7 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= long.MinValue ? long.MinValue : (long)value;
|
value <= long.MinValue ? long.MinValue : (long)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static uint SatF32ToU32(float value)
|
public static uint SatF32ToU32(float value)
|
||||||
{
|
{
|
||||||
if (float.IsNaN(value))
|
if (float.IsNaN(value))
|
||||||
@@ -155,11 +131,7 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static ulong SatF32ToU64(float value)
|
public static ulong SatF32ToU64(float value)
|
||||||
{
|
{
|
||||||
if (float.IsNaN(value))
|
if (float.IsNaN(value))
|
||||||
@@ -171,11 +143,7 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
|
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static int SatF64ToS32(double value)
|
public static int SatF64ToS32(double value)
|
||||||
{
|
{
|
||||||
if (double.IsNaN(value))
|
if (double.IsNaN(value))
|
||||||
@@ -187,11 +155,7 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= int.MinValue ? int.MinValue : (int)value;
|
value <= int.MinValue ? int.MinValue : (int)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static long SatF64ToS64(double value)
|
public static long SatF64ToS64(double value)
|
||||||
{
|
{
|
||||||
if (double.IsNaN(value))
|
if (double.IsNaN(value))
|
||||||
@@ -203,11 +167,7 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= long.MinValue ? long.MinValue : (long)value;
|
value <= long.MinValue ? long.MinValue : (long)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static uint SatF64ToU32(double value)
|
public static uint SatF64ToU32(double value)
|
||||||
{
|
{
|
||||||
if (double.IsNaN(value))
|
if (double.IsNaN(value))
|
||||||
@@ -219,11 +179,7 @@ namespace ARMeilleure.Instructions
|
|||||||
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
value <= uint.MinValue ? uint.MinValue : (uint)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static ulong SatF64ToU64(double value)
|
public static ulong SatF64ToU64(double value)
|
||||||
{
|
{
|
||||||
if (double.IsNaN(value))
|
if (double.IsNaN(value))
|
||||||
@@ -237,11 +193,7 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Count"
|
#region "Count"
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
||||||
{
|
{
|
||||||
value ^= value >> 1;
|
value ^= value >> 1;
|
||||||
@@ -261,11 +213,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static ReadOnlySpan<byte> ClzNibbleTbl => [4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
|
private static ReadOnlySpan<byte> ClzNibbleTbl => [4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
||||||
{
|
{
|
||||||
if (value == 0ul)
|
if (value == 0ul)
|
||||||
@@ -289,81 +237,49 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Table"
|
#region "Table"
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
|
public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
|
||||||
{
|
{
|
||||||
return TblOrTbx(default, vector, bytes, tb0);
|
return TblOrTbx(default, vector, bytes, tb0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
|
public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
|
||||||
{
|
{
|
||||||
return TblOrTbx(default, vector, bytes, tb0, tb1);
|
return TblOrTbx(default, vector, bytes, tb0, tb1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
||||||
{
|
{
|
||||||
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
|
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
|
public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
|
||||||
{
|
{
|
||||||
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3);
|
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
|
public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
|
||||||
{
|
{
|
||||||
return TblOrTbx(dest, vector, bytes, tb0);
|
return TblOrTbx(dest, vector, bytes, tb0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
|
public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
|
||||||
{
|
{
|
||||||
return TblOrTbx(dest, vector, bytes, tb0, tb1);
|
return TblOrTbx(dest, vector, bytes, tb0, tb1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
|
||||||
{
|
{
|
||||||
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
|
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
|
public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
|
||||||
{
|
{
|
||||||
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
|
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
|
||||||
@@ -405,54 +321,22 @@ namespace ARMeilleure.Instructions
|
|||||||
private const uint Crc32RevPoly = 0xedb88320;
|
private const uint Crc32RevPoly = 0xedb88320;
|
||||||
private const uint Crc32cRevPoly = 0x82f63b78;
|
private const uint Crc32cRevPoly = 0x82f63b78;
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
|
public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
|
public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
|
public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
|
public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
|
public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
|
public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
|
public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
|
public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
|
||||||
|
|
||||||
private static uint Crc32h(uint crc, uint poly, ushort val)
|
private static uint Crc32h(uint crc, uint poly, ushort val)
|
||||||
@@ -503,41 +387,25 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Aes"
|
#region "Aes"
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 Decrypt(V128 value, V128 roundKey)
|
public static V128 Decrypt(V128 value, V128 roundKey)
|
||||||
{
|
{
|
||||||
return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
|
return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 Encrypt(V128 value, V128 roundKey)
|
public static V128 Encrypt(V128 value, V128 roundKey)
|
||||||
{
|
{
|
||||||
return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
|
return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 InverseMixColumns(V128 value)
|
public static V128 InverseMixColumns(V128 value)
|
||||||
{
|
{
|
||||||
return CryptoHelper.AesInvMixColumns(value);
|
return CryptoHelper.AesInvMixColumns(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 MixColumns(V128 value)
|
public static V128 MixColumns(V128 value)
|
||||||
{
|
{
|
||||||
return CryptoHelper.AesMixColumns(value);
|
return CryptoHelper.AesMixColumns(value);
|
||||||
@@ -545,11 +413,7 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Sha1"
|
#region "Sha1"
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
|
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
|
||||||
{
|
{
|
||||||
for (int e = 0; e <= 3; e++)
|
for (int e = 0; e <= 3; e++)
|
||||||
@@ -570,21 +434,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return hash_abcd;
|
return hash_abcd;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static uint FixedRotate(uint hash_e)
|
public static uint FixedRotate(uint hash_e)
|
||||||
{
|
{
|
||||||
return hash_e.Rol(30);
|
return hash_e.Rol(30);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
|
public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
|
||||||
{
|
{
|
||||||
for (int e = 0; e <= 3; e++)
|
for (int e = 0; e <= 3; e++)
|
||||||
@@ -605,11 +461,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return hash_abcd;
|
return hash_abcd;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
|
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
|
||||||
{
|
{
|
||||||
for (int e = 0; e <= 3; e++)
|
for (int e = 0; e <= 3; e++)
|
||||||
@@ -630,11 +482,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return hash_abcd;
|
return hash_abcd;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
|
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
|
||||||
{
|
{
|
||||||
ulong t2 = w4_7.Extract<ulong>(0);
|
ulong t2 = w4_7.Extract<ulong>(0);
|
||||||
@@ -645,11 +493,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result ^ (w0_3 ^ w8_11);
|
return result ^ (w0_3 ^ w8_11);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
|
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
|
||||||
{
|
{
|
||||||
V128 t = tw0_3 ^ (w12_15 >> 32);
|
V128 t = tw0_3 ^ (w12_15 >> 32);
|
||||||
@@ -694,31 +538,19 @@ namespace ARMeilleure.Instructions
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Sha256"
|
#region "Sha256"
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
||||||
{
|
{
|
||||||
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
|
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
||||||
{
|
{
|
||||||
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
|
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
|
public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
|
||||||
{
|
{
|
||||||
V128 result = new();
|
V128 result = new();
|
||||||
@@ -737,11 +569,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
|
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
|
||||||
{
|
{
|
||||||
V128 result = new();
|
V128 result = new();
|
||||||
@@ -843,11 +671,7 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static V128 PolynomialMult64_128(ulong op1, ulong op2)
|
public static V128 PolynomialMult64_128(ulong op1, ulong op2)
|
||||||
{
|
{
|
||||||
V128 result = V128.Zero;
|
V128 result = V128.Zero;
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
#if ANDROID
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
#else
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
@@ -317,11 +313,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
static class SoftFloat16_32
|
static class SoftFloat16_32
|
||||||
{
|
{
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPConvert(ushort valueBits)
|
public static float FPConvert(ushort valueBits)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -497,11 +489,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
static class SoftFloat16_64
|
static class SoftFloat16_64
|
||||||
{
|
{
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPConvert(ushort valueBits)
|
public static double FPConvert(ushort valueBits)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -677,11 +665,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
static class SoftFloat32_16
|
static class SoftFloat32_16
|
||||||
{
|
{
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static ushort FPConvert(float value)
|
public static ushort FPConvert(float value)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -801,21 +785,13 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
static class SoftFloat32
|
static class SoftFloat32
|
||||||
{
|
{
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPAdd(float value1, float value2)
|
public static float FPAdd(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPAddFpscrImpl(value1, value2, false);
|
return FPAddFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPAddFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPAddFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -872,11 +848,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static int FPCompare(float value1, float value2, byte signalNaNs)
|
public static int FPCompare(float value1, float value2, byte signalNaNs)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -915,11 +887,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPCompareEQ(float value1, float value2)
|
public static float FPCompareEQ(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPCompareEQFpscrImpl(value1, value2, false);
|
return FPCompareEQFpscrImpl(value1, value2, false);
|
||||||
@@ -952,31 +920,19 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPCompareEQFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPCompareEQFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPCompareGE(float value1, float value2)
|
public static float FPCompareGE(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value1, value2, false);
|
return FPCompareGEFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPCompareGEFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPCompareGEFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -1006,21 +962,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPCompareGT(float value1, float value2)
|
public static float FPCompareGT(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPCompareGTFpscrImpl(value1, value2, false);
|
return FPCompareGTFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPCompareGTFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPCompareGTFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -1050,51 +998,31 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPCompareLE(float value1, float value2)
|
public static float FPCompareLE(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value2, value1, false);
|
return FPCompareGEFpscrImpl(value2, value1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPCompareLT(float value1, float value2)
|
public static float FPCompareLT(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPCompareGTFpscrImpl(value2, value1, false);
|
return FPCompareGTFpscrImpl(value2, value1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPCompareLEFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPCompareLEFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPCompareLTFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPCompareLTFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPDiv(float value1, float value2)
|
public static float FPDiv(float value1, float value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -1147,21 +1075,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPMax(float value1, float value2)
|
public static float FPMax(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPMaxFpscrImpl(value1, value2, false);
|
return FPMaxFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPMaxFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPMaxFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -1228,11 +1148,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPMaxNum(float value1, float value2)
|
public static float FPMaxNum(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPMaxNumFpscrImpl(value1, value2, false);
|
return FPMaxNumFpscrImpl(value1, value2, false);
|
||||||
@@ -1258,31 +1174,19 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMaxFpscrImpl(value1, value2, standardFpscr);
|
return FPMaxFpscrImpl(value1, value2, standardFpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPMaxNumFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPMaxNumFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPMin(float value1, float value2)
|
public static float FPMin(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPMinFpscrImpl(value1, value2, false);
|
return FPMinFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPMinFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPMinFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -1349,21 +1253,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPMinNum(float value1, float value2)
|
public static float FPMinNum(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPMinNumFpscrImpl(value1, value2, false);
|
return FPMinNumFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPMinNumFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPMinNumFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -1389,21 +1285,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMinFpscrImpl(value1, value2, standardFpscr);
|
return FPMinFpscrImpl(value1, value2, standardFpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPMul(float value1, float value2)
|
public static float FPMul(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPMulFpscrImpl(value1, value2, false);
|
return FPMulFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPMulFpscr(float value1, float value2, byte standardFpscr)
|
public static float FPMulFpscr(float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -1456,21 +1344,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPMulAdd(float valueA, float value1, float value2)
|
public static float FPMulAdd(float valueA, float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPMulAddFpscr(float valueA, float value1, float value2, byte standardFpscr)
|
public static float FPMulAddFpscr(float valueA, float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||||
@@ -1542,11 +1422,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPMulSub(float valueA, float value1, float value2)
|
public static float FPMulSub(float valueA, float value1, float value2)
|
||||||
{
|
{
|
||||||
value1 = value1.FPNeg();
|
value1 = value1.FPNeg();
|
||||||
@@ -1554,11 +1430,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPMulSubFpscr(float valueA, float value1, float value2, byte standardFpscr)
|
public static float FPMulSubFpscr(float valueA, float value1, float value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
value1 = value1.FPNeg();
|
value1 = value1.FPNeg();
|
||||||
@@ -1566,11 +1438,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPMulX(float value1, float value2)
|
public static float FPMulX(float value1, float value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -1616,11 +1484,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPNegMulAdd(float valueA, float value1, float value2)
|
public static float FPNegMulAdd(float valueA, float value1, float value2)
|
||||||
{
|
{
|
||||||
valueA = valueA.FPNeg();
|
valueA = valueA.FPNeg();
|
||||||
@@ -1629,11 +1493,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPNegMulSub(float valueA, float value1, float value2)
|
public static float FPNegMulSub(float valueA, float value1, float value2)
|
||||||
{
|
{
|
||||||
valueA = valueA.FPNeg();
|
valueA = valueA.FPNeg();
|
||||||
@@ -1641,21 +1501,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPRecipEstimate(float value)
|
public static float FPRecipEstimate(float value)
|
||||||
{
|
{
|
||||||
return FPRecipEstimateFpscrImpl(value, false);
|
return FPRecipEstimateFpscrImpl(value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPRecipEstimateFpscr(float value, byte standardFpscr)
|
public static float FPRecipEstimateFpscr(float value, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
|
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
|
||||||
@@ -1748,11 +1600,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPRecipStep(float value1, float value2)
|
public static float FPRecipStep(float value1, float value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -1787,11 +1635,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPRecipStepFused(float value1, float value2)
|
public static float FPRecipStepFused(float value1, float value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -1835,11 +1679,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPRecpX(float value)
|
public static float FPRecpX(float value)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -1865,21 +1705,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPRSqrtEstimate(float value)
|
public static float FPRSqrtEstimate(float value)
|
||||||
{
|
{
|
||||||
return FPRSqrtEstimateFpscrImpl(value, false);
|
return FPRSqrtEstimateFpscrImpl(value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPRSqrtEstimateFpscr(float value, byte standardFpscr)
|
public static float FPRSqrtEstimateFpscr(float value, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
|
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
|
||||||
@@ -1999,11 +1831,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPRSqrtStep(float value1, float value2)
|
public static float FPRSqrtStep(float value1, float value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -2038,11 +1866,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPRSqrtStepFused(float value1, float value2)
|
public static float FPRSqrtStepFused(float value1, float value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -2086,11 +1910,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPSqrt(float value)
|
public static float FPSqrt(float value)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -2133,11 +1953,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static float FPSub(float value1, float value2)
|
public static float FPSub(float value1, float value2)
|
||||||
{
|
{
|
||||||
return FPSubFpscrImpl(value1, value2, false);
|
return FPSubFpscrImpl(value1, value2, false);
|
||||||
@@ -2384,11 +2200,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
static class SoftFloat64_16
|
static class SoftFloat64_16
|
||||||
{
|
{
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static ushort FPConvert(double value)
|
public static ushort FPConvert(double value)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -2508,21 +2320,13 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
static class SoftFloat64
|
static class SoftFloat64
|
||||||
{
|
{
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPAdd(double value1, double value2)
|
public static double FPAdd(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPAddFpscrImpl(value1, value2, false);
|
return FPAddFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPAddFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPAddFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -2579,11 +2383,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static int FPCompare(double value1, double value2, byte signalNaNs)
|
public static int FPCompare(double value1, double value2, byte signalNaNs)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -2622,21 +2422,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPCompareEQ(double value1, double value2)
|
public static double FPCompareEQ(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPCompareEQFpscrImpl(value1, value2, false);
|
return FPCompareEQFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPCompareEQFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPCompareEQFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -2669,21 +2461,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPCompareGE(double value1, double value2)
|
public static double FPCompareGE(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value1, value2, false);
|
return FPCompareGEFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPCompareGEFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPCompareGEFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -2713,21 +2497,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPCompareGT(double value1, double value2)
|
public static double FPCompareGT(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPCompareGTFpscrImpl(value1, value2, false);
|
return FPCompareGTFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPCompareGTFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPCompareGTFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -2757,51 +2533,31 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPCompareLE(double value1, double value2)
|
public static double FPCompareLE(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value2, value1, false);
|
return FPCompareGEFpscrImpl(value2, value1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPCompareLT(double value1, double value2)
|
public static double FPCompareLT(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPCompareGTFpscrImpl(value2, value1, false);
|
return FPCompareGTFpscrImpl(value2, value1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPCompareLEFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPCompareLEFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPCompareLTFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPCompareLTFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPCompareGTFpscrImpl(value2, value1, standardFpscr == 1);
|
return FPCompareGTFpscrImpl(value2, value1, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPDiv(double value1, double value2)
|
public static double FPDiv(double value1, double value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -2854,21 +2610,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPMax(double value1, double value2)
|
public static double FPMax(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPMaxFpscrImpl(value1, value2, false);
|
return FPMaxFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPMaxFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPMaxFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -2935,21 +2683,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPMaxNum(double value1, double value2)
|
public static double FPMaxNum(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPMaxNumFpscrImpl(value1, value2, false);
|
return FPMaxNumFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPMaxNumFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPMaxNumFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -2975,21 +2715,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMaxFpscrImpl(value1, value2, standardFpscr);
|
return FPMaxFpscrImpl(value1, value2, standardFpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPMin(double value1, double value2)
|
public static double FPMin(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPMinFpscrImpl(value1, value2, false);
|
return FPMinFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPMinFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPMinFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -3056,21 +2788,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPMinNum(double value1, double value2)
|
public static double FPMinNum(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPMinNumFpscrImpl(value1, value2, false);
|
return FPMinNumFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPMinNumFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPMinNumFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -3096,21 +2820,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMinFpscrImpl(value1, value2, standardFpscr);
|
return FPMinFpscrImpl(value1, value2, standardFpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPMul(double value1, double value2)
|
public static double FPMul(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPMulFpscrImpl(value1, value2, false);
|
return FPMulFpscrImpl(value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPMulFpscr(double value1, double value2, byte standardFpscr)
|
public static double FPMulFpscr(double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
|
return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
|
||||||
@@ -3163,21 +2879,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPMulAdd(double valueA, double value1, double value2)
|
public static double FPMulAdd(double valueA, double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPMulAddFpscr(double valueA, double value1, double value2, byte standardFpscr)
|
public static double FPMulAddFpscr(double valueA, double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||||
@@ -3249,11 +2957,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPMulSub(double valueA, double value1, double value2)
|
public static double FPMulSub(double valueA, double value1, double value2)
|
||||||
{
|
{
|
||||||
value1 = value1.FPNeg();
|
value1 = value1.FPNeg();
|
||||||
@@ -3261,11 +2965,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPMulSubFpscr(double valueA, double value1, double value2, byte standardFpscr)
|
public static double FPMulSubFpscr(double valueA, double value1, double value2, byte standardFpscr)
|
||||||
{
|
{
|
||||||
value1 = value1.FPNeg();
|
value1 = value1.FPNeg();
|
||||||
@@ -3273,11 +2973,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPMulX(double value1, double value2)
|
public static double FPMulX(double value1, double value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -3323,11 +3019,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPNegMulAdd(double valueA, double value1, double value2)
|
public static double FPNegMulAdd(double valueA, double value1, double value2)
|
||||||
{
|
{
|
||||||
valueA = valueA.FPNeg();
|
valueA = valueA.FPNeg();
|
||||||
@@ -3336,11 +3028,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPNegMulSub(double valueA, double value1, double value2)
|
public static double FPNegMulSub(double valueA, double value1, double value2)
|
||||||
{
|
{
|
||||||
valueA = valueA.FPNeg();
|
valueA = valueA.FPNeg();
|
||||||
@@ -3348,21 +3036,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
return FPMulAddFpscrImpl(valueA, value1, value2, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPRecipEstimate(double value)
|
public static double FPRecipEstimate(double value)
|
||||||
{
|
{
|
||||||
return FPRecipEstimateFpscrImpl(value, false);
|
return FPRecipEstimateFpscrImpl(value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPRecipEstimateFpscr(double value, byte standardFpscr)
|
public static double FPRecipEstimateFpscr(double value, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
|
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
|
||||||
@@ -3455,11 +3135,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPRecipStep(double value1, double value2)
|
public static double FPRecipStep(double value1, double value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -3494,11 +3170,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPRecipStepFused(double value1, double value2)
|
public static double FPRecipStepFused(double value1, double value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -3542,11 +3214,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPRecpX(double value)
|
public static double FPRecpX(double value)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -3572,21 +3240,13 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPRSqrtEstimate(double value)
|
public static double FPRSqrtEstimate(double value)
|
||||||
{
|
{
|
||||||
return FPRSqrtEstimateFpscrImpl(value, false);
|
return FPRSqrtEstimateFpscrImpl(value, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPRSqrtEstimateFpscr(double value, byte standardFpscr)
|
public static double FPRSqrtEstimateFpscr(double value, byte standardFpscr)
|
||||||
{
|
{
|
||||||
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
|
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
|
||||||
@@ -3706,11 +3366,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPRSqrtStep(double value1, double value2)
|
public static double FPRSqrtStep(double value1, double value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -3745,11 +3401,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPRSqrtStepFused(double value1, double value2)
|
public static double FPRSqrtStepFused(double value1, double value2)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -3793,11 +3445,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPSqrt(double value)
|
public static double FPSqrt(double value)
|
||||||
{
|
{
|
||||||
ExecutionContext context = NativeInterface.GetContext();
|
ExecutionContext context = NativeInterface.GetContext();
|
||||||
@@ -3840,11 +3488,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
#else
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
#endif
|
|
||||||
public static double FPSub(double value1, double value2)
|
public static double FPSub(double value1, double value2)
|
||||||
{
|
{
|
||||||
return FPSubFpscr(value1, value2, false);
|
return FPSubFpscr(value1, value2, false);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using System;
|
|||||||
|
|
||||||
namespace ARMeilleure.Memory
|
namespace ARMeilleure.Memory
|
||||||
{
|
{
|
||||||
public class ReservedRegion
|
public class ReservedRegion : IDisposable
|
||||||
{
|
{
|
||||||
public const int DefaultGranularity = 65536; // Mapping granularity in Windows.
|
public const int DefaultGranularity = 65536; // Mapping granularity in Windows.
|
||||||
|
|
||||||
|
|||||||
@@ -8,13 +8,11 @@ namespace ARMeilleure
|
|||||||
// low-core count PPTC
|
// low-core count PPTC
|
||||||
public static bool EcoFriendly { get; set; } = false;
|
public static bool EcoFriendly { get; set; } = false;
|
||||||
|
|
||||||
// Jit cache eviction
|
|
||||||
public static bool CacheEviction { get; set; } = false;
|
|
||||||
|
|
||||||
public static bool FastFP { get; set; } = true;
|
public static bool FastFP { get; set; } = true;
|
||||||
|
|
||||||
public static bool AllowLcqInFunctionTable { get; set; } = true;
|
public static bool AllowLcqInFunctionTable { get; set; } = true;
|
||||||
public static bool UseUnmanagedDispatchLoop { get; set; } = true;
|
public static bool UseUnmanagedDispatchLoop { get; set; } = true;
|
||||||
|
public static bool EnableDebugging { get; set; } = false;
|
||||||
public static bool EnableDeepCallRecursionProtection { get; set; } = true;
|
public static bool EnableDeepCallRecursionProtection { get; set; } = true;
|
||||||
|
|
||||||
public static bool UseAdvSimdIfAvailable { get; set; } = true;
|
public static bool UseAdvSimdIfAvailable { get; set; } = true;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace ARMeilleure.Signal
|
|||||||
{
|
{
|
||||||
public static class NativeSignalHandlerGenerator
|
public static class NativeSignalHandlerGenerator
|
||||||
{
|
{
|
||||||
public const int MaxTrackedRanges = 8;
|
public const int MaxTrackedRanges = 16;
|
||||||
|
|
||||||
private const int StructAddressOffset = 0;
|
private const int StructAddressOffset = 0;
|
||||||
private const int StructWriteOffset = 4;
|
private const int StructWriteOffset = 4;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
|
using ARMeilleure.Translation.Cache;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ namespace ARMeilleure.Signal
|
|||||||
public delegate int DebugThreadLocalMapGetOrReserve(int threadId, int initialState);
|
public delegate int DebugThreadLocalMapGetOrReserve(int threadId, int initialState);
|
||||||
public delegate void DebugNativeWriteLoop(nint nativeWriteLoopPtr, nint writePtr);
|
public delegate void DebugNativeWriteLoop(nint nativeWriteLoopPtr, nint writePtr);
|
||||||
|
|
||||||
public static DebugPartialUnmap GenerateDebugPartialUnmap()
|
public static DebugPartialUnmap GenerateDebugPartialUnmap(JitCache jitCache)
|
||||||
{
|
{
|
||||||
EmitterContext context = new();
|
EmitterContext context = new();
|
||||||
|
|
||||||
@@ -31,10 +32,10 @@ namespace ARMeilleure.Signal
|
|||||||
|
|
||||||
OperandType[] argTypes = [OperandType.I64];
|
OperandType[] argTypes = [OperandType.I64];
|
||||||
|
|
||||||
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DebugPartialUnmap>();
|
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DebugPartialUnmap>(jitCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DebugThreadLocalMapGetOrReserve GenerateDebugThreadLocalMapGetOrReserve(nint structPtr)
|
public static DebugThreadLocalMapGetOrReserve GenerateDebugThreadLocalMapGetOrReserve(JitCache jitCache, nint structPtr)
|
||||||
{
|
{
|
||||||
EmitterContext context = new();
|
EmitterContext context = new();
|
||||||
|
|
||||||
@@ -48,10 +49,10 @@ namespace ARMeilleure.Signal
|
|||||||
|
|
||||||
OperandType[] argTypes = [OperandType.I64];
|
OperandType[] argTypes = [OperandType.I64];
|
||||||
|
|
||||||
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DebugThreadLocalMapGetOrReserve>();
|
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DebugThreadLocalMapGetOrReserve>(jitCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DebugNativeWriteLoop GenerateDebugNativeWriteLoop()
|
public static DebugNativeWriteLoop GenerateDebugNativeWriteLoop(JitCache jitCache)
|
||||||
{
|
{
|
||||||
EmitterContext context = new();
|
EmitterContext context = new();
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ namespace ARMeilleure.Signal
|
|||||||
|
|
||||||
OperandType[] argTypes = [OperandType.I64];
|
OperandType[] argTypes = [OperandType.I64];
|
||||||
|
|
||||||
return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DebugNativeWriteLoop>();
|
return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DebugNativeWriteLoop>(jitCache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace ARMeilleure.State
|
namespace ARMeilleure.State
|
||||||
{
|
{
|
||||||
@@ -10,7 +11,7 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
internal nint NativeContextPtr => _nativeContext.BasePtr;
|
internal nint NativeContextPtr => _nativeContext.BasePtr;
|
||||||
|
|
||||||
private bool _interrupted;
|
internal bool Interrupted { get; private set; }
|
||||||
|
|
||||||
private readonly ICounter _counter;
|
private readonly ICounter _counter;
|
||||||
|
|
||||||
@@ -67,6 +68,8 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
public bool IsAarch32 { get; set; }
|
public bool IsAarch32 { get; set; }
|
||||||
|
|
||||||
|
public ulong ThreadUid { get; set; }
|
||||||
|
|
||||||
internal ExecutionMode ExecutionMode
|
internal ExecutionMode ExecutionMode
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -92,14 +95,19 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
||||||
private readonly ExceptionCallback _breakCallback;
|
private readonly ExceptionCallback _breakCallback;
|
||||||
|
private readonly ExceptionCallbackNoArgs _stepCallback;
|
||||||
private readonly ExceptionCallback _supervisorCallback;
|
private readonly ExceptionCallback _supervisorCallback;
|
||||||
private readonly ExceptionCallback _undefinedCallback;
|
private readonly ExceptionCallback _undefinedCallback;
|
||||||
|
|
||||||
|
internal int ShouldStep;
|
||||||
|
public ulong DebugPc { get; set; }
|
||||||
|
|
||||||
public ExecutionContext(
|
public ExecutionContext(
|
||||||
IJitMemoryAllocator allocator,
|
IJitMemoryAllocator allocator,
|
||||||
ICounter counter,
|
ICounter counter,
|
||||||
ExceptionCallbackNoArgs interruptCallback = null,
|
ExceptionCallbackNoArgs interruptCallback = null,
|
||||||
ExceptionCallback breakCallback = null,
|
ExceptionCallback breakCallback = null,
|
||||||
|
ExceptionCallbackNoArgs stepCallback = null,
|
||||||
ExceptionCallback supervisorCallback = null,
|
ExceptionCallback supervisorCallback = null,
|
||||||
ExceptionCallback undefinedCallback = null)
|
ExceptionCallback undefinedCallback = null)
|
||||||
{
|
{
|
||||||
@@ -107,6 +115,7 @@ namespace ARMeilleure.State
|
|||||||
_counter = counter;
|
_counter = counter;
|
||||||
_interruptCallback = interruptCallback;
|
_interruptCallback = interruptCallback;
|
||||||
_breakCallback = breakCallback;
|
_breakCallback = breakCallback;
|
||||||
|
_stepCallback = stepCallback;
|
||||||
_supervisorCallback = supervisorCallback;
|
_supervisorCallback = supervisorCallback;
|
||||||
_undefinedCallback = undefinedCallback;
|
_undefinedCallback = undefinedCallback;
|
||||||
|
|
||||||
@@ -134,9 +143,9 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
internal void CheckInterrupt()
|
internal void CheckInterrupt()
|
||||||
{
|
{
|
||||||
if (_interrupted)
|
if (Interrupted)
|
||||||
{
|
{
|
||||||
_interrupted = false;
|
Interrupted = false;
|
||||||
|
|
||||||
_interruptCallback?.Invoke(this);
|
_interruptCallback?.Invoke(this);
|
||||||
}
|
}
|
||||||
@@ -146,16 +155,37 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
public void RequestInterrupt()
|
public void RequestInterrupt()
|
||||||
{
|
{
|
||||||
_interrupted = true;
|
Interrupted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StepHandler()
|
||||||
|
{
|
||||||
|
_stepCallback?.Invoke(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RequestDebugStep()
|
||||||
|
{
|
||||||
|
Interlocked.Exchange(ref ShouldStep, 1);
|
||||||
|
RequestInterrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnBreak(ulong address, int imm)
|
internal void OnBreak(ulong address, int imm)
|
||||||
{
|
{
|
||||||
|
if (Optimizations.EnableDebugging)
|
||||||
|
{
|
||||||
|
DebugPc = Pc;
|
||||||
|
}
|
||||||
|
|
||||||
_breakCallback?.Invoke(this, address, imm);
|
_breakCallback?.Invoke(this, address, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnSupervisorCall(ulong address, int imm)
|
internal void OnSupervisorCall(ulong address, int imm)
|
||||||
{
|
{
|
||||||
|
if (Optimizations.EnableDebugging)
|
||||||
|
{
|
||||||
|
DebugPc = Pc;
|
||||||
|
}
|
||||||
|
|
||||||
_supervisorCallback?.Invoke(this, address, imm);
|
_supervisorCallback?.Invoke(this, address, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ namespace ARMeilleure.State
|
|||||||
public int Running;
|
public int Running;
|
||||||
public int CallDepth;
|
public int CallDepth;
|
||||||
public long Tpidr2El0;
|
public long Tpidr2El0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Precise PC value used for debugging.
|
||||||
|
/// This will only be set when Optimizations.EnableDebugging is true.
|
||||||
|
/// </summary>
|
||||||
|
public ulong DebugPrecisePc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static NativeCtxStorage _dummyStorage = new();
|
private static NativeCtxStorage _dummyStorage = new();
|
||||||
@@ -40,6 +46,11 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
public ulong GetPc()
|
public ulong GetPc()
|
||||||
{
|
{
|
||||||
|
if (Optimizations.EnableDebugging)
|
||||||
|
{
|
||||||
|
return GetStorage().DebugPrecisePc;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: More precise tracking of PC value.
|
// TODO: More precise tracking of PC value.
|
||||||
return GetStorage().DispatchAddress;
|
return GetStorage().DispatchAddress;
|
||||||
}
|
}
|
||||||
@@ -269,6 +280,11 @@ namespace ARMeilleure.State
|
|||||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Running);
|
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Running);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int GetDebugPrecisePcOffset()
|
||||||
|
{
|
||||||
|
return StorageOffset(ref _dummyStorage, ref _dummyStorage.DebugPrecisePc);
|
||||||
|
}
|
||||||
|
|
||||||
public static int GetCallDepthOffset()
|
public static int GetCallDepthOffset()
|
||||||
{
|
{
|
||||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.CallDepth);
|
return StorageOffset(ref _dummyStorage, ref _dummyStorage.CallDepth);
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ namespace ARMeilleure.Translation
|
|||||||
public bool HighCq { get; }
|
public bool HighCq { get; }
|
||||||
public bool HasPtc { get; }
|
public bool HasPtc { get; }
|
||||||
public Aarch32Mode Mode { get; }
|
public Aarch32Mode Mode { get; }
|
||||||
|
public bool IsSingleStep { get; }
|
||||||
|
|
||||||
private int _ifThenBlockStateIndex = 0;
|
private int _ifThenBlockStateIndex = 0;
|
||||||
private Condition[] _ifThenBlockState = [];
|
private Condition[] _ifThenBlockState = [];
|
||||||
@@ -66,7 +67,8 @@ namespace ARMeilleure.Translation
|
|||||||
ulong entryAddress,
|
ulong entryAddress,
|
||||||
bool highCq,
|
bool highCq,
|
||||||
bool hasPtc,
|
bool hasPtc,
|
||||||
Aarch32Mode mode)
|
Aarch32Mode mode,
|
||||||
|
bool isSingleStep)
|
||||||
{
|
{
|
||||||
Memory = memory;
|
Memory = memory;
|
||||||
CountTable = countTable;
|
CountTable = countTable;
|
||||||
@@ -76,6 +78,7 @@ namespace ARMeilleure.Translation
|
|||||||
HighCq = highCq;
|
HighCq = highCq;
|
||||||
HasPtc = hasPtc;
|
HasPtc = hasPtc;
|
||||||
Mode = mode;
|
Mode = mode;
|
||||||
|
IsSingleStep = isSingleStep;
|
||||||
|
|
||||||
_labels = new Dictionary<ulong, Operand>();
|
_labels = new Dictionary<ulong, Operand>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
|
|
||||||
namespace ARMeilleure.Translation.Cache
|
namespace ARMeilleure.Translation.Cache
|
||||||
{
|
{
|
||||||
readonly struct CacheEntry : IComparable<CacheEntry>
|
public readonly struct CacheEntry : IComparable<CacheEntry>
|
||||||
{
|
{
|
||||||
public int Offset { get; }
|
public int Offset { get; }
|
||||||
public int Size { get; }
|
public int Size { get; }
|
||||||
|
|||||||
@@ -23,11 +23,30 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly int _regionSize;
|
||||||
|
private int _regionCount;
|
||||||
|
|
||||||
private readonly List<MemoryBlock> _blocks = [];
|
private readonly List<MemoryBlock> _blocks = [];
|
||||||
|
|
||||||
public CacheMemoryAllocator(int capacity)
|
public CacheMemoryAllocator(int regionSize, int initialRegionCount = 1)
|
||||||
{
|
{
|
||||||
_blocks.Add(new MemoryBlock(0, capacity));
|
_regionCount = 0;
|
||||||
|
_regionSize = regionSize;
|
||||||
|
|
||||||
|
for (; initialRegionCount > 0; initialRegionCount--)
|
||||||
|
{
|
||||||
|
_blocks.Add(new MemoryBlock(_regionSize * _regionCount, _regionSize));
|
||||||
|
_regionCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddNewBlocks(int count)
|
||||||
|
{
|
||||||
|
for (; count > 0; count--)
|
||||||
|
{
|
||||||
|
_blocks.Add(new MemoryBlock(_regionSize * _regionCount, _regionSize));
|
||||||
|
_regionCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Allocate(int size)
|
public int Allocate(int size)
|
||||||
@@ -66,12 +85,13 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
index = ~index;
|
index = ~index;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index < _blocks.Count)
|
int endOffs = block.Offset + block.Size;
|
||||||
|
|
||||||
|
// Don't merge blocks from different allocations
|
||||||
|
if (index < _blocks.Count && endOffs % _regionSize != 0)
|
||||||
{
|
{
|
||||||
MemoryBlock next = _blocks[index];
|
MemoryBlock next = _blocks[index];
|
||||||
|
|
||||||
int endOffs = block.Offset + block.Size;
|
|
||||||
|
|
||||||
if (next.Offset == endOffs)
|
if (next.Offset == endOffs)
|
||||||
{
|
{
|
||||||
block = new MemoryBlock(block.Offset, block.Size + next.Size);
|
block = new MemoryBlock(block.Offset, block.Size + next.Size);
|
||||||
@@ -79,7 +99,8 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index > 0)
|
// Don't merge blocks from different allocations
|
||||||
|
if (index > 0 && block.Offset % _regionSize != 0)
|
||||||
{
|
{
|
||||||
MemoryBlock prev = _blocks[index - 1];
|
MemoryBlock prev = _blocks[index - 1];
|
||||||
|
|
||||||
|
|||||||
@@ -2,140 +2,70 @@ using ARMeilleure.CodeGen;
|
|||||||
using ARMeilleure.CodeGen.Unwinding;
|
using ARMeilleure.CodeGen.Unwinding;
|
||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using ARMeilleure.Native;
|
using ARMeilleure.Native;
|
||||||
|
using Humanizer;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace ARMeilleure.Translation.Cache
|
namespace ARMeilleure.Translation.Cache
|
||||||
{
|
{
|
||||||
static partial class JitCache
|
public partial class JitCache : IDisposable
|
||||||
{
|
{
|
||||||
private static readonly int _pageSize = (int)MemoryBlock.GetPageSize();
|
private static readonly int _pageSize = (int)MemoryBlock.GetPageSize();
|
||||||
private static readonly int _pageMask = _pageSize - 1;
|
private static readonly int _pageMask = _pageSize - 1;
|
||||||
|
|
||||||
private const int CodeAlignment = 4;
|
private const int CodeAlignment = 4; // Bytes.
|
||||||
private const int FullCacheSize = 2047 * 1024 * 1024;
|
private const uint CacheSize = 256 * 1024 * 1024;
|
||||||
private const int ReducedCacheSize = FullCacheSize / 8;
|
|
||||||
|
|
||||||
private const float EvictionTargetPercentage = 0.20f;
|
private readonly JitCacheInvalidation _jitCacheInvalidator;
|
||||||
private const int MaxEntriesToEvictAtOnce = 100;
|
|
||||||
|
|
||||||
// Simple logging configuration
|
private readonly CacheMemoryAllocator _cacheAllocator;
|
||||||
private const int LogInterval = 5000; // Log every 5000 allocations
|
|
||||||
|
|
||||||
private static ReservedRegion _jitRegion;
|
private readonly List<CacheEntry> _cacheEntries = [];
|
||||||
private static JitCacheInvalidation _jitCacheInvalidator;
|
|
||||||
|
|
||||||
private static CacheMemoryAllocator _cacheAllocator;
|
private readonly Lock _lock = new();
|
||||||
|
|
||||||
private static readonly List<CacheEntry> _cacheEntries = [];
|
private readonly List<ReservedRegion> _jitRegions = [];
|
||||||
private static readonly Dictionary<int, EntryUsageStats> _entryUsageStats = [];
|
|
||||||
|
|
||||||
private static readonly Lock _lock = new();
|
|
||||||
private static bool _initialized;
|
|
||||||
private static int _cacheSize;
|
|
||||||
|
|
||||||
// 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")]
|
[SupportedOSPlatform("windows")]
|
||||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||||
public static partial nint FlushInstructionCache(nint hProcess, nint lpAddress, nuint dwSize);
|
private static partial nint FlushInstructionCache(nint hProcess, nint lpAddress, nuint dwSize);
|
||||||
|
|
||||||
public static void Initialize(IJitMemoryAllocator allocator)
|
public JitCache(IJitMemoryAllocator allocator)
|
||||||
{
|
{
|
||||||
if (_initialized)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (_initialized)
|
_jitRegions.Add(new(allocator, CacheSize));
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_cacheSize = Optimizations.CacheEviction ? ReducedCacheSize : FullCacheSize;
|
_cacheAllocator = new((int)CacheSize);
|
||||||
_jitRegion = new ReservedRegion(allocator, (ulong)_cacheSize);
|
|
||||||
|
|
||||||
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
|
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
_jitCacheInvalidator = new JitCacheInvalidation(allocator);
|
_jitCacheInvalidator = new JitCacheInvalidation(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
_cacheAllocator = new CacheMemoryAllocator(_cacheSize);
|
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
JitUnwindWindows.InstallFunctionTableHandler(_jitRegion.Pointer, (uint)_cacheSize, _jitRegion.Pointer + Allocate(_pageSize));
|
JitUnwindWindows.InstallFunctionTableHandler(
|
||||||
|
this, _jitRegions[0].Pointer, CacheSize, _jitRegions[0].Pointer + Allocate(_pageSize)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Cpu, $"JIT Cache initialized: Size={_cacheSize / (1024 * 1024)} MB, Eviction={Optimizations.CacheEviction}");
|
|
||||||
_initialized = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static nint Map(CompiledFunction func)
|
public nint Map(CompiledFunction func)
|
||||||
{
|
{
|
||||||
byte[] code = func.Code;
|
byte[] code = func.Code;
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
Debug.Assert(_initialized);
|
int funcOffset = Allocate(code.Length);
|
||||||
_totalAllocations++;
|
nint funcPtr = GetFunctionPtr(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)
|
if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
|
||||||
{
|
{
|
||||||
@@ -165,79 +95,104 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
|
|
||||||
Add(funcOffset, code.Length, func.UnwindInfo);
|
Add(funcOffset, code.Length, func.UnwindInfo);
|
||||||
|
|
||||||
// Simple periodic logging
|
|
||||||
if (_totalAllocations % LogInterval == 0)
|
|
||||||
{
|
|
||||||
LogCacheStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
return funcPtr;
|
return funcPtr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Unmap(nint pointer)
|
public void Unmap(nint pointer)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
Debug.Assert(_initialized);
|
for (int i = 0; i < _jitRegions.Count; i++)
|
||||||
|
|
||||||
int funcOffset = (int)(pointer.ToInt64() - _jitRegion.Pointer.ToInt64());
|
|
||||||
|
|
||||||
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
|
|
||||||
{
|
{
|
||||||
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
|
ReservedRegion jitRegion = _jitRegions[i];
|
||||||
_cacheEntries.RemoveAt(entryIndex);
|
if (pointer.ToInt64() < jitRegion.Pointer.ToInt64() ||
|
||||||
|
pointer.ToInt64() >= (jitRegion.Pointer + (nint)CacheSize).ToInt64())
|
||||||
if (Optimizations.CacheEviction)
|
|
||||||
{
|
{
|
||||||
_entryUsageStats.Remove(funcOffset);
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int funcOffset = (int)(pointer.ToInt64() - jitRegion.Pointer.ToInt64() + i * CacheSize);
|
||||||
|
|
||||||
|
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
|
||||||
|
{
|
||||||
|
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
|
||||||
|
_cacheEntries.RemoveAt(entryIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReprotectAsWritable(int offset, int size)
|
private void ReprotectAsWritable(int offset, int size)
|
||||||
{
|
{
|
||||||
int endOffs = offset + size;
|
int endOffs = offset + size;
|
||||||
|
int regionStart = (offset % (int)CacheSize) & ~_pageMask;
|
||||||
int regionStart = offset & ~_pageMask;
|
int regionEnd = endOffs % (int)CacheSize == 0
|
||||||
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
|
? (((int)CacheSize) + _pageMask) & ~_pageMask
|
||||||
|
: ((endOffs % (int)CacheSize) + _pageMask) & ~_pageMask;
|
||||||
_jitRegion.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
GetRegion(offset).Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReprotectAsExecutable(int offset, int size)
|
private void ReprotectAsExecutable(int offset, int size)
|
||||||
{
|
{
|
||||||
int endOffs = offset + size;
|
int endOffs = offset + size;
|
||||||
|
int regionStart = (offset % (int)CacheSize) & ~_pageMask;
|
||||||
|
int regionEnd = endOffs % (int)CacheSize == 0
|
||||||
|
? (((int)CacheSize) + _pageMask) & ~_pageMask
|
||||||
|
: ((endOffs % (int)CacheSize) + _pageMask) & ~_pageMask;
|
||||||
|
|
||||||
int regionStart = offset & ~_pageMask;
|
GetRegion(offset).Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||||
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
|
|
||||||
|
|
||||||
_jitRegion.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int Allocate(int codeSize)
|
private int Allocate(int codeSize)
|
||||||
{
|
{
|
||||||
codeSize = AlignCodeSize(codeSize);
|
codeSize = AlignCodeSize(codeSize);
|
||||||
|
|
||||||
int allocOffset = _cacheAllocator.Allocate(codeSize);
|
int allocOffset = _cacheAllocator.Allocate(codeSize);
|
||||||
|
|
||||||
if (allocOffset < 0)
|
if (allocOffset >= 0)
|
||||||
{
|
{
|
||||||
throw new OutOfMemoryException("JIT Cache exhausted.");
|
GetRegion(allocOffset).ExpandIfNeeded((ulong)(allocOffset % (int)CacheSize) + (ulong)codeSize);
|
||||||
|
return allocOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
_jitRegion.ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
|
_cacheAllocator.AddNewBlocks(1);
|
||||||
|
ReservedRegion newRegion = new(_jitRegions[0].Allocator, CacheSize);
|
||||||
|
|
||||||
|
Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache of size {(_jitRegions.Count * CacheSize).Bytes()} exhausted, creating new Cache Region ({((_jitRegions.Count + 1) * CacheSize).Bytes()} Total Allocation).");
|
||||||
|
|
||||||
|
_jitRegions.Add(newRegion);
|
||||||
|
|
||||||
|
allocOffset = _cacheAllocator.Allocate(codeSize);
|
||||||
|
if (allocOffset < 0)
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException("Failed to allocate in new Cache Region!");
|
||||||
|
}
|
||||||
|
|
||||||
|
GetRegion(allocOffset).ExpandIfNeeded((ulong)(allocOffset % (int)CacheSize) + (ulong)codeSize);
|
||||||
return allocOffset;
|
return allocOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private nint GetFunctionPtr(int offset)
|
||||||
|
{
|
||||||
|
return GetRegion(offset).Pointer + (offset % (int)CacheSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReservedRegion GetRegion(int offset)
|
||||||
|
{
|
||||||
|
int index = offset / (int)CacheSize;
|
||||||
|
|
||||||
|
return _jitRegions[index];
|
||||||
|
}
|
||||||
|
|
||||||
private static int AlignCodeSize(int codeSize)
|
private static int AlignCodeSize(int codeSize)
|
||||||
{
|
{
|
||||||
return checked(codeSize + (CodeAlignment - 1)) & ~(CodeAlignment - 1);
|
return checked(codeSize + (CodeAlignment - 1)) & ~(CodeAlignment - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Add(int offset, int size, UnwindInfo unwindInfo)
|
private void Add(int offset, int size, UnwindInfo unwindInfo)
|
||||||
{
|
{
|
||||||
CacheEntry entry = new(offset, size, unwindInfo);
|
CacheEntry entry = new(offset, size, unwindInfo);
|
||||||
|
|
||||||
@@ -249,14 +204,9 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
}
|
}
|
||||||
|
|
||||||
_cacheEntries.Insert(index, entry);
|
_cacheEntries.Insert(index, entry);
|
||||||
|
|
||||||
if (Optimizations.CacheEviction)
|
|
||||||
{
|
|
||||||
_entryUsageStats[offset] = new EntryUsageStats();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryFind(int offset, out CacheEntry entry, out int entryIndex)
|
public bool TryFind(int offset, out CacheEntry entry, out int entryIndex)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
@@ -270,12 +220,6 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
{
|
{
|
||||||
entry = _cacheEntries[index];
|
entry = _cacheEntries[index];
|
||||||
|
|
||||||
if (Optimizations.CacheEviction && _entryUsageStats.TryGetValue(offset, out EntryUsageStats stats))
|
|
||||||
{
|
|
||||||
stats.UpdateUsage();
|
|
||||||
}
|
|
||||||
|
|
||||||
entryIndex = index;
|
entryIndex = index;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -286,82 +230,17 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EvictEntries(int requiredSize)
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (!Optimizations.CacheEviction)
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
return;
|
JitUnwindWindows.RemoveFunctionTableHandler(_jitRegions[0].Pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
lock (_lock)
|
foreach (ReservedRegion jitRegion in _jitRegions)
|
||||||
{
|
{
|
||||||
int targetSpace = Math.Max(requiredSize, (int)(_cacheSize * EvictionTargetPercentage));
|
jitRegion.Dispose();
|
||||||
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}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
using ARMeilleure.CodeGen.Unwinding;
|
using ARMeilleure.CodeGen.Unwinding;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
@@ -27,6 +29,29 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
public unsafe fixed ushort UnwindCodes[MaxUnwindCodesArraySize];
|
public unsafe fixed ushort UnwindCodes[MaxUnwindCodesArraySize];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private unsafe struct InternalFunctionHandler
|
||||||
|
{
|
||||||
|
public InternalFunctionHandler(JitCache jitCache, nint workBufferPtr)
|
||||||
|
{
|
||||||
|
_jitCache = jitCache;
|
||||||
|
|
||||||
|
_runtimeFunction = (RuntimeFunction*)workBufferPtr;
|
||||||
|
|
||||||
|
_unwindInfo = (UnwindInfo*)(workBufferPtr + _sizeOfRuntimeFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly JitCache _jitCache;
|
||||||
|
|
||||||
|
readonly RuntimeFunction* _runtimeFunction;
|
||||||
|
|
||||||
|
readonly UnwindInfo* _unwindInfo;
|
||||||
|
|
||||||
|
public RuntimeFunction* FunctionTableHandler(ulong controlPc, nint context)
|
||||||
|
{
|
||||||
|
return JitUnwindWindows.FunctionTableHandler(_jitCache, _runtimeFunction, _unwindInfo, controlPc, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private enum UnwindOp
|
private enum UnwindOp
|
||||||
{
|
{
|
||||||
PushNonvol = 0,
|
PushNonvol = 0,
|
||||||
@@ -59,27 +84,28 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
|
|
||||||
private static GetRuntimeFunctionCallback _getRuntimeFunctionCallback;
|
private static GetRuntimeFunctionCallback _getRuntimeFunctionCallback;
|
||||||
|
|
||||||
private static int _sizeOfRuntimeFunction;
|
private static readonly int _sizeOfRuntimeFunction;
|
||||||
|
|
||||||
private unsafe static RuntimeFunction* _runtimeFunction;
|
private static readonly ConcurrentDictionary<ulong, InternalFunctionHandler> _functionTableHandlers = new();
|
||||||
|
|
||||||
private unsafe static UnwindInfo* _unwindInfo;
|
static JitUnwindWindows()
|
||||||
|
{
|
||||||
|
_sizeOfRuntimeFunction = Marshal.SizeOf<RuntimeFunction>();
|
||||||
|
}
|
||||||
|
|
||||||
public static void InstallFunctionTableHandler(nint codeCachePointer, uint codeCacheLength, nint workBufferPtr)
|
public static void InstallFunctionTableHandler(JitCache jitCache, nint codeCachePointer, uint codeCacheLength, nint workBufferPtr)
|
||||||
{
|
{
|
||||||
ulong codeCachePtr = (ulong)codeCachePointer.ToInt64();
|
ulong codeCachePtr = (ulong)codeCachePointer.ToInt64();
|
||||||
|
|
||||||
_sizeOfRuntimeFunction = Marshal.SizeOf<RuntimeFunction>();
|
|
||||||
|
|
||||||
bool result;
|
bool result;
|
||||||
|
|
||||||
|
InternalFunctionHandler handler;
|
||||||
|
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
_runtimeFunction = (RuntimeFunction*)workBufferPtr;
|
handler = new InternalFunctionHandler(jitCache, workBufferPtr);
|
||||||
|
|
||||||
_unwindInfo = (UnwindInfo*)(workBufferPtr + _sizeOfRuntimeFunction);
|
_getRuntimeFunctionCallback = handler.FunctionTableHandler;
|
||||||
|
|
||||||
_getRuntimeFunctionCallback = new GetRuntimeFunctionCallback(FunctionTableHandler);
|
|
||||||
|
|
||||||
result = RtlInstallFunctionTableCallback(
|
result = RtlInstallFunctionTableCallback(
|
||||||
codeCachePtr | 3,
|
codeCachePtr | 3,
|
||||||
@@ -94,6 +120,8 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
{
|
{
|
||||||
throw new InvalidOperationException("Failure installing function table callback.");
|
throw new InvalidOperationException("Failure installing function table callback.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_functionTableHandlers.TryAdd(codeCachePtr, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RemoveFunctionTableHandler(nint codeCachePointer)
|
public static void RemoveFunctionTableHandler(nint codeCachePointer)
|
||||||
@@ -111,24 +139,26 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
{
|
{
|
||||||
throw new InvalidOperationException("Failure removing function table callback.");
|
throw new InvalidOperationException("Failure removing function table callback.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_functionTableHandlers.Remove(codeCachePtr, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, nint context)
|
private static unsafe RuntimeFunction* FunctionTableHandler(JitCache jitCache, RuntimeFunction* runtimeFunction, UnwindInfo* unwindInfo, ulong controlPc, nint context)
|
||||||
{
|
{
|
||||||
int offset = (int)((long)controlPc - context.ToInt64());
|
int offset = (int)((long)controlPc - context.ToInt64());
|
||||||
|
|
||||||
if (!JitCache.TryFind(offset, out CacheEntry funcEntry, out _))
|
if (!jitCache.TryFind(offset, out CacheEntry funcEntry, out _))
|
||||||
{
|
{
|
||||||
return null; // Not found.
|
return null; // Not found.
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeGen.Unwinding.UnwindInfo unwindInfo = funcEntry.UnwindInfo;
|
CodeGen.Unwinding.UnwindInfo funcUnwindInfo = funcEntry.UnwindInfo;
|
||||||
|
|
||||||
int codeIndex = 0;
|
int codeIndex = 0;
|
||||||
|
|
||||||
for (int index = unwindInfo.PushEntries.Length - 1; index >= 0; index--)
|
for (int index = funcUnwindInfo.PushEntries.Length - 1; index >= 0; index--)
|
||||||
{
|
{
|
||||||
UnwindPushEntry entry = unwindInfo.PushEntries[index];
|
UnwindPushEntry entry = funcUnwindInfo.PushEntries[index];
|
||||||
|
|
||||||
switch (entry.PseudoOp)
|
switch (entry.PseudoOp)
|
||||||
{
|
{
|
||||||
@@ -140,14 +170,14 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
|
|
||||||
if (stackOffset <= 0xFFFF0)
|
if (stackOffset <= 0xFFFF0)
|
||||||
{
|
{
|
||||||
_unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.SaveXmm128, entry.PrologOffset, entry.RegIndex);
|
unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.SaveXmm128, entry.PrologOffset, entry.RegIndex);
|
||||||
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(stackOffset / 16);
|
unwindInfo->UnwindCodes[codeIndex++] = (ushort)(stackOffset / 16);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.SaveXmm128Far, entry.PrologOffset, entry.RegIndex);
|
unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.SaveXmm128Far, entry.PrologOffset, entry.RegIndex);
|
||||||
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(stackOffset >> 0);
|
unwindInfo->UnwindCodes[codeIndex++] = (ushort)(stackOffset >> 0);
|
||||||
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(stackOffset >> 16);
|
unwindInfo->UnwindCodes[codeIndex++] = (ushort)(stackOffset >> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -161,18 +191,18 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
|
|
||||||
if (allocSize <= 128)
|
if (allocSize <= 128)
|
||||||
{
|
{
|
||||||
_unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocSmall, entry.PrologOffset, (allocSize / 8) - 1);
|
unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocSmall, entry.PrologOffset, (allocSize / 8) - 1);
|
||||||
}
|
}
|
||||||
else if (allocSize <= 0x7FFF8)
|
else if (allocSize <= 0x7FFF8)
|
||||||
{
|
{
|
||||||
_unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 0);
|
unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 0);
|
||||||
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize / 8);
|
unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize / 8);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 1);
|
unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 1);
|
||||||
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 0);
|
unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 0);
|
||||||
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 16);
|
unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -180,7 +210,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
|
|
||||||
case UnwindPseudoOp.PushReg:
|
case UnwindPseudoOp.PushReg:
|
||||||
{
|
{
|
||||||
_unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.PushNonvol, entry.PrologOffset, entry.RegIndex);
|
unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.PushNonvol, entry.PrologOffset, entry.RegIndex);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -192,16 +222,16 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
|
|
||||||
Debug.Assert(codeIndex <= MaxUnwindCodesArraySize);
|
Debug.Assert(codeIndex <= MaxUnwindCodesArraySize);
|
||||||
|
|
||||||
_unwindInfo->VersionAndFlags = 1; // Flags: The function has no handler.
|
unwindInfo->VersionAndFlags = 1; // Flags: The function has no handler.
|
||||||
_unwindInfo->SizeOfProlog = (byte)unwindInfo.PrologSize;
|
unwindInfo->SizeOfProlog = (byte)funcUnwindInfo.PrologSize;
|
||||||
_unwindInfo->CountOfUnwindCodes = (byte)codeIndex;
|
unwindInfo->CountOfUnwindCodes = (byte)codeIndex;
|
||||||
_unwindInfo->FrameRegister = 0;
|
unwindInfo->FrameRegister = 0;
|
||||||
|
|
||||||
_runtimeFunction->BeginAddress = (uint)funcEntry.Offset;
|
runtimeFunction->BeginAddress = (uint)funcEntry.Offset;
|
||||||
_runtimeFunction->EndAddress = (uint)(funcEntry.Offset + funcEntry.Size);
|
runtimeFunction->EndAddress = (uint)(funcEntry.Offset + funcEntry.Size);
|
||||||
_runtimeFunction->UnwindData = (uint)_sizeOfRuntimeFunction;
|
runtimeFunction->UnwindData = (uint)_sizeOfRuntimeFunction;
|
||||||
|
|
||||||
return _runtimeFunction;
|
return runtimeFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ushort PackUnwindOp(UnwindOp op, int prologOffset, int opInfo)
|
private static ushort PackUnwindOp(UnwindOp op, int prologOffset, int opInfo)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.Translation
|
namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
public class DelegateInfo
|
class DelegateInfo
|
||||||
{
|
{
|
||||||
public nint FuncPtr { get; }
|
public nint FuncPtr { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -2,358 +2,11 @@ using ARMeilleure.Instructions;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
#if ANDROID
|
|
||||||
using ARMeilleure.State;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ARMeilleure.Translation
|
namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
static class Delegates
|
static class Delegates
|
||||||
{
|
{
|
||||||
#if ANDROID
|
|
||||||
// MathHelper delegates
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double MathHelperAbsDelegate(double value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double MathHelperCeilingDelegate(double value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double MathHelperFloorDelegate(double value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double MathHelperRoundDelegate(double value, int mode);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double MathHelperTruncateDelegate(double value);
|
|
||||||
|
|
||||||
// MathHelperF delegates
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float MathHelperFAbsDelegate(float value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float MathHelperFCeilingDelegate(float value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float MathHelperFFloorDelegate(float value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float MathHelperFRoundDelegate(float value, int mode);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float MathHelperFTruncateDelegate(float value);
|
|
||||||
|
|
||||||
// NativeInterface delegates
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate void NativeInterfaceBreakDelegate(ulong address, int imm);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate byte NativeInterfaceCheckSynchronizationDelegate();
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate void NativeInterfaceEnqueueForRejitDelegate(ulong address);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate ulong NativeInterfaceGetCntfrqEl0Delegate();
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate ulong NativeInterfaceGetCntpctEl0Delegate();
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate ulong NativeInterfaceGetCntvctEl0Delegate();
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate ulong NativeInterfaceGetCtrEl0Delegate();
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate ulong NativeInterfaceGetDczidEl0Delegate();
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate ulong NativeInterfaceGetFunctionAddressDelegate(ulong address);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate void NativeInterfaceInvalidateCacheLineDelegate(ulong address);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate byte NativeInterfaceReadByteDelegate(ulong address);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate ushort NativeInterfaceReadUInt16Delegate(ulong address);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate uint NativeInterfaceReadUInt32Delegate(ulong address);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate ulong NativeInterfaceReadUInt64Delegate(ulong address);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 NativeInterfaceReadVector128Delegate(ulong address);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate void NativeInterfaceSignalMemoryTrackingDelegate(ulong address, ulong size, byte write);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate void NativeInterfaceSupervisorCallDelegate(ulong address, int imm);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate void NativeInterfaceThrowInvalidMemoryAccessDelegate(ulong address);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate void NativeInterfaceUndefinedDelegate(ulong address, int opCode);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate void NativeInterfaceWriteByteDelegate(ulong address, byte value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate void NativeInterfaceWriteUInt16Delegate(ulong address, ushort value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate void NativeInterfaceWriteUInt32Delegate(ulong address, uint value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate void NativeInterfaceWriteUInt64Delegate(ulong address, ulong value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate void NativeInterfaceWriteVector128Delegate(ulong address, V128 value);
|
|
||||||
|
|
||||||
// SoftFallback delegates
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate ulong SoftFallbackCountLeadingSignsDelegate(ulong value, int size);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate ulong SoftFallbackCountLeadingZerosDelegate(ulong value, int size);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate uint SoftFallbackCrc32bDelegate(uint crc, byte val);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate uint SoftFallbackCrc32cbDelegate(uint crc, byte val);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate uint SoftFallbackCrc32chDelegate(uint crc, ushort val);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate uint SoftFallbackCrc32cwDelegate(uint crc, uint val);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate uint SoftFallbackCrc32cxDelegate(uint crc, ulong val);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate uint SoftFallbackCrc32hDelegate(uint crc, ushort val);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate uint SoftFallbackCrc32wDelegate(uint crc, uint val);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate uint SoftFallbackCrc32xDelegate(uint crc, ulong val);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackDecryptDelegate(V128 value, V128 roundKey);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackEncryptDelegate(V128 value, V128 roundKey);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate uint SoftFallbackFixedRotateDelegate(uint hash_e);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackHashChooseDelegate(V128 hash_abcd, uint hash_e, V128 wk);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackHashLowerDelegate(V128 hash_abcd, V128 hash_efgh, V128 wk);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackHashMajorityDelegate(V128 hash_abcd, uint hash_e, V128 wk);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackHashParityDelegate(V128 hash_abcd, uint hash_e, V128 wk);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackHashUpperDelegate(V128 hash_abcd, V128 hash_efgh, V128 wk);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackInverseMixColumnsDelegate(V128 value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackMixColumnsDelegate(V128 value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackPolynomialMult64_128Delegate(ulong op1, ulong op2);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate int SoftFallbackSatF32ToS32Delegate(float value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate long SoftFallbackSatF32ToS64Delegate(float value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate uint SoftFallbackSatF32ToU32Delegate(float value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate ulong SoftFallbackSatF32ToU64Delegate(float value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate int SoftFallbackSatF64ToS32Delegate(double value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate long SoftFallbackSatF64ToS64Delegate(double value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate uint SoftFallbackSatF64ToU32Delegate(double value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate ulong SoftFallbackSatF64ToU64Delegate(double value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackSha1SchedulePart1Delegate(V128 w0_3, V128 w4_7, V128 w8_11);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackSha1SchedulePart2Delegate(V128 tw0_3, V128 w12_15);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackSha256SchedulePart1Delegate(V128 w0_3, V128 w4_7);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackSha256SchedulePart2Delegate(V128 w0_3, V128 w8_11, V128 w12_15);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate long SoftFallbackSignedShrImm64Delegate(long value, long roundConst, int shift);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackTbl1Delegate(V128 vector, int bytes, V128 table);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackTbl2Delegate(V128 vector, int bytes, V128 table0, V128 table1);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackTbl3Delegate(V128 vector, int bytes, V128 table0, V128 table1, V128 table2);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackTbl4Delegate(V128 vector, int bytes, V128 table0, V128 table1, V128 table2, V128 table3);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackTbx1Delegate(V128 dest, V128 vector, int bytes, V128 table);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackTbx2Delegate(V128 dest, V128 vector, int bytes, V128 table0, V128 table1);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackTbx3Delegate(V128 dest, V128 vector, int bytes, V128 table0, V128 table1, V128 table2);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate V128 SoftFallbackTbx4Delegate(V128 dest, V128 vector, int bytes, V128 table0, V128 table1, V128 table2, V128 table3);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate ulong SoftFallbackUnsignedShrImm64Delegate(ulong value, long roundConst, int shift);
|
|
||||||
|
|
||||||
// SoftFloat delegates
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat16_32FPConvertDelegate(ushort value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat16_64FPConvertDelegate(ushort value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPAddDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPAddFpscrDelegate(float a, float b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate int SoftFloat32FPCompareDelegate(float a, float b, byte signalNaNs);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPCompareEQDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPCompareEQFpscrDelegate(float a, float b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPCompareGEDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPCompareGEFpscrDelegate(float a, float b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPCompareGTDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPCompareGTFpscrDelegate(float a, float b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPCompareLEDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPCompareLEFpscrDelegate(float a, float b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPCompareLTDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPCompareLTFpscrDelegate(float a, float b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPDivDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPMaxDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPMaxFpscrDelegate(float a, float b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPMaxNumDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPMaxNumFpscrDelegate(float a, float b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPMinDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPMinFpscrDelegate(float a, float b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPMinNumDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPMinNumFpscrDelegate(float a, float b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPMulDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPMulFpscrDelegate(float a, float b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPMulAddDelegate(float a, float b, float c);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPMulAddFpscrDelegate(float a, float b, float c, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPMulSubDelegate(float a, float b, float c);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPMulSubFpscrDelegate(float a, float b, float c, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPMulXDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPNegMulAddDelegate(float a, float b, float c);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPNegMulSubDelegate(float a, float b, float c);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPRecipEstimateDelegate(float a);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPRecipEstimateFpscrDelegate(float a, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPRecipStepDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPRecipStepFusedDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPRecpXDelegate(float a);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPRSqrtEstimateDelegate(float a);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPRSqrtEstimateFpscrDelegate(float a, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPRSqrtStepDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPRSqrtStepFusedDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPSqrtDelegate(float a);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate float SoftFloat32FPSubDelegate(float a, float b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate ushort SoftFloat32_16FPConvertDelegate(float value);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPAddDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPAddFpscrDelegate(double a, double b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate int SoftFloat64FPCompareDelegate(double a, double b, byte signalNaNs);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPCompareEQDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPCompareEQFpscrDelegate(double a, double b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPCompareGEDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPCompareGEFpscrDelegate(double a, double b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPCompareGTDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPCompareGTFpscrDelegate(double a, double b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPCompareLEDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPCompareLEFpscrDelegate(double a, double b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPCompareLTDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPCompareLTFpscrDelegate(double a, double b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPDivDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPMaxDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPMaxFpscrDelegate(double a, double b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPMaxNumDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPMaxNumFpscrDelegate(double a, double b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPMinDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPMinFpscrDelegate(double a, double b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPMinNumDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPMinNumFpscrDelegate(double a, double b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPMulDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPMulFpscrDelegate(double a, double b, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPMulAddDelegate(double a, double b, double c);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPMulAddFpscrDelegate(double a, double b, double c, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPMulSubDelegate(double a, double b, double c);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPMulSubFpscrDelegate(double a, double b, double c, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPMulXDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPNegMulAddDelegate(double a, double b, double c);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPNegMulSubDelegate(double a, double b, double c);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPRecipEstimateDelegate(double a);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPRecipEstimateFpscrDelegate(double a, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPRecipStepDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPRecipStepFusedDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPRecpXDelegate(double a);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPRSqrtEstimateDelegate(double a);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPRSqrtEstimateFpscrDelegate(double a, byte standardFpscr);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPRSqrtStepDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPRSqrtStepFusedDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPSqrtDelegate(double a);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate double SoftFloat64FPSubDelegate(double a, double b);
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
||||||
public delegate ushort SoftFloat64_16FPConvertDelegate(double value);
|
|
||||||
|
|
||||||
private static readonly Dictionary<string, Delegate> _androidDelegates;
|
|
||||||
#endif
|
|
||||||
public static bool TryGetDelegateFuncPtrByIndex(int index, out nint funcPtr)
|
public static bool TryGetDelegateFuncPtrByIndex(int index, out nint funcPtr)
|
||||||
{
|
{
|
||||||
if (index >= 0 && index < _delegates.Count)
|
if (index >= 0 && index < _delegates.Count)
|
||||||
@@ -400,32 +53,7 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
string key = GetKey(method);
|
string key = GetKey(method);
|
||||||
|
|
||||||
#if ANDROID
|
_delegates.Add(key, new DelegateInfo(method.MethodHandle.GetFunctionPointer())); // ArgumentException (key).
|
||||||
if (_androidDelegates.TryGetValue(key, out Delegate del))
|
|
||||||
{
|
|
||||||
nint funcPtr = Marshal.GetFunctionPointerForDelegate(del);
|
|
||||||
_delegates.Add(key, new DelegateInfo(funcPtr));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_delegates.Add(key, new DelegateInfo(method.MethodHandle.GetFunctionPointer()));
|
|
||||||
}
|
|
||||||
catch (NotSupportedException) when (IsRunningOnAndroid())
|
|
||||||
{
|
|
||||||
throw new PlatformNotSupportedException($"Cannot obtain function pointer {key}: it must be registered.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsRunningOnAndroid()
|
|
||||||
{
|
|
||||||
#if ANDROID
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetKey(MethodInfo info)
|
private static string GetKey(MethodInfo info)
|
||||||
@@ -439,190 +67,6 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
_delegates = new SortedList<string, DelegateInfo>();
|
_delegates = new SortedList<string, DelegateInfo>();
|
||||||
|
|
||||||
#if ANDROID
|
|
||||||
_androidDelegates = new Dictionary<string, Delegate>
|
|
||||||
{
|
|
||||||
// MathHelper delegates
|
|
||||||
{ "MathHelper.Abs", new MathHelperAbsDelegate(Math.Abs) },
|
|
||||||
{ "MathHelper.Ceiling", new MathHelperCeilingDelegate(Math.Ceiling) },
|
|
||||||
{ "MathHelper.Floor", new MathHelperFloorDelegate(Math.Floor) },
|
|
||||||
{ "MathHelper.Round", new MathHelperRoundDelegate((value, mode) => Math.Round(value, (MidpointRounding)mode)) },
|
|
||||||
{ "MathHelper.Truncate", new MathHelperTruncateDelegate(Math.Truncate) },
|
|
||||||
|
|
||||||
// MathHelperF delegates
|
|
||||||
{ "MathHelperF.Abs", new MathHelperFAbsDelegate(MathF.Abs) },
|
|
||||||
{ "MathHelperF.Ceiling", new MathHelperFCeilingDelegate(MathF.Ceiling) },
|
|
||||||
{ "MathHelperF.Floor", new MathHelperFFloorDelegate(MathF.Floor) },
|
|
||||||
{ "MathHelperF.Round", new MathHelperFRoundDelegate((value, mode) => MathF.Round(value, (MidpointRounding)mode)) },
|
|
||||||
{ "MathHelperF.Truncate", new MathHelperFTruncateDelegate(MathF.Truncate) },
|
|
||||||
|
|
||||||
// NativeInterface delegates
|
|
||||||
{ "NativeInterface.Break", new NativeInterfaceBreakDelegate(NativeInterface.Break) },
|
|
||||||
{ "NativeInterface.CheckSynchronization", new NativeInterfaceCheckSynchronizationDelegate(NativeInterface.CheckSynchronization) },
|
|
||||||
{ "NativeInterface.EnqueueForRejit", new NativeInterfaceEnqueueForRejitDelegate(NativeInterface.EnqueueForRejit) },
|
|
||||||
{ "NativeInterface.GetCntfrqEl0", new NativeInterfaceGetCntfrqEl0Delegate(NativeInterface.GetCntfrqEl0) },
|
|
||||||
{ "NativeInterface.GetCntpctEl0", new NativeInterfaceGetCntpctEl0Delegate(NativeInterface.GetCntpctEl0) },
|
|
||||||
{ "NativeInterface.GetCntvctEl0", new NativeInterfaceGetCntvctEl0Delegate(NativeInterface.GetCntvctEl0) },
|
|
||||||
{ "NativeInterface.GetCtrEl0", new NativeInterfaceGetCtrEl0Delegate(NativeInterface.GetCtrEl0) },
|
|
||||||
{ "NativeInterface.GetDczidEl0", new NativeInterfaceGetDczidEl0Delegate(NativeInterface.GetDczidEl0) },
|
|
||||||
{ "NativeInterface.GetFunctionAddress", new NativeInterfaceGetFunctionAddressDelegate(NativeInterface.GetFunctionAddress) },
|
|
||||||
{ "NativeInterface.InvalidateCacheLine", new NativeInterfaceInvalidateCacheLineDelegate(NativeInterface.InvalidateCacheLine) },
|
|
||||||
{ "NativeInterface.ReadByte", new NativeInterfaceReadByteDelegate(NativeInterface.ReadByte) },
|
|
||||||
{ "NativeInterface.ReadUInt16", new NativeInterfaceReadUInt16Delegate(NativeInterface.ReadUInt16) },
|
|
||||||
{ "NativeInterface.ReadUInt32", new NativeInterfaceReadUInt32Delegate(NativeInterface.ReadUInt32) },
|
|
||||||
{ "NativeInterface.ReadUInt64", new NativeInterfaceReadUInt64Delegate(NativeInterface.ReadUInt64) },
|
|
||||||
{ "NativeInterface.ReadVector128", new NativeInterfaceReadVector128Delegate(NativeInterface.ReadVector128) },
|
|
||||||
{ "NativeInterface.SignalMemoryTracking", new NativeInterfaceSignalMemoryTrackingDelegate(NativeInterface.SignalMemoryTracking) },
|
|
||||||
{ "NativeInterface.SupervisorCall", new NativeInterfaceSupervisorCallDelegate(NativeInterface.SupervisorCall) },
|
|
||||||
{ "NativeInterface.ThrowInvalidMemoryAccess", new NativeInterfaceThrowInvalidMemoryAccessDelegate(NativeInterface.ThrowInvalidMemoryAccess) },
|
|
||||||
{ "NativeInterface.Undefined", new NativeInterfaceUndefinedDelegate(NativeInterface.Undefined) },
|
|
||||||
{ "NativeInterface.WriteByte", new NativeInterfaceWriteByteDelegate(NativeInterface.WriteByte) },
|
|
||||||
{ "NativeInterface.WriteUInt16", new NativeInterfaceWriteUInt16Delegate(NativeInterface.WriteUInt16) },
|
|
||||||
{ "NativeInterface.WriteUInt32", new NativeInterfaceWriteUInt32Delegate(NativeInterface.WriteUInt32) },
|
|
||||||
{ "NativeInterface.WriteUInt64", new NativeInterfaceWriteUInt64Delegate(NativeInterface.WriteUInt64) },
|
|
||||||
{ "NativeInterface.WriteVector128", new NativeInterfaceWriteVector128Delegate(NativeInterface.WriteVector128) },
|
|
||||||
|
|
||||||
// SoftFallback delegates
|
|
||||||
{ "SoftFallback.CountLeadingSigns", new SoftFallbackCountLeadingSignsDelegate(SoftFallback.CountLeadingSigns) },
|
|
||||||
{ "SoftFallback.CountLeadingZeros", new SoftFallbackCountLeadingZerosDelegate(SoftFallback.CountLeadingZeros) },
|
|
||||||
{ "SoftFallback.Crc32b", new SoftFallbackCrc32bDelegate(SoftFallback.Crc32b) },
|
|
||||||
{ "SoftFallback.Crc32cb", new SoftFallbackCrc32cbDelegate(SoftFallback.Crc32cb) },
|
|
||||||
{ "SoftFallback.Crc32ch", new SoftFallbackCrc32chDelegate(SoftFallback.Crc32ch) },
|
|
||||||
{ "SoftFallback.Crc32cw", new SoftFallbackCrc32cwDelegate(SoftFallback.Crc32cw) },
|
|
||||||
{ "SoftFallback.Crc32cx", new SoftFallbackCrc32cxDelegate(SoftFallback.Crc32cx) },
|
|
||||||
{ "SoftFallback.Crc32h", new SoftFallbackCrc32hDelegate(SoftFallback.Crc32h) },
|
|
||||||
{ "SoftFallback.Crc32w", new SoftFallbackCrc32wDelegate(SoftFallback.Crc32w) },
|
|
||||||
{ "SoftFallback.Crc32x", new SoftFallbackCrc32xDelegate(SoftFallback.Crc32x) },
|
|
||||||
{ "SoftFallback.Decrypt", new SoftFallbackDecryptDelegate(SoftFallback.Decrypt) },
|
|
||||||
{ "SoftFallback.Encrypt", new SoftFallbackEncryptDelegate(SoftFallback.Encrypt) },
|
|
||||||
{ "SoftFallback.FixedRotate", new SoftFallbackFixedRotateDelegate(SoftFallback.FixedRotate) },
|
|
||||||
{ "SoftFallback.HashChoose", new SoftFallbackHashChooseDelegate(SoftFallback.HashChoose) },
|
|
||||||
{ "SoftFallback.HashLower", new SoftFallbackHashLowerDelegate(SoftFallback.HashLower) },
|
|
||||||
{ "SoftFallback.HashMajority", new SoftFallbackHashMajorityDelegate(SoftFallback.HashMajority) },
|
|
||||||
{ "SoftFallback.HashParity", new SoftFallbackHashParityDelegate(SoftFallback.HashParity) },
|
|
||||||
{ "SoftFallback.HashUpper", new SoftFallbackHashUpperDelegate(SoftFallback.HashUpper) },
|
|
||||||
{ "SoftFallback.InverseMixColumns", new SoftFallbackInverseMixColumnsDelegate(SoftFallback.InverseMixColumns) },
|
|
||||||
{ "SoftFallback.MixColumns", new SoftFallbackMixColumnsDelegate(SoftFallback.MixColumns) },
|
|
||||||
{ "SoftFallback.PolynomialMult64_128", new SoftFallbackPolynomialMult64_128Delegate(SoftFallback.PolynomialMult64_128) },
|
|
||||||
{ "SoftFallback.SatF32ToS32", new SoftFallbackSatF32ToS32Delegate(SoftFallback.SatF32ToS32) },
|
|
||||||
{ "SoftFallback.SatF32ToS64", new SoftFallbackSatF32ToS64Delegate(SoftFallback.SatF32ToS64) },
|
|
||||||
{ "SoftFallback.SatF32ToU32", new SoftFallbackSatF32ToU32Delegate(SoftFallback.SatF32ToU32) },
|
|
||||||
{ "SoftFallback.SatF32ToU64", new SoftFallbackSatF32ToU64Delegate(SoftFallback.SatF32ToU64) },
|
|
||||||
{ "SoftFallback.SatF64ToS32", new SoftFallbackSatF64ToS32Delegate(SoftFallback.SatF64ToS32) },
|
|
||||||
{ "SoftFallback.SatF64ToS64", new SoftFallbackSatF64ToS64Delegate(SoftFallback.SatF64ToS64) },
|
|
||||||
{ "SoftFallback.SatF64ToU32", new SoftFallbackSatF64ToU32Delegate(SoftFallback.SatF64ToU32) },
|
|
||||||
{ "SoftFallback.SatF64ToU64", new SoftFallbackSatF64ToU64Delegate(SoftFallback.SatF64ToU64) },
|
|
||||||
{ "SoftFallback.Sha1SchedulePart1", new SoftFallbackSha1SchedulePart1Delegate(SoftFallback.Sha1SchedulePart1) },
|
|
||||||
{ "SoftFallback.Sha1SchedulePart2", new SoftFallbackSha1SchedulePart2Delegate(SoftFallback.Sha1SchedulePart2) },
|
|
||||||
{ "SoftFallback.Sha256SchedulePart1", new SoftFallbackSha256SchedulePart1Delegate(SoftFallback.Sha256SchedulePart1) },
|
|
||||||
{ "SoftFallback.Sha256SchedulePart2", new SoftFallbackSha256SchedulePart2Delegate(SoftFallback.Sha256SchedulePart2) },
|
|
||||||
{ "SoftFallback.SignedShrImm64", new SoftFallbackSignedShrImm64Delegate(SoftFallback.SignedShrImm64) },
|
|
||||||
{ "SoftFallback.Tbl1", new SoftFallbackTbl1Delegate(SoftFallback.Tbl1) },
|
|
||||||
{ "SoftFallback.Tbl2", new SoftFallbackTbl2Delegate(SoftFallback.Tbl2) },
|
|
||||||
{ "SoftFallback.Tbl3", new SoftFallbackTbl3Delegate(SoftFallback.Tbl3) },
|
|
||||||
{ "SoftFallback.Tbl4", new SoftFallbackTbl4Delegate(SoftFallback.Tbl4) },
|
|
||||||
{ "SoftFallback.Tbx1", new SoftFallbackTbx1Delegate(SoftFallback.Tbx1) },
|
|
||||||
{ "SoftFallback.Tbx2", new SoftFallbackTbx2Delegate(SoftFallback.Tbx2) },
|
|
||||||
{ "SoftFallback.Tbx3", new SoftFallbackTbx3Delegate(SoftFallback.Tbx3) },
|
|
||||||
{ "SoftFallback.Tbx4", new SoftFallbackTbx4Delegate(SoftFallback.Tbx4) },
|
|
||||||
{ "SoftFallback.UnsignedShrImm64", new SoftFallbackUnsignedShrImm64Delegate(SoftFallback.UnsignedShrImm64) },
|
|
||||||
|
|
||||||
// SoftFloat delegates
|
|
||||||
{ "SoftFloat16_32.FPConvert", new SoftFloat16_32FPConvertDelegate(SoftFloat16_32.FPConvert) },
|
|
||||||
{ "SoftFloat16_64.FPConvert", new SoftFloat16_64FPConvertDelegate(SoftFloat16_64.FPConvert) },
|
|
||||||
|
|
||||||
{ "SoftFloat32.FPAdd", new SoftFloat32FPAddDelegate(SoftFloat32.FPAdd) },
|
|
||||||
{ "SoftFloat32.FPAddFpscr", new SoftFloat32FPAddFpscrDelegate(SoftFloat32.FPAddFpscr) },
|
|
||||||
{ "SoftFloat32.FPCompare", new SoftFloat32FPCompareDelegate(SoftFloat32.FPCompare) },
|
|
||||||
{ "SoftFloat32.FPCompareEQ", new SoftFloat32FPCompareEQDelegate(SoftFloat32.FPCompareEQ) },
|
|
||||||
{ "SoftFloat32.FPCompareEQFpscr", new SoftFloat32FPCompareEQFpscrDelegate(SoftFloat32.FPCompareEQFpscr) },
|
|
||||||
{ "SoftFloat32.FPCompareGE", new SoftFloat32FPCompareGEDelegate(SoftFloat32.FPCompareGE) },
|
|
||||||
{ "SoftFloat32.FPCompareGEFpscr", new SoftFloat32FPCompareGEFpscrDelegate(SoftFloat32.FPCompareGEFpscr) },
|
|
||||||
{ "SoftFloat32.FPCompareGT", new SoftFloat32FPCompareGTDelegate(SoftFloat32.FPCompareGT) },
|
|
||||||
{ "SoftFloat32.FPCompareGTFpscr", new SoftFloat32FPCompareGTFpscrDelegate(SoftFloat32.FPCompareGTFpscr) },
|
|
||||||
{ "SoftFloat32.FPCompareLE", new SoftFloat32FPCompareLEDelegate(SoftFloat32.FPCompareLE) },
|
|
||||||
{ "SoftFloat32.FPCompareLEFpscr", new SoftFloat32FPCompareLEFpscrDelegate(SoftFloat32.FPCompareLEFpscr) },
|
|
||||||
{ "SoftFloat32.FPCompareLT", new SoftFloat32FPCompareLTDelegate(SoftFloat32.FPCompareLT) },
|
|
||||||
{ "SoftFloat32.FPCompareLTFpscr", new SoftFloat32FPCompareLTFpscrDelegate(SoftFloat32.FPCompareLTFpscr) },
|
|
||||||
{ "SoftFloat32.FPDiv", new SoftFloat32FPDivDelegate(SoftFloat32.FPDiv) },
|
|
||||||
{ "SoftFloat32.FPMax", new SoftFloat32FPMaxDelegate(SoftFloat32.FPMax) },
|
|
||||||
{ "SoftFloat32.FPMaxFpscr", new SoftFloat32FPMaxFpscrDelegate(SoftFloat32.FPMaxFpscr) },
|
|
||||||
{ "SoftFloat32.FPMaxNum", new SoftFloat32FPMaxNumDelegate(SoftFloat32.FPMaxNum) },
|
|
||||||
{ "SoftFloat32.FPMaxNumFpscr", new SoftFloat32FPMaxNumFpscrDelegate(SoftFloat32.FPMaxNumFpscr) },
|
|
||||||
{ "SoftFloat32.FPMin", new SoftFloat32FPMinDelegate(SoftFloat32.FPMin) },
|
|
||||||
{ "SoftFloat32.FPMinFpscr", new SoftFloat32FPMinFpscrDelegate(SoftFloat32.FPMinFpscr) },
|
|
||||||
{ "SoftFloat32.FPMinNum", new SoftFloat32FPMinNumDelegate(SoftFloat32.FPMinNum) },
|
|
||||||
{ "SoftFloat32.FPMinNumFpscr", new SoftFloat32FPMinNumFpscrDelegate(SoftFloat32.FPMinNumFpscr) },
|
|
||||||
{ "SoftFloat32.FPMul", new SoftFloat32FPMulDelegate(SoftFloat32.FPMul) },
|
|
||||||
{ "SoftFloat32.FPMulFpscr", new SoftFloat32FPMulFpscrDelegate(SoftFloat32.FPMulFpscr) },
|
|
||||||
{ "SoftFloat32.FPMulAdd", new SoftFloat32FPMulAddDelegate(SoftFloat32.FPMulAdd) },
|
|
||||||
{ "SoftFloat32.FPMulAddFpscr", new SoftFloat32FPMulAddFpscrDelegate(SoftFloat32.FPMulAddFpscr) },
|
|
||||||
{ "SoftFloat32.FPMulSub", new SoftFloat32FPMulSubDelegate(SoftFloat32.FPMulSub) },
|
|
||||||
{ "SoftFloat32.FPMulSubFpscr", new SoftFloat32FPMulSubFpscrDelegate(SoftFloat32.FPMulSubFpscr) },
|
|
||||||
{ "SoftFloat32.FPMulX", new SoftFloat32FPMulXDelegate(SoftFloat32.FPMulX) },
|
|
||||||
{ "SoftFloat32.FPNegMulAdd", new SoftFloat32FPNegMulAddDelegate(SoftFloat32.FPNegMulAdd) },
|
|
||||||
{ "SoftFloat32.FPNegMulSub", new SoftFloat32FPNegMulSubDelegate(SoftFloat32.FPNegMulSub) },
|
|
||||||
{ "SoftFloat32.FPRecipEstimate", new SoftFloat32FPRecipEstimateDelegate(SoftFloat32.FPRecipEstimate) },
|
|
||||||
{ "SoftFloat32.FPRecipEstimateFpscr", new SoftFloat32FPRecipEstimateFpscrDelegate(SoftFloat32.FPRecipEstimateFpscr) },
|
|
||||||
{ "SoftFloat32.FPRecipStep", new SoftFloat32FPRecipStepDelegate(SoftFloat32.FPRecipStep) },
|
|
||||||
{ "SoftFloat32.FPRecipStepFused", new SoftFloat32FPRecipStepFusedDelegate(SoftFloat32.FPRecipStepFused) },
|
|
||||||
{ "SoftFloat32.FPRecpX", new SoftFloat32FPRecpXDelegate(SoftFloat32.FPRecpX) },
|
|
||||||
{ "SoftFloat32.FPRSqrtEstimate", new SoftFloat32FPRSqrtEstimateDelegate(SoftFloat32.FPRSqrtEstimate) },
|
|
||||||
{ "SoftFloat32.FPRSqrtEstimateFpscr", new SoftFloat32FPRSqrtEstimateFpscrDelegate(SoftFloat32.FPRSqrtEstimateFpscr) },
|
|
||||||
{ "SoftFloat32.FPRSqrtStep", new SoftFloat32FPRSqrtStepDelegate(SoftFloat32.FPRSqrtStep) },
|
|
||||||
{ "SoftFloat32.FPRSqrtStepFused", new SoftFloat32FPRSqrtStepFusedDelegate(SoftFloat32.FPRSqrtStepFused) },
|
|
||||||
{ "SoftFloat32.FPSqrt", new SoftFloat32FPSqrtDelegate(SoftFloat32.FPSqrt) },
|
|
||||||
{ "SoftFloat32.FPSub", new SoftFloat32FPSubDelegate(SoftFloat32.FPSub) },
|
|
||||||
|
|
||||||
{ "SoftFloat32_16.FPConvert", new SoftFloat32_16FPConvertDelegate(SoftFloat32_16.FPConvert) },
|
|
||||||
|
|
||||||
{ "SoftFloat64.FPAdd", new SoftFloat64FPAddDelegate(SoftFloat64.FPAdd) },
|
|
||||||
{ "SoftFloat64.FPAddFpscr", new SoftFloat64FPAddFpscrDelegate(SoftFloat64.FPAddFpscr) },
|
|
||||||
{ "SoftFloat64.FPCompare", new SoftFloat64FPCompareDelegate(SoftFloat64.FPCompare) },
|
|
||||||
{ "SoftFloat64.FPCompareEQ", new SoftFloat64FPCompareEQDelegate(SoftFloat64.FPCompareEQ) },
|
|
||||||
{ "SoftFloat64.FPCompareEQFpscr", new SoftFloat64FPCompareEQFpscrDelegate(SoftFloat64.FPCompareEQFpscr) },
|
|
||||||
{ "SoftFloat64.FPCompareGE", new SoftFloat64FPCompareGEDelegate(SoftFloat64.FPCompareGE) },
|
|
||||||
{ "SoftFloat64.FPCompareGEFpscr", new SoftFloat64FPCompareGEFpscrDelegate(SoftFloat64.FPCompareGEFpscr) },
|
|
||||||
{ "SoftFloat64.FPCompareGT", new SoftFloat64FPCompareGTDelegate(SoftFloat64.FPCompareGT) },
|
|
||||||
{ "SoftFloat64.FPCompareGTFpscr", new SoftFloat64FPCompareGTFpscrDelegate(SoftFloat64.FPCompareGTFpscr) },
|
|
||||||
{ "SoftFloat64.FPCompareLE", new SoftFloat64FPCompareLEDelegate(SoftFloat64.FPCompareLE) },
|
|
||||||
{ "SoftFloat64.FPCompareLEFpscr", new SoftFloat64FPCompareLEFpscrDelegate(SoftFloat64.FPCompareLEFpscr) },
|
|
||||||
{ "SoftFloat64.FPCompareLT", new SoftFloat64FPCompareLTDelegate(SoftFloat64.FPCompareLT) },
|
|
||||||
{ "SoftFloat64.FPCompareLTFpscr", new SoftFloat64FPCompareLTFpscrDelegate(SoftFloat64.FPCompareLTFpscr) },
|
|
||||||
{ "SoftFloat64.FPDiv", new SoftFloat64FPDivDelegate(SoftFloat64.FPDiv) },
|
|
||||||
{ "SoftFloat64.FPMax", new SoftFloat64FPMaxDelegate(SoftFloat64.FPMax) },
|
|
||||||
{ "SoftFloat64.FPMaxFpscr", new SoftFloat64FPMaxFpscrDelegate(SoftFloat64.FPMaxFpscr) },
|
|
||||||
{ "SoftFloat64.FPMaxNum", new SoftFloat64FPMaxNumDelegate(SoftFloat64.FPMaxNum) },
|
|
||||||
{ "SoftFloat64.FPMaxNumFpscr", new SoftFloat64FPMaxNumFpscrDelegate(SoftFloat64.FPMaxNumFpscr) },
|
|
||||||
{ "SoftFloat64.FPMin", new SoftFloat64FPMinDelegate(SoftFloat64.FPMin) },
|
|
||||||
{ "SoftFloat64.FPMinFpscr", new SoftFloat64FPMinFpscrDelegate(SoftFloat64.FPMinFpscr) },
|
|
||||||
{ "SoftFloat64.FPMinNum", new SoftFloat64FPMinNumDelegate(SoftFloat64.FPMinNum) },
|
|
||||||
{ "SoftFloat64.FPMinNumFpscr", new SoftFloat64FPMinNumFpscrDelegate(SoftFloat64.FPMinNumFpscr) },
|
|
||||||
{ "SoftFloat64.FPMul", new SoftFloat64FPMulDelegate(SoftFloat64.FPMul) },
|
|
||||||
{ "SoftFloat64.FPMulFpscr", new SoftFloat64FPMulFpscrDelegate(SoftFloat64.FPMulFpscr) },
|
|
||||||
{ "SoftFloat64.FPMulAdd", new SoftFloat64FPMulAddDelegate(SoftFloat64.FPMulAdd) },
|
|
||||||
{ "SoftFloat64.FPMulAddFpscr", new SoftFloat64FPMulAddFpscrDelegate(SoftFloat64.FPMulAddFpscr) },
|
|
||||||
{ "SoftFloat64.FPMulSub", new SoftFloat64FPMulSubDelegate(SoftFloat64.FPMulSub) },
|
|
||||||
{ "SoftFloat64.FPMulSubFpscr", new SoftFloat64FPMulSubFpscrDelegate(SoftFloat64.FPMulSubFpscr) },
|
|
||||||
{ "SoftFloat64.FPMulX", new SoftFloat64FPMulXDelegate(SoftFloat64.FPMulX) },
|
|
||||||
{ "SoftFloat64.FPNegMulAdd", new SoftFloat64FPNegMulAddDelegate(SoftFloat64.FPNegMulAdd) },
|
|
||||||
{ "SoftFloat64.FPNegMulSub", new SoftFloat64FPNegMulSubDelegate(SoftFloat64.FPNegMulSub) },
|
|
||||||
{ "SoftFloat64.FPRecipEstimate", new SoftFloat64FPRecipEstimateDelegate(SoftFloat64.FPRecipEstimate) },
|
|
||||||
{ "SoftFloat64.FPRecipEstimateFpscr", new SoftFloat64FPRecipEstimateFpscrDelegate(SoftFloat64.FPRecipEstimateFpscr) },
|
|
||||||
{ "SoftFloat64.FPRecipStep", new SoftFloat64FPRecipStepDelegate(SoftFloat64.FPRecipStep) },
|
|
||||||
{ "SoftFloat64.FPRecipStepFused", new SoftFloat64FPRecipStepFusedDelegate(SoftFloat64.FPRecipStepFused) },
|
|
||||||
{ "SoftFloat64.FPRecpX", new SoftFloat64FPRecpXDelegate(SoftFloat64.FPRecpX) },
|
|
||||||
{ "SoftFloat64.FPRSqrtEstimate", new SoftFloat64FPRSqrtEstimateDelegate(SoftFloat64.FPRSqrtEstimate) },
|
|
||||||
{ "SoftFloat64.FPRSqrtEstimateFpscr", new SoftFloat64FPRSqrtEstimateFpscrDelegate(SoftFloat64.FPRSqrtEstimateFpscr) },
|
|
||||||
{ "SoftFloat64.FPRSqrtStep", new SoftFloat64FPRSqrtStepDelegate(SoftFloat64.FPRSqrtStep) },
|
|
||||||
{ "SoftFloat64.FPRSqrtStepFused", new SoftFloat64FPRSqrtStepFusedDelegate(SoftFloat64.FPRSqrtStepFused) },
|
|
||||||
{ "SoftFloat64.FPSqrt", new SoftFloat64FPSqrtDelegate(SoftFloat64.FPSqrt) },
|
|
||||||
{ "SoftFloat64.FPSub", new SoftFloat64FPSubDelegate(SoftFloat64.FPSub) },
|
|
||||||
|
|
||||||
{ "SoftFloat64_16.FPConvert", new SoftFloat64_16FPConvertDelegate(SoftFloat64_16.FPConvert) }
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Abs)));
|
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Abs)));
|
||||||
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Ceiling)));
|
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Ceiling)));
|
||||||
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Floor)));
|
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Floor)));
|
||||||
@@ -708,44 +152,44 @@ namespace ARMeilleure.Translation
|
|||||||
SetDelegateInfo(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)));
|
SetDelegateInfo(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)));
|
||||||
|
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQ)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQ)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQFpscr)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGE)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGE)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGT)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGT)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGTFpscr)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGTFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLE)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLE)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLT)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLT)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLTFpscr)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLTFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPDiv)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPDiv)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxFpscr)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinFpscr)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMul)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMul)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulFpscr)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAdd)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSub)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSub)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSubFpscr)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSubFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulX)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulX)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulAdd)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt)));
|
||||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSub)));
|
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSub)));
|
||||||
@@ -753,44 +197,44 @@ namespace ARMeilleure.Translation
|
|||||||
SetDelegateInfo(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)));
|
SetDelegateInfo(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)));
|
||||||
|
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAdd)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAddFpscr)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAddFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQ)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQ)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQFpscr)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGE)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGE)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGT)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGT)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGTFpscr)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGTFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLE)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLE)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLT)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLT)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLTFpscr)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLTFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPDiv)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPDiv)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMax)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMax)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxFpscr)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNum)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNum)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMin)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMin)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinFpscr)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNum)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNum)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMul)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMul)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulFpscr)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAdd)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSub)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSub)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSubFpscr)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSubFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulX)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulX)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulAdd)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulAdd)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep))); // A32 only.
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt)));
|
||||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub)));
|
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub)));
|
||||||
|
|||||||
@@ -97,14 +97,7 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
public virtual Operand Call(MethodInfo info, params Operand[] callArgs)
|
public virtual Operand Call(MethodInfo info, params Operand[] callArgs)
|
||||||
{
|
{
|
||||||
#if ANDROID
|
|
||||||
// For Android, use the Delegates class to get the function pointer
|
|
||||||
int index = Delegates.GetDelegateIndex(info);
|
|
||||||
nint funcPtr = Delegates.GetDelegateFuncPtrByIndex(index);
|
|
||||||
#else
|
|
||||||
// For other platforms, use direct method handle approach
|
|
||||||
nint funcPtr = info.MethodHandle.GetFunctionPointer();
|
nint funcPtr = info.MethodHandle.GetFunctionPointer();
|
||||||
#endif
|
|
||||||
|
|
||||||
OperandType returnType = GetOperandType(info.ReturnType);
|
OperandType returnType = GetOperandType(info.ReturnType);
|
||||||
|
|
||||||
|
|||||||
@@ -359,10 +359,7 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
IntervalTreeNode<TK, TV> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
IntervalTreeNode<TK, TV> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
||||||
|
|
||||||
if (tmp != null)
|
tmp?.Parent = ParentOf(replacementNode);
|
||||||
{
|
|
||||||
tmp.Parent = ParentOf(replacementNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ParentOf(replacementNode) == null)
|
if (ParentOf(replacementNode) == null)
|
||||||
{
|
{
|
||||||
@@ -570,10 +567,7 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
IntervalTreeNode<TK, TV> right = RightOf(node);
|
IntervalTreeNode<TK, TV> right = RightOf(node);
|
||||||
node.Right = LeftOf(right);
|
node.Right = LeftOf(right);
|
||||||
if (node.Right != null)
|
node.Right?.Parent = node;
|
||||||
{
|
|
||||||
node.Right.Parent = node;
|
|
||||||
}
|
|
||||||
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
|
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
|
||||||
right.Parent = nodeParent;
|
right.Parent = nodeParent;
|
||||||
if (nodeParent == null)
|
if (nodeParent == null)
|
||||||
@@ -601,10 +595,7 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
IntervalTreeNode<TK, TV> left = LeftOf(node);
|
IntervalTreeNode<TK, TV> left = LeftOf(node);
|
||||||
node.Left = RightOf(left);
|
node.Left = RightOf(left);
|
||||||
if (node.Left != null)
|
node.Left?.Parent = node;
|
||||||
{
|
|
||||||
node.Left.Parent = node;
|
|
||||||
}
|
|
||||||
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
|
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
|
||||||
left.Parent = nodeParent;
|
left.Parent = nodeParent;
|
||||||
if (nodeParent == null)
|
if (nodeParent == null)
|
||||||
@@ -651,10 +642,7 @@ namespace ARMeilleure.Translation
|
|||||||
/// <param name="color">Color (Boolean)</param>
|
/// <param name="color">Color (Boolean)</param>
|
||||||
private static void SetColor(IntervalTreeNode<TK, TV> node, bool color)
|
private static void SetColor(IntervalTreeNode<TK, TV> node, bool color)
|
||||||
{
|
{
|
||||||
if (node != null)
|
node?.Color = color;
|
||||||
{
|
|
||||||
node.Color = color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using ARMeilleure.CodeGen.Unwinding;
|
|||||||
using ARMeilleure.Common;
|
using ARMeilleure.Common;
|
||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
|
using ARMeilleure.Translation.Cache;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
@@ -31,11 +32,14 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 7031; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 7020; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
|
||||||
|
private const string TitleIdTextDefault = "0000000000000000";
|
||||||
|
private const string DisplayVersionDefault = "0";
|
||||||
|
|
||||||
public static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1);
|
public static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1);
|
||||||
public static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2);
|
public static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2);
|
||||||
public static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
|
public static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
|
||||||
@@ -46,6 +50,8 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
public PtcProfiler Profiler { get; }
|
public PtcProfiler Profiler { get; }
|
||||||
|
|
||||||
|
private readonly JitCache _jitCache;
|
||||||
|
|
||||||
// Carriers.
|
// Carriers.
|
||||||
private MemoryStream _infosStream;
|
private MemoryStream _infosStream;
|
||||||
private List<byte[]> _codesList;
|
private List<byte[]> _codesList;
|
||||||
@@ -61,7 +67,8 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
public PtcCacheInfo CacheInfo { get; private set; }
|
public string TitleIdText { get; private set; }
|
||||||
|
public string DisplayVersion { get; private set; }
|
||||||
|
|
||||||
private MemoryManagerType _memoryMode;
|
private MemoryManagerType _memoryMode;
|
||||||
|
|
||||||
@@ -75,7 +82,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private volatile int _translateTotalCount;
|
private volatile int _translateTotalCount;
|
||||||
public event Action<PtcLoadingState, int, int> PtcStateChanged;
|
public event Action<PtcLoadingState, int, int> PtcStateChanged;
|
||||||
|
|
||||||
public Ptc()
|
public Ptc(JitCache jitCache)
|
||||||
{
|
{
|
||||||
Profiler = new PtcProfiler(this);
|
Profiler = new PtcProfiler(this);
|
||||||
|
|
||||||
@@ -86,9 +93,12 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
_waitEvent = new ManualResetEvent(true);
|
_waitEvent = new ManualResetEvent(true);
|
||||||
|
|
||||||
|
_jitCache = jitCache;
|
||||||
|
|
||||||
_disposed = false;
|
_disposed = false;
|
||||||
|
|
||||||
CacheInfo = new PtcCacheInfo(0, null, null, 0, null, "Unknown", "default");
|
TitleIdText = TitleIdTextDefault;
|
||||||
|
DisplayVersion = DisplayVersionDefault;
|
||||||
|
|
||||||
CachePathActual = string.Empty;
|
CachePathActual = string.Empty;
|
||||||
CachePathBackup = string.Empty;
|
CachePathBackup = string.Empty;
|
||||||
@@ -96,24 +106,20 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
Disable();
|
Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize(PtcCacheInfo cacheInfo, bool enabled, MemoryManagerType memoryMode)
|
public void Initialize(string titleIdText, string displayVersion, bool enabled, MemoryManagerType memoryMode, string cacheSelector)
|
||||||
{
|
{
|
||||||
Wait();
|
Wait();
|
||||||
|
|
||||||
Profiler.Wait();
|
Profiler.Wait();
|
||||||
Profiler.ClearEntries();
|
Profiler.ClearEntries();
|
||||||
|
|
||||||
CacheInfo = cacheInfo;
|
Logger.Info?.Print(LogClass.Ptc, $"Initializing Profiled Persistent Translation Cache v{InternalVersion}\n\t\t (title: {titleIdText}, version: '{displayVersion}', selector: '{cacheSelector}', enabled: {enabled}).");
|
||||||
|
|
||||||
Logger.Info?.Print(
|
if (!enabled || string.IsNullOrEmpty(titleIdText) || titleIdText == TitleIdTextDefault)
|
||||||
LogClass.Ptc,
|
|
||||||
$"Initializing Profiled Persistent Translation Cache v{InternalVersion}\n\t\t " +
|
|
||||||
$"(pid: {cacheInfo.ProcessId}, title: {cacheInfo.TitleIdText}, application: {cacheInfo.ApplicationIdText}, " +
|
|
||||||
$"programIndex: {cacheInfo.ProgramIndex}, version: '{cacheInfo.DisplayVersion}', kind: {cacheInfo.ProcessKind}, " +
|
|
||||||
$"selector: '{cacheInfo.CacheSelector}', key: '{cacheInfo.CacheKey}', enabled: {enabled}).");
|
|
||||||
|
|
||||||
if (!enabled || cacheInfo.TitleIdText == PtcCacheInfo.TitleIdTextDefault)
|
|
||||||
{
|
{
|
||||||
|
TitleIdText = TitleIdTextDefault;
|
||||||
|
DisplayVersion = DisplayVersionDefault;
|
||||||
|
|
||||||
CachePathActual = string.Empty;
|
CachePathActual = string.Empty;
|
||||||
CachePathBackup = string.Empty;
|
CachePathBackup = string.Empty;
|
||||||
|
|
||||||
@@ -122,10 +128,12 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TitleIdText = titleIdText;
|
||||||
|
DisplayVersion = !string.IsNullOrEmpty(displayVersion) ? displayVersion : DisplayVersionDefault;
|
||||||
_memoryMode = memoryMode;
|
_memoryMode = memoryMode;
|
||||||
|
|
||||||
string workPathActual = Path.Combine(AppDataManager.GamesDirPath, CacheInfo.TitleIdText, "cache", "cpu", ActualDir);
|
string workPathActual = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", ActualDir);
|
||||||
string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, CacheInfo.TitleIdText, "cache", "cpu", BackupDir);
|
string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", BackupDir);
|
||||||
|
|
||||||
if (!Directory.Exists(workPathActual))
|
if (!Directory.Exists(workPathActual))
|
||||||
{
|
{
|
||||||
@@ -137,14 +145,8 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
Directory.CreateDirectory(workPathBackup);
|
Directory.CreateDirectory(workPathBackup);
|
||||||
}
|
}
|
||||||
|
|
||||||
CachePathActual = Path.Combine(workPathActual, CacheInfo.DisplayVersion) + "-" + CacheInfo.CacheSelector;
|
CachePathActual = Path.Combine(workPathActual, DisplayVersion) + "-" + cacheSelector;
|
||||||
CachePathBackup = Path.Combine(workPathBackup, CacheInfo.DisplayVersion) + "-" + CacheInfo.CacheSelector;
|
CachePathBackup = Path.Combine(workPathBackup, DisplayVersion) + "-" + cacheSelector;
|
||||||
|
|
||||||
Logger.Info?.Print(
|
|
||||||
LogClass.Ptc,
|
|
||||||
$"PPTC cache owner selected (pid: {CacheInfo.ProcessId}, title: {CacheInfo.TitleIdText}, application: {CacheInfo.ApplicationIdText}, " +
|
|
||||||
$"version: '{CacheInfo.DisplayVersion}', kind: {CacheInfo.ProcessKind}, selector: '{CacheInfo.CacheSelector}', " +
|
|
||||||
$"key: '{CacheInfo.CacheKey}', path: '{CachePathActual}').");
|
|
||||||
|
|
||||||
PreLoad();
|
PreLoad();
|
||||||
Profiler.PreLoad();
|
Profiler.PreLoad();
|
||||||
@@ -253,7 +255,8 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
outerHeader.FeatureInfo != GetFeatureInfo() ||
|
outerHeader.FeatureInfo != GetFeatureInfo() ||
|
||||||
outerHeader.MemoryManagerMode != GetMemoryManagerMode() ||
|
outerHeader.MemoryManagerMode != GetMemoryManagerMode() ||
|
||||||
outerHeader.OSPlatform != GetOSPlatform() ||
|
outerHeader.OSPlatform != GetOSPlatform() ||
|
||||||
outerHeader.Architecture != (uint)RuntimeInformation.ProcessArchitecture)
|
outerHeader.Architecture != (uint)RuntimeInformation.ProcessArchitecture ||
|
||||||
|
outerHeader.DebuggerMode != Optimizations.EnableDebugging)
|
||||||
{
|
{
|
||||||
InvalidateCompressedStream(compressedStream);
|
InvalidateCompressedStream(compressedStream);
|
||||||
|
|
||||||
@@ -367,12 +370,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
long fileSize = new FileInfo(fileName).Length;
|
long fileSize = new FileInfo(fileName).Length;
|
||||||
|
|
||||||
Logger.Info?.Print(
|
Logger.Info?.Print(LogClass.Ptc, $"{(isBackup ? "Loaded Backup Translation Cache" : "Loaded Translation Cache")} (size: {fileSize} bytes, translated functions: {GetEntriesCount()}).");
|
||||||
LogClass.Ptc,
|
|
||||||
$"{(isBackup ? "Loaded Backup Translation Cache" : "Loaded Translation Cache")} " +
|
|
||||||
$"(pid: {CacheInfo.ProcessId}, title: {CacheInfo.TitleIdText}, version: '{CacheInfo.DisplayVersion}', kind: {CacheInfo.ProcessKind}, " +
|
|
||||||
$"selector: '{CacheInfo.CacheSelector}', key: '{CacheInfo.CacheKey}', path: '{fileName}', " +
|
|
||||||
$"size: {fileSize} bytes, translated functions: {GetEntriesCount()}).");
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -434,6 +432,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
MemoryManagerMode = GetMemoryManagerMode(),
|
MemoryManagerMode = GetMemoryManagerMode(),
|
||||||
OSPlatform = GetOSPlatform(),
|
OSPlatform = GetOSPlatform(),
|
||||||
Architecture = (uint)RuntimeInformation.ProcessArchitecture,
|
Architecture = (uint)RuntimeInformation.ProcessArchitecture,
|
||||||
|
DebuggerMode = Optimizations.EnableDebugging,
|
||||||
|
|
||||||
UncompressedStreamSize =
|
UncompressedStreamSize =
|
||||||
(long)Unsafe.SizeOf<InnerHeader>() +
|
(long)Unsafe.SizeOf<InnerHeader>() +
|
||||||
@@ -731,7 +730,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return new UnwindInfo(pushEntries, prologueSize);
|
return new UnwindInfo(pushEntries, prologueSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TranslatedFunction FastTranslate(
|
private TranslatedFunction FastTranslate(
|
||||||
byte[] code,
|
byte[] code,
|
||||||
Counter<uint> callCounter,
|
Counter<uint> callCounter,
|
||||||
ulong guestSize,
|
ulong guestSize,
|
||||||
@@ -739,7 +738,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
bool highCq)
|
bool highCq)
|
||||||
{
|
{
|
||||||
CompiledFunction cFunc = new(code, unwindInfo, RelocInfo.Empty);
|
CompiledFunction cFunc = new(code, unwindInfo, RelocInfo.Empty);
|
||||||
GuestFunction gFunc = cFunc.MapWithPointer<GuestFunction>(out nint gFuncPointer);
|
GuestFunction gFunc = cFunc.MapWithPointer<GuestFunction>(_jitCache, out nint gFuncPointer);
|
||||||
|
|
||||||
return new TranslatedFunction(gFunc, gFuncPointer, callCounter, guestSize, highCq);
|
return new TranslatedFunction(gFunc, gFuncPointer, callCounter, guestSize, highCq);
|
||||||
}
|
}
|
||||||
@@ -1030,7 +1029,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return osPlatform;
|
return osPlatform;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 86*/)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 87*/)]
|
||||||
private struct OuterHeader
|
private struct OuterHeader
|
||||||
{
|
{
|
||||||
public ulong Magic;
|
public ulong Magic;
|
||||||
@@ -1042,6 +1041,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
public byte MemoryManagerMode;
|
public byte MemoryManagerMode;
|
||||||
public uint OSPlatform;
|
public uint OSPlatform;
|
||||||
public uint Architecture;
|
public uint Architecture;
|
||||||
|
public bool DebuggerMode;
|
||||||
|
|
||||||
public long UncompressedStreamSize;
|
public long UncompressedStreamSize;
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
namespace ARMeilleure.Translation.PTC
|
|
||||||
{
|
|
||||||
public readonly struct PtcCacheInfo
|
|
||||||
{
|
|
||||||
public const string TitleIdTextDefault = "0000000000000000";
|
|
||||||
public const string ApplicationIdTextDefault = "0000000000000000";
|
|
||||||
public const string DisplayVersionDefault = "0";
|
|
||||||
|
|
||||||
public ulong ProcessId { get; }
|
|
||||||
public string TitleIdText { get; }
|
|
||||||
public string ApplicationIdText { get; }
|
|
||||||
public byte ProgramIndex { get; }
|
|
||||||
public string DisplayVersion { get; }
|
|
||||||
public string ProcessKind { get; }
|
|
||||||
public string CacheSelector { get; }
|
|
||||||
|
|
||||||
public string CacheKey => $"{DisplayVersion}-{CacheSelector}";
|
|
||||||
|
|
||||||
public PtcCacheInfo(
|
|
||||||
ulong processId,
|
|
||||||
string titleIdText,
|
|
||||||
string applicationIdText,
|
|
||||||
byte programIndex,
|
|
||||||
string displayVersion,
|
|
||||||
string processKind,
|
|
||||||
string cacheSelector)
|
|
||||||
{
|
|
||||||
ProcessId = processId;
|
|
||||||
TitleIdText = !string.IsNullOrEmpty(titleIdText) ? titleIdText : TitleIdTextDefault;
|
|
||||||
ApplicationIdText = !string.IsNullOrEmpty(applicationIdText) ? applicationIdText : ApplicationIdTextDefault;
|
|
||||||
ProgramIndex = programIndex;
|
|
||||||
DisplayVersion = !string.IsNullOrEmpty(displayVersion) ? displayVersion : DisplayVersionDefault;
|
|
||||||
ProcessKind = processKind ?? string.Empty;
|
|
||||||
CacheSelector = string.IsNullOrEmpty(cacheSelector) ? "default" : cacheSelector;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,13 +9,13 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
using static ARMeilleure.Translation.PTC.PtcFormatter;
|
using static ARMeilleure.Translation.PTC.PtcFormatter;
|
||||||
using Timer = System.Timers.Timer;
|
using Timer = System.Timers.Timer;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Translation.PTC
|
namespace ARMeilleure.Translation.PTC
|
||||||
{
|
{
|
||||||
@@ -23,7 +23,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
private const string OuterHeaderMagicString = "Pohd\0\0\0\0";
|
private const string OuterHeaderMagicString = "Pohd\0\0\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 7031; //! Not to be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 6698; //! Not to be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private static readonly uint[] _migrateInternalVersions =
|
private static readonly uint[] _migrateInternalVersions =
|
||||||
[
|
[
|
||||||
@@ -254,12 +254,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
long fileSize = new FileInfo(fileName).Length;
|
long fileSize = new FileInfo(fileName).Length;
|
||||||
|
|
||||||
Logger.Info?.Print(
|
Logger.Info?.Print(LogClass.Ptc, $"{(isBackup ? "Loaded Backup Profiling Info" : "Loaded Profiling Info")} (size: {fileSize} bytes, profiled functions: {ProfiledFuncs.Count}).");
|
||||||
LogClass.Ptc,
|
|
||||||
$"{(isBackup ? "Loaded Backup Profiling Info" : "Loaded Profiling Info")} " +
|
|
||||||
$"(pid: {_ptc.CacheInfo.ProcessId}, title: {_ptc.CacheInfo.TitleIdText}, version: '{_ptc.CacheInfo.DisplayVersion}', " +
|
|
||||||
$"kind: {_ptc.CacheInfo.ProcessKind}, selector: '{_ptc.CacheInfo.CacheSelector}', key: '{_ptc.CacheInfo.CacheKey}', " +
|
|
||||||
$"path: '{fileName}', size: {fileSize} bytes, profiled functions: {ProfiledFuncs.Count}).");
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -380,11 +375,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
if (fileSize != 0L)
|
if (fileSize != 0L)
|
||||||
{
|
{
|
||||||
Logger.Info?.Print(
|
Logger.Info?.Print(LogClass.Ptc, $"Saved Profiling Info (size: {fileSize} bytes, profiled functions: {profiledFuncsCount}).");
|
||||||
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}).");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,11 @@ namespace ARMeilleure.Translation
|
|||||||
private readonly IJitMemoryAllocator _allocator;
|
private readonly IJitMemoryAllocator _allocator;
|
||||||
private readonly ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>> _oldFuncs;
|
private readonly ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>> _oldFuncs;
|
||||||
|
|
||||||
|
public readonly JitCache JitCache;
|
||||||
private readonly Ptc _ptc;
|
private readonly Ptc _ptc;
|
||||||
|
|
||||||
internal TranslatorCache<TranslatedFunction> Functions { get; }
|
internal TranslatorCache<TranslatedFunction> Functions { get; }
|
||||||
internal IAddressTable<ulong> FunctionTable { get; }
|
public IAddressTable<ulong> FunctionTable { get; }
|
||||||
internal EntryTable<uint> CountTable { get; }
|
internal EntryTable<uint> CountTable { get; }
|
||||||
internal TranslatorStubs Stubs { get; }
|
internal TranslatorStubs Stubs { get; }
|
||||||
internal TranslatorQueue Queue { get; }
|
internal TranslatorQueue Queue { get; }
|
||||||
@@ -43,23 +44,26 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
_oldFuncs = new ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>>();
|
_oldFuncs = new ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>>();
|
||||||
|
|
||||||
_ptc = new Ptc();
|
JitCache = new JitCache(allocator);
|
||||||
|
|
||||||
|
_ptc = new Ptc(JitCache);
|
||||||
|
|
||||||
Queue = new TranslatorQueue();
|
Queue = new TranslatorQueue();
|
||||||
|
|
||||||
JitCache.Initialize(allocator);
|
|
||||||
|
|
||||||
CountTable = new EntryTable<uint>();
|
CountTable = new EntryTable<uint>();
|
||||||
Functions = new TranslatorCache<TranslatedFunction>();
|
Functions = new TranslatorCache<TranslatedFunction>();
|
||||||
|
|
||||||
FunctionTable = functionTable;
|
FunctionTable = functionTable;
|
||||||
Stubs = new TranslatorStubs(FunctionTable);
|
|
||||||
|
Stubs = new TranslatorStubs(JitCache, FunctionTable);
|
||||||
|
|
||||||
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPtcLoadState LoadDiskCache(PtcCacheInfo cacheInfo, bool enabled)
|
public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled, string cacheSelector)
|
||||||
{
|
{
|
||||||
_ptc.Initialize(cacheInfo, enabled, Memory.Type);
|
_ptc.Initialize(titleIdText, displayVersion, enabled, Memory.Type, cacheSelector);
|
||||||
return _ptc;
|
return _ptc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +123,25 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
NativeInterface.RegisterThread(context, Memory, this);
|
NativeInterface.RegisterThread(context, Memory, this);
|
||||||
|
|
||||||
if (Optimizations.UseUnmanagedDispatchLoop)
|
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)
|
||||||
{
|
{
|
||||||
Stubs.DispatchLoop(context.NativeContextPtr, address);
|
Stubs.DispatchLoop(context.NativeContextPtr, address);
|
||||||
}
|
}
|
||||||
@@ -149,6 +171,7 @@ namespace ARMeilleure.Translation
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClearJitCache();
|
ClearJitCache();
|
||||||
|
JitCache.Dispose();
|
||||||
|
|
||||||
Stubs.Dispose();
|
Stubs.Dispose();
|
||||||
FunctionTable.Dispose();
|
FunctionTable.Dispose();
|
||||||
@@ -176,7 +199,7 @@ namespace ARMeilleure.Translation
|
|||||||
return nextAddr;
|
return nextAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong Step(State.ExecutionContext context, ulong address)
|
private ulong Step(State.ExecutionContext context, ulong address)
|
||||||
{
|
{
|
||||||
TranslatedFunction func = Translate(address, context.ExecutionMode, highCq: false, singleStep: true);
|
TranslatedFunction func = Translate(address, context.ExecutionMode, highCq: false, singleStep: true);
|
||||||
|
|
||||||
@@ -187,6 +210,8 @@ namespace ARMeilleure.Translation
|
|||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
internal TranslatedFunction GetOrTranslate(ulong address, ExecutionMode mode)
|
internal TranslatedFunction GetOrTranslate(ulong address, ExecutionMode mode)
|
||||||
{
|
{
|
||||||
if (!Functions.TryGetValue(address, out TranslatedFunction func))
|
if (!Functions.TryGetValue(address, out TranslatedFunction func))
|
||||||
@@ -230,7 +255,8 @@ namespace ARMeilleure.Translation
|
|||||||
address,
|
address,
|
||||||
highCq,
|
highCq,
|
||||||
_ptc.State != PtcState.Disabled,
|
_ptc.State != PtcState.Disabled,
|
||||||
mode: Aarch32Mode.User);
|
mode: Aarch32Mode.User,
|
||||||
|
isSingleStep: singleStep);
|
||||||
|
|
||||||
Logger.StartPass(PassName.Decoding);
|
Logger.StartPass(PassName.Decoding);
|
||||||
|
|
||||||
@@ -284,7 +310,7 @@ namespace ARMeilleure.Translation
|
|||||||
_ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
|
_ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
GuestFunction func = compiledFunc.MapWithPointer<GuestFunction>(out nint funcPointer);
|
GuestFunction func = compiledFunc.MapWithPointer<GuestFunction>(JitCache, out nint funcPointer);
|
||||||
|
|
||||||
Allocators.ResetAll();
|
Allocators.ResetAll();
|
||||||
|
|
||||||
@@ -369,9 +395,13 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
if (block.Exit)
|
if (block.Exit)
|
||||||
{
|
{
|
||||||
// Left option here as it may be useful if we need to return to managed rather than tail call in
|
// Return to managed rather than tail call.
|
||||||
// future. (eg. for debug)
|
bool useReturns = Optimizations.EnableDebugging;
|
||||||
bool useReturns = false;
|
|
||||||
|
if (Optimizations.EnableDebugging)
|
||||||
|
{
|
||||||
|
EmitDebugPrecisePcUpdate(context, block.Address);
|
||||||
|
}
|
||||||
|
|
||||||
InstEmitFlowHelper.EmitVirtualJump(context, Const(block.Address), isReturn: useReturns);
|
InstEmitFlowHelper.EmitVirtualJump(context, Const(block.Address), isReturn: useReturns);
|
||||||
}
|
}
|
||||||
@@ -395,6 +425,11 @@ namespace ARMeilleure.Translation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Optimizations.EnableDebugging)
|
||||||
|
{
|
||||||
|
EmitDebugPrecisePcUpdate(context, opCode.Address);
|
||||||
|
}
|
||||||
|
|
||||||
Operand lblPredicateSkip = default;
|
Operand lblPredicateSkip = default;
|
||||||
|
|
||||||
if (context.IsInIfThenBlock && context.CurrentIfThenBlockCond != Condition.Al)
|
if (context.IsInIfThenBlock && context.CurrentIfThenBlockCond != Condition.Al)
|
||||||
@@ -491,6 +526,14 @@ namespace ARMeilleure.Translation
|
|||||||
context.MarkLabel(lblExit);
|
context.MarkLabel(lblExit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void EmitDebugPrecisePcUpdate(EmitterContext context, ulong address)
|
||||||
|
{
|
||||||
|
long debugPrecisePcOffs = NativeContext.GetDebugPrecisePcOffset();
|
||||||
|
|
||||||
|
Operand debugPrecisePcAddr = context.Add(context.LoadArgument(OperandType.I64, 0), Const(debugPrecisePcOffs));
|
||||||
|
context.Store(debugPrecisePcAddr, Const(address));
|
||||||
|
}
|
||||||
|
|
||||||
public void InvalidateJitCacheRegion(ulong address, ulong size)
|
public void InvalidateJitCacheRegion(ulong address, ulong size)
|
||||||
{
|
{
|
||||||
ulong[] overlapAddresses = [];
|
ulong[] overlapAddresses = [];
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ namespace ARMeilleure.Translation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
class TranslatorStubs : IDisposable
|
class TranslatorStubs : IDisposable
|
||||||
{
|
{
|
||||||
|
private readonly JitCache _jitCache;
|
||||||
|
|
||||||
private readonly Lazy<nint> _slowDispatchStub;
|
private readonly Lazy<nint> _slowDispatchStub;
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
@@ -83,12 +85,15 @@ namespace ARMeilleure.Translation
|
|||||||
/// Initializes a new instance of the <see cref="TranslatorStubs"/> class with the specified
|
/// Initializes a new instance of the <see cref="TranslatorStubs"/> class with the specified
|
||||||
/// <see cref="Translator"/> instance.
|
/// <see cref="Translator"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="jitCache">Jit cache to map functions in</param>
|
||||||
/// <param name="functionTable">Function table used to store pointers to the functions that the guest code will call</param>
|
/// <param name="functionTable">Function table used to store pointers to the functions that the guest code will call</param>
|
||||||
/// <exception cref="ArgumentNullException"><paramref name="translator"/> is null</exception>
|
/// <exception cref="ArgumentNullException"><paramref name="translator"/> is null</exception>
|
||||||
public TranslatorStubs(IAddressTable<ulong> functionTable)
|
public TranslatorStubs(JitCache jitCache, IAddressTable<ulong> functionTable)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(functionTable);
|
ArgumentNullException.ThrowIfNull(functionTable);
|
||||||
|
|
||||||
|
_jitCache = jitCache;
|
||||||
|
|
||||||
_functionTable = functionTable;
|
_functionTable = functionTable;
|
||||||
_slowDispatchStub = new(GenerateSlowDispatchStub, isThreadSafe: true);
|
_slowDispatchStub = new(GenerateSlowDispatchStub, isThreadSafe: true);
|
||||||
_dispatchStub = new(GenerateDispatchStub, isThreadSafe: true);
|
_dispatchStub = new(GenerateDispatchStub, isThreadSafe: true);
|
||||||
@@ -115,12 +120,12 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
if (_dispatchStub.IsValueCreated)
|
if (_dispatchStub.IsValueCreated)
|
||||||
{
|
{
|
||||||
JitCache.Unmap(_dispatchStub.Value);
|
_jitCache.Unmap(_dispatchStub.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_dispatchLoop.IsValueCreated)
|
if (_dispatchLoop.IsValueCreated)
|
||||||
{
|
{
|
||||||
JitCache.Unmap(Marshal.GetFunctionPointerForDelegate(_dispatchLoop.Value));
|
_jitCache.Unmap(Marshal.GetFunctionPointerForDelegate(_dispatchLoop.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
@@ -188,7 +193,7 @@ namespace ARMeilleure.Translation
|
|||||||
OperandType retType = OperandType.I64;
|
OperandType retType = OperandType.I64;
|
||||||
OperandType[] argTypes = new[] { OperandType.I64 };
|
OperandType[] argTypes = new[] { OperandType.I64 };
|
||||||
|
|
||||||
GuestFunction 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>(_jitCache);
|
||||||
|
|
||||||
return Marshal.GetFunctionPointerForDelegate(func);
|
return Marshal.GetFunctionPointerForDelegate(func);
|
||||||
}
|
}
|
||||||
@@ -213,7 +218,7 @@ namespace ARMeilleure.Translation
|
|||||||
OperandType retType = OperandType.I64;
|
OperandType retType = OperandType.I64;
|
||||||
OperandType[] argTypes = new[] { OperandType.I64 };
|
OperandType[] argTypes = new[] { OperandType.I64 };
|
||||||
|
|
||||||
GuestFunction 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>(_jitCache);
|
||||||
|
|
||||||
return Marshal.GetFunctionPointerForDelegate(func);
|
return Marshal.GetFunctionPointerForDelegate(func);
|
||||||
}
|
}
|
||||||
@@ -290,7 +295,7 @@ namespace ARMeilleure.Translation
|
|||||||
OperandType retType = OperandType.None;
|
OperandType retType = OperandType.None;
|
||||||
OperandType[] argTypes = new[] { OperandType.I64, OperandType.I64 };
|
OperandType[] argTypes = new[] { OperandType.I64, OperandType.I64 };
|
||||||
|
|
||||||
return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DispatcherFunction>();
|
return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DispatcherFunction>(_jitCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -314,7 +319,7 @@ namespace ARMeilleure.Translation
|
|||||||
OperandType retType = OperandType.I64;
|
OperandType retType = OperandType.I64;
|
||||||
OperandType[] argTypes = new[] { OperandType.I64, OperandType.I64 };
|
OperandType[] argTypes = new[] { OperandType.I64, OperandType.I64 };
|
||||||
|
|
||||||
return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<WrapperFunction>();
|
return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<WrapperFunction>(_jitCache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using ARMeilleure.CodeGen.X86;
|
using ARMeilleure.CodeGen.X86;
|
||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
|
using ARMeilleure.Translation.Cache;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||||
@@ -59,7 +60,7 @@ namespace ARMeilleure.Translation
|
|||||||
return context.VectorExtract(OperandType.I32, vec, 0);
|
return context.VectorExtract(OperandType.I32, vec, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FpFlagsPInvokeTest GenerateFpFlagsPInvokeTest()
|
public static FpFlagsPInvokeTest GenerateFpFlagsPInvokeTest(JitCache jitCache)
|
||||||
{
|
{
|
||||||
EmitterContext context = new();
|
EmitterContext context = new();
|
||||||
|
|
||||||
@@ -141,7 +142,7 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
OperandType[] argTypes = [OperandType.I64];
|
OperandType[] argTypes = [OperandType.I64];
|
||||||
|
|
||||||
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<FpFlagsPInvokeTest>();
|
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<FpFlagsPInvokeTest>(jitCache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
.idea/
|
|
||||||
*.iml
|
|
||||||
.gradle
|
|
||||||
local.properties
|
|
||||||
.DS_Store
|
|
||||||
build/
|
|
||||||
captures
|
|
||||||
.externalNativeBuild
|
|
||||||
.cxx/
|
|
||||||
|
|
||||||
app/src/main/jniLibs/arm64-v8a/**
|
|
||||||
!app/src/main/jniLibs/arm64-v8a/.gitkeep
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
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
@@ -1,37 +0,0 @@
|
|||||||
-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*();
|
|
||||||
}
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
<?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>
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
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}
|
|
||||||
)
|
|
||||||
@@ -1,254 +0,0 @@
|
|||||||
// 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;
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
//
|
|
||||||
// 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 deleted from 8fae8ce254
Submodule src/KenjinxAndroid/app/src/main/cpp/libraries/openal deleted from c41d64c6a3
@@ -1,305 +0,0 @@
|
|||||||
// 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);
|
|
||||||
};
|
|
||||||
@@ -1,404 +0,0 @@
|
|||||||
// 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;
|
|
||||||
|
|
||||||
@@ -1,236 +0,0 @@
|
|||||||
// 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.
|
Before Width: | Height: | Size: 14 KiB |
@@ -1,7 +0,0 @@
|
|||||||
package org.kenjinx.android
|
|
||||||
|
|
||||||
enum class BackendThreading {
|
|
||||||
Auto,
|
|
||||||
Off,
|
|
||||||
On
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package org.kenjinx.android
|
|
||||||
|
|
||||||
import androidx.activity.ComponentActivity
|
|
||||||
|
|
||||||
abstract class BaseActivity : ComponentActivity() {
|
|
||||||
companion object {
|
|
||||||
val crashHandler = CrashHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,436 +0,0 @@
|
|||||||
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()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,420 +0,0 @@
|
|||||||
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()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,413 +0,0 @@
|
|||||||
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()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,410 +0,0 @@
|
|||||||
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()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,414 +0,0 @@
|
|||||||
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()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,411 +0,0 @@
|
|||||||
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()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,510 +0,0 @@
|
|||||||
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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package org.kenjinx.android
|
|
||||||
|
|
||||||
interface IGameController {
|
|
||||||
val isVisible: Boolean
|
|
||||||
fun setVisible(isVisible: Boolean)
|
|
||||||
fun connect()
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +0,0 @@
|
|||||||
package org.kenjinx.android
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.content.Context
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class KenjinxApplication : Application() {
|
|
||||||
init {
|
|
||||||
instance = this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
lateinit var instance: KenjinxApplication
|
|
||||||
private set
|
|
||||||
|
|
||||||
val context: Context get() = instance.applicationContext
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,371 +0,0 @@
|
|||||||
package org.kenjinx.android
|
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
import com.sun.jna.JNIEnv
|
|
||||||
import com.sun.jna.Library
|
|
||||||
import com.sun.jna.Native
|
|
||||||
import org.kenjinx.android.viewmodels.GameInfo
|
|
||||||
import java.util.Collections
|
|
||||||
import android.view.Surface
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
|
|
||||||
interface KenjinxNativeJna : Library {
|
|
||||||
fun deviceInitialize(
|
|
||||||
memoryManagerMode: Int,
|
|
||||||
useNce: Boolean,
|
|
||||||
memoryConfiguration: Int,
|
|
||||||
systemLanguage: Int,
|
|
||||||
regionCode: Int,
|
|
||||||
vSyncMode: Int,
|
|
||||||
enableDockedMode: Boolean,
|
|
||||||
enablePptc: Boolean,
|
|
||||||
enableLowPowerPptc: Boolean,
|
|
||||||
enableJitCacheEviction: Boolean,
|
|
||||||
enableInternetAccess: Boolean,
|
|
||||||
enableFsIntegrityChecks: Boolean,
|
|
||||||
fsGlobalAccessLogMode: Int,
|
|
||||||
timeZone: String,
|
|
||||||
ignoreMissingServices: Boolean
|
|
||||||
): Boolean
|
|
||||||
|
|
||||||
fun graphicsInitialize(
|
|
||||||
rescale: Float = 1f,
|
|
||||||
maxAnisotropy: Float = 0f,
|
|
||||||
fastGpuTime: Boolean = true,
|
|
||||||
fast2DCopy: Boolean = true,
|
|
||||||
enableMacroJit: Boolean = false,
|
|
||||||
enableMacroHLE: Boolean = true,
|
|
||||||
enableShaderCache: Boolean = true,
|
|
||||||
enableTextureRecompression: Boolean = false,
|
|
||||||
backendThreading: Int = BackendThreading.Auto.ordinal
|
|
||||||
): Boolean
|
|
||||||
|
|
||||||
fun graphicsInitializeRenderer(
|
|
||||||
extensions: Array<String>,
|
|
||||||
extensionsLength: Int,
|
|
||||||
driver: Long
|
|
||||||
): Boolean
|
|
||||||
|
|
||||||
fun javaInitialize(appPath: String, env: JNIEnv): Boolean
|
|
||||||
fun deviceLaunchMiiEditor(): Boolean
|
|
||||||
fun deviceGetGameFrameRate(): Double
|
|
||||||
fun deviceGetGameFrameTime(): Double
|
|
||||||
fun deviceGetGameFifo(): Double
|
|
||||||
fun deviceLoadDescriptor(fileDescriptor: Int, gameType: Int, updateDescriptor: Int): Boolean
|
|
||||||
fun graphicsRendererSetSize(width: Int, height: Int)
|
|
||||||
fun graphicsRendererSetVsync(vSyncMode: Int)
|
|
||||||
fun graphicsRendererRunLoop()
|
|
||||||
fun graphicsSetFullscreenStretch(enable: Boolean)
|
|
||||||
fun deviceReloadFilesystem()
|
|
||||||
fun inputInitialize(width: Int, height: Int)
|
|
||||||
fun inputSetClientSize(width: Int, height: Int)
|
|
||||||
fun inputSetTouchPoint(x: Int, y: Int)
|
|
||||||
fun inputReleaseTouchPoint()
|
|
||||||
fun inputUpdate()
|
|
||||||
fun inputSetButtonPressed(button: Int, id: Int)
|
|
||||||
fun inputSetButtonReleased(button: Int, id: Int)
|
|
||||||
fun inputConnectGamepad(index: Int): Int
|
|
||||||
fun inputSetStickAxis(stick: Int, x: Float, y: Float, id: Int)
|
|
||||||
fun inputSetAccelerometerData(x: Float, y: Float, z: Float, id: Int)
|
|
||||||
fun inputSetGyroData(x: Float, y: Float, z: Float, id: Int)
|
|
||||||
fun deviceCloseEmulation()
|
|
||||||
fun deviceReinitEmulation()
|
|
||||||
fun deviceSignalEmulationClose()
|
|
||||||
|
|
||||||
fun detachWindow()
|
|
||||||
// >>> Rendering-related additions for the toggle:
|
|
||||||
fun deviceWaitForGpuDone(timeoutMs: Int)
|
|
||||||
fun deviceRecreateSwapchain()
|
|
||||||
fun graphicsSetBackendThreading(mode: Int)
|
|
||||||
fun graphicsSetPresentEnabled(enabled: Boolean)
|
|
||||||
// <<<
|
|
||||||
|
|
||||||
fun userGetOpenedUser(): String
|
|
||||||
fun userGetUserPicture(userId: String): String
|
|
||||||
fun userSetUserPicture(userId: String, picture: String)
|
|
||||||
fun userGetUserName(userId: String): String
|
|
||||||
fun userSetUserName(userId: String, userName: String)
|
|
||||||
fun userAddUser(username: String, picture: String)
|
|
||||||
fun userDeleteUser(userId: String)
|
|
||||||
fun userOpenUser(userId: String)
|
|
||||||
fun userCloseUser(userId: String)
|
|
||||||
fun loggingSetEnabled(logLevel: Int, enabled: Boolean)
|
|
||||||
fun deviceVerifyFirmware(fileDescriptor: Int, isXci: Boolean): String
|
|
||||||
fun deviceInstallFirmware(fileDescriptor: Int, isXci: Boolean)
|
|
||||||
fun deviceGetInstalledFirmwareVersion(): String
|
|
||||||
fun uiHandlerSetup()
|
|
||||||
fun uiHandlerSetResponse(isOkPressed: Boolean, input: String)
|
|
||||||
fun deviceGetDlcTitleId(path: String, ncaPath: String): String
|
|
||||||
fun deviceGetGameInfo(fileDescriptor: Int, extension: String, info: GameInfo)
|
|
||||||
fun userGetAllUsers(): Array<String>
|
|
||||||
fun deviceGetDlcContentList(path: String, titleId: Long): Array<String>
|
|
||||||
fun loggingEnabledGraphicsLog(enabled: Boolean)
|
|
||||||
// Surface rotation (0/90/180/270 degrees)
|
|
||||||
fun deviceSetSurfaceRotation(degrees: Int)
|
|
||||||
// (optional alias): compact resize shortcut
|
|
||||||
fun deviceResize(width: Int, height: Int)
|
|
||||||
// Set window handle after each query
|
|
||||||
fun deviceSetWindowHandle(handle: Long)
|
|
||||||
// Amiibo
|
|
||||||
fun amiiboLoadBin(bytes: ByteArray, length: Int): Boolean
|
|
||||||
fun amiiboClear()
|
|
||||||
|
|
||||||
// AUDIO: Direct JNA bridge to C# exports
|
|
||||||
fun audioSetPaused(paused: Boolean)
|
|
||||||
fun audioSetMuted(muted: Boolean)
|
|
||||||
}
|
|
||||||
|
|
||||||
val jnaInstance: KenjinxNativeJna = Native.load(
|
|
||||||
"kenjinx",
|
|
||||||
KenjinxNativeJna::class.java,
|
|
||||||
Collections.singletonMap(Library.OPTION_ALLOW_OBJECTS, true)
|
|
||||||
)
|
|
||||||
|
|
||||||
object KenjinxNative : KenjinxNativeJna by jnaInstance {
|
|
||||||
|
|
||||||
fun loggingSetEnabled(logLevel: LogLevel, enabled: Boolean) =
|
|
||||||
loggingSetEnabled(logLevel.ordinal, enabled)
|
|
||||||
|
|
||||||
// --- Rendering: Single-threaded option & secure wrappers --------------------
|
|
||||||
|
|
||||||
// 0 = Auto, 1 = SingleThread (Disable Threaded), 2 = Threaded
|
|
||||||
private const val THREADING_AUTO = 0
|
|
||||||
private const val THREADING_SINGLE = 1
|
|
||||||
private const val THREADING_THREADED = 2
|
|
||||||
|
|
||||||
override fun graphicsSetBackendThreading(mode: Int) {
|
|
||||||
try {
|
|
||||||
jnaInstance.graphicsSetBackendThreading(mode)
|
|
||||||
} catch (_: Throwable) {
|
|
||||||
Log.w("KenjinxNative", "graphicsSetBackendThreading not available")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun deviceRecreateSwapchain() {
|
|
||||||
try { jnaInstance.deviceRecreateSwapchain() } catch (_: Throwable) { /* ignore */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun deviceWaitForGpuDone(timeoutMs: Int) {
|
|
||||||
try { jnaInstance.deviceWaitForGpuDone(timeoutMs) } catch (_: Throwable) { /* ignore */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun graphicsSetPresentEnabled(enabled: Boolean) {
|
|
||||||
try { jnaInstance.graphicsSetPresentEnabled(enabled) } catch (_: Throwable) { /* ignore */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Secure deviceResize implementation (pure rendering)
|
|
||||||
override fun deviceResize(width: Int, height: Int) {
|
|
||||||
try {
|
|
||||||
graphicsRendererSetSize(width, height)
|
|
||||||
inputSetClientSize(width, height)
|
|
||||||
} catch (_: Throwable) { /* ignore */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Robust graphicsInitialize with QCOM heuristics + fallback → SingleThread
|
|
||||||
override fun graphicsInitialize(
|
|
||||||
rescale: Float,
|
|
||||||
maxAnisotropy: Float,
|
|
||||||
fastGpuTime: Boolean,
|
|
||||||
fast2DCopy: Boolean,
|
|
||||||
enableMacroJit: Boolean,
|
|
||||||
enableMacroHLE: Boolean,
|
|
||||||
enableShaderCache: Boolean,
|
|
||||||
enableTextureRecompression: Boolean,
|
|
||||||
backendThreading: Int
|
|
||||||
): Boolean {
|
|
||||||
val requested = backendThreading
|
|
||||||
val isQcom = "qcom".equals(Build.HARDWARE, true)
|
|
||||||
|
|
||||||
// Heuristic: On QCOM, when "Auto" is selected, first try single-threaded mode;
|
|
||||||
// explicitly set values remain unchanged.
|
|
||||||
val firstChoice =
|
|
||||||
if (isQcom && requested == THREADING_AUTO) THREADING_SINGLE else requested
|
|
||||||
|
|
||||||
Log.i(
|
|
||||||
"KenjinxNative",
|
|
||||||
"graphicsInitialize: request=$requested firstChoice=$firstChoice hw=${Build.HARDWARE}"
|
|
||||||
)
|
|
||||||
|
|
||||||
return try {
|
|
||||||
jnaInstance.graphicsInitialize(
|
|
||||||
rescale,
|
|
||||||
maxAnisotropy,
|
|
||||||
fastGpuTime,
|
|
||||||
fast2DCopy,
|
|
||||||
enableMacroJit,
|
|
||||||
enableMacroHLE,
|
|
||||||
enableShaderCache,
|
|
||||||
enableTextureRecompression,
|
|
||||||
firstChoice
|
|
||||||
)
|
|
||||||
} catch (t: Throwable) {
|
|
||||||
Log.e(
|
|
||||||
"KenjinxNative",
|
|
||||||
"graphicsInitialize failed (firstChoice=$firstChoice). Fallback → SingleThread",
|
|
||||||
t
|
|
||||||
)
|
|
||||||
try {
|
|
||||||
jnaInstance.graphicsInitialize(
|
|
||||||
rescale,
|
|
||||||
maxAnisotropy,
|
|
||||||
fastGpuTime,
|
|
||||||
fast2DCopy,
|
|
||||||
enableMacroJit,
|
|
||||||
enableMacroHLE,
|
|
||||||
enableShaderCache,
|
|
||||||
enableTextureRecompression,
|
|
||||||
THREADING_SINGLE
|
|
||||||
)
|
|
||||||
} catch (t2: Throwable) {
|
|
||||||
Log.e("KenjinxNative", "graphicsInitialize fallback failed", t2)
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Optional wrappers for audio (safer logging) ---
|
|
||||||
override fun audioSetPaused(paused: Boolean) {
|
|
||||||
try { jnaInstance.audioSetPaused(paused) }
|
|
||||||
catch (t: Throwable) { Log.w("KenjinxNative", "audioSetPaused unavailable", t) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun audioSetMuted(muted: Boolean) {
|
|
||||||
try { jnaInstance.audioSetMuted(muted) }
|
|
||||||
catch (t: Throwable) { Log.w("KenjinxNative", "audioSetMuted unavailable", t) }
|
|
||||||
}
|
|
||||||
// ----------------------------------------------------
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.R)
|
|
||||||
@JvmStatic
|
|
||||||
fun frameEnded() = MainActivity.frameEnded()
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun test() { /* no-op */ }
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun getSurfacePtr(): Long = MainActivity.mainViewModel?.gameHost?.currentSurface ?: -1
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun getWindowHandle(): Long =
|
|
||||||
MainActivity.mainViewModel?.gameHost?.currentWindowHandle ?: -1
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun updateProgress(infoPtr: Long, progress: Float) {
|
|
||||||
// Get string from native pointer and push into progress overlay
|
|
||||||
val text = NativeHelpers.instance.getStringJava(infoPtr)
|
|
||||||
MainActivity.mainViewModel?.gameHost?.setProgress(text, progress)
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun onSurfaceSizeChanged(width: Int, height: Int) {
|
|
||||||
// No-Op: Placeholder – Hook if needed.
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun setSurfaceRotationByAndroidRotation(androidRotation: Int?) {
|
|
||||||
val degrees = when (androidRotation) {
|
|
||||||
Surface.ROTATION_0 -> 0
|
|
||||||
Surface.ROTATION_90 -> 90
|
|
||||||
Surface.ROTATION_180 -> 180
|
|
||||||
Surface.ROTATION_270 -> 270
|
|
||||||
else -> 0
|
|
||||||
}
|
|
||||||
try { deviceSetSurfaceRotation(degrees) } catch (_: Throwable) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun resizeRendererAndInput(width: Int, height: Int) {
|
|
||||||
try {
|
|
||||||
// Alternatively: deviceResize(width, height)
|
|
||||||
graphicsRendererSetSize(width, height)
|
|
||||||
inputSetClientSize(width, height)
|
|
||||||
} catch (_: Throwable) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun detachWindow() {
|
|
||||||
try { graphicsSetPresentEnabled(false) } catch (_: Throwable) {}
|
|
||||||
try { deviceWaitForGpuDone(100) } catch (_: Throwable) {}
|
|
||||||
try { jnaInstance.detachWindow() } catch (_: Throwable) {}
|
|
||||||
try { deviceSetWindowHandle(0) } catch (_: Throwable) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun reattachWindowIfReady(): Boolean {
|
|
||||||
return try {
|
|
||||||
val handle = getWindowHandle()
|
|
||||||
if (handle <= 0) return false
|
|
||||||
deviceSetWindowHandle(handle)
|
|
||||||
deviceRecreateSwapchain()
|
|
||||||
true
|
|
||||||
} catch (_: Throwable) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Variant A (Pointer → Strings via NativeHelpers).
|
|
||||||
* Used by older JNI/Interop paths.
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun updateUiHandler(
|
|
||||||
newTitlePointer: Long,
|
|
||||||
newMessagePointer: Long,
|
|
||||||
newWatermarkPointer: Long,
|
|
||||||
newType: Int,
|
|
||||||
min: Int,
|
|
||||||
max: Int,
|
|
||||||
nMode: Int,
|
|
||||||
newSubtitlePointer: Long,
|
|
||||||
newInitialTextPointer: Long
|
|
||||||
) {
|
|
||||||
val title = NativeHelpers.instance.getStringJava(newTitlePointer)
|
|
||||||
val message = NativeHelpers.instance.getStringJava(newMessagePointer)
|
|
||||||
val watermark = NativeHelpers.instance.getStringJava(newWatermarkPointer)
|
|
||||||
val subtitle = NativeHelpers.instance.getStringJava(newSubtitlePointer)
|
|
||||||
val initialText = NativeHelpers.instance.getStringJava(newInitialTextPointer)
|
|
||||||
val mode = KeyboardMode.entries.getOrNull(nMode) ?: KeyboardMode.Default
|
|
||||||
|
|
||||||
MainActivity.mainViewModel?.activity?.uiHandler?.update(
|
|
||||||
newTitle = title,
|
|
||||||
newMessage = message,
|
|
||||||
newWatermark = watermark,
|
|
||||||
newType = newType,
|
|
||||||
min = min,
|
|
||||||
max = max,
|
|
||||||
newMode = mode,
|
|
||||||
newSubtitle = subtitle,
|
|
||||||
newInitialText = initialText
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Variant B (strings directly). Used by newer JNI/interop paths.
|
|
||||||
* Signature exactly matches the C# call in AndroidUIHandler.cs / Interop.UpdateUiHandler(...).
|
|
||||||
*/
|
|
||||||
@JvmStatic
|
|
||||||
fun uiHandlerUpdate(
|
|
||||||
title: String,
|
|
||||||
message: String,
|
|
||||||
watermark: String,
|
|
||||||
type: Int,
|
|
||||||
min: Int,
|
|
||||||
max: Int,
|
|
||||||
nMode: Int,
|
|
||||||
subtitle: String,
|
|
||||||
initialText: String
|
|
||||||
) {
|
|
||||||
val mode = KeyboardMode.entries.getOrNull(nMode) ?: KeyboardMode.Default
|
|
||||||
MainActivity.mainViewModel?.activity?.uiHandler?.update(
|
|
||||||
newTitle = title,
|
|
||||||
newMessage = message,
|
|
||||||
newWatermark = watermark,
|
|
||||||
newType = type,
|
|
||||||
min = min,
|
|
||||||
max = max,
|
|
||||||
newMode = mode,
|
|
||||||
newSubtitle = subtitle,
|
|
||||||
newInitialText = initialText
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
package org.kenjinx.android
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.core.content.FileProvider
|
|
||||||
import net.lingala.zip4j.ZipFile
|
|
||||||
import org.kenjinx.android.viewmodels.MainViewModel
|
|
||||||
import java.io.File
|
|
||||||
import java.net.URLConnection
|
|
||||||
|
|
||||||
class Logging(private var viewModel: MainViewModel) {
|
|
||||||
val logPath = MainActivity.AppPath + "/Logs"
|
|
||||||
|
|
||||||
init {
|
|
||||||
File(logPath).mkdirs()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun requestExport() {
|
|
||||||
val files = File(logPath).listFiles()
|
|
||||||
files?.apply {
|
|
||||||
val zipExportPath = MainActivity.AppPath + "/log.zip"
|
|
||||||
File(zipExportPath).delete()
|
|
||||||
var count = 0
|
|
||||||
if (files.isNotEmpty()) {
|
|
||||||
val zipFile = ZipFile(zipExportPath)
|
|
||||||
for (file in files) {
|
|
||||||
if (file.isFile) {
|
|
||||||
zipFile.addFile(file)
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
zipFile.close()
|
|
||||||
}
|
|
||||||
if (count > 0) {
|
|
||||||
val zip = File(zipExportPath)
|
|
||||||
val uri = FileProvider.getUriForFile(
|
|
||||||
viewModel.activity,
|
|
||||||
viewModel.activity.packageName + ".fileprovider",
|
|
||||||
zip
|
|
||||||
)
|
|
||||||
val intent = Intent(Intent.ACTION_SEND)
|
|
||||||
intent.putExtra(Intent.EXTRA_STREAM, uri)
|
|
||||||
intent.setDataAndType(uri, URLConnection.guessContentTypeFromName(zip.name))
|
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
|
||||||
val chooser = Intent.createChooser(intent, "Share logs")
|
|
||||||
viewModel.activity.startActivity(chooser)
|
|
||||||
} else {
|
|
||||||
File(zipExportPath).delete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clearLogs() {
|
|
||||||
if (File(logPath).exists()) {
|
|
||||||
File(logPath).deleteRecursively()
|
|
||||||
}
|
|
||||||
|
|
||||||
File(logPath).mkdirs()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class LogLevel {
|
|
||||||
Debug, Stub, Info, Warning, Error, Guest, AccessLog, Notice, Trace
|
|
||||||
}
|
|
||||||
@@ -1,734 +0,0 @@
|
|||||||
package org.kenjinx.android
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.os.Environment
|
|
||||||
import android.view.KeyEvent
|
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.WindowManager
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.activity.compose.setContent
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.core.net.toUri
|
|
||||||
import androidx.core.view.WindowCompat
|
|
||||||
import androidx.core.view.WindowInsetsCompat
|
|
||||||
import androidx.core.view.WindowInsetsControllerCompat
|
|
||||||
import androidx.documentfile.provider.DocumentFile
|
|
||||||
import com.anggrayudi.storage.SimpleStorageHelper
|
|
||||||
import com.sun.jna.JNIEnv
|
|
||||||
import org.kenjinx.android.ui.theme.KenjinxAndroidTheme
|
|
||||||
import org.kenjinx.android.viewmodels.MainViewModel
|
|
||||||
import org.kenjinx.android.viewmodels.QuickSettings
|
|
||||||
import org.kenjinx.android.viewmodels.GameModel
|
|
||||||
import org.kenjinx.android.views.MainView
|
|
||||||
import android.content.pm.ActivityInfo
|
|
||||||
import android.content.res.Configuration
|
|
||||||
import android.hardware.display.DisplayManager
|
|
||||||
import android.net.Uri
|
|
||||||
import android.view.Surface
|
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import java.io.File
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import android.Manifest
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.IntentFilter
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Build
|
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import org.kenjinx.android.service.EmulationService
|
|
||||||
import androidx.core.content.edit
|
|
||||||
|
|
||||||
class MainActivity : BaseActivity() {
|
|
||||||
private var physicalControllerManager: PhysicalControllerManager =
|
|
||||||
PhysicalControllerManager(this)
|
|
||||||
private lateinit var motionSensorManager: MotionSensorManager
|
|
||||||
private var _isInit: Boolean = false
|
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
|
||||||
private val ENABLE_PRESENT_DELAY_MS = 400L
|
|
||||||
private val REATTACH_DELAY_MS = 300L
|
|
||||||
private var wantPresentEnabled = false
|
|
||||||
private val TAG_FG = "FgPresent"
|
|
||||||
private val delayedHandleIntent = object : Runnable { override fun run() { handleIntent() } }
|
|
||||||
var storedIntent: Intent = Intent()
|
|
||||||
var isGameRunning = false
|
|
||||||
var isActive = false
|
|
||||||
var storageHelper: SimpleStorageHelper? = null
|
|
||||||
lateinit var uiHandler: UiHandler
|
|
||||||
|
|
||||||
// Persistence for zombie detection
|
|
||||||
private val PREFS = "emu_core"
|
|
||||||
private val KEY_EMU_RUNNING = "emu_running"
|
|
||||||
|
|
||||||
// Display Rotation + Orientation Handling
|
|
||||||
private lateinit var displayManager: DisplayManager
|
|
||||||
private var lastKnownRotation: Int? = null
|
|
||||||
private var pulsingOrientation = false
|
|
||||||
private var lastPulseAt = 0L
|
|
||||||
|
|
||||||
private val TAG_ROT = "RotationDebug"
|
|
||||||
|
|
||||||
private fun rotLog(msg: String) {
|
|
||||||
val enabled = BuildConfig.DEBUG && QuickSettings(this).enableDebugLogs
|
|
||||||
if (enabled) Log.d(TAG_ROT, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val serviceStopReceiver = object : BroadcastReceiver() {
|
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
|
||||||
if (intent?.action == EmulationService.ACTION_STOPPED) {
|
|
||||||
handler.removeCallbacks(reattachWindowWhenReady)
|
|
||||||
handler.removeCallbacks(enablePresentWhenReady)
|
|
||||||
clearEmuRunningFlag()
|
|
||||||
hardColdReset("service stopped broadcast")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val displayListener = object : DisplayManager.DisplayListener {
|
|
||||||
override fun onDisplayAdded(displayId: Int) {}
|
|
||||||
override fun onDisplayRemoved(displayId: Int) {}
|
|
||||||
override fun onDisplayChanged(displayId: Int) {
|
|
||||||
if (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
||||||
display?.displayId != displayId
|
|
||||||
} else {
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
) return
|
|
||||||
val rot = display?.rotation
|
|
||||||
if (rot == lastKnownRotation) return
|
|
||||||
|
|
||||||
rotLog("onDisplayChanged: display.rotation=$rot → ${deg(rot)}°")
|
|
||||||
|
|
||||||
val pref = QuickSettings(this@MainActivity).orientationPreference
|
|
||||||
val old = lastKnownRotation
|
|
||||||
lastKnownRotation = rot
|
|
||||||
|
|
||||||
// 1) Inform Native/Renderer (applies to Sensor & SensorLandscape)
|
|
||||||
try { KenjinxNative.setSurfaceRotationByAndroidRotation(rot) } catch (_: Throwable) {}
|
|
||||||
|
|
||||||
// 2) Initiate host resize (applies to Sensor & SensorLandscape)
|
|
||||||
if (isGameRunning) {
|
|
||||||
handler.post {
|
|
||||||
try { mainViewModel?.gameHost?.onOrientationOrSizeChanged(rot) } catch (_: Throwable) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3) Only with SENSOR_LANDSCAPE: gentle pulse with real 90↔270 flip
|
|
||||||
if (pref == QuickSettings.OrientationPreference.SensorLandscape && old != null && rot != null) {
|
|
||||||
val isSideFlip = (old == Surface.ROTATION_90 && rot == Surface.ROTATION_270) ||
|
|
||||||
(old == Surface.ROTATION_270 && rot == Surface.ROTATION_90)
|
|
||||||
if (isSideFlip) doOrientationPulse(rot)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun deg(r: Int?): Int = when (r) {
|
|
||||||
Surface.ROTATION_0 -> 0
|
|
||||||
Surface.ROTATION_90 -> 90
|
|
||||||
Surface.ROTATION_180 -> 180
|
|
||||||
Surface.ROTATION_270 -> 270
|
|
||||||
else -> -1
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setPresentEnabled(enabled: Boolean, reason: String) {
|
|
||||||
wantPresentEnabled = enabled
|
|
||||||
try {
|
|
||||||
KenjinxNative.graphicsSetPresentEnabled(enabled)
|
|
||||||
Log.d(TAG_FG, "present=${if (enabled) "ENABLED" else "DISABLED"} ($reason)")
|
|
||||||
} catch (_: Throwable) {
|
|
||||||
Log.d(TAG_FG, "native toggle not available ($reason)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val enablePresentWhenReady = object : Runnable {
|
|
||||||
override fun run() {
|
|
||||||
val isReallyResumed = lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED) && isActive
|
|
||||||
val hasFocusNow = hasWindowFocus()
|
|
||||||
val rendererReady = mainViewModel?.rendererReady == true
|
|
||||||
|
|
||||||
if (!isReallyResumed || !hasFocusNow || !rendererReady) {
|
|
||||||
handler.postDelayed(this, ENABLE_PRESENT_DELAY_MS)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setPresentEnabled(true, "focus regained + delay")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val reattachWindowWhenReady = object : Runnable {
|
|
||||||
override fun run() {
|
|
||||||
val isReallyResumed = lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED) && isActive
|
|
||||||
val hasFocusNow = hasWindowFocus()
|
|
||||||
if (!isReallyResumed || !hasFocusNow) {
|
|
||||||
handler.postDelayed(this, REATTACH_DELAY_MS)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try { mainViewModel?.gameHost?.rebindNativeWindow(force = true) } catch (_: Throwable) {}
|
|
||||||
|
|
||||||
if (!KenjinxNative.reattachWindowIfReady()) {
|
|
||||||
handler.postDelayed(this, REATTACH_DELAY_MS)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
Log.d(TAG_FG, "window reattached")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun doOrientationPulse(currentRot: Int) {
|
|
||||||
val now = android.os.SystemClock.uptimeMillis()
|
|
||||||
if (pulsingOrientation || now - lastPulseAt < 350L) return
|
|
||||||
pulsingOrientation = true
|
|
||||||
lastPulseAt = now
|
|
||||||
|
|
||||||
// Short lock on the target page (prevents flickering)
|
|
||||||
val lock = if (currentRot == Surface.ROTATION_90)
|
|
||||||
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
|
||||||
else
|
|
||||||
ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
|
|
||||||
|
|
||||||
try { requestedOrientation = lock } catch (_: Throwable) {}
|
|
||||||
handler.post {
|
|
||||||
if (isGameRunning) {
|
|
||||||
try { KenjinxNative.setSurfaceRotationByAndroidRotation(currentRot) } catch (_: Throwable) {}
|
|
||||||
try { mainViewModel?.gameHost?.onOrientationOrSizeChanged(currentRot) } catch (_: Throwable) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// After a short time back to SENSOR_LANDSCAPE
|
|
||||||
handler.postDelayed({
|
|
||||||
try { requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE } catch (_: Throwable) {}
|
|
||||||
handler.post {
|
|
||||||
if (isGameRunning) {
|
|
||||||
try {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
||||||
KenjinxNative.setSurfaceRotationByAndroidRotation(display?.rotation)
|
|
||||||
}
|
|
||||||
} catch (_: Throwable) {}
|
|
||||||
try {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
||||||
mainViewModel?.gameHost?.onOrientationOrSizeChanged(display?.rotation)
|
|
||||||
}
|
|
||||||
} catch (_: Throwable) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pulsingOrientation = false
|
|
||||||
}, 250)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
var mainViewModel: MainViewModel? = null
|
|
||||||
var AppPath: String = ""
|
|
||||||
var StorageHelper: SimpleStorageHelper? = null
|
|
||||||
|
|
||||||
const val EXTRA_BOOT_PATH = "bootPath"
|
|
||||||
const val EXTRA_FORCE_NCE_PPTC = "forceNceAndPptc"
|
|
||||||
const val EXTRA_TITLE_ID = "titleId"
|
|
||||||
const val EXTRA_TITLE_NAME = "titleName"
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.R)
|
|
||||||
@JvmStatic
|
|
||||||
fun frameEnded() {
|
|
||||||
mainViewModel?.activity?.apply {
|
|
||||||
if (isActive && QuickSettings(this).enablePerformanceMode) {
|
|
||||||
mainViewModel?.performanceManager?.setTurboMode(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mainViewModel?.gameHost?.hideProgressIndicator()
|
|
||||||
}
|
|
||||||
|
|
||||||
// <<< is called from the Native/Lib page to set the loading progress
|
|
||||||
@JvmStatic
|
|
||||||
fun updateProgress(info: String, percent: Float) {
|
|
||||||
// Route directly via the GameHost – it takes care of the progress states
|
|
||||||
mainViewModel?.gameHost?.setProgress(info, percent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
storageHelper = SimpleStorageHelper(this)
|
|
||||||
StorageHelper = storageHelper
|
|
||||||
System.loadLibrary("kenjinxjni")
|
|
||||||
initVm()
|
|
||||||
}
|
|
||||||
|
|
||||||
private external fun initVm()
|
|
||||||
|
|
||||||
private fun initialize() {
|
|
||||||
if (_isInit) return
|
|
||||||
val appPath: String = AppPath
|
|
||||||
|
|
||||||
val quickSettings = QuickSettings(this)
|
|
||||||
KenjinxNative.loggingSetEnabled(LogLevel.Info, quickSettings.enableInfoLogs)
|
|
||||||
KenjinxNative.loggingSetEnabled(LogLevel.Stub, quickSettings.enableStubLogs)
|
|
||||||
KenjinxNative.loggingSetEnabled(LogLevel.Warning, quickSettings.enableWarningLogs)
|
|
||||||
KenjinxNative.loggingSetEnabled(LogLevel.Error, quickSettings.enableErrorLogs)
|
|
||||||
KenjinxNative.loggingSetEnabled(LogLevel.AccessLog, quickSettings.enableFsAccessLogs)
|
|
||||||
KenjinxNative.loggingSetEnabled(LogLevel.Guest, quickSettings.enableGuestLogs)
|
|
||||||
KenjinxNative.loggingSetEnabled(LogLevel.Trace, quickSettings.enableTraceLogs)
|
|
||||||
KenjinxNative.loggingSetEnabled(LogLevel.Debug, quickSettings.enableDebugLogs)
|
|
||||||
KenjinxNative.loggingEnabledGraphicsLog(quickSettings.enableGraphicsLogs)
|
|
||||||
|
|
||||||
_isInit = KenjinxNative.javaInitialize(appPath, JNIEnv.CURRENT)
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.R)
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
ensureNotificationPermission()
|
|
||||||
|
|
||||||
motionSensorManager = MotionSensorManager(this)
|
|
||||||
Thread.setDefaultUncaughtExceptionHandler(crashHandler)
|
|
||||||
|
|
||||||
if (!Environment.isExternalStorageManager()
|
|
||||||
) {
|
|
||||||
storageHelper?.storage?.requestFullStorageAccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
AppPath = this.getExternalFilesDir(null)!!.absolutePath
|
|
||||||
|
|
||||||
coldResetIfZombie("onCreate")
|
|
||||||
initialize()
|
|
||||||
|
|
||||||
window.attributes.layoutInDisplayCutoutMode =
|
|
||||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
|
||||||
|
|
||||||
// Apply alignment
|
|
||||||
applyOrientationPreference()
|
|
||||||
|
|
||||||
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
|
|
||||||
controller.hide(WindowInsetsCompat.Type.systemBars())
|
|
||||||
controller.systemBarsBehavior =
|
|
||||||
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
|
||||||
}
|
|
||||||
|
|
||||||
uiHandler = UiHandler()
|
|
||||||
displayManager = getSystemService(DISPLAY_SERVICE) as DisplayManager
|
|
||||||
|
|
||||||
mainViewModel = MainViewModel(this)
|
|
||||||
mainViewModel!!.physicalControllerManager = physicalControllerManager
|
|
||||||
mainViewModel!!.motionSensorManager = motionSensorManager
|
|
||||||
mainViewModel!!.refreshFirmwareVersion()
|
|
||||||
|
|
||||||
mainViewModel?.apply {
|
|
||||||
setContent {
|
|
||||||
KenjinxAndroidTheme {
|
|
||||||
Surface(
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
color = MaterialTheme.colorScheme.background
|
|
||||||
) {
|
|
||||||
MainView.Main(mainViewModel = this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
storedIntent = intent
|
|
||||||
rotLog("onCreate: initial display.rotation=${display?.rotation} → ${deg(display?.rotation)}°")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent) {
|
|
||||||
super.onNewIntent(intent)
|
|
||||||
storedIntent = intent
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
|
||||||
storageHelper?.onSaveInstanceState(outState)
|
|
||||||
super.onSaveInstanceState(outState)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
|
||||||
super.onRestoreInstanceState(savedInstanceState)
|
|
||||||
storageHelper?.onRestoreInstanceState(savedInstanceState)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("RestrictedApi")
|
|
||||||
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
|
||||||
event.apply { if (physicalControllerManager.onKeyEvent(this)) return true }
|
|
||||||
return super.dispatchKeyEvent(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dispatchGenericMotionEvent(ev: MotionEvent?): Boolean {
|
|
||||||
ev?.apply { physicalControllerManager.onMotionEvent(this) }
|
|
||||||
return super.dispatchGenericMotionEvent(ev)
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Audio foreground/background gating ---
|
|
||||||
private fun setAudioForegroundState(inForeground: Boolean) {
|
|
||||||
// Preferred: pause instead of just muting
|
|
||||||
try { KenjinxNative.audioSetPaused(!inForeground) } catch (_: Throwable) {}
|
|
||||||
// Fallback: Master Mute
|
|
||||||
try { KenjinxNative.audioSetMuted(!inForeground) } catch (_: Throwable) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------- BACKGROUND STABILITY: Present gating ---------
|
|
||||||
override fun onStart() {
|
|
||||||
super.onStart()
|
|
||||||
coldResetIfZombie("onStart")
|
|
||||||
|
|
||||||
if (isGameRunning && mainViewModel?.rendererReady == true) {
|
|
||||||
try {
|
|
||||||
KenjinxNative.graphicsSetPresentEnabled(true)
|
|
||||||
Log.d(TAG_FG, "present=ENABLED (onStart)")
|
|
||||||
} catch (_: Throwable) {}
|
|
||||||
} else {
|
|
||||||
Log.d(TAG_FG, "skip enable present (onStart) — rendererReady=${mainViewModel?.rendererReady}")
|
|
||||||
setPresentEnabled(false, "cold reset: onStart (no game)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStop() {
|
|
||||||
super.onStop()
|
|
||||||
if (isGameRunning) {
|
|
||||||
setAudioForegroundState(false)
|
|
||||||
handler.removeCallbacks(reattachWindowWhenReady)
|
|
||||||
handler.removeCallbacks(enablePresentWhenReady)
|
|
||||||
setPresentEnabled(false, "onStop")
|
|
||||||
try { KenjinxNative.detachWindow() } catch (_: Throwable) {}
|
|
||||||
}
|
|
||||||
// IMPORTANT: Safely release the binding (prevents memory leak)
|
|
||||||
try { mainViewModel?.gameHost?.shutdownBinding() } catch (_: Throwable) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onTrimMemory(level: Int) {
|
|
||||||
super.onTrimMemory(level)
|
|
||||||
if (level >= TRIM_MEMORY_UI_HIDDEN && isGameRunning) {
|
|
||||||
setAudioForegroundState(false)
|
|
||||||
if (mainViewModel?.rendererReady == true) {
|
|
||||||
try {
|
|
||||||
setPresentEnabled(false, "onTrimMemory:$level")
|
|
||||||
KenjinxNative.detachWindow()
|
|
||||||
} catch (_: Throwable) {}
|
|
||||||
} else {
|
|
||||||
Log.d(TAG_FG, "skip disable present (onTrimMemory) — rendererReady=${mainViewModel?.rendererReady}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// --------------------------------------------------------
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
isActive = true
|
|
||||||
setAudioForegroundState(true)
|
|
||||||
|
|
||||||
coldResetIfZombie("onResume")
|
|
||||||
|
|
||||||
applyOrientationPreference()
|
|
||||||
|
|
||||||
// Enable display listener
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
||||||
lastKnownRotation = display?.rotation
|
|
||||||
rotLog("onResume: display.rotation=${display?.rotation} → ${deg(display?.rotation)}°")
|
|
||||||
}
|
|
||||||
|
|
||||||
try { displayManager.registerDisplayListener(displayListener, handler) } catch (_: Throwable) {}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (Build.VERSION.SDK_INT >= 33) {
|
|
||||||
registerReceiver(
|
|
||||||
serviceStopReceiver,
|
|
||||||
IntentFilter(EmulationService.ACTION_STOPPED),
|
|
||||||
RECEIVER_EXPORTED
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
registerReceiver(serviceStopReceiver, IntentFilter(EmulationService.ACTION_STOPPED))
|
|
||||||
}
|
|
||||||
} catch (_: Throwable) {}
|
|
||||||
|
|
||||||
handler.removeCallbacks(reattachWindowWhenReady)
|
|
||||||
handler.removeCallbacks(enablePresentWhenReady)
|
|
||||||
|
|
||||||
try { mainViewModel?.gameHost?.rebindNativeWindow(force = true) } catch (_: Throwable) {}
|
|
||||||
|
|
||||||
handler.postDelayed(delayedHandleIntent, 10)
|
|
||||||
|
|
||||||
if (isGameRunning && QuickSettings(this).enableMotion) {
|
|
||||||
motionSensorManager.register()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isGameRunning) {
|
|
||||||
handler.postDelayed(reattachWindowWhenReady, REATTACH_DELAY_MS)
|
|
||||||
if (hasWindowFocus()) {
|
|
||||||
handler.postDelayed(enablePresentWhenReady, ENABLE_PRESENT_DELAY_MS)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setPresentEnabled(false, "cold reset: onResume (no game)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
|
||||||
super.onWindowFocusChanged(hasFocus)
|
|
||||||
if (!isGameRunning) return
|
|
||||||
|
|
||||||
handler.removeCallbacks(reattachWindowWhenReady)
|
|
||||||
handler.removeCallbacks(enablePresentWhenReady)
|
|
||||||
|
|
||||||
if (hasFocus && isActive) {
|
|
||||||
setAudioForegroundState(true)
|
|
||||||
// First ensure that the binding exists
|
|
||||||
try { mainViewModel?.gameHost?.ensureServiceStartedAndBound() } catch (_: Throwable) {}
|
|
||||||
|
|
||||||
setPresentEnabled(false, "focus gained → pre-rebind")
|
|
||||||
try { mainViewModel?.gameHost?.rebindNativeWindow(force = true) } catch (_: Throwable) {}
|
|
||||||
handler.postDelayed(reattachWindowWhenReady, 150L)
|
|
||||||
val rot = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) display?.rotation else null
|
|
||||||
handler.postDelayed({ try { mainViewModel?.gameHost?.postReattachKicks(rot) } catch (_: Throwable) {} }, 200L)
|
|
||||||
handler.postDelayed(enablePresentWhenReady, 450L)
|
|
||||||
} else {
|
|
||||||
setAudioForegroundState(false)
|
|
||||||
setPresentEnabled(false, "focus lost")
|
|
||||||
try { KenjinxNative.detachWindow() } catch (_: Throwable) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.R)
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
isActive = false
|
|
||||||
setAudioForegroundState(false)
|
|
||||||
|
|
||||||
handler.removeCallbacks(reattachWindowWhenReady)
|
|
||||||
handler.removeCallbacks(enablePresentWhenReady)
|
|
||||||
|
|
||||||
if (isGameRunning) {
|
|
||||||
setPresentEnabled(false, "onPause")
|
|
||||||
try { KenjinxNative.detachWindow() } catch (_: Throwable) {}
|
|
||||||
mainViewModel?.performanceManager?.setTurboMode(false)
|
|
||||||
motionSensorManager.unregister()
|
|
||||||
}
|
|
||||||
|
|
||||||
try { displayManager.unregisterDisplayListener(displayListener) } catch (_: Throwable) {}
|
|
||||||
try { unregisterReceiver(serviceStopReceiver) } catch (_: Throwable) {}
|
|
||||||
|
|
||||||
// Clean up binding (prevents memory leak when swiping away the task)
|
|
||||||
try { mainViewModel?.gameHost?.shutdownBinding() } catch (_: Throwable) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleIntent() {
|
|
||||||
when (storedIntent.action) {
|
|
||||||
Intent.ACTION_VIEW, "org.kenjinx.android.LAUNCH_GAME" -> {
|
|
||||||
val bootPathExtra = storedIntent.getStringExtra(EXTRA_BOOT_PATH)
|
|
||||||
val forceNceAndPptc = storedIntent.getBooleanExtra(EXTRA_FORCE_NCE_PPTC, false)
|
|
||||||
val titleId = storedIntent.getStringExtra(EXTRA_TITLE_ID) ?: ""
|
|
||||||
val titleName = storedIntent.getStringExtra(EXTRA_TITLE_NAME) ?: ""
|
|
||||||
val dataUri: Uri? = storedIntent.data
|
|
||||||
|
|
||||||
val chosenUri: Uri? = when {
|
|
||||||
!bootPathExtra.isNullOrEmpty() -> bootPathExtra.toUri()
|
|
||||||
dataUri != null -> dataUri
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chosenUri != null) {
|
|
||||||
val doc = when (chosenUri.scheme?.lowercase()) {
|
|
||||||
"content" -> DocumentFile.fromSingleUri(this, chosenUri)
|
|
||||||
"file" -> chosenUri.path?.let { File(it) }?.let { DocumentFile.fromFile(it) }
|
|
||||||
else -> {
|
|
||||||
chosenUri.path?.let { File(it) }?.takeIf { it.exists() }?.let { DocumentFile.fromFile(it) }
|
|
||||||
?: DocumentFile.fromSingleUri(this, chosenUri)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doc != null && doc.exists()) {
|
|
||||||
val gameModel = GameModel(doc, this)
|
|
||||||
gameModel.getGameInfo()
|
|
||||||
mainViewModel?.loadGameModel?.value = gameModel
|
|
||||||
mainViewModel?.bootPath?.value = "gameItem_${gameModel.titleName}"
|
|
||||||
mainViewModel?.forceNceAndPptc?.value = forceNceAndPptc
|
|
||||||
storedIntent = Intent()
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
Log.w("ShortcutDebug", "DocumentFile not found or not accessible: $chosenUri")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (titleId.isNotEmpty() || titleName.isNotEmpty()) {
|
|
||||||
resolveGameByTitleIdOrName(titleId, titleName)?.let { doc ->
|
|
||||||
val gameModel = GameModel(doc, this)
|
|
||||||
gameModel.getGameInfo()
|
|
||||||
mainViewModel?.loadGameModel?.value = gameModel
|
|
||||||
mainViewModel?.bootPath?.value = "gameItem_${gameModel.titleName}"
|
|
||||||
mainViewModel?.forceNceAndPptc?.value = forceNceAndPptc
|
|
||||||
storedIntent = Intent()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyOrientationPreference() {
|
|
||||||
val pref = QuickSettings(this).orientationPreference
|
|
||||||
requestedOrientation = pref.value
|
|
||||||
val rot = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
||||||
this.display?.rotation
|
|
||||||
} else {
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
null
|
|
||||||
}
|
|
||||||
rotLog("applyOrientationPreference: rot=$rot → ${deg(rot)}°, pref=${pref.name}")
|
|
||||||
try { KenjinxNative.setSurfaceRotationByAndroidRotation(rot) } catch (_: Throwable) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.R)
|
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
|
||||||
super.onConfigurationChanged(newConfig)
|
|
||||||
val rot = this.display?.rotation
|
|
||||||
val old = lastKnownRotation
|
|
||||||
lastKnownRotation = rot
|
|
||||||
|
|
||||||
rotLog("onConfigurationChanged: display.rotation=$rot → ${deg(rot)}°")
|
|
||||||
|
|
||||||
try { KenjinxNative.setSurfaceRotationByAndroidRotation(rot) } catch (_: Throwable) {}
|
|
||||||
|
|
||||||
val pref = QuickSettings(this).orientationPreference
|
|
||||||
val shouldPropagate =
|
|
||||||
pref == QuickSettings.OrientationPreference.Sensor ||
|
|
||||||
pref == QuickSettings.OrientationPreference.SensorLandscape
|
|
||||||
|
|
||||||
if (shouldPropagate && isGameRunning) {
|
|
||||||
handler.post { try { mainViewModel?.gameHost?.onOrientationOrSizeChanged(rot) } catch (_: Throwable) {} }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pref == QuickSettings.OrientationPreference.SensorLandscape && old != null && rot != null) {
|
|
||||||
val isSideFlip = (old == Surface.ROTATION_90 && rot == Surface.ROTATION_270) ||
|
|
||||||
(old == Surface.ROTATION_270 && rot == Surface.ROTATION_90)
|
|
||||||
if (isSideFlip) doOrientationPulse(rot)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val requestNotifPerm = registerForActivityResult(
|
|
||||||
ActivityResultContracts.RequestPermission()
|
|
||||||
) { /* optional: Log/Toast */ }
|
|
||||||
|
|
||||||
private fun ensureNotificationPermission() {
|
|
||||||
if (Build.VERSION.SDK_INT >= 33) {
|
|
||||||
val granted = ContextCompat.checkSelfPermission(
|
|
||||||
this, Manifest.permission.POST_NOTIFICATIONS
|
|
||||||
) == PackageManager.PERMISSION_GRANTED
|
|
||||||
if (!granted) {
|
|
||||||
requestNotifPerm.launch(Manifest.permission.POST_NOTIFICATIONS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun resolveGameByTitleIdOrName(titleIdHex: String?, displayName: String?): DocumentFile? {
|
|
||||||
val gamesRoot = getDefaultGamesTree() ?: return null
|
|
||||||
for (child in gamesRoot.listFiles()) {
|
|
||||||
if (!child.isFile) continue
|
|
||||||
if (!displayName.isNullOrBlank()) {
|
|
||||||
val n = child.name ?: ""
|
|
||||||
if (n.contains(displayName, ignoreCase = true)) return child
|
|
||||||
}
|
|
||||||
if (!titleIdHex.isNullOrBlank()) {
|
|
||||||
val tid = getTitleIdFast(child)
|
|
||||||
if (tid != null && tid.equals(titleIdHex, ignoreCase = true)) return child
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!titleIdHex.isNullOrBlank()) {
|
|
||||||
for (child in gamesRoot.listFiles()) {
|
|
||||||
if (!child.isFile) continue
|
|
||||||
val tid = getTitleIdFast(child)
|
|
||||||
if (tid != null && tid.equals(titleIdHex, ignoreCase = true)) return child
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getDefaultGamesTree(): DocumentFile? {
|
|
||||||
val vm = mainViewModel
|
|
||||||
if (vm?.defaultGameFolderUri != null) {
|
|
||||||
return DocumentFile.fromTreeUri(this, vm.defaultGameFolderUri!!)
|
|
||||||
}
|
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
|
||||||
val legacyPath = prefs.getString("gameFolder", null)
|
|
||||||
if (!legacyPath.isNullOrEmpty()) {
|
|
||||||
// Without a SAF URI, tree listing is not possible
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getTitleIdFast(file: DocumentFile): String? {
|
|
||||||
val name = file.name ?: return null
|
|
||||||
val dot = name.lastIndexOf('.')
|
|
||||||
if (dot <= 0 || dot >= name.length - 1) return null
|
|
||||||
val ext = name.substring(dot + 1).lowercase()
|
|
||||||
return try {
|
|
||||||
contentResolver.openFileDescriptor(file.uri, "r")?.use { pfd ->
|
|
||||||
val info = org.kenjinx.android.viewmodels.GameInfo()
|
|
||||||
KenjinxNative.deviceGetGameInfo(pfd.fd, ext, info)
|
|
||||||
info.TitleId?.lowercase()
|
|
||||||
}
|
|
||||||
} catch (_: Exception) { null }
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.R)
|
|
||||||
fun shutdownAndRestart() {
|
|
||||||
val packageManager = packageManager
|
|
||||||
val intent = packageManager.getLaunchIntentForPackage(packageName)
|
|
||||||
val componentName = intent?.component
|
|
||||||
val restartIntent = Intent.makeRestartActivityTask(componentName)
|
|
||||||
mainViewModel?.let { it.performanceManager?.setTurboMode(false) }
|
|
||||||
startActivity(restartIntent)
|
|
||||||
Runtime.getRuntime().exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
handler.removeCallbacks(enablePresentWhenReady)
|
|
||||||
handler.removeCallbacks(reattachWindowWhenReady)
|
|
||||||
// If the activity dies → the binding is guaranteed to be released
|
|
||||||
try { mainViewModel?.gameHost?.shutdownBinding() } catch (_: Throwable) {}
|
|
||||||
super.onDestroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------- Helpers ----------
|
|
||||||
|
|
||||||
private fun setEmuRunningFlag(value: Boolean) {
|
|
||||||
try {
|
|
||||||
getSharedPreferences(PREFS, MODE_PRIVATE)
|
|
||||||
.edit {
|
|
||||||
putBoolean(KEY_EMU_RUNNING, value)
|
|
||||||
}
|
|
||||||
} catch (_: Throwable) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun clearEmuRunningFlag() = setEmuRunningFlag(false)
|
|
||||||
|
|
||||||
private fun hardColdReset(reason: String) {
|
|
||||||
Log.d(TAG_FG, "Cold graphics reset ($reason)")
|
|
||||||
isGameRunning = false
|
|
||||||
mainViewModel?.rendererReady = false
|
|
||||||
|
|
||||||
try { setPresentEnabled(false, "cold reset: $reason") } catch (_: Throwable) {}
|
|
||||||
try { KenjinxNative.detachWindow() } catch (_: Throwable) {}
|
|
||||||
|
|
||||||
try { stopService(Intent(this, EmulationService::class.java)) } catch (_: Throwable) {}
|
|
||||||
|
|
||||||
try { mainViewModel?.loadGameModel?.value = null } catch (_: Throwable) {}
|
|
||||||
try { mainViewModel?.bootPath?.value = "" } catch (_: Throwable) {}
|
|
||||||
try { mainViewModel?.forceNceAndPptc?.value = false } catch (_: Throwable) {}
|
|
||||||
storedIntent = Intent()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun coldResetIfZombie(phase: String) {
|
|
||||||
try {
|
|
||||||
val zombie = getSharedPreferences(PREFS, MODE_PRIVATE)
|
|
||||||
.getBoolean(KEY_EMU_RUNNING, false)
|
|
||||||
if (zombie) {
|
|
||||||
clearEmuRunningFlag()
|
|
||||||
setPresentEnabled(false, "kill stray: $phase")
|
|
||||||
hardColdReset("kill stray: $phase")
|
|
||||||
}
|
|
||||||
} catch (_: Throwable) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
package org.kenjinx.android
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.hardware.Sensor
|
|
||||||
import android.hardware.SensorEvent
|
|
||||||
import android.hardware.SensorEventListener2
|
|
||||||
import android.hardware.SensorManager
|
|
||||||
import android.view.OrientationEventListener
|
|
||||||
|
|
||||||
class MotionSensorManager(val activity: MainActivity) : SensorEventListener2 {
|
|
||||||
private var isRegistered: Boolean = false
|
|
||||||
private var gyro: Sensor?
|
|
||||||
private var accelerometer: Sensor?
|
|
||||||
private var sensorManager: SensorManager =
|
|
||||||
activity.getSystemService(Activity.SENSOR_SERVICE) as SensorManager
|
|
||||||
private var controllerId: Int = -1
|
|
||||||
|
|
||||||
private val motionGyroOrientation: FloatArray = FloatArray(3)
|
|
||||||
private val motionAcelOrientation: FloatArray = FloatArray(3)
|
|
||||||
|
|
||||||
init {
|
|
||||||
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
|
|
||||||
gyro = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)
|
|
||||||
setOrientation90()
|
|
||||||
object : OrientationEventListener(activity) {
|
|
||||||
override fun onOrientationChanged(orientation: Int) {
|
|
||||||
when {
|
|
||||||
isWithinOrientationRange(orientation, 270) -> {
|
|
||||||
setOrientation270()
|
|
||||||
}
|
|
||||||
|
|
||||||
isWithinOrientationRange(orientation, 90) -> {
|
|
||||||
setOrientation90()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isWithinOrientationRange(
|
|
||||||
currentOrientation: Int, targetOrientation: Int, epsilon: Int = 90
|
|
||||||
): Boolean {
|
|
||||||
return currentOrientation > targetOrientation - epsilon
|
|
||||||
&& currentOrientation < targetOrientation + epsilon
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setOrientation270() {
|
|
||||||
motionGyroOrientation[0] = -1.0f
|
|
||||||
motionGyroOrientation[1] = 1.0f
|
|
||||||
motionGyroOrientation[2] = 1.0f
|
|
||||||
motionAcelOrientation[0] = 1.0f
|
|
||||||
motionAcelOrientation[1] = -1.0f
|
|
||||||
motionAcelOrientation[2] = -1.0f
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setOrientation90() {
|
|
||||||
motionGyroOrientation[0] = 1.0f
|
|
||||||
motionGyroOrientation[1] = -1.0f
|
|
||||||
motionGyroOrientation[2] = 1.0f
|
|
||||||
motionAcelOrientation[0] = -1.0f
|
|
||||||
motionAcelOrientation[1] = 1.0f
|
|
||||||
motionAcelOrientation[2] = -1.0f
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setControllerId(id: Int) {
|
|
||||||
controllerId = id
|
|
||||||
}
|
|
||||||
|
|
||||||
fun register() {
|
|
||||||
if (isRegistered)
|
|
||||||
return
|
|
||||||
gyro?.apply {
|
|
||||||
sensorManager.registerListener(
|
|
||||||
this@MotionSensorManager,
|
|
||||||
gyro,
|
|
||||||
SensorManager.SENSOR_DELAY_GAME
|
|
||||||
)
|
|
||||||
}
|
|
||||||
accelerometer?.apply {
|
|
||||||
sensorManager.registerListener(
|
|
||||||
this@MotionSensorManager,
|
|
||||||
accelerometer,
|
|
||||||
SensorManager.SENSOR_DELAY_GAME
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
isRegistered = true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun unregister() {
|
|
||||||
sensorManager.unregisterListener(this)
|
|
||||||
isRegistered = false
|
|
||||||
|
|
||||||
if (controllerId != -1) {
|
|
||||||
KenjinxNative.inputSetAccelerometerData(0.0F, 0.0F, 0.0F, controllerId)
|
|
||||||
KenjinxNative.inputSetGyroData(0.0F, 0.0F, 0.0F, controllerId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSensorChanged(event: SensorEvent?) {
|
|
||||||
if (controllerId != -1)
|
|
||||||
if (isRegistered)
|
|
||||||
event?.apply {
|
|
||||||
when (sensor.type) {
|
|
||||||
Sensor.TYPE_ACCELEROMETER -> {
|
|
||||||
val x = motionAcelOrientation[0] * event.values[1]
|
|
||||||
val y = motionAcelOrientation[1] * event.values[0]
|
|
||||||
val z = motionAcelOrientation[2] * event.values[2]
|
|
||||||
|
|
||||||
KenjinxNative.inputSetAccelerometerData(
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
z,
|
|
||||||
controllerId
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Sensor.TYPE_GYROSCOPE -> {
|
|
||||||
val x = motionGyroOrientation[0] * event.values[1]
|
|
||||||
val y = motionGyroOrientation[1] * event.values[0]
|
|
||||||
val z = motionGyroOrientation[2] * event.values[2]
|
|
||||||
KenjinxNative.inputSetGyroData(x, y, z, controllerId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
KenjinxNative.inputSetAccelerometerData(0.0F, 0.0F, 0.0F, controllerId)
|
|
||||||
KenjinxNative.inputSetGyroData(0.0F, 0.0F, 0.0F, controllerId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFlushCompleted(sensor: Sensor?) {
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package org.kenjinx.android
|
|
||||||
|
|
||||||
class NativeGraphicsInterop {
|
|
||||||
var VkCreateSurface: Long = 0
|
|
||||||
var SurfaceHandle: Long = 0
|
|
||||||
var VkRequiredExtensions: Array<String>? = null
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package org.kenjinx.android
|
|
||||||
|
|
||||||
import android.view.Surface
|
|
||||||
|
|
||||||
class NativeHelpers {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val instance = NativeHelpers()
|
|
||||||
|
|
||||||
init {
|
|
||||||
System.loadLibrary("kenjinxjni")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
external fun releaseNativeWindow(window: Long)
|
|
||||||
external fun getCreateSurfacePtr(): Long
|
|
||||||
external fun getNativeWindow(surface: Surface): Long
|
|
||||||
|
|
||||||
external fun loadDriver(
|
|
||||||
nativeLibPath: String,
|
|
||||||
privateAppsPath: String,
|
|
||||||
driverName: String
|
|
||||||
): Long
|
|
||||||
|
|
||||||
external fun setTurboMode(enable: Boolean)
|
|
||||||
external fun getMaxSwapInterval(nativeWindow: Long): Int
|
|
||||||
external fun getMinSwapInterval(nativeWindow: Long): Int
|
|
||||||
external fun setSwapInterval(nativeWindow: Long, swapInterval: Int): Int
|
|
||||||
external fun getStringJava(ptr: Long): String
|
|
||||||
external fun setIsInitialOrientationFlipped(isFlipped: Boolean)
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
package org.kenjinx.android
|
|
||||||
|
|
||||||
import android.view.SurfaceView
|
|
||||||
|
|
||||||
class NativeWindow(val surface: SurfaceView) {
|
|
||||||
var nativePointer: Long
|
|
||||||
private val nativeHelpers: NativeHelpers = NativeHelpers.instance
|
|
||||||
private var _swapInterval: Int = 0
|
|
||||||
|
|
||||||
val maxSwapInterval: Int
|
|
||||||
get() {
|
|
||||||
return if (nativePointer == -1L) 0 else nativeHelpers.getMaxSwapInterval(nativePointer)
|
|
||||||
}
|
|
||||||
|
|
||||||
val minSwapInterval: Int
|
|
||||||
get() {
|
|
||||||
return if (nativePointer == -1L) 0 else nativeHelpers.getMinSwapInterval(nativePointer)
|
|
||||||
}
|
|
||||||
|
|
||||||
var swapInterval: Int
|
|
||||||
get() {
|
|
||||||
return _swapInterval
|
|
||||||
}
|
|
||||||
set(value) {
|
|
||||||
if (nativePointer == -1L || nativeHelpers.setSwapInterval(nativePointer, value) == 0)
|
|
||||||
_swapInterval = value
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
nativePointer = nativeHelpers.getNativeWindow(surface.holder.surface)
|
|
||||||
|
|
||||||
swapInterval = maxOf(1, minSwapInterval)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun requeryWindowHandle(): Long {
|
|
||||||
nativePointer = nativeHelpers.getNativeWindow(surface.holder.surface)
|
|
||||||
|
|
||||||
swapInterval = swapInterval
|
|
||||||
|
|
||||||
return nativePointer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package org.kenjinx.android
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Build
|
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import kotlin.math.abs
|
|
||||||
|
|
||||||
class PerformanceManager(private val activity: MainActivity) {
|
|
||||||
companion object {
|
|
||||||
@RequiresApi(Build.VERSION_CODES.R)
|
|
||||||
fun force60HzRefreshRate(enable: Boolean, activity: MainActivity) {
|
|
||||||
// Hack for MIUI devices since they don't support the standard Android APIs
|
|
||||||
try {
|
|
||||||
val setFpsIntent = Intent("com.miui.powerkeeper.SET_ACTIVITY_FPS").apply {
|
|
||||||
putExtra("package_name", "org.kenjinx.android")
|
|
||||||
putExtra("isEnter", enable)
|
|
||||||
}
|
|
||||||
activity.sendBroadcast(setFpsIntent)
|
|
||||||
} catch (_: Exception) {
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enable)
|
|
||||||
activity.display?.supportedModes?.minByOrNull { abs(it.refreshRate - 60f) }
|
|
||||||
?.let { activity.window.attributes.preferredDisplayModeId = it.modeId }
|
|
||||||
else
|
|
||||||
activity.display?.supportedModes?.maxByOrNull { it.refreshRate }
|
|
||||||
?.let { activity.window.attributes.preferredDisplayModeId = it.modeId }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.R)
|
|
||||||
fun setTurboMode(enable: Boolean) {
|
|
||||||
NativeHelpers.instance.setTurboMode(enable)
|
|
||||||
force60HzRefreshRate(enable, activity)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package org.kenjinx.android
|
|
||||||
|
|
||||||
import android.app.ActivityManager
|
|
||||||
import android.content.Context.ACTIVITY_SERVICE
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.compose.runtime.MutableState
|
|
||||||
import java.io.RandomAccessFile
|
|
||||||
|
|
||||||
object PerformanceMonitor {
|
|
||||||
fun getFrequencies(frequencies: MutableList<Double>){
|
|
||||||
frequencies.clear()
|
|
||||||
for (i in 0 until Runtime.getRuntime().availableProcessors()) {
|
|
||||||
runCatching {
|
|
||||||
val raf = RandomAccessFile("/sys/devices/system/cpu/cpu$i/cpufreq/scaling_cur_freq", "r")
|
|
||||||
|
|
||||||
frequencies.add(raf.use { it.readLine().toDouble() / 1000.0 })
|
|
||||||
}.onFailure {
|
|
||||||
Log.e("Performance Monitor", "Failed to read frequency of CPU core $i", it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getMemoryUsage(
|
|
||||||
usedMem: MutableState<Int>,
|
|
||||||
totalMem: MutableState<Int>) {
|
|
||||||
MainActivity.mainViewModel?.activity?.apply {
|
|
||||||
val actManager = getSystemService(ACTIVITY_SERVICE) as ActivityManager
|
|
||||||
val memInfo = ActivityManager.MemoryInfo()
|
|
||||||
actManager.getMemoryInfo(memInfo)
|
|
||||||
val availMemory = memInfo.availMem.toDouble() / (1024 * 1024)
|
|
||||||
val totalMemory = memInfo.totalMem.toDouble() / (1024 * 1024)
|
|
||||||
|
|
||||||
usedMem.value = (totalMemory - availMemory).toInt()
|
|
||||||
totalMem.value = totalMemory.toInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-194
@@ -1,194 +0,0 @@
|
|||||||
package org.kenjinx.android
|
|
||||||
|
|
||||||
import android.view.InputDevice
|
|
||||||
import android.view.KeyEvent
|
|
||||||
import android.view.MotionEvent
|
|
||||||
import org.kenjinx.android.viewmodels.QuickSettings
|
|
||||||
import kotlin.math.abs
|
|
||||||
|
|
||||||
class PhysicalControllerManager(val activity: MainActivity) {
|
|
||||||
private var controllerId: Int = -1
|
|
||||||
|
|
||||||
// Trigger debounce (analog → digital)
|
|
||||||
private var leftTriggerPressed = false
|
|
||||||
private var rightTriggerPressed = false
|
|
||||||
private val pressThreshold = 0.65f
|
|
||||||
private val releaseThreshold = 0.45f
|
|
||||||
|
|
||||||
fun onKeyEvent(event: KeyEvent): Boolean {
|
|
||||||
// Make sure we are connected
|
|
||||||
if (controllerId == -1) {
|
|
||||||
controllerId = KenjinxNative.inputConnectGamepad(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
val id = getGamePadButtonInputId(event.keyCode)
|
|
||||||
if (id != GamePadButtonInputId.None) {
|
|
||||||
val isNotFallback = (event.flags and KeyEvent.FLAG_FALLBACK) == 0
|
|
||||||
if (isNotFallback) {
|
|
||||||
when (event.action) {
|
|
||||||
KeyEvent.ACTION_UP -> KenjinxNative.inputSetButtonReleased(id.ordinal, controllerId)
|
|
||||||
KeyEvent.ACTION_DOWN -> KenjinxNative.inputSetButtonPressed(id.ordinal, controllerId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onMotionEvent(ev: MotionEvent) {
|
|
||||||
if (ev.action != MotionEvent.ACTION_MOVE) return
|
|
||||||
|
|
||||||
if (controllerId == -1) {
|
|
||||||
controllerId = KenjinxNative.inputConnectGamepad(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
val device = ev.device
|
|
||||||
val source = InputDevice.SOURCE_JOYSTICK
|
|
||||||
|
|
||||||
fun hasAxis(axis: Int): Boolean =
|
|
||||||
device?.getMotionRange(axis, source) != null
|
|
||||||
|
|
||||||
fun axisValue(axis: Int): Float = ev.getAxisValue(axis)
|
|
||||||
|
|
||||||
// --- Sticks (right side prefers RX/RY, fallback Z/RZ) ---
|
|
||||||
val rightXaxis = if (hasAxis(MotionEvent.AXIS_RX)) MotionEvent.AXIS_RX else MotionEvent.AXIS_Z
|
|
||||||
val rightYaxis = if (hasAxis(MotionEvent.AXIS_RY)) MotionEvent.AXIS_RY else MotionEvent.AXIS_RZ
|
|
||||||
|
|
||||||
val leftStickX = if (hasAxis(MotionEvent.AXIS_X)) axisValue(MotionEvent.AXIS_X) else 0f
|
|
||||||
val leftStickY = if (hasAxis(MotionEvent.AXIS_Y)) axisValue(MotionEvent.AXIS_Y) else 0f
|
|
||||||
val rightStickX = if (hasAxis(rightXaxis)) axisValue(rightXaxis) else 0f
|
|
||||||
val rightStickY = if (hasAxis(rightYaxis)) axisValue(rightYaxis) else 0f
|
|
||||||
|
|
||||||
KenjinxNative.inputSetStickAxis(1, leftStickX, -leftStickY, controllerId)
|
|
||||||
KenjinxNative.inputSetStickAxis(2, rightStickX, -rightStickY, controllerId)
|
|
||||||
|
|
||||||
// --- Reading the triggers (with fallbacks) ---
|
|
||||||
// Preferred: LTRIGGER/RTRIGGER, then BRAKE/GAS.
|
|
||||||
// If the right stick uses RX/RY (standard on Xbox), Z/RZ are free -> use them as a further fallback.
|
|
||||||
// If the stick uses Z/RZ, these are NOT used for triggers (to avoid conflicts).
|
|
||||||
val rightStickUsesZ = (rightXaxis == MotionEvent.AXIS_Z)
|
|
||||||
val rightStickUsesRZ = (rightYaxis == MotionEvent.AXIS_RZ)
|
|
||||||
|
|
||||||
val rawLT = when {
|
|
||||||
hasAxis(MotionEvent.AXIS_LTRIGGER) -> axisValue(MotionEvent.AXIS_LTRIGGER)
|
|
||||||
hasAxis(MotionEvent.AXIS_BRAKE) -> axisValue(MotionEvent.AXIS_BRAKE)
|
|
||||||
!rightStickUsesZ && hasAxis(MotionEvent.AXIS_Z) -> axisValue(MotionEvent.AXIS_Z)
|
|
||||||
else -> 0f
|
|
||||||
}
|
|
||||||
val rawRT = when {
|
|
||||||
hasAxis(MotionEvent.AXIS_RTRIGGER) -> axisValue(MotionEvent.AXIS_RTRIGGER)
|
|
||||||
hasAxis(MotionEvent.AXIS_GAS) -> axisValue(MotionEvent.AXIS_GAS)
|
|
||||||
!rightStickUsesRZ && hasAxis(MotionEvent.AXIS_RZ) -> axisValue(MotionEvent.AXIS_RZ)
|
|
||||||
else -> 0f
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some pads produce slight offsets – normalize them
|
|
||||||
val lt = if (abs(rawLT) < 0.02f) 0f else rawLT.coerceIn(0f, 1f)
|
|
||||||
val rt = if (abs(rawRT) < 0.02f) 0f else rawRT.coerceIn(0f, 1f)
|
|
||||||
|
|
||||||
// Analog to digital conversion with hysteresis
|
|
||||||
if (!leftTriggerPressed && lt >= pressThreshold) {
|
|
||||||
leftTriggerPressed = true
|
|
||||||
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.LeftTrigger.ordinal, controllerId)
|
|
||||||
} else if (leftTriggerPressed && lt <= releaseThreshold) {
|
|
||||||
leftTriggerPressed = false
|
|
||||||
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.LeftTrigger.ordinal, controllerId)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rightTriggerPressed && rt >= pressThreshold) {
|
|
||||||
rightTriggerPressed = true
|
|
||||||
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.RightTrigger.ordinal, controllerId)
|
|
||||||
} else if (rightTriggerPressed && rt <= releaseThreshold) {
|
|
||||||
rightTriggerPressed = false
|
|
||||||
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.RightTrigger.ordinal, controllerId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- DPAD as HAT (as before) ---
|
|
||||||
device?.apply {
|
|
||||||
if (sources and InputDevice.SOURCE_DPAD != InputDevice.SOURCE_DPAD) {
|
|
||||||
val dPadHor = ev.getAxisValue(MotionEvent.AXIS_HAT_X)
|
|
||||||
val dPadVert = ev.getAxisValue(MotionEvent.AXIS_HAT_Y)
|
|
||||||
|
|
||||||
if (dPadVert == 0.0f) {
|
|
||||||
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, controllerId)
|
|
||||||
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, controllerId)
|
|
||||||
}
|
|
||||||
if (dPadHor == 0.0f) {
|
|
||||||
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, controllerId)
|
|
||||||
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, controllerId)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dPadVert < 0.0f) {
|
|
||||||
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadUp.ordinal, controllerId)
|
|
||||||
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadDown.ordinal, controllerId)
|
|
||||||
}
|
|
||||||
if (dPadHor < 0.0f) {
|
|
||||||
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadLeft.ordinal, controllerId)
|
|
||||||
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadRight.ordinal, controllerId)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dPadVert > 0.0f) {
|
|
||||||
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadUp.ordinal, controllerId)
|
|
||||||
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadDown.ordinal, controllerId)
|
|
||||||
}
|
|
||||||
if (dPadHor > 0.0f) {
|
|
||||||
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.DpadLeft.ordinal, controllerId)
|
|
||||||
KenjinxNative.inputSetButtonPressed(GamePadButtonInputId.DpadRight.ordinal, controllerId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun connect(): Int {
|
|
||||||
controllerId = KenjinxNative.inputConnectGamepad(0)
|
|
||||||
return controllerId
|
|
||||||
}
|
|
||||||
|
|
||||||
fun disconnect() {
|
|
||||||
controllerId = -1
|
|
||||||
// If a trigger got "stuck" during the disconnect, release it as a precaution
|
|
||||||
if (leftTriggerPressed) {
|
|
||||||
leftTriggerPressed = false
|
|
||||||
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.LeftTrigger.ordinal, controllerId)
|
|
||||||
}
|
|
||||||
if (rightTriggerPressed) {
|
|
||||||
rightTriggerPressed = false
|
|
||||||
KenjinxNative.inputSetButtonReleased(GamePadButtonInputId.RightTrigger.ordinal, controllerId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getGamePadButtonInputId(keycode: Int): GamePadButtonInputId {
|
|
||||||
val quickSettings = QuickSettings(activity)
|
|
||||||
return when (keycode) {
|
|
||||||
// ABXY (Switch/Xbox Layout)
|
|
||||||
KeyEvent.KEYCODE_BUTTON_A -> if (!quickSettings.useSwitchLayout) GamePadButtonInputId.A else GamePadButtonInputId.B
|
|
||||||
KeyEvent.KEYCODE_BUTTON_B -> if (!quickSettings.useSwitchLayout) GamePadButtonInputId.B else GamePadButtonInputId.A
|
|
||||||
KeyEvent.KEYCODE_BUTTON_X -> if (!quickSettings.useSwitchLayout) GamePadButtonInputId.X else GamePadButtonInputId.Y
|
|
||||||
KeyEvent.KEYCODE_BUTTON_Y -> if (!quickSettings.useSwitchLayout) GamePadButtonInputId.Y else GamePadButtonInputId.X
|
|
||||||
|
|
||||||
// Shoulder & Trigger (in case a pad sends them as keys)
|
|
||||||
KeyEvent.KEYCODE_BUTTON_L1 -> GamePadButtonInputId.LeftShoulder
|
|
||||||
KeyEvent.KEYCODE_BUTTON_L2 -> GamePadButtonInputId.LeftTrigger
|
|
||||||
KeyEvent.KEYCODE_BUTTON_R1 -> GamePadButtonInputId.RightShoulder
|
|
||||||
KeyEvent.KEYCODE_BUTTON_R2 -> GamePadButtonInputId.RightTrigger
|
|
||||||
|
|
||||||
// L3 / R3
|
|
||||||
KeyEvent.KEYCODE_BUTTON_THUMBL -> GamePadButtonInputId.LeftStickButton
|
|
||||||
KeyEvent.KEYCODE_BUTTON_THUMBR -> GamePadButtonInputId.RightStickButton
|
|
||||||
KeyEvent.KEYCODE_BUTTON_11 -> GamePadButtonInputId.LeftStickButton
|
|
||||||
KeyEvent.KEYCODE_BUTTON_12 -> GamePadButtonInputId.RightStickButton
|
|
||||||
|
|
||||||
// D-Pad
|
|
||||||
KeyEvent.KEYCODE_DPAD_UP -> GamePadButtonInputId.DpadUp
|
|
||||||
KeyEvent.KEYCODE_DPAD_DOWN -> GamePadButtonInputId.DpadDown
|
|
||||||
KeyEvent.KEYCODE_DPAD_LEFT -> GamePadButtonInputId.DpadLeft
|
|
||||||
KeyEvent.KEYCODE_DPAD_RIGHT -> GamePadButtonInputId.DpadRight
|
|
||||||
|
|
||||||
// Plus/Minus
|
|
||||||
KeyEvent.KEYCODE_BUTTON_START -> GamePadButtonInputId.Plus
|
|
||||||
KeyEvent.KEYCODE_BUTTON_SELECT -> GamePadButtonInputId.Minus
|
|
||||||
|
|
||||||
else -> GamePadButtonInputId.None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user