0
0
Fork 0
mirror of https://github.com/ryujinx-mirror/ryujinx.git synced 2024-12-22 23:45:46 +00:00

Add a Multithreading layer for the GAL, multi-thread shader compilation at runtime (#2501)

* Initial Implementation

About as fast as nvidia GL multithreading, can be improved with faster command queuing.

* Struct based command list

Speeds up a bit. Still a lot of time lost to resource copy.

* Do shader init while the render thread is active.

* Introduce circular span pool V1

Ideally should be able to use structs instead of references for storing these spans on commands. Will try that next.

* Refactor SpanRef some more

Use a struct to represent SpanRef, rather than a reference.

* Flush buffers on background thread

* Use a span for UpdateRenderScale.

Much faster than copying the array.

* Calculate command size using reflection

* WIP parallel shaders

* Some minor optimisation

* Only 2 max refs per command now.

The command with 3 refs is gone. 😌

* Don't cast on the GPU side

* Remove redundant casts, force sync on window present

* Fix Shader Cache

* Fix host shader save.

* Fixup to work with new renderer stuff

* Make command Run static, use array of delegates as lookup

Profile says this takes less time than the previous way.

* Bring up to date

* Add settings toggle. Fix Muiltithreading Off mode.

* Fix warning.

* Release tracking lock for flushes

* Fix Conditional Render fast path with threaded gal

* Make handle iteration safe when releasing the lock

This is mostly temporary.

* Attempt to set backend threading on driver

Only really works on nvidia before launching a game.

* Fix race condition with BufferModifiedRangeList, exceptions in tracking actions

* Update buffer set commands

* Some cleanup

* Only use stutter workaround when using opengl renderer non-threaded

* Add host-conditional reservation of counter events

There has always been the possibility that conditional rendering could use a query object just as it is disposed by the counter queue. This change makes it so that when the host decides to use host conditional rendering, the query object is reserved so that it cannot be deleted. Counter events can optionally start reserved, as the threaded implementation can reserve them before the backend creates them, and there would otherwise be a short amount of time where the counter queue could dispose the event before a call to reserve it could be made.

* Address Feedback

* Make counter flush tracked again.

Hopefully does not cause any issues this time.

* Wait for FlushTo on the main queue thread.

Currently assumes only one thread will want to FlushTo (in this case, the GPU thread)

* Add SDL2 headless integration

* Add HLE macro commands.

Co-authored-by: Mary <mary@mary.zone>
This commit is contained in:
riperiperi 2021-08-26 23:31:29 +01:00 committed by GitHub
parent 501c3d5cea
commit ec3e848d79
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
143 changed files with 4491 additions and 200 deletions

View file

@ -0,0 +1,9 @@
namespace Ryujinx.Common.Configuration
{
public enum BackendThreading
{
Auto,
Off,
On
}
}

View file

@ -0,0 +1,20 @@
using System;
namespace Ryujinx.Common.Pools
{
public static class ThreadStaticArray<T>
{
[ThreadStatic]
private static T[] _array;
public static ref T[] Get()
{
if (_array == null)
{
_array = new T[1];
}
return ref _array;
}
}
}

View file

@ -6,6 +6,8 @@ namespace Ryujinx.Graphics.GAL
{
bool Invalid { get; set; }
bool ReserveForHostAccess();
void Flush();
}
}

View file

@ -99,6 +99,6 @@ namespace Ryujinx.Graphics.GAL
bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual);
void EndHostConditionalRendering();
void UpdateRenderScale(ShaderStage stage, float[] scales, int textureCount, int imageCount);
void UpdateRenderScale(ShaderStage stage, ReadOnlySpan<float> scales, int textureCount, int imageCount);
}
}

View file

@ -8,11 +8,13 @@ namespace Ryujinx.Graphics.GAL
{
event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
bool PreferThreading { get; }
IPipeline Pipeline { get; }
IWindow Window { get; }
void BackgroundContextAction(Action action);
void BackgroundContextAction(Action action, bool alwaysBackground = false);
IShader CompileShader(ShaderStage stage, string code);
@ -39,10 +41,15 @@ namespace Ryujinx.Graphics.GAL
void PreFrame();
ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler);
ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, bool hostReserved);
void ResetCounter(CounterType type);
void RunLoop(Action gpuLoop)
{
gpuLoop();
}
void WaitSync(ulong id);
void Initialize(GraphicsDebugLevel logLevel);

View file

@ -1,8 +1,10 @@
using System;
namespace Ryujinx.Graphics.GAL
{
public interface IWindow
{
void Present(ITexture texture, ImageCrop crop);
void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback);
void SetSize(int width, int height);
}

View file

@ -0,0 +1,170 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
namespace Ryujinx.Graphics.GAL.Multithreading
{
/// <summary>
/// Buffer handles given to the client are not the same as those provided by the backend,
/// as their handle is created at a later point on the queue.
/// The handle returned is a unique identifier that will map to the real buffer when it is available.
/// Note that any uses within the queue should be safe, but outside you must use MapBufferBlocking.
/// </summary>
class BufferMap
{
private ulong _bufferHandle = 0;
private Dictionary<BufferHandle, BufferHandle> _bufferMap = new Dictionary<BufferHandle, BufferHandle>();
private HashSet<BufferHandle> _inFlight = new HashSet<BufferHandle>();
private AutoResetEvent _inFlightChanged = new AutoResetEvent(false);
internal BufferHandle CreateBufferHandle()
{
ulong handle64 = Interlocked.Increment(ref _bufferHandle);
BufferHandle threadedHandle = Unsafe.As<ulong, BufferHandle>(ref handle64);
lock (_inFlight)
{
_inFlight.Add(threadedHandle);
}
return threadedHandle;
}
internal void AssignBuffer(BufferHandle threadedHandle, BufferHandle realHandle)
{
lock (_bufferMap)
{
_bufferMap[threadedHandle] = realHandle;
}
lock (_inFlight)
{
_inFlight.Remove(threadedHandle);
}
_inFlightChanged.Set();
}
internal void UnassignBuffer(BufferHandle threadedHandle)
{
lock (_bufferMap)
{
_bufferMap.Remove(threadedHandle);
}
}
internal BufferHandle MapBuffer(BufferHandle handle)
{
// Maps a threaded buffer to a backend one.
// Threaded buffers are returned on creation as the buffer
// isn't actually created until the queue runs the command.
BufferHandle result;
lock (_bufferMap)
{
if (!_bufferMap.TryGetValue(handle, out result))
{
result = BufferHandle.Null;
}
return result;
}
}
internal BufferHandle MapBufferBlocking(BufferHandle handle)
{
// Blocks until the handle is available.
BufferHandle result;
lock (_bufferMap)
{
if (_bufferMap.TryGetValue(handle, out result))
{
return result;
}
}
bool signal = false;
while (true)
{
lock (_inFlight)
{
if (!_inFlight.Contains(handle))
{
break;
}
}
_inFlightChanged.WaitOne();
signal = true;
}
if (signal)
{
// Signal other threads which might still be waiting.
_inFlightChanged.Set();
}
return MapBuffer(handle);
}
internal BufferRange MapBufferRange(BufferRange range)
{
return new BufferRange(MapBuffer(range.Handle), range.Offset, range.Size);
}
internal Span<BufferRange> MapBufferRanges(Span<BufferRange> ranges)
{
// Rewrite the buffer ranges to point to the mapped handles.
lock (_bufferMap)
{
for (int i = 0; i < ranges.Length; i++)
{
ref BufferRange range = ref ranges[i];
BufferHandle result;
if (!_bufferMap.TryGetValue(range.Handle, out result))
{
result = BufferHandle.Null;
}
range = new BufferRange(result, range.Offset, range.Size);
}
}
return ranges;
}
internal Span<VertexBufferDescriptor> MapBufferRanges(Span<VertexBufferDescriptor> ranges)
{
// Rewrite the buffer ranges to point to the mapped handles.
lock (_bufferMap)
{
for (int i = 0; i < ranges.Length; i++)
{
BufferRange range = ranges[i].Buffer;
BufferHandle result;
if (!_bufferMap.TryGetValue(range.Handle, out result))
{
result = BufferHandle.Null;
}
range = new BufferRange(result, range.Offset, range.Size);
ranges[i] = new VertexBufferDescriptor(range, ranges[i].Stride, ranges[i].Divisor);
}
}
return ranges;
}
}
}

View file

