aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs')
-rw-r--r--src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs142
1 files changed, 105 insertions, 37 deletions
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
index d7ee24b1..18e7ac00 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
@@ -1,4 +1,5 @@
using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw;
using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Memory;
using System;
@@ -8,7 +9,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// <summary>
/// Draw manager.
/// </summary>
- class DrawManager
+ class DrawManager : IDisposable
{
// Since we don't know the index buffer size for indirect draws,
// we must assume a minimum and maximum size and use that for buffer data update purposes.
@@ -20,6 +21,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
private readonly DeviceStateWithShadow<ThreedClassState> _state;
private readonly DrawState _drawState;
private readonly SpecializationStateUpdater _currentSpecState;
+ private readonly VtgAsCompute _vtgAsCompute;
private bool _topologySet;
private bool _instancedDrawPending;
@@ -53,6 +55,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_state = state;
_drawState = drawState;
_currentSpecState = spec;
+ _vtgAsCompute = new(context, channel, state);
}
/// <summary>
@@ -127,7 +130,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
if (renderEnable == ConditionalRenderEnabled.False)
{
- PerformDeferredDraws();
+ PerformDeferredDraws(engine);
}
_drawState.DrawIndexed = false;
@@ -190,13 +193,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_channel.BufferManager.SetIndexBuffer(br, IndexType.UInt);
- _context.Renderer.Pipeline.DrawIndexed(inlineIndexCount, 1, firstIndex, firstVertex, firstInstance);
+ DrawImpl(engine, inlineIndexCount, 1, firstIndex, firstVertex, firstInstance, indexed: true);
}
else if (_drawState.DrawIndexed)
{
int firstVertex = (int)_state.State.FirstVertex;
- _context.Renderer.Pipeline.DrawIndexed(indexCount, 1, firstIndex, firstVertex, firstInstance);
+ DrawImpl(engine, indexCount, 1, firstIndex, firstVertex, firstInstance, indexed: true);
}
else
{
@@ -204,7 +207,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
var drawState = _state.State.VertexBufferDrawState;
#pragma warning restore IDE0059
- _context.Renderer.Pipeline.Draw(drawVertexCount, 1, drawFirstVertex, firstInstance);
+ DrawImpl(engine, drawVertexCount, 1, 0, drawFirstVertex, firstInstance, indexed: false);
}
_drawState.DrawIndexed = false;
@@ -219,24 +222,26 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// Starts draw.
/// This sets primitive type and instanced draw parameters.
/// </summary>
+ /// <param name="engine">3D engine where this method is being called</param>
/// <param name="argument">Method call argument</param>
- public void DrawBegin(int argument)
+ public void DrawBegin(ThreedClass engine, int argument)
{
bool incrementInstance = (argument & (1 << 26)) != 0;
bool resetInstance = (argument & (1 << 27)) == 0;
PrimitiveType type = (PrimitiveType)(argument & 0xffff);
- DrawBegin(incrementInstance, resetInstance, type);
+ DrawBegin(engine, incrementInstance, resetInstance, type);
}
/// <summary>
/// Starts draw.
/// This sets primitive type and instanced draw parameters.
/// </summary>
+ /// <param name="engine">3D engine where this method is being called</param>
/// <param name="incrementInstance">Indicates if the current instance should be incremented</param>
/// <param name="resetInstance">Indicates if the current instance should be set to zero</param>
/// <param name="primitiveType">Primitive type</param>
- private void DrawBegin(bool incrementInstance, bool resetInstance, PrimitiveType primitiveType)
+ private void DrawBegin(ThreedClass engine, bool incrementInstance, bool resetInstance, PrimitiveType primitiveType)
{
if (incrementInstance)
{
@@ -244,7 +249,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
}
else if (resetInstance)
{
- PerformDeferredDraws();
+ PerformDeferredDraws(engine);
_instanceIndex = 0;
}
@@ -364,7 +369,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// <param name="instanced">True to increment the current instance value, false otherwise</param>
private void DrawIndexBufferBeginEndInstance(ThreedClass engine, int argument, bool instanced)
{
- DrawBegin(instanced, !instanced, (PrimitiveType)((argument >> 28) & 0xf));
+ DrawBegin(engine, instanced, !instanced, (PrimitiveType)((argument >> 28) & 0xf));
int firstIndex = argument & 0xffff;
int indexCount = (argument >> 16) & 0xfff;
@@ -409,7 +414,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// <param name="instanced">True to increment the current instance value, false otherwise</param>
private void DrawVertexArrayBeginEndInstance(ThreedClass engine, int argument, bool instanced)
{
- DrawBegin(instanced, !instanced, (PrimitiveType)((argument >> 28) & 0xf));
+ DrawBegin(engine, instanced, !instanced, (PrimitiveType)((argument >> 28) & 0xf));
int firstVertex = argument & 0xffff;
int vertexCount = (argument >> 16) & 0xfff;
@@ -541,23 +546,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
engine.UpdateState();
- if (instanceCount > 1)
- {
- // Must be called after UpdateState as it assumes the shader state
- // has already been set, and that bindings have been updated already.
-
- _channel.BufferManager.SetInstancedDrawVertexCount(count);
- }
+ DrawImpl(engine, count, instanceCount, firstIndex, firstVertex, firstInstance, indexed);
if (indexed)
{
- _context.Renderer.Pipeline.DrawIndexed(count, instanceCount, firstIndex, firstVertex, firstInstance);
_state.State.FirstVertex = 0;
}
- else
- {
- _context.Renderer.Pipeline.Draw(count, instanceCount, firstVertex, firstInstance);
- }
_state.State.FirstInstance = 0;
@@ -570,6 +564,67 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
}
/// <summary>
+ /// Performs a indexed or non-indexed draw.
+ /// </summary>
+ /// <param name="engine">3D engine where this method is being called</param>
+ /// <param name="count">Index count for indexed draws, vertex count for non-indexed draws</param>
+ /// <param name="instanceCount">Instance count</param>
+ /// <param name="firstIndex">First index on the index buffer for indexed draws, ignored for non-indexed draws</param>
+ /// <param name="firstVertex">First vertex on the vertex buffer</param>
+ /// <param name="firstInstance">First instance</param>
+ /// <param name="indexed">True if the draw is indexed, false otherwise</param>
+ private void DrawImpl(
+ ThreedClass engine,
+ int count,
+ int instanceCount,
+ int firstIndex,
+ int firstVertex,
+ int firstInstance,
+ bool indexed)
+ {
+ if (instanceCount > 1)
+ {
+ _channel.BufferManager.SetInstancedDrawVertexCount(count);
+ }
+
+ if (_drawState.VertexAsCompute != null)
+ {
+ _vtgAsCompute.DrawAsCompute(
+ engine,
+ _drawState.VertexAsCompute,
+ _drawState.GeometryAsCompute,
+ _drawState.VertexPassthrough,
+ _drawState.Topology,
+ count,
+ instanceCount,
+ firstIndex,
+ firstVertex,
+ firstInstance,
+ indexed);
+
+ if (_drawState.GeometryAsCompute != null)
+ {
+ // Geometry draws need to change the topology, so we need to set it here again
+ // if we are going to do a regular draw.
+ // Would have been better to do that on the callee, but doing it here
+ // avoids having to pass the draw manager instance.
+ ForceStateDirty();
+ }
+ }
+ else
+ {
+ if (indexed)
+ {
+ _context.Renderer.Pipeline.DrawIndexed(count, instanceCount, firstIndex, firstVertex, firstInstance);
+ }
+ else
+ {
+ _context.Renderer.Pipeline.Draw(count, instanceCount, firstVertex, firstInstance);
+ }
+ }
+ }
+
+ /// <summary>
/// Performs a indirect draw, with parameters from a GPU buffer.
/// </summary>
/// <param name="engine">3D engine where this method is being called</param>
@@ -667,43 +722,42 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// Once we detect the last instanced draw, then we perform the host instanced draw,
/// with the accumulated instance count.
/// </summary>
- public void PerformDeferredDraws()
+ /// <param name="engine">3D engine where this method is being called</param>
+ public void PerformDeferredDraws(ThreedClass engine)
{
// Perform any pending instanced draw.
if (_instancedDrawPending)
{
_instancedDrawPending = false;
+ int instanceCount = _instanceIndex + 1;
+ int firstInstance = _instancedFirstInstance;
bool indexedInline = _instancedIndexedInline;
if (_instancedIndexed || indexedInline)
{
+ int indexCount = _instancedIndexCount;
+
if (indexedInline)
{
int inlineIndexCount = _drawState.IbStreamer.GetAndResetInlineIndexCount(_context.Renderer);
BufferRange br = new(_drawState.IbStreamer.GetInlineIndexBuffer(), 0, inlineIndexCount * 4);
_channel.BufferManager.SetIndexBuffer(br, IndexType.UInt);
+ indexCount = inlineIndexCount;
}
- _channel.BufferManager.SetInstancedDrawVertexCount(_instancedIndexCount);
+ int firstIndex = _instancedFirstIndex;
+ int firstVertex = _instancedFirstVertex;
- _context.Renderer.Pipeline.DrawIndexed(
- _instancedIndexCount,
- _instanceIndex + 1,
- _instancedFirstIndex,
- _instancedFirstVertex,
- _instancedFirstInstance);
+ DrawImpl(engine, indexCount, instanceCount, firstIndex, firstVertex, firstInstance, indexed: true);
}
else
{
- _channel.BufferManager.SetInstancedDrawVertexCount(_instancedDrawStateCount);
+ int vertexCount = _instancedDrawStateCount;
+ int firstVertex = _instancedDrawStateFirst;
- _context.Renderer.Pipeline.Draw(
- _instancedDrawStateCount,
- _instanceIndex + 1,
- _instancedDrawStateFirst,
- _instancedFirstInstance);
+ DrawImpl(engine, vertexCount, instanceCount, 0, firstVertex, firstInstance, indexed: false);
}
}
}
@@ -866,5 +920,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_context.Renderer.Pipeline.EndHostConditionalRendering();
}
}
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _vtgAsCompute.Dispose();
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
}
}