aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2021-07-11 17:20:40 -0300
committerGitHub <noreply@github.com>2021-07-11 17:20:40 -0300
commit40b21cc3c4d2622bbd4f88d43073341854d9a671 (patch)
tree6e9dc6a42e7c0bae5b03db468481771d5a6937ef
parentb5190f16810eb77388c861d1d1773e19644808db (diff)
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
-rw-r--r--Ryujinx.Graphics.Device/AccessControl.cs10
-rw-r--r--Ryujinx.Graphics.Device/DeviceState.cs124
-rw-r--r--Ryujinx.Graphics.Device/RegisterAttribute.cs15
-rw-r--r--Ryujinx.Graphics.Device/SizeCalculator.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/ClassId.cs14
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs38
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Compute/ComputeQmd.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/ConditionalRenderEnabled.cs3
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/DeviceStateWithShadow.cs95
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs15
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Dma/DmaTexture.cs20
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs7
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs176
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs134
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs12
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MME/IMacroEE.cs6
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MME/Macro.cs4
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MME/MacroInterpreter.cs22
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MME/MacroJit.cs4
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MME/MacroJitCompiler.cs6
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MME/MacroJitContext.cs12
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MethodClear.cs85
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs343
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MethodFirmware.cs12
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MethodIncrementSyncpoint.cs21
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MethodReport.cs131
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MethodResetCounter.cs31
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferBind.cs85
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs88
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Methods.cs1138
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/MmeShadowScratch.cs3
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/SetMmeShadowRamControlMode.cs13
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/ConditionalRendering.cs (renamed from Ryujinx.Graphics.Gpu/Engine/MethodConditionalRendering.cs)58
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/ConstantBufferUpdater.cs173
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs410
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/DrawState.cs45
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/IbStreamer.cs (renamed from Ryujinx.Graphics.Gpu/Engine/IbStreamer.cs)5
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/SemaphoreUpdater.cs222
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs166
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs1044
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs428
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs861
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs6
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Twod/TwodClassState.cs13
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Twod/TwodTexture.cs22
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Types/Boolean32.cs (renamed from Ryujinx.Graphics.Gpu/State/Boolean32.cs)2
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs (renamed from Ryujinx.Graphics.Gpu/State/ColorFormat.cs)2
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Types/GpuVa.cs (renamed from Ryujinx.Graphics.Gpu/State/GpuVa.cs)2
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Types/MemoryLayout.cs (renamed from Ryujinx.Graphics.Gpu/State/MemoryLayout.cs)2
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Types/PrimitiveType.cs (renamed from Ryujinx.Graphics.Gpu/State/PrimitiveType.cs)3
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Types/SamplerIndex.cs (renamed from Ryujinx.Graphics.Gpu/State/SamplerIndex.cs)2
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Types/SbDescriptor.cs (renamed from Ryujinx.Graphics.Gpu/State/SbDescriptor.cs)2
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Types/ZetaFormat.cs (renamed from Ryujinx.Graphics.Gpu/State/ZetaFormat.cs)2
-rw-r--r--Ryujinx.Graphics.Gpu/GpuChannel.cs11
-rw-r--r--Ryujinx.Graphics.Gpu/GpuContext.cs8
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureCache.cs9
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureManager.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferCache.cs1
-rw-r--r--Ryujinx.Graphics.Gpu/MethodParams.cs52
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs34
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs16
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs61
-rw-r--r--Ryujinx.Graphics.Gpu/ShadowRamControl.cs28
-rw-r--r--Ryujinx.Graphics.Gpu/State/BlendState.cs31
-rw-r--r--Ryujinx.Graphics.Gpu/State/BlendStateCommon.cs31
-rw-r--r--Ryujinx.Graphics.Gpu/State/ClearColors.cs15
-rw-r--r--Ryujinx.Graphics.Gpu/State/Condition.cs14
-rw-r--r--Ryujinx.Graphics.Gpu/State/ConditionState.cs13
-rw-r--r--Ryujinx.Graphics.Gpu/State/CopyBufferTexture.cs18
-rw-r--r--Ryujinx.Graphics.Gpu/State/CopyRegion.cs19
-rw-r--r--Ryujinx.Graphics.Gpu/State/CopyTexture.cs20
-rw-r--r--Ryujinx.Graphics.Gpu/State/DepthBiasState.cs14
-rw-r--r--Ryujinx.Graphics.Gpu/State/FaceState.cs16
-rw-r--r--Ryujinx.Graphics.Gpu/State/GpuState.cs477
-rw-r--r--Ryujinx.Graphics.Gpu/State/GpuStateTable.cs87
-rw-r--r--Ryujinx.Graphics.Gpu/State/IndexBufferState.cs19
-rw-r--r--Ryujinx.Graphics.Gpu/State/Inline2MemoryParams.cs22
-rw-r--r--Ryujinx.Graphics.Gpu/State/LogicalOpState.cs12
-rw-r--r--Ryujinx.Graphics.Gpu/State/MethodOffset.cs134
-rw-r--r--Ryujinx.Graphics.Gpu/State/PoolState.cs13
-rw-r--r--Ryujinx.Graphics.Gpu/State/PrimitiveRestartState.cs13
-rw-r--r--Ryujinx.Graphics.Gpu/State/ReportCounterType.cs29
-rw-r--r--Ryujinx.Graphics.Gpu/State/ResetCounterType.cs24
-rw-r--r--Ryujinx.Graphics.Gpu/State/RtColorMask.cs49
-rw-r--r--Ryujinx.Graphics.Gpu/State/RtColorState.cs26
-rw-r--r--Ryujinx.Graphics.Gpu/State/RtControl.cs31
-rw-r--r--Ryujinx.Graphics.Gpu/State/RtDepthStencilState.cs15
-rw-r--r--Ryujinx.Graphics.Gpu/State/ScissorState.cs14
-rw-r--r--Ryujinx.Graphics.Gpu/State/ScreenScissorState.cs12
-rw-r--r--Ryujinx.Graphics.Gpu/State/SemaphoreOperation.cs12
-rw-r--r--Ryujinx.Graphics.Gpu/State/SemaphoreState.cs14
-rw-r--r--Ryujinx.Graphics.Gpu/State/ShaderState.cs37
-rw-r--r--Ryujinx.Graphics.Gpu/State/ShaderType.cs14
-rw-r--r--Ryujinx.Graphics.Gpu/State/Size3D.cs14
-rw-r--r--Ryujinx.Graphics.Gpu/State/StencilBackMasks.cs14
-rw-r--r--Ryujinx.Graphics.Gpu/State/StencilBackTestState.cs18
-rw-r--r--Ryujinx.Graphics.Gpu/State/StencilTestState.cs21
-rw-r--r--Ryujinx.Graphics.Gpu/State/TfBufferState.cs18
-rw-r--r--Ryujinx.Graphics.Gpu/State/TfState.cs15
-rw-r--r--Ryujinx.Graphics.Gpu/State/UniformBufferState.cs14
-rw-r--r--Ryujinx.Graphics.Gpu/State/VertexAttribState.cs48
-rw-r--r--Ryujinx.Graphics.Gpu/State/VertexBufferDrawState.cs13
-rw-r--r--Ryujinx.Graphics.Gpu/State/VertexBufferState.cs32
-rw-r--r--Ryujinx.Graphics.Gpu/State/ViewVolumeClipControl.cs11
-rw-r--r--Ryujinx.Graphics.Gpu/State/ViewportExtents.cs17
-rw-r--r--Ryujinx.Graphics.Gpu/State/ViewportTransform.cs57
-rw-r--r--Ryujinx.Graphics.Gpu/State/YControl.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs2
-rw-r--r--Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/ChannelInitialization.cs1361
-rw-r--r--Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs2
111 files changed, 5260 insertions, 4018 deletions
diff --git a/Ryujinx.Graphics.Device/AccessControl.cs b/Ryujinx.Graphics.Device/AccessControl.cs
deleted file mode 100644
index 02203783..00000000
--- a/Ryujinx.Graphics.Device/AccessControl.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace Ryujinx.Graphics.Device
-{
- public enum AccessControl
- {
- None = 0,
- ReadOnly = 1 << 0,
- WriteOnly = 1 << 1,
- ReadWrite = ReadOnly | WriteOnly
- }
-}
diff --git a/Ryujinx.Graphics.Device/DeviceState.cs b/Ryujinx.Graphics.Device/DeviceState.cs
index 1001d295..18100571 100644
--- a/Ryujinx.Graphics.Device/DeviceState.cs
+++ b/Ryujinx.Graphics.Device/DeviceState.cs
@@ -1,10 +1,8 @@
using System;
-using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Linq;
-using System.Reflection;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Device
{
@@ -14,28 +12,22 @@ namespace Ryujinx.Graphics.Device
public TState State;
- private readonly BitArray _readableRegisters;
- private readonly BitArray _writableRegisters;
+ private uint Size => (uint)(Unsafe.SizeOf<TState>() + RegisterSize - 1) / RegisterSize;
- private readonly Dictionary<int, Func<int>> _readCallbacks;
- private readonly Dictionary<int, Action<int>> _writeCallbacks;
+ private readonly Func<int>[] _readCallbacks;
+ private readonly Action<int>[] _writeCallbacks;
- private readonly Dictionary<int, string> _fieldNamesForDebug;
+ private readonly Dictionary<uint, string> _fieldNamesForDebug;
private readonly Action<string> _debugLogCallback;
public DeviceState(IReadOnlyDictionary<string, RwCallback> callbacks = null, Action<string> debugLogCallback = null)
{
- int size = (Unsafe.SizeOf<TState>() + RegisterSize - 1) / RegisterSize;
-
- _readableRegisters = new BitArray(size);
- _writableRegisters = new BitArray(size);
-
- _readCallbacks = new Dictionary<int, Func<int>>();
- _writeCallbacks = new Dictionary<int, Action<int>>();
+ _readCallbacks = new Func<int>[Size];
+ _writeCallbacks = new Action<int>[Size];
if (debugLogCallback != null)
{
- _fieldNamesForDebug = new Dictionary<int, string>();
+ _fieldNamesForDebug = new Dictionary<uint, string>();
_debugLogCallback = debugLogCallback;
}
@@ -45,32 +37,30 @@ namespace Ryujinx.Graphics.Device
for (int fieldIndex = 0; fieldIndex < fields.Length; fieldIndex++)
{
var field = fields[fieldIndex];
- var regAttr = field.GetCustomAttributes<RegisterAttribute>(false).FirstOrDefault();
int sizeOfField = SizeCalculator.SizeOf(field.FieldType);
for (int i = 0; i < ((sizeOfField + 3) & ~3); i += 4)
{
- _readableRegisters[(offset + i) / RegisterSize] = regAttr?.AccessControl.HasFlag(AccessControl.ReadOnly) ?? true;
- _writableRegisters[(offset + i) / RegisterSize] = regAttr?.AccessControl.HasFlag(AccessControl.WriteOnly) ?? true;
- }
-
- if (callbacks != null && callbacks.TryGetValue(field.Name, out var cb))
- {
- if (cb.Read != null)
- {
- _readCallbacks.Add(offset, cb.Read);
- }
+ int index = (offset + i) / RegisterSize;
- if (cb.Write != null)
+ if (callbacks != null && callbacks.TryGetValue(field.Name, out var cb))
{
- _writeCallbacks.Add(offset, cb.Write);
+ if (cb.Read != null)
+ {
+ _readCallbacks[index] = cb.Read;
+ }
+
+ if (cb.Write != null)
+ {
+ _writeCallbacks[index] = cb.Write;
+ }
}
}
if (debugLogCallback != null)
{
- _fieldNamesForDebug.Add(offset, field.Name);
+ _fieldNamesForDebug.Add((uint)offset, field.Name);
}
offset += sizeOfField;
@@ -79,48 +69,71 @@ namespace Ryujinx.Graphics.Device
Debug.Assert(offset == Unsafe.SizeOf<TState>());
}
- public virtual int Read(int offset)
+ public int Read(int offset)
{
- if (Check(offset) && _readableRegisters[offset / RegisterSize])
+ uint index = (uint)offset / RegisterSize;
+
+ if (index < Size)
{
- int alignedOffset = Align(offset);
+ uint alignedOffset = index * RegisterSize;
- if (_readCallbacks.TryGetValue(alignedOffset, out Func<int> read))
+ var readCallback = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_readCallbacks), (IntPtr)index);
+ if (readCallback != null)
{
- return read();
+ return readCallback();
}
else
{
- return GetRef<int>(alignedOffset);
+ return GetRefUnchecked<int>(alignedOffset);
}
}
return 0;
}
- public virtual void Write(int offset, int data)
+ public void Write(int offset, int data)
{
- if (Check(offset) && _writableRegisters[offset / RegisterSize])
+ uint index = (uint)offset / RegisterSize;
+
+ if (index < Size)
{
- int alignedOffset = Align(offset);
+ uint alignedOffset = index * RegisterSize;
+ DebugWrite(alignedOffset, data);
- if (_fieldNamesForDebug != null && _fieldNamesForDebug.TryGetValue(alignedOffset, out string fieldName))
- {
- _debugLogCallback($"{typeof(TState).Name}.{fieldName} = 0x{data:X}");
- }
+ GetRefIntAlignedUncheck(index) = data;
- GetRef<int>(alignedOffset) = data;
+ Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_writeCallbacks), (IntPtr)index)?.Invoke(data);
+ }
+ }
- if (_writeCallbacks.TryGetValue(alignedOffset, out Action<int> write))
- {
- write(data);
- }
+ public void WriteWithRedundancyCheck(int offset, int data, out bool changed)
+ {
+ uint index = (uint)offset / RegisterSize;
+
+ if (index < Size)
+ {
+ uint alignedOffset = index * RegisterSize;
+ DebugWrite(alignedOffset, data);
+
+ ref var storage = ref GetRefIntAlignedUncheck(index);
+ changed = storage != data;
+ storage = data;
+
+ Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_writeCallbacks), (IntPtr)index)?.Invoke(data);
+ }
+ else
+ {
+ changed = false;
}
}
- private bool Check(int offset)
+ [Conditional("DEBUG")]
+ private void DebugWrite(uint alignedOffset, int data)
{
- return (uint)Align(offset) < Unsafe.SizeOf<TState>();
+ if (_fieldNamesForDebug != null && _fieldNamesForDebug.TryGetValue(alignedOffset, out string fieldName))
+ {
+ _debugLogCallback($"{typeof(TState).Name}.{fieldName} = 0x{data:X}");
+ }
}
public ref T GetRef<T>(int offset) where T : unmanaged
@@ -130,12 +143,19 @@ namespace Ryujinx.Graphics.Device
throw new ArgumentOutOfRangeException(nameof(offset));
}
+ return ref GetRefUnchecked<T>((uint)offset);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private ref T GetRefUnchecked<T>(uint offset) where T : unmanaged
+ {
return ref Unsafe.As<TState, T>(ref Unsafe.AddByteOffset(ref State, (IntPtr)offset));
}
- private static int Align(int offset)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private ref int GetRefIntAlignedUncheck(ulong index)
{
- return offset & ~(RegisterSize - 1);
+ return ref Unsafe.Add(ref Unsafe.As<TState, int>(ref State), (IntPtr)index);
}
}
}
diff --git a/Ryujinx.Graphics.Device/RegisterAttribute.cs b/Ryujinx.Graphics.Device/RegisterAttribute.cs
deleted file mode 100644
index 6e198963..00000000
--- a/Ryujinx.Graphics.Device/RegisterAttribute.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-
-namespace Ryujinx.Graphics.Device
-{
- [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
- public sealed class RegisterAttribute : Attribute
- {
- public AccessControl AccessControl { get; }
-
- public RegisterAttribute(AccessControl ac)
- {
- AccessControl = ac;
- }
- }
-}
diff --git a/Ryujinx.Graphics.Device/SizeCalculator.cs b/Ryujinx.Graphics.Device/SizeCalculator.cs
index 7cc48915..7409c041 100644
--- a/Ryujinx.Graphics.Device/SizeCalculator.cs
+++ b/Ryujinx.Graphics.Device/SizeCalculator.cs
@@ -3,7 +3,7 @@ using System.Reflection;
namespace Ryujinx.Graphics.Device
{
- static class SizeCalculator
+ public static class SizeCalculator
{
public static int SizeOf(Type type)
{
diff --git a/Ryujinx.Graphics.Gpu/ClassId.cs b/Ryujinx.Graphics.Gpu/ClassId.cs
index 97f1e32b..4e475a24 100644
--- a/Ryujinx.Graphics.Gpu/ClassId.cs
+++ b/Ryujinx.Graphics.Gpu/ClassId.cs
@@ -3,13 +3,13 @@ namespace Ryujinx.Graphics.Gpu
/// <summary>
/// GPU engine class ID.
/// </summary>
- enum ClassId
+ public enum ClassId
{
- Engine2D = 0x902d,
- Engine3D = 0xb197,
- EngineCompute = 0xb1c0,
- EngineInline2Memory = 0xa140,
- EngineDma = 0xb0b5,
- EngineGpfifo = 0xb06f
+ Twod = 0x902d,
+ Threed = 0xb197,
+ Compute = 0xb1c0,
+ InlineToMemory = 0xa140,
+ Dma = 0xb0b5,
+ GPFifo = 0xb06f
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs b/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
index 5d1fd2c0..ac8b1186 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
@@ -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)
+ {
+ _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)
{
- LaunchDma(ref Unsafe.As<ComputeClassState, InlineToMemoryClassState>(ref _state.State), 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();
}
}
}
diff --git a/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeQmd.cs b/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeQmd.cs
index a1116074..1b20e41c 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeQmd.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeQmd.cs
@@ -1,4 +1,4 @@
-using Ryujinx.Graphics.Gpu.State;
+using Ryujinx.Graphics.Gpu.Engine.Types;
using System;
using System.Runtime.CompilerServices;
diff --git a/Ryujinx.Graphics.Gpu/Engine/ConditionalRenderEnabled.cs b/Ryujinx.Graphics.Gpu/Engine/ConditionalRenderEnabled.cs
index 451f4963..5581b5cc 100644
--- a/Ryujinx.Graphics.Gpu/Engine/ConditionalRenderEnabled.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/ConditionalRenderEnabled.cs
@@ -1,5 +1,8 @@
namespace Ryujinx.Graphics.Gpu.Engine
{
+ /// <summary>
+ /// Conditional rendering enable.
+ /// </summary>
enum ConditionalRenderEnabled
{
False,
diff --git a/Ryujinx.Graphics.Gpu/Engine/DeviceStateWithShadow.cs b/Ryujinx.Graphics.Gpu/Engine/DeviceStateWithShadow.cs
new file mode 100644
index 00000000..3a06bc2a
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Engine/DeviceStateWithShadow.cs
@@ -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);
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs b/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs
index 58fa2326..70909168 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs
@@ -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;
diff --git a/Ryujinx.Graphics.Gpu/Engine/Dma/DmaTexture.cs b/Ryujinx.Graphics.Gpu/Engine/Dma/DmaTexture.cs
new file mode 100644
index 00000000..6873ff40
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Engine/Dma/DmaTexture.cs
@@ -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
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs b/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs
index 75b19c37..28822f4e 100644
--- a/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoClass.cs
@@ -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);
}
diff --git a/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs b/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs
index c2727f48..dd5e6fe5 100644
--- a/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs
@@ -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,67 +152,124 @@ 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)
- {
- _subChannels[meth.SubChannel].ClearCallbacks();
-
- _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)
+ if (offset < 0x60)
{
- _subChannels[meth.SubChannel].CallMethod(meth);
+ _fifoClass.Write(offset * 4, argument);
}
- else
+ else if (offset < 0xe00)
{
- int macroIndex = (meth.Method >> 1) & MacroIndexMask;
+ offset *= 4;
- if ((meth.Method & 1) != 0)
+ switch (subChannel)
{
- _fifoClass.MmePushArgument(macroIndex, meth.Argument);
+ 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
+ }
+ else
+ {
+ IDeviceState state = subChannel switch
{
- _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;
+
+ if ((offset & 1) != 0)
+ {
+ _fifoClass.MmePushArgument(macroIndex, argument);
+ }
+ else
+ {
+ _fifoClass.MmeStart(macroIndex, argument);
+ }
- _context.Methods.PerformDeferredDraws();
+ if (isLastCall)
+ {
+ _fifoClass.CallMme(macroIndex, state);
+
+ _3dClass.PerformDeferredDraws();
+ }
}
}
}
/// <summary>
- /// Sets the shadow ram control value of all sub-channels.
+ /// Writes data directly to the state of the specified class.
/// </summary>
- /// <param name="control">New shadow ram control value</param>
- public void SetShadowRamControl(ShadowRamControl control)
+ /// <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)
{
- for (int i = 0; i < _subChannels.Length; i++)
+ switch (classId)
{
- _subChannels[i].ShadowRamControl = control;
+ 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(int control)
+ {
+ _3dClass.SetShadowRamControl(control);
+ }
+
+ /// <summary>
/// Forces a full host state update by marking all state as modified,
/// and also requests all GPU resources in use to be rebound.
/// </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();
}
}
}
diff --git a/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs b/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs
deleted file mode 100644
index 3d23b785..00000000
--- a/Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs
+++ /dev/null
@@ -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();
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs b/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
index 0e7d6fb0..cb4133ec 100644
--- a/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/InlineToMemory/InlineToMemoryClass.cs
@@ -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)
{
diff --git a/Ryujinx.Graphics.Gpu/Engine/MME/IMacroEE.cs b/Ryujinx.Graphics.Gpu/Engine/MME/IMacroEE.cs
index b056ecc8..b957de08 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MME/IMacroEE.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MME/IMacroEE.cs
@@ -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);
}
}
diff --git a/Ryujinx.Graphics.Gpu/Engine/MME/Macro.cs b/Ryujinx.Graphics.Gpu/Engine/MME/Macro.cs
index 9847f4c0..1a79afb9 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MME/Macro.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MME/Macro.cs
@@ -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)
{
diff --git a/Ryujinx.Graphics.Gpu/Engine/MME/MacroInterpreter.cs b/Ryujinx.Graphics.Gpu/Engine/MME/MacroInterpreter.cs
index 9a834ca6..0173a7fb 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MME/MacroInterpreter.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MME/MacroInterpreter.cs
@@ -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;
}
diff --git a/Ryujinx.Graphics.Gpu/Engine/MME/MacroJit.cs b/Ryujinx.Graphics.Gpu/Engine/MME/MacroJit.cs
index 346ae6cf..f0393dd1 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MME/MacroJit.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MME/MacroJit.cs
@@ -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)
{
diff --git a/Ryujinx.Graphics.Gpu/Engine/MME/MacroJitCompiler.cs b/Ryujinx.Graphics.Gpu/Engine/MME/MacroJitCompiler.cs
index e752b9dc..d281a75a 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MME/MacroJitCompiler.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MME/MacroJitCompiler.cs
@@ -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.
diff --git a/Ryujinx.Graphics.Gpu/Engine/MME/MacroJitContext.cs b/Ryujinx.Graphics.Gpu/Engine/MME/MacroJitContext.cs
index ba426dc0..aa31c9ee 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MME/MacroJitContext.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MME/MacroJitContext.cs
@@ -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);
}
}
}
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodClear.cs b/Ryujinx.Graphics.Gpu/Engine/MethodClear.cs
deleted file mode 100644
index 5f6316dc..00000000
--- a/Ryujinx.Graphics.Gpu/Engine/MethodClear.cs
+++ /dev/null
@@ -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();
- }
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs b/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs
deleted file mode 100644
index fec1cc46..00000000
--- a/Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs
+++ /dev/null
@@ -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);
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodFirmware.cs b/Ryujinx.Graphics.Gpu/Engine/MethodFirmware.cs
deleted file mode 100644
index 25a48af9..00000000
--- a/Ryujinx.Graphics.Gpu/Engine/MethodFirmware.cs
+++ /dev/null
@@ -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);
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodIncrementSyncpoint.cs b/Ryujinx.Graphics.Gpu/Engine/MethodIncrementSyncpoint.cs
deleted file mode 100644
index 9c22275d..00000000
--- a/Ryujinx.Graphics.Gpu/Engine/MethodIncrementSyncpoint.cs
+++ /dev/null
@@ -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);
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodReport.cs b/Ryujinx.Graphics.Gpu/Engine/MethodReport.cs
deleted file mode 100644
index 2dd0bbfa..00000000
--- a/Ryujinx.Graphics.Gpu/Engine/MethodReport.cs
+++ /dev/null
@@ -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;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodResetCounter.cs b/Ryujinx.Graphics.Gpu/Engine/MethodResetCounter.cs
deleted file mode 100644
index 79f8e1e8..00000000
--- a/Ryujinx.Graphics.Gpu/Engine/MethodResetCounter.cs
+++ /dev/null
@@ -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;
- }
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferBind.cs b/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferBind.cs
deleted file mode 100644
index 0746efa5..00000000
--- a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferBind.cs
+++ /dev/null
@@ -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);
- }
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs b/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs
deleted file mode 100644
index 49c8cda4..00000000
--- a/Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs
+++ /dev/null
@@ -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);
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
deleted file mode 100644
index 756d56d9..00000000
--- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs
+++ /dev/null
@@ -1,1138 +0,0 @@
-using Ryujinx.Common.Logging;
-using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Gpu.Image;
-using Ryujinx.Graphics.Gpu.Memory;
-using Ryujinx.Graphics.Gpu.Shader;
-using Ryujinx.Graphics.Gpu.State;
-using Ryujinx.Graphics.Shader;
-using Ryujinx.Graphics.Texture;
-using System;
-using System.Linq;
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.Graphics.Gpu.Engine
-{
- using Texture = Image.Texture;
-
- /// <summary>
- /// GPU method implementations.
- /// </summary>
- partial class Methods
- {
- private readonly GpuContext _context;
- private readonly ShaderProgramInfo[] _currentProgramInfo;
-
- private bool _isAnyVbInstanced;
- private bool _vsUsesInstanceId;
- private byte _vsClipDistancesWritten;
-
- private bool _forceShaderUpdate;
-
- private bool _prevTfEnable;
-
- /// <summary>
- /// Creates a new instance of the GPU methods class.
- /// </summary>
- /// <param name="context">GPU context</param>
- public Methods(GpuContext context)
- {
- _context = context;
-
- _currentProgramInfo = new ShaderProgramInfo[Constants.ShaderStages];
- }
-
- /// <summary>
- /// Register callback for GPU method calls that triggers an action on the GPU.
- /// </summary>
- /// <param name="state">GPU state where the triggers will be registered</param>
- public void RegisterCallbacks(GpuState state)
- {
- state.RegisterCallback(MethodOffset.LaunchDma, LaunchDma);
- state.RegisterCallback(MethodOffset.LoadInlineData, LoadInlineData);
-
- state.RegisterCallback(MethodOffset.SyncpointAction, IncrementSyncpoint);
-
- state.RegisterCallback(MethodOffset.TextureBarrier, TextureBarrier);
- state.RegisterCallback(MethodOffset.TextureBarrierTiled, TextureBarrierTiled);
-
- state.RegisterCallback(MethodOffset.VbElementU8, VbElementU8);
- state.RegisterCallback(MethodOffset.VbElementU16, VbElementU16);
- state.RegisterCallback(MethodOffset.VbElementU32, VbElementU32);
-
- state.RegisterCallback(MethodOffset.ResetCounter, ResetCounter);
-
- state.RegisterCallback(MethodOffset.DrawEnd, DrawEnd);
- state.RegisterCallback(MethodOffset.DrawBegin, DrawBegin);
- state.RegisterCallback(MethodOffset.DrawIndexedSmall, DrawIndexedSmall);
- state.RegisterCallback(MethodOffset.DrawIndexedSmall2, DrawIndexedSmall2);
- state.RegisterCallback(MethodOffset.DrawIndexedSmallIncInstance, DrawIndexedSmallIncInstance);
- state.RegisterCallback(MethodOffset.DrawIndexedSmallIncInstance2, DrawIndexedSmallIncInstance2);
-
- state.RegisterCallback(MethodOffset.IndexBufferCount, SetIndexBufferCount);
-
- state.RegisterCallback(MethodOffset.Clear, Clear);
-
- state.RegisterCallback(MethodOffset.Report, Report);
-
- state.RegisterCallback(MethodOffset.FirmwareCall4, FirmwareCall4);
-
- state.RegisterCallback(MethodOffset.UniformBufferUpdateData, 16, UniformBufferUpdate);
-
- state.RegisterCallback(MethodOffset.UniformBufferBindVertex, UniformBufferBindVertex);
- state.RegisterCallback(MethodOffset.UniformBufferBindTessControl, UniformBufferBindTessControl);
- state.RegisterCallback(MethodOffset.UniformBufferBindTessEvaluation, UniformBufferBindTessEvaluation);
- state.RegisterCallback(MethodOffset.UniformBufferBindGeometry, UniformBufferBindGeometry);
- state.RegisterCallback(MethodOffset.UniformBufferBindFragment, UniformBufferBindFragment);
- }
-
- /// <summary>
- /// Updates host state based on the current guest GPU state.
- /// </summary>
- /// <param name="state">Guest 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 UpdateState(GpuState state, int firstIndex, int indexCount)
- {
- bool tfEnable = state.Get<Boolean32>(MethodOffset.TfEnable);
-
- if (!tfEnable && _prevTfEnable)
- {
- _context.Renderer.Pipeline.EndTransformFeedback();
- _prevTfEnable = false;
- }
-
- FlushUboDirty(state.Channel.MemoryManager);
-
- // Shaders must be the first one to be updated if modified, because
- // some of the other state depends on information from the currently
- // bound shaders.
- if (state.QueryModified(MethodOffset.ShaderBaseAddress, MethodOffset.ShaderState) || _forceShaderUpdate)
- {
- _forceShaderUpdate = false;
-
- UpdateShaderState(state);
- }
-
- if (state.QueryModified(MethodOffset.TfBufferState))
- {
- UpdateTfBufferState(state);
- }
-
- if (state.QueryModified(MethodOffset.ClipDistanceEnable))
- {
- UpdateUserClipState(state);
- }
-
- if (state.QueryModified(MethodOffset.RasterizeEnable))
- {
- UpdateRasterizerState(state);
- }
-
- if (state.QueryModified(MethodOffset.RtColorState,
- MethodOffset.RtDepthStencilState,
- MethodOffset.RtControl,
- MethodOffset.RtDepthStencilSize,
- MethodOffset.RtDepthStencilEnable))
- {
- UpdateRenderTargetState(state, useControl: true);
- }
-
- if (state.QueryModified(MethodOffset.ScissorState))
- {
- UpdateScissorState(state);
- }
-
- if (state.QueryModified(MethodOffset.ViewVolumeClipControl))
- {
- UpdateDepthClampState(state);
- }
-
- if (state.QueryModified(MethodOffset.AlphaTestEnable,
- MethodOffset.AlphaTestRef,
- MethodOffset.AlphaTestFunc))
- {
- UpdateAlphaTestState(state);
- }
-
- if (state.QueryModified(MethodOffset.DepthTestEnable,
- MethodOffset.DepthWriteEnable,
- MethodOffset.DepthTestFunc))
- {
- UpdateDepthTestState(state);
- }
-
- if (state.QueryModified(MethodOffset.DepthMode,
- MethodOffset.ViewportTransform,
- MethodOffset.ViewportExtents))
- {
- UpdateViewportTransform(state);
- }
-
- if (state.QueryModified(MethodOffset.DepthBiasState,
- MethodOffset.DepthBiasFactor,
- MethodOffset.DepthBiasUnits,
- MethodOffset.DepthBiasClamp))
- {
- UpdateDepthBiasState(state);
- }
-
- if (state.QueryModified(MethodOffset.StencilBackMasks,
- MethodOffset.StencilTestState,
- MethodOffset.StencilBackTestState))
- {
- UpdateStencilTestState(state);
- }
-
- // Pools.
- if (state.QueryModified(MethodOffset.SamplerPoolState, MethodOffset.SamplerIndex))
- {
- UpdateSamplerPoolState(state);
- }
-
- if (state.QueryModified(MethodOffset.TexturePoolState))
- {
- UpdateTexturePoolState(state);
- }
-
- // Rasterizer state.
- if (state.QueryModified(MethodOffset.VertexAttribState))
- {
- UpdateVertexAttribState(state);
- }
-
- if (state.QueryModified(MethodOffset.LineWidthSmooth, MethodOffset.LineSmoothEnable))
- {
- UpdateLineState(state);
- }
-
- if (state.QueryModified(MethodOffset.PointSize,
- MethodOffset.VertexProgramPointSize,
- MethodOffset.PointSpriteEnable,
- MethodOffset.PointCoordReplace))
- {
- UpdatePointState(state);
- }
-
- if (state.QueryModified(MethodOffset.PrimitiveRestartState))
- {
- UpdatePrimitiveRestartState(state);
- }
-
- if (state.QueryModified(MethodOffset.IndexBufferState))
- {
- UpdateIndexBufferState(state, firstIndex, indexCount);
- }
-
- if (state.QueryModified(MethodOffset.VertexBufferDrawState,
- MethodOffset.VertexBufferInstanced,
- MethodOffset.VertexBufferState,
- MethodOffset.VertexBufferEndAddress))
- {
- UpdateVertexBufferState(state);
- }
-
- if (state.QueryModified(MethodOffset.FaceState))
- {
- UpdateFaceState(state);
- }
-
- if (state.QueryModified(MethodOffset.RtColorMaskShared, MethodOffset.RtColorMask))
- {
- UpdateRtColorMask(state);
- }
-
- if (state.QueryModified(MethodOffset.BlendIndependent,
- MethodOffset.BlendConstant,
- MethodOffset.BlendStateCommon,
- MethodOffset.BlendEnableCommon,
- MethodOffset.BlendEnable,
- MethodOffset.BlendState))
- {
- UpdateBlendState(state);
- }
-
- if (state.QueryModified(MethodOffset.LogicOpState))
- {
- UpdateLogicOpState(state);
- }
-
- CommitBindings(state);
-
- if (tfEnable && !_prevTfEnable)
- {
- _context.Renderer.Pipeline.BeginTransformFeedback(Topology);
- _prevTfEnable = true;
- }
- }
-
- /// <summary>
- /// Updates Rasterizer primitive discard state based on guest gpu state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateRasterizerState(GpuState state)
- {
- Boolean32 enable = state.Get<Boolean32>(MethodOffset.RasterizeEnable);
- _context.Renderer.Pipeline.SetRasterizerDiscard(!enable);
- }
-
- /// <summary>
- /// Ensures that the bindings are visible to the host GPU.
- /// Note: this actually performs the binding using the host graphics API.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void CommitBindings(GpuState state)
- {
- UpdateStorageBuffers(state);
-
- state.Channel.TextureManager.CommitGraphicsBindings();
- state.Channel.BufferManager.CommitGraphicsBindings();
- }
-
- /// <summary>
- /// Updates storage buffer bindings.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateStorageBuffers(GpuState state)
- {
- for (int stage = 0; stage < _currentProgramInfo.Length; stage++)
- {
- ShaderProgramInfo info = _currentProgramInfo[stage];
-
- if (info == null)
- {
- continue;
- }
-
- for (int index = 0; index < info.SBuffers.Count; index++)
- {
- BufferDescriptor sb = info.SBuffers[index];
-
- ulong sbDescAddress = state.Channel.BufferManager.GetGraphicsUniformBufferAddress(stage, 0);
-
- int sbDescOffset = 0x110 + stage * 0x100 + sb.Slot * 0x10;
-
- sbDescAddress += (ulong)sbDescOffset;
-
- SbDescriptor sbDescriptor = state.Channel.MemoryManager.Physical.Read<SbDescriptor>(sbDescAddress);
-
- state.Channel.BufferManager.SetGraphicsStorageBuffer(stage, sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size, sb.Flags);
- }
- }
- }
-
- /// <summary>
- /// Updates render targets (color and depth-stencil buffers) based on current render target state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- /// <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>
- private void UpdateRenderTargetState(GpuState state, bool useControl, int singleUse = -1)
- {
- var memoryManager = state.Channel.MemoryManager;
- var rtControl = state.Get<RtControl>(MethodOffset.RtControl);
-
- int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;
-
- var msaaMode = state.Get<TextureMsaaMode>(MethodOffset.RtMsaaMode);
-
- int samplesInX = msaaMode.SamplesInX();
- int samplesInY = msaaMode.SamplesInY();
-
- var scissor = state.Get<ScreenScissorState>(MethodOffset.ScreenScissorState);
- Size sizeHint = new Size(scissor.X + scissor.Width, scissor.Y + scissor.Height, 1);
-
- bool changedScale = false;
-
- for (int index = 0; index < Constants.TotalRenderTargets; index++)
- {
- int rtIndex = useControl ? rtControl.UnpackPermutationIndex(index) : index;
-
- var colorState = state.Get<RtColorState>(MethodOffset.RtColorState, rtIndex);
-
- if (index >= count || !IsRtEnabled(colorState))
- {
- changedScale |= state.Channel.TextureManager.SetRenderTargetColor(index, null);
-
- continue;
- }
-
- Texture color = memoryManager.Physical.TextureCache.FindOrCreateTexture(
- memoryManager,
- colorState,
- samplesInX,
- samplesInY,
- sizeHint);
-
- changedScale |= state.Channel.TextureManager.SetRenderTargetColor(index, color);
- }
-
- bool dsEnable = state.Get<Boolean32>(MethodOffset.RtDepthStencilEnable);
-
- Texture depthStencil = null;
-
- if (dsEnable)
- {
- var dsState = state.Get<RtDepthStencilState>(MethodOffset.RtDepthStencilState);
- var dsSize = state.Get<Size3D>(MethodOffset.RtDepthStencilSize);
-
- depthStencil = memoryManager.Physical.TextureCache.FindOrCreateTexture(
- memoryManager,
- dsState,
- dsSize,
- samplesInX,
- samplesInY,
- sizeHint);
- }
-
- changedScale |= state.Channel.TextureManager.SetRenderTargetDepthStencil(depthStencil);
-
- if (changedScale)
- {
- state.Channel.TextureManager.UpdateRenderTargetScale(singleUse);
- _context.Renderer.Pipeline.SetRenderTargetScale(state.Channel.TextureManager.RenderTargetScale);
-
- UpdateViewportTransform(state);
- UpdateScissorState(state);
- }
- }
-
- /// <summary>
- /// Checks if a render target color buffer is used.
- /// </summary>
- /// <param name="colorState">Color buffer information</param>
- /// <returns>True if the specified buffer is enabled/used, false otherwise</returns>
- private static bool IsRtEnabled(RtColorState colorState)
- {
- // Colors are disabled by writing 0 to the format.
- return colorState.Format != 0 && colorState.WidthOrStride != 0;
- }
-
- /// <summary>
- /// Updates host scissor test state based on current GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateScissorState(GpuState state)
- {
- for (int index = 0; index < Constants.TotalViewports; index++)
- {
- ScissorState scissor = state.Get<ScissorState>(MethodOffset.ScissorState, index);
-
- bool enable = scissor.Enable && (scissor.X1 != 0 || scissor.Y1 != 0 || scissor.X2 != 0xffff || scissor.Y2 != 0xffff);
-
- if (enable)
- {
- int x = scissor.X1;
- int y = scissor.Y1;
- int width = scissor.X2 - x;
- int height = scissor.Y2 - y;
-
- float scale = state.Channel.TextureManager.RenderTargetScale;
- if (scale != 1f)
- {
- x = (int)(x * scale);
- y = (int)(y * scale);
- width = (int)Math.Ceiling(width * scale);
- height = (int)Math.Ceiling(height * scale);
- }
-
- _context.Renderer.Pipeline.SetScissor(index, true, x, y, width, height);
- }
- else
- {
- _context.Renderer.Pipeline.SetScissor(index, false, 0, 0, 0, 0);
- }
- }
- }
-
- /// <summary>
- /// Updates host depth clamp state based on current GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateDepthClampState(GpuState state)
- {
- ViewVolumeClipControl clip = state.Get<ViewVolumeClipControl>(MethodOffset.ViewVolumeClipControl);
- _context.Renderer.Pipeline.SetDepthClamp((clip & ViewVolumeClipControl.DepthClampDisabled) == 0);
- }
-
- /// <summary>
- /// Updates host alpha test state based on current GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateAlphaTestState(GpuState state)
- {
- _context.Renderer.Pipeline.SetAlphaTest(
- state.Get<Boolean32>(MethodOffset.AlphaTestEnable),
- state.Get<float>(MethodOffset.AlphaTestRef),
- state.Get<CompareOp>(MethodOffset.AlphaTestFunc));
- }
-
- /// <summary>
- /// Updates host depth test state based on current GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateDepthTestState(GpuState state)
- {
- _context.Renderer.Pipeline.SetDepthTest(new DepthTestDescriptor(
- state.Get<Boolean32>(MethodOffset.DepthTestEnable),
- state.Get<Boolean32>(MethodOffset.DepthWriteEnable),
- state.Get<CompareOp>(MethodOffset.DepthTestFunc)));
- }
-
- /// <summary>
- /// Updates host viewport transform and clipping state based on current GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateViewportTransform(GpuState state)
- {
- var yControl = state.Get<YControl> (MethodOffset.YControl);
- var face = state.Get<FaceState>(MethodOffset.FaceState);
-
- UpdateFrontFace(yControl, face.FrontFace);
-
- bool flipY = yControl.HasFlag(YControl.NegateY);
-
- Span<Viewport> viewports = stackalloc Viewport[Constants.TotalViewports];
-
- for (int index = 0; index < Constants.TotalViewports; index++)
- {
- var transform = state.Get<ViewportTransform>(MethodOffset.ViewportTransform, index);
- var extents = state.Get<ViewportExtents> (MethodOffset.ViewportExtents, index);
-
- float scaleX = MathF.Abs(transform.ScaleX);
- float scaleY = transform.ScaleY;
-
- if (flipY)
- {
- scaleY = -scaleY;
- }
-
- if (!_context.Capabilities.SupportsViewportSwizzle && transform.UnpackSwizzleY() == ViewportSwizzle.NegativeY)
- {
- scaleY = -scaleY;
- }
-
- if (index == 0)
- {
- // Try to guess the depth mode being used on the high level API
- // based on current transform.
- // It is setup like so by said APIs:
- // If depth mode is ZeroToOne:
- // TranslateZ = Near
- // ScaleZ = Far - Near
- // If depth mode is MinusOneToOne:
- // TranslateZ = (Near + Far) / 2
- // ScaleZ = (Far - Near) / 2
- // DepthNear/Far are sorted such as that Near is always less than Far.
- DepthMode depthMode = extents.DepthNear != transform.TranslateZ &&
- extents.DepthFar != transform.TranslateZ ? DepthMode.MinusOneToOne : DepthMode.ZeroToOne;
-
- _context.Renderer.Pipeline.SetDepthMode(depthMode);
- }
-
- float x = transform.TranslateX - scaleX;
- float y = transform.TranslateY - scaleY;
-
- float width = scaleX * 2;
- float height = scaleY * 2;
-
- float scale = state.Channel.TextureManager.RenderTargetScale;
- if (scale != 1f)
- {
- x *= scale;
- y *= scale;
- width *= scale;
- height *= scale;
- }
-
- RectangleF region = new RectangleF(x, y, width, height);
-
- ViewportSwizzle swizzleX = transform.UnpackSwizzleX();
- ViewportSwizzle swizzleY = transform.UnpackSwizzleY();
- ViewportSwizzle swizzleZ = transform.UnpackSwizzleZ();
- ViewportSwizzle swizzleW = transform.UnpackSwizzleW();
-
- float depthNear = extents.DepthNear;
- float depthFar = extents.DepthFar;
-
- if (transform.ScaleZ < 0)
- {
- float temp = depthNear;
- depthNear = depthFar;
- depthFar = temp;
- }
-
- viewports[index] = new Viewport(region, swizzleX, swizzleY, swizzleZ, swizzleW, depthNear, depthFar);
- }
-
- _context.Renderer.Pipeline.SetViewports(0, viewports);
- }
-
- /// <summary>
- /// Updates host depth bias (also called polygon offset) state based on current GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateDepthBiasState(GpuState state)
- {
- var depthBias = state.Get<DepthBiasState>(MethodOffset.DepthBiasState);
-
- float factor = state.Get<float>(MethodOffset.DepthBiasFactor);
- float units = state.Get<float>(MethodOffset.DepthBiasUnits);
- float clamp = state.Get<float>(MethodOffset.DepthBiasClamp);
-
- PolygonModeMask enables;
-
- enables = (depthBias.PointEnable ? PolygonModeMask.Point : 0);
- enables |= (depthBias.LineEnable ? PolygonModeMask.Line : 0);
- enables |= (depthBias.FillEnable ? PolygonModeMask.Fill : 0);
-
- _context.Renderer.Pipeline.SetDepthBias(enables, factor, units / 2f, clamp);
- }
-
- /// <summary>
- /// Updates host stencil test state based on current GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateStencilTestState(GpuState state)
- {
- var backMasks = state.Get<StencilBackMasks>(MethodOffset.StencilBackMasks);
- var test = state.Get<StencilTestState>(MethodOffset.StencilTestState);
- var backTest = state.Get<StencilBackTestState>(MethodOffset.StencilBackTestState);
-
- CompareOp backFunc;
- StencilOp backSFail;
- StencilOp backDpPass;
- StencilOp backDpFail;
- int backFuncRef;
- int backFuncMask;
- int backMask;
-
- if (backTest.TwoSided)
- {
- backFunc = backTest.BackFunc;
- backSFail = backTest.BackSFail;
- backDpPass = backTest.BackDpPass;
- backDpFail = backTest.BackDpFail;
- backFuncRef = backMasks.FuncRef;
- backFuncMask = backMasks.FuncMask;
- backMask = backMasks.Mask;
- }
- else
- {
- backFunc = test.FrontFunc;
- backSFail = test.FrontSFail;
- backDpPass = test.FrontDpPass;
- backDpFail = test.FrontDpFail;
- backFuncRef = test.FrontFuncRef;
- backFuncMask = test.FrontFuncMask;
- backMask = test.FrontMask;
- }
-
- _context.Renderer.Pipeline.SetStencilTest(new StencilTestDescriptor(
- test.Enable,
- test.FrontFunc,
- test.FrontSFail,
- test.FrontDpPass,
- test.FrontDpFail,
- test.FrontFuncRef,
- test.FrontFuncMask,
- test.FrontMask,
- backFunc,
- backSFail,
- backDpPass,
- backDpFail,
- backFuncRef,
- backFuncMask,
- backMask));
- }
-
- /// <summary>
- /// Updates current sampler pool address and size based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateSamplerPoolState(GpuState state)
- {
- var texturePool = state.Get<PoolState>(MethodOffset.TexturePoolState);
- var samplerPool = state.Get<PoolState>(MethodOffset.SamplerPoolState);
-
- var samplerIndex = state.Get<SamplerIndex>(MethodOffset.SamplerIndex);
-
- int maximumId = samplerIndex == SamplerIndex.ViaHeaderIndex
- ? texturePool.MaximumId
- : samplerPool.MaximumId;
-
- state.Channel.TextureManager.SetGraphicsSamplerPool(samplerPool.Address.Pack(), maximumId, samplerIndex);
- }
-
- /// <summary>
- /// Updates current texture pool address and size based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateTexturePoolState(GpuState state)
- {
- var texturePool = state.Get<PoolState>(MethodOffset.TexturePoolState);
-
- state.Channel.TextureManager.SetGraphicsTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
- state.Channel.TextureManager.SetGraphicsTextureBufferIndex(state.Get<int>(MethodOffset.TextureBufferIndex));
- }
-
- /// <summary>
- /// Updates host vertex attributes based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateVertexAttribState(GpuState state)
- {
- Span<VertexAttribDescriptor> vertexAttribs = stackalloc VertexAttribDescriptor[Constants.TotalVertexAttribs];
-
- for (int index = 0; index < Constants.TotalVertexAttribs; index++)
- {
- var vertexAttrib = state.Get<VertexAttribState>(MethodOffset.VertexAttribState, index);
-
- if (!FormatTable.TryGetAttribFormat(vertexAttrib.UnpackFormat(), out Format format))
- {
- Logger.Debug?.Print(LogClass.Gpu, $"Invalid attribute format 0x{vertexAttrib.UnpackFormat():X}.");
-
- format = Format.R32G32B32A32Float;
- }
-
- vertexAttribs[index] = new VertexAttribDescriptor(
- vertexAttrib.UnpackBufferIndex(),
- vertexAttrib.UnpackOffset(),
- vertexAttrib.UnpackIsConstant(),
- format);
- }
-
- _context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
- }
-
- /// <summary>
- /// Updates host line width based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateLineState(GpuState state)
- {
- float width = state.Get<float>(MethodOffset.LineWidthSmooth);
- bool smooth = state.Get<Boolean32>(MethodOffset.LineSmoothEnable);
-
- _context.Renderer.Pipeline.SetLineParameters(width, smooth);
- }
-
- /// <summary>
- /// Updates host point size based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdatePointState(GpuState state)
- {
- float size = state.Get<float>(MethodOffset.PointSize);
- bool isProgramPointSize = state.Get<Boolean32>(MethodOffset.VertexProgramPointSize);
- bool enablePointSprite = state.Get<Boolean32>(MethodOffset.PointSpriteEnable);
-
- // TODO: Need to figure out a way to map PointCoordReplace enable bit.
- Origin origin = (state.Get<int>(MethodOffset.PointCoordReplace) & 4) == 0 ? Origin.LowerLeft : Origin.UpperLeft;
-
- _context.Renderer.Pipeline.SetPointParameters(size, isProgramPointSize, enablePointSprite, origin);
- }
-
- /// <summary>
- /// Updates host primitive restart based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdatePrimitiveRestartState(GpuState state)
- {
- PrimitiveRestartState primitiveRestart = state.Get<PrimitiveRestartState>(MethodOffset.PrimitiveRestartState);
-
- _context.Renderer.Pipeline.SetPrimitiveRestart(
- primitiveRestart.Enable,
- primitiveRestart.Index);
- }
-
- /// <summary>
- /// Updates host index buffer binding based on guest 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 UpdateIndexBufferState(GpuState state, int firstIndex, int indexCount)
- {
- var indexBuffer = state.Get<IndexBufferState>(MethodOffset.IndexBufferState);
-
- if (indexCount == 0)
- {
- return;
- }
-
- ulong gpuVa = indexBuffer.Address.Pack();
-
- // Do not use the end address to calculate the size, because
- // the result may be much larger than the real size of the index buffer.
- ulong size = (ulong)(firstIndex + indexCount);
-
- switch (indexBuffer.Type)
- {
- case IndexType.UShort: size *= 2; break;
- case IndexType.UInt: size *= 4; break;
- }
-
- state.Channel.BufferManager.SetIndexBuffer(gpuVa, size, indexBuffer.Type);
-
- // The index buffer affects the vertex buffer size calculation, we
- // need to ensure that they are updated.
- UpdateVertexBufferState(state);
- }
-
- /// <summary>
- /// Updates host vertex buffer bindings based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateVertexBufferState(GpuState state)
- {
- _isAnyVbInstanced = false;
-
- for (int index = 0; index < Constants.TotalVertexBuffers; index++)
- {
- var vertexBuffer = state.Get<VertexBufferState>(MethodOffset.VertexBufferState, index);
-
- if (!vertexBuffer.UnpackEnable())
- {
- state.Channel.BufferManager.SetVertexBuffer(index, 0, 0, 0, 0);
-
- continue;
- }
-
- GpuVa endAddress = state.Get<GpuVa>(MethodOffset.VertexBufferEndAddress, index);
-
- ulong address = vertexBuffer.Address.Pack();
-
- int stride = vertexBuffer.UnpackStride();
-
- bool instanced = state.Get<Boolean32>(MethodOffset.VertexBufferInstanced + index);
-
- int divisor = instanced ? vertexBuffer.Divisor : 0;
-
- _isAnyVbInstanced |= divisor != 0;
-
- ulong size;
-
- if (_ibStreamer.HasInlineIndexData || _drawIndexed || stride == 0 || instanced)
- {
- // This size may be (much) larger than the real vertex buffer size.
- // Avoid calculating it this way, unless we don't have any other option.
- size = endAddress.Pack() - address + 1;
- }
- else
- {
- // For non-indexed draws, we can guess the size from the vertex count
- // and stride.
- int firstInstance = state.Get<int>(MethodOffset.FirstInstance);
-
- var drawState = state.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
-
- size = (ulong)((firstInstance + drawState.First + drawState.Count) * stride);
- }
-
- state.Channel.BufferManager.SetVertexBuffer(index, address, size, stride, divisor);
- }
- }
-
- /// <summary>
- /// Updates host face culling and orientation based on guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateFaceState(GpuState state)
- {
- var yControl = state.Get<YControl> (MethodOffset.YControl);
- var face = state.Get<FaceState>(MethodOffset.FaceState);
-
- _context.Renderer.Pipeline.SetFaceCulling(face.CullEnable, face.CullFace);
-
- UpdateFrontFace(yControl, face.FrontFace);
- }
-
- /// <summary>
- /// Updates the front face based on the current front face and the origin.
- /// </summary>
- /// <param name="yControl">Y control register value, where the origin is located</param>
- /// <param name="frontFace">Front face</param>
- private void UpdateFrontFace(YControl yControl, FrontFace frontFace)
- {
- bool isUpperLeftOrigin = !yControl.HasFlag(YControl.TriangleRastFlip);
-
- if (isUpperLeftOrigin)
- {
- frontFace = frontFace == FrontFace.CounterClockwise ? FrontFace.Clockwise : FrontFace.CounterClockwise;
- }
-
- _context.Renderer.Pipeline.SetFrontFace(frontFace);
- }
-
- /// <summary>
- /// Updates host render target color masks, based on guest GPU state.
- /// This defines which color channels are written to each color buffer.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateRtColorMask(GpuState state)
- {
- bool rtColorMaskShared = state.Get<Boolean32>(MethodOffset.RtColorMaskShared);
-
- Span<uint> componentMasks = stackalloc uint[Constants.TotalRenderTargets];
-
- for (int index = 0; index < Constants.TotalRenderTargets; index++)
- {
- var colorMask = state.Get<RtColorMask>(MethodOffset.RtColorMask, rtColorMaskShared ? 0 : index);
-
- uint componentMask;
-
- componentMask = (colorMask.UnpackRed() ? 1u : 0u);
- componentMask |= (colorMask.UnpackGreen() ? 2u : 0u);
- componentMask |= (colorMask.UnpackBlue() ? 4u : 0u);
- componentMask |= (colorMask.UnpackAlpha() ? 8u : 0u);
-
- componentMasks[index] = componentMask;
- }
-
- _context.Renderer.Pipeline.SetRenderTargetColorMasks(componentMasks);
- }
-
- /// <summary>
- /// Updates host render target color buffer blending state, based on guest state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateBlendState(GpuState state)
- {
- bool blendIndependent = state.Get<Boolean32>(MethodOffset.BlendIndependent);
- ColorF blendConstant = state.Get<ColorF>(MethodOffset.BlendConstant);
-
- for (int index = 0; index < Constants.TotalRenderTargets; index++)
- {
- BlendDescriptor descriptor;
-
- if (blendIndependent)
- {
- bool enable = state.Get<Boolean32> (MethodOffset.BlendEnable, index);
- var blend = state.Get<BlendState>(MethodOffset.BlendState, index);
-
- descriptor = new BlendDescriptor(
- enable,
- blendConstant,
- blend.ColorOp,
- blend.ColorSrcFactor,
- blend.ColorDstFactor,
- blend.AlphaOp,
- blend.AlphaSrcFactor,
- blend.AlphaDstFactor);
- }
- else
- {
- bool enable = state.Get<Boolean32> (MethodOffset.BlendEnable, 0);
- var blend = state.Get<BlendStateCommon>(MethodOffset.BlendStateCommon);
-
- descriptor = new BlendDescriptor(
- enable,
- blendConstant,
- blend.ColorOp,
- blend.ColorSrcFactor,
- blend.ColorDstFactor,
- blend.AlphaOp,
- blend.AlphaSrcFactor,
- blend.AlphaDstFactor);
- }
-
- _context.Renderer.Pipeline.SetBlendState(index, descriptor);
- }
- }
-
- /// <summary>
- /// Updates host logical operation state, based on guest state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- public void UpdateLogicOpState(GpuState state)
- {
- LogicalOpState logicOpState = state.Get<LogicalOpState>(MethodOffset.LogicOpState);
-
- _context.Renderer.Pipeline.SetLogicOpState(logicOpState.Enable, logicOpState.LogicalOp);
- }
-
- /// <summary>
- /// Updates host shaders based on the guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateShaderState(GpuState state)
- {
- ShaderAddresses addresses = new ShaderAddresses();
-
- Span<ShaderAddresses> addressesSpan = MemoryMarshal.CreateSpan(ref addresses, 1);
-
- Span<ulong> addressesArray = MemoryMarshal.Cast<ShaderAddresses, ulong>(addressesSpan);
-
- ulong baseAddress = state.Get<GpuVa>(MethodOffset.ShaderBaseAddress).Pack();
-
- for (int index = 0; index < 6; index++)
- {
- var shader = state.Get<ShaderState>(MethodOffset.ShaderState, index);
-
- if (!shader.UnpackEnable() && index != 1)
- {
- continue;
- }
-
- addressesArray[index] = baseAddress + shader.Offset;
- }
-
- ShaderBundle gs = state.Channel.MemoryManager.Physical.ShaderCache.GetGraphicsShader(state, addresses);
-
- byte oldVsClipDistancesWritten = _vsClipDistancesWritten;
-
- _vsUsesInstanceId = gs.Shaders[0]?.Info.UsesInstanceId ?? false;
- _vsClipDistancesWritten = gs.Shaders[0]?.Info.ClipDistancesWritten ?? 0;
-
- if (oldVsClipDistancesWritten != _vsClipDistancesWritten)
- {
- UpdateUserClipState(state);
- }
-
- int storageBufferBindingsCount = 0;
- int uniformBufferBindingsCount = 0;
-
- for (int stage = 0; stage < Constants.ShaderStages; stage++)
- {
- ShaderProgramInfo info = gs.Shaders[stage]?.Info;
-
- _currentProgramInfo[stage] = info;
-
- if (info == null)
- {
- state.Channel.TextureManager.SetGraphicsTextures(stage, Array.Empty<TextureBindingInfo>());
- state.Channel.TextureManager.SetGraphicsImages(stage, Array.Empty<TextureBindingInfo>());
- state.Channel.BufferManager.SetGraphicsStorageBufferBindings(stage, null);
- state.Channel.BufferManager.SetGraphicsUniformBufferBindings(stage, null);
- continue;
- }
-
- var textureBindings = new TextureBindingInfo[info.Textures.Count];
-
- for (int index = 0; index < info.Textures.Count; index++)
- {
- var descriptor = info.Textures[index];
-
- Target target = ShaderTexture.GetTarget(descriptor.Type);
-
- textureBindings[index] = new TextureBindingInfo(
- target,
- descriptor.Binding,
- descriptor.CbufSlot,
- descriptor.HandleIndex,
- descriptor.Flags);
- }
-
- state.Channel.TextureManager.SetGraphicsTextures(stage, textureBindings);
-
- var imageBindings = new TextureBindingInfo[info.Images.Count];
-
- for (int index = 0; index < info.Images.Count; index++)
- {
- var descriptor = info.Images[index];
-
- Target target = ShaderTexture.GetTarget(descriptor.Type);
- Format format = ShaderTexture.GetFormat(descriptor.Format);
-
- imageBindings[index] = new TextureBindingInfo(
- target,
- format,
- descriptor.Binding,
- descriptor.CbufSlot,
- descriptor.HandleIndex,
- descriptor.Flags);
- }
-
- state.Channel.TextureManager.SetGraphicsImages(stage, imageBindings);
-
- state.Channel.BufferManager.SetGraphicsStorageBufferBindings(stage, info.SBuffers);
- state.Channel.BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers);
-
- if (info.SBuffers.Count != 0)
- {
- storageBufferBindingsCount = Math.Max(storageBufferBindingsCount, info.SBuffers.Max(x => x.Binding) + 1);
- }
-
- if (info.CBuffers.Count != 0)
- {
- uniformBufferBindingsCount = Math.Max(uniformBufferBindingsCount, info.CBuffers.Max(x => x.Binding) + 1);
- }
- }
-
- state.Channel.BufferManager.SetGraphicsStorageBufferBindingsCount(storageBufferBindingsCount);
- state.Channel.BufferManager.SetGraphicsUniformBufferBindingsCount(uniformBufferBindingsCount);
-
- _context.Renderer.Pipeline.SetProgram(gs.HostProgram);
- }
-
- /// <summary>
- /// Forces the shaders to be rebound on the next draw.
- /// </summary>
- public void ForceShaderUpdate()
- {
- _forceShaderUpdate = true;
- }
-
- /// <summary>
- /// Updates transform feedback buffer state based on the guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateTfBufferState(GpuState state)
- {
- for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
- {
- TfBufferState tfb = state.Get<TfBufferState>(MethodOffset.TfBufferState, index);
-
- if (!tfb.Enable)
- {
- state.Channel.BufferManager.SetTransformFeedbackBuffer(index, 0, 0);
-
- continue;
- }
-
- state.Channel.BufferManager.SetTransformFeedbackBuffer(index, tfb.Address.Pack(), (uint)tfb.Size);
- }
- }
-
- /// <summary>
- /// Updates user-defined clipping based on the guest GPU state.
- /// </summary>
- /// <param name="state">Current GPU state</param>
- private void UpdateUserClipState(GpuState state)
- {
- int clipMask = state.Get<int>(MethodOffset.ClipDistanceEnable) & _vsClipDistancesWritten;
-
- for (int i = 0; i < Constants.TotalClipDistances; ++i)
- {
- _context.Renderer.Pipeline.SetUserClipDistance(i, (clipMask & (1 << i)) != 0);
- }
- }
-
- /// <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="state">Current GPU state (unused)</param>
- /// <param name="argument">Method call argument (unused)</param>
- private void TextureBarrier(GpuState state, 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="state">Current GPU state (unused)</param>
- /// <param name="argument">Method call argument (unused)</param>
- private void TextureBarrierTiled(GpuState state, int argument)
- {
- _context.Renderer.Pipeline.TextureBarrierTiled();
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Engine/MmeShadowScratch.cs b/Ryujinx.Graphics.Gpu/Engine/MmeShadowScratch.cs
index df9021e0..a3295616 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MmeShadowScratch.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/MmeShadowScratch.cs
@@ -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
{
diff --git a/Ryujinx.Graphics.Gpu/Engine/SetMmeShadowRamControlMode.cs b/Ryujinx.Graphics.Gpu/Engine/SetMmeShadowRamControlMode.cs
new file mode 100644
index 00000000..060d35ca
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Engine/SetMmeShadowRamControlMode.cs
@@ -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,
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Engine/MethodConditionalRendering.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ConditionalRendering.cs
index 039ed78e..85f66985 100644
--- a/Ryujinx.Graphics.Gpu/Engine/MethodConditionalRendering.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ConditionalRendering.cs
@@ -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;
}
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/ConstantBufferUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ConstantBufferUpdater.cs
new file mode 100644
index 00000000..f4006ba9
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ConstantBufferUpdater.cs
@@ -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;
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
new file mode 100644
index 00000000..d58f175d
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
@@ -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();
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawState.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawState.cs
new file mode 100644
index 00000000..ff186acc
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawState.cs
@@ -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();
+ }
+}
diff --git a/Ryujinx.Graphics.Gpu/Engine/IbStreamer.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/IbStreamer.cs
index b407c941..96b2ed9c 100644
--- a/Ryujinx.Graphics.Gpu/Engine/IbStreamer.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/IbStreamer.cs
@@ -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>
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/SemaphoreUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/SemaphoreUpdater.cs
new file mode 100644
index 00000000..37fa51c4
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/SemaphoreUpdater.cs
@@ -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;
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs
new file mode 100644
index 00000000..2af7a402
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs
@@ -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;
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
new file mode 100644
index 00000000..4ff084e9
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
@@ -0,0 +1,1044 @@
+using Ryujinx.Common.Logging;
+using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Engine.Types;
+using Ryujinx.Graphics.Gpu.Image;
+using Ryujinx.Graphics.Gpu.Shader;
+using Ryujinx.Graphics.Shader;
+using Ryujinx.Graphics.Texture;
+using System;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Graphics.Gpu.Engine.Threed
+{
+ /// <summary>
+ /// GPU state updater.
+ /// </summary>
+ class StateUpdater
+ {
+ public const int ShaderStateIndex = 0;
+ public const int RasterizerStateIndex = 1;
+ public const int ScissorStateIndex = 2;
+ public const int VertexBufferStateIndex = 3;
+
+ private readonly GpuContext _context;
+ private readonly GpuChannel _channel;
+ private readonly DeviceStateWithShadow<ThreedClassState> _state;
+ private readonly DrawState _drawState;
+
+ private readonly StateUpdateTracker<ThreedClassState> _updateTracker;
+
+ private readonly ShaderProgramInfo[] _currentProgramInfo;
+
+ private byte _vsClipDistancesWritten;
+
+ private bool _prevDrawIndexed;
+ private bool _prevTfEnable;
+
+ /// <summary>
+ /// Creates a new instance of the state updater.
+ /// </summary>
+ /// <param name="context">GPU context</param>
+ /// <param name="channel">GPU channel</param>
+ /// <param name="state">3D engine state</param>
+ /// <param name="drawState">Draw state</param>
+ public StateUpdater(GpuContext context, GpuChannel channel, DeviceStateWithShadow<ThreedClassState> state, DrawState drawState)
+ {
+ _context = context;
+ _channel = channel;
+ _state = state;
+ _drawState = drawState;
+ _currentProgramInfo = new ShaderProgramInfo[Constants.ShaderStages];
+
+ // ShaderState must be the first, as other state updates depends on information from the currently bound shader.
+ // Rasterizer and scissor states are checked by render target clear, their indexes
+ // must be updated on the constants "RasterizerStateIndex" and "ScissorStateIndex" if modified.
+ // The vertex buffer state may be forced dirty when a indexed draw starts, the "VertexBufferStateIndex"
+ // constant must be updated if modified.
+ // The order of the other state updates doesn't matter.
+ _updateTracker = new StateUpdateTracker<ThreedClassState>(new[]
+ {
+ new StateUpdateCallbackEntry(UpdateShaderState,
+ nameof(ThreedClassState.ShaderBaseAddress),
+ nameof(ThreedClassState.ShaderState)),
+
+ new StateUpdateCallbackEntry(UpdateRasterizerState, nameof(ThreedClassState.RasterizeEnable)),
+ new StateUpdateCallbackEntry(UpdateScissorState, nameof(ThreedClassState.ScissorState)),
+
+ new StateUpdateCallbackEntry(UpdateVertexBufferState,
+ nameof(ThreedClassState.VertexBufferDrawState),
+ nameof(ThreedClassState.VertexBufferInstanced),
+ nameof(ThreedClassState.VertexBufferState),
+ nameof(ThreedClassState.VertexBufferEndAddress)),
+
+ new StateUpdateCallbackEntry(UpdateTfBufferState, nameof(ThreedClassState.TfBufferState)),
+ new StateUpdateCallbackEntry(UpdateUserClipState, nameof(ThreedClassState.ClipDistanceEnable)),
+
+ new StateUpdateCallbackEntry(UpdateRenderTargetState,
+ nameof(ThreedClassState.RtColorState),
+ nameof(ThreedClassState.RtDepthStencilState),
+ nameof(ThreedClassState.RtControl),
+ nameof(ThreedClassState.RtDepthStencilSize),
+ nameof(ThreedClassState.RtDepthStencilEnable)),
+
+ new StateUpdateCallbackEntry(UpdateDepthClampState, nameof(ThreedClassState.ViewVolumeClipControl)),
+
+ new StateUpdateCallbackEntry(UpdateAlphaTestState,
+ nameof(ThreedClassState.AlphaTestEnable),
+ nameof(ThreedClassState.AlphaTestRef),
+ nameof(ThreedClassState.AlphaTestFunc)),
+
+ new StateUpdateCallbackEntry(UpdateDepthTestState,
+ nameof(ThreedClassState.DepthTestEnable),
+ nameof(ThreedClassState.DepthWriteEnable),
+ nameof(ThreedClassState.DepthTestFunc)),
+
+ new StateUpdateCallbackEntry(UpdateViewportTransform,
+ nameof(ThreedClassState.DepthMode),
+ nameof(ThreedClassState.ViewportTransform),
+ nameof(ThreedClassState.ViewportExtents),
+ nameof(ThreedClassState.YControl)),
+
+ new StateUpdateCallbackEntry(UpdateDepthBiasState,
+ nameof(ThreedClassState.DepthBiasState),
+ nameof(ThreedClassState.DepthBiasFactor),
+ nameof(ThreedClassState.DepthBiasUnits),
+ nameof(ThreedClassState.DepthBiasClamp)),
+
+ new StateUpdateCallbackEntry(UpdateStencilTestState,
+ nameof(ThreedClassState.StencilBackMasks),
+ nameof(ThreedClassState.StencilTestState),
+ nameof(ThreedClassState.StencilBackTestState)),
+
+ new StateUpdateCallbackEntry(UpdateSamplerPoolState,
+ nameof(ThreedClassState.SamplerPoolState),
+ nameof(ThreedClassState.SamplerIndex)),
+
+ new StateUpdateCallbackEntry(UpdateTexturePoolState, nameof(ThreedClassState.TexturePoolState)),
+ new StateUpdateCallbackEntry(UpdateVertexAttribState, nameof(ThreedClassState.VertexAttribState)),
+
+ new StateUpdateCallbackEntry(UpdateLineState,
+ nameof(ThreedClassState.LineWidthSmooth),
+ nameof(ThreedClassState.LineSmoothEnable)),
+
+ new StateUpdateCallbackEntry(UpdatePointState,
+ nameof(ThreedClassState.PointSize),
+ nameof(ThreedClassState.VertexProgramPointSize),
+ nameof(ThreedClassState.PointSpriteEnable),
+ nameof(ThreedClassState.PointCoordReplace)),
+
+ new StateUpdateCallbackEntry(UpdatePrimitiveRestartState, nameof(ThreedClassState.PrimitiveRestartState)),
+
+ new StateUpdateCallbackEntry(UpdateIndexBufferState,
+ nameof(ThreedClassState.IndexBufferState),
+ nameof(ThreedClassState.IndexBufferCount)),
+
+ new StateUpdateCallbackEntry(UpdateFaceState, nameof(ThreedClassState.FaceState)),
+
+ new StateUpdateCallbackEntry(UpdateRtColorMask,
+ nameof(ThreedClassState.RtColorMaskShared),
+ nameof(ThreedClassState.RtColorMask)),
+
+ new StateUpdateCallbackEntry(UpdateBlendState,
+ nameof(ThreedClassState.BlendIndependent),
+ nameof(ThreedClassState.BlendConstant),
+ nameof(ThreedClassState.BlendStateCommon),
+ nameof(ThreedClassState.BlendEnableCommon),
+ nameof(ThreedClassState.BlendEnable),
+ nameof(ThreedClassState.BlendState)),
+
+ new StateUpdateCallbackEntry(UpdateLogicOpState, nameof(ThreedClassState.LogicOpState))
+ });
+ }
+
+ /// <summary>
+ /// Sets a register at a specific offset as dirty.
+ /// This must be called if the register value was modified.
+ /// </summary>
+ /// <param name="offset">Register offset</param>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void SetDirty(int offset)
+ {
+ _updateTracker.SetDirty(offset);
+ }
+
+ /// <summary>
+ /// Force all the guest state to be marked as dirty.
+ /// The next call to <see cref="Update"/> will update all the host state.
+ /// </summary>
+ public void SetAllDirty()
+ {
+ _updateTracker.SetAllDirty();
+ }
+
+ /// <summary>
+ /// Updates host state for any modified guest state, since the last time this function was called.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Update()
+ {
+ // The vertex buffer size is calculated using a different
+ // method when doing indexed draws, so we need to make sure
+ // to update the vertex buffers if we are doing a regular
+ // draw after a indexed one and vice-versa.
+ if (_drawState.DrawIndexed != _prevDrawIndexed)
+ {
+ _updateTracker.ForceDirty(VertexBufferStateIndex);
+ _prevDrawIndexed = _drawState.DrawIndexed;
+ }
+
+ bool tfEnable = _state.State.TfEnable;
+
+ if (!tfEnable && _prevTfEnable)
+ {
+ _context.Renderer.Pipeline.EndTransformFeedback();
+ _prevTfEnable = false;
+ }
+
+ _updateTracker.Update(ulong.MaxValue);
+
+ CommitBindings();
+
+ if (tfEnable && !_prevTfEnable)
+ {
+ _context.Renderer.Pipeline.BeginTransformFeedback(_drawState.Topology);
+ _prevTfEnable = true;
+ }
+ }
+
+ /// <summary>
+ /// Updates the host state for any modified guest state group with the respective bit set on <paramref name="mask"/>.
+ /// </summary>
+ /// <param name="mask">Mask, where each bit set corresponds to a group index that should be checked and updated</param>
+ public void Update(ulong mask)
+ {
+ _updateTracker.Update(mask);
+ }
+
+ /// <summary>
+ /// Ensures that the bindings are visible to the host GPU.
+ /// Note: this actually performs the binding using the host graphics API.
+ /// </summary>
+ private void CommitBindings()
+ {
+ UpdateStorageBuffers();
+
+ _channel.TextureManager.CommitGraphicsBindings();
+ _channel.BufferManager.CommitGraphicsBindings();
+ }
+
+ /// <summary>
+ /// Updates storage buffer bindings.
+ /// </summary>
+ private void UpdateStorageBuffers()
+ {
+ for (int stage = 0; stage < Constants.ShaderStages; stage++)
+ {
+ ShaderProgramInfo info = _currentProgramInfo[stage];
+
+ if (info == null)
+ {
+ continue;
+ }
+
+ for (int index = 0; index < info.SBuffers.Count; index++)
+ {
+ BufferDescriptor sb = info.SBuffers[index];
+
+ ulong sbDescAddress = _channel.BufferManager.GetGraphicsUniformBufferAddress(stage, 0);
+
+ int sbDescOffset = 0x110 + stage * 0x100 + sb.Slot * 0x10;
+
+ sbDescAddress += (ulong)sbDescOffset;
+
+ SbDescriptor sbDescriptor = _channel.MemoryManager.Physical.Read<SbDescriptor>(sbDescAddress);
+
+ _channel.BufferManager.SetGraphicsStorageBuffer(stage, sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size, sb.Flags);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Updates transform feedback buffer state based on the guest GPU state.
+ /// </summary>
+ private void UpdateTfBufferState()
+ {
+ for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
+ {
+ TfBufferState tfb = _state.State.TfBufferState[index];
+
+ if (!tfb.Enable)
+ {
+ _channel.BufferManager.SetTransformFeedbackBuffer(index, 0, 0);
+
+ continue;
+ }
+
+ _channel.BufferManager.SetTransformFeedbackBuffer(index, tfb.Address.Pack(), (uint)tfb.Size);
+ }
+ }
+
+ /// <summary>
+ /// Updates Rasterizer primitive discard state based on guest gpu state.
+ /// </summary>
+ private void UpdateRasterizerState()
+ {
+ bool enable = _state.State.RasterizeEnable;
+ _context.Renderer.Pipeline.SetRasterizerDiscard(!enable);
+ }
+
+ /// <summary>
+ /// Updates render targets (color and depth-stencil buffers) based on current render target state.
+ /// </summary>
+ private void UpdateRenderTargetState()
+ {
+ UpdateRenderTargetState(true);
+ }
+
+ /// <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)
+ {
+ var memoryManager = _channel.MemoryManager;
+ var rtControl = _state.State.RtControl;
+
+ int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;
+
+ var msaaMode = _state.State.RtMsaaMode;
+
+ int samplesInX = msaaMode.SamplesInX();
+ int samplesInY = msaaMode.SamplesInY();
+
+ var scissor = _state.State.ScreenScissorState;
+ Size sizeHint = new Size(scissor.X + scissor.Width, scissor.Y + scissor.Height, 1);
+
+ bool changedScale = false;
+
+ for (int index = 0; index < Constants.TotalRenderTargets; index++)
+ {
+ int rtIndex = useControl ? rtControl.UnpackPermutationIndex(index) : index;
+
+ var colorState = _state.State.RtColorState[rtIndex];
+
+ if (index >= count || !IsRtEnabled(colorState))
+ {
+ changedScale |= _channel.TextureManager.SetRenderTargetColor(index, null);
+
+ continue;
+ }
+
+ Image.Texture color = memoryManager.Physical.TextureCache.FindOrCreateTexture(
+ memoryManager,
+ colorState,
+ samplesInX,
+ samplesInY,
+ sizeHint);
+
+ changedScale |= _channel.TextureManager.SetRenderTargetColor(index, color);
+ }
+
+ bool dsEnable = _state.State.RtDepthStencilEnable;
+
+ Image.Texture depthStencil = null;
+
+ if (dsEnable)
+ {
+ var dsState = _state.State.RtDepthStencilState;
+ var dsSize = _state.State.RtDepthStencilSize;
+
+ depthStencil = memoryManager.Physical.TextureCache.FindOrCreateTexture(
+ memoryManager,
+ dsState,
+ dsSize,
+ samplesInX,
+ samplesInY,
+ sizeHint);
+ }
+
+ changedScale |= _channel.TextureManager.SetRenderTargetDepthStencil(depthStencil);
+
+ if (changedScale)
+ {
+ _channel.TextureManager.UpdateRenderTargetScale(singleUse);
+ _context.Renderer.Pipeline.SetRenderTargetScale(_channel.TextureManager.RenderTargetScale);
+
+ UpdateViewportTransform();
+ UpdateScissorState();
+ }
+ }
+
+ /// <summary>
+ /// Checks if a render target color buffer is used.
+ /// </summary>
+ /// <param name="colorState">Color buffer information</param>
+ /// <returns>True if the specified buffer is enabled/used, false otherwise</returns>
+ private static bool IsRtEnabled(RtColorState colorState)
+ {
+ // Colors are disabled by writing 0 to the format.
+ return colorState.Format != 0 && colorState.WidthOrStride != 0;
+ }
+
+ /// <summary>
+ /// Updates host scissor test state based on current GPU state.
+ /// </summary>
+ private void UpdateScissorState()
+ {
+ for (int index = 0; index < Constants.TotalViewports; index++)
+ {
+ ScissorState scissor = _state.State.ScissorState[index];
+
+ bool enable = scissor.Enable && (scissor.X1 != 0 || scissor.Y1 != 0 || scissor.X2 != 0xffff || scissor.Y2 != 0xffff);
+
+ if (enable)
+ {
+ int x = scissor.X1;
+ int y = scissor.Y1;
+ int width = scissor.X2 - x;
+ int height = scissor.Y2 - y;
+
+ float scale = _channel.TextureManager.RenderTargetScale;
+ if (scale != 1f)
+ {
+ x = (int)(x * scale);
+ y = (int)(y * scale);
+ width = (int)Math.Ceiling(width * scale);
+ height = (int)Math.Ceiling(height * scale);
+ }
+
+ _context.Renderer.Pipeline.SetScissor(index, true, x, y, width, height);
+ }
+ else
+ {
+ _context.Renderer.Pipeline.SetScissor(index, false, 0, 0, 0, 0);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Updates host depth clamp state based on current GPU state.
+ /// </summary>
+ /// <param name="state">Current GPU state</param>
+ private void UpdateDepthClampState()
+ {
+ ViewVolumeClipControl clip = _state.State.ViewVolumeClipControl;
+ _context.Renderer.Pipeline.SetDepthClamp((clip & ViewVolumeClipControl.DepthClampDisabled) == 0);
+ }
+
+ /// <summary>
+ /// Updates host alpha test state based on current GPU state.
+ /// </summary>
+ private void UpdateAlphaTestState()
+ {
+ _context.Renderer.Pipeline.SetAlphaTest(
+ _state.State.AlphaTestEnable,
+ _state.State.AlphaTestRef,
+ _state.State.AlphaTestFunc);
+ }
+
+ /// <summary>
+ /// Updates host depth test state based on current GPU state.
+ /// </summary>
+ private void UpdateDepthTestState()
+ {
+ _context.Renderer.Pipeline.SetDepthTest(new DepthTestDescriptor(
+ _state.State.DepthTestEnable,
+ _state.State.DepthWriteEnable,
+ _state.State.DepthTestFunc));
+ }
+
+ /// <summary>
+ /// Updates host viewport transform and clipping state based on current GPU state.
+ /// </summary>
+ private void UpdateViewportTransform()
+ {
+ var yControl = _state.State.YControl;
+ var face = _state.State.FaceState;
+
+ UpdateFrontFace(yControl, face.FrontFace);
+
+ bool flipY = yControl.HasFlag(YControl.NegateY);
+
+ Span<Viewport> viewports = stackalloc Viewport[Constants.TotalViewports];
+
+ for (int index = 0; index < Constants.TotalViewports; index++)
+ {
+ var transform = _state.State.ViewportTransform[index];
+ var extents = _state.State.ViewportExtents[index];
+
+ float scaleX = MathF.Abs(transform.ScaleX);
+ float scaleY = transform.ScaleY;
+
+ if (flipY)
+ {
+ scaleY = -scaleY;
+ }
+
+ if (!_context.Capabilities.SupportsViewportSwizzle && transform.UnpackSwizzleY() == ViewportSwizzle.NegativeY)
+ {
+ scaleY = -scaleY;
+ }
+
+ if (index == 0)
+ {
+ // Try to guess the depth mode being used on the high level API
+ // based on current transform.
+ // It is setup like so by said APIs:
+ // If depth mode is ZeroToOne:
+ // TranslateZ = Near
+ // ScaleZ = Far - Near
+ // If depth mode is MinusOneToOne:
+ // TranslateZ = (Near + Far) / 2
+ // ScaleZ = (Far - Near) / 2
+ // DepthNear/Far are sorted such as that Near is always less than Far.
+ DepthMode depthMode = extents.DepthNear != transform.TranslateZ &&
+ extents.DepthFar != transform.TranslateZ ? DepthMode.MinusOneToOne : DepthMode.ZeroToOne;
+
+ _context.Renderer.Pipeline.SetDepthMode(depthMode);
+ }
+
+ float x = transform.TranslateX - scaleX;
+ float y = transform.TranslateY - scaleY;
+
+ float width = scaleX * 2;
+ float height = scaleY * 2;
+
+ float scale = _channel.TextureManager.RenderTargetScale;
+ if (scale != 1f)
+ {
+ x *= scale;
+ y *= scale;
+ width *= scale;
+ height *= scale;
+ }
+
+ RectangleF region = new RectangleF(x, y, width, height);
+
+ ViewportSwizzle swizzleX = transform.UnpackSwizzleX();
+ ViewportSwizzle swizzleY = transform.UnpackSwizzleY();
+ ViewportSwizzle swizzleZ = transform.UnpackSwizzleZ();
+ ViewportSwizzle swizzleW = transform.UnpackSwizzleW();
+
+ float depthNear = extents.DepthNear;
+ float depthFar = extents.DepthFar;
+
+ if (transform.ScaleZ < 0)
+ {
+ float temp = depthNear;
+ depthNear = depthFar;
+ depthFar = temp;
+ }
+
+ viewports[index] = new Viewport(region, swizzleX, swizzleY, swizzleZ, swizzleW, depthNear, depthFar);
+ }
+
+ _context.Renderer.Pipeline.SetViewports(0, viewports);
+ }
+
+ /// <summary>
+ /// Updates host depth bias (also called polygon offset) state based on current GPU state.
+ /// </summary>
+ private void UpdateDepthBiasState()
+ {
+ var depthBias = _state.State.DepthBiasState;
+
+ float factor = _state.State.DepthBiasFactor;
+ float units = _state.State.DepthBiasUnits;
+ float clamp = _state.State.DepthBiasClamp;
+
+ PolygonModeMask enables;
+
+ enables = (depthBias.PointEnable ? PolygonModeMask.Point : 0);
+ enables |= (depthBias.LineEnable ? PolygonModeMask.Line : 0);
+ enables |= (depthBias.FillEnable ? PolygonModeMask.Fill : 0);
+
+ _context.Renderer.Pipeline.SetDepthBias(enables, factor, units / 2f, clamp);
+ }
+
+ /// <summary>
+ /// Updates host stencil test state based on current GPU state.
+ /// </summary>
+ private void UpdateStencilTestState()
+ {
+ var backMasks = _state.State.StencilBackMasks;
+ var test = _state.State.StencilTestState;
+ var backTest = _state.State.StencilBackTestState;
+
+ CompareOp backFunc;
+ StencilOp backSFail;
+ StencilOp backDpPass;
+ StencilOp backDpFail;
+ int backFuncRef;
+ int backFuncMask;
+ int backMask;
+
+ if (backTest.TwoSided)
+ {
+ backFunc = backTest.BackFunc;
+ backSFail = backTest.BackSFail;
+ backDpPass = backTest.BackDpPass;
+ backDpFail = backTest.BackDpFail;
+ backFuncRef = backMasks.FuncRef;
+ backFuncMask = backMasks.FuncMask;
+ backMask = backMasks.Mask;
+ }
+ else
+ {
+ backFunc = test.FrontFunc;
+ backSFail = test.FrontSFail;
+ backDpPass = test.FrontDpPass;
+ backDpFail = test.FrontDpFail;
+ backFuncRef = test.FrontFuncRef;
+ backFuncMask = test.FrontFuncMask;
+ backMask = test.FrontMask;
+ }
+
+ _context.Renderer.Pipeline.SetStencilTest(new StencilTestDescriptor(
+ test.Enable,
+ test.FrontFunc,
+ test.FrontSFail,
+ test.FrontDpPass,
+ test.FrontDpFail,
+ test.FrontFuncRef,
+ test.FrontFuncMask,
+ test.FrontMask,
+ backFunc,
+ backSFail,
+ backDpPass,
+ backDpFail,
+ backFuncRef,
+ backFuncMask,
+ backMask));
+ }
+
+ /// <summary>
+ /// Updates user-defined clipping based on the guest GPU state.
+ /// </summary>
+ private void UpdateUserClipState()
+ {
+ uint clipMask = _state.State.ClipDistanceEnable & _vsClipDistancesWritten;
+
+ for (int i = 0; i < Constants.TotalClipDistances; ++i)
+ {
+ _context.Renderer.Pipeline.SetUserClipDistance(i, (clipMask & (1 << i)) != 0);
+ }
+ }
+
+ /// <summary>
+ /// Updates current sampler pool address and size based on guest GPU state.
+ /// </summary>
+ private void UpdateSamplerPoolState()
+ {
+ var texturePool = _state.State.TexturePoolState;
+ var samplerPool = _state.State.SamplerPoolState;
+
+ var samplerIndex = _state.State.SamplerIndex;
+
+ int maximumId = samplerIndex == SamplerIndex.ViaHeaderIndex
+ ? texturePool.MaximumId
+ : samplerPool.MaximumId;
+
+ _channel.TextureManager.SetGraphicsSamplerPool(samplerPool.Address.Pack(), maximumId, samplerIndex);
+ }
+
+ /// <summary>
+ /// Updates current texture pool address and size based on guest GPU state.
+ /// </summary>
+ private void UpdateTexturePoolState()
+ {
+ var texturePool = _state.State.TexturePoolState;
+
+ _channel.TextureManager.SetGraphicsTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
+ _channel.TextureManager.SetGraphicsTextureBufferIndex((int)_state.State.TextureBufferIndex);
+ }
+
+ /// <summary>
+ /// Updates host vertex attributes based on guest GPU state.
+ /// </summary>
+ private void UpdateVertexAttribState()
+ {
+ Span<VertexAttribDescriptor> vertexAttribs = stackalloc VertexAttribDescriptor[Constants.TotalVertexAttribs];
+
+ for (int index = 0; index < Constants.TotalVertexAttribs; index++)
+ {
+ var vertexAttrib = _state.State.VertexAttribState[index];
+
+ if (!FormatTable.TryGetAttribFormat(vertexAttrib.UnpackFormat(), out Format format))
+ {
+ Logger.Debug?.Print(LogClass.Gpu, $"Invalid attribute format 0x{vertexAttrib.UnpackFormat():X}.");
+
+ format = Format.R32G32B32A32Float;
+ }
+
+ vertexAttribs[index] = new VertexAttribDescriptor(
+ vertexAttrib.UnpackBufferIndex(),
+ vertexAttrib.UnpackOffset(),
+ vertexAttrib.UnpackIsConstant(),
+ format);
+ }
+
+ _context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
+ }
+
+ /// <summary>
+ /// Updates host line width based on guest GPU state.
+ /// </summary>
+ private void UpdateLineState()
+ {
+ float width = _state.State.LineWidthSmooth;
+ bool smooth = _state.State.LineSmoothEnable;
+
+ _context.Renderer.Pipeline.SetLineParameters(width, smooth);
+ }
+
+ /// <summary>
+ /// Updates host point size based on guest GPU state.
+ /// </summary>
+ private void UpdatePointState()
+ {
+ float size = _state.State.PointSize;
+ bool isProgramPointSize = _state.State.VertexProgramPointSize;
+ bool enablePointSprite = _state.State.PointSpriteEnable;
+
+ // TODO: Need to figure out a way to map PointCoordReplace enable bit.
+ Origin origin = (_state.State.PointCoordReplace & 4) == 0 ? Origin.LowerLeft : Origin.UpperLeft;
+
+ _context.Renderer.Pipeline.SetPointParameters(size, isProgramPointSize, enablePointSprite, origin);
+ }
+
+ /// <summary>
+ /// Updates host primitive restart based on guest GPU state.
+ /// </summary>
+ private void UpdatePrimitiveRestartState()
+ {
+ PrimitiveRestartState primitiveRestart = _state.State.PrimitiveRestartState;
+
+ _context.Renderer.Pipeline.SetPrimitiveRestart(primitiveRestart.Enable, primitiveRestart.Index);
+ }
+
+ /// <summary>
+ /// Updates host index buffer binding based on guest GPU state.
+ /// </summary>
+ private void UpdateIndexBufferState()
+ {
+ var indexBuffer = _state.State.IndexBufferState;
+
+ if (_drawState.IndexCount == 0)
+ {
+ return;
+ }
+
+ ulong gpuVa = indexBuffer.Address.Pack();
+
+ // Do not use the end address to calculate the size, because
+ // the result may be much larger than the real size of the index buffer.
+ ulong size = (ulong)(_drawState.FirstIndex + _drawState.IndexCount);
+
+ switch (indexBuffer.Type)
+ {
+ case IndexType.UShort: size *= 2; break;
+ case IndexType.UInt: size *= 4; break;
+ }
+
+ _channel.BufferManager.SetIndexBuffer(gpuVa, size, indexBuffer.Type);
+ }
+
+ /// <summary>
+ /// Updates host vertex buffer bindings based on guest GPU state.
+ /// </summary>
+ private void UpdateVertexBufferState()
+ {
+ _drawState.IsAnyVbInstanced = false;
+
+ for (int index = 0; index < Constants.TotalVertexBuffers; index++)
+ {
+ var vertexBuffer = _state.State.VertexBufferState[index];
+
+ if (!vertexBuffer.UnpackEnable())
+ {
+ _channel.BufferManager.SetVertexBuffer(index, 0, 0, 0, 0);
+
+ continue;
+ }
+
+ GpuVa endAddress = _state.State.VertexBufferEndAddress[index];
+
+ ulong address = vertexBuffer.Address.Pack();
+
+ int stride = vertexBuffer.UnpackStride();
+
+ bool instanced = _state.State.VertexBufferInstanced[index];
+
+ int divisor = instanced ? vertexBuffer.Divisor : 0;
+
+ _drawState.IsAnyVbInstanced |= divisor != 0;
+
+ ulong size;
+
+ if (_drawState.IbStreamer.HasInlineIndexData || _drawState.DrawIndexed || stride == 0 || instanced)
+ {
+ // This size may be (much) larger than the real vertex buffer size.
+ // Avoid calculating it this way, unless we don't have any other option.
+ size = endAddress.Pack() - address + 1;
+ }
+ else
+ {
+ // For non-indexed draws, we can guess the size from the vertex count
+ // and stride.
+ int firstInstance = (int)_state.State.FirstInstance;
+
+ var drawState = _state.State.VertexBufferDrawState;
+
+ size = (ulong)((firstInstance + drawState.First + drawState.Count) * stride);
+ }
+
+ _channel.BufferManager.SetVertexBuffer(index, address, size, stride, divisor);
+ }
+ }
+
+ /// <summary>
+ /// Updates host face culling and orientation based on guest GPU state.
+ /// </summary>
+ private void UpdateFaceState()
+ {
+ var yControl = _state.State.YControl;
+ var face = _state.State.FaceState;
+
+ _context.Renderer.Pipeline.SetFaceCulling(face.CullEnable, face.CullFace);
+
+ UpdateFrontFace(yControl, face.FrontFace);
+ }
+
+ /// <summary>
+ /// Updates the front face based on the current front face and the origin.
+ /// </summary>
+ /// <param name="yControl">Y control register value, where the origin is located</param>
+ /// <param name="frontFace">Front face</param>
+ private void UpdateFrontFace(YControl yControl, FrontFace frontFace)
+ {
+ bool isUpperLeftOrigin = !yControl.HasFlag(YControl.TriangleRastFlip);
+
+ if (isUpperLeftOrigin)
+ {
+ frontFace = frontFace == FrontFace.CounterClockwise ? FrontFace.Clockwise : FrontFace.CounterClockwise;
+ }
+
+ _context.Renderer.Pipeline.SetFrontFace(frontFace);
+ }
+
+ /// <summary>
+ /// Updates host render target color masks, based on guest GPU state.
+ /// This defines which color channels are written to each color buffer.
+ /// </summary>
+ private void UpdateRtColorMask()
+ {
+ bool rtColorMaskShared = _state.State.RtColorMaskShared;
+
+ Span<uint> componentMasks = stackalloc uint[Constants.TotalRenderTargets];
+
+ for (int index = 0; index < Constants.TotalRenderTargets; index++)
+ {
+ var colorMask = _state.State.RtColorMask[rtColorMaskShared ? 0 : index];
+
+ uint componentMask;
+
+ componentMask = (colorMask.UnpackRed() ? 1u : 0u);
+ componentMask |= (colorMask.UnpackGreen() ? 2u : 0u);
+ componentMask |= (colorMask.UnpackBlue() ? 4u : 0u);
+ componentMask |= (colorMask.UnpackAlpha() ? 8u : 0u);
+
+ componentMasks[index] = componentMask;
+ }
+
+ _context.Renderer.Pipeline.SetRenderTargetColorMasks(componentMasks);
+ }
+
+ /// <summary>
+ /// Updates host render target color buffer blending state, based on guest state.
+ /// </summary>
+ private void UpdateBlendState()
+ {
+ bool blendIndependent = _state.State.BlendIndependent;
+ ColorF blendConstant = _state.State.BlendConstant;
+
+ for (int index = 0; index < Constants.TotalRenderTargets; index++)
+ {
+ BlendDescriptor descriptor;
+
+ if (blendIndependent)
+ {
+ bool enable = _state.State.BlendEnable[index];
+ var blend = _state.State.BlendState[index];
+
+ descriptor = new BlendDescriptor(
+ enable,
+ blendConstant,
+ blend.ColorOp,
+ blend.ColorSrcFactor,
+ blend.ColorDstFactor,
+ blend.AlphaOp,
+ blend.AlphaSrcFactor,
+ blend.AlphaDstFactor);
+ }
+ else
+ {
+ bool enable = _state.State.BlendEnable[0];
+ var blend = _state.State.BlendStateCommon;
+
+ descriptor = new BlendDescriptor(
+ enable,
+ blendConstant,
+ blend.ColorOp,
+ blend.ColorSrcFactor,
+ blend.ColorDstFactor,
+ blend.AlphaOp,
+ blend.AlphaSrcFactor,
+ blend.AlphaDstFactor);
+ }
+
+ _context.Renderer.Pipeline.SetBlendState(index, descriptor);
+ }
+ }
+
+ /// <summary>
+ /// Updates host logical operation state, based on guest state.
+ /// </summary>
+ private void UpdateLogicOpState()
+ {
+ LogicalOpState logicOpState = _state.State.LogicOpState;
+
+ _context.Renderer.Pipeline.SetLogicOpState(logicOpState.Enable, logicOpState.LogicalOp);
+ }
+
+ /// <summary>
+ /// Updates host shaders based on the guest GPU state.
+ /// </summary>
+ private void UpdateShaderState()
+ {
+ ShaderAddresses addresses = new ShaderAddresses();
+
+ Span<ShaderAddresses> addressesSpan = MemoryMarshal.CreateSpan(ref addresses, 1);
+
+ Span<ulong> addressesArray = MemoryMarshal.Cast<ShaderAddresses, ulong>(addressesSpan);
+
+ ulong baseAddress = _state.State.ShaderBaseAddress.Pack();
+
+ for (int index = 0; index < 6; index++)
+ {
+ var shader = _state.State.ShaderState[index];
+
+ if (!shader.UnpackEnable() && index != 1)
+ {
+ continue;
+ }
+
+ addressesArray[index] = baseAddress + shader.Offset;
+ }
+
+ GpuAccessorState gas = new GpuAccessorState(
+ _state.State.TexturePoolState.Address.Pack(),
+ _state.State.TexturePoolState.MaximumId,
+ (int)_state.State.TextureBufferIndex,
+ _state.State.EarlyZForce,
+ _drawState.Topology);
+
+ ShaderBundle gs = _channel.MemoryManager.Physical.ShaderCache.GetGraphicsShader(ref _state.State, _channel, gas, addresses);
+
+ byte oldVsClipDistancesWritten = _vsClipDistancesWritten;
+
+ _drawState.VsUsesInstanceId = gs.Shaders[0]?.Info.UsesInstanceId ?? false;
+ _vsClipDistancesWritten = gs.Shaders[0]?.Info.ClipDistancesWritten ?? 0;
+
+ if (oldVsClipDistancesWritten != _vsClipDistancesWritten)
+ {
+ UpdateUserClipState();
+ }
+
+ int storageBufferBindingsCount = 0;
+ int uniformBufferBindingsCount = 0;
+
+ for (int stage = 0; stage < Constants.ShaderStages; stage++)
+ {
+ ShaderProgramInfo info = gs.Shaders[stage]?.Info;
+
+ _currentProgramInfo[stage] = info;
+
+ if (info == null)
+ {
+ _channel.TextureManager.SetGraphicsTextures(stage, Array.Empty<TextureBindingInfo>());
+ _channel.TextureManager.SetGraphicsImages(stage, Array.Empty<TextureBindingInfo>());
+ _channel.BufferManager.SetGraphicsStorageBufferBindings(stage, null);
+ _channel.BufferManager.SetGraphicsUniformBufferBindings(stage, null);
+ continue;
+ }
+
+ var textureBindings = new TextureBindingInfo[info.Textures.Count];
+
+ for (int index = 0; index < info.Textures.Count; index++)
+ {
+ var descriptor = info.Textures[index];
+
+ Target target = ShaderTexture.GetTarget(descriptor.Type);
+
+ textureBindings[index] = new TextureBindingInfo(
+ target,
+ descriptor.Binding,
+ descriptor.CbufSlot,
+ descriptor.HandleIndex,
+ descriptor.Flags);
+ }
+
+ _channel.TextureManager.SetGraphicsTextures(stage, textureBindings);
+
+ var imageBindings = new TextureBindingInfo[info.Images.Count];
+
+ for (int index = 0; index < info.Images.Count; index++)
+ {
+ var descriptor = info.Images[index];
+
+ Target target = ShaderTexture.GetTarget(descriptor.Type);
+ Format format = ShaderTexture.GetFormat(descriptor.Format);
+
+ imageBindings[index] = new TextureBindingInfo(
+ target,
+ format,
+ descriptor.Binding,
+ descriptor.CbufSlot,
+ descriptor.HandleIndex,
+ descriptor.Flags);
+ }
+
+ _channel.TextureManager.SetGraphicsImages(stage, imageBindings);
+
+ _channel.BufferManager.SetGraphicsStorageBufferBindings(stage, info.SBuffers);
+ _channel.BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers);
+
+ if (info.SBuffers.Count != 0)
+ {
+ storageBufferBindingsCount = Math.Max(storageBufferBindingsCount, info.SBuffers.Max(x => x.Binding) + 1);
+ }
+
+ if (info.CBuffers.Count != 0)
+ {
+ uniformBufferBindingsCount = Math.Max(uniformBufferBindingsCount, info.CBuffers.Max(x => x.Binding) + 1);
+ }
+ }
+
+ _channel.BufferManager.SetGraphicsStorageBufferBindingsCount(storageBufferBindingsCount);
+ _channel.BufferManager.SetGraphicsUniformBufferBindingsCount(uniformBufferBindingsCount);
+
+ _context.Renderer.Pipeline.SetProgram(gs.HostProgram);
+ }
+
+ /// <summary>
+ /// Forces the shaders to be rebound on the next draw.
+ /// </summary>
+ public void ForceShaderUpdate()
+ {
+ _updateTracker.ForceDirty(ShaderStateIndex);
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
new file mode 100644
index 00000000..ad6a1d0e
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
@@ -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;
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs
new file mode 100644
index 00000000..a6392e3d
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs
@@ -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
+ }
+}
diff --git a/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs b/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs
index d4f6d879..3c74c164 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs
@@ -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;
diff --git a/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClassState.cs b/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClassState.cs
index fdc4204d..46fddb04 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClassState.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Twod/TwodClassState.cs
@@ -14,17 +14,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Twod
}
/// <summary>
- /// MME shadow RAM control mode.
- /// </summary>
- enum SetMmeShadowRamControlMode
- {
- MethodTrack = 0,
- MethodTrackWithFilter = 1,
- MethodPassthrough = 2,
- MethodReplay = 3,
- }
-
- /// <summary>
/// Format of the destination texture.
/// </summary>
enum SetDstFormatV
@@ -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;
diff --git a/Ryujinx.Graphics.Gpu/Engine/Twod/TwodTexture.cs b/Ryujinx.Graphics.Gpu/Engine/Twod/TwodTexture.cs
new file mode 100644
index 00000000..c28da094
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Engine/Twod/TwodTexture.cs
@@ -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
+ }
+}
diff --git a/Ryujinx.Graphics.Gpu/State/Boolean32.cs b/Ryujinx.Graphics.Gpu/Engine/Types/Boolean32.cs
index 78e13b73..c982347a 100644
--- a/Ryujinx.Graphics.Gpu/State/Boolean32.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Types/Boolean32.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Graphics.Gpu.State
+namespace Ryujinx.Graphics.Gpu.Engine.Types
{
/// <summary>
/// Boolean value, stored as a 32-bits integer in memory.
diff --git a/Ryujinx.Graphics.Gpu/State/ColorFormat.cs b/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs
index 11126396..e780ec23 100644
--- a/Ryujinx.Graphics.Gpu/State/ColorFormat.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs
@@ -1,7 +1,7 @@
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Image;
-namespace Ryujinx.Graphics.Gpu.State
+namespace Ryujinx.Graphics.Gpu.Engine.Types
{
/// <summary>
/// Color texture format.
diff --git a/Ryujinx.Graphics.Gpu/State/GpuVa.cs b/Ryujinx.Graphics.Gpu/Engine/Types/GpuVa.cs
index d6b7def3..839faac9 100644
--- a/Ryujinx.Graphics.Gpu/State/GpuVa.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Types/GpuVa.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Graphics.Gpu.State
+namespace Ryujinx.Graphics.Gpu.Engine.Types
{
/// <summary>
/// Split GPU virtual address.
diff --git a/Ryujinx.Graphics.Gpu/State/MemoryLayout.cs b/Ryujinx.Graphics.Gpu/Engine/Types/MemoryLayout.cs
index c98831f9..6da96bd4 100644
--- a/Ryujinx.Graphics.Gpu/State/MemoryLayout.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Types/MemoryLayout.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Graphics.Gpu.State
+namespace Ryujinx.Graphics.Gpu.Engine.Types
{
/// <summary>
/// Memory layout parameters, for block linear textures.
diff --git a/Ryujinx.Graphics.Gpu/State/PrimitiveType.cs b/Ryujinx.Graphics.Gpu/Engine/Types/PrimitiveType.cs
index b49088aa..dae63124 100644
--- a/Ryujinx.Graphics.Gpu/State/PrimitiveType.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Types/PrimitiveType.cs
@@ -1,6 +1,6 @@
using Ryujinx.Graphics.GAL;
-namespace Ryujinx.Graphics.Gpu.State
+namespace Ryujinx.Graphics.Gpu.Engine.Types
{
/// <summary>
/// Draw primitive type.
@@ -29,7 +29,6 @@ namespace Ryujinx.Graphics.Gpu.State
/// </summary>
enum PrimitiveTypeOverride
{
- Invalid = 0,
Points = 1,
Lines = 2,
LineStrip = 3,
diff --git a/Ryujinx.Graphics.Gpu/State/SamplerIndex.cs b/Ryujinx.Graphics.Gpu/Engine/Types/SamplerIndex.cs
index c2aaff43..839a4d0a 100644
--- a/Ryujinx.Graphics.Gpu/State/SamplerIndex.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Types/SamplerIndex.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Graphics.Gpu.State
+namespace Ryujinx.Graphics.Gpu.Engine.Types
{
/// <summary>
/// Sampler pool indexing mode.
diff --git a/Ryujinx.Graphics.Gpu/State/SbDescriptor.cs b/Ryujinx.Graphics.Gpu/Engine/Types/SbDescriptor.cs
index 9723b719..c457dbf9 100644
--- a/Ryujinx.Graphics.Gpu/State/SbDescriptor.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Types/SbDescriptor.cs
@@ -1,4 +1,4 @@
-namespace Ryujinx.Graphics.Gpu.State
+namespace Ryujinx.Graphics.Gpu.Engine.Types
{
/// <summary>
/// Storage buffer address and size information.
diff --git a/Ryujinx.Graphics.Gpu/State/ZetaFormat.cs b/Ryujinx.Graphics.Gpu/Engine/Types/ZetaFormat.cs
index 01b608b3..2de38fd2 100644
--- a/Ryujinx.Graphics.Gpu/State/ZetaFormat.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Types/ZetaFormat.cs
@@ -1,7 +1,7 @@
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Image;
-namespace Ryujinx.Graphics.Gpu.State
+namespace Ryujinx.Graphics.Gpu.Engine.Types
{
/// <summary>
/// Depth-stencil texture format.
diff --git a/Ryujinx.Graphics.Gpu/GpuChannel.cs b/Ryujinx.Graphics.Gpu/GpuChannel.cs
index e9f08eb8..b9d91f93 100644
--- a/Ryujinx.Graphics.Gpu/GpuChannel.cs
+++ b/Ryujinx.Graphics.Gpu/GpuChannel.cs
@@ -65,6 +65,17 @@ namespace Ryujinx.Graphics.Gpu
}
/// <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, uint value)
+ {
+ _processor.Write(classId, offset, (int)value);
+ }
+
+ /// <summary>
/// Push a GPFIFO entry in the form of a prefetched command buffer.
/// It is intended to be used by nvservices to handle special cases.
/// </summary>
diff --git a/Ryujinx.Graphics.Gpu/GpuContext.cs b/Ryujinx.Graphics.Gpu/GpuContext.cs
index 7fae249e..734fc492 100644
--- a/Ryujinx.Graphics.Gpu/GpuContext.cs
+++ b/Ryujinx.Graphics.Gpu/GpuContext.cs
@@ -1,5 +1,4 @@
using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Gpu.Engine;
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Gpu.Shader;
@@ -27,11 +26,6 @@ namespace Ryujinx.Graphics.Gpu
public IRenderer Renderer { get; }
/// <summary>
- /// GPU engine methods processing.
- /// </summary>
- internal Methods Methods { get; }
-
- /// <summary>
/// GPU General Purpose FIFO queue.
/// </summary>
public GPFifoDevice GPFifo { get; }
@@ -94,8 +88,6 @@ namespace Ryujinx.Graphics.Gpu
{
Renderer = renderer;
- Methods = new Methods(this);
-
GPFifo = new GPFifoDevice(this);
Synchronization = new SynchronizationManager();
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
index b247f99f..96eb6f04 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
@@ -1,5 +1,5 @@
using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Gpu.State;
+using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Shader;
using System;
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
index 106dc8e8..1b54033c 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
@@ -1,8 +1,11 @@
using Ryujinx.Common;
using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Engine.Dma;
+using Ryujinx.Graphics.Gpu.Engine.Threed;
+using Ryujinx.Graphics.Gpu.Engine.Twod;
+using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.Memory;
-using Ryujinx.Graphics.Gpu.State;
using Ryujinx.Graphics.Texture;
using Ryujinx.Memory.Range;
using System;
@@ -151,7 +154,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <returns>The texture</returns>
public Texture FindOrCreateTexture(
MemoryManager memoryManager,
- CopyTexture copyTexture,
+ TwodTexture copyTexture,
ulong offset,
FormatInfo formatInfo,
bool preferScaling = true,
@@ -762,7 +765,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <returns>A matching texture, or null if there is no match</returns>
public Texture FindTexture(
MemoryManager memoryManager,
- CopyBufferTexture tex,
+ DmaTexture tex,
ulong gpuVa,
int bpp,
int stride,
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
index fcc67f72..157b7c17 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
@@ -1,5 +1,5 @@
using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Gpu.State;
+using Ryujinx.Graphics.Gpu.Engine.Types;
using System;
namespace Ryujinx.Graphics.Gpu.Image
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs b/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
index 6c5116ba..58dd838e 100644
--- a/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/BufferCache.cs
@@ -1,5 +1,4 @@
using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Gpu.State;
using Ryujinx.Memory.Range;
using System;
using System.Collections.Generic;
diff --git a/Ryujinx.Graphics.Gpu/MethodParams.cs b/Ryujinx.Graphics.Gpu/MethodParams.cs
deleted file mode 100644
index dd60f77c..00000000
--- a/Ryujinx.Graphics.Gpu/MethodParams.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-namespace Ryujinx.Graphics
-{
- /// <summary>
- /// Method call parameters.
- /// </summary>
- struct MethodParams
- {
- /// <summary>
- /// Method offset.
- /// </summary>
- public int Method { get; }
-
- /// <summary>
- /// Method call argument.
- /// </summary>
- public int Argument { get; }
-
- /// <summary>
- /// Sub-channel where the call should be sent.
- /// </summary>
- public int SubChannel { get; }
-
- /// <summary>
- /// For multiple calls to the same method, this is the remaining calls count.
- /// </summary>
- public int MethodCount { get; }
-
- /// <summary>
- /// Indicates if the current call is the last one from a batch of calls to the same method.
- /// </summary>
- public bool IsLastCall => MethodCount <= 1;
-
- /// <summary>
- /// Constructs the method call parameters structure.
- /// </summary>
- /// <param name="method">Method offset</param>
- /// <param name="argument">Method call argument</param>
- /// <param name="subChannel">Optional sub-channel where the method should be sent (not required for macro calls)</param>
- /// <param name="methodCount">Optional remaining calls count (not required for macro calls)</param>
- public MethodParams(
- int method,
- int argument,
- int subChannel = 0,
- int methodCount = 0)
- {
- Method = method;
- Argument = argument;
- SubChannel = subChannel;
- MethodCount = methodCount;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
index 7fb979f4..b7059b51 100644
--- a/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs
@@ -144,27 +144,21 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <returns>Current primitive topology</returns>
public InputTopology QueryPrimitiveTopology()
{
- switch (_context.Methods.Topology)
+ return _state.Topology switch
{
- case PrimitiveTopology.Points:
- return InputTopology.Points;
- case PrimitiveTopology.Lines:
- case PrimitiveTopology.LineLoop:
- case PrimitiveTopology.LineStrip:
- return InputTopology.Lines;
- case PrimitiveTopology.LinesAdjacency:
- case PrimitiveTopology.LineStripAdjacency:
- return InputTopology.LinesAdjacency;
- case PrimitiveTopology.Triangles:
- case PrimitiveTopology.TriangleStrip:
- case PrimitiveTopology.TriangleFan:
- return InputTopology.Triangles;
- case PrimitiveTopology.TrianglesAdjacency:
- case PrimitiveTopology.TriangleStripAdjacency:
- return InputTopology.TrianglesAdjacency;
- }
-
- return InputTopology.Points;
+ PrimitiveTopology.Points => InputTopology.Points,
+ PrimitiveTopology.Lines or
+ PrimitiveTopology.LineLoop or
+ PrimitiveTopology.LineStrip => InputTopology.Lines,
+ PrimitiveTopology.LinesAdjacency or
+ PrimitiveTopology.LineStripAdjacency => InputTopology.LinesAdjacency,
+ PrimitiveTopology.Triangles or
+ PrimitiveTopology.TriangleStrip or
+ PrimitiveTopology.TriangleFan => InputTopology.Triangles,
+ PrimitiveTopology.TrianglesAdjacency or
+ PrimitiveTopology.TriangleStripAdjacency => InputTopology.TrianglesAdjacency,
+ _ => InputTopology.Points,
+ };
}
/// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs b/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs
index 17660cf9..8d817113 100644
--- a/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/GpuAccessorState.cs
@@ -1,3 +1,5 @@
+using Ryujinx.Graphics.GAL;
+
namespace Ryujinx.Graphics.Gpu.Shader
{
/// <summary>
@@ -26,18 +28,30 @@ namespace Ryujinx.Graphics.Gpu.Shader
public bool EarlyZForce { get; }
/// <summary>
+ /// Primitive topology of current draw.
+ /// </summary>
+ public PrimitiveTopology Topology { get; }
+
+ /// <summary>
/// Creates a new instance of the GPU accessor state.
/// </summary>
/// <param name="texturePoolGpuVa">GPU virtual address of the texture pool</param>
/// <param name="texturePoolMaximumId">Maximum ID of the texture pool</param>
/// <param name="textureBufferIndex">Constant buffer slot where the texture handles are located</param>
/// <param name="earlyZForce">Early Z force enable</param>
- public GpuAccessorState(ulong texturePoolGpuVa, int texturePoolMaximumId, int textureBufferIndex, bool earlyZForce)
+ /// <param name="topology">Primitive topology</param>
+ public GpuAccessorState(
+ ulong texturePoolGpuVa,
+ int texturePoolMaximumId,
+ int textureBufferIndex,
+ bool earlyZForce,
+ PrimitiveTopology topology)
{
TexturePoolGpuVa = texturePoolGpuVa;
TexturePoolMaximumId = texturePoolMaximumId;
TextureBufferIndex = textureBufferIndex;
EarlyZForce = earlyZForce;
+ Topology = topology;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index 031c95a9..e5c1fb83 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -1,15 +1,16 @@
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Engine.Threed;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Gpu.Shader.Cache;
using Ryujinx.Graphics.Gpu.Shader.Cache.Definition;
-using Ryujinx.Graphics.Gpu.State;
using Ryujinx.Graphics.Shader;
using Ryujinx.Graphics.Shader.Translation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
@@ -593,10 +594,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <remarks>
/// This automatically translates, compiles and adds the code to the cache if not present.
/// </remarks>
- /// <param name="state">Current GPU state</param>
+ /// <param name="state">GPU state</param>
+ /// <param name="channel">GPU channel</param>
+ /// <param name="gas">GPU accessor state</param>
/// <param name="addresses">Addresses of the shaders for each stage</param>
/// <returns>Compiled graphics shader code</returns>
- public ShaderBundle GetGraphicsShader(GpuState state, ShaderAddresses addresses)
+ public ShaderBundle GetGraphicsShader(ref ThreedClassState state, GpuChannel channel, GpuAccessorState gas, ShaderAddresses addresses)
{
bool isCached = _gpPrograms.TryGetValue(addresses, out List<ShaderBundle> list);
@@ -604,7 +607,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
foreach (ShaderBundle cachedGpShaders in list)
{
- if (IsShaderEqual(state.Channel.MemoryManager, cachedGpShaders, addresses))
+ if (IsShaderEqual(channel.MemoryManager, cachedGpShaders, addresses))
{
return cachedGpShaders;
}
@@ -613,7 +616,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
TranslatorContext[] shaderContexts = new TranslatorContext[Constants.ShaderStages + 1];
- TransformFeedbackDescriptor[] tfd = GetTransformFeedbackDescriptors(state);
+ TransformFeedbackDescriptor[] tfd = GetTransformFeedbackDescriptors(ref state);
TranslationFlags flags = DefaultFlags;
@@ -626,14 +629,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
if (addresses.VertexA != 0)
{
- shaderContexts[0] = DecodeGraphicsShader(state, counts, flags | TranslationFlags.VertexA, ShaderStage.Vertex, addresses.VertexA);
+ shaderContexts[0] = DecodeGraphicsShader(channel, gas, counts, flags | TranslationFlags.VertexA, ShaderStage.Vertex, addresses.VertexA);
}
- shaderContexts[1] = DecodeGraphicsShader(state, counts, flags, ShaderStage.Vertex, addresses.Vertex);
- shaderContexts[2] = DecodeGraphicsShader(state, counts, flags, ShaderStage.TessellationControl, addresses.TessControl);
- shaderContexts[3] = DecodeGraphicsShader(state, counts, flags, ShaderStage.TessellationEvaluation, addresses.TessEvaluation);
- shaderContexts[4] = DecodeGraphicsShader(state, counts, flags, ShaderStage.Geometry, addresses.Geometry);
- shaderContexts[5] = DecodeGraphicsShader(state, counts, flags, ShaderStage.Fragment, addresses.Fragment);
+ shaderContexts[1] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.Vertex, addresses.Vertex);
+ shaderContexts[2] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.TessellationControl, addresses.TessControl);
+ shaderContexts[3] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.TessellationEvaluation, addresses.TessEvaluation);
+ shaderContexts[4] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.Geometry, addresses.Geometry);
+ shaderContexts[5] = DecodeGraphicsShader(channel, gas, counts, flags, ShaderStage.Fragment, addresses.Fragment);
bool isShaderCacheEnabled = _cacheManager != null;
bool isShaderCacheReadOnly = false;
@@ -656,7 +659,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
isShaderCacheReadOnly = _cacheManager.IsReadOnly;
// Compute hash and prepare data for shader disk cache comparison.
- shaderCacheEntries = CacheHelper.CreateShaderCacheEntries(state.Channel.MemoryManager, shaderContexts);
+ shaderCacheEntries = CacheHelper.CreateShaderCacheEntries(channel.MemoryManager, shaderContexts);
programCodeHash = CacheHelper.ComputeGuestHashFromCache(shaderCacheEntries, tfd);
}
@@ -673,11 +676,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
// The shader isn't currently cached, translate it and compile it.
ShaderCodeHolder[] shaders = new ShaderCodeHolder[Constants.ShaderStages];
- shaders[0] = TranslateShader(state.Channel.MemoryManager, shaderContexts[1], shaderContexts[0]);
- shaders[1] = TranslateShader(state.Channel.MemoryManager, shaderContexts[2]);
- shaders[2] = TranslateShader(state.Channel.MemoryManager, shaderContexts[3]);
- shaders[3] = TranslateShader(state.Channel.MemoryManager, shaderContexts[4]);
- shaders[4] = TranslateShader(state.Channel.MemoryManager, shaderContexts[5]);
+ shaders[0] = TranslateShader(channel.MemoryManager, shaderContexts[1], shaderContexts[0]);
+ shaders[1] = TranslateShader(channel.MemoryManager, shaderContexts[2]);
+ shaders[2] = TranslateShader(channel.MemoryManager, shaderContexts[3]);
+ shaders[3] = TranslateShader(channel.MemoryManager, shaderContexts[4]);
+ shaders[4] = TranslateShader(channel.MemoryManager, shaderContexts[5]);
List<IShader> hostShaders = new List<IShader>();
@@ -733,9 +736,9 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary>
/// <param name="state">Current GPU state</param>
/// <returns>Four transform feedback descriptors for the enabled TFBs, or null if TFB is disabled</returns>
- private static TransformFeedbackDescriptor[] GetTransformFeedbackDescriptors(GpuState state)
+ private static TransformFeedbackDescriptor[] GetTransformFeedbackDescriptors(ref ThreedClassState state)
{
- bool tfEnable = state.Get<Boolean32>(MethodOffset.TfEnable);
+ bool tfEnable = state.TfEnable;
if (!tfEnable)
{
@@ -746,13 +749,13 @@ namespace Ryujinx.Graphics.Gpu.Shader
for (int i = 0; i < Constants.TotalTransformFeedbackBuffers; i++)
{
- var tf = state.Get<TfState>(MethodOffset.TfState, i);
+ var tf = state.TfState[i];
int length = (int)Math.Min((uint)tf.VaryingsCount, 0x80);
- var varyingLocations = state.GetSpan(MethodOffset.TfVaryingLocations + i * 0x80, length).ToArray();
+ var varyingLocations = MemoryMarshal.Cast<uint, byte>(state.TfVaryingLocations[i].ToSpan()).Slice(0, length);
- descs[i] = new TransformFeedbackDescriptor(tf.BufferIndex, tf.Stride, varyingLocations);
+ descs[i] = new TransformFeedbackDescriptor(tf.BufferIndex, tf.Stride, varyingLocations.ToArray());
}
return descs;
@@ -871,14 +874,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <remarks>
/// This will combine the "Vertex A" and "Vertex B" shader stages, if specified, into one shader.
/// </remarks>
- /// <param name="state">Current GPU state</param>
+ /// <param name="channel">GPU channel</param>
+ /// <param name="gas">GPU accessor state</param>
/// <param name="counts">Cumulative shader resource counts</param>
/// <param name="flags">Flags that controls shader translation</param>
/// <param name="stage">Shader stage</param>
/// <param name="gpuVa">GPU virtual address of the shader code</param>
/// <returns>The generated translator context</returns>
private TranslatorContext DecodeGraphicsShader(
- GpuState state,
+ GpuChannel channel,
+ GpuAccessorState gas,
TranslationCounts counts,
TranslationFlags flags,
ShaderStage stage,
@@ -889,13 +894,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
return null;
}
- GpuAccessorState gas = new GpuAccessorState(
- state.Get<PoolState>(MethodOffset.TexturePoolState).Address.Pack(),
- state.Get<PoolState>(MethodOffset.TexturePoolState).MaximumId,
- state.Get<int>(MethodOffset.TextureBufferIndex),
- state.Get<Boolean32>(MethodOffset.EarlyZForce));
-
- GpuAccessor gpuAccessor = new GpuAccessor(_context, state.Channel, gas, (int)stage - 1);
+ GpuAccessor gpuAccessor = new GpuAccessor(_context, channel, gas, (int)stage - 1);
var options = new TranslationOptions(TargetLanguage.Glsl, TargetApi.OpenGL, flags);
return Translator.CreateContext(gpuVa, gpuAccessor, options, counts);
diff --git a/Ryujinx.Graphics.Gpu/ShadowRamControl.cs b/Ryujinx.Graphics.Gpu/ShadowRamControl.cs
deleted file mode 100644
index 10dd39bc..00000000
--- a/Ryujinx.Graphics.Gpu/ShadowRamControl.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-namespace Ryujinx.Graphics.Gpu
-{
- /// <summary>
- /// Shadow RAM Control setting.
- /// </summary>
- enum ShadowRamControl
- {
- /// <summary>
- /// Track data writes and store them on shadow RAM.
- /// </summary>
- Track = 0,
-
- /// <summary>
- /// Track data writes and store them on shadow RAM, with filtering.
- /// </summary>
- TrackWithFilter = 1,
-
- /// <summary>
- /// Writes data directly without storing on shadow RAM.
- /// </summary>
- Passthrough = 2,
-
- /// <summary>
- /// Ignore data being written and replace with data on shadow RAM instead.
- /// </summary>
- Replay = 3
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/BlendState.cs b/Ryujinx.Graphics.Gpu/State/BlendState.cs
deleted file mode 100644
index ba16b8bd..00000000
--- a/Ryujinx.Graphics.Gpu/State/BlendState.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using Ryujinx.Graphics.GAL;
-
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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
-
- public static BlendState Default = new BlendState
- {
- ColorOp = BlendOp.Add,
- ColorSrcFactor = BlendFactor.One,
- ColorDstFactor = BlendFactor.Zero,
- AlphaOp = BlendOp.Add,
- AlphaSrcFactor = BlendFactor.One,
- AlphaDstFactor = BlendFactor.Zero
- };
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/BlendStateCommon.cs b/Ryujinx.Graphics.Gpu/State/BlendStateCommon.cs
deleted file mode 100644
index f402a5a7..00000000
--- a/Ryujinx.Graphics.Gpu/State/BlendStateCommon.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using Ryujinx.Graphics.GAL;
-
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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
-
- public static BlendStateCommon Default = new BlendStateCommon
- {
- ColorOp = BlendOp.Add,
- ColorSrcFactor = BlendFactor.One,
- ColorDstFactor = BlendFactor.Zero,
- AlphaOp = BlendOp.Add,
- AlphaSrcFactor = BlendFactor.One,
- AlphaDstFactor = BlendFactor.Zero
- };
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/ClearColors.cs b/Ryujinx.Graphics.Gpu/State/ClearColors.cs
deleted file mode 100644
index ba29c899..00000000
--- a/Ryujinx.Graphics.Gpu/State/ClearColors.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/Condition.cs b/Ryujinx.Graphics.Gpu/State/Condition.cs
deleted file mode 100644
index 5afdbe3e..00000000
--- a/Ryujinx.Graphics.Gpu/State/Condition.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// Condition for conditional rendering.
- /// </summary>
- enum Condition
- {
- Never,
- Always,
- ResultNonZero,
- Equal,
- NotEqual
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/ConditionState.cs b/Ryujinx.Graphics.Gpu/State/ConditionState.cs
deleted file mode 100644
index 3388e8f0..00000000
--- a/Ryujinx.Graphics.Gpu/State/ConditionState.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// Condition parameters for conditional rendering.
- /// </summary>
- struct ConditionState
- {
-#pragma warning disable CS0649
- public GpuVa Address;
- public Condition Condition;
-#pragma warning restore CS0649
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/CopyBufferTexture.cs b/Ryujinx.Graphics.Gpu/State/CopyBufferTexture.cs
deleted file mode 100644
index dfbab37a..00000000
--- a/Ryujinx.Graphics.Gpu/State/CopyBufferTexture.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// Buffer to texture copy parameters.
- /// </summary>
- struct CopyBufferTexture
- {
-#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
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/State/CopyRegion.cs b/Ryujinx.Graphics.Gpu/State/CopyRegion.cs
deleted file mode 100644
index 29889835..00000000
--- a/Ryujinx.Graphics.Gpu/State/CopyRegion.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// Texture copy region.
- /// </summary>
- struct CopyRegion
- {
-#pragma warning disable CS0649
- public int DstX;
- public int DstY;
- public int DstWidth;
- public int DstHeight;
- public long SrcWidthRF;
- public long SrcHeightRF;
- public long SrcXF;
- public long SrcYF;
-#pragma warning restore CS0649
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/State/CopyTexture.cs b/Ryujinx.Graphics.Gpu/State/CopyTexture.cs
deleted file mode 100644
index 28ea0bd8..00000000
--- a/Ryujinx.Graphics.Gpu/State/CopyTexture.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// Texture to texture (with optional resizing) copy parameters.
- /// </summary>
- struct CopyTexture
- {
-#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
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/State/DepthBiasState.cs b/Ryujinx.Graphics.Gpu/State/DepthBiasState.cs
deleted file mode 100644
index 0a125804..00000000
--- a/Ryujinx.Graphics.Gpu/State/DepthBiasState.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/FaceState.cs b/Ryujinx.Graphics.Gpu/State/FaceState.cs
deleted file mode 100644
index e817b3ae..00000000
--- a/Ryujinx.Graphics.Gpu/State/FaceState.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using Ryujinx.Graphics.GAL;
-
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/GpuState.cs b/Ryujinx.Graphics.Gpu/State/GpuState.cs
deleted file mode 100644
index 0b209da7..00000000
--- a/Ryujinx.Graphics.Gpu/State/GpuState.cs
+++ /dev/null
@@ -1,477 +0,0 @@
-using Ryujinx.Graphics.Device;
-using Ryujinx.Graphics.Gpu.Image;
-using System;
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// GPU state.
- /// </summary>
- class GpuState
- {
- private const int RegistersCount = 0xe00;
-
- public delegate void MethodCallback(GpuState state, int argument);
-
- private readonly int[] _memory;
- private readonly int[] _shadow;
-
- /// <summary>
- /// GPU register information.
- /// </summary>
- private struct Register
- {
- public MethodCallback Callback;
-
- public MethodOffset BaseOffset;
-
- public int Stride;
- public int Count;
-
- public bool Modified;
- }
-
- private readonly Register[] _registers;
-
- private readonly IDeviceState _deviceState;
-
- /// <summary>
- /// Gets or sets the shadow ram control used for this sub-channel.
- /// </summary>
- public ShadowRamControl ShadowRamControl { get; set; }
-
- /// <summary>
- /// GPU channel for the sub-channel state.
- /// </summary>
- public GpuChannel Channel { get; }
-
- /// <summary>
- /// Creates a new instance of the GPU state.
- /// </summary>
- /// <param name="channel">Channel that the sub-channel state belongs to</param>
- /// <param name="deviceState">Optional device state that will replace the internal backing storage</param>
- public GpuState(GpuChannel channel, IDeviceState deviceState = null)
- {
- Channel = channel;
- _deviceState = deviceState;
-
- _memory = new int[RegistersCount];
- _shadow = new int[RegistersCount];
-
- _registers = new Register[RegistersCount];
-
- for (int index = 0; index < _registers.Length; index++)
- {
- _registers[index].BaseOffset = (MethodOffset)index;
- _registers[index].Stride = 1;
- _registers[index].Count = 1;
- _registers[index].Modified = true;
- }
-
- foreach (var item in GpuStateTable.Table)
- {
- int totalRegs = item.Size * item.Count;
-
- for (int regOffset = 0; regOffset < totalRegs; regOffset++)
- {
- int index = (int)item.Offset + regOffset;
-
- _registers[index].BaseOffset = item.Offset;
- _registers[index].Stride = item.Size;
- _registers[index].Count = item.Count;
- }
- }
-
- InitializeDefaultState(_memory);
- InitializeDefaultState(_shadow);
- }
-
- /// <summary>
- /// Calls a GPU method, using this state.
- /// </summary>
- /// <param name="meth">The GPU method to be called</param>
- public void CallMethod(MethodParams meth)
- {
- int value = meth.Argument;
-
- // Methods < 0x80 shouldn't be affected by shadow RAM at all.
- if (meth.Method >= 0x80)
- {
- ShadowRamControl shadowCtrl = ShadowRamControl;
-
- // TODO: Figure out what TrackWithFilter does, compared to Track.
- if (shadowCtrl == ShadowRamControl.Track ||
- shadowCtrl == ShadowRamControl.TrackWithFilter)
- {
- _shadow[meth.Method] = value;
- }
- else if (shadowCtrl == ShadowRamControl.Replay)
- {
- value = _shadow[meth.Method];
- }
- }
-
- if (_deviceState != null)
- {
- _deviceState.Write(meth.Method * 4, meth.Argument);
- }
- else
- {
- Register register = _registers[meth.Method];
-
- if (_memory[meth.Method] != value)
- {
- _registers[(int)register.BaseOffset].Modified = true;
- }
-
- _memory[meth.Method] = value;
-
- register.Callback?.Invoke(this, value);
- }
- }
-
- /// <summary>
- /// Reads data from a GPU register at the given offset.
- /// </summary>
- /// <param name="offset">Offset to be read</param>
- /// <returns>Data at the register</returns>
- public int Read(int offset)
- {
- if (_deviceState != null)
- {
- return _deviceState.Read(offset * 4);
- }
-
- return _memory[offset];
- }
-
- /// <summary>
- /// Writes data to the GPU register at the given offset.
- /// </summary>
- /// <param name="offset">Offset to be written</param>
- /// <param name="value">Value to be written</param>
- public void Write(int offset, int value)
- {
- _memory[offset] = value;
- }
-
- /// <summary>
- /// Writes an offset value at the uniform buffer offset register.
- /// </summary>
- /// <param name="offset">The offset to be written</param>
- public void SetUniformBufferOffset(int offset)
- {
- _memory[(int)MethodOffset.UniformBufferState + 3] = offset;
- }
-
- /// <summary>
- /// Initializes registers with the default state.
- /// </summary>
- private void InitializeDefaultState(int[] memory)
- {
- // Enable Rasterizer
- memory[(int)MethodOffset.RasterizeEnable] = 1;
-
- // Depth ranges.
- for (int index = 0; index < Constants.TotalViewports; index++)
- {
- memory[(int)MethodOffset.ViewportExtents + index * 4 + 2] = 0;
- memory[(int)MethodOffset.ViewportExtents + index * 4 + 3] = 0x3F800000;
-
- // Set swizzle to +XYZW
- memory[(int)MethodOffset.ViewportTransform + index * 8 + 6] = 0x6420;
- }
-
- // Viewport transform enable.
- memory[(int)MethodOffset.ViewportTransformEnable] = 1;
-
- // Default front stencil mask.
- memory[0x4e7] = 0xff;
-
- // Conditional rendering condition.
- memory[0x556] = (int)Condition.Always;
-
- // Default color mask.
- for (int index = 0; index < Constants.TotalRenderTargets; index++)
- {
- memory[(int)MethodOffset.RtColorMask + index] = 0x1111;
- }
-
- // Default blend states
- Set(MethodOffset.BlendStateCommon, BlendStateCommon.Default);
-
- for (int index = 0; index < Constants.TotalRenderTargets; index++)
- {
- Set(MethodOffset.BlendState, index, BlendState.Default);
- }
-
- // Default Point Parameters
- memory[(int)MethodOffset.PointSpriteEnable] = 1;
- memory[(int)MethodOffset.PointSize] = 0x3F800000; // 1.0f
- memory[(int)MethodOffset.PointCoordReplace] = 0x8; // Enable
- }
-
- /// <summary>
- /// Registers a callback that is called every time a GPU method, or methods are called.
- /// </summary>
- /// <param name="offset">Offset of the method</param>
- /// <param name="count">Word count of the methods region</param>
- /// <param name="callback">Calllback to be called</param>
- public void RegisterCallback(MethodOffset offset, int count, MethodCallback callback)
- {
- for (int index = 0; index < count; index++)
- {
- _registers[(int)offset + index].Callback = callback;
- }
- }
-
- /// <summary>
- /// Registers a callback that is called every time a GPU method is called.
- /// </summary>
- /// <param name="offset">Offset of the method</param>
- /// <param name="callback">Calllback to be called</param>
- public void RegisterCallback(MethodOffset offset, MethodCallback callback)
- {
- _registers[(int)offset].Callback = callback;
- }
-
- /// <summary>
- /// Clear all registered callbacks.
- /// </summary>
- public void ClearCallbacks()
- {
- for (int index = 0; index < _registers.Length; index++)
- {
- _registers[index].Callback = null;
- }
- }
-
- /// <summary>
- /// Forces a full host state update by marking all state as modified,
- /// and also requests all GPU resources in use to be rebound.
- /// </summary>
- public void ForceAllDirty()
- {
- for (int index = 0; index < _registers.Length; index++)
- {
- _registers[index].Modified = true;
- }
-
- Channel.BufferManager.Rebind();
- Channel.TextureManager.Rebind();
- }
-
- /// <summary>
- /// Checks if a given register has been modified since the last call to this method.
- /// </summary>
- /// <param name="offset">Register offset</param>
- /// <returns>True if modified, false otherwise</returns>
- public bool QueryModified(MethodOffset offset)
- {
- bool modified = _registers[(int)offset].Modified;
-
- _registers[(int)offset].Modified = false;
-
- return modified;
- }
-
- /// <summary>
- /// Checks if two registers have been modified since the last call to this method.
- /// </summary>
- /// <param name="m1">First register offset</param>
- /// <param name="m2">Second register offset</param>
- /// <returns>True if any register was modified, false otherwise</returns>
- public bool QueryModified(MethodOffset m1, MethodOffset m2)
- {
- bool modified = _registers[(int)m1].Modified ||
- _registers[(int)m2].Modified;
-
- _registers[(int)m1].Modified = false;
- _registers[(int)m2].Modified = false;
-
- return modified;
- }
-
- /// <summary>
- /// Checks if three registers have been modified since the last call to this method.
- /// </summary>
- /// <param name="m1">First register offset</param>
- /// <param name="m2">Second register offset</param>
- /// <param name="m3">Third register offset</param>
- /// <returns>True if any register was modified, false otherwise</returns>
- public bool QueryModified(MethodOffset m1, MethodOffset m2, MethodOffset m3)
- {
- bool modified = _registers[(int)m1].Modified ||
- _registers[(int)m2].Modified ||
- _registers[(int)m3].Modified;
-
- _registers[(int)m1].Modified = false;
- _registers[(int)m2].Modified = false;
- _registers[(int)m3].Modified = false;
-
- return modified;
- }
-
- /// <summary>
- /// Checks if four registers have been modified since the last call to this method.
- /// </summary>
- /// <param name="m1">First register offset</param>
- /// <param name="m2">Second register offset</param>
- /// <param name="m3">Third register offset</param>
- /// <param name="m4">Fourth register offset</param>
- /// <returns>True if any register was modified, false otherwise</returns>
- public bool QueryModified(MethodOffset m1, MethodOffset m2, MethodOffset m3, MethodOffset m4)
- {
- bool modified = _registers[(int)m1].Modified ||
- _registers[(int)m2].Modified ||
- _registers[(int)m3].Modified ||
- _registers[(int)m4].Modified;
-
- _registers[(int)m1].Modified = false;
- _registers[(int)m2].Modified = false;
- _registers[(int)m3].Modified = false;
- _registers[(int)m4].Modified = false;
-
- return modified;
- }
-
- /// <summary>
- /// Checks if five registers have been modified since the last call to this method.
- /// </summary>
- /// <param name="m1">First register offset</param>
- /// <param name="m2">Second register offset</param>
- /// <param name="m3">Third register offset</param>
- /// <param name="m4">Fourth register offset</param>
- /// <param name="m5">Fifth register offset</param>
- /// <returns>True if any register was modified, false otherwise</returns>
- public bool QueryModified(
- MethodOffset m1,
- MethodOffset m2,
- MethodOffset m3,
- MethodOffset m4,
- MethodOffset m5)
- {
- bool modified = _registers[(int)m1].Modified ||
- _registers[(int)m2].Modified ||
- _registers[(int)m3].Modified ||
- _registers[(int)m4].Modified ||
- _registers[(int)m5].Modified;
-
- _registers[(int)m1].Modified = false;
- _registers[(int)m2].Modified = false;
- _registers[(int)m3].Modified = false;
- _registers[(int)m4].Modified = false;
- _registers[(int)m5].Modified = false;
-
- return modified;
- }
-
- /// <summary>
- /// Checks if six registers have been modified since the last call to this method.
- /// </summary>
- /// <param name="m1">First register offset</param>
- /// <param name="m2">Second register offset</param>
- /// <param name="m3">Third register offset</param>
- /// <param name="m4">Fourth register offset</param>
- /// <param name="m5">Fifth register offset</param>
- /// <param name="m6">Sixth register offset</param>
- /// <returns>True if any register was modified, false otherwise</returns>
- public bool QueryModified(
- MethodOffset m1,
- MethodOffset m2,
- MethodOffset m3,
- MethodOffset m4,
- MethodOffset m5,
- MethodOffset m6)
- {
- bool modified = _registers[(int)m1].Modified ||
- _registers[(int)m2].Modified ||
- _registers[(int)m3].Modified ||
- _registers[(int)m4].Modified ||
- _registers[(int)m5].Modified ||
- _registers[(int)m6].Modified;
-
- _registers[(int)m1].Modified = false;
- _registers[(int)m2].Modified = false;
- _registers[(int)m3].Modified = false;
- _registers[(int)m4].Modified = false;
- _registers[(int)m5].Modified = false;
- _registers[(int)m6].Modified = false;
-
- return modified;
- }
-
- /// <summary>
- /// Gets indexed data from a given register offset.
- /// </summary>
- /// <typeparam name="T">Type of the data</typeparam>
- /// <param name="offset">Register offset</param>
- /// <param name="index">Index for indexed data</param>
- /// <returns>The data at the specified location</returns>
- public T Get<T>(MethodOffset offset, int index) where T : unmanaged
- {
- Register register = _registers[(int)offset];
-
- if ((uint)index >= register.Count)
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
-
- return Get<T>(offset + index * register.Stride);
- }
-
- /// <summary>
- /// Gets data from a given register offset.
- /// </summary>
- /// <typeparam name="T">Type of the data</typeparam>
- /// <param name="offset">Register offset</param>
- /// <returns>The data at the specified location</returns>
- public T Get<T>(MethodOffset offset) where T : unmanaged
- {
- return MemoryMarshal.Cast<int, T>(_memory.AsSpan().Slice((int)offset))[0];
- }
-
- /// <summary>
- /// Gets a span of the data at a given register offset.
- /// </summary>
- /// <param name="offset">Register offset</param>
- /// <param name="length">Length of the data in bytes</param>
- /// <returns>The data at the specified location</returns>
- public Span<byte> GetSpan(MethodOffset offset, int length)
- {
- return MemoryMarshal.Cast<int, byte>(_memory.AsSpan().Slice((int)offset)).Slice(0, length);
- }
-
- /// <summary>
- /// Sets indexed data to a given register offset.
- /// </summary>
- /// <typeparam name="T">Type of the data</typeparam>
- /// <param name="offset">Register offset</param>
- /// <param name="index">Index for indexed data</param>
- /// <param name="data">The data to set</param>
- public void Set<T>(MethodOffset offset, int index, T data) where T : unmanaged
- {
- Register register = _registers[(int)offset];
-
- if ((uint)index >= register.Count)
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
-
- Set(offset + index * register.Stride, data);
- }
-
- /// <summary>
- /// Sets data to a given register offset.
- /// </summary>
- /// <typeparam name="T">Type of the data</typeparam>
- /// <param name="offset">Register offset</param>
- /// <param name="data">The data to set</param>
- public void Set<T>(MethodOffset offset, T data) where T : unmanaged
- {
- ReadOnlySpan<int> intSpan = MemoryMarshal.Cast<T, int>(MemoryMarshal.CreateReadOnlySpan(ref data, 1));
- intSpan.CopyTo(_memory.AsSpan().Slice((int)offset, intSpan.Length));
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/GpuStateTable.cs b/Ryujinx.Graphics.Gpu/State/GpuStateTable.cs
deleted file mode 100644
index 899e0a59..00000000
--- a/Ryujinx.Graphics.Gpu/State/GpuStateTable.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-using Ryujinx.Graphics.GAL;
-using System;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// GPU State item sizes table.
- /// </summary>
- static class GpuStateTable
- {
- /// <summary>
- /// GPU state table item, with size for structures, and count for indexed state data.
- /// </summary>
- public struct TableItem
- {
- /// <summary>
- /// Offset of the data.
- /// </summary>
- public MethodOffset Offset { get; }
-
- /// <summary>
- /// Size in words.
- /// </summary>
- public int Size { get; }
-
- /// <summary>
- /// Count for indexed data, or 1 if not indexed.
- /// </summary>
- public int Count { get; }
-
- /// <summary>
- /// Constructs the table item structure.
- /// </summary>
- /// <param name="offset">Data offset</param>
- /// <param name="type">Data type</param>
- /// <param name="count">Data count, for indexed data</param>
- public TableItem(MethodOffset offset, Type type, int count)
- {
- int sizeInBytes = Marshal.SizeOf(type);
-
- Debug.Assert((sizeInBytes & 3) == 0);
-
- Offset = offset;
- Size = sizeInBytes / 4;
- Count = count;
- }
- }
-
- /// <summary>
- /// Table of GPU state structure sizes and counts.
- /// </summary>
- public static TableItem[] Table = new TableItem[]
- {
- new TableItem(MethodOffset.TfBufferState, typeof(TfBufferState), Constants.TotalTransformFeedbackBuffers),
- new TableItem(MethodOffset.TfState, typeof(TfState), Constants.TotalTransformFeedbackBuffers),
- new TableItem(MethodOffset.RtColorState, typeof(RtColorState), Constants.TotalRenderTargets),
- new TableItem(MethodOffset.ViewportTransform, typeof(ViewportTransform), Constants.TotalViewports),
- new TableItem(MethodOffset.ViewportExtents, typeof(ViewportExtents), Constants.TotalViewports),
- new TableItem(MethodOffset.VertexBufferDrawState, typeof(VertexBufferDrawState), 1),
- new TableItem(MethodOffset.DepthBiasState, typeof(DepthBiasState), 1),
- new TableItem(MethodOffset.ScissorState, typeof(ScissorState), Constants.TotalViewports),
- new TableItem(MethodOffset.StencilBackMasks, typeof(StencilBackMasks), 1),
- new TableItem(MethodOffset.RtDepthStencilState, typeof(RtDepthStencilState), 1),
- new TableItem(MethodOffset.VertexAttribState, typeof(VertexAttribState), Constants.TotalVertexAttribs),
- new TableItem(MethodOffset.RtDepthStencilSize, typeof(Size3D), 1),
- new TableItem(MethodOffset.BlendEnable, typeof(Boolean32), Constants.TotalRenderTargets),
- new TableItem(MethodOffset.StencilTestState, typeof(StencilTestState), 1),
- new TableItem(MethodOffset.SamplerPoolState, typeof(PoolState), 1),
- new TableItem(MethodOffset.TexturePoolState, typeof(PoolState), 1),
- new TableItem(MethodOffset.StencilBackTestState, typeof(StencilBackTestState), 1),
- new TableItem(MethodOffset.ShaderBaseAddress, typeof(GpuVa), 1),
- new TableItem(MethodOffset.PrimitiveRestartState, typeof(PrimitiveRestartState), 1),
- new TableItem(MethodOffset.IndexBufferState, typeof(IndexBufferState), 1),
- new TableItem(MethodOffset.VertexBufferInstanced, typeof(Boolean32), Constants.TotalVertexBuffers),
- new TableItem(MethodOffset.FaceState, typeof(FaceState), 1),
- new TableItem(MethodOffset.RtColorMask, typeof(RtColorMask), Constants.TotalRenderTargets),
- new TableItem(MethodOffset.VertexBufferState, typeof(VertexBufferState), Constants.TotalVertexBuffers),
- new TableItem(MethodOffset.BlendConstant, typeof(ColorF), 1),
- new TableItem(MethodOffset.BlendStateCommon, typeof(BlendStateCommon), 1),
- new TableItem(MethodOffset.BlendState, typeof(BlendState), Constants.TotalRenderTargets),
- new TableItem(MethodOffset.VertexBufferEndAddress, typeof(GpuVa), Constants.TotalVertexBuffers),
- new TableItem(MethodOffset.ShaderState, typeof(ShaderState), Constants.ShaderStages + 1),
- };
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/State/IndexBufferState.cs b/Ryujinx.Graphics.Gpu/State/IndexBufferState.cs
deleted file mode 100644
index 8ae38bb8..00000000
--- a/Ryujinx.Graphics.Gpu/State/IndexBufferState.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using Ryujinx.Graphics.GAL;
-
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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;
- public int Count;
-#pragma warning restore CS0649
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/Inline2MemoryParams.cs b/Ryujinx.Graphics.Gpu/State/Inline2MemoryParams.cs
deleted file mode 100644
index f4009592..00000000
--- a/Ryujinx.Graphics.Gpu/State/Inline2MemoryParams.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// Inline-to-memory copy parameters.
- /// </summary>
- struct Inline2MemoryParams
- {
-#pragma warning disable CS0649
- public int LineLengthIn;
- public int LineCount;
- public GpuVa DstAddress;
- public int DstStride;
- public MemoryLayout DstMemoryLayout;
- public int DstWidth;
- public int DstHeight;
- public int DstDepth;
- public int DstZ;
- public int DstX;
- public int DstY;
-#pragma warning restore CS0649
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/State/LogicalOpState.cs b/Ryujinx.Graphics.Gpu/State/LogicalOpState.cs
deleted file mode 100644
index d052a45c..00000000
--- a/Ryujinx.Graphics.Gpu/State/LogicalOpState.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using Ryujinx.Graphics.GAL;
-
-namespace Ryujinx.Graphics.Gpu.State
-{
- struct LogicalOpState
- {
-#pragma warning disable CS0649
- public Boolean32 Enable;
- public LogicalOp LogicalOp;
-#pragma warning restore CS0649
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/MethodOffset.cs b/Ryujinx.Graphics.Gpu/State/MethodOffset.cs
deleted file mode 100644
index 1ddef95c..00000000
--- a/Ryujinx.Graphics.Gpu/State/MethodOffset.cs
+++ /dev/null
@@ -1,134 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// GPU method offset.
- /// </summary>
- /// <remarks>
- /// This is indexed in 32 bits word.
- /// </remarks>
- enum MethodOffset
- {
- BindChannel = 0x0,
- I2mParams = 0x60,
- LaunchDma = 0x6c,
- LoadInlineData = 0x6d,
- CopyDstTexture = 0x80,
- EarlyZForce = 0x84,
- CopySrcTexture = 0x8c,
- DispatchParamsAddress = 0xad,
- Dispatch = 0xaf,
- SyncpointAction = 0xb2,
- CopyBuffer = 0xc0,
- RasterizeEnable = 0xdf,
- TfBufferState = 0xe0,
- CopyBufferParams = 0x100,
- TfState = 0x1c0,
- CopyBufferConstA = 0x1c0,
- CopyBufferConstB = 0x1c1,
- CopyBufferSwizzle = 0x1c2,
- CopyBufferDstTexture = 0x1c3,
- CopyBufferSrcTexture = 0x1ca,
- TfEnable = 0x1d1,
- RtColorState = 0x200,
- CopyTextureControl = 0x223,
- CopyRegion = 0x22c,
- CopyTexture = 0x237,
- ViewportTransform = 0x280,
- ViewportExtents = 0x300,
- VertexBufferDrawState = 0x35d,
- DepthMode = 0x35f,
- ClearColors = 0x360,
- ClearDepthValue = 0x364,
- ClearStencilValue = 0x368,
- DepthBiasState = 0x370,
- TextureBarrier = 0x378,
- ScissorState = 0x380,
- StencilBackMasks = 0x3d5,
- InvalidateTextures = 0x3dd,
- TextureBarrierTiled = 0x3df,
- RtColorMaskShared = 0x3e4,
- RtDepthStencilState = 0x3f8,
- ScreenScissorState = 0x3fd,
- VertexAttribState = 0x458,
- RtControl = 0x487,
- RtDepthStencilSize = 0x48a,
- SamplerIndex = 0x48d,
- DepthTestEnable = 0x4b3,
- BlendIndependent = 0x4b9,
- DepthWriteEnable = 0x4ba,
- AlphaTestEnable = 0x4bb,
- VbElementU8 = 0x4c1,
- DepthTestFunc = 0x4c3,
- AlphaTestRef = 0x4c4,
- AlphaTestFunc = 0x4c5,
- BlendConstant = 0x4c7,
- BlendStateCommon = 0x4cf,
- BlendEnableCommon = 0x4d7,
- BlendEnable = 0x4d8,
- StencilTestState = 0x4e0,
- YControl = 0x4eb,
- LineWidthSmooth = 0x4ec,
- LineWidthAliased = 0x4ed,
- FirstVertex = 0x50d,
- FirstInstance = 0x50e,
- ClipDistanceEnable = 0x544,
- PointSize = 0x546,
- PointSpriteEnable = 0x548,
- ResetCounter = 0x54c,
- RtDepthStencilEnable = 0x54e,
- ConditionState = 0x554,
- SamplerPoolState = 0x557,
- DepthBiasFactor = 0x55b,
- LineSmoothEnable = 0x55c,
- TexturePoolState = 0x55d,
- StencilBackTestState = 0x565,
- DepthBiasUnits = 0x56f,
- RtMsaaMode = 0x574,
- VbElementU32 = 0x57a,
- VbElementU16 = 0x57c,
- PointCoordReplace = 0x581,
- ShaderBaseAddress = 0x582,
- DrawEnd = 0x585,
- DrawBegin = 0x586,
- PrimitiveRestartState = 0x591,
- IndexBufferState = 0x5f2,
- IndexBufferCount = 0x5f8,
- DrawIndexedSmall = 0x5f9,
- DrawIndexedSmall2 = 0x5fa,
- DrawIndexedSmallIncInstance = 0x5fc,
- DrawIndexedSmallIncInstance2 = 0x5fd,
- DepthBiasClamp = 0x61f,
- VertexBufferInstanced = 0x620,
- VertexProgramPointSize = 0x644,
- FaceState = 0x646,
- ViewportTransformEnable = 0x64b,
- ViewVolumeClipControl = 0x64f,
- PrimitiveTypeOverride = 0x65c,
- LogicOpState = 0x671,
- Clear = 0x674,
- RtColorMask = 0x680,
- ReportState = 0x6c0,
- Report = 0x6c3,
- VertexBufferState = 0x700,
- BlendState = 0x780,
- VertexBufferEndAddress = 0x7c0,
- ShaderState = 0x800,
- FirmwareCall0 = 0x8c0,
- FirmwareCall1 = 0x8c1,
- FirmwareCall2 = 0x8c2,
- FirmwareCall3 = 0x8c3,
- FirmwareCall4 = 0x8c4,
- FirmwareCall5 = 0x8c5,
- FirmwareCall6 = 0x8c6,
- FirmwareCall7 = 0x8c7,
- UniformBufferState = 0x8e0,
- UniformBufferUpdateData = 0x8e4,
- UniformBufferBindVertex = 0x904,
- UniformBufferBindTessControl = 0x90c,
- UniformBufferBindTessEvaluation = 0x914,
- UniformBufferBindGeometry = 0x91c,
- UniformBufferBindFragment = 0x924,
- TextureBufferIndex = 0x982,
- TfVaryingLocations = 0xa00
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/State/PoolState.cs b/Ryujinx.Graphics.Gpu/State/PoolState.cs
deleted file mode 100644
index ba4dfb78..00000000
--- a/Ryujinx.Graphics.Gpu/State/PoolState.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// Texture or sampler pool state.
- /// </summary>
- struct PoolState
- {
-#pragma warning disable CS0649
- public GpuVa Address;
- public int MaximumId;
-#pragma warning restore CS0649
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/State/PrimitiveRestartState.cs b/Ryujinx.Graphics.Gpu/State/PrimitiveRestartState.cs
deleted file mode 100644
index d046b522..00000000
--- a/Ryujinx.Graphics.Gpu/State/PrimitiveRestartState.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// Primitive restart state.
- /// </summary>
- struct PrimitiveRestartState
- {
-#pragma warning disable CS0649
- public Boolean32 Enable;
- public int Index;
-#pragma warning restore CS0649
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/ReportCounterType.cs b/Ryujinx.Graphics.Gpu/State/ReportCounterType.cs
deleted file mode 100644
index 6bde2844..00000000
--- a/Ryujinx.Graphics.Gpu/State/ReportCounterType.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// Counter type for GPU counter reporting.
- /// </summary>
- 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
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/State/ResetCounterType.cs b/Ryujinx.Graphics.Gpu/State/ResetCounterType.cs
deleted file mode 100644
index aaf575e1..00000000
--- a/Ryujinx.Graphics.Gpu/State/ResetCounterType.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// Counter type for GPU counter reset.
- /// </summary>
- 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
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/State/RtColorMask.cs b/Ryujinx.Graphics.Gpu/State/RtColorMask.cs
deleted file mode 100644
index 3567bf37..00000000
--- a/Ryujinx.Graphics.Gpu/State/RtColorMask.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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;
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/RtColorState.cs b/Ryujinx.Graphics.Gpu/State/RtColorState.cs
deleted file mode 100644
index 457725ff..00000000
--- a/Ryujinx.Graphics.Gpu/State/RtColorState.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/RtControl.cs b/Ryujinx.Graphics.Gpu/State/RtControl.cs
deleted file mode 100644
index 8b6b1867..00000000
--- a/Ryujinx.Graphics.Gpu/State/RtControl.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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);
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/RtDepthStencilState.cs b/Ryujinx.Graphics.Gpu/State/RtDepthStencilState.cs
deleted file mode 100644
index 3886f58c..00000000
--- a/Ryujinx.Graphics.Gpu/State/RtDepthStencilState.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/ScissorState.cs b/Ryujinx.Graphics.Gpu/State/ScissorState.cs
deleted file mode 100644
index 4f4b02dc..00000000
--- a/Ryujinx.Graphics.Gpu/State/ScissorState.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- 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
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/ScreenScissorState.cs b/Ryujinx.Graphics.Gpu/State/ScreenScissorState.cs
deleted file mode 100644
index 2fbf9934..00000000
--- a/Ryujinx.Graphics.Gpu/State/ScreenScissorState.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- struct ScreenScissorState
- {
-#pragma warning disable CS0649
- public ushort X;
- public ushort Width;
- public ushort Y;
- public ushort Height;
-#pragma warning restore CS0649
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/SemaphoreOperation.cs b/Ryujinx.Graphics.Gpu/State/SemaphoreOperation.cs
deleted file mode 100644
index 67f3c127..00000000
--- a/Ryujinx.Graphics.Gpu/State/SemaphoreOperation.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// GPU semaphore operation.
- /// </summary>
- enum SemaphoreOperation
- {
- Release = 0,
- Acquire = 1,
- Counter = 2
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/State/SemaphoreState.cs b/Ryujinx.Graphics.Gpu/State/SemaphoreState.cs
deleted file mode 100644
index bfc5720a..00000000
--- a/Ryujinx.Graphics.Gpu/State/SemaphoreState.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// GPU semaphore state.
- /// </summary>
- struct SemaphoreState
- {
-#pragma warning disable CS0649
- public GpuVa Address;
- public int Payload;
- public uint Control;
-#pragma warning restore CS0649
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/ShaderState.cs b/Ryujinx.Graphics.Gpu/State/ShaderState.cs
deleted file mode 100644
index 4cf67c74..00000000
--- a/Ryujinx.Graphics.Gpu/State/ShaderState.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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;
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/ShaderType.cs b/Ryujinx.Graphics.Gpu/State/ShaderType.cs
deleted file mode 100644
index 58506821..00000000
--- a/Ryujinx.Graphics.Gpu/State/ShaderType.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// Shader stage name.
- /// </summary>
- enum ShaderType
- {
- Vertex,
- TessellationControl,
- TessellationEvaluation,
- Geometry,
- Fragment
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/Size3D.cs b/Ryujinx.Graphics.Gpu/State/Size3D.cs
deleted file mode 100644
index 1c127da6..00000000
--- a/Ryujinx.Graphics.Gpu/State/Size3D.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/StencilBackMasks.cs b/Ryujinx.Graphics.Gpu/State/StencilBackMasks.cs
deleted file mode 100644
index 49061cc5..00000000
--- a/Ryujinx.Graphics.Gpu/State/StencilBackMasks.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/StencilBackTestState.cs b/Ryujinx.Graphics.Gpu/State/StencilBackTestState.cs
deleted file mode 100644
index 16655322..00000000
--- a/Ryujinx.Graphics.Gpu/State/StencilBackTestState.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Ryujinx.Graphics.GAL;
-
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/StencilTestState.cs b/Ryujinx.Graphics.Gpu/State/StencilTestState.cs
deleted file mode 100644
index 72f85f2b..00000000
--- a/Ryujinx.Graphics.Gpu/State/StencilTestState.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using Ryujinx.Graphics.GAL;
-
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/TfBufferState.cs b/Ryujinx.Graphics.Gpu/State/TfBufferState.cs
deleted file mode 100644
index 24dc0952..00000000
--- a/Ryujinx.Graphics.Gpu/State/TfBufferState.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/TfState.cs b/Ryujinx.Graphics.Gpu/State/TfState.cs
deleted file mode 100644
index fb8b950b..00000000
--- a/Ryujinx.Graphics.Gpu/State/TfState.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/UniformBufferState.cs b/Ryujinx.Graphics.Gpu/State/UniformBufferState.cs
deleted file mode 100644
index d547ea82..00000000
--- a/Ryujinx.Graphics.Gpu/State/UniformBufferState.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/VertexAttribState.cs b/Ryujinx.Graphics.Gpu/State/VertexAttribState.cs
deleted file mode 100644
index dbb75a5b..00000000
--- a/Ryujinx.Graphics.Gpu/State/VertexAttribState.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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;
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/VertexBufferDrawState.cs b/Ryujinx.Graphics.Gpu/State/VertexBufferDrawState.cs
deleted file mode 100644
index 3e11838a..00000000
--- a/Ryujinx.Graphics.Gpu/State/VertexBufferDrawState.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <summary>
- /// Draw state for non-indexed draws.
- /// </summary>
- struct VertexBufferDrawState
- {
-#pragma warning disable CS0649
- public int First;
- public int Count;
-#pragma warning restore CS0649
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/VertexBufferState.cs b/Ryujinx.Graphics.Gpu/State/VertexBufferState.cs
deleted file mode 100644
index 85176d82..00000000
--- a/Ryujinx.Graphics.Gpu/State/VertexBufferState.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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;
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/ViewVolumeClipControl.cs b/Ryujinx.Graphics.Gpu/State/ViewVolumeClipControl.cs
deleted file mode 100644
index ace8342c..00000000
--- a/Ryujinx.Graphics.Gpu/State/ViewVolumeClipControl.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-
-namespace Ryujinx.Graphics.Gpu.State
-{
- [Flags]
- enum ViewVolumeClipControl
- {
- ForceDepthRangeZeroToOne = 1 << 0,
- DepthClampDisabled = 1 << 11,
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/State/ViewportExtents.cs b/Ryujinx.Graphics.Gpu/State/ViewportExtents.cs
deleted file mode 100644
index d7728f41..00000000
--- a/Ryujinx.Graphics.Gpu/State/ViewportExtents.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/ViewportTransform.cs b/Ryujinx.Graphics.Gpu/State/ViewportTransform.cs
deleted file mode 100644
index b795ea15..00000000
--- a/Ryujinx.Graphics.Gpu/State/ViewportTransform.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using Ryujinx.Graphics.GAL;
-
-namespace Ryujinx.Graphics.Gpu.State
-{
- /// <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);
- }
- }
-}
diff --git a/Ryujinx.Graphics.Gpu/State/YControl.cs b/Ryujinx.Graphics.Gpu/State/YControl.cs
deleted file mode 100644
index 58e000d9..00000000
--- a/Ryujinx.Graphics.Gpu/State/YControl.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-
-namespace Ryujinx.Graphics.Gpu.State
-{
- [Flags]
- enum YControl
- {
- NegateY = 1 << 0,
- TriangleRastFlip = 1 << 4
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs b/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs
index 1fcc12b5..024b0bb4 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs
+++ b/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs
@@ -1,9 +1,9 @@
-using Ryujinx.Graphics.Gpu;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Host1x;
using Ryujinx.Graphics.Nvdec;
using Ryujinx.Graphics.Vic;
using System;
+using GpuContext = Ryujinx.Graphics.Gpu.GpuContext;
namespace Ryujinx.HLE.HOS.Services.Nv
{
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/ChannelInitialization.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/ChannelInitialization.cs
new file mode 100644
index 00000000..87a06bd3
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/ChannelInitialization.cs
@@ -0,0 +1,1361 @@
+using Ryujinx.Graphics.Gpu;
+
+namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
+{
+ static class ChannelInitialization
+ {
+ public static void InitializeState(GpuChannel channel)
+ {
+ channel.Write(ClassId.Threed, 0x800, 0x0);
+ channel.Write(ClassId.Threed, 0x840, 0x0);
+ channel.Write(ClassId.Threed, 0x880, 0x0);
+ channel.Write(ClassId.Threed, 0x8C0, 0x0);
+ channel.Write(ClassId.Threed, 0x900, 0x0);
+ channel.Write(ClassId.Threed, 0x940, 0x0);
+ channel.Write(ClassId.Threed, 0x980, 0x0);
+ channel.Write(ClassId.Threed, 0x9C0, 0x0);
+ channel.Write(ClassId.Threed, 0x804, 0x0);
+ channel.Write(ClassId.Threed, 0x844, 0x0);
+ channel.Write(ClassId.Threed, 0x884, 0x0);
+ channel.Write(ClassId.Threed, 0x8C4, 0x0);
+ channel.Write(ClassId.Threed, 0x904, 0x0);
+ channel.Write(ClassId.Threed, 0x944, 0x0);
+ channel.Write(ClassId.Threed, 0x984, 0x0);
+ channel.Write(ClassId.Threed, 0x9C4, 0x0);
+ channel.Write(ClassId.Threed, 0x808, 0x400);
+ channel.Write(ClassId.Threed, 0x848, 0x400);
+ channel.Write(ClassId.Threed, 0x888, 0x400);
+ channel.Write(ClassId.Threed, 0x8C8, 0x400);
+ channel.Write(ClassId.Threed, 0x908, 0x400);
+ channel.Write(ClassId.Threed, 0x948, 0x400);
+ channel.Write(ClassId.Threed, 0x988, 0x400);
+ channel.Write(ClassId.Threed, 0x9C8, 0x400);
+ channel.Write(ClassId.Threed, 0x80C, 0x300);
+ channel.Write(ClassId.Threed, 0x84C, 0x300);
+ channel.Write(ClassId.Threed, 0x88C, 0x300);
+ channel.Write(ClassId.Threed, 0x8CC, 0x300);
+ channel.Write(ClassId.Threed, 0x90C, 0x300);
+ channel.Write(ClassId.Threed, 0x94C, 0x300);
+ channel.Write(ClassId.Threed, 0x98C, 0x300);
+ channel.Write(ClassId.Threed, 0x9CC, 0x300);
+ channel.Write(ClassId.Threed, 0x810, 0xCF);
+ channel.Write(ClassId.Threed, 0x850, 0x0);
+ channel.Write(ClassId.Threed, 0x890, 0x0);
+ channel.Write(ClassId.Threed, 0x8D0, 0x0);
+ channel.Write(ClassId.Threed, 0x910, 0x0);
+ channel.Write(ClassId.Threed, 0x950, 0x0);
+ channel.Write(ClassId.Threed, 0x990, 0x0);
+ channel.Write(ClassId.Threed, 0x9D0, 0x0);
+ channel.Write(ClassId.Threed, 0x814, 0x40);
+ channel.Write(ClassId.Threed, 0x854, 0x40);
+ channel.Write(ClassId.Threed, 0x894, 0x40);
+ channel.Write(ClassId.Threed, 0x8D4, 0x40);
+ channel.Write(ClassId.Threed, 0x914, 0x40);
+ channel.Write(ClassId.Threed, 0x954, 0x40);
+ channel.Write(ClassId.Threed, 0x994, 0x40);
+ channel.Write(ClassId.Threed, 0x9D4, 0x40);
+ channel.Write(ClassId.Threed, 0x818, 0x1);
+ channel.Write(ClassId.Threed, 0x858, 0x1);
+ channel.Write(ClassId.Threed, 0x898, 0x1);
+ channel.Write(ClassId.Threed, 0x8D8, 0x1);
+ channel.Write(ClassId.Threed, 0x918, 0x1);
+ channel.Write(ClassId.Threed, 0x958, 0x1);
+ channel.Write(ClassId.Threed, 0x998, 0x1);
+ channel.Write(ClassId.Threed, 0x9D8, 0x1);
+ channel.Write(ClassId.Threed, 0x81C, 0x0);
+ channel.Write(ClassId.Threed, 0x85C, 0x0);
+ channel.Write(ClassId.Threed, 0x89C, 0x0);
+ channel.Write(ClassId.Threed, 0x8DC, 0x0);
+ channel.Write(ClassId.Threed, 0x91C, 0x0);
+ channel.Write(ClassId.Threed, 0x95C, 0x0);
+ channel.Write(ClassId.Threed, 0x99C, 0x0);
+ channel.Write(ClassId.Threed, 0x9DC, 0x0);
+ channel.Write(ClassId.Threed, 0x820, 0x0);
+ channel.Write(ClassId.Threed, 0x860, 0x0);
+ channel.Write(ClassId.Threed, 0x8A0, 0x0);
+ channel.Write(ClassId.Threed, 0x8E0, 0x0);
+ channel.Write(ClassId.Threed, 0x920, 0x0);
+ channel.Write(ClassId.Threed, 0x960, 0x0);
+ channel.Write(ClassId.Threed, 0x9A0, 0x0);
+ channel.Write(ClassId.Threed, 0x9E0, 0x0);
+ channel.Write(ClassId.Threed, 0x1C00, 0x0);
+ channel.Write(ClassId.Threed, 0x1C10, 0x0);
+ channel.Write(ClassId.Threed, 0x1C20, 0x0);
+ channel.Write(ClassId.Threed, 0x1C30, 0x0);
+ channel.Write(ClassId.Threed, 0x1C40, 0x0);
+ channel.Write(ClassId.Threed, 0x1C50, 0x0);
+ channel.Write(ClassId.Threed, 0x1C60, 0x0);
+ channel.Write(ClassId.Threed, 0x1C70, 0x0);
+ channel.Write(ClassId.Threed, 0x1C80, 0x0);
+ channel.Write(ClassId.Threed, 0x1C90, 0x0);
+ channel.Write(ClassId.Threed, 0x1CA0, 0x0);
+ channel.Write(ClassId.Threed, 0x1CB0, 0x0);
+ channel.Write(ClassId.Threed, 0x1CC0, 0x0);
+ channel.Write(ClassId.Threed, 0x1CD0, 0x0);
+ channel.Write(ClassId.Threed, 0x1CE0, 0x0);
+ channel.Write(ClassId.Threed, 0x1CF0, 0x0);
+ channel.Write(ClassId.Threed, 0x1C04, 0x0);
+ channel.Write(ClassId.Threed, 0x1C14, 0x0);
+ channel.Write(ClassId.Threed, 0x1C24, 0x0);
+ channel.Write(ClassId.Threed, 0x1C34, 0x0);
+ channel.Write(ClassId.Threed, 0x1C44, 0x0);
+ channel.Write(ClassId.Threed, 0x1C54, 0x0);
+ channel.Write(ClassId.Threed, 0x1C64, 0x0);
+ channel.Write(ClassId.Threed, 0x1C74, 0x0);
+ channel.Write(ClassId.Threed, 0x1C84, 0x0);
+ channel.Write(ClassId.Threed, 0x1C94, 0x0);
+ channel.Write(ClassId.Threed, 0x1CA4, 0x0);
+ channel.Write(ClassId.Threed, 0x1CB4, 0x0);
+ channel.Write(ClassId.Threed, 0x1CC4, 0x0);
+ channel.Write(ClassId.Threed, 0x1CD4, 0x0);
+ channel.Write(ClassId.Threed, 0x1CE4, 0x0);
+ channel.Write(ClassId.Threed, 0x1CF4, 0x0);
+ channel.Write(ClassId.Threed, 0x1C08, 0x0);
+ channel.Write(ClassId.Threed, 0x1C18, 0x0);
+ channel.Write(ClassId.Threed, 0x1C28, 0x0);
+ channel.Write(ClassId.Threed, 0x1C38, 0x0);
+ channel.Write(ClassId.Threed, 0x1C48, 0x0);
+ channel.Write(ClassId.Threed, 0x1C58, 0x0);
+ channel.Write(ClassId.Threed, 0x1C68, 0x0);
+ channel.Write(ClassId.Threed, 0x1C78, 0x0);
+ channel.Write(ClassId.Threed, 0x1C88, 0x0);
+ channel.Write(ClassId.Threed, 0x1C98, 0x0);
+ channel.Write(ClassId.Threed, 0x1CA8, 0x0);
+ channel.Write(ClassId.Threed, 0x1CB8, 0x0);
+ channel.Write(ClassId.Threed, 0x1CC8, 0x0);
+ channel.Write(ClassId.Threed, 0x1CD8, 0x0);
+ channel.Write(ClassId.Threed, 0x1CE8, 0x0);
+ channel.Write(ClassId.Threed, 0x1CF8, 0x0);
+ channel.Write(ClassId.Threed, 0x1C0C, 0x0);
+ channel.Write(ClassId.Threed, 0x1C1C, 0x0);
+ channel.Write(ClassId.Threed, 0x1C2C, 0x0);
+ channel.Write(ClassId.Threed, 0x1C3C, 0x0);
+ channel.Write(ClassId.Threed, 0x1C4C, 0x0);
+ channel.Write(ClassId.Threed, 0x1C5C, 0x0);
+ channel.Write(ClassId.Threed, 0x1C6C, 0x0);
+ channel.Write(ClassId.Threed, 0x1C7C, 0x0);
+ channel.Write(ClassId.Threed, 0x1C8C, 0x0);
+ channel.Write(ClassId.Threed, 0x1C9C, 0x0);
+ channel.Write(ClassId.Threed, 0x1CAC, 0x0);
+ channel.Write(ClassId.Threed, 0x1CBC, 0x0);
+ channel.Write(ClassId.Threed, 0x1CCC, 0x0);
+ channel.Write(ClassId.Threed, 0x1CDC, 0x0);
+ channel.Write(ClassId.Threed, 0x1CEC, 0x0);
+ channel.Write(ClassId.Threed, 0x1CFC, 0x0);
+ channel.Write(ClassId.Threed, 0x1D00, 0x0);
+ channel.Write(ClassId.Threed, 0x1D10, 0x0);
+ channel.Write(ClassId.Threed, 0x1D20, 0x0);
+ channel.Write(ClassId.Threed, 0x1D30, 0x0);
+ channel.Write(ClassId.Threed, 0x1D40, 0x0);
+ channel.Write(ClassId.Threed, 0x1D50, 0x0);
+ channel.Write(ClassId.Threed, 0x1D60, 0x0);
+ channel.Write(ClassId.Threed, 0x1D70, 0x0);
+ channel.Write(ClassId.Threed, 0x1D80, 0x0);
+ channel.Write(ClassId.Threed, 0x1D90, 0x0);
+ channel.Write(ClassId.Threed, 0x1DA0, 0x0);
+ channel.Write(ClassId.Threed, 0x1DB0, 0x0);
+ channel.Write(ClassId.Threed, 0x1DC0, 0x0);
+ channel.Write(ClassId.Threed, 0x1DD0, 0x0);
+ channel.Write(ClassId.Threed, 0x1DE0, 0x0);
+ channel.Write(ClassId.Threed, 0x1DF0, 0x0);
+ channel.Write(ClassId.Threed, 0x1D04, 0x0);
+ channel.Write(ClassId.Threed, 0x1D14, 0x0);
+ channel.Write(ClassId.Threed, 0x1D24, 0x0);
+ channel.Write(ClassId.Threed, 0x1D34, 0x0);
+ channel.Write(ClassId.Threed, 0x1D44, 0x0);
+ channel.Write(ClassId.Threed, 0x1D54, 0x0);
+ channel.Write(ClassId.Threed, 0x1D64, 0x0);
+ channel.Write(ClassId.Threed, 0x1D74, 0x0);
+ channel.Write(ClassId.Threed, 0x1D84, 0x0);
+ channel.Write(ClassId.Threed, 0x1D94, 0x0);
+ channel.Write(ClassId.Threed, 0x1DA4, 0x0);
+ channel.Write(ClassId.Threed, 0x1DB4, 0x0);
+ channel.Write(ClassId.Threed, 0x1DC4, 0x0);
+ channel.Write(ClassId.Threed, 0x1DD4, 0x0);
+ channel.Write(ClassId.Threed, 0x1DE4, 0x0);
+ channel.Write(ClassId.Threed, 0x1DF4, 0x0);
+ channel.Write(ClassId.Threed, 0x1D08, 0x0);
+ channel.Write(ClassId.Threed, 0x1D18, 0x0);
+ channel.Write(ClassId.Threed, 0x1D28, 0x0);
+ channel.Write(ClassId.Threed, 0x1D38, 0x0);
+ channel.Write(ClassId.Threed, 0x1D48, 0x0);
+ channel.Write(ClassId.Threed, 0x1D58, 0x0);
+ channel.Write(ClassId.Threed, 0x1D68, 0x0);
+ channel.Write(ClassId.Threed, 0x1D78, 0x0);
+ channel.Write(ClassId.Threed, 0x1D88, 0x0);
+ channel.Write(ClassId.Threed, 0x1D98, 0x0);
+ channel.Write(ClassId.Threed, 0x1DA8, 0x0);
+ channel.Write(ClassId.Threed, 0x1DB8, 0x0);
+ channel.Write(ClassId.Threed, 0x1DC8, 0x0);
+ channel.Write(ClassId.Threed, 0x1DD8, 0x0);
+ channel.Write(ClassId.Threed, 0x1DE8, 0x0);
+ channel.Write(ClassId.Threed, 0x1DF8, 0x0);
+ channel.Write(ClassId.Threed, 0x1D0C, 0x0);
+ channel.Write(ClassId.Threed, 0x1D1C, 0x0);
+ channel.Write(ClassId.Threed, 0x1D2C, 0x0);
+ channel.Write(ClassId.Threed, 0x1D3C, 0x0);
+ channel.Write(ClassId.Threed, 0x1D4C, 0x0);
+ channel.Write(ClassId.Threed, 0x1D5C, 0x0);
+ channel.Write(ClassId.Threed, 0x1D6C, 0x0);
+ channel.Write(ClassId.Threed, 0x1D7C, 0x0);
+ channel.Write(ClassId.Threed, 0x1D8C, 0x0);
+ channel.Write(ClassId.Threed, 0x1D9C, 0x0);
+ channel.Write(ClassId.Threed, 0x1DAC, 0x0);
+ channel.Write(ClassId.Threed, 0x1DBC, 0x0);
+ channel.Write(ClassId.Threed, 0x1DCC, 0x0);
+ channel.Write(ClassId.Threed, 0x1DDC, 0x0);
+ channel.Write(ClassId.Threed, 0x1DEC, 0x0);
+ channel.Write(ClassId.Threed, 0x1DFC, 0x0);
+ channel.Write(ClassId.Threed, 0x1F00, 0x0);
+ channel.Write(ClassId.Threed, 0x1F08, 0x0);
+ channel.Write(ClassId.Threed, 0x1F10, 0x0);
+ channel.Write(ClassId.Threed, 0x1F18, 0x0);
+ channel.Write(ClassId.Threed, 0x1F20, 0x0);
+ channel.Write(ClassId.Threed, 0x1F28, 0x0);
+ channel.Write(ClassId.Threed, 0x1F30, 0x0);
+ channel.Write(ClassId.Threed, 0x1F38, 0x0);
+ channel.Write(ClassId.Threed, 0x1F40, 0x0);
+ channel.Write(ClassId.Threed, 0x1F48, 0x0);
+ channel.Write(ClassId.Threed, 0x1F50, 0x0);
+ channel.Write(ClassId.Threed, 0x1F58, 0x0);
+ channel.Write(ClassId.Threed, 0x1F60, 0x0);
+ channel.Write(ClassId.Threed, 0x1F68, 0x0);
+ channel.Write(ClassId.Threed, 0x1F70, 0x0);
+ channel.Write(ClassId.Threed, 0x1F78, 0x0);
+ channel.Write(ClassId.Threed, 0x1F04, 0x0);
+ channel.Write(ClassId.Threed, 0x1F0C, 0x0);
+ channel.Write(ClassId.Threed, 0x1F14, 0x0);
+ channel.Write(ClassId.Threed, 0x1F1C, 0x0);
+ channel.Write(ClassId.Threed, 0x1F24, 0x0);
+ channel.Write(ClassId.Threed, 0x1F2C, 0x0);
+ channel.Write(ClassId.Threed, 0x1F34, 0x0);
+ channel.Write(ClassId.Threed, 0x1F3C, 0x0);
+ channel.Write(ClassId.Threed, 0x1F44, 0x0);
+ channel.Write(ClassId.Threed, 0x1F4C, 0x0);
+ channel.Write(ClassId.Threed, 0x1F54, 0x0);
+ channel.Write(ClassId.Threed, 0x1F5C, 0x0);
+ channel.Write(ClassId.Threed, 0x1F64, 0x0);
+ channel.Write(ClassId.Threed, 0x1F6C, 0x0);
+ channel.Write(ClassId.Threed, 0x1F74, 0x0);
+ channel.Write(ClassId.Threed, 0x1F7C, 0x0);
+ channel.Write(ClassId.Threed, 0x1F80, 0x0);
+ channel.Write(ClassId.Threed, 0x1F88, 0x0);
+ channel.Write(ClassId.Threed, 0x1F90, 0x0);
+ channel.Write(ClassId.Threed, 0x1F98, 0x0);
+ channel.Write(ClassId.Threed, 0x1FA0, 0x0);
+ channel.Write(ClassId.Threed, 0x1FA8, 0x0);
+ channel.Write(ClassId.Threed, 0x1FB0, 0x0);
+ channel.Write(ClassId.Threed, 0x1FB8, 0x0);
+ channel.Write(ClassId.Threed, 0x1FC0, 0x0);
+ channel.Write(ClassId.Threed, 0x1FC8, 0x0);
+ channel.Write(ClassId.Threed, 0x1FD0, 0x0);
+ channel.Write(ClassId.Threed, 0x1FD8, 0x0);
+ channel.Write(ClassId.Threed, 0x1FE0, 0x0);
+ channel.Write(ClassId.Threed, 0x1FE8, 0x0);
+ channel.Write(ClassId.Threed, 0x1FF0, 0x0);
+ channel.Write(ClassId.Threed, 0x1FF8, 0x0);
+ channel.Write(ClassId.Threed, 0x1F84, 0x0);
+ channel.Write(ClassId.Threed, 0x1F8C, 0x0);
+ channel.Write(ClassId.Threed, 0x1F94, 0x0);
+ channel.Write(ClassId.Threed, 0x1F9C, 0x0);
+ channel.Write(ClassId.Threed, 0x1FA4, 0x0);
+ channel.Write(ClassId.Threed, 0x1FAC, 0x0);
+ channel.Write(ClassId.Threed, 0x1FB4, 0x0);
+ channel.Write(ClassId.Threed, 0x1FBC, 0x0);
+ channel.Write(ClassId.Threed, 0x1FC4, 0x0);
+ channel.Write(ClassId.Threed, 0x1FCC, 0x0);
+ channel.Write(ClassId.Threed, 0x1FD4, 0x0);
+ channel.Write(ClassId.Threed, 0x1FDC, 0x0);
+ channel.Write(ClassId.Threed, 0x1FE4, 0x0);
+ channel.Write(ClassId.Threed, 0x1FEC, 0x0);
+ channel.Write(ClassId.Threed, 0x1FF4, 0x0);
+ channel.Write(ClassId.Threed, 0x1FFC, 0x0);
+ channel.Write(ClassId.Threed, 0x2000, 0x0);
+ channel.Write(ClassId.Threed, 0x2040, 0x11);
+ channel.Write(ClassId.Threed, 0x2080, 0x20);
+ channel.Write(ClassId.Threed, 0x20C0, 0x30);
+ channel.Write(ClassId.Threed, 0x2100, 0x40);
+ channel.Write(ClassId.Threed, 0x2140, 0x51);
+ channel.Write(ClassId.Threed, 0x200C, 0x1);
+ channel.Write(ClassId.Threed, 0x204C, 0x1);
+ channel.Write(ClassId.Threed, 0x208C, 0x1);
+ channel.Write(ClassId.Threed, 0x20CC, 0x1);
+ channel.Write(ClassId.Threed, 0x210C, 0x1);
+ channel.Write(ClassId.Threed, 0x214C, 0x1);
+ channel.Write(ClassId.Threed, 0x2010, 0x0);
+ channel.Write(ClassId.Threed, 0x2050, 0x0);
+ channel.Write(ClassId.Threed, 0x2090, 0x1);
+ channel.Write(ClassId.Threed, 0x20D0, 0x2);
+ channel.Write(ClassId.Threed, 0x2110, 0x3);
+ channel.Write(ClassId.Threed, 0x2150, 0x4);
+ channel.Write(ClassId.Threed, 0x380, 0x0);
+ channel.Write(ClassId.Threed, 0x3A0, 0x0);
+ channel.Write(ClassId.Threed, 0x3C0, 0x0);
+ channel.Write(ClassId.Threed, 0x3E0, 0x0);
+ channel.Write(ClassId.Threed, 0x384, 0x0);
+ channel.Write(ClassId.Threed, 0x3A4, 0x0);
+ channel.Write(ClassId.Threed, 0x3C4, 0x0);
+ channel.Write(ClassId.Threed, 0x3E4, 0x0);
+ channel.Write(ClassId.Threed, 0x388, 0x0);
+ channel.Write(ClassId.Threed, 0x3A8, 0x0);
+ channel.Write(ClassId.Threed, 0x3C8, 0x0);
+ channel.Write(ClassId.Threed, 0x3E8, 0x0);
+ channel.Write(ClassId.Threed, 0x38C, 0x0);
+ channel.Write(ClassId.Threed, 0x3AC, 0x0);
+ channel.Write(ClassId.Threed, 0x3CC, 0x0);
+ channel.Write(ClassId.Threed, 0x3EC, 0x0);
+ channel.Write(ClassId.Threed, 0x700, 0x0);
+ channel.Write(ClassId.Threed, 0x710, 0x0);
+ channel.Write(ClassId.Threed, 0x720, 0x0);
+ channel.Write(ClassId.Threed, 0x730, 0x0);
+ channel.Write(ClassId.Threed, 0x704, 0x0);
+ channel.Write(ClassId.Threed, 0x714, 0x0);
+ channel.Write(ClassId.Threed, 0x724, 0x0);
+ channel.Write(ClassId.Threed, 0x734, 0x0);
+ channel.Write(ClassId.Threed, 0x708, 0x0);
+ channel.Write(ClassId.Threed, 0x718, 0x0);
+ channel.Write(ClassId.Threed, 0x728, 0x0);
+ channel.Write(ClassId.Threed, 0x738, 0x0);
+ channel.Write(ClassId.Threed, 0x2800, 0x0);
+ channel.Write(ClassId.Threed, 0x2804, 0x0);
+ channel.Write(ClassId.Threed, 0x2808, 0x0);
+ channel.Write(ClassId.Threed, 0x280C, 0x0);
+ channel.Write(ClassId.Threed, 0x2810, 0x0);
+ channel.Write(ClassId.Threed, 0x2814, 0x0);
+ channel.Write(ClassId.Threed, 0x2818, 0x0);
+ channel.Write(ClassId.Threed, 0x281C, 0x0);
+ channel.Write(ClassId.Threed, 0x2820, 0x0);
+ channel.Write(ClassId.Threed, 0x2824, 0x0);
+ channel.Write(ClassId.Threed, 0x2828, 0x0);
+ channel.Write(ClassId.Threed, 0x282C, 0x0);
+ channel.Write(ClassId.Threed, 0x2830, 0x0);
+ channel.Write(ClassId.Threed, 0x2834, 0x0);
+ channel.Write(ClassId.Threed, 0x2838, 0x0);
+ channel.Write(ClassId.Threed, 0x283C, 0x0);
+ channel.Write(ClassId.Threed, 0x2840, 0x0);
+ channel.Write(ClassId.Threed, 0x2844, 0x0);
+ channel.Write(ClassId.Threed, 0x2848, 0x0);
+ channel.Write(ClassId.Threed, 0x284C, 0x0);
+ channel.Write(ClassId.Threed, 0x2850, 0x0);
+ channel.Write(ClassId.Threed, 0x2854, 0x0);
+ channel.Write(ClassId.Threed, 0x2858, 0x0);
+ channel.Write(ClassId.Threed, 0x285C, 0x0);
+ channel.Write(ClassId.Threed, 0x2860, 0x0);
+ channel.Write(ClassId.Threed, 0x2864, 0x0);
+ channel.Write(ClassId.Threed, 0x2868, 0x0);
+ channel.Write(ClassId.Threed, 0x286C, 0x0);
+ channel.Write(ClassId.Threed, 0x2870, 0x0);
+ channel.Write(ClassId.Threed, 0x2874, 0x0);
+ channel.Write(ClassId.Threed, 0x2878, 0x0);
+ channel.Write(ClassId.Threed, 0x287C, 0x0);
+ channel.Write(ClassId.Threed, 0x2880, 0x0);
+ channel.Write(ClassId.Threed, 0x2884, 0x0);
+ channel.Write(ClassId.Threed, 0x2888, 0x0);
+ channel.Write(ClassId.Threed, 0x288C, 0x0);
+ channel.Write(ClassId.Threed, 0x2890, 0x0);
+ channel.Write(ClassId.Threed, 0x2894, 0x0);
+ channel.Write(ClassId.Threed, 0x2898, 0x0);
+ channel.Write(ClassId.Threed, 0x289C, 0x0);
+ channel.Write(ClassId.Threed, 0x28A0, 0x0);
+ channel.Write(ClassId.Threed, 0x28A4, 0x0);
+ channel.Write(ClassId.Threed, 0x28A8, 0x0);
+ channel.Write(ClassId.Threed, 0x28AC, 0x0);
+ channel.Write(ClassId.Threed, 0x28B0, 0x0);
+ channel.Write(ClassId.Threed, 0x28B4, 0x0);
+ channel.Write(ClassId.Threed, 0x28B8, 0x0);
+ channel.Write(ClassId.Threed, 0x28BC, 0x0);
+ channel.Write(ClassId.Threed, 0x28C0, 0x0);
+ channel.Write(ClassId.Threed, 0x28C4, 0x0);
+ channel.Write(ClassId.Threed, 0x28C8, 0x0);
+ channel.Write(ClassId.Threed, 0x28CC, 0x0);
+ channel.Write(ClassId.Threed, 0x28D0, 0x0);
+ channel.Write(ClassId.Threed, 0x28D4, 0x0);
+ channel.Write(ClassId.Threed, 0x28D8, 0x0);
+ channel.Write(ClassId.Threed, 0x28DC, 0x0);
+ channel.Write(ClassId.Threed, 0x28E0, 0x0);
+ channel.Write(ClassId.Threed, 0x28E4, 0x0);
+ channel.Write(ClassId.Threed, 0x28E8, 0x0);
+ channel.Write(ClassId.Threed, 0x28EC, 0x0);
+ channel.Write(ClassId.Threed, 0x28F0, 0x0);
+ channel.Write(ClassId.Threed, 0x28F4, 0x0);
+ channel.Write(ClassId.Threed, 0x28F8, 0x0);
+ channel.Write(ClassId.Threed, 0x28FC, 0x0);
+ channel.Write(ClassId.Threed, 0x2900, 0x0);
+ channel.Write(ClassId.Threed, 0x2904, 0x0);
+ channel.Write(ClassId.Threed, 0x2908, 0x0);
+ channel.Write(ClassId.Threed, 0x290C, 0x0);
+ channel.Write(ClassId.Threed, 0x2910, 0x0);
+ channel.Write(ClassId.Threed, 0x2914, 0x0);
+ channel.Write(ClassId.Threed, 0x2918, 0x0);
+ channel.Write(ClassId.Threed, 0x291C, 0x0);
+ channel.Write(ClassId.Threed, 0x2920, 0x0);
+ channel.Write(ClassId.Threed, 0x2924, 0x0);
+ channel.Write(ClassId.Threed, 0x2928, 0x0);
+ channel.Write(ClassId.Threed, 0x292C, 0x0);
+ channel.Write(ClassId.Threed, 0x2930, 0x0);
+ channel.Write(ClassId.Threed, 0x2934, 0x0);
+ channel.Write(ClassId.Threed, 0x2938, 0x0);
+ channel.Write(ClassId.Threed, 0x293C, 0x0);
+ channel.Write(ClassId.Threed, 0x2940, 0x0);
+ channel.Write(ClassId.Threed, 0x2944, 0x0);
+ channel.Write(ClassId.Threed, 0x2948, 0x0);
+ channel.Write(ClassId.Threed, 0x294C, 0x0);
+ channel.Write(ClassId.Threed, 0x2950, 0x0);
+ channel.Write(ClassId.Threed, 0x2954, 0x0);
+ channel.Write(ClassId.Threed, 0x2958, 0x0);
+ channel.Write(ClassId.Threed, 0x295C, 0x0);
+ channel.Write(ClassId.Threed, 0x2960, 0x0);
+ channel.Write(ClassId.Threed, 0x2964, 0x0);
+ channel.Write(ClassId.Threed, 0x2968, 0x0);
+ channel.Write(ClassId.Threed, 0x296C, 0x0);
+ channel.Write(ClassId.Threed, 0x2970, 0x0);
+ channel.Write(ClassId.Threed, 0x2974, 0x0);
+ channel.Write(ClassId.Threed, 0x2978, 0x0);
+ channel.Write(ClassId.Threed, 0x297C, 0x0);
+ channel.Write(ClassId.Threed, 0x2980, 0x0);
+ channel.Write(ClassId.Threed, 0x2984, 0x0);
+ channel.Write(ClassId.Threed, 0x2988, 0x0);
+ channel.Write(ClassId.Threed, 0x298C, 0x0);
+ channel.Write(ClassId.Threed, 0x2990, 0x0);
+ channel.Write(ClassId.Threed, 0x2994, 0x0);
+ channel.Write(ClassId.Threed, 0x2998, 0x0);
+ channel.Write(ClassId.Threed, 0x299C, 0x0);
+ channel.Write(ClassId.Threed, 0x29A0, 0x0);
+ channel.Write(ClassId.Threed, 0x29A4, 0x0);
+ channel.Write(ClassId.Threed, 0x29A8, 0x0);
+ channel.Write(ClassId.Threed, 0x29AC, 0x0);
+ channel.Write(ClassId.Threed, 0x29B0, 0x0);
+ channel.Write(ClassId.Threed, 0x29B4, 0x0);
+ channel.Write(ClassId.Threed, 0x29B8, 0x0);
+ channel.Write(ClassId.Threed, 0x29BC, 0x0);
+ channel.Write(ClassId.Threed, 0x29C0, 0x0);
+ channel.Write(ClassId.Threed, 0x29C4, 0x0);
+ channel.Write(ClassId.Threed, 0x29C8, 0x0);
+ channel.Write(ClassId.Threed, 0x29CC, 0x0);
+ channel.Write(ClassId.Threed, 0x29D0, 0x0);
+ channel.Write(ClassId.Threed, 0x29D4, 0x0);
+ channel.Write(ClassId.Threed, 0x29D8, 0x0);
+ channel.Write(ClassId.Threed, 0x29DC, 0x0);
+ channel.Write(ClassId.Threed, 0x29E0, 0x0);
+ channel.Write(ClassId.Threed, 0x29E4, 0x0);
+ channel.Write(ClassId.Threed, 0x29E8, 0x0);
+ channel.Write(ClassId.Threed, 0x29EC, 0x0);
+ channel.Write(ClassId.Threed, 0x29F0, 0x0);
+ channel.Write(ClassId.Threed, 0x29F4, 0x0);
+ channel.Write(ClassId.Threed, 0x29F8, 0x0);
+ channel.Write(ClassId.Threed, 0x29FC, 0x0);
+ channel.Write(ClassId.Threed, 0xA00, 0x0);
+ channel.Write(ClassId.Threed, 0xA20, 0x0);
+ channel.Write(ClassId.Threed, 0xA40, 0x0);
+ channel.Write(ClassId.Threed, 0xA60, 0x0);
+ channel.Write(ClassId.Threed, 0xA80, 0x0);
+ channel.Write(ClassId.Threed, 0xAA0, 0x0);
+ channel.Write(ClassId.Threed, 0xAC0, 0x0);
+ channel.Write(ClassId.Threed, 0xAE0, 0x0);
+ channel.Write(ClassId.Threed, 0xB00, 0x0);
+ channel.Write(ClassId.Threed, 0xB20, 0x0);
+ channel.Write(ClassId.Threed, 0xB40, 0x0);
+ channel.Write(ClassId.Threed, 0xB60, 0x0);
+ channel.Write(ClassId.Threed, 0xB80, 0x0);
+ channel.Write(ClassId.Threed, 0xBA0, 0x0);
+ channel.Write(ClassId.Threed, 0xBC0, 0x0);
+ channel.Write(ClassId.Threed, 0xBE0, 0x0);
+ channel.Write(ClassId.Threed, 0xA04, 0x0);
+ channel.Write(ClassId.Threed, 0xA24, 0x0);
+ channel.Write(ClassId.Threed, 0xA44, 0x0);
+ channel.Write(ClassId.Threed, 0xA64, 0x0);
+ channel.Write(ClassId.Threed, 0xA84, 0x0);
+ channel.Write(ClassId.Threed, 0xAA4, 0x0);
+ channel.Write(ClassId.Threed, 0xAC4, 0x0);
+ channel.Write(ClassId.Threed, 0xAE4, 0x0);
+ channel.Write(ClassId.Threed, 0xB04, 0x0);
+ channel.Write(ClassId.Threed, 0xB24, 0x0);
+ channel.Write(ClassId.Threed, 0xB44, 0x0);
+ channel.Write(ClassId.Threed, 0xB64, 0x0);
+ channel.Write(ClassId.Threed, 0xB84, 0x0);
+ channel.Write(ClassId.Threed, 0xBA4, 0x0);
+ channel.Write(ClassId.Threed, 0xBC4, 0x0);
+ channel.Write(ClassId.Threed, 0xBE4, 0x0);
+ channel.Write(ClassId.Threed, 0xA08, 0x0);
+ channel.Write(ClassId.Threed, 0xA28, 0x0);
+ channel.Write(ClassId.Threed, 0xA48, 0x0);
+ channel.Write(ClassId.Threed, 0xA68, 0x0);
+ channel.Write(ClassId.Threed, 0xA88, 0x0);
+ channel.Write(ClassId.Threed, 0xAA8, 0x0);
+ channel.Write(ClassId.Threed, 0xAC8, 0x0);
+ channel.Write(ClassId.Threed, 0xAE8, 0x0);
+ channel.Write(ClassId.Threed, 0xB08, 0x0);
+ channel.Write(ClassId.Threed, 0xB28, 0x0);
+ channel.Write(ClassId.Threed, 0xB48, 0x0);
+ channel.Write(ClassId.Threed, 0xB68, 0x0);
+ channel.Write(ClassId.Threed, 0xB88, 0x0);
+ channel.Write(ClassId.Threed, 0xBA8, 0x0);
+ channel.Write(ClassId.Threed, 0xBC8, 0x0);
+ channel.Write(ClassId.Threed, 0xBE8, 0x0);
+ channel.Write(ClassId.Threed, 0xA0C, 0x0);
+ channel.Write(ClassId.Threed, 0xA2C, 0x0);
+ channel.Write(ClassId.Threed, 0xA4C, 0x0);
+ channel.Write(ClassId.Threed, 0xA6C, 0x0);
+ channel.Write(ClassId.Threed, 0xA8C, 0x0);
+ channel.Write(ClassId.Threed, 0xAAC, 0x0);
+ channel.Write(ClassId.Threed, 0xACC, 0x0);
+ channel.Write(ClassId.Threed, 0xAEC, 0x0);
+ channel.Write(ClassId.Threed, 0xB0C, 0x0);
+ channel.Write(ClassId.Threed, 0xB2C, 0x0);
+ channel.Write(ClassId.Threed, 0xB4C, 0x0);
+ channel.Write(ClassId.Threed, 0xB6C, 0x0);
+ channel.Write(ClassId.Threed, 0xB8C, 0x0);
+ channel.Write(ClassId.Threed, 0xBAC, 0x0);
+ channel.Write(ClassId.Threed, 0xBCC, 0x0);
+ channel.Write(ClassId.Threed, 0xBEC, 0x0);
+ channel.Write(ClassId.Threed, 0xA10, 0x0);
+ channel.Write(ClassId.Threed, 0xA30, 0x0);
+ channel.Write(ClassId.Threed, 0xA50, 0x0);
+ channel.Write(ClassId.Threed, 0xA70, 0x0);
+ channel.Write(ClassId.Threed, 0xA90, 0x0);
+ channel.Write(ClassId.Threed, 0xAB0, 0x0);
+ channel.Write(ClassId.Threed, 0xAD0, 0x0);
+ channel.Write(ClassId.Threed, 0xAF0, 0x0);
+ channel.Write(ClassId.Threed, 0xB10, 0x0);
+ channel.Write(ClassId.Threed, 0xB30, 0x0);
+ channel.Write(ClassId.Threed, 0xB50, 0x0);
+ channel.Write(ClassId.Threed, 0xB70, 0x0);
+ channel.Write(ClassId.Threed, 0xB90, 0x0);
+ channel.Write(ClassId.Threed, 0xBB0, 0x0);
+ channel.Write(ClassId.Threed, 0xBD0, 0x0);
+ channel.Write(ClassId.Threed, 0xBF0, 0x0);
+ channel.Write(ClassId.Threed, 0xA14, 0x0);
+ channel.Write(ClassId.Threed, 0xA34, 0x0);
+ channel.Write(ClassId.Threed, 0xA54, 0x0);
+ channel.Write(ClassId.Threed, 0xA74, 0x0);
+ channel.Write(ClassId.Threed, 0xA94, 0x0);
+ channel.Write(ClassId.Threed, 0xAB4, 0x0);
+ channel.Write(ClassId.Threed, 0xAD4, 0x0);
+ channel.Write(ClassId.Threed, 0xAF4, 0x0);
+ channel.Write(ClassId.Threed, 0xB14, 0x0);
+ channel.Write(ClassId.Threed, 0xB34, 0x0);
+ channel.Write(ClassId.Threed, 0xB54, 0x0);
+ channel.Write(ClassId.Threed, 0xB74, 0x0);
+ channel.Write(ClassId.Threed, 0xB94, 0x0);
+ channel.Write(ClassId.Threed, 0xBB4, 0x0);
+ channel.Write(ClassId.Threed, 0xBD4, 0x0);
+ channel.Write(ClassId.Threed, 0xBF4, 0x0);
+ channel.Write(ClassId.Threed, 0xA18, 0x6420);
+ channel.Write(ClassId.Threed, 0xA38, 0x6420);
+ channel.Write(ClassId.Threed, 0xA58, 0x6420);
+ channel.Write(ClassId.Threed, 0xA78, 0x6420);
+ channel.Write(ClassId.Threed, 0xA98, 0x6420);
+ channel.Write(ClassId.Threed, 0xAB8, 0x6420);
+ channel.Write(ClassId.Threed, 0xAD8, 0x6420);
+ channel.Write(ClassId.Threed, 0xAF8, 0x6420);
+ channel.Write(ClassId.Threed, 0xB18, 0x6420);
+ channel.Write(ClassId.Threed, 0xB38, 0x6420);
+ channel.Write(ClassId.Threed, 0xB58, 0x6420);
+ channel.Write(ClassId.Threed, 0xB78, 0x6420);
+ channel.Write(ClassId.Threed, 0xB98, 0x6420);
+ channel.Write(ClassId.Threed, 0xBB8, 0x6420);
+ channel.Write(ClassId.Threed, 0xBD8, 0x6420);
+ channel.Write(ClassId.Threed, 0xBF8, 0x6420);
+ channel.Write(ClassId.Threed, 0xA1C, 0x0);
+ channel.Write(ClassId.Threed, 0xA3C, 0x0);
+ channel.Write(ClassId.Threed, 0xA5C, 0x0);
+ channel.Write(ClassId.Threed, 0xA7C, 0x0);
+ channel.Write(ClassId.Threed, 0xA9C, 0x0);
+ channel.Write(ClassId.Threed, 0xABC, 0x0);
+ channel.Write(ClassId.Threed, 0xADC, 0x0);
+ channel.Write(ClassId.Threed, 0xAFC, 0x0);
+ channel.Write(ClassId.Threed, 0xB1C, 0x0);
+ channel.Write(ClassId.Threed, 0xB3C, 0x0);
+ channel.Write(ClassId.Threed, 0xB5C, 0x0);
+ channel.Write(ClassId.Threed, 0xB7C, 0x0);
+ channel.Write(ClassId.Threed, 0xB9C, 0x0);
+ channel.Write(ClassId.Threed, 0xBBC, 0x0);
+ channel.Write(ClassId.Threed, 0xBDC, 0x0);
+ channel.Write(ClassId.Threed, 0xBFC, 0x0);
+ channel.Write(ClassId.Threed, 0xC00, 0x0);
+ channel.Write(ClassId.Threed, 0xC10, 0x0);
+ channel.Write(ClassId.Threed, 0xC20, 0x0);
+ channel.Write(ClassId.Threed, 0xC30, 0x0);
+ channel.Write(ClassId.Threed, 0xC40, 0x0);
+ channel.Write(ClassId.Threed, 0xC50, 0x0);
+ channel.Write(ClassId.Threed, 0xC60, 0x0);
+ channel.Write(ClassId.Threed, 0xC70, 0x0);
+ channel.Write(ClassId.Threed, 0xC80, 0x0);
+ channel.Write(ClassId.Threed, 0xC90, 0x0);
+ channel.Write(ClassId.Threed, 0xCA0, 0x0);
+ channel.Write(ClassId.Threed, 0xCB0, 0x0);
+ channel.Write(ClassId.Threed, 0xCC0, 0x0);
+ channel.Write(ClassId.Threed, 0xCD0, 0x0);
+ channel.Write(ClassId.Threed, 0xCE0, 0x0);
+ channel.Write(ClassId.Threed, 0xCF0, 0x0);
+ channel.Write(ClassId.Threed, 0xC04, 0x0);
+ channel.Write(ClassId.Threed, 0xC14, 0x0);
+ channel.Write(ClassId.Threed, 0xC24, 0x0);
+ channel.Write(ClassId.Threed, 0xC34, 0x0);
+ channel.Write(ClassId.Threed, 0xC44, 0x0);
+ channel.Write(ClassId.Threed, 0xC54, 0x0);
+ channel.Write(ClassId.Threed, 0xC64, 0x0);
+ channel.Write(ClassId.Threed, 0xC74, 0x0);
+ channel.Write(ClassId.Threed, 0xC84, 0x0);
+ channel.Write(ClassId.Threed, 0xC94, 0x0);
+ channel.Write(ClassId.Threed, 0xCA4, 0x0);
+ channel.Write(ClassId.Threed, 0xCB4, 0x0);
+ channel.Write(ClassId.Threed, 0xCC4, 0x0);
+ channel.Write(ClassId.Threed, 0xCD4, 0x0);
+ channel.Write(ClassId.Threed, 0xCE4, 0x0);
+ channel.Write(ClassId.Threed, 0xCF4, 0x0);
+ channel.Write(ClassId.Threed, 0xC08, 0x0);
+ channel.Write(ClassId.Threed, 0xC18, 0x0);
+ channel.Write(ClassId.Threed, 0xC28, 0x0);
+ channel.Write(ClassId.Threed, 0xC38, 0x0);
+ channel.Write(ClassId.Threed, 0xC48, 0x0);
+ channel.Write(ClassId.Threed, 0xC58, 0x0);
+ channel.Write(ClassId.Threed, 0xC68, 0x0);
+ channel.Write(ClassId.Threed, 0xC78, 0x0);
+ channel.Write(ClassId.Threed, 0xC88, 0x0);
+ channel.Write(ClassId.Threed, 0xC98, 0x0);
+ channel.Write(ClassId.Threed, 0xCA8, 0x0);
+ channel.Write(ClassId.Threed, 0xCB8, 0x0);
+ channel.Write(ClassId.Threed, 0xCC8, 0x0);
+ channel.Write(ClassId.Threed, 0xCD8, 0x0);
+ channel.Write(ClassId.Threed, 0xCE8, 0x0);
+ channel.Write(ClassId.Threed, 0xCF8, 0x0);
+ channel.Write(ClassId.Threed, 0xC0C, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xC1C, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xC2C, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xC3C, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xC4C, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xC5C, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xC6C, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xC7C, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xC8C, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xC9C, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xCAC, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xCBC, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xCCC, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xCDC, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xCEC, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xCFC, 0x3F800000);
+ channel.Write(ClassId.Threed, 0xD00, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD08, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD10, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD18, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD20, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD28, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD30, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD38, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD04, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD0C, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD14, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD1C, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD24, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD2C, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD34, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD3C, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE00, 0x0);
+ channel.Write(ClassId.Threed, 0xE10, 0x0);
+ channel.Write(ClassId.Threed, 0xE20, 0x0);
+ channel.Write(ClassId.Threed, 0xE30, 0x0);
+ channel.Write(ClassId.Threed, 0xE40, 0x0);
+ channel.Write(ClassId.Threed, 0xE50, 0x0);
+ channel.Write(ClassId.Threed, 0xE60, 0x0);
+ channel.Write(ClassId.Threed, 0xE70, 0x0);
+ channel.Write(ClassId.Threed, 0xE80, 0x0);
+ channel.Write(ClassId.Threed, 0xE90, 0x0);
+ channel.Write(ClassId.Threed, 0xEA0, 0x0);
+ channel.Write(ClassId.Threed, 0xEB0, 0x0);
+ channel.Write(ClassId.Threed, 0xEC0, 0x0);
+ channel.Write(ClassId.Threed, 0xED0, 0x0);
+ channel.Write(ClassId.Threed, 0xEE0, 0x0);
+ channel.Write(ClassId.Threed, 0xEF0, 0x0);
+ channel.Write(ClassId.Threed, 0xE04, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE14, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE24, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE34, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE44, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE54, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE64, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE74, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE84, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE94, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xEA4, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xEB4, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xEC4, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xED4, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xEE4, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xEF4, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE08, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE18, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE28, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE38, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE48, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE58, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE68, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE78, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE88, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xE98, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xEA8, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xEB8, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xEC8, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xED8, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xEE8, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xEF8, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD40, 0x0);
+ channel.Write(ClassId.Threed, 0xD48, 0x0);
+ channel.Write(ClassId.Threed, 0xD50, 0x0);
+ channel.Write(ClassId.Threed, 0xD58, 0x0);
+ channel.Write(ClassId.Threed, 0xD44, 0x0);
+ channel.Write(ClassId.Threed, 0xD4C, 0x0);
+ channel.Write(ClassId.Threed, 0xD54, 0x0);
+ channel.Write(ClassId.Threed, 0xD5C, 0x0);
+ channel.Write(ClassId.Threed, 0x1E00, 0x1);
+ channel.Write(ClassId.Threed, 0x1E20, 0x1);
+ channel.Write(ClassId.Threed, 0x1E40, 0x1);
+ channel.Write(ClassId.Threed, 0x1E60, 0x1);
+ channel.Write(ClassId.Threed, 0x1E80, 0x1);
+ channel.Write(ClassId.Threed, 0x1EA0, 0x1);
+ channel.Write(ClassId.Threed, 0x1EC0, 0x1);
+ channel.Write(ClassId.Threed, 0x1EE0, 0x1);
+ channel.Write(ClassId.Threed, 0x1E04, 0x1);
+ channel.Write(ClassId.Threed, 0x1E24, 0x1);
+ channel.Write(ClassId.Threed, 0x1E44, 0x1);
+ channel.Write(ClassId.Threed, 0x1E64, 0x1);
+ channel.Write(ClassId.Threed, 0x1E84, 0x1);
+ channel.Write(ClassId.Threed, 0x1EA4, 0x1);
+ channel.Write(ClassId.Threed, 0x1EC4, 0x1);
+ channel.Write(ClassId.Threed, 0x1EE4, 0x1);
+ channel.Write(ClassId.Threed, 0x1E08, 0x2);
+ channel.Write(ClassId.Threed, 0x1E28, 0x2);
+ channel.Write(ClassId.Threed, 0x1E48, 0x2);
+ channel.Write(ClassId.Threed, 0x1E68, 0x2);
+ channel.Write(ClassId.Threed, 0x1E88, 0x2);
+ channel.Write(ClassId.Threed, 0x1EA8, 0x2);
+ channel.Write(ClassId.Threed, 0x1EC8, 0x2);
+ channel.Write(ClassId.Threed, 0x1EE8, 0x2);
+ channel.Write(ClassId.Threed, 0x1E0C, 0x1);
+ channel.Write(ClassId.Threed, 0x1E2C, 0x1);
+ channel.Write(ClassId.Threed, 0x1E4C, 0x1);
+ channel.Write(ClassId.Threed, 0x1E6C, 0x1);
+ channel.Write(ClassId.Threed, 0x1E8C, 0x1);
+ channel.Write(ClassId.Threed, 0x1EAC, 0x1);
+ channel.Write(ClassId.Threed, 0x1ECC, 0x1);
+ channel.Write(ClassId.Threed, 0x1EEC, 0x1);
+ channel.Write(ClassId.Threed, 0x1E10, 0x1);
+ channel.Write(ClassId.Threed, 0x1E30, 0x1);
+ channel.Write(ClassId.Threed, 0x1E50, 0x1);
+ channel.Write(ClassId.Threed, 0x1E70, 0x1);
+ channel.Write(ClassId.Threed, 0x1E90, 0x1);
+ channel.Write(ClassId.Threed, 0x1EB0, 0x1);
+ channel.Write(ClassId.Threed, 0x1ED0, 0x1);
+ channel.Write(ClassId.Threed, 0x1EF0, 0x1);
+ channel.Write(ClassId.Threed, 0x1E14, 0x2);
+ channel.Write(ClassId.Threed, 0x1E34, 0x2);
+ channel.Write(ClassId.Threed, 0x1E54, 0x2);
+ channel.Write(ClassId.Threed, 0x1E74, 0x2);
+ channel.Write(ClassId.Threed, 0x1E94, 0x2);
+ channel.Write(ClassId.Threed, 0x1EB4, 0x2);
+ channel.Write(ClassId.Threed, 0x1ED4, 0x2);
+ channel.Write(ClassId.Threed, 0x1EF4, 0x2);
+ channel.Write(ClassId.Threed, 0x1E18, 0x1);
+ channel.Write(ClassId.Threed, 0x1E38, 0x1);
+ channel.Write(ClassId.Threed, 0x1E58, 0x1);
+ channel.Write(ClassId.Threed, 0x1E78, 0x1);
+ channel.Write(ClassId.Threed, 0x1E98, 0x1);
+ channel.Write(ClassId.Threed, 0x1EB8, 0x1);
+ channel.Write(ClassId.Threed, 0x1ED8, 0x1);
+ channel.Write(ClassId.Threed, 0x1EF8, 0x1);
+ channel.Write(ClassId.Threed, 0x1480, 0x0);
+ channel.Write(ClassId.Threed, 0x1490, 0x0);
+ channel.Write(ClassId.Threed, 0x14A0, 0x0);
+ channel.Write(ClassId.Threed, 0x14B0, 0x0);
+ channel.Write(ClassId.Threed, 0x14C0, 0x0);
+ channel.Write(ClassId.Threed, 0x14D0, 0x0);
+ channel.Write(ClassId.Threed, 0x14E0, 0x0);
+ channel.Write(ClassId.Threed, 0x14F0, 0x0);
+ channel.Write(ClassId.Threed, 0x1484, 0x0);
+ channel.Write(ClassId.Threed, 0x1494, 0x0);
+ channel.Write(ClassId.Threed, 0x14A4, 0x0);
+ channel.Write(ClassId.Threed, 0x14B4, 0x0);
+ channel.Write(ClassId.Threed, 0x14C4, 0x0);
+ channel.Write(ClassId.Threed, 0x14D4, 0x0);
+ channel.Write(ClassId.Threed, 0x14E4, 0x0);
+ channel.Write(ClassId.Threed, 0x14F4, 0x0);
+ channel.Write(ClassId.Threed, 0x1488, 0x0);
+ channel.Write(ClassId.Threed, 0x1498, 0x0);
+ channel.Write(ClassId.Threed, 0x14A8, 0x0);
+ channel.Write(ClassId.Threed, 0x14B8, 0x0);
+ channel.Write(ClassId.Threed, 0x14C8, 0x0);
+ channel.Write(ClassId.Threed, 0x14D8, 0x0);
+ channel.Write(ClassId.Threed, 0x14E8, 0x0);
+ channel.Write(ClassId.Threed, 0x14F8, 0x0);
+ channel.Write(ClassId.Threed, 0x3400, 0x0);
+ channel.Write(ClassId.Threed, 0x3404, 0x0);
+ channel.Write(ClassId.Threed, 0x3408, 0x0);
+ channel.Write(ClassId.Threed, 0x340C, 0x0);
+ channel.Write(ClassId.Threed, 0x3410, 0x0);
+ channel.Write(ClassId.Threed, 0x3414, 0x0);
+ channel.Write(ClassId.Threed, 0x3418, 0x0);
+ channel.Write(ClassId.Threed, 0x341C, 0x0);
+ channel.Write(ClassId.Threed, 0x3420, 0x0);
+ channel.Write(ClassId.Threed, 0x3424, 0x0);
+ channel.Write(ClassId.Threed, 0x3428, 0x0);
+ channel.Write(ClassId.Threed, 0x342C, 0x0);
+ channel.Write(ClassId.Threed, 0x3430, 0x0);
+ channel.Write(ClassId.Threed, 0x3434, 0x0);
+ channel.Write(ClassId.Threed, 0x3438, 0x0);
+ channel.Write(ClassId.Threed, 0x343C, 0x0);
+ channel.Write(ClassId.Threed, 0x3440, 0x0);
+ channel.Write(ClassId.Threed, 0x3444, 0x0);
+ channel.Write(ClassId.Threed, 0x3448, 0x0);
+ channel.Write(ClassId.Threed, 0x344C, 0x0);
+ channel.Write(ClassId.Threed, 0x3450, 0x0);
+ channel.Write(ClassId.Threed, 0x3454, 0x0);
+ channel.Write(ClassId.Threed, 0x3458, 0x0);
+ channel.Write(ClassId.Threed, 0x345C, 0x0);
+ channel.Write(ClassId.Threed, 0x3460, 0x0);
+ channel.Write(ClassId.Threed, 0x3464, 0x0);
+ channel.Write(ClassId.Threed, 0x3468, 0x0);
+ channel.Write(ClassId.Threed, 0x346C, 0x0);
+ channel.Write(ClassId.Threed, 0x3470, 0x0);
+ channel.Write(ClassId.Threed, 0x3474, 0x0);
+ channel.Write(ClassId.Threed, 0x3478, 0x0);
+ channel.Write(ClassId.Threed, 0x347C, 0x0);
+ channel.Write(ClassId.Threed, 0x3480, 0x0);
+ channel.Write(ClassId.Threed, 0x3484, 0x0);
+ channel.Write(ClassId.Threed, 0x3488, 0x0);
+ channel.Write(ClassId.Threed, 0x348C, 0x0);
+ channel.Write(ClassId.Threed, 0x3490, 0x0);
+ channel.Write(ClassId.Threed, 0x3494, 0x0);
+ channel.Write(ClassId.Threed, 0x3498, 0x0);
+ channel.Write(ClassId.Threed, 0x349C, 0x0);
+ channel.Write(ClassId.Threed, 0x34A0, 0x0);
+ channel.Write(ClassId.Threed, 0x34A4, 0x0);
+ channel.Write(ClassId.Threed, 0x34A8, 0x0);
+ channel.Write(ClassId.Threed, 0x34AC, 0x0);
+ channel.Write(ClassId.Threed, 0x34B0, 0x0);
+ channel.Write(ClassId.Threed, 0x34B4, 0x0);
+ channel.Write(ClassId.Threed, 0x34B8, 0x0);
+ channel.Write(ClassId.Threed, 0x34BC, 0x0);
+ channel.Write(ClassId.Threed, 0x34C0, 0x0);
+ channel.Write(ClassId.Threed, 0x34C4, 0x0);
+ channel.Write(ClassId.Threed, 0x34C8, 0x0);
+ channel.Write(ClassId.Threed, 0x34CC, 0x0);
+ channel.Write(ClassId.Threed, 0x34D0, 0x0);
+ channel.Write(ClassId.Threed, 0x34D4, 0x0);
+ channel.Write(ClassId.Threed, 0x34D8, 0x0);
+ channel.Write(ClassId.Threed, 0x34DC, 0x0);
+ channel.Write(ClassId.Threed, 0x34E0, 0x0);
+ channel.Write(ClassId.Threed, 0x34E4, 0x0);
+ channel.Write(ClassId.Threed, 0x34E8, 0x0);
+ channel.Write(ClassId.Threed, 0x34EC, 0x0);
+ channel.Write(ClassId.Threed, 0x34F0, 0x0);
+ channel.Write(ClassId.Threed, 0x34F4, 0x0);
+ channel.Write(ClassId.Threed, 0x34F8, 0x0);
+ channel.Write(ClassId.Threed, 0x34FC, 0x0);
+ channel.Write(ClassId.Threed, 0x3500, 0x0);
+ channel.Write(ClassId.Threed, 0x3504, 0x0);
+ channel.Write(ClassId.Threed, 0x3508, 0x0);
+ channel.Write(ClassId.Threed, 0x350C, 0x0);
+ channel.Write(ClassId.Threed, 0x3510, 0x0);
+ channel.Write(ClassId.Threed, 0x3514, 0x0);
+ channel.Write(ClassId.Threed, 0x3518, 0x0);
+ channel.Write(ClassId.Threed, 0x351C, 0x0);
+ channel.Write(ClassId.Threed, 0x3520, 0x0);
+ channel.Write(ClassId.Threed, 0x3524, 0x0);
+ channel.Write(ClassId.Threed, 0x3528, 0x0);
+ channel.Write(ClassId.Threed, 0x352C, 0x0);
+ channel.Write(ClassId.Threed, 0x3530, 0x0);
+ channel.Write(ClassId.Threed, 0x3534, 0x0);
+ channel.Write(ClassId.Threed, 0x3538, 0x0);
+ channel.Write(ClassId.Threed, 0x353C, 0x0);
+ channel.Write(ClassId.Threed, 0x3540, 0x0);
+ channel.Write(ClassId.Threed, 0x3544, 0x0);
+ channel.Write(ClassId.Threed, 0x3548, 0x0);
+ channel.Write(ClassId.Threed, 0x354C, 0x0);
+ channel.Write(ClassId.Threed, 0x3550, 0x0);
+ channel.Write(ClassId.Threed, 0x3554, 0x0);
+ channel.Write(ClassId.Threed, 0x3558, 0x0);
+ channel.Write(ClassId.Threed, 0x355C, 0x0);
+ channel.Write(ClassId.Threed, 0x3560, 0x0);
+ channel.Write(ClassId.Threed, 0x3564, 0x0);
+ channel.Write(ClassId.Threed, 0x3568, 0x0);
+ channel.Write(ClassId.Threed, 0x356C, 0x0);
+ channel.Write(ClassId.Threed, 0x3570, 0x0);
+ channel.Write(ClassId.Threed, 0x3574, 0x0);
+ channel.Write(ClassId.Threed, 0x3578, 0x0);
+ channel.Write(ClassId.Threed, 0x357C, 0x0);
+ channel.Write(ClassId.Threed, 0x3580, 0x0);
+ channel.Write(ClassId.Threed, 0x3584, 0x0);
+ channel.Write(ClassId.Threed, 0x3588, 0x0);
+ channel.Write(ClassId.Threed, 0x358C, 0x0);
+ channel.Write(ClassId.Threed, 0x3590, 0x0);
+ channel.Write(ClassId.Threed, 0x3594, 0x0);
+ channel.Write(ClassId.Threed, 0x3598, 0x0);
+ channel.Write(ClassId.Threed, 0x359C, 0x0);
+ channel.Write(ClassId.Threed, 0x35A0, 0x0);
+ channel.Write(ClassId.Threed, 0x35A4, 0x0);
+ channel.Write(ClassId.Threed, 0x35A8, 0x0);
+ channel.Write(ClassId.Threed, 0x35AC, 0x0);
+ channel.Write(ClassId.Threed, 0x35B0, 0x0);
+ channel.Write(ClassId.Threed, 0x35B4, 0x0);
+ channel.Write(ClassId.Threed, 0x35B8, 0x0);
+ channel.Write(ClassId.Threed, 0x35BC, 0x0);
+ channel.Write(ClassId.Threed, 0x35C0, 0x0);
+ channel.Write(ClassId.Threed, 0x35C4, 0x0);
+ channel.Write(ClassId.Threed, 0x35C8, 0x0);
+ channel.Write(ClassId.Threed, 0x35CC, 0x0);
+ channel.Write(ClassId.Threed, 0x35D0, 0x0);
+ channel.Write(ClassId.Threed, 0x35D4, 0x0);
+ channel.Write(ClassId.Threed, 0x35D8, 0x0);
+ channel.Write(ClassId.Threed, 0x35DC, 0x0);
+ channel.Write(ClassId.Threed, 0x35E0, 0x0);
+ channel.Write(ClassId.Threed, 0x35E4, 0x0);
+ channel.Write(ClassId.Threed, 0x35E8, 0x0);
+ channel.Write(ClassId.Threed, 0x35EC, 0x0);
+ channel.Write(ClassId.Threed, 0x35F0, 0x0);
+ channel.Write(ClassId.Threed, 0x35F4, 0x0);
+ channel.Write(ClassId.Threed, 0x35F8, 0x0);
+ channel.Write(ClassId.Threed, 0x35FC, 0x0);
+ channel.Write(ClassId.Threed, 0x30C, 0x1);
+ channel.Write(ClassId.Threed, 0x1944, 0x0);
+ channel.Write(ClassId.Threed, 0x1514, 0x0);
+ channel.Write(ClassId.Threed, 0xD68, 0xFFFF);
+ channel.Write(ClassId.Threed, 0x121C, 0xFAC6881);
+ channel.Write(ClassId.Threed, 0xFAC, 0x1);
+ channel.Write(ClassId.Threed, 0x1538, 0x1);
+ channel.Write(ClassId.Threed, 0xFE0, 0x0);
+ channel.Write(ClassId.Threed, 0xFE4, 0x0);
+ channel.Write(ClassId.Threed, 0xFE8, 0x14);
+ channel.Write(ClassId.Threed, 0xFEC, 0x40);
+ channel.Write(ClassId.Threed, 0xFF0, 0x0);
+ channel.Write(ClassId.Threed, 0x179C, 0x0);
+ channel.Write(ClassId.Threed, 0x1228, 0x400);
+ channel.Write(ClassId.Threed, 0x122C, 0x300);
+ channel.Write(ClassId.Threed, 0x1230, 0x10001);
+ channel.Write(ClassId.Threed, 0x7F8, 0x0);
+ channel.Write(ClassId.Threed, 0x1208, 0x0);
+ channel.Write(ClassId.Threed, 0x15B4, 0x1);
+ channel.Write(ClassId.Threed, 0x15CC, 0x0);
+ channel.Write(ClassId.Threed, 0x1534, 0x0);
+ channel.Write(ClassId.Threed, 0x754, 0x1);
+ channel.Write(ClassId.Threed, 0xFB0, 0x0);
+ channel.Write(ClassId.Threed, 0x15D0, 0x0);
+ channel.Write(ClassId.Threed, 0x11E0, 0x88888888);
+ channel.Write(ClassId.Threed, 0x11E4, 0x88888888);
+ channel.Write(ClassId.Threed, 0x11E8, 0x88888888);
+ channel.Write(ClassId.Threed, 0x11EC, 0x88888888);
+ channel.Write(ClassId.Threed, 0x153C, 0x0);
+ channel.Write(ClassId.Threed, 0x16B4, 0x3);
+ channel.Write(ClassId.Threed, 0xFA4, 0x1);
+ channel.Write(ClassId.Threed, 0xFBC, 0xFFFF);
+ channel.Write(ClassId.Threed, 0xFC0, 0xFFFF);
+ channel.Write(ClassId.Threed, 0xFC4, 0xFFFF);
+ channel.Write(ClassId.Threed, 0xFC8, 0xFFFF);
+ channel.Write(ClassId.Threed, 0xFA8, 0xFFFF);
+ channel.Write(ClassId.Threed, 0xDF8, 0x0);
+ channel.Write(ClassId.Threed, 0xDFC, 0x0);
+ channel.Write(ClassId.Threed, 0x1948, 0x0);
+ channel.Write(ClassId.Threed, 0x1970, 0x1);
+ channel.Write(ClassId.Threed, 0x161C, 0x9F0);
+ channel.Write(ClassId.Threed, 0xDCC, 0x10);
+ channel.Write(ClassId.Threed, 0x15E4, 0x0);
+ channel.Write(ClassId.Threed, 0x1160, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x1164, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x1168, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x116C, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x1170, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x1174, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x1178, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x117C, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x1180, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x1184, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x1188, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x118C, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x1190, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x1194, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x1198, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x119C, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11A0, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11A4, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11A8, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11AC, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11B0, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11B4, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11B8, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11BC, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11C0, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11C4, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11C8, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11CC, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11D0, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11D4, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11D8, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x11DC, 0x25E00040);
+ channel.Write(ClassId.Threed, 0x1880, 0x0);
+ channel.Write(ClassId.Threed, 0x1884, 0x0);
+ channel.Write(ClassId.Threed, 0x1888, 0x0);
+ channel.Write(ClassId.Threed, 0x188C, 0x0);
+ channel.Write(ClassId.Threed, 0x1890, 0x0);
+ channel.Write(ClassId.Threed, 0x1894, 0x0);
+ channel.Write(ClassId.Threed, 0x1898, 0x0);
+ channel.Write(ClassId.Threed, 0x189C, 0x0);
+ channel.Write(ClassId.Threed, 0x18A0, 0x0);
+ channel.Write(ClassId.Threed, 0x18A4, 0x0);
+ channel.Write(ClassId.Threed, 0x18A8, 0x0);
+ channel.Write(ClassId.Threed, 0x18AC, 0x0);
+ channel.Write(ClassId.Threed, 0x18B0, 0x0);
+ channel.Write(ClassId.Threed, 0x18B4, 0x0);
+ channel.Write(ClassId.Threed, 0x18B8, 0x0);
+ channel.Write(ClassId.Threed, 0x18BC, 0x0);
+ channel.Write(ClassId.Threed, 0x18C0, 0x0);
+ channel.Write(ClassId.Threed, 0x18C4, 0x0);
+ channel.Write(ClassId.Threed, 0x18C8, 0x0);
+ channel.Write(ClassId.Threed, 0x18CC, 0x0);
+ channel.Write(ClassId.Threed, 0x18D0, 0x0);
+ channel.Write(ClassId.Threed, 0x18D4, 0x0);
+ channel.Write(ClassId.Threed, 0x18D8, 0x0);
+ channel.Write(ClassId.Threed, 0x18DC, 0x0);
+ channel.Write(ClassId.Threed, 0x18E0, 0x0);
+ channel.Write(ClassId.Threed, 0x18E4, 0x0);
+ channel.Write(ClassId.Threed, 0x18E8, 0x0);
+ channel.Write(ClassId.Threed, 0x18EC, 0x0);
+ channel.Write(ClassId.Threed, 0x18F0, 0x0);
+ channel.Write(ClassId.Threed, 0x18F4, 0x0);
+ channel.Write(ClassId.Threed, 0x18F8, 0x0);
+ channel.Write(ClassId.Threed, 0x18FC, 0x0);
+ channel.Write(ClassId.Threed, 0xF84, 0x0);
+ channel.Write(ClassId.Threed, 0xF88, 0x0);
+ channel.Write(ClassId.Threed, 0x17C8, 0x0);
+ channel.Write(ClassId.Threed, 0x17CC, 0x0);
+ channel.Write(ClassId.Threed, 0x17D0, 0xFF);
+ channel.Write(ClassId.Threed, 0x17D4, 0xFFFFFFFF);
+ channel.Write(ClassId.Threed, 0x17D8, 0x2);
+ channel.Write(ClassId.Threed, 0x17DC, 0x0);
+ channel.Write(ClassId.Threed, 0x15F4, 0x0);
+ channel.Write(ClassId.Threed, 0x15F8, 0x0);
+ channel.Write(ClassId.Threed, 0x1434, 0x0);
+ channel.Write(ClassId.Threed, 0x1438, 0x0);
+ channel.Write(ClassId.Threed, 0xD74, 0x0);
+ channel.Write(ClassId.Threed, 0x13A4, 0x0);
+ channel.Write(ClassId.Threed, 0x1318, 0x1);
+ channel.Write(ClassId.Threed, 0x1080, 0x0);
+ channel.Write(ClassId.Threed, 0x1084, 0x0);
+ channel.Write(ClassId.Threed, 0x1088, 0x1);
+ channel.Write(ClassId.Threed, 0x108C, 0x1);
+ channel.Write(ClassId.Threed, 0x1090, 0x0);
+ channel.Write(ClassId.Threed, 0x1094, 0x1);
+ channel.Write(ClassId.Threed, 0x1098, 0x0);
+ channel.Write(ClassId.Threed, 0x109C, 0x1);
+ channel.Write(ClassId.Threed, 0x10A0, 0x0);
+ channel.Write(ClassId.Threed, 0x10A4, 0x0);
+ channel.Write(ClassId.Threed, 0x1644, 0x0);
+ channel.Write(ClassId.Threed, 0x748, 0x0);
+ channel.Write(ClassId.Threed, 0xDE8, 0x0);
+ channel.Write(ClassId.Threed, 0x1648, 0x0);
+ channel.Write(ClassId.Threed, 0x12A4, 0x0);
+ channel.Write(ClassId.Threed, 0x1120, 0x0);
+ channel.Write(ClassId.Threed, 0x1124, 0x0);
+ channel.Write(ClassId.Threed, 0x1128, 0x0);
+ channel.Write(ClassId.Threed, 0x112C, 0x0);
+ channel.Write(ClassId.Threed, 0x1118, 0x0);
+ channel.Write(ClassId.Threed, 0x164C, 0x0);
+ channel.Write(ClassId.Threed, 0x1658, 0x0);
+ channel.Write(ClassId.Threed, 0x1910, 0x290);
+ channel.Write(ClassId.Threed, 0x1518, 0x0);
+ channel.Write(ClassId.Threed, 0x165C, 0x1);
+ channel.Write(ClassId.Threed, 0x1520, 0x0);
+ channel.Write(ClassId.Threed, 0x1604, 0x0);
+ channel.Write(ClassId.Threed, 0x1570, 0x0);
+ channel.Write(ClassId.Threed, 0x13B0, 0x3F800000);
+ channel.Write(ClassId.Threed, 0x13B4, 0x3F800000);
+ channel.Write(ClassId.Threed, 0x20C, 0x0);
+ channel.Write(ClassId.Threed, 0x1670, 0x30201000);
+ channel.Write(ClassId.Threed, 0x1674, 0x70605040);
+ channel.Write(ClassId.Threed, 0x1678, 0xB8A89888);
+ channel.Write(ClassId.Threed, 0x167C, 0xF8E8D8C8);
+ channel.Write(ClassId.Threed, 0x166C, 0x0);
+ channel.Write(ClassId.Threed, 0x1680, 0xFFFF00);
+ channel.Write(ClassId.Threed, 0x12D0, 0x3);
+ channel.Write(ClassId.Threed, 0x113C, 0x0);
+ channel.Write(ClassId.Threed, 0x12D4, 0x2);
+ channel.Write(ClassId.Threed, 0x1684, 0x0);
+ channel.Write(ClassId.Threed, 0x1688, 0x0);
+ channel.Write(ClassId.Threed, 0xDAC, 0x1B02);
+ channel.Write(ClassId.Threed, 0xDB0, 0x1B02);
+ channel.Write(ClassId.Threed, 0xDB4, 0x0);
+ channel.Write(ClassId.Threed, 0x168C, 0x0);
+ channel.Write(ClassId.Threed, 0x15BC, 0x0);
+ channel.Write(ClassId.Threed, 0x156C, 0x0);
+ channel.Write(ClassId.Threed, 0x187C, 0x0);
+ channel.Write(ClassId.Threed, 0x1110, 0x1);
+ channel.Write(ClassId.Threed, 0xDC0, 0x0);
+ channel.Write(ClassId.Threed, 0xDC4, 0x0);
+ channel.Write(ClassId.Threed, 0xDC8, 0x0);
+ channel.Write(ClassId.Threed, 0xF40, 0x0);
+ channel.Write(ClassId.Threed, 0xF44, 0x0);
+ channel.Write(ClassId.Threed, 0xF48, 0x0);
+ channel.Write(ClassId.Threed, 0xF4C, 0x0);
+ channel.Write(ClassId.Threed, 0xF50, 0x0);
+ channel.Write(ClassId.Threed, 0x1234, 0x0);
+ channel.Write(ClassId.Threed, 0x1690, 0x0);
+ channel.Write(ClassId.Threed, 0x790, 0x0);
+ channel.Write(ClassId.Threed, 0x794, 0x0);
+ channel.Write(ClassId.Threed, 0x798, 0x0);
+ channel.Write(ClassId.Threed, 0x79C, 0x0);
+ channel.Write(ClassId.Threed, 0x7A0, 0x0);
+ channel.Write(ClassId.Threed, 0x77C, 0x0);
+ channel.Write(ClassId.Threed, 0x1000, 0x10);
+ channel.Write(ClassId.Threed, 0x10FC, 0x0);
+ channel.Write(ClassId.Threed, 0x1290, 0x0);
+ channel.Write(ClassId.Threed, 0x218, 0x10);
+ channel.Write(ClassId.Threed, 0x12D8, 0x0);
+ channel.Write(ClassId.Threed, 0x12DC, 0x10);
+ channel.Write(ClassId.Threed, 0xD94, 0x1);
+ channel.Write(ClassId.Threed, 0x155C, 0x0);
+ channel.Write(ClassId.Threed, 0x1560, 0x0);
+ channel.Write(ClassId.Threed, 0x1564, 0xFFF);
+ channel.Write(ClassId.Threed, 0x1574, 0x0);
+ channel.Write(ClassId.Threed, 0x1578, 0x0);
+ channel.Write(ClassId.Threed, 0x157C, 0xFFFFF);
+ channel.Write(ClassId.Threed, 0x1354, 0x0);
+ channel.Write(ClassId.Threed, 0x1610, 0x12);
+ channel.Write(ClassId.Threed, 0x1608, 0x0);
+ channel.Write(ClassId.Threed, 0x160C, 0x0);
+ channel.Write(ClassId.Threed, 0x260C, 0x0);
+ channel.Write(ClassId.Threed, 0x7AC, 0x0);
+ channel.Write(ClassId.Threed, 0x162C, 0x3);
+ channel.Write(ClassId.Threed, 0x210, 0x0);
+ channel.Write(ClassId.Threed, 0x320, 0x0);
+ channel.Write(ClassId.Threed, 0x324, 0x3F800000);
+ channel.Write(ClassId.Threed, 0x328, 0x3F800000);
+ channel.Write(ClassId.Threed, 0x32C, 0x3F800000);
+ channel.Write(ClassId.Threed, 0x330, 0x3F800000);
+ channel.Write(ClassId.Threed, 0x334, 0x3F800000);
+ channel.Write(ClassId.Threed, 0x338, 0x3F800000);
+ channel.Write(ClassId.Threed, 0x750, 0x0);
+ channel.Write(ClassId.Threed, 0x760, 0x39291909);
+ channel.Write(ClassId.Threed, 0x764, 0x79695949);
+ channel.Write(ClassId.Threed, 0x768, 0xB9A99989);
+ channel.Write(ClassId.Threed, 0x76C, 0xF9E9D9C9);
+ channel.Write(ClassId.Threed, 0x770, 0x30201000);
+ channel.Write(ClassId.Threed, 0x774, 0x70605040);
+ channel.Write(ClassId.Threed, 0x778, 0x9080);
+ channel.Write(ClassId.Threed, 0x780, 0x39291909);
+ channel.Write(ClassId.Threed, 0x784, 0x79695949);
+ channel.Write(ClassId.Threed, 0x788, 0xB9A99989);
+ channel.Write(ClassId.Threed, 0x78C, 0xF9E9D9C9);
+ channel.Write(ClassId.Threed, 0x7D0, 0x30201000);
+ channel.Write(ClassId.Threed, 0x7D4, 0x70605040);
+ channel.Write(ClassId.Threed, 0x7D8, 0x9080);
+ channel.Write(ClassId.Threed, 0x1004, 0x0);
+ channel.Write(ClassId.Threed, 0x1240, 0x0);
+ channel.Write(ClassId.Threed, 0x1244, 0x0);
+ channel.Write(ClassId.Threed, 0x1248, 0x0);
+ channel.Write(ClassId.Threed, 0x124C, 0x0);
+ channel.Write(ClassId.Threed, 0x1250, 0x0);
+ channel.Write(ClassId.Threed, 0x1254, 0x0);
+ channel.Write(ClassId.Threed, 0x1258, 0x0);
+ channel.Write(ClassId.Threed, 0x125C, 0x0);
+ channel.Write(ClassId.Threed, 0x37C, 0x1);
+ channel.Write(ClassId.Threed, 0x740, 0x0);
+ channel.Write(ClassId.Threed, 0x1148, 0x0);
+ channel.Write(ClassId.Threed, 0xFB4, 0x0);
+ channel.Write(ClassId.Threed, 0xFB8, 0x2);
+ channel.Write(ClassId.Threed, 0x1130, 0x2);
+ channel.Write(ClassId.Threed, 0xFD4, 0x0);
+ channel.Write(ClassId.Threed, 0xFD8, 0x0);
+ channel.Write(ClassId.Threed, 0x1030, 0x20181008);
+ channel.Write(ClassId.Threed, 0x1034, 0x40383028);
+ channel.Write(ClassId.Threed, 0x1038, 0x60585048);
+ channel.Write(ClassId.Threed, 0x103C, 0x80787068);
+ channel.Write(ClassId.Threed, 0x744, 0x0);
+ channel.Write(ClassId.Threed, 0x2600, 0x0);
+ channel.Write(ClassId.Threed, 0x1918, 0x0);
+ channel.Write(ClassId.Threed, 0x191C, 0x900);
+ channel.Write(ClassId.Threed, 0x1920, 0x405);
+ channel.Write(ClassId.Threed, 0x1308, 0x1);
+ channel.Write(ClassId.Threed, 0x1924, 0x0);
+ channel.Write(ClassId.Threed, 0x13AC, 0x0);
+ channel.Write(ClassId.Threed, 0x192C, 0x1);
+ channel.Write(ClassId.Threed, 0x193C, 0x2C1C);
+ channel.Write(ClassId.Threed, 0xD7C, 0x0);
+ channel.Write(ClassId.Threed, 0xF8C, 0x0);
+ channel.Write(ClassId.Threed, 0x2C0, 0x1);
+ channel.Write(ClassId.Threed, 0x1510, 0x0);
+ channel.Write(ClassId.Threed, 0x1940, 0x0);
+ channel.Write(ClassId.Threed, 0xFF4, 0x0);
+ channel.Write(ClassId.Threed, 0xFF8, 0x0);
+ channel.Write(ClassId.Threed, 0x194C, 0x0);
+ channel.Write(ClassId.Threed, 0x1950, 0x0);
+ channel.Write(ClassId.Threed, 0x1968, 0x0);
+ channel.Write(ClassId.Threed, 0x1590, 0x3F);
+ channel.Write(ClassId.Threed, 0x7E8, 0x0);
+ channel.Write(ClassId.Threed, 0x7EC, 0x0);
+ channel.Write(ClassId.Threed, 0x7F0, 0x0);
+ channel.Write(ClassId.Threed, 0x7F4, 0x0);
+ channel.Write(ClassId.Threed, 0x196C, 0x11);
+ channel.Write(ClassId.Threed, 0x2E4, 0xB001);
+ channel.Write(ClassId.Threed, 0x36C, 0x0);
+ channel.Write(ClassId.Threed, 0x370, 0x0);
+ channel.Write(ClassId.Threed, 0x197C, 0x0);
+ channel.Write(ClassId.Threed, 0xFCC, 0x0);
+ channel.Write(ClassId.Threed, 0xFD0, 0x0);
+ channel.Write(ClassId.Threed, 0x2D8, 0x40);
+ channel.Write(ClassId.Threed, 0x1980, 0x80);
+ channel.Write(ClassId.Threed, 0x1504, 0x80);
+ channel.Write(ClassId.Threed, 0x1984, 0x0);
+ channel.Write(ClassId.Threed, 0xF60, 0x0);
+ channel.Write(ClassId.Threed, 0xF64, 0x400040);
+ channel.Write(ClassId.Threed, 0xF68, 0x2212);
+ channel.Write(ClassId.Threed, 0xF6C, 0x8080203);
+ channel.Write(ClassId.Threed, 0x1108, 0x8);
+ channel.Write(ClassId.Threed, 0xF70, 0x80001);
+ channel.Write(ClassId.Threed, 0xFFC, 0x0);
+ channel.Write(ClassId.Threed, 0x1134, 0x0);
+ channel.Write(ClassId.Threed, 0xF1C, 0x0);
+ channel.Write(ClassId.Threed, 0x11F8, 0x0);
+ channel.Write(ClassId.Threed, 0x1138, 0x1);
+ channel.Write(ClassId.Threed, 0x300, 0x1);
+ channel.Write(ClassId.Threed, 0x13A8, 0x0);
+ channel.Write(ClassId.Threed, 0x1224, 0x0);
+ channel.Write(ClassId.Threed, 0x12EC, 0x0);
+ channel.Write(ClassId.Threed, 0x1310, 0x0);
+ channel.Write(ClassId.Threed, 0x1314, 0x1);
+ channel.Write(ClassId.Threed, 0x1380, 0x0);
+ channel.Write(ClassId.Threed, 0x1384, 0x1);
+ channel.Write(ClassId.Threed, 0x1388, 0x1);
+ channel.Write(ClassId.Threed, 0x138C, 0x1);
+ channel.Write(ClassId.Threed, 0x1390, 0x1);
+ channel.Write(ClassId.Threed, 0x1394, 0x0);
+ channel.Write(ClassId.Threed, 0x139C, 0x0);
+ channel.Write(ClassId.Threed, 0x1398, 0x0);
+ channel.Write(ClassId.Threed, 0x1594, 0x0);
+ channel.Write(ClassId.Threed, 0x1598, 0x1);
+ channel.Write(ClassId.Threed, 0x159C, 0x1);
+ channel.Write(ClassId.Threed, 0x15A0, 0x1);
+ channel.Write(ClassId.Threed, 0x15A4, 0x1);
+ channel.Write(ClassId.Threed, 0xF54, 0x0);
+ channel.Write(ClassId.Threed, 0xF58, 0x0);
+ channel.Write(ClassId.Threed, 0xF5C, 0x0);
+ channel.Write(ClassId.Threed, 0x19BC, 0x0);
+ channel.Write(ClassId.Threed, 0xF9C, 0x0);
+ channel.Write(ClassId.Threed, 0xFA0, 0x0);
+ channel.Write(ClassId.Threed, 0x12CC, 0x0);
+ channel.Write(ClassId.Threed, 0x12E8, 0x0);
+ channel.Write(ClassId.Threed, 0x130C, 0x1);
+ channel.Write(ClassId.Threed, 0x1360, 0x0);
+ channel.Write(ClassId.Threed, 0x1364, 0x0);
+ channel.Write(ClassId.Threed, 0x1368, 0x0);
+ channel.Write(ClassId.Threed, 0x136C, 0x0);
+ channel.Write(ClassId.Threed, 0x1370, 0x0);
+ channel.Write(ClassId.Threed, 0x1374, 0x0);
+ channel.Write(ClassId.Threed, 0x1378, 0x0);
+ channel.Write(ClassId.Threed, 0x137C, 0x0);
+ channel.Write(ClassId.Threed, 0x133C, 0x1);
+ channel.Write(ClassId.Threed, 0x1340, 0x1);
+ channel.Write(ClassId.Threed, 0x1344, 0x2);
+ channel.Write(ClassId.Threed, 0x1348, 0x1);
+ channel.Write(ClassId.Threed, 0x134C, 0x1);
+ channel.Write(ClassId.Threed, 0x1350, 0x2);
+ channel.Write(ClassId.Threed, 0x1358, 0x1);
+ channel.Write(ClassId.Threed, 0x12E4, 0x0);
+ channel.Write(ClassId.Threed, 0x131C, 0x0);
+ channel.Write(ClassId.Threed, 0x1320, 0x0);
+ channel.Write(ClassId.Threed, 0x1324, 0x0);
+ channel.Write(ClassId.Threed, 0x1328, 0x0);
+ channel.Write(ClassId.Threed, 0x19C0, 0x0);
+ channel.Write(ClassId.Threed, 0x1140, 0x0);
+ channel.Write(ClassId.Threed, 0xDD0, 0x0);
+ channel.Write(ClassId.Threed, 0xDD4, 0x1);
+ channel.Write(ClassId.Threed, 0x2F4, 0x0);
+ channel.Write(ClassId.Threed, 0x19C4, 0x0);
+ channel.Write(ClassId.Threed, 0x19C8, 0x1500);
+ channel.Write(ClassId.Threed, 0x135C, 0x0);
+ channel.Write(ClassId.Threed, 0xF90, 0x0);
+ channel.Write(ClassId.Threed, 0x19E0, 0x1);
+ channel.Write(ClassId.Threed, 0x19E4, 0x1);
+ channel.Write(ClassId.Threed, 0x19E8, 0x1);
+ channel.Write(ClassId.Threed, 0x19EC, 0x1);
+ channel.Write(ClassId.Threed, 0x19F0, 0x1);
+ channel.Write(ClassId.Threed, 0x19F4, 0x1);
+ channel.Write(ClassId.Threed, 0x19F8, 0x1);
+ channel.Write(ClassId.Threed, 0x19FC, 0x1);
+ channel.Write(ClassId.Threed, 0x19CC, 0x1);
+ channel.Write(ClassId.Threed, 0x111C, 0x1);
+ channel.Write(ClassId.Threed, 0x15B8, 0x0);
+ channel.Write(ClassId.Threed, 0x1A00, 0x1111);
+ channel.Write(ClassId.Threed, 0x1A04, 0x0);
+ channel.Write(ClassId.Threed, 0x1A08, 0x0);
+ channel.Write(ClassId.Threed, 0x1A0C, 0x0);
+ channel.Write(ClassId.Threed, 0x1A10, 0x0);
+ channel.Write(ClassId.Threed, 0x1A14, 0x0);
+ channel.Write(ClassId.Threed, 0x1A18, 0x0);
+ channel.Write(ClassId.Threed, 0x1A1C, 0x0);
+ channel.Write(ClassId.Threed, 0xD6C, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0xD70, 0xFFFF0000);
+ channel.Write(ClassId.Threed, 0x10F8, 0x1010);
+ channel.Write(ClassId.Threed, 0xD80, 0x0);
+ channel.Write(ClassId.Threed, 0xD84, 0x0);
+ channel.Write(ClassId.Threed, 0xD88, 0x0);
+ channel.Write(ClassId.Threed, 0xD8C, 0x0);
+ channel.Write(ClassId.Threed, 0xD90, 0x0);
+ channel.Write(ClassId.Threed, 0xDA0, 0x0);
+ channel.Write(ClassId.Threed, 0x7A4, 0x0);
+ channel.Write(ClassId.Threed, 0x7A8, 0x0);
+ channel.Write(ClassId.Threed, 0x1508, 0x80000000);
+ channel.Write(ClassId.Threed, 0x150C, 0x40000000);
+ channel.Write(ClassId.Threed, 0x1668, 0x0);
+ channel.Write(ClassId.Threed, 0x318, 0x8);
+ channel.Write(ClassId.Threed, 0x31C, 0x8);
+ channel.Write(ClassId.Threed, 0xD9C, 0x1);
+ channel.Write(ClassId.Threed, 0xF14, 0x0);
+ channel.Write(ClassId.Threed, 0x374, 0x0);
+ channel.Write(ClassId.Threed, 0x378, 0xC);
+ channel.Write(ClassId.Threed, 0x7DC, 0x0);
+ channel.Write(ClassId.Threed, 0x74C, 0x55);
+ channel.Write(ClassId.Threed, 0x1420, 0x3);
+ channel.Write(ClassId.Threed, 0x1008, 0x8);
+ channel.Write(ClassId.Threed, 0x100C, 0x40);
+ channel.Write(ClassId.Threed, 0x1010, 0x12C);
+ channel.Write(ClassId.Threed, 0xD60, 0x40);
+ channel.Write(ClassId.Threed, 0x1018, 0x20);
+ channel.Write(ClassId.Threed, 0x101C, 0x1);
+ channel.Write(ClassId.Threed, 0x1020, 0x20);
+ channel.Write(ClassId.Threed, 0x1024, 0x1);
+ channel.Write(ClassId.Threed, 0x1444, 0x0);
+ channel.Write(ClassId.Threed, 0x1448, 0x0);
+ channel.Write(ClassId.Threed, 0x144C, 0x0);
+ channel.Write(ClassId.Threed, 0x360, 0x20164010);
+ channel.Write(ClassId.Threed, 0x364, 0x20);
+ channel.Write(ClassId.Threed, 0x368, 0x0);
+ channel.Write(ClassId.Threed, 0xDA8, 0x30);
+ channel.Write(ClassId.Threed, 0xDE4, 0x0);
+ channel.Write(ClassId.Threed, 0x204, 0x6);
+ channel.Write(ClassId.Threed, 0x2D0, 0x3FFFFF);
+ channel.Write(ClassId.Threed, 0x1220, 0x5);
+ channel.Write(ClassId.Threed, 0xFDC, 0x0);
+ channel.Write(ClassId.Threed, 0xF98, 0x400008);
+ channel.Write(ClassId.Threed, 0x1284, 0x8000080);
+ channel.Write(ClassId.Threed, 0x1450, 0x400008);
+ channel.Write(ClassId.Threed, 0x1454, 0x8000080);
+ channel.Write(ClassId.Threed, 0x214, 0x0);
+ channel.Write(ClassId.Twod, 0x200, 0xCF);
+ channel.Write(ClassId.Twod, 0x204, 0x1);
+ channel.Write(ClassId.Twod, 0x208, 0x20);
+ channel.Write(ClassId.Twod, 0x20C, 0x1);
+ channel.Write(ClassId.Twod, 0x210, 0x0);
+ channel.Write(ClassId.Twod, 0x214, 0x80);
+ channel.Write(ClassId.Twod, 0x218, 0x100);
+ channel.Write(ClassId.Twod, 0x21C, 0x100);
+ channel.Write(ClassId.Twod, 0x220, 0x0);
+ channel.Write(ClassId.Twod, 0x224, 0x0);
+ channel.Write(ClassId.Twod, 0x230, 0xCF);
+ channel.Write(ClassId.Twod, 0x234, 0x1);
+ channel.Write(ClassId.Twod, 0x238, 0x20);
+ channel.Write(ClassId.Twod, 0x23C, 0x1);
+ channel.Write(ClassId.Twod, 0x244, 0x80);
+ channel.Write(ClassId.Twod, 0x248, 0x100);
+ channel.Write(ClassId.Twod, 0x24C, 0x100);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs
index ebaab0c9..a85fd44c 100644
--- a/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs
+++ b/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs
@@ -54,6 +54,8 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel
_host1xContext = GetHost1XContext(context.Device.Gpu, owner);
Channel = _device.Gpu.CreateChannel();
+ ChannelInitialization.InitializeState(Channel);
+
ChannelSyncpoints = new uint[MaxModuleSyncpoint];
_channelSyncpoint.Id = _device.System.HostSyncpoint.AllocateSyncpoint(false);