@ -0,0 +1,234 @@
using Ryujinx.Graphics.GAL.Multithreading.Commands;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Buffer;
using Ryujinx.Graphics.GAL.Multithreading.Commands.CounterEvent;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Program;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Sampler;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Shader;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Window;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.GAL.Multithreading
{
static class CommandHelper
{
private delegate void CommandDelegate(Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer);
private static int _totalCommands = (int)Enum.GetValues<CommandType>().Max() + 1;
private static CommandDelegate[] _lookup = new CommandDelegate[_totalCommands];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ref T GetCommand<T>(Span<byte> memory)
{
return ref Unsafe.As<byte, T>(ref MemoryMarshal.GetReference(memory));
}
public static int GetMaxCommandSize()
{
Assembly assembly = typeof(CommandHelper).Assembly;
IEnumerable<Type> commands = assembly.GetTypes().Where(type => typeof(IGALCommand).IsAssignableFrom(type) && type.IsValueType);
int maxSize = commands.Max(command =>
{
MethodInfo method = typeof(Unsafe).GetMethod(nameof(Unsafe.SizeOf));
MethodInfo generic = method.MakeGenericMethod(command);
int size = (int)generic.Invoke(null, null);
return size;
});
InitLookup();
return maxSize + 1; // 1 byte reserved for command size.
}
private static void InitLookup()
{
_lookup[(int)CommandType.Action] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
ActionCommand.Run(ref GetCommand<ActionCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CompileShader] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
CompileShaderCommand.Run(ref GetCommand<CompileShaderCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CreateBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
CreateBufferCommand.Run(ref GetCommand<CreateBufferCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CreateProgram] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
CreateProgramCommand.Run(ref GetCommand<CreateProgramCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CreateSampler] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
CreateSamplerCommand.Run(ref GetCommand<CreateSamplerCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CreateSync] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
CreateSyncCommand.Run(ref GetCommand<CreateSyncCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CreateTexture] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
CreateTextureCommand.Run(ref GetCommand<CreateTextureCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.GetCapabilities] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
GetCapabilitiesCommand.Run(ref GetCommand<GetCapabilitiesCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.PreFrame] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
PreFrameCommand.Run(ref GetCommand<PreFrameCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ReportCounter] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
ReportCounterCommand.Run(ref GetCommand<ReportCounterCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ResetCounter] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
ResetCounterCommand.Run(ref GetCommand<ResetCounterCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.UpdateCounters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
UpdateCountersCommand.Run(ref GetCommand<UpdateCountersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.BufferDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
BufferDisposeCommand.Run(ref GetCommand<BufferDisposeCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.BufferGetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
BufferGetDataCommand.Run(ref GetCommand<BufferGetDataCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.BufferSetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
BufferSetDataCommand.Run(ref GetCommand<BufferSetDataCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CounterEventDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
CounterEventDisposeCommand.Run(ref GetCommand<CounterEventDisposeCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CounterEventFlush] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
CounterEventFlushCommand.Run(ref GetCommand<CounterEventFlushCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ProgramDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
ProgramDisposeCommand.Run(ref GetCommand<ProgramDisposeCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ProgramGetBinary] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
ProgramGetBinaryCommand.Run(ref GetCommand<ProgramGetBinaryCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ProgramCheckLink] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
ProgramCheckLinkCommand.Run(ref GetCommand<ProgramCheckLinkCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SamplerDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SamplerDisposeCommand.Run(ref GetCommand<SamplerDisposeCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ShaderDispose] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
ShaderDisposeCommand.Run(ref GetCommand<ShaderDisposeCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureCopyTo] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
TextureCopyToCommand.Run(ref GetCommand<TextureCopyToCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureCopyToScaled] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
TextureCopyToScaledCommand.Run(ref GetCommand<TextureCopyToScaledCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureCopyToSlice] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
TextureCopyToSliceCommand.Run(ref GetCommand<TextureCopyToSliceCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureCreateView] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
TextureCreateViewCommand.Run(ref GetCommand<TextureCreateViewCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureGetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
TextureGetDataCommand.Run(ref GetCommand<TextureGetDataCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureRelease] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
TextureReleaseCommand.Run(ref GetCommand<TextureReleaseCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureSetData] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
TextureSetDataCommand.Run(ref GetCommand<TextureSetDataCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureSetDataSlice] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
TextureSetDataSliceCommand.Run(ref GetCommand<TextureSetDataSliceCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureSetStorage] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
TextureSetStorageCommand.Run(ref GetCommand<TextureSetStorageCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.WindowPresent] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
WindowPresentCommand.Run(ref GetCommand<WindowPresentCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.Barrier] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
BarrierCommand.Run(ref GetCommand<BarrierCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.BeginTransformFeedback] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
BeginTransformFeedbackCommand.Run(ref GetCommand<BeginTransformFeedbackCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ClearBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
ClearBufferCommand.Run(ref GetCommand<ClearBufferCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ClearRenderTargetColor] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
ClearRenderTargetColorCommand.Run(ref GetCommand<ClearRenderTargetColorCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.ClearRenderTargetDepthStencil] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
ClearRenderTargetDepthStencilCommand.Run(ref GetCommand<ClearRenderTargetDepthStencilCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CommandBufferBarrier] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
CommandBufferBarrierCommand.Run(ref GetCommand<CommandBufferBarrierCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.CopyBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
CopyBufferCommand.Run(ref GetCommand<CopyBufferCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.DispatchCompute] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
DispatchComputeCommand.Run(ref GetCommand<DispatchComputeCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.Draw] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
DrawCommand.Run(ref GetCommand<DrawCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.DrawIndexed] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
DrawIndexedCommand.Run(ref GetCommand<DrawIndexedCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.EndHostConditionalRendering] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
EndHostConditionalRenderingCommand.Run(renderer);
_lookup[(int)CommandType.EndTransformFeedback] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
EndTransformFeedbackCommand.Run(ref GetCommand<EndTransformFeedbackCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.MultiDrawIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
MultiDrawIndirectCountCommand.Run(ref GetCommand<MultiDrawIndirectCountCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.MultiDrawIndexedIndirectCount] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
MultiDrawIndexedIndirectCountCommand.Run(ref GetCommand<MultiDrawIndexedIndirectCountCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetAlphaTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetAlphaTestCommand.Run(ref GetCommand<SetAlphaTestCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetBlendState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetBlendStateCommand.Run(ref GetCommand<SetBlendStateCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetDepthBias] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetDepthBiasCommand.Run(ref GetCommand<SetDepthBiasCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetDepthClamp] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetDepthClampCommand.Run(ref GetCommand<SetDepthClampCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetDepthMode] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetDepthModeCommand.Run(ref GetCommand<SetDepthModeCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetDepthTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetDepthTestCommand.Run(ref GetCommand<SetDepthTestCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetFaceCulling] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetFaceCullingCommand.Run(ref GetCommand<SetFaceCullingCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetFrontFace] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetFrontFaceCommand.Run(ref GetCommand<SetFrontFaceCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetStorageBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetStorageBuffersCommand.Run(ref GetCommand<SetStorageBuffersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetTransformFeedbackBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetTransformFeedbackBuffersCommand.Run(ref GetCommand<SetTransformFeedbackBuffersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetUniformBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetUniformBuffersCommand.Run(ref GetCommand<SetUniformBuffersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetImage] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetImageCommand.Run(ref GetCommand<SetImageCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetIndexBuffer] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetIndexBufferCommand.Run(ref GetCommand<SetIndexBufferCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetLineParameters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetLineParametersCommand.Run(ref GetCommand<SetLineParametersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetLogicOpState] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetLogicOpStateCommand.Run(ref GetCommand<SetLogicOpStateCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetPointParameters] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetPointParametersCommand.Run(ref GetCommand<SetPointParametersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetPrimitiveRestart] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetPrimitiveRestartCommand.Run(ref GetCommand<SetPrimitiveRestartCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetPrimitiveTopology] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetPrimitiveTopologyCommand.Run(ref GetCommand<SetPrimitiveTopologyCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetProgram] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetProgramCommand.Run(ref GetCommand<SetProgramCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetRasterizerDiscard] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetRasterizerDiscardCommand.Run(ref GetCommand<SetRasterizerDiscardCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetRenderTargetColorMasks] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetRenderTargetColorMasksCommand.Run(ref GetCommand<SetRenderTargetColorMasksCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetRenderTargetScale] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetRenderTargetScaleCommand.Run(ref GetCommand<SetRenderTargetScaleCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetRenderTargets] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetRenderTargetsCommand.Run(ref GetCommand<SetRenderTargetsCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetSampler] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetSamplerCommand.Run(ref GetCommand<SetSamplerCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetScissor] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetScissorCommand.Run(ref GetCommand<SetScissorCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetStencilTest] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetStencilTestCommand.Run(ref GetCommand<SetStencilTestCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetTexture] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetTextureCommand.Run(ref GetCommand<SetTextureCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetUserClipDistance] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetUserClipDistanceCommand.Run(ref GetCommand<SetUserClipDistanceCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetVertexAttribs] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetVertexAttribsCommand.Run(ref GetCommand<SetVertexAttribsCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetVertexBuffers] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetVertexBuffersCommand.Run(ref GetCommand<SetVertexBuffersCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.SetViewports] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
SetViewportsCommand.Run(ref GetCommand<SetViewportsCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureBarrier] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
TextureBarrierCommand.Run(ref GetCommand<TextureBarrierCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TextureBarrierTiled] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
TextureBarrierTiledCommand.Run(ref GetCommand<TextureBarrierTiledCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TryHostConditionalRendering] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
TryHostConditionalRenderingCommand.Run(ref GetCommand<TryHostConditionalRenderingCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.TryHostConditionalRenderingFlush] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
TryHostConditionalRenderingFlushCommand.Run(ref GetCommand<TryHostConditionalRenderingFlushCommand>(memory), threaded, renderer);
_lookup[(int)CommandType.UpdateRenderScale] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
UpdateRenderScaleCommand.Run(ref GetCommand<UpdateRenderScaleCommand>(memory), threaded, renderer);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void RunCommand(Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer)
{
_lookup[memory[memory.Length - 1]](memory, threaded, renderer);
}
}
}

View file

@ -0,0 +1,97 @@
namespace Ryujinx.Graphics.GAL.Multithreading
{
enum CommandType : byte
{
Action,
CompileShader,
CreateBuffer,
CreateProgram,
CreateSampler,
CreateSync,
CreateTexture,
GetCapabilities,
Unused,
PreFrame,
ReportCounter,
ResetCounter,
UpdateCounters,
BufferDispose,
BufferGetData,
BufferSetData,
CounterEventDispose,
CounterEventFlush,
ProgramDispose,
ProgramGetBinary,
ProgramCheckLink,
SamplerDispose,
ShaderDispose,
TextureCopyTo,
TextureCopyToScaled,
TextureCopyToSlice,
TextureCreateView,
TextureGetData,
TextureRelease,
TextureSetData,
TextureSetDataSlice,
TextureSetStorage,
WindowPresent,
Barrier,
BeginTransformFeedback,
ClearBuffer,
ClearRenderTargetColor,
ClearRenderTargetDepthStencil,
CommandBufferBarrier,
CopyBuffer,
DispatchCompute,
Draw,
DrawIndexed,
EndHostConditionalRendering,
EndTransformFeedback,
MultiDrawIndirectCount,
MultiDrawIndexedIndirectCount,
SetAlphaTest,
SetBlendState,
SetDepthBias,
SetDepthClamp,
SetDepthMode,
SetDepthTest,
SetFaceCulling,
SetFrontFace,
SetStorageBuffers,
SetTransformFeedbackBuffers,
SetUniformBuffers,
SetImage,
SetIndexBuffer,
SetLineParameters,
SetLogicOpState,
SetPointParameters,
SetPrimitiveRestart,
SetPrimitiveTopology,
SetProgram,
SetRasterizerDiscard,
SetRenderTargetColorMasks,
SetRenderTargetScale,
SetRenderTargets,
SetSampler,
SetScissor,
SetStencilTest,
SetTexture,
SetUserClipDistance,
SetVertexAttribs,
SetVertexBuffers,
SetViewports,
TextureBarrier,
TextureBarrierTiled,
TryHostConditionalRendering,
TryHostConditionalRenderingFlush,
UpdateRenderScale
}
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct BarrierCommand : IGALCommand
{
public CommandType CommandType => CommandType.Barrier;
public static void Run(ref BarrierCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.Barrier();
}
}
}

View file

@ -0,0 +1,18 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct BeginTransformFeedbackCommand : IGALCommand
{
public CommandType CommandType => CommandType.BeginTransformFeedback;
private PrimitiveTopology _topology;
public void Set(PrimitiveTopology topology)
{
_topology = topology;
}
public static void Run(ref BeginTransformFeedbackCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.BeginTransformFeedback(command._topology);
}
}
}

View file

@ -0,0 +1,19 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Buffer
{
struct BufferDisposeCommand : IGALCommand
{
public CommandType CommandType => CommandType.BufferDispose;
private BufferHandle _buffer;
public void Set(BufferHandle buffer)
{
_buffer = buffer;
}
public static void Run(ref BufferDisposeCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.DeleteBuffer(threaded.Buffers.MapBuffer(command._buffer));
threaded.Buffers.UnassignBuffer(command._buffer);
}
}
}

View file

@ -0,0 +1,29 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using System;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Buffer
{
struct BufferGetDataCommand : IGALCommand
{
public CommandType CommandType => CommandType.BufferGetData;
private BufferHandle _buffer;
private int _offset;
private int _size;
private TableRef<ResultBox<PinnedSpan<byte>>> _result;
public void Set(BufferHandle buffer, int offset, int size, TableRef<ResultBox<PinnedSpan<byte>>> result)
{
_buffer = buffer;
_offset = offset;
_size = size;
_result = result;
}
public static void Run(ref BufferGetDataCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ReadOnlySpan<byte> result = renderer.GetBufferData(threaded.Buffers.MapBuffer(command._buffer), command._offset, command._size);
command._result.Get(threaded).Result = new PinnedSpan<byte>(result);
}
}
}

View file

@ -0,0 +1,27 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using System;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Buffer
{
struct BufferSetDataCommand : IGALCommand
{
public CommandType CommandType => CommandType.BufferSetData;
private BufferHandle _buffer;
private int _offset;
private SpanRef<byte> _data;
public void Set(BufferHandle buffer, int offset, SpanRef<byte> data)
{
_buffer = buffer;
_offset = offset;
_data = data;
}
public static void Run(ref BufferSetDataCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ReadOnlySpan<byte> data = command._data.Get(threaded);
renderer.SetBufferData(threaded.Buffers.MapBuffer(command._buffer), command._offset, data);
command._data.Dispose(threaded);
}
}
}

View file

@ -0,0 +1,24 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct ClearBufferCommand : IGALCommand
{
public CommandType CommandType => CommandType.ClearBuffer;
private BufferHandle _destination;
private int _offset;
private int _size;
private uint _value;
public void Set(BufferHandle destination, int offset, int size, uint value)
{
_destination = destination;
_offset = offset;
_size = size;
_value = value;
}
public static void Run(ref ClearBufferCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.ClearBuffer(threaded.Buffers.MapBuffer(command._destination), command._offset, command._size, command._value);
}
}
}

View file

@ -0,0 +1,22 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct ClearRenderTargetColorCommand : IGALCommand
{
public CommandType CommandType => CommandType.ClearRenderTargetColor;
private int _index;
private uint _componentMask;
private ColorF _color;
public void Set(int index, uint componentMask, ColorF color)
{
_index = index;
_componentMask = componentMask;
_color = color;
}
public static void Run(ref ClearRenderTargetColorCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.ClearRenderTargetColor(command._index, command._componentMask, command._color);
}
}
}

View file

@ -0,0 +1,24 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct ClearRenderTargetDepthStencilCommand : IGALCommand
{
public CommandType CommandType => CommandType.ClearRenderTargetDepthStencil;
private float _depthValue;
private bool _depthMask;
private int _stencilValue;
private int _stencilMask;
public void Set(float depthValue, bool depthMask, int stencilValue, int stencilMask)
{
_depthValue = depthValue;
_depthMask = depthMask;
_stencilValue = stencilValue;
_stencilMask = stencilMask;
}
public static void Run(ref ClearRenderTargetDepthStencilCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.ClearRenderTargetDepthStencil(command._depthValue, command._depthMask, command._stencilValue, command._stencilMask);
}
}
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct CommandBufferBarrierCommand : IGALCommand
{
public CommandType CommandType => CommandType.CommandBufferBarrier;
public static void Run(ref CommandBufferBarrierCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.CommandBufferBarrier();
}
}
}

View file

@ -0,0 +1,26 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct CopyBufferCommand : IGALCommand
{
public CommandType CommandType => CommandType.CopyBuffer;
private BufferHandle _source;
private BufferHandle _destination;
private int _srcOffset;
private int _dstOffset;
private int _size;
public void Set(BufferHandle source, BufferHandle destination, int srcOffset, int dstOffset, int size)
{
_source = source;
_destination = destination;
_srcOffset = srcOffset;
_dstOffset = dstOffset;
_size = size;
}
public static void Run(ref CopyBufferCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.CopyBuffer(threaded.Buffers.MapBuffer(command._source), threaded.Buffers.MapBuffer(command._destination), command._srcOffset, command._dstOffset, command._size);
}
}
}

View file

@ -0,0 +1,21 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.CounterEvent
{
struct CounterEventDisposeCommand : IGALCommand
{
public CommandType CommandType => CommandType.CounterEventDispose;
private TableRef<ThreadedCounterEvent> _event;
public void Set(TableRef<ThreadedCounterEvent> evt)
{
_event = evt;
}
public static void Run(ref CounterEventDisposeCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._event.Get(threaded).Base.Dispose();
}
}
}

View file

@ -0,0 +1,21 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.CounterEvent
{
struct CounterEventFlushCommand : IGALCommand
{
public CommandType CommandType => CommandType.CounterEventFlush;
private TableRef<ThreadedCounterEvent> _event;
public void Set(TableRef<ThreadedCounterEvent> evt)
{
_event = evt;
}
public static void Run(ref CounterEventFlushCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._event.Get(threaded).Base.Flush();
}
}
}

View file

@ -0,0 +1,22 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct DispatchComputeCommand : IGALCommand
{
public CommandType CommandType => CommandType.DispatchCompute;
private int _groupsX;
private int _groupsY;
private int _groupsZ;
public void Set(int groupsX, int groupsY, int groupsZ)
{
_groupsX = groupsX;
_groupsY = groupsY;
_groupsZ = groupsZ;
}
public static void Run(ref DispatchComputeCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.DispatchCompute(command._groupsX, command._groupsY, command._groupsZ);
}
}
}

View file

@ -0,0 +1,26 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct DrawIndexedCommand : IGALCommand
{
public CommandType CommandType => CommandType.DrawIndexed;
private int _indexCount;
private int _instanceCount;
private int _firstIndex;
private int _firstVertex;
private int _firstInstance;
public void Set(int indexCount, int instanceCount, int firstIndex, int firstVertex, int firstInstance)
{
_indexCount = indexCount;
_instanceCount = instanceCount;
_firstIndex = firstIndex;
_firstVertex = firstVertex;
_firstInstance = firstInstance;
}
public static void Run(ref DrawIndexedCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.DrawIndexed(command._indexCount, command._instanceCount, command._firstIndex, command._firstVertex, command._firstInstance);
}
}
}

View file

@ -0,0 +1,24 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct DrawCommand : IGALCommand
{
public CommandType CommandType => CommandType.Draw;
private int _vertexCount;
private int _instanceCount;
private int _firstVertex;
private int _firstInstance;
public void Set(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
{
_vertexCount = vertexCount;
_instanceCount = instanceCount;
_firstVertex = firstVertex;
_firstInstance = firstInstance;
}
public static void Run(ref DrawCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.Draw(command._vertexCount, command._instanceCount, command._firstVertex, command._firstInstance);
}
}
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct EndHostConditionalRenderingCommand : IGALCommand
{
public CommandType CommandType => CommandType.EndHostConditionalRendering;
public static void Run(IRenderer renderer)
{
renderer.Pipeline.EndHostConditionalRendering();
}
}
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct EndTransformFeedbackCommand : IGALCommand
{
public CommandType CommandType => CommandType.EndTransformFeedback;
public static void Run(ref EndTransformFeedbackCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.EndTransformFeedback();
}
}
}

View file

@ -0,0 +1,7 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
interface IGALCommand
{
CommandType CommandType { get; }
}
}

View file

@ -0,0 +1,29 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct MultiDrawIndexedIndirectCountCommand : IGALCommand
{
public CommandType CommandType => CommandType.MultiDrawIndexedIndirectCount;
private BufferRange _indirectBuffer;
private BufferRange _parameterBuffer;
private int _maxDrawCount;
private int _stride;
public void Set(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
{
_indirectBuffer = indirectBuffer;
_parameterBuffer = parameterBuffer;
_maxDrawCount = maxDrawCount;
_stride = stride;
}
public static void Run(ref MultiDrawIndexedIndirectCountCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.MultiDrawIndexedIndirectCount(
threaded.Buffers.MapBufferRange(command._indirectBuffer),
threaded.Buffers.MapBufferRange(command._parameterBuffer),
command._maxDrawCount,
command._stride
);
}
}
}

View file

@ -0,0 +1,29 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct MultiDrawIndirectCountCommand : IGALCommand
{
public CommandType CommandType => CommandType.MultiDrawIndirectCount;
private BufferRange _indirectBuffer;
private BufferRange _parameterBuffer;
private int _maxDrawCount;
private int _stride;
public void Set(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
{
_indirectBuffer = indirectBuffer;
_parameterBuffer = parameterBuffer;
_maxDrawCount = maxDrawCount;
_stride = stride;
}
public static void Run(ref MultiDrawIndirectCountCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.MultiDrawIndirectCount(
threaded.Buffers.MapBufferRange(command._indirectBuffer),
threaded.Buffers.MapBufferRange(command._parameterBuffer),
command._maxDrawCount,
command._stride
);
}
}
}

View file

@ -0,0 +1,27 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Program
{
struct ProgramCheckLinkCommand : IGALCommand
{
public CommandType CommandType => CommandType.ProgramCheckLink;
private TableRef<ThreadedProgram> _program;
private bool _blocking;
private TableRef<ResultBox<ProgramLinkStatus>> _result;
public void Set(TableRef<ThreadedProgram> program, bool blocking, TableRef<ResultBox<ProgramLinkStatus>> result)
{
_program = program;
_blocking = blocking;
_result = result;
}
public static void Run(ref ProgramCheckLinkCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ProgramLinkStatus result = command._program.Get(threaded).Base.CheckProgramLink(command._blocking);
command._result.Get(threaded).Result = result;
}
}
}

View file

@ -0,0 +1,21 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Program
{
struct ProgramDisposeCommand : IGALCommand
{
public CommandType CommandType => CommandType.ProgramDispose;
private TableRef<ThreadedProgram> _program;
public void Set(TableRef<ThreadedProgram> program)
{
_program = program;
}
public static void Run(ref ProgramDisposeCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._program.Get(threaded).Base.Dispose();
}
}
}

View file

@ -0,0 +1,25 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Program
{
struct ProgramGetBinaryCommand : IGALCommand
{
public CommandType CommandType => CommandType.ProgramGetBinary;
private TableRef<ThreadedProgram> _program;
private TableRef<ResultBox<byte[]>> _result;
public void Set(TableRef<ThreadedProgram> program, TableRef<ResultBox<byte[]>> result)
{
_program = program;
_result = result;
}
public static void Run(ref ProgramGetBinaryCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
byte[] result = command._program.Get(threaded).Base.GetBinary();
command._result.Get(threaded).Result = result;
}
}
}

View file

@ -0,0 +1,21 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using System;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{
struct ActionCommand : IGALCommand
{
public CommandType CommandType => CommandType.Action;
private TableRef<Action> _action;
public void Set(TableRef<Action> action)
{
_action = action;
}
public static void Run(ref ActionCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._action.Get(threaded)();
}
}
}

View file

@ -0,0 +1,22 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{
struct CompileShaderCommand : IGALCommand
{
public CommandType CommandType => CommandType.CompileShader;
private TableRef<ThreadedShader> _shader;
public void Set(TableRef<ThreadedShader> shader)
{
_shader = shader;
}
public static void Run(ref CompileShaderCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedShader shader = command._shader.Get(threaded);
shader.EnsureCreated();
}
}
}

View file

@ -0,0 +1,23 @@
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using Ryujinx.Graphics.Shader;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{
struct CreateBufferCommand : IGALCommand
{
public CommandType CommandType => CommandType.CreateBuffer;
private BufferHandle _threadedHandle;
private int _size;
public void Set(BufferHandle threadedHandle, int size)
{
_threadedHandle = threadedHandle;
_size = size;
}
public static void Run(ref CreateBufferCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
threaded.Buffers.AssignBuffer(command._threadedHandle, renderer.CreateBuffer(command._size));
}
}
}

View file

@ -0,0 +1,28 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources.Programs;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{
struct CreateProgramCommand : IGALCommand
{
public CommandType CommandType => CommandType.CreateProgram;
private TableRef<IProgramRequest> _request;
public void Set(TableRef<IProgramRequest> request)
{
_request = request;
}
public static void Run(ref CreateProgramCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
IProgramRequest request = command._request.Get(threaded);
if (request.Threaded.Base == null)
{
request.Threaded.Base = request.Create(renderer);
}
threaded.Programs.ProcessQueue();
}
}
}

View file

@ -0,0 +1,23 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{
struct CreateSamplerCommand : IGALCommand
{
public CommandType CommandType => CommandType.CreateSampler;
private TableRef<ThreadedSampler> _sampler;
private SamplerCreateInfo _info;
public void Set(TableRef<ThreadedSampler> sampler, SamplerCreateInfo info)
{
_sampler = sampler;
_info = info;
}
public static void Run(ref CreateSamplerCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._sampler.Get(threaded).Base = renderer.CreateSampler(command._info);
}
}
}

View file

@ -0,0 +1,20 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{
struct CreateSyncCommand : IGALCommand
{
public CommandType CommandType => CommandType.CreateSync;
private ulong _id;
public void Set(ulong id)
{
_id = id;
}
public static void Run(ref CreateSyncCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.CreateSync(command._id);
threaded.Sync.AssignSync(command._id);
}
}
}

View file

@ -0,0 +1,25 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{
struct CreateTextureCommand : IGALCommand
{
public CommandType CommandType => CommandType.CreateTexture;
private TableRef<ThreadedTexture> _texture;
private TextureCreateInfo _info;
private float _scale;
public void Set(TableRef<ThreadedTexture> texture, TextureCreateInfo info, float scale)
{
_texture = texture;
_info = info;
_scale = scale;
}
public static void Run(ref CreateTextureCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._texture.Get(threaded).Base = renderer.CreateTexture(command._info, command._scale);
}
}
}

View file

@ -0,0 +1,20 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{
struct GetCapabilitiesCommand : IGALCommand
{
public CommandType CommandType => CommandType.GetCapabilities;
private TableRef<ResultBox<Capabilities>> _result;
public void Set(TableRef<ResultBox<Capabilities>> result)
{
_result = result;
}
public static void Run(ref GetCapabilitiesCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._result.Get(threaded).Result = renderer.GetCapabilities();
}
}
}

View file

@ -0,0 +1,14 @@
using System;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{
struct PreFrameCommand : IGALCommand
{
public CommandType CommandType => CommandType.PreFrame;
public static void Run(ref PreFrameCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.PreFrame();
}
}
}

View file

@ -0,0 +1,30 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{
struct ReportCounterCommand : IGALCommand
{
public CommandType CommandType => CommandType.ReportCounter;
private TableRef<ThreadedCounterEvent> _event;
private CounterType _type;
private TableRef<EventHandler<ulong>> _resultHandler;
private bool _hostReserved;
public void Set(TableRef<ThreadedCounterEvent> evt, CounterType type, TableRef<EventHandler<ulong>> resultHandler, bool hostReserved)
{
_event = evt;
_type = type;
_resultHandler = resultHandler;
_hostReserved = hostReserved;
}
public static void Run(ref ReportCounterCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedCounterEvent evt = command._event.Get(threaded);
evt.Create(renderer, command._type, command._resultHandler.Get(threaded), command._hostReserved);
}
}
}

View file

@ -0,0 +1,18 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{
struct ResetCounterCommand : IGALCommand
{
public CommandType CommandType => CommandType.ResetCounter;
private CounterType _type;
public void Set(CounterType type)
{
_type = type;
}
public static void Run(ref ResetCounterCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.ResetCounter(command._type);
}
}
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{
struct UpdateCountersCommand : IGALCommand
{
public CommandType CommandType => CommandType.UpdateCounters;
public static void Run(ref UpdateCountersCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.UpdateCounters();
}
}
}

View file

@ -0,0 +1,21 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Sampler
{
struct SamplerDisposeCommand : IGALCommand
{
public CommandType CommandType => CommandType.SamplerDispose;
private TableRef<ThreadedSampler> _sampler;
public void Set(TableRef<ThreadedSampler> sampler)
{
_sampler = sampler;
}
public static void Run(ref SamplerDisposeCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._sampler.Get(threaded).Base.Dispose();
}
}
}

View file

@ -0,0 +1,22 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetAlphaTestCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetAlphaTest;
private bool _enable;
private float _reference;
private CompareOp _op;
public void Set(bool enable, float reference, CompareOp op)
{
_enable = enable;
_reference = reference;
_op = op;
}
public static void Run(ref SetAlphaTestCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetAlphaTest(command._enable, command._reference, command._op);
}
}
}

View file

@ -0,0 +1,20 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetBlendStateCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetBlendState;
private int _index;
private BlendDescriptor _blend;
public void Set(int index, BlendDescriptor blend)
{
_index = index;
_blend = blend;
}
public static void Run(ref SetBlendStateCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetBlendState(command._index, command._blend);
}
}
}

View file

@ -0,0 +1,24 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetDepthBiasCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetDepthBias;
private PolygonModeMask _enables;
private float _factor;
private float _units;
private float _clamp;
public void Set(PolygonModeMask enables, float factor, float units, float clamp)
{
_enables = enables;
_factor = factor;
_units = units;
_clamp = clamp;
}
public static void Run(ref SetDepthBiasCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetDepthBias(command._enables, command._factor, command._units, command._clamp);
}
}
}

View file

@ -0,0 +1,18 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetDepthClampCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetDepthClamp;
private bool _clamp;
public void Set(bool clamp)
{
_clamp = clamp;
}
public static void Run(ref SetDepthClampCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetDepthClamp(command._clamp);
}
}
}

View file

@ -0,0 +1,18 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetDepthModeCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetDepthMode;
private DepthMode _mode;
public void Set(DepthMode mode)
{
_mode = mode;
}
public static void Run(ref SetDepthModeCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetDepthMode(command._mode);
}
}
}

View file

@ -0,0 +1,18 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetDepthTestCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetDepthTest;
private DepthTestDescriptor _depthTest;
public void Set(DepthTestDescriptor depthTest)
{
_depthTest = depthTest;
}
public static void Run(ref SetDepthTestCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetDepthTest(command._depthTest);
}
}
}

View file

@ -0,0 +1,20 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetFaceCullingCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetFaceCulling;
private bool _enable;
private Face _face;
public void Set(bool enable, Face face)
{
_enable = enable;
_face = face;
}
public static void Run(ref SetFaceCullingCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetFaceCulling(command._enable, command._face);
}
}
}

View file

@ -0,0 +1,18 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetFrontFaceCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetFrontFace;
private FrontFace _frontFace;
public void Set(FrontFace frontFace)
{
_frontFace = frontFace;
}
public static void Run(ref SetFrontFaceCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetFrontFace(command._frontFace);
}
}
}

View file

@ -0,0 +1,25 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetImageCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetImage;
private int _binding;
private TableRef<ITexture> _texture;
private Format _imageFormat;
public void Set(int binding, TableRef<ITexture> texture, Format imageFormat)
{
_binding = binding;
_texture = texture;
_imageFormat = imageFormat;
}
public static void Run(ref SetImageCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetImage(command._binding, command._texture.GetAs<ThreadedTexture>(threaded)?.Base, command._imageFormat);
}
}
}

View file

@ -0,0 +1,21 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetIndexBufferCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetIndexBuffer;
private BufferRange _buffer;
private IndexType _type;
public void Set(BufferRange buffer, IndexType type)
{
_buffer = buffer;
_type = type;
}
public static void Run(ref SetIndexBufferCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
BufferRange range = threaded.Buffers.MapBufferRange(command._buffer);
renderer.Pipeline.SetIndexBuffer(range, command._type);
}
}
}

View file

@ -0,0 +1,20 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetLineParametersCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetLineParameters;
private float _width;
private bool _smooth;
public void Set(float width, bool smooth)
{
_width = width;
_smooth = smooth;
}
public static void Run(ref SetLineParametersCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetLineParameters(command._width, command._smooth);
}
}
}

