Compare commits

...

16 Commits

Author SHA1 Message Date
jhorv
8198b99935 Fix Linux hang on shutdown (#4617)
* Rework StdErr-to-log redirection to use built-in FileStream, and do reads asynchronously to avoid hanging the process shutdown.

* set _disposable to false ASAP
2023-03-30 22:07:07 +02:00
ACGNnsj
460f96967d Slight Code Refactoring (#4373)
* Simplify return statements by using ternary expressions

* Remove a redundant type conversion

* Reduce nesting by inverting "if" statements

* Try to improve code readability by using LINQ and inverting "if" statements

* Try to improve code readability by using LINQ, using ternary expressions, and inverting "if" statements

* Add line breaks to long LINQ

* Add line breaks to long LINQ
2023-03-28 14:59:43 +02:00
Mary
7ca779a26d audout: Fix a possible crash with SDL2 when the SDL2 audio backend is dummy (#4605)
This change makes audio device error not fatal.
In case of error, the SDL2 audio backend will behave like the dummy
backend.
2023-03-27 20:56:36 +02:00
Mary
b5032b3c91 vulkan: Fix access level of extensions fields and make them readonly (#4608) 2023-03-27 08:40:27 +02:00
Mary
f0a3dff136 vulkan: Remove CreateCommandBufferPool from VulkanInitialization (#4606)
It was only called in one place, that can be simplified.
2023-03-27 02:16:31 +00:00
Mary
f659dcb9d8 vulkan: fix broken "VK_EXT_subgroup_size_control" support check (#4607)
Not sure since when it was broken...
2023-03-26 19:01:30 +02:00
riperiperi
a34fb0e939 Vulkan: Insert barriers before clears (#4596)
* Vulkan: Insert barriers before clears

Newer NVIDIA GPUs seem to be able to start clearing render targets before the last rasterization task is completed, which can cause it to clear a texture while it is being sampled.

This change adds a barrier from read to write when doing a clear, assuming it has been sampled in the past. It could be possible for this to be needed for sample into draw by some GPU, but it's not right now afaik.

This should fix visual artifacts on newer NVIDIA GPUs and driver combos. Contrary to popular belief, Tetris® Effect: Connected is not affected. Testing welcome, hopefully should fix most cases of this and not cost too much performance.

* Visual Studio Moment

* Address feedback

* Address Feedback 2
2023-03-26 12:51:02 +02:00
Mary
21ce8a9b80 chore: Update Ryujinx.SDL2-CS to 2.26.3 (#4479) 2023-03-24 22:42:24 +01:00
gdkchan
9ecbee8032 Batch inline index buffer update (#4587) 2023-03-24 14:19:54 +01:00
gdkchan
80519af67d Update short cache textures if modified (#4586) 2023-03-24 12:54:58 +01:00
gdkchan
26e30faff3 Fix handle leak on IShopServiceAccessServerInterface.CreateServerInterface (#4591) 2023-03-24 11:56:54 +01:00
Wunk
0992310b76 ARMeilleure: Check for XSAVE cpuid flag for AVX{2,512} (#4584)
Protection for the `xgetbv` instruction for systems that do not support
`xcr0` such as nehalem processors.

The `XSAVE` cpuid indicates support for `XSAVE`, `XRESTOR`, `XSETBV`,
`XGETBV` while `OSXSAVE` indicates if the operating system itself has
`XSAVE` turned on. Both must be checked at the same time.
2023-03-22 14:51:21 -03:00
Andrew Glaze
009c1101d2 CI: add a version tag to correlate release versions with commits (#4572)
* add step to tag commit with release version

* add step to tag commit with release version

* Rename step to “Create Tag”

* Fix name
2023-03-22 13:17:28 +01:00
gdkchan
ba95ee54ab Revert "Use source generated json serializers in order to improve code trimming (#4094)" (#4576)
This reverts commit 4ce4299ca2.
2023-03-21 20:14:46 -03:00
Andrey Sukharev
4ce4299ca2 Use source generated json serializers in order to improve code trimming (#4094)
* Use source generated json serializers in order to improve code trimming

* Use strongly typed github releases model to fetch updates instead of raw Newtonsoft.Json parsing

* Use separate model for LogEventArgs serialization

* Make dynamic object formatter static. Fix string builder pooling.

* Do not inherit json version of LogEventArgs from EventArgs

* Fix extra space in object formatting

* Write log json directly to stream instead of using buffer writer

* Rebase fixes

* Rebase fixes

* Rebase fixes

* Enforce block-scoped namespaces in the solution. Convert style for existing code

* Apply suggestions from code review

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

* Rebase indent fix

* Fix indent

* Delete unnecessary json properties

* Rebase fix

* Remove overridden json property names as they are handled in the options

* Apply suggestions from code review

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

* Use default json options in github api calls

* Indentation and spacing fixes

---------

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
2023-03-21 19:41:19 -03:00
Wunk
17620d18db ARMeilleure: Add initial support for AVX512 (EVEX encoding) (cont) (#4147)
* ARMeilleure: Add AVX512{F,VL,DQ,BW} detection

Add `UseAvx512Ortho` and `UseAvx512OrthoFloat` optimization flags as
short-hands for `F+VL` and `F+VL+DQ`.

* ARMeilleure: Add initial support for EVEX instruction encoding

Does not implement rounding, or exception controls.

* ARMeilleure: Add `X86Vpternlogd`

Accelerates the vector-`Not` instruction.

* ARMeilleure: Add check for `OSXSAVE` for AVX{2,512}

* ARMeilleure: Add check for `XCR0` flags

Add XCR0 register checks for AVX and AVX512F, following the guidelines
from section 14.3 and 15.2 from the Intel Architecture Software
Developer's Manual.

* ARMeilleure: Remove redundant `ReProtect` and `Dispose`, formatting

* ARMeilleure: Move XCR0 procedure to GetXcr0Eax

* ARMeilleure: Add `XCR0` to `FeatureInfo` structure

* ARMeilleure: Utilize `ReadOnlySpan` for Xcr0 assembly

Avoids an additional allocation

* ARMeilleure: Formatting fixes

* ARMeilleure: Fix EVEX encoding src2 register index

> Just like in VEX prefix, vvvv is provided in inverted form.

* ARMeilleure: Add `X86Vpternlogd` acceleration to `Vmvn_I`

Passes unit tests, verified instruction utilization

* ARMeilleure: Fix EVEX register operand designations

Operand 2 was being sourced improperly.

EVEX encoded instructions source their operands like so:
Operand 1: ModRM:reg
Operand 2: EVEX.vvvvv
Operand 3: ModRM:r/m
Operand 4: Imm

This fixes the improper register designations when emitting vpternlog.
Now "dest", "src1", "src2" arguments emit in the proper order in EVEX instructions.

* ARMeilleure: Add `X86Vpternlogd` acceleration to `Orn_V`

* ARMeilleure: PTC version bump

* ARMeilleure: Update EVEX encoding Debug.Assert to Debug.Fail

* ARMeilleure: Update EVEX encoding comment capitalization
2023-03-20 16:09:24 -03:00
34 changed files with 509 additions and 363 deletions

View File

@@ -112,6 +112,17 @@ jobs:
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }} repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
token: ${{ secrets.RELEASE_TOKEN }} token: ${{ secrets.RELEASE_TOKEN }}
- name: Create tag
uses: actions/github-script@v5
with:
script: |
github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: 'refs/tags/${{ steps.version_info.outputs.build_version }}',
sha: context.sha
})
flatpak_release: flatpak_release:
uses: ./.github/workflows/flatpak.yml uses: ./.github/workflows/flatpak.yml
needs: release needs: release

View File

@@ -7,6 +7,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" /> <ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -1034,7 +1034,13 @@ namespace ARMeilleure.CodeGen.X86
Debug.Assert(opCode != BadOp, "Invalid opcode value."); Debug.Assert(opCode != BadOp, "Invalid opcode value.");
if ((flags & InstructionFlags.Vex) != 0 && HardwareCapabilities.SupportsVexEncoding) if ((flags & InstructionFlags.Evex) != 0 && HardwareCapabilities.SupportsEvexEncoding)
{
WriteEvexInst(dest, src1, src2, type, flags, opCode);
opCode &= 0xff;
}
else if ((flags & InstructionFlags.Vex) != 0 && HardwareCapabilities.SupportsVexEncoding)
{ {
// In a vex encoding, only one prefix can be active at a time. The active prefix is encoded in the second byte using two bits. // In a vex encoding, only one prefix can be active at a time. The active prefix is encoded in the second byte using two bits.
@@ -1153,6 +1159,103 @@ namespace ARMeilleure.CodeGen.X86
} }
} }
private void WriteEvexInst(
Operand dest,
Operand src1,
Operand src2,
OperandType type,
InstructionFlags flags,
int opCode,
bool broadcast = false,
int registerWidth = 128,
int maskRegisterIdx = 0,
bool zeroElements = false)
{
int op1Idx = dest.GetRegister().Index;
int op2Idx = src1.GetRegister().Index;
int op3Idx = src2.GetRegister().Index;
WriteByte(0x62);
// P0
// Extend operand 1 register
bool r = (op1Idx & 8) == 0;
// Extend operand 3 register
bool x = (op3Idx & 16) == 0;
// Extend operand 3 register
bool b = (op3Idx & 8) == 0;
// Extend operand 1 register
bool rp = (op1Idx & 16) == 0;
// Escape code index
byte mm = 0b00;
switch ((ushort)(opCode >> 8))
{
case 0xf00: mm = 0b01; break;
case 0xf38: mm = 0b10; break;
case 0xf3a: mm = 0b11; break;
default: Debug.Fail($"Failed to EVEX encode opcode 0x{opCode:X}."); break;
}
WriteByte(
(byte)(
(r ? 0x80 : 0) |
(x ? 0x40 : 0) |
(b ? 0x20 : 0) |
(rp ? 0x10 : 0) |
mm));
// P1
// Specify 64-bit lane mode
bool w = Is64Bits(type);
// Operand 2 register index
byte vvvv = (byte)(~op2Idx & 0b1111);
// Opcode prefix
byte pp = (flags & InstructionFlags.PrefixMask) switch
{
InstructionFlags.Prefix66 => 0b01,
InstructionFlags.PrefixF3 => 0b10,
InstructionFlags.PrefixF2 => 0b11,
_ => 0
};
WriteByte(
(byte)(
(w ? 0x80 : 0) |
(vvvv << 3) |
0b100 |
pp));
// P2
// Mask register determines what elements to zero, rather than what elements to merge
bool z = zeroElements;
// Specifies register-width
byte ll = 0b00;
switch (registerWidth)
{
case 128: ll = 0b00; break;
case 256: ll = 0b01; break;
case 512: ll = 0b10; break;
default: Debug.Fail($"Invalid EVEX vector register width {registerWidth}."); break;
}
// Embedded broadcast in the case of a memory operand
bool bcast = broadcast;
// Extend operand 2 register
bool vp = (op2Idx & 16) == 0;
// Mask register index
Debug.Assert(maskRegisterIdx < 8, $"Invalid mask register index {maskRegisterIdx}.");
byte aaa = (byte)(maskRegisterIdx & 0b111);
WriteByte(
(byte)(
(z ? 0x80 : 0) |
(ll << 5) |
(bcast ? 0x10 : 0) |
(vp ? 8 : 0) |
aaa));
}
private void WriteCompactInst(Operand operand, int opCode) private void WriteCompactInst(Operand operand, int opCode)
{ {
int regIndex = operand.GetRegister().Index; int regIndex = operand.GetRegister().Index;

View File

@@ -20,6 +20,7 @@ namespace ARMeilleure.CodeGen.X86
Reg8Dest = 1 << 2, Reg8Dest = 1 << 2,
RexW = 1 << 3, RexW = 1 << 3,
Vex = 1 << 4, Vex = 1 << 4,
Evex = 1 << 5,
PrefixBit = 16, PrefixBit = 16,
PrefixMask = 7 << PrefixBit, PrefixMask = 7 << PrefixBit,
@@ -278,6 +279,7 @@ namespace ARMeilleure.CodeGen.X86
Add(X86Instruction.Vfnmsub231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bf, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW)); Add(X86Instruction.Vfnmsub231sd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bf, InstructionFlags.Vex | InstructionFlags.Prefix66 | InstructionFlags.RexW));
Add(X86Instruction.Vfnmsub231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bf, InstructionFlags.Vex | InstructionFlags.Prefix66)); Add(X86Instruction.Vfnmsub231ss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38bf, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Vpblendvb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4c, InstructionFlags.Vex | InstructionFlags.Prefix66)); Add(X86Instruction.Vpblendvb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a4c, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Vpternlogd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a25, InstructionFlags.Evex | InstructionFlags.Prefix66));
Add(X86Instruction.Xor, new InstructionInfo(0x00000031, 0x06000083, 0x06000081, BadOp, 0x00000033, InstructionFlags.None)); Add(X86Instruction.Xor, new InstructionInfo(0x00000031, 0x06000083, 0x06000081, BadOp, 0x00000033, InstructionFlags.None));
Add(X86Instruction.Xorpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex | InstructionFlags.Prefix66)); Add(X86Instruction.Xorpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex | InstructionFlags.Prefix66));
Add(X86Instruction.Xorps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex)); Add(X86Instruction.Xorps, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f57, InstructionFlags.Vex));

View File

@@ -1,10 +1,14 @@
using Ryujinx.Memory;
using System; using System;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
namespace ARMeilleure.CodeGen.X86 namespace ARMeilleure.CodeGen.X86
{ {
static class HardwareCapabilities static class HardwareCapabilities
{ {
private delegate uint GetXcr0();
static HardwareCapabilities() static HardwareCapabilities()
{ {
if (!X86Base.IsSupported) if (!X86Base.IsSupported)
@@ -24,6 +28,34 @@ namespace ARMeilleure.CodeGen.X86
FeatureInfo7Ebx = (FeatureFlags7Ebx)ebx7; FeatureInfo7Ebx = (FeatureFlags7Ebx)ebx7;
FeatureInfo7Ecx = (FeatureFlags7Ecx)ecx7; FeatureInfo7Ecx = (FeatureFlags7Ecx)ecx7;
} }
Xcr0InfoEax = (Xcr0FlagsEax)GetXcr0Eax();
}
private static uint GetXcr0Eax()
{
if (!FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Xsave))
{
// XSAVE feature required for xgetbv
return 0;
}
ReadOnlySpan<byte> asmGetXcr0 = new byte[]
{
0x31, 0xc9, // xor ecx, ecx
0xf, 0x01, 0xd0, // xgetbv
0xc3, // ret
};
using MemoryBlock memGetXcr0 = new MemoryBlock((ulong)asmGetXcr0.Length);
memGetXcr0.Write(0, asmGetXcr0);
memGetXcr0.Reprotect(0, (ulong)asmGetXcr0.Length, MemoryPermission.ReadAndExecute);
var fGetXcr0 = Marshal.GetDelegateForFunctionPointer<GetXcr0>(memGetXcr0.Pointer);
return fGetXcr0();
} }
[Flags] [Flags]
@@ -44,6 +76,8 @@ namespace ARMeilleure.CodeGen.X86
Sse42 = 1 << 20, Sse42 = 1 << 20,
Popcnt = 1 << 23, Popcnt = 1 << 23,
Aes = 1 << 25, Aes = 1 << 25,
Xsave = 1 << 26,
Osxsave = 1 << 27,
Avx = 1 << 28, Avx = 1 << 28,
F16c = 1 << 29 F16c = 1 << 29
} }
@@ -52,7 +86,11 @@ namespace ARMeilleure.CodeGen.X86
public enum FeatureFlags7Ebx public enum FeatureFlags7Ebx
{ {
Avx2 = 1 << 5, Avx2 = 1 << 5,
Sha = 1 << 29 Avx512f = 1 << 16,
Avx512dq = 1 << 17,
Sha = 1 << 29,
Avx512bw = 1 << 30,
Avx512vl = 1 << 31
} }
[Flags] [Flags]
@@ -61,10 +99,21 @@ namespace ARMeilleure.CodeGen.X86
Gfni = 1 << 8, Gfni = 1 << 8,
} }
[Flags]
public enum Xcr0FlagsEax
{
Sse = 1 << 1,
YmmHi128 = 1 << 2,
Opmask = 1 << 5,
ZmmHi256 = 1 << 6,
Hi16Zmm = 1 << 7
}
public static FeatureFlags1Edx FeatureInfo1Edx { get; } public static FeatureFlags1Edx FeatureInfo1Edx { get; }
public static FeatureFlags1Ecx FeatureInfo1Ecx { get; } public static FeatureFlags1Ecx FeatureInfo1Ecx { get; }
public static FeatureFlags7Ebx FeatureInfo7Ebx { get; } = 0; public static FeatureFlags7Ebx FeatureInfo7Ebx { get; } = 0;
public static FeatureFlags7Ecx FeatureInfo7Ecx { get; } = 0; public static FeatureFlags7Ecx FeatureInfo7Ecx { get; } = 0;
public static Xcr0FlagsEax Xcr0InfoEax { get; } = 0;
public static bool SupportsSse => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse); public static bool SupportsSse => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse);
public static bool SupportsSse2 => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse2); public static bool SupportsSse2 => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse2);
@@ -76,8 +125,13 @@ namespace ARMeilleure.CodeGen.X86
public static bool SupportsSse42 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse42); public static bool SupportsSse42 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse42);
public static bool SupportsPopcnt => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Popcnt); public static bool SupportsPopcnt => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Popcnt);
public static bool SupportsAesni => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Aes); public static bool SupportsAesni => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Aes);
public static bool SupportsAvx => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Avx); public static bool SupportsAvx => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Avx | FeatureFlags1Ecx.Xsave | FeatureFlags1Ecx.Osxsave) && Xcr0InfoEax.HasFlag(Xcr0FlagsEax.Sse | Xcr0FlagsEax.YmmHi128);
public static bool SupportsAvx2 => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx2) && SupportsAvx; public static bool SupportsAvx2 => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx2) && SupportsAvx;
public static bool SupportsAvx512F => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512f) && FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Xsave | FeatureFlags1Ecx.Osxsave)
&& Xcr0InfoEax.HasFlag(Xcr0FlagsEax.Sse | Xcr0FlagsEax.YmmHi128 | Xcr0FlagsEax.Opmask | Xcr0FlagsEax.ZmmHi256 | Xcr0FlagsEax.Hi16Zmm);
public static bool SupportsAvx512Vl => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512vl) && SupportsAvx512F;
public static bool SupportsAvx512Bw => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512bw) && SupportsAvx512F;
public static bool SupportsAvx512Dq => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512dq) && SupportsAvx512F;
public static bool SupportsF16c => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.F16c); public static bool SupportsF16c => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.F16c);
public static bool SupportsSha => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Sha); public static bool SupportsSha => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Sha);
public static bool SupportsGfni => FeatureInfo7Ecx.HasFlag(FeatureFlags7Ecx.Gfni); public static bool SupportsGfni => FeatureInfo7Ecx.HasFlag(FeatureFlags7Ecx.Gfni);
@@ -85,5 +139,6 @@ namespace ARMeilleure.CodeGen.X86
public static bool ForceLegacySse { get; set; } public static bool ForceLegacySse { get; set; }
public static bool SupportsVexEncoding => SupportsAvx && !ForceLegacySse; public static bool SupportsVexEncoding => SupportsAvx && !ForceLegacySse;
public static bool SupportsEvexEncoding => SupportsAvx512F && !ForceLegacySse;
} }
} }

