From f90ee9b7070dfbf3d6f9713a180b0ec899a039b8 Mon Sep 17 00:00:00 2001 From: gdk Date: Tue, 15 Oct 2019 00:10:20 -0300 Subject: [PATCH] Handle quad and quad strip primitive types using triangle fans --- Ryujinx.Graphics.OpenGL/GraphicsPipeline.cs | 220 +++++++++++++++++--- 1 file changed, 195 insertions(+), 25 deletions(-) diff --git a/Ryujinx.Graphics.OpenGL/GraphicsPipeline.cs b/Ryujinx.Graphics.OpenGL/GraphicsPipeline.cs index e9f6b2fb..e904efed 100644 --- a/Ryujinx.Graphics.OpenGL/GraphicsPipeline.cs +++ b/Ryujinx.Graphics.OpenGL/GraphicsPipeline.cs @@ -273,30 +273,82 @@ namespace Ryujinx.Graphics.OpenGL PrepareForDraw(); + if (_primitiveType == PrimitiveType.Quads) + { + DrawQuadsImpl(vertexCount, instanceCount, firstVertex, firstInstance); + } + else if (_primitiveType == PrimitiveType.QuadStrip) + { + DrawQuadStripImpl(vertexCount, instanceCount, firstVertex, firstInstance); + } + else + { + DrawImpl(vertexCount, instanceCount, firstVertex, firstInstance); + } + } + + private void DrawQuadsImpl( + int vertexCount, + int instanceCount, + int firstVertex, + int firstInstance) + { + // TODO: Instanced rendering. + int quadsCount = vertexCount / 4; + + int[] firsts = new int[quadsCount]; + int[] counts = new int[quadsCount]; + + for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++) + { + firsts[quadIndex] = firstVertex + quadIndex * 4; + counts[quadIndex] = 4; + } + + GL.MultiDrawArrays( + PrimitiveType.TriangleFan, + firsts, + counts, + quadsCount); + } + + private void DrawQuadStripImpl( + int vertexCount, + int instanceCount, + int firstVertex, + int firstInstance) + { + // TODO: Instanced rendering. + int quadsCount = (vertexCount - 2) / 2; + + int[] firsts = new int[quadsCount]; + int[] counts = new int[quadsCount]; + + firsts[0] = firstVertex; + counts[0] = 4; + + for (int quadIndex = 1; quadIndex < quadsCount; quadIndex++) + { + firsts[quadIndex] = firstVertex + quadIndex * 2; + counts[quadIndex] = 4; + } + + GL.MultiDrawArrays( + PrimitiveType.TriangleFan, + firsts, + counts, + quadsCount); + } + + private void DrawImpl( + int vertexCount, + int instanceCount, + int firstVertex, + int firstInstance) + { if (firstInstance == 0 && instanceCount == 1) { - if (_primitiveType == PrimitiveType.Quads) - { - for (int offset = 0; offset < vertexCount; offset += 4) - { - GL.DrawArrays(PrimitiveType.TriangleFan, firstVertex + offset, 4); - } - } - else if (_primitiveType == PrimitiveType.QuadStrip) - { - GL.DrawArrays(PrimitiveType.TriangleFan, firstVertex, 4); - - for (int offset = 2; offset < vertexCount; offset += 2) - { - GL.DrawArrays(PrimitiveType.TriangleFan, firstVertex + offset, 4); - } - } - else - { - GL.DrawArrays(_primitiveType, firstVertex, vertexCount); - } - - // GL.DrawArrays(_primitiveType, firstVertex, vertexCount); + GL.DrawArrays(_primitiveType, firstVertex, vertexCount); } else if (firstInstance == 0) { @@ -329,14 +381,132 @@ namespace Ryujinx.Graphics.OpenGL int firstIndexOffset = firstIndex; + int indexElemSize = 1; + switch (_elementsType) { - case DrawElementsType.UnsignedShort: firstIndexOffset *= 2; break; - case DrawElementsType.UnsignedInt: firstIndexOffset *= 4; break; + case DrawElementsType.UnsignedShort: indexElemSize = 2; break; + case DrawElementsType.UnsignedInt: indexElemSize = 4; break; } - IntPtr indexBaseOffset = _indexBaseOffset + firstIndexOffset; + IntPtr indexBaseOffset = _indexBaseOffset + firstIndex * indexElemSize; + if (_primitiveType == PrimitiveType.Quads) + { + DrawQuadsIndexedImpl( + indexCount, + instanceCount, + indexBaseOffset, + indexElemSize, + firstVertex, + firstInstance); + } + else if (_primitiveType == PrimitiveType.QuadStrip) + { + DrawQuadStripIndexedImpl( + indexCount, + instanceCount, + indexBaseOffset, + indexElemSize, + firstVertex, + firstInstance); + } + else + { + DrawIndexedImpl( + indexCount, + instanceCount, + indexBaseOffset, + indexElemSize, + firstVertex, + firstInstance); + } + } + + private void DrawQuadsIndexedImpl( + int indexCount, + int instanceCount, + IntPtr indexBaseOffset, + int indexElemSize, + int firstVertex, + int firstInstance) + { + // TODO: Instanced rendering. + int quadsCount = indexCount / 4; + + IntPtr[] indices = new IntPtr[quadsCount]; + + int[] counts = new int[quadsCount]; + + int[] baseVertices = new int[quadsCount]; + + for (int quadIndex = 0; quadIndex < quadsCount; quadIndex++) + { + indices[quadIndex] = indexBaseOffset + quadIndex * 4 * indexElemSize; + + counts[quadIndex] = 4; + + baseVertices[quadIndex] = firstVertex; + } + + GL.MultiDrawElementsBaseVertex( + PrimitiveType.TriangleFan, + counts, + _elementsType, + indices, + quadsCount, + baseVertices); + } + + private void DrawQuadStripIndexedImpl( + int indexCount, + int instanceCount, + IntPtr indexBaseOffset, + int indexElemSize, + int firstVertex, + int firstInstance) + { + // TODO: Instanced rendering. + int quadsCount = (indexCount - 2) / 2; + + IntPtr[] indices = new IntPtr[quadsCount]; + + int[] counts = new int[quadsCount]; + + int[] baseVertices = new int[quadsCount]; + + indices[0] = indexBaseOffset; + + counts[0] = 4; + + baseVertices[0] = firstVertex; + + for (int quadIndex = 1; quadIndex < quadsCount; quadIndex++) + { + indices[quadIndex] = indexBaseOffset + quadIndex * 2 * indexElemSize; + + counts[quadIndex] = 4; + + baseVertices[quadIndex] = firstVertex; + } + + GL.MultiDrawElementsBaseVertex( + PrimitiveType.TriangleFan, + counts, + _elementsType, + indices, + quadsCount, + baseVertices); + } + + private void DrawIndexedImpl( + int indexCount, + int instanceCount, + IntPtr indexBaseOffset, + int indexElemSize, + int firstVertex, + int firstInstance) + { if (firstInstance == 0 && firstVertex == 0 && instanceCount == 1) { GL.DrawElements(_primitiveType, indexCount, _elementsType, indexBaseOffset);