From f460ecc1829c1b34f2198cc41528b1c6de99d976 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Fri, 6 Oct 2023 23:55:07 +0100 Subject: GPU: Add HLE macros for popular NVN macros (#5761) * GPU: Add HLE macros for popular NVN macros * Remove non-vector equality check The case where it's not hardware accelerated will do the check integer-wise anyways. * Whitespace :pensive: * Address Feedback --- src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs | 206 ++++++++++++++++++++++++ 1 file changed, 206 insertions(+) (limited to 'src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs') diff --git a/src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs b/src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs index a4c4dd10..7d9e1ec0 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs @@ -1,7 +1,10 @@ using Ryujinx.Common.Logging; +using Ryujinx.Common.Memory; using Ryujinx.Graphics.Device; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Gpu.Engine.GPFifo; +using Ryujinx.Graphics.Gpu.Engine.Threed; +using Ryujinx.Graphics.Gpu.Engine.Types; using System; using System.Collections.Generic; @@ -15,9 +18,18 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME private const int ColorLayerCountOffset = 0x818; private const int ColorStructSize = 0x40; private const int ZetaLayerCountOffset = 0x1230; + private const int UniformBufferBindVertexOffset = 0x2410; + private const int FirstVertexOffset = 0x1434; private const int IndirectIndexedDataEntrySize = 0x14; + private const int LogicOpOffset = 0x19c4; + private const int ShaderIdScratchOffset = 0x3470; + private const int ShaderAddressScratchOffset = 0x3488; + private const int UpdateConstantBufferAddressesBase = 0x34a8; + private const int UpdateConstantBufferSizesBase = 0x34bc; + private const int UpdateConstantBufferAddressCbu = 0x3460; + private readonly GPFifoProcessor _processor; private readonly MacroHLEFunctionName _functionName; @@ -49,6 +61,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME { switch (_functionName) { + case MacroHLEFunctionName.BindShaderProgram: + BindShaderProgram(state, arg0); + break; case MacroHLEFunctionName.ClearColor: ClearColor(state, arg0); break; @@ -58,6 +73,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME case MacroHLEFunctionName.DrawArraysInstanced: DrawArraysInstanced(state, arg0); break; + case MacroHLEFunctionName.DrawElements: + DrawElements(state, arg0); + break; case MacroHLEFunctionName.DrawElementsInstanced: DrawElementsInstanced(state, arg0); break; @@ -67,6 +85,21 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME case MacroHLEFunctionName.MultiDrawElementsIndirectCount: MultiDrawElementsIndirectCount(state, arg0); break; + case MacroHLEFunctionName.UpdateBlendState: + UpdateBlendState(state, arg0); + break; + case MacroHLEFunctionName.UpdateColorMasks: + UpdateColorMasks(state, arg0); + break; + case MacroHLEFunctionName.UpdateUniformBufferState: + UpdateUniformBufferState(state, arg0); + break; + case MacroHLEFunctionName.UpdateUniformBufferStateCbu: + UpdateUniformBufferStateCbu(state, arg0); + break; + case MacroHLEFunctionName.UpdateUniformBufferStateCbuV2: + UpdateUniformBufferStateCbuV2(state, arg0); + break; default: throw new NotImplementedException(_functionName.ToString()); } @@ -75,6 +108,149 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME Fifo.Clear(); } + /// + /// Binds a shader program with the index in arg0. + /// + /// GPU state at the time of the call + /// First argument of the call + private void BindShaderProgram(IDeviceState state, int arg0) + { + int scratchOffset = ShaderIdScratchOffset + arg0 * 4; + + int lastId = state.Read(scratchOffset); + int id = FetchParam().Word; + int offset = FetchParam().Word; + + if (lastId == id) + { + FetchParam(); + FetchParam(); + + return; + } + + _processor.ThreedClass.SetShaderOffset(arg0, (uint)offset); + + // Removes overflow on the method address into the increment portion. + // Present in the original macro. + int addrMask = unchecked((int)0xfffc0fff) << 2; + + state.Write(scratchOffset & addrMask, id); + state.Write((ShaderAddressScratchOffset + arg0 * 4) & addrMask, offset); + + int stage = FetchParam().Word; + uint cbAddress = (uint)FetchParam().Word; + + _processor.ThreedClass.UpdateUniformBufferState(65536, cbAddress >> 24, cbAddress << 8); + + int stageOffset = (stage & 0x7f) << 3; + + state.Write((UniformBufferBindVertexOffset + stageOffset * 4) & addrMask, 17); + } + + /// + /// Updates uniform buffer state for update or bind. + /// + /// GPU state at the time of the call + /// First argument of the call + private void UpdateUniformBufferState(IDeviceState state, int arg0) + { + uint address = (uint)state.Read(UpdateConstantBufferAddressesBase + arg0 * 4); + int size = state.Read(UpdateConstantBufferSizesBase + arg0 * 4); + + _processor.ThreedClass.UpdateUniformBufferState(size, address >> 24, address << 8); + } + + /// + /// Updates uniform buffer state for update. + /// + /// GPU state at the time of the call + /// First argument of the call + private void UpdateUniformBufferStateCbu(IDeviceState state, int arg0) + { + uint address = (uint)state.Read(UpdateConstantBufferAddressCbu); + + UniformBufferState ubState = new() + { + Address = new() + { + High = address >> 24, + Low = address << 8 + }, + Size = 24320, + Offset = arg0 << 2 + }; + + _processor.ThreedClass.UpdateUniformBufferState(ubState); + } + + /// + /// Updates uniform buffer state for update. + /// + /// GPU state at the time of the call + /// First argument of the call + private void UpdateUniformBufferStateCbuV2(IDeviceState state, int arg0) + { + uint address = (uint)state.Read(UpdateConstantBufferAddressCbu); + + UniformBufferState ubState = new() + { + Address = new() + { + High = address >> 24, + Low = address << 8 + }, + Size = 28672, + Offset = arg0 << 2 + }; + + _processor.ThreedClass.UpdateUniformBufferState(ubState); + } + + /// + /// Updates blend enable using the given argument. + /// + /// GPU state at the time of the call + /// First argument of the call + private void UpdateBlendState(IDeviceState state, int arg0) + { + state.Write(LogicOpOffset, 0); + + Array8 enable = new(); + + for (int i = 0; i < 8; i++) + { + enable[i] = new Boolean32((uint)(arg0 >> (i + 8)) & 1); + } + + _processor.ThreedClass.UpdateBlendEnable(ref enable); + } + + /// + /// Updates color masks using the given argument and three pushed arguments. + /// + /// GPU state at the time of the call + /// First argument of the call + private void UpdateColorMasks(IDeviceState state, int arg0) + { + Array8 masks = new(); + + int index = 0; + + for (int i = 0; i < 4; i++) + { + masks[index++] = new RtColorMask((uint)arg0 & 0x1fff); + masks[index++] = new RtColorMask(((uint)arg0 >> 16) & 0x1fff); + + if (i != 3) + { + arg0 = FetchParam().Word; + } + } + + _processor.ThreedClass.UpdateColorMasks(ref masks); + } + /// /// Clears one bound color target. /// @@ -129,6 +305,36 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME indexed: false); } + /// + /// Performs a indexed draw. + /// + /// GPU state at the time of the call + /// First argument of the call + private void DrawElements(IDeviceState state, int arg0) + { + var topology = (PrimitiveTopology)arg0; + + var indexAddressHigh = FetchParam(); + var indexAddressLow = FetchParam(); + var indexType = FetchParam(); + var firstIndex = 0; + var indexCount = FetchParam(); + + _processor.ThreedClass.UpdateIndexBuffer( + (uint)indexAddressHigh.Word, + (uint)indexAddressLow.Word, + (IndexType)indexType.Word); + + _processor.ThreedClass.Draw( + topology, + indexCount.Word, + 1, + firstIndex, + state.Read(FirstVertexOffset), + 0, + indexed: true); + } + /// /// Performs a indexed draw. /// -- cgit v1.2.3