View File

@@ -180,6 +180,7 @@ namespace ARMeilleure.CodeGen.X86
Add(Intrinsic.X86Vfnmadd231ss, new IntrinsicInfo(X86Instruction.Vfnmadd231ss, IntrinsicType.Fma)); Add(Intrinsic.X86Vfnmadd231ss, new IntrinsicInfo(X86Instruction.Vfnmadd231ss, IntrinsicType.Fma));
Add(Intrinsic.X86Vfnmsub231sd, new IntrinsicInfo(X86Instruction.Vfnmsub231sd, IntrinsicType.Fma)); Add(Intrinsic.X86Vfnmsub231sd, new IntrinsicInfo(X86Instruction.Vfnmsub231sd, IntrinsicType.Fma));
Add(Intrinsic.X86Vfnmsub231ss, new IntrinsicInfo(X86Instruction.Vfnmsub231ss, IntrinsicType.Fma)); Add(Intrinsic.X86Vfnmsub231ss, new IntrinsicInfo(X86Instruction.Vfnmsub231ss, IntrinsicType.Fma));
Add(Intrinsic.X86Vpternlogd, new IntrinsicInfo(X86Instruction.Vpternlogd, IntrinsicType.TernaryImm));
Add(Intrinsic.X86Xorpd, new IntrinsicInfo(X86Instruction.Xorpd, IntrinsicType.Binary)); Add(Intrinsic.X86Xorpd, new IntrinsicInfo(X86Instruction.Xorpd, IntrinsicType.Binary));
Add(Intrinsic.X86Xorps, new IntrinsicInfo(X86Instruction.Xorps, IntrinsicType.Binary)); Add(Intrinsic.X86Xorps, new IntrinsicInfo(X86Instruction.Xorps, IntrinsicType.Binary));
} }

