Merge remote-tracking branch 'origin' into riperiperi/a32-wip
This commit is contained in:
commit
491154c7bb
49 changed files with 522 additions and 639 deletions
|
@ -1,6 +1,7 @@
|
|||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
|
@ -552,6 +553,50 @@ namespace ARMeilleure.Memory
|
|||
return data;
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> GetSpan(ulong address, ulong size)
|
||||
{
|
||||
if (IsContiguous(address, size))
|
||||
{
|
||||
return new ReadOnlySpan<byte>((void*)Translate((long)address), (int)size);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ReadBytes((long)address, (long)size);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool IsContiguous(ulong address, ulong size)
|
||||
{
|
||||
if (!IsValidPosition((long)address))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ulong endVa = (address + size + PageMask) & ~(ulong)PageMask;
|
||||
|
||||
address &= ~(ulong)PageMask;
|
||||
|
||||
int pages = (int)((endVa - address) / PageSize);
|
||||
|
||||
for (int page = 0; page < pages - 1; page++)
|
||||
{
|
||||
if (!IsValidPosition((long)address + PageSize))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetPtEntry((long)address) + PageSize != GetPtEntry((long)address + PageSize))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
address += PageSize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void WriteSByte(long position, sbyte value)
|
||||
{
|
||||
WriteByte(position, (byte)value);
|
||||
|
|
|
@ -58,9 +58,12 @@ namespace ARMeilleure.Translation
|
|||
{
|
||||
if (Interlocked.Increment(ref _threadCount) == 1)
|
||||
{
|
||||
Thread backgroundTranslatorThread = new Thread(TranslateQueuedSubs);
|
||||
Thread backgroundTranslatorThread = new Thread(TranslateQueuedSubs)
|
||||
{
|
||||
Name = "CPU.BackgroundTranslatorThread",
|
||||
Priority = ThreadPriority.Lowest
|
||||
};
|
||||
|
||||
backgroundTranslatorThread.Priority = ThreadPriority.Lowest;
|
||||
backgroundTranslatorThread.Start();
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,10 @@ namespace Ryujinx.Audio
|
|||
_context = new AudioContext();
|
||||
_tracks = new ConcurrentDictionary<int, OpenALAudioTrack>();
|
||||
_keepPolling = true;
|
||||
_audioPollerThread = new Thread(AudioPollerWork);
|
||||
_audioPollerThread = new Thread(AudioPollerWork)
|
||||
{
|
||||
Name = "Audio.PollerThread"
|
||||
};
|
||||
|
||||
_audioPollerThread.Start();
|
||||
}
|
||||
|
|
|
@ -18,8 +18,13 @@ namespace Ryujinx.Common.Logging
|
|||
|
||||
sb.AppendFormat(@"{0:hh\:mm\:ss\.fff}", args.Time);
|
||||
sb.Append(" | ");
|
||||
sb.AppendFormat("{0:d4}", args.ThreadId);
|
||||
sb.Append(' ');
|
||||
|
||||
if (args.ThreadName != null)
|
||||
{
|
||||
sb.Append(args.ThreadName);
|
||||
sb.Append(' ');
|
||||
}
|
||||
|
||||
sb.Append(args.Message);
|
||||
|
||||
if (args.Data != null)
|
||||
|
|
|
@ -4,28 +4,28 @@ namespace Ryujinx.Common.Logging
|
|||
{
|
||||
public class LogEventArgs : EventArgs
|
||||
{
|
||||
public LogLevel Level { get; private set; }
|
||||
public TimeSpan Time { get; private set; }
|
||||
public int ThreadId { get; private set; }
|
||||
public LogLevel Level { get; private set; }
|
||||
public TimeSpan Time { get; private set; }
|
||||
public string ThreadName { get; private set; }
|
||||
|
||||
public string Message { get; private set; }
|
||||
public object Data { get; private set; }
|
||||
|
||||
public LogEventArgs(LogLevel level, TimeSpan time, int threadId, string message)
|
||||
public LogEventArgs(LogLevel level, TimeSpan time, string threadName, string message)
|
||||
{
|
||||
Level = level;
|
||||
Time = time;
|
||||
ThreadId = threadId;
|
||||
Message = message;
|
||||
Level = level;
|
||||
Time = time;
|
||||
ThreadName = threadName;
|
||||
Message = message;
|
||||
}
|
||||
|
||||
public LogEventArgs(LogLevel level, TimeSpan time, int threadId, string message, object data)
|
||||
public LogEventArgs(LogLevel level, TimeSpan time, string threadName, string message, object data)
|
||||
{
|
||||
Level = level;
|
||||
Time = time;
|
||||
ThreadId = threadId;
|
||||
Message = message;
|
||||
Data = data;
|
||||
Level = level;
|
||||
Time = time;
|
||||
ThreadName = threadName;
|
||||
Message = message;
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -155,7 +155,7 @@ namespace Ryujinx.Common.Logging
|
|||
{
|
||||
if (m_EnabledLevels[(int)logLevel] && m_EnabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(logLevel, m_Time.Elapsed, Thread.CurrentThread.ManagedThreadId, message));
|
||||
Updated?.Invoke(null, new LogEventArgs(logLevel, m_Time.Elapsed, Thread.CurrentThread.Name, message));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,7 @@ namespace Ryujinx.Common.Logging
|
|||
{
|
||||
if (m_EnabledLevels[(int)logLevel] && m_EnabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(logLevel, m_Time.Elapsed, Thread.CurrentThread.ManagedThreadId, message, data));
|
||||
Updated?.Invoke(null, new LogEventArgs(logLevel, m_Time.Elapsed, Thread.CurrentThread.Name, message, data));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ namespace Ryujinx.Common.Logging
|
|||
}
|
||||
});
|
||||
|
||||
_messageThread.Name = "Logger.MessageThread";
|
||||
_messageThread.IsBackground = true;
|
||||
_messageThread.Start();
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@ namespace Ryujinx.Graphics.GAL
|
|||
|
||||
byte[] GetData(int offset, int size);
|
||||
|
||||
void SetData(Span<byte> data);
|
||||
void SetData(ReadOnlySpan<byte> data);
|
||||
|
||||
void SetData(int offset, Span<byte> data);
|
||||
void SetData(int offset, ReadOnlySpan<byte> data);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,8 @@ namespace Ryujinx.Graphics.GAL
|
|||
{
|
||||
public interface IPipeline
|
||||
{
|
||||
void Barrier();
|
||||
|
||||
void ClearRenderTargetColor(int index, uint componentMask, ColorF color);
|
||||
|
||||
void ClearRenderTargetDepthStencil(
|
||||
|
|
|
@ -18,8 +18,6 @@ namespace Ryujinx.Graphics.GAL
|
|||
ISampler CreateSampler(SamplerCreateInfo info);
|
||||
ITexture CreateTexture(TextureCreateInfo info);
|
||||
|
||||
void FlushPipelines();
|
||||
|
||||
Capabilities GetCapabilities();
|
||||
|
||||
ulong GetCounter(CounterType type);
|
||||
|
|
|
@ -11,6 +11,6 @@ namespace Ryujinx.Graphics.GAL
|
|||
|
||||
byte[] GetData();
|
||||
|
||||
void SetData(Span<byte> data);
|
||||
void SetData(ReadOnlySpan<byte> data);
|
||||
}
|
||||
}
|
|
@ -77,7 +77,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|||
|
||||
sbDescAddress += (ulong)sbDescOffset;
|
||||
|
||||
Span<byte> sbDescriptorData = _context.PhysicalMemory.Read(sbDescAddress, 0x10);
|
||||
ReadOnlySpan<byte> sbDescriptorData = _context.PhysicalMemory.GetSpan(sbDescAddress, 0x10);
|
||||
|
||||
SbDescriptor sbDescriptor = MemoryMarshal.Cast<byte, SbDescriptor>(sbDescriptorData)[0];
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|||
ulong srcAddress = srcBaseAddress + (ulong)srcOffset;
|
||||
ulong dstAddress = dstBaseAddress + (ulong)dstOffset;
|
||||
|
||||
Span<byte> pixel = _context.PhysicalMemory.Read(srcAddress, (ulong)srcBpp);
|
||||
ReadOnlySpan<byte> pixel = _context.PhysicalMemory.GetSpan(srcAddress, (ulong)srcBpp);
|
||||
|
||||
_context.PhysicalMemory.Write(dstAddress, pixel);
|
||||
}
|
||||
|
|
|
@ -235,7 +235,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|||
|
||||
sbDescAddress += (ulong)sbDescOffset;
|
||||
|
||||
Span<byte> sbDescriptorData = _context.PhysicalMemory.Read(sbDescAddress, 0x10);
|
||||
ReadOnlySpan<byte> sbDescriptorData = _context.PhysicalMemory.GetSpan(sbDescAddress, 0x10);
|
||||
|
||||
SbDescriptor sbDescriptor = MemoryMarshal.Cast<byte, SbDescriptor>(sbDescriptorData)[0];
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
{
|
||||
ulong address = Address + (ulong)(uint)id * DescriptorSize;
|
||||
|
||||
Span<byte> data = Context.PhysicalMemory.Read(address, DescriptorSize);
|
||||
ReadOnlySpan<byte> data = Context.PhysicalMemory.GetSpan(address, DescriptorSize);
|
||||
|
||||
SamplerDescriptor descriptor = MemoryMarshal.Cast<byte, SamplerDescriptor>(data)[0];
|
||||
|
||||
|
|
|
@ -304,7 +304,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
return;
|
||||
}
|
||||
|
||||
Span<byte> data = _context.PhysicalMemory.Read(Address, Size);
|
||||
ReadOnlySpan<byte> data = _context.PhysicalMemory.GetSpan(Address, Size);
|
||||
|
||||
if (Info.IsLinear)
|
||||
{
|
||||
|
|
|
@ -197,7 +197,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
address = bufferManager.GetGraphicsUniformBufferAddress(stageIndex, binding.CbufSlot);
|
||||
}
|
||||
|
||||
packedId = MemoryMarshal.Cast<byte, int>(_context.PhysicalMemory.Read(address + (ulong)binding.CbufOffset * 4, 4))[0];
|
||||
packedId = MemoryMarshal.Cast<byte, int>(_context.PhysicalMemory.GetSpan(address + (ulong)binding.CbufOffset * 4, 4))[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -321,7 +321,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
address += (uint)wordOffset * 4;
|
||||
|
||||
return BitConverter.ToInt32(_context.PhysicalMemory.Read(address, 4));
|
||||
return BitConverter.ToInt32(_context.PhysicalMemory.GetSpan(address, 4));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -85,7 +85,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
{
|
||||
ulong address = Address + (ulong)(uint)id * DescriptorSize;
|
||||
|
||||
Span<byte> data = Context.PhysicalMemory.Read(address, DescriptorSize);
|
||||
ReadOnlySpan<byte> data = Context.PhysicalMemory.GetSpan(address, DescriptorSize);
|
||||
|
||||
return MemoryMarshal.Cast<byte, TextureDescriptor>(data)[0];
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
|
||||
if (texture != null)
|
||||
{
|
||||
Span<byte> data = Context.PhysicalMemory.Read(address, DescriptorSize);
|
||||
ReadOnlySpan<byte> data = Context.PhysicalMemory.GetSpan(address, DescriptorSize);
|
||||
|
||||
TextureDescriptor descriptor = MemoryMarshal.Cast<byte, TextureDescriptor>(data)[0];
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
|
||||
int offset = (int)(mAddress - Address);
|
||||
|
||||
HostBuffer.SetData(offset, _context.PhysicalMemory.Read(mAddress, mSize));
|
||||
HostBuffer.SetData(offset, _context.PhysicalMemory.GetSpan(mAddress, mSize));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// </summary>
|
||||
public void Invalidate()
|
||||
{
|
||||
HostBuffer.SetData(0, _context.PhysicalMemory.Read(Address, Size));
|
||||
HostBuffer.SetData(0, _context.PhysicalMemory.GetSpan(Address, Size));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -27,23 +27,23 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// <returns>Byte array with the data</returns>
|
||||
public byte[] ReadBytes(ulong gpuVa, ulong size)
|
||||
{
|
||||
return Read(gpuVa, size).ToArray();
|
||||
return GetSpan(gpuVa, size).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads data from GPU mapped memory.
|
||||
/// Gets a read-only span of data from GPU mapped memory.
|
||||
/// This reads as much data as possible, up to the specified maximum size.
|
||||
/// </summary>
|
||||
/// <param name="gpuVa">GPU virtual address where the data is located</param>
|
||||
/// <param name="maxSize">Maximum size of the data</param>
|
||||
/// <returns>The data at the specified memory location</returns>
|
||||
public Span<byte> Read(ulong gpuVa, ulong maxSize)
|
||||
/// <returns>The span of the data at the specified memory location</returns>
|
||||
public ReadOnlySpan<byte> GetSpan(ulong gpuVa, ulong maxSize)
|
||||
{
|
||||
ulong processVa = _context.MemoryManager.Translate(gpuVa);
|
||||
|
||||
ulong size = Math.Min(_context.MemoryManager.GetSubSize(gpuVa), maxSize);
|
||||
|
||||
return _context.PhysicalMemory.Read(processVa, size);
|
||||
return _context.PhysicalMemory.GetSpan(processVa, size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
|
||||
ulong size = (uint)Marshal.SizeOf<T>();
|
||||
|
||||
return MemoryMarshal.Cast<byte, T>(_context.PhysicalMemory.Read(processVa, size))[0];
|
||||
return MemoryMarshal.Cast<byte, T>(_context.PhysicalMemory.GetSpan(processVa, size))[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -70,7 +70,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
{
|
||||
ulong processVa = _context.MemoryManager.Translate(gpuVa);
|
||||
|
||||
return BitConverter.ToInt32(_context.PhysicalMemory.Read(processVa, 4));
|
||||
return BitConverter.ToInt32(_context.PhysicalMemory.GetSpan(processVa, 4));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -82,7 +82,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
{
|
||||
ulong processVa = _context.MemoryManager.Translate(gpuVa);
|
||||
|
||||
return BitConverter.ToUInt64(_context.PhysicalMemory.Read(processVa, 8));
|
||||
return BitConverter.ToUInt64(_context.PhysicalMemory.GetSpan(processVa, 8));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -22,14 +22,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads data from the application process.
|
||||
/// Gets a span of data from the application process.
|
||||
/// </summary>
|
||||
/// <param name="address">Address to be read</param>
|
||||
/// <param name="size">Size in bytes to be read</param>
|
||||
/// <returns>The data at the specified memory location</returns>
|
||||
public Span<byte> Read(ulong address, ulong size)
|
||||
/// <param name="address">Start address of the range</param>
|
||||
/// <param name="size">Size in bytes to be range</param>
|
||||
/// <returns>A read only span of the data at the specified memory location</returns>
|
||||
public ReadOnlySpan<byte> GetSpan(ulong address, ulong size)
|
||||
{
|
||||
return _cpuMemory.ReadBytes((long)address, (long)size);
|
||||
return _cpuMemory.GetSpan(address, size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -37,7 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// </summary>
|
||||
/// <param name="address">Address to write into</param>
|
||||
/// <param name="data">Data to be written</param>
|
||||
public void Write(ulong address, Span<byte> data)
|
||||
public void Write(ulong address, ReadOnlySpan<byte> data)
|
||||
{
|
||||
_cpuMemory.WriteBytes((long)address, data.ToArray());
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ namespace Ryujinx.Graphics.Gpu
|
|||
{
|
||||
_context.Methods.PerformDeferredDraws();
|
||||
|
||||
_context.Renderer.FlushPipelines();
|
||||
_context.Renderer.Pipeline.Barrier();
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -265,7 +265,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||
|
||||
ShaderProgram program;
|
||||
|
||||
Span<byte> code = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
|
||||
ReadOnlySpan<byte> code = _context.MemoryAccessor.GetSpan(gpuVa, MaxProgramSize);
|
||||
|
||||
program = Translator.Translate(code, callbacks, DefaultFlags | TranslationFlags.Compute);
|
||||
|
||||
|
@ -319,8 +319,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||
|
||||
if (gpuVaA != 0)
|
||||
{
|
||||
Span<byte> codeA = _context.MemoryAccessor.Read(gpuVaA, MaxProgramSize);
|
||||
Span<byte> codeB = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
|
||||
ReadOnlySpan<byte> codeA = _context.MemoryAccessor.GetSpan(gpuVaA, MaxProgramSize);
|
||||
ReadOnlySpan<byte> codeB = _context.MemoryAccessor.GetSpan(gpuVa, MaxProgramSize);
|
||||
|
||||
program = Translator.Translate(codeA, codeB, callbacks, DefaultFlags);
|
||||
|
||||
|
@ -340,7 +340,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||
}
|
||||
else
|
||||
{
|
||||
Span<byte> code = _context.MemoryAccessor.Read(gpuVa, MaxProgramSize);
|
||||
ReadOnlySpan<byte> code = _context.MemoryAccessor.GetSpan(gpuVa, MaxProgramSize);
|
||||
|
||||
program = Translator.Translate(code, callbacks, DefaultFlags);
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||
/// <param name="compute">True for compute shader code, false for graphics shader code</param>
|
||||
/// <param name="fullPath">Output path for the shader code with header included</param>
|
||||
/// <param name="codePath">Output path for the shader code without header</param>
|
||||
public void Dump(Span<byte> code, bool compute, out string fullPath, out string codePath)
|
||||
public void Dump(ReadOnlySpan<byte> code, bool compute, out string fullPath, out string codePath)
|
||||
{
|
||||
_dumpPath = GraphicsConfig.ShadersDumpPath;
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
return data;
|
||||
}
|
||||
|
||||
public void SetData(Span<byte> data)
|
||||
public void SetData(ReadOnlySpan<byte> data)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
|
@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
public void SetData(int offset, Span<byte> data)
|
||||
public void SetData(int offset, ReadOnlySpan<byte> data)
|
||||
{
|
||||
GL.BindBuffer(BufferTarget.CopyWriteBuffer, Handle);
|
||||
|
||||
|
|
|
@ -37,6 +37,11 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
_clipDepthMode = ClipDepthMode.NegativeOneToOne;
|
||||
}
|
||||
|
||||
public void Barrier()
|
||||
{
|
||||
GL.MemoryBarrier(MemoryBarrierFlags.AllBarrierBits);
|
||||
}
|
||||
|
||||
public void ClearRenderTargetColor(int index, uint componentMask, ColorF color)
|
||||
{
|
||||
GL.ColorMask(
|
||||
|
@ -165,26 +170,35 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
int firstVertex,
|
||||
int firstInstance)
|
||||
{
|
||||
// TODO: Instanced rendering.
|
||||
int quadsCount = (vertexCount - 2) / 2;
|
||||
|
||||
int[] firsts = new int[quadsCount];
|
||||
int[] counts = new int[quadsCount];
|
||||
|
||||
firsts[0] = firstVertex;
|
||||
counts[0] = 4;
|
||||
|
||||
for (int quadIndex = 1; quadIndex < quadsCount; quadIndex++)
|
||||
if (firstInstance != 0 || instanceCount != 1)
|
||||
{
|
||||
firsts[quadIndex] = firstVertex + quadIndex * 2;
|
||||
counts[quadIndex] = 4;
|
||||
for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++)
|
||||
{
|
||||
GL.DrawArraysInstancedBaseInstance(PrimitiveType.TriangleFan, firstVertex + quadIndex * 2, 4, instanceCount, firstInstance);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int[] firsts = new int[quadsCount];
|
||||
int[] counts = new int[quadsCount];
|
||||
|
||||
GL.MultiDrawArrays(
|
||||
PrimitiveType.TriangleFan,
|
||||
firsts,
|
||||
counts,
|
||||
quadsCount);
|
||||
firsts[0] = firstVertex;
|
||||
counts[0] = 4;
|
||||
|
||||
for (int quadIndex = 1; quadIndex < quadsCount; quadIndex++)
|
||||
{
|
||||
firsts[quadIndex] = firstVertex + quadIndex * 2;
|
||||
counts[quadIndex] = 4;
|
||||
}
|
||||
|
||||
GL.MultiDrawArrays(
|
||||
PrimitiveType.TriangleFan,
|
||||
firsts,
|
||||
counts,
|
||||
quadsCount);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawImpl(
|
||||
|
@ -277,31 +291,75 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
int firstVertex,
|
||||
int firstInstance)
|
||||
{
|
||||
// TODO: Instanced rendering.
|
||||
int quadsCount = indexCount / 4;
|
||||
|
||||
IntPtr[] indices = new IntPtr[quadsCount];
|
||||
|
||||
int[] counts = new int[quadsCount];
|
||||
|
||||
int[] baseVertices = new int[quadsCount];
|
||||
|
||||
for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++)
|
||||
if (firstInstance != 0 || instanceCount != 1)
|
||||
{
|
||||
indices[quadIndex] = indexBaseOffset + quadIndex * 4 * indexElemSize;
|
||||
|
||||
counts[quadIndex] = 4;
|
||||
|
||||
baseVertices[quadIndex] = firstVertex;
|
||||
if (firstVertex != 0 && firstInstance != 0)
|
||||
{
|
||||
for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++)
|
||||
{
|
||||
GL.DrawElementsInstancedBaseVertexBaseInstance(
|
||||
PrimitiveType.TriangleFan,
|
||||
4,
|
||||
_elementsType,
|
||||
indexBaseOffset + quadIndex * 4 * indexElemSize,
|
||||
instanceCount,
|
||||
firstVertex,
|
||||
firstInstance);
|
||||
}
|
||||
}
|
||||
else if (firstInstance != 0)
|
||||
{
|
||||
for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++)
|
||||
{
|
||||
GL.DrawElementsInstancedBaseInstance(
|
||||
PrimitiveType.TriangleFan,
|
||||
4,
|
||||
_elementsType,
|
||||
indexBaseOffset + quadIndex * 4 * indexElemSize,
|
||||
instanceCount,
|
||||
firstInstance);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++)
|
||||
{
|
||||
GL.DrawElementsInstanced(
|
||||
PrimitiveType.TriangleFan,
|
||||
4,
|
||||
_elementsType,
|
||||
indexBaseOffset + quadIndex * 4 * indexElemSize,
|
||||
instanceCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IntPtr[] indices = new IntPtr[quadsCount];
|
||||
|
||||
GL.MultiDrawElementsBaseVertex(
|
||||
PrimitiveType.TriangleFan,
|
||||
counts,
|
||||
_elementsType,
|
||||
indices,
|
||||
quadsCount,
|
||||
baseVertices);
|
||||
int[] counts = new int[quadsCount];
|
||||
|
||||
int[] baseVertices = new int[quadsCount];
|
||||
|
||||
for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++)
|
||||
{
|
||||
indices[quadIndex] = indexBaseOffset + quadIndex * 4 * indexElemSize;
|
||||
|
||||
counts[quadIndex] = 4;
|
||||
|
||||
baseVertices[quadIndex] = firstVertex;
|
||||
}
|
||||
|
||||
GL.MultiDrawElementsBaseVertex(
|
||||
PrimitiveType.TriangleFan,
|
||||
counts,
|
||||
_elementsType,
|
||||
indices,
|
||||
quadsCount,
|
||||
baseVertices);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawQuadStripIndexedImpl(
|
||||
|
|
|
@ -55,11 +55,6 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
return new TextureStorage(this, info).CreateDefaultView();
|
||||
}
|
||||
|
||||
public void FlushPipelines()
|
||||
{
|
||||
GL.Finish();
|
||||
}
|
||||
|
||||
public Capabilities GetCapabilities()
|
||||
{
|
||||
return new Capabilities(
|
||||
|
|
|
@ -217,7 +217,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
public void SetData(Span<byte> data)
|
||||
public void SetData(ReadOnlySpan<byte> data)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||
_opActivators = new ConcurrentDictionary<Type, OpActivator>();
|
||||
}
|
||||
|
||||
public static Block[] Decode(Span<byte> code, ulong headerSize)
|
||||
public static Block[] Decode(ReadOnlySpan<byte> code, ulong headerSize)
|
||||
{
|
||||
List<Block> blocks = new List<Block>();
|
||||
|
||||
|
@ -214,10 +214,10 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||
}
|
||||
|
||||
private static void FillBlock(
|
||||
Span<byte> code,
|
||||
Block block,
|
||||
ulong limitAddress,
|
||||
ulong startAddress)
|
||||
ReadOnlySpan<byte> code,
|
||||
Block block,
|
||||
ulong limitAddress,
|
||||
ulong startAddress)
|
||||
{
|
||||
ulong address = block.Address;
|
||||
|
||||
|
|
|
@ -76,9 +76,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
public bool OmapSampleMask { get; }
|
||||
public bool OmapDepth { get; }
|
||||
|
||||
public ShaderHeader(Span<byte> code)
|
||||
public ShaderHeader(ReadOnlySpan<byte> code)
|
||||
{
|
||||
Span<int> header = MemoryMarshal.Cast<byte, int>(code);
|
||||
ReadOnlySpan<int> header = MemoryMarshal.Cast<byte, int>(code);
|
||||
|
||||
int commonWord0 = header[0];
|
||||
int commonWord1 = header[1];
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
{
|
||||
private const int HeaderSize = 0x50;
|
||||
|
||||
public static Span<byte> ExtractCode(Span<byte> code, bool compute, out int headerSize)
|
||||
public static ReadOnlySpan<byte> ExtractCode(ReadOnlySpan<byte> code, bool compute, out int headerSize)
|
||||
{
|
||||
headerSize = compute ? 0 : HeaderSize;
|
||||
|
||||
|
@ -38,14 +38,14 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
return code.Slice(0, headerSize + (int)endAddress);
|
||||
}
|
||||
|
||||
public static ShaderProgram Translate(Span<byte> code, TranslatorCallbacks callbacks, TranslationFlags flags)
|
||||
public static ShaderProgram Translate(ReadOnlySpan<byte> code, TranslatorCallbacks callbacks, TranslationFlags flags)
|
||||
{
|
||||
Operation[] ops = DecodeShader(code, callbacks, flags, out ShaderConfig config, out int size);
|
||||
|
||||
return Translate(ops, config, size);
|
||||
}
|
||||
|
||||
public static ShaderProgram Translate(Span<byte> vpACode, Span<byte> vpBCode, TranslatorCallbacks callbacks, TranslationFlags flags)
|
||||
public static ShaderProgram Translate(ReadOnlySpan<byte> vpACode, ReadOnlySpan<byte> vpBCode, TranslatorCallbacks callbacks, TranslationFlags flags)
|
||||
{
|
||||
Operation[] vpAOps = DecodeShader(vpACode, callbacks, flags, out _, out _);
|
||||
Operation[] vpBOps = DecodeShader(vpBCode, callbacks, flags, out ShaderConfig config, out int sizeB);
|
||||
|
@ -88,7 +88,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
}
|
||||
|
||||
private static Operation[] DecodeShader(
|
||||
Span<byte> code,
|
||||
ReadOnlySpan<byte> code,
|
||||
TranslatorCallbacks callbacks,
|
||||
TranslationFlags flags,
|
||||
out ShaderConfig config,
|
||||
|
|
|
@ -28,6 +28,8 @@ namespace Ryujinx.HLE.FileSystem.Content
|
|||
|
||||
private Switch _device;
|
||||
|
||||
private readonly object _lock = new object();
|
||||
|
||||
public ContentManager(Switch device)
|
||||
{
|
||||
_contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>();
|
||||
|
@ -58,139 +60,151 @@ namespace Ryujinx.HLE.FileSystem.Content
|
|||
|
||||
public void LoadEntries(bool ignoreMissingFonts = false)
|
||||
{
|
||||
_contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>();
|
||||
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
|
||||
|
||||
foreach (StorageId storageId in Enum.GetValues(typeof(StorageId)))
|
||||
lock (_lock)
|
||||
{
|
||||
string contentDirectory = null;
|
||||
string contentPathString = null;
|
||||
string registeredDirectory = null;
|
||||
_contentDictionary = new SortedDictionary<(ulong, NcaContentType), string>();
|
||||
_locationEntries = new Dictionary<StorageId, LinkedList<LocationEntry>>();
|
||||
|
||||
try
|
||||
foreach (StorageId storageId in Enum.GetValues(typeof(StorageId)))
|
||||
{
|
||||
contentPathString = LocationHelper.GetContentRoot(storageId);
|
||||
contentDirectory = LocationHelper.GetRealPath(_device.FileSystem, contentPathString);
|
||||
registeredDirectory = Path.Combine(contentDirectory, "registered");
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string contentDirectory = null;
|
||||
string contentPathString = null;
|
||||
string registeredDirectory = null;
|
||||
|
||||
Directory.CreateDirectory(registeredDirectory);
|
||||
|
||||
LinkedList<LocationEntry> locationList = new LinkedList<LocationEntry>();
|
||||
|
||||
void AddEntry(LocationEntry entry)
|
||||
{
|
||||
locationList.AddLast(entry);
|
||||
}
|
||||
|
||||
foreach (string directoryPath in Directory.EnumerateDirectories(registeredDirectory))
|
||||
{
|
||||
if (Directory.GetFiles(directoryPath).Length > 0)
|
||||
try
|
||||
{
|
||||
string ncaName = new DirectoryInfo(directoryPath).Name.Replace(".nca", string.Empty);
|
||||
contentPathString = LocationHelper.GetContentRoot(storageId);
|
||||
contentDirectory = LocationHelper.GetRealPath(_device.FileSystem, contentPathString);
|
||||
registeredDirectory = Path.Combine(contentDirectory, "registered");
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
using (FileStream ncaFile = new FileStream(Directory.GetFiles(directoryPath)[0], FileMode.Open, FileAccess.Read))
|
||||
Directory.CreateDirectory(registeredDirectory);
|
||||
|
||||
LinkedList<LocationEntry> locationList = new LinkedList<LocationEntry>();
|
||||
|
||||
void AddEntry(LocationEntry entry)
|
||||
{
|
||||
locationList.AddLast(entry);
|
||||
}
|
||||
|
||||
foreach (string directoryPath in Directory.EnumerateDirectories(registeredDirectory))
|
||||
{
|
||||
if (Directory.GetFiles(directoryPath).Length > 0)
|
||||
{
|
||||
Nca nca = new Nca(_device.System.KeySet, ncaFile.AsStorage());
|
||||
string ncaName = new DirectoryInfo(directoryPath).Name.Replace(".nca", string.Empty);
|
||||
|
||||
string switchPath = contentPathString + ":/" + ncaFile.Name.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar);
|
||||
using (FileStream ncaFile = File.OpenRead(Directory.GetFiles(directoryPath)[0]))
|
||||
{
|
||||
Nca nca = new Nca(_device.System.KeySet, ncaFile.AsStorage());
|
||||
|
||||
// Change path format to switch's
|
||||
switchPath = switchPath.Replace('\\', '/');
|
||||
string switchPath = contentPathString + ":/" + ncaFile.Name.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar);
|
||||
|
||||
LocationEntry entry = new LocationEntry(switchPath,
|
||||
0,
|
||||
(long)nca.Header.TitleId,
|
||||
nca.Header.ContentType);
|
||||
// Change path format to switch's
|
||||
switchPath = switchPath.Replace('\\', '/');
|
||||
|
||||
AddEntry(entry);
|
||||
LocationEntry entry = new LocationEntry(switchPath,
|
||||
0,
|
||||
(long)nca.Header.TitleId,
|
||||
nca.Header.ContentType);
|
||||
|
||||
_contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName);
|
||||
AddEntry(entry);
|
||||
|
||||
_contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string filePath in Directory.EnumerateFiles(contentDirectory))
|
||||
{
|
||||
if (Path.GetExtension(filePath) == ".nca")
|
||||
{
|
||||
string ncaName = Path.GetFileNameWithoutExtension(filePath);
|
||||
|
||||
using (FileStream ncaFile = new FileStream(filePath, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
Nca nca = new Nca(_device.System.KeySet, ncaFile.AsStorage());
|
||||
|
||||
string switchPath = contentPathString + ":/" + filePath.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar);
|
||||
|
||||
// Change path format to switch's
|
||||
switchPath = switchPath.Replace('\\', '/');
|
||||
|
||||
LocationEntry entry = new LocationEntry(switchPath,
|
||||
0,
|
||||
(long)nca.Header.TitleId,
|
||||
nca.Header.ContentType);
|
||||
|
||||
AddEntry(entry);
|
||||
|
||||
_contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_locationEntries.ContainsKey(storageId) && _locationEntries[storageId]?.Count == 0)
|
||||
{
|
||||
_locationEntries.Remove(storageId);
|
||||
}
|
||||
|
||||
if (!_locationEntries.ContainsKey(storageId))
|
||||
{
|
||||
_locationEntries.Add(storageId, locationList);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string filePath in Directory.EnumerateFiles(contentDirectory))
|
||||
{
|
||||
if (Path.GetExtension(filePath) == ".nca")
|
||||
{
|
||||
string ncaName = Path.GetFileNameWithoutExtension(filePath);
|
||||
TimeManager.Instance.InitializeTimeZone(_device);
|
||||
|
||||
using (FileStream ncaFile = new FileStream(filePath, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
Nca nca = new Nca(_device.System.KeySet, ncaFile.AsStorage());
|
||||
|
||||
string switchPath = contentPathString + ":/" + filePath.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar);
|
||||
|
||||
// Change path format to switch's
|
||||
switchPath = switchPath.Replace('\\', '/');
|
||||
|
||||
LocationEntry entry = new LocationEntry(switchPath,
|
||||
0,
|
||||
(long)nca.Header.TitleId,
|
||||
nca.Header.ContentType);
|
||||
|
||||
AddEntry(entry);
|
||||
|
||||
_contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_locationEntries.ContainsKey(storageId) && _locationEntries[storageId]?.Count == 0)
|
||||
{
|
||||
_locationEntries.Remove(storageId);
|
||||
}
|
||||
|
||||
if (!_locationEntries.ContainsKey(storageId))
|
||||
{
|
||||
_locationEntries.Add(storageId, locationList);
|
||||
}
|
||||
_device.System.Font.Initialize(this, ignoreMissingFonts);
|
||||
}
|
||||
|
||||
TimeManager.Instance.InitializeTimeZone(_device);
|
||||
|
||||
_device.System.Font.Initialize(this, ignoreMissingFonts);
|
||||
}
|
||||
|
||||
public void ClearEntry(long titleId, NcaContentType contentType, StorageId storageId)
|
||||
{
|
||||
RemoveLocationEntry(titleId, contentType, storageId);
|
||||
lock (_lock)
|
||||
{
|
||||
RemoveLocationEntry(titleId, contentType, storageId);
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshEntries(StorageId storageId, int flag)
|
||||
{
|
||||
LinkedList<LocationEntry> locationList = _locationEntries[storageId];
|
||||
LinkedListNode<LocationEntry> locationEntry = locationList.First;
|
||||
|
||||
while (locationEntry != null)
|
||||
lock (_lock)
|
||||
{
|
||||
LinkedListNode<LocationEntry> nextLocationEntry = locationEntry.Next;
|
||||
LinkedList<LocationEntry> locationList = _locationEntries[storageId];
|
||||
LinkedListNode<LocationEntry> locationEntry = locationList.First;
|
||||
|
||||
if (locationEntry.Value.Flag == flag)
|
||||
while (locationEntry != null)
|
||||
{
|
||||
locationList.Remove(locationEntry.Value);
|
||||
}
|
||||
LinkedListNode<LocationEntry> nextLocationEntry = locationEntry.Next;
|
||||
|
||||
locationEntry = nextLocationEntry;
|
||||
if (locationEntry.Value.Flag == flag)
|
||||
{
|
||||
locationList.Remove(locationEntry.Value);
|
||||
}
|
||||
|
||||
locationEntry = nextLocationEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasNca(string ncaId, StorageId storageId)
|
||||
{
|
||||
if (_contentDictionary.ContainsValue(ncaId))
|
||||
lock (_lock)
|
||||
{
|
||||
var content = _contentDictionary.FirstOrDefault(x => x.Value == ncaId);
|
||||
long titleId = (long)content.Key.Item1;
|
||||
if (_contentDictionary.ContainsValue(ncaId))
|
||||
{
|
||||
var content = _contentDictionary.FirstOrDefault(x => x.Value == ncaId);
|
||||
long titleId = (long)content.Key.Item1;
|
||||
|
||||
NcaContentType contentType = content.Key.type;
|
||||
StorageId storage = GetInstalledStorage(titleId, contentType, storageId);
|
||||
NcaContentType contentType = content.Key.type;
|
||||
StorageId storage = GetInstalledStorage(titleId, contentType, storageId);
|
||||
|
||||
return storage == storageId;
|
||||
return storage == storageId;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -198,9 +212,12 @@ namespace Ryujinx.HLE.FileSystem.Content
|
|||
|
||||
public UInt128 GetInstalledNcaId(long titleId, NcaContentType contentType)
|
||||
{
|
||||
if (_contentDictionary.ContainsKey(((ulong)titleId, contentType)))
|
||||
lock (_lock)
|
||||
{
|
||||
return new UInt128(_contentDictionary[((ulong)titleId, contentType)]);
|
||||
if (_contentDictionary.ContainsKey(((ulong)titleId, contentType)))
|
||||
{
|
||||
return new UInt128(_contentDictionary[((ulong)titleId, contentType)]);
|
||||
}
|
||||
}
|
||||
|
||||
return new UInt128();
|
||||
|
@ -208,19 +225,25 @@ namespace Ryujinx.HLE.FileSystem.Content
|
|||
|
||||
public StorageId GetInstalledStorage(long titleId, NcaContentType contentType, StorageId storageId)
|
||||
{
|
||||
LocationEntry locationEntry = GetLocation(titleId, contentType, storageId);
|
||||
lock (_lock)
|
||||
{
|
||||
LocationEntry locationEntry = GetLocation(titleId, contentType, storageId);
|
||||
|
||||
return locationEntry.ContentPath != null ?
|
||||
LocationHelper.GetStorageId(locationEntry.ContentPath) : StorageId.None;
|
||||
return locationEntry.ContentPath != null ?
|
||||
LocationHelper.GetStorageId(locationEntry.ContentPath) : StorageId.None;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetInstalledContentPath(long titleId, StorageId storageId, NcaContentType contentType)
|
||||
{
|
||||
LocationEntry locationEntry = GetLocation(titleId, contentType, storageId);
|
||||
|
||||
if (VerifyContentType(locationEntry, contentType))
|
||||
lock (_lock)
|
||||
{
|
||||
return locationEntry.ContentPath;
|
||||
LocationEntry locationEntry = GetLocation(titleId, contentType, storageId);
|
||||
|
||||
if (VerifyContentType(locationEntry, contentType))
|
||||
{
|
||||
return locationEntry.ContentPath;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
|
@ -228,14 +251,17 @@ namespace Ryujinx.HLE.FileSystem.Content
|
|||
|
||||
public void RedirectLocation(LocationEntry newEntry, StorageId storageId)
|
||||
{
|
||||
LocationEntry locationEntry = GetLocation(newEntry.TitleId, newEntry.ContentType, storageId);
|
||||
|
||||
if (locationEntry.ContentPath != null)
|
||||
lock (_lock)
|
||||
{
|
||||
RemoveLocationEntry(newEntry.TitleId, newEntry.ContentType, storageId);
|
||||
}
|
||||
LocationEntry locationEntry = GetLocation(newEntry.TitleId, newEntry.ContentType, storageId);
|
||||
|
||||
AddLocationEntry(newEntry, storageId);
|
||||
if (locationEntry.ContentPath != null)
|
||||
{
|
||||
RemoveLocationEntry(newEntry.TitleId, newEntry.ContentType, storageId);
|
||||
}
|
||||
|
||||
AddLocationEntry(newEntry, storageId);
|
||||
}
|
||||
}
|
||||
|
||||
private bool VerifyContentType(LocationEntry locationEntry, NcaContentType contentType)
|
||||
|
@ -827,28 +853,31 @@ namespace Ryujinx.HLE.FileSystem.Content
|
|||
{
|
||||
LoadEntries(true);
|
||||
|
||||
var locationEnties = _locationEntries[StorageId.NandSystem];
|
||||
|
||||
foreach (var entry in locationEnties)
|
||||
lock (_lock)
|
||||
{
|
||||
if (entry.ContentType == NcaContentType.Data)
|
||||
var locationEnties = _locationEntries[StorageId.NandSystem];
|
||||
|
||||
foreach (var entry in locationEnties)
|
||||
{
|
||||
var path = _device.FileSystem.SwitchPathToSystemPath(entry.ContentPath);
|
||||
|
||||
using (IStorage ncaStorage = File.Open(path, FileMode.Open).AsStorage())
|
||||
if (entry.ContentType == NcaContentType.Data)
|
||||
{
|
||||
Nca nca = new Nca(_device.System.KeySet, ncaStorage);
|
||||
var path = _device.FileSystem.SwitchPathToSystemPath(entry.ContentPath);
|
||||
|
||||
if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data)
|
||||
using (FileStream fileStream = File.OpenRead(path))
|
||||
{
|
||||
var romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
|
||||
Nca nca = new Nca(_device.System.KeySet, fileStream.AsStorage());
|
||||
|
||||
if (romfs.OpenFile(out IFile systemVersionFile, "/file", OpenMode.Read).IsSuccess())
|
||||
if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data)
|
||||
{
|
||||
return new SystemVersion(systemVersionFile.AsStream());
|
||||
}
|
||||
}
|
||||
var romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
|
||||
|
||||
if (romfs.OpenFile(out IFile systemVersionFile, "/file", OpenMode.Read).IsSuccess())
|
||||
{
|
||||
return new SystemVersion(systemVersionFile.AsStream());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
|
|||
|
||||
_keepRunning = true;
|
||||
|
||||
Thread work = new Thread(WaitAndCheckScheduledObjects);
|
||||
Thread work = new Thread(WaitAndCheckScheduledObjects)
|
||||
{
|
||||
Name = "HLE.TimeManager"
|
||||
};
|
||||
|
||||
work.Start();
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
public class RAttribute : Attribute
|
||||
{
|
||||
public readonly int Index;
|
||||
|
||||
public RAttribute(int index)
|
||||
{
|
||||
Index = index;
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
{
|
||||
ExecutionContext context = (ExecutionContext)sender;
|
||||
|
||||
Action<SvcHandler, ExecutionContext> svcFunc = SvcTable.GetSvcFunc(e.Id, context.IsAarch32);
|
||||
Action<SvcHandler, ExecutionContext> svcFunc = context.IsAarch32 ? SvcTable.SvcTable32[e.Id] : SvcTable.SvcTable64[e.Id];
|
||||
|
||||
if (svcFunc == null)
|
||||
{
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
}
|
||||
}
|
||||
|
||||
public KernelResult ConnectToNamedPort64(ulong namePtr, out int handle)
|
||||
public KernelResult ConnectToNamedPort64([R(1)] ulong namePtr, [R(1)] out int handle)
|
||||
{
|
||||
return ConnectToNamedPort(namePtr, out handle);
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return result;
|
||||
}
|
||||
|
||||
public KernelResult SendSyncRequest64(int handle)
|
||||
public KernelResult SendSyncRequest64([R(0)] int handle)
|
||||
{
|
||||
return SendSyncRequest((ulong)_system.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle);
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return SendSyncRequest((ulong)_system.Scheduler.GetCurrentThread().Context.Tpidr, 0x100, handle);
|
||||
}
|
||||
|
||||
public KernelResult SendSyncRequestWithUserBuffer64(ulong messagePtr, ulong size, int handle)
|
||||
public KernelResult SendSyncRequestWithUserBuffer64([R(0)] ulong messagePtr, [R(1)] ulong size, [R(2)] int handle)
|
||||
{
|
||||
return SendSyncRequest(messagePtr, size, handle);
|
||||
}
|
||||
|
@ -178,10 +178,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
}
|
||||
|
||||
public KernelResult CreateSession64(
|
||||
bool isLight,
|
||||
ulong namePtr,
|
||||
out int serverSessionHandle,
|
||||
out int clientSessionHandle)
|
||||
[R(2)] bool isLight,
|
||||
[R(3)] ulong namePtr,
|
||||
[R(1)] out int serverSessionHandle,
|
||||
[R(2)] out int clientSessionHandle)
|
||||
{
|
||||
return CreateSession(isLight, namePtr, out serverSessionHandle, out clientSessionHandle);
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return result;
|
||||
}
|
||||
|
||||
public KernelResult AcceptSession64(int portHandle, out int sessionHandle)
|
||||
public KernelResult AcceptSession64([R(1)] int portHandle, [R(1)] out int sessionHandle)
|
||||
{
|
||||
return AcceptSession(portHandle, out sessionHandle);
|
||||
}
|
||||
|
@ -309,11 +309,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
}
|
||||
|
||||
public KernelResult ReplyAndReceive64(
|
||||
ulong handlesPtr,
|
||||
int handlesCount,
|
||||
int replyTargetHandle,
|
||||
long timeout,
|
||||
out int handleIndex)
|
||||
[R(1)] ulong handlesPtr,
|
||||
[R(2)] int handlesCount,
|
||||
[R(3)] int replyTargetHandle,
|
||||
[R(4)] long timeout,
|
||||
[R(1)] out int handleIndex)
|
||||
{
|
||||
handleIndex = 0;
|
||||
|
||||
|
@ -395,11 +395,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
}
|
||||
|
||||
public KernelResult CreatePort64(
|
||||
int maxSessions,
|
||||
bool isLight,
|
||||
ulong namePtr,
|
||||
out int serverPortHandle,
|
||||
out int clientPortHandle)
|
||||
[R(2)] int maxSessions,
|
||||
[R(3)] bool isLight,
|
||||
[R(4)] ulong namePtr,
|
||||
[R(1)] out int serverPortHandle,
|
||||
[R(2)] out int clientPortHandle)
|
||||
{
|
||||
return CreatePort(maxSessions, isLight, namePtr, out serverPortHandle, out clientPortHandle);
|
||||
}
|
||||
|
@ -439,7 +439,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return result;
|
||||
}
|
||||
|
||||
public KernelResult ManageNamedPort64(ulong namePtr, int maxSessions, out int handle)
|
||||
public KernelResult ManageNamedPort64([R(1)] ulong namePtr, [R(2)] int maxSessions, [R(1)] out int handle)
|
||||
{
|
||||
return ManageNamedPort(namePtr, maxSessions, out handle);
|
||||
}
|
||||
|
@ -484,7 +484,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return result;
|
||||
}
|
||||
|
||||
public KernelResult ConnectToPort64(int clientPortHandle, out int clientSessionHandle)
|
||||
public KernelResult ConnectToPort64([R(1)] int clientPortHandle, [R(1)] out int clientSessionHandle)
|
||||
{
|
||||
return ConnectToPort(clientPortHandle, out clientSessionHandle);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
{
|
||||
partial class SvcHandler
|
||||
{
|
||||
public KernelResult SetHeapSize64(ulong size, out ulong position)
|
||||
public KernelResult SetHeapSize64([R(1)] ulong size, [R(1)] out ulong position)
|
||||
{
|
||||
return SetHeapSize(size, out position);
|
||||
}
|
||||
|
@ -35,10 +35,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
}
|
||||
|
||||
public KernelResult SetMemoryAttribute64(
|
||||
ulong position,
|
||||
ulong size,
|
||||
MemoryAttribute attributeMask,
|
||||
MemoryAttribute attributeValue)
|
||||
[R(0)] ulong position,
|
||||
[R(1)] ulong size,
|
||||
[R(2)] MemoryAttribute attributeMask,
|
||||
[R(3)] MemoryAttribute attributeValue)
|
||||
{
|
||||
return SetMemoryAttribute(position, size, attributeMask, attributeValue);
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return result;
|
||||
}
|
||||
|
||||
public KernelResult MapMemory64(ulong dst, ulong src, ulong size)
|
||||
public KernelResult MapMemory64([R(0)] ulong dst, [R(1)] ulong src, [R(2)] ulong size)
|
||||
{
|
||||
return MapMemory(dst, src, size);
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return _process.MemoryManager.Map(dst, src, size);
|
||||
}
|
||||
|
||||
public KernelResult UnmapMemory64(ulong dst, ulong src, ulong size)
|
||||
public KernelResult UnmapMemory64([R(0)] ulong dst, [R(1)] ulong src, [R(2)] ulong size)
|
||||
{
|
||||
return UnmapMemory(dst, src, size);
|
||||
}
|
||||
|
@ -173,18 +173,20 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return _process.MemoryManager.Unmap(dst, src, size);
|
||||
}
|
||||
|
||||
public KernelResult QueryMemory64(ulong infoPtr, ulong x1, ulong position)
|
||||
public KernelResult QueryMemory64([R(0)] ulong infoPtr, [R(2)] ulong position, [R(1)] out ulong pageInfo)
|
||||
{
|
||||
return QueryMemory(infoPtr, position);
|
||||
return QueryMemory(infoPtr, position, out pageInfo);
|
||||
}
|
||||
|
||||
public KernelResult QueryMemory32([R(0)] uint infoPtr, [R(1)] uint r1, [R(2)] uint position)
|
||||
public KernelResult QueryMemory32([R(0)] uint infoPtr, [R(1)] uint r1, [R(2)] uint position, [R(1)] out uint pageInfo)
|
||||
{
|
||||
// FIXME: Nintendo here bzero the pointer info structure and then copy every element one by one if QueryMemory succeed.
|
||||
return QueryMemory(infoPtr, position);
|
||||
KernelResult result = QueryMemory(infoPtr, position, out ulong pageInfo64);
|
||||
pageInfo = (uint)pageInfo64;
|
||||
return result;
|
||||
}
|
||||
|
||||
private KernelResult QueryMemory(ulong infoPtr, ulong position)
|
||||
private KernelResult QueryMemory(ulong infoPtr, ulong position, out ulong pageInfo)
|
||||
{
|
||||
KMemoryInfo blkInfo = _process.MemoryManager.QueryMemory(position);
|
||||
|
||||
|
@ -197,10 +199,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
_process.CpuMemory.WriteInt32 ((long)infoPtr + 0x20, blkInfo.DeviceRefCount);
|
||||
_process.CpuMemory.WriteInt32 ((long)infoPtr + 0x24, 0);
|
||||
|
||||
pageInfo = 0;
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult MapSharedMemory64(int handle, ulong address, ulong size, MemoryPermission permission)
|
||||
public KernelResult MapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size, [R(3)] MemoryPermission permission)
|
||||
{
|
||||
return MapSharedMemory(handle, address, size, permission);
|
||||
}
|
||||
|
@ -256,7 +260,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
permission);
|
||||
}
|
||||
|
||||
public KernelResult UnmapSharedMemory64(int handle, ulong address, ulong size)
|
||||
public KernelResult UnmapSharedMemory64([R(0)] int handle, [R(1)] ulong address, [R(2)] ulong size)
|
||||
{
|
||||
return UnmapSharedMemory(handle, address, size);
|
||||
}
|
||||
|
@ -307,10 +311,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
}
|
||||
|
||||
public KernelResult CreateTransferMemory64(
|
||||
ulong address,
|
||||
ulong size,
|
||||
MemoryPermission permission,
|
||||
out int handle)
|
||||
[R(1)] ulong address,
|
||||
[R(2)] ulong size,
|
||||
[R(3)] MemoryPermission permission,
|
||||
[R(1)] out int handle)
|
||||
{
|
||||
return CreateTransferMemory(address, size, permission, out handle);
|
||||
}
|
||||
|
@ -360,7 +364,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return _process.HandleTable.GenerateHandle(transferMemory, out handle);
|
||||
}
|
||||
|
||||
public KernelResult MapPhysicalMemory64(ulong address, ulong size)
|
||||
public KernelResult MapPhysicalMemory64([R(0)] ulong address, [R(1)] ulong size)
|
||||
{
|
||||
return MapPhysicalMemory(address, size);
|
||||
}
|
||||
|
@ -398,7 +402,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return _process.MemoryManager.MapPhysicalMemory(address, size);
|
||||
}
|
||||
|
||||
public KernelResult UnmapPhysicalMemory64(ulong address, ulong size)
|
||||
public KernelResult UnmapPhysicalMemory64([R(0)] ulong address, [R(1)] ulong size)
|
||||
{
|
||||
return UnmapPhysicalMemory(address, size);
|
||||
}
|
||||
|
@ -436,7 +440,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return _process.MemoryManager.UnmapPhysicalMemory(address, size);
|
||||
}
|
||||
|
||||
public KernelResult MapProcessCodeMemory64(int handle, ulong dst, ulong src, ulong size)
|
||||
public KernelResult MapProcessCodeMemory64([R(0)] int handle, [R(1)] ulong dst, [R(2)] ulong src, [R(3)] ulong size)
|
||||
{
|
||||
return MapProcessCodeMemory(handle, dst, src, size);
|
||||
}
|
||||
|
@ -478,7 +482,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return targetProcess.MemoryManager.MapProcessCodeMemory(dst, src, size);
|
||||
}
|
||||
|
||||
public KernelResult UnmapProcessCodeMemory64(int handle, ulong dst, ulong src, ulong size)
|
||||
public KernelResult UnmapProcessCodeMemory64([R(0)] int handle, [R(1)] ulong dst, [R(2)] ulong src, [R(3)] ulong size)
|
||||
{
|
||||
return UnmapProcessCodeMemory(handle, dst, src, size);
|
||||
}
|
||||
|
@ -520,7 +524,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return targetProcess.MemoryManager.UnmapProcessCodeMemory(dst, src, size);
|
||||
}
|
||||
|
||||
public KernelResult SetProcessMemoryPermission64(int handle, ulong src, ulong size, MemoryPermission permission)
|
||||
public KernelResult SetProcessMemoryPermission64([R(0)] int handle, [R(1)] ulong src, [R(2)] ulong size, [R(3)] MemoryPermission permission)
|
||||
{
|
||||
return SetProcessMemoryPermission(handle, src, size, permission);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
ExitProcess();
|
||||
}
|
||||
|
||||
public KernelResult TerminateProcess64(int handle)
|
||||
public KernelResult TerminateProcess64([R(0)] int handle)
|
||||
{
|
||||
return TerminateProcess(handle);
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
_system.Scheduler.GetCurrentProcess().TerminateCurrentProcess();
|
||||
}
|
||||
|
||||
public KernelResult SignalEvent64(int handle)
|
||||
public KernelResult SignalEvent64([R(0)] int handle)
|
||||
{
|
||||
return SignalEvent(handle);
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return result;
|
||||
}
|
||||
|
||||
public KernelResult ClearEvent64(int handle)
|
||||
public KernelResult ClearEvent64([R(0)] int handle)
|
||||
{
|
||||
return ClearEvent(handle);
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return result;
|
||||
}
|
||||
|
||||
public KernelResult CloseHandle64(int handle)
|
||||
public KernelResult CloseHandle64([R(0)] int handle)
|
||||
{
|
||||
return CloseHandle(handle);
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult ResetSignal64(int handle)
|
||||
public KernelResult ResetSignal64([R(0)] int handle)
|
||||
{
|
||||
return ResetSignal(handle);
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return _system.Scheduler.GetCurrentThread().Context.CntpctEl0;
|
||||
}
|
||||
|
||||
public KernelResult GetProcessId64(int handle, out long pid)
|
||||
public KernelResult GetProcessId64([R(1)] int handle, [R(1)] out long pid)
|
||||
{
|
||||
return GetProcessId(handle, out pid);
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
: KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
public void Break64(ulong reason, ulong x1, ulong info)
|
||||
public void Break64([R(0)] ulong reason, [R(1)] ulong x1, [R(2)] ulong info)
|
||||
{
|
||||
Break(reason);
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
}
|
||||
}
|
||||
|
||||
public void OutputDebugString64(ulong strPtr, ulong size)
|
||||
public void OutputDebugString64([R(0)] ulong strPtr, [R(1)] ulong size)
|
||||
{
|
||||
OutputDebugString(strPtr, size);
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
Logger.PrintWarning(LogClass.KernelSvc, str);
|
||||
}
|
||||
|
||||
public KernelResult GetInfo64(uint id, int handle, long subId, out long value)
|
||||
public KernelResult GetInfo64([R(1)] uint id, [R(2)] int handle, [R(3)] long subId, [R(1)] out long value)
|
||||
{
|
||||
return GetInfo(id, handle, subId, out value);
|
||||
}
|
||||
|
@ -522,7 +522,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult CreateEvent64(out int wEventHandle, out int rEventHandle)
|
||||
public KernelResult CreateEvent64([R(1)] out int wEventHandle, [R(2)] out int rEventHandle)
|
||||
{
|
||||
return CreateEvent(out wEventHandle, out rEventHandle);
|
||||
}
|
||||
|
@ -550,7 +550,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return result;
|
||||
}
|
||||
|
||||
public KernelResult GetProcessList64(ulong address, int maxCount, out int count)
|
||||
public KernelResult GetProcessList64([R(1)] ulong address, [R(2)] int maxCount, [R(1)] out int count)
|
||||
{
|
||||
return GetProcessList(address, maxCount, out count);
|
||||
}
|
||||
|
@ -604,7 +604,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult GetSystemInfo64(uint id, int handle, long subId, out long value)
|
||||
public KernelResult GetSystemInfo64([R(1)] uint id, [R(2)] int handle, [R(3)] long subId, [R(1)] out long value)
|
||||
{
|
||||
return GetSystemInfo(id, handle, subId, out value);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ using Ryujinx.Common.Logging;
|
|||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
@ -14,16 +13,17 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
{
|
||||
private const int SvcFuncMaxArguments64 = 8;
|
||||
private const int SvcFuncMaxArguments32 = 4;
|
||||
private const int SvcMax = 0x80;
|
||||
|
||||
private static Dictionary<int, string> _svcFuncs64;
|
||||
private static Dictionary<int, string> _svcFuncs32;
|
||||
|
||||
private static Action<SvcHandler, ExecutionContext>[] _svcTable64;
|
||||
private static Action<SvcHandler, ExecutionContext>[] _svcTable32;
|
||||
public static Action<SvcHandler, ExecutionContext>[] SvcTable32 { get; }
|
||||
public static Action<SvcHandler, ExecutionContext>[] SvcTable64 { get; }
|
||||
|
||||
static SvcTable()
|
||||
{
|
||||
_svcFuncs64 = new Dictionary<int, string>
|
||||
SvcTable32 = new Action<SvcHandler, ExecutionContext>[SvcMax];
|
||||
SvcTable64 = new Action<SvcHandler, ExecutionContext>[SvcMax];
|
||||
|
||||
Dictionary<int, string> svcFuncs64 = new Dictionary<int, string>
|
||||
{
|
||||
{ 0x01, nameof(SvcHandler.SetHeapSize64) },
|
||||
{ 0x03, nameof(SvcHandler.SetMemoryAttribute64) },
|
||||
|
@ -83,7 +83,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
{ 0x7B, nameof(SvcHandler.TerminateProcess64) }
|
||||
};
|
||||
|
||||
_svcFuncs32 = new Dictionary<int, string>
|
||||
foreach (KeyValuePair<int, string> value in svcFuncs64)
|
||||
{
|
||||
SvcTable64[value.Key] = GenerateMethod(value.Value, SvcFuncMaxArguments64);
|
||||
}
|
||||
|
||||
Dictionary<int, string> svcFuncs32 = new Dictionary<int, string>
|
||||
{
|
||||
{ 0x01, nameof(SvcHandler.SetHeapSize32) },
|
||||
{ 0x03, nameof(SvcHandler.SetMemoryAttribute32) },
|
||||
|
@ -121,46 +126,13 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
{ 0x5F, nameof(SvcHandler.FlushProcessDataCache32) }
|
||||
};
|
||||
|
||||
_svcTable64 = new Action<SvcHandler, ExecutionContext>[0x80];
|
||||
_svcTable32 = new Action<SvcHandler, ExecutionContext>[0x80];
|
||||
foreach (KeyValuePair<int, string> value in svcFuncs32)
|
||||
{
|
||||
SvcTable32[value.Key] = GenerateMethod(value.Value, SvcFuncMaxArguments32);
|
||||
}
|
||||
}
|
||||
|
||||
public static Action<SvcHandler, ExecutionContext> GetSvcFunc(int svcId, bool aarch32)
|
||||
{
|
||||
Action<SvcHandler, ExecutionContext>[] table = aarch32 ? _svcTable32 : _svcTable64;
|
||||
if (table[svcId] != null)
|
||||
{
|
||||
return table[svcId];
|
||||
}
|
||||
|
||||
Dictionary<int, string> funcTable = aarch32 ? _svcFuncs32 : _svcFuncs64;
|
||||
if (funcTable.TryGetValue(svcId, out string svcName))
|
||||
{
|
||||
Action<SvcHandler, ExecutionContext> svcFunc;
|
||||
|
||||
if (aarch32)
|
||||
{
|
||||
svcFunc = GenerateMethod32(svcName);
|
||||
}
|
||||
else
|
||||
{
|
||||
svcFunc = GenerateMethod64(svcName);
|
||||
}
|
||||
table[svcId] = svcFunc;
|
||||
|
||||
return table[svcId] = svcFunc;
|
||||
}
|
||||
|
||||
if (aarch32 && _svcFuncs64.TryGetValue(svcId, out string svcName64))
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Svc \"{svcName64}\" ({svcId}) does not have a 32-bit call signature defined - fell back to 64-bit.");
|
||||
throw new NotImplementedException($"Svc \"{svcName64}\" ({svcId}) does not have a 32-bit call signature defined.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Action<SvcHandler, ExecutionContext> GenerateMethod64(string svcName)
|
||||
private static Action<SvcHandler, ExecutionContext> GenerateMethod(string svcName, int registerCleanCount)
|
||||
{
|
||||
Type[] argTypes = new Type[] { typeof(SvcHandler), typeof(ExecutionContext) };
|
||||
|
||||
|
@ -170,11 +142,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
|
||||
ParameterInfo[] methodArgs = methodInfo.GetParameters();
|
||||
|
||||
if (methodArgs.Length > SvcFuncMaxArguments64)
|
||||
{
|
||||
throw new InvalidOperationException($"Method \"{svcName}\" has too many arguments, max is {SvcFuncMaxArguments64}.");
|
||||
}
|
||||
|
||||
ILGenerator generator = method.GetILGenerator();
|
||||
|
||||
void ConvertToArgType(Type sourceType)
|
||||
|
@ -184,236 +151,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
switch (Type.GetTypeCode(sourceType))
|
||||
{
|
||||
case TypeCode.UInt32: generator.Emit(OpCodes.Conv_U4); break;
|
||||
case TypeCode.Int32: generator.Emit(OpCodes.Conv_I4); break;
|
||||
case TypeCode.Int32: generator.Emit(OpCodes.Conv_I4); break;
|
||||
case TypeCode.UInt16: generator.Emit(OpCodes.Conv_U2); break;
|
||||
case TypeCode.Int16: generator.Emit(OpCodes.Conv_I2); break;
|
||||
case TypeCode.Byte: generator.Emit(OpCodes.Conv_U1); break;
|
||||
case TypeCode.SByte: generator.Emit(OpCodes.Conv_I1); break;
|
||||
|
||||
case TypeCode.Boolean:
|
||||
generator.Emit(OpCodes.Conv_I4);
|
||||
generator.Emit(OpCodes.Ldc_I4_1);
|
||||
generator.Emit(OpCodes.And);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertToFieldType(Type sourceType)
|
||||
{
|
||||
CheckIfTypeIsSupported(sourceType, svcName);
|
||||
|
||||
switch (Type.GetTypeCode(sourceType))
|
||||
{
|
||||
case TypeCode.UInt32:
|
||||
case TypeCode.Int32:
|
||||
case TypeCode.UInt16:
|
||||
case TypeCode.Int16:
|
||||
case TypeCode.Byte:
|
||||
case TypeCode.SByte:
|
||||
case TypeCode.Boolean:
|
||||
generator.Emit(OpCodes.Conv_U8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// For functions returning output values, the first registers
|
||||
// are used to hold pointers where the value will be stored,
|
||||
// so they can't be used to pass argument and we must
|
||||
// skip them.
|
||||
int byRefArgsCount = 0;
|
||||
|
||||
for (int index = 0; index < methodArgs.Length; index++)
|
||||
{
|
||||
if (methodArgs[index].ParameterType.IsByRef)
|
||||
{
|
||||
byRefArgsCount++;
|
||||
}
|
||||
}
|
||||
|
||||
BindingFlags staticNonPublic = BindingFlags.NonPublic | BindingFlags.Static;
|
||||
|
||||
// Print all the arguments for debugging purposes.
|
||||
int inputArgsCount = methodArgs.Length - byRefArgsCount;
|
||||
|
||||
if (inputArgsCount != 0)
|
||||
{
|
||||
generator.Emit(OpCodes.Ldc_I4, inputArgsCount);
|
||||
|
||||
generator.Emit(OpCodes.Newarr, typeof(object));
|
||||
|
||||
string argsFormat = svcName;
|
||||
|
||||
for (int index = 0; index < inputArgsCount; index++)
|
||||
{
|
||||
argsFormat += $" {methodArgs[index].Name}: 0x{{{index}:X8}},";
|
||||
|
||||
generator.Emit(OpCodes.Dup);
|
||||
generator.Emit(OpCodes.Ldc_I4, index);
|
||||
|
||||
generator.Emit(OpCodes.Ldarg_1);
|
||||
generator.Emit(OpCodes.Ldc_I4, byRefArgsCount + index);
|
||||
|
||||
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
|
||||
|
||||
generator.Emit(OpCodes.Call, info);
|
||||
|
||||
generator.Emit(OpCodes.Box, typeof(ulong));
|
||||
|
||||
generator.Emit(OpCodes.Stelem_Ref);
|
||||
}
|
||||
|
||||
argsFormat = argsFormat.Substring(0, argsFormat.Length - 1);
|
||||
|
||||
generator.Emit(OpCodes.Ldstr, argsFormat);
|
||||
}
|
||||
else
|
||||
{
|
||||
generator.Emit(OpCodes.Ldnull);
|
||||
|
||||
generator.Emit(OpCodes.Ldstr, svcName);
|
||||
}
|
||||
|
||||
MethodInfo printArgsMethod = typeof(SvcTable).GetMethod(nameof(PrintArguments), staticNonPublic);
|
||||
|
||||
generator.Emit(OpCodes.Call, printArgsMethod);
|
||||
|
||||
// Call the SVC function handler.
|
||||
generator.Emit(OpCodes.Ldarg_0);
|
||||
|
||||
List<LocalBuilder> locals = new List<LocalBuilder>();
|
||||
|
||||
for (int index = 0; index < methodArgs.Length; index++)
|
||||
{
|
||||
Type argType = methodArgs[index].ParameterType;
|
||||
|
||||
if (argType.IsByRef)
|
||||
{
|
||||
argType = argType.GetElementType();
|
||||
|
||||
LocalBuilder local = generator.DeclareLocal(argType);
|
||||
|
||||
locals.Add(local);
|
||||
|
||||
if (!methodArgs[index].IsOut)
|
||||
{
|
||||
generator.Emit(OpCodes.Ldarg_1);
|
||||
generator.Emit(OpCodes.Ldc_I4, index);
|
||||
|
||||
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
|
||||
|
||||
generator.Emit(OpCodes.Call, info);
|
||||
|
||||
ConvertToArgType(argType);
|
||||
|
||||
generator.Emit(OpCodes.Stloc, local);
|
||||
}
|
||||
|
||||
generator.Emit(OpCodes.Ldloca, local);
|
||||
}
|
||||
else
|
||||
{
|
||||
generator.Emit(OpCodes.Ldarg_1);
|
||||
generator.Emit(OpCodes.Ldc_I4, byRefArgsCount + index);
|
||||
|
||||
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.GetX));
|
||||
|
||||
generator.Emit(OpCodes.Call, info);
|
||||
|
||||
ConvertToArgType(argType);
|
||||
}
|
||||
}
|
||||
|
||||
generator.Emit(OpCodes.Call, methodInfo);
|
||||
|
||||
int outRegIndex = 0;
|
||||
|
||||
Type retType = methodInfo.ReturnType;
|
||||
|
||||
// Print result code.
|
||||
if (retType == typeof(KernelResult))
|
||||
{
|
||||
MethodInfo printResultMethod = typeof(SvcTable).GetMethod(nameof(PrintResult), staticNonPublic);
|
||||
|
||||
generator.Emit(OpCodes.Dup);
|
||||
generator.Emit(OpCodes.Ldstr, svcName);
|
||||
generator.Emit(OpCodes.Call, printResultMethod);
|
||||
}
|
||||
|
||||
// Save return value into register X0 (when the method has a return value).
|
||||
if (retType != typeof(void))
|
||||
{
|
||||
CheckIfTypeIsSupported(retType, svcName);
|
||||
|
||||
LocalBuilder tempLocal = generator.DeclareLocal(retType);
|
||||
|
||||
generator.Emit(OpCodes.Stloc, tempLocal);
|
||||
generator.Emit(OpCodes.Ldarg_1);
|
||||
generator.Emit(OpCodes.Ldc_I4, outRegIndex++);
|
||||
generator.Emit(OpCodes.Ldloc, tempLocal);
|
||||
|
||||
ConvertToFieldType(retType);
|
||||
|
||||
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX));
|
||||
|
||||
generator.Emit(OpCodes.Call, info);
|
||||
}
|
||||
|
||||
for (int index = 0; index < locals.Count; index++)
|
||||
{
|
||||
generator.Emit(OpCodes.Ldarg_1);
|
||||
generator.Emit(OpCodes.Ldc_I4, outRegIndex++);
|
||||
generator.Emit(OpCodes.Ldloc, locals[index]);
|
||||
|
||||
ConvertToFieldType(locals[index].LocalType);
|
||||
|
||||
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX));
|
||||
|
||||
generator.Emit(OpCodes.Call, info);
|
||||
}
|
||||
|
||||
// Zero out the remaining unused registers.
|
||||
while (outRegIndex < SvcFuncMaxArguments64)
|
||||
{
|
||||
generator.Emit(OpCodes.Ldarg_1);
|
||||
generator.Emit(OpCodes.Ldc_I4, outRegIndex++);
|
||||
generator.Emit(OpCodes.Ldc_I8, 0L);
|
||||
|
||||
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX));
|
||||
|
||||
generator.Emit(OpCodes.Call, info);
|
||||
}
|
||||
|
||||
generator.Emit(OpCodes.Ret);
|
||||
|
||||
return (Action<SvcHandler, ExecutionContext>)method.CreateDelegate(typeof(Action<SvcHandler, ExecutionContext>));
|
||||
}
|
||||
|
||||
// TODO: merge 64 bits variant
|
||||
private static Action<SvcHandler, ExecutionContext> GenerateMethod32(string svcName)
|
||||
{
|
||||
Type[] argTypes = new Type[] { typeof(SvcHandler), typeof(ExecutionContext) };
|
||||
|
||||
DynamicMethod method = new DynamicMethod(svcName, null, argTypes);
|
||||
|
||||
MethodInfo methodInfo = typeof(SvcHandler).GetMethod(svcName);
|
||||
|
||||
ParameterInfo[] methodArgs = methodInfo.GetParameters();
|
||||
int numArgs = methodArgs.Count(x => !x.IsOut);
|
||||
|
||||
ILGenerator generator = method.GetILGenerator();
|
||||
|
||||
void ConvertToArgType(Type sourceType)
|
||||
{
|
||||
CheckIfTypeIsSupported(sourceType, svcName);
|
||||
|
||||
switch (Type.GetTypeCode(sourceType))
|
||||
{
|
||||
case TypeCode.UInt32: generator.Emit(OpCodes.Conv_U4); break;
|
||||
case TypeCode.Int32: generator.Emit(OpCodes.Conv_I4); break;
|
||||
case TypeCode.UInt16: generator.Emit(OpCodes.Conv_U2); break;
|
||||
case TypeCode.Int16: generator.Emit(OpCodes.Conv_I2); break;
|
||||
case TypeCode.Byte: generator.Emit(OpCodes.Conv_U1); break;
|
||||
case TypeCode.SByte: generator.Emit(OpCodes.Conv_I1); break;
|
||||
case TypeCode.Int16: generator.Emit(OpCodes.Conv_I2); break;
|
||||
case TypeCode.Byte: generator.Emit(OpCodes.Conv_U1); break;
|
||||
case TypeCode.SByte: generator.Emit(OpCodes.Conv_I1); break;
|
||||
|
||||
case TypeCode.Boolean:
|
||||
generator.Emit(OpCodes.Conv_I4);
|
||||
|
@ -511,7 +253,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
|
||||
argsFormat = argsFormat.Substring(0, argsFormat.Length - 1);
|
||||
|
||||
generator.Emit(OpCodes.Ldstr, argsFormat);
|
||||
generator.Emit(OpCodes.Ldstr, argsFormat);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -573,8 +315,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
|
||||
generator.Emit(OpCodes.Call, methodInfo);
|
||||
|
||||
int outRegIndex = 0;
|
||||
|
||||
Type retType = methodInfo.ReturnType;
|
||||
|
||||
// Print result code.
|
||||
|
@ -587,6 +327,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
generator.Emit(OpCodes.Call, printResultMethod);
|
||||
}
|
||||
|
||||
uint registerInUse = 0;
|
||||
|
||||
// Save return value into register X0 (when the method has a return value).
|
||||
if (retType != typeof(void))
|
||||
{
|
||||
|
@ -596,7 +338,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
|
||||
generator.Emit(OpCodes.Stloc, tempLocal);
|
||||
generator.Emit(OpCodes.Ldarg_1);
|
||||
generator.Emit(OpCodes.Ldc_I4, outRegIndex++);
|
||||
generator.Emit(OpCodes.Ldc_I4, 0);
|
||||
generator.Emit(OpCodes.Ldloc, tempLocal);
|
||||
|
||||
ConvertToFieldType(retType);
|
||||
|
@ -604,6 +346,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX));
|
||||
|
||||
generator.Emit(OpCodes.Call, info);
|
||||
|
||||
registerInUse |= 1u << 0;
|
||||
}
|
||||
|
||||
for (int index = 0; index < locals.Count; index++)
|
||||
|
@ -618,26 +362,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
MethodInfo info = typeof(ExecutionContext).GetMethod(nameof(ExecutionContext.SetX));
|
||||
|
||||
generator.Emit(OpCodes.Call, info);
|
||||
}
|
||||
|
||||
bool IsRegisterInUse(int registerIndex)
|
||||
{
|
||||
for (int index = 0; index < locals.Count; index++)
|
||||
{
|
||||
if (registerIndex == locals[index].Item2.Index)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
registerInUse |= 1u << attribute.Index;
|
||||
}
|
||||
|
||||
// Zero out the remaining unused registers.
|
||||
/*
|
||||
for (int i = 0; i < SvcFuncMaxArguments32; i++)
|
||||
for (int i = 0; i < registerCleanCount; i++)
|
||||
{
|
||||
if (IsRegisterInUse(i))
|
||||
if ((registerInUse & (1u << i)) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -650,7 +382,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
|
||||
generator.Emit(OpCodes.Call, info);
|
||||
}
|
||||
*/
|
||||
|
||||
generator.Emit(OpCodes.Ret);
|
||||
|
||||
|
@ -690,8 +421,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
|
||||
private static void PrintResult(KernelResult result, string svcName)
|
||||
{
|
||||
if (result != KernelResult.Success &&
|
||||
result != KernelResult.TimedOut &&
|
||||
if (result != KernelResult.Success &&
|
||||
result != KernelResult.TimedOut &&
|
||||
result != KernelResult.Cancelled &&
|
||||
result != KernelResult.InvalidState)
|
||||
{
|
||||
|
|
|
@ -9,12 +9,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
partial class SvcHandler
|
||||
{
|
||||
public KernelResult CreateThread64(
|
||||
ulong entrypoint,
|
||||
ulong argsPtr,
|
||||
ulong stackTop,
|
||||
int priority,
|
||||
int cpuCore,
|
||||
out int handle)
|
||||
[R(1)] ulong entrypoint,
|
||||
[R(2)] ulong argsPtr,
|
||||
[R(3)] ulong stackTop,
|
||||
[R(4)] int priority,
|
||||
[R(5)] int cpuCore,
|
||||
[R(1)] out int handle)
|
||||
{
|
||||
return CreateThread(entrypoint, argsPtr, stackTop, priority, cpuCore, out handle);
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return result;
|
||||
}
|
||||
|
||||
public KernelResult StartThread64(int handle)
|
||||
public KernelResult StartThread64([R(0)] int handle)
|
||||
{
|
||||
return StartThread(handle);
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
currentThread.Exit();
|
||||
}
|
||||
|
||||
public void SleepThread64(long timeout)
|
||||
public void SleepThread64([R(0)] long timeout)
|
||||
{
|
||||
SleepThread(timeout);
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
}
|
||||
}
|
||||
|
||||
public KernelResult GetThreadPriority64(int handle, out int priority)
|
||||
public KernelResult GetThreadPriority64([R(1)] int handle, [R(1)] out int priority)
|
||||
{
|
||||
return GetThreadPriority(handle, out priority);
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
}
|
||||
}
|
||||
|
||||
public KernelResult SetThreadPriority64(int handle, int priority)
|
||||
public KernelResult SetThreadPriority64([R(0)] int handle, [R(1)] int priority)
|
||||
{
|
||||
return SetThreadPriority(handle, priority);
|
||||
}
|
||||
|
@ -229,7 +229,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult GetThreadCoreMask64(int handle, out int preferredCore, out long affinityMask)
|
||||
public KernelResult GetThreadCoreMask64([R(2)] int handle, [R(1)] out int preferredCore, [R(2)] out long affinityMask)
|
||||
{
|
||||
return GetThreadCoreMask(handle, out preferredCore, out affinityMask);
|
||||
}
|
||||
|
@ -254,7 +254,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
}
|
||||
}
|
||||
|
||||
public KernelResult SetThreadCoreMask64(int handle, int preferredCore, long affinityMask)
|
||||
public KernelResult SetThreadCoreMask64([R(0)] int handle, [R(1)] int preferredCore, [R(2)] long affinityMask)
|
||||
{
|
||||
return SetThreadCoreMask(handle, preferredCore, affinityMask);
|
||||
}
|
||||
|
@ -322,7 +322,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return _system.Scheduler.GetCurrentThread().CurrentCore;
|
||||
}
|
||||
|
||||
public KernelResult GetThreadId64(int handle, out long threadUid)
|
||||
public KernelResult GetThreadId64([R(1)] int handle, [R(1)] out long threadUid)
|
||||
{
|
||||
return GetThreadId(handle, out threadUid);
|
||||
}
|
||||
|
@ -357,7 +357,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
}
|
||||
}
|
||||
|
||||
public KernelResult SetThreadActivity64(int handle, bool pause)
|
||||
public KernelResult SetThreadActivity64([R(0)] int handle, [R(1)] bool pause)
|
||||
{
|
||||
return SetThreadActivity(handle, pause);
|
||||
}
|
||||
|
@ -384,7 +384,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return thread.SetActivity(pause);
|
||||
}
|
||||
|
||||
public KernelResult GetThreadContext364(ulong address, int handle)
|
||||
public KernelResult GetThreadContext364([R(0)] ulong address, [R(1)] int handle)
|
||||
{
|
||||
return GetThreadContext3(address, handle);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
{
|
||||
partial class SvcHandler
|
||||
{
|
||||
public KernelResult WaitSynchronization64(ulong handlesPtr, int handlesCount, long timeout, out int handleIndex)
|
||||
public KernelResult WaitSynchronization64([R(1)] ulong handlesPtr, [R(2)] int handlesCount, [R(3)] long timeout, [R(1)] out int handleIndex)
|
||||
{
|
||||
return WaitSynchronization(handlesPtr, handlesCount, timeout, out handleIndex);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return _system.Synchronization.WaitFor(syncObjs.ToArray(), timeout, out handleIndex);
|
||||
}
|
||||
|
||||
public KernelResult CancelSynchronization64(int handle)
|
||||
public KernelResult CancelSynchronization64([R(0)] int handle)
|
||||
{
|
||||
return CancelSynchronization(handle);
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult ArbitrateLock64(int ownerHandle, ulong mutexAddress, int requesterHandle)
|
||||
public KernelResult ArbitrateLock64([R(0)] int ownerHandle, [R(1)] ulong mutexAddress, [R(2)] int requesterHandle)
|
||||
{
|
||||
return ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return currentProcess.AddressArbiter.ArbitrateLock(ownerHandle, mutexAddress, requesterHandle);
|
||||
}
|
||||
|
||||
public KernelResult ArbitrateUnlock64(ulong mutexAddress)
|
||||
public KernelResult ArbitrateUnlock64([R(0)] ulong mutexAddress)
|
||||
{
|
||||
return ArbitrateUnlock(mutexAddress);
|
||||
}
|
||||
|
@ -126,10 +126,10 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
}
|
||||
|
||||
public KernelResult WaitProcessWideKeyAtomic64(
|
||||
ulong mutexAddress,
|
||||
ulong condVarAddress,
|
||||
int handle,
|
||||
long timeout)
|
||||
[R(0)] ulong mutexAddress,
|
||||
[R(1)] ulong condVarAddress,
|
||||
[R(2)] int handle,
|
||||
[R(3)] long timeout)
|
||||
{
|
||||
return WaitProcessWideKeyAtomic(mutexAddress, condVarAddress, handle, timeout);
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
timeout);
|
||||
}
|
||||
|
||||
public KernelResult SignalProcessWideKey64(ulong address, int count)
|
||||
public KernelResult SignalProcessWideKey64([R(0)] ulong address, [R(1)] int count)
|
||||
{
|
||||
return SignalProcessWideKey(address, count);
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult WaitForAddress64(ulong address, ArbitrationType type, int value, long timeout)
|
||||
public KernelResult WaitForAddress64([R(0)] ulong address, [R(1)] ArbitrationType type, [R(2)] int value, [R(3)] long timeout)
|
||||
{
|
||||
return WaitForAddress(address, type, value, timeout);
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return result;
|
||||
}
|
||||
|
||||
public KernelResult SignalToAddress64(ulong address, SignalType type, int value, int count)
|
||||
public KernelResult SignalToAddress64([R(0)] ulong address, [R(1)] SignalType type, [R(2)] int value, [R(3)] int count)
|
||||
{
|
||||
return SignalToAddress(address, type, value, count);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
|
||||
public void StartAutoPreemptionThread()
|
||||
{
|
||||
Thread preemptionThread = new Thread(PreemptCurrentThread);
|
||||
Thread preemptionThread = new Thread(PreemptCurrentThread)
|
||||
{
|
||||
Name = "HLE.PreemptionThread"
|
||||
};
|
||||
|
||||
_keepPreempting = true;
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
is64Bits = true;
|
||||
}
|
||||
|
||||
HostThread = new Thread(customHostThreadStart == null ? () => ThreadStart(entrypoint) : customHostThreadStart);
|
||||
HostThread = new Thread(customHostThreadStart ?? (() => ThreadStart(entrypoint)));
|
||||
|
||||
Context = new ARMeilleure.State.ExecutionContext();
|
||||
|
||||
|
@ -185,7 +185,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
|
||||
ThreadUid = System.GetThreadUid();
|
||||
|
||||
HostThread.Name = $"Host Thread (thread id {ThreadUid})";
|
||||
HostThread.Name = $"HLE.HostThread.{ThreadUid}";
|
||||
|
||||
_hasBeenInitialized = true;
|
||||
|
||||
|
|
|
@ -55,7 +55,10 @@ namespace Ryujinx.Profiler
|
|||
_cleanupRunning = true;
|
||||
|
||||
// Create cleanup thread.
|
||||
_cleanupThread = new Thread(CleanupLoop);
|
||||
_cleanupThread = new Thread(CleanupLoop)
|
||||
{
|
||||
Name = "Profiler.CleanupThread"
|
||||
};
|
||||
_cleanupThread.Start();
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,10 @@ namespace Ryujinx.Profiler.UI
|
|||
{
|
||||
_profilerRunning = true;
|
||||
_prevTime = 0;
|
||||
_profileThread = new Thread(ProfileLoop);
|
||||
_profileThread = new Thread(ProfileLoop)
|
||||
{
|
||||
Name = "Profiler.ProfileThread"
|
||||
};
|
||||
_profileThread.Start();
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +63,10 @@ namespace Ryujinx.Profiler.UI
|
|||
using (_window = new ProfileWindow())
|
||||
{
|
||||
// Create thread for render loop
|
||||
_renderThread = new Thread(RenderLoop);
|
||||
_renderThread = new Thread(RenderLoop)
|
||||
{
|
||||
Name = "Profiler.RenderThread"
|
||||
};
|
||||
_renderThread.Start();
|
||||
|
||||
while (_profilerRunning)
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
namespace Ryujinx.Ui
|
||||
{
|
||||
internal struct AboutInfo
|
||||
{
|
||||
public string InstallVersion;
|
||||
public string InstallCommit;
|
||||
public string InstallBranch;
|
||||
}
|
||||
}
|
|
@ -13,8 +13,6 @@ namespace Ryujinx.Ui
|
|||
{
|
||||
public class AboutWindow : Window
|
||||
{
|
||||
private static AboutInfo AboutInformation { get; set; }
|
||||
|
||||
#pragma warning disable CS0649
|
||||
#pragma warning disable IDE0044
|
||||
[GUI] Window _aboutWin;
|
||||
|
|
|
@ -120,7 +120,10 @@ namespace Ryujinx.Ui
|
|||
Context.MakeCurrent(null);
|
||||
|
||||
// OpenTK doesn't like sleeps in its thread, to avoid this a renderer thread is created
|
||||
_renderThread = new Thread(RenderLoop);
|
||||
_renderThread = new Thread(RenderLoop)
|
||||
{
|
||||
Name = "GUI.RenderThread"
|
||||
};
|
||||
|
||||
_renderThread.Start();
|
||||
|
||||
|
|
|
@ -653,6 +653,7 @@ namespace Ryujinx.Ui
|
|||
}
|
||||
});
|
||||
|
||||
thread.Name = "GUI.FirmwareInstallerThread";
|
||||
thread.Start();
|
||||
}
|
||||
else
|
||||
|
|
Loading…
Add table
Reference in a new issue