2018-04-08 20:17:35 +01:00
|
|
|
using OpenTK.Graphics.OpenGL;
|
|
|
|
using System;
|
|
|
|
|
|
|
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
|
|
|
{
|
2018-08-20 02:25:26 +01:00
|
|
|
class OGLRasterizer : IGalRasterizer
|
2018-04-08 20:17:35 +01:00
|
|
|
{
|
2018-09-20 02:02:11 +01:00
|
|
|
public bool DepthWriteEnabled { set; private get; }
|
|
|
|
|
2018-06-09 01:15:56 +01:00
|
|
|
private int[] VertexBuffers;
|
|
|
|
|
|
|
|
private OGLCachedResource<int> VboCache;
|
|
|
|
private OGLCachedResource<int> IboCache;
|
|
|
|
|
2018-04-08 20:17:35 +01:00
|
|
|
private struct IbInfo
|
|
|
|
{
|
|
|
|
public int Count;
|
2018-06-29 00:48:18 +01:00
|
|
|
public int ElemSizeLog2;
|
2018-04-08 20:17:35 +01:00
|
|
|
|
|
|
|
public DrawElementsType Type;
|
|
|
|
}
|
|
|
|
|
|
|
|
private IbInfo IndexBuffer;
|
|
|
|
|
|
|
|
public OGLRasterizer()
|
|
|
|
{
|
2018-04-29 21:58:38 +01:00
|
|
|
VertexBuffers = new int[32];
|
2018-04-08 20:17:35 +01:00
|
|
|
|
2018-06-09 01:15:56 +01:00
|
|
|
VboCache = new OGLCachedResource<int>(GL.DeleteBuffer);
|
|
|
|
IboCache = new OGLCachedResource<int>(GL.DeleteBuffer);
|
|
|
|
|
2018-04-08 20:17:35 +01:00
|
|
|
IndexBuffer = new IbInfo();
|
2018-09-20 02:02:11 +01:00
|
|
|
|
|
|
|
DepthWriteEnabled = true;
|
2018-04-08 20:17:35 +01:00
|
|
|
}
|
|
|
|
|
2018-07-10 03:01:59 +01:00
|
|
|
public void LockCaches()
|
|
|
|
{
|
|
|
|
VboCache.Lock();
|
|
|
|
IboCache.Lock();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void UnlockCaches()
|
|
|
|
{
|
|
|
|
VboCache.Unlock();
|
|
|
|
IboCache.Unlock();
|
|
|
|
}
|
|
|
|
|
2018-08-10 05:09:40 +01:00
|
|
|
public void ClearBuffers(
|
|
|
|
GalClearBufferFlags Flags,
|
2018-08-20 02:25:26 +01:00
|
|
|
int Attachment,
|
2018-08-10 05:09:40 +01:00
|
|
|
float Red, float Green, float Blue, float Alpha,
|
|
|
|
float Depth,
|
|
|
|
int Stencil)
|
2018-04-08 20:17:35 +01:00
|
|
|
{
|
2018-09-20 02:02:11 +01:00
|
|
|
//OpenGL needs glDepthMask to be enabled to clear it
|
|
|
|
if (!DepthWriteEnabled)
|
|
|
|
{
|
|
|
|
GL.DepthMask(true);
|
|
|
|
}
|
|
|
|
|
2018-06-28 04:11:49 +01:00
|
|
|
GL.ColorMask(
|
|
|
|
Flags.HasFlag(GalClearBufferFlags.ColorRed),
|
|
|
|
Flags.HasFlag(GalClearBufferFlags.ColorGreen),
|
|
|
|
Flags.HasFlag(GalClearBufferFlags.ColorBlue),
|
|
|
|
Flags.HasFlag(GalClearBufferFlags.ColorAlpha));
|
2018-04-08 20:17:35 +01:00
|
|
|
|
2018-08-20 02:25:26 +01:00
|
|
|
GL.ClearBuffer(ClearBuffer.Color, Attachment, new float[] { Red, Green, Blue, Alpha });
|
|
|
|
|
2018-04-08 20:17:35 +01:00
|
|
|
if (Flags.HasFlag(GalClearBufferFlags.Depth))
|
|
|
|
{
|
2018-08-20 02:25:26 +01:00
|
|
|
GL.ClearBuffer(ClearBuffer.Depth, 0, ref Depth);
|
2018-04-08 20:17:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Flags.HasFlag(GalClearBufferFlags.Stencil))
|
|
|
|
{
|
2018-08-20 02:25:26 +01:00
|
|
|
GL.ClearBuffer(ClearBuffer.Stencil, 0, ref Stencil);
|
2018-04-08 20:17:35 +01:00
|
|
|
}
|
|
|
|
|
2018-06-28 04:11:49 +01:00
|
|
|
GL.ColorMask(true, true, true, true);
|
2018-09-20 02:02:11 +01:00
|
|
|
|
|
|
|
if (!DepthWriteEnabled)
|
|
|
|
{
|
|
|
|
GL.DepthMask(false);
|
|
|
|
}
|
2018-04-08 20:17:35 +01:00
|
|
|
}
|
|
|
|
|
2018-06-24 01:39:25 +01:00
|
|
|
public bool IsVboCached(long Key, long DataSize)
|
2018-06-09 01:15:56 +01:00
|
|
|
{
|
2018-06-24 01:39:25 +01:00
|
|
|
return VboCache.TryGetSize(Key, out long Size) && Size == DataSize;
|
2018-06-09 01:15:56 +01:00
|
|
|
}
|
|
|
|
|
2018-06-24 01:39:25 +01:00
|
|
|
public bool IsIboCached(long Key, long DataSize)
|
2018-06-09 01:15:56 +01:00
|
|
|
{
|
2018-06-24 01:39:25 +01:00
|
|
|
return IboCache.TryGetSize(Key, out long Size) && Size == DataSize;
|
2018-06-09 01:15:56 +01:00
|
|
|
}
|
|
|
|
|
2018-07-19 20:02:51 +01:00
|
|
|
public void CreateVbo(long Key, int DataSize, IntPtr HostAddress)
|
2018-04-08 20:17:35 +01:00
|
|
|
{
|
2018-06-09 01:15:56 +01:00
|
|
|
int Handle = GL.GenBuffer();
|
|
|
|
|
2018-07-19 20:02:51 +01:00
|
|
|
VboCache.AddOrUpdate(Key, Handle, (uint)DataSize);
|
2018-04-08 20:17:35 +01:00
|
|
|
|
2018-07-19 20:02:51 +01:00
|
|
|
IntPtr Length = new IntPtr(DataSize);
|
2018-04-08 20:17:35 +01:00
|
|
|
|
2018-06-09 01:15:56 +01:00
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
|
2018-07-19 20:02:51 +01:00
|
|
|
GL.BufferData(BufferTarget.ArrayBuffer, Length, HostAddress, BufferUsageHint.StreamDraw);
|
2018-06-09 01:15:56 +01:00
|
|
|
}
|
|
|
|
|
2018-07-19 20:02:51 +01:00
|
|
|
public void CreateIbo(long Key, int DataSize, IntPtr HostAddress)
|
2018-06-09 01:15:56 +01:00
|
|
|
{
|
|
|
|
int Handle = GL.GenBuffer();
|
|
|
|
|
2018-07-19 20:02:51 +01:00
|
|
|
IboCache.AddOrUpdate(Key, Handle, (uint)DataSize);
|
2018-06-09 01:15:56 +01:00
|
|
|
|
2018-07-19 20:02:51 +01:00
|
|
|
IntPtr Length = new IntPtr(DataSize);
|
2018-06-09 01:15:56 +01:00
|
|
|
|
|
|
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle);
|
2018-07-19 20:02:51 +01:00
|
|
|
GL.BufferData(BufferTarget.ElementArrayBuffer, Length, HostAddress, BufferUsageHint.StreamDraw);
|
2018-06-09 01:15:56 +01:00
|
|
|
}
|
|
|
|
|
2018-10-13 02:37:01 +01:00
|
|
|
public void CreateIbo(long Key, int DataSize, byte[] Buffer)
|
|
|
|
{
|
|
|
|
int Handle = GL.GenBuffer();
|
|
|
|
|
|
|
|
IboCache.AddOrUpdate(Key, Handle, (uint)DataSize);
|
|
|
|
|
|
|
|
IntPtr Length = new IntPtr(Buffer.Length);
|
|
|
|
|
|
|
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle);
|
|
|
|
GL.BufferData(BufferTarget.ElementArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
|
|
|
|
}
|
|
|
|
|
2018-07-10 03:01:59 +01:00
|
|
|
public void SetIndexArray(int Size, GalIndexFormat Format)
|
2018-04-08 20:17:35 +01:00
|
|
|
{
|
|
|
|
IndexBuffer.Type = OGLEnumConverter.GetDrawElementsType(Format);
|
|
|
|
|
2018-06-09 01:15:56 +01:00
|
|
|
IndexBuffer.Count = Size >> (int)Format;
|
2018-06-29 00:48:18 +01:00
|
|
|
|
|
|
|
IndexBuffer.ElemSizeLog2 = (int)Format;
|
2018-04-08 20:17:35 +01:00
|
|
|
}
|
|
|
|
|
2018-09-18 05:30:35 +01:00
|
|
|
public void DrawArrays(int First, int Count, GalPrimitiveType PrimType)
|
2018-04-08 20:17:35 +01:00
|
|
|
{
|
2018-09-18 05:30:35 +01:00
|
|
|
if (Count == 0)
|
2018-04-08 20:17:35 +01:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-13 02:37:01 +01:00
|
|
|
if (PrimType == GalPrimitiveType.Quads)
|
|
|
|
{
|
|
|
|
for (int Offset = 0; Offset < Count; Offset += 4)
|
|
|
|
{
|
|
|
|
GL.DrawArrays(PrimitiveType.TriangleFan, First + Offset, 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (PrimType == GalPrimitiveType.QuadStrip)
|
|
|
|
{
|
|
|
|
GL.DrawArrays(PrimitiveType.TriangleFan, First, 4);
|
|
|
|
|
|
|
|
for (int Offset = 2; Offset < Count; Offset += 2)
|
|
|
|
{
|
|
|
|
GL.DrawArrays(PrimitiveType.TriangleFan, First + Offset, 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, Count);
|
|
|
|
}
|
2018-04-08 20:17:35 +01:00
|
|
|
}
|
|
|
|
|
2018-06-29 00:48:18 +01:00
|
|
|
public void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType)
|
2018-04-08 20:17:35 +01:00
|
|
|
{
|
2018-06-24 01:39:25 +01:00
|
|
|
if (!IboCache.TryGetValue(IboKey, out int IboHandle))
|
2018-06-09 01:15:56 +01:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-04-08 20:17:35 +01:00
|
|
|
PrimitiveType Mode = OGLEnumConverter.GetPrimitiveType(PrimType);
|
|
|
|
|
2018-06-09 01:15:56 +01:00
|
|
|
GL.BindBuffer(BufferTarget.ElementArrayBuffer, IboHandle);
|
2018-04-08 20:17:35 +01:00
|
|
|
|
2018-06-29 00:48:18 +01:00
|
|
|
First <<= IndexBuffer.ElemSizeLog2;
|
|
|
|
|
|
|
|
if (VertexBase != 0)
|
|
|
|
{
|
|
|
|
IntPtr Indices = new IntPtr(First);
|
|
|
|
|
|
|
|
GL.DrawElementsBaseVertex(Mode, IndexBuffer.Count, IndexBuffer.Type, Indices, VertexBase);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GL.DrawElements(Mode, IndexBuffer.Count, IndexBuffer.Type, First);
|
|
|
|
}
|
2018-04-08 20:17:35 +01:00
|
|
|
}
|
2018-08-10 05:09:40 +01:00
|
|
|
|
|
|
|
public bool TryGetVbo(long VboKey, out int VboHandle)
|
|
|
|
{
|
|
|
|
return VboCache.TryGetValue(VboKey, out VboHandle);
|
|
|
|
}
|
2018-04-08 20:17:35 +01:00
|
|
|
}
|
|
|
|
}
|