Compare commits
46 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 |
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'
|
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@ -3,19 +3,13 @@ name: Build job
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs: {}
|
inputs: {}
|
||||||
#push:
|
|
||||||
# branches: [ master ]
|
|
||||||
# paths-ignore:
|
|
||||||
# - '.github/*'
|
|
||||||
# - '.github/ISSUE_TEMPLATE/**'
|
|
||||||
# - '*.yml'
|
|
||||||
# - 'README.md'
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '.github/*'
|
- '.github/**'
|
||||||
- '.github/ISSUE_TEMPLATE/**'
|
|
||||||
- '*.yml'
|
- '*.yml'
|
||||||
|
- '*.json'
|
||||||
|
- '*.config'
|
||||||
- 'README.md'
|
- 'README.md'
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
|
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'
|
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
@ -6,9 +6,10 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '.github/*'
|
- '.github/**'
|
||||||
- '.github/ISSUE_TEMPLATE/**'
|
|
||||||
- '*.yml'
|
- '*.yml'
|
||||||
|
- '*.json'
|
||||||
|
- '*.config'
|
||||||
- 'README.md'
|
- 'README.md'
|
||||||
|
|
||||||
concurrency: release
|
concurrency: release
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
||||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.31.0" />
|
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.31.0" />
|
||||||
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
||||||
<PackageVersion Include="System.Management" Version="7.0.1" />
|
<PackageVersion Include="System.Management" Version="7.0.2" />
|
||||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||||
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.6.1" />
|
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.6.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -39,10 +39,15 @@
|
|||||||
<key>CSResourcesFileMapped</key>
|
<key>CSResourcesFileMapped</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>Copyright © 2018 - 2022 Ryujinx Team and Contributors.</string>
|
<string>Copyright © 2018 - 2023 Ryujinx Team and Contributors.</string>
|
||||||
<key>LSApplicationCategoryType</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
<string>public.app-category.games</string>
|
<string>public.app-category.games</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>11.0</string>
|
<string>11.0</string>
|
||||||
|
<key>LSEnvironment</key>
|
||||||
|
<dict>
|
||||||
|
<key>COMPlus_DefaultStackSize</key>
|
||||||
|
<string>200000</string>
|
||||||
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -168,8 +168,6 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
|
|
||||||
Logger.StartPass(PassName.CodeGeneration);
|
Logger.StartPass(PassName.CodeGeneration);
|
||||||
|
|
||||||
//Console.Error.WriteLine(IRDumper.GetDump(cfg));
|
|
||||||
|
|
||||||
bool relocatable = (cctx.Options & CompilerOptions.Relocatable) != 0;
|
bool relocatable = (cctx.Options & CompilerOptions.Relocatable) != 0;
|
||||||
|
|
||||||
CodeGenContext context = new(allocResult, maxCallArgs, cfg.Blocks.Count, relocatable);
|
CodeGenContext context = new(allocResult, maxCallArgs, cfg.Blocks.Count, relocatable);
|
||||||
|
@ -179,6 +179,35 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
(uint)operation.GetSource(2).AsInt32());
|
(uint)operation.GetSource(2).AsInt32());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IntrinsicType.Vector128Unary:
|
||||||
|
GenerateVectorUnary(
|
||||||
|
context,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
info.Inst,
|
||||||
|
operation.Destination,
|
||||||
|
operation.GetSource(0));
|
||||||
|
break;
|
||||||
|
case IntrinsicType.Vector128Binary:
|
||||||
|
GenerateVectorBinary(
|
||||||
|
context,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
info.Inst,
|
||||||
|
operation.Destination,
|
||||||
|
operation.GetSource(0),
|
||||||
|
operation.GetSource(1));
|
||||||
|
break;
|
||||||
|
case IntrinsicType.Vector128BinaryRd:
|
||||||
|
GenerateVectorUnary(
|
||||||
|
context,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
info.Inst,
|
||||||
|
operation.Destination,
|
||||||
|
operation.GetSource(1));
|
||||||
|
break;
|
||||||
|
|
||||||
case IntrinsicType.VectorUnary:
|
case IntrinsicType.VectorUnary:
|
||||||
GenerateVectorUnary(
|
GenerateVectorUnary(
|
||||||
context,
|
context,
|
||||||
|
@ -19,8 +19,8 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
Add(Intrinsic.Arm64AddvV, new IntrinsicInfo(0x0e31b800u, IntrinsicType.VectorUnary));
|
Add(Intrinsic.Arm64AddvV, new IntrinsicInfo(0x0e31b800u, IntrinsicType.VectorUnary));
|
||||||
Add(Intrinsic.Arm64AddS, new IntrinsicInfo(0x5e208400u, IntrinsicType.ScalarBinary));
|
Add(Intrinsic.Arm64AddS, new IntrinsicInfo(0x5e208400u, IntrinsicType.ScalarBinary));
|
||||||
Add(Intrinsic.Arm64AddV, new IntrinsicInfo(0x0e208400u, IntrinsicType.VectorBinary));
|
Add(Intrinsic.Arm64AddV, new IntrinsicInfo(0x0e208400u, IntrinsicType.VectorBinary));
|
||||||
Add(Intrinsic.Arm64AesdV, new IntrinsicInfo(0x4e285800u, IntrinsicType.Vector128Unary));
|
Add(Intrinsic.Arm64AesdV, new IntrinsicInfo(0x4e285800u, IntrinsicType.Vector128BinaryRd));
|
||||||
Add(Intrinsic.Arm64AeseV, new IntrinsicInfo(0x4e284800u, IntrinsicType.Vector128Unary));
|
Add(Intrinsic.Arm64AeseV, new IntrinsicInfo(0x4e284800u, IntrinsicType.Vector128BinaryRd));
|
||||||
Add(Intrinsic.Arm64AesimcV, new IntrinsicInfo(0x4e287800u, IntrinsicType.Vector128Unary));
|
Add(Intrinsic.Arm64AesimcV, new IntrinsicInfo(0x4e287800u, IntrinsicType.Vector128Unary));
|
||||||
Add(Intrinsic.Arm64AesmcV, new IntrinsicInfo(0x4e286800u, IntrinsicType.Vector128Unary));
|
Add(Intrinsic.Arm64AesmcV, new IntrinsicInfo(0x4e286800u, IntrinsicType.Vector128Unary));
|
||||||
Add(Intrinsic.Arm64AndV, new IntrinsicInfo(0x0e201c00u, IntrinsicType.VectorBinaryBitwise));
|
Add(Intrinsic.Arm64AndV, new IntrinsicInfo(0x0e201c00u, IntrinsicType.VectorBinaryBitwise));
|
||||||
|
@ -23,6 +23,10 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
ScalarTernaryShlRd,
|
ScalarTernaryShlRd,
|
||||||
ScalarTernaryShrRd,
|
ScalarTernaryShrRd,
|
||||||
|
|
||||||
|
Vector128Unary,
|
||||||
|
Vector128Binary,
|
||||||
|
Vector128BinaryRd,
|
||||||
|
|
||||||
VectorUnary,
|
VectorUnary,
|
||||||
VectorUnaryBitwise,
|
VectorUnaryBitwise,
|
||||||
VectorUnaryByElem,
|
VectorUnaryByElem,
|
||||||
@ -50,9 +54,6 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
VectorTernaryShlRd,
|
VectorTernaryShlRd,
|
||||||
VectorTernaryShrRd,
|
VectorTernaryShrRd,
|
||||||
|
|
||||||
Vector128Unary,
|
|
||||||
Vector128Binary,
|
|
||||||
|
|
||||||
GetRegister,
|
GetRegister,
|
||||||
SetRegister
|
SetRegister
|
||||||
}
|
}
|
||||||
|
@ -746,6 +746,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
|||||||
info.Type == IntrinsicType.ScalarTernaryFPRdByElem ||
|
info.Type == IntrinsicType.ScalarTernaryFPRdByElem ||
|
||||||
info.Type == IntrinsicType.ScalarTernaryShlRd ||
|
info.Type == IntrinsicType.ScalarTernaryShlRd ||
|
||||||
info.Type == IntrinsicType.ScalarTernaryShrRd ||
|
info.Type == IntrinsicType.ScalarTernaryShrRd ||
|
||||||
|
info.Type == IntrinsicType.Vector128BinaryRd ||
|
||||||
info.Type == IntrinsicType.VectorBinaryRd ||
|
info.Type == IntrinsicType.VectorBinaryRd ||
|
||||||
info.Type == IntrinsicType.VectorInsertByElem ||
|
info.Type == IntrinsicType.VectorInsertByElem ||
|
||||||
info.Type == IntrinsicType.VectorTernaryRd ||
|
info.Type == IntrinsicType.VectorTernaryRd ||
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum OpCode32SimdSelMode : int
|
enum OpCode32SimdSelMode
|
||||||
{
|
{
|
||||||
Eq = 0,
|
Eq = 0,
|
||||||
Vs,
|
Vs,
|
||||||
|
@ -17,7 +17,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res;
|
Operand res;
|
||||||
|
|
||||||
if (Optimizations.UseAesni)
|
if (Optimizations.UseArm64Aes)
|
||||||
|
{
|
||||||
|
res = context.AddIntrinsic(Intrinsic.Arm64AesdV, d, n);
|
||||||
|
}
|
||||||
|
else if (Optimizations.UseAesni)
|
||||||
{
|
{
|
||||||
res = context.AddIntrinsic(Intrinsic.X86Aesdeclast, context.AddIntrinsic(Intrinsic.X86Xorpd, d, n), context.VectorZero());
|
res = context.AddIntrinsic(Intrinsic.X86Aesdeclast, context.AddIntrinsic(Intrinsic.X86Xorpd, d, n), context.VectorZero());
|
||||||
}
|
}
|
||||||
@ -38,7 +42,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res;
|
Operand res;
|
||||||
|
|
||||||
if (Optimizations.UseAesni)
|
if (Optimizations.UseArm64Aes)
|
||||||
|
{
|
||||||
|
res = context.AddIntrinsic(Intrinsic.Arm64AeseV, d, n);
|
||||||
|
}
|
||||||
|
else if (Optimizations.UseAesni)
|
||||||
{
|
{
|
||||||
res = context.AddIntrinsic(Intrinsic.X86Aesenclast, context.AddIntrinsic(Intrinsic.X86Xorpd, d, n), context.VectorZero());
|
res = context.AddIntrinsic(Intrinsic.X86Aesenclast, context.AddIntrinsic(Intrinsic.X86Xorpd, d, n), context.VectorZero());
|
||||||
}
|
}
|
||||||
@ -58,7 +66,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res;
|
Operand res;
|
||||||
|
|
||||||
if (Optimizations.UseAesni)
|
if (Optimizations.UseArm64Aes)
|
||||||
|
{
|
||||||
|
res = context.AddIntrinsic(Intrinsic.Arm64AesimcV, n);
|
||||||
|
}
|
||||||
|
else if (Optimizations.UseAesni)
|
||||||
{
|
{
|
||||||
res = context.AddIntrinsic(Intrinsic.X86Aesimc, n);
|
res = context.AddIntrinsic(Intrinsic.X86Aesimc, n);
|
||||||
}
|
}
|
||||||
@ -78,7 +90,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res;
|
Operand res;
|
||||||
|
|
||||||
if (Optimizations.UseAesni)
|
if (Optimizations.UseArm64Aes)
|
||||||
|
{
|
||||||
|
res = context.AddIntrinsic(Intrinsic.Arm64AesmcV, n);
|
||||||
|
}
|
||||||
|
else if (Optimizations.UseAesni)
|
||||||
{
|
{
|
||||||
Operand roundKey = context.VectorZero();
|
Operand roundKey = context.VectorZero();
|
||||||
|
|
||||||
|
@ -17,7 +17,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res;
|
Operand res;
|
||||||
|
|
||||||
if (Optimizations.UseAesni)
|
if (Optimizations.UseArm64Aes)
|
||||||
|
{
|
||||||
|
res = context.AddIntrinsic(Intrinsic.Arm64AesdV, d, n);
|
||||||
|
}
|
||||||
|
else if (Optimizations.UseAesni)
|
||||||
{
|
{
|
||||||
res = context.AddIntrinsic(Intrinsic.X86Aesdeclast, context.AddIntrinsic(Intrinsic.X86Xorpd, d, n), context.VectorZero());
|
res = context.AddIntrinsic(Intrinsic.X86Aesdeclast, context.AddIntrinsic(Intrinsic.X86Xorpd, d, n), context.VectorZero());
|
||||||
}
|
}
|
||||||
@ -38,7 +42,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res;
|
Operand res;
|
||||||
|
|
||||||
if (Optimizations.UseAesni)
|
if (Optimizations.UseArm64Aes)
|
||||||
|
{
|
||||||
|
res = context.AddIntrinsic(Intrinsic.Arm64AeseV, d, n);
|
||||||
|
}
|
||||||
|
else if (Optimizations.UseAesni)
|
||||||
{
|
{
|
||||||
res = context.AddIntrinsic(Intrinsic.X86Aesenclast, context.AddIntrinsic(Intrinsic.X86Xorpd, d, n), context.VectorZero());
|
res = context.AddIntrinsic(Intrinsic.X86Aesenclast, context.AddIntrinsic(Intrinsic.X86Xorpd, d, n), context.VectorZero());
|
||||||
}
|
}
|
||||||
@ -58,7 +66,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res;
|
Operand res;
|
||||||
|
|
||||||
if (Optimizations.UseAesni)
|
if (Optimizations.UseArm64Aes)
|
||||||
|
{
|
||||||
|
res = context.AddIntrinsic(Intrinsic.Arm64AesimcV, n);
|
||||||
|
}
|
||||||
|
else if (Optimizations.UseAesni)
|
||||||
{
|
{
|
||||||
res = context.AddIntrinsic(Intrinsic.X86Aesimc, n);
|
res = context.AddIntrinsic(Intrinsic.X86Aesimc, n);
|
||||||
}
|
}
|
||||||
@ -78,7 +90,11 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res;
|
Operand res;
|
||||||
|
|
||||||
if (Optimizations.UseAesni)
|
if (Optimizations.UseArm64Aes)
|
||||||
|
{
|
||||||
|
res = context.AddIntrinsic(Intrinsic.Arm64AesmcV, n);
|
||||||
|
}
|
||||||
|
else if (Optimizations.UseAesni)
|
||||||
{
|
{
|
||||||
Operand roundKey = context.VectorZero();
|
Operand roundKey = context.VectorZero();
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
Operand m = GetVecA32(op.Vm >> 1);
|
Operand m = GetVecA32(op.Vm >> 1);
|
||||||
|
|
||||||
Operand toConvert = InstEmitSimdHelper32Arm64.EmitExtractScalar(context, m, op.Vm, doubleSize);
|
Operand toConvert = InstEmitSimdHelper32Arm64.EmitExtractScalar(context, m, op.Vm, true);
|
||||||
|
|
||||||
Intrinsic inst = (unsigned ? Intrinsic.Arm64FcvtzuGp : Intrinsic.Arm64FcvtzsGp) | Intrinsic.Arm64VDouble;
|
Intrinsic inst = (unsigned ? Intrinsic.Arm64FcvtzuGp : Intrinsic.Arm64FcvtzsGp) | Intrinsic.Arm64VDouble;
|
||||||
|
|
||||||
@ -175,7 +175,7 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, unsigned ? Intrinsic.Arm64FcvtzuS : Intrinsic.Arm64FcvtzsS);
|
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, unsigned ? Intrinsic.Arm64FcvtzuS : Intrinsic.Arm64FcvtzsS, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!roundWithFpscr && Optimizations.UseSse41)
|
else if (!roundWithFpscr && Optimizations.UseSse41)
|
||||||
@ -259,6 +259,41 @@ namespace ARMeilleure.Instructions
|
|||||||
Intrinsic inst;
|
Intrinsic inst;
|
||||||
|
|
||||||
if (Optimizations.UseAdvSimd)
|
if (Optimizations.UseAdvSimd)
|
||||||
|
{
|
||||||
|
bool doubleSize = floatSize == OperandType.FP64;
|
||||||
|
|
||||||
|
if (doubleSize)
|
||||||
|
{
|
||||||
|
Operand m = GetVecA32(op.Vm >> 1);
|
||||||
|
|
||||||
|
Operand toConvert = InstEmitSimdHelper32Arm64.EmitExtractScalar(context, m, op.Vm, true);
|
||||||
|
|
||||||
|
if (unsigned)
|
||||||
|
{
|
||||||
|
inst = rm switch {
|
||||||
|
0b00 => Intrinsic.Arm64FcvtauGp,
|
||||||
|
0b01 => Intrinsic.Arm64FcvtnuGp,
|
||||||
|
0b10 => Intrinsic.Arm64FcvtpuGp,
|
||||||
|
0b11 => Intrinsic.Arm64FcvtmuGp,
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(rm))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inst = rm switch {
|
||||||
|
0b00 => Intrinsic.Arm64FcvtasGp,
|
||||||
|
0b01 => Intrinsic.Arm64FcvtnsGp,
|
||||||
|
0b10 => Intrinsic.Arm64FcvtpsGp,
|
||||||
|
0b11 => Intrinsic.Arm64FcvtmsGp,
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(rm))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand asInteger = context.AddIntrinsicInt(inst | Intrinsic.Arm64VDouble, toConvert);
|
||||||
|
|
||||||
|
InsertScalar(context, op.Vd, asInteger);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (unsigned)
|
if (unsigned)
|
||||||
{
|
{
|
||||||
@ -283,6 +318,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, inst);
|
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, inst);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (Optimizations.UseSse41)
|
else if (Optimizations.UseSse41)
|
||||||
{
|
{
|
||||||
EmitSse41ConvertInt32(context, RMToRoundMode(rm), !unsigned);
|
EmitSse41ConvertInt32(context, RMToRoundMode(rm), !unsigned);
|
||||||
|
@ -192,11 +192,10 @@ namespace ARMeilleure.Instructions
|
|||||||
EmitVectorTernaryOpSimd32(context, (d, n, m) => context.AddIntrinsic(inst, d, n, m));
|
EmitVectorTernaryOpSimd32(context, (d, n, m) => context.AddIntrinsic(inst, d, n, m));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void EmitScalarUnaryOpSimd32(ArmEmitterContext context, Func1I scalarFunc)
|
public static void EmitScalarUnaryOpSimd32(ArmEmitterContext context, Func1I scalarFunc, bool doubleSize)
|
||||||
{
|
{
|
||||||
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
||||||
|
|
||||||
bool doubleSize = (op.Size & 1) != 0;
|
|
||||||
int shift = doubleSize ? 1 : 2;
|
int shift = doubleSize ? 1 : 2;
|
||||||
Operand m = GetVecA32(op.Vm >> shift);
|
Operand m = GetVecA32(op.Vm >> shift);
|
||||||
Operand d = GetVecA32(op.Vd >> shift);
|
Operand d = GetVecA32(op.Vd >> shift);
|
||||||
@ -215,8 +214,13 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
||||||
|
|
||||||
inst |= ((op.Size & 1) != 0 ? Intrinsic.Arm64VDouble : Intrinsic.Arm64VFloat) | Intrinsic.Arm64V128;
|
EmitScalarUnaryOpF32(context, inst, (op.Size & 1) != 0);
|
||||||
EmitScalarUnaryOpSimd32(context, (m) => (inst == 0) ? m : context.AddIntrinsic(inst, m));
|
}
|
||||||
|
|
||||||
|
public static void EmitScalarUnaryOpF32(ArmEmitterContext context, Intrinsic inst, bool doubleSize)
|
||||||
|
{
|
||||||
|
inst |= (doubleSize ? Intrinsic.Arm64VDouble : Intrinsic.Arm64VFloat) | Intrinsic.Arm64V128;
|
||||||
|
EmitScalarUnaryOpSimd32(context, (m) => (inst == 0) ? m : context.AddIntrinsic(inst, m), doubleSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void EmitScalarBinaryOpSimd32(ArmEmitterContext context, Func2I scalarFunc)
|
public static void EmitScalarBinaryOpSimd32(ArmEmitterContext context, Func2I scalarFunc)
|
||||||
|
@ -228,7 +228,6 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
switch (context.Fpcr.GetRoundingMode())
|
switch (context.Fpcr.GetRoundingMode())
|
||||||
{
|
{
|
||||||
default:
|
|
||||||
case FPRoundingMode.ToNearest:
|
case FPRoundingMode.ToNearest:
|
||||||
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
|
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
|
||||||
overflowToInf = true;
|
overflowToInf = true;
|
||||||
@ -248,6 +247,9 @@ namespace ARMeilleure.Instructions
|
|||||||
roundUp = false;
|
roundUp = false;
|
||||||
overflowToInf = false;
|
overflowToInf = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.GetRoundingMode()}\".");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roundUp)
|
if (roundUp)
|
||||||
@ -412,7 +414,6 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
switch (context.Fpcr.GetRoundingMode())
|
switch (context.Fpcr.GetRoundingMode())
|
||||||
{
|
{
|
||||||
default:
|
|
||||||
case FPRoundingMode.ToNearest:
|
case FPRoundingMode.ToNearest:
|
||||||
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
|
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
|
||||||
overflowToInf = true;
|
overflowToInf = true;
|
||||||
@ -432,6 +433,9 @@ namespace ARMeilleure.Instructions
|
|||||||
roundUp = false;
|
roundUp = false;
|
||||||
overflowToInf = false;
|
overflowToInf = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.GetRoundingMode()}\".");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roundUp)
|
if (roundUp)
|
||||||
@ -585,7 +589,6 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
switch (context.Fpcr.GetRoundingMode())
|
switch (context.Fpcr.GetRoundingMode())
|
||||||
{
|
{
|
||||||
default:
|
|
||||||
case FPRoundingMode.ToNearest:
|
case FPRoundingMode.ToNearest:
|
||||||
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
|
roundUp = (error > 0.5d || (error == 0.5d && (intMant & 1u) == 1u));
|
||||||
overflowToInf = true;
|
overflowToInf = true;
|
||||||
@ -605,6 +608,9 @@ namespace ARMeilleure.Instructions
|
|||||||
roundUp = false;
|
roundUp = false;
|
||||||
overflowToInf = false;
|
overflowToInf = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentException($"Invalid rounding mode \"{context.Fpcr.GetRoundingMode()}\".");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roundUp)
|
if (roundUp)
|
||||||
@ -1433,11 +1439,24 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
switch (fpcr.GetRoundingMode())
|
switch (fpcr.GetRoundingMode())
|
||||||
{
|
{
|
||||||
|
case FPRoundingMode.ToNearest:
|
||||||
|
overflowToInf = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FPRoundingMode.TowardsPlusInfinity:
|
||||||
|
overflowToInf = !sign;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FPRoundingMode.TowardsMinusInfinity:
|
||||||
|
overflowToInf = sign;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FPRoundingMode.TowardsZero:
|
||||||
|
overflowToInf = false;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
case FPRoundingMode.ToNearest: overflowToInf = true; break;
|
throw new ArgumentException($"Invalid rounding mode \"{fpcr.GetRoundingMode()}\".");
|
||||||
case FPRoundingMode.TowardsPlusInfinity: overflowToInf = !sign; break;
|
|
||||||
case FPRoundingMode.TowardsMinusInfinity: overflowToInf = sign; break;
|
|
||||||
case FPRoundingMode.TowardsZero: overflowToInf = false; break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
|
result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
|
||||||
@ -2845,11 +2864,24 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
switch (fpcr.GetRoundingMode())
|
switch (fpcr.GetRoundingMode())
|
||||||
{
|
{
|
||||||
|
case FPRoundingMode.ToNearest:
|
||||||
|
overflowToInf = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FPRoundingMode.TowardsPlusInfinity:
|
||||||
|
overflowToInf = !sign;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FPRoundingMode.TowardsMinusInfinity:
|
||||||
|
overflowToInf = sign;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FPRoundingMode.TowardsZero:
|
||||||
|
overflowToInf = false;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
case FPRoundingMode.ToNearest: overflowToInf = true; break;
|
throw new ArgumentException($"Invalid rounding mode \"{fpcr.GetRoundingMode()}\".");
|
||||||
case FPRoundingMode.TowardsPlusInfinity: overflowToInf = !sign; break;
|
|
||||||
case FPRoundingMode.TowardsMinusInfinity: overflowToInf = sign; break;
|
|
||||||
case FPRoundingMode.TowardsZero: overflowToInf = false; break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
|
result = overflowToInf ? FPInfinity(sign) : FPMaxNormal(sign);
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
namespace ARMeilleure.IntermediateRepresentation
|
namespace ARMeilleure.IntermediateRepresentation
|
||||||
{
|
{
|
||||||
|
[Flags]
|
||||||
enum Intrinsic : ushort
|
enum Intrinsic : ushort
|
||||||
{
|
{
|
||||||
// X86 (SSE and AVX)
|
// X86 (SSE and AVX)
|
||||||
|
@ -6,7 +6,7 @@ namespace ARMeilleure.Memory
|
|||||||
{
|
{
|
||||||
IntPtr Pointer { get; }
|
IntPtr Pointer { get; }
|
||||||
|
|
||||||
bool Commit(ulong offset, ulong size);
|
void Commit(ulong offset, ulong size);
|
||||||
|
|
||||||
void MapAsRx(ulong offset, ulong size);
|
void MapAsRx(ulong offset, ulong size);
|
||||||
void MapAsRwx(ulong offset, ulong size);
|
void MapAsRwx(ulong offset, ulong size);
|
||||||
|
@ -13,6 +13,7 @@ namespace ARMeilleure
|
|||||||
public static bool UseUnmanagedDispatchLoop { get; set; } = true;
|
public static bool UseUnmanagedDispatchLoop { get; set; } = true;
|
||||||
|
|
||||||
public static bool UseAdvSimdIfAvailable { get; set; } = true;
|
public static bool UseAdvSimdIfAvailable { get; set; } = true;
|
||||||
|
public static bool UseArm64AesIfAvailable { get; set; } = true;
|
||||||
public static bool UseArm64PmullIfAvailable { get; set; } = true;
|
public static bool UseArm64PmullIfAvailable { get; set; } = true;
|
||||||
|
|
||||||
public static bool UseSseIfAvailable { get; set; } = true;
|
public static bool UseSseIfAvailable { get; set; } = true;
|
||||||
@ -41,6 +42,7 @@ namespace ARMeilleure
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal static bool UseAdvSimd => UseAdvSimdIfAvailable && Arm64HardwareCapabilities.SupportsAdvSimd;
|
internal static bool UseAdvSimd => UseAdvSimdIfAvailable && Arm64HardwareCapabilities.SupportsAdvSimd;
|
||||||
|
internal static bool UseArm64Aes => UseArm64AesIfAvailable && Arm64HardwareCapabilities.SupportsAes;
|
||||||
internal static bool UseArm64Pmull => UseArm64PmullIfAvailable && Arm64HardwareCapabilities.SupportsPmull;
|
internal static bool UseArm64Pmull => UseArm64PmullIfAvailable && Arm64HardwareCapabilities.SupportsPmull;
|
||||||
|
|
||||||
internal static bool UseSse => UseSseIfAvailable && X86HardwareCapabilities.SupportsSse;
|
internal static bool UseSse => UseSseIfAvailable && X86HardwareCapabilities.SupportsSse;
|
||||||
|
@ -78,7 +78,7 @@ namespace ARMeilleure.Signal
|
|||||||
private static IntPtr _signalHandlerPtr;
|
private static IntPtr _signalHandlerPtr;
|
||||||
private static IntPtr _signalHandlerHandle;
|
private static IntPtr _signalHandlerHandle;
|
||||||
|
|
||||||
private static readonly object _lock = new object();
|
private static readonly object _lock = new();
|
||||||
private static bool _initialized;
|
private static bool _initialized;
|
||||||
|
|
||||||
static NativeSignalHandler()
|
static NativeSignalHandler()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.State
|
namespace ARMeilleure.State
|
||||||
{
|
{
|
||||||
enum ExecutionMode : int
|
enum ExecutionMode
|
||||||
{
|
{
|
||||||
Aarch32Arm = 0,
|
Aarch32Arm = 0,
|
||||||
Aarch32Thumb = 1,
|
Aarch32Thumb = 1,
|
||||||
|
@ -13,8 +13,8 @@ namespace ARMeilleure.State
|
|||||||
// _e0 & _e1 could be marked as readonly, however they are not readonly because we modify them through the Unsafe
|
// _e0 & _e1 could be marked as readonly, however they are not readonly because we modify them through the Unsafe
|
||||||
// APIs. This also means that one should be careful when changing the layout of this struct.
|
// APIs. This also means that one should be careful when changing the layout of this struct.
|
||||||
|
|
||||||
private ulong _e0;
|
private readonly ulong _e0;
|
||||||
private ulong _e1;
|
private readonly ulong _e1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a new <see cref="V128"/> with all bits set to zero.
|
/// Gets a new <see cref="V128"/> with all bits set to zero.
|
||||||
|
@ -2,6 +2,7 @@ using ARMeilleure.CodeGen;
|
|||||||
using ARMeilleure.CodeGen.Unwinding;
|
using ARMeilleure.CodeGen.Unwinding;
|
||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using ARMeilleure.Native;
|
using ARMeilleure.Native;
|
||||||
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@ -12,8 +13,8 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
{
|
{
|
||||||
static partial class JitCache
|
static partial class JitCache
|
||||||
{
|
{
|
||||||
private const int PageSize = 4 * 1024;
|
private static readonly int PageSize = (int)MemoryBlock.GetPageSize();
|
||||||
private const int PageMask = PageSize - 1;
|
private static readonly int PageMask = PageSize - 1;
|
||||||
|
|
||||||
private const int CodeAlignment = 4; // Bytes.
|
private const int CodeAlignment = 4; // Bytes.
|
||||||
private const int CacheSize = 2047 * 1024 * 1024;
|
private const int CacheSize = 2047 * 1024 * 1024;
|
||||||
@ -25,7 +26,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
|
|
||||||
private static readonly List<CacheEntry> _cacheEntries = new List<CacheEntry>();
|
private static readonly List<CacheEntry> _cacheEntries = new List<CacheEntry>();
|
||||||
|
|
||||||
private static readonly object _lock = new object();
|
private static readonly object _lock = new();
|
||||||
private static bool _initialized;
|
private static bool _initialized;
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
|
@ -30,7 +30,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 4661; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 5292; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
@ -18,7 +18,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
|
|||||||
private readonly ManualResetEvent _pauseEvent;
|
private readonly ManualResetEvent _pauseEvent;
|
||||||
private readonly ConcurrentDictionary<OpenALHardwareDeviceSession, byte> _sessions;
|
private readonly ConcurrentDictionary<OpenALHardwareDeviceSession, byte> _sessions;
|
||||||
private bool _stillRunning;
|
private bool _stillRunning;
|
||||||
private Thread _updaterThread;
|
private readonly Thread _updaterThread;
|
||||||
|
|
||||||
public OpenALHardwareDeviceDriver()
|
public OpenALHardwareDeviceDriver()
|
||||||
{
|
{
|
||||||
@ -73,7 +73,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
|
|||||||
throw new ArgumentException($"{channelCount}");
|
throw new ArgumentException($"{channelCount}");
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenALHardwareDeviceSession session = new OpenALHardwareDeviceSession(this, memoryManager, sampleFormat, sampleRate, channelCount, volume);
|
OpenALHardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount, volume);
|
||||||
|
|
||||||
_sessions.TryAdd(session, 0);
|
_sessions.TryAdd(session, 0);
|
||||||
|
|
||||||
@ -123,6 +123,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,14 +10,14 @@ namespace Ryujinx.Audio.Backends.OpenAL
|
|||||||
{
|
{
|
||||||
class OpenALHardwareDeviceSession : HardwareDeviceSessionOutputBase
|
class OpenALHardwareDeviceSession : HardwareDeviceSessionOutputBase
|
||||||
{
|
{
|
||||||
private OpenALHardwareDeviceDriver _driver;
|
private readonly OpenALHardwareDeviceDriver _driver;
|
||||||
private int _sourceId;
|
private readonly int _sourceId;
|
||||||
private ALFormat _targetFormat;
|
private readonly ALFormat _targetFormat;
|
||||||
private bool _isActive;
|
private bool _isActive;
|
||||||
private Queue<OpenALAudioBuffer> _queuedBuffers;
|
private readonly Queue<OpenALAudioBuffer> _queuedBuffers;
|
||||||
private ulong _playedSampleCount;
|
private ulong _playedSampleCount;
|
||||||
|
|
||||||
private object _lock = new object();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
public OpenALHardwareDeviceSession(OpenALHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
|
public OpenALHardwareDeviceSession(OpenALHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
|
||||||
{
|
{
|
||||||
@ -32,23 +32,17 @@ namespace Ryujinx.Audio.Backends.OpenAL
|
|||||||
|
|
||||||
private ALFormat GetALFormat()
|
private ALFormat GetALFormat()
|
||||||
{
|
{
|
||||||
switch (RequestedSampleFormat)
|
return RequestedSampleFormat switch
|
||||||
{
|
{
|
||||||
case SampleFormat.PcmInt16:
|
SampleFormat.PcmInt16 => RequestedChannelCount switch
|
||||||
switch (RequestedChannelCount)
|
|
||||||
{
|
{
|
||||||
case 1:
|
1 => ALFormat.Mono16,
|
||||||
return ALFormat.Mono16;
|
2 => ALFormat.Stereo16,
|
||||||
case 2:
|
6 => ALFormat.Multi51Chn16Ext,
|
||||||
return ALFormat.Stereo16;
|
_ => throw new NotImplementedException($"Unsupported channel config {RequestedChannelCount}"),
|
||||||
case 6:
|
},
|
||||||
return ALFormat.Multi51Chn16Ext;
|
_ => throw new NotImplementedException($"Unsupported sample format {RequestedSampleFormat}"),
|
||||||
default:
|
};
|
||||||
throw new NotImplementedException($"Unsupported channel config {RequestedChannelCount}");
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException($"Unsupported sample format {RequestedSampleFormat}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PrepareToClose() { }
|
public override void PrepareToClose() { }
|
||||||
@ -69,7 +63,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
|
|||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
OpenALAudioBuffer driverBuffer = new OpenALAudioBuffer
|
OpenALAudioBuffer driverBuffer = new()
|
||||||
{
|
{
|
||||||
DriverIdentifier = buffer.DataPointer,
|
DriverIdentifier = buffer.DataPointer,
|
||||||
BufferId = AL.GenBuffer(),
|
BufferId = AL.GenBuffer(),
|
||||||
|
@ -19,12 +19,14 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
private readonly ManualResetEvent _pauseEvent;
|
private readonly ManualResetEvent _pauseEvent;
|
||||||
private readonly ConcurrentDictionary<SDL2HardwareDeviceSession, byte> _sessions;
|
private readonly ConcurrentDictionary<SDL2HardwareDeviceSession, byte> _sessions;
|
||||||
|
|
||||||
private bool _supportSurroundConfiguration;
|
private readonly bool _supportSurroundConfiguration;
|
||||||
|
|
||||||
// TODO: Add this to SDL2-CS
|
// TODO: Add this to SDL2-CS
|
||||||
// NOTE: We use a DllImport here because of marshaling issue for spec.
|
// NOTE: We use a DllImport here because of marshaling issue for spec.
|
||||||
|
#pragma warning disable SYSLIB1054
|
||||||
[DllImport("SDL2")]
|
[DllImport("SDL2")]
|
||||||
private static extern int SDL_GetDefaultAudioInfo(IntPtr name, out SDL_AudioSpec spec, int isCapture);
|
private static extern int SDL_GetDefaultAudioInfo(IntPtr name, out SDL_AudioSpec spec, int isCapture);
|
||||||
|
#pragma warning restore SYSLIB1054
|
||||||
|
|
||||||
public SDL2HardwareDeviceDriver()
|
public SDL2HardwareDeviceDriver()
|
||||||
{
|
{
|
||||||
@ -90,7 +92,7 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
throw new NotImplementedException("Input direction is currently not implemented on SDL2 backend!");
|
throw new NotImplementedException("Input direction is currently not implemented on SDL2 backend!");
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL2HardwareDeviceSession session = new SDL2HardwareDeviceSession(this, memoryManager, sampleFormat, sampleRate, channelCount, volume);
|
SDL2HardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount, volume);
|
||||||
|
|
||||||
_sessions.TryAdd(session, 0);
|
_sessions.TryAdd(session, 0);
|
||||||
|
|
||||||
@ -135,8 +137,7 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
|
|
||||||
if (device == 0)
|
if (device == 0)
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Application,
|
Logger.Error?.Print(LogClass.Application, $"SDL2 open audio device initialization failed with error \"{SDL_GetError()}\"");
|
||||||
$"SDL2 open audio device initialization failed with error \"{SDL_GetError()}\"");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -156,6 +157,7 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,19 +12,19 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
{
|
{
|
||||||
class SDL2HardwareDeviceSession : HardwareDeviceSessionOutputBase
|
class SDL2HardwareDeviceSession : HardwareDeviceSessionOutputBase
|
||||||
{
|
{
|
||||||
private SDL2HardwareDeviceDriver _driver;
|
private readonly SDL2HardwareDeviceDriver _driver;
|
||||||
private ConcurrentQueue<SDL2AudioBuffer> _queuedBuffers;
|
private readonly ConcurrentQueue<SDL2AudioBuffer> _queuedBuffers;
|
||||||
private DynamicRingBuffer _ringBuffer;
|
private readonly DynamicRingBuffer _ringBuffer;
|
||||||
private ulong _playedSampleCount;
|
private ulong _playedSampleCount;
|
||||||
private ManualResetEvent _updateRequiredEvent;
|
private readonly ManualResetEvent _updateRequiredEvent;
|
||||||
private uint _outputStream;
|
private uint _outputStream;
|
||||||
private bool _hasSetupError;
|
private bool _hasSetupError;
|
||||||
private SDL_AudioCallback _callbackDelegate;
|
private readonly SDL_AudioCallback _callbackDelegate;
|
||||||
private int _bytesPerFrame;
|
private readonly int _bytesPerFrame;
|
||||||
private uint _sampleCount;
|
private uint _sampleCount;
|
||||||
private bool _started;
|
private bool _started;
|
||||||
private float _volume;
|
private float _volume;
|
||||||
private ushort _nativeSampleFormat;
|
private readonly ushort _nativeSampleFormat;
|
||||||
|
|
||||||
public SDL2HardwareDeviceSession(SDL2HardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
|
public SDL2HardwareDeviceSession(SDL2HardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
|
||||||
{
|
{
|
||||||
@ -72,7 +72,7 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
|
|
||||||
private unsafe void Update(IntPtr userdata, IntPtr stream, int streamLength)
|
private unsafe void Update(IntPtr userdata, IntPtr stream, int streamLength)
|
||||||
{
|
{
|
||||||
Span<byte> streamSpan = new Span<byte>((void*)stream, streamLength);
|
Span<byte> streamSpan = new((void*)stream, streamLength);
|
||||||
|
|
||||||
int maxFrameCount = (int)GetSampleCount(streamLength);
|
int maxFrameCount = (int)GetSampleCount(streamLength);
|
||||||
int bufferedFrames = _ringBuffer.Length / _bytesPerFrame;
|
int bufferedFrames = _ringBuffer.Length / _bytesPerFrame;
|
||||||
@ -82,7 +82,7 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
if (frameCount == 0)
|
if (frameCount == 0)
|
||||||
{
|
{
|
||||||
// SDL2 left the responsibility to the user to clear the buffer.
|
// SDL2 left the responsibility to the user to clear the buffer.
|
||||||
streamSpan.Fill(0);
|
streamSpan.Clear();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
IntPtr pStreamSrc = (IntPtr)p;
|
IntPtr pStreamSrc = (IntPtr)p;
|
||||||
|
|
||||||
// Zero the dest buffer
|
// Zero the dest buffer
|
||||||
streamSpan.Fill(0);
|
streamSpan.Clear();
|
||||||
|
|
||||||
// Apply volume to written data
|
// Apply volume to written data
|
||||||
SDL_MixAudioFormat(stream, pStreamSrc, _nativeSampleFormat, (uint)samples.Length, (int)(_volume * SDL_MIX_MAXVOLUME));
|
SDL_MixAudioFormat(stream, pStreamSrc, _nativeSampleFormat, (uint)samples.Length, (int)(_volume * SDL_MIX_MAXVOLUME));
|
||||||
@ -151,7 +151,7 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
|
|
||||||
if (_outputStream != 0)
|
if (_outputStream != 0)
|
||||||
{
|
{
|
||||||
SDL2AudioBuffer driverBuffer = new SDL2AudioBuffer(buffer.DataPointer, GetSampleCount(buffer));
|
SDL2AudioBuffer driverBuffer = new(buffer.DataPointer, GetSampleCount(buffer));
|
||||||
|
|
||||||
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
|
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
|
||||||
|
|
||||||
|
@ -10,19 +10,19 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
|
|||||||
private const string LibraryName = "libsoundio";
|
private const string LibraryName = "libsoundio";
|
||||||
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
public unsafe delegate void OnDeviceChangeNativeDelegate(IntPtr ctx);
|
public delegate void OnDeviceChangeNativeDelegate(IntPtr ctx);
|
||||||
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
public unsafe delegate void OnBackendDisconnectedDelegate(IntPtr ctx, SoundIoError err);
|
public delegate void OnBackendDisconnectedDelegate(IntPtr ctx, SoundIoError err);
|
||||||
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
public unsafe delegate void OnEventsSignalDelegate(IntPtr ctx);
|
public delegate void OnEventsSignalDelegate(IntPtr ctx);
|
||||||
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
public unsafe delegate void EmitRtPrioWarningDelegate();
|
public delegate void EmitRtPrioWarningDelegate();
|
||||||
|
|
||||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
public unsafe delegate void JackCallbackDelegate(IntPtr msg);
|
public delegate void JackCallbackDelegate(IntPtr msg);
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct SoundIoStruct
|
public struct SoundIoStruct
|
||||||
@ -110,69 +110,69 @@ namespace Ryujinx.Audio.Backends.SoundIo.Native
|
|||||||
}
|
}
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial IntPtr soundio_create();
|
internal static partial IntPtr soundio_create();
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial SoundIoError soundio_connect(IntPtr ctx);
|
internal static partial SoundIoError soundio_connect(IntPtr ctx);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial void soundio_disconnect(IntPtr ctx);
|
internal static partial void soundio_disconnect(IntPtr ctx);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial void soundio_flush_events(IntPtr ctx);
|
internal static partial void soundio_flush_events(IntPtr ctx);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial int soundio_output_device_count(IntPtr ctx);
|
internal static partial int soundio_output_device_count(IntPtr ctx);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial int soundio_default_output_device_index(IntPtr ctx);
|
internal static partial int soundio_default_output_device_index(IntPtr ctx);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial IntPtr soundio_get_output_device(IntPtr ctx, int index);
|
internal static partial IntPtr soundio_get_output_device(IntPtr ctx, int index);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
public static partial bool soundio_device_supports_format(IntPtr devCtx, SoundIoFormat format);
|
internal static partial bool soundio_device_supports_format(IntPtr devCtx, SoundIoFormat format);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
public static partial bool soundio_device_supports_layout(IntPtr devCtx, IntPtr layout);
|
internal static partial bool soundio_device_supports_layout(IntPtr devCtx, IntPtr layout);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
public static partial bool soundio_device_supports_sample_rate(IntPtr devCtx, int sampleRate);
|
internal static partial bool soundio_device_supports_sample_rate(IntPtr devCtx, int sampleRate);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial IntPtr soundio_outstream_create(IntPtr devCtx);
|
internal static partial IntPtr soundio_outstream_create(IntPtr devCtx);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial SoundIoError soundio_outstream_open(IntPtr outStreamCtx);
|
internal static partial SoundIoError soundio_outstream_open(IntPtr outStreamCtx);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial SoundIoError soundio_outstream_start(IntPtr outStreamCtx);
|
internal static partial SoundIoError soundio_outstream_start(IntPtr outStreamCtx);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial SoundIoError soundio_outstream_begin_write(IntPtr outStreamCtx, IntPtr areas, IntPtr frameCount);
|
internal static partial SoundIoError soundio_outstream_begin_write(IntPtr outStreamCtx, IntPtr areas, IntPtr frameCount);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial SoundIoError soundio_outstream_end_write(IntPtr outStreamCtx);
|
internal static partial SoundIoError soundio_outstream_end_write(IntPtr outStreamCtx);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial SoundIoError soundio_outstream_pause(IntPtr devCtx, [MarshalAs(UnmanagedType.Bool)] bool pause);
|
internal static partial SoundIoError soundio_outstream_pause(IntPtr devCtx, [MarshalAs(UnmanagedType.Bool)] bool pause);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial SoundIoError soundio_outstream_set_volume(IntPtr devCtx, double volume);
|
internal static partial SoundIoError soundio_outstream_set_volume(IntPtr devCtx, double volume);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial void soundio_outstream_destroy(IntPtr streamCtx);
|
internal static partial void soundio_outstream_destroy(IntPtr streamCtx);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial void soundio_destroy(IntPtr ctx);
|
internal static partial void soundio_destroy(IntPtr ctx);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial IntPtr soundio_channel_layout_get_default(int channelCount);
|
internal static partial IntPtr soundio_channel_layout_get_default(int channelCount);
|
||||||
|
|
||||||
[LibraryImport(LibraryName)]
|
[LibraryImport(LibraryName)]
|
||||||
public static partial IntPtr soundio_strerror(SoundIoError err);
|
internal static partial IntPtr soundio_strerror(SoundIoError err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ryujinx.Audio.Backends.SoundIo.Native
|
namespace Ryujinx.Audio.Backends.SoundIo.Native
|
||||||
{
|
{
|
||||||
public enum SoundIoBackend : int
|
public enum SoundIoBackend
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
Jack = 1,
|
Jack = 1,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Reflection.Metadata;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
@ -141,7 +141,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
|||||||
throw new NotImplementedException("Input direction is currently not implemented on SoundIO backend!");
|
throw new NotImplementedException("Input direction is currently not implemented on SoundIO backend!");
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundIoHardwareDeviceSession session = new SoundIoHardwareDeviceSession(this, memoryManager, sampleFormat, sampleRate, channelCount, volume);
|
SoundIoHardwareDeviceSession session = new(this, memoryManager, sampleFormat, sampleRate, channelCount, volume);
|
||||||
|
|
||||||
_sessions.TryAdd(session, 0);
|
_sessions.TryAdd(session, 0);
|
||||||
|
|
||||||
@ -202,6 +202,8 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
|
||||||
if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
|
if (Interlocked.CompareExchange(ref _disposeState, 1, 0) == 0)
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
|
@ -12,12 +12,12 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
|||||||
{
|
{
|
||||||
class SoundIoHardwareDeviceSession : HardwareDeviceSessionOutputBase
|
class SoundIoHardwareDeviceSession : HardwareDeviceSessionOutputBase
|
||||||
{
|
{
|
||||||
private SoundIoHardwareDeviceDriver _driver;
|
private readonly SoundIoHardwareDeviceDriver _driver;
|
||||||
private ConcurrentQueue<SoundIoAudioBuffer> _queuedBuffers;
|
private readonly ConcurrentQueue<SoundIoAudioBuffer> _queuedBuffers;
|
||||||
private SoundIoOutStreamContext _outputStream;
|
private SoundIoOutStreamContext _outputStream;
|
||||||
private DynamicRingBuffer _ringBuffer;
|
private readonly DynamicRingBuffer _ringBuffer;
|
||||||
private ulong _playedSampleCount;
|
private ulong _playedSampleCount;
|
||||||
private ManualResetEvent _updateRequiredEvent;
|
private readonly ManualResetEvent _updateRequiredEvent;
|
||||||
private int _disposeState;
|
private int _disposeState;
|
||||||
|
|
||||||
public SoundIoHardwareDeviceSession(SoundIoHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
|
public SoundIoHardwareDeviceSession(SoundIoHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
|
||||||
@ -54,7 +54,7 @@ namespace Ryujinx.Audio.Backends.SoundIo
|
|||||||
|
|
||||||
public override void QueueBuffer(AudioBuffer buffer)
|
public override void QueueBuffer(AudioBuffer buffer)
|
||||||
{
|
{
|
||||||
SoundIoAudioBuffer driverBuffer = new SoundIoAudioBuffer(buffer.DataPointer, GetSampleCount(buffer));
|
SoundIoAudioBuffer driverBuffer = new(buffer.DataPointer, GetSampleCount(buffer));
|
||||||
|
|
||||||
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
|
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock used to control the waiters registration.
|
/// Lock used to control the waiters registration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private object _lock = new object();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Events signaled when the driver played audio buffers.
|
/// Events signaled when the driver played audio buffers.
|
||||||
|
@ -10,7 +10,7 @@ namespace Ryujinx.Audio.Backends.Common
|
|||||||
{
|
{
|
||||||
private const int RingBufferAlignment = 2048;
|
private const int RingBufferAlignment = 2048;
|
||||||
|
|
||||||
private object _lock = new object();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
private byte[] _buffer;
|
private byte[] _buffer;
|
||||||
private int _size;
|
private int _size;
|
||||||
|
@ -164,7 +164,7 @@ namespace Ryujinx.Audio
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default coefficients used for standard 5.1 surround to stereo downmixing.
|
/// The default coefficients used for standard 5.1 surround to stereo downmixing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static float[] DefaultSurroundToStereoCoefficients = new float[4]
|
public static readonly float[] DefaultSurroundToStereoCoefficients = new float[4]
|
||||||
{
|
{
|
||||||
1.0f,
|
1.0f,
|
||||||
0.707f,
|
0.707f,
|
||||||
|
@ -14,12 +14,12 @@ namespace Ryujinx.Audio.Input
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class AudioInputManager : IDisposable
|
public class AudioInputManager : IDisposable
|
||||||
{
|
{
|
||||||
private object _lock = new object();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock used for session allocation.
|
/// Lock used for session allocation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private object _sessionLock = new object();
|
private readonly object _sessionLock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The session ids allocation table.
|
/// The session ids allocation table.
|
||||||
|
@ -48,7 +48,7 @@ namespace Ryujinx.Audio.Input
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The lock of the parent.
|
/// The lock of the parent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private object _parentLock;
|
private readonly object _parentLock;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The dispose state.
|
/// The dispose state.
|
||||||
|
@ -14,12 +14,12 @@ namespace Ryujinx.Audio.Output
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class AudioOutputManager : IDisposable
|
public class AudioOutputManager : IDisposable
|
||||||
{
|
{
|
||||||
private object _lock = new object();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock used for session allocation.
|
/// Lock used for session allocation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private object _sessionLock = new object();
|
private readonly object _sessionLock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The session ids allocation table.
|
/// The session ids allocation table.
|
||||||
|
@ -48,7 +48,7 @@ namespace Ryujinx.Audio.Output
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// THe lock of the parent.
|
/// THe lock of the parent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private object _parentLock;
|
private readonly object _parentLock;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The dispose state.
|
/// The dispose state.
|
||||||
|
@ -26,7 +26,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
public class AudioRenderSystem : IDisposable
|
public class AudioRenderSystem : IDisposable
|
||||||
{
|
{
|
||||||
private object _lock = new object();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
private AudioRendererRenderingDevice _renderingDevice;
|
private AudioRendererRenderingDevice _renderingDevice;
|
||||||
private AudioRendererExecutionMode _executionMode;
|
private AudioRendererExecutionMode _executionMode;
|
||||||
|
@ -19,12 +19,12 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock used for session allocation.
|
/// Lock used for session allocation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private object _sessionLock = new object();
|
private readonly object _sessionLock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock used to control the <see cref="AudioProcessor"/> running state.
|
/// Lock used to control the <see cref="AudioProcessor"/> running state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private object _audioProcessorLock = new object();
|
private readonly object _audioProcessorLock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The session ids allocation table.
|
/// The session ids allocation table.
|
||||||
|
@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Server.Upsampler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Global lock of the object.
|
/// Global lock of the object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private object Lock = new object();
|
private readonly object Lock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The upsamplers instances.
|
/// The upsamplers instances.
|
||||||
|
@ -40,6 +40,7 @@ using SixLabors.ImageSharp;
|
|||||||
using SixLabors.ImageSharp.Formats.Png;
|
using SixLabors.ImageSharp.Formats.Png;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
using SixLabors.ImageSharp.Processing;
|
using SixLabors.ImageSharp.Processing;
|
||||||
|
using SPB.Graphics.Exceptions;
|
||||||
using SPB.Graphics.Vulkan;
|
using SPB.Graphics.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -133,7 +134,7 @@ namespace Ryujinx.Ava
|
|||||||
_inputManager = inputManager;
|
_inputManager = inputManager;
|
||||||
_accountManager = accountManager;
|
_accountManager = accountManager;
|
||||||
_userChannelPersistence = userChannelPersistence;
|
_userChannelPersistence = userChannelPersistence;
|
||||||
_renderingThread = new Thread(RenderLoop, 1 * 1024 * 1024) { Name = "GUI.RenderThread" };
|
_renderingThread = new Thread(RenderLoop) { Name = "GUI.RenderThread" };
|
||||||
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
||||||
_glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel;
|
_glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel;
|
||||||
_topLevel = topLevel;
|
_topLevel = topLevel;
|
||||||
@ -475,11 +476,20 @@ namespace Ryujinx.Ava
|
|||||||
_windowsMultimediaTimerResolution = null;
|
_windowsMultimediaTimerResolution = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
(_rendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent();
|
if (_rendererHost.EmbeddedWindow is EmbeddedWindowOpenGL openGlWindow)
|
||||||
|
{
|
||||||
|
// Try to bind the OpenGL context before calling the shutdown event.
|
||||||
|
openGlWindow.MakeCurrent(false, false);
|
||||||
|
|
||||||
Device.DisposeGpu();
|
Device.DisposeGpu();
|
||||||
|
|
||||||
(_rendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(null);
|
// Unbind context and destroy everything.
|
||||||
|
openGlWindow.MakeCurrent(true, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Device.DisposeGpu();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HideCursorState_Changed(object sender, ReactiveEventArgs<HideCursorMode> state)
|
private void HideCursorState_Changed(object sender, ReactiveEventArgs<HideCursorMode> state)
|
||||||
@ -930,7 +940,7 @@ namespace Ryujinx.Ava
|
|||||||
_gpuDoneEvent.Set();
|
_gpuDoneEvent.Set();
|
||||||
});
|
});
|
||||||
|
|
||||||
(_rendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(null);
|
(_rendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateStatus()
|
public void UpdateStatus()
|
||||||
@ -1044,7 +1054,7 @@ namespace Ryujinx.Ava
|
|||||||
ScreenshotRequested = true;
|
ScreenshotRequested = true;
|
||||||
break;
|
break;
|
||||||
case KeyboardHotkeyState.ShowUi:
|
case KeyboardHotkeyState.ShowUi:
|
||||||
_viewModel.ShowMenuAndStatusBar = true;
|
_viewModel.ShowMenuAndStatusBar = !_viewModel.ShowMenuAndStatusBar;
|
||||||
break;
|
break;
|
||||||
case KeyboardHotkeyState.Pause:
|
case KeyboardHotkeyState.Pause:
|
||||||
if (_viewModel.IsPaused)
|
if (_viewModel.IsPaused)
|
||||||
|
@ -123,7 +123,7 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
X11Window = PlatformHelper.CreateOpenGLWindow(FramebufferFormat.Default, 0, 0, 100, 100) as GLXWindow;
|
X11Window = PlatformHelper.CreateOpenGLWindow(new FramebufferFormat(new ColorFormat(8, 8, 8, 0), 16, 0, ColorFormat.Zero, 0, 2, false), 0, 0, 100, 100) as GLXWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowHandle = X11Window.WindowHandle.RawHandle;
|
WindowHandle = X11Window.WindowHandle.RawHandle;
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.OpenGL;
|
using Ryujinx.Graphics.OpenGL;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
using SPB.Graphics;
|
using SPB.Graphics;
|
||||||
|
using SPB.Graphics.Exceptions;
|
||||||
using SPB.Graphics.OpenGL;
|
using SPB.Graphics.OpenGL;
|
||||||
using SPB.Platform;
|
using SPB.Platform;
|
||||||
using SPB.Platform.WGL;
|
using SPB.Platform.WGL;
|
||||||
@ -18,8 +20,6 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
|
|
||||||
public OpenGLContextBase Context { get; set; }
|
public OpenGLContextBase Context { get; set; }
|
||||||
|
|
||||||
public EmbeddedWindowOpenGL() { }
|
|
||||||
|
|
||||||
protected override void OnWindowDestroying()
|
protected override void OnWindowDestroying()
|
||||||
{
|
{
|
||||||
Context.Dispose();
|
Context.Dispose();
|
||||||
@ -62,14 +62,21 @@ namespace Ryujinx.Ava.UI.Renderer
|
|||||||
Context.MakeCurrent(null);
|
Context.MakeCurrent(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MakeCurrent()
|
public void MakeCurrent(bool unbind = false, bool shouldThrow = true)
|
||||||
{
|
{
|
||||||
Context?.MakeCurrent(_window);
|
try
|
||||||
|
{
|
||||||
|
Context?.MakeCurrent(!unbind ? _window : null);
|
||||||
|
}
|
||||||
|
catch (ContextException e)
|
||||||
|
{
|
||||||
|
if (shouldThrow)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MakeCurrent(NativeWindowBase window)
|
Logger.Warning?.Print(LogClass.Ui, $"Failed to {(!unbind ? "bind" : "unbind")} OpenGL context: {e}");
|
||||||
{
|
}
|
||||||
Context?.MakeCurrent(window);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SwapBuffers()
|
public void SwapBuffers()
|
||||||
|
@ -264,7 +264,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
private void SelectLastScannedAmiibo()
|
private void SelectLastScannedAmiibo()
|
||||||
{
|
{
|
||||||
AmiiboApi scanned = _amiiboList.FirstOrDefault(amiibo => amiibo.GetId() == LastScannedAmiiboId);
|
AmiiboApi scanned = _amiiboList.Find(amiibo => amiibo.GetId() == LastScannedAmiiboId);
|
||||||
|
|
||||||
SeriesSelectedIndex = AmiiboSeries.IndexOf(scanned.AmiiboSeries);
|
SeriesSelectedIndex = AmiiboSeries.IndexOf(scanned.AmiiboSeries);
|
||||||
AmiiboSelectedIndex = AmiiboList.IndexOf(scanned);
|
AmiiboSelectedIndex = AmiiboList.IndexOf(scanned);
|
||||||
@ -325,7 +325,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
AmiiboApi selected = _amiibos[_amiiboSelectedIndex];
|
AmiiboApi selected = _amiibos[_amiiboSelectedIndex];
|
||||||
|
|
||||||
string imageUrl = _amiiboList.FirstOrDefault(amiibo => amiibo.Equals(selected)).Image;
|
string imageUrl = _amiiboList.Find(amiibo => amiibo.Equals(selected)).Image;
|
||||||
|
|
||||||
string usageString = "";
|
string usageString = "";
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||||||
// This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical
|
// This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical
|
||||||
[Flags]
|
[Flags]
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<ControllerType>))]
|
[JsonConverter(typeof(TypedStringEnumConverter<ControllerType>))]
|
||||||
public enum ControllerType : int
|
public enum ControllerType
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
ProController = 1 << 0,
|
ProController = 1 << 0,
|
||||||
|
@ -5,7 +5,7 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||||||
{
|
{
|
||||||
// This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical
|
// This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<PlayerIndex>))]
|
[JsonConverter(typeof(TypedStringEnumConverter<PlayerIndex>))]
|
||||||
public enum PlayerIndex : int
|
public enum PlayerIndex
|
||||||
{
|
{
|
||||||
Player1 = 0,
|
Player1 = 0,
|
||||||
Player2 = 1,
|
Player2 = 1,
|
||||||
|
@ -24,6 +24,24 @@ namespace Ryujinx.Common.Memory
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool TryRead<T>(out T value) where T : unmanaged
|
||||||
|
{
|
||||||
|
int valueSize = Unsafe.SizeOf<T>();
|
||||||
|
|
||||||
|
if (valueSize > _input.Length)
|
||||||
|
{
|
||||||
|
value = default;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = MemoryMarshal.Cast<byte, T>(_input)[0];
|
||||||
|
|
||||||
|
_input = _input.Slice(valueSize);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public ReadOnlySpan<byte> GetSpan(int size)
|
public ReadOnlySpan<byte> GetSpan(int size)
|
||||||
{
|
{
|
||||||
ReadOnlySpan<byte> data = _input.Slice(0, size);
|
ReadOnlySpan<byte> data = _input.Slice(0, size);
|
||||||
|
@ -5,7 +5,7 @@ using System;
|
|||||||
|
|
||||||
namespace Ryujinx.Cpu
|
namespace Ryujinx.Cpu
|
||||||
{
|
{
|
||||||
class AddressSpace : IDisposable
|
public class AddressSpace : IDisposable
|
||||||
{
|
{
|
||||||
private const ulong PageSize = 0x1000;
|
private const ulong PageSize = 0x1000;
|
||||||
|
|
||||||
@ -154,7 +154,9 @@ namespace Ryujinx.Cpu
|
|||||||
public MemoryBlock Base { get; }
|
public MemoryBlock Base { get; }
|
||||||
public MemoryBlock Mirror { get; }
|
public MemoryBlock Mirror { get; }
|
||||||
|
|
||||||
public AddressSpace(MemoryBlock backingMemory, ulong asSize, bool supports4KBPages)
|
public ulong AddressSpaceSize { get; }
|
||||||
|
|
||||||
|
public AddressSpace(MemoryBlock backingMemory, MemoryBlock baseMemory, MemoryBlock mirrorMemory, ulong addressSpaceSize, bool supports4KBPages)
|
||||||
{
|
{
|
||||||
if (!supports4KBPages)
|
if (!supports4KBPages)
|
||||||
{
|
{
|
||||||
@ -163,17 +165,48 @@ namespace Ryujinx.Cpu
|
|||||||
_privateTree = new IntrusiveRedBlackTree<PrivateMapping>();
|
_privateTree = new IntrusiveRedBlackTree<PrivateMapping>();
|
||||||
_treeLock = new object();
|
_treeLock = new object();
|
||||||
|
|
||||||
_mappingTree.Add(new Mapping(0UL, asSize, MappingType.None));
|
_mappingTree.Add(new Mapping(0UL, addressSpaceSize, MappingType.None));
|
||||||
_privateTree.Add(new PrivateMapping(0UL, asSize, default));
|
_privateTree.Add(new PrivateMapping(0UL, addressSpaceSize, default));
|
||||||
}
|
}
|
||||||
|
|
||||||
_backingMemory = backingMemory;
|
_backingMemory = backingMemory;
|
||||||
_supports4KBPages = supports4KBPages;
|
_supports4KBPages = supports4KBPages;
|
||||||
|
|
||||||
|
Base = baseMemory;
|
||||||
|
Mirror = mirrorMemory;
|
||||||
|
AddressSpaceSize = addressSpaceSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryCreate(MemoryBlock backingMemory, ulong asSize, bool supports4KBPages, out AddressSpace addressSpace)
|
||||||
|
{
|
||||||
|
addressSpace = null;
|
||||||
|
|
||||||
MemoryAllocationFlags asFlags = MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible;
|
MemoryAllocationFlags asFlags = MemoryAllocationFlags.Reserve | MemoryAllocationFlags.ViewCompatible;
|
||||||
|
|
||||||
Base = new MemoryBlock(asSize, asFlags);
|
ulong minAddressSpaceSize = Math.Min(asSize, 1UL << 36);
|
||||||
Mirror = new MemoryBlock(asSize, asFlags);
|
|
||||||
|
// Attempt to create the address space with expected size or try to reduce it until it succeed.
|
||||||
|
for (ulong addressSpaceSize = asSize; addressSpaceSize >= minAddressSpaceSize; addressSpaceSize >>= 1)
|
||||||
|
{
|
||||||
|
MemoryBlock baseMemory = null;
|
||||||
|
MemoryBlock mirrorMemory = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
baseMemory = new MemoryBlock(addressSpaceSize, asFlags);
|
||||||
|
mirrorMemory = new MemoryBlock(addressSpaceSize, asFlags);
|
||||||
|
addressSpace = new AddressSpace(backingMemory, baseMemory, mirrorMemory, addressSpaceSize, supports4KBPages);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (SystemException)
|
||||||
|
{
|
||||||
|
baseMemory?.Dispose();
|
||||||
|
mirrorMemory?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return addressSpace != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags)
|
public void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags)
|
||||||
|
@ -15,7 +15,7 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
_impl = new MemoryBlock(size, flags);
|
_impl = new MemoryBlock(size, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Commit(ulong offset, ulong size) => _impl.Commit(offset, size);
|
public void Commit(ulong offset, ulong size) => _impl.Commit(offset, size);
|
||||||
public void MapAsRx(ulong offset, ulong size) => _impl.Reprotect(offset, size, MemoryPermission.ReadAndExecute);
|
public void MapAsRx(ulong offset, ulong size) => _impl.Reprotect(offset, size, MemoryPermission.ReadAndExecute);
|
||||||
public void MapAsRwx(ulong offset, ulong size) => _impl.Reprotect(offset, size, MemoryPermission.ReadWriteExecute);
|
public void MapAsRwx(ulong offset, ulong size) => _impl.Reprotect(offset, size, MemoryPermission.ReadWriteExecute);
|
||||||
|
|
||||||
|
@ -38,7 +38,8 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
private readonly bool _unsafeMode;
|
private readonly bool _unsafeMode;
|
||||||
|
|
||||||
private readonly AddressSpace _addressSpace;
|
private readonly AddressSpace _addressSpace;
|
||||||
private readonly ulong _addressSpaceSize;
|
|
||||||
|
public ulong AddressSpaceSize { get; }
|
||||||
|
|
||||||
private readonly PageTable<ulong> _pageTable;
|
private readonly PageTable<ulong> _pageTable;
|
||||||
|
|
||||||
@ -62,21 +63,21 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the host mapped memory manager.
|
/// Creates a new instance of the host mapped memory manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="backingMemory">Physical backing memory where virtual memory will be mapped to</param>
|
/// <param name="addressSpace">Address space instance to use</param>
|
||||||
/// <param name="addressSpaceSize">Size of the address space</param>
|
|
||||||
/// <param name="unsafeMode">True if unmanaged access should not be masked (unsafe), false otherwise.</param>
|
/// <param name="unsafeMode">True if unmanaged access should not be masked (unsafe), false otherwise.</param>
|
||||||
/// <param name="invalidAccessHandler">Optional function to handle invalid memory accesses</param>
|
/// <param name="invalidAccessHandler">Optional function to handle invalid memory accesses</param>
|
||||||
public MemoryManagerHostMapped(MemoryBlock backingMemory, ulong addressSpaceSize, bool unsafeMode, InvalidAccessHandler invalidAccessHandler = null)
|
public MemoryManagerHostMapped(AddressSpace addressSpace, bool unsafeMode, InvalidAccessHandler invalidAccessHandler)
|
||||||
{
|
{
|
||||||
|
_addressSpace = addressSpace;
|
||||||
_pageTable = new PageTable<ulong>();
|
_pageTable = new PageTable<ulong>();
|
||||||
_invalidAccessHandler = invalidAccessHandler;
|
_invalidAccessHandler = invalidAccessHandler;
|
||||||
_unsafeMode = unsafeMode;
|
_unsafeMode = unsafeMode;
|
||||||
_addressSpaceSize = addressSpaceSize;
|
AddressSpaceSize = addressSpace.AddressSpaceSize;
|
||||||
|
|
||||||
ulong asSize = PageSize;
|
ulong asSize = PageSize;
|
||||||
int asBits = PageBits;
|
int asBits = PageBits;
|
||||||
|
|
||||||
while (asSize < addressSpaceSize)
|
while (asSize < AddressSpaceSize)
|
||||||
{
|
{
|
||||||
asSize <<= 1;
|
asSize <<= 1;
|
||||||
asBits++;
|
asBits++;
|
||||||
@ -86,8 +87,6 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
|
|
||||||
_pageBitmap = new ulong[1 << (AddressSpaceBits - (PageBits + PageToPteShift))];
|
_pageBitmap = new ulong[1 << (AddressSpaceBits - (PageBits + PageToPteShift))];
|
||||||
|
|
||||||
_addressSpace = new AddressSpace(backingMemory, asSize, Supports4KBPages);
|
|
||||||
|
|
||||||
Tracking = new MemoryTracking(this, (int)MemoryBlock.GetPageSize(), invalidAccessHandler);
|
Tracking = new MemoryTracking(this, (int)MemoryBlock.GetPageSize(), invalidAccessHandler);
|
||||||
_memoryEh = new MemoryEhMeilleure(_addressSpace.Base, _addressSpace.Mirror, Tracking);
|
_memoryEh = new MemoryEhMeilleure(_addressSpace.Base, _addressSpace.Mirror, Tracking);
|
||||||
}
|
}
|
||||||
@ -99,7 +98,7 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
/// <returns>True if the virtual address is part of the addressable space</returns>
|
/// <returns>True if the virtual address is part of the addressable space</returns>
|
||||||
private bool ValidateAddress(ulong va)
|
private bool ValidateAddress(ulong va)
|
||||||
{
|
{
|
||||||
return va < _addressSpaceSize;
|
return va < AddressSpaceSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -111,7 +110,7 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
private bool ValidateAddressAndSize(ulong va, ulong size)
|
private bool ValidateAddressAndSize(ulong va, ulong size)
|
||||||
{
|
{
|
||||||
ulong endVa = va + size;
|
ulong endVa = va + size;
|
||||||
return endVa >= va && endVa >= size && endVa <= _addressSpaceSize;
|
return endVa >= va && endVa >= size && endVa <= AddressSpaceSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Device
|
|||||||
|
|
||||||
public TState State;
|
public TState State;
|
||||||
|
|
||||||
private uint Size => (uint)(Unsafe.SizeOf<TState>() + RegisterSize - 1) / RegisterSize;
|
private static uint Size => (uint)(Unsafe.SizeOf<TState>() + RegisterSize - 1) / RegisterSize;
|
||||||
|
|
||||||
private readonly Func<int>[] _readCallbacks;
|
private readonly Func<int>[] _readCallbacks;
|
||||||
private readonly Action<int>[] _writeCallbacks;
|
private readonly Action<int>[] _writeCallbacks;
|
||||||
|
@ -28,6 +28,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
public readonly bool SupportsFragmentShaderOrderingIntel;
|
public readonly bool SupportsFragmentShaderOrderingIntel;
|
||||||
public readonly bool SupportsGeometryShader;
|
public readonly bool SupportsGeometryShader;
|
||||||
public readonly bool SupportsGeometryShaderPassthrough;
|
public readonly bool SupportsGeometryShaderPassthrough;
|
||||||
|
public readonly bool SupportsTransformFeedback;
|
||||||
public readonly bool SupportsImageLoadFormatted;
|
public readonly bool SupportsImageLoadFormatted;
|
||||||
public readonly bool SupportsLayerVertexTessellation;
|
public readonly bool SupportsLayerVertexTessellation;
|
||||||
public readonly bool SupportsMismatchingViewFormat;
|
public readonly bool SupportsMismatchingViewFormat;
|
||||||
@ -77,6 +78,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
bool supportsFragmentShaderOrderingIntel,
|
bool supportsFragmentShaderOrderingIntel,
|
||||||
bool supportsGeometryShader,
|
bool supportsGeometryShader,
|
||||||
bool supportsGeometryShaderPassthrough,
|
bool supportsGeometryShaderPassthrough,
|
||||||
|
bool supportsTransformFeedback,
|
||||||
bool supportsImageLoadFormatted,
|
bool supportsImageLoadFormatted,
|
||||||
bool supportsLayerVertexTessellation,
|
bool supportsLayerVertexTessellation,
|
||||||
bool supportsMismatchingViewFormat,
|
bool supportsMismatchingViewFormat,
|
||||||
@ -122,6 +124,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;
|
SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;
|
||||||
SupportsGeometryShader = supportsGeometryShader;
|
SupportsGeometryShader = supportsGeometryShader;
|
||||||
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
||||||
|
SupportsTransformFeedback = supportsTransformFeedback;
|
||||||
SupportsImageLoadFormatted = supportsImageLoadFormatted;
|
SupportsImageLoadFormatted = supportsImageLoadFormatted;
|
||||||
SupportsLayerVertexTessellation = supportsLayerVertexTessellation;
|
SupportsLayerVertexTessellation = supportsLayerVertexTessellation;
|
||||||
SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
|
SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
|
||||||
|
@ -56,7 +56,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
private int _refConsumerPtr;
|
private int _refConsumerPtr;
|
||||||
|
|
||||||
private Action _interruptAction;
|
private Action _interruptAction;
|
||||||
private object _interruptLock = new();
|
private readonly object _interruptLock = new();
|
||||||
|
|
||||||
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
|
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
|
||||||
|
|
||||||
|
@ -539,6 +539,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
engine.UpdateState();
|
engine.UpdateState();
|
||||||
|
|
||||||
|
if (instanceCount > 1)
|
||||||
|
{
|
||||||
|
// Must be called after UpdateState as it assumes the shader state
|
||||||
|
// has already been set, and that bindings have been updated already.
|
||||||
|
|
||||||
|
_channel.BufferManager.SetInstancedDrawVertexCount(count);
|
||||||
|
}
|
||||||
|
|
||||||
if (indexed)
|
if (indexed)
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.DrawIndexed(count, instanceCount, firstIndex, firstVertex, firstInstance);
|
_context.Renderer.Pipeline.DrawIndexed(count, instanceCount, firstIndex, firstVertex, firstInstance);
|
||||||
@ -676,6 +684,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
_channel.BufferManager.SetIndexBuffer(br, IndexType.UInt);
|
_channel.BufferManager.SetIndexBuffer(br, IndexType.UInt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_channel.BufferManager.SetInstancedDrawVertexCount(_instancedIndexCount);
|
||||||
|
|
||||||
_context.Renderer.Pipeline.DrawIndexed(
|
_context.Renderer.Pipeline.DrawIndexed(
|
||||||
_instancedIndexCount,
|
_instancedIndexCount,
|
||||||
_instanceIndex + 1,
|
_instanceIndex + 1,
|
||||||
@ -685,6 +695,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
_channel.BufferManager.SetInstancedDrawVertexCount(_instancedDrawStateCount);
|
||||||
|
|
||||||
_context.Renderer.Pipeline.Draw(
|
_context.Renderer.Pipeline.Draw(
|
||||||
_instancedDrawStateCount,
|
_instancedDrawStateCount,
|
||||||
_instanceIndex + 1,
|
_instanceIndex + 1,
|
||||||
|
@ -269,7 +269,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
_prevFirstVertex = _state.State.FirstVertex;
|
_prevFirstVertex = _state.State.FirstVertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tfEnable = _state.State.TfEnable;
|
bool tfEnable = _state.State.TfEnable && _context.Capabilities.SupportsTransformFeedback;
|
||||||
|
|
||||||
if (!tfEnable && _prevTfEnable)
|
if (!tfEnable && _prevTfEnable)
|
||||||
{
|
{
|
||||||
@ -1367,6 +1367,22 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
_vsUsesDrawParameters = gs.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
_vsUsesDrawParameters = gs.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
||||||
_vsClipDistancesWritten = gs.Shaders[1]?.Info.ClipDistancesWritten ?? 0;
|
_vsClipDistancesWritten = gs.Shaders[1]?.Info.ClipDistancesWritten ?? 0;
|
||||||
|
|
||||||
|
bool hasTransformFeedback = gs.SpecializationState.TransformFeedbackDescriptors != null;
|
||||||
|
if (hasTransformFeedback != _channel.BufferManager.HasTransformFeedbackOutputs)
|
||||||
|
{
|
||||||
|
if (!_context.Capabilities.SupportsTransformFeedback)
|
||||||
|
{
|
||||||
|
// If host does not support transform feedback, and the shader changed,
|
||||||
|
// we might need to update bindings as transform feedback emulation
|
||||||
|
// uses storage buffer bindings that might have been used for something
|
||||||
|
// else in a previous draw.
|
||||||
|
|
||||||
|
_channel.BufferManager.ForceTransformFeedbackAndStorageBuffersDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
_channel.BufferManager.HasTransformFeedbackOutputs = hasTransformFeedback;
|
||||||
|
}
|
||||||
|
|
||||||
if (oldVsClipDistancesWritten != _vsClipDistancesWritten)
|
if (oldVsClipDistancesWritten != _vsClipDistancesWritten)
|
||||||
{
|
{
|
||||||
UpdateUserClipState();
|
UpdateUserClipState();
|
||||||
|
@ -512,7 +512,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// <returns>True if at least one of the handles is dirty</returns>
|
/// <returns>True if at least one of the handles is dirty</returns>
|
||||||
private bool CheckDirty()
|
private bool CheckDirty()
|
||||||
{
|
{
|
||||||
return Handles.Any(handle => handle.Dirty);
|
return Array.Exists(Handles, handle => handle.Dirty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -6,6 +6,7 @@ using Ryujinx.Graphics.Shader;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Memory
|
namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
{
|
{
|
||||||
@ -14,12 +15,17 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
class BufferManager
|
class BufferManager
|
||||||
{
|
{
|
||||||
|
private const int TfInfoVertexCountOffset = Constants.TotalTransformFeedbackBuffers * sizeof(int);
|
||||||
|
private const int TfInfoBufferSize = TfInfoVertexCountOffset + sizeof(int);
|
||||||
|
|
||||||
private readonly GpuContext _context;
|
private readonly GpuContext _context;
|
||||||
private readonly GpuChannel _channel;
|
private readonly GpuChannel _channel;
|
||||||
|
|
||||||
private int _unalignedStorageBuffers;
|
private int _unalignedStorageBuffers;
|
||||||
public bool HasUnalignedStorageBuffers => _unalignedStorageBuffers > 0;
|
public bool HasUnalignedStorageBuffers => _unalignedStorageBuffers > 0;
|
||||||
|
|
||||||
|
public bool HasTransformFeedbackOutputs { get; set; }
|
||||||
|
|
||||||
private IndexBuffer _indexBuffer;
|
private IndexBuffer _indexBuffer;
|
||||||
private readonly VertexBuffer[] _vertexBuffers;
|
private readonly VertexBuffer[] _vertexBuffers;
|
||||||
private readonly BufferBounds[] _transformFeedbackBuffers;
|
private readonly BufferBounds[] _transformFeedbackBuffers;
|
||||||
@ -98,6 +104,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
private readonly BuffersPerStage[] _gpStorageBuffers;
|
private readonly BuffersPerStage[] _gpStorageBuffers;
|
||||||
private readonly BuffersPerStage[] _gpUniformBuffers;
|
private readonly BuffersPerStage[] _gpUniformBuffers;
|
||||||
|
|
||||||
|
private BufferHandle _tfInfoBuffer;
|
||||||
|
private int[] _tfInfoData;
|
||||||
|
|
||||||
private bool _gpStorageBuffersDirty;
|
private bool _gpStorageBuffersDirty;
|
||||||
private bool _gpUniformBuffersDirty;
|
private bool _gpUniformBuffersDirty;
|
||||||
|
|
||||||
@ -137,6 +146,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
_bufferTextures = new List<BufferTextureBinding>();
|
_bufferTextures = new List<BufferTextureBinding>();
|
||||||
|
|
||||||
_ranges = new BufferAssignment[Constants.TotalGpUniformBuffers * Constants.ShaderStages];
|
_ranges = new BufferAssignment[Constants.TotalGpUniformBuffers * Constants.ShaderStages];
|
||||||
|
|
||||||
|
if (!context.Capabilities.SupportsTransformFeedback)
|
||||||
|
{
|
||||||
|
_tfInfoData = new int[Constants.TotalTransformFeedbackBuffers];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -319,6 +333,31 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
_gpUniformBuffersDirty = true;
|
_gpUniformBuffersDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the number of vertices per instance on a instanced draw. Used for transform feedback emulation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vertexCount">Vertex count per instance</param>
|
||||||
|
public void SetInstancedDrawVertexCount(int vertexCount)
|
||||||
|
{
|
||||||
|
if (!_context.Capabilities.SupportsTransformFeedback &&
|
||||||
|
HasTransformFeedbackOutputs &&
|
||||||
|
_tfInfoBuffer != BufferHandle.Null)
|
||||||
|
{
|
||||||
|
Span<byte> data = stackalloc byte[sizeof(int)];
|
||||||
|
MemoryMarshal.Cast<byte, int>(data)[0] = vertexCount;
|
||||||
|
_context.Renderer.SetBufferData(_tfInfoBuffer, TfInfoVertexCountOffset, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Forces transform feedback and storage buffers to be updated on the next draw.
|
||||||
|
/// </summary>
|
||||||
|
public void ForceTransformFeedbackAndStorageBuffersDirty()
|
||||||
|
{
|
||||||
|
_transformFeedbackBuffersDirty = true;
|
||||||
|
_gpStorageBuffersDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the binding points for the storage buffers bound on the compute pipeline.
|
/// Sets the binding points for the storage buffers bound on the compute pipeline.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -537,6 +576,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
_transformFeedbackBuffersDirty = false;
|
_transformFeedbackBuffersDirty = false;
|
||||||
|
|
||||||
|
if (_context.Capabilities.SupportsTransformFeedback)
|
||||||
|
{
|
||||||
Span<BufferRange> tfbs = stackalloc BufferRange[Constants.TotalTransformFeedbackBuffers];
|
Span<BufferRange> tfbs = stackalloc BufferRange[Constants.TotalTransformFeedbackBuffers];
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
|
for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
|
||||||
@ -554,6 +595,57 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
_context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs);
|
_context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs);
|
||||||
}
|
}
|
||||||
|
else if (HasTransformFeedbackOutputs)
|
||||||
|
{
|
||||||
|
Span<int> info = _tfInfoData.AsSpan();
|
||||||
|
Span<BufferAssignment> buffers = stackalloc BufferAssignment[Constants.TotalTransformFeedbackBuffers + 1];
|
||||||
|
|
||||||
|
bool needsDataUpdate = false;
|
||||||
|
|
||||||
|
if (_tfInfoBuffer == BufferHandle.Null)
|
||||||
|
{
|
||||||
|
_tfInfoBuffer = _context.Renderer.CreateBuffer(TfInfoBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffers[0] = new BufferAssignment(0, new BufferRange(_tfInfoBuffer, 0, TfInfoBufferSize));
|
||||||
|
|
||||||
|
int alignment = _context.Capabilities.StorageBufferOffsetAlignment;
|
||||||
|
|
||||||
|
for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
|
||||||
|
{
|
||||||
|
BufferBounds tfb = _transformFeedbackBuffers[index];
|
||||||
|
|
||||||
|
if (tfb.Address == 0)
|
||||||
|
{
|
||||||
|
buffers[1 + index] = new BufferAssignment(1 + index, BufferRange.Empty);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ulong endAddress = tfb.Address + tfb.Size;
|
||||||
|
ulong address = BitUtils.AlignDown(tfb.Address, (ulong)alignment);
|
||||||
|
ulong size = endAddress - address;
|
||||||
|
|
||||||
|
int tfeOffset = ((int)tfb.Address & (alignment - 1)) / 4;
|
||||||
|
|
||||||
|
if (info[index] != tfeOffset)
|
||||||
|
{
|
||||||
|
info[index] = tfeOffset;
|
||||||
|
needsDataUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffers[1 + index] = new BufferAssignment(1 + index, bufferCache.GetBufferRange(address, size, write: true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsDataUpdate)
|
||||||
|
{
|
||||||
|
Span<byte> infoData = MemoryMarshal.Cast<int, byte>(info);
|
||||||
|
_context.Renderer.SetBufferData(_tfInfoBuffer, 0, infoData);
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Renderer.Pipeline.SetStorageBuffers(buffers);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
|
for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
|
||||||
|
@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
private List<BufferMigration> _sources;
|
private List<BufferMigration> _sources;
|
||||||
private BufferMigration _migrationTarget;
|
private BufferMigration _migrationTarget;
|
||||||
|
|
||||||
private object _lock = new object();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the modified range list has any entries or not.
|
/// Whether the modified range list has any entries or not.
|
||||||
|
@ -37,7 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
ShaderSpecializationState oldSpecState,
|
ShaderSpecializationState oldSpecState,
|
||||||
ShaderSpecializationState newSpecState,
|
ShaderSpecializationState newSpecState,
|
||||||
ResourceCounts counts,
|
ResourceCounts counts,
|
||||||
int stageIndex) : base(context, counts, stageIndex)
|
int stageIndex) : base(context, counts, stageIndex, oldSpecState.TransformFeedbackDescriptors != null)
|
||||||
{
|
{
|
||||||
_data = data;
|
_data = data;
|
||||||
_cb1Data = cb1Data;
|
_cb1Data = cb1Data;
|
||||||
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||||
private const uint CodeGenVersion = 5044;
|
private const uint CodeGenVersion = 5311;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
@ -368,7 +368,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
|
|
||||||
if (hostCode != null)
|
if (hostCode != null)
|
||||||
{
|
{
|
||||||
ShaderInfo shaderInfo = ShaderInfoBuilder.BuildForCache(context, shaders, specState.PipelineState);
|
ShaderInfo shaderInfo = ShaderInfoBuilder.BuildForCache(
|
||||||
|
context,
|
||||||
|
shaders,
|
||||||
|
specState.PipelineState,
|
||||||
|
specState.TransformFeedbackDescriptors != null);
|
||||||
|
|
||||||
IProgram hostProgram;
|
IProgram hostProgram;
|
||||||
|
|
||||||
|
@ -491,7 +491,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
{
|
{
|
||||||
ShaderSource[] shaderSources = new ShaderSource[compilation.TranslatedStages.Length];
|
ShaderSource[] shaderSources = new ShaderSource[compilation.TranslatedStages.Length];
|
||||||
|
|
||||||
ShaderInfoBuilder shaderInfoBuilder = new ShaderInfoBuilder(_context);
|
ShaderInfoBuilder shaderInfoBuilder = new ShaderInfoBuilder(_context, compilation.SpecializationState.TransformFeedbackDescriptors != null);
|
||||||
|
|
||||||
for (int index = 0; index < compilation.TranslatedStages.Length; index++)
|
for (int index = 0; index < compilation.TranslatedStages.Length; index++)
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
GpuContext context,
|
GpuContext context,
|
||||||
GpuChannel channel,
|
GpuChannel channel,
|
||||||
GpuAccessorState state,
|
GpuAccessorState state,
|
||||||
int stageIndex) : base(context, state.ResourceCounts, stageIndex)
|
int stageIndex) : base(context, state.ResourceCounts, stageIndex, state.TransformFeedbackDescriptors != null)
|
||||||
{
|
{
|
||||||
_isVulkan = context.Capabilities.Api == TargetApi.Vulkan;
|
_isVulkan = context.Capabilities.Api == TargetApi.Vulkan;
|
||||||
_channel = channel;
|
_channel = channel;
|
||||||
@ -44,7 +44,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <param name="context">GPU context</param>
|
/// <param name="context">GPU context</param>
|
||||||
/// <param name="channel">GPU channel</param>
|
/// <param name="channel">GPU channel</param>
|
||||||
/// <param name="state">Current GPU state</param>
|
/// <param name="state">Current GPU state</param>
|
||||||
public GpuAccessor(GpuContext context, GpuChannel channel, GpuAccessorState state) : base(context, state.ResourceCounts, 0)
|
public GpuAccessor(GpuContext context, GpuChannel channel, GpuAccessorState state) : base(context, state.ResourceCounts, 0, false)
|
||||||
{
|
{
|
||||||
_channel = channel;
|
_channel = channel;
|
||||||
_state = state;
|
_state = state;
|
||||||
|
@ -17,40 +17,56 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
private readonly ResourceCounts _resourceCounts;
|
private readonly ResourceCounts _resourceCounts;
|
||||||
private readonly int _stageIndex;
|
private readonly int _stageIndex;
|
||||||
|
|
||||||
|
private readonly int _reservedConstantBuffers;
|
||||||
|
private readonly int _reservedStorageBuffers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new GPU accessor.
|
/// Creates a new GPU accessor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">GPU context</param>
|
/// <param name="context">GPU context</param>
|
||||||
public GpuAccessorBase(GpuContext context, ResourceCounts resourceCounts, int stageIndex)
|
/// <param name="resourceCounts">Counter of GPU resources used by the shader</param>
|
||||||
|
/// <param name="stageIndex">Index of the shader stage, 0 for compute</param>
|
||||||
|
/// <param name="tfEnabled">Indicates if the current graphics shader is used with transform feedback enabled</param>
|
||||||
|
public GpuAccessorBase(GpuContext context, ResourceCounts resourceCounts, int stageIndex, bool tfEnabled)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_resourceCounts = resourceCounts;
|
_resourceCounts = resourceCounts;
|
||||||
_stageIndex = stageIndex;
|
_stageIndex = stageIndex;
|
||||||
|
|
||||||
|
_reservedConstantBuffers = 1; // For the support buffer.
|
||||||
|
_reservedStorageBuffers = !context.Capabilities.SupportsTransformFeedback && tfEnabled ? 5 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int QueryBindingConstantBuffer(int index)
|
public int QueryBindingConstantBuffer(int index)
|
||||||
{
|
{
|
||||||
|
int binding;
|
||||||
|
|
||||||
if (_context.Capabilities.Api == TargetApi.Vulkan)
|
if (_context.Capabilities.Api == TargetApi.Vulkan)
|
||||||
{
|
{
|
||||||
// We need to start counting from 1 since binding 0 is reserved for the support uniform buffer.
|
binding = GetBindingFromIndex(index, _context.Capabilities.MaximumUniformBuffersPerStage, "Uniform buffer");
|
||||||
return GetBindingFromIndex(index, _context.Capabilities.MaximumUniformBuffersPerStage, "Uniform buffer") + 1;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return _resourceCounts.UniformBuffersCount++;
|
binding = _resourceCounts.UniformBuffersCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return binding + _reservedConstantBuffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int QueryBindingStorageBuffer(int index)
|
public int QueryBindingStorageBuffer(int index)
|
||||||
{
|
{
|
||||||
|
int binding;
|
||||||
|
|
||||||
if (_context.Capabilities.Api == TargetApi.Vulkan)
|
if (_context.Capabilities.Api == TargetApi.Vulkan)
|
||||||
{
|
{
|
||||||
return GetBindingFromIndex(index, _context.Capabilities.MaximumStorageBuffersPerStage, "Storage buffer");
|
binding = GetBindingFromIndex(index, _context.Capabilities.MaximumStorageBuffersPerStage, "Storage buffer");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return _resourceCounts.StorageBuffersCount++;
|
binding = _resourceCounts.StorageBuffersCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return binding + _reservedStorageBuffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int QueryBindingTexture(int index, bool isBuffer)
|
public int QueryBindingTexture(int index, bool isBuffer)
|
||||||
@ -149,6 +165,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
public bool QueryHostSupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
|
public bool QueryHostSupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
|
||||||
|
|
||||||
|
public bool QueryHostSupportsTransformFeedback() => _context.Capabilities.SupportsTransformFeedback;
|
||||||
|
|
||||||
public bool QueryHostSupportsViewportIndexVertexTessellation() => _context.Capabilities.SupportsViewportIndexVertexTessellation;
|
public bool QueryHostSupportsViewportIndexVertexTessellation() => _context.Capabilities.SupportsViewportIndexVertexTessellation;
|
||||||
|
|
||||||
public bool QueryHostSupportsViewportMask() => _context.Capabilities.SupportsViewportMask;
|
public bool QueryHostSupportsViewportMask() => _context.Capabilities.SupportsViewportMask;
|
||||||
|
@ -24,13 +24,5 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// Total of images used by the shaders.
|
/// Total of images used by the shaders.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ImagesCount;
|
public int ImagesCount;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of the shader resource counts class.
|
|
||||||
/// </summary>
|
|
||||||
public ResourceCounts()
|
|
||||||
{
|
|
||||||
UniformBuffersCount = 1; // The first binding is reserved for the support buffer.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -362,7 +362,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
TranslatorContext previousStage = null;
|
TranslatorContext previousStage = null;
|
||||||
|
|
||||||
ShaderInfoBuilder infoBuilder = new ShaderInfoBuilder(_context);
|
ShaderInfoBuilder infoBuilder = new ShaderInfoBuilder(_context, transformFeedbackDescriptors != null);
|
||||||
|
|
||||||
for (int stageIndex = 0; stageIndex < Constants.ShaderStages; stageIndex++)
|
for (int stageIndex = 0; stageIndex < Constants.ShaderStages; stageIndex++)
|
||||||
{
|
{
|
||||||
|
@ -16,15 +16,24 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
private const int TextureSetIndex = 2;
|
private const int TextureSetIndex = 2;
|
||||||
private const int ImageSetIndex = 3;
|
private const int ImageSetIndex = 3;
|
||||||
|
|
||||||
private const ResourceStages SupportBufferStags =
|
private const ResourceStages SupportBufferStages =
|
||||||
ResourceStages.Compute |
|
ResourceStages.Compute |
|
||||||
ResourceStages.Vertex |
|
ResourceStages.Vertex |
|
||||||
ResourceStages.Fragment;
|
ResourceStages.Fragment;
|
||||||
|
|
||||||
|
private const ResourceStages VtgStages =
|
||||||
|
ResourceStages.Vertex |
|
||||||
|
ResourceStages.TessellationControl |
|
||||||
|
ResourceStages.TessellationEvaluation |
|
||||||
|
ResourceStages.Geometry;
|
||||||
|
|
||||||
private readonly GpuContext _context;
|
private readonly GpuContext _context;
|
||||||
|
|
||||||
private int _fragmentOutputMap;
|
private int _fragmentOutputMap;
|
||||||
|
|
||||||
|
private readonly int _reservedConstantBuffers;
|
||||||
|
private readonly int _reservedStorageBuffers;
|
||||||
|
|
||||||
private readonly List<ResourceDescriptor>[] _resourceDescriptors;
|
private readonly List<ResourceDescriptor>[] _resourceDescriptors;
|
||||||
private readonly List<ResourceUsage>[] _resourceUsages;
|
private readonly List<ResourceUsage>[] _resourceUsages;
|
||||||
|
|
||||||
@ -32,7 +41,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// Creates a new shader info builder.
|
/// Creates a new shader info builder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">GPU context that owns the shaders that will be added to the builder</param>
|
/// <param name="context">GPU context that owns the shaders that will be added to the builder</param>
|
||||||
public ShaderInfoBuilder(GpuContext context)
|
/// <param name="tfEnabled">Indicates if the graphics shader is used with transform feedback enabled</param>
|
||||||
|
public ShaderInfoBuilder(GpuContext context, bool tfEnabled)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
|
|
||||||
@ -47,7 +57,22 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
_resourceUsages[index] = new();
|
_resourceUsages[index] = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
AddDescriptor(SupportBufferStags, ResourceType.UniformBuffer, UniformSetIndex, 0, 1);
|
AddDescriptor(SupportBufferStages, ResourceType.UniformBuffer, UniformSetIndex, 0, 1);
|
||||||
|
|
||||||
|
_reservedConstantBuffers = 1; // For the support buffer.
|
||||||
|
|
||||||
|
if (!context.Capabilities.SupportsTransformFeedback && tfEnabled)
|
||||||
|
{
|
||||||
|
_reservedStorageBuffers = 5;
|
||||||
|
|
||||||
|
AddDescriptor(VtgStages, ResourceType.StorageBuffer, StorageSetIndex, 0, 5);
|
||||||
|
AddUsage(VtgStages, ResourceType.StorageBuffer, ResourceAccess.Read, StorageSetIndex, 0, 1);
|
||||||
|
AddUsage(VtgStages, ResourceType.StorageBuffer, ResourceAccess.Write, StorageSetIndex, 1, 4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_reservedStorageBuffers = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -86,8 +111,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
int texturesPerStage = (int)_context.Capabilities.MaximumTexturesPerStage;
|
int texturesPerStage = (int)_context.Capabilities.MaximumTexturesPerStage;
|
||||||
int imagesPerStage = (int)_context.Capabilities.MaximumImagesPerStage;
|
int imagesPerStage = (int)_context.Capabilities.MaximumImagesPerStage;
|
||||||
|
|
||||||
int uniformBinding = 1 + stageIndex * uniformsPerStage;
|
int uniformBinding = _reservedConstantBuffers + stageIndex * uniformsPerStage;
|
||||||
int storageBinding = stageIndex * storagesPerStage;
|
int storageBinding = _reservedStorageBuffers + stageIndex * storagesPerStage;
|
||||||
int textureBinding = stageIndex * texturesPerStage * 2;
|
int textureBinding = stageIndex * texturesPerStage * 2;
|
||||||
int imageBinding = stageIndex * imagesPerStage * 2;
|
int imageBinding = stageIndex * imagesPerStage * 2;
|
||||||
|
|
||||||
@ -133,6 +158,23 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
AddDescriptor(stages, type2, setIndex, binding + count, count);
|
AddDescriptor(stages, type2, setIndex, binding + count, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds buffer usage information to the list of usages.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stages">Shader stages where the resource is used</param>
|
||||||
|
/// <param name="type">Type of the resource</param>
|
||||||
|
/// <param name="access">How the resource is accessed by the shader stages where it is used</param>
|
||||||
|
/// <param name="setIndex">Descriptor set number where the resource will be bound</param>
|
||||||
|
/// <param name="binding">Binding number where the resource will be bound</param>
|
||||||
|
/// <param name="count">Number of resources bound at the binding location</param>
|
||||||
|
private void AddUsage(ResourceStages stages, ResourceType type, ResourceAccess access, int setIndex, int binding, int count)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < count; index++)
|
||||||
|
{
|
||||||
|
_resourceUsages[setIndex].Add(new ResourceUsage(binding + index, type, stages, access));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds buffer usage information to the list of usages.
|
/// Adds buffer usage information to the list of usages.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -212,10 +254,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <param name="context">GPU context that owns the shaders</param>
|
/// <param name="context">GPU context that owns the shaders</param>
|
||||||
/// <param name="programs">Shaders from the disk cache</param>
|
/// <param name="programs">Shaders from the disk cache</param>
|
||||||
/// <param name="pipeline">Optional pipeline for background compilation</param>
|
/// <param name="pipeline">Optional pipeline for background compilation</param>
|
||||||
|
/// <param name="tfEnabled">Indicates if the graphics shader is used with transform feedback enabled</param>
|
||||||
/// <returns>Shader information</returns>
|
/// <returns>Shader information</returns>
|
||||||
public static ShaderInfo BuildForCache(GpuContext context, IEnumerable<CachedShaderStage> programs, ProgramPipelineState? pipeline)
|
public static ShaderInfo BuildForCache(
|
||||||
|
GpuContext context,
|
||||||
|
IEnumerable<CachedShaderStage> programs,
|
||||||
|
ProgramPipelineState? pipeline,
|
||||||
|
bool tfEnabled)
|
||||||
{
|
{
|
||||||
ShaderInfoBuilder builder = new ShaderInfoBuilder(context);
|
ShaderInfoBuilder builder = new ShaderInfoBuilder(context, tfEnabled);
|
||||||
|
|
||||||
foreach (CachedShaderStage program in programs)
|
foreach (CachedShaderStage program in programs)
|
||||||
{
|
{
|
||||||
@ -237,7 +284,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <returns>Shader information</returns>
|
/// <returns>Shader information</returns>
|
||||||
public static ShaderInfo BuildForCompute(GpuContext context, ShaderProgramInfo info, bool fromCache = false)
|
public static ShaderInfo BuildForCompute(GpuContext context, ShaderProgramInfo info, bool fromCache = false)
|
||||||
{
|
{
|
||||||
ShaderInfoBuilder builder = new ShaderInfoBuilder(context);
|
ShaderInfoBuilder builder = new ShaderInfoBuilder(context, tfEnabled: false);
|
||||||
|
|
||||||
builder.AddStageInfo(info);
|
builder.AddStageInfo(info);
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
|
|||||||
private readonly AVCodec_decode _decodeFrame;
|
private readonly AVCodec_decode _decodeFrame;
|
||||||
private static readonly FFmpegApi.av_log_set_callback_callback _logFunc;
|
private static readonly FFmpegApi.av_log_set_callback_callback _logFunc;
|
||||||
private readonly AVCodec* _codec;
|
private readonly AVCodec* _codec;
|
||||||
private AVPacket* _packet;
|
private readonly AVPacket* _packet;
|
||||||
private AVCodecContext* _context;
|
private readonly AVCodecContext* _context;
|
||||||
|
|
||||||
public FFmpegContext(AVCodecID codecId)
|
public FFmpegContext(AVCodecID codecId)
|
||||||
{
|
{
|
||||||
@ -164,7 +164,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
|
|||||||
FFmpegApi.av_packet_free(ppPacket);
|
FFmpegApi.av_packet_free(ppPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
FFmpegApi.avcodec_close(_context);
|
_ = FFmpegApi.avcodec_close(_context);
|
||||||
|
|
||||||
fixed (AVCodecContext** ppContext = &_context)
|
fixed (AVCodecContext** ppContext = &_context)
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
|
|||||||
|
|
||||||
private readonly byte[] _workBuffer = new byte[WorkBufferSize];
|
private readonly byte[] _workBuffer = new byte[WorkBufferSize];
|
||||||
|
|
||||||
private FFmpegContext _context = new FFmpegContext(AVCodecID.AV_CODEC_ID_H264);
|
private FFmpegContext _context = new(AVCodecID.AV_CODEC_ID_H264);
|
||||||
|
|
||||||
private int _oldOutputWidth;
|
private int _oldOutputWidth;
|
||||||
private int _oldOutputHeight;
|
private int _oldOutputHeight;
|
||||||
@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
|
|||||||
byte[] output = new byte[data.Length + prep.Length];
|
byte[] output = new byte[data.Length + prep.Length];
|
||||||
|
|
||||||
prep.CopyTo(output);
|
prep.CopyTo(output);
|
||||||
data.CopyTo(new Span<byte>(output).Slice(prep.Length));
|
data.CopyTo(new Span<byte>(output)[prep.Length..]);
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
@ -84,9 +84,9 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
|
|||||||
Flush();
|
Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Span<byte> AsSpan()
|
public readonly Span<byte> AsSpan()
|
||||||
{
|
{
|
||||||
return new Span<byte>(_workBuffer).Slice(0, _offset);
|
return new Span<byte>(_workBuffer)[.._offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteU(uint value, int valueSize) => WriteBits((int)value, valueSize);
|
public void WriteU(uint value, int valueSize) => WriteBits((int)value, valueSize);
|
||||||
|
@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
|
|||||||
{
|
{
|
||||||
public static Span<byte> Reconstruct(ref H264PictureInfo pictureInfo, byte[] workBuffer)
|
public static Span<byte> Reconstruct(ref H264PictureInfo pictureInfo, byte[] workBuffer)
|
||||||
{
|
{
|
||||||
H264BitStreamWriter writer = new H264BitStreamWriter(workBuffer);
|
H264BitStreamWriter writer = new(workBuffer);
|
||||||
|
|
||||||
// Sequence Parameter Set.
|
// Sequence Parameter Set.
|
||||||
writer.WriteU(1, 24);
|
writer.WriteU(1, 24);
|
||||||
|
@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
|||||||
{
|
{
|
||||||
struct AVCodec
|
struct AVCodec
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
public unsafe byte* Name;
|
public unsafe byte* Name;
|
||||||
public unsafe byte* LongName;
|
public unsafe byte* LongName;
|
||||||
public int Type;
|
public int Type;
|
||||||
|
@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
|||||||
{
|
{
|
||||||
struct AVCodec501
|
struct AVCodec501
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
public unsafe byte* Name;
|
public unsafe byte* Name;
|
||||||
public unsafe byte* LongName;
|
public unsafe byte* LongName;
|
||||||
public int Type;
|
public int Type;
|
||||||
|
@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
|||||||
{
|
{
|
||||||
struct AVCodecContext
|
struct AVCodecContext
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
public unsafe IntPtr AvClass;
|
public unsafe IntPtr AvClass;
|
||||||
public int LogLevelOffset;
|
public int LogLevelOffset;
|
||||||
public int CodecType;
|
public int CodecType;
|
||||||
|
@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
|||||||
{
|
{
|
||||||
struct AVFrame
|
struct AVFrame
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
public Array8<IntPtr> Data;
|
public Array8<IntPtr> Data;
|
||||||
public Array8<int> LineSize;
|
public Array8<int> LineSize;
|
||||||
public IntPtr ExtendedData;
|
public IntPtr ExtendedData;
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
using System;
|
using AVBufferRef = System.IntPtr;
|
||||||
|
|
||||||
using AVBufferRef = System.IntPtr;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
||||||
{
|
{
|
||||||
struct AVPacket
|
struct AVPacket
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
public unsafe AVBufferRef* Buf;
|
public unsafe AVBufferRef* Buf;
|
||||||
public long Pts;
|
public long Pts;
|
||||||
public long Dts;
|
public long Dts;
|
||||||
@ -14,11 +12,11 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
|||||||
public int Size;
|
public int Size;
|
||||||
public int StreamIndex;
|
public int StreamIndex;
|
||||||
public int Flags;
|
public int Flags;
|
||||||
public IntPtr SizeData;
|
public AVBufferRef SizeData;
|
||||||
public int SizeDataElems;
|
public int SizeDataElems;
|
||||||
public long Duration;
|
public long Duration;
|
||||||
public long Position;
|
public long Position;
|
||||||
public IntPtr Opaque;
|
public AVBufferRef Opaque;
|
||||||
public unsafe AVBufferRef* OpaqueRef;
|
public unsafe AVBufferRef* OpaqueRef;
|
||||||
public AVRational TimeBase;
|
public AVRational TimeBase;
|
||||||
#pragma warning restore CS0649
|
#pragma warning restore CS0649
|
||||||
|
@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
|||||||
{
|
{
|
||||||
struct FFCodec<T> where T : struct
|
struct FFCodec<T> where T : struct
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
public T Base;
|
public T Base;
|
||||||
public int CapsInternalOrCbType;
|
public int CapsInternalOrCbType;
|
||||||
public int PrivDataSize;
|
public int PrivDataSize;
|
||||||
|
@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
|||||||
{
|
{
|
||||||
struct FFCodecLegacy<T> where T : struct
|
struct FFCodecLegacy<T> where T : struct
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
public T Base;
|
public T Base;
|
||||||
public uint CapsInternalOrCbType;
|
public uint CapsInternalOrCbType;
|
||||||
public int PrivDataSize;
|
public int PrivDataSize;
|
||||||
|
@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
|||||||
public const string AvCodecLibraryName = "avcodec";
|
public const string AvCodecLibraryName = "avcodec";
|
||||||
public const string AvUtilLibraryName = "avutil";
|
public const string AvUtilLibraryName = "avutil";
|
||||||
|
|
||||||
private static readonly Dictionary<string, (int, int)> _librariesWhitelist = new Dictionary<string, (int, int)>
|
private static readonly Dictionary<string, (int, int)> _librariesWhitelist = new()
|
||||||
{
|
{
|
||||||
{ AvCodecLibraryName, (58, 59) },
|
{ AvCodecLibraryName, (58, 59) },
|
||||||
{ AvUtilLibraryName, (56, 57) }
|
{ AvUtilLibraryName, (56, 57) }
|
||||||
@ -61,9 +61,8 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
|||||||
{
|
{
|
||||||
NativeLibrary.SetDllImportResolver(typeof(FFmpegApi).Assembly, (name, assembly, path) =>
|
NativeLibrary.SetDllImportResolver(typeof(FFmpegApi).Assembly, (name, assembly, path) =>
|
||||||
{
|
{
|
||||||
IntPtr handle;
|
|
||||||
|
|
||||||
if (name == AvUtilLibraryName && TryLoadWhitelistedLibrary(AvUtilLibraryName, assembly, path, out handle))
|
if (name == AvUtilLibraryName && TryLoadWhitelistedLibrary(AvUtilLibraryName, assembly, path, out nint handle))
|
||||||
{
|
{
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,9 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
|
|||||||
public int RequestedWidth { get; }
|
public int RequestedWidth { get; }
|
||||||
public int RequestedHeight { get; }
|
public int RequestedHeight { get; }
|
||||||
|
|
||||||
public Plane YPlane => new Plane((IntPtr)Frame->Data[0], Stride * Height);
|
public Plane YPlane => new((IntPtr)Frame->Data[0], Stride * Height);
|
||||||
public Plane UPlane => new Plane((IntPtr)Frame->Data[1], UvStride * UvHeight);
|
public Plane UPlane => new((IntPtr)Frame->Data[1], UvStride * UvHeight);
|
||||||
public Plane VPlane => new Plane((IntPtr)Frame->Data[2], UvStride * UvHeight);
|
public Plane VPlane => new((IntPtr)Frame->Data[2], UvStride * UvHeight);
|
||||||
|
|
||||||
public FrameField Field => Frame->InterlacedFrame != 0 ? FrameField.Interlaced : FrameField.Progressive;
|
public FrameField Field => Frame->InterlacedFrame != 0 ? FrameField.Interlaced : FrameField.Progressive;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Vp8
|
|||||||
{
|
{
|
||||||
public bool IsHardwareAccelerated => false;
|
public bool IsHardwareAccelerated => false;
|
||||||
|
|
||||||
private readonly FFmpegContext _context = new FFmpegContext(AVCodecID.AV_CODEC_ID_VP8);
|
private readonly FFmpegContext _context = new(AVCodecID.AV_CODEC_ID_VP8);
|
||||||
|
|
||||||
public ISurface CreateSurface(int width, int height)
|
public ISurface CreateSurface(int width, int height)
|
||||||
{
|
{
|
||||||
@ -43,7 +43,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Vp8
|
|||||||
frame[9] = (byte)((pictureInfo.FrameHeight >> 8) & 0x3F);
|
frame[9] = (byte)((pictureInfo.FrameHeight >> 8) & 0x3F);
|
||||||
}
|
}
|
||||||
|
|
||||||
bitstream.CopyTo(new Span<byte>(frame).Slice(uncompHeaderSize));
|
bitstream.CopyTo(new Span<byte>(frame)[uncompHeaderSize..]);
|
||||||
|
|
||||||
return _context.DecodeFrame(outSurf, frame) == 0;
|
return _context.DecodeFrame(outSurf, frame) == 0;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ namespace Ryujinx.Graphics.Nvdec.Image
|
|||||||
int width,
|
int width,
|
||||||
int height)
|
int height)
|
||||||
{
|
{
|
||||||
OffsetCalculator calc = new OffsetCalculator(width, height, 0, false, 2, 2);
|
OffsetCalculator calc = new(width, height, 0, false, 2, 2);
|
||||||
|
|
||||||
if (Sse2.IsSupported)
|
if (Sse2.IsSupported)
|
||||||
{
|
{
|
||||||
|
@ -60,7 +60,7 @@ namespace Ryujinx.Graphics.Nvdec.Image
|
|||||||
|
|
||||||
WriteLuma(
|
WriteLuma(
|
||||||
lumaBottom.Memory.Span,
|
lumaBottom.Memory.Span,
|
||||||
surface.YPlane.AsSpan().Slice(surface.Stride),
|
surface.YPlane.AsSpan()[surface.Stride..],
|
||||||
surface.Stride * 2,
|
surface.Stride * 2,
|
||||||
surface.Width,
|
surface.Width,
|
||||||
surface.Height / 2);
|
surface.Height / 2);
|
||||||
@ -80,8 +80,8 @@ namespace Ryujinx.Graphics.Nvdec.Image
|
|||||||
|
|
||||||
WriteChroma(
|
WriteChroma(
|
||||||
chromaBottom.Memory.Span,
|
chromaBottom.Memory.Span,
|
||||||
surface.UPlane.AsSpan().Slice(surface.UvStride),
|
surface.UPlane.AsSpan()[surface.UvStride..],
|
||||||
surface.VPlane.AsSpan().Slice(surface.UvStride),
|
surface.VPlane.AsSpan()[surface.UvStride..],
|
||||||
surface.UvStride * 2,
|
surface.UvStride * 2,
|
||||||
surface.UvWidth,
|
surface.UvWidth,
|
||||||
surface.UvHeight / 2);
|
surface.UvHeight / 2);
|
||||||
@ -100,7 +100,7 @@ namespace Ryujinx.Graphics.Nvdec.Image
|
|||||||
int width,
|
int width,
|
||||||
int height)
|
int height)
|
||||||
{
|
{
|
||||||
OffsetCalculator calc = new OffsetCalculator(width, height, 0, false, 2, 2);
|
OffsetCalculator calc = new(width, height, 0, false, 2, 2);
|
||||||
|
|
||||||
if (Sse2.IsSupported)
|
if (Sse2.IsSupported)
|
||||||
{
|
{
|
||||||
|
@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Nvdec
|
|||||||
private readonly DeviceState<NvdecRegisters> _state;
|
private readonly DeviceState<NvdecRegisters> _state;
|
||||||
|
|
||||||
private long _currentId;
|
private long _currentId;
|
||||||
private ConcurrentDictionary<long, NvdecDecoderContext> _contexts;
|
private readonly ConcurrentDictionary<long, NvdecDecoderContext> _contexts;
|
||||||
private NvdecDecoderContext _currentContext;
|
private NvdecDecoderContext _currentContext;
|
||||||
|
|
||||||
public NvdecDevice(MemoryManager gmm)
|
public NvdecDevice(MemoryManager gmm)
|
||||||
|
@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Nvdec
|
|||||||
{
|
{
|
||||||
struct NvdecRegisters
|
struct NvdecRegisters
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
public Array64<uint> Reserved0;
|
public Array64<uint> Reserved0;
|
||||||
public uint Nop;
|
public uint Nop;
|
||||||
public Array63<uint> Reserved104;
|
public Array63<uint> Reserved104;
|
||||||
|
@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Nvdec
|
|||||||
{
|
{
|
||||||
struct NvdecStatus
|
struct NvdecStatus
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
public uint MbsCorrectlyDecoded;
|
public uint MbsCorrectlyDecoded;
|
||||||
public uint MbsInError;
|
public uint MbsInError;
|
||||||
public uint Reserved;
|
public uint Reserved;
|
||||||
|
@ -5,8 +5,9 @@ namespace Ryujinx.Graphics.Nvdec.Types.H264
|
|||||||
{
|
{
|
||||||
struct PictureInfo
|
struct PictureInfo
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0169, CS0649
|
#pragma warning disable IDE0051, CS0169, CS0649 // Remove unused private member
|
||||||
Array18<uint> Unknown0;
|
Array18<uint> Unknown0;
|
||||||
|
#pragma warning restore IDE0051
|
||||||
public uint BitstreamSize;
|
public uint BitstreamSize;
|
||||||
public uint NumSlices;
|
public uint NumSlices;
|
||||||
public uint Unknown50;
|
public uint Unknown50;
|
||||||
@ -50,24 +51,24 @@ namespace Ryujinx.Graphics.Nvdec.Types.H264
|
|||||||
public Array10<uint> Unknown2D4;
|
public Array10<uint> Unknown2D4;
|
||||||
#pragma warning restore CS0169, CS0649
|
#pragma warning restore CS0169, CS0649
|
||||||
|
|
||||||
public bool MbAdaptiveFrameFieldFlag => (Flags & (1 << 0)) != 0;
|
public readonly bool MbAdaptiveFrameFieldFlag => (Flags & (1 << 0)) != 0;
|
||||||
public bool Direct8x8InferenceFlag => (Flags & (1 << 1)) != 0;
|
public readonly bool Direct8x8InferenceFlag => (Flags & (1 << 1)) != 0;
|
||||||
public bool WeightedPredFlag => (Flags & (1 << 2)) != 0;
|
public readonly bool WeightedPredFlag => (Flags & (1 << 2)) != 0;
|
||||||
public bool ConstrainedIntraPredFlag => (Flags & (1 << 3)) != 0;
|
public readonly bool ConstrainedIntraPredFlag => (Flags & (1 << 3)) != 0;
|
||||||
public bool IsReference => (Flags & (1 << 4)) != 0;
|
public readonly bool IsReference => (Flags & (1 << 4)) != 0;
|
||||||
public bool FieldPicFlag => (Flags & (1 << 5)) != 0;
|
public readonly bool FieldPicFlag => (Flags & (1 << 5)) != 0;
|
||||||
public bool BottomFieldFlag => (Flags & (1 << 6)) != 0;
|
public readonly bool BottomFieldFlag => (Flags & (1 << 6)) != 0;
|
||||||
public uint Log2MaxFrameNumMinus4 => (uint)(Flags >> 8) & 0xf;
|
public readonly uint Log2MaxFrameNumMinus4 => (uint)(Flags >> 8) & 0xf;
|
||||||
public ushort ChromaFormatIdc => (ushort)((Flags >> 12) & 3);
|
public readonly ushort ChromaFormatIdc => (ushort)((Flags >> 12) & 3);
|
||||||
public uint PicOrderCntType => (uint)(Flags >> 14) & 3;
|
public readonly uint PicOrderCntType => (uint)(Flags >> 14) & 3;
|
||||||
public int PicInitQpMinus26 => ExtractSx(Flags, 16, 6);
|
public readonly int PicInitQpMinus26 => ExtractSx(Flags, 16, 6);
|
||||||
public int ChromaQpIndexOffset => ExtractSx(Flags, 22, 5);
|
public readonly int ChromaQpIndexOffset => ExtractSx(Flags, 22, 5);
|
||||||
public int SecondChromaQpIndexOffset => ExtractSx(Flags, 27, 5);
|
public readonly int SecondChromaQpIndexOffset => ExtractSx(Flags, 27, 5);
|
||||||
public uint WeightedBipredIdc => (uint)(Flags >> 32) & 3;
|
public readonly uint WeightedBipredIdc => (uint)(Flags >> 32) & 3;
|
||||||
public uint OutputSurfaceIndex => (uint)(Flags >> 34) & 0x7f;
|
public readonly uint OutputSurfaceIndex => (uint)(Flags >> 34) & 0x7f;
|
||||||
public uint ColIndex => (uint)(Flags >> 41) & 0x1f;
|
public readonly uint ColIndex => (uint)(Flags >> 41) & 0x1f;
|
||||||
public ushort FrameNum => (ushort)(Flags >> 46);
|
public readonly ushort FrameNum => (ushort)(Flags >> 46);
|
||||||
public bool QpprimeYZeroTransformBypassFlag => (Flags2 & (1 << 1)) != 0;
|
public readonly bool QpprimeYZeroTransformBypassFlag => (Flags2 & (1 << 1)) != 0;
|
||||||
|
|
||||||
private static int ExtractSx(ulong packed, int lsb, int length)
|
private static int ExtractSx(ulong packed, int lsb, int length)
|
||||||
{
|
{
|
||||||
|
@ -4,12 +4,12 @@ namespace Ryujinx.Graphics.Nvdec.Types.H264
|
|||||||
{
|
{
|
||||||
struct ReferenceFrame
|
struct ReferenceFrame
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
public uint Flags;
|
public uint Flags;
|
||||||
public Array2<uint> FieldOrderCnt;
|
public Array2<uint> FieldOrderCnt;
|
||||||
public uint FrameNum;
|
public uint FrameNum;
|
||||||
#pragma warning restore CS0649
|
#pragma warning restore CS0649
|
||||||
|
|
||||||
public uint OutputSurfaceIndex => (uint)Flags & 0x7f;
|
public readonly uint OutputSurfaceIndex => (uint)Flags & 0x7f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Nvdec.Types.Vp8
|
|||||||
{
|
{
|
||||||
struct PictureInfo
|
struct PictureInfo
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
public Array13<uint> Unknown0;
|
public Array13<uint> Unknown0;
|
||||||
public uint GpTimerTimeoutValue;
|
public uint GpTimerTimeoutValue;
|
||||||
public ushort FrameWidth;
|
public ushort FrameWidth;
|
||||||
|
@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Nvdec.Types.Vp9
|
|||||||
{
|
{
|
||||||
struct EntropyProbs
|
struct EntropyProbs
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649 // Field is never assigned to
|
||||||
public Array10<Array10<Array8<byte>>> KfYModeProbE0ToE7;
|
public Array10<Array10<Array8<byte>>> KfYModeProbE0ToE7;
|
||||||
public Array10<Array10<byte>> KfYModeProbE8;
|
public Array10<Array10<byte>> KfYModeProbE8;
|
||||||
public Array3<byte> Padding384;
|
public Array3<byte> Padding384;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user