View file

@ -0,0 +1,20 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetLogicOpStateCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetLogicOpState;
private bool _enable;
private LogicalOp _op;
public void Set(bool enable, LogicalOp op)
{
_enable = enable;
_op = op;
}
public static void Run(ref SetLogicOpStateCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetLogicOpState(command._enable, command._op);
}
}
}

View file

@ -0,0 +1,24 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetPointParametersCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetPointParameters;
private float _size;
private bool _isProgramPointSize;
private bool _enablePointSprite;
private Origin _origin;
public void Set(float size, bool isProgramPointSize, bool enablePointSprite, Origin origin)
{
_size = size;
_isProgramPointSize = isProgramPointSize;
_enablePointSprite = enablePointSprite;
_origin = origin;
}
public static void Run(ref SetPointParametersCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetPointParameters(command._size, command._isProgramPointSize, command._enablePointSprite, command._origin);
}
}
}

View file

@ -0,0 +1,20 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetPrimitiveRestartCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetPrimitiveRestart;
private bool _enable;
private int _index;
public void Set(bool enable, int index)
{
_enable = enable;
_index = index;
}
public static void Run(ref SetPrimitiveRestartCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetPrimitiveRestart(command._enable, command._index);
}
}
}

View file

@ -0,0 +1,18 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetPrimitiveTopologyCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetPrimitiveTopology;
private PrimitiveTopology _topology;
public void Set(PrimitiveTopology topology)
{
_topology = topology;
}
public static void Run(ref SetPrimitiveTopologyCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetPrimitiveTopology(command._topology);
}
}
}