View File

@@ -219,6 +219,7 @@ namespace ARMeilleure.CodeGen.X86
Vfnmsub231sd, Vfnmsub231sd,
Vfnmsub231ss, Vfnmsub231ss,
Vpblendvb, Vpblendvb,
Vpternlogd,
Xor, Xor,
Xorpd, Xorpd,
Xorps, Xorps,

View File

@@ -254,7 +254,22 @@ namespace ARMeilleure.Instructions
public static void Not_V(ArmEmitterContext context) public static void Not_V(ArmEmitterContext context)
{ {
if (Optimizations.UseSse2) if (Optimizations.UseAvx512Ortho)
{
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
Operand n = GetVec(op.Rn);
Operand res = context.AddIntrinsic(Intrinsic.X86Vpternlogd, n, n, Const(~0b10101010));
if (op.RegisterSize == RegisterSize.Simd64)
{
res = context.VectorZeroUpper64(res);
}
context.Copy(GetVec(op.Rd), res);
}
else if (Optimizations.UseSse2)
{ {
OpCodeSimd op = (OpCodeSimd)context.CurrOp; OpCodeSimd op = (OpCodeSimd)context.CurrOp;
@@ -283,6 +298,22 @@ namespace ARMeilleure.Instructions
{ {
InstEmitSimdHelperArm64.EmitVectorBinaryOp(context, Intrinsic.Arm64OrnV); InstEmitSimdHelperArm64.EmitVectorBinaryOp(context, Intrinsic.Arm64OrnV);
} }
else if (Optimizations.UseAvx512Ortho)
{
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
Operand n = GetVec(op.Rn);
Operand m = GetVec(op.Rm);
Operand res = context.AddIntrinsic(Intrinsic.X86Vpternlogd, n, m, Const(0b11001100 | ~0b10101010));
if (op.RegisterSize == RegisterSize.Simd64)
{
res = context.VectorZeroUpper64(res);
}
context.Copy(GetVec(op.Rd), res);
}
else if (Optimizations.UseSse2) else if (Optimizations.UseSse2)
{ {
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp; OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;

View File

@@ -151,6 +151,13 @@ namespace ARMeilleure.Instructions
{ {
InstEmitSimdHelper32Arm64.EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.Arm64OrnV | Intrinsic.Arm64V128, n, m)); InstEmitSimdHelper32Arm64.EmitVectorBinaryOpSimd32(context, (n, m) => context.AddIntrinsic(Intrinsic.Arm64OrnV | Intrinsic.Arm64V128, n, m));
} }
else if (Optimizations.UseAvx512Ortho)
{
EmitVectorBinaryOpSimd32(context, (n, m) =>
{
return context.AddIntrinsic(Intrinsic.X86Vpternlogd, n, m, Const(0b11001100 | ~0b10101010));
});
}
else if (Optimizations.UseSse2) else if (Optimizations.UseSse2)
{ {
Operand mask = context.VectorOne(); Operand mask = context.VectorOne();

View File

@@ -34,7 +34,14 @@ namespace ARMeilleure.Instructions
public static void Vmvn_I(ArmEmitterContext context) public static void Vmvn_I(ArmEmitterContext context)
{ {
if (Optimizations.UseSse2) if (Optimizations.UseAvx512Ortho)
{
EmitVectorUnaryOpSimd32(context, (op1) =>
{
return context.AddIntrinsic(Intrinsic.X86Vpternlogd, op1, op1, Const(0b01010101));
});
}
else if (Optimizations.UseSse2)
{ {
EmitVectorUnaryOpSimd32(context, (op1) => EmitVectorUnaryOpSimd32(context, (op1) =>
{ {

View File

@@ -173,6 +173,7 @@ namespace ARMeilleure.IntermediateRepresentation
X86Vfnmadd231ss, X86Vfnmadd231ss,
X86Vfnmsub231sd, X86Vfnmsub231sd,
X86Vfnmsub231ss, X86Vfnmsub231ss,
X86Vpternlogd,
X86Xorpd, X86Xorpd,
X86Xorps, X86Xorps,

View File

@@ -23,6 +23,10 @@ namespace ARMeilleure
public static bool UseSse42IfAvailable { get; set; } = true; public static bool UseSse42IfAvailable { get; set; } = true;
public static bool UsePopCntIfAvailable { get; set; } = true; public static bool UsePopCntIfAvailable { get; set; } = true;
public static bool UseAvxIfAvailable { get; set; } = true; public static bool UseAvxIfAvailable { get; set; } = true;
public static bool UseAvx512FIfAvailable { get; set; } = true;
public static bool UseAvx512VlIfAvailable { get; set; } = true;
public static bool UseAvx512BwIfAvailable { get; set; } = true;
public static bool UseAvx512DqIfAvailable { get; set; } = true;
public static bool UseF16cIfAvailable { get; set; } = true; public static bool UseF16cIfAvailable { get; set; } = true;
public static bool UseFmaIfAvailable { get; set; } = true; public static bool UseFmaIfAvailable { get; set; } = true;
public static bool UseAesniIfAvailable { get; set; } = true; public static bool UseAesniIfAvailable { get; set; } = true;
@@ -47,11 +51,18 @@ namespace ARMeilleure
internal static bool UseSse42 => UseSse42IfAvailable && X86HardwareCapabilities.SupportsSse42; internal static bool UseSse42 => UseSse42IfAvailable && X86HardwareCapabilities.SupportsSse42;
internal static bool UsePopCnt => UsePopCntIfAvailable && X86HardwareCapabilities.SupportsPopcnt; internal static bool UsePopCnt => UsePopCntIfAvailable && X86HardwareCapabilities.SupportsPopcnt;
internal static bool UseAvx => UseAvxIfAvailable && X86HardwareCapabilities.SupportsAvx && !ForceLegacySse; internal static bool UseAvx => UseAvxIfAvailable && X86HardwareCapabilities.SupportsAvx && !ForceLegacySse;
internal static bool UseAvx512F => UseAvx512FIfAvailable && X86HardwareCapabilities.SupportsAvx512F && !ForceLegacySse;
internal static bool UseAvx512Vl => UseAvx512VlIfAvailable && X86HardwareCapabilities.SupportsAvx512Vl && !ForceLegacySse;
internal static bool UseAvx512Bw => UseAvx512BwIfAvailable && X86HardwareCapabilities.SupportsAvx512Bw && !ForceLegacySse;
internal static bool UseAvx512Dq => UseAvx512DqIfAvailable && X86HardwareCapabilities.SupportsAvx512Dq && !ForceLegacySse;
internal static bool UseF16c => UseF16cIfAvailable && X86HardwareCapabilities.SupportsF16c; internal static bool UseF16c => UseF16cIfAvailable && X86HardwareCapabilities.SupportsF16c;
internal static bool UseFma => UseFmaIfAvailable && X86HardwareCapabilities.SupportsFma; internal static bool UseFma => UseFmaIfAvailable && X86HardwareCapabilities.SupportsFma;
internal static bool UseAesni => UseAesniIfAvailable && X86HardwareCapabilities.SupportsAesni; internal static bool UseAesni => UseAesniIfAvailable && X86HardwareCapabilities.SupportsAesni;
internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && X86HardwareCapabilities.SupportsPclmulqdq; internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && X86HardwareCapabilities.SupportsPclmulqdq;
internal static bool UseSha => UseShaIfAvailable && X86HardwareCapabilities.SupportsSha; internal static bool UseSha => UseShaIfAvailable && X86HardwareCapabilities.SupportsSha;
internal static bool UseGfni => UseGfniIfAvailable && X86HardwareCapabilities.SupportsGfni; internal static bool UseGfni => UseGfniIfAvailable && X86HardwareCapabilities.SupportsGfni;
internal static bool UseAvx512Ortho => UseAvx512F && UseAvx512Vl;
internal static bool UseAvx512OrthoFloat => UseAvx512Ortho && UseAvx512Dq;
} }
} }

View File

@@ -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 = 4484; //! To be incremented manually for each change to the ARMeilleure project. private const uint InternalVersion = 4485; //! 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";
@@ -969,6 +969,7 @@ namespace ARMeilleure.Translation.PTC
(ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap, (ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap,
(ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap2, (ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap2,
(ulong)Arm64HardwareCapabilities.MacOsFeatureInfo, (ulong)Arm64HardwareCapabilities.MacOsFeatureInfo,
0,
0); 0);
} }
else if (RuntimeInformation.ProcessArchitecture == Architecture.X64) else if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
@@ -977,11 +978,12 @@ namespace ARMeilleure.Translation.PTC
(ulong)X86HardwareCapabilities.FeatureInfo1Ecx, (ulong)X86HardwareCapabilities.FeatureInfo1Ecx,
(ulong)X86HardwareCapabilities.FeatureInfo1Edx, (ulong)X86HardwareCapabilities.FeatureInfo1Edx,
(ulong)X86HardwareCapabilities.FeatureInfo7Ebx, (ulong)X86HardwareCapabilities.FeatureInfo7Ebx,
(ulong)X86HardwareCapabilities.FeatureInfo7Ecx); (ulong)X86HardwareCapabilities.FeatureInfo7Ecx,
(ulong)X86HardwareCapabilities.Xcr0InfoEax);
} }
else else
{ {
return new FeatureInfo(0, 0, 0, 0); return new FeatureInfo(0, 0, 0, 0, 0);
} }
} }
@@ -1002,7 +1004,7 @@ namespace ARMeilleure.Translation.PTC
return osPlatform; return osPlatform;
} }
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 78*/)] [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 86*/)]
private struct OuterHeader private struct OuterHeader
{ {
public ulong Magic; public ulong Magic;
@@ -1034,8 +1036,8 @@ namespace ARMeilleure.Translation.PTC
} }
} }
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 32*/)] [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 40*/)]
private record struct FeatureInfo(ulong FeatureInfo0, ulong FeatureInfo1, ulong FeatureInfo2, ulong FeatureInfo3); private record struct FeatureInfo(ulong FeatureInfo0, ulong FeatureInfo1, ulong FeatureInfo2, ulong FeatureInfo3, ulong FeatureInfo4);
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 128*/)] [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 128*/)]
private struct InnerHeader private struct InnerHeader

