Separate GPU engines (part 2/2) (#2440)
* 3D engine now uses DeviceState too, plus new state modification tracking * Remove old methods code * Remove GpuState and friends * Optimize DeviceState, force inline some functions * This change was not supposed to go in * Proper channel initialization * Optimize state read/write methods even more * Fix debug build * Do not dirty state if the write is redundant * The YControl register should dirty either the viewport or front face state too, to update the host origin * Avoid redundant vertex buffer updates * Move state and get rid of the Ryujinx.Graphics.Gpu.State namespace * Comments and nits * Fix rebase * PR feedback * Move changed = false to improve codegen * PR feedback * Carry RyuJIT a bit more
This commit is contained in:
parent
b5190f1681
commit
40b21cc3c4
111 changed files with 5262 additions and 4020 deletions
|
@ -1,9 +1,10 @@
|
|||
using Ryujinx.Graphics.Device;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Engine.InlineToMemory;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Threed;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
using Ryujinx.Graphics.Gpu.Shader;
|
||||
using Ryujinx.Graphics.Gpu.State;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -14,27 +15,34 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
|||
/// <summary>
|
||||
/// Represents a compute engine class.
|
||||
/// </summary>
|
||||
class ComputeClass : InlineToMemoryClass, IDeviceState
|
||||
class ComputeClass : IDeviceState
|
||||
{
|
||||
private readonly GpuContext _context;
|
||||
private readonly GpuChannel _channel;
|
||||
private readonly ThreedClass _3dEngine;
|
||||
private readonly DeviceState<ComputeClassState> _state;
|
||||
|
||||
private readonly InlineToMemoryClass _i2mClass;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the compute engine class.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context</param>
|
||||
/// <param name="channel">GPU channel</param>
|
||||
public ComputeClass(GpuContext context, GpuChannel channel) : base(context, channel, false)
|
||||
/// <param name="threedEngine">3D engine</param>
|
||||
public ComputeClass(GpuContext context, GpuChannel channel, ThreedClass threedEngine)
|
||||
{
|
||||
_context = context;
|
||||
_channel = channel;
|
||||
_3dEngine = threedEngine;
|
||||
_state = new DeviceState<ComputeClassState>(new Dictionary<string, RwCallback>
|
||||
{
|
||||
{ nameof(ComputeClassState.LaunchDma), new RwCallback(LaunchDma, null) },
|
||||
{ nameof(ComputeClassState.LoadInlineData), new RwCallback(LoadInlineData, null) },
|
||||
{ nameof(ComputeClassState.SendSignalingPcasB), new RwCallback(SendSignalingPcasB, null) }
|
||||
});
|
||||
|
||||
_i2mClass = new InlineToMemoryClass(context, channel, initializeState: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -42,22 +50,31 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
|||
/// </summary>
|
||||
/// <param name="offset">Register byte offset</param>
|
||||
/// <returns>Data at the specified offset</returns>
|
||||
public override int Read(int offset) => _state.Read(offset);
|
||||
public int Read(int offset) => _state.Read(offset);
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to the class registers.
|
||||
/// </summary>
|
||||
/// <param name="offset">Register byte offset</param>
|
||||
/// <param name="data">Data to be written</param>
|
||||
public override void Write(int offset, int data) => _state.Write(offset, data);
|
||||
public void Write(int offset, int data) => _state.Write(offset, data);
|
||||
|
||||
/// <summary>
|
||||
/// Launches the Inline-to-Memory DMA copy operation.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
protected override void LaunchDma(int argument)
|
||||
private void LaunchDma(int argument)
|
||||
{
|
||||
LaunchDma(ref Unsafe.As<ComputeClassState, InlineToMemoryClassState>(ref _state.State), argument);
|
||||
_i2mClass.LaunchDma(ref Unsafe.As<ComputeClassState, InlineToMemoryClassState>(ref _state.State), argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes a word of data to the Inline-to-Memory engine.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void LoadInlineData(int argument)
|
||||
{
|
||||
_i2mClass.LoadInlineData(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -68,7 +85,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
|||
{
|
||||
var memoryManager = _channel.MemoryManager;
|
||||
|
||||
_context.Methods.FlushUboDirty(memoryManager);
|
||||
_3dEngine.FlushUboDirty();
|
||||
|
||||
uint qmdAddress = _state.State.SendPcasA;
|
||||
|
||||
|
@ -102,7 +119,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
|||
texturePoolGpuVa,
|
||||
_state.State.SetTexHeaderPoolCMaximumIndex,
|
||||
_state.State.SetBindlessTextureConstantBufferSlotSelect,
|
||||
false);
|
||||
false,
|
||||
PrimitiveTopology.Points);
|
||||
|
||||
ShaderBundle cs = memoryManager.Physical.ShaderCache.GetComputeShader(
|
||||
_channel,
|
||||
|
@ -207,7 +225,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
|
|||
|
||||
_context.Renderer.Pipeline.DispatchCompute(qmd.CtaRasterWidth, qmd.CtaRasterHeight, qmd.CtaRasterDepth);
|
||||
|
||||
_context.Methods.ForceShaderUpdate();
|
||||
_3dEngine.ForceShaderUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Ryujinx.Graphics.Gpu.State;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
{
|
||||
/// <summary>
|
||||
/// Conditional rendering enable.
|
||||
/// </summary>
|
||||
enum ConditionalRenderEnabled
|
||||
{
|
||||
False,
|
||||
|
|
95
Ryujinx.Graphics.Gpu/Engine/DeviceStateWithShadow.cs
Normal file
95
Ryujinx.Graphics.Gpu/Engine/DeviceStateWithShadow.cs
Normal file
|
@ -0,0 +1,95 @@
|
|||
using Ryujinx.Graphics.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
{
|
||||
/// <summary>
|
||||
/// State interface with a shadow memory control register.
|
||||
/// </summary>
|
||||
interface IShadowState
|
||||
{
|
||||
/// <summary>
|
||||
/// MME shadow ram control mode.
|
||||
/// </summary>
|
||||
SetMmeShadowRamControlMode SetMmeShadowRamControlMode { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a device's state, with a additional shadow state.
|
||||
/// </summary>
|
||||
/// <typeparam name="TState">Type of the state</typeparam>
|
||||
class DeviceStateWithShadow<TState> : IDeviceState where TState : unmanaged, IShadowState
|
||||
{
|
||||
private readonly DeviceState<TState> _state;
|
||||
private readonly DeviceState<TState> _shadowState;
|
||||
|
||||
/// <summary>
|
||||
/// Current device state.
|
||||
/// </summary>
|
||||
public ref TState State => ref _state.State;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the device state, with shadow state.
|
||||
/// </summary>
|
||||
/// <param name="callbacks">Optional that will be called if a register specified by name is read or written</param>
|
||||
/// <param name="debugLogCallback">Optional callback to be used for debug log messages</param>
|
||||
public DeviceStateWithShadow(IReadOnlyDictionary<string, RwCallback> callbacks = null, Action<string> debugLogCallback = null)
|
||||
{
|
||||
_state = new DeviceState<TState>(callbacks, debugLogCallback);
|
||||
_shadowState = new DeviceState<TState>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a value from a register.
|
||||
/// </summary>
|
||||
/// <param name="offset">Register offset in bytes</param>
|
||||
/// <returns>Value stored on the register</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int Read(int offset)
|
||||
{
|
||||
return _state.Read(offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a value to a register.
|
||||
/// </summary>
|
||||
/// <param name="offset">Register offset in bytes</param>
|
||||
/// <param name="value">Value to be written</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Write(int offset, int value)
|
||||
{
|
||||
WriteWithRedundancyCheck(offset, value, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a value to a register, returning a value indicating if <paramref name="value"/>
|
||||
/// is different from the current value on the register.
|
||||
/// </summary>
|
||||
/// <param name="offset">Register offset in bytes</param>
|
||||
/// <param name="value">Value to be written</param>
|
||||
/// <param name="changed">True if the value was changed, false otherwise</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteWithRedundancyCheck(int offset, int value, out bool changed)
|
||||
{
|
||||
var shadowRamControl = _state.State.SetMmeShadowRamControlMode;
|
||||
if (shadowRamControl == SetMmeShadowRamControlMode.MethodPassthrough || offset < 0x200)
|
||||
{
|
||||
_state.WriteWithRedundancyCheck(offset, value, out changed);
|
||||
}
|
||||
else if (shadowRamControl == SetMmeShadowRamControlMode.MethodTrack ||
|
||||
shadowRamControl == SetMmeShadowRamControlMode.MethodTrackWithFilter)
|
||||
{
|
||||
_shadowState.Write(offset, value);
|
||||
_state.WriteWithRedundancyCheck(offset, value, out changed);
|
||||
}
|
||||
else /* if (shadowRamControl == SetMmeShadowRamControlMode.MethodReplay) */
|
||||
{
|
||||
Debug.Assert(shadowRamControl == SetMmeShadowRamControlMode.MethodReplay);
|
||||
_state.WriteWithRedundancyCheck(offset, _shadowState.Read(offset), out changed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.Device;
|
||||
using Ryujinx.Graphics.Gpu.State;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Threed;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -16,6 +16,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||
{
|
||||
private readonly GpuContext _context;
|
||||
private readonly GpuChannel _channel;
|
||||
private readonly ThreedClass _3dEngine;
|
||||
private readonly DeviceState<DmaClassState> _state;
|
||||
|
||||
/// <summary>
|
||||
|
@ -35,10 +36,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||
/// </summary>
|
||||
/// <param name="context">GPU context</param>
|
||||
/// <param name="channel">GPU channel</param>
|
||||
public DmaClass(GpuContext context, GpuChannel channel)
|
||||
/// <param name="threedEngine">3D engine</param>
|
||||
public DmaClass(GpuContext context, GpuChannel channel, ThreedClass threedEngine)
|
||||
{
|
||||
_context = context;
|
||||
_channel = channel;
|
||||
_3dEngine = threedEngine;
|
||||
_state = new DeviceState<DmaClassState>(new Dictionary<string, RwCallback>
|
||||
{
|
||||
{ nameof(DmaClassState.LaunchDma), new RwCallback(LaunchDma, null) }
|
||||
|
@ -69,7 +72,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||
/// <param name="xCount">Number of pixels to be copied</param>
|
||||
/// <param name="yCount">Number of lines to be copied</param>
|
||||
/// <returns></returns>
|
||||
private static bool IsTextureCopyComplete(CopyBufferTexture tex, bool linear, int bpp, int stride, int xCount, int yCount)
|
||||
private static bool IsTextureCopyComplete(DmaTexture tex, bool linear, int bpp, int stride, int xCount, int yCount)
|
||||
{
|
||||
if (linear)
|
||||
{
|
||||
|
@ -116,7 +119,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||
int xCount = (int)_state.State.LineLengthIn;
|
||||
int yCount = (int)_state.State.LineCount;
|
||||
|
||||
_context.Methods.FlushUboDirty(memoryManager);
|
||||
_3dEngine.FlushUboDirty();
|
||||
|
||||
if (copy2D)
|
||||
{
|
||||
|
@ -125,8 +128,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
|||
int srcBpp = remap ? ((int)_state.State.SetRemapComponentsNumSrcComponents + 1) * componentSize : 1;
|
||||
int dstBpp = remap ? ((int)_state.State.SetRemapComponentsNumDstComponents + 1) * componentSize : 1;
|
||||
|
||||
var dst = Unsafe.As<uint, CopyBufferTexture>(ref _state.State.SetDstBlockSize);
|
||||
var src = Unsafe.As<uint, CopyBufferTexture>(ref _state.State.SetSrcBlockSize);
|
||||
var dst = Unsafe.As<uint, DmaTexture>(ref _state.State.SetDstBlockSize);
|
||||
var src = Unsafe.As<uint, DmaTexture>(ref _state.State.SetSrcBlockSize);
|
||||
|
||||
int srcStride = (int)_state.State.PitchIn;
|
||||
int dstStride = (int)_state.State.PitchOut;
|
||||
|
|
20
Ryujinx.Graphics.Gpu/Engine/Dma/DmaTexture.cs
Normal file
20
Ryujinx.Graphics.Gpu/Engine/Dma/DmaTexture.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
||||
{
|
||||
/// <summary>
|
||||
/// Buffer to texture copy parameters.
|
||||
/// </summary>
|
||||
struct DmaTexture
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public MemoryLayout MemoryLayout;
|
||||
public int Width;
|
||||
public int Height;
|
||||
public int Depth;
|
||||
public int RegionZ;
|
||||
public ushort RegionX;
|
||||
public ushort RegionY;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using Ryujinx.Graphics.Device;
|
||||
using Ryujinx.Graphics.Gpu.Engine.MME;
|
||||
using Ryujinx.Graphics.Gpu.State;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
@ -150,7 +149,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
|||
/// <param name="argument">Method call argument</param>
|
||||
public void WaitForIdle(int argument)
|
||||
{
|
||||
_context.Methods.PerformDeferredDraws();
|
||||
_parent.PerformDeferredDraws();
|
||||
_context.Renderer.Pipeline.Barrier();
|
||||
|
||||
_context.CreateHostSyncIfNeeded();
|
||||
|
@ -189,7 +188,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
|||
/// <param name="argument">Method call argument</param>
|
||||
public void SetMmeShadowRamControl(int argument)
|
||||
{
|
||||
_parent.SetShadowRamControl((ShadowRamControl)argument);
|
||||
_parent.SetShadowRamControl(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -217,7 +216,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
|||
/// </summary>
|
||||
/// <param name="index">Index of the macro</param>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
public void CallMme(int index, GpuState state)
|
||||
public void CallMme(int index, IDeviceState state)
|
||||
{
|
||||
_macros[index].Execute(_macroCode, state);
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
using Ryujinx.Graphics.Gpu.Engine.Compute;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Dma;
|
||||
using Ryujinx.Graphics.Gpu.Engine.InlineToMemory;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Threed;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Twod;
|
||||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using Ryujinx.Graphics.Gpu.State;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
|
@ -18,9 +18,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
|||
private const int MacrosCount = 0x80;
|
||||
private const int MacroIndexMask = MacrosCount - 1;
|
||||
|
||||
private readonly GpuContext _context;
|
||||
private const int UniformBufferUpdateDataMethodOffset = 0x8e4;
|
||||
|
||||
private readonly GpuChannel _channel;
|
||||
|
||||
/// <summary>
|
||||
/// Channel memory manager.
|
||||
/// </summary>
|
||||
public MemoryManager MemoryManager => _channel.MemoryManager;
|
||||
|
||||
/// <summary>
|
||||
|
@ -37,8 +41,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
|||
|
||||
private DmaState _state;
|
||||
|
||||
private readonly GpuState[] _subChannels;
|
||||
private readonly IDeviceState[] _subChannels2;
|
||||
private readonly ThreedClass _3dClass;
|
||||
private readonly ComputeClass _computeClass;
|
||||
private readonly InlineToMemoryClass _i2mClass;
|
||||
private readonly TwodClass _2dClass;
|
||||
private readonly DmaClass _dmaClass;
|
||||
|
||||
private readonly GPFifoClass _fifoClass;
|
||||
|
||||
/// <summary>
|
||||
|
@ -48,29 +56,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
|||
/// <param name="channel">Channel that the GPFIFO processor belongs to</param>
|
||||
public GPFifoProcessor(GpuContext context, GpuChannel channel)
|
||||
{
|
||||
_context = context;
|
||||
_channel = channel;
|
||||
|
||||
_fifoClass = new GPFifoClass(context, this);
|
||||
_subChannels = new GpuState[8];
|
||||
_subChannels2 = new IDeviceState[8]
|
||||
{
|
||||
null,
|
||||
new ComputeClass(context, channel),
|
||||
new InlineToMemoryClass(context, channel),
|
||||
new TwodClass(channel),
|
||||
new DmaClass(context, channel),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
};
|
||||
|
||||
for (int index = 0; index < _subChannels.Length; index++)
|
||||
{
|
||||
_subChannels[index] = new GpuState(channel, _subChannels2[index]);
|
||||
|
||||
_context.Methods.RegisterCallbacks(_subChannels[index]);
|
||||
}
|
||||
_3dClass = new ThreedClass(context, channel);
|
||||
_computeClass = new ComputeClass(context, channel, _3dClass);
|
||||
_i2mClass = new InlineToMemoryClass(context, channel);
|
||||
_2dClass = new TwodClass(channel);
|
||||
_dmaClass = new DmaClass(context, channel, _3dClass);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -85,7 +78,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
|||
|
||||
if (_state.MethodCount != 0)
|
||||
{
|
||||
Send(new MethodParams(_state.Method, command, _state.SubChannel, _state.MethodCount));
|
||||
Send(_state.Method, command, _state.SubChannel, _state.MethodCount <= 1);
|
||||
|
||||
if (!_state.NonIncrementing)
|
||||
{
|
||||
|
@ -121,13 +114,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
|||
_state.NonIncrementing = meth.SecOp == SecOp.NonIncMethod;
|
||||
break;
|
||||
case SecOp.ImmdDataMethod:
|
||||
Send(new MethodParams(meth.MethodAddress, meth.ImmdData, meth.MethodSubchannel, 1));
|
||||
Send(meth.MethodAddress, meth.ImmdData, meth.MethodSubchannel, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_context.Methods.FlushUboDirty(MemoryManager);
|
||||
_3dClass.FlushUboDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -145,11 +138,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
|||
|
||||
if (meth.MethodCount < availableCount &&
|
||||
meth.SecOp == SecOp.NonIncMethod &&
|
||||
meth.MethodAddress == (int)MethodOffset.UniformBufferUpdateData)
|
||||
meth.MethodAddress == UniformBufferUpdateDataMethodOffset)
|
||||
{
|
||||
GpuState state = _subChannels[meth.MethodSubchannel];
|
||||
|
||||
_context.Methods.UniformBufferUpdate(state, commandBuffer.Slice(offset + 1, meth.MethodCount));
|
||||
_3dClass.ConstantBufferUpdate(commandBuffer.Slice(offset + 1, meth.MethodCount));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -161,55 +152,105 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
|||
/// Sends a uncompressed method for processing by the graphics pipeline.
|
||||
/// </summary>
|
||||
/// <param name="meth">Method to be processed</param>
|
||||
private void Send(MethodParams meth)
|
||||
private void Send(int offset, int argument, int subChannel, bool isLastCall)
|
||||
{
|
||||
if ((MethodOffset)meth.Method == MethodOffset.BindChannel)
|
||||
if (offset < 0x60)
|
||||
{
|
||||
_subChannels[meth.SubChannel].ClearCallbacks();
|
||||
_fifoClass.Write(offset * 4, argument);
|
||||
}
|
||||
else if (offset < 0xe00)
|
||||
{
|
||||
offset *= 4;
|
||||
|
||||
_context.Methods.RegisterCallbacks(_subChannels[meth.SubChannel]);
|
||||
}
|
||||
else if (meth.Method < 0x60)
|
||||
{
|
||||
// TODO: check if macros are shared between subchannels or not. For now let's assume they are.
|
||||
_fifoClass.Write(meth.Method * 4, meth.Argument);
|
||||
}
|
||||
else if (meth.Method < 0xe00)
|
||||
{
|
||||
_subChannels[meth.SubChannel].CallMethod(meth);
|
||||
switch (subChannel)
|
||||
{
|
||||
case 0:
|
||||
_3dClass.Write(offset, argument);
|
||||
break;
|
||||
case 1:
|
||||
_computeClass.Write(offset, argument);
|
||||
break;
|
||||
case 2:
|
||||
_i2mClass.Write(offset, argument);
|
||||
break;
|
||||
case 3:
|
||||
_2dClass.Write(offset, argument);
|
||||
break;
|
||||
case 4:
|
||||
_dmaClass.Write(offset, argument);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int macroIndex = (meth.Method >> 1) & MacroIndexMask;
|
||||
|
||||
if ((meth.Method & 1) != 0)
|
||||
IDeviceState state = subChannel switch
|
||||
{
|
||||
_fifoClass.MmePushArgument(macroIndex, meth.Argument);
|
||||
}
|
||||
else
|
||||
{
|
||||
_fifoClass.MmeStart(macroIndex, meth.Argument);
|
||||
}
|
||||
0 => _3dClass,
|
||||
3 => _2dClass,
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (meth.IsLastCall)
|
||||
if (state != null)
|
||||
{
|
||||
_fifoClass.CallMme(macroIndex, _subChannels[meth.SubChannel]);
|
||||
int macroIndex = (offset >> 1) & MacroIndexMask;
|
||||
|
||||
_context.Methods.PerformDeferredDraws();
|
||||
if ((offset & 1) != 0)
|
||||
{
|
||||
_fifoClass.MmePushArgument(macroIndex, argument);
|
||||
}
|
||||
else
|
||||
{
|
||||
_fifoClass.MmeStart(macroIndex, argument);
|
||||
}
|
||||
|
||||
if (isLastCall)
|
||||
{
|
||||
_fifoClass.CallMme(macroIndex, state);
|
||||
|
||||
_3dClass.PerformDeferredDraws();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes data directly to the state of the specified class.
|
||||
/// </summary>
|
||||
/// <param name="classId">ID of the class to write the data into</param>
|
||||
/// <param name="offset">State offset in bytes</param>
|
||||
/// <param name="value">Value to be written</param>
|
||||
public void Write(ClassId classId, int offset, int value)
|
||||
{
|
||||
switch (classId)
|
||||
{
|
||||
case ClassId.Threed:
|
||||
_3dClass.Write(offset, value);
|
||||
break;
|
||||
case ClassId.Compute:
|
||||
_computeClass.Write(offset, value);
|
||||
break;
|
||||
case ClassId.InlineToMemory:
|
||||
_i2mClass.Write(offset, value);
|
||||
break;
|
||||
case ClassId.Twod:
|
||||
_2dClass.Write(offset, value);
|
||||
break;
|
||||
case ClassId.Dma:
|
||||
_dmaClass.Write(offset, value);
|
||||
break;
|
||||
case ClassId.GPFifo:
|
||||
_fifoClass.Write(offset, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the shadow ram control value of all sub-channels.
|
||||
/// </summary>
|
||||
/// <param name="control">New shadow ram control value</param>
|
||||
public void SetShadowRamControl(ShadowRamControl control)
|
||||
public void SetShadowRamControl(int control)
|
||||
{
|
||||
for (int i = 0; i < _subChannels.Length; i++)
|
||||
{
|
||||
_subChannels[i].ShadowRamControl = control;
|
||||
}
|
||||
_3dClass.SetShadowRamControl(control);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -218,10 +259,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
|||
/// </summary>
|
||||
public void ForceAllDirty()
|
||||
{
|
||||
for (int index = 0; index < _subChannels.Length; index++)
|
||||
{
|
||||
_subChannels[index].ForceAllDirty();
|
||||
}
|
||||
_3dClass.ForceStateDirty();
|
||||
_channel.BufferManager.Rebind();
|
||||
_channel.TextureManager.Rebind();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform any deferred draws.
|
||||
/// </summary>
|
||||
public void PerformDeferredDraws()
|
||||
{
|
||||
_3dClass.PerformDeferredDraws();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,134 +0,0 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.Gpu.State;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
{
|
||||
partial class Methods
|
||||
{
|
||||
private Inline2MemoryParams _params;
|
||||
|
||||
private bool _isLinear;
|
||||
|
||||
private int _offset;
|
||||
private int _size;
|
||||
|
||||
private bool _finished;
|
||||
|
||||
private int[] _buffer;
|
||||
|
||||
/// <summary>
|
||||
/// Launches Inline-to-Memory engine DMA copy.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void LaunchDma(GpuState state, int argument)
|
||||
{
|
||||
_params = state.Get<Inline2MemoryParams>(MethodOffset.I2mParams);
|
||||
|
||||
_isLinear = (argument & 1) != 0;
|
||||
|
||||
_offset = 0;
|
||||
_size = _params.LineLengthIn * _params.LineCount;
|
||||
|
||||
int count = BitUtils.DivRoundUp(_size, 4);
|
||||
|
||||
if (_buffer == null || _buffer.Length < count)
|
||||
{
|
||||
_buffer = new int[count];
|
||||
}
|
||||
|
||||
ulong dstBaseAddress = state.Channel.MemoryManager.Translate(_params.DstAddress.Pack());
|
||||
|
||||
// Trigger read tracking, to flush any managed resources in the destination region.
|
||||
state.Channel.MemoryManager.Physical.GetSpan(dstBaseAddress, _size, true);
|
||||
|
||||
_finished = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes a word of data to the Inline-to-Memory engine.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void LoadInlineData(GpuState state, int argument)
|
||||
{
|
||||
if (!_finished)
|
||||
{
|
||||
_buffer[_offset++] = argument;
|
||||
|
||||
if (_offset * 4 >= _size)
|
||||
{
|
||||
FinishTransfer(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs actual copy of the inline data after the transfer is finished.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
private void FinishTransfer(GpuState state)
|
||||
{
|
||||
Span<byte> data = MemoryMarshal.Cast<int, byte>(_buffer).Slice(0, _size);
|
||||
|
||||
if (_isLinear && _params.LineCount == 1)
|
||||
{
|
||||
ulong address = state.Channel.MemoryManager.Translate(_params.DstAddress.Pack());
|
||||
|
||||
state.Channel.MemoryManager.Physical.Write(address, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
var dstCalculator = new OffsetCalculator(
|
||||
_params.DstWidth,
|
||||
_params.DstHeight,
|
||||
_params.DstStride,
|
||||
_isLinear,
|
||||
_params.DstMemoryLayout.UnpackGobBlocksInY(),
|
||||
1);
|
||||
|
||||
int srcOffset = 0;
|
||||
|
||||
ulong dstBaseAddress = state.Channel.MemoryManager.Translate(_params.DstAddress.Pack());
|
||||
|
||||
for (int y = _params.DstY; y < _params.DstY + _params.LineCount; y++)
|
||||
{
|
||||
int x1 = _params.DstX;
|
||||
int x2 = _params.DstX + _params.LineLengthIn;
|
||||
int x2Trunc = _params.DstX + BitUtils.AlignDown(_params.LineLengthIn, 16);
|
||||
|
||||
int x;
|
||||
|
||||
for (x = x1; x < x2Trunc; x += 16, srcOffset += 16)
|
||||
{
|
||||
int dstOffset = dstCalculator.GetOffset(x, y);
|
||||
|
||||
ulong dstAddress = dstBaseAddress + (ulong)dstOffset;
|
||||
|
||||
Span<byte> pixel = data.Slice(srcOffset, 16);
|
||||
|
||||
state.Channel.MemoryManager.Physical.Write(dstAddress, pixel);
|
||||
}
|
||||
|
||||
for (; x < x2; x++, srcOffset++)
|
||||
{
|
||||
int dstOffset = dstCalculator.GetOffset(x, y);
|
||||
|
||||
ulong dstAddress = dstBaseAddress + (ulong)dstOffset;
|
||||
|
||||
Span<byte> pixel = data.Slice(srcOffset, 1);
|
||||
|
||||
state.Channel.MemoryManager.Physical.Write(dstAddress, pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_finished = true;
|
||||
|
||||
_context.AdvanceSequence();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -41,7 +41,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
|
|||
/// <param name="context">GPU context</param>
|
||||
/// <param name="channel">GPU channel</param>
|
||||
/// <param name="initializeState">Indicates if the internal state should be initialized. Set to false if part of another engine</param>
|
||||
protected InlineToMemoryClass(GpuContext context, GpuChannel channel, bool initializeState)
|
||||
public InlineToMemoryClass(GpuContext context, GpuChannel channel, bool initializeState)
|
||||
{
|
||||
_context = context;
|
||||
_channel = channel;
|
||||
|
@ -70,20 +70,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
|
|||
/// </summary>
|
||||
/// <param name="offset">Register byte offset</param>
|
||||
/// <returns>Data at the specified offset</returns>
|
||||
public virtual int Read(int offset) => _state.Read(offset);
|
||||
public int Read(int offset) => _state.Read(offset);
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to the class registers.
|
||||
/// </summary>
|
||||
/// <param name="offset">Register byte offset</param>
|
||||
/// <param name="data">Data to be written</param>
|
||||
public virtual void Write(int offset, int data) => _state.Write(offset, data);
|
||||
public void Write(int offset, int data) => _state.Write(offset, data);
|
||||
|
||||
/// <summary>
|
||||
/// Launches Inline-to-Memory engine DMA copy.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
protected virtual void LaunchDma(int argument)
|
||||
private void LaunchDma(int argument)
|
||||
{
|
||||
LaunchDma(ref _state.State, argument);
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
|
|||
/// </summary>
|
||||
/// <param name="state">Current class state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
protected void LaunchDma(ref InlineToMemoryClassState state, int argument)
|
||||
public void LaunchDma(ref InlineToMemoryClassState state, int argument)
|
||||
{
|
||||
_isLinear = (argument & 1) != 0;
|
||||
|
||||
|
@ -131,7 +131,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
|
|||
/// Pushes a word of data to the Inline-to-Memory engine.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
protected void LoadInlineData(int argument)
|
||||
public void LoadInlineData(int argument)
|
||||
{
|
||||
if (!_finished)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Ryujinx.Graphics.Gpu.State;
|
||||
using Ryujinx.Graphics.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||
/// <summary>
|
||||
/// Arguments FIFO.
|
||||
/// </summary>
|
||||
public Queue<int> Fifo { get; }
|
||||
Queue<int> Fifo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Should execute the GPU Macro code being passed.
|
||||
|
@ -20,6 +20,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||
/// <param name="code">Code to be executed</param>
|
||||
/// <param name="state">GPU state at the time of the call</param>
|
||||
/// <param name="arg0">First argument to be passed to the GPU Macro</param>
|
||||
void Execute(ReadOnlySpan<int> code, GpuState state, int arg0);
|
||||
void Execute(ReadOnlySpan<int> code, IDeviceState state, int arg0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Ryujinx.Graphics.Gpu.State;
|
||||
using Ryujinx.Graphics.Device;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
|
@ -55,7 +55,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||
/// </summary>
|
||||
/// <param name="code">Program code</param>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
public void Execute(ReadOnlySpan<int> code, GpuState state)
|
||||
public void Execute(ReadOnlySpan<int> code, IDeviceState state)
|
||||
{
|
||||
if (_executionPending)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.Gpu.State;
|
||||
using Ryujinx.Graphics.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
@ -45,7 +45,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||
/// <param name="code">Code of the program to execute</param>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="arg0">Optional argument passed to the program, 0 if not used</param>
|
||||
public void Execute(ReadOnlySpan<int> code, GpuState state, int arg0)
|
||||
public void Execute(ReadOnlySpan<int> code, IDeviceState state, int arg0)
|
||||
{
|
||||
Reset();
|
||||
|
||||
|
@ -55,7 +55,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||
|
||||
FetchOpCode(code);
|
||||
|
||||
while (Step(code, state)) ;
|
||||
while (Step(code, state))
|
||||
{
|
||||
}
|
||||
|
||||
// Due to the delay slot, we still need to execute
|
||||
// one more instruction before we actually exit.
|
||||
|
@ -85,7 +87,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||
/// <param name="code">Program code to execute</param>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <returns>True to continue execution, false if the program exited</returns>
|
||||
private bool Step(ReadOnlySpan<int> code, GpuState state)
|
||||
private bool Step(ReadOnlySpan<int> code, IDeviceState state)
|
||||
{
|
||||
int baseAddr = _pc - 1;
|
||||
|
||||
|
@ -193,7 +195,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <returns>Operation result</returns>
|
||||
private int GetAluResult(GpuState state)
|
||||
private int GetAluResult(IDeviceState state)
|
||||
{
|
||||
AluOperation op = (AluOperation)(_opCode & 7);
|
||||
|
||||
|
@ -378,9 +380,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="reg">Register offset to read</param>
|
||||
/// <returns>GPU register value</returns>
|
||||
private int Read(GpuState state, int reg)
|
||||
private int Read(IDeviceState state, int reg)
|
||||
{
|
||||
return state.Read(reg);
|
||||
return state.Read(reg * 4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -388,11 +390,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="value">Call argument</param>
|
||||
private void Send(GpuState state, int value)
|
||||
private void Send(IDeviceState state, int value)
|
||||
{
|
||||
MethodParams meth = new MethodParams(_methAddr, value);
|
||||
|
||||
state.CallMethod(meth);
|
||||
state.Write(_methAddr * 4, value);
|
||||
|
||||
_methAddr += _methIncr;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Ryujinx.Graphics.Gpu.State;
|
||||
using Ryujinx.Graphics.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||
/// <param name="code">Code of the program to execute</param>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="arg0">Optional argument passed to the program, 0 if not used</param>
|
||||
public void Execute(ReadOnlySpan<int> code, GpuState state, int arg0)
|
||||
public void Execute(ReadOnlySpan<int> code, IDeviceState state, int arg0)
|
||||
{
|
||||
if (_execute == null)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Ryujinx.Graphics.Gpu.State;
|
||||
using Ryujinx.Graphics.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Emit;
|
||||
|
@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||
/// </summary>
|
||||
public MacroJitCompiler()
|
||||
{
|
||||
_meth = new DynamicMethod("Macro", typeof(void), new Type[] { typeof(MacroJitContext), typeof(GpuState), typeof(int) });
|
||||
_meth = new DynamicMethod("Macro", typeof(void), new Type[] { typeof(MacroJitContext), typeof(IDeviceState), typeof(int) });
|
||||
_ilGen = _meth.GetILGenerator();
|
||||
_gprs = new LocalBuilder[8];
|
||||
|
||||
|
@ -39,7 +39,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||
_ilGen.Emit(OpCodes.Stloc, _gprs[1]);
|
||||
}
|
||||
|
||||
public delegate void MacroExecute(MacroJitContext context, GpuState state, int arg0);
|
||||
public delegate void MacroExecute(MacroJitContext context, IDeviceState state, int arg0);
|
||||
|
||||
/// <summary>
|
||||
/// Translates a new piece of GPU Macro code into host executable code.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.Gpu.State;
|
||||
using Ryujinx.Graphics.Device;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
|
@ -36,9 +36,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="reg">Register offset to read</param>
|
||||
/// <returns>GPU register value</returns>
|
||||
public static int Read(GpuState state, int reg)
|
||||
public static int Read(IDeviceState state, int reg)
|
||||
{
|
||||
return state.Read(reg);
|
||||
return state.Read(reg * 4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -47,11 +47,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||
/// <param name="value">Call argument</param>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="methAddr">Address, in words, of the method</param>
|
||||
public static void Send(int value, GpuState state, int methAddr)
|
||||
public static void Send(int value, IDeviceState state, int methAddr)
|
||||
{
|
||||
MethodParams meth = new MethodParams(methAddr, value);
|
||||
|
||||
state.CallMethod(meth);
|
||||
state.Write(methAddr * 4, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.State;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
{
|
||||
partial class Methods
|
||||
{
|
||||
/// <summary>
|
||||
/// Clears the current color and depth-stencil buffers.
|
||||
/// Which buffers should be cleared is also specified on the argument.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void Clear(GpuState state, int argument)
|
||||
{
|
||||
ConditionalRenderEnabled renderEnable = GetRenderEnable(state);
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.False)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Scissor and rasterizer discard also affect clears.
|
||||
if (state.QueryModified(MethodOffset.ScissorState))
|
||||
{
|
||||
UpdateScissorState(state);
|
||||
}
|
||||
|
||||
if (state.QueryModified(MethodOffset.RasterizeEnable))
|
||||
{
|
||||
UpdateRasterizerState(state);
|
||||
}
|
||||
|
||||
int index = (argument >> 6) & 0xf;
|
||||
|
||||
UpdateRenderTargetState(state, useControl: false, singleUse: index);
|
||||
|
||||
state.Channel.TextureManager.UpdateRenderTargets();
|
||||
|
||||
bool clearDepth = (argument & 1) != 0;
|
||||
bool clearStencil = (argument & 2) != 0;
|
||||
|
||||
uint componentMask = (uint)((argument >> 2) & 0xf);
|
||||
|
||||
if (componentMask != 0)
|
||||
{
|
||||
var clearColor = state.Get<ClearColors>(MethodOffset.ClearColors);
|
||||
|
||||
ColorF color = new ColorF(
|
||||
clearColor.Red,
|
||||
clearColor.Green,
|
||||
clearColor.Blue,
|
||||
clearColor.Alpha);
|
||||
|
||||
_context.Renderer.Pipeline.ClearRenderTargetColor(index, componentMask, color);
|
||||
}
|
||||
|
||||
if (clearDepth || clearStencil)
|
||||
{
|
||||
float depthValue = state.Get<float>(MethodOffset.ClearDepthValue);
|
||||
int stencilValue = state.Get<int> (MethodOffset.ClearStencilValue);
|
||||
|
||||
int stencilMask = 0;
|
||||
|
||||
if (clearStencil)
|
||||
{
|
||||
stencilMask = state.Get<StencilTestState>(MethodOffset.StencilTestState).FrontMask;
|
||||
}
|
||||
|
||||
_context.Renderer.Pipeline.ClearRenderTargetDepthStencil(
|
||||
depthValue,
|
||||
clearDepth,
|
||||
stencilValue,
|
||||
stencilMask);
|
||||
}
|
||||
|
||||
UpdateRenderTargetState(state, useControl: true);
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||
{
|
||||
_context.Renderer.Pipeline.EndHostConditionalRendering();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,343 +0,0 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
using Ryujinx.Graphics.Gpu.State;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
{
|
||||
partial class Methods
|
||||
{
|
||||
private bool _drawIndexed;
|
||||
|
||||
private bool _instancedDrawPending;
|
||||
private bool _instancedIndexed;
|
||||
|
||||
private int _instancedFirstIndex;
|
||||
private int _instancedFirstVertex;
|
||||
private int _instancedFirstInstance;
|
||||
private int _instancedIndexCount;
|
||||
private int _instancedDrawStateFirst;
|
||||
private int _instancedDrawStateCount;
|
||||
|
||||
private int _instanceIndex;
|
||||
|
||||
private IbStreamer _ibStreamer;
|
||||
|
||||
/// <summary>
|
||||
/// Primitive topology of the current draw.
|
||||
/// </summary>
|
||||
public PrimitiveTopology Topology { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Finishes the draw call.
|
||||
/// This draws geometry on the bound buffers based on the current GPU state.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawEnd(GpuState state, int argument)
|
||||
{
|
||||
var indexBuffer = state.Get<IndexBufferState>(MethodOffset.IndexBufferState);
|
||||
|
||||
DrawEnd(state, indexBuffer.First, indexBuffer.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finishes the draw call.
|
||||
/// This draws geometry on the bound buffers based on the current GPU state.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="firstIndex">Index of the first index buffer element used on the draw</param>
|
||||
/// <param name="indexCount">Number of index buffer elements used on the draw</param>
|
||||
private void DrawEnd(GpuState state, int firstIndex, int indexCount)
|
||||
{
|
||||
ConditionalRenderEnabled renderEnable = GetRenderEnable(state);
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.False || _instancedDrawPending)
|
||||
{
|
||||
if (renderEnable == ConditionalRenderEnabled.False)
|
||||
{
|
||||
PerformDeferredDraws();
|
||||
}
|
||||
|
||||
_drawIndexed = false;
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||
{
|
||||
_context.Renderer.Pipeline.EndHostConditionalRendering();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateState(state, firstIndex, indexCount);
|
||||
|
||||
bool instanced = _vsUsesInstanceId || _isAnyVbInstanced;
|
||||
|
||||
if (instanced)
|
||||
{
|
||||
_instancedDrawPending = true;
|
||||
|
||||
_instancedIndexed = _drawIndexed;
|
||||
|
||||
_instancedFirstIndex = firstIndex;
|
||||
_instancedFirstVertex = state.Get<int>(MethodOffset.FirstVertex);
|
||||
_instancedFirstInstance = state.Get<int>(MethodOffset.FirstInstance);
|
||||
|
||||
_instancedIndexCount = indexCount;
|
||||
|
||||
var drawState = state.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
|
||||
|
||||
_instancedDrawStateFirst = drawState.First;
|
||||
_instancedDrawStateCount = drawState.Count;
|
||||
|
||||
_drawIndexed = false;
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||
{
|
||||
_context.Renderer.Pipeline.EndHostConditionalRendering();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int firstInstance = state.Get<int>(MethodOffset.FirstInstance);
|
||||
|
||||
int inlineIndexCount = _ibStreamer.GetAndResetInlineIndexCount();
|
||||
|
||||
if (inlineIndexCount != 0)
|
||||
{
|
||||
int firstVertex = state.Get<int>(MethodOffset.FirstVertex);
|
||||
|
||||
BufferRange br = new BufferRange(_ibStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4);
|
||||
|
||||
state.Channel.BufferManager.SetIndexBuffer(br, IndexType.UInt);
|
||||
|
||||
_context.Renderer.Pipeline.DrawIndexed(
|
||||
inlineIndexCount,
|
||||
1,
|
||||
firstIndex,
|
||||
firstVertex,
|
||||
firstInstance);
|
||||
}
|
||||
else if (_drawIndexed)
|
||||
{
|
||||
int firstVertex = state.Get<int>(MethodOffset.FirstVertex);
|
||||
|
||||
_context.Renderer.Pipeline.DrawIndexed(
|
||||
indexCount,
|
||||
1,
|
||||
firstIndex,
|
||||
firstVertex,
|
||||
firstInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
var drawState = state.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
|
||||
|
||||
_context.Renderer.Pipeline.Draw(
|
||||
drawState.Count,
|
||||
1,
|
||||
drawState.First,
|
||||
firstInstance);
|
||||
}
|
||||
|
||||
_drawIndexed = false;
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||
{
|
||||
_context.Renderer.Pipeline.EndHostConditionalRendering();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts draw.
|
||||
/// This sets primitive type and instanced draw parameters.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawBegin(GpuState state, int argument)
|
||||
{
|
||||
bool incrementInstance = (argument & (1 << 26)) != 0;
|
||||
bool resetInstance = (argument & (1 << 27)) == 0;
|
||||
|
||||
PrimitiveType type = (PrimitiveType)(argument & 0xffff);
|
||||
|
||||
PrimitiveTypeOverride typeOverride = state.Get<PrimitiveTypeOverride>(MethodOffset.PrimitiveTypeOverride);
|
||||
|
||||
if (typeOverride != PrimitiveTypeOverride.Invalid)
|
||||
{
|
||||
DrawBegin(incrementInstance, resetInstance, typeOverride.Convert());
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawBegin(incrementInstance, resetInstance, type.Convert());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts draw.
|
||||
/// This sets primitive type and instanced draw parameters.
|
||||
/// </summary>
|
||||
/// <param name="incrementInstance">Indicates if the current instance should be incremented</param>
|
||||
/// <param name="resetInstance">Indicates if the current instance should be set to zero</param>
|
||||
/// <param name="topology">Primitive topology</param>
|
||||
private void DrawBegin(bool incrementInstance, bool resetInstance, PrimitiveTopology topology)
|
||||
{
|
||||
if (incrementInstance)
|
||||
{
|
||||
_instanceIndex++;
|
||||
}
|
||||
else if (resetInstance)
|
||||
{
|
||||
PerformDeferredDraws();
|
||||
|
||||
_instanceIndex = 0;
|
||||
}
|
||||
|
||||
_context.Renderer.Pipeline.SetPrimitiveTopology(topology);
|
||||
|
||||
Topology = topology;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the index buffer count.
|
||||
/// This also sets internal state that indicates that the next draw is an indexed draw.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void SetIndexBufferCount(GpuState state, int argument)
|
||||
{
|
||||
_drawIndexed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawIndexedSmall(GpuState state, int argument)
|
||||
{
|
||||
DrawIndexedSmall(state, argument, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawIndexedSmall2(GpuState state, int argument)
|
||||
{
|
||||
DrawIndexedSmall(state, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements,
|
||||
/// while also pre-incrementing the current instance value.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawIndexedSmallIncInstance(GpuState state, int argument)
|
||||
{
|
||||
DrawIndexedSmall(state, argument, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements,
|
||||
/// while also pre-incrementing the current instance value.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawIndexedSmallIncInstance2(GpuState state, int argument)
|
||||
{
|
||||
DrawIndexedSmallIncInstance(state, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements,
|
||||
/// while optionally also pre-incrementing the current instance value.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
/// <param name="instanced">True to increment the current instance value, false otherwise</param>
|
||||
private void DrawIndexedSmall(GpuState state, int argument, bool instanced)
|
||||
{
|
||||
PrimitiveTypeOverride typeOverride = state.Get<PrimitiveTypeOverride>(MethodOffset.PrimitiveTypeOverride);
|
||||
|
||||
DrawBegin(instanced, !instanced, typeOverride.Convert());
|
||||
|
||||
int firstIndex = argument & 0xffff;
|
||||
int indexCount = (argument >> 16) & 0xfff;
|
||||
|
||||
bool oldDrawIndexed = _drawIndexed;
|
||||
|
||||
_drawIndexed = true;
|
||||
|
||||
DrawEnd(state, firstIndex, indexCount);
|
||||
|
||||
_drawIndexed = oldDrawIndexed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes four 8-bit index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void VbElementU8(GpuState state, int argument)
|
||||
{
|
||||
_ibStreamer.VbElementU8(_context.Renderer, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes two 16-bit index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void VbElementU16(GpuState state, int argument)
|
||||
{
|
||||
_ibStreamer.VbElementU16(_context.Renderer, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes one 32-bit index buffer element.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void VbElementU32(GpuState state, int argument)
|
||||
{
|
||||
_ibStreamer.VbElementU32(_context.Renderer, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform any deferred draws.
|
||||
/// This is used for instanced draws.
|
||||
/// Since each instance is a separate draw, we defer the draw and accumulate the instance count.
|
||||
/// Once we detect the last instanced draw, then we perform the host instanced draw,
|
||||
/// with the accumulated instance count.
|
||||
/// </summary>
|
||||
public void PerformDeferredDraws()
|
||||
{
|
||||
// Perform any pending instanced draw.
|
||||
if (_instancedDrawPending)
|
||||
{
|
||||
_instancedDrawPending = false;
|
||||
|
||||
if (_instancedIndexed)
|
||||
{
|
||||
_context.Renderer.Pipeline.DrawIndexed(
|
||||
_instancedIndexCount,
|
||||
_instanceIndex + 1,
|
||||
_instancedFirstIndex,
|
||||
_instancedFirstVertex,
|
||||
_instancedFirstInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.Renderer.Pipeline.Draw(
|
||||
_instancedDrawStateCount,
|
||||
_instanceIndex + 1,
|
||||
_instancedDrawStateFirst,
|
||||
_instancedFirstInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
using Ryujinx.Graphics.Gpu.State;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
{
|
||||
partial class Methods
|
||||
{
|
||||
private void FirmwareCall4(GpuState state, int argument)
|
||||
{
|
||||
state.Write(0xd00, 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
using Ryujinx.Graphics.Gpu.State;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
{
|
||||
partial class Methods
|
||||
{
|
||||
/// <summary>
|
||||
/// Performs an incrementation on a syncpoint.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void IncrementSyncpoint(GpuState state, int argument)
|
||||
{
|
||||
uint syncpointId = (uint)(argument) & 0xFFFF;
|
||||
|
||||
_context.CreateHostSyncIfNeeded();
|
||||
_context.Renderer.UpdateCounters(); // Poll the query counters, the game may want an updated result.
|
||||
_context.Synchronization.IncrementSyncpoint(syncpointId);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using Ryujinx.Graphics.Gpu.State;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
{
|
||||
partial class Methods
|
||||
{
|
||||
private const int NsToTicksFractionNumerator = 384;
|
||||
private const int NsToTicksFractionDenominator = 625;
|
||||
|
||||
/// <summary>
|
||||
/// Writes a GPU counter to guest memory.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void Report(GpuState state, int argument)
|
||||
{
|
||||
SemaphoreOperation op = (SemaphoreOperation)(argument & 3);
|
||||
ReportCounterType type = (ReportCounterType)((argument >> 23) & 0x1f);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case SemaphoreOperation.Release: ReleaseSemaphore(state); break;
|
||||
case SemaphoreOperation.Counter: ReportCounter(state, type); break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes (or Releases) a GPU semaphore value to guest memory.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
private void ReleaseSemaphore(GpuState state)
|
||||
{
|
||||
var rs = state.Get<SemaphoreState>(MethodOffset.ReportState);
|
||||
|
||||
state.Channel.MemoryManager.Write(rs.Address.Pack(), rs.Payload);
|
||||
|
||||
_context.AdvanceSequence();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Packed GPU counter data (including GPU timestamp) in memory.
|
||||
/// </summary>
|
||||
private struct CounterData
|
||||
{
|
||||
public ulong Counter;
|
||||
public ulong Timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a GPU counter to guest memory.
|
||||
/// This also writes the current timestamp value.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="type">Counter to be written to memory</param>
|
||||
private void ReportCounter(GpuState state, ReportCounterType type)
|
||||
{
|
||||
var rs = state.Get<SemaphoreState>(MethodOffset.ReportState);
|
||||
|
||||
ulong gpuVa = rs.Address.Pack();
|
||||
|
||||
ulong ticks = ConvertNanosecondsToTicks((ulong)PerformanceCounter.ElapsedNanoseconds);
|
||||
|
||||
if (GraphicsConfig.FastGpuTime)
|
||||
{
|
||||
// Divide by some amount to report time as if operations were performed faster than they really are.
|
||||
// This can prevent some games from switching to a lower resolution because rendering is too slow.
|
||||
ticks /= 256;
|
||||
}
|
||||
|
||||
ICounterEvent counter = null;
|
||||
|
||||
EventHandler<ulong> resultHandler = (object evt, ulong result) =>
|
||||
{
|
||||
CounterData counterData = new CounterData();
|
||||
|
||||
counterData.Counter = result;
|
||||
counterData.Timestamp = ticks;
|
||||
|
||||
if (counter?.Invalid != true)
|
||||
{
|
||||
state.Channel.MemoryManager.Write(gpuVa, counterData);
|
||||
}
|
||||
};
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ReportCounterType.Zero:
|
||||
resultHandler(null, 0);
|
||||
break;
|
||||
case ReportCounterType.SamplesPassed:
|
||||
counter = _context.Renderer.ReportCounter(CounterType.SamplesPassed, resultHandler);
|
||||
break;
|
||||
case ReportCounterType.PrimitivesGenerated:
|
||||
counter = _context.Renderer.ReportCounter(CounterType.PrimitivesGenerated, resultHandler);
|
||||
break;
|
||||
case ReportCounterType.TransformFeedbackPrimitivesWritten:
|
||||
counter = _context.Renderer.ReportCounter(CounterType.TransformFeedbackPrimitivesWritten, resultHandler);
|
||||
break;
|
||||
}
|
||||
|
||||
state.Channel.MemoryManager.CounterCache.AddOrUpdate(gpuVa, counter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a nanoseconds timestamp value to Maxwell time ticks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The frequency is 614400000 Hz.
|
||||
/// </remarks>
|
||||
/// <param name="nanoseconds">Timestamp in nanoseconds</param>
|
||||
/// <returns>Maxwell ticks</returns>
|
||||
private static ulong ConvertNanosecondsToTicks(ulong nanoseconds)
|
||||
{
|
||||
// We need to divide first to avoid overflows.
|
||||
// We fix up the result later by calculating the difference and adding
|
||||
// that to the result.
|
||||
ulong divided = nanoseconds / NsToTicksFractionDenominator;
|
||||
|
||||
ulong rounded = divided * NsToTicksFractionDenominator;
|
||||
|
||||
ulong errorBias = (nanoseconds - rounded) * NsToTicksFractionNumerator / NsToTicksFractionDenominator;
|
||||
|
||||
return divided * NsToTicksFractionNumerator + errorBias;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.State;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
{
|
||||
partial class Methods
|
||||
{
|
||||
/// <summary>
|
||||
/// Resets the value of an internal GPU counter back to zero.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void ResetCounter(GpuState state, int argument)
|
||||
{
|
||||
ResetCounterType type = (ResetCounterType)argument;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ResetCounterType.SamplesPassed:
|
||||
_context.Renderer.ResetCounter(CounterType.SamplesPassed);
|
||||
break;
|
||||
case ResetCounterType.PrimitivesGenerated:
|
||||
_context.Renderer.ResetCounter(CounterType.PrimitivesGenerated);
|
||||
break;
|
||||
case ResetCounterType.TransformFeedbackPrimitivesWritten:
|
||||
_context.Renderer.ResetCounter(CounterType.TransformFeedbackPrimitivesWritten);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
using Ryujinx.Graphics.Gpu.State;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
{
|
||||
partial class Methods
|
||||
{
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the vertex shader stage.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void UniformBufferBindVertex(GpuState state, int argument)
|
||||
{
|
||||
UniformBufferBind(state, argument, ShaderType.Vertex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the tessellation control shader stage.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void UniformBufferBindTessControl(GpuState state, int argument)
|
||||
{
|
||||
UniformBufferBind(state, argument, ShaderType.TessellationControl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the tessellation evaluation shader stage.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void UniformBufferBindTessEvaluation(GpuState state, int argument)
|
||||
{
|
||||
UniformBufferBind(state, argument, ShaderType.TessellationEvaluation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the geometry shader stage.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void UniformBufferBindGeometry(GpuState state, int argument)
|
||||
{
|
||||
UniformBufferBind(state, argument, ShaderType.Geometry);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the fragment shader stage.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void UniformBufferBindFragment(GpuState state, int argument)
|
||||
{
|
||||
UniformBufferBind(state, argument, ShaderType.Fragment);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///Binds a uniform buffer for the specified shader stage.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
/// <param name="type">Shader stage that will access the uniform buffer</param>
|
||||
private void UniformBufferBind(GpuState state, int argument, ShaderType type)
|
||||
{
|
||||
bool enable = (argument & 1) != 0;
|
||||
|
||||
int index = (argument >> 4) & 0x1f;
|
||||
|
||||
FlushUboDirty(state.Channel.MemoryManager);
|
||||
|
||||
if (enable)
|
||||
{
|
||||
var uniformBuffer = state.Get<UniformBufferState>(MethodOffset.UniformBufferState);
|
||||
|
||||
ulong address = uniformBuffer.Address.Pack();
|
||||
|
||||
state.Channel.BufferManager.SetGraphicsUniformBuffer((int)type, index, address, (uint)uniformBuffer.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
state.Channel.BufferManager.SetGraphicsUniformBuffer((int)type, index, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using Ryujinx.Graphics.Gpu.State;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
{
|
||||
partial class Methods
|
||||
{
|
||||
// State associated with direct uniform buffer updates.
|
||||
// This state is used to attempt to batch together consecutive updates.
|
||||
private ulong _ubBeginCpuAddress = 0;
|
||||
private ulong _ubFollowUpAddress = 0;
|
||||
private ulong _ubByteCount = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Flushes any queued ubo updates.
|
||||
/// </summary>
|
||||
/// <param name="memoryManager">GPU memory manager where the uniform buffer is mapped</param>
|
||||
public void FlushUboDirty(MemoryManager memoryManager)
|
||||
{
|
||||
if (_ubFollowUpAddress != 0)
|
||||
{
|
||||
memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount);
|
||||
|
||||
_ubFollowUpAddress = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the uniform buffer data with inline data.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="argument">New uniform buffer data word</param>
|
||||
private void UniformBufferUpdate(GpuState state, int argument)
|
||||
{
|
||||
var uniformBuffer = state.Get<UniformBufferState>(MethodOffset.UniformBufferState);
|
||||
|
||||
ulong address = uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset;
|
||||
|
||||
if (_ubFollowUpAddress != address)
|
||||
{
|
||||
FlushUboDirty(state.Channel.MemoryManager);
|
||||
|
||||
_ubByteCount = 0;
|
||||
_ubBeginCpuAddress = state.Channel.MemoryManager.Translate(address);
|
||||
}
|
||||
|
||||
var byteData = MemoryMarshal.Cast<int, byte>(MemoryMarshal.CreateSpan(ref argument, 1));
|
||||
state.Channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
|
||||
|
||||
_ubFollowUpAddress = address + 4;
|
||||
_ubByteCount += 4;
|
||||
|
||||
state.SetUniformBufferOffset(uniformBuffer.Offset + 4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the uniform buffer data with inline data.
|
||||
/// </summary>
|
||||
/// <param name="state">Current GPU state</param>
|
||||
/// <param name="data">Data to be written to the uniform buffer</param>
|
||||
public void UniformBufferUpdate(GpuState state, ReadOnlySpan<int> data)
|
||||
{
|
||||
var uniformBuffer = state.Get<UniformBufferState>(MethodOffset.UniformBufferState);
|
||||
|
||||
ulong address = uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset;
|
||||
|
||||
ulong size = (ulong)data.Length * 4;
|
||||
|
||||
if (_ubFollowUpAddress != address)
|
||||
{
|
||||
FlushUboDirty(state.Channel.MemoryManager);
|
||||
|
||||
_ubByteCount = 0;
|
||||
_ubBeginCpuAddress = state.Channel.MemoryManager.Translate(address);
|
||||
}
|
||||
|
||||
var byteData = MemoryMarshal.Cast<int, byte>(data);
|
||||
state.Channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
|
||||
|
||||
_ubFollowUpAddress = address + size;
|
||||
_ubByteCount += size;
|
||||
|
||||
state.SetUniformBufferOffset(uniformBuffer.Offset + data.Length * 4);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -3,6 +3,9 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents temporary storage used by macros.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Size = 1024)]
|
||||
struct MmeShadowScratch
|
||||
{
|
||||
|
|
13
Ryujinx.Graphics.Gpu/Engine/SetMmeShadowRamControlMode.cs
Normal file
13
Ryujinx.Graphics.Gpu/Engine/SetMmeShadowRamControlMode.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
{
|
||||
/// <summary>
|
||||
/// MME shadow RAM control mode.
|
||||
/// </summary>
|
||||
enum SetMmeShadowRamControlMode
|
||||
{
|
||||
MethodTrack = 0,
|
||||
MethodTrackWithFilter = 1,
|
||||
MethodPassthrough = 2,
|
||||
MethodReplay = 3,
|
||||
}
|
||||
}
|
|
@ -1,37 +1,41 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using Ryujinx.Graphics.Gpu.State;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
partial class Methods
|
||||
/// <summary>
|
||||
/// Helper methods used for conditional rendering.
|
||||
/// </summary>
|
||||
static class ConditionalRendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if draws and clears should be performed, according
|
||||
/// to currently set conditional rendering conditions.
|
||||
/// </summary>
|
||||
/// <param name="state">GPU state</param>
|
||||
/// <param name="context">GPU context</param>
|
||||
/// <param name="memoryManager">Memory manager bound to the channel currently executing</param>
|
||||
/// <param name="address">Conditional rendering buffer address</param>
|
||||
/// <param name="condition">Conditional rendering condition</param>
|
||||
/// <returns>True if rendering is enabled, false otherwise</returns>
|
||||
private ConditionalRenderEnabled GetRenderEnable(GpuState state)
|
||||
public static ConditionalRenderEnabled GetRenderEnable(GpuContext context, MemoryManager memoryManager, GpuVa address, Condition condition)
|
||||
{
|
||||
ConditionState condState = state.Get<ConditionState>(MethodOffset.ConditionState);
|
||||
|
||||
switch (condState.Condition)
|
||||
switch (condition)
|
||||
{
|
||||
case Condition.Always:
|
||||
return ConditionalRenderEnabled.True;
|
||||
case Condition.Never:
|
||||
return ConditionalRenderEnabled.False;
|
||||
case Condition.ResultNonZero:
|
||||
return CounterNonZero(state, condState.Address.Pack());
|
||||
return CounterNonZero(context, memoryManager, address.Pack());
|
||||
case Condition.Equal:
|
||||
return CounterCompare(state, condState.Address.Pack(), true);
|
||||
return CounterCompare(context, memoryManager, address.Pack(), true);
|
||||
case Condition.NotEqual:
|
||||
return CounterCompare(state, condState.Address.Pack(), false);
|
||||
return CounterCompare(context, memoryManager, address.Pack(), false);
|
||||
}
|
||||
|
||||
Logger.Warning?.Print(LogClass.Gpu, $"Invalid conditional render condition \"{condState.Condition}\".");
|
||||
Logger.Warning?.Print(LogClass.Gpu, $"Invalid conditional render condition \"{condition}\".");
|
||||
|
||||
return ConditionalRenderEnabled.True;
|
||||
}
|
||||
|
@ -39,54 +43,56 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|||
/// <summary>
|
||||
/// Checks if the counter value at a given GPU memory address is non-zero.
|
||||
/// </summary>
|
||||
/// <param name="state">GPU state</param>
|
||||
/// <param name="context">GPU context</param>
|
||||
/// <param name="memoryManager">Memory manager bound to the channel currently executing</param>
|
||||
/// <param name="gpuVa">GPU virtual address of the counter value</param>
|
||||
/// <returns>True if the value is not zero, false otherwise. Returns host if handling with host conditional rendering</returns>
|
||||
private ConditionalRenderEnabled CounterNonZero(GpuState state, ulong gpuVa)
|
||||
private static ConditionalRenderEnabled CounterNonZero(GpuContext context, MemoryManager memoryManager, ulong gpuVa)
|
||||
{
|
||||
ICounterEvent evt = state.Channel.MemoryManager.CounterCache.FindEvent(gpuVa);
|
||||
ICounterEvent evt = memoryManager.CounterCache.FindEvent(gpuVa);
|
||||
|
||||
if (evt == null)
|
||||
{
|
||||
return ConditionalRenderEnabled.False;
|
||||
}
|
||||
|
||||
if (_context.Renderer.Pipeline.TryHostConditionalRendering(evt, 0L, false))
|
||||
if (context.Renderer.Pipeline.TryHostConditionalRendering(evt, 0L, false))
|
||||
{
|
||||
return ConditionalRenderEnabled.Host;
|
||||
}
|
||||
else
|
||||
{
|
||||
evt.Flush();
|
||||
return (state.Channel.MemoryManager.Read<ulong>(gpuVa) != 0) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
|
||||
return (memoryManager.Read<ulong>(gpuVa) != 0) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the counter at a given GPU memory address passes a specified equality comparison.
|
||||
/// </summary>
|
||||
/// <param name="state">GPU state</param>
|
||||
/// <param name="context">GPU context</param>
|
||||
/// <param name="memoryManager">Memory manager bound to the channel currently executing</param>
|
||||
/// <param name="gpuVa">GPU virtual address</param>
|
||||
/// <param name="isEqual">True to check if the values are equal, false to check if they are not equal</param>
|
||||
/// <returns>True if the condition is met, false otherwise. Returns host if handling with host conditional rendering</returns>
|
||||
private ConditionalRenderEnabled CounterCompare(GpuState state, ulong gpuVa, bool isEqual)
|
||||
private static ConditionalRenderEnabled CounterCompare(GpuContext context, MemoryManager memoryManager, ulong gpuVa, bool isEqual)
|
||||
{
|
||||
ICounterEvent evt = FindEvent(state.Channel.MemoryManager.CounterCache, gpuVa);
|
||||
ICounterEvent evt2 = FindEvent(state.Channel.MemoryManager.CounterCache, gpuVa + 16);
|
||||
ICounterEvent evt = FindEvent(memoryManager.CounterCache, gpuVa);
|
||||
ICounterEvent evt2 = FindEvent(memoryManager.CounterCache, gpuVa + 16);
|
||||
|
||||
bool useHost;
|
||||
|
||||
if (evt != null && evt2 == null)
|
||||
{
|
||||
useHost = _context.Renderer.Pipeline.TryHostConditionalRendering(evt, state.Channel.MemoryManager.Read<ulong>(gpuVa + 16), isEqual);
|
||||
useHost = context.Renderer.Pipeline.TryHostConditionalRendering(evt, memoryManager.Read<ulong>(gpuVa + 16), isEqual);
|
||||
}
|
||||
else if (evt == null && evt2 != null)
|
||||
{
|
||||
useHost = _context.Renderer.Pipeline.TryHostConditionalRendering(evt2, state.Channel.MemoryManager.Read<ulong>(gpuVa), isEqual);
|
||||
useHost = context.Renderer.Pipeline.TryHostConditionalRendering(evt2, memoryManager.Read<ulong>(gpuVa), isEqual);
|
||||
}
|
||||
else if (evt != null && evt2 != null)
|
||||
{
|
||||
useHost = _context.Renderer.Pipeline.TryHostConditionalRendering(evt, evt2, isEqual);
|
||||
useHost = context.Renderer.Pipeline.TryHostConditionalRendering(evt, evt2, isEqual);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -102,8 +108,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|||
evt?.Flush();
|
||||
evt2?.Flush();
|
||||
|
||||
ulong x = state.Channel.MemoryManager.Read<ulong>(gpuVa);
|
||||
ulong y = state.Channel.MemoryManager.Read<ulong>(gpuVa + 16);
|
||||
ulong x = memoryManager.Read<ulong>(gpuVa);
|
||||
ulong y = memoryManager.Read<ulong>(gpuVa + 16);
|
||||
|
||||
return (isEqual ? x == y : x != y) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False;
|
||||
}
|
173
Ryujinx.Graphics.Gpu/Engine/Threed/ConstantBufferUpdater.cs
Normal file
173
Ryujinx.Graphics.Gpu/Engine/Threed/ConstantBufferUpdater.cs
Normal file
|
@ -0,0 +1,173 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
/// <summary>
|
||||
/// Constant buffer updater.
|
||||
/// </summary>
|
||||
class ConstantBufferUpdater
|
||||
{
|
||||
private readonly GpuChannel _channel;
|
||||
private readonly DeviceStateWithShadow<ThreedClassState> _state;
|
||||
|
||||
// State associated with direct uniform buffer updates.
|
||||
// This state is used to attempt to batch together consecutive updates.
|
||||
private ulong _ubBeginCpuAddress = 0;
|
||||
private ulong _ubFollowUpAddress = 0;
|
||||
private ulong _ubByteCount = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the constant buffer updater.
|
||||
/// </summary>
|
||||
/// <param name="channel">GPU channel</param>
|
||||
/// <param name="state">Channel state</param>
|
||||
public ConstantBufferUpdater(GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state)
|
||||
{
|
||||
_channel = channel;
|
||||
_state = state;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the vertex shader stage.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void BindVertex(int argument)
|
||||
{
|
||||
Bind(argument, ShaderType.Vertex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the tessellation control shader stage.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void BindTessControl(int argument)
|
||||
{
|
||||
Bind(argument, ShaderType.TessellationControl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the tessellation evaluation shader stage.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void BindTessEvaluation(int argument)
|
||||
{
|
||||
Bind(argument, ShaderType.TessellationEvaluation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the geometry shader stage.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void BindGeometry(int argument)
|
||||
{
|
||||
Bind(argument, ShaderType.Geometry);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the fragment shader stage.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void BindFragment(int argument)
|
||||
{
|
||||
Bind(argument, ShaderType.Fragment);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the specified shader stage.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
/// <param name="type">Shader stage that will access the uniform buffer</param>
|
||||
private void Bind(int argument, ShaderType type)
|
||||
{
|
||||
bool enable = (argument & 1) != 0;
|
||||
|
||||
int index = (argument >> 4) & 0x1f;
|
||||
|
||||
FlushUboDirty();
|
||||
|
||||
if (enable)
|
||||
{
|
||||
var uniformBuffer = _state.State.UniformBufferState;
|
||||
|
||||
ulong address = uniformBuffer.Address.Pack();
|
||||
|
||||
_channel.BufferManager.SetGraphicsUniformBuffer((int)type, index, address, (uint)uniformBuffer.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
_channel.BufferManager.SetGraphicsUniformBuffer((int)type, index, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes any queued UBO updates.
|
||||
/// </summary>
|
||||
public void FlushUboDirty()
|
||||
{
|
||||
if (_ubFollowUpAddress != 0)
|
||||
{
|
||||
var memoryManager = _channel.MemoryManager;
|
||||
memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount);
|
||||
|
||||
_ubFollowUpAddress = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the uniform buffer data with inline data.
|
||||
/// </summary>
|
||||
/// <param name="argument">New uniform buffer data word</param>
|
||||
public void Update(int argument)
|
||||
{
|
||||
var uniformBuffer = _state.State.UniformBufferState;
|
||||
|
||||
ulong address = uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset;
|
||||
|
||||
if (_ubFollowUpAddress != address)
|
||||
{
|
||||
FlushUboDirty();
|
||||
|
||||
_ubByteCount = 0;
|
||||
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
|
||||
}
|
||||
|
||||
var byteData = MemoryMarshal.Cast<int, byte>(MemoryMarshal.CreateSpan(ref argument, 1));
|
||||
_channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
|
||||
|
||||
_ubFollowUpAddress = address + 4;
|
||||
_ubByteCount += 4;
|
||||
|
||||
_state.State.UniformBufferState.Offset += 4;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the uniform buffer data with inline data.
|
||||
/// </summary>
|
||||
/// <param name="data">Data to be written to the uniform buffer</param>
|
||||
public void Update(ReadOnlySpan<int> data)
|
||||
{
|
||||
var uniformBuffer = _state.State.UniformBufferState;
|
||||
|
||||
ulong address = uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset;
|
||||
|
||||
ulong size = (ulong)data.Length * 4;
|
||||
|
||||
if (_ubFollowUpAddress != address)
|
||||
{
|
||||
FlushUboDirty();
|
||||
|
||||
_ubByteCount = 0;
|
||||
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
|
||||
}
|
||||
|
||||
var byteData = MemoryMarshal.Cast<int, byte>(data);
|
||||
_channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
|
||||
|
||||
_ubFollowUpAddress = address + size;
|
||||
_ubByteCount += size;
|
||||
|
||||
_state.State.UniformBufferState.Offset += data.Length * 4;
|
||||
}
|
||||
}
|
||||
}
|
410
Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
Normal file
410
Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
Normal file
|
@ -0,0 +1,410 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
/// <summary>
|
||||
/// Draw manager.
|
||||
/// </summary>
|
||||
class DrawManager
|
||||
{
|
||||
private readonly GpuContext _context;
|
||||
private readonly GpuChannel _channel;
|
||||
private readonly DeviceStateWithShadow<ThreedClassState> _state;
|
||||
private readonly DrawState _drawState;
|
||||
|
||||
private bool _instancedDrawPending;
|
||||
private bool _instancedIndexed;
|
||||
|
||||
private int _instancedFirstIndex;
|
||||
private int _instancedFirstVertex;
|
||||
private int _instancedFirstInstance;
|
||||
private int _instancedIndexCount;
|
||||
private int _instancedDrawStateFirst;
|
||||
private int _instancedDrawStateCount;
|
||||
|
||||
private int _instanceIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the draw manager.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context</param>
|
||||
/// <param name="channel">GPU channel</param>
|
||||
/// <param name="state">Channel state</param>
|
||||
/// <param name="drawState">Draw state</param>
|
||||
public DrawManager(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState)
|
||||
{
|
||||
_context = context;
|
||||
_channel = channel;
|
||||
_state = state;
|
||||
_drawState = drawState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes four 8-bit index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void VbElementU8(int argument)
|
||||
{
|
||||
_drawState.IbStreamer.VbElementU8(_context.Renderer, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes two 16-bit index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void VbElementU16(int argument)
|
||||
{
|
||||
_drawState.IbStreamer.VbElementU16(_context.Renderer, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes one 32-bit index buffer element.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void VbElementU32(int argument)
|
||||
{
|
||||
_drawState.IbStreamer.VbElementU32(_context.Renderer, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finishes the draw call.
|
||||
/// This draws geometry on the bound buffers based on the current GPU state.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawEnd(ThreedClass engine, int argument)
|
||||
{
|
||||
DrawEnd(engine, _state.State.IndexBufferState.First, (int)_state.State.IndexBufferCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finishes the draw call.
|
||||
/// This draws geometry on the bound buffers based on the current GPU state.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="firstIndex">Index of the first index buffer element used on the draw</param>
|
||||
/// <param name="indexCount">Number of index buffer elements used on the draw</param>
|
||||
private void DrawEnd(ThreedClass engine, int firstIndex, int indexCount)
|
||||
{
|
||||
ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable(
|
||||
_context,
|
||||
_channel.MemoryManager,
|
||||
_state.State.RenderEnableAddress,
|
||||
_state.State.RenderEnableCondition);
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.False || _instancedDrawPending)
|
||||
{
|
||||
if (renderEnable == ConditionalRenderEnabled.False)
|
||||
{
|
||||
PerformDeferredDraws();
|
||||
}
|
||||
|
||||
_drawState.DrawIndexed = false;
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||
{
|
||||
_context.Renderer.Pipeline.EndHostConditionalRendering();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_drawState.FirstIndex = firstIndex;
|
||||
_drawState.IndexCount = indexCount;
|
||||
|
||||
engine.UpdateState();
|
||||
|
||||
bool instanced = _drawState.VsUsesInstanceId || _drawState.IsAnyVbInstanced;
|
||||
|
||||
if (instanced)
|
||||
{
|
||||
_instancedDrawPending = true;
|
||||
|
||||
_instancedIndexed = _drawState.DrawIndexed;
|
||||
|
||||
_instancedFirstIndex = firstIndex;
|
||||
_instancedFirstVertex = (int)_state.State.FirstVertex;
|
||||
_instancedFirstInstance = (int)_state.State.FirstInstance;
|
||||
|
||||
_instancedIndexCount = indexCount;
|
||||
|
||||
var drawState = _state.State.VertexBufferDrawState;
|
||||
|
||||
_instancedDrawStateFirst = drawState.First;
|
||||
_instancedDrawStateCount = drawState.Count;
|
||||
|
||||
_drawState.DrawIndexed = false;
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||
{
|
||||
_context.Renderer.Pipeline.EndHostConditionalRendering();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int firstInstance = (int)_state.State.FirstInstance;
|
||||
|
||||
int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount();
|
||||
|
||||
if (inlineIndexCount != 0)
|
||||
{
|
||||
int firstVertex = (int)_state.State.FirstVertex;
|
||||
|
||||
BufferRange br = new BufferRange(_drawState.IbStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4);
|
||||
|
||||
_channel.BufferManager.SetIndexBuffer(br, IndexType.UInt);
|
||||
|
||||
_context.Renderer.Pipeline.DrawIndexed(inlineIndexCount, 1, firstIndex, firstVertex, firstInstance);
|
||||
}
|
||||
else if (_drawState.DrawIndexed)
|
||||
{
|
||||
int firstVertex = (int)_state.State.FirstVertex;
|
||||
|
||||
_context.Renderer.Pipeline.DrawIndexed(indexCount, 1, firstIndex, firstVertex, firstInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
var drawState = _state.State.VertexBufferDrawState;
|
||||
|
||||
_context.Renderer.Pipeline.Draw(drawState.Count, 1, drawState.First, firstInstance);
|
||||
}
|
||||
|
||||
_drawState.DrawIndexed = false;
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||
{
|
||||
_context.Renderer.Pipeline.EndHostConditionalRendering();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts draw.
|
||||
/// This sets primitive type and instanced draw parameters.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawBegin(int argument)
|
||||
{
|
||||
bool incrementInstance = (argument & (1 << 26)) != 0;
|
||||
bool resetInstance = (argument & (1 << 27)) == 0;
|
||||
|
||||
if (_state.State.PrimitiveTypeOverrideEnable)
|
||||
{
|
||||
PrimitiveTypeOverride typeOverride = _state.State.PrimitiveTypeOverride;
|
||||
DrawBegin(incrementInstance, resetInstance, typeOverride.Convert());
|
||||
}
|
||||
else
|
||||
{
|
||||
PrimitiveType type = (PrimitiveType)(argument & 0xffff);
|
||||
DrawBegin(incrementInstance, resetInstance, type.Convert());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts draw.
|
||||
/// This sets primitive type and instanced draw parameters.
|
||||
/// </summary>
|
||||
/// <param name="incrementInstance">Indicates if the current instance should be incremented</param>
|
||||
/// <param name="resetInstance">Indicates if the current instance should be set to zero</param>
|
||||
/// <param name="topology">Primitive topology</param>
|
||||
private void DrawBegin(bool incrementInstance, bool resetInstance, PrimitiveTopology topology)
|
||||
{
|
||||
if (incrementInstance)
|
||||
{
|
||||
_instanceIndex++;
|
||||
}
|
||||
else if (resetInstance)
|
||||
{
|
||||
PerformDeferredDraws();
|
||||
|
||||
_instanceIndex = 0;
|
||||
}
|
||||
|
||||
_context.Renderer.Pipeline.SetPrimitiveTopology(topology);
|
||||
|
||||
_drawState.Topology = topology;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the index buffer count.
|
||||
/// This also sets internal state that indicates that the next draw is an indexed draw.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void SetIndexBufferCount(int argument)
|
||||
{
|
||||
_drawState.DrawIndexed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawIndexedSmall(ThreedClass engine, int argument)
|
||||
{
|
||||
DrawIndexedSmall(engine, argument, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawIndexedSmall2(ThreedClass engine, int argument)
|
||||
{
|
||||
DrawIndexedSmall(engine, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements,
|
||||
/// while also pre-incrementing the current instance value.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawIndexedSmallIncInstance(ThreedClass engine, int argument)
|
||||
{
|
||||
DrawIndexedSmall(engine, argument, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements,
|
||||
/// while also pre-incrementing the current instance value.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawIndexedSmallIncInstance2(ThreedClass engine, int argument)
|
||||
{
|
||||
DrawIndexedSmallIncInstance(engine, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements,
|
||||
/// while optionally also pre-incrementing the current instance value.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
/// <param name="instanced">True to increment the current instance value, false otherwise</param>
|
||||
private void DrawIndexedSmall(ThreedClass engine, int argument, bool instanced)
|
||||
{
|
||||
PrimitiveTypeOverride typeOverride = _state.State.PrimitiveTypeOverride;
|
||||
|
||||
DrawBegin(instanced, !instanced, typeOverride.Convert());
|
||||
|
||||
int firstIndex = argument & 0xffff;
|
||||
int indexCount = (argument >> 16) & 0xfff;
|
||||
|
||||
bool oldDrawIndexed = _drawState.DrawIndexed;
|
||||
|
||||
_drawState.DrawIndexed = true;
|
||||
|
||||
DrawEnd(engine, firstIndex, indexCount);
|
||||
|
||||
_drawState.DrawIndexed = oldDrawIndexed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform any deferred draws.
|
||||
/// This is used for instanced draws.
|
||||
/// Since each instance is a separate draw, we defer the draw and accumulate the instance count.
|
||||
/// Once we detect the last instanced draw, then we perform the host instanced draw,
|
||||
/// with the accumulated instance count.
|
||||
/// </summary>
|
||||
public void PerformDeferredDraws()
|
||||
{
|
||||
// Perform any pending instanced draw.
|
||||
if (_instancedDrawPending)
|
||||
{
|
||||
_instancedDrawPending = false;
|
||||
|
||||
if (_instancedIndexed)
|
||||
{
|
||||
_context.Renderer.Pipeline.DrawIndexed(
|
||||
_instancedIndexCount,
|
||||
_instanceIndex + 1,
|
||||
_instancedFirstIndex,
|
||||
_instancedFirstVertex,
|
||||
_instancedFirstInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.Renderer.Pipeline.Draw(
|
||||
_instancedDrawStateCount,
|
||||
_instanceIndex + 1,
|
||||
_instancedDrawStateFirst,
|
||||
_instancedFirstInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the current color and depth-stencil buffers.
|
||||
/// Which buffers should be cleared is also specified on the argument.
|
||||
/// </summary>
|
||||
/// <param name="engine">3D engine where this method is being called</param>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void Clear(ThreedClass engine, int argument)
|
||||
{
|
||||
ConditionalRenderEnabled renderEnable = ConditionalRendering.GetRenderEnable(
|
||||
_context,
|
||||
_channel.MemoryManager,
|
||||
_state.State.RenderEnableAddress,
|
||||
_state.State.RenderEnableCondition);
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.False)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Scissor and rasterizer discard also affect clears.
|
||||
engine.UpdateState((1UL << StateUpdater.RasterizerStateIndex) | (1UL << StateUpdater.ScissorStateIndex));
|
||||
|
||||
int index = (argument >> 6) & 0xf;
|
||||
|
||||
engine.UpdateRenderTargetState(useControl: false, singleUse: index);
|
||||
|
||||
_channel.TextureManager.UpdateRenderTargets();
|
||||
|
||||
bool clearDepth = (argument & 1) != 0;
|
||||
bool clearStencil = (argument & 2) != 0;
|
||||
|
||||
uint componentMask = (uint)((argument >> 2) & 0xf);
|
||||
|
||||
if (componentMask != 0)
|
||||
{
|
||||
var clearColor = _state.State.ClearColors;
|
||||
|
||||
ColorF color = new ColorF(clearColor.Red, clearColor.Green, clearColor.Blue, clearColor.Alpha);
|
||||
|
||||
_context.Renderer.Pipeline.ClearRenderTargetColor(index, componentMask, color);
|
||||
}
|
||||
|
||||
if (clearDepth || clearStencil)
|
||||
{
|
||||
float depthValue = _state.State.ClearDepthValue;
|
||||
int stencilValue = (int)_state.State.ClearStencilValue;
|
||||
|
||||
int stencilMask = 0;
|
||||
|
||||
if (clearStencil)
|
||||
{
|
||||
stencilMask = _state.State.StencilTestState.FrontMask;
|
||||
}
|
||||
|
||||
_context.Renderer.Pipeline.ClearRenderTargetDepthStencil(
|
||||
depthValue,
|
||||
clearDepth,
|
||||
stencilValue,
|
||||
stencilMask);
|
||||
}
|
||||
|
||||
engine.UpdateRenderTargetState(useControl: true);
|
||||
|
||||
if (renderEnable == ConditionalRenderEnabled.Host)
|
||||
{
|
||||
_context.Renderer.Pipeline.EndHostConditionalRendering();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
45
Ryujinx.Graphics.Gpu/Engine/Threed/DrawState.cs
Normal file
45
Ryujinx.Graphics.Gpu/Engine/Threed/DrawState.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
/// <summary>
|
||||
/// Draw state.
|
||||
/// </summary>
|
||||
class DrawState
|
||||
{
|
||||
/// <summary>
|
||||
/// First index to be used for the draw on the index buffer.
|
||||
/// </summary>
|
||||
public int FirstIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Number of indices to be used for the draw on the index buffer.
|
||||
/// </summary>
|
||||
public int IndexCount;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the next draw will be a indexed draw.
|
||||
/// </summary>
|
||||
public bool DrawIndexed;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if any of the currently used vertex shaders reads the instance ID.
|
||||
/// </summary>
|
||||
public bool VsUsesInstanceId;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if any of the currently used vertex buffers is instanced.
|
||||
/// </summary>
|
||||
public bool IsAnyVbInstanced;
|
||||
|
||||
/// <summary>
|
||||
/// Primitive topology for the next draw.
|
||||
/// </summary>
|
||||
public PrimitiveTopology Topology;
|
||||
|
||||
/// <summary>
|
||||
/// Index buffer data streamer for inline index buffer updates, such as those used in legacy OpenGL.
|
||||
/// </summary>
|
||||
public IbStreamer IbStreamer = new IbStreamer();
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL;
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds inline index buffer state.
|
||||
|
@ -15,6 +15,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
|
|||
private int _inlineIndexBufferSize;
|
||||
private int _inlineIndexCount;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if any index buffer data has been pushed.
|
||||
/// </summary>
|
||||
public bool HasInlineIndexData => _inlineIndexCount != 0;
|
||||
|
||||
/// <summary>
|
222
Ryujinx.Graphics.Gpu/Engine/Threed/SemaphoreUpdater.cs
Normal file
222
Ryujinx.Graphics.Gpu/Engine/Threed/SemaphoreUpdater.cs
Normal file
|
@ -0,0 +1,222 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
/// <summary>
|
||||
/// Semaphore updater.
|
||||
/// </summary>
|
||||
class SemaphoreUpdater
|
||||
{
|
||||
private const int NsToTicksFractionNumerator = 384;
|
||||
private const int NsToTicksFractionDenominator = 625;
|
||||
|
||||
/// <summary>
|
||||
/// GPU semaphore operation.
|
||||
/// </summary>
|
||||
private enum SemaphoreOperation
|
||||
{
|
||||
Release = 0,
|
||||
Acquire = 1,
|
||||
Counter = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Counter type for GPU counter reset.
|
||||
/// </summary>
|
||||
private enum ResetCounterType
|
||||
{
|
||||
SamplesPassed = 1,
|
||||
ZcullStats = 2,
|
||||
TransformFeedbackPrimitivesWritten = 0x10,
|
||||
InputVertices = 0x12,
|
||||
InputPrimitives = 0x13,
|
||||
VertexShaderInvocations = 0x15,
|
||||
TessControlShaderInvocations = 0x16,
|
||||
TessEvaluationShaderInvocations = 0x17,
|
||||
TessEvaluationShaderPrimitives = 0x18,
|
||||
GeometryShaderInvocations = 0x1a,
|
||||
GeometryShaderPrimitives = 0x1b,
|
||||
ClipperInputPrimitives = 0x1c,
|
||||
ClipperOutputPrimitives = 0x1d,
|
||||
FragmentShaderInvocations = 0x1e,
|
||||
PrimitivesGenerated = 0x1f
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Counter type for GPU counter reporting.
|
||||
/// </summary>
|
||||
private enum ReportCounterType
|
||||
{
|
||||
Zero = 0,
|
||||
InputVertices = 1,
|
||||
InputPrimitives = 3,
|
||||
VertexShaderInvocations = 5,
|
||||
GeometryShaderInvocations = 7,
|
||||
GeometryShaderPrimitives = 9,
|
||||
ZcullStats0 = 0xa,
|
||||
TransformFeedbackPrimitivesWritten = 0xb,
|
||||
ZcullStats1 = 0xc,
|
||||
ZcullStats2 = 0xe,
|
||||
ClipperInputPrimitives = 0xf,
|
||||
ZcullStats3 = 0x10,
|
||||
ClipperOutputPrimitives = 0x11,
|
||||
PrimitivesGenerated = 0x12,
|
||||
FragmentShaderInvocations = 0x13,
|
||||
SamplesPassed = 0x15,
|
||||
TransformFeedbackOffset = 0x1a,
|
||||
TessControlShaderInvocations = 0x1b,
|
||||
TessEvaluationShaderInvocations = 0x1d,
|
||||
TessEvaluationShaderPrimitives = 0x1f
|
||||
}
|
||||
|
||||
private readonly GpuContext _context;
|
||||
private readonly GpuChannel _channel;
|
||||
private readonly DeviceStateWithShadow<ThreedClassState> _state;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the semaphore updater.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context</param>
|
||||
/// <param name="channel">GPU channel</param>
|
||||
/// <param name="state">Channel state</param>
|
||||
public SemaphoreUpdater(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state)
|
||||
{
|
||||
_context = context;
|
||||
_channel = channel;
|
||||
_state = state;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the value of an internal GPU counter back to zero.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void ResetCounter(int argument)
|
||||
{
|
||||
ResetCounterType type = (ResetCounterType)argument;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ResetCounterType.SamplesPassed:
|
||||
_context.Renderer.ResetCounter(CounterType.SamplesPassed);
|
||||
break;
|
||||
case ResetCounterType.PrimitivesGenerated:
|
||||
_context.Renderer.ResetCounter(CounterType.PrimitivesGenerated);
|
||||
break;
|
||||
case ResetCounterType.TransformFeedbackPrimitivesWritten:
|
||||
_context.Renderer.ResetCounter(CounterType.TransformFeedbackPrimitivesWritten);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a GPU counter to guest memory.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void Report(int argument)
|
||||
{
|
||||
SemaphoreOperation op = (SemaphoreOperation)(argument & 3);
|
||||
ReportCounterType type = (ReportCounterType)((argument >> 23) & 0x1f);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case SemaphoreOperation.Release: ReleaseSemaphore(); break;
|
||||
case SemaphoreOperation.Counter: ReportCounter(type); break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes (or Releases) a GPU semaphore value to guest memory.
|
||||
/// </summary>
|
||||
private void ReleaseSemaphore()
|
||||
{
|
||||
_channel.MemoryManager.Write(_state.State.SemaphoreAddress.Pack(), _state.State.SemaphorePayload);
|
||||
|
||||
_context.AdvanceSequence();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Packed GPU counter data (including GPU timestamp) in memory.
|
||||
/// </summary>
|
||||
private struct CounterData
|
||||
{
|
||||
public ulong Counter;
|
||||
public ulong Timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a GPU counter to guest memory.
|
||||
/// This also writes the current timestamp value.
|
||||
/// </summary>
|
||||
/// <param name="type">Counter to be written to memory</param>
|
||||
private void ReportCounter(ReportCounterType type)
|
||||
{
|
||||
ulong gpuVa = _state.State.SemaphoreAddress.Pack();
|
||||
|
||||
ulong ticks = ConvertNanosecondsToTicks((ulong)PerformanceCounter.ElapsedNanoseconds);
|
||||
|
||||
if (GraphicsConfig.FastGpuTime)
|
||||
{
|
||||
// Divide by some amount to report time as if operations were performed faster than they really are.
|
||||
// This can prevent some games from switching to a lower resolution because rendering is too slow.
|
||||
ticks /= 256;
|
||||
}
|
||||
|
||||
ICounterEvent counter = null;
|
||||
|
||||
void resultHandler(object evt, ulong result)
|
||||
{
|
||||
CounterData counterData = new CounterData
|
||||
{
|
||||
Counter = result,
|
||||
Timestamp = ticks
|
||||
};
|
||||
|
||||
if (counter?.Invalid != true)
|
||||
{
|
||||
_channel.MemoryManager.Write(gpuVa, counterData);
|
||||
}
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ReportCounterType.Zero:
|
||||
resultHandler(null, 0);
|
||||
break;
|
||||
case ReportCounterType.SamplesPassed:
|
||||
counter = _context.Renderer.ReportCounter(CounterType.SamplesPassed, resultHandler);
|
||||
break;
|
||||
case ReportCounterType.PrimitivesGenerated:
|
||||
counter = _context.Renderer.ReportCounter(CounterType.PrimitivesGenerated, resultHandler);
|
||||
break;
|
||||
case ReportCounterType.TransformFeedbackPrimitivesWritten:
|
||||
counter = _context.Renderer.ReportCounter(CounterType.TransformFeedbackPrimitivesWritten, resultHandler);
|
||||
break;
|
||||
}
|
||||
|
||||
_channel.MemoryManager.CounterCache.AddOrUpdate(gpuVa, counter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a nanoseconds timestamp value to Maxwell time ticks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The frequency is 614400000 Hz.
|
||||
/// </remarks>
|
||||
/// <param name="nanoseconds">Timestamp in nanoseconds</param>
|
||||
/// <returns>Maxwell ticks</returns>
|
||||
private static ulong ConvertNanosecondsToTicks(ulong nanoseconds)
|
||||
{
|
||||
// We need to divide first to avoid overflows.
|
||||
// We fix up the result later by calculating the difference and adding
|
||||
// that to the result.
|
||||
ulong divided = nanoseconds / NsToTicksFractionDenominator;
|
||||
|
||||
ulong rounded = divided * NsToTicksFractionDenominator;
|
||||
|
||||
ulong errorBias = (nanoseconds - rounded) * NsToTicksFractionNumerator / NsToTicksFractionDenominator;
|
||||
|
||||
return divided * NsToTicksFractionNumerator + errorBias;
|
||||
}
|
||||
}
|
||||
}
|
166
Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs
Normal file
166
Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs
Normal file
|
@ -0,0 +1,166 @@
|
|||
using Ryujinx.Graphics.Device;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
/// <summary>
|
||||
/// State update callback entry, with the callback function and associated field names.
|
||||
/// </summary>
|
||||
struct StateUpdateCallbackEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Callback function, to be called if the register was written as the state needs to be updated.
|
||||
/// </summary>
|
||||
public Action Callback { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the state fields (registers) associated with the callback function.
|
||||
/// </summary>
|
||||
public string[] FieldNames { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new state update callback entry.
|
||||
/// </summary>
|
||||
/// <param name="callback">Callback function, to be called if the register was written as the state needs to be updated</param>
|
||||
/// <param name="fieldNames">Name of the state fields (registers) associated with the callback function</param>
|
||||
public StateUpdateCallbackEntry(Action callback, params string[] fieldNames)
|
||||
{
|
||||
Callback = callback;
|
||||
FieldNames = fieldNames;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GPU state update tracker.
|
||||
/// </summary>
|
||||
/// <typeparam name="TState">State type</typeparam>
|
||||
class StateUpdateTracker<TState>
|
||||
{
|
||||
private const int BlockSize = 0xe00;
|
||||
private const int RegisterSize = sizeof(uint);
|
||||
|
||||
private readonly byte[] _registerToGroupMapping;
|
||||
private readonly Action[] _callbacks;
|
||||
private ulong _dirtyMask;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the state update tracker.
|
||||
/// </summary>
|
||||
/// <param name="entries">Update tracker callback entries</param>
|
||||
public StateUpdateTracker(StateUpdateCallbackEntry[] entries)
|
||||
{
|
||||
_registerToGroupMapping = new byte[BlockSize];
|
||||
_callbacks = new Action[entries.Length];
|
||||
|
||||
var fieldToDelegate = new Dictionary<string, int>();
|
||||
|
||||
for (int entryIndex = 0; entryIndex < entries.Length; entryIndex++)
|
||||
{
|
||||
var entry = entries[entryIndex];
|
||||
|
||||
foreach (var fieldName in entry.FieldNames)
|
||||
{
|
||||
fieldToDelegate.Add(fieldName, entryIndex);
|
||||
}
|
||||
|
||||
_callbacks[entryIndex] = entry.Callback;
|
||||
}
|
||||
|
||||
var fields = typeof(TState).GetFields();
|
||||
int offset = 0;
|
||||
|
||||
for (int fieldIndex = 0; fieldIndex < fields.Length; fieldIndex++)
|
||||
{
|
||||
var field = fields[fieldIndex];
|
||||
|
||||
int sizeOfField = SizeCalculator.SizeOf(field.FieldType);
|
||||
|
||||
if (fieldToDelegate.TryGetValue(field.Name, out int entryIndex))
|
||||
{
|
||||
for (int i = 0; i < ((sizeOfField + 3) & ~3); i += 4)
|
||||
{
|
||||
_registerToGroupMapping[(offset + i) / RegisterSize] = (byte)(entryIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
offset += sizeOfField;
|
||||
}
|
||||
|
||||
Debug.Assert(offset == Unsafe.SizeOf<TState>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a register as modified.
|
||||
/// </summary>
|
||||
/// <param name="offset">Register offset in bytes</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void SetDirty(int offset)
|
||||
{
|
||||
uint index = (uint)offset / RegisterSize;
|
||||
|
||||
if (index < BlockSize)
|
||||
{
|
||||
int groupIndex = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_registerToGroupMapping), (IntPtr)index);
|
||||
if (groupIndex != 0)
|
||||
{
|
||||
groupIndex--;
|
||||
_dirtyMask |= 1UL << groupIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces a register group as dirty, by index.
|
||||
/// </summary>
|
||||
/// <param name="groupIndex">Index of the group to be dirtied</param>
|
||||
public void ForceDirty(int groupIndex)
|
||||
{
|
||||
if ((uint)groupIndex >= _callbacks.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(groupIndex));
|
||||
}
|
||||
|
||||
_dirtyMask |= 1UL << groupIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces all register groups as dirty, triggering a full update on the next call to <see cref="Update"/>.
|
||||
/// </summary>
|
||||
public void SetAllDirty()
|
||||
{
|
||||
Debug.Assert(_callbacks.Length <= sizeof(ulong) * 8);
|
||||
_dirtyMask = ulong.MaxValue >> ((sizeof(ulong) * 8) - _callbacks.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check all the groups specified by <paramref name="checkMask"/> for modification, and update if modified.
|
||||
/// </summary>
|
||||
/// <param name="checkMask">Mask, where each bit set corresponds to a group index that should be checked</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Update(ulong checkMask)
|
||||
{
|
||||
ulong mask = _dirtyMask & checkMask;
|
||||
if (mask == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
int groupIndex = BitOperations.TrailingZeroCount(mask);
|
||||
|
||||
_callbacks[groupIndex]();
|
||||
|
||||
mask &= ~(1UL << groupIndex);
|
||||
}
|
||||
while (mask != 0);
|
||||
|
||||
_dirtyMask &= ~checkMask;
|
||||
}
|
||||
}
|
||||
}
|
1044
Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
Normal file
1044
Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
Normal file
File diff suppressed because it is too large
Load diff
428
Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
Normal file
428
Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
Normal file
|
@ -0,0 +1,428 @@
|
|||
using Ryujinx.Graphics.Device;
|
||||
using Ryujinx.Graphics.Gpu.Engine.InlineToMemory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a 3D engine class.
|
||||
/// </summary>
|
||||
class ThreedClass : IDeviceState
|
||||
{
|
||||
private readonly GpuContext _context;
|
||||
private readonly DeviceStateWithShadow<ThreedClassState> _state;
|
||||
|
||||
private readonly InlineToMemoryClass _i2mClass;
|
||||
private readonly DrawManager _drawManager;
|
||||
private readonly SemaphoreUpdater _semaphoreUpdater;
|
||||
private readonly ConstantBufferUpdater _cbUpdater;
|
||||
private readonly StateUpdater _stateUpdater;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the 3D engine class.
|
||||
/// </summary>
|
||||
/// <param name="context">GPU context</param>
|
||||
/// <param name="channel">GPU channel</param>
|
||||
public ThreedClass(GpuContext context, GpuChannel channel)
|
||||
{
|
||||
_context = context;
|
||||
_state = new DeviceStateWithShadow<ThreedClassState>(new Dictionary<string, RwCallback>
|
||||
{
|
||||
{ nameof(ThreedClassState.LaunchDma), new RwCallback(LaunchDma, null) },
|
||||
{ nameof(ThreedClassState.LoadInlineData), new RwCallback(LoadInlineData, null) },
|
||||
{ nameof(ThreedClassState.SyncpointAction), new RwCallback(IncrementSyncpoint, null) },
|
||||
{ nameof(ThreedClassState.TextureBarrier), new RwCallback(TextureBarrier, null) },
|
||||
{ nameof(ThreedClassState.TextureBarrierTiled), new RwCallback(TextureBarrierTiled, null) },
|
||||
{ nameof(ThreedClassState.VbElementU8), new RwCallback(VbElementU8, null) },
|
||||
{ nameof(ThreedClassState.VbElementU16), new RwCallback(VbElementU16, null) },
|
||||
{ nameof(ThreedClassState.VbElementU32), new RwCallback(VbElementU32, null) },
|
||||
{ nameof(ThreedClassState.ResetCounter), new RwCallback(ResetCounter, null) },
|
||||
{ nameof(ThreedClassState.RenderEnableCondition), new RwCallback(null, Zero) },
|
||||
{ nameof(ThreedClassState.DrawEnd), new RwCallback(DrawEnd, null) },
|
||||
{ nameof(ThreedClassState.DrawBegin), new RwCallback(DrawBegin, null) },
|
||||
{ nameof(ThreedClassState.DrawIndexedSmall), new RwCallback(DrawIndexedSmall, null) },
|
||||
{ nameof(ThreedClassState.DrawIndexedSmall2), new RwCallback(DrawIndexedSmall2, null) },
|
||||
{ nameof(ThreedClassState.DrawIndexedSmallIncInstance), new RwCallback(DrawIndexedSmallIncInstance, null) },
|
||||
{ nameof(ThreedClassState.DrawIndexedSmallIncInstance2), new RwCallback(DrawIndexedSmallIncInstance2, null) },
|
||||
{ nameof(ThreedClassState.IndexBufferCount), new RwCallback(SetIndexBufferCount, null) },
|
||||
{ nameof(ThreedClassState.Clear), new RwCallback(Clear, null) },
|
||||
{ nameof(ThreedClassState.SemaphoreControl), new RwCallback(Report, null) },
|
||||
{ nameof(ThreedClassState.SetFalcon04), new RwCallback(SetFalcon04, null) },
|
||||
{ nameof(ThreedClassState.UniformBufferUpdateData), new RwCallback(ConstantBufferUpdate, null) },
|
||||
{ nameof(ThreedClassState.UniformBufferBindVertex), new RwCallback(ConstantBufferBindVertex, null) },
|
||||
{ nameof(ThreedClassState.UniformBufferBindTessControl), new RwCallback(ConstantBufferBindTessControl, null) },
|
||||
{ nameof(ThreedClassState.UniformBufferBindTessEvaluation), new RwCallback(ConstantBufferBindTessEvaluation, null) },
|
||||
{ nameof(ThreedClassState.UniformBufferBindGeometry), new RwCallback(ConstantBufferBindGeometry, null) },
|
||||
{ nameof(ThreedClassState.UniformBufferBindFragment), new RwCallback(ConstantBufferBindFragment, null) }
|
||||
});
|
||||
|
||||
_i2mClass = new InlineToMemoryClass(context, channel, initializeState: false);
|
||||
|
||||
var drawState = new DrawState();
|
||||
|
||||
_drawManager = new DrawManager(context, channel, _state, drawState);
|
||||
_semaphoreUpdater = new SemaphoreUpdater(context, channel, _state);
|
||||
_cbUpdater = new ConstantBufferUpdater(channel, _state);
|
||||
_stateUpdater = new StateUpdater(context, channel, _state, drawState);
|
||||
|
||||
// This defaults to "always", even without any register write.
|
||||
// Reads just return 0, regardless of what was set there.
|
||||
_state.State.RenderEnableCondition = Condition.Always;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads data from the class registers.
|
||||
/// </summary>
|
||||
/// <param name="offset">Register byte offset</param>
|
||||
/// <returns>Data at the specified offset</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int Read(int offset) => _state.Read(offset);
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to the class registers.
|
||||
/// </summary>
|
||||
/// <param name="offset">Register byte offset</param>
|
||||
/// <param name="data">Data to be written</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Write(int offset, int data)
|
||||
{
|
||||
_state.WriteWithRedundancyCheck(offset, data, out bool valueChanged);
|
||||
|
||||
if (valueChanged)
|
||||
{
|
||||
_stateUpdater.SetDirty(offset);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the shadow ram control value of all sub-channels.
|
||||
/// </summary>
|
||||
/// <param name="control">New shadow ram control value</param>
|
||||
public void SetShadowRamControl(int control)
|
||||
{
|
||||
_state.State.SetMmeShadowRamControl = (uint)control;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates current host state for all registers modified since the last call to this method.
|
||||
/// </summary>
|
||||
public void UpdateState()
|
||||
{
|
||||
_cbUpdater.FlushUboDirty();
|
||||
_stateUpdater.Update();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates current host state for all registers modified since the last call to this method.
|
||||
/// </summary>
|
||||
/// <param name="mask">Mask where each bit set indicates that the respective state group index should be checked</param>
|
||||
public void UpdateState(ulong mask)
|
||||
{
|
||||
_stateUpdater.Update(mask);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates render targets (color and depth-stencil buffers) based on current render target state.
|
||||
/// </summary>
|
||||
/// <param name="useControl">Use draw buffers information from render target control register</param>
|
||||
/// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param>
|
||||
public void UpdateRenderTargetState(bool useControl, int singleUse = -1)
|
||||
{
|
||||
_stateUpdater.UpdateRenderTargetState(useControl, singleUse);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks the entire state as dirty, forcing a full host state update before the next draw.
|
||||
/// </summary>
|
||||
public void ForceStateDirty()
|
||||
{
|
||||
_stateUpdater.SetAllDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces the shaders to be rebound on the next draw.
|
||||
/// </summary>
|
||||
public void ForceShaderUpdate()
|
||||
{
|
||||
_stateUpdater.ForceShaderUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes any queued UBO updates.
|
||||
/// </summary>
|
||||
public void FlushUboDirty()
|
||||
{
|
||||
_cbUpdater.FlushUboDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform any deferred draws.
|
||||
/// </summary>
|
||||
public void PerformDeferredDraws()
|
||||
{
|
||||
_drawManager.PerformDeferredDraws();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the currently bound constant buffer.
|
||||
/// </summary>
|
||||
/// <param name="data">Data to be written to the buffer</param>
|
||||
public void ConstantBufferUpdate(ReadOnlySpan<int> data)
|
||||
{
|
||||
_cbUpdater.Update(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Launches the Inline-to-Memory DMA copy operation.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void LaunchDma(int argument)
|
||||
{
|
||||
_i2mClass.LaunchDma(ref Unsafe.As<ThreedClassState, InlineToMemoryClassState>(ref _state.State), argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes a word of data to the Inline-to-Memory engine.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void LoadInlineData(int argument)
|
||||
{
|
||||
_i2mClass.LoadInlineData(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs an incrementation on a syncpoint.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void IncrementSyncpoint(int argument)
|
||||
{
|
||||
uint syncpointId = (uint)argument & 0xFFFF;
|
||||
|
||||
_context.CreateHostSyncIfNeeded();
|
||||
_context.Renderer.UpdateCounters(); // Poll the query counters, the game may want an updated result.
|
||||
_context.Synchronization.IncrementSyncpoint(syncpointId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Issues a texture barrier.
|
||||
/// This waits until previous texture writes from the GPU to finish, before
|
||||
/// performing new operations with said textures.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument (unused)</param>
|
||||
private void TextureBarrier(int argument)
|
||||
{
|
||||
_context.Renderer.Pipeline.TextureBarrier();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Issues a texture barrier.
|
||||
/// This waits until previous texture writes from the GPU to finish, before
|
||||
/// performing new operations with said textures.
|
||||
/// This performs a per-tile wait, it is only valid if both the previous write
|
||||
/// and current access has the same access patterns.
|
||||
/// This may be faster than the regular barrier on tile-based rasterizers.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument (unused)</param>
|
||||
private void TextureBarrierTiled(int argument)
|
||||
{
|
||||
_context.Renderer.Pipeline.TextureBarrierTiled();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes four 8-bit index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void VbElementU8(int argument)
|
||||
{
|
||||
_drawManager.VbElementU8(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes two 16-bit index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void VbElementU16(int argument)
|
||||
{
|
||||
_drawManager.VbElementU16(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes one 32-bit index buffer element.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void VbElementU32(int argument)
|
||||
{
|
||||
_drawManager.VbElementU32(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the value of an internal GPU counter back to zero.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void ResetCounter(int argument)
|
||||
{
|
||||
_semaphoreUpdater.ResetCounter(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finishes the draw call.
|
||||
/// This draws geometry on the bound buffers based on the current GPU state.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawEnd(int argument)
|
||||
{
|
||||
_drawManager.DrawEnd(this, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts draw.
|
||||
/// This sets primitive type and instanced draw parameters.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawBegin(int argument)
|
||||
{
|
||||
_drawManager.DrawBegin(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the index buffer count.
|
||||
/// This also sets internal state that indicates that the next draw is an indexed draw.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void SetIndexBufferCount(int argument)
|
||||
{
|
||||
_drawManager.SetIndexBufferCount(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawIndexedSmall(int argument)
|
||||
{
|
||||
_drawManager.DrawIndexedSmall(this, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawIndexedSmall2(int argument)
|
||||
{
|
||||
_drawManager.DrawIndexedSmall2(this, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements,
|
||||
/// while also pre-incrementing the current instance value.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawIndexedSmallIncInstance(int argument)
|
||||
{
|
||||
_drawManager.DrawIndexedSmallIncInstance(this, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a indexed draw with a low number of index buffer elements,
|
||||
/// while also pre-incrementing the current instance value.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void DrawIndexedSmallIncInstance2(int argument)
|
||||
{
|
||||
_drawManager.DrawIndexedSmallIncInstance2(this, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the current color and depth-stencil buffers.
|
||||
/// Which buffers should be cleared is also specified on the argument.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void Clear(int argument)
|
||||
{
|
||||
_drawManager.Clear(this, argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a GPU counter to guest memory.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void Report(int argument)
|
||||
{
|
||||
_semaphoreUpdater.Report(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs high-level emulation of Falcon microcode function number "4".
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void SetFalcon04(int argument)
|
||||
{
|
||||
_state.State.SetMmeShadowScratch[0] = 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the uniform buffer data with inline data.
|
||||
/// </summary>
|
||||
/// <param name="argument">New uniform buffer data word</param>
|
||||
private void ConstantBufferUpdate(int argument)
|
||||
{
|
||||
_cbUpdater.Update(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the vertex shader stage.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void ConstantBufferBindVertex(int argument)
|
||||
{
|
||||
_cbUpdater.BindVertex(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the tessellation control shader stage.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void ConstantBufferBindTessControl(int argument)
|
||||
{
|
||||
_cbUpdater.BindTessControl(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the tessellation evaluation shader stage.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void ConstantBufferBindTessEvaluation(int argument)
|
||||
{
|
||||
_cbUpdater.BindTessEvaluation(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the geometry shader stage.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void ConstantBufferBindGeometry(int argument)
|
||||
{
|
||||
_cbUpdater.BindGeometry(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds a uniform buffer for the fragment shader stage.
|
||||
/// </summary>
|
||||
/// <param name="argument">Method call argument</param>
|
||||
private void ConstantBufferBindFragment(int argument)
|
||||
{
|
||||
_cbUpdater.BindFragment(argument);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generic register read function that just returns 0.
|
||||
/// </summary>
|
||||
/// <returns>Zero</returns>
|
||||
private static int Zero()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
861
Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs
Normal file
861
Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs
Normal file
|
@ -0,0 +1,861 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Engine.InlineToMemory;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
/// <summary>
|
||||
/// Shader stage name.
|
||||
/// </summary>
|
||||
enum ShaderType
|
||||
{
|
||||
Vertex,
|
||||
TessellationControl,
|
||||
TessellationEvaluation,
|
||||
Geometry,
|
||||
Fragment
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transform feedback buffer state.
|
||||
/// </summary>
|
||||
struct TfBufferState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public Boolean32 Enable;
|
||||
public GpuVa Address;
|
||||
public int Size;
|
||||
public int Offset;
|
||||
public uint Padding0;
|
||||
public uint Padding1;
|
||||
public uint Padding2;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transform feedback state.
|
||||
/// </summary>
|
||||
struct TfState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public int BufferIndex;
|
||||
public int VaryingsCount;
|
||||
public int Stride;
|
||||
public uint Padding;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Render target color buffer state.
|
||||
/// </summary>
|
||||
struct RtColorState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public GpuVa Address;
|
||||
public int WidthOrStride;
|
||||
public int Height;
|
||||
public ColorFormat Format;
|
||||
public MemoryLayout MemoryLayout;
|
||||
public int Depth;
|
||||
public int LayerSize;
|
||||
public int BaseLayer;
|
||||
public int Unknown0x24;
|
||||
public int Padding0;
|
||||
public int Padding1;
|
||||
public int Padding2;
|
||||
public int Padding3;
|
||||
public int Padding4;
|
||||
public int Padding5;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Viewport transform parameters, for viewport transformation.
|
||||
/// </summary>
|
||||
struct ViewportTransform
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public float ScaleX;
|
||||
public float ScaleY;
|
||||
public float ScaleZ;
|
||||
public float TranslateX;
|
||||
public float TranslateY;
|
||||
public float TranslateZ;
|
||||
public uint Swizzle;
|
||||
public uint SubpixelPrecisionBias;
|
||||
#pragma warning restore CS0649
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks viewport swizzle of the position X component.
|
||||
/// </summary>
|
||||
/// <returns>Swizzle enum value</returns>
|
||||
public ViewportSwizzle UnpackSwizzleX()
|
||||
{
|
||||
return (ViewportSwizzle)(Swizzle & 7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks viewport swizzle of the position Y component.
|
||||
/// </summary>
|
||||
/// <returns>Swizzle enum value</returns>
|
||||
public ViewportSwizzle UnpackSwizzleY()
|
||||
{
|
||||
return (ViewportSwizzle)((Swizzle >> 4) & 7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks viewport swizzle of the position Z component.
|
||||
/// </summary>
|
||||
/// <returns>Swizzle enum value</returns>
|
||||
public ViewportSwizzle UnpackSwizzleZ()
|
||||
{
|
||||
return (ViewportSwizzle)((Swizzle >> 8) & 7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks viewport swizzle of the position W component.
|
||||
/// </summary>
|
||||
/// <returns>Swizzle enum value</returns>
|
||||
public ViewportSwizzle UnpackSwizzleW()
|
||||
{
|
||||
return (ViewportSwizzle)((Swizzle >> 12) & 7);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Viewport extents for viewport clipping, also includes depth range.
|
||||
/// </summary>
|
||||
struct ViewportExtents
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public ushort X;
|
||||
public ushort Width;
|
||||
public ushort Y;
|
||||
public ushort Height;
|
||||
public float DepthNear;
|
||||
public float DepthFar;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw state for non-indexed draws.
|
||||
/// </summary>
|
||||
struct VertexBufferDrawState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public int First;
|
||||
public int Count;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Color buffer clear color.
|
||||
/// </summary>
|
||||
struct ClearColors
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public float Red;
|
||||
public float Green;
|
||||
public float Blue;
|
||||
public float Alpha;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Depth bias (also called polygon offset) parameters.
|
||||
/// </summary>
|
||||
struct DepthBiasState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public Boolean32 PointEnable;
|
||||
public Boolean32 LineEnable;
|
||||
public Boolean32 FillEnable;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scissor state.
|
||||
/// </summary>
|
||||
struct ScissorState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public Boolean32 Enable;
|
||||
public ushort X1;
|
||||
public ushort X2;
|
||||
public ushort Y1;
|
||||
public ushort Y2;
|
||||
public uint Padding;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stencil test masks for back tests.
|
||||
/// </summary>
|
||||
struct StencilBackMasks
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public int FuncRef;
|
||||
public int Mask;
|
||||
public int FuncMask;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Render target depth-stencil buffer state.
|
||||
/// </summary>
|
||||
struct RtDepthStencilState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public GpuVa Address;
|
||||
public ZetaFormat Format;
|
||||
public MemoryLayout MemoryLayout;
|
||||
public int LayerSize;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Screen scissor state.
|
||||
/// </summary>
|
||||
struct ScreenScissorState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public ushort X;
|
||||
public ushort Width;
|
||||
public ushort Y;
|
||||
public ushort Height;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Vertex buffer attribute state.
|
||||
/// </summary>
|
||||
struct VertexAttribState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public uint Attribute;
|
||||
#pragma warning restore CS0649
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the index of the vertex buffer this attribute belongs to.
|
||||
/// </summary>
|
||||
/// <returns>Vertex buffer index</returns>
|
||||
public int UnpackBufferIndex()
|
||||
{
|
||||
return (int)(Attribute & 0x1f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the attribute constant flag.
|
||||
/// </summary>
|
||||
/// <returns>True if the attribute is constant, false otherwise</returns>
|
||||
public bool UnpackIsConstant()
|
||||
{
|
||||
return (Attribute & 0x40) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the offset, in bytes, of the attribute on the vertex buffer.
|
||||
/// </summary>
|
||||
/// <returns>Attribute offset in bytes</returns>
|
||||
public int UnpackOffset()
|
||||
{
|
||||
return (int)((Attribute >> 7) & 0x3fff);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the Maxwell attribute format integer.
|
||||
/// </summary>
|
||||
/// <returns>Attribute format integer</returns>
|
||||
public uint UnpackFormat()
|
||||
{
|
||||
return Attribute & 0x3fe00000;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Render target draw buffers control.
|
||||
/// </summary>
|
||||
struct RtControl
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public uint Packed;
|
||||
#pragma warning restore CS0649
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the number of active draw buffers.
|
||||
/// </summary>
|
||||
/// <returns>Number of active draw buffers</returns>
|
||||
public int UnpackCount()
|
||||
{
|
||||
return (int)(Packed & 0xf);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the color attachment index for a given draw buffer.
|
||||
/// </summary>
|
||||
/// <param name="index">Index of the draw buffer</param>
|
||||
/// <returns>Attachment index</returns>
|
||||
public int UnpackPermutationIndex(int index)
|
||||
{
|
||||
return (int)((Packed >> (4 + index * 3)) & 7);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 3D, 2D or 1D texture size.
|
||||
/// </summary>
|
||||
struct Size3D
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public int Width;
|
||||
public int Height;
|
||||
public int Depth;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stencil front test state and masks.
|
||||
/// </summary>
|
||||
struct StencilTestState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public Boolean32 Enable;
|
||||
public StencilOp FrontSFail;
|
||||
public StencilOp FrontDpFail;
|
||||
public StencilOp FrontDpPass;
|
||||
public CompareOp FrontFunc;
|
||||
public int FrontFuncRef;
|
||||
public int FrontFuncMask;
|
||||
public int FrontMask;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Screen Y control register.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
enum YControl
|
||||
{
|
||||
NegateY = 1 << 0,
|
||||
TriangleRastFlip = 1 << 4
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Condition for conditional rendering.
|
||||
/// </summary>
|
||||
enum Condition
|
||||
{
|
||||
Never,
|
||||
Always,
|
||||
ResultNonZero,
|
||||
Equal,
|
||||
NotEqual
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Texture or sampler pool state.
|
||||
/// </summary>
|
||||
struct PoolState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public GpuVa Address;
|
||||
public int MaximumId;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stencil back test state.
|
||||
/// </summary>
|
||||
struct StencilBackTestState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public Boolean32 TwoSided;
|
||||
public StencilOp BackSFail;
|
||||
public StencilOp BackDpFail;
|
||||
public StencilOp BackDpPass;
|
||||
public CompareOp BackFunc;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Primitive restart state.
|
||||
/// </summary>
|
||||
struct PrimitiveRestartState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public Boolean32 Enable;
|
||||
public int Index;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GPU index buffer state.
|
||||
/// This is used on indexed draws.
|
||||
/// </summary>
|
||||
struct IndexBufferState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public GpuVa Address;
|
||||
public GpuVa EndAddress;
|
||||
public IndexType Type;
|
||||
public int First;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Face culling and orientation parameters.
|
||||
/// </summary>
|
||||
struct FaceState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public Boolean32 CullEnable;
|
||||
public FrontFace FrontFace;
|
||||
public Face CullFace;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// View volume clip control.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
enum ViewVolumeClipControl
|
||||
{
|
||||
ForceDepthRangeZeroToOne = 1 << 0,
|
||||
DepthClampDisabled = 1 << 11
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logical operation state.
|
||||
/// </summary>
|
||||
struct LogicalOpState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public Boolean32 Enable;
|
||||
public LogicalOp LogicalOp;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Render target color buffer mask.
|
||||
/// This defines which color channels are written to the color buffer.
|
||||
/// </summary>
|
||||
struct RtColorMask
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public uint Packed;
|
||||
#pragma warning restore CS0649
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks red channel enable.
|
||||
/// </summary>
|
||||
/// <returns>True to write the new red channel color, false to keep the old value</returns>
|
||||
public bool UnpackRed()
|
||||
{
|
||||
return (Packed & 0x1) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks green channel enable.
|
||||
/// </summary>
|
||||
/// <returns>True to write the new green channel color, false to keep the old value</returns>
|
||||
public bool UnpackGreen()
|
||||
{
|
||||
return (Packed & 0x10) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks blue channel enable.
|
||||
/// </summary>
|
||||
/// <returns>True to write the new blue channel color, false to keep the old value</returns>
|
||||
public bool UnpackBlue()
|
||||
{
|
||||
return (Packed & 0x100) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks alpha channel enable.
|
||||
/// </summary>
|
||||
/// <returns>True to write the new alpha channel color, false to keep the old value</returns>
|
||||
public bool UnpackAlpha()
|
||||
{
|
||||
return (Packed & 0x1000) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Vertex buffer state.
|
||||
/// </summary>
|
||||
struct VertexBufferState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public uint Control;
|
||||
public GpuVa Address;
|
||||
public int Divisor;
|
||||
#pragma warning restore CS0649
|
||||
|
||||
/// <summary>
|
||||
/// Vertex buffer stride, defined as the number of bytes occupied by each vertex in memory.
|
||||
/// </summary>
|
||||
/// <returns>Vertex buffer stride</returns>
|
||||
public int UnpackStride()
|
||||
{
|
||||
return (int)(Control & 0xfff);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Vertex buffer enable.
|
||||
/// </summary>
|
||||
/// <returns>True if the vertex buffer is enabled, false otherwise</returns>
|
||||
public bool UnpackEnable()
|
||||
{
|
||||
return (Control & (1 << 12)) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Color buffer blending parameters, shared by all color buffers.
|
||||
/// </summary>
|
||||
struct BlendStateCommon
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public Boolean32 SeparateAlpha;
|
||||
public BlendOp ColorOp;
|
||||
public BlendFactor ColorSrcFactor;
|
||||
public BlendFactor ColorDstFactor;
|
||||
public BlendOp AlphaOp;
|
||||
public BlendFactor AlphaSrcFactor;
|
||||
public uint Unknown0x1354;
|
||||
public BlendFactor AlphaDstFactor;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Color buffer blending parameters.
|
||||
/// </summary>
|
||||
struct BlendState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public Boolean32 SeparateAlpha;
|
||||
public BlendOp ColorOp;
|
||||
public BlendFactor ColorSrcFactor;
|
||||
public BlendFactor ColorDstFactor;
|
||||
public BlendOp AlphaOp;
|
||||
public BlendFactor AlphaSrcFactor;
|
||||
public BlendFactor AlphaDstFactor;
|
||||
public uint Padding;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Graphics shader stage state.
|
||||
/// </summary>
|
||||
struct ShaderState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public uint Control;
|
||||
public uint Offset;
|
||||
public uint Unknown0x8;
|
||||
public int MaxRegisters;
|
||||
public ShaderType Type;
|
||||
public uint Unknown0x14;
|
||||
public uint Unknown0x18;
|
||||
public uint Unknown0x1c;
|
||||
public uint Unknown0x20;
|
||||
public uint Unknown0x24;
|
||||
public uint Unknown0x28;
|
||||
public uint Unknown0x2c;
|
||||
public uint Unknown0x30;
|
||||
public uint Unknown0x34;
|
||||
public uint Unknown0x38;
|
||||
public uint Unknown0x3c;
|
||||
#pragma warning restore CS0649
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks shader enable information.
|
||||
/// Must be ignored for vertex shaders, those are always enabled.
|
||||
/// </summary>
|
||||
/// <returns>True if the stage is enabled, false otherwise</returns>
|
||||
public bool UnpackEnable()
|
||||
{
|
||||
return (Control & 1) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uniform buffer state for the uniform buffer currently being modified.
|
||||
/// </summary>
|
||||
struct UniformBufferState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public int Size;
|
||||
public GpuVa Address;
|
||||
public int Offset;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
unsafe struct ThreedClassState : IShadowState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public uint SetObject;
|
||||
public int SetObjectClassId => (int)((SetObject >> 0) & 0xFFFF);
|
||||
public int SetObjectEngineId => (int)((SetObject >> 16) & 0x1F);
|
||||
public fixed uint Reserved04[63];
|
||||
public uint NoOperation;
|
||||
public uint SetNotifyA;
|
||||
public int SetNotifyAAddressUpper => (int)((SetNotifyA >> 0) & 0xFF);
|
||||
public uint SetNotifyB;
|
||||
public uint Notify;
|
||||
public NotifyType NotifyType => (NotifyType)(Notify);
|
||||
public uint WaitForIdle;
|
||||
public uint LoadMmeInstructionRamPointer;
|
||||
public uint LoadMmeInstructionRam;
|
||||
public uint LoadMmeStartAddressRamPointer;
|
||||
public uint LoadMmeStartAddressRam;
|
||||
public uint SetMmeShadowRamControl;
|
||||
public SetMmeShadowRamControlMode SetMmeShadowRamControlMode => (SetMmeShadowRamControlMode)((SetMmeShadowRamControl >> 0) & 0x3);
|
||||
public fixed uint Reserved128[2];
|
||||
public uint SetGlobalRenderEnableA;
|
||||
public int SetGlobalRenderEnableAOffsetUpper => (int)((SetGlobalRenderEnableA >> 0) & 0xFF);
|
||||
public uint SetGlobalRenderEnableB;
|
||||
public uint SetGlobalRenderEnableC;
|
||||
public int SetGlobalRenderEnableCMode => (int)((SetGlobalRenderEnableC >> 0) & 0x7);
|
||||
public uint SendGoIdle;
|
||||
public uint PmTrigger;
|
||||
public uint PmTriggerWfi;
|
||||
public fixed uint Reserved148[2];
|
||||
public uint SetInstrumentationMethodHeader;
|
||||
public uint SetInstrumentationMethodData;
|
||||
public fixed uint Reserved158[10];
|
||||
public uint LineLengthIn;
|
||||
public uint LineCount;
|
||||
public uint OffsetOutUpper;
|
||||
public int OffsetOutUpperValue => (int)((OffsetOutUpper >> 0) & 0xFF);
|
||||
public uint OffsetOut;
|
||||
public uint PitchOut;
|
||||
public uint SetDstBlockSize;
|
||||
public SetDstBlockSizeWidth SetDstBlockSizeWidth => (SetDstBlockSizeWidth)((SetDstBlockSize >> 0) & 0xF);
|
||||
public SetDstBlockSizeHeight SetDstBlockSizeHeight => (SetDstBlockSizeHeight)((SetDstBlockSize >> 4) & 0xF);
|
||||
public SetDstBlockSizeDepth SetDstBlockSizeDepth => (SetDstBlockSizeDepth)((SetDstBlockSize >> 8) & 0xF);
|
||||
public uint SetDstWidth;
|
||||
public uint SetDstHeight;
|
||||
public uint SetDstDepth;
|
||||
public uint SetDstLayer;
|
||||
public uint SetDstOriginBytesX;
|
||||
public int SetDstOriginBytesXV => (int)((SetDstOriginBytesX >> 0) & 0xFFFFF);
|
||||
public uint SetDstOriginSamplesY;
|
||||
public int SetDstOriginSamplesYV => (int)((SetDstOriginSamplesY >> 0) & 0xFFFF);
|
||||
public uint LaunchDma;
|
||||
public LaunchDmaDstMemoryLayout LaunchDmaDstMemoryLayout => (LaunchDmaDstMemoryLayout)((LaunchDma >> 0) & 0x1);
|
||||
public LaunchDmaCompletionType LaunchDmaCompletionType => (LaunchDmaCompletionType)((LaunchDma >> 4) & 0x3);
|
||||
public LaunchDmaInterruptType LaunchDmaInterruptType => (LaunchDmaInterruptType)((LaunchDma >> 8) & 0x3);
|
||||
public LaunchDmaSemaphoreStructSize LaunchDmaSemaphoreStructSize => (LaunchDmaSemaphoreStructSize)((LaunchDma >> 12) & 0x1);
|
||||
public bool LaunchDmaReductionEnable => (LaunchDma & 0x2) != 0;
|
||||
public LaunchDmaReductionOp LaunchDmaReductionOp => (LaunchDmaReductionOp)((LaunchDma >> 13) & 0x7);
|
||||
public LaunchDmaReductionFormat LaunchDmaReductionFormat => (LaunchDmaReductionFormat)((LaunchDma >> 2) & 0x3);
|
||||
public bool LaunchDmaSysmembarDisable => (LaunchDma & 0x40) != 0;
|
||||
public uint LoadInlineData;
|
||||
public fixed uint Reserved1B8[22];
|
||||
public Boolean32 EarlyZForce;
|
||||
public fixed uint Reserved214[45];
|
||||
public uint SyncpointAction;
|
||||
public fixed uint Reserved2CC[44];
|
||||
public Boolean32 RasterizeEnable;
|
||||
public Array4<TfBufferState> TfBufferState;
|
||||
public fixed uint Reserved400[192];
|
||||
public Array4<TfState> TfState;
|
||||
public fixed uint Reserved740[1];
|
||||
public Boolean32 TfEnable;
|
||||
public fixed uint Reserved748[46];
|
||||
public Array8<RtColorState> RtColorState;
|
||||
public Array16<ViewportTransform> ViewportTransform;
|
||||
public Array16<ViewportExtents> ViewportExtents;
|
||||
public fixed uint ReservedD00[29];
|
||||
public VertexBufferDrawState VertexBufferDrawState;
|
||||
public uint DepthMode;
|
||||
public ClearColors ClearColors;
|
||||
public float ClearDepthValue;
|
||||
public fixed uint ReservedD94[3];
|
||||
public uint ClearStencilValue;
|
||||
public fixed uint ReservedDA4[7];
|
||||
public DepthBiasState DepthBiasState;
|
||||
public fixed uint ReservedDCC[5];
|
||||
public uint TextureBarrier;
|
||||
public fixed uint ReservedDE4[7];
|
||||
public Array16<ScissorState> ScissorState;
|
||||
public fixed uint ReservedF00[21];
|
||||
public StencilBackMasks StencilBackMasks;
|
||||
public fixed uint ReservedF60[5];
|
||||
public uint InvalidateTextures;
|
||||
public fixed uint ReservedF78[1];
|
||||
public uint TextureBarrierTiled;
|
||||
public fixed uint ReservedF80[4];
|
||||
public Boolean32 RtColorMaskShared;
|
||||
public fixed uint ReservedF94[19];
|
||||
public RtDepthStencilState RtDepthStencilState;
|
||||
public ScreenScissorState ScreenScissorState;
|
||||
public fixed uint ReservedFFC[89];
|
||||
public Array16<VertexAttribState> VertexAttribState;
|
||||
public fixed uint Reserved11A0[31];
|
||||
public RtControl RtControl;
|
||||
public fixed uint Reserved1220[2];
|
||||
public Size3D RtDepthStencilSize;
|
||||
public SamplerIndex SamplerIndex;
|
||||
public fixed uint Reserved1238[37];
|
||||
public Boolean32 DepthTestEnable;
|
||||
public fixed uint Reserved12D0[5];
|
||||
public Boolean32 BlendIndependent;
|
||||
public Boolean32 DepthWriteEnable;
|
||||
public Boolean32 AlphaTestEnable;
|
||||
public fixed uint Reserved12F0[5];
|
||||
public uint VbElementU8;
|
||||
public uint Reserved1308;
|
||||
public CompareOp DepthTestFunc;
|
||||
public float AlphaTestRef;
|
||||
public CompareOp AlphaTestFunc;
|
||||
public uint Reserved1318;
|
||||
public ColorF BlendConstant;
|
||||
public fixed uint Reserved132C[4];
|
||||
public BlendStateCommon BlendStateCommon;
|
||||
public Boolean32 BlendEnableCommon;
|
||||
public Array8<Boolean32> BlendEnable;
|
||||
public StencilTestState StencilTestState;
|
||||
public fixed uint Reserved13A0[3];
|
||||
public YControl YControl;
|
||||
public float LineWidthSmooth;
|
||||
public float LineWidthAliased;
|
||||
public fixed uint Reserved13B8[31];
|
||||
public uint FirstVertex;
|
||||
public uint FirstInstance;
|
||||
public fixed uint Reserved143C[53];
|
||||
public uint ClipDistanceEnable;
|
||||
public uint Reserved1514;
|
||||
public float PointSize;
|
||||
public uint Reserved151C;
|
||||
public Boolean32 PointSpriteEnable;
|
||||
public fixed uint Reserved1524[3];
|
||||
public uint ResetCounter;
|
||||
public uint Reserved1534;
|
||||
public Boolean32 RtDepthStencilEnable;
|
||||
public fixed uint Reserved153C[5];
|
||||
public GpuVa RenderEnableAddress;
|
||||
public Condition RenderEnableCondition;
|
||||
public PoolState SamplerPoolState;
|
||||
public uint Reserved1568;
|
||||
public float DepthBiasFactor;
|
||||
public Boolean32 LineSmoothEnable;
|
||||
public PoolState TexturePoolState;
|
||||
public fixed uint Reserved1580[5];
|
||||
public StencilBackTestState StencilBackTestState;
|
||||
public fixed uint Reserved15A8[5];
|
||||
public float DepthBiasUnits;
|
||||
public fixed uint Reserved15C0[4];
|
||||
public TextureMsaaMode RtMsaaMode;
|
||||
public fixed uint Reserved15D4[5];
|
||||
public uint VbElementU32;
|
||||
public uint Reserved15EC;
|
||||
public uint VbElementU16;
|
||||
public fixed uint Reserved15F4[4];
|
||||
public uint PointCoordReplace;
|
||||
public GpuVa ShaderBaseAddress;
|
||||
public uint Reserved1610;
|
||||
public uint DrawEnd;
|
||||
public uint DrawBegin;
|
||||
public fixed uint Reserved161C[10];
|
||||
public PrimitiveRestartState PrimitiveRestartState;
|
||||
public fixed uint Reserved164C[95];
|
||||
public IndexBufferState IndexBufferState;
|
||||
public uint IndexBufferCount;
|
||||
public uint DrawIndexedSmall;
|
||||
public uint DrawIndexedSmall2;
|
||||
public uint Reserved17EC;
|
||||
public uint DrawIndexedSmallIncInstance;
|
||||
public uint DrawIndexedSmallIncInstance2;
|
||||
public fixed uint Reserved17F8[33];
|
||||
public float DepthBiasClamp;
|
||||
public Array16<Boolean32> VertexBufferInstanced;
|
||||
public fixed uint Reserved18C0[20];
|
||||
public Boolean32 VertexProgramPointSize;
|
||||
public uint Reserved1914;
|
||||
public FaceState FaceState;
|
||||
public fixed uint Reserved1924[2];
|
||||
public uint ViewportTransformEnable;
|
||||
public fixed uint Reserved1930[3];
|
||||
public ViewVolumeClipControl ViewVolumeClipControl;
|
||||
public fixed uint Reserved1940[2];
|
||||
public Boolean32 PrimitiveTypeOverrideEnable;
|
||||
public fixed uint Reserved194C[9];
|
||||
public PrimitiveTypeOverride PrimitiveTypeOverride;
|
||||
public fixed uint Reserved1974[20];
|
||||
public LogicalOpState LogicOpState;
|
||||
public uint Reserved19CC;
|
||||
public uint Clear;
|
||||
public fixed uint Reserved19D4[11];
|
||||
public Array8<RtColorMask> RtColorMask;
|
||||
public fixed uint Reserved1A20[56];
|
||||
public GpuVa SemaphoreAddress;
|
||||
public int SemaphorePayload;
|
||||
public uint SemaphoreControl;
|
||||
public fixed uint Reserved1B10[60];
|
||||
public Array16<VertexBufferState> VertexBufferState;
|
||||
public fixed uint Reserved1D00[64];
|
||||
public Array8<BlendState> BlendState;
|
||||
public Array16<GpuVa> VertexBufferEndAddress;
|
||||
public fixed uint Reserved1F80[32];
|
||||
public Array6<ShaderState> ShaderState;
|
||||
public fixed uint Reserved2180[96];
|
||||
public uint SetFalcon00;
|
||||
public uint SetFalcon01;
|
||||
public uint SetFalcon02;
|
||||
public uint SetFalcon03;
|
||||
public uint SetFalcon04;
|
||||
public uint SetFalcon05;
|
||||
public uint SetFalcon06;
|
||||
public uint SetFalcon07;
|
||||
public uint SetFalcon08;
|
||||
public uint SetFalcon09;
|
||||
public uint SetFalcon10;
|
||||
public uint SetFalcon11;
|
||||
public uint SetFalcon12;
|
||||
public uint SetFalcon13;
|
||||
public uint SetFalcon14;
|
||||
public uint SetFalcon15;
|
||||
public uint SetFalcon16;
|
||||
public uint SetFalcon17;
|
||||
public uint SetFalcon18;
|
||||
public uint SetFalcon19;
|
||||
public uint SetFalcon20;
|
||||
public uint SetFalcon21;
|
||||
public uint SetFalcon22;
|
||||
public uint SetFalcon23;
|
||||
public uint SetFalcon24;
|
||||
public uint SetFalcon25;
|
||||
public uint SetFalcon26;
|
||||
public uint SetFalcon27;
|
||||
public uint SetFalcon28;
|
||||
public uint SetFalcon29;
|
||||
public uint SetFalcon30;
|
||||
public uint SetFalcon31;
|
||||
public UniformBufferState UniformBufferState;
|
||||
public Array16<uint> UniformBufferUpdateData;
|
||||
public fixed uint Reserved23D0[16];
|
||||
public uint UniformBufferBindVertex;
|
||||
public fixed uint Reserved2414[7];
|
||||
public uint UniformBufferBindTessControl;
|
||||
public fixed uint Reserved2434[7];
|
||||
public uint UniformBufferBindTessEvaluation;
|
||||
public fixed uint Reserved2454[7];
|
||||
public uint UniformBufferBindGeometry;
|
||||
public fixed uint Reserved2474[7];
|
||||
public uint UniformBufferBindFragment;
|
||||
public fixed uint Reserved2494[93];
|
||||
public uint TextureBufferIndex;
|
||||
public fixed uint Reserved260C[125];
|
||||
public Array4<Array32<uint>> TfVaryingLocations;
|
||||
public fixed uint Reserved2A00[640];
|
||||
public MmeShadowScratch SetMmeShadowScratch;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
using Ryujinx.Graphics.Device;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
using Ryujinx.Graphics.Gpu.State;
|
||||
using Ryujinx.Graphics.Texture;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -52,8 +52,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Twod
|
|||
{
|
||||
var memoryManager = _channel.MemoryManager;
|
||||
|
||||
var dstCopyTexture = Unsafe.As<uint, CopyTexture>(ref _state.State.SetDstFormat);
|
||||
var srcCopyTexture = Unsafe.As<uint, CopyTexture>(ref _state.State.SetSrcFormat);
|
||||
var dstCopyTexture = Unsafe.As<uint, TwodTexture>(ref _state.State.SetDstFormat);
|
||||
var srcCopyTexture = Unsafe.As<uint, TwodTexture>(ref _state.State.SetSrcFormat);
|
||||
|
||||
long srcX = ((long)_state.State.SetPixelsFromMemorySrcX0Int << 32) | (long)(ulong)_state.State.SetPixelsFromMemorySrcX0Frac;
|
||||
long srcY = ((long)_state.State.PixelsFromMemorySrcY0Int << 32) | (long)(ulong)_state.State.SetPixelsFromMemorySrcY0Frac;
|
||||
|
|
|
@ -13,17 +13,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Twod
|
|||
WriteThenAwaken = 1,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MME shadow RAM control mode.
|
||||
/// </summary>
|
||||
enum SetMmeShadowRamControlMode
|
||||
{
|
||||
MethodTrack = 0,
|
||||
MethodTrackWithFilter = 1,
|
||||
MethodPassthrough = 2,
|
||||
MethodReplay = 3,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Format of the destination texture.
|
||||
/// </summary>
|
||||
|
@ -506,7 +495,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Twod
|
|||
/// <summary>
|
||||
/// 2D class state.
|
||||
/// </summary>
|
||||
unsafe struct TwodClassState
|
||||
unsafe struct TwodClassState : IShadowState
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public uint SetObject;
|
||||
|
|
22
Ryujinx.Graphics.Gpu/Engine/Twod/TwodTexture.cs
Normal file
22
Ryujinx.Graphics.Gpu/Engine/Twod/TwodTexture.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Twod
|
||||
{
|
||||
/// <summary>
|
||||
/// Texture to texture (with optional resizing) copy parameters.
|
||||
/// </summary>
|
||||
struct TwodTexture
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public ColorFormat Format;
|
||||
public Boolean32 LinearLayout;
|
||||
public MemoryLayout MemoryLayout;
|
||||
public int Depth;
|
||||
public int Layer;
|
||||
public int Stride;
|
||||
public int Width;
|
||||
public int Height;
|
||||
public GpuVa Address;
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
}
|
17
Ryujinx.Graphics.Gpu/Engine/Types/Boolean32.cs
Normal file
17
Ryujinx.Graphics.Gpu/Engine/Types/Boolean32.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
namespace Ryujinx.Graphics.Gpu.Engine.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Boolean value, stored as a 32-bits integer in memory.
|
||||
/// </summary>
|
||||
struct Boolean32
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
private uint _value;
|
||||
#pragma warning restore CS0649
|
||||
|
||||
public static implicit operator bool(Boolean32 value)
|
||||
{
|
||||
return (value._value & 1) != 0;
|
||||
}
|
||||
}
|
||||
}
|
134
Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs
Normal file
134
Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs
Normal file
|
@ -0,0 +1,134 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Color texture format.
|
||||
/// </summary>
|
||||
enum ColorFormat
|
||||
{
|
||||
R32G32B32A32Float = 0xc0,
|
||||
R32G32B32A32Sint = 0xc1,
|
||||
R32G32B32A32Uint = 0xc2,
|
||||
R32G32B32X32Float = 0xc3,
|
||||
R32G32B32X32Sint = 0xc4,
|
||||
R32G32B32X32Uint = 0xc5,
|
||||
R16G16B16X16Unorm = 0xc6,
|
||||
R16G16B16X16Snorm = 0xc7,
|
||||
R16G16B16X16Sint = 0xc8,
|
||||
R16G16B16X16Uint = 0xc9,
|
||||
R16G16B16A16Float = 0xca,
|
||||
R32G32Float = 0xcb,
|
||||
R32G32Sint = 0xcc,
|
||||
R32G32Uint = 0xcd,
|
||||
R16G16B16X16Float = 0xce,
|
||||
B8G8R8A8Unorm = 0xcf,
|
||||
B8G8R8A8Srgb = 0xd0,
|
||||
R10G10B10A2Unorm = 0xd1,
|
||||
R10G10B10A2Uint = 0xd2,
|
||||
R8G8B8A8Unorm = 0xd5,
|
||||
R8G8B8A8Srgb = 0xd6,
|
||||
R8G8B8X8Snorm = 0xd7,
|
||||
R8G8B8X8Sint = 0xd8,
|
||||
R8G8B8X8Uint = 0xd9,
|
||||
R16G16Unorm = 0xda,
|
||||
R16G16Snorm = 0xdb,
|
||||
R16G16Sint = 0xdc,
|
||||
R16G16Uint = 0xdd,
|
||||
R16G16Float = 0xde,
|
||||
R11G11B10Float = 0xe0,
|
||||
R32Sint = 0xe3,
|
||||
R32Uint = 0xe4,
|
||||
R32Float = 0xe5,
|
||||
B8G8R8X8Unorm = 0xe6,
|
||||
B8G8R8X8Srgb = 0xe7,
|
||||
B5G6R5Unorm = 0xe8,
|
||||
B5G5R5A1Unorm = 0xe9,
|
||||
R8G8Unorm = 0xea,
|
||||
R8G8Snorm = 0xeb,
|
||||
R8G8Sint = 0xec,
|
||||
R8G8Uint = 0xed,
|
||||
R16Unorm = 0xee,
|
||||
R16Snorm = 0xef,
|
||||
R16Sint = 0xf0,
|
||||
R16Uint = 0xf1,
|
||||
R16Float = 0xf2,
|
||||
R8Unorm = 0xf3,
|
||||
R8Snorm = 0xf4,
|
||||
R8Sint = 0xf5,
|
||||
R8Uint = 0xf6,
|
||||
B5G5R5X1Unorm = 0xf8,
|
||||
R8G8B8X8Unorm = 0xf9,
|
||||
R8G8B8X8Srgb = 0xfa
|
||||
}
|
||||
|
||||
static class ColorFormatConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts the color texture format to a host compatible format.
|
||||
/// </summary>
|
||||
/// <param name="format">Color format</param>
|
||||
/// <returns>Host compatible format enum value</returns>
|
||||
public static FormatInfo Convert(this ColorFormat format)
|
||||
{
|
||||
return format switch
|
||||
{
|
||||
ColorFormat.R32G32B32A32Float => new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16, 4),
|
||||
ColorFormat.R32G32B32A32Sint => new FormatInfo(Format.R32G32B32A32Sint, 1, 1, 16, 4),
|
||||
ColorFormat.R32G32B32A32Uint => new FormatInfo(Format.R32G32B32A32Uint, 1, 1, 16, 4),
|
||||
ColorFormat.R32G32B32X32Float => new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16, 4),
|
||||
ColorFormat.R32G32B32X32Sint => new FormatInfo(Format.R32G32B32A32Sint, 1, 1, 16, 4),
|
||||
ColorFormat.R32G32B32X32Uint => new FormatInfo(Format.R32G32B32A32Uint, 1, 1, 16, 4),
|
||||
ColorFormat.R16G16B16X16Unorm => new FormatInfo(Format.R16G16B16A16Unorm, 1, 1, 8, 4),
|
||||
ColorFormat.R16G16B16X16Snorm => new FormatInfo(Format.R16G16B16A16Snorm, 1, 1, 8, 4),
|
||||
ColorFormat.R16G16B16X16Sint => new FormatInfo(Format.R16G16B16A16Sint, 1, 1, 8, 4),
|
||||
ColorFormat.R16G16B16X16Uint => new FormatInfo(Format.R16G16B16A16Uint, 1, 1, 8, 4),
|
||||
ColorFormat.R16G16B16A16Float => new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8, 4),
|
||||
ColorFormat.R32G32Float => new FormatInfo(Format.R32G32Float, 1, 1, 8, 2),
|
||||
ColorFormat.R32G32Sint => new FormatInfo(Format.R32G32Sint, 1, 1, 8, 2),
|
||||
ColorFormat.R32G32Uint => new FormatInfo(Format.R32G32Uint, 1, 1, 8, 2),
|
||||
ColorFormat.R16G16B16X16Float => new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8, 4),
|
||||
ColorFormat.B8G8R8A8Unorm => new FormatInfo(Format.B8G8R8A8Unorm, 1, 1, 4, 4),
|
||||
ColorFormat.B8G8R8A8Srgb => new FormatInfo(Format.B8G8R8A8Srgb, 1, 1, 4, 4),
|
||||
ColorFormat.R10G10B10A2Unorm => new FormatInfo(Format.R10G10B10A2Unorm, 1, 1, 4, 4),
|
||||
ColorFormat.R10G10B10A2Uint => new FormatInfo(Format.R10G10B10A2Uint, 1, 1, 4, 4),
|
||||
ColorFormat.R8G8B8A8Unorm => new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4),
|
||||
ColorFormat.R8G8B8A8Srgb => new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4, 4),
|
||||
ColorFormat.R8G8B8X8Snorm => new FormatInfo(Format.R8G8B8A8Snorm, 1, 1, 4, 4),
|
||||
ColorFormat.R8G8B8X8Sint => new FormatInfo(Format.R8G8B8A8Sint, 1, 1, 4, 4),
|
||||
ColorFormat.R8G8B8X8Uint => new FormatInfo(Format.R8G8B8A8Uint, 1, 1, 4, 4),
|
||||
ColorFormat.R16G16Unorm => new FormatInfo(Format.R16G16Unorm, 1, 1, 4, 2),
|
||||
ColorFormat.R16G16Snorm => new FormatInfo(Format.R16G16Snorm, 1, 1, 4, 2),
|
||||
ColorFormat.R16G16Sint => new FormatInfo(Format.R16G16Sint, 1, 1, 4, 2),
|
||||
ColorFormat.R16G16Uint => new FormatInfo(Format.R16G16Uint, 1, 1, 4, 2),
|
||||
ColorFormat.R16G16Float => new FormatInfo(Format.R16G16Float, 1, 1, 4, 2),
|
||||
ColorFormat.R11G11B10Float => new FormatInfo(Format.R11G11B10Float, 1, 1, 4, 3),
|
||||
ColorFormat.R32Sint => new FormatInfo(Format.R32Sint, 1, 1, 4, 1),
|
||||
ColorFormat.R32Uint => new FormatInfo(Format.R32Uint, 1, 1, 4, 1),
|
||||
ColorFormat.R32Float => new FormatInfo(Format.R32Float, 1, 1, 4, 1),
|
||||
ColorFormat.B8G8R8X8Unorm => new FormatInfo(Format.B8G8R8A8Unorm, 1, 1, 4, 4),
|
||||
ColorFormat.B8G8R8X8Srgb => new FormatInfo(Format.B8G8R8A8Srgb, 1, 1, 4, 4),
|
||||
ColorFormat.B5G6R5Unorm => new FormatInfo(Format.B5G6R5Unorm, 1, 1, 2, 3),
|
||||
ColorFormat.B5G5R5A1Unorm => new FormatInfo(Format.B5G5R5A1Unorm, 1, 1, 2, 4),
|
||||
ColorFormat.R8G8Unorm => new FormatInfo(Format.R8G8Unorm, 1, 1, 2, 2),
|
||||
ColorFormat.R8G8Snorm => new FormatInfo(Format.R8G8Snorm, 1, 1, 2, 2),
|
||||
ColorFormat.R8G8Sint => new FormatInfo(Format.R8G8Sint, 1, 1, 2, 2),
|
||||
ColorFormat.R8G8Uint => new FormatInfo(Format.R8G8Uint, 1, 1, 2, 2),
|
||||
ColorFormat.R16Unorm => new FormatInfo(Format.R16Unorm, 1, 1, 2, 1),
|
||||
ColorFormat.R16Snorm => new FormatInfo(Format.R16Snorm, 1, 1, 2, 1),
|
||||
ColorFormat.R16Sint => new FormatInfo(Format.R16Sint, 1, 1, 2, 1),
|
||||
ColorFormat.R16Uint => new FormatInfo(Format.R16Uint, 1, 1, 2, 1),
|
||||
ColorFormat.R16Float => new FormatInfo(Format.R16Float, 1, 1, 2, 1),
|
||||
ColorFormat.R8Unorm => new FormatInfo(Format.R8Unorm, 1, 1, 1, 1),
|
||||
ColorFormat.R8Snorm => new FormatInfo(Format.R8Snorm, 1, 1, 1, 1),
|
||||
ColorFormat.R8Sint => new FormatInfo(Format.R8Sint, 1, 1, 1, 1),
|
||||
ColorFormat.R8Uint => new FormatInfo(Format.R8Uint, 1, 1, 1, 1),
|
||||
ColorFormat.B5G5R5X1Unorm => new FormatInfo(Format.B5G5R5X1Unorm, 1, 1, 2, 4),
|
||||
ColorFormat.R8G8B8X8Unorm => new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4),
|
||||
ColorFormat.R8G8B8X8Srgb => new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4, 4),
|
||||
_ => FormatInfo.Default
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
22
Ryujinx.Graphics.Gpu/Engine/Types/GpuVa.cs
Normal file
22
Ryujinx.Graphics.Gpu/Engine/Types/GpuVa.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
namespace Ryujinx.Graphics.Gpu.Engine.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Split GPU virtual address.
|
||||
/// </summary>
|
||||
struct GpuVa
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public uint High;
|
||||
public uint Low;
|
||||
#pragma warning restore CS0649
|
||||
|
||||
/// <summary>
|
||||
/// Packs the split address into a 64-bits address value.
|
||||
/// </summary>
|
||||
/// <returns>The 64-bits address value</returns>
|
||||
public ulong Pack()
|
||||
{
|
||||
return Low | ((ulong)High << 32);
|
||||
}
|
||||
}
|
||||
}
|
37
Ryujinx.Graphics.Gpu/Engine/Types/MemoryLayout.cs
Normal file
37
Ryujinx.Graphics.Gpu/Engine/Types/MemoryLayout.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
namespace Ryujinx.Graphics.Gpu.Engine.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Memory layout parameters, for block linear textures.
|
||||
/// </summary>
|
||||
struct MemoryLayout
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public uint Packed;
|
||||
#pragma warning restore CS0649
|
||||
|
||||
public int UnpackGobBlocksInX()
|
||||
{
|
||||
return 1 << (int)(Packed & 0xf);
|
||||
}
|
||||
|
||||
public int UnpackGobBlocksInY()
|
||||
{
|
||||
return 1 << (int)((Packed >> 4) & 0xf);
|
||||
}
|
||||
|
||||
public int UnpackGobBlocksInZ()
|
||||
{
|
||||
return 1 << (int)((Packed >> 8) & 0xf);
|
||||
}
|
||||
|
||||
public bool UnpackIsLinear()
|
||||
{
|
||||
return (Packed & 0x1000) != 0;
|
||||
}
|
||||
|
||||
public bool UnpackIsTarget3D()
|
||||
{
|
||||
return (Packed & 0x10000) != 0;
|
||||
}
|
||||
}
|
||||
}
|
99
Ryujinx.Graphics.Gpu/Engine/Types/PrimitiveType.cs
Normal file
99
Ryujinx.Graphics.Gpu/Engine/Types/PrimitiveType.cs
Normal file
|
@ -0,0 +1,99 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Draw primitive type.
|
||||
/// </summary>
|
||||
enum PrimitiveType
|
||||
{
|
||||
Points,
|
||||
Lines,
|
||||
LineLoop,
|
||||
LineStrip,
|
||||
Triangles,
|
||||
TriangleStrip,
|
||||
TriangleFan,
|
||||
Quads,
|
||||
QuadStrip,
|
||||
Polygon,
|
||||
LinesAdjacency,
|
||||
LineStripAdjacency,
|
||||
TrianglesAdjacency,
|
||||
TriangleStripAdjacency,
|
||||
Patches
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Alternative primitive type that might override <see cref="PrimitiveType"/>.
|
||||
/// </summary>
|
||||
enum PrimitiveTypeOverride
|
||||
{
|
||||
Points = 1,
|
||||
Lines = 2,
|
||||
LineStrip = 3,
|
||||
Triangles = 4,
|
||||
TriangleStrip = 5,
|
||||
TriangleFan = 0x1015,
|
||||
LinesAdjacency = 10,
|
||||
LineStripAdjacency = 11,
|
||||
TrianglesAdjacency = 12,
|
||||
TriangleStripAdjacency = 13,
|
||||
Patches = 14
|
||||
}
|
||||
|
||||
static class PrimitiveTypeConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts the primitive type into something that can be used with the host API.
|
||||
/// </summary>
|
||||
/// <param name="type">The primitive type to convert</param>
|
||||
/// <returns>A host compatible enum value</returns>
|
||||
public static PrimitiveTopology Convert(this PrimitiveType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
PrimitiveType.Points => PrimitiveTopology.Points,
|
||||
PrimitiveType.Lines => PrimitiveTopology.Lines,
|
||||
PrimitiveType.LineLoop => PrimitiveTopology.LineLoop,
|
||||
PrimitiveType.LineStrip => PrimitiveTopology.LineStrip,
|
||||
PrimitiveType.Triangles => PrimitiveTopology.Triangles,
|
||||
PrimitiveType.TriangleStrip => PrimitiveTopology.TriangleStrip,
|
||||
PrimitiveType.TriangleFan => PrimitiveTopology.TriangleFan,
|
||||
PrimitiveType.Quads => PrimitiveTopology.Quads,
|
||||
PrimitiveType.QuadStrip => PrimitiveTopology.QuadStrip,
|
||||
PrimitiveType.Polygon => PrimitiveTopology.Polygon,
|
||||
PrimitiveType.LinesAdjacency => PrimitiveTopology.LinesAdjacency,
|
||||
PrimitiveType.LineStripAdjacency => PrimitiveTopology.LineStripAdjacency,
|
||||
PrimitiveType.TrianglesAdjacency => PrimitiveTopology.TrianglesAdjacency,
|
||||
PrimitiveType.TriangleStripAdjacency => PrimitiveTopology.TriangleStripAdjacency,
|
||||
PrimitiveType.Patches => PrimitiveTopology.Patches,
|
||||
_ => PrimitiveTopology.Triangles
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the primitive type into something that can be used with the host API.
|
||||
/// </summary>
|
||||
/// <param name="type">The primitive type to convert</param>
|
||||
/// <returns>A host compatible enum value</returns>
|
||||
public static PrimitiveTopology Convert(this PrimitiveTypeOverride type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
PrimitiveTypeOverride.Points => PrimitiveTopology.Points,
|
||||
PrimitiveTypeOverride.Lines => PrimitiveTopology.Lines,
|
||||
PrimitiveTypeOverride.LineStrip => PrimitiveTopology.LineStrip,
|
||||
PrimitiveTypeOverride.Triangles => PrimitiveTopology.Triangles,
|
||||
PrimitiveTypeOverride.TriangleStrip => PrimitiveTopology.TriangleStrip,
|
||||
PrimitiveTypeOverride.TriangleFan => PrimitiveTopology.TriangleFan,
|
||||
PrimitiveTypeOverride.LinesAdjacency => PrimitiveTopology.LinesAdjacency,
|
||||
PrimitiveTypeOverride.LineStripAdjacency => PrimitiveTopology.LineStripAdjacency,
|
||||
PrimitiveTypeOverride.TrianglesAdjacency => PrimitiveTopology.TrianglesAdjacency,
|
||||
PrimitiveTypeOverride.TriangleStripAdjacency => PrimitiveTopology.TriangleStripAdjacency,
|
||||
PrimitiveTypeOverride.Patches => PrimitiveTopology.Patches,
|
||||
_ => PrimitiveTopology.Triangles
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
11
Ryujinx.Graphics.Gpu/Engine/Types/SamplerIndex.cs
Normal file
11
Ryujinx.Graphics.Gpu/Engine/Types/SamplerIndex.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace Ryujinx.Graphics.Gpu.Engine.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Sampler pool indexing mode.
|
||||
/// </summary>
|
||||
enum SamplerIndex
|
||||
{
|
||||
Independently = 0,
|
||||
ViaHeaderIndex = 1
|
||||
}
|
||||
}
|
20
Ryujinx.Graphics.Gpu/Engine/Types/SbDescriptor.cs
Normal file
20
Ryujinx.Graphics.Gpu/Engine/Types/SbDescriptor.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
namespace Ryujinx.Graphics.Gpu.Engine.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Storage buffer address and size information.
|
||||
/// </summary>
|
||||
struct SbDescriptor
|
||||
{
|
||||
#pragma warning disable CS0649
|
||||
public uint AddressLow;
|
||||
public uint AddressHigh;
|
||||
public int Size;
|
||||
public int Padding;
|
||||
#pragma warning restore CS0649
|
||||
|
||||
public ulong PackAddress()
|
||||
{
|
||||
return AddressLow | ((ulong)AddressHigh << 32);
|
||||
}
|
||||
}
|
||||
}
|
42
Ryujinx.Graphics.Gpu/Engine/Types/ZetaFormat.cs
Normal file
42
Ryujinx.Graphics.Gpu/Engine/Types/ZetaFormat.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Image;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Depth-stencil texture format.
|
||||
/// </summary>
|
||||
enum ZetaFormat
|
||||
{
|
||||
D32Float = 0xa,
|
||||
D16Unorm = 0x13,
|
||||
D24UnormS8Uint = 0x14,
|
||||
D24Unorm = 0x15,
|
||||
S8UintD24Unorm = 0x16,
|
||||
S8Uint = 0x17,
|
||||
D32FloatS8Uint = 0x19
|
||||
}
|
||||
|
||||
static class ZetaFormatConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts the depth-stencil texture format to a host compatible format.
|
||||
/// </summary>
|
||||
/// <param name="format">Depth-stencil format</param>
|
||||
/// <returns>Host compatible format enum value</returns>
|
||||
public static FormatInfo Convert(this ZetaFormat format)
|
||||
{
|
||||
return format switch
|
||||
{
|
||||
ZetaFormat.D32Float => new FormatInfo(Format.D32Float, 1, 1, 4, 1),
|
||||
ZetaFormat.D16Unorm => new FormatInfo(Format.D16Unorm, 1, 1, 2, 1),
|
||||
ZetaFormat.D24UnormS8Uint => new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4, 2),
|
||||
ZetaFormat.D24Unorm => new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4, 1),
|
||||
ZetaFormat.S8UintD24Unorm => new FormatInfo(Format.D24UnormS8Uint, 1, 1, 4, 2),
|
||||
ZetaFormat.S8Uint => new FormatInfo(Format.S8Uint, 1, 1, 1, 1),
|
||||
ZetaFormat.D32FloatS8Uint => new FormatInfo(Format.D32FloatS8Uint, 1, 1, 8, 2),
|
||||
_ => FormatInfo.Default
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue