Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
8198b99935 | ||
|
460f96967d | ||
|
7ca779a26d | ||
|
b5032b3c91 | ||
|
f0a3dff136 | ||
|
f659dcb9d8 | ||
|
a34fb0e939 | ||
|
21ce8a9b80 | ||
|
9ecbee8032 | ||
|
80519af67d | ||
|
26e30faff3 | ||
|
0992310b76 |
@@ -34,6 +34,12 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
private static uint GetXcr0Eax()
|
private static uint GetXcr0Eax()
|
||||||
{
|
{
|
||||||
|
if (!FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Xsave))
|
||||||
|
{
|
||||||
|
// XSAVE feature required for xgetbv
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ReadOnlySpan<byte> asmGetXcr0 = new byte[]
|
ReadOnlySpan<byte> asmGetXcr0 = new byte[]
|
||||||
{
|
{
|
||||||
0x31, 0xc9, // xor ecx, ecx
|
0x31, 0xc9, // xor ecx, ecx
|
||||||
@@ -70,6 +76,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
Sse42 = 1 << 20,
|
Sse42 = 1 << 20,
|
||||||
Popcnt = 1 << 23,
|
Popcnt = 1 << 23,
|
||||||
Aes = 1 << 25,
|
Aes = 1 << 25,
|
||||||
|
Xsave = 1 << 26,
|
||||||
Osxsave = 1 << 27,
|
Osxsave = 1 << 27,
|
||||||
Avx = 1 << 28,
|
Avx = 1 << 28,
|
||||||
F16c = 1 << 29
|
F16c = 1 << 29
|
||||||
@@ -118,9 +125,9 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
public static bool SupportsSse42 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse42);
|
public static bool SupportsSse42 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse42);
|
||||||
public static bool SupportsPopcnt => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Popcnt);
|
public static bool SupportsPopcnt => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Popcnt);
|
||||||
public static bool SupportsAesni => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Aes);
|
public static bool SupportsAesni => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Aes);
|
||||||
public static bool SupportsAvx => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Avx | FeatureFlags1Ecx.Osxsave) && Xcr0InfoEax.HasFlag(Xcr0FlagsEax.Sse | Xcr0FlagsEax.YmmHi128);
|
public static bool SupportsAvx => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Avx | FeatureFlags1Ecx.Xsave | FeatureFlags1Ecx.Osxsave) && Xcr0InfoEax.HasFlag(Xcr0FlagsEax.Sse | Xcr0FlagsEax.YmmHi128);
|
||||||
public static bool SupportsAvx2 => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx2) && SupportsAvx;
|
public static bool SupportsAvx2 => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx2) && SupportsAvx;
|
||||||
public static bool SupportsAvx512F => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512f) && FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Osxsave)
|
public static bool SupportsAvx512F => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512f) && FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Xsave | FeatureFlags1Ecx.Osxsave)
|
||||||
&& Xcr0InfoEax.HasFlag(Xcr0FlagsEax.Sse | Xcr0FlagsEax.YmmHi128 | Xcr0FlagsEax.Opmask | Xcr0FlagsEax.ZmmHi256 | Xcr0FlagsEax.Hi16Zmm);
|
&& Xcr0InfoEax.HasFlag(Xcr0FlagsEax.Sse | Xcr0FlagsEax.YmmHi128 | Xcr0FlagsEax.Opmask | Xcr0FlagsEax.ZmmHi256 | Xcr0FlagsEax.Hi16Zmm);
|
||||||
public static bool SupportsAvx512Vl => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512vl) && SupportsAvx512F;
|
public static bool SupportsAvx512Vl => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512vl) && SupportsAvx512F;
|
||||||
public static bool SupportsAvx512Bw => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512bw) && SupportsAvx512F;
|
public static bool SupportsAvx512Bw => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx512bw) && SupportsAvx512F;
|
||||||
|
@@ -34,7 +34,7 @@
|
|||||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
|
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||||
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
|
<PackageVersion Include="Ryujinx.GtkSharp" Version="3.24.24.59-ryujinx" />
|
||||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.26.1-build23" />
|
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.26.3-build25" />
|
||||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
|
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||||
|
@@ -18,6 +18,7 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
private ulong _playedSampleCount;
|
private ulong _playedSampleCount;
|
||||||
private ManualResetEvent _updateRequiredEvent;
|
private ManualResetEvent _updateRequiredEvent;
|
||||||
private uint _outputStream;
|
private uint _outputStream;
|
||||||
|
private bool _hasSetupError;
|
||||||
private SDL_AudioCallback _callbackDelegate;
|
private SDL_AudioCallback _callbackDelegate;
|
||||||
private int _bytesPerFrame;
|
private int _bytesPerFrame;
|
||||||
private uint _sampleCount;
|
private uint _sampleCount;
|
||||||
@@ -42,7 +43,7 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
private void EnsureAudioStreamSetup(AudioBuffer buffer)
|
private void EnsureAudioStreamSetup(AudioBuffer buffer)
|
||||||
{
|
{
|
||||||
uint bufferSampleCount = (uint)GetSampleCount(buffer);
|
uint bufferSampleCount = (uint)GetSampleCount(buffer);
|
||||||
bool needAudioSetup = _outputStream == 0 ||
|
bool needAudioSetup = (_outputStream == 0 && !_hasSetupError) ||
|
||||||
(bufferSampleCount >= Constants.TargetSampleCount && bufferSampleCount < _sampleCount);
|
(bufferSampleCount >= Constants.TargetSampleCount && bufferSampleCount < _sampleCount);
|
||||||
|
|
||||||
if (needAudioSetup)
|
if (needAudioSetup)
|
||||||
@@ -51,12 +52,9 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
|
|
||||||
uint newOutputStream = SDL2HardwareDeviceDriver.OpenStream(RequestedSampleFormat, RequestedSampleRate, RequestedChannelCount, _sampleCount, _callbackDelegate);
|
uint newOutputStream = SDL2HardwareDeviceDriver.OpenStream(RequestedSampleFormat, RequestedSampleRate, RequestedChannelCount, _sampleCount, _callbackDelegate);
|
||||||
|
|
||||||
if (newOutputStream == 0)
|
_hasSetupError = newOutputStream == 0;
|
||||||
{
|
|
||||||
// No stream in place, this is unexpected.
|
if (!_hasSetupError)
|
||||||
throw new InvalidOperationException($"OpenStream failed with error: \"{SDL_GetError()}\"");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if (_outputStream != 0)
|
if (_outputStream != 0)
|
||||||
{
|
{
|
||||||
@@ -151,11 +149,20 @@ namespace Ryujinx.Audio.Backends.SDL2
|
|||||||
{
|
{
|
||||||
EnsureAudioStreamSetup(buffer);
|
EnsureAudioStreamSetup(buffer);
|
||||||
|
|
||||||
SDL2AudioBuffer driverBuffer = new SDL2AudioBuffer(buffer.DataPointer, GetSampleCount(buffer));
|
if (_outputStream != 0)
|
||||||
|
{
|
||||||
|
SDL2AudioBuffer driverBuffer = new SDL2AudioBuffer(buffer.DataPointer, GetSampleCount(buffer));
|
||||||
|
|
||||||
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
|
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
|
||||||
|
|
||||||
_queuedBuffers.Enqueue(driverBuffer);
|
_queuedBuffers.Enqueue(driverBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Interlocked.Add(ref _playedSampleCount, GetSampleCount(buffer));
|
||||||
|
|
||||||
|
_updateRequiredEvent.Set();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetVolume(float volume)
|
public override void SetVolume(float volume)
|
||||||
|
@@ -1,18 +1,21 @@
|
|||||||
|
using Microsoft.Win32.SafeHandles;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Ryujinx.Common.SystemInterop
|
namespace Ryujinx.Common.SystemInterop
|
||||||
{
|
{
|
||||||
public partial class StdErrAdapter : IDisposable
|
public partial class StdErrAdapter : IDisposable
|
||||||
{
|
{
|
||||||
private bool _disposable = false;
|
private bool _disposable = false;
|
||||||
private UnixStream _pipeReader;
|
private Stream _pipeReader;
|
||||||
private UnixStream _pipeWriter;
|
private Stream _pipeWriter;
|
||||||
private Thread _worker;
|
private CancellationTokenSource _cancellationTokenSource;
|
||||||
|
private Task _worker;
|
||||||
|
|
||||||
public StdErrAdapter()
|
public StdErrAdapter()
|
||||||
{
|
{
|
||||||
@@ -31,37 +34,39 @@ namespace Ryujinx.Common.SystemInterop
|
|||||||
(int readFd, int writeFd) = MakePipe();
|
(int readFd, int writeFd) = MakePipe();
|
||||||
dup2(writeFd, stdErrFileno);
|
dup2(writeFd, stdErrFileno);
|
||||||
|
|
||||||
_pipeReader = new UnixStream(readFd);
|
_pipeReader = CreateFileDescriptorStream(readFd);
|
||||||
_pipeWriter = new UnixStream(writeFd);
|
_pipeWriter = CreateFileDescriptorStream(writeFd);
|
||||||
|
|
||||||
_worker = new Thread(EventWorker);
|
_cancellationTokenSource = new CancellationTokenSource();
|
||||||
|
_worker = Task.Run(async () => await EventWorkerAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token);
|
||||||
_disposable = true;
|
_disposable = true;
|
||||||
_worker.Start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("linux")]
|
[SupportedOSPlatform("linux")]
|
||||||
[SupportedOSPlatform("macos")]
|
[SupportedOSPlatform("macos")]
|
||||||
private void EventWorker()
|
private async Task EventWorkerAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
TextReader reader = new StreamReader(_pipeReader);
|
using TextReader reader = new StreamReader(_pipeReader, leaveOpen: true);
|
||||||
string line;
|
string line;
|
||||||
while ((line = reader.ReadLine()) != null)
|
while (cancellationToken.IsCancellationRequested == false && (line = await reader.ReadLineAsync(cancellationToken)) != null)
|
||||||
{
|
{
|
||||||
Logger.Error?.PrintRawMsg(line);
|
Logger.Error?.PrintRawMsg(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Dispose(bool disposing)
|
private void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (_disposable)
|
if (_disposable)
|
||||||
{
|
{
|
||||||
|
_disposable = false;
|
||||||
|
|
||||||
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
|
_cancellationTokenSource.Cancel();
|
||||||
|
_worker.Wait(0);
|
||||||
_pipeReader?.Close();
|
_pipeReader?.Close();
|
||||||
_pipeWriter?.Close();
|
_pipeWriter?.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
_disposable = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,11 +79,11 @@ namespace Ryujinx.Common.SystemInterop
|
|||||||
private static partial int dup2(int fd, int fd2);
|
private static partial int dup2(int fd, int fd2);
|
||||||
|
|
||||||
[LibraryImport("libc", SetLastError = true)]
|
[LibraryImport("libc", SetLastError = true)]
|
||||||
private static unsafe partial int pipe(int* pipefd);
|
private static partial int pipe(Span<int> pipefd);
|
||||||
|
|
||||||
private static unsafe (int, int) MakePipe()
|
private static (int, int) MakePipe()
|
||||||
{
|
{
|
||||||
int *pipefd = stackalloc int[2];
|
Span<int> pipefd = stackalloc int[2];
|
||||||
|
|
||||||
if (pipe(pipefd) == 0)
|
if (pipe(pipefd) == 0)
|
||||||
{
|
{
|
||||||
@@ -89,5 +94,16 @@ namespace Ryujinx.Common.SystemInterop
|
|||||||
throw new();
|
throw new();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SupportedOSPlatform("linux")]
|
||||||
|
[SupportedOSPlatform("macos")]
|
||||||
|
private static Stream CreateFileDescriptorStream(int fd)
|
||||||
|
{
|
||||||
|
return new FileStream(
|
||||||
|
new SafeFileHandle((IntPtr)fd, ownsHandle: true),
|
||||||
|
FileAccess.ReadWrite
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,155 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.SystemInterop
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("linux")]
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
public partial class UnixStream : Stream, IDisposable
|
|
||||||
{
|
|
||||||
private const int InvalidFd = -1;
|
|
||||||
|
|
||||||
private int _fd;
|
|
||||||
|
|
||||||
[LibraryImport("libc", SetLastError = true)]
|
|
||||||
private static partial long read(int fd, IntPtr buf, ulong count);
|
|
||||||
|
|
||||||
[LibraryImport("libc", SetLastError = true)]
|
|
||||||
private static partial long write(int fd, IntPtr buf, ulong count);
|
|
||||||
|
|
||||||
[LibraryImport("libc", SetLastError = true)]
|
|
||||||
private static partial int close(int fd);
|
|
||||||
|
|
||||||
public UnixStream(int fd)
|
|
||||||
{
|
|
||||||
if (InvalidFd == fd)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Invalid file descriptor");
|
|
||||||
}
|
|
||||||
|
|
||||||
_fd = fd;
|
|
||||||
|
|
||||||
CanRead = read(fd, IntPtr.Zero, 0) != -1;
|
|
||||||
CanWrite = write(fd, IntPtr.Zero, 0) != -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
~UnixStream()
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CanRead { get; }
|
|
||||||
public override bool CanWrite { get; }
|
|
||||||
public override bool CanSeek => false;
|
|
||||||
|
|
||||||
public override long Length => throw new NotSupportedException();
|
|
||||||
|
|
||||||
public override long Position
|
|
||||||
{
|
|
||||||
get => throw new NotSupportedException();
|
|
||||||
set => throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Flush()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override unsafe int Read([In, Out] byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
if (offset < 0 || offset > (buffer.Length - count) || count < 0)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer.Length == 0)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
long r = 0;
|
|
||||||
fixed (byte* buf = &buffer[offset])
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
r = read(_fd, (IntPtr)buf, (ulong)count);
|
|
||||||
} while (ShouldRetry(r));
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int)r;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override unsafe void Write(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
if (offset < 0 || offset > (buffer.Length - count) || count < 0)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer.Length == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fixed (byte* buf = &buffer[offset])
|
|
||||||
{
|
|
||||||
long r = 0;
|
|
||||||
do {
|
|
||||||
r = write(_fd, (IntPtr)buf, (ulong)count);
|
|
||||||
} while (ShouldRetry(r));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override long Seek(long offset, SeekOrigin origin)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetLength(long value)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Close()
|
|
||||||
{
|
|
||||||
if (_fd == InvalidFd)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Flush();
|
|
||||||
|
|
||||||
int r;
|
|
||||||
do {
|
|
||||||
r = close(_fd);
|
|
||||||
} while (ShouldRetry(r));
|
|
||||||
|
|
||||||
_fd = InvalidFd;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDisposable.Dispose()
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ShouldRetry(long r)
|
|
||||||
{
|
|
||||||
if (r == -1)
|
|
||||||
{
|
|
||||||
const int eintr = 4;
|
|
||||||
|
|
||||||
int errno = Marshal.GetLastPInvokeError();
|
|
||||||
|
|
||||||
if (errno == eintr)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new SystemException($"Operation failed with error 0x{errno:X}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -180,7 +180,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
int firstInstance = (int)_state.State.FirstInstance;
|
int firstInstance = (int)_state.State.FirstInstance;
|
||||||
|
|
||||||
int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount();
|
int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount(_context.Renderer);
|
||||||
|
|
||||||
if (inlineIndexCount != 0)
|
if (inlineIndexCount != 0)
|
||||||
{
|
{
|
||||||
@@ -670,7 +670,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
{
|
{
|
||||||
if (indexedInline)
|
if (indexedInline)
|
||||||
{
|
{
|
||||||
int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount();
|
int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount(_context.Renderer);
|
||||||
BufferRange br = new BufferRange(_drawState.IbStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4);
|
BufferRange br = new BufferRange(_drawState.IbStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4);
|
||||||
|
|
||||||
_channel.BufferManager.SetIndexBuffer(br, IndexType.UInt);
|
_channel.BufferManager.SetIndexBuffer(br, IndexType.UInt);
|
||||||
|
@@ -11,9 +11,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
struct IbStreamer
|
struct IbStreamer
|
||||||
{
|
{
|
||||||
|
private const int BufferCapacity = 256; // Must be a power of 2.
|
||||||
|
|
||||||
private BufferHandle _inlineIndexBuffer;
|
private BufferHandle _inlineIndexBuffer;
|
||||||
private int _inlineIndexBufferSize;
|
private int _inlineIndexBufferSize;
|
||||||
private int _inlineIndexCount;
|
private int _inlineIndexCount;
|
||||||
|
private uint[] _buffer;
|
||||||
|
private int _bufferOffset;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates if any index buffer data has been pushed.
|
/// Indicates if any index buffer data has been pushed.
|
||||||
@@ -38,9 +42,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// Gets the number of elements on the current inline index buffer,
|
/// Gets the number of elements on the current inline index buffer,
|
||||||
/// while also reseting it to zero for the next draw.
|
/// while also reseting it to zero for the next draw.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="renderer">Host renderer</param>
|
||||||
/// <returns>Inline index bufffer count</returns>
|
/// <returns>Inline index bufffer count</returns>
|
||||||
public int GetAndResetInlineIndexCount()
|
public int GetAndResetInlineIndexCount(IRenderer renderer)
|
||||||
{
|
{
|
||||||
|
UpdateRemaining(renderer);
|
||||||
int temp = _inlineIndexCount;
|
int temp = _inlineIndexCount;
|
||||||
_inlineIndexCount = 0;
|
_inlineIndexCount = 0;
|
||||||
return temp;
|
return temp;
|
||||||
@@ -58,16 +64,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
byte i2 = (byte)(argument >> 16);
|
byte i2 = (byte)(argument >> 16);
|
||||||
byte i3 = (byte)(argument >> 24);
|
byte i3 = (byte)(argument >> 24);
|
||||||
|
|
||||||
Span<uint> data = stackalloc uint[4];
|
int offset = _inlineIndexCount;
|
||||||
|
|
||||||
data[0] = i0;
|
PushData(renderer, offset, i0);
|
||||||
data[1] = i1;
|
PushData(renderer, offset + 1, i1);
|
||||||
data[2] = i2;
|
PushData(renderer, offset + 2, i2);
|
||||||
data[3] = i3;
|
PushData(renderer, offset + 3, i3);
|
||||||
|
|
||||||
int offset = _inlineIndexCount * 4;
|
|
||||||
|
|
||||||
renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data));
|
|
||||||
|
|
||||||
_inlineIndexCount += 4;
|
_inlineIndexCount += 4;
|
||||||
}
|
}
|
||||||
@@ -82,14 +84,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
ushort i0 = (ushort)argument;
|
ushort i0 = (ushort)argument;
|
||||||
ushort i1 = (ushort)(argument >> 16);
|
ushort i1 = (ushort)(argument >> 16);
|
||||||
|
|
||||||
Span<uint> data = stackalloc uint[2];
|
int offset = _inlineIndexCount;
|
||||||
|
|
||||||
data[0] = i0;
|
PushData(renderer, offset, i0);
|
||||||
data[1] = i1;
|
PushData(renderer, offset + 1, i1);
|
||||||
|
|
||||||
int offset = _inlineIndexCount * 4;
|
|
||||||
|
|
||||||
renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data));
|
|
||||||
|
|
||||||
_inlineIndexCount += 2;
|
_inlineIndexCount += 2;
|
||||||
}
|
}
|
||||||
@@ -103,13 +101,61 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
{
|
{
|
||||||
uint i0 = (uint)argument;
|
uint i0 = (uint)argument;
|
||||||
|
|
||||||
Span<uint> data = stackalloc uint[1];
|
int offset = _inlineIndexCount++;
|
||||||
|
|
||||||
data[0] = i0;
|
PushData(renderer, offset, i0);
|
||||||
|
}
|
||||||
|
|
||||||
int offset = _inlineIndexCount++ * 4;
|
/// <summary>
|
||||||
|
/// Pushes a 32-bit value to the index buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="renderer">Host renderer</param>
|
||||||
|
/// <param name="offset">Offset where the data should be written, in 32-bit words</param>
|
||||||
|
/// <param name="value">Index value to be written</param>
|
||||||
|
private void PushData(IRenderer renderer, int offset, uint value)
|
||||||
|
{
|
||||||
|
if (_buffer == null)
|
||||||
|
{
|
||||||
|
_buffer = new uint[BufferCapacity];
|
||||||
|
}
|
||||||
|
|
||||||
renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast<uint, byte>(data));
|
// We upload data in chunks.
|
||||||
|
// If we are at the start of a chunk, then the buffer might be full,
|
||||||
|
// in that case we need to submit any existing data before overwriting the buffer.
|
||||||
|
int subOffset = offset & (BufferCapacity - 1);
|
||||||
|
|
||||||
|
if (subOffset == 0 && offset != 0)
|
||||||
|
{
|
||||||
|
int baseOffset = (offset - BufferCapacity) * sizeof(uint);
|
||||||
|
BufferHandle buffer = GetInlineIndexBuffer(renderer, baseOffset, BufferCapacity * sizeof(uint));
|
||||||
|
renderer.SetBufferData(buffer, baseOffset, MemoryMarshal.Cast<uint, byte>(_buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
_buffer[subOffset] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Makes sure that any pending data is submitted to the GPU before the index buffer is used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="renderer">Host renderer</param>
|
||||||
|
private void UpdateRemaining(IRenderer renderer)
|
||||||
|
{
|
||||||
|
int offset = _inlineIndexCount;
|
||||||
|
if (offset == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = offset & (BufferCapacity - 1);
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
count = BufferCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
int baseOffset = (offset - count) * sizeof(uint);
|
||||||
|
int length = count * sizeof(uint);
|
||||||
|
BufferHandle buffer = GetInlineIndexBuffer(renderer, baseOffset, length);
|
||||||
|
renderer.SetBufferData(buffer, baseOffset, MemoryMarshal.Cast<uint, byte>(_buffer).Slice(0, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -117,12 +163,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="renderer">Host renderer</param>
|
/// <param name="renderer">Host renderer</param>
|
||||||
/// <param name="offset">Offset where the data will be written</param>
|
/// <param name="offset">Offset where the data will be written</param>
|
||||||
|
/// <param name="length">Number of bytes that will be written</param>
|
||||||
/// <returns>Buffer handle</returns>
|
/// <returns>Buffer handle</returns>
|
||||||
private BufferHandle GetInlineIndexBuffer(IRenderer renderer, int offset)
|
private BufferHandle GetInlineIndexBuffer(IRenderer renderer, int offset, int length)
|
||||||
{
|
{
|
||||||
// Calculate a reasonable size for the buffer that can fit all the data,
|
// Calculate a reasonable size for the buffer that can fit all the data,
|
||||||
// and that also won't require frequent resizes if we need to push more data.
|
// and that also won't require frequent resizes if we need to push more data.
|
||||||
int size = BitUtils.AlignUp(offset + 0x10, 0x200);
|
int size = BitUtils.AlignUp(offset + length + 0x10, 0x200);
|
||||||
|
|
||||||
if (_inlineIndexBuffer == BufferHandle.Null)
|
if (_inlineIndexBuffer == BufferHandle.Null)
|
||||||
{
|
{
|
||||||
|
@@ -130,6 +130,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
return ref descriptor;
|
return ref descriptor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
texture.SynchronizeMemory();
|
||||||
|
}
|
||||||
|
|
||||||
Items[id] = texture;
|
Items[id] = texture;
|
||||||
|
|
||||||
@@ -233,7 +237,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queues a request to update a texture's mapping.
|
/// Queues a request to update a texture's mapping.
|
||||||
/// Mapping is updated later to avoid deleting the texture if it is still sparsely mapped.
|
/// Mapping is updated later to avoid deleting the texture if it is still sparsely mapped.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="texture">Texture with potential mapping change</param>
|
/// <param name="texture">Texture with potential mapping change</param>
|
||||||
|
@@ -236,7 +236,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
else if (texture is TextureView view)
|
else if (texture is TextureView view)
|
||||||
{
|
{
|
||||||
view.Storage.InsertBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
view.Storage.InsertWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
||||||
|
|
||||||
_textureRefs[binding] = view.GetImageView();
|
_textureRefs[binding] = view.GetImageView();
|
||||||
_samplerRefs[binding] = ((SamplerHolder)sampler)?.GetSampler();
|
_samplerRefs[binding] = ((SamplerHolder)sampler)?.GetSampler();
|
||||||
|
@@ -322,7 +322,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
GAL.Format.S8Uint => ImageAspectFlags.StencilBit,
|
GAL.Format.S8Uint => ImageAspectFlags.StencilBit,
|
||||||
GAL.Format.D24UnormS8Uint or
|
GAL.Format.D24UnormS8Uint or
|
||||||
GAL.Format.D32FloatS8Uint or
|
GAL.Format.D32FloatS8Uint or
|
||||||
GAL.Format.S8UintD24Unorm => ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit,
|
GAL.Format.S8UintD24Unorm => ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit,
|
||||||
_ => ImageAspectFlags.ColorBit
|
_ => ImageAspectFlags.ColorBit
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -218,5 +218,23 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
AccessFlags.DepthStencilAttachmentWriteBit,
|
AccessFlags.DepthStencilAttachmentWriteBit,
|
||||||
PipelineStageFlags.ColorAttachmentOutputBit);
|
PipelineStageFlags.ColorAttachmentOutputBit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void InsertClearBarrier(CommandBufferScoped cbs, int index)
|
||||||
|
{
|
||||||
|
if (_colors != null)
|
||||||
|
{
|
||||||
|
int realIndex = Array.IndexOf(AttachmentIndices, index);
|
||||||
|
|
||||||
|
if (realIndex != -1)
|
||||||
|
{
|
||||||
|
_colors[realIndex].Storage?.InsertReadToWriteBarrier(cbs, AccessFlags.ColorAttachmentWriteBit, PipelineStageFlags.ColorAttachmentOutputBit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertClearBarrierDS(CommandBufferScoped cbs)
|
||||||
|
{
|
||||||
|
_depthStencil?.Storage?.InsertReadToWriteBarrier(cbs, AccessFlags.DepthStencilAttachmentWriteBit, PipelineStageFlags.EarlyFragmentTestsBit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -226,6 +226,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
var attachment = new ClearAttachment(ImageAspectFlags.ColorBit, (uint)index, clearValue);
|
var attachment = new ClearAttachment(ImageAspectFlags.ColorBit, (uint)index, clearValue);
|
||||||
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
|
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
|
||||||
|
|
||||||
|
FramebufferParams.InsertClearBarrier(Cbs, index);
|
||||||
|
|
||||||
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
|
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,6 +258,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
var attachment = new ClearAttachment(flags, 0, clearValue);
|
var attachment = new ClearAttachment(flags, 0, clearValue);
|
||||||
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
|
var clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
|
||||||
|
|
||||||
|
FramebufferParams.InsertClearBarrierDS(Cbs);
|
||||||
|
|
||||||
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
|
Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -46,6 +46,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private AccessFlags _lastModificationAccess;
|
private AccessFlags _lastModificationAccess;
|
||||||
private PipelineStageFlags _lastModificationStage;
|
private PipelineStageFlags _lastModificationStage;
|
||||||
|
private AccessFlags _lastReadAccess;
|
||||||
|
private PipelineStageFlags _lastReadStage;
|
||||||
|
|
||||||
private int _viewsCount;
|
private int _viewsCount;
|
||||||
private ulong _size;
|
private ulong _size;
|
||||||
@@ -440,31 +442,39 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_lastModificationStage = stage;
|
_lastModificationStage = stage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InsertBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags)
|
public void InsertReadToWriteBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags)
|
||||||
{
|
{
|
||||||
|
if (_lastReadAccess != AccessFlags.NoneKhr)
|
||||||
|
{
|
||||||
|
ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags();
|
||||||
|
|
||||||
|
TextureView.InsertImageBarrier(
|
||||||
|
_gd.Api,
|
||||||
|
cbs.CommandBuffer,
|
||||||
|
_imageAuto.Get(cbs).Value,
|
||||||
|
_lastReadAccess,
|
||||||
|
dstAccessFlags,
|
||||||
|
_lastReadStage,
|
||||||
|
dstStageFlags,
|
||||||
|
aspectFlags,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
_info.GetLayers(),
|
||||||
|
_info.Levels);
|
||||||
|
|
||||||
|
_lastReadAccess = AccessFlags.NoneKhr;
|
||||||
|
_lastReadStage = PipelineStageFlags.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InsertWriteToReadBarrier(CommandBufferScoped cbs, AccessFlags dstAccessFlags, PipelineStageFlags dstStageFlags)
|
||||||
|
{
|
||||||
|
_lastReadAccess |= dstAccessFlags;
|
||||||
|
_lastReadStage |= dstStageFlags;
|
||||||
|
|
||||||
if (_lastModificationAccess != AccessFlags.NoneKhr)
|
if (_lastModificationAccess != AccessFlags.NoneKhr)
|
||||||
{
|
{
|
||||||
ImageAspectFlags aspectFlags;
|
ImageAspectFlags aspectFlags = Info.Format.ConvertAspectFlags();
|
||||||
|
|
||||||
if (_info.Format.IsDepthOrStencil())
|
|
||||||
{
|
|
||||||
if (_info.Format == GAL.Format.S8Uint)
|
|
||||||
{
|
|
||||||
aspectFlags = ImageAspectFlags.StencilBit;
|
|
||||||
}
|
|
||||||
else if (_info.Format == GAL.Format.D16Unorm || _info.Format == GAL.Format.D32Float)
|
|
||||||
{
|
|
||||||
aspectFlags = ImageAspectFlags.DepthBit;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aspectFlags = ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aspectFlags = ImageAspectFlags.ColorBit;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureView.InsertImageBarrier(
|
TextureView.InsertImageBarrier(
|
||||||
_gd.Api,
|
_gd.Api,
|
||||||
|
@@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private const string AppName = "Ryujinx.Graphics.Vulkan";
|
private const string AppName = "Ryujinx.Graphics.Vulkan";
|
||||||
private const int QueuesCount = 2;
|
private const int QueuesCount = 2;
|
||||||
|
|
||||||
public static string[] DesirableExtensions { get; } = new string[]
|
private static readonly string[] _desirableExtensions = new string[]
|
||||||
{
|
{
|
||||||
ExtConditionalRendering.ExtensionName,
|
ExtConditionalRendering.ExtensionName,
|
||||||
ExtExtendedDynamicState.ExtensionName,
|
ExtExtendedDynamicState.ExtensionName,
|
||||||
@@ -42,7 +42,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
"VK_KHR_portability_subset", // By spec, we should enable this if present.
|
"VK_KHR_portability_subset", // By spec, we should enable this if present.
|
||||||
};
|
};
|
||||||
|
|
||||||
public static string[] RequiredExtensions { get; } = new string[]
|
private static readonly string[] _requiredExtensions = new string[]
|
||||||
{
|
{
|
||||||
KhrSwapchain.ExtensionName
|
KhrSwapchain.ExtensionName
|
||||||
};
|
};
|
||||||
@@ -337,14 +337,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
string extensionName = Marshal.PtrToStringAnsi((IntPtr)pExtensionProperties[i].ExtensionName);
|
string extensionName = Marshal.PtrToStringAnsi((IntPtr)pExtensionProperties[i].ExtensionName);
|
||||||
|
|
||||||
if (RequiredExtensions.Contains(extensionName))
|
if (_requiredExtensions.Contains(extensionName))
|
||||||
{
|
{
|
||||||
extensionMatches++;
|
extensionMatches++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return extensionMatches == RequiredExtensions.Length && FindSuitableQueueFamily(api, physicalDevice, surface, out _) != InvalidIndex;
|
return extensionMatches == _requiredExtensions.Length && FindSuitableQueueFamily(api, physicalDevice, surface, out _) != InvalidIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static uint FindSuitableQueueFamily(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface, out uint queueCount)
|
internal static uint FindSuitableQueueFamily(Vk api, PhysicalDevice physicalDevice, SurfaceKHR surface, out uint queueCount)
|
||||||
@@ -626,7 +626,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
pExtendedFeatures = &featuresCustomBorderColor;
|
pExtendedFeatures = &featuresCustomBorderColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
var enabledExtensions = RequiredExtensions.Union(DesirableExtensions.Intersect(supportedExtensions)).ToArray();
|
var enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(supportedExtensions)).ToArray();
|
||||||
|
|
||||||
IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length];
|
IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length];
|
||||||
|
|
||||||
@@ -672,11 +672,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return extensionProperties.Select(x => Marshal.PtrToStringAnsi((IntPtr)x.ExtensionName)).ToArray();
|
return extensionProperties.Select(x => Marshal.PtrToStringAnsi((IntPtr)x.ExtensionName)).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static CommandBufferPool CreateCommandBufferPool(Vk api, Device device, Queue queue, object queueLock, uint queueFamilyIndex)
|
|
||||||
{
|
|
||||||
return new CommandBufferPool(api, device, queue, queueLock, queueFamilyIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal unsafe static void CreateDebugMessenger(
|
internal unsafe static void CreateDebugMessenger(
|
||||||
Vk api,
|
Vk api,
|
||||||
GraphicsDebugLevel logLevel,
|
GraphicsDebugLevel logLevel,
|
||||||
|
@@ -168,7 +168,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
SType = StructureType.PhysicalDeviceSubgroupSizeControlPropertiesExt
|
SType = StructureType.PhysicalDeviceSubgroupSizeControlPropertiesExt
|
||||||
};
|
};
|
||||||
|
|
||||||
if (Capabilities.SupportsSubgroupSizeControl)
|
bool supportsSubgroupSizeControl = supportedExtensions.Contains("VK_EXT_subgroup_size_control");
|
||||||
|
|
||||||
|
if (supportsSubgroupSizeControl)
|
||||||
{
|
{
|
||||||
properties2.PNext = &propertiesSubgroupSizeControl;
|
properties2.PNext = &propertiesSubgroupSizeControl;
|
||||||
}
|
}
|
||||||
@@ -292,7 +294,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
supportedExtensions.Contains(KhrDrawIndirectCount.ExtensionName),
|
supportedExtensions.Contains(KhrDrawIndirectCount.ExtensionName),
|
||||||
supportedExtensions.Contains("VK_EXT_fragment_shader_interlock"),
|
supportedExtensions.Contains("VK_EXT_fragment_shader_interlock"),
|
||||||
supportedExtensions.Contains("VK_NV_geometry_shader_passthrough"),
|
supportedExtensions.Contains("VK_NV_geometry_shader_passthrough"),
|
||||||
supportedExtensions.Contains("VK_EXT_subgroup_size_control"),
|
supportsSubgroupSizeControl,
|
||||||
featuresShaderInt8.ShaderInt8,
|
featuresShaderInt8.ShaderInt8,
|
||||||
supportedExtensions.Contains("VK_EXT_shader_stencil_export"),
|
supportedExtensions.Contains("VK_EXT_shader_stencil_export"),
|
||||||
supportedExtensions.Contains(ExtConditionalRendering.ExtensionName),
|
supportedExtensions.Contains(ExtConditionalRendering.ExtensionName),
|
||||||
@@ -318,7 +320,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
MemoryAllocator = new MemoryAllocator(Api, _physicalDevice, _device, properties.Limits.MaxMemoryAllocationCount);
|
MemoryAllocator = new MemoryAllocator(Api, _physicalDevice, _device, properties.Limits.MaxMemoryAllocationCount);
|
||||||
|
|
||||||
CommandBufferPool = VulkanInitialization.CreateCommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex);
|
CommandBufferPool = new CommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex);
|
||||||
|
|
||||||
DescriptorSetManager = new DescriptorSetManager(_device);
|
DescriptorSetManager = new DescriptorSetManager(_device);
|
||||||
|
|
||||||
|
@@ -14,6 +14,9 @@ namespace Ryujinx.HLE.HOS.Services.Nim
|
|||||||
// CreateServerInterface(pid, handle<unknown>, u64) -> object<nn::ec::IShopServiceAccessServer>
|
// CreateServerInterface(pid, handle<unknown>, u64) -> object<nn::ec::IShopServiceAccessServer>
|
||||||
public ResultCode CreateServerInterface(ServiceCtx context)
|
public ResultCode CreateServerInterface(ServiceCtx context)
|
||||||
{
|
{
|
||||||
|
// Close transfer memory immediately as we don't use it.
|
||||||
|
context.Device.System.KernelContext.Syscall.CloseHandle(context.Request.HandleDesc.ToCopy[0]);
|
||||||
|
|
||||||
MakeObject(context, new IShopServiceAccessServer());
|
MakeObject(context, new IShopServiceAccessServer());
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceNim);
|
Logger.Stub?.PrintStub(LogClass.ServiceNim);
|
||||||
|
@@ -4,6 +4,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Ryujinx.Horizon.Generators.Kernel
|
namespace Ryujinx.Horizon.Generators.Kernel
|
||||||
{
|
{
|
||||||
@@ -151,24 +152,15 @@ namespace Ryujinx.Horizon.Generators.Kernel
|
|||||||
GenerateMethod32(generator, context.Compilation, method);
|
GenerateMethod32(generator, context.Compilation, method);
|
||||||
GenerateMethod64(generator, context.Compilation, method);
|
GenerateMethod64(generator, context.Compilation, method);
|
||||||
|
|
||||||
foreach (var attributeList in method.AttributeLists)
|
foreach (AttributeSyntax attribute in method.AttributeLists.SelectMany(attributeList =>
|
||||||
|
attributeList.Attributes.Where(attribute =>
|
||||||
|
GetCanonicalTypeName(context.Compilation, attribute) == TypeSvcAttribute)))
|
||||||
{
|
{
|
||||||
foreach (var attribute in attributeList.Attributes)
|
syscalls.AddRange(from attributeArg in attribute.ArgumentList.Arguments
|
||||||
{
|
where attributeArg.Expression.Kind() == SyntaxKind.NumericLiteralExpression
|
||||||
if (GetCanonicalTypeName(context.Compilation, attribute) != TypeSvcAttribute)
|
select (LiteralExpressionSyntax)attributeArg.Expression
|
||||||
{
|
into numericLiteral
|
||||||
continue;
|
select new SyscallIdAndName((int)numericLiteral.Token.Value, method.Identifier.Text));
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var attributeArg in attribute.ArgumentList.Arguments)
|
|
||||||
{
|
|
||||||
if (attributeArg.Expression.Kind() == SyntaxKind.NumericLiteralExpression)
|
|
||||||
{
|
|
||||||
LiteralExpressionSyntax numericLiteral = (LiteralExpressionSyntax)attributeArg.Expression;
|
|
||||||
syscalls.Add(new SyscallIdAndName((int)numericLiteral.Token.Value, method.Identifier.Text));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,28 +502,14 @@ namespace Ryujinx.Horizon.Generators.Kernel
|
|||||||
|
|
||||||
private static string GenerateCastFromUInt64(string value, string canonicalTargetTypeName, string targetTypeName)
|
private static string GenerateCastFromUInt64(string value, string canonicalTargetTypeName, string targetTypeName)
|
||||||
{
|
{
|
||||||
if (canonicalTargetTypeName == TypeSystemBoolean)
|
return canonicalTargetTypeName == TypeSystemBoolean ? $"({value} & 1) != 0" : $"({targetTypeName}){value}";
|
||||||
{
|
|
||||||
return $"({value} & 1) != 0";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $"({targetTypeName}){value}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsPointerSized(Compilation compilation, ParameterSyntax parameterSyntax)
|
private static bool IsPointerSized(Compilation compilation, ParameterSyntax parameterSyntax)
|
||||||
{
|
{
|
||||||
foreach (var attributeList in parameterSyntax.AttributeLists)
|
return parameterSyntax.AttributeLists.Any(attributeList =>
|
||||||
{
|
attributeList.Attributes.Any(attribute =>
|
||||||
foreach (var attribute in attributeList.Attributes)
|
GetCanonicalTypeName(compilation, attribute) == TypePointerSizedAttribute));
|
||||||
{
|
|
||||||
if (GetCanonicalTypeName(compilation, attribute) == TypePointerSizedAttribute)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize(GeneratorInitializationContext context)
|
public void Initialize(GeneratorInitializationContext context)
|
||||||
|
@@ -16,38 +16,37 @@ namespace Ryujinx.Horizon.Generators.Kernel
|
|||||||
|
|
||||||
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||||
{
|
{
|
||||||
if (syntaxNode is ClassDeclarationSyntax classDeclaration && classDeclaration.AttributeLists.Count != 0)
|
if (!(syntaxNode is ClassDeclarationSyntax classDeclaration) || classDeclaration.AttributeLists.Count == 0)
|
||||||
{
|
{
|
||||||
foreach (var attributeList in classDeclaration.AttributeLists)
|
return;
|
||||||
{
|
}
|
||||||
if (attributeList.Attributes.Any(x => x.Name.GetText().ToString() == "SvcImpl"))
|
|
||||||
{
|
|
||||||
foreach (var memberDeclaration in classDeclaration.Members)
|
|
||||||
{
|
|
||||||
if (memberDeclaration is MethodDeclarationSyntax methodDeclaration)
|
|
||||||
{
|
|
||||||
VisitMethod(methodDeclaration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
if (!classDeclaration.AttributeLists.Any(attributeList =>
|
||||||
}
|
attributeList.Attributes.Any(x => x.Name.GetText().ToString() == "SvcImpl")))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var memberDeclaration in classDeclaration.Members)
|
||||||
|
{
|
||||||
|
if (memberDeclaration is MethodDeclarationSyntax methodDeclaration)
|
||||||
|
{
|
||||||
|
VisitMethod(methodDeclaration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void VisitMethod(MethodDeclarationSyntax methodDeclaration)
|
private void VisitMethod(MethodDeclarationSyntax methodDeclaration)
|
||||||
{
|
{
|
||||||
if (methodDeclaration.AttributeLists.Count != 0)
|
if (methodDeclaration.AttributeLists.Count == 0)
|
||||||
{
|
{
|
||||||
foreach (var attributeList in methodDeclaration.AttributeLists)
|
return;
|
||||||
{
|
}
|
||||||
if (attributeList.Attributes.Any(x => x.Name.GetText().ToString() == "Svc"))
|
|
||||||
{
|
if (methodDeclaration.AttributeLists.Any(attributeList =>
|
||||||
SvcImplementations.Add(methodDeclaration);
|
attributeList.Attributes.Any(x => x.Name.GetText().ToString() == "Svc")))
|
||||||
break;
|
{
|
||||||
}
|
SvcImplementations.Add(methodDeclaration);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -40,12 +40,7 @@ namespace Ryujinx.Horizon.Sdk.Sf
|
|||||||
var runtimeMetadata = context.Processor.GetRuntimeMetadata();
|
var runtimeMetadata = context.Processor.GetRuntimeMetadata();
|
||||||
Result result = context.Processor.PrepareForProcess(ref context, runtimeMetadata);
|
Result result = context.Processor.PrepareForProcess(ref context, runtimeMetadata);
|
||||||
|
|
||||||
if (result.IsFailure)
|
return result.IsFailure ? result : _invoke(ref context, _processor, runtimeMetadata, inRawData, ref outHeader);
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _invoke(ref context, _processor, runtimeMetadata, inRawData, ref outHeader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void GetCmifOutHeaderPointer(ref Span<CmifOutHeader> outHeader, ref Span<byte> outRawData)
|
public static void GetCmifOutHeaderPointer(ref Span<CmifOutHeader> outHeader, ref Span<byte> outRawData)
|
||||||
|
@@ -53,7 +53,7 @@ namespace Ryujinx.Horizon.Sdk.Sf
|
|||||||
|
|
||||||
public static void SerializeArg<T>(Span<byte> outRawData, int offset, T value) where T : unmanaged
|
public static void SerializeArg<T>(Span<byte> outRawData, int offset, T value) where T : unmanaged
|
||||||
{
|
{
|
||||||
MemoryMarshal.Cast<byte, T>(outRawData.Slice(offset, Unsafe.SizeOf<T>()))[0] = (T)value;
|
MemoryMarshal.Cast<byte, T>(outRawData.Slice(offset, Unsafe.SizeOf<T>()))[0] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SerializeCopyHandle(HipcMessageData response, int index, int value)
|
public static void SerializeCopyHandle(HipcMessageData response, int index, int value)
|
||||||
|
@@ -41,10 +41,8 @@ namespace Ryujinx.Horizon.Sdk.Sf
|
|||||||
{
|
{
|
||||||
_args = args;
|
_args = args;
|
||||||
|
|
||||||
for (int i = 0; i < args.Length; i++)
|
foreach (CommandArg argInfo in args)
|
||||||
{
|
{
|
||||||
var argInfo = args[i];
|
|
||||||
|
|
||||||
switch (argInfo.Type)
|
switch (argInfo.Type)
|
||||||
{
|
{
|
||||||
case CommandArgType.Buffer:
|
case CommandArgType.Buffer:
|
||||||
@@ -239,14 +237,13 @@ namespace Ryujinx.Horizon.Sdk.Sf
|
|||||||
{
|
{
|
||||||
return mode == HipcBufferMode.NonSecure;
|
return mode == HipcBufferMode.NonSecure;
|
||||||
}
|
}
|
||||||
else if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice))
|
|
||||||
|
if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice))
|
||||||
{
|
{
|
||||||
return mode == HipcBufferMode.NonDevice;
|
return mode == HipcBufferMode.NonDevice;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return mode == HipcBufferMode.Normal;
|
||||||
return mode == HipcBufferMode.Normal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetOutBuffers(HipcMessageData response, bool[] isBufferMapAlias)
|
public void SetOutBuffers(HipcMessageData response, bool[] isBufferMapAlias)
|
||||||
@@ -261,28 +258,30 @@ namespace Ryujinx.Horizon.Sdk.Sf
|
|||||||
}
|
}
|
||||||
|
|
||||||
var flags = _args[i].BufferFlags;
|
var flags = _args[i].BufferFlags;
|
||||||
if (flags.HasFlag(HipcBufferFlags.Out))
|
if (!flags.HasFlag(HipcBufferFlags.Out))
|
||||||
{
|
{
|
||||||
var buffer = _bufferRanges[i];
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags.HasFlag(HipcBufferFlags.Pointer))
|
var buffer = _bufferRanges[i];
|
||||||
|
|
||||||
|
if (flags.HasFlag(HipcBufferFlags.Pointer))
|
||||||
|
{
|
||||||
|
response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(buffer.Address, (ushort)buffer.Size, recvPointerIndex);
|
||||||
|
}
|
||||||
|
else if (flags.HasFlag(HipcBufferFlags.AutoSelect))
|
||||||
|
{
|
||||||
|
if (!isBufferMapAlias[i])
|
||||||
{
|
{
|
||||||
response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(buffer.Address, (ushort)buffer.Size, recvPointerIndex);
|
response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(buffer.Address, (ushort)buffer.Size, recvPointerIndex);
|
||||||
}
|
}
|
||||||
else if (flags.HasFlag(HipcBufferFlags.AutoSelect))
|
else
|
||||||
{
|
{
|
||||||
if (!isBufferMapAlias[i])
|
response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(0UL, 0, recvPointerIndex);
|
||||||
{
|
|
||||||
response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(buffer.Address, (ushort)buffer.Size, recvPointerIndex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
response.SendStatics[recvPointerIndex] = new HipcStaticDescriptor(0UL, 0, recvPointerIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
recvPointerIndex++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recvPointerIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,15 +338,17 @@ namespace Ryujinx.Horizon.Sdk.Sf
|
|||||||
|
|
||||||
int inObjectIndex = 0;
|
int inObjectIndex = 0;
|
||||||
|
|
||||||
for (int i = 0; i < _args.Length; i++)
|
foreach (CommandArg t in _args)
|
||||||
{
|
{
|
||||||
if (_args[i].Type == CommandArgType.InObject)
|
if (t.Type != CommandArgType.InObject)
|
||||||
{
|
{
|
||||||
int index = inObjectIndex++;
|
continue;
|
||||||
var inObject = inObjects[index];
|
|
||||||
|
|
||||||
objects[index] = inObject?.ServiceObject;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int index = inObjectIndex++;
|
||||||
|
var inObject = inObjects[index];
|
||||||
|
|
||||||
|
objects[index] = inObject?.ServiceObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result.Success;
|
return Result.Success;
|
||||||
|
@@ -37,12 +37,7 @@ namespace Ryujinx.Horizon.Sm.Impl
|
|||||||
|
|
||||||
result = GetServiceImpl(out handle, ref _services[serviceIndex]);
|
result = GetServiceImpl(out handle, ref _services[serviceIndex]);
|
||||||
|
|
||||||
if (result == KernelResult.SessionCountExceeded)
|
return result == KernelResult.SessionCountExceeded ? SmResult.OutOfSessions : result;
|
||||||
{
|
|
||||||
return SmResult.OutOfSessions;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result GetServiceImpl(out int handle, ref ServiceInfo serviceInfo)
|
private Result GetServiceImpl(out int handle, ref ServiceInfo serviceInfo)
|
||||||
@@ -61,13 +56,7 @@ namespace Ryujinx.Horizon.Sm.Impl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Validation with GetProcessInfo etc.
|
// TODO: Validation with GetProcessInfo etc.
|
||||||
|
return HasServiceInfo(name) ? SmResult.AlreadyRegistered : RegisterServiceImpl(out handle, processId, name, maxSessions, isLight);
|
||||||
if (HasServiceInfo(name))
|
|
||||||
{
|
|
||||||
return SmResult.AlreadyRegistered;
|
|
||||||
}
|
|
||||||
|
|
||||||
return RegisterServiceImpl(out handle, processId, name, maxSessions, isLight);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result RegisterServiceForSelf(out int handle, ServiceName name, int maxSessions)
|
public Result RegisterServiceForSelf(out int handle, ServiceName name, int maxSessions)
|
||||||
|
Reference in New Issue
Block a user