aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Gal/OpenGL/OglRasterizer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics/Gal/OpenGL/OglRasterizer.cs')
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OglRasterizer.cs207
1 files changed, 207 insertions, 0 deletions
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglRasterizer.cs b/Ryujinx.Graphics/Gal/OpenGL/OglRasterizer.cs
new file mode 100644
index 00000000..c19911c5
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OglRasterizer.cs
@@ -0,0 +1,207 @@
+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);
+ }
+ }
+} \ No newline at end of file