View File

@@ -34,7 +34,7 @@
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" /> <PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" /> <PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" /> <PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.26.1-build23" /> <PackageVersion Include="Ryujinx.SDL2-CS" Version="2.26.3-build25" />
<PackageVersion Include="shaderc.net" Version="0.1.0" /> <PackageVersion Include="shaderc.net" Version="0.1.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" /> <PackageVersion Include="SharpZipLib" Version="1.4.2" />
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" /> <PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />

View File

@@ -18,6 +18,7 @@ namespace Ryujinx.Audio.Backends.SDL2
private ulong _playedSampleCount; private ulong _playedSampleCount;
private ManualResetEvent _updateRequiredEvent; private ManualResetEvent _updateRequiredEvent;
private uint _outputStream; private uint _outputStream;
private bool _hasSetupError;
private SDL_AudioCallback _callbackDelegate; private SDL_AudioCallback _callbackDelegate;
private int _bytesPerFrame; private int _bytesPerFrame;
private uint _sampleCount; private uint _sampleCount;
@@ -42,7 +43,7 @@ namespace Ryujinx.Audio.Backends.SDL2
private void EnsureAudioStreamSetup(AudioBuffer buffer) private void EnsureAudioStreamSetup(AudioBuffer buffer)
{ {
uint bufferSampleCount = (uint)GetSampleCount(buffer); uint bufferSampleCount = (uint)GetSampleCount(buffer);
bool needAudioSetup = _outputStream == 0 || bool needAudioSetup = (_outputStream == 0 && !_hasSetupError) ||
(bufferSampleCount >= Constants.TargetSampleCount && bufferSampleCount < _sampleCount); (bufferSampleCount >= Constants.TargetSampleCount && bufferSampleCount < _sampleCount);
if (needAudioSetup) if (needAudioSetup)
@@ -51,12 +52,9 @@ namespace Ryujinx.Audio.Backends.SDL2
uint newOutputStream = SDL2HardwareDeviceDriver.OpenStream(RequestedSampleFormat, RequestedSampleRate, RequestedChannelCount, _sampleCount, _callbackDelegate); uint newOutputStream = SDL2HardwareDeviceDriver.OpenStream(RequestedSampleFormat, RequestedSampleRate, RequestedChannelCount, _sampleCount, _callbackDelegate);
if (newOutputStream == 0) _hasSetupError = newOutputStream == 0;
{
// No stream in place, this is unexpected. if (!_hasSetupError)
throw new InvalidOperationException($"OpenStream failed with error: \"{SDL_GetError()}\"");
}
else
{ {
if (_outputStream != 0) if (_outputStream != 0)
{ {
@@ -151,11 +149,20 @@ namespace Ryujinx.Audio.Backends.SDL2
{ {
EnsureAudioStreamSetup(buffer); EnsureAudioStreamSetup(buffer);
SDL2AudioBuffer driverBuffer = new SDL2AudioBuffer(buffer.DataPointer, GetSampleCount(buffer)); if (_outputStream != 0)
{
SDL2AudioBuffer driverBuffer = new SDL2AudioBuffer(buffer.DataPointer, GetSampleCount(buffer));
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length); _ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
_queuedBuffers.Enqueue(driverBuffer); _queuedBuffers.Enqueue(driverBuffer);
}
else
{
Interlocked.Add(ref _playedSampleCount, GetSampleCount(buffer));
_updateRequiredEvent.Set();
}
} }
public override void SetVolume(float volume) public override void SetVolume(float volume)

View File

@@ -1,18 +1,21 @@
using Microsoft.Win32.SafeHandles;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using System; using System;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Versioning; using System.Runtime.Versioning;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
namespace Ryujinx.Common.SystemInterop namespace Ryujinx.Common.SystemInterop
{ {
public partial class StdErrAdapter : IDisposable public partial class StdErrAdapter : IDisposable
{ {
private bool _disposable = false; private bool _disposable = false;
private UnixStream _pipeReader; private Stream _pipeReader;
private UnixStream _pipeWriter; private Stream _pipeWriter;
private Thread _worker; private CancellationTokenSource _cancellationTokenSource;
private Task _worker;
public StdErrAdapter() public StdErrAdapter()
{ {
@@ -31,37 +34,39 @@ namespace Ryujinx.Common.SystemInterop
(int readFd, int writeFd) = MakePipe(); (int readFd, int writeFd) = MakePipe();
dup2(writeFd, stdErrFileno); dup2(writeFd, stdErrFileno);
_pipeReader = new UnixStream(readFd); _pipeReader = CreateFileDescriptorStream(readFd);
_pipeWriter = new UnixStream(writeFd); _pipeWriter = CreateFileDescriptorStream(writeFd);
_worker = new Thread(EventWorker); _cancellationTokenSource = new CancellationTokenSource();
_worker = Task.Run(async () => await EventWorkerAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token);
_disposable = true; _disposable = true;
_worker.Start();
} }
[SupportedOSPlatform("linux")] [SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")] [SupportedOSPlatform("macos")]
private void EventWorker() private async Task EventWorkerAsync(CancellationToken cancellationToken)
{ {
TextReader reader = new StreamReader(_pipeReader); using TextReader reader = new StreamReader(_pipeReader, leaveOpen: true);
string line; string line;
while ((line = reader.ReadLine()) != null) while (cancellationToken.IsCancellationRequested == false && (line = await reader.ReadLineAsync(cancellationToken)) != null)
{ {
Logger.Error?.PrintRawMsg(line); Logger.Error?.PrintRawMsg(line);
} }
} }
private void Dispose(bool disposing) private void Dispose(bool disposing)
{ {
if (_disposable) if (_disposable)
{ {
_disposable = false;
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
{ {
_cancellationTokenSource.Cancel();
_worker.Wait(0);
_pipeReader?.Close(); _pipeReader?.Close();
_pipeWriter?.Close(); _pipeWriter?.Close();
} }
_disposable = false;
} }
} }
@@ -74,11 +79,11 @@ namespace Ryujinx.Common.SystemInterop
private static partial int dup2(int fd, int fd2); private static partial int dup2(int fd, int fd2);
[LibraryImport("libc", SetLastError = true)] [LibraryImport("libc", SetLastError = true)]
private static unsafe partial int pipe(int* pipefd); private static partial int pipe(Span<int> pipefd);
private static unsafe (int, int) MakePipe() private static (int, int) MakePipe()
{ {
int *pipefd = stackalloc int[2]; Span<int> pipefd = stackalloc int[2];
if (pipe(pipefd) == 0) if (pipe(pipefd) == 0)
{ {
@@ -89,5 +94,16 @@ namespace Ryujinx.Common.SystemInterop
throw new(); throw new();
} }
} }
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
private static Stream CreateFileDescriptorStream(int fd)
{
return new FileStream(
new SafeFileHandle((IntPtr)fd, ownsHandle: true),
FileAccess.ReadWrite
);
}
} }
} }

View File

@@ -1,155 +0,0 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Ryujinx.Common.SystemInterop
{
[SupportedOSPlatform("linux")]
[SupportedOSPlatform("macos")]
public partial class UnixStream : Stream, IDisposable
{
private const int InvalidFd = -1;
private int _fd;
[LibraryImport("libc", SetLastError = true)]
private static partial long read(int fd, IntPtr buf, ulong count);
[LibraryImport("libc", SetLastError = true)]
private static partial long write(int fd, IntPtr buf, ulong count);
[LibraryImport("libc", SetLastError = true)]
private static partial int close(int fd);
public UnixStream(int fd)
{
if (InvalidFd == fd)
{
throw new ArgumentException("Invalid file descriptor");
}
_fd = fd;
CanRead = read(fd, IntPtr.Zero, 0) != -1;
CanWrite = write(fd, IntPtr.Zero, 0) != -1;
}
~UnixStream()
{
Close();
}
public override bool CanRead { get; }
public override bool CanWrite { get; }
public override bool CanSeek => false;
public override long Length => throw new NotSupportedException();
public override long Position
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
}
public override void Flush()
{
}
public override unsafe int Read([In, Out] byte[] buffer, int offset, int count)
{
if (offset < 0 || offset > (buffer.Length - count) || count < 0)
{
throw new ArgumentOutOfRangeException();
}
if (buffer.Length == 0)
{
return 0;
}
long r = 0;
fixed (byte* buf = &buffer[offset])
{
do
{
r = read(_fd, (IntPtr)buf, (ulong)count);
} while (ShouldRetry(r));
}
return (int)r;
}
public override unsafe void Write(byte[] buffer, int offset, int count)
{
if (offset < 0 || offset > (buffer.Length - count) || count < 0)
{
throw new ArgumentOutOfRangeException();
}
if (buffer.Length == 0)
{
return;
}
fixed (byte* buf = &buffer[offset])
{
long r = 0;
do {
r = write(_fd, (IntPtr)buf, (ulong)count);
} while (ShouldRetry(r));
}
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Close()
{
if (_fd == InvalidFd)
{
return;
}
Flush();
int r;
do {
r = close(_fd);
} while (ShouldRetry(r));
_fd = InvalidFd;
}
void IDisposable.Dispose()
{
Close();
}
private bool ShouldRetry(long r)
{
if (r == -1)
{
const int eintr = 4;
int errno = Marshal.GetLastPInvokeError();
if (errno == eintr)
{
return true;
}
throw new SystemException($"Operation failed with error 0x{errno:X}");
}
return false;
}
}
}

View File

@@ -180,7 +180,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
int firstInstance = (int)_state.State.FirstInstance; int firstInstance = (int)_state.State.FirstInstance;
int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount(); int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount(_context.Renderer);
if (inlineIndexCount != 0) if (inlineIndexCount != 0)
{ {
@@ -670,7 +670,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
{ {
if (indexedInline) if (indexedInline)
{ {
int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount(); int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount(_context.Renderer);
BufferRange br = new BufferRange(_drawState.IbStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4); BufferRange br = new BufferRange(_drawState.IbStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4);
_channel.BufferManager.SetIndexBuffer(br, IndexType.UInt); _channel.BufferManager.SetIndexBuffer(br, IndexType.UInt);

View File

@@ -11,9 +11,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// </summary> /// </summary>
struct IbStreamer struct IbStreamer
{ {
private const int BufferCapacity = 256; // Must be a power of 2.
private BufferHandle _inlineIndexBuffer; private BufferHandle _inlineIndexBuffer;
private int _inlineIndexBufferSize; private int _inlineIndexBufferSize;
private int _inlineIndexCount; private int _inlineIndexCount;
private uint[] _buffer;
private int _bufferOffset;
/// <summary> /// <summary>
/// Indicates if any index buffer data has been pushed. /// Indicates if any index buffer data has been pushed.
@@ -38,9 +42,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// Gets the number of elements on the current inline index buffer, /// Gets the number of elements on the current inline index buffer,
/// while also reseting it to zero for the next draw. /// while also reseting it to zero for the next draw.
/// </summary> /// </summary>
/// <param name="renderer">Host renderer</param>
/// <returns>Inline index bufffer count</returns> /// <returns>Inline index bufffer count</returns>
public int GetAndResetInlineIndexCount() public int GetAndResetInlineIndexCount(IRenderer renderer)
{ {
UpdateRemaining(renderer);
int temp = _inlineIndexCount; int temp = _inlineIndexCount;
_inlineIndexCount = 0; _inlineIndexCount = 0;
return temp; return temp;
@@ -58,16 +64,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
byte i2 = (byte)(argument >> 16); byte i2 = (byte)(argument >> 16);
byte i3 = (byte)(argument >> 24); byte i3 = (byte)(argument >> 24);
Span<uint> data = stackalloc uint[4]; int offset = _inlineIndexCount;
data[0] = i0; PushData(renderer, offset, i0);
data[1] = i1; PushData(renderer, offset + 1, i1);
data[2] = i2; PushData(renderer, offset + 2, i2);
data[3] = i3; PushData(renderer, offset + 3, i3);
int offset = _inlineIndexCount * 4;
renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data));
_inlineIndexCount += 4; _inlineIndexCount += 4;
} }
@@ -82,14 +84,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
ushort i0 = (ushort)argument; ushort i0 = (ushort)argument;
ushort i1 = (ushort)(argument >> 16); ushort i1 = (ushort)(argument >> 16);
Span<uint> data = stackalloc uint[2]; int offset = _inlineIndexCount;
data[0] = i0; PushData(renderer, offset, i0);
data[1] = i1; PushData(renderer, offset + 1, i1);
int offset = _inlineIndexCount * 4;
renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data));
_inlineIndexCount += 2; _inlineIndexCount += 2;
} }
@@ -103,13 +101,61 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
{ {
uint i0 = (uint)argument; uint i0 = (uint)argument;
Span<uint> data = stackalloc uint[1]; int offset = _inlineIndexCount++;
data[0] = i0; PushData(renderer, offset, i0);
}
int offset = _inlineIndexCount++ * 4; /// <summary>
/// Pushes a 32-bit value to the index buffer.
/// </summary>
/// <param name="renderer">Host renderer</param>
/// <param name="offset">Offset where the data should be written, in 32-bit words</param>
/// <param name="value">Index value to be written</param>
private void PushData(IRenderer renderer, int offset, uint value)
{
if (_buffer == null)
{
_buffer = new uint[BufferCapacity];
}
renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data)); // We upload data in chunks.
// If we are at the start of a chunk, then the buffer might be full,
// in that case we need to submit any existing data before overwriting the buffer.
int subOffset = offset & (BufferCapacity - 1);
if (subOffset == 0 && offset != 0)
{
int baseOffset = (offset - BufferCapacity) * sizeof(uint);
BufferHandle buffer = GetInlineIndexBuffer(renderer, baseOffset, BufferCapacity * sizeof(uint));
renderer.SetBufferData(buffer, baseOffset, MemoryMarshal.Cast<uint, byte>(_buffer));
}
_buffer[subOffset] = value;
}
/// <summary>
/// Makes sure that any pending data is submitted to the GPU before the index buffer is used.
/// </summary>
/// <param name="renderer">Host renderer</param>
private void UpdateRemaining(IRenderer renderer)
{
int offset = _inlineIndexCount;
if (offset == 0)
{
return;
}
int count = offset & (BufferCapacity - 1);
if (count == 0)
{
count = BufferCapacity;
}
int baseOffset = (offset - count) * sizeof(uint);
int length = count * sizeof(uint);
BufferHandle buffer = GetInlineIndexBuffer(renderer, baseOffset, length);
renderer.SetBufferData(buffer, baseOffset, MemoryMarshal.Cast<uint, byte>(_buffer).Slice(0, length));
} }
/// <summary> /// <summary>
@@ -117,12 +163,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// </summary> /// </summary>
/// <param name="renderer">Host renderer</param> /// <param name="renderer">Host renderer</param>
/// <param name="offset">Offset where the data will be written</param> /// <param name="offset">Offset where the data will be written</param>
/// <param name="length">Number of bytes that will be written</param>
/// <returns>Buffer handle</returns> /// <returns>Buffer handle</returns>
private BufferHandle GetInlineIndexBuffer(IRenderer renderer, int offset) private BufferHandle GetInlineIndexBuffer(IRenderer renderer, int offset, int length)
{ {
// Calculate a reasonable size for the buffer that can fit all the data, // Calculate a reasonable size for the buffer that can fit all the data,
// and that also won't require frequent resizes if we need to push more data. // and that also won't require frequent resizes if we need to push more data.
int size = BitUtils.AlignUp(offset + 0x10, 0x200); int size = BitUtils.AlignUp(offset + length + 0x10, 0x200);
if (_inlineIndexBuffer == BufferHandle.Null) if (_inlineIndexBuffer == BufferHandle.Null)
{ {

View File

@@ -130,6 +130,10 @@ namespace Ryujinx.Graphics.Gpu.Image
return ref descriptor; return ref descriptor;
} }
} }
else
{
texture.SynchronizeMemory();
}
Items[id] = texture; Items[id] = texture;
@@ -233,7 +237,7 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
/// <summary> /// <summary>
/// Queues a request to update a texture's mapping. /// Queues a request to update a texture's mapping.
/// Mapping is updated later to avoid deleting the texture if it is still sparsely mapped. /// Mapping is updated later to avoid deleting the texture if it is still sparsely mapped.
/// </summary> /// </summary>
/// <param name="texture">Texture with potential mapping change</param> /// <param name="texture">Texture with potential mapping change</param>

View File

@@ -236,7 +236,7 @@ namespace Ryujinx.Graphics.Vulkan
} }
else if (texture is TextureView view) else if (texture is TextureView view)
{ {
view.Storage.InsertBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags()); view.Storage.InsertWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
_textureRefs[binding] = view.GetImageView(); _textureRefs[binding] = view.GetImageView();
_samplerRefs[binding] = ((SamplerHolder)sampler)?.GetSampler(); _samplerRefs[binding] = ((SamplerHolder)sampler)?.GetSampler();

View File

@@ -322,7 +322,7 @@ namespace Ryujinx.Graphics.Vulkan
GAL.Format.S8Uint => ImageAspectFlags.StencilBit, GAL.Format.S8Uint => ImageAspectFlags.StencilBit,
GAL.Format.D24UnormS8Uint or GAL.Format.D24UnormS8Uint or
GAL.Format.D32FloatS8Uint or GAL.Format.D32FloatS8Uint or
GAL.Format.S8UintD24Unorm => ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit, GAL.Format.S8UintD24Unorm => ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit,
_ => ImageAspectFlags.ColorBit _ => ImageAspectFlags.ColorBit
}; };
} }

View File

@@ -218,5 +218,23 @@ namespace Ryujinx.Graphics.Vulkan
AccessFlags.DepthStencilAttachmentWriteBit, AccessFlags.DepthStencilAttachmentWriteBit,
PipelineStageFlags.ColorAttachmentOutputBit); PipelineStageFlags.ColorAttachmentOutputBit);
} }
public void InsertClearBarrier(CommandBufferScoped cbs, int index)
{
if (_colors != null)
{
int realIndex = Array.IndexOf(AttachmentIndices, index);
if (realIndex != -1)
{
_colors[realIndex].Storage?.InsertReadToWriteBarrier(cbs, AccessFlags.ColorAttachmentWriteBit, PipelineStageFlags.ColorAttachmentOutputBit);
}
}
}
public void InsertClearBarrierDS(CommandBufferScoped cbs)
{
_depthStencil?.Storage?.InsertReadToWriteBarrier(cbs, AccessFlags.DepthStencilAttachmentWriteBit, PipelineStageFlags.EarlyFragmentTestsBit);
}
} }
} }

