Implement HLE macro for DrawElementsIndirect (#3748)
* Implement HLE macro for DrawElementsIndirect * Shader cache version bump * Use GL_ARB_shader_draw_parameters extension on OpenGL * Fix DrawIndexedIndirectCount on Vulkan when extension is not supported * Implement DrawIndex * Alignment * Fix some validation errors * Rename BaseIds to DrawParameters * Fix incorrect index buffer and vertex buffer size in some cases * Add HLE macros for DrawArraysInstanced and DrawElementsInstanced * Perform a regular draw when indirect data is not modified * Use non-indirect draw methods if indirect buffer was not GPU modified * Only check if draw parameters match if the shader actually uses them * Expose Macro HLE setting on GUI * Reset FirstVertex and FirstInstance after draw * Update shader cache version again since some people already tested this * PR feedback Co-authored-by: riperiperi <rhy3756547@hotmail.com>
This commit is contained in:
@ -34,10 +34,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
private ProgramPipelineState _pipeline;
|
||||
|
||||
private bool _vsUsesDrawParameters;
|
||||
private bool _vtgWritesRtLayer;
|
||||
private byte _vsClipDistancesWritten;
|
||||
|
||||
private bool _prevDrawIndexed;
|
||||
private bool _prevDrawIndirect;
|
||||
private IndexType _prevIndexType;
|
||||
private uint _prevFirstVertex;
|
||||
private bool _prevTfEnable;
|
||||
@ -210,7 +212,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
// of the shader for the new state.
|
||||
if (_shaderSpecState != null)
|
||||
{
|
||||
if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState(), GetGraphicsState(), false))
|
||||
if (!_shaderSpecState.MatchesGraphics(_channel, GetPoolState(), GetGraphicsState(), _vsUsesDrawParameters, false))
|
||||
{
|
||||
ForceShaderUpdate();
|
||||
}
|
||||
@ -237,6 +239,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_prevDrawIndexed = _drawState.DrawIndexed;
|
||||
}
|
||||
|
||||
// Some draw parameters are used to restrict the vertex buffer size,
|
||||
// but they can't be used on indirect draws because their values are unknown in this case.
|
||||
// When switching between indirect and non-indirect draw, we need to
|
||||
// make sure the vertex buffer sizes are still correct.
|
||||
if (_drawState.DrawIndirect != _prevDrawIndirect)
|
||||
{
|
||||
_updateTracker.ForceDirty(VertexBufferStateIndex);
|
||||
}
|
||||
|
||||
// In some cases, the index type is also used to guess the
|
||||
// vertex buffer size, so we must update it if the type changed too.
|
||||
if (_drawState.DrawIndexed &&
|
||||
@ -938,6 +949,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_drawState.IsAnyVbInstanced = false;
|
||||
|
||||
bool drawIndexed = _drawState.DrawIndexed;
|
||||
bool drawIndirect = _drawState.DrawIndirect;
|
||||
|
||||
for (int index = 0; index < Constants.TotalVertexBuffers; index++)
|
||||
{
|
||||
var vertexBuffer = _state.State.VertexBufferState[index];
|
||||
@ -965,14 +979,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
ulong vbSize = endAddress.Pack() - address + 1;
|
||||
ulong size;
|
||||
|
||||
if (_drawState.IbStreamer.HasInlineIndexData || _drawState.DrawIndexed || stride == 0 || instanced)
|
||||
if (_drawState.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 = vbSize;
|
||||
|
||||
if (stride > 0 && indexTypeSmall && _drawState.DrawIndexed && !instanced)
|
||||
if (stride > 0 && indexTypeSmall && drawIndexed && !drawIndirect && !instanced)
|
||||
{
|
||||
// If the index type is a small integer type, then we might be still able
|
||||
// to reduce the vertex buffer size based on the maximum possible index value.
|
||||
@ -1207,6 +1221,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
byte oldVsClipDistancesWritten = _vsClipDistancesWritten;
|
||||
|
||||
_drawState.VsUsesInstanceId = gs.Shaders[1]?.Info.UsesInstanceId ?? false;
|
||||
_vsUsesDrawParameters = gs.Shaders[1]?.Info.UsesDrawParameters ?? false;
|
||||
_vsClipDistancesWritten = gs.Shaders[1]?.Info.ClipDistancesWritten ?? 0;
|
||||
|
||||
if (oldVsClipDistancesWritten != _vsClipDistancesWritten)
|
||||
@ -1222,6 +1237,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_context.Renderer.Pipeline.SetProgram(gs.HostProgram);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates bindings consumed by the shader stage on the texture and buffer managers.
|
||||
/// </summary>
|
||||
/// <param name="stage">Shader stage to have the bindings updated</param>
|
||||
/// <param name="info">Shader stage bindings info</param>
|
||||
private void UpdateStageBindings(int stage, ShaderProgramInfo info)
|
||||
{
|
||||
_currentProgramInfo[stage] = info;
|
||||
@ -1340,7 +1360,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_state.State.AlphaTestEnable,
|
||||
_state.State.AlphaTestFunc,
|
||||
_state.State.AlphaTestRef,
|
||||
ref attributeTypes);
|
||||
ref attributeTypes,
|
||||
_drawState.HasConstantBufferDrawParameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
Reference in New Issue
Block a user