Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
32d21ddf17 | ||
|
82f90704a0 | ||
|
f978d3726a | ||
|
6f28c4abad | ||
|
105c9712c1 | ||
|
4d804ed45e | ||
|
4a27d29412 | ||
|
5bd2c58ad6 | ||
|
cf4c78b9c8 | ||
|
52aa4b6c22 | ||
|
5a02433080 | ||
|
915a0f7173 | ||
|
0cc266ff19 | ||
|
9a1b74799d | ||
|
638f3761f3 | ||
|
193ca3c9a2 | ||
|
eb0bb36bbf | ||
|
0e95a8271a | ||
|
76b474e97b | ||
|
27ee86f33b | ||
|
f7ec310231 |
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:
|
||||
workflow_dispatch:
|
||||
inputs: {}
|
||||
#push:
|
||||
# branches: [ master ]
|
||||
# paths-ignore:
|
||||
# - '.github/*'
|
||||
# - '.github/ISSUE_TEMPLATE/**'
|
||||
# - '*.yml'
|
||||
# - 'README.md'
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- '.github/*'
|
||||
- '.github/ISSUE_TEMPLATE/**'
|
||||
- '.github/**'
|
||||
- '*.yml'
|
||||
- '*.json'
|
||||
- '*.config'
|
||||
- 'README.md'
|
||||
|
||||
concurrency:
|
||||
|
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:
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- '.github/*'
|
||||
- '.github/ISSUE_TEMPLATE/**'
|
||||
- '.github/**'
|
||||
- '*.yml'
|
||||
- '*.json'
|
||||
- '*.config'
|
||||
- 'README.md'
|
||||
|
||||
concurrency: release
|
||||
|
@@ -46,7 +46,7 @@
|
||||
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.31.0" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
||||
<PackageVersion Include="System.Management" Version="7.0.1" />
|
||||
<PackageVersion Include="System.Management" Version="7.0.2" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||
<PackageVersion Include="XamlNameReferenceGenerator" Version="1.6.1" />
|
||||
</ItemGroup>
|
||||
|
@@ -168,8 +168,6 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
|
||||
Logger.StartPass(PassName.CodeGeneration);
|
||||
|
||||
//Console.Error.WriteLine(IRDumper.GetDump(cfg));
|
||||
|
||||
bool relocatable = (cctx.Options & CompilerOptions.Relocatable) != 0;
|
||||
|
||||
CodeGenContext context = new(allocResult, maxCallArgs, cfg.Blocks.Count, relocatable);
|
||||
|
@@ -179,6 +179,35 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
(uint)operation.GetSource(2).AsInt32());
|
||||
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:
|
||||
GenerateVectorUnary(
|
||||
context,
|
||||
|
@@ -19,8 +19,8 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
Add(Intrinsic.Arm64AddvV, new IntrinsicInfo(0x0e31b800u, IntrinsicType.VectorUnary));
|
||||
Add(Intrinsic.Arm64AddS, new IntrinsicInfo(0x5e208400u, IntrinsicType.ScalarBinary));
|
||||
Add(Intrinsic.Arm64AddV, new IntrinsicInfo(0x0e208400u, IntrinsicType.VectorBinary));
|
||||
Add(Intrinsic.Arm64AesdV, new IntrinsicInfo(0x4e285800u, IntrinsicType.Vector128Unary));
|
||||
Add(Intrinsic.Arm64AeseV, new IntrinsicInfo(0x4e284800u, IntrinsicType.Vector128Unary));
|
||||
Add(Intrinsic.Arm64AesdV, new IntrinsicInfo(0x4e285800u, IntrinsicType.Vector128BinaryRd));
|
||||
Add(Intrinsic.Arm64AeseV, new IntrinsicInfo(0x4e284800u, IntrinsicType.Vector128BinaryRd));
|
||||
Add(Intrinsic.Arm64AesimcV, new IntrinsicInfo(0x4e287800u, IntrinsicType.Vector128Unary));
|
||||
Add(Intrinsic.Arm64AesmcV, new IntrinsicInfo(0x4e286800u, IntrinsicType.Vector128Unary));
|
||||
Add(Intrinsic.Arm64AndV, new IntrinsicInfo(0x0e201c00u, IntrinsicType.VectorBinaryBitwise));
|
||||
|
@@ -23,6 +23,10 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
ScalarTernaryShlRd,
|
||||
ScalarTernaryShrRd,
|
||||
|
||||
Vector128Unary,
|
||||
Vector128Binary,
|
||||
Vector128BinaryRd,
|
||||
|
||||
VectorUnary,
|
||||
VectorUnaryBitwise,
|
||||
VectorUnaryByElem,
|
||||
@@ -50,9 +54,6 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
VectorTernaryShlRd,
|
||||
VectorTernaryShrRd,
|
||||
|
||||
Vector128Unary,
|
||||
Vector128Binary,
|
||||
|
||||
GetRegister,
|
||||
SetRegister
|
||||
}
|
||||
|
@@ -746,6 +746,7 @@ namespace ARMeilleure.CodeGen.Arm64
|
||||
info.Type == IntrinsicType.ScalarTernaryFPRdByElem ||
|
||||
info.Type == IntrinsicType.ScalarTernaryShlRd ||
|
||||
info.Type == IntrinsicType.ScalarTernaryShrRd ||
|
||||
info.Type == IntrinsicType.Vector128BinaryRd ||
|
||||
info.Type == IntrinsicType.VectorBinaryRd ||
|
||||
info.Type == IntrinsicType.VectorInsertByElem ||
|
||||
info.Type == IntrinsicType.VectorTernaryRd ||
|
||||
|
@@ -13,7 +13,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
enum OpCode32SimdSelMode : int
|
||||
enum OpCode32SimdSelMode
|
||||
{
|
||||
Eq = 0,
|
||||
Vs,
|
||||
|
@@ -17,7 +17,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
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());
|
||||
}
|
||||
@@ -38,7 +42,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
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());
|
||||
}
|
||||
@@ -58,7 +66,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand res;
|
||||
|
||||
if (Optimizations.UseAesni)
|
||||
if (Optimizations.UseArm64Aes)
|
||||
{
|
||||
res = context.AddIntrinsic(Intrinsic.Arm64AesimcV, n);
|
||||
}
|
||||
else if (Optimizations.UseAesni)
|
||||
{
|
||||
res = context.AddIntrinsic(Intrinsic.X86Aesimc, n);
|
||||
}
|
||||
@@ -78,7 +90,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand res;
|
||||
|
||||
if (Optimizations.UseAesni)
|
||||
if (Optimizations.UseArm64Aes)
|
||||
{
|
||||
res = context.AddIntrinsic(Intrinsic.Arm64AesmcV, n);
|
||||
}
|
||||
else if (Optimizations.UseAesni)
|
||||
{
|
||||
Operand roundKey = context.VectorZero();
|
||||
|
||||
|
@@ -17,7 +17,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
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());
|
||||
}
|
||||
@@ -38,7 +42,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
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());
|
||||
}
|
||||
@@ -58,7 +66,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand res;
|
||||
|
||||
if (Optimizations.UseAesni)
|
||||
if (Optimizations.UseArm64Aes)
|
||||
{
|
||||
res = context.AddIntrinsic(Intrinsic.Arm64AesimcV, n);
|
||||
}
|
||||
else if (Optimizations.UseAesni)
|
||||
{
|
||||
res = context.AddIntrinsic(Intrinsic.X86Aesimc, n);
|
||||
}
|
||||
@@ -78,7 +90,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand res;
|
||||
|
||||
if (Optimizations.UseAesni)
|
||||
if (Optimizations.UseArm64Aes)
|
||||
{
|
||||
res = context.AddIntrinsic(Intrinsic.Arm64AesmcV, n);
|
||||
}
|
||||
else if (Optimizations.UseAesni)
|
||||
{
|
||||
Operand roundKey = context.VectorZero();
|
||||
|
||||
|
@@ -165,7 +165,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -175,7 +175,7 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, unsigned ? Intrinsic.Arm64FcvtzuS : Intrinsic.Arm64FcvtzsS);
|
||||
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, unsigned ? Intrinsic.Arm64FcvtzuS : Intrinsic.Arm64FcvtzsS, false);
|
||||
}
|
||||
}
|
||||
else if (!roundWithFpscr && Optimizations.UseSse41)
|
||||
@@ -260,28 +260,64 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
if (Optimizations.UseAdvSimd)
|
||||
{
|
||||
if (unsigned)
|
||||
bool doubleSize = floatSize == OperandType.FP64;
|
||||
|
||||
if (doubleSize)
|
||||
{
|
||||
inst = rm switch {
|
||||
0b00 => Intrinsic.Arm64FcvtauS,
|
||||
0b01 => Intrinsic.Arm64FcvtnuS,
|
||||
0b10 => Intrinsic.Arm64FcvtpuS,
|
||||
0b11 => Intrinsic.Arm64FcvtmuS,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(rm))
|
||||
};
|
||||
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
|
||||
{
|
||||
inst = rm switch {
|
||||
0b00 => Intrinsic.Arm64FcvtasS,
|
||||
0b01 => Intrinsic.Arm64FcvtnsS,
|
||||
0b10 => Intrinsic.Arm64FcvtpsS,
|
||||
0b11 => Intrinsic.Arm64FcvtmsS,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(rm))
|
||||
};
|
||||
}
|
||||
if (unsigned)
|
||||
{
|
||||
inst = rm switch {
|
||||
0b00 => Intrinsic.Arm64FcvtauS,
|
||||
0b01 => Intrinsic.Arm64FcvtnuS,
|
||||
0b10 => Intrinsic.Arm64FcvtpuS,
|
||||
0b11 => Intrinsic.Arm64FcvtmuS,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(rm))
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
inst = rm switch {
|
||||
0b00 => Intrinsic.Arm64FcvtasS,
|
||||
0b01 => Intrinsic.Arm64FcvtnsS,
|
||||
0b10 => Intrinsic.Arm64FcvtpsS,
|
||||
0b11 => Intrinsic.Arm64FcvtmsS,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(rm))
|
||||
};
|
||||
}
|
||||
|
||||
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, inst);
|
||||
InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, inst);
|
||||
}
|
||||
}
|
||||
else if (Optimizations.UseSse41)
|
||||
{
|
||||
|
@@ -192,11 +192,10 @@ namespace ARMeilleure.Instructions
|
||||
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;
|
||||
|
||||
bool doubleSize = (op.Size & 1) != 0;
|
||||
int shift = doubleSize ? 1 : 2;
|
||||
Operand m = GetVecA32(op.Vm >> shift);
|
||||
Operand d = GetVecA32(op.Vd >> shift);
|
||||
@@ -215,8 +214,13 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
||||
|
||||
inst |= ((op.Size & 1) != 0 ? Intrinsic.Arm64VDouble : Intrinsic.Arm64VFloat) | Intrinsic.Arm64V128;
|
||||
EmitScalarUnaryOpSimd32(context, (m) => (inst == 0) ? m : context.AddIntrinsic(inst, m));
|
||||
EmitScalarUnaryOpF32(context, inst, (op.Size & 1) != 0);
|
||||
}
|
||||
|
||||
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)
|
||||
|
@@ -1,5 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
[Flags]
|
||||
enum Intrinsic : ushort
|
||||
{
|
||||
// X86 (SSE and AVX)
|
||||
|
@@ -13,6 +13,7 @@ namespace ARMeilleure
|
||||
public static bool UseUnmanagedDispatchLoop { 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 UseSseIfAvailable { get; set; } = true;
|
||||
@@ -41,6 +42,7 @@ namespace ARMeilleure
|
||||
}
|
||||
|
||||
internal static bool UseAdvSimd => UseAdvSimdIfAvailable && Arm64HardwareCapabilities.SupportsAdvSimd;
|
||||
internal static bool UseArm64Aes => UseArm64AesIfAvailable && Arm64HardwareCapabilities.SupportsAes;
|
||||
internal static bool UseArm64Pmull => UseArm64PmullIfAvailable && Arm64HardwareCapabilities.SupportsPmull;
|
||||
|
||||
internal static bool UseSse => UseSseIfAvailable && X86HardwareCapabilities.SupportsSse;
|
||||
|
@@ -78,7 +78,7 @@ namespace ARMeilleure.Signal
|
||||
private static IntPtr _signalHandlerPtr;
|
||||
private static IntPtr _signalHandlerHandle;
|
||||
|
||||
private static readonly object _lock = new object();
|
||||
private static readonly object _lock = new();
|
||||
private static bool _initialized;
|
||||
|
||||
static NativeSignalHandler()
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
enum ExecutionMode : int
|
||||
enum ExecutionMode
|
||||
{
|
||||
Aarch32Arm = 0,
|
||||
Aarch32Thumb = 1,
|
||||
|
@@ -2,6 +2,7 @@ using ARMeilleure.CodeGen;
|
||||
using ARMeilleure.CodeGen.Unwinding;
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.Native;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@@ -12,8 +13,8 @@ namespace ARMeilleure.Translation.Cache
|
||||
{
|
||||
static partial class JitCache
|
||||
{
|
||||
private const int PageSize = 4 * 1024;
|
||||
private const int PageMask = PageSize - 1;
|
||||
private static readonly int PageSize = (int)MemoryBlock.GetPageSize();
|
||||
private static readonly int PageMask = PageSize - 1;
|
||||
|
||||
private const int CodeAlignment = 4; // Bytes.
|
||||
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 object _lock = new object();
|
||||
private static readonly object _lock = new();
|
||||
private static bool _initialized;
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
|
@@ -30,7 +30,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
private const string OuterHeaderMagicString = "PTCohd\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 BackupDir = "1";
|
||||
|
@@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
|
||||
private Queue<OpenALAudioBuffer> _queuedBuffers;
|
||||
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)
|
||||
{
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.Audio.Backends.SoundIo.Native
|
||||
{
|
||||
public enum SoundIoBackend : int
|
||||
public enum SoundIoBackend
|
||||
{
|
||||
None = 0,
|
||||
Jack = 1,
|
||||
|
@@ -11,7 +11,7 @@ namespace Ryujinx.Audio
|
||||
/// <summary>
|
||||
/// Lock used to control the waiters registration.
|
||||
/// </summary>
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Events signaled when the driver played audio buffers.
|
||||
|
@@ -10,7 +10,7 @@ namespace Ryujinx.Audio.Backends.Common
|
||||
{
|
||||
private const int RingBufferAlignment = 2048;
|
||||
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
private byte[] _buffer;
|
||||
private int _size;
|
||||
|
@@ -14,12 +14,12 @@ namespace Ryujinx.Audio.Input
|
||||
/// </summary>
|
||||
public class AudioInputManager : IDisposable
|
||||
{
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Lock used for session allocation.
|
||||
/// </summary>
|
||||
private object _sessionLock = new object();
|
||||
private readonly object _sessionLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// The session ids allocation table.
|
||||
|
@@ -48,7 +48,7 @@ namespace Ryujinx.Audio.Input
|
||||
/// <summary>
|
||||
/// The lock of the parent.
|
||||
/// </summary>
|
||||
private object _parentLock;
|
||||
private readonly object _parentLock;
|
||||
|
||||
/// <summary>
|
||||
/// The dispose state.
|
||||
|
@@ -14,12 +14,12 @@ namespace Ryujinx.Audio.Output
|
||||
/// </summary>
|
||||
public class AudioOutputManager : IDisposable
|
||||
{
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Lock used for session allocation.
|
||||
/// </summary>
|
||||
private object _sessionLock = new object();
|
||||
private readonly object _sessionLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// The session ids allocation table.
|
||||
|
@@ -48,7 +48,7 @@ namespace Ryujinx.Audio.Output
|
||||
/// <summary>
|
||||
/// THe lock of the parent.
|
||||
/// </summary>
|
||||
private object _parentLock;
|
||||
private readonly object _parentLock;
|
||||
|
||||
/// <summary>
|
||||
/// The dispose state.
|
||||
|
@@ -26,7 +26,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
public class AudioRenderSystem : IDisposable
|
||||
{
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
private AudioRendererRenderingDevice _renderingDevice;
|
||||
private AudioRendererExecutionMode _executionMode;
|
||||
|
@@ -19,12 +19,12 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <summary>
|
||||
/// Lock used for session allocation.
|
||||
/// </summary>
|
||||
private object _sessionLock = new object();
|
||||
private readonly object _sessionLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Lock used to control the <see cref="AudioProcessor"/> running state.
|
||||
/// </summary>
|
||||
private object _audioProcessorLock = new object();
|
||||
private readonly object _audioProcessorLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// The session ids allocation table.
|
||||
|
@@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Server.Upsampler
|
||||
/// <summary>
|
||||
/// Global lock of the object.
|
||||
/// </summary>
|
||||
private object Lock = new object();
|
||||
private readonly object Lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// The upsamplers instances.
|
||||
|
@@ -40,6 +40,7 @@ using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Formats.Png;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using SPB.Graphics.Exceptions;
|
||||
using SPB.Graphics.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -475,11 +476,20 @@ namespace Ryujinx.Ava
|
||||
_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)
|
||||
@@ -930,7 +940,7 @@ namespace Ryujinx.Ava
|
||||
_gpuDoneEvent.Set();
|
||||
});
|
||||
|
||||
(_rendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(null);
|
||||
(_rendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(true);
|
||||
}
|
||||
|
||||
public void UpdateStatus()
|
||||
@@ -1044,7 +1054,7 @@ namespace Ryujinx.Ava
|
||||
ScreenshotRequested = true;
|
||||
break;
|
||||
case KeyboardHotkeyState.ShowUi:
|
||||
_viewModel.ShowMenuAndStatusBar = true;
|
||||
_viewModel.ShowMenuAndStatusBar = !_viewModel.ShowMenuAndStatusBar;
|
||||
break;
|
||||
case KeyboardHotkeyState.Pause:
|
||||
if (_viewModel.IsPaused)
|
||||
|
@@ -741,7 +741,7 @@ namespace Ryujinx.Modules
|
||||
var files = Directory.EnumerateFiles(HomeDir); // All files directly in base dir.
|
||||
|
||||
// Determine and exclude user files only when the updater is running, not when cleaning old files
|
||||
if (_running)
|
||||
if (_running && !OperatingSystem.IsMacOS())
|
||||
{
|
||||
// Compare the loose files in base directory against the loose files from the incoming update, and store foreign ones in a user list.
|
||||
var oldFiles = Directory.EnumerateFiles(HomeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
|
||||
|
@@ -123,7 +123,7 @@ namespace Ryujinx.Ava.UI.Renderer
|
||||
}
|
||||
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;
|
||||
|
@@ -1,9 +1,11 @@
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.OpenGL;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using SPB.Graphics;
|
||||
using SPB.Graphics.Exceptions;
|
||||
using SPB.Graphics.OpenGL;
|
||||
using SPB.Platform;
|
||||
using SPB.Platform.WGL;
|
||||
@@ -18,8 +20,6 @@ namespace Ryujinx.Ava.UI.Renderer
|
||||
|
||||
public OpenGLContextBase Context { get; set; }
|
||||
|
||||
public EmbeddedWindowOpenGL() { }
|
||||
|
||||
protected override void OnWindowDestroying()
|
||||
{
|
||||
Context.Dispose();
|
||||
@@ -62,14 +62,21 @@ namespace Ryujinx.Ava.UI.Renderer
|
||||
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)
|
||||
{
|
||||
Context?.MakeCurrent(window);
|
||||
Logger.Warning?.Print(LogClass.Ui, $"Failed to {(!unbind ? "bind" : "unbind")} OpenGL context: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
public void SwapBuffers()
|
||||
|
@@ -96,7 +96,7 @@ namespace Ryujinx.Common.Configuration
|
||||
if (OperatingSystem.IsMacOS() && Mode == LaunchMode.UserProfile)
|
||||
{
|
||||
string oldConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), DefaultBaseDir);
|
||||
if (Path.Exists(oldConfigPath) && !Path.Exists(BaseDirPath))
|
||||
if (Path.Exists(oldConfigPath) && !IsPathSymlink(oldConfigPath) && !Path.Exists(BaseDirPath))
|
||||
{
|
||||
CopyDirectory(oldConfigPath, BaseDirPath);
|
||||
Directory.Delete(oldConfigPath, true);
|
||||
@@ -115,6 +115,14 @@ namespace Ryujinx.Common.Configuration
|
||||
Directory.CreateDirectory(KeysDirPath = Path.Combine(BaseDirPath, KeysDir));
|
||||
}
|
||||
|
||||
// Check if existing old baseDirPath is a symlink, to prevent possible errors.
|
||||
// Should be removed, when the existance of the old directory isn't checked anymore.
|
||||
private static bool IsPathSymlink(string path)
|
||||
{
|
||||
FileAttributes attributes = File.GetAttributes(path);
|
||||
return (attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint;
|
||||
}
|
||||
|
||||
private static void CopyDirectory(string sourceDir, string destinationDir)
|
||||
{
|
||||
var dir = new DirectoryInfo(sourceDir);
|
||||
|
@@ -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
|
||||
[Flags]
|
||||
[JsonConverter(typeof(TypedStringEnumConverter<ControllerType>))]
|
||||
public enum ControllerType : int
|
||||
public enum ControllerType
|
||||
{
|
||||
None,
|
||||
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
|
||||
[JsonConverter(typeof(TypedStringEnumConverter<PlayerIndex>))]
|
||||
public enum PlayerIndex : int
|
||||
public enum PlayerIndex
|
||||
{
|
||||
Player1 = 0,
|
||||
Player2 = 1,
|
||||
|
@@ -24,6 +24,24 @@ namespace Ryujinx.Common.Memory
|
||||
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)
|
||||
{
|
||||
ReadOnlySpan<byte> data = _input.Slice(0, size);
|
||||
|
@@ -28,6 +28,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
public readonly bool SupportsFragmentShaderOrderingIntel;
|
||||
public readonly bool SupportsGeometryShader;
|
||||
public readonly bool SupportsGeometryShaderPassthrough;
|
||||
public readonly bool SupportsTransformFeedback;
|
||||
public readonly bool SupportsImageLoadFormatted;
|
||||
public readonly bool SupportsLayerVertexTessellation;
|
||||
public readonly bool SupportsMismatchingViewFormat;
|
||||
@@ -77,6 +78,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
bool supportsFragmentShaderOrderingIntel,
|
||||
bool supportsGeometryShader,
|
||||
bool supportsGeometryShaderPassthrough,
|
||||
bool supportsTransformFeedback,
|
||||
bool supportsImageLoadFormatted,
|
||||
bool supportsLayerVertexTessellation,
|
||||
bool supportsMismatchingViewFormat,
|
||||
@@ -122,6 +124,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
SupportsFragmentShaderOrderingIntel = supportsFragmentShaderOrderingIntel;
|
||||
SupportsGeometryShader = supportsGeometryShader;
|
||||
SupportsGeometryShaderPassthrough = supportsGeometryShaderPassthrough;
|
||||
SupportsTransformFeedback = supportsTransformFeedback;
|
||||
SupportsImageLoadFormatted = supportsImageLoadFormatted;
|
||||
SupportsLayerVertexTessellation = supportsLayerVertexTessellation;
|
||||
SupportsMismatchingViewFormat = supportsMismatchingViewFormat;
|
||||
|
@@ -56,7 +56,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
private int _refConsumerPtr;
|
||||
|
||||
private Action _interruptAction;
|
||||
private object _interruptLock = new();
|
||||
private readonly object _interruptLock = new();
|
||||
|
||||
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
|
||||
|
||||
|
@@ -539,6 +539,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
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)
|
||||
{
|
||||
_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.SetInstancedDrawVertexCount(_instancedIndexCount);
|
||||
|
||||
_context.Renderer.Pipeline.DrawIndexed(
|
||||
_instancedIndexCount,
|
||||
_instanceIndex + 1,
|
||||
@@ -685,6 +695,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
}
|
||||
else
|
||||
{
|
||||
_channel.BufferManager.SetInstancedDrawVertexCount(_instancedDrawStateCount);
|
||||
|
||||
_context.Renderer.Pipeline.Draw(
|
||||
_instancedDrawStateCount,
|
||||
_instanceIndex + 1,
|
||||
|
@@ -269,7 +269,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_prevFirstVertex = _state.State.FirstVertex;
|
||||
}
|
||||
|
||||
bool tfEnable = _state.State.TfEnable;
|
||||
bool tfEnable = _state.State.TfEnable && _context.Capabilities.SupportsTransformFeedback;
|
||||
|
||||
if (!tfEnable && _prevTfEnable)
|
||||
{
|
||||
@@ -1367,6 +1367,22 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_vsUsesDrawParameters = gs.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
||||
_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)
|
||||
{
|
||||
UpdateUserClipState();
|
||||
|
@@ -6,6 +6,7 @@ using Ryujinx.Graphics.Shader;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
@@ -14,12 +15,17 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// </summary>
|
||||
class BufferManager
|
||||
{
|
||||
private const int TfInfoVertexCountOffset = Constants.TotalTransformFeedbackBuffers * sizeof(int);
|
||||
private const int TfInfoBufferSize = TfInfoVertexCountOffset + sizeof(int);
|
||||
|
||||
private readonly GpuContext _context;
|
||||
private readonly GpuChannel _channel;
|
||||
|
||||
private int _unalignedStorageBuffers;
|
||||
public bool HasUnalignedStorageBuffers => _unalignedStorageBuffers > 0;
|
||||
|
||||
public bool HasTransformFeedbackOutputs { get; set; }
|
||||
|
||||
private IndexBuffer _indexBuffer;
|
||||
private readonly VertexBuffer[] _vertexBuffers;
|
||||
private readonly BufferBounds[] _transformFeedbackBuffers;
|
||||
@@ -98,6 +104,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
private readonly BuffersPerStage[] _gpStorageBuffers;
|
||||
private readonly BuffersPerStage[] _gpUniformBuffers;
|
||||
|
||||
private BufferHandle _tfInfoBuffer;
|
||||
private int[] _tfInfoData;
|
||||
|
||||
private bool _gpStorageBuffersDirty;
|
||||
private bool _gpUniformBuffersDirty;
|
||||
|
||||
@@ -137,6 +146,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
_bufferTextures = new List<BufferTextureBinding>();
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// Sets the binding points for the storage buffers bound on the compute pipeline.
|
||||
/// </summary>
|
||||
@@ -537,22 +576,75 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
_transformFeedbackBuffersDirty = false;
|
||||
|
||||
Span<BufferRange> tfbs = stackalloc BufferRange[Constants.TotalTransformFeedbackBuffers];
|
||||
|
||||
for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
|
||||
if (_context.Capabilities.SupportsTransformFeedback)
|
||||
{
|
||||
BufferBounds tfb = _transformFeedbackBuffers[index];
|
||||
Span<BufferRange> tfbs = stackalloc BufferRange[Constants.TotalTransformFeedbackBuffers];
|
||||
|
||||
if (tfb.Address == 0)
|
||||
for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
|
||||
{
|
||||
tfbs[index] = BufferRange.Empty;
|
||||
continue;
|
||||
BufferBounds tfb = _transformFeedbackBuffers[index];
|
||||
|
||||
if (tfb.Address == 0)
|
||||
{
|
||||
tfbs[index] = BufferRange.Empty;
|
||||
continue;
|
||||
}
|
||||
|
||||
tfbs[index] = bufferCache.GetBufferRange(tfb.Address, tfb.Size, write: true);
|
||||
}
|
||||
|
||||
tfbs[index] = bufferCache.GetBufferRange(tfb.Address, tfb.Size, write: true);
|
||||
_context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs);
|
||||
}
|
||||
else if (HasTransformFeedbackOutputs)
|
||||
{
|
||||
Span<int> info = _tfInfoData.AsSpan();
|
||||
Span<BufferAssignment> buffers = stackalloc BufferAssignment[Constants.TotalTransformFeedbackBuffers + 1];
|
||||
|
||||
_context.Renderer.Pipeline.SetTransformFeedbackBuffers(tfbs);
|
||||
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
|
||||
{
|
||||
|
@@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
private List<BufferMigration> _sources;
|
||||
private BufferMigration _migrationTarget;
|
||||
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Whether the modified range list has any entries or not.
|
||||
@@ -125,7 +125,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
|
||||
|
||||
if (overlap.Address > address)
|
||||
{
|
||||
// The start of the remaining region is uncovered by this overlap. Call the action for it.
|
||||
|
@@ -37,7 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
ShaderSpecializationState oldSpecState,
|
||||
ShaderSpecializationState newSpecState,
|
||||
ResourceCounts counts,
|
||||
int stageIndex) : base(context, counts, stageIndex)
|
||||
int stageIndex) : base(context, counts, stageIndex, oldSpecState.TransformFeedbackDescriptors != null)
|
||||
{
|
||||
_data = data;
|
||||
_cb1Data = cb1Data;
|
||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
private const ushort FileFormatVersionMajor = 1;
|
||||
private const ushort FileFormatVersionMinor = 2;
|
||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||
private const uint CodeGenVersion = 5044;
|
||||
private const uint CodeGenVersion = 5080;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
@@ -368,7 +368,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
|
||||
if (hostCode != null)
|
||||
{
|
||||
ShaderInfo shaderInfo = ShaderInfoBuilder.BuildForCache(context, shaders, specState.PipelineState);
|
||||
ShaderInfo shaderInfo = ShaderInfoBuilder.BuildForCache(
|
||||
context,
|
||||
shaders,
|
||||
specState.PipelineState,
|
||||
specState.TransformFeedbackDescriptors != null);
|
||||
|
||||
IProgram hostProgram;
|
||||
|
||||
|
@@ -491,7 +491,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
{
|
||||
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++)
|
||||
{
|
||||
|
@@ -30,7 +30,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
GpuContext context,
|
||||
GpuChannel channel,
|
||||
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;
|
||||
_channel = channel;
|
||||
@@ -44,7 +44,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <param name="context">GPU context</param>
|
||||
/// <param name="channel">GPU channel</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;
|
||||
_state = state;
|
||||
|
@@ -17,40 +17,56 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
private readonly ResourceCounts _resourceCounts;
|
||||
private readonly int _stageIndex;
|
||||
|
||||
private readonly int _reservedConstantBuffers;
|
||||
private readonly int _reservedStorageBuffers;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new GPU accessor.
|
||||
/// </summary>
|
||||
/// <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;
|
||||
_resourceCounts = resourceCounts;
|
||||
_stageIndex = stageIndex;
|
||||
|
||||
_reservedConstantBuffers = 1; // For the support buffer.
|
||||
_reservedStorageBuffers = !context.Capabilities.SupportsTransformFeedback && tfEnabled ? 5 : 0;
|
||||
}
|
||||
|
||||
public int QueryBindingConstantBuffer(int index)
|
||||
{
|
||||
int binding;
|
||||
|
||||
if (_context.Capabilities.Api == TargetApi.Vulkan)
|
||||
{
|
||||
// We need to start counting from 1 since binding 0 is reserved for the support uniform buffer.
|
||||
return GetBindingFromIndex(index, _context.Capabilities.MaximumUniformBuffersPerStage, "Uniform buffer") + 1;
|
||||
binding = GetBindingFromIndex(index, _context.Capabilities.MaximumUniformBuffersPerStage, "Uniform buffer");
|
||||
}
|
||||
else
|
||||
{
|
||||
return _resourceCounts.UniformBuffersCount++;
|
||||
binding = _resourceCounts.UniformBuffersCount++;
|
||||
}
|
||||
|
||||
return binding + _reservedConstantBuffers;
|
||||
}
|
||||
|
||||
public int QueryBindingStorageBuffer(int index)
|
||||
{
|
||||
int binding;
|
||||
|
||||
if (_context.Capabilities.Api == TargetApi.Vulkan)
|
||||
{
|
||||
return GetBindingFromIndex(index, _context.Capabilities.MaximumStorageBuffersPerStage, "Storage buffer");
|
||||
binding = GetBindingFromIndex(index, _context.Capabilities.MaximumStorageBuffersPerStage, "Storage buffer");
|
||||
}
|
||||
else
|
||||
{
|
||||
return _resourceCounts.StorageBuffersCount++;
|
||||
binding = _resourceCounts.StorageBuffersCount++;
|
||||
}
|
||||
|
||||
return binding + _reservedStorageBuffers;
|
||||
}
|
||||
|
||||
public int QueryBindingTexture(int index, bool isBuffer)
|
||||
@@ -149,6 +165,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
public bool QueryHostSupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
|
||||
|
||||
public bool QueryHostSupportsTransformFeedback() => _context.Capabilities.SupportsTransformFeedback;
|
||||
|
||||
public bool QueryHostSupportsViewportIndexVertexTessellation() => _context.Capabilities.SupportsViewportIndexVertexTessellation;
|
||||
|
||||
public bool QueryHostSupportsViewportMask() => _context.Capabilities.SupportsViewportMask;
|
||||
|
@@ -24,13 +24,5 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// Total of images used by the shaders.
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
ShaderInfoBuilder infoBuilder = new ShaderInfoBuilder(_context);
|
||||
ShaderInfoBuilder infoBuilder = new ShaderInfoBuilder(_context, transformFeedbackDescriptors != null);
|
||||
|
||||
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 ImageSetIndex = 3;
|
||||
|
||||
private const ResourceStages SupportBufferStags =
|
||||
private const ResourceStages SupportBufferStages =
|
||||
ResourceStages.Compute |
|
||||
ResourceStages.Vertex |
|
||||
ResourceStages.Fragment;
|
||||
|
||||
private const ResourceStages VtgStages =
|
||||
ResourceStages.Vertex |
|
||||
ResourceStages.TessellationControl |
|
||||
ResourceStages.TessellationEvaluation |
|
||||
ResourceStages.Geometry;
|
||||
|
||||
private readonly GpuContext _context;
|
||||
|
||||
private int _fragmentOutputMap;
|
||||
|
||||
private readonly int _reservedConstantBuffers;
|
||||
private readonly int _reservedStorageBuffers;
|
||||
|
||||
private readonly List<ResourceDescriptor>[] _resourceDescriptors;
|
||||
private readonly List<ResourceUsage>[] _resourceUsages;
|
||||
|
||||
@@ -32,7 +41,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// Creates a new shader info builder.
|
||||
/// </summary>
|
||||
/// <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;
|
||||
|
||||
@@ -47,7 +57,22 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
_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>
|
||||
@@ -86,8 +111,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
int texturesPerStage = (int)_context.Capabilities.MaximumTexturesPerStage;
|
||||
int imagesPerStage = (int)_context.Capabilities.MaximumImagesPerStage;
|
||||
|
||||
int uniformBinding = 1 + stageIndex * uniformsPerStage;
|
||||
int storageBinding = stageIndex * storagesPerStage;
|
||||
int uniformBinding = _reservedConstantBuffers + stageIndex * uniformsPerStage;
|
||||
int storageBinding = _reservedStorageBuffers + stageIndex * storagesPerStage;
|
||||
int textureBinding = stageIndex * texturesPerStage * 2;
|
||||
int imageBinding = stageIndex * imagesPerStage * 2;
|
||||
|
||||
@@ -133,6 +158,23 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
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>
|
||||
/// Adds buffer usage information to the list of usages.
|
||||
/// </summary>
|
||||
@@ -212,10 +254,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <param name="context">GPU context that owns the shaders</param>
|
||||
/// <param name="programs">Shaders from the disk cache</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>
|
||||
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)
|
||||
{
|
||||
@@ -237,7 +284,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
/// <returns>Shader information</returns>
|
||||
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);
|
||||
|
||||
|
@@ -153,6 +153,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
supportsFragmentShaderOrderingIntel: HwCapabilities.SupportsFragmentShaderOrdering,
|
||||
supportsGeometryShader: true,
|
||||
supportsGeometryShaderPassthrough: HwCapabilities.SupportsGeometryShaderPassthrough,
|
||||
supportsTransformFeedback: true,
|
||||
supportsImageLoadFormatted: HwCapabilities.SupportsImageLoadFormatted,
|
||||
supportsLayerVertexTessellation: HwCapabilities.SupportsShaderViewportLayerArray,
|
||||
supportsMismatchingViewFormat: HwCapabilities.SupportsMismatchingViewFormat,
|
||||
|
@@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
||||
private ulong _accumulatedCounter;
|
||||
private int _waiterCount;
|
||||
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
private Queue<BufferedQuery> _queryPool;
|
||||
private AutoResetEvent _queuedEvent = new AutoResetEvent(false);
|
||||
|
@@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
||||
private bool _hostAccessReserved = false;
|
||||
private int _refCount = 1; // Starts with a reference from the counter queue.
|
||||
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
private ulong _result = ulong.MaxValue;
|
||||
private double _divisor = 1f;
|
||||
|
||||
|
@@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
{
|
||||
private const int DisposedLiveFrames = 2;
|
||||
|
||||
private readonly object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
private readonly Dictionary<TextureCreateInfo, List<DisposedTexture>> _textures = new Dictionary<TextureCreateInfo, List<DisposedTexture>>();
|
||||
|
||||
/// <summary>
|
||||
|
@@ -10,5 +10,11 @@ namespace Ryujinx.Graphics.Shader
|
||||
public const int NvnBaseVertexByteOffset = 0x640;
|
||||
public const int NvnBaseInstanceByteOffset = 0x644;
|
||||
public const int NvnDrawIndexByteOffset = 0x648;
|
||||
|
||||
// Transform Feedback emulation.
|
||||
|
||||
public const int TfeInfoBinding = 0;
|
||||
public const int TfeBufferBaseBinding = 1;
|
||||
public const int TfeBuffersCount = 4;
|
||||
}
|
||||
}
|
@@ -1,3 +1,5 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Decoders
|
||||
{
|
||||
enum AlSize
|
||||
@@ -711,6 +713,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
||||
TexSamplerBorderColor = 22,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum VectorSelect
|
||||
{
|
||||
U8B0 = 0,
|
||||
|
@@ -1,5 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Decoders
|
||||
{
|
||||
[Flags]
|
||||
enum InstProps : ushort
|
||||
{
|
||||
None = 0,
|
||||
|
@@ -367,6 +367,15 @@ namespace Ryujinx.Graphics.Shader
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries host GPU transform feedback support.
|
||||
/// </summary>
|
||||
/// <returns>True if the GPU and driver supports transform feedback, false otherwise</returns>
|
||||
bool QueryHostSupportsTransformFeedback()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queries host support for writes to the viewport index from vertex or tessellation shader stages.
|
||||
/// </summary>
|
||||
|
@@ -1,5 +1,8 @@
|
||||
namespace Ryujinx.Graphics.Shader.Translation
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
[Flags]
|
||||
enum AggregateType
|
||||
{
|
||||
Invalid,
|
||||
|
@@ -234,6 +234,45 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
public void PrepareForVertexReturn()
|
||||
{
|
||||
if (!Config.GpuAccessor.QueryHostSupportsTransformFeedback() && Config.GpuAccessor.QueryTransformFeedbackEnabled())
|
||||
{
|
||||
Operand vertexCount = this.Load(StorageKind.StorageBuffer, Constants.TfeInfoBinding, Const(1));
|
||||
|
||||
for (int tfbIndex = 0; tfbIndex < Constants.TfeBuffersCount; tfbIndex++)
|
||||
{
|
||||
var locations = Config.GpuAccessor.QueryTransformFeedbackVaryingLocations(tfbIndex);
|
||||
var stride = Config.GpuAccessor.QueryTransformFeedbackStride(tfbIndex);
|
||||
|
||||
Operand baseOffset = this.Load(StorageKind.StorageBuffer, Constants.TfeInfoBinding, Const(0), Const(tfbIndex));
|
||||
Operand baseVertex = this.Load(StorageKind.Input, IoVariable.BaseVertex);
|
||||
Operand baseInstance = this.Load(StorageKind.Input, IoVariable.BaseInstance);
|
||||
Operand vertexIndex = this.Load(StorageKind.Input, IoVariable.VertexIndex);
|
||||
Operand instanceIndex = this.Load(StorageKind.Input, IoVariable.InstanceIndex);
|
||||
|
||||
Operand outputVertexOffset = this.ISubtract(vertexIndex, baseVertex);
|
||||
Operand outputInstanceOffset = this.ISubtract(instanceIndex, baseInstance);
|
||||
|
||||
Operand outputBaseVertex = this.IMultiply(outputInstanceOffset, vertexCount);
|
||||
|
||||
Operand vertexOffset = this.IMultiply(this.IAdd(outputBaseVertex, outputVertexOffset), Const(stride / 4));
|
||||
baseOffset = this.IAdd(baseOffset, vertexOffset);
|
||||
|
||||
for (int j = 0; j < locations.Length; j++)
|
||||
{
|
||||
byte location = locations[j];
|
||||
if (location == 0xff)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Operand offset = this.IAdd(baseOffset, Const(j));
|
||||
Operand value = Instructions.AttributeMap.GenerateAttributeLoad(this, null, location * 4, isOutput: true, isPerPatch: false);
|
||||
|
||||
this.Store(StorageKind.StorageBuffer, Constants.TfeBufferBaseBinding + tfbIndex, Const(0), offset, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.GpuAccessor.QueryViewportTransformDisable())
|
||||
{
|
||||
Operand x = this.Load(StorageKind.Output, IoVariable.Position, null, Const(0));
|
||||
|
@@ -132,6 +132,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
_transformFeedbackDefinitions = new Dictionary<TransformFeedbackVariable, TransformFeedbackOutput>();
|
||||
|
||||
TransformFeedbackEnabled =
|
||||
stage != ShaderStage.Compute &&
|
||||
gpuAccessor.QueryTransformFeedbackEnabled() &&
|
||||
gpuAccessor.QueryHostSupportsTransformFeedback();
|
||||
|
||||
UsedInputAttributesPerPatch = new HashSet<int>();
|
||||
UsedOutputAttributesPerPatch = new HashSet<int>();
|
||||
|
||||
@@ -139,6 +144,31 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
_usedImages = new Dictionary<TextureInfo, TextureMeta>();
|
||||
|
||||
ResourceManager = new ResourceManager(stage, gpuAccessor, new ShaderProperties());
|
||||
|
||||
if (!gpuAccessor.QueryHostSupportsTransformFeedback() && gpuAccessor.QueryTransformFeedbackEnabled())
|
||||
{
|
||||
StructureType tfeInfoStruct = new StructureType(new StructureField[]
|
||||
{
|
||||
new StructureField(AggregateType.Array | AggregateType.U32, "base_offset", 4),
|
||||
new StructureField(AggregateType.U32, "vertex_count")
|
||||
});
|
||||
|
||||
BufferDefinition tfeInfoBuffer = new BufferDefinition(BufferLayout.Std430, 1, Constants.TfeInfoBinding, "tfe_info", tfeInfoStruct);
|
||||
|
||||
Properties.AddStorageBuffer(Constants.TfeInfoBinding, tfeInfoBuffer);
|
||||
|
||||
StructureType tfeDataStruct = new StructureType(new StructureField[]
|
||||
{
|
||||
new StructureField(AggregateType.Array | AggregateType.U32, "data", 0)
|
||||
});
|
||||
|
||||
for (int i = 0; i < Constants.TfeBuffersCount; i++)
|
||||
{
|
||||
int binding = Constants.TfeBufferBaseBinding + i;
|
||||
BufferDefinition tfeDataBuffer = new BufferDefinition(BufferLayout.Std430, 1, binding, $"tfe_data{i}", tfeDataStruct);
|
||||
Properties.AddStorageBuffer(binding, tfeDataBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ShaderConfig(
|
||||
@@ -151,7 +181,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
ThreadsPerInputPrimitive = 1;
|
||||
OutputTopology = outputTopology;
|
||||
MaxOutputVertices = maxOutputVertices;
|
||||
TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
|
||||
}
|
||||
|
||||
public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationOptions options) : this(header.Stage, gpuAccessor, options)
|
||||
@@ -165,7 +194,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
OmapTargets = header.OmapTargets;
|
||||
OmapSampleMask = header.OmapSampleMask;
|
||||
OmapDepth = header.OmapDepth;
|
||||
TransformFeedbackEnabled = gpuAccessor.QueryTransformFeedbackEnabled();
|
||||
LastInVertexPipeline = header.Stage < ShaderStage.Fragment;
|
||||
}
|
||||
|
||||
@@ -726,7 +754,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
var descriptors = new TextureDescriptor[dict.Count];
|
||||
|
||||
int i = 0;
|
||||
foreach (var kv in dict.OrderBy(x => x.Key.Indexed).OrderBy(x => x.Key.Handle))
|
||||
foreach (var kv in dict.OrderBy(x => x.Key.Indexed).ThenBy(x => x.Key.Handle))
|
||||
{
|
||||
var info = kv.Key;
|
||||
var meta = kv.Value;
|
||||
@@ -824,4 +852,4 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
OmapTargets);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -16,9 +16,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_descriptorSets = descriptorSets;
|
||||
}
|
||||
|
||||
public void InitializeBuffers(int setIndex, int baseBinding, int countPerUnit, DescriptorType type, VkBuffer dummyBuffer)
|
||||
public void InitializeBuffers(int setIndex, int baseBinding, int count, DescriptorType type, VkBuffer dummyBuffer)
|
||||
{
|
||||
Span<DescriptorBufferInfo> infos = stackalloc DescriptorBufferInfo[countPerUnit];
|
||||
Span<DescriptorBufferInfo> infos = stackalloc DescriptorBufferInfo[count];
|
||||
|
||||
infos.Fill(new DescriptorBufferInfo()
|
||||
{
|
||||
|
@@ -596,36 +596,19 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void Initialize(CommandBufferScoped cbs, int setIndex, DescriptorSetCollection dsc)
|
||||
{
|
||||
// We don't support clearing texture descriptors currently.
|
||||
if (setIndex != PipelineBase.UniformSetIndex && setIndex != PipelineBase.StorageSetIndex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var dummyBuffer = _dummyBuffer?.GetBuffer().Get(cbs).Value ?? default;
|
||||
|
||||
uint stages = _program.Stages;
|
||||
|
||||
while (stages != 0)
|
||||
foreach (ResourceBindingSegment segment in _program.ClearSegments[setIndex])
|
||||
{
|
||||
int stage = BitOperations.TrailingZeroCount(stages);
|
||||
stages &= ~(1u << stage);
|
||||
|
||||
if (setIndex == PipelineBase.UniformSetIndex)
|
||||
{
|
||||
dsc.InitializeBuffers(
|
||||
0,
|
||||
1 + stage * Constants.MaxUniformBuffersPerStage,
|
||||
Constants.MaxUniformBuffersPerStage,
|
||||
DescriptorType.UniformBuffer,
|
||||
dummyBuffer);
|
||||
}
|
||||
else if (setIndex == PipelineBase.StorageSetIndex)
|
||||
{
|
||||
dsc.InitializeBuffers(
|
||||
0,
|
||||
stage * Constants.MaxStorageBuffersPerStage,
|
||||
Constants.MaxStorageBuffersPerStage,
|
||||
DescriptorType.StorageBuffer,
|
||||
dummyBuffer);
|
||||
}
|
||||
dsc.InitializeBuffers(0, segment.Binding, segment.Count, segment.Type.Convert(), dummyBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan.MoltenVK
|
||||
{
|
||||
enum MVKConfigLogLevel : int
|
||||
enum MVKConfigLogLevel
|
||||
{
|
||||
None = 0,
|
||||
Error = 1,
|
||||
@@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
|
||||
Debug = 4
|
||||
}
|
||||
|
||||
enum MVKConfigTraceVulkanCalls : int
|
||||
enum MVKConfigTraceVulkanCalls
|
||||
{
|
||||
None = 0,
|
||||
Enter = 1,
|
||||
@@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
|
||||
Duration = 3
|
||||
}
|
||||
|
||||
enum MVKConfigAutoGPUCaptureScope : int
|
||||
enum MVKConfigAutoGPUCaptureScope
|
||||
{
|
||||
None = 0,
|
||||
Device = 1,
|
||||
@@ -28,7 +28,7 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum MVKConfigAdvertiseExtensions : int
|
||||
enum MVKConfigAdvertiseExtensions
|
||||
{
|
||||
All = 0x00000001,
|
||||
MoltenVK = 0x00000002,
|
||||
@@ -36,7 +36,7 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
|
||||
Portability = 0x00000008
|
||||
}
|
||||
|
||||
enum MVKVkSemaphoreSupportStyle : int
|
||||
enum MVKVkSemaphoreSupportStyle
|
||||
{
|
||||
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE = 0,
|
||||
MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE = 1,
|
||||
|
@@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
private ulong _accumulatedCounter;
|
||||
private int _waiterCount;
|
||||
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
private Queue<BufferedQuery> _queryPool;
|
||||
private AutoResetEvent _queuedEvent = new AutoResetEvent(false);
|
||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
private bool _hostAccessReserved = false;
|
||||
private int _refCount = 1; // Starts with a reference from the counter queue.
|
||||
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
private ulong _result = ulong.MaxValue;
|
||||
private double _divisor = 1f;
|
||||
|
||||
|
@@ -24,6 +24,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public uint Stages { get; }
|
||||
|
||||
public ResourceBindingSegment[][] ClearSegments { get; }
|
||||
public ResourceBindingSegment[][] BindingSegments { get; }
|
||||
|
||||
public ProgramLinkStatus LinkStatus { get; private set; }
|
||||
@@ -115,6 +116,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
Stages = stages;
|
||||
|
||||
ClearSegments = BuildClearSegments(resourceLayout.Sets);
|
||||
BindingSegments = BuildBindingSegments(resourceLayout.SetUsages);
|
||||
|
||||
_compileTask = Task.CompletedTask;
|
||||
@@ -135,6 +137,60 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_firstBackgroundUse = !fromCache;
|
||||
}
|
||||
|
||||
private static ResourceBindingSegment[][] BuildClearSegments(ReadOnlyCollection<ResourceDescriptorCollection> sets)
|
||||
{
|
||||
ResourceBindingSegment[][] segments = new ResourceBindingSegment[sets.Count][];
|
||||
|
||||
for (int setIndex = 0; setIndex < sets.Count; setIndex++)
|
||||
{
|
||||
List<ResourceBindingSegment> currentSegments = new List<ResourceBindingSegment>();
|
||||
|
||||
ResourceDescriptor currentDescriptor = default;
|
||||
int currentCount = 0;
|
||||
|
||||
for (int index = 0; index < sets[setIndex].Descriptors.Count; index++)
|
||||
{
|
||||
ResourceDescriptor descriptor = sets[setIndex].Descriptors[index];
|
||||
|
||||
if (currentDescriptor.Binding + currentCount != descriptor.Binding ||
|
||||
currentDescriptor.Type != descriptor.Type ||
|
||||
currentDescriptor.Stages != descriptor.Stages)
|
||||
{
|
||||
if (currentCount != 0)
|
||||
{
|
||||
currentSegments.Add(new ResourceBindingSegment(
|
||||
currentDescriptor.Binding,
|
||||
currentCount,
|
||||
currentDescriptor.Type,
|
||||
currentDescriptor.Stages,
|
||||
ResourceAccess.ReadWrite));
|
||||
}
|
||||
|
||||
currentDescriptor = descriptor;
|
||||
currentCount = descriptor.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentCount += descriptor.Count;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentCount != 0)
|
||||
{
|
||||
currentSegments.Add(new ResourceBindingSegment(
|
||||
currentDescriptor.Binding,
|
||||
currentCount,
|
||||
currentDescriptor.Type,
|
||||
currentDescriptor.Stages,
|
||||
ResourceAccess.ReadWrite));
|
||||
}
|
||||
|
||||
segments[setIndex] = currentSegments.ToArray();
|
||||
}
|
||||
|
||||
return segments;
|
||||
}
|
||||
|
||||
private static ResourceBindingSegment[][] BuildBindingSegments(ReadOnlyCollection<ResourceUsageCollection> setUsages)
|
||||
{
|
||||
ResourceBindingSegment[][] segments = new ResourceBindingSegment[setUsages.Count][];
|
||||
|
@@ -589,6 +589,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
supportsFragmentShaderOrderingIntel: false,
|
||||
supportsGeometryShader: Capabilities.SupportsGeometryShader,
|
||||
supportsGeometryShaderPassthrough: Capabilities.SupportsGeometryShaderPassthrough,
|
||||
supportsTransformFeedback: Capabilities.SupportsTransformFeedback,
|
||||
supportsImageLoadFormatted: features2.Features.ShaderStorageImageReadWithoutFormat,
|
||||
supportsLayerVertexTessellation: featuresVk12.ShaderOutputLayer,
|
||||
supportsMismatchingViewFormat: true,
|
||||
|
@@ -60,7 +60,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
private bool _canAcceptController = false;
|
||||
private KeyboardInputMode _inputMode = KeyboardInputMode.ControllerAndKeyboard;
|
||||
|
||||
private object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
public event EventHandler AppletStateChanged;
|
||||
|
||||
|
@@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
private const int TextBoxBlinkSleepMilliseconds = 100;
|
||||
private const int RendererWaitTimeoutMilliseconds = 100;
|
||||
|
||||
private readonly object _stateLock = new object();
|
||||
private readonly object _stateLock = new();
|
||||
|
||||
private SoftwareKeyboardUiState _state = new SoftwareKeyboardUiState();
|
||||
private SoftwareKeyboardRendererBase _renderer;
|
||||
|
@@ -26,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
const string CancelText = "Cancel";
|
||||
const string ControllerToggleText = "Toggle input";
|
||||
|
||||
private readonly object _bufferLock = new object();
|
||||
private readonly object _bufferLock = new();
|
||||
|
||||
private RenderingSurfaceInfo _surfaceInfo = null;
|
||||
private Image<Argb32> _surface = null;
|
||||
@@ -311,7 +311,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
private static RectangleF MeasureString(ReadOnlySpan<char> text, Font font)
|
||||
{
|
||||
RendererOptions options = new RendererOptions(font);
|
||||
|
||||
|
||||
if (text == "")
|
||||
{
|
||||
FontRectangle emptyRectangle = TextMeasurer.Measure(" ", options);
|
||||
|
@@ -26,8 +26,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
}
|
||||
|
||||
private TRef<bool> _cancelled = null;
|
||||
private Thread _thread = null;
|
||||
private object _lock = new object();
|
||||
private Thread _thread = null;
|
||||
private readonly object _lock = new();
|
||||
|
||||
public bool IsRunning
|
||||
{
|
||||
|
@@ -40,8 +40,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
|
||||
public ProcessState State { get; private set; }
|
||||
|
||||
private object _processLock;
|
||||
private object _threadingLock;
|
||||
private readonly object _processLock = new();
|
||||
private readonly object _threadingLock = new();
|
||||
|
||||
public KAddressArbiter AddressArbiter { get; private set; }
|
||||
|
||||
@@ -94,9 +94,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
|
||||
public KProcess(KernelContext context, bool allowCodeMemoryForJit = false) : base(context)
|
||||
{
|
||||
_processLock = new object();
|
||||
_threadingLock = new object();
|
||||
|
||||
AddressArbiter = new KAddressArbiter(context);
|
||||
|
||||
_fullTlsPages = new SortedDictionary<ulong, KTlsPageInfo>();
|
||||
|
@@ -112,7 +112,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
public bool WaitingInArbitration { get; set; }
|
||||
|
||||
private object _activityOperationLock;
|
||||
private readonly object _activityOperationLock = new();
|
||||
|
||||
public KThread(KernelContext context) : base(context)
|
||||
{
|
||||
@@ -123,8 +123,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
_mutexWaiters = new LinkedList<KThread>();
|
||||
_pinnedWaiters = new LinkedList<KThread>();
|
||||
|
||||
_activityOperationLock = new object();
|
||||
}
|
||||
|
||||
public Result Initialize(
|
||||
|
@@ -1,5 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
{
|
||||
[Flags]
|
||||
enum ThreadSchedState : ushort
|
||||
{
|
||||
LowMask = 0xf,
|
||||
|
@@ -154,7 +154,7 @@ namespace Ryujinx.HLE.HOS
|
||||
}
|
||||
|
||||
private static DirectoryInfo FindTitleDir(DirectoryInfo contentsDir, string titleId)
|
||||
=> contentsDir.EnumerateDirectories($"{titleId}*", DirEnumOptions).FirstOrDefault();
|
||||
=> contentsDir.EnumerateDirectories(titleId, DirEnumOptions).FirstOrDefault();
|
||||
|
||||
private static void AddModsFromDirectory(ModCache mods, DirectoryInfo dir, string titleId)
|
||||
{
|
||||
|
@@ -17,8 +17,8 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||
private KEvent _accumulatedSuspendedTickChangedEvent;
|
||||
private int _accumulatedSuspendedTickChangedEventHandle;
|
||||
|
||||
private object _fatalSectionLock = new object();
|
||||
private int _fatalSectionCount;
|
||||
private readonly object _fatalSectionLock = new();
|
||||
private int _fatalSectionCount;
|
||||
|
||||
// TODO: Set this when the game goes in suspension (go back to home menu ect), we currently don't support that so we can keep it set to 0.
|
||||
private ulong _accumulatedSuspendedTickValue = 0;
|
||||
@@ -429,4 +429,4 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||
private readonly UserId _userId;
|
||||
private readonly FriendServicePermissionLevel _permissionLevel;
|
||||
|
||||
private readonly object _lock = new object();
|
||||
private readonly object _lock = new();
|
||||
|
||||
private KEvent _notificationEvent;
|
||||
private int _notificationEventHandle = 0;
|
||||
|
@@ -1,8 +1,29 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
[Service("hidbus")]
|
||||
class IHidbusServer : IpcService
|
||||
{
|
||||
public IHidbusServer(ServiceCtx context) { }
|
||||
|
||||
[CommandCmif(1)]
|
||||
// GetBusHandle(nn::hid::NpadIdType, nn::hidbus::BusType, nn::applet::AppletResourceUserId) -> (bool HasHandle, nn::hidbus::BusHandle)
|
||||
public ResultCode GetBusHandle(ServiceCtx context)
|
||||
{
|
||||
NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadInt32();
|
||||
context.RequestData.BaseStream.Position += 4; // Padding
|
||||
BusType busType = (BusType)context.RequestData.ReadInt64();
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
context.ResponseData.Write(false);
|
||||
context.ResponseData.BaseStream.Position += 7; // Padding
|
||||
context.ResponseData.WriteStruct(new BusHandle());
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { npadIdType, busType, appletResourceUserId });
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
14
src/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/BusHandle.cs
Normal file
14
src/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/BusHandle.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct BusHandle
|
||||
{
|
||||
public int AbstractedPadId;
|
||||
public byte InternalIndex;
|
||||
public byte PlayerNumber;
|
||||
public byte BusTypeId;
|
||||
public byte IsValid;
|
||||
}
|
||||
}
|
9
src/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/BusType.cs
Normal file
9
src/Ryujinx.HLE/HOS/Services/Hid/Types/Npad/BusType.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public enum BusType : long
|
||||
{
|
||||
LeftJoyRail = 0,
|
||||
RightJoyRail = 1,
|
||||
InternalBus = 2
|
||||
}
|
||||
}
|
@@ -3,7 +3,7 @@ using System;
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
[Flags]
|
||||
public enum ControllerType : int
|
||||
public enum ControllerType
|
||||
{
|
||||
None,
|
||||
ProController = 1 << 0,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public enum NpadIdType : int
|
||||
public enum NpadIdType
|
||||
{
|
||||
Player1 = 0,
|
||||
Player2 = 1,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public enum PlayerIndex : int
|
||||
public enum PlayerIndex
|
||||
{
|
||||
Player1 = 0,
|
||||
Player2 = 1,
|
||||
|
@@ -3,7 +3,7 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad
|
||||
{
|
||||
[Flags]
|
||||
enum DeviceType : int
|
||||
enum DeviceType
|
||||
{
|
||||
None = 0,
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad
|
||||
{
|
||||
enum NpadBatteryLevel : int
|
||||
enum NpadBatteryLevel
|
||||
{
|
||||
Percent0,
|
||||
Percent25,
|
||||
|
@@ -775,7 +775,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types
|
||||
|
||||
private static ReadOnlySpan<ElementInfo> ElementInfos => MemoryMarshal.Cast<byte, ElementInfo>(ElementInfoArray);
|
||||
|
||||
private enum ElementInfoIndex : int
|
||||
private enum ElementInfoIndex
|
||||
{
|
||||
HairType,
|
||||
Height,
|
||||
|
@@ -21,7 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types
|
||||
};
|
||||
|
||||
[Flags]
|
||||
public enum BeardAndMustacheFlag : int
|
||||
public enum BeardAndMustacheFlag
|
||||
{
|
||||
Beard = 1,
|
||||
Mustache
|
||||
|
@@ -1,6 +1,6 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Mii.Types
|
||||
{
|
||||
enum Source : int
|
||||
enum Source
|
||||
{
|
||||
Database,
|
||||
Default
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user