View file

@ -0,0 +1,25 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetProgramCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetProgram;
private TableRef<IProgram> _program;
public void Set(TableRef<IProgram> program)
{
_program = program;
}
public static void Run(ref SetProgramCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedProgram program = command._program.GetAs<ThreadedProgram>(threaded);
threaded.Programs.WaitForProgram(program);
renderer.Pipeline.SetProgram(program.Base);
}
}
}

View file

@ -0,0 +1,18 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetRasterizerDiscardCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetRasterizerDiscard;
private bool _discard;
public void Set(bool discard)
{
_discard = discard;
}
public static void Run(ref SetRasterizerDiscardCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetRasterizerDiscard(command._discard);
}
}
}

View file

@ -0,0 +1,23 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using System;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetRenderTargetColorMasksCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetRenderTargetColorMasks;
private SpanRef<uint> _componentMask;
public void Set(SpanRef<uint> componentMask)
{
_componentMask = componentMask;
}
public static void Run(ref SetRenderTargetColorMasksCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ReadOnlySpan<uint> componentMask = command._componentMask.Get(threaded);
renderer.Pipeline.SetRenderTargetColorMasks(componentMask);
command._componentMask.Dispose(threaded);
}
}
}

View file

@ -0,0 +1,18 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetRenderTargetScaleCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetRenderTargetScale;
private float _scale;
public void Set(float scale)
{
_scale = scale;
}
public static void Run(ref SetRenderTargetScaleCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetRenderTargetScale(command._scale);
}
}
}

