From 40b21cc3c4d2622bbd4f88d43073341854d9a671 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 11 Jul 2021 17:20:40 -0300 Subject: [PATCH] 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 --- Ryujinx.Graphics.Device/AccessControl.cs | 10 - Ryujinx.Graphics.Device/DeviceState.cs | 126 +- Ryujinx.Graphics.Device/RegisterAttribute.cs | 15 - Ryujinx.Graphics.Device/SizeCalculator.cs | 2 +- Ryujinx.Graphics.Gpu/ClassId.cs | 14 +- .../Engine/Compute/ComputeClass.cs | 38 +- .../Engine/Compute/ComputeQmd.cs | 2 +- .../Engine/ConditionalRenderEnabled.cs | 3 + .../Engine/DeviceStateWithShadow.cs | 95 ++ Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs | 15 +- Ryujinx.Graphics.Gpu/Engine/Dma/DmaTexture.cs | 20 + .../Engine/GPFifo/GPFifoClass.cs | 7 +- .../Engine/GPFifo/GPFifoProcessor.cs | 178 ++- Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs | 134 -- .../InlineToMemory/InlineToMemoryClass.cs | 12 +- Ryujinx.Graphics.Gpu/Engine/MME/IMacroEE.cs | 6 +- Ryujinx.Graphics.Gpu/Engine/MME/Macro.cs | 4 +- .../Engine/MME/MacroInterpreter.cs | 22 +- Ryujinx.Graphics.Gpu/Engine/MME/MacroJit.cs | 4 +- .../Engine/MME/MacroJitCompiler.cs | 6 +- .../Engine/MME/MacroJitContext.cs | 12 +- Ryujinx.Graphics.Gpu/Engine/MethodClear.cs | 85 - Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs | 343 ----- Ryujinx.Graphics.Gpu/Engine/MethodFirmware.cs | 12 - .../Engine/MethodIncrementSyncpoint.cs | 21 - Ryujinx.Graphics.Gpu/Engine/MethodReport.cs | 131 -- .../Engine/MethodResetCounter.cs | 31 - .../Engine/MethodUniformBufferBind.cs | 85 - .../Engine/MethodUniformBufferUpdate.cs | 88 -- Ryujinx.Graphics.Gpu/Engine/Methods.cs | 1138 -------------- .../Engine/MmeShadowScratch.cs | 3 + .../Engine/SetMmeShadowRamControlMode.cs | 13 + .../ConditionalRendering.cs} | 58 +- .../Engine/Threed/ConstantBufferUpdater.cs | 173 +++ .../Engine/Threed/DrawManager.cs | 410 +++++ .../Engine/Threed/DrawState.cs | 45 + .../Engine/{ => Threed}/IbStreamer.cs | 5 +- .../Engine/Threed/SemaphoreUpdater.cs | 222 +++ .../Engine/Threed/StateUpdateTracker.cs | 166 ++ .../Engine/Threed/StateUpdater.cs | 1044 +++++++++++++ .../Engine/Threed/ThreedClass.cs | 428 ++++++ .../Engine/Threed/ThreedClassState.cs | 861 +++++++++++ Ryujinx.Graphics.Gpu/Engine/Twod/TwodClass.cs | 6 +- .../Engine/Twod/TwodClassState.cs | 13 +- .../Engine/Twod/TwodTexture.cs | 22 + .../{State => Engine/Types}/Boolean32.cs | 2 +- .../{State => Engine/Types}/ColorFormat.cs | 2 +- .../{State => Engine/Types}/GpuVa.cs | 2 +- .../{State => Engine/Types}/MemoryLayout.cs | 2 +- .../{State => Engine/Types}/PrimitiveType.cs | 3 +- .../{State => Engine/Types}/SamplerIndex.cs | 2 +- .../{State => Engine/Types}/SbDescriptor.cs | 2 +- .../{State => Engine/Types}/ZetaFormat.cs | 2 +- Ryujinx.Graphics.Gpu/GpuChannel.cs | 11 + Ryujinx.Graphics.Gpu/GpuContext.cs | 8 - .../Image/TextureBindingsManager.cs | 2 +- Ryujinx.Graphics.Gpu/Image/TextureCache.cs | 9 +- Ryujinx.Graphics.Gpu/Image/TextureManager.cs | 2 +- Ryujinx.Graphics.Gpu/Memory/BufferCache.cs | 1 - Ryujinx.Graphics.Gpu/MethodParams.cs | 52 - Ryujinx.Graphics.Gpu/Shader/GpuAccessor.cs | 34 +- .../Shader/GpuAccessorState.cs | 16 +- Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs | 61 +- Ryujinx.Graphics.Gpu/ShadowRamControl.cs | 28 - Ryujinx.Graphics.Gpu/State/BlendState.cs | 31 - .../State/BlendStateCommon.cs | 31 - Ryujinx.Graphics.Gpu/State/ClearColors.cs | 15 - Ryujinx.Graphics.Gpu/State/Condition.cs | 14 - Ryujinx.Graphics.Gpu/State/ConditionState.cs | 13 - .../State/CopyBufferTexture.cs | 18 - Ryujinx.Graphics.Gpu/State/CopyRegion.cs | 19 - Ryujinx.Graphics.Gpu/State/CopyTexture.cs | 20 - Ryujinx.Graphics.Gpu/State/DepthBiasState.cs | 14 - Ryujinx.Graphics.Gpu/State/FaceState.cs | 16 - Ryujinx.Graphics.Gpu/State/GpuState.cs | 477 ------ Ryujinx.Graphics.Gpu/State/GpuStateTable.cs | 87 -- .../State/IndexBufferState.cs | 19 - .../State/Inline2MemoryParams.cs | 22 - Ryujinx.Graphics.Gpu/State/LogicalOpState.cs | 12 - Ryujinx.Graphics.Gpu/State/MethodOffset.cs | 134 -- Ryujinx.Graphics.Gpu/State/PoolState.cs | 13 - .../State/PrimitiveRestartState.cs | 13 - .../State/ReportCounterType.cs | 29 - .../State/ResetCounterType.cs | 24 - Ryujinx.Graphics.Gpu/State/RtColorMask.cs | 49 - Ryujinx.Graphics.Gpu/State/RtColorState.cs | 26 - Ryujinx.Graphics.Gpu/State/RtControl.cs | 31 - .../State/RtDepthStencilState.cs | 15 - Ryujinx.Graphics.Gpu/State/ScissorState.cs | 14 - .../State/ScreenScissorState.cs | 12 - .../State/SemaphoreOperation.cs | 12 - Ryujinx.Graphics.Gpu/State/SemaphoreState.cs | 14 - Ryujinx.Graphics.Gpu/State/ShaderState.cs | 37 - Ryujinx.Graphics.Gpu/State/ShaderType.cs | 14 - Ryujinx.Graphics.Gpu/State/Size3D.cs | 14 - .../State/StencilBackMasks.cs | 14 - .../State/StencilBackTestState.cs | 18 - .../State/StencilTestState.cs | 21 - Ryujinx.Graphics.Gpu/State/TfBufferState.cs | 18 - Ryujinx.Graphics.Gpu/State/TfState.cs | 15 - .../State/UniformBufferState.cs | 14 - .../State/VertexAttribState.cs | 48 - .../State/VertexBufferDrawState.cs | 13 - .../State/VertexBufferState.cs | 32 - .../State/ViewVolumeClipControl.cs | 11 - Ryujinx.Graphics.Gpu/State/ViewportExtents.cs | 17 - .../State/ViewportTransform.cs | 57 - Ryujinx.Graphics.Gpu/State/YControl.cs | 11 - Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs | 2 +- .../NvHostChannel/ChannelInitialization.cs | 1361 +++++++++++++++++ .../NvHostChannel/NvHostChannelDeviceFile.cs | 2 + 111 files changed, 5262 insertions(+), 4020 deletions(-) delete mode 100644 Ryujinx.Graphics.Device/AccessControl.cs delete mode 100644 Ryujinx.Graphics.Device/RegisterAttribute.cs create mode 100644 Ryujinx.Graphics.Gpu/Engine/DeviceStateWithShadow.cs create mode 100644 Ryujinx.Graphics.Gpu/Engine/Dma/DmaTexture.cs delete mode 100644 Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs delete mode 100644 Ryujinx.Graphics.Gpu/Engine/MethodClear.cs delete mode 100644 Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs delete mode 100644 Ryujinx.Graphics.Gpu/Engine/MethodFirmware.cs delete mode 100644 Ryujinx.Graphics.Gpu/Engine/MethodIncrementSyncpoint.cs delete mode 100644 Ryujinx.Graphics.Gpu/Engine/MethodReport.cs delete mode 100644 Ryujinx.Graphics.Gpu/Engine/MethodResetCounter.cs delete mode 100644 Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferBind.cs delete mode 100644 Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs delete mode 100644 Ryujinx.Graphics.Gpu/Engine/Methods.cs create mode 100644 Ryujinx.Graphics.Gpu/Engine/SetMmeShadowRamControlMode.cs rename Ryujinx.Graphics.Gpu/Engine/{MethodConditionalRendering.cs => Threed/ConditionalRendering.cs} (56%) create mode 100644 Ryujinx.Graphics.Gpu/Engine/Threed/ConstantBufferUpdater.cs create mode 100644 Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs create mode 100644 Ryujinx.Graphics.Gpu/Engine/Threed/DrawState.cs rename Ryujinx.Graphics.Gpu/Engine/{ => Threed}/IbStreamer.cs (96%) create mode 100644 Ryujinx.Graphics.Gpu/Engine/Threed/SemaphoreUpdater.cs create mode 100644 Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdateTracker.cs create mode 100644 Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs create mode 100644 Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs create mode 100644 Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs create mode 100644 Ryujinx.Graphics.Gpu/Engine/Twod/TwodTexture.cs rename Ryujinx.Graphics.Gpu/{State => Engine/Types}/Boolean32.cs (88%) rename Ryujinx.Graphics.Gpu/{State => Engine/Types}/ColorFormat.cs (99%) rename Ryujinx.Graphics.Gpu/{State => Engine/Types}/GpuVa.cs (91%) rename Ryujinx.Graphics.Gpu/{State => Engine/Types}/MemoryLayout.cs (94%) rename Ryujinx.Graphics.Gpu/{State => Engine/Types}/PrimitiveType.cs (98%) rename Ryujinx.Graphics.Gpu/{State => Engine/Types}/SamplerIndex.cs (78%) rename Ryujinx.Graphics.Gpu/{State => Engine/Types}/SbDescriptor.cs (90%) rename Ryujinx.Graphics.Gpu/{State => Engine/Types}/ZetaFormat.cs (97%) delete mode 100644 Ryujinx.Graphics.Gpu/MethodParams.cs delete mode 100644 Ryujinx.Graphics.Gpu/ShadowRamControl.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/BlendState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/BlendStateCommon.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/ClearColors.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/Condition.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/ConditionState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/CopyBufferTexture.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/CopyRegion.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/CopyTexture.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/DepthBiasState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/FaceState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/GpuState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/GpuStateTable.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/IndexBufferState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/Inline2MemoryParams.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/LogicalOpState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/MethodOffset.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/PoolState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/PrimitiveRestartState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/ReportCounterType.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/ResetCounterType.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/RtColorMask.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/RtColorState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/RtControl.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/RtDepthStencilState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/ScissorState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/ScreenScissorState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/SemaphoreOperation.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/SemaphoreState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/ShaderState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/ShaderType.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/Size3D.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/StencilBackMasks.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/StencilBackTestState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/StencilTestState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/TfBufferState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/TfState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/UniformBufferState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/VertexAttribState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/VertexBufferDrawState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/VertexBufferState.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/ViewVolumeClipControl.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/ViewportExtents.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/ViewportTransform.cs delete mode 100644 Ryujinx.Graphics.Gpu/State/YControl.cs create mode 100644 Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/ChannelInitialization.cs 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() + RegisterSize - 1) / RegisterSize; - private readonly Dictionary> _readCallbacks; - private readonly Dictionary> _writeCallbacks; + private readonly Func[] _readCallbacks; + private readonly Action[] _writeCallbacks; - private readonly Dictionary _fieldNamesForDebug; + private readonly Dictionary _fieldNamesForDebug; private readonly Action _debugLogCallback; public DeviceState(IReadOnlyDictionary callbacks = null, Action debugLogCallback = null) { - int size = (Unsafe.SizeOf() + RegisterSize - 1) / RegisterSize; - - _readableRegisters = new BitArray(size); - _writableRegisters = new BitArray(size); - - _readCallbacks = new Dictionary>(); - _writeCallbacks = new Dictionary>(); + _readCallbacks = new Func[Size]; + _writeCallbacks = new Action[Size]; if (debugLogCallback != null) { - _fieldNamesForDebug = new Dictionary(); + _fieldNamesForDebug = new Dictionary(); _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(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; - } + int index = (offset + i) / RegisterSize; - if (callbacks != null && callbacks.TryGetValue(field.Name, out var cb)) - { - if (cb.Read != null) + if (callbacks != null && callbacks.TryGetValue(field.Name, out var cb)) { - _readCallbacks.Add(offset, cb.Read); - } + if (cb.Read != null) + { + _readCallbacks[index] = cb.Read; + } - if (cb.Write != null) - { - _writeCallbacks.Add(offset, cb.Write); + 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()); } - public virtual int Read(int offset) + public int Read(int offset) { - if (Check(offset) && _readableRegisters[offset / RegisterSize]) - { - int alignedOffset = Align(offset); + uint index = (uint)offset / RegisterSize; - if (_readCallbacks.TryGetValue(alignedOffset, out Func read)) + if (index < Size) + { + uint alignedOffset = index * RegisterSize; + + var readCallback = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_readCallbacks), (IntPtr)index); + if (readCallback != null) { - return read(); + return readCallback(); } else { - return GetRef(alignedOffset); + return GetRefUnchecked(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(alignedOffset) = data; - - if (_writeCallbacks.TryGetValue(alignedOffset, out Action write)) - { - write(data); - } + Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_writeCallbacks), (IntPtr)index)?.Invoke(data); } } - private bool Check(int offset) + public void WriteWithRedundancyCheck(int offset, int data, out bool changed) { - return (uint)Align(offset) < Unsafe.SizeOf(); + 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; + } + } + + [Conditional("DEBUG")] + private void DebugWrite(uint alignedOffset, int data) + { + if (_fieldNamesForDebug != null && _fieldNamesForDebug.TryGetValue(alignedOffset, out string fieldName)) + { + _debugLogCallback($"{typeof(TState).Name}.{fieldName} = 0x{data:X}"); + } } public ref T GetRef(int offset) where T : unmanaged @@ -130,12 +143,19 @@ namespace Ryujinx.Graphics.Device throw new ArgumentOutOfRangeException(nameof(offset)); } + return ref GetRefUnchecked((uint)offset); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ref T GetRefUnchecked(uint offset) where T : unmanaged + { return ref Unsafe.As(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(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 /// /// GPU engine class ID. /// - 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 /// /// Represents a compute engine class. /// - class ComputeClass : InlineToMemoryClass, IDeviceState + class ComputeClass : IDeviceState { private readonly GpuContext _context; private readonly GpuChannel _channel; + private readonly ThreedClass _3dEngine; private readonly DeviceState _state; + private readonly InlineToMemoryClass _i2mClass; + /// /// Creates a new instance of the compute engine class. /// /// GPU context /// GPU channel - public ComputeClass(GpuContext context, GpuChannel channel) : base(context, channel, false) + /// 3D engine + public ComputeClass(GpuContext context, GpuChannel channel, ThreedClass threedEngine) { _context = context; _channel = channel; + _3dEngine = threedEngine; _state = new DeviceState(new Dictionary { { 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); } /// @@ -42,22 +50,31 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute /// /// Register byte offset /// Data at the specified offset - public override int Read(int offset) => _state.Read(offset); + public int Read(int offset) => _state.Read(offset); /// /// Writes data to the class registers. /// /// Register byte offset /// Data to be written - public override void Write(int offset, int data) => _state.Write(offset, data); + public void Write(int offset, int data) => _state.Write(offset, data); /// /// Launches the Inline-to-Memory DMA copy operation. /// /// Method call argument - protected override void LaunchDma(int argument) + private void LaunchDma(int argument) { - LaunchDma(ref Unsafe.As(ref _state.State), argument); + _i2mClass.LaunchDma(ref Unsafe.As(ref _state.State), argument); + } + + /// + /// Pushes a word of data to the Inline-to-Memory engine. + /// + /// Method call argument + private void LoadInlineData(int argument) + { + _i2mClass.LoadInlineData(argument); } /// @@ -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 { + /// + /// Conditional rendering enable. + /// 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 +{ + /// + /// State interface with a shadow memory control register. + /// + interface IShadowState + { + /// + /// MME shadow ram control mode. + /// + SetMmeShadowRamControlMode SetMmeShadowRamControlMode { get; } + } + + /// + /// Represents a device's state, with a additional shadow state. + /// + /// Type of the state + class DeviceStateWithShadow : IDeviceState where TState : unmanaged, IShadowState + { + private readonly DeviceState _state; + private readonly DeviceState _shadowState; + + /// + /// Current device state. + /// + public ref TState State => ref _state.State; + + /// + /// Creates a new instance of the device state, with shadow state. + /// + /// Optional that will be called if a register specified by name is read or written + /// Optional callback to be used for debug log messages + public DeviceStateWithShadow(IReadOnlyDictionary callbacks = null, Action debugLogCallback = null) + { + _state = new DeviceState(callbacks, debugLogCallback); + _shadowState = new DeviceState(); + } + + /// + /// Reads a value from a register. + /// + /// Register offset in bytes + /// Value stored on the register + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Read(int offset) + { + return _state.Read(offset); + } + + /// + /// Writes a value to a register. + /// + /// Register offset in bytes + /// Value to be written + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(int offset, int value) + { + WriteWithRedundancyCheck(offset, value, out _); + } + + /// + /// Writes a value to a register, returning a value indicating if + /// is different from the current value on the register. + /// + /// Register offset in bytes + /// Value to be written + /// True if the value was changed, false otherwise + [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 _state; /// @@ -35,10 +36,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma /// /// GPU context /// GPU channel - public DmaClass(GpuContext context, GpuChannel channel) + /// 3D engine + public DmaClass(GpuContext context, GpuChannel channel, ThreedClass threedEngine) { _context = context; _channel = channel; + _3dEngine = threedEngine; _state = new DeviceState(new Dictionary { { nameof(DmaClassState.LaunchDma), new RwCallback(LaunchDma, null) } @@ -69,7 +72,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma /// Number of pixels to be copied /// Number of lines to be copied /// - 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(ref _state.State.SetDstBlockSize); - var src = Unsafe.As(ref _state.State.SetSrcBlockSize); + var dst = Unsafe.As(ref _state.State.SetDstBlockSize); + var src = Unsafe.As(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 +{ + /// + /// Buffer to texture copy parameters. + /// + 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 /// Method call argument 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 /// Method call argument public void SetMmeShadowRamControl(int argument) { - _parent.SetShadowRamControl((ShadowRamControl)argument); + _parent.SetShadowRamControl(argument); } /// @@ -217,7 +216,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo /// /// Index of the macro /// Current GPU state - 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; + /// + /// Channel memory manager. + /// public MemoryManager MemoryManager => _channel.MemoryManager; /// @@ -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; /// @@ -48,29 +56,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo /// Channel that the GPFIFO processor belongs to 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); } /// @@ -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(); } /// @@ -145,11 +138,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo if (meth.MethodCount < availableCount && meth.SecOp == SecOp.NonIncMethod && - meth.MethodAddress == (int)MethodOffset.UniformBufferUpdateData) + meth.MethodAddress == UniformBufferUpdateDataMethodOffset) { - GpuState state = _subChannels[meth.MethodSubchannel]; - - _context.Methods.UniformBufferUpdate(state, commandBuffer.Slice(offset + 1, meth.MethodCount)); + _3dClass.ConstantBufferUpdate(commandBuffer.Slice(offset + 1, meth.MethodCount)); return true; } @@ -161,55 +152,105 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo /// Sends a uncompressed method for processing by the graphics pipeline. /// /// Method to be processed - private void Send(MethodParams meth) + private void Send(int offset, int argument, int subChannel, bool isLastCall) { - if ((MethodOffset)meth.Method == MethodOffset.BindChannel) + if (offset < 0x60) { - _subChannels[meth.SubChannel].ClearCallbacks(); + _fifoClass.Write(offset * 4, argument); + } + else if (offset < 0xe00) + { + offset *= 4; - _context.Methods.RegisterCallbacks(_subChannels[meth.SubChannel]); - } - else if (meth.Method < 0x60) - { - // TODO: check if macros are shared between subchannels or not. For now let's assume they are. - _fifoClass.Write(meth.Method * 4, meth.Argument); - } - else if (meth.Method < 0xe00) - { - _subChannels[meth.SubChannel].CallMethod(meth); + switch (subChannel) + { + case 0: + _3dClass.Write(offset, argument); + break; + case 1: + _computeClass.Write(offset, argument); + break; + case 2: + _i2mClass.Write(offset, argument); + break; + case 3: + _2dClass.Write(offset, argument); + break; + case 4: + _dmaClass.Write(offset, argument); + break; + } } else { - int macroIndex = (meth.Method >> 1) & MacroIndexMask; - - if ((meth.Method & 1) != 0) + IDeviceState state = subChannel switch { - _fifoClass.MmePushArgument(macroIndex, meth.Argument); - } - else - { - _fifoClass.MmeStart(macroIndex, meth.Argument); - } + 0 => _3dClass, + 3 => _2dClass, + _ => null + }; - if (meth.IsLastCall) + if (state != null) { - _fifoClass.CallMme(macroIndex, _subChannels[meth.SubChannel]); + int macroIndex = (offset >> 1) & MacroIndexMask; - _context.Methods.PerformDeferredDraws(); + if ((offset & 1) != 0) + { + _fifoClass.MmePushArgument(macroIndex, argument); + } + else + { + _fifoClass.MmeStart(macroIndex, argument); + } + + if (isLastCall) + { + _fifoClass.CallMme(macroIndex, state); + + _3dClass.PerformDeferredDraws(); + } } } } + /// + /// Writes data directly to the state of the specified class. + /// + /// ID of the class to write the data into + /// State offset in bytes + /// Value to be written + public void Write(ClassId classId, int offset, int value) + { + switch (classId) + { + case ClassId.Threed: + _3dClass.Write(offset, value); + break; + case ClassId.Compute: + _computeClass.Write(offset, value); + break; + case ClassId.InlineToMemory: + _i2mClass.Write(offset, value); + break; + case ClassId.Twod: + _2dClass.Write(offset, value); + break; + case ClassId.Dma: + _dmaClass.Write(offset, value); + break; + case ClassId.GPFifo: + _fifoClass.Write(offset, value); + break; + } + } + /// /// Sets the shadow ram control value of all sub-channels. /// /// New shadow ram control value - public void SetShadowRamControl(ShadowRamControl control) + public void SetShadowRamControl(int control) { - for (int i = 0; i < _subChannels.Length; i++) - { - _subChannels[i].ShadowRamControl = control; - } + _3dClass.SetShadowRamControl(control); } /// @@ -218,10 +259,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo /// public void ForceAllDirty() { - for (int index = 0; index < _subChannels.Length; index++) - { - _subChannels[index].ForceAllDirty(); - } + _3dClass.ForceStateDirty(); + _channel.BufferManager.Rebind(); + _channel.TextureManager.Rebind(); + } + + /// + /// Perform any deferred draws. + /// + 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; - - /// - /// Launches Inline-to-Memory engine DMA copy. - /// - /// Current GPU state - /// Method call argument - public void LaunchDma(GpuState state, int argument) - { - _params = state.Get(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; - } - - /// - /// Pushes a word of data to the Inline-to-Memory engine. - /// - /// Current GPU state - /// Method call argument - public void LoadInlineData(GpuState state, int argument) - { - if (!_finished) - { - _buffer[_offset++] = argument; - - if (_offset * 4 >= _size) - { - FinishTransfer(state); - } - } - } - - /// - /// Performs actual copy of the inline data after the transfer is finished. - /// - /// Current GPU state - private void FinishTransfer(GpuState state) - { - Span data = MemoryMarshal.Cast(_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 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 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 /// GPU context /// GPU channel /// Indicates if the internal state should be initialized. Set to false if part of another engine - 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 /// /// Register byte offset /// Data at the specified offset - public virtual int Read(int offset) => _state.Read(offset); + public int Read(int offset) => _state.Read(offset); /// /// Writes data to the class registers. /// /// Register byte offset /// Data to be written - public virtual void Write(int offset, int data) => _state.Write(offset, data); + public void Write(int offset, int data) => _state.Write(offset, data); /// /// Launches Inline-to-Memory engine DMA copy. /// /// Method call argument - 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 /// /// Current class state /// Method call argument - 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. /// /// Method call argument - 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 /// /// Arguments FIFO. /// - public Queue Fifo { get; } + Queue Fifo { get; } /// /// Should execute the GPU Macro code being passed. @@ -20,6 +20,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME /// Code to be executed /// GPU state at the time of the call /// First argument to be passed to the GPU Macro - void Execute(ReadOnlySpan code, GpuState state, int arg0); + void Execute(ReadOnlySpan 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 /// /// Program code /// Current GPU state - public void Execute(ReadOnlySpan code, GpuState state) + public void Execute(ReadOnlySpan 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 /// Code of the program to execute /// Current GPU state /// Optional argument passed to the program, 0 if not used - public void Execute(ReadOnlySpan code, GpuState state, int arg0) + public void Execute(ReadOnlySpan 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 /// Program code to execute /// Current GPU state /// True to continue execution, false if the program exited - private bool Step(ReadOnlySpan code, GpuState state) + private bool Step(ReadOnlySpan code, IDeviceState state) { int baseAddr = _pc - 1; @@ -193,7 +195,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME /// /// Current GPU state /// Operation result - 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 /// Current GPU state /// Register offset to read /// GPU register value - private int Read(GpuState state, int reg) + private int Read(IDeviceState state, int reg) { - return state.Read(reg); + return state.Read(reg * 4); } /// @@ -388,11 +390,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME /// /// Current GPU state /// Call argument - 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 /// Code of the program to execute /// Current GPU state /// Optional argument passed to the program, 0 if not used - public void Execute(ReadOnlySpan code, GpuState state, int arg0) + public void Execute(ReadOnlySpan 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 /// 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); /// /// 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 /// Current GPU state /// Register offset to read /// GPU register value - 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); } /// @@ -47,11 +47,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME /// Call argument /// Current GPU state /// Address, in words, of the method - 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 - { - /// - /// Clears the current color and depth-stencil buffers. - /// Which buffers should be cleared is also specified on the argument. - /// - /// Current GPU state - /// Method call argument - 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(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(MethodOffset.ClearDepthValue); - int stencilValue = state.Get (MethodOffset.ClearStencilValue); - - int stencilMask = 0; - - if (clearStencil) - { - stencilMask = state.Get(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; - - /// - /// Primitive topology of the current draw. - /// - public PrimitiveTopology Topology { get; private set; } - - /// - /// Finishes the draw call. - /// This draws geometry on the bound buffers based on the current GPU state. - /// - /// Current GPU state - /// Method call argument - private void DrawEnd(GpuState state, int argument) - { - var indexBuffer = state.Get(MethodOffset.IndexBufferState); - - DrawEnd(state, indexBuffer.First, indexBuffer.Count); - } - - /// - /// Finishes the draw call. - /// This draws geometry on the bound buffers based on the current GPU state. - /// - /// Current GPU state - /// Index of the first index buffer element used on the draw - /// Number of index buffer elements used on the draw - 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(MethodOffset.FirstVertex); - _instancedFirstInstance = state.Get(MethodOffset.FirstInstance); - - _instancedIndexCount = indexCount; - - var drawState = state.Get(MethodOffset.VertexBufferDrawState); - - _instancedDrawStateFirst = drawState.First; - _instancedDrawStateCount = drawState.Count; - - _drawIndexed = false; - - if (renderEnable == ConditionalRenderEnabled.Host) - { - _context.Renderer.Pipeline.EndHostConditionalRendering(); - } - - return; - } - - int firstInstance = state.Get(MethodOffset.FirstInstance); - - int inlineIndexCount = _ibStreamer.GetAndResetInlineIndexCount(); - - if (inlineIndexCount != 0) - { - int firstVertex = state.Get(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(MethodOffset.FirstVertex); - - _context.Renderer.Pipeline.DrawIndexed( - indexCount, - 1, - firstIndex, - firstVertex, - firstInstance); - } - else - { - var drawState = state.Get(MethodOffset.VertexBufferDrawState); - - _context.Renderer.Pipeline.Draw( - drawState.Count, - 1, - drawState.First, - firstInstance); - } - - _drawIndexed = false; - - if (renderEnable == ConditionalRenderEnabled.Host) - { - _context.Renderer.Pipeline.EndHostConditionalRendering(); - } - } - - /// - /// Starts draw. - /// This sets primitive type and instanced draw parameters. - /// - /// Current GPU state - /// Method call argument - 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(MethodOffset.PrimitiveTypeOverride); - - if (typeOverride != PrimitiveTypeOverride.Invalid) - { - DrawBegin(incrementInstance, resetInstance, typeOverride.Convert()); - } - else - { - DrawBegin(incrementInstance, resetInstance, type.Convert()); - } - } - - /// - /// Starts draw. - /// This sets primitive type and instanced draw parameters. - /// - /// Indicates if the current instance should be incremented - /// Indicates if the current instance should be set to zero - /// Primitive topology - 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; - } - - /// - /// Sets the index buffer count. - /// This also sets internal state that indicates that the next draw is an indexed draw. - /// - /// Current GPU state - /// Method call argument - private void SetIndexBufferCount(GpuState state, int argument) - { - _drawIndexed = true; - } - - /// - /// Performs a indexed draw with a low number of index buffer elements. - /// - /// Current GPU state - /// Method call argument - private void DrawIndexedSmall(GpuState state, int argument) - { - DrawIndexedSmall(state, argument, false); - } - - /// - /// Performs a indexed draw with a low number of index buffer elements. - /// - /// Current GPU state - /// Method call argument - private void DrawIndexedSmall2(GpuState state, int argument) - { - DrawIndexedSmall(state, argument); - } - - /// - /// Performs a indexed draw with a low number of index buffer elements, - /// while also pre-incrementing the current instance value. - /// - /// Current GPU state - /// Method call argument - private void DrawIndexedSmallIncInstance(GpuState state, int argument) - { - DrawIndexedSmall(state, argument, true); - } - - /// - /// Performs a indexed draw with a low number of index buffer elements, - /// while also pre-incrementing the current instance value. - /// - /// Current GPU state - /// Method call argument - private void DrawIndexedSmallIncInstance2(GpuState state, int argument) - { - DrawIndexedSmallIncInstance(state, argument); - } - - /// - /// Performs a indexed draw with a low number of index buffer elements, - /// while optionally also pre-incrementing the current instance value. - /// - /// Current GPU state - /// Method call argument - /// True to increment the current instance value, false otherwise - private void DrawIndexedSmall(GpuState state, int argument, bool instanced) - { - PrimitiveTypeOverride typeOverride = state.Get(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; - } - - /// - /// Pushes four 8-bit index buffer elements. - /// - /// Current GPU state - /// Method call argument - private void VbElementU8(GpuState state, int argument) - { - _ibStreamer.VbElementU8(_context.Renderer, argument); - } - - /// - /// Pushes two 16-bit index buffer elements. - /// - /// Current GPU state - /// Method call argument - private void VbElementU16(GpuState state, int argument) - { - _ibStreamer.VbElementU16(_context.Renderer, argument); - } - - /// - /// Pushes one 32-bit index buffer element. - /// - /// Current GPU state - /// Method call argument - private void VbElementU32(GpuState state, int argument) - { - _ibStreamer.VbElementU32(_context.Renderer, argument); - } - - /// - /// 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. - /// - 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 - { - /// - /// Performs an incrementation on a syncpoint. - /// - /// Current GPU state - /// Method call argument - 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; - - /// - /// Writes a GPU counter to guest memory. - /// - /// Current GPU state - /// Method call argument - 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; - } - } - - /// - /// Writes (or Releases) a GPU semaphore value to guest memory. - /// - /// Current GPU state - private void ReleaseSemaphore(GpuState state) - { - var rs = state.Get(MethodOffset.ReportState); - - state.Channel.MemoryManager.Write(rs.Address.Pack(), rs.Payload); - - _context.AdvanceSequence(); - } - - /// - /// Packed GPU counter data (including GPU timestamp) in memory. - /// - private struct CounterData - { - public ulong Counter; - public ulong Timestamp; - } - - /// - /// Writes a GPU counter to guest memory. - /// This also writes the current timestamp value. - /// - /// Current GPU state - /// Counter to be written to memory - private void ReportCounter(GpuState state, ReportCounterType type) - { - var rs = state.Get(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 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); - } - - /// - /// Converts a nanoseconds timestamp value to Maxwell time ticks. - /// - /// - /// The frequency is 614400000 Hz. - /// - /// Timestamp in nanoseconds - /// Maxwell ticks - 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 - { - /// - /// Resets the value of an internal GPU counter back to zero. - /// - /// Current GPU state - /// Method call argument - 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 - { - /// - /// Binds a uniform buffer for the vertex shader stage. - /// - /// Current GPU state - /// Method call argument - private void UniformBufferBindVertex(GpuState state, int argument) - { - UniformBufferBind(state, argument, ShaderType.Vertex); - } - - /// - /// Binds a uniform buffer for the tessellation control shader stage. - /// - /// Current GPU state - /// Method call argument - private void UniformBufferBindTessControl(GpuState state, int argument) - { - UniformBufferBind(state, argument, ShaderType.TessellationControl); - } - - /// - /// Binds a uniform buffer for the tessellation evaluation shader stage. - /// - /// Current GPU state - /// Method call argument - private void UniformBufferBindTessEvaluation(GpuState state, int argument) - { - UniformBufferBind(state, argument, ShaderType.TessellationEvaluation); - } - - /// - /// Binds a uniform buffer for the geometry shader stage. - /// - /// Current GPU state - /// Method call argument - private void UniformBufferBindGeometry(GpuState state, int argument) - { - UniformBufferBind(state, argument, ShaderType.Geometry); - } - - /// - /// Binds a uniform buffer for the fragment shader stage. - /// - /// Current GPU state - /// Method call argument - private void UniformBufferBindFragment(GpuState state, int argument) - { - UniformBufferBind(state, argument, ShaderType.Fragment); - } - - /// - ///Binds a uniform buffer for the specified shader stage. - /// - /// Current GPU state - /// Method call argument - /// Shader stage that will access the uniform buffer - 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(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; - - /// - /// Flushes any queued ubo updates. - /// - /// GPU memory manager where the uniform buffer is mapped - public void FlushUboDirty(MemoryManager memoryManager) - { - if (_ubFollowUpAddress != 0) - { - memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount); - - _ubFollowUpAddress = 0; - } - } - - /// - /// Updates the uniform buffer data with inline data. - /// - /// Current GPU state - /// New uniform buffer data word - private void UniformBufferUpdate(GpuState state, int argument) - { - var uniformBuffer = state.Get(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(MemoryMarshal.CreateSpan(ref argument, 1)); - state.Channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData); - - _ubFollowUpAddress = address + 4; - _ubByteCount += 4; - - state.SetUniformBufferOffset(uniformBuffer.Offset + 4); - } - - /// - /// Updates the uniform buffer data with inline data. - /// - /// Current GPU state - /// Data to be written to the uniform buffer - public void UniformBufferUpdate(GpuState state, ReadOnlySpan data) - { - var uniformBuffer = state.Get(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(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; - - /// - /// GPU method implementations. - /// - 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; - - /// - /// Creates a new instance of the GPU methods class. - /// - /// GPU context - public Methods(GpuContext context) - { - _context = context; - - _currentProgramInfo = new ShaderProgramInfo[Constants.ShaderStages]; - } - - /// - /// Register callback for GPU method calls that triggers an action on the GPU. - /// - /// GPU state where the triggers will be registered - 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); - } - - /// - /// Updates host state based on the current guest GPU state. - /// - /// Guest GPU state - /// Index of the first index buffer element used on the draw - /// Number of index buffer elements used on the draw - private void UpdateState(GpuState state, int firstIndex, int indexCount) - { - bool tfEnable = state.Get(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; - } - } - - /// - /// Updates Rasterizer primitive discard state based on guest gpu state. - /// - /// Current GPU state - private void UpdateRasterizerState(GpuState state) - { - Boolean32 enable = state.Get(MethodOffset.RasterizeEnable); - _context.Renderer.Pipeline.SetRasterizerDiscard(!enable); - } - - /// - /// Ensures that the bindings are visible to the host GPU. - /// Note: this actually performs the binding using the host graphics API. - /// - /// Current GPU state - private void CommitBindings(GpuState state) - { - UpdateStorageBuffers(state); - - state.Channel.TextureManager.CommitGraphicsBindings(); - state.Channel.BufferManager.CommitGraphicsBindings(); - } - - /// - /// Updates storage buffer bindings. - /// - /// Current GPU state - 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(sbDescAddress); - - state.Channel.BufferManager.SetGraphicsStorageBuffer(stage, sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size, sb.Flags); - } - } - } - - /// - /// Updates render targets (color and depth-stencil buffers) based on current render target state. - /// - /// Current GPU state - /// Use draw buffers information from render target control register - /// If this is not -1, it indicates that only the given indexed target will be used. - private void UpdateRenderTargetState(GpuState state, bool useControl, int singleUse = -1) - { - var memoryManager = state.Channel.MemoryManager; - var rtControl = state.Get(MethodOffset.RtControl); - - int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets; - - var msaaMode = state.Get(MethodOffset.RtMsaaMode); - - int samplesInX = msaaMode.SamplesInX(); - int samplesInY = msaaMode.SamplesInY(); - - var scissor = state.Get(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(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(MethodOffset.RtDepthStencilEnable); - - Texture depthStencil = null; - - if (dsEnable) - { - var dsState = state.Get(MethodOffset.RtDepthStencilState); - var dsSize = state.Get(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); - } - } - - /// - /// Checks if a render target color buffer is used. - /// - /// Color buffer information - /// True if the specified buffer is enabled/used, false otherwise - private static bool IsRtEnabled(RtColorState colorState) - { - // Colors are disabled by writing 0 to the format. - return colorState.Format != 0 && colorState.WidthOrStride != 0; - } - - /// - /// Updates host scissor test state based on current GPU state. - /// - /// Current GPU state - private void UpdateScissorState(GpuState state) - { - for (int index = 0; index < Constants.TotalViewports; index++) - { - ScissorState scissor = state.Get(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); - } - } - } - - /// - /// Updates host depth clamp state based on current GPU state. - /// - /// Current GPU state - private void UpdateDepthClampState(GpuState state) - { - ViewVolumeClipControl clip = state.Get(MethodOffset.ViewVolumeClipControl); - _context.Renderer.Pipeline.SetDepthClamp((clip & ViewVolumeClipControl.DepthClampDisabled) == 0); - } - - /// - /// Updates host alpha test state based on current GPU state. - /// - /// Current GPU state - private void UpdateAlphaTestState(GpuState state) - { - _context.Renderer.Pipeline.SetAlphaTest( - state.Get(MethodOffset.AlphaTestEnable), - state.Get(MethodOffset.AlphaTestRef), - state.Get(MethodOffset.AlphaTestFunc)); - } - - /// - /// Updates host depth test state based on current GPU state. - /// - /// Current GPU state - private void UpdateDepthTestState(GpuState state) - { - _context.Renderer.Pipeline.SetDepthTest(new DepthTestDescriptor( - state.Get(MethodOffset.DepthTestEnable), - state.Get(MethodOffset.DepthWriteEnable), - state.Get(MethodOffset.DepthTestFunc))); - } - - /// - /// Updates host viewport transform and clipping state based on current GPU state. - /// - /// Current GPU state - private void UpdateViewportTransform(GpuState state) - { - var yControl = state.Get (MethodOffset.YControl); - var face = state.Get(MethodOffset.FaceState); - - UpdateFrontFace(yControl, face.FrontFace); - - bool flipY = yControl.HasFlag(YControl.NegateY); - - Span viewports = stackalloc Viewport[Constants.TotalViewports]; - - for (int index = 0; index < Constants.TotalViewports; index++) - { - var transform = state.Get(MethodOffset.ViewportTransform, index); - var extents = state.Get (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); - } - - /// - /// Updates host depth bias (also called polygon offset) state based on current GPU state. - /// - /// Current GPU state - private void UpdateDepthBiasState(GpuState state) - { - var depthBias = state.Get(MethodOffset.DepthBiasState); - - float factor = state.Get(MethodOffset.DepthBiasFactor); - float units = state.Get(MethodOffset.DepthBiasUnits); - float clamp = state.Get(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); - } - - /// - /// Updates host stencil test state based on current GPU state. - /// - /// Current GPU state - private void UpdateStencilTestState(GpuState state) - { - var backMasks = state.Get(MethodOffset.StencilBackMasks); - var test = state.Get(MethodOffset.StencilTestState); - var backTest = state.Get(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)); - } - - /// - /// Updates current sampler pool address and size based on guest GPU state. - /// - /// Current GPU state - private void UpdateSamplerPoolState(GpuState state) - { - var texturePool = state.Get(MethodOffset.TexturePoolState); - var samplerPool = state.Get(MethodOffset.SamplerPoolState); - - var samplerIndex = state.Get(MethodOffset.SamplerIndex); - - int maximumId = samplerIndex == SamplerIndex.ViaHeaderIndex - ? texturePool.MaximumId - : samplerPool.MaximumId; - - state.Channel.TextureManager.SetGraphicsSamplerPool(samplerPool.Address.Pack(), maximumId, samplerIndex); - } - - /// - /// Updates current texture pool address and size based on guest GPU state. - /// - /// Current GPU state - private void UpdateTexturePoolState(GpuState state) - { - var texturePool = state.Get(MethodOffset.TexturePoolState); - - state.Channel.TextureManager.SetGraphicsTexturePool(texturePool.Address.Pack(), texturePool.MaximumId); - state.Channel.TextureManager.SetGraphicsTextureBufferIndex(state.Get(MethodOffset.TextureBufferIndex)); - } - - /// - /// Updates host vertex attributes based on guest GPU state. - /// - /// Current GPU state - private void UpdateVertexAttribState(GpuState state) - { - Span vertexAttribs = stackalloc VertexAttribDescriptor[Constants.TotalVertexAttribs]; - - for (int index = 0; index < Constants.TotalVertexAttribs; index++) - { - var vertexAttrib = state.Get(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); - } - - /// - /// Updates host line width based on guest GPU state. - /// - /// Current GPU state - private void UpdateLineState(GpuState state) - { - float width = state.Get(MethodOffset.LineWidthSmooth); - bool smooth = state.Get(MethodOffset.LineSmoothEnable); - - _context.Renderer.Pipeline.SetLineParameters(width, smooth); - } - - /// - /// Updates host point size based on guest GPU state. - /// - /// Current GPU state - private void UpdatePointState(GpuState state) - { - float size = state.Get(MethodOffset.PointSize); - bool isProgramPointSize = state.Get(MethodOffset.VertexProgramPointSize); - bool enablePointSprite = state.Get(MethodOffset.PointSpriteEnable); - - // TODO: Need to figure out a way to map PointCoordReplace enable bit. - Origin origin = (state.Get(MethodOffset.PointCoordReplace) & 4) == 0 ? Origin.LowerLeft : Origin.UpperLeft; - - _context.Renderer.Pipeline.SetPointParameters(size, isProgramPointSize, enablePointSprite, origin); - } - - /// - /// Updates host primitive restart based on guest GPU state. - /// - /// Current GPU state - private void UpdatePrimitiveRestartState(GpuState state) - { - PrimitiveRestartState primitiveRestart = state.Get(MethodOffset.PrimitiveRestartState); - - _context.Renderer.Pipeline.SetPrimitiveRestart( - primitiveRestart.Enable, - primitiveRestart.Index); - } - - /// - /// Updates host index buffer binding based on guest GPU state. - /// - /// Current GPU state - /// Index of the first index buffer element used on the draw - /// Number of index buffer elements used on the draw - private void UpdateIndexBufferState(GpuState state, int firstIndex, int indexCount) - { - var indexBuffer = state.Get(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); - } - - /// - /// Updates host vertex buffer bindings based on guest GPU state. - /// - /// Current GPU state - private void UpdateVertexBufferState(GpuState state) - { - _isAnyVbInstanced = false; - - for (int index = 0; index < Constants.TotalVertexBuffers; index++) - { - var vertexBuffer = state.Get(MethodOffset.VertexBufferState, index); - - if (!vertexBuffer.UnpackEnable()) - { - state.Channel.BufferManager.SetVertexBuffer(index, 0, 0, 0, 0); - - continue; - } - - GpuVa endAddress = state.Get(MethodOffset.VertexBufferEndAddress, index); - - ulong address = vertexBuffer.Address.Pack(); - - int stride = vertexBuffer.UnpackStride(); - - bool instanced = state.Get(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(MethodOffset.FirstInstance); - - var drawState = state.Get(MethodOffset.VertexBufferDrawState); - - size = (ulong)((firstInstance + drawState.First + drawState.Count) * stride); - } - - state.Channel.BufferManager.SetVertexBuffer(index, address, size, stride, divisor); - } - } - - /// - /// Updates host face culling and orientation based on guest GPU state. - /// - /// Current GPU state - private void UpdateFaceState(GpuState state) - { - var yControl = state.Get (MethodOffset.YControl); - var face = state.Get(MethodOffset.FaceState); - - _context.Renderer.Pipeline.SetFaceCulling(face.CullEnable, face.CullFace); - - UpdateFrontFace(yControl, face.FrontFace); - } - - /// - /// Updates the front face based on the current front face and the origin. - /// - /// Y control register value, where the origin is located - /// Front face - 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); - } - - /// - /// Updates host render target color masks, based on guest GPU state. - /// This defines which color channels are written to each color buffer. - /// - /// Current GPU state - private void UpdateRtColorMask(GpuState state) - { - bool rtColorMaskShared = state.Get(MethodOffset.RtColorMaskShared); - - Span componentMasks = stackalloc uint[Constants.TotalRenderTargets]; - - for (int index = 0; index < Constants.TotalRenderTargets; index++) - { - var colorMask = state.Get(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); - } - - /// - /// Updates host render target color buffer blending state, based on guest state. - /// - /// Current GPU state - private void UpdateBlendState(GpuState state) - { - bool blendIndependent = state.Get(MethodOffset.BlendIndependent); - ColorF blendConstant = state.Get(MethodOffset.BlendConstant); - - for (int index = 0; index < Constants.TotalRenderTargets; index++) - { - BlendDescriptor descriptor; - - if (blendIndependent) - { - bool enable = state.Get (MethodOffset.BlendEnable, index); - var blend = state.Get(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 (MethodOffset.BlendEnable, 0); - var blend = state.Get(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); - } - } - - /// - /// Updates host logical operation state, based on guest state. - /// - /// Current GPU state - public void UpdateLogicOpState(GpuState state) - { - LogicalOpState logicOpState = state.Get(MethodOffset.LogicOpState); - - _context.Renderer.Pipeline.SetLogicOpState(logicOpState.Enable, logicOpState.LogicalOp); - } - - /// - /// Updates host shaders based on the guest GPU state. - /// - /// Current GPU state - private void UpdateShaderState(GpuState state) - { - ShaderAddresses addresses = new ShaderAddresses(); - - Span addressesSpan = MemoryMarshal.CreateSpan(ref addresses, 1); - - Span addressesArray = MemoryMarshal.Cast(addressesSpan); - - ulong baseAddress = state.Get(MethodOffset.ShaderBaseAddress).Pack(); - - for (int index = 0; index < 6; index++) - { - var shader = state.Get(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()); - state.Channel.TextureManager.SetGraphicsImages(stage, Array.Empty()); - 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); - } - - /// - /// Forces the shaders to be rebound on the next draw. - /// - public void ForceShaderUpdate() - { - _forceShaderUpdate = true; - } - - /// - /// Updates transform feedback buffer state based on the guest GPU state. - /// - /// Current GPU state - private void UpdateTfBufferState(GpuState state) - { - for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++) - { - TfBufferState tfb = state.Get(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); - } - } - - /// - /// Updates user-defined clipping based on the guest GPU state. - /// - /// Current GPU state - private void UpdateUserClipState(GpuState state) - { - int clipMask = state.Get(MethodOffset.ClipDistanceEnable) & _vsClipDistancesWritten; - - for (int i = 0; i < Constants.TotalClipDistances; ++i) - { - _context.Renderer.Pipeline.SetUserClipDistance(i, (clipMask & (1 << i)) != 0); - } - } - - /// - /// Issues a texture barrier. - /// This waits until previous texture writes from the GPU to finish, before - /// performing new operations with said textures. - /// - /// Current GPU state (unused) - /// Method call argument (unused) - private void TextureBarrier(GpuState state, int argument) - { - _context.Renderer.Pipeline.TextureBarrier(); - } - - /// - /// 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. - /// - /// Current GPU state (unused) - /// Method call argument (unused) - 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 { + /// + /// Represents temporary storage used by macros. + /// [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 +{ + /// + /// MME shadow RAM control mode. + /// + 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 similarity index 56% rename from Ryujinx.Graphics.Gpu/Engine/MethodConditionalRendering.cs rename to 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 + /// + /// Helper methods used for conditional rendering. + /// + static class ConditionalRendering { /// /// Checks if draws and clears should be performed, according /// to currently set conditional rendering conditions. /// - /// GPU state + /// GPU context + /// Memory manager bound to the channel currently executing + /// Conditional rendering buffer address + /// Conditional rendering condition /// True if rendering is enabled, false otherwise - private ConditionalRenderEnabled GetRenderEnable(GpuState state) + public static ConditionalRenderEnabled GetRenderEnable(GpuContext context, MemoryManager memoryManager, GpuVa address, Condition condition) { - ConditionState condState = state.Get(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 /// /// Checks if the counter value at a given GPU memory address is non-zero. /// - /// GPU state + /// GPU context + /// Memory manager bound to the channel currently executing /// GPU virtual address of the counter value /// True if the value is not zero, false otherwise. Returns host if handling with host conditional rendering - 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(gpuVa) != 0) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False; + return (memoryManager.Read(gpuVa) != 0) ? ConditionalRenderEnabled.True : ConditionalRenderEnabled.False; } } /// /// Checks if the counter at a given GPU memory address passes a specified equality comparison. /// - /// GPU state + /// GPU context + /// Memory manager bound to the channel currently executing /// GPU virtual address /// True to check if the values are equal, false to check if they are not equal /// True if the condition is met, false otherwise. Returns host if handling with host conditional rendering - 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(gpuVa + 16), isEqual); + useHost = context.Renderer.Pipeline.TryHostConditionalRendering(evt, memoryManager.Read(gpuVa + 16), isEqual); } else if (evt == null && evt2 != null) { - useHost = _context.Renderer.Pipeline.TryHostConditionalRendering(evt2, state.Channel.MemoryManager.Read(gpuVa), isEqual); + useHost = context.Renderer.Pipeline.TryHostConditionalRendering(evt2, memoryManager.Read(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(gpuVa); - ulong y = state.Channel.MemoryManager.Read(gpuVa + 16); + ulong x = memoryManager.Read(gpuVa); + ulong y = memoryManager.Read(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 +{ + /// + /// Constant buffer updater. + /// + class ConstantBufferUpdater + { + private readonly GpuChannel _channel; + private readonly DeviceStateWithShadow _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; + + /// + /// Creates a new instance of the constant buffer updater. + /// + /// GPU channel + /// Channel state + public ConstantBufferUpdater(GpuChannel channel, DeviceStateWithShadow state) + { + _channel = channel; + _state = state; + } + + /// + /// Binds a uniform buffer for the vertex shader stage. + /// + /// Method call argument + public void BindVertex(int argument) + { + Bind(argument, ShaderType.Vertex); + } + + /// + /// Binds a uniform buffer for the tessellation control shader stage. + /// + /// Method call argument + public void BindTessControl(int argument) + { + Bind(argument, ShaderType.TessellationControl); + } + + /// + /// Binds a uniform buffer for the tessellation evaluation shader stage. + /// + /// Method call argument + public void BindTessEvaluation(int argument) + { + Bind(argument, ShaderType.TessellationEvaluation); + } + + /// + /// Binds a uniform buffer for the geometry shader stage. + /// + /// Method call argument + public void BindGeometry(int argument) + { + Bind(argument, ShaderType.Geometry); + } + + /// + /// Binds a uniform buffer for the fragment shader stage. + /// + /// Method call argument + public void BindFragment(int argument) + { + Bind(argument, ShaderType.Fragment); + } + + /// + /// Binds a uniform buffer for the specified shader stage. + /// + /// Method call argument + /// Shader stage that will access the uniform buffer + 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); + } + } + + /// + /// Flushes any queued UBO updates. + /// + public void FlushUboDirty() + { + if (_ubFollowUpAddress != 0) + { + var memoryManager = _channel.MemoryManager; + memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount); + + _ubFollowUpAddress = 0; + } + } + + /// + /// Updates the uniform buffer data with inline data. + /// + /// New uniform buffer data word + 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(MemoryMarshal.CreateSpan(ref argument, 1)); + _channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData); + + _ubFollowUpAddress = address + 4; + _ubByteCount += 4; + + _state.State.UniformBufferState.Offset += 4; + } + + /// + /// Updates the uniform buffer data with inline data. + /// + /// Data to be written to the uniform buffer + public void Update(ReadOnlySpan 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(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 +{ + /// + /// Draw manager. + /// + class DrawManager + { + private readonly GpuContext _context; + private readonly GpuChannel _channel; + private readonly DeviceStateWithShadow _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; + + /// + /// Creates a new instance of the draw manager. + /// + /// GPU context + /// GPU channel + /// Channel state + /// Draw state + public DrawManager(GpuContext context, GpuChannel channel, DeviceStateWithShadow state, DrawState drawState) + { + _context = context; + _channel = channel; + _state = state; + _drawState = drawState; + } + + /// + /// Pushes four 8-bit index buffer elements. + /// + /// Method call argument + public void VbElementU8(int argument) + { + _drawState.IbStreamer.VbElementU8(_context.Renderer, argument); + } + + /// + /// Pushes two 16-bit index buffer elements. + /// + /// Method call argument + public void VbElementU16(int argument) + { + _drawState.IbStreamer.VbElementU16(_context.Renderer, argument); + } + + /// + /// Pushes one 32-bit index buffer element. + /// + /// Method call argument + public void VbElementU32(int argument) + { + _drawState.IbStreamer.VbElementU32(_context.Renderer, argument); + } + + /// + /// Finishes the draw call. + /// This draws geometry on the bound buffers based on the current GPU state. + /// + /// 3D engine where this method is being called + /// Method call argument + public void DrawEnd(ThreedClass engine, int argument) + { + DrawEnd(engine, _state.State.IndexBufferState.First, (int)_state.State.IndexBufferCount); + } + + /// + /// Finishes the draw call. + /// This draws geometry on the bound buffers based on the current GPU state. + /// + /// 3D engine where this method is being called + /// Index of the first index buffer element used on the draw + /// Number of index buffer elements used on the draw + 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(); + } + } + + /// + /// Starts draw. + /// This sets primitive type and instanced draw parameters. + /// + /// Method call argument + 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()); + } + } + + /// + /// Starts draw. + /// This sets primitive type and instanced draw parameters. + /// + /// Indicates if the current instance should be incremented + /// Indicates if the current instance should be set to zero + /// Primitive topology + 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; + } + + /// + /// Sets the index buffer count. + /// This also sets internal state that indicates that the next draw is an indexed draw. + /// + /// Method call argument + public void SetIndexBufferCount(int argument) + { + _drawState.DrawIndexed = true; + } + + /// + /// Performs a indexed draw with a low number of index buffer elements. + /// + /// 3D engine where this method is being called + /// Method call argument + public void DrawIndexedSmall(ThreedClass engine, int argument) + { + DrawIndexedSmall(engine, argument, false); + } + + /// + /// Performs a indexed draw with a low number of index buffer elements. + /// + /// 3D engine where this method is being called + /// Method call argument + public void DrawIndexedSmall2(ThreedClass engine, int argument) + { + DrawIndexedSmall(engine, argument); + } + + /// + /// Performs a indexed draw with a low number of index buffer elements, + /// while also pre-incrementing the current instance value. + /// + /// 3D engine where this method is being called + /// Method call argument + public void DrawIndexedSmallIncInstance(ThreedClass engine, int argument) + { + DrawIndexedSmall(engine, argument, true); + } + + /// + /// Performs a indexed draw with a low number of index buffer elements, + /// while also pre-incrementing the current instance value. + /// + /// 3D engine where this method is being called + /// Method call argument + public void DrawIndexedSmallIncInstance2(ThreedClass engine, int argument) + { + DrawIndexedSmallIncInstance(engine, argument); + } + + /// + /// Performs a indexed draw with a low number of index buffer elements, + /// while optionally also pre-incrementing the current instance value. + /// + /// 3D engine where this method is being called + /// Method call argument + /// True to increment the current instance value, false otherwise + 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; + } + + /// + /// 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. + /// + 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); + } + } + } + + /// + /// Clears the current color and depth-stencil buffers. + /// Which buffers should be cleared is also specified on the argument. + /// + /// 3D engine where this method is being called + /// Method call argument + 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 +{ + /// + /// Draw state. + /// + class DrawState + { + /// + /// First index to be used for the draw on the index buffer. + /// + public int FirstIndex; + + /// + /// Number of indices to be used for the draw on the index buffer. + /// + public int IndexCount; + + /// + /// Indicates if the next draw will be a indexed draw. + /// + public bool DrawIndexed; + + /// + /// Indicates if any of the currently used vertex shaders reads the instance ID. + /// + public bool VsUsesInstanceId; + + /// + /// Indicates if any of the currently used vertex buffers is instanced. + /// + public bool IsAnyVbInstanced; + + /// + /// Primitive topology for the next draw. + /// + public PrimitiveTopology Topology; + + /// + /// Index buffer data streamer for inline index buffer updates, such as those used in legacy OpenGL. + /// + public IbStreamer IbStreamer = new IbStreamer(); + } +} diff --git a/Ryujinx.Graphics.Gpu/Engine/IbStreamer.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/IbStreamer.cs similarity index 96% rename from Ryujinx.Graphics.Gpu/Engine/IbStreamer.cs rename to 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 { /// /// Holds inline index buffer state. @@ -15,6 +15,9 @@ namespace Ryujinx.Graphics.Gpu.Engine private int _inlineIndexBufferSize; private int _inlineIndexCount; + /// + /// Indicates if any index buffer data has been pushed. + /// public bool HasInlineIndexData => _inlineIndexCount != 0; /// 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 +{ + /// + /// Semaphore updater. + /// + class SemaphoreUpdater + { + private const int NsToTicksFractionNumerator = 384; + private const int NsToTicksFractionDenominator = 625; + + /// + /// GPU semaphore operation. + /// + private enum SemaphoreOperation + { + Release = 0, + Acquire = 1, + Counter = 2 + } + + /// + /// Counter type for GPU counter reset. + /// + 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 + } + + /// + /// Counter type for GPU counter reporting. + /// + 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 _state; + + /// + /// Creates a new instance of the semaphore updater. + /// + /// GPU context + /// GPU channel + /// Channel state + public SemaphoreUpdater(GpuContext context, GpuChannel channel, DeviceStateWithShadow state) + { + _context = context; + _channel = channel; + _state = state; + } + + /// + /// Resets the value of an internal GPU counter back to zero. + /// + /// Method call argument + 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; + } + } + + /// + /// Writes a GPU counter to guest memory. + /// + /// Method call argument + 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; + } + } + + /// + /// Writes (or Releases) a GPU semaphore value to guest memory. + /// + private void ReleaseSemaphore() + { + _channel.MemoryManager.Write(_state.State.SemaphoreAddress.Pack(), _state.State.SemaphorePayload); + + _context.AdvanceSequence(); + } + + /// + /// Packed GPU counter data (including GPU timestamp) in memory. + /// + private struct CounterData + { + public ulong Counter; + public ulong Timestamp; + } + + /// + /// Writes a GPU counter to guest memory. + /// This also writes the current timestamp value. + /// + /// Counter to be written to memory + 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); + } + + /// + /// Converts a nanoseconds timestamp value to Maxwell time ticks. + /// + /// + /// The frequency is 614400000 Hz. + /// + /// Timestamp in nanoseconds + /// Maxwell ticks + 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 +{ + /// + /// State update callback entry, with the callback function and associated field names. + /// + struct StateUpdateCallbackEntry + { + /// + /// Callback function, to be called if the register was written as the state needs to be updated. + /// + public Action Callback { get; } + + /// + /// Name of the state fields (registers) associated with the callback function. + /// + public string[] FieldNames { get; } + + /// + /// Creates a new state update callback entry. + /// + /// Callback function, to be called if the register was written as the state needs to be updated + /// Name of the state fields (registers) associated with the callback function + public StateUpdateCallbackEntry(Action callback, params string[] fieldNames) + { + Callback = callback; + FieldNames = fieldNames; + } + } + + /// + /// GPU state update tracker. + /// + /// State type + class StateUpdateTracker + { + private const int BlockSize = 0xe00; + private const int RegisterSize = sizeof(uint); + + private readonly byte[] _registerToGroupMapping; + private readonly Action[] _callbacks; + private ulong _dirtyMask; + + /// + /// Creates a new instance of the state update tracker. + /// + /// Update tracker callback entries + public StateUpdateTracker(StateUpdateCallbackEntry[] entries) + { + _registerToGroupMapping = new byte[BlockSize]; + _callbacks = new Action[entries.Length]; + + var fieldToDelegate = new Dictionary(); + + 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()); + } + + /// + /// Sets a register as modified. + /// + /// Register offset in bytes + [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; + } + } + } + + /// + /// Forces a register group as dirty, by index. + /// + /// Index of the group to be dirtied + public void ForceDirty(int groupIndex) + { + if ((uint)groupIndex >= _callbacks.Length) + { + throw new ArgumentOutOfRangeException(nameof(groupIndex)); + } + + _dirtyMask |= 1UL << groupIndex; + } + + /// + /// Forces all register groups as dirty, triggering a full update on the next call to . + /// + public void SetAllDirty() + { + Debug.Assert(_callbacks.Length <= sizeof(ulong) * 8); + _dirtyMask = ulong.MaxValue >> ((sizeof(ulong) * 8) - _callbacks.Length); + } + + /// + /// Check all the groups specified by for modification, and update if modified. + /// + /// Mask, where each bit set corresponds to a group index that should be checked + [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 +{ + /// + /// GPU state updater. + /// + 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 _state; + private readonly DrawState _drawState; + + private readonly StateUpdateTracker _updateTracker; + + private readonly ShaderProgramInfo[] _currentProgramInfo; + + private byte _vsClipDistancesWritten; + + private bool _prevDrawIndexed; + private bool _prevTfEnable; + + /// + /// Creates a new instance of the state updater. + /// + /// GPU context + /// GPU channel + /// 3D engine state + /// Draw state + public StateUpdater(GpuContext context, GpuChannel channel, DeviceStateWithShadow 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(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)) + }); + } + + /// + /// Sets a register at a specific offset as dirty. + /// This must be called if the register value was modified. + /// + /// Register offset + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetDirty(int offset) + { + _updateTracker.SetDirty(offset); + } + + /// + /// Force all the guest state to be marked as dirty. + /// The next call to will update all the host state. + /// + public void SetAllDirty() + { + _updateTracker.SetAllDirty(); + } + + /// + /// Updates host state for any modified guest state, since the last time this function was called. + /// + [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; + } + } + + /// + /// Updates the host state for any modified guest state group with the respective bit set on . + /// + /// Mask, where each bit set corresponds to a group index that should be checked and updated + public void Update(ulong mask) + { + _updateTracker.Update(mask); + } + + /// + /// Ensures that the bindings are visible to the host GPU. + /// Note: this actually performs the binding using the host graphics API. + /// + private void CommitBindings() + { + UpdateStorageBuffers(); + + _channel.TextureManager.CommitGraphicsBindings(); + _channel.BufferManager.CommitGraphicsBindings(); + } + + /// + /// Updates storage buffer bindings. + /// + 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(sbDescAddress); + + _channel.BufferManager.SetGraphicsStorageBuffer(stage, sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size, sb.Flags); + } + } + } + + /// + /// Updates transform feedback buffer state based on the guest GPU state. + /// + 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); + } + } + + /// + /// Updates Rasterizer primitive discard state based on guest gpu state. + /// + private void UpdateRasterizerState() + { + bool enable = _state.State.RasterizeEnable; + _context.Renderer.Pipeline.SetRasterizerDiscard(!enable); + } + + /// + /// Updates render targets (color and depth-stencil buffers) based on current render target state. + /// + private void UpdateRenderTargetState() + { + UpdateRenderTargetState(true); + } + + /// + /// Updates render targets (color and depth-stencil buffers) based on current render target state. + /// + /// Use draw buffers information from render target control register + /// If this is not -1, it indicates that only the given indexed target will be used. + 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(); + } + } + + /// + /// Checks if a render target color buffer is used. + /// + /// Color buffer information + /// True if the specified buffer is enabled/used, false otherwise + private static bool IsRtEnabled(RtColorState colorState) + { + // Colors are disabled by writing 0 to the format. + return colorState.Format != 0 && colorState.WidthOrStride != 0; + } + + /// + /// Updates host scissor test state based on current GPU state. + /// + 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); + } + } + } + + /// + /// Updates host depth clamp state based on current GPU state. + /// + /// Current GPU state + private void UpdateDepthClampState() + { + ViewVolumeClipControl clip = _state.State.ViewVolumeClipControl; + _context.Renderer.Pipeline.SetDepthClamp((clip & ViewVolumeClipControl.DepthClampDisabled) == 0); + } + + /// + /// Updates host alpha test state based on current GPU state. + /// + private void UpdateAlphaTestState() + { + _context.Renderer.Pipeline.SetAlphaTest( + _state.State.AlphaTestEnable, + _state.State.AlphaTestRef, + _state.State.AlphaTestFunc); + } + + /// + /// Updates host depth test state based on current GPU state. + /// + private void UpdateDepthTestState() + { + _context.Renderer.Pipeline.SetDepthTest(new DepthTestDescriptor( + _state.State.DepthTestEnable, + _state.State.DepthWriteEnable, + _state.State.DepthTestFunc)); + } + + /// + /// Updates host viewport transform and clipping state based on current GPU state. + /// + private void UpdateViewportTransform() + { + var yControl = _state.State.YControl; + var face = _state.State.FaceState; + + UpdateFrontFace(yControl, face.FrontFace); + + bool flipY = yControl.HasFlag(YControl.NegateY); + + Span 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); + } + + /// + /// Updates host depth bias (also called polygon offset) state based on current GPU state. + /// + 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); + } + + /// + /// Updates host stencil test state based on current GPU state. + /// + 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)); + } + + /// + /// Updates user-defined clipping based on the guest GPU state. + /// + 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); + } + } + + /// + /// Updates current sampler pool address and size based on guest GPU state. + /// + 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); + } + + /// + /// Updates current texture pool address and size based on guest GPU state. + /// + private void UpdateTexturePoolState() + { + var texturePool = _state.State.TexturePoolState; + + _channel.TextureManager.SetGraphicsTexturePool(texturePool.Address.Pack(), texturePool.MaximumId); + _channel.TextureManager.SetGraphicsTextureBufferIndex((int)_state.State.TextureBufferIndex); + } + + /// + /// Updates host vertex attributes based on guest GPU state. + /// + private void UpdateVertexAttribState() + { + Span 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); + } + + /// + /// Updates host line width based on guest GPU state. + /// + private void UpdateLineState() + { + float width = _state.State.LineWidthSmooth; + bool smooth = _state.State.LineSmoothEnable; + + _context.Renderer.Pipeline.SetLineParameters(width, smooth); + } + + /// + /// Updates host point size based on guest GPU state. + /// + 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); + } + + /// + /// Updates host primitive restart based on guest GPU state. + /// + private void UpdatePrimitiveRestartState() + { + PrimitiveRestartState primitiveRestart = _state.State.PrimitiveRestartState; + + _context.Renderer.Pipeline.SetPrimitiveRestart(primitiveRestart.Enable, primitiveRestart.Index); + } + + /// + /// Updates host index buffer binding based on guest GPU state. + /// + 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); + } + + /// + /// Updates host vertex buffer bindings based on guest GPU state. + /// + 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); + } + } + + /// + /// Updates host face culling and orientation based on guest GPU state. + /// + 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); + } + + /// + /// Updates the front face based on the current front face and the origin. + /// + /// Y control register value, where the origin is located + /// Front face + 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); + } + + /// + /// Updates host render target color masks, based on guest GPU state. + /// This defines which color channels are written to each color buffer. + /// + private void UpdateRtColorMask() + { + bool rtColorMaskShared = _state.State.RtColorMaskShared; + + Span 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); + } + + /// + /// Updates host render target color buffer blending state, based on guest state. + /// + 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); + } + } + + /// + /// Updates host logical operation state, based on guest state. + /// + private void UpdateLogicOpState() + { + LogicalOpState logicOpState = _state.State.LogicOpState; + + _context.Renderer.Pipeline.SetLogicOpState(logicOpState.Enable, logicOpState.LogicalOp); + } + + /// + /// Updates host shaders based on the guest GPU state. + /// + private void UpdateShaderState() + { + ShaderAddresses addresses = new ShaderAddresses(); + + Span addressesSpan = MemoryMarshal.CreateSpan(ref addresses, 1); + + Span addressesArray = MemoryMarshal.Cast(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()); + _channel.TextureManager.SetGraphicsImages(stage, Array.Empty()); + _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); + } + + /// + /// Forces the shaders to be rebound on the next draw. + /// + 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 +{ + /// + /// Represents a 3D engine class. + /// + class ThreedClass : IDeviceState + { + private readonly GpuContext _context; + private readonly DeviceStateWithShadow _state; + + private readonly InlineToMemoryClass _i2mClass; + private readonly DrawManager _drawManager; + private readonly SemaphoreUpdater _semaphoreUpdater; + private readonly ConstantBufferUpdater _cbUpdater; + private readonly StateUpdater _stateUpdater; + + /// + /// Creates a new instance of the 3D engine class. + /// + /// GPU context + /// GPU channel + public ThreedClass(GpuContext context, GpuChannel channel) + { + _context = context; + _state = new DeviceStateWithShadow(new Dictionary + { + { 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; + } + + /// + /// Reads data from the class registers. + /// + /// Register byte offset + /// Data at the specified offset + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Read(int offset) => _state.Read(offset); + + /// + /// Writes data to the class registers. + /// + /// Register byte offset + /// Data to be written + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(int offset, int data) + { + _state.WriteWithRedundancyCheck(offset, data, out bool valueChanged); + + if (valueChanged) + { + _stateUpdater.SetDirty(offset); + } + } + + /// + /// Sets the shadow ram control value of all sub-channels. + /// + /// New shadow ram control value + public void SetShadowRamControl(int control) + { + _state.State.SetMmeShadowRamControl = (uint)control; + } + + /// + /// Updates current host state for all registers modified since the last call to this method. + /// + public void UpdateState() + { + _cbUpdater.FlushUboDirty(); + _stateUpdater.Update(); + } + + /// + /// Updates current host state for all registers modified since the last call to this method. + /// + /// Mask where each bit set indicates that the respective state group index should be checked + public void UpdateState(ulong mask) + { + _stateUpdater.Update(mask); + } + + /// + /// Updates render targets (color and depth-stencil buffers) based on current render target state. + /// + /// Use draw buffers information from render target control register + /// If this is not -1, it indicates that only the given indexed target will be used. + public void UpdateRenderTargetState(bool useControl, int singleUse = -1) + { + _stateUpdater.UpdateRenderTargetState(useControl, singleUse); + } + + /// + /// Marks the entire state as dirty, forcing a full host state update before the next draw. + /// + public void ForceStateDirty() + { + _stateUpdater.SetAllDirty(); + } + + /// + /// Forces the shaders to be rebound on the next draw. + /// + public void ForceShaderUpdate() + { + _stateUpdater.ForceShaderUpdate(); + } + + /// + /// Flushes any queued UBO updates. + /// + public void FlushUboDirty() + { + _cbUpdater.FlushUboDirty(); + } + + /// + /// Perform any deferred draws. + /// + public void PerformDeferredDraws() + { + _drawManager.PerformDeferredDraws(); + } + + /// + /// Updates the currently bound constant buffer. + /// + /// Data to be written to the buffer + public void ConstantBufferUpdate(ReadOnlySpan data) + { + _cbUpdater.Update(data); + } + + /// + /// Launches the Inline-to-Memory DMA copy operation. + /// + /// Method call argument + private void LaunchDma(int argument) + { + _i2mClass.LaunchDma(ref Unsafe.As(ref _state.State), argument); + } + + /// + /// Pushes a word of data to the Inline-to-Memory engine. + /// + /// Method call argument + private void LoadInlineData(int argument) + { + _i2mClass.LoadInlineData(argument); + } + + /// + /// Performs an incrementation on a syncpoint. + /// + /// Method call argument + 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); + } + + /// + /// Issues a texture barrier. + /// This waits until previous texture writes from the GPU to finish, before + /// performing new operations with said textures. + /// + /// Method call argument (unused) + private void TextureBarrier(int argument) + { + _context.Renderer.Pipeline.TextureBarrier(); + } + + /// + /// 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. + /// + /// Method call argument (unused) + private void TextureBarrierTiled(int argument) + { + _context.Renderer.Pipeline.TextureBarrierTiled(); + } + + /// + /// Pushes four 8-bit index buffer elements. + /// + /// Method call argument + private void VbElementU8(int argument) + { + _drawManager.VbElementU8(argument); + } + + /// + /// Pushes two 16-bit index buffer elements. + /// + /// Method call argument + private void VbElementU16(int argument) + { + _drawManager.VbElementU16(argument); + } + + /// + /// Pushes one 32-bit index buffer element. + /// + /// Method call argument + private void VbElementU32(int argument) + { + _drawManager.VbElementU32(argument); + } + + /// + /// Resets the value of an internal GPU counter back to zero. + /// + /// Method call argument + private void ResetCounter(int argument) + { + _semaphoreUpdater.ResetCounter(argument); + } + + /// + /// Finishes the draw call. + /// This draws geometry on the bound buffers based on the current GPU state. + /// + /// Method call argument + private void DrawEnd(int argument) + { + _drawManager.DrawEnd(this, argument); + } + + /// + /// Starts draw. + /// This sets primitive type and instanced draw parameters. + /// + /// Method call argument + private void DrawBegin(int argument) + { + _drawManager.DrawBegin(argument); + } + + /// + /// Sets the index buffer count. + /// This also sets internal state that indicates that the next draw is an indexed draw. + /// + /// Method call argument + private void SetIndexBufferCount(int argument) + { + _drawManager.SetIndexBufferCount(argument); + } + + /// + /// Performs a indexed draw with a low number of index buffer elements. + /// + /// Method call argument + private void DrawIndexedSmall(int argument) + { + _drawManager.DrawIndexedSmall(this, argument); + } + + /// + /// Performs a indexed draw with a low number of index buffer elements. + /// + /// Method call argument + private void DrawIndexedSmall2(int argument) + { + _drawManager.DrawIndexedSmall2(this, argument); + } + + /// + /// Performs a indexed draw with a low number of index buffer elements, + /// while also pre-incrementing the current instance value. + /// + /// Method call argument + private void DrawIndexedSmallIncInstance(int argument) + { + _drawManager.DrawIndexedSmallIncInstance(this, argument); + } + + /// + /// Performs a indexed draw with a low number of index buffer elements, + /// while also pre-incrementing the current instance value. + /// + /// Method call argument + private void DrawIndexedSmallIncInstance2(int argument) + { + _drawManager.DrawIndexedSmallIncInstance2(this, argument); + } + + /// + /// Clears the current color and depth-stencil buffers. + /// Which buffers should be cleared is also specified on the argument. + /// + /// Method call argument + private void Clear(int argument) + { + _drawManager.Clear(this, argument); + } + + /// + /// Writes a GPU counter to guest memory. + /// + /// Method call argument + private void Report(int argument) + { + _semaphoreUpdater.Report(argument); + } + + /// + /// Performs high-level emulation of Falcon microcode function number "4". + /// + /// Method call argument + private void SetFalcon04(int argument) + { + _state.State.SetMmeShadowScratch[0] = 1; + } + + /// + /// Updates the uniform buffer data with inline data. + /// + /// New uniform buffer data word + private void ConstantBufferUpdate(int argument) + { + _cbUpdater.Update(argument); + } + + /// + /// Binds a uniform buffer for the vertex shader stage. + /// + /// Method call argument + private void ConstantBufferBindVertex(int argument) + { + _cbUpdater.BindVertex(argument); + } + + /// + /// Binds a uniform buffer for the tessellation control shader stage. + /// + /// Method call argument + private void ConstantBufferBindTessControl(int argument) + { + _cbUpdater.BindTessControl(argument); + } + + /// + /// Binds a uniform buffer for the tessellation evaluation shader stage. + /// + /// Method call argument + private void ConstantBufferBindTessEvaluation(int argument) + { + _cbUpdater.BindTessEvaluation(argument); + } + + /// + /// Binds a uniform buffer for the geometry shader stage. + /// + /// Method call argument + private void ConstantBufferBindGeometry(int argument) + { + _cbUpdater.BindGeometry(argument); + } + + /// + /// Binds a uniform buffer for the fragment shader stage. + /// + /// Method call argument + private void ConstantBufferBindFragment(int argument) + { + _cbUpdater.BindFragment(argument); + } + + /// + /// Generic register read function that just returns 0. + /// + /// Zero + 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 +{ + /// + /// Shader stage name. + /// + enum ShaderType + { + Vertex, + TessellationControl, + TessellationEvaluation, + Geometry, + Fragment + } + + /// + /// Transform feedback buffer state. + /// + 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 + } + + /// + /// Transform feedback state. + /// + struct TfState + { +#pragma warning disable CS0649 + public int BufferIndex; + public int VaryingsCount; + public int Stride; + public uint Padding; +#pragma warning restore CS0649 + } + + /// + /// Render target color buffer state. + /// + 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 + } + + /// + /// Viewport transform parameters, for viewport transformation. + /// + 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 + + /// + /// Unpacks viewport swizzle of the position X component. + /// + /// Swizzle enum value + public ViewportSwizzle UnpackSwizzleX() + { + return (ViewportSwizzle)(Swizzle & 7); + } + + /// + /// Unpacks viewport swizzle of the position Y component. + /// + /// Swizzle enum value + public ViewportSwizzle UnpackSwizzleY() + { + return (ViewportSwizzle)((Swizzle >> 4) & 7); + } + + /// + /// Unpacks viewport swizzle of the position Z component. + /// + /// Swizzle enum value + public ViewportSwizzle UnpackSwizzleZ() + { + return (ViewportSwizzle)((Swizzle >> 8) & 7); + } + + /// + /// Unpacks viewport swizzle of the position W component. + /// + /// Swizzle enum value + public ViewportSwizzle UnpackSwizzleW() + { + return (ViewportSwizzle)((Swizzle >> 12) & 7); + } + } + + /// + /// Viewport extents for viewport clipping, also includes depth range. + /// + 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 + } + + /// + /// Draw state for non-indexed draws. + /// + struct VertexBufferDrawState + { +#pragma warning disable CS0649 + public int First; + public int Count; +#pragma warning restore CS0649 + } + + /// + /// Color buffer clear color. + /// + struct ClearColors + { +#pragma warning disable CS0649 + public float Red; + public float Green; + public float Blue; + public float Alpha; +#pragma warning restore CS0649 + } + + /// + /// Depth bias (also called polygon offset) parameters. + /// + struct DepthBiasState + { +#pragma warning disable CS0649 + public Boolean32 PointEnable; + public Boolean32 LineEnable; + public Boolean32 FillEnable; +#pragma warning restore CS0649 + } + + /// + /// Scissor 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 + } + + /// + /// Stencil test masks for back tests. + /// + struct StencilBackMasks + { +#pragma warning disable CS0649 + public int FuncRef; + public int Mask; + public int FuncMask; +#pragma warning restore CS0649 + } + + /// + /// Render target depth-stencil buffer state. + /// + struct RtDepthStencilState + { +#pragma warning disable CS0649 + public GpuVa Address; + public ZetaFormat Format; + public MemoryLayout MemoryLayout; + public int LayerSize; +#pragma warning restore CS0649 + } + + /// + /// Screen scissor state. + /// + struct ScreenScissorState + { +#pragma warning disable CS0649 + public ushort X; + public ushort Width; + public ushort Y; + public ushort Height; +#pragma warning restore CS0649 + } + + /// + /// Vertex buffer attribute state. + /// + struct VertexAttribState + { +#pragma warning disable CS0649 + public uint Attribute; +#pragma warning restore CS0649 + + /// + /// Unpacks the index of the vertex buffer this attribute belongs to. + /// + /// Vertex buffer index + public int UnpackBufferIndex() + { + return (int)(Attribute & 0x1f); + } + + /// + /// Unpacks the attribute constant flag. + /// + /// True if the attribute is constant, false otherwise + public bool UnpackIsConstant() + { + return (Attribute & 0x40) != 0; + } + + /// + /// Unpacks the offset, in bytes, of the attribute on the vertex buffer. + /// + /// Attribute offset in bytes + public int UnpackOffset() + { + return (int)((Attribute >> 7) & 0x3fff); + } + + /// + /// Unpacks the Maxwell attribute format integer. + /// + /// Attribute format integer + public uint UnpackFormat() + { + return Attribute & 0x3fe00000; + } + } + + /// + /// Render target draw buffers control. + /// + struct RtControl + { +#pragma warning disable CS0649 + public uint Packed; +#pragma warning restore CS0649 + + /// + /// Unpacks the number of active draw buffers. + /// + /// Number of active draw buffers + public int UnpackCount() + { + return (int)(Packed & 0xf); + } + + /// + /// Unpacks the color attachment index for a given draw buffer. + /// + /// Index of the draw buffer + /// Attachment index + public int UnpackPermutationIndex(int index) + { + return (int)((Packed >> (4 + index * 3)) & 7); + } + } + + /// + /// 3D, 2D or 1D texture size. + /// + struct Size3D + { +#pragma warning disable CS0649 + public int Width; + public int Height; + public int Depth; +#pragma warning restore CS0649 + } + + /// + /// Stencil front test state and masks. + /// + 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 + } + + /// + /// Screen Y control register. + /// + [Flags] + enum YControl + { + NegateY = 1 << 0, + TriangleRastFlip = 1 << 4 + } + + /// + /// Condition for conditional rendering. + /// + enum Condition + { + Never, + Always, + ResultNonZero, + Equal, + NotEqual + } + + /// + /// Texture or sampler pool state. + /// + struct PoolState + { +#pragma warning disable CS0649 + public GpuVa Address; + public int MaximumId; +#pragma warning restore CS0649 + } + + /// + /// Stencil back test state. + /// + 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 + } + + /// + /// Primitive restart state. + /// + struct PrimitiveRestartState + { +#pragma warning disable CS0649 + public Boolean32 Enable; + public int Index; +#pragma warning restore CS0649 + } + + /// + /// GPU index buffer state. + /// This is used on indexed draws. + /// + struct IndexBufferState + { +#pragma warning disable CS0649 + public GpuVa Address; + public GpuVa EndAddress; + public IndexType Type; + public int First; +#pragma warning restore CS0649 + } + + /// + /// Face culling and orientation parameters. + /// + struct FaceState + { +#pragma warning disable CS0649 + public Boolean32 CullEnable; + public FrontFace FrontFace; + public Face CullFace; +#pragma warning restore CS0649 + } + + /// + /// View volume clip control. + /// + [Flags] + enum ViewVolumeClipControl + { + ForceDepthRangeZeroToOne = 1 << 0, + DepthClampDisabled = 1 << 11 + } + + /// + /// Logical operation state. + /// + struct LogicalOpState + { +#pragma warning disable CS0649 + public Boolean32 Enable; + public LogicalOp LogicalOp; +#pragma warning restore CS0649 + } + + /// + /// Render target color buffer mask. + /// This defines which color channels are written to the color buffer. + /// + struct RtColorMask + { +#pragma warning disable CS0649 + public uint Packed; +#pragma warning restore CS0649 + + /// + /// Unpacks red channel enable. + /// + /// True to write the new red channel color, false to keep the old value + public bool UnpackRed() + { + return (Packed & 0x1) != 0; + } + + /// + /// Unpacks green channel enable. + /// + /// True to write the new green channel color, false to keep the old value + public bool UnpackGreen() + { + return (Packed & 0x10) != 0; + } + + /// + /// Unpacks blue channel enable. + /// + /// True to write the new blue channel color, false to keep the old value + public bool UnpackBlue() + { + return (Packed & 0x100) != 0; + } + + /// + /// Unpacks alpha channel enable. + /// + /// True to write the new alpha channel color, false to keep the old value + public bool UnpackAlpha() + { + return (Packed & 0x1000) != 0; + } + } + + /// + /// Vertex buffer state. + /// + struct VertexBufferState + { +#pragma warning disable CS0649 + public uint Control; + public GpuVa Address; + public int Divisor; +#pragma warning restore CS0649 + + /// + /// Vertex buffer stride, defined as the number of bytes occupied by each vertex in memory. + /// + /// Vertex buffer stride + public int UnpackStride() + { + return (int)(Control & 0xfff); + } + + /// + /// Vertex buffer enable. + /// + /// True if the vertex buffer is enabled, false otherwise + public bool UnpackEnable() + { + return (Control & (1 << 12)) != 0; + } + } + + /// + /// Color buffer blending parameters, shared by all color buffers. + /// + 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 + } + + /// + /// Color buffer blending parameters. + /// + 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 + } + + /// + /// Graphics shader stage state. + /// + 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 + + /// + /// Unpacks shader enable information. + /// Must be ignored for vertex shaders, those are always enabled. + /// + /// True if the stage is enabled, false otherwise + public bool UnpackEnable() + { + return (Control & 1) != 0; + } + } + + /// + /// Uniform buffer state for the uniform buffer currently being modified. + /// + 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; + public fixed uint Reserved400[192]; + public Array4 TfState; + public fixed uint Reserved740[1]; + public Boolean32 TfEnable; + public fixed uint Reserved748[46]; + public Array8 RtColorState; + public Array16 ViewportTransform; + public Array16 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; + 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; + 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 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 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; + public fixed uint Reserved1A20[56]; + public GpuVa SemaphoreAddress; + public int SemaphorePayload; + public uint SemaphoreControl; + public fixed uint Reserved1B10[60]; + public Array16 VertexBufferState; + public fixed uint Reserved1D00[64]; + public Array8 BlendState; + public Array16 VertexBufferEndAddress; + public fixed uint Reserved1F80[32]; + public Array6 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 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> 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(ref _state.State.SetDstFormat); - var srcCopyTexture = Unsafe.As(ref _state.State.SetSrcFormat); + var dstCopyTexture = Unsafe.As(ref _state.State.SetDstFormat); + var srcCopyTexture = Unsafe.As(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 @@ -13,17 +13,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Twod WriteThenAwaken = 1, } - /// - /// MME shadow RAM control mode. - /// - enum SetMmeShadowRamControlMode - { - MethodTrack = 0, - MethodTrackWithFilter = 1, - MethodPassthrough = 2, - MethodReplay = 3, - } - /// /// Format of the destination texture. /// @@ -506,7 +495,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Twod /// /// 2D class state. /// - 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 +{ + /// + /// Texture to texture (with optional resizing) copy parameters. + /// + 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 similarity index 88% rename from Ryujinx.Graphics.Gpu/State/Boolean32.cs rename to 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 { /// /// 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 similarity index 99% rename from Ryujinx.Graphics.Gpu/State/ColorFormat.cs rename to 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 { /// /// Color texture format. diff --git a/Ryujinx.Graphics.Gpu/State/GpuVa.cs b/Ryujinx.Graphics.Gpu/Engine/Types/GpuVa.cs similarity index 91% rename from Ryujinx.Graphics.Gpu/State/GpuVa.cs rename to 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 { /// /// Split GPU virtual address. diff --git a/Ryujinx.Graphics.Gpu/State/MemoryLayout.cs b/Ryujinx.Graphics.Gpu/Engine/Types/MemoryLayout.cs similarity index 94% rename from Ryujinx.Graphics.Gpu/State/MemoryLayout.cs rename to 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 { /// /// Memory layout parameters, for block linear textures. diff --git a/Ryujinx.Graphics.Gpu/State/PrimitiveType.cs b/Ryujinx.Graphics.Gpu/Engine/Types/PrimitiveType.cs similarity index 98% rename from Ryujinx.Graphics.Gpu/State/PrimitiveType.cs rename to 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 { /// /// Draw primitive type. @@ -29,7 +29,6 @@ namespace Ryujinx.Graphics.Gpu.State /// 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 similarity index 78% rename from Ryujinx.Graphics.Gpu/State/SamplerIndex.cs rename to 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 { /// /// Sampler pool indexing mode. diff --git a/Ryujinx.Graphics.Gpu/State/SbDescriptor.cs b/Ryujinx.Graphics.Gpu/Engine/Types/SbDescriptor.cs similarity index 90% rename from Ryujinx.Graphics.Gpu/State/SbDescriptor.cs rename to 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 { /// /// Storage buffer address and size information. diff --git a/Ryujinx.Graphics.Gpu/State/ZetaFormat.cs b/Ryujinx.Graphics.Gpu/Engine/Types/ZetaFormat.cs similarity index 97% rename from Ryujinx.Graphics.Gpu/State/ZetaFormat.cs rename to 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 { /// /// 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 @@ -64,6 +64,17 @@ namespace Ryujinx.Graphics.Gpu memoryManager.Physical.BufferCache.NotifyBuffersModified += BufferManager.Rebind; } + /// + /// Writes data directly to the state of the specified class. + /// + /// ID of the class to write the data into + /// State offset in bytes + /// Value to be written + public void Write(ClassId classId, int offset, uint value) + { + _processor.Write(classId, offset, (int)value); + } + /// /// Push a GPFIFO entry in the form of a prefetched command buffer. /// It is intended to be used by nvservices to handle special cases. 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; @@ -26,11 +25,6 @@ namespace Ryujinx.Graphics.Gpu /// public IRenderer Renderer { get; } - /// - /// GPU engine methods processing. - /// - internal Methods Methods { get; } - /// /// GPU General Purpose FIFO queue. /// @@ -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 /// The texture 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 /// A matching texture, or null if there is no match 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 -{ - /// - /// Method call parameters. - /// - struct MethodParams - { - /// - /// Method offset. - /// - public int Method { get; } - - /// - /// Method call argument. - /// - public int Argument { get; } - - /// - /// Sub-channel where the call should be sent. - /// - public int SubChannel { get; } - - /// - /// For multiple calls to the same method, this is the remaining calls count. - /// - public int MethodCount { get; } - - /// - /// Indicates if the current call is the last one from a batch of calls to the same method. - /// - public bool IsLastCall => MethodCount <= 1; - - /// - /// Constructs the method call parameters structure. - /// - /// Method offset - /// Method call argument - /// Optional sub-channel where the method should be sent (not required for macro calls) - /// Optional remaining calls count (not required for macro calls) - 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 /// Current primitive topology 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, + }; } /// 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 { /// @@ -25,6 +27,11 @@ namespace Ryujinx.Graphics.Gpu.Shader /// public bool EarlyZForce { get; } + /// + /// Primitive topology of current draw. + /// + public PrimitiveTopology Topology { get; } + /// /// Creates a new instance of the GPU accessor state. /// @@ -32,12 +39,19 @@ namespace Ryujinx.Graphics.Gpu.Shader /// Maximum ID of the texture pool /// Constant buffer slot where the texture handles are located /// Early Z force enable - public GpuAccessorState(ulong texturePoolGpuVa, int texturePoolMaximumId, int textureBufferIndex, bool earlyZForce) + /// Primitive topology + 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 /// /// This automatically translates, compiles and adds the code to the cache if not present. /// - /// Current GPU state + /// GPU state + /// GPU channel + /// GPU accessor state /// Addresses of the shaders for each stage /// Compiled graphics shader code - 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 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 hostShaders = new List(); @@ -733,9 +736,9 @@ namespace Ryujinx.Graphics.Gpu.Shader /// /// Current GPU state /// Four transform feedback descriptors for the enabled TFBs, or null if TFB is disabled - private static TransformFeedbackDescriptor[] GetTransformFeedbackDescriptors(GpuState state) + private static TransformFeedbackDescriptor[] GetTransformFeedbackDescriptors(ref ThreedClassState state) { - bool tfEnable = state.Get(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(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(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 /// /// This will combine the "Vertex A" and "Vertex B" shader stages, if specified, into one shader. /// - /// Current GPU state + /// GPU channel + /// GPU accessor state /// Cumulative shader resource counts /// Flags that controls shader translation /// Shader stage /// GPU virtual address of the shader code /// The generated translator context 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(MethodOffset.TexturePoolState).Address.Pack(), - state.Get(MethodOffset.TexturePoolState).MaximumId, - state.Get(MethodOffset.TextureBufferIndex), - state.Get(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 -{ - /// - /// Shadow RAM Control setting. - /// - enum ShadowRamControl - { - /// - /// Track data writes and store them on shadow RAM. - /// - Track = 0, - - /// - /// Track data writes and store them on shadow RAM, with filtering. - /// - TrackWithFilter = 1, - - /// - /// Writes data directly without storing on shadow RAM. - /// - Passthrough = 2, - - /// - /// Ignore data being written and replace with data on shadow RAM instead. - /// - 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 -{ - /// - /// Color buffer blending parameters. - /// - 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 -{ - /// - /// Color buffer blending parameters, shared by all color buffers. - /// - 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 -{ - /// - /// Color buffer clear color. - /// - 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 -{ - /// - /// Condition for conditional rendering. - /// - 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 -{ - /// - /// Condition parameters for conditional rendering. - /// - 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 -{ - /// - /// Buffer to texture copy parameters. - /// - 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 -{ - /// - /// Texture copy region. - /// - 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 -{ - /// - /// Texture to texture (with optional resizing) copy parameters. - /// - 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 -{ - /// - /// Depth bias (also called polygon offset) parameters. - /// - 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 -{ - /// - /// Face culling and orientation parameters. - /// - 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 -{ - /// - /// GPU state. - /// - class GpuState - { - private const int RegistersCount = 0xe00; - - public delegate void MethodCallback(GpuState state, int argument); - - private readonly int[] _memory; - private readonly int[] _shadow; - - /// - /// GPU register information. - /// - 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; - - /// - /// Gets or sets the shadow ram control used for this sub-channel. - /// - public ShadowRamControl ShadowRamControl { get; set; } - - /// - /// GPU channel for the sub-channel state. - /// - public GpuChannel Channel { get; } - - /// - /// Creates a new instance of the GPU state. - /// - /// Channel that the sub-channel state belongs to - /// Optional device state that will replace the internal backing storage - 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); - } - - /// - /// Calls a GPU method, using this state. - /// - /// The GPU method to be called - 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); - } - } - - /// - /// Reads data from a GPU register at the given offset. - /// - /// Offset to be read - /// Data at the register - public int Read(int offset) - { - if (_deviceState != null) - { - return _deviceState.Read(offset * 4); - } - - return _memory[offset]; - } - - /// - /// Writes data to the GPU register at the given offset. - /// - /// Offset to be written - /// Value to be written - public void Write(int offset, int value) - { - _memory[offset] = value; - } - - /// - /// Writes an offset value at the uniform buffer offset register. - /// - /// The offset to be written - public void SetUniformBufferOffset(int offset) - { - _memory[(int)MethodOffset.UniformBufferState + 3] = offset; - } - - /// - /// Initializes registers with the default state. - /// - 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 - } - - /// - /// Registers a callback that is called every time a GPU method, or methods are called. - /// - /// Offset of the method - /// Word count of the methods region - /// Calllback to be called - public void RegisterCallback(MethodOffset offset, int count, MethodCallback callback) - { - for (int index = 0; index < count; index++) - { - _registers[(int)offset + index].Callback = callback; - } - } - - /// - /// Registers a callback that is called every time a GPU method is called. - /// - /// Offset of the method - /// Calllback to be called - public void RegisterCallback(MethodOffset offset, MethodCallback callback) - { - _registers[(int)offset].Callback = callback; - } - - /// - /// Clear all registered callbacks. - /// - public void ClearCallbacks() - { - for (int index = 0; index < _registers.Length; index++) - { - _registers[index].Callback = null; - } - } - - /// - /// Forces a full host state update by marking all state as modified, - /// and also requests all GPU resources in use to be rebound. - /// - public void ForceAllDirty() - { - for (int index = 0; index < _registers.Length; index++) - { - _registers[index].Modified = true; - } - - Channel.BufferManager.Rebind(); - Channel.TextureManager.Rebind(); - } - - /// - /// Checks if a given register has been modified since the last call to this method. - /// - /// Register offset - /// True if modified, false otherwise - public bool QueryModified(MethodOffset offset) - { - bool modified = _registers[(int)offset].Modified; - - _registers[(int)offset].Modified = false; - - return modified; - } - - /// - /// Checks if two registers have been modified since the last call to this method. - /// - /// First register offset - /// Second register offset - /// True if any register was modified, false otherwise - 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; - } - - /// - /// Checks if three registers have been modified since the last call to this method. - /// - /// First register offset - /// Second register offset - /// Third register offset - /// True if any register was modified, false otherwise - 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; - } - - /// - /// Checks if four registers have been modified since the last call to this method. - /// - /// First register offset - /// Second register offset - /// Third register offset - /// Fourth register offset - /// True if any register was modified, false otherwise - 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; - } - - /// - /// Checks if five registers have been modified since the last call to this method. - /// - /// First register offset - /// Second register offset - /// Third register offset - /// Fourth register offset - /// Fifth register offset - /// True if any register was modified, false otherwise - 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; - } - - /// - /// Checks if six registers have been modified since the last call to this method. - /// - /// First register offset - /// Second register offset - /// Third register offset - /// Fourth register offset - /// Fifth register offset - /// Sixth register offset - /// True if any register was modified, false otherwise - 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; - } - - /// - /// Gets indexed data from a given register offset. - /// - /// Type of the data - /// Register offset - /// Index for indexed data - /// The data at the specified location - public T Get(MethodOffset offset, int index) where T : unmanaged - { - Register register = _registers[(int)offset]; - - if ((uint)index >= register.Count) - { - throw new ArgumentOutOfRangeException(nameof(index)); - } - - return Get(offset + index * register.Stride); - } - - /// - /// Gets data from a given register offset. - /// - /// Type of the data - /// Register offset - /// The data at the specified location - public T Get(MethodOffset offset) where T : unmanaged - { - return MemoryMarshal.Cast(_memory.AsSpan().Slice((int)offset))[0]; - } - - /// - /// Gets a span of the data at a given register offset. - /// - /// Register offset - /// Length of the data in bytes - /// The data at the specified location - public Span GetSpan(MethodOffset offset, int length) - { - return MemoryMarshal.Cast(_memory.AsSpan().Slice((int)offset)).Slice(0, length); - } - - /// - /// Sets indexed data to a given register offset. - /// - /// Type of the data - /// Register offset - /// Index for indexed data - /// The data to set - public void Set(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); - } - - /// - /// Sets data to a given register offset. - /// - /// Type of the data - /// Register offset - /// The data to set - public void Set(MethodOffset offset, T data) where T : unmanaged - { - ReadOnlySpan intSpan = MemoryMarshal.Cast(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 -{ - /// - /// GPU State item sizes table. - /// - static class GpuStateTable - { - /// - /// GPU state table item, with size for structures, and count for indexed state data. - /// - public struct TableItem - { - /// - /// Offset of the data. - /// - public MethodOffset Offset { get; } - - /// - /// Size in words. - /// - public int Size { get; } - - /// - /// Count for indexed data, or 1 if not indexed. - /// - public int Count { get; } - - /// - /// Constructs the table item structure. - /// - /// Data offset - /// Data type - /// Data count, for indexed data - 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; - } - } - - /// - /// Table of GPU state structure sizes and counts. - /// - 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 -{ - /// - /// GPU index buffer state. - /// This is used on indexed draws. - /// - 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 -{ - /// - /// Inline-to-memory copy parameters. - /// - 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 -{ - /// - /// GPU method offset. - /// - /// - /// This is indexed in 32 bits word. - /// - 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 -{ - /// - /// Texture or sampler pool state. - /// - 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 -{ - /// - /// Primitive restart state. - /// - 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 -{ - /// - /// Counter type for GPU counter reporting. - /// - 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 -{ - /// - /// Counter type for GPU counter reset. - /// - 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 -{ - /// - /// Render target color buffer mask. - /// This defines which color channels are written to the color buffer. - /// - struct RtColorMask - { -#pragma warning disable CS0649 - public uint Packed; -#pragma warning restore CS0649 - - /// - /// Unpacks red channel enable. - /// - /// True to write the new red channel color, false to keep the old value - public bool UnpackRed() - { - return (Packed & 0x1) != 0; - } - - /// - /// Unpacks green channel enable. - /// - /// True to write the new green channel color, false to keep the old value - public bool UnpackGreen() - { - return (Packed & 0x10) != 0; - } - - /// - /// Unpacks blue channel enable. - /// - /// True to write the new blue channel color, false to keep the old value - public bool UnpackBlue() - { - return (Packed & 0x100) != 0; - } - - /// - /// Unpacks alpha channel enable. - /// - /// True to write the new alpha channel color, false to keep the old value - 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 -{ - /// - /// Render target color buffer state. - /// - 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 -{ - /// - /// Render target draw buffers control. - /// - struct RtControl - { -#pragma warning disable CS0649 - public uint Packed; -#pragma warning restore CS0649 - - /// - /// Unpacks the number of active draw buffers. - /// - /// Number of active draw buffers - public int UnpackCount() - { - return (int)(Packed & 0xf); - } - - /// - /// Unpacks the color attachment index for a given draw buffer. - /// - /// Index of the draw buffer - /// Attachment index - 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 -{ - /// - /// Render target depth-stencil buffer state. - /// - 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 -{ - /// - /// GPU semaphore operation. - /// - 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 -{ - /// - /// GPU semaphore state. - /// - 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 -{ - /// - /// Graphics shader stage state. - /// - 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 - - /// - /// Unpacks shader enable information. - /// Must be ignored for vertex shaders, those are always enabled. - /// - /// True if the stage is enabled, false otherwise - 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 -{ - /// - /// Shader stage name. - /// - 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 -{ - /// - /// 3D, 2D or 1D texture size. - /// - 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 -{ - /// - /// Stencil test masks for back tests. - /// - 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 -{ - /// - /// Stencil back test state. - /// - 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 -{ - /// - /// Stencil front test state and masks. - /// - 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 -{ - /// - /// Transform feedback buffer state. - /// - 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 -{ - /// - /// Transform feedback state. - /// - 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 -{ - /// - /// Uniform buffer state for the uniform buffer currently being modified. - /// - 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 -{ - /// - /// Vertex buffer attribute state. - /// - struct VertexAttribState - { -#pragma warning disable CS0649 - public uint Attribute; -#pragma warning restore CS0649 - - /// - /// Unpacks the index of the vertex buffer this attribute belongs to. - /// - /// Vertex buffer index - public int UnpackBufferIndex() - { - return (int)(Attribute & 0x1f); - } - - /// - /// Unpacks the attribute constant flag. - /// - /// True if the attribute is constant, false otherwise - public bool UnpackIsConstant() - { - return (Attribute & 0x40) != 0; - } - - /// - /// Unpacks the offset, in bytes, of the attribute on the vertex buffer. - /// - /// Attribute offset in bytes - public int UnpackOffset() - { - return (int)((Attribute >> 7) & 0x3fff); - } - - /// - /// Unpacks the Maxwell attribute format integer. - /// - /// Attribute format integer - 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 -{ - /// - /// Draw state for non-indexed draws. - /// - 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 -{ - /// - /// Vertex buffer state. - /// - struct VertexBufferState - { -#pragma warning disable CS0649 - public uint Control; - public GpuVa Address; - public int Divisor; -#pragma warning restore CS0649 - - /// - /// Vertex buffer stride, defined as the number of bytes occupied by each vertex in memory. - /// - /// Vertex buffer stride - public int UnpackStride() - { - return (int)(Control & 0xfff); - } - - /// - /// Vertex buffer enable. - /// - /// True if the vertex buffer is enabled, false otherwise - 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 -{ - /// - /// Viewport extents for viewport clipping, also includes depth range. - /// - 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 -{ - /// - /// Viewport transform parameters, for viewport transformation. - /// - 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 - - /// - /// Unpacks viewport swizzle of the position X component. - /// - /// Swizzle enum value - public ViewportSwizzle UnpackSwizzleX() - { - return (ViewportSwizzle)(Swizzle & 7); - } - - /// - /// Unpacks viewport swizzle of the position Y component. - /// - /// Swizzle enum value - public ViewportSwizzle UnpackSwizzleY() - { - return (ViewportSwizzle)((Swizzle >> 4) & 7); - } - - /// - /// Unpacks viewport swizzle of the position Z component. - /// - /// Swizzle enum value - public ViewportSwizzle UnpackSwizzleZ() - { - return (ViewportSwizzle)((Swizzle >> 8) & 7); - } - - /// - /// Unpacks viewport swizzle of the position W component. - /// - /// Swizzle enum value - 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);