Compare commits
292 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 | |||
4dd77316f7 | |||
3f98369a17 | |||
c26aeefe03 | |||
666e05f5cb | |||
8d9d508dc7 | |||
e27f5522e2 | |||
add2a9d151 | |||
9e50dd99d7 | |||
0dec91bb42 | |||
d9b63353b0 | |||
eabd0ec93f | |||
138d5dc64a | |||
3e68a87d63 | |||
69b6ef7a4a | |||
40e87c634e | |||
79d1c190db | |||
2bc88467eb | |||
baf8752e74 | |||
d5e4378aea | |||
6dbcdfea47 | |||
c5258cf082 | |||
5c89e22bb9 | |||
11ecff2ff0 | |||
4c3f09644a | |||
e187a8870a | |||
a64fee29dc | |||
9ef94c8292 | |||
915d6d044c | |||
a4780ab33b | |||
a947a45d81 | |||
9db73f74cf | |||
a1efd87c45 | |||
49be977588 | |||
c95be55091 | |||
63dedbda86 | |||
c532118d94 | |||
52d6f2e656 | |||
c9bc4eaf58 | |||
3249f8ff41 | |||
1b41b285ac | |||
f5a6f45b27 | |||
210557951b | |||
4c2d9ff3ff | |||
8198b99935 | |||
460f96967d | |||
7ca779a26d | |||
b5032b3c91 | |||
f0a3dff136 | |||
f659dcb9d8 | |||
a34fb0e939 | |||
21ce8a9b80 | |||
9ecbee8032 | |||
80519af67d | |||
26e30faff3 | |||
0992310b76 | |||
009c1101d2 | |||
ba95ee54ab | |||
4ce4299ca2 |
@ -63,6 +63,10 @@ dotnet_code_quality_unused_parameters = all:suggestion
|
||||
|
||||
#### C# Coding Conventions ####
|
||||
|
||||
# Namespace preferences
|
||||
csharp_style_namespace_declarations = block_scoped:warning
|
||||
resharper_csharp_namespace_body = block_scoped
|
||||
|
||||
# var preferences
|
||||
csharp_style_var_elsewhere = false:silent
|
||||
csharp_style_var_for_built_in_types = false:silent
|
||||
|
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
|
8
.github/assign/audio.yml
vendored
Normal file
8
.github/assign/audio.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
addReviewers: true
|
||||
|
||||
reviewers:
|
||||
- marysaka
|
||||
|
||||
filterLabels:
|
||||
include:
|
||||
- audio
|
11
.github/assign/cpu.yml
vendored
Normal file
11
.github/assign/cpu.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
addReviewers: true
|
||||
|
||||
reviewers:
|
||||
- gdkchan
|
||||
- riperiperi
|
||||
- marysaka
|
||||
- LDj3SNuD
|
||||
|
||||
filterLabels:
|
||||
include:
|
||||
- cpu
|
4
.github/assign/global.yml
vendored
Normal file
4
.github/assign/global.yml
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
addReviewers: true
|
||||
|
||||
reviewers:
|
||||
- Ryujinx/developers
|
10
.github/assign/gpu.yml
vendored
Normal file
10
.github/assign/gpu.yml
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
addReviewers: true
|
||||
|
||||
reviewers:
|
||||
- gdkchan
|
||||
- riperiperi
|
||||
- marysaka
|
||||
|
||||
filterLabels:
|
||||
include:
|
||||
- gpu
|
11
.github/assign/gui.yml
vendored
Normal file
11
.github/assign/gui.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
addReviewers: true
|
||||
|
||||
reviewers:
|
||||
- Ack77
|
||||
- emmauss
|
||||
- TSRBerry
|
||||
- marysaka
|
||||
|
||||
filterLabels:
|
||||
include:
|
||||
- gui
|
11
.github/assign/horizon.yml
vendored
Normal file
11
.github/assign/horizon.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
addReviewers: true
|
||||
|
||||
reviewers:
|
||||
- gdkchan
|
||||
- Ack77
|
||||
- marysaka
|
||||
- TSRBerry
|
||||
|
||||
filterLabels:
|
||||
include:
|
||||
- horizon
|
9
.github/assign/infra.yml
vendored
Normal file
9
.github/assign/infra.yml
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
addReviewers: true
|
||||
|
||||
reviewers:
|
||||
- marysaka
|
||||
- TSRBerry
|
||||
|
||||
filterLabels:
|
||||
include:
|
||||
- infra
|
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'
|
114
.github/workflows/build.yml
vendored
114
.github/workflows/build.yml
vendored
@ -3,25 +3,29 @@ 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/**'
|
||||
- '.github/**'
|
||||
- '*.yml'
|
||||
- '*.json'
|
||||
- '*.config'
|
||||
- 'README.md'
|
||||
|
||||
concurrency:
|
||||
group: pr-checks-${{ github.event.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
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 +37,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 +47,107 @@ jobs:
|
||||
RELEASE_ZIP_OS_NAME: win_x64
|
||||
|
||||
fail-fast: false
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||
RYUJINX_BASE_VERSION: "1.1.0"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
global-json-file: global.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 }}"
|
||||
|
||||
- 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'
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
|
||||
build_macos:
|
||||
name: macOS Universal (${{ matrix.configuration }})
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
strategy:
|
||||
matrix:
|
||||
configuration: [ Debug, Release ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 14
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 14
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
|
||||
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
|
||||
rm apple-codesign.tar.gz
|
||||
mv rcodesign $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get git short hash
|
||||
id: git_short_hash
|
||||
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Publish macOS
|
||||
run: |
|
||||
./distribution/macos/create_macos_build.sh . publish_tmp publish_ava ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
|
||||
|
||||
- name: Upload Ryujinx.Ava artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
||||
path: "publish_ava/*.tar.gz"
|
||||
if: github.event_name == 'pull_request'
|
5
.github/workflows/flatpak.yml
vendored
5
.github/workflows/flatpak.yml
vendored
@ -12,13 +12,14 @@ 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 }}"
|
||||
|
||||
@ -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
|
3
.github/workflows/nightly_pr_comment.yml
vendored
3
.github/workflows/nightly_pr_comment.yml
vendored
@ -7,6 +7,7 @@ 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 +66,4 @@ jobs:
|
||||
} else {
|
||||
core.info(`Creating a comment`);
|
||||
await github.rest.issues.createComment({repo, owner, issue_number, body});
|
||||
}
|
||||
}
|
54
.github/workflows/pr_triage.yml
vendored
Normal file
54
.github/workflows/pr_triage.yml
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
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:
|
||||
- name: Update labels based on changes
|
||||
uses: actions/labeler@v4
|
||||
with:
|
||||
sync-labels: true
|
||||
dot: true
|
||||
|
||||
- name: Auto Assign [Audio]
|
||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
||||
with:
|
||||
configuration-path: '.github/assign/audio.yml'
|
||||
|
||||
- name: Auto Assign [CPU]
|
||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
||||
with:
|
||||
configuration-path: '.github/assign/cpu.yml'
|
||||
|
||||
- name: Auto Assign [GPU]
|
||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
||||
with:
|
||||
configuration-path: '.github/assign/gpu.yml'
|
||||
|
||||
- name: Auto Assign [GUI]
|
||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
||||
with:
|
||||
configuration-path: '.github/assign/gui.yml'
|
||||
|
||||
- name: Auto Assign [Horizon]
|
||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
||||
with:
|
||||
configuration-path: '.github/assign/horizon.yml'
|
||||
|
||||
- name: Auto Assign [Infra]
|
||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
||||
with:
|
||||
configuration-path: '.github/assign/infra.yml'
|
||||
|
||||
- name: Auto Assign [Global]
|
||||
uses: kentaro-m/auto-assign-action@v1.2.5
|
||||
with:
|
||||
configuration-path: '.github/assign/global.yml'
|
175
.github/workflows/release.yml
vendored
175
.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,79 +23,108 @@ env:
|
||||
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master"
|
||||
|
||||
jobs:
|
||||
tag:
|
||||
name: Create tag
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Create tag
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
github.rest.git.createRef({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: 'refs/tags/${{ steps.version_info.outputs.build_version }}',
|
||||
sha: context.sha
|
||||
})
|
||||
|
||||
release:
|
||||
runs-on: windows-latest
|
||||
name: Release ${{ matrix.OS_NAME }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest ]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
OS_NAME: Linux x64
|
||||
DOTNET_RUNTIME_IDENTIFIER: linux-x64
|
||||
RELEASE_ZIP_OS_NAME: linux_x64
|
||||
|
||||
- os: windows-latest
|
||||
OS_NAME: Windows x64
|
||||
DOTNET_RUNTIME_IDENTIFIER: win10-x64
|
||||
RELEASE_ZIP_OS_NAME: win_x64
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Configure for release
|
||||
run: |
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' Ryujinx.Common/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
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
|
||||
- name: Create output dir
|
||||
run: "mkdir release_output"
|
||||
- name: Publish Windows
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
dotnet publish -c Release -r win10-x64 -o ./publish_windows/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx --self-contained 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
|
||||
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_gtk/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true
|
||||
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true
|
||||
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Ava --self-contained true
|
||||
|
||||
- name: Packing Windows builds
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: |
|
||||
pushd publish_windows
|
||||
pushd publish_gtk
|
||||
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
|
||||
pushd publish_windows_sdl2_headless
|
||||
pushd publish_sdl2_headless
|
||||
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
|
||||
pushd publish_windows_ava
|
||||
pushd publish_ava
|
||||
7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Publish Linux
|
||||
run: |
|
||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded Ryujinx --self-contained 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
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
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
|
||||
pushd publish_gtk
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
popd
|
||||
|
||||
pushd publish_linux_sdl2_headless
|
||||
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
|
||||
pushd publish_sdl2_headless
|
||||
chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2
|
||||
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||
popd
|
||||
|
||||
pushd publish_linux_ava
|
||||
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
|
||||
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
|
||||
|
||||
@ -104,9 +134,70 @@ jobs:
|
||||
name: ${{ steps.version_info.outputs.build_version }}
|
||||
artifacts: "release_output/*.tar.gz,release_output/*.zip"
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: "For more informations about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
|
||||
body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
|
||||
omitBodyDuringUpdate: true
|
||||
allowUpdates: true
|
||||
replacesArtifacts: true
|
||||
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
|
||||
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
macos_release:
|
||||
name: Release MacOS universal
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 14
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 14
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
|
||||
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
|
||||
rm apple-codesign.tar.gz
|
||||
mv rcodesign $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Configure for release
|
||||
run: |
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
shell: bash
|
||||
|
||||
- name: Publish macOS
|
||||
run: |
|
||||
./distribution/macos/create_macos_build.sh . publish_tmp publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release
|
||||
|
||||
- name: Pushing new release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: ${{ steps.version_info.outputs.build_version }}
|
||||
artifacts: "publish_ava/*.tar.gz"
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
|
||||
omitBodyDuringUpdate: true
|
||||
allowUpdates: true
|
||||
removeArtifacts: true
|
||||
replacesArtifacts: true
|
||||
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
|
||||
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
|
||||
@ -117,4 +208,4 @@ jobs:
|
||||
needs: release
|
||||
with:
|
||||
ryujinx_version: "1.1.${{ github.run_number }}"
|
||||
secrets: inherit
|
||||
secrets: inherit
|
@ -1,6 +0,0 @@
|
||||
namespace ARMeilleure.Decoders;
|
||||
|
||||
interface IOpCode32Exception
|
||||
{
|
||||
int Id { get; }
|
||||
}
|
@ -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,267 +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.GetTpidrroEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr32))); // A32 only.
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl032))); // A32 only.
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032))); // A32 only.
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SupervisorCall)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Undefined)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128)));
|
||||
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingSigns)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingZeros)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32b)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cb)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32ch)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cw)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cx)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32h)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.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)));
|
||||
}
|
||||
}
|
||||
}
|
@ -3,17 +3,17 @@
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Avalonia" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia" Version="0.10.21" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="0.10.21" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="0.10.21" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="0.10.21" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="0.10.21" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="0.10.18" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="Concentus" Version="1.1.7" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.1.3.18" />
|
||||
<PackageVersion Include="DynamicData" Version="7.12.11" />
|
||||
<PackageVersion Include="DynamicData" Version="7.14.2" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="1.4.5" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
|
||||
@ -21,7 +21,7 @@
|
||||
<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.NET.Test.Sdk" Version="17.6.3" />
|
||||
<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.1-build23" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.26.3-build25" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||
@ -44,10 +44,10 @@
|
||||
<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.27.0" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.31.0" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
||||
<PackageVersion Include="System.Management" Version="7.0.0" />
|
||||
<PackageVersion Include="System.Management" Version="7.0.2" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.5.1" />
|
||||
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.6.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
@ -40,7 +40,7 @@
|
||||
|
||||
## Compatibility
|
||||
|
||||
As of November 2022, Ryujinx has been tested on approximately 3,800 titles; over 3,600 boot past menus and into gameplay, with roughly 3,200 of those being considered playable.
|
||||
As of April 2023, Ryujinx has been tested on approximately 4,050 titles; over 4,000 boot past menus and into gameplay, with roughly 3,400 of those being considered playable.
|
||||
You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
||||
|
||||
## Usage
|
||||
|
@ -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,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,32 +0,0 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.UI.Controls.InputDialog"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Focusable="True">
|
||||
<Grid
|
||||
Margin="5,10,5,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock HorizontalAlignment="Center" Text="{Binding Message}" />
|
||||
<TextBox
|
||||
Grid.Row="1"
|
||||
Width="300"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Center"
|
||||
MaxLength="{Binding MaxLength}"
|
||||
Text="{Binding Input, Mode=TwoWay}" />
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Margin="5,5,5,10"
|
||||
HorizontalAlignment="Center"
|
||||
Text="{Binding SubMessage}" />
|
||||
</Grid>
|
||||
</UserControl>
|
@ -1,57 +0,0 @@
|
||||
using Avalonia.Controls;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.Models;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Controls
|
||||
{
|
||||
public partial class InputDialog : UserControl
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public string Input { get; set; }
|
||||
public string SubMessage { get; set; }
|
||||
|
||||
public uint MaxLength { get; }
|
||||
|
||||
public InputDialog(string message, string input = "", string subMessage = "", uint maxLength = int.MaxValue)
|
||||
{
|
||||
Message = message;
|
||||
Input = input;
|
||||
SubMessage = subMessage;
|
||||
MaxLength = maxLength;
|
||||
|
||||
DataContext = this;
|
||||
}
|
||||
|
||||
public InputDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public static async Task<(UserResult Result, string Input)> ShowInputDialog(string title, string message,
|
||||
string input = "", string subMessage = "", uint maxLength = int.MaxValue)
|
||||
{
|
||||
UserResult result = UserResult.Cancel;
|
||||
|
||||
InputDialog content = new InputDialog(message, input, subMessage, maxLength);
|
||||
ContentDialog contentDialog = new ContentDialog
|
||||
{
|
||||
Title = title,
|
||||
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
SecondaryButtonText = "",
|
||||
CloseButtonText = LocaleManager.Instance[LocaleKeys.InputDialogCancel],
|
||||
Content = content,
|
||||
PrimaryButtonCommand = MiniCommand.Create(() =>
|
||||
{
|
||||
result = UserResult.Ok;
|
||||
input = content.Input;
|
||||
})
|
||||
};
|
||||
await contentDialog.ShowAsync();
|
||||
|
||||
return (result, input);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Models
|
||||
{
|
||||
public class Amiibo
|
||||
{
|
||||
public struct AmiiboJson
|
||||
{
|
||||
[JsonPropertyName("amiibo")] public List<AmiiboApi> Amiibo { get; set; }
|
||||
[JsonPropertyName("lastUpdated")] public DateTime LastUpdated { get; set; }
|
||||
}
|
||||
|
||||
public struct AmiiboApi
|
||||
{
|
||||
[JsonPropertyName("name")] public string Name { get; set; }
|
||||
[JsonPropertyName("head")] public string Head { get; set; }
|
||||
[JsonPropertyName("tail")] public string Tail { get; set; }
|
||||
[JsonPropertyName("image")] public string Image { get; set; }
|
||||
[JsonPropertyName("amiiboSeries")] public string AmiiboSeries { get; set; }
|
||||
[JsonPropertyName("character")] public string Character { get; set; }
|
||||
[JsonPropertyName("gameSeries")] public string GameSeries { get; set; }
|
||||
[JsonPropertyName("type")] public string Type { get; set; }
|
||||
|
||||
[JsonPropertyName("release")] public Dictionary<string, string> Release { get; set; }
|
||||
|
||||
[JsonPropertyName("gamesSwitch")] public List<AmiiboApiGamesSwitch> GamesSwitch { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
public string GetId()
|
||||
{
|
||||
return Head + Tail;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is AmiiboApi amiibo)
|
||||
{
|
||||
return amiibo.Head + amiibo.Tail == Head + Tail;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public class AmiiboApiGamesSwitch
|
||||
{
|
||||
[JsonPropertyName("amiiboUsage")] public List<AmiiboApiUsage> AmiiboUsage { get; set; }
|
||||
|
||||
[JsonPropertyName("gameID")] public List<string> GameId { get; set; }
|
||||
|
||||
[JsonPropertyName("gameName")] public string GameName { get; set; }
|
||||
}
|
||||
|
||||
public class AmiiboApiUsage
|
||||
{
|
||||
[JsonPropertyName("Usage")] public string Usage { get; set; }
|
||||
|
||||
[JsonPropertyName("write")] public bool Write { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
@ -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,250 +0,0 @@
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Threading;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.Ns;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.Models;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Path = System.IO.Path;
|
||||
using SpanHelpers = LibHac.Common.SpanHelpers;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels;
|
||||
|
||||
public class TitleUpdateViewModel : BaseModel
|
||||
{
|
||||
public TitleUpdateMetadata _titleUpdateWindowData;
|
||||
public readonly string _titleUpdateJsonPath;
|
||||
private VirtualFileSystem _virtualFileSystem { get; }
|
||||
private ulong _titleId { get; }
|
||||
private string _titleName { get; }
|
||||
|
||||
private AvaloniaList<TitleUpdateModel> _titleUpdates = new();
|
||||
private AvaloniaList<object> _views = new();
|
||||
private object _selectedUpdate;
|
||||
|
||||
public AvaloniaList<TitleUpdateModel> TitleUpdates
|
||||
{
|
||||
get => _titleUpdates;
|
||||
set
|
||||
{
|
||||
_titleUpdates = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public AvaloniaList<object> Views
|
||||
{
|
||||
get => _views;
|
||||
set
|
||||
{
|
||||
_views = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public object SelectedUpdate
|
||||
{
|
||||
get => _selectedUpdate;
|
||||
set
|
||||
{
|
||||
_selectedUpdate = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
|
||||
{
|
||||
_virtualFileSystem = virtualFileSystem;
|
||||
|
||||
_titleId = titleId;
|
||||
_titleName = titleName;
|
||||
|
||||
_titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json");
|
||||
|
||||
try
|
||||
{
|
||||
_titleUpdateWindowData = JsonHelper.DeserializeFromFile<TitleUpdateMetadata>(_titleUpdateJsonPath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {_titleId} at {_titleUpdateJsonPath}");
|
||||
|
||||
_titleUpdateWindowData = new TitleUpdateMetadata
|
||||
{
|
||||
Selected = "",
|
||||
Paths = new List<string>()
|
||||
};
|
||||
|
||||
Save();
|
||||
}
|
||||
|
||||
LoadUpdates();
|
||||
}
|
||||
|
||||
private void LoadUpdates()
|
||||
{
|
||||
foreach (string path in _titleUpdateWindowData.Paths)
|
||||
{
|
||||
AddUpdate(path);
|
||||
}
|
||||
|
||||
TitleUpdateModel selected = TitleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected, null);
|
||||
|
||||
SelectedUpdate = selected;
|
||||
|
||||
// NOTE: Save the list again to remove leftovers.
|
||||
Save();
|
||||
|
||||
SortUpdates();
|
||||
}
|
||||
|
||||
public void SortUpdates()
|
||||
{
|
||||
var list = TitleUpdates.ToList();
|
||||
|
||||
list.Sort((first, second) =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(first.Control.DisplayVersionString.ToString()))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString()))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return Version.Parse(first.Control.DisplayVersionString.ToString()).CompareTo(Version.Parse(second.Control.DisplayVersionString.ToString())) * -1;
|
||||
});
|
||||
|
||||
Views.Clear();
|
||||
Views.Add(new BaseModel());
|
||||
Views.AddRange(list);
|
||||
|
||||
if (SelectedUpdate == null)
|
||||
{
|
||||
SelectedUpdate = Views[0];
|
||||
}
|
||||
else if (!TitleUpdates.Contains(SelectedUpdate))
|
||||
{
|
||||
if (Views.Count > 1)
|
||||
{
|
||||
SelectedUpdate = Views[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedUpdate = Views[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddUpdate(string path)
|
||||
{
|
||||
if (File.Exists(path) && TitleUpdates.All(x => x.Path != path))
|
||||
{
|
||||
using FileStream file = new(path, FileMode.Open, FileAccess.Read);
|
||||
|
||||
try
|
||||
{
|
||||
(Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateDataFromPartition(_virtualFileSystem, new PartitionFileSystem(file.AsStorage()), _titleId.ToString("x16"), 0);
|
||||
|
||||
if (controlNca != null && patchNca != null)
|
||||
{
|
||||
ApplicationControlProperty controlData = new();
|
||||
|
||||
using UniqueRef<IFile> nacpFile = new();
|
||||
|
||||
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
|
||||
|
||||
TitleUpdates.Add(new TitleUpdateModel(controlData, path));
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage]);
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogLoadNcaErrorMessage, ex.Message, path));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveUpdate(TitleUpdateModel update)
|
||||
{
|
||||
TitleUpdates.Remove(update);
|
||||
|
||||
SortUpdates();
|
||||
}
|
||||
|
||||
public async void Add()
|
||||
{
|
||||
OpenFileDialog dialog = new()
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.SelectUpdateDialogTitle],
|
||||
AllowMultiple = true
|
||||
};
|
||||
|
||||
dialog.Filters.Add(new FileDialogFilter
|
||||
{
|
||||
Name = "NSP",
|
||||
Extensions = { "nsp" }
|
||||
});
|
||||
|
||||
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
string[] files = await dialog.ShowAsync(desktop.MainWindow);
|
||||
|
||||
if (files != null)
|
||||
{
|
||||
foreach (string file in files)
|
||||
{
|
||||
AddUpdate(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SortUpdates();
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
_titleUpdateWindowData.Paths.Clear();
|
||||
_titleUpdateWindowData.Selected = "";
|
||||
|
||||
foreach (TitleUpdateModel update in TitleUpdates)
|
||||
{
|
||||
_titleUpdateWindowData.Paths.Add(update.Path);
|
||||
|
||||
if (update == SelectedUpdate)
|
||||
{
|
||||
_titleUpdateWindowData.Selected = update.Path;
|
||||
}
|
||||
}
|
||||
|
||||
File.WriteAllBytes(_titleUpdateJsonPath, Encoding.UTF8.GetBytes(JsonHelper.Serialize(_titleUpdateWindowData, true)));
|
||||
}
|
||||
}
|
@ -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,12 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration
|
||||
{
|
||||
public enum AntiAliasing
|
||||
{
|
||||
None,
|
||||
Fxaa,
|
||||
SmaaLow,
|
||||
SmaaMedium,
|
||||
SmaaHigh,
|
||||
SmaaUltra
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration
|
||||
{
|
||||
public enum BackendThreading
|
||||
{
|
||||
Auto,
|
||||
Off,
|
||||
On
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration
|
||||
{
|
||||
public enum GraphicsBackend
|
||||
{
|
||||
Vulkan,
|
||||
OpenGl
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
||||
{
|
||||
public enum MotionInputBackendType : byte
|
||||
{
|
||||
Invalid,
|
||||
GamepadDriver,
|
||||
CemuHook
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration.Hid.Controller
|
||||
{
|
||||
public enum StickInputId : byte
|
||||
{
|
||||
Unbound,
|
||||
Left,
|
||||
Right,
|
||||
|
||||
Count
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Common.Configuration.Hid
|
||||
{
|
||||
[Flags]
|
||||
// This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical
|
||||
public enum ControllerType : int
|
||||
{
|
||||
None,
|
||||
ProController = 1 << 0,
|
||||
Handheld = 1 << 1,
|
||||
JoyconPair = 1 << 2,
|
||||
JoyconLeft = 1 << 3,
|
||||
JoyconRight = 1 << 4,
|
||||
Invalid = 1 << 5,
|
||||
Pokeball = 1 << 6,
|
||||
SystemExternal = 1 << 29,
|
||||
System = 1 << 30
|
||||
}
|
||||
}
|
@ -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,9 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration.Hid
|
||||
{
|
||||
public enum InputBackendType
|
||||
{
|
||||
Invalid,
|
||||
WindowKeyboard,
|
||||
GamepadSDL2,
|
||||
}
|
||||
}
|
@ -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,18 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration.Hid
|
||||
{
|
||||
// This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical
|
||||
public enum PlayerIndex : int
|
||||
{
|
||||
Player1 = 0,
|
||||
Player2 = 1,
|
||||
Player3 = 2,
|
||||
Player4 = 3,
|
||||
Player5 = 4,
|
||||
Player6 = 5,
|
||||
Player7 = 6,
|
||||
Player8 = 7,
|
||||
Handheld = 8,
|
||||
Unknown = 9,
|
||||
Auto = 10 // Shouldn't be used directly
|
||||
}
|
||||
}
|
@ -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,9 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration
|
||||
{
|
||||
public enum MemoryManagerMode : byte
|
||||
{
|
||||
SoftwarePageTable,
|
||||
HostMapped,
|
||||
HostMappedUnsafe
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace Ryujinx.Common.Configuration
|
||||
{
|
||||
public enum ScalingFilter
|
||||
{
|
||||
Bilinear,
|
||||
Nearest,
|
||||
Fsr
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Common.Logging
|
||||
{
|
||||
internal class DefaultLogFormatter : ILogFormatter
|
||||
{
|
||||
private static readonly ObjectPool<StringBuilder> _stringBuilderPool = SharedPools.Default<StringBuilder>();
|
||||
|
||||
public string Format(LogEventArgs args)
|
||||
{
|
||||
StringBuilder sb = _stringBuilderPool.Allocate();
|
||||
|
||||
try
|
||||
{
|
||||
sb.Clear();
|
||||
|
||||
sb.AppendFormat(@"{0:hh\:mm\:ss\.fff}", args.Time);
|
||||
sb.Append($" |{args.Level.ToString()[0]}| ");
|
||||
|
||||
if (args.ThreadName != null)
|
||||
{
|
||||
sb.Append(args.ThreadName);
|
||||
sb.Append(' ');
|
||||
}
|
||||
|
||||
sb.Append(args.Message);
|
||||
|
||||
if (args.Data != null)
|
||||
{
|
||||
PropertyInfo[] props = args.Data.GetType().GetProperties();
|
||||
|
||||
sb.Append(" {");
|
||||
|
||||
foreach (var prop in props)
|
||||
{
|
||||
sb.Append(prop.Name);
|
||||
sb.Append(": ");
|
||||
|
||||
if (typeof(Array).IsAssignableFrom(prop.PropertyType))
|
||||
{
|
||||
Array array = (Array)prop.GetValue(args.Data);
|
||||
foreach (var item in array)
|
||||
{
|
||||
sb.Append(item.ToString());
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
if (array.Length > 0)
|
||||
{
|
||||
sb.Remove(sb.Length - 2, 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(prop.GetValue(args.Data));
|
||||
}
|
||||
|
||||
sb.Append(" ; ");
|
||||
}
|
||||
|
||||
// We remove the final ';' from the string
|
||||
if (props.Length > 0)
|
||||
{
|
||||
sb.Remove(sb.Length - 3, 3);
|
||||
}
|
||||
|
||||
sb.Append('}');
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_stringBuilderPool.Release(sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Common.Logging
|
||||
{
|
||||
public class LogEventArgs : EventArgs
|
||||
{
|
||||
public readonly LogLevel Level;
|
||||
public readonly TimeSpan Time;
|
||||
public readonly string ThreadName;
|
||||
|
||||
public readonly string Message;
|
||||
public readonly object Data;
|
||||
|
||||
public LogEventArgs(LogLevel level, TimeSpan time, string threadName, string message)
|
||||
{
|
||||
Level = level;
|
||||
Time = time;
|
||||
ThreadName = threadName;
|
||||
Message = message;
|
||||
}
|
||||
|
||||
public LogEventArgs(LogLevel level, TimeSpan time, string threadName, string message, object data)
|
||||
{
|
||||
Level = level;
|
||||
Time = time;
|
||||
ThreadName = threadName;
|
||||
Message = message;
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Common.Memory
|
||||
{
|
||||
public ref struct SpanReader
|
||||
{
|
||||
private ReadOnlySpan<byte> _input;
|
||||
|
||||
public int Length => _input.Length;
|
||||
|
||||
public SpanReader(ReadOnlySpan<byte> input)
|
||||
{
|
||||
_input = input;
|
||||
}
|
||||
|
||||
public T Read<T>() where T : unmanaged
|
||||
{
|
||||
T value = MemoryMarshal.Cast<byte, T>(_input)[0];
|
||||
|
||||
_input = _input.Slice(Unsafe.SizeOf<T>());
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> GetSpan(int size)
|
||||
{
|
||||
ReadOnlySpan<byte> data = _input.Slice(0, size);
|
||||
|
||||
_input = _input.Slice(size);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public T ReadAt<T>(int offset) where T : unmanaged
|
||||
{
|
||||
return MemoryMarshal.Cast<byte, T>(_input.Slice(offset))[0];
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> GetSpanAt(int offset, int size)
|
||||
{
|
||||
return _input.Slice(offset, size);
|
||||
}
|
||||
|
||||
public void Skip(int size)
|
||||
{
|
||||
_input = _input.Slice(size);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Common.SystemInterop
|
||||
{
|
||||
public partial class StdErrAdapter : IDisposable
|
||||
{
|
||||
private bool _disposable = false;
|
||||
private UnixStream _pipeReader;
|
||||
private UnixStream _pipeWriter;
|
||||
private Thread _worker;
|
||||
|
||||
public StdErrAdapter()
|
||||
{
|
||||
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
{
|
||||
RegisterPosix();
|
||||
}
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("linux")]
|
||||
[SupportedOSPlatform("macos")]
|
||||
private void RegisterPosix()
|
||||
{
|
||||
const int stdErrFileno = 2;
|
||||
|
||||
(int readFd, int writeFd) = MakePipe();
|
||||
dup2(writeFd, stdErrFileno);
|
||||
|
||||
_pipeReader = new UnixStream(readFd);
|
||||
_pipeWriter = new UnixStream(writeFd);
|
||||
|
||||
_worker = new Thread(EventWorker);
|
||||
_disposable = true;
|
||||
_worker.Start();
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("linux")]
|
||||
[SupportedOSPlatform("macos")]
|
||||
private void EventWorker()
|
||||
{
|
||||
TextReader reader = new StreamReader(_pipeReader);
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
Logger.Error?.PrintRawMsg(line);
|
||||
}
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (_disposable)
|
||||
{
|
||||
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||
{
|
||||
_pipeReader?.Close();
|
||||
_pipeWriter?.Close();
|
||||
}
|
||||
|
||||
_disposable = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int dup2(int fd, int fd2);
|
||||
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static unsafe partial int pipe(int* pipefd);
|
||||
|
||||
private static unsafe (int, int) MakePipe()
|
||||
{
|
||||
int *pipefd = stackalloc int[2];
|
||||
|
||||
if (pipe(pipefd) == 0)
|
||||
{
|
||||
return (pipefd[0], pipefd[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Ryujinx.Common.SystemInterop
|
||||
{
|
||||
[SupportedOSPlatform("linux")]
|
||||
[SupportedOSPlatform("macos")]
|
||||
public partial class UnixStream : Stream, IDisposable
|
||||
{
|
||||
private const int InvalidFd = -1;
|
||||
|
||||
private int _fd;
|
||||
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial long read(int fd, IntPtr buf, ulong count);
|
||||
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial long write(int fd, IntPtr buf, ulong count);
|
||||
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int close(int fd);
|
||||
|
||||
public UnixStream(int fd)
|
||||
{
|
||||
if (InvalidFd == fd)
|
||||
{
|
||||
throw new ArgumentException("Invalid file descriptor");
|
||||
}
|
||||
|
||||
_fd = fd;
|
||||
|
||||
CanRead = read(fd, IntPtr.Zero, 0) != -1;
|
||||
CanWrite = write(fd, IntPtr.Zero, 0) != -1;
|
||||
}
|
||||
|
||||
~UnixStream()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
public override bool CanRead { get; }
|
||||
public override bool CanWrite { get; }
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override long Length => throw new NotSupportedException();
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => throw new NotSupportedException();
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
}
|
||||
|
||||
public override unsafe int Read([In, Out] byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (offset < 0 || offset > (buffer.Length - count) || count < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (buffer.Length == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
long r = 0;
|
||||
fixed (byte* buf = &buffer[offset])
|
||||
{
|
||||
do
|
||||
{
|
||||
r = read(_fd, (IntPtr)buf, (ulong)count);
|
||||
} while (ShouldRetry(r));
|
||||
}
|
||||
|
||||
return (int)r;
|
||||
}
|
||||
|
||||
public override unsafe void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (offset < 0 || offset > (buffer.Length - count) || count < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (buffer.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fixed (byte* buf = &buffer[offset])
|
||||
{
|
||||
long r = 0;
|
||||
do {
|
||||
r = write(_fd, (IntPtr)buf, (ulong)count);
|
||||
} while (ShouldRetry(r));
|
||||
}
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
if (_fd == InvalidFd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Flush();
|
||||
|
||||
int r;
|
||||
do {
|
||||
r = close(_fd);
|
||||
} while (ShouldRetry(r));
|
||||
|
||||
_fd = InvalidFd;
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private bool ShouldRetry(long r)
|
||||
{
|
||||
if (r == -1)
|
||||
{
|
||||
const int eintr = 4;
|
||||
|
||||
int errno = Marshal.GetLastPInvokeError();
|
||||
|
||||
if (errno == eintr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new SystemException($"Operation failed with error 0x{errno:X}");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
public class JsonHelper
|
||||
{
|
||||
public static JsonNamingPolicy SnakeCase { get; }
|
||||
|
||||
private class SnakeCaseNamingPolicy : JsonNamingPolicy
|
||||
{
|
||||
public override string ConvertName(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < name.Length; i++)
|
||||
{
|
||||
char c = name[i];
|
||||
|
||||
if (char.IsUpper(c))
|
||||
{
|
||||
if (i == 0 || char.IsUpper(name[i - 1]))
|
||||
{
|
||||
builder.Append(char.ToLowerInvariant(c));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append("_");
|
||||
builder.Append(char.ToLowerInvariant(c));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
static JsonHelper()
|
||||
{
|
||||
SnakeCase = new SnakeCaseNamingPolicy();
|
||||
}
|
||||
|
||||
public static JsonSerializerOptions GetDefaultSerializerOptions(bool prettyPrint = false)
|
||||
{
|
||||
JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
DictionaryKeyPolicy = SnakeCase,
|
||||
PropertyNamingPolicy = SnakeCase,
|
||||
WriteIndented = prettyPrint,
|
||||
AllowTrailingCommas = true,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip
|
||||
};
|
||||
|
||||
options.Converters.Add(new JsonStringEnumConverter());
|
||||
options.Converters.Add(new JsonInputConfigConverter());
|
||||
options.Converters.Add(new JsonMotionConfigControllerConverter());
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(Stream stream)
|
||||
{
|
||||
using (BinaryReader reader = new BinaryReader(stream))
|
||||
{
|
||||
return JsonSerializer.Deserialize<T>(reader.ReadBytes((int)(stream.Length - stream.Position)), GetDefaultSerializerOptions());
|
||||
}
|
||||
}
|
||||
|
||||
public static T DeserializeFromFile<T>(string path)
|
||||
{
|
||||
return Deserialize<T>(File.ReadAllText(path));
|
||||
}
|
||||
|
||||
public static T Deserialize<T>(string json)
|
||||
{
|
||||
return JsonSerializer.Deserialize<T>(json, GetDefaultSerializerOptions());
|
||||
}
|
||||
|
||||
public static void Serialize<TValue>(Stream stream, TValue obj, bool prettyPrint = false)
|
||||
{
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
writer.Write(SerializeToUtf8Bytes(obj, prettyPrint));
|
||||
}
|
||||
}
|
||||
|
||||
public static string Serialize<TValue>(TValue obj, bool prettyPrint = false)
|
||||
{
|
||||
return JsonSerializer.Serialize(obj, GetDefaultSerializerOptions(prettyPrint));
|
||||
}
|
||||
|
||||
public static byte[] SerializeToUtf8Bytes<T>(T obj, bool prettyPrint = false)
|
||||
{
|
||||
return JsonSerializer.SerializeToUtf8Bytes(obj, GetDefaultSerializerOptions(prettyPrint));
|
||||
}
|
||||
}
|
||||
}
|
@ -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,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,41 +0,0 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public enum BlendFactor
|
||||
{
|
||||
Zero = 1,
|
||||
One,
|
||||
SrcColor,
|
||||
OneMinusSrcColor,
|
||||
SrcAlpha,
|
||||
OneMinusSrcAlpha,
|
||||
DstAlpha,
|
||||
OneMinusDstAlpha,
|
||||
DstColor,
|
||||
OneMinusDstColor,
|
||||
SrcAlphaSaturate,
|
||||
Src1Color = 0x10,
|
||||
OneMinusSrc1Color,
|
||||
Src1Alpha,
|
||||
OneMinusSrc1Alpha,
|
||||
ConstantColor = 0xc001,
|
||||
OneMinusConstantColor,
|
||||
ConstantAlpha,
|
||||
OneMinusConstantAlpha,
|
||||
|
||||
ZeroGl = 0x4000,
|
||||
OneGl = 0x4001,
|
||||
SrcColorGl = 0x4300,
|
||||
OneMinusSrcColorGl = 0x4301,
|
||||
SrcAlphaGl = 0x4302,
|
||||
OneMinusSrcAlphaGl = 0x4303,
|
||||
DstAlphaGl = 0x4304,
|
||||
OneMinusDstAlphaGl = 0x4305,
|
||||
DstColorGl = 0x4306,
|
||||
OneMinusDstColorGl = 0x4307,
|
||||
SrcAlphaSaturateGl = 0x4308,
|
||||
Src1ColorGl = 0xc900,
|
||||
OneMinusSrc1ColorGl = 0xc901,
|
||||
Src1AlphaGl = 0xc902,
|
||||
OneMinusSrc1AlphaGl = 0xc903
|
||||
}
|
||||
}
|
@ -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,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,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,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,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,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 = config.LastInPipeline ? context.Info.GetTransformFeedbackOutputComponents(attrOffset) : 1;
|
||||
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 (Config.LastInPipeline && 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,784 +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 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;
|
||||
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 (context.Config.LastInPipeline && 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);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user