diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs')
-rw-r--r-- | src/Ryujinx.Graphics.Gpu/Engine/MME/MacroHLE.cs | 206 |
1 files changed, 206 insertions, 0 deletions
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()); } @@ -76,6 +109,149 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME } /// <summary> + /// Binds a shader program with the index in arg0. + /// </summary> + /// <param name="state">GPU state at the time of the call</param> + /// <param name="arg0">First argument of the call</param> + 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); + } + + /// <summary> + /// Updates uniform buffer state for update or bind. + /// </summary> + /// <param name="state">GPU state at the time of the call</param> + /// <param name="arg0">First argument of the call</param> + 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); + } + + /// <summary> + /// Updates uniform buffer state for update. + /// </summary> + /// <param name="state">GPU state at the time of the call</param> + /// <param name="arg0">First argument of the call</param> + 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); + } + + /// <summary> + /// Updates uniform buffer state for update. + /// </summary> + /// <param name="state">GPU state at the time of the call</param> + /// <param name="arg0">First argument of the call</param> + 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); + } + + /// <summary> + /// Updates blend enable using the given argument. + /// </summary> + /// <param name="state">GPU state at the time of the call</param> + /// <param name="arg0">First argument of the call</param> + private void UpdateBlendState(IDeviceState state, int arg0) + { + state.Write(LogicOpOffset, 0); + + Array8<Boolean32> enable = new(); + + for (int i = 0; i < 8; i++) + { + enable[i] = new Boolean32((uint)(arg0 >> (i + 8)) & 1); + } + + _processor.ThreedClass.UpdateBlendEnable(ref enable); + } + + /// <summary> + /// Updates color masks using the given argument and three pushed arguments. + /// </summary> + /// <param name="state">GPU state at the time of the call</param> + /// <param name="arg0">First argument of the call</param> + private void UpdateColorMasks(IDeviceState state, int arg0) + { + Array8<RtColorMask> 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); + } + + /// <summary> /// Clears one bound color target. /// </summary> /// <param name="state">GPU state at the time of the call</param> @@ -134,6 +310,36 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME /// </summary> /// <param name="state">GPU state at the time of the call</param> /// <param name="arg0">First argument of the call</param> + 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); + } + + /// <summary> + /// Performs a indexed draw. + /// </summary> + /// <param name="state">GPU state at the time of the call</param> + /// <param name="arg0">First argument of the call</param> private void DrawElementsInstanced(IDeviceState state, int arg0) { var topology = (PrimitiveTopology)arg0; |