mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-09-27 19:58:00 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb37aea614 | ||
|
|
b40265e029 | ||
|
|
10c9e46fbe | ||
|
|
01f037ae83 | ||
|
|
bf618dc0b3 | ||
|
|
8b36e9fb39 | ||
|
|
0cf29113c0 | ||
|
|
e75d162dbd | ||
|
|
038f8352e0 | ||
|
|
2f48a5007a | ||
|
|
45db10220e | ||
|
|
ebe623bc07 | ||
|
|
4bcfae5905 | ||
|
|
eb6a7b9fea | ||
|
|
df322e6d57 | ||
|
|
d46a6bfed5 | ||
|
|
0e810e1e96 | ||
|
|
5da6c490b3 | ||
|
|
2ec9dda408 | ||
|
|
5b03721db6 | ||
|
|
3c644a712d | ||
|
|
19013d360a | ||
|
|
9bcb744a6a | ||
|
|
06ea0c32d3 | ||
|
|
feb3d9d31f | ||
|
|
198ee01437 | ||
|
|
58e3b5489b | ||
|
|
73b2eb6aeb | ||
|
|
6202526666 | ||
|
|
25bb6e8af7 | ||
|
|
191819488e | ||
|
|
85eb4761e8 | ||
|
|
90bf2ece82 | ||
|
|
772233d003 | ||
|
|
33955c1cb0 |
@@ -22,7 +22,7 @@
|
|||||||
<PackageVersion Include="LibHac" Version="0.19.0" />
|
<PackageVersion Include="LibHac" Version="0.19.0" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
||||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.6.1" />
|
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.9.0" />
|
||||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||||
@@ -48,8 +48,8 @@
|
|||||||
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
||||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
|
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
|
||||||
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
||||||
<PackageVersion Include="System.IO.Hashing" Version="9.0.3" />
|
<PackageVersion Include="System.IO.Hashing" Version="9.0.4" />
|
||||||
<PackageVersion Include="System.Management" Version="9.0.3" />
|
<PackageVersion Include="System.Management" Version="9.0.4" />
|
||||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -283,8 +283,6 @@ namespace ARMeilleure.Instructions
|
|||||||
switch (op.ShiftType)
|
switch (op.ShiftType)
|
||||||
{
|
{
|
||||||
case ShiftType.Lsr:
|
case ShiftType.Lsr:
|
||||||
shift = 32;
|
|
||||||
break;
|
|
||||||
case ShiftType.Asr:
|
case ShiftType.Asr:
|
||||||
shift = 32;
|
shift = 32;
|
||||||
break;
|
break;
|
||||||
@@ -332,8 +330,6 @@ namespace ARMeilleure.Instructions
|
|||||||
switch (shiftType)
|
switch (shiftType)
|
||||||
{
|
{
|
||||||
case ShiftType.Lsr:
|
case ShiftType.Lsr:
|
||||||
shift = 32;
|
|
||||||
break;
|
|
||||||
case ShiftType.Asr:
|
case ShiftType.Asr:
|
||||||
shift = 32;
|
shift = 32;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -305,8 +305,6 @@ namespace ARMeilleure.Instructions
|
|||||||
context.Store16(physAddr, value);
|
context.Store16(physAddr, value);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
context.Store(physAddr, value);
|
|
||||||
break;
|
|
||||||
case 3:
|
case 3:
|
||||||
context.Store(physAddr, value);
|
context.Store(physAddr, value);
|
||||||
break;
|
break;
|
||||||
@@ -591,8 +589,6 @@ namespace ARMeilleure.Instructions
|
|||||||
value = context.VectorInsert16(vector, value, elem);
|
value = context.VectorInsert16(vector, value, elem);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
value = context.VectorInsert(vector, value, elem);
|
|
||||||
break;
|
|
||||||
case 3:
|
case 3:
|
||||||
value = context.VectorInsert(vector, value, elem);
|
value = context.VectorInsert(vector, value, elem);
|
||||||
break;
|
break;
|
||||||
@@ -733,8 +729,6 @@ namespace ARMeilleure.Instructions
|
|||||||
switch (op.ShiftType)
|
switch (op.ShiftType)
|
||||||
{
|
{
|
||||||
case ShiftType.Lsr:
|
case ShiftType.Lsr:
|
||||||
shift = 32;
|
|
||||||
break;
|
|
||||||
case ShiftType.Asr:
|
case ShiftType.Asr:
|
||||||
shift = 32;
|
shift = 32;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -2082,8 +2082,6 @@ namespace ARMeilleure.Instructions
|
|||||||
vector = context.VectorInsert16(vector, value, index);
|
vector = context.VectorInsert16(vector, value, index);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
vector = context.VectorInsert(vector, value, index);
|
|
||||||
break;
|
|
||||||
case 3:
|
case 3:
|
||||||
vector = context.VectorInsert(vector, value, index);
|
vector = context.VectorInsert(vector, value, index);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace ARMeilleure
|
namespace ARMeilleure
|
||||||
{
|
{
|
||||||
using Arm64HardwareCapabilities = ARMeilleure.CodeGen.Arm64.HardwareCapabilities;
|
using Arm64HardwareCapabilities = CodeGen.Arm64.HardwareCapabilities;
|
||||||
using X86HardwareCapabilities = ARMeilleure.CodeGen.X86.HardwareCapabilities;
|
using X86HardwareCapabilities = CodeGen.X86.HardwareCapabilities;
|
||||||
|
|
||||||
public static class Optimizations
|
public static class Optimizations
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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 = 6998; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 7008; //! 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";
|
||||||
@@ -563,6 +563,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
if (AreCarriersEmpty() || ContainsBlacklistedFunctions())
|
if (AreCarriersEmpty() || ContainsBlacklistedFunctions())
|
||||||
{
|
{
|
||||||
|
ResetCarriersIfNeeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -869,7 +870,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
Debug.Assert(Profiler.IsAddressInStaticCodeRange(address));
|
Debug.Assert(Profiler.IsAddressInStaticCodeRange(address));
|
||||||
|
|
||||||
TranslatedFunction func = translator.Translate(address, executionMode, highCq);
|
TranslatedFunction func = translator.Translate(address, executionMode, highCq, pptcTranslation: true);
|
||||||
|
|
||||||
if (func == null)
|
if (func == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ namespace ARMeilleure.Translation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal TranslatedFunction Translate(ulong address, ExecutionMode mode, bool highCq, bool singleStep = false)
|
internal TranslatedFunction Translate(ulong address, ExecutionMode mode, bool highCq, bool singleStep = false, bool pptcTranslation = false)
|
||||||
{
|
{
|
||||||
var context = new ArmEmitterContext(
|
var context = new ArmEmitterContext(
|
||||||
Memory,
|
Memory,
|
||||||
@@ -246,7 +246,7 @@ namespace ARMeilleure.Translation
|
|||||||
context.Branch(context.GetLabel(address));
|
context.Branch(context.GetLabel(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlFlowGraph cfg = EmitAndGetCFG(context, blocks, out Range funcRange, out Counter<uint> counter);
|
ControlFlowGraph cfg = EmitAndGetCFG(context, blocks, out Range funcRange, out Counter<uint> counter, pptcTranslation);
|
||||||
|
|
||||||
if (cfg == null)
|
if (cfg == null)
|
||||||
{
|
{
|
||||||
@@ -326,7 +326,8 @@ namespace ARMeilleure.Translation
|
|||||||
ArmEmitterContext context,
|
ArmEmitterContext context,
|
||||||
Block[] blocks,
|
Block[] blocks,
|
||||||
out Range range,
|
out Range range,
|
||||||
out Counter<uint> counter)
|
out Counter<uint> counter,
|
||||||
|
bool pptcTranslation)
|
||||||
{
|
{
|
||||||
counter = null;
|
counter = null;
|
||||||
|
|
||||||
@@ -411,7 +412,10 @@ namespace ARMeilleure.Translation
|
|||||||
if (opCode.Instruction.Emitter != null)
|
if (opCode.Instruction.Emitter != null)
|
||||||
{
|
{
|
||||||
opCode.Instruction.Emitter(context);
|
opCode.Instruction.Emitter(context);
|
||||||
if (opCode.Instruction.Name == InstName.Und && blkIndex == 0)
|
// if we're pre-compiling PPTC functions, and we hit an Undefined instruction as the first
|
||||||
|
// instruction in the block, mark the function as blacklisted
|
||||||
|
// this way, we don't pre-compile Exlaunch hooks, which allows ExeFS mods to run with PPTC
|
||||||
|
if (pptcTranslation && opCode.Instruction.Name == InstName.Und && blkIndex == 0)
|
||||||
{
|
{
|
||||||
range = new Range(rangeStart, rangeEnd);
|
range = new Range(rangeStart, rangeEnd);
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
/// Map decibel to linear.
|
/// Map decibel to linear.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="db">The decibel value to convert</param>
|
/// <param name="db">The decibel value to convert</param>
|
||||||
/// <returns>Converted linear value/returns>
|
/// <returns>Converted linear value</returns>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static float DecibelToLinear(float db)
|
public static float DecibelToLinear(float db)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -496,12 +496,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
return (10090.9f, 3490.9f);
|
return (10090.9f, 3490.9f);
|
||||||
case SampleRateConversionQuality.High:
|
case SampleRateConversionQuality.High:
|
||||||
if (sampleCount == 160)
|
|
||||||
{
|
|
||||||
return (9446.36f, 2308.91f);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (12520.85f, 3480.61f);
|
|
||||||
case SampleRateConversionQuality.Low:
|
case SampleRateConversionQuality.Low:
|
||||||
if (sampleCount == 160)
|
if (sampleCount == 160)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,13 +1,33 @@
|
|||||||
|
using Ryujinx.Common.Utilities;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Common.GraphicsDriver
|
namespace Ryujinx.Common.GraphicsDriver
|
||||||
{
|
{
|
||||||
public static class DriverUtilities
|
public static class DriverUtilities
|
||||||
{
|
{
|
||||||
|
private static void AddMesaFlags(string envVar, string newFlags)
|
||||||
|
{
|
||||||
|
string existingFlags = Environment.GetEnvironmentVariable(envVar);
|
||||||
|
|
||||||
|
string flags = existingFlags == null ? newFlags : $"{existingFlags},{newFlags}";
|
||||||
|
|
||||||
|
OsUtils.SetEnvironmentVariableNoCaching(envVar, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InitDriverConfig(bool oglThreading)
|
||||||
|
{
|
||||||
|
if (OperatingSystem.IsLinux())
|
||||||
|
{
|
||||||
|
AddMesaFlags("RADV_DEBUG", "nodcc");
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleOGLThreading(oglThreading);
|
||||||
|
}
|
||||||
|
|
||||||
public static void ToggleOGLThreading(bool enabled)
|
public static void ToggleOGLThreading(bool enabled)
|
||||||
{
|
{
|
||||||
Environment.SetEnvironmentVariable("mesa_glthread", enabled.ToString().ToLower());
|
OsUtils.SetEnvironmentVariableNoCaching("mesa_glthread", enabled.ToString().ToLower());
|
||||||
Environment.SetEnvironmentVariable("__GL_THREADED_OPTIMIZATIONS", enabled ? "1" : "0");
|
OsUtils.SetEnvironmentVariableNoCaching("__GL_THREADED_OPTIMIZATIONS", enabled ? "1" : "0");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,9 +46,9 @@ namespace Ryujinx.Common.Logging.Targets
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up old logs, should only keep 3
|
// Clean up old logs, should only keep 4
|
||||||
FileInfo[] files = logDir.GetFiles("*.log").OrderBy((info => info.CreationTime)).ToArray();
|
FileInfo[] files = logDir.GetFiles("*.log").OrderBy((info => info.CreationTime)).ToArray();
|
||||||
for (int i = 0; i < files.Length - 2; i++)
|
for (int i = 0; i < files.Length - 3; i++)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Common.Utilities
|
||||||
|
{
|
||||||
|
public partial class OsUtils
|
||||||
|
{
|
||||||
|
[LibraryImport("libc", SetLastError = true)]
|
||||||
|
private static partial int setenv([MarshalAs(UnmanagedType.LPStr)] string name, [MarshalAs(UnmanagedType.LPStr)] string value, int overwrite);
|
||||||
|
|
||||||
|
public static void SetEnvironmentVariableNoCaching(string key, string value)
|
||||||
|
{
|
||||||
|
// Set the value in the cached environment variables, too.
|
||||||
|
Environment.SetEnvironmentVariable(key, value);
|
||||||
|
|
||||||
|
if (!OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
int res = setenv(key, value, 1);
|
||||||
|
Debug.Assert(res != -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -191,7 +191,7 @@ namespace Ryujinx.Common.Utilities
|
|||||||
|
|
||||||
if (timedSw.Elapsed.TotalSeconds > 0)
|
if (timedSw.Elapsed.TotalSeconds > 0)
|
||||||
{
|
{
|
||||||
Log?.Write(LogType.Info, $"Checked at {readSizeB / (double)XCIFileTrimmer.BytesInAMegabyte / timedSw.Elapsed.TotalSeconds:N} Mb/sec");
|
Log?.Write(LogType.Info, $"Checked at {readSizeB / (double)BytesInAMegabyte / timedSw.Elapsed.TotalSeconds:N} Mb/sec");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (freeSpaceValid)
|
if (freeSpaceValid)
|
||||||
@@ -219,7 +219,7 @@ namespace Ryujinx.Common.Utilities
|
|||||||
|
|
||||||
private bool CheckPadding(long readSizeB, CancellationToken? cancelToken = null)
|
private bool CheckPadding(long readSizeB, CancellationToken? cancelToken = null)
|
||||||
{
|
{
|
||||||
long maxReads = readSizeB / XCIFileTrimmer.BufferSize;
|
long maxReads = readSizeB / BufferSize;
|
||||||
long read = 0;
|
long read = 0;
|
||||||
var buffer = new byte[BufferSize];
|
var buffer = new byte[BufferSize];
|
||||||
|
|
||||||
@@ -230,12 +230,12 @@ namespace Ryujinx.Common.Utilities
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bytes = _fileStream.Read(buffer, 0, XCIFileTrimmer.BufferSize);
|
int bytes = _fileStream.Read(buffer, 0, BufferSize);
|
||||||
if (bytes == 0)
|
if (bytes == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
Log?.Progress(read, maxReads, "Verifying file can be trimmed", false);
|
Log?.Progress(read, maxReads, "Verifying file can be trimmed", false);
|
||||||
if (buffer.Take(bytes).AsParallel().Any(b => b != XCIFileTrimmer.PaddingByte))
|
if (buffer.Take(bytes).AsParallel().Any(b => b != PaddingByte))
|
||||||
{
|
{
|
||||||
Log?.Write(LogType.Warn, "Free space is NOT valid");
|
Log?.Write(LogType.Warn, "Free space is NOT valid");
|
||||||
return false;
|
return false;
|
||||||
@@ -380,7 +380,7 @@ namespace Ryujinx.Common.Utilities
|
|||||||
|
|
||||||
if (timedSw.Elapsed.TotalSeconds > 0)
|
if (timedSw.Elapsed.TotalSeconds > 0)
|
||||||
{
|
{
|
||||||
Log?.Write(LogType.Info, $"Wrote at {bytesToWriteB / (double)XCIFileTrimmer.BytesInAMegabyte / timedSw.Elapsed.TotalSeconds:N} Mb/sec");
|
Log?.Write(LogType.Info, $"Wrote at {bytesToWriteB / (double)BytesInAMegabyte / timedSw.Elapsed.TotalSeconds:N} Mb/sec");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cancelToken.HasValue && cancelToken.Value.IsCancellationRequested)
|
if (cancelToken.HasValue && cancelToken.Value.IsCancellationRequested)
|
||||||
@@ -408,13 +408,13 @@ namespace Ryujinx.Common.Utilities
|
|||||||
private void WritePadding(FileStream outfileStream, long bytesToWriteB, CancellationToken? cancelToken = null)
|
private void WritePadding(FileStream outfileStream, long bytesToWriteB, CancellationToken? cancelToken = null)
|
||||||
{
|
{
|
||||||
long bytesLeftToWriteB = bytesToWriteB;
|
long bytesLeftToWriteB = bytesToWriteB;
|
||||||
long writes = bytesLeftToWriteB / XCIFileTrimmer.BufferSize;
|
long writes = bytesLeftToWriteB / BufferSize;
|
||||||
int write = 0;
|
int write = 0;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var buffer = new byte[BufferSize];
|
var buffer = new byte[BufferSize];
|
||||||
Array.Fill<byte>(buffer, XCIFileTrimmer.PaddingByte);
|
Array.Fill<byte>(buffer, PaddingByte);
|
||||||
|
|
||||||
while (bytesLeftToWriteB > 0)
|
while (bytesLeftToWriteB > 0)
|
||||||
{
|
{
|
||||||
@@ -423,7 +423,7 @@ namespace Ryujinx.Common.Utilities
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long bytesToWrite = Math.Min(XCIFileTrimmer.BufferSize, bytesLeftToWriteB);
|
long bytesToWrite = Math.Min(BufferSize, bytesLeftToWriteB);
|
||||||
|
|
||||||
#if !XCI_TRIMMER_READ_ONLY_MODE
|
#if !XCI_TRIMMER_READ_ONLY_MODE
|
||||||
outfileStream.Write(buffer, 0, (int)bytesToWrite);
|
outfileStream.Write(buffer, 0, (int)bytesToWrite);
|
||||||
@@ -504,12 +504,12 @@ namespace Ryujinx.Common.Utilities
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup offset
|
// Setup offset
|
||||||
_offsetB = (long)(assumeKeyArea ? XCIFileTrimmer.CartKeyAreaSize : 0);
|
_offsetB = (long)(assumeKeyArea ? CartKeyAreaSize : 0);
|
||||||
|
|
||||||
// Check header
|
// Check header
|
||||||
Pos = _offsetB + XCIFileTrimmer.HeaderFilePos;
|
Pos = _offsetB + HeaderFilePos;
|
||||||
string head = System.Text.Encoding.ASCII.GetString(_binaryReader.ReadBytes(4));
|
string head = System.Text.Encoding.ASCII.GetString(_binaryReader.ReadBytes(4));
|
||||||
if (head != XCIFileTrimmer.HeaderMagicValue)
|
if (head != HeaderMagicValue)
|
||||||
{
|
{
|
||||||
if (!assumeKeyArea)
|
if (!assumeKeyArea)
|
||||||
{
|
{
|
||||||
@@ -524,17 +524,17 @@ namespace Ryujinx.Common.Utilities
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read Cart Size
|
// Read Cart Size
|
||||||
Pos = _offsetB + XCIFileTrimmer.CartSizeFilePos;
|
Pos = _offsetB + CartSizeFilePos;
|
||||||
byte cartSizeId = _binaryReader.ReadByte();
|
byte cartSizeId = _binaryReader.ReadByte();
|
||||||
if (!_cartSizesGB.TryGetValue(cartSizeId, out long cartSizeNGB))
|
if (!_cartSizesGB.TryGetValue(cartSizeId, out long cartSizeNGB))
|
||||||
{
|
{
|
||||||
Log?.Write(LogType.Error, $"The source file doesn't look like an XCI file as the Cartridge Size is incorrect (0x{cartSizeId:X2})");
|
Log?.Write(LogType.Error, $"The source file doesn't look like an XCI file as the Cartridge Size is incorrect (0x{cartSizeId:X2})");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_cartSizeB = cartSizeNGB * XCIFileTrimmer.CartSizeMBinFormattedGB * XCIFileTrimmer.BytesInAMegabyte;
|
_cartSizeB = cartSizeNGB * CartSizeMBinFormattedGB * BytesInAMegabyte;
|
||||||
|
|
||||||
// Read data size
|
// Read data size
|
||||||
Pos = _offsetB + XCIFileTrimmer.DataSizeFilePos;
|
Pos = _offsetB + DataSizeFilePos;
|
||||||
long records = (long)BitConverter.ToUInt32(_binaryReader.ReadBytes(4), 0);
|
long records = (long)BitConverter.ToUInt32(_binaryReader.ReadBytes(4), 0);
|
||||||
_dataSizeB = RecordsToByte(records);
|
_dataSizeB = RecordsToByte(records);
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using Ryujinx.Memory.Tracking;
|
|||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using Ryujinx.Memory.Tracking;
|
|||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ using Ryujinx.Memory.Tracking;
|
|||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.Jit
|
namespace Ryujinx.Cpu.Jit
|
||||||
|
|||||||
@@ -703,8 +703,6 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
|||||||
switch ((ArmShiftType)sType)
|
switch ((ArmShiftType)sType)
|
||||||
{
|
{
|
||||||
case ArmShiftType.Lsr:
|
case ArmShiftType.Lsr:
|
||||||
shift = 32;
|
|
||||||
break;
|
|
||||||
case ArmShiftType.Asr:
|
case ArmShiftType.Asr:
|
||||||
shift = 32;
|
shift = 32;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -50,10 +50,6 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
public readonly bool SupportsViewportSwizzle;
|
public readonly bool SupportsViewportSwizzle;
|
||||||
public readonly bool SupportsIndirectParameters;
|
public readonly bool SupportsIndirectParameters;
|
||||||
public readonly bool SupportsDepthClipControl;
|
public readonly bool SupportsDepthClipControl;
|
||||||
public readonly bool SupportsExtendedDynamicState;
|
|
||||||
public readonly bool SupportsExtendedDynamicState2;
|
|
||||||
public readonly bool SupportsLogicOpDynamicState;
|
|
||||||
public readonly bool SupportsPatchControlPointsDynamicState;
|
|
||||||
|
|
||||||
public readonly int UniformBufferSetIndex;
|
public readonly int UniformBufferSetIndex;
|
||||||
public readonly int StorageBufferSetIndex;
|
public readonly int StorageBufferSetIndex;
|
||||||
@@ -122,10 +118,6 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
bool supportsViewportSwizzle,
|
bool supportsViewportSwizzle,
|
||||||
bool supportsIndirectParameters,
|
bool supportsIndirectParameters,
|
||||||
bool supportsDepthClipControl,
|
bool supportsDepthClipControl,
|
||||||
bool supportsExtendedDynamicState,
|
|
||||||
bool supportsExtendedDynamicState2,
|
|
||||||
bool supportsLogicOpDynamicState,
|
|
||||||
bool supportsPatchControlPointsDynamicState,
|
|
||||||
int uniformBufferSetIndex,
|
int uniformBufferSetIndex,
|
||||||
int storageBufferSetIndex,
|
int storageBufferSetIndex,
|
||||||
int textureSetIndex,
|
int textureSetIndex,
|
||||||
@@ -188,10 +180,6 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
SupportsViewportSwizzle = supportsViewportSwizzle;
|
SupportsViewportSwizzle = supportsViewportSwizzle;
|
||||||
SupportsIndirectParameters = supportsIndirectParameters;
|
SupportsIndirectParameters = supportsIndirectParameters;
|
||||||
SupportsDepthClipControl = supportsDepthClipControl;
|
SupportsDepthClipControl = supportsDepthClipControl;
|
||||||
SupportsExtendedDynamicState = supportsExtendedDynamicState;
|
|
||||||
SupportsExtendedDynamicState2 = supportsExtendedDynamicState2;
|
|
||||||
SupportsLogicOpDynamicState = supportsLogicOpDynamicState;
|
|
||||||
SupportsPatchControlPointsDynamicState = supportsPatchControlPointsDynamicState;
|
|
||||||
UniformBufferSetIndex = uniformBufferSetIndex;
|
UniformBufferSetIndex = uniformBufferSetIndex;
|
||||||
StorageBufferSetIndex = storageBufferSetIndex;
|
StorageBufferSetIndex = storageBufferSetIndex;
|
||||||
TextureSetIndex = textureSetIndex;
|
TextureSetIndex = textureSetIndex;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
{
|
{
|
||||||
public enum Face
|
public enum Face
|
||||||
{
|
{
|
||||||
None = 0,
|
|
||||||
Front = 0x404,
|
Front = 0x404,
|
||||||
Back = 0x405,
|
Back = 0x405,
|
||||||
FrontAndBack = 0x408,
|
FrontAndBack = 0x408,
|
||||||
|
|||||||
@@ -275,8 +275,6 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
case Format.D24UnormS8Uint:
|
case Format.D24UnormS8Uint:
|
||||||
return 4;
|
return 4;
|
||||||
case Format.D32FloatS8Uint:
|
case Format.D32FloatS8Uint:
|
||||||
return 8;
|
|
||||||
|
|
||||||
case Format.Bc1RgbaUnorm:
|
case Format.Bc1RgbaUnorm:
|
||||||
case Format.Bc1RgbaSrgb:
|
case Format.Bc1RgbaSrgb:
|
||||||
return 8;
|
return 8;
|
||||||
@@ -303,8 +301,6 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
|
|
||||||
case Format.Etc2RgbaUnorm:
|
case Format.Etc2RgbaUnorm:
|
||||||
case Format.Etc2RgbaSrgb:
|
case Format.Etc2RgbaSrgb:
|
||||||
return 16;
|
|
||||||
|
|
||||||
case Format.Astc4x4Unorm:
|
case Format.Astc4x4Unorm:
|
||||||
case Format.Astc5x4Unorm:
|
case Format.Astc5x4Unorm:
|
||||||
case Format.Astc5x5Unorm:
|
case Format.Astc5x5Unorm:
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp);
|
void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp);
|
||||||
void SetDepthClamp(bool clamp);
|
void SetDepthClamp(bool clamp);
|
||||||
void SetDepthMode(DepthMode mode);
|
void SetDepthMode(DepthMode mode);
|
||||||
void SetDepthTest(DepthTestDescriptor depthTest, bool signalChange = true);
|
void SetDepthTest(DepthTestDescriptor depthTest);
|
||||||
|
|
||||||
void SetFaceCulling(Face face);
|
void SetFaceCulling(bool enable, Face face);
|
||||||
|
|
||||||
void SetFrontFace(FrontFace frontFace);
|
void SetFrontFace(FrontFace frontFace);
|
||||||
|
|
||||||
@@ -75,16 +75,16 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
|
|
||||||
void SetPrimitiveRestart(bool enable, int index);
|
void SetPrimitiveRestart(bool enable, int index);
|
||||||
|
|
||||||
void SetPrimitiveTopology(PrimitiveTopology topology, bool signalChange = true);
|
void SetPrimitiveTopology(PrimitiveTopology topology);
|
||||||
|
|
||||||
void SetProgram(IProgram program, bool signalChange = true);
|
void SetProgram(IProgram program);
|
||||||
|
|
||||||
void SetRasterizerDiscard(bool discard);
|
void SetRasterizerDiscard(bool discard);
|
||||||
|
|
||||||
void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask, bool signalChange = true);
|
void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask);
|
||||||
void SetRenderTargets(ITexture[] colors, ITexture depthStencil);
|
void SetRenderTargets(ITexture[] colors, ITexture depthStencil);
|
||||||
|
|
||||||
void SetScissors(ReadOnlySpan<Rectangle<int>> regions, bool signalChange = true);
|
void SetScissors(ReadOnlySpan<Rectangle<int>> regions);
|
||||||
|
|
||||||
void SetStencilTest(StencilTestDescriptor stencilTest);
|
void SetStencilTest(StencilTestDescriptor stencilTest);
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs);
|
void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs);
|
||||||
void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers);
|
void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers);
|
||||||
|
|
||||||
void SetViewports(ReadOnlySpan<Viewport> viewports, bool signalChange = true);
|
void SetViewports(ReadOnlySpan<Viewport> viewports);
|
||||||
|
|
||||||
void TextureBarrier();
|
void TextureBarrier();
|
||||||
void TextureBarrierTiled();
|
void TextureBarrierTiled();
|
||||||
|
|||||||
@@ -3,16 +3,18 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
|||||||
struct SetFaceCullingCommand : IGALCommand, IGALCommand<SetFaceCullingCommand>
|
struct SetFaceCullingCommand : IGALCommand, IGALCommand<SetFaceCullingCommand>
|
||||||
{
|
{
|
||||||
public readonly CommandType CommandType => CommandType.SetFaceCulling;
|
public readonly CommandType CommandType => CommandType.SetFaceCulling;
|
||||||
|
private bool _enable;
|
||||||
private Face _face;
|
private Face _face;
|
||||||
|
|
||||||
public void Set(Face face)
|
public void Set(bool enable, Face face)
|
||||||
{
|
{
|
||||||
|
_enable = enable;
|
||||||
_face = face;
|
_face = face;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Run(ref SetFaceCullingCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
public static void Run(ref SetFaceCullingCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||||
{
|
{
|
||||||
renderer.Pipeline.SetFaceCulling(command._face);
|
renderer.Pipeline.SetFaceCulling(command._enable, command._face);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,15 +159,15 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetDepthTest(DepthTestDescriptor depthTest, bool signalChange = true)
|
public void SetDepthTest(DepthTestDescriptor depthTest)
|
||||||
{
|
{
|
||||||
_renderer.New<SetDepthTestCommand>().Set(depthTest);
|
_renderer.New<SetDepthTestCommand>().Set(depthTest);
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetFaceCulling(Face face)
|
public void SetFaceCulling(bool enable, Face face)
|
||||||
{
|
{
|
||||||
_renderer.New<SetFaceCullingCommand>().Set(face);
|
_renderer.New<SetFaceCullingCommand>().Set(enable, face);
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,13 +243,13 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetPrimitiveTopology(PrimitiveTopology topology, bool signalChange = true)
|
public void SetPrimitiveTopology(PrimitiveTopology topology)
|
||||||
{
|
{
|
||||||
_renderer.New<SetPrimitiveTopologyCommand>().Set(topology);
|
_renderer.New<SetPrimitiveTopologyCommand>().Set(topology);
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetProgram(IProgram program, bool signalChange = true)
|
public void SetProgram(IProgram program)
|
||||||
{
|
{
|
||||||
_renderer.New<SetProgramCommand>().Set(Ref(program));
|
_renderer.New<SetProgramCommand>().Set(Ref(program));
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
@@ -261,7 +261,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask, bool signalChange = true)
|
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask)
|
||||||
{
|
{
|
||||||
_renderer.New<SetRenderTargetColorMasksCommand>().Set(_renderer.CopySpan(componentMask));
|
_renderer.New<SetRenderTargetColorMasksCommand>().Set(_renderer.CopySpan(componentMask));
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
@@ -273,7 +273,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetScissors(ReadOnlySpan<Rectangle<int>> scissors, bool signalChange = true)
|
public void SetScissors(ReadOnlySpan<Rectangle<int>> scissors)
|
||||||
{
|
{
|
||||||
_renderer.New<SetScissorsCommand>().Set(_renderer.CopySpan(scissors));
|
_renderer.New<SetScissorsCommand>().Set(_renderer.CopySpan(scissors));
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
@@ -339,7 +339,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetViewports(ReadOnlySpan<Viewport> viewports, bool signalChange = true)
|
public void SetViewports(ReadOnlySpan<Viewport> viewports)
|
||||||
{
|
{
|
||||||
_renderer.New<SetViewportsCommand>().Set(_renderer.CopySpan(viewports));
|
_renderer.New<SetViewportsCommand>().Set(_renderer.CopySpan(viewports));
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
|
|||||||
@@ -51,12 +51,11 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
public StencilTestDescriptor StencilTest;
|
public StencilTestDescriptor StencilTest;
|
||||||
public FrontFace FrontFace;
|
public FrontFace FrontFace;
|
||||||
public Face CullMode;
|
public Face CullMode;
|
||||||
|
public bool CullEnable;
|
||||||
|
|
||||||
public PolygonModeMask BiasEnable;
|
public PolygonModeMask BiasEnable;
|
||||||
|
|
||||||
public bool AlphaToCoverageEnable;
|
public float LineWidth;
|
||||||
public bool AlphaToOneEnable;
|
|
||||||
|
|
||||||
// TODO: Polygon mode.
|
// TODO: Polygon mode.
|
||||||
public bool DepthClampEnable;
|
public bool DepthClampEnable;
|
||||||
public bool RasterizerDiscard;
|
public bool RasterizerDiscard;
|
||||||
@@ -64,9 +63,6 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
public bool PrimitiveRestartEnable;
|
public bool PrimitiveRestartEnable;
|
||||||
public uint PatchControlPoints;
|
public uint PatchControlPoints;
|
||||||
|
|
||||||
public float DepthBiasUnits;
|
|
||||||
public float DepthBiasFactor;
|
|
||||||
|
|
||||||
public DepthMode DepthMode;
|
public DepthMode DepthMode;
|
||||||
|
|
||||||
public void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
|
public void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
|
||||||
|
|||||||
@@ -506,7 +506,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
maxDrawCount,
|
maxDrawCount,
|
||||||
stride,
|
stride,
|
||||||
indexCount,
|
indexCount,
|
||||||
Threed.IndirectDrawType.DrawIndexedIndirectCount);
|
IndirectDrawType.DrawIndexedIndirectCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed.Blender
|
namespace Ryujinx.Graphics.Gpu.Engine.Threed.Blender
|
||||||
|
|||||||
@@ -853,9 +853,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
enables |= (depthBias.FillEnable ? PolygonModeMask.Fill : 0);
|
enables |= (depthBias.FillEnable ? PolygonModeMask.Fill : 0);
|
||||||
|
|
||||||
_pipeline.BiasEnable = enables;
|
_pipeline.BiasEnable = enables;
|
||||||
_pipeline.DepthBiasUnits = units / 2f;
|
|
||||||
_pipeline.DepthBiasFactor = factor;
|
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetDepthBias(enables, factor, units / 2f, clamp);
|
_context.Renderer.Pipeline.SetDepthBias(enables, factor, units / 2f, clamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1028,6 +1025,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
float width = _state.State.LineWidthSmooth;
|
float width = _state.State.LineWidthSmooth;
|
||||||
bool smooth = _state.State.LineSmoothEnable;
|
bool smooth = _state.State.LineSmoothEnable;
|
||||||
|
|
||||||
|
_pipeline.LineWidth = width;
|
||||||
_context.Renderer.Pipeline.SetLineParameters(width, smooth);
|
_context.Renderer.Pipeline.SetLineParameters(width, smooth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1197,16 +1195,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
var yControl = _state.State.YControl;
|
var yControl = _state.State.YControl;
|
||||||
var face = _state.State.FaceState;
|
var face = _state.State.FaceState;
|
||||||
|
|
||||||
if (face.CullEnable)
|
_pipeline.CullEnable = face.CullEnable;
|
||||||
{
|
|
||||||
_pipeline.CullMode = face.CullFace;
|
_pipeline.CullMode = face.CullFace;
|
||||||
_context.Renderer.Pipeline.SetFaceCulling(face.CullFace);
|
_context.Renderer.Pipeline.SetFaceCulling(face.CullEnable, face.CullFace);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_pipeline.CullMode = Face.None;
|
|
||||||
_context.Renderer.Pipeline.SetFaceCulling(Face.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateFrontFace(yControl, face.FrontFace);
|
UpdateFrontFace(yControl, face.FrontFace);
|
||||||
}
|
}
|
||||||
@@ -1396,8 +1387,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
bool alphaToCoverageEnable = (_state.State.MultisampleControl & 1) != 0;
|
bool alphaToCoverageEnable = (_state.State.MultisampleControl & 1) != 0;
|
||||||
bool alphaToOneEnable = (_state.State.MultisampleControl & 0x10) != 0;
|
bool alphaToOneEnable = (_state.State.MultisampleControl & 0x10) != 0;
|
||||||
|
|
||||||
_pipeline.AlphaToCoverageEnable = alphaToCoverageEnable;
|
|
||||||
_pipeline.AlphaToOneEnable = alphaToOneEnable;
|
|
||||||
_context.Renderer.Pipeline.SetMultisampleState(new MultisampleDescriptor(
|
_context.Renderer.Pipeline.SetMultisampleState(new MultisampleDescriptor(
|
||||||
alphaToCoverageEnable,
|
alphaToCoverageEnable,
|
||||||
_state.State.AlphaToCoverageDitherEnable,
|
_state.State.AlphaToCoverageDitherEnable,
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
return (AddressMode)(Word0 & 7);
|
return (AddressMode)(Word0 & 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
// <summary>
|
/// <summary>
|
||||||
/// Unpacks the texture wrap mode along the Y axis.
|
/// Unpacks the texture wrap mode along the Y axis.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The texture wrap mode enum</returns>
|
/// <returns>The texture wrap mode enum</returns>
|
||||||
@@ -82,7 +82,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
return (AddressMode)((Word0 >> 3) & 7);
|
return (AddressMode)((Word0 >> 3) & 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
// <summary>
|
/// <summary>
|
||||||
/// Unpacks the texture wrap mode along the Z axis.
|
/// Unpacks the texture wrap mode along the Z axis.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The texture wrap mode enum</returns>
|
/// <returns>The texture wrap mode enum</returns>
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using Ryujinx.Graphics.Gpu.Memory;
|
|||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Image
|
namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|||||||
@@ -422,7 +422,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// <param name="texturePool">The current texture pool</param>
|
/// <param name="texturePool">The current texture pool</param>
|
||||||
/// <param name="samplerPool">The current sampler pool</param>
|
/// <param name="samplerPool">The current sampler pool</param>
|
||||||
/// <param name="stage">The shader stage using the textures to be bound</param>
|
/// <param name="stage">The shader stage using the textures to be bound</param>
|
||||||
/// <param name="stageIndex">The stage number of the specified shader stage</param
|
/// <param name="stageIndex">The stage number of the specified shader stage</param>
|
||||||
/// <param name="poolModified">True if either the texture or sampler pool was modified, false otherwise</param>
|
/// <param name="poolModified">True if either the texture or sampler pool was modified, false otherwise</param>
|
||||||
/// <param name="specState">Specialization state for the bound shader</param>
|
/// <param name="specState">Specialization state for the bound shader</param>
|
||||||
/// <returns>True if all bound textures match the current shader specialiation state, false otherwise</returns>
|
/// <returns>True if all bound textures match the current shader specialiation state, false otherwise</returns>
|
||||||
|
|||||||
@@ -723,7 +723,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// Checks if aliasing of two formats that would normally be considered incompatible be allowed,
|
/// Checks if aliasing of two formats that would normally be considered incompatible be allowed,
|
||||||
/// using copy dependencies.
|
/// using copy dependencies.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="lhsFormat">Format information of the first texture</param
|
/// <param name="lhsFormat">Format information of the first texture</param>
|
||||||
/// <param name="rhsFormat">Format information of the second texture</param>
|
/// <param name="rhsFormat">Format information of the second texture</param>
|
||||||
/// <returns>True if aliasing should be allowed, false otherwise</returns>
|
/// <returns>True if aliasing should be allowed, false otherwise</returns>
|
||||||
private static bool IsIncompatibleFormatAliasingAllowed(FormatInfo lhsFormat, FormatInfo rhsFormat)
|
private static bool IsIncompatibleFormatAliasingAllowed(FormatInfo lhsFormat, FormatInfo rhsFormat)
|
||||||
@@ -747,7 +747,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// Check if the target of the first texture view information is compatible with the target of the second texture view information.
|
/// Check if the target of the first texture view information is compatible with the target of the second texture view information.
|
||||||
/// This follows the host API target compatibility rules.
|
/// This follows the host API target compatibility rules.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="lhs">Texture information of the texture view</param
|
/// <param name="lhs">Texture information of the texture view</param>
|
||||||
/// <param name="rhs">Texture information of the texture view</param>
|
/// <param name="rhs">Texture information of the texture view</param>
|
||||||
/// <param name="caps">Host GPU capabilities</param>
|
/// <param name="caps">Host GPU capabilities</param>
|
||||||
/// <returns>True if the targets are compatible, false otherwise</returns>
|
/// <returns>True if the targets are compatible, false otherwise</returns>
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
case TextureTarget.Texture1D:
|
case TextureTarget.Texture1D:
|
||||||
return Target.Texture1D;
|
return Target.Texture1D;
|
||||||
case TextureTarget.Texture2D:
|
case TextureTarget.Texture2D:
|
||||||
return Target.Texture2D;
|
|
||||||
case TextureTarget.Texture2DRect:
|
case TextureTarget.Texture2DRect:
|
||||||
return Target.Texture2D;
|
return Target.Texture2D;
|
||||||
case TextureTarget.Texture3D:
|
case TextureTarget.Texture3D:
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// Sets whether the format of a given render target is a BGRA format.
|
/// Sets whether the format of a given render target is a BGRA format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">Render target index</param>
|
/// <param name="index">Render target index</param>
|
||||||
/// <param name="isBgra">True if the format is BGRA< false otherwise</param>
|
/// <param name="isBgra">True if the format is BGRA, false otherwise</param>
|
||||||
public void SetRenderTargetIsBgra(int index, bool isBgra)
|
public void SetRenderTargetIsBgra(int index, bool isBgra)
|
||||||
{
|
{
|
||||||
bool isBgraChanged = _data.FragmentIsBgra[index].X != 0 != isBgra;
|
bool isBgraChanged = _data.FragmentIsBgra[index].X != 0 != isBgra;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using Ryujinx.Graphics.GAL;
|
|||||||
using Ryujinx.Graphics.Gpu.Engine;
|
using Ryujinx.Graphics.Gpu.Engine;
|
||||||
using Ryujinx.Graphics.Gpu.Image;
|
using Ryujinx.Graphics.Gpu.Image;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using System;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Shader
|
namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private readonly CancellationToken _cancellationToken;
|
private readonly CancellationToken _cancellationToken;
|
||||||
private readonly Action<ShaderCacheState, int, int> _stateChangeCallback;
|
private readonly Action<ShaderCacheState, int, int> _stateChangeCallback;
|
||||||
|
|
||||||
private readonly HashSet<ProgramPipelineState> _pipelineStateSet = new();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if the cache should be loaded.
|
/// Indicates if the cache should be loaded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -234,7 +232,10 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
|
|
||||||
for (int index = 0; index < ThreadCount; index++)
|
for (int index = 0; index < ThreadCount; index++)
|
||||||
{
|
{
|
||||||
workThreads[index] = new Thread(ProcessAsyncQueue) { Name = $"GPU.AsyncTranslationThread.{index}", };
|
workThreads[index] = new Thread(ProcessAsyncQueue)
|
||||||
|
{
|
||||||
|
Name = $"GPU.AsyncTranslationThread.{index}",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
int programCount = _hostStorage.GetProgramCount();
|
int programCount = _hostStorage.GetProgramCount();
|
||||||
@@ -304,8 +305,6 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
using var streams = _hostStorage.GetOutputStreams(_context);
|
using var streams = _hostStorage.GetOutputStreams(_context);
|
||||||
|
|
||||||
int packagedShaders = 0;
|
int packagedShaders = 0;
|
||||||
ProgramPipelineState currentPipelineState = default;
|
|
||||||
|
|
||||||
foreach (var kv in _programList)
|
foreach (var kv in _programList)
|
||||||
{
|
{
|
||||||
if (!Active)
|
if (!Active)
|
||||||
@@ -315,53 +314,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
|
|
||||||
(CachedShaderProgram program, byte[] binaryCode) = kv.Value;
|
(CachedShaderProgram program, byte[] binaryCode) = kv.Value;
|
||||||
|
|
||||||
if (program.SpecializationState.PipelineState.HasValue && _context.Capabilities.SupportsExtendedDynamicState)
|
|
||||||
{
|
|
||||||
currentPipelineState = program.SpecializationState.PipelineState.Value;
|
|
||||||
|
|
||||||
if (_context.Capabilities.SupportsExtendedDynamicState)
|
|
||||||
{
|
|
||||||
currentPipelineState.StencilTest = default;
|
|
||||||
|
|
||||||
currentPipelineState.CullMode = 0;
|
|
||||||
currentPipelineState.FrontFace = 0;
|
|
||||||
currentPipelineState.DepthTest = default;
|
|
||||||
currentPipelineState.Topology = ConvertToClass(currentPipelineState.Topology);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_context.Capabilities.SupportsExtendedDynamicState2)
|
|
||||||
{
|
|
||||||
currentPipelineState.PrimitiveRestartEnable = false;
|
|
||||||
currentPipelineState.BiasEnable = 0;
|
|
||||||
currentPipelineState.RasterizerDiscard = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_context.Capabilities.SupportsLogicOpDynamicState)
|
|
||||||
{
|
|
||||||
currentPipelineState.LogicOp = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_context.Capabilities.SupportsPatchControlPointsDynamicState)
|
|
||||||
{
|
|
||||||
currentPipelineState.PatchControlPoints = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_pipelineStateSet.Contains(currentPipelineState) ||
|
|
||||||
!_context.Capabilities.SupportsExtendedDynamicState ||
|
|
||||||
!program.SpecializationState.PipelineState.HasValue)
|
|
||||||
{
|
|
||||||
_hostStorage.AddShader(_context, program, binaryCode, streams);
|
_hostStorage.AddShader(_context, program, binaryCode, streams);
|
||||||
|
|
||||||
_stateChangeCallback(ShaderCacheState.Packaging, ++packagedShaders, _programList.Count);
|
_stateChangeCallback(ShaderCacheState.Packaging, ++packagedShaders, _programList.Count);
|
||||||
|
}
|
||||||
|
|
||||||
if (_context.Capabilities.SupportsExtendedDynamicState)
|
Logger.Info?.Print(LogClass.Gpu, $"Rebuilt {_programList.Count} shaders successfully.");
|
||||||
{
|
|
||||||
_pipelineStateSet.Add(currentPipelineState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Logger.Info?.Print(LogClass.Gpu, $"Rebuilt {packagedShaders} shaders successfully.");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -385,29 +343,6 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
_stateChangeCallback(ShaderCacheState.Loaded, programCount, programCount);
|
_stateChangeCallback(ShaderCacheState.Loaded, programCount, programCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PrimitiveTopology ConvertToClass(PrimitiveTopology topology)
|
|
||||||
{
|
|
||||||
return topology switch
|
|
||||||
{
|
|
||||||
PrimitiveTopology.Points => PrimitiveTopology.Points,
|
|
||||||
PrimitiveTopology.Lines or
|
|
||||||
PrimitiveTopology.LineStrip or
|
|
||||||
PrimitiveTopology.LinesAdjacency or
|
|
||||||
PrimitiveTopology.LineStripAdjacency => PrimitiveTopology.Lines,
|
|
||||||
PrimitiveTopology.Triangles or
|
|
||||||
PrimitiveTopology.TriangleStrip or
|
|
||||||
PrimitiveTopology.TriangleFan or
|
|
||||||
PrimitiveTopology.TrianglesAdjacency or
|
|
||||||
PrimitiveTopology.TriangleStripAdjacency or
|
|
||||||
PrimitiveTopology.Polygon => PrimitiveTopology.TriangleStrip,
|
|
||||||
PrimitiveTopology.Patches => PrimitiveTopology.Patches,
|
|
||||||
PrimitiveTopology.Quads => PrimitiveTopology.Quads,
|
|
||||||
PrimitiveTopology.QuadStrip => PrimitiveTopology.QuadStrip,
|
|
||||||
PrimitiveTopology.LineLoop => PrimitiveTopology.LineLoop,
|
|
||||||
_ => PrimitiveTopology.TriangleStrip,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enqueues a host program for compilation.
|
/// Enqueues a host program for compilation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -136,8 +136,6 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||||||
|
|
||||||
ulong frameSize = (ulong)(1 + (useHighbitdepth ? 1 : 0)) * (yplaneSize + (2 * uvplaneSize));
|
ulong frameSize = (ulong)(1 + (useHighbitdepth ? 1 : 0)) * (yplaneSize + (2 * uvplaneSize));
|
||||||
|
|
||||||
ArrayPtr<byte> buf = ArrayPtr<byte>.Null;
|
|
||||||
|
|
||||||
// frame_size is stored in buffer_alloc_sz, which is an int. If it won't
|
// frame_size is stored in buffer_alloc_sz, which is an int. If it won't
|
||||||
// fit, fail early.
|
// fit, fail early.
|
||||||
if (frameSize > int.MaxValue)
|
if (frameSize > int.MaxValue)
|
||||||
@@ -212,7 +210,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||||||
SubsamplingX = ssX;
|
SubsamplingX = ssX;
|
||||||
SubsamplingY = ssY;
|
SubsamplingY = ssY;
|
||||||
|
|
||||||
buf = BufferAlloc;
|
ArrayPtr<byte> buf = BufferAlloc;
|
||||||
if (useHighbitdepth)
|
if (useHighbitdepth)
|
||||||
{
|
{
|
||||||
// Store uint16 addresses when using 16bit framebuffers
|
// Store uint16 addresses when using 16bit framebuffers
|
||||||
|
|||||||
@@ -277,11 +277,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||||||
public CodecErr Decode(MemoryAllocator allocator, ArrayPtr<byte> data)
|
public CodecErr Decode(MemoryAllocator allocator, ArrayPtr<byte> data)
|
||||||
{
|
{
|
||||||
ArrayPtr<byte> dataStart = data;
|
ArrayPtr<byte> dataStart = data;
|
||||||
CodecErr res;
|
|
||||||
Array8<uint> frameSizes = new();
|
Array8<uint> frameSizes = new();
|
||||||
int frameCount = 0;
|
int frameCount = 0;
|
||||||
|
|
||||||
res = Types.Decoder.ParseSuperframeIndex(data, (ulong)data.Length, ref frameSizes, out frameCount);
|
CodecErr res = Decoder.ParseSuperframeIndex(data, (ulong)data.Length, ref frameSizes, out frameCount);
|
||||||
if (res != CodecErr.Ok)
|
if (res != CodecErr.Ok)
|
||||||
{
|
{
|
||||||
return res;
|
return res;
|
||||||
@@ -322,7 +321,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||||||
// Account for suboptimal termination by the encoder.
|
// Account for suboptimal termination by the encoder.
|
||||||
while (dataStart.Length != 0)
|
while (dataStart.Length != 0)
|
||||||
{
|
{
|
||||||
byte marker = Types.Decoder.ReadMarker(dataStart);
|
byte marker = Decoder.ReadMarker(dataStart);
|
||||||
if (marker != 0)
|
if (marker != 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -191,10 +191,6 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
|
supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
|
||||||
supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
|
supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
|
||||||
supportsDepthClipControl: true,
|
supportsDepthClipControl: true,
|
||||||
supportsExtendedDynamicState: false,
|
|
||||||
supportsExtendedDynamicState2: false,
|
|
||||||
supportsLogicOpDynamicState: false,
|
|
||||||
supportsPatchControlPointsDynamicState: false,
|
|
||||||
uniformBufferSetIndex: 0,
|
uniformBufferSetIndex: 0,
|
||||||
storageBufferSetIndex: 1,
|
storageBufferSetIndex: 1,
|
||||||
textureSetIndex: 2,
|
textureSetIndex: 2,
|
||||||
|
|||||||
@@ -898,7 +898,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetDepthTest(DepthTestDescriptor depthTest, bool signalChange = true)
|
public void SetDepthTest(DepthTestDescriptor depthTest)
|
||||||
{
|
{
|
||||||
if (depthTest.TestEnable)
|
if (depthTest.TestEnable)
|
||||||
{
|
{
|
||||||
@@ -915,11 +915,11 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
_depthTestEnable = depthTest.TestEnable;
|
_depthTestEnable = depthTest.TestEnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetFaceCulling(Face face)
|
public void SetFaceCulling(bool enable, Face face)
|
||||||
{
|
{
|
||||||
_cullEnable = face != Face.None;
|
_cullEnable = enable;
|
||||||
|
|
||||||
if (!_cullEnable)
|
if (!enable)
|
||||||
{
|
{
|
||||||
GL.Disable(EnableCap.CullFace);
|
GL.Disable(EnableCap.CullFace);
|
||||||
return;
|
return;
|
||||||
@@ -1107,12 +1107,12 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
GL.Enable(EnableCap.PrimitiveRestart);
|
GL.Enable(EnableCap.PrimitiveRestart);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetPrimitiveTopology(PrimitiveTopology topology, bool signalChange = true)
|
public void SetPrimitiveTopology(PrimitiveTopology topology)
|
||||||
{
|
{
|
||||||
_primitiveType = topology.Convert();
|
_primitiveType = topology.Convert();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetProgram(IProgram program, bool signalChange = true)
|
public void SetProgram(IProgram program)
|
||||||
{
|
{
|
||||||
Program prg = (Program)program;
|
Program prg = (Program)program;
|
||||||
|
|
||||||
@@ -1154,7 +1154,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
_rasterizerDiscard = discard;
|
_rasterizerDiscard = discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMasks, bool signalChange = true)
|
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMasks)
|
||||||
{
|
{
|
||||||
_componentMasks = 0;
|
_componentMasks = 0;
|
||||||
|
|
||||||
@@ -1195,7 +1195,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
_framebuffer.SetDrawBuffers(colors.Length);
|
_framebuffer.SetDrawBuffers(colors.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetScissors(ReadOnlySpan<Rectangle<int>> regions, bool signalChange = true)
|
public void SetScissors(ReadOnlySpan<Rectangle<int>> regions)
|
||||||
{
|
{
|
||||||
int count = Math.Min(regions.Length, Constants.MaxViewports);
|
int count = Math.Min(regions.Length, Constants.MaxViewports);
|
||||||
|
|
||||||
@@ -1388,7 +1388,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
_vertexArray.SetVertexBuffers(vertexBuffers);
|
_vertexArray.SetVertexBuffers(vertexBuffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetViewports(ReadOnlySpan<Viewport> viewports, bool signalChange = true)
|
public void SetViewports(ReadOnlySpan<Viewport> viewports)
|
||||||
{
|
{
|
||||||
Array.Resize(ref _viewportArray, viewports.Length * 4);
|
Array.Resize(ref _viewportArray, viewports.Length * 4);
|
||||||
Array.Resize(ref _depthRangeArray, viewports.Length * 2);
|
Array.Resize(ref _depthRangeArray, viewports.Length * 2);
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
{
|
{
|
||||||
public static void RunPass(TransformContext context)
|
public static void RunPass(TransformContext context)
|
||||||
{
|
{
|
||||||
|
for (int blkIndex = 0; blkIndex < context.Blocks.Length; blkIndex++)
|
||||||
|
{
|
||||||
|
XmadOptimizer.RunPass(context.Blocks[blkIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
RunOptimizationPasses(context.Blocks, context.ResourceManager);
|
RunOptimizationPasses(context.Blocks, context.ResourceManager);
|
||||||
|
|
||||||
// TODO: Some of those are not optimizations and shouldn't be here.
|
// TODO: Some of those are not optimizations and shouldn't be here.
|
||||||
@@ -355,7 +360,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
|||||||
operation.TurnIntoCopy(attrMulLhs);
|
operation.TurnIntoCopy(attrMulLhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RemoveNode(BasicBlock block, LinkedListNode<INode> llNode)
|
public static void RemoveNode(BasicBlock block, LinkedListNode<INode> llNode)
|
||||||
{
|
{
|
||||||
// Remove a node from the nodes list, and also remove itself
|
// Remove a node from the nodes list, and also remove itself
|
||||||
// from all the use lists on the operands that this node uses.
|
// from all the use lists on the operands that this node uses.
|
||||||
|
|||||||
@@ -0,0 +1,342 @@
|
|||||||
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
|
{
|
||||||
|
static class XmadOptimizer
|
||||||
|
{
|
||||||
|
public static void RunPass(BasicBlock block)
|
||||||
|
{
|
||||||
|
for (LinkedListNode<INode> node = block.Operations.First; node != null; node = node.Next)
|
||||||
|
{
|
||||||
|
if (!(node.Value is Operation operation))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TryMatchXmadPattern(operation, out Operand x, out Operand y, out Operand addend))
|
||||||
|
{
|
||||||
|
LinkedListNode<INode> nextNode;
|
||||||
|
|
||||||
|
if (addend != null)
|
||||||
|
{
|
||||||
|
Operand temp = OperandHelper.Local();
|
||||||
|
|
||||||
|
nextNode = block.Operations.AddAfter(node, new Operation(Instruction.Multiply, temp, x, y));
|
||||||
|
nextNode = block.Operations.AddAfter(nextNode, new Operation(Instruction.Add, operation.Dest, temp, addend));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nextNode = block.Operations.AddAfter(node, new Operation(Instruction.Multiply, operation.Dest, x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
Optimizer.RemoveNode(block, node);
|
||||||
|
node = nextNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryMatchXmadPattern(Operation operation, out Operand x, out Operand y, out Operand addend)
|
||||||
|
{
|
||||||
|
return TryMatchXmad32x32Pattern(operation, out x, out y, out addend) ||
|
||||||
|
TryMatchXmad32x16Pattern(operation, out x, out y, out addend);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryMatchXmad32x32Pattern(Operation operation, out Operand x, out Operand y, out Operand addend)
|
||||||
|
{
|
||||||
|
x = null;
|
||||||
|
y = null;
|
||||||
|
addend = null;
|
||||||
|
|
||||||
|
if (operation.Inst != Instruction.Add)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand src1 = operation.GetSource(0);
|
||||||
|
Operand src2 = operation.GetSource(1);
|
||||||
|
|
||||||
|
if (!(src2.AsgOp is Operation addOp) || addOp.Inst != Instruction.Add)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand lowTimesLowResult = GetCopySource(addOp.GetSource(0));
|
||||||
|
|
||||||
|
if (!(lowTimesLowResult.AsgOp is Operation lowTimesLowOp))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryMatchLowTimesLow(lowTimesLowOp, out x, out y, out addend))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand lowTimesHighResult = GetCopySource(GetShifted16Source(addOp.GetSource(1), Instruction.ShiftLeft));
|
||||||
|
|
||||||
|
if (!(lowTimesHighResult.AsgOp is Operation lowTimesHighOp))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryMatchLowTimesHigh(lowTimesHighOp, x, y))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(src1.AsgOp is Operation highTimesHighOp))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryMatchHighTimesHigh(highTimesHighOp, x, lowTimesHighResult))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryMatchXmad32x16Pattern(Operation operation, out Operand x, out Operand y, out Operand addend)
|
||||||
|
{
|
||||||
|
x = null;
|
||||||
|
y = null;
|
||||||
|
addend = null;
|
||||||
|
|
||||||
|
if (operation.Inst != Instruction.Add)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand src1 = operation.GetSource(0);
|
||||||
|
Operand src2 = operation.GetSource(1);
|
||||||
|
|
||||||
|
Operand lowTimesLowResult = GetCopySource(src2);
|
||||||
|
|
||||||
|
if (!(lowTimesLowResult.AsgOp is Operation lowTimesLowOp))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryMatchLowTimesLow(lowTimesLowOp, out x, out y, out addend))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand highTimesLowResult = src1;
|
||||||
|
|
||||||
|
if (!(highTimesLowResult.AsgOp is Operation highTimesLowOp))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryMatchHighTimesLow(highTimesLowOp, x, y))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return y.Type == OperandType.Constant && (ushort)y.Value == y.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryMatchLowTimesLow(Operation operation, out Operand x, out Operand y, out Operand addend)
|
||||||
|
{
|
||||||
|
// x = x & 0xFFFF
|
||||||
|
// y = y & 0xFFFF
|
||||||
|
// lowTimesLow = x * y
|
||||||
|
|
||||||
|
x = null;
|
||||||
|
y = null;
|
||||||
|
addend = null;
|
||||||
|
|
||||||
|
if (operation.Inst == Instruction.Add)
|
||||||
|
{
|
||||||
|
if (!(operation.GetSource(0).AsgOp is Operation mulOp))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
addend = operation.GetSource(1);
|
||||||
|
operation = mulOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation.Inst != Instruction.Multiply)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand src1 = GetMasked16Source(operation.GetSource(0));
|
||||||
|
Operand src2 = GetMasked16Source(operation.GetSource(1));
|
||||||
|
|
||||||
|
if (src1 == null || src2 == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = src1;
|
||||||
|
y = src2;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryMatchLowTimesHigh(Operation operation, Operand x, Operand y)
|
||||||
|
{
|
||||||
|
// xLow = x & 0xFFFF
|
||||||
|
// yHigh = y >> 16
|
||||||
|
// lowTimesHigh = xLow * yHigh
|
||||||
|
// result = (lowTimesHigh & 0xFFFF) | (y << 16)
|
||||||
|
|
||||||
|
if (operation.Inst != Instruction.BitwiseOr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand mulResult = GetMasked16Source(operation.GetSource(0));
|
||||||
|
|
||||||
|
if (mulResult == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mulResult = GetCopySource(mulResult);
|
||||||
|
|
||||||
|
if (!(mulResult.AsgOp is Operation mulOp) || mulOp.Inst != Instruction.Multiply)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetMasked16Source(mulOp.GetSource(0)) != x)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetShifted16Source(mulOp.GetSource(1), Instruction.ShiftRightU32) != y)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetShifted16Source(operation.GetSource(1), Instruction.ShiftLeft) != y)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryMatchHighTimesLow(Operation operation, Operand x, Operand y)
|
||||||
|
{
|
||||||
|
// xHigh = x >> 16
|
||||||
|
// yLow = y & 0xFFFF
|
||||||
|
// highTimesLow = xHigh * yLow
|
||||||
|
// result = highTimesLow << 16
|
||||||
|
|
||||||
|
if (operation.Inst != Instruction.ShiftLeft || !IsConst(operation.GetSource(1), 16))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand mulResult = operation.GetSource(0);
|
||||||
|
|
||||||
|
if (!(mulResult.AsgOp is Operation mulOp) || mulOp.Inst != Instruction.Multiply)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetShifted16Source(mulOp.GetSource(0), Instruction.ShiftRightU32) != x)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand src2 = GetMasked16Source(mulOp.GetSource(1));
|
||||||
|
|
||||||
|
if (src2.Type != y.Type || src2.Value != y.Value)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryMatchHighTimesHigh(Operation operation, Operand x, Operand lowTimesHighResult)
|
||||||
|
{
|
||||||
|
// xHigh = x >> 16
|
||||||
|
// lowTimesHighResultHigh = lowTimesHighResult >> 16
|
||||||
|
// highTimesHigh = xHigh * lowTimesHighResultHigh
|
||||||
|
// result = highTimesHigh << 16
|
||||||
|
|
||||||
|
if (operation.Inst != Instruction.ShiftLeft || !IsConst(operation.GetSource(1), 16))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand mulResult = operation.GetSource(0);
|
||||||
|
|
||||||
|
if (!(mulResult.AsgOp is Operation mulOp) || mulOp.Inst != Instruction.Multiply)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetShifted16Source(mulOp.GetSource(0), Instruction.ShiftRightU32) != x)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetCopySource(GetShifted16Source(mulOp.GetSource(1), Instruction.ShiftRightU32)) != lowTimesHighResult)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operand GetMasked16Source(Operand value)
|
||||||
|
{
|
||||||
|
if (!(value.AsgOp is Operation maskOp))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maskOp.Inst != Instruction.BitwiseAnd || !IsConst(maskOp.GetSource(1), ushort.MaxValue))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return maskOp.GetSource(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operand GetShifted16Source(Operand value, Instruction shiftInst)
|
||||||
|
{
|
||||||
|
if (!(value.AsgOp is Operation shiftOp))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shiftOp.Inst != shiftInst || !IsConst(shiftOp.GetSource(1), 16))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return shiftOp.GetSource(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operand GetCopySource(Operand value)
|
||||||
|
{
|
||||||
|
while (value.AsgOp is Operation operation && IsCopy(operation))
|
||||||
|
{
|
||||||
|
value = operation.GetSource(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsCopy(Operation operation)
|
||||||
|
{
|
||||||
|
return operation.Inst == Instruction.Copy || (operation.Inst == Instruction.Add && IsConst(operation.GetSource(1), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsConst(Operand operand, int value)
|
||||||
|
{
|
||||||
|
return operand.Type == OperandType.Constant && operand.Value == value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,10 +32,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
CommandBuffer
|
CommandBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool _feedbackLoopActive;
|
||||||
private PipelineStageFlags _incoherentBufferWriteStages;
|
private PipelineStageFlags _incoherentBufferWriteStages;
|
||||||
private PipelineStageFlags _incoherentTextureWriteStages;
|
private PipelineStageFlags _incoherentTextureWriteStages;
|
||||||
private PipelineStageFlags _extraStages;
|
private PipelineStageFlags _extraStages;
|
||||||
private IncoherentBarrierType _queuedIncoherentBarrier;
|
private IncoherentBarrierType _queuedIncoherentBarrier;
|
||||||
|
private bool _queuedFeedbackLoopBarrier;
|
||||||
|
|
||||||
public BarrierBatch(VulkanRenderer gd)
|
public BarrierBatch(VulkanRenderer gd)
|
||||||
{
|
{
|
||||||
@@ -53,17 +55,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
stages |= PipelineStageFlags.TransformFeedbackBitExt;
|
stages |= PipelineStageFlags.TransformFeedbackBitExt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gd.IsTBDR)
|
|
||||||
{
|
|
||||||
// Desktop GPUs can transform image barriers into memory barriers.
|
|
||||||
|
|
||||||
access |= AccessFlags.DepthStencilAttachmentWriteBit | AccessFlags.ColorAttachmentWriteBit;
|
|
||||||
access |= AccessFlags.DepthStencilAttachmentReadBit | AccessFlags.ColorAttachmentReadBit;
|
|
||||||
|
|
||||||
stages |= PipelineStageFlags.EarlyFragmentTestsBit | PipelineStageFlags.LateFragmentTestsBit;
|
|
||||||
stages |= PipelineStageFlags.ColorAttachmentOutputBit;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (access, stages);
|
return (access, stages);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,16 +169,34 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
|
|
||||||
_queuedIncoherentBarrier = IncoherentBarrierType.None;
|
_queuedIncoherentBarrier = IncoherentBarrierType.None;
|
||||||
|
_queuedFeedbackLoopBarrier = false;
|
||||||
}
|
}
|
||||||
|
else if (_feedbackLoopActive && _queuedFeedbackLoopBarrier)
|
||||||
|
{
|
||||||
|
// Feedback loop barrier.
|
||||||
|
|
||||||
|
MemoryBarrier barrier = new MemoryBarrier()
|
||||||
|
{
|
||||||
|
SType = StructureType.MemoryBarrier,
|
||||||
|
SrcAccessMask = AccessFlags.ShaderWriteBit,
|
||||||
|
DstAccessMask = AccessFlags.ShaderReadBit
|
||||||
|
};
|
||||||
|
|
||||||
|
QueueBarrier(barrier, PipelineStageFlags.FragmentShaderBit, PipelineStageFlags.AllGraphicsBit);
|
||||||
|
|
||||||
|
_queuedFeedbackLoopBarrier = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_feedbackLoopActive = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe void Flush(CommandBufferScoped cbs, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass)
|
public unsafe void Flush(CommandBufferScoped cbs, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass)
|
||||||
{
|
{
|
||||||
Flush(cbs, null, inRenderPass, rpHolder, endRenderPass);
|
Flush(cbs, null, false, inRenderPass, rpHolder, endRenderPass);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe void Flush(CommandBufferScoped cbs, ShaderCollection program, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass)
|
public unsafe void Flush(CommandBufferScoped cbs, ShaderCollection program, bool feedbackLoopActive, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass)
|
||||||
{
|
{
|
||||||
if (program != null)
|
if (program != null)
|
||||||
{
|
{
|
||||||
@@ -195,6 +204,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_incoherentTextureWriteStages |= program.IncoherentTextureWriteStages;
|
_incoherentTextureWriteStages |= program.IncoherentTextureWriteStages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_feedbackLoopActive |= feedbackLoopActive;
|
||||||
|
|
||||||
FlushMemoryBarrier(program, inRenderPass);
|
FlushMemoryBarrier(program, inRenderPass);
|
||||||
|
|
||||||
if (!inRenderPass && rpHolder != null)
|
if (!inRenderPass && rpHolder != null)
|
||||||
@@ -406,6 +417,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
_queuedIncoherentBarrier = type;
|
_queuedIncoherentBarrier = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_queuedFeedbackLoopBarrier = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void QueueTextureBarrier()
|
public void QueueTextureBarrier()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Ryujinx.Graphics.GAL;
|
|||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
|
using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
|
||||||
@@ -41,15 +42,15 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private record struct TextureRef
|
private record struct TextureRef
|
||||||
{
|
{
|
||||||
public ShaderStage Stage;
|
public ShaderStage Stage;
|
||||||
public TextureStorage Storage;
|
public TextureView View;
|
||||||
public Auto<DisposableImageView> View;
|
public Auto<DisposableImageView> ImageView;
|
||||||
public Auto<DisposableSampler> Sampler;
|
public Auto<DisposableSampler> Sampler;
|
||||||
|
|
||||||
public TextureRef(ShaderStage stage, TextureStorage storage, Auto<DisposableImageView> view, Auto<DisposableSampler> sampler)
|
public TextureRef(ShaderStage stage, TextureView view, Auto<DisposableImageView> imageView, Auto<DisposableSampler> sampler)
|
||||||
{
|
{
|
||||||
Stage = stage;
|
Stage = stage;
|
||||||
Storage = storage;
|
|
||||||
View = view;
|
View = view;
|
||||||
|
ImageView = imageView;
|
||||||
Sampler = sampler;
|
Sampler = sampler;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,14 +58,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private record struct ImageRef
|
private record struct ImageRef
|
||||||
{
|
{
|
||||||
public ShaderStage Stage;
|
public ShaderStage Stage;
|
||||||
public TextureStorage Storage;
|
public TextureView View;
|
||||||
public Auto<DisposableImageView> View;
|
public Auto<DisposableImageView> ImageView;
|
||||||
|
|
||||||
public ImageRef(ShaderStage stage, TextureStorage storage, Auto<DisposableImageView> view)
|
public ImageRef(ShaderStage stage, TextureView view, Auto<DisposableImageView> imageView)
|
||||||
{
|
{
|
||||||
Stage = stage;
|
Stage = stage;
|
||||||
Storage = storage;
|
|
||||||
View = view;
|
View = view;
|
||||||
|
ImageView = imageView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,6 +123,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private readonly TextureView _dummyTexture;
|
private readonly TextureView _dummyTexture;
|
||||||
private readonly SamplerHolder _dummySampler;
|
private readonly SamplerHolder _dummySampler;
|
||||||
|
|
||||||
|
public List<TextureView> FeedbackLoopHazards { get; private set; }
|
||||||
|
|
||||||
public DescriptorSetUpdater(VulkanRenderer gd, Device device)
|
public DescriptorSetUpdater(VulkanRenderer gd, Device device)
|
||||||
{
|
{
|
||||||
_gd = gd;
|
_gd = gd;
|
||||||
@@ -206,10 +209,15 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_templateUpdater = new();
|
_templateUpdater = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize(bool isMainPipeline)
|
||||||
{
|
{
|
||||||
MemoryOwner<byte> dummyTextureData = MemoryOwner<byte>.RentCleared(4);
|
MemoryOwner<byte> dummyTextureData = MemoryOwner<byte>.RentCleared(4);
|
||||||
_dummyTexture.SetData(dummyTextureData);
|
_dummyTexture.SetData(dummyTextureData);
|
||||||
|
|
||||||
|
if (isMainPipeline)
|
||||||
|
{
|
||||||
|
FeedbackLoopHazards = new();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool BindingOverlaps(ref DescriptorBufferInfo info, int bindingOffset, int offset, int size)
|
private static bool BindingOverlaps(ref DescriptorBufferInfo info, int bindingOffset, int offset, int size)
|
||||||
@@ -272,6 +280,18 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public void InsertBindingBarriers(CommandBufferScoped cbs)
|
public void InsertBindingBarriers(CommandBufferScoped cbs)
|
||||||
{
|
{
|
||||||
|
if ((FeedbackLoopHazards?.Count ?? 0) > 0)
|
||||||
|
{
|
||||||
|
// Clear existing hazards - they will be rebuilt.
|
||||||
|
|
||||||
|
foreach (TextureView hazard in FeedbackLoopHazards)
|
||||||
|
{
|
||||||
|
hazard.DecrementHazardUses();
|
||||||
|
}
|
||||||
|
|
||||||
|
FeedbackLoopHazards.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
foreach (ResourceBindingSegment segment in _program.BindingSegments[PipelineBase.TextureSetIndex])
|
foreach (ResourceBindingSegment segment in _program.BindingSegments[PipelineBase.TextureSetIndex])
|
||||||
{
|
{
|
||||||
if (segment.Type == ResourceType.TextureAndSampler)
|
if (segment.Type == ResourceType.TextureAndSampler)
|
||||||
@@ -281,7 +301,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
for (int i = 0; i < segment.Count; i++)
|
for (int i = 0; i < segment.Count; i++)
|
||||||
{
|
{
|
||||||
ref var texture = ref _textureRefs[segment.Binding + i];
|
ref var texture = ref _textureRefs[segment.Binding + i];
|
||||||
texture.Storage?.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, texture.Stage.ConvertToPipelineStageFlags());
|
texture.View?.PrepareForUsage(cbs, texture.Stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -302,7 +322,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
for (int i = 0; i < segment.Count; i++)
|
for (int i = 0; i < segment.Count; i++)
|
||||||
{
|
{
|
||||||
ref var image = ref _imageRefs[segment.Binding + i];
|
ref var image = ref _imageRefs[segment.Binding + i];
|
||||||
image.Storage?.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, image.Stage.ConvertToPipelineStageFlags());
|
image.View?.PrepareForUsage(cbs, image.Stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -376,9 +396,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
else if (image is TextureView view)
|
else if (image is TextureView view)
|
||||||
{
|
{
|
||||||
view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
ref ImageRef iRef = ref _imageRefs[binding];
|
||||||
|
|
||||||
_imageRefs[binding]= new(stage, view.Storage, view.GetIdentityImageView());
|
iRef.View?.ClearUsage(FeedbackLoopHazards);
|
||||||
|
view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
||||||
|
|
||||||
|
iRef = new(stage, view, view.GetIdentityImageView());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -476,9 +499,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
else if (texture is TextureView view)
|
else if (texture is TextureView view)
|
||||||
{
|
{
|
||||||
view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
ref TextureRef iRef = ref _textureRefs[binding];
|
||||||
|
|
||||||
_textureRefs[binding] = new(stage, view.Storage, view.GetImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
iRef.View?.ClearUsage(FeedbackLoopHazards);
|
||||||
|
view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
||||||
|
|
||||||
|
iRef = new(stage, view, view.GetImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -500,7 +526,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
||||||
|
|
||||||
_textureRefs[binding] = new(stage, view.Storage, view.GetIdentityImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
_textureRefs[binding] = new(stage, view, view.GetIdentityImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
||||||
|
|
||||||
SignalDirty(DirtyFlags.Texture);
|
SignalDirty(DirtyFlags.Texture);
|
||||||
}
|
}
|
||||||
@@ -826,7 +852,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
ref var texture = ref textures[i];
|
ref var texture = ref textures[i];
|
||||||
ref var refs = ref _textureRefs[binding + i];
|
ref var refs = ref _textureRefs[binding + i];
|
||||||
|
|
||||||
texture.ImageView = refs.View?.Get(cbs).Value ?? default;
|
texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default;
|
||||||
texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
|
texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
|
||||||
|
|
||||||
if (texture.ImageView.Handle == 0)
|
if (texture.ImageView.Handle == 0)
|
||||||
@@ -876,7 +902,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
images[i].ImageView = _imageRefs[binding + i].View?.Get(cbs).Value ?? default;
|
images[i].ImageView = _imageRefs[binding + i].ImageView?.Get(cbs).Value ?? default;
|
||||||
}
|
}
|
||||||
|
|
||||||
tu.Push<DescriptorImageInfo>(images[..count]);
|
tu.Push<DescriptorImageInfo>(images[..count]);
|
||||||
@@ -947,7 +973,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
ref var texture = ref textures[i];
|
ref var texture = ref textures[i];
|
||||||
ref var refs = ref _textureRefs[binding + i];
|
ref var refs = ref _textureRefs[binding + i];
|
||||||
|
|
||||||
texture.ImageView = refs.View?.Get(cbs).Value ?? default;
|
texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default;
|
||||||
texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
|
texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
|
||||||
|
|
||||||
if (texture.ImageView.Handle == 0)
|
if (texture.ImageView.Handle == 0)
|
||||||
|
|||||||
@@ -254,8 +254,8 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
|||||||
|
|
||||||
scissors[0] = new Rectangle<int>(0, 0, texture.Width, texture.Height);
|
scissors[0] = new Rectangle<int>(0, 0, texture.Width, texture.Height);
|
||||||
|
|
||||||
_pipeline.SetRenderTarget(texture, (uint)texture.Width, (uint)texture.Height, false);
|
_pipeline.SetRenderTarget(texture, (uint)texture.Width, (uint)texture.Height);
|
||||||
_pipeline.SetRenderTargetColorMasks(colorMasks, false);
|
_pipeline.SetRenderTargetColorMasks(colorMasks);
|
||||||
_pipeline.SetScissors(scissors);
|
_pipeline.SetScissors(scissors);
|
||||||
_pipeline.ClearRenderTargetColor(0, 0, 1, new ColorF(0f, 0f, 0f, 1f));
|
_pipeline.ClearRenderTargetColor(0, 0, 1, new ColorF(0f, 0f, 0f, 1f));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -238,7 +238,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Face.Back => CullModeFlags.BackBit,
|
Face.Back => CullModeFlags.BackBit,
|
||||||
Face.Front => CullModeFlags.FrontBit,
|
Face.Front => CullModeFlags.FrontBit,
|
||||||
Face.FrontAndBack => CullModeFlags.FrontAndBack,
|
Face.FrontAndBack => CullModeFlags.FrontAndBack,
|
||||||
Face.None => CullModeFlags.None,
|
|
||||||
_ => LogInvalidAndReturn(face, nameof(Face), CullModeFlags.BackBit),
|
_ => LogInvalidAndReturn(face, nameof(Face), CullModeFlags.BackBit),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -311,25 +310,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PrimitiveTopology ConvertToClass(this PrimitiveTopology topology)
|
|
||||||
{
|
|
||||||
return topology switch
|
|
||||||
{
|
|
||||||
PrimitiveTopology.PointList => PrimitiveTopology.PointList,
|
|
||||||
PrimitiveTopology.LineList or
|
|
||||||
PrimitiveTopology.LineStrip or
|
|
||||||
PrimitiveTopology.LineListWithAdjacency or
|
|
||||||
PrimitiveTopology.LineStripWithAdjacency => PrimitiveTopology.LineList,
|
|
||||||
PrimitiveTopology.TriangleList or
|
|
||||||
PrimitiveTopology.TriangleStrip or
|
|
||||||
PrimitiveTopology.TriangleFan or
|
|
||||||
PrimitiveTopology.TriangleListWithAdjacency or
|
|
||||||
PrimitiveTopology.TriangleStripWithAdjacency => PrimitiveTopology.TriangleStrip,
|
|
||||||
PrimitiveTopology.PatchList => PrimitiveTopology.PatchList,
|
|
||||||
_ => LogInvalidAndReturn(topology, nameof(PrimitiveTopology), PrimitiveTopology.TriangleStrip),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static StencilOp Convert(this GAL.StencilOp op)
|
public static StencilOp Convert(this GAL.StencilOp op)
|
||||||
{
|
{
|
||||||
return op switch
|
return op switch
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
internal enum FeedbackLoopAspects
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Color = 1 << 0,
|
||||||
|
Depth = 1 << 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,48 +9,48 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
class FormatCapabilities
|
class FormatCapabilities
|
||||||
{
|
{
|
||||||
private static readonly GAL.Format[] _scaledFormats =
|
private static readonly Format[] _scaledFormats =
|
||||||
[
|
[
|
||||||
GAL.Format.R8Uscaled,
|
Format.R8Uscaled,
|
||||||
GAL.Format.R8Sscaled,
|
Format.R8Sscaled,
|
||||||
GAL.Format.R16Uscaled,
|
Format.R16Uscaled,
|
||||||
GAL.Format.R16Sscaled,
|
Format.R16Sscaled,
|
||||||
GAL.Format.R8G8Uscaled,
|
Format.R8G8Uscaled,
|
||||||
GAL.Format.R8G8Sscaled,
|
Format.R8G8Sscaled,
|
||||||
GAL.Format.R16G16Uscaled,
|
Format.R16G16Uscaled,
|
||||||
GAL.Format.R16G16Sscaled,
|
Format.R16G16Sscaled,
|
||||||
GAL.Format.R8G8B8Uscaled,
|
Format.R8G8B8Uscaled,
|
||||||
GAL.Format.R8G8B8Sscaled,
|
Format.R8G8B8Sscaled,
|
||||||
GAL.Format.R16G16B16Uscaled,
|
Format.R16G16B16Uscaled,
|
||||||
GAL.Format.R16G16B16Sscaled,
|
Format.R16G16B16Sscaled,
|
||||||
GAL.Format.R8G8B8A8Uscaled,
|
Format.R8G8B8A8Uscaled,
|
||||||
GAL.Format.R8G8B8A8Sscaled,
|
Format.R8G8B8A8Sscaled,
|
||||||
GAL.Format.R16G16B16A16Uscaled,
|
Format.R16G16B16A16Uscaled,
|
||||||
GAL.Format.R16G16B16A16Sscaled,
|
Format.R16G16B16A16Sscaled,
|
||||||
GAL.Format.R10G10B10A2Uscaled,
|
Format.R10G10B10A2Uscaled,
|
||||||
GAL.Format.R10G10B10A2Sscaled
|
Format.R10G10B10A2Sscaled
|
||||||
];
|
];
|
||||||
|
|
||||||
private static readonly GAL.Format[] _intFormats =
|
private static readonly Format[] _intFormats =
|
||||||
[
|
[
|
||||||
GAL.Format.R8Uint,
|
Format.R8Uint,
|
||||||
GAL.Format.R8Sint,
|
Format.R8Sint,
|
||||||
GAL.Format.R16Uint,
|
Format.R16Uint,
|
||||||
GAL.Format.R16Sint,
|
Format.R16Sint,
|
||||||
GAL.Format.R8G8Uint,
|
Format.R8G8Uint,
|
||||||
GAL.Format.R8G8Sint,
|
Format.R8G8Sint,
|
||||||
GAL.Format.R16G16Uint,
|
Format.R16G16Uint,
|
||||||
GAL.Format.R16G16Sint,
|
Format.R16G16Sint,
|
||||||
GAL.Format.R8G8B8Uint,
|
Format.R8G8B8Uint,
|
||||||
GAL.Format.R8G8B8Sint,
|
Format.R8G8B8Sint,
|
||||||
GAL.Format.R16G16B16Uint,
|
Format.R16G16B16Uint,
|
||||||
GAL.Format.R16G16B16Sint,
|
Format.R16G16B16Sint,
|
||||||
GAL.Format.R8G8B8A8Uint,
|
Format.R8G8B8A8Uint,
|
||||||
GAL.Format.R8G8B8A8Sint,
|
Format.R8G8B8A8Sint,
|
||||||
GAL.Format.R16G16B16A16Uint,
|
Format.R16G16B16A16Uint,
|
||||||
GAL.Format.R16G16B16A16Sint,
|
Format.R16G16B16A16Sint,
|
||||||
GAL.Format.R10G10B10A2Uint,
|
Format.R10G10B10A2Uint,
|
||||||
GAL.Format.R10G10B10A2Sint
|
Format.R10G10B10A2Sint
|
||||||
];
|
];
|
||||||
|
|
||||||
private readonly FormatFeatureFlags[] _bufferTable;
|
private readonly FormatFeatureFlags[] _bufferTable;
|
||||||
|
|||||||
@@ -302,6 +302,27 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_depthStencil?.Storage?.AddStoreOpUsage(true);
|
_depthStencil?.Storage?.AddStoreOpUsage(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ClearBindings()
|
||||||
|
{
|
||||||
|
_depthStencil?.Storage.ClearBindings();
|
||||||
|
|
||||||
|
for (int i = 0; i < _colorsCanonical.Length; i++)
|
||||||
|
{
|
||||||
|
_colorsCanonical[i]?.Storage.ClearBindings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddBindings()
|
||||||
|
{
|
||||||
|
_depthStencil?.Storage.AddBinding(_depthStencil);
|
||||||
|
|
||||||
|
for (int i = 0; i < _colorsCanonical.Length; i++)
|
||||||
|
{
|
||||||
|
TextureView color = _colorsCanonical[i];
|
||||||
|
color?.Storage.AddBinding(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer(
|
public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer(
|
||||||
VulkanRenderer gd,
|
VulkanRenderer gd,
|
||||||
Device device,
|
Device device,
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
public readonly bool SupportsShaderStorageImageMultisample;
|
public readonly bool SupportsShaderStorageImageMultisample;
|
||||||
public readonly bool SupportsConditionalRendering;
|
public readonly bool SupportsConditionalRendering;
|
||||||
public readonly bool SupportsExtendedDynamicState;
|
public readonly bool SupportsExtendedDynamicState;
|
||||||
public readonly PhysicalDeviceExtendedDynamicState2FeaturesEXT SupportsExtendedDynamicState2;
|
|
||||||
public readonly bool SupportsMultiView;
|
public readonly bool SupportsMultiView;
|
||||||
public readonly bool SupportsNullDescriptors;
|
public readonly bool SupportsNullDescriptors;
|
||||||
public readonly bool SupportsPushDescriptors;
|
public readonly bool SupportsPushDescriptors;
|
||||||
@@ -47,14 +46,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
public readonly bool SupportsViewportArray2;
|
public readonly bool SupportsViewportArray2;
|
||||||
public readonly bool SupportsHostImportedMemory;
|
public readonly bool SupportsHostImportedMemory;
|
||||||
public readonly bool SupportsDepthClipControl;
|
public readonly bool SupportsDepthClipControl;
|
||||||
public readonly bool SupportsWideLines;
|
public readonly bool SupportsAttachmentFeedbackLoop;
|
||||||
|
public readonly bool SupportsDynamicAttachmentFeedbackLoop;
|
||||||
public readonly uint SubgroupSize;
|
public readonly uint SubgroupSize;
|
||||||
public readonly SampleCountFlags SupportedSampleCounts;
|
public readonly SampleCountFlags SupportedSampleCounts;
|
||||||
public readonly PortabilitySubsetFlags PortabilitySubset;
|
public readonly PortabilitySubsetFlags PortabilitySubset;
|
||||||
public readonly uint VertexBufferAlignment;
|
public readonly uint VertexBufferAlignment;
|
||||||
public readonly uint SubTexelPrecisionBits;
|
public readonly uint SubTexelPrecisionBits;
|
||||||
public readonly ulong MinResourceAlignment;
|
public readonly ulong MinResourceAlignment;
|
||||||
public readonly uint MaxTessellationPatchSize;
|
|
||||||
|
|
||||||
public HardwareCapabilities(
|
public HardwareCapabilities(
|
||||||
bool supportsIndexTypeUint8,
|
bool supportsIndexTypeUint8,
|
||||||
@@ -72,8 +71,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
bool supportsShaderStorageImageMultisample,
|
bool supportsShaderStorageImageMultisample,
|
||||||
bool supportsConditionalRendering,
|
bool supportsConditionalRendering,
|
||||||
bool supportsExtendedDynamicState,
|
bool supportsExtendedDynamicState,
|
||||||
PhysicalDeviceExtendedDynamicState2FeaturesEXT supportsExtendedDynamicState2,
|
|
||||||
uint maxTessellationPatchSize,
|
|
||||||
bool supportsMultiView,
|
bool supportsMultiView,
|
||||||
bool supportsNullDescriptors,
|
bool supportsNullDescriptors,
|
||||||
bool supportsPushDescriptors,
|
bool supportsPushDescriptors,
|
||||||
@@ -89,7 +86,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
bool supportsViewportArray2,
|
bool supportsViewportArray2,
|
||||||
bool supportsHostImportedMemory,
|
bool supportsHostImportedMemory,
|
||||||
bool supportsDepthClipControl,
|
bool supportsDepthClipControl,
|
||||||
bool supportsWideLines,
|
bool supportsAttachmentFeedbackLoop,
|
||||||
|
bool supportsDynamicAttachmentFeedbackLoop,
|
||||||
uint subgroupSize,
|
uint subgroupSize,
|
||||||
SampleCountFlags supportedSampleCounts,
|
SampleCountFlags supportedSampleCounts,
|
||||||
PortabilitySubsetFlags portabilitySubset,
|
PortabilitySubsetFlags portabilitySubset,
|
||||||
@@ -112,8 +110,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
SupportsShaderStorageImageMultisample = supportsShaderStorageImageMultisample;
|
SupportsShaderStorageImageMultisample = supportsShaderStorageImageMultisample;
|
||||||
SupportsConditionalRendering = supportsConditionalRendering;
|
SupportsConditionalRendering = supportsConditionalRendering;
|
||||||
SupportsExtendedDynamicState = supportsExtendedDynamicState;
|
SupportsExtendedDynamicState = supportsExtendedDynamicState;
|
||||||
SupportsExtendedDynamicState2 = supportsExtendedDynamicState2;
|
|
||||||
MaxTessellationPatchSize = maxTessellationPatchSize;
|
|
||||||
SupportsMultiView = supportsMultiView;
|
SupportsMultiView = supportsMultiView;
|
||||||
SupportsNullDescriptors = supportsNullDescriptors;
|
SupportsNullDescriptors = supportsNullDescriptors;
|
||||||
SupportsPushDescriptors = supportsPushDescriptors;
|
SupportsPushDescriptors = supportsPushDescriptors;
|
||||||
@@ -129,7 +125,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
SupportsViewportArray2 = supportsViewportArray2;
|
SupportsViewportArray2 = supportsViewportArray2;
|
||||||
SupportsHostImportedMemory = supportsHostImportedMemory;
|
SupportsHostImportedMemory = supportsHostImportedMemory;
|
||||||
SupportsDepthClipControl = supportsDepthClipControl;
|
SupportsDepthClipControl = supportsDepthClipControl;
|
||||||
SupportsWideLines = supportsWideLines;
|
SupportsAttachmentFeedbackLoop = supportsAttachmentFeedbackLoop;
|
||||||
|
SupportsDynamicAttachmentFeedbackLoop = supportsDynamicAttachmentFeedbackLoop;
|
||||||
SubgroupSize = subgroupSize;
|
SubgroupSize = subgroupSize;
|
||||||
SupportedSampleCounts = supportedSampleCounts;
|
SupportedSampleCounts = supportedSampleCounts;
|
||||||
PortabilitySubset = portabilitySubset;
|
PortabilitySubset = portabilitySubset;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using Ryujinx.Graphics.Shader;
|
|||||||
using Ryujinx.Graphics.Shader.Translation;
|
using Ryujinx.Graphics.Shader.Translation;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
|
using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
|
||||||
using Format = Ryujinx.Graphics.GAL.Format;
|
using Format = Ryujinx.Graphics.GAL.Format;
|
||||||
@@ -406,35 +405,35 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
if (dstIsDepthOrStencil)
|
if (dstIsDepthOrStencil)
|
||||||
{
|
{
|
||||||
_pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit, false);
|
_pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit);
|
||||||
_pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always), false);
|
_pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always));
|
||||||
}
|
}
|
||||||
else if (src.Info.Target.IsMultisample())
|
else if (src.Info.Target.IsMultisample())
|
||||||
{
|
{
|
||||||
_pipeline.SetProgram(_programColorBlitMs, false);
|
_pipeline.SetProgram(_programColorBlitMs);
|
||||||
}
|
}
|
||||||
else if (clearAlpha)
|
else if (clearAlpha)
|
||||||
{
|
{
|
||||||
_pipeline.SetProgram(_programColorBlitClearAlpha, false);
|
_pipeline.SetProgram(_programColorBlitClearAlpha);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_pipeline.SetProgram(_programColorBlit, false);
|
_pipeline.SetProgram(_programColorBlit);
|
||||||
}
|
}
|
||||||
|
|
||||||
int dstWidth = dst.Width;
|
int dstWidth = dst.Width;
|
||||||
int dstHeight = dst.Height;
|
int dstHeight = dst.Height;
|
||||||
|
|
||||||
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false);
|
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight);
|
||||||
_pipeline.SetRenderTargetColorMasks([0xf], false);
|
_pipeline.SetRenderTargetColorMasks([0xf]);
|
||||||
_pipeline.SetScissors([new Rectangle<int>(0, 0, dstWidth, dstHeight)], false);
|
_pipeline.SetScissors([new Rectangle<int>(0, 0, dstWidth, dstHeight)]);
|
||||||
|
|
||||||
if (clearAlpha)
|
if (clearAlpha)
|
||||||
{
|
{
|
||||||
_pipeline.ClearRenderTargetColor(0, 0, 1, new ColorF(0f, 0f, 0f, 1f));
|
_pipeline.ClearRenderTargetColor(0, 0, 1, new ColorF(0f, 0f, 0f, 1f));
|
||||||
}
|
}
|
||||||
|
|
||||||
_pipeline.SetViewports(viewports, false);
|
_pipeline.SetViewports(viewports);
|
||||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||||
_pipeline.Draw(4, 1, 0, 0);
|
_pipeline.Draw(4, 1, 0, 0);
|
||||||
|
|
||||||
@@ -501,10 +500,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
int dstWidth = dst.Width;
|
int dstWidth = dst.Width;
|
||||||
int dstHeight = dst.Height;
|
int dstHeight = dst.Height;
|
||||||
|
|
||||||
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false);
|
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight);
|
||||||
_pipeline.SetScissors([new Rectangle<int>(0, 0, dstWidth, dstHeight)], false);
|
_pipeline.SetScissors([new Rectangle<int>(0, 0, dstWidth, dstHeight)]);
|
||||||
_pipeline.SetViewports(viewports, false);
|
_pipeline.SetViewports(viewports);
|
||||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip, false);
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||||
|
|
||||||
var aspectFlags = src.Info.Format.ConvertAspectFlags();
|
var aspectFlags = src.Info.Format.ConvertAspectFlags();
|
||||||
|
|
||||||
@@ -566,12 +565,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
if (isDepth)
|
if (isDepth)
|
||||||
{
|
{
|
||||||
_pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit, false);
|
_pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit);
|
||||||
_pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always));
|
_pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programStencilBlitMs : _programStencilBlit, false);
|
_pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programStencilBlitMs : _programStencilBlit);
|
||||||
_pipeline.SetStencilTest(CreateStencilTestDescriptor(true));
|
_pipeline.SetStencilTest(CreateStencilTestDescriptor(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,11 +660,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
program = _programColorClearF;
|
program = _programColorClearF;
|
||||||
}
|
}
|
||||||
|
|
||||||
_pipeline.SetProgram(program, false);
|
_pipeline.SetProgram(program);
|
||||||
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false);
|
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight);
|
||||||
_pipeline.SetRenderTargetColorMasks(new[] { componentMask }, false);
|
_pipeline.SetRenderTargetColorMasks(new[] { componentMask });
|
||||||
_pipeline.SetViewports(viewports, false);
|
_pipeline.SetViewports(viewports);
|
||||||
_pipeline.SetScissors([scissor], false);
|
_pipeline.SetScissors([scissor]);
|
||||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||||
_pipeline.Draw(4, 1, 0, 0);
|
_pipeline.Draw(4, 1, 0, 0);
|
||||||
_pipeline.Finish();
|
_pipeline.Finish();
|
||||||
@@ -708,12 +707,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
0f,
|
0f,
|
||||||
1f);
|
1f);
|
||||||
|
|
||||||
_pipeline.SetProgram(_programDepthStencilClear, false);
|
_pipeline.SetProgram(_programDepthStencilClear);
|
||||||
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false);
|
_pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight);
|
||||||
_pipeline.SetViewports(viewports, false);
|
_pipeline.SetViewports(viewports);
|
||||||
_pipeline.SetScissors([scissor], false);
|
_pipeline.SetScissors([scissor]);
|
||||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip, false);
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||||
_pipeline.SetDepthTest(new DepthTestDescriptor(true, depthMask, CompareOp.Always), false);
|
_pipeline.SetDepthTest(new DepthTestDescriptor(true, depthMask, CompareOp.Always));
|
||||||
_pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xff, stencilMask));
|
_pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xff, stencilMask));
|
||||||
_pipeline.Draw(4, 1, 0, 0);
|
_pipeline.Draw(4, 1, 0, 0);
|
||||||
_pipeline.Finish();
|
_pipeline.Finish();
|
||||||
@@ -771,8 +770,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
0f,
|
0f,
|
||||||
1f);
|
1f);
|
||||||
|
|
||||||
pipeline.SetProgram(_programColorBlit, false);
|
pipeline.SetProgram(_programColorBlit);
|
||||||
pipeline.SetViewports(viewports, false);
|
pipeline.SetViewports(viewports);
|
||||||
pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||||
pipeline.Draw(4, 1, 0, 0);
|
pipeline.Draw(4, 1, 0, 0);
|
||||||
|
|
||||||
@@ -1094,16 +1093,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
0f,
|
0f,
|
||||||
1f);
|
1f);
|
||||||
|
|
||||||
_pipeline.SetScissors([new Rectangle<int>(0, 0, dst.Width, dst.Height)], false);
|
_pipeline.SetScissors([new Rectangle<int>(0, 0, dst.Width, dst.Height)]);
|
||||||
_pipeline.SetViewports(viewports, false);
|
_pipeline.SetViewports(viewports);
|
||||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip, false);
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||||
|
|
||||||
for (int z = 0; z < depth; z++)
|
for (int z = 0; z < depth; z++)
|
||||||
{
|
{
|
||||||
var srcView = Create2DLayerView(src, srcLayer + z, 0);
|
var srcView = Create2DLayerView(src, srcLayer + z, 0);
|
||||||
var dstView = Create2DLayerView(dst, dstLayer + z, 0);
|
var dstView = Create2DLayerView(dst, dstLayer + z, 0);
|
||||||
|
|
||||||
_pipeline.SetRenderTarget(dstView, (uint)dst.Width, (uint)dst.Height, false);
|
_pipeline.SetRenderTarget(dstView, (uint)dst.Width, (uint)dst.Height);
|
||||||
|
|
||||||
CopyMSDraw(srcView, aspectFlags, fromMS: true);
|
CopyMSDraw(srcView, aspectFlags, fromMS: true);
|
||||||
|
|
||||||
@@ -1216,9 +1215,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
1f);
|
1f);
|
||||||
|
|
||||||
_pipeline.SetRenderTargetColorMasks([0xf]);
|
_pipeline.SetRenderTargetColorMasks([0xf]);
|
||||||
_pipeline.SetScissors([new Rectangle<int>(0, 0, dst.Width, dst.Height)], false);
|
_pipeline.SetScissors([new Rectangle<int>(0, 0, dst.Width, dst.Height)]);
|
||||||
_pipeline.SetViewports(viewports, false);
|
_pipeline.SetViewports(viewports);
|
||||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip, false);
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||||
|
|
||||||
_pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
|
_pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
|
||||||
|
|
||||||
@@ -1229,7 +1228,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
var srcView = Create2DLayerView(src, srcLayer + z, 0);
|
var srcView = Create2DLayerView(src, srcLayer + z, 0);
|
||||||
var dstView = Create2DLayerView(dst, dstLayer + z, 0);
|
var dstView = Create2DLayerView(dst, dstLayer + z, 0);
|
||||||
|
|
||||||
_pipeline.SetRenderTarget(dstView, (uint)dst.Width, (uint)dst.Height, false);
|
_pipeline.SetRenderTarget(dstView, (uint)dst.Width, (uint)dst.Height);
|
||||||
|
|
||||||
CopyMSDraw(srcView, aspectFlags, fromMS: false);
|
CopyMSDraw(srcView, aspectFlags, fromMS: false);
|
||||||
|
|
||||||
@@ -1246,7 +1245,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_pipeline.SetProgram(_programColorDrawToMs, false);
|
_pipeline.SetProgram(_programColorDrawToMs);
|
||||||
|
|
||||||
var format = GetFormat(src.Info.BytesPerPixel);
|
var format = GetFormat(src.Info.BytesPerPixel);
|
||||||
var vkFormat = FormatTable.GetFormat(format);
|
var vkFormat = FormatTable.GetFormat(format);
|
||||||
@@ -1323,12 +1322,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
if (isDepth)
|
if (isDepth)
|
||||||
{
|
{
|
||||||
_pipeline.SetProgram(fromMS ? _programDepthDrawToNonMs : _programDepthDrawToMs, false);
|
_pipeline.SetProgram(fromMS ? _programDepthDrawToNonMs : _programDepthDrawToMs);
|
||||||
_pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always));
|
_pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_pipeline.SetProgram(fromMS ? _programStencilDrawToNonMs : _programStencilDrawToMs, false);
|
_pipeline.SetProgram(fromMS ? _programStencilDrawToNonMs : _programStencilDrawToMs);
|
||||||
_pipeline.SetStencilTest(CreateStencilTestDescriptor(true));
|
_pipeline.SetStencilTest(CreateStencilTestDescriptor(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@@ -34,6 +34,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
public readonly Action EndRenderPassDelegate;
|
public readonly Action EndRenderPassDelegate;
|
||||||
|
|
||||||
protected PipelineDynamicState DynamicState;
|
protected PipelineDynamicState DynamicState;
|
||||||
|
protected bool IsMainPipeline;
|
||||||
private PipelineState _newState;
|
private PipelineState _newState;
|
||||||
private bool _graphicsStateDirty;
|
private bool _graphicsStateDirty;
|
||||||
private bool _computeStateDirty;
|
private bool _computeStateDirty;
|
||||||
@@ -73,7 +74,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private readonly BufferState[] _transformFeedbackBuffers;
|
private readonly BufferState[] _transformFeedbackBuffers;
|
||||||
private readonly VertexBufferState[] _vertexBuffers;
|
private readonly VertexBufferState[] _vertexBuffers;
|
||||||
private ulong _vertexBuffersDirty;
|
private ulong _vertexBuffersDirty;
|
||||||
private bool _bindingsSet;
|
|
||||||
protected Rectangle<int> ClearScissor;
|
protected Rectangle<int> ClearScissor;
|
||||||
|
|
||||||
private readonly VertexBufferUpdater _vertexBufferUpdater;
|
private readonly VertexBufferUpdater _vertexBufferUpdater;
|
||||||
@@ -87,15 +87,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private bool _tfEnabled;
|
private bool _tfEnabled;
|
||||||
private bool _tfActive;
|
private bool _tfActive;
|
||||||
|
|
||||||
private readonly bool _supportExtDynamic;
|
private FeedbackLoopAspects _feedbackLoop;
|
||||||
private readonly bool _supportExtDynamic2;
|
private bool _passWritesDepthStencil;
|
||||||
|
|
||||||
private readonly PipelineColorBlendAttachmentState[] _storedBlend;
|
private readonly PipelineColorBlendAttachmentState[] _storedBlend;
|
||||||
public ulong DrawCount { get; private set; }
|
public ulong DrawCount { get; private set; }
|
||||||
public bool RenderPassActive { get; private set; }
|
public bool RenderPassActive { get; private set; }
|
||||||
|
|
||||||
private readonly int[] _vertexBufferBindings;
|
|
||||||
|
|
||||||
public unsafe PipelineBase(VulkanRenderer gd, Device device)
|
public unsafe PipelineBase(VulkanRenderer gd, Device device)
|
||||||
{
|
{
|
||||||
Gd = gd;
|
Gd = gd;
|
||||||
@@ -128,24 +126,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_storedBlend = new PipelineColorBlendAttachmentState[Constants.MaxRenderTargets];
|
_storedBlend = new PipelineColorBlendAttachmentState[Constants.MaxRenderTargets];
|
||||||
|
|
||||||
_supportExtDynamic = gd.Capabilities.SupportsExtendedDynamicState;
|
_newState.Initialize();
|
||||||
|
|
||||||
_supportExtDynamic2 = gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2;
|
|
||||||
|
|
||||||
_bindingsSet = false;
|
|
||||||
|
|
||||||
_vertexBufferBindings = new int[Constants.MaxVertexBuffers];
|
|
||||||
for (int i = 0; i < Constants.MaxVertexBuffers; i++)
|
|
||||||
{
|
|
||||||
_vertexBufferBindings[i] = i + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_newState.Initialize(gd.Capabilities);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
_descriptorSetUpdater.Initialize();
|
_descriptorSetUpdater.Initialize(IsMainPipeline);
|
||||||
|
|
||||||
QuadsToTrisPattern = new IndexBufferPattern(Gd, 4, 6, 0, [0, 1, 2, 0, 2, 3], 4, false);
|
QuadsToTrisPattern = new IndexBufferPattern(Gd, 4, 6, 0, [0, 1, 2, 0, 2, 3], 4, false);
|
||||||
TriFanToTrisPattern = new IndexBufferPattern(Gd, 3, 3, 2, [int.MinValue, -1, 0], 1, true);
|
TriFanToTrisPattern = new IndexBufferPattern(Gd, 3, 3, 2, [int.MinValue, -1, 0], 1, true);
|
||||||
@@ -646,46 +632,19 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
if (texture is TextureView srcTexture)
|
if (texture is TextureView srcTexture)
|
||||||
{
|
{
|
||||||
CullModeFlags oldCullMode;
|
var oldCullMode = _newState.CullMode;
|
||||||
bool oldStencilTestEnable;
|
var oldStencilTestEnable = _newState.StencilTestEnable;
|
||||||
bool oldDepthTestEnable;
|
var oldDepthTestEnable = _newState.DepthTestEnable;
|
||||||
bool oldDepthWriteEnable;
|
var oldDepthWriteEnable = _newState.DepthWriteEnable;
|
||||||
PrimitiveTopology oldTopology;
|
var oldViewports = DynamicState.Viewports;
|
||||||
Array16<Silk.NET.Vulkan.Viewport> oldViewports = DynamicState.Viewports;
|
var oldViewportsCount = _newState.ViewportsCount;
|
||||||
uint oldViewportsCount;
|
var oldTopology = _topology;
|
||||||
|
|
||||||
if (_supportExtDynamic)
|
|
||||||
{
|
|
||||||
oldCullMode = DynamicState.CullMode;
|
|
||||||
oldStencilTestEnable = DynamicState.StencilTestEnable;
|
|
||||||
oldDepthTestEnable = DynamicState.DepthTestEnable;
|
|
||||||
oldDepthWriteEnable = DynamicState.DepthWriteEnable;
|
|
||||||
oldTopology = _topology;
|
|
||||||
oldViewportsCount = DynamicState.ViewportsCount;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
oldCullMode = _newState.CullMode;
|
|
||||||
oldStencilTestEnable = _newState.StencilTestEnable;
|
|
||||||
oldDepthTestEnable = _newState.DepthTestEnable;
|
|
||||||
oldDepthWriteEnable = _newState.DepthWriteEnable;
|
|
||||||
oldTopology = _topology;
|
|
||||||
oldViewportsCount = _newState.ViewportsCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_supportExtDynamic)
|
|
||||||
{
|
|
||||||
DynamicState.SetCullMode(CullModeFlags.None);
|
|
||||||
DynamicState.SetDepthTestBool(false, false);
|
|
||||||
DynamicState.SetStencilTest(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_newState.CullMode = CullModeFlags.None;
|
_newState.CullMode = CullModeFlags.None;
|
||||||
_newState.StencilTestEnable = false;
|
_newState.StencilTestEnable = false;
|
||||||
_newState.DepthTestEnable = false;
|
_newState.DepthTestEnable = false;
|
||||||
_newState.DepthWriteEnable = false;
|
_newState.DepthWriteEnable = false;
|
||||||
}
|
SignalStateChange();
|
||||||
|
|
||||||
Gd.HelperShader.DrawTexture(
|
Gd.HelperShader.DrawTexture(
|
||||||
Gd,
|
Gd,
|
||||||
@@ -695,24 +654,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
srcRegion,
|
srcRegion,
|
||||||
dstRegion);
|
dstRegion);
|
||||||
|
|
||||||
if (_supportExtDynamic)
|
|
||||||
{
|
|
||||||
DynamicState.SetCullMode(oldCullMode);
|
|
||||||
DynamicState.SetStencilTest(oldStencilTestEnable);
|
|
||||||
DynamicState.SetDepthTestBool(oldDepthTestEnable, oldDepthWriteEnable);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_newState.CullMode = oldCullMode;
|
_newState.CullMode = oldCullMode;
|
||||||
_newState.StencilTestEnable = oldStencilTestEnable;
|
_newState.StencilTestEnable = oldStencilTestEnable;
|
||||||
_newState.DepthTestEnable = oldDepthTestEnable;
|
_newState.DepthTestEnable = oldDepthTestEnable;
|
||||||
_newState.DepthWriteEnable = oldDepthWriteEnable;
|
_newState.DepthWriteEnable = oldDepthWriteEnable;
|
||||||
_newState.ViewportsCount = oldViewportsCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetPrimitiveTopology(oldTopology);
|
SetPrimitiveTopology(oldTopology);
|
||||||
|
|
||||||
DynamicState.SetViewports(ref oldViewports, oldViewportsCount);
|
DynamicState.SetViewports(ref oldViewports, oldViewportsCount);
|
||||||
|
|
||||||
|
_newState.ViewportsCount = oldViewportsCount;
|
||||||
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -840,103 +791,50 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp)
|
public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp)
|
||||||
{
|
|
||||||
bool depthBiasEnable = (enables != 0) && (factor != 0 && units != 0);
|
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
if (_supportExtDynamic2)
|
|
||||||
{
|
|
||||||
DynamicState.SetDepthBiasEnable(depthBiasEnable);
|
|
||||||
}
|
|
||||||
else if (_newState.DepthBiasEnable != depthBiasEnable)
|
|
||||||
{
|
|
||||||
_newState.DepthBiasEnable = depthBiasEnable;
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (depthBiasEnable)
|
|
||||||
{
|
{
|
||||||
DynamicState.SetDepthBias(factor, units, clamp);
|
DynamicState.SetDepthBias(factor, units, clamp);
|
||||||
}
|
|
||||||
|
|
||||||
if (changed)
|
_newState.DepthBiasEnable = enables != 0;
|
||||||
{
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void SetDepthClamp(bool clamp)
|
public void SetDepthClamp(bool clamp)
|
||||||
{
|
{
|
||||||
_newState.DepthClampEnable = clamp;
|
_newState.DepthClampEnable = clamp;
|
||||||
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetDepthMode(DepthMode mode)
|
public void SetDepthMode(DepthMode mode)
|
||||||
{
|
{
|
||||||
bool newMode = mode == DepthMode.MinusOneToOne;
|
bool oldMode = _newState.DepthMode;
|
||||||
|
_newState.DepthMode = mode == DepthMode.MinusOneToOne;
|
||||||
if (_newState.DepthMode == newMode)
|
if (_newState.DepthMode != oldMode)
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_newState.DepthMode = newMode;
|
|
||||||
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void SetDepthTest(DepthTestDescriptor depthTest, bool signalChange = true)
|
public void SetDepthTest(DepthTestDescriptor depthTest)
|
||||||
{
|
|
||||||
if (_supportExtDynamic)
|
|
||||||
{
|
|
||||||
DynamicState.SetDepthTestBool(depthTest.TestEnable, depthTest.WriteEnable);
|
|
||||||
if (depthTest.TestEnable)
|
|
||||||
{
|
|
||||||
DynamicState.SetDepthTestCompareOp(depthTest.Func.Convert());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
_newState.DepthTestEnable = depthTest.TestEnable;
|
_newState.DepthTestEnable = depthTest.TestEnable;
|
||||||
_newState.DepthWriteEnable = depthTest.WriteEnable;
|
_newState.DepthWriteEnable = depthTest.WriteEnable;
|
||||||
_newState.DepthCompareOp = depthTest.Func.Convert();
|
_newState.DepthCompareOp = depthTest.Func.Convert();
|
||||||
|
|
||||||
if (signalChange)
|
UpdatePassDepthStencil();
|
||||||
{
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
public void SetFaceCulling(bool enable, Face face)
|
||||||
|
|
||||||
public void SetFaceCulling(Face face)
|
|
||||||
{
|
{
|
||||||
if (_supportExtDynamic)
|
_newState.CullMode = enable ? face.Convert() : CullModeFlags.None;
|
||||||
{
|
|
||||||
DynamicState.SetCullMode(face.Convert());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_newState.CullMode = face.Convert();
|
|
||||||
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void SetFrontFace(FrontFace frontFace)
|
public void SetFrontFace(FrontFace frontFace)
|
||||||
{
|
|
||||||
if (_supportExtDynamic)
|
|
||||||
{
|
|
||||||
DynamicState.SetFrontFace(frontFace.Convert());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
_newState.FrontFace = frontFace.Convert();
|
_newState.FrontFace = frontFace.Convert();
|
||||||
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void SetImage(ShaderStage stage, int binding, ITexture image)
|
public void SetImage(ShaderStage stage, int binding, ITexture image)
|
||||||
{
|
{
|
||||||
@@ -974,56 +872,28 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public void SetLineParameters(float width, bool smooth)
|
public void SetLineParameters(float width, bool smooth)
|
||||||
{
|
{
|
||||||
if (!Gd.IsMoltenVk)
|
_newState.LineWidth = width;
|
||||||
{
|
SignalStateChange();
|
||||||
DynamicState.SetLineWidth(Gd.Capabilities.SupportsWideLines ? width : 1.0f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetLogicOpState(bool enable, LogicalOp op)
|
public void SetLogicOpState(bool enable, LogicalOp op)
|
||||||
{
|
{
|
||||||
// Vendors other than NVIDIA have a bug where it enables logical operations even for float formats,
|
|
||||||
// so we need to force disable them here.
|
|
||||||
bool logicOpEnable = enable && (Gd.Vendor == Vendor.Nvidia || _newState.Internal.LogicOpsAllowed);
|
|
||||||
|
|
||||||
_newState.LogicOpEnable = enable;
|
_newState.LogicOpEnable = enable;
|
||||||
|
|
||||||
if (Gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2LogicOp)
|
|
||||||
{
|
|
||||||
if (logicOpEnable)
|
|
||||||
{
|
|
||||||
DynamicState.SetLogicOp(op.Convert());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_newState.LogicOp = op.Convert();
|
_newState.LogicOp = op.Convert();
|
||||||
}
|
|
||||||
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetMultisampleState(MultisampleDescriptor multisample)
|
public void SetMultisampleState(MultisampleDescriptor multisample)
|
||||||
{
|
{
|
||||||
_newState.AlphaToCoverageEnable = multisample.AlphaToCoverageEnable;
|
_newState.AlphaToCoverageEnable = multisample.AlphaToCoverageEnable;
|
||||||
|
|
||||||
_newState.AlphaToOneEnable = multisample.AlphaToOneEnable;
|
_newState.AlphaToOneEnable = multisample.AlphaToOneEnable;
|
||||||
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetPatchParameters(int vertices, ReadOnlySpan<float> defaultOuterLevel, ReadOnlySpan<float> defaultInnerLevel)
|
public void SetPatchParameters(int vertices, ReadOnlySpan<float> defaultOuterLevel, ReadOnlySpan<float> defaultInnerLevel)
|
||||||
{
|
|
||||||
if (Gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints)
|
|
||||||
{
|
|
||||||
DynamicState.SetPatchControlPoints((uint)vertices);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
_newState.PatchControlPoints = (uint)vertices;
|
_newState.PatchControlPoints = (uint)vertices;
|
||||||
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Default levels (likely needs emulation on shaders?)
|
// TODO: Default levels (likely needs emulation on shaders?)
|
||||||
}
|
}
|
||||||
@@ -1039,22 +909,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void SetPrimitiveRestart(bool enable, int index)
|
public void SetPrimitiveRestart(bool enable, int index)
|
||||||
{
|
|
||||||
if (_supportExtDynamic2)
|
|
||||||
{
|
|
||||||
DynamicState.SetPrimitiveRestartEnable(enable);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
_newState.PrimitiveRestartEnable = enable;
|
_newState.PrimitiveRestartEnable = enable;
|
||||||
|
// TODO: What to do about the index?
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: What to do about the index?
|
public void SetPrimitiveTopology(PrimitiveTopology topology)
|
||||||
}
|
|
||||||
|
|
||||||
public void SetPrimitiveTopology(PrimitiveTopology topology, bool signalChange = true)
|
|
||||||
{
|
{
|
||||||
_topology = topology;
|
_topology = topology;
|
||||||
|
|
||||||
@@ -1062,18 +923,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_newState.Topology = vkTopology;
|
_newState.Topology = vkTopology;
|
||||||
|
|
||||||
if (_supportExtDynamic)
|
|
||||||
{
|
|
||||||
DynamicState.SetPrimitiveTopology(vkTopology);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signalChange)
|
|
||||||
{
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void SetProgram(IProgram program, bool signalChange = true)
|
public void SetProgram(IProgram program)
|
||||||
{
|
{
|
||||||
var internalProgram = (ShaderCollection)program;
|
var internalProgram = (ShaderCollection)program;
|
||||||
var stages = internalProgram.GetInfos();
|
var stages = internalProgram.GetInfos();
|
||||||
@@ -1089,10 +942,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
stages.CopyTo(_newState.Stages.AsSpan()[..stages.Length]);
|
stages.CopyTo(_newState.Stages.AsSpan()[..stages.Length]);
|
||||||
|
|
||||||
if (signalChange)
|
|
||||||
{
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
|
||||||
|
|
||||||
if (internalProgram.IsCompute)
|
if (internalProgram.IsCompute)
|
||||||
{
|
{
|
||||||
@@ -1117,27 +967,19 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void SetRasterizerDiscard(bool discard)
|
public void SetRasterizerDiscard(bool discard)
|
||||||
{
|
|
||||||
if (_supportExtDynamic2)
|
|
||||||
{
|
|
||||||
DynamicState.SetRasterizerDiscard(discard);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
_newState.RasterizerDiscardEnable = discard;
|
_newState.RasterizerDiscardEnable = discard;
|
||||||
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
|
||||||
|
|
||||||
if (!discard && Gd.IsQualcommProprietary)
|
if (!discard && Gd.IsQualcommProprietary)
|
||||||
{
|
{
|
||||||
// On Adreno, enabling rasterizer discard somehow corrupts the viewport state.
|
// On Adreno, enabling rasterizer discard somehow corrupts the viewport state.
|
||||||
// Force it to be updated on next use to work around this bug.
|
// Force it to be updated on next use to work around this bug.
|
||||||
DynamicState.ForceAllDirty(Gd);
|
DynamicState.ForceAllDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask, bool signalChange = true)
|
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask)
|
||||||
{
|
{
|
||||||
int count = Math.Min(Constants.MaxRenderTargets, componentMask.Length);
|
int count = Math.Min(Constants.MaxRenderTargets, componentMask.Length);
|
||||||
int writtenAttachments = 0;
|
int writtenAttachments = 0;
|
||||||
@@ -1176,11 +1018,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
SetRenderTargetsInternal(_preMaskColors, _preMaskDepthStencil, true);
|
SetRenderTargetsInternal(_preMaskColors, _preMaskDepthStencil, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
if (signalChange)
|
|
||||||
{
|
{
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
|
||||||
|
|
||||||
if (writtenAttachments != _writtenAttachmentCount)
|
if (writtenAttachments != _writtenAttachmentCount)
|
||||||
{
|
{
|
||||||
@@ -1204,7 +1043,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
SetRenderTargetsInternal(colors, depthStencil, Gd.IsTBDR);
|
SetRenderTargetsInternal(colors, depthStencil, Gd.IsTBDR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetScissors(ReadOnlySpan<Rectangle<int>> regions, bool signalChange = true)
|
public void SetScissors(ReadOnlySpan<Rectangle<int>> regions)
|
||||||
{
|
{
|
||||||
int maxScissors = Gd.Capabilities.SupportsMultiView ? Constants.MaxViewports : 1;
|
int maxScissors = Gd.Capabilities.SupportsMultiView ? Constants.MaxViewports : 1;
|
||||||
int count = Math.Min(maxScissors, regions.Length);
|
int count = Math.Min(maxScissors, regions.Length);
|
||||||
@@ -1213,8 +1052,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
ClearScissor = regions[0];
|
ClearScissor = regions[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicState.ScissorsCount = count;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var region = regions[i];
|
var region = regions[i];
|
||||||
@@ -1224,36 +1061,23 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
DynamicState.SetScissor(i, new Rect2D(offset, extent));
|
DynamicState.SetScissor(i, new Rect2D(offset, extent));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_supportExtDynamic)
|
DynamicState.ScissorsCount = count;
|
||||||
{
|
|
||||||
_newState.ScissorsCount = (uint)count;
|
|
||||||
|
|
||||||
if (signalChange)
|
_newState.ScissorsCount = (uint)count;
|
||||||
{
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetStencilTest(StencilTestDescriptor stencilTest)
|
public void SetStencilTest(StencilTestDescriptor stencilTest)
|
||||||
{
|
{
|
||||||
if (_supportExtDynamic)
|
DynamicState.SetStencilMasks(
|
||||||
{
|
(uint)stencilTest.BackFuncMask,
|
||||||
DynamicState.SetStencilTestandOp(
|
(uint)stencilTest.BackMask,
|
||||||
stencilTest.BackSFail.Convert(),
|
(uint)stencilTest.BackFuncRef,
|
||||||
stencilTest.BackDpPass.Convert(),
|
(uint)stencilTest.FrontFuncMask,
|
||||||
stencilTest.BackDpFail.Convert(),
|
(uint)stencilTest.FrontMask,
|
||||||
stencilTest.BackFunc.Convert(),
|
(uint)stencilTest.FrontFuncRef);
|
||||||
stencilTest.FrontSFail.Convert(),
|
|
||||||
stencilTest.FrontDpPass.Convert(),
|
|
||||||
stencilTest.FrontDpFail.Convert(),
|
|
||||||
stencilTest.FrontFunc.Convert(),
|
|
||||||
stencilTest.TestEnable);
|
|
||||||
|
|
||||||
SignalStateChange();
|
_newState.StencilTestEnable = stencilTest.TestEnable;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_newState.StencilBackFailOp = stencilTest.BackSFail.Convert();
|
_newState.StencilBackFailOp = stencilTest.BackSFail.Convert();
|
||||||
_newState.StencilBackPassOp = stencilTest.BackDpPass.Convert();
|
_newState.StencilBackPassOp = stencilTest.BackDpPass.Convert();
|
||||||
_newState.StencilBackDepthFailOp = stencilTest.BackDpFail.Convert();
|
_newState.StencilBackDepthFailOp = stencilTest.BackDpFail.Convert();
|
||||||
@@ -1262,19 +1086,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_newState.StencilFrontPassOp = stencilTest.FrontDpPass.Convert();
|
_newState.StencilFrontPassOp = stencilTest.FrontDpPass.Convert();
|
||||||
_newState.StencilFrontDepthFailOp = stencilTest.FrontDpFail.Convert();
|
_newState.StencilFrontDepthFailOp = stencilTest.FrontDpFail.Convert();
|
||||||
_newState.StencilFrontCompareOp = stencilTest.FrontFunc.Convert();
|
_newState.StencilFrontCompareOp = stencilTest.FrontFunc.Convert();
|
||||||
_newState.StencilTestEnable = stencilTest.TestEnable;
|
|
||||||
|
|
||||||
|
UpdatePassDepthStencil();
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicState.SetStencilMask((uint)stencilTest.BackFuncMask,
|
|
||||||
(uint)stencilTest.BackMask,
|
|
||||||
(uint)stencilTest.BackFuncRef,
|
|
||||||
(uint)stencilTest.FrontFuncMask,
|
|
||||||
(uint)stencilTest.FrontMask,
|
|
||||||
(uint)stencilTest.FrontFuncRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
||||||
{
|
{
|
||||||
_descriptorSetUpdater.SetStorageBuffers(CommandBuffer, buffers);
|
_descriptorSetUpdater.SetStorageBuffers(CommandBuffer, buffers);
|
||||||
@@ -1391,24 +1207,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
int count = Math.Min(Constants.MaxVertexBuffers, vertexBuffers.Length);
|
int count = Math.Min(Constants.MaxVertexBuffers, vertexBuffers.Length);
|
||||||
|
|
||||||
|
_newState.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, 0, VertexInputRate.Vertex);
|
||||||
|
|
||||||
int validCount = 1;
|
int validCount = 1;
|
||||||
|
|
||||||
if (!_bindingsSet)
|
|
||||||
{
|
|
||||||
_newState.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, _supportExtDynamic && (!Gd.IsMoltenVk || Gd.SupportsMTL31) ? null : 0, VertexInputRate.Vertex);
|
|
||||||
|
|
||||||
for (int i = 1; i < count; i++)
|
|
||||||
{
|
|
||||||
_newState.Internal.VertexBindingDescriptions[i] = new VertexInputBindingDescription((uint)i);
|
|
||||||
}
|
|
||||||
|
|
||||||
_bindingsSet = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
BufferHandle lastHandle = default;
|
BufferHandle lastHandle = default;
|
||||||
Auto<DisposableBuffer> lastBuffer = default;
|
Auto<DisposableBuffer> lastBuffer = default;
|
||||||
bool vertexBindingDescriptionChanged = false;
|
|
||||||
bool vertexDescriptionCountChanged = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
@@ -1427,32 +1231,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
if (vb != null)
|
if (vb != null)
|
||||||
{
|
{
|
||||||
|
int binding = i + 1;
|
||||||
int descriptorIndex = validCount++;
|
int descriptorIndex = validCount++;
|
||||||
|
|
||||||
if (_supportExtDynamic && (!Gd.IsMoltenVk || Gd.SupportsMTL31))
|
_newState.Internal.VertexBindingDescriptions[descriptorIndex] = new VertexInputBindingDescription(
|
||||||
{
|
(uint)binding,
|
||||||
if (_newState.Internal.VertexBindingDescriptions[descriptorIndex].InputRate != inputRate ||
|
(uint)vertexBuffer.Stride,
|
||||||
_newState.Internal.VertexBindingDescriptions[descriptorIndex].Binding != _vertexBufferBindings[i])
|
inputRate);
|
||||||
{
|
|
||||||
_newState.Internal.VertexBindingDescriptions[descriptorIndex].InputRate = inputRate;
|
|
||||||
_newState.Internal.VertexBindingDescriptions[descriptorIndex].Binding = (uint)_vertexBufferBindings[i];
|
|
||||||
|
|
||||||
vertexBindingDescriptionChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_newState.Internal.VertexBindingDescriptions[descriptorIndex].InputRate != inputRate ||
|
|
||||||
_newState.Internal.VertexBindingDescriptions[descriptorIndex].Stride != vertexBuffer.Stride ||
|
|
||||||
_newState.Internal.VertexBindingDescriptions[descriptorIndex].Binding != _vertexBufferBindings[i])
|
|
||||||
{
|
|
||||||
_newState.Internal.VertexBindingDescriptions[descriptorIndex].Binding = (uint)_vertexBufferBindings[i];
|
|
||||||
_newState.Internal.VertexBindingDescriptions[descriptorIndex].Stride = (uint)vertexBuffer.Stride;
|
|
||||||
_newState.Internal.VertexBindingDescriptions[descriptorIndex].InputRate = inputRate;
|
|
||||||
|
|
||||||
vertexBindingDescriptionChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int vbSize = vertexBuffer.Buffer.Size;
|
int vbSize = vertexBuffer.Buffer.Size;
|
||||||
|
|
||||||
@@ -1468,7 +1253,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ref var buffer = ref _vertexBuffers[_vertexBufferBindings[i]];
|
ref var buffer = ref _vertexBuffers[binding];
|
||||||
int oldScalarAlign = buffer.AttributeScalarAlignment;
|
int oldScalarAlign = buffer.AttributeScalarAlignment;
|
||||||
|
|
||||||
if (Gd.Capabilities.VertexBufferAlignment < 2 &&
|
if (Gd.Capabilities.VertexBufferAlignment < 2 &&
|
||||||
@@ -1485,7 +1270,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
vbSize,
|
vbSize,
|
||||||
vertexBuffer.Stride);
|
vertexBuffer.Stride);
|
||||||
|
|
||||||
buffer.BindVertexBuffer(Gd, Cbs, (uint)_vertexBufferBindings[i], ref _newState, _vertexBufferUpdater);
|
buffer.BindVertexBuffer(Gd, Cbs, (uint)binding, ref _newState, _vertexBufferUpdater);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1501,7 +1286,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
vbSize,
|
vbSize,
|
||||||
vertexBuffer.Stride);
|
vertexBuffer.Stride);
|
||||||
|
|
||||||
_vertexBuffersDirty |= 1UL << _vertexBufferBindings[i];
|
_vertexBuffersDirty |= 1UL << binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.AttributeScalarAlignment = oldScalarAlign;
|
buffer.AttributeScalarAlignment = oldScalarAlign;
|
||||||
@@ -1511,19 +1296,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_vertexBufferUpdater.Commit(Cbs);
|
_vertexBufferUpdater.Commit(Cbs);
|
||||||
|
|
||||||
if (_newState.VertexBindingDescriptionsCount != validCount)
|
|
||||||
{
|
|
||||||
_newState.VertexBindingDescriptionsCount = (uint)validCount;
|
_newState.VertexBindingDescriptionsCount = (uint)validCount;
|
||||||
vertexDescriptionCountChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vertexDescriptionCountChanged || vertexBindingDescriptionChanged)
|
|
||||||
{
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void SetViewports(ReadOnlySpan<Viewport> viewports, bool signalChange = true)
|
public void SetViewports(ReadOnlySpan<Viewport> viewports)
|
||||||
{
|
{
|
||||||
int maxViewports = Gd.Capabilities.SupportsMultiView ? Constants.MaxViewports : 1;
|
int maxViewports = Gd.Capabilities.SupportsMultiView ? Constants.MaxViewports : 1;
|
||||||
int count = Math.Min(maxViewports, viewports.Length);
|
int count = Math.Min(maxViewports, viewports.Length);
|
||||||
@@ -1548,16 +1325,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Clamp(viewport.DepthFar)));
|
Clamp(viewport.DepthFar)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_supportExtDynamic)
|
|
||||||
{
|
|
||||||
_newState.ViewportsCount = (uint)count;
|
_newState.ViewportsCount = (uint)count;
|
||||||
|
|
||||||
if (signalChange)
|
|
||||||
{
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SwapBuffer(Auto<DisposableBuffer> from, Auto<DisposableBuffer> to)
|
public void SwapBuffer(Auto<DisposableBuffer> from, Auto<DisposableBuffer> to)
|
||||||
{
|
{
|
||||||
@@ -1605,7 +1375,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
|
_vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
|
||||||
|
|
||||||
_descriptorSetUpdater.SignalCommandBufferChange();
|
_descriptorSetUpdater.SignalCommandBufferChange();
|
||||||
DynamicState.ForceAllDirty(Gd);
|
DynamicState.ForceAllDirty();
|
||||||
_currentPipelineHandle = 0;
|
_currentPipelineHandle = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1665,7 +1435,23 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsMainPipeline)
|
||||||
|
{
|
||||||
|
FramebufferParams?.ClearBindings();
|
||||||
|
}
|
||||||
|
|
||||||
FramebufferParams = new FramebufferParams(Device, colors, depthStencil);
|
FramebufferParams = new FramebufferParams(Device, colors, depthStencil);
|
||||||
|
|
||||||
|
if (IsMainPipeline)
|
||||||
|
{
|
||||||
|
FramebufferParams.AddBindings();
|
||||||
|
|
||||||
|
_newState.FeedbackLoopAspects = FeedbackLoopAspects.None;
|
||||||
|
_bindingBarriersDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_passWritesDepthStencil = false;
|
||||||
|
UpdatePassDepthStencil();
|
||||||
UpdatePipelineAttachmentFormats();
|
UpdatePipelineAttachmentFormats();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1732,11 +1518,86 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Gd.Barriers.Flush(Cbs, _program, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||||
|
|
||||||
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Compute);
|
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Compute);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool ChangeFeedbackLoop(FeedbackLoopAspects aspects)
|
||||||
|
{
|
||||||
|
// AMD Radeon RX GPUs + Qualcomm SoCs only
|
||||||
|
if ((Gd.Vendor == Vendor.Amd && Gd.GpuRenderer.Contains("RX")) || Gd.Vendor == Vendor.Qualcomm)
|
||||||
|
{
|
||||||
|
if (_feedbackLoop != aspects)
|
||||||
|
{
|
||||||
|
if (Gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
|
||||||
|
{
|
||||||
|
DynamicState.SetFeedbackLoop(aspects);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_newState.FeedbackLoopAspects = aspects;
|
||||||
|
}
|
||||||
|
|
||||||
|
_feedbackLoop = aspects;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private bool UpdateFeedbackLoop()
|
||||||
|
{
|
||||||
|
List<TextureView> hazards = _descriptorSetUpdater.FeedbackLoopHazards;
|
||||||
|
|
||||||
|
if ((hazards?.Count ?? 0) > 0)
|
||||||
|
{
|
||||||
|
FeedbackLoopAspects aspects = 0;
|
||||||
|
|
||||||
|
foreach (TextureView view in hazards)
|
||||||
|
{
|
||||||
|
// May need to enforce feedback loop layout here in the future.
|
||||||
|
// Though technically, it should always work with the general layout.
|
||||||
|
|
||||||
|
if (view.Info.Format.IsDepthOrStencil())
|
||||||
|
{
|
||||||
|
if (_passWritesDepthStencil)
|
||||||
|
{
|
||||||
|
// If depth/stencil isn't written in the pass, it doesn't count as a feedback loop.
|
||||||
|
|
||||||
|
aspects |= FeedbackLoopAspects.Depth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
aspects |= FeedbackLoopAspects.Color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ChangeFeedbackLoop(aspects);
|
||||||
|
}
|
||||||
|
else if (_feedbackLoop != 0)
|
||||||
|
{
|
||||||
|
return ChangeFeedbackLoop(FeedbackLoopAspects.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdatePassDepthStencil()
|
||||||
|
{
|
||||||
|
if (!RenderPassActive)
|
||||||
|
{
|
||||||
|
_passWritesDepthStencil = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stencil test being enabled doesn't necessarily mean a write, but it's not critical to check.
|
||||||
|
_passWritesDepthStencil |= (_newState.DepthTestEnable && _newState.DepthWriteEnable) || _newState.StencilTestEnable;
|
||||||
|
}
|
||||||
|
|
||||||
private bool RecreateGraphicsPipelineIfNeeded()
|
private bool RecreateGraphicsPipelineIfNeeded()
|
||||||
{
|
{
|
||||||
if (AutoFlush.ShouldFlushDraw(DrawCount))
|
if (AutoFlush.ShouldFlushDraw(DrawCount))
|
||||||
@@ -1778,7 +1639,15 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_vertexBufferUpdater.Commit(Cbs);
|
_vertexBufferUpdater.Commit(Cbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_graphicsStateDirty || Pbp != PipelineBindPoint.Graphics)
|
if (_bindingBarriersDirty)
|
||||||
|
{
|
||||||
|
// Stale barriers may have been activated by switching program. Emit any that are relevant.
|
||||||
|
_descriptorSetUpdater.InsertBindingBarriers(Cbs);
|
||||||
|
|
||||||
|
_bindingBarriersDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UpdateFeedbackLoop() || _graphicsStateDirty || Pbp != PipelineBindPoint.Graphics)
|
||||||
{
|
{
|
||||||
if (!CreatePipeline(PipelineBindPoint.Graphics))
|
if (!CreatePipeline(PipelineBindPoint.Graphics))
|
||||||
{
|
{
|
||||||
@@ -1787,17 +1656,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_graphicsStateDirty = false;
|
_graphicsStateDirty = false;
|
||||||
Pbp = PipelineBindPoint.Graphics;
|
Pbp = PipelineBindPoint.Graphics;
|
||||||
|
|
||||||
if (_bindingBarriersDirty)
|
|
||||||
{
|
|
||||||
// Stale barriers may have been activated by switching program. Emit any that are relevant.
|
|
||||||
_descriptorSetUpdater.InsertBindingBarriers(Cbs);
|
|
||||||
|
|
||||||
_bindingBarriersDirty = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Gd.Barriers.Flush(Cbs, _program, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||||
|
|
||||||
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Graphics);
|
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Graphics);
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using Silk.NET.Vulkan;
|
|||||||
using System;
|
using System;
|
||||||
using Format = Silk.NET.Vulkan.Format;
|
using Format = Silk.NET.Vulkan.Format;
|
||||||
using PolygonMode = Silk.NET.Vulkan.PolygonMode;
|
using PolygonMode = Silk.NET.Vulkan.PolygonMode;
|
||||||
using PrimitiveTopology = Ryujinx.Graphics.GAL.PrimitiveTopology;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
@@ -161,38 +160,35 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public static PipelineState ToVulkanPipelineState(this ProgramPipelineState state, VulkanRenderer gd)
|
public static PipelineState ToVulkanPipelineState(this ProgramPipelineState state, VulkanRenderer gd)
|
||||||
{
|
{
|
||||||
var extendedDynamicState2 = gd.Capabilities.SupportsExtendedDynamicState2;
|
|
||||||
var extendedDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
|
|
||||||
|
|
||||||
PipelineState pipeline = new();
|
PipelineState pipeline = new();
|
||||||
pipeline.Initialize(gd.Capabilities);
|
pipeline.Initialize();
|
||||||
|
|
||||||
// It is assumed that Dynamic State is enabled when this conversion is used.
|
// It is assumed that Dynamic State is enabled when this conversion is used.
|
||||||
|
|
||||||
|
pipeline.CullMode = state.CullEnable ? state.CullMode.Convert() : CullModeFlags.None;
|
||||||
|
|
||||||
pipeline.DepthBoundsTestEnable = false; // Not implemented.
|
pipeline.DepthBoundsTestEnable = false; // Not implemented.
|
||||||
|
|
||||||
pipeline.DepthClampEnable = state.DepthClampEnable;
|
pipeline.DepthClampEnable = state.DepthClampEnable;
|
||||||
|
|
||||||
pipeline.AlphaToCoverageEnable = state.AlphaToCoverageEnable;
|
|
||||||
pipeline.AlphaToOneEnable = state.AlphaToOneEnable;
|
|
||||||
|
|
||||||
pipeline.DepthMode = state.DepthMode == DepthMode.MinusOneToOne;
|
|
||||||
|
|
||||||
pipeline.HasDepthStencil = state.DepthStencilEnable;
|
|
||||||
|
|
||||||
pipeline.PolygonMode = PolygonMode.Fill; // Not implemented.
|
|
||||||
|
|
||||||
pipeline.Topology = gd.TopologyRemap(state.Topology).Convert();
|
|
||||||
|
|
||||||
if (!extendedDynamicState)
|
|
||||||
{
|
|
||||||
pipeline.DepthCompareOp = state.DepthTest.Func.Convert();
|
|
||||||
pipeline.CullMode = state.CullMode.Convert();
|
|
||||||
|
|
||||||
pipeline.DepthTestEnable = state.DepthTest.TestEnable;
|
pipeline.DepthTestEnable = state.DepthTest.TestEnable;
|
||||||
pipeline.DepthWriteEnable = state.DepthTest.WriteEnable;
|
pipeline.DepthWriteEnable = state.DepthTest.WriteEnable;
|
||||||
|
pipeline.DepthCompareOp = state.DepthTest.Func.Convert();
|
||||||
|
pipeline.DepthMode = state.DepthMode == DepthMode.MinusOneToOne;
|
||||||
|
|
||||||
pipeline.FrontFace = state.FrontFace.Convert();
|
pipeline.FrontFace = state.FrontFace.Convert();
|
||||||
|
|
||||||
|
pipeline.HasDepthStencil = state.DepthStencilEnable;
|
||||||
|
pipeline.LineWidth = state.LineWidth;
|
||||||
|
pipeline.LogicOpEnable = state.LogicOpEnable;
|
||||||
|
pipeline.LogicOp = state.LogicOp.Convert();
|
||||||
|
|
||||||
|
pipeline.PatchControlPoints = state.PatchControlPoints;
|
||||||
|
pipeline.PolygonMode = PolygonMode.Fill; // Not implemented.
|
||||||
|
pipeline.PrimitiveRestartEnable = state.PrimitiveRestartEnable;
|
||||||
|
pipeline.RasterizerDiscardEnable = state.RasterizerDiscard;
|
||||||
|
pipeline.SamplesCount = (uint)state.SamplesCount;
|
||||||
|
|
||||||
if (gd.Capabilities.SupportsMultiView)
|
if (gd.Capabilities.SupportsMultiView)
|
||||||
{
|
{
|
||||||
pipeline.ScissorsCount = Constants.MaxViewports;
|
pipeline.ScissorsCount = Constants.MaxViewports;
|
||||||
@@ -204,7 +200,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
pipeline.ViewportsCount = 1;
|
pipeline.ViewportsCount = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline.StencilTestEnable = state.StencilTest.TestEnable;
|
pipeline.DepthBiasEnable = state.BiasEnable != 0;
|
||||||
|
|
||||||
|
// Stencil masks and ref are dynamic, so are 0 in the Vulkan pipeline.
|
||||||
|
|
||||||
pipeline.StencilFrontFailOp = state.StencilTest.FrontSFail.Convert();
|
pipeline.StencilFrontFailOp = state.StencilTest.FrontSFail.Convert();
|
||||||
pipeline.StencilFrontPassOp = state.StencilTest.FrontDpPass.Convert();
|
pipeline.StencilFrontPassOp = state.StencilTest.FrontDpPass.Convert();
|
||||||
@@ -215,29 +213,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
pipeline.StencilBackPassOp = state.StencilTest.BackDpPass.Convert();
|
pipeline.StencilBackPassOp = state.StencilTest.BackDpPass.Convert();
|
||||||
pipeline.StencilBackDepthFailOp = state.StencilTest.BackDpFail.Convert();
|
pipeline.StencilBackDepthFailOp = state.StencilTest.BackDpFail.Convert();
|
||||||
pipeline.StencilBackCompareOp = state.StencilTest.BackFunc.Convert();
|
pipeline.StencilBackCompareOp = state.StencilTest.BackFunc.Convert();
|
||||||
}
|
|
||||||
|
|
||||||
if (!extendedDynamicState2.ExtendedDynamicState2)
|
pipeline.StencilTestEnable = state.StencilTest.TestEnable;
|
||||||
{
|
|
||||||
pipeline.PrimitiveRestartEnable = state.PrimitiveRestartEnable;
|
|
||||||
pipeline.RasterizerDiscardEnable = state.RasterizerDiscard;
|
|
||||||
pipeline.DepthBiasEnable = (state.BiasEnable != 0) &&
|
|
||||||
(state.DepthBiasFactor != 0 && state.DepthBiasUnits != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!extendedDynamicState2.ExtendedDynamicState2LogicOp)
|
pipeline.Topology = gd.TopologyRemap(state.Topology).Convert();
|
||||||
{
|
|
||||||
pipeline.LogicOp = state.LogicOp.Convert();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!extendedDynamicState2.ExtendedDynamicState2PatchControlPoints)
|
|
||||||
{
|
|
||||||
pipeline.PatchControlPoints = state.PatchControlPoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline.SamplesCount = (uint)state.SamplesCount;
|
|
||||||
|
|
||||||
pipeline.LogicOpEnable = state.LogicOpEnable;
|
|
||||||
|
|
||||||
int vaCount = Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount);
|
int vaCount = Math.Min(Constants.MaxVertexAttributes, state.VertexAttribCount);
|
||||||
int vbCount = Math.Min(Constants.MaxVertexBuffers, state.VertexBufferCount);
|
int vbCount = Math.Min(Constants.MaxVertexBuffers, state.VertexBufferCount);
|
||||||
@@ -262,7 +241,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
|
|
||||||
int descriptorIndex = 1;
|
int descriptorIndex = 1;
|
||||||
pipeline.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, extendedDynamicState && (!gd.IsMoltenVk || gd.SupportsMTL31) ? null : 0, VertexInputRate.Vertex);
|
pipeline.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, 0, VertexInputRate.Vertex);
|
||||||
|
|
||||||
for (int i = 0; i < vbCount; i++)
|
for (int i = 0; i < vbCount; i++)
|
||||||
{
|
{
|
||||||
@@ -282,7 +261,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
// TODO: Support divisor > 1
|
// TODO: Support divisor > 1
|
||||||
pipeline.Internal.VertexBindingDescriptions[descriptorIndex++] = new VertexInputBindingDescription(
|
pipeline.Internal.VertexBindingDescriptions[descriptorIndex++] = new VertexInputBindingDescription(
|
||||||
(uint)i + 1,
|
(uint)i + 1,
|
||||||
extendedDynamicState && (!gd.IsMoltenVk || gd.SupportsMTL31) ? null : (uint)alignedStride,
|
(uint)alignedStride,
|
||||||
inputRate);
|
inputRate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using Ryujinx.Common.Memory;
|
|||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using Silk.NET.Vulkan.Extensions.EXT;
|
using Silk.NET.Vulkan.Extensions.EXT;
|
||||||
using System;
|
using System;
|
||||||
using System.Numerics;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
@@ -11,7 +10,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private float _depthBiasSlopeFactor;
|
private float _depthBiasSlopeFactor;
|
||||||
private float _depthBiasConstantFactor;
|
private float _depthBiasConstantFactor;
|
||||||
private float _depthBiasClamp;
|
private float _depthBiasClamp;
|
||||||
private bool _depthBiasEnable;
|
|
||||||
|
|
||||||
public int ScissorsCount;
|
public int ScissorsCount;
|
||||||
private Array16<Rect2D> _scissors;
|
private Array16<Rect2D> _scissors;
|
||||||
@@ -23,41 +21,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private uint _frontWriteMask;
|
private uint _frontWriteMask;
|
||||||
private uint _frontReference;
|
private uint _frontReference;
|
||||||
|
|
||||||
private StencilOp _backFailOp;
|
|
||||||
private StencilOp _backPassOp;
|
|
||||||
private StencilOp _backDepthFailOp;
|
|
||||||
private CompareOp _backCompareOp;
|
|
||||||
private StencilOp _frontFailOp;
|
|
||||||
private StencilOp _frontPassOp;
|
|
||||||
private StencilOp _frontDepthFailOp;
|
|
||||||
private CompareOp _frontCompareOp;
|
|
||||||
|
|
||||||
private float _lineWidth;
|
|
||||||
|
|
||||||
public bool StencilTestEnable;
|
|
||||||
|
|
||||||
public bool DepthTestEnable;
|
|
||||||
public bool DepthWriteEnable;
|
|
||||||
private CompareOp _depthCompareOp;
|
|
||||||
|
|
||||||
private Array4<float> _blendConstants;
|
private Array4<float> _blendConstants;
|
||||||
|
|
||||||
|
private FeedbackLoopAspects _feedbackLoopAspects;
|
||||||
|
|
||||||
public uint ViewportsCount;
|
public uint ViewportsCount;
|
||||||
public Array16<Viewport> Viewports;
|
public Array16<Viewport> Viewports;
|
||||||
|
|
||||||
public CullModeFlags CullMode;
|
|
||||||
private FrontFace _frontFace;
|
|
||||||
|
|
||||||
private bool _discard;
|
|
||||||
|
|
||||||
private LogicOp _logicOp;
|
|
||||||
|
|
||||||
private uint _patchControlPoints;
|
|
||||||
|
|
||||||
public PrimitiveTopology Topology;
|
|
||||||
|
|
||||||
private bool _primitiveRestartEnable;
|
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
private enum DirtyFlags
|
private enum DirtyFlags
|
||||||
{
|
{
|
||||||
@@ -67,21 +37,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Scissor = 1 << 2,
|
Scissor = 1 << 2,
|
||||||
Stencil = 1 << 3,
|
Stencil = 1 << 3,
|
||||||
Viewport = 1 << 4,
|
Viewport = 1 << 4,
|
||||||
CullMode = 1 << 5,
|
FeedbackLoop = 1 << 5,
|
||||||
FrontFace = 1 << 6,
|
All = Blend | DepthBias | Scissor | Stencil | Viewport | FeedbackLoop,
|
||||||
DepthTestBool = 1 << 7,
|
|
||||||
DepthTestCompareOp = 1 << 8,
|
|
||||||
StencilTestEnableAndStencilOp = 1 << 9,
|
|
||||||
LineWidth = 1 << 10,
|
|
||||||
RasterDiscard = 1 << 11,
|
|
||||||
LogicOp = 1 << 12,
|
|
||||||
PatchControlPoints = 1 << 13,
|
|
||||||
PrimitiveRestart = 1 << 14,
|
|
||||||
PrimitiveTopology = 1 << 15,
|
|
||||||
DepthBiasEnable = 1 << 16,
|
|
||||||
Standard = Blend | DepthBias | Scissor | Stencil | Viewport,
|
|
||||||
Extended = CullMode | FrontFace | DepthTestBool | DepthTestCompareOp | StencilTestEnableAndStencilOp | PrimitiveTopology,
|
|
||||||
Extended2 = RasterDiscard | PrimitiveRestart | DepthBiasEnable,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DirtyFlags _dirty;
|
private DirtyFlags _dirty;
|
||||||
@@ -92,6 +49,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_blendConstants[1] = g;
|
_blendConstants[1] = g;
|
||||||
_blendConstants[2] = b;
|
_blendConstants[2] = b;
|
||||||
_blendConstants[3] = a;
|
_blendConstants[3] = a;
|
||||||
|
|
||||||
_dirty |= DirtyFlags.Blend;
|
_dirty |= DirtyFlags.Blend;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,64 +62,15 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_dirty |= DirtyFlags.DepthBias;
|
_dirty |= DirtyFlags.DepthBias;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetDepthBiasEnable(bool enable)
|
|
||||||
{
|
|
||||||
_depthBiasEnable = enable;
|
|
||||||
_dirty |= DirtyFlags.DepthBiasEnable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetScissor(int index, Rect2D scissor)
|
public void SetScissor(int index, Rect2D scissor)
|
||||||
{
|
{
|
||||||
_scissors[index] = scissor;
|
_scissors[index] = scissor;
|
||||||
|
|
||||||
_dirty |= DirtyFlags.Scissor;
|
_dirty |= DirtyFlags.Scissor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetDepthTestBool(bool testEnable, bool writeEnable)
|
public void SetStencilMasks(
|
||||||
{
|
uint backCompareMask,
|
||||||
DepthTestEnable = testEnable;
|
|
||||||
DepthWriteEnable = writeEnable;
|
|
||||||
_dirty |= DirtyFlags.DepthTestBool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetDepthTestCompareOp(CompareOp depthTestOp)
|
|
||||||
{
|
|
||||||
_depthCompareOp = depthTestOp;
|
|
||||||
_dirty |= DirtyFlags.DepthTestCompareOp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetStencilTestandOp(
|
|
||||||
StencilOp backFailOp,
|
|
||||||
StencilOp backPassOp,
|
|
||||||
StencilOp backDepthFailOp,
|
|
||||||
CompareOp backCompareOp,
|
|
||||||
StencilOp frontFailOp,
|
|
||||||
StencilOp frontPassOp,
|
|
||||||
StencilOp frontDepthFailOp,
|
|
||||||
CompareOp frontCompareOp,
|
|
||||||
bool stencilTestEnable)
|
|
||||||
{
|
|
||||||
_backFailOp = backFailOp;
|
|
||||||
_backPassOp = backPassOp;
|
|
||||||
_backDepthFailOp = backDepthFailOp;
|
|
||||||
_backCompareOp = backCompareOp;
|
|
||||||
_frontFailOp = frontFailOp;
|
|
||||||
_frontPassOp = frontPassOp;
|
|
||||||
_frontDepthFailOp = frontDepthFailOp;
|
|
||||||
_frontCompareOp = frontCompareOp;
|
|
||||||
|
|
||||||
StencilTestEnable = stencilTestEnable;
|
|
||||||
|
|
||||||
_dirty |= DirtyFlags.StencilTestEnableAndStencilOp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetStencilTest(bool stencilTestEnable)
|
|
||||||
{
|
|
||||||
StencilTestEnable = stencilTestEnable;
|
|
||||||
|
|
||||||
_dirty |= DirtyFlags.StencilTestEnableAndStencilOp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetStencilMask(uint backCompareMask,
|
|
||||||
uint backWriteMask,
|
uint backWriteMask,
|
||||||
uint backReference,
|
uint backReference,
|
||||||
uint frontCompareMask,
|
uint frontCompareMask,
|
||||||
@@ -174,180 +83,72 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_frontCompareMask = frontCompareMask;
|
_frontCompareMask = frontCompareMask;
|
||||||
_frontWriteMask = frontWriteMask;
|
_frontWriteMask = frontWriteMask;
|
||||||
_frontReference = frontReference;
|
_frontReference = frontReference;
|
||||||
|
|
||||||
_dirty |= DirtyFlags.Stencil;
|
_dirty |= DirtyFlags.Stencil;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetViewport(int index, Viewport viewport)
|
public void SetViewport(int index, Viewport viewport)
|
||||||
{
|
{
|
||||||
Viewports[index] = viewport;
|
Viewports[index] = viewport;
|
||||||
|
|
||||||
_dirty |= DirtyFlags.Viewport;
|
_dirty |= DirtyFlags.Viewport;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetViewports(ref Array16<Viewport> viewports, uint viewportsCount)
|
public void SetViewports(ref Array16<Viewport> viewports, uint viewportsCount)
|
||||||
{
|
|
||||||
if (!Viewports.Equals(viewports) || ViewportsCount != viewportsCount)
|
|
||||||
{
|
{
|
||||||
Viewports = viewports;
|
Viewports = viewports;
|
||||||
ViewportsCount = viewportsCount;
|
ViewportsCount = viewportsCount;
|
||||||
|
|
||||||
if (ViewportsCount != 0)
|
if (ViewportsCount != 0)
|
||||||
{
|
{
|
||||||
_dirty |= DirtyFlags.Viewport;
|
_dirty |= DirtyFlags.Viewport;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetFeedbackLoop(FeedbackLoopAspects aspects)
|
||||||
|
{
|
||||||
|
_feedbackLoopAspects = aspects;
|
||||||
|
|
||||||
|
_dirty |= DirtyFlags.FeedbackLoop;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCullMode(CullModeFlags cullMode)
|
public void ForceAllDirty()
|
||||||
{
|
{
|
||||||
CullMode = cullMode;
|
_dirty = DirtyFlags.All;
|
||||||
_dirty |= DirtyFlags.CullMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetFrontFace(FrontFace frontFace)
|
|
||||||
{
|
|
||||||
_frontFace = frontFace;
|
|
||||||
_dirty |= DirtyFlags.FrontFace;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetLineWidth(float width)
|
|
||||||
{
|
|
||||||
_lineWidth = width;
|
|
||||||
_dirty |= DirtyFlags.LineWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetRasterizerDiscard(bool discard)
|
|
||||||
{
|
|
||||||
_discard = discard;
|
|
||||||
_dirty |= DirtyFlags.RasterDiscard;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetPrimitiveRestartEnable(bool primitiveRestart)
|
|
||||||
{
|
|
||||||
_primitiveRestartEnable = primitiveRestart;
|
|
||||||
_dirty |= DirtyFlags.PrimitiveRestart;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetPrimitiveTopology(PrimitiveTopology primitiveTopology)
|
|
||||||
{
|
|
||||||
Topology = primitiveTopology;
|
|
||||||
_dirty |= DirtyFlags.PrimitiveTopology;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetLogicOp(LogicOp op)
|
|
||||||
{
|
|
||||||
_logicOp = op;
|
|
||||||
_dirty |= DirtyFlags.LogicOp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetPatchControlPoints(uint points)
|
|
||||||
{
|
|
||||||
_patchControlPoints = points;
|
|
||||||
_dirty |= DirtyFlags.PatchControlPoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ForceAllDirty(VulkanRenderer gd)
|
|
||||||
{
|
|
||||||
_dirty = DirtyFlags.Standard;
|
|
||||||
|
|
||||||
if (gd.Capabilities.SupportsExtendedDynamicState)
|
|
||||||
{
|
|
||||||
_dirty |= DirtyFlags.Extended;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2)
|
|
||||||
{
|
|
||||||
_dirty |= DirtyFlags.Extended2;
|
|
||||||
|
|
||||||
if (gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2LogicOp)
|
|
||||||
{
|
|
||||||
_dirty |= DirtyFlags.LogicOp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints)
|
|
||||||
{
|
|
||||||
_dirty |= DirtyFlags.PatchControlPoints;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gd.IsMoltenVk)
|
|
||||||
{
|
|
||||||
_dirty |= DirtyFlags.LineWidth;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReplayIfDirty(VulkanRenderer gd, CommandBuffer commandBuffer)
|
public void ReplayIfDirty(VulkanRenderer gd, CommandBuffer commandBuffer)
|
||||||
{
|
{
|
||||||
if (_dirty == DirtyFlags.None)
|
Vk api = gd.Api;
|
||||||
|
|
||||||
|
if (_dirty.HasFlag(DirtyFlags.Blend))
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var api = gd.Api;
|
|
||||||
var extendedStateApi = gd.ExtendedDynamicStateApi;
|
|
||||||
var extendedState2Api = gd.ExtendedDynamicState2Api;
|
|
||||||
|
|
||||||
DirtyFlags dirtyFlags = _dirty;
|
|
||||||
|
|
||||||
while (dirtyFlags != DirtyFlags.None)
|
|
||||||
{
|
|
||||||
int bitIndex = BitOperations.TrailingZeroCount((uint)dirtyFlags);
|
|
||||||
DirtyFlags currentFlag = (DirtyFlags)(1 << bitIndex);
|
|
||||||
|
|
||||||
switch (currentFlag)
|
|
||||||
{
|
|
||||||
case DirtyFlags.Blend:
|
|
||||||
RecordBlend(api, commandBuffer);
|
RecordBlend(api, commandBuffer);
|
||||||
break;
|
|
||||||
case DirtyFlags.DepthBias:
|
|
||||||
RecordDepthBias(api, commandBuffer);
|
|
||||||
break;
|
|
||||||
case DirtyFlags.Scissor:
|
|
||||||
RecordScissor(gd, commandBuffer);
|
|
||||||
break;
|
|
||||||
case DirtyFlags.Stencil:
|
|
||||||
RecordStencil(api, commandBuffer);
|
|
||||||
break;
|
|
||||||
case DirtyFlags.Viewport:
|
|
||||||
RecordViewport(gd, commandBuffer);
|
|
||||||
break;
|
|
||||||
case DirtyFlags.CullMode:
|
|
||||||
RecordCullMode(extendedStateApi, commandBuffer);
|
|
||||||
break;
|
|
||||||
case DirtyFlags.FrontFace:
|
|
||||||
RecordFrontFace(extendedStateApi, commandBuffer);
|
|
||||||
break;
|
|
||||||
case DirtyFlags.DepthTestBool:
|
|
||||||
RecordDepthTestBool(extendedStateApi, commandBuffer);
|
|
||||||
break;
|
|
||||||
case DirtyFlags.DepthTestCompareOp:
|
|
||||||
RecordDepthTestCompareOp(extendedStateApi, commandBuffer);
|
|
||||||
break;
|
|
||||||
case DirtyFlags.StencilTestEnableAndStencilOp:
|
|
||||||
RecordStencilTestAndOp(extendedStateApi, commandBuffer);
|
|
||||||
break;
|
|
||||||
case DirtyFlags.LineWidth:
|
|
||||||
RecordLineWidth(api, commandBuffer);
|
|
||||||
break;
|
|
||||||
case DirtyFlags.RasterDiscard:
|
|
||||||
RecordRasterizationDiscard(extendedState2Api, commandBuffer);
|
|
||||||
break;
|
|
||||||
case DirtyFlags.LogicOp:
|
|
||||||
RecordLogicOp(extendedState2Api, commandBuffer);
|
|
||||||
break;
|
|
||||||
case DirtyFlags.PatchControlPoints:
|
|
||||||
RecordPatchControlPoints(extendedState2Api, commandBuffer);
|
|
||||||
break;
|
|
||||||
case DirtyFlags.PrimitiveRestart:
|
|
||||||
RecordPrimitiveRestartEnable(gd, commandBuffer);
|
|
||||||
break;
|
|
||||||
case DirtyFlags.PrimitiveTopology:
|
|
||||||
RecordPrimitiveTopology(extendedStateApi, commandBuffer);
|
|
||||||
break;
|
|
||||||
case DirtyFlags.DepthBiasEnable:
|
|
||||||
RecordDepthBiasEnable(extendedState2Api, commandBuffer);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dirtyFlags &= ~currentFlag;
|
if (_dirty.HasFlag(DirtyFlags.DepthBias))
|
||||||
|
{
|
||||||
|
RecordDepthBias(api, commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_dirty.HasFlag(DirtyFlags.Scissor))
|
||||||
|
{
|
||||||
|
RecordScissor(api, commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_dirty.HasFlag(DirtyFlags.Stencil))
|
||||||
|
{
|
||||||
|
RecordStencilMasks(api, commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_dirty.HasFlag(DirtyFlags.Viewport))
|
||||||
|
{
|
||||||
|
RecordViewport(api, commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_dirty.HasFlag(DirtyFlags.FeedbackLoop) && gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
|
||||||
|
{
|
||||||
|
RecordFeedbackLoop(gd.DynamicFeedbackLoopApi, commandBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
_dirty = DirtyFlags.None;
|
_dirty = DirtyFlags.None;
|
||||||
@@ -363,27 +164,15 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
api.CmdSetDepthBias(commandBuffer, _depthBiasConstantFactor, _depthBiasClamp, _depthBiasSlopeFactor);
|
api.CmdSetDepthBias(commandBuffer, _depthBiasConstantFactor, _depthBiasClamp, _depthBiasSlopeFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly void RecordDepthBiasEnable(ExtExtendedDynamicState2 gd, CommandBuffer commandBuffer)
|
private void RecordScissor(Vk api, CommandBuffer commandBuffer)
|
||||||
{
|
|
||||||
gd.CmdSetDepthBiasEnable(commandBuffer, _depthBiasEnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RecordScissor(VulkanRenderer gd, CommandBuffer commandBuffer)
|
|
||||||
{
|
{
|
||||||
if (ScissorsCount != 0)
|
if (ScissorsCount != 0)
|
||||||
{
|
{
|
||||||
if (gd.Capabilities.SupportsExtendedDynamicState)
|
api.CmdSetScissor(commandBuffer, 0, (uint)ScissorsCount, _scissors.AsSpan());
|
||||||
{
|
|
||||||
gd.ExtendedDynamicStateApi.CmdSetScissorWithCount(commandBuffer, (uint)ScissorsCount, _scissors.AsSpan());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gd.Api.CmdSetScissor(commandBuffer, 0, (uint)ScissorsCount, _scissors.AsSpan());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly void RecordStencil(Vk api, CommandBuffer commandBuffer)
|
private readonly void RecordStencilMasks(Vk api, CommandBuffer commandBuffer)
|
||||||
{
|
{
|
||||||
api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backCompareMask);
|
api.CmdSetStencilCompareMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backCompareMask);
|
||||||
api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backWriteMask);
|
api.CmdSetStencilWriteMask(commandBuffer, StencilFaceFlags.FaceBackBit, _backWriteMask);
|
||||||
@@ -393,107 +182,24 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontReference);
|
api.CmdSetStencilReference(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly void RecordStencilTestAndOp(ExtExtendedDynamicState api, CommandBuffer commandBuffer)
|
private void RecordViewport(Vk api, CommandBuffer commandBuffer)
|
||||||
{
|
{
|
||||||
api.CmdSetStencilTestEnable(commandBuffer, StencilTestEnable);
|
if (ViewportsCount != 0)
|
||||||
|
|
||||||
api.CmdSetStencilOp(commandBuffer, StencilFaceFlags.FaceBackBit, _backFailOp, _backPassOp, _backDepthFailOp, _backCompareOp);
|
|
||||||
api.CmdSetStencilOp(commandBuffer, StencilFaceFlags.FaceFrontBit, _frontFailOp, _frontPassOp, _frontDepthFailOp, _frontCompareOp);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RecordViewport(VulkanRenderer gd, CommandBuffer commandBuffer)
|
|
||||||
{
|
{
|
||||||
if (ViewportsCount == 0)
|
api.CmdSetViewport(commandBuffer, 0, ViewportsCount, Viewports.AsSpan());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly void RecordFeedbackLoop(ExtAttachmentFeedbackLoopDynamicState api, CommandBuffer commandBuffer)
|
||||||
{
|
{
|
||||||
return;
|
ImageAspectFlags aspects = (_feedbackLoopAspects & FeedbackLoopAspects.Color) != 0 ? ImageAspectFlags.ColorBit : 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (gd.Capabilities.SupportsExtendedDynamicState)
|
if ((_feedbackLoopAspects & FeedbackLoopAspects.Depth) != 0)
|
||||||
{
|
{
|
||||||
gd.ExtendedDynamicStateApi.CmdSetViewportWithCount(commandBuffer, ViewportsCount, Viewports.AsSpan());
|
aspects |= ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gd.Api.CmdSetViewport(commandBuffer, 0, ViewportsCount, Viewports.AsSpan());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly void RecordCullMode(ExtExtendedDynamicState api, CommandBuffer commandBuffer)
|
api.CmdSetAttachmentFeedbackLoopEnable(commandBuffer, aspects);
|
||||||
{
|
|
||||||
api.CmdSetCullMode(commandBuffer, CullMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly void RecordFrontFace(ExtExtendedDynamicState api, CommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
api.CmdSetFrontFace(commandBuffer, _frontFace);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly void RecordDepthTestBool(ExtExtendedDynamicState api, CommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
api.CmdSetDepthTestEnable(commandBuffer, DepthTestEnable);
|
|
||||||
|
|
||||||
api.CmdSetDepthWriteEnable(commandBuffer, DepthWriteEnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly void RecordDepthTestCompareOp(ExtExtendedDynamicState api, CommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
api.CmdSetDepthCompareOp(commandBuffer, _depthCompareOp);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly void RecordRasterizationDiscard(ExtExtendedDynamicState2 extendedDynamicState2Api, CommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
extendedDynamicState2Api.CmdSetRasterizerDiscardEnable(commandBuffer, _discard);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly void RecordPrimitiveRestartEnable(VulkanRenderer gd, CommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
bool primitiveRestartEnable = _primitiveRestartEnable;
|
|
||||||
|
|
||||||
bool topologySupportsRestart;
|
|
||||||
|
|
||||||
if (gd.Capabilities.SupportsPrimitiveTopologyListRestart)
|
|
||||||
{
|
|
||||||
topologySupportsRestart = gd.Capabilities.SupportsPrimitiveTopologyPatchListRestart ||
|
|
||||||
Topology != PrimitiveTopology.PatchList;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
topologySupportsRestart = Topology == PrimitiveTopology.LineStrip ||
|
|
||||||
Topology == PrimitiveTopology.TriangleStrip ||
|
|
||||||
Topology == PrimitiveTopology.TriangleFan ||
|
|
||||||
Topology == PrimitiveTopology.LineStripWithAdjacency ||
|
|
||||||
Topology == PrimitiveTopology.TriangleStripWithAdjacency;
|
|
||||||
}
|
|
||||||
|
|
||||||
primitiveRestartEnable &= topologySupportsRestart;
|
|
||||||
|
|
||||||
// Cannot disable primitiveRestartEnable for these Topologies on MacOS.
|
|
||||||
if (gd.IsMoltenVk)
|
|
||||||
{
|
|
||||||
primitiveRestartEnable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
gd.ExtendedDynamicState2Api.CmdSetPrimitiveRestartEnable(commandBuffer, primitiveRestartEnable);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly void RecordPrimitiveTopology(ExtExtendedDynamicState extendedDynamicStateApi, CommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
extendedDynamicStateApi.CmdSetPrimitiveTopology(commandBuffer, Topology);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly void RecordLogicOp(ExtExtendedDynamicState2 extendedDynamicState2Api, CommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
extendedDynamicState2Api.CmdSetLogicOp(commandBuffer, _logicOp);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly void RecordPatchControlPoints(ExtExtendedDynamicState2 extendedDynamicState2Api, CommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
extendedDynamicState2Api.CmdSetPatchControlPoints(commandBuffer, _patchControlPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly void RecordLineWidth(Vk api, CommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
api.CmdSetLineWidth(commandBuffer, _lineWidth);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_activeBufferMirrors = [];
|
_activeBufferMirrors = [];
|
||||||
|
|
||||||
CommandBuffer = (Cbs = gd.CommandBufferPool.Rent()).CommandBuffer;
|
CommandBuffer = (Cbs = gd.CommandBufferPool.Rent()).CommandBuffer;
|
||||||
|
|
||||||
|
IsMainPipeline = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CopyPendingQuery()
|
private void CopyPendingQuery()
|
||||||
|
|||||||
@@ -8,16 +8,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRenderTarget(TextureView view, uint width, uint height, bool signalChange = true)
|
public void SetRenderTarget(TextureView view, uint width, uint height)
|
||||||
{
|
{
|
||||||
CreateFramebuffer(view, width, height);
|
CreateFramebuffer(view, width, height);
|
||||||
CreateRenderPass();
|
CreateRenderPass();
|
||||||
|
|
||||||
if (signalChange)
|
|
||||||
{
|
|
||||||
SignalStateChange();
|
SignalStateChange();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void CreateFramebuffer(TextureView view, uint width, uint height)
|
private void CreateFramebuffer(TextureView view, uint width, uint height)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,236 +7,302 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
struct PipelineState : IDisposable
|
struct PipelineState : IDisposable
|
||||||
{
|
{
|
||||||
private const int MaxDynamicStatesCount = 23;
|
private const int MaxDynamicStatesCount = 9;
|
||||||
|
|
||||||
public PipelineUid Internal;
|
public PipelineUid Internal;
|
||||||
|
|
||||||
public PolygonMode PolygonMode
|
public float LineWidth
|
||||||
{
|
{
|
||||||
readonly get => (PolygonMode)((Internal.Id0 >> 0) & 0x3FFFFFFF);
|
readonly get => BitConverter.Int32BitsToSingle((int)((Internal.Id0 >> 0) & 0xFFFFFFFF));
|
||||||
set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFFFC0000000) | ((ulong)value << 0);
|
set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFFF00000000) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint StagesCount
|
public float DepthBiasClamp
|
||||||
{
|
{
|
||||||
readonly get => (byte)((Internal.Id0 >> 30) & 0xFF);
|
readonly get => BitConverter.Int32BitsToSingle((int)((Internal.Id0 >> 32) & 0xFFFFFFFF));
|
||||||
set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFC03FFFFFFF) | ((ulong)value << 30);
|
set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFFF) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint VertexAttributeDescriptionsCount
|
public float DepthBiasConstantFactor
|
||||||
{
|
{
|
||||||
readonly get => (byte)((Internal.Id0 >> 38) & 0xFF);
|
readonly get => BitConverter.Int32BitsToSingle((int)((Internal.Id1 >> 0) & 0xFFFFFFFF));
|
||||||
set => Internal.Id0 = (Internal.Id0 & 0xFFFFC03FFFFFFFFF) | ((ulong)value << 38);
|
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFF00000000) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint VertexBindingDescriptionsCount
|
public float DepthBiasSlopeFactor
|
||||||
{
|
{
|
||||||
readonly get => (byte)((Internal.Id0 >> 46) & 0xFF);
|
readonly get => BitConverter.Int32BitsToSingle((int)((Internal.Id1 >> 32) & 0xFFFFFFFF));
|
||||||
set => Internal.Id0 = (Internal.Id0 & 0xFFC03FFFFFFFFFFF) | ((ulong)value << 46);
|
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFF) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint ViewportsCount
|
public uint StencilFrontCompareMask
|
||||||
{
|
|
||||||
readonly get => (byte)((Internal.Id0 >> 54) & 0xFF);
|
|
||||||
set => Internal.Id0 = (Internal.Id0 & 0xC03FFFFFFFFFFFFF) | ((ulong)value << 54);
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint ScissorsCount
|
|
||||||
{
|
|
||||||
readonly get => (byte)((Internal.Id1 >> 0) & 0xFF);
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFFFFFFFF00) | ((ulong)value << 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint ColorBlendAttachmentStateCount
|
|
||||||
{
|
|
||||||
readonly get => (byte)((Internal.Id1 >> 8) & 0xFF);
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFFFFFF00FF) | ((ulong)value << 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PrimitiveTopology Topology
|
|
||||||
{
|
|
||||||
readonly get => (PrimitiveTopology)((Internal.Id1 >> 16) & 0xF);
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFFFFF0FFFF) | ((ulong)value << 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LogicOp LogicOp
|
|
||||||
{
|
|
||||||
readonly get => (LogicOp)((Internal.Id1 >> 20) & 0xF);
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFFFF0FFFFF) | ((ulong)value << 20);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompareOp DepthCompareOp
|
|
||||||
{
|
|
||||||
readonly get => (CompareOp)((Internal.Id1 >> 24) & 0x7);
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFFF8FFFFFF) | ((ulong)value << 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StencilOp StencilFrontFailOp
|
|
||||||
{
|
|
||||||
readonly get => (StencilOp)((Internal.Id1 >> 27) & 0x7);
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFFC7FFFFFF) | ((ulong)value << 27);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StencilOp StencilFrontPassOp
|
|
||||||
{
|
|
||||||
readonly get => (StencilOp)((Internal.Id1 >> 30) & 0x7);
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFE3FFFFFFF) | ((ulong)value << 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StencilOp StencilFrontDepthFailOp
|
|
||||||
{
|
|
||||||
readonly get => (StencilOp)((Internal.Id1 >> 33) & 0x7);
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFF1FFFFFFFF) | ((ulong)value << 33);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompareOp StencilFrontCompareOp
|
|
||||||
{
|
|
||||||
readonly get => (CompareOp)((Internal.Id1 >> 36) & 0x7);
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFF8FFFFFFFFF) | ((ulong)value << 36);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StencilOp StencilBackFailOp
|
|
||||||
{
|
|
||||||
readonly get => (StencilOp)((Internal.Id1 >> 39) & 0x7);
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFFFFC7FFFFFFFFF) | ((ulong)value << 39);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StencilOp StencilBackPassOp
|
|
||||||
{
|
|
||||||
readonly get => (StencilOp)((Internal.Id1 >> 42) & 0x7);
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFFFE3FFFFFFFFFF) | ((ulong)value << 42);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StencilOp StencilBackDepthFailOp
|
|
||||||
{
|
|
||||||
readonly get => (StencilOp)((Internal.Id1 >> 45) & 0x7);
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFFF1FFFFFFFFFFF) | ((ulong)value << 45);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompareOp StencilBackCompareOp
|
|
||||||
{
|
|
||||||
readonly get => (CompareOp)((Internal.Id1 >> 48) & 0x7);
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFF8FFFFFFFFFFFF) | ((ulong)value << 48);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CullModeFlags CullMode
|
|
||||||
{
|
|
||||||
readonly get => (CullModeFlags)((Internal.Id1 >> 51) & 0x3);
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFE7FFFFFFFFFFFF) | ((ulong)value << 51);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool PrimitiveRestartEnable
|
|
||||||
{
|
|
||||||
readonly get => ((Internal.Id1 >> 53) & 0x1) != 0UL;
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFDFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 53);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DepthClampEnable
|
|
||||||
{
|
|
||||||
readonly get => ((Internal.Id1 >> 54) & 0x1) != 0UL;
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFFBFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 54);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool RasterizerDiscardEnable
|
|
||||||
{
|
|
||||||
readonly get => ((Internal.Id1 >> 55) & 0x1) != 0UL;
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFF7FFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 55);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FrontFace FrontFace
|
|
||||||
{
|
|
||||||
readonly get => (FrontFace)((Internal.Id1 >> 56) & 0x1);
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFEFFFFFFFFFFFFFF) | ((ulong)value << 56);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DepthBiasEnable
|
|
||||||
{
|
|
||||||
readonly get => ((Internal.Id1 >> 57) & 0x1) != 0UL;
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFDFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 57);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DepthTestEnable
|
|
||||||
{
|
|
||||||
readonly get => ((Internal.Id1 >> 58) & 0x1) != 0UL;
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xFBFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 58);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DepthWriteEnable
|
|
||||||
{
|
|
||||||
readonly get => ((Internal.Id1 >> 59) & 0x1) != 0UL;
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xF7FFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 59);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DepthBoundsTestEnable
|
|
||||||
{
|
|
||||||
readonly get => ((Internal.Id1 >> 60) & 0x1) != 0UL;
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xEFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 60);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool StencilTestEnable
|
|
||||||
{
|
|
||||||
readonly get => ((Internal.Id1 >> 61) & 0x1) != 0UL;
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xDFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 61);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool LogicOpEnable
|
|
||||||
{
|
|
||||||
readonly get => ((Internal.Id1 >> 62) & 0x1) != 0UL;
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0xBFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 62);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasDepthStencil
|
|
||||||
{
|
|
||||||
readonly get => ((Internal.Id1 >> 63) & 0x1) != 0UL;
|
|
||||||
set => Internal.Id1 = (Internal.Id1 & 0x7FFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 63);
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint PatchControlPoints
|
|
||||||
{
|
{
|
||||||
readonly get => (uint)((Internal.Id2 >> 0) & 0xFFFFFFFF);
|
readonly get => (uint)((Internal.Id2 >> 0) & 0xFFFFFFFF);
|
||||||
set => Internal.Id2 = (Internal.Id2 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
|
set => Internal.Id2 = (Internal.Id2 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint SamplesCount
|
public uint StencilFrontWriteMask
|
||||||
{
|
{
|
||||||
readonly get => (uint)((Internal.Id2 >> 32) & 0xFFFFFFFF);
|
readonly get => (uint)((Internal.Id2 >> 32) & 0xFFFFFFFF);
|
||||||
set => Internal.Id2 = (Internal.Id2 & 0xFFFFFFFF) | ((ulong)value << 32);
|
set => Internal.Id2 = (Internal.Id2 & 0xFFFFFFFF) | ((ulong)value << 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public uint StencilFrontReference
|
||||||
|
{
|
||||||
|
readonly get => (uint)((Internal.Id3 >> 0) & 0xFFFFFFFF);
|
||||||
|
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint StencilBackCompareMask
|
||||||
|
{
|
||||||
|
readonly get => (uint)((Internal.Id3 >> 32) & 0xFFFFFFFF);
|
||||||
|
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFF) | ((ulong)value << 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint StencilBackWriteMask
|
||||||
|
{
|
||||||
|
readonly get => (uint)((Internal.Id4 >> 0) & 0xFFFFFFFF);
|
||||||
|
set => Internal.Id4 = (Internal.Id4 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint StencilBackReference
|
||||||
|
{
|
||||||
|
readonly get => (uint)((Internal.Id4 >> 32) & 0xFFFFFFFF);
|
||||||
|
set => Internal.Id4 = (Internal.Id4 & 0xFFFFFFFF) | ((ulong)value << 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PolygonMode PolygonMode
|
||||||
|
{
|
||||||
|
readonly get => (PolygonMode)((Internal.Id5 >> 0) & 0x3FFFFFFF);
|
||||||
|
set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFFFC0000000) | ((ulong)value << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint StagesCount
|
||||||
|
{
|
||||||
|
readonly get => (byte)((Internal.Id5 >> 30) & 0xFF);
|
||||||
|
set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFC03FFFFFFF) | ((ulong)value << 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint VertexAttributeDescriptionsCount
|
||||||
|
{
|
||||||
|
readonly get => (byte)((Internal.Id5 >> 38) & 0xFF);
|
||||||
|
set => Internal.Id5 = (Internal.Id5 & 0xFFFFC03FFFFFFFFF) | ((ulong)value << 38);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint VertexBindingDescriptionsCount
|
||||||
|
{
|
||||||
|
readonly get => (byte)((Internal.Id5 >> 46) & 0xFF);
|
||||||
|
set => Internal.Id5 = (Internal.Id5 & 0xFFC03FFFFFFFFFFF) | ((ulong)value << 46);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint ViewportsCount
|
||||||
|
{
|
||||||
|
readonly get => (byte)((Internal.Id5 >> 54) & 0xFF);
|
||||||
|
set => Internal.Id5 = (Internal.Id5 & 0xC03FFFFFFFFFFFFF) | ((ulong)value << 54);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint ScissorsCount
|
||||||
|
{
|
||||||
|
readonly get => (byte)((Internal.Id6 >> 0) & 0xFF);
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFFFFF00) | ((ulong)value << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint ColorBlendAttachmentStateCount
|
||||||
|
{
|
||||||
|
readonly get => (byte)((Internal.Id6 >> 8) & 0xFF);
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFFF00FF) | ((ulong)value << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrimitiveTopology Topology
|
||||||
|
{
|
||||||
|
readonly get => (PrimitiveTopology)((Internal.Id6 >> 16) & 0xF);
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFFF0FFFF) | ((ulong)value << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogicOp LogicOp
|
||||||
|
{
|
||||||
|
readonly get => (LogicOp)((Internal.Id6 >> 20) & 0xF);
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFFF0FFFFF) | ((ulong)value << 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompareOp DepthCompareOp
|
||||||
|
{
|
||||||
|
readonly get => (CompareOp)((Internal.Id6 >> 24) & 0x7);
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFF8FFFFFF) | ((ulong)value << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StencilOp StencilFrontFailOp
|
||||||
|
{
|
||||||
|
readonly get => (StencilOp)((Internal.Id6 >> 27) & 0x7);
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFC7FFFFFF) | ((ulong)value << 27);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StencilOp StencilFrontPassOp
|
||||||
|
{
|
||||||
|
readonly get => (StencilOp)((Internal.Id6 >> 30) & 0x7);
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFE3FFFFFFF) | ((ulong)value << 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StencilOp StencilFrontDepthFailOp
|
||||||
|
{
|
||||||
|
readonly get => (StencilOp)((Internal.Id6 >> 33) & 0x7);
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFF1FFFFFFFF) | ((ulong)value << 33);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompareOp StencilFrontCompareOp
|
||||||
|
{
|
||||||
|
readonly get => (CompareOp)((Internal.Id6 >> 36) & 0x7);
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFF8FFFFFFFFF) | ((ulong)value << 36);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StencilOp StencilBackFailOp
|
||||||
|
{
|
||||||
|
readonly get => (StencilOp)((Internal.Id6 >> 39) & 0x7);
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFFFFC7FFFFFFFFF) | ((ulong)value << 39);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StencilOp StencilBackPassOp
|
||||||
|
{
|
||||||
|
readonly get => (StencilOp)((Internal.Id6 >> 42) & 0x7);
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFFFE3FFFFFFFFFF) | ((ulong)value << 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StencilOp StencilBackDepthFailOp
|
||||||
|
{
|
||||||
|
readonly get => (StencilOp)((Internal.Id6 >> 45) & 0x7);
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFFF1FFFFFFFFFFF) | ((ulong)value << 45);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompareOp StencilBackCompareOp
|
||||||
|
{
|
||||||
|
readonly get => (CompareOp)((Internal.Id6 >> 48) & 0x7);
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFF8FFFFFFFFFFFF) | ((ulong)value << 48);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CullModeFlags CullMode
|
||||||
|
{
|
||||||
|
readonly get => (CullModeFlags)((Internal.Id6 >> 51) & 0x3);
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFE7FFFFFFFFFFFF) | ((ulong)value << 51);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PrimitiveRestartEnable
|
||||||
|
{
|
||||||
|
readonly get => ((Internal.Id6 >> 53) & 0x1) != 0UL;
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFDFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 53);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DepthClampEnable
|
||||||
|
{
|
||||||
|
readonly get => ((Internal.Id6 >> 54) & 0x1) != 0UL;
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFFBFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 54);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RasterizerDiscardEnable
|
||||||
|
{
|
||||||
|
readonly get => ((Internal.Id6 >> 55) & 0x1) != 0UL;
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFF7FFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 55);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrontFace FrontFace
|
||||||
|
{
|
||||||
|
readonly get => (FrontFace)((Internal.Id6 >> 56) & 0x1);
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFEFFFFFFFFFFFFFF) | ((ulong)value << 56);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DepthBiasEnable
|
||||||
|
{
|
||||||
|
readonly get => ((Internal.Id6 >> 57) & 0x1) != 0UL;
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFDFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 57);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DepthTestEnable
|
||||||
|
{
|
||||||
|
readonly get => ((Internal.Id6 >> 58) & 0x1) != 0UL;
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xFBFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 58);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DepthWriteEnable
|
||||||
|
{
|
||||||
|
readonly get => ((Internal.Id6 >> 59) & 0x1) != 0UL;
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xF7FFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 59);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DepthBoundsTestEnable
|
||||||
|
{
|
||||||
|
readonly get => ((Internal.Id6 >> 60) & 0x1) != 0UL;
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xEFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool StencilTestEnable
|
||||||
|
{
|
||||||
|
readonly get => ((Internal.Id6 >> 61) & 0x1) != 0UL;
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xDFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 61);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool LogicOpEnable
|
||||||
|
{
|
||||||
|
readonly get => ((Internal.Id6 >> 62) & 0x1) != 0UL;
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0xBFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 62);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasDepthStencil
|
||||||
|
{
|
||||||
|
readonly get => ((Internal.Id6 >> 63) & 0x1) != 0UL;
|
||||||
|
set => Internal.Id6 = (Internal.Id6 & 0x7FFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 63);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint PatchControlPoints
|
||||||
|
{
|
||||||
|
readonly get => (uint)((Internal.Id7 >> 0) & 0xFFFFFFFF);
|
||||||
|
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint SamplesCount
|
||||||
|
{
|
||||||
|
readonly get => (uint)((Internal.Id7 >> 32) & 0xFFFFFFFF);
|
||||||
|
set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFF) | ((ulong)value << 32);
|
||||||
|
}
|
||||||
|
|
||||||
public bool AlphaToCoverageEnable
|
public bool AlphaToCoverageEnable
|
||||||
{
|
{
|
||||||
readonly get => ((Internal.Id3 >> 0) & 0x1) != 0UL;
|
readonly get => ((Internal.Id8 >> 0) & 0x1) != 0UL;
|
||||||
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFFFFFFFFFE) | ((value ? 1UL : 0UL) << 0);
|
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFFE) | ((value ? 1UL : 0UL) << 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AlphaToOneEnable
|
public bool AlphaToOneEnable
|
||||||
{
|
{
|
||||||
readonly get => ((Internal.Id3 >> 1) & 0x1) != 0UL;
|
readonly get => ((Internal.Id8 >> 1) & 0x1) != 0UL;
|
||||||
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFFFFFFFFFD) | ((value ? 1UL : 0UL) << 1);
|
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFFD) | ((value ? 1UL : 0UL) << 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AdvancedBlendSrcPreMultiplied
|
public bool AdvancedBlendSrcPreMultiplied
|
||||||
{
|
{
|
||||||
readonly get => ((Internal.Id3 >> 2) & 0x1) != 0UL;
|
readonly get => ((Internal.Id8 >> 2) & 0x1) != 0UL;
|
||||||
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFFFFFFFFFB) | ((value ? 1UL : 0UL) << 2);
|
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFFB) | ((value ? 1UL : 0UL) << 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AdvancedBlendDstPreMultiplied
|
public bool AdvancedBlendDstPreMultiplied
|
||||||
{
|
{
|
||||||
readonly get => ((Internal.Id3 >> 3) & 0x1) != 0UL;
|
readonly get => ((Internal.Id8 >> 3) & 0x1) != 0UL;
|
||||||
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFFFFFFFFF7) | ((value ? 1UL : 0UL) << 3);
|
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFF7) | ((value ? 1UL : 0UL) << 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlendOverlapEXT AdvancedBlendOverlap
|
public BlendOverlapEXT AdvancedBlendOverlap
|
||||||
{
|
{
|
||||||
readonly get => (BlendOverlapEXT)((Internal.Id3 >> 4) & 0x3);
|
readonly get => (BlendOverlapEXT)((Internal.Id8 >> 4) & 0x3);
|
||||||
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFFFFFFFFCF) | ((ulong)value << 4);
|
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFCF) | ((ulong)value << 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DepthMode
|
public bool DepthMode
|
||||||
{
|
{
|
||||||
readonly get => ((Internal.Id3 >> 6) & 0x1) != 0UL;
|
readonly get => ((Internal.Id8 >> 6) & 0x1) != 0UL;
|
||||||
set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6);
|
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FeedbackLoopAspects FeedbackLoopAspects
|
||||||
|
{
|
||||||
|
readonly get => (FeedbackLoopAspects)((Internal.Id8 >> 7) & 0x3);
|
||||||
|
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFE7F) | (((ulong)value) << 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasTessellationControlShader;
|
public bool HasTessellationControlShader;
|
||||||
@@ -246,11 +312,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private Array32<VertexInputAttributeDescription> _vertexAttributeDescriptions2;
|
private Array32<VertexInputAttributeDescription> _vertexAttributeDescriptions2;
|
||||||
|
|
||||||
private bool _supportsExtDynamicState;
|
public void Initialize()
|
||||||
private PhysicalDeviceExtendedDynamicState2FeaturesEXT _supportsExtDynamicState2;
|
|
||||||
private uint _blendEnables;
|
|
||||||
|
|
||||||
public void Initialize(HardwareCapabilities capabilities)
|
|
||||||
{
|
{
|
||||||
HasTessellationControlShader = false;
|
HasTessellationControlShader = false;
|
||||||
Stages = new NativeArray<PipelineShaderStageCreateInfo>(Constants.MaxShaderStages);
|
Stages = new NativeArray<PipelineShaderStageCreateInfo>(Constants.MaxShaderStages);
|
||||||
@@ -259,53 +321,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
AdvancedBlendDstPreMultiplied = true;
|
AdvancedBlendDstPreMultiplied = true;
|
||||||
AdvancedBlendOverlap = BlendOverlapEXT.UncorrelatedExt;
|
AdvancedBlendOverlap = BlendOverlapEXT.UncorrelatedExt;
|
||||||
|
|
||||||
|
LineWidth = 1f;
|
||||||
|
SamplesCount = 1;
|
||||||
DepthMode = true;
|
DepthMode = true;
|
||||||
|
|
||||||
PolygonMode = PolygonMode.Fill;
|
|
||||||
DepthBoundsTestEnable = false;
|
|
||||||
|
|
||||||
_supportsExtDynamicState = capabilities.SupportsExtendedDynamicState;
|
|
||||||
_supportsExtDynamicState2 = capabilities.SupportsExtendedDynamicState2;
|
|
||||||
|
|
||||||
if (_supportsExtDynamicState)
|
|
||||||
{
|
|
||||||
StencilFrontFailOp = 0;
|
|
||||||
StencilFrontPassOp = 0;
|
|
||||||
StencilFrontDepthFailOp = 0;
|
|
||||||
StencilFrontCompareOp = 0;
|
|
||||||
|
|
||||||
StencilBackFailOp = 0;
|
|
||||||
StencilBackPassOp = 0;
|
|
||||||
StencilBackDepthFailOp = 0;
|
|
||||||
StencilBackCompareOp = 0;
|
|
||||||
|
|
||||||
ViewportsCount = 0;
|
|
||||||
ScissorsCount = 0;
|
|
||||||
|
|
||||||
CullMode = 0;
|
|
||||||
FrontFace = 0;
|
|
||||||
DepthTestEnable = false;
|
|
||||||
DepthWriteEnable = false;
|
|
||||||
DepthCompareOp = 0;
|
|
||||||
StencilTestEnable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_supportsExtDynamicState2.ExtendedDynamicState2)
|
|
||||||
{
|
|
||||||
PrimitiveRestartEnable = false;
|
|
||||||
DepthBiasEnable = false;
|
|
||||||
RasterizerDiscardEnable = false;
|
|
||||||
|
|
||||||
if (_supportsExtDynamicState2.ExtendedDynamicState2LogicOp)
|
|
||||||
{
|
|
||||||
LogicOp = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_supportsExtDynamicState2.ExtendedDynamicState2PatchControlPoints)
|
|
||||||
{
|
|
||||||
PatchControlPoints = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe Auto<DisposablePipeline> CreateComputePipeline(
|
public unsafe Auto<DisposablePipeline> CreateComputePipeline(
|
||||||
@@ -323,6 +341,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
SType = StructureType.ComputePipelineCreateInfo,
|
SType = StructureType.ComputePipelineCreateInfo,
|
||||||
Stage = Stages[0],
|
Stage = Stages[0],
|
||||||
|
BasePipelineIndex = -1,
|
||||||
Layout = PipelineLayout,
|
Layout = PipelineLayout,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -358,74 +377,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return pipeline;
|
return pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void CheckCapability(VulkanRenderer gd)
|
|
||||||
{
|
|
||||||
// Vendors other than NVIDIA have a bug where it enables logical operations even for float formats,
|
|
||||||
// so we need to force disable them here.
|
|
||||||
LogicOpEnable = LogicOpEnable && (gd.Vendor == Vendor.Nvidia || Internal.LogicOpsAllowed);
|
|
||||||
|
|
||||||
if (!_supportsExtDynamicState)
|
|
||||||
{
|
|
||||||
DepthWriteEnable = DepthWriteEnable && DepthTestEnable;
|
|
||||||
DepthCompareOp = DepthTestEnable ? DepthCompareOp : default;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_supportsExtDynamicState2.ExtendedDynamicState2LogicOp)
|
|
||||||
{
|
|
||||||
LogicOp = LogicOpEnable ? LogicOp : default;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_supportsExtDynamicState2.ExtendedDynamicState2)
|
|
||||||
{
|
|
||||||
bool topologySupportsRestart;
|
|
||||||
|
|
||||||
if (gd.Capabilities.SupportsPrimitiveTopologyListRestart)
|
|
||||||
{
|
|
||||||
topologySupportsRestart = gd.Capabilities.SupportsPrimitiveTopologyPatchListRestart ||
|
|
||||||
Topology != PrimitiveTopology.PatchList;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
topologySupportsRestart = Topology == PrimitiveTopology.LineStrip ||
|
|
||||||
Topology == PrimitiveTopology.TriangleStrip ||
|
|
||||||
Topology == PrimitiveTopology.TriangleFan ||
|
|
||||||
Topology == PrimitiveTopology.LineStripWithAdjacency ||
|
|
||||||
Topology == PrimitiveTopology.TriangleStripWithAdjacency;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrimitiveRestartEnable &= topologySupportsRestart;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_supportsExtDynamicState)
|
|
||||||
{
|
|
||||||
Topology = Topology.ConvertToClass();
|
|
||||||
}
|
|
||||||
|
|
||||||
Topology = HasTessellationControlShader ? PrimitiveTopology.PatchList : Topology;
|
|
||||||
|
|
||||||
if (gd.IsMoltenVk && Internal.AttachmentIntegerFormatMask != 0)
|
|
||||||
{
|
|
||||||
_blendEnables = 0;
|
|
||||||
|
|
||||||
// Blend can't be enabled for integer formats, so let's make sure it is disabled.
|
|
||||||
uint attachmentIntegerFormatMask = Internal.AttachmentIntegerFormatMask;
|
|
||||||
|
|
||||||
while (attachmentIntegerFormatMask != 0)
|
|
||||||
{
|
|
||||||
int i = BitOperations.TrailingZeroCount(attachmentIntegerFormatMask);
|
|
||||||
|
|
||||||
if (Internal.ColorBlendAttachmentState[i].BlendEnable)
|
|
||||||
{
|
|
||||||
_blendEnables |= 1u << i;
|
|
||||||
}
|
|
||||||
|
|
||||||
Internal.ColorBlendAttachmentState[i].BlendEnable = false;
|
|
||||||
attachmentIntegerFormatMask &= ~(1u << i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe Auto<DisposablePipeline> CreateGraphicsPipeline(
|
public unsafe Auto<DisposablePipeline> CreateGraphicsPipeline(
|
||||||
VulkanRenderer gd,
|
VulkanRenderer gd,
|
||||||
Device device,
|
Device device,
|
||||||
@@ -434,17 +385,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
RenderPass renderPass,
|
RenderPass renderPass,
|
||||||
bool throwOnError = false)
|
bool throwOnError = false)
|
||||||
{
|
{
|
||||||
CheckCapability(gd);
|
|
||||||
|
|
||||||
// Using patches topology without a tessellation shader is invalid.
|
|
||||||
// If we find such a case, return null pipeline to skip the draw.
|
|
||||||
if (Topology == PrimitiveTopology.PatchList && !HasTessellationControlShader)
|
|
||||||
{
|
|
||||||
program.AddGraphicsPipeline(ref Internal, null);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (program.TryGetGraphicsPipeline(ref Internal, out var pipeline))
|
if (program.TryGetGraphicsPipeline(ref Internal, out var pipeline))
|
||||||
{
|
{
|
||||||
return pipeline;
|
return pipeline;
|
||||||
@@ -454,7 +394,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
bool isMoltenVk = gd.IsMoltenVk;
|
bool isMoltenVk = gd.IsMoltenVk;
|
||||||
|
|
||||||
if (isMoltenVk && !_supportsExtDynamicState)
|
if (isMoltenVk)
|
||||||
{
|
{
|
||||||
UpdateVertexAttributeDescriptions(gd);
|
UpdateVertexAttributeDescriptions(gd);
|
||||||
}
|
}
|
||||||
@@ -468,30 +408,69 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
SType = StructureType.PipelineVertexInputStateCreateInfo,
|
SType = StructureType.PipelineVertexInputStateCreateInfo,
|
||||||
VertexAttributeDescriptionCount = VertexAttributeDescriptionsCount,
|
VertexAttributeDescriptionCount = VertexAttributeDescriptionsCount,
|
||||||
PVertexAttributeDescriptions = isMoltenVk && !_supportsExtDynamicState ? pVertexAttributeDescriptions2 : pVertexAttributeDescriptions,
|
PVertexAttributeDescriptions = isMoltenVk ? pVertexAttributeDescriptions2 : pVertexAttributeDescriptions,
|
||||||
VertexBindingDescriptionCount = VertexBindingDescriptionsCount,
|
VertexBindingDescriptionCount = VertexBindingDescriptionsCount,
|
||||||
PVertexBindingDescriptions = pVertexBindingDescriptions,
|
PVertexBindingDescriptions = pVertexBindingDescriptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Using patches topology without a tessellation shader is invalid.
|
||||||
|
// If we find such a case, return null pipeline to skip the draw.
|
||||||
|
if (Topology == PrimitiveTopology.PatchList && !HasTessellationControlShader)
|
||||||
|
{
|
||||||
|
program.AddGraphicsPipeline(ref Internal, null);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool primitiveRestartEnable = PrimitiveRestartEnable;
|
||||||
|
|
||||||
|
bool topologySupportsRestart;
|
||||||
|
|
||||||
|
if (gd.Capabilities.SupportsPrimitiveTopologyListRestart)
|
||||||
|
{
|
||||||
|
topologySupportsRestart = gd.Capabilities.SupportsPrimitiveTopologyPatchListRestart || Topology != PrimitiveTopology.PatchList;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
topologySupportsRestart = Topology == PrimitiveTopology.LineStrip ||
|
||||||
|
Topology == PrimitiveTopology.TriangleStrip ||
|
||||||
|
Topology == PrimitiveTopology.TriangleFan ||
|
||||||
|
Topology == PrimitiveTopology.LineStripWithAdjacency ||
|
||||||
|
Topology == PrimitiveTopology.TriangleStripWithAdjacency;
|
||||||
|
}
|
||||||
|
|
||||||
|
primitiveRestartEnable &= topologySupportsRestart;
|
||||||
|
|
||||||
var inputAssemblyState = new PipelineInputAssemblyStateCreateInfo
|
var inputAssemblyState = new PipelineInputAssemblyStateCreateInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.PipelineInputAssemblyStateCreateInfo,
|
SType = StructureType.PipelineInputAssemblyStateCreateInfo,
|
||||||
Topology = Topology,
|
PrimitiveRestartEnable = primitiveRestartEnable,
|
||||||
|
Topology = HasTessellationControlShader ? PrimitiveTopology.PatchList : Topology,
|
||||||
};
|
};
|
||||||
|
|
||||||
PipelineTessellationStateCreateInfo tessellationState;
|
var tessellationState = new PipelineTessellationStateCreateInfo
|
||||||
|
{
|
||||||
|
SType = StructureType.PipelineTessellationStateCreateInfo,
|
||||||
|
PatchControlPoints = PatchControlPoints,
|
||||||
|
};
|
||||||
|
|
||||||
var rasterizationState = new PipelineRasterizationStateCreateInfo
|
var rasterizationState = new PipelineRasterizationStateCreateInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.PipelineRasterizationStateCreateInfo,
|
SType = StructureType.PipelineRasterizationStateCreateInfo,
|
||||||
DepthClampEnable = DepthClampEnable,
|
DepthClampEnable = DepthClampEnable,
|
||||||
// When widelines feature is not supported it must be 1.0f, this will be ignored if Line Width dynamic state is supported
|
RasterizerDiscardEnable = RasterizerDiscardEnable,
|
||||||
LineWidth = 1.0f,
|
PolygonMode = PolygonMode,
|
||||||
|
LineWidth = LineWidth,
|
||||||
|
CullMode = CullMode,
|
||||||
|
FrontFace = FrontFace,
|
||||||
|
DepthBiasEnable = DepthBiasEnable,
|
||||||
};
|
};
|
||||||
|
|
||||||
var viewportState = new PipelineViewportStateCreateInfo
|
var viewportState = new PipelineViewportStateCreateInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.PipelineViewportStateCreateInfo,
|
SType = StructureType.PipelineViewportStateCreateInfo,
|
||||||
|
ViewportCount = ViewportsCount,
|
||||||
|
ScissorCount = ScissorsCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (gd.Capabilities.SupportsDepthClipControl)
|
if (gd.Capabilities.SupportsDepthClipControl)
|
||||||
@@ -515,20 +494,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
AlphaToOneEnable = AlphaToOneEnable,
|
AlphaToOneEnable = AlphaToOneEnable,
|
||||||
};
|
};
|
||||||
|
|
||||||
var depthStencilState = new PipelineDepthStencilStateCreateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.PipelineDepthStencilStateCreateInfo,
|
|
||||||
DepthBoundsTestEnable = DepthBoundsTestEnable,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!_supportsExtDynamicState)
|
|
||||||
{
|
|
||||||
rasterizationState.CullMode = CullMode;
|
|
||||||
rasterizationState.FrontFace = FrontFace;
|
|
||||||
|
|
||||||
viewportState.ViewportCount = ViewportsCount;
|
|
||||||
viewportState.ScissorCount = ScissorsCount;
|
|
||||||
|
|
||||||
var stencilFront = new StencilOpState(
|
var stencilFront = new StencilOpState(
|
||||||
StencilFrontFailOp,
|
StencilFrontFailOp,
|
||||||
StencilFrontPassOp,
|
StencilFrontPassOp,
|
||||||
@@ -541,49 +506,59 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
StencilBackDepthFailOp,
|
StencilBackDepthFailOp,
|
||||||
StencilBackCompareOp);
|
StencilBackCompareOp);
|
||||||
|
|
||||||
depthStencilState.Front = stencilFront;
|
var depthStencilState = new PipelineDepthStencilStateCreateInfo
|
||||||
depthStencilState.Back = stencilBack;
|
|
||||||
depthStencilState.StencilTestEnable = StencilTestEnable;
|
|
||||||
depthStencilState.DepthTestEnable = DepthTestEnable;
|
|
||||||
depthStencilState.DepthWriteEnable = DepthWriteEnable;
|
|
||||||
depthStencilState.DepthCompareOp = DepthCompareOp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_supportsExtDynamicState2.ExtendedDynamicState2)
|
|
||||||
{
|
{
|
||||||
|
SType = StructureType.PipelineDepthStencilStateCreateInfo,
|
||||||
inputAssemblyState.PrimitiveRestartEnable = PrimitiveRestartEnable;
|
DepthTestEnable = DepthTestEnable,
|
||||||
rasterizationState.DepthBiasEnable = DepthBiasEnable;
|
DepthWriteEnable = DepthWriteEnable,
|
||||||
rasterizationState.RasterizerDiscardEnable = RasterizerDiscardEnable;
|
DepthCompareOp = DepthCompareOp,
|
||||||
}
|
DepthBoundsTestEnable = false,
|
||||||
|
StencilTestEnable = StencilTestEnable,
|
||||||
if (!gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints)
|
Front = stencilFront,
|
||||||
{
|
Back = stencilBack,
|
||||||
tessellationState = new PipelineTessellationStateCreateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.PipelineTessellationStateCreateInfo,
|
|
||||||
PatchControlPoints = PatchControlPoints,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uint blendEnables = 0;
|
||||||
|
|
||||||
|
if (gd.IsMoltenVk && Internal.AttachmentIntegerFormatMask != 0)
|
||||||
|
{
|
||||||
|
// Blend can't be enabled for integer formats, so let's make sure it is disabled.
|
||||||
|
uint attachmentIntegerFormatMask = Internal.AttachmentIntegerFormatMask;
|
||||||
|
|
||||||
|
while (attachmentIntegerFormatMask != 0)
|
||||||
|
{
|
||||||
|
int i = BitOperations.TrailingZeroCount(attachmentIntegerFormatMask);
|
||||||
|
|
||||||
|
if (Internal.ColorBlendAttachmentState[i].BlendEnable)
|
||||||
|
{
|
||||||
|
blendEnables |= 1u << i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Internal.ColorBlendAttachmentState[i].BlendEnable = false;
|
||||||
|
attachmentIntegerFormatMask &= ~(1u << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vendors other than NVIDIA have a bug where it enables logical operations even for float formats,
|
||||||
|
// so we need to force disable them here.
|
||||||
|
bool logicOpEnable = LogicOpEnable && (gd.Vendor == Vendor.Nvidia || Internal.LogicOpsAllowed);
|
||||||
|
|
||||||
var colorBlendState = new PipelineColorBlendStateCreateInfo
|
var colorBlendState = new PipelineColorBlendStateCreateInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.PipelineColorBlendStateCreateInfo,
|
SType = StructureType.PipelineColorBlendStateCreateInfo,
|
||||||
|
LogicOpEnable = logicOpEnable,
|
||||||
|
LogicOp = LogicOp,
|
||||||
AttachmentCount = ColorBlendAttachmentStateCount,
|
AttachmentCount = ColorBlendAttachmentStateCount,
|
||||||
PAttachments = pColorBlendAttachmentState,
|
PAttachments = pColorBlendAttachmentState,
|
||||||
LogicOpEnable = LogicOpEnable,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2LogicOp)
|
PipelineColorBlendAdvancedStateCreateInfoEXT colorBlendAdvancedState;
|
||||||
{
|
|
||||||
colorBlendState.LogicOp = LogicOp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!AdvancedBlendSrcPreMultiplied ||
|
if (!AdvancedBlendSrcPreMultiplied ||
|
||||||
!AdvancedBlendDstPreMultiplied ||
|
!AdvancedBlendDstPreMultiplied ||
|
||||||
AdvancedBlendOverlap != BlendOverlapEXT.UncorrelatedExt)
|
AdvancedBlendOverlap != BlendOverlapEXT.UncorrelatedExt)
|
||||||
{
|
{
|
||||||
PipelineColorBlendAdvancedStateCreateInfoEXT colorBlendAdvancedState = new PipelineColorBlendAdvancedStateCreateInfoEXT
|
colorBlendAdvancedState = new PipelineColorBlendAdvancedStateCreateInfoEXT
|
||||||
{
|
{
|
||||||
SType = StructureType.PipelineColorBlendAdvancedStateCreateInfoExt,
|
SType = StructureType.PipelineColorBlendAdvancedStateCreateInfoExt,
|
||||||
SrcPremultiplied = AdvancedBlendSrcPreMultiplied,
|
SrcPremultiplied = AdvancedBlendSrcPreMultiplied,
|
||||||
@@ -594,75 +569,64 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
colorBlendState.PNext = &colorBlendAdvancedState;
|
colorBlendState.PNext = &colorBlendAdvancedState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
|
||||||
|
bool supportsFeedbackLoopDynamicState = gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop;
|
||||||
|
|
||||||
DynamicState* dynamicStates = stackalloc DynamicState[MaxDynamicStatesCount];
|
DynamicState* dynamicStates = stackalloc DynamicState[MaxDynamicStatesCount];
|
||||||
|
|
||||||
uint dynamicStatesCount = 7;
|
int dynamicStatesCount = 7;
|
||||||
|
|
||||||
dynamicStates[0] = DynamicState.Viewport;
|
dynamicStates[0] = DynamicState.Viewport;
|
||||||
dynamicStates[1] = DynamicState.Scissor;
|
dynamicStates[1] = DynamicState.Scissor;
|
||||||
dynamicStates[2] = DynamicState.StencilCompareMask;
|
dynamicStates[2] = DynamicState.DepthBias;
|
||||||
dynamicStates[3] = DynamicState.StencilWriteMask;
|
dynamicStates[3] = DynamicState.StencilCompareMask;
|
||||||
dynamicStates[4] = DynamicState.StencilReference;
|
dynamicStates[4] = DynamicState.StencilWriteMask;
|
||||||
dynamicStates[5] = DynamicState.BlendConstants;
|
dynamicStates[5] = DynamicState.StencilReference;
|
||||||
dynamicStates[6] = DynamicState.DepthBias;
|
dynamicStates[6] = DynamicState.BlendConstants;
|
||||||
|
|
||||||
if (!isMoltenVk)
|
if (supportsExtDynamicState)
|
||||||
{
|
{
|
||||||
//LineWidth dynamic state is only supported on macOS when using Metal Private API on newer version of MoltenVK
|
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.LineWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_supportsExtDynamicState)
|
|
||||||
{
|
|
||||||
if (gd.SupportsMTL31 || !gd.IsMoltenVk)
|
|
||||||
{
|
|
||||||
// Requires Metal 3.1 and new MoltenVK, however extended dynamic states extension is not
|
|
||||||
// available on older versions of MVK, so we can safely check only OS version.
|
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.VertexInputBindingStrideExt;
|
dynamicStates[dynamicStatesCount++] = DynamicState.VertexInputBindingStrideExt;
|
||||||
}
|
}
|
||||||
dynamicStates[0] = DynamicState.ViewportWithCountExt;
|
|
||||||
dynamicStates[1] = DynamicState.ScissorWithCountExt;
|
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.CullModeExt;
|
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.FrontFaceExt;
|
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.DepthTestEnableExt;
|
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.DepthWriteEnableExt;
|
|
||||||
|
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.DepthCompareOpExt;
|
if (supportsFeedbackLoopDynamicState)
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.StencilTestEnableExt;
|
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.StencilOpExt;
|
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.PrimitiveTopologyExt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_supportsExtDynamicState2.ExtendedDynamicState2)
|
|
||||||
{
|
{
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.DepthBiasEnableExt;
|
dynamicStates[dynamicStatesCount++] = DynamicState.AttachmentFeedbackLoopEnableExt;
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.RasterizerDiscardEnableExt;
|
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.PrimitiveRestartEnableExt;
|
|
||||||
|
|
||||||
if (_supportsExtDynamicState2.ExtendedDynamicState2LogicOp)
|
|
||||||
{
|
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.LogicOpExt;
|
|
||||||
}
|
|
||||||
if (_supportsExtDynamicState2.ExtendedDynamicState2PatchControlPoints)
|
|
||||||
{
|
|
||||||
dynamicStates[dynamicStatesCount++] = DynamicState.PatchControlPointsExt;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo
|
var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.PipelineDynamicStateCreateInfo,
|
SType = StructureType.PipelineDynamicStateCreateInfo,
|
||||||
DynamicStateCount = dynamicStatesCount,
|
DynamicStateCount = (uint)dynamicStatesCount,
|
||||||
PDynamicStates = dynamicStates,
|
PDynamicStates = dynamicStates,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PipelineCreateFlags flags = 0;
|
||||||
|
|
||||||
|
if (gd.Capabilities.SupportsAttachmentFeedbackLoop)
|
||||||
|
{
|
||||||
|
FeedbackLoopAspects aspects = FeedbackLoopAspects;
|
||||||
|
|
||||||
|
if ((aspects & FeedbackLoopAspects.Color) != 0)
|
||||||
|
{
|
||||||
|
flags |= PipelineCreateFlags.CreateColorAttachmentFeedbackLoopBitExt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((aspects & FeedbackLoopAspects.Depth) != 0)
|
||||||
|
{
|
||||||
|
flags |= PipelineCreateFlags.CreateDepthStencilAttachmentFeedbackLoopBitExt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var pipelineCreateInfo = new GraphicsPipelineCreateInfo
|
var pipelineCreateInfo = new GraphicsPipelineCreateInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.GraphicsPipelineCreateInfo,
|
SType = StructureType.GraphicsPipelineCreateInfo,
|
||||||
|
Flags = flags,
|
||||||
StageCount = StagesCount,
|
StageCount = StagesCount,
|
||||||
PStages = Stages.Pointer,
|
PStages = Stages.Pointer,
|
||||||
PVertexInputState = &vertexInputState,
|
PVertexInputState = &vertexInputState,
|
||||||
PInputAssemblyState = &inputAssemblyState,
|
PInputAssemblyState = &inputAssemblyState,
|
||||||
|
PTessellationState = &tessellationState,
|
||||||
PViewportState = &viewportState,
|
PViewportState = &viewportState,
|
||||||
PRasterizationState = &rasterizationState,
|
PRasterizationState = &rasterizationState,
|
||||||
PMultisampleState = &multisampleState,
|
PMultisampleState = &multisampleState,
|
||||||
@@ -673,11 +637,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
RenderPass = renderPass,
|
RenderPass = renderPass,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!gd.Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints)
|
|
||||||
{
|
|
||||||
pipelineCreateInfo.PTessellationState = &tessellationState;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result result = gd.Api.CreateGraphicsPipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle);
|
Result result = gd.Api.CreateGraphicsPipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle);
|
||||||
|
|
||||||
if (throwOnError)
|
if (throwOnError)
|
||||||
@@ -690,21 +649,21 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore previous blend enable values if we changed it.
|
||||||
|
while (blendEnables != 0)
|
||||||
|
{
|
||||||
|
int i = BitOperations.TrailingZeroCount(blendEnables);
|
||||||
|
|
||||||
|
Internal.ColorBlendAttachmentState[i].BlendEnable = true;
|
||||||
|
blendEnables &= ~(1u << i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline = new Auto<DisposablePipeline>(new DisposablePipeline(gd.Api, device, pipelineHandle));
|
pipeline = new Auto<DisposablePipeline>(new DisposablePipeline(gd.Api, device, pipelineHandle));
|
||||||
|
|
||||||
program.AddGraphicsPipeline(ref Internal, pipeline);
|
program.AddGraphicsPipeline(ref Internal, pipeline);
|
||||||
|
|
||||||
// Restore previous blend enable values if we changed it.
|
|
||||||
while (_blendEnables != 0)
|
|
||||||
{
|
|
||||||
int i = BitOperations.TrailingZeroCount(_blendEnables);
|
|
||||||
|
|
||||||
Internal.ColorBlendAttachmentState[i].BlendEnable = true;
|
|
||||||
_blendEnables &= ~(1u << i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return pipeline;
|
return pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,17 +11,23 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
public ulong Id0;
|
public ulong Id0;
|
||||||
public ulong Id1;
|
public ulong Id1;
|
||||||
|
|
||||||
public ulong Id2;
|
public ulong Id2;
|
||||||
public ulong Id3;
|
public ulong Id3;
|
||||||
|
|
||||||
private readonly uint VertexAttributeDescriptionsCount => (byte)((Id0 >> 38) & 0xFF);
|
public ulong Id4;
|
||||||
private readonly uint VertexBindingDescriptionsCount => (byte)((Id0 >> 46) & 0xFF);
|
public ulong Id5;
|
||||||
private readonly uint ColorBlendAttachmentStateCount => (byte)((Id1 >> 8) & 0xFF);
|
public ulong Id6;
|
||||||
private readonly bool HasDepthStencil => ((Id1 >> 63) & 0x1) != 0UL;
|
|
||||||
|
public ulong Id7;
|
||||||
|
public ulong Id8;
|
||||||
|
|
||||||
|
private readonly uint VertexAttributeDescriptionsCount => (byte)((Id5 >> 38) & 0xFF);
|
||||||
|
private readonly uint VertexBindingDescriptionsCount => (byte)((Id5 >> 46) & 0xFF);
|
||||||
|
private readonly uint ColorBlendAttachmentStateCount => (byte)((Id6 >> 8) & 0xFF);
|
||||||
|
private readonly bool HasDepthStencil => ((Id6 >> 63) & 0x1) != 0UL;
|
||||||
|
|
||||||
public Array32<VertexInputAttributeDescription> VertexAttributeDescriptions;
|
public Array32<VertexInputAttributeDescription> VertexAttributeDescriptions;
|
||||||
public Array32<VertexInputBindingDescription> VertexBindingDescriptions;
|
public Array33<VertexInputBindingDescription> VertexBindingDescriptions;
|
||||||
public Array8<PipelineColorBlendAttachmentState> ColorBlendAttachmentState;
|
public Array8<PipelineColorBlendAttachmentState> ColorBlendAttachmentState;
|
||||||
public Array9<Format> AttachmentFormats;
|
public Array9<Format> AttachmentFormats;
|
||||||
public uint AttachmentIntegerFormatMask;
|
public uint AttachmentIntegerFormatMask;
|
||||||
@@ -34,7 +40,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public bool Equals(ref PipelineUid other)
|
public bool Equals(ref PipelineUid other)
|
||||||
{
|
{
|
||||||
if (!Unsafe.As<ulong, Vector256<byte>>(ref Id0).Equals(Unsafe.As<ulong, Vector256<byte>>(ref other.Id0)))
|
if (!Unsafe.As<ulong, Vector256<byte>>(ref Id0).Equals(Unsafe.As<ulong, Vector256<byte>>(ref other.Id0)) ||
|
||||||
|
!Unsafe.As<ulong, Vector256<byte>>(ref Id4).Equals(Unsafe.As<ulong, Vector256<byte>>(ref other.Id4)) ||
|
||||||
|
!Unsafe.As<ulong, Vector128<byte>>(ref Id7).Equals(Unsafe.As<ulong, Vector128<byte>>(ref other.Id7)))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -72,7 +80,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
ulong hash64 = Id0 * 23 ^
|
ulong hash64 = Id0 * 23 ^
|
||||||
Id1 * 23 ^
|
Id1 * 23 ^
|
||||||
Id2 * 23 ^
|
Id2 * 23 ^
|
||||||
Id3 * 23;
|
Id3 * 23 ^
|
||||||
|
Id4 * 23 ^
|
||||||
|
Id5 * 23 ^
|
||||||
|
Id6 * 23 ^
|
||||||
|
Id7 * 23 ^
|
||||||
|
Id8 * 23;
|
||||||
|
|
||||||
for (int i = 0; i < (int)VertexAttributeDescriptionsCount; i++)
|
for (int i = 0; i < (int)VertexAttributeDescriptionsCount; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using System.Collections.Generic;
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using PrimitiveTopology = Silk.NET.Vulkan.PrimitiveTopology;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
@@ -539,7 +538,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
public void CreateBackgroundComputePipeline()
|
public void CreateBackgroundComputePipeline()
|
||||||
{
|
{
|
||||||
PipelineState pipeline = new();
|
PipelineState pipeline = new();
|
||||||
pipeline.Initialize(_gd.Capabilities);
|
pipeline.Initialize();
|
||||||
|
|
||||||
pipeline.Stages[0] = _shaders[0].GetInfo();
|
pipeline.Stages[0] = _shaders[0].GetInfo();
|
||||||
pipeline.StagesCount = 1;
|
pipeline.StagesCount = 1;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Silk.NET.Vulkan;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using Format = Ryujinx.Graphics.GAL.Format;
|
using Format = Ryujinx.Graphics.GAL.Format;
|
||||||
using VkBuffer = Silk.NET.Vulkan.Buffer;
|
using VkBuffer = Silk.NET.Vulkan.Buffer;
|
||||||
using VkFormat = Silk.NET.Vulkan.Format;
|
using VkFormat = Silk.NET.Vulkan.Format;
|
||||||
@@ -12,6 +13,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
class TextureStorage : IDisposable
|
class TextureStorage : IDisposable
|
||||||
{
|
{
|
||||||
|
private struct TextureSliceInfo
|
||||||
|
{
|
||||||
|
public int BindCount;
|
||||||
|
}
|
||||||
|
|
||||||
private const MemoryPropertyFlags DefaultImageMemoryFlags =
|
private const MemoryPropertyFlags DefaultImageMemoryFlags =
|
||||||
MemoryPropertyFlags.DeviceLocalBit;
|
MemoryPropertyFlags.DeviceLocalBit;
|
||||||
|
|
||||||
@@ -43,6 +49,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private readonly Image _image;
|
private readonly Image _image;
|
||||||
private readonly Auto<DisposableImage> _imageAuto;
|
private readonly Auto<DisposableImage> _imageAuto;
|
||||||
private readonly Auto<MemoryAllocation> _allocationAuto;
|
private readonly Auto<MemoryAllocation> _allocationAuto;
|
||||||
|
private readonly int _depthOrLayers;
|
||||||
private Auto<MemoryAllocation> _foreignAllocationAuto;
|
private Auto<MemoryAllocation> _foreignAllocationAuto;
|
||||||
|
|
||||||
private Dictionary<Format, TextureStorage> _aliasedStorages;
|
private Dictionary<Format, TextureStorage> _aliasedStorages;
|
||||||
@@ -55,6 +62,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private int _viewsCount;
|
private int _viewsCount;
|
||||||
private readonly ulong _size;
|
private readonly ulong _size;
|
||||||
|
|
||||||
|
private int _bindCount;
|
||||||
|
private readonly TextureSliceInfo[] _slices;
|
||||||
|
|
||||||
public VkFormat VkFormat { get; }
|
public VkFormat VkFormat { get; }
|
||||||
|
|
||||||
public unsafe TextureStorage(
|
public unsafe TextureStorage(
|
||||||
@@ -75,6 +85,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
var depth = (uint)(info.Target == Target.Texture3D ? info.Depth : 1);
|
var depth = (uint)(info.Target == Target.Texture3D ? info.Depth : 1);
|
||||||
|
|
||||||
VkFormat = format;
|
VkFormat = format;
|
||||||
|
_depthOrLayers = info.GetDepthOrLayers();
|
||||||
|
|
||||||
var type = info.Target.Convert();
|
var type = info.Target.Convert();
|
||||||
|
|
||||||
@@ -82,7 +93,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
var sampleCountFlags = ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)info.Samples);
|
var sampleCountFlags = ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)info.Samples);
|
||||||
|
|
||||||
var usage = GetImageUsage(info.Format, gd.Capabilities, isMsImageStorageSupported, true);
|
var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities);
|
||||||
|
|
||||||
var flags = ImageCreateFlags.CreateMutableFormatBit | ImageCreateFlags.CreateExtendedUsageBit;
|
var flags = ImageCreateFlags.CreateMutableFormatBit | ImageCreateFlags.CreateExtendedUsageBit;
|
||||||
|
|
||||||
@@ -150,6 +161,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
InitialTransition(ImageLayout.Preinitialized, ImageLayout.General);
|
InitialTransition(ImageLayout.Preinitialized, ImageLayout.General);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_slices = new TextureSliceInfo[levels * _depthOrLayers];
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextureStorage CreateAliasedColorForDepthStorageUnsafe(Format format)
|
public TextureStorage CreateAliasedColorForDepthStorageUnsafe(Format format)
|
||||||
@@ -294,7 +307,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ImageUsageFlags GetImageUsage(Format format, in HardwareCapabilities capabilities, bool isMsImageStorageSupported, bool extendedUsage)
|
public static ImageUsageFlags GetImageUsage(Format format, Target target, in HardwareCapabilities capabilities)
|
||||||
{
|
{
|
||||||
var usage = DefaultUsageFlags;
|
var usage = DefaultUsageFlags;
|
||||||
|
|
||||||
@@ -307,11 +320,19 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
usage |= ImageUsageFlags.ColorAttachmentBit;
|
usage |= ImageUsageFlags.ColorAttachmentBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((format.IsImageCompatible() && isMsImageStorageSupported) || extendedUsage)
|
bool isMsImageStorageSupported = capabilities.SupportsShaderStorageImageMultisample;
|
||||||
|
|
||||||
|
if (format.IsImageCompatible() && (isMsImageStorageSupported || !target.IsMultisample()))
|
||||||
{
|
{
|
||||||
usage |= ImageUsageFlags.StorageBit;
|
usage |= ImageUsageFlags.StorageBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (capabilities.SupportsAttachmentFeedbackLoop &&
|
||||||
|
(usage & (ImageUsageFlags.DepthStencilAttachmentBit | ImageUsageFlags.ColorAttachmentBit)) != 0)
|
||||||
|
{
|
||||||
|
usage |= ImageUsageFlags.AttachmentFeedbackLoopBitExt;
|
||||||
|
}
|
||||||
|
|
||||||
return usage;
|
return usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,6 +533,55 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddBinding(TextureView view)
|
||||||
|
{
|
||||||
|
// Assumes a view only has a first level.
|
||||||
|
|
||||||
|
int index = view.FirstLevel * _depthOrLayers + view.FirstLayer;
|
||||||
|
int layers = view.Layers;
|
||||||
|
|
||||||
|
for (int i = 0; i < layers; i++)
|
||||||
|
{
|
||||||
|
ref TextureSliceInfo info = ref _slices[index++];
|
||||||
|
|
||||||
|
info.BindCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_bindCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearBindings()
|
||||||
|
{
|
||||||
|
if (_bindCount != 0)
|
||||||
|
{
|
||||||
|
Array.Clear(_slices, 0, _slices.Length);
|
||||||
|
|
||||||
|
_bindCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool IsBound(TextureView view)
|
||||||
|
{
|
||||||
|
if (_bindCount != 0)
|
||||||
|
{
|
||||||
|
int index = view.FirstLevel * _depthOrLayers + view.FirstLayer;
|
||||||
|
int layers = view.Layers;
|
||||||
|
|
||||||
|
for (int i = 0; i < layers; i++)
|
||||||
|
{
|
||||||
|
ref TextureSliceInfo info = ref _slices[index++];
|
||||||
|
|
||||||
|
if (info.BindCount != 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public void IncrementViewsCount()
|
public void IncrementViewsCount()
|
||||||
{
|
{
|
||||||
_viewsCount++;
|
_viewsCount++;
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private readonly Auto<DisposableImageView> _imageView2dArray;
|
private readonly Auto<DisposableImageView> _imageView2dArray;
|
||||||
private Dictionary<Format, TextureView> _selfManagedViews;
|
private Dictionary<Format, TextureView> _selfManagedViews;
|
||||||
|
|
||||||
|
private int _hazardUses;
|
||||||
|
|
||||||
private readonly TextureCreateInfo _info;
|
private readonly TextureCreateInfo _info;
|
||||||
|
|
||||||
private HashTableSlim<RenderPassCacheKey, RenderPassHolder> _renderPasses;
|
private HashTableSlim<RenderPassCacheKey, RenderPassHolder> _renderPasses;
|
||||||
@@ -62,8 +64,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
bool isMsImageStorageSupported = gd.Capabilities.SupportsShaderStorageImageMultisample || !info.Target.IsMultisample();
|
bool isMsImageStorageSupported = gd.Capabilities.SupportsShaderStorageImageMultisample || !info.Target.IsMultisample();
|
||||||
|
|
||||||
var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format, isMsImageStorageSupported);
|
var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format, isMsImageStorageSupported);
|
||||||
var usage = TextureStorage.GetImageUsage(info.Format, gd.Capabilities, isMsImageStorageSupported, false);
|
var usage = TextureStorage.GetImageUsage(info.Format, info.Target, gd.Capabilities);
|
||||||
|
|
||||||
var levels = (uint)info.Levels;
|
var levels = (uint)info.Levels;
|
||||||
var layers = (uint)info.GetLayers();
|
var layers = (uint)info.GetLayers();
|
||||||
|
|
||||||
@@ -1037,6 +1038,34 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void PrepareForUsage(CommandBufferScoped cbs, PipelineStageFlags flags, List<TextureView> feedbackLoopHazards)
|
||||||
|
{
|
||||||
|
Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, flags);
|
||||||
|
|
||||||
|
if (feedbackLoopHazards != null && Storage.IsBound(this))
|
||||||
|
{
|
||||||
|
feedbackLoopHazards.Add(this);
|
||||||
|
_hazardUses++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearUsage(List<TextureView> feedbackLoopHazards)
|
||||||
|
{
|
||||||
|
if (_hazardUses != 0 && feedbackLoopHazards != null)
|
||||||
|
{
|
||||||
|
feedbackLoopHazards.Remove(this);
|
||||||
|
_hazardUses--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DecrementHazardUses()
|
||||||
|
{
|
||||||
|
if (_hazardUses != 0)
|
||||||
|
{
|
||||||
|
_hazardUses--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer(
|
public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer(
|
||||||
VulkanRenderer gd,
|
VulkanRenderer gd,
|
||||||
Device device,
|
Device device,
|
||||||
|
|||||||
@@ -73,22 +73,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_buffer = autoBuffer;
|
_buffer = autoBuffer;
|
||||||
|
|
||||||
if (!gd.Capabilities.SupportsExtendedDynamicState)
|
|
||||||
{
|
|
||||||
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)stride;
|
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)stride;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int size);
|
autoBuffer = gd.BufferManager.GetBuffer(cbs.CommandBuffer, _handle, false, out int size);
|
||||||
|
|
||||||
if (!gd.Capabilities.SupportsExtendedDynamicState)
|
|
||||||
{
|
|
||||||
// The original stride must be reapplied in case it was rewritten.
|
// The original stride must be reapplied in case it was rewritten.
|
||||||
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride;
|
state.Internal.VertexBindingDescriptions[DescriptorIndex].Stride = (uint)_stride;
|
||||||
}
|
|
||||||
|
|
||||||
if (_offset >= size)
|
if (_offset >= size)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
if (_count != 0)
|
if (_count != 0)
|
||||||
{
|
{
|
||||||
if (_gd.Capabilities.SupportsExtendedDynamicState && (_gd.SupportsMTL31 || !_gd.IsMoltenVk))
|
if (_gd.Capabilities.SupportsExtendedDynamicState)
|
||||||
{
|
{
|
||||||
_gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
|
_gd.ExtendedDynamicStateApi.CmdBindVertexBuffers2(
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
[
|
[
|
||||||
ExtConditionalRendering.ExtensionName,
|
ExtConditionalRendering.ExtensionName,
|
||||||
ExtExtendedDynamicState.ExtensionName,
|
ExtExtendedDynamicState.ExtensionName,
|
||||||
ExtExtendedDynamicState2.ExtensionName,
|
|
||||||
ExtTransformFeedback.ExtensionName,
|
ExtTransformFeedback.ExtensionName,
|
||||||
KhrDrawIndirectCount.ExtensionName,
|
KhrDrawIndirectCount.ExtensionName,
|
||||||
KhrPushDescriptor.ExtensionName,
|
KhrPushDescriptor.ExtensionName,
|
||||||
@@ -45,7 +44,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
"VK_KHR_portability_subset", // As per spec, we should enable this if present.
|
"VK_KHR_portability_subset", // As per spec, we should enable this if present.
|
||||||
"VK_EXT_4444_formats",
|
"VK_EXT_4444_formats",
|
||||||
"VK_KHR_8bit_storage",
|
"VK_KHR_8bit_storage",
|
||||||
"VK_KHR_maintenance2"
|
"VK_KHR_maintenance2",
|
||||||
|
"VK_EXT_attachment_feedback_loop_layout",
|
||||||
|
"VK_EXT_attachment_feedback_loop_dynamic_state"
|
||||||
];
|
];
|
||||||
|
|
||||||
private static readonly string[] _requiredExtensions =
|
private static readonly string[] _requiredExtensions =
|
||||||
@@ -315,17 +316,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
features2.PNext = &supportedFeaturesCustomBorderColor;
|
features2.PNext = &supportedFeaturesCustomBorderColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
PhysicalDeviceExtendedDynamicState2FeaturesEXT supportedFeaturesExtExtendedDynamicState2 = new()
|
|
||||||
{
|
|
||||||
SType = StructureType.PhysicalDeviceExtendedDynamicState2FeaturesExt,
|
|
||||||
PNext = features2.PNext,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState2.ExtensionName))
|
|
||||||
{
|
|
||||||
features2.PNext = &supportedFeaturesExtExtendedDynamicState2;
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT supportedFeaturesPrimitiveTopologyListRestart = new()
|
PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT supportedFeaturesPrimitiveTopologyListRestart = new()
|
||||||
{
|
{
|
||||||
SType = StructureType.PhysicalDevicePrimitiveTopologyListRestartFeaturesExt,
|
SType = StructureType.PhysicalDevicePrimitiveTopologyListRestartFeaturesExt,
|
||||||
@@ -371,6 +361,28 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
features2.PNext = &supportedFeaturesDepthClipControl;
|
features2.PNext = &supportedFeaturesDepthClipControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT supportedFeaturesAttachmentFeedbackLoopLayout = new()
|
||||||
|
{
|
||||||
|
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt,
|
||||||
|
PNext = features2.PNext,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout"))
|
||||||
|
{
|
||||||
|
features2.PNext = &supportedFeaturesAttachmentFeedbackLoopLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT supportedFeaturesDynamicAttachmentFeedbackLoopLayout = new()
|
||||||
|
{
|
||||||
|
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt,
|
||||||
|
PNext = features2.PNext,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state"))
|
||||||
|
{
|
||||||
|
features2.PNext = &supportedFeaturesDynamicAttachmentFeedbackLoopLayout;
|
||||||
|
}
|
||||||
|
|
||||||
PhysicalDeviceVulkan12Features supportedPhysicalDeviceVulkan12Features = new()
|
PhysicalDeviceVulkan12Features supportedPhysicalDeviceVulkan12Features = new()
|
||||||
{
|
{
|
||||||
SType = StructureType.PhysicalDeviceVulkan12Features,
|
SType = StructureType.PhysicalDeviceVulkan12Features,
|
||||||
@@ -406,7 +418,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
TessellationShader = supportedFeatures.TessellationShader,
|
TessellationShader = supportedFeatures.TessellationShader,
|
||||||
VertexPipelineStoresAndAtomics = supportedFeatures.VertexPipelineStoresAndAtomics,
|
VertexPipelineStoresAndAtomics = supportedFeatures.VertexPipelineStoresAndAtomics,
|
||||||
RobustBufferAccess = useRobustBufferAccess,
|
RobustBufferAccess = useRobustBufferAccess,
|
||||||
WideLines = supportedFeatures.WideLines,
|
|
||||||
SampleRateShading = supportedFeatures.SampleRateShading,
|
SampleRateShading = supportedFeatures.SampleRateShading,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -464,20 +475,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
pExtendedFeatures = &featuresExtendedDynamicState;
|
pExtendedFeatures = &featuresExtendedDynamicState;
|
||||||
|
|
||||||
if (physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState2.ExtensionName))
|
|
||||||
{
|
|
||||||
var featuresExtendedDynamicState2 = new PhysicalDeviceExtendedDynamicState2FeaturesEXT()
|
|
||||||
{
|
|
||||||
SType = StructureType.PhysicalDeviceExtendedDynamicState2FeaturesExt,
|
|
||||||
PNext = pExtendedFeatures,
|
|
||||||
ExtendedDynamicState2 = supportedFeaturesExtExtendedDynamicState2.ExtendedDynamicState2,
|
|
||||||
ExtendedDynamicState2LogicOp = supportedFeaturesExtExtendedDynamicState2.ExtendedDynamicState2LogicOp,
|
|
||||||
ExtendedDynamicState2PatchControlPoints = supportedFeaturesExtExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints,
|
|
||||||
};
|
|
||||||
|
|
||||||
pExtendedFeatures = &featuresExtendedDynamicState2;
|
|
||||||
}
|
|
||||||
|
|
||||||
var featuresVk11 = new PhysicalDeviceVulkan11Features
|
var featuresVk11 = new PhysicalDeviceVulkan11Features
|
||||||
{
|
{
|
||||||
SType = StructureType.PhysicalDeviceVulkan11Features,
|
SType = StructureType.PhysicalDeviceVulkan11Features,
|
||||||
@@ -560,6 +557,36 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
pExtendedFeatures = &featuresDepthClipControl;
|
pExtendedFeatures = &featuresDepthClipControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT featuresAttachmentFeedbackLoopLayout;
|
||||||
|
|
||||||
|
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout") &&
|
||||||
|
supportedFeaturesAttachmentFeedbackLoopLayout.AttachmentFeedbackLoopLayout)
|
||||||
|
{
|
||||||
|
featuresAttachmentFeedbackLoopLayout = new()
|
||||||
|
{
|
||||||
|
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt,
|
||||||
|
PNext = pExtendedFeatures,
|
||||||
|
AttachmentFeedbackLoopLayout = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
pExtendedFeatures = &featuresAttachmentFeedbackLoopLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT featuresDynamicAttachmentFeedbackLoopLayout;
|
||||||
|
|
||||||
|
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state") &&
|
||||||
|
supportedFeaturesDynamicAttachmentFeedbackLoopLayout.AttachmentFeedbackLoopDynamicState)
|
||||||
|
{
|
||||||
|
featuresDynamicAttachmentFeedbackLoopLayout = new()
|
||||||
|
{
|
||||||
|
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt,
|
||||||
|
PNext = pExtendedFeatures,
|
||||||
|
AttachmentFeedbackLoopDynamicState = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
pExtendedFeatures = &featuresDynamicAttachmentFeedbackLoopLayout;
|
||||||
|
}
|
||||||
|
|
||||||
var enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(physicalDevice.DeviceExtensions)).ToArray();
|
var enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(physicalDevice.DeviceExtensions)).ToArray();
|
||||||
|
|
||||||
IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length];
|
IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length];
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
internal KhrSwapchain SwapchainApi { get; private set; }
|
internal KhrSwapchain SwapchainApi { get; private set; }
|
||||||
internal ExtConditionalRendering ConditionalRenderingApi { get; private set; }
|
internal ExtConditionalRendering ConditionalRenderingApi { get; private set; }
|
||||||
internal ExtExtendedDynamicState ExtendedDynamicStateApi { get; private set; }
|
internal ExtExtendedDynamicState ExtendedDynamicStateApi { get; private set; }
|
||||||
internal ExtExtendedDynamicState2 ExtendedDynamicState2Api { get; private set; }
|
|
||||||
internal KhrPushDescriptor PushDescriptorApi { get; private set; }
|
internal KhrPushDescriptor PushDescriptorApi { get; private set; }
|
||||||
internal ExtTransformFeedback TransformFeedbackApi { get; private set; }
|
internal ExtTransformFeedback TransformFeedbackApi { get; private set; }
|
||||||
internal KhrDrawIndirectCount DrawIndirectCountApi { get; private set; }
|
internal KhrDrawIndirectCount DrawIndirectCountApi { get; private set; }
|
||||||
|
internal ExtAttachmentFeedbackLoopDynamicState DynamicFeedbackLoopApi { get; private set; }
|
||||||
|
|
||||||
internal uint QueueFamilyIndex { get; private set; }
|
internal uint QueueFamilyIndex { get; private set; }
|
||||||
internal Queue Queue { get; private set; }
|
internal Queue Queue { get; private set; }
|
||||||
@@ -93,7 +93,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
internal bool IsIntelArc { get; private set; }
|
internal bool IsIntelArc { get; private set; }
|
||||||
internal bool IsQualcommProprietary { get; private set; }
|
internal bool IsQualcommProprietary { get; private set; }
|
||||||
internal bool IsMoltenVk { get; private set; }
|
internal bool IsMoltenVk { get; private set; }
|
||||||
internal bool SupportsMTL31 { get; private set; }
|
|
||||||
internal bool IsTBDR { get; private set; }
|
internal bool IsTBDR { get; private set; }
|
||||||
internal bool IsSharedMemory { get; private set; }
|
internal bool IsSharedMemory { get; private set; }
|
||||||
|
|
||||||
@@ -122,8 +121,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
// Any device running on MacOS is using MoltenVK, even Intel and AMD vendors.
|
// Any device running on MacOS is using MoltenVK, even Intel and AMD vendors.
|
||||||
IsMoltenVk = true;
|
IsMoltenVk = true;
|
||||||
|
|
||||||
SupportsMTL31 = OperatingSystem.IsMacOSVersionAtLeast(14);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,11 +138,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
ExtendedDynamicStateApi = extendedDynamicStateApi;
|
ExtendedDynamicStateApi = extendedDynamicStateApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtExtendedDynamicState2 extendedDynamicState2Api))
|
|
||||||
{
|
|
||||||
ExtendedDynamicState2Api = extendedDynamicState2Api;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Api.TryGetDeviceExtension(_instance.Instance, _device, out KhrPushDescriptor pushDescriptorApi))
|
if (Api.TryGetDeviceExtension(_instance.Instance, _device, out KhrPushDescriptor pushDescriptorApi))
|
||||||
{
|
{
|
||||||
PushDescriptorApi = pushDescriptorApi;
|
PushDescriptorApi = pushDescriptorApi;
|
||||||
@@ -161,6 +153,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
DrawIndirectCountApi = drawIndirectCountApi;
|
DrawIndirectCountApi = drawIndirectCountApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtAttachmentFeedbackLoopDynamicState dynamicFeedbackLoopApi))
|
||||||
|
{
|
||||||
|
DynamicFeedbackLoopApi = dynamicFeedbackLoopApi;
|
||||||
|
}
|
||||||
|
|
||||||
if (maxQueueCount >= 2)
|
if (maxQueueCount >= 2)
|
||||||
{
|
{
|
||||||
Api.GetDeviceQueue(_device, queueFamilyIndex, 1, out var backgroundQueue);
|
Api.GetDeviceQueue(_device, queueFamilyIndex, 1, out var backgroundQueue);
|
||||||
@@ -235,11 +232,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
SType = StructureType.PhysicalDevicePrimitiveTopologyListRestartFeaturesExt,
|
SType = StructureType.PhysicalDevicePrimitiveTopologyListRestartFeaturesExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
PhysicalDeviceExtendedDynamicState2FeaturesEXT featuresExtendedDynamicState2 = new()
|
|
||||||
{
|
|
||||||
SType = StructureType.PhysicalDeviceExtendedDynamicState2FeaturesExt,
|
|
||||||
};
|
|
||||||
|
|
||||||
PhysicalDeviceRobustness2FeaturesEXT featuresRobustness2 = new()
|
PhysicalDeviceRobustness2FeaturesEXT featuresRobustness2 = new()
|
||||||
{
|
{
|
||||||
SType = StructureType.PhysicalDeviceRobustness2FeaturesExt,
|
SType = StructureType.PhysicalDeviceRobustness2FeaturesExt,
|
||||||
@@ -260,6 +252,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
SType = StructureType.PhysicalDeviceDepthClipControlFeaturesExt,
|
SType = StructureType.PhysicalDeviceDepthClipControlFeaturesExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT featuresAttachmentFeedbackLoop = new()
|
||||||
|
{
|
||||||
|
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt,
|
||||||
|
};
|
||||||
|
|
||||||
|
PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT featuresDynamicAttachmentFeedbackLoop = new()
|
||||||
|
{
|
||||||
|
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt,
|
||||||
|
};
|
||||||
|
|
||||||
PhysicalDevicePortabilitySubsetFeaturesKHR featuresPortabilitySubset = new()
|
PhysicalDevicePortabilitySubsetFeaturesKHR featuresPortabilitySubset = new()
|
||||||
{
|
{
|
||||||
SType = StructureType.PhysicalDevicePortabilitySubsetFeaturesKhr,
|
SType = StructureType.PhysicalDevicePortabilitySubsetFeaturesKhr,
|
||||||
@@ -270,12 +272,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
features2.PNext = &featuresPrimitiveTopologyListRestart;
|
features2.PNext = &featuresPrimitiveTopologyListRestart;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState2.ExtensionName))
|
|
||||||
{
|
|
||||||
featuresExtendedDynamicState2.PNext = features2.PNext;
|
|
||||||
features2.PNext = &featuresExtendedDynamicState2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_physicalDevice.IsDeviceExtensionPresent("VK_EXT_robustness2"))
|
if (_physicalDevice.IsDeviceExtensionPresent("VK_EXT_robustness2"))
|
||||||
{
|
{
|
||||||
featuresRobustness2.PNext = features2.PNext;
|
featuresRobustness2.PNext = features2.PNext;
|
||||||
@@ -302,6 +298,22 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
features2.PNext = &featuresDepthClipControl;
|
features2.PNext = &featuresDepthClipControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool supportsAttachmentFeedbackLoop = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout");
|
||||||
|
|
||||||
|
if (supportsAttachmentFeedbackLoop)
|
||||||
|
{
|
||||||
|
featuresAttachmentFeedbackLoop.PNext = features2.PNext;
|
||||||
|
features2.PNext = &featuresAttachmentFeedbackLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool supportsDynamicAttachmentFeedbackLoop = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state");
|
||||||
|
|
||||||
|
if (supportsDynamicAttachmentFeedbackLoop)
|
||||||
|
{
|
||||||
|
featuresDynamicAttachmentFeedbackLoop.PNext = features2.PNext;
|
||||||
|
features2.PNext = &featuresDynamicAttachmentFeedbackLoop;
|
||||||
|
}
|
||||||
|
|
||||||
bool usePortability = _physicalDevice.IsDeviceExtensionPresent("VK_KHR_portability_subset");
|
bool usePortability = _physicalDevice.IsDeviceExtensionPresent("VK_KHR_portability_subset");
|
||||||
|
|
||||||
if (usePortability)
|
if (usePortability)
|
||||||
@@ -393,10 +405,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
properties.Limits.FramebufferDepthSampleCounts &
|
properties.Limits.FramebufferDepthSampleCounts &
|
||||||
properties.Limits.FramebufferStencilSampleCounts;
|
properties.Limits.FramebufferStencilSampleCounts;
|
||||||
|
|
||||||
// Temporarily disable this, can be added back at a later date, make it easy to re-enable.
|
|
||||||
// Disabled because currently causing Device Lost error on NVIDIA.
|
|
||||||
featuresExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints = false;
|
|
||||||
|
|
||||||
Capabilities = new HardwareCapabilities(
|
Capabilities = new HardwareCapabilities(
|
||||||
_physicalDevice.IsDeviceExtensionPresent("VK_EXT_index_type_uint8"),
|
_physicalDevice.IsDeviceExtensionPresent("VK_EXT_index_type_uint8"),
|
||||||
supportsCustomBorderColor,
|
supportsCustomBorderColor,
|
||||||
@@ -413,8 +421,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
features2.Features.ShaderStorageImageMultisample,
|
features2.Features.ShaderStorageImageMultisample,
|
||||||
_physicalDevice.IsDeviceExtensionPresent(ExtConditionalRendering.ExtensionName),
|
_physicalDevice.IsDeviceExtensionPresent(ExtConditionalRendering.ExtensionName),
|
||||||
_physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState.ExtensionName),
|
_physicalDevice.IsDeviceExtensionPresent(ExtExtendedDynamicState.ExtensionName),
|
||||||
featuresExtendedDynamicState2,
|
|
||||||
_physicalDevice.PhysicalDeviceProperties.Limits.MaxTessellationPatchSize,
|
|
||||||
features2.Features.MultiViewport && !(IsMoltenVk && Vendor == Vendor.Amd), // Workaround for AMD on MoltenVK issue
|
features2.Features.MultiViewport && !(IsMoltenVk && Vendor == Vendor.Amd), // Workaround for AMD on MoltenVK issue
|
||||||
featuresRobustness2.NullDescriptor || IsMoltenVk,
|
featuresRobustness2.NullDescriptor || IsMoltenVk,
|
||||||
supportsPushDescriptors && !IsMoltenVk,
|
supportsPushDescriptors && !IsMoltenVk,
|
||||||
@@ -430,7 +436,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_physicalDevice.IsDeviceExtensionPresent("VK_NV_viewport_array2"),
|
_physicalDevice.IsDeviceExtensionPresent("VK_NV_viewport_array2"),
|
||||||
_physicalDevice.IsDeviceExtensionPresent(ExtExternalMemoryHost.ExtensionName),
|
_physicalDevice.IsDeviceExtensionPresent(ExtExternalMemoryHost.ExtensionName),
|
||||||
supportsDepthClipControl && featuresDepthClipControl.DepthClipControl,
|
supportsDepthClipControl && featuresDepthClipControl.DepthClipControl,
|
||||||
_physicalDevice.PhysicalDeviceFeatures.WideLines,
|
supportsAttachmentFeedbackLoop && featuresAttachmentFeedbackLoop.AttachmentFeedbackLoopLayout,
|
||||||
|
supportsDynamicAttachmentFeedbackLoop && featuresDynamicAttachmentFeedbackLoop.AttachmentFeedbackLoopDynamicState,
|
||||||
propertiesSubgroup.SubgroupSize,
|
propertiesSubgroup.SubgroupSize,
|
||||||
supportedSampleCounts,
|
supportedSampleCounts,
|
||||||
portabilityFlags,
|
portabilityFlags,
|
||||||
@@ -764,10 +771,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
supportsViewportSwizzle: false,
|
supportsViewportSwizzle: false,
|
||||||
supportsIndirectParameters: true,
|
supportsIndirectParameters: true,
|
||||||
supportsDepthClipControl: Capabilities.SupportsDepthClipControl,
|
supportsDepthClipControl: Capabilities.SupportsDepthClipControl,
|
||||||
supportsExtendedDynamicState: Capabilities.SupportsExtendedDynamicState,
|
|
||||||
supportsExtendedDynamicState2: Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2,
|
|
||||||
supportsLogicOpDynamicState: Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2LogicOp,
|
|
||||||
supportsPatchControlPointsDynamicState: Capabilities.SupportsExtendedDynamicState2.ExtendedDynamicState2PatchControlPoints,
|
|
||||||
uniformBufferSetIndex: PipelineBase.UniformSetIndex,
|
uniformBufferSetIndex: PipelineBase.UniformSetIndex,
|
||||||
storageBufferSetIndex: PipelineBase.StorageSetIndex,
|
storageBufferSetIndex: PipelineBase.StorageSetIndex,
|
||||||
textureSetIndex: PipelineBase.TextureSetIndex,
|
textureSetIndex: PipelineBase.TextureSetIndex,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ namespace Ryujinx.HLE.Generators
|
|||||||
var type = constructors.Where(x => x.ParameterList.Parameters.Count == 2).FirstOrDefault().ParameterList.Parameters[1].Type;
|
var type = constructors.Where(x => x.ParameterList.Parameters.Count == 2).FirstOrDefault().ParameterList.Parameters[1].Type;
|
||||||
var model = context.Compilation.GetSemanticModel(type.SyntaxTree);
|
var model = context.Compilation.GetSemanticModel(type.SyntaxTree);
|
||||||
var typeSymbol = model.GetSymbolInfo(type).Symbol as INamedTypeSymbol;
|
var typeSymbol = model.GetSymbolInfo(type).Symbol as INamedTypeSymbol;
|
||||||
var fullName = typeSymbol.ToString();
|
var fullName = typeSymbol?.ToString();
|
||||||
generator.EnterScope("if (parameter != null)");
|
generator.EnterScope("if (parameter != null)");
|
||||||
generator.AppendLine($"return new {GetFullName(className, context)}(context, ({fullName})parameter);");
|
generator.AppendLine($"return new {GetFullName(className, context)}(context, ({fullName})parameter);");
|
||||||
generator.LeaveScope();
|
generator.LeaveScope();
|
||||||
@@ -67,7 +67,7 @@ namespace Ryujinx.HLE.Generators
|
|||||||
{
|
{
|
||||||
var typeSymbol = context.Compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetDeclaredSymbol(syntaxNode);
|
var typeSymbol = context.Compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetDeclaredSymbol(syntaxNode);
|
||||||
|
|
||||||
return typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
return typeSymbol?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize(GeneratorInitializationContext context)
|
public void Initialize(GeneratorInitializationContext context)
|
||||||
|
|||||||
@@ -1054,8 +1054,6 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
verified = verifyKeys(lines, titlePattern);
|
verified = verifyKeys(lines, titlePattern);
|
||||||
break;
|
break;
|
||||||
case "console.keys":
|
case "console.keys":
|
||||||
verified = verifyKeys(lines, genericPattern);
|
|
||||||
break;
|
|
||||||
case "dev.keys":
|
case "dev.keys":
|
||||||
verified = verifyKeys(lines, genericPattern);
|
verified = verifyKeys(lines, genericPattern);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -2241,8 +2241,6 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
|
|||||||
|
|
||||||
return new CastExpression("reinterpret_cast", to, from);
|
return new CastExpression("reinterpret_cast", to, from);
|
||||||
case 'm':
|
case 'm':
|
||||||
_position += 2;
|
|
||||||
return ParseBinaryExpression("%");
|
|
||||||
case 'M':
|
case 'M':
|
||||||
_position += 2;
|
_position += 2;
|
||||||
return ParseBinaryExpression("%");
|
return ParseBinaryExpression("%");
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ namespace Ryujinx.HLE.HOS
|
|||||||
|
|
||||||
if (StrEquals(RomfsDir, modDir.Name))
|
if (StrEquals(RomfsDir, modDir.Name))
|
||||||
{
|
{
|
||||||
var modData = modMetadata.Mods.FirstOrDefault(x => modDir.FullName.Contains(x.Path));
|
var modData = modMetadata.Mods.FirstOrDefault(x => modDir.Parent.FullName.Equals(x.Path));
|
||||||
var enabled = modData?.Enabled ?? true;
|
var enabled = modData?.Enabled ?? true;
|
||||||
|
|
||||||
mods.RomfsDirs.Add(mod = new Mod<DirectoryInfo>(dir.Name, modDir, enabled));
|
mods.RomfsDirs.Add(mod = new Mod<DirectoryInfo>(dir.Name, modDir, enabled));
|
||||||
@@ -183,7 +183,7 @@ namespace Ryujinx.HLE.HOS
|
|||||||
}
|
}
|
||||||
else if (StrEquals(ExefsDir, modDir.Name))
|
else if (StrEquals(ExefsDir, modDir.Name))
|
||||||
{
|
{
|
||||||
var modData = modMetadata.Mods.FirstOrDefault(x => modDir.FullName.Contains(x.Path));
|
var modData = modMetadata.Mods.FirstOrDefault(x => modDir.Parent.FullName.Equals(x.Path));
|
||||||
var enabled = modData?.Enabled ?? true;
|
var enabled = modData?.Enabled ?? true;
|
||||||
|
|
||||||
mods.ExefsDirs.Add(mod = new Mod<DirectoryInfo>(dir.Name, modDir, enabled));
|
mods.ExefsDirs.Add(mod = new Mod<DirectoryInfo>(dir.Name, modDir, enabled));
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using Ryujinx.Common.Utilities;
|
|||||||
using Ryujinx.HLE.HOS.Services.Account.Acc.Types;
|
using Ryujinx.HLE.HOS.Services.Account.Acc.Types;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
|
|||||||
+13
@@ -269,6 +269,19 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
|||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[CommandCmif(29)] // 11.0.0+
|
||||||
|
// GetCacheStorageMax() -> (s32 cache_storage_index_max, s64 cache_storage_data_and_journal_size_max)
|
||||||
|
public ResultCode GetCacheStorageMax(ServiceCtx context)
|
||||||
|
{
|
||||||
|
ApplicationControlProperty nacp = context.Device.Processes.ActiveApplication.ApplicationControlProperties;
|
||||||
|
|
||||||
|
context.ResponseData.Write((Int32)nacp.CacheStorageIndexMax);
|
||||||
|
context.ResponseData.Write(0);
|
||||||
|
context.ResponseData.Write(nacp.CacheStorageDataAndJournalSizeMax);
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
[CommandCmif(30)]
|
[CommandCmif(30)]
|
||||||
// BeginBlockingHomeButtonShortAndLongPressed()
|
// BeginBlockingHomeButtonShortAndLongPressed()
|
||||||
public ResultCode BeginBlockingHomeButtonShortAndLongPressed(ServiceCtx context)
|
public ResultCode BeginBlockingHomeButtonShortAndLongPressed(ServiceCtx context)
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using Ryujinx.HLE.HOS.Services.Mii.Types;
|
|||||||
using Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption;
|
using Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption;
|
||||||
using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager;
|
using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv
|
|||||||
{
|
{
|
||||||
targetPrevAddress = InvalidAddress;
|
targetPrevAddress = InvalidAddress;
|
||||||
}
|
}
|
||||||
node = node.Previous;
|
node = node?.Previous;
|
||||||
_tree.Remove(prevAddress);
|
_tree.Remove(prevAddress);
|
||||||
_list.Remove(_dictionary[prevAddress]);
|
_list.Remove(_dictionary[prevAddress]);
|
||||||
_dictionary.Remove(prevAddress);
|
_dictionary.Remove(prevAddress);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy;
|
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy;
|
||||||
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|||||||
@@ -83,7 +83,6 @@ namespace Ryujinx.HLE.HOS.Services.Spl
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ConfigItem.SecurityEngineInterruptNumber:
|
case ConfigItem.SecurityEngineInterruptNumber:
|
||||||
return SmcResult.NotImplemented;
|
|
||||||
case ConfigItem.FuseVersion:
|
case ConfigItem.FuseVersion:
|
||||||
return SmcResult.NotImplemented;
|
return SmcResult.NotImplemented;
|
||||||
case ConfigItem.HardwareType:
|
case ConfigItem.HardwareType:
|
||||||
@@ -107,15 +106,10 @@ namespace Ryujinx.HLE.HOS.Services.Spl
|
|||||||
configValue = 0;
|
configValue = 0;
|
||||||
break;
|
break;
|
||||||
case ConfigItem.KernelConfiguration:
|
case ConfigItem.KernelConfiguration:
|
||||||
return SmcResult.NotImplemented;
|
|
||||||
case ConfigItem.IsChargerHiZModeEnabled:
|
case ConfigItem.IsChargerHiZModeEnabled:
|
||||||
return SmcResult.NotImplemented;
|
|
||||||
case ConfigItem.QuestState:
|
case ConfigItem.QuestState:
|
||||||
return SmcResult.NotImplemented;
|
|
||||||
case ConfigItem.RegulatorType:
|
case ConfigItem.RegulatorType:
|
||||||
return SmcResult.NotImplemented;
|
|
||||||
case ConfigItem.DeviceUniqueKeyGeneration:
|
case ConfigItem.DeviceUniqueKeyGeneration:
|
||||||
return SmcResult.NotImplemented;
|
|
||||||
case ConfigItem.Package2Hash:
|
case ConfigItem.Package2Hash:
|
||||||
return SmcResult.NotImplemented;
|
return SmcResult.NotImplemented;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace Ryujinx.HLE.Loaders.Mods
|
|||||||
/// Adds a patch in the form of an RLE (Fill mode).
|
/// Adds a patch in the form of an RLE (Fill mode).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="offset">Memory offset</param>
|
/// <param name="offset">Memory offset</param>
|
||||||
/// <param name="length"The fill length</param>
|
/// <param name="length">The fill length</param>
|
||||||
/// <param name="filler">The byte to fill</param>
|
/// <param name="filler">The byte to fill</param>
|
||||||
public void AddFill(uint offset, int length, byte filler)
|
public void AddFill(uint offset, int length, byte filler)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ namespace Ryujinx.HLE.UI
|
|||||||
/// <param name="value">The value associated to the <paramref name="kind"/>.</param>
|
/// <param name="value">The value associated to the <paramref name="kind"/>.</param>
|
||||||
void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value);
|
void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
/// Displays a Message Dialog box specific to Error Applet and blocks until it is closed.
|
/// Displays a Message Dialog box specific to Error Applet and blocks until it is closed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>False when OK is pressed, True when another button (Details) is pressed.</returns>
|
/// <returns>False when OK is pressed, True when another button (Details) is pressed.</returns>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using Ryujinx.Common.Configuration.Hid;
|
|||||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||||
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
|
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
|
||||||
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||||
|
using Ryujinx.Common.GraphicsDriver;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Logging.Targets;
|
using Ryujinx.Common.Logging.Targets;
|
||||||
using Ryujinx.Common.SystemInterop;
|
using Ryujinx.Common.SystemInterop;
|
||||||
@@ -462,6 +463,8 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
GraphicsConfig.ShadersDumpPath = option.GraphicsShadersDumpPath;
|
GraphicsConfig.ShadersDumpPath = option.GraphicsShadersDumpPath;
|
||||||
GraphicsConfig.EnableMacroHLE = !option.DisableMacroHLE;
|
GraphicsConfig.EnableMacroHLE = !option.DisableMacroHLE;
|
||||||
|
|
||||||
|
DriverUtilities.InitDriverConfig(option.BackendThreading == BackendThreading.Off);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
LoadApplication(option);
|
LoadApplication(option);
|
||||||
|
|||||||
@@ -418,7 +418,7 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
// Get screen touch position
|
// Get screen touch position
|
||||||
if (!_enableMouse)
|
if (!_enableMouse)
|
||||||
{
|
{
|
||||||
hasTouch = TouchScreenManager.Update(true, (_inputManager.MouseDriver as SDL2MouseDriver).IsButtonPressed(MouseButton.Button1), _aspectRatio.ToFloat());
|
hasTouch = TouchScreenManager.Update(true, ((SDL2MouseDriver)_inputManager.MouseDriver).IsButtonPressed(MouseButton.Button1), _aspectRatio.ToFloat());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasTouch)
|
if (!hasTouch)
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ namespace Ryujinx.Horizon.Kernel.Generators
|
|||||||
{
|
{
|
||||||
string name = methodParameter.Identifier.Text;
|
string name = methodParameter.Identifier.Text;
|
||||||
string argName = GetPrefixedArgName(name);
|
string argName = GetPrefixedArgName(name);
|
||||||
string typeName = methodParameter.Type.ToString();
|
string typeName = methodParameter.Type?.ToString();
|
||||||
string canonicalTypeName = GetCanonicalTypeName(compilation, methodParameter.Type);
|
string canonicalTypeName = GetCanonicalTypeName(compilation, methodParameter.Type);
|
||||||
|
|
||||||
if (methodParameter.Modifiers.Any(SyntaxKind.OutKeyword))
|
if (methodParameter.Modifiers.Any(SyntaxKind.OutKeyword))
|
||||||
@@ -329,7 +329,7 @@ namespace Ryujinx.Horizon.Kernel.Generators
|
|||||||
{
|
{
|
||||||
string name = methodParameter.Identifier.Text;
|
string name = methodParameter.Identifier.Text;
|
||||||
string argName = GetPrefixedArgName(name);
|
string argName = GetPrefixedArgName(name);
|
||||||
string typeName = methodParameter.Type.ToString();
|
string typeName = methodParameter.Type?.ToString();
|
||||||
string canonicalTypeName = GetCanonicalTypeName(compilation, methodParameter.Type);
|
string canonicalTypeName = GetCanonicalTypeName(compilation, methodParameter.Type);
|
||||||
|
|
||||||
if (methodParameter.Modifiers.Any(SyntaxKind.OutKeyword))
|
if (methodParameter.Modifiers.Any(SyntaxKind.OutKeyword))
|
||||||
@@ -415,9 +415,9 @@ namespace Ryujinx.Horizon.Kernel.Generators
|
|||||||
private static string GetCanonicalTypeName(Compilation compilation, SyntaxNode syntaxNode)
|
private static string GetCanonicalTypeName(Compilation compilation, SyntaxNode syntaxNode)
|
||||||
{
|
{
|
||||||
TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
|
TypeInfo typeInfo = compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetTypeInfo(syntaxNode);
|
||||||
if (typeInfo.Type.ContainingNamespace == null)
|
if (typeInfo.Type?.ContainingNamespace == null)
|
||||||
{
|
{
|
||||||
return typeInfo.Type.Name;
|
return typeInfo.Type?.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"{typeInfo.Type.ContainingNamespace.ToDisplayString()}.{typeInfo.Type.Name}";
|
return $"{typeInfo.Type.ContainingNamespace.ToDisplayString()}.{typeInfo.Type.Name}";
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using Ryujinx.Common;
|
|||||||
using Ryujinx.Horizon.Common;
|
using Ryujinx.Horizon.Common;
|
||||||
using Ryujinx.Horizon.Sdk.Sf;
|
using Ryujinx.Horizon.Sdk.Sf;
|
||||||
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Horizon.Sdk.Codec.Detail
|
namespace Ryujinx.Horizon.Sdk.Codec.Detail
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Horizon.Sdk.OsTypes
|
namespace Ryujinx.Horizon.Sdk.OsTypes
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.SDL2.Common;
|
using Ryujinx.SDL2.Common;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -36,6 +37,7 @@ namespace Ryujinx.Input.SDL2
|
|||||||
SDL2Driver.Instance.Initialize();
|
SDL2Driver.Instance.Initialize();
|
||||||
SDL2Driver.Instance.OnJoyStickConnected += HandleJoyStickConnected;
|
SDL2Driver.Instance.OnJoyStickConnected += HandleJoyStickConnected;
|
||||||
SDL2Driver.Instance.OnJoystickDisconnected += HandleJoyStickDisconnected;
|
SDL2Driver.Instance.OnJoystickDisconnected += HandleJoyStickDisconnected;
|
||||||
|
SDL2Driver.Instance.OnJoyBatteryUpdated += HandleJoyBatteryUpdated;
|
||||||
|
|
||||||
// Add already connected gamepads
|
// Add already connected gamepads
|
||||||
int numJoysticks = SDL_NumJoysticks();
|
int numJoysticks = SDL_NumJoysticks();
|
||||||
@@ -57,16 +59,19 @@ namespace Ryujinx.Input.SDL2
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the first 4 char of the guid (CRC part) to make it stable
|
||||||
|
string guidString = "0000" + guid.ToString().Substring(4);
|
||||||
|
|
||||||
string id;
|
string id;
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
int guidIndex = 0;
|
int guidIndex = 0;
|
||||||
id = guidIndex + "-" + guid;
|
id = guidIndex + "-" + guidString;
|
||||||
|
|
||||||
while (_gamepadsIds.Contains(id))
|
while (_gamepadsIds.Contains(id))
|
||||||
{
|
{
|
||||||
id = (++guidIndex) + "-" + guid;
|
id = (++guidIndex) + "-" + guidString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +88,8 @@ namespace Ryujinx.Input.SDL2
|
|||||||
|
|
||||||
private void HandleJoyStickDisconnected(int joystickInstanceId)
|
private void HandleJoyStickDisconnected(int joystickInstanceId)
|
||||||
{
|
{
|
||||||
|
bool joyConPairDisconnected = false;
|
||||||
|
|
||||||
if (_gamepadsInstanceIdsMapping.TryGetValue(joystickInstanceId, out string id))
|
if (_gamepadsInstanceIdsMapping.TryGetValue(joystickInstanceId, out string id))
|
||||||
{
|
{
|
||||||
_gamepadsInstanceIdsMapping.Remove(joystickInstanceId);
|
_gamepadsInstanceIdsMapping.Remove(joystickInstanceId);
|
||||||
@@ -90,14 +97,25 @@ namespace Ryujinx.Input.SDL2
|
|||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
_gamepadsIds.Remove(id);
|
_gamepadsIds.Remove(id);
|
||||||
|
if (!SDL2JoyConPair.IsCombinable(_gamepadsIds))
|
||||||
|
{
|
||||||
|
_gamepadsIds.Remove(SDL2JoyConPair.Id);
|
||||||
|
joyConPairDisconnected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OnGamepadDisconnected?.Invoke(id);
|
OnGamepadDisconnected?.Invoke(id);
|
||||||
|
if (joyConPairDisconnected)
|
||||||
|
{
|
||||||
|
OnGamepadDisconnected?.Invoke(SDL2JoyConPair.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleJoyStickConnected(int joystickDeviceId, int joystickInstanceId)
|
private void HandleJoyStickConnected(int joystickDeviceId, int joystickInstanceId)
|
||||||
{
|
{
|
||||||
|
bool joyConPairConnected = false;
|
||||||
|
|
||||||
if (SDL_IsGameController(joystickDeviceId) == SDL_bool.SDL_TRUE)
|
if (SDL_IsGameController(joystickDeviceId) == SDL_bool.SDL_TRUE)
|
||||||
{
|
{
|
||||||
if (_gamepadsInstanceIdsMapping.ContainsKey(joystickInstanceId))
|
if (_gamepadsInstanceIdsMapping.ContainsKey(joystickInstanceId))
|
||||||
@@ -122,12 +140,30 @@ namespace Ryujinx.Input.SDL2
|
|||||||
_gamepadsIds.Insert(joystickDeviceId, id);
|
_gamepadsIds.Insert(joystickDeviceId, id);
|
||||||
else
|
else
|
||||||
_gamepadsIds.Add(id);
|
_gamepadsIds.Add(id);
|
||||||
|
|
||||||
|
if (SDL2JoyConPair.IsCombinable(_gamepadsIds))
|
||||||
|
{
|
||||||
|
_gamepadsIds.Remove(SDL2JoyConPair.Id);
|
||||||
|
_gamepadsIds.Add(SDL2JoyConPair.Id);
|
||||||
|
joyConPairConnected = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OnGamepadConnected?.Invoke(id);
|
OnGamepadConnected?.Invoke(id);
|
||||||
|
if (joyConPairConnected)
|
||||||
|
{
|
||||||
|
OnGamepadConnected?.Invoke(SDL2JoyConPair.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleJoyBatteryUpdated(int joystickDeviceId, SDL_JoystickPowerLevel powerLevel)
|
||||||
|
{
|
||||||
|
Logger.Info?.Print(LogClass.Hid,
|
||||||
|
$"{SDL_GameControllerNameForIndex(joystickDeviceId)} power level: {powerLevel}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
@@ -159,6 +195,14 @@ namespace Ryujinx.Input.SDL2
|
|||||||
|
|
||||||
public IGamepad GetGamepad(string id)
|
public IGamepad GetGamepad(string id)
|
||||||
{
|
{
|
||||||
|
if (id == SDL2JoyConPair.Id)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
return SDL2JoyConPair.GetGamepad(_gamepadsIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int joystickIndex = GetJoystickIndexByGamepadId(id);
|
int joystickIndex = GetJoystickIndexByGamepadId(id);
|
||||||
|
|
||||||
if (joystickIndex == -1)
|
if (joystickIndex == -1)
|
||||||
@@ -173,6 +217,11 @@ namespace Ryujinx.Input.SDL2
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SDL_GameControllerName(gamepadHandle).StartsWith(SDL2JoyCon.Prefix))
|
||||||
|
{
|
||||||
|
return new SDL2JoyCon(gamepadHandle, id);
|
||||||
|
}
|
||||||
|
|
||||||
return new SDL2Gamepad(gamepadHandle, id);
|
return new SDL2Gamepad(gamepadHandle, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,414 @@
|
|||||||
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
|
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Threading;
|
||||||
|
using static SDL2.SDL;
|
||||||
|
|
||||||
|
namespace Ryujinx.Input.SDL2
|
||||||
|
{
|
||||||
|
internal class SDL2JoyCon : IGamepad
|
||||||
|
{
|
||||||
|
private bool HasConfiguration => _configuration != null;
|
||||||
|
|
||||||
|
private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From)
|
||||||
|
{
|
||||||
|
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not GamepadButtonInputId.Unbound;
|
||||||
|
}
|
||||||
|
|
||||||
|
private StandardControllerInputConfig _configuration;
|
||||||
|
|
||||||
|
private readonly Dictionary<GamepadButtonInputId,SDL_GameControllerButton> _leftButtonsDriverMapping = new()
|
||||||
|
{
|
||||||
|
{ GamepadButtonInputId.LeftStick , SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSTICK },
|
||||||
|
{GamepadButtonInputId.DpadUp ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_Y},
|
||||||
|
{GamepadButtonInputId.DpadDown ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A},
|
||||||
|
{GamepadButtonInputId.DpadLeft ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B},
|
||||||
|
{GamepadButtonInputId.DpadRight ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X},
|
||||||
|
{GamepadButtonInputId.Minus ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START},
|
||||||
|
{GamepadButtonInputId.LeftShoulder,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE2},
|
||||||
|
{GamepadButtonInputId.LeftTrigger,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE4},
|
||||||
|
{GamepadButtonInputId.SingleRightTrigger0,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
|
||||||
|
{GamepadButtonInputId.SingleLeftTrigger0,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
|
||||||
|
};
|
||||||
|
private readonly Dictionary<GamepadButtonInputId,SDL_GameControllerButton> _rightButtonsDriverMapping = new()
|
||||||
|
{
|
||||||
|
{GamepadButtonInputId.RightStick,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSTICK},
|
||||||
|
{GamepadButtonInputId.A,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B},
|
||||||
|
{GamepadButtonInputId.B,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_Y},
|
||||||
|
{GamepadButtonInputId.X,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A},
|
||||||
|
{GamepadButtonInputId.Y,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X},
|
||||||
|
{GamepadButtonInputId.Plus,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START},
|
||||||
|
{GamepadButtonInputId.RightShoulder,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE1},
|
||||||
|
{GamepadButtonInputId.RightTrigger,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE3},
|
||||||
|
{GamepadButtonInputId.SingleRightTrigger1,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
|
||||||
|
{GamepadButtonInputId.SingleLeftTrigger1,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER}
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly Dictionary<GamepadButtonInputId, SDL_GameControllerButton> _buttonsDriverMapping;
|
||||||
|
private readonly Lock _userMappingLock = new();
|
||||||
|
|
||||||
|
private readonly List<ButtonMappingEntry> _buttonsUserMapping;
|
||||||
|
|
||||||
|
private readonly StickInputId[] _stickUserMapping =
|
||||||
|
[
|
||||||
|
StickInputId.Unbound, StickInputId.Left, StickInputId.Right
|
||||||
|
];
|
||||||
|
|
||||||
|
public GamepadFeaturesFlag Features { get; }
|
||||||
|
|
||||||
|
private nint _gamepadHandle;
|
||||||
|
|
||||||
|
private enum JoyConType
|
||||||
|
{
|
||||||
|
Left, Right
|
||||||
|
}
|
||||||
|
|
||||||
|
public const string Prefix = "Nintendo Switch Joy-Con";
|
||||||
|
public const string LeftName = "Nintendo Switch Joy-Con (L)";
|
||||||
|
public const string RightName = "Nintendo Switch Joy-Con (R)";
|
||||||
|
|
||||||
|
private readonly JoyConType _joyConType;
|
||||||
|
|
||||||
|
public SDL2JoyCon(nint gamepadHandle, string driverId)
|
||||||
|
{
|
||||||
|
_gamepadHandle = gamepadHandle;
|
||||||
|
_buttonsUserMapping = new List<ButtonMappingEntry>(10);
|
||||||
|
|
||||||
|
Name = SDL_GameControllerName(_gamepadHandle);
|
||||||
|
Id = driverId;
|
||||||
|
Features = GetFeaturesFlag();
|
||||||
|
|
||||||
|
// Enable motion tracking
|
||||||
|
if (Features.HasFlag(GamepadFeaturesFlag.Motion))
|
||||||
|
{
|
||||||
|
if (SDL_GameControllerSetSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL,
|
||||||
|
SDL_bool.SDL_TRUE) != 0)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Hid,
|
||||||
|
$"Could not enable data reporting for SensorType {SDL_SensorType.SDL_SENSOR_ACCEL}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SDL_GameControllerSetSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO,
|
||||||
|
SDL_bool.SDL_TRUE) != 0)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Hid,
|
||||||
|
$"Could not enable data reporting for SensorType {SDL_SensorType.SDL_SENSOR_GYRO}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (Name)
|
||||||
|
{
|
||||||
|
case LeftName:
|
||||||
|
{
|
||||||
|
_buttonsDriverMapping = _leftButtonsDriverMapping;
|
||||||
|
_joyConType = JoyConType.Left;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RightName:
|
||||||
|
{
|
||||||
|
_buttonsDriverMapping = _rightButtonsDriverMapping;
|
||||||
|
_joyConType = JoyConType.Right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private GamepadFeaturesFlag GetFeaturesFlag()
|
||||||
|
{
|
||||||
|
GamepadFeaturesFlag result = GamepadFeaturesFlag.None;
|
||||||
|
|
||||||
|
if (SDL_GameControllerHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL) == SDL_bool.SDL_TRUE &&
|
||||||
|
SDL_GameControllerHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO) == SDL_bool.SDL_TRUE)
|
||||||
|
{
|
||||||
|
result |= GamepadFeaturesFlag.Motion;
|
||||||
|
}
|
||||||
|
|
||||||
|
int error = SDL_GameControllerRumble(_gamepadHandle, 0, 0, 100);
|
||||||
|
|
||||||
|
if (error == 0)
|
||||||
|
{
|
||||||
|
result |= GamepadFeaturesFlag.Rumble;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Id { get; }
|
||||||
|
public string Name { get; }
|
||||||
|
public bool IsConnected => SDL_GameControllerGetAttached(_gamepadHandle) == SDL_bool.SDL_TRUE;
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && _gamepadHandle != nint.Zero)
|
||||||
|
{
|
||||||
|
SDL_GameControllerClose(_gamepadHandle);
|
||||||
|
|
||||||
|
_gamepadHandle = nint.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void SetTriggerThreshold(float triggerThreshold)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||||
|
{
|
||||||
|
if (!Features.HasFlag(GamepadFeaturesFlag.Rumble))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ushort lowFrequencyRaw = (ushort)(lowFrequency * ushort.MaxValue);
|
||||||
|
ushort highFrequencyRaw = (ushort)(highFrequency * ushort.MaxValue);
|
||||||
|
|
||||||
|
if (durationMs == uint.MaxValue)
|
||||||
|
{
|
||||||
|
if (SDL_GameControllerRumble(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, SDL_HAPTIC_INFINITY) !=
|
||||||
|
0)
|
||||||
|
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
|
||||||
|
}
|
||||||
|
else if (durationMs > SDL_HAPTIC_INFINITY)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Hid, $"Unsupported rumble duration {durationMs}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (SDL_GameControllerRumble(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, durationMs) != 0)
|
||||||
|
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 GetMotionData(MotionInputId inputId)
|
||||||
|
{
|
||||||
|
SDL_SensorType sensorType = inputId switch
|
||||||
|
{
|
||||||
|
MotionInputId.Accelerometer => SDL_SensorType.SDL_SENSOR_ACCEL,
|
||||||
|
MotionInputId.Gyroscope => SDL_SensorType.SDL_SENSOR_GYRO,
|
||||||
|
_ => SDL_SensorType.SDL_SENSOR_INVALID
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!Features.HasFlag(GamepadFeaturesFlag.Motion) || sensorType is SDL_SensorType.SDL_SENSOR_INVALID)
|
||||||
|
return Vector3.Zero;
|
||||||
|
|
||||||
|
const int ElementCount = 3;
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
float* values = stackalloc float[ElementCount];
|
||||||
|
|
||||||
|
int result = SDL_GameControllerGetSensorData(_gamepadHandle, sensorType, (nint)values, ElementCount);
|
||||||
|
|
||||||
|
if (result != 0)
|
||||||
|
return Vector3.Zero;
|
||||||
|
|
||||||
|
Vector3 value = _joyConType switch
|
||||||
|
{
|
||||||
|
JoyConType.Left => new Vector3(-values[2], values[1], values[0]),
|
||||||
|
JoyConType.Right => new Vector3(values[2], values[1], -values[0]),
|
||||||
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
|
};
|
||||||
|
|
||||||
|
return inputId switch
|
||||||
|
{
|
||||||
|
MotionInputId.Gyroscope => RadToDegree(value),
|
||||||
|
MotionInputId.Accelerometer => GsToMs2(value),
|
||||||
|
_ => value
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector3 RadToDegree(Vector3 rad) => rad * (180 / MathF.PI);
|
||||||
|
|
||||||
|
private static Vector3 GsToMs2(Vector3 gs) => gs / SDL_STANDARD_GRAVITY;
|
||||||
|
|
||||||
|
public void SetConfiguration(InputConfig configuration)
|
||||||
|
{
|
||||||
|
lock (_userMappingLock)
|
||||||
|
{
|
||||||
|
_configuration = (StandardControllerInputConfig)configuration;
|
||||||
|
|
||||||
|
_buttonsUserMapping.Clear();
|
||||||
|
|
||||||
|
// First update sticks
|
||||||
|
_stickUserMapping[(int)StickInputId.Left] = (StickInputId)_configuration.LeftJoyconStick.Joystick;
|
||||||
|
_stickUserMapping[(int)StickInputId.Right] = (StickInputId)_configuration.RightJoyconStick.Joystick;
|
||||||
|
|
||||||
|
|
||||||
|
switch (_joyConType)
|
||||||
|
{
|
||||||
|
case JoyConType.Left:
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (GamepadButtonInputId)_configuration.LeftJoyconStick.StickButton));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (GamepadButtonInputId)_configuration.LeftJoycon.DpadUp));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown, (GamepadButtonInputId)_configuration.LeftJoycon.DpadDown));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft, (GamepadButtonInputId)_configuration.LeftJoycon.DpadLeft));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight, (GamepadButtonInputId)_configuration.LeftJoycon.DpadRight));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonMinus));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonL));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonZl));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonSr));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonSl));
|
||||||
|
break;
|
||||||
|
case JoyConType.Right:
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick, (GamepadButtonInputId)_configuration.RightJoyconStick.StickButton));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A, (GamepadButtonInputId)_configuration.RightJoycon.ButtonA));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B, (GamepadButtonInputId)_configuration.RightJoycon.ButtonB));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X, (GamepadButtonInputId)_configuration.RightJoycon.ButtonX));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y, (GamepadButtonInputId)_configuration.RightJoycon.ButtonY));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus, (GamepadButtonInputId)_configuration.RightJoycon.ButtonPlus));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder, (GamepadButtonInputId)_configuration.RightJoycon.ButtonR));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (GamepadButtonInputId)_configuration.RightJoycon.ButtonZr));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, (GamepadButtonInputId)_configuration.RightJoycon.ButtonSr));
|
||||||
|
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (GamepadButtonInputId)_configuration.RightJoycon.ButtonSl));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
SetTriggerThreshold(_configuration.TriggerThreshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetLed(uint packedRgb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public GamepadStateSnapshot GetStateSnapshot()
|
||||||
|
{
|
||||||
|
return IGamepad.GetStateSnapshot(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||||
|
{
|
||||||
|
GamepadStateSnapshot rawState = GetStateSnapshot();
|
||||||
|
GamepadStateSnapshot result = default;
|
||||||
|
|
||||||
|
lock (_userMappingLock)
|
||||||
|
{
|
||||||
|
if (_buttonsUserMapping.Count == 0)
|
||||||
|
return rawState;
|
||||||
|
|
||||||
|
|
||||||
|
// ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
|
||||||
|
foreach (ButtonMappingEntry entry in _buttonsUserMapping)
|
||||||
|
{
|
||||||
|
if (!entry.IsValid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Do not touch state of button already pressed
|
||||||
|
if (!result.IsPressed(entry.To))
|
||||||
|
{
|
||||||
|
result.SetPressed(entry.To, rawState.IsPressed(entry.From));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(float leftStickX, float leftStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Left]);
|
||||||
|
(float rightStickX, float rightStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Right]);
|
||||||
|
|
||||||
|
result.SetStick(StickInputId.Left, leftStickX, leftStickY);
|
||||||
|
result.SetStick(StickInputId.Right, rightStickX, rightStickY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static float ConvertRawStickValue(short value)
|
||||||
|
{
|
||||||
|
const float ConvertRate = 1.0f / (short.MaxValue + 0.5f);
|
||||||
|
|
||||||
|
return value * ConvertRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JoyconConfigControllerStick<GamepadInputId, Common.Configuration.Hid.Controller.StickInputId>
|
||||||
|
GetLogicalJoyStickConfig(StickInputId inputId)
|
||||||
|
{
|
||||||
|
switch (inputId)
|
||||||
|
{
|
||||||
|
case StickInputId.Left:
|
||||||
|
if (_configuration.RightJoyconStick.Joystick ==
|
||||||
|
Common.Configuration.Hid.Controller.StickInputId.Left)
|
||||||
|
return _configuration.RightJoyconStick;
|
||||||
|
else
|
||||||
|
return _configuration.LeftJoyconStick;
|
||||||
|
case StickInputId.Right:
|
||||||
|
if (_configuration.LeftJoyconStick.Joystick ==
|
||||||
|
Common.Configuration.Hid.Controller.StickInputId.Right)
|
||||||
|
return _configuration.LeftJoyconStick;
|
||||||
|
else
|
||||||
|
return _configuration.RightJoyconStick;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public (float, float) GetStick(StickInputId inputId)
|
||||||
|
{
|
||||||
|
if (inputId == StickInputId.Unbound)
|
||||||
|
return (0.0f, 0.0f);
|
||||||
|
|
||||||
|
if (inputId == StickInputId.Left && _joyConType == JoyConType.Right || inputId == StickInputId.Right && _joyConType == JoyConType.Left)
|
||||||
|
{
|
||||||
|
return (0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
(short stickX, short stickY) = GetStickXY();
|
||||||
|
|
||||||
|
float resultX = ConvertRawStickValue(stickX);
|
||||||
|
float resultY = -ConvertRawStickValue(stickY);
|
||||||
|
|
||||||
|
if (HasConfiguration)
|
||||||
|
{
|
||||||
|
var joyconStickConfig = GetLogicalJoyStickConfig(inputId);
|
||||||
|
|
||||||
|
if (joyconStickConfig != null)
|
||||||
|
{
|
||||||
|
if (joyconStickConfig.InvertStickX)
|
||||||
|
resultX = -resultX;
|
||||||
|
|
||||||
|
if (joyconStickConfig.InvertStickY)
|
||||||
|
resultY = -resultY;
|
||||||
|
|
||||||
|
if (joyconStickConfig.Rotate90CW)
|
||||||
|
{
|
||||||
|
float temp = resultX;
|
||||||
|
resultX = resultY;
|
||||||
|
resultY = -temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return inputId switch
|
||||||
|
{
|
||||||
|
StickInputId.Left when _joyConType == JoyConType.Left => (resultY, -resultX),
|
||||||
|
StickInputId.Right when _joyConType == JoyConType.Right => (-resultY, resultX),
|
||||||
|
_ => (0.0f, 0.0f)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private (short, short) GetStickXY()
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTX),
|
||||||
|
SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTY));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPressed(GamepadButtonInputId inputId)
|
||||||
|
{
|
||||||
|
if (!_buttonsDriverMapping.TryGetValue(inputId, out var button))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SDL_GameControllerGetButton(_gamepadHandle, button) == 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using static SDL2.SDL;
|
||||||
|
|
||||||
|
namespace Ryujinx.Input.SDL2
|
||||||
|
{
|
||||||
|
internal class SDL2JoyConPair(IGamepad left, IGamepad right) : IGamepad
|
||||||
|
{
|
||||||
|
public GamepadFeaturesFlag Features => (left?.Features ?? GamepadFeaturesFlag.None) |
|
||||||
|
(right?.Features ?? GamepadFeaturesFlag.None);
|
||||||
|
|
||||||
|
public const string Id = "JoyConPair";
|
||||||
|
string IGamepad.Id => Id;
|
||||||
|
|
||||||
|
public string Name => "* Nintendo Switch Joy-Con (L/R)";
|
||||||
|
public bool IsConnected => left is { IsConnected: true } && right is { IsConnected: true };
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
left?.Dispose();
|
||||||
|
right?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||||
|
{
|
||||||
|
return GetStateSnapshot();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 GetMotionData(MotionInputId inputId)
|
||||||
|
{
|
||||||
|
return inputId switch
|
||||||
|
{
|
||||||
|
MotionInputId.Accelerometer or
|
||||||
|
MotionInputId.Gyroscope => left.GetMotionData(inputId),
|
||||||
|
MotionInputId.SecondAccelerometer => right.GetMotionData(MotionInputId.Accelerometer),
|
||||||
|
MotionInputId.SecondGyroscope => right.GetMotionData(MotionInputId.Gyroscope),
|
||||||
|
_ => Vector3.Zero
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public GamepadStateSnapshot GetStateSnapshot()
|
||||||
|
{
|
||||||
|
return IGamepad.GetStateSnapshot(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public (float, float) GetStick(StickInputId inputId)
|
||||||
|
{
|
||||||
|
return inputId switch
|
||||||
|
{
|
||||||
|
StickInputId.Left => left.GetStick(StickInputId.Left),
|
||||||
|
StickInputId.Right => right.GetStick(StickInputId.Right),
|
||||||
|
_ => (0, 0)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPressed(GamepadButtonInputId inputId)
|
||||||
|
{
|
||||||
|
return left.IsPressed(inputId) || right.IsPressed(inputId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||||
|
{
|
||||||
|
if (lowFrequency != 0)
|
||||||
|
{
|
||||||
|
right.Rumble(lowFrequency, lowFrequency, durationMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (highFrequency != 0)
|
||||||
|
{
|
||||||
|
left.Rumble(highFrequency, highFrequency, durationMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lowFrequency == 0 && highFrequency == 0)
|
||||||
|
{
|
||||||
|
left.Rumble(0, 0, durationMs);
|
||||||
|
right.Rumble(0, 0, durationMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetConfiguration(InputConfig configuration)
|
||||||
|
{
|
||||||
|
left.SetConfiguration(configuration);
|
||||||
|
right.SetConfiguration(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetLed(uint packedRgb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTriggerThreshold(float triggerThreshold)
|
||||||
|
{
|
||||||
|
left.SetTriggerThreshold(triggerThreshold);
|
||||||
|
right.SetTriggerThreshold(triggerThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsCombinable(List<string> gamepadsIds)
|
||||||
|
{
|
||||||
|
(int leftIndex, int rightIndex) = DetectJoyConPair(gamepadsIds);
|
||||||
|
return leftIndex >= 0 && rightIndex >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (int leftIndex, int rightIndex) DetectJoyConPair(List<string> gamepadsIds)
|
||||||
|
{
|
||||||
|
var gamepadNames = gamepadsIds.Where(gamepadId => gamepadId != Id)
|
||||||
|
.Select((_, index) => SDL_GameControllerNameForIndex(index)).ToList();
|
||||||
|
int leftIndex = gamepadNames.IndexOf(SDL2JoyCon.LeftName);
|
||||||
|
int rightIndex = gamepadNames.IndexOf(SDL2JoyCon.RightName);
|
||||||
|
|
||||||
|
return (leftIndex, rightIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IGamepad GetGamepad(List<string> gamepadsIds)
|
||||||
|
{
|
||||||
|
(int leftIndex, int rightIndex) = DetectJoyConPair(gamepadsIds);
|
||||||
|
if (leftIndex == -1 || rightIndex == -1)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
nint leftGamepadHandle = SDL_GameControllerOpen(leftIndex);
|
||||||
|
nint rightGamepadHandle = SDL_GameControllerOpen(rightIndex);
|
||||||
|
|
||||||
|
if (leftGamepadHandle == nint.Zero || rightGamepadHandle == nint.Zero)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return new SDL2JoyConPair(new SDL2JoyCon(leftGamepadHandle, gamepadsIds[leftIndex]),
|
||||||
|
new SDL2JoyCon(rightGamepadHandle, gamepadsIds[rightIndex]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -269,10 +269,12 @@ namespace Ryujinx.Input.HLE
|
|||||||
if (motionConfig.MotionBackend != MotionInputBackendType.CemuHook)
|
if (motionConfig.MotionBackend != MotionInputBackendType.CemuHook)
|
||||||
{
|
{
|
||||||
_leftMotionInput = new MotionInput();
|
_leftMotionInput = new MotionInput();
|
||||||
|
_rightMotionInput = new MotionInput();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_leftMotionInput = null;
|
_leftMotionInput = null;
|
||||||
|
_rightMotionInput = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,11 +302,24 @@ namespace Ryujinx.Input.HLE
|
|||||||
_leftMotionInput.Update(accelerometer, gyroscope, (ulong)PerformanceCounter.ElapsedNanoseconds / 1000, controllerConfig.Motion.Sensitivity, (float)controllerConfig.Motion.GyroDeadzone);
|
_leftMotionInput.Update(accelerometer, gyroscope, (ulong)PerformanceCounter.ElapsedNanoseconds / 1000, controllerConfig.Motion.Sensitivity, (float)controllerConfig.Motion.GyroDeadzone);
|
||||||
|
|
||||||
if (controllerConfig.ControllerType == ConfigControllerType.JoyconPair)
|
if (controllerConfig.ControllerType == ConfigControllerType.JoyconPair)
|
||||||
|
{
|
||||||
|
if (gamepad.Id == "JoyConPair")
|
||||||
|
{
|
||||||
|
Vector3 rightAccelerometer = gamepad.GetMotionData(MotionInputId.SecondAccelerometer);
|
||||||
|
Vector3 rightGyroscope = gamepad.GetMotionData(MotionInputId.SecondGyroscope);
|
||||||
|
|
||||||
|
rightAccelerometer = new Vector3(rightAccelerometer.X, -rightAccelerometer.Z, rightAccelerometer.Y);
|
||||||
|
rightGyroscope = new Vector3(rightGyroscope.X, -rightGyroscope.Z, rightGyroscope.Y);
|
||||||
|
|
||||||
|
_rightMotionInput.Update(rightAccelerometer, rightGyroscope, (ulong)PerformanceCounter.ElapsedNanoseconds / 1000, controllerConfig.Motion.Sensitivity, (float)controllerConfig.Motion.GyroDeadzone);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
_rightMotionInput = _leftMotionInput;
|
_rightMotionInput = _leftMotionInput;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (controllerConfig.Motion.MotionBackend == MotionInputBackendType.CemuHook && controllerConfig.Motion is CemuHookMotionConfigController cemuControllerConfig)
|
else if (controllerConfig.Motion.MotionBackend == MotionInputBackendType.CemuHook && controllerConfig.Motion is CemuHookMotionConfigController cemuControllerConfig)
|
||||||
{
|
{
|
||||||
int clientId = (int)controllerConfig.PlayerIndex;
|
int clientId = (int)controllerConfig.PlayerIndex;
|
||||||
@@ -336,6 +351,7 @@ namespace Ryujinx.Input.HLE
|
|||||||
// Reset states
|
// Reset states
|
||||||
State = default;
|
State = default;
|
||||||
_leftMotionInput = null;
|
_leftMotionInput = null;
|
||||||
|
_rightMotionInput = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,5 +21,17 @@ namespace Ryujinx.Input
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>Values are in degrees</remarks>
|
/// <remarks>Values are in degrees</remarks>
|
||||||
Gyroscope,
|
Gyroscope,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Second accelerometer.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Values are in m/s^2</remarks>
|
||||||
|
SecondAccelerometer,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Second gyroscope.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Values are in degrees</remarks>
|
||||||
|
SecondGyroscope
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Ryujinx.Memory.Range;
|
using Ryujinx.Memory.Range;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Ryujinx.Memory
|
namespace Ryujinx.Memory
|
||||||
|
|||||||
@@ -31,9 +31,13 @@ namespace Ryujinx.SDL2.Common
|
|||||||
private uint _refereceCount;
|
private uint _refereceCount;
|
||||||
private Thread _worker;
|
private Thread _worker;
|
||||||
|
|
||||||
|
private const uint SDL_JOYBATTERYUPDATED = 1543;
|
||||||
|
|
||||||
public event Action<int, int> OnJoyStickConnected;
|
public event Action<int, int> OnJoyStickConnected;
|
||||||
public event Action<int> OnJoystickDisconnected;
|
public event Action<int> OnJoystickDisconnected;
|
||||||
|
|
||||||
|
public event Action<int, SDL_JoystickPowerLevel> OnJoyBatteryUpdated;
|
||||||
|
|
||||||
private ConcurrentDictionary<uint, Action<SDL_Event>> _registeredWindowHandlers;
|
private ConcurrentDictionary<uint, Action<SDL_Event>> _registeredWindowHandlers;
|
||||||
|
|
||||||
private readonly Lock _lock = new();
|
private readonly Lock _lock = new();
|
||||||
@@ -143,6 +147,10 @@ namespace Ryujinx.SDL2.Common
|
|||||||
|
|
||||||
OnJoystickDisconnected?.Invoke(evnt.cbutton.which);
|
OnJoystickDisconnected?.Invoke(evnt.cbutton.which);
|
||||||
}
|
}
|
||||||
|
else if ((uint)evnt.type == SDL_JOYBATTERYUPDATED)
|
||||||
|
{
|
||||||
|
OnJoyBatteryUpdated?.Invoke(evnt.cbutton.which, (SDL_JoystickPowerLevel)evnt.user.code);
|
||||||
|
}
|
||||||
else if (evnt.type == SDL_EventType.SDL_WINDOWEVENT || evnt.type == SDL_EventType.SDL_MOUSEBUTTONDOWN || evnt.type == SDL_EventType.SDL_MOUSEBUTTONUP)
|
else if (evnt.type == SDL_EventType.SDL_WINDOWEVENT || evnt.type == SDL_EventType.SDL_MOUSEBUTTONDOWN || evnt.type == SDL_EventType.SDL_MOUSEBUTTONUP)
|
||||||
{
|
{
|
||||||
if (_registeredWindowHandlers.TryGetValue(evnt.window.windowID, out Action<SDL_Event> handler))
|
if (_registeredWindowHandlers.TryGetValue(evnt.window.windowID, out Action<SDL_Event> handler))
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Tests.Cpu
|
namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -795,10 +795,9 @@ namespace Ryujinx.UI.App.Common
|
|||||||
{
|
{
|
||||||
ldnWebHost = DefaultLanPlayWebHost;
|
ldnWebHost = DefaultLanPlayWebHost;
|
||||||
}
|
}
|
||||||
IEnumerable<LdnGameData> ldnGameDataArray = Array.Empty<LdnGameData>();
|
|
||||||
using HttpClient httpClient = new HttpClient();
|
using HttpClient httpClient = new HttpClient();
|
||||||
string ldnGameDataArrayString = await httpClient.GetStringAsync($"https://{ldnWebHost}/api/public_games");
|
string ldnGameDataArrayString = await httpClient.GetStringAsync($"https://{ldnWebHost}/api/public_games");
|
||||||
ldnGameDataArray = JsonHelper.Deserialize(ldnGameDataArrayString, _ldnDataSerializerContext.IEnumerableLdnGameData);
|
IEnumerable<LdnGameData> ldnGameDataArray = JsonHelper.Deserialize(ldnGameDataArrayString, _ldnDataSerializerContext.IEnumerableLdnGameData);
|
||||||
var evt = new LdnGameDataReceivedEventArgs
|
var evt = new LdnGameDataReceivedEventArgs
|
||||||
{
|
{
|
||||||
LdnData = ldnGameDataArray
|
LdnData = ldnGameDataArray
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current version of the file format
|
/// The current version of the file format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int CurrentVersion = 56;
|
public const int CurrentVersion = 57;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version of the configuration file format
|
/// Version of the configuration file format
|
||||||
@@ -164,7 +164,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
public bool ShowConfirmExit { get; set; }
|
public bool ShowConfirmExit { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ignore "Applet" dialog
|
/// Ignore Controller Applet dialog
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IgnoreApplet { get; set; }
|
public bool IgnoreApplet { get; set; }
|
||||||
|
|
||||||
@@ -355,6 +355,11 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool StartFullscreen { get; set; }
|
public bool StartFullscreen { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start games with UI hidden
|
||||||
|
/// </summary>
|
||||||
|
public bool StartNoUI { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Show console window
|
/// Show console window
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ using Ryujinx.UI.Common.Helper;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.Json.Nodes;
|
|
||||||
|
|
||||||
namespace Ryujinx.UI.Common.Configuration
|
namespace Ryujinx.UI.Common.Configuration
|
||||||
{
|
{
|
||||||
@@ -89,9 +88,9 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// <summary>
|
|
||||||
/// Determines main window start-up position, size and state
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// Determines main window start-up position, size and state
|
||||||
|
/// </summary>
|
||||||
public class WindowStartupSettings
|
public class WindowStartupSettings
|
||||||
{
|
{
|
||||||
public ReactiveObject<int> WindowSizeWidth { get; private set; }
|
public ReactiveObject<int> WindowSizeWidth { get; private set; }
|
||||||
@@ -165,6 +164,11 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ReactiveObject<bool> StartFullscreen { get; private set; }
|
public ReactiveObject<bool> StartFullscreen { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start games with UI hidden
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> StartNoUI { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Hide / Show Console Window
|
/// Hide / Show Console Window
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -207,6 +211,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
CustomThemePath = new ReactiveObject<string>();
|
CustomThemePath = new ReactiveObject<string>();
|
||||||
BaseStyle = new ReactiveObject<string>();
|
BaseStyle = new ReactiveObject<string>();
|
||||||
StartFullscreen = new ReactiveObject<bool>();
|
StartFullscreen = new ReactiveObject<bool>();
|
||||||
|
StartNoUI = new ReactiveObject<bool>();
|
||||||
GameListViewMode = new ReactiveObject<int>();
|
GameListViewMode = new ReactiveObject<int>();
|
||||||
ShowNames = new ReactiveObject<bool>();
|
ShowNames = new ReactiveObject<bool>();
|
||||||
GridSize = new ReactiveObject<int>();
|
GridSize = new ReactiveObject<int>();
|
||||||
@@ -679,9 +684,9 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
public ReactiveObject<bool> ShowConfirmExit { get; private set; }
|
public ReactiveObject<bool> ShowConfirmExit { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ignore Applet
|
/// Ignore Controller Applet
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ReactiveObject<bool> IgnoreApplet { get; private set; }
|
public ReactiveObject<bool> IgnoreControllerApplet { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables or disables save window size, position and state on close.
|
/// Enables or disables save window size, position and state on close.
|
||||||
@@ -709,7 +714,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
EnableDiscordIntegration = new ReactiveObject<bool>();
|
EnableDiscordIntegration = new ReactiveObject<bool>();
|
||||||
CheckUpdatesOnStart = new ReactiveObject<bool>();
|
CheckUpdatesOnStart = new ReactiveObject<bool>();
|
||||||
ShowConfirmExit = new ReactiveObject<bool>();
|
ShowConfirmExit = new ReactiveObject<bool>();
|
||||||
IgnoreApplet = new ReactiveObject<bool>();
|
IgnoreControllerApplet = new ReactiveObject<bool>();
|
||||||
RememberWindowState = new ReactiveObject<bool>();
|
RememberWindowState = new ReactiveObject<bool>();
|
||||||
EnableHardwareAcceleration = new ReactiveObject<bool>();
|
EnableHardwareAcceleration = new ReactiveObject<bool>();
|
||||||
HideCursor = new ReactiveObject<HideCursorMode>();
|
HideCursor = new ReactiveObject<HideCursorMode>();
|
||||||
@@ -748,7 +753,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
EnableDiscordIntegration = EnableDiscordIntegration,
|
EnableDiscordIntegration = EnableDiscordIntegration,
|
||||||
CheckUpdatesOnStart = CheckUpdatesOnStart,
|
CheckUpdatesOnStart = CheckUpdatesOnStart,
|
||||||
ShowConfirmExit = ShowConfirmExit,
|
ShowConfirmExit = ShowConfirmExit,
|
||||||
IgnoreApplet = IgnoreApplet,
|
IgnoreApplet = IgnoreControllerApplet,
|
||||||
RememberWindowState = RememberWindowState,
|
RememberWindowState = RememberWindowState,
|
||||||
EnableHardwareAcceleration = EnableHardwareAcceleration,
|
EnableHardwareAcceleration = EnableHardwareAcceleration,
|
||||||
HideCursor = HideCursor,
|
HideCursor = HideCursor,
|
||||||
@@ -818,6 +823,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
ApplicationSort = UI.ApplicationSort,
|
ApplicationSort = UI.ApplicationSort,
|
||||||
IsAscendingOrder = UI.IsAscendingOrder,
|
IsAscendingOrder = UI.IsAscendingOrder,
|
||||||
StartFullscreen = UI.StartFullscreen,
|
StartFullscreen = UI.StartFullscreen,
|
||||||
|
StartNoUI = UI.StartNoUI,
|
||||||
ShowConsole = UI.ShowConsole,
|
ShowConsole = UI.ShowConsole,
|
||||||
EnableKeyboard = Hid.EnableKeyboard,
|
EnableKeyboard = Hid.EnableKeyboard,
|
||||||
EnableMouse = Hid.EnableMouse,
|
EnableMouse = Hid.EnableMouse,
|
||||||
@@ -866,12 +872,12 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
EnableDiscordIntegration.Value = true;
|
EnableDiscordIntegration.Value = true;
|
||||||
CheckUpdatesOnStart.Value = true;
|
CheckUpdatesOnStart.Value = true;
|
||||||
ShowConfirmExit.Value = true;
|
ShowConfirmExit.Value = true;
|
||||||
IgnoreApplet.Value = false;
|
IgnoreControllerApplet.Value = false;
|
||||||
RememberWindowState.Value = true;
|
RememberWindowState.Value = true;
|
||||||
EnableHardwareAcceleration.Value = true;
|
EnableHardwareAcceleration.Value = true;
|
||||||
HideCursor.Value = HideCursorMode.OnIdle;
|
HideCursor.Value = HideCursorMode.OnIdle;
|
||||||
Graphics.VSyncMode.Value = VSyncMode.Switch;
|
Graphics.VSyncMode.Value = VSyncMode.Switch;
|
||||||
Graphics.CustomVSyncInterval.Value = 60;
|
Graphics.CustomVSyncInterval.Value = 120;
|
||||||
Graphics.EnableCustomVSyncInterval.Value = false;
|
Graphics.EnableCustomVSyncInterval.Value = false;
|
||||||
Graphics.EnableShaderCache.Value = true;
|
Graphics.EnableShaderCache.Value = true;
|
||||||
Graphics.EnableTextureRecompression.Value = false;
|
Graphics.EnableTextureRecompression.Value = false;
|
||||||
@@ -1610,7 +1616,16 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
CustomVSyncIntervalDecrement = Key.Unbound,
|
CustomVSyncIntervalDecrement = Key.Unbound,
|
||||||
};
|
};
|
||||||
|
|
||||||
configurationFileFormat.CustomVSyncInterval = 60;
|
configurationFileFormat.CustomVSyncInterval = 120;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 57)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 57.");
|
||||||
|
|
||||||
|
configurationFileFormat.StartNoUI = false;
|
||||||
|
|
||||||
configurationFileUpdated = true;
|
configurationFileUpdated = true;
|
||||||
}
|
}
|
||||||
@@ -1645,7 +1660,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
EnableDiscordIntegration.Value = configurationFileFormat.EnableDiscordIntegration;
|
EnableDiscordIntegration.Value = configurationFileFormat.EnableDiscordIntegration;
|
||||||
CheckUpdatesOnStart.Value = configurationFileFormat.CheckUpdatesOnStart;
|
CheckUpdatesOnStart.Value = configurationFileFormat.CheckUpdatesOnStart;
|
||||||
ShowConfirmExit.Value = configurationFileFormat.ShowConfirmExit;
|
ShowConfirmExit.Value = configurationFileFormat.ShowConfirmExit;
|
||||||
IgnoreApplet.Value = configurationFileFormat.IgnoreApplet;
|
IgnoreControllerApplet.Value = configurationFileFormat.IgnoreApplet;
|
||||||
RememberWindowState.Value = configurationFileFormat.RememberWindowState;
|
RememberWindowState.Value = configurationFileFormat.RememberWindowState;
|
||||||
EnableHardwareAcceleration.Value = configurationFileFormat.EnableHardwareAcceleration;
|
EnableHardwareAcceleration.Value = configurationFileFormat.EnableHardwareAcceleration;
|
||||||
HideCursor.Value = configurationFileFormat.HideCursor;
|
HideCursor.Value = configurationFileFormat.HideCursor;
|
||||||
@@ -1697,6 +1712,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
UI.GridSize.Value = configurationFileFormat.GridSize;
|
UI.GridSize.Value = configurationFileFormat.GridSize;
|
||||||
UI.ApplicationSort.Value = configurationFileFormat.ApplicationSort;
|
UI.ApplicationSort.Value = configurationFileFormat.ApplicationSort;
|
||||||
UI.StartFullscreen.Value = configurationFileFormat.StartFullscreen;
|
UI.StartFullscreen.Value = configurationFileFormat.StartFullscreen;
|
||||||
|
UI.StartNoUI.Value = configurationFileFormat.StartNoUI;
|
||||||
UI.ShowConsole.Value = configurationFileFormat.ShowConsole;
|
UI.ShowConsole.Value = configurationFileFormat.ShowConsole;
|
||||||
UI.WindowStartup.WindowSizeWidth.Value = configurationFileFormat.WindowStartup.WindowSizeWidth;
|
UI.WindowStartup.WindowSizeWidth.Value = configurationFileFormat.WindowStartup.WindowSizeWidth;
|
||||||
UI.WindowStartup.WindowSizeHeight.Value = configurationFileFormat.WindowStartup.WindowSizeHeight;
|
UI.WindowStartup.WindowSizeHeight.Value = configurationFileFormat.WindowStartup.WindowSizeHeight;
|
||||||
|
|||||||
@@ -99,16 +99,13 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
Dictionary<ulong, ContentMetaData> updates =
|
Dictionary<ulong, ContentMetaData> updates =
|
||||||
pfs.GetContentData(ContentMetaType.Patch, vfs, checkLevel);
|
pfs.GetContentData(ContentMetaType.Patch, vfs, checkLevel);
|
||||||
|
|
||||||
Nca patchNca = null;
|
|
||||||
Nca controlNca = null;
|
|
||||||
|
|
||||||
if (!updates.TryGetValue(applicationIdBase, out ContentMetaData content))
|
if (!updates.TryGetValue(applicationIdBase, out ContentMetaData content))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
patchNca = content.GetNcaByType(vfs.KeySet, ContentType.Program);
|
Nca patchNca = content.GetNcaByType(vfs.KeySet, ContentType.Program);
|
||||||
controlNca = content.GetNcaByType(vfs.KeySet, ContentType.Control);
|
Nca controlNca = content.GetNcaByType(vfs.KeySet, ContentType.Control);
|
||||||
|
|
||||||
if (controlNca == null || patchNca == null)
|
if (controlNca == null || patchNca == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
public static ThemeVariant DetectSystemTheme()
|
public static ThemeVariant DetectSystemTheme()
|
||||||
{
|
{
|
||||||
if (Application.Current is App app)
|
if (Current is App app)
|
||||||
{
|
{
|
||||||
var colorValues = app.PlatformSettings.GetColorValues();
|
var colorValues = app.PlatformSettings.GetColorValues();
|
||||||
|
|
||||||
|
|||||||
@@ -414,11 +414,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
string filename = $"{sanitizedApplicationName}_{currentTime.Year}-{currentTime.Month:D2}-{currentTime.Day:D2}_{currentTime.Hour:D2}-{currentTime.Minute:D2}-{currentTime.Second:D2}.png";
|
string filename = $"{sanitizedApplicationName}_{currentTime.Year}-{currentTime.Month:D2}-{currentTime.Day:D2}_{currentTime.Hour:D2}-{currentTime.Minute:D2}-{currentTime.Second:D2}.png";
|
||||||
|
|
||||||
string directory = AppDataManager.Mode switch
|
string directory = Path.Combine(AppDataManager.BaseDirPath, "screenshots");
|
||||||
{
|
|
||||||
AppDataManager.LaunchMode.Portable or AppDataManager.LaunchMode.Custom => Path.Combine(AppDataManager.BaseDirPath, "screenshots"),
|
|
||||||
_ => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "Ryujinx"),
|
|
||||||
};
|
|
||||||
|
|
||||||
string path = Path.Combine(directory, filename);
|
string path = Path.Combine(directory, filename);
|
||||||
|
|
||||||
@@ -1031,7 +1027,7 @@ namespace Ryujinx.Ava
|
|||||||
_viewModel.WindowState = WindowState.FullScreen;
|
_viewModel.WindowState = WindowState.FullScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_viewModel.WindowState == WindowState.FullScreen)
|
if (_viewModel.WindowState == WindowState.FullScreen || _viewModel.StartGamesWithoutUI)
|
||||||
{
|
{
|
||||||
_viewModel.ShowMenuAndStatusBar = false;
|
_viewModel.ShowMenuAndStatusBar = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,7 +162,6 @@
|
|||||||
"SettingsTabSystemDramSize10GiB": "10GiB",
|
"SettingsTabSystemDramSize10GiB": "10GiB",
|
||||||
"SettingsTabSystemDramSize12GiB": "12GiB",
|
"SettingsTabSystemDramSize12GiB": "12GiB",
|
||||||
"SettingsTabSystemIgnoreMissingServices": "تجاهل الخدمات المفقودة",
|
"SettingsTabSystemIgnoreMissingServices": "تجاهل الخدمات المفقودة",
|
||||||
"SettingsTabSystemIgnoreApplet": "Ignore Applet",
|
|
||||||
"SettingsTabGraphics": "الرسومات",
|
"SettingsTabGraphics": "الرسومات",
|
||||||
"SettingsTabGraphicsAPI": "API الرسومات ",
|
"SettingsTabGraphicsAPI": "API الرسومات ",
|
||||||
"SettingsTabGraphicsEnableShaderCache": "تفعيل ذاكرة المظللات المؤقتة",
|
"SettingsTabGraphicsEnableShaderCache": "تفعيل ذاكرة المظللات المؤقتة",
|
||||||
@@ -549,8 +548,9 @@
|
|||||||
"AboutDiscordUrlTooltipMessage": "انقر لفتح دعوة إلى خادم ريوجينكس في ديكسورد في متصفحك الافتراضي.",
|
"AboutDiscordUrlTooltipMessage": "انقر لفتح دعوة إلى خادم ريوجينكس في ديكسورد في متصفحك الافتراضي.",
|
||||||
"AboutTwitterUrlTooltipMessage": "انقر لفتح صفحة ريوجينكس في تويتر في متصفحك الافتراضي.",
|
"AboutTwitterUrlTooltipMessage": "انقر لفتح صفحة ريوجينكس في تويتر في متصفحك الافتراضي.",
|
||||||
"AboutRyujinxAboutTitle": "حول:",
|
"AboutRyujinxAboutTitle": "حول:",
|
||||||
"AboutRyujinxAboutContent": "ريوجينكس هو محاكي لجهاز نينتندو سويتش™.\nمن فضلك ادعمنا على باتريون.\nاحصل على آخر الأخبار على تويتر أو ديسكورد.\nيمكن للمطورين المهتمين بالمساهمة معرفة المزيد على غيت هاب أو ديسكورد.",
|
"AboutRyujinxAboutContent": "ريوجينكس هو محاكي لجهاز نينتندو سويتش™.\n\nيمكن للمطورين المهتمين بالمساهمة معرفة المزيد على غيت هاب.",
|
||||||
"AboutRyujinxMaintainersTitle": "تتم صيانته بواسطة:",
|
"AboutRyujinxMaintainersTitle": "تتم صيانته بواسطة:",
|
||||||
|
"AboutRyujinxFormerMaintainersTitle": "تم صيانتها سابقًا بواسطة:",
|
||||||
"AboutRyujinxMaintainersContentTooltipMessage": "انقر لفتح صفحة المساهمين في متصفحك الافتراضي.",
|
"AboutRyujinxMaintainersContentTooltipMessage": "انقر لفتح صفحة المساهمين في متصفحك الافتراضي.",
|
||||||
"AboutRyujinxSupprtersTitle": "مدعوم على باتريون بواسطة:",
|
"AboutRyujinxSupprtersTitle": "مدعوم على باتريون بواسطة:",
|
||||||
"AmiiboSeriesLabel": "مجموعة أميبو",
|
"AmiiboSeriesLabel": "مجموعة أميبو",
|
||||||
@@ -601,7 +601,6 @@
|
|||||||
"UseHypervisorTooltip": "استخدم هايبرڤايزور بدلا من JIT. يعمل على تحسين الأداء بشكل كبير عند توفره، ولكنه قد يكون غير مستقر في حالته الحالية.",
|
"UseHypervisorTooltip": "استخدم هايبرڤايزور بدلا من JIT. يعمل على تحسين الأداء بشكل كبير عند توفره، ولكنه قد يكون غير مستقر في حالته الحالية.",
|
||||||
"DRamTooltip": "يستخدم تخطيط وضع الذاكرة البديل لتقليد نموذج سويتش المطورين.\n\nيعد هذا مفيدا فقط لحزم النسيج عالية الدقة أو تعديلات دقة 4K. لا يحسن الأداء.\n\nاتركه معطلا إذا لم تكن متأكدا.",
|
"DRamTooltip": "يستخدم تخطيط وضع الذاكرة البديل لتقليد نموذج سويتش المطورين.\n\nيعد هذا مفيدا فقط لحزم النسيج عالية الدقة أو تعديلات دقة 4K. لا يحسن الأداء.\n\nاتركه معطلا إذا لم تكن متأكدا.",
|
||||||
"IgnoreMissingServicesTooltip": "يتجاهل خدمات نظام هوريزون غير المنفذة. قد يساعد هذا في تجاوز الأعطال عند تشغيل ألعاب معينة.\n\nاتركه معطلا إذا كنت غير متأكد.",
|
"IgnoreMissingServicesTooltip": "يتجاهل خدمات نظام هوريزون غير المنفذة. قد يساعد هذا في تجاوز الأعطال عند تشغيل ألعاب معينة.\n\nاتركه معطلا إذا كنت غير متأكد.",
|
||||||
"IgnoreAppletTooltip": "لن يظهر مربع الحوار الخارجي \"تطبيق وحدة التحكم\" إذا تم فصل لوحة الألعاب أثناء اللعب. ولن تظهر مطالبة بإغلاق مربع الحوار أو إعداد وحدة تحكم جديدة. وبمجرد إعادة توصيل وحدة التحكم التي تم فصلها سابقًا، ستستأنف اللعبة تلقائيًا.",
|
|
||||||
"GraphicsBackendThreadingTooltip": "ينفذ أوامر الواجهة الخلفية للرسومات على مسار ثاني.\n\nيعمل على تسريع عملية تجميع المظللات وتقليل التقطيع وتحسين الأداء على برامج تشغيل وحدة الرسوميات دون دعم المسارات المتعددة الخاصة بهم. أداء أفضل قليلا على برامج التشغيل ذات المسارات المتعددة.\n\nاضبط على تلقائي إذا لم تكن متأكدا.",
|
"GraphicsBackendThreadingTooltip": "ينفذ أوامر الواجهة الخلفية للرسومات على مسار ثاني.\n\nيعمل على تسريع عملية تجميع المظللات وتقليل التقطيع وتحسين الأداء على برامج تشغيل وحدة الرسوميات دون دعم المسارات المتعددة الخاصة بهم. أداء أفضل قليلا على برامج التشغيل ذات المسارات المتعددة.\n\nاضبط على تلقائي إذا لم تكن متأكدا.",
|
||||||
"GalThreadingTooltip": "ينفذ أوامر الواجهة الخلفية للرسومات على مسار ثاني.\n\nيعمل على تسريع عملية تجميع المظللات وتقليل التقطيع وتحسين الأداء على برامج تشغيل وحدة الرسوميات دون دعم المسارات المتعددة الخاصة بهم. أداء أفضل قليلا على برامج التشغيل ذات المسارات المتعددة.\n\nاضبط على تلقائي إذا لم تكن متأكدا.",
|
"GalThreadingTooltip": "ينفذ أوامر الواجهة الخلفية للرسومات على مسار ثاني.\n\nيعمل على تسريع عملية تجميع المظللات وتقليل التقطيع وتحسين الأداء على برامج تشغيل وحدة الرسوميات دون دعم المسارات المتعددة الخاصة بهم. أداء أفضل قليلا على برامج التشغيل ذات المسارات المتعددة.\n\nاضبط على تلقائي إذا لم تكن متأكدا.",
|
||||||
"ShaderCacheToggleTooltip": "يحفظ ذاكرة المظللات المؤقتة على القرص مما يقلل من التقطيع في عمليات التشغيل اللاحقة.\n\nاتركه مفعلا إذا لم تكن متأكدا.",
|
"ShaderCacheToggleTooltip": "يحفظ ذاكرة المظللات المؤقتة على القرص مما يقلل من التقطيع في عمليات التشغيل اللاحقة.\n\nاتركه مفعلا إذا لم تكن متأكدا.",
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
"MenuBarOptions": "_Optionen",
|
"MenuBarOptions": "_Optionen",
|
||||||
"MenuBarOptionsToggleFullscreen": "Vollbild",
|
"MenuBarOptionsToggleFullscreen": "Vollbild",
|
||||||
"MenuBarOptionsStartGamesInFullscreen": "Spiele im Vollbildmodus starten",
|
"MenuBarOptionsStartGamesInFullscreen": "Spiele im Vollbildmodus starten",
|
||||||
|
"MenuBarOptionsStartGamesWithoutUI": "Spiele ohne Benutzeroberfläche starten",
|
||||||
"MenuBarOptionsStopEmulation": "Emulation beenden",
|
"MenuBarOptionsStopEmulation": "Emulation beenden",
|
||||||
"MenuBarOptionsSettings": "_Einstellungen",
|
"MenuBarOptionsSettings": "_Einstellungen",
|
||||||
"MenuBarOptionsManageUserProfiles": "_Benutzerprofile verwalten",
|
"MenuBarOptionsManageUserProfiles": "_Benutzerprofile verwalten",
|
||||||
@@ -162,7 +163,6 @@
|
|||||||
"SettingsTabSystemDramSize10GiB": "10GiB",
|
"SettingsTabSystemDramSize10GiB": "10GiB",
|
||||||
"SettingsTabSystemDramSize12GiB": "12GiB",
|
"SettingsTabSystemDramSize12GiB": "12GiB",
|
||||||
"SettingsTabSystemIgnoreMissingServices": "Ignoriere fehlende Dienste",
|
"SettingsTabSystemIgnoreMissingServices": "Ignoriere fehlende Dienste",
|
||||||
"SettingsTabSystemIgnoreApplet": "Applet ignorieren",
|
|
||||||
"SettingsTabGraphics": "Grafik",
|
"SettingsTabGraphics": "Grafik",
|
||||||
"SettingsTabGraphicsAPI": "Grafik-API",
|
"SettingsTabGraphicsAPI": "Grafik-API",
|
||||||
"SettingsTabGraphicsEnableShaderCache": "Shader-Cache aktivieren",
|
"SettingsTabGraphicsEnableShaderCache": "Shader-Cache aktivieren",
|
||||||
@@ -549,8 +549,9 @@
|
|||||||
"AboutDiscordUrlTooltipMessage": "Klicke hier, um eine Einladung zum Ryujinx Discord Server im Standardbrowser zu öffnen.",
|
"AboutDiscordUrlTooltipMessage": "Klicke hier, um eine Einladung zum Ryujinx Discord Server im Standardbrowser zu öffnen.",
|
||||||
"AboutTwitterUrlTooltipMessage": "Klicke hier, um die Ryujinx Twitter Seite im Standardbrowser zu öffnen.",
|
"AboutTwitterUrlTooltipMessage": "Klicke hier, um die Ryujinx Twitter Seite im Standardbrowser zu öffnen.",
|
||||||
"AboutRyujinxAboutTitle": "Über:",
|
"AboutRyujinxAboutTitle": "Über:",
|
||||||
"AboutRyujinxAboutContent": "Ryujinx ist ein Nintendo Switch™ Emulator.\nBitte unterstütze uns auf Patreon.\nAuf Twitter oder Discord erfährst du alle Neuigkeiten.\nEntwickler, die an einer Mitarbeit interessiert sind, können auf GitHub oder Discord mehr erfahren.",
|
"AboutRyujinxAboutContent": "Ryujinx ist ein Nintendo Switch™ Emulator.\n\nEntwickler, die an einer Mitarbeit interessiert sind, können auf GitHub mehr erfahren.",
|
||||||
"AboutRyujinxMaintainersTitle": "Entwickelt von:",
|
"AboutRyujinxMaintainersTitle": "Entwickelt von:",
|
||||||
|
"AboutRyujinxFormerMaintainersTitle": "Früher Entwickelt von:",
|
||||||
"AboutRyujinxMaintainersContentTooltipMessage": "Klicke hier, um die Liste der Mitwirkenden im Standardbrowser zu öffnen.",
|
"AboutRyujinxMaintainersContentTooltipMessage": "Klicke hier, um die Liste der Mitwirkenden im Standardbrowser zu öffnen.",
|
||||||
"AboutRyujinxSupprtersTitle": "Unterstützt auf Patreon von:",
|
"AboutRyujinxSupprtersTitle": "Unterstützt auf Patreon von:",
|
||||||
"AmiiboSeriesLabel": "Amiibo-Serie",
|
"AmiiboSeriesLabel": "Amiibo-Serie",
|
||||||
@@ -601,7 +602,6 @@
|
|||||||
"UseHypervisorTooltip": "Verwende Hypervisor anstelle von JIT. Verbessert die Leistung stark, falls vorhanden, kann jedoch in seinem aktuellen Zustand instabil sein.",
|
"UseHypervisorTooltip": "Verwende Hypervisor anstelle von JIT. Verbessert die Leistung stark, falls vorhanden, kann jedoch in seinem aktuellen Zustand instabil sein.",
|
||||||
"DRamTooltip": "Erhöht den Arbeitsspeicher des emulierten Systems von 4 GiB auf 6 GiB.\n\nDies ist nur für Texturenpakete mit höherer Auflösung oder Mods mit 4K-Auflösung nützlich. Diese Option verbessert NICHT die Leistung.\n\nIm Zweifelsfall AUS lassen.",
|
"DRamTooltip": "Erhöht den Arbeitsspeicher des emulierten Systems von 4 GiB auf 6 GiB.\n\nDies ist nur für Texturenpakete mit höherer Auflösung oder Mods mit 4K-Auflösung nützlich. Diese Option verbessert NICHT die Leistung.\n\nIm Zweifelsfall AUS lassen.",
|
||||||
"IgnoreMissingServicesTooltip": "Durch diese Option werden nicht implementierte Dienste der Switch-Firmware ignoriert. Dies kann dabei helfen, Abstürze beim Starten bestimmter Spiele zu umgehen.\n\nIm Zweifelsfall AUS lassen.",
|
"IgnoreMissingServicesTooltip": "Durch diese Option werden nicht implementierte Dienste der Switch-Firmware ignoriert. Dies kann dabei helfen, Abstürze beim Starten bestimmter Spiele zu umgehen.\n\nIm Zweifelsfall AUS lassen.",
|
||||||
"IgnoreAppletTooltip": "Der externe Dialog \"Controller-Applet\" wird nicht angezeigt, wenn das Gamepad während des Spiels getrennt wird. Es erfolgt keine Aufforderung, den Dialog zu schließen oder einen neuen Controller einzurichten. Sobald der zuvor getrennte Controller wieder angeschlossen wird, wird das Spiel automatisch fortgesetzt.",
|
|
||||||
"GraphicsBackendThreadingTooltip": "Führt Grafik-Backend Befehle auf einem zweiten Thread aus.\n\nDies beschleunigt die Shader-Kompilierung, reduziert Stottern und verbessert die Leistung auf GPU-Treibern ohne eigene Multithreading-Unterstützung. Geringfügig bessere Leistung bei Treibern mit Multithreading.\n\nIm Zweifelsfall auf AUTO stellen.",
|
"GraphicsBackendThreadingTooltip": "Führt Grafik-Backend Befehle auf einem zweiten Thread aus.\n\nDies beschleunigt die Shader-Kompilierung, reduziert Stottern und verbessert die Leistung auf GPU-Treibern ohne eigene Multithreading-Unterstützung. Geringfügig bessere Leistung bei Treibern mit Multithreading.\n\nIm Zweifelsfall auf AUTO stellen.",
|
||||||
"GalThreadingTooltip": "Führt Grafik-Backend Befehle auf einem zweiten Thread aus.\n\nDies Beschleunigt die Shader-Kompilierung, reduziert Stottern und verbessert die Leistung auf GPU-Treibern ohne eigene Multithreading-Unterstützung. Geringfügig bessere Leistung bei Treibern mit Multithreading.\n\nIm Zweifelsfall auf auf AUTO stellen.",
|
"GalThreadingTooltip": "Führt Grafik-Backend Befehle auf einem zweiten Thread aus.\n\nDies Beschleunigt die Shader-Kompilierung, reduziert Stottern und verbessert die Leistung auf GPU-Treibern ohne eigene Multithreading-Unterstützung. Geringfügig bessere Leistung bei Treibern mit Multithreading.\n\nIm Zweifelsfall auf auf AUTO stellen.",
|
||||||
"ShaderCacheToggleTooltip": "Speichert einen persistenten Shader Cache, der das Stottern bei nachfolgenden Durchläufen reduziert.\n\nIm Zweifelsfall AN lassen.",
|
"ShaderCacheToggleTooltip": "Speichert einen persistenten Shader Cache, der das Stottern bei nachfolgenden Durchläufen reduziert.\n\nIm Zweifelsfall AN lassen.",
|
||||||
|
|||||||
@@ -162,7 +162,6 @@
|
|||||||
"SettingsTabSystemDramSize10GiB": "10GiB",
|
"SettingsTabSystemDramSize10GiB": "10GiB",
|
||||||
"SettingsTabSystemDramSize12GiB": "12GiB",
|
"SettingsTabSystemDramSize12GiB": "12GiB",
|
||||||
"SettingsTabSystemIgnoreMissingServices": "Αγνόηση υπηρεσιών που λείπουν",
|
"SettingsTabSystemIgnoreMissingServices": "Αγνόηση υπηρεσιών που λείπουν",
|
||||||
"SettingsTabSystemIgnoreApplet": "Αγνοήστε το Applet",
|
|
||||||
"SettingsTabGraphics": "Γραφικά",
|
"SettingsTabGraphics": "Γραφικά",
|
||||||
"SettingsTabGraphicsAPI": "API Γραφικά",
|
"SettingsTabGraphicsAPI": "API Γραφικά",
|
||||||
"SettingsTabGraphicsEnableShaderCache": "Ενεργοποίηση Προσωρινής Μνήμης Shader",
|
"SettingsTabGraphicsEnableShaderCache": "Ενεργοποίηση Προσωρινής Μνήμης Shader",
|
||||||
@@ -549,8 +548,9 @@
|
|||||||
"AboutDiscordUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε μία πρόσκληση στον διακομιστή Ryujinx Discord στο προεπιλεγμένο πρόγραμμα περιήγησης.",
|
"AboutDiscordUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε μία πρόσκληση στον διακομιστή Ryujinx Discord στο προεπιλεγμένο πρόγραμμα περιήγησης.",
|
||||||
"AboutTwitterUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε τη σελίδα Ryujinx Twitter στο προεπιλεγμένο πρόγραμμα περιήγησης.",
|
"AboutTwitterUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε τη σελίδα Ryujinx Twitter στο προεπιλεγμένο πρόγραμμα περιήγησης.",
|
||||||
"AboutRyujinxAboutTitle": "Σχετικά με:",
|
"AboutRyujinxAboutTitle": "Σχετικά με:",
|
||||||
"AboutRyujinxAboutContent": "Το Ryujinx είναι ένας εξομοιωτής για το Nintendo Switch™.\nΥποστηρίξτε μας στο Patreon.\nΛάβετε όλα τα τελευταία νέα στο Twitter ή στο Discord.\nΟι προγραμματιστές που ενδιαφέρονται να συνεισφέρουν μπορούν να μάθουν περισσότερα στο GitHub ή στο Discord μας.",
|
"AboutRyujinxAboutContent": "Το Ryujinx είναι ένας εξομοιωτής για το Nintendo Switch™.\n\nΟι προγραμματιστές που ενδιαφέρονται να συνεισφέρουν μπορούν να μάθουν περισσότερα στον GitHub μας.",
|
||||||
"AboutRyujinxMaintainersTitle": "Συντηρείται από:",
|
"AboutRyujinxMaintainersTitle": "Συντηρείται από:",
|
||||||
|
"AboutRyujinxFormerMaintainersTitle": "Προηγουμένως διατηρείται από:",
|
||||||
"AboutRyujinxMaintainersContentTooltipMessage": "Κάντε κλικ για να ανοίξετε τη σελίδα Συνεισφέροντες στο προεπιλεγμένο πρόγραμμα περιήγησης.",
|
"AboutRyujinxMaintainersContentTooltipMessage": "Κάντε κλικ για να ανοίξετε τη σελίδα Συνεισφέροντες στο προεπιλεγμένο πρόγραμμα περιήγησης.",
|
||||||
"AboutRyujinxSupprtersTitle": "Υποστηρίζεται στο Patreon από:",
|
"AboutRyujinxSupprtersTitle": "Υποστηρίζεται στο Patreon από:",
|
||||||
"AmiiboSeriesLabel": "Σειρά Amiibo",
|
"AmiiboSeriesLabel": "Σειρά Amiibo",
|
||||||
@@ -601,7 +601,6 @@
|
|||||||
"UseHypervisorTooltip": "Χρησιμοποιήστε Hypervisor αντί για JIT. Βελτιώνει σημαντικά την απόδοση όταν διατίθεται, αλλά μπορεί να είναι ασταθής στην τρέχουσα κατάστασή του.",
|
"UseHypervisorTooltip": "Χρησιμοποιήστε Hypervisor αντί για JIT. Βελτιώνει σημαντικά την απόδοση όταν διατίθεται, αλλά μπορεί να είναι ασταθής στην τρέχουσα κατάστασή του.",
|
||||||
"DRamTooltip": "Επεκτείνει την ποσότητα της μνήμης στο εξομοιούμενο σύστημα από 4 GiB σε 6 GiB",
|
"DRamTooltip": "Επεκτείνει την ποσότητα της μνήμης στο εξομοιούμενο σύστημα από 4 GiB σε 6 GiB",
|
||||||
"IgnoreMissingServicesTooltip": "Ενεργοποίηση ή απενεργοποίηση της αγνοώησης για υπηρεσίες που λείπουν",
|
"IgnoreMissingServicesTooltip": "Ενεργοποίηση ή απενεργοποίηση της αγνοώησης για υπηρεσίες που λείπουν",
|
||||||
"IgnoreAppletTooltip": "Το εξωτερικό παράθυρο διαλόγου \"Ελεγκτής μικροεφαρμογής\" δεν θα εμφανιστεί εάν το gamepad αποσυνδεθεί κατά τη διάρκεια του παιχνιδιού. Δεν θα σας ζητηθεί να κλείσετε το παράθυρο διαλόγου ή να ρυθμίσετε έναν νέο ελεγκτή. Μόλις επανασυνδεθεί το χειριστήριο που είχε αποσυνδεθεί προηγουμένως, το παιχνίδι θα συνεχιστεί αυτόματα.",
|
|
||||||
"GraphicsBackendThreadingTooltip": "Ενεργοποίηση Πολυνηματικής Επεξεργασίας Γραφικών",
|
"GraphicsBackendThreadingTooltip": "Ενεργοποίηση Πολυνηματικής Επεξεργασίας Γραφικών",
|
||||||
"GalThreadingTooltip": "Εκτελεί εντολές γραφικών σε ένα δεύτερο νήμα. Επιτρέπει την πολυνηματική μεταγλώττιση Shader σε χρόνο εκτέλεσης, μειώνει το τρεμόπαιγμα και βελτιώνει την απόδοση των προγραμμάτων οδήγησης χωρίς τη δική τους υποστήριξη πολλαπλών νημάτων. Ποικίλες κορυφαίες επιδόσεις σε προγράμματα οδήγησης με multithreading. Μπορεί να χρειαστεί επανεκκίνηση του Ryujinx για να απενεργοποιήσετε σωστά την ενσωματωμένη λειτουργία πολλαπλών νημάτων του προγράμματος οδήγησης ή ίσως χρειαστεί να το κάνετε χειροκίνητα για να έχετε την καλύτερη απόδοση.",
|
"GalThreadingTooltip": "Εκτελεί εντολές γραφικών σε ένα δεύτερο νήμα. Επιτρέπει την πολυνηματική μεταγλώττιση Shader σε χρόνο εκτέλεσης, μειώνει το τρεμόπαιγμα και βελτιώνει την απόδοση των προγραμμάτων οδήγησης χωρίς τη δική τους υποστήριξη πολλαπλών νημάτων. Ποικίλες κορυφαίες επιδόσεις σε προγράμματα οδήγησης με multithreading. Μπορεί να χρειαστεί επανεκκίνηση του Ryujinx για να απενεργοποιήσετε σωστά την ενσωματωμένη λειτουργία πολλαπλών νημάτων του προγράμματος οδήγησης ή ίσως χρειαστεί να το κάνετε χειροκίνητα για να έχετε την καλύτερη απόδοση.",
|
||||||
"ShaderCacheToggleTooltip": "Ενεργοποιεί ή απενεργοποιεί την Προσωρινή Μνήμη Shader",
|
"ShaderCacheToggleTooltip": "Ενεργοποιεί ή απενεργοποιεί την Προσωρινή Μνήμη Shader",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user