Compare commits
580 Commits
Author | SHA1 | Date | |
---|---|---|---|
378080eb87 | |||
e8f5e97fa4 | |||
f3873620a3 | |||
986ac9ff83 | |||
42b9c1e8fe | |||
3b375525fb | |||
e6658c133c | |||
5b42a4d2c4 | |||
8f0c89ffd6 | |||
2c9715acf6 | |||
274af65f69 | |||
4ca78eded5 | |||
6cb6b15612 | |||
2725e40838 | |||
c2e4c8f98e | |||
b53e7ffd46 | |||
ac66643346 | |||
21e88f17f6 | |||
5626f2ca1c | |||
402f05b8ef | |||
fb27042e01 | |||
69a9de33d3 | |||
bba51c2eeb | |||
fc26189fe1 | |||
a40c90e7dd | |||
f864a49014 | |||
ecbf303266 | |||
b3bf05356b | |||
cb4b58052f | |||
f8cdd5f484 | |||
22202be394 | |||
17ba217940 | |||
aae4595bdb | |||
880fd3cfcb | |||
f679f25e08 | |||
c2709b3bdd | |||
2b6e81deea | |||
7271f1b18e | |||
5fda543f84 | |||
95c06de4c1 | |||
49c63ea077 | |||
531da8a1c0 | |||
5cbdfbc7a4 | |||
e0544dd9c7 | |||
aa784c3e5e | |||
9205077590 | |||
0ed40c7175 | |||
40d47b7aa2 | |||
ec0bb74968 | |||
42f7f98666 | |||
95bad6995c | |||
3d42995822 | |||
9095941fd1 | |||
ba71141bdc | |||
0a0675a7f6 | |||
a7c6e6a8cf | |||
0bc8151c7e | |||
40c17673f5 | |||
a8950d6ac4 | |||
162798b026 | |||
1b28ecd63e | |||
895d9b53bc | |||
0e06aace45 | |||
adf4ebcd60 | |||
470a8031a4 | |||
5440d4ad5c | |||
dde208b480 | |||
4c3d2d5d75 | |||
fab11ba3f1 | |||
332891b5ff | |||
7df4fcada7 | |||
d6698680be | |||
e5c9838b0b | |||
f8ec878796 | |||
9ff21f9ab6 | |||
aa021085cf | |||
1f5d881860 | |||
1f664100bd | |||
1f5e1ffa80 | |||
264438ff19 | |||
3b8ac1641a | |||
4250732353 | |||
4d1579acbf | |||
6279f5e430 | |||
b7d2bff6aa | |||
7c327fecb3 | |||
cc1a933a2f | |||
dd574146fb | |||
2c94ac455e | |||
e18d258fa0 | |||
36f10df775 | |||
680e548022 | |||
21c4176157 | |||
3b4ff2d6d9 | |||
12504f280c | |||
250fc51374 | |||
206e0882c2 | |||
609abc8b9b | |||
cee7121058 | |||
cd124bda58 | |||
9f12e50a54 | |||
097562bc6c | |||
db4242c5dc | |||
4dd77316f7 | |||
3f98369a17 | |||
c26aeefe03 | |||
666e05f5cb | |||
8d9d508dc7 | |||
e27f5522e2 | |||
add2a9d151 | |||
9e50dd99d7 | |||
0dec91bb42 | |||
d9b63353b0 | |||
eabd0ec93f | |||
138d5dc64a | |||
3e68a87d63 | |||
69b6ef7a4a | |||
40e87c634e | |||
79d1c190db | |||
2bc88467eb | |||
baf8752e74 | |||
d5e4378aea | |||
6dbcdfea47 | |||
c5258cf082 | |||
5c89e22bb9 | |||
11ecff2ff0 | |||
4c3f09644a | |||
e187a8870a | |||
a64fee29dc | |||
9ef94c8292 | |||
915d6d044c | |||
a4780ab33b | |||
a947a45d81 | |||
9db73f74cf | |||
a1efd87c45 | |||
49be977588 | |||
c95be55091 | |||
63dedbda86 | |||
c532118d94 | |||
52d6f2e656 | |||
c9bc4eaf58 | |||
3249f8ff41 | |||
1b41b285ac | |||
f5a6f45b27 | |||
210557951b | |||
4c2d9ff3ff | |||
8198b99935 | |||
460f96967d | |||
7ca779a26d | |||
b5032b3c91 | |||
f0a3dff136 | |||
f659dcb9d8 | |||
a34fb0e939 | |||
21ce8a9b80 | |||
9ecbee8032 | |||
80519af67d | |||
26e30faff3 | |||
0992310b76 | |||
009c1101d2 | |||
ba95ee54ab | |||
4ce4299ca2 | |||
17620d18db | |||
9f1cf6458c | |||
67b4e63cff | |||
c05c688ee8 | |||
b2623dc27d | |||
5131b71437 | |||
7870423671 | |||
b72916fbc1 | |||
da073fce61 | |||
1fc90e57d2 | |||
eafcc314a9 | |||
6e9bd4de13 | |||
05a41b31bc | |||
eed17f963e | |||
c09c0c002d | |||
d56d335c0b | |||
23c844b2aa | |||
81691b9e37 | |||
2dc422bc14 | |||
a80fa5e33f | |||
954e995321 | |||
dad9ab6bb6 | |||
f0562b9c75 | |||
b8556530f2 | |||
4f3af839be | |||
155736c986 | |||
dba908dc78 | |||
ecee34a50c | |||
9b5a0c3889 | |||
80b4972139 | |||
5d85468302 | |||
9b1cc2cec6 | |||
e691622f0a | |||
f663a5cd38 | |||
f7c2e867f4 | |||
cedd200745 | |||
58207685c0 | |||
095ad923ad | |||
f07ae7d53f | |||
c308f09722 | |||
f1eef29409 | |||
1f8d66db7c | |||
c3a5716a95 | |||
1f1e2a7f03 | |||
e54f9dc4b4 | |||
edfd4d70c0 | |||
fc43aecbbd | |||
58d7a1fe97 | |||
7aa430f1a5 | |||
6bf460e104 | |||
efb135b74c | |||
a707842e14 | |||
a5a9b9bc8b | |||
17078ad929 | |||
32450d45de | |||
ed7a0474c6 | |||
fe9c49949a | |||
052b23c83c | |||
e4f68592c3 | |||
1dcd44b94f | |||
61b1ce252f | |||
5f38086f94 | |||
7bae440d3a | |||
f1943fd0b6 | |||
ec8d4f3af5 | |||
b3f0978869 | |||
f614d2c435 | |||
40c9416097 | |||
618c8edc79 | |||
99fc4fa61b | |||
f6d5499a16 | |||
26bf13a65d | |||
96cf242bcf | |||
59755818ef | |||
f8beeeb7d3 | |||
cb250162cb | |||
7528f94536 | |||
43081c16c4 | |||
780627e7b0 | |||
9044cb38d1 | |||
a53cfdab78 | |||
c7f9962dde | |||
296c4a3d01 | |||
e7cf4e6eaf | |||
a1a4771ac1 | |||
2fd819613f | |||
ad6ff6ce99 | |||
dc30d94852 | |||
4f293f8cbe | |||
32a1cd83fd | |||
e3d0ccf8d5 | |||
c14844d12c | |||
7fea26e97e | |||
7b7f62c776 | |||
423dbc8888 | |||
6adf15e479 | |||
2747f12591 | |||
a47824f961 | |||
8474d52778 | |||
dd7a924596 | |||
a76eaf9a9a | |||
009e6bcd1b | |||
eb2cc159fa | |||
bb89e36fd8 | |||
de3134adbe | |||
36d53819a4 | |||
ae4324032a | |||
f449895e6d | |||
410be95ab6 | |||
cff9046fc7 | |||
86fd0643c2 | |||
43a83a401e | |||
f0e27a23a5 | |||
e68650237d | |||
1faff14e73 | |||
784cf9d594 | |||
64263c5218 | |||
065c4e520d | |||
139a930407 | |||
719dc97bbd | |||
41bba5310a | |||
8071c8c8c0 | |||
b402b4e7f6 | |||
93df366b2c | |||
cd3a15aea5 | |||
070136b3f7 | |||
08ab47c6c0 | |||
85faa9d8fa | |||
dca5b14493 | |||
4d2c8e2a44 | |||
8fa248ceb4 | |||
30862b5ffd | |||
9f57747c57 | |||
fe29a2ff6e | |||
e9a173e00c | |||
a11784fcbf | |||
fd36c8deca | |||
70638340b3 | |||
4b495f3333 | |||
934b5a64e5 | |||
cee667b491 | |||
94a64f2aea | |||
2355c2af62 | |||
5e0f8e8738 | |||
d16288a2a8 | |||
600f86dc7b | |||
7210c17c5e | |||
a16854e55a | |||
3e455a90a1 | |||
e4413542b2 | |||
8c720783f5 | |||
8734ea9dd4 | |||
c586e6d2b7 | |||
3a4eeb77fe | |||
51b3953cfc | |||
610eecc1c1 | |||
492056abf6 | |||
ee6e682ab4 | |||
6f60e102a2 | |||
eeb2af9953 | |||
550747eac6 | |||
3ffceab1fb | |||
b9f2a96595 | |||
cbaa845f5d | |||
9e2681f2d7 | |||
81fae0d1a6 | |||
38519f3b9a | |||
7f27aabbd0 | |||
e876c43ce9 | |||
8639245533 | |||
d6b86a6629 | |||
8f2b7b5b8e | |||
fc4b7cba2c | |||
08831eecf7 | |||
c6a139a6e7 | |||
02714a1291 | |||
09c9686498 | |||
b6614c6ad5 | |||
b1d4b174a6 | |||
2b23463daa | |||
9dfe81770a | |||
52c115a1f8 | |||
e20abbf9cc | |||
76671d63d4 | |||
3d1a0bf374 | |||
c20f3fbebd | |||
0d3b82477e | |||
470be03c2f | |||
c963b3c804 | |||
a4fdfb5f94 | |||
37d27c4c99 | |||
f906eb06c2 | |||
219f63ff4e | |||
1cca3e99ab | |||
55a23e5ec8 | |||
479d1fd8b0 | |||
cb70e7bb30 | |||
c200a7b7c6 | |||
6268170a10 | |||
ee0f9b03a4 | |||
f93c5f006a | |||
295fbd0542 | |||
d7310d7a1c | |||
8c50943a2e | |||
ec4cd57ccf | |||
5a085cba0f | |||
1a1d33a018 | |||
0fbcd630bc | |||
f4d731ae20 | |||
8ac53c66b4 | |||
0f50de72be | |||
df758eddd1 | |||
5f32a8ed94 | |||
535fbec675 | |||
6fe88115a3 | |||
475fa4d390 | |||
edf7e628ca | |||
ba5c0cf5d8 | |||
403e67d983 | |||
c6f1908e0f | |||
851d81d24a | |||
459c4caeba | |||
539b22ef7b | |||
872f036d64 | |||
dca96122bf | |||
e752959109 | |||
cf01664698 | |||
b283a4adcd | |||
8428bb6541 | |||
9a0330f7f8 | |||
57fc996337 | |||
1f3b860f06 | |||
abe3c02ab4 | |||
45b417b2b4 | |||
d076339e3e | |||
837836431d | |||
9f555db5cd | |||
bf7fa60dfc | |||
752b93d3b7 | |||
f23b2878cc | |||
e211c3f00a | |||
d3709a753f | |||
ab676d58ea | |||
2372c194f1 | |||
40311310d1 | |||
dde9bb5c69 | |||
266338a7c9 | |||
90156eea4c | |||
071c01c235 | |||
de06ffb0f7 | |||
8a7de35e3f | |||
121296834a | |||
bbb24d8c7e | |||
4da44e09cb | |||
ae13f0ab4d | |||
a2a35f1be6 | |||
aedfadaaf7 | |||
5c0fb0cec3 | |||
17a1cab5d2 | |||
73aed239c3 | |||
9ac66336a2 | |||
4965681e06 | |||
3868a00206 | |||
933e5144a9 | |||
73a42c85c4 | |||
39ba11054b | |||
c250e3392c | |||
e56b069081 | |||
204c031fef | |||
d9053bbe37 | |||
c25e8427aa | |||
21a081b185 | |||
b540ea80d1 | |||
d692a9b83e | |||
9677ddaa5d | |||
ce92e8cd04 | |||
456fc04007 | |||
458452279c | |||
817b89767a | |||
3fb583c98c | |||
d2686e0a5b | |||
4905101df1 | |||
8750b90a7f | |||
af01100050 | |||
c0821fee1f | |||
a5c2aead67 | |||
d41c95dcff | |||
fbf2b09706 | |||
1fc0f569de | |||
dff138229c | |||
472119c8da | |||
1865ea87e5 | |||
18b61aff59 | |||
cb22629ac1 | |||
6f0f99ee2b | |||
70f2da8fdf | |||
5d3ef7761b | |||
476b4683cf | |||
5fb5079730 | |||
3fbacd0f49 | |||
7aa6abc120 | |||
548bfd60a2 | |||
65778a6b78 | |||
f4e879a1e6 | |||
a1ddaa2736 | |||
008286b79f | |||
a0c77f8d11 | |||
ece36b274d | |||
f3cc2e5703 | |||
5a39d3c4a1 | |||
cc51a03af9 | |||
567c64e149 | |||
36f00985d3 | |||
748d87adcc | |||
0fd47ff490 | |||
f088c3d344 | |||
905a191e28 | |||
ab0491817e | |||
5de6ae426e | |||
69ced3a6e8 | |||
2e43d01d36 | |||
7373ec5792 | |||
de162a648b | |||
131baebe2a | |||
187372cbde | |||
022d495335 | |||
c1372ed775 | |||
a16682cfd3 | |||
7c53b69c30 | |||
33a4d7d1ba | |||
391e08dd27 | |||
b5cf8b8af9 | |||
55043c8afc | |||
5d73a9f5fc | |||
2c9ab5e45f | |||
d536cc8ae6 | |||
d751da84f9 | |||
11aae9cfbc | |||
b96794e72b | |||
f1d1670b0b | |||
b8de72de8f | |||
eebc39228d | |||
9daf029f35 | |||
51a27032f0 | |||
a6a67a2b7a | |||
c6d05301aa | |||
647de4cd31 | |||
f82309fa2d | |||
7d8e198c33 | |||
3d98e1361b | |||
141cf61ff7 | |||
3fe3598d41 | |||
59cdf310bd | |||
4e34170a84 | |||
d540af5dc0 | |||
f7c7b66fc0 | |||
28ba55598d | |||
9719b6a112 | |||
f70236f947 | |||
eafadf10c7 | |||
9b06ee7736 | |||
baba2c2467 | |||
286e5d39b2 | |||
dc529c1181 | |||
c7cf1cbc35 | |||
d8e487d018 | |||
5fdc46ac7f | |||
1e5b45f580 | |||
62585755fd | |||
56621615b1 | |||
2099a3e84b | |||
7d26e4ac7b | |||
8d41402fa6 | |||
5af8ce7c38 | |||
77c4291c34 | |||
6e92b7a378 | |||
9b852c7481 | |||
c40c3905e2 | |||
a6cd044f0f | |||
f5a1de6ac5 | |||
2aeb5b00e3 | |||
60ba7b71f2 | |||
7c1d2bbb98 | |||
beacf8c1c8 | |||
0dbe45ae37 | |||
2b50e52e48 | |||
49eadbc209 | |||
2df16ded9b | |||
e43390c723 | |||
5af1327068 | |||
88a8d1e567 | |||
bf77d1cab9 | |||
1ca0517c99 | |||
599d485bff | |||
60e16c15b6 | |||
2068445939 | |||
a4fc9f8050 | |||
5437d6cb13 | |||
7539e26144 | |||
1c3697b6a4 | |||
81f848e54f | |||
358a781639 | |||
45ce540b9b | |||
96bf7f8522 | |||
33e673ceb8 | |||
9c2500de5f | |||
dbe43c1719 | |||
f502cfaf62 | |||
1fd5cf2b4a | |||
814f75142e | |||
4c0eb91d7e | |||
da75a9a6ea | |||
41790aa743 | |||
0cb1e926b5 | |||
6f0395538b | |||
b9f1ff3c77 | |||
a77af4c5e9 | |||
fbcf802fbc | |||
c3c41fa4bb |
@ -63,6 +63,10 @@ dotnet_code_quality_unused_parameters = all:suggestion
|
||||
|
||||
#### C# Coding Conventions ####
|
||||
|
||||
# Namespace preferences
|
||||
csharp_style_namespace_declarations = block_scoped:warning
|
||||
resharper_csharp_namespace_body = block_scoped
|
||||
|
||||
# var preferences
|
||||
csharp_style_var_elsewhere = false:silent
|
||||
csharp_style_var_for_built_in_types = false:silent
|
||||
@ -89,6 +93,7 @@ csharp_style_conditional_delegate_call = true:suggestion
|
||||
# Modifier preferences
|
||||
csharp_prefer_static_local_function = true:suggestion
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
||||
csharp_style_prefer_readonly_struct = true
|
||||
|
||||
# Code-block preferences
|
||||
csharp_prefer_braces = true:silent
|
||||
|
61
.gitattributes
vendored
61
.gitattributes
vendored
@ -1,63 +1,4 @@
|
||||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
||||
* text=auto eol=lf
|
||||
|
43
.github/ISSUE_TEMPLATE/bug_report.md
vendored
43
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,43 +0,0 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Something doesn't work correctly in Ryujinx. Note that game-specific issues should be instead posted on the Game Compatibility List at https://github.com/Ryujinx/Ryujinx-Games-List, unless it is a provable regression.
|
||||
#assignees:
|
||||
---
|
||||
|
||||
## Bug Report
|
||||
|
||||
[ If any section does not apply, replace its contents with "N/A". ]</br>
|
||||
[ Lines between [ ] (square brackets) should be removed before posting. ]
|
||||
|
||||
### What's the issue you encountered?
|
||||
|
||||
[ Describe the issue in detail and what you were doing beforehand. ]</br>
|
||||
[ Did you make any changes related to Ryujinx itself? ]</br>
|
||||
[ If so, make sure to include details relating to what exactly you changed. ]
|
||||
|
||||
### How can the issue be reproduced?
|
||||
|
||||
[ Include a detailed step by step process for recreating your issue. ]
|
||||
|
||||
### Log file
|
||||
|
||||
[ Logs files can be found under ``Logs`` folder in Ryujinx program folder. ]</br>
|
||||
[ If you don't include a crash report in instances of crash related issues, we will ask you one to provide one. ]
|
||||
|
||||
### Environment?
|
||||
|
||||
- Ryujinx version: 1.0.X</br>
|
||||
[ Replace X's with the Ryujinx version at time of crash. ]
|
||||
- Game version: X.X.X</br>
|
||||
[ Replace X's with the game version at time of crash. ]
|
||||
- System Specs:
|
||||
- OS: *(e.g. Windows 10)*
|
||||
- CPU: *(e.g. i7-6700)*
|
||||
- GPU: *(e.g. NVIDIA RTX 2070)*
|
||||
- RAM: *(e.g. 16GB)*
|
||||
- Applied Mods : [ Yes (Which ones) / No ]
|
||||
|
||||
### Additional context?
|
||||
|
||||
Additional info about your environment:</br>
|
||||
[ Any other information relevant to your issue. ]
|
86
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
86
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
name: Bug Report
|
||||
description: File a bug report
|
||||
title: "[Bug]"
|
||||
labels: bug
|
||||
body:
|
||||
- type: textarea
|
||||
id: issue
|
||||
attributes:
|
||||
label: Description of the issue
|
||||
description: What's the issue you encountered?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: repro
|
||||
attributes:
|
||||
label: Reproduction steps
|
||||
description: How can the issue be reproduced?
|
||||
placeholder: Describe each step as precisely as possible
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: log
|
||||
attributes:
|
||||
label: Log file
|
||||
description: A log file will help our developers to better diagnose and fix the issue.
|
||||
placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. You can drag and drop the log on to the text area
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: os
|
||||
attributes:
|
||||
label: OS
|
||||
placeholder: "e.g. Windows 10"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: ryujinx-version
|
||||
attributes:
|
||||
label: Ryujinx version
|
||||
placeholder: "e.g. 1.0.470"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: game-version
|
||||
attributes:
|
||||
label: Game version
|
||||
placeholder: "e.g. 1.1.1"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: cpu
|
||||
attributes:
|
||||
label: CPU
|
||||
placeholder: "e.g. i7-6700"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: gpu
|
||||
attributes:
|
||||
label: GPU
|
||||
placeholder: "e.g. NVIDIA RTX 2070"
|
||||
validations:
|
||||
required: false
|
||||
- type: input
|
||||
id: ram
|
||||
attributes:
|
||||
label: RAM
|
||||
placeholder: "e.g. 16GB"
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: mods
|
||||
attributes:
|
||||
label: List of applied mods
|
||||
placeholder: You can list applied mods here.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: additional-context
|
||||
attributes:
|
||||
label: Additional context?
|
||||
description: |
|
||||
- Additional info about your environment:
|
||||
- Any other information relevant to your issue.
|
||||
validations:
|
||||
required: false
|
34
.github/ISSUE_TEMPLATE/feature_request.md
vendored
34
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Suggest a new feature for Ryujinx.
|
||||
#assignees:
|
||||
---
|
||||
|
||||
## Feature Request
|
||||
|
||||
[ If any section does not apply, replace its contents with "N/A". ]</br>
|
||||
[ If you do not have the information needed for a section, replace its contents with "Unknown". ]</br>
|
||||
[ Lines between [ ] (square brackets) are to be removed before posting. ]</br>
|
||||
|
||||
[ Please search for existing [feature requests](https://github.com/Ryujinx/Ryujinx/issues) before you make your own request. ]</br>
|
||||
[ Duplicate requests will be marked as such and you will be referred to the original request. ]
|
||||
|
||||
### What feature are you suggesting?
|
||||
#### Overview:
|
||||
- [ Include the basic, high-level concepts for this feature here. ]
|
||||
|
||||
#### Smaller Details:
|
||||
- [ These may include specific methods of implementation etc. ]
|
||||
|
||||
#### Nature of Request:
|
||||
[ Remove all that do not apply to your request. ]
|
||||
- Addition
|
||||
- [ Ex: Addition of certain original features or features from other community projects. ]
|
||||
- [ If you are suggesting porting features or including features from other projects, include what license they are distributed under and what, if any libraries those project use. ]
|
||||
- Change
|
||||
- Removal
|
||||
- [Ex: Removal of certain features or implementation due to a specific issue/bug or because of low quality code, etc.]
|
||||
|
||||
### Why would this feature be useful?
|
||||
[ If this is a feature for an end-user, how does it benefit the end-user? ]</br>
|
||||
[ If this feature is for developers, what does it add to Ryujinx that did not already exist? ]
|
30
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
30
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: Feature Request
|
||||
description: Suggest a new feature for Ryujinx.
|
||||
title: "[Feature Request]"
|
||||
body:
|
||||
- type: textarea
|
||||
id: overview
|
||||
attributes:
|
||||
label: Overview
|
||||
description: Include the basic, high-level concepts for this feature here.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: details
|
||||
attributes:
|
||||
label: Smaller details
|
||||
description: These may include specific methods of implementation etc.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: request
|
||||
attributes:
|
||||
label: Nature of request
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: feature
|
||||
attributes:
|
||||
label: Why would this feature be useful?
|
||||
validations:
|
||||
required: true
|
@ -1,34 +0,0 @@
|
||||
---
|
||||
name: Missing CPU Instruction
|
||||
about: CPU Instruction is missing in Ryujinx.
|
||||
#assignees:
|
||||
---
|
||||
|
||||
## Missing CPU Instruction
|
||||
|
||||
[ If any section does not apply, replace its contents with "N/A". ]</br>
|
||||
[ If you do not have the information needed for a section, replace its contents with "Unknown". ]</br>
|
||||
[ Lines between [ ] (square brackets) are to be removed before posting. ]
|
||||
|
||||
[ Please search for existing [missing CPU instruction](https://github.com/Ryujinx/Ryujinx/issues) before you make your own issue. ]</br>
|
||||
[ See the following [issue](https://github.com/Ryujinx/Ryujinx/issues/1405) as an example ]</br>
|
||||
[ Duplicate issue will be marked as such and you will be referred to the original request. ]
|
||||
|
||||
### What CPU instruction is missing?
|
||||
|
||||
Requires the *INSTRUCTION* instruction.</br>
|
||||
[ Replace *INSTRUCTION* by the instruction name, e.g. VADDL.U16 ]
|
||||
|
||||
```
|
||||
*
|
||||
```
|
||||
[ Add the undefined instruction error message in the above code block ]
|
||||
|
||||
### Instruction name
|
||||
```
|
||||
*
|
||||
```
|
||||
[ Include the name from [armconverter.com](https://armconverter.com/?disasm) or [shell-storm.org](http://shell-storm.org/online/Online-Assembler-and-Disassembler/?arch=arm64&endianness=big&dis_with_raw=True&dis_with_ins=True) in the above code block ]
|
||||
|
||||
### Required by:
|
||||
[ Add our (games list database)[https://github.com/Ryujinx/Ryujinx-Games-List/issues] links of games who require this instruction ]
|
26
.github/ISSUE_TEMPLATE/missing_cpu_instruction.yml
vendored
Normal file
26
.github/ISSUE_TEMPLATE/missing_cpu_instruction.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
name: Missing CPU Instruction
|
||||
description: CPU Instruction is missing in Ryujinx.
|
||||
title: "[CPU]"
|
||||
labels: [cpu, not-implemented]
|
||||
body:
|
||||
- type: textarea
|
||||
id: instruction
|
||||
attributes:
|
||||
label: CPU instruction
|
||||
description: What CPU instruction is missing?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: name
|
||||
attributes:
|
||||
label: Instruction name
|
||||
description: Include the name from [armconverter.com](https://armconverter.com/?disasm) or [shell-storm.org](http://shell-storm.org/online/Online-Assembler-and-Disassembler/?arch=arm64&endianness=big&dis_with_raw=True&dis_with_ins=True) in the above code block
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: required
|
||||
attributes:
|
||||
label: Required by
|
||||
description: Add links to the [compatibility list page(s)](https://github.com/Ryujinx/Ryujinx-Games-List/issues) of the game(s) that require this instruction.
|
||||
validations:
|
||||
required: true
|
35
.github/ISSUE_TEMPLATE/missing_service_call.md
vendored
35
.github/ISSUE_TEMPLATE/missing_service_call.md
vendored
@ -1,35 +0,0 @@
|
||||
---
|
||||
name: Missing Service Call
|
||||
about: Service call is missing in Ryujinx.
|
||||
#assignees:
|
||||
---
|
||||
|
||||
## Missing Service Call
|
||||
|
||||
[ If any section does not apply, replace its contents with "N/A". ]</br>
|
||||
[ If you do not have the information needed for a section, replace its contents with "Unknown". ]</br>
|
||||
[ Lines between [ ] (square brackets) are to be removed before posting. ]
|
||||
|
||||
[ Please search for existing [missing service call](https://github.com/Ryujinx/Ryujinx/issues) before you make your own issue. ]</br>
|
||||
[ See the following [issue](https://github.com/Ryujinx/Ryujinx/issues/1431) as an example ]</br>
|
||||
[ Duplicate issue will be marked as such and you will be referred to the original request. ]
|
||||
|
||||
### What service call is missing?
|
||||
|
||||
*SERVICE* *INTERFACE*: *NUMBER* (*NAME*) is not implemented.</br>
|
||||
[ Replace *SERVICE* by the service name, e.g. appletAE ]</br>
|
||||
[ Replace *INTERFACE* by the interface name, e.g. IAllSystemAppletProxiesService ]</br>
|
||||
[ Replace *NUMBER* by the call number, e.g. 100 ]</br>
|
||||
[ Replace *NAME* by the call name, e.g. OpenSystemAppletProxy ]</br>
|
||||
[ e.g. appletAE IAllSystemAppletProxiesService: 100 (OpenSystemAppletProxy) ]
|
||||
|
||||
[ Add related links to the specific call from [Switchbrew](https://switchbrew.org/w/index.php?title=Services_API) and/or [SwIPC](https://reswitched.github.io/SwIPC/) ]
|
||||
|
||||
### Service description
|
||||
```
|
||||
*
|
||||
```
|
||||
[ Include the description/explanation from [Switchbrew](https://switchbrew.org/w/index.php?title=Services_API) and/or [SwIPC](https://reswitched.github.io/SwIPC/) in the above code block ]
|
||||
|
||||
### Required by:
|
||||
[ Add our (games list database)[https://github.com/Ryujinx/Ryujinx-Games-List/issues] links of games who require this call ]
|
25
.github/ISSUE_TEMPLATE/missing_service_call.yml
vendored
Normal file
25
.github/ISSUE_TEMPLATE/missing_service_call.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: Missing Service Call
|
||||
description: Service call is missing in Ryujinx.
|
||||
labels: not-implemented
|
||||
body:
|
||||
- type: textarea
|
||||
id: instruction
|
||||
attributes:
|
||||
label: Service call
|
||||
description: What service call is missing?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: name
|
||||
attributes:
|
||||
label: Service description
|
||||
description: Include the description/explanation from [Switchbrew](https://switchbrew.org/w/index.php?title=Services_API) and/or [SwIPC](https://reswitched.github.io/SwIPC/) in the above code block
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: required
|
||||
attributes:
|
||||
label: Required by
|
||||
description: Add links to the [compatibility list page(s)](https://github.com/Ryujinx/Ryujinx-Games-List/issues) of the game(s) that require this service.
|
||||
validations:
|
||||
required: true
|
24
.github/dependabot.yml
vendored
Normal file
24
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
labels:
|
||||
- "infra"
|
||||
reviewers:
|
||||
- marysaka
|
||||
commit-message:
|
||||
prefix: "ci"
|
||||
|
||||
- package-ecosystem: nuget
|
||||
directory: /
|
||||
open-pull-requests-limit: 5
|
||||
schedule:
|
||||
interval: daily
|
||||
labels:
|
||||
- "infra"
|
||||
reviewers:
|
||||
- marysaka
|
||||
commit-message:
|
||||
prefix: nuget
|
119
.github/workflows/build.yml
vendored
119
.github/workflows/build.yml
vendored
@ -18,10 +18,16 @@ on:
|
||||
- '*.yml'
|
||||
- 'README.md'
|
||||
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
RYUJINX_BASE_VERSION: "1.1.0"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.os }} (${{ matrix.configuration }})
|
||||
name: ${{ matrix.OS_NAME }} (${{ matrix.configuration }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||
@ -33,7 +39,7 @@ jobs:
|
||||
RELEASE_ZIP_OS_NAME: linux_x64
|
||||
|
||||
- os: macOS-latest
|
||||
OS_NAME: MacOS x64
|
||||
OS_NAME: macOS x64
|
||||
DOTNET_RUNTIME_IDENTIFIER: osx-x64
|
||||
RELEASE_ZIP_OS_NAME: osx_x64
|
||||
|
||||
@ -43,50 +49,107 @@ jobs:
|
||||
RELEASE_ZIP_OS_NAME: win_x64
|
||||
|
||||
fail-fast: false
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
RYUJINX_BASE_VERSION: "1.1.0"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-dotnet@v1
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 6.0.x
|
||||
- name: Ensure NuGet Source
|
||||
uses: fabriciomurta/ensure-nuget-source@v1
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Get git short hash
|
||||
id: git_short_hash
|
||||
run: echo "::set-output name=result::$(git rev-parse --short "${{ github.sha }}")"
|
||||
- name: Clear
|
||||
run: dotnet clean && dotnet nuget locals all --clear
|
||||
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Build
|
||||
run: dotnet build -c "${{ matrix.configuration }}" /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER
|
||||
run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER
|
||||
|
||||
- name: Test
|
||||
run: dotnet test -c "${{ matrix.configuration }}"
|
||||
run: dotnet test --no-build -c "${{ matrix.configuration }}"
|
||||
|
||||
- name: Publish Ryujinx
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx --self-contained
|
||||
if: github.event_name == 'pull_request'
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained true
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
|
||||
- name: Publish Ryujinx.Headless.SDL2
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Headless.SDL2 --self-contained
|
||||
if: github.event_name == 'pull_request'
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
|
||||
- name: Publish Ryujinx.Ava
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava /p:Version="1.0.0" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Ava
|
||||
if: github.event_name == 'pull_request'
|
||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Ava --self-contained true
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
|
||||
- name: Set executable bit
|
||||
run: |
|
||||
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh
|
||||
chmod +x ./publish_sdl2_headless/Ryujinx.Headless.SDL2 ./publish_sdl2_headless/Ryujinx.sh
|
||||
chmod +x ./publish_ava/Ryujinx.Ava ./publish_ava/Ryujinx.sh
|
||||
if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-latest'
|
||||
|
||||
- name: Upload Ryujinx artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||
path: publish
|
||||
if: github.event_name == 'pull_request'
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
|
||||
- name: Upload Ryujinx.Headless.SDL2 artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||
path: publish_sdl2_headless
|
||||
if: github.event_name == 'pull_request'
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
|
||||
- name: Upload Ryujinx.Ava artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||
path: publish_ava
|
||||
if: github.event_name == 'pull_request'
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
|
||||
build_macos:
|
||||
name: macOS Universal (${{ matrix.configuration }})
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [ Debug, Release ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 14
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 14
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
|
||||
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
|
||||
rm apple-codesign.tar.gz
|
||||
mv rcodesign $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get git short hash
|
||||
id: git_short_hash
|
||||
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Publish macOS
|
||||
run: |
|
||||
./distribution/macos/create_macos_build.sh . publish_tmp publish_ava ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
|
||||
|
||||
- name: Upload Ryujinx.Ava artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
||||
path: "publish_ava/*.tar.gz"
|
||||
if: github.event_name == 'pull_request'
|
172
.github/workflows/flatpak.yml
vendored
Normal file
172
.github/workflows/flatpak.yml
vendored
Normal file
@ -0,0 +1,172 @@
|
||||
name: Flatpak release job
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
ryujinx_version:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
|
||||
concurrency: flatpak-release
|
||||
|
||||
jobs:
|
||||
release:
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
|
||||
GIT_COMMITTER_NAME: "RyujinxBot"
|
||||
GIT_COMMITTER_EMAIL: "61127645+RyujinxBot@users.noreply.github.com"
|
||||
RYUJINX_PROJECT_FILE: "src/Ryujinx/Ryujinx.csproj"
|
||||
NUGET_SOURCES_DESTDIR: "nuget-sources"
|
||||
RYUJINX_VERSION: "${{ inputs.ryujinx_version }}"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
path: Ryujinx
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
global-json-file: Ryujinx/global.json
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
working-directory: Ryujinx
|
||||
run: |
|
||||
echo "git_hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
repository: flathub/org.ryujinx.Ryujinx
|
||||
token: ${{ secrets.RYUJINX_BOT_PAT }}
|
||||
submodules: recursive
|
||||
path: flathub
|
||||
|
||||
- name: Install dependencies
|
||||
run: python -m pip install PyYAML lxml
|
||||
|
||||
- name: Restore Nuget packages
|
||||
run: dotnet restore Ryujinx/${{ env.RYUJINX_PROJECT_FILE }}
|
||||
|
||||
- name: Generate nuget_sources.json
|
||||
shell: python
|
||||
run: |
|
||||
from pathlib import Path
|
||||
import base64
|
||||
import binascii
|
||||
import json
|
||||
import os
|
||||
|
||||
sources = []
|
||||
|
||||
for path in Path(os.environ['NUGET_PACKAGES']).glob('**/*.nupkg.sha512'):
|
||||
name = path.parent.parent.name
|
||||
version = path.parent.name
|
||||
filename = '{}.{}.nupkg'.format(name, version)
|
||||
url = 'https://api.nuget.org/v3-flatcontainer/{}/{}/{}'.format(name, version, filename)
|
||||
|
||||
with path.open() as fp:
|
||||
sha512 = binascii.hexlify(base64.b64decode(fp.read())).decode('ascii')
|
||||
|
||||
sources.append({
|
||||
'type': 'file',
|
||||
'url': url,
|
||||
'sha512': sha512,
|
||||
'dest': os.environ['NUGET_SOURCES_DESTDIR'],
|
||||
'dest-filename': filename,
|
||||
})
|
||||
|
||||
with open('flathub/nuget_sources.json', 'w') as fp:
|
||||
json.dump(sources, fp, indent=4)
|
||||
|
||||
- name: Update flatpak metadata
|
||||
id: metadata
|
||||
env:
|
||||
RYUJINX_GIT_HASH: ${{ steps.version_info.outputs.git_hash }}
|
||||
shell: python
|
||||
run: |
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import os
|
||||
import yaml
|
||||
from datetime import datetime
|
||||
from lxml import etree
|
||||
|
||||
|
||||
# Ensure we don't destroy multiline strings
|
||||
def str_presenter(dumper, data):
|
||||
if len(data.splitlines()) > 1:
|
||||
return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="|")
|
||||
return dumper.represent_scalar("tag:yaml.org,2002:str", data)
|
||||
|
||||
|
||||
yaml.representer.SafeRepresenter.add_representer(str, str_presenter)
|
||||
|
||||
yaml_file = "flathub/org.ryujinx.Ryujinx.yml"
|
||||
xml_file = "flathub/org.ryujinx.Ryujinx.appdata.xml"
|
||||
|
||||
with open(yaml_file, "r") as f:
|
||||
data = yaml.safe_load(f)
|
||||
|
||||
for source in data["modules"][0]["sources"]:
|
||||
if type(source) is str:
|
||||
continue
|
||||
if (
|
||||
source["type"] == "git"
|
||||
and source["url"] == "https://github.com/Ryujinx/Ryujinx.git"
|
||||
):
|
||||
source["commit"] = os.environ['RYUJINX_GIT_HASH']
|
||||
|
||||
is_same_version = data["modules"][0]["build-options"]["env"]["RYUJINX_VERSION"] == os.environ['RYUJINX_VERSION']
|
||||
|
||||
with open(os.environ['GITHUB_OUTPUT'], "a") as gh_out:
|
||||
if is_same_version:
|
||||
gh_out.write(f"commit_message=Retry update to {os.environ['RYUJINX_VERSION']}")
|
||||
else:
|
||||
gh_out.write(f"commit_message=Update to {os.environ['RYUJINX_VERSION']}")
|
||||
|
||||
if not is_same_version:
|
||||
data["modules"][0]["build-options"]["env"]["RYUJINX_VERSION"] = os.environ['RYUJINX_VERSION']
|
||||
|
||||
with open(yaml_file, "w") as f:
|
||||
yaml.safe_dump(data, f, sort_keys=False)
|
||||
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
tree = etree.parse(xml_file, parser)
|
||||
|
||||
root = tree.getroot()
|
||||
|
||||
releases = root.find("releases")
|
||||
|
||||
element = etree.Element("release")
|
||||
element.set("version", os.environ['RYUJINX_VERSION'])
|
||||
element.set("date", datetime.now().date().isoformat())
|
||||
releases.insert(0, element)
|
||||
|
||||
# Ensure 4 spaces
|
||||
etree.indent(root, space=" ")
|
||||
|
||||
with open(xml_file, "wb") as f:
|
||||
f.write(
|
||||
etree.tostring(
|
||||
tree,
|
||||
pretty_print=True,
|
||||
encoding="UTF-8",
|
||||
doctype='<?xml version="1.0" encoding="UTF-8"?>',
|
||||
)
|
||||
)
|
||||
|
||||
- name: Push flatpak update
|
||||
working-directory: flathub
|
||||
env:
|
||||
COMMIT_MESSAGE: ${{ steps.metadata.outputs.commit_message }}
|
||||
run: |
|
||||
git config user.name "${{ env.GIT_COMMITTER_NAME }}"
|
||||
git config user.email "${{ env.GIT_COMMITTER_EMAIL }}"
|
||||
git add .
|
||||
git commit -m "$COMMIT_MESSAGE"
|
||||
git push origin master
|
15
.github/workflows/nightly_pr_comment.yml
vendored
15
.github/workflows/nightly_pr_comment.yml
vendored
@ -7,8 +7,9 @@ jobs:
|
||||
pr_comment:
|
||||
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
steps:
|
||||
- uses: actions/github-script@v3
|
||||
- uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const {owner, repo} = context.repo;
|
||||
@ -16,7 +17,7 @@ jobs:
|
||||
const pull_head_sha = '${{github.event.workflow_run.head_sha}}';
|
||||
|
||||
const issue_number = await (async () => {
|
||||
const pulls = await github.pulls.list({owner, repo});
|
||||
const pulls = await github.rest.pulls.list({owner, repo});
|
||||
for await (const {data} of github.paginate.iterator(pulls)) {
|
||||
for (const pull of data) {
|
||||
if (pull.head.sha === pull_head_sha) {
|
||||
@ -31,7 +32,7 @@ jobs:
|
||||
return core.error(`No matching pull request found`);
|
||||
}
|
||||
|
||||
const {data: {artifacts}} = await github.actions.listWorkflowRunArtifacts({owner, repo, run_id});
|
||||
const {data: {artifacts}} = await github.rest.actions.listWorkflowRunArtifacts({owner, repo, run_id});
|
||||
if (!artifacts.length) {
|
||||
return core.error(`No artifacts found`);
|
||||
}
|
||||
@ -57,12 +58,12 @@ jobs:
|
||||
body += hidden_headless_artifacts;
|
||||
body += hidden_debug_artifacts;
|
||||
|
||||
const {data: comments} = await github.issues.listComments({repo, owner, issue_number});
|
||||
const {data: comments} = await github.rest.issues.listComments({repo, owner, issue_number});
|
||||
const existing_comment = comments.find((c) => c.user.login === 'github-actions[bot]');
|
||||
if (existing_comment) {
|
||||
core.info(`Updating comment ${existing_comment.id}`);
|
||||
await github.issues.updateComment({repo, owner, comment_id: existing_comment.id, body});
|
||||
await github.rest.issues.updateComment({repo, owner, comment_id: existing_comment.id, body});
|
||||
} else {
|
||||
core.info(`Creating a comment`);
|
||||
await github.issues.createComment({repo, owner, issue_number, body});
|
||||
}
|
||||
await github.rest.issues.createComment({repo, owner, issue_number, body});
|
||||
}
|
193
.github/workflows/release.yml
vendored
193
.github/workflows/release.yml
vendored
@ -11,81 +11,118 @@ on:
|
||||
- '*.yml'
|
||||
- 'README.md'
|
||||
|
||||
concurrency: release
|
||||
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
RYUJINX_BASE_VERSION: "1.1"
|
||||
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "master"
|
||||
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryujinx"
|
||||
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master"
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: windows-latest
|
||||
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
RYUJINX_BASE_VERSION: "1.1"
|
||||
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "master"
|
||||
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryujinx"
|
||||
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master"
|
||||
|
||||
tag:
|
||||
name: Create tag
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 6.0.x
|
||||
- name: Ensure NuGet Source
|
||||
uses: fabriciomurta/ensure-nuget-source@v1
|
||||
- name: Clear
|
||||
run: dotnet clean && dotnet nuget locals all --clear
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "::set-output name=build_version::${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}"
|
||||
echo "::set-output name=git_short_hash::$(git rev-parse --short "${{ github.sha }}")"
|
||||
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Create tag
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
github.rest.git.createRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: 'refs/tags/${{ steps.version_info.outputs.build_version }}',
|
||||
sha: context.sha
|
||||
})
|
||||
|
||||
release:
|
||||
name: Release ${{ matrix.OS_NAME }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
OS_NAME: Linux x64
|
||||
DOTNET_RUNTIME_IDENTIFIER: linux-x64
|
||||
RELEASE_ZIP_OS_NAME: linux_x64
|
||||
|
||||
- os: windows-latest
|
||||
OS_NAME: Windows x64
|
||||
DOTNET_RUNTIME_IDENTIFIER: win10-x64
|
||||
RELEASE_ZIP_OS_NAME: win_x64
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Configure for release
|
||||
run: |
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' Ryujinx.Common/ReleaseInformations.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
|
||||
- name: Create output dir
|
||||
run: "mkdir release_output"
|
||||
- name: Publish Windows
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained
|
||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained
|
||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows_ava/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Ava --self-contained
|
||||
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_gtk/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true
|
||||
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true
|
||||
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Ava --self-contained true
|
||||
|
||||
- name: Packing Windows builds
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: |
|
||||
pushd publish_windows
|
||||
pushd publish_gtk
|
||||
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
|
||||
pushd publish_windows_sdl2_headless
|
||||
pushd publish_sdl2_headless
|
||||
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
|
||||
pushd publish_windows_ava
|
||||
pushd publish_ava
|
||||
7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Publish Linux
|
||||
run: |
|
||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained
|
||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained
|
||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux_ava/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Ava --self-contained
|
||||
|
||||
- name: Packing Linux builds
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
pushd publish_linux
|
||||
pushd publish_gtk
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
popd
|
||||
|
||||
pushd publish_linux_sdl2_headless
|
||||
pushd publish_sdl2_headless
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2
|
||||
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
popd
|
||||
|
||||
pushd publish_linux_ava
|
||||
pushd publish_ava
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx.Ava
|
||||
tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
popd
|
||||
shell: bash
|
||||
@ -96,10 +133,78 @@ jobs:
|
||||
name: ${{ steps.version_info.outputs.build_version }}
|
||||
artifacts: "release_output/*.tar.gz,release_output/*.zip"
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: "For more informations about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
|
||||
body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
|
||||
omitBodyDuringUpdate: true
|
||||
allowUpdates: true
|
||||
removeArtifacts: true
|
||||
replacesArtifacts: true
|
||||
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
|
||||
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
macos_release:
|
||||
name: Release MacOS universal
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 14
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 14
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
|
||||
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
|
||||
rm apple-codesign.tar.gz
|
||||
mv rcodesign $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Configure for release
|
||||
run: |
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
|
||||
- name: Publish macOS
|
||||
run: |
|
||||
./distribution/macos/create_macos_build.sh . publish_tmp publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release
|
||||
|
||||
- name: Pushing new release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: ${{ steps.version_info.outputs.build_version }}
|
||||
artifacts: "publish_ava/*.tar.gz"
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
|
||||
omitBodyDuringUpdate: true
|
||||
allowUpdates: true
|
||||
replacesArtifacts: true
|
||||
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
|
||||
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
flatpak_release:
|
||||
uses: ./.github/workflows/flatpak.yml
|
||||
needs: release
|
||||
with:
|
||||
ryujinx_version: "1.1.${{ github.run_number }}"
|
||||
secrets: inherit
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -125,6 +125,9 @@ ClientBin/
|
||||
packages/*
|
||||
*.config
|
||||
|
||||
# Include nuget.config
|
||||
!nuget.config
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
@ -167,3 +170,6 @@ launchSettings.json
|
||||
|
||||
# NetCore Publishing Profiles
|
||||
PublishProfiles/
|
||||
|
||||
# Glade backup files
|
||||
*.glade~
|
||||
|
@ -1,12 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,290 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace ARMeilleure.CodeGen.X86
|
||||
{
|
||||
partial class Assembler
|
||||
{
|
||||
public static bool SupportsVexPrefix(X86Instruction inst)
|
||||
{
|
||||
return _instTable[(int)inst].Flags.HasFlag(InstructionFlags.Vex);
|
||||
}
|
||||
|
||||
private const int BadOp = 0;
|
||||
|
||||
[Flags]
|
||||
private enum InstructionFlags
|
||||
{
|
||||
None = 0,
|
||||
RegOnly = 1 << 0,
|
||||
Reg8Src = 1 << 1,
|
||||
Reg8Dest = 1 << 2,
|
||||
RexW = 1 << 3,
|
||||
Vex = 1 << 4,
|
||||
|
||||
PrefixBit = 16,
|
||||
PrefixMask = 7 << PrefixBit,
|
||||
Prefix66 = 1 << PrefixBit,
|
||||
PrefixF3 = 2 << PrefixBit,
|
||||
PrefixF2 = 4 << PrefixBit
|
||||
}
|
||||
|
||||
private readonly struct InstructionInfo
|
||||
{
|
||||
public int OpRMR { get; }
|
||||
public int OpRMImm8 { get; }
|
||||
public int OpRMImm32 { get; }
|
||||
public int OpRImm64 { get; }
|
||||
public int OpRRM { get; }
|
||||
|
||||
public InstructionFlags Flags { get; }
|
||||
|
||||
public InstructionInfo(
|
||||
int opRMR,
|
||||
int opRMImm8,
|
||||
int opRMImm32,
|
||||
int opRImm64,
|
||||
int opRRM,
|
||||
InstructionFlags flags)
|
||||
{
|
||||
OpRMR = opRMR;
|
||||
OpRMImm8 = opRMImm8;
|
||||
OpRMImm32 = opRMImm32;
|
||||
OpRImm64 = opRImm64;
|
||||
OpRRM = opRRM;
|
||||
Flags = flags;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly static InstructionInfo[] _instTable;
|
||||
|
||||
static Assembler()
|
||||
{
|
||||
_instTable = new InstructionInfo[(int)X86Instruction.Count];
|
||||
|
||||
// Name RM/R RM/I8 RM/I32 R/I64 R/RM Flags
|
||||
Add(X86Instruction.Add, new InstructionInfo(0x00000001, 0x00000083, 0x00000081, BadOp, 0x00000003, InstructionFlags.None));
|
||||
Add(X86Instruction.Addpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Addps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Addsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Addss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f58, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Aesdec, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38de, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Aesdeclast, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38df, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Aesenc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38dc, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Aesenclast, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38dd, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Aesimc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38db, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.And, new InstructionInfo(0x00000021, 0x04000083, 0x04000081, BadOp, 0x00000023, InstructionFlags.None));
|
||||
Add(X86Instruction.Andnpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f55, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Andnps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f55, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Andpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f54, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Andps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f54, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Blendvpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3815, InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Blendvps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3814, InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Bsr, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fbd, InstructionFlags.None));
|
||||
Add(X86Instruction.Bswap, new InstructionInfo(0x00000fc8, BadOp, BadOp, BadOp, BadOp, InstructionFlags.RegOnly));
|
||||
Add(X86Instruction.Call, new InstructionInfo(0x020000ff, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||
Add(X86Instruction.Cmovcc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f40, InstructionFlags.None));
|
||||
Add(X86Instruction.Cmp, new InstructionInfo(0x00000039, 0x07000083, 0x07000081, BadOp, 0x0000003b, InstructionFlags.None));
|
||||
Add(X86Instruction.Cmppd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Cmpps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Cmpsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Cmpss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc2, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Cmpxchg, new InstructionInfo(0x00000fb1, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||
Add(X86Instruction.Cmpxchg16b, new InstructionInfo(0x01000fc7, BadOp, BadOp, BadOp, BadOp, InstructionFlags.RexW));
|
||||
Add(X86Instruction.Cmpxchg8, new InstructionInfo(0x00000fb0, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Reg8Src));
|
||||
Add(X86Instruction.Comisd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2f, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Comiss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2f, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Crc32, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38f1, InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Crc32_16, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38f1, InstructionFlags.PrefixF2 | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Crc32_8, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38f0, InstructionFlags.PrefixF2 | InstructionFlags.Reg8Src));
|
||||
Add(X86Instruction.Cvtdq2pd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe6, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Cvtdq2ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5b, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Cvtpd2dq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe6, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Cvtpd2ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Cvtps2dq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5b, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Cvtps2pd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Cvtsd2si, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2d, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Cvtsd2ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Cvtsi2sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2a, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Cvtsi2ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2a, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Cvtss2sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5a, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Cvtss2si, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f2d, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Div, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x060000f7, InstructionFlags.None));
|
||||
Add(X86Instruction.Divpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Divps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Divsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Divss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5e, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Haddpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Haddps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7c, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Idiv, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x070000f7, InstructionFlags.None));
|
||||
Add(X86Instruction.Imul, new InstructionInfo(BadOp, 0x0000006b, 0x00000069, BadOp, 0x00000faf, InstructionFlags.None));
|
||||
Add(X86Instruction.Imul128, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x050000f7, InstructionFlags.None));
|
||||
Add(X86Instruction.Insertps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a21, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Jmp, new InstructionInfo(0x040000ff, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||
Add(X86Instruction.Ldmxcsr, new InstructionInfo(0x02000fae, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Lea, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x0000008d, InstructionFlags.None));
|
||||
Add(X86Instruction.Maxpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Maxps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Maxsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Maxss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5f, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Minpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Minps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Minsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Minss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5d, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Mov, new InstructionInfo(0x00000089, BadOp, 0x000000c7, 0x000000b8, 0x0000008b, InstructionFlags.None));
|
||||
Add(X86Instruction.Mov16, new InstructionInfo(0x00000089, BadOp, 0x000000c7, BadOp, 0x0000008b, InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Mov8, new InstructionInfo(0x00000088, 0x000000c6, BadOp, BadOp, 0x0000008a, InstructionFlags.Reg8Src | InstructionFlags.Reg8Dest));
|
||||
Add(X86Instruction.Movd, new InstructionInfo(0x00000f7e, BadOp, BadOp, BadOp, 0x00000f6e, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Movdqu, new InstructionInfo(0x00000f7f, BadOp, BadOp, BadOp, 0x00000f6f, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Movhlps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f12, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Movlhps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f16, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Movq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f7e, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Movsd, new InstructionInfo(0x00000f11, BadOp, BadOp, BadOp, 0x00000f10, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Movss, new InstructionInfo(0x00000f11, BadOp, BadOp, BadOp, 0x00000f10, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Movsx16, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fbf, InstructionFlags.None));
|
||||
Add(X86Instruction.Movsx32, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000063, InstructionFlags.None));
|
||||
Add(X86Instruction.Movsx8, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fbe, InstructionFlags.Reg8Src));
|
||||
Add(X86Instruction.Movzx16, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fb7, InstructionFlags.None));
|
||||
Add(X86Instruction.Movzx8, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fb6, InstructionFlags.Reg8Src));
|
||||
Add(X86Instruction.Mul128, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x040000f7, InstructionFlags.None));
|
||||
Add(X86Instruction.Mulpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Mulps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Mulsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Mulss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f59, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Neg, new InstructionInfo(0x030000f7, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||
Add(X86Instruction.Not, new InstructionInfo(0x020000f7, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||
Add(X86Instruction.Or, new InstructionInfo(0x00000009, 0x01000083, 0x01000081, BadOp, 0x0000000b, InstructionFlags.None));
|
||||
Add(X86Instruction.Paddb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffc, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Paddd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffe, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Paddq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fd4, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Paddw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffd, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Palignr, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0f, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pand, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fdb, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pandn, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fdf, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pavgb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe0, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pavgw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe3, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pblendvb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3810, InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pclmulqdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a44, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pcmpeqb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f74, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pcmpeqd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f76, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pcmpeqq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3829, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pcmpeqw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f75, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pcmpgtb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f64, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pcmpgtd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f66, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pcmpgtq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3837, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pcmpgtw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f65, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pextrb, new InstructionInfo(0x000f3a14, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pextrd, new InstructionInfo(0x000f3a16, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pextrq, new InstructionInfo(0x000f3a16, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.RexW | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pextrw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc5, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pinsrb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a20, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pinsrd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a22, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pinsrq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a22, InstructionFlags.Vex | InstructionFlags.RexW | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pinsrw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc4, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pmaxsb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pmaxsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383d, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pmaxsw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fee, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pmaxub, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fde, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pmaxud, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383f, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pmaxuw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383e, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pminsb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3838, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pminsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3839, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pminsw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fea, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pminub, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fda, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pminud, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383b, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pminuw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f383a, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pmovsxbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3820, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pmovsxdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3825, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pmovsxwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3823, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pmovzxbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3830, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pmovzxdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3835, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pmovzxwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3833, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pmulld, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3840, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pmullw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fd5, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pop, new InstructionInfo(0x0000008f, BadOp, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||
Add(X86Instruction.Popcnt, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fb8, InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Por, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000feb, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pshufb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3800, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pshufd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f70, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pslld, new InstructionInfo(BadOp, 0x06000f72, BadOp, BadOp, 0x00000ff2, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pslldq, new InstructionInfo(BadOp, 0x07000f73, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Psllq, new InstructionInfo(BadOp, 0x06000f73, BadOp, BadOp, 0x00000ff3, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Psllw, new InstructionInfo(BadOp, 0x06000f71, BadOp, BadOp, 0x00000ff1, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Psrad, new InstructionInfo(BadOp, 0x04000f72, BadOp, BadOp, 0x00000fe2, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Psraw, new InstructionInfo(BadOp, 0x04000f71, BadOp, BadOp, 0x00000fe1, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Psrld, new InstructionInfo(BadOp, 0x02000f72, BadOp, BadOp, 0x00000fd2, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Psrlq, new InstructionInfo(BadOp, 0x02000f73, BadOp, BadOp, 0x00000fd3, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Psrldq, new InstructionInfo(BadOp, 0x03000f73, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Psrlw, new InstructionInfo(BadOp, 0x02000f71, BadOp, BadOp, 0x00000fd1, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Psubb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ff8, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Psubd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffa, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Psubq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffb, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Psubw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ff9, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Punpckhbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f68, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Punpckhdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f6a, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Punpckhqdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f6d, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Punpckhwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f69, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Punpcklbw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f60, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Punpckldq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f62, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Punpcklqdq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f6c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Punpcklwd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f61, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Push, new InstructionInfo(BadOp, 0x0000006a, 0x00000068, BadOp, 0x060000ff, InstructionFlags.None));
|
||||
Add(X86Instruction.Pxor, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fef, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Rcpps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f53, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Rcpss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f53, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Ror, new InstructionInfo(0x010000d3, 0x010000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||
Add(X86Instruction.Roundpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a09, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Roundps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a08, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Roundsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0b, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Roundss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0a, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Rsqrtps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f52, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Rsqrtss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f52, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Sar, new InstructionInfo(0x070000d3, 0x070000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||
Add(X86Instruction.Setcc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f90, InstructionFlags.Reg8Dest));
|
||||
Add(X86Instruction.Sha256Msg1, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cc, InstructionFlags.None));
|
||||
Add(X86Instruction.Sha256Msg2, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cd, InstructionFlags.None));
|
||||
Add(X86Instruction.Sha256Rnds2, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cb, InstructionFlags.None));
|
||||
Add(X86Instruction.Shl, new InstructionInfo(0x040000d3, 0x040000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||
Add(X86Instruction.Shr, new InstructionInfo(0x050000d3, 0x050000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||
Add(X86Instruction.Shufpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc6, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Shufps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc6, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Sqrtpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Sqrtps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Sqrtsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Sqrtss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f51, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Stmxcsr, new InstructionInfo(0x03000fae, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Sub, new InstructionInfo(0x00000029, 0x05000083, 0x05000081, BadOp, 0x0000002b, InstructionFlags.None));
|
||||
Add(X86Instruction.Subpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Subps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Subsd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex | InstructionFlags.PrefixF2));
|
||||
Add(X86Instruction.Subss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f5c, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Test, new InstructionInfo(0x00000085, BadOp, 0x000000f7, BadOp, BadOp, InstructionFlags.None));
|
||||
Add(X86Instruction.Unpckhpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f15, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Unpckhps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f15, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Unpcklpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f14, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Unpcklps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f14, InstructionFlags.Vex));
|
||||
Add(X86Instruction.Vblendvpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4b, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Vblendvps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4a, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Vcvtph2ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3813, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Vcvtps2ph, new InstructionInfo(0x000f3a1d, BadOp, BadOp, BadOp, BadOp, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Vfmadd231ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38b8, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Vfmadd231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38b9, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
|
||||
Add(X86Instruction.Vfmadd231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38b9, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Vfmsub231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bb, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
|
||||
Add(X86Instruction.Vfmsub231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bb, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Vfnmadd231ps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bc, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Vfnmadd231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bd, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
|
||||
Add(X86Instruction.Vfnmadd231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bd, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Vfnmsub231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bf, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
|
||||
Add(X86Instruction.Vfnmsub231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bf, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Vpblendvb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4c, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Xor, new InstructionInfo(0x00000031, 0x06000083, 0x06000081, BadOp, 0x00000033, InstructionFlags.None));
|
||||
Add(X86Instruction.Xorpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Xorps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex));
|
||||
|
||||
static void Add(X86Instruction inst, in InstructionInfo info)
|
||||
{
|
||||
_instTable[(int)inst] = info;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,198 +0,0 @@
|
||||
using ARMeilleure.Common;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
|
||||
namespace ARMeilleure.CodeGen.X86
|
||||
{
|
||||
static class IntrinsicTable
|
||||
{
|
||||
private const int BadOp = 0;
|
||||
|
||||
private static IntrinsicInfo[] _intrinTable;
|
||||
|
||||
static IntrinsicTable()
|
||||
{
|
||||
_intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))];
|
||||
|
||||
Add(Intrinsic.X86Addpd, new IntrinsicInfo(X86Instruction.Addpd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Addps, new IntrinsicInfo(X86Instruction.Addps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Addsd, new IntrinsicInfo(X86Instruction.Addsd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Addss, new IntrinsicInfo(X86Instruction.Addss, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Aesdec, new IntrinsicInfo(X86Instruction.Aesdec, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Aesdeclast, new IntrinsicInfo(X86Instruction.Aesdeclast, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Aesenc, new IntrinsicInfo(X86Instruction.Aesenc, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Aesenclast, new IntrinsicInfo(X86Instruction.Aesenclast, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Aesimc, new IntrinsicInfo(X86Instruction.Aesimc, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Andnpd, new IntrinsicInfo(X86Instruction.Andnpd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Andnps, new IntrinsicInfo(X86Instruction.Andnps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Andpd, new IntrinsicInfo(X86Instruction.Andpd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Andps, new IntrinsicInfo(X86Instruction.Andps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Blendvpd, new IntrinsicInfo(X86Instruction.Blendvpd, IntrinsicType.Ternary));
|
||||
Add(Intrinsic.X86Blendvps, new IntrinsicInfo(X86Instruction.Blendvps, IntrinsicType.Ternary));
|
||||
Add(Intrinsic.X86Cmppd, new IntrinsicInfo(X86Instruction.Cmppd, IntrinsicType.TernaryImm));
|
||||
Add(Intrinsic.X86Cmpps, new IntrinsicInfo(X86Instruction.Cmpps, IntrinsicType.TernaryImm));
|
||||
Add(Intrinsic.X86Cmpsd, new IntrinsicInfo(X86Instruction.Cmpsd, IntrinsicType.TernaryImm));
|
||||
Add(Intrinsic.X86Cmpss, new IntrinsicInfo(X86Instruction.Cmpss, IntrinsicType.TernaryImm));
|
||||
Add(Intrinsic.X86Comisdeq, new IntrinsicInfo(X86Instruction.Comisd, IntrinsicType.Comis_));
|
||||
Add(Intrinsic.X86Comisdge, new IntrinsicInfo(X86Instruction.Comisd, IntrinsicType.Comis_));
|
||||
Add(Intrinsic.X86Comisdlt, new IntrinsicInfo(X86Instruction.Comisd, IntrinsicType.Comis_));
|
||||
Add(Intrinsic.X86Comisseq, new IntrinsicInfo(X86Instruction.Comiss, IntrinsicType.Comis_));
|
||||
Add(Intrinsic.X86Comissge, new IntrinsicInfo(X86Instruction.Comiss, IntrinsicType.Comis_));
|
||||
Add(Intrinsic.X86Comisslt, new IntrinsicInfo(X86Instruction.Comiss, IntrinsicType.Comis_));
|
||||
Add(Intrinsic.X86Crc32, new IntrinsicInfo(X86Instruction.Crc32, IntrinsicType.Crc32));
|
||||
Add(Intrinsic.X86Crc32_16, new IntrinsicInfo(X86Instruction.Crc32_16, IntrinsicType.Crc32));
|
||||
Add(Intrinsic.X86Crc32_8, new IntrinsicInfo(X86Instruction.Crc32_8, IntrinsicType.Crc32));
|
||||
Add(Intrinsic.X86Cvtdq2pd, new IntrinsicInfo(X86Instruction.Cvtdq2pd, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Cvtdq2ps, new IntrinsicInfo(X86Instruction.Cvtdq2ps, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Cvtpd2dq, new IntrinsicInfo(X86Instruction.Cvtpd2dq, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Cvtpd2ps, new IntrinsicInfo(X86Instruction.Cvtpd2ps, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Cvtps2dq, new IntrinsicInfo(X86Instruction.Cvtps2dq, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Cvtps2pd, new IntrinsicInfo(X86Instruction.Cvtps2pd, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Cvtsd2si, new IntrinsicInfo(X86Instruction.Cvtsd2si, IntrinsicType.UnaryToGpr));
|
||||
Add(Intrinsic.X86Cvtsd2ss, new IntrinsicInfo(X86Instruction.Cvtsd2ss, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Cvtsi2sd, new IntrinsicInfo(X86Instruction.Cvtsi2sd, IntrinsicType.BinaryGpr));
|
||||
Add(Intrinsic.X86Cvtsi2si, new IntrinsicInfo(X86Instruction.Movd, IntrinsicType.UnaryToGpr));
|
||||
Add(Intrinsic.X86Cvtsi2ss, new IntrinsicInfo(X86Instruction.Cvtsi2ss, IntrinsicType.BinaryGpr));
|
||||
Add(Intrinsic.X86Cvtss2sd, new IntrinsicInfo(X86Instruction.Cvtss2sd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Cvtss2si, new IntrinsicInfo(X86Instruction.Cvtss2si, IntrinsicType.UnaryToGpr));
|
||||
Add(Intrinsic.X86Divpd, new IntrinsicInfo(X86Instruction.Divpd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Divps, new IntrinsicInfo(X86Instruction.Divps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Divsd, new IntrinsicInfo(X86Instruction.Divsd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Divss, new IntrinsicInfo(X86Instruction.Divss, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Haddpd, new IntrinsicInfo(X86Instruction.Haddpd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Haddps, new IntrinsicInfo(X86Instruction.Haddps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Insertps, new IntrinsicInfo(X86Instruction.Insertps, IntrinsicType.TernaryImm));
|
||||
Add(Intrinsic.X86Maxpd, new IntrinsicInfo(X86Instruction.Maxpd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Maxps, new IntrinsicInfo(X86Instruction.Maxps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Maxsd, new IntrinsicInfo(X86Instruction.Maxsd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Maxss, new IntrinsicInfo(X86Instruction.Maxss, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Minpd, new IntrinsicInfo(X86Instruction.Minpd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Minps, new IntrinsicInfo(X86Instruction.Minps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Minsd, new IntrinsicInfo(X86Instruction.Minsd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Minss, new IntrinsicInfo(X86Instruction.Minss, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Movhlps, new IntrinsicInfo(X86Instruction.Movhlps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Movlhps, new IntrinsicInfo(X86Instruction.Movlhps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Movss, new IntrinsicInfo(X86Instruction.Movss, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Mulpd, new IntrinsicInfo(X86Instruction.Mulpd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Mulps, new IntrinsicInfo(X86Instruction.Mulps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Mulsd, new IntrinsicInfo(X86Instruction.Mulsd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Mulss, new IntrinsicInfo(X86Instruction.Mulss, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Mxcsrmb, new IntrinsicInfo(X86Instruction.None, IntrinsicType.Mxcsr)); // Mask bits.
|
||||
Add(Intrinsic.X86Mxcsrub, new IntrinsicInfo(X86Instruction.None, IntrinsicType.Mxcsr)); // Unmask bits.
|
||||
Add(Intrinsic.X86Paddb, new IntrinsicInfo(X86Instruction.Paddb, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Paddd, new IntrinsicInfo(X86Instruction.Paddd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Paddq, new IntrinsicInfo(X86Instruction.Paddq, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Paddw, new IntrinsicInfo(X86Instruction.Paddw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Palignr, new IntrinsicInfo(X86Instruction.Palignr, IntrinsicType.TernaryImm));
|
||||
Add(Intrinsic.X86Pand, new IntrinsicInfo(X86Instruction.Pand, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pandn, new IntrinsicInfo(X86Instruction.Pandn, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pavgb, new IntrinsicInfo(X86Instruction.Pavgb, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pavgw, new IntrinsicInfo(X86Instruction.Pavgw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pblendvb, new IntrinsicInfo(X86Instruction.Pblendvb, IntrinsicType.Ternary));
|
||||
Add(Intrinsic.X86Pclmulqdq, new IntrinsicInfo(X86Instruction.Pclmulqdq, IntrinsicType.TernaryImm));
|
||||
Add(Intrinsic.X86Pcmpeqb, new IntrinsicInfo(X86Instruction.Pcmpeqb, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pcmpeqd, new IntrinsicInfo(X86Instruction.Pcmpeqd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pcmpeqq, new IntrinsicInfo(X86Instruction.Pcmpeqq, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pcmpeqw, new IntrinsicInfo(X86Instruction.Pcmpeqw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pcmpgtb, new IntrinsicInfo(X86Instruction.Pcmpgtb, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pcmpgtd, new IntrinsicInfo(X86Instruction.Pcmpgtd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pcmpgtq, new IntrinsicInfo(X86Instruction.Pcmpgtq, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pcmpgtw, new IntrinsicInfo(X86Instruction.Pcmpgtw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pmaxsb, new IntrinsicInfo(X86Instruction.Pmaxsb, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pmaxsd, new IntrinsicInfo(X86Instruction.Pmaxsd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pmaxsw, new IntrinsicInfo(X86Instruction.Pmaxsw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pmaxub, new IntrinsicInfo(X86Instruction.Pmaxub, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pmaxud, new IntrinsicInfo(X86Instruction.Pmaxud, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pmaxuw, new IntrinsicInfo(X86Instruction.Pmaxuw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pminsb, new IntrinsicInfo(X86Instruction.Pminsb, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pminsd, new IntrinsicInfo(X86Instruction.Pminsd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pminsw, new IntrinsicInfo(X86Instruction.Pminsw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pminub, new IntrinsicInfo(X86Instruction.Pminub, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pminud, new IntrinsicInfo(X86Instruction.Pminud, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pminuw, new IntrinsicInfo(X86Instruction.Pminuw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pmovsxbw, new IntrinsicInfo(X86Instruction.Pmovsxbw, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Pmovsxdq, new IntrinsicInfo(X86Instruction.Pmovsxdq, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Pmovsxwd, new IntrinsicInfo(X86Instruction.Pmovsxwd, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Pmovzxbw, new IntrinsicInfo(X86Instruction.Pmovzxbw, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Pmovzxdq, new IntrinsicInfo(X86Instruction.Pmovzxdq, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Pmovzxwd, new IntrinsicInfo(X86Instruction.Pmovzxwd, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Pmulld, new IntrinsicInfo(X86Instruction.Pmulld, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pmullw, new IntrinsicInfo(X86Instruction.Pmullw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Popcnt, new IntrinsicInfo(X86Instruction.Popcnt, IntrinsicType.PopCount));
|
||||
Add(Intrinsic.X86Por, new IntrinsicInfo(X86Instruction.Por, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pshufb, new IntrinsicInfo(X86Instruction.Pshufb, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pshufd, new IntrinsicInfo(X86Instruction.Pshufd, IntrinsicType.BinaryImm));
|
||||
Add(Intrinsic.X86Pslld, new IntrinsicInfo(X86Instruction.Pslld, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pslldq, new IntrinsicInfo(X86Instruction.Pslldq, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Psllq, new IntrinsicInfo(X86Instruction.Psllq, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Psllw, new IntrinsicInfo(X86Instruction.Psllw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Psrad, new IntrinsicInfo(X86Instruction.Psrad, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Psraw, new IntrinsicInfo(X86Instruction.Psraw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Psrld, new IntrinsicInfo(X86Instruction.Psrld, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Psrlq, new IntrinsicInfo(X86Instruction.Psrlq, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Psrldq, new IntrinsicInfo(X86Instruction.Psrldq, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Psrlw, new IntrinsicInfo(X86Instruction.Psrlw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Psubb, new IntrinsicInfo(X86Instruction.Psubb, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Psubd, new IntrinsicInfo(X86Instruction.Psubd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Psubq, new IntrinsicInfo(X86Instruction.Psubq, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Psubw, new IntrinsicInfo(X86Instruction.Psubw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Punpckhbw, new IntrinsicInfo(X86Instruction.Punpckhbw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Punpckhdq, new IntrinsicInfo(X86Instruction.Punpckhdq, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Punpckhqdq, new IntrinsicInfo(X86Instruction.Punpckhqdq, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Punpckhwd, new IntrinsicInfo(X86Instruction.Punpckhwd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Punpcklbw, new IntrinsicInfo(X86Instruction.Punpcklbw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Punpckldq, new IntrinsicInfo(X86Instruction.Punpckldq, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Punpcklqdq, new IntrinsicInfo(X86Instruction.Punpcklqdq, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Punpcklwd, new IntrinsicInfo(X86Instruction.Punpcklwd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pxor, new IntrinsicInfo(X86Instruction.Pxor, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Rcpps, new IntrinsicInfo(X86Instruction.Rcpps, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Rcpss, new IntrinsicInfo(X86Instruction.Rcpss, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Roundpd, new IntrinsicInfo(X86Instruction.Roundpd, IntrinsicType.BinaryImm));
|
||||
Add(Intrinsic.X86Roundps, new IntrinsicInfo(X86Instruction.Roundps, IntrinsicType.BinaryImm));
|
||||
Add(Intrinsic.X86Roundsd, new IntrinsicInfo(X86Instruction.Roundsd, IntrinsicType.BinaryImm));
|
||||
Add(Intrinsic.X86Roundss, new IntrinsicInfo(X86Instruction.Roundss, IntrinsicType.BinaryImm));
|
||||
Add(Intrinsic.X86Rsqrtps, new IntrinsicInfo(X86Instruction.Rsqrtps, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Rsqrtss, new IntrinsicInfo(X86Instruction.Rsqrtss, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Sha256Msg1, new IntrinsicInfo(X86Instruction.Sha256Msg1, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Sha256Msg2, new IntrinsicInfo(X86Instruction.Sha256Msg2, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Sha256Rnds2, new IntrinsicInfo(X86Instruction.Sha256Rnds2, IntrinsicType.Ternary));
|
||||
Add(Intrinsic.X86Shufpd, new IntrinsicInfo(X86Instruction.Shufpd, IntrinsicType.TernaryImm));
|
||||
Add(Intrinsic.X86Shufps, new IntrinsicInfo(X86Instruction.Shufps, IntrinsicType.TernaryImm));
|
||||
Add(Intrinsic.X86Sqrtpd, new IntrinsicInfo(X86Instruction.Sqrtpd, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Sqrtps, new IntrinsicInfo(X86Instruction.Sqrtps, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Sqrtsd, new IntrinsicInfo(X86Instruction.Sqrtsd, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Sqrtss, new IntrinsicInfo(X86Instruction.Sqrtss, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Subpd, new IntrinsicInfo(X86Instruction.Subpd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Subps, new IntrinsicInfo(X86Instruction.Subps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Subsd, new IntrinsicInfo(X86Instruction.Subsd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Subss, new IntrinsicInfo(X86Instruction.Subss, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Unpckhpd, new IntrinsicInfo(X86Instruction.Unpckhpd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Unpckhps, new IntrinsicInfo(X86Instruction.Unpckhps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Unpcklpd, new IntrinsicInfo(X86Instruction.Unpcklpd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Unpcklps, new IntrinsicInfo(X86Instruction.Unpcklps, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Vcvtph2ps, new IntrinsicInfo(X86Instruction.Vcvtph2ps, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Vcvtps2ph, new IntrinsicInfo(X86Instruction.Vcvtps2ph, IntrinsicType.BinaryImm));
|
||||
Add(Intrinsic.X86Vfmadd231ps, new IntrinsicInfo(X86Instruction.Vfmadd231ps, IntrinsicType.Fma));
|
||||
Add(Intrinsic.X86Vfmadd231sd, new IntrinsicInfo(X86Instruction.Vfmadd231sd, IntrinsicType.Fma));
|
||||
Add(Intrinsic.X86Vfmadd231ss, new IntrinsicInfo(X86Instruction.Vfmadd231ss, IntrinsicType.Fma));
|
||||
Add(Intrinsic.X86Vfmsub231sd, new IntrinsicInfo(X86Instruction.Vfmsub231sd, IntrinsicType.Fma));
|
||||
Add(Intrinsic.X86Vfmsub231ss, new IntrinsicInfo(X86Instruction.Vfmsub231ss, IntrinsicType.Fma));
|
||||
Add(Intrinsic.X86Vfnmadd231ps, new IntrinsicInfo(X86Instruction.Vfnmadd231ps, IntrinsicType.Fma));
|
||||
Add(Intrinsic.X86Vfnmadd231sd, new IntrinsicInfo(X86Instruction.Vfnmadd231sd, IntrinsicType.Fma));
|
||||
Add(Intrinsic.X86Vfnmadd231ss, new IntrinsicInfo(X86Instruction.Vfnmadd231ss, IntrinsicType.Fma));
|
||||
Add(Intrinsic.X86Vfnmsub231sd, new IntrinsicInfo(X86Instruction.Vfnmsub231sd, IntrinsicType.Fma));
|
||||
Add(Intrinsic.X86Vfnmsub231ss, new IntrinsicInfo(X86Instruction.Vfnmsub231ss, IntrinsicType.Fma));
|
||||
Add(Intrinsic.X86Xorpd, new IntrinsicInfo(X86Instruction.Xorpd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Xorps, new IntrinsicInfo(X86Instruction.Xorps, IntrinsicType.Binary));
|
||||
}
|
||||
|
||||
private static void Add(Intrinsic intrin, IntrinsicInfo info)
|
||||
{
|
||||
_intrinTable[(int)intrin] = info;
|
||||
}
|
||||
|
||||
public static IntrinsicInfo GetInfo(Intrinsic intrin)
|
||||
{
|
||||
return _intrinTable[(int)intrin];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
namespace ARMeilleure.Decoders;
|
||||
|
||||
interface IOpCode32Exception
|
||||
{
|
||||
int Id { get; }
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
using ARMeilleure.Decoders;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
static partial class InstEmit
|
||||
{
|
||||
private const int DczSizeLog2 = 4; // Log2 size in words
|
||||
public const int DczSizeInBytes = 4 << DczSizeLog2;
|
||||
|
||||
public static void Hint(ArmEmitterContext context)
|
||||
{
|
||||
// Execute as no-op.
|
||||
}
|
||||
|
||||
public static void Isb(ArmEmitterContext context)
|
||||
{
|
||||
// Execute as no-op.
|
||||
}
|
||||
|
||||
public static void Mrs(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||
|
||||
MethodInfo info;
|
||||
|
||||
switch (GetPackedId(op))
|
||||
{
|
||||
case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break;
|
||||
case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break;
|
||||
case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
|
||||
case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)); break;
|
||||
case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)); break;
|
||||
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break;
|
||||
case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)); break;
|
||||
case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break;
|
||||
case 0b11_011_1110_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)); break;
|
||||
case 0b11_011_1110_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)); break;
|
||||
|
||||
default: throw new NotImplementedException($"Unknown MRS 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
|
||||
}
|
||||
|
||||
SetIntOrZR(context, op.Rt, context.Call(info));
|
||||
}
|
||||
|
||||
public static void Msr(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||
|
||||
MethodInfo info;
|
||||
|
||||
switch (GetPackedId(op))
|
||||
{
|
||||
case 0b11_011_0100_0010_000: EmitSetNzcv(context); return;
|
||||
case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr)); break;
|
||||
case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr)); break;
|
||||
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)); break;
|
||||
|
||||
default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
|
||||
}
|
||||
|
||||
context.Call(info, GetIntOrZR(context, op.Rt));
|
||||
}
|
||||
|
||||
public static void Nop(ArmEmitterContext context)
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
public static void Sys(ArmEmitterContext context)
|
||||
{
|
||||
// This instruction is used to do some operations on the CPU like cache invalidation,
|
||||
// address translation and the like.
|
||||
// We treat it as no-op here since we don't have any cache being emulated anyway.
|
||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||
|
||||
switch (GetPackedId(op))
|
||||
{
|
||||
case 0b11_011_0111_0100_001:
|
||||
{
|
||||
// DC ZVA
|
||||
Operand t = GetIntOrZR(context, op.Rt);
|
||||
|
||||
for (long offset = 0; offset < DczSizeInBytes; offset += 8)
|
||||
{
|
||||
Operand address = context.Add(t, Const(offset));
|
||||
|
||||
InstEmitMemoryHelper.EmitStore(context, address, RegisterConsts.ZeroIndex, 3);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// No-op
|
||||
case 0b11_011_0111_1110_001: // DC CIVAC
|
||||
break;
|
||||
|
||||
case 0b11_011_0111_0101_001: // IC IVAU
|
||||
Operand target = Register(op.Rt, RegisterType.Integer, OperandType.I64);
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)), target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetPackedId(OpCodeSystem op)
|
||||
{
|
||||
int id;
|
||||
|
||||
id = op.Op2 << 0;
|
||||
id |= op.CRm << 3;
|
||||
id |= op.CRn << 7;
|
||||
id |= op.Op1 << 11;
|
||||
id |= op.Op0 << 14;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
private static void EmitGetNzcv(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||
|
||||
Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
|
||||
Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag));
|
||||
Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag));
|
||||
Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag));
|
||||
|
||||
Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh));
|
||||
|
||||
SetIntOrZR(context, op.Rt, nzcvSh);
|
||||
}
|
||||
|
||||
private static void EmitSetNzcv(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||
|
||||
Operand t = GetIntOrZR(context, op.Rt);
|
||||
t = context.ConvertI64ToI32(t);
|
||||
|
||||
Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag));
|
||||
v = context.BitwiseAnd (v, Const(1));
|
||||
|
||||
Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag));
|
||||
c = context.BitwiseAnd (c, Const(1));
|
||||
|
||||
Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag));
|
||||
z = context.BitwiseAnd (z, Const(1));
|
||||
|
||||
Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag));
|
||||
n = context.BitwiseAnd (n, Const(1));
|
||||
|
||||
SetFlag(context, PState.VFlag, v);
|
||||
SetFlag(context, PState.CFlag, c);
|
||||
SetFlag(context, PState.ZFlag, z);
|
||||
SetFlag(context, PState.NFlag, n);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,176 +0,0 @@
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
enum Intrinsic : ushort
|
||||
{
|
||||
X86Addpd,
|
||||
X86Addps,
|
||||
X86Addsd,
|
||||
X86Addss,
|
||||
X86Aesdec,
|
||||
X86Aesdeclast,
|
||||
X86Aesenc,
|
||||
X86Aesenclast,
|
||||
X86Aesimc,
|
||||
X86Andnpd,
|
||||
X86Andnps,
|
||||
X86Andpd,
|
||||
X86Andps,
|
||||
X86Blendvpd,
|
||||
X86Blendvps,
|
||||
X86Cmppd,
|
||||
X86Cmpps,
|
||||
X86Cmpsd,
|
||||
X86Cmpss,
|
||||
X86Comisdeq,
|
||||
X86Comisdge,
|
||||
X86Comisdlt,
|
||||
X86Comisseq,
|
||||
X86Comissge,
|
||||
X86Comisslt,
|
||||
X86Crc32,
|
||||
X86Crc32_16,
|
||||
X86Crc32_8,
|
||||
X86Cvtdq2pd,
|
||||
X86Cvtdq2ps,
|
||||
X86Cvtpd2dq,
|
||||
X86Cvtpd2ps,
|
||||
X86Cvtps2dq,
|
||||
X86Cvtps2pd,
|
||||
X86Cvtsd2si,
|
||||
X86Cvtsd2ss,
|
||||
X86Cvtsi2sd,
|
||||
X86Cvtsi2si,
|
||||
X86Cvtsi2ss,
|
||||
X86Cvtss2sd,
|
||||
X86Cvtss2si,
|
||||
X86Divpd,
|
||||
X86Divps,
|
||||
X86Divsd,
|
||||
X86Divss,
|
||||
X86Haddpd,
|
||||
X86Haddps,
|
||||
X86Insertps,
|
||||
X86Maxpd,
|
||||
X86Maxps,
|
||||
X86Maxsd,
|
||||
X86Maxss,
|
||||
X86Minpd,
|
||||
X86Minps,
|
||||
X86Minsd,
|
||||
X86Minss,
|
||||
X86Movhlps,
|
||||
X86Movlhps,
|
||||
X86Movss,
|
||||
X86Mulpd,
|
||||
X86Mulps,
|
||||
X86Mulsd,
|
||||
X86Mulss,
|
||||
X86Mxcsrmb,
|
||||
X86Mxcsrub,
|
||||
X86Paddb,
|
||||
X86Paddd,
|
||||
X86Paddq,
|
||||
X86Paddw,
|
||||
X86Palignr,
|
||||
X86Pand,
|
||||
X86Pandn,
|
||||
X86Pavgb,
|
||||
X86Pavgw,
|
||||
X86Pblendvb,
|
||||
X86Pclmulqdq,
|
||||
X86Pcmpeqb,
|
||||
X86Pcmpeqd,
|
||||
X86Pcmpeqq,
|
||||
X86Pcmpeqw,
|
||||
X86Pcmpgtb,
|
||||
X86Pcmpgtd,
|
||||
X86Pcmpgtq,
|
||||
X86Pcmpgtw,
|
||||
X86Pmaxsb,
|
||||
X86Pmaxsd,
|
||||
X86Pmaxsw,
|
||||
X86Pmaxub,
|
||||
X86Pmaxud,
|
||||
X86Pmaxuw,
|
||||
X86Pminsb,
|
||||
X86Pminsd,
|
||||
X86Pminsw,
|
||||
X86Pminub,
|
||||
X86Pminud,
|
||||
X86Pminuw,
|
||||
X86Pmovsxbw,
|
||||
X86Pmovsxdq,
|
||||
X86Pmovsxwd,
|
||||
X86Pmovzxbw,
|
||||
X86Pmovzxdq,
|
||||
X86Pmovzxwd,
|
||||
X86Pmulld,
|
||||
X86Pmullw,
|
||||
X86Popcnt,
|
||||
X86Por,
|
||||
X86Pshufb,
|
||||
X86Pshufd,
|
||||
X86Pslld,
|
||||
X86Pslldq,
|
||||
X86Psllq,
|
||||
X86Psllw,
|
||||
X86Psrad,
|
||||
X86Psraw,
|
||||
X86Psrld,
|
||||
X86Psrlq,
|
||||
X86Psrldq,
|
||||
X86Psrlw,
|
||||
X86Psubb,
|
||||
X86Psubd,
|
||||
X86Psubq,
|
||||
X86Psubw,
|
||||
X86Punpckhbw,
|
||||
X86Punpckhdq,
|
||||
X86Punpckhqdq,
|
||||
X86Punpckhwd,
|
||||
X86Punpcklbw,
|
||||
X86Punpckldq,
|
||||
X86Punpcklqdq,
|
||||
X86Punpcklwd,
|
||||
X86Pxor,
|
||||
X86Rcpps,
|
||||
X86Rcpss,
|
||||
X86Roundpd,
|
||||
X86Roundps,
|
||||
X86Roundsd,
|
||||
X86Roundss,
|
||||
X86Rsqrtps,
|
||||
X86Rsqrtss,
|
||||
X86Sha256Msg1,
|
||||
X86Sha256Msg2,
|
||||
X86Sha256Rnds2,
|
||||
X86Shufpd,
|
||||
X86Shufps,
|
||||
X86Sqrtpd,
|
||||
X86Sqrtps,
|
||||
X86Sqrtsd,
|
||||
X86Sqrtss,
|
||||
X86Subpd,
|
||||
X86Subps,
|
||||
X86Subsd,
|
||||
X86Subss,
|
||||
X86Unpckhpd,
|
||||
X86Unpckhps,
|
||||
X86Unpcklpd,
|
||||
X86Unpcklps,
|
||||
X86Vcvtph2ps,
|
||||
X86Vcvtps2ph,
|
||||
X86Vfmadd231ps,
|
||||
X86Vfmadd231sd,
|
||||
X86Vfmadd231ss,
|
||||
X86Vfmsub231sd,
|
||||
X86Vfmsub231ss,
|
||||
X86Vfnmadd231ps,
|
||||
X86Vfnmadd231sd,
|
||||
X86Vfnmadd231ss,
|
||||
X86Vfnmsub231sd,
|
||||
X86Vfnmsub231ss,
|
||||
X86Xorpd,
|
||||
X86Xorps
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
using ARMeilleure.CodeGen.X86;
|
||||
|
||||
namespace ARMeilleure
|
||||
{
|
||||
public static class Optimizations
|
||||
{
|
||||
public static bool FastFP { get; set; } = true;
|
||||
|
||||
public static bool AllowLcqInFunctionTable { get; set; } = true;
|
||||
public static bool UseUnmanagedDispatchLoop { get; set; } = true;
|
||||
|
||||
public static bool UseSseIfAvailable { get; set; } = true;
|
||||
public static bool UseSse2IfAvailable { get; set; } = true;
|
||||
public static bool UseSse3IfAvailable { get; set; } = true;
|
||||
public static bool UseSsse3IfAvailable { get; set; } = true;
|
||||
public static bool UseSse41IfAvailable { get; set; } = true;
|
||||
public static bool UseSse42IfAvailable { get; set; } = true;
|
||||
public static bool UsePopCntIfAvailable { get; set; } = true;
|
||||
public static bool UseAvxIfAvailable { get; set; } = true;
|
||||
public static bool UseF16cIfAvailable { get; set; } = true;
|
||||
public static bool UseFmaIfAvailable { get; set; } = true;
|
||||
public static bool UseAesniIfAvailable { get; set; } = true;
|
||||
public static bool UsePclmulqdqIfAvailable { get; set; } = true;
|
||||
public static bool UseShaIfAvailable { get; set; } = true;
|
||||
|
||||
public static bool ForceLegacySse
|
||||
{
|
||||
get => HardwareCapabilities.ForceLegacySse;
|
||||
set => HardwareCapabilities.ForceLegacySse = value;
|
||||
}
|
||||
|
||||
internal static bool UseSse => UseSseIfAvailable && HardwareCapabilities.SupportsSse;
|
||||
internal static bool UseSse2 => UseSse2IfAvailable && HardwareCapabilities.SupportsSse2;
|
||||
internal static bool UseSse3 => UseSse3IfAvailable && HardwareCapabilities.SupportsSse3;
|
||||
internal static bool UseSsse3 => UseSsse3IfAvailable && HardwareCapabilities.SupportsSsse3;
|
||||
internal static bool UseSse41 => UseSse41IfAvailable && HardwareCapabilities.SupportsSse41;
|
||||
internal static bool UseSse42 => UseSse42IfAvailable && HardwareCapabilities.SupportsSse42;
|
||||
internal static bool UsePopCnt => UsePopCntIfAvailable && HardwareCapabilities.SupportsPopcnt;
|
||||
internal static bool UseAvx => UseAvxIfAvailable && HardwareCapabilities.SupportsAvx && !ForceLegacySse;
|
||||
internal static bool UseF16c => UseF16cIfAvailable && HardwareCapabilities.SupportsF16c;
|
||||
internal static bool UseFma => UseFmaIfAvailable && HardwareCapabilities.SupportsFma;
|
||||
internal static bool UseAesni => UseAesniIfAvailable && HardwareCapabilities.SupportsAesni;
|
||||
internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && HardwareCapabilities.SupportsPclmulqdq;
|
||||
internal static bool UseSha => UseShaIfAvailable && HardwareCapabilities.SupportsSha;
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
[Flags]
|
||||
public enum FPCR : uint
|
||||
{
|
||||
Ufe = 1u << 11,
|
||||
Fz = 1u << 24,
|
||||
Dn = 1u << 25,
|
||||
Ahp = 1u << 26,
|
||||
|
||||
A32Mask = 0x07FF9F00u
|
||||
}
|
||||
|
||||
public static class FPCRExtensions
|
||||
{
|
||||
private const int RModeShift = 22;
|
||||
|
||||
public static FPRoundingMode GetRoundingMode(this FPCR fpcr)
|
||||
{
|
||||
return (FPRoundingMode)(((int)fpcr >> RModeShift) & 3);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
public enum FPRoundingMode
|
||||
{
|
||||
ToNearest = 0,
|
||||
TowardsPlusInfinity = 1,
|
||||
TowardsMinusInfinity = 2,
|
||||
TowardsZero = 3
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
[Flags]
|
||||
public enum FPSR : uint
|
||||
{
|
||||
Ufc = 1u << 3,
|
||||
Qc = 1u << 27,
|
||||
|
||||
Nzcv = (1u << 31) | (1u << 30) | (1u << 29) | (1u << 28),
|
||||
|
||||
A32Mask = 0xF800009Fu
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
public enum FPState
|
||||
{
|
||||
VFlag = 28,
|
||||
CFlag = 29,
|
||||
ZFlag = 30,
|
||||
NFlag = 31
|
||||
}
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
static class DelegateHelper
|
||||
{
|
||||
private const string DelegateTypesAssemblyName = "JitDelegateTypes";
|
||||
|
||||
private static readonly ModuleBuilder _modBuilder;
|
||||
|
||||
private static readonly Dictionary<string, Type> _delegateTypesCache;
|
||||
|
||||
static DelegateHelper()
|
||||
{
|
||||
AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(DelegateTypesAssemblyName), AssemblyBuilderAccess.Run);
|
||||
|
||||
_modBuilder = asmBuilder.DefineDynamicModule(DelegateTypesAssemblyName);
|
||||
|
||||
_delegateTypesCache = new Dictionary<string, Type>();
|
||||
}
|
||||
|
||||
public static Delegate GetDelegate(MethodInfo info)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(info));
|
||||
}
|
||||
|
||||
Type[] parameters = info.GetParameters().Select(pI => pI.ParameterType).ToArray();
|
||||
Type returnType = info.ReturnType;
|
||||
|
||||
Type delegateType = GetDelegateType(parameters, returnType);
|
||||
|
||||
return Delegate.CreateDelegate(delegateType, info);
|
||||
}
|
||||
|
||||
private static Type GetDelegateType(Type[] parameters, Type returnType)
|
||||
{
|
||||
string key = GetFunctionSignatureKey(parameters, returnType);
|
||||
|
||||
if (!_delegateTypesCache.TryGetValue(key, out Type delegateType))
|
||||
{
|
||||
delegateType = MakeDelegateType(parameters, returnType, key);
|
||||
|
||||
_delegateTypesCache.TryAdd(key, delegateType);
|
||||
}
|
||||
|
||||
return delegateType;
|
||||
}
|
||||
|
||||
private static string GetFunctionSignatureKey(Type[] parameters, Type returnType)
|
||||
{
|
||||
string sig = GetTypeName(returnType);
|
||||
|
||||
foreach (Type type in parameters)
|
||||
{
|
||||
sig += '_' + GetTypeName(type);
|
||||
}
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
private static string GetTypeName(Type type)
|
||||
{
|
||||
return type.FullName.Replace(".", string.Empty);
|
||||
}
|
||||
|
||||
private const MethodAttributes CtorAttributes =
|
||||
MethodAttributes.RTSpecialName |
|
||||
MethodAttributes.HideBySig |
|
||||
MethodAttributes.Public;
|
||||
|
||||
private const TypeAttributes DelegateTypeAttributes =
|
||||
TypeAttributes.Class |
|
||||
TypeAttributes.Public |
|
||||
TypeAttributes.Sealed |
|
||||
TypeAttributes.AnsiClass |
|
||||
TypeAttributes.AutoClass;
|
||||
|
||||
private const MethodImplAttributes ImplAttributes =
|
||||
MethodImplAttributes.Runtime |
|
||||
MethodImplAttributes.Managed;
|
||||
|
||||
private const MethodAttributes InvokeAttributes =
|
||||
MethodAttributes.Public |
|
||||
MethodAttributes.HideBySig |
|
||||
MethodAttributes.NewSlot |
|
||||
MethodAttributes.Virtual;
|
||||
|
||||
private static readonly Type[] _delegateCtorSignature = { typeof(object), typeof(IntPtr) };
|
||||
|
||||
private static Type MakeDelegateType(Type[] parameters, Type returnType, string name)
|
||||
{
|
||||
TypeBuilder builder = _modBuilder.DefineType(name, DelegateTypeAttributes, typeof(MulticastDelegate));
|
||||
|
||||
builder.DefineConstructor(CtorAttributes, CallingConventions.Standard, _delegateCtorSignature).SetImplementationFlags(ImplAttributes);
|
||||
|
||||
builder.DefineMethod("Invoke", InvokeAttributes, returnType, parameters).SetImplementationFlags(ImplAttributes);
|
||||
|
||||
return builder.CreateTypeInfo();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,291 +0,0 @@
|
||||
using ARMeilleure.Instructions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
static class Delegates
|
||||
{
|
||||
public static bool TryGetDelegateFuncPtrByIndex(int index, out IntPtr funcPtr)
|
||||
{
|
||||
if (index >= 0 && index < _delegates.Count)
|
||||
{
|
||||
funcPtr = _delegates.Values[index].FuncPtr; // O(1).
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
funcPtr = default;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr GetDelegateFuncPtrByIndex(int index)
|
||||
{
|
||||
if (index < 0 || index >= _delegates.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException($"({nameof(index)} = {index})");
|
||||
}
|
||||
|
||||
return _delegates.Values[index].FuncPtr; // O(1).
|
||||
}
|
||||
|
||||
public static IntPtr GetDelegateFuncPtr(MethodInfo info)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(info));
|
||||
}
|
||||
|
||||
string key = GetKey(info);
|
||||
|
||||
if (!_delegates.TryGetValue(key, out DelegateInfo dlgInfo)) // O(log(n)).
|
||||
{
|
||||
throw new KeyNotFoundException($"({nameof(key)} = {key})");
|
||||
}
|
||||
|
||||
return dlgInfo.FuncPtr;
|
||||
}
|
||||
|
||||
public static int GetDelegateIndex(MethodInfo info)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(info));
|
||||
}
|
||||
|
||||
string key = GetKey(info);
|
||||
|
||||
int index = _delegates.IndexOfKey(key); // O(log(n)).
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
throw new KeyNotFoundException($"({nameof(key)} = {key})");
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
private static void SetDelegateInfo(MethodInfo info)
|
||||
{
|
||||
string key = GetKey(info);
|
||||
|
||||
Delegate dlg = DelegateHelper.GetDelegate(info);
|
||||
|
||||
_delegates.Add(key, new DelegateInfo(dlg)); // ArgumentException (key).
|
||||
}
|
||||
|
||||
private static string GetKey(MethodInfo info)
|
||||
{
|
||||
return $"{info.DeclaringType.Name}.{info.Name}";
|
||||
}
|
||||
|
||||
private static readonly SortedList<string, DelegateInfo> _delegates;
|
||||
|
||||
static Delegates()
|
||||
{
|
||||
_delegates = new SortedList<string, DelegateInfo>();
|
||||
|
||||
SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Abs), new Type[] { typeof(double) }));
|
||||
SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Ceiling), new Type[] { typeof(double) }));
|
||||
SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Floor), new Type[] { typeof(double) }));
|
||||
SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Round), new Type[] { typeof(double), typeof(MidpointRounding) }));
|
||||
SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Truncate), new Type[] { typeof(double) }));
|
||||
|
||||
SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Abs), new Type[] { typeof(float) }));
|
||||
SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Ceiling), new Type[] { typeof(float) }));
|
||||
SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Floor), new Type[] { typeof(float) }));
|
||||
SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Round), new Type[] { typeof(float), typeof(MidpointRounding) }));
|
||||
SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Truncate), new Type[] { typeof(float) }));
|
||||
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Break)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.CheckSynchronization)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.EnqueueForRejit)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr32))); // A32 only.
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl032))); // A32 only.
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032))); // A32 only.
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SupervisorCall)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Undefined)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128)));
|
||||
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingSigns)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingZeros)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32b)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cb)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32ch)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cw)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cx)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32h)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashParity)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashUpper)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS32)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU32)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart1)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart2)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlReg)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlRegSatQ)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl1)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl2)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl3)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl4)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx1)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx2)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx3)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx4)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlReg)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlRegSatQ)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64)));
|
||||
|
||||
SetDelegateInfo(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)));
|
||||
SetDelegateInfo(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)));
|
||||
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQ)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGE)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGT)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGTFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLE)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLT)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLTFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPDiv)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMul)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSub)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSubFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulX)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt)));
|
||||
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSub)));
|
||||
|
||||
SetDelegateInfo(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)));
|
||||
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAddFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQ)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGE)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGT)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGTFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLE)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLT)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLTFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPDiv)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMax)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNum)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMin)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNum)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMul)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSub)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSubFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulX)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulAdd)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt)));
|
||||
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub)));
|
||||
|
||||
SetDelegateInfo(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)));
|
||||
}
|
||||
}
|
||||
}
|
53
Directory.Packages.props
Normal file
53
Directory.Packages.props
Normal file
@ -0,0 +1,53 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Avalonia" Version="0.10.19" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="0.10.19" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="0.10.19" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="0.10.19" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="0.10.19" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="Concentus" Version="1.1.7" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.1.3.18" />
|
||||
<PackageVersion Include="DynamicData" Version="7.13.8" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="1.4.5" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
|
||||
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
|
||||
<PackageVersion Include="LibHac" Version="0.18.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
<PackageVersion Include="NUnit" Version="3.13.3" />
|
||||
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||
<PackageVersion Include="OpenTK.Core" Version="4.7.7" />
|
||||
<PackageVersion Include="OpenTK.Graphics" Version="4.7.7" />
|
||||
<PackageVersion Include="OpenTK.OpenAL" Version="4.7.7" />
|
||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.7.7" />
|
||||
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.26.3-build25" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
|
||||
<PackageVersion Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
||||
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.30.1" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
||||
<PackageVersion Include="System.Management" Version="7.0.1" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.6.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
18
README.md
18
README.md
@ -21,13 +21,17 @@
|
||||
<img src="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml/badge.svg"
|
||||
alt="">
|
||||
</a>
|
||||
<a href="https://crwd.in/ryujinx">
|
||||
<img src="https://badges.crowdin.net/ryujinx/localized.svg"
|
||||
alt="">
|
||||
</a>
|
||||
<a href="https://discord.com/invite/VkQYXAZ">
|
||||
<img src="https://img.shields.io/discord/410208534861447168?color=5865F2&label=Ryujinx&logo=discord&logoColor=white"
|
||||
alt="Discord">
|
||||
</a>
|
||||
<br>
|
||||
<br>
|
||||
<img src="https://raw.githubusercontent.com/Ryujinx/Ryujinx-Website/master/static/public/shell_fullsize.png">
|
||||
<img src="https://raw.githubusercontent.com/Ryujinx/Ryujinx-Website/master/public/assets/images/shell.png">
|
||||
</p>
|
||||
|
||||
<h5 align="center">
|
||||
@ -36,18 +40,20 @@
|
||||
|
||||
## Compatibility
|
||||
|
||||
As of September 2022, Ryujinx has been tested on approximately 3,600 titles; over 3,400 boot past menus and into gameplay, with roughly 2,700 of those being considered playable. You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues).
|
||||
Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
||||
As of April 2023, Ryujinx has been tested on approximately 4,050 titles; over 4,000 boot past menus and into gameplay, with roughly 3,400 of those being considered playable.
|
||||
You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
||||
|
||||
## Usage
|
||||
|
||||
To run this emulator, your PC must be equipped with at least 8GB of RAM; failing to meet this requirement may result in a poor gameplay experience or unexpected crashes.
|
||||
To run this emulator, your PC must be equipped with at least 8GiB of RAM; failing to meet this requirement may result in a poor gameplay experience or unexpected crashes.
|
||||
|
||||
See our [Setup & Configuration Guide](https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide) on how to set up the emulator.
|
||||
|
||||
For our Local Wireless and LAN builds, see our [Multiplayer: Local Play/Local Wireless Guide
|
||||
](https://github.com/Ryujinx/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide).
|
||||
|
||||
Avalonia UI comes with translations for various languages. See [Crowdin](https://crwd.in/ryujinx) for more information.
|
||||
|
||||
## Latest build
|
||||
|
||||
These builds are compiled automatically for each commit on the master branch. While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken.**
|
||||
@ -62,7 +68,7 @@ The latest automatic build for Windows, macOS, and Linux can be found on the [Of
|
||||
If you wish to build the emulator yourself, follow these steps:
|
||||
|
||||
### Step 1
|
||||
Install the X64 version of [.NET 6.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/6.0).
|
||||
Install the X64 version of [.NET 7.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/7.0).
|
||||
|
||||
### Step 2
|
||||
Either use `git clone https://github.com/Ryujinx/Ryujinx` on the command line to clone the repository or use Code --> Download zip button to get the files.
|
||||
@ -90,7 +96,7 @@ Ryujinx system files are stored in the `Ryujinx` folder. This folder is located
|
||||
|
||||
- **GPU**
|
||||
|
||||
The GPU emulator emulates the Switch's Maxwell GPU using the OpenGL API (version 4.5 minimum) through a custom build of OpenTK. There are currently four graphics enhancements available to the end user in Ryujinx: disk shader caching, resolution scaling, aspect ratio adjustment and anisotropic filtering. These enhancements can be adjusted or toggled as desired in the GUI.
|
||||
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively. There are currently six graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Anti-Aliasing, Scaling Filters (including FSR), Anisotropic Filtering and Aspect Ratio Adjustment. These enhancements can be adjusted or toggled as desired in the GUI.
|
||||
|
||||
- **Input**
|
||||
|
||||
|
@ -1,38 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public static class MarshalEx
|
||||
{
|
||||
public static double ReadDouble(IntPtr handle, int offset = 0)
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble(Marshal.ReadInt64(handle, offset));
|
||||
}
|
||||
|
||||
public static void WriteDouble(IntPtr handle, double value)
|
||||
{
|
||||
WriteDouble(handle, 0, value);
|
||||
}
|
||||
|
||||
public static void WriteDouble(IntPtr handle, int offset, double value)
|
||||
{
|
||||
Marshal.WriteInt64(handle, offset, BitConverter.DoubleToInt64Bits(value));
|
||||
}
|
||||
|
||||
public static float ReadFloat(IntPtr handle, int offset = 0)
|
||||
{
|
||||
return BitConverter.Int32BitsToSingle(Marshal.ReadInt32(handle, offset));
|
||||
}
|
||||
|
||||
public static void WriteFloat(IntPtr handle, float value)
|
||||
{
|
||||
WriteFloat(handle, 0, value);
|
||||
}
|
||||
|
||||
public static void WriteFloat(IntPtr handle, int offset, float value)
|
||||
{
|
||||
Marshal.WriteInt32(handle, offset, BitConverter.SingleToInt32Bits(value));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,386 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public class SoundIO : IDisposable
|
||||
{
|
||||
Pointer<SoundIo> handle;
|
||||
|
||||
public SoundIO()
|
||||
{
|
||||
handle = Natives.soundio_create();
|
||||
}
|
||||
|
||||
internal SoundIO(Pointer<SoundIo> handle)
|
||||
{
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
foreach (var h in allocated_hglobals)
|
||||
{
|
||||
Marshal.FreeHGlobal(h);
|
||||
}
|
||||
|
||||
Natives.soundio_destroy(handle);
|
||||
}
|
||||
|
||||
// Equality (based on handle)
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
var d = other as SoundIO;
|
||||
|
||||
return d != null && this.handle == d.handle;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (int)(IntPtr)handle;
|
||||
}
|
||||
|
||||
public static bool operator == (SoundIO obj1, SoundIO obj2)
|
||||
{
|
||||
return obj1 is null ? obj2 is null : obj1.Equals(obj2);
|
||||
}
|
||||
|
||||
public static bool operator != (SoundIO obj1, SoundIO obj2)
|
||||
{
|
||||
return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
|
||||
}
|
||||
|
||||
// fields
|
||||
|
||||
// FIXME: this should be taken care in more centralized/decent manner... we don't want to write
|
||||
// this kind of code anywhere we need string marshaling.
|
||||
List<IntPtr> allocated_hglobals = new List<IntPtr>();
|
||||
|
||||
public string ApplicationName {
|
||||
get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, app_name_offset)); }
|
||||
set
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
var existing = Marshal.ReadIntPtr(handle, app_name_offset);
|
||||
if (allocated_hglobals.Contains (existing))
|
||||
{
|
||||
allocated_hglobals.Remove(existing);
|
||||
Marshal.FreeHGlobal(existing);
|
||||
}
|
||||
|
||||
var ptr = Marshal.StringToHGlobalAnsi(value);
|
||||
Marshal.WriteIntPtr(handle, app_name_offset, ptr);
|
||||
allocated_hglobals.Add(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int app_name_offset = (int)Marshal.OffsetOf<SoundIo>("app_name");
|
||||
|
||||
public SoundIOBackend CurrentBackend
|
||||
{
|
||||
get { return (SoundIOBackend)Marshal.ReadInt32(handle, current_backend_offset); }
|
||||
}
|
||||
|
||||
static readonly int current_backend_offset = (int)Marshal.OffsetOf<SoundIo>("current_backend");
|
||||
|
||||
// emit_rtprio_warning
|
||||
public Action EmitRealtimePriorityWarning
|
||||
{
|
||||
get { return emit_rtprio_warning; }
|
||||
set
|
||||
{
|
||||
emit_rtprio_warning = value;
|
||||
|
||||
var ptr = Marshal.GetFunctionPointerForDelegate(on_devices_change);
|
||||
|
||||
Marshal.WriteIntPtr(handle, emit_rtprio_warning_offset, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int emit_rtprio_warning_offset = (int)Marshal.OffsetOf<SoundIo>("emit_rtprio_warning");
|
||||
|
||||
Action emit_rtprio_warning;
|
||||
|
||||
// jack_error_callback
|
||||
public Action<string> JackErrorCallback
|
||||
{
|
||||
get { return jack_error_callback; }
|
||||
set
|
||||
{
|
||||
jack_error_callback = value;
|
||||
if (value == null)
|
||||
{
|
||||
jack_error_callback = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
jack_error_callback_native = msg => jack_error_callback(msg);
|
||||
}
|
||||
|
||||
var ptr = Marshal.GetFunctionPointerForDelegate(jack_error_callback_native);
|
||||
Marshal.WriteIntPtr(handle, jack_error_callback_offset, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int jack_error_callback_offset = (int)Marshal.OffsetOf<SoundIo>("jack_error_callback");
|
||||
|
||||
Action<string> jack_error_callback;
|
||||
delegate void jack_error_delegate(string message);
|
||||
jack_error_delegate jack_error_callback_native;
|
||||
|
||||
// jack_info_callback
|
||||
public Action<string> JackInfoCallback
|
||||
{
|
||||
get { return jack_info_callback; }
|
||||
set
|
||||
{
|
||||
jack_info_callback = value;
|
||||
if (value == null)
|
||||
{
|
||||
jack_info_callback = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
jack_info_callback_native = msg => jack_info_callback(msg);
|
||||
}
|
||||
|
||||
var ptr = Marshal.GetFunctionPointerForDelegate(jack_info_callback_native);
|
||||
Marshal.WriteIntPtr(handle, jack_info_callback_offset, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int jack_info_callback_offset = (int)Marshal.OffsetOf<SoundIo>("jack_info_callback");
|
||||
|
||||
Action<string> jack_info_callback;
|
||||
delegate void jack_info_delegate(string message);
|
||||
jack_info_delegate jack_info_callback_native;
|
||||
|
||||
// on_backend_disconnect
|
||||
public Action<int> OnBackendDisconnect
|
||||
{
|
||||
get { return on_backend_disconnect; }
|
||||
set
|
||||
{
|
||||
on_backend_disconnect = value;
|
||||
if (value == null)
|
||||
{
|
||||
on_backend_disconnect_native = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
on_backend_disconnect_native = (sio, err) => on_backend_disconnect(err);
|
||||
}
|
||||
|
||||
var ptr = Marshal.GetFunctionPointerForDelegate(on_backend_disconnect_native);
|
||||
Marshal.WriteIntPtr(handle, on_backend_disconnect_offset, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int on_backend_disconnect_offset = (int)Marshal.OffsetOf<SoundIo>("on_backend_disconnect");
|
||||
|
||||
Action<int> on_backend_disconnect;
|
||||
delegate void on_backend_disconnect_delegate(IntPtr handle, int errorCode);
|
||||
on_backend_disconnect_delegate on_backend_disconnect_native;
|
||||
|
||||
// on_devices_change
|
||||
public Action OnDevicesChange
|
||||
{
|
||||
get { return on_devices_change; }
|
||||
set
|
||||
{
|
||||
on_devices_change = value;
|
||||
if (value == null)
|
||||
{
|
||||
on_devices_change_native = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
on_devices_change_native = sio => on_devices_change();
|
||||
}
|
||||
|
||||
var ptr = Marshal.GetFunctionPointerForDelegate(on_devices_change_native);
|
||||
Marshal.WriteIntPtr(handle, on_devices_change_offset, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int on_devices_change_offset = (int)Marshal.OffsetOf<SoundIo>("on_devices_change");
|
||||
|
||||
Action on_devices_change;
|
||||
delegate void on_devices_change_delegate(IntPtr handle);
|
||||
on_devices_change_delegate on_devices_change_native;
|
||||
|
||||
// on_events_signal
|
||||
public Action OnEventsSignal
|
||||
{
|
||||
get { return on_events_signal; }
|
||||
set
|
||||
{
|
||||
on_events_signal = value;
|
||||
if (value == null)
|
||||
{
|
||||
on_events_signal_native = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
on_events_signal_native = sio => on_events_signal();
|
||||
}
|
||||
|
||||
var ptr = Marshal.GetFunctionPointerForDelegate(on_events_signal_native);
|
||||
Marshal.WriteIntPtr(handle, on_events_signal_offset, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int on_events_signal_offset = (int)Marshal.OffsetOf<SoundIo>("on_events_signal");
|
||||
|
||||
Action on_events_signal;
|
||||
delegate void on_events_signal_delegate(IntPtr handle);
|
||||
on_events_signal_delegate on_events_signal_native;
|
||||
|
||||
|
||||
// functions
|
||||
|
||||
public int BackendCount
|
||||
{
|
||||
get { return Natives.soundio_backend_count(handle); }
|
||||
}
|
||||
|
||||
public int InputDeviceCount
|
||||
{
|
||||
get { return Natives.soundio_input_device_count(handle); }
|
||||
}
|
||||
|
||||
public int OutputDeviceCount
|
||||
{
|
||||
get { return Natives.soundio_output_device_count(handle); }
|
||||
}
|
||||
|
||||
public int DefaultInputDeviceIndex
|
||||
{
|
||||
get { return Natives.soundio_default_input_device_index(handle); }
|
||||
}
|
||||
|
||||
public int DefaultOutputDeviceIndex
|
||||
{
|
||||
get { return Natives.soundio_default_output_device_index(handle); }
|
||||
}
|
||||
|
||||
public SoundIOBackend GetBackend(int index)
|
||||
{
|
||||
return (SoundIOBackend)Natives.soundio_get_backend(handle, index);
|
||||
}
|
||||
|
||||
public SoundIODevice GetInputDevice(int index)
|
||||
{
|
||||
return new SoundIODevice(Natives.soundio_get_input_device(handle, index));
|
||||
}
|
||||
|
||||
public SoundIODevice GetOutputDevice(int index)
|
||||
{
|
||||
return new SoundIODevice(Natives.soundio_get_output_device(handle, index));
|
||||
}
|
||||
|
||||
public void Connect()
|
||||
{
|
||||
var ret = (SoundIoError)Natives.soundio_connect(handle);
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
{
|
||||
throw new SoundIOException(ret);
|
||||
}
|
||||
}
|
||||
|
||||
public void ConnectBackend(SoundIOBackend backend)
|
||||
{
|
||||
var ret = (SoundIoError)Natives.soundio_connect_backend(handle, (SoundIoBackend)backend);
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
{
|
||||
throw new SoundIOException(ret);
|
||||
}
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
Natives.soundio_disconnect(handle);
|
||||
}
|
||||
|
||||
public void FlushEvents()
|
||||
{
|
||||
Natives.soundio_flush_events(handle);
|
||||
}
|
||||
|
||||
public void WaitEvents()
|
||||
{
|
||||
Natives.soundio_wait_events(handle);
|
||||
}
|
||||
|
||||
public void Wakeup()
|
||||
{
|
||||
Natives.soundio_wakeup(handle);
|
||||
}
|
||||
|
||||
public void ForceDeviceScan()
|
||||
{
|
||||
Natives.soundio_force_device_scan(handle);
|
||||
}
|
||||
|
||||
public SoundIORingBuffer CreateRingBuffer(int capacity)
|
||||
{
|
||||
return new SoundIORingBuffer(Natives.soundio_ring_buffer_create(handle, capacity));
|
||||
}
|
||||
|
||||
// static methods
|
||||
|
||||
public static string VersionString
|
||||
{
|
||||
get { return Marshal.PtrToStringAnsi(Natives.soundio_version_string()); }
|
||||
}
|
||||
|
||||
public static int VersionMajor
|
||||
{
|
||||
get { return Natives.soundio_version_major(); }
|
||||
}
|
||||
|
||||
public static int VersionMinor
|
||||
{
|
||||
get { return Natives.soundio_version_minor(); }
|
||||
}
|
||||
|
||||
public static int VersionPatch
|
||||
{
|
||||
get { return Natives.soundio_version_patch(); }
|
||||
}
|
||||
|
||||
public static string GetBackendName(SoundIOBackend backend)
|
||||
{
|
||||
return Marshal.PtrToStringAnsi(Natives.soundio_backend_name((SoundIoBackend)backend));
|
||||
}
|
||||
|
||||
public static bool HaveBackend(SoundIOBackend backend)
|
||||
{
|
||||
return Natives.soundio_have_backend((SoundIoBackend)backend);
|
||||
}
|
||||
|
||||
public static int GetBytesPerSample(SoundIOFormat format)
|
||||
{
|
||||
return Natives.soundio_get_bytes_per_sample((SoundIoFormat)format);
|
||||
}
|
||||
|
||||
public static int GetBytesPerFrame(SoundIOFormat format, int channelCount)
|
||||
{
|
||||
return Natives.soundio_get_bytes_per_frame((SoundIoFormat)format, channelCount);
|
||||
}
|
||||
|
||||
public static int GetBytesPerSecond(SoundIOFormat format, int channelCount, int sampleRate)
|
||||
{
|
||||
return Natives.soundio_get_bytes_per_second((SoundIoFormat)format, channelCount, sampleRate);
|
||||
}
|
||||
|
||||
public static string GetSoundFormatName(SoundIOFormat format)
|
||||
{
|
||||
return Marshal.PtrToStringAnsi(Natives.soundio_format_string((SoundIoFormat)format));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public enum SoundIOBackend
|
||||
{
|
||||
None,
|
||||
Jack,
|
||||
PulseAudio,
|
||||
Alsa,
|
||||
CoreAudio,
|
||||
Wasapi,
|
||||
Dummy
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public struct SoundIOChannelArea
|
||||
{
|
||||
internal SoundIOChannelArea(Pointer<SoundIoChannelArea> handle)
|
||||
{
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
Pointer<SoundIoChannelArea> handle;
|
||||
|
||||
public IntPtr Pointer
|
||||
{
|
||||
get { return Marshal.ReadIntPtr(handle, ptr_offset); }
|
||||
set { Marshal.WriteIntPtr(handle, ptr_offset, value); }
|
||||
}
|
||||
|
||||
static readonly int ptr_offset = (int)Marshal.OffsetOf<SoundIoChannelArea>("ptr");
|
||||
|
||||
public int Step
|
||||
{
|
||||
get { return Marshal.ReadInt32(handle, step_offset); }
|
||||
}
|
||||
|
||||
static readonly int step_offset = (int)Marshal.OffsetOf<SoundIoChannelArea>("step");
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public struct SoundIOChannelAreas
|
||||
{
|
||||
static readonly int native_size = Marshal.SizeOf<SoundIoChannelArea>();
|
||||
|
||||
internal SoundIOChannelAreas(IntPtr head, int channelCount, int frameCount)
|
||||
{
|
||||
this.head = head;
|
||||
this.channel_count = channelCount;
|
||||
this.frame_count = frameCount;
|
||||
}
|
||||
|
||||
IntPtr head;
|
||||
int channel_count;
|
||||
int frame_count;
|
||||
|
||||
public bool IsEmpty
|
||||
{
|
||||
get { return head == IntPtr.Zero; }
|
||||
}
|
||||
|
||||
public SoundIOChannelArea GetArea(int channel)
|
||||
{
|
||||
return new SoundIOChannelArea(head + native_size * channel);
|
||||
}
|
||||
|
||||
public int ChannelCount => channel_count;
|
||||
public int FrameCount => frame_count;
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public enum SoundIOChannelId
|
||||
{
|
||||
Invalid,
|
||||
FrontLeft,
|
||||
FrontRight,
|
||||
FrontCenter,
|
||||
Lfe,
|
||||
BackLeft,
|
||||
BackRight,
|
||||
FrontLeftCenter,
|
||||
FrontRightCenter,
|
||||
BackCenter,
|
||||
SideLeft,
|
||||
SideRight,
|
||||
TopCenter,
|
||||
TopFrontLeft,
|
||||
TopFrontCenter,
|
||||
TopFrontRight,
|
||||
TopBackLeft,
|
||||
TopBackCenter,
|
||||
TopBackRight,
|
||||
BackLeftCenter,
|
||||
BackRightCenter,
|
||||
FrontLeftWide,
|
||||
FrontRightWide,
|
||||
FrontLeftHigh,
|
||||
FrontCenterHigh,
|
||||
FrontRightHigh,
|
||||
TopFrontLeftCenter,
|
||||
TopFrontRightCenter,
|
||||
TopSideLeft,
|
||||
TopSideRight,
|
||||
LeftLfe,
|
||||
RightLfe,
|
||||
Lfe2,
|
||||
BottomCenter,
|
||||
BottomLeftCenter,
|
||||
BottomRightCenter,
|
||||
MsMid,
|
||||
MsSide,
|
||||
AmbisonicW,
|
||||
AmbisonicX,
|
||||
AmbisonicY,
|
||||
AmbisonicZ,
|
||||
XyX,
|
||||
XyY,
|
||||
HeadphonesLeft,
|
||||
HeadphonesRight,
|
||||
ClickTrack,
|
||||
ForeignLanguage,
|
||||
HearingImpaired,
|
||||
Narration,
|
||||
Haptic,
|
||||
DialogCentricMix,
|
||||
Aux,
|
||||
Aux0,
|
||||
Aux1,
|
||||
Aux2,
|
||||
Aux3,
|
||||
Aux4,
|
||||
Aux5,
|
||||
Aux6,
|
||||
Aux7,
|
||||
Aux8,
|
||||
Aux9,
|
||||
Aux10,
|
||||
Aux11,
|
||||
Aux12,
|
||||
Aux13,
|
||||
Aux14,
|
||||
Aux15
|
||||
}
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public struct SoundIOChannelLayout
|
||||
{
|
||||
public static int BuiltInCount
|
||||
{
|
||||
get { return Natives.soundio_channel_layout_builtin_count(); }
|
||||
}
|
||||
|
||||
public static SoundIOChannelLayout GetBuiltIn(int index)
|
||||
{
|
||||
return new SoundIOChannelLayout(Natives.soundio_channel_layout_get_builtin(index));
|
||||
}
|
||||
|
||||
public static SoundIOChannelLayout GetDefault(int channelCount)
|
||||
{
|
||||
var handle = Natives.soundio_channel_layout_get_default(channelCount);
|
||||
|
||||
return new SoundIOChannelLayout (handle);
|
||||
}
|
||||
|
||||
public static SoundIOChannelId ParseChannelId(string name)
|
||||
{
|
||||
var ptr = Marshal.StringToHGlobalAnsi(name);
|
||||
|
||||
try
|
||||
{
|
||||
return (SoundIOChannelId)Natives.soundio_parse_channel_id(ptr, name.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// instance members
|
||||
|
||||
internal SoundIOChannelLayout(Pointer<SoundIoChannelLayout> handle)
|
||||
{
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
readonly Pointer<SoundIoChannelLayout> handle;
|
||||
|
||||
public bool IsNull
|
||||
{
|
||||
get { return handle.Handle == IntPtr.Zero; }
|
||||
}
|
||||
|
||||
internal IntPtr Handle
|
||||
{
|
||||
get { return handle; }
|
||||
}
|
||||
|
||||
public int ChannelCount
|
||||
{
|
||||
get { return IsNull ? 0 : Marshal.ReadInt32((IntPtr)handle + channel_count_offset); }
|
||||
}
|
||||
|
||||
static readonly int channel_count_offset = (int)Marshal.OffsetOf<SoundIoChannelLayout>("channel_count");
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return IsNull ? null : Marshal.PtrToStringAnsi(Marshal.ReadIntPtr((IntPtr)handle + name_offset)); }
|
||||
}
|
||||
|
||||
static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoChannelLayout>("name");
|
||||
|
||||
public IEnumerable<SoundIOChannelId> Channels
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsNull) yield break;
|
||||
|
||||
for (int i = 0; i < 24; i++)
|
||||
{
|
||||
yield return (SoundIOChannelId)Marshal.ReadInt32((IntPtr)handle + channels_offset + sizeof(SoundIoChannelId) * i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int channels_offset = (int)Marshal.OffsetOf<SoundIoChannelLayout>("channels");
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
if (!(other is SoundIOChannelLayout)) return false;
|
||||
|
||||
var s = (SoundIOChannelLayout) other;
|
||||
|
||||
return handle == s.handle || Natives.soundio_channel_layout_equal(handle, s.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return handle.GetHashCode();
|
||||
}
|
||||
|
||||
public string DetectBuiltInName()
|
||||
{
|
||||
if (IsNull) throw new InvalidOperationException();
|
||||
|
||||
return Natives.soundio_channel_layout_detect_builtin(handle) ? Name : null;
|
||||
}
|
||||
|
||||
public int FindChannel(SoundIOChannelId channel)
|
||||
{
|
||||
if (IsNull) throw new InvalidOperationException();
|
||||
|
||||
return Natives.soundio_channel_layout_find_channel(handle, (SoundIoChannelId)channel);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,267 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public class SoundIODevice
|
||||
{
|
||||
public static SoundIOChannelLayout BestMatchingChannelLayout(SoundIODevice device1, SoundIODevice device2)
|
||||
{
|
||||
var ptr1 = Marshal.ReadIntPtr(device1.handle, layouts_offset);
|
||||
var ptr2 = Marshal.ReadIntPtr(device2.handle, layouts_offset);
|
||||
|
||||
return new SoundIOChannelLayout(Natives.soundio_best_matching_channel_layout(ptr1, device1.LayoutCount, ptr2, device2.LayoutCount));
|
||||
}
|
||||
|
||||
internal SoundIODevice(Pointer<SoundIoDevice> handle)
|
||||
{
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
readonly Pointer<SoundIoDevice> handle;
|
||||
|
||||
// Equality (based on handle and native func)
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
var d = other as SoundIODevice;
|
||||
|
||||
return d != null && (this.handle == d.handle || Natives.soundio_device_equal (this.handle, d.handle));
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (int)(IntPtr)handle;
|
||||
}
|
||||
|
||||
public static bool operator == (SoundIODevice obj1, SoundIODevice obj2)
|
||||
{
|
||||
return obj1 is null ? obj2 is null : obj1.Equals(obj2);
|
||||
}
|
||||
|
||||
public static bool operator != (SoundIODevice obj1, SoundIODevice obj2)
|
||||
{
|
||||
return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
|
||||
}
|
||||
|
||||
// fields
|
||||
|
||||
public SoundIODeviceAim Aim
|
||||
{
|
||||
get { return (SoundIODeviceAim)Marshal.ReadInt32(handle, aim_offset); }
|
||||
}
|
||||
|
||||
static readonly int aim_offset = (int)Marshal.OffsetOf<SoundIoDevice>("aim");
|
||||
|
||||
public SoundIOFormat CurrentFormat
|
||||
{
|
||||
get { return (SoundIOFormat)Marshal.ReadInt32(handle, current_format_offset); }
|
||||
}
|
||||
|
||||
static readonly int current_format_offset = (int)Marshal.OffsetOf<SoundIoDevice>("current_format");
|
||||
|
||||
public SoundIOChannelLayout CurrentLayout
|
||||
{
|
||||
get { return new SoundIOChannelLayout((IntPtr)handle + current_layout_offset); }
|
||||
}
|
||||
|
||||
static readonly int current_layout_offset = (int)Marshal.OffsetOf<SoundIoDevice>("current_layout");
|
||||
|
||||
public int FormatCount
|
||||
{
|
||||
get { return Marshal.ReadInt32(handle, format_count_offset); }
|
||||
}
|
||||
|
||||
static readonly int format_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("format_count");
|
||||
|
||||
public IEnumerable<SoundIOFormat> Formats
|
||||
{
|
||||
get
|
||||
{
|
||||
var ptr = Marshal.ReadIntPtr(handle, formats_offset);
|
||||
|
||||
for (int i = 0; i < FormatCount; i++)
|
||||
{
|
||||
yield return (SoundIOFormat)Marshal.ReadInt32(ptr, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int formats_offset = (int)Marshal.OffsetOf<SoundIoDevice>("formats");
|
||||
|
||||
public string Id
|
||||
{
|
||||
get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, id_offset)); }
|
||||
}
|
||||
|
||||
static readonly int id_offset = (int)Marshal.OffsetOf<SoundIoDevice>("id");
|
||||
|
||||
public bool IsRaw
|
||||
{
|
||||
get { return Marshal.ReadInt32(handle, is_raw_offset) != 0; }
|
||||
}
|
||||
|
||||
static readonly int is_raw_offset = (int)Marshal.OffsetOf<SoundIoDevice>("is_raw");
|
||||
|
||||
public int LayoutCount
|
||||
{
|
||||
get { return Marshal.ReadInt32(handle, layout_count_offset); }
|
||||
}
|
||||
|
||||
static readonly int layout_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("layout_count");
|
||||
|
||||
public IEnumerable<SoundIOChannelLayout> Layouts
|
||||
{
|
||||
get
|
||||
{
|
||||
var ptr = Marshal.ReadIntPtr (handle, layouts_offset);
|
||||
|
||||
for (int i = 0; i < LayoutCount; i++)
|
||||
{
|
||||
yield return new SoundIOChannelLayout(ptr + i * Marshal.SizeOf<SoundIoChannelLayout>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int layouts_offset = (int)Marshal.OffsetOf<SoundIoDevice>("layouts");
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); }
|
||||
}
|
||||
|
||||
static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoDevice>("name");
|
||||
|
||||
public int ProbeError
|
||||
{
|
||||
get { return Marshal.ReadInt32(handle, probe_error_offset); }
|
||||
}
|
||||
|
||||
static readonly int probe_error_offset = (int)Marshal.OffsetOf<SoundIoDevice>("probe_error");
|
||||
|
||||
public int ReferenceCount
|
||||
{
|
||||
get { return Marshal.ReadInt32(handle, ref_count_offset); }
|
||||
}
|
||||
|
||||
static readonly int ref_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("ref_count");
|
||||
|
||||
public int SampleRateCount
|
||||
{
|
||||
get { return Marshal.ReadInt32(handle, sample_rate_count_offset); }
|
||||
}
|
||||
|
||||
static readonly int sample_rate_count_offset = (int)Marshal.OffsetOf<SoundIoDevice>("sample_rate_count");
|
||||
|
||||
public IEnumerable<SoundIOSampleRateRange> SampleRates
|
||||
{
|
||||
get
|
||||
{
|
||||
var ptr = Marshal.ReadIntPtr(handle, sample_rates_offset);
|
||||
|
||||
for (int i = 0; i < SampleRateCount; i++)
|
||||
{
|
||||
yield return new SoundIOSampleRateRange(Marshal.ReadInt32(ptr, i * 2), Marshal.ReadInt32(ptr, i * 2 + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int sample_rates_offset = (int)Marshal.OffsetOf<SoundIoDevice>("sample_rates");
|
||||
|
||||
public double SoftwareLatencyCurrent
|
||||
{
|
||||
get { return MarshalEx.ReadDouble(handle, software_latency_current_offset); }
|
||||
set { MarshalEx.WriteDouble(handle, software_latency_current_offset, value); }
|
||||
}
|
||||
|
||||
static readonly int software_latency_current_offset = (int)Marshal.OffsetOf<SoundIoDevice>("software_latency_current");
|
||||
|
||||
public double SoftwareLatencyMin
|
||||
{
|
||||
get { return MarshalEx.ReadDouble(handle, software_latency_min_offset); }
|
||||
set { MarshalEx.WriteDouble(handle, software_latency_min_offset, value); }
|
||||
}
|
||||
|
||||
static readonly int software_latency_min_offset = (int)Marshal.OffsetOf<SoundIoDevice>("software_latency_min");
|
||||
|
||||
public double SoftwareLatencyMax
|
||||
{
|
||||
get { return MarshalEx.ReadDouble(handle, software_latency_max_offset); }
|
||||
set { MarshalEx.WriteDouble(handle, software_latency_max_offset, value); }
|
||||
}
|
||||
|
||||
static readonly int software_latency_max_offset = (int)Marshal.OffsetOf<SoundIoDevice>("software_latency_max");
|
||||
|
||||
public SoundIO SoundIO
|
||||
{
|
||||
get { return new SoundIO(Marshal.ReadIntPtr(handle, soundio_offset)); }
|
||||
}
|
||||
|
||||
static readonly int soundio_offset = (int)Marshal.OffsetOf<SoundIoDevice>("soundio");
|
||||
|
||||
// functions
|
||||
|
||||
public void AddReference()
|
||||
{
|
||||
Natives.soundio_device_ref(handle);
|
||||
}
|
||||
|
||||
public void RemoveReference()
|
||||
{
|
||||
Natives.soundio_device_unref(handle);
|
||||
}
|
||||
|
||||
public void SortDeviceChannelLayouts()
|
||||
{
|
||||
Natives.soundio_device_sort_channel_layouts(handle);
|
||||
}
|
||||
|
||||
public static readonly SoundIOFormat S16NE = BitConverter.IsLittleEndian ? SoundIOFormat.S16LE : SoundIOFormat.S16BE;
|
||||
public static readonly SoundIOFormat U16NE = BitConverter.IsLittleEndian ? SoundIOFormat.U16LE : SoundIOFormat.U16BE;
|
||||
public static readonly SoundIOFormat S24NE = BitConverter.IsLittleEndian ? SoundIOFormat.S24LE : SoundIOFormat.S24BE;
|
||||
public static readonly SoundIOFormat U24NE = BitConverter.IsLittleEndian ? SoundIOFormat.U24LE : SoundIOFormat.U24BE;
|
||||
public static readonly SoundIOFormat S32NE = BitConverter.IsLittleEndian ? SoundIOFormat.S32LE : SoundIOFormat.S32BE;
|
||||
public static readonly SoundIOFormat U32NE = BitConverter.IsLittleEndian ? SoundIOFormat.U32LE : SoundIOFormat.U32BE;
|
||||
public static readonly SoundIOFormat Float32NE = BitConverter.IsLittleEndian ? SoundIOFormat.Float32LE : SoundIOFormat.Float32BE;
|
||||
public static readonly SoundIOFormat Float64NE = BitConverter.IsLittleEndian ? SoundIOFormat.Float64LE : SoundIOFormat.Float64BE;
|
||||
public static readonly SoundIOFormat S16FE = !BitConverter.IsLittleEndian ? SoundIOFormat.S16LE : SoundIOFormat.S16BE;
|
||||
public static readonly SoundIOFormat U16FE = !BitConverter.IsLittleEndian ? SoundIOFormat.U16LE : SoundIOFormat.U16BE;
|
||||
public static readonly SoundIOFormat S24FE = !BitConverter.IsLittleEndian ? SoundIOFormat.S24LE : SoundIOFormat.S24BE;
|
||||
public static readonly SoundIOFormat U24FE = !BitConverter.IsLittleEndian ? SoundIOFormat.U24LE : SoundIOFormat.U24BE;
|
||||
public static readonly SoundIOFormat S32FE = !BitConverter.IsLittleEndian ? SoundIOFormat.S32LE : SoundIOFormat.S32BE;
|
||||
public static readonly SoundIOFormat U32FE = !BitConverter.IsLittleEndian ? SoundIOFormat.U32LE : SoundIOFormat.U32BE;
|
||||
public static readonly SoundIOFormat Float32FE = !BitConverter.IsLittleEndian ? SoundIOFormat.Float32LE : SoundIOFormat.Float32BE;
|
||||
public static readonly SoundIOFormat Float64FE = !BitConverter.IsLittleEndian ? SoundIOFormat.Float64LE : SoundIOFormat.Float64BE;
|
||||
|
||||
public bool SupportsFormat(SoundIOFormat format)
|
||||
{
|
||||
return Natives.soundio_device_supports_format(handle, (SoundIoFormat)format);
|
||||
}
|
||||
|
||||
public bool SupportsSampleRate(int sampleRate)
|
||||
{
|
||||
return Natives.soundio_device_supports_sample_rate(handle, sampleRate);
|
||||
}
|
||||
|
||||
public bool SupportsChannelCount(int channelCount)
|
||||
{
|
||||
return Natives.soundio_device_supports_layout(handle, SoundIOChannelLayout.GetDefault(channelCount).Handle);
|
||||
}
|
||||
|
||||
public int GetNearestSampleRate(int sampleRate)
|
||||
{
|
||||
return Natives.soundio_device_nearest_sample_rate(handle, sampleRate);
|
||||
}
|
||||
|
||||
public SoundIOInStream CreateInStream()
|
||||
{
|
||||
return new SoundIOInStream(Natives.soundio_instream_create(handle));
|
||||
}
|
||||
|
||||
public SoundIOOutStream CreateOutStream()
|
||||
{
|
||||
return new SoundIOOutStream(Natives.soundio_outstream_create(handle));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public enum SoundIODeviceAim // soundio.h (228, 6)
|
||||
{
|
||||
Input,
|
||||
Output
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public class SoundIOException : Exception
|
||||
{
|
||||
internal SoundIOException(SoundIoError errorCode) : base (Marshal.PtrToStringAnsi(Natives.soundio_strerror((int) errorCode))) { }
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public enum SoundIOFormat
|
||||
{
|
||||
Invalid,
|
||||
S8,
|
||||
U8,
|
||||
S16LE,
|
||||
S16BE,
|
||||
U16LE,
|
||||
U16BE,
|
||||
S24LE,
|
||||
S24BE,
|
||||
U24LE,
|
||||
U24BE,
|
||||
S32LE,
|
||||
S32BE,
|
||||
U32LE,
|
||||
U32BE,
|
||||
Float32LE,
|
||||
Float32BE,
|
||||
Float64LE,
|
||||
Float64BE
|
||||
}
|
||||
}
|
@ -1,293 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public class SoundIOInStream : IDisposable
|
||||
{
|
||||
internal SoundIOInStream(Pointer<SoundIoInStream> handle)
|
||||
{
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
Pointer<SoundIoInStream> handle;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Natives.soundio_instream_destroy(handle);
|
||||
}
|
||||
|
||||
// Equality (based on handle)
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
var d = other as SoundIOInStream;
|
||||
|
||||
return d != null && (this.handle == d.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (int)(IntPtr)handle;
|
||||
}
|
||||
|
||||
public static bool operator == (SoundIOInStream obj1, SoundIOInStream obj2)
|
||||
{
|
||||
return obj1 is null ? obj2 is null : obj1.Equals(obj2);
|
||||
}
|
||||
|
||||
public static bool operator != (SoundIOInStream obj1, SoundIOInStream obj2)
|
||||
{
|
||||
return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
|
||||
}
|
||||
|
||||
// fields
|
||||
|
||||
public SoundIODevice Device
|
||||
{
|
||||
get { return new SoundIODevice(Marshal.ReadIntPtr(handle, device_offset)); }
|
||||
}
|
||||
|
||||
static readonly int device_offset = (int)Marshal.OffsetOf<SoundIoInStream>("device");
|
||||
|
||||
public SoundIOFormat Format
|
||||
{
|
||||
get { return (SoundIOFormat)Marshal.ReadInt32(handle, format_offset); }
|
||||
set { Marshal.WriteInt32(handle, format_offset, (int) value); }
|
||||
}
|
||||
|
||||
static readonly int format_offset = (int)Marshal.OffsetOf<SoundIoInStream>("format");
|
||||
|
||||
public int SampleRate
|
||||
{
|
||||
get { return Marshal.ReadInt32(handle, sample_rate_offset); }
|
||||
set { Marshal.WriteInt32(handle, sample_rate_offset, value); }
|
||||
}
|
||||
|
||||
static readonly int sample_rate_offset = (int)Marshal.OffsetOf<SoundIoInStream>("sample_rate");
|
||||
|
||||
public SoundIOChannelLayout Layout
|
||||
{
|
||||
get { return new SoundIOChannelLayout ((IntPtr) handle + layout_offset); }
|
||||
set
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
Buffer.MemoryCopy((void*)((IntPtr)handle + layout_offset), (void*)value.Handle, Marshal.SizeOf<SoundIoChannelLayout>(), Marshal.SizeOf<SoundIoChannelLayout>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int layout_offset = (int)Marshal.OffsetOf<SoundIoInStream>("layout");
|
||||
|
||||
public double SoftwareLatency
|
||||
{
|
||||
get { return MarshalEx.ReadDouble(handle, software_latency_offset); }
|
||||
set { MarshalEx.WriteDouble(handle, software_latency_offset, value); }
|
||||
}
|
||||
|
||||
static readonly int software_latency_offset = (int)Marshal.OffsetOf<SoundIoInStream>("software_latency");
|
||||
|
||||
// error_callback
|
||||
public Action ErrorCallback
|
||||
{
|
||||
get { return error_callback; }
|
||||
set
|
||||
{
|
||||
error_callback = value;
|
||||
error_callback_native = _ => error_callback();
|
||||
|
||||
var ptr = Marshal.GetFunctionPointerForDelegate(error_callback_native);
|
||||
|
||||
Marshal.WriteIntPtr(handle, error_callback_offset, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int error_callback_offset = (int)Marshal.OffsetOf<SoundIoInStream>("error_callback");
|
||||
|
||||
Action error_callback;
|
||||
delegate void error_callback_delegate(IntPtr handle);
|
||||
error_callback_delegate error_callback_native;
|
||||
|
||||
// read_callback
|
||||
public Action<int,int> ReadCallback
|
||||
{
|
||||
get { return read_callback; }
|
||||
set
|
||||
{
|
||||
read_callback = value;
|
||||
read_callback_native = (_, minFrameCount, maxFrameCount) => read_callback(minFrameCount, maxFrameCount);
|
||||
|
||||
var ptr = Marshal.GetFunctionPointerForDelegate(read_callback_native);
|
||||
|
||||
Marshal.WriteIntPtr(handle, read_callback_offset, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int read_callback_offset = (int)Marshal.OffsetOf<SoundIoInStream>("read_callback");
|
||||
|
||||
Action<int, int> read_callback;
|
||||
delegate void read_callback_delegate(IntPtr handle, int min, int max);
|
||||
read_callback_delegate read_callback_native;
|
||||
|
||||
// overflow_callback
|
||||
public Action OverflowCallback
|
||||
{
|
||||
get { return overflow_callback; }
|
||||
set
|
||||
{
|
||||
overflow_callback = value;
|
||||
overflow_callback_native = _ => overflow_callback();
|
||||
|
||||
var ptr = Marshal.GetFunctionPointerForDelegate(overflow_callback_native);
|
||||
|
||||
Marshal.WriteIntPtr(handle, overflow_callback_offset, ptr);
|
||||
}
|
||||
}
|
||||
static readonly int overflow_callback_offset = (int)Marshal.OffsetOf<SoundIoInStream>("overflow_callback");
|
||||
|
||||
Action overflow_callback;
|
||||
delegate void overflow_callback_delegate(IntPtr handle);
|
||||
overflow_callback_delegate overflow_callback_native;
|
||||
|
||||
// FIXME: this should be taken care in more centralized/decent manner... we don't want to write
|
||||
// this kind of code anywhere we need string marshaling.
|
||||
List<IntPtr> allocated_hglobals = new List<IntPtr>();
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); }
|
||||
set
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
var existing = Marshal.ReadIntPtr(handle, name_offset);
|
||||
if (allocated_hglobals.Contains(existing))
|
||||
{
|
||||
allocated_hglobals.Remove(existing);
|
||||
Marshal.FreeHGlobal(existing);
|
||||
}
|
||||
|
||||
var ptr = Marshal.StringToHGlobalAnsi(value);
|
||||
Marshal.WriteIntPtr(handle, name_offset, ptr);
|
||||
allocated_hglobals.Add(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoInStream>("name");
|
||||
|
||||
public bool NonTerminalHint
|
||||
{
|
||||
get { return Marshal.ReadInt32(handle, non_terminal_hint_offset) != 0; }
|
||||
}
|
||||
|
||||
static readonly int non_terminal_hint_offset = (int)Marshal.OffsetOf<SoundIoInStream>("non_terminal_hint");
|
||||
|
||||
public int BytesPerFrame
|
||||
{
|
||||
get { return Marshal.ReadInt32(handle, bytes_per_frame_offset); }
|
||||
}
|
||||
|
||||
static readonly int bytes_per_frame_offset = (int)Marshal.OffsetOf<SoundIoInStream>("bytes_per_frame");
|
||||
|
||||
public int BytesPerSample
|
||||
{
|
||||
get { return Marshal.ReadInt32(handle, bytes_per_sample_offset); }
|
||||
}
|
||||
|
||||
static readonly int bytes_per_sample_offset = (int)Marshal.OffsetOf<SoundIoInStream>("bytes_per_sample");
|
||||
|
||||
public string LayoutErrorMessage
|
||||
{
|
||||
get
|
||||
{
|
||||
var code = (SoundIoError)Marshal.ReadInt32(handle, layout_error_offset);
|
||||
|
||||
return code == SoundIoError.SoundIoErrorNone ? null : Marshal.PtrToStringAnsi(Natives.soundio_strerror((int)code));
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int layout_error_offset = (int)Marshal.OffsetOf<SoundIoInStream>("layout_error");
|
||||
|
||||
// functions
|
||||
|
||||
public void Open()
|
||||
{
|
||||
var ret = (SoundIoError)Natives.soundio_instream_open(handle);
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
{
|
||||
throw new SoundIOException(ret);
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
var ret = (SoundIoError)Natives.soundio_instream_start(handle);
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
{
|
||||
throw new SoundIOException(ret);
|
||||
}
|
||||
}
|
||||
|
||||
public SoundIOChannelAreas BeginRead(ref int frameCount)
|
||||
{
|
||||
IntPtr ptrs = default;
|
||||
int nativeFrameCount = frameCount;
|
||||
|
||||
unsafe
|
||||
{
|
||||
var frameCountPtr = &nativeFrameCount;
|
||||
var ptrptr = &ptrs;
|
||||
var ret = (SoundIoError)Natives.soundio_instream_begin_read(handle, (IntPtr)ptrptr, (IntPtr)frameCountPtr);
|
||||
|
||||
frameCount = *frameCountPtr;
|
||||
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
{
|
||||
throw new SoundIOException(ret);
|
||||
}
|
||||
|
||||
return new SoundIOChannelAreas(ptrs, Layout.ChannelCount, frameCount);
|
||||
}
|
||||
}
|
||||
|
||||
public void EndRead()
|
||||
{
|
||||
var ret = (SoundIoError)Natives.soundio_instream_end_read(handle);
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
{
|
||||
throw new SoundIOException(ret);
|
||||
}
|
||||
}
|
||||
|
||||
public void Pause(bool pause)
|
||||
{
|
||||
var ret = (SoundIoError)Natives.soundio_instream_pause(handle, pause);
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
{
|
||||
throw new SoundIOException(ret);
|
||||
}
|
||||
}
|
||||
|
||||
public double GetLatency()
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
double* dptr = null;
|
||||
IntPtr p = new IntPtr(dptr);
|
||||
|
||||
var ret = (SoundIoError)Natives.soundio_instream_get_latency(handle, p);
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
{
|
||||
throw new SoundIOException(ret);
|
||||
}
|
||||
|
||||
dptr = (double*)p;
|
||||
|
||||
return *dptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,331 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public class SoundIOOutStream : IDisposable
|
||||
{
|
||||
internal SoundIOOutStream (Pointer<SoundIoOutStream> handle)
|
||||
{
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
Pointer<SoundIoOutStream> handle;
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
Natives.soundio_outstream_destroy (handle);
|
||||
}
|
||||
// Equality (based on handle)
|
||||
|
||||
public override bool Equals (object other)
|
||||
{
|
||||
var d = other as SoundIOOutStream;
|
||||
|
||||
return d != null && (this.handle == d.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return (int)(IntPtr)handle;
|
||||
}
|
||||
|
||||
public static bool operator == (SoundIOOutStream obj1, SoundIOOutStream obj2)
|
||||
{
|
||||
return obj1 is null ? obj2 is null : obj1.Equals(obj2);
|
||||
}
|
||||
|
||||
public static bool operator != (SoundIOOutStream obj1, SoundIOOutStream obj2)
|
||||
{
|
||||
return obj1 is null ? obj2 is object : !obj1.Equals(obj2);
|
||||
}
|
||||
|
||||
// fields
|
||||
|
||||
public SoundIODevice Device
|
||||
{
|
||||
get { return new SoundIODevice(Marshal.ReadIntPtr(handle, device_offset)); }
|
||||
}
|
||||
|
||||
static readonly int device_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("device");
|
||||
|
||||
public SoundIOFormat Format
|
||||
{
|
||||
get { return (SoundIOFormat) Marshal.ReadInt32(handle, format_offset); }
|
||||
set { Marshal.WriteInt32(handle, format_offset, (int) value); }
|
||||
}
|
||||
|
||||
static readonly int format_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("format");
|
||||
|
||||
public int SampleRate
|
||||
{
|
||||
get { return Marshal.ReadInt32(handle, sample_rate_offset); }
|
||||
set { Marshal.WriteInt32(handle, sample_rate_offset, value); }
|
||||
}
|
||||
|
||||
static readonly int sample_rate_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("sample_rate");
|
||||
|
||||
public SoundIOChannelLayout Layout
|
||||
{
|
||||
get { unsafe { return new SoundIOChannelLayout((IntPtr) (void*)((IntPtr)handle + layout_offset)); } }
|
||||
set
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
Buffer.MemoryCopy((void*)value.Handle, (void*)((IntPtr)handle + layout_offset), Marshal.SizeOf<SoundIoChannelLayout>(), Marshal.SizeOf<SoundIoChannelLayout>());
|
||||
}
|
||||
}
|
||||
}
|
||||
static readonly int layout_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("layout");
|
||||
|
||||
public double SoftwareLatency
|
||||
{
|
||||
get { return MarshalEx.ReadDouble (handle, software_latency_offset); }
|
||||
set { MarshalEx.WriteDouble (handle, software_latency_offset, value); }
|
||||
}
|
||||
|
||||
static readonly int software_latency_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("software_latency");
|
||||
|
||||
public float Volume
|
||||
{
|
||||
get { return MarshalEx.ReadFloat(handle, volume_offset); }
|
||||
set { MarshalEx.WriteFloat(handle, volume_offset, value); }
|
||||
}
|
||||
|
||||
static readonly int volume_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("volume");
|
||||
|
||||
// error_callback
|
||||
public Action ErrorCallback
|
||||
{
|
||||
get { return error_callback; }
|
||||
set
|
||||
{
|
||||
error_callback = value;
|
||||
if (value == null)
|
||||
{
|
||||
error_callback_native = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
error_callback_native = stream => error_callback();
|
||||
}
|
||||
|
||||
var ptr = Marshal.GetFunctionPointerForDelegate(error_callback_native);
|
||||
Marshal.WriteIntPtr(handle, error_callback_offset, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int error_callback_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("error_callback");
|
||||
|
||||
Action error_callback;
|
||||
delegate void error_callback_delegate (IntPtr handle);
|
||||
error_callback_delegate error_callback_native;
|
||||
|
||||
// write_callback
|
||||
public Action<int, int> WriteCallback
|
||||
{
|
||||
get { return write_callback; }
|
||||
set
|
||||
{
|
||||
write_callback = value;
|
||||
if (value == null)
|
||||
{
|
||||
write_callback_native = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_callback_native = (h, frame_count_min, frame_count_max) => write_callback(frame_count_min, frame_count_max);
|
||||
}
|
||||
|
||||
var ptr = Marshal.GetFunctionPointerForDelegate (write_callback_native);
|
||||
Marshal.WriteIntPtr (handle, write_callback_offset, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int write_callback_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("write_callback");
|
||||
|
||||
Action<int, int> write_callback;
|
||||
delegate void write_callback_delegate(IntPtr handle, int min, int max);
|
||||
write_callback_delegate write_callback_native;
|
||||
|
||||
// underflow_callback
|
||||
public Action UnderflowCallback
|
||||
{
|
||||
get { return underflow_callback; }
|
||||
set
|
||||
{
|
||||
underflow_callback = value;
|
||||
if (value == null)
|
||||
{
|
||||
underflow_callback_native = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
underflow_callback_native = h => underflow_callback();
|
||||
}
|
||||
|
||||
var ptr = Marshal.GetFunctionPointerForDelegate (underflow_callback_native);
|
||||
Marshal.WriteIntPtr (handle, underflow_callback_offset, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int underflow_callback_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("underflow_callback");
|
||||
|
||||
Action underflow_callback;
|
||||
delegate void underflow_callback_delegate(IntPtr handle);
|
||||
underflow_callback_delegate underflow_callback_native;
|
||||
|
||||
// FIXME: this should be taken care in more centralized/decent manner... we don't want to write
|
||||
// this kind of code anywhere we need string marshaling.
|
||||
List<IntPtr> allocated_hglobals = new List<IntPtr>();
|
||||
|
||||
public string Name {
|
||||
get { return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(handle, name_offset)); }
|
||||
set
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
var existing = Marshal.ReadIntPtr(handle, name_offset);
|
||||
if (allocated_hglobals.Contains(existing))
|
||||
{
|
||||
allocated_hglobals.Remove(existing);
|
||||
Marshal.FreeHGlobal(existing);
|
||||
}
|
||||
|
||||
var ptr = Marshal.StringToHGlobalAnsi(value);
|
||||
Marshal.WriteIntPtr(handle, name_offset, ptr);
|
||||
allocated_hglobals.Add(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int name_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("name");
|
||||
|
||||
public bool NonTerminalHint
|
||||
{
|
||||
get { return Marshal.ReadInt32(handle, non_terminal_hint_offset) != 0; }
|
||||
}
|
||||
|
||||
static readonly int non_terminal_hint_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("non_terminal_hint");
|
||||
|
||||
public int BytesPerFrame
|
||||
{
|
||||
get { return Marshal.ReadInt32(handle, bytes_per_frame_offset); }
|
||||
}
|
||||
|
||||
static readonly int bytes_per_frame_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("bytes_per_frame");
|
||||
|
||||
public int BytesPerSample
|
||||
{
|
||||
get { return Marshal.ReadInt32(handle, bytes_per_sample_offset); }
|
||||
}
|
||||
|
||||
static readonly int bytes_per_sample_offset = (int)Marshal.OffsetOf<SoundIoOutStream>("bytes_per_sample");
|
||||
|
||||
public string LayoutErrorMessage
|
||||
{
|
||||
get
|
||||
{
|
||||
var code = (SoundIoError)Marshal.ReadInt32(handle, layout_error_offset);
|
||||
|
||||
return code == SoundIoError.SoundIoErrorNone ? null : Marshal.PtrToStringAnsi(Natives.soundio_strerror((int)code));
|
||||
}
|
||||
}
|
||||
|
||||
static readonly int layout_error_offset = (int)Marshal.OffsetOf<SoundIoOutStream> ("layout_error");
|
||||
|
||||
// functions
|
||||
|
||||
public void Open ()
|
||||
{
|
||||
var ret = (SoundIoError)Natives.soundio_outstream_open(handle);
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
{
|
||||
throw new SoundIOException(ret);
|
||||
}
|
||||
}
|
||||
|
||||
public void Start ()
|
||||
{
|
||||
var ret = (SoundIoError)Natives.soundio_outstream_start(handle);
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
{
|
||||
throw new SoundIOException(ret);
|
||||
}
|
||||
}
|
||||
|
||||
public SoundIOChannelAreas BeginWrite(ref int frameCount)
|
||||
{
|
||||
IntPtr ptrs = default;
|
||||
int nativeFrameCount = frameCount;
|
||||
|
||||
unsafe
|
||||
{
|
||||
var frameCountPtr = &nativeFrameCount;
|
||||
var ptrptr = &ptrs;
|
||||
var ret = (SoundIoError)Natives.soundio_outstream_begin_write(handle, (IntPtr)ptrptr, (IntPtr)frameCountPtr);
|
||||
|
||||
frameCount = *frameCountPtr;
|
||||
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
{
|
||||
throw new SoundIOException(ret);
|
||||
}
|
||||
|
||||
return new SoundIOChannelAreas(ptrs, Layout.ChannelCount, frameCount);
|
||||
}
|
||||
}
|
||||
|
||||
public void EndWrite ()
|
||||
{
|
||||
var ret = (SoundIoError)Natives.soundio_outstream_end_write(handle);
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
{
|
||||
throw new SoundIOException(ret);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearBuffer ()
|
||||
{
|
||||
_ = Natives.soundio_outstream_clear_buffer(handle);
|
||||
}
|
||||
|
||||
public void Pause (bool pause)
|
||||
{
|
||||
var ret = (SoundIoError)Natives.soundio_outstream_pause(handle, pause);
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
{
|
||||
throw new SoundIOException(ret);
|
||||
}
|
||||
}
|
||||
|
||||
public double GetLatency ()
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
double* dptr = null;
|
||||
IntPtr p = new IntPtr(dptr);
|
||||
|
||||
var ret = (SoundIoError)Natives.soundio_outstream_get_latency(handle, p);
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
{
|
||||
throw new SoundIOException(ret);
|
||||
}
|
||||
|
||||
dptr = (double*)p;
|
||||
|
||||
return *dptr;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVolume (double volume)
|
||||
{
|
||||
var ret = (SoundIoError)Natives.soundio_outstream_set_volume(handle, volume);
|
||||
if (ret != SoundIoError.SoundIoErrorNone)
|
||||
{
|
||||
throw new SoundIOException(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
using System;
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public class SoundIORingBuffer : IDisposable
|
||||
{
|
||||
internal SoundIORingBuffer(IntPtr handle)
|
||||
{
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
IntPtr handle;
|
||||
|
||||
public int Capacity
|
||||
{
|
||||
get { return Natives.soundio_ring_buffer_capacity(handle); }
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Natives.soundio_ring_buffer_clear(handle);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Natives.soundio_ring_buffer_destroy(handle);
|
||||
}
|
||||
|
||||
public int FillCount
|
||||
{
|
||||
get { return Natives.soundio_ring_buffer_fill_count(handle); }
|
||||
}
|
||||
|
||||
public int FreeCount
|
||||
{
|
||||
get { return Natives.soundio_ring_buffer_free_count(handle); }
|
||||
}
|
||||
|
||||
public IntPtr ReadPointer
|
||||
{
|
||||
get { return Natives.soundio_ring_buffer_read_ptr(handle); }
|
||||
}
|
||||
|
||||
public IntPtr WritePointer
|
||||
{
|
||||
get { return Natives.soundio_ring_buffer_write_ptr(handle); }
|
||||
}
|
||||
|
||||
public void AdvanceReadPointer(int count)
|
||||
{
|
||||
Natives.soundio_ring_buffer_advance_read_ptr(handle, count);
|
||||
}
|
||||
|
||||
public void AdvanceWritePointer(int count)
|
||||
{
|
||||
Natives.soundio_ring_buffer_advance_write_ptr(handle, count);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public struct SoundIOSampleRateRange
|
||||
{
|
||||
internal SoundIOSampleRateRange(int min, int max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
|
||||
public readonly int Min;
|
||||
public readonly int Max;
|
||||
}
|
||||
}
|
@ -1,643 +0,0 @@
|
||||
// This source file is generated by nclang PInvokeGenerator.
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using delegate0 = SoundIOSharp.Delegates.delegate0;
|
||||
using delegate1 = SoundIOSharp.Delegates.delegate1;
|
||||
using delegate2 = SoundIOSharp.Delegates.delegate2;
|
||||
using delegate3 = SoundIOSharp.Delegates.delegate3;
|
||||
using delegate4 = SoundIOSharp.Delegates.delegate4;
|
||||
using delegate5 = SoundIOSharp.Delegates.delegate5;
|
||||
using delegate6 = SoundIOSharp.Delegates.delegate6;
|
||||
using delegate7 = SoundIOSharp.Delegates.delegate7;
|
||||
using delegate8 = SoundIOSharp.Delegates.delegate8;
|
||||
using delegate9 = SoundIOSharp.Delegates.delegate9;
|
||||
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
enum SoundIoError // soundio.h (72, 6)
|
||||
{
|
||||
SoundIoErrorNone = 0,
|
||||
SoundIoErrorNoMem = 1,
|
||||
SoundIoErrorInitAudioBackend = 2,
|
||||
SoundIoErrorSystemResources = 3,
|
||||
SoundIoErrorOpeningDevice = 4,
|
||||
SoundIoErrorNoSuchDevice = 5,
|
||||
SoundIoErrorInvalid = 6,
|
||||
SoundIoErrorBackendUnavailable = 7,
|
||||
SoundIoErrorStreaming = 8,
|
||||
SoundIoErrorIncompatibleDevice = 9,
|
||||
SoundIoErrorNoSuchClient = 10,
|
||||
SoundIoErrorIncompatibleBackend = 11,
|
||||
SoundIoErrorBackendDisconnected = 12,
|
||||
SoundIoErrorInterrupted = 13,
|
||||
SoundIoErrorUnderflow = 14,
|
||||
SoundIoErrorEncodingString = 15,
|
||||
}
|
||||
|
||||
enum SoundIoChannelId // soundio.h (106, 6)
|
||||
{
|
||||
SoundIoChannelIdInvalid = 0,
|
||||
SoundIoChannelIdFrontLeft = 1,
|
||||
SoundIoChannelIdFrontRight = 2,
|
||||
SoundIoChannelIdFrontCenter = 3,
|
||||
SoundIoChannelIdLfe = 4,
|
||||
SoundIoChannelIdBackLeft = 5,
|
||||
SoundIoChannelIdBackRight = 6,
|
||||
SoundIoChannelIdFrontLeftCenter = 7,
|
||||
SoundIoChannelIdFrontRightCenter = 8,
|
||||
SoundIoChannelIdBackCenter = 9,
|
||||
SoundIoChannelIdSideLeft = 10,
|
||||
SoundIoChannelIdSideRight = 11,
|
||||
SoundIoChannelIdTopCenter = 12,
|
||||
SoundIoChannelIdTopFrontLeft = 13,
|
||||
SoundIoChannelIdTopFrontCenter = 14,
|
||||
SoundIoChannelIdTopFrontRight = 15,
|
||||
SoundIoChannelIdTopBackLeft = 16,
|
||||
SoundIoChannelIdTopBackCenter = 17,
|
||||
SoundIoChannelIdTopBackRight = 18,
|
||||
SoundIoChannelIdBackLeftCenter = 19,
|
||||
SoundIoChannelIdBackRightCenter = 20,
|
||||
SoundIoChannelIdFrontLeftWide = 21,
|
||||
SoundIoChannelIdFrontRightWide = 22,
|
||||
SoundIoChannelIdFrontLeftHigh = 23,
|
||||
SoundIoChannelIdFrontCenterHigh = 24,
|
||||
SoundIoChannelIdFrontRightHigh = 25,
|
||||
SoundIoChannelIdTopFrontLeftCenter = 26,
|
||||
SoundIoChannelIdTopFrontRightCenter = 27,
|
||||
SoundIoChannelIdTopSideLeft = 28,
|
||||
SoundIoChannelIdTopSideRight = 29,
|
||||
SoundIoChannelIdLeftLfe = 30,
|
||||
SoundIoChannelIdRightLfe = 31,
|
||||
SoundIoChannelIdLfe2 = 32,
|
||||
SoundIoChannelIdBottomCenter = 33,
|
||||
SoundIoChannelIdBottomLeftCenter = 34,
|
||||
SoundIoChannelIdBottomRightCenter = 35,
|
||||
SoundIoChannelIdMsMid = 36,
|
||||
SoundIoChannelIdMsSide = 37,
|
||||
SoundIoChannelIdAmbisonicW = 38,
|
||||
SoundIoChannelIdAmbisonicX = 39,
|
||||
SoundIoChannelIdAmbisonicY = 40,
|
||||
SoundIoChannelIdAmbisonicZ = 41,
|
||||
SoundIoChannelIdXyX = 42,
|
||||
SoundIoChannelIdXyY = 43,
|
||||
SoundIoChannelIdHeadphonesLeft = 44,
|
||||
SoundIoChannelIdHeadphonesRight = 45,
|
||||
SoundIoChannelIdClickTrack = 46,
|
||||
SoundIoChannelIdForeignLanguage = 47,
|
||||
SoundIoChannelIdHearingImpaired = 48,
|
||||
SoundIoChannelIdNarration = 49,
|
||||
SoundIoChannelIdHaptic = 50,
|
||||
SoundIoChannelIdDialogCentricMix = 51,
|
||||
SoundIoChannelIdAux = 52,
|
||||
SoundIoChannelIdAux0 = 53,
|
||||
SoundIoChannelIdAux1 = 54,
|
||||
SoundIoChannelIdAux2 = 55,
|
||||
SoundIoChannelIdAux3 = 56,
|
||||
SoundIoChannelIdAux4 = 57,
|
||||
SoundIoChannelIdAux5 = 58,
|
||||
SoundIoChannelIdAux6 = 59,
|
||||
SoundIoChannelIdAux7 = 60,
|
||||
SoundIoChannelIdAux8 = 61,
|
||||
SoundIoChannelIdAux9 = 62,
|
||||
SoundIoChannelIdAux10 = 63,
|
||||
SoundIoChannelIdAux11 = 64,
|
||||
SoundIoChannelIdAux12 = 65,
|
||||
SoundIoChannelIdAux13 = 66,
|
||||
SoundIoChannelIdAux14 = 67,
|
||||
SoundIoChannelIdAux15 = 68,
|
||||
}
|
||||
|
||||
enum SoundIoChannelLayoutId // soundio.h (189, 6)
|
||||
{
|
||||
SoundIoChannelLayoutIdMono = 0,
|
||||
SoundIoChannelLayoutIdStereo = 1,
|
||||
SoundIoChannelLayoutId2Point1 = 2,
|
||||
SoundIoChannelLayoutId3Point0 = 3,
|
||||
SoundIoChannelLayoutId3Point0Back = 4,
|
||||
SoundIoChannelLayoutId3Point1 = 5,
|
||||
SoundIoChannelLayoutId4Point0 = 6,
|
||||
SoundIoChannelLayoutIdQuad = 7,
|
||||
SoundIoChannelLayoutIdQuadSide = 8,
|
||||
SoundIoChannelLayoutId4Point1 = 9,
|
||||
SoundIoChannelLayoutId5Point0Back = 10,
|
||||
SoundIoChannelLayoutId5Point0Side = 11,
|
||||
SoundIoChannelLayoutId5Point1 = 12,
|
||||
SoundIoChannelLayoutId5Point1Back = 13,
|
||||
SoundIoChannelLayoutId6Point0Side = 14,
|
||||
SoundIoChannelLayoutId6Point0Front = 15,
|
||||
SoundIoChannelLayoutIdHexagonal = 16,
|
||||
SoundIoChannelLayoutId6Point1 = 17,
|
||||
SoundIoChannelLayoutId6Point1Back = 18,
|
||||
SoundIoChannelLayoutId6Point1Front = 19,
|
||||
SoundIoChannelLayoutId7Point0 = 20,
|
||||
SoundIoChannelLayoutId7Point0Front = 21,
|
||||
SoundIoChannelLayoutId7Point1 = 22,
|
||||
SoundIoChannelLayoutId7Point1Wide = 23,
|
||||
SoundIoChannelLayoutId7Point1WideBack = 24,
|
||||
SoundIoChannelLayoutIdOctagonal = 25,
|
||||
}
|
||||
|
||||
enum SoundIoBackend // soundio.h (218, 6)
|
||||
{
|
||||
SoundIoBackendNone = 0,
|
||||
SoundIoBackendJack = 1,
|
||||
SoundIoBackendPulseAudio = 2,
|
||||
SoundIoBackendAlsa = 3,
|
||||
SoundIoBackendCoreAudio = 4,
|
||||
SoundIoBackendWasapi = 5,
|
||||
SoundIoBackendDummy = 6,
|
||||
}
|
||||
|
||||
enum SoundIoDeviceAim // soundio.h (228, 6)
|
||||
{
|
||||
SoundIoDeviceAimInput = 0,
|
||||
SoundIoDeviceAimOutput = 1,
|
||||
}
|
||||
|
||||
enum SoundIoFormat // soundio.h (235, 6)
|
||||
{
|
||||
SoundIoFormatInvalid = 0,
|
||||
SoundIoFormatS8 = 1,
|
||||
SoundIoFormatU8 = 2,
|
||||
SoundIoFormatS16LE = 3,
|
||||
SoundIoFormatS16BE = 4,
|
||||
SoundIoFormatU16LE = 5,
|
||||
SoundIoFormatU16BE = 6,
|
||||
SoundIoFormatS24LE = 7,
|
||||
SoundIoFormatS24BE = 8,
|
||||
SoundIoFormatU24LE = 9,
|
||||
SoundIoFormatU24BE = 10,
|
||||
SoundIoFormatS32LE = 11,
|
||||
SoundIoFormatS32BE = 12,
|
||||
SoundIoFormatU32LE = 13,
|
||||
SoundIoFormatU32BE = 14,
|
||||
SoundIoFormatFloat32LE = 15,
|
||||
SoundIoFormatFloat32BE = 16,
|
||||
SoundIoFormatFloat64LE = 17,
|
||||
SoundIoFormatFloat64BE = 18,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIoChannelLayout // soundio.h (306, 8)
|
||||
{
|
||||
[CTypeDetails("Pointer<byte>")] public System.IntPtr @name;
|
||||
public int @channel_count;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
|
||||
[CTypeDetails("ConstArrayOf<SoundIoChannelId>")] public SoundIoChannelId[] @channels;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIoSampleRateRange // soundio.h (313, 8)
|
||||
{
|
||||
public int @min;
|
||||
public int @max;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIoChannelArea // soundio.h (319, 8)
|
||||
{
|
||||
[CTypeDetails("Pointer<byte>")] public System.IntPtr @ptr;
|
||||
public int @step;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIo // soundio.h (328, 8)
|
||||
{
|
||||
[CTypeDetails("Pointer<void>")] public System.IntPtr @userdata;
|
||||
[CTypeDetails("Pointer<void (SoundIo *)>")] public delegate0 @on_devices_change;
|
||||
[CTypeDetails("Pointer<void (SoundIo *, int)>")] public delegate1 @on_backend_disconnect;
|
||||
[CTypeDetails("Pointer<void (SoundIo *)>")] public Delegates.delegate0 @on_events_signal;
|
||||
public SoundIoBackend @current_backend;
|
||||
[CTypeDetails("Pointer<byte>")] public System.IntPtr @app_name;
|
||||
[CTypeDetails("Pointer<void ()>")] public delegate2 @emit_rtprio_warning;
|
||||
[CTypeDetails("Pointer<void (const char *)>")] public delegate3 @jack_info_callback;
|
||||
[CTypeDetails("Pointer<void (const char *)>")] public Delegates.delegate3 @jack_error_callback;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIoDevice // soundio.h (387, 8)
|
||||
{
|
||||
[CTypeDetails("Pointer<SoundIo>")] public System.IntPtr @soundio;
|
||||
[CTypeDetails("Pointer<byte>")] public System.IntPtr @id;
|
||||
[CTypeDetails("Pointer<byte>")] public System.IntPtr @name;
|
||||
public SoundIoDeviceAim @aim;
|
||||
[CTypeDetails("Pointer<SoundIoChannelLayout>")] public System.IntPtr @layouts;
|
||||
public int @layout_count;
|
||||
public SoundIoChannelLayout @current_layout;
|
||||
[CTypeDetails("Pointer<SoundIoFormat>")] public System.IntPtr @formats;
|
||||
public int @format_count;
|
||||
public SoundIoFormat @current_format;
|
||||
[CTypeDetails("Pointer<SoundIoSampleRateRange>")] public System.IntPtr @sample_rates;
|
||||
public int @sample_rate_count;
|
||||
public int @sample_rate_current;
|
||||
public double @software_latency_min;
|
||||
public double @software_latency_max;
|
||||
public double @software_latency_current;
|
||||
public bool @is_raw;
|
||||
public int @ref_count;
|
||||
public int @probe_error;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIoOutStream // soundio.h (497, 8)
|
||||
{
|
||||
[CTypeDetails("Pointer<SoundIoDevice>")] public System.IntPtr @device;
|
||||
public SoundIoFormat @format;
|
||||
public int @sample_rate;
|
||||
public SoundIoChannelLayout @layout;
|
||||
public double @software_latency;
|
||||
public float @volume;
|
||||
[CTypeDetails("Pointer<void>")] public System.IntPtr @userdata;
|
||||
[CTypeDetails("Pointer<void (SoundIoOutStream *, int, int)>")] public delegate4 @write_callback;
|
||||
[CTypeDetails("Pointer<void (SoundIoOutStream *)>")] public delegate5 @underflow_callback;
|
||||
[CTypeDetails("Pointer<void (SoundIoOutStream *, int)>")] public delegate6 @error_callback;
|
||||
[CTypeDetails("Pointer<byte>")] public System.IntPtr @name;
|
||||
public bool @non_terminal_hint;
|
||||
public int @bytes_per_frame;
|
||||
public int @bytes_per_sample;
|
||||
public int @layout_error;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIoInStream // soundio.h (600, 8)
|
||||
{
|
||||
[CTypeDetails("Pointer<SoundIoDevice>")] public System.IntPtr @device;
|
||||
public SoundIoFormat @format;
|
||||
public int @sample_rate;
|
||||
public SoundIoChannelLayout @layout;
|
||||
public double @software_latency;
|
||||
[CTypeDetails("Pointer<void>")] public System.IntPtr @userdata;
|
||||
[CTypeDetails("Pointer<void (SoundIoInStream *, int, int)>")] public delegate7 @read_callback;
|
||||
[CTypeDetails("Pointer<void (SoundIoInStream *)>")] public delegate8 @overflow_callback;
|
||||
[CTypeDetails("Pointer<void (SoundIoInStream *, int)>")] public delegate9 @error_callback;
|
||||
[CTypeDetails("Pointer<byte>")] public System.IntPtr @name;
|
||||
public bool @non_terminal_hint;
|
||||
public int @bytes_per_frame;
|
||||
public int @bytes_per_sample;
|
||||
public int @layout_error;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct SoundIoRingBuffer // soundio.h (1170, 8)
|
||||
{
|
||||
}
|
||||
|
||||
partial class Natives
|
||||
{
|
||||
const string LibraryName = "libsoundio";
|
||||
// function soundio_version_string - soundio.h (682, 28)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_version_string();
|
||||
|
||||
// function soundio_version_major - soundio.h (684, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_version_major();
|
||||
|
||||
// function soundio_version_minor - soundio.h (686, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_version_minor();
|
||||
|
||||
// function soundio_version_patch - soundio.h (688, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_version_patch();
|
||||
|
||||
// function soundio_create - soundio.h (694, 32)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_create();
|
||||
|
||||
// function soundio_destroy - soundio.h (695, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_destroy([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_connect - soundio.h (705, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_connect([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_connect_backend - soundio.h (717, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_connect_backend([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, SoundIoBackend @backend);
|
||||
|
||||
// function soundio_disconnect - soundio.h (718, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_disconnect([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_strerror - soundio.h (721, 28)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_strerror(int @error);
|
||||
|
||||
// function soundio_backend_name - soundio.h (723, 28)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_backend_name(SoundIoBackend @backend);
|
||||
|
||||
// function soundio_backend_count - soundio.h (726, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_backend_count([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_get_backend - soundio.h (729, 36)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern SoundIoBackend soundio_get_backend([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @index);
|
||||
|
||||
// function soundio_have_backend - soundio.h (732, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern bool soundio_have_backend(SoundIoBackend @backend);
|
||||
|
||||
// function soundio_flush_events - soundio.h (756, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_flush_events([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_wait_events - soundio.h (760, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_wait_events([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_wakeup - soundio.h (763, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_wakeup([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_force_device_scan - soundio.h (780, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_force_device_scan([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_channel_layout_equal - soundio.h (787, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern bool soundio_channel_layout_equal([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @a, [CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @b);
|
||||
|
||||
// function soundio_get_channel_name - soundio.h (791, 28)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_get_channel_name(SoundIoChannelId @id);
|
||||
|
||||
// function soundio_parse_channel_id - soundio.h (795, 38)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern SoundIoChannelId soundio_parse_channel_id([CTypeDetails("Pointer<byte>")]System.IntPtr @str, int @str_len);
|
||||
|
||||
// function soundio_channel_layout_builtin_count - soundio.h (798, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_channel_layout_builtin_count();
|
||||
|
||||
// function soundio_channel_layout_get_builtin - soundio.h (803, 51)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_channel_layout_get_builtin(int @index);
|
||||
|
||||
// function soundio_channel_layout_get_default - soundio.h (806, 51)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_channel_layout_get_default(int @channel_count);
|
||||
|
||||
// function soundio_channel_layout_find_channel - soundio.h (809, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_channel_layout_find_channel([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layout, SoundIoChannelId @channel);
|
||||
|
||||
// function soundio_channel_layout_detect_builtin - soundio.h (814, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern bool soundio_channel_layout_detect_builtin([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layout);
|
||||
|
||||
// function soundio_best_matching_channel_layout - soundio.h (819, 51)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_best_matching_channel_layout([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @preferred_layouts, int @preferred_layout_count, [CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @available_layouts, int @available_layout_count);
|
||||
|
||||
// function soundio_sort_channel_layouts - soundio.h (824, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_sort_channel_layouts([CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layouts, int @layout_count);
|
||||
|
||||
// function soundio_get_bytes_per_sample - soundio.h (830, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_get_bytes_per_sample(SoundIoFormat @format);
|
||||
|
||||
// function soundio_get_bytes_per_frame - soundio.h (833, 19)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_get_bytes_per_frame(SoundIoFormat @format, int @channel_count);
|
||||
|
||||
// function soundio_get_bytes_per_second - soundio.h (838, 19)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_get_bytes_per_second(SoundIoFormat @format, int @channel_count, int @sample_rate);
|
||||
|
||||
// function soundio_format_string - soundio.h (845, 29)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_format_string(SoundIoFormat @format);
|
||||
|
||||
// function soundio_input_device_count - soundio.h (861, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_input_device_count([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_output_device_count - soundio.h (864, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_output_device_count([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_get_input_device - soundio.h (870, 38)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_get_input_device([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @index);
|
||||
|
||||
// function soundio_get_output_device - soundio.h (875, 38)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_get_output_device([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @index);
|
||||
|
||||
// function soundio_default_input_device_index - soundio.h (880, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_default_input_device_index([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_default_output_device_index - soundio.h (885, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_default_output_device_index([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio);
|
||||
|
||||
// function soundio_device_ref - soundio.h (888, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_device_ref([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
|
||||
|
||||
// function soundio_device_unref - soundio.h (891, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_device_unref([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
|
||||
|
||||
// function soundio_device_equal - soundio.h (895, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern bool soundio_device_equal([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @a, [CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @b);
|
||||
|
||||
// function soundio_device_sort_channel_layouts - soundio.h (900, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_device_sort_channel_layouts([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
|
||||
|
||||
// function soundio_device_supports_format - soundio.h (904, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern bool soundio_device_supports_format([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, SoundIoFormat @format);
|
||||
|
||||
// function soundio_device_supports_layout - soundio.h (909, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern bool soundio_device_supports_layout([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, [CTypeDetails("Pointer<SoundIoChannelLayout>")]System.IntPtr @layout);
|
||||
|
||||
// function soundio_device_supports_sample_rate - soundio.h (914, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern bool soundio_device_supports_sample_rate([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, int @sample_rate);
|
||||
|
||||
// function soundio_device_nearest_sample_rate - soundio.h (919, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_device_nearest_sample_rate([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device, int @sample_rate);
|
||||
|
||||
// function soundio_outstream_create - soundio.h (929, 41)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_outstream_create([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
|
||||
|
||||
// function soundio_outstream_destroy - soundio.h (931, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_outstream_destroy([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
|
||||
|
||||
// function soundio_outstream_open - soundio.h (954, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_open([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
|
||||
|
||||
// function soundio_outstream_start - soundio.h (965, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_start([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
|
||||
|
||||
// function soundio_outstream_begin_write - soundio.h (997, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_begin_write([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, [CTypeDetails("Pointer<System.IntPtr>")]System.IntPtr @areas, [CTypeDetails("Pointer<int>")]System.IntPtr @frame_count);
|
||||
|
||||
// function soundio_outstream_end_write - soundio.h (1009, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_end_write([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
|
||||
|
||||
// function soundio_outstream_clear_buffer - soundio.h (1024, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_clear_buffer([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream);
|
||||
|
||||
// function soundio_outstream_pause - soundio.h (1045, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_pause([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, bool @pause);
|
||||
|
||||
// function soundio_outstream_get_latency - soundio.h (1058, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_get_latency([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, [CTypeDetails("Pointer<double>")]System.IntPtr @out_latency);
|
||||
|
||||
// function soundio_outstream_set_volume - soundio.h (1061, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_outstream_set_volume([CTypeDetails("Pointer<SoundIoOutStream>")]System.IntPtr @outstream, double @volume);
|
||||
|
||||
// function soundio_instream_create - soundio.h (1071, 40)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_instream_create([CTypeDetails("Pointer<SoundIoDevice>")]System.IntPtr @device);
|
||||
|
||||
// function soundio_instream_destroy - soundio.h (1073, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_instream_destroy([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
|
||||
|
||||
// function soundio_instream_open - soundio.h (1093, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_instream_open([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
|
||||
|
||||
// function soundio_instream_start - soundio.h (1102, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_instream_start([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
|
||||
|
||||
// function soundio_instream_begin_read - soundio.h (1133, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_instream_begin_read([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream, [CTypeDetails("Pointer<System.IntPtr>")]System.IntPtr @areas, [CTypeDetails("Pointer<int>")]System.IntPtr @frame_count);
|
||||
|
||||
// function soundio_instream_end_read - soundio.h (1143, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_instream_end_read([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream);
|
||||
|
||||
// function soundio_instream_pause - soundio.h (1156, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_instream_pause([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream, bool @pause);
|
||||
|
||||
// function soundio_instream_get_latency - soundio.h (1166, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_instream_get_latency([CTypeDetails("Pointer<SoundIoInStream>")]System.IntPtr @instream, [CTypeDetails("Pointer<double>")]System.IntPtr @out_latency);
|
||||
|
||||
// function soundio_ring_buffer_create - soundio.h (1181, 42)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_ring_buffer_create([CTypeDetails("Pointer<SoundIo>")]System.IntPtr @soundio, int @requested_capacity);
|
||||
|
||||
// function soundio_ring_buffer_destroy - soundio.h (1182, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_ring_buffer_destroy([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
||||
|
||||
// function soundio_ring_buffer_capacity - soundio.h (1186, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_ring_buffer_capacity([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
||||
|
||||
// function soundio_ring_buffer_write_ptr - soundio.h (1189, 22)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_ring_buffer_write_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
||||
|
||||
// function soundio_ring_buffer_advance_write_ptr - soundio.h (1191, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_ring_buffer_advance_write_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer, int @count);
|
||||
|
||||
// function soundio_ring_buffer_read_ptr - soundio.h (1194, 22)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern System.IntPtr soundio_ring_buffer_read_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
||||
|
||||
// function soundio_ring_buffer_advance_read_ptr - soundio.h (1196, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_ring_buffer_advance_read_ptr([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer, int @count);
|
||||
|
||||
// function soundio_ring_buffer_fill_count - soundio.h (1199, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_ring_buffer_fill_count([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
||||
|
||||
// function soundio_ring_buffer_free_count - soundio.h (1202, 20)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern int soundio_ring_buffer_free_count([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
||||
|
||||
// function soundio_ring_buffer_clear - soundio.h (1205, 21)
|
||||
[DllImport(LibraryName)]
|
||||
internal static extern void soundio_ring_buffer_clear([CTypeDetails("Pointer<SoundIoRingBuffer>")]System.IntPtr @ring_buffer);
|
||||
|
||||
}
|
||||
|
||||
class Delegates
|
||||
{
|
||||
public delegate void delegate0(System.IntPtr p0);
|
||||
public delegate void delegate1(System.IntPtr p0, int p1);
|
||||
public delegate void delegate2();
|
||||
public delegate void delegate3(System.IntPtr p0);
|
||||
public delegate void delegate4(System.IntPtr p0, int p1, int p2);
|
||||
public delegate void delegate5(System.IntPtr p0);
|
||||
public delegate void delegate6(System.IntPtr p0, int p1);
|
||||
public delegate void delegate7(System.IntPtr p0, int p1, int p2);
|
||||
public delegate void delegate8(System.IntPtr p0);
|
||||
public delegate void delegate9(System.IntPtr p0, int p1);
|
||||
}
|
||||
|
||||
public struct Pointer<T>
|
||||
{
|
||||
public IntPtr Handle;
|
||||
public static implicit operator IntPtr(Pointer<T> value) { return value.Handle; }
|
||||
public static implicit operator Pointer<T>(IntPtr value) { return new Pointer<T>(value); }
|
||||
|
||||
public Pointer(IntPtr handle)
|
||||
{
|
||||
Handle = handle;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Pointer<T> && this == (Pointer<T>)obj;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (int)Handle;
|
||||
}
|
||||
|
||||
public static bool operator ==(Pointer<T> p1, Pointer<T> p2)
|
||||
{
|
||||
return p1.Handle == p2.Handle;
|
||||
}
|
||||
|
||||
public static bool operator !=(Pointer<T> p1, Pointer<T> p2)
|
||||
{
|
||||
return p1.Handle != p2.Handle;
|
||||
}
|
||||
}
|
||||
public struct ArrayOf<T> { }
|
||||
public struct ConstArrayOf<T> { }
|
||||
public class CTypeDetailsAttribute : Attribute
|
||||
{
|
||||
public CTypeDetailsAttribute(string value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
using Ryujinx.Audio.Backends.Common;
|
||||
using Ryujinx.Audio.Common;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Audio.Backends.CompatLayer
|
||||
{
|
||||
class CompatLayerHardwareDeviceSession : HardwareDeviceSessionOutputBase
|
||||
{
|
||||
private HardwareDeviceSessionOutputBase _realSession;
|
||||
private uint _userChannelCount;
|
||||
|
||||
public CompatLayerHardwareDeviceSession(HardwareDeviceSessionOutputBase realSession, uint userChannelCount) : base(realSession.MemoryManager, realSession.RequestedSampleFormat, realSession.RequestedSampleRate, userChannelCount)
|
||||
{
|
||||
_realSession = realSession;
|
||||
_userChannelCount = userChannelCount;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_realSession.Dispose();
|
||||
}
|
||||
|
||||
public override ulong GetPlayedSampleCount()
|
||||
{
|
||||
return _realSession.GetPlayedSampleCount();
|
||||
}
|
||||
|
||||
public override float GetVolume()
|
||||
{
|
||||
return _realSession.GetVolume();
|
||||
}
|
||||
|
||||
public override void PrepareToClose()
|
||||
{
|
||||
_realSession.PrepareToClose();
|
||||
}
|
||||
|
||||
public override void QueueBuffer(AudioBuffer buffer)
|
||||
{
|
||||
_realSession.QueueBuffer(buffer);
|
||||
}
|
||||
|
||||
public override bool RegisterBuffer(AudioBuffer buffer, byte[] samples)
|
||||
{
|
||||
if (RequestedSampleFormat != SampleFormat.PcmInt16)
|
||||
{
|
||||
throw new NotImplementedException("Downmixing formats other than PCM16 is not supported.");
|
||||
}
|
||||
|
||||
if (samples == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
short[] downmixedBufferPCM16;
|
||||
|
||||
ReadOnlySpan<short> samplesPCM16 = MemoryMarshal.Cast<byte, short>(samples);
|
||||
|
||||
if (_userChannelCount == 6)
|
||||
{
|
||||
downmixedBufferPCM16 = Downmixing.DownMixSurroundToStereo(samplesPCM16);
|
||||
|
||||
if (_realSession.RequestedChannelCount == 1)
|
||||
{
|
||||
downmixedBufferPCM16 = Downmixing.DownMixStereoToMono(downmixedBufferPCM16);
|
||||
}
|
||||
}
|
||||
else if (_userChannelCount == 2 && _realSession.RequestedChannelCount == 1)
|
||||
{
|
||||
downmixedBufferPCM16 = Downmixing.DownMixStereoToMono(samplesPCM16);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException($"Downmixing from {_userChannelCount} to {_realSession.RequestedChannelCount} not implemented.");
|
||||
}
|
||||
|
||||
byte[] downmixedBuffer = MemoryMarshal.Cast<short, byte>(downmixedBufferPCM16).ToArray();
|
||||
|
||||
AudioBuffer fakeBuffer = new AudioBuffer
|
||||
{
|
||||
BufferTag = buffer.BufferTag,
|
||||
DataPointer = buffer.DataPointer,
|
||||
DataSize = (ulong)downmixedBuffer.Length
|
||||
};
|
||||
|
||||
bool result = _realSession.RegisterBuffer(fakeBuffer, downmixedBuffer);
|
||||
|
||||
if (result)
|
||||
{
|
||||
buffer.Data = fakeBuffer.Data;
|
||||
buffer.DataSize = fakeBuffer.DataSize;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void SetVolume(float volume)
|
||||
{
|
||||
_realSession.SetVolume(volume);
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
_realSession.Start();
|
||||
}
|
||||
|
||||
public override void Stop()
|
||||
{
|
||||
_realSession.Stop();
|
||||
}
|
||||
|
||||
public override void UnregisterBuffer(AudioBuffer buffer)
|
||||
{
|
||||
_realSession.UnregisterBuffer(buffer);
|
||||
}
|
||||
|
||||
public override bool WasBufferFullyConsumed(AudioBuffer buffer)
|
||||
{
|
||||
return _realSession.WasBufferFullyConsumed(buffer);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,272 +0,0 @@
|
||||
{
|
||||
"MenuBarFile": "_Fichier",
|
||||
"MenuBarFileOpenFromFile": "_Charger un jeu depuis un fichier",
|
||||
"MenuBarFileOpenUnpacked": "Charger un jeu _extrait",
|
||||
"MenuBarFileOpenEmuFolder": "Ouvrir le dossier Ryujinx",
|
||||
"MenuBarFileOpenLogsFolder": "Ouvrir le dossier de Logs",
|
||||
"MenuBarFileExit": "_Quitter",
|
||||
"MenuBarOptions": "Options",
|
||||
"MenuBarOptionsToggleFullscreen": "Basculer en plein écran",
|
||||
"MenuBarOptionsStartGamesInFullscreen": "Démarrer le jeu en plein écran",
|
||||
"MenuBarOptionsStopEmulation": "Arrêter l'émulation",
|
||||
"MenuBarOptionsSettings": "_Paramètres",
|
||||
"MenuBarOptionsManageUserProfiles": "_Gêrer les profils d'utilisateurs",
|
||||
"MenuBarActions": "_Actions",
|
||||
"MenuBarOptionsSimulateWakeUpMessage": "Simuler une sortie de veille",
|
||||
"MenuBarActionsScanAmiibo": "Scanner un Amiibo",
|
||||
"MenuBarTools": "_Outils",
|
||||
"MenuBarToolsInstallFirmware": "Installer un firmware",
|
||||
"MenuBarFileToolsInstallFirmwareFromFile": "Installer un firmware depuis un fichier XCI ou ZIP",
|
||||
"MenuBarFileToolsInstallFirmwareFromDirectory": "Installer un firmware depuis un dossier",
|
||||
"MenuBarHelp": "Aide",
|
||||
"MenuBarHelpCheckForUpdates": "Vérifier les mises à jour",
|
||||
"MenuBarHelpAbout": "Á propos",
|
||||
"MenuSearch": "Rechercher...",
|
||||
"GameListHeaderFavorite": "Favoris",
|
||||
"GameListHeaderIcon": "Icône",
|
||||
"GameListHeaderApplication": "Application",
|
||||
"GameListHeaderDeveloper": "Développeur",
|
||||
"GameListHeaderVersion": "Version",
|
||||
"GameListHeaderTimePlayed": "Temps de jeu",
|
||||
"GameListHeaderLastPlayed": "Dernière partie",
|
||||
"GameListHeaderFileExtension": "Extension du Fichier",
|
||||
"GameListHeaderFileSize": "Taille du Fichier",
|
||||
"GameListHeaderPath": "Chemin",
|
||||
"GameListContextMenuOpenUserSaveDirectory": "Ouvrir le dossier de sauvegarde utilisateur",
|
||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde utilisateur du jeu",
|
||||
"GameListContextMenuOpenUserDeviceDirectory": "Ouvrir le dossier de sauvegarde console",
|
||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde console du jeu",
|
||||
"GameListContextMenuOpenUserBcatDirectory": "Ouvrir le dossier de sauvegarde BCAT",
|
||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Ouvre le dossier contenant la sauvegarde BCAT du jeu",
|
||||
"GameListContextMenuManageTitleUpdates": "Gérer les mises à jour",
|
||||
"GameListContextMenuManageTitleUpdatesToolTip": "Ouvre la fenêtre de gestion des mises à jour",
|
||||
"GameListContextMenuManageDlc": "Gérer les DLC",
|
||||
"GameListContextMenuManageDlcToolTip": "Ouvre la fenêtre de gestion des DLC",
|
||||
"GameListContextMenuOpenModsDirectory": "Ouvrir le dossier des Mods",
|
||||
"GameListContextMenuOpenModsDirectoryToolTip": "Ouvre le dossier contenant les mods du jeu",
|
||||
"GameListContextMenuCacheManagement": "Gestion des caches",
|
||||
"GameListContextMenuCacheManagementPurgePptc": "Purger le PPTC",
|
||||
"GameListContextMenuCacheManagementPurgePptcToolTip": "Supprime le PPTC du jeu",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCache": "Purger le cache des Shaders",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Supprime le cache des shaders du jeu",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectory": "Ouvrir le dossier du PPTC",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Ouvre le dossier contenant le PPTC du jeu",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Ouvrir le dossier du cache des shaders",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Ouvre le dossier contenant le cache des shaders du jeu",
|
||||
"GameListContextMenuExtractData": "Extraire les données",
|
||||
"GameListContextMenuExtractDataExeFS": "ExeFS",
|
||||
"GameListContextMenuExtractDataExeFSToolTip": "Extrait la section ExeFS du jeu (mise à jour incluse)",
|
||||
"GameListContextMenuExtractDataRomFS": "RomFS",
|
||||
"GameListContextMenuExtractDataRomFSToolTip": "Extrait la section RomFS du jeu (mise à jour incluse)",
|
||||
"GameListContextMenuExtractDataLogo": "Logo",
|
||||
"GameListContextMenuExtractDataLogoToolTip": "Extrait la section Logo du jeu (mise à jour incluse)",
|
||||
"StatusBarGamesLoaded": "{0}/{1} Jeux chargés",
|
||||
"StatusBarSystemVersion": "Version du Firmware: {0}",
|
||||
"Settings": "Paramètres",
|
||||
"SettingsTabGeneral": "Général",
|
||||
"SettingsTabGeneralGeneral": "Général",
|
||||
"SettingsTabGeneralEnableDiscordRichPresence": "Active Discord Rich Presence",
|
||||
"SettingsTabGeneralCheckUpdatesOnLaunch": "Vérifier les mises à jour au démarrage",
|
||||
"SettingsTabGeneralShowConfirmExitDialog": "Afficher le message de \"Confirmation de fermeture\"",
|
||||
"SettingsTabGeneralHideCursorOnIdle": "Masquer le curseur si inactif",
|
||||
"SettingsTabGeneralGameDirectories": "Dossiers de Jeux",
|
||||
"SettingsTabGeneralAdd": "Ajouter",
|
||||
"SettingsTabGeneralRemove": "Supprimer",
|
||||
"SettingsTabSystem": "Système",
|
||||
"SettingsTabSystemCore": "Core",
|
||||
"SettingsTabSystemSystemRegion": "Région du système:",
|
||||
"SettingsTabSystemSystemRegionJapan": "Japon",
|
||||
"SettingsTabSystemSystemRegionUSA": "USA",
|
||||
"SettingsTabSystemSystemRegionEurope": "Europe",
|
||||
"SettingsTabSystemSystemRegionAustralia": "Australie",
|
||||
"SettingsTabSystemSystemRegionChina": "Chine",
|
||||
"SettingsTabSystemSystemRegionKorea": "Corée",
|
||||
"SettingsTabSystemSystemRegionTaiwan": "Taïwan",
|
||||
"SettingsTabSystemSystemLanguage": "Langue du système:",
|
||||
"SettingsTabSystemSystemLanguageJapanese": "Japonais",
|
||||
"SettingsTabSystemSystemLanguageAmericanEnglish": "Américain",
|
||||
"SettingsTabSystemSystemLanguageFrench": "Français",
|
||||
"SettingsTabSystemSystemLanguageGerman": "Allemand",
|
||||
"SettingsTabSystemSystemLanguageItalian": "Italien",
|
||||
"SettingsTabSystemSystemLanguageSpanish": "Espagnol",
|
||||
"SettingsTabSystemSystemLanguageChinese": "Chinois",
|
||||
"SettingsTabSystemSystemLanguageKorean": "Coréen",
|
||||
"SettingsTabSystemSystemLanguageDutch": "Néerlandais",
|
||||
"SettingsTabSystemSystemLanguagePortuguese": "Portugais",
|
||||
"SettingsTabSystemSystemLanguageRussian": "Russe",
|
||||
"SettingsTabSystemSystemLanguageTaiwanese": "Taïwanais",
|
||||
"SettingsTabSystemSystemLanguageBritishEnglish": "Anglais",
|
||||
"SettingsTabSystemSystemLanguageCanadianFrench": "Canadien",
|
||||
"SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Espagnol latino-américain",
|
||||
"SettingsTabSystemSystemLanguageSimplifiedChinese": "Chinois simplifié",
|
||||
"SettingsTabSystemSystemLanguageTraditionalChinese": "Chinois traditionnel",
|
||||
"SettingsTabSystemSystemTimeZone": "Fuseau horaire du système:",
|
||||
"SettingsTabSystemSystemTime": "Heure du système:",
|
||||
"SettingsTabSystemEnableVsync": "Activer la VSync",
|
||||
"SettingsTabSystemEnablePptc": "Activer le PPTC (Profiled Persistent Translation Cache)",
|
||||
"SettingsTabSystemEnableFsIntegrityChecks": "Activer la vérification de l'intégrité du système de fichiers",
|
||||
"SettingsTabSystemAudioBackend": "Bibliothèque Audio:",
|
||||
"SettingsTabSystemAudioBackendDummy": "Dummy",
|
||||
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
|
||||
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": " (Cela peut causer des instabilitées)",
|
||||
"SettingsTabSystemExpandDramSize": "Augmenter la taille de la DRAM à 6GB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignorer les services manquant",
|
||||
"SettingsTabGraphics": "Graphique",
|
||||
"SettingsTabGraphicsAPI": "API Graphique",
|
||||
"SettingsTabGraphicsEnableShaderCache": "Activer le cache des shaders",
|
||||
"SettingsTabGraphicsAnisotropicFiltering": "Filtrage anisotrope:",
|
||||
"SettingsTabGraphicsAnisotropicFilteringAuto": "Auto",
|
||||
"SettingsTabGraphicsAnisotropicFiltering2x": "2x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering4x": "4x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering8x": "8x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering16x": "16x",
|
||||
"SettingsTabGraphicsResolutionScale": "Échelle de résolution:",
|
||||
"SettingsTabGraphicsResolutionScaleCustom": "Customisée (Non recommandée)",
|
||||
"SettingsTabGraphicsResolutionScaleNative": "Native (720p/1080p)",
|
||||
"SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)",
|
||||
"SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)",
|
||||
"SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)",
|
||||
"SettingsTabGraphicsAspectRatio": "Format:",
|
||||
"SettingsTabGraphicsAspectRatio4x3": "4:3",
|
||||
"SettingsTabGraphicsAspectRatio16x9": "16:9",
|
||||
"SettingsTabGraphicsAspectRatio16x10": "16:10",
|
||||
"SettingsTabGraphicsAspectRatio21x9": "21:9",
|
||||
"SettingsTabGraphicsAspectRatio32x9": "32:9",
|
||||
"SettingsTabGraphicsAspectRatioStretch": "Écran étiré",
|
||||
"SettingsTabGraphicsDeveloperOptions": "Options développeur",
|
||||
"SettingsTabGraphicsShaderDumpPath": "Chemin du dossier de dump des shaders:",
|
||||
"SettingsTabGraphicsFeatures": "Fonctionnalités & Améliorations",
|
||||
"SettingsTabLogging": "Journaux",
|
||||
"SettingsTabLoggingLogging": "Journaux",
|
||||
"SettingsTabLoggingEnableLoggingToFile": "Activer la sauvegarde des journaux vers un fichier",
|
||||
"SettingsTabLoggingEnableStubLogs": "Activer les journaux stub",
|
||||
"SettingsTabLoggingEnableInfoLogs": "Activer les journaux d'informations",
|
||||
"SettingsTabLoggingEnableWarningLogs": "Activer les journaux d'avertissements",
|
||||
"SettingsTabLoggingEnableErrorLogs": "Activer les journaux d'erreurs",
|
||||
"SettingsTabLoggingEnableGuestLogs": "Activer les journaux du programme simulé",
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Activer les journaux des accès au système de fichiers",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Niveau des journaux des accès au système de fichiers:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Options développeur (ATTENTION: Cela peut réduire les performances)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "Niveau des journaux OpenGL:",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "Aucun",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "Erreur",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Ralentissements",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "Tout",
|
||||
"SettingsTabLoggingEnableDebugLogs": "Activer les journaux de debug",
|
||||
"SettingsTabInput": "Contrôles",
|
||||
"SettingsTabInputEnableDockedMode": "Active le mode station d'accueil",
|
||||
"SettingsTabInputDirectKeyboardAccess": "Accès direct au clavier",
|
||||
"SettingsButtonSave": "Enregistrer",
|
||||
"SettingsButtonClose": "Fermer",
|
||||
"SettingsButtonApply": "Appliquer",
|
||||
"ControllerSettingsPlayer": "Joueur",
|
||||
"ControllerSettingsPlayer1": "Joueur 1",
|
||||
"ControllerSettingsPlayer2": "Joueur 2",
|
||||
"ControllerSettingsPlayer3": "Joueur 3",
|
||||
"ControllerSettingsPlayer4": "Joueur 4",
|
||||
"ControllerSettingsPlayer5": "Joueur 5",
|
||||
"ControllerSettingsPlayer6": "Joueur 6",
|
||||
"ControllerSettingsPlayer7": "Joueur 7",
|
||||
"ControllerSettingsPlayer8": "Joueur 8",
|
||||
"ControllerSettingsHandheld": "Portable",
|
||||
"ControllerSettingsInputDevice": "Périphériques",
|
||||
"ControllerSettingsRefresh": "Actualiser",
|
||||
"ControllerSettingsDeviceDisabled": "Désactivé",
|
||||
"ControllerSettingsControllerType": "Type de Controleur",
|
||||
"ControllerSettingsControllerTypeHandheld": "Portable",
|
||||
"ControllerSettingsControllerTypeProController": "Pro Controller",
|
||||
"ControllerSettingsControllerTypeJoyConPair": "JoyCon Joints",
|
||||
"ControllerSettingsControllerTypeJoyConLeft": "JoyCon Gauche",
|
||||
"ControllerSettingsControllerTypeJoyConRight": "JoyCon Droite",
|
||||
"ControllerSettingsProfile": "Profil",
|
||||
"ControllerSettingsProfileDefault": "Défaut",
|
||||
"ControllerSettingsLoad": "Charger",
|
||||
"ControllerSettingsAdd": "Ajouter",
|
||||
"ControllerSettingsRemove": "Supprimer",
|
||||
"ControllerSettingsButtons": "Boutons",
|
||||
"ControllerSettingsButtonA": "A",
|
||||
"ControllerSettingsButtonB": "B",
|
||||
"ControllerSettingsButtonX": "X",
|
||||
"ControllerSettingsButtonY": "Y",
|
||||
"ControllerSettingsButtonPlus": "+",
|
||||
"ControllerSettingsButtonMinus": "-",
|
||||
"ControllerSettingsDPad": "Croix Directionnelle",
|
||||
"ControllerSettingsDPadUp": "Haut",
|
||||
"ControllerSettingsDPadDown": "Bas",
|
||||
"ControllerSettingsDPadLeft": "Gauche",
|
||||
"ControllerSettingsDPadRight": "Droite",
|
||||
"ControllerSettingsLStick": "Joystick Gauche",
|
||||
"ControllerSettingsLStickButton": "Bouton",
|
||||
"ControllerSettingsLStickUp": "Haut",
|
||||
"ControllerSettingsLStickDown": "Bas",
|
||||
"ControllerSettingsLStickLeft": "Gauche",
|
||||
"ControllerSettingsLStickRight": "Droite",
|
||||
"ControllerSettingsLStickStick": "Joystick",
|
||||
"ControllerSettingsLStickInvertXAxis": "Inverser l'axe X",
|
||||
"ControllerSettingsLStickInvertYAxis": "Inverser l'axe Y",
|
||||
"ControllerSettingsLStickDeadzone": "Zone morte:",
|
||||
"ControllerSettingsRStick": "Joystick Droit",
|
||||
"ControllerSettingsRStickButton": "Bouton",
|
||||
"ControllerSettingsRStickUp": "Haut",
|
||||
"ControllerSettingsRStickDown": "Bas",
|
||||
"ControllerSettingsRStickLeft": "Gauche",
|
||||
"ControllerSettingsRStickRight": "Droite",
|
||||
"ControllerSettingsRStickStick": "Joystick",
|
||||
"ControllerSettingsRStickInvertXAxis": "Inverser l'axe X",
|
||||
"ControllerSettingsRStickInvertYAxis": "Inverser l'axe Y",
|
||||
"ControllerSettingsRStickDeadzone": "Zone morte:",
|
||||
"ControllerSettingsTriggers": "Gachettes",
|
||||
"ControllerSettingsTriggersLeft": "Gachettes Gauche",
|
||||
"ControllerSettingsTriggersRight": "Gachettes Droite",
|
||||
"ControllerSettingsTriggersButtonsLeft": "Boutons Gachettes Gauche",
|
||||
"ControllerSettingsTriggersButtonsRight": "Boutons Gachettes Droite",
|
||||
"ControllerSettingsTriggerL": "L",
|
||||
"ControllerSettingsTriggerR": "R",
|
||||
"ControllerSettingsTriggerZL": "ZL",
|
||||
"ControllerSettingsTriggerZR": "ZR",
|
||||
"ControllerSettingsLeftSL": "SL",
|
||||
"ControllerSettingsLeftSR": "SR",
|
||||
"ControllerSettingsRightSL": "SL",
|
||||
"ControllerSettingsRightSR": "SR",
|
||||
"ControllerSettingsExtraButtonsLeft": "Boutons Gauche",
|
||||
"ControllerSettingsExtraButtonsRight": "Boutons Droite",
|
||||
"ControllerSettingsMisc": "Divers",
|
||||
"ControllerSettingsTriggerThreshold": "Seuil de gachettes:",
|
||||
"ControllerSettingsMotion": "Mouvements",
|
||||
"ControllerSettingsConfigureGeneral": "Configurer",
|
||||
"ControllerSettingsMotionUseCemuhookCompatibleMotion": "Utiliser un capteur de mouvements CemuHook",
|
||||
"ControllerSettingsMotionControllerSlot": "Contrôleur ID:",
|
||||
"ControllerSettingsMotionMirrorInput": "Inverser les contrôles",
|
||||
"ControllerSettingsMotionRightJoyConSlot": "JoyCon Droit ID:",
|
||||
"ControllerSettingsMotionServerHost": "Addresse du Server:",
|
||||
"ControllerSettingsMotionGyroSensitivity": "Sensibilitée du gyroscope:",
|
||||
"ControllerSettingsMotionGyroDeadzone": "Zone morte du gyroscope:",
|
||||
"ControllerSettingsSave": "Enregistrer",
|
||||
"ControllerSettingsClose": "Fermer",
|
||||
"UserProfilesSelectedUserProfile": "Choisir un profil utilisateur:",
|
||||
"UserProfilesSaveProfileName": "Enregistrer le nom du profil",
|
||||
"UserProfilesChangeProfileImage": "Changer l'image du profil",
|
||||
"UserProfilesAvailableUserProfiles": "Profils utilisateurs disponible:",
|
||||
"UserProfilesAddNewProfile": "Ajouter un nouveau profil",
|
||||
"UserProfilesDeleteSelectedProfile": "Supprimer le profil sélectionné",
|
||||
"UserProfilesClose": "Fermer",
|
||||
"ProfileImageSelectionTitle": "Sélection de l'image du profil",
|
||||
"ProfileImageSelectionHeader": "Choisir l'image du profil",
|
||||
"ProfileImageSelectionNote": "Vous pouvez importer une image de profil personnalisée ou sélectionner un avatar à partir du firmware",
|
||||
"ProfileImageSelectionImportImage": "Importer une image",
|
||||
"ProfileImageSelectionSelectAvatar": "Choisir un avatar du firmware",
|
||||
"InputDialogTitle": "Fenêtre d'entrée de texte",
|
||||
"InputDialogOk": "OK",
|
||||
"InputDialogCancel": "Annuler",
|
||||
"InputDialogAddNewProfileTitle": "Choisir un nom de profil",
|
||||
"InputDialogAddNewProfileHeader": "Merci d'entrer un nom de profil",
|
||||
"InputDialogAddNewProfileSubtext": "(Longueur max.: {0})",
|
||||
"AvatarChoose": "Choisir",
|
||||
"AvatarSetBackgroundColor": "Choisir une couleur de fond",
|
||||
"AvatarClose": "Fermer",
|
||||
"ControllerMotionTitle": "Motion Control Settings",
|
||||
"ControllerRumbleTitle": "Rumble Settings"
|
||||
}
|
@ -1,560 +0,0 @@
|
||||
{
|
||||
"MenuBarFileOpenApplet": "Apri applet",
|
||||
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Apri l'editor Mii in modalità standalone",
|
||||
"SettingsTabInputDirectMouseAccess": "Accesso diretto al mouse",
|
||||
"SettingsTabSystemMemoryManagerMode": "Modalità di gestione della memoria:",
|
||||
"SettingsTabSystemMemoryManagerModeSoftware": "Software",
|
||||
"SettingsTabSystemMemoryManagerModeHost": "Host (veloce)",
|
||||
"SettingsTabSystemMemoryManagerModeHostUnchecked": "Host Unchecked (più veloce, non sicura)",
|
||||
"MenuBarFile": "_File",
|
||||
"MenuBarFileOpenFromFile": "_Carica applicazione da un file",
|
||||
"MenuBarFileOpenUnpacked": "Carica _gioco estratto",
|
||||
"MenuBarFileOpenEmuFolder": "Apri cartella di Ryujinx",
|
||||
"MenuBarFileOpenLogsFolder": "Apri cartella dei logs",
|
||||
"MenuBarFileExit": "_Esci",
|
||||
"MenuBarOptions": "Opzioni",
|
||||
"MenuBarOptionsToggleFullscreen": "Schermo intero",
|
||||
"MenuBarOptionsStartGamesInFullscreen": "Avvia i giochi a schermo intero",
|
||||
"MenuBarOptionsStopEmulation": "Ferma emulazione",
|
||||
"MenuBarOptionsSettings": "_Impostazioni",
|
||||
"MenuBarOptionsManageUserProfiles": "_Gestisci i profili utente",
|
||||
"MenuBarActions": "_Azioni",
|
||||
"MenuBarOptionsSimulateWakeUpMessage": "Simula messaggio Wake-up",
|
||||
"MenuBarActionsScanAmiibo": "Scansiona un Amiibo",
|
||||
"MenuBarTools": "_Strumenti",
|
||||
"MenuBarToolsInstallFirmware": "Installa firmware",
|
||||
"MenuBarFileToolsInstallFirmwareFromFile": "Installa un firmware da file XCI o ZIP",
|
||||
"MenuBarFileToolsInstallFirmwareFromDirectory": "Installa un firmare da una cartella",
|
||||
"MenuBarHelp": "Aiuto",
|
||||
"MenuBarHelpCheckForUpdates": "Controlla aggiornamenti",
|
||||
"MenuBarHelpAbout": "Informazioni",
|
||||
"MenuSearch": "Cerca...",
|
||||
"GameListHeaderFavorite": "Pref",
|
||||
"GameListHeaderIcon": "Icona",
|
||||
"GameListHeaderApplication": "Nome",
|
||||
"GameListHeaderDeveloper": "Sviluppatore",
|
||||
"GameListHeaderVersion": "Versione",
|
||||
"GameListHeaderTimePlayed": "Tempo di gioco",
|
||||
"GameListHeaderLastPlayed": "Giocato l'ultima volta",
|
||||
"GameListHeaderFileExtension": "Estensione",
|
||||
"GameListHeaderFileSize": "Dimensione file",
|
||||
"GameListHeaderPath": "Percorso",
|
||||
"GameListContextMenuOpenUserSaveDirectory": "Apri la cartella salvataggi dell'utente",
|
||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "Apre la cartella che contiene i salvataggi di gioco dell'utente",
|
||||
"GameListContextMenuOpenUserDeviceDirectory": "Apri la cartella dispositivo dell'utente",
|
||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "Apre la cartella che contiene i salvataggi di gioco del dispositivo",
|
||||
"GameListContextMenuOpenUserBcatDirectory": "Apri la cartella BCAT dell'utente",
|
||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "Apre la cartella che contiene i salvataggi BCAT dell'applicazione",
|
||||
"GameListContextMenuManageTitleUpdates": "Gestisci aggiornamenti del gioco",
|
||||
"GameListContextMenuManageTitleUpdatesToolTip": "Apre la finestra di gestione aggiornamenti del gioco",
|
||||
"GameListContextMenuManageDlc": "Gestici DLC",
|
||||
"GameListContextMenuManageDlcToolTip": "Apre la finestra di gestione DLC",
|
||||
"GameListContextMenuOpenModsDirectory": "Apri cartella delle mods",
|
||||
"GameListContextMenuOpenModsDirectoryToolTip": "Apre la cartella che contiene le mods dell'applicazione",
|
||||
"GameListContextMenuCacheManagement": "Gestione della cache",
|
||||
"GameListContextMenuCacheManagementPurgePptc": "Pulisci PPTC cache",
|
||||
"GameListContextMenuCacheManagementPurgePptcToolTip": "Elimina la PPTC cache dell'applicazione",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCache": "Pulisci shader cache",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Elimina la shader cache dell'applicazione",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectory": "Apri cartella PPTC",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "Apre la cartella che contiene la PPTC cache dell'applicazione",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectory": "Apri cartella shader cache",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "Apre la cartella che contiene la shader cache dell'applicazione",
|
||||
"GameListContextMenuExtractData": "Estrai dati",
|
||||
"GameListContextMenuExtractDataExeFS": "ExeFS",
|
||||
"GameListContextMenuExtractDataExeFSToolTip": "Estrae la sezione ExeFS dall'attuale configurazione dell'applicazione (includendo aggiornamenti)",
|
||||
"GameListContextMenuExtractDataRomFS": "RomFS",
|
||||
"GameListContextMenuExtractDataRomFSToolTip": "Estrae la sezione RomFS dall'attuale configurazione dell'applicazione (includendo aggiornamenti)",
|
||||
"GameListContextMenuExtractDataLogo": "Logo",
|
||||
"GameListContextMenuExtractDataLogoToolTip": "Estrae la sezione Logo dall'attuale configurazione dell'applicazione (includendo aggiornamenti)",
|
||||
"StatusBarGamesLoaded": "{0}/{1} Giochi caricati",
|
||||
"StatusBarSystemVersion": "Versione di sistema: {0}",
|
||||
"Settings": "Impostazioni",
|
||||
"SettingsTabGeneral": "Interfaccia utente",
|
||||
"SettingsTabGeneralGeneral": "Generali",
|
||||
"SettingsTabGeneralEnableDiscordRichPresence": "Attiva Discord Rich Presence",
|
||||
"SettingsTabGeneralCheckUpdatesOnLaunch": "Controlla aggiornamenti all'avvio",
|
||||
"SettingsTabGeneralShowConfirmExitDialog": "Mostra dialogo \"Conferma Uscita\"",
|
||||
"SettingsTabGeneralHideCursorOnIdle": "Nascondi cursore inattivo",
|
||||
"SettingsTabGeneralGameDirectories": "Cartelle dei giochi",
|
||||
"SettingsTabGeneralAdd": "Aggiungi",
|
||||
"SettingsTabGeneralRemove": "Rimuovi",
|
||||
"SettingsTabSystem": "Sistema",
|
||||
"SettingsTabSystemCore": "Core",
|
||||
"SettingsTabSystemSystemRegion": "Regione di sistema:",
|
||||
"SettingsTabSystemSystemRegionJapan": "Giappone",
|
||||
"SettingsTabSystemSystemRegionUSA": "Stati Uniti d'America",
|
||||
"SettingsTabSystemSystemRegionEurope": "Europa",
|
||||
"SettingsTabSystemSystemRegionAustralia": "Australia",
|
||||
"SettingsTabSystemSystemRegionChina": "Cina",
|
||||
"SettingsTabSystemSystemRegionKorea": "Corea",
|
||||
"SettingsTabSystemSystemRegionTaiwan": "Taiwan",
|
||||
"SettingsTabSystemSystemLanguage": "Lingua di sistema:",
|
||||
"SettingsTabSystemSystemLanguageJapanese": "Giapponese",
|
||||
"SettingsTabSystemSystemLanguageAmericanEnglish": "Inglese americano",
|
||||
"SettingsTabSystemSystemLanguageFrench": "Francese",
|
||||
"SettingsTabSystemSystemLanguageGerman": "Tedesco",
|
||||
"SettingsTabSystemSystemLanguageItalian": "Italiano",
|
||||
"SettingsTabSystemSystemLanguageSpanish": "Spagnolo",
|
||||
"SettingsTabSystemSystemLanguageChinese": "Cinese",
|
||||
"SettingsTabSystemSystemLanguageKorean": "Coreano",
|
||||
"SettingsTabSystemSystemLanguageDutch": "Olandese",
|
||||
"SettingsTabSystemSystemLanguagePortuguese": "Portoghese",
|
||||
"SettingsTabSystemSystemLanguageRussian": "Russo",
|
||||
"SettingsTabSystemSystemLanguageTaiwanese": "Taiwanese",
|
||||
"SettingsTabSystemSystemLanguageBritishEnglish": "Inglese britannico",
|
||||
"SettingsTabSystemSystemLanguageCanadianFrench": "Francese canadese",
|
||||
"SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Spagnolo latino americano",
|
||||
"SettingsTabSystemSystemLanguageSimplifiedChinese": "Cinese semplificato",
|
||||
"SettingsTabSystemSystemLanguageTraditionalChinese": "Cinese tradizionale",
|
||||
"SettingsTabSystemSystemTimeZone": "Fuso orario di sistema:",
|
||||
"SettingsTabSystemSystemTime": "Data e ora di sistema:",
|
||||
"SettingsTabSystemEnableVsync": "Attiva VSync",
|
||||
"SettingsTabSystemEnablePptc": "Attiva PPTC (Profiled Persistent Translation Cache)",
|
||||
"SettingsTabSystemEnableFsIntegrityChecks": "Attiva controlli d'integrità FS",
|
||||
"SettingsTabSystemAudioBackend": "Backend audio:",
|
||||
"SettingsTabSystemAudioBackendDummy": "Dummy",
|
||||
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
|
||||
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": " (Possono causare instabilità)",
|
||||
"SettingsTabSystemExpandDramSize": "Espandi dimensione DRAM a 6GB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignora servizi mancanti",
|
||||
"SettingsTabGraphics": "Grafica",
|
||||
"SettingsTabGraphicsAPI": "API Grafiche",
|
||||
"SettingsTabGraphicsEnableShaderCache": "Attiva Shader Cache",
|
||||
"SettingsTabGraphicsAnisotropicFiltering": "Filtro anisotropico:",
|
||||
"SettingsTabGraphicsAnisotropicFilteringAuto": "Auto",
|
||||
"SettingsTabGraphicsAnisotropicFiltering2x": "2x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering4x": "4x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering8x": "8x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering16x": "16x",
|
||||
"SettingsTabGraphicsResolutionScale": "Scala della risoluzione:",
|
||||
"SettingsTabGraphicsResolutionScaleCustom": "Personalizzata (Non raccomandata)",
|
||||
"SettingsTabGraphicsResolutionScaleNative": "Nativa (720p/1080p)",
|
||||
"SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)",
|
||||
"SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)",
|
||||
"SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)",
|
||||
"SettingsTabGraphicsAspectRatio": "Rapporto d'aspetto:",
|
||||
"SettingsTabGraphicsAspectRatio4x3": "4:3",
|
||||
"SettingsTabGraphicsAspectRatio16x9": "16:9",
|
||||
"SettingsTabGraphicsAspectRatio16x10": "16:10",
|
||||
"SettingsTabGraphicsAspectRatio21x9": "21:9",
|
||||
"SettingsTabGraphicsAspectRatio32x9": "32:9",
|
||||
"SettingsTabGraphicsAspectRatioStretch": "Adatta alla finestra",
|
||||
"SettingsTabGraphicsDeveloperOptions": "Opzioni da sviluppatore",
|
||||
"SettingsTabGraphicsShaderDumpPath": "Percorso di dump degli shaders:",
|
||||
"SettingsTabLogging": "Log",
|
||||
"SettingsTabLoggingLogging": "Log",
|
||||
"SettingsTabLoggingEnableLoggingToFile": "Salva i log su file",
|
||||
"SettingsTabLoggingEnableStubLogs": "Attiva Stub Logs",
|
||||
"SettingsTabLoggingEnableInfoLogs": "Attiva Info Logs",
|
||||
"SettingsTabLoggingEnableWarningLogs": "Attiva Warning Logs",
|
||||
"SettingsTabLoggingEnableErrorLogs": "Attiva Error Logs",
|
||||
"SettingsTabLoggingEnableTraceLogs": "Attiva Trace Logs",
|
||||
"SettingsTabLoggingEnableGuestLogs": "Attiva Guest Logs",
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Attiva Fs Access Logs",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Modalità di log accesso globale Fs:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Opzioni da sviluppatore (AVVISO: Ridurrà le prestazioni)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "Livello di log OpenGL:",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "Nessuno",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "Errore",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Rallentamenti",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "Tutto",
|
||||
"SettingsTabLoggingEnableDebugLogs": "Attiva logs di debug",
|
||||
"SettingsTabInput": "Input",
|
||||
"SettingsTabInputEnableDockedMode": "Attiva modalità TV",
|
||||
"SettingsTabInputDirectKeyboardAccess": "Accesso diretto alla tastiera",
|
||||
"SettingsButtonSave": "Salva",
|
||||
"SettingsButtonClose": "Chiudi",
|
||||
"SettingsButtonApply": "Applica",
|
||||
"ControllerSettingsPlayer": "Giocatore",
|
||||
"ControllerSettingsPlayer1": "Giocatore 1",
|
||||
"ControllerSettingsPlayer2": "Giocatore 2",
|
||||
"ControllerSettingsPlayer3": "Giocatore 3",
|
||||
"ControllerSettingsPlayer4": "Giocatore 4",
|
||||
"ControllerSettingsPlayer5": "Giocatore 5",
|
||||
"ControllerSettingsPlayer6": "Giocatore 6",
|
||||
"ControllerSettingsPlayer7": "Giocatore 7",
|
||||
"ControllerSettingsPlayer8": "Giocatore 8",
|
||||
"ControllerSettingsHandheld": "Portatile",
|
||||
"ControllerSettingsInputDevice": "Dispositivo di input",
|
||||
"ControllerSettingsRefresh": "Ricarica",
|
||||
"ControllerSettingsDeviceDisabled": "Disabilitato",
|
||||
"ControllerSettingsControllerType": "Tipo di controller",
|
||||
"ControllerSettingsControllerTypeHandheld": "Portatile",
|
||||
"ControllerSettingsControllerTypeProController": "Pro Controller",
|
||||
"ControllerSettingsControllerTypeJoyConPair": "Coppia di JoyCon",
|
||||
"ControllerSettingsControllerTypeJoyConLeft": "JoyCon sinistro",
|
||||
"ControllerSettingsControllerTypeJoyConRight": "JoyCon destro",
|
||||
"ControllerSettingsProfile": "Profilo",
|
||||
"ControllerSettingsProfileDefault": "Predefinito",
|
||||
"ControllerSettingsLoad": "Carica",
|
||||
"ControllerSettingsAdd": "Aggiungi",
|
||||
"ControllerSettingsRemove": "Rimuovi",
|
||||
"ControllerSettingsButtons": "Pulsanti",
|
||||
"ControllerSettingsButtonA": "A",
|
||||
"ControllerSettingsButtonB": "B",
|
||||
"ControllerSettingsButtonX": "X",
|
||||
"ControllerSettingsButtonY": "Y",
|
||||
"ControllerSettingsButtonPlus": "+",
|
||||
"ControllerSettingsButtonMinus": "-",
|
||||
"ControllerSettingsDPad": "Croce direzionale",
|
||||
"ControllerSettingsDPadUp": "Su",
|
||||
"ControllerSettingsDPadDown": "Giù",
|
||||
"ControllerSettingsDPadLeft": "Sinistra",
|
||||
"ControllerSettingsDPadRight": "Destra",
|
||||
"ControllerSettingsLStick": "Stick sinistro",
|
||||
"ControllerSettingsLStickButton": "Pulsante",
|
||||
"ControllerSettingsLStickUp": "Su",
|
||||
"ControllerSettingsLStickDown": "Giù",
|
||||
"ControllerSettingsLStickLeft": "Sinistra",
|
||||
"ControllerSettingsLStickRight": "Destra",
|
||||
"ControllerSettingsLStickStick": "Stick",
|
||||
"ControllerSettingsLStickInvertXAxis": "Inverti stick X",
|
||||
"ControllerSettingsLStickInvertYAxis": "Inverti stick Y",
|
||||
"ControllerSettingsLStickDeadzone": "Zona morta:",
|
||||
"ControllerSettingsRStick": "Stick destro",
|
||||
"ControllerSettingsRStickButton": "Pulsante",
|
||||
"ControllerSettingsRStickUp": "Su",
|
||||
"ControllerSettingsRStickDown": "Giù",
|
||||
"ControllerSettingsRStickLeft": "Sinistra",
|
||||
"ControllerSettingsRStickRight": "Destra",
|
||||
"ControllerSettingsRStickStick": "Stick",
|
||||
"ControllerSettingsRStickInvertXAxis": "Inverti stick X",
|
||||
"ControllerSettingsRStickInvertYAxis": "Inverti stick Y",
|
||||
"ControllerSettingsRStickDeadzone": "Zona morta:",
|
||||
"ControllerSettingsTriggersLeft": "Grilletto sinistro",
|
||||
"ControllerSettingsTriggersRight": "Grilletto destro",
|
||||
"ControllerSettingsTriggersButtonsLeft": "Pulsante dorsale sinistro",
|
||||
"ControllerSettingsTriggersButtonsRight": "Pulsante dorsale destro",
|
||||
"ControllerSettingsTriggers": "Grilletti",
|
||||
"ControllerSettingsTriggerL": "L",
|
||||
"ControllerSettingsTriggerR": "R",
|
||||
"ControllerSettingsTriggerZL": "ZL",
|
||||
"ControllerSettingsTriggerZR": "ZR",
|
||||
"ControllerSettingsLeftSL": "SL",
|
||||
"ControllerSettingsLeftSR": "SR",
|
||||
"ControllerSettingsRightSL": "SL",
|
||||
"ControllerSettingsRightSR": "SR",
|
||||
"ControllerSettingsExtraButtonsLeft": "Tasto sinitro",
|
||||
"ControllerSettingsExtraButtonsRight": "Tasto destro",
|
||||
"ControllerSettingsMisc": "Miscellanee",
|
||||
"ControllerSettingsTriggerThreshold": "Sensibilità dei grilletti:",
|
||||
"ControllerSettingsMotion": "Movimento",
|
||||
"ControllerSettingsMotionUseCemuhookCompatibleMotion": "Usa sensore compatibile con CemuHook",
|
||||
"ControllerSettingsMotionControllerSlot": "Slot del controller:",
|
||||
"ControllerSettingsMotionMirrorInput": "Input specchiato",
|
||||
"ControllerSettingsMotionRightJoyConSlot": "Slot JoyCon destro:",
|
||||
"ControllerSettingsMotionServerHost": "Server:",
|
||||
"ControllerSettingsMotionGyroSensitivity": "Sensibilità del giroscopio:",
|
||||
"ControllerSettingsMotionGyroDeadzone": "Zona morta del giroscopio:",
|
||||
"ControllerSettingsSave": "Salva",
|
||||
"ControllerSettingsClose": "Chiudi",
|
||||
"UserProfilesSelectedUserProfile": "Profilo utente selezionato:",
|
||||
"UserProfilesSaveProfileName": "Salva nome del profilo",
|
||||
"UserProfilesChangeProfileImage": "Cambia immagine profilo",
|
||||
"UserProfilesAvailableUserProfiles": "Profili utente disponibili:",
|
||||
"UserProfilesAddNewProfile": "Aggiungi nuovo profilo",
|
||||
"UserProfilesDeleteSelectedProfile": "Elimina il profilo selezionato",
|
||||
"UserProfilesClose": "Chiudi",
|
||||
"ProfileImageSelectionTitle": "Selezione dell'immagine profilo",
|
||||
"ProfileImageSelectionHeader": "Scegli un'immagine profilo",
|
||||
"ProfileImageSelectionNote": "Puoi importare un'immagine profilo personalizzata o selezionare un avatar dal firmware di sistema",
|
||||
"ProfileImageSelectionImportImage": "Importa file immagine",
|
||||
"ProfileImageSelectionSelectAvatar": "Seleziona avatar dal firmware",
|
||||
"InputDialogTitle": "Input Dialog",
|
||||
"InputDialogOk": "OK",
|
||||
"InputDialogCancel": "Annulla",
|
||||
"InputDialogAddNewProfileTitle": "Scegli il nome profilo",
|
||||
"InputDialogAddNewProfileHeader": "Digita un nome profilo",
|
||||
"InputDialogAddNewProfileSubtext": "(Lunghezza massima: {0})",
|
||||
"AvatarChoose": "Scegli",
|
||||
"AvatarSetBackgroundColor": "Imposta colore di sfondo",
|
||||
"AvatarClose": "Chiudi",
|
||||
"ControllerSettingsLoadProfileToolTip": "Carica profilo",
|
||||
"ControllerSettingsAddProfileToolTip": "Aggiungi profilo",
|
||||
"ControllerSettingsRemoveProfileToolTip": "Rimuovi profilo",
|
||||
"ControllerSettingsSaveProfileToolTip": "Salva profilo",
|
||||
"MenuBarFileToolsTakeScreenshot": "Fai uno screenshot",
|
||||
"MenuBarFileToolsHideUi": "Nascondi Ui",
|
||||
"GameListContextMenuToggleFavorite": "Preferito",
|
||||
"GameListContextMenuToggleFavoriteToolTip": "Segna il gioco come preferito",
|
||||
"SettingsTabGeneralTheme": "Tema",
|
||||
"SettingsTabGeneralThemeCustomTheme": "Percorso del tema personalizzato",
|
||||
"SettingsTabGeneralThemeBaseStyle": "Modalità",
|
||||
"SettingsTabGeneralThemeBaseStyleDark": "Scura",
|
||||
"SettingsTabGeneralThemeBaseStyleLight": "Chiara",
|
||||
"SettingsTabGeneralThemeEnableCustomTheme": "Attiva tema personalizzato",
|
||||
"ButtonBrowse": "Sfoglia",
|
||||
"ControllerSettingsConfigureGeneral": "Configura",
|
||||
"ControllerSettingsRumble": "Vibrazione",
|
||||
"ControllerSettingsRumbleStrongMultiplier": "Moltiplicatore vibrazione forte",
|
||||
"ControllerSettingsRumbleWeakMultiplier": "Moltiplicatore vibrazione debole",
|
||||
"DialogMessageSaveNotAvailableMessage": "Non ci sono dati di salvataggio per {0} [{1:x16}]",
|
||||
"DialogMessageSaveNotAvailableCreateSaveMessage": "Vuoi creare dei dat di salvataggio per questo gioco?",
|
||||
"DialogConfirmationTitle": "Ryujinx - Conferma",
|
||||
"DialogUpdaterTitle": "Ryujinx - Updater",
|
||||
"DialogErrorTitle": "Ryujinx - Errore",
|
||||
"DialogWarningTitle": "Ryujinx - Avviso",
|
||||
"DialogExitTitle": "Ryujinx - Uscita",
|
||||
"DialogErrorMessage": "Ryujinx ha riscontrato un problema",
|
||||
"DialogExitMessage": "Sei sicuro di voler chiudere Ryujinx?",
|
||||
"DialogExitSubMessage": "Tutti i dati non salvati andranno persi!",
|
||||
"DialogMessageCreateSaveErrorMessage": "C'è stato un errore durante la creazione dei dati di salvataggio: {0}",
|
||||
"DialogMessageFindSaveErrorMessage": "C'è stato un errore durante la ricerca dei dati di salvataggio: {0}",
|
||||
"FolderDialogExtractTitle": "Scegli una cartella in cui estrarre",
|
||||
"DialogNcaExtractionMessage": "Estrazione della sezione {0} da {1}...",
|
||||
"DialogNcaExtractionTitle": "Ryujinx - Estrattore sezione NCA",
|
||||
"DialogNcaExtractionMainNcaNotFoundErrorMessage": "L'estrazione è fallita. L'NCA principale non era presente nel file selezionato.",
|
||||
"DialogNcaExtractionCheckLogErrorMessage": "L'estrazione è fallita. Leggi il log per più informazioni.",
|
||||
"DialogNcaExtractionSuccessMessage": "Estrazione completata con successo.",
|
||||
"DialogUpdaterConvertFailedMessage": "La conversione dell'attuale versione di Ryujinx è fallita.",
|
||||
"DialogUpdaterCancelUpdateMessage": "Annullando l'aggiornamento!",
|
||||
"DialogUpdaterAlreadyOnLatestVersionMessage": "Stai già usando la versione più recente di Ryujinx!",
|
||||
"DialogUpdaterFailedToGetVersionMessage": "Si è verificato un errore nel tentativo di ottenere informazioni da Github Release. Questo può verificarsi se una nuova release è in compilazione su GitHub Actions. Riprova tra qualche minuto.",
|
||||
"DialogUpdaterConvertFailedGithubMessage": "La conversione della versione di Ryujinx ricevuta da Github Release è fallita.",
|
||||
"DialogUpdaterDownloadingMessage": "Download dell'aggiornamento...",
|
||||
"DialogUpdaterExtractionMessage": "Estrazione dell'aggiornamento...",
|
||||
"DialogUpdaterRenamingMessage": "Rinominazione dell'aggiornamento...",
|
||||
"DialogUpdaterAddingFilesMessage": "Aggiunta nuovo aggiornamento...",
|
||||
"DialogUpdaterCompleteMessage": "Aggiornamento completato!",
|
||||
"DialogUpdaterRestartMessage": "Vuoi riavviare Ryujinx adesso?",
|
||||
"DialogUpdaterArchNotSupportedMessage": "Non stai usando un'architettura di sistema supportata!",
|
||||
"DialogUpdaterArchNotSupportedSubMessage": "(Solo sistemi x64 sono supportati!)",
|
||||
"DialogUpdaterNoInternetMessage": "Non sei connesso ad Internet!",
|
||||
"DialogUpdaterNoInternetSubMessage": "Verifica di avere una connessione ad Internet funzionante!",
|
||||
"DialogUpdaterDirtyBuildMessage": "Non puoi aggiornare una Dirty build di Ryujinx!",
|
||||
"DialogUpdaterDirtyBuildSubMessage": "Scarica Ryujinx da https://ryujinx.org/ se stai cercando una versione supportata.",
|
||||
"DialogRestartRequiredMessage": "Riavvio richiesto",
|
||||
"DialogThemeRestartMessage": "Il tema è stato salvato. E' richiesto un riavvio per applicare un tema.",
|
||||
"DialogThemeRestartSubMessage": "Vuoi riavviare?",
|
||||
"DialogFirmwareInstallEmbeddedMessage": "Vuoi installare il firmware incorporato in questo gioco? (Firmware {0})",
|
||||
"DialogFirmwareInstallEmbeddedSuccessMessage": "Non è stato trovato alcun firmware installato, ma Ryujinx è riuscito di installare il firmware {0} dal gioco fornito.\nL'emulatore si avvierà adesso.",
|
||||
"DialogFirmwareNoFirmwareInstalledMessage": "Nessun firmware installato",
|
||||
"DialogFirmwareInstalledMessage": "Il firmware {0} è stato installato",
|
||||
"DialogOpenSettingsWindowLabel": "Apri finestra delle impostazioni",
|
||||
"DialogControllerAppletTitle": "Applet del controller",
|
||||
"DialogMessageDialogErrorExceptionMessage": "Errore nella visualizzazione del Message Dialog: {0}",
|
||||
"DialogSoftwareKeyboardErrorExceptionMessage": "Errore nella visualizzazione della tastiera software: {0}",
|
||||
"DialogErrorAppletErrorExceptionMessage": "Errore nella visualizzazione dell'ErrorApplet Dialog: {0}",
|
||||
"DialogUserErrorDialogMessage": "{0}: {1}",
|
||||
"DialogUserErrorDialogInfoMessage": "\nPer più informazioni su come risolvere questo errore, segui la nostra guida all'installazione.",
|
||||
"DialogUserErrorDialogTitle": "Errore di Ryujinx ({0})",
|
||||
"DialogAmiiboApiTitle": "Amiibo API",
|
||||
"DialogAmiiboApiFailFetchMessage": "Si è verificato un errore durante il recupero delle informazioni dall'API.",
|
||||
"DialogAmiiboApiConnectErrorMessage": "Impossibile connettersi al server Amiibo API. Il servizio potrebbe essere fuori uso o potresti dover verificare che la tua connessione internet sia online.",
|
||||
"DialogProfileInvalidProfileErrorMessage": "Il profilo {0} è incompatibile con l'attuale sistema di configurazione input.",
|
||||
"DialogProfileDefaultProfileOverwriteErrorMessage": "Il profilo predefinito non può essere sovrascritto",
|
||||
"DialogProfileDeleteProfileTitle": "Eliminazione profilo",
|
||||
"DialogProfileDeleteProfileMessage": "Quest'azione è irreversibile, sei sicuro di voler continuare?",
|
||||
"DialogWarning": "Avviso",
|
||||
"DialogPPTCDeletionMessage": "Stai per eliminare la PPTC cache per :\n\n{0}\n\nSei sicuro di voler proseguire?",
|
||||
"DialogPPTCDeletionErrorMessage": "Errore nell'eliminazione della PPTC cache a {0}: {1}",
|
||||
"DialogShaderDeletionMessage": "Stai per eliminare la Shader cache per :\n\n{0}\n\nSei sicuro di voler proseguire?",
|
||||
"DialogShaderDeletionErrorMessage": "Errore nell'eliminazione della Shader cache a {0}: {1}",
|
||||
"DialogRyujinxErrorMessage": "Ryujinx ha incontrato un errore",
|
||||
"DialogInvalidTitleIdErrorMessage": "Errore UI: Il gioco selezionato non ha un title ID valido",
|
||||
"DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "Un firmware di sistema valido non è stato trovato in {0}.",
|
||||
"DialogFirmwareInstallerFirmwareInstallTitle": "Installa firmware {0}",
|
||||
"DialogFirmwareInstallerFirmwareInstallMessage": "La versione di sistema {0} sarà installata.",
|
||||
"DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\nQuesta sostituirà l'attuale versione di sistema {0}.",
|
||||
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nVuoi continuare?",
|
||||
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "Installazione del firmware...",
|
||||
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "La versione di sistema {0} è stata installata.",
|
||||
"DialogUserProfileDeletionWarningMessage": "Non ci sarebbero altri profili da aprire se il profilo selezionato viene cancellato",
|
||||
"DialogUserProfileDeletionConfirmMessage": "Vuoi eliminare il profilo selezionato?",
|
||||
"DialogControllerSettingsModifiedConfirmMessage": "Le attuali impostazioni del controller sono state aggiornate.",
|
||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Vuoi salvare?",
|
||||
"DialogDlcLoadNcaErrorMessage": "{0}. File errato: {1}",
|
||||
"DialogDlcNoDlcErrorMessage": "Il file specificato non contiene un DLC per il titolo selezionato!",
|
||||
"DialogPerformanceCheckLoggingEnabledMessage": "Hai abilitato il trace logging, che è progettato per essere usato solo dagli sviluppatori.",
|
||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Per prestazioni ottimali, si raccomanda di disabilitare il trace logging. Vuoi disabilitare il debug logging adesso?",
|
||||
"DialogPerformanceCheckShaderDumpEnabledMessage": "Hai abilitato lo shader dumping, che è progettato per essere usato solo dagli sviluppatori.",
|
||||
"DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "Per prestazioni ottimali, si raccomanda di disabilitare lo shader dumping. Vuoi disabilitare lo shader dumping adesso?",
|
||||
"DialogLoadAppGameAlreadyLoadedMessage": "Un gioco è già stato caricato",
|
||||
"DialogLoadAppGameAlreadyLoadedSubMessage": "Ferma l'emulazione o chiudi l'emulatore prima di avviare un altro gioco.",
|
||||
"DialogUpdateAddUpdateErrorMessage": "Il file specificato non contiene un aggiornamento per il titolo selezionato!",
|
||||
"DialogSettingsBackendThreadingWarningTitle": "Avviso - Backend Threading",
|
||||
"DialogSettingsBackendThreadingWarningMessage": "Ryujinx deve essere riavviato dopo aver cambiato questa opzione per applicarla completamente. A seconda della tua piattaforma, potrebbe essere necessario disabilitare manualmente il multithreading del driver quando usi quello di Ryujinx.",
|
||||
"SettingsTabGraphicsFeaturesOptions": "Funzionalità",
|
||||
"SettingsTabGraphicsBackendMultithreading": "Graphics Backend Multithreading",
|
||||
"CommonAuto": "Auto",
|
||||
"CommonOff": "Spento",
|
||||
"CommonOn": "Acceso",
|
||||
"InputDialogYes": "Si",
|
||||
"InputDialogNo": "No",
|
||||
"DialogProfileInvalidProfileNameErrorMessage": "Il nome del file contiene caratteri non validi. Riprova.",
|
||||
"MenuBarOptionsPauseEmulation": "Pausa",
|
||||
"MenuBarOptionsResumeEmulation": "Riprendi",
|
||||
"AboutUrlTooltipMessage": "Clicca per aprire il sito web di Ryujinx nel tuo browser predefinito.",
|
||||
"AboutDisclaimerMessage": "Ryujinx non è affiliato con Nintendo™,\no i suoi partner, in alcun modo.",
|
||||
"AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) è usata\nnella nostra emulazione Amiibo.",
|
||||
"AboutPatreonUrlTooltipMessage": "Clicca per aprire la pagina Patreon di Ryujinx nel tuo browser predefinito.",
|
||||
"AboutGithubUrlTooltipMessage": "Clicca per aprire la pagina GitHub di Ryujinx nel tuo browser predefinito.",
|
||||
"AboutDiscordUrlTooltipMessage": "Clicca per aprire un invito al server Discord di Ryujinx nel tuo browser predefinito.",
|
||||
"AboutTwitterUrlTooltipMessage": "Clicca per aprire la pagina Twitter di Ryujinx nel tuo browser predefinito.",
|
||||
"AboutRyujinxAboutTitle": "Informazioni:",
|
||||
"AboutRyujinxAboutContent": "Ryujinx è un emulatore per la Nintendo Switch™.\nPer favore supportaci su Patreon.\nRicevi tutte le ultime notizie sul nostro Twitter o su Discord.\nGli sviluppatori interessati a contribuire possono trovare più informazioni sul nostro GitHub o Discord.",
|
||||
"AboutRyujinxMaintainersTitle": "Mantenuto da:",
|
||||
"AboutRyujinxMaintainersContentTooltipMessage": "Clicca per aprire la pagina dei Contributors nel tuo browser predefinito.",
|
||||
"AboutRyujinxSupprtersTitle": "Supportato su Patreon da:",
|
||||
"AmiiboSeriesLabel": "Serie Amiibo",
|
||||
"AmiiboCharacterLabel": "Personaggio",
|
||||
"AmiiboScanButtonLabel": "Scannerizza",
|
||||
"AmiiboOptionsShowAllLabel": "Mostra tutti gli amiibo",
|
||||
"AmiiboOptionsUsRandomTagLabel": "Hack: Usa un tag uuid casuale",
|
||||
"DlcManagerTableHeadingEnabledLabel": "Abilitato",
|
||||
"DlcManagerTableHeadingTitleIdLabel": "Title ID",
|
||||
"DlcManagerTableHeadingContainerPathLabel": "Percorso del contenitore",
|
||||
"DlcManagerTableHeadingFullPathLabel": "Percorso completo",
|
||||
"DlcManagerRemoveAllButton": "Rimuovi tutti",
|
||||
"MenuBarOptionsChangeLanguage": "Cambia lingua",
|
||||
"CommonSort": "Ordina",
|
||||
"CommonShowNames": "Mostra nomi",
|
||||
"CommonFavorite": "Preferito",
|
||||
"OrderAscending": "Crescente",
|
||||
"OrderDescending": "Decrescente",
|
||||
"SettingsTabGraphicsFeatures": "Funzionalità & Miglioramenti",
|
||||
"ErrorWindowTitle": "Finestra errore",
|
||||
"ToggleDiscordTooltip": "Attiva o disattiva Discord Rich Presence",
|
||||
"AddGameDirBoxTooltip": "Inserisci la directory di un gioco per aggiungerlo alla lista",
|
||||
"AddGameDirTooltip": "Aggiungi la directory di un gioco alla lista",
|
||||
"RemoveGameDirTooltip": "Rimuovi la directory di gioco selezionata",
|
||||
"CustomThemeCheckTooltip": "Attiva o disattiva temi personalizzati nella GUI",
|
||||
"CustomThemePathTooltip": "Percorso al tema GUI personalizzato",
|
||||
"CustomThemeBrowseTooltip": "Sfoglia per cercare un tema GUI personalizzato",
|
||||
"DockModeToggleTooltip": "Attiva o disabilta modalità TV",
|
||||
"DirectKeyboardTooltip": "Attiva o disattiva \"il supporto all'accesso diretto alla tastiera (HID)\" (Fornisce l'accesso ai giochi alla tua tastiera come dispositivo di immissione del testo)",
|
||||
"DirectMouseTooltip": "Attiva o disattiva \"il supporto all'accesso diretto al mouse (HID)\" (Fornisce l'accesso ai giochi al tuo mouse come dispositivo di puntamento)",
|
||||
"RegionTooltip": "Cambia regione di sistema",
|
||||
"LanguageTooltip": "Cambia lingua di sistema",
|
||||
"TimezoneTooltip": "Cambia fuso orario di sistema",
|
||||
"TimeTooltip": "Cambia data e ora di sistema",
|
||||
"VSyncToggleTooltip": "Attiva o disattiva sincronizzazione verticale",
|
||||
"PptcToggleTooltip": "Attiva o disattiva PPTC",
|
||||
"FsIntegrityToggleTooltip": "Attiva controlli d'integrità sui file dei contenuti di gioco",
|
||||
"AudioBackendTooltip": "Cambia backend audio",
|
||||
"MemoryManagerTooltip": "Cambia il modo in cui la memoria guest è mappata e vi si accede. Influisce notevolmente sulle prestazioni della CPU emulata.",
|
||||
"MemoryManagerSoftwareTooltip": "Usa una software page table per la traduzione degli indirizzi. Massima precisione ma prestazioni più lente.",
|
||||
"MemoryManagerHostTooltip": "Mappa direttamente la memoria nello spazio degli indirizzi dell'host. Compilazione ed esecuzione JIT molto più veloce.",
|
||||
"MemoryManagerUnsafeTooltip": "Mappa direttamente la memoria, ma non maschera l'indirizzo all'interno dello spazio degli indirizzi guest prima dell'accesso. Più veloce, ma a costo della sicurezza. L'applicazione guest può accedere alla memoria da qualsiasi punto di Ryujinx, quindi esegui solo programmi di cui ti fidi con questa modalità.",
|
||||
"DRamTooltip": "Espande l'ammontare di memoria sul sistema emulato da 4GB A 6GB",
|
||||
"IgnoreMissingServicesTooltip": "Attiva o disattiva l'opzione di ignorare i servizi mancanti",
|
||||
"GraphicsBackendThreadingTooltip": "Attiva il Graphics Backend Multithreading",
|
||||
"GalThreadingTooltip": "Esegue i comandi del backend grafico su un secondo thread. Permette il multithreading runtime della compilazione degli shader, riduce lo stuttering e migliora le prestazioni sui driver senza supporto multithreading proprio. Varia leggermente le prestazioni di picco sui driver con multithreading. Ryujinx potrebbe aver bisogno di essere riavviato per disabilitare correttamente il multithreading integrato nel driver, o potrebbe essere necessario farlo manualmente per ottenere le migliori prestazioni.",
|
||||
"ShaderCacheToggleTooltip": "Attiva o disattiva la Shader Cache",
|
||||
"ResolutionScaleTooltip": "Scala della risoluzione applicata ai render targets applicabili",
|
||||
"ResolutionScaleEntryTooltip": "Scala della risoluzione in virgola mobile, come 1,5. Le scale non integrali hanno maggiori probabilità di causare problemi o crash.",
|
||||
"AnisotropyTooltip": "Livello del filtro anisotropico (imposta su Auto per usare il valore richiesto dal gioco)",
|
||||
"AspectRatioTooltip": "Rapporto d'aspetto applicato alla finestra del renderer.",
|
||||
"ShaderDumpPathTooltip": "Percorso di dump Graphics Shaders",
|
||||
"FileLogTooltip": "Attiva o disattiva il logging su file",
|
||||
"StubLogTooltip": "Attiva messaggi stub log",
|
||||
"InfoLogTooltip": "Attiva messaggi info log",
|
||||
"WarnLogTooltip": "Attiva messaggi warning log",
|
||||
"ErrorLogTooltip": "Attiva messaggi error log",
|
||||
"TraceLogTooltip": "Attiva messaggi trace log",
|
||||
"GuestLogTooltip": "Attiva messaggi guest log",
|
||||
"FileAccessLogTooltip": "Attiva messaggi file access log",
|
||||
"FSAccessLogModeTooltip": "Attiva output FS access log alla console. Le modalità possibili sono 0-3",
|
||||
"DeveloperOptionTooltip": "Usa con attenzione",
|
||||
"OpenGlLogLevel": "Richiede livelli di log appropriati abilitati",
|
||||
"DebugLogTooltip": "Attiva messaggi debug log",
|
||||
"LoadApplicationFileTooltip": "Apri un file explorer per scegliere un file compatibile Switch da caricare",
|
||||
"LoadApplicationFolderTooltip": "Apri un file explorer per scegliere un file compatibile Switch, applicazione sfusa da caricare",
|
||||
"OpenRyujinxFolderTooltip": "Apri la cartella del filesystem di Ryujinx",
|
||||
"OpenRyujinxLogsTooltip": "Apre la cartella dove vengono scritti i log",
|
||||
"ExitTooltip": "Esci da Ryujinx",
|
||||
"OpenSettingsTooltip": "Apri finestra delle impostazioni",
|
||||
"OpenProfileManagerTooltip": "Apri la finestra di gestione dei profili utente",
|
||||
"StopEmulationTooltip": "Ferma l'emulazione del gioco attuale e torna alla selezione dei giochi",
|
||||
"CheckUpdatesTooltip": "Controlla la presenza di aggiornamenti di Ryujinx",
|
||||
"OpenAboutTooltip": "Apri finestra delle informazioni",
|
||||
"GridSize": "Dimensione griglia",
|
||||
"GridSizeTooltip": "Cambia la dimensione dei riquardi della griglia",
|
||||
"SettingsTabSystemSystemLanguageBrazilianPortuguese": "Portoghese Brasiliano",
|
||||
"AboutRyujinxContributorsButtonHeader": "Vedi tutti i Contributors",
|
||||
"SettingsTabSystemAudioVolume": "Volume: ",
|
||||
"AudioVolumeTooltip": "Cambia volume audio",
|
||||
"SettingsTabSystemEnableInternetAccess": "Attiva Guest Internet Access",
|
||||
"EnableInternetAccessTooltip": "Attiva il guest Internet access. Se abilitato, l'applicazione si comporterà come se la console Switch emulata fosse collegata a Internet. Si noti che in alcuni casi, le applicazioni possono comunque accedere a Internet anche con questa opzione disabilitata",
|
||||
"GameListContextMenuManageCheatToolTip": "Gestisci Cheats",
|
||||
"GameListContextMenuManageCheat": "Gestisci Cheats",
|
||||
"ControllerSettingsStickRange": "Raggio:",
|
||||
"DialogStopEmulationTitle": "Ryujinx - Ferma emulazione",
|
||||
"DialogStopEmulationMessage": "Sei sicuro di voler fermare l'emulazione?",
|
||||
"SettingsTabCpu": "CPU",
|
||||
"SettingsTabAudio": "Audio",
|
||||
"SettingsTabNetwork": "Rete",
|
||||
"SettingsTabNetworkConnection": "Connessione di rete",
|
||||
"SettingsTabCpuCache": "Cache CPU",
|
||||
"SettingsTabCpuMemory": "Memoria CPU",
|
||||
"DialogUpdaterFlatpakNotSupportedMessage": "Per favore aggiorna Ryujinx via FlatHub.",
|
||||
"UpdaterDisabledWarningTitle": "Updater disabilitato!",
|
||||
"GameListContextMenuOpenSdModsDirectory": "Apri cartella delle mods Atmosphere",
|
||||
"GameListContextMenuOpenSdModsDirectoryToolTip": "Apre la cartella aternativa di atmosphere che contiene le mods dell'applicazione",
|
||||
"ControllerSettingsRotate90": "Ruota in senso orario di 90°",
|
||||
"IconSize": "Dimensioni icona",
|
||||
"IconSizeTooltip": "Cambia le dimensioni dell'icona di un gioco",
|
||||
"MenuBarOptionsShowConsole": "Mostra console",
|
||||
"ShaderCachePurgeError" : "Errore nella pulizia della shader cache a {0}: {1}",
|
||||
"UserErrorNoKeys": "Chiavi non trovate",
|
||||
"UserErrorNoFirmware": "Firmware non trovato",
|
||||
"UserErrorFirmwareParsingFailed": "Errori di analisi del firmware",
|
||||
"UserErrorApplicationNotFound": "Applicazione non trovata",
|
||||
"UserErrorUnknown": "Errore sconosciuto",
|
||||
"UserErrorUndefined": "Errore non definito",
|
||||
"UserErrorNoKeysDescription": "Ryujinx non è riuscito a trovare il file 'prod.keys'",
|
||||
"UserErrorNoFirmwareDescription": "Ryujinx non è riuscito a trovare alcun firmware installato",
|
||||
"UserErrorFirmwareParsingFailedDescription": "Ryujinx non è riuscito ad analizzare il firmware. Questo di solito è causato da chiavi non aggiornate.",
|
||||
"UserErrorApplicationNotFoundDescription": "Ryujinx non è riuscito a trovare un'applicazione valida al percorso specificato.",
|
||||
"UserErrorUnknownDescription": "Si è verificato un errore sconosciuto!",
|
||||
"UserErrorUndefinedDescription": "Si è verificato un errore sconosciuto! Non dovrebbe succedere, per favore contatta uno sviluppatore!",
|
||||
"OpenSetupGuideMessage": "Apri la guida all'installazione",
|
||||
"NoUpdate": "Nessun aggiornamento",
|
||||
"TitleUpdateVersionLabel": "Versione {0} - {1}",
|
||||
"RyujinxInfo": "Ryujinx - Info",
|
||||
"RyujinxConfirm": "Ryujinx - Conferma",
|
||||
"FileDialogAllTypes": "Tutti i tipi",
|
||||
"Never": "Mai",
|
||||
"SwkbdMinCharacters": "Non può avere meno di {0} caratteri",
|
||||
"SwkbdMinRangeCharacters": "Può avere da {0} a {1} caratteri",
|
||||
"SoftwareKeyboard": "Tastiera software",
|
||||
"DialogControllerAppletMessagePlayerRange": "L'applicazione richiede {0} giocatori con:\n\nTIPI: {1}\n\nGIOCATORI: {2}\n\n{3}Apri le impostazioni e riconfigura l'input adesso o premi Chiudi.",
|
||||
"DialogControllerAppletMessage": "L'applicazione richiede esattamente {0} giocatori con:\n\nTIPI: {1}\n\nGIOCATORI: {2}\n\n{3}Apri le impostazioni e riconfigura l'input adesso o premi Chiudi.",
|
||||
"DialogControllerAppletDockModeSet": "Modalità TV attivata. Neanche portatile è valida.\n\n",
|
||||
"UpdaterRenaming": "Rinominazione dei vecchi files...",
|
||||
"UpdaterRenameFailed": "L'updater non è riuscito a rinominare il file: {0}",
|
||||
"UpdaterAddingFiles": "Aggiunta nuovi files...",
|
||||
"UpdaterExtracting": "Estrazione aggiornamento...",
|
||||
"UpdaterDownloading": "Download aggiornamento...",
|
||||
"Game": "Gioco",
|
||||
"Docked": "TV",
|
||||
"Handheld": "Portatile",
|
||||
"ConnectionError": "Errore di connessione.",
|
||||
"AboutPageDeveloperListMore": "{0} e altri ancora...",
|
||||
"ApiError": "Errore dell'API.",
|
||||
"LoadingHeading": "Caricamento di {0}",
|
||||
"CompilingPPTC": "Compilazione PTC",
|
||||
"CompilingShaders": "Compilazione Shaders",
|
||||
"AllKeyboards": "Tutte le tastiere",
|
||||
"OpenFileDialogTitle": "Seleziona un file supportato da aprire",
|
||||
"OpenFolderDialogTitle": "Seleziona una cartella con un gioco estratto",
|
||||
"AllSupportedFormats": "Tutti i formati supportati",
|
||||
"RyujinxUpdater": "Ryujinx Updater",
|
||||
"SettingsTabHotkeys": "Tasti di scelta rapida",
|
||||
"SettingsTabHotkeysHotkeys": "Tasti di scelta rapida",
|
||||
"SettingsTabHotkeysToggleVsyncHotkey": "VSync:",
|
||||
"SettingsTabHotkeysScreenshotHotkey": "Screenshot:",
|
||||
"SettingsTabHotkeysShowUiHotkey": "Mostra UI:",
|
||||
"SettingsTabHotkeysPauseHotkey": "Metti in pausa:",
|
||||
"SettingsTabHotkeysToggleMuteHotkey": "Muta:",
|
||||
"ControllerMotionTitle": "Impostazioni dei sensori di movimento",
|
||||
"ControllerRumbleTitle": "Impostazioni di vibrazione",
|
||||
"SettingsSelectThemeFileDialogTitle" : "Seleziona file del tema",
|
||||
"SettingsXamlThemeFile" : "File del tema xaml",
|
||||
"SettingsTabHotkeysResScaleUpHotkey": "Aumentare la risoluzione:",
|
||||
"SettingsTabHotkeysResScaleDownHotkey": "Diminuire la risoluzione:"
|
||||
}
|
@ -1,494 +0,0 @@
|
||||
{
|
||||
"MenuBarFileOpenApplet": "애플릿 열기",
|
||||
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "독립 실행형 모드에서 Mii 편집기 애플릿 열기",
|
||||
"SettingsTabInputDirectMouseAccess": "직접 마우스 액세스",
|
||||
"SettingsTabSystemMemoryManagerMode": "메모리 관리자 모드 :",
|
||||
"SettingsTabSystemMemoryManagerModeSoftware": "소프트웨어",
|
||||
"SettingsTabSystemMemoryManagerModeHost": "호스트 (빠른)",
|
||||
"SettingsTabSystemMemoryManagerModeHostUnchecked": "호스트가 확인되지 않음 (가장 빠르고 안전하지 않은)",
|
||||
"MenuBarFile": "_파일",
|
||||
"MenuBarFileOpenFromFile": "_서류철음에서 애플리케이션 로드",
|
||||
"MenuBarFileOpenUnpacked": "_압축을 푼 게임 로드",
|
||||
"MenuBarFileOpenEmuFolder": "Ryujinx 폴더 열기",
|
||||
"MenuBarFileOpenLogsFolder": "로그 폴더 열기",
|
||||
"MenuBarFileExit": "_그만두",
|
||||
"MenuBarOptions": "옵션",
|
||||
"MenuBarOptionsToggleFullscreen": "전체 화면 전환",
|
||||
"MenuBarOptionsStartGamesInFullscreen": "전체 화면 모드에서 게임 열기",
|
||||
"MenuBarOptionsStopEmulation": "에뮬레이션 중지",
|
||||
"MenuBarOptionsSettings": "_조절",
|
||||
"MenuBarOptionsManageUserProfiles": "사용자 프로필 _관리",
|
||||
"MenuBarActions": "_행위",
|
||||
"MenuBarOptionsSimulateWakeUpMessage": "깨우기 명령어 시뮬레이션",
|
||||
"MenuBarActionsScanAmiibo": "Amiibo 스캔",
|
||||
"MenuBarTools": "_도구",
|
||||
"MenuBarToolsInstallFirmware": "펌웨어 설치",
|
||||
"MenuBarFileToolsInstallFirmwareFromFile": "XCI 또는 ZIP에서 펌웨어 설치",
|
||||
"MenuBarFileToolsInstallFirmwareFromDirectory": "디렉토리에서 펌웨어 설치",
|
||||
"MenuBarHelp": "돕다",
|
||||
"MenuBarHelpCheckForUpdates": "업데이트 확인",
|
||||
"MenuBarHelpAbout": "통지",
|
||||
"MenuSearch": "찾다···",
|
||||
"GameListHeaderFavorite": "즐겨찾기",
|
||||
"GameListHeaderIcon": "상",
|
||||
"GameListHeaderApplication": "이름",
|
||||
"GameListHeaderDeveloper": "개발자",
|
||||
"GameListHeaderVersion": "버전",
|
||||
"GameListHeaderTimePlayed": "플레이 시간",
|
||||
"GameListHeaderLastPlayed": "해본 마지막",
|
||||
"GameListHeaderFileExtension": "파일 확장자",
|
||||
"GameListHeaderFileSize": "파일 크기",
|
||||
"GameListHeaderPath": "파일 경로",
|
||||
"GameListContextMenuOpenUserSaveDirectory": "사용자 저장 폴더 열기",
|
||||
"GameListContextMenuOpenUserSaveDirectoryToolTip": "응용 프로그램의 사용자 저장이 포함된 폴더를 엽니다",
|
||||
"GameListContextMenuOpenUserDeviceDirectory": "사용자 장치 폴더 열기",
|
||||
"GameListContextMenuOpenUserDeviceDirectoryToolTip": "응용 프로그램의 장치 저장이 포함된 폴더를 엽니다",
|
||||
"GameListContextMenuOpenUserBcatDirectory": "사용자의 BCAT 폴더 열기",
|
||||
"GameListContextMenuOpenUserBcatDirectoryToolTip": "응용 프로그램의 BCAT 저장이 포함된 폴더를 엽니다",
|
||||
"GameListContextMenuManageTitleUpdates": "타이틀 업데이트 관리s",
|
||||
"GameListContextMenuManageTitleUpdatesToolTip": "타이틀 업데이트 관리 창 열기",
|
||||
"GameListContextMenuManageDlc": "DLC 관리",
|
||||
"GameListContextMenuManageDlcToolTip": "DLC 관리 창 열기",
|
||||
"GameListContextMenuOpenModsDirectory": "모드 디렉토리 열기",
|
||||
"GameListContextMenuOpenModsDirectoryToolTip": "응용 프로그램의 모드가들 포함된 디렉터리를 엽니다",
|
||||
"GameListContextMenuCacheManagement": "캐시 관리",
|
||||
"GameListContextMenuCacheManagementPurgePptc": "PPTC 캐시 제거",
|
||||
"GameListContextMenuCacheManagementPurgePptcToolTip": "응용 프로그램 PPTC 캐시 삭제",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCache": "셰이더 캐시 제거",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "애플리케이션 셰이더 캐시를 삭제합니다.",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectory": "PPTC 디렉토리 열기",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectoryToolTip": "응용 프로그램 PPTC 캐시가 포함된 디렉터리를 엽니다",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectory": "셰이더 캐시 디렉토리 열기",
|
||||
"GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip": "응용 프로그램 셰이더 캐시가 포함된 디렉터리를 엽니다",
|
||||
"GameListContextMenuExtractData": "데이터 추출",
|
||||
"GameListContextMenuExtractDataExeFS": "ExeFS",
|
||||
"GameListContextMenuExtractDataExeFSToolTip": "애플리케이션의 현재 구성에서 ExeFS 추출 (업데이트 포함)",
|
||||
"GameListContextMenuExtractDataRomFS": "RomFS",
|
||||
"GameListContextMenuExtractDataRomFSToolTip": "애플리케이션의 현재 구성에서 RomFS 추출 (업데이트 포함)",
|
||||
"GameListContextMenuExtractDataLogo": "Logo",
|
||||
"GameListContextMenuExtractDataLogoToolTip": "애플리케이션의 현재 구성에서 로고 섹션 추출 (업데이트 포함)",
|
||||
"StatusBarGamesLoaded": "로드된 {0}/{1}개의 게임",
|
||||
"StatusBarSystemVersion": "시스템 버전 : {0}",
|
||||
"Settings": "조절",
|
||||
"SettingsTabGeneral": "사용자 인터페이스",
|
||||
"SettingsTabGeneralGeneral": "일반",
|
||||
"SettingsTabGeneralEnableDiscordRichPresence": "Discord Rich Presence 활성화",
|
||||
"SettingsTabGeneralCheckUpdatesOnLaunch": "열 때 업데이트 확인",
|
||||
"SettingsTabGeneralShowConfirmExitDialog": "\"종료 확인\" 대화 상자 표시",
|
||||
"SettingsTabGeneralHideCursorOnIdle": "유휴 상태에서 커서 숨기기",
|
||||
"SettingsTabGeneralGameDirectories": "게임 디렉토리들",
|
||||
"SettingsTabGeneralAdd": "추가하다",
|
||||
"SettingsTabGeneralRemove": "제거하다",
|
||||
"SettingsTabSystem": "체계",
|
||||
"SettingsTabSystemCore": "핵심",
|
||||
"SettingsTabSystemSystemRegion": "시스템 영역 :",
|
||||
"SettingsTabSystemSystemRegionJapan": "일본",
|
||||
"SettingsTabSystemSystemRegionUSA": "미국",
|
||||
"SettingsTabSystemSystemRegionEurope": "유럽",
|
||||
"SettingsTabSystemSystemRegionAustralia": "호주",
|
||||
"SettingsTabSystemSystemRegionChina": "중국",
|
||||
"SettingsTabSystemSystemRegionKorea": "한국",
|
||||
"SettingsTabSystemSystemRegionTaiwan": "대만",
|
||||
"SettingsTabSystemSystemLanguage": "시스템 언어 :",
|
||||
"SettingsTabSystemSystemLanguageJapanese": "일본어",
|
||||
"SettingsTabSystemSystemLanguageAmericanEnglish": "영어(미국)",
|
||||
"SettingsTabSystemSystemLanguageFrench": "프랑스어",
|
||||
"SettingsTabSystemSystemLanguageGerman": "독일어",
|
||||
"SettingsTabSystemSystemLanguageItalian": "이탈리아어",
|
||||
"SettingsTabSystemSystemLanguageSpanish": "스페인어",
|
||||
"SettingsTabSystemSystemLanguageChinese": "중국어",
|
||||
"SettingsTabSystemSystemLanguageKorean": "한국어",
|
||||
"SettingsTabSystemSystemLanguageDutch": "네덜란드 어",
|
||||
"SettingsTabSystemSystemLanguagePortuguese": "포르투갈어",
|
||||
"SettingsTabSystemSystemLanguageRussian": "러시아어",
|
||||
"SettingsTabSystemSystemLanguageTaiwanese": "대만어",
|
||||
"SettingsTabSystemSystemLanguageBritishEnglish": "영어(영국)",
|
||||
"SettingsTabSystemSystemLanguageCanadianFrench": "프랑스어(캐나다)",
|
||||
"SettingsTabSystemSystemLanguageLatinAmericanSpanish": "스페인어(라틴 아메리카)",
|
||||
"SettingsTabSystemSystemLanguageSimplifiedChinese": "중국어 간체",
|
||||
"SettingsTabSystemSystemLanguageTraditionalChinese": "중국어 번체",
|
||||
"SettingsTabSystemSystemTimeZone": "시스템 시간대 :",
|
||||
"SettingsTabSystemSystemTime": "시스템 시간 :",
|
||||
"SettingsTabSystemEnableVsync": "수직 동기화 사용",
|
||||
"SettingsTabSystemEnablePptc": "PPTC(Profiled Persistent Translation Cache) 활성화",
|
||||
"SettingsTabSystemEnableFsIntegrityChecks": "FS 무결성 검사 활성화",
|
||||
"SettingsTabSystemAudioBackend": "오디오 백엔드 :",
|
||||
"SettingsTabSystemAudioBackendDummy": "Dummy",
|
||||
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
|
||||
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "해킹",
|
||||
"SettingsTabSystemHacksNote": " (불안정을 일으킬 수 있음)",
|
||||
"SettingsTabSystemExpandDramSize": "DRAM 크기를 6GB로 확장",
|
||||
"SettingsTabSystemIgnoreMissingServices": "누락된 서비스 무시",
|
||||
"SettingsTabGraphics": "제도법",
|
||||
"SettingsTabGraphicsAPI": "그래픽 API",
|
||||
"SettingsTabGraphicsEnableShaderCache": "셰이더 캐시 활성화",
|
||||
"SettingsTabGraphicsAnisotropicFiltering": "이방성 필터링 :",
|
||||
"SettingsTabGraphicsAnisotropicFilteringAuto": "자동적 인",
|
||||
"SettingsTabGraphicsAnisotropicFiltering2x": "2x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering4x": "4x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering8x": "8x",
|
||||
"SettingsTabGraphicsAnisotropicFiltering16x": "16x",
|
||||
"SettingsTabGraphicsResolutionScale": "해상도 스케일 :",
|
||||
"SettingsTabGraphicsResolutionScaleCustom": "사용자 지정(권장하지 않음)",
|
||||
"SettingsTabGraphicsResolutionScaleNative": "기본 (720p/1080p)",
|
||||
"SettingsTabGraphicsResolutionScale2x": "2x (1440p/2160p)",
|
||||
"SettingsTabGraphicsResolutionScale3x": "3x (2160p/3240p)",
|
||||
"SettingsTabGraphicsResolutionScale4x": "4x (2880p/4320p)",
|
||||
"SettingsTabGraphicsAspectRatio": "종횡비 :",
|
||||
"SettingsTabGraphicsAspectRatio4x3": "4:3",
|
||||
"SettingsTabGraphicsAspectRatio16x9": "16:9",
|
||||
"SettingsTabGraphicsAspectRatio16x10": "16:10",
|
||||
"SettingsTabGraphicsAspectRatio21x9": "21:9",
|
||||
"SettingsTabGraphicsAspectRatio32x9": "32:9",
|
||||
"SettingsTabGraphicsAspectRatioStretch": "창에 맞게 늘리기",
|
||||
"SettingsTabGraphicsDeveloperOptions": "개발자 옵션",
|
||||
"SettingsTabGraphicsShaderDumpPath": "그래픽 쉐이더 덤프 경로 :",
|
||||
"SettingsTabLogging": "로깅",
|
||||
"SettingsTabLoggingLogging": "로깅",
|
||||
"SettingsTabLoggingEnableLoggingToFile": "파일에 로깅 활성화",
|
||||
"SettingsTabLoggingEnableStubLogs": "스텁 로그 켜기 ",
|
||||
"SettingsTabLoggingEnableInfoLogs": "정보 로그 켜기",
|
||||
"SettingsTabLoggingEnableWarningLogs": "경고 로그 켜기",
|
||||
"SettingsTabLoggingEnableErrorLogs": "오류 로그 켜기",
|
||||
"SettingsTabLoggingEnableGuestLogs": "게스트 로그 켜기",
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Fs 액세스 로그 켜기",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs 전역 액세스 로그 모드 :",
|
||||
"SettingsTabLoggingDeveloperOptions": "개발자 옵션 (경고 : 성능이 저하됩니다.)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "OpenGL 로그 수준 :",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "없음",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "오류",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "감속",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "모두",
|
||||
"SettingsTabLoggingEnableDebugLogs": "디버그 로그 사용",
|
||||
"SettingsTabInput": "입력",
|
||||
"SettingsTabInputEnableDockedMode": "도킹 모드 활성화",
|
||||
"SettingsTabInputDirectKeyboardAccess": "직접 키보드 액세스",
|
||||
"SettingsButtonSave": "구하다",
|
||||
"SettingsButtonClose": "출구",
|
||||
"SettingsButtonApply": "적용하다",
|
||||
"ControllerSettingsPlayer": "플레이어",
|
||||
"ControllerSettingsPlayer1": "플레이어 1",
|
||||
"ControllerSettingsPlayer2": "플레이어 2",
|
||||
"ControllerSettingsPlayer3": "플레이어 3",
|
||||
"ControllerSettingsPlayer4": "플레이어 4",
|
||||
"ControllerSettingsPlayer5": "플레이어 5",
|
||||
"ControllerSettingsPlayer6": "플레이어 6",
|
||||
"ControllerSettingsPlayer7": "플레이어 7",
|
||||
"ControllerSettingsPlayer8": "플레이어 8",
|
||||
"ControllerSettingsHandheld": "휴대용",
|
||||
"ControllerSettingsInputDevice": "입력 장치",
|
||||
"ControllerSettingsRefresh": "새로 고치다",
|
||||
"ControllerSettingsDeviceDisabled": "장애가있는",
|
||||
"ControllerSettingsControllerType": "컨트롤러 유형",
|
||||
"ControllerSettingsControllerTypeHandheld": "휴대용",
|
||||
"ControllerSettingsControllerTypeProController": "Pro Controller",
|
||||
"ControllerSettingsControllerTypeJoyConPair": "JoyCon 페어",
|
||||
"ControllerSettingsControllerTypeJoyConLeft": "JoyCon 왼쪽",
|
||||
"ControllerSettingsControllerTypeJoyConRight": "JoyCon 오른쪽",
|
||||
"ControllerSettingsProfile": "프로필",
|
||||
"ControllerSettingsProfileDefault": "기본",
|
||||
"ControllerSettingsLoad": "짐",
|
||||
"ControllerSettingsAdd": "추가하다",
|
||||
"ControllerSettingsRemove": "제거하다",
|
||||
"ControllerSettingsButtons": "버튼",
|
||||
"ControllerSettingsButtonA": "A",
|
||||
"ControllerSettingsButtonB": "B",
|
||||
"ControllerSettingsButtonX": "X",
|
||||
"ControllerSettingsButtonY": "Y",
|
||||
"ControllerSettingsButtonPlus": "+",
|
||||
"ControllerSettingsButtonMinus": "-",
|
||||
"ControllerSettingsDPad": "Directional Pad",
|
||||
"ControllerSettingsDPadUp": "위로",
|
||||
"ControllerSettingsDPadDown": "아래에",
|
||||
"ControllerSettingsDPadLeft": "왼쪽",
|
||||
"ControllerSettingsDPadRight": "오른쪽",
|
||||
"ControllerSettingsLStick": "왼쪽 스틱",
|
||||
"ControllerSettingsLStickButton": "단추",
|
||||
"ControllerSettingsLStickUp": "위로",
|
||||
"ControllerSettingsLStickDown": "아래에",
|
||||
"ControllerSettingsLStickLeft": "왼쪽",
|
||||
"ControllerSettingsLStickRight": "오른쪽",
|
||||
"ControllerSettingsLStickStick": "막대",
|
||||
"ControllerSettingsLStickInvertXAxis": "스틱 X축 반전",
|
||||
"ControllerSettingsLStickInvertYAxis": "스틱 Y축 반전",
|
||||
"ControllerSettingsLStickDeadzone": "데드 존 :",
|
||||
"ControllerSettingsRStick": "오른쪽 스틱",
|
||||
"ControllerSettingsRStickButton": "단추",
|
||||
"ControllerSettingsRStickUp": "위로",
|
||||
"ControllerSettingsRStickDown": "아래에",
|
||||
"ControllerSettingsRStickLeft": "왼쪽",
|
||||
"ControllerSettingsRStickRight": "오른쪽",
|
||||
"ControllerSettingsRStickStick": "Stick",
|
||||
"ControllerSettingsRStickInvertXAxis": "스틱 X축 반전",
|
||||
"ControllerSettingsRStickInvertYAxis": "스틱 Y축 반전",
|
||||
"ControllerSettingsRStickDeadzone": "데드 존 :",
|
||||
"ControllerSettingsTriggersLeft": "왼쪽 트리거",
|
||||
"ControllerSettingsTriggersRight": "오른쪽 트리거",
|
||||
"ControllerSettingsTriggersButtonsLeft": "트리거 버튼 왼쪽",
|
||||
"ControllerSettingsTriggersButtonsRight": "트리거 버튼 오른쪽",
|
||||
"ControllerSettingsTriggers": "방아쇠",
|
||||
"ControllerSettingsTriggerL": "L",
|
||||
"ControllerSettingsTriggerR": "R",
|
||||
"ControllerSettingsTriggerZL": "ZL",
|
||||
"ControllerSettingsTriggerZR": "ZR",
|
||||
"ControllerSettingsLeftSL": "SL",
|
||||
"ControllerSettingsLeftSR": "SR",
|
||||
"ControllerSettingsRightSL": "SL",
|
||||
"ControllerSettingsRightSR": "SR",
|
||||
"ControllerSettingsExtraButtonsLeft": "왼쪽 버튼",
|
||||
"ControllerSettingsExtraButtonsRight": "버튼 오른쪽",
|
||||
"ControllerSettingsMisc": "여러 가지 잡다한",
|
||||
"ControllerSettingsTriggerThreshold": "트리거 임계값 :",
|
||||
"ControllerSettingsMotion": "운동",
|
||||
"ControllerSettingsMotionUseCemuhookCompatibleMotion": "CemuHook 호환 모션 사용",
|
||||
"ControllerSettingsMotionControllerSlot": "컨트롤러 슬롯 :",
|
||||
"ControllerSettingsMotionMirrorInput": "미러 입력",
|
||||
"ControllerSettingsMotionRightJoyConSlot": "오른쪽 JoyCon 슬롯 :",
|
||||
"ControllerSettingsMotionServerHost": "서버 호스트 :",
|
||||
"ControllerSettingsMotionGyroSensitivity": "자이로 감도 :",
|
||||
"ControllerSettingsMotionGyroDeadzone": "자이로 데드존 :",
|
||||
"ControllerSettingsSave": "구하다",
|
||||
"ControllerSettingsClose": "출구",
|
||||
"UserProfilesSelectedUserProfile": "선택한 사용자 프로필 :",
|
||||
"UserProfilesSaveProfileName": "프로필 이름 저장",
|
||||
"UserProfilesChangeProfileImage": "프로필 이미지 변경",
|
||||
"UserProfilesAvailableUserProfiles": "사용 가능한 사용자 프로필 :",
|
||||
"UserProfilesAddNewProfile": "새 프로필 추가",
|
||||
"UserProfilesDeleteSelectedProfile": "선택한 프로필 삭제",
|
||||
"UserProfilesClose": "출구",
|
||||
"ProfileImageSelectionTitle": "프로필 이미지 선택",
|
||||
"ProfileImageSelectionHeader": "이미지 선택",
|
||||
"ProfileImageSelectionNote": "사용자 정의 프로필 이미지를 사용하거나 시스템 펌웨어에서 하나를 선택할 수 있습니다",
|
||||
"ProfileImageSelectionImportImage": "이미지 파일 가져오기",
|
||||
"ProfileImageSelectionSelectAvatar": "펌웨어 아바타 선택",
|
||||
"InputDialogTitle": "입력 대화 상자",
|
||||
"InputDialogOk": "확인",
|
||||
"InputDialogCancel": "취소",
|
||||
"InputDialogAddNewProfileTitle": "프로필 이름 선택",
|
||||
"InputDialogAddNewProfileHeader": "프로필 이름을 입력하세요",
|
||||
"InputDialogAddNewProfileSubtext": "최대 길이 : {0})",
|
||||
"AvatarChoose": "선택하다",
|
||||
"AvatarSetBackgroundColor": "배경색 설정",
|
||||
"AvatarClose": "출구",
|
||||
"ControllerSettingsLoadProfileToolTip": "프로필 로드",
|
||||
"ControllerSettingsAddProfileToolTip": "프로필 추가",
|
||||
"ControllerSettingsRemoveProfileToolTip": "프로필 제거",
|
||||
"ControllerSettingsSaveProfileToolTip": "프로필 저장",
|
||||
"MenuBarFileToolsTakeScreenshot": "스크린 샷을 찍다",
|
||||
"MenuBarFileToolsHideUi": "사용자 인터페이스 숨기기",
|
||||
"GameListContextMenuToggleFavorite": "즐겨찾기 설정",
|
||||
"GameListContextMenuToggleFavoriteToolTip": "이 게임이 즐겨찾기인지 여부를 전환합니다",
|
||||
"SettingsTabGeneralTheme": "테마",
|
||||
"SettingsTabGeneralThemeCustomTheme": "사용자 정의 테마 경로",
|
||||
"SettingsTabGeneralThemeBaseStyle": "기본 스타일",
|
||||
"SettingsTabGeneralThemeBaseStyleDark": "어두운",
|
||||
"SettingsTabGeneralThemeBaseStyleLight": "빛",
|
||||
"SettingsTabGeneralThemeEnableCustomTheme": "사용자 정의 테마 활성화",
|
||||
"ButtonBrowse": "검색",
|
||||
"ControllerSettingsConfigureGeneral": "션 구성",
|
||||
"ControllerSettingsRumble": "하인 좌석",
|
||||
"ControllerSettingsRumbleStrongMultiplier": "강력한 럼블 배율기",
|
||||
"ControllerSettingsRumbleWeakMultiplier": "약한 럼블 승수",
|
||||
"DialogMessageSaveNotAvailableMessage": "에 대한 세이브 데이터가 없습니다 {0} [{1:x16}]",
|
||||
"DialogMessageSaveNotAvailableCreateSaveMessage": "이 게임의 세이브 데이터를 생성하시겠습니까?",
|
||||
"DialogConfirmationTitle": "Ryujinx - 확인",
|
||||
"DialogUpdaterTitle": "Ryujinx - 업데이터",
|
||||
"DialogErrorTitle": "Ryujinx - 오류",
|
||||
"DialogWarningTitle": "Ryujinx - 경고",
|
||||
"DialogExitTitle": "Ryujinx - 출구",
|
||||
"DialogErrorMessage": "Ryujinx에 오류가 발생했습니다",
|
||||
"DialogExitMessage": "Ryujinx를 종료하시겠습니까?",
|
||||
"DialogExitSubMessage": "저장하지 않은 모든 데이터는 손실됩니다!",
|
||||
"DialogMessageCreateSaveErrorMessage": "지정된 세이브 데이터를 작성하는 중에 오류가 발생했습니다 : {0}",
|
||||
"DialogMessageFindSaveErrorMessage": "지정된 저장 데이터를 찾는 중에 오류가 발생했습니다 : {0}",
|
||||
"FolderDialogExtractTitle": "추출할 폴더 선택",
|
||||
"DialogNcaExtractionMessage": "{1}에서 섹션 {0} 추출···",
|
||||
"DialogNcaExtractionTitle": "Ryujinx - NCA 섹션 추출기",
|
||||
"DialogNcaExtractionMainNcaNotFoundErrorMessage": "추출 실패. 선택한 파일에 기본 NCA가 없습니다.",
|
||||
"DialogNcaExtractionCheckLogErrorMessage": "추출 실패. 자세한 내용은 로그 파일을 읽으십시오.",
|
||||
"DialogNcaExtractionSuccessMessage": "추출이 성공적으로 완료되었습니다.",
|
||||
"DialogUpdaterConvertFailedMessage": "현재 Ryujinx 버전을 변환하지 못했습니다.",
|
||||
"DialogUpdaterCancelUpdateMessage": "업데이트 취소 중!",
|
||||
"DialogUpdaterAlreadyOnLatestVersionMessage": "이미 최신 버전의 Ryujinx를 사용하고 있습니다!",
|
||||
"DialogUpdaterFailedToGetVersionMessage": "Github 릴리스에서 릴리스 정보를 가져오는 중에 오류가 발생했습니다. 이는 GitHub Actions에서 새 릴리스를 컴파일하는 경우 발생할 수 있습니다. 몇 분 후에 다시 시도하십시오.",
|
||||
"DialogUpdaterConvertFailedGithubMessage": "Github Release에서 받은 Ryujinx 버전을 변환하지 못했습니다.",
|
||||
"DialogUpdaterDownloadingMessage": "업데이트 다운로드 중···",
|
||||
"DialogUpdaterExtractionMessage": "업데이트 추출···",
|
||||
"DialogUpdaterRenamingMessage": "업데이트 이름 바꾸기···",
|
||||
"DialogUpdaterAddingFilesMessage": "새 업데이트 추가···",
|
||||
"DialogUpdaterCompleteMessage": "업데이트 완료!",
|
||||
"DialogUpdaterRestartMessage": "지금 Ryujinx를 다시 시작하시겠습니까?",
|
||||
"DialogUpdaterArchNotSupportedMessage": "지원되는 시스템 아키텍처를 실행하고 있지 않습니다!",
|
||||
"DialogUpdaterArchNotSupportedSubMessage": "(x86 시스템만 지원됩니다!)",
|
||||
"DialogUpdaterNoInternetMessage": "인터넷에 연결되어 있지 않습니다!",
|
||||
"DialogUpdaterNoInternetSubMessage": "인터넷 연결이 작동하는지 확인하십시오!",
|
||||
"DialogUpdaterDirtyBuildMessage": "Ryujinx의 더러운 빌드는 업데이트할 수 없습니다!",
|
||||
"DialogUpdaterDirtyBuildSubMessage": "지원되는 버전을 찾고 있다면 https://ryujinx.org/에서 Ryujinx를 다운로드하십시오.",
|
||||
"DialogRestartRequiredMessage": "재시작 필요",
|
||||
"DialogThemeRestartMessage": "테마가 저장되었습니다. 테마를 적용하려면 다시 시작해야 합니다.",
|
||||
"DialogThemeRestartSubMessage": "다시 시작하시겠습니까?",
|
||||
"DialogFirmwareInstallEmbeddedMessage": "이 게임에 내장된 펌웨어를 설치하시겠습니까? (펌웨어 {0})",
|
||||
"DialogFirmwareInstallEmbeddedSuccessMessage": "설치된 펌웨어를 찾을 수 없지만 Ryujinx는 제공된 게임에서 펌웨어 {0} 설치할 수 있었습니다.\n이제 에뮬레이터가 시작됩니다.",
|
||||
"DialogFirmwareNoFirmwareInstalledMessage": "펌웨어가 설치되지 않았습니다",
|
||||
"DialogFirmwareInstalledMessage": "펌웨어 {0} 설치되었습니다.",
|
||||
"DialogOpenSettingsWindowLabel": "설정 창 열기",
|
||||
"DialogControllerAppletTitle": "컨트롤러 애플릿",
|
||||
"DialogMessageDialogErrorExceptionMessage": "메시지 대화 상자를 표시하는 동안 오류가 발생했습니다 : {0}",
|
||||
"DialogSoftwareKeyboardErrorExceptionMessage": "소프트웨어 키보드를 표시하는 동안 오류가 발생했습니다 : {0}",
|
||||
"DialogErrorAppletErrorExceptionMessage": "ErrorApplet 대화 상자를 표시하는 동안 오류가 발생했습니다 : {0}",
|
||||
"DialogUserErrorDialogMessage": "{0}: {1}",
|
||||
"DialogUserErrorDialogInfoMessage": "\n이 오류를 수정하는 방법에 대한 자세한 내용은 설정 가이드를 따르십시오",
|
||||
"DialogUserErrorDialogTitle": "Ryuijnx의 오류 ({0})",
|
||||
"DialogAmiiboApiTitle": "Amiibo API",
|
||||
"DialogAmiiboApiFailFetchMessage": "API에서 정보를 가져오는 동안 오류가 발생했습니다.",
|
||||
"DialogAmiiboApiConnectErrorMessage": "Amiibo API 서버에 연결할 수 없습니다. 서비스가 다운되었거나 인터넷 연결이 오프라인인지 확인해야 할 수 있습니다.",
|
||||
"DialogProfileInvalidProfileErrorMessage": "프로필 AAA는 현재 입력 구성 시스템과 호환되지 않습니다.",
|
||||
"DialogProfileDefaultProfileOverwriteErrorMessage": "기본 프로필을 덮어쓸 수 없습니다",
|
||||
"DialogProfileDeleteProfileTitle": "프로필 삭제",
|
||||
"DialogProfileDeleteProfileMessage": "이 작업은 되돌릴 수 없습니다. 계속하시겠습니까?",
|
||||
"DialogWarning": "경고",
|
||||
"DialogPPTCDeletionMessage": "{0}에\n\n 대한 PPTC 캐시를 삭제하려고 합니다.\n\n계속하시겠습니까?",
|
||||
"DialogPPTCDeletionErrorMessage": "{0} : {1}에서 PPTC 캐시를 제거하는 동안 오류가 발생했습니다.",
|
||||
"DialogShaderDeletionMessage": "{0}에\n\n 대한 셰이더 캐시를 삭제하려고 합니다.\n\n계속하시겠습니까?",
|
||||
"DialogShaderDeletionErrorMessage": "{0} : {1}에서 셰이더 캐시를 제거하는 동안 오류가 발생했습니다.",
|
||||
"DialogRyujinxErrorMessage": "Ryujinx에 오류가 발생했습니다",
|
||||
"DialogInvalidTitleIdErrorMessage": "UI 오류 : 선택한 게임에 유효한 제목 ID가 없습니다",
|
||||
"DialogFirmwareInstallerFirmwareNotFoundErrorMessage": "{0}에서 유효한 시스템 펌웨어를 찾을 수 없습니다.",
|
||||
"DialogFirmwareInstallerFirmwareInstallTitle": "펌웨어 {0} 설치",
|
||||
"DialogFirmwareInstallerFirmwareInstallMessage": "시스템 버전 {0}가 설치되려고 합니다",
|
||||
"DialogFirmwareInstallerFirmwareInstallSubMessage": "\n\n이것은 현재 설치된 버전 {0}를 대체합니다.",
|
||||
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n계속하시겠습니까?",
|
||||
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "펌웨어 설치···",
|
||||
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "시스템 버전 {0}가 성공적으로 설치되었습니다.",
|
||||
"DialogUserProfileDeletionWarningMessage": "선택한 프로필이 삭제되면 사용 가능한 다른 프로필이 없습니다",
|
||||
"DialogUserProfileDeletionConfirmMessage": "선택한 프로필을 삭제하시겠습니까",
|
||||
"DialogControllerSettingsModifiedConfirmMessage": "현재 컨트롤러 설정이 업데이트되었습니다.",
|
||||
"DialogControllerSettingsModifiedConfirmSubMessage": "저장하시겠습니까?",
|
||||
"DialogDlcLoadNcaErrorMessage": "{0}. 오류 파일 : {1}",
|
||||
"DialogDlcNoDlcErrorMessage": "지정한 파일에 선택한 타이틀의 DLC가 없습니다!",
|
||||
"DialogPerformanceCheckLoggingEnabledMessage": "개발자 전용으로 설계된 디버그 로깅을 활성화했습니다.",
|
||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "최적의 성능을 위해 디버그 로깅을 비활성화하는 것이 좋습니다. 지금 디버그 로깅을 비활성화하시겠습니까?",
|
||||
"DialogPerformanceCheckShaderDumpEnabledMessage": "Y개발자만 사용하도록 설계된 셰이더 덤핑이 활성화되어 있습니다.",
|
||||
"DialogPerformanceCheckShaderDumpEnabledConfirmMessage": "최적의 성능을 위해 셰이더 덤핑을 비활성화하는 것이 좋습니다. 지금 셰이더 덤핑을 비활성화하시겠습니까?",
|
||||
"DialogLoadAppGameAlreadyLoadedMessage": "다른 게임이 이미 로드되었습니다",
|
||||
"DialogLoadAppGameAlreadyLoadedSubMessage": "다른 게임을 시작하기 전에 에뮬레이션을 중지하거나 에뮬레이터를 닫으십시오.",
|
||||
"DialogUpdateAddUpdateErrorMessage": "파일에 선택한 제목에 대한 업데이트가 포함되어 있지 않습니다!",
|
||||
"DialogSettingsBackendThreadingWarningTitle": "경고 - 백엔드 스레딩",
|
||||
"DialogSettingsBackendThreadingWarningMessage": "변경 사항을 완전히 적용하려면 이 옵션을 변경한 후 Ryujinx를 다시 시작해야 합니다. 플랫폼에 따라 Ryujinx를 사용할 때 드라이버 자체의 멀티스레딩을 수동으로 비활성화해야 할 수도 있습니다.",
|
||||
"SettingsTabGraphicsFeaturesOptions": "특징",
|
||||
"SettingsTabGraphicsBackendMultithreading": "그래픽 백엔드 멀티스레딩 :",
|
||||
"CommonAuto": "자동적 인",
|
||||
"CommonOff": "끄다",
|
||||
"CommonOn": "켜짐",
|
||||
"InputDialogYes": "네",
|
||||
"InputDialogNo": "아니",
|
||||
"DialogProfileInvalidProfileNameErrorMessage": "파일 이름에 잘못된 기호가 있습니다. 다시 시도하십시오.",
|
||||
"MenuBarOptionsPauseEmulation": "정지시키다",
|
||||
"MenuBarOptionsResumeEmulation": "재개하다",
|
||||
"AboutUrlTooltipMessage": "기본 브라우저에서 Ryujinx 웹사이트를 열려면 클릭하십시오.",
|
||||
"AboutDisclaimerMessage": "Ryujinx는 Nintendo™와 제휴하지 않으며,\n어떤 식으로든 또는 그 파트너.",
|
||||
"AboutAmiiboDisclaimerMessage": "AmiiboAPI(www.amiiboapi.com) 사용\nAmiibo 에뮬레이션에서.",
|
||||
"AboutPatreonUrlTooltipMessage": "기본 브라우저에서 Ryujinx Patreon 페이지를 열려면 클릭하세요.",
|
||||
"AboutGithubUrlTooltipMessage": "클릭하여 기본 브라우저에서 Ryujinx GitHub 페이지를 엽니다.",
|
||||
"AboutDiscordUrlTooltipMessage": "기본 브라우저에서 Ryujinx Discord 서버 초대를 열려면 클릭하세요.",
|
||||
"AboutTwitterUrlTooltipMessage": "클릭하여 기본 브라우저에서 Ryujinx Twitter 페이지를 엽니다.",
|
||||
"AboutRyujinxAboutTitle": "에 대한 :",
|
||||
"AboutRyujinxAboutContent": "Ryujinx는 Nintendo Switch™용 에뮬레이터입니다.\nPatreon에서 지원해 주세요.\n모든 최신 뉴스는 Twitter 또는 Discord에서 확인하세요.\n기고에 관심이 있는 개발자는 GitHub 또는 Discord에서 자세한 내용을 확인할 수 있습니다.",
|
||||
"AboutRyujinxMaintainersTitle": "유지 관리 :",
|
||||
"AboutRyujinxMaintainersContentTooltipMessage": "기본 브라우저에서 기여자 페이지를 열려면 클릭하십시오.",
|
||||
"AboutRyujinxSupprtersTitle": "Patreon에서 지원 :",
|
||||
"AmiiboSeriesLabel": "Amiibo 시리즈",
|
||||
"AmiiboCharacterLabel": "성격",
|
||||
"AmiiboScanButtonLabel": "스캔",
|
||||
"AmiiboOptionsShowAllLabel": "모든 Amiibo 표시",
|
||||
"AmiiboOptionsUsRandomTagLabel": "해킹: 임의의 태그 UUID 사용",
|
||||
"DlcManagerTableHeadingEnabledLabel": "활성화됨",
|
||||
"DlcManagerTableHeadingTitleIdLabel": "제목 ID",
|
||||
"DlcManagerTableHeadingContainerPathLabel": "컨테이너 경로",
|
||||
"DlcManagerTableHeadingFullPathLabel": "전체 경로",
|
||||
"DlcManagerRemoveAllButton": "모두 제거",
|
||||
"MenuBarOptionsChangeLanguage": "언어 변경",
|
||||
"CommonSort": "정렬",
|
||||
"CommonShowNames": "이름 표시",
|
||||
"CommonFavorite": "가장 좋아하는",
|
||||
"OrderAscending": "오름차순",
|
||||
"OrderDescending": "내림차순",
|
||||
"SettingsTabGraphicsFeatures": "특징ㆍ개선 사항",
|
||||
"ErrorWindowTitle": "오류 창",
|
||||
"ToggleDiscordTooltip": "Discord Rich Presence 활성화 또는 비활성화",
|
||||
"AddGameDirBoxTooltip": "게임 디렉토리를 입력하여 목록에 추가하세요",
|
||||
"AddGameDirTooltip": "목록에 게임 디렉토리 추가",
|
||||
"RemoveGameDirTooltip": "선택한 게임 디렉토리 제거",
|
||||
"CustomThemeCheckTooltip": "GUI에서 사용자 정의 테마 활성화 또는 비활성화",
|
||||
"CustomThemePathTooltip": "사용자 지정 GUI 테마 경로",
|
||||
"CustomThemeBrowseTooltip": "사용자 정의 GUI 테마 찾기",
|
||||
"DockModeToggleTooltip": "도킹 모드 활성화 또는 비활성화",
|
||||
"DirectKeyboardTooltip": "\"직접 키보드 액세스(HID) 지원\" 활성화 또는 비활성화(텍스트 입력 장치로 키보드에 대한 게임 액세스 제공)",
|
||||
"DirectMouseTooltip": "\"직접 마우스 액세스(HID) 지원\" 활성화 또는 비활성화(포인팅 장치로 마우스에 대한 게임 액세스 제공)",
|
||||
"RegionTooltip": "시스템 지역 변경",
|
||||
"LanguageTooltip": "시스템 언어 변경",
|
||||
"TimezoneTooltip": "시스템 시간대 변경",
|
||||
"TimeTooltip": "시스템 시간 변경",
|
||||
"VSyncToggleTooltip": "수직 동기화 활성화 또는 비활성화",
|
||||
"PptcToggleTooltip": "PPTC 활성화 또는 비활성화",
|
||||
"FsIntegrityToggleTooltip": "게임 콘텐츠 파일에 대한 무결성 검사 활성화",
|
||||
"AudioBackendTooltip": "오디오 백엔드 변경",
|
||||
"MemoryManagerTooltip": "게스트 메모리가 매핑되고 액세스되는 방식을 변경합니다. 에뮬레이트된 CPU 성능에 큰 영향을 줍니다.",
|
||||
"MemoryManagerSoftwareTooltip": "주소 변환을 위해 소프트웨어 페이지 테이블을 사용하십시오. 정확도는 가장 높지만 성능은 가장 느립니다.",
|
||||
"MemoryManagerHostTooltip": "호스트 주소 공간에서 메모리를 직접 매핑합니다. 훨씬 더 빠른 JIT 컴파일 및 실행.",
|
||||
"MemoryManagerUnsafeTooltip": "메모리를 직접 매핑하지만 액세스하기 전에 게스트 주소 공간 내의 주소를 마스킹하지 마십시오. 더 빠르지만 안전을 희생해야 합니다. 게스트 응용 프로그램은 Ryujinx의 어디에서나 메모리에 액세스할 수 있으므로 이 모드로 신뢰할 수 있는 프로그램만 실행하십시오.",
|
||||
"DRamTooltip": "에뮬레이트된 시스템의 메모리 양을 4GB에서 6GB로 확장",
|
||||
"IgnoreMissingServicesTooltip": "누락된 서비스 무시 옵션 활성화 또는 비활성화",
|
||||
"GraphicsBackendThreadingTooltip": "그래픽 백엔드 멀티스레딩 활성화",
|
||||
"GalThreadingTooltip": "두 번째 스레드에서 그래픽 백엔드 명령을 실행합니다. 셰이더 컴파일의 런타임 멀티스레딩을 허용하고, 말더듬을 줄이고, 자체 멀티스레딩 지원 없이 드라이버의 성능을 개선합니다. 멀티스레딩이 있는 드라이버에서 약간 다른 최대 성능. 드라이버 내장 멀티스레딩을 올바르게 비활성화하려면 Ryujinx를 다시 시작해야 할 수도 있고 최상의 성능을 얻으려면 수동으로 수행해야 할 수도 있습니다.",
|
||||
"ShaderCacheToggleTooltip": "셰이더 캐시 활성화 또는 비활성화",
|
||||
"ResolutionScaleTooltip": "적용 가능한 렌더 타겟에 적용된 해상도 배율",
|
||||
"ResolutionScaleEntryTooltip": "1.5와 같은 부동 소수점 해상도 스케일. 비적분 스케일은 문제나 충돌을 일으킬 가능성이 더 큽니다.",
|
||||
"AnisotropyTooltip": "이방성 필터링 수준(게임에서 요청한 값을 사용하려면 자동으로 설정)",
|
||||
"AspectRatioTooltip": "렌더러 창에 적용된 종횡비.",
|
||||
"ShaderDumpPathTooltip": "그래픽 셰이더 덤프 경로",
|
||||
"FileLogTooltip": "디스크의 파일에 대한 로깅 활성화 또는 비활성화",
|
||||
"StubLogTooltip": "스텁 로그 메시지 인쇄 활성화",
|
||||
"InfoLogTooltip": "정보 로그 메시지 인쇄 활성화",
|
||||
"WarnLogTooltip": "경고 로그 메시지 인쇄 활성화",
|
||||
"ErrorLogTooltip": "오류 로그 메시지 인쇄 활성화",
|
||||
"GuestLogTooltip": "게스트 로그 메시지 인쇄 활성화",
|
||||
"FileAccessLogTooltip": "파일 액세스 로그 메시지 인쇄 활성화",
|
||||
"FSAccessLogModeTooltip": "콘솔에 대한 FS 액세스 로그 출력을 활성화합니다. 가능한 모드는 0-3입니다",
|
||||
"DeveloperOptionTooltip": "주의해서 사용",
|
||||
"OpenGlLogLevel": "적절한 로그 수준이 활성화되어 있어야 합니다",
|
||||
"DebugLogTooltip": "디버그 로그 메시지 인쇄 활성화",
|
||||
"LoadApplicationFileTooltip": "로드할 Switch 호환 파일을 선택하려면 파일 선택기를 엽니다.",
|
||||
"LoadApplicationFolderTooltip": "파일 선택기를 열어 로드할 Switch 호환 가능하고 압축을 푼 응용 프로그램을 선택합니다",
|
||||
"OpenRyujinxFolderTooltip": "Ryujinx 파일 시스템 폴더 열기",
|
||||
"OpenRyujinxLogsTooltip": "로그가 기록되는 폴더를 엽니다.",
|
||||
"ExitTooltip": "Ryujinx 종료",
|
||||
"OpenSettingsTooltip": "설정 창 열기",
|
||||
"OpenProfileManagerTooltip": "사용자 프로필 관리자 창 열기",
|
||||
"StopEmulationTooltip": "현재 게임의 에뮬레이션을 중지하고 게임 선택으로 돌아가기",
|
||||
"CheckUpdatesTooltip": "Ryujinx 업데이트 확인",
|
||||
"OpenAboutTooltip": "정보 창 열기",
|
||||
"GridSize": "그리드 크기",
|
||||
"GridSizeTooltip": "그리드 항목의 크기 변경",
|
||||
"SettingsTabSystemSystemLanguageBrazilianPortuguese": "포르투갈어(브라질)",
|
||||
"AboutRyujinxContributorsButtonHeader": "모든 기여자 보기",
|
||||
"SettingsTabSystemAudioVolume": "용량 : ",
|
||||
"AudioVolumeTooltip": "오디오 볼륨 변경",
|
||||
"SettingsTabSystemEnableInternetAccess": "게스트 인터넷 액세스 활성화s",
|
||||
"EnableInternetAccessTooltip": "게스트 인터넷 액세스를 활성화합니다. 활성화된 경우 응용 프로그램은 에뮬레이트된 스위치 콘솔이 인터넷에 연결된 것처럼 작동합니다. 경우에 따라 이 옵션이 비활성화된 경우에도 응용 프로그램이 인터넷에 계속 액세스할 수 있습니다",
|
||||
"GameListContextMenuManageCheatToolTip" : "치트 관리",
|
||||
"GameListContextMenuManageCheat" : "치트 관리",
|
||||
"ControllerSettingsStickRange" : "범위:",
|
||||
"DialogStopEmulationTitle" : "Ryujinx - 에뮬레이션 중지",
|
||||
"DialogStopEmulationMessage": "에뮬레이션을 중지하시겠습니까?",
|
||||
"SettingsTabCpu": "CPU",
|
||||
"SettingsTabAudio": "오디오",
|
||||
"SettingsTabNetwork": "회로망",
|
||||
"SettingsTabNetworkConnection" : "네트워크 연결",
|
||||
"SettingsTabCpuCache" : "CPU 캐시",
|
||||
"SettingsTabCpuMemory" : "CPU 메모리",
|
||||
"ControllerMotionTitle": "Motion Control Settings",
|
||||
"ControllerRumbleTitle": "Rumble Settings"
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Ryujinx.Ava.Common.Locale
|
||||
{
|
||||
class LocaleManager : BaseModel
|
||||
{
|
||||
private const string DefaultLanguageCode = "en_US";
|
||||
|
||||
private Dictionary<string, string> _localeStrings;
|
||||
private ConcurrentDictionary<string, object[]> _dynamicValues;
|
||||
|
||||
public static LocaleManager Instance { get; } = new LocaleManager();
|
||||
public Dictionary<string, string> LocaleStrings { get => _localeStrings; set => _localeStrings = value; }
|
||||
|
||||
|
||||
public LocaleManager()
|
||||
{
|
||||
_localeStrings = new Dictionary<string, string>();
|
||||
_dynamicValues = new ConcurrentDictionary<string, object[]>();
|
||||
|
||||
Load();
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
string localeLanguageCode = CultureInfo.CurrentCulture.Name.Replace('-', '_');
|
||||
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ConfigurationState.Instance.Ui.LanguageCode.Value))
|
||||
{
|
||||
localeLanguageCode = ConfigurationState.Instance.Ui.LanguageCode.Value;
|
||||
}
|
||||
}
|
||||
|
||||
// Load english first, if the target language translation is incomplete, we default to english.
|
||||
LoadDefaultLanguage();
|
||||
|
||||
if (localeLanguageCode != DefaultLanguageCode)
|
||||
{
|
||||
LoadLanguage(localeLanguageCode);
|
||||
}
|
||||
}
|
||||
|
||||
public string this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_localeStrings.TryGetValue(key, out string value))
|
||||
{
|
||||
if (_dynamicValues.TryGetValue(key, out var dynamicValue))
|
||||
{
|
||||
return string.Format(value, dynamicValue);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
set
|
||||
{
|
||||
_localeStrings[key] = value;
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateDynamicValue(string key, params object[] values)
|
||||
{
|
||||
_dynamicValues[key] = values;
|
||||
|
||||
OnPropertyChanged("Item");
|
||||
}
|
||||
|
||||
public void LoadDefaultLanguage()
|
||||
{
|
||||
LoadLanguage(DefaultLanguageCode);
|
||||
}
|
||||
|
||||
public void LoadLanguage(string languageCode)
|
||||
{
|
||||
string languageJson = EmbeddedResources.ReadAllText($"Ryujinx.Ava/Assets/Locales/{languageCode}.json");
|
||||
|
||||
if (languageJson == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var strings = JsonSerializer.Deserialize<Dictionary<string, string>>(languageJson);
|
||||
|
||||
foreach (var item in strings)
|
||||
{
|
||||
this[item.Key] = item.Value;
|
||||
}
|
||||
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
ConfigurationState.Instance.Ui.LanguageCode.Value = languageCode;
|
||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Ryujinx.Input;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using MouseButton = Ryujinx.Input.MouseButton;
|
||||
using Size = System.Drawing.Size;
|
||||
|
||||
namespace Ryujinx.Ava.Input
|
||||
{
|
||||
internal class AvaloniaMouseDriver : IGamepadDriver
|
||||
{
|
||||
private Control _widget;
|
||||
private bool _isDisposed;
|
||||
private Size _size;
|
||||
|
||||
public bool[] PressedButtons { get; }
|
||||
|
||||
public Vector2 CurrentPosition { get; private set; }
|
||||
public Vector2 Scroll { get; private set; }
|
||||
|
||||
public AvaloniaMouseDriver(Control parent)
|
||||
{
|
||||
_widget = parent;
|
||||
|
||||
_widget.PointerMoved += Parent_PointerMovedEvent;
|
||||
_widget.PointerPressed += Parent_PointerPressEvent;
|
||||
_widget.PointerReleased += Parent_PointerReleaseEvent;
|
||||
_widget.PointerWheelChanged += Parent_ScrollEvent;
|
||||
|
||||
PressedButtons = new bool[(int)MouseButton.Count];
|
||||
|
||||
_size = new Size((int)parent.Bounds.Width, (int)parent.Bounds.Height);
|
||||
parent.GetObservable(Control.BoundsProperty).Subscribe(Resized);
|
||||
}
|
||||
|
||||
private void Resized(Rect rect)
|
||||
{
|
||||
_size = new Size((int)rect.Width, (int)rect.Height);
|
||||
}
|
||||
|
||||
private void Parent_ScrollEvent(object o, PointerWheelEventArgs args)
|
||||
{
|
||||
Scroll = new Vector2((float)args.Delta.X, (float)args.Delta.Y);
|
||||
}
|
||||
|
||||
private void Parent_PointerReleaseEvent(object o, PointerReleasedEventArgs args)
|
||||
{
|
||||
var pointerProperties = args.GetCurrentPoint(_widget).Properties;
|
||||
PressedButtons[(int)args.InitialPressMouseButton - 1] = false;
|
||||
}
|
||||
|
||||
private void Parent_PointerPressEvent(object o, PointerPressedEventArgs args)
|
||||
{
|
||||
var pointerProperties = args.GetCurrentPoint(_widget).Properties;
|
||||
|
||||
PressedButtons[(int)pointerProperties.PointerUpdateKind] = true;
|
||||
}
|
||||
|
||||
private void Parent_PointerMovedEvent(object o, PointerEventArgs args)
|
||||
{
|
||||
var position = args.GetPosition(_widget);
|
||||
|
||||
CurrentPosition = new Vector2((float)position.X, (float)position.Y);
|
||||
}
|
||||
|
||||
public void SetMousePressed(MouseButton button)
|
||||
{
|
||||
PressedButtons[(int)button] = true;
|
||||
}
|
||||
|
||||
public void SetMouseReleased(MouseButton button)
|
||||
{
|
||||
PressedButtons[(int)button] = false;
|
||||
}
|
||||
|
||||
public void SetPosition(double x, double y)
|
||||
{
|
||||
CurrentPosition = new Vector2((float)x, (float)y);
|
||||
}
|
||||
|
||||
public bool IsButtonPressed(MouseButton button)
|
||||
{
|
||||
return PressedButtons[(int)button];
|
||||
}
|
||||
|
||||
public Size GetClientSize()
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
public string DriverName => "Avalonia";
|
||||
|
||||
public event Action<string> OnGamepadConnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public event Action<string> OnGamepadDisconnected
|
||||
{
|
||||
add { }
|
||||
remove { }
|
||||
}
|
||||
|
||||
public ReadOnlySpan<string> GamepadsIds => new[] { "0" };
|
||||
|
||||
public IGamepad GetGamepad(string id)
|
||||
{
|
||||
return new AvaloniaMouse(this);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isDisposed = true;
|
||||
|
||||
_widget.PointerMoved -= Parent_PointerMovedEvent;
|
||||
_widget.PointerPressed -= Parent_PointerPressEvent;
|
||||
_widget.PointerReleased -= Parent_PointerReleaseEvent;
|
||||
_widget.PointerWheelChanged -= Parent_ScrollEvent;
|
||||
|
||||
_widget = null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,654 +0,0 @@
|
||||
using Avalonia.Threading;
|
||||
using ICSharpCode.SharpZipLib.GZip;
|
||||
using ICSharpCode.SharpZipLib.Tar;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Ryujinx.Ava;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.Controls;
|
||||
using Ryujinx.Ava.Ui.Windows;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Modules
|
||||
{
|
||||
internal static class Updater
|
||||
{
|
||||
private const string GitHubApiURL = "https://api.github.com";
|
||||
internal static bool Running;
|
||||
|
||||
private static readonly string HomeDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
private static readonly string UpdateDir = Path.Combine(Path.GetTempPath(), "Ryujinx", "update");
|
||||
private static readonly string UpdatePublishDir = Path.Combine(UpdateDir, "publish");
|
||||
private static readonly int ConnectionCount = 4;
|
||||
|
||||
private static string _buildVer;
|
||||
private static string _platformExt;
|
||||
private static string _buildUrl;
|
||||
private static long _buildSize;
|
||||
|
||||
private static readonly string[] WindowsDependencyDirs = Array.Empty<string>();
|
||||
|
||||
public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate)
|
||||
{
|
||||
if (Running)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Running = true;
|
||||
mainWindow.CanUpdate = false;
|
||||
|
||||
// Detect current platform
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
_platformExt = "osx_x64.zip";
|
||||
}
|
||||
else if (OperatingSystem.IsWindows())
|
||||
{
|
||||
_platformExt = "win_x64.zip";
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
_platformExt = "linux_x64.tar.gz";
|
||||
}
|
||||
|
||||
Version newVersion;
|
||||
Version currentVersion;
|
||||
|
||||
try
|
||||
{
|
||||
currentVersion = Version.Parse(Program.Version);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, "Failed to convert the current Ryujinx version!");
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterConvertFailedMessage"], LocaleManager.Instance["DialogUpdaterCancelUpdateMessage"]);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Get latest version number from GitHub API
|
||||
try
|
||||
{
|
||||
using (HttpClient jsonClient = ConstructHttpClient())
|
||||
{
|
||||
string buildInfoURL = $"{GitHubApiURL}/repos/{ReleaseInformations.ReleaseChannelOwner}/{ReleaseInformations.ReleaseChannelRepo}/releases/latest";
|
||||
|
||||
string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL);
|
||||
JObject jsonRoot = JObject.Parse(fetchedJson);
|
||||
JToken assets = jsonRoot["assets"];
|
||||
|
||||
_buildVer = (string)jsonRoot["name"];
|
||||
|
||||
foreach (JToken asset in assets)
|
||||
{
|
||||
string assetName = (string)asset["name"];
|
||||
string assetState = (string)asset["state"];
|
||||
string downloadURL = (string)asset["browser_download_url"];
|
||||
|
||||
if (assetName.StartsWith("test-ava-ryujinx") && assetName.EndsWith(_platformExt))
|
||||
{
|
||||
_buildUrl = downloadURL;
|
||||
|
||||
if (assetState != "uploaded")
|
||||
{
|
||||
if (showVersionUpToDate)
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance["DialogUpdaterAlreadyOnLatestVersionMessage"], "");
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If build not done, assume no new update are availaible.
|
||||
if (_buildUrl == null)
|
||||
{
|
||||
if (showVersionUpToDate)
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance["DialogUpdaterAlreadyOnLatestVersionMessage"], "");
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, exception.Message);
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUpdaterFailedToGetVersionMessage"]);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
newVersion = Version.Parse(_buildVer);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, "Failed to convert the received Ryujinx version from Github!");
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterConvertFailedGithubMessage"], LocaleManager.Instance["DialogUpdaterCancelUpdateMessage"]);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (newVersion <= currentVersion)
|
||||
{
|
||||
if (showVersionUpToDate)
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance["DialogUpdaterAlreadyOnLatestVersionMessage"], "");
|
||||
});
|
||||
}
|
||||
|
||||
Running = false;
|
||||
mainWindow.CanUpdate = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch build size information to learn chunk sizes.
|
||||
using (HttpClient buildSizeClient = ConstructHttpClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
buildSizeClient.DefaultRequestHeaders.Add("Range", "bytes=0-0");
|
||||
|
||||
HttpResponseMessage message = await buildSizeClient.GetAsync(new Uri(_buildUrl), HttpCompletionOption.ResponseHeadersRead);
|
||||
|
||||
_buildSize = message.Content.Headers.ContentRange.Length.Value;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, ex.Message);
|
||||
Logger.Warning?.Print(LogClass.Application, "Couldn't determine build size for update, using single-threaded updater");
|
||||
|
||||
_buildSize = -1;
|
||||
}
|
||||
}
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
// Show a message asking the user if they want to update
|
||||
UpdaterWindow updateDialog = new(mainWindow, newVersion, _buildUrl);
|
||||
await updateDialog.ShowDialog(mainWindow);
|
||||
});
|
||||
}
|
||||
|
||||
private static HttpClient ConstructHttpClient()
|
||||
{
|
||||
HttpClient result = new HttpClient();
|
||||
|
||||
// Required by GitHub to interract with APIs.
|
||||
result.DefaultRequestHeaders.Add("User-Agent", "Ryujinx-Updater/1.0.0");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void UpdateRyujinx(UpdaterWindow updateDialog, string downloadUrl)
|
||||
{
|
||||
// Empty update dir, although it shouldn't ever have anything inside it
|
||||
if (Directory.Exists(UpdateDir))
|
||||
{
|
||||
Directory.Delete(UpdateDir, true);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(UpdateDir);
|
||||
|
||||
string updateFile = Path.Combine(UpdateDir, "update.bin");
|
||||
|
||||
// Download the update .zip
|
||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterDownloading"];
|
||||
updateDialog.ProgressBar.Value = 0;
|
||||
updateDialog.ProgressBar.Maximum = 100;
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
if (_buildSize >= 0)
|
||||
{
|
||||
DoUpdateWithMultipleThreads(updateDialog, downloadUrl, updateFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void DoUpdateWithMultipleThreads(UpdaterWindow updateDialog, string downloadUrl, string updateFile)
|
||||
{
|
||||
// Multi-Threaded Updater
|
||||
long chunkSize = _buildSize / ConnectionCount;
|
||||
long remainderChunk = _buildSize % ConnectionCount;
|
||||
|
||||
int completedRequests = 0;
|
||||
int totalProgressPercentage = 0;
|
||||
int[] progressPercentage = new int[ConnectionCount];
|
||||
|
||||
List<byte[]> list = new List<byte[]>(ConnectionCount);
|
||||
List<WebClient> webClients = new List<WebClient>(ConnectionCount);
|
||||
|
||||
for (int i = 0; i < ConnectionCount; i++)
|
||||
{
|
||||
list.Add(Array.Empty<byte>());
|
||||
}
|
||||
|
||||
for (int i = 0; i < ConnectionCount; i++)
|
||||
{
|
||||
#pragma warning disable SYSLIB0014
|
||||
// TODO: WebClient is obsolete and need to be replaced with a more complex logic using HttpClient.
|
||||
using (WebClient client = new WebClient())
|
||||
#pragma warning restore SYSLIB0014
|
||||
{
|
||||
webClients.Add(client);
|
||||
|
||||
if (i == ConnectionCount - 1)
|
||||
{
|
||||
client.Headers.Add("Range", $"bytes={chunkSize * i}-{(chunkSize * (i + 1) - 1) + remainderChunk}");
|
||||
}
|
||||
else
|
||||
{
|
||||
client.Headers.Add("Range", $"bytes={chunkSize * i}-{chunkSize * (i + 1) - 1}");
|
||||
}
|
||||
|
||||
client.DownloadProgressChanged += (_, args) =>
|
||||
{
|
||||
int index = (int)args.UserState;
|
||||
|
||||
Interlocked.Add(ref totalProgressPercentage, -1 * progressPercentage[index]);
|
||||
Interlocked.Exchange(ref progressPercentage[index], args.ProgressPercentage);
|
||||
Interlocked.Add(ref totalProgressPercentage, args.ProgressPercentage);
|
||||
|
||||
updateDialog.ProgressBar.Value = totalProgressPercentage / ConnectionCount;
|
||||
};
|
||||
|
||||
client.DownloadDataCompleted += (_, args) =>
|
||||
{
|
||||
int index = (int)args.UserState;
|
||||
|
||||
if (args.Cancelled)
|
||||
{
|
||||
webClients[index].Dispose();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
list[index] = args.Result;
|
||||
Interlocked.Increment(ref completedRequests);
|
||||
|
||||
if (Interlocked.Equals(completedRequests, ConnectionCount))
|
||||
{
|
||||
byte[] mergedFileBytes = new byte[_buildSize];
|
||||
for (int connectionIndex = 0, destinationOffset = 0; connectionIndex < ConnectionCount; connectionIndex++)
|
||||
{
|
||||
Array.Copy(list[connectionIndex], 0, mergedFileBytes, destinationOffset, list[connectionIndex].Length);
|
||||
destinationOffset += list[connectionIndex].Length;
|
||||
}
|
||||
|
||||
File.WriteAllBytes(updateFile, mergedFileBytes);
|
||||
|
||||
try
|
||||
{
|
||||
InstallUpdate(updateDialog, updateFile);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, e.Message);
|
||||
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
|
||||
|
||||
DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
client.DownloadDataAsync(new Uri(downloadUrl), i);
|
||||
}
|
||||
catch (WebException ex)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, ex.Message);
|
||||
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
|
||||
|
||||
for (int j = 0; j < webClients.Count; j++)
|
||||
{
|
||||
webClients[j].CancelAsync();
|
||||
}
|
||||
|
||||
DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DoUpdateWithSingleThreadWorker(UpdaterWindow updateDialog, string downloadUrl, string updateFile)
|
||||
{
|
||||
using (HttpClient client = new HttpClient())
|
||||
{
|
||||
// We do not want to timeout while downloading
|
||||
client.Timeout = TimeSpan.FromDays(1);
|
||||
|
||||
using (HttpResponseMessage response = client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead).Result)
|
||||
using (Stream remoteFileStream = response.Content.ReadAsStreamAsync().Result)
|
||||
{
|
||||
using (Stream updateFileStream = File.Open(updateFile, FileMode.Create))
|
||||
{
|
||||
long totalBytes = response.Content.Headers.ContentLength.Value;
|
||||
long byteWritten = 0;
|
||||
|
||||
byte[] buffer = new byte[32 * 1024];
|
||||
|
||||
while (true)
|
||||
{
|
||||
int readSize = remoteFileStream.Read(buffer);
|
||||
|
||||
if (readSize == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
byteWritten += readSize;
|
||||
|
||||
updateDialog.ProgressBar.Value = ((double)byteWritten / totalBytes) * 100;
|
||||
updateFileStream.Write(buffer, 0, readSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InstallUpdate(updateDialog, updateFile);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DoUpdateWithSingleThread(UpdaterWindow updateDialog, string downloadUrl, string updateFile)
|
||||
{
|
||||
Thread worker = new Thread(() => DoUpdateWithSingleThreadWorker(updateDialog, downloadUrl, updateFile));
|
||||
worker.Name = "Updater.SingleThreadWorker";
|
||||
worker.Start();
|
||||
}
|
||||
|
||||
[DllImport("libc", SetLastError = true)]
|
||||
private static extern int chmod(string path, uint mode);
|
||||
|
||||
private static void SetUnixPermissions()
|
||||
{
|
||||
string ryuBin = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx");
|
||||
|
||||
if (!OperatingSystem.IsWindows())
|
||||
{
|
||||
chmod(ryuBin, 493);
|
||||
}
|
||||
}
|
||||
|
||||
private static async void InstallUpdate(UpdaterWindow updateDialog, string updateFile)
|
||||
{
|
||||
// Extract Update
|
||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterExtracting"];
|
||||
updateDialog.ProgressBar.Value = 0;
|
||||
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
using (Stream inStream = File.OpenRead(updateFile))
|
||||
using (Stream gzipStream = new GZipInputStream(inStream))
|
||||
using (TarInputStream tarStream = new TarInputStream(gzipStream, Encoding.ASCII))
|
||||
{
|
||||
updateDialog.ProgressBar.Maximum = inStream.Length;
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
TarEntry tarEntry;
|
||||
while ((tarEntry = tarStream.GetNextEntry()) != null)
|
||||
{
|
||||
if (tarEntry.IsDirectory) continue;
|
||||
|
||||
string outPath = Path.Combine(UpdateDir, tarEntry.Name);
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
||||
|
||||
using (FileStream outStream = File.OpenWrite(outPath))
|
||||
{
|
||||
tarStream.CopyEntryContents(outStream);
|
||||
}
|
||||
|
||||
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(tarEntry.ModTime, DateTimeKind.Utc));
|
||||
|
||||
TarEntry entry = tarEntry;
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
updateDialog.ProgressBar.Value += entry.Size;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
updateDialog.ProgressBar.Value = inStream.Length;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (Stream inStream = File.OpenRead(updateFile))
|
||||
using (ZipFile zipFile = new ZipFile(inStream))
|
||||
{
|
||||
updateDialog.ProgressBar.Maximum = zipFile.Count;
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
foreach (ZipEntry zipEntry in zipFile)
|
||||
{
|
||||
if (zipEntry.IsDirectory) continue;
|
||||
|
||||
string outPath = Path.Combine(UpdateDir, zipEntry.Name);
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outPath));
|
||||
|
||||
using (Stream zipStream = zipFile.GetInputStream(zipEntry))
|
||||
using (FileStream outStream = File.OpenWrite(outPath))
|
||||
{
|
||||
zipStream.CopyTo(outStream);
|
||||
}
|
||||
|
||||
File.SetLastWriteTime(outPath, DateTime.SpecifyKind(zipEntry.DateTime, DateTimeKind.Utc));
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
updateDialog.ProgressBar.Value++;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Delete downloaded zip
|
||||
File.Delete(updateFile);
|
||||
|
||||
List<string> allFiles = EnumerateFilesToDelete().ToList();
|
||||
|
||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterRenaming"];
|
||||
updateDialog.ProgressBar.Value = 0;
|
||||
updateDialog.ProgressBar.Maximum = allFiles.Count;
|
||||
|
||||
// Replace old files
|
||||
await Task.Run(() =>
|
||||
{
|
||||
foreach (string file in allFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Move(file, file + ".ryuold");
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
updateDialog.ProgressBar.Value++;
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, string.Format(LocaleManager.Instance["UpdaterRenameFailed"], file));
|
||||
}
|
||||
}
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
updateDialog.MainText.Text = LocaleManager.Instance["UpdaterAddingFiles"];
|
||||
updateDialog.ProgressBar.Value = 0;
|
||||
updateDialog.ProgressBar.Maximum = Directory.GetFiles(UpdatePublishDir, "*", SearchOption.AllDirectories).Length;
|
||||
});
|
||||
|
||||
MoveAllFilesOver(UpdatePublishDir, HomeDir, updateDialog);
|
||||
});
|
||||
|
||||
Directory.Delete(UpdateDir, true);
|
||||
|
||||
SetUnixPermissions();
|
||||
|
||||
updateDialog.MainText.Text = LocaleManager.Instance["DialogUpdaterCompleteMessage"];
|
||||
updateDialog.SecondaryText.Text = LocaleManager.Instance["DialogUpdaterRestartMessage"];
|
||||
|
||||
updateDialog.ProgressBar.IsVisible = false;
|
||||
updateDialog.ButtonBox.IsVisible = true;
|
||||
}
|
||||
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
public static bool CanUpdate(bool showWarnings, StyleableWindow parent)
|
||||
{
|
||||
#if !DISABLE_UPDATER
|
||||
if (RuntimeInformation.OSArchitecture != Architecture.X64)
|
||||
{
|
||||
if (showWarnings)
|
||||
{
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterArchNotSupportedMessage"],
|
||||
LocaleManager.Instance["DialogUpdaterArchNotSupportedSubMessage"]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NetworkInterface.GetIsNetworkAvailable())
|
||||
{
|
||||
if (showWarnings)
|
||||
{
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterNoInternetMessage"],
|
||||
LocaleManager.Instance["DialogUpdaterNoInternetSubMessage"]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Program.Version.Contains("dirty") || !ReleaseInformations.IsValid())
|
||||
{
|
||||
if (showWarnings)
|
||||
{
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterDirtyBuildMessage"],
|
||||
LocaleManager.Instance["DialogUpdaterDirtyBuildSubMessage"]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
if (showWarnings)
|
||||
{
|
||||
if (ReleaseInformations.IsFlatHubBuild())
|
||||
{
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["UpdaterDisabledWarningTitle"], LocaleManager.Instance["DialogUpdaterFlatpakNotSupportedMessage"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["UpdaterDisabledWarningTitle"], LocaleManager.Instance["DialogUpdaterDirtyBuildSubMessage"]);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
|
||||
// NOTE: This method should always reflect the latest build layout.s
|
||||
private static IEnumerable<string> EnumerateFilesToDelete()
|
||||
{
|
||||
var files = Directory.EnumerateFiles(HomeDir); // All files directly in base dir.
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
foreach (string dir in WindowsDependencyDirs)
|
||||
{
|
||||
string dirPath = Path.Combine(HomeDir, dir);
|
||||
if (Directory.Exists(dirPath))
|
||||
{
|
||||
files = files.Concat(Directory.EnumerateFiles(dirPath, "*", SearchOption.AllDirectories));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
private static void MoveAllFilesOver(string root, string dest, UpdaterWindow dialog)
|
||||
{
|
||||
foreach (string directory in Directory.GetDirectories(root))
|
||||
{
|
||||
string dirName = Path.GetFileName(directory);
|
||||
|
||||
if (!Directory.Exists(Path.Combine(dest, dirName)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.Combine(dest, dirName));
|
||||
}
|
||||
|
||||
MoveAllFilesOver(directory, Path.Combine(dest, dirName), dialog);
|
||||
}
|
||||
|
||||
foreach (string file in Directory.GetFiles(root))
|
||||
{
|
||||
File.Move(file, Path.Combine(dest, Path.GetFileName(file)), true);
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
dialog.ProgressBar.Value++;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void CleanupUpdate()
|
||||
{
|
||||
foreach (string file in Directory.GetFiles(HomeDir, "*.ryuold", SearchOption.AllDirectories))
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,312 +0,0 @@
|
||||
using ARMeilleure.Translation.PTC;
|
||||
using Avalonia;
|
||||
using Avalonia.OpenGL;
|
||||
using Avalonia.Rendering;
|
||||
using Avalonia.Threading;
|
||||
using Ryujinx.Ava.Ui.Backend;
|
||||
using Ryujinx.Ava.Ui.Controls;
|
||||
using Ryujinx.Ava.Ui.Windows;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.GraphicsDriver;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.System;
|
||||
using Ryujinx.Common.SystemInfo;
|
||||
using Ryujinx.Graphics.Vulkan;
|
||||
using Ryujinx.Modules;
|
||||
using Ryujinx.Ui.Common;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
public static double WindowScaleFactor { get; set; }
|
||||
public static double ActualScaleFactor { get; set; }
|
||||
public static string Version { get; private set; }
|
||||
public static string ConfigurationPath { get; private set; }
|
||||
public static string CommandLineProfile { get; set; }
|
||||
public static bool PreviewerDetached { get; private set; }
|
||||
|
||||
public static RenderTimer RenderTimer { get; private set; }
|
||||
public static bool UseVulkan { get; private set; }
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern int MessageBoxA(IntPtr hWnd, string text, string caption, uint type);
|
||||
|
||||
private const uint MB_ICONWARNING = 0x30;
|
||||
private const int BaseDpi = 96;
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Version = ReleaseInformations.GetVersion();
|
||||
|
||||
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
|
||||
{
|
||||
MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MB_ICONWARNING);
|
||||
}
|
||||
|
||||
PreviewerDetached = true;
|
||||
|
||||
Initialize(args);
|
||||
|
||||
RenderTimer = new RenderTimer();
|
||||
|
||||
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
||||
|
||||
RenderTimer.Dispose();
|
||||
}
|
||||
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
{
|
||||
return AppBuilder.Configure<App>()
|
||||
.UsePlatformDetect()
|
||||
.With(new X11PlatformOptions
|
||||
{
|
||||
EnableMultiTouch = true,
|
||||
EnableIme = true,
|
||||
UseEGL = false,
|
||||
UseGpu = !UseVulkan,
|
||||
GlProfiles = new List<GlVersion>()
|
||||
{
|
||||
new GlVersion(GlProfileType.OpenGL, 4, 3)
|
||||
}
|
||||
})
|
||||
.With(new Win32PlatformOptions
|
||||
{
|
||||
EnableMultitouch = true,
|
||||
UseWgl = !UseVulkan,
|
||||
WglProfiles = new List<GlVersion>()
|
||||
{
|
||||
new GlVersion(GlProfileType.OpenGL, 4, 3)
|
||||
},
|
||||
AllowEglInitialization = false,
|
||||
CompositionBackdropCornerRadius = 8f,
|
||||
})
|
||||
.UseSkia()
|
||||
.With(new Ui.Vulkan.VulkanOptions()
|
||||
{
|
||||
ApplicationName = "Ryujinx.Graphics.Vulkan",
|
||||
MaxQueueCount = 2,
|
||||
PreferDiscreteGpu = true,
|
||||
PreferredDevice = !PreviewerDetached ? "" : ConfigurationState.Instance.Graphics.PreferredGpu.Value,
|
||||
UseDebug = !PreviewerDetached ? false : ConfigurationState.Instance.Logger.GraphicsDebugLevel.Value != GraphicsDebugLevel.None,
|
||||
})
|
||||
.With(new SkiaOptions()
|
||||
{
|
||||
CustomGpuFactory = UseVulkan ? SkiaGpuFactory.CreateVulkanGpu : null
|
||||
})
|
||||
.AfterSetup(_ =>
|
||||
{
|
||||
AvaloniaLocator.CurrentMutable
|
||||
.Bind<IRenderTimer>().ToConstant(RenderTimer)
|
||||
.Bind<IRenderLoop>().ToConstant(new RenderLoop(RenderTimer, Dispatcher.UIThread));
|
||||
})
|
||||
.LogToTrace();
|
||||
}
|
||||
|
||||
private static void Initialize(string[] args)
|
||||
{
|
||||
// Parse Arguments.
|
||||
string launchPathArg = null;
|
||||
string baseDirPathArg = null;
|
||||
bool startFullscreenArg = false;
|
||||
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
{
|
||||
string arg = args[i];
|
||||
|
||||
if (arg == "-r" || arg == "--root-data-dir")
|
||||
{
|
||||
if (i + 1 >= args.Length)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
baseDirPathArg = args[++i];
|
||||
}
|
||||
else if (arg == "-p" || arg == "--profile")
|
||||
{
|
||||
if (i + 1 >= args.Length)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
CommandLineProfile = args[++i];
|
||||
}
|
||||
else if (arg == "-f" || arg == "--fullscreen")
|
||||
{
|
||||
startFullscreenArg = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
launchPathArg = arg;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete backup files after updating.
|
||||
Task.Run(Updater.CleanupUpdate);
|
||||
|
||||
Console.Title = $"Ryujinx Console {Version}";
|
||||
|
||||
// Hook unhandled exception and process exit events.
|
||||
AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
|
||||
AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit();
|
||||
|
||||
// Setup base data directory.
|
||||
AppDataManager.Initialize(baseDirPathArg);
|
||||
|
||||
// Initialize the configuration.
|
||||
ConfigurationState.Initialize();
|
||||
|
||||
// Initialize the logger system.
|
||||
LoggerModule.Initialize();
|
||||
|
||||
// Initialize Discord integration.
|
||||
DiscordIntegrationModule.Initialize();
|
||||
|
||||
ReloadConfig();
|
||||
|
||||
UseVulkan = PreviewerDetached ? ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.Vulkan : false;
|
||||
|
||||
if (UseVulkan)
|
||||
{
|
||||
if (VulkanRenderer.GetPhysicalDevices().Length == 0)
|
||||
{
|
||||
UseVulkan = false;
|
||||
|
||||
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.OpenGl;
|
||||
|
||||
Logger.Warning?.PrintMsg(LogClass.Application, "A suitable Vulkan physical device is not available. Falling back to OpenGL");
|
||||
}
|
||||
}
|
||||
|
||||
if (UseVulkan)
|
||||
{
|
||||
// With a custom gpu backend, avalonia doesn't enable dpi awareness, so the backend must handle it. This isn't so for the opengl backed,
|
||||
// as that uses avalonia's gpu backend and it's enabled there.
|
||||
ForceDpiAware.Windows();
|
||||
}
|
||||
|
||||
WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor();
|
||||
ActualScaleFactor = ForceDpiAware.GetActualScaleFactor() / BaseDpi;
|
||||
|
||||
// Logging system information.
|
||||
PrintSystemInfo();
|
||||
|
||||
// Enable OGL multithreading on the driver, when available.
|
||||
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
||||
DriverUtilities.ToggleOGLThreading(threadingMode == BackendThreading.Off);
|
||||
|
||||
// Check if keys exists.
|
||||
bool hasSystemProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys"));
|
||||
if (!hasSystemProdKeys)
|
||||
{
|
||||
if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys"))))
|
||||
{
|
||||
MainWindow.ShowKeyErrorOnLoad = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (launchPathArg != null)
|
||||
{
|
||||
MainWindow.DeferLoadApplication(launchPathArg, startFullscreenArg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ReloadConfig()
|
||||
{
|
||||
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json");
|
||||
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json");
|
||||
|
||||
// Now load the configuration as the other subsystems are now registered
|
||||
if (File.Exists(localConfigurationPath))
|
||||
{
|
||||
ConfigurationPath = localConfigurationPath;
|
||||
}
|
||||
else if (File.Exists(appDataConfigurationPath))
|
||||
{
|
||||
ConfigurationPath = appDataConfigurationPath;
|
||||
}
|
||||
|
||||
if (ConfigurationPath == null)
|
||||
{
|
||||
// No configuration, we load the default values and save it to disk
|
||||
ConfigurationPath = appDataConfigurationPath;
|
||||
|
||||
ConfigurationState.Instance.LoadDefault();
|
||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(ConfigurationPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ConfigurationFileFormat.TryLoad(ConfigurationPath, out ConfigurationFileFormat configurationFileFormat))
|
||||
{
|
||||
ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
ConfigurationState.Instance.LoadDefault();
|
||||
|
||||
Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location {ConfigurationPath}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void PrintSystemInfo()
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"Ryujinx Version: {Version}");
|
||||
SystemInfo.Gather().Print();
|
||||
|
||||
var enabledLogs = Logger.GetEnabledLevels();
|
||||
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(enabledLogs.Count == 0 ? "<None>" : string.Join(", ", enabledLogs))}");
|
||||
|
||||
if (AppDataManager.Mode == AppDataManager.LaunchMode.Custom)
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"Launch Mode: Custom Path {AppDataManager.BaseDirPath}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"Launch Mode: {AppDataManager.Mode}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessUnhandledException(Exception ex, bool isTerminating)
|
||||
{
|
||||
Ptc.Close();
|
||||
PtcProfiler.Stop();
|
||||
|
||||
string message = $"Unhandled exception caught: {ex}";
|
||||
|
||||
Logger.Error?.PrintMsg(LogClass.Application, message);
|
||||
|
||||
if (Logger.Error == null)
|
||||
{
|
||||
Logger.Notice.PrintMsg(LogClass.Application, message);
|
||||
}
|
||||
|
||||
if (isTerminating)
|
||||
{
|
||||
Exit();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Exit()
|
||||
{
|
||||
DiscordIntegrationModule.Exit();
|
||||
|
||||
Ptc.Dispose();
|
||||
PtcProfiler.Dispose();
|
||||
|
||||
Logger.Shutdown();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
using Avalonia;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Ryujinx.Ava.Ui.Backend.Interop;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Backend
|
||||
{
|
||||
public abstract class BackendSurface : IDisposable
|
||||
{
|
||||
protected IntPtr Display => _display;
|
||||
|
||||
private IntPtr _display = IntPtr.Zero;
|
||||
|
||||
[DllImport("libX11.so.6")]
|
||||
public static extern IntPtr XOpenDisplay(IntPtr display);
|
||||
|
||||
[DllImport("libX11.so.6")]
|
||||
public static extern int XCloseDisplay(IntPtr display);
|
||||
|
||||
private PixelSize _currentSize;
|
||||
public IntPtr Handle { get; protected set; }
|
||||
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
public BackendSurface(IntPtr handle)
|
||||
{
|
||||
Handle = handle;
|
||||
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
_display = XOpenDisplay(IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
public PixelSize Size
|
||||
{
|
||||
get
|
||||
{
|
||||
PixelSize size = new PixelSize();
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
GetClientRect(Handle, out var rect);
|
||||
size = new PixelSize(rect.right, rect.bottom);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
XWindowAttributes attributes = new XWindowAttributes();
|
||||
XGetWindowAttributes(Display, Handle, ref attributes);
|
||||
|
||||
size = new PixelSize(attributes.width, attributes.height);
|
||||
}
|
||||
|
||||
_currentSize = size;
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
public PixelSize CurrentSize => _currentSize;
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (IsDisposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(BackendSurface));
|
||||
}
|
||||
|
||||
IsDisposed = true;
|
||||
|
||||
if (_display != IntPtr.Zero)
|
||||
{
|
||||
XCloseDisplay(_display);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
using FluentAvalonia.Interop;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Backend
|
||||
{
|
||||
public static class Interop
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct XWindowAttributes
|
||||
{
|
||||
public int x;
|
||||
public int y;
|
||||
public int width;
|
||||
public int height;
|
||||
public int border_width;
|
||||
public int depth;
|
||||
public IntPtr visual;
|
||||
public IntPtr root;
|
||||
public int c_class;
|
||||
public int bit_gravity;
|
||||
public int win_gravity;
|
||||
public int backing_store;
|
||||
public IntPtr backing_planes;
|
||||
public IntPtr backing_pixel;
|
||||
public int save_under;
|
||||
public IntPtr colormap;
|
||||
public int map_installed;
|
||||
public int map_state;
|
||||
public IntPtr all_event_masks;
|
||||
public IntPtr your_event_mask;
|
||||
public IntPtr do_not_propagate_mask;
|
||||
public int override_direct;
|
||||
public IntPtr screen;
|
||||
}
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool GetClientRect(IntPtr hwnd, out RECT lpRect);
|
||||
|
||||
[DllImport("libX11.so.6")]
|
||||
public static extern int XCloseDisplay(IntPtr display);
|
||||
|
||||
[DllImport("libX11.so.6")]
|
||||
public static extern int XGetWindowAttributes(IntPtr display, IntPtr window, ref XWindowAttributes attributes);
|
||||
|
||||
[DllImport("libX11.so.6")]
|
||||
public static extern IntPtr XOpenDisplay(IntPtr display);
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Skia;
|
||||
using Ryujinx.Ava.Ui.Vulkan;
|
||||
using Ryujinx.Ava.Ui.Backend.Vulkan;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Backend
|
||||
{
|
||||
public static class SkiaGpuFactory
|
||||
{
|
||||
public static ISkiaGpu CreateVulkanGpu()
|
||||
{
|
||||
var skiaOptions = AvaloniaLocator.Current.GetService<SkiaOptions>() ?? new SkiaOptions();
|
||||
var platformInterface = AvaloniaLocator.Current.GetService<VulkanPlatformInterface>();
|
||||
|
||||
if (platformInterface == null)
|
||||
{
|
||||
VulkanPlatformInterface.TryInitialize();
|
||||
}
|
||||
|
||||
var gpu = new VulkanSkiaGpu(skiaOptions.MaxGpuResourceSizeBytes);
|
||||
AvaloniaLocator.CurrentMutable.Bind<VulkanSkiaGpu>().ToConstant(gpu);
|
||||
|
||||
return gpu;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
using System;
|
||||
using Silk.NET.Vulkan;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan
|
||||
{
|
||||
public static class ResultExtensions
|
||||
{
|
||||
public static void ThrowOnError(this Result result)
|
||||
{
|
||||
// Only negative result codes are errors.
|
||||
if ((int)result < (int)Result.Success)
|
||||
{
|
||||
throw new Exception($"Unexpected API error \"{result}\".");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,201 +0,0 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Avalonia.Skia;
|
||||
using Ryujinx.Ava.Ui.Vulkan;
|
||||
using Ryujinx.Ava.Ui.Vulkan.Surfaces;
|
||||
using Silk.NET.Vulkan;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Backend.Vulkan
|
||||
{
|
||||
internal class VulkanRenderTarget : ISkiaGpuRenderTarget
|
||||
{
|
||||
public GRContext GrContext { get; private set; }
|
||||
|
||||
private readonly VulkanSurfaceRenderTarget _surface;
|
||||
private readonly VulkanPlatformInterface _vulkanPlatformInterface;
|
||||
private readonly IVulkanPlatformSurface _vulkanPlatformSurface;
|
||||
private GRVkBackendContext _grVkBackend;
|
||||
|
||||
public VulkanRenderTarget(VulkanPlatformInterface vulkanPlatformInterface, IVulkanPlatformSurface vulkanPlatformSurface)
|
||||
{
|
||||
_surface = vulkanPlatformInterface.CreateRenderTarget(vulkanPlatformSurface);
|
||||
_vulkanPlatformInterface = vulkanPlatformInterface;
|
||||
_vulkanPlatformSurface = vulkanPlatformSurface;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
GRVkGetProcedureAddressDelegate getProc = GetVulkanProcAddress;
|
||||
|
||||
_grVkBackend = new GRVkBackendContext()
|
||||
{
|
||||
VkInstance = _surface.Device.Handle,
|
||||
VkPhysicalDevice = _vulkanPlatformInterface.PhysicalDevice.Handle,
|
||||
VkDevice = _surface.Device.Handle,
|
||||
VkQueue = _surface.Device.Queue.Handle,
|
||||
GraphicsQueueIndex = _vulkanPlatformInterface.PhysicalDevice.QueueFamilyIndex,
|
||||
GetProcedureAddress = getProc
|
||||
};
|
||||
|
||||
GrContext = GRContext.CreateVulkan(_grVkBackend);
|
||||
|
||||
var gpu = AvaloniaLocator.Current.GetService<VulkanSkiaGpu>();
|
||||
|
||||
if (gpu.MaxResourceBytes.HasValue)
|
||||
{
|
||||
GrContext.SetResourceCacheLimit(gpu.MaxResourceBytes.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private IntPtr GetVulkanProcAddress(string name, IntPtr instanceHandle, IntPtr deviceHandle)
|
||||
{
|
||||
IntPtr addr;
|
||||
|
||||
if (deviceHandle != IntPtr.Zero)
|
||||
{
|
||||
addr = _vulkanPlatformInterface.Api.GetDeviceProcAddr(new Device(deviceHandle), name);
|
||||
|
||||
if (addr != IntPtr.Zero)
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
|
||||
addr = _vulkanPlatformInterface.Api.GetDeviceProcAddr(new Device(_surface.Device.Handle), name);
|
||||
|
||||
if (addr != IntPtr.Zero)
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
addr = _vulkanPlatformInterface.Api.GetInstanceProcAddr(new Instance(_vulkanPlatformInterface.Instance.Handle), name);
|
||||
|
||||
if (addr == IntPtr.Zero)
|
||||
{
|
||||
addr = _vulkanPlatformInterface.Api.GetInstanceProcAddr(new Instance(instanceHandle), name);
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_grVkBackend.Dispose();
|
||||
GrContext.Dispose();
|
||||
_surface.Dispose();
|
||||
}
|
||||
|
||||
public ISkiaGpuRenderSession BeginRenderingSession()
|
||||
{
|
||||
var session = _surface.BeginDraw(_vulkanPlatformSurface.Scaling);
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
var disp = session.Display;
|
||||
var api = session.Api;
|
||||
|
||||
var size = session.Size;
|
||||
var scaling = session.Scaling;
|
||||
if (size.Width <= 0 || size.Height <= 0 || scaling < 0)
|
||||
{
|
||||
size = new Avalonia.PixelSize(1, 1);
|
||||
scaling = 1;
|
||||
}
|
||||
|
||||
lock (GrContext)
|
||||
{
|
||||
GrContext.ResetContext();
|
||||
|
||||
var image = _surface.GetImage();
|
||||
|
||||
var imageInfo = new GRVkImageInfo()
|
||||
{
|
||||
CurrentQueueFamily = disp.QueueFamilyIndex,
|
||||
Format = (uint)image.Format,
|
||||
Image = image.Handle,
|
||||
ImageLayout = (uint)image.CurrentLayout,
|
||||
ImageTiling = (uint)image.Tiling,
|
||||
ImageUsageFlags = _surface.UsageFlags,
|
||||
LevelCount = _surface.MipLevels,
|
||||
SampleCount = 1,
|
||||
Protected = false,
|
||||
Alloc = new GRVkAlloc()
|
||||
{
|
||||
Memory = image.MemoryHandle,
|
||||
Flags = 0,
|
||||
Offset = 0,
|
||||
Size = _surface.MemorySize
|
||||
}
|
||||
};
|
||||
|
||||
var renderTarget =
|
||||
new GRBackendRenderTarget((int)size.Width, (int)size.Height, 1,
|
||||
imageInfo);
|
||||
var surface = SKSurface.Create(GrContext, renderTarget,
|
||||
GRSurfaceOrigin.TopLeft,
|
||||
_surface.IsRgba ? SKColorType.Rgba8888 : SKColorType.Bgra8888, SKColorSpace.CreateSrgb());
|
||||
|
||||
if (surface == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Surface can't be created with the provided render target");
|
||||
}
|
||||
|
||||
success = true;
|
||||
|
||||
return new VulkanGpuSession(GrContext, renderTarget, surface, session);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
session.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCorrupted { get; }
|
||||
|
||||
internal class VulkanGpuSession : ISkiaGpuRenderSession
|
||||
{
|
||||
private readonly GRBackendRenderTarget _backendRenderTarget;
|
||||
private readonly VulkanSurfaceRenderingSession _vulkanSession;
|
||||
|
||||
public VulkanGpuSession(GRContext grContext,
|
||||
GRBackendRenderTarget backendRenderTarget,
|
||||
SKSurface surface,
|
||||
VulkanSurfaceRenderingSession vulkanSession)
|
||||
{
|
||||
GrContext = grContext;
|
||||
_backendRenderTarget = backendRenderTarget;
|
||||
SkSurface = surface;
|
||||
_vulkanSession = vulkanSession;
|
||||
|
||||
SurfaceOrigin = GRSurfaceOrigin.TopLeft;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (_vulkanSession.Display.Lock)
|
||||
{
|
||||
SkSurface.Canvas.Flush();
|
||||
|
||||
SkSurface.Dispose();
|
||||
_backendRenderTarget.Dispose();
|
||||
GrContext.Flush();
|
||||
|
||||
_vulkanSession.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public GRContext GrContext { get; }
|
||||
public SKSurface SkSurface { get; }
|
||||
public double ScaleFactor => _vulkanSession.Scaling;
|
||||
public GRSurfaceOrigin SurfaceOrigin { get; }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Avalonia;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Skia;
|
||||
using Avalonia.X11;
|
||||
using Ryujinx.Ava.Ui.Vulkan;
|
||||
using Silk.NET.Vulkan;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Backend.Vulkan
|
||||
{
|
||||
public class VulkanSkiaGpu : ISkiaGpu
|
||||
{
|
||||
private readonly VulkanPlatformInterface _vulkan;
|
||||
public long? MaxResourceBytes { get; }
|
||||
|
||||
public VulkanSkiaGpu(long? maxResourceBytes)
|
||||
{
|
||||
_vulkan = AvaloniaLocator.Current.GetService<VulkanPlatformInterface>();
|
||||
MaxResourceBytes = maxResourceBytes;
|
||||
}
|
||||
|
||||
public ISkiaGpuRenderTarget TryCreateRenderTarget(IEnumerable<object> surfaces)
|
||||
{
|
||||
foreach (var surface in surfaces)
|
||||
{
|
||||
VulkanWindowSurface window;
|
||||
|
||||
if (surface is IPlatformHandle handle)
|
||||
{
|
||||
window = new VulkanWindowSurface(handle.Handle);
|
||||
}
|
||||
else if (surface is X11FramebufferSurface x11FramebufferSurface)
|
||||
{
|
||||
// As of Avalonia 0.10.13, an IPlatformHandle isn't passed for linux, so use reflection to otherwise get the window id
|
||||
var xId = (IntPtr)x11FramebufferSurface.GetType().GetField(
|
||||
"_xid",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(x11FramebufferSurface);
|
||||
|
||||
window = new VulkanWindowSurface(xId);
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
VulkanRenderTarget vulkanRenderTarget = new VulkanRenderTarget(_vulkan, window);
|
||||
|
||||
return vulkanRenderTarget;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public ISkiaSurface TryCreateSurface(PixelSize size, ISkiaGpuRenderSession session)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
using Avalonia;
|
||||
using Ryujinx.Ava.Ui.Vulkan;
|
||||
using Ryujinx.Ava.Ui.Vulkan.Surfaces;
|
||||
using Silk.NET.Vulkan;
|
||||
using Silk.NET.Vulkan.Extensions.KHR;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Backend.Vulkan
|
||||
{
|
||||
internal class VulkanWindowSurface : BackendSurface, IVulkanPlatformSurface
|
||||
{
|
||||
public float Scaling => (float)Program.ActualScaleFactor;
|
||||
|
||||
public PixelSize SurfaceSize => Size;
|
||||
|
||||
public VulkanWindowSurface(IntPtr handle) : base(handle)
|
||||
{
|
||||
}
|
||||
|
||||
public unsafe SurfaceKHR CreateSurface(VulkanInstance instance)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
if (instance.Api.TryGetInstanceExtension(new Instance(instance.Handle), out KhrWin32Surface surfaceExtension))
|
||||
{
|
||||
var createInfo = new Win32SurfaceCreateInfoKHR() { Hinstance = 0, Hwnd = Handle, SType = StructureType.Win32SurfaceCreateInfoKhr };
|
||||
|
||||
surfaceExtension.CreateWin32Surface(new Instance(instance.Handle), createInfo, null, out var surface).ThrowOnError();
|
||||
|
||||
return surface;
|
||||
}
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
if (instance.Api.TryGetInstanceExtension(new Instance(instance.Handle), out KhrXlibSurface surfaceExtension))
|
||||
{
|
||||
var createInfo = new XlibSurfaceCreateInfoKHR()
|
||||
{
|
||||
SType = StructureType.XlibSurfaceCreateInfoKhr,
|
||||
Dpy = (nint*)Display,
|
||||
Window = Handle
|
||||
};
|
||||
|
||||
surfaceExtension.CreateXlibSurface(new Instance(instance.Handle), createInfo, null, out var surface).ThrowOnError();
|
||||
|
||||
return surface;
|
||||
}
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException("The current platform does not support surface creation.");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Silk.NET.Vulkan;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan.Surfaces
|
||||
{
|
||||
public interface IVulkanPlatformSurface : IDisposable
|
||||
{
|
||||
float Scaling { get; }
|
||||
PixelSize SurfaceSize { get; }
|
||||
SurfaceKHR CreateSurface(VulkanInstance instance);
|
||||
}
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Ryujinx.Graphics.Vulkan;
|
||||
using Silk.NET.Vulkan;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan.Surfaces
|
||||
{
|
||||
internal class VulkanSurfaceRenderTarget : IDisposable
|
||||
{
|
||||
private readonly VulkanPlatformInterface _platformInterface;
|
||||
private readonly Format _format;
|
||||
|
||||
private VulkanCommandBufferPool.VulkanCommandBuffer _commandBuffer;
|
||||
private VulkanImage Image { get; set; }
|
||||
private object _lock = new object();
|
||||
|
||||
public uint MipLevels => Image.MipLevels;
|
||||
public VulkanDevice Device { get; }
|
||||
|
||||
public VulkanSurfaceRenderTarget(VulkanPlatformInterface platformInterface, VulkanSurface surface)
|
||||
{
|
||||
_platformInterface = platformInterface;
|
||||
|
||||
var device = VulkanInitialization.CreateDevice(platformInterface.Api,
|
||||
platformInterface.PhysicalDevice.InternalHandle,
|
||||
platformInterface.PhysicalDevice.QueueFamilyIndex,
|
||||
VulkanInitialization.GetSupportedExtensions(platformInterface.Api, platformInterface.PhysicalDevice.InternalHandle),
|
||||
platformInterface.PhysicalDevice.QueueCount);
|
||||
|
||||
Device = new VulkanDevice(device, platformInterface.PhysicalDevice, platformInterface.Api);
|
||||
|
||||
Display = VulkanDisplay.CreateDisplay(
|
||||
platformInterface.Instance,
|
||||
Device,
|
||||
platformInterface.PhysicalDevice,
|
||||
surface);
|
||||
Surface = surface;
|
||||
|
||||
// Skia seems to only create surfaces from images with unorm format
|
||||
IsRgba = Display.SurfaceFormat.Format >= Format.R8G8B8A8Unorm &&
|
||||
Display.SurfaceFormat.Format <= Format.R8G8B8A8Srgb;
|
||||
|
||||
_format = IsRgba ? Format.R8G8B8A8Unorm : Format.B8G8R8A8Unorm;
|
||||
}
|
||||
|
||||
public bool IsRgba { get; }
|
||||
|
||||
public uint ImageFormat => (uint)_format;
|
||||
|
||||
public ulong MemorySize => Image.MemorySize;
|
||||
|
||||
public VulkanDisplay Display { get; private set; }
|
||||
|
||||
public VulkanSurface Surface { get; private set; }
|
||||
|
||||
public uint UsageFlags => Image.UsageFlags;
|
||||
|
||||
public PixelSize Size { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
DestroyImage();
|
||||
Display?.Dispose();
|
||||
Surface?.Dispose();
|
||||
Device?.Dispose();
|
||||
|
||||
Display = null;
|
||||
Surface = null;
|
||||
}
|
||||
}
|
||||
|
||||
public VulkanSurfaceRenderingSession BeginDraw(float scaling)
|
||||
{
|
||||
if (Image == null)
|
||||
{
|
||||
RecreateImage();
|
||||
}
|
||||
|
||||
_commandBuffer?.WaitForFence();
|
||||
_commandBuffer = null;
|
||||
|
||||
var session = new VulkanSurfaceRenderingSession(Display, Device, this, scaling);
|
||||
|
||||
Image.TransitionLayout(ImageLayout.ColorAttachmentOptimal, AccessFlags.AccessNoneKhr);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
public void RecreateImage()
|
||||
{
|
||||
DestroyImage();
|
||||
CreateImage();
|
||||
}
|
||||
|
||||
private void CreateImage()
|
||||
{
|
||||
Size = Display.Size;
|
||||
|
||||
Image = new VulkanImage(Device, _platformInterface.PhysicalDevice, Display.CommandBufferPool, ImageFormat, Size);
|
||||
}
|
||||
|
||||
private void DestroyImage()
|
||||
{
|
||||
_commandBuffer?.WaitForFence();
|
||||
_commandBuffer = null;
|
||||
Image?.Dispose();
|
||||
Image = null;
|
||||
}
|
||||
|
||||
public VulkanImage GetImage()
|
||||
{
|
||||
return Image;
|
||||
}
|
||||
|
||||
public void EndDraw()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (Display == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_commandBuffer = Display.StartPresentation();
|
||||
|
||||
Display.BlitImageToCurrentImage(this, _commandBuffer.InternalHandle);
|
||||
|
||||
Display.EndPresentation(_commandBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,215 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Silk.NET.Vulkan;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan
|
||||
{
|
||||
internal class VulkanCommandBufferPool : IDisposable
|
||||
{
|
||||
private readonly VulkanDevice _device;
|
||||
private readonly CommandPool _commandPool;
|
||||
|
||||
private readonly List<VulkanCommandBuffer> _usedCommandBuffers = new();
|
||||
private readonly object _lock = new object();
|
||||
|
||||
public unsafe VulkanCommandBufferPool(VulkanDevice device, VulkanPhysicalDevice physicalDevice)
|
||||
{
|
||||
_device = device;
|
||||
|
||||
var commandPoolCreateInfo = new CommandPoolCreateInfo
|
||||
{
|
||||
SType = StructureType.CommandPoolCreateInfo,
|
||||
Flags = CommandPoolCreateFlags.CommandPoolCreateResetCommandBufferBit,
|
||||
QueueFamilyIndex = physicalDevice.QueueFamilyIndex
|
||||
};
|
||||
|
||||
device.Api.CreateCommandPool(_device.InternalHandle, commandPoolCreateInfo, null, out _commandPool)
|
||||
.ThrowOnError();
|
||||
}
|
||||
|
||||
private CommandBuffer AllocateCommandBuffer()
|
||||
{
|
||||
var commandBufferAllocateInfo = new CommandBufferAllocateInfo
|
||||
{
|
||||
SType = StructureType.CommandBufferAllocateInfo,
|
||||
CommandPool = _commandPool,
|
||||
CommandBufferCount = 1,
|
||||
Level = CommandBufferLevel.Primary
|
||||
};
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_device.Api.AllocateCommandBuffers(_device.InternalHandle, commandBufferAllocateInfo, out var commandBuffer);
|
||||
|
||||
return commandBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
public VulkanCommandBuffer CreateCommandBuffer()
|
||||
{
|
||||
return new(_device, this);
|
||||
}
|
||||
|
||||
public void FreeUsedCommandBuffers()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var usedCommandBuffer in _usedCommandBuffers)
|
||||
{
|
||||
usedCommandBuffer.Dispose();
|
||||
}
|
||||
|
||||
_usedCommandBuffers.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void DisposeCommandBuffer(VulkanCommandBuffer commandBuffer)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_usedCommandBuffers.Add(commandBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
FreeUsedCommandBuffers();
|
||||
_device.Api.DestroyCommandPool(_device.InternalHandle, _commandPool, Span<AllocationCallbacks>.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public class VulkanCommandBuffer : IDisposable
|
||||
{
|
||||
private readonly VulkanCommandBufferPool _commandBufferPool;
|
||||
private readonly VulkanDevice _device;
|
||||
private readonly Fence _fence;
|
||||
private bool _hasEnded;
|
||||
private bool _hasStarted;
|
||||
private bool _isDisposed;
|
||||
private object _lock = new object();
|
||||
|
||||
public IntPtr Handle => InternalHandle.Handle;
|
||||
|
||||
internal CommandBuffer InternalHandle { get; }
|
||||
|
||||
internal unsafe VulkanCommandBuffer(VulkanDevice device, VulkanCommandBufferPool commandBufferPool)
|
||||
{
|
||||
_device = device;
|
||||
_commandBufferPool = commandBufferPool;
|
||||
|
||||
InternalHandle = _commandBufferPool.AllocateCommandBuffer();
|
||||
|
||||
var fenceCreateInfo = new FenceCreateInfo()
|
||||
{
|
||||
SType = StructureType.FenceCreateInfo,
|
||||
Flags = FenceCreateFlags.FenceCreateSignaledBit
|
||||
};
|
||||
|
||||
device.Api.CreateFence(device.InternalHandle, fenceCreateInfo, null, out _fence);
|
||||
}
|
||||
|
||||
public void WaitForFence()
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
_device.Api.WaitForFences(_device.InternalHandle, 1, _fence, true, ulong.MaxValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void BeginRecording()
|
||||
{
|
||||
if (!_hasStarted)
|
||||
{
|
||||
_hasStarted = true;
|
||||
|
||||
var beginInfo = new CommandBufferBeginInfo
|
||||
{
|
||||
SType = StructureType.CommandBufferBeginInfo,
|
||||
Flags = CommandBufferUsageFlags.CommandBufferUsageOneTimeSubmitBit
|
||||
};
|
||||
|
||||
_device.Api.BeginCommandBuffer(InternalHandle, beginInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public void EndRecording()
|
||||
{
|
||||
if (_hasStarted && !_hasEnded)
|
||||
{
|
||||
_hasEnded = true;
|
||||
|
||||
_device.Api.EndCommandBuffer(InternalHandle);
|
||||
}
|
||||
}
|
||||
|
||||
public void Submit()
|
||||
{
|
||||
Submit(null, null, null, _fence);
|
||||
}
|
||||
|
||||
public unsafe void Submit(
|
||||
ReadOnlySpan<Semaphore> waitSemaphores,
|
||||
ReadOnlySpan<PipelineStageFlags> waitDstStageMask,
|
||||
ReadOnlySpan<Semaphore> signalSemaphores,
|
||||
Fence? fence = null)
|
||||
{
|
||||
EndRecording();
|
||||
|
||||
if (!fence.HasValue)
|
||||
{
|
||||
fence = _fence;
|
||||
}
|
||||
|
||||
fixed (Semaphore* pWaitSemaphores = waitSemaphores, pSignalSemaphores = signalSemaphores)
|
||||
{
|
||||
fixed (PipelineStageFlags* pWaitDstStageMask = waitDstStageMask)
|
||||
{
|
||||
var commandBuffer = InternalHandle;
|
||||
var submitInfo = new SubmitInfo
|
||||
{
|
||||
SType = StructureType.SubmitInfo,
|
||||
WaitSemaphoreCount = waitSemaphores != null ? (uint)waitSemaphores.Length : 0,
|
||||
PWaitSemaphores = pWaitSemaphores,
|
||||
PWaitDstStageMask = pWaitDstStageMask,
|
||||
CommandBufferCount = 1,
|
||||
PCommandBuffers = &commandBuffer,
|
||||
SignalSemaphoreCount = signalSemaphores != null ? (uint)signalSemaphores.Length : 0,
|
||||
PSignalSemaphores = pSignalSemaphores,
|
||||
};
|
||||
|
||||
_device.Api.ResetFences(_device.InternalHandle, 1, fence.Value);
|
||||
|
||||
_device.Submit(submitInfo, fence.Value);
|
||||
}
|
||||
}
|
||||
|
||||
_commandBufferPool.DisposeCommandBuffer(this);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
_isDisposed = true;
|
||||
|
||||
_device.Api.WaitForFences(_device.InternalHandle, 1, _fence, true, ulong.MaxValue);
|
||||
_device.Api.FreeCommandBuffers(_device.InternalHandle, _commandBufferPool._commandPool, 1, InternalHandle);
|
||||
_device.Api.DestroyFence(_device.InternalHandle, _fence, Span<AllocationCallbacks>.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
using System;
|
||||
using Silk.NET.Vulkan;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan
|
||||
{
|
||||
internal class VulkanDevice : IDisposable
|
||||
{
|
||||
private static object _lock = new object();
|
||||
|
||||
public VulkanDevice(Device apiHandle, VulkanPhysicalDevice physicalDevice, Vk api)
|
||||
{
|
||||
InternalHandle = apiHandle;
|
||||
Api = api;
|
||||
|
||||
api.GetDeviceQueue(apiHandle, physicalDevice.QueueFamilyIndex, 0, out var queue);
|
||||
|
||||
Queue = new VulkanQueue(this, queue);
|
||||
|
||||
PresentQueue = Queue;
|
||||
}
|
||||
|
||||
public IntPtr Handle => InternalHandle.Handle;
|
||||
|
||||
internal Device InternalHandle { get; }
|
||||
public Vk Api { get; }
|
||||
|
||||
public VulkanQueue Queue { get; private set; }
|
||||
public VulkanQueue PresentQueue { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
WaitIdle();
|
||||
Queue = null;
|
||||
Api.DestroyDevice(InternalHandle, Span<AllocationCallbacks>.Empty);
|
||||
}
|
||||
|
||||
internal void Submit(SubmitInfo submitInfo, Fence fence = default)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
Api.QueueSubmit(Queue.InternalHandle, 1, submitInfo, fence).ThrowOnError();
|
||||
}
|
||||
}
|
||||
|
||||
public void WaitIdle()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
Api.DeviceWaitIdle(InternalHandle);
|
||||
}
|
||||
}
|
||||
|
||||
public void QueueWaitIdle()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
Api.QueueWaitIdle(Queue.InternalHandle);
|
||||
}
|
||||
}
|
||||
|
||||
public object Lock => _lock;
|
||||
}
|
||||
}
|
@ -1,456 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Avalonia;
|
||||
using Ryujinx.Ava.Ui.Vulkan.Surfaces;
|
||||
using Silk.NET.Vulkan;
|
||||
using Silk.NET.Vulkan.Extensions.KHR;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan
|
||||
{
|
||||
internal class VulkanDisplay : IDisposable
|
||||
{
|
||||
private static KhrSwapchain _swapchainExtension;
|
||||
private readonly VulkanInstance _instance;
|
||||
private readonly VulkanPhysicalDevice _physicalDevice;
|
||||
private readonly VulkanSemaphorePair _semaphorePair;
|
||||
private readonly VulkanDevice _device;
|
||||
private uint _nextImage;
|
||||
private readonly VulkanSurface _surface;
|
||||
private SurfaceFormatKHR _surfaceFormat;
|
||||
private SwapchainKHR _swapchain;
|
||||
private Extent2D _swapchainExtent;
|
||||
private Image[] _swapchainImages;
|
||||
private ImageView[] _swapchainImageViews = Array.Empty<ImageView>();
|
||||
private bool _vsyncStateChanged;
|
||||
private bool _vsyncEnabled;
|
||||
private bool _surfaceChanged;
|
||||
|
||||
public event EventHandler Presented;
|
||||
|
||||
public VulkanCommandBufferPool CommandBufferPool { get; set; }
|
||||
|
||||
public object Lock => _device.Lock;
|
||||
|
||||
private VulkanDisplay(VulkanInstance instance, VulkanDevice device,
|
||||
VulkanPhysicalDevice physicalDevice, VulkanSurface surface, SwapchainKHR swapchain,
|
||||
Extent2D swapchainExtent)
|
||||
{
|
||||
_instance = instance;
|
||||
_device = device;
|
||||
_physicalDevice = physicalDevice;
|
||||
_swapchain = swapchain;
|
||||
_swapchainExtent = swapchainExtent;
|
||||
_surface = surface;
|
||||
|
||||
CreateSwapchainImages();
|
||||
|
||||
_semaphorePair = new VulkanSemaphorePair(_device);
|
||||
|
||||
CommandBufferPool = new VulkanCommandBufferPool(device, physicalDevice);
|
||||
}
|
||||
|
||||
public PixelSize Size { get; private set; }
|
||||
public uint QueueFamilyIndex => _physicalDevice.QueueFamilyIndex;
|
||||
|
||||
internal SurfaceFormatKHR SurfaceFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_surfaceFormat.Format == Format.Undefined)
|
||||
{
|
||||
_surfaceFormat = _surface.GetSurfaceFormat(_physicalDevice);
|
||||
}
|
||||
|
||||
return _surfaceFormat;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_device.WaitIdle();
|
||||
_semaphorePair?.Dispose();
|
||||
DestroyCurrentImageViews();
|
||||
_swapchainExtension.DestroySwapchain(_device.InternalHandle, _swapchain, Span<AllocationCallbacks>.Empty);
|
||||
CommandBufferPool.Dispose();
|
||||
}
|
||||
|
||||
public bool IsSurfaceChanged()
|
||||
{
|
||||
var changed = _surfaceChanged;
|
||||
_surfaceChanged = false;
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static unsafe SwapchainKHR CreateSwapchain(VulkanInstance instance, VulkanDevice device,
|
||||
VulkanPhysicalDevice physicalDevice, VulkanSurface surface, out Extent2D swapchainExtent,
|
||||
SwapchainKHR? oldswapchain = null, bool vsyncEnabled = true)
|
||||
{
|
||||
if (_swapchainExtension == null)
|
||||
{
|
||||
instance.Api.TryGetDeviceExtension(instance.InternalHandle, device.InternalHandle, out _swapchainExtension);
|
||||
}
|
||||
|
||||
while (!surface.CanSurfacePresent(physicalDevice))
|
||||
{
|
||||
Thread.Sleep(16);
|
||||
}
|
||||
|
||||
VulkanSurface.SurfaceExtension.GetPhysicalDeviceSurfaceCapabilities(physicalDevice.InternalHandle,
|
||||
surface.ApiHandle, out var capabilities);
|
||||
|
||||
var imageCount = capabilities.MinImageCount + 1;
|
||||
if (capabilities.MaxImageCount > 0 && imageCount > capabilities.MaxImageCount)
|
||||
{
|
||||
imageCount = capabilities.MaxImageCount;
|
||||
}
|
||||
|
||||
var surfaceFormat = surface.GetSurfaceFormat(physicalDevice);
|
||||
|
||||
bool supportsIdentityTransform = capabilities.SupportedTransforms.HasFlag(SurfaceTransformFlagsKHR.SurfaceTransformIdentityBitKhr);
|
||||
bool isRotated = capabilities.CurrentTransform.HasFlag(SurfaceTransformFlagsKHR.SurfaceTransformRotate90BitKhr) ||
|
||||
capabilities.CurrentTransform.HasFlag(SurfaceTransformFlagsKHR.SurfaceTransformRotate270BitKhr);
|
||||
|
||||
swapchainExtent = GetSwapchainExtent(surface, capabilities);
|
||||
|
||||
CompositeAlphaFlagsKHR compositeAlphaFlags = GetSuitableCompositeAlphaFlags(capabilities);
|
||||
|
||||
PresentModeKHR presentMode = GetSuitablePresentMode(physicalDevice, surface, vsyncEnabled);
|
||||
|
||||
var swapchainCreateInfo = new SwapchainCreateInfoKHR
|
||||
{
|
||||
SType = StructureType.SwapchainCreateInfoKhr,
|
||||
Surface = surface.ApiHandle,
|
||||
MinImageCount = imageCount,
|
||||
ImageFormat = surfaceFormat.Format,
|
||||
ImageColorSpace = surfaceFormat.ColorSpace,
|
||||
ImageExtent = swapchainExtent,
|
||||
ImageUsage =
|
||||
ImageUsageFlags.ImageUsageColorAttachmentBit | ImageUsageFlags.ImageUsageTransferDstBit,
|
||||
ImageSharingMode = SharingMode.Exclusive,
|
||||
ImageArrayLayers = 1,
|
||||
PreTransform = supportsIdentityTransform && isRotated ?
|
||||
SurfaceTransformFlagsKHR.SurfaceTransformIdentityBitKhr :
|
||||
capabilities.CurrentTransform,
|
||||
CompositeAlpha = compositeAlphaFlags,
|
||||
PresentMode = presentMode,
|
||||
Clipped = true,
|
||||
OldSwapchain = oldswapchain ?? new SwapchainKHR()
|
||||
};
|
||||
|
||||
_swapchainExtension.CreateSwapchain(device.InternalHandle, swapchainCreateInfo, null, out var swapchain)
|
||||
.ThrowOnError();
|
||||
|
||||
if (oldswapchain != null)
|
||||
{
|
||||
_swapchainExtension.DestroySwapchain(device.InternalHandle, oldswapchain.Value, null);
|
||||
}
|
||||
|
||||
return swapchain;
|
||||
}
|
||||
|
||||
private static unsafe Extent2D GetSwapchainExtent(VulkanSurface surface, SurfaceCapabilitiesKHR capabilities)
|
||||
{
|
||||
Extent2D swapchainExtent;
|
||||
if (capabilities.CurrentExtent.Width != uint.MaxValue)
|
||||
{
|
||||
swapchainExtent = capabilities.CurrentExtent;
|
||||
}
|
||||
else
|
||||
{
|
||||
var surfaceSize = surface.SurfaceSize;
|
||||
|
||||
var width = Math.Clamp((uint)surfaceSize.Width, capabilities.MinImageExtent.Width, capabilities.MaxImageExtent.Width);
|
||||
var height = Math.Clamp((uint)surfaceSize.Height, capabilities.MinImageExtent.Height, capabilities.MaxImageExtent.Height);
|
||||
|
||||
swapchainExtent = new Extent2D(width, height);
|
||||
}
|
||||
|
||||
return swapchainExtent;
|
||||
}
|
||||
|
||||
private static unsafe CompositeAlphaFlagsKHR GetSuitableCompositeAlphaFlags(SurfaceCapabilitiesKHR capabilities)
|
||||
{
|
||||
var compositeAlphaFlags = CompositeAlphaFlagsKHR.CompositeAlphaOpaqueBitKhr;
|
||||
|
||||
if (capabilities.SupportedCompositeAlpha.HasFlag(CompositeAlphaFlagsKHR.CompositeAlphaPostMultipliedBitKhr))
|
||||
{
|
||||
compositeAlphaFlags = CompositeAlphaFlagsKHR.CompositeAlphaPostMultipliedBitKhr;
|
||||
}
|
||||
else if (capabilities.SupportedCompositeAlpha.HasFlag(CompositeAlphaFlagsKHR.CompositeAlphaPreMultipliedBitKhr))
|
||||
{
|
||||
compositeAlphaFlags = CompositeAlphaFlagsKHR.CompositeAlphaPreMultipliedBitKhr;
|
||||
}
|
||||
|
||||
return compositeAlphaFlags;
|
||||
}
|
||||
|
||||
private static unsafe PresentModeKHR GetSuitablePresentMode(VulkanPhysicalDevice physicalDevice, VulkanSurface surface, bool vsyncEnabled)
|
||||
{
|
||||
uint presentModesCount;
|
||||
|
||||
VulkanSurface.SurfaceExtension.GetPhysicalDeviceSurfacePresentModes(physicalDevice.InternalHandle,
|
||||
surface.ApiHandle,
|
||||
&presentModesCount, null);
|
||||
|
||||
var presentModes = new PresentModeKHR[presentModesCount];
|
||||
|
||||
fixed (PresentModeKHR* pPresentModes = presentModes)
|
||||
{
|
||||
VulkanSurface.SurfaceExtension.GetPhysicalDeviceSurfacePresentModes(physicalDevice.InternalHandle,
|
||||
surface.ApiHandle, &presentModesCount, pPresentModes);
|
||||
}
|
||||
|
||||
var modes = presentModes.ToList();
|
||||
|
||||
if (!vsyncEnabled && modes.Contains(PresentModeKHR.PresentModeImmediateKhr))
|
||||
{
|
||||
return PresentModeKHR.PresentModeImmediateKhr;
|
||||
}
|
||||
else if (modes.Contains(PresentModeKHR.PresentModeMailboxKhr))
|
||||
{
|
||||
return PresentModeKHR.PresentModeMailboxKhr;
|
||||
}
|
||||
else if (modes.Contains(PresentModeKHR.PresentModeFifoKhr))
|
||||
{
|
||||
return PresentModeKHR.PresentModeFifoKhr;
|
||||
}
|
||||
else
|
||||
{
|
||||
return PresentModeKHR.PresentModeImmediateKhr;
|
||||
}
|
||||
}
|
||||
|
||||
internal static VulkanDisplay CreateDisplay(VulkanInstance instance, VulkanDevice device,
|
||||
VulkanPhysicalDevice physicalDevice, VulkanSurface surface)
|
||||
{
|
||||
var swapchain = CreateSwapchain(instance, device, physicalDevice, surface, out var extent, null, true);
|
||||
|
||||
return new VulkanDisplay(instance, device, physicalDevice, surface, swapchain, extent);
|
||||
}
|
||||
|
||||
private unsafe void CreateSwapchainImages()
|
||||
{
|
||||
DestroyCurrentImageViews();
|
||||
|
||||
Size = new PixelSize((int)_swapchainExtent.Width, (int)_swapchainExtent.Height);
|
||||
|
||||
uint imageCount = 0;
|
||||
|
||||
_swapchainExtension.GetSwapchainImages(_device.InternalHandle, _swapchain, &imageCount, null);
|
||||
|
||||
_swapchainImages = new Image[imageCount];
|
||||
|
||||
fixed (Image* pSwapchainImages = _swapchainImages)
|
||||
{
|
||||
_swapchainExtension.GetSwapchainImages(_device.InternalHandle, _swapchain, &imageCount, pSwapchainImages);
|
||||
}
|
||||
|
||||
_swapchainImageViews = new ImageView[imageCount];
|
||||
|
||||
var surfaceFormat = SurfaceFormat;
|
||||
|
||||
for (var i = 0; i < imageCount; i++)
|
||||
{
|
||||
_swapchainImageViews[i] = CreateSwapchainImageView(_swapchainImages[i], surfaceFormat.Format);
|
||||
}
|
||||
}
|
||||
|
||||
private void DestroyCurrentImageViews()
|
||||
{
|
||||
for (var i = 0; i < _swapchainImageViews.Length; i++)
|
||||
{
|
||||
_instance.Api.DestroyImageView(_device.InternalHandle, _swapchainImageViews[i], Span<AllocationCallbacks>.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
internal void ChangeVSyncMode(bool vsyncEnabled)
|
||||
{
|
||||
_vsyncStateChanged = true;
|
||||
_vsyncEnabled = vsyncEnabled;
|
||||
}
|
||||
|
||||
private void Recreate()
|
||||
{
|
||||
_device.WaitIdle();
|
||||
_swapchain = CreateSwapchain(_instance, _device, _physicalDevice, _surface, out _swapchainExtent, _swapchain, _vsyncEnabled);
|
||||
|
||||
CreateSwapchainImages();
|
||||
|
||||
_surfaceChanged = true;
|
||||
}
|
||||
|
||||
private unsafe ImageView CreateSwapchainImageView(Image swapchainImage, Format format)
|
||||
{
|
||||
var componentMapping = new ComponentMapping(
|
||||
ComponentSwizzle.Identity,
|
||||
ComponentSwizzle.Identity,
|
||||
ComponentSwizzle.Identity,
|
||||
ComponentSwizzle.Identity);
|
||||
|
||||
var subresourceRange = new ImageSubresourceRange(ImageAspectFlags.ImageAspectColorBit, 0, 1, 0, 1);
|
||||
|
||||
var imageCreateInfo = new ImageViewCreateInfo
|
||||
{
|
||||
SType = StructureType.ImageViewCreateInfo,
|
||||
Image = swapchainImage,
|
||||
ViewType = ImageViewType.ImageViewType2D,
|
||||
Format = format,
|
||||
Components = componentMapping,
|
||||
SubresourceRange = subresourceRange
|
||||
};
|
||||
|
||||
_instance.Api.CreateImageView(_device.InternalHandle, imageCreateInfo, null, out var imageView).ThrowOnError();
|
||||
return imageView;
|
||||
}
|
||||
|
||||
public bool EnsureSwapchainAvailable()
|
||||
{
|
||||
if (Size != _surface.SurfaceSize || _vsyncStateChanged)
|
||||
{
|
||||
_vsyncStateChanged = false;
|
||||
|
||||
Recreate();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal VulkanCommandBufferPool.VulkanCommandBuffer StartPresentation()
|
||||
{
|
||||
_nextImage = 0;
|
||||
while (true)
|
||||
{
|
||||
var acquireResult = _swapchainExtension.AcquireNextImage(
|
||||
_device.InternalHandle,
|
||||
_swapchain,
|
||||
ulong.MaxValue,
|
||||
_semaphorePair.ImageAvailableSemaphore,
|
||||
new Fence(),
|
||||
ref _nextImage);
|
||||
|
||||
if (acquireResult == Result.ErrorOutOfDateKhr ||
|
||||
acquireResult == Result.SuboptimalKhr)
|
||||
{
|
||||
Recreate();
|
||||
}
|
||||
else
|
||||
{
|
||||
acquireResult.ThrowOnError();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var commandBuffer = CommandBufferPool.CreateCommandBuffer();
|
||||
commandBuffer.BeginRecording();
|
||||
|
||||
VulkanMemoryHelper.TransitionLayout(_device, commandBuffer.InternalHandle,
|
||||
_swapchainImages[_nextImage], ImageLayout.Undefined,
|
||||
AccessFlags.AccessNoneKhr,
|
||||
ImageLayout.TransferDstOptimal,
|
||||
AccessFlags.AccessTransferWriteBit,
|
||||
1);
|
||||
|
||||
return commandBuffer;
|
||||
}
|
||||
|
||||
internal void BlitImageToCurrentImage(VulkanSurfaceRenderTarget renderTarget, CommandBuffer commandBuffer)
|
||||
{
|
||||
var image = renderTarget.GetImage();
|
||||
|
||||
VulkanMemoryHelper.TransitionLayout(_device, commandBuffer,
|
||||
image.InternalHandle.Value, (ImageLayout)image.CurrentLayout,
|
||||
AccessFlags.AccessNoneKhr,
|
||||
ImageLayout.TransferSrcOptimal,
|
||||
AccessFlags.AccessTransferReadBit,
|
||||
renderTarget.MipLevels);
|
||||
|
||||
var srcBlitRegion = new ImageBlit
|
||||
{
|
||||
SrcOffsets = new ImageBlit.SrcOffsetsBuffer
|
||||
{
|
||||
Element0 = new Offset3D(0, 0, 0),
|
||||
Element1 = new Offset3D(renderTarget.Size.Width, renderTarget.Size.Height, 1),
|
||||
},
|
||||
DstOffsets = new ImageBlit.DstOffsetsBuffer
|
||||
{
|
||||
Element0 = new Offset3D(0, 0, 0),
|
||||
Element1 = new Offset3D(Size.Width, Size.Height, 1),
|
||||
},
|
||||
SrcSubresource = new ImageSubresourceLayers
|
||||
{
|
||||
AspectMask = ImageAspectFlags.ImageAspectColorBit,
|
||||
BaseArrayLayer = 0,
|
||||
LayerCount = 1,
|
||||
MipLevel = 0
|
||||
},
|
||||
DstSubresource = new ImageSubresourceLayers
|
||||
{
|
||||
AspectMask = ImageAspectFlags.ImageAspectColorBit,
|
||||
BaseArrayLayer = 0,
|
||||
LayerCount = 1,
|
||||
MipLevel = 0
|
||||
}
|
||||
};
|
||||
|
||||
_device.Api.CmdBlitImage(commandBuffer, image.InternalHandle.Value,
|
||||
ImageLayout.TransferSrcOptimal,
|
||||
_swapchainImages[_nextImage],
|
||||
ImageLayout.TransferDstOptimal,
|
||||
1,
|
||||
srcBlitRegion,
|
||||
Filter.Linear);
|
||||
|
||||
VulkanMemoryHelper.TransitionLayout(_device, commandBuffer,
|
||||
image.InternalHandle.Value, ImageLayout.TransferSrcOptimal,
|
||||
AccessFlags.AccessTransferReadBit,
|
||||
(ImageLayout)image.CurrentLayout,
|
||||
AccessFlags.AccessNoneKhr,
|
||||
renderTarget.MipLevels);
|
||||
}
|
||||
|
||||
internal unsafe void EndPresentation(VulkanCommandBufferPool.VulkanCommandBuffer commandBuffer)
|
||||
{
|
||||
VulkanMemoryHelper.TransitionLayout(_device, commandBuffer.InternalHandle,
|
||||
_swapchainImages[_nextImage], ImageLayout.TransferDstOptimal,
|
||||
AccessFlags.AccessNoneKhr,
|
||||
ImageLayout.PresentSrcKhr,
|
||||
AccessFlags.AccessNoneKhr,
|
||||
1);
|
||||
|
||||
commandBuffer.Submit(
|
||||
stackalloc[] { _semaphorePair.ImageAvailableSemaphore },
|
||||
stackalloc[] { PipelineStageFlags.PipelineStageColorAttachmentOutputBit },
|
||||
stackalloc[] { _semaphorePair.RenderFinishedSemaphore });
|
||||
|
||||
var semaphore = _semaphorePair.RenderFinishedSemaphore;
|
||||
var swapchain = _swapchain;
|
||||
var nextImage = _nextImage;
|
||||
|
||||
Result result;
|
||||
|
||||
var presentInfo = new PresentInfoKHR
|
||||
{
|
||||
SType = StructureType.PresentInfoKhr,
|
||||
WaitSemaphoreCount = 1,
|
||||
PWaitSemaphores = &semaphore,
|
||||
SwapchainCount = 1,
|
||||
PSwapchains = &swapchain,
|
||||
PImageIndices = &nextImage,
|
||||
PResults = &result
|
||||
};
|
||||
|
||||
lock (_device.Lock)
|
||||
{
|
||||
_swapchainExtension.QueuePresent(_device.PresentQueue.InternalHandle, presentInfo);
|
||||
}
|
||||
|
||||
CommandBufferPool.FreeUsedCommandBuffers();
|
||||
|
||||
Presented?.Invoke(this, null);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,165 +0,0 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Silk.NET.Vulkan;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan
|
||||
{
|
||||
internal class VulkanImage : IDisposable
|
||||
{
|
||||
private readonly VulkanDevice _device;
|
||||
private readonly VulkanPhysicalDevice _physicalDevice;
|
||||
private readonly VulkanCommandBufferPool _commandBufferPool;
|
||||
private ImageLayout _currentLayout;
|
||||
private AccessFlags _currentAccessFlags;
|
||||
private ImageUsageFlags _imageUsageFlags { get; }
|
||||
private ImageView? _imageView { get; set; }
|
||||
private DeviceMemory _imageMemory { get; set; }
|
||||
|
||||
internal Image? InternalHandle { get; private set; }
|
||||
internal Format Format { get; }
|
||||
internal ImageAspectFlags AspectFlags { get; private set; }
|
||||
|
||||
public ulong Handle => InternalHandle?.Handle ?? 0;
|
||||
public ulong ViewHandle => _imageView?.Handle ?? 0;
|
||||
public uint UsageFlags => (uint)_imageUsageFlags;
|
||||
public ulong MemoryHandle => _imageMemory.Handle;
|
||||
public uint MipLevels { get; private set; }
|
||||
public PixelSize Size { get; }
|
||||
public ulong MemorySize { get; private set; }
|
||||
public uint CurrentLayout => (uint)_currentLayout;
|
||||
|
||||
public VulkanImage(
|
||||
VulkanDevice device,
|
||||
VulkanPhysicalDevice physicalDevice,
|
||||
VulkanCommandBufferPool commandBufferPool,
|
||||
uint format,
|
||||
PixelSize size,
|
||||
uint mipLevels = 0)
|
||||
{
|
||||
_device = device;
|
||||
_physicalDevice = physicalDevice;
|
||||
_commandBufferPool = commandBufferPool;
|
||||
Format = (Format)format;
|
||||
Size = size;
|
||||
MipLevels = mipLevels;
|
||||
_imageUsageFlags =
|
||||
ImageUsageFlags.ImageUsageColorAttachmentBit | ImageUsageFlags.ImageUsageTransferDstBit |
|
||||
ImageUsageFlags.ImageUsageTransferSrcBit | ImageUsageFlags.ImageUsageSampledBit;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public unsafe void Initialize()
|
||||
{
|
||||
if (!InternalHandle.HasValue)
|
||||
{
|
||||
MipLevels = MipLevels != 0 ? MipLevels : (uint)Math.Floor(Math.Log(Math.Max(Size.Width, Size.Height), 2));
|
||||
|
||||
var imageCreateInfo = new ImageCreateInfo
|
||||
{
|
||||
SType = StructureType.ImageCreateInfo,
|
||||
ImageType = ImageType.ImageType2D,
|
||||
Format = Format,
|
||||
Extent = new Extent3D((uint?)Size.Width, (uint?)Size.Height, 1),
|
||||
MipLevels = MipLevels,
|
||||
ArrayLayers = 1,
|
||||
Samples = SampleCountFlags.SampleCount1Bit,
|
||||
Tiling = Tiling,
|
||||
Usage = _imageUsageFlags,
|
||||
SharingMode = SharingMode.Exclusive,
|
||||
InitialLayout = ImageLayout.Undefined,
|
||||
Flags = ImageCreateFlags.ImageCreateMutableFormatBit
|
||||
};
|
||||
|
||||
_device.Api.CreateImage(_device.InternalHandle, imageCreateInfo, null, out var image).ThrowOnError();
|
||||
InternalHandle = image;
|
||||
|
||||
_device.Api.GetImageMemoryRequirements(_device.InternalHandle, InternalHandle.Value,
|
||||
out var memoryRequirements);
|
||||
|
||||
var memoryAllocateInfo = new MemoryAllocateInfo
|
||||
{
|
||||
SType = StructureType.MemoryAllocateInfo,
|
||||
AllocationSize = memoryRequirements.Size,
|
||||
MemoryTypeIndex = (uint)VulkanMemoryHelper.FindSuitableMemoryTypeIndex(
|
||||
_physicalDevice,
|
||||
memoryRequirements.MemoryTypeBits, MemoryPropertyFlags.MemoryPropertyDeviceLocalBit)
|
||||
};
|
||||
|
||||
_device.Api.AllocateMemory(_device.InternalHandle, memoryAllocateInfo, null,
|
||||
out var imageMemory);
|
||||
|
||||
_imageMemory = imageMemory;
|
||||
|
||||
_device.Api.BindImageMemory(_device.InternalHandle, InternalHandle.Value, _imageMemory, 0);
|
||||
|
||||
MemorySize = memoryRequirements.Size;
|
||||
|
||||
var componentMapping = new ComponentMapping(
|
||||
ComponentSwizzle.Identity,
|
||||
ComponentSwizzle.Identity,
|
||||
ComponentSwizzle.Identity,
|
||||
ComponentSwizzle.Identity);
|
||||
|
||||
AspectFlags = ImageAspectFlags.ImageAspectColorBit;
|
||||
|
||||
var subresourceRange = new ImageSubresourceRange(AspectFlags, 0, MipLevels, 0, 1);
|
||||
|
||||
var imageViewCreateInfo = new ImageViewCreateInfo
|
||||
{
|
||||
SType = StructureType.ImageViewCreateInfo,
|
||||
Image = InternalHandle.Value,
|
||||
ViewType = ImageViewType.ImageViewType2D,
|
||||
Format = Format,
|
||||
Components = componentMapping,
|
||||
SubresourceRange = subresourceRange
|
||||
};
|
||||
|
||||
_device.Api
|
||||
.CreateImageView(_device.InternalHandle, imageViewCreateInfo, null, out var imageView)
|
||||
.ThrowOnError();
|
||||
|
||||
_imageView = imageView;
|
||||
|
||||
_currentLayout = ImageLayout.Undefined;
|
||||
|
||||
TransitionLayout(ImageLayout.ColorAttachmentOptimal, AccessFlags.AccessNoneKhr);
|
||||
}
|
||||
}
|
||||
|
||||
public ImageTiling Tiling => ImageTiling.Optimal;
|
||||
|
||||
internal void TransitionLayout(ImageLayout destinationLayout, AccessFlags destinationAccessFlags)
|
||||
{
|
||||
var commandBuffer = _commandBufferPool.CreateCommandBuffer();
|
||||
commandBuffer.BeginRecording();
|
||||
|
||||
VulkanMemoryHelper.TransitionLayout(_device, commandBuffer.InternalHandle, InternalHandle.Value,
|
||||
_currentLayout,
|
||||
_currentAccessFlags,
|
||||
destinationLayout, destinationAccessFlags,
|
||||
MipLevels);
|
||||
|
||||
commandBuffer.EndRecording();
|
||||
|
||||
commandBuffer.Submit();
|
||||
|
||||
_currentLayout = destinationLayout;
|
||||
_currentAccessFlags = destinationAccessFlags;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (InternalHandle != null)
|
||||
{
|
||||
_device.Api.DestroyImageView(_device.InternalHandle, _imageView.Value, Span<AllocationCallbacks>.Empty);
|
||||
_device.Api.DestroyImage(_device.InternalHandle, InternalHandle.Value, Span<AllocationCallbacks>.Empty);
|
||||
_device.Api.FreeMemory(_device.InternalHandle, _imageMemory, Span<AllocationCallbacks>.Empty);
|
||||
|
||||
_imageView = default;
|
||||
InternalHandle = null;
|
||||
_imageMemory = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Silk.NET.Core;
|
||||
using Silk.NET.Vulkan;
|
||||
using Silk.NET.Vulkan.Extensions.EXT;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan
|
||||
{
|
||||
public class VulkanInstance : IDisposable
|
||||
{
|
||||
private const string EngineName = "Avalonia Vulkan";
|
||||
|
||||
private VulkanInstance(Instance apiHandle, Vk api)
|
||||
{
|
||||
InternalHandle = apiHandle;
|
||||
Api = api;
|
||||
}
|
||||
|
||||
public IntPtr Handle => InternalHandle.Handle;
|
||||
|
||||
internal Instance InternalHandle { get; }
|
||||
public Vk Api { get; }
|
||||
|
||||
internal static IEnumerable<string> RequiredInstanceExtensions
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return "VK_KHR_surface";
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
yield return "VK_KHR_xlib_surface";
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
yield return "VK_KHR_win32_surface";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Api?.DestroyInstance(InternalHandle, Span<AllocationCallbacks>.Empty);
|
||||
Api?.Dispose();
|
||||
}
|
||||
|
||||
internal static unsafe VulkanInstance Create(VulkanOptions options)
|
||||
{
|
||||
var api = Vk.GetApi();
|
||||
var applicationName = Marshal.StringToHGlobalAnsi(options.ApplicationName);
|
||||
var engineName = Marshal.StringToHGlobalAnsi(EngineName);
|
||||
var enabledExtensions = new List<string>(options.InstanceExtensions);
|
||||
|
||||
enabledExtensions.AddRange(RequiredInstanceExtensions);
|
||||
|
||||
var applicationInfo = new ApplicationInfo
|
||||
{
|
||||
PApplicationName = (byte*)applicationName,
|
||||
ApiVersion = Vk.Version12.Value,
|
||||
PEngineName = (byte*)engineName,
|
||||
EngineVersion = new Version32(1, 0, 0),
|
||||
ApplicationVersion = new Version32(1, 0, 0)
|
||||
};
|
||||
|
||||
var enabledLayers = new HashSet<string>();
|
||||
|
||||
if (options.UseDebug)
|
||||
{
|
||||
enabledExtensions.Add(ExtDebugUtils.ExtensionName);
|
||||
enabledExtensions.Add(ExtDebugReport.ExtensionName);
|
||||
if (IsLayerAvailable(api, "VK_LAYER_KHRONOS_validation"))
|
||||
enabledLayers.Add("VK_LAYER_KHRONOS_validation");
|
||||
}
|
||||
|
||||
foreach (var layer in options.EnabledLayers)
|
||||
enabledLayers.Add(layer);
|
||||
|
||||
var ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Count];
|
||||
var ppEnabledLayers = stackalloc IntPtr[enabledLayers.Count];
|
||||
|
||||
for (var i = 0; i < enabledExtensions.Count; i++)
|
||||
ppEnabledExtensions[i] = Marshal.StringToHGlobalAnsi(enabledExtensions[i]);
|
||||
|
||||
var layers = enabledLayers.ToList();
|
||||
|
||||
for (var i = 0; i < enabledLayers.Count; i++)
|
||||
ppEnabledLayers[i] = Marshal.StringToHGlobalAnsi(layers[i]);
|
||||
|
||||
var instanceCreateInfo = new InstanceCreateInfo
|
||||
{
|
||||
SType = StructureType.InstanceCreateInfo,
|
||||
PApplicationInfo = &applicationInfo,
|
||||
PpEnabledExtensionNames = (byte**)ppEnabledExtensions,
|
||||
PpEnabledLayerNames = (byte**)ppEnabledLayers,
|
||||
EnabledExtensionCount = (uint)enabledExtensions.Count,
|
||||
EnabledLayerCount = (uint)enabledLayers.Count
|
||||
};
|
||||
|
||||
api.CreateInstance(in instanceCreateInfo, null, out var instance).ThrowOnError();
|
||||
|
||||
Marshal.FreeHGlobal(applicationName);
|
||||
Marshal.FreeHGlobal(engineName);
|
||||
|
||||
for (var i = 0; i < enabledExtensions.Count; i++) Marshal.FreeHGlobal(ppEnabledExtensions[i]);
|
||||
|
||||
for (var i = 0; i < enabledLayers.Count; i++) Marshal.FreeHGlobal(ppEnabledLayers[i]);
|
||||
|
||||
return new VulkanInstance(instance, api);
|
||||
}
|
||||
|
||||
private static unsafe bool IsLayerAvailable(Vk api, string layerName)
|
||||
{
|
||||
uint layerPropertiesCount;
|
||||
|
||||
api.EnumerateInstanceLayerProperties(&layerPropertiesCount, null).ThrowOnError();
|
||||
|
||||
var layerProperties = new LayerProperties[layerPropertiesCount];
|
||||
|
||||
fixed (LayerProperties* pLayerProperties = layerProperties)
|
||||
{
|
||||
api.EnumerateInstanceLayerProperties(&layerPropertiesCount, layerProperties).ThrowOnError();
|
||||
|
||||
for (var i = 0; i < layerPropertiesCount; i++)
|
||||
{
|
||||
var currentLayerName = Marshal.PtrToStringAnsi((IntPtr)pLayerProperties[i].LayerName);
|
||||
|
||||
if (currentLayerName == layerName) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
using Silk.NET.Vulkan;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan
|
||||
{
|
||||
internal static class VulkanMemoryHelper
|
||||
{
|
||||
internal static int FindSuitableMemoryTypeIndex(VulkanPhysicalDevice physicalDevice, uint memoryTypeBits,
|
||||
MemoryPropertyFlags flags)
|
||||
{
|
||||
physicalDevice.Api.GetPhysicalDeviceMemoryProperties(physicalDevice.InternalHandle, out var properties);
|
||||
|
||||
for (var i = 0; i < properties.MemoryTypeCount; i++)
|
||||
{
|
||||
var type = properties.MemoryTypes[i];
|
||||
|
||||
if ((memoryTypeBits & (1 << i)) != 0 && type.PropertyFlags.HasFlag(flags)) return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
internal static unsafe void TransitionLayout(VulkanDevice device,
|
||||
CommandBuffer commandBuffer,
|
||||
Image image,
|
||||
ImageLayout sourceLayout,
|
||||
AccessFlags sourceAccessMask,
|
||||
ImageLayout destinationLayout,
|
||||
AccessFlags destinationAccessMask,
|
||||
uint mipLevels)
|
||||
{
|
||||
var subresourceRange = new ImageSubresourceRange(ImageAspectFlags.ImageAspectColorBit, 0, mipLevels, 0, 1);
|
||||
|
||||
var barrier = new ImageMemoryBarrier
|
||||
{
|
||||
SType = StructureType.ImageMemoryBarrier,
|
||||
SrcAccessMask = sourceAccessMask,
|
||||
DstAccessMask = destinationAccessMask,
|
||||
OldLayout = sourceLayout,
|
||||
NewLayout = destinationLayout,
|
||||
SrcQueueFamilyIndex = Vk.QueueFamilyIgnored,
|
||||
DstQueueFamilyIndex = Vk.QueueFamilyIgnored,
|
||||
Image = image,
|
||||
SubresourceRange = subresourceRange
|
||||
};
|
||||
|
||||
device.Api.CmdPipelineBarrier(
|
||||
commandBuffer,
|
||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
||||
PipelineStageFlags.PipelineStageAllCommandsBit,
|
||||
0,
|
||||
0,
|
||||
null,
|
||||
0,
|
||||
null,
|
||||
1,
|
||||
barrier);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan
|
||||
{
|
||||
public class VulkanOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the application name of the Vulkan instance
|
||||
/// </summary>
|
||||
public string ApplicationName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies additional extensions to enable if available on the instance
|
||||
/// </summary>
|
||||
public IEnumerable<string> InstanceExtensions { get; set; } = Enumerable.Empty<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Specifies layers to enable if available on the instance
|
||||
/// </summary>
|
||||
public IEnumerable<string> EnabledLayers { get; set; } = Enumerable.Empty<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Enables the debug layer
|
||||
/// </summary>
|
||||
public bool UseDebug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Selects the first suitable discrete GPU available
|
||||
/// </summary>
|
||||
public bool PreferDiscreteGpu { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the device to use if available and suitable.
|
||||
/// </summary>
|
||||
public string PreferredDevice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Max number of device queues to request
|
||||
/// </summary>
|
||||
public uint MaxQueueCount { get; set; }
|
||||
}
|
||||
}
|
@ -1,219 +0,0 @@
|
||||
using Ryujinx.Graphics.Vulkan;
|
||||
using Silk.NET.Core;
|
||||
using Silk.NET.Vulkan;
|
||||
using Silk.NET.Vulkan.Extensions.KHR;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan
|
||||
{
|
||||
public unsafe class VulkanPhysicalDevice
|
||||
{
|
||||
private VulkanPhysicalDevice(PhysicalDevice apiHandle, Vk api, uint queueCount, uint queueFamilyIndex)
|
||||
{
|
||||
InternalHandle = apiHandle;
|
||||
Api = api;
|
||||
QueueCount = queueCount;
|
||||
QueueFamilyIndex = queueFamilyIndex;
|
||||
|
||||
api.GetPhysicalDeviceProperties(apiHandle, out var properties);
|
||||
|
||||
DeviceName = Marshal.PtrToStringAnsi((IntPtr)properties.DeviceName);
|
||||
DeviceId = VulkanInitialization.StringFromIdPair(properties.VendorID, properties.DeviceID);
|
||||
|
||||
var version = (Version32)properties.ApiVersion;
|
||||
ApiVersion = new Version((int)version.Major, (int)version.Minor, 0, (int)version.Patch);
|
||||
}
|
||||
|
||||
internal PhysicalDevice InternalHandle { get; }
|
||||
internal Vk Api { get; }
|
||||
public uint QueueCount { get; }
|
||||
public uint QueueFamilyIndex { get; }
|
||||
public IntPtr Handle => InternalHandle.Handle;
|
||||
|
||||
public string DeviceName { get; }
|
||||
public string DeviceId { get; }
|
||||
public Version ApiVersion { get; }
|
||||
public static Dictionary<PhysicalDevice, PhysicalDeviceProperties> PhysicalDevices { get; private set; }
|
||||
public static IEnumerable<KeyValuePair<PhysicalDevice, PhysicalDeviceProperties>> SuitableDevices { get; private set; }
|
||||
|
||||
internal static void SelectAvailableDevices(VulkanInstance instance,
|
||||
VulkanSurface surface, bool preferDiscreteGpu, string preferredDevice)
|
||||
{
|
||||
uint physicalDeviceCount;
|
||||
|
||||
instance.Api.EnumeratePhysicalDevices(instance.InternalHandle, &physicalDeviceCount, null).ThrowOnError();
|
||||
|
||||
var physicalDevices = new PhysicalDevice[physicalDeviceCount];
|
||||
|
||||
fixed (PhysicalDevice* pPhysicalDevices = physicalDevices)
|
||||
{
|
||||
instance.Api.EnumeratePhysicalDevices(instance.InternalHandle, &physicalDeviceCount, pPhysicalDevices)
|
||||
.ThrowOnError();
|
||||
}
|
||||
|
||||
PhysicalDevices = new Dictionary<PhysicalDevice, PhysicalDeviceProperties>();
|
||||
|
||||
foreach (var physicalDevice in physicalDevices)
|
||||
{
|
||||
instance.Api.GetPhysicalDeviceProperties(physicalDevice, out var properties);
|
||||
PhysicalDevices.Add(physicalDevice, properties);
|
||||
}
|
||||
|
||||
SuitableDevices = PhysicalDevices.Where(x => IsSuitableDevice(
|
||||
instance.Api,
|
||||
x.Key,
|
||||
x.Value,
|
||||
surface.ApiHandle,
|
||||
out _,
|
||||
out _));
|
||||
}
|
||||
|
||||
internal static VulkanPhysicalDevice FindSuitablePhysicalDevice(VulkanInstance instance,
|
||||
VulkanSurface surface, bool preferDiscreteGpu, string preferredDevice)
|
||||
{
|
||||
SelectAvailableDevices(instance, surface, preferDiscreteGpu, preferredDevice);
|
||||
|
||||
uint queueFamilyIndex = 0;
|
||||
uint queueCount = 0;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(preferredDevice))
|
||||
{
|
||||
var physicalDevice = SuitableDevices.FirstOrDefault(x => VulkanInitialization.StringFromIdPair(x.Value.VendorID, x.Value.DeviceID) == preferredDevice);
|
||||
|
||||
queueFamilyIndex = FindSuitableQueueFamily(instance.Api, physicalDevice.Key,
|
||||
surface.ApiHandle, out queueCount);
|
||||
if (queueFamilyIndex != int.MaxValue)
|
||||
{
|
||||
return new VulkanPhysicalDevice(physicalDevice.Key, instance.Api, queueCount, queueFamilyIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (preferDiscreteGpu)
|
||||
{
|
||||
var discreteGpus = SuitableDevices.Where(p => p.Value.DeviceType == PhysicalDeviceType.DiscreteGpu);
|
||||
|
||||
foreach (var gpu in discreteGpus)
|
||||
{
|
||||
queueFamilyIndex = FindSuitableQueueFamily(instance.Api, gpu.Key,
|
||||
surface.ApiHandle, out queueCount);
|
||||
if (queueFamilyIndex != int.MaxValue)
|
||||
{
|
||||
return new VulkanPhysicalDevice(gpu.Key, instance.Api, queueCount, queueFamilyIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var physicalDevice in SuitableDevices)
|
||||
{
|
||||
queueFamilyIndex = FindSuitableQueueFamily(instance.Api, physicalDevice.Key,
|
||||
surface.ApiHandle, out queueCount);
|
||||
if (queueFamilyIndex != int.MaxValue)
|
||||
{
|
||||
return new VulkanPhysicalDevice(physicalDevice.Key, instance.Api, queueCount, queueFamilyIndex);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("No suitable physical device found");
|
||||
}
|
||||
|
||||
private static unsafe bool IsSuitableDevice(Vk api, PhysicalDevice physicalDevice, PhysicalDeviceProperties properties, SurfaceKHR surface,
|
||||
out uint queueCount, out uint familyIndex)
|
||||
{
|
||||
queueCount = 0;
|
||||
familyIndex = 0;
|
||||
|
||||
if (properties.DeviceType == PhysicalDeviceType.Cpu) return false;
|
||||
|
||||
var extensionMatches = 0;
|
||||
uint propertiesCount;
|
||||
|
||||
api.EnumerateDeviceExtensionProperties(physicalDevice, (byte*)null, &propertiesCount, null).ThrowOnError();
|
||||
|
||||
var extensionProperties = new ExtensionProperties[propertiesCount];
|
||||
|
||||
fixed (ExtensionProperties* pExtensionProperties = extensionProperties)
|
||||
{
|
||||
api.EnumerateDeviceExtensionProperties(
|
||||
physicalDevice,
|
||||
(byte*)null,
|
||||
&propertiesCount,
|
||||
pExtensionProperties).ThrowOnError();
|
||||
|
||||
for (var i = 0; i < propertiesCount; i++)
|
||||
{
|
||||
var extensionName = Marshal.PtrToStringAnsi((IntPtr)pExtensionProperties[i].ExtensionName);
|
||||
|
||||
if (VulkanInitialization.RequiredExtensions.Contains(extensionName))
|
||||
{
|
||||
extensionMatches++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (extensionMatches == VulkanInitialization.RequiredExtensions.Length)
|
||||
{
|
||||
familyIndex = FindSuitableQueueFamily(api, physicalDevice, surface, out queueCount);
|
||||
|
||||
return familyIndex != uint.MaxValue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal unsafe string[] GetSupportedExtensions()
|
||||
{
|
||||
uint propertiesCount;
|
||||
|
||||
Api.EnumerateDeviceExtensionProperties(InternalHandle, (byte*)null, &propertiesCount, null).ThrowOnError();
|
||||
|
||||
var extensionProperties = new ExtensionProperties[propertiesCount];
|
||||
|
||||
fixed (ExtensionProperties* pExtensionProperties = extensionProperties)
|
||||
{
|
||||
Api.EnumerateDeviceExtensionProperties(InternalHandle, (byte*)null, &propertiesCount, pExtensionProperties)
|
||||
.ThrowOnError();
|
||||
}
|
||||
|
||||
return extensionProperties.Select(x => Marshal.PtrToStringAnsi((IntPtr)x.ExtensionName)).ToArray();
|
||||
}
|
||||
|
||||
private static uint FindSuitableQueueFamily(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface,
|
||||
out uint queueCount)
|
||||
{
|
||||
const QueueFlags RequiredFlags = QueueFlags.QueueGraphicsBit | QueueFlags.QueueComputeBit;
|
||||
|
||||
var khrSurface = new KhrSurface(api.Context);
|
||||
|
||||
uint propertiesCount;
|
||||
|
||||
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &propertiesCount, null);
|
||||
|
||||
var properties = new QueueFamilyProperties[propertiesCount];
|
||||
|
||||
fixed (QueueFamilyProperties* pProperties = properties)
|
||||
{
|
||||
api.GetPhysicalDeviceQueueFamilyProperties(physicalDevice, &propertiesCount, pProperties);
|
||||
}
|
||||
|
||||
for (uint index = 0; index < propertiesCount; index++)
|
||||
{
|
||||
var queueFlags = properties[index].QueueFlags;
|
||||
|
||||
khrSurface.GetPhysicalDeviceSurfaceSupport(physicalDevice, index, surface, out var surfaceSupported)
|
||||
.ThrowOnError();
|
||||
|
||||
if (queueFlags.HasFlag(RequiredFlags) && surfaceSupported)
|
||||
{
|
||||
queueCount = properties[index].QueueCount;
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
queueCount = 0;
|
||||
return uint.MaxValue;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
using Avalonia;
|
||||
using Ryujinx.Ava.Ui.Vulkan.Surfaces;
|
||||
using Ryujinx.Graphics.Vulkan;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan
|
||||
{
|
||||
internal class VulkanPlatformInterface : IDisposable
|
||||
{
|
||||
private static VulkanOptions _options;
|
||||
|
||||
private VulkanPlatformInterface(VulkanInstance instance)
|
||||
{
|
||||
Instance = instance;
|
||||
Api = instance.Api;
|
||||
}
|
||||
|
||||
public VulkanPhysicalDevice PhysicalDevice { get; private set; }
|
||||
public VulkanInstance Instance { get; }
|
||||
public Vk Api { get; private set; }
|
||||
public VulkanSurfaceRenderTarget MainSurface { get; set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Instance?.Dispose();
|
||||
Api?.Dispose();
|
||||
}
|
||||
|
||||
private static VulkanPlatformInterface TryCreate()
|
||||
{
|
||||
_options = AvaloniaLocator.Current.GetService<VulkanOptions>() ?? new VulkanOptions();
|
||||
|
||||
var instance = VulkanInstance.Create(_options);
|
||||
|
||||
return new VulkanPlatformInterface(instance);
|
||||
}
|
||||
|
||||
public static bool TryInitialize()
|
||||
{
|
||||
var feature = TryCreate();
|
||||
if (feature != null)
|
||||
{
|
||||
AvaloniaLocator.CurrentMutable.Bind<VulkanPlatformInterface>().ToConstant(feature);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public VulkanSurfaceRenderTarget CreateRenderTarget(IVulkanPlatformSurface platformSurface)
|
||||
{
|
||||
var surface = VulkanSurface.CreateSurface(Instance, platformSurface);
|
||||
|
||||
if (PhysicalDevice == null)
|
||||
{
|
||||
PhysicalDevice = VulkanPhysicalDevice.FindSuitablePhysicalDevice(Instance, surface, _options.PreferDiscreteGpu, _options.PreferredDevice);
|
||||
}
|
||||
|
||||
var renderTarget = new VulkanSurfaceRenderTarget(this, surface);
|
||||
|
||||
if (MainSurface == null && surface != null)
|
||||
{
|
||||
MainSurface = renderTarget;
|
||||
}
|
||||
|
||||
return renderTarget;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
using System;
|
||||
using Silk.NET.Vulkan;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan
|
||||
{
|
||||
internal class VulkanQueue
|
||||
{
|
||||
public VulkanQueue(VulkanDevice device, Queue apiHandle)
|
||||
{
|
||||
Device = device;
|
||||
InternalHandle = apiHandle;
|
||||
}
|
||||
|
||||
public VulkanDevice Device { get; }
|
||||
public IntPtr Handle => InternalHandle.Handle;
|
||||
internal Queue InternalHandle { get; }
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
using System;
|
||||
using Silk.NET.Vulkan;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan
|
||||
{
|
||||
internal class VulkanSemaphorePair : IDisposable
|
||||
{
|
||||
private readonly VulkanDevice _device;
|
||||
|
||||
public unsafe VulkanSemaphorePair(VulkanDevice device)
|
||||
{
|
||||
_device = device;
|
||||
|
||||
var semaphoreCreateInfo = new SemaphoreCreateInfo { SType = StructureType.SemaphoreCreateInfo };
|
||||
|
||||
_device.Api.CreateSemaphore(_device.InternalHandle, semaphoreCreateInfo, null, out var semaphore).ThrowOnError();
|
||||
ImageAvailableSemaphore = semaphore;
|
||||
|
||||
_device.Api.CreateSemaphore(_device.InternalHandle, semaphoreCreateInfo, null, out semaphore).ThrowOnError();
|
||||
RenderFinishedSemaphore = semaphore;
|
||||
}
|
||||
|
||||
internal Semaphore ImageAvailableSemaphore { get; }
|
||||
internal Semaphore RenderFinishedSemaphore { get; }
|
||||
|
||||
public unsafe void Dispose()
|
||||
{
|
||||
_device.Api.DestroySemaphore(_device.InternalHandle, ImageAvailableSemaphore, null);
|
||||
_device.Api.DestroySemaphore(_device.InternalHandle, RenderFinishedSemaphore, null);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Ryujinx.Ava.Ui.Vulkan.Surfaces;
|
||||
using Silk.NET.Vulkan;
|
||||
using Silk.NET.Vulkan.Extensions.KHR;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan
|
||||
{
|
||||
public class VulkanSurface : IDisposable
|
||||
{
|
||||
private readonly VulkanInstance _instance;
|
||||
private readonly IVulkanPlatformSurface _vulkanPlatformSurface;
|
||||
|
||||
private VulkanSurface(IVulkanPlatformSurface vulkanPlatformSurface, VulkanInstance instance)
|
||||
{
|
||||
_vulkanPlatformSurface = vulkanPlatformSurface;
|
||||
_instance = instance;
|
||||
ApiHandle = vulkanPlatformSurface.CreateSurface(instance);
|
||||
}
|
||||
|
||||
internal SurfaceKHR ApiHandle { get; }
|
||||
|
||||
internal static KhrSurface SurfaceExtension { get; private set; }
|
||||
|
||||
internal PixelSize SurfaceSize => _vulkanPlatformSurface.SurfaceSize;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
SurfaceExtension.DestroySurface(_instance.InternalHandle, ApiHandle, Span<AllocationCallbacks>.Empty);
|
||||
_vulkanPlatformSurface.Dispose();
|
||||
}
|
||||
|
||||
internal static VulkanSurface CreateSurface(VulkanInstance instance, IVulkanPlatformSurface vulkanPlatformSurface)
|
||||
{
|
||||
if (SurfaceExtension == null)
|
||||
{
|
||||
instance.Api.TryGetInstanceExtension(instance.InternalHandle, out KhrSurface extension);
|
||||
|
||||
SurfaceExtension = extension;
|
||||
}
|
||||
|
||||
return new VulkanSurface(vulkanPlatformSurface, instance);
|
||||
}
|
||||
|
||||
internal bool CanSurfacePresent(VulkanPhysicalDevice physicalDevice)
|
||||
{
|
||||
SurfaceExtension.GetPhysicalDeviceSurfaceSupport(physicalDevice.InternalHandle, physicalDevice.QueueFamilyIndex, ApiHandle, out var isSupported);
|
||||
|
||||
return isSupported;
|
||||
}
|
||||
|
||||
internal SurfaceFormatKHR GetSurfaceFormat(VulkanPhysicalDevice physicalDevice)
|
||||
{
|
||||
Span<uint> surfaceFormatsCount = stackalloc uint[1];
|
||||
SurfaceExtension.GetPhysicalDeviceSurfaceFormats(physicalDevice.InternalHandle, ApiHandle, surfaceFormatsCount, Span<SurfaceFormatKHR>.Empty);
|
||||
Span<SurfaceFormatKHR> surfaceFormats = stackalloc SurfaceFormatKHR[(int)surfaceFormatsCount[0]];
|
||||
SurfaceExtension.GetPhysicalDeviceSurfaceFormats(physicalDevice.InternalHandle, ApiHandle, surfaceFormatsCount, surfaceFormats);
|
||||
|
||||
if (surfaceFormats.Length == 1 && surfaceFormats[0].Format == Format.Undefined)
|
||||
{
|
||||
return new SurfaceFormatKHR(Format.B8G8R8A8Unorm, ColorSpaceKHR.ColorspaceSrgbNonlinearKhr);
|
||||
}
|
||||
|
||||
foreach (var format in surfaceFormats)
|
||||
{
|
||||
if (format.Format == Format.B8G8R8A8Unorm && format.ColorSpace == ColorSpaceKHR.ColorspaceSrgbNonlinearKhr)
|
||||
{
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
return surfaceFormats[0];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Ryujinx.Ava.Ui.Vulkan.Surfaces;
|
||||
using Silk.NET.Vulkan;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Vulkan
|
||||
{
|
||||
internal class VulkanSurfaceRenderingSession : IDisposable
|
||||
{
|
||||
private readonly VulkanDevice _device;
|
||||
private readonly VulkanSurfaceRenderTarget _renderTarget;
|
||||
|
||||
public VulkanSurfaceRenderingSession(VulkanDisplay display, VulkanDevice device,
|
||||
VulkanSurfaceRenderTarget renderTarget, float scaling)
|
||||
{
|
||||
Display = display;
|
||||
_device = device;
|
||||
_renderTarget = renderTarget;
|
||||
Scaling = scaling;
|
||||
Begin();
|
||||
}
|
||||
|
||||
public VulkanDisplay Display { get; }
|
||||
|
||||
public PixelSize Size => _renderTarget.Size;
|
||||
public Vk Api => _device.Api;
|
||||
|
||||
public float Scaling { get; }
|
||||
|
||||
private void Begin()
|
||||
{
|
||||
if (!Display.EnsureSwapchainAvailable())
|
||||
{
|
||||
_renderTarget.RecreateImage();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_renderTarget.EndDraw();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
using SPB.Graphics;
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
[SupportedOSPlatform("linux")]
|
||||
internal class AvaloniaGlxContext : SPB.Platform.GLX.GLXOpenGLContext
|
||||
{
|
||||
public AvaloniaGlxContext(IntPtr handle)
|
||||
: base(FramebufferFormat.Default, 0, 0, 0, false, null)
|
||||
{
|
||||
ContextHandle = handle;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
using SPB.Graphics;
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
internal class AvaloniaWglContext : SPB.Platform.WGL.WGLOpenGLContext
|
||||
{
|
||||
public AvaloniaWglContext(IntPtr handle)
|
||||
: base(FramebufferFormat.Default, 0, 0, 0, false, null)
|
||||
{
|
||||
ContextHandle = handle;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,326 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Threading;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.Models;
|
||||
using Ryujinx.Ava.Ui.Windows;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public static class ContentDialogHelper
|
||||
{
|
||||
private static bool _isChoiceDialogOpen;
|
||||
|
||||
private async static Task<UserResult> ShowContentDialog(
|
||||
string title,
|
||||
string primaryText,
|
||||
string secondaryText,
|
||||
string primaryButton,
|
||||
string secondaryButton,
|
||||
string closeButton,
|
||||
int iconSymbol,
|
||||
UserResult primaryButtonResult = UserResult.Ok)
|
||||
{
|
||||
UserResult result = UserResult.None;
|
||||
|
||||
ContentDialog contentDialog = new ContentDialog();
|
||||
|
||||
await ShowDialog();
|
||||
|
||||
async Task ShowDialog()
|
||||
{
|
||||
contentDialog.Title = title;
|
||||
contentDialog.PrimaryButtonText = primaryButton;
|
||||
contentDialog.SecondaryButtonText = secondaryButton;
|
||||
contentDialog.CloseButtonText = closeButton;
|
||||
contentDialog.Content = CreateDialogTextContent(primaryText, secondaryText, iconSymbol);
|
||||
|
||||
contentDialog.PrimaryButtonCommand = MiniCommand.Create(() =>
|
||||
{
|
||||
result = primaryButtonResult;
|
||||
});
|
||||
contentDialog.SecondaryButtonCommand = MiniCommand.Create(() =>
|
||||
{
|
||||
result = UserResult.No;
|
||||
});
|
||||
contentDialog.CloseButtonCommand = MiniCommand.Create(() =>
|
||||
{
|
||||
result = UserResult.Cancel;
|
||||
});
|
||||
|
||||
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async static Task<UserResult> ShowDeferredContentDialog(
|
||||
StyleableWindow window,
|
||||
string title,
|
||||
string primaryText,
|
||||
string secondaryText,
|
||||
string primaryButton,
|
||||
string secondaryButton,
|
||||
string closeButton,
|
||||
int iconSymbol,
|
||||
ManualResetEvent deferResetEvent,
|
||||
Func<Window, Task> doWhileDeferred = null)
|
||||
{
|
||||
bool startedDeferring = false;
|
||||
|
||||
UserResult result = UserResult.None;
|
||||
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = title,
|
||||
PrimaryButtonText = primaryButton,
|
||||
SecondaryButtonText = secondaryButton,
|
||||
CloseButtonText = closeButton,
|
||||
Content = CreateDialogTextContent(primaryText, secondaryText, iconSymbol),
|
||||
PrimaryButtonCommand = MiniCommand.Create(() =>
|
||||
{
|
||||
result = primaryButton == LocaleManager.Instance["InputDialogYes"] ? UserResult.Yes : UserResult.Ok;
|
||||
}),
|
||||
};
|
||||
contentDialog.SecondaryButtonCommand = MiniCommand.Create(() =>
|
||||
{
|
||||
contentDialog.PrimaryButtonClick -= DeferClose;
|
||||
result = UserResult.No;
|
||||
});
|
||||
contentDialog.CloseButtonCommand = MiniCommand.Create(() =>
|
||||
{
|
||||
contentDialog.PrimaryButtonClick -= DeferClose;
|
||||
result = UserResult.Cancel;
|
||||
});
|
||||
contentDialog.PrimaryButtonClick += DeferClose;
|
||||
await contentDialog.ShowAsync(ContentDialogPlacement.Popup);
|
||||
|
||||
return result;
|
||||
|
||||
async void DeferClose(ContentDialog sender, ContentDialogButtonClickEventArgs args)
|
||||
{
|
||||
if (startedDeferring)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
contentDialog.PrimaryButtonClick -= DeferClose;
|
||||
|
||||
startedDeferring = true;
|
||||
|
||||
var deferral = args.GetDeferral();
|
||||
|
||||
result = primaryButton == LocaleManager.Instance["InputDialogYes"] ? UserResult.Yes : UserResult.Ok;
|
||||
|
||||
contentDialog.PrimaryButtonClick -= DeferClose;
|
||||
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
Task.Run(() =>
|
||||
{
|
||||
deferResetEvent.WaitOne();
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
deferral.Complete();
|
||||
});
|
||||
});
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
|
||||
if (doWhileDeferred != null)
|
||||
{
|
||||
await doWhileDeferred(window);
|
||||
|
||||
deferResetEvent.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Grid CreateDialogTextContent(string primaryText, string secondaryText, int symbol)
|
||||
{
|
||||
Grid content = new Grid();
|
||||
content.RowDefinitions = new RowDefinitions() { new RowDefinition(), new RowDefinition() };
|
||||
content.ColumnDefinitions = new ColumnDefinitions() { new ColumnDefinition(GridLength.Auto), new ColumnDefinition() };
|
||||
|
||||
content.MinHeight = 80;
|
||||
|
||||
SymbolIcon icon = new SymbolIcon { Symbol = (Symbol)symbol, Margin = new Avalonia.Thickness(10) };
|
||||
icon.FontSize = 40;
|
||||
icon.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center;
|
||||
Grid.SetColumn(icon, 0);
|
||||
Grid.SetRowSpan(icon, 2);
|
||||
Grid.SetRow(icon, 0);
|
||||
|
||||
TextBlock primaryLabel = new TextBlock()
|
||||
{
|
||||
Text = primaryText,
|
||||
Margin = new Avalonia.Thickness(5),
|
||||
TextWrapping = Avalonia.Media.TextWrapping.Wrap,
|
||||
MaxWidth = 450
|
||||
};
|
||||
TextBlock secondaryLabel = new TextBlock()
|
||||
{
|
||||
Text = secondaryText,
|
||||
Margin = new Avalonia.Thickness(5),
|
||||
TextWrapping = Avalonia.Media.TextWrapping.Wrap,
|
||||
MaxWidth = 450
|
||||
};
|
||||
|
||||
Grid.SetColumn(primaryLabel, 1);
|
||||
Grid.SetColumn(secondaryLabel, 1);
|
||||
Grid.SetRow(primaryLabel, 0);
|
||||
Grid.SetRow(secondaryLabel, 1);
|
||||
|
||||
content.Children.Add(icon);
|
||||
content.Children.Add(primaryLabel);
|
||||
content.Children.Add(secondaryLabel);
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
public static async Task<UserResult> CreateInfoDialog(
|
||||
string primary,
|
||||
string secondaryText,
|
||||
string acceptButton,
|
||||
string closeButton,
|
||||
string title)
|
||||
{
|
||||
return await ShowContentDialog(
|
||||
title,
|
||||
primary,
|
||||
secondaryText,
|
||||
acceptButton,
|
||||
"",
|
||||
closeButton,
|
||||
(int)Symbol.Important);
|
||||
}
|
||||
|
||||
internal static async Task<UserResult> CreateConfirmationDialog(
|
||||
string primaryText,
|
||||
string secondaryText,
|
||||
string acceptButtonText,
|
||||
string cancelButtonText,
|
||||
string title,
|
||||
UserResult primaryButtonResult = UserResult.Yes)
|
||||
{
|
||||
return await ShowContentDialog(
|
||||
string.IsNullOrWhiteSpace(title) ? LocaleManager.Instance["DialogConfirmationTitle"] : title,
|
||||
primaryText,
|
||||
secondaryText,
|
||||
acceptButtonText,
|
||||
"",
|
||||
cancelButtonText,
|
||||
(int)Symbol.Help,
|
||||
primaryButtonResult);
|
||||
}
|
||||
|
||||
internal static UpdateWaitWindow CreateWaitingDialog(string mainText, string secondaryText)
|
||||
{
|
||||
return new(mainText, secondaryText);
|
||||
}
|
||||
|
||||
internal static async Task CreateUpdaterInfoDialog(string primary, string secondaryText)
|
||||
{
|
||||
await ShowContentDialog(
|
||||
LocaleManager.Instance["DialogUpdaterTitle"],
|
||||
primary,
|
||||
secondaryText,
|
||||
"",
|
||||
"",
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
(int)Symbol.Important);
|
||||
}
|
||||
|
||||
internal static async Task CreateWarningDialog(string primary, string secondaryText)
|
||||
{
|
||||
await ShowContentDialog(
|
||||
LocaleManager.Instance["DialogWarningTitle"],
|
||||
primary,
|
||||
secondaryText,
|
||||
"",
|
||||
"",
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
(int)Symbol.Important);
|
||||
}
|
||||
|
||||
internal static async Task CreateErrorDialog(string errorMessage, string secondaryErrorMessage = "")
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, errorMessage);
|
||||
|
||||
await ShowContentDialog(
|
||||
LocaleManager.Instance["DialogErrorTitle"],
|
||||
LocaleManager.Instance["DialogErrorMessage"],
|
||||
errorMessage,
|
||||
secondaryErrorMessage,
|
||||
"",
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
(int)Symbol.Dismiss);
|
||||
}
|
||||
|
||||
internal static async Task<bool> CreateChoiceDialog(string title, string primary, string secondaryText)
|
||||
{
|
||||
if (_isChoiceDialogOpen)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_isChoiceDialogOpen = true;
|
||||
|
||||
UserResult response =
|
||||
await ShowContentDialog(
|
||||
title,
|
||||
primary,
|
||||
secondaryText,
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
"",
|
||||
LocaleManager.Instance["InputDialogNo"],
|
||||
(int)Symbol.Help,
|
||||
UserResult.Yes);
|
||||
|
||||
_isChoiceDialogOpen = false;
|
||||
|
||||
return response == UserResult.Yes;
|
||||
}
|
||||
|
||||
internal static async Task<bool> CreateExitDialog()
|
||||
{
|
||||
return await CreateChoiceDialog(
|
||||
LocaleManager.Instance["DialogExitTitle"],
|
||||
LocaleManager.Instance["DialogExitMessage"],
|
||||
LocaleManager.Instance["DialogExitSubMessage"]);
|
||||
}
|
||||
|
||||
internal static async Task<bool> CreateStopEmulationDialog()
|
||||
{
|
||||
return await CreateChoiceDialog(
|
||||
LocaleManager.Instance["DialogStopEmulationTitle"],
|
||||
LocaleManager.Instance["DialogStopEmulationMessage"],
|
||||
LocaleManager.Instance["DialogExitSubMessage"]);
|
||||
}
|
||||
|
||||
internal static async Task<string> CreateInputDialog(
|
||||
string title,
|
||||
string mainText,
|
||||
string subText,
|
||||
uint maxLength = int.MaxValue,
|
||||
string input = "")
|
||||
{
|
||||
var result = await InputDialog.ShowInputDialog(
|
||||
title,
|
||||
mainText,
|
||||
input,
|
||||
subText,
|
||||
maxLength);
|
||||
|
||||
if (result.Result == UserResult.Ok)
|
||||
{
|
||||
return result.Input;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,219 +0,0 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.GameGridView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
|
||||
<MenuItem
|
||||
Command="{Binding ToggleFavorite}"
|
||||
Header="{locale:Locale GameListContextMenuToggleFavorite}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuToggleFavoriteToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Command="{Binding OpenUserSaveDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenUserSaveDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenDeviceSaveDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenUserDeviceDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserDeviceDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenBcatSaveDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenUserBcatDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserBcatDirectoryToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Command="{Binding OpenTitleUpdateManager}"
|
||||
Header="{locale:Locale GameListContextMenuManageTitleUpdates}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageTitleUpdatesToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenDownloadableContentManager}"
|
||||
Header="{locale:Locale GameListContextMenuManageDlc}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageDlcToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenCheatManager}"
|
||||
Header="{locale:Locale GameListContextMenuManageCheat}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageCheatToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenModsDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenModsDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenModsDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenSdModsDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenSdModsDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenSdModsDirectoryToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem Header="{locale:Locale GameListContextMenuCacheManagement}">
|
||||
<MenuItem
|
||||
Command="{Binding PurgePtcCache}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementPurgePptc}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgePptcToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding PurgeShaderCache}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCache}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCacheToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenPtcDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenShaderCacheDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip}" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="{locale:Locale GameListContextMenuExtractData}">
|
||||
<MenuItem
|
||||
Command="{Binding ExtractExeFs}"
|
||||
Header="{locale:Locale GameListContextMenuExtractDataExeFS}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataExeFSToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding ExtractRomFs}"
|
||||
Header="{locale:Locale GameListContextMenuExtractDataRomFS}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataRomFSToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding ExtractLogo}"
|
||||
Header="{locale:Locale GameListContextMenuExtractDataLogo}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataLogoToolTip}" />
|
||||
</MenuItem>
|
||||
</MenuFlyout>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ListBox
|
||||
Grid.Row="0"
|
||||
Padding="8"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
ContextFlyout="{StaticResource GameContextMenu}"
|
||||
DoubleTapped="GameList_DoubleTapped"
|
||||
Items="{Binding AppsObservableList}"
|
||||
SelectionChanged="GameList_SelectionChanged">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<flex:FlexPanel
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
AlignContent="FlexStart"
|
||||
JustifyContent="Center" />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
<ListBox.Styles>
|
||||
<Style Selector="ListBoxItem">
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="Margin" Value="5" />
|
||||
<Setter Property="CornerRadius" Value="5" />
|
||||
<Setter Property="Background" Value="{DynamicResource SystemAccentColorDark3}" />
|
||||
<Style.Animations>
|
||||
<Animation Duration="0:0:0.7">
|
||||
<KeyFrame Cue="0%">
|
||||
<Setter Property="MaxWidth" Value="0" />
|
||||
<Setter Property="Opacity" Value="0.0" />
|
||||
</KeyFrame>
|
||||
<KeyFrame Cue="50%">
|
||||
<Setter Property="MaxWidth" Value="1000" />
|
||||
<Setter Property="Opacity" Value="0.3" />
|
||||
</KeyFrame>
|
||||
<KeyFrame Cue="100%">
|
||||
<Setter Property="MaxWidth" Value="1000" />
|
||||
<Setter Property="Opacity" Value="1.0" />
|
||||
</KeyFrame>
|
||||
</Animation>
|
||||
</Style.Animations>
|
||||
</Style>
|
||||
</ListBox.Styles>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.Styles>
|
||||
<Style Selector="ui|SymbolIcon.small.icon">
|
||||
<Setter Property="FontSize" Value="15" />
|
||||
</Style>
|
||||
<Style Selector="ui|SymbolIcon.normal.icon">
|
||||
<Setter Property="FontSize" Value="19" />
|
||||
</Style>
|
||||
<Style Selector="ui|SymbolIcon.large.icon">
|
||||
<Setter Property="FontSize" Value="23" />
|
||||
</Style>
|
||||
<Style Selector="ui|SymbolIcon.huge.icon">
|
||||
<Setter Property="FontSize" Value="26" />
|
||||
</Style>
|
||||
</Grid.Styles>
|
||||
<Border
|
||||
Margin="0"
|
||||
Padding="{Binding $parent[UserControl].DataContext.GridItemPadding}"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
||||
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
|
||||
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
||||
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
||||
ClipToBounds="True"
|
||||
CornerRadius="5">
|
||||
<Grid Margin="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Grid.Row="0"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Height="50"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
IsVisible="{Binding $parent[UserControl].DataContext.ShowNames}">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding TitleName}"
|
||||
TextAlignment="Center"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ui:SymbolIcon
|
||||
Margin="5"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
||||
Classes.icon="true"
|
||||
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
|
||||
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
||||
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
||||
Foreground="Yellow"
|
||||
IsVisible="{Binding Favorite}"
|
||||
Symbol="StarFilled" />
|
||||
<ui:SymbolIcon
|
||||
Margin="5"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
||||
Classes.icon="true"
|
||||
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
|
||||
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
||||
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
||||
Foreground="Black"
|
||||
IsVisible="{Binding Favorite}"
|
||||
Symbol="Star" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,82 +0,0 @@
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using LibHac.Common;
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class GameGridView : UserControl
|
||||
{
|
||||
private ApplicationData _selectedApplication;
|
||||
public static readonly RoutedEvent<ApplicationOpenedEventArgs> ApplicationOpenedEvent =
|
||||
RoutedEvent.Register<GameGridView, ApplicationOpenedEventArgs>(nameof(ApplicationOpened), RoutingStrategies.Bubble);
|
||||
|
||||
public event EventHandler<ApplicationOpenedEventArgs> ApplicationOpened
|
||||
{
|
||||
add { AddHandler(ApplicationOpenedEvent, value); }
|
||||
remove { RemoveHandler(ApplicationOpenedEvent, value); }
|
||||
}
|
||||
|
||||
public void GameList_DoubleTapped(object sender, RoutedEventArgs args)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
if (listBox.SelectedItem is ApplicationData selected)
|
||||
{
|
||||
RaiseEvent(new ApplicationOpenedEventArgs(selected, ApplicationOpenedEvent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void GameList_SelectionChanged(object sender, SelectionChangedEventArgs args)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
var selected = listBox.SelectedItem as ApplicationData;
|
||||
|
||||
_selectedApplication = selected;
|
||||
}
|
||||
}
|
||||
|
||||
public ApplicationData SelectedApplication => _selectedApplication;
|
||||
|
||||
public GameGridView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
(DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
|
||||
}
|
||||
|
||||
private void MenuBase_OnMenuOpened(object sender, EventArgs e)
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
if (selection != null)
|
||||
{
|
||||
if (sender is ContextMenu menu)
|
||||
{
|
||||
bool canHaveUserSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.UserAccountSaveDataSize > 0;
|
||||
bool canHaveDeviceSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.DeviceSaveDataSize > 0;
|
||||
bool canHaveBcatSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
|
||||
|
||||
((menu.Items as AvaloniaList<object>)[2] as MenuItem).IsEnabled = canHaveUserSave;
|
||||
((menu.Items as AvaloniaList<object>)[3] as MenuItem).IsEnabled = canHaveDeviceSave;
|
||||
((menu.Items as AvaloniaList<object>)[4] as MenuItem).IsEnabled = canHaveBcatSave;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,238 +0,0 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.GameListView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
|
||||
<MenuItem
|
||||
Command="{Binding ToggleFavorite}"
|
||||
Header="{locale:Locale GameListContextMenuToggleFavorite}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuToggleFavoriteToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Command="{Binding OpenUserSaveDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenUserSaveDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenDeviceSaveDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenUserDeviceDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserDeviceDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenBcatSaveDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenUserBcatDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserBcatDirectoryToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Command="{Binding OpenTitleUpdateManager}"
|
||||
Header="{locale:Locale GameListContextMenuManageTitleUpdates}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageTitleUpdatesToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenDownloadableContentManager}"
|
||||
Header="{locale:Locale GameListContextMenuManageDlc}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageDlcToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenCheatManager}"
|
||||
Header="{locale:Locale GameListContextMenuManageCheat}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuManageCheatToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenModsDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenModsDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenModsDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenSdModsDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenSdModsDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenSdModsDirectoryToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem Header="{locale:Locale GameListContextMenuCacheManagement}">
|
||||
<MenuItem
|
||||
Command="{Binding PurgePtcCache}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementPurgePptc}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgePptcToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding PurgeShaderCache}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCache}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCacheToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenPtcDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenShaderCacheDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip}" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="{locale:Locale GameListContextMenuExtractData}">
|
||||
<MenuItem
|
||||
Command="{Binding ExtractExeFs}"
|
||||
Header="{locale:Locale GameListContextMenuExtractDataExeFS}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataExeFSToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding ExtractRomFs}"
|
||||
Header="{locale:Locale GameListContextMenuExtractDataRomFS}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataRomFSToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding ExtractLogo}"
|
||||
Header="{locale:Locale GameListContextMenuExtractDataLogo}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataLogoToolTip}" />
|
||||
</MenuItem>
|
||||
</MenuFlyout>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<ListBox
|
||||
Name="GameListBox"
|
||||
Grid.Row="0"
|
||||
Padding="8"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
ContextFlyout="{StaticResource GameContextMenu}"
|
||||
DoubleTapped="GameList_DoubleTapped"
|
||||
Items="{Binding AppsObservableList}"
|
||||
SelectionChanged="GameList_SelectionChanged">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="2" />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
<ListBox.Styles>
|
||||
<Style Selector="ListBoxItem">
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="CornerRadius" Value="5" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource SystemAccentColorDark3}" />
|
||||
<Setter Property="BorderThickness" Value="2" />
|
||||
<Style.Animations>
|
||||
<Animation Duration="0:0:0.7">
|
||||
<KeyFrame Cue="0%">
|
||||
<Setter Property="MaxHeight" Value="0" />
|
||||
<Setter Property="Opacity" Value="0.0" />
|
||||
</KeyFrame>
|
||||
<KeyFrame Cue="50%">
|
||||
<Setter Property="MaxHeight" Value="1000" />
|
||||
<Setter Property="Opacity" Value="0.3" />
|
||||
</KeyFrame>
|
||||
<KeyFrame Cue="100%">
|
||||
<Setter Property="MaxHeight" Value="1000" />
|
||||
<Setter Property="Opacity" Value="1.0" />
|
||||
</KeyFrame>
|
||||
</Animation>
|
||||
</Style.Animations>
|
||||
</Style>
|
||||
</ListBox.Styles>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Border
|
||||
Margin="0"
|
||||
Padding="10"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
ClipToBounds="True"
|
||||
CornerRadius="5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="10" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Grid.RowSpan="3"
|
||||
Grid.Column="0"
|
||||
Margin="0"
|
||||
Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
|
||||
Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
|
||||
Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
|
||||
Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
|
||||
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
|
||||
<StackPanel
|
||||
Grid.Column="2"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Orientation="Vertical"
|
||||
Spacing="5">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding TitleName}"
|
||||
TextAlignment="Left"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding Developer}"
|
||||
TextAlignment="Left"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding Version}"
|
||||
TextAlignment="Left"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Grid.Column="3"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Orientation="Vertical"
|
||||
Spacing="5">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding TimePlayed}"
|
||||
TextAlignment="Right"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding LastPlayed}"
|
||||
TextAlignment="Right"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding FileSize}"
|
||||
TextAlignment="Right"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
<ui:SymbolIcon
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="-5,-5,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
FontSize="20"
|
||||
Foreground="Yellow"
|
||||
IsVisible="{Binding Favorite}"
|
||||
Symbol="StarFilled" />
|
||||
<ui:SymbolIcon
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="-5,-5,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
FontSize="20"
|
||||
Foreground="Black"
|
||||
IsVisible="{Binding Favorite}"
|
||||
Symbol="Star" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,82 +0,0 @@
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using LibHac.Common;
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class GameListView : UserControl
|
||||
{
|
||||
private ApplicationData _selectedApplication;
|
||||
public static readonly RoutedEvent<ApplicationOpenedEventArgs> ApplicationOpenedEvent =
|
||||
RoutedEvent.Register<GameGridView, ApplicationOpenedEventArgs>(nameof(ApplicationOpened), RoutingStrategies.Bubble);
|
||||
|
||||
public event EventHandler<ApplicationOpenedEventArgs> ApplicationOpened
|
||||
{
|
||||
add { AddHandler(ApplicationOpenedEvent, value); }
|
||||
remove { RemoveHandler(ApplicationOpenedEvent, value); }
|
||||
}
|
||||
|
||||
public void GameList_DoubleTapped(object sender, RoutedEventArgs args)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
if (listBox.SelectedItem is ApplicationData selected)
|
||||
{
|
||||
RaiseEvent(new ApplicationOpenedEventArgs(selected, ApplicationOpenedEvent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void GameList_SelectionChanged(object sender, SelectionChangedEventArgs args)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
var selected = listBox.SelectedItem as ApplicationData;
|
||||
|
||||
_selectedApplication = selected;
|
||||
}
|
||||
}
|
||||
|
||||
public ApplicationData SelectedApplication => _selectedApplication;
|
||||
|
||||
public GameListView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
(DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
|
||||
}
|
||||
|
||||
private void MenuBase_OnMenuOpened(object sender, EventArgs e)
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
if (selection != null)
|
||||
{
|
||||
if (sender is ContextMenu menu)
|
||||
{
|
||||
bool canHaveUserSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.UserAccountSaveDataSize > 0;
|
||||
bool canHaveDeviceSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.DeviceSaveDataSize > 0;
|
||||
bool canHaveBcatSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
|
||||
|
||||
((menu.Items as AvaloniaList<object>)[2] as MenuItem).IsEnabled = canHaveUserSave;
|
||||
((menu.Items as AvaloniaList<object>)[3] as MenuItem).IsEnabled = canHaveDeviceSave;
|
||||
((menu.Items as AvaloniaList<object>)[4] as MenuItem).IsEnabled = canHaveBcatSave;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public enum Glyph : int
|
||||
{
|
||||
List,
|
||||
Grid,
|
||||
Chip
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
using Avalonia.OpenGL;
|
||||
using SPB.Graphics.OpenGL;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
internal static class IGlContextExtension
|
||||
{
|
||||
public static OpenGLContextBase AsOpenGLContextBase(this IGlContext context)
|
||||
{
|
||||
var handle = (IntPtr)context.GetType().GetProperty("Handle").GetValue(context);
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
return new AvaloniaWglContext(handle);
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
return new AvaloniaGlxContext(handle);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.InputDialog"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
<Grid
|
||||
Margin="5,10,5,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock HorizontalAlignment="Center" Text="{Binding Message}" />
|
||||
<TextBox
|
||||
Grid.Row="1"
|
||||
Width="300"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Center"
|
||||
MaxLength="{Binding MaxLength}"
|
||||
Text="{Binding Input, Mode=TwoWay}" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Margin="5,5,5,10"
|
||||
HorizontalAlignment="Center"
|
||||
Text="{Binding SubMessage}" />
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,56 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.Models;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class InputDialog : UserControl
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public string Input { get; set; }
|
||||
public string SubMessage { get; set; }
|
||||
|
||||
public uint MaxLength { get; }
|
||||
|
||||
public InputDialog(string message, string input = "", string subMessage = "", uint maxLength = int.MaxValue)
|
||||
{
|
||||
Message = message;
|
||||
Input = input;
|
||||
SubMessage = subMessage;
|
||||
MaxLength = maxLength;
|
||||
|
||||
DataContext = this;
|
||||
}
|
||||
|
||||
public InputDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public static async Task<(UserResult Result, string Input)> ShowInputDialog(string title, string message,
|
||||
string input = "", string subMessage = "", uint maxLength = int.MaxValue)
|
||||
{
|
||||
UserResult result = UserResult.Cancel;
|
||||
|
||||
InputDialog content = new InputDialog(message, input, subMessage, maxLength);
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = title,
|
||||
PrimaryButtonText = LocaleManager.Instance["InputDialogOk"],
|
||||
SecondaryButtonText = "",
|
||||
CloseButtonText = LocaleManager.Instance["InputDialogCancel"],
|
||||
Content = content,
|
||||
PrimaryButtonCommand = MiniCommand.Create(() =>
|
||||
{
|
||||
result = UserResult.Ok;
|
||||
input = content.Input;
|
||||
})
|
||||
};
|
||||
await contentDialog.ShowAsync();
|
||||
|
||||
return (result, input);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.NavigationDialogHost">
|
||||
<ui:Frame HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
|
||||
x:Name="ContentFrame" />
|
||||
</UserControl>
|
@ -1,85 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class NavigationDialogHost : UserControl
|
||||
{
|
||||
public AccountManager AccountManager { get; }
|
||||
public ContentManager ContentManager { get; }
|
||||
public UserProfileViewModel ViewModel { get; set; }
|
||||
|
||||
public NavigationDialogHost()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public NavigationDialogHost(AccountManager accountManager, ContentManager contentManager,
|
||||
VirtualFileSystem virtualFileSystem)
|
||||
{
|
||||
AccountManager = accountManager;
|
||||
ContentManager = contentManager;
|
||||
ViewModel = new UserProfileViewModel(this);
|
||||
|
||||
|
||||
if (contentManager.GetCurrentFirmwareVersion() != null)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
AvatarProfileViewModel.PreloadAvatars(contentManager, virtualFileSystem);
|
||||
});
|
||||
}
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void GoBack(object parameter = null)
|
||||
{
|
||||
if (ContentFrame.BackStack.Count > 0)
|
||||
{
|
||||
ContentFrame.GoBack();
|
||||
}
|
||||
|
||||
ViewModel.LoadProfiles();
|
||||
}
|
||||
|
||||
public void Navigate(Type sourcePageType, object parameter)
|
||||
{
|
||||
ContentFrame.Navigate(sourcePageType, parameter);
|
||||
}
|
||||
|
||||
public static async Task Show(AccountManager ownerAccountManager, ContentManager ownerContentManager, VirtualFileSystem ownerVirtualFileSystem)
|
||||
{
|
||||
var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem);
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = LocaleManager.Instance["UserProfileWindowTitle"],
|
||||
PrimaryButtonText = "",
|
||||
SecondaryButtonText = "",
|
||||
CloseButtonText = LocaleManager.Instance["UserProfilesClose"],
|
||||
Content = content,
|
||||
Padding = new Thickness(0)
|
||||
};
|
||||
|
||||
contentDialog.Closed += (sender, args) =>
|
||||
{
|
||||
content.ViewModel.Dispose();
|
||||
};
|
||||
|
||||
await contentDialog.ShowAsync();
|
||||
}
|
||||
|
||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnAttachedToVisualTree(e);
|
||||
|
||||
Navigate(typeof(UserSelector), this);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,192 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.OpenGL;
|
||||
using Avalonia.Platform;
|
||||
using Avalonia.Rendering.SceneGraph;
|
||||
using Avalonia.Skia;
|
||||
using Avalonia.Threading;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using SkiaSharp;
|
||||
using SPB.Graphics;
|
||||
using SPB.Graphics.OpenGL;
|
||||
using SPB.Platform;
|
||||
using SPB.Windowing;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
internal class OpenGLRendererControl : RendererControl
|
||||
{
|
||||
public int Major { get; }
|
||||
public int Minor { get; }
|
||||
public OpenGLContextBase GameContext { get; set; }
|
||||
|
||||
public static OpenGLContextBase PrimaryContext =>
|
||||
AvaloniaLocator.Current.GetService<IPlatformOpenGlInterface>()
|
||||
.PrimaryContext.AsOpenGLContextBase();
|
||||
|
||||
private SwappableNativeWindowBase _gameBackgroundWindow;
|
||||
|
||||
private IntPtr _fence;
|
||||
|
||||
public OpenGLRendererControl(int major, int minor, GraphicsDebugLevel graphicsDebugLevel) : base(graphicsDebugLevel)
|
||||
{
|
||||
Major = major;
|
||||
Minor = minor;
|
||||
}
|
||||
|
||||
public override void DestroyBackgroundContext()
|
||||
{
|
||||
Image = null;
|
||||
|
||||
if (_fence != IntPtr.Zero)
|
||||
{
|
||||
DrawOperation.Dispose();
|
||||
GL.DeleteSync(_fence);
|
||||
}
|
||||
|
||||
GlDrawOperation.DeleteFramebuffer();
|
||||
|
||||
GameContext?.Dispose();
|
||||
|
||||
_gameBackgroundWindow?.Dispose();
|
||||
}
|
||||
|
||||
internal override void Present(object image)
|
||||
{
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
Image = (int)image;
|
||||
|
||||
InvalidateVisual();
|
||||
}).Wait();
|
||||
|
||||
if (_fence != IntPtr.Zero)
|
||||
{
|
||||
GL.DeleteSync(_fence);
|
||||
}
|
||||
|
||||
_fence = GL.FenceSync(SyncCondition.SyncGpuCommandsComplete, WaitSyncFlags.None);
|
||||
|
||||
InvalidateVisual();
|
||||
|
||||
_gameBackgroundWindow.SwapBuffers();
|
||||
}
|
||||
|
||||
internal override void MakeCurrent()
|
||||
{
|
||||
GameContext.MakeCurrent(_gameBackgroundWindow);
|
||||
}
|
||||
|
||||
internal override void MakeCurrent(SwappableNativeWindowBase window)
|
||||
{
|
||||
GameContext.MakeCurrent(window);
|
||||
}
|
||||
|
||||
protected override void CreateWindow()
|
||||
{
|
||||
var flags = OpenGLContextFlags.Compat;
|
||||
if (DebugLevel != GraphicsDebugLevel.None)
|
||||
{
|
||||
flags |= OpenGLContextFlags.Debug;
|
||||
}
|
||||
_gameBackgroundWindow = PlatformHelper.CreateOpenGLWindow(FramebufferFormat.Default, 0, 0, 100, 100);
|
||||
_gameBackgroundWindow.Hide();
|
||||
|
||||
GameContext = PlatformHelper.CreateOpenGLContext(FramebufferFormat.Default, Major, Minor, flags, shareContext: PrimaryContext);
|
||||
GameContext.Initialize(_gameBackgroundWindow);
|
||||
}
|
||||
|
||||
protected override ICustomDrawOperation CreateDrawOperation()
|
||||
{
|
||||
return new GlDrawOperation(this);
|
||||
}
|
||||
|
||||
private class GlDrawOperation : ICustomDrawOperation
|
||||
{
|
||||
private static int _framebuffer;
|
||||
|
||||
public Rect Bounds { get; }
|
||||
|
||||
private readonly OpenGLRendererControl _control;
|
||||
|
||||
public GlDrawOperation(OpenGLRendererControl control)
|
||||
{
|
||||
_control = control;
|
||||
Bounds = _control.Bounds;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public static void DeleteFramebuffer()
|
||||
{
|
||||
if (_framebuffer == 0)
|
||||
{
|
||||
GL.DeleteFramebuffer(_framebuffer);
|
||||
}
|
||||
|
||||
_framebuffer = 0;
|
||||
}
|
||||
|
||||
public bool Equals(ICustomDrawOperation other)
|
||||
{
|
||||
return other is GlDrawOperation operation && Equals(this, operation) && operation.Bounds == Bounds;
|
||||
}
|
||||
|
||||
public bool HitTest(Point p)
|
||||
{
|
||||
return Bounds.Contains(p);
|
||||
}
|
||||
|
||||
private void CreateRenderTarget()
|
||||
{
|
||||
_framebuffer = GL.GenFramebuffer();
|
||||
}
|
||||
|
||||
public void Render(IDrawingContextImpl context)
|
||||
{
|
||||
if (_control.Image == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_framebuffer == 0)
|
||||
{
|
||||
CreateRenderTarget();
|
||||
}
|
||||
|
||||
int currentFramebuffer = GL.GetInteger(GetPName.FramebufferBinding);
|
||||
|
||||
var image = _control.Image;
|
||||
var fence = _control._fence;
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, _framebuffer);
|
||||
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, (int)image, 0);
|
||||
GL.BindFramebuffer(FramebufferTarget.Framebuffer, currentFramebuffer);
|
||||
|
||||
if (context is not ISkiaDrawingContextImpl skiaDrawingContextImpl)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var imageInfo = new SKImageInfo((int)_control.RenderSize.Width, (int)_control.RenderSize.Height, SKColorType.Rgba8888);
|
||||
var glInfo = new GRGlFramebufferInfo((uint)_framebuffer, SKColorType.Rgba8888.ToGlSizedFormat());
|
||||
|
||||
GL.WaitSync(fence, WaitSyncFlags.None, ulong.MaxValue);
|
||||
|
||||
using var backendTexture = new GRBackendRenderTarget(imageInfo.Width, imageInfo.Height, 1, 0, glInfo);
|
||||
using var surface = SKSurface.Create(skiaDrawingContextImpl.GrContext, backendTexture, GRSurfaceOrigin.BottomLeft, SKColorType.Rgba8888);
|
||||
|
||||
if (surface == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var rect = new Rect(new Point(), _control.RenderSize);
|
||||
|
||||
using var snapshot = surface.Snapshot();
|
||||
skiaDrawingContextImpl.SkCanvas.DrawImage(snapshot, rect.ToSKRect(), _control.Bounds.ToSKRect(), new SKPaint());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.ProfileImageSelectionDialog">
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="5,10,5, 5">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="70" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock FontWeight="Bold" FontSize="18" HorizontalAlignment="Center" Grid.Row="1"
|
||||
Text="{Locale:Locale ProfileImageSelectionHeader}" />
|
||||
<TextBlock FontWeight="Bold" Grid.Row="2" Margin="10" MaxWidth="400" TextWrapping="Wrap"
|
||||
HorizontalAlignment="Center" TextAlignment="Center" Text="{Locale:Locale ProfileImageSelectionNote}" />
|
||||
<StackPanel Margin="5,0" Spacing="10" Grid.Row="4" HorizontalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
<Button Name="Import" Click="Import_OnClick" Width="200">
|
||||
<TextBlock Text="{Locale:Locale ProfileImageSelectionImportImage}" />
|
||||
</Button>
|
||||
<Button Name="SelectFirmwareImage" IsEnabled="{Binding FirmwareFound}" Click="SelectFirmwareImage_OnClick"
|
||||
Width="200">
|
||||
<TextBlock Text="{Locale:Locale ProfileImageSelectionSelectAvatar}" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,100 +0,0 @@
|
||||
using Avalonia.Rendering;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Timers;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
internal class RenderTimer : IRenderTimer, IDisposable
|
||||
{
|
||||
public event Action<TimeSpan> Tick
|
||||
{
|
||||
add
|
||||
{
|
||||
_tick += value;
|
||||
|
||||
if (_subscriberCount++ == 0)
|
||||
{
|
||||
Start();
|
||||
}
|
||||
}
|
||||
|
||||
remove
|
||||
{
|
||||
if (--_subscriberCount == 0)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
_tick -= value;
|
||||
}
|
||||
}
|
||||
|
||||
private Thread _tickThread;
|
||||
private readonly System.Timers.Timer _timer;
|
||||
|
||||
private Action<TimeSpan> _tick;
|
||||
private int _subscriberCount;
|
||||
|
||||
private bool _isRunning;
|
||||
|
||||
private AutoResetEvent _resetEvent;
|
||||
|
||||
public RenderTimer()
|
||||
{
|
||||
_timer = new System.Timers.Timer(15);
|
||||
_resetEvent = new AutoResetEvent(true);
|
||||
_timer.Elapsed += Timer_Elapsed;
|
||||
}
|
||||
|
||||
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
TickNow();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_timer.Start();
|
||||
if (_tickThread == null)
|
||||
{
|
||||
_tickThread = new Thread(RunTick);
|
||||
_tickThread.Name = "RenderTimerTickThread";
|
||||
_tickThread.IsBackground = true;
|
||||
_isRunning = true;
|
||||
_tickThread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public void RunTick()
|
||||
{
|
||||
while (_isRunning)
|
||||
{
|
||||
_resetEvent.WaitOne();
|
||||
_tick?.Invoke(TimeSpan.FromMilliseconds(Environment.TickCount));
|
||||
}
|
||||
}
|
||||
|
||||
public void TickNow()
|
||||
{
|
||||
lock (_timer)
|
||||
{
|
||||
_resetEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_timer.Stop();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_timer.Elapsed -= Timer_Elapsed;
|
||||
_timer.Stop();
|
||||
_isRunning = false;
|
||||
_resetEvent.Set();
|
||||
_tickThread.Join();
|
||||
_resetEvent.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Rendering.SceneGraph;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using SPB.Windowing;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
internal abstract class RendererControl : Control
|
||||
{
|
||||
protected object Image { get; set; }
|
||||
|
||||
public event EventHandler<EventArgs> RendererInitialized;
|
||||
public event EventHandler<Size> SizeChanged;
|
||||
|
||||
protected Size RenderSize { get; private set; }
|
||||
public bool IsStarted { get; private set; }
|
||||
|
||||
public GraphicsDebugLevel DebugLevel { get; }
|
||||
|
||||
private bool _isInitialized;
|
||||
|
||||
protected ICustomDrawOperation DrawOperation { get; private set; }
|
||||
|
||||
public RendererControl(GraphicsDebugLevel graphicsDebugLevel)
|
||||
{
|
||||
DebugLevel = graphicsDebugLevel;
|
||||
IObservable<Rect> resizeObservable = this.GetObservable(BoundsProperty);
|
||||
|
||||
resizeObservable.Subscribe(Resized);
|
||||
|
||||
Focusable = true;
|
||||
}
|
||||
|
||||
protected void Resized(Rect rect)
|
||||
{
|
||||
SizeChanged?.Invoke(this, rect.Size);
|
||||
|
||||
if (!rect.IsEmpty)
|
||||
{
|
||||
RenderSize = rect.Size * VisualRoot.RenderScaling;
|
||||
DrawOperation = CreateDrawOperation();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract ICustomDrawOperation CreateDrawOperation();
|
||||
protected abstract void CreateWindow();
|
||||
|
||||
public override void Render(DrawingContext context)
|
||||
{
|
||||
if (!_isInitialized)
|
||||
{
|
||||
CreateWindow();
|
||||
|
||||
OnRendererInitialized();
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
||||
if (!IsStarted || Image == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (DrawOperation != null)
|
||||
{
|
||||
context.Custom(DrawOperation);
|
||||
}
|
||||
|
||||
base.Render(context);
|
||||
}
|
||||
|
||||
protected void OnRendererInitialized()
|
||||
{
|
||||
RendererInitialized?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
internal abstract void Present(object image);
|
||||
|
||||
internal void Start()
|
||||
{
|
||||
IsStarted = true;
|
||||
}
|
||||
|
||||
internal void Stop()
|
||||
{
|
||||
IsStarted = false;
|
||||
}
|
||||
|
||||
public abstract void DestroyBackgroundContext();
|
||||
internal abstract void MakeCurrent();
|
||||
internal abstract void MakeCurrent(SwappableNativeWindowBase window);
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using Ryujinx.Ava.Ui.Windows;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class UpdateWaitWindow : StyleableWindow
|
||||
{
|
||||
public UpdateWaitWindow(string primaryText, string secondaryText) : this()
|
||||
{
|
||||
PrimaryText.Text = primaryText;
|
||||
SecondaryText.Text = secondaryText;
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||
}
|
||||
|
||||
public UpdateWaitWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.UserEditor"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:models="clr-namespace:Ryujinx.Ava.Ui.Models"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
||||
Margin="0"
|
||||
Padding="0"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Stretch"
|
||||
Orientation="Vertical">
|
||||
<Image
|
||||
Name="ProfileImage"
|
||||
Width="96"
|
||||
Height="96"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
Source="{Binding Image, Converter={StaticResource ByteImage}}" />
|
||||
<Button
|
||||
Name="ChangePictureButton"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="ChangePictureButton_Click"
|
||||
Content="{Locale:Locale UserProfilesChangeProfileImage}" />
|
||||
<Button
|
||||
Name="AddPictureButton"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="ChangePictureButton_Click"
|
||||
Content="{Locale:Locale UserProfilesSetProfileImage}" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="5,10"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Vertical"
|
||||
Spacing="10">
|
||||
<TextBlock Text="{Locale:Locale UserProfilesName}" />
|
||||
<TextBox
|
||||
Name="NameBox"
|
||||
Width="300"
|
||||
HorizontalAlignment="Stretch"
|
||||
MaxLength="{Binding MaxProfileNameLength}"
|
||||
Text="{Binding Name}" />
|
||||
<TextBlock Text="{Locale:Locale UserProfilesUserId}" />
|
||||
<TextBlock Name="IdLabel" Text="{Binding UserId}" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal"
|
||||
Spacing="10">
|
||||
<Button
|
||||
Name="SaveButton"
|
||||
Click="SaveButton_Click"
|
||||
Content="{Locale:Locale Save}" />
|
||||
<Button
|
||||
Name="CloseButton"
|
||||
HorizontalAlignment="Right"
|
||||
Click="CloseButton_Click"
|
||||
Content="{Locale:Locale Discard}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,123 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Interactivity;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using FluentAvalonia.UI.Navigation;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.Models;
|
||||
using UserProfile = Ryujinx.Ava.Ui.Models.UserProfile;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class UserEditor : UserControl
|
||||
{
|
||||
private NavigationDialogHost _parent;
|
||||
private UserProfile _profile;
|
||||
private bool _isNewUser;
|
||||
|
||||
public TempProfile TempProfile { get; set; }
|
||||
public uint MaxProfileNameLength => 0x20;
|
||||
|
||||
public UserEditor()
|
||||
{
|
||||
InitializeComponent();
|
||||
AddHandler(Frame.NavigatedToEvent, (s, e) =>
|
||||
{
|
||||
NavigatedTo(e);
|
||||
}, RoutingStrategies.Direct);
|
||||
}
|
||||
|
||||
private void NavigatedTo(NavigationEventArgs arg)
|
||||
{
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
switch (arg.NavigationMode)
|
||||
{
|
||||
case NavigationMode.New:
|
||||
var args = ((NavigationDialogHost parent, UserProfile profile, bool isNewUser))arg.Parameter;
|
||||
_isNewUser = args.isNewUser;
|
||||
if (!_isNewUser)
|
||||
{
|
||||
_profile = args.profile;
|
||||
TempProfile = new TempProfile(_profile);
|
||||
}
|
||||
else
|
||||
{
|
||||
TempProfile = new TempProfile();
|
||||
}
|
||||
|
||||
_parent = args.parent;
|
||||
break;
|
||||
}
|
||||
|
||||
DataContext = TempProfile;
|
||||
|
||||
AddPictureButton.IsVisible = _isNewUser;
|
||||
IdLabel.IsVisible = !_isNewUser;
|
||||
ChangePictureButton.IsVisible = !_isNewUser;
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_parent?.GoBack();
|
||||
}
|
||||
|
||||
private async void SaveButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DataValidationErrors.ClearErrors(NameBox);
|
||||
bool isInvalid = false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(TempProfile.Name))
|
||||
{
|
||||
DataValidationErrors.SetError(NameBox, new DataValidationException(LocaleManager.Instance["UserProfileEmptyNameError"]));
|
||||
|
||||
isInvalid = true;
|
||||
}
|
||||
|
||||
if (TempProfile.Image == null)
|
||||
{
|
||||
await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["UserProfileNoImageError"], "");
|
||||
|
||||
isInvalid = true;
|
||||
}
|
||||
|
||||
if(isInvalid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_profile != null)
|
||||
{
|
||||
_profile.Name = TempProfile.Name;
|
||||
_profile.Image = TempProfile.Image;
|
||||
_profile.UpdateState();
|
||||
_parent.AccountManager.SetUserName(_profile.UserId, _profile.Name);
|
||||
_parent.AccountManager.SetUserImage(_profile.UserId, _profile.Image);
|
||||
}
|
||||
else if (_isNewUser)
|
||||
{
|
||||
_parent.AccountManager.AddUser(TempProfile.Name, TempProfile.Image);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_parent?.GoBack();
|
||||
}
|
||||
|
||||
public void SelectProfileImage()
|
||||
{
|
||||
_parent.Navigate(typeof(ProfileImageSelectionDialog), (_parent, TempProfile));
|
||||
}
|
||||
|
||||
private void ChangePictureButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_profile != null || _isNewUser)
|
||||
{
|
||||
SelectProfileImage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.Ui.Controls.UserSelector"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:Locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:controls="clr-namespace:Ryujinx.Ava.Ui.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.Ui.ViewModels"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<controls:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||
</UserControl.Resources>
|
||||
<Design.DataContext>
|
||||
<viewModels:UserProfileViewModel />
|
||||
</Design.DataContext>
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<ListBox
|
||||
Margin="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
DoubleTapped="ProfilesList_DoubleTapped"
|
||||
Items="{Binding Profiles}"
|
||||
SelectionChanged="SelectingItemsControl_SelectionChanged">
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<flex:FlexPanel
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
AlignContent="FlexStart"
|
||||
JustifyContent="Center" />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Border
|
||||
Margin="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
ClipToBounds="True"
|
||||
CornerRadius="5">
|
||||
<Grid Margin="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Grid.Row="0"
|
||||
Width="96"
|
||||
Height="96"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
Source="{Binding Image, Converter={StaticResource ByteImage}}" />
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Height="30"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding Name}"
|
||||
TextAlignment="Center"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<Border
|
||||
Width="10"
|
||||
Height="10"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Background="LimeGreen"
|
||||
CornerRadius="5"
|
||||
IsVisible="{Binding IsOpened}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Margin="10,0"
|
||||
HorizontalAlignment="Center"
|
||||
Orientation="Horizontal"
|
||||
Spacing="10">
|
||||
<Button Command="{Binding AddUser}" Content="{Locale:Locale UserProfilesAddNewProfile}" />
|
||||
<Button
|
||||
Command="{Binding EditUser}"
|
||||
Content="{Locale:Locale UserProfilesEditProfile}"
|
||||
IsEnabled="{Binding IsSelectedProfiledEditable}" />
|
||||
<Button
|
||||
Command="{Binding DeleteUser}"
|
||||
Content="{Locale:Locale UserProfilesDeleteSelectedProfile}"
|
||||
IsEnabled="{Binding IsSelectedProfileDeletable}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,77 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using FluentAvalonia.UI.Navigation;
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using UserProfile = Ryujinx.Ava.Ui.Models.UserProfile;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
public partial class UserSelector : UserControl
|
||||
{
|
||||
private NavigationDialogHost _parent;
|
||||
public UserProfileViewModel ViewModel { get; set; }
|
||||
|
||||
public UserSelector()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
AddHandler(Frame.NavigatedToEvent, (s, e) =>
|
||||
{
|
||||
NavigatedTo(e);
|
||||
}, RoutingStrategies.Direct);
|
||||
}
|
||||
}
|
||||
|
||||
private void NavigatedTo(NavigationEventArgs arg)
|
||||
{
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
if (arg.NavigationMode == NavigationMode.New)
|
||||
{
|
||||
_parent = (NavigationDialogHost)arg.Parameter;
|
||||
ViewModel = _parent.ViewModel;
|
||||
}
|
||||
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProfilesList_DoubleTapped(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
int selectedIndex = listBox.SelectedIndex;
|
||||
|
||||
if (selectedIndex >= 0 && selectedIndex < ViewModel.Profiles.Count)
|
||||
{
|
||||
ViewModel.SelectedProfile = ViewModel.Profiles[selectedIndex];
|
||||
|
||||
_parent?.AccountManager?.OpenUser(ViewModel.SelectedProfile.UserId);
|
||||
|
||||
ViewModel.LoadProfiles();
|
||||
|
||||
foreach (UserProfile profile in ViewModel.Profiles)
|
||||
{
|
||||
profile.UpdateState();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectingItemsControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
int selectedIndex = listBox.SelectedIndex;
|
||||
|
||||
if (selectedIndex >= 0 && selectedIndex < ViewModel.Profiles.Count)
|
||||
{
|
||||
ViewModel.HighlightedProfile = ViewModel.Profiles[selectedIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user