View File

@@ -226,6 +226,8 @@ namespace Ryujinx.Graphics.Vulkan
var attachment = new ClearAttachment(ImageAspectFlags.ColorBit, (uint)index, clearValue); var attachment = new ClearAttachment(ImageAspectFlags.ColorBit, (uint)index, clearValue);
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount); var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
FramebufferParams.InsertClearBarrier(Cbs, index);
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect); Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
} }
@@ -256,6 +258,8 @@ namespace Ryujinx.Graphics.Vulkan
var attachment = new ClearAttachment(flags, 0, clearValue); var attachment = new ClearAttachment(flags, 0, clearValue);
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount); var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
FramebufferParams.InsertClearBarrierDS(Cbs);
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect); Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
} }

View File

@@ -46,6 +46,8 @@ namespace Ryujinx.Graphics.Vulkan
private AccessFlags _lastModificationAccess; private AccessFlags _lastModificationAccess;
private PipelineStageFlags _lastModificationStage; private PipelineStageFlags _lastModificationStage;
private AccessFlags _lastReadAccess;
private PipelineStageFlags _lastReadStage;
private int _viewsCount; private int _viewsCount;
private ulong _size; private ulong _size;
@@ -440,31 +442,39 @@ namespace Ryujinx.Graphics.Vulkan
_lastModificationStage = stage; _lastModificationStage = stage;
} }
public void InsertBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags) public void InsertReadToWriteBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags)
{ {
if (_lastReadAccess != AccessFlags.NoneKhr)
{
ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags();
TextureView.InsertImageBarrier(
_gd.Api,
cbs.CommandBuffer,
_imageAuto.Get(cbs).Value,
_lastReadAccess,
dstAccessFlags,
_lastReadStage,
dstStageFlags,
aspectFlags,
0,
0,
_info.GetLayers(),
_info.Levels);
_lastReadAccess = AccessFlags.NoneKhr;
_lastReadStage = PipelineStageFlags.None;
}
}
public void InsertWriteToReadBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags)
{
_lastReadAccess |= dstAccessFlags;
_lastReadStage |= dstStageFlags;
if (_lastModificationAccess != AccessFlags.NoneKhr) if (_lastModificationAccess != AccessFlags.NoneKhr)
{ {
ImageAspectFlags aspectFlags; ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags();
if (_info.Format.IsDepthOrStencil())
{
if (_info.Format == GAL.Format.S8Uint)
{
aspectFlags = ImageAspectFlags.StencilBit;
}
else if (_info.Format == GAL.Format.D16Unorm || _info.Format == GAL.Format.D32Float)
{
aspectFlags = ImageAspectFlags.DepthBit;
}
else
{
aspectFlags = ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit;
}
}
else
{
aspectFlags = ImageAspectFlags.ColorBit;
}
TextureView.InsertImageBarrier( TextureView.InsertImageBarrier(
_gd.Api, _gd.Api,

View File

@@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.Vulkan
private const string AppName = "Ryujinx.Graphics.Vulkan"; private const string AppName = "Ryujinx.Graphics.Vulkan";
private const int QueuesCount = 2; private const int QueuesCount = 2;
public static string[] DesirableExtensions { get; } = new string[] private static readonly string[] _desirableExtensions = new string[]
{ {
ExtConditionalRendering.ExtensionName, ExtConditionalRendering.ExtensionName,
ExtExtendedDynamicState.ExtensionName, ExtExtendedDynamicState.ExtensionName,
@@ -42,7 +42,7 @@ namespace Ryujinx.Graphics.Vulkan
"VK_KHR_portability_subset", // By spec, we should enable this if present. "VK_KHR_portability_subset", // By spec, we should enable this if present.
}; };
public static string[] RequiredExtensions { get; } = new string[] private static readonly string[] _requiredExtensions = new string[]
{ {
KhrSwapchain.ExtensionName KhrSwapchain.ExtensionName
}; };
@@ -337,14 +337,14 @@ namespace Ryujinx.Graphics.Vulkan
{ {
string extensionName = Marshal.PtrToStringAnsi((IntPtr)pExtensionProperties[i].ExtensionName); string extensionName = Marshal.PtrToStringAnsi((IntPtr)pExtensionProperties[i].ExtensionName);
if (RequiredExtensions.Contains(extensionName)) if (_requiredExtensions.Contains(extensionName))
{ {
extensionMatches++; extensionMatches++;
} }
} }
} }
return extensionMatches == RequiredExtensions.Length && FindSuitableQueueFamily(api, physicalDevice, surface, out _) != InvalidIndex; return extensionMatches == _requiredExtensions.Length && FindSuitableQueueFamily(api, physicalDevice, surface, out _) != InvalidIndex;
} }
internal static uint FindSuitableQueueFamily(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface, out uint queueCount) internal static uint FindSuitableQueueFamily(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface, out uint queueCount)
@@ -626,7 +626,7 @@ namespace Ryujinx.Graphics.Vulkan
pExtendedFeatures = &featuresCustomBorderColor; pExtendedFeatures = &featuresCustomBorderColor;
} }
var enabledExtensions = RequiredExtensions.Union(DesirableExtensions.Intersect(supportedExtensions)).ToArray(); var enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(supportedExtensions)).ToArray();
IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length]; IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length];
@@ -672,11 +672,6 @@ namespace Ryujinx.Graphics.Vulkan
return extensionProperties.Select(x => Marshal.PtrToStringAnsi((IntPtr)x.ExtensionName)).ToArray(); return extensionProperties.Select(x => Marshal.PtrToStringAnsi((IntPtr)x.ExtensionName)).ToArray();
} }
internal static CommandBufferPool CreateCommandBufferPool(Vk api, Device device, Queue queue, object queueLock, uint queueFamilyIndex)
{
return new CommandBufferPool(api, device, queue, queueLock, queueFamilyIndex);
}
internal unsafe static void CreateDebugMessenger( internal unsafe static void CreateDebugMessenger(
Vk api, Vk api,
GraphicsDebugLevel logLevel, GraphicsDebugLevel logLevel,

View File

@@ -168,7 +168,9 @@ namespace Ryujinx.Graphics.Vulkan
SType = StructureType.PhysicalDeviceSubgroupSizeControlPropertiesExt SType = StructureType.PhysicalDeviceSubgroupSizeControlPropertiesExt
}; };
if (Capabilities.SupportsSubgroupSizeControl) bool supportsSubgroupSizeControl = supportedExtensions.Contains("VK_EXT_subgroup_size_control");
if (supportsSubgroupSizeControl)
{ {
properties2.PNext = &propertiesSubgroupSizeControl; properties2.PNext = &propertiesSubgroupSizeControl;
} }
@@ -292,7 +294,7 @@ namespace Ryujinx.Graphics.Vulkan
supportedExtensions.Contains(KhrDrawIndirectCount.ExtensionName), supportedExtensions.Contains(KhrDrawIndirectCount.ExtensionName),
supportedExtensions.Contains("VK_EXT_fragment_shader_interlock"), supportedExtensions.Contains("VK_EXT_fragment_shader_interlock"),
supportedExtensions.Contains("VK_NV_geometry_shader_passthrough"), supportedExtensions.Contains("VK_NV_geometry_shader_passthrough"),
supportedExtensions.Contains("VK_EXT_subgroup_size_control"), supportsSubgroupSizeControl,
featuresShaderInt8.ShaderInt8, featuresShaderInt8.ShaderInt8,
supportedExtensions.Contains("VK_EXT_shader_stencil_export"), supportedExtensions.Contains("VK_EXT_shader_stencil_export"),
supportedExtensions.Contains(ExtConditionalRendering.ExtensionName), supportedExtensions.Contains(ExtConditionalRendering.ExtensionName),
@@ -318,7 +320,7 @@ namespace Ryujinx.Graphics.Vulkan
MemoryAllocator = new MemoryAllocator(Api, _physicalDevice, _device, properties.Limits.MaxMemoryAllocationCount); MemoryAllocator = new MemoryAllocator(Api, _physicalDevice, _device, properties.Limits.MaxMemoryAllocationCount);
CommandBufferPool = VulkanInitialization.CreateCommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex); CommandBufferPool = new CommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex);
DescriptorSetManager = new DescriptorSetManager(_device); DescriptorSetManager = new DescriptorSetManager(_device);

