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...
This commit is contained in:
BaronKiko 2019-01-01 17:08:15 +00:00 committed by gdkchan
parent 016156c288
commit cf147f1e49
2 changed files with 67 additions and 17 deletions

View file

@ -691,11 +691,11 @@ namespace Ryujinx.Graphics.Graphics3d
if (PrimType == GalPrimitiveType.Quads) if (PrimType == GalPrimitiveType.Quads)
{ {
Buffer = QuadHelper.ConvertIbQuadsToTris(Buffer, IndexEntrySize, IndexCount); Buffer = QuadHelper.ConvertQuadsToTris(Buffer, IndexEntrySize, IndexCount);
} }
else /* if (PrimType == GalPrimitiveType.QuadStrip) */ else /* if (PrimType == GalPrimitiveType.QuadStrip) */
{ {
Buffer = QuadHelper.ConvertIbQuadStripToTris(Buffer, IndexEntrySize, IndexCount); Buffer = QuadHelper.ConvertQuadStripToTris(Buffer, IndexEntrySize, IndexCount);
} }
Gpu.Renderer.Rasterizer.CreateIbo(IboKey, IbSize, Buffer); Gpu.Renderer.Rasterizer.CreateIbo(IboKey, IbSize, Buffer);
@ -710,11 +710,11 @@ namespace Ryujinx.Graphics.Graphics3d
{ {
if (PrimType == GalPrimitiveType.Quads) 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) */ 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 VboKey = Vmm.GetPhysicalAddress(VbPosition);
long VbSize = (VbEndPos - VbPosition) + 1; 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 (!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); 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, //Quad primitive types were deprecated on OpenGL 3.x,
//they are converted to a triangles index buffer on IB creation, //they are converted to a triangles index buffer on IB creation,
//so we should use the triangles type here too. //so we should use the triangles type here too.
if (PrimType == GalPrimitiveType.Quads || if (PrimType == GalPrimitiveType.Quads || PrimType == GalPrimitiveType.QuadStrip)
PrimType == GalPrimitiveType.QuadStrip)
{ {
PrimType = GalPrimitiveType.Triangles;
//Note: We assume that index first points to the first //Note: We assume that index first points to the first
//vertex of a quad, if it points to the middle of a //vertex of a quad, if it points to the middle of a
//quad (First % 4 != 0 for Quads) then it will not work properly. //quad (First % 4 != 0 for Quads) then it will not work properly.
if (PrimType == GalPrimitiveType.Quads) 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); Gpu.Renderer.Rasterizer.DrawElements(IboKey, IndexFirst, VertexBase, PrimType);
@ -888,6 +917,27 @@ namespace Ryujinx.Graphics.Graphics3d
int VertexFirst = ReadRegister(NvGpuEngine3dReg.VertexArrayFirst); int VertexFirst = ReadRegister(NvGpuEngine3dReg.VertexArrayFirst);
int VertexCount = ReadRegister(NvGpuEngine3dReg.VertexArrayCount); 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); Gpu.Renderer.Rasterizer.DrawArrays(VertexFirst, VertexCount, PrimType);
} }

View file

@ -4,17 +4,17 @@ namespace Ryujinx.Graphics
{ {
static class QuadHelper static class QuadHelper
{ {
public static int ConvertIbSizeQuadsToTris(int Size) public static int ConvertSizeQuadsToTris(int Size)
{ {
return Size <= 0 ? 0 : (Size / 4) * 6; 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; 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; int PrimitivesCount = Count / 4;
@ -46,7 +46,7 @@ namespace Ryujinx.Graphics
return Output; 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; int PrimitivesCount = (Count - 2) / 2;