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 😔
* Address Feedback
This commit is contained in:
parent
086564c3c8
commit
f460ecc182
9 changed files with 467 additions and 14 deletions
|
@ -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();
|
||||
}
|
||||
|
||||
/// <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>
|
||||
|
@ -129,6 +305,36 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||
indexed: false);
|
||||
}
|
||||
|
||||
/// <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 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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue