Ryujinx/Ryujinx.Graphics/Gal/OpenGL/OglRasterizer.cs

207 lines
6.2 KiB
C#
Raw Normal View History

using OpenTK.Graphics.OpenGL;
using System;
namespace Ryujinx.Graphics.Gal.OpenGL
{
class OglRasterizer : IGalRasterizer
{
private const long MaxVertexBufferCacheSize = 128 * 1024 * 1024;
private const long MaxIndexBufferCacheSize = 64 * 1024 * 1024;
private int[] _vertexBuffers;
private OglCachedResource<int> _vboCache;
private OglCachedResource<int> _iboCache;
private struct IbInfo
{
public int Count;
public int ElemSizeLog2;
public DrawElementsType Type;
}
private IbInfo _indexBuffer;
public OglRasterizer()
{
_vertexBuffers = new int[32];
_vboCache = new OglCachedResource<int>(GL.DeleteBuffer, MaxVertexBufferCacheSize);
_iboCache = new OglCachedResource<int>(GL.DeleteBuffer, MaxIndexBufferCacheSize);
_indexBuffer = new IbInfo();
}
public void LockCaches()
{
_vboCache.Lock();
_iboCache.Lock();
}
public void UnlockCaches()
{
_vboCache.Unlock();
_iboCache.Unlock();
}
public void ClearBuffers(
GalClearBufferFlags flags,
int attachment,
float red,
float green,
float blue,
float alpha,
float depth,
int stencil)
{
GL.ColorMask(
attachment,
flags.HasFlag(GalClearBufferFlags.ColorRed),
flags.HasFlag(GalClearBufferFlags.ColorGreen),
flags.HasFlag(GalClearBufferFlags.ColorBlue),
flags.HasFlag(GalClearBufferFlags.ColorAlpha));
GL.ClearBuffer(ClearBuffer.Color, attachment, new float[] { red, green, blue, alpha });
GL.ColorMask(attachment, true, true, true, true);
GL.DepthMask(true);
if (flags.HasFlag(GalClearBufferFlags.Depth))
{
GL.ClearBuffer(ClearBuffer.Depth, 0, ref depth);
}
if (flags.HasFlag(GalClearBufferFlags.Stencil))
{
GL.ClearBuffer(ClearBuffer.Stencil, 0, ref stencil);
}
}
public bool IsVboCached(long key, long dataSize)
{
return _vboCache.TryGetSize(key, out long size) && size == dataSize;
}
public bool IsIboCached(long key, long dataSize)
{
return _iboCache.TryGetSize(key, out long size) && size == dataSize;
}
public void CreateVbo(long key, int dataSize, IntPtr hostAddress)
{
int handle = GL.GenBuffer();
_vboCache.AddOrUpdate(key, handle, dataSize);
IntPtr length = new IntPtr(dataSize);
GL.BindBuffer(BufferTarget.ArrayBuffer, handle);
GL.BufferData(BufferTarget.ArrayBuffer, length, hostAddress, BufferUsageHint.StreamDraw);
}
public void CreateVbo(long key, byte[] data)
{
int handle = GL.GenBuffer();
_vboCache.AddOrUpdate(key, handle, data.Length);
IntPtr length = new IntPtr(data.Length);
GL.BindBuffer(BufferTarget.ArrayBuffer, handle);
GL.BufferData(BufferTarget.ArrayBuffer, length, data, BufferUsageHint.StreamDraw);
}
public void CreateIbo(long key, int dataSize, IntPtr hostAddress)
{
int handle = GL.GenBuffer();
_iboCache.AddOrUpdate(key, handle, (uint)dataSize);
IntPtr length = new IntPtr(dataSize);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, handle);
GL.BufferData(BufferTarget.ElementArrayBuffer, length, hostAddress, BufferUsageHint.StreamDraw);
}
public void CreateIbo(long key, int dataSize, byte[] buffer)
{
int handle = GL.GenBuffer();
_iboCache.AddOrUpdate(key, handle, dataSize);
IntPtr length = new IntPtr(buffer.Length);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, handle);
GL.BufferData(BufferTarget.ElementArrayBuffer, length, buffer, BufferUsageHint.StreamDraw);
}
public void SetIndexArray(int size, GalIndexFormat format)
{
_indexBuffer.Type = OglEnumConverter.GetDrawElementsType(format);
_indexBuffer.Count = size >> (int)format;
_indexBuffer.ElemSizeLog2 = (int)format;
}
public void DrawArrays(int first, int count, GalPrimitiveType primType)
{
if (count == 0)
{
return;
}
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);
}
}
public void DrawElements(long iboKey, int first, int vertexBase, GalPrimitiveType primType)
{
if (!_iboCache.TryGetValue(iboKey, out int iboHandle))
{
return;
}
PrimitiveType mode = OglEnumConverter.GetPrimitiveType(primType);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, iboHandle);
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);
}
}
public bool TryGetVbo(long vboKey, out int vboHandle)
{
return _vboCache.TryGetValue(vboKey, out vboHandle);
}
}
}