View file

@ -0,0 +1,24 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System.Linq;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetRenderTargetsCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetRenderTargets;
private TableRef<ITexture[]> _colors;
private TableRef<ITexture> _depthStencil;
public void Set(TableRef<ITexture[]> colors, TableRef<ITexture> depthStencil)
{
_colors = colors;
_depthStencil = depthStencil;
}
public static void Run(ref SetRenderTargetsCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetRenderTargets(command._colors.Get(threaded).Select(color => ((ThreadedTexture)color)?.Base).ToArray(), command._depthStencil.GetAs<ThreadedTexture>(threaded)?.Base);
}
}
}

View file

@ -0,0 +1,23 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetSamplerCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetSampler;
private int _index;
private TableRef<ISampler> _sampler;
public void Set(int index, TableRef<ISampler> sampler)
{
_index = index;
_sampler = sampler;
}
public static void Run(ref SetSamplerCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetSampler(command._index, command._sampler.GetAs<ThreadedSampler>(threaded)?.Base);
}
}
}

View file

@ -0,0 +1,28 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetScissorCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetScissor;
private int _index;
private bool _enable;
private int _x;
private int _y;
private int _width;
private int _height;
public void Set(int index, bool enable, int x, int y, int width, int height)
{
_index = index;
_enable = enable;
_x = x;
_y = y;
_width = width;
_height = height;
}
public static void Run(ref SetScissorCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetScissor(command._index, command._enable, command._x, command._y, command._width, command._height);
}
}
}

View file

@ -0,0 +1,18 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetStencilTestCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetStencilTest;
private StencilTestDescriptor _stencilTest;
public void Set(StencilTestDescriptor stencilTest)
{
_stencilTest = stencilTest;
}
public static void Run(ref SetStencilTestCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetStencilTest(command._stencilTest);
}
}
}

View file

@ -0,0 +1,25 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using System;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetStorageBuffersCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetStorageBuffers;
private int _first;
private SpanRef<BufferRange> _buffers;
public void Set(int first, SpanRef<BufferRange> buffers)
{
_first = first;
_buffers = buffers;
}
public static void Run(ref SetStorageBuffersCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
Span<BufferRange> buffers = command._buffers.Get(threaded);
renderer.Pipeline.SetStorageBuffers(command._first, threaded.Buffers.MapBufferRanges(buffers));
command._buffers.Dispose(threaded);
}
}
}

View file

@ -0,0 +1,23 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetTextureCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetTexture;
private int _binding;
private TableRef<ITexture> _texture;
public void Set(int binding, TableRef<ITexture> texture)
{
_binding = binding;
_texture = texture;
}
public static void Run(ref SetTextureCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetTexture(command._binding, command._texture.GetAs<ThreadedTexture>(threaded)?.Base);
}
}
}

View file

@ -0,0 +1,23 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using System;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetTransformFeedbackBuffersCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetTransformFeedbackBuffers;
private SpanRef<BufferRange> _buffers;
public void Set(SpanRef<BufferRange> buffers)
{
_buffers = buffers;
}
public static void Run(ref SetTransformFeedbackBuffersCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
Span<BufferRange> buffers = command._buffers.Get(threaded);
renderer.Pipeline.SetTransformFeedbackBuffers(threaded.Buffers.MapBufferRanges(buffers));
command._buffers.Dispose(threaded);
}
}
}

View file

@ -0,0 +1,25 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using System;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetUniformBuffersCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetUniformBuffers;
private int _first;
private SpanRef<BufferRange> _buffers;
public void Set(int first, SpanRef<BufferRange> buffers)
{
_first = first;
_buffers = buffers;
}
public static void Run(ref SetUniformBuffersCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
Span<BufferRange> buffers = command._buffers.Get(threaded);
renderer.Pipeline.SetUniformBuffers(command._first, threaded.Buffers.MapBufferRanges(buffers));
command._buffers.Dispose(threaded);
}
}
}

View file

@ -0,0 +1,20 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetUserClipDistanceCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetUserClipDistance;
private int _index;
private bool _enableClip;
public void Set(int index, bool enableClip)
{
_index = index;
_enableClip = enableClip;
}
public static void Run(ref SetUserClipDistanceCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetUserClipDistance(command._index, command._enableClip);
}
}
}

View file

@ -0,0 +1,23 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using System;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetVertexAttribsCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetVertexAttribs;
private SpanRef<VertexAttribDescriptor> _vertexAttribs;
public void Set(SpanRef<VertexAttribDescriptor> vertexAttribs)
{
_vertexAttribs = vertexAttribs;
}
public static void Run(ref SetVertexAttribsCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ReadOnlySpan<VertexAttribDescriptor> vertexAttribs = command._vertexAttribs.Get(threaded);
renderer.Pipeline.SetVertexAttribs(vertexAttribs);
command._vertexAttribs.Dispose(threaded);
}
}
}

View file

@ -0,0 +1,24 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using System;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetVertexBuffersCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetVertexBuffers;
private SpanRef<VertexBufferDescriptor> _vertexBuffers;
public void Set(SpanRef<VertexBufferDescriptor> vertexBuffers)
{
_vertexBuffers = vertexBuffers;
}
public static void Run(ref SetVertexBuffersCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
Span<VertexBufferDescriptor> vertexBuffers = command._vertexBuffers.Get(threaded);
renderer.Pipeline.SetVertexBuffers(threaded.Buffers.MapBufferRanges(vertexBuffers));
command._vertexBuffers.Dispose(threaded);
}
}
}

View file

@ -0,0 +1,26 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using System;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetViewportsCommand : IGALCommand
{
public CommandType CommandType => CommandType.SetViewports;
private int _first;
private SpanRef<Viewport> _viewports;
public void Set(int first, SpanRef<Viewport> viewports)
{
_first = first;
_viewports = viewports;
}
public static void Run(ref SetViewportsCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ReadOnlySpan<Viewport> viewports = command._viewports.Get(threaded);
renderer.Pipeline.SetViewports(command._first, viewports);
command._viewports.Dispose(threaded);
}
}
}

View file

@ -0,0 +1,21 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Shader
{
struct ShaderDisposeCommand : IGALCommand
{
public CommandType CommandType => CommandType.ShaderDispose;
private TableRef<ThreadedShader> _shader;
public void Set(TableRef<ThreadedShader> shader)
{
_shader = shader;
}
public static void Run(ref ShaderDisposeCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._shader.Get(threaded).Base.Dispose();
}
}
}

View file

