Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f906eb06c2 | ||
|
219f63ff4e | ||
|
1cca3e99ab | ||
|
55a23e5ec8 | ||
|
479d1fd8b0 | ||
|
cb70e7bb30 | ||
|
c200a7b7c6 | ||
|
6268170a10 | ||
|
ee0f9b03a4 | ||
|
f93c5f006a |
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -1033,13 +1033,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
Debug.Assert(opCode != BadOp, "Invalid opcode value.");
|
Debug.Assert(opCode != BadOp, "Invalid opcode value.");
|
||||||
|
|
||||||
if ((flags & InstructionFlags.Evex) != 0 && HardwareCapabilities.SupportsEvexEncoding)
|
if ((flags & InstructionFlags.Vex) != 0 && HardwareCapabilities.SupportsVexEncoding)
|
||||||
{
|
|
||||||
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.
|
||||||
|
|
||||||
@@ -1158,103 +1152,6 @@ 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 destIdx = dest.GetRegister().Index;
|
|
||||||
int src1Idx = src1.GetRegister().Index;
|
|
||||||
int src2Idx = src2.GetRegister().Index;
|
|
||||||
|
|
||||||
WriteByte(0x62);
|
|
||||||
|
|
||||||
// P0
|
|
||||||
// Extend dest register
|
|
||||||
bool r = (destIdx & 8) == 0;
|
|
||||||
// Extend src register
|
|
||||||
bool x = (src1Idx & 16) == 0;
|
|
||||||
// Extend src register
|
|
||||||
bool b = (src1Idx & 8) == 0;
|
|
||||||
// Extend dest register
|
|
||||||
bool rp = (destIdx & 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.Assert(false, $"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);
|
|
||||||
// Src2 register index
|
|
||||||
byte vvvv = (byte)(src2Idx & 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.Assert(false, $"Invalid EVEX vector register width {registerWidth}."); break;
|
|
||||||
}
|
|
||||||
// Embedded broadcast in the case of a memory operand
|
|
||||||
bool bcast = broadcast;
|
|
||||||
// Extend src2 register
|
|
||||||
bool vp = (src2Idx & 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;
|
||||||
|
@@ -20,7 +20,6 @@ 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,
|
||||||
@@ -279,7 +278,6 @@ 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));
|
||||||
|
@@ -1587,6 +1587,12 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
|
Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
|
||||||
|
|
||||||
|
// We can eliminate the move if source is already 32-bit and the registers are the same.
|
||||||
|
if (dest.Value == source.Value && source.Type == OperandType.I32)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
context.Assembler.Mov(dest, source, OperandType.I32);
|
context.Assembler.Mov(dest, source, OperandType.I32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,14 +1,10 @@
|
|||||||
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)
|
||||||
@@ -28,28 +24,6 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
FeatureInfo7Ebx = (FeatureFlags7Ebx)ebx7;
|
FeatureInfo7Ebx = (FeatureFlags7Ebx)ebx7;
|
||||||
FeatureInfo7Ecx = (FeatureFlags7Ecx)ecx7;
|
FeatureInfo7Ecx = (FeatureFlags7Ecx)ecx7;
|
||||||
}
|
}
|
||||||
|
|
||||||
Xcr0InfoEax = (Xcr0FlagsEax)GetXcr0Eax();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static uint GetXcr0Eax()
|
|
||||||
{
|
|
||||||
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]
|
||||||
@@ -70,7 +44,6 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Sse42 = 1 << 20,
|
Sse42 = 1 << 20,
|
||||||
Popcnt = 1 << 23,
|
Popcnt = 1 << 23,
|
||||||
Aes = 1 << 25,
|
Aes = 1 << 25,
|
||||||
Osxsave = 1 << 27,
|
|
||||||
Avx = 1 << 28,
|
Avx = 1 << 28,
|
||||||
F16c = 1 << 29
|
F16c = 1 << 29
|
||||||
}
|
}
|
||||||
@@ -79,11 +52,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
public enum FeatureFlags7Ebx
|
public enum FeatureFlags7Ebx
|
||||||
{
|
{
|
||||||
Avx2 = 1 << 5,
|
Avx2 = 1 << 5,
|
||||||
Avx512f = 1 << 16,
|
Sha = 1 << 29
|
||||||
Avx512dq = 1 << 17,
|
|
||||||
Sha = 1 << 29,
|
|
||||||
Avx512bw = 1 << 30,
|
|
||||||
Avx512vl = 1 << 31
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
@@ -92,21 +61,10 @@ 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);
|
||||||
@@ -118,13 +76,8 @@ 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 | FeatureFlags1Ecx.Osxsave) && Xcr0InfoEax.HasFlag(Xcr0FlagsEax.Sse | Xcr0FlagsEax.YmmHi128);
|
public static bool SupportsAvx => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Avx);
|
||||||
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.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);
|
||||||
@@ -132,6 +85,5 @@ 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -182,7 +182,6 @@ 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));
|
||||||
}
|
}
|
||||||
|
@@ -219,7 +219,6 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Vfnmsub231sd,
|
Vfnmsub231sd,
|
||||||
Vfnmsub231ss,
|
Vfnmsub231ss,
|
||||||
Vpblendvb,
|
Vpblendvb,
|
||||||
Vpternlogd,
|
|
||||||
Xor,
|
Xor,
|
||||||
Xorpd,
|
Xorpd,
|
||||||
Xorps,
|
Xorps,
|
||||||
|
@@ -381,7 +381,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
for (int index = 0; index < elems; index++)
|
for (int index = 0; index < elems; index++)
|
||||||
{
|
{
|
||||||
Operand ne = context.VectorExtract(type, GetVec(op.Rn), 0);
|
Operand ne = context.VectorExtract(type, GetVec(op.Rn), index);
|
||||||
|
|
||||||
if (sizeF == 0)
|
if (sizeF == 0)
|
||||||
{
|
{
|
||||||
@@ -389,8 +389,6 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand e = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
|
Operand e = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
|
||||||
context.LoadFromContext();
|
context.LoadFromContext();
|
||||||
|
|
||||||
e = context.ZeroExtend16(OperandType.I64, e);
|
|
||||||
|
|
||||||
res = EmitVectorInsert(context, res, e, part + index, 1);
|
res = EmitVectorInsert(context, res, e, part + index, 1);
|
||||||
}
|
}
|
||||||
else /* if (sizeF == 1) */
|
else /* if (sizeF == 1) */
|
||||||
|
@@ -224,22 +224,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Not_V(ArmEmitterContext context)
|
public static void Not_V(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
if (Optimizations.UseAvx512Ortho)
|
if (Optimizations.UseSse2)
|
||||||
{
|
|
||||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
|
||||||
|
|
||||||
Operand n = GetVec(op.Rn);
|
|
||||||
|
|
||||||
Operand res = context.AddIntrinsic(Intrinsic.X86Vpternlogd, n, n, Const(0b01010101));
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
@@ -171,7 +171,6 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
X86Vfnmadd231ss,
|
X86Vfnmadd231ss,
|
||||||
X86Vfnmsub231sd,
|
X86Vfnmsub231sd,
|
||||||
X86Vfnmsub231ss,
|
X86Vfnmsub231ss,
|
||||||
X86Vpternlogd,
|
|
||||||
X86Xorpd,
|
X86Xorpd,
|
||||||
X86Xorps
|
X86Xorps
|
||||||
}
|
}
|
||||||
|
@@ -378,14 +378,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
if (Kind == OperandKind.LocalVariable)
|
return ((ulong)_data).GetHashCode();
|
||||||
{
|
|
||||||
return base.GetHashCode();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return (int)Value ^ ((int)Kind << 16) ^ ((int)Type << 20);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Equals(Operand operand)
|
public bool Equals(Operand operand)
|
||||||
|
@@ -17,10 +17,6 @@ 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;
|
||||||
@@ -42,18 +38,11 @@ namespace ARMeilleure
|
|||||||
internal static bool UseSse42 => UseSse42IfAvailable && HardwareCapabilities.SupportsSse42;
|
internal static bool UseSse42 => UseSse42IfAvailable && HardwareCapabilities.SupportsSse42;
|
||||||
internal static bool UsePopCnt => UsePopCntIfAvailable && HardwareCapabilities.SupportsPopcnt;
|
internal static bool UsePopCnt => UsePopCntIfAvailable && HardwareCapabilities.SupportsPopcnt;
|
||||||
internal static bool UseAvx => UseAvxIfAvailable && HardwareCapabilities.SupportsAvx && !ForceLegacySse;
|
internal static bool UseAvx => UseAvxIfAvailable && HardwareCapabilities.SupportsAvx && !ForceLegacySse;
|
||||||
internal static bool UseAvx512F => UseAvx512FIfAvailable && HardwareCapabilities.SupportsAvx512F && !ForceLegacySse;
|
|
||||||
internal static bool UseAvx512Vl => UseAvx512VlIfAvailable && HardwareCapabilities.SupportsAvx512Vl && !ForceLegacySse;
|
|
||||||
internal static bool UseAvx512Bw => UseAvx512BwIfAvailable && HardwareCapabilities.SupportsAvx512Bw && !ForceLegacySse;
|
|
||||||
internal static bool UseAvx512Dq => UseAvx512DqIfAvailable && HardwareCapabilities.SupportsAvx512Dq && !ForceLegacySse;
|
|
||||||
internal static bool UseF16c => UseF16cIfAvailable && HardwareCapabilities.SupportsF16c;
|
internal static bool UseF16c => UseF16cIfAvailable && HardwareCapabilities.SupportsF16c;
|
||||||
internal static bool UseFma => UseFmaIfAvailable && HardwareCapabilities.SupportsFma;
|
internal static bool UseFma => UseFmaIfAvailable && HardwareCapabilities.SupportsFma;
|
||||||
internal static bool UseAesni => UseAesniIfAvailable && HardwareCapabilities.SupportsAesni;
|
internal static bool UseAesni => UseAesniIfAvailable && HardwareCapabilities.SupportsAesni;
|
||||||
internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && HardwareCapabilities.SupportsPclmulqdq;
|
internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && HardwareCapabilities.SupportsPclmulqdq;
|
||||||
internal static bool UseSha => UseShaIfAvailable && HardwareCapabilities.SupportsSha;
|
internal static bool UseSha => UseShaIfAvailable && HardwareCapabilities.SupportsSha;
|
||||||
internal static bool UseGfni => UseGfniIfAvailable && HardwareCapabilities.SupportsGfni;
|
internal static bool UseGfni => UseGfniIfAvailable && HardwareCapabilities.SupportsGfni;
|
||||||
|
|
||||||
internal static bool UseAvx512Ortho => UseAvx512F && UseAvx512Vl;
|
|
||||||
internal static bool UseAvx512OrthoFloat => UseAvx512Ortho && UseAvx512Dq;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -27,7 +27,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 = 3714; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 4159; //! 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";
|
||||||
@@ -952,8 +952,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
(uint)HardwareCapabilities.FeatureInfo1Ecx,
|
(uint)HardwareCapabilities.FeatureInfo1Ecx,
|
||||||
(uint)HardwareCapabilities.FeatureInfo1Edx,
|
(uint)HardwareCapabilities.FeatureInfo1Edx,
|
||||||
(uint)HardwareCapabilities.FeatureInfo7Ebx,
|
(uint)HardwareCapabilities.FeatureInfo7Ebx,
|
||||||
(uint)HardwareCapabilities.FeatureInfo7Ecx,
|
(uint)HardwareCapabilities.FeatureInfo7Ecx);
|
||||||
(uint)HardwareCapabilities.Xcr0InfoEax);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte GetMemoryManagerMode()
|
private static byte GetMemoryManagerMode()
|
||||||
@@ -973,7 +972,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return osPlatform;
|
return osPlatform;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 62*/)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 58*/)]
|
||||||
private struct OuterHeader
|
private struct OuterHeader
|
||||||
{
|
{
|
||||||
public ulong Magic;
|
public ulong Magic;
|
||||||
@@ -1004,8 +1003,8 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 20*/)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 16*/)]
|
||||||
private record struct FeatureInfo(uint FeatureInfo0, uint FeatureInfo1, uint FeatureInfo2, uint FeatureInfo3, uint FeatureInfo4);
|
private record struct FeatureInfo(uint FeatureInfo0, uint FeatureInfo1, uint FeatureInfo2, uint FeatureInfo3);
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 128*/)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 128*/)]
|
||||||
private struct InnerHeader
|
private struct InnerHeader
|
||||||
|
@@ -45,7 +45,7 @@
|
|||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBox
|
<TextBox
|
||||||
Name="Input"
|
Name="Input"
|
||||||
Grid.Row="2"
|
Grid.Row="3"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@@ -14,6 +14,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
public readonly bool SupportsBc123Compression;
|
public readonly bool SupportsBc123Compression;
|
||||||
public readonly bool SupportsBc45Compression;
|
public readonly bool SupportsBc45Compression;
|
||||||
public readonly bool SupportsBc67Compression;
|
public readonly bool SupportsBc67Compression;
|
||||||
|
public readonly bool SupportsEtc2Compression;
|
||||||
public readonly bool Supports3DTextureCompression;
|
public readonly bool Supports3DTextureCompression;
|
||||||
public readonly bool SupportsBgraFormat;
|
public readonly bool SupportsBgraFormat;
|
||||||
public readonly bool SupportsR4G4Format;
|
public readonly bool SupportsR4G4Format;
|
||||||
@@ -50,6 +51,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
bool supportsBc123Compression,
|
bool supportsBc123Compression,
|
||||||
bool supportsBc45Compression,
|
bool supportsBc45Compression,
|
||||||
bool supportsBc67Compression,
|
bool supportsBc67Compression,
|
||||||
|
bool supportsEtc2Compression,
|
||||||
bool supports3DTextureCompression,
|
bool supports3DTextureCompression,
|
||||||
bool supportsBgraFormat,
|
bool supportsBgraFormat,
|
||||||
bool supportsR4G4Format,
|
bool supportsR4G4Format,
|
||||||
@@ -83,6 +85,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
SupportsBc123Compression = supportsBc123Compression;
|
SupportsBc123Compression = supportsBc123Compression;
|
||||||
SupportsBc45Compression = supportsBc45Compression;
|
SupportsBc45Compression = supportsBc45Compression;
|
||||||
SupportsBc67Compression = supportsBc67Compression;
|
SupportsBc67Compression = supportsBc67Compression;
|
||||||
|
SupportsEtc2Compression = supportsEtc2Compression;
|
||||||
Supports3DTextureCompression = supports3DTextureCompression;
|
Supports3DTextureCompression = supports3DTextureCompression;
|
||||||
SupportsBgraFormat = supportsBgraFormat;
|
SupportsBgraFormat = supportsBgraFormat;
|
||||||
SupportsR4G4Format = supportsR4G4Format;
|
SupportsR4G4Format = supportsR4G4Format;
|
||||||
|
@@ -516,6 +516,27 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the texture format is an ETC2 format.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="format">Texture format</param>
|
||||||
|
/// <returns>True if the texture format is an ETC2 format, false otherwise</returns>
|
||||||
|
public static bool IsEtc2(this Format format)
|
||||||
|
{
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
|
case Format.Etc2RgbaSrgb:
|
||||||
|
case Format.Etc2RgbaUnorm:
|
||||||
|
case Format.Etc2RgbPtaSrgb:
|
||||||
|
case Format.Etc2RgbPtaUnorm:
|
||||||
|
case Format.Etc2RgbSrgb:
|
||||||
|
case Format.Etc2RgbUnorm:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if the texture format is a BGR format.
|
/// Checks if the texture format is a BGR format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -142,6 +142,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
_drawState.FirstIndex = firstIndex;
|
_drawState.FirstIndex = firstIndex;
|
||||||
_drawState.IndexCount = indexCount;
|
_drawState.IndexCount = indexCount;
|
||||||
|
_drawState.DrawFirstVertex = drawFirstVertex;
|
||||||
|
_drawState.DrawVertexCount = drawVertexCount;
|
||||||
_currentSpecState.SetHasConstantBufferDrawParameters(false);
|
_currentSpecState.SetHasConstantBufferDrawParameters(false);
|
||||||
|
|
||||||
engine.UpdateState();
|
engine.UpdateState();
|
||||||
@@ -163,10 +165,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
_instancedIndexCount = ibCount != 0 ? ibCount : indexCount;
|
_instancedIndexCount = ibCount != 0 ? ibCount : indexCount;
|
||||||
|
|
||||||
var drawState = _state.State.VertexBufferDrawState;
|
_instancedDrawStateFirst = drawFirstVertex;
|
||||||
|
_instancedDrawStateCount = drawVertexCount;
|
||||||
_instancedDrawStateFirst = drawState.First;
|
|
||||||
_instancedDrawStateCount = drawState.Count;
|
|
||||||
|
|
||||||
_drawState.DrawIndexed = false;
|
_drawState.DrawIndexed = false;
|
||||||
|
|
||||||
@@ -415,6 +415,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
bool oldDrawIndexed = _drawState.DrawIndexed;
|
bool oldDrawIndexed = _drawState.DrawIndexed;
|
||||||
|
|
||||||
_drawState.DrawIndexed = false;
|
_drawState.DrawIndexed = false;
|
||||||
|
engine.ForceStateDirty(VertexBufferFirstMethodOffset * 4);
|
||||||
|
|
||||||
DrawEnd(engine, 0, 0, firstVertex, vertexCount);
|
DrawEnd(engine, 0, 0, firstVertex, vertexCount);
|
||||||
|
|
||||||
@@ -526,8 +527,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_state.State.VertexBufferDrawState.First = firstVertex;
|
_drawState.DrawFirstVertex = firstVertex;
|
||||||
_state.State.VertexBufferDrawState.Count = count;
|
_drawState.DrawVertexCount = count;
|
||||||
engine.ForceStateDirty(VertexBufferFirstMethodOffset * 4);
|
engine.ForceStateDirty(VertexBufferFirstMethodOffset * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,6 +17,16 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int IndexCount;
|
public int IndexCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// First vertex used on non-indexed draws. This value is stored somewhere else on indexed draws.
|
||||||
|
/// </summary>
|
||||||
|
public int DrawFirstVertex;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Vertex count used on non-indexed draws. Indexed draws have a index count instead.
|
||||||
|
/// </summary>
|
||||||
|
public int DrawVertexCount;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if the next draw will be a indexed draw.
|
/// Indicates if the next draw will be a indexed draw.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -989,6 +989,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
bool drawIndexed = _drawState.DrawIndexed;
|
bool drawIndexed = _drawState.DrawIndexed;
|
||||||
bool drawIndirect = _drawState.DrawIndirect;
|
bool drawIndirect = _drawState.DrawIndirect;
|
||||||
|
int drawFirstVertex = _drawState.DrawFirstVertex;
|
||||||
|
int drawVertexCount = _drawState.DrawVertexCount;
|
||||||
uint vbEnableMask = 0;
|
uint vbEnableMask = 0;
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalVertexBuffers; index++)
|
for (int index = 0; index < Constants.TotalVertexBuffers; index++)
|
||||||
@@ -1050,9 +1052,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
int firstInstance = (int)_state.State.FirstInstance;
|
int firstInstance = (int)_state.State.FirstInstance;
|
||||||
|
|
||||||
var drawState = _state.State.VertexBufferDrawState;
|
size = Math.Min(vbSize, (ulong)((firstInstance + drawFirstVertex + drawVertexCount) * stride));
|
||||||
|
|
||||||
size = Math.Min(vbSize, (ulong)((firstInstance + drawState.First + drawState.Count) * stride));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_pipeline.VertexBuffers[index] = new BufferPipelineDescriptor(_channel.MemoryManager.IsMapped(address), stride, divisor);
|
_pipeline.VertexBuffers[index] = new BufferPipelineDescriptor(_channel.MemoryManager.IsMapped(address), stride, divisor);
|
||||||
|
@@ -208,8 +208,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
Bc6HSf16Float = Bc6HSf16 | RFloat | GFloat | BFloat | AFloat, // 0x7ff90
|
Bc6HSf16Float = Bc6HSf16 | RFloat | GFloat | BFloat | AFloat, // 0x7ff90
|
||||||
Bc6HUf16Float = Bc6HUf16 | RFloat | GFloat | BFloat | AFloat, // 0x7ff91
|
Bc6HUf16Float = Bc6HUf16 | RFloat | GFloat | BFloat | AFloat, // 0x7ff91
|
||||||
Etc2RgbUnorm = Etc2Rgb | RUnorm | GUnorm | BUnorm | AUnorm, // 0x24906
|
Etc2RgbUnorm = Etc2Rgb | RUnorm | GUnorm | BUnorm | AUnorm, // 0x24906
|
||||||
|
Etc2RgbPtaUnorm = Etc2RgbPta | RUnorm | GUnorm | BUnorm | AUnorm, // 0x2490a
|
||||||
Etc2RgbaUnorm = Etc2Rgba | RUnorm | GUnorm | BUnorm | AUnorm, // 0x2490b
|
Etc2RgbaUnorm = Etc2Rgba | RUnorm | GUnorm | BUnorm | AUnorm, // 0x2490b
|
||||||
Etc2RgbUnormSrgb = Etc2Rgb | RUnorm | GUnorm | BUnorm | AUnorm | Srgb, // 0xa4906
|
Etc2RgbUnormSrgb = Etc2Rgb | RUnorm | GUnorm | BUnorm | AUnorm | Srgb, // 0xa4906
|
||||||
|
Etc2RgbPtaUnormSrgb = Etc2RgbPta | RUnorm | GUnorm | BUnorm | AUnorm | Srgb, // 0xa490a
|
||||||
Etc2RgbaUnormSrgb = Etc2Rgba | RUnorm | GUnorm | BUnorm | AUnorm | Srgb, // 0xa490b
|
Etc2RgbaUnormSrgb = Etc2Rgba | RUnorm | GUnorm | BUnorm | AUnorm | Srgb, // 0xa490b
|
||||||
Astc2D4x4Unorm = Astc2D4x4 | RUnorm | GUnorm | BUnorm | AUnorm, // 0x24940
|
Astc2D4x4Unorm = Astc2D4x4 | RUnorm | GUnorm | BUnorm | AUnorm, // 0x24940
|
||||||
Astc2D5x4Unorm = Astc2D5x4 | RUnorm | GUnorm | BUnorm | AUnorm, // 0x24950
|
Astc2D5x4Unorm = Astc2D5x4 | RUnorm | GUnorm | BUnorm | AUnorm, // 0x24950
|
||||||
@@ -429,8 +431,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
{ TextureFormat.Bc6HSf16Float, new FormatInfo(Format.Bc6HSfloat, 4, 4, 16, 4) },
|
{ TextureFormat.Bc6HSf16Float, new FormatInfo(Format.Bc6HSfloat, 4, 4, 16, 4) },
|
||||||
{ TextureFormat.Bc6HUf16Float, new FormatInfo(Format.Bc6HUfloat, 4, 4, 16, 4) },
|
{ TextureFormat.Bc6HUf16Float, new FormatInfo(Format.Bc6HUfloat, 4, 4, 16, 4) },
|
||||||
{ TextureFormat.Etc2RgbUnorm, new FormatInfo(Format.Etc2RgbUnorm, 4, 4, 8, 3) },
|
{ TextureFormat.Etc2RgbUnorm, new FormatInfo(Format.Etc2RgbUnorm, 4, 4, 8, 3) },
|
||||||
|
{ TextureFormat.Etc2RgbPtaUnorm, new FormatInfo(Format.Etc2RgbPtaUnorm, 4, 4, 8, 4) },
|
||||||
{ TextureFormat.Etc2RgbaUnorm, new FormatInfo(Format.Etc2RgbaUnorm, 4, 4, 16, 4) },
|
{ TextureFormat.Etc2RgbaUnorm, new FormatInfo(Format.Etc2RgbaUnorm, 4, 4, 16, 4) },
|
||||||
{ TextureFormat.Etc2RgbUnormSrgb, new FormatInfo(Format.Etc2RgbSrgb, 4, 4, 8, 3) },
|
{ TextureFormat.Etc2RgbUnormSrgb, new FormatInfo(Format.Etc2RgbSrgb, 4, 4, 8, 3) },
|
||||||
|
{ TextureFormat.Etc2RgbPtaUnormSrgb, new FormatInfo(Format.Etc2RgbPtaSrgb, 4, 4, 8, 4) },
|
||||||
{ TextureFormat.Etc2RgbaUnormSrgb, new FormatInfo(Format.Etc2RgbaSrgb, 4, 4, 16, 4) },
|
{ TextureFormat.Etc2RgbaUnormSrgb, new FormatInfo(Format.Etc2RgbaSrgb, 4, 4, 16, 4) },
|
||||||
{ TextureFormat.Astc2D4x4Unorm, new FormatInfo(Format.Astc4x4Unorm, 4, 4, 16, 4) },
|
{ TextureFormat.Astc2D4x4Unorm, new FormatInfo(Format.Astc4x4Unorm, 4, 4, 16, 4) },
|
||||||
{ TextureFormat.Astc2D5x4Unorm, new FormatInfo(Format.Astc5x4Unorm, 5, 4, 16, 4) },
|
{ TextureFormat.Astc2D5x4Unorm, new FormatInfo(Format.Astc5x4Unorm, 5, 4, 16, 4) },
|
||||||
|
@@ -857,9 +857,23 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
result = decoded;
|
result = decoded;
|
||||||
}
|
}
|
||||||
else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm)
|
else if (!_context.Capabilities.SupportsEtc2Compression && Format.IsEtc2())
|
||||||
{
|
{
|
||||||
result = PixelConverter.ConvertR4G4ToR4G4B4A4(result);
|
switch (Format)
|
||||||
|
{
|
||||||
|
case Format.Etc2RgbaSrgb:
|
||||||
|
case Format.Etc2RgbaUnorm:
|
||||||
|
result = ETC2Decoder.DecodeRgba(result, width, height, depth, levels, layers);
|
||||||
|
break;
|
||||||
|
case Format.Etc2RgbPtaSrgb:
|
||||||
|
case Format.Etc2RgbPtaUnorm:
|
||||||
|
result = ETC2Decoder.DecodePta(result, width, height, depth, levels, layers);
|
||||||
|
break;
|
||||||
|
case Format.Etc2RgbSrgb:
|
||||||
|
case Format.Etc2RgbUnorm:
|
||||||
|
result = ETC2Decoder.DecodeRgb(result, width, height, depth, levels, layers);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!TextureCompatibility.HostSupportsBcFormat(Format, Target, _context.Capabilities))
|
else if (!TextureCompatibility.HostSupportsBcFormat(Format, Target, _context.Capabilities))
|
||||||
{
|
{
|
||||||
@@ -895,6 +909,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!_context.Capabilities.SupportsR4G4Format && Format == Format.R4G4Unorm)
|
||||||
|
{
|
||||||
|
result = PixelConverter.ConvertR4G4ToR4G4B4A4(result);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@@ -320,10 +320,15 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
|
|
||||||
// Check if the texture pool has been modified since bindings were last committed.
|
// Check if the texture pool has been modified since bindings were last committed.
|
||||||
// If it wasn't, then it's possible to avoid looking up textures again when the handle remains the same.
|
// If it wasn't, then it's possible to avoid looking up textures again when the handle remains the same.
|
||||||
bool poolModified = _cachedTexturePool != texturePool || _cachedSamplerPool != samplerPool;
|
if (_cachedTexturePool != texturePool || _cachedSamplerPool != samplerPool)
|
||||||
|
{
|
||||||
|
Rebind();
|
||||||
|
|
||||||
_cachedTexturePool = texturePool;
|
_cachedTexturePool = texturePool;
|
||||||
_cachedSamplerPool = samplerPool;
|
_cachedSamplerPool = samplerPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool poolModified = false;
|
||||||
|
|
||||||
if (texturePool != null)
|
if (texturePool != null)
|
||||||
{
|
{
|
||||||
|
@@ -67,6 +67,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// <returns>A host compatible format</returns>
|
/// <returns>A host compatible format</returns>
|
||||||
public static FormatInfo ToHostCompatibleFormat(TextureInfo info, Capabilities caps)
|
public static FormatInfo ToHostCompatibleFormat(TextureInfo info, Capabilities caps)
|
||||||
{
|
{
|
||||||
|
// The host API does not support those compressed formats.
|
||||||
|
// We assume software decompression will be done for those textures,
|
||||||
|
// and so we adjust the format here to match the decompressor output.
|
||||||
|
|
||||||
if (!caps.SupportsAstcCompression)
|
if (!caps.SupportsAstcCompression)
|
||||||
{
|
{
|
||||||
if (info.FormatInfo.Format.IsAstcUnorm())
|
if (info.FormatInfo.Format.IsAstcUnorm())
|
||||||
@@ -83,16 +87,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!caps.SupportsR4G4Format && info.FormatInfo.Format == Format.R4G4Unorm)
|
|
||||||
{
|
|
||||||
return new FormatInfo(Format.R4G4B4A4Unorm, 1, 1, 2, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!HostSupportsBcFormat(info.FormatInfo.Format, info.Target, caps))
|
if (!HostSupportsBcFormat(info.FormatInfo.Format, info.Target, caps))
|
||||||
{
|
{
|
||||||
// The host API does not this compressed format.
|
|
||||||
// We assume software decompression will be done for those textures,
|
|
||||||
// and so we adjust the format here to match the decompressor output.
|
|
||||||
switch (info.FormatInfo.Format)
|
switch (info.FormatInfo.Format)
|
||||||
{
|
{
|
||||||
case Format.Bc1RgbaSrgb:
|
case Format.Bc1RgbaSrgb:
|
||||||
@@ -119,6 +115,26 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!caps.SupportsEtc2Compression)
|
||||||
|
{
|
||||||
|
switch (info.FormatInfo.Format)
|
||||||
|
{
|
||||||
|
case Format.Etc2RgbaSrgb:
|
||||||
|
case Format.Etc2RgbPtaSrgb:
|
||||||
|
case Format.Etc2RgbSrgb:
|
||||||
|
return new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4, 4);
|
||||||
|
case Format.Etc2RgbaUnorm:
|
||||||
|
case Format.Etc2RgbPtaUnorm:
|
||||||
|
case Format.Etc2RgbUnorm:
|
||||||
|
return new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!caps.SupportsR4G4Format && info.FormatInfo.Format == Format.R4G4Unorm)
|
||||||
|
{
|
||||||
|
return new FormatInfo(Format.R4G4B4A4Unorm, 1, 1, 2, 4);
|
||||||
|
}
|
||||||
|
|
||||||
return info.FormatInfo;
|
return info.FormatInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -110,6 +110,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
supportsBc123Compression: HwCapabilities.SupportsTextureCompressionS3tc,
|
supportsBc123Compression: HwCapabilities.SupportsTextureCompressionS3tc,
|
||||||
supportsBc45Compression: HwCapabilities.SupportsTextureCompressionRgtc,
|
supportsBc45Compression: HwCapabilities.SupportsTextureCompressionRgtc,
|
||||||
supportsBc67Compression: true, // Should check BPTC extension, but for some reason NVIDIA is not exposing the extension.
|
supportsBc67Compression: true, // Should check BPTC extension, but for some reason NVIDIA is not exposing the extension.
|
||||||
|
supportsEtc2Compression: true,
|
||||||
supports3DTextureCompression: false,
|
supports3DTextureCompression: false,
|
||||||
supportsBgraFormat: false,
|
supportsBgraFormat: false,
|
||||||
supportsR4G4Format: false,
|
supportsR4G4Format: false,
|
||||||
|
682
Ryujinx.Graphics.Texture/ETC2Decoder.cs
Normal file
682
Ryujinx.Graphics.Texture/ETC2Decoder.cs
Normal file
@@ -0,0 +1,682 @@
|
|||||||
|
using Ryujinx.Common;
|
||||||
|
using System;
|
||||||
|
using System.Buffers.Binary;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Texture
|
||||||
|
{
|
||||||
|
public static class ETC2Decoder
|
||||||
|
{
|
||||||
|
private const uint AlphaMask = 0xff000000u;
|
||||||
|
|
||||||
|
private const int BlockWidth = 4;
|
||||||
|
private const int BlockHeight = 4;
|
||||||
|
|
||||||
|
private static readonly int[][] _etc1Lut =
|
||||||
|
{
|
||||||
|
new int[] { 2, 8, -2, -8 },
|
||||||
|
new int[] { 5, 17, -5, -17 },
|
||||||
|
new int[] { 9, 29, -9, -29 },
|
||||||
|
new int[] { 13, 42, -13, -42 },
|
||||||
|
new int[] { 18, 60, -18, -60 },
|
||||||
|
new int[] { 24, 80, -24, -80 },
|
||||||
|
new int[] { 33, 106, -33, -106 },
|
||||||
|
new int[] { 47, 183, -47, -183 }
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly int[] _etc2Lut =
|
||||||
|
{
|
||||||
|
3, 6, 11, 16, 23, 32, 41, 64
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly int[][] _etc2AlphaLut =
|
||||||
|
{
|
||||||
|
new int[] { -3, -6, -9, -15, 2, 5, 8, 14 },
|
||||||
|
new int[] { -3, -7, -10, -13, 2, 6, 9, 12 },
|
||||||
|
new int[] { -2, -5, -8, -13, 1, 4, 7, 12 },
|
||||||
|
new int[] { -2, -4, -6, -13, 1, 3, 5, 12 },
|
||||||
|
new int[] { -3, -6, -8, -12, 2, 5, 7, 11 },
|
||||||
|
new int[] { -3, -7, -9, -11, 2, 6, 8, 10 },
|
||||||
|
new int[] { -4, -7, -8, -11, 3, 6, 7, 10 },
|
||||||
|
new int[] { -3, -5, -8, -11, 2, 4, 7, 10 },
|
||||||
|
new int[] { -2, -6, -8, -10, 1, 5, 7, 9 },
|
||||||
|
new int[] { -2, -5, -8, -10, 1, 4, 7, 9 },
|
||||||
|
new int[] { -2, -4, -8, -10, 1, 3, 7, 9 },
|
||||||
|
new int[] { -2, -5, -7, -10, 1, 4, 6, 9 },
|
||||||
|
new int[] { -3, -4, -7, -10, 2, 3, 6, 9 },
|
||||||
|
new int[] { -1, -2, -3, -10, 0, 1, 2, 9 },
|
||||||
|
new int[] { -4, -6, -8, -9, 3, 5, 7, 8 },
|
||||||
|
new int[] { -3, -5, -7, -9, 2, 4, 6, 8 }
|
||||||
|
};
|
||||||
|
|
||||||
|
public static byte[] DecodeRgb(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
|
||||||
|
{
|
||||||
|
ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data);
|
||||||
|
|
||||||
|
int inputOffset = 0;
|
||||||
|
|
||||||
|
byte[] output = new byte[CalculateOutputSize(width, height, depth, levels, layers)];
|
||||||
|
|
||||||
|
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output);
|
||||||
|
Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight];
|
||||||
|
|
||||||
|
int imageBaseOOffs = 0;
|
||||||
|
|
||||||
|
for (int l = 0; l < levels; l++)
|
||||||
|
{
|
||||||
|
int wInBlocks = BitUtils.DivRoundUp(width, BlockWidth);
|
||||||
|
int hInBlocks = BitUtils.DivRoundUp(height, BlockHeight);
|
||||||
|
|
||||||
|
for (int l2 = 0; l2 < layers; l2++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < depth; z++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < hInBlocks; y++)
|
||||||
|
{
|
||||||
|
int ty = y * BlockHeight;
|
||||||
|
int bh = Math.Min(BlockHeight, height - ty);
|
||||||
|
|
||||||
|
for (int x = 0; x < wInBlocks; x++)
|
||||||
|
{
|
||||||
|
int tx = x * BlockWidth;
|
||||||
|
int bw = Math.Min(BlockWidth, width - tx);
|
||||||
|
|
||||||
|
ulong colorBlock = dataUlong[inputOffset++];
|
||||||
|
|
||||||
|
DecodeBlock(tile, colorBlock);
|
||||||
|
|
||||||
|
for (int py = 0; py < bh; py++)
|
||||||
|
{
|
||||||
|
int oOffsBase = imageBaseOOffs + ((ty + py) * width) + tx;
|
||||||
|
|
||||||
|
for (int px = 0; px < bw; px++)
|
||||||
|
{
|
||||||
|
int oOffs = oOffsBase + px;
|
||||||
|
|
||||||
|
outputUint[oOffs] = tile[py * BlockWidth + px] | AlphaMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
imageBaseOOffs += width * height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
width = Math.Max(1, width >> 1);
|
||||||
|
height = Math.Max(1, height >> 1);
|
||||||
|
depth = Math.Max(1, depth >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] DecodePta(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
|
||||||
|
{
|
||||||
|
ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data);
|
||||||
|
|
||||||
|
int inputOffset = 0;
|
||||||
|
|
||||||
|
byte[] output = new byte[CalculateOutputSize(width, height, depth, levels, layers)];
|
||||||
|
|
||||||
|
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output);
|
||||||
|
Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight];
|
||||||
|
|
||||||
|
int imageBaseOOffs = 0;
|
||||||
|
|
||||||
|
for (int l = 0; l < levels; l++)
|
||||||
|
{
|
||||||
|
int wInBlocks = BitUtils.DivRoundUp(width, BlockWidth);
|
||||||
|
int hInBlocks = BitUtils.DivRoundUp(height, BlockHeight);
|
||||||
|
|
||||||
|
for (int l2 = 0; l2 < layers; l2++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < depth; z++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < hInBlocks; y++)
|
||||||
|
{
|
||||||
|
int ty = y * BlockHeight;
|
||||||
|
int bh = Math.Min(BlockHeight, height - ty);
|
||||||
|
|
||||||
|
for (int x = 0; x < wInBlocks; x++)
|
||||||
|
{
|
||||||
|
int tx = x * BlockWidth;
|
||||||
|
int bw = Math.Min(BlockWidth, width - tx);
|
||||||
|
|
||||||
|
ulong colorBlock = dataUlong[inputOffset++];
|
||||||
|
|
||||||
|
DecodeBlockPta(tile, colorBlock);
|
||||||
|
|
||||||
|
for (int py = 0; py < bh; py++)
|
||||||
|
{
|
||||||
|
int oOffsBase = imageBaseOOffs + ((ty + py) * width) + tx;
|
||||||
|
|
||||||
|
tile.Slice(py * BlockWidth, bw).CopyTo(outputUint.Slice(oOffsBase, bw));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
imageBaseOOffs += width * height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
width = Math.Max(1, width >> 1);
|
||||||
|
height = Math.Max(1, height >> 1);
|
||||||
|
depth = Math.Max(1, depth >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] DecodeRgba(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
|
||||||
|
{
|
||||||
|
ReadOnlySpan<ulong> dataUlong = MemoryMarshal.Cast<byte, ulong>(data);
|
||||||
|
|
||||||
|
int inputOffset = 0;
|
||||||
|
|
||||||
|
byte[] output = new byte[CalculateOutputSize(width, height, depth, levels, layers)];
|
||||||
|
|
||||||
|
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output);
|
||||||
|
Span<uint> tile = stackalloc uint[BlockWidth * BlockHeight];
|
||||||
|
|
||||||
|
int imageBaseOOffs = 0;
|
||||||
|
|
||||||
|
for (int l = 0; l < levels; l++)
|
||||||
|
{
|
||||||
|
int wInBlocks = BitUtils.DivRoundUp(width, BlockWidth);
|
||||||
|
int hInBlocks = BitUtils.DivRoundUp(height, BlockHeight);
|
||||||
|
|
||||||
|
for (int l2 = 0; l2 < layers; l2++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < depth; z++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < hInBlocks; y++)
|
||||||
|
{
|
||||||
|
int ty = y * BlockHeight;
|
||||||
|
int bh = Math.Min(BlockHeight, height - ty);
|
||||||
|
|
||||||
|
for (int x = 0; x < wInBlocks; x++)
|
||||||
|
{
|
||||||
|
int tx = x * BlockWidth;
|
||||||
|
int bw = Math.Min(BlockWidth, width - tx);
|
||||||
|
|
||||||
|
ulong alphaBlock = dataUlong[inputOffset];
|
||||||
|
ulong colorBlock = dataUlong[inputOffset + 1];
|
||||||
|
|
||||||
|
inputOffset += 2;
|
||||||
|
|
||||||
|
DecodeBlock(tile, colorBlock);
|
||||||
|
|
||||||
|
byte alphaBase = (byte)alphaBlock;
|
||||||
|
int[] alphaTable = _etc2AlphaLut[(alphaBlock >> 8) & 0xf];
|
||||||
|
int alphaMultiplier = (int)(alphaBlock >> 12) & 0xf;
|
||||||
|
ulong alphaIndices = BinaryPrimitives.ReverseEndianness(alphaBlock);
|
||||||
|
|
||||||
|
if (alphaMultiplier != 0)
|
||||||
|
{
|
||||||
|
for (int py = 0; py < bh; py++)
|
||||||
|
{
|
||||||
|
int oOffsBase = imageBaseOOffs + ((ty + py) * width) + tx;
|
||||||
|
|
||||||
|
for (int px = 0; px < bw; px++)
|
||||||
|
{
|
||||||
|
int oOffs = oOffsBase + px;
|
||||||
|
int alphaIndex = (int)((alphaIndices >> (((px * BlockHeight + py) ^ 0xf) * 3)) & 7);
|
||||||
|
|
||||||
|
byte a = Saturate(alphaBase + alphaTable[alphaIndex] * alphaMultiplier);
|
||||||
|
|
||||||
|
outputUint[oOffs] = tile[py * BlockWidth + px] | ((uint)a << 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint a = (uint)alphaBase << 24;
|
||||||
|
|
||||||
|
for (int py = 0; py < bh; py++)
|
||||||
|
{
|
||||||
|
int oOffsBase = imageBaseOOffs + ((ty + py) * width) + tx;
|
||||||
|
|
||||||
|
for (int px = 0; px < bw; px++)
|
||||||
|
{
|
||||||
|
int oOffs = oOffsBase + px;
|
||||||
|
|
||||||
|
outputUint[oOffs] = tile[py * BlockWidth + px] | a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
imageBaseOOffs += width * height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
width = Math.Max(1, width >> 1);
|
||||||
|
height = Math.Max(1, height >> 1);
|
||||||
|
depth = Math.Max(1, depth >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DecodeBlock(Span<uint> tile, ulong block)
|
||||||
|
{
|
||||||
|
uint blockLow = (uint)(block >> 0);
|
||||||
|
uint blockHigh = (uint)(block >> 32);
|
||||||
|
|
||||||
|
uint r1, g1, b1;
|
||||||
|
uint r2, g2, b2;
|
||||||
|
|
||||||
|
bool differentialMode = (blockLow & 0x2000000) != 0;
|
||||||
|
|
||||||
|
if (differentialMode)
|
||||||
|
{
|
||||||
|
(r1, g1, b1, r2, g2, b2) = UnpackRgb555DiffEndPoints(blockLow);
|
||||||
|
|
||||||
|
if (r2 > 31)
|
||||||
|
{
|
||||||
|
DecodeBlock59T(tile, blockLow, blockHigh);
|
||||||
|
}
|
||||||
|
else if (g2 > 31)
|
||||||
|
{
|
||||||
|
DecodeBlock58H(tile, blockLow, blockHigh);
|
||||||
|
}
|
||||||
|
else if (b2 > 31)
|
||||||
|
{
|
||||||
|
DecodeBlock57P(tile, block);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r1 |= r1 >> 5;
|
||||||
|
g1 |= g1 >> 5;
|
||||||
|
b1 |= b1 >> 5;
|
||||||
|
|
||||||
|
r2 = (r2 << 3) | (r2 >> 2);
|
||||||
|
g2 = (g2 << 3) | (g2 >> 2);
|
||||||
|
b2 = (b2 << 3) | (b2 >> 2);
|
||||||
|
|
||||||
|
DecodeBlockETC1(tile, blockLow, blockHigh, r1, g1, b1, r2, g2, b2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r1 = (blockLow & 0x0000f0) >> 0;
|
||||||
|
g1 = (blockLow & 0x00f000) >> 8;
|
||||||
|
b1 = (blockLow & 0xf00000) >> 16;
|
||||||
|
|
||||||
|
r2 = (blockLow & 0x00000f) << 4;
|
||||||
|
g2 = (blockLow & 0x000f00) >> 4;
|
||||||
|
b2 = (blockLow & 0x0f0000) >> 12;
|
||||||
|
|
||||||
|
r1 |= r1 >> 4;
|
||||||
|
g1 |= g1 >> 4;
|
||||||
|
b1 |= b1 >> 4;
|
||||||
|
|
||||||
|
r2 |= r2 >> 4;
|
||||||
|
g2 |= g2 >> 4;
|
||||||
|
b2 |= b2 >> 4;
|
||||||
|
|
||||||
|
DecodeBlockETC1(tile, blockLow, blockHigh, r1, g1, b1, r2, g2, b2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DecodeBlockPta(Span<uint> tile, ulong block)
|
||||||
|
{
|
||||||
|
uint blockLow = (uint)(block >> 0);
|
||||||
|
uint blockHigh = (uint)(block >> 32);
|
||||||
|
|
||||||
|
(uint r1, uint g1, uint b1, uint r2, uint g2, uint b2) = UnpackRgb555DiffEndPoints(blockLow);
|
||||||
|
|
||||||
|
bool fullyOpaque = (blockLow & 0x2000000) != 0;
|
||||||
|
|
||||||
|
if (fullyOpaque)
|
||||||
|
{
|
||||||
|
if (r2 > 31)
|
||||||
|
{
|
||||||
|
DecodeBlock59T(tile, blockLow, blockHigh);
|
||||||
|
}
|
||||||
|
else if (g2 > 31)
|
||||||
|
{
|
||||||
|
DecodeBlock58H(tile, blockLow, blockHigh);
|
||||||
|
}
|
||||||
|
else if (b2 > 31)
|
||||||
|
{
|
||||||
|
DecodeBlock57P(tile, block);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r1 |= r1 >> 5;
|
||||||
|
g1 |= g1 >> 5;
|
||||||
|
b1 |= b1 >> 5;
|
||||||
|
|
||||||
|
r2 = (r2 << 3) | (r2 >> 2);
|
||||||
|
g2 = (g2 << 3) | (g2 >> 2);
|
||||||
|
b2 = (b2 << 3) | (b2 >> 2);
|
||||||
|
|
||||||
|
DecodeBlockETC1(tile, blockLow, blockHigh, r1, g1, b1, r2, g2, b2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < tile.Length; i++)
|
||||||
|
{
|
||||||
|
tile[i] |= AlphaMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (r2 > 31)
|
||||||
|
{
|
||||||
|
DecodeBlock59T(tile, blockLow, blockHigh, AlphaMask);
|
||||||
|
}
|
||||||
|
else if (g2 > 31)
|
||||||
|
{
|
||||||
|
DecodeBlock58H(tile, blockLow, blockHigh, AlphaMask);
|
||||||
|
}
|
||||||
|
else if (b2 > 31)
|
||||||
|
{
|
||||||
|
DecodeBlock57P(tile, block);
|
||||||
|
|
||||||
|
for (int i = 0; i < tile.Length; i++)
|
||||||
|
{
|
||||||
|
tile[i] |= AlphaMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r1 |= r1 >> 5;
|
||||||
|
g1 |= g1 >> 5;
|
||||||
|
b1 |= b1 >> 5;
|
||||||
|
|
||||||
|
r2 = (r2 << 3) | (r2 >> 2);
|
||||||
|
g2 = (g2 << 3) | (g2 >> 2);
|
||||||
|
b2 = (b2 << 3) | (b2 >> 2);
|
||||||
|
|
||||||
|
DecodeBlockETC1(tile, blockLow, blockHigh, r1, g1, b1, r2, g2, b2, AlphaMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (uint, uint, uint, uint, uint, uint) UnpackRgb555DiffEndPoints(uint blockLow)
|
||||||
|
{
|
||||||
|
uint r1 = (blockLow & 0x0000f8) >> 0;
|
||||||
|
uint g1 = (blockLow & 0x00f800) >> 8;
|
||||||
|
uint b1 = (blockLow & 0xf80000) >> 16;
|
||||||
|
|
||||||
|
uint r2 = (uint)((sbyte)(r1 >> 3) + ((sbyte)((blockLow & 0x000007) << 5) >> 5));
|
||||||
|
uint g2 = (uint)((sbyte)(g1 >> 3) + ((sbyte)((blockLow & 0x000700) >> 3) >> 5));
|
||||||
|
uint b2 = (uint)((sbyte)(b1 >> 3) + ((sbyte)((blockLow & 0x070000) >> 11) >> 5));
|
||||||
|
|
||||||
|
return (r1, g1, b1, r2, g2, b2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DecodeBlock59T(Span<uint> tile, uint blockLow, uint blockHigh, uint alphaMask = 0)
|
||||||
|
{
|
||||||
|
uint r1 = (blockLow & 3) | ((blockLow >> 1) & 0xc);
|
||||||
|
uint g1 = (blockLow >> 12) & 0xf;
|
||||||
|
uint b1 = (blockLow >> 8) & 0xf;
|
||||||
|
|
||||||
|
uint r2 = (blockLow >> 20) & 0xf;
|
||||||
|
uint g2 = (blockLow >> 16) & 0xf;
|
||||||
|
uint b2 = (blockLow >> 28) & 0xf;
|
||||||
|
|
||||||
|
r1 |= r1 << 4;
|
||||||
|
g1 |= g1 << 4;
|
||||||
|
b1 |= b1 << 4;
|
||||||
|
|
||||||
|
r2 |= r2 << 4;
|
||||||
|
g2 |= g2 << 4;
|
||||||
|
b2 |= b2 << 4;
|
||||||
|
|
||||||
|
int dist = _etc2Lut[((blockLow >> 24) & 1) | ((blockLow >> 25) & 6)];
|
||||||
|
|
||||||
|
Span<uint> palette = stackalloc uint[4];
|
||||||
|
|
||||||
|
palette[0] = Pack(r1, g1, b1);
|
||||||
|
palette[1] = Pack(r2, g2, b2, dist);
|
||||||
|
palette[2] = Pack(r2, g2, b2);
|
||||||
|
palette[3] = Pack(r2, g2, b2, -dist);
|
||||||
|
|
||||||
|
blockHigh = BinaryPrimitives.ReverseEndianness(blockHigh);
|
||||||
|
|
||||||
|
for (int y = 0; y < BlockHeight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BlockWidth; x++)
|
||||||
|
{
|
||||||
|
int offset = (y * 4) + x;
|
||||||
|
int index = (x * 4) + y;
|
||||||
|
|
||||||
|
int paletteIndex = (int)((blockHigh >> index) & 1) | (int)((blockHigh >> (index + 15)) & 2);
|
||||||
|
|
||||||
|
tile[offset] = palette[paletteIndex];
|
||||||
|
|
||||||
|
if (alphaMask != 0)
|
||||||
|
{
|
||||||
|
if (paletteIndex == 2)
|
||||||
|
{
|
||||||
|
tile[offset] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tile[offset] |= alphaMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DecodeBlock58H(Span<uint> tile, uint blockLow, uint blockHigh, uint alphaMask = 0)
|
||||||
|
{
|
||||||
|
uint r1 = (blockLow >> 3) & 0xf;
|
||||||
|
uint g1 = ((blockLow << 1) & 0xe) | ((blockLow >> 12) & 1);
|
||||||
|
uint b1 = ((blockLow >> 23) & 1) | ((blockLow >> 7) & 6) | ((blockLow >> 8) & 8);
|
||||||
|
|
||||||
|
uint r2 = (blockLow >> 19) & 0xf;
|
||||||
|
uint g2 = ((blockLow >> 31) & 1) | ((blockLow >> 15) & 0xe);
|
||||||
|
uint b2 = (blockLow >> 27) & 0xf;
|
||||||
|
|
||||||
|
uint rgb1 = Pack4Be(r1, g1, b1);
|
||||||
|
uint rgb2 = Pack4Be(r2, g2, b2);
|
||||||
|
|
||||||
|
r1 |= r1 << 4;
|
||||||
|
g1 |= g1 << 4;
|
||||||
|
b1 |= b1 << 4;
|
||||||
|
|
||||||
|
r2 |= r2 << 4;
|
||||||
|
g2 |= g2 << 4;
|
||||||
|
b2 |= b2 << 4;
|
||||||
|
|
||||||
|
int dist = _etc2Lut[(rgb1 >= rgb2 ? 1u : 0u) | ((blockLow >> 23) & 2) | ((blockLow >> 24) & 4)];
|
||||||
|
|
||||||
|
Span<uint> palette = stackalloc uint[4];
|
||||||
|
|
||||||
|
palette[0] = Pack(r1, g1, b1, dist);
|
||||||
|
palette[1] = Pack(r1, g1, b1, -dist);
|
||||||
|
palette[2] = Pack(r2, g2, b2, dist);
|
||||||
|
palette[3] = Pack(r2, g2, b2, -dist);
|
||||||
|
|
||||||
|
blockHigh = BinaryPrimitives.ReverseEndianness(blockHigh);
|
||||||
|
|
||||||
|
for (int y = 0; y < BlockHeight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BlockWidth; x++)
|
||||||
|
{
|
||||||
|
int offset = (y * 4) + x;
|
||||||
|
int index = (x * 4) + y;
|
||||||
|
|
||||||
|
int paletteIndex = (int)((blockHigh >> index) & 1) | (int)((blockHigh >> (index + 15)) & 2);
|
||||||
|
|
||||||
|
tile[offset] = palette[paletteIndex];
|
||||||
|
|
||||||
|
if (alphaMask != 0)
|
||||||
|
{
|
||||||
|
if (paletteIndex == 2)
|
||||||
|
{
|
||||||
|
tile[offset] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tile[offset] |= alphaMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DecodeBlock57P(Span<uint> tile, ulong block)
|
||||||
|
{
|
||||||
|
int r0 = (int)((block >> 1) & 0x3f);
|
||||||
|
int g0 = (int)(((block >> 9) & 0x3f) | ((block & 1) << 6));
|
||||||
|
int b0 = (int)(((block >> 31) & 1) | ((block >> 15) & 6) | ((block >> 16) & 0x18) | ((block >> 3) & 0x20));
|
||||||
|
|
||||||
|
int rh = (int)(((block >> 24) & 1) | ((block >> 25) & 0x3e));
|
||||||
|
int gh = (int)((block >> 33) & 0x7f);
|
||||||
|
int bh = (int)(((block >> 43) & 0x1f) | ((block >> 27) & 0x20));
|
||||||
|
|
||||||
|
int rv = (int)(((block >> 53) & 7) | ((block >> 37) & 0x38));
|
||||||
|
int gv = (int)(((block >> 62) & 3) | ((block >> 46) & 0x7c));
|
||||||
|
int bv = (int)((block >> 56) & 0x3f);
|
||||||
|
|
||||||
|
r0 = (r0 << 2) | (r0 >> 4);
|
||||||
|
g0 = (g0 << 1) | (g0 >> 6);
|
||||||
|
b0 = (b0 << 2) | (b0 >> 4);
|
||||||
|
|
||||||
|
rh = (rh << 2) | (rh >> 4);
|
||||||
|
gh = (gh << 1) | (gh >> 6);
|
||||||
|
bh = (bh << 2) | (bh >> 4);
|
||||||
|
|
||||||
|
rv = (rv << 2) | (rv >> 4);
|
||||||
|
gv = (gv << 1) | (gv >> 6);
|
||||||
|
bv = (bv << 2) | (bv >> 4);
|
||||||
|
|
||||||
|
for (int y = 0; y < BlockHeight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BlockWidth; x++)
|
||||||
|
{
|
||||||
|
int offset = y * BlockWidth + x;
|
||||||
|
|
||||||
|
byte r = Saturate(((x * (rh - r0)) + (y * (rv - r0)) + (r0 * 4) + 2) >> 2);
|
||||||
|
byte g = Saturate(((x * (gh - g0)) + (y * (gv - g0)) + (g0 * 4) + 2) >> 2);
|
||||||
|
byte b = Saturate(((x * (bh - b0)) + (y * (bv - b0)) + (b0 * 4) + 2) >> 2);
|
||||||
|
|
||||||
|
tile[offset] = Pack(r, g, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DecodeBlockETC1(
|
||||||
|
Span<uint> tile,
|
||||||
|
uint blockLow,
|
||||||
|
uint blockHigh,
|
||||||
|
uint r1,
|
||||||
|
uint g1,
|
||||||
|
uint b1,
|
||||||
|
uint r2,
|
||||||
|
uint g2,
|
||||||
|
uint b2,
|
||||||
|
uint alphaMask = 0)
|
||||||
|
{
|
||||||
|
int[] table1 = _etc1Lut[(blockLow >> 29) & 7];
|
||||||
|
int[] table2 = _etc1Lut[(blockLow >> 26) & 7];
|
||||||
|
|
||||||
|
bool flip = (blockLow & 0x1000000) != 0;
|
||||||
|
|
||||||
|
if (!flip)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < BlockHeight; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BlockWidth / 2; x++)
|
||||||
|
{
|
||||||
|
uint color1 = CalculatePixel(r1, g1, b1, x + 0, y, blockHigh, table1, alphaMask);
|
||||||
|
uint color2 = CalculatePixel(r2, g2, b2, x + 2, y, blockHigh, table2, alphaMask);
|
||||||
|
|
||||||
|
int offset1 = y * BlockWidth + x;
|
||||||
|
int offset2 = y * BlockWidth + x + 2;
|
||||||
|
|
||||||
|
tile[offset1] = color1;
|
||||||
|
tile[offset2] = color2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int y = 0; y < BlockHeight / 2; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BlockWidth; x++)
|
||||||
|
{
|
||||||
|
uint color1 = CalculatePixel(r1, g1, b1, x, y + 0, blockHigh, table1, alphaMask);
|
||||||
|
uint color2 = CalculatePixel(r2, g2, b2, x, y + 2, blockHigh, table2, alphaMask);
|
||||||
|
|
||||||
|
int offset1 = (y * BlockWidth) + x;
|
||||||
|
int offset2 = ((y + 2) * BlockWidth) + x;
|
||||||
|
|
||||||
|
tile[offset1] = color1;
|
||||||
|
tile[offset2] = color2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint CalculatePixel(uint r, uint g, uint b, int x, int y, uint block, int[] table, uint alphaMask)
|
||||||
|
{
|
||||||
|
int index = x * BlockHeight + y;
|
||||||
|
uint msb = block << 1;
|
||||||
|
uint tableIndex = index < 8
|
||||||
|
? ((block >> (index + 24)) & 1) + ((msb >> (index + 8)) & 2)
|
||||||
|
: ((block >> (index + 8)) & 1) + ((msb >> (index - 8)) & 2);
|
||||||
|
|
||||||
|
if (alphaMask != 0)
|
||||||
|
{
|
||||||
|
if (tableIndex == 0)
|
||||||
|
{
|
||||||
|
return Pack(r, g, b) | alphaMask;
|
||||||
|
}
|
||||||
|
else if (tableIndex == 2)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Pack(r, g, b, table[tableIndex]) | alphaMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Pack(r, g, b, table[tableIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint Pack(uint r, uint g, uint b, int offset)
|
||||||
|
{
|
||||||
|
r = Saturate((int)(r + offset));
|
||||||
|
g = Saturate((int)(g + offset));
|
||||||
|
b = Saturate((int)(b + offset));
|
||||||
|
|
||||||
|
return Pack(r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint Pack(uint r, uint g, uint b)
|
||||||
|
{
|
||||||
|
return r | (g << 8) | (b << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint Pack4Be(uint r, uint g, uint b)
|
||||||
|
{
|
||||||
|
return (r << 8) | (g << 4) | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte Saturate(int value)
|
||||||
|
{
|
||||||
|
return value > byte.MaxValue ? byte.MaxValue : value < byte.MinValue ? byte.MinValue : (byte)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int CalculateOutputSize(int width, int height, int depth, int levels, int layers)
|
||||||
|
{
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
for (int l = 0; l < levels; l++)
|
||||||
|
{
|
||||||
|
size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -388,6 +388,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
GAL.Format.Bc7Srgb,
|
GAL.Format.Bc7Srgb,
|
||||||
GAL.Format.Bc7Unorm);
|
GAL.Format.Bc7Unorm);
|
||||||
|
|
||||||
|
bool supportsEtc2CompressionFormat = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
|
||||||
|
GAL.Format.Etc2RgbaSrgb,
|
||||||
|
GAL.Format.Etc2RgbaUnorm,
|
||||||
|
GAL.Format.Etc2RgbPtaSrgb,
|
||||||
|
GAL.Format.Etc2RgbPtaUnorm,
|
||||||
|
GAL.Format.Etc2RgbSrgb,
|
||||||
|
GAL.Format.Etc2RgbUnorm);
|
||||||
|
|
||||||
PhysicalDeviceVulkan12Features featuresVk12 = new PhysicalDeviceVulkan12Features()
|
PhysicalDeviceVulkan12Features featuresVk12 = new PhysicalDeviceVulkan12Features()
|
||||||
{
|
{
|
||||||
@@ -414,6 +421,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
supportsBc123Compression: supportsBc123CompressionFormat,
|
supportsBc123Compression: supportsBc123CompressionFormat,
|
||||||
supportsBc45Compression: supportsBc45CompressionFormat,
|
supportsBc45Compression: supportsBc45CompressionFormat,
|
||||||
supportsBc67Compression: supportsBc67CompressionFormat,
|
supportsBc67Compression: supportsBc67CompressionFormat,
|
||||||
|
supportsEtc2Compression: supportsEtc2CompressionFormat,
|
||||||
supports3DTextureCompression: true,
|
supports3DTextureCompression: true,
|
||||||
supportsBgraFormat: true,
|
supportsBgraFormat: true,
|
||||||
supportsR4G4Format: false,
|
supportsR4G4Format: false,
|
||||||
|
@@ -8,6 +8,8 @@ using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu;
|
|||||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel;
|
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl;
|
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrl;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu;
|
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostCtrlGpu;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostDbgGpu;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostProfGpu;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
|
||||||
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
using Ryujinx.HLE.HOS.Services.Nv.Types;
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
@@ -23,7 +25,13 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||||||
[Service("nvdrv:t")]
|
[Service("nvdrv:t")]
|
||||||
class INvDrvServices : IpcService
|
class INvDrvServices : IpcService
|
||||||
{
|
{
|
||||||
private static Dictionary<string, Type> _deviceFileRegistry = new Dictionary<string, Type>()
|
private static readonly List<string> _deviceFileDebugRegistry = new List<string>()
|
||||||
|
{
|
||||||
|
"/dev/nvhost-dbg-gpu",
|
||||||
|
"/dev/nvhost-prof-gpu"
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, Type> _deviceFileRegistry = new Dictionary<string, Type>()
|
||||||
{
|
{
|
||||||
{ "/dev/nvmap", typeof(NvMapDeviceFile) },
|
{ "/dev/nvmap", typeof(NvMapDeviceFile) },
|
||||||
{ "/dev/nvhost-ctrl", typeof(NvHostCtrlDeviceFile) },
|
{ "/dev/nvhost-ctrl", typeof(NvHostCtrlDeviceFile) },
|
||||||
@@ -35,6 +43,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||||||
//{ "/dev/nvhost-nvjpg", typeof(NvHostChannelDeviceFile) },
|
//{ "/dev/nvhost-nvjpg", typeof(NvHostChannelDeviceFile) },
|
||||||
{ "/dev/nvhost-vic", typeof(NvHostChannelDeviceFile) },
|
{ "/dev/nvhost-vic", typeof(NvHostChannelDeviceFile) },
|
||||||
//{ "/dev/nvhost-display", typeof(NvHostChannelDeviceFile) },
|
//{ "/dev/nvhost-display", typeof(NvHostChannelDeviceFile) },
|
||||||
|
{ "/dev/nvhost-dbg-gpu", typeof(NvHostDbgGpuDeviceFile) },
|
||||||
|
{ "/dev/nvhost-prof-gpu", typeof(NvHostProfGpuDeviceFile) },
|
||||||
};
|
};
|
||||||
|
|
||||||
public static IdDictionary DeviceFileIdRegistry = new IdDictionary();
|
public static IdDictionary DeviceFileIdRegistry = new IdDictionary();
|
||||||
@@ -44,13 +54,23 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||||||
|
|
||||||
private bool _transferMemInitialized = false;
|
private bool _transferMemInitialized = false;
|
||||||
|
|
||||||
|
// TODO: This should call set:sys::GetDebugModeFlag
|
||||||
|
private bool _debugModeEnabled = false;
|
||||||
|
|
||||||
public INvDrvServices(ServiceCtx context) : base(context.Device.System.NvDrvServer)
|
public INvDrvServices(ServiceCtx context) : base(context.Device.System.NvDrvServer)
|
||||||
{
|
{
|
||||||
_owner = 0;
|
_owner = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int Open(ServiceCtx context, string path)
|
private NvResult Open(ServiceCtx context, string path, out int fd)
|
||||||
{
|
{
|
||||||
|
fd = -1;
|
||||||
|
|
||||||
|
if (!_debugModeEnabled && _deviceFileDebugRegistry.Contains(path))
|
||||||
|
{
|
||||||
|
return NvResult.NotSupported;
|
||||||
|
}
|
||||||
|
|
||||||
if (_deviceFileRegistry.TryGetValue(path, out Type deviceFileClass))
|
if (_deviceFileRegistry.TryGetValue(path, out Type deviceFileClass))
|
||||||
{
|
{
|
||||||
ConstructorInfo constructor = deviceFileClass.GetConstructor(new Type[] { typeof(ServiceCtx), typeof(IVirtualMemoryManager), typeof(ulong) });
|
ConstructorInfo constructor = deviceFileClass.GetConstructor(new Type[] { typeof(ServiceCtx), typeof(IVirtualMemoryManager), typeof(ulong) });
|
||||||
@@ -59,14 +79,14 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||||||
|
|
||||||
deviceFile.Path = path;
|
deviceFile.Path = path;
|
||||||
|
|
||||||
return DeviceFileIdRegistry.Add(deviceFile);
|
fd = DeviceFileIdRegistry.Add(deviceFile);
|
||||||
}
|
|
||||||
else
|
return NvResult.Success;
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.ServiceNv, $"Cannot find file device \"{path}\"!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
Logger.Warning?.Print(LogClass.ServiceNv, $"Cannot find file device \"{path}\"!");
|
||||||
|
|
||||||
|
return NvResult.FileOperationFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private NvResult GetIoctlArgument(ServiceCtx context, NvIoctl ioctlCommand, out Span<byte> arguments)
|
private NvResult GetIoctlArgument(ServiceCtx context, NvIoctl ioctlCommand, out Span<byte> arguments)
|
||||||
@@ -229,12 +249,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||||||
|
|
||||||
string path = MemoryHelper.ReadAsciiString(context.Memory, pathPtr, (long)pathSize);
|
string path = MemoryHelper.ReadAsciiString(context.Memory, pathPtr, (long)pathSize);
|
||||||
|
|
||||||
fd = Open(context, path);
|
errorCode = Open(context, path, out fd);
|
||||||
|
|
||||||
if (fd == -1)
|
|
||||||
{
|
|
||||||
errorCode = NvResult.FileOperationFailed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.ResponseData.Write(fd);
|
context.ResponseData.Write(fd);
|
||||||
|
@@ -0,0 +1,11 @@
|
|||||||
|
using Ryujinx.Memory;
|
||||||
|
using System;
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostDbgGpu
|
||||||
|
{
|
||||||
|
class NvHostDbgGpuDeviceFile : NvDeviceFile
|
||||||
|
{
|
||||||
|
public NvHostDbgGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, ulong owner) : base(context, owner) { }
|
||||||
|
|
||||||
|
public override void Close() { }
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
using Ryujinx.Memory;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostProfGpu
|
||||||
|
{
|
||||||
|
class NvHostProfGpuDeviceFile : NvDeviceFile
|
||||||
|
{
|
||||||
|
public NvHostProfGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, ulong owner) : base(context, owner) { }
|
||||||
|
|
||||||
|
public override void Close() { }
|
||||||
|
}
|
||||||
|
}
|
@@ -57,9 +57,9 @@ namespace Ryujinx.HLE.HOS.SystemState
|
|||||||
DesiredTitleLanguage = language switch
|
DesiredTitleLanguage = language switch
|
||||||
{
|
{
|
||||||
SystemLanguage.Taiwanese or
|
SystemLanguage.Taiwanese or
|
||||||
SystemLanguage.TraditionalChinese => TitleLanguage.Taiwanese,
|
SystemLanguage.TraditionalChinese => TitleLanguage.TraditionalChinese,
|
||||||
SystemLanguage.Chinese or
|
SystemLanguage.Chinese or
|
||||||
SystemLanguage.SimplifiedChinese => TitleLanguage.Chinese,
|
SystemLanguage.SimplifiedChinese => TitleLanguage.SimplifiedChinese,
|
||||||
_ => Enum.Parse<TitleLanguage>(Enum.GetName<SystemLanguage>(language)),
|
_ => Enum.Parse<TitleLanguage>(Enum.GetName<SystemLanguage>(language)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -15,8 +15,8 @@
|
|||||||
Portuguese,
|
Portuguese,
|
||||||
Russian,
|
Russian,
|
||||||
Korean,
|
Korean,
|
||||||
Taiwanese,
|
TraditionalChinese,
|
||||||
Chinese,
|
SimplifiedChinese,
|
||||||
BrazilianPortuguese
|
BrazilianPortuguese
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,9 +11,7 @@
|
|||||||
<ProjectReference Include="..\Ryujinx.Graphics.Host1x\Ryujinx.Graphics.Host1x.csproj" />
|
<ProjectReference Include="..\Ryujinx.Graphics.Host1x\Ryujinx.Graphics.Host1x.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.Graphics.Nvdec\Ryujinx.Graphics.Nvdec.csproj" />
|
<ProjectReference Include="..\Ryujinx.Graphics.Nvdec\Ryujinx.Graphics.Nvdec.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.Graphics.Vic\Ryujinx.Graphics.Vic.csproj" />
|
<ProjectReference Include="..\Ryujinx.Graphics.Vic\Ryujinx.Graphics.Vic.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj"
|
<ProjectReference Include="..\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||||
OutputItemType="Analyzer"
|
|
||||||
ReferenceOutputAssembly="false" />
|
|
||||||
<ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
|
<ProjectReference Include="..\Ryujinx.Memory\Ryujinx.Memory.csproj" />
|
||||||
<ProjectReference Include="..\ARMeilleure\ARMeilleure.csproj" />
|
<ProjectReference Include="..\ARMeilleure\ARMeilleure.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
|
<ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
|
||||||
|
@@ -2176,8 +2176,8 @@ namespace Ryujinx.Tests.Cpu
|
|||||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||||
opcodes |= ((q & 1) << 30);
|
opcodes |= ((q & 1) << 30);
|
||||||
|
|
||||||
V128 v0 = MakeVectorE0E1(z, z);
|
V128 v0 = MakeVectorE0E1(z, a);
|
||||||
V128 v1 = MakeVectorE0E1(a, a);
|
V128 v1 = MakeVectorE0E1(a, z);
|
||||||
|
|
||||||
int rnd = (int)TestContext.CurrentContext.Random.NextUInt();
|
int rnd = (int)TestContext.CurrentContext.Random.NextUInt();
|
||||||
|
|
||||||
@@ -2202,8 +2202,8 @@ namespace Ryujinx.Tests.Cpu
|
|||||||
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||||
opcodes |= ((q & 1) << 30);
|
opcodes |= ((q & 1) << 30);
|
||||||
|
|
||||||
V128 v0 = MakeVectorE0E1(z, z);
|
V128 v0 = MakeVectorE0E1(z, a);
|
||||||
V128 v1 = MakeVectorE0E1(a, a);
|
V128 v1 = MakeVectorE0E1(a, z);
|
||||||
|
|
||||||
SingleOpcode(opcodes, v0: v0, v1: v1);
|
SingleOpcode(opcodes, v0: v0, v1: v1);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user