|
|
@@ -51,13 +51,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|
|
|
|
|
private readonly DescriptorSetUpdater _descriptorSetUpdater;
|
|
|
|
|
|
- private BufferState _indexBuffer;
|
|
|
+ private IndexBufferState _indexBuffer;
|
|
|
+ private IndexBufferPattern _indexBufferPattern;
|
|
|
private readonly BufferState[] _transformFeedbackBuffers;
|
|
|
private readonly VertexBufferState[] _vertexBuffers;
|
|
|
private ulong _vertexBuffersDirty;
|
|
|
protected Rectangle<int> ClearScissor;
|
|
|
|
|
|
public SupportBufferUpdater SupportBufferUpdater;
|
|
|
+ public IndexBufferPattern QuadsToTrisPattern;
|
|
|
+ public IndexBufferPattern TriFanToTrisPattern;
|
|
|
|
|
|
private bool _needsIndexBufferRebind;
|
|
|
private bool _needsTransformFeedbackBuffersRebind;
|
|
|
@@ -107,6 +110,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|
|
{
|
|
|
SupportBufferUpdater = new SupportBufferUpdater(Gd);
|
|
|
SupportBufferUpdater.UpdateRenderScale(_renderScale, 0, SupportBuffer.RenderScaleMaxCount);
|
|
|
+
|
|
|
+ QuadsToTrisPattern = new IndexBufferPattern(Gd, 4, 6, 0, new[] { 0, 1, 2, 0, 2, 3 }, 4, false);
|
|
|
+ TriFanToTrisPattern = new IndexBufferPattern(Gd, 3, 3, 2, new[] { int.MinValue, -1, 0 }, 1, true);
|
|
|
}
|
|
|
|
|
|
public unsafe void Barrier()
|
|
|
@@ -245,6 +251,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public void DirtyIndexBuffer(Auto<DisposableBuffer> buffer)
|
|
|
+ {
|
|
|
+ if (_indexBuffer.BoundEquals(buffer))
|
|
|
+ {
|
|
|
+ _needsIndexBufferRebind = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
|
|
|
{
|
|
|
if (!_program.IsLinked)
|
|
|
@@ -267,24 +281,59 @@ namespace Ryujinx.Graphics.Vulkan
|
|
|
|
|
|
RecreatePipelineIfNeeded(PipelineBindPoint.Graphics);
|
|
|
BeginRenderPass();
|
|
|
- ResumeTransformFeedbackInternal();
|
|
|
DrawCount++;
|
|
|
|
|
|
- if (_topology == GAL.PrimitiveTopology.Quads)
|
|
|
+ if (Gd.TopologyUnsupported(_topology))
|
|
|
{
|
|
|
- int quadsCount = vertexCount / 4;
|
|
|
+ // Temporarily bind a conversion pattern as an index buffer.
|
|
|
+ _needsIndexBufferRebind = true;
|
|
|
|
|
|
- for (int i = 0; i < quadsCount; i++)
|
|
|
+ IndexBufferPattern pattern = _topology switch
|
|
|
{
|
|
|
- Gd.Api.CmdDraw(CommandBuffer, 4, (uint)instanceCount, (uint)(firstVertex + i * 4), (uint)firstInstance);
|
|
|
- }
|
|
|
+ GAL.PrimitiveTopology.Quads => QuadsToTrisPattern,
|
|
|
+ GAL.PrimitiveTopology.TriangleFan => TriFanToTrisPattern,
|
|
|
+ _ => throw new NotSupportedException($"Unsupported topology: {_topology}")
|
|
|
+ };
|
|
|
+
|
|
|
+ BufferHandle handle = pattern.GetRepeatingBuffer(vertexCount, out int indexCount);
|
|
|
+ var buffer = Gd.BufferManager.GetBuffer(CommandBuffer, handle, false);
|
|
|
+
|
|
|
+ Gd.Api.CmdBindIndexBuffer(CommandBuffer, buffer.Get(Cbs, 0, indexCount * sizeof(int)).Value, 0, Silk.NET.Vulkan.IndexType.Uint32);
|
|
|
+
|
|
|
+ BeginRenderPass(); // May have been interrupted to set buffer data.
|
|
|
+ ResumeTransformFeedbackInternal();
|
|
|
+
|
|
|
+ Gd.Api.CmdDrawIndexed(CommandBuffer, (uint)indexCount, (uint)instanceCount, 0, firstVertex, (uint)firstInstance);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
+ ResumeTransformFeedbackInternal();
|
|
|
+
|
|
|
Gd.Api.CmdDraw(CommandBuffer, (uint)vertexCount, (uint)instanceCount, (uint)firstVertex, (uint)firstInstance);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private void UpdateIndexBufferPattern()
|
|
|
+ {
|
|
|
+ IndexBufferPattern pattern = null;
|
|
|
+
|
|
|
+ if (Gd.TopologyUnsupported(_topology))
|
|
|
+ {
|
|
|
+ pattern = _topology switch
|
|
|
+ {
|
|
|
+ GAL.PrimitiveTopology.Quads => QuadsToTrisPattern,
|
|
|
+ GAL.PrimitiveTopology.TriangleFan => TriFanToTrisPattern,
|
|
|
+ _ => throw new NotSupportedException($"Unsupported topology: {_topology}")
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_indexBufferPattern != pattern)
|
|
|
+ {
|
|
|
+ _indexBufferPattern = pattern;
|
|
|
+ _needsIndexBufferRebind = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int firstVertex, int firstInstance)
|
|
|
{
|
|
|
if (!_program.IsLinked)
|
|
|
@@ -292,22 +341,34 @@ namespace Ryujinx.Graphics.Vulkan
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ UpdateIndexBufferPattern();
|
|
|
RecreatePipelineIfNeeded(PipelineBindPoint.Graphics);
|
|
|
BeginRenderPass();
|
|
|
- ResumeTransformFeedbackInternal();
|
|
|
DrawCount++;
|
|
|
|
|
|
- if (_topology == GAL.PrimitiveTopology.Quads)
|
|
|
+ if (_indexBufferPattern != null)
|
|
|
{
|
|
|
- int quadsCount = indexCount / 4;
|
|
|
+ // Convert the index buffer into a supported topology.
|
|
|
+ IndexBufferPattern pattern = _indexBufferPattern;
|
|
|
+
|
|
|
+ int convertedCount = pattern.GetConvertedCount(indexCount);
|
|
|
|
|
|
- for (int i = 0; i < quadsCount; i++)
|
|
|
+ if (_needsIndexBufferRebind)
|
|
|
{
|
|
|
- Gd.Api.CmdDrawIndexed(CommandBuffer, 4, (uint)instanceCount, (uint)(firstIndex + i * 4), firstVertex, (uint)firstInstance);
|
|
|
+ _indexBuffer.BindConvertedIndexBuffer(Gd, Cbs, firstIndex, indexCount, convertedCount, pattern);
|
|
|
+
|
|
|
+ _needsIndexBufferRebind = false;
|
|
|
}
|
|
|
+
|
|
|
+ BeginRenderPass(); // May have been interrupted to set buffer data.
|
|
|
+ ResumeTransformFeedbackInternal();
|
|
|
+
|
|
|
+ Gd.Api.CmdDrawIndexed(CommandBuffer, (uint)convertedCount, (uint)instanceCount, 0, firstVertex, (uint)firstInstance);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
+ ResumeTransformFeedbackInternal();
|
|
|
+
|
|
|
Gd.Api.CmdDrawIndexed(CommandBuffer, (uint)indexCount, (uint)instanceCount, (uint)firstIndex, firstVertex, (uint)firstInstance);
|
|
|
}
|
|
|
}
|
|
|
@@ -500,34 +561,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|
|
|
|
|
public void SetIndexBuffer(BufferRange buffer, GAL.IndexType type)
|
|
|
{
|
|
|
- _indexBuffer.Dispose();
|
|
|
-
|
|
|
if (buffer.Handle != BufferHandle.Null)
|
|
|
{
|
|
|
- Auto<DisposableBuffer> ib = null;
|
|
|
- int offset = buffer.Offset;
|
|
|
- int size = buffer.Size;
|
|
|
-
|
|
|
- if (type == GAL.IndexType.UByte && !Gd.Capabilities.SupportsIndexTypeUint8)
|
|
|
- {
|
|
|
- ib = Gd.BufferManager.GetBufferI8ToI16(Cbs, buffer.Handle, offset, size);
|
|
|
- offset = 0;
|
|
|
- size *= 2;
|
|
|
- type = GAL.IndexType.UShort;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- ib = Gd.BufferManager.GetBuffer(CommandBuffer, buffer.Handle, false);
|
|
|
- }
|
|
|
-
|
|
|
- _indexBuffer = new BufferState(ib, offset, size, type.Convert());
|
|
|
+ _indexBuffer = new IndexBufferState(buffer.Handle, buffer.Offset, buffer.Size, type.Convert());
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- _indexBuffer = BufferState.Null;
|
|
|
+ _indexBuffer = IndexBufferState.Null;
|
|
|
}
|
|
|
|
|
|
- _indexBuffer.BindIndexBuffer(Gd.Api, Cbs);
|
|
|
+ _needsIndexBufferRebind = true;
|
|
|
}
|
|
|
|
|
|
public void SetLineParameters(float width, bool smooth)
|
|
|
@@ -584,7 +627,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|
|
{
|
|
|
_topology = topology;
|
|
|
|
|
|
- var vkTopology = topology.Convert();
|
|
|
+ var vkTopology = Gd.TopologyRemap(topology).Convert();
|
|
|
|
|
|
_newState.Topology = vkTopology;
|
|
|
|
|
|
@@ -1127,9 +1170,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|
|
// Commit changes to the support buffer before drawing.
|
|
|
SupportBufferUpdater.Commit();
|
|
|
|
|
|
- if (_needsIndexBufferRebind)
|
|
|
+ if (_needsIndexBufferRebind && _indexBufferPattern == null)
|
|
|
{
|
|
|
- _indexBuffer.BindIndexBuffer(Gd.Api, Cbs);
|
|
|
+ _indexBuffer.BindIndexBuffer(Gd, Cbs);
|
|
|
_needsIndexBufferRebind = false;
|
|
|
}
|
|
|
|
|
|
@@ -1265,7 +1308,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|
|
{
|
|
|
_renderPass?.Dispose();
|
|
|
_framebuffer?.Dispose();
|
|
|
- _indexBuffer.Dispose();
|
|
|
_newState.Dispose();
|
|
|
_descriptorSetUpdater.Dispose();
|
|
|
|