@ -0,0 +1,28 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{
struct TextureCopyToCommand : IGALCommand
{
public CommandType CommandType => CommandType.TextureCopyTo;
private TableRef<ThreadedTexture> _texture;
private TableRef<ThreadedTexture> _destination;
private int _firstLayer;
private int _firstLevel;
public void Set(TableRef<ThreadedTexture> texture, TableRef<ThreadedTexture> destination, int firstLayer, int firstLevel)
{
_texture = texture;
_destination = destination;
_firstLayer = firstLayer;
_firstLevel = firstLevel;
}
public static void Run(ref TextureCopyToCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedTexture source = command._texture.Get(threaded);
source.Base.CopyTo(command._destination.Get(threaded).Base, command._firstLayer, command._firstLevel);
}
}
}

View file

@ -0,0 +1,30 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{
struct TextureCopyToScaledCommand : IGALCommand
{
public CommandType CommandType => CommandType.TextureCopyToScaled;
private TableRef<ThreadedTexture> _texture;
private TableRef<ThreadedTexture> _destination;
private Extents2D _srcRegion;
private Extents2D _dstRegion;
private bool _linearFilter;
public void Set(TableRef<ThreadedTexture> texture, TableRef<ThreadedTexture> destination, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter)
{
_texture = texture;
_destination = destination;
_srcRegion = srcRegion;
_dstRegion = dstRegion;
_linearFilter = linearFilter;
}
public static void Run(ref TextureCopyToScaledCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedTexture source = command._texture.Get(threaded);
source.Base.CopyTo(command._destination.Get(threaded).Base, command._srcRegion, command._dstRegion, command._linearFilter);
}
}
}

View file

@ -0,0 +1,32 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{
struct TextureCopyToSliceCommand : IGALCommand
{
public CommandType CommandType => CommandType.TextureCopyToSlice;
private TableRef<ThreadedTexture> _texture;
private TableRef<ThreadedTexture> _destination;
private int _srcLayer;
private int _dstLayer;
private int _srcLevel;
private int _dstLevel;
public void Set(TableRef<ThreadedTexture> texture, TableRef<ThreadedTexture> destination, int srcLayer, int dstLayer, int srcLevel, int dstLevel)
{
_texture = texture;
_destination = destination;
_srcLayer = srcLayer;
_dstLayer = dstLayer;
_srcLevel = srcLevel;
_dstLevel = dstLevel;
}
public static void Run(ref TextureCopyToSliceCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedTexture source = command._texture.Get(threaded);
source.Base.CopyTo(command._destination.Get(threaded).Base, command._srcLayer, command._dstLayer, command._srcLevel, command._dstLevel);
}
}
}

View file

@ -0,0 +1,30 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{
struct TextureCreateViewCommand : IGALCommand
{
public CommandType CommandType => CommandType.TextureCreateView;
private TableRef<ThreadedTexture> _texture;
private TableRef<ThreadedTexture> _destination;
private TextureCreateInfo _info;
private int _firstLayer;
private int _firstLevel;
public void Set(TableRef<ThreadedTexture> texture, TableRef<ThreadedTexture> destination, TextureCreateInfo info, int firstLayer, int firstLevel)
{
_texture = texture;
_destination = destination;
_info = info;
_firstLayer = firstLayer;
_firstLevel = firstLevel;
}
public static void Run(ref TextureCreateViewCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedTexture source = command._texture.Get(threaded);
command._destination.Get(threaded).Base = source.Base.CreateView(command._info, command._firstLayer, command._firstLevel);
}
}
}

View file

@ -0,0 +1,26 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{
struct TextureGetDataCommand : IGALCommand
{
public CommandType CommandType => CommandType.TextureGetData;
private TableRef<ThreadedTexture> _texture;
private TableRef<ResultBox<PinnedSpan<byte>>> _result;
public void Set(TableRef<ThreadedTexture> texture, TableRef<ResultBox<PinnedSpan<byte>>> result)
{
_texture = texture;
_result = result;
}
public static void Run(ref TextureGetDataCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ReadOnlySpan<byte> result = command._texture.Get(threaded).Base.GetData();
command._result.Get(threaded).Result = new PinnedSpan<byte>(result);
}
}
}

View file

@ -0,0 +1,21 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{
struct TextureReleaseCommand : IGALCommand
{
public CommandType CommandType => CommandType.TextureRelease;
private TableRef<ThreadedTexture> _texture;
public void Set(TableRef<ThreadedTexture> texture)
{
_texture = texture;
}
public static void Run(ref TextureReleaseCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._texture.Get(threaded).Base.Release();
}
}
}

View file

@ -0,0 +1,25 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{
struct TextureSetDataCommand : IGALCommand
{
public CommandType CommandType => CommandType.TextureSetData;
private TableRef<ThreadedTexture> _texture;
private TableRef<byte[]> _data;
public void Set(TableRef<ThreadedTexture> texture, TableRef<byte[]> data)
{
_texture = texture;
_data = data;
}
public static void Run(ref TextureSetDataCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedTexture texture = command._texture.Get(threaded);
texture.Base.SetData(new ReadOnlySpan<byte>(command._data.Get(threaded)));
}
}
}

View file

@ -0,0 +1,29 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{
struct TextureSetDataSliceCommand : IGALCommand
{
public CommandType CommandType => CommandType.TextureSetDataSlice;
private TableRef<ThreadedTexture> _texture;
private TableRef<byte[]> _data;
private int _layer;
private int _level;
public void Set(TableRef<ThreadedTexture> texture, TableRef<byte[]> data, int layer, int level)
{
_texture = texture;
_data = data;
_layer = layer;
_level = level;
}
public static void Run(ref TextureSetDataSliceCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedTexture texture = command._texture.Get(threaded);
texture.Base.SetData(new ReadOnlySpan<byte>(command._data.Get(threaded)), command._layer, command._level);
}
}
}

View file

@ -0,0 +1,23 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{
struct TextureSetStorageCommand : IGALCommand
{
public CommandType CommandType => CommandType.TextureSetStorage;
private TableRef<ThreadedTexture> _texture;
private BufferRange _storage;
public void Set(TableRef<ThreadedTexture> texture, BufferRange storage)
{
_texture = texture;
_storage = storage;
}
public static void Run(ref TextureSetStorageCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._texture.Get(threaded).Base.SetStorage(threaded.Buffers.MapBufferRange(command._storage));
}
}
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct TextureBarrierCommand : IGALCommand
{
public CommandType CommandType => CommandType.TextureBarrier;
public static void Run(ref TextureBarrierCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.TextureBarrier();
}
}
}

View file

@ -0,0 +1,12 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct TextureBarrierTiledCommand : IGALCommand
{
public CommandType CommandType => CommandType.TextureBarrierTiled;
public static void Run(ref TextureBarrierTiledCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.TextureBarrierTiled();
}
}
}

View file

@ -0,0 +1,25 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct TryHostConditionalRenderingCommand : IGALCommand
{
public CommandType CommandType => CommandType.TryHostConditionalRendering;
private TableRef<ThreadedCounterEvent> _value;
private ulong _compare;
private bool _isEqual;
public void Set(TableRef<ThreadedCounterEvent> value, ulong compare, bool isEqual)
{
_value = value;
_compare = compare;
_isEqual = isEqual;
}
public static void Run(ref TryHostConditionalRenderingCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.TryHostConditionalRendering(command._value.Get(threaded)?.Base, command._compare, command._isEqual);
}
}
}

View file

@ -0,0 +1,25 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct TryHostConditionalRenderingFlushCommand : IGALCommand
{
public CommandType CommandType => CommandType.TryHostConditionalRenderingFlush;
private TableRef<ThreadedCounterEvent> _value;
private TableRef<ThreadedCounterEvent> _compare;
private bool _isEqual;
public void Set(TableRef<ThreadedCounterEvent> value, TableRef<ThreadedCounterEvent> compare, bool isEqual)
{
_value = value;
_compare = compare;
_isEqual = isEqual;
}
public static void Run(ref TryHostConditionalRenderingFlushCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.TryHostConditionalRendering(command._value.Get(threaded)?.Base, command._compare.Get(threaded)?.Base, command._isEqual);
}
}
}

View file

@ -0,0 +1,28 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.Shader;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct UpdateRenderScaleCommand : IGALCommand
{
public CommandType CommandType => CommandType.UpdateRenderScale;
private ShaderStage _stage;
private SpanRef<float> _scales;
private int _textureCount;
private int _imageCount;
public void Set(ShaderStage stage, SpanRef<float> scales, int textureCount, int imageCount)
{
_stage = stage;
_scales = scales;
_textureCount = textureCount;
_imageCount = imageCount;
}
public static void Run(ref UpdateRenderScaleCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.UpdateRenderScale(command._stage, command._scales.Get(threaded), command._textureCount, command._imageCount);
command._scales.Dispose(threaded);
}
}
}