View File

@@ -14,6 +14,9 @@ namespace Ryujinx.HLE.HOS.Services.Nim
// CreateServerInterface(pid, handle<unknown>, u64) -> object<nn::ec::IShopServiceAccessServer> // CreateServerInterface(pid, handle<unknown>, u64) -> object<nn::ec::IShopServiceAccessServer>
public ResultCode CreateServerInterface(ServiceCtx context) public ResultCode CreateServerInterface(ServiceCtx context)
{ {
// Close transfer memory immediately as we don't use it.
context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]);
MakeObject(context, new IShopServiceAccessServer()); MakeObject(context, new IShopServiceAccessServer());
Logger.Stub?.PrintStub(LogClass.ServiceNim); Logger.Stub?.PrintStub(LogClass.ServiceNim);

View File

@@ -4,6 +4,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
namespace Ryujinx.Horizon.Generators.Kernel namespace Ryujinx.Horizon.Generators.Kernel
{ {
@@ -151,24 +152,15 @@ namespace Ryujinx.Horizon.Generators.Kernel
GenerateMethod32(generator, context.Compilation, method); GenerateMethod32(generator, context.Compilation, method);
GenerateMethod64(generator, context.Compilation, method); GenerateMethod64(generator, context.Compilation, method);
foreach (var attributeList in method.AttributeLists) foreach (AttributeSyntax attribute in method.AttributeLists.SelectMany(attributeList =>
attributeList.Attributes.Where(attribute =>
GetCanonicalTypeName(context.Compilation, attribute) == TypeSvcAttribute)))
{ {
foreach (var attribute in attributeList.Attributes) syscalls.AddRange(from attributeArg in attribute.ArgumentList.Arguments
{ where attributeArg.Expression.Kind() == SyntaxKind.NumericLiteralExpression
if (GetCanonicalTypeName(context.Compilation, attribute) != TypeSvcAttribute) select (LiteralExpressionSyntax)attributeArg.Expression
{ into numericLiteral
continue; select new SyscallIdAndName((int)numericLiteral.Token.Value, method.Identifier.Text));
}
foreach (var attributeArg in attribute.ArgumentList.Arguments)
{
if (attributeArg.Expression.Kind() == SyntaxKind.NumericLiteralExpression)
{
LiteralExpressionSyntax numericLiteral = (LiteralExpressionSyntax)attributeArg.Expression;
syscalls.Add(new SyscallIdAndName((int)numericLiteral.Token.Value, method.Identifier.Text));
}
}
}
} }
} }
@@ -510,28 +502,14 @@ namespace Ryujinx.Horizon.Generators.Kernel
private static string GenerateCastFromUInt64(string value, string canonicalTargetTypeName, string targetTypeName) private static string GenerateCastFromUInt64(string value, string canonicalTargetTypeName, string targetTypeName)
{ {
if (canonicalTargetTypeName == TypeSystemBoolean) return canonicalTargetTypeName == TypeSystemBoolean ? $"({value} & 1) != 0" : $"({targetTypeName}){value}";
{
return $"({value} & 1) != 0";
}
return $"({targetTypeName}){value}";
} }
private static bool IsPointerSized(Compilation compilation, ParameterSyntax parameterSyntax) private static bool IsPointerSized(Compilation compilation, ParameterSyntax parameterSyntax)
{ {
foreach (var attributeList in parameterSyntax.AttributeLists) return parameterSyntax.AttributeLists.Any(attributeList =>
{ attributeList.Attributes.Any(attribute =>
foreach (var attribute in attributeList.Attributes) GetCanonicalTypeName(compilation, attribute) == TypePointerSizedAttribute));
{
if (GetCanonicalTypeName(compilation, attribute) == TypePointerSizedAttribute)
{
return true;
}
}
}
return false;
} }
public void Initialize(GeneratorInitializationContext context) public void Initialize(GeneratorInitializationContext context)

