Compare commits
326 Commits
Author | SHA1 | Date | |
---|---|---|---|
41b104d0fb | |||
bc44b85b0b | |||
01c2b8097c | |||
4bd2ca3f0d | |||
e63157cc33 | |||
7f2fb049f5 | |||
4744bde0e5 | |||
4a835bb2b9 | |||
ddc9ae2a83 | |||
d6d3cdd573 | |||
53bd4c9f60 | |||
eca8808649 | |||
f6c3f1cdfd | |||
8026e1c804 | |||
d9f9bbfaa6 | |||
fe9e19d8cc | |||
fb55f57da7 | |||
44862dce3e | |||
e601419bd4 | |||
d6bc0de785 | |||
9f26fd3600 | |||
88df636c87 | |||
7ccff037e8 | |||
a745913329 | |||
e6700b314f | |||
e2cfe6fe44 | |||
210f475484 | |||
ddb6493896 | |||
f631933e60 | |||
5ff6ea6d82 | |||
c2d9c6955d | |||
fbe0c211c1 | |||
db0f3c0b74 | |||
34447d7359 | |||
5f771f5661 | |||
93cd327873 | |||
12cbacffca | |||
437c78e198 | |||
f09bba82b9 | |||
93d78f9ac4 | |||
cd7b52f995 | |||
7f96dbc024 | |||
3e5c211394 | |||
153b8bfc7c | |||
c6a699414a | |||
2563f88de0 | |||
b0b7843d5c | |||
6ed613a6e6 | |||
64079c034c | |||
17354d59d1 | |||
0c445184c1 | |||
511b558ddc | |||
9b8625d999 | |||
b12ea343d0 | |||
abaa35ad3a | |||
effd546331 | |||
492a046335 | |||
550fd4a733 | |||
33f544fd92 | |||
b423197619 | |||
8edfb2bc7b | |||
ddefb4fff4 | |||
2efd74b9cb | |||
8c61ddd49d | |||
7b2225c6b0 | |||
fe15c77d30 | |||
5e9678c8fa | |||
773e239db7 | |||
42750a74f8 | |||
3ab0a71c7b | |||
6e784e0aca | |||
5a0aa074b6 | |||
93aa40f1fb | |||
bedee64af5 | |||
86931cc3f1 | |||
2be8b6ea45 | |||
f95b7c5877 | |||
eb528ae0f0 | |||
487261592e | |||
9e04e6cba1 | |||
4cf2419e6c | |||
440abac9f8 | |||
732714349e | |||
016262514d | |||
326749498b | |||
fec8291c17 | |||
c5d9e67cb2 | |||
e5261228d7 | |||
e61c09bc85 | |||
ac2444f908 | |||
9c6071a645 | |||
fa32ef9275 | |||
7805d27e67 | |||
6c515e1822 | |||
8a363b5df2 | |||
2b5abac809 | |||
c19c8bbade | |||
1c7a90ef35 | |||
3b46bb73f7 | |||
2457cfc911 | |||
515fc32b21 | |||
0684b00b3c | |||
02b5c7ea89 | |||
801b71a128 | |||
12c5f6ee89 | |||
79a1314ee4 | |||
e9848339dd | |||
6e28a4dd13 | |||
7c989f88bd | |||
16fa983704 | |||
40daca5684 | |||
981e0c082d | |||
cebfa54467 | |||
fc20d9b925 | |||
0a75b73fa4 | |||
46b7c905f5 | |||
40f2bd37e3 | |||
9288ffd26d | |||
2cdc82cb91 | |||
6aa8d71588 | |||
9becbd7d72 | |||
e055217292 | |||
fbaf62c230 | |||
b186ec9fc5 | |||
0191e2396a | |||
e96299eef5 | |||
ff53dcf560 | |||
2de78a2d55 | |||
b29ded1d60 | |||
9860bfb2cd | |||
f6ada8d169 | |||
42d31f646d | |||
07fc3ded68 | |||
fd01259d2b | |||
7ffe7f8442 | |||
2b2ce68f07 | |||
bc53d00463 | |||
bddb2a1483 | |||
e3bacfa774 | |||
7c2f07d124 | |||
ede5b3c324 | |||
df5be5812f | |||
bc392e55df | |||
fffc3ed193 | |||
7d160e98fd | |||
bf96bc84a8 | |||
91e4caaa69 | |||
efbd29463d | |||
7608cb37ab | |||
d604e98227 | |||
58907e2c29 | |||
649d372f7d | |||
f9a538bb0f | |||
f92921a6d1 | |||
32d21ddf17 | |||
82f90704a0 | |||
f978d3726a | |||
6f28c4abad | |||
105c9712c1 | |||
4d804ed45e | |||
4a27d29412 | |||
5bd2c58ad6 | |||
cf4c78b9c8 | |||
52aa4b6c22 | |||
5a02433080 | |||
915a0f7173 | |||
0cc266ff19 | |||
9a1b74799d | |||
638f3761f3 | |||
193ca3c9a2 | |||
eb0bb36bbf | |||
0e95a8271a | |||
76b474e97b | |||
27ee86f33b | |||
f7ec310231 | |||
e94d24f508 | |||
2bf4555591 | |||
86de288142 | |||
f35aa8e9d6 | |||
0e8e735a6d | |||
0003a7c118 | |||
2cdcfe46d8 | |||
fe30c03cac | |||
5813b2e354 | |||
af1906ea04 | |||
68848000f7 | |||
d98da47a0f | |||
306f7e93a0 | |||
8954ff3af2 | |||
d2f3adbf69 | |||
d511c845b7 | |||
21c9ac6240 | |||
81c9052847 | |||
9367e3c35d | |||
52cf141874 | |||
8a352df3c6 | |||
c545c59851 | |||
96ea4e8c8e | |||
b8f48bcf64 | |||
6966211e07 | |||
57524a4c8a | |||
f4539c49d8 | |||
12c62fdbc2 | |||
e3c6be5e29 | |||
4741a05df9 | |||
c6676007bf | |||
92b0b7d753 | |||
232237bf28 | |||
c27e453fd3 | |||
0e037d0213 | |||
0dca1fbe12 | |||
35d91a0e58 | |||
a73a5d7e85 | |||
832a5e8852 | |||
96d1f0da2d | |||
597388ecda | |||
1cf6d7b7bb | |||
7bc9d0cdad | |||
dc0dbc50ab | |||
994f4dc77d | |||
c9e297b74c | |||
dd514a115c | |||
7e0b4bd538 | |||
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 |
@ -1,8 +1,7 @@
|
||||
# Remove the line below if you want to inherit .editorconfig settings from higher directories
|
||||
root = true
|
||||
|
||||
# C# files
|
||||
[*.cs]
|
||||
[*]
|
||||
|
||||
#### Core EditorConfig Options ####
|
||||
|
||||
@ -12,8 +11,18 @@ indent_style = space
|
||||
tab_width = 4
|
||||
|
||||
# New line preferences
|
||||
end_of_line = crlf
|
||||
insert_final_newline = false
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# JSON files
|
||||
[*.json]
|
||||
|
||||
# Indentation and spacing
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
|
||||
# C# files
|
||||
[*.cs]
|
||||
|
||||
#### .NET Coding Conventions ####
|
||||
|
||||
@ -59,7 +68,7 @@ dotnet_style_prefer_simplified_interpolation = true:suggestion
|
||||
dotnet_style_readonly_field = true:suggestion
|
||||
|
||||
# Parameter preferences
|
||||
dotnet_code_quality_unused_parameters = all:suggestion
|
||||
dotnet_code_quality_unused_parameters = all:silent
|
||||
|
||||
#### C# Coding Conventions ####
|
||||
|
||||
@ -85,7 +94,7 @@ csharp_style_expression_bodied_properties = true:silent
|
||||
# Pattern matching preferences
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_prefer_switch_expression = true:suggestion
|
||||
csharp_style_prefer_switch_expression = false:silent
|
||||
|
||||
# Null-checking preferences
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
@ -94,6 +103,7 @@ csharp_style_conditional_delegate_call = true:suggestion
|
||||
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
|
||||
csharp_style_prefer_method_group_conversion = true
|
||||
|
||||
# Code-block preferences
|
||||
csharp_prefer_braces = true:silent
|
||||
@ -109,6 +119,7 @@ csharp_style_prefer_range_operator = true:suggestion
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
|
||||
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
|
||||
csharp_style_implicit_object_creation_when_type_is_apparent = true
|
||||
|
||||
# 'using' directive preferences
|
||||
csharp_using_directive_placement = outside_namespace:silent
|
||||
@ -140,7 +151,6 @@ csharp_space_after_dot = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_around_declaration_statements = false
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_before_comma = false
|
||||
csharp_space_before_dot = false
|
||||
@ -158,23 +168,31 @@ csharp_space_between_square_brackets = false
|
||||
|
||||
# Wrapping preferences
|
||||
csharp_preserve_single_line_blocks = true
|
||||
csharp_preserve_single_line_statements = true
|
||||
csharp_preserve_single_line_statements = false
|
||||
|
||||
#### Naming styles ####
|
||||
|
||||
# Naming rules
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
dotnet_naming_rule.interfaces_should_be_prefixed_with_I.severity = suggestion
|
||||
dotnet_naming_rule.interfaces_should_be_prefixed_with_I.symbols = interface
|
||||
dotnet_naming_rule.interfaces_should_be_prefixed_with_I.style = IPascalCase
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = PascalCase
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = PascalCase
|
||||
|
||||
dotnet_naming_rule.private_static_readonly_fields_should_be_camel_case_and_prefixed_with__.symbols = private_static_readonly_fields
|
||||
dotnet_naming_rule.private_static_readonly_fields_should_be_camel_case_and_prefixed_with__.severity = suggestion
|
||||
dotnet_naming_rule.private_static_readonly_fields_should_be_camel_case_and_prefixed_with__.style = _camelCase
|
||||
|
||||
dotnet_naming_rule.local_constants_should_be_pascal_case.symbols = local_constants
|
||||
dotnet_naming_rule.local_constants_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.local_constants_should_be_pascal_case.style = PascalCase
|
||||
|
||||
# Symbol specifications
|
||||
|
||||
@ -190,14 +208,39 @@ dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, meth
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private
|
||||
dotnet_naming_symbols.private_static_readonly_fields.required_modifiers = static, readonly
|
||||
|
||||
dotnet_naming_symbols.local_constants.applicable_kinds = local
|
||||
dotnet_naming_symbols.local_constants.applicable_accessibilities = local
|
||||
dotnet_naming_symbols.local_constants.required_modifiers = const
|
||||
|
||||
# Naming styles
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
dotnet_naming_style._camelCase.required_prefix = _
|
||||
dotnet_naming_style._camelCase.required_suffix =
|
||||
dotnet_naming_style._camelCase.word_separator =
|
||||
dotnet_naming_style._camelCase.capitalization = camel_case
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||
dotnet_naming_style.PascalCase.required_prefix =
|
||||
dotnet_naming_style.PascalCase.required_suffix =
|
||||
dotnet_naming_style.PascalCase.word_separator =
|
||||
dotnet_naming_style.PascalCase.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.IPascalCase.required_prefix = I
|
||||
dotnet_naming_style.IPascalCase.required_suffix =
|
||||
dotnet_naming_style.IPascalCase.word_separator =
|
||||
dotnet_naming_style.IPascalCase.capitalization = pascal_case
|
||||
|
||||
[src/Ryujinx.HLE/HOS/Services/**.cs]
|
||||
# Disable "mark members as static" rule for services
|
||||
dotnet_diagnostic.CA1822.severity = none
|
||||
|
||||
[src/Ryujinx.Ava/UI/ViewModels/**.cs]
|
||||
# Disable "mark members as static" rule for ViewModels
|
||||
dotnet_diagnostic.CA1822.severity = none
|
||||
|
||||
[src/Ryujinx.Tests/Cpu/*.cs]
|
||||
# Disable naming rules for CPU tests
|
||||
dotnet_diagnostic.IDE1006.severity = none
|
||||
|
19
.github/ISSUE_TEMPLATE/missing_shader_instruction.yml
vendored
Normal file
19
.github/ISSUE_TEMPLATE/missing_shader_instruction.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
name: Missing Shader Instruction
|
||||
description: Shader Instruction is missing in Ryujinx.
|
||||
title: "[GPU]"
|
||||
labels: [gpu, not-implemented]
|
||||
body:
|
||||
- type: textarea
|
||||
id: instruction
|
||||
attributes:
|
||||
label: Shader instruction
|
||||
description: What shader instruction is missing?
|
||||
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
|
18
.github/csc.json
vendored
Normal file
18
.github/csc.json
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "csc",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^((?:\\\\|/)(?:[^\\\\/:]+(?:\\\\|/))+[^\\\\/]+)\\((\\d+),(\\d+)\\):\\s+([a-zA-Z]+)\\s+([^:]+):\\s+([^[]+)\\s+\\[",
|
||||
"file": 1,
|
||||
"line": 2,
|
||||
"column": 3,
|
||||
"severity": 4,
|
||||
"code": 5,
|
||||
"message": 6
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
33
.github/labeler.yml
vendored
Normal file
33
.github/labeler.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
audio: 'src/Ryujinx.Audio*/**'
|
||||
|
||||
cpu:
|
||||
- 'src/ARMeilleure/**'
|
||||
- 'src/Ryujinx.Cpu/**'
|
||||
- 'src/Ryujinx.Memory/**'
|
||||
|
||||
gpu:
|
||||
- 'src/Ryujinx.Graphics.*/**'
|
||||
- 'src/Spv.Generator/**'
|
||||
- 'src/Ryujinx.ShaderTools/**'
|
||||
|
||||
'graphics-backend:opengl': 'src/Ryujinx.Graphics.OpenGL/**'
|
||||
'graphics-backend:vulkan':
|
||||
- 'src/Ryujinx.Graphics.Vulkan/**'
|
||||
- 'src/Spv.Generator/**'
|
||||
|
||||
gui:
|
||||
- 'src/Ryujinx/**'
|
||||
- 'src/Ryujinx.Ui.Common/**'
|
||||
- 'src/Ryujinx.Ui.LocaleGenerator/**'
|
||||
- 'src/Ryujinx.Ava/**'
|
||||
|
||||
horizon:
|
||||
- 'src/Ryujinx.HLE/**'
|
||||
- 'src/Ryujinx.Horizon*/**'
|
||||
|
||||
kernel: 'src/Ryujinx.HLE/HOS/Kernel/**'
|
||||
|
||||
infra:
|
||||
- '.github/**'
|
||||
- 'distribution/**'
|
||||
- 'Directory.Packages.props'
|
32
.github/reviewers.yml
vendored
Normal file
32
.github/reviewers.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
audio:
|
||||
- marysaka
|
||||
|
||||
cpu:
|
||||
- gdkchan
|
||||
- riperiperi
|
||||
- marysaka
|
||||
- LDj3SNuD
|
||||
|
||||
gpu:
|
||||
- gdkchan
|
||||
- riperiperi
|
||||
- marysaka
|
||||
|
||||
gui:
|
||||
- Ack77
|
||||
- emmauss
|
||||
- TSRBerry
|
||||
- marysaka
|
||||
|
||||
horizon:
|
||||
- gdkchan
|
||||
- Ack77
|
||||
- marysaka
|
||||
- TSRBerry
|
||||
|
||||
infra:
|
||||
- marysaka
|
||||
- TSRBerry
|
||||
|
||||
default:
|
||||
- '@developers'
|
135
.github/workflows/build.yml
vendored
135
.github/workflows/build.yml
vendored
@ -1,27 +1,18 @@
|
||||
name: Build job
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs: {}
|
||||
#push:
|
||||
# branches: [ master ]
|
||||
# paths-ignore:
|
||||
# - '.github/*'
|
||||
# - '.github/ISSUE_TEMPLATE/**'
|
||||
# - '*.yml'
|
||||
# - 'README.md'
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- '.github/*'
|
||||
- '.github/ISSUE_TEMPLATE/**'
|
||||
- '*.yml'
|
||||
- 'README.md'
|
||||
workflow_call:
|
||||
|
||||
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 +24,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,47 +34,125 @@ 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@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Overwrite csc problem matcher
|
||||
run: echo "::add-matcher::.github/csc.json"
|
||||
|
||||
- name: Get git short hash
|
||||
id: git_short_hash
|
||||
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
|
||||
|
||||
- name: Test
|
||||
run: dotnet test --no-build -c "${{ matrix.configuration }}"
|
||||
uses: TSRBerry/unstable-commands@v1
|
||||
with:
|
||||
commands: dotnet test --no-build -c "${{ matrix.configuration }}"
|
||||
timeout-minutes: 10
|
||||
retry-codes: 139
|
||||
|
||||
- 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 true
|
||||
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 true
|
||||
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="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Ava --self-contained true
|
||||
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@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@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@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' && 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@v4
|
||||
|
||||
- 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 Ryujinx.Ava
|
||||
run: |
|
||||
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
|
||||
|
||||
- name: Publish macOS Ryujinx.Headless.SDL2
|
||||
run: |
|
||||
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
|
||||
|
||||
- name: Upload Ryujinx.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'
|
||||
|
||||
- name: Upload Ryujinx.Headless.SDL2 artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
||||
path: "publish_headless/*.tar.gz"
|
||||
if: github.event_name == 'pull_request'
|
74
.github/workflows/checks.yml
vendored
Normal file
74
.github/workflows/checks.yml
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
name: Perform checks
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
paths:
|
||||
- '**'
|
||||
- '!.github/**'
|
||||
- '!*.yml'
|
||||
- '!*.config'
|
||||
- '!README.md'
|
||||
- '.github/workflows/*.yml'
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
checks: write
|
||||
|
||||
concurrency:
|
||||
group: pr-checks-${{ github.event.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Overwrite csc problem matcher
|
||||
run: echo "::add-matcher::.github/csc.json"
|
||||
|
||||
- run: dotnet restore
|
||||
|
||||
- name: Print dotnet format version
|
||||
run: dotnet format --version
|
||||
|
||||
- name: Run dotnet format whitespace
|
||||
run: |
|
||||
dotnet format whitespace --verify-no-changes --report ./whitespace-report.json -v d
|
||||
|
||||
# For some unknown reason this step sometimes fails with exit code 139 (segfault?),
|
||||
# so in that case we'll try again (3 tries max).
|
||||
- name: Run dotnet format style
|
||||
uses: TSRBerry/unstable-commands@v1
|
||||
with:
|
||||
commands: dotnet format style --severity info --verify-no-changes --report ./style-report.json -v d
|
||||
timeout-minutes: 5
|
||||
retry-codes: 139
|
||||
|
||||
# For some unknown reason this step sometimes fails with exit code 139 (segfault?),
|
||||
# so in that case we'll try again (3 tries max).
|
||||
- name: Run dotnet format analyzers
|
||||
uses: TSRBerry/unstable-commands@v1
|
||||
with:
|
||||
commands: dotnet format analyzers --severity info --verify-no-changes --report ./analyzers-report.json -v d
|
||||
timeout-minutes: 5
|
||||
retry-codes: 139
|
||||
|
||||
- name: Upload report
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dotnet-format
|
||||
path: ./*-report.json
|
||||
|
||||
pr_build:
|
||||
uses: ./.github/workflows/build.yml
|
||||
needs: format
|
||||
secrets: inherit
|
9
.github/workflows/flatpak.yml
vendored
9
.github/workflows/flatpak.yml
vendored
@ -12,18 +12,19 @@ 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: "Ryujinx/Ryujinx.csproj"
|
||||
RYUJINX_PROJECT_FILE: "src/Ryujinx/Ryujinx.csproj"
|
||||
NUGET_SOURCES_DESTDIR: "nuget-sources"
|
||||
RYUJINX_VERSION: "${{ inputs.ryujinx_version }}"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: Ryujinx
|
||||
|
||||
@ -37,7 +38,7 @@ jobs:
|
||||
run: |
|
||||
echo "git_hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: flathub/org.ryujinx.Ryujinx
|
||||
token: ${{ secrets.RYUJINX_BOT_PAT }}
|
||||
@ -168,4 +169,4 @@ jobs:
|
||||
git config user.email "${{ env.GIT_COMMITTER_EMAIL }}"
|
||||
git add .
|
||||
git commit -m "$COMMIT_MESSAGE"
|
||||
git push origin master
|
||||
git push origin master
|
7
.github/workflows/nightly_pr_comment.yml
vendored
7
.github/workflows/nightly_pr_comment.yml
vendored
@ -1,12 +1,15 @@
|
||||
name: Comment PR artifacts links
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ['Build job']
|
||||
workflows: ['Perform checks']
|
||||
types: [completed]
|
||||
|
||||
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@v6
|
||||
with:
|
||||
@ -65,4 +68,4 @@ jobs:
|
||||
} else {
|
||||
core.info(`Creating a comment`);
|
||||
await github.rest.issues.createComment({repo, owner, issue_number, body});
|
||||
}
|
||||
}
|
47
.github/workflows/pr_triage.yml
vendored
Normal file
47
.github/workflows/pr_triage.yml
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
name: "Pull Request Triage"
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, ready_for_review]
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# Grab sources to get latest labeler.yml
|
||||
- name: Fetch sources
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# Ensure we pin the source origin as pull_request_target run under forks.
|
||||
fetch-depth: 0
|
||||
repository: Ryujinx/Ryujinx
|
||||
ref: master
|
||||
|
||||
- name: Checkout Ryujinx-Mako
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: Ryujinx/Ryujinx-Mako
|
||||
ref: master
|
||||
path: '.ryujinx-mako'
|
||||
|
||||
- name: Setup Ryujinx-Mako
|
||||
uses: ./.ryujinx-mako/.github/actions/setup-mako
|
||||
|
||||
- name: Update labels based on changes
|
||||
uses: actions/labeler@v4
|
||||
with:
|
||||
sync-labels: true
|
||||
dot: true
|
||||
|
||||
- name: Assign reviewers
|
||||
run: |
|
||||
poetry -n -C .ryujinx-mako run ryujinx-mako update-reviewers ${{ github.repository }} ${{ github.event.pull_request.number }} .github/reviewers.yml
|
||||
shell: bash
|
||||
env:
|
||||
MAKO_APP_ID: ${{ secrets.MAKO_APP_ID }}
|
||||
MAKO_PRIVATE_KEY: ${{ secrets.MAKO_PRIVATE_KEY }}
|
||||
MAKO_INSTALLATION_ID: ${{ secrets.MAKO_INSTALLATION_ID }}
|
261
.github/workflows/release.yml
vendored
261
.github/workflows/release.yml
vendored
@ -6,9 +6,10 @@ on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- '.github/*'
|
||||
- '.github/ISSUE_TEMPLATE/**'
|
||||
- '.github/**'
|
||||
- '*.yml'
|
||||
- '*.json'
|
||||
- '*.config'
|
||||
- 'README.md'
|
||||
|
||||
concurrency: release
|
||||
@ -22,98 +23,18 @@ env:
|
||||
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master"
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: windows-latest
|
||||
tag:
|
||||
name: Create tag
|
||||
runs-on: ubuntu-latest
|
||||
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/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
- name: Create output dir
|
||||
run: "mkdir release_output"
|
||||
- name: Publish Windows
|
||||
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 true
|
||||
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 true
|
||||
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 true
|
||||
- name: Packing Windows builds
|
||||
run: |
|
||||
pushd publish_windows
|
||||
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
|
||||
pushd publish_windows_sdl2_headless
|
||||
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
|
||||
pushd publish_windows_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 true
|
||||
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 true
|
||||
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 true
|
||||
|
||||
- name: Packing Linux builds
|
||||
run: |
|
||||
pushd publish_linux
|
||||
tar --exclude "publish/Ryujinx" --exclude "publish/Ryujinx.sh" -cvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish
|
||||
python3 ../distribution/misc/add_tar_exec.py ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx" "publish/Ryujinx"
|
||||
python3 ../distribution/misc/add_tar_exec.py ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.sh" "publish/Ryujinx.sh"
|
||||
gzip -9 < ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz
|
||||
rm ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar
|
||||
popd
|
||||
|
||||
pushd publish_linux_sdl2_headless
|
||||
tar --exclude "publish/Ryujinx.Headless.SDL2" --exclude "publish/Ryujinx.sh" -cvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish
|
||||
python3 ../distribution/misc/add_tar_exec.py ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.Headless.SDL2" "publish/Ryujinx.Headless.SDL2"
|
||||
python3 ../distribution/misc/add_tar_exec.py ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.sh" "publish/Ryujinx.sh"
|
||||
gzip -9 < ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz
|
||||
rm ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar
|
||||
popd
|
||||
|
||||
pushd publish_linux_ava
|
||||
tar --exclude "publish/Ryujinx.Ava" --exclude "publish/Ryujinx.sh" -cvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish
|
||||
python3 ../distribution/misc/add_tar_exec.py ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.Ava" "publish/Ryujinx.Ava"
|
||||
python3 ../distribution/misc/add_tar_exec.py ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.sh" "publish/Ryujinx.sh"
|
||||
gzip -9 < ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz
|
||||
rm ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Pushing new release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
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)."
|
||||
allowUpdates: true
|
||||
removeArtifacts: true
|
||||
replacesArtifacts: true
|
||||
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
|
||||
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
- name: Create tag
|
||||
uses: actions/github-script@v5
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
github.rest.git.createRef({
|
||||
@ -123,9 +44,175 @@ jobs:
|
||||
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@v4
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Overwrite csc problem matcher
|
||||
run: echo "::add-matcher::.github/csc.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;' 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
|
||||
run: |
|
||||
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_gtk
|
||||
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
|
||||
pushd publish_sdl2_headless
|
||||
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
|
||||
pushd publish_ava
|
||||
7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Packing Linux builds
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: |
|
||||
pushd publish_gtk
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
popd
|
||||
|
||||
pushd publish_sdl2_headless
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2
|
||||
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
popd
|
||||
|
||||
pushd publish_ava
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx.Ava
|
||||
tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Pushing new release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
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 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 }}
|
||||
|
||||
macos_release:
|
||||
name: Release MacOS universal
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- 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 Ryujinx.Ava
|
||||
run: |
|
||||
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release
|
||||
|
||||
- name: Publish macOS Ryujinx.Headless.SDL2
|
||||
run: |
|
||||
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release
|
||||
|
||||
- name: Pushing new release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: ${{ steps.version_info.outputs.build_version }}
|
||||
artifacts: "publish_ava/*.tar.gz, publish_headless/*.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
|
||||
secrets: inherit
|
@ -1,11 +0,0 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCodeLit : IOpCode
|
||||
{
|
||||
int Rt { get; }
|
||||
long Immediate { get; }
|
||||
int Size { get; }
|
||||
bool Signed { get; }
|
||||
bool Prefetch { get; }
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCodeMemLit : OpCode, IOpCodeLit
|
||||
{
|
||||
public int Rt { get; }
|
||||
public long Immediate { get; }
|
||||
public int Size { get; }
|
||||
public bool Signed { get; }
|
||||
public bool Prefetch { get; }
|
||||
|
||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeMemLit(inst, address, opCode);
|
||||
|
||||
public OpCodeMemLit(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
Rt = opCode & 0x1f;
|
||||
|
||||
Immediate = (long)address + DecoderHelper.DecodeImmS19_2(opCode);
|
||||
|
||||
switch ((opCode >> 30) & 3)
|
||||
{
|
||||
case 0: Size = 2; Signed = false; Prefetch = false; break;
|
||||
case 1: Size = 3; Signed = false; Prefetch = false; break;
|
||||
case 2: Size = 2; Signed = true; Prefetch = false; break;
|
||||
case 3: Size = 0; Signed = false; Prefetch = true; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCodeSimdMemMs : OpCodeMemReg, IOpCodeSimd
|
||||
{
|
||||
public int Reps { get; }
|
||||
public int SElems { get; }
|
||||
public int Elems { get; }
|
||||
public bool WBack { get; }
|
||||
|
||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdMemMs(inst, address, opCode);
|
||||
|
||||
public OpCodeSimdMemMs(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
switch ((opCode >> 12) & 0xf)
|
||||
{
|
||||
case 0b0000: Reps = 1; SElems = 4; break;
|
||||
case 0b0010: Reps = 4; SElems = 1; break;
|
||||
case 0b0100: Reps = 1; SElems = 3; break;
|
||||
case 0b0110: Reps = 3; SElems = 1; break;
|
||||
case 0b0111: Reps = 1; SElems = 1; break;
|
||||
case 0b1000: Reps = 1; SElems = 2; break;
|
||||
case 0b1010: Reps = 2; SElems = 1; break;
|
||||
|
||||
default: Instruction = InstDescriptor.Undefined; return;
|
||||
}
|
||||
|
||||
Size = (opCode >> 10) & 3;
|
||||
WBack = ((opCode >> 23) & 1) != 0;
|
||||
|
||||
bool q = ((opCode >> 30) & 1) != 0;
|
||||
|
||||
if (!q && Size == 3 && SElems != 1)
|
||||
{
|
||||
Instruction = InstDescriptor.Undefined;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Extend64 = false;
|
||||
|
||||
RegisterSize = q
|
||||
? RegisterSize.Simd128
|
||||
: RegisterSize.Simd64;
|
||||
|
||||
Elems = (GetBitsCount() >> 3) >> Size;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCodeSimdMemSs : OpCodeMemReg, IOpCodeSimd
|
||||
{
|
||||
public int SElems { get; }
|
||||
public int Index { get; }
|
||||
public bool Replicate { get; }
|
||||
public bool WBack { get; }
|
||||
|
||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdMemSs(inst, address, opCode);
|
||||
|
||||
public OpCodeSimdMemSs(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
int size = (opCode >> 10) & 3;
|
||||
int s = (opCode >> 12) & 1;
|
||||
int sElems = (opCode >> 12) & 2;
|
||||
int scale = (opCode >> 14) & 3;
|
||||
int l = (opCode >> 22) & 1;
|
||||
int q = (opCode >> 30) & 1;
|
||||
|
||||
sElems |= (opCode >> 21) & 1;
|
||||
|
||||
sElems++;
|
||||
|
||||
int index = (q << 3) | (s << 2) | size;
|
||||
|
||||
switch (scale)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
if ((size & 1) != 0)
|
||||
{
|
||||
Instruction = InstDescriptor.Undefined;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
index >>= 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
if ((size & 2) != 0 ||
|
||||
((size & 1) != 0 && s != 0))
|
||||
{
|
||||
Instruction = InstDescriptor.Undefined;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((size & 1) != 0)
|
||||
{
|
||||
index >>= 3;
|
||||
|
||||
scale = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
index >>= 2;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
if (l == 0 || s != 0)
|
||||
{
|
||||
Instruction = InstDescriptor.Undefined;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
scale = size;
|
||||
|
||||
Replicate = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Index = index;
|
||||
SElems = sElems;
|
||||
Size = scale;
|
||||
|
||||
Extend64 = false;
|
||||
|
||||
WBack = ((opCode >> 23) & 1) != 0;
|
||||
|
||||
RegisterSize = q != 0
|
||||
? RegisterSize.Simd128
|
||||
: RegisterSize.Simd64;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
enum Comparison
|
||||
{
|
||||
Equal = 0,
|
||||
NotEqual = 1,
|
||||
Greater = 2,
|
||||
LessOrEqual = 3,
|
||||
GreaterUI = 4,
|
||||
LessOrEqualUI = 5,
|
||||
GreaterOrEqual = 6,
|
||||
Less = 7,
|
||||
GreaterOrEqualUI = 8,
|
||||
LessUI = 9
|
||||
}
|
||||
|
||||
static class ComparisonExtensions
|
||||
{
|
||||
public static Comparison Invert(this Comparison comp)
|
||||
{
|
||||
return (Comparison)((int)comp ^ 1);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
enum OperandType
|
||||
{
|
||||
None,
|
||||
I32,
|
||||
I64,
|
||||
FP32,
|
||||
FP64,
|
||||
V128
|
||||
}
|
||||
|
||||
static class OperandTypeExtensions
|
||||
{
|
||||
public static bool IsInteger(this OperandType type)
|
||||
{
|
||||
return type == OperandType.I32 ||
|
||||
type == OperandType.I64;
|
||||
}
|
||||
|
||||
public static RegisterType ToRegisterType(this OperandType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OperandType.FP32: return RegisterType.Vector;
|
||||
case OperandType.FP64: return RegisterType.Vector;
|
||||
case OperandType.I32: return RegisterType.Integer;
|
||||
case OperandType.I64: return RegisterType.Integer;
|
||||
case OperandType.V128: return RegisterType.Vector;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Invalid operand type \"{type}\".");
|
||||
}
|
||||
|
||||
public static int GetSizeInBytes(this OperandType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OperandType.FP32: return 4;
|
||||
case OperandType.FP64: return 8;
|
||||
case OperandType.I32: return 4;
|
||||
case OperandType.I64: return 8;
|
||||
case OperandType.V128: return 16;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Invalid operand type \"{type}\".");
|
||||
}
|
||||
|
||||
public static int GetSizeInBytesLog2(this OperandType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case OperandType.FP32: return 2;
|
||||
case OperandType.FP64: return 3;
|
||||
case OperandType.I32: return 2;
|
||||
case OperandType.I64: return 3;
|
||||
case OperandType.V128: return 4;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Invalid operand type \"{type}\".");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
enum Aarch32Mode
|
||||
{
|
||||
User = 0b10000,
|
||||
Fiq = 0b10001,
|
||||
Irq = 0b10010,
|
||||
Supervisor = 0b10011,
|
||||
Monitor = 0b10110,
|
||||
Abort = 0b10111,
|
||||
Hypervisor = 0b11010,
|
||||
Undefined = 0b11011,
|
||||
System = 0b11111
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
enum FPException
|
||||
{
|
||||
InvalidOp = 0,
|
||||
DivideByZero = 1,
|
||||
Overflow = 2,
|
||||
Underflow = 3,
|
||||
Inexact = 4,
|
||||
InputDenorm = 7
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
public enum FPRoundingMode
|
||||
{
|
||||
ToNearest = 0, // With ties to even.
|
||||
TowardsPlusInfinity = 1,
|
||||
TowardsMinusInfinity = 2,
|
||||
TowardsZero = 3,
|
||||
ToNearestAway = 4 // With ties to away.
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
static class RegisterConsts
|
||||
{
|
||||
public const int IntRegsCount = 32;
|
||||
public const int VecRegsCount = 32;
|
||||
public const int FlagsCount = 32;
|
||||
public const int FpFlagsCount = 32;
|
||||
public const int IntAndVecRegsCount = IntRegsCount + VecRegsCount;
|
||||
public const int FpFlagsOffset = IntRegsCount + VecRegsCount + FlagsCount;
|
||||
public const int TotalCount = IntRegsCount + VecRegsCount + FlagsCount + FpFlagsCount;
|
||||
|
||||
public const int ZeroIndex = 31;
|
||||
}
|
||||
}
|
@ -1,104 +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)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(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,261 +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)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(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)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(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.GetFunctionAddress)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
|
||||
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.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.Encrypt)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate)));
|
||||
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.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.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.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)));
|
||||
}
|
||||
}
|
||||
}
|
147
CONTRIBUTING.md
Normal file
147
CONTRIBUTING.md
Normal file
@ -0,0 +1,147 @@
|
||||
# Contribution to Ryujinx
|
||||
|
||||
You can contribute to Ryujinx with PRs, testing of PRs and issues. Contributing code and other implementations is greatly appreciated alongside simply filing issues for problems you encounter.
|
||||
Please read the entire document before continuing as it can potentially save everyone involved a significant amount of time.
|
||||
|
||||
# Quick Links
|
||||
|
||||
* [Code Style Documentation](docs/coding-guidelines/coding-style.md)
|
||||
* [Pull Request Guidelines](docs/workflow/pr-guide.md)
|
||||
|
||||
## Reporting Issues
|
||||
|
||||
We always welcome bug reports, feature proposals and overall feedback. Here are a few tips on how you can make reporting your issue as effective as possible.
|
||||
|
||||
### Identify Where to Report
|
||||
|
||||
The Ryujinx codebase is distributed across multiple repositories in the [Ryujinx organization](https://github.com/Ryujinx). Depending on the feedback you might want to file the issue on a different repo. Here are a few common repos:
|
||||
|
||||
* [Ryujinx/Ryujinx](https://github.com/Ryujinx/Ryujinx) Ryujinx core project files.
|
||||
* [Ryujinx/Ryujinx-Games-List](https://github.com/Ryujinx/Ryujinx-Games-List) Ryujinx game compatibility list.
|
||||
* [Ryujinx/Ryujinx-Website](https://github.com/Ryujinx/Ryujinx-Website) Ryujinx website source code.
|
||||
* [Ryujinx/Ryujinx-Ldn-Website](https://github.com/Ryujinx/Ryujinx-Ldn-Website) Ryujinx LDN website source code.
|
||||
|
||||
### Finding Existing Issues
|
||||
|
||||
Before filing a new issue, please search our [open issues](https://github.com/Ryujinx/Ryujinx/issues) to check if it already exists.
|
||||
|
||||
If you do find an existing issue, please include your own feedback in the discussion. Do consider upvoting (👍 reaction) the original post, as this helps us prioritize popular issues in our backlog.
|
||||
|
||||
### Writing a Good Feature Request
|
||||
|
||||
Please review any feature requests already opened to both check it has not already been suggested, and to familiarize yourself with the format. When ready to submit a proposal, please use the [Feature Request issue template](https://github.com/Ryujinx/Ryujinx/issues/new?assignees=&labels=&projects=&template=feature_request.yml&title=%5BFeature+Request%5D).
|
||||
|
||||
### Writing a Good Bug Report
|
||||
|
||||
Good bug reports make it easier for maintainers to verify and root cause the underlying problem. The better a bug report, the faster the problem will be resolved.
|
||||
Ideally, a bug report should contain the following information:
|
||||
|
||||
* A high-level description of the problem.
|
||||
* A _minimal reproduction_, i.e. the smallest time commitment/configuration required to reproduce the wrong behavior. This can be in the form of a small homebrew application, or by providing a save file and reproduction steps for a specific game.
|
||||
* A description of the _expected behavior_, contrasted with the _actual behavior_ observed.
|
||||
* Information on the environment: OS/distro, CPU, GPU (including driver), RAM etc.
|
||||
* A Ryujinx log file of the run instance where the issue occurred. Log files can be found in `[Executable Folder]/Logs` and are named chronologically.
|
||||
* Additional information, e.g. is it a regression from previous versions? Are there any known workarounds?
|
||||
|
||||
When ready to submit a bug report, please use the [Bug Report issue template](https://github.com/Ryujinx/Ryujinx/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D).
|
||||
|
||||
## Contributing Changes
|
||||
|
||||
Project maintainers will merge changes that both improve the project and meet our standards for code quality.
|
||||
|
||||
The [Pull Request Guide](docs/workflow/pr-guide.md) and [License](https://github.com/Ryujinx/Ryujinx/blob/master/LICENSE.txt) docs define additional guidance.
|
||||
|
||||
### DOs and DON'Ts
|
||||
|
||||
Please do:
|
||||
|
||||
* **DO** follow our [coding style](docs/coding-guidelines/coding-style.md) (C# code-specific).
|
||||
* **DO** give priority to the current style of the project or file you're changing even if it diverges from the general guidelines.
|
||||
* **DO** keep the discussions focused. When a new or related topic comes up
|
||||
it's often better to create new issue than to side track the discussion.
|
||||
* **DO** clearly state on an issue that you are going to take on implementing it.
|
||||
* **DO** blog and tweet (or whatever) about your contributions, frequently!
|
||||
|
||||
Please do not:
|
||||
|
||||
* **DON'T** make PRs for style changes.
|
||||
* **DON'T** surprise us with big pull requests. Instead, file an issue and talk with us on Discord to start
|
||||
a discussion so we can agree on a direction before you invest a large amount
|
||||
of time.
|
||||
* **DON'T** commit code that you didn't write. If you find code that you think is a good fit to add to Ryujinx, file an issue or talk to us on Discord to start a discussion before proceeding.
|
||||
* **DON'T** submit PRs that alter licensing related files or headers. If you believe there's a problem with them, file an issue and we'll be happy to discuss it.
|
||||
|
||||
### Suggested Workflow
|
||||
|
||||
We use and recommend the following workflow:
|
||||
|
||||
1. Create or find an issue for your work.
|
||||
- You can skip this step for trivial changes.
|
||||
- Get agreement from the team and the community that your proposed change is a good one if it is of significant size or changes core functionality.
|
||||
- Clearly state that you are going to take on implementing it, if that's the case. You can request that the issue be assigned to you. Note: The issue filer and the implementer don't have to be the same person.
|
||||
2. Create a personal fork of the repository on GitHub (if you don't already have one).
|
||||
3. In your fork, create a branch off of main (`git checkout -b mybranch`).
|
||||
- Branches are useful since they isolate your changes from incoming changes from upstream. They also enable you to create multiple PRs from the same fork.
|
||||
4. Make and commit your changes to your branch.
|
||||
- [Build Instructions](https://github.com/Ryujinx/Ryujinx#building) explains how to build and test.
|
||||
- Commit messages should be clear statements of action and intent.
|
||||
6. Build the repository with your changes.
|
||||
- Make sure that the builds are clean.
|
||||
- Make sure that `dotnet format` has been run and any corrections tested and committed.
|
||||
7. Create a pull request (PR) against the Ryujinx/Ryujinx repository's **main** branch.
|
||||
- State in the description what issue or improvement your change is addressing.
|
||||
- Check if all the Continuous Integration checks are passing. Refer to [Actions](https://github.com/Ryujinx/Ryujinx/actions) to check for outstanding errors.
|
||||
8. Wait for feedback or approval of your changes from the [core development team](https://github.com/orgs/Ryujinx/teams/developers)
|
||||
- Details about the pull request [review procedure](docs/workflow/ci/pr-guide.md).
|
||||
9. When the team members have signed off, and all checks are green, your PR will be merged.
|
||||
- The next official build will automatically include your change.
|
||||
- You can delete the branch you used for making the change.
|
||||
|
||||
### Good First Issues
|
||||
|
||||
The team marks the most straightforward issues as [good first issues](https://github.com/Ryujinx/Ryujinx/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). This set of issues is the place to start if you are interested in contributing but new to the codebase.
|
||||
|
||||
### Commit Messages
|
||||
|
||||
Please format commit messages as follows (based on [A Note About Git Commit Messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)):
|
||||
|
||||
```
|
||||
Summarize change in 50 characters or less
|
||||
|
||||
Provide more detail after the first line. Leave one blank line below the
|
||||
summary and wrap all lines at 72 characters or less.
|
||||
|
||||
If the change fixes an issue, leave another blank line after the final
|
||||
paragraph and indicate which issue is fixed in the specific format
|
||||
below.
|
||||
|
||||
Fix #42
|
||||
```
|
||||
|
||||
Also do your best to factor commits appropriately, not too large with unrelated things in the same commit, and not too small with the same small change applied N times in N different commits.
|
||||
|
||||
### PR - CI Process
|
||||
|
||||
The [Ryujinx continuous integration](https://github.com/Ryujinx/Ryujinx/actions) (CI) system will automatically perform the required builds and run tests (including the ones you are expected to run) for PRs. Builds and test runs must be clean or have bugs properly filed against flaky/unexpected failures that are unrelated to your change.
|
||||
|
||||
If the CI build fails for any reason, the PR actions tab should be consulted for further information on the failure. There are a few usual suspects for such a failure:
|
||||
* `dotnet format` has not been run on the PR and has outstanding stylistic issues.
|
||||
* There is an error within the PR that fails a test or errors the compiler.
|
||||
* Random failure of the workflow can occasionally result in a CI failure. In this scenario a maintainer will manually restart the job.
|
||||
|
||||
### PR Feedback
|
||||
|
||||
Ryujinx team and community members will provide feedback on your change. Community feedback is highly valued. You may see the absence of team feedback if the community has already provided good review feedback.
|
||||
|
||||
Two Ryujinx team members must review and approve every PR prior to merge. They will often reply with "LGTM, see nit". That means that the PR will be merged once the feedback is resolved. "LGTM" == "looks good to me".
|
||||
|
||||
There are lots of thoughts and [approaches](https://github.com/antlr/antlr4-cpp/blob/master/CONTRIBUTING.md#emoji) for how to efficiently discuss changes. It is best to be clear and explicit with your feedback. Please be patient with people who might not understand the finer details about your approach to feedback.
|
||||
|
||||
#### Copying Changes from Other Projects
|
||||
|
||||
Ryujinx uses some implementations and frameworks from other projects. The following rules must be followed for PRs that include changes from another project:
|
||||
|
||||
- The license of the file is [permissive](https://en.wikipedia.org/wiki/Permissive_free_software_licence).
|
||||
- The license of the file is left in-tact.
|
||||
- The contribution is correctly attributed in the [3rd party notices](https://github.com/Ryujinx/Ryujinx/blob/master/distribution/legal/THIRDPARTY.md) file in the repository, as needed.
|
||||
|
@ -3,25 +3,25 @@
|
||||
<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="Avalonia" Version="11.0.4" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.4" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.0.4" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.4" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.4" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.2" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.2" />
|
||||
<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.5" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="1.4.5" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
<PackageVersion Include="DynamicData" Version="7.14.2" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.4" />
|
||||
<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="jp2masa.Avalonia.Flexbox" Version="0.3.0-beta.4" />
|
||||
<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.CodeAnalysis.CSharp" Version="4.6.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
|
||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
<PackageVersion Include="NUnit" Version="3.13.3" />
|
||||
@ -34,7 +34,7 @@
|
||||
<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="Ryujinx.SDL2-CS" Version="2.28.1-build28" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||
@ -44,10 +44,9 @@
|
||||
<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.29.0" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="7.0.0" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
||||
<PackageVersion Include="System.Management" Version="7.0.1" />
|
||||
<PackageVersion Include="System.Management" Version="7.0.2" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.6.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -1,756 +0,0 @@
|
||||
using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Audio.Renderer.Dsp.Command;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using static Ryujinx.Audio.Renderer.Parameter.VoiceInParameter;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="ICommandProcessingTimeEstimator"/> version 3. (added with REV8)
|
||||
/// </summary>
|
||||
public class CommandProcessingTimeEstimatorVersion3 : ICommandProcessingTimeEstimator
|
||||
{
|
||||
protected uint _sampleCount;
|
||||
protected uint _bufferCount;
|
||||
|
||||
public CommandProcessingTimeEstimatorVersion3(uint sampleCount, uint bufferCount)
|
||||
{
|
||||
_sampleCount = sampleCount;
|
||||
_bufferCount = bufferCount;
|
||||
}
|
||||
|
||||
public uint Estimate(PerformanceCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
return (uint)498.17f;
|
||||
}
|
||||
|
||||
return (uint)489.42f;
|
||||
}
|
||||
|
||||
public uint Estimate(ClearMixBufferCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
float costPerBuffer = 440.68f;
|
||||
float baseCost = 0;
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
costPerBuffer = 266.65f;
|
||||
}
|
||||
|
||||
return (uint)(baseCost + costPerBuffer * _bufferCount);
|
||||
}
|
||||
|
||||
public uint Estimate(BiquadFilterCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
return (uint)4173.2f;
|
||||
}
|
||||
|
||||
return (uint)5585.1f;
|
||||
}
|
||||
|
||||
public uint Estimate(MixRampGroupedCommand command)
|
||||
{
|
||||
float costPerSample = 6.4434f;
|
||||
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
costPerSample = 6.708f;
|
||||
}
|
||||
|
||||
int volumeCount = 0;
|
||||
|
||||
for (int i = 0; i < command.MixBufferCount; i++)
|
||||
{
|
||||
if (command.Volume0[i] != 0.0f || command.Volume1[i] != 0.0f)
|
||||
{
|
||||
volumeCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return (uint)(_sampleCount * costPerSample * volumeCount);
|
||||
}
|
||||
|
||||
public uint Estimate(MixRampCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
return (uint)1968.7f;
|
||||
}
|
||||
|
||||
return (uint)2459.4f;
|
||||
}
|
||||
|
||||
public uint Estimate(DepopPrepareCommand command)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public uint Estimate(VolumeRampCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
return (uint)1425.3f;
|
||||
}
|
||||
|
||||
return (uint)1700.0f;
|
||||
}
|
||||
|
||||
public uint Estimate(PcmInt16DataSourceCommandVersion1 command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
float costPerSample = 710.143f;
|
||||
float baseCost = 7853.286f;
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
costPerSample = 427.52f;
|
||||
baseCost = 6329.442f;
|
||||
}
|
||||
|
||||
return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f))));
|
||||
}
|
||||
|
||||
public uint Estimate(AdpcmDataSourceCommandVersion1 command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
float costPerSample = 3564.1f;
|
||||
float baseCost = 9736.702f;
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
costPerSample = 2125.6f;
|
||||
baseCost = 7913.808f;
|
||||
}
|
||||
|
||||
return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f))));
|
||||
}
|
||||
|
||||
public uint Estimate(DepopForMixBuffersCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
return (uint)739.64f;
|
||||
}
|
||||
|
||||
return (uint)910.97f;
|
||||
}
|
||||
|
||||
public uint Estimate(CopyMixBufferCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
return (uint)842.59f;
|
||||
}
|
||||
|
||||
return (uint)986.72f;
|
||||
}
|
||||
|
||||
public uint Estimate(MixCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
return (uint)1402.8f;
|
||||
}
|
||||
|
||||
return (uint)1853.2f;
|
||||
}
|
||||
|
||||
public virtual uint Estimate(DelayCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)8929.04f;
|
||||
case 2:
|
||||
return (uint)25500.75f;
|
||||
case 4:
|
||||
return (uint)47759.62f;
|
||||
case 6:
|
||||
return (uint)82203.07f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)1295.20f;
|
||||
case 2:
|
||||
return (uint)1213.60f;
|
||||
case 4:
|
||||
return (uint)942.03f;
|
||||
case 6:
|
||||
return (uint)1001.55f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)11941.05f;
|
||||
case 2:
|
||||
return (uint)37197.37f;
|
||||
case 4:
|
||||
return (uint)69749.84f;
|
||||
case 6:
|
||||
return (uint)120042.40f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)997.67f;
|
||||
case 2:
|
||||
return (uint)977.63f;
|
||||
case 4:
|
||||
return (uint)792.30f;
|
||||
case 6:
|
||||
return (uint)875.43f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual uint Estimate(ReverbCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)81475.05f;
|
||||
case 2:
|
||||
return (uint)84975.0f;
|
||||
case 4:
|
||||
return (uint)91625.15f;
|
||||
case 6:
|
||||
return (uint)95332.27f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)536.30f;
|
||||
case 2:
|
||||
return (uint)588.70f;
|
||||
case 4:
|
||||
return (uint)643.70f;
|
||||
case 6:
|
||||
return (uint)706.0f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)120174.47f;
|
||||
case 2:
|
||||
return (uint)25262.22f;
|
||||
case 4:
|
||||
return (uint)135751.23f;
|
||||
case 6:
|
||||
return (uint)141129.23f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)617.64f;
|
||||
case 2:
|
||||
return (uint)659.54f;
|
||||
case 4:
|
||||
return (uint)711.43f;
|
||||
case 6:
|
||||
return (uint)778.07f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual uint Estimate(Reverb3dCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)116754.0f;
|
||||
case 2:
|
||||
return (uint)125912.05f;
|
||||
case 4:
|
||||
return (uint)146336.03f;
|
||||
case 6:
|
||||
return (uint)165812.66f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)734.0f;
|
||||
case 2:
|
||||
return (uint)766.62f;
|
||||
case 4:
|
||||
return (uint)797.46f;
|
||||
case 6:
|
||||
return (uint)867.43f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)170292.34f;
|
||||
case 2:
|
||||
return (uint)183875.63f;
|
||||
case 4:
|
||||
return (uint)214696.19f;
|
||||
case 6:
|
||||
return (uint)243846.77f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)508.47f;
|
||||
case 2:
|
||||
return (uint)582.45f;
|
||||
case 4:
|
||||
return (uint)626.42f;
|
||||
case 6:
|
||||
return (uint)682.47f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint Estimate(AuxiliaryBufferCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
if (command.Enabled)
|
||||
{
|
||||
return (uint)7182.14f;
|
||||
}
|
||||
|
||||
return (uint)472.11f;
|
||||
}
|
||||
|
||||
if (command.Enabled)
|
||||
{
|
||||
return (uint)9435.96f;
|
||||
}
|
||||
|
||||
return (uint)462.62f;
|
||||
}
|
||||
|
||||
public uint Estimate(VolumeCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
return (uint)1311.1f;
|
||||
}
|
||||
|
||||
return (uint)1713.6f;
|
||||
}
|
||||
|
||||
public uint Estimate(CircularBufferSinkCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
float costPerBuffer = 770.26f;
|
||||
float baseCost = 0f;
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
costPerBuffer = 531.07f;
|
||||
}
|
||||
|
||||
return (uint)(baseCost + costPerBuffer * command.InputCount);
|
||||
}
|
||||
|
||||
public uint Estimate(DownMixSurroundToStereoCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
return (uint)9949.7f;
|
||||
}
|
||||
|
||||
return (uint)14679.0f;
|
||||
}
|
||||
|
||||
public uint Estimate(UpsampleCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
return (uint)312990.0f;
|
||||
}
|
||||
|
||||
return (uint)0.0f;
|
||||
}
|
||||
|
||||
public uint Estimate(DeviceSinkCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
Debug.Assert(command.InputCount == 2 || command.InputCount == 6);
|
||||
|
||||
if (command.InputCount == 2)
|
||||
{
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
return (uint)8980.0f;
|
||||
}
|
||||
|
||||
return (uint)9221.9f;
|
||||
}
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
return (uint)9177.9f;
|
||||
}
|
||||
|
||||
return (uint)9725.9f;
|
||||
}
|
||||
|
||||
public uint Estimate(PcmFloatDataSourceCommandVersion1 command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
float costPerSample = 3490.9f;
|
||||
float baseCost = 10090.9f;
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
costPerSample = 2310.4f;
|
||||
baseCost = 7845.25f;
|
||||
}
|
||||
|
||||
return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f))));
|
||||
}
|
||||
|
||||
public uint Estimate(DataSourceVersion2Command command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
(float baseCost, float costPerSample) = GetCostByFormat(_sampleCount, command.SampleFormat, command.SrcQuality);
|
||||
|
||||
return (uint)(baseCost + (costPerSample * (((command.SampleRate / 200.0f) / _sampleCount) * (command.Pitch * 0.000030518f) - 1.0f)));
|
||||
}
|
||||
|
||||
private static (float, float) GetCostByFormat(uint sampleCount, SampleFormat format, SampleRateConversionQuality quality)
|
||||
{
|
||||
Debug.Assert(sampleCount == 160 || sampleCount == 240);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case SampleFormat.PcmInt16:
|
||||
switch (quality)
|
||||
{
|
||||
case SampleRateConversionQuality.Default:
|
||||
if (sampleCount == 160)
|
||||
{
|
||||
return (6329.44f, 427.52f);
|
||||
}
|
||||
|
||||
return (7853.28f, 710.14f);
|
||||
case SampleRateConversionQuality.High:
|
||||
if (sampleCount == 160)
|
||||
{
|
||||
return (8049.42f, 371.88f);
|
||||
}
|
||||
|
||||
return (10138.84f, 610.49f);
|
||||
case SampleRateConversionQuality.Low:
|
||||
if (sampleCount == 160)
|
||||
{
|
||||
return (5062.66f, 423.43f);
|
||||
}
|
||||
|
||||
return (5810.96f, 676.72f);
|
||||
default:
|
||||
throw new NotImplementedException($"{format} {quality}");
|
||||
}
|
||||
case SampleFormat.PcmFloat:
|
||||
switch (quality)
|
||||
{
|
||||
case SampleRateConversionQuality.Default:
|
||||
if (sampleCount == 160)
|
||||
{
|
||||
return (7845.25f, 2310.4f);
|
||||
}
|
||||
|
||||
return (10090.9f, 3490.9f);
|
||||
case SampleRateConversionQuality.High:
|
||||
if (sampleCount == 160)
|
||||
{
|
||||
return (9446.36f, 2308.91f);
|
||||
}
|
||||
|
||||
return (12520.85f, 3480.61f);
|
||||
case SampleRateConversionQuality.Low:
|
||||
if (sampleCount == 160)
|
||||
{
|
||||
return (9446.36f, 2308.91f);
|
||||
}
|
||||
|
||||
return (12520.85f, 3480.61f);
|
||||
default:
|
||||
throw new NotImplementedException($"{format} {quality}");
|
||||
}
|
||||
case SampleFormat.Adpcm:
|
||||
switch (quality)
|
||||
{
|
||||
case SampleRateConversionQuality.Default:
|
||||
if (sampleCount == 160)
|
||||
{
|
||||
return (7913.81f, 1827.66f);
|
||||
}
|
||||
|
||||
return (9736.70f, 2756.37f);
|
||||
case SampleRateConversionQuality.High:
|
||||
if (sampleCount == 160)
|
||||
{
|
||||
return (9607.81f, 1829.29f);
|
||||
}
|
||||
|
||||
return (12154.38f, 2731.31f);
|
||||
case SampleRateConversionQuality.Low:
|
||||
if (sampleCount == 160)
|
||||
{
|
||||
return (6517.48f, 1824.61f);
|
||||
}
|
||||
|
||||
return (7929.44f, 2732.15f);
|
||||
default:
|
||||
throw new NotImplementedException($"{format} {quality}");
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException($"{format}");
|
||||
}
|
||||
}
|
||||
|
||||
private uint EstimateLimiterCommandCommon(LimiterParameter parameter, bool enabled)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
switch (parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)21392.0f;
|
||||
case 2:
|
||||
return (uint)26829.0f;
|
||||
case 4:
|
||||
return (uint)32405.0f;
|
||||
case 6:
|
||||
return (uint)52219.0f;
|
||||
default:
|
||||
throw new NotImplementedException($"{parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)897.0f;
|
||||
case 2:
|
||||
return (uint)931.55f;
|
||||
case 4:
|
||||
return (uint)975.39f;
|
||||
case 6:
|
||||
return (uint)1016.8f;
|
||||
default:
|
||||
throw new NotImplementedException($"{parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
switch (parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)30556.0f;
|
||||
case 2:
|
||||
return (uint)39011.0f;
|
||||
case 4:
|
||||
return (uint)48270.0f;
|
||||
case 6:
|
||||
return (uint)76712.0f;
|
||||
default:
|
||||
throw new NotImplementedException($"{parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)874.43f;
|
||||
case 2:
|
||||
return (uint)921.55f;
|
||||
case 4:
|
||||
return (uint)945.26f;
|
||||
case 6:
|
||||
return (uint)992.26f;
|
||||
default:
|
||||
throw new NotImplementedException($"{parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint Estimate(LimiterCommandVersion1 command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
return EstimateLimiterCommandCommon(command.Parameter, command.IsEffectEnabled);
|
||||
}
|
||||
|
||||
public uint Estimate(LimiterCommandVersion2 command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (!command.Parameter.StatisticsEnabled || !command.IsEffectEnabled)
|
||||
{
|
||||
return EstimateLimiterCommandCommon(command.Parameter, command.IsEffectEnabled);
|
||||
}
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)23309.0f;
|
||||
case 2:
|
||||
return (uint)29954.0f;
|
||||
case 4:
|
||||
return (uint)35807.0f;
|
||||
case 6:
|
||||
return (uint)58340.0f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)33526.0f;
|
||||
case 2:
|
||||
return (uint)43549.0f;
|
||||
case 4:
|
||||
return (uint)52190.0f;
|
||||
case 6:
|
||||
return (uint)85527.0f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
|
||||
public virtual uint Estimate(GroupedBiquadFilterCommand command)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public virtual uint Estimate(CaptureBufferCommand command)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public virtual uint Estimate(CompressorCommand command)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,310 +0,0 @@
|
||||
using Ryujinx.Audio.Renderer.Dsp.Command;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="ICommandProcessingTimeEstimator"/> version 5. (added with REV11)
|
||||
/// </summary>
|
||||
public class CommandProcessingTimeEstimatorVersion5 : CommandProcessingTimeEstimatorVersion4
|
||||
{
|
||||
public CommandProcessingTimeEstimatorVersion5(uint sampleCount, uint bufferCount) : base(sampleCount, bufferCount) { }
|
||||
|
||||
public override uint Estimate(DelayCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return 8929;
|
||||
case 2:
|
||||
return 25501;
|
||||
case 4:
|
||||
return 47760;
|
||||
case 6:
|
||||
return 82203;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)1295.20f;
|
||||
case 2:
|
||||
return (uint)1213.60f;
|
||||
case 4:
|
||||
return (uint)942.03f;
|
||||
case 6:
|
||||
return (uint)1001.6f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return 11941;
|
||||
case 2:
|
||||
return 37197;
|
||||
case 4:
|
||||
return 69750;
|
||||
case 6:
|
||||
return 12004;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)997.67f;
|
||||
case 2:
|
||||
return (uint)977.63f;
|
||||
case 4:
|
||||
return (uint)792.31f;
|
||||
case 6:
|
||||
return (uint)875.43f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override uint Estimate(ReverbCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return 81475;
|
||||
case 2:
|
||||
return 84975;
|
||||
case 4:
|
||||
return 91625;
|
||||
case 6:
|
||||
return 95332;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)536.30f;
|
||||
case 2:
|
||||
return (uint)588.80f;
|
||||
case 4:
|
||||
return (uint)643.70f;
|
||||
case 6:
|
||||
return (uint)706.0f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return 120170;
|
||||
case 2:
|
||||
return 125260;
|
||||
case 4:
|
||||
return 135750;
|
||||
case 6:
|
||||
return 141130;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)617.64f;
|
||||
case 2:
|
||||
return (uint)659.54f;
|
||||
case 4:
|
||||
return (uint)711.44f;
|
||||
case 6:
|
||||
return (uint)778.07f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override uint Estimate(Reverb3dCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return 116750;
|
||||
case 2:
|
||||
return 125910;
|
||||
case 4:
|
||||
return 146340;
|
||||
case 6:
|
||||
return 165810;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return 735;
|
||||
case 2:
|
||||
return (uint)766.62f;
|
||||
case 4:
|
||||
return (uint)834.07f;
|
||||
case 6:
|
||||
return (uint)875.44f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return 170290;
|
||||
case 2:
|
||||
return 183880;
|
||||
case 4:
|
||||
return 214700;
|
||||
case 6:
|
||||
return 243850;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)508.47f;
|
||||
case 2:
|
||||
return (uint)582.45f;
|
||||
case 4:
|
||||
return (uint)626.42f;
|
||||
case 6:
|
||||
return (uint)682.47f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override uint Estimate(CompressorCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return 34431;
|
||||
case 2:
|
||||
return 44253;
|
||||
case 4:
|
||||
return 63827;
|
||||
case 6:
|
||||
return 83361;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)630.12f;
|
||||
case 2:
|
||||
return (uint)638.27f;
|
||||
case 4:
|
||||
return (uint)705.86f;
|
||||
case 6:
|
||||
return (uint)782.02f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return 51095;
|
||||
case 2:
|
||||
return 65693;
|
||||
case 4:
|
||||
return 95383;
|
||||
case 6:
|
||||
return 124510;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)840.14f;
|
||||
case 2:
|
||||
return (uint)826.1f;
|
||||
case 4:
|
||||
return (uint)901.88f;
|
||||
case 6:
|
||||
return (uint)965.29f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<Application
|
||||
x:Class="Ryujinx.Ava.App"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:sty="using:FluentAvalonia.Styling">
|
||||
<Application.Styles>
|
||||
<sty:FluentAvaloniaTheme PreferSystemTheme="False" />
|
||||
</Application.Styles>
|
||||
</Application>
|
@ -1,65 +0,0 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<StyleInclude Source="avares://Ryujinx.Ava/Assets/Styles/Styles.xaml" />
|
||||
<Design.PreviewWith>
|
||||
<Border Height="2000" Padding="20">
|
||||
<StackPanel Spacing="5">
|
||||
<TextBlock Text="Code Font Family" />
|
||||
<Grid RowDefinitions="*,Auto">
|
||||
<Menu Grid.Row="1" Width="100">
|
||||
<MenuItem Header="File">
|
||||
<MenuItem Header="Test 1" />
|
||||
<MenuItem Header="Test 2" />
|
||||
<MenuItem Header="Test 3">
|
||||
<MenuItem.Icon>
|
||||
<CheckBox Margin="0" IsChecked="{Binding Checkbox, Mode=TwoWay}" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button
|
||||
Name="btnAdd"
|
||||
HorizontalAlignment="Right"
|
||||
Content="Add" />
|
||||
<Button
|
||||
Name="btnRem"
|
||||
HorizontalAlignment="Right"
|
||||
Content="Add" />
|
||||
<TextBox
|
||||
Width="100"
|
||||
VerticalAlignment="Center"
|
||||
Text="Rrrrr"
|
||||
UseFloatingWatermark="True"
|
||||
Watermark="Hello" />
|
||||
<CheckBox>Test Check</CheckBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Design.PreviewWith>
|
||||
<Styles.Resources>
|
||||
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" Color="{DynamicResource DataGridSelectionColor}" />
|
||||
<SolidColorBrush x:Key="ThemeAccentColorBrush" Color="{DynamicResource SystemAccentColor}" />
|
||||
<SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource ThemeAccentColor4}" />
|
||||
<Color x:Key="ControlFillColorSecondary">#008AA8</Color>
|
||||
<SolidColorBrush x:Key="ControlFillColorSecondaryBrush" Color="{StaticResource ControlFillColorSecondary}" />
|
||||
<StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="ControlFillColorSecondaryBrush" />
|
||||
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
|
||||
<Color x:Key="SystemAccentColorDark1">#FF99b000</Color>
|
||||
<Color x:Key="SystemAccentColorDark2">#FF006d7d</Color>
|
||||
<Color x:Key="SystemAccentColorDark3">#FF00525E</Color>
|
||||
<Color x:Key="SystemAccentColorLight1">#FF00dbff</Color>
|
||||
<Color x:Key="SystemAccentColorLight2">#FF19dfff</Color>
|
||||
<Color x:Key="SystemAccentColorLight3">#FF33e3ff</Color>
|
||||
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
||||
<Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</Color>
|
||||
<Color x:Key="ThemeControlBorderColor">#FF505050</Color>
|
||||
<Color x:Key="TextOnAccentFillColorPrimary">#FFFFFFFF</Color>
|
||||
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
||||
<Color x:Key="ThemeForegroundColor">#FFFFFFFF</Color>
|
||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#3D3D3D</Color>
|
||||
<Color x:Key="AppListBackgroundColor">#0FFFFFFF</Color>
|
||||
<Color x:Key="AppListHoverBackgroundColor">#1EFFFFFF</Color>
|
||||
<Color x:Key="SecondaryTextColor">#A0FFFFFF</Color>
|
||||
</Styles.Resources>
|
||||
</Styles>
|
@ -1,57 +0,0 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<StyleInclude Source="avares://Ryujinx.Ava/Assets/Styles/Styles.xaml" />
|
||||
<Design.PreviewWith>
|
||||
<Border Height="2000" Padding="20">
|
||||
<StackPanel Spacing="5">
|
||||
<TextBlock Text="Code Font Family" />
|
||||
<Grid RowDefinitions="*,Auto">
|
||||
<Menu Grid.Row="1" Width="100">
|
||||
<MenuItem Header="File">
|
||||
<MenuItem Header="Test 1" />
|
||||
<MenuItem Header="Test 2" />
|
||||
<MenuItem Header="Test 3">
|
||||
<MenuItem.Icon>
|
||||
<CheckBox Margin="0" IsChecked="{Binding Checkbox, Mode=TwoWay}" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button
|
||||
Name="btnAdd"
|
||||
HorizontalAlignment="Right"
|
||||
Content="Add" />
|
||||
<Button
|
||||
Name="btnRem"
|
||||
HorizontalAlignment="Right"
|
||||
Content="Add" />
|
||||
<TextBox
|
||||
Width="100"
|
||||
VerticalAlignment="Center"
|
||||
Text="Rrrrr"
|
||||
UseFloatingWatermark="True"
|
||||
Watermark="Hello" />
|
||||
<CheckBox>Test Check</CheckBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Design.PreviewWith>
|
||||
<Styles.Resources>
|
||||
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" Color="{DynamicResource DataGridSelectionColor}" />
|
||||
<SolidColorBrush x:Key="ThemeAccentColorBrush" Color="{DynamicResource SystemAccentColor}" />
|
||||
<SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource ThemeAccentColor4}" />
|
||||
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
|
||||
<Color x:Key="ThemeAccentColor4">#FFe8e8e8</Color>
|
||||
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
||||
<Color x:Key="ThemeContentBackgroundColor">#FFF0F0F0</Color>
|
||||
<Color x:Key="ThemeControlBorderColor">#FFd6d6d6</Color>
|
||||
<Color x:Key="TextOnAccentFillColorPrimary">#FFFFFFFF</Color>
|
||||
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
||||
<Color x:Key="ThemeForegroundColor">#FF000000</Color>
|
||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
|
||||
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
|
||||
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
|
||||
<Color x:Key="SecondaryTextColor">#A0000000</Color>
|
||||
</Styles.Resources>
|
||||
</Styles>
|
@ -1,323 +0,0 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia">
|
||||
<Design.PreviewWith>
|
||||
<Border Height="2000" Padding="20">
|
||||
<StackPanel Spacing="5">
|
||||
<TextBlock Text="Code Font Family" />
|
||||
<Grid RowDefinitions="*,Auto">
|
||||
<Menu Grid.Row="1" Width="100">
|
||||
<MenuItem Header="File">
|
||||
<MenuItem Header="Test 1" />
|
||||
<MenuItem Header="Test 2" />
|
||||
<MenuItem Header="Test 3">
|
||||
<MenuItem.Icon>
|
||||
<CheckBox Margin="0" IsChecked="{Binding Checkbox, Mode=TwoWay}" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ToggleButton
|
||||
Name="btnAdd"
|
||||
Height="28"
|
||||
HorizontalAlignment="Right"
|
||||
Content="Addy" />
|
||||
<Button
|
||||
Name="btnRem"
|
||||
HorizontalAlignment="Right"
|
||||
Content="Add" />
|
||||
<TextBox
|
||||
Width="100"
|
||||
VerticalAlignment="Center"
|
||||
Text="Rrrrr"
|
||||
UseFloatingWatermark="True"
|
||||
Watermark="Hello" />
|
||||
<CheckBox>Test Check</CheckBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<ui:NumberBox Value="1" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Design.PreviewWith>
|
||||
<Style Selector="Border.small">
|
||||
<Setter Property="Width" Value="100" />
|
||||
</Style>
|
||||
<Style Selector="Border.normal">
|
||||
<Setter Property="Width" Value="130" />
|
||||
</Style>
|
||||
<Style Selector="Border.large">
|
||||
<Setter Property="Width" Value="160" />
|
||||
</Style>
|
||||
<Style Selector="Border.huge">
|
||||
<Setter Property="Width" Value="200" />
|
||||
</Style>
|
||||
<Style Selector="Border.settings">
|
||||
<Setter Property="Background" Value="{DynamicResource ThemeDarkColor}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource MenuFlyoutPresenterBorderColor}" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="5" />
|
||||
</Style>
|
||||
<Style Selector="Image.small">
|
||||
<Setter Property="Width" Value="50" />
|
||||
</Style>
|
||||
<Style Selector="Image.normal">
|
||||
<Setter Property="Width" Value="80" />
|
||||
</Style>
|
||||
<Style Selector="Image.large">
|
||||
<Setter Property="Width" Value="100" />
|
||||
</Style>
|
||||
<Style Selector="Image.huge">
|
||||
<Setter Property="Width" Value="120" />
|
||||
</Style>
|
||||
<Style Selector="#TitleBarHost > Image">
|
||||
<Setter Property="Margin" Value="10" />
|
||||
</Style>
|
||||
<Style Selector="#TitleBarHost > Label">
|
||||
<Setter Property="Margin" Value="5" />
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
</Style>
|
||||
<Style Selector="Button.SystemCaption">
|
||||
<Setter Property="MinWidth" Value="10" />
|
||||
</Style>
|
||||
<Style Selector="DataGridColumnHeader">
|
||||
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundBrush}" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="Background" Value="{DynamicResource ThemeControlBorderColor}" />
|
||||
<Setter Property="SeparatorBrush" Value="{DynamicResource ThemeControlBorderColor}" />
|
||||
<Setter Property="Padding" Value="5" />
|
||||
<Setter Property="Background" Value="{DynamicResource ThemeContentBackgroundColor}" />
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<Grid Background="{TemplateBinding Background}" ColumnDefinitions="*,Auto">
|
||||
<Grid
|
||||
Margin="{TemplateBinding Padding}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
ColumnDefinitions="*,Auto">
|
||||
<ContentPresenter Content="{TemplateBinding Content}" />
|
||||
<Path
|
||||
Name="SortIcon"
|
||||
Grid.Column="1"
|
||||
Width="8"
|
||||
Margin="4,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Data="F1 M -5.215,6.099L 5.215,6.099L 0,0L -5.215,6.099 Z "
|
||||
Fill="{TemplateBinding Foreground}"
|
||||
Stretch="Uniform" />
|
||||
</Grid>
|
||||
<Rectangle
|
||||
Name="VerticalSeparator"
|
||||
Grid.Column="1"
|
||||
Width="1"
|
||||
VerticalAlignment="Stretch"
|
||||
Fill="{TemplateBinding SeparatorBrush}"
|
||||
IsVisible="{TemplateBinding AreSeparatorsVisible}" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style Selector="DataGrid">
|
||||
<Setter Property="RowBackground" Value="{DynamicResource ThemeAccentBrush4}" />
|
||||
<Setter Property="AlternatingRowBackground" Value="#00FFFFFF" />
|
||||
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundBrush}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ThemeBorderLowColor}" />
|
||||
<Setter Property="BorderThickness" Value="{DynamicResource ThemeBorderThickness}" />
|
||||
</Style>
|
||||
<Style Selector="DataGridRow:selected:focus /template/ Rectangle#BackgroundRectangle">
|
||||
<Setter Property="Fill" Value="{DynamicResource SystemAccentColor}" />
|
||||
<Setter Property="Opacity" Value="{DynamicResource DataGridRowSelectedBackgroundOpacity}" />
|
||||
</Style>
|
||||
<Style Selector="DataGridRow:pointerover /template/ Rectangle#BackgroundRectangle">
|
||||
<Setter Property="Fill" Value="{DynamicResource SystemListLowColor}" />
|
||||
</Style>
|
||||
<Style Selector="DataGridRow:selected /template/ Rectangle#BackgroundRectangle">
|
||||
<Setter Property="Fill" Value="{DynamicResource SystemAccentColor}" />
|
||||
<Setter Property="Opacity" Value="{DynamicResource DataGridRowSelectedUnfocusedBackgroundOpacity}" />
|
||||
</Style>
|
||||
<Style Selector="DataGridRow:selected:pointerover /template/ Rectangle#BackgroundRectangle">
|
||||
<Setter Property="Fill" Value="{DynamicResource SystemAccentColor}" />
|
||||
<Setter Property="Opacity" Value="{DynamicResource DataGridRowSelectedHoveredUnfocusedBackgroundOpacity}" />
|
||||
</Style>
|
||||
<Style Selector="DataGridRow:selected:pointerover:focus /template/ Rectangle#BackgroundRectangle">
|
||||
<Setter Property="Fill" Value="{DynamicResource SystemAccentColor}" />
|
||||
<Setter Property="Opacity" Value="{DynamicResource DataGridRowSelectedHoveredBackgroundOpacity}" />
|
||||
</Style>
|
||||
<Style Selector="DataGridCell">
|
||||
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
||||
</Style>
|
||||
<Style Selector="DataGridCell.Left">
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
</Style>
|
||||
<Style Selector="CheckBox">
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
</Style>
|
||||
|
||||
<Style Selector="MenuItem">
|
||||
<Setter Property="Height" Value="{DynamicResource MenuItemHeight}" />
|
||||
<Setter Property="Padding" Value="{DynamicResource MenuItemPadding}" />
|
||||
<Setter Property="FontSize" Value="12" />
|
||||
</Style>
|
||||
<Style Selector="MenuItem:selected /template/ Border#root">
|
||||
<Setter Property="Background" Value="{DynamicResource ThemeControlBorderColor}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ThemeControlBorderColor}" />
|
||||
</Style>
|
||||
<Style Selector="TabItem > ScrollViewer">
|
||||
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundColor}" />
|
||||
<Setter Property="Margin" Value="0,-5,0,0" />
|
||||
</Style>
|
||||
<Style Selector="TabItem > ScrollViewer > Border">
|
||||
<Setter Property="BorderThickness" Value="0,1,0,0" />
|
||||
<Setter Property="Background" Value="{DynamicResource ThemeBackgroundColor}" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource HighlightBrush}" />
|
||||
</Style>
|
||||
<Style Selector="Button">
|
||||
<Setter Property="MinWidth" Value="80" />
|
||||
</Style>
|
||||
<Style Selector="ProgressBar /template/ Border#ProgressBarTrack">
|
||||
<Setter Property="IsVisible" Value="False" />
|
||||
</Style>
|
||||
<Style Selector="ToggleButton">
|
||||
<Setter Property="Padding" Value="0,-5,0,0" />
|
||||
</Style>
|
||||
<Style Selector="TabItem">
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="BorderThickness" Value="0,0,1,0" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ThemeButtonForegroundColor}" />
|
||||
<Setter Property="Background" Value="{DynamicResource HighlightColor}" />
|
||||
</Style>
|
||||
<Style Selector="TabItem:pointerover">
|
||||
<Setter Property="Foreground" Value="{DynamicResource ThemeButtonForegroundColor}" />
|
||||
</Style>
|
||||
<Style Selector="TabItem:selected">
|
||||
<Setter Property="Background" Value="{DynamicResource HighlightColor}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource ThemeBackgroundColor}" />
|
||||
</Style>
|
||||
<Style Selector="TextBlock">
|
||||
<Setter Property="Margin" Value="{DynamicResource TextMargin}" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource FontSize}" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="TextWrapping" Value="WrapWithOverflow" />
|
||||
</Style>
|
||||
<Style Selector="TextBlock.h1">
|
||||
<Setter Property="Margin" Value="{DynamicResource TextMargin}" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="FontWeight" Value="Bold" />
|
||||
<Setter Property="FontSize" Value="16" />
|
||||
<Setter Property="TextWrapping" Value="WrapWithOverflow" />
|
||||
</Style>
|
||||
<Style Selector="Separator">
|
||||
<Setter Property="Background" Value="{DynamicResource ThemeControlBorderColor}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource ThemeControlBorderColor}" />
|
||||
<Setter Property="MinHeight" Value="1" />
|
||||
</Style>
|
||||
<Style Selector=":is(Button).DateTimeFlyoutButtonStyle">
|
||||
<Setter Property="Background" Value="{DynamicResource HighlightColor}" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource ThemeBackgroundColor}" />
|
||||
</Style>
|
||||
<Style Selector="DatePickerPresenter">
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ThemeButtonForegroundColor}" />
|
||||
</Style>
|
||||
<Style Selector="DataGridCell">
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
</Style>
|
||||
<Style Selector="CheckBox TextBlock">
|
||||
<Setter Property="Margin" Value="0,5,0,0" />
|
||||
</Style>
|
||||
<Style Selector="ContextMenu">
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource MenuFlyoutPresenterBorderBrush}" />
|
||||
<Setter Property="BorderThickness" Value="{DynamicResource MenuFlyoutPresenterBorderThemeThickness}" />
|
||||
</Style>
|
||||
<Style Selector="TextBox">
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
</Style>
|
||||
<Style Selector="TextBox.NumberBoxTextBoxStyle">
|
||||
<Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" />
|
||||
</Style>
|
||||
<Style Selector="ListBox ListBoxItem">
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="CornerRadius" Value="5" />
|
||||
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||
<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>
|
||||
<Style Selector="ListBox ListBoxItem:selected /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource AppListBackgroundColor}" />
|
||||
</Style>
|
||||
<Style Selector="ListBox ListBoxItem:pointerover /template/ ContentPresenter">
|
||||
<Setter Property="Background" Value="{DynamicResource AppListHoverBackgroundColor}" />
|
||||
</Style>
|
||||
<Styles.Resources>
|
||||
<SolidColorBrush x:Key="ThemeAccentColorBrush" Color="{DynamicResource SystemAccentColor}" />
|
||||
<StaticResource x:Key="ListViewItemBackgroundSelected" ResourceKey="ThemeAccentColorBrush" />
|
||||
<StaticResource x:Key="ListViewItemBackgroundPressed" ResourceKey="SystemAccentColorDark1" />
|
||||
<StaticResource x:Key="ListViewItemBackgroundPointerOver" ResourceKey="SystemAccentColorDark2" />
|
||||
<StaticResource x:Key="ListViewItemBackgroundSelectedPressed" ResourceKey="ThemeAccentColorBrush" />
|
||||
<StaticResource x:Key="ListViewItemBackgroundSelectedPointerOver" ResourceKey="SystemAccentColorDark2" />
|
||||
<SolidColorBrush
|
||||
x:Key="DataGridGridLinesBrush"
|
||||
Opacity="0.4"
|
||||
Color="{DynamicResource SystemBaseMediumLowColor}" />
|
||||
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" Color="{DynamicResource DataGridSelectionColor}" />
|
||||
<SolidColorBrush x:Key="MenuFlyoutPresenterBorderBrush" Color="{DynamicResource MenuFlyoutPresenterBorderColor}" />
|
||||
<SolidColorBrush x:Key="FlyoutBorderThemeBrush" Color="{DynamicResource MenuFlyoutPresenterBorderColor}" />
|
||||
<SolidColorBrush x:Key="ListBoxBackground" Color="{DynamicResource ThemeContentBackgroundColor}" />
|
||||
<SolidColorBrush x:Key="ThemeForegroundBrush" Color="{DynamicResource ThemeForegroundColor}" />
|
||||
<SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource ThemeAccentColor4}" />
|
||||
<SolidColorBrush x:Key="SplitButtonBackgroundChecked" Color="#00E81123" />
|
||||
<SolidColorBrush x:Key="SplitButtonBackgroundCheckedPointerOver" Color="#00E81123" />
|
||||
<SolidColorBrush x:Key="SplitButtonBackgroundCheckedPressed" Color="#00E81123" />
|
||||
<SolidColorBrush x:Key="SplitButtonBackgroundCheckedDisabled" Color="#00E81123" />
|
||||
<Thickness x:Key="PageMargin">40 0 40 0</Thickness>
|
||||
<Thickness x:Key="Margin">0 5 0 5</Thickness>
|
||||
<Thickness x:Key="MenuItemPadding">5 0 5 0</Thickness>
|
||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#00000000</Color>
|
||||
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
|
||||
<Color x:Key="SystemAccentColorDark1">#FF00C3E3</Color>
|
||||
<Color x:Key="SystemAccentColorDark2">#FF00C3E3</Color>
|
||||
<Color x:Key="SystemAccentColorDark3">#FF00C3E3</Color>
|
||||
<Color x:Key="SystemAccentColorLight1">#FF00C3E3</Color>
|
||||
<Color x:Key="SystemAccentColorLight2">#FF00C3E3</Color>
|
||||
<Color x:Key="SystemAccentColorLight3">#FF00C3E3</Color>
|
||||
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
||||
<Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</Color>
|
||||
<Color x:Key="ThemeControlBorderColor">#FF505050</Color>
|
||||
<Color x:Key="VsyncEnabled">#FF2EEAC9</Color>
|
||||
<Color x:Key="VsyncDisabled">#FFFF4554</Color>
|
||||
<Color x:Key="AppListBackgroundColor">#0FFFFFFF</Color>
|
||||
<Color x:Key="AppListHoverBackgroundColor">#1EFFFFFF</Color>
|
||||
<Color x:Key="SecondaryTextColor">#A0FFFFFF</Color>
|
||||
<x:Double x:Key="ScrollBarThickness">15</x:Double>
|
||||
<x:Double x:Key="FontSizeSmall">8</x:Double>
|
||||
<x:Double x:Key="FontSizeNormal">10</x:Double>
|
||||
<x:Double x:Key="FontSize">12</x:Double>
|
||||
<x:Double x:Key="FontSizeLarge">15</x:Double>
|
||||
<x:Double x:Key="ControlContentThemeFontSize">13</x:Double>
|
||||
<x:Double x:Key="MenuItemHeight">26</x:Double>
|
||||
<x:Double x:Key="TabItemMinHeight">28</x:Double>
|
||||
<x:Double x:Key="ContentDialogMaxWidth">600</x:Double>
|
||||
<x:Double x:Key="ContentDialogMaxHeight">756</x:Double>
|
||||
</Styles.Resources>
|
||||
</Styles>
|
@ -1,30 +0,0 @@
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Markup.Xaml.MarkupExtensions;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.Common.Locale
|
||||
{
|
||||
internal class LocaleExtension : MarkupExtension
|
||||
{
|
||||
public LocaleExtension(LocaleKeys key)
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public LocaleKeys Key { get; }
|
||||
|
||||
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||
{
|
||||
LocaleKeys keyToUse = Key;
|
||||
|
||||
ReflectionBindingExtension binding = new($"[{keyToUse}]")
|
||||
{
|
||||
Mode = BindingMode.OneWay,
|
||||
Source = LocaleManager.Instance
|
||||
};
|
||||
|
||||
return binding.ProvideValue(serviceProvider);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,177 +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: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"
|
||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d"
|
||||
Focusable="True">
|
||||
<UserControl.Resources>
|
||||
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||
<MenuFlyout x:Key="GameContextMenu">
|
||||
<MenuItem
|
||||
Command="{Binding ToggleFavorite}"
|
||||
Header="{locale:Locale GameListContextMenuToggleFavorite}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuToggleFavoriteToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Command="{Binding OpenUserSaveDirectory}"
|
||||
IsEnabled="{Binding EnabledUserSaveDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenUserSaveDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenDeviceSaveDirectory}"
|
||||
IsEnabled="{Binding EnabledDeviceSaveDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenDeviceSaveDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenDeviceSaveDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenBcatSaveDirectory}"
|
||||
IsEnabled="{Binding EnabledBcatSaveDirectory}"
|
||||
Header="{locale:Locale GameListContextMenuOpenBcatSaveDirectory}"
|
||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenBcatSaveDirectoryToolTip}" />
|
||||
<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="Margin" Value="5" />
|
||||
<Setter Property="CornerRadius" Value="4" />
|
||||
</Style>
|
||||
<Style Selector="ListBoxItem:selected /template/ Border#SelectionIndicator">
|
||||
<Setter Property="MinHeight" Value="{Binding $parent[UserControl].DataContext.GridItemSelectorSize}" />
|
||||
</Style>
|
||||
</ListBox.Styles>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Border
|
||||
Margin="10"
|
||||
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="4">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Image
|
||||
Grid.Row="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
|
||||
<Panel
|
||||
Grid.Row="1"
|
||||
Height="50"
|
||||
Margin="0 10 0 0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
IsVisible="{Binding $parent[UserControl].DataContext.ShowNames}">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding TitleName}"
|
||||
TextAlignment="Center"
|
||||
TextWrapping="Wrap" />
|
||||
</Panel>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ui:SymbolIcon
|
||||
Margin="5,5,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
FontSize="16"
|
||||
Foreground="{DynamicResource SystemAccentColor}"
|
||||
IsVisible="{Binding Favorite}"
|
||||
Symbol="StarFilled" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,52 +0,0 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Helpers
|
||||
{
|
||||
public class HotKeyControl : ContentControl, ICommandSource
|
||||
{
|
||||
public static readonly StyledProperty<object> CommandParameterProperty =
|
||||
AvaloniaProperty.Register<HotKeyControl, object>(nameof(CommandParameter));
|
||||
|
||||
public static readonly DirectProperty<HotKeyControl, ICommand> CommandProperty =
|
||||
AvaloniaProperty.RegisterDirect<HotKeyControl, ICommand>(nameof(Command),
|
||||
control => control.Command, (control, command) => control.Command = command, enableDataValidation: true);
|
||||
|
||||
public static readonly StyledProperty<KeyGesture> HotKeyProperty = HotKeyManager.HotKeyProperty.AddOwner<Button>();
|
||||
|
||||
private ICommand _command;
|
||||
private bool _commandCanExecute;
|
||||
|
||||
public ICommand Command
|
||||
{
|
||||
get { return _command; }
|
||||
set { SetAndRaise(CommandProperty, ref _command, value); }
|
||||
}
|
||||
|
||||
public KeyGesture HotKey
|
||||
{
|
||||
get { return GetValue(HotKeyProperty); }
|
||||
set { SetValue(HotKeyProperty, value); }
|
||||
}
|
||||
|
||||
public object CommandParameter
|
||||
{
|
||||
get { return GetValue(CommandParameterProperty); }
|
||||
set { SetValue(CommandParameterProperty, value); }
|
||||
}
|
||||
|
||||
public void CanExecuteChanged(object sender, EventArgs e)
|
||||
{
|
||||
var canExecute = Command == null || Command.CanExecute(CommandParameter);
|
||||
|
||||
if (canExecute != _commandCanExecute)
|
||||
{
|
||||
_commandCanExecute = canExecute;
|
||||
UpdateIsEffectivelyEnabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,363 +0,0 @@
|
||||
using Avalonia.Media;
|
||||
using DynamicData;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.Ncm;
|
||||
using LibHac.Tools.Fs;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Ava.UI.Models;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Formats.Png;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Color = Avalonia.Media.Color;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
internal class AvatarProfileViewModel : BaseModel, IDisposable
|
||||
{
|
||||
private const int MaxImageTasks = 4;
|
||||
|
||||
private static readonly Dictionary<string, byte[]> _avatarStore = new();
|
||||
private static bool _isPreloading;
|
||||
private static Action _loadCompleteAction;
|
||||
|
||||
private ObservableCollection<ProfileImageModel> _images;
|
||||
private Color _backgroundColor = Colors.White;
|
||||
|
||||
private int _selectedIndex;
|
||||
private int _imagesLoaded;
|
||||
private bool _isActive;
|
||||
private byte[] _selectedImage;
|
||||
private bool _isIndeterminate = true;
|
||||
|
||||
public bool IsActive
|
||||
{
|
||||
get => _isActive;
|
||||
set => _isActive = value;
|
||||
}
|
||||
|
||||
public AvatarProfileViewModel()
|
||||
{
|
||||
_images = new ObservableCollection<ProfileImageModel>();
|
||||
}
|
||||
|
||||
public AvatarProfileViewModel(Action loadCompleteAction)
|
||||
{
|
||||
_images = new ObservableCollection<ProfileImageModel>();
|
||||
|
||||
if (_isPreloading)
|
||||
{
|
||||
_loadCompleteAction = loadCompleteAction;
|
||||
}
|
||||
else
|
||||
{
|
||||
ReloadImages();
|
||||
}
|
||||
}
|
||||
|
||||
public Color BackgroundColor
|
||||
{
|
||||
get => _backgroundColor;
|
||||
set
|
||||
{
|
||||
_backgroundColor = value;
|
||||
|
||||
IsActive = false;
|
||||
|
||||
ReloadImages();
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<ProfileImageModel> Images
|
||||
{
|
||||
get => _images;
|
||||
set
|
||||
{
|
||||
_images = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsIndeterminate
|
||||
{
|
||||
get => _isIndeterminate;
|
||||
set
|
||||
{
|
||||
_isIndeterminate = value;
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public int ImageCount => _avatarStore.Count;
|
||||
|
||||
public int ImagesLoaded
|
||||
{
|
||||
get => _imagesLoaded;
|
||||
set
|
||||
{
|
||||
_imagesLoaded = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public int SelectedIndex
|
||||
{
|
||||
get => _selectedIndex;
|
||||
set
|
||||
{
|
||||
_selectedIndex = value;
|
||||
|
||||
if (_selectedIndex == -1)
|
||||
{
|
||||
SelectedImage = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedImage = _images[_selectedIndex].Data;
|
||||
}
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] SelectedImage
|
||||
{
|
||||
get => _selectedImage;
|
||||
private set => _selectedImage = value;
|
||||
}
|
||||
|
||||
public void ReloadImages()
|
||||
{
|
||||
if (_isPreloading)
|
||||
{
|
||||
IsIndeterminate = false;
|
||||
return;
|
||||
}
|
||||
Task.Run(() =>
|
||||
{
|
||||
IsActive = true;
|
||||
|
||||
Images.Clear();
|
||||
int selectedIndex = _selectedIndex;
|
||||
int index = 0;
|
||||
|
||||
ImagesLoaded = 0;
|
||||
IsIndeterminate = false;
|
||||
|
||||
var keys = _avatarStore.Keys.ToList();
|
||||
|
||||
var newImages = new List<ProfileImageModel>();
|
||||
var tasks = new List<Task>();
|
||||
|
||||
for (int i = 0; i < MaxImageTasks; i++)
|
||||
{
|
||||
var start = i;
|
||||
tasks.Add(Task.Run(() => ImageTask(start)));
|
||||
}
|
||||
|
||||
Task.WaitAll(tasks.ToArray());
|
||||
|
||||
Images.AddRange(newImages);
|
||||
|
||||
void ImageTask(int start)
|
||||
{
|
||||
for (int i = start; i < keys.Count; i += MaxImageTasks)
|
||||
{
|
||||
if (!IsActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var key = keys[i];
|
||||
var image = _avatarStore[keys[i]];
|
||||
|
||||
var data = ProcessImage(image);
|
||||
newImages.Add(new ProfileImageModel(key, data));
|
||||
if (index++ == selectedIndex)
|
||||
{
|
||||
SelectedImage = data;
|
||||
}
|
||||
|
||||
Interlocked.Increment(ref _imagesLoaded);
|
||||
OnPropertyChanged(nameof(ImagesLoaded));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private byte[] ProcessImage(byte[] data)
|
||||
{
|
||||
using (MemoryStream streamJpg = new())
|
||||
{
|
||||
Image avatarImage = Image.Load(data, new PngDecoder());
|
||||
|
||||
avatarImage.Mutate(x => x.BackgroundColor(new Rgba32(BackgroundColor.R,
|
||||
BackgroundColor.G,
|
||||
BackgroundColor.B,
|
||||
BackgroundColor.A)));
|
||||
avatarImage.SaveAsJpeg(streamJpg);
|
||||
|
||||
return streamJpg.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static void PreloadAvatars(ContentManager contentManager, VirtualFileSystem virtualFileSystem)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_avatarStore.Count > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isPreloading = true;
|
||||
|
||||
string contentPath =
|
||||
contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem,
|
||||
NcaContentType.Data);
|
||||
string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(avatarPath))
|
||||
{
|
||||
using (IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open))
|
||||
{
|
||||
Nca nca = new(virtualFileSystem.KeySet, ncaFileStream);
|
||||
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
||||
|
||||
foreach (DirectoryEntryEx item in romfs.EnumerateEntries())
|
||||
{
|
||||
// TODO: Parse DatabaseInfo.bin and table.bin files for more accuracy.
|
||||
if (item.Type == DirectoryEntryType.File && item.FullPath.Contains("chara") &&
|
||||
item.FullPath.Contains("szs"))
|
||||
{
|
||||
using var file = new UniqueRef<IFile>();
|
||||
|
||||
romfs.OpenFile(ref file.Ref, ("/" + item.FullPath).ToU8Span(), OpenMode.Read)
|
||||
.ThrowIfFailure();
|
||||
|
||||
using (MemoryStream stream = new())
|
||||
using (MemoryStream streamPng = new())
|
||||
{
|
||||
file.Get.AsStream().CopyTo(stream);
|
||||
|
||||
stream.Position = 0;
|
||||
|
||||
Image avatarImage = Image.LoadPixelData<Rgba32>(DecompressYaz0(stream), 256, 256);
|
||||
|
||||
avatarImage.SaveAsPng(streamPng);
|
||||
|
||||
_avatarStore.Add(item.FullPath, streamPng.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isPreloading = false;
|
||||
_loadCompleteAction?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] DecompressYaz0(Stream stream)
|
||||
{
|
||||
using (BinaryReader reader = new(stream))
|
||||
{
|
||||
reader.ReadInt32(); // Magic
|
||||
|
||||
uint decodedLength = BinaryPrimitives.ReverseEndianness(reader.ReadUInt32());
|
||||
|
||||
reader.ReadInt64(); // Padding
|
||||
|
||||
byte[] input = new byte[stream.Length - stream.Position];
|
||||
stream.Read(input, 0, input.Length);
|
||||
|
||||
uint inputOffset = 0;
|
||||
|
||||
byte[] output = new byte[decodedLength];
|
||||
uint outputOffset = 0;
|
||||
|
||||
ushort mask = 0;
|
||||
byte header = 0;
|
||||
|
||||
while (outputOffset < decodedLength)
|
||||
{
|
||||
if ((mask >>= 1) == 0)
|
||||
{
|
||||
header = input[inputOffset++];
|
||||
mask = 0x80;
|
||||
}
|
||||
|
||||
if ((header & mask) != 0)
|
||||
{
|
||||
if (outputOffset == output.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
output[outputOffset++] = input[inputOffset++];
|
||||
}
|
||||
else
|
||||
{
|
||||
byte byte1 = input[inputOffset++];
|
||||
byte byte2 = input[inputOffset++];
|
||||
|
||||
uint dist = (uint)((byte1 & 0xF) << 8) | byte2;
|
||||
uint position = outputOffset - (dist + 1);
|
||||
|
||||
uint length = (uint)byte1 >> 4;
|
||||
if (length == 0)
|
||||
{
|
||||
length = (uint)input[inputOffset++] + 0x12;
|
||||
}
|
||||
else
|
||||
{
|
||||
length += 2;
|
||||
}
|
||||
|
||||
uint gap = outputOffset - position;
|
||||
uint nonOverlappingLength = length;
|
||||
|
||||
if (nonOverlappingLength > gap)
|
||||
{
|
||||
nonOverlappingLength = gap;
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(output, (int)position, output, (int)outputOffset, (int)nonOverlappingLength);
|
||||
outputOffset += nonOverlappingLength;
|
||||
position += nonOverlappingLength;
|
||||
length -= nonOverlappingLength;
|
||||
|
||||
while (length-- > 0)
|
||||
{
|
||||
output[outputOffset++] = output[position++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_loadCompleteAction = null;
|
||||
IsActive = false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,230 +0,0 @@
|
||||
using Avalonia.Media;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.Ncm;
|
||||
using LibHac.Tools.Fs;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Ava.UI.Models;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using Color = Avalonia.Media.Color;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
internal class UserFirmwareAvatarSelectorViewModel : BaseModel
|
||||
{
|
||||
private static readonly Dictionary<string, byte[]> _avatarStore = new();
|
||||
|
||||
private ObservableCollection<ProfileImageModel> _images;
|
||||
private Color _backgroundColor = Colors.White;
|
||||
|
||||
private int _selectedIndex;
|
||||
private byte[] _selectedImage;
|
||||
|
||||
public UserFirmwareAvatarSelectorViewModel()
|
||||
{
|
||||
_images = new ObservableCollection<ProfileImageModel>();
|
||||
|
||||
LoadImagesFromStore();
|
||||
}
|
||||
|
||||
public Color BackgroundColor
|
||||
{
|
||||
get => _backgroundColor;
|
||||
set
|
||||
{
|
||||
_backgroundColor = value;
|
||||
OnPropertyChanged();
|
||||
ChangeImageBackground();
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<ProfileImageModel> Images
|
||||
{
|
||||
get => _images;
|
||||
set
|
||||
{
|
||||
_images = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public int SelectedIndex
|
||||
{
|
||||
get => _selectedIndex;
|
||||
set
|
||||
{
|
||||
_selectedIndex = value;
|
||||
|
||||
if (_selectedIndex == -1)
|
||||
{
|
||||
SelectedImage = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedImage = _images[_selectedIndex].Data;
|
||||
}
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] SelectedImage
|
||||
{
|
||||
get => _selectedImage;
|
||||
private set => _selectedImage = value;
|
||||
}
|
||||
|
||||
private void LoadImagesFromStore()
|
||||
{
|
||||
Images.Clear();
|
||||
|
||||
foreach (var image in _avatarStore)
|
||||
{
|
||||
Images.Add(new ProfileImageModel(image.Key, image.Value));
|
||||
}
|
||||
}
|
||||
|
||||
private void ChangeImageBackground()
|
||||
{
|
||||
foreach (var image in Images)
|
||||
{
|
||||
image.BackgroundColor = new SolidColorBrush(BackgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
public static void PreloadAvatars(ContentManager contentManager, VirtualFileSystem virtualFileSystem)
|
||||
{
|
||||
if (_avatarStore.Count > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data);
|
||||
string avatarPath = virtualFileSystem.SwitchPathToSystemPath(contentPath);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(avatarPath))
|
||||
{
|
||||
using (IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open))
|
||||
{
|
||||
Nca nca = new(virtualFileSystem.KeySet, ncaFileStream);
|
||||
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
|
||||
|
||||
foreach (DirectoryEntryEx item in romfs.EnumerateEntries())
|
||||
{
|
||||
// TODO: Parse DatabaseInfo.bin and table.bin files for more accuracy.
|
||||
if (item.Type == DirectoryEntryType.File && item.FullPath.Contains("chara") && item.FullPath.Contains("szs"))
|
||||
{
|
||||
using var file = new UniqueRef<IFile>();
|
||||
|
||||
romfs.OpenFile(ref file.Ref, ("/" + item.FullPath).ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
|
||||
using (MemoryStream stream = new())
|
||||
using (MemoryStream streamPng = new())
|
||||
{
|
||||
file.Get.AsStream().CopyTo(stream);
|
||||
|
||||
stream.Position = 0;
|
||||
|
||||
Image avatarImage = Image.LoadPixelData<Rgba32>(DecompressYaz0(stream), 256, 256);
|
||||
|
||||
avatarImage.SaveAsPng(streamPng);
|
||||
|
||||
_avatarStore.Add(item.FullPath, streamPng.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] DecompressYaz0(Stream stream)
|
||||
{
|
||||
using (BinaryReader reader = new(stream))
|
||||
{
|
||||
reader.ReadInt32(); // Magic
|
||||
|
||||
uint decodedLength = BinaryPrimitives.ReverseEndianness(reader.ReadUInt32());
|
||||
|
||||
reader.ReadInt64(); // Padding
|
||||
|
||||
byte[] input = new byte[stream.Length - stream.Position];
|
||||
stream.Read(input, 0, input.Length);
|
||||
|
||||
uint inputOffset = 0;
|
||||
|
||||
byte[] output = new byte[decodedLength];
|
||||
uint outputOffset = 0;
|
||||
|
||||
ushort mask = 0;
|
||||
byte header = 0;
|
||||
|
||||
while (outputOffset < decodedLength)
|
||||
{
|
||||
if ((mask >>= 1) == 0)
|
||||
{
|
||||
header = input[inputOffset++];
|
||||
mask = 0x80;
|
||||
}
|
||||
|
||||
if ((header & mask) != 0)
|
||||
{
|
||||
if (outputOffset == output.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
output[outputOffset++] = input[inputOffset++];
|
||||
}
|
||||
else
|
||||
{
|
||||
byte byte1 = input[inputOffset++];
|
||||
byte byte2 = input[inputOffset++];
|
||||
|
||||
uint dist = (uint)((byte1 & 0xF) << 8) | byte2;
|
||||
uint position = outputOffset - (dist + 1);
|
||||
|
||||
uint length = (uint)byte1 >> 4;
|
||||
if (length == 0)
|
||||
{
|
||||
length = (uint)input[inputOffset++] + 0x12;
|
||||
}
|
||||
else
|
||||
{
|
||||
length += 2;
|
||||
}
|
||||
|
||||
uint gap = outputOffset - position;
|
||||
uint nonOverlappingLength = length;
|
||||
|
||||
if (nonOverlappingLength > gap)
|
||||
{
|
||||
nonOverlappingLength = gap;
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(output, (int)position, output, (int)outputOffset, (int)nonOverlappingLength);
|
||||
outputOffset += nonOverlappingLength;
|
||||
position += nonOverlappingLength;
|
||||
length -= nonOverlappingLength;
|
||||
|
||||
while (length-- > 0)
|
||||
{
|
||||
output[outputOffset++] = output[position++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsInputView"
|
||||
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:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="viewModels:SettingsViewModel">
|
||||
<Design.DataContext>
|
||||
<viewModels:SettingsViewModel />
|
||||
</Design.DataContext>
|
||||
<ScrollViewer
|
||||
Name="InputPage"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="settings">
|
||||
<StackPanel Margin="4" Orientation="Vertical">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox Margin="5,0"
|
||||
ToolTip.Tip="{locale:Locale DockModeToggleTooltip}"
|
||||
IsChecked="{Binding EnableDockedMode}">
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{locale:Locale SettingsTabInputEnableDockedMode}" />
|
||||
</CheckBox>
|
||||
<CheckBox Margin="5,0"
|
||||
ToolTip.Tip="{locale:Locale DirectKeyboardTooltip}"
|
||||
IsChecked="{Binding EnableKeyboard}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabInputDirectKeyboardAccess}" />
|
||||
</CheckBox>
|
||||
<CheckBox Margin="5,0"
|
||||
ToolTip.Tip="{locale:Locale DirectMouseTooltip}"
|
||||
IsChecked="{Binding EnableMouse}">
|
||||
<TextBlock Text="{locale:Locale SettingsTabInputDirectMouseAccess}" />
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
<window:ControllerSettingsWindow Name="ControllerSettings" Margin="0" MinHeight="600" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
@ -1,71 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Models;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
public partial class MotionSettingsWindow : UserControl
|
||||
{
|
||||
private readonly InputConfiguration<GamepadInputId, StickInputId> _viewmodel;
|
||||
|
||||
public MotionSettingsWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = _viewmodel;
|
||||
}
|
||||
|
||||
public MotionSettingsWindow(ControllerSettingsViewModel viewmodel)
|
||||
{
|
||||
var config = viewmodel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
|
||||
|
||||
_viewmodel = new InputConfiguration<GamepadInputId, StickInputId>()
|
||||
{
|
||||
Slot = config.Slot,
|
||||
AltSlot = config.AltSlot,
|
||||
DsuServerHost = config.DsuServerHost,
|
||||
DsuServerPort = config.DsuServerPort,
|
||||
MirrorInput = config.MirrorInput,
|
||||
EnableMotion = config.EnableMotion,
|
||||
Sensitivity = config.Sensitivity,
|
||||
GyroDeadzone = config.GyroDeadzone,
|
||||
EnableCemuHookMotion = config.EnableCemuHookMotion
|
||||
};
|
||||
|
||||
InitializeComponent();
|
||||
DataContext = _viewmodel;
|
||||
}
|
||||
|
||||
public static async Task Show(ControllerSettingsViewModel viewmodel)
|
||||
{
|
||||
MotionSettingsWindow content = new MotionSettingsWindow(viewmodel);
|
||||
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.ControllerMotionTitle],
|
||||
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave],
|
||||
SecondaryButtonText = "",
|
||||
CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose],
|
||||
Content = content
|
||||
};
|
||||
contentDialog.PrimaryButtonClick += (sender, args) =>
|
||||
{
|
||||
var config = viewmodel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
|
||||
config.Slot = content._viewmodel.Slot;
|
||||
config.EnableMotion = content._viewmodel.EnableMotion;
|
||||
config.Sensitivity = content._viewmodel.Sensitivity;
|
||||
config.GyroDeadzone = content._viewmodel.GyroDeadzone;
|
||||
config.AltSlot = content._viewmodel.AltSlot;
|
||||
config.DsuServerHost = content._viewmodel.DsuServerHost;
|
||||
config.DsuServerPort = content._viewmodel.DsuServerPort;
|
||||
config.EnableCemuHookMotion = content._viewmodel.EnableCemuHookMotion;
|
||||
config.MirrorInput = content._viewmodel.MirrorInput;
|
||||
};
|
||||
|
||||
await contentDialog.ShowAsync();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Models;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
public partial class RumbleSettingsWindow : UserControl
|
||||
{
|
||||
private readonly InputConfiguration<GamepadInputId, StickInputId> _viewmodel;
|
||||
|
||||
public RumbleSettingsWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = _viewmodel;
|
||||
}
|
||||
|
||||
public RumbleSettingsWindow(ControllerSettingsViewModel viewmodel)
|
||||
{
|
||||
var config = viewmodel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
|
||||
|
||||
_viewmodel = new InputConfiguration<GamepadInputId, StickInputId>()
|
||||
{
|
||||
StrongRumble = config.StrongRumble, WeakRumble = config.WeakRumble
|
||||
};
|
||||
|
||||
InitializeComponent();
|
||||
DataContext = _viewmodel;
|
||||
}
|
||||
|
||||
public static async Task Show(ControllerSettingsViewModel viewmodel)
|
||||
{
|
||||
RumbleSettingsWindow content = new RumbleSettingsWindow(viewmodel);
|
||||
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.ControllerRumbleTitle],
|
||||
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave],
|
||||
SecondaryButtonText = "",
|
||||
CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose],
|
||||
Content = content,
|
||||
};
|
||||
|
||||
contentDialog.PrimaryButtonClick += (sender, args) =>
|
||||
{
|
||||
var config = viewmodel.Configuration as InputConfiguration<GamepadInputId, StickInputId>;
|
||||
config.StrongRumble = content._viewmodel.StrongRumble;
|
||||
config.WeakRumble = content._viewmodel.WeakRumble;
|
||||
};
|
||||
|
||||
await contentDialog.ShowAsync();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration.Hid
|
||||
{
|
||||
public class GenericInputConfigurationCommon<Button> : InputConfig where Button : unmanaged
|
||||
{
|
||||
/// <summary>
|
||||
/// Left JoyCon Controller Bindings
|
||||
/// </summary>
|
||||
public LeftJoyconCommonConfig<Button> LeftJoycon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Right JoyCon Controller Bindings
|
||||
/// </summary>
|
||||
public RightJoyconCommonConfig<Button> RightJoycon { get; set; }
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration.Hid.Keyboard
|
||||
{
|
||||
public class JoyconConfigKeyboardStick<Key> where Key: unmanaged
|
||||
{
|
||||
public Key StickUp { get; set; }
|
||||
public Key StickDown { get; set; }
|
||||
public Key StickLeft { get; set; }
|
||||
public Key StickRight { get; set; }
|
||||
public Key StickButton { get; set; }
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration.Hid
|
||||
{
|
||||
public class LeftJoyconCommonConfig<Button>
|
||||
{
|
||||
public Button ButtonMinus { get; set; }
|
||||
public Button ButtonL { get; set; }
|
||||
public Button ButtonZl { get; set; }
|
||||
public Button ButtonSl { get; set; }
|
||||
public Button ButtonSr { get; set; }
|
||||
public Button DpadUp { get; set; }
|
||||
public Button DpadDown { get; set; }
|
||||
public Button DpadLeft { get; set; }
|
||||
public Button DpadRight { get; set; }
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration.Hid
|
||||
{
|
||||
public class RightJoyconCommonConfig<Button>
|
||||
{
|
||||
public Button ButtonPlus { get; set; }
|
||||
public Button ButtonR { get; set; }
|
||||
public Button ButtonZr { get; set; }
|
||||
public Button ButtonSl { get; set; }
|
||||
public Button ButtonSr { get; set; }
|
||||
public Button ButtonX { get; set; }
|
||||
public Button ButtonB { get; set; }
|
||||
public Button ButtonY { get; set; }
|
||||
public Button ButtonA { get; set; }
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
using Microsoft.IO;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
public static class StreamUtils
|
||||
{
|
||||
public static byte[] StreamToBytes(Stream input)
|
||||
{
|
||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
||||
{
|
||||
input.CopyTo(stream);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<byte[]> StreamToBytesAsync(Stream input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
||||
{
|
||||
await input.CopyToAsync(stream, cancellationToken);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,320 +0,0 @@
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Cpu.AppleHv
|
||||
{
|
||||
struct hv_vcpu_exit_exception_t
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public ulong syndrome;
|
||||
public ulong virtual_address;
|
||||
public ulong physical_address;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
struct hv_vcpu_exit_t
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public uint reason;
|
||||
public hv_vcpu_exit_exception_t exception;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
enum hv_reg_t : uint
|
||||
{
|
||||
HV_REG_X0,
|
||||
HV_REG_X1,
|
||||
HV_REG_X2,
|
||||
HV_REG_X3,
|
||||
HV_REG_X4,
|
||||
HV_REG_X5,
|
||||
HV_REG_X6,
|
||||
HV_REG_X7,
|
||||
HV_REG_X8,
|
||||
HV_REG_X9,
|
||||
HV_REG_X10,
|
||||
HV_REG_X11,
|
||||
HV_REG_X12,
|
||||
HV_REG_X13,
|
||||
HV_REG_X14,
|
||||
HV_REG_X15,
|
||||
HV_REG_X16,
|
||||
HV_REG_X17,
|
||||
HV_REG_X18,
|
||||
HV_REG_X19,
|
||||
HV_REG_X20,
|
||||
HV_REG_X21,
|
||||
HV_REG_X22,
|
||||
HV_REG_X23,
|
||||
HV_REG_X24,
|
||||
HV_REG_X25,
|
||||
HV_REG_X26,
|
||||
HV_REG_X27,
|
||||
HV_REG_X28,
|
||||
HV_REG_X29,
|
||||
HV_REG_FP = HV_REG_X29,
|
||||
HV_REG_X30,
|
||||
HV_REG_LR = HV_REG_X30,
|
||||
HV_REG_PC,
|
||||
HV_REG_FPCR,
|
||||
HV_REG_FPSR,
|
||||
HV_REG_CPSR,
|
||||
}
|
||||
|
||||
enum hv_simd_fp_reg_t : uint
|
||||
{
|
||||
HV_SIMD_FP_REG_Q0,
|
||||
HV_SIMD_FP_REG_Q1,
|
||||
HV_SIMD_FP_REG_Q2,
|
||||
HV_SIMD_FP_REG_Q3,
|
||||
HV_SIMD_FP_REG_Q4,
|
||||
HV_SIMD_FP_REG_Q5,
|
||||
HV_SIMD_FP_REG_Q6,
|
||||
HV_SIMD_FP_REG_Q7,
|
||||
HV_SIMD_FP_REG_Q8,
|
||||
HV_SIMD_FP_REG_Q9,
|
||||
HV_SIMD_FP_REG_Q10,
|
||||
HV_SIMD_FP_REG_Q11,
|
||||
HV_SIMD_FP_REG_Q12,
|
||||
HV_SIMD_FP_REG_Q13,
|
||||
HV_SIMD_FP_REG_Q14,
|
||||
HV_SIMD_FP_REG_Q15,
|
||||
HV_SIMD_FP_REG_Q16,
|
||||
HV_SIMD_FP_REG_Q17,
|
||||
HV_SIMD_FP_REG_Q18,
|
||||
HV_SIMD_FP_REG_Q19,
|
||||
HV_SIMD_FP_REG_Q20,
|
||||
HV_SIMD_FP_REG_Q21,
|
||||
HV_SIMD_FP_REG_Q22,
|
||||
HV_SIMD_FP_REG_Q23,
|
||||
HV_SIMD_FP_REG_Q24,
|
||||
HV_SIMD_FP_REG_Q25,
|
||||
HV_SIMD_FP_REG_Q26,
|
||||
HV_SIMD_FP_REG_Q27,
|
||||
HV_SIMD_FP_REG_Q28,
|
||||
HV_SIMD_FP_REG_Q29,
|
||||
HV_SIMD_FP_REG_Q30,
|
||||
HV_SIMD_FP_REG_Q31,
|
||||
}
|
||||
|
||||
enum hv_sys_reg_t : ushort
|
||||
{
|
||||
HV_SYS_REG_DBGBVR0_EL1 = 0x8004,
|
||||
HV_SYS_REG_DBGBCR0_EL1 = 0x8005,
|
||||
HV_SYS_REG_DBGWVR0_EL1 = 0x8006,
|
||||
HV_SYS_REG_DBGWCR0_EL1 = 0x8007,
|
||||
HV_SYS_REG_DBGBVR1_EL1 = 0x800c,
|
||||
HV_SYS_REG_DBGBCR1_EL1 = 0x800d,
|
||||
HV_SYS_REG_DBGWVR1_EL1 = 0x800e,
|
||||
HV_SYS_REG_DBGWCR1_EL1 = 0x800f,
|
||||
HV_SYS_REG_MDCCINT_EL1 = 0x8010,
|
||||
HV_SYS_REG_MDSCR_EL1 = 0x8012,
|
||||
HV_SYS_REG_DBGBVR2_EL1 = 0x8014,
|
||||
HV_SYS_REG_DBGBCR2_EL1 = 0x8015,
|
||||
HV_SYS_REG_DBGWVR2_EL1 = 0x8016,
|
||||
HV_SYS_REG_DBGWCR2_EL1 = 0x8017,
|
||||
HV_SYS_REG_DBGBVR3_EL1 = 0x801c,
|
||||
HV_SYS_REG_DBGBCR3_EL1 = 0x801d,
|
||||
HV_SYS_REG_DBGWVR3_EL1 = 0x801e,
|
||||
HV_SYS_REG_DBGWCR3_EL1 = 0x801f,
|
||||
HV_SYS_REG_DBGBVR4_EL1 = 0x8024,
|
||||
HV_SYS_REG_DBGBCR4_EL1 = 0x8025,
|
||||
HV_SYS_REG_DBGWVR4_EL1 = 0x8026,
|
||||
HV_SYS_REG_DBGWCR4_EL1 = 0x8027,
|
||||
HV_SYS_REG_DBGBVR5_EL1 = 0x802c,
|
||||
HV_SYS_REG_DBGBCR5_EL1 = 0x802d,
|
||||
HV_SYS_REG_DBGWVR5_EL1 = 0x802e,
|
||||
HV_SYS_REG_DBGWCR5_EL1 = 0x802f,
|
||||
HV_SYS_REG_DBGBVR6_EL1 = 0x8034,
|
||||
HV_SYS_REG_DBGBCR6_EL1 = 0x8035,
|
||||
HV_SYS_REG_DBGWVR6_EL1 = 0x8036,
|
||||
HV_SYS_REG_DBGWCR6_EL1 = 0x8037,
|
||||
HV_SYS_REG_DBGBVR7_EL1 = 0x803c,
|
||||
HV_SYS_REG_DBGBCR7_EL1 = 0x803d,
|
||||
HV_SYS_REG_DBGWVR7_EL1 = 0x803e,
|
||||
HV_SYS_REG_DBGWCR7_EL1 = 0x803f,
|
||||
HV_SYS_REG_DBGBVR8_EL1 = 0x8044,
|
||||
HV_SYS_REG_DBGBCR8_EL1 = 0x8045,
|
||||
HV_SYS_REG_DBGWVR8_EL1 = 0x8046,
|
||||
HV_SYS_REG_DBGWCR8_EL1 = 0x8047,
|
||||
HV_SYS_REG_DBGBVR9_EL1 = 0x804c,
|
||||
HV_SYS_REG_DBGBCR9_EL1 = 0x804d,
|
||||
HV_SYS_REG_DBGWVR9_EL1 = 0x804e,
|
||||
HV_SYS_REG_DBGWCR9_EL1 = 0x804f,
|
||||
HV_SYS_REG_DBGBVR10_EL1 = 0x8054,
|
||||
HV_SYS_REG_DBGBCR10_EL1 = 0x8055,
|
||||
HV_SYS_REG_DBGWVR10_EL1 = 0x8056,
|
||||
HV_SYS_REG_DBGWCR10_EL1 = 0x8057,
|
||||
HV_SYS_REG_DBGBVR11_EL1 = 0x805c,
|
||||
HV_SYS_REG_DBGBCR11_EL1 = 0x805d,
|
||||
HV_SYS_REG_DBGWVR11_EL1 = 0x805e,
|
||||
HV_SYS_REG_DBGWCR11_EL1 = 0x805f,
|
||||
HV_SYS_REG_DBGBVR12_EL1 = 0x8064,
|
||||
HV_SYS_REG_DBGBCR12_EL1 = 0x8065,
|
||||
HV_SYS_REG_DBGWVR12_EL1 = 0x8066,
|
||||
HV_SYS_REG_DBGWCR12_EL1 = 0x8067,
|
||||
HV_SYS_REG_DBGBVR13_EL1 = 0x806c,
|
||||
HV_SYS_REG_DBGBCR13_EL1 = 0x806d,
|
||||
HV_SYS_REG_DBGWVR13_EL1 = 0x806e,
|
||||
HV_SYS_REG_DBGWCR13_EL1 = 0x806f,
|
||||
HV_SYS_REG_DBGBVR14_EL1 = 0x8074,
|
||||
HV_SYS_REG_DBGBCR14_EL1 = 0x8075,
|
||||
HV_SYS_REG_DBGWVR14_EL1 = 0x8076,
|
||||
HV_SYS_REG_DBGWCR14_EL1 = 0x8077,
|
||||
HV_SYS_REG_DBGBVR15_EL1 = 0x807c,
|
||||
HV_SYS_REG_DBGBCR15_EL1 = 0x807d,
|
||||
HV_SYS_REG_DBGWVR15_EL1 = 0x807e,
|
||||
HV_SYS_REG_DBGWCR15_EL1 = 0x807f,
|
||||
HV_SYS_REG_MIDR_EL1 = 0xc000,
|
||||
HV_SYS_REG_MPIDR_EL1 = 0xc005,
|
||||
HV_SYS_REG_ID_AA64PFR0_EL1 = 0xc020,
|
||||
HV_SYS_REG_ID_AA64PFR1_EL1 = 0xc021,
|
||||
HV_SYS_REG_ID_AA64DFR0_EL1 = 0xc028,
|
||||
HV_SYS_REG_ID_AA64DFR1_EL1 = 0xc029,
|
||||
HV_SYS_REG_ID_AA64ISAR0_EL1 = 0xc030,
|
||||
HV_SYS_REG_ID_AA64ISAR1_EL1 = 0xc031,
|
||||
HV_SYS_REG_ID_AA64MMFR0_EL1 = 0xc038,
|
||||
HV_SYS_REG_ID_AA64MMFR1_EL1 = 0xc039,
|
||||
HV_SYS_REG_ID_AA64MMFR2_EL1 = 0xc03a,
|
||||
HV_SYS_REG_SCTLR_EL1 = 0xc080,
|
||||
HV_SYS_REG_CPACR_EL1 = 0xc082,
|
||||
HV_SYS_REG_TTBR0_EL1 = 0xc100,
|
||||
HV_SYS_REG_TTBR1_EL1 = 0xc101,
|
||||
HV_SYS_REG_TCR_EL1 = 0xc102,
|
||||
HV_SYS_REG_APIAKEYLO_EL1 = 0xc108,
|
||||
HV_SYS_REG_APIAKEYHI_EL1 = 0xc109,
|
||||
HV_SYS_REG_APIBKEYLO_EL1 = 0xc10a,
|
||||
HV_SYS_REG_APIBKEYHI_EL1 = 0xc10b,
|
||||
HV_SYS_REG_APDAKEYLO_EL1 = 0xc110,
|
||||
HV_SYS_REG_APDAKEYHI_EL1 = 0xc111,
|
||||
HV_SYS_REG_APDBKEYLO_EL1 = 0xc112,
|
||||
HV_SYS_REG_APDBKEYHI_EL1 = 0xc113,
|
||||
HV_SYS_REG_APGAKEYLO_EL1 = 0xc118,
|
||||
HV_SYS_REG_APGAKEYHI_EL1 = 0xc119,
|
||||
HV_SYS_REG_SPSR_EL1 = 0xc200,
|
||||
HV_SYS_REG_ELR_EL1 = 0xc201,
|
||||
HV_SYS_REG_SP_EL0 = 0xc208,
|
||||
HV_SYS_REG_AFSR0_EL1 = 0xc288,
|
||||
HV_SYS_REG_AFSR1_EL1 = 0xc289,
|
||||
HV_SYS_REG_ESR_EL1 = 0xc290,
|
||||
HV_SYS_REG_FAR_EL1 = 0xc300,
|
||||
HV_SYS_REG_PAR_EL1 = 0xc3a0,
|
||||
HV_SYS_REG_MAIR_EL1 = 0xc510,
|
||||
HV_SYS_REG_AMAIR_EL1 = 0xc518,
|
||||
HV_SYS_REG_VBAR_EL1 = 0xc600,
|
||||
HV_SYS_REG_CONTEXTIDR_EL1 = 0xc681,
|
||||
HV_SYS_REG_TPIDR_EL1 = 0xc684,
|
||||
HV_SYS_REG_CNTKCTL_EL1 = 0xc708,
|
||||
HV_SYS_REG_CSSELR_EL1 = 0xd000,
|
||||
HV_SYS_REG_TPIDR_EL0 = 0xde82,
|
||||
HV_SYS_REG_TPIDRRO_EL0 = 0xde83,
|
||||
HV_SYS_REG_CNTV_CTL_EL0 = 0xdf19,
|
||||
HV_SYS_REG_CNTV_CVAL_EL0 = 0xdf1a,
|
||||
HV_SYS_REG_SP_EL1 = 0xe208,
|
||||
}
|
||||
|
||||
enum hv_memory_flags_t : ulong
|
||||
{
|
||||
HV_MEMORY_READ = 1UL << 0,
|
||||
HV_MEMORY_WRITE = 1UL << 1,
|
||||
HV_MEMORY_EXEC = 1UL << 2
|
||||
}
|
||||
|
||||
enum hv_result_t : uint
|
||||
{
|
||||
HV_SUCCESS = 0,
|
||||
HV_ERROR = 0xfae94001,
|
||||
HV_BUSY = 0xfae94002,
|
||||
HV_BAD_ARGUMENT = 0xfae94003,
|
||||
HV_NO_RESOURCES = 0xfae94005,
|
||||
HV_NO_DEVICE = 0xfae94006,
|
||||
HV_DENIED = 0xfae94007,
|
||||
HV_UNSUPPORTED = 0xfae9400f
|
||||
}
|
||||
|
||||
enum hv_interrupt_type_t : uint
|
||||
{
|
||||
HV_INTERRUPT_TYPE_IRQ,
|
||||
HV_INTERRUPT_TYPE_FIQ
|
||||
}
|
||||
|
||||
struct hv_simd_fp_uchar16_t
|
||||
{
|
||||
public ulong Low;
|
||||
public ulong High;
|
||||
}
|
||||
|
||||
static class HvResultExtensions
|
||||
{
|
||||
public static void ThrowOnError(this hv_result_t result)
|
||||
{
|
||||
if (result != hv_result_t.HV_SUCCESS)
|
||||
{
|
||||
throw new Exception($"Unexpected result \"{result}\".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static partial class HvApi
|
||||
{
|
||||
public const string LibraryName = "/System/Library/Frameworks/Hypervisor.framework/Hypervisor";
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vm_get_max_vcpu_count(out uint max_vcpu_count);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vm_create(IntPtr config);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vm_destroy();
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vm_map(ulong addr, ulong ipa, ulong size, hv_memory_flags_t flags);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vm_unmap(ulong ipa, ulong size);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vm_protect(ulong ipa, ulong size, hv_memory_flags_t flags);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public unsafe static partial hv_result_t hv_vcpu_create(out ulong vcpu, ref hv_vcpu_exit_t* exit, IntPtr config);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public unsafe static partial hv_result_t hv_vcpu_destroy(ulong vcpu);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_run(ulong vcpu);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpus_exit(ref ulong vcpus, uint vcpu_count);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_set_vtimer_mask(ulong vcpu, [MarshalAs(UnmanagedType.Bool)] bool vtimer_is_masked);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_get_reg(ulong vcpu, hv_reg_t reg, out ulong value);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_set_reg(ulong vcpu, hv_reg_t reg, ulong value);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_get_simd_fp_reg(ulong vcpu, hv_simd_fp_reg_t reg, out hv_simd_fp_uchar16_t value);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_set_simd_fp_reg(ulong vcpu, hv_simd_fp_reg_t reg, hv_simd_fp_uchar16_t value); // DO NOT USE DIRECTLY!
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_get_sys_reg(ulong vcpu, hv_sys_reg_t reg, out ulong value);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_set_sys_reg(ulong vcpu, hv_sys_reg_t reg, ulong value);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_get_pending_interrupt(ulong vcpu, hv_interrupt_type_t type, [MarshalAs(UnmanagedType.Bool)] out bool pending);
|
||||
|
||||
[LibraryImport(LibraryName, SetLastError = true)]
|
||||
public static partial hv_result_t hv_vcpu_set_pending_interrupt(ulong vcpu, hv_interrupt_type_t type, [MarshalAs(UnmanagedType.Bool)] bool pending);
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
namespace Ryujinx.Cpu.AppleHv
|
||||
{
|
||||
unsafe class HvVcpu
|
||||
{
|
||||
public readonly ulong Handle;
|
||||
public readonly hv_vcpu_exit_t* ExitInfo;
|
||||
public readonly IHvExecutionContext ShadowContext;
|
||||
public readonly IHvExecutionContext NativeContext;
|
||||
public readonly bool IsEphemeral;
|
||||
|
||||
public HvVcpu(
|
||||
ulong handle,
|
||||
hv_vcpu_exit_t* exitInfo,
|
||||
IHvExecutionContext shadowContext,
|
||||
IHvExecutionContext nativeContext,
|
||||
bool isEphemeral)
|
||||
{
|
||||
Handle = handle;
|
||||
ExitInfo = exitInfo;
|
||||
ShadowContext = shadowContext;
|
||||
NativeContext = nativeContext;
|
||||
IsEphemeral = isEphemeral;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
using Ryujinx.Memory.Tracking;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Cpu.Tracking
|
||||
{
|
||||
public class CpuMultiRegionHandle : IMultiRegionHandle
|
||||
{
|
||||
private readonly MultiRegionHandle _impl;
|
||||
|
||||
public bool Dirty => _impl.Dirty;
|
||||
|
||||
internal CpuMultiRegionHandle(MultiRegionHandle impl)
|
||||
{
|
||||
_impl = impl;
|
||||
}
|
||||
|
||||
public void Dispose() => _impl.Dispose();
|
||||
public void ForceDirty(ulong address, ulong size) => _impl.ForceDirty(address, size);
|
||||
public IEnumerable<IRegionHandle> GetHandles() => _impl.GetHandles();
|
||||
public void QueryModified(Action<ulong, ulong> modifiedAction) => _impl.QueryModified(modifiedAction);
|
||||
public void QueryModified(ulong address, ulong size, Action<ulong, ulong> modifiedAction) => _impl.QueryModified(address, size, modifiedAction);
|
||||
public void QueryModified(ulong address, ulong size, Action<ulong, ulong> modifiedAction, int sequenceNumber) => _impl.QueryModified(address, size, modifiedAction, sequenceNumber);
|
||||
public void RegisterAction(ulong address, ulong size, RegionSignal action) => _impl.RegisterAction(address, size, action);
|
||||
public void RegisterPreciseAction(ulong address, ulong size, PreciseRegionSignal action) => _impl.RegisterPreciseAction(address, size, action);
|
||||
public void SignalWrite() => _impl.SignalWrite();
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
using Ryujinx.Memory.Tracking;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Cpu.Tracking
|
||||
{
|
||||
public class CpuRegionHandle : IRegionHandle
|
||||
{
|
||||
private readonly RegionHandle _impl;
|
||||
|
||||
public bool Dirty => _impl.Dirty;
|
||||
public bool Unmapped => _impl.Unmapped;
|
||||
public ulong Address => _impl.Address;
|
||||
public ulong Size => _impl.Size;
|
||||
public ulong EndAddress => _impl.EndAddress;
|
||||
|
||||
internal CpuRegionHandle(RegionHandle impl)
|
||||
{
|
||||
_impl = impl;
|
||||
}
|
||||
|
||||
public void Dispose() => _impl.Dispose();
|
||||
public bool DirtyOrVolatile() => _impl.DirtyOrVolatile();
|
||||
public void ForceDirty() => _impl.ForceDirty();
|
||||
public IRegionHandle GetHandle() => _impl;
|
||||
public void RegisterAction(RegionSignal action) => _impl.RegisterAction(action);
|
||||
public void RegisterPreciseAction(PreciseRegionSignal action) => _impl.RegisterPreciseAction(action);
|
||||
public void RegisterDirtyEvent(Action action) => _impl.RegisterDirtyEvent(action);
|
||||
public void Reprotect(bool asDirty = false) => _impl.Reprotect(asDirty);
|
||||
|
||||
public bool OverlapsWith(ulong address, ulong size) => _impl.OverlapsWith(address, size);
|
||||
|
||||
public bool RangeEquals(CpuRegionHandle other)
|
||||
{
|
||||
return _impl.RealAddress == other._impl.RealAddress && _impl.RealSize == other._impl.RealSize;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
using Ryujinx.Memory.Tracking;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Cpu.Tracking
|
||||
{
|
||||
public class CpuSmartMultiRegionHandle : IMultiRegionHandle
|
||||
{
|
||||
private readonly SmartMultiRegionHandle _impl;
|
||||
|
||||
public bool Dirty => _impl.Dirty;
|
||||
|
||||
internal CpuSmartMultiRegionHandle(SmartMultiRegionHandle impl)
|
||||
{
|
||||
_impl = impl;
|
||||
}
|
||||
|
||||
public void Dispose() => _impl.Dispose();
|
||||
public void ForceDirty(ulong address, ulong size) => _impl.ForceDirty(address, size);
|
||||
public void RegisterAction(RegionSignal action) => _impl.RegisterAction(action);
|
||||
public void RegisterPreciseAction(PreciseRegionSignal action) => _impl.RegisterPreciseAction(action);
|
||||
public void QueryModified(Action<ulong, ulong> modifiedAction) => _impl.QueryModified(modifiedAction);
|
||||
public void QueryModified(ulong address, ulong size, Action<ulong, ulong> modifiedAction) => _impl.QueryModified(address, size, modifiedAction);
|
||||
public void QueryModified(ulong address, ulong size, Action<ulong, ulong> modifiedAction, int sequenceNumber) => _impl.QueryModified(address, size, modifiedAction, sequenceNumber);
|
||||
public void SignalWrite() => _impl.SignalWrite();
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public enum BlendOp
|
||||
{
|
||||
Add = 1,
|
||||
Subtract,
|
||||
ReverseSubtract,
|
||||
Minimum,
|
||||
Maximum,
|
||||
|
||||
AddGl = 0x8006,
|
||||
MinimumGl = 0x8007,
|
||||
MaximumGl = 0x8008,
|
||||
SubtractGl = 0x800a,
|
||||
ReverseSubtractGl = 0x800b
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public enum Face
|
||||
{
|
||||
Front = 0x404,
|
||||
Back = 0x405,
|
||||
FrontAndBack = 0x408
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public readonly struct ImageCrop
|
||||
{
|
||||
public int Left { get; }
|
||||
public int Right { get; }
|
||||
public int Top { get; }
|
||||
public int Bottom { get; }
|
||||
public bool FlipX { get; }
|
||||
public bool FlipY { get; }
|
||||
public bool IsStretched { get; }
|
||||
public float AspectRatioX { get; }
|
||||
public float AspectRatioY { get; }
|
||||
|
||||
public ImageCrop(
|
||||
int left,
|
||||
int right,
|
||||
int top,
|
||||
int bottom,
|
||||
bool flipX,
|
||||
bool flipY,
|
||||
bool isStretched,
|
||||
float aspectRatioX,
|
||||
float aspectRatioY)
|
||||
{
|
||||
Left = left;
|
||||
Right = right;
|
||||
Top = top;
|
||||
Bottom = bottom;
|
||||
FlipX = flipX;
|
||||
FlipY = flipY;
|
||||
IsStretched = isStretched;
|
||||
AspectRatioX = aspectRatioX;
|
||||
AspectRatioY = aspectRatioY;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||
{
|
||||
struct SetRenderTargetScaleCommand : IGALCommand, IGALCommand<SetRenderTargetScaleCommand>
|
||||
{
|
||||
public CommandType CommandType => CommandType.SetRenderTargetScale;
|
||||
private float _scale;
|
||||
|
||||
public void Set(float scale)
|
||||
{
|
||||
_scale = scale;
|
||||
}
|
||||
|
||||
public static void Run(ref SetRenderTargetScaleCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
renderer.Pipeline.SetRenderTargetScale(command._scale);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Model;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||
{
|
||||
struct UpdateRenderScaleCommand : IGALCommand, IGALCommand<UpdateRenderScaleCommand>
|
||||
{
|
||||
public CommandType CommandType => CommandType.UpdateRenderScale;
|
||||
private SpanRef<float> _scales;
|
||||
private int _totalCount;
|
||||
private int _fragmentCount;
|
||||
|
||||
public void Set(SpanRef<float> scales, int totalCount, int fragmentCount)
|
||||
{
|
||||
_scales = scales;
|
||||
_totalCount = totalCount;
|
||||
_fragmentCount = fragmentCount;
|
||||
}
|
||||
|
||||
public static void Run(ref UpdateRenderScaleCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
renderer.Pipeline.UpdateRenderScale(command._scales.Get(threaded), command._totalCount, command._fragmentCount);
|
||||
command._scales.Dispose(threaded);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public readonly struct ScreenCaptureImageInfo
|
||||
{
|
||||
public ScreenCaptureImageInfo(int width, int height, bool isBgra, byte[] data, bool flipX, bool flipY)
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
IsBgra = isBgra;
|
||||
Data = data;
|
||||
FlipX = flipX;
|
||||
FlipY = flipY;
|
||||
}
|
||||
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
public byte[] Data { get; }
|
||||
public bool IsBgra { get; }
|
||||
public bool FlipX { get; }
|
||||
public bool FlipY { get; }
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public readonly struct ShaderBindings
|
||||
{
|
||||
public IReadOnlyCollection<int> UniformBufferBindings { get; }
|
||||
public IReadOnlyCollection<int> StorageBufferBindings { get; }
|
||||
public IReadOnlyCollection<int> TextureBindings { get; }
|
||||
public IReadOnlyCollection<int> ImageBindings { get; }
|
||||
|
||||
public ShaderBindings(
|
||||
IReadOnlyCollection<int> uniformBufferBindings,
|
||||
IReadOnlyCollection<int> storageBufferBindings,
|
||||
IReadOnlyCollection<int> textureBindings,
|
||||
IReadOnlyCollection<int> imageBindings)
|
||||
{
|
||||
UniformBufferBindings = uniformBufferBindings;
|
||||
StorageBufferBindings = storageBufferBindings;
|
||||
TextureBindings = textureBindings;
|
||||
ImageBindings = imageBindings;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public readonly struct StencilTestDescriptor
|
||||
{
|
||||
public bool TestEnable { get; }
|
||||
|
||||
public CompareOp FrontFunc { get; }
|
||||
public StencilOp FrontSFail { get; }
|
||||
public StencilOp FrontDpPass { get; }
|
||||
public StencilOp FrontDpFail { get; }
|
||||
public int FrontFuncRef { get; }
|
||||
public int FrontFuncMask { get; }
|
||||
public int FrontMask { get; }
|
||||
public CompareOp BackFunc { get; }
|
||||
public StencilOp BackSFail { get; }
|
||||
public StencilOp BackDpPass { get; }
|
||||
public StencilOp BackDpFail { get; }
|
||||
public int BackFuncRef { get; }
|
||||
public int BackFuncMask { get; }
|
||||
public int BackMask { get; }
|
||||
|
||||
public StencilTestDescriptor(
|
||||
bool testEnable,
|
||||
CompareOp frontFunc,
|
||||
StencilOp frontSFail,
|
||||
StencilOp frontDpPass,
|
||||
StencilOp frontDpFail,
|
||||
int frontFuncRef,
|
||||
int frontFuncMask,
|
||||
int frontMask,
|
||||
CompareOp backFunc,
|
||||
StencilOp backSFail,
|
||||
StencilOp backDpPass,
|
||||
StencilOp backDpFail,
|
||||
int backFuncRef,
|
||||
int backFuncMask,
|
||||
int backMask)
|
||||
{
|
||||
TestEnable = testEnable;
|
||||
FrontFunc = frontFunc;
|
||||
FrontSFail = frontSFail;
|
||||
FrontDpPass = frontDpPass;
|
||||
FrontDpFail = frontDpFail;
|
||||
FrontFuncRef = frontFuncRef;
|
||||
FrontFuncMask = frontFuncMask;
|
||||
FrontMask = frontMask;
|
||||
BackFunc = backFunc;
|
||||
BackSFail = backSFail;
|
||||
BackDpPass = backDpPass;
|
||||
BackDpFail = backDpFail;
|
||||
BackFuncRef = backFuncRef;
|
||||
BackFuncMask = backFuncMask;
|
||||
BackMask = backMask;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public class SupportBufferUpdater : IDisposable
|
||||
{
|
||||
public SupportBuffer Data;
|
||||
public BufferHandle Handle;
|
||||
|
||||
private IRenderer _renderer;
|
||||
private int _startOffset = -1;
|
||||
private int _endOffset = -1;
|
||||
|
||||
public SupportBufferUpdater(IRenderer renderer)
|
||||
{
|
||||
_renderer = renderer;
|
||||
Handle = renderer.CreateBuffer(SupportBuffer.RequiredSize);
|
||||
renderer.Pipeline.ClearBuffer(Handle, 0, SupportBuffer.RequiredSize, 0);
|
||||
}
|
||||
|
||||
private void MarkDirty(int startOffset, int byteSize)
|
||||
{
|
||||
int endOffset = startOffset + byteSize;
|
||||
|
||||
if (_startOffset == -1)
|
||||
{
|
||||
_startOffset = startOffset;
|
||||
_endOffset = endOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (startOffset < _startOffset)
|
||||
{
|
||||
_startOffset = startOffset;
|
||||
}
|
||||
|
||||
if (endOffset > _endOffset)
|
||||
{
|
||||
_endOffset = endOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateFragmentRenderScaleCount(int count)
|
||||
{
|
||||
if (Data.FragmentRenderScaleCount.X != count)
|
||||
{
|
||||
Data.FragmentRenderScaleCount.X = count;
|
||||
|
||||
MarkDirty(SupportBuffer.FragmentRenderScaleCountOffset, sizeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateGenericField<T>(int baseOffset, ReadOnlySpan<T> data, Span<T> target, int offset, int count) where T : unmanaged
|
||||
{
|
||||
data.Slice(0, count).CopyTo(target.Slice(offset));
|
||||
|
||||
int elemSize = Unsafe.SizeOf<T>();
|
||||
|
||||
MarkDirty(baseOffset + offset * elemSize, count * elemSize);
|
||||
}
|
||||
|
||||
public void UpdateRenderScale(ReadOnlySpan<Vector4<float>> data, int offset, int count)
|
||||
{
|
||||
UpdateGenericField(SupportBuffer.GraphicsRenderScaleOffset, data, Data.RenderScale.AsSpan(), offset, count);
|
||||
}
|
||||
|
||||
public void UpdateFragmentIsBgra(ReadOnlySpan<Vector4<int>> data, int offset, int count)
|
||||
{
|
||||
UpdateGenericField(SupportBuffer.FragmentIsBgraOffset, data, Data.FragmentIsBgra.AsSpan(), offset, count);
|
||||
}
|
||||
|
||||
public void UpdateViewportInverse(Vector4<float> data)
|
||||
{
|
||||
Data.ViewportInverse = data;
|
||||
|
||||
MarkDirty(SupportBuffer.ViewportInverseOffset, SupportBuffer.FieldSize);
|
||||
}
|
||||
|
||||
public void Commit()
|
||||
{
|
||||
if (_startOffset != -1)
|
||||
{
|
||||
ReadOnlySpan<byte> data = MemoryMarshal.Cast<SupportBuffer, byte>(MemoryMarshal.CreateSpan(ref Data, 1));
|
||||
|
||||
_renderer.SetBufferData(Handle, _startOffset, data.Slice(_startOffset, _endOffset - _startOffset));
|
||||
|
||||
_startOffset = -1;
|
||||
_endOffset = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_renderer.DeleteBuffer(Handle);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,275 +0,0 @@
|
||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of the dependent Queue Meta Data.
|
||||
/// </summary>
|
||||
enum DependentQmdType
|
||||
{
|
||||
Queue,
|
||||
Grid
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of the release memory barrier.
|
||||
/// </summary>
|
||||
enum ReleaseMembarType
|
||||
{
|
||||
FeNone,
|
||||
FeSysmembar
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of the CWD memory barrier.
|
||||
/// </summary>
|
||||
enum CwdMembarType
|
||||
{
|
||||
L1None,
|
||||
L1Sysmembar,
|
||||
L1Membar
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// NaN behavior of 32-bits float operations on the shader.
|
||||
/// </summary>
|
||||
enum Fp32NanBehavior
|
||||
{
|
||||
Legacy,
|
||||
Fp64Compatible
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// NaN behavior of 32-bits float to integer conversion on the shader.
|
||||
/// </summary>
|
||||
enum Fp32F2iNanBehavior
|
||||
{
|
||||
PassZero,
|
||||
PassIndefinite
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Limit of calls.
|
||||
/// </summary>
|
||||
enum ApiVisibleCallLimit
|
||||
{
|
||||
_32,
|
||||
NoCheck
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shared memory bank mapping mode.
|
||||
/// </summary>
|
||||
enum SharedMemoryBankMapping
|
||||
{
|
||||
FourBytesPerBank,
|
||||
EightBytesPerBank
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Denormal behavior of 32-bits float narrowing instructions.
|
||||
/// </summary>
|
||||
enum Fp32NarrowInstruction
|
||||
{
|
||||
KeepDenorms,
|
||||
FlushDenorms
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configuration of the L1 cache.
|
||||
/// </summary>
|
||||
enum L1Configuration
|
||||
{
|
||||
DirectlyAddressableMemorySize16kb,
|
||||
DirectlyAddressableMemorySize32kb,
|
||||
DirectlyAddressableMemorySize48kb
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reduction operation.
|
||||
/// </summary>
|
||||
enum ReductionOp
|
||||
{
|
||||
RedAdd,
|
||||
RedMin,
|
||||
RedMax,
|
||||
RedInc,
|
||||
RedDec,
|
||||
RedAnd,
|
||||
RedOr,
|
||||
RedXor
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reduction format.
|
||||
/// </summary>
|
||||
enum ReductionFormat
|
||||
{
|
||||
Unsigned32,
|
||||
Signed32
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Size of a structure in words.
|
||||
/// </summary>
|
||||
enum StructureSize
|
||||
{
|
||||
FourWords,
|
||||
OneWord
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compute Queue Meta Data.
|
||||
/// </summary>
|
||||
unsafe struct ComputeQmd
|
||||
{
|
||||
private fixed int _words[64];
|
||||
|
||||
public int OuterPut => BitRange(30, 0);
|
||||
public bool OuterOverflow => Bit(31);
|
||||
public int OuterGet => BitRange(62, 32);
|
||||
public bool OuterStickyOverflow => Bit(63);
|
||||
public int InnerGet => BitRange(94, 64);
|
||||
public bool InnerOverflow => Bit(95);
|
||||
public int InnerPut => BitRange(126, 96);
|
||||
public bool InnerStickyOverflow => Bit(127);
|
||||
public int QmdReservedAA => BitRange(159, 128);
|
||||
public int DependentQmdPointer => BitRange(191, 160);
|
||||
public int QmdGroupId => BitRange(197, 192);
|
||||
public bool SmGlobalCachingEnable => Bit(198);
|
||||
public bool RunCtaInOneSmPartition => Bit(199);
|
||||
public bool IsQueue => Bit(200);
|
||||
public bool AddToHeadOfQmdGroupLinkedList => Bit(201);
|
||||
public bool SemaphoreReleaseEnable0 => Bit(202);
|
||||
public bool SemaphoreReleaseEnable1 => Bit(203);
|
||||
public bool RequireSchedulingPcas => Bit(204);
|
||||
public bool DependentQmdScheduleEnable => Bit(205);
|
||||
public DependentQmdType DependentQmdType => (DependentQmdType)BitRange(206, 206);
|
||||
public bool DependentQmdFieldCopy => Bit(207);
|
||||
public int QmdReservedB => BitRange(223, 208);
|
||||
public int CircularQueueSize => BitRange(248, 224);
|
||||
public bool QmdReservedC => Bit(249);
|
||||
public bool InvalidateTextureHeaderCache => Bit(250);
|
||||
public bool InvalidateTextureSamplerCache => Bit(251);
|
||||
public bool InvalidateTextureDataCache => Bit(252);
|
||||
public bool InvalidateShaderDataCache => Bit(253);
|
||||
public bool InvalidateInstructionCache => Bit(254);
|
||||
public bool InvalidateShaderConstantCache => Bit(255);
|
||||
public int ProgramOffset => BitRange(287, 256);
|
||||
public int CircularQueueAddrLower => BitRange(319, 288);
|
||||
public int CircularQueueAddrUpper => BitRange(327, 320);
|
||||
public int QmdReservedD => BitRange(335, 328);
|
||||
public int CircularQueueEntrySize => BitRange(351, 336);
|
||||
public int CwdReferenceCountId => BitRange(357, 352);
|
||||
public int CwdReferenceCountDeltaMinusOne => BitRange(365, 358);
|
||||
public ReleaseMembarType ReleaseMembarType => (ReleaseMembarType)BitRange(366, 366);
|
||||
public bool CwdReferenceCountIncrEnable => Bit(367);
|
||||
public CwdMembarType CwdMembarType => (CwdMembarType)BitRange(369, 368);
|
||||
public bool SequentiallyRunCtas => Bit(370);
|
||||
public bool CwdReferenceCountDecrEnable => Bit(371);
|
||||
public bool Throttled => Bit(372);
|
||||
public Fp32NanBehavior Fp32NanBehavior => (Fp32NanBehavior)BitRange(376, 376);
|
||||
public Fp32F2iNanBehavior Fp32F2iNanBehavior => (Fp32F2iNanBehavior)BitRange(377, 377);
|
||||
public ApiVisibleCallLimit ApiVisibleCallLimit => (ApiVisibleCallLimit)BitRange(378, 378);
|
||||
public SharedMemoryBankMapping SharedMemoryBankMapping => (SharedMemoryBankMapping)BitRange(379, 379);
|
||||
public SamplerIndex SamplerIndex => (SamplerIndex)BitRange(382, 382);
|
||||
public Fp32NarrowInstruction Fp32NarrowInstruction => (Fp32NarrowInstruction)BitRange(383, 383);
|
||||
public int CtaRasterWidth => BitRange(415, 384);
|
||||
public int CtaRasterHeight => BitRange(431, 416);
|
||||
public int CtaRasterDepth => BitRange(447, 432);
|
||||
public int CtaRasterWidthResume => BitRange(479, 448);
|
||||
public int CtaRasterHeightResume => BitRange(495, 480);
|
||||
public int CtaRasterDepthResume => BitRange(511, 496);
|
||||
public int QueueEntriesPerCtaMinusOne => BitRange(518, 512);
|
||||
public int CoalesceWaitingPeriod => BitRange(529, 522);
|
||||
public int SharedMemorySize => BitRange(561, 544);
|
||||
public int QmdReservedG => BitRange(575, 562);
|
||||
public int QmdVersion => BitRange(579, 576);
|
||||
public int QmdMajorVersion => BitRange(583, 580);
|
||||
public int QmdReservedH => BitRange(591, 584);
|
||||
public int CtaThreadDimension0 => BitRange(607, 592);
|
||||
public int CtaThreadDimension1 => BitRange(623, 608);
|
||||
public int CtaThreadDimension2 => BitRange(639, 624);
|
||||
public bool ConstantBufferValid(int i) => Bit(640 + i * 1);
|
||||
public int QmdReservedI => BitRange(668, 648);
|
||||
public L1Configuration L1Configuration => (L1Configuration)BitRange(671, 669);
|
||||
public int SmDisableMaskLower => BitRange(703, 672);
|
||||
public int SmDisableMaskUpper => BitRange(735, 704);
|
||||
public int Release0AddressLower => BitRange(767, 736);
|
||||
public int Release0AddressUpper => BitRange(775, 768);
|
||||
public int QmdReservedJ => BitRange(783, 776);
|
||||
public ReductionOp Release0ReductionOp => (ReductionOp)BitRange(790, 788);
|
||||
public bool QmdReservedK => Bit(791);
|
||||
public ReductionFormat Release0ReductionFormat => (ReductionFormat)BitRange(793, 792);
|
||||
public bool Release0ReductionEnable => Bit(794);
|
||||
public StructureSize Release0StructureSize => (StructureSize)BitRange(799, 799);
|
||||
public int Release0Payload => BitRange(831, 800);
|
||||
public int Release1AddressLower => BitRange(863, 832);
|
||||
public int Release1AddressUpper => BitRange(871, 864);
|
||||
public int QmdReservedL => BitRange(879, 872);
|
||||
public ReductionOp Release1ReductionOp => (ReductionOp)BitRange(886, 884);
|
||||
public bool QmdReservedM => Bit(887);
|
||||
public ReductionFormat Release1ReductionFormat => (ReductionFormat)BitRange(889, 888);
|
||||
public bool Release1ReductionEnable => Bit(890);
|
||||
public StructureSize Release1StructureSize => (StructureSize)BitRange(895, 895);
|
||||
public int Release1Payload => BitRange(927, 896);
|
||||
public int ConstantBufferAddrLower(int i) => BitRange(959 + i * 64, 928 + i * 64);
|
||||
public int ConstantBufferAddrUpper(int i) => BitRange(967 + i * 64, 960 + i * 64);
|
||||
public int ConstantBufferReservedAddr(int i) => BitRange(973 + i * 64, 968 + i * 64);
|
||||
public bool ConstantBufferInvalidate(int i) => Bit(974 + i * 64);
|
||||
public int ConstantBufferSize(int i) => BitRange(991 + i * 64, 975 + i * 64);
|
||||
public int ShaderLocalMemoryLowSize => BitRange(1463, 1440);
|
||||
public int QmdReservedN => BitRange(1466, 1464);
|
||||
public int BarrierCount => BitRange(1471, 1467);
|
||||
public int ShaderLocalMemoryHighSize => BitRange(1495, 1472);
|
||||
public int RegisterCount => BitRange(1503, 1496);
|
||||
public int ShaderLocalMemoryCrsSize => BitRange(1527, 1504);
|
||||
public int SassVersion => BitRange(1535, 1528);
|
||||
public int HwOnlyInnerGet => BitRange(1566, 1536);
|
||||
public bool HwOnlyRequireSchedulingPcas => Bit(1567);
|
||||
public int HwOnlyInnerPut => BitRange(1598, 1568);
|
||||
public bool HwOnlyScgType => Bit(1599);
|
||||
public int HwOnlySpanListHeadIndex => BitRange(1629, 1600);
|
||||
public bool QmdReservedQ => Bit(1630);
|
||||
public bool HwOnlySpanListHeadIndexValid => Bit(1631);
|
||||
public int HwOnlySkedNextQmdPointer => BitRange(1663, 1632);
|
||||
public int QmdSpareE => BitRange(1695, 1664);
|
||||
public int QmdSpareF => BitRange(1727, 1696);
|
||||
public int QmdSpareG => BitRange(1759, 1728);
|
||||
public int QmdSpareH => BitRange(1791, 1760);
|
||||
public int QmdSpareI => BitRange(1823, 1792);
|
||||
public int QmdSpareJ => BitRange(1855, 1824);
|
||||
public int QmdSpareK => BitRange(1887, 1856);
|
||||
public int QmdSpareL => BitRange(1919, 1888);
|
||||
public int QmdSpareM => BitRange(1951, 1920);
|
||||
public int QmdSpareN => BitRange(1983, 1952);
|
||||
public int DebugIdUpper => BitRange(2015, 1984);
|
||||
public int DebugIdLower => BitRange(2047, 2016);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool Bit(int bit)
|
||||
{
|
||||
if ((uint)bit >= 64 * 32)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(bit));
|
||||
}
|
||||
|
||||
return (_words[bit >> 5] & (1 << (bit & 31))) != 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private int BitRange(int upper, int lower)
|
||||
{
|
||||
if ((uint)lower >= 64 * 32)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(lower));
|
||||
}
|
||||
|
||||
int mask = (int)(uint.MaxValue >> (32 - (upper - lower + 1)));
|
||||
|
||||
return (_words[lower >> 5] >> (lower & 31)) & mask;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
// This file was auto-generated from NVIDIA official Maxwell definitions.
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
||||
{
|
||||
enum TertOp
|
||||
{
|
||||
Grp0IncMethod = 0,
|
||||
Grp0SetSubDevMask = 1,
|
||||
Grp0StoreSubDevMask = 2,
|
||||
Grp0UseSubDevMask = 3,
|
||||
Grp2NonIncMethod = 0
|
||||
}
|
||||
|
||||
enum SecOp
|
||||
{
|
||||
Grp0UseTert = 0,
|
||||
IncMethod = 1,
|
||||
Grp2UseTert = 2,
|
||||
NonIncMethod = 3,
|
||||
ImmdDataMethod = 4,
|
||||
OneInc = 5,
|
||||
Reserved6 = 6,
|
||||
EndPbSegment = 7
|
||||
}
|
||||
|
||||
struct CompressedMethod
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public uint Method;
|
||||
#pragma warning restore CS0649
|
||||
public int MethodAddressOld => (int)((Method >> 2) & 0x7FF);
|
||||
public int MethodAddress => (int)((Method >> 0) & 0xFFF);
|
||||
public int SubdeviceMask => (int)((Method >> 4) & 0xFFF);
|
||||
public int MethodSubchannel => (int)((Method >> 13) & 0x7);
|
||||
public TertOp TertOp => (TertOp)((Method >> 16) & 0x3);
|
||||
public int MethodCountOld => (int)((Method >> 18) & 0x7FF);
|
||||
public int MethodCount => (int)((Method >> 16) & 0x1FFF);
|
||||
public int ImmdData => (int)((Method >> 16) & 0x1FFF);
|
||||
public SecOp SecOp => (SecOp)((Method >> 29) & 0x7);
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
// This file was auto-generated from NVIDIA official Maxwell definitions.
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
||||
{
|
||||
enum Entry0Fetch
|
||||
{
|
||||
Unconditional = 0,
|
||||
Conditional = 1,
|
||||
}
|
||||
|
||||
enum Entry1Priv
|
||||
{
|
||||
User = 0,
|
||||
Kernel = 1,
|
||||
}
|
||||
|
||||
enum Entry1Level
|
||||
{
|
||||
Main = 0,
|
||||
Subroutine = 1,
|
||||
}
|
||||
|
||||
enum Entry1Sync
|
||||
{
|
||||
Proceed = 0,
|
||||
Wait = 1,
|
||||
}
|
||||
|
||||
enum Entry1Opcode
|
||||
{
|
||||
Nop = 0,
|
||||
Illegal = 1,
|
||||
Crc = 2,
|
||||
PbCrc = 3,
|
||||
}
|
||||
|
||||
struct GPEntry
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public uint Entry0;
|
||||
#pragma warning restore CS0649
|
||||
public Entry0Fetch Entry0Fetch => (Entry0Fetch)((Entry0 >> 0) & 0x1);
|
||||
public int Entry0Get => (int)((Entry0 >> 2) & 0x3FFFFFFF);
|
||||
public int Entry0Operand => (int)(Entry0);
|
||||
#pragma warning disable CS0649
|
||||
public uint Entry1;
|
||||
#pragma warning restore CS0649
|
||||
public int Entry1GetHi => (int)((Entry1 >> 0) & 0xFF);
|
||||
public Entry1Priv Entry1Priv => (Entry1Priv)((Entry1 >> 8) & 0x1);
|
||||
public Entry1Level Entry1Level => (Entry1Level)((Entry1 >> 9) & 0x1);
|
||||
public int Entry1Length => (int)((Entry1 >> 10) & 0x1FFFFF);
|
||||
public Entry1Sync Entry1Sync => (Entry1Sync)((Entry1 >> 31) & 0x1);
|
||||
public Entry1Opcode Entry1Opcode => (Entry1Opcode)((Entry1 >> 0) & 0xFF);
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
public class UnmapEventArgs
|
||||
{
|
||||
public ulong Address { get; }
|
||||
public ulong Size { get; }
|
||||
|
||||
public UnmapEventArgs(ulong address, ulong size)
|
||||
{
|
||||
Address = address;
|
||||
Size = size;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
internal enum PredictionMode
|
||||
{
|
||||
DcPred = 0, // Average of above and left pixels
|
||||
VPred = 1, // Vertical
|
||||
HPred = 2, // Horizontal
|
||||
D45Pred = 3, // Directional 45 deg = round(arctan(1 / 1) * 180 / pi)
|
||||
D135Pred = 4, // Directional 135 deg = 180 - 45
|
||||
D117Pred = 5, // Directional 117 deg = 180 - 63
|
||||
D153Pred = 6, // Directional 153 deg = 180 - 27
|
||||
D207Pred = 7, // Directional 207 deg = 180 + 27
|
||||
D63Pred = 8, // Directional 63 deg = round(arctan(2 / 1) * 180 / pi)
|
||||
TmPred = 9, // True-motion
|
||||
NearestMv = 10,
|
||||
NearMv = 11,
|
||||
ZeroMv = 12,
|
||||
NewMv = 13,
|
||||
MbModeCount = 14
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
internal enum SegLvlFeatures
|
||||
{
|
||||
SegLvlAltQ = 0, // Use alternate Quantizer ....
|
||||
SegLvlAltLf = 1, // Use alternate loop filter value...
|
||||
SegLvlRefFrame = 2, // Optional Segment reference frame
|
||||
SegLvlSkip = 3, // Optional Segment (0,0) + skip mode
|
||||
SegLvlMax = 4 // Number of features supported
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
public enum TxMode
|
||||
{
|
||||
Only4X4 = 0, // Only 4x4 transform used
|
||||
Allow8X8 = 1, // Allow block transform size up to 8x8
|
||||
Allow16X16 = 2, // Allow block transform size up to 16x16
|
||||
Allow32X32 = 3, // Allow block transform size up to 32x32
|
||||
TxModeSelect = 4, // Transform specified for each block
|
||||
TxModes = 5
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
internal enum TxType
|
||||
{
|
||||
DctDct = 0, // DCT in both horizontal and vertical
|
||||
AdstDct = 1, // ADST in vertical, DCT in horizontal
|
||||
DctAdst = 2, // DCT in vertical, ADST in horizontal
|
||||
AdstAdst = 3, // ADST in both directions
|
||||
TxTypes = 4
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL
|
||||
{
|
||||
readonly struct FormatInfo
|
||||
{
|
||||
public int Components { get; }
|
||||
public bool Normalized { get; }
|
||||
public bool Scaled { get; }
|
||||
|
||||
public PixelInternalFormat PixelInternalFormat { get; }
|
||||
public PixelFormat PixelFormat { get; }
|
||||
public PixelType PixelType { get; }
|
||||
|
||||
public bool IsCompressed { get; }
|
||||
|
||||
public FormatInfo(
|
||||
int components,
|
||||
bool normalized,
|
||||
bool scaled,
|
||||
All pixelInternalFormat,
|
||||
PixelFormat pixelFormat,
|
||||
PixelType pixelType)
|
||||
{
|
||||
Components = components;
|
||||
Normalized = normalized;
|
||||
Scaled = scaled;
|
||||
PixelInternalFormat = (PixelInternalFormat)pixelInternalFormat;
|
||||
PixelFormat = pixelFormat;
|
||||
PixelType = pixelType;
|
||||
IsCompressed = false;
|
||||
}
|
||||
|
||||
public FormatInfo(int components, bool normalized, bool scaled, All pixelFormat)
|
||||
{
|
||||
Components = components;
|
||||
Normalized = normalized;
|
||||
Scaled = scaled;
|
||||
PixelInternalFormat = 0;
|
||||
PixelFormat = (PixelFormat)pixelFormat;
|
||||
PixelType = 0;
|
||||
IsCompressed = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL
|
||||
{
|
||||
static class HwCapabilities
|
||||
{
|
||||
private static readonly Lazy<bool> _supportsAlphaToCoverageDitherControl = new Lazy<bool>(() => HasExtension("GL_NV_alpha_to_coverage_dither_control"));
|
||||
private static readonly Lazy<bool> _supportsAstcCompression = new Lazy<bool>(() => HasExtension("GL_KHR_texture_compression_astc_ldr"));
|
||||
private static readonly Lazy<bool> _supportsBlendEquationAdvanced = new Lazy<bool>(() => HasExtension("GL_NV_blend_equation_advanced"));
|
||||
private static readonly Lazy<bool> _supportsDrawTexture = new Lazy<bool>(() => HasExtension("GL_NV_draw_texture"));
|
||||
private static readonly Lazy<bool> _supportsFragmentShaderInterlock = new Lazy<bool>(() => HasExtension("GL_ARB_fragment_shader_interlock"));
|
||||
private static readonly Lazy<bool> _supportsFragmentShaderOrdering = new Lazy<bool>(() => HasExtension("GL_INTEL_fragment_shader_ordering"));
|
||||
private static readonly Lazy<bool> _supportsGeometryShaderPassthrough = new Lazy<bool>(() => HasExtension("GL_NV_geometry_shader_passthrough"));
|
||||
private static readonly Lazy<bool> _supportsImageLoadFormatted = new Lazy<bool>(() => HasExtension("GL_EXT_shader_image_load_formatted"));
|
||||
private static readonly Lazy<bool> _supportsIndirectParameters = new Lazy<bool>(() => HasExtension("GL_ARB_indirect_parameters"));
|
||||
private static readonly Lazy<bool> _supportsParallelShaderCompile = new Lazy<bool>(() => HasExtension("GL_ARB_parallel_shader_compile"));
|
||||
private static readonly Lazy<bool> _supportsPolygonOffsetClamp = new Lazy<bool>(() => HasExtension("GL_EXT_polygon_offset_clamp"));
|
||||
private static readonly Lazy<bool> _supportsQuads = new Lazy<bool>(SupportsQuadsCheck);
|
||||
private static readonly Lazy<bool> _supportsSeamlessCubemapPerTexture = new Lazy<bool>(() => HasExtension("GL_ARB_seamless_cubemap_per_texture"));
|
||||
private static readonly Lazy<bool> _supportsShaderBallot = new Lazy<bool>(() => HasExtension("GL_ARB_shader_ballot"));
|
||||
private static readonly Lazy<bool> _supportsShaderViewportLayerArray = new Lazy<bool>(() => HasExtension("GL_ARB_shader_viewport_layer_array"));
|
||||
private static readonly Lazy<bool> _supportsTextureCompressionBptc = new Lazy<bool>(() => HasExtension("GL_EXT_texture_compression_bptc"));
|
||||
private static readonly Lazy<bool> _supportsTextureCompressionRgtc = new Lazy<bool>(() => HasExtension("GL_EXT_texture_compression_rgtc"));
|
||||
private static readonly Lazy<bool> _supportsTextureCompressionS3tc = new Lazy<bool>(() => HasExtension("GL_EXT_texture_compression_s3tc"));
|
||||
private static readonly Lazy<bool> _supportsTextureShadowLod = new Lazy<bool>(() => HasExtension("GL_EXT_texture_shadow_lod"));
|
||||
private static readonly Lazy<bool> _supportsViewportSwizzle = new Lazy<bool>(() => HasExtension("GL_NV_viewport_swizzle"));
|
||||
|
||||
private static readonly Lazy<int> _maximumComputeSharedMemorySize = new Lazy<int>(() => GetLimit(All.MaxComputeSharedMemorySize));
|
||||
private static readonly Lazy<int> _storageBufferOffsetAlignment = new Lazy<int>(() => GetLimit(All.ShaderStorageBufferOffsetAlignment));
|
||||
|
||||
public enum GpuVendor
|
||||
{
|
||||
Unknown,
|
||||
AmdWindows,
|
||||
AmdUnix,
|
||||
IntelWindows,
|
||||
IntelUnix,
|
||||
Nvidia
|
||||
}
|
||||
|
||||
private static readonly Lazy<GpuVendor> _gpuVendor = new Lazy<GpuVendor>(GetGpuVendor);
|
||||
|
||||
private static bool _isAMD => _gpuVendor.Value == GpuVendor.AmdWindows || _gpuVendor.Value == GpuVendor.AmdUnix;
|
||||
private static bool _isIntel => _gpuVendor.Value == GpuVendor.IntelWindows || _gpuVendor.Value == GpuVendor.IntelUnix;
|
||||
|
||||
public static GpuVendor Vendor => _gpuVendor.Value;
|
||||
|
||||
private static Lazy<float> _maxSupportedAnisotropy = new Lazy<float>(GL.GetFloat((GetPName)All.MaxTextureMaxAnisotropy));
|
||||
|
||||
public static bool UsePersistentBufferForFlush => _gpuVendor.Value == GpuVendor.AmdWindows || _gpuVendor.Value == GpuVendor.Nvidia;
|
||||
|
||||
public static bool SupportsAlphaToCoverageDitherControl => _supportsAlphaToCoverageDitherControl.Value;
|
||||
public static bool SupportsAstcCompression => _supportsAstcCompression.Value;
|
||||
public static bool SupportsBlendEquationAdvanced => _supportsBlendEquationAdvanced.Value;
|
||||
public static bool SupportsDrawTexture => _supportsDrawTexture.Value;
|
||||
public static bool SupportsFragmentShaderInterlock => _supportsFragmentShaderInterlock.Value;
|
||||
public static bool SupportsFragmentShaderOrdering => _supportsFragmentShaderOrdering.Value;
|
||||
public static bool SupportsGeometryShaderPassthrough => _supportsGeometryShaderPassthrough.Value;
|
||||
public static bool SupportsImageLoadFormatted => _supportsImageLoadFormatted.Value;
|
||||
public static bool SupportsIndirectParameters => _supportsIndirectParameters.Value;
|
||||
public static bool SupportsParallelShaderCompile => _supportsParallelShaderCompile.Value;
|
||||
public static bool SupportsPolygonOffsetClamp => _supportsPolygonOffsetClamp.Value;
|
||||
public static bool SupportsQuads => _supportsQuads.Value;
|
||||
public static bool SupportsSeamlessCubemapPerTexture => _supportsSeamlessCubemapPerTexture.Value;
|
||||
public static bool SupportsShaderBallot => _supportsShaderBallot.Value;
|
||||
public static bool SupportsShaderViewportLayerArray => _supportsShaderViewportLayerArray.Value;
|
||||
public static bool SupportsTextureCompressionBptc => _supportsTextureCompressionBptc.Value;
|
||||
public static bool SupportsTextureCompressionRgtc => _supportsTextureCompressionRgtc.Value;
|
||||
public static bool SupportsTextureCompressionS3tc => _supportsTextureCompressionS3tc.Value;
|
||||
public static bool SupportsTextureShadowLod => _supportsTextureShadowLod.Value;
|
||||
public static bool SupportsViewportSwizzle => _supportsViewportSwizzle.Value;
|
||||
|
||||
public static bool SupportsMismatchingViewFormat => _gpuVendor.Value != GpuVendor.AmdWindows && _gpuVendor.Value != GpuVendor.IntelWindows;
|
||||
public static bool SupportsNonConstantTextureOffset => _gpuVendor.Value == GpuVendor.Nvidia;
|
||||
public static bool RequiresSyncFlush => _gpuVendor.Value == GpuVendor.AmdWindows || _isIntel;
|
||||
|
||||
public static int MaximumComputeSharedMemorySize => _maximumComputeSharedMemorySize.Value;
|
||||
public static int StorageBufferOffsetAlignment => _storageBufferOffsetAlignment.Value;
|
||||
|
||||
public static float MaximumSupportedAnisotropy => _maxSupportedAnisotropy.Value;
|
||||
|
||||
private static bool HasExtension(string name)
|
||||
{
|
||||
int numExtensions = GL.GetInteger(GetPName.NumExtensions);
|
||||
|
||||
for (int extension = 0; extension < numExtensions; extension++)
|
||||
{
|
||||
if (GL.GetString(StringNameIndexed.Extensions, extension) == name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int GetLimit(All name)
|
||||
{
|
||||
return GL.GetInteger((GetPName)name);
|
||||
}
|
||||
|
||||
private static GpuVendor GetGpuVendor()
|
||||
{
|
||||
string vendor = GL.GetString(StringName.Vendor).ToLower();
|
||||
|
||||
if (vendor == "nvidia corporation")
|
||||
{
|
||||
return GpuVendor.Nvidia;
|
||||
}
|
||||
else if (vendor == "intel")
|
||||
{
|
||||
string renderer = GL.GetString(StringName.Renderer).ToLower();
|
||||
|
||||
return renderer.Contains("mesa") ? GpuVendor.IntelUnix : GpuVendor.IntelWindows;
|
||||
}
|
||||
else if (vendor == "ati technologies inc." || vendor == "advanced micro devices, inc.")
|
||||
{
|
||||
return GpuVendor.AmdWindows;
|
||||
}
|
||||
else if (vendor == "amd" || vendor == "x.org")
|
||||
{
|
||||
return GpuVendor.AmdUnix;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GpuVendor.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool SupportsQuadsCheck()
|
||||
{
|
||||
GL.GetError(); // Clear any existing error.
|
||||
GL.Begin(PrimitiveType.Quads);
|
||||
GL.End();
|
||||
|
||||
return GL.GetError() == ErrorCode.NoError;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader
|
||||
{
|
||||
public enum AttributeType : byte
|
||||
{
|
||||
// Generic types.
|
||||
Float,
|
||||
Sint,
|
||||
Uint
|
||||
}
|
||||
|
||||
static class AttributeTypeExtensions
|
||||
{
|
||||
public static string ToVec4Type(this AttributeType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
AttributeType.Float => "vec4",
|
||||
AttributeType.Sint => "ivec4",
|
||||
AttributeType.Uint => "uvec4",
|
||||
_ => throw new ArgumentException($"Invalid attribute type \"{type}\".")
|
||||
};
|
||||
}
|
||||
|
||||
public static AggregateType ToAggregateType(this AttributeType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
AttributeType.Float => AggregateType.FP32,
|
||||
AttributeType.Sint => AggregateType.S32,
|
||||
AttributeType.Uint => AggregateType.U32,
|
||||
_ => throw new ArgumentException($"Invalid attribute type \"{type}\".")
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Shader
|
||||
{
|
||||
public struct BufferDescriptor
|
||||
{
|
||||
// New fields should be added to the end of the struct to keep disk shader cache compatibility.
|
||||
|
||||
public readonly int Binding;
|
||||
public readonly int Slot;
|
||||
public BufferUsageFlags Flags;
|
||||
|
||||
public BufferDescriptor(int binding, int slot)
|
||||
{
|
||||
Binding = binding;
|
||||
Slot = slot;
|
||||
|
||||
Flags = BufferUsageFlags.None;
|
||||
}
|
||||
|
||||
public BufferDescriptor SetFlag(BufferUsageFlags flag)
|
||||
{
|
||||
Flags |= flag;
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,801 +0,0 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
{
|
||||
static class Declarations
|
||||
{
|
||||
public static void Declare(CodeGenContext context, StructuredProgramInfo info)
|
||||
{
|
||||
context.AppendLine(context.Config.Options.TargetApi == TargetApi.Vulkan ? "#version 460 core" : "#version 450 core");
|
||||
context.AppendLine("#extension GL_ARB_gpu_shader_int64 : enable");
|
||||
|
||||
if (context.Config.GpuAccessor.QueryHostSupportsShaderBallot())
|
||||
{
|
||||
context.AppendLine("#extension GL_ARB_shader_ballot : enable");
|
||||
}
|
||||
else
|
||||
{
|
||||
context.AppendLine("#extension GL_KHR_shader_subgroup_basic : enable");
|
||||
context.AppendLine("#extension GL_KHR_shader_subgroup_ballot : enable");
|
||||
}
|
||||
|
||||
context.AppendLine("#extension GL_ARB_shader_group_vote : enable");
|
||||
context.AppendLine("#extension GL_EXT_shader_image_load_formatted : enable");
|
||||
context.AppendLine("#extension GL_EXT_texture_shadow_lod : enable");
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Compute)
|
||||
{
|
||||
context.AppendLine("#extension GL_ARB_compute_shader : enable");
|
||||
}
|
||||
else if (context.Config.Stage == ShaderStage.Fragment)
|
||||
{
|
||||
if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderInterlock())
|
||||
{
|
||||
context.AppendLine("#extension GL_ARB_fragment_shader_interlock : enable");
|
||||
}
|
||||
else if (context.Config.GpuAccessor.QueryHostSupportsFragmentShaderOrderingIntel())
|
||||
{
|
||||
context.AppendLine("#extension GL_INTEL_fragment_shader_ordering : enable");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (context.Config.Stage == ShaderStage.Vertex)
|
||||
{
|
||||
context.AppendLine("#extension GL_ARB_shader_draw_parameters : enable");
|
||||
}
|
||||
|
||||
context.AppendLine("#extension GL_ARB_shader_viewport_layer_array : enable");
|
||||
}
|
||||
|
||||
if (context.Config.GpPassthrough && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
context.AppendLine("#extension GL_NV_geometry_shader_passthrough : enable");
|
||||
}
|
||||
|
||||
context.AppendLine("#pragma optionNV(fastmath off)");
|
||||
context.AppendLine();
|
||||
|
||||
context.AppendLine($"const int {DefaultNames.UndefinedName} = 0;");
|
||||
context.AppendLine();
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Compute)
|
||||
{
|
||||
int localMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeLocalMemorySize(), 4);
|
||||
|
||||
if (localMemorySize != 0)
|
||||
{
|
||||
string localMemorySizeStr = NumberFormatter.FormatInt(localMemorySize);
|
||||
|
||||
context.AppendLine($"uint {DefaultNames.LocalMemoryName}[{localMemorySizeStr}];");
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
int sharedMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeSharedMemorySize(), 4);
|
||||
|
||||
if (sharedMemorySize != 0)
|
||||
{
|
||||
string sharedMemorySizeStr = NumberFormatter.FormatInt(sharedMemorySize);
|
||||
|
||||
context.AppendLine($"shared uint {DefaultNames.SharedMemoryName}[{sharedMemorySizeStr}];");
|
||||
context.AppendLine();
|
||||
}
|
||||
}
|
||||
else if (context.Config.LocalMemorySize != 0)
|
||||
{
|
||||
int localMemorySize = BitUtils.DivRoundUp(context.Config.LocalMemorySize, 4);
|
||||
|
||||
string localMemorySizeStr = NumberFormatter.FormatInt(localMemorySize);
|
||||
|
||||
context.AppendLine($"uint {DefaultNames.LocalMemoryName}[{localMemorySizeStr}];");
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
var cBufferDescriptors = context.Config.GetConstantBufferDescriptors();
|
||||
if (cBufferDescriptors.Length != 0)
|
||||
{
|
||||
DeclareUniforms(context, cBufferDescriptors);
|
||||
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
var sBufferDescriptors = context.Config.GetStorageBufferDescriptors();
|
||||
if (sBufferDescriptors.Length != 0)
|
||||
{
|
||||
DeclareStorages(context, sBufferDescriptors);
|
||||
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
var textureDescriptors = context.Config.GetTextureDescriptors();
|
||||
if (textureDescriptors.Length != 0)
|
||||
{
|
||||
DeclareSamplers(context, textureDescriptors);
|
||||
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
var imageDescriptors = context.Config.GetImageDescriptors();
|
||||
if (imageDescriptors.Length != 0)
|
||||
{
|
||||
DeclareImages(context, imageDescriptors);
|
||||
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
if (context.Config.Stage != ShaderStage.Compute)
|
||||
{
|
||||
if (context.Config.Stage == ShaderStage.Geometry)
|
||||
{
|
||||
InputTopology inputTopology = context.Config.GpuAccessor.QueryPrimitiveTopology();
|
||||
string inPrimitive = inputTopology.ToGlslString();
|
||||
|
||||
context.AppendLine($"layout (invocations = {context.Config.ThreadsPerInputPrimitive}, {inPrimitive}) in;");
|
||||
|
||||
if (context.Config.GpPassthrough && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
context.AppendLine($"layout (passthrough) in gl_PerVertex");
|
||||
context.EnterScope();
|
||||
context.AppendLine("vec4 gl_Position;");
|
||||
context.AppendLine("float gl_PointSize;");
|
||||
context.AppendLine("float gl_ClipDistance[];");
|
||||
context.LeaveScope(";");
|
||||
}
|
||||
else
|
||||
{
|
||||
string outPrimitive = context.Config.OutputTopology.ToGlslString();
|
||||
|
||||
int maxOutputVertices = context.Config.GpPassthrough
|
||||
? inputTopology.ToInputVertices()
|
||||
: context.Config.MaxOutputVertices;
|
||||
|
||||
context.AppendLine($"layout ({outPrimitive}, max_vertices = {maxOutputVertices}) out;");
|
||||
}
|
||||
|
||||
context.AppendLine();
|
||||
}
|
||||
else if (context.Config.Stage == ShaderStage.TessellationControl)
|
||||
{
|
||||
int threadsPerInputPrimitive = context.Config.ThreadsPerInputPrimitive;
|
||||
|
||||
context.AppendLine($"layout (vertices = {threadsPerInputPrimitive}) out;");
|
||||
context.AppendLine();
|
||||
}
|
||||
else if (context.Config.Stage == ShaderStage.TessellationEvaluation)
|
||||
{
|
||||
bool tessCw = context.Config.GpuAccessor.QueryTessCw();
|
||||
|
||||
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
|
||||
{
|
||||
// We invert the front face on Vulkan backend, so we need to do that here aswell.
|
||||
tessCw = !tessCw;
|
||||
}
|
||||
|
||||
string patchType = context.Config.GpuAccessor.QueryTessPatchType().ToGlsl();
|
||||
string spacing = context.Config.GpuAccessor.QueryTessSpacing().ToGlsl();
|
||||
string windingOrder = tessCw ? "cw" : "ccw";
|
||||
|
||||
context.AppendLine($"layout ({patchType}, {spacing}, {windingOrder}) in;");
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
if (context.Config.UsedInputAttributes != 0 || context.Config.GpPassthrough)
|
||||
{
|
||||
DeclareInputAttributes(context, info);
|
||||
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
if (context.Config.UsedOutputAttributes != 0 || context.Config.Stage != ShaderStage.Fragment)
|
||||
{
|
||||
DeclareOutputAttributes(context, info);
|
||||
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
if (context.Config.UsedInputAttributesPerPatch.Count != 0)
|
||||
{
|
||||
DeclareInputAttributesPerPatch(context, context.Config.UsedInputAttributesPerPatch);
|
||||
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
if (context.Config.UsedOutputAttributesPerPatch.Count != 0)
|
||||
{
|
||||
DeclareUsedOutputAttributesPerPatch(context, context.Config.UsedOutputAttributesPerPatch);
|
||||
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline)
|
||||
{
|
||||
var tfOutput = context.Info.GetTransformFeedbackOutput(AttributeConsts.PositionX);
|
||||
if (tfOutput.Valid)
|
||||
{
|
||||
context.AppendLine($"layout (xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}) out gl_PerVertex");
|
||||
context.EnterScope();
|
||||
context.AppendLine("vec4 gl_Position;");
|
||||
context.LeaveScope(context.Config.Stage == ShaderStage.TessellationControl ? " gl_out[];" : ";");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string localSizeX = NumberFormatter.FormatInt(context.Config.GpuAccessor.QueryComputeLocalSizeX());
|
||||
string localSizeY = NumberFormatter.FormatInt(context.Config.GpuAccessor.QueryComputeLocalSizeY());
|
||||
string localSizeZ = NumberFormatter.FormatInt(context.Config.GpuAccessor.QueryComputeLocalSizeZ());
|
||||
|
||||
context.AppendLine(
|
||||
"layout (" +
|
||||
$"local_size_x = {localSizeX}, " +
|
||||
$"local_size_y = {localSizeY}, " +
|
||||
$"local_size_z = {localSizeZ}) in;");
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
bool isFragment = context.Config.Stage == ShaderStage.Fragment;
|
||||
|
||||
if (isFragment || context.Config.Stage == ShaderStage.Compute || context.Config.Stage == ShaderStage.Vertex)
|
||||
{
|
||||
if (isFragment && context.Config.GpuAccessor.QueryEarlyZForce())
|
||||
{
|
||||
context.AppendLine("layout(early_fragment_tests) in;");
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
if ((context.Config.UsedFeatures & (FeatureFlags.FragCoordXY | FeatureFlags.IntegerSampling)) != 0)
|
||||
{
|
||||
string stage = OperandManager.GetShaderStagePrefix(context.Config.Stage);
|
||||
|
||||
int scaleElements = context.Config.GetTextureDescriptors().Length + context.Config.GetImageDescriptors().Length;
|
||||
|
||||
if (isFragment)
|
||||
{
|
||||
scaleElements++; // Also includes render target scale, for gl_FragCoord.
|
||||
}
|
||||
|
||||
DeclareSupportUniformBlock(context, context.Config.Stage, scaleElements);
|
||||
|
||||
if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IntegerSampling) && scaleElements != 0)
|
||||
{
|
||||
AppendHelperFunction(context, $"Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/TexelFetchScale_{stage}.glsl");
|
||||
context.AppendLine();
|
||||
}
|
||||
}
|
||||
else if (isFragment || context.Config.Stage == ShaderStage.Vertex)
|
||||
{
|
||||
DeclareSupportUniformBlock(context, context.Config.Stage, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.AtomicMinMaxS32Shared) != 0)
|
||||
{
|
||||
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Shared.glsl");
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.AtomicMinMaxS32Storage) != 0)
|
||||
{
|
||||
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/AtomicMinMaxS32Storage.glsl");
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.MultiplyHighS32) != 0)
|
||||
{
|
||||
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/MultiplyHighS32.glsl");
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.MultiplyHighU32) != 0)
|
||||
{
|
||||
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/MultiplyHighU32.glsl");
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.Shuffle) != 0)
|
||||
{
|
||||
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/Shuffle.glsl");
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.ShuffleDown) != 0)
|
||||
{
|
||||
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleDown.glsl");
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.ShuffleUp) != 0)
|
||||
{
|
||||
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleUp.glsl");
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.ShuffleXor) != 0)
|
||||
{
|
||||
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/ShuffleXor.glsl");
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.StoreSharedSmallInt) != 0)
|
||||
{
|
||||
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/StoreSharedSmallInt.glsl");
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.StoreStorageSmallInt) != 0)
|
||||
{
|
||||
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/StoreStorageSmallInt.glsl");
|
||||
}
|
||||
|
||||
if ((info.HelperFunctionsMask & HelperFunctionsMask.SwizzleAdd) != 0)
|
||||
{
|
||||
AppendHelperFunction(context, "Ryujinx.Graphics.Shader/CodeGen/Glsl/HelperFunctions/SwizzleAdd.glsl");
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetTfLayout(TransformFeedbackOutput tfOutput)
|
||||
{
|
||||
if (tfOutput.Valid)
|
||||
{
|
||||
return $"layout (xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}) ";
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public static void DeclareLocals(CodeGenContext context, StructuredFunction function)
|
||||
{
|
||||
foreach (AstOperand decl in function.Locals)
|
||||
{
|
||||
string name = context.OperandManager.DeclareLocal(decl);
|
||||
|
||||
context.AppendLine(GetVarTypeName(context, decl.VarType) + " " + name + ";");
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetVarTypeName(CodeGenContext context, AggregateType type, bool precise = true)
|
||||
{
|
||||
if (context.Config.GpuAccessor.QueryHostReducedPrecision())
|
||||
{
|
||||
precise = false;
|
||||
}
|
||||
|
||||
return type switch
|
||||
{
|
||||
AggregateType.Void => "void",
|
||||
AggregateType.Bool => "bool",
|
||||
AggregateType.FP32 => precise ? "precise float" : "float",
|
||||
AggregateType.FP64 => "double",
|
||||
AggregateType.S32 => "int",
|
||||
AggregateType.U32 => "uint",
|
||||
AggregateType.Vector2 | AggregateType.Bool => "bvec2",
|
||||
AggregateType.Vector2 | AggregateType.FP32 => precise ? "precise vec2" : "vec2",
|
||||
AggregateType.Vector2 | AggregateType.FP64 => "dvec2",
|
||||
AggregateType.Vector2 | AggregateType.S32 => "ivec2",
|
||||
AggregateType.Vector2 | AggregateType.U32 => "uvec2",
|
||||
AggregateType.Vector3 | AggregateType.Bool => "bvec3",
|
||||
AggregateType.Vector3 | AggregateType.FP32 => precise ? "precise vec3" : "vec3",
|
||||
AggregateType.Vector3 | AggregateType.FP64 => "dvec3",
|
||||
AggregateType.Vector3 | AggregateType.S32 => "ivec3",
|
||||
AggregateType.Vector3 | AggregateType.U32 => "uvec3",
|
||||
AggregateType.Vector4 | AggregateType.Bool => "bvec4",
|
||||
AggregateType.Vector4 | AggregateType.FP32 => precise ? "precise vec4" : "vec4",
|
||||
AggregateType.Vector4 | AggregateType.FP64 => "dvec4",
|
||||
AggregateType.Vector4 | AggregateType.S32 => "ivec4",
|
||||
AggregateType.Vector4 | AggregateType.U32 => "uvec4",
|
||||
_ => throw new ArgumentException($"Invalid variable type \"{type}\".")
|
||||
};
|
||||
}
|
||||
|
||||
private static void DeclareUniforms(CodeGenContext context, BufferDescriptor[] descriptors)
|
||||
{
|
||||
string ubSize = "[" + NumberFormatter.FormatInt(Constants.ConstantBufferSize / 16) + "]";
|
||||
|
||||
if (context.Config.UsedFeatures.HasFlag(FeatureFlags.CbIndexing))
|
||||
{
|
||||
string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
|
||||
|
||||
ubName += "_" + DefaultNames.UniformNamePrefix;
|
||||
|
||||
string blockName = $"{ubName}_{DefaultNames.BlockSuffix}";
|
||||
|
||||
context.AppendLine($"layout (binding = {context.Config.FirstConstantBufferBinding}, std140) uniform {blockName}");
|
||||
context.EnterScope();
|
||||
context.AppendLine("vec4 " + DefaultNames.DataName + ubSize + ";");
|
||||
context.LeaveScope($" {ubName}[{NumberFormatter.FormatInt(descriptors.Max(x => x.Slot) + 1)}];");
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var descriptor in descriptors)
|
||||
{
|
||||
string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
|
||||
|
||||
ubName += "_" + DefaultNames.UniformNamePrefix + descriptor.Slot;
|
||||
|
||||
context.AppendLine($"layout (binding = {descriptor.Binding}, std140) uniform {ubName}");
|
||||
context.EnterScope();
|
||||
context.AppendLine("vec4 " + OperandManager.GetUbName(context.Config.Stage, descriptor.Slot, false) + ubSize + ";");
|
||||
context.LeaveScope(";");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareStorages(CodeGenContext context, BufferDescriptor[] descriptors)
|
||||
{
|
||||
string sbName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
|
||||
|
||||
sbName += "_" + DefaultNames.StorageNamePrefix;
|
||||
|
||||
string blockName = $"{sbName}_{DefaultNames.BlockSuffix}";
|
||||
|
||||
string layout = context.Config.Options.TargetApi == TargetApi.Vulkan ? ", set = 1" : string.Empty;
|
||||
|
||||
context.AppendLine($"layout (binding = {context.Config.FirstStorageBufferBinding}{layout}, std430) buffer {blockName}");
|
||||
context.EnterScope();
|
||||
context.AppendLine("uint " + DefaultNames.DataName + "[];");
|
||||
context.LeaveScope($" {sbName}[{NumberFormatter.FormatInt(descriptors.Max(x => x.Slot) + 1)}];");
|
||||
}
|
||||
|
||||
private static void DeclareSamplers(CodeGenContext context, TextureDescriptor[] descriptors)
|
||||
{
|
||||
int arraySize = 0;
|
||||
foreach (var descriptor in descriptors)
|
||||
{
|
||||
if (descriptor.Type.HasFlag(SamplerType.Indexed))
|
||||
{
|
||||
if (arraySize == 0)
|
||||
{
|
||||
arraySize = ShaderConfig.SamplerArraySize;
|
||||
}
|
||||
else if (--arraySize != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
string indexExpr = NumberFormatter.FormatInt(arraySize);
|
||||
|
||||
string samplerName = OperandManager.GetSamplerName(
|
||||
context.Config.Stage,
|
||||
descriptor.CbufSlot,
|
||||
descriptor.HandleIndex,
|
||||
descriptor.Type.HasFlag(SamplerType.Indexed),
|
||||
indexExpr);
|
||||
|
||||
string samplerTypeName = descriptor.Type.ToGlslSamplerType();
|
||||
|
||||
string layout = string.Empty;
|
||||
|
||||
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
|
||||
{
|
||||
layout = ", set = 2";
|
||||
}
|
||||
|
||||
context.AppendLine($"layout (binding = {descriptor.Binding}{layout}) uniform {samplerTypeName} {samplerName};");
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareImages(CodeGenContext context, TextureDescriptor[] descriptors)
|
||||
{
|
||||
int arraySize = 0;
|
||||
foreach (var descriptor in descriptors)
|
||||
{
|
||||
if (descriptor.Type.HasFlag(SamplerType.Indexed))
|
||||
{
|
||||
if (arraySize == 0)
|
||||
{
|
||||
arraySize = ShaderConfig.SamplerArraySize;
|
||||
}
|
||||
else if (--arraySize != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
string indexExpr = NumberFormatter.FormatInt(arraySize);
|
||||
|
||||
string imageName = OperandManager.GetImageName(
|
||||
context.Config.Stage,
|
||||
descriptor.CbufSlot,
|
||||
descriptor.HandleIndex,
|
||||
descriptor.Format,
|
||||
descriptor.Type.HasFlag(SamplerType.Indexed),
|
||||
indexExpr);
|
||||
|
||||
string imageTypeName = descriptor.Type.ToGlslImageType(descriptor.Format.GetComponentType());
|
||||
|
||||
if (descriptor.Flags.HasFlag(TextureUsageFlags.ImageCoherent))
|
||||
{
|
||||
imageTypeName = "coherent " + imageTypeName;
|
||||
}
|
||||
|
||||
string layout = descriptor.Format.ToGlslFormat();
|
||||
|
||||
if (!string.IsNullOrEmpty(layout))
|
||||
{
|
||||
layout = ", " + layout;
|
||||
}
|
||||
|
||||
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
|
||||
{
|
||||
layout = $", set = 3{layout}";
|
||||
}
|
||||
|
||||
context.AppendLine($"layout (binding = {descriptor.Binding}{layout}) uniform {imageTypeName} {imageName};");
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareInputAttributes(CodeGenContext context, StructuredProgramInfo info)
|
||||
{
|
||||
if (context.Config.UsedFeatures.HasFlag(FeatureFlags.IaIndexing))
|
||||
{
|
||||
string suffix = context.Config.Stage == ShaderStage.Geometry ? "[]" : string.Empty;
|
||||
|
||||
context.AppendLine($"layout (location = 0) in vec4 {DefaultNames.IAttributePrefix}{suffix}[{Constants.MaxAttributes}];");
|
||||
}
|
||||
else
|
||||
{
|
||||
int usedAttributes = context.Config.UsedInputAttributes | context.Config.PassthroughAttributes;
|
||||
while (usedAttributes != 0)
|
||||
{
|
||||
int index = BitOperations.TrailingZeroCount(usedAttributes);
|
||||
DeclareInputAttribute(context, info, index);
|
||||
usedAttributes &= ~(1 << index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareInputAttributesPerPatch(CodeGenContext context, HashSet<int> attrs)
|
||||
{
|
||||
foreach (int attr in attrs.Order())
|
||||
{
|
||||
DeclareInputAttributePerPatch(context, attr);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareInputAttribute(CodeGenContext context, StructuredProgramInfo info, int attr)
|
||||
{
|
||||
string suffix = AttributeInfo.IsArrayAttributeGlsl(context.Config.Stage, isOutAttr: false) ? "[]" : string.Empty;
|
||||
string iq = string.Empty;
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Fragment)
|
||||
{
|
||||
iq = context.Config.ImapTypes[attr].GetFirstUsedType() switch
|
||||
{
|
||||
PixelImap.Constant => "flat ",
|
||||
PixelImap.ScreenLinear => "noperspective ",
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
string name = $"{DefaultNames.IAttributePrefix}{attr}";
|
||||
|
||||
if (context.Config.TransformFeedbackEnabled && context.Config.Stage == ShaderStage.Fragment)
|
||||
{
|
||||
int attrOffset = AttributeConsts.UserAttributeBase + attr * 16;
|
||||
int components = context.Info.GetTransformFeedbackOutputComponents(attrOffset);
|
||||
|
||||
if (components > 1)
|
||||
{
|
||||
string type = components switch
|
||||
{
|
||||
2 => "vec2",
|
||||
3 => "vec3",
|
||||
4 => "vec4",
|
||||
_ => "float"
|
||||
};
|
||||
|
||||
context.AppendLine($"layout (location = {attr}) in {type} {name};");
|
||||
}
|
||||
|
||||
for (int c = components > 1 ? components : 0; c < 4; c++)
|
||||
{
|
||||
char swzMask = "xyzw"[c];
|
||||
|
||||
context.AppendLine($"layout (location = {attr}, component = {c}) {iq}in float {name}_{swzMask}{suffix};");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool passthrough = (context.Config.PassthroughAttributes & (1 << attr)) != 0;
|
||||
string pass = passthrough && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough() ? "passthrough, " : string.Empty;
|
||||
string type;
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Vertex)
|
||||
{
|
||||
type = context.Config.GpuAccessor.QueryAttributeType(attr).ToVec4Type();
|
||||
}
|
||||
else
|
||||
{
|
||||
type = AttributeType.Float.ToVec4Type();
|
||||
}
|
||||
|
||||
context.AppendLine($"layout ({pass}location = {attr}) {iq}in {type} {name}{suffix};");
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareInputAttributePerPatch(CodeGenContext context, int attr)
|
||||
{
|
||||
int location = context.Config.GetPerPatchAttributeLocation(attr);
|
||||
string name = $"{DefaultNames.PerPatchAttributePrefix}{attr}";
|
||||
|
||||
context.AppendLine($"layout (location = {location}) patch in vec4 {name};");
|
||||
}
|
||||
|
||||
private static void DeclareOutputAttributes(CodeGenContext context, StructuredProgramInfo info)
|
||||
{
|
||||
if (context.Config.UsedFeatures.HasFlag(FeatureFlags.OaIndexing))
|
||||
{
|
||||
context.AppendLine($"layout (location = 0) out vec4 {DefaultNames.OAttributePrefix}[{Constants.MaxAttributes}];");
|
||||
}
|
||||
else
|
||||
{
|
||||
int usedAttributes = context.Config.UsedOutputAttributes;
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Fragment && context.Config.GpuAccessor.QueryDualSourceBlendEnable())
|
||||
{
|
||||
int firstOutput = BitOperations.TrailingZeroCount(usedAttributes);
|
||||
int mask = 3 << firstOutput;
|
||||
|
||||
if ((usedAttributes & mask) == mask)
|
||||
{
|
||||
usedAttributes &= ~mask;
|
||||
DeclareOutputDualSourceBlendAttribute(context, firstOutput);
|
||||
}
|
||||
}
|
||||
|
||||
while (usedAttributes != 0)
|
||||
{
|
||||
int index = BitOperations.TrailingZeroCount(usedAttributes);
|
||||
DeclareOutputAttribute(context, index);
|
||||
usedAttributes &= ~(1 << index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareOutputAttribute(CodeGenContext context, int attr)
|
||||
{
|
||||
string suffix = AttributeInfo.IsArrayAttributeGlsl(context.Config.Stage, isOutAttr: true) ? "[]" : string.Empty;
|
||||
string name = $"{DefaultNames.OAttributePrefix}{attr}{suffix}";
|
||||
|
||||
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline)
|
||||
{
|
||||
int attrOffset = AttributeConsts.UserAttributeBase + attr * 16;
|
||||
int components = context.Info.GetTransformFeedbackOutputComponents(attrOffset);
|
||||
|
||||
if (components > 1)
|
||||
{
|
||||
string type = components switch
|
||||
{
|
||||
2 => "vec2",
|
||||
3 => "vec3",
|
||||
4 => "vec4",
|
||||
_ => "float"
|
||||
};
|
||||
|
||||
string xfb = string.Empty;
|
||||
|
||||
var tfOutput = context.Info.GetTransformFeedbackOutput(attrOffset);
|
||||
if (tfOutput.Valid)
|
||||
{
|
||||
xfb = $", xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}";
|
||||
}
|
||||
|
||||
context.AppendLine($"layout (location = {attr}{xfb}) out {type} {name};");
|
||||
}
|
||||
|
||||
for (int c = components > 1 ? components : 0; c < 4; c++)
|
||||
{
|
||||
char swzMask = "xyzw"[c];
|
||||
|
||||
string xfb = string.Empty;
|
||||
|
||||
var tfOutput = context.Info.GetTransformFeedbackOutput(attrOffset + c * 4);
|
||||
if (tfOutput.Valid)
|
||||
{
|
||||
xfb = $", xfb_buffer = {tfOutput.Buffer}, xfb_offset = {tfOutput.Offset}, xfb_stride = {tfOutput.Stride}";
|
||||
}
|
||||
|
||||
context.AppendLine($"layout (location = {attr}, component = {c}{xfb}) out float {name}_{swzMask};");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string type = context.Config.Stage != ShaderStage.Fragment ? "vec4" :
|
||||
context.Config.GpuAccessor.QueryFragmentOutputType(attr) switch
|
||||
{
|
||||
AttributeType.Sint => "ivec4",
|
||||
AttributeType.Uint => "uvec4",
|
||||
_ => "vec4"
|
||||
};
|
||||
|
||||
if (context.Config.GpuAccessor.QueryHostReducedPrecision() && context.Config.Stage == ShaderStage.Vertex && attr == 0)
|
||||
{
|
||||
context.AppendLine($"layout (location = {attr}) invariant out {type} {name};");
|
||||
}
|
||||
else
|
||||
{
|
||||
context.AppendLine($"layout (location = {attr}) out {type} {name};");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareOutputDualSourceBlendAttribute(CodeGenContext context, int attr)
|
||||
{
|
||||
string name = $"{DefaultNames.OAttributePrefix}{attr}";
|
||||
string name2 = $"{DefaultNames.OAttributePrefix}{(attr + 1)}";
|
||||
|
||||
context.AppendLine($"layout (location = {attr}, index = 0) out vec4 {name};");
|
||||
context.AppendLine($"layout (location = {attr}, index = 1) out vec4 {name2};");
|
||||
}
|
||||
|
||||
private static void DeclareUsedOutputAttributesPerPatch(CodeGenContext context, HashSet<int> attrs)
|
||||
{
|
||||
foreach (int attr in attrs.Order())
|
||||
{
|
||||
DeclareOutputAttributePerPatch(context, attr);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareOutputAttributePerPatch(CodeGenContext context, int attr)
|
||||
{
|
||||
int location = context.Config.GetPerPatchAttributeLocation(attr);
|
||||
string name = $"{DefaultNames.PerPatchAttributePrefix}{attr}";
|
||||
|
||||
context.AppendLine($"layout (location = {location}) patch out vec4 {name};");
|
||||
}
|
||||
|
||||
private static void DeclareSupportUniformBlock(CodeGenContext context, ShaderStage stage, int scaleElements)
|
||||
{
|
||||
bool needsSupportBlock = stage == ShaderStage.Fragment ||
|
||||
(context.Config.LastInVertexPipeline && context.Config.GpuAccessor.QueryViewportTransformDisable());
|
||||
|
||||
if (!needsSupportBlock && scaleElements == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
context.AppendLine($"layout (binding = 0, std140) uniform {DefaultNames.SupportBlockName}");
|
||||
context.EnterScope();
|
||||
|
||||
switch (stage)
|
||||
{
|
||||
case ShaderStage.Fragment:
|
||||
case ShaderStage.Vertex:
|
||||
context.AppendLine($"uint {DefaultNames.SupportBlockAlphaTestName};");
|
||||
context.AppendLine($"bool {DefaultNames.SupportBlockIsBgraName}[{SupportBuffer.FragmentIsBgraCount}];");
|
||||
context.AppendLine($"vec4 {DefaultNames.SupportBlockViewportInverse};");
|
||||
context.AppendLine($"int {DefaultNames.SupportBlockFragmentScaleCount};");
|
||||
break;
|
||||
case ShaderStage.Compute:
|
||||
context.AppendLine($"uint s_reserved[{SupportBuffer.ComputeRenderScaleOffset / SupportBuffer.FieldSize}];");
|
||||
break;
|
||||
}
|
||||
|
||||
context.AppendLine($"float {DefaultNames.SupportBlockRenderScaleName}[{SupportBuffer.RenderScaleMaxCount}];");
|
||||
|
||||
context.LeaveScope(";");
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
private static void AppendHelperFunction(CodeGenContext context, string filename)
|
||||
{
|
||||
string code = EmbeddedResources.ReadAllText(filename);
|
||||
|
||||
code = code.Replace("\t", CodeGenContext.Tab);
|
||||
code = code.Replace("$SHARED_MEM$", DefaultNames.SharedMemoryName);
|
||||
code = code.Replace("$STORAGE_MEM$", OperandManager.GetShaderStagePrefix(context.Config.Stage) + "_" + DefaultNames.StorageNamePrefix);
|
||||
|
||||
if (context.Config.GpuAccessor.QueryHostSupportsShaderBallot())
|
||||
{
|
||||
code = code.Replace("$SUBGROUP_INVOCATION$", "gl_SubGroupInvocationARB");
|
||||
code = code.Replace("$SUBGROUP_BROADCAST$", "readInvocationARB");
|
||||
}
|
||||
else
|
||||
{
|
||||
code = code.Replace("$SUBGROUP_INVOCATION$", "gl_SubgroupInvocationID");
|
||||
code = code.Replace("$SUBGROUP_BROADCAST$", "subgroupBroadcast");
|
||||
}
|
||||
|
||||
context.AppendLine(code);
|
||||
context.AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
{
|
||||
static class DefaultNames
|
||||
{
|
||||
public const string LocalNamePrefix = "temp";
|
||||
|
||||
public const string SamplerNamePrefix = "tex";
|
||||
public const string ImageNamePrefix = "img";
|
||||
|
||||
public const string PerPatchAttributePrefix = "patch_attr_";
|
||||
public const string IAttributePrefix = "in_attr";
|
||||
public const string OAttributePrefix = "out_attr";
|
||||
|
||||
public const string StorageNamePrefix = "s";
|
||||
|
||||
public const string DataName = "data";
|
||||
|
||||
public const string SupportBlockName = "support_block";
|
||||
public const string SupportBlockAlphaTestName = "s_alpha_test";
|
||||
public const string SupportBlockIsBgraName = "s_is_bgra";
|
||||
public const string SupportBlockViewportInverse = "s_viewport_inverse";
|
||||
public const string SupportBlockFragmentScaleCount = "s_frag_scale_count";
|
||||
public const string SupportBlockRenderScaleName = "s_render_scale";
|
||||
|
||||
public const string BlockSuffix = "block";
|
||||
|
||||
public const string UniformNamePrefix = "c";
|
||||
public const string UniformNameSuffix = "data";
|
||||
|
||||
public const string LocalMemoryName = "local_mem";
|
||||
public const string SharedMemoryName = "shared_mem";
|
||||
|
||||
public const string ArgumentNamePrefix = "a";
|
||||
|
||||
public const string UndefinedName = "undef";
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
int Helper_AtomicMaxS32(int offset, int value)
|
||||
{
|
||||
uint oldValue, newValue;
|
||||
do
|
||||
{
|
||||
oldValue = $SHARED_MEM$[offset];
|
||||
newValue = uint(max(int(oldValue), value));
|
||||
} while (atomicCompSwap($SHARED_MEM$[offset], oldValue, newValue) != oldValue);
|
||||
return int(oldValue);
|
||||
}
|
||||
|
||||
int Helper_AtomicMinS32(int offset, int value)
|
||||
{
|
||||
uint oldValue, newValue;
|
||||
do
|
||||
{
|
||||
oldValue = $SHARED_MEM$[offset];
|
||||
newValue = uint(min(int(oldValue), value));
|
||||
} while (atomicCompSwap($SHARED_MEM$[offset], oldValue, newValue) != oldValue);
|
||||
return int(oldValue);
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
int Helper_AtomicMaxS32(int index, int offset, int value)
|
||||
{
|
||||
uint oldValue, newValue;
|
||||
do
|
||||
{
|
||||
oldValue = $STORAGE_MEM$[index].data[offset];
|
||||
newValue = uint(max(int(oldValue), value));
|
||||
} while (atomicCompSwap($STORAGE_MEM$[index].data[offset], oldValue, newValue) != oldValue);
|
||||
return int(oldValue);
|
||||
}
|
||||
|
||||
int Helper_AtomicMinS32(int index, int offset, int value)
|
||||
{
|
||||
uint oldValue, newValue;
|
||||
do
|
||||
{
|
||||
oldValue = $STORAGE_MEM$[index].data[offset];
|
||||
newValue = uint(min(int(oldValue), value));
|
||||
} while (atomicCompSwap($STORAGE_MEM$[index].data[offset], oldValue, newValue) != oldValue);
|
||||
return int(oldValue);
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
{
|
||||
static class HelperFunctionNames
|
||||
{
|
||||
public static string AtomicMaxS32 = "Helper_AtomicMaxS32";
|
||||
public static string AtomicMinS32 = "Helper_AtomicMinS32";
|
||||
|
||||
public static string MultiplyHighS32 = "Helper_MultiplyHighS32";
|
||||
public static string MultiplyHighU32 = "Helper_MultiplyHighU32";
|
||||
|
||||
public static string Shuffle = "Helper_Shuffle";
|
||||
public static string ShuffleDown = "Helper_ShuffleDown";
|
||||
public static string ShuffleUp = "Helper_ShuffleUp";
|
||||
public static string ShuffleXor = "Helper_ShuffleXor";
|
||||
public static string SwizzleAdd = "Helper_SwizzleAdd";
|
||||
|
||||
public static string StoreShared16 = "Helper_StoreShared16";
|
||||
public static string StoreShared8 = "Helper_StoreShared8";
|
||||
public static string StoreStorage16 = "Helper_StoreStorage16";
|
||||
public static string StoreStorage8 = "Helper_StoreStorage8";
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
float Helper_Shuffle(float x, uint index, uint mask, out bool valid)
|
||||
{
|
||||
uint clamp = mask & 0x1fu;
|
||||
uint segMask = (mask >> 8) & 0x1fu;
|
||||
uint minThreadId = $SUBGROUP_INVOCATION$ & segMask;
|
||||
uint maxThreadId = minThreadId | (clamp & ~segMask);
|
||||
uint srcThreadId = (index & ~segMask) | minThreadId;
|
||||
valid = srcThreadId <= maxThreadId;
|
||||
float v = $SUBGROUP_BROADCAST$(x, srcThreadId);
|
||||
return valid ? v : x;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
float Helper_ShuffleDown(float x, uint index, uint mask, out bool valid)
|
||||
{
|
||||
uint clamp = mask & 0x1fu;
|
||||
uint segMask = (mask >> 8) & 0x1fu;
|
||||
uint minThreadId = $SUBGROUP_INVOCATION$ & segMask;
|
||||
uint maxThreadId = minThreadId | (clamp & ~segMask);
|
||||
uint srcThreadId = $SUBGROUP_INVOCATION$ + index;
|
||||
valid = srcThreadId <= maxThreadId;
|
||||
float v = $SUBGROUP_BROADCAST$(x, srcThreadId);
|
||||
return valid ? v : x;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
float Helper_ShuffleUp(float x, uint index, uint mask, out bool valid)
|
||||
{
|
||||
uint segMask = (mask >> 8) & 0x1fu;
|
||||
uint minThreadId = $SUBGROUP_INVOCATION$ & segMask;
|
||||
uint srcThreadId = $SUBGROUP_INVOCATION$ - index;
|
||||
valid = int(srcThreadId) >= int(minThreadId);
|
||||
float v = $SUBGROUP_BROADCAST$(x, srcThreadId);
|
||||
return valid ? v : x;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
float Helper_ShuffleXor(float x, uint index, uint mask, out bool valid)
|
||||
{
|
||||
uint clamp = mask & 0x1fu;
|
||||
uint segMask = (mask >> 8) & 0x1fu;
|
||||
uint minThreadId = $SUBGROUP_INVOCATION$ & segMask;
|
||||
uint maxThreadId = minThreadId | (clamp & ~segMask);
|
||||
uint srcThreadId = $SUBGROUP_INVOCATION$ ^ index;
|
||||
valid = srcThreadId <= maxThreadId;
|
||||
float v = $SUBGROUP_BROADCAST$(x, srcThreadId);
|
||||
return valid ? v : x;
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
void Helper_StoreShared16(int offset, uint value)
|
||||
{
|
||||
int wordOffset = offset >> 2;
|
||||
int bitOffset = (offset & 3) * 8;
|
||||
uint oldValue, newValue;
|
||||
do
|
||||
{
|
||||
oldValue = $SHARED_MEM$[wordOffset];
|
||||
newValue = bitfieldInsert(oldValue, value, bitOffset, 16);
|
||||
} while (atomicCompSwap($SHARED_MEM$[wordOffset], oldValue, newValue) != oldValue);
|
||||
}
|
||||
|
||||
void Helper_StoreShared8(int offset, uint value)
|
||||
{
|
||||
int wordOffset = offset >> 2;
|
||||
int bitOffset = (offset & 3) * 8;
|
||||
uint oldValue, newValue;
|
||||
do
|
||||
{
|
||||
oldValue = $SHARED_MEM$[wordOffset];
|
||||
newValue = bitfieldInsert(oldValue, value, bitOffset, 8);
|
||||
} while (atomicCompSwap($SHARED_MEM$[wordOffset], oldValue, newValue) != oldValue);
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
void Helper_StoreStorage16(int index, int offset, uint value)
|
||||
{
|
||||
int wordOffset = offset >> 2;
|
||||
int bitOffset = (offset & 3) * 8;
|
||||
uint oldValue, newValue;
|
||||
do
|
||||
{
|
||||
oldValue = $STORAGE_MEM$[index].data[wordOffset];
|
||||
newValue = bitfieldInsert(oldValue, value, bitOffset, 16);
|
||||
} while (atomicCompSwap($STORAGE_MEM$[index].data[wordOffset], oldValue, newValue) != oldValue);
|
||||
}
|
||||
|
||||
void Helper_StoreStorage8(int index, int offset, uint value)
|
||||
{
|
||||
int wordOffset = offset >> 2;
|
||||
int bitOffset = (offset & 3) * 8;
|
||||
uint oldValue, newValue;
|
||||
do
|
||||
{
|
||||
oldValue = $STORAGE_MEM$[index].data[wordOffset];
|
||||
newValue = bitfieldInsert(oldValue, value, bitOffset, 8);
|
||||
} while (atomicCompSwap($STORAGE_MEM$[index].data[wordOffset], oldValue, newValue) != oldValue);
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex)
|
||||
{
|
||||
float scale = s_render_scale[samplerIndex];
|
||||
if (scale == 1.0)
|
||||
{
|
||||
return inputVec;
|
||||
}
|
||||
return ivec2(vec2(inputVec) * scale);
|
||||
}
|
||||
|
||||
int Helper_TextureSizeUnscale(int size, int samplerIndex)
|
||||
{
|
||||
float scale = s_render_scale[samplerIndex];
|
||||
if (scale == 1.0)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
return int(float(size) / scale);
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex)
|
||||
{
|
||||
float scale = s_render_scale[1 + samplerIndex];
|
||||
if (scale == 1.0)
|
||||
{
|
||||
return inputVec;
|
||||
}
|
||||
if (scale < 0.0) // If less than 0, try interpolate between texels by using the screen position.
|
||||
{
|
||||
return ivec2(vec2(inputVec) * (-scale) + mod(gl_FragCoord.xy, 0.0 - scale));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ivec2(vec2(inputVec) * scale);
|
||||
}
|
||||
}
|
||||
|
||||
int Helper_TextureSizeUnscale(int size, int samplerIndex)
|
||||
{
|
||||
float scale = abs(s_render_scale[1 + samplerIndex]);
|
||||
if (scale == 1.0)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
return int(float(size) / scale);
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
ivec2 Helper_TexelFetchScale(ivec2 inputVec, int samplerIndex)
|
||||
{
|
||||
float scale = abs(s_render_scale[1 + samplerIndex + s_frag_scale_count]);
|
||||
if (scale == 1.0)
|
||||
{
|
||||
return inputVec;
|
||||
}
|
||||
|
||||
return ivec2(vec2(inputVec) * scale);
|
||||
}
|
||||
|
||||
int Helper_TextureSizeUnscale(int size, int samplerIndex)
|
||||
{
|
||||
float scale = abs(s_render_scale[1 + samplerIndex + s_frag_scale_count]);
|
||||
if (scale == 1.0)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
return int(float(size) / scale);
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||
{
|
||||
[Flags]
|
||||
enum InstType
|
||||
{
|
||||
OpNullary = Op | 0,
|
||||
OpUnary = Op | 1,
|
||||
OpBinary = Op | 2,
|
||||
OpBinaryCom = Op | 2 | Commutative,
|
||||
OpTernary = Op | 3,
|
||||
|
||||
CallNullary = Call | 0,
|
||||
CallUnary = Call | 1,
|
||||
CallBinary = Call | 2,
|
||||
CallTernary = Call | 3,
|
||||
CallQuaternary = Call | 4,
|
||||
|
||||
// The atomic instructions have one extra operand,
|
||||
// for the storage slot and offset pair.
|
||||
AtomicBinary = Call | Atomic | 3,
|
||||
AtomicTernary = Call | Atomic | 4,
|
||||
|
||||
Commutative = 1 << 8,
|
||||
Op = 1 << 9,
|
||||
Call = 1 << 10,
|
||||
Atomic = 1 << 11,
|
||||
Special = 1 << 12,
|
||||
|
||||
ArityMask = 0xff
|
||||
}
|
||||
}
|
@ -1,505 +0,0 @@
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Numerics;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
{
|
||||
class OperandManager
|
||||
{
|
||||
private static readonly string[] StagePrefixes = new string[] { "cp", "vp", "tcp", "tep", "gp", "fp" };
|
||||
|
||||
private readonly struct BuiltInAttribute
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
public AggregateType Type { get; }
|
||||
|
||||
public BuiltInAttribute(string name, AggregateType type)
|
||||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<int, BuiltInAttribute> _builtInAttributes = new Dictionary<int, BuiltInAttribute>()
|
||||
{
|
||||
{ AttributeConsts.Layer, new BuiltInAttribute("gl_Layer", AggregateType.S32) },
|
||||
{ AttributeConsts.PointSize, new BuiltInAttribute("gl_PointSize", AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionX, new BuiltInAttribute("gl_Position.x", AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionY, new BuiltInAttribute("gl_Position.y", AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionZ, new BuiltInAttribute("gl_Position.z", AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionW, new BuiltInAttribute("gl_Position.w", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance0, new BuiltInAttribute("gl_ClipDistance[0]", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance1, new BuiltInAttribute("gl_ClipDistance[1]", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance2, new BuiltInAttribute("gl_ClipDistance[2]", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance3, new BuiltInAttribute("gl_ClipDistance[3]", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance4, new BuiltInAttribute("gl_ClipDistance[4]", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance5, new BuiltInAttribute("gl_ClipDistance[5]", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance6, new BuiltInAttribute("gl_ClipDistance[6]", AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance7, new BuiltInAttribute("gl_ClipDistance[7]", AggregateType.FP32) },
|
||||
{ AttributeConsts.PointCoordX, new BuiltInAttribute("gl_PointCoord.x", AggregateType.FP32) },
|
||||
{ AttributeConsts.PointCoordY, new BuiltInAttribute("gl_PointCoord.y", AggregateType.FP32) },
|
||||
{ AttributeConsts.TessCoordX, new BuiltInAttribute("gl_TessCoord.x", AggregateType.FP32) },
|
||||
{ AttributeConsts.TessCoordY, new BuiltInAttribute("gl_TessCoord.y", AggregateType.FP32) },
|
||||
{ AttributeConsts.InstanceId, new BuiltInAttribute("gl_InstanceID", AggregateType.S32) },
|
||||
{ AttributeConsts.VertexId, new BuiltInAttribute("gl_VertexID", AggregateType.S32) },
|
||||
{ AttributeConsts.BaseInstance, new BuiltInAttribute("gl_BaseInstanceARB", AggregateType.S32) },
|
||||
{ AttributeConsts.BaseVertex, new BuiltInAttribute("gl_BaseVertexARB", AggregateType.S32) },
|
||||
{ AttributeConsts.InstanceIndex, new BuiltInAttribute("gl_InstanceIndex", AggregateType.S32) },
|
||||
{ AttributeConsts.VertexIndex, new BuiltInAttribute("gl_VertexIndex", AggregateType.S32) },
|
||||
{ AttributeConsts.DrawIndex, new BuiltInAttribute("gl_DrawIDARB", AggregateType.S32) },
|
||||
{ AttributeConsts.FrontFacing, new BuiltInAttribute("gl_FrontFacing", AggregateType.Bool) },
|
||||
|
||||
// Special.
|
||||
{ AttributeConsts.FragmentOutputDepth, new BuiltInAttribute("gl_FragDepth", AggregateType.FP32) },
|
||||
{ AttributeConsts.ThreadKill, new BuiltInAttribute("gl_HelperInvocation", AggregateType.Bool) },
|
||||
{ AttributeConsts.ThreadIdX, new BuiltInAttribute("gl_LocalInvocationID.x", AggregateType.U32) },
|
||||
{ AttributeConsts.ThreadIdY, new BuiltInAttribute("gl_LocalInvocationID.y", AggregateType.U32) },
|
||||
{ AttributeConsts.ThreadIdZ, new BuiltInAttribute("gl_LocalInvocationID.z", AggregateType.U32) },
|
||||
{ AttributeConsts.CtaIdX, new BuiltInAttribute("gl_WorkGroupID.x", AggregateType.U32) },
|
||||
{ AttributeConsts.CtaIdY, new BuiltInAttribute("gl_WorkGroupID.y", AggregateType.U32) },
|
||||
{ AttributeConsts.CtaIdZ, new BuiltInAttribute("gl_WorkGroupID.z", AggregateType.U32) },
|
||||
{ AttributeConsts.LaneId, new BuiltInAttribute(null, AggregateType.U32) },
|
||||
{ AttributeConsts.InvocationId, new BuiltInAttribute("gl_InvocationID", AggregateType.S32) },
|
||||
{ AttributeConsts.PrimitiveId, new BuiltInAttribute("gl_PrimitiveID", AggregateType.S32) },
|
||||
{ AttributeConsts.PatchVerticesIn, new BuiltInAttribute("gl_PatchVerticesIn", AggregateType.S32) },
|
||||
{ AttributeConsts.EqMask, new BuiltInAttribute(null, AggregateType.U32) },
|
||||
{ AttributeConsts.GeMask, new BuiltInAttribute(null, AggregateType.U32) },
|
||||
{ AttributeConsts.GtMask, new BuiltInAttribute(null, AggregateType.U32) },
|
||||
{ AttributeConsts.LeMask, new BuiltInAttribute(null, AggregateType.U32) },
|
||||
{ AttributeConsts.LtMask, new BuiltInAttribute(null, AggregateType.U32) },
|
||||
|
||||
// Support uniforms.
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 0, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[0]", AggregateType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 4, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[1]", AggregateType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 8, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[2]", AggregateType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 12, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[3]", AggregateType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 16, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[4]", AggregateType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 20, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[5]", AggregateType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 24, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[6]", AggregateType.Bool) },
|
||||
{ AttributeConsts.FragmentOutputIsBgraBase + 28, new BuiltInAttribute($"{DefaultNames.SupportBlockIsBgraName}[7]", AggregateType.Bool) },
|
||||
|
||||
{ AttributeConsts.SupportBlockViewInverseX, new BuiltInAttribute($"{DefaultNames.SupportBlockViewportInverse}.x", AggregateType.FP32) },
|
||||
{ AttributeConsts.SupportBlockViewInverseY, new BuiltInAttribute($"{DefaultNames.SupportBlockViewportInverse}.y", AggregateType.FP32) }
|
||||
};
|
||||
|
||||
private Dictionary<AstOperand, string> _locals;
|
||||
|
||||
public OperandManager()
|
||||
{
|
||||
_locals = new Dictionary<AstOperand, string>();
|
||||
}
|
||||
|
||||
public string DeclareLocal(AstOperand operand)
|
||||
{
|
||||
string name = $"{DefaultNames.LocalNamePrefix}_{_locals.Count}";
|
||||
|
||||
_locals.Add(operand, name);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
public string GetExpression(CodeGenContext context, AstOperand operand)
|
||||
{
|
||||
return operand.Type switch
|
||||
{
|
||||
OperandType.Argument => GetArgumentName(operand.Value),
|
||||
OperandType.Attribute => GetAttributeName(context, operand.Value, perPatch: false),
|
||||
OperandType.AttributePerPatch => GetAttributeName(context, operand.Value, perPatch: true),
|
||||
OperandType.Constant => NumberFormatter.FormatInt(operand.Value),
|
||||
OperandType.ConstantBuffer => GetConstantBufferName(operand, context.Config),
|
||||
OperandType.LocalVariable => _locals[operand],
|
||||
OperandType.Undefined => DefaultNames.UndefinedName,
|
||||
_ => throw new ArgumentException($"Invalid operand type \"{operand.Type}\".")
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetConstantBufferName(AstOperand operand, ShaderConfig config)
|
||||
{
|
||||
return GetConstantBufferName(operand.CbufSlot, operand.CbufOffset, config.Stage, config.UsedFeatures.HasFlag(FeatureFlags.CbIndexing));
|
||||
}
|
||||
|
||||
public static string GetConstantBufferName(int slot, int offset, ShaderStage stage, bool cbIndexable)
|
||||
{
|
||||
return $"{GetUbName(stage, slot, cbIndexable)}[{offset >> 2}].{GetSwizzleMask(offset & 3)}";
|
||||
}
|
||||
|
||||
private static string GetVec4Indexed(string vectorName, string indexExpr, bool indexElement)
|
||||
{
|
||||
if (indexElement)
|
||||
{
|
||||
return $"{vectorName}[{indexExpr}]";
|
||||
}
|
||||
|
||||
string result = $"{vectorName}.x";
|
||||
for (int i = 1; i < 4; i++)
|
||||
{
|
||||
result = $"(({indexExpr}) == {i}) ? ({vectorName}.{GetSwizzleMask(i)}) : ({result})";
|
||||
}
|
||||
return $"({result})";
|
||||
}
|
||||
|
||||
public static string GetConstantBufferName(int slot, string offsetExpr, ShaderStage stage, bool cbIndexable, bool indexElement)
|
||||
{
|
||||
return GetVec4Indexed(GetUbName(stage, slot, cbIndexable) + $"[{offsetExpr} >> 2]", offsetExpr + " & 3", indexElement);
|
||||
}
|
||||
|
||||
public static string GetConstantBufferName(string slotExpr, string offsetExpr, ShaderStage stage, bool indexElement)
|
||||
{
|
||||
return GetVec4Indexed(GetUbName(stage, slotExpr) + $"[{offsetExpr} >> 2]", offsetExpr + " & 3", indexElement);
|
||||
}
|
||||
|
||||
public static string GetOutAttributeName(CodeGenContext context, int value, bool perPatch)
|
||||
{
|
||||
return GetAttributeName(context, value, perPatch, isOutAttr: true);
|
||||
}
|
||||
|
||||
public static string GetAttributeName(CodeGenContext context, int value, bool perPatch, bool isOutAttr = false, string indexExpr = "0")
|
||||
{
|
||||
ShaderConfig config = context.Config;
|
||||
|
||||
if ((value & AttributeConsts.LoadOutputMask) != 0)
|
||||
{
|
||||
isOutAttr = true;
|
||||
}
|
||||
|
||||
value &= AttributeConsts.Mask & ~3;
|
||||
char swzMask = GetSwizzleMask((value >> 2) & 3);
|
||||
|
||||
if (perPatch)
|
||||
{
|
||||
if (value >= AttributeConsts.UserAttributePerPatchBase && value < AttributeConsts.UserAttributePerPatchEnd)
|
||||
{
|
||||
value -= AttributeConsts.UserAttributePerPatchBase;
|
||||
|
||||
return $"{DefaultNames.PerPatchAttributePrefix}{(value >> 4)}.{swzMask}";
|
||||
}
|
||||
else if (value < AttributeConsts.UserAttributePerPatchBase)
|
||||
{
|
||||
return value switch
|
||||
{
|
||||
AttributeConsts.TessLevelOuter0 => "gl_TessLevelOuter[0]",
|
||||
AttributeConsts.TessLevelOuter1 => "gl_TessLevelOuter[1]",
|
||||
AttributeConsts.TessLevelOuter2 => "gl_TessLevelOuter[2]",
|
||||
AttributeConsts.TessLevelOuter3 => "gl_TessLevelOuter[3]",
|
||||
AttributeConsts.TessLevelInner0 => "gl_TessLevelInner[0]",
|
||||
AttributeConsts.TessLevelInner1 => "gl_TessLevelInner[1]",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd)
|
||||
{
|
||||
int attrOffset = value;
|
||||
value -= AttributeConsts.UserAttributeBase;
|
||||
|
||||
string prefix = isOutAttr
|
||||
? DefaultNames.OAttributePrefix
|
||||
: DefaultNames.IAttributePrefix;
|
||||
|
||||
bool indexable = config.UsedFeatures.HasFlag(isOutAttr ? FeatureFlags.OaIndexing : FeatureFlags.IaIndexing);
|
||||
|
||||
if (indexable)
|
||||
{
|
||||
string name = prefix;
|
||||
|
||||
if (config.Stage == ShaderStage.Geometry && !isOutAttr)
|
||||
{
|
||||
name += $"[{indexExpr}]";
|
||||
}
|
||||
|
||||
return name + $"[{(value >> 4)}]." + swzMask;
|
||||
}
|
||||
else if (config.TransformFeedbackEnabled &&
|
||||
((config.LastInVertexPipeline && isOutAttr) ||
|
||||
(config.Stage == ShaderStage.Fragment && !isOutAttr)))
|
||||
{
|
||||
int components = context.Info.GetTransformFeedbackOutputComponents(attrOffset);
|
||||
string name = components > 1 ? $"{prefix}{(value >> 4)}" : $"{prefix}{(value >> 4)}_{swzMask}";
|
||||
|
||||
if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
||||
{
|
||||
name += isOutAttr ? "[gl_InvocationID]" : $"[{indexExpr}]";
|
||||
}
|
||||
|
||||
return components > 1 ? name + '.' + swzMask : name;
|
||||
}
|
||||
else
|
||||
{
|
||||
string name = $"{prefix}{(value >> 4)}";
|
||||
|
||||
if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
||||
{
|
||||
name += isOutAttr ? "[gl_InvocationID]" : $"[{indexExpr}]";
|
||||
}
|
||||
|
||||
return name + '.' + swzMask;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value >= AttributeConsts.FragmentOutputColorBase && value < AttributeConsts.FragmentOutputColorEnd)
|
||||
{
|
||||
value -= AttributeConsts.FragmentOutputColorBase;
|
||||
|
||||
return $"{DefaultNames.OAttributePrefix}{(value >> 4)}.{swzMask}";
|
||||
}
|
||||
else if (_builtInAttributes.TryGetValue(value, out BuiltInAttribute builtInAttr))
|
||||
{
|
||||
string subgroupMask = value switch
|
||||
{
|
||||
AttributeConsts.EqMask => "Eq",
|
||||
AttributeConsts.GeMask => "Ge",
|
||||
AttributeConsts.GtMask => "Gt",
|
||||
AttributeConsts.LeMask => "Le",
|
||||
AttributeConsts.LtMask => "Lt",
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (subgroupMask != null)
|
||||
{
|
||||
return config.GpuAccessor.QueryHostSupportsShaderBallot()
|
||||
? $"unpackUint2x32(gl_SubGroup{subgroupMask}MaskARB).x"
|
||||
: $"gl_Subgroup{subgroupMask}Mask.x";
|
||||
}
|
||||
else if (value == AttributeConsts.LaneId)
|
||||
{
|
||||
return config.GpuAccessor.QueryHostSupportsShaderBallot()
|
||||
? "gl_SubGroupInvocationARB"
|
||||
: "gl_SubgroupInvocationID";
|
||||
}
|
||||
|
||||
if (config.Stage == ShaderStage.Fragment)
|
||||
{
|
||||
// TODO: There must be a better way to handle this...
|
||||
switch (value)
|
||||
{
|
||||
case AttributeConsts.PositionX: return $"(gl_FragCoord.x / {DefaultNames.SupportBlockRenderScaleName}[0])";
|
||||
case AttributeConsts.PositionY: return $"(gl_FragCoord.y / {DefaultNames.SupportBlockRenderScaleName}[0])";
|
||||
case AttributeConsts.PositionZ: return "gl_FragCoord.z";
|
||||
case AttributeConsts.PositionW: return "gl_FragCoord.w";
|
||||
|
||||
case AttributeConsts.FrontFacing:
|
||||
if (config.GpuAccessor.QueryHostHasFrontFacingBug())
|
||||
{
|
||||
// This is required for Intel on Windows, gl_FrontFacing sometimes returns incorrect
|
||||
// (flipped) values. Doing this seems to fix it.
|
||||
return "(-floatBitsToInt(float(gl_FrontFacing)) < 0)";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string name = builtInAttr.Name;
|
||||
|
||||
if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr) && AttributeInfo.IsArrayBuiltIn(value))
|
||||
{
|
||||
name = isOutAttr ? $"gl_out[gl_InvocationID].{name}" : $"gl_in[{indexExpr}].{name}";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Warn about unknown built-in attribute.
|
||||
|
||||
return isOutAttr ? "// bad_attr0x" + value.ToString("X") : "0.0";
|
||||
}
|
||||
|
||||
public static string GetAttributeName(string attrExpr, ShaderConfig config, bool isOutAttr = false, string indexExpr = "0")
|
||||
{
|
||||
string name = isOutAttr
|
||||
? DefaultNames.OAttributePrefix
|
||||
: DefaultNames.IAttributePrefix;
|
||||
|
||||
if (config.Stage == ShaderStage.Geometry && !isOutAttr)
|
||||
{
|
||||
name += $"[{indexExpr}]";
|
||||
}
|
||||
|
||||
return $"{name}[{attrExpr} >> 2][{attrExpr} & 3]";
|
||||
}
|
||||
|
||||
public static string GetUbName(ShaderStage stage, int slot, bool cbIndexable)
|
||||
{
|
||||
if (cbIndexable)
|
||||
{
|
||||
return GetUbName(stage, NumberFormatter.FormatInt(slot, AggregateType.S32));
|
||||
}
|
||||
|
||||
return $"{GetShaderStagePrefix(stage)}_{DefaultNames.UniformNamePrefix}{slot}_{DefaultNames.UniformNameSuffix}";
|
||||
}
|
||||
|
||||
private static string GetUbName(ShaderStage stage, string slotExpr)
|
||||
{
|
||||
return $"{GetShaderStagePrefix(stage)}_{DefaultNames.UniformNamePrefix}[{slotExpr}].{DefaultNames.DataName}";
|
||||
}
|
||||
|
||||
public static string GetSamplerName(ShaderStage stage, AstTextureOperation texOp, string indexExpr)
|
||||
{
|
||||
return GetSamplerName(stage, texOp.CbufSlot, texOp.Handle, texOp.Type.HasFlag(SamplerType.Indexed), indexExpr);
|
||||
}
|
||||
|
||||
public static string GetSamplerName(ShaderStage stage, int cbufSlot, int handle, bool indexed, string indexExpr)
|
||||
{
|
||||
string suffix = cbufSlot < 0 ? $"_tcb_{handle:X}" : $"_cb{cbufSlot}_{handle:X}";
|
||||
|
||||
if (indexed)
|
||||
{
|
||||
suffix += $"a[{indexExpr}]";
|
||||
}
|
||||
|
||||
return GetShaderStagePrefix(stage) + "_" + DefaultNames.SamplerNamePrefix + suffix;
|
||||
}
|
||||
|
||||
public static string GetImageName(ShaderStage stage, AstTextureOperation texOp, string indexExpr)
|
||||
{
|
||||
return GetImageName(stage, texOp.CbufSlot, texOp.Handle, texOp.Format, texOp.Type.HasFlag(SamplerType.Indexed), indexExpr);
|
||||
}
|
||||
|
||||
public static string GetImageName(
|
||||
ShaderStage stage,
|
||||
int cbufSlot,
|
||||
int handle,
|
||||
TextureFormat format,
|
||||
bool indexed,
|
||||
string indexExpr)
|
||||
{
|
||||
string suffix = cbufSlot < 0
|
||||
? $"_tcb_{handle:X}_{format.ToGlslFormat()}"
|
||||
: $"_cb{cbufSlot}_{handle:X}_{format.ToGlslFormat()}";
|
||||
|
||||
if (indexed)
|
||||
{
|
||||
suffix += $"a[{indexExpr}]";
|
||||
}
|
||||
|
||||
return GetShaderStagePrefix(stage) + "_" + DefaultNames.ImageNamePrefix + suffix;
|
||||
}
|
||||
|
||||
public static string GetShaderStagePrefix(ShaderStage stage)
|
||||
{
|
||||
int index = (int)stage;
|
||||
|
||||
if ((uint)index >= StagePrefixes.Length)
|
||||
{
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
return StagePrefixes[index];
|
||||
}
|
||||
|
||||
private static char GetSwizzleMask(int value)
|
||||
{
|
||||
return "xyzw"[value];
|
||||
}
|
||||
|
||||
public static string GetArgumentName(int argIndex)
|
||||
{
|
||||
return $"{DefaultNames.ArgumentNamePrefix}{argIndex}";
|
||||
}
|
||||
|
||||
public static AggregateType GetNodeDestType(CodeGenContext context, IAstNode node, bool isAsgDest = false)
|
||||
{
|
||||
if (node is AstOperation operation)
|
||||
{
|
||||
if (operation.Inst == Instruction.LoadAttribute)
|
||||
{
|
||||
// Load attribute basically just returns the attribute value.
|
||||
// Some built-in attributes may have different types, so we need
|
||||
// to return the type based on the attribute that is being read.
|
||||
if (operation.GetSource(0) is AstOperand operand && operand.Type == OperandType.Constant)
|
||||
{
|
||||
if (_builtInAttributes.TryGetValue(operand.Value & ~3, out BuiltInAttribute builtInAttr))
|
||||
{
|
||||
return builtInAttr.Type;
|
||||
}
|
||||
}
|
||||
|
||||
return OperandInfo.GetVarType(OperandType.Attribute);
|
||||
}
|
||||
else if (operation.Inst == Instruction.Call)
|
||||
{
|
||||
AstOperand funcId = (AstOperand)operation.GetSource(0);
|
||||
|
||||
Debug.Assert(funcId.Type == OperandType.Constant);
|
||||
|
||||
return context.GetFunction(funcId.Value).ReturnType;
|
||||
}
|
||||
else if (operation.Inst == Instruction.VectorExtract)
|
||||
{
|
||||
return GetNodeDestType(context, operation.GetSource(0)) & ~AggregateType.ElementCountMask;
|
||||
}
|
||||
else if (operation is AstTextureOperation texOp)
|
||||
{
|
||||
if (texOp.Inst == Instruction.ImageLoad ||
|
||||
texOp.Inst == Instruction.ImageStore ||
|
||||
texOp.Inst == Instruction.ImageAtomic)
|
||||
{
|
||||
return texOp.GetVectorType(texOp.Format.GetComponentType());
|
||||
}
|
||||
else if (texOp.Inst == Instruction.TextureSample)
|
||||
{
|
||||
return texOp.GetVectorType(GetDestVarType(operation.Inst));
|
||||
}
|
||||
}
|
||||
|
||||
return GetDestVarType(operation.Inst);
|
||||
}
|
||||
else if (node is AstOperand operand)
|
||||
{
|
||||
if (operand.Type == OperandType.Argument)
|
||||
{
|
||||
int argIndex = operand.Value;
|
||||
|
||||
return context.CurrentFunction.GetArgumentType(argIndex);
|
||||
}
|
||||
|
||||
return GetOperandVarType(context, operand, isAsgDest);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Invalid node type \"{node?.GetType().Name ?? "null"}\".");
|
||||
}
|
||||
}
|
||||
|
||||
private static AggregateType GetOperandVarType(CodeGenContext context, AstOperand operand, bool isAsgDest = false)
|
||||
{
|
||||
if (operand.Type == OperandType.Attribute)
|
||||
{
|
||||
if (_builtInAttributes.TryGetValue(operand.Value & ~3, out BuiltInAttribute builtInAttr))
|
||||
{
|
||||
return builtInAttr.Type;
|
||||
}
|
||||
else if (context.Config.Stage == ShaderStage.Vertex && !isAsgDest &&
|
||||
operand.Value >= AttributeConsts.UserAttributeBase &&
|
||||
operand.Value < AttributeConsts.UserAttributeEnd)
|
||||
{
|
||||
int location = (operand.Value - AttributeConsts.UserAttributeBase) / 16;
|
||||
|
||||
AttributeType type = context.Config.GpuAccessor.QueryAttributeType(location);
|
||||
|
||||
return type.ToAggregateType();
|
||||
}
|
||||
else if (context.Config.Stage == ShaderStage.Fragment && isAsgDest &&
|
||||
operand.Value >= AttributeConsts.FragmentOutputColorBase &&
|
||||
operand.Value < AttributeConsts.FragmentOutputColorEnd)
|
||||
{
|
||||
int location = (operand.Value - AttributeConsts.FragmentOutputColorBase) / 16;
|
||||
|
||||
AttributeType type = context.Config.GpuAccessor.QueryFragmentOutputType(location);
|
||||
|
||||
return type.ToAggregateType();
|
||||
}
|
||||
}
|
||||
|
||||
return OperandInfo.GetVarType(operand);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,656 +0,0 @@
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using Spv.Generator;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static Spv.Specification;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
using IrConsts = IntermediateRepresentation.IrConsts;
|
||||
using IrOperandType = IntermediateRepresentation.OperandType;
|
||||
|
||||
partial class CodeGenContext : Module
|
||||
{
|
||||
private const uint SpirvVersionMajor = 1;
|
||||
private const uint SpirvVersionMinor = 3;
|
||||
private const uint SpirvVersionRevision = 0;
|
||||
private const uint SpirvVersionPacked = (SpirvVersionMajor << 16) | (SpirvVersionMinor << 8) | SpirvVersionRevision;
|
||||
|
||||
public StructuredProgramInfo Info { get; }
|
||||
|
||||
public ShaderConfig Config { get; }
|
||||
|
||||
public int InputVertices { get; }
|
||||
|
||||
public Dictionary<int, Instruction> UniformBuffers { get; } = new Dictionary<int, Instruction>();
|
||||
public Instruction SupportBuffer { get; set; }
|
||||
public Instruction UniformBuffersArray { get; set; }
|
||||
public Instruction StorageBuffersArray { get; set; }
|
||||
public Instruction LocalMemory { get; set; }
|
||||
public Instruction SharedMemory { get; set; }
|
||||
public Instruction InputsArray { get; set; }
|
||||
public Instruction OutputsArray { get; set; }
|
||||
public Dictionary<TextureMeta, SamplerType> SamplersTypes { get; } = new Dictionary<TextureMeta, SamplerType>();
|
||||
public Dictionary<TextureMeta, (Instruction, Instruction, Instruction)> Samplers { get; } = new Dictionary<TextureMeta, (Instruction, Instruction, Instruction)>();
|
||||
public Dictionary<TextureMeta, (Instruction, Instruction)> Images { get; } = new Dictionary<TextureMeta, (Instruction, Instruction)>();
|
||||
public Dictionary<int, Instruction> Inputs { get; } = new Dictionary<int, Instruction>();
|
||||
public Dictionary<int, Instruction> Outputs { get; } = new Dictionary<int, Instruction>();
|
||||
public Dictionary<int, Instruction> InputsPerPatch { get; } = new Dictionary<int, Instruction>();
|
||||
public Dictionary<int, Instruction> OutputsPerPatch { get; } = new Dictionary<int, Instruction>();
|
||||
|
||||
public Instruction CoordTemp { get; set; }
|
||||
private readonly Dictionary<AstOperand, Instruction> _locals = new Dictionary<AstOperand, Instruction>();
|
||||
private readonly Dictionary<int, Instruction[]> _localForArgs = new Dictionary<int, Instruction[]>();
|
||||
private readonly Dictionary<int, Instruction> _funcArgs = new Dictionary<int, Instruction>();
|
||||
private readonly Dictionary<int, (StructuredFunction, Instruction)> _functions = new Dictionary<int, (StructuredFunction, Instruction)>();
|
||||
|
||||
private class BlockState
|
||||
{
|
||||
private int _entryCount;
|
||||
private readonly List<Instruction> _labels = new List<Instruction>();
|
||||
|
||||
public Instruction GetNextLabel(CodeGenContext context)
|
||||
{
|
||||
return GetLabel(context, _entryCount);
|
||||
}
|
||||
|
||||
public Instruction GetNextLabelAutoIncrement(CodeGenContext context)
|
||||
{
|
||||
return GetLabel(context, _entryCount++);
|
||||
}
|
||||
|
||||
public Instruction GetLabel(CodeGenContext context, int index)
|
||||
{
|
||||
while (index >= _labels.Count)
|
||||
{
|
||||
_labels.Add(context.Label());
|
||||
}
|
||||
|
||||
return _labels[index];
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<AstBlock, BlockState> _labels = new Dictionary<AstBlock, BlockState>();
|
||||
|
||||
public Dictionary<AstBlock, (Instruction, Instruction)> LoopTargets { get; set; }
|
||||
|
||||
public AstBlock CurrentBlock { get; private set; }
|
||||
|
||||
public SpirvDelegates Delegates { get; }
|
||||
|
||||
public CodeGenContext(
|
||||
StructuredProgramInfo info,
|
||||
ShaderConfig config,
|
||||
GeneratorPool<Instruction> instPool,
|
||||
GeneratorPool<LiteralInteger> integerPool) : base(SpirvVersionPacked, instPool, integerPool)
|
||||
{
|
||||
Info = info;
|
||||
Config = config;
|
||||
|
||||
if (config.Stage == ShaderStage.Geometry)
|
||||
{
|
||||
InputTopology inPrimitive = config.GpuAccessor.QueryPrimitiveTopology();
|
||||
|
||||
InputVertices = inPrimitive switch
|
||||
{
|
||||
InputTopology.Points => 1,
|
||||
InputTopology.Lines => 2,
|
||||
InputTopology.LinesAdjacency => 2,
|
||||
InputTopology.Triangles => 3,
|
||||
InputTopology.TrianglesAdjacency => 3,
|
||||
_ => throw new InvalidOperationException($"Invalid input topology \"{inPrimitive}\".")
|
||||
};
|
||||
}
|
||||
|
||||
AddCapability(Capability.Shader);
|
||||
AddCapability(Capability.Float64);
|
||||
|
||||
SetMemoryModel(AddressingModel.Logical, MemoryModel.GLSL450);
|
||||
|
||||
Delegates = new SpirvDelegates(this);
|
||||
}
|
||||
|
||||
public void StartFunction()
|
||||
{
|
||||
_locals.Clear();
|
||||
_localForArgs.Clear();
|
||||
_funcArgs.Clear();
|
||||
}
|
||||
|
||||
public void EnterBlock(AstBlock block)
|
||||
{
|
||||
CurrentBlock = block;
|
||||
AddLabel(GetBlockStateLazy(block).GetNextLabelAutoIncrement(this));
|
||||
}
|
||||
|
||||
public Instruction GetFirstLabel(AstBlock block)
|
||||
{
|
||||
return GetBlockStateLazy(block).GetLabel(this, 0);
|
||||
}
|
||||
|
||||
public Instruction GetNextLabel(AstBlock block)
|
||||
{
|
||||
return GetBlockStateLazy(block).GetNextLabel(this);
|
||||
}
|
||||
|
||||
private BlockState GetBlockStateLazy(AstBlock block)
|
||||
{
|
||||
if (!_labels.TryGetValue(block, out var blockState))
|
||||
{
|
||||
blockState = new BlockState();
|
||||
|
||||
_labels.Add(block, blockState);
|
||||
}
|
||||
|
||||
return blockState;
|
||||
}
|
||||
|
||||
public Instruction NewBlock()
|
||||
{
|
||||
var label = Label();
|
||||
Branch(label);
|
||||
AddLabel(label);
|
||||
return label;
|
||||
}
|
||||
|
||||
public Instruction[] GetMainInterface()
|
||||
{
|
||||
var mainInterface = new List<Instruction>();
|
||||
|
||||
mainInterface.AddRange(Inputs.Values);
|
||||
mainInterface.AddRange(Outputs.Values);
|
||||
mainInterface.AddRange(InputsPerPatch.Values);
|
||||
mainInterface.AddRange(OutputsPerPatch.Values);
|
||||
|
||||
if (InputsArray != null)
|
||||
{
|
||||
mainInterface.Add(InputsArray);
|
||||
}
|
||||
|
||||
if (OutputsArray != null)
|
||||
{
|
||||
mainInterface.Add(OutputsArray);
|
||||
}
|
||||
|
||||
return mainInterface.ToArray();
|
||||
}
|
||||
|
||||
public void DeclareLocal(AstOperand local, Instruction spvLocal)
|
||||
{
|
||||
_locals.Add(local, spvLocal);
|
||||
}
|
||||
|
||||
public void DeclareLocalForArgs(int funcIndex, Instruction[] spvLocals)
|
||||
{
|
||||
_localForArgs.Add(funcIndex, spvLocals);
|
||||
}
|
||||
|
||||
public void DeclareArgument(int argIndex, Instruction spvLocal)
|
||||
{
|
||||
_funcArgs.Add(argIndex, spvLocal);
|
||||
}
|
||||
|
||||
public void DeclareFunction(int funcIndex, StructuredFunction function, Instruction spvFunc)
|
||||
{
|
||||
_functions.Add(funcIndex, (function, spvFunc));
|
||||
}
|
||||
|
||||
public Instruction GetFP32(IAstNode node)
|
||||
{
|
||||
return Get(AggregateType.FP32, node);
|
||||
}
|
||||
|
||||
public Instruction GetFP64(IAstNode node)
|
||||
{
|
||||
return Get(AggregateType.FP64, node);
|
||||
}
|
||||
|
||||
public Instruction GetS32(IAstNode node)
|
||||
{
|
||||
return Get(AggregateType.S32, node);
|
||||
}
|
||||
|
||||
public Instruction GetU32(IAstNode node)
|
||||
{
|
||||
return Get(AggregateType.U32, node);
|
||||
}
|
||||
|
||||
public Instruction Get(AggregateType type, IAstNode node)
|
||||
{
|
||||
if (node is AstOperation operation)
|
||||
{
|
||||
var opResult = Instructions.Generate(this, operation);
|
||||
return BitcastIfNeeded(type, opResult.Type, opResult.Value);
|
||||
}
|
||||
else if (node is AstOperand operand)
|
||||
{
|
||||
return operand.Type switch
|
||||
{
|
||||
IrOperandType.Argument => GetArgument(type, operand),
|
||||
IrOperandType.Attribute => GetAttribute(type, operand.Value & AttributeConsts.Mask, (operand.Value & AttributeConsts.LoadOutputMask) != 0),
|
||||
IrOperandType.AttributePerPatch => GetAttributePerPatch(type, operand.Value & AttributeConsts.Mask, (operand.Value & AttributeConsts.LoadOutputMask) != 0),
|
||||
IrOperandType.Constant => GetConstant(type, operand),
|
||||
IrOperandType.ConstantBuffer => GetConstantBuffer(type, operand),
|
||||
IrOperandType.LocalVariable => GetLocal(type, operand),
|
||||
IrOperandType.Undefined => GetUndefined(type),
|
||||
_ => throw new ArgumentException($"Invalid operand type \"{operand.Type}\".")
|
||||
};
|
||||
}
|
||||
|
||||
throw new NotImplementedException(node.GetType().Name);
|
||||
}
|
||||
|
||||
public Instruction GetWithType(IAstNode node, out AggregateType type)
|
||||
{
|
||||
if (node is AstOperation operation)
|
||||
{
|
||||
var opResult = Instructions.Generate(this, operation);
|
||||
type = opResult.Type;
|
||||
return opResult.Value;
|
||||
}
|
||||
else if (node is AstOperand operand)
|
||||
{
|
||||
switch (operand.Type)
|
||||
{
|
||||
case IrOperandType.LocalVariable:
|
||||
type = operand.VarType;
|
||||
return GetLocal(type, operand);
|
||||
default:
|
||||
throw new ArgumentException($"Invalid operand type \"{operand.Type}\".");
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotImplementedException(node.GetType().Name);
|
||||
}
|
||||
|
||||
private Instruction GetUndefined(AggregateType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
AggregateType.Bool => ConstantFalse(TypeBool()),
|
||||
AggregateType.FP32 => Constant(TypeFP32(), 0f),
|
||||
AggregateType.FP64 => Constant(TypeFP64(), 0d),
|
||||
_ => Constant(GetType(type), 0)
|
||||
};
|
||||
}
|
||||
|
||||
public Instruction GetAttributeElemPointer(int attr, bool isOutAttr, Instruction index, out AggregateType elemType)
|
||||
{
|
||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||
var attrInfo = AttributeInfo.From(Config, attr, isOutAttr);
|
||||
|
||||
int attrOffset = attrInfo.BaseValue;
|
||||
AggregateType type = attrInfo.Type;
|
||||
|
||||
Instruction ioVariable, elemIndex;
|
||||
|
||||
Instruction invocationId = null;
|
||||
|
||||
if (Config.Stage == ShaderStage.TessellationControl && isOutAttr)
|
||||
{
|
||||
invocationId = Load(TypeS32(), Inputs[AttributeConsts.InvocationId]);
|
||||
}
|
||||
|
||||
bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
|
||||
|
||||
if (isUserAttr &&
|
||||
((!isOutAttr && Config.UsedFeatures.HasFlag(FeatureFlags.IaIndexing)) ||
|
||||
(isOutAttr && Config.UsedFeatures.HasFlag(FeatureFlags.OaIndexing))))
|
||||
{
|
||||
elemType = AggregateType.FP32;
|
||||
ioVariable = isOutAttr ? OutputsArray : InputsArray;
|
||||
elemIndex = Constant(TypeU32(), attrInfo.GetInnermostIndex());
|
||||
var vecIndex = Constant(TypeU32(), (attr - AttributeConsts.UserAttributeBase) >> 4);
|
||||
|
||||
bool isArray = AttributeInfo.IsArrayAttributeSpirv(Config.Stage, isOutAttr);
|
||||
|
||||
if (invocationId != null && isArray)
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId, index, vecIndex, elemIndex);
|
||||
}
|
||||
else if (invocationId != null)
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId, vecIndex, elemIndex);
|
||||
}
|
||||
else if (isArray)
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index, vecIndex, elemIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, vecIndex, elemIndex);
|
||||
}
|
||||
}
|
||||
|
||||
bool isViewportInverse = attr == AttributeConsts.SupportBlockViewInverseX || attr == AttributeConsts.SupportBlockViewInverseY;
|
||||
|
||||
if (isViewportInverse)
|
||||
{
|
||||
elemType = AggregateType.FP32;
|
||||
elemIndex = Constant(TypeU32(), (attr - AttributeConsts.SupportBlockViewInverseX) >> 2);
|
||||
return AccessChain(TypePointer(StorageClass.Uniform, TypeFP32()), SupportBuffer, Constant(TypeU32(), 2), elemIndex);
|
||||
}
|
||||
|
||||
elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||
|
||||
if (isUserAttr && Config.TransformFeedbackEnabled &&
|
||||
((isOutAttr && Config.LastInVertexPipeline) ||
|
||||
(!isOutAttr && Config.Stage == ShaderStage.Fragment)))
|
||||
{
|
||||
attrOffset = attr;
|
||||
type = elemType;
|
||||
|
||||
if (isOutAttr)
|
||||
{
|
||||
int components = Info.GetTransformFeedbackOutputComponents(attr);
|
||||
|
||||
if (components > 1)
|
||||
{
|
||||
attrOffset &= ~0xf;
|
||||
type = components switch
|
||||
{
|
||||
2 => AggregateType.Vector2 | AggregateType.FP32,
|
||||
3 => AggregateType.Vector3 | AggregateType.FP32,
|
||||
4 => AggregateType.Vector4 | AggregateType.FP32,
|
||||
_ => AggregateType.FP32
|
||||
};
|
||||
|
||||
attrInfo = new AttributeInfo(attrOffset, (attr - attrOffset) / 4, components, type, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ioVariable = isOutAttr ? Outputs[attrOffset] : Inputs[attrOffset];
|
||||
|
||||
bool isIndexed = AttributeInfo.IsArrayAttributeSpirv(Config.Stage, isOutAttr) && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr));
|
||||
|
||||
if ((type & (AggregateType.Array | AggregateType.ElementCountMask)) == 0)
|
||||
{
|
||||
if (invocationId != null)
|
||||
{
|
||||
return isIndexed
|
||||
? AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId, index)
|
||||
: AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId);
|
||||
}
|
||||
else
|
||||
{
|
||||
return isIndexed ? AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index) : ioVariable;
|
||||
}
|
||||
}
|
||||
|
||||
elemIndex = Constant(TypeU32(), attrInfo.GetInnermostIndex());
|
||||
|
||||
if (invocationId != null && isIndexed)
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId, index, elemIndex);
|
||||
}
|
||||
else if (invocationId != null)
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId, elemIndex);
|
||||
}
|
||||
else if (isIndexed)
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index, elemIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, elemIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public Instruction GetAttributeElemPointer(Instruction attrIndex, bool isOutAttr, Instruction index, out AggregateType elemType)
|
||||
{
|
||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||
|
||||
Instruction invocationId = null;
|
||||
|
||||
if (Config.Stage == ShaderStage.TessellationControl && isOutAttr)
|
||||
{
|
||||
invocationId = Load(TypeS32(), Inputs[AttributeConsts.InvocationId]);
|
||||
}
|
||||
|
||||
elemType = AggregateType.FP32;
|
||||
var ioVariable = isOutAttr ? OutputsArray : InputsArray;
|
||||
var vecIndex = ShiftRightLogical(TypeS32(), attrIndex, Constant(TypeS32(), 2));
|
||||
var elemIndex = BitwiseAnd(TypeS32(), attrIndex, Constant(TypeS32(), 3));
|
||||
|
||||
bool isArray = AttributeInfo.IsArrayAttributeSpirv(Config.Stage, isOutAttr);
|
||||
|
||||
if (invocationId != null && isArray)
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId, index, vecIndex, elemIndex);
|
||||
}
|
||||
else if (invocationId != null)
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, invocationId, vecIndex, elemIndex);
|
||||
}
|
||||
else if (isArray)
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, index, vecIndex, elemIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, vecIndex, elemIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public Instruction GetAttribute(AggregateType type, int attr, bool isOutAttr, Instruction index = null)
|
||||
{
|
||||
if (!AttributeInfo.Validate(Config, attr, isOutAttr: false))
|
||||
{
|
||||
return GetConstant(type, new AstOperand(IrOperandType.Constant, 0));
|
||||
}
|
||||
|
||||
var elemPointer = GetAttributeElemPointer(attr, isOutAttr, index, out var elemType);
|
||||
var value = Load(GetType(elemType), elemPointer);
|
||||
|
||||
if (Config.Stage == ShaderStage.Fragment)
|
||||
{
|
||||
if (attr == AttributeConsts.PositionX || attr == AttributeConsts.PositionY)
|
||||
{
|
||||
var pointerType = TypePointer(StorageClass.Uniform, TypeFP32());
|
||||
var fieldIndex = Constant(TypeU32(), 4);
|
||||
var scaleIndex = Constant(TypeU32(), 0);
|
||||
|
||||
var scaleElemPointer = AccessChain(pointerType, SupportBuffer, fieldIndex, scaleIndex);
|
||||
var scale = Load(TypeFP32(), scaleElemPointer);
|
||||
|
||||
value = FDiv(TypeFP32(), value, scale);
|
||||
}
|
||||
else if (attr == AttributeConsts.FrontFacing && Config.GpuAccessor.QueryHostHasFrontFacingBug())
|
||||
{
|
||||
// Workaround for what appears to be a bug on Intel compiler.
|
||||
var valueFloat = Select(TypeFP32(), value, Constant(TypeFP32(), 1f), Constant(TypeFP32(), 0f));
|
||||
var valueAsInt = Bitcast(TypeS32(), valueFloat);
|
||||
var valueNegated = SNegate(TypeS32(), valueAsInt);
|
||||
|
||||
value = SLessThan(TypeBool(), valueNegated, Constant(TypeS32(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
return BitcastIfNeeded(type, elemType, value);
|
||||
}
|
||||
|
||||
public Instruction GetAttributePerPatchElemPointer(int attr, bool isOutAttr, out AggregateType elemType)
|
||||
{
|
||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||
var attrInfo = AttributeInfo.FromPatch(Config, attr, isOutAttr);
|
||||
|
||||
int attrOffset = attrInfo.BaseValue;
|
||||
Instruction ioVariable = isOutAttr ? OutputsPerPatch[attrOffset] : InputsPerPatch[attrOffset];
|
||||
|
||||
elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||
|
||||
if ((attrInfo.Type & (AggregateType.Array | AggregateType.ElementCountMask)) == 0)
|
||||
{
|
||||
return ioVariable;
|
||||
}
|
||||
|
||||
var elemIndex = Constant(TypeU32(), attrInfo.GetInnermostIndex());
|
||||
return AccessChain(TypePointer(storageClass, GetType(elemType)), ioVariable, elemIndex);
|
||||
}
|
||||
|
||||
public Instruction GetAttributePerPatch(AggregateType type, int attr, bool isOutAttr)
|
||||
{
|
||||
if (!AttributeInfo.ValidatePerPatch(Config, attr, isOutAttr: false))
|
||||
{
|
||||
return GetConstant(type, new AstOperand(IrOperandType.Constant, 0));
|
||||
}
|
||||
|
||||
var elemPointer = GetAttributePerPatchElemPointer(attr, isOutAttr, out var elemType);
|
||||
return BitcastIfNeeded(type, elemType, Load(GetType(elemType), elemPointer));
|
||||
}
|
||||
|
||||
public Instruction GetAttribute(AggregateType type, Instruction attr, bool isOutAttr, Instruction index = null)
|
||||
{
|
||||
var elemPointer = GetAttributeElemPointer(attr, isOutAttr, index, out var elemType);
|
||||
return BitcastIfNeeded(type, elemType, Load(GetType(elemType), elemPointer));
|
||||
}
|
||||
|
||||
public Instruction GetConstant(AggregateType type, AstOperand operand)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
AggregateType.Bool => operand.Value != 0 ? ConstantTrue(TypeBool()) : ConstantFalse(TypeBool()),
|
||||
AggregateType.FP32 => Constant(TypeFP32(), BitConverter.Int32BitsToSingle(operand.Value)),
|
||||
AggregateType.FP64 => Constant(TypeFP64(), (double)BitConverter.Int32BitsToSingle(operand.Value)),
|
||||
AggregateType.S32 => Constant(TypeS32(), operand.Value),
|
||||
AggregateType.U32 => Constant(TypeU32(), (uint)operand.Value),
|
||||
_ => throw new ArgumentException($"Invalid type \"{type}\".")
|
||||
};
|
||||
}
|
||||
|
||||
public Instruction GetConstantBuffer(AggregateType type, AstOperand operand)
|
||||
{
|
||||
var i1 = Constant(TypeS32(), 0);
|
||||
var i2 = Constant(TypeS32(), operand.CbufOffset >> 2);
|
||||
var i3 = Constant(TypeU32(), operand.CbufOffset & 3);
|
||||
|
||||
Instruction elemPointer;
|
||||
|
||||
if (UniformBuffersArray != null)
|
||||
{
|
||||
var ubVariable = UniformBuffersArray;
|
||||
var i0 = Constant(TypeS32(), operand.CbufSlot);
|
||||
|
||||
elemPointer = AccessChain(TypePointer(StorageClass.Uniform, TypeFP32()), ubVariable, i0, i1, i2, i3);
|
||||
}
|
||||
else
|
||||
{
|
||||
var ubVariable = UniformBuffers[operand.CbufSlot];
|
||||
|
||||
elemPointer = AccessChain(TypePointer(StorageClass.Uniform, TypeFP32()), ubVariable, i1, i2, i3);
|
||||
}
|
||||
|
||||
return BitcastIfNeeded(type, AggregateType.FP32, Load(TypeFP32(), elemPointer));
|
||||
}
|
||||
|
||||
public Instruction GetLocalPointer(AstOperand local)
|
||||
{
|
||||
return _locals[local];
|
||||
}
|
||||
|
||||
public Instruction[] GetLocalForArgsPointers(int funcIndex)
|
||||
{
|
||||
return _localForArgs[funcIndex];
|
||||
}
|
||||
|
||||
public Instruction GetArgumentPointer(AstOperand funcArg)
|
||||
{
|
||||
return _funcArgs[funcArg.Value];
|
||||
}
|
||||
|
||||
public Instruction GetLocal(AggregateType dstType, AstOperand local)
|
||||
{
|
||||
var srcType = local.VarType;
|
||||
return BitcastIfNeeded(dstType, srcType, Load(GetType(srcType), GetLocalPointer(local)));
|
||||
}
|
||||
|
||||
public Instruction GetArgument(AggregateType dstType, AstOperand funcArg)
|
||||
{
|
||||
var srcType = funcArg.VarType;
|
||||
return BitcastIfNeeded(dstType, srcType, Load(GetType(srcType), GetArgumentPointer(funcArg)));
|
||||
}
|
||||
|
||||
public (StructuredFunction, Instruction) GetFunction(int funcIndex)
|
||||
{
|
||||
return _functions[funcIndex];
|
||||
}
|
||||
|
||||
public Instruction GetType(AggregateType type, int length = 1)
|
||||
{
|
||||
if ((type & AggregateType.Array) != 0)
|
||||
{
|
||||
return TypeArray(GetType(type & ~AggregateType.Array), Constant(TypeU32(), length));
|
||||
}
|
||||
else if ((type & AggregateType.ElementCountMask) != 0)
|
||||
{
|
||||
int vectorLength = (type & AggregateType.ElementCountMask) switch
|
||||
{
|
||||
AggregateType.Vector2 => 2,
|
||||
AggregateType.Vector3 => 3,
|
||||
AggregateType.Vector4 => 4,
|
||||
_ => 1
|
||||
};
|
||||
|
||||
return TypeVector(GetType(type & ~AggregateType.ElementCountMask), vectorLength);
|
||||
}
|
||||
|
||||
return type switch
|
||||
{
|
||||
AggregateType.Void => TypeVoid(),
|
||||
AggregateType.Bool => TypeBool(),
|
||||
AggregateType.FP32 => TypeFP32(),
|
||||
AggregateType.FP64 => TypeFP64(),
|
||||
AggregateType.S32 => TypeS32(),
|
||||
AggregateType.U32 => TypeU32(),
|
||||
_ => throw new ArgumentException($"Invalid attribute type \"{type}\".")
|
||||
};
|
||||
}
|
||||
|
||||
public Instruction BitcastIfNeeded(AggregateType dstType, AggregateType srcType, Instruction value)
|
||||
{
|
||||
if (dstType == srcType)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
if (dstType == AggregateType.Bool)
|
||||
{
|
||||
return INotEqual(TypeBool(), BitcastIfNeeded(AggregateType.S32, srcType, value), Constant(TypeS32(), 0));
|
||||
}
|
||||
else if (srcType == AggregateType.Bool)
|
||||
{
|
||||
var intTrue = Constant(TypeS32(), IrConsts.True);
|
||||
var intFalse = Constant(TypeS32(), IrConsts.False);
|
||||
|
||||
return BitcastIfNeeded(dstType, AggregateType.S32, Select(TypeS32(), value, intTrue, intFalse));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Bitcast(GetType(dstType, 1), value);
|
||||
}
|
||||
}
|
||||
|
||||
public Instruction TypeS32()
|
||||
{
|
||||
return TypeInt(32, true);
|
||||
}
|
||||
|
||||
public Instruction TypeU32()
|
||||
{
|
||||
return TypeInt(32, false);
|
||||
}
|
||||
|
||||
public Instruction TypeFP32()
|
||||
{
|
||||
return TypeFloat(32);
|
||||
}
|
||||
|
||||
public Instruction TypeFP64()
|
||||
{
|
||||
return TypeFloat(64);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,805 +0,0 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using Spv.Generator;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using static Spv.Specification;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
static class Declarations
|
||||
{
|
||||
// At least 16 attributes are guaranteed by the spec.
|
||||
public const int MaxAttributes = 16;
|
||||
|
||||
private static readonly string[] StagePrefixes = new string[] { "cp", "vp", "tcp", "tep", "gp", "fp" };
|
||||
|
||||
public static void DeclareParameters(CodeGenContext context, StructuredFunction function)
|
||||
{
|
||||
DeclareParameters(context, function.InArguments, 0);
|
||||
DeclareParameters(context, function.OutArguments, function.InArguments.Length);
|
||||
}
|
||||
|
||||
private static void DeclareParameters(CodeGenContext context, IEnumerable<AggregateType> argTypes, int argIndex)
|
||||
{
|
||||
foreach (var argType in argTypes)
|
||||
{
|
||||
var argPointerType = context.TypePointer(StorageClass.Function, context.GetType(argType));
|
||||
var spvArg = context.FunctionParameter(argPointerType);
|
||||
|
||||
context.DeclareArgument(argIndex++, spvArg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DeclareLocals(CodeGenContext context, StructuredFunction function)
|
||||
{
|
||||
foreach (AstOperand local in function.Locals)
|
||||
{
|
||||
var localPointerType = context.TypePointer(StorageClass.Function, context.GetType(local.VarType));
|
||||
var spvLocal = context.Variable(localPointerType, StorageClass.Function);
|
||||
|
||||
context.AddLocalVariable(spvLocal);
|
||||
context.DeclareLocal(local, spvLocal);
|
||||
}
|
||||
|
||||
var ivector2Type = context.TypeVector(context.TypeS32(), 2);
|
||||
var coordTempPointerType = context.TypePointer(StorageClass.Function, ivector2Type);
|
||||
var coordTemp = context.Variable(coordTempPointerType, StorageClass.Function);
|
||||
|
||||
context.AddLocalVariable(coordTemp);
|
||||
context.CoordTemp = coordTemp;
|
||||
}
|
||||
|
||||
public static void DeclareLocalForArgs(CodeGenContext context, List<StructuredFunction> functions)
|
||||
{
|
||||
for (int funcIndex = 0; funcIndex < functions.Count; funcIndex++)
|
||||
{
|
||||
StructuredFunction function = functions[funcIndex];
|
||||
Instruction[] locals = new Instruction[function.InArguments.Length];
|
||||
|
||||
for (int i = 0; i < function.InArguments.Length; i++)
|
||||
{
|
||||
var type = function.GetArgumentType(i);
|
||||
var localPointerType = context.TypePointer(StorageClass.Function, context.GetType(type));
|
||||
var spvLocal = context.Variable(localPointerType, StorageClass.Function);
|
||||
|
||||
context.AddLocalVariable(spvLocal);
|
||||
|
||||
locals[i] = spvLocal;
|
||||
}
|
||||
|
||||
context.DeclareLocalForArgs(funcIndex, locals);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DeclareAll(CodeGenContext context, StructuredProgramInfo info)
|
||||
{
|
||||
if (context.Config.Stage == ShaderStage.Compute)
|
||||
{
|
||||
int localMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeLocalMemorySize(), 4);
|
||||
|
||||
if (localMemorySize != 0)
|
||||
{
|
||||
DeclareLocalMemory(context, localMemorySize);
|
||||
}
|
||||
|
||||
int sharedMemorySize = BitUtils.DivRoundUp(context.Config.GpuAccessor.QueryComputeSharedMemorySize(), 4);
|
||||
|
||||
if (sharedMemorySize != 0)
|
||||
{
|
||||
DeclareSharedMemory(context, sharedMemorySize);
|
||||
}
|
||||
}
|
||||
else if (context.Config.LocalMemorySize != 0)
|
||||
{
|
||||
int localMemorySize = BitUtils.DivRoundUp(context.Config.LocalMemorySize, 4);
|
||||
DeclareLocalMemory(context, localMemorySize);
|
||||
}
|
||||
|
||||
DeclareSupportBuffer(context);
|
||||
DeclareUniformBuffers(context, context.Config.GetConstantBufferDescriptors());
|
||||
DeclareStorageBuffers(context, context.Config.GetStorageBufferDescriptors());
|
||||
DeclareSamplers(context, context.Config.GetTextureDescriptors());
|
||||
DeclareImages(context, context.Config.GetImageDescriptors());
|
||||
DeclareInputAttributes(context, info, perPatch: false);
|
||||
DeclareOutputAttributes(context, info, perPatch: false);
|
||||
DeclareInputAttributes(context, info, perPatch: true);
|
||||
DeclareOutputAttributes(context, info, perPatch: true);
|
||||
}
|
||||
|
||||
private static void DeclareLocalMemory(CodeGenContext context, int size)
|
||||
{
|
||||
context.LocalMemory = DeclareMemory(context, StorageClass.Private, size);
|
||||
}
|
||||
|
||||
private static void DeclareSharedMemory(CodeGenContext context, int size)
|
||||
{
|
||||
context.SharedMemory = DeclareMemory(context, StorageClass.Workgroup, size);
|
||||
}
|
||||
|
||||
private static Instruction DeclareMemory(CodeGenContext context, StorageClass storage, int size)
|
||||
{
|
||||
var arrayType = context.TypeArray(context.TypeU32(), context.Constant(context.TypeU32(), size));
|
||||
var pointerType = context.TypePointer(storage, arrayType);
|
||||
var variable = context.Variable(pointerType, storage);
|
||||
|
||||
context.AddGlobalVariable(variable);
|
||||
|
||||
return variable;
|
||||
}
|
||||
|
||||
private static void DeclareSupportBuffer(CodeGenContext context)
|
||||
{
|
||||
if (!context.Config.Stage.SupportsRenderScale() && !(context.Config.LastInVertexPipeline && context.Config.GpuAccessor.QueryViewportTransformDisable()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var isBgraArrayType = context.TypeArray(context.TypeU32(), context.Constant(context.TypeU32(), SupportBuffer.FragmentIsBgraCount));
|
||||
var viewportInverseVectorType = context.TypeVector(context.TypeFP32(), 4);
|
||||
var renderScaleArrayType = context.TypeArray(context.TypeFP32(), context.Constant(context.TypeU32(), SupportBuffer.RenderScaleMaxCount));
|
||||
|
||||
context.Decorate(isBgraArrayType, Decoration.ArrayStride, (LiteralInteger)SupportBuffer.FieldSize);
|
||||
context.Decorate(renderScaleArrayType, Decoration.ArrayStride, (LiteralInteger)SupportBuffer.FieldSize);
|
||||
|
||||
var supportBufferStructType = context.TypeStruct(false, context.TypeU32(), isBgraArrayType, viewportInverseVectorType, context.TypeS32(), renderScaleArrayType);
|
||||
|
||||
context.MemberDecorate(supportBufferStructType, 0, Decoration.Offset, (LiteralInteger)SupportBuffer.FragmentAlphaTestOffset);
|
||||
context.MemberDecorate(supportBufferStructType, 1, Decoration.Offset, (LiteralInteger)SupportBuffer.FragmentIsBgraOffset);
|
||||
context.MemberDecorate(supportBufferStructType, 2, Decoration.Offset, (LiteralInteger)SupportBuffer.ViewportInverseOffset);
|
||||
context.MemberDecorate(supportBufferStructType, 3, Decoration.Offset, (LiteralInteger)SupportBuffer.FragmentRenderScaleCountOffset);
|
||||
context.MemberDecorate(supportBufferStructType, 4, Decoration.Offset, (LiteralInteger)SupportBuffer.GraphicsRenderScaleOffset);
|
||||
context.Decorate(supportBufferStructType, Decoration.Block);
|
||||
|
||||
var supportBufferPointerType = context.TypePointer(StorageClass.Uniform, supportBufferStructType);
|
||||
var supportBufferVariable = context.Variable(supportBufferPointerType, StorageClass.Uniform);
|
||||
|
||||
context.Decorate(supportBufferVariable, Decoration.DescriptorSet, (LiteralInteger)0);
|
||||
context.Decorate(supportBufferVariable, Decoration.Binding, (LiteralInteger)0);
|
||||
|
||||
context.AddGlobalVariable(supportBufferVariable);
|
||||
|
||||
context.SupportBuffer = supportBufferVariable;
|
||||
}
|
||||
|
||||
private static void DeclareUniformBuffers(CodeGenContext context, BufferDescriptor[] descriptors)
|
||||
{
|
||||
if (descriptors.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint ubSize = Constants.ConstantBufferSize / 16;
|
||||
|
||||
var ubArrayType = context.TypeArray(context.TypeVector(context.TypeFP32(), 4), context.Constant(context.TypeU32(), ubSize), true);
|
||||
context.Decorate(ubArrayType, Decoration.ArrayStride, (LiteralInteger)16);
|
||||
var ubStructType = context.TypeStruct(true, ubArrayType);
|
||||
context.Decorate(ubStructType, Decoration.Block);
|
||||
context.MemberDecorate(ubStructType, 0, Decoration.Offset, (LiteralInteger)0);
|
||||
|
||||
if (context.Config.UsedFeatures.HasFlag(FeatureFlags.CbIndexing))
|
||||
{
|
||||
int count = descriptors.Max(x => x.Slot) + 1;
|
||||
|
||||
var ubStructArrayType = context.TypeArray(ubStructType, context.Constant(context.TypeU32(), count));
|
||||
var ubPointerType = context.TypePointer(StorageClass.Uniform, ubStructArrayType);
|
||||
var ubVariable = context.Variable(ubPointerType, StorageClass.Uniform);
|
||||
|
||||
context.Name(ubVariable, $"{GetStagePrefix(context.Config.Stage)}_u");
|
||||
context.Decorate(ubVariable, Decoration.DescriptorSet, (LiteralInteger)0);
|
||||
context.Decorate(ubVariable, Decoration.Binding, (LiteralInteger)context.Config.FirstConstantBufferBinding);
|
||||
context.AddGlobalVariable(ubVariable);
|
||||
|
||||
context.UniformBuffersArray = ubVariable;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ubPointerType = context.TypePointer(StorageClass.Uniform, ubStructType);
|
||||
|
||||
foreach (var descriptor in descriptors)
|
||||
{
|
||||
var ubVariable = context.Variable(ubPointerType, StorageClass.Uniform);
|
||||
|
||||
context.Name(ubVariable, $"{GetStagePrefix(context.Config.Stage)}_c{descriptor.Slot}");
|
||||
context.Decorate(ubVariable, Decoration.DescriptorSet, (LiteralInteger)0);
|
||||
context.Decorate(ubVariable, Decoration.Binding, (LiteralInteger)descriptor.Binding);
|
||||
context.AddGlobalVariable(ubVariable);
|
||||
context.UniformBuffers.Add(descriptor.Slot, ubVariable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareStorageBuffers(CodeGenContext context, BufferDescriptor[] descriptors)
|
||||
{
|
||||
if (descriptors.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int setIndex = context.Config.Options.TargetApi == TargetApi.Vulkan ? 1 : 0;
|
||||
int count = descriptors.Max(x => x.Slot) + 1;
|
||||
|
||||
var sbArrayType = context.TypeRuntimeArray(context.TypeU32());
|
||||
context.Decorate(sbArrayType, Decoration.ArrayStride, (LiteralInteger)4);
|
||||
var sbStructType = context.TypeStruct(true, sbArrayType);
|
||||
context.Decorate(sbStructType, Decoration.BufferBlock);
|
||||
context.MemberDecorate(sbStructType, 0, Decoration.Offset, (LiteralInteger)0);
|
||||
var sbStructArrayType = context.TypeArray(sbStructType, context.Constant(context.TypeU32(), count));
|
||||
var sbPointerType = context.TypePointer(StorageClass.Uniform, sbStructArrayType);
|
||||
var sbVariable = context.Variable(sbPointerType, StorageClass.Uniform);
|
||||
|
||||
context.Name(sbVariable, $"{GetStagePrefix(context.Config.Stage)}_s");
|
||||
context.Decorate(sbVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
|
||||
context.Decorate(sbVariable, Decoration.Binding, (LiteralInteger)context.Config.FirstStorageBufferBinding);
|
||||
context.AddGlobalVariable(sbVariable);
|
||||
|
||||
context.StorageBuffersArray = sbVariable;
|
||||
}
|
||||
|
||||
private static void DeclareSamplers(CodeGenContext context, TextureDescriptor[] descriptors)
|
||||
{
|
||||
foreach (var descriptor in descriptors)
|
||||
{
|
||||
var meta = new TextureMeta(descriptor.CbufSlot, descriptor.HandleIndex, descriptor.Format);
|
||||
|
||||
if (context.Samplers.ContainsKey(meta))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int setIndex = context.Config.Options.TargetApi == TargetApi.Vulkan ? 2 : 0;
|
||||
|
||||
var dim = (descriptor.Type & SamplerType.Mask) switch
|
||||
{
|
||||
SamplerType.Texture1D => Dim.Dim1D,
|
||||
SamplerType.Texture2D => Dim.Dim2D,
|
||||
SamplerType.Texture3D => Dim.Dim3D,
|
||||
SamplerType.TextureCube => Dim.Cube,
|
||||
SamplerType.TextureBuffer => Dim.Buffer,
|
||||
_ => throw new InvalidOperationException($"Invalid sampler type \"{descriptor.Type & SamplerType.Mask}\".")
|
||||
};
|
||||
|
||||
var imageType = context.TypeImage(
|
||||
context.TypeFP32(),
|
||||
dim,
|
||||
descriptor.Type.HasFlag(SamplerType.Shadow),
|
||||
descriptor.Type.HasFlag(SamplerType.Array),
|
||||
descriptor.Type.HasFlag(SamplerType.Multisample),
|
||||
1,
|
||||
ImageFormat.Unknown);
|
||||
|
||||
var nameSuffix = meta.CbufSlot < 0 ? $"_tcb_{meta.Handle:X}" : $"_cb{meta.CbufSlot}_{meta.Handle:X}";
|
||||
|
||||
var sampledImageType = context.TypeSampledImage(imageType);
|
||||
var sampledImagePointerType = context.TypePointer(StorageClass.UniformConstant, sampledImageType);
|
||||
var sampledImageVariable = context.Variable(sampledImagePointerType, StorageClass.UniformConstant);
|
||||
|
||||
context.Samplers.Add(meta, (imageType, sampledImageType, sampledImageVariable));
|
||||
context.SamplersTypes.Add(meta, descriptor.Type);
|
||||
|
||||
context.Name(sampledImageVariable, $"{GetStagePrefix(context.Config.Stage)}_tex{nameSuffix}");
|
||||
context.Decorate(sampledImageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
|
||||
context.Decorate(sampledImageVariable, Decoration.Binding, (LiteralInteger)descriptor.Binding);
|
||||
context.AddGlobalVariable(sampledImageVariable);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareImages(CodeGenContext context, TextureDescriptor[] descriptors)
|
||||
{
|
||||
foreach (var descriptor in descriptors)
|
||||
{
|
||||
var meta = new TextureMeta(descriptor.CbufSlot, descriptor.HandleIndex, descriptor.Format);
|
||||
|
||||
if (context.Images.ContainsKey(meta))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int setIndex = context.Config.Options.TargetApi == TargetApi.Vulkan ? 3 : 0;
|
||||
|
||||
var dim = GetDim(descriptor.Type);
|
||||
|
||||
var imageType = context.TypeImage(
|
||||
context.GetType(meta.Format.GetComponentType()),
|
||||
dim,
|
||||
descriptor.Type.HasFlag(SamplerType.Shadow),
|
||||
descriptor.Type.HasFlag(SamplerType.Array),
|
||||
descriptor.Type.HasFlag(SamplerType.Multisample),
|
||||
AccessQualifier.ReadWrite,
|
||||
GetImageFormat(meta.Format));
|
||||
|
||||
var nameSuffix = meta.CbufSlot < 0 ?
|
||||
$"_tcb_{meta.Handle:X}_{meta.Format.ToGlslFormat()}" :
|
||||
$"_cb{meta.CbufSlot}_{meta.Handle:X}_{meta.Format.ToGlslFormat()}";
|
||||
|
||||
var imagePointerType = context.TypePointer(StorageClass.UniformConstant, imageType);
|
||||
var imageVariable = context.Variable(imagePointerType, StorageClass.UniformConstant);
|
||||
|
||||
context.Images.Add(meta, (imageType, imageVariable));
|
||||
|
||||
context.Name(imageVariable, $"{GetStagePrefix(context.Config.Stage)}_img{nameSuffix}");
|
||||
context.Decorate(imageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
|
||||
context.Decorate(imageVariable, Decoration.Binding, (LiteralInteger)descriptor.Binding);
|
||||
|
||||
if (descriptor.Flags.HasFlag(TextureUsageFlags.ImageCoherent))
|
||||
{
|
||||
context.Decorate(imageVariable, Decoration.Coherent);
|
||||
}
|
||||
|
||||
context.AddGlobalVariable(imageVariable);
|
||||
}
|
||||
}
|
||||
|
||||
private static Dim GetDim(SamplerType type)
|
||||
{
|
||||
return (type & SamplerType.Mask) switch
|
||||
{
|
||||
SamplerType.Texture1D => Dim.Dim1D,
|
||||
SamplerType.Texture2D => Dim.Dim2D,
|
||||
SamplerType.Texture3D => Dim.Dim3D,
|
||||
SamplerType.TextureCube => Dim.Cube,
|
||||
SamplerType.TextureBuffer => Dim.Buffer,
|
||||
_ => throw new ArgumentException($"Invalid sampler type \"{type & SamplerType.Mask}\".")
|
||||
};
|
||||
}
|
||||
|
||||
private static ImageFormat GetImageFormat(TextureFormat format)
|
||||
{
|
||||
return format switch
|
||||
{
|
||||
TextureFormat.Unknown => ImageFormat.Unknown,
|
||||
TextureFormat.R8Unorm => ImageFormat.R8,
|
||||
TextureFormat.R8Snorm => ImageFormat.R8Snorm,
|
||||
TextureFormat.R8Uint => ImageFormat.R8ui,
|
||||
TextureFormat.R8Sint => ImageFormat.R8i,
|
||||
TextureFormat.R16Float => ImageFormat.R16f,
|
||||
TextureFormat.R16Unorm => ImageFormat.R16,
|
||||
TextureFormat.R16Snorm => ImageFormat.R16Snorm,
|
||||
TextureFormat.R16Uint => ImageFormat.R16ui,
|
||||
TextureFormat.R16Sint => ImageFormat.R16i,
|
||||
TextureFormat.R32Float => ImageFormat.R32f,
|
||||
TextureFormat.R32Uint => ImageFormat.R32ui,
|
||||
TextureFormat.R32Sint => ImageFormat.R32i,
|
||||
TextureFormat.R8G8Unorm => ImageFormat.Rg8,
|
||||
TextureFormat.R8G8Snorm => ImageFormat.Rg8Snorm,
|
||||
TextureFormat.R8G8Uint => ImageFormat.Rg8ui,
|
||||
TextureFormat.R8G8Sint => ImageFormat.Rg8i,
|
||||
TextureFormat.R16G16Float => ImageFormat.Rg16f,
|
||||
TextureFormat.R16G16Unorm => ImageFormat.Rg16,
|
||||
TextureFormat.R16G16Snorm => ImageFormat.Rg16Snorm,
|
||||
TextureFormat.R16G16Uint => ImageFormat.Rg16ui,
|
||||
TextureFormat.R16G16Sint => ImageFormat.Rg16i,
|
||||
TextureFormat.R32G32Float => ImageFormat.Rg32f,
|
||||
TextureFormat.R32G32Uint => ImageFormat.Rg32ui,
|
||||
TextureFormat.R32G32Sint => ImageFormat.Rg32i,
|
||||
TextureFormat.R8G8B8A8Unorm => ImageFormat.Rgba8,
|
||||
TextureFormat.R8G8B8A8Snorm => ImageFormat.Rgba8Snorm,
|
||||
TextureFormat.R8G8B8A8Uint => ImageFormat.Rgba8ui,
|
||||
TextureFormat.R8G8B8A8Sint => ImageFormat.Rgba8i,
|
||||
TextureFormat.R16G16B16A16Float => ImageFormat.Rgba16f,
|
||||
TextureFormat.R16G16B16A16Unorm => ImageFormat.Rgba16,
|
||||
TextureFormat.R16G16B16A16Snorm => ImageFormat.Rgba16Snorm,
|
||||
TextureFormat.R16G16B16A16Uint => ImageFormat.Rgba16ui,
|
||||
TextureFormat.R16G16B16A16Sint => ImageFormat.Rgba16i,
|
||||
TextureFormat.R32G32B32A32Float => ImageFormat.Rgba32f,
|
||||
TextureFormat.R32G32B32A32Uint => ImageFormat.Rgba32ui,
|
||||
TextureFormat.R32G32B32A32Sint => ImageFormat.Rgba32i,
|
||||
TextureFormat.R10G10B10A2Unorm => ImageFormat.Rgb10A2,
|
||||
TextureFormat.R10G10B10A2Uint => ImageFormat.Rgb10a2ui,
|
||||
TextureFormat.R11G11B10Float => ImageFormat.R11fG11fB10f,
|
||||
_ => throw new ArgumentException($"Invalid texture format \"{format}\".")
|
||||
};
|
||||
}
|
||||
|
||||
private static void DeclareInputAttributes(CodeGenContext context, StructuredProgramInfo info, bool perPatch)
|
||||
{
|
||||
bool iaIndexing = context.Config.UsedFeatures.HasFlag(FeatureFlags.IaIndexing);
|
||||
|
||||
if (iaIndexing && !perPatch)
|
||||
{
|
||||
var attrType = context.TypeVector(context.TypeFP32(), (LiteralInteger)4);
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)MaxAttributes));
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Geometry)
|
||||
{
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)context.InputVertices));
|
||||
}
|
||||
|
||||
var spvType = context.TypePointer(StorageClass.Input, attrType);
|
||||
var spvVar = context.Variable(spvType, StorageClass.Input);
|
||||
|
||||
if (context.Config.PassthroughAttributes != 0 && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.PassthroughNV);
|
||||
}
|
||||
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)0);
|
||||
|
||||
context.AddGlobalVariable(spvVar);
|
||||
context.InputsArray = spvVar;
|
||||
}
|
||||
|
||||
var inputs = perPatch ? info.InputsPerPatch : info.Inputs;
|
||||
|
||||
foreach (int attr in inputs)
|
||||
{
|
||||
if (!AttributeInfo.Validate(context.Config, attr, isOutAttr: false, perPatch))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
|
||||
|
||||
if (iaIndexing && isUserAttr && !perPatch)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
PixelImap iq = PixelImap.Unused;
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Fragment)
|
||||
{
|
||||
if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd)
|
||||
{
|
||||
iq = context.Config.ImapTypes[(attr - AttributeConsts.UserAttributeBase) / 16].GetFirstUsedType();
|
||||
}
|
||||
else
|
||||
{
|
||||
AttributeInfo attrInfo = AttributeInfo.From(context.Config, attr, isOutAttr: false);
|
||||
AggregateType elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||
|
||||
if (attrInfo.IsBuiltin && (elemType == AggregateType.S32 || elemType == AggregateType.U32))
|
||||
{
|
||||
iq = PixelImap.Constant;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeclareInputOrOutput(context, attr, perPatch, isOutAttr: false, iq);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareOutputAttributes(CodeGenContext context, StructuredProgramInfo info, bool perPatch)
|
||||
{
|
||||
bool oaIndexing = context.Config.UsedFeatures.HasFlag(FeatureFlags.OaIndexing);
|
||||
|
||||
if (oaIndexing && !perPatch)
|
||||
{
|
||||
var attrType = context.TypeVector(context.TypeFP32(), (LiteralInteger)4);
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)MaxAttributes));
|
||||
|
||||
if (context.Config.Stage == ShaderStage.TessellationControl)
|
||||
{
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), context.Config.ThreadsPerInputPrimitive));
|
||||
}
|
||||
|
||||
var spvType = context.TypePointer(StorageClass.Output, attrType);
|
||||
var spvVar = context.Variable(spvType, StorageClass.Output);
|
||||
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)0);
|
||||
|
||||
context.AddGlobalVariable(spvVar);
|
||||
context.OutputsArray = spvVar;
|
||||
}
|
||||
|
||||
var outputs = perPatch ? info.OutputsPerPatch : info.Outputs;
|
||||
|
||||
foreach (int attr in outputs)
|
||||
{
|
||||
if (!AttributeInfo.Validate(context.Config, attr, isOutAttr: true, perPatch))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
|
||||
|
||||
if (oaIndexing && isUserAttr && !perPatch)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
DeclareOutputAttribute(context, attr, perPatch);
|
||||
}
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Vertex)
|
||||
{
|
||||
DeclareOutputAttribute(context, AttributeConsts.PositionX, perPatch: false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareOutputAttribute(CodeGenContext context, int attr, bool perPatch)
|
||||
{
|
||||
DeclareInputOrOutput(context, attr, perPatch, isOutAttr: true);
|
||||
}
|
||||
|
||||
public static void DeclareInvocationId(CodeGenContext context)
|
||||
{
|
||||
DeclareInputOrOutput(context, AttributeConsts.LaneId, perPatch: false, isOutAttr: false);
|
||||
}
|
||||
|
||||
private static void DeclareInputOrOutput(CodeGenContext context, int attr, bool perPatch, bool isOutAttr, PixelImap iq = PixelImap.Unused)
|
||||
{
|
||||
bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
|
||||
if (isUserAttr && context.Config.TransformFeedbackEnabled && !perPatch &&
|
||||
((isOutAttr && context.Config.LastInVertexPipeline) ||
|
||||
(!isOutAttr && context.Config.Stage == ShaderStage.Fragment)))
|
||||
{
|
||||
DeclareTransformFeedbackInputOrOutput(context, attr, isOutAttr, iq);
|
||||
return;
|
||||
}
|
||||
|
||||
var dict = perPatch
|
||||
? (isOutAttr ? context.OutputsPerPatch : context.InputsPerPatch)
|
||||
: (isOutAttr ? context.Outputs : context.Inputs);
|
||||
|
||||
var attrInfo = perPatch
|
||||
? AttributeInfo.FromPatch(context.Config, attr, isOutAttr)
|
||||
: AttributeInfo.From(context.Config, attr, isOutAttr);
|
||||
|
||||
if (dict.ContainsKey(attrInfo.BaseValue))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||
var attrType = context.GetType(attrInfo.Type, attrInfo.Length);
|
||||
bool builtInPassthrough = false;
|
||||
|
||||
if (AttributeInfo.IsArrayAttributeSpirv(context.Config.Stage, isOutAttr) && !perPatch && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr)))
|
||||
{
|
||||
int arraySize = context.Config.Stage == ShaderStage.Geometry ? context.InputVertices : 32;
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)arraySize));
|
||||
|
||||
if (context.Config.GpPassthrough && context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
builtInPassthrough = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (context.Config.Stage == ShaderStage.TessellationControl && isOutAttr && !perPatch)
|
||||
{
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), context.Config.ThreadsPerInputPrimitive));
|
||||
}
|
||||
|
||||
var spvType = context.TypePointer(storageClass, attrType);
|
||||
var spvVar = context.Variable(spvType, storageClass);
|
||||
|
||||
if (builtInPassthrough)
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.PassthroughNV);
|
||||
}
|
||||
|
||||
if (attrInfo.IsBuiltin)
|
||||
{
|
||||
if (perPatch)
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.Patch);
|
||||
}
|
||||
|
||||
if (context.Config.GpuAccessor.QueryHostReducedPrecision() && attr == AttributeConsts.PositionX && context.Config.Stage != ShaderStage.Fragment)
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.Invariant);
|
||||
}
|
||||
|
||||
context.Decorate(spvVar, Decoration.BuiltIn, (LiteralInteger)GetBuiltIn(context, attrInfo.BaseValue));
|
||||
|
||||
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline && isOutAttr)
|
||||
{
|
||||
var tfOutput = context.Info.GetTransformFeedbackOutput(attrInfo.BaseValue);
|
||||
if (tfOutput.Valid)
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)tfOutput.Buffer);
|
||||
context.Decorate(spvVar, Decoration.XfbStride, (LiteralInteger)tfOutput.Stride);
|
||||
context.Decorate(spvVar, Decoration.Offset, (LiteralInteger)tfOutput.Offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (perPatch)
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.Patch);
|
||||
|
||||
int location = context.Config.GetPerPatchAttributeLocation((attr - AttributeConsts.UserAttributePerPatchBase) / 16);
|
||||
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||
}
|
||||
else if (isUserAttr)
|
||||
{
|
||||
int location = (attr - AttributeConsts.UserAttributeBase) / 16;
|
||||
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||
|
||||
if (!isOutAttr &&
|
||||
!perPatch &&
|
||||
(context.Config.PassthroughAttributes & (1 << location)) != 0 &&
|
||||
context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.PassthroughNV);
|
||||
}
|
||||
}
|
||||
else if (attr >= AttributeConsts.FragmentOutputColorBase && attr < AttributeConsts.FragmentOutputColorEnd)
|
||||
{
|
||||
int location = (attr - AttributeConsts.FragmentOutputColorBase) / 16;
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Fragment && context.Config.GpuAccessor.QueryDualSourceBlendEnable())
|
||||
{
|
||||
int firstLocation = BitOperations.TrailingZeroCount(context.Config.UsedOutputAttributes);
|
||||
int index = location - firstLocation;
|
||||
int mask = 3 << firstLocation;
|
||||
|
||||
if ((uint)index < 2 && (context.Config.UsedOutputAttributes & mask) == mask)
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)firstLocation);
|
||||
context.Decorate(spvVar, Decoration.Index, (LiteralInteger)index);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isOutAttr)
|
||||
{
|
||||
switch (iq)
|
||||
{
|
||||
case PixelImap.Constant:
|
||||
context.Decorate(spvVar, Decoration.Flat);
|
||||
break;
|
||||
case PixelImap.ScreenLinear:
|
||||
context.Decorate(spvVar, Decoration.NoPerspective);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
context.AddGlobalVariable(spvVar);
|
||||
dict.Add(attrInfo.BaseValue, spvVar);
|
||||
}
|
||||
|
||||
private static void DeclareTransformFeedbackInputOrOutput(CodeGenContext context, int attr, bool isOutAttr, PixelImap iq = PixelImap.Unused)
|
||||
{
|
||||
var dict = isOutAttr ? context.Outputs : context.Inputs;
|
||||
var attrInfo = AttributeInfo.From(context.Config, attr, isOutAttr);
|
||||
|
||||
bool hasComponent = true;
|
||||
int component = (attr >> 2) & 3;
|
||||
int components = 1;
|
||||
var type = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||
|
||||
if (isOutAttr)
|
||||
{
|
||||
components = context.Info.GetTransformFeedbackOutputComponents(attr);
|
||||
|
||||
if (components > 1)
|
||||
{
|
||||
attr &= ~0xf;
|
||||
type = components switch
|
||||
{
|
||||
2 => AggregateType.Vector2 | AggregateType.FP32,
|
||||
3 => AggregateType.Vector3 | AggregateType.FP32,
|
||||
4 => AggregateType.Vector4 | AggregateType.FP32,
|
||||
_ => AggregateType.FP32
|
||||
};
|
||||
|
||||
hasComponent = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (dict.ContainsKey(attr))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||
var attrType = context.GetType(type, components);
|
||||
|
||||
if (AttributeInfo.IsArrayAttributeSpirv(context.Config.Stage, isOutAttr) && (!attrInfo.IsBuiltin || AttributeInfo.IsArrayBuiltIn(attr)))
|
||||
{
|
||||
int arraySize = context.Config.Stage == ShaderStage.Geometry ? context.InputVertices : 32;
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), (LiteralInteger)arraySize));
|
||||
}
|
||||
|
||||
if (context.Config.Stage == ShaderStage.TessellationControl && isOutAttr)
|
||||
{
|
||||
attrType = context.TypeArray(attrType, context.Constant(context.TypeU32(), context.Config.ThreadsPerInputPrimitive));
|
||||
}
|
||||
|
||||
var spvType = context.TypePointer(storageClass, attrType);
|
||||
var spvVar = context.Variable(spvType, storageClass);
|
||||
|
||||
Debug.Assert(attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd);
|
||||
int location = (attr - AttributeConsts.UserAttributeBase) / 16;
|
||||
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||
|
||||
if (hasComponent)
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.Component, (LiteralInteger)component);
|
||||
}
|
||||
|
||||
if (isOutAttr)
|
||||
{
|
||||
var tfOutput = context.Info.GetTransformFeedbackOutput(attr);
|
||||
if (tfOutput.Valid)
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.XfbBuffer, (LiteralInteger)tfOutput.Buffer);
|
||||
context.Decorate(spvVar, Decoration.XfbStride, (LiteralInteger)tfOutput.Stride);
|
||||
context.Decorate(spvVar, Decoration.Offset, (LiteralInteger)tfOutput.Offset);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((context.Config.PassthroughAttributes & (1 << location)) != 0 &&
|
||||
context.Config.GpuAccessor.QueryHostSupportsGeometryShaderPassthrough())
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.PassthroughNV);
|
||||
}
|
||||
|
||||
switch (iq)
|
||||
{
|
||||
case PixelImap.Constant:
|
||||
context.Decorate(spvVar, Decoration.Flat);
|
||||
break;
|
||||
case PixelImap.ScreenLinear:
|
||||
context.Decorate(spvVar, Decoration.NoPerspective);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
context.AddGlobalVariable(spvVar);
|
||||
dict.Add(attr, spvVar);
|
||||
}
|
||||
|
||||
private static BuiltIn GetBuiltIn(CodeGenContext context, int attr)
|
||||
{
|
||||
return attr switch
|
||||
{
|
||||
AttributeConsts.TessLevelOuter0 => BuiltIn.TessLevelOuter,
|
||||
AttributeConsts.TessLevelInner0 => BuiltIn.TessLevelInner,
|
||||
AttributeConsts.Layer => BuiltIn.Layer,
|
||||
AttributeConsts.ViewportIndex => BuiltIn.ViewportIndex,
|
||||
AttributeConsts.PointSize => BuiltIn.PointSize,
|
||||
AttributeConsts.PositionX => context.Config.Stage == ShaderStage.Fragment ? BuiltIn.FragCoord : BuiltIn.Position,
|
||||
AttributeConsts.ClipDistance0 => BuiltIn.ClipDistance,
|
||||
AttributeConsts.PointCoordX => BuiltIn.PointCoord,
|
||||
AttributeConsts.TessCoordX => BuiltIn.TessCoord,
|
||||
AttributeConsts.InstanceId => BuiltIn.InstanceId,
|
||||
AttributeConsts.VertexId => BuiltIn.VertexId,
|
||||
AttributeConsts.BaseInstance => BuiltIn.BaseInstance,
|
||||
AttributeConsts.BaseVertex => BuiltIn.BaseVertex,
|
||||
AttributeConsts.InstanceIndex => BuiltIn.InstanceIndex,
|
||||
AttributeConsts.VertexIndex => BuiltIn.VertexIndex,
|
||||
AttributeConsts.DrawIndex => BuiltIn.DrawIndex,
|
||||
AttributeConsts.FrontFacing => BuiltIn.FrontFacing,
|
||||
AttributeConsts.FragmentOutputDepth => BuiltIn.FragDepth,
|
||||
AttributeConsts.ThreadKill => BuiltIn.HelperInvocation,
|
||||
AttributeConsts.ThreadIdX => BuiltIn.LocalInvocationId,
|
||||
AttributeConsts.CtaIdX => BuiltIn.WorkgroupId,
|
||||
AttributeConsts.LaneId => BuiltIn.SubgroupLocalInvocationId,
|
||||
AttributeConsts.InvocationId => BuiltIn.InvocationId,
|
||||
AttributeConsts.PrimitiveId => BuiltIn.PrimitiveId,
|
||||
AttributeConsts.PatchVerticesIn => BuiltIn.PatchVertices,
|
||||
AttributeConsts.EqMask => BuiltIn.SubgroupEqMask,
|
||||
AttributeConsts.GeMask => BuiltIn.SubgroupGeMask,
|
||||
AttributeConsts.GtMask => BuiltIn.SubgroupGtMask,
|
||||
AttributeConsts.LeMask => BuiltIn.SubgroupLeMask,
|
||||
AttributeConsts.LtMask => BuiltIn.SubgroupLtMask,
|
||||
AttributeConsts.SupportBlockViewInverseX => BuiltIn.Position,
|
||||
AttributeConsts.SupportBlockViewInverseY => BuiltIn.Position,
|
||||
_ => throw new ArgumentException($"Invalid attribute number 0x{attr:X}.")
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetStagePrefix(ShaderStage stage)
|
||||
{
|
||||
return StagePrefixes[(int)stage];
|
||||
}
|
||||
}
|
||||
}
|
@ -1,227 +0,0 @@
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using static Spv.Specification;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
using SpvInstruction = Spv.Generator.Instruction;
|
||||
|
||||
static class ScalingHelpers
|
||||
{
|
||||
public static SpvInstruction ApplyScaling(
|
||||
CodeGenContext context,
|
||||
AstTextureOperation texOp,
|
||||
SpvInstruction vector,
|
||||
bool intCoords,
|
||||
bool isBindless,
|
||||
bool isIndexed,
|
||||
bool isArray,
|
||||
int pCount)
|
||||
{
|
||||
if (intCoords)
|
||||
{
|
||||
if (context.Config.Stage.SupportsRenderScale() &&
|
||||
!isBindless &&
|
||||
!isIndexed)
|
||||
{
|
||||
int index = texOp.Inst == Instruction.ImageLoad
|
||||
? context.Config.GetTextureDescriptors().Length + context.Config.FindImageDescriptorIndex(texOp)
|
||||
: context.Config.FindTextureDescriptorIndex(texOp);
|
||||
|
||||
if (pCount == 3 && isArray)
|
||||
{
|
||||
return ApplyScaling2DArray(context, vector, index);
|
||||
}
|
||||
else if (pCount == 2 && !isArray)
|
||||
{
|
||||
return ApplyScaling2D(context, vector, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
private static SpvInstruction ApplyScaling2DArray(CodeGenContext context, SpvInstruction vector, int index)
|
||||
{
|
||||
// The array index is not scaled, just x and y.
|
||||
var vectorXY = context.VectorShuffle(context.TypeVector(context.TypeS32(), 2), vector, vector, 0, 1);
|
||||
var vectorZ = context.CompositeExtract(context.TypeS32(), vector, 2);
|
||||
var vectorXYScaled = ApplyScaling2D(context, vectorXY, index);
|
||||
var vectorScaled = context.CompositeConstruct(context.TypeVector(context.TypeS32(), 3), vectorXYScaled, vectorZ);
|
||||
|
||||
return vectorScaled;
|
||||
}
|
||||
|
||||
private static SpvInstruction ApplyScaling2D(CodeGenContext context, SpvInstruction vector, int index)
|
||||
{
|
||||
var pointerType = context.TypePointer(StorageClass.Uniform, context.TypeFP32());
|
||||
var fieldIndex = context.Constant(context.TypeU32(), 4);
|
||||
var scaleIndex = context.Constant(context.TypeU32(), index);
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Vertex)
|
||||
{
|
||||
var scaleCountPointerType = context.TypePointer(StorageClass.Uniform, context.TypeS32());
|
||||
var scaleCountElemPointer = context.AccessChain(scaleCountPointerType, context.SupportBuffer, context.Constant(context.TypeU32(), 3));
|
||||
var scaleCount = context.Load(context.TypeS32(), scaleCountElemPointer);
|
||||
|
||||
scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, scaleCount);
|
||||
}
|
||||
|
||||
scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, context.Constant(context.TypeU32(), 1));
|
||||
|
||||
var scaleElemPointer = context.AccessChain(pointerType, context.SupportBuffer, fieldIndex, scaleIndex);
|
||||
var scale = context.Load(context.TypeFP32(), scaleElemPointer);
|
||||
|
||||
var ivector2Type = context.TypeVector(context.TypeS32(), 2);
|
||||
var localVector = context.CoordTemp;
|
||||
|
||||
var passthrough = context.FOrdEqual(context.TypeBool(), scale, context.Constant(context.TypeFP32(), 1f));
|
||||
|
||||
var mergeLabel = context.Label();
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Fragment)
|
||||
{
|
||||
var scaledInterpolatedLabel = context.Label();
|
||||
var scaledNoInterpolationLabel = context.Label();
|
||||
|
||||
var needsInterpolation = context.FOrdLessThan(context.TypeBool(), scale, context.Constant(context.TypeFP32(), 0f));
|
||||
|
||||
context.SelectionMerge(mergeLabel, SelectionControlMask.MaskNone);
|
||||
context.BranchConditional(needsInterpolation, scaledInterpolatedLabel, scaledNoInterpolationLabel);
|
||||
|
||||
// scale < 0.0
|
||||
context.AddLabel(scaledInterpolatedLabel);
|
||||
|
||||
ApplyScalingInterpolated(context, localVector, vector, scale);
|
||||
context.Branch(mergeLabel);
|
||||
|
||||
// scale >= 0.0
|
||||
context.AddLabel(scaledNoInterpolationLabel);
|
||||
|
||||
ApplyScalingNoInterpolation(context, localVector, vector, scale);
|
||||
context.Branch(mergeLabel);
|
||||
|
||||
context.AddLabel(mergeLabel);
|
||||
|
||||
var passthroughLabel = context.Label();
|
||||
var finalMergeLabel = context.Label();
|
||||
|
||||
context.SelectionMerge(finalMergeLabel, SelectionControlMask.MaskNone);
|
||||
context.BranchConditional(passthrough, passthroughLabel, finalMergeLabel);
|
||||
|
||||
context.AddLabel(passthroughLabel);
|
||||
|
||||
context.Store(localVector, vector);
|
||||
context.Branch(finalMergeLabel);
|
||||
|
||||
context.AddLabel(finalMergeLabel);
|
||||
|
||||
return context.Load(ivector2Type, localVector);
|
||||
}
|
||||
else
|
||||
{
|
||||
var passthroughLabel = context.Label();
|
||||
var scaledLabel = context.Label();
|
||||
|
||||
context.SelectionMerge(mergeLabel, SelectionControlMask.MaskNone);
|
||||
context.BranchConditional(passthrough, passthroughLabel, scaledLabel);
|
||||
|
||||
// scale == 1.0
|
||||
context.AddLabel(passthroughLabel);
|
||||
|
||||
context.Store(localVector, vector);
|
||||
context.Branch(mergeLabel);
|
||||
|
||||
// scale != 1.0
|
||||
context.AddLabel(scaledLabel);
|
||||
|
||||
ApplyScalingNoInterpolation(context, localVector, vector, scale);
|
||||
context.Branch(mergeLabel);
|
||||
|
||||
context.AddLabel(mergeLabel);
|
||||
|
||||
return context.Load(ivector2Type, localVector);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ApplyScalingInterpolated(CodeGenContext context, SpvInstruction output, SpvInstruction vector, SpvInstruction scale)
|
||||
{
|
||||
var vector2Type = context.TypeVector(context.TypeFP32(), 2);
|
||||
|
||||
var scaleNegated = context.FNegate(context.TypeFP32(), scale);
|
||||
var scaleVector = context.CompositeConstruct(vector2Type, scaleNegated, scaleNegated);
|
||||
|
||||
var vectorFloat = context.ConvertSToF(vector2Type, vector);
|
||||
var vectorScaled = context.VectorTimesScalar(vector2Type, vectorFloat, scaleNegated);
|
||||
|
||||
var fragCoordPointer = context.Inputs[AttributeConsts.PositionX];
|
||||
var fragCoord = context.Load(context.TypeVector(context.TypeFP32(), 4), fragCoordPointer);
|
||||
var fragCoordXY = context.VectorShuffle(vector2Type, fragCoord, fragCoord, 0, 1);
|
||||
|
||||
var scaleMod = context.FMod(vector2Type, fragCoordXY, scaleVector);
|
||||
var vectorInterpolated = context.FAdd(vector2Type, vectorScaled, scaleMod);
|
||||
|
||||
context.Store(output, context.ConvertFToS(context.TypeVector(context.TypeS32(), 2), vectorInterpolated));
|
||||
}
|
||||
|
||||
private static void ApplyScalingNoInterpolation(CodeGenContext context, SpvInstruction output, SpvInstruction vector, SpvInstruction scale)
|
||||
{
|
||||
if (context.Config.Stage == ShaderStage.Vertex)
|
||||
{
|
||||
scale = context.GlslFAbs(context.TypeFP32(), scale);
|
||||
}
|
||||
|
||||
var vector2Type = context.TypeVector(context.TypeFP32(), 2);
|
||||
|
||||
var vectorFloat = context.ConvertSToF(vector2Type, vector);
|
||||
var vectorScaled = context.VectorTimesScalar(vector2Type, vectorFloat, scale);
|
||||
|
||||
context.Store(output, context.ConvertFToS(context.TypeVector(context.TypeS32(), 2), vectorScaled));
|
||||
}
|
||||
|
||||
public static SpvInstruction ApplyUnscaling(
|
||||
CodeGenContext context,
|
||||
AstTextureOperation texOp,
|
||||
SpvInstruction size,
|
||||
bool isBindless,
|
||||
bool isIndexed)
|
||||
{
|
||||
if (context.Config.Stage.SupportsRenderScale() &&
|
||||
!isBindless &&
|
||||
!isIndexed)
|
||||
{
|
||||
int index = context.Config.FindTextureDescriptorIndex(texOp);
|
||||
|
||||
var pointerType = context.TypePointer(StorageClass.Uniform, context.TypeFP32());
|
||||
var fieldIndex = context.Constant(context.TypeU32(), 4);
|
||||
var scaleIndex = context.Constant(context.TypeU32(), index);
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Vertex)
|
||||
{
|
||||
var scaleCountPointerType = context.TypePointer(StorageClass.Uniform, context.TypeS32());
|
||||
var scaleCountElemPointer = context.AccessChain(scaleCountPointerType, context.SupportBuffer, context.Constant(context.TypeU32(), 3));
|
||||
var scaleCount = context.Load(context.TypeS32(), scaleCountElemPointer);
|
||||
|
||||
scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, scaleCount);
|
||||
}
|
||||
|
||||
scaleIndex = context.IAdd(context.TypeU32(), scaleIndex, context.Constant(context.TypeU32(), 1));
|
||||
|
||||
var scaleElemPointer = context.AccessChain(pointerType, context.SupportBuffer, fieldIndex, scaleIndex);
|
||||
var scale = context.GlslFAbs(context.TypeFP32(), context.Load(context.TypeFP32(), scaleElemPointer));
|
||||
|
||||
var passthrough = context.FOrdEqual(context.TypeBool(), scale, context.Constant(context.TypeFP32(), 1f));
|
||||
|
||||
var sizeFloat = context.ConvertSToF(context.TypeFP32(), size);
|
||||
var sizeUnscaled = context.FDiv(context.TypeFP32(), sizeFloat, scale);
|
||||
var sizeUnscaledInt = context.ConvertFToS(context.TypeS32(), sizeUnscaled);
|
||||
|
||||
return context.Select(context.TypeS32(), passthrough, size, sizeUnscaledInt);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
{
|
||||
readonly record struct TextureMeta(int CbufSlot, int Handle, TextureFormat Format);
|
||||
}
|
@ -1,379 +0,0 @@
|
||||
using Ryujinx.Graphics.Shader.Decoders;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Instructions
|
||||
{
|
||||
static partial class InstEmit
|
||||
{
|
||||
public static void AtomCas(EmitterContext context)
|
||||
{
|
||||
InstAtomCas op = context.GetOp<InstAtomCas>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction AtomCas is not implemented.");
|
||||
}
|
||||
|
||||
public static void AtomsCas(EmitterContext context)
|
||||
{
|
||||
InstAtomsCas op = context.GetOp<InstAtomsCas>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction AtomsCas is not implemented.");
|
||||
}
|
||||
|
||||
public static void B2r(EmitterContext context)
|
||||
{
|
||||
InstB2r op = context.GetOp<InstB2r>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction B2r is not implemented.");
|
||||
}
|
||||
|
||||
public static void Bpt(EmitterContext context)
|
||||
{
|
||||
InstBpt op = context.GetOp<InstBpt>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Bpt is not implemented.");
|
||||
}
|
||||
|
||||
public static void Cctl(EmitterContext context)
|
||||
{
|
||||
InstCctl op = context.GetOp<InstCctl>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Cctl is not implemented.");
|
||||
}
|
||||
|
||||
public static void Cctll(EmitterContext context)
|
||||
{
|
||||
InstCctll op = context.GetOp<InstCctll>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Cctll is not implemented.");
|
||||
}
|
||||
|
||||
public static void Cctlt(EmitterContext context)
|
||||
{
|
||||
InstCctlt op = context.GetOp<InstCctlt>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Cctlt is not implemented.");
|
||||
}
|
||||
|
||||
public static void Cs2r(EmitterContext context)
|
||||
{
|
||||
InstCs2r op = context.GetOp<InstCs2r>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Cs2r is not implemented.");
|
||||
}
|
||||
|
||||
public static void FchkR(EmitterContext context)
|
||||
{
|
||||
InstFchkR op = context.GetOp<InstFchkR>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction FchkR is not implemented.");
|
||||
}
|
||||
|
||||
public static void FchkI(EmitterContext context)
|
||||
{
|
||||
InstFchkI op = context.GetOp<InstFchkI>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction FchkI is not implemented.");
|
||||
}
|
||||
|
||||
public static void FchkC(EmitterContext context)
|
||||
{
|
||||
InstFchkC op = context.GetOp<InstFchkC>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction FchkC is not implemented.");
|
||||
}
|
||||
|
||||
public static void Getcrsptr(EmitterContext context)
|
||||
{
|
||||
InstGetcrsptr op = context.GetOp<InstGetcrsptr>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Getcrsptr is not implemented.");
|
||||
}
|
||||
|
||||
public static void Getlmembase(EmitterContext context)
|
||||
{
|
||||
InstGetlmembase op = context.GetOp<InstGetlmembase>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Getlmembase is not implemented.");
|
||||
}
|
||||
|
||||
public static void Ide(EmitterContext context)
|
||||
{
|
||||
InstIde op = context.GetOp<InstIde>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Ide is not implemented.");
|
||||
}
|
||||
|
||||
public static void IdpR(EmitterContext context)
|
||||
{
|
||||
InstIdpR op = context.GetOp<InstIdpR>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction IdpR is not implemented.");
|
||||
}
|
||||
|
||||
public static void IdpC(EmitterContext context)
|
||||
{
|
||||
InstIdpC op = context.GetOp<InstIdpC>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction IdpC is not implemented.");
|
||||
}
|
||||
|
||||
public static void ImadspR(EmitterContext context)
|
||||
{
|
||||
InstImadspR op = context.GetOp<InstImadspR>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction ImadspR is not implemented.");
|
||||
}
|
||||
|
||||
public static void ImadspI(EmitterContext context)
|
||||
{
|
||||
InstImadspI op = context.GetOp<InstImadspI>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction ImadspI is not implemented.");
|
||||
}
|
||||
|
||||
public static void ImadspC(EmitterContext context)
|
||||
{
|
||||
InstImadspC op = context.GetOp<InstImadspC>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction ImadspC is not implemented.");
|
||||
}
|
||||
|
||||
public static void ImadspRc(EmitterContext context)
|
||||
{
|
||||
InstImadspRc op = context.GetOp<InstImadspRc>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction ImadspRc is not implemented.");
|
||||
}
|
||||
|
||||
public static void Jcal(EmitterContext context)
|
||||
{
|
||||
InstJcal op = context.GetOp<InstJcal>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Jcal is not implemented.");
|
||||
}
|
||||
|
||||
public static void Jmp(EmitterContext context)
|
||||
{
|
||||
InstJmp op = context.GetOp<InstJmp>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Jmp is not implemented.");
|
||||
}
|
||||
|
||||
public static void Jmx(EmitterContext context)
|
||||
{
|
||||
InstJmx op = context.GetOp<InstJmx>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Jmx is not implemented.");
|
||||
}
|
||||
|
||||
public static void Ld(EmitterContext context)
|
||||
{
|
||||
InstLd op = context.GetOp<InstLd>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Ld is not implemented.");
|
||||
}
|
||||
|
||||
public static void Lepc(EmitterContext context)
|
||||
{
|
||||
InstLepc op = context.GetOp<InstLepc>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Lepc is not implemented.");
|
||||
}
|
||||
|
||||
public static void Longjmp(EmitterContext context)
|
||||
{
|
||||
InstLongjmp op = context.GetOp<InstLongjmp>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Longjmp is not implemented.");
|
||||
}
|
||||
|
||||
public static void P2rR(EmitterContext context)
|
||||
{
|
||||
InstP2rR op = context.GetOp<InstP2rR>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction P2rR is not implemented.");
|
||||
}
|
||||
|
||||
public static void P2rI(EmitterContext context)
|
||||
{
|
||||
InstP2rI op = context.GetOp<InstP2rI>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction P2rI is not implemented.");
|
||||
}
|
||||
|
||||
public static void P2rC(EmitterContext context)
|
||||
{
|
||||
InstP2rC op = context.GetOp<InstP2rC>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction P2rC is not implemented.");
|
||||
}
|
||||
|
||||
public static void Pexit(EmitterContext context)
|
||||
{
|
||||
InstPexit op = context.GetOp<InstPexit>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Pexit is not implemented.");
|
||||
}
|
||||
|
||||
public static void Pixld(EmitterContext context)
|
||||
{
|
||||
InstPixld op = context.GetOp<InstPixld>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Pixld is not implemented.");
|
||||
}
|
||||
|
||||
public static void Plongjmp(EmitterContext context)
|
||||
{
|
||||
InstPlongjmp op = context.GetOp<InstPlongjmp>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Plongjmp is not implemented.");
|
||||
}
|
||||
|
||||
public static void Pret(EmitterContext context)
|
||||
{
|
||||
InstPret op = context.GetOp<InstPret>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Pret is not implemented.");
|
||||
}
|
||||
|
||||
public static void PrmtR(EmitterContext context)
|
||||
{
|
||||
InstPrmtR op = context.GetOp<InstPrmtR>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction PrmtR is not implemented.");
|
||||
}
|
||||
|
||||
public static void PrmtI(EmitterContext context)
|
||||
{
|
||||
InstPrmtI op = context.GetOp<InstPrmtI>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction PrmtI is not implemented.");
|
||||
}
|
||||
|
||||
public static void PrmtC(EmitterContext context)
|
||||
{
|
||||
InstPrmtC op = context.GetOp<InstPrmtC>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction PrmtC is not implemented.");
|
||||
}
|
||||
|
||||
public static void PrmtRc(EmitterContext context)
|
||||
{
|
||||
InstPrmtRc op = context.GetOp<InstPrmtRc>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction PrmtRc is not implemented.");
|
||||
}
|
||||
|
||||
public static void R2b(EmitterContext context)
|
||||
{
|
||||
InstR2b op = context.GetOp<InstR2b>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction R2b is not implemented.");
|
||||
}
|
||||
|
||||
public static void Ram(EmitterContext context)
|
||||
{
|
||||
InstRam op = context.GetOp<InstRam>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Ram is not implemented.");
|
||||
}
|
||||
|
||||
public static void Rtt(EmitterContext context)
|
||||
{
|
||||
InstRtt op = context.GetOp<InstRtt>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Rtt is not implemented.");
|
||||
}
|
||||
|
||||
public static void Sam(EmitterContext context)
|
||||
{
|
||||
InstSam op = context.GetOp<InstSam>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Sam is not implemented.");
|
||||
}
|
||||
|
||||
public static void Setcrsptr(EmitterContext context)
|
||||
{
|
||||
InstSetcrsptr op = context.GetOp<InstSetcrsptr>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Setcrsptr is not implemented.");
|
||||
}
|
||||
|
||||
public static void Setlmembase(EmitterContext context)
|
||||
{
|
||||
InstSetlmembase op = context.GetOp<InstSetlmembase>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Setlmembase is not implemented.");
|
||||
}
|
||||
|
||||
public static void St(EmitterContext context)
|
||||
{
|
||||
InstSt op = context.GetOp<InstSt>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction St is not implemented.");
|
||||
}
|
||||
|
||||
public static void Stp(EmitterContext context)
|
||||
{
|
||||
InstStp op = context.GetOp<InstStp>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Stp is not implemented.");
|
||||
}
|
||||
|
||||
public static void Txa(EmitterContext context)
|
||||
{
|
||||
InstTxa op = context.GetOp<InstTxa>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Txa is not implemented.");
|
||||
}
|
||||
|
||||
public static void Vabsdiff(EmitterContext context)
|
||||
{
|
||||
InstVabsdiff op = context.GetOp<InstVabsdiff>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Vabsdiff is not implemented.");
|
||||
}
|
||||
|
||||
public static void Vabsdiff4(EmitterContext context)
|
||||
{
|
||||
InstVabsdiff4 op = context.GetOp<InstVabsdiff4>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Vabsdiff4 is not implemented.");
|
||||
}
|
||||
|
||||
public static void Vadd(EmitterContext context)
|
||||
{
|
||||
InstVadd op = context.GetOp<InstVadd>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Vadd is not implemented.");
|
||||
}
|
||||
|
||||
public static void Votevtg(EmitterContext context)
|
||||
{
|
||||
InstVotevtg op = context.GetOp<InstVotevtg>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Votevtg is not implemented.");
|
||||
}
|
||||
|
||||
public static void Vset(EmitterContext context)
|
||||
{
|
||||
InstVset op = context.GetOp<InstVset>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Vset is not implemented.");
|
||||
}
|
||||
|
||||
public static void Vshl(EmitterContext context)
|
||||
{
|
||||
InstVshl op = context.GetOp<InstVshl>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Vshl is not implemented.");
|
||||
}
|
||||
|
||||
public static void Vshr(EmitterContext context)
|
||||
{
|
||||
InstVshr op = context.GetOp<InstVshr>();
|
||||
|
||||
context.Config.GpuAccessor.Log("Shader instruction Vshr is not implemented.");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,341 +0,0 @@
|
||||
using Ryujinx.Graphics.Shader.Decoders;
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
|
||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Instructions
|
||||
{
|
||||
static partial class InstEmit
|
||||
{
|
||||
public static void Al2p(EmitterContext context)
|
||||
{
|
||||
InstAl2p op = context.GetOp<InstAl2p>();
|
||||
|
||||
context.Copy(GetDest(op.Dest), context.IAdd(GetSrcReg(context, op.SrcA), Const(op.Imm11)));
|
||||
}
|
||||
|
||||
public static void Ald(EmitterContext context)
|
||||
{
|
||||
InstAld op = context.GetOp<InstAld>();
|
||||
|
||||
Operand primVertex = context.Copy(GetSrcReg(context, op.SrcB));
|
||||
|
||||
for (int index = 0; index < (int)op.AlSize + 1; index++)
|
||||
{
|
||||
Register rd = new Register(op.Dest + index, RegisterType.Gpr);
|
||||
|
||||
if (rd.IsRZ)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (op.Phys)
|
||||
{
|
||||
Operand userAttrOffset = context.ISubtract(GetSrcReg(context, op.SrcA), Const(AttributeConsts.UserAttributeBase));
|
||||
Operand userAttrIndex = context.ShiftRightU32(userAttrOffset, Const(2));
|
||||
|
||||
context.Copy(Register(rd), context.LoadAttribute(Const(AttributeConsts.UserAttributeBase), userAttrIndex, primVertex));
|
||||
|
||||
context.Config.SetUsedFeature(FeatureFlags.IaIndexing);
|
||||
}
|
||||
else if (op.SrcB == RegisterConsts.RegisterZeroIndex || op.P)
|
||||
{
|
||||
int offset = FixedFuncToUserAttribute(context.Config, op.Imm11 + index * 4, op.O);
|
||||
|
||||
context.FlagAttributeRead(offset);
|
||||
|
||||
if (op.O && CanLoadOutput(offset))
|
||||
{
|
||||
offset |= AttributeConsts.LoadOutputMask;
|
||||
}
|
||||
|
||||
Operand src = op.P ? AttributePerPatch(offset) : CreateInputAttribute(context, offset);
|
||||
|
||||
context.Copy(Register(rd), src);
|
||||
}
|
||||
else
|
||||
{
|
||||
int offset = FixedFuncToUserAttribute(context.Config, op.Imm11 + index * 4, op.O);
|
||||
|
||||
context.FlagAttributeRead(offset);
|
||||
|
||||
if (op.O && CanLoadOutput(offset))
|
||||
{
|
||||
offset |= AttributeConsts.LoadOutputMask;
|
||||
}
|
||||
|
||||
Operand src = Const(offset);
|
||||
|
||||
context.Copy(Register(rd), context.LoadAttribute(src, Const(0), primVertex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ast(EmitterContext context)
|
||||
{
|
||||
InstAst op = context.GetOp<InstAst>();
|
||||
|
||||
for (int index = 0; index < (int)op.AlSize + 1; index++)
|
||||
{
|
||||
if (op.SrcB + index > RegisterConsts.RegisterZeroIndex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Register rd = new Register(op.SrcB + index, RegisterType.Gpr);
|
||||
|
||||
if (op.Phys)
|
||||
{
|
||||
Operand userAttrOffset = context.ISubtract(GetSrcReg(context, op.SrcA), Const(AttributeConsts.UserAttributeBase));
|
||||
Operand userAttrIndex = context.ShiftRightU32(userAttrOffset, Const(2));
|
||||
|
||||
context.StoreAttribute(Const(AttributeConsts.UserAttributeBase), userAttrIndex, Register(rd));
|
||||
|
||||
context.Config.SetUsedFeature(FeatureFlags.OaIndexing);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Support indirect stores using Ra.
|
||||
|
||||
int offset = op.Imm11 + index * 4;
|
||||
|
||||
if (!context.Config.IsUsedOutputAttribute(offset))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
offset = FixedFuncToUserAttribute(context.Config, offset, isOutput: true);
|
||||
|
||||
context.FlagAttributeWritten(offset);
|
||||
|
||||
Operand dest = op.P ? AttributePerPatch(offset) : Attribute(offset);
|
||||
|
||||
context.Copy(dest, Register(rd));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ipa(EmitterContext context)
|
||||
{
|
||||
InstIpa op = context.GetOp<InstIpa>();
|
||||
|
||||
context.FlagAttributeRead(op.Imm10);
|
||||
|
||||
Operand res;
|
||||
|
||||
bool isFixedFunc = false;
|
||||
|
||||
if (op.Idx)
|
||||
{
|
||||
Operand userAttrOffset = context.ISubtract(GetSrcReg(context, op.SrcA), Const(AttributeConsts.UserAttributeBase));
|
||||
Operand userAttrIndex = context.ShiftRightU32(userAttrOffset, Const(2));
|
||||
|
||||
res = context.LoadAttribute(Const(AttributeConsts.UserAttributeBase), userAttrIndex, Const(0));
|
||||
res = context.FPMultiply(res, Attribute(AttributeConsts.PositionW));
|
||||
|
||||
context.Config.SetUsedFeature(FeatureFlags.IaIndexing);
|
||||
}
|
||||
else
|
||||
{
|
||||
isFixedFunc = TryFixedFuncToUserAttributeIpa(context, op.Imm10, out res);
|
||||
|
||||
if (op.Imm10 >= AttributeConsts.UserAttributeBase && op.Imm10 < AttributeConsts.UserAttributeEnd)
|
||||
{
|
||||
int index = (op.Imm10 - AttributeConsts.UserAttributeBase) >> 4;
|
||||
|
||||
if (context.Config.ImapTypes[index].GetFirstUsedType() == PixelImap.Perspective)
|
||||
{
|
||||
res = context.FPMultiply(res, Attribute(AttributeConsts.PositionW));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (op.IpaOp == IpaOp.Multiply && !isFixedFunc)
|
||||
{
|
||||
Operand srcB = GetSrcReg(context, op.SrcB);
|
||||
|
||||
res = context.FPMultiply(res, srcB);
|
||||
}
|
||||
|
||||
res = context.FPSaturate(res, op.Sat);
|
||||
|
||||
context.Copy(GetDest(op.Dest), res);
|
||||
}
|
||||
|
||||
public static void Isberd(EmitterContext context)
|
||||
{
|
||||
InstIsberd op = context.GetOp<InstIsberd>();
|
||||
|
||||
// This instruction performs a load from ISBE (Internal Stage Buffer Entry) memory.
|
||||
// Here, we just propagate the offset, as the result from this instruction is usually
|
||||
// used with ALD to perform vertex load on geometry or tessellation shaders.
|
||||
// The offset is calculated as (PrimitiveIndex * VerticesPerPrimitive) + VertexIndex.
|
||||
// Since we hardcode PrimitiveIndex to zero, then the offset will be just VertexIndex.
|
||||
context.Copy(GetDest(op.Dest), GetSrcReg(context, op.SrcA));
|
||||
}
|
||||
|
||||
public static void OutR(EmitterContext context)
|
||||
{
|
||||
InstOutR op = context.GetOp<InstOutR>();
|
||||
|
||||
EmitOut(context, op.OutType.HasFlag(OutType.Emit), op.OutType.HasFlag(OutType.Cut));
|
||||
}
|
||||
|
||||
public static void OutI(EmitterContext context)
|
||||
{
|
||||
InstOutI op = context.GetOp<InstOutI>();
|
||||
|
||||
EmitOut(context, op.OutType.HasFlag(OutType.Emit), op.OutType.HasFlag(OutType.Cut));
|
||||
}
|
||||
|
||||
public static void OutC(EmitterContext context)
|
||||
{
|
||||
InstOutC op = context.GetOp<InstOutC>();
|
||||
|
||||
EmitOut(context, op.OutType.HasFlag(OutType.Emit), op.OutType.HasFlag(OutType.Cut));
|
||||
}
|
||||
|
||||
private static void EmitOut(EmitterContext context, bool emit, bool cut)
|
||||
{
|
||||
if (!(emit || cut))
|
||||
{
|
||||
context.Config.GpuAccessor.Log("Invalid OUT encoding.");
|
||||
}
|
||||
|
||||
if (emit)
|
||||
{
|
||||
if (context.Config.LastInVertexPipeline)
|
||||
{
|
||||
context.PrepareForVertexReturn(out var tempXLocal, out var tempYLocal, out var tempZLocal);
|
||||
|
||||
context.EmitVertex();
|
||||
|
||||
// Restore output position value before transformation.
|
||||
|
||||
if (tempXLocal != null)
|
||||
{
|
||||
context.Copy(Attribute(AttributeConsts.PositionX), tempXLocal);
|
||||
}
|
||||
|
||||
if (tempYLocal != null)
|
||||
{
|
||||
context.Copy(Attribute(AttributeConsts.PositionY), tempYLocal);
|
||||
}
|
||||
|
||||
if (tempZLocal != null)
|
||||
{
|
||||
context.Copy(Attribute(AttributeConsts.PositionZ), tempZLocal);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context.EmitVertex();
|
||||
}
|
||||
}
|
||||
|
||||
if (cut)
|
||||
{
|
||||
context.EndPrimitive();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CanLoadOutput(int attr)
|
||||
{
|
||||
return attr != AttributeConsts.TessCoordX && attr != AttributeConsts.TessCoordY;
|
||||
}
|
||||
|
||||
private static bool TryFixedFuncToUserAttributeIpa(EmitterContext context, int attr, out Operand selectedAttr)
|
||||
{
|
||||
if (attr >= AttributeConsts.FrontColorDiffuseR && attr < AttributeConsts.BackColorDiffuseR)
|
||||
{
|
||||
// TODO: If two sided rendering is enabled, then this should return
|
||||
// FrontColor if the fragment is front facing, and back color otherwise.
|
||||
int index = (attr - AttributeConsts.FrontColorDiffuseR) >> 4;
|
||||
int userAttrIndex = context.Config.GetFreeUserAttribute(isOutput: false, index);
|
||||
Operand frontAttr = Attribute(AttributeConsts.UserAttributeBase + userAttrIndex * 16 + (attr & 0xf));
|
||||
|
||||
context.Config.SetInputUserAttributeFixedFunc(userAttrIndex);
|
||||
|
||||
selectedAttr = frontAttr;
|
||||
return true;
|
||||
}
|
||||
else if (attr >= AttributeConsts.BackColorDiffuseR && attr < AttributeConsts.ClipDistance0)
|
||||
{
|
||||
selectedAttr = ConstF(((attr >> 2) & 3) == 3 ? 1f : 0f);
|
||||
return true;
|
||||
}
|
||||
else if (attr >= AttributeConsts.TexCoordBase && attr < AttributeConsts.TexCoordEnd)
|
||||
{
|
||||
selectedAttr = Attribute(FixedFuncToUserAttribute(context.Config, attr, AttributeConsts.TexCoordBase, 4, isOutput: false));
|
||||
return true;
|
||||
}
|
||||
|
||||
selectedAttr = Attribute(attr);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int FixedFuncToUserAttribute(ShaderConfig config, int attr, bool isOutput)
|
||||
{
|
||||
bool supportsLayerFromVertexOrTess = config.GpuAccessor.QueryHostSupportsLayerVertexTessellation();
|
||||
int fixedStartAttr = supportsLayerFromVertexOrTess ? 0 : 1;
|
||||
|
||||
if (attr == AttributeConsts.Layer && config.Stage != ShaderStage.Geometry && !supportsLayerFromVertexOrTess)
|
||||
{
|
||||
attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.Layer, 0, isOutput);
|
||||
config.SetLayerOutputAttribute(attr);
|
||||
}
|
||||
else if (attr >= AttributeConsts.FrontColorDiffuseR && attr < AttributeConsts.ClipDistance0)
|
||||
{
|
||||
attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.FrontColorDiffuseR, fixedStartAttr, isOutput);
|
||||
}
|
||||
else if (attr >= AttributeConsts.TexCoordBase && attr < AttributeConsts.TexCoordEnd)
|
||||
{
|
||||
attr = FixedFuncToUserAttribute(config, attr, AttributeConsts.TexCoordBase, fixedStartAttr + 4, isOutput);
|
||||
}
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
private static int FixedFuncToUserAttribute(ShaderConfig config, int attr, int baseAttr, int baseIndex, bool isOutput)
|
||||
{
|
||||
int index = (attr - baseAttr) >> 4;
|
||||
int userAttrIndex = config.GetFreeUserAttribute(isOutput, index);
|
||||
|
||||
if ((uint)userAttrIndex < Constants.MaxAttributes)
|
||||
{
|
||||
userAttrIndex += baseIndex;
|
||||
attr = AttributeConsts.UserAttributeBase + userAttrIndex * 16 + (attr & 0xf);
|
||||
|
||||
if (isOutput)
|
||||
{
|
||||
config.SetOutputUserAttributeFixedFunc(userAttrIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
config.SetInputUserAttributeFixedFunc(userAttrIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
private static Operand CreateInputAttribute(EmitterContext context, int attr)
|
||||
{
|
||||
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
|
||||
{
|
||||
if (attr == AttributeConsts.InstanceId)
|
||||
{
|
||||
return context.ISubtract(Attribute(AttributeConsts.InstanceIndex), Attribute(AttributeConsts.BaseInstance));
|
||||
}
|
||||
else if (attr == AttributeConsts.VertexId)
|
||||
{
|
||||
return Attribute(AttributeConsts.VertexIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return Attribute(attr);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
using Ryujinx.Graphics.Shader.Decoders;
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.Instructions.InstEmitAluHelper;
|
||||
using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
|
||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Instructions
|
||||
{
|
||||
static partial class InstEmit
|
||||
{
|
||||
public static void Pset(EmitterContext context)
|
||||
{
|
||||
InstPset op = context.GetOp<InstPset>();
|
||||
|
||||
Operand srcA = context.BitwiseNot(Register(op.Src2Pred, RegisterType.Predicate), op.Src2PredInv);
|
||||
Operand srcB = context.BitwiseNot(Register(op.Src1Pred, RegisterType.Predicate), op.Src1PredInv);
|
||||
Operand srcC = context.BitwiseNot(Register(op.SrcPred, RegisterType.Predicate), op.SrcPredInv);
|
||||
|
||||
Operand res = GetPredLogicalOp(context, op.BoolOpAB, srcA, srcB);
|
||||
res = GetPredLogicalOp(context, op.BoolOpC, res, srcC);
|
||||
|
||||
Operand dest = GetDest(op.Dest);
|
||||
|
||||
if (op.BVal)
|
||||
{
|
||||
context.Copy(dest, context.ConditionalSelect(res, ConstF(1), Const(0)));
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Copy(dest, res);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Psetp(EmitterContext context)
|
||||
{
|
||||
InstPsetp op = context.GetOp<InstPsetp>();
|
||||
|
||||
Operand srcA = context.BitwiseNot(Register(op.Src2Pred, RegisterType.Predicate), op.Src2PredInv);
|
||||
Operand srcB = context.BitwiseNot(Register(op.Src1Pred, RegisterType.Predicate), op.Src1PredInv);
|
||||
|
||||
Operand p0Res = GetPredLogicalOp(context, op.BoolOpAB, srcA, srcB);
|
||||
Operand p1Res = context.BitwiseNot(p0Res);
|
||||
Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
|
||||
|
||||
p0Res = GetPredLogicalOp(context, op.BoolOpC, p0Res, srcPred);
|
||||
p1Res = GetPredLogicalOp(context, op.BoolOpC, p1Res, srcPred);
|
||||
|
||||
context.Copy(Register(op.DestPred, RegisterType.Predicate), p0Res);
|
||||
context.Copy(Register(op.DestPredInv, RegisterType.Predicate), p1Res);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
using Ryujinx.Graphics.Shader.Decoders;
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
|
||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Instructions
|
||||
{
|
||||
static partial class InstEmit
|
||||
{
|
||||
public static void Fswzadd(EmitterContext context)
|
||||
{
|
||||
InstFswzadd op = context.GetOp<InstFswzadd>();
|
||||
|
||||
Operand srcA = GetSrcReg(context, op.SrcA);
|
||||
Operand srcB = GetSrcReg(context, op.SrcB);
|
||||
Operand dest = GetDest(op.Dest);
|
||||
|
||||
context.Copy(dest, context.FPSwizzleAdd(srcA, srcB, op.PnWord));
|
||||
|
||||
InstEmitAluHelper.SetFPZnFlags(context, dest, op.WriteCC);
|
||||
}
|
||||
|
||||
public static void Shfl(EmitterContext context)
|
||||
{
|
||||
InstShfl op = context.GetOp<InstShfl>();
|
||||
|
||||
Operand pred = Register(op.DestPred, RegisterType.Predicate);
|
||||
|
||||
Operand srcA = GetSrcReg(context, op.SrcA);
|
||||
|
||||
Operand srcB = op.BFixShfl ? Const(op.SrcBImm) : GetSrcReg(context, op.SrcB);
|
||||
Operand srcC = op.CFixShfl ? Const(op.SrcCImm) : GetSrcReg(context, op.SrcC);
|
||||
|
||||
(Operand res, Operand valid) = op.ShflMode switch
|
||||
{
|
||||
ShflMode.Idx => context.Shuffle(srcA, srcB, srcC),
|
||||
ShflMode.Up => context.ShuffleUp(srcA, srcB, srcC),
|
||||
ShflMode.Down => context.ShuffleDown(srcA, srcB, srcC),
|
||||
ShflMode.Bfly => context.ShuffleXor(srcA, srcB, srcC),
|
||||
_ => (null, null)
|
||||
};
|
||||
|
||||
context.Copy(GetDest(op.Dest), res);
|
||||
context.Copy(pred, valid);
|
||||
}
|
||||
|
||||
public static void Vote(EmitterContext context)
|
||||
{
|
||||
InstVote op = context.GetOp<InstVote>();
|
||||
|
||||
Operand pred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
|
||||
Operand res = null;
|
||||
|
||||
switch (op.VoteMode)
|
||||
{
|
||||
case VoteMode.All:
|
||||
res = context.VoteAll(pred);
|
||||
break;
|
||||
case VoteMode.Any:
|
||||
res = context.VoteAny(pred);
|
||||
break;
|
||||
case VoteMode.Eq:
|
||||
res = context.VoteAllEqual(pred);
|
||||
break;
|
||||
}
|
||||
|
||||
if (res != null)
|
||||
{
|
||||
context.Copy(Register(op.VpDest, RegisterType.Predicate), res);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Config.GpuAccessor.Log($"Invalid vote operation: {op.VoteMode}.");
|
||||
}
|
||||
|
||||
if (op.Dest != RegisterConsts.RegisterZeroIndex)
|
||||
{
|
||||
context.Copy(GetDest(op.Dest), context.Ballot(pred));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
{
|
||||
enum OperandType
|
||||
{
|
||||
Argument,
|
||||
Attribute,
|
||||
AttributePerPatch,
|
||||
Constant,
|
||||
ConstantBuffer,
|
||||
Label,
|
||||
LocalVariable,
|
||||
Register,
|
||||
Undefined
|
||||
}
|
||||
|
||||
static class OperandTypeExtensions
|
||||
{
|
||||
public static bool IsAttribute(this OperandType type)
|
||||
{
|
||||
return type == OperandType.Attribute || type == OperandType.AttributePerPatch;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||
{
|
||||
[Flags]
|
||||
enum TextureFlags
|
||||
{
|
||||
None = 0,
|
||||
Bindless = 1 << 0,
|
||||
Gather = 1 << 1,
|
||||
Derivatives = 1 << 2,
|
||||
IntCoords = 1 << 3,
|
||||
LodBias = 1 << 4,
|
||||
LodLevel = 1 << 5,
|
||||
Offset = 1 << 6,
|
||||
Offsets = 1 << 7,
|
||||
Coherent = 1 << 8,
|
||||
|
||||
AtomicMask = 15 << 16,
|
||||
|
||||
Add = 0 << 16,
|
||||
Minimum = 1 << 16,
|
||||
Maximum = 2 << 16,
|
||||
Increment = 3 << 16,
|
||||
Decrement = 4 << 16,
|
||||
BitwiseAnd = 5 << 16,
|
||||
BitwiseOr = 6 << 16,
|
||||
BitwiseXor = 7 << 16,
|
||||
Swap = 8 << 16,
|
||||
CAS = 9 << 16
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Shader
|
||||
{
|
||||
enum OutputTopology
|
||||
{
|
||||
PointList = 1,
|
||||
LineStrip = 6,
|
||||
TriangleStrip = 7
|
||||
}
|
||||
|
||||
static class OutputTopologyExtensions
|
||||
{
|
||||
public static string ToGlslString(this OutputTopology topology)
|
||||
{
|
||||
switch (topology)
|
||||
{
|
||||
case OutputTopology.LineStrip: return "line_strip";
|
||||
case OutputTopology.PointList: return "points";
|
||||
case OutputTopology.TriangleStrip: return "triangle_strip";
|
||||
}
|
||||
|
||||
return "points";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="CodeGen\Glsl\HelperFunctions\TexelFetchScale_vp.glsl" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||
<ProjectReference Include="..\Spv.Generator\Spv.Generator.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\AtomicMinMaxS32Shared.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\AtomicMinMaxS32Storage.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\MultiplyHighS32.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\MultiplyHighU32.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\Shuffle.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\ShuffleDown.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\ShuffleUp.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\ShuffleXor.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\StoreSharedSmallInt.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\StoreStorageSmallInt.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\SwizzleAdd.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\TexelFetchScale_vp.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\TexelFetchScale_fp.glsl" />
|
||||
<EmbeddedResource Include="CodeGen\Glsl\HelperFunctions\TexelFetchScale_cp.glsl" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,8 +0,0 @@
|
||||
namespace Ryujinx.Graphics.Shader
|
||||
{
|
||||
public enum ShaderIdentification
|
||||
{
|
||||
None,
|
||||
GeometryLayerPassthrough
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
{
|
||||
[Flags]
|
||||
enum HelperFunctionsMask
|
||||
{
|
||||
AtomicMinMaxS32Shared = 1 << 0,
|
||||
AtomicMinMaxS32Storage = 1 << 1,
|
||||
MultiplyHighS32 = 1 << 2,
|
||||
MultiplyHighU32 = 1 << 3,
|
||||
Shuffle = 1 << 4,
|
||||
ShuffleDown = 1 << 5,
|
||||
ShuffleUp = 1 << 6,
|
||||
ShuffleXor = 1 << 7,
|
||||
StoreSharedSmallInt = 1 << 8,
|
||||
StoreStorageSmallInt = 1 << 9,
|
||||
SwizzleAdd = 1 << 10,
|
||||
FSI = 1 << 11
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user