View file

@ -0,0 +1,27 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Window
{
struct WindowPresentCommand : IGALCommand
{
public CommandType CommandType => CommandType.WindowPresent;
private TableRef<ThreadedTexture> _texture;
private ImageCrop _crop;
private TableRef<Action> _swapBuffersCallback;
public void Set(TableRef<ThreadedTexture> texture, ImageCrop crop, TableRef<Action> swapBuffersCallback)
{
_texture = texture;
_crop = crop;
_swapBuffersCallback = swapBuffersCallback;
}
public static void Run(ref WindowPresentCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
threaded.SignalFrame();
renderer.Window.Present(command._texture.Get(threaded)?.Base, command._crop, command._swapBuffersCallback.Get(threaded));
}
}
}

View file

@ -0,0 +1,89 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
namespace Ryujinx.Graphics.GAL.Multithreading.Model
{
/// <summary>
/// A memory pool for passing through Span<T> resources with one producer and consumer.
/// Data is copied on creation to part of the pool, then that region is reserved until it is disposed by the consumer.
/// Similar to the command queue, this pool assumes that data is created and disposed in the same order.
/// </summary>
class CircularSpanPool
{
private ThreadedRenderer _renderer;
private byte[] _pool;
private int _size;
private int _producerPtr;
private int _producerSkipPosition = -1;
private int _consumerPtr;
public CircularSpanPool(ThreadedRenderer renderer, int size)
{
_renderer = renderer;
_size = size;
_pool = new byte[size];
}
public SpanRef<T> Insert<T>(ReadOnlySpan<T> data) where T : unmanaged
{
int size = data.Length * Unsafe.SizeOf<T>();
// Wrapping aware circular queue.
// If there's no space at the end of the pool for this span, we can't fragment it.
// So just loop back around to the start. Remember the last skipped position.
bool wraparound = _producerPtr + size >= _size;
int index = wraparound ? 0 : _producerPtr;
// _consumerPtr is from another thread, and we're taking it without a lock, so treat this as a snapshot in the past.
// We know that it will always be before or equal to the producer pointer, and it cannot pass it.
// This is enough to reason about if there is space in the queue for the data, even if we're checking against an outdated value.
int consumer = _consumerPtr;
bool beforeConsumer = _producerPtr < consumer;
if (size > _size - 1 || (wraparound && beforeConsumer) || ((index < consumer || wraparound) && index + size >= consumer))
{
// Just get an array in the following situations:
// - The data is too large to fit in the pool.
// - A wraparound would happen but the consumer would be covered by it.
// - The producer would catch up to the consumer as a result.
return new SpanRef<T>(_renderer, data.ToArray());
}
data.CopyTo(MemoryMarshal.Cast<byte, T>(new Span<byte>(_pool).Slice(index, size)));
if (wraparound)
{
_producerSkipPosition = _producerPtr;
}
_producerPtr = index + size;
return new SpanRef<T>(data.Length);
}
public Span<T> Get<T>(int length) where T : unmanaged
{
int size = length * Unsafe.SizeOf<T>();
if (_consumerPtr == Interlocked.CompareExchange(ref _producerSkipPosition, -1, _consumerPtr))
{
_consumerPtr = 0;
}
return MemoryMarshal.Cast<byte, T>(new Span<byte>(_pool).Slice(_consumerPtr, size));
}
public void Dispose<T>(int length) where T : unmanaged
{
int size = length * Unsafe.SizeOf<T>();
_consumerPtr = _consumerPtr + size;
}
}
}

View file

@ -0,0 +1,23 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.GAL.Multithreading.Model
{
unsafe struct PinnedSpan<T> where T : unmanaged
{
private void* _ptr;
private int _size;
public PinnedSpan(ReadOnlySpan<T> span)
{
_ptr = Unsafe.AsPointer(ref MemoryMarshal.GetReference(span));
_size = span.Length;
}
public ReadOnlySpan<T> Get()
{
return new ReadOnlySpan<T>(_ptr, _size * Unsafe.SizeOf<T>());
}
}
}

View file

@ -0,0 +1,7 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Model
{
public class ResultBox<T>
{
public T Result;
}
}

View file

@ -0,0 +1,39 @@
using System;
namespace Ryujinx.Graphics.GAL.Multithreading.Model
{
struct SpanRef<T> where T : unmanaged
{
private int _packedLengthId;
public SpanRef(ThreadedRenderer renderer, T[] data)
{
_packedLengthId = -(renderer.AddTableRef(data) + 1);
}
public SpanRef(int length)
{
_packedLengthId = length;
}
public Span<T> Get(ThreadedRenderer renderer)
{
if (_packedLengthId >= 0)
{
return renderer.SpanPool.Get<T>(_packedLengthId);
}
else
{
return new Span<T>((T[])renderer.RemoveTableRef(-(_packedLengthId + 1)));
}
}
public void Dispose(ThreadedRenderer renderer)
{
if (_packedLengthId > 0)
{
renderer.SpanPool.Dispose<T>(_packedLengthId);
}
}
}
}

View file

@ -0,0 +1,22 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Model
{
struct TableRef<T>
{
private int _index;
public TableRef(ThreadedRenderer renderer, T reference)
{
_index = renderer.AddTableRef(reference);
}
public T Get(ThreadedRenderer renderer)
{
return (T)renderer.RemoveTableRef(_index);
}
public T2 GetAs<T2>(ThreadedRenderer renderer) where T2 : T
{
return (T2)renderer.RemoveTableRef(_index);
}
}
}

View file

@ -0,0 +1,107 @@
using Ryujinx.Graphics.GAL.Multithreading.Resources.Programs;
using System;
using System.Collections.Generic;
using System.Threading;
namespace Ryujinx.Graphics.GAL.Multithreading.Resources
{
/// <summary>
/// A structure handling multithreaded compilation for programs.
/// </summary>
class ProgramQueue
{
private const int MaxConcurrentCompilations = 8;
private IRenderer _renderer;
private Queue<IProgramRequest> _toCompile;
private List<ThreadedProgram> _inProgress;
public ProgramQueue(IRenderer renderer)
{
_renderer = renderer;
_toCompile = new Queue<IProgramRequest>();
_inProgress = new List<ThreadedProgram>();
}
public void Add(IProgramRequest request)
{
lock (_toCompile)
{
_toCompile.Enqueue(request);
}
}
public void ProcessQueue()
{
for (int i = 0; i < _inProgress.Count; i++)
{
ThreadedProgram program = _inProgress[i];
ProgramLinkStatus status = program.Base.CheckProgramLink(false);
if (status != ProgramLinkStatus.Incomplete)
{
program.Compiled = true;
_inProgress.RemoveAt(i--);
}
}
int freeSpace = MaxConcurrentCompilations - _inProgress.Count;
for (int i = 0; i < freeSpace; i++)
{
// Begin compilation of some programs in the compile queue.
IProgramRequest program;
lock (_toCompile)
{
if (!_toCompile.TryDequeue(out program))
{
break;
}
}
if (program.Threaded.Base != null)
{
ProgramLinkStatus status = program.Threaded.Base.CheckProgramLink(false);
if (status != ProgramLinkStatus.Incomplete)
{
// This program is already compiled. Keep going through the queue.
program.Threaded.Compiled = true;
i--;
continue;
}
}
else
{
program.Threaded.Base = program.Create(_renderer);
}
_inProgress.Add(program.Threaded);
}
}
/// <summary>
/// Process the queue until the given program has finished compiling.
/// This will begin compilation of other programs on the queue as well.
/// </summary>
/// <param name="program">The program to wait for</param>
public void WaitForProgram(ThreadedProgram program)
{
Span<SpinWait> spinWait = stackalloc SpinWait[1];
while (!program.Compiled)
{
ProcessQueue();
if (!program.Compiled)
{
spinWait[0].SpinOnce(-1);
}
}
}
}
}

View file

@ -0,0 +1,21 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs
{
class BinaryProgramRequest : IProgramRequest
{
public ThreadedProgram Threaded { get; set; }
private byte[] _data;
public BinaryProgramRequest(ThreadedProgram program, byte[] data)
{
Threaded = program;
_data = data;
}
public IProgram Create(IRenderer renderer)
{
return renderer.LoadProgramBinary(_data);
}
}
}

View file

@ -0,0 +1,8 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs
{
interface IProgramRequest
{
ThreadedProgram Threaded { get; set; }
IProgram Create(IRenderer renderer);
}
}

Some files were not shown because too many files have changed in this diff Show more