View File

@@ -16,38 +16,37 @@ namespace Ryujinx.Horizon.Generators.Kernel
public void OnVisitSyntaxNode(SyntaxNode syntaxNode) public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{ {
if (syntaxNode is ClassDeclarationSyntax classDeclaration && classDeclaration.AttributeLists.Count != 0) if (!(syntaxNode is ClassDeclarationSyntax classDeclaration) || classDeclaration.AttributeLists.Count == 0)
{ {
foreach (var attributeList in classDeclaration.AttributeLists) return;
{ }
if (attributeList.Attributes.Any(x => x.Name.GetText().ToString() == "SvcImpl"))
{
foreach (var memberDeclaration in classDeclaration.Members)
{
if (memberDeclaration is MethodDeclarationSyntax methodDeclaration)
{
VisitMethod(methodDeclaration);
}
}
break; if (!classDeclaration.AttributeLists.Any(attributeList =>
} attributeList.Attributes.Any(x => x.Name.GetText().ToString() == "SvcImpl")))
{
return;
}
foreach (var memberDeclaration in classDeclaration.Members)
{
if (memberDeclaration is MethodDeclarationSyntax methodDeclaration)
{
VisitMethod(methodDeclaration);
} }
} }
} }
private void VisitMethod(MethodDeclarationSyntax methodDeclaration) private void VisitMethod(MethodDeclarationSyntax methodDeclaration)
{ {
if (methodDeclaration.AttributeLists.Count != 0) if (methodDeclaration.AttributeLists.Count == 0)
{ {
foreach (var attributeList in methodDeclaration.AttributeLists) return;
{ }
if (attributeList.Attributes.Any(x => x.Name.GetText().ToString() == "Svc"))
{ if (methodDeclaration.AttributeLists.Any(attributeList =>
SvcImplementations.Add(methodDeclaration); attributeList.Attributes.Any(x => x.Name.GetText().ToString() == "Svc")))
break; {
} SvcImplementations.Add(methodDeclaration);
}
} }
} }
} }

