From cf147f1e4977a2dfe197d00341739b72a0e3a129 Mon Sep 17 00:00:00 2001 From: BaronKiko Date: Tue, 1 Jan 2019 17:08:15 +0000 Subject: [PATCH] Quad to triangle optimization (#552) * Fix minor bug with ordering leading to incorrect ordering * Converts quads and quadstrips to triangle * A new line for emmaus * Refactor to remove Ib from quadhelper methods * 20 extra brackets... --- Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs | 76 ++++++++++++++++---- Ryujinx.Graphics/QuadHelper.cs | 8 +-- 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs index fefd2e671..dc1eec3b6 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs @@ -691,11 +691,11 @@ namespace Ryujinx.Graphics.Graphics3d if (PrimType == GalPrimitiveType.Quads) { - Buffer = QuadHelper.ConvertIbQuadsToTris(Buffer, IndexEntrySize, IndexCount); + Buffer = QuadHelper.ConvertQuadsToTris(Buffer, IndexEntrySize, IndexCount); } else /* if (PrimType == GalPrimitiveType.QuadStrip) */ { - Buffer = QuadHelper.ConvertIbQuadStripToTris(Buffer, IndexEntrySize, IndexCount); + Buffer = QuadHelper.ConvertQuadStripToTris(Buffer, IndexEntrySize, IndexCount); } Gpu.Renderer.Rasterizer.CreateIbo(IboKey, IbSize, Buffer); @@ -710,11 +710,11 @@ namespace Ryujinx.Graphics.Graphics3d { if (PrimType == GalPrimitiveType.Quads) { - Gpu.Renderer.Rasterizer.SetIndexArray(QuadHelper.ConvertIbSizeQuadsToTris(IbSize), IndexFormat); + Gpu.Renderer.Rasterizer.SetIndexArray(QuadHelper.ConvertSizeQuadsToTris(IbSize), IndexFormat); } else /* if (PrimType == GalPrimitiveType.QuadStrip) */ { - Gpu.Renderer.Rasterizer.SetIndexArray(QuadHelper.ConvertIbSizeQuadStripToTris(IbSize), IndexFormat); + Gpu.Renderer.Rasterizer.SetIndexArray(QuadHelper.ConvertSizeQuadStripToTris(IbSize), IndexFormat); } } } @@ -796,12 +796,42 @@ namespace Ryujinx.Graphics.Graphics3d long VboKey = Vmm.GetPhysicalAddress(VbPosition); long VbSize = (VbEndPos - VbPosition) + 1; + int ModifiedVbSize = (int)VbSize; - bool VboCached = Gpu.Renderer.Rasterizer.IsVboCached(VboKey, VbSize); + + // If quads convert size to triangle length + if (Stride == 0) + { + if (PrimType == GalPrimitiveType.Quads) + { + ModifiedVbSize = QuadHelper.ConvertSizeQuadsToTris(ModifiedVbSize); + } + else if (PrimType == GalPrimitiveType.QuadStrip) + { + ModifiedVbSize = QuadHelper.ConvertSizeQuadStripToTris(ModifiedVbSize); + } + } + + bool VboCached = Gpu.Renderer.Rasterizer.IsVboCached(VboKey, ModifiedVbSize); if (!VboCached || Gpu.ResourceManager.MemoryRegionModified(Vmm, VboKey, VbSize, NvGpuBufferType.Vertex)) { - if (Vmm.TryGetHostAddress(VbPosition, VbSize, out IntPtr VbPtr)) + if ((PrimType == GalPrimitiveType.Quads | PrimType == GalPrimitiveType.QuadStrip) && Stride != 0) + { + // Convert quad buffer to triangles + byte[] data = Vmm.ReadBytes(VbPosition, VbSize); + + if (PrimType == GalPrimitiveType.Quads) + { + data = QuadHelper.ConvertQuadsToTris(data, Stride, (int)(VbSize / Stride)); + } + else + { + data = QuadHelper.ConvertQuadStripToTris(data, Stride, (int)(VbSize / Stride)); + } + Gpu.Renderer.Rasterizer.CreateVbo(VboKey, data); + } + else if (Vmm.TryGetHostAddress(VbPosition, VbSize, out IntPtr VbPtr)) { Gpu.Renderer.Rasterizer.CreateVbo(VboKey, (int)VbSize, VbPtr); } @@ -863,22 +893,21 @@ namespace Ryujinx.Graphics.Graphics3d //Quad primitive types were deprecated on OpenGL 3.x, //they are converted to a triangles index buffer on IB creation, //so we should use the triangles type here too. - if (PrimType == GalPrimitiveType.Quads || - PrimType == GalPrimitiveType.QuadStrip) + if (PrimType == GalPrimitiveType.Quads || PrimType == GalPrimitiveType.QuadStrip) { - PrimType = GalPrimitiveType.Triangles; - //Note: We assume that index first points to the first //vertex of a quad, if it points to the middle of a //quad (First % 4 != 0 for Quads) then it will not work properly. if (PrimType == GalPrimitiveType.Quads) { - IndexFirst = QuadHelper.ConvertIbSizeQuadsToTris(IndexFirst); + IndexFirst = QuadHelper.ConvertSizeQuadsToTris(IndexFirst); } - else /* if (PrimType == GalPrimitiveType.QuadStrip) */ + else // QuadStrip { - IndexFirst = QuadHelper.ConvertIbSizeQuadStripToTris(IndexFirst); + IndexFirst = QuadHelper.ConvertSizeQuadStripToTris(IndexFirst); } + + PrimType = GalPrimitiveType.Triangles; } Gpu.Renderer.Rasterizer.DrawElements(IboKey, IndexFirst, VertexBase, PrimType); @@ -888,6 +917,27 @@ namespace Ryujinx.Graphics.Graphics3d int VertexFirst = ReadRegister(NvGpuEngine3dReg.VertexArrayFirst); int VertexCount = ReadRegister(NvGpuEngine3dReg.VertexArrayCount); + //Quad primitive types were deprecated on OpenGL 3.x, + //they are converted to a triangles index buffer on IB creation, + //so we should use the triangles type here too. + if (PrimType == GalPrimitiveType.Quads || PrimType == GalPrimitiveType.QuadStrip) + { + //Note: We assume that index first points to the first + //vertex of a quad, if it points to the middle of a + //quad (First % 4 != 0 for Quads) then it will not work properly. + if (PrimType == GalPrimitiveType.Quads) + { + VertexFirst = QuadHelper.ConvertSizeQuadsToTris(VertexFirst); + } + else // QuadStrip + { + VertexFirst = QuadHelper.ConvertSizeQuadStripToTris(VertexFirst); + } + + PrimType = GalPrimitiveType.Triangles; + VertexCount = QuadHelper.ConvertSizeQuadsToTris(VertexCount); + } + Gpu.Renderer.Rasterizer.DrawArrays(VertexFirst, VertexCount, PrimType); } diff --git a/Ryujinx.Graphics/QuadHelper.cs b/Ryujinx.Graphics/QuadHelper.cs index 0dfffce0b..d5fea9abd 100644 --- a/Ryujinx.Graphics/QuadHelper.cs +++ b/Ryujinx.Graphics/QuadHelper.cs @@ -4,17 +4,17 @@ namespace Ryujinx.Graphics { static class QuadHelper { - public static int ConvertIbSizeQuadsToTris(int Size) + public static int ConvertSizeQuadsToTris(int Size) { return Size <= 0 ? 0 : (Size / 4) * 6; } - public static int ConvertIbSizeQuadStripToTris(int Size) + public static int ConvertSizeQuadStripToTris(int Size) { return Size <= 1 ? 0 : ((Size - 2) / 2) * 6; } - public static byte[] ConvertIbQuadsToTris(byte[] Data, int EntrySize, int Count) + public static byte[] ConvertQuadsToTris(byte[] Data, int EntrySize, int Count) { int PrimitivesCount = Count / 4; @@ -46,7 +46,7 @@ namespace Ryujinx.Graphics return Output; } - public static byte[] ConvertIbQuadStripToTris(byte[] Data, int EntrySize, int Count) + public static byte[] ConvertQuadStripToTris(byte[] Data, int EntrySize, int Count) { int PrimitivesCount = (Count - 2) / 2;