View File

@@ -40,12 +40,7 @@ namespace Ryujinx.Horizon.Sdk.Sf
var runtimeMetadata = context.Processor.GetRuntimeMetadata(); var runtimeMetadata = context.Processor.GetRuntimeMetadata();
Result result = context.Processor.PrepareForProcess(ref context, runtimeMetadata); Result result = context.Processor.PrepareForProcess(ref context, runtimeMetadata);
if (result.IsFailure) return result.IsFailure ? result : _invoke(ref context, _processor, runtimeMetadata, inRawData, ref outHeader);
{
return result;
}
return _invoke(ref context, _processor, runtimeMetadata, inRawData, ref outHeader);
} }
public static void GetCmifOutHeaderPointer(ref Span<CmifOutHeader> outHeader, ref Span<byte> outRawData) public static void GetCmifOutHeaderPointer(ref Span<CmifOutHeader> outHeader, ref Span<byte> outRawData)

View File

@@ -53,7 +53,7 @@ namespace Ryujinx.Horizon.Sdk.Sf
public static void SerializeArg<T>(Span<byte> outRawData, int offset, T value) where T : unmanaged public static void SerializeArg<T>(Span<byte> outRawData, int offset, T value) where T : unmanaged
{ {
MemoryMarshal.Cast<byte, T>(outRawData.Slice(offset, Unsafe.SizeOf<T>()))[0] = (T)value; MemoryMarshal.Cast<byte, T>(outRawData.Slice(offset, Unsafe.SizeOf<T>()))[0] = value;
} }
public static void SerializeCopyHandle(HipcMessageData response, int index, int value) public static void SerializeCopyHandle(HipcMessageData response, int index, int value)

View File

@@ -41,10 +41,8 @@ namespace Ryujinx.Horizon.Sdk.Sf
{ {
_args = args; _args = args;
for (int i = 0; i < args.Length; i++) foreach (CommandArg argInfo in args)
{ {
var argInfo = args[i];
switch (argInfo.Type) switch (argInfo.Type)
{ {
case CommandArgType.Buffer: case CommandArgType.Buffer:
@@ -239,14 +237,13 @@ namespace Ryujinx.Horizon.Sdk.Sf
{ {
return mode == HipcBufferMode.NonSecure; return mode == HipcBufferMode.NonSecure;
} }
else if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice))
if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice))
{ {
return mode == HipcBufferMode.NonDevice; return mode == HipcBufferMode.NonDevice;
} }
else
{ return mode == HipcBufferMode.Normal;
return mode == HipcBufferMode.Normal;
}
} }
public void SetOutBuffers(HipcMessageData response, bool[] isBufferMapAlias) public void SetOutBuffers(HipcMessageData response, bool[] isBufferMapAlias)
@@ -261,28 +258,30 @@ namespace Ryujinx.Horizon.Sdk.Sf
} }
var flags = _args[i].BufferFlags; var flags = _args[i].BufferFlags;
if (flags.HasFlag(HipcBufferFlags.Out)) if (!flags.HasFlag(HipcBufferFlags.Out))
{ {
var buffer = _bufferRanges[i]; continue;
}
if (flags.HasFlag(HipcBufferFlags.Pointer)) var buffer = _bufferRanges[i];
if (flags.HasFlag(HipcBufferFlags.Pointer))
{
response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(buffer.Address, (ushort)buffer.Size, recvPointerIndex);
}
else if (flags.HasFlag(HipcBufferFlags.AutoSelect))
{
if (!isBufferMapAlias[i])
{ {
response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(buffer.Address, (ushort)buffer.Size, recvPointerIndex); response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(buffer.Address, (ushort)buffer.Size, recvPointerIndex);
} }
else if (flags.HasFlag(HipcBufferFlags.AutoSelect)) else
{ {
if (!isBufferMapAlias[i]) response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(0UL, 0, recvPointerIndex);
{
response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(buffer.Address, (ushort)buffer.Size, recvPointerIndex);
}
else
{
response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(0UL, 0, recvPointerIndex);
}
} }
recvPointerIndex++;
} }
recvPointerIndex++;
} }
} }
@@ -339,15 +338,17 @@ namespace Ryujinx.Horizon.Sdk.Sf
int inObjectIndex = 0; int inObjectIndex = 0;
for (int i = 0; i < _args.Length; i++) foreach (CommandArg t in _args)
{ {
if (_args[i].Type == CommandArgType.InObject) if (t.Type != CommandArgType.InObject)
{ {
int index = inObjectIndex++; continue;
var inObject = inObjects[index];
objects[index] = inObject?.ServiceObject;
} }
int index = inObjectIndex++;
var inObject = inObjects[index];
objects[index] = inObject?.ServiceObject;
} }
return Result.Success; return Result.Success;

View File

@@ -37,12 +37,7 @@ namespace Ryujinx.Horizon.Sm.Impl
result = GetServiceImpl(out handle, ref _services[serviceIndex]); result = GetServiceImpl(out handle, ref _services[serviceIndex]);
if (result == KernelResult.SessionCountExceeded) return result == KernelResult.SessionCountExceeded ? SmResult.OutOfSessions : result;
{
return SmResult.OutOfSessions;
}
return result;
} }
private Result GetServiceImpl(out int handle, ref ServiceInfo serviceInfo) private Result GetServiceImpl(out int handle, ref ServiceInfo serviceInfo)
@@ -61,13 +56,7 @@ namespace Ryujinx.Horizon.Sm.Impl
} }
// TODO: Validation with GetProcessInfo etc. // TODO: Validation with GetProcessInfo etc.
return HasServiceInfo(name) ? SmResult.AlreadyRegistered : RegisterServiceImpl(out handle, processId, name, maxSessions, isLight);
if (HasServiceInfo(name))
{
return SmResult.AlreadyRegistered;
}
return RegisterServiceImpl(out handle, processId, name, maxSessions, isLight);
} }
public Result RegisterServiceForSelf(out int handle, ServiceName name, int maxSessions) public Result RegisterServiceForSelf(out int handle, ServiceName name, int maxSessions)