aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Gal/OpenGL
diff options
context:
space:
mode:
authorAlex Barney <thealexbarney@gmail.com>2019-03-03 19:45:25 -0600
committerjduncanator <1518948+jduncanator@users.noreply.github.com>2019-03-04 12:45:25 +1100
commit1f554c1093dde6a4d3ed80fae2675abfb6c12fac (patch)
treebbbdfb87999168288777ac404081f3e49c7440ae /Ryujinx.Graphics/Gal/OpenGL
parent8e71ea0812f6b56ff819dbda951b463bcb5eb8dc (diff)
Do naming refactoring on Ryujinx.Graphics (#611)
* Renaming part 1 * Renaming part 2 * Renaming part 3 * Renaming part 4 * Renaming part 5 * Renaming part 6 * Renaming part 7 * Renaming part 8 * Renaming part 9 * Renaming part 10 * General cleanup * Thought I got all of these * Apply #595 * Additional renaming * Tweaks from feedback * Rename files
Diffstat (limited to 'Ryujinx.Graphics/Gal/OpenGL')
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/DeleteValueCallback.cs2
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs6
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs191
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs74
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs70
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLLimit.cs12
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs207
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs549
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs58
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs298
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLShaderProgram.cs86
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs381
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs191
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OglConstBuffer.cs74
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OglEnumConverter.cs (renamed from Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs)192
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OglExtension.cs70
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OglLimit.cs12
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OglPipeline.cs (renamed from Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs)490
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OglRasterizer.cs207
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OglRenderTarget.cs549
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OglRenderer.cs58
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OglShader.cs298
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs86
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OglStreamBuffer.cs (renamed from Ryujinx.Graphics/Gal/OpenGL/OGLStreamBuffer.cs)24
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs381
25 files changed, 2283 insertions, 2283 deletions
diff --git a/Ryujinx.Graphics/Gal/OpenGL/DeleteValueCallback.cs b/Ryujinx.Graphics/Gal/OpenGL/DeleteValueCallback.cs
index acd8d72f..63b626f1 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/DeleteValueCallback.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/DeleteValueCallback.cs
@@ -1,4 +1,4 @@
namespace Ryujinx.Graphics.Gal.OpenGL
{
- delegate void DeleteValue<T>(T Value);
+ delegate void DeleteValue<T>(T value);
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs
index 5714f3d8..d7f6f004 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs
@@ -18,10 +18,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public bool HasDepth => ImageUtils.HasDepth(Image.Format);
public bool HasStencil => ImageUtils.HasStencil(Image.Format);
- public ImageHandler(int Handle, GalImage Image)
+ public ImageHandler(int handle, GalImage image)
{
- this.Handle = Handle;
- this.Image = Image;
+ Handle = handle;
+ Image = image;
}
}
}
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs
deleted file mode 100644
index 6e17872b..00000000
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs
+++ /dev/null
@@ -1,191 +0,0 @@
-using Ryujinx.Common;
-using System;
-using System.Collections.Generic;
-
-namespace Ryujinx.Graphics.Gal.OpenGL
-{
- class OGLCachedResource<T>
- {
- public delegate void DeleteValue(T Value);
-
- private const int MinTimeDelta = 5 * 60000;
- private const int MaxRemovalsPerRun = 10;
-
- private struct CacheBucket
- {
- public T Value { get; private set; }
-
- public LinkedListNode<long> Node { get; private set; }
-
- public long DataSize { get; private set; }
-
- public long Timestamp { get; private set; }
-
- public CacheBucket(T Value, long DataSize, LinkedListNode<long> Node)
- {
- this.Value = Value;
- this.DataSize = DataSize;
- this.Node = Node;
-
- Timestamp = PerformanceCounter.ElapsedMilliseconds;
- }
- }
-
- private Dictionary<long, CacheBucket> Cache;
-
- private LinkedList<long> SortedCache;
-
- private DeleteValue DeleteValueCallback;
-
- private Queue<T> DeletePending;
-
- private bool Locked;
-
- private long MaxSize;
- private long TotalSize;
-
- public OGLCachedResource(DeleteValue DeleteValueCallback, long MaxSize)
- {
- this.MaxSize = MaxSize;
-
- if (DeleteValueCallback == null)
- {
- throw new ArgumentNullException(nameof(DeleteValueCallback));
- }
-
- this.DeleteValueCallback = DeleteValueCallback;
-
- Cache = new Dictionary<long, CacheBucket>();
-
- SortedCache = new LinkedList<long>();
-
- DeletePending = new Queue<T>();
- }
-
- public void Lock()
- {
- Locked = true;
- }
-
- public void Unlock()
- {
- Locked = false;
-
- while (DeletePending.TryDequeue(out T Value))
- {
- DeleteValueCallback(Value);
- }
-
- ClearCacheIfNeeded();
- }
-
- public void AddOrUpdate(long Key, T Value, long Size)
- {
- if (!Locked)
- {
- ClearCacheIfNeeded();
- }
-
- LinkedListNode<long> Node = SortedCache.AddLast(Key);
-
- CacheBucket NewBucket = new CacheBucket(Value, Size, Node);
-
- if (Cache.TryGetValue(Key, out CacheBucket Bucket))
- {
- if (Locked)
- {
- DeletePending.Enqueue(Bucket.Value);
- }
- else
- {
- DeleteValueCallback(Bucket.Value);
- }
-
- SortedCache.Remove(Bucket.Node);
-
- TotalSize -= Bucket.DataSize;
-
- Cache[Key] = NewBucket;
- }
- else
- {
- Cache.Add(Key, NewBucket);
- }
-
- TotalSize += Size;
- }
-
- public bool TryGetValue(long Key, out T Value)
- {
- if (Cache.TryGetValue(Key, out CacheBucket Bucket))
- {
- Value = Bucket.Value;
-
- SortedCache.Remove(Bucket.Node);
-
- LinkedListNode<long> Node = SortedCache.AddLast(Key);
-
- Cache[Key] = new CacheBucket(Value, Bucket.DataSize, Node);
-
- return true;
- }
-
- Value = default(T);
-
- return false;
- }
-
- public bool TryGetSize(long Key, out long Size)
- {
- if (Cache.TryGetValue(Key, out CacheBucket Bucket))
- {
- Size = Bucket.DataSize;
-
- return true;
- }
-
- Size = 0;
-
- return false;
- }
-
- private void ClearCacheIfNeeded()
- {
- long Timestamp = PerformanceCounter.ElapsedMilliseconds;
-
- int Count = 0;
-
- while (Count++ < MaxRemovalsPerRun)
- {
- LinkedListNode<long> Node = SortedCache.First;
-
- if (Node == null)
- {
- break;
- }
-
- CacheBucket Bucket = Cache[Node.Value];
-
- long TimeDelta = Timestamp - Bucket.Timestamp;
-
- if (TimeDelta <= MinTimeDelta && !UnderMemoryPressure())
- {
- break;
- }
-
- SortedCache.Remove(Node);
-
- Cache.Remove(Node.Value);
-
- DeleteValueCallback(Bucket.Value);
-
- TotalSize -= Bucket.DataSize;
- }
- }
-
- private bool UnderMemoryPressure()
- {
- return TotalSize >= MaxSize;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs
deleted file mode 100644
index a12681c7..00000000
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using OpenTK.Graphics.OpenGL;
-using System;
-
-namespace Ryujinx.Graphics.Gal.OpenGL
-{
- class OGLConstBuffer : IGalConstBuffer
- {
- private const long MaxConstBufferCacheSize = 64 * 1024 * 1024;
-
- private OGLCachedResource<OGLStreamBuffer> Cache;
-
- public OGLConstBuffer()
- {
- Cache = new OGLCachedResource<OGLStreamBuffer>(DeleteBuffer, MaxConstBufferCacheSize);
- }
-
- public void LockCache()
- {
- Cache.Lock();
- }
-
- public void UnlockCache()
- {
- Cache.Unlock();
- }
-
- public void Create(long Key, long Size)
- {
- OGLStreamBuffer Buffer = new OGLStreamBuffer(BufferTarget.UniformBuffer, Size);
-
- Cache.AddOrUpdate(Key, Buffer, Size);
- }
-
- public bool IsCached(long Key, long Size)
- {
- return Cache.TryGetSize(Key, out long CachedSize) && CachedSize == Size;
- }
-
- public void SetData(long Key, long Size, IntPtr HostAddress)
- {
- if (Cache.TryGetValue(Key, out OGLStreamBuffer Buffer))
- {
- Buffer.SetData(Size, HostAddress);
- }
- }
-
- public void SetData(long Key, byte[] Data)
- {
- if (Cache.TryGetValue(Key, out OGLStreamBuffer Buffer))
- {
- Buffer.SetData(Data);
- }
- }
-
- public bool TryGetUbo(long Key, out int UboHandle)
- {
- if (Cache.TryGetValue(Key, out OGLStreamBuffer Buffer))
- {
- UboHandle = Buffer.Handle;
-
- return true;
- }
-
- UboHandle = 0;
-
- return false;
- }
-
- private static void DeleteBuffer(OGLStreamBuffer Buffer)
- {
- Buffer.Dispose();
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs
deleted file mode 100644
index eb06f83c..00000000
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using OpenTK.Graphics.OpenGL;
-using Ryujinx.Common.Logging;
-using System;
-
-namespace Ryujinx.Graphics.Gal.OpenGL
-{
- static class OGLExtension
- {
- // Private lazy backing variables
- private static Lazy<bool> s_EnhancedLayouts = new Lazy<bool>(() => HasExtension("GL_ARB_enhanced_layouts"));
- private static Lazy<bool> s_TextureMirrorClamp = new Lazy<bool>(() => HasExtension("GL_EXT_texture_mirror_clamp"));
- private static Lazy<bool> s_ViewportArray = new Lazy<bool>(() => HasExtension("GL_ARB_viewport_array"));
-
- private static Lazy<bool> s_NvidiaDriver = new Lazy<bool>(() => IsNvidiaDriver());
-
- // Public accessors
- public static bool EnhancedLayouts => s_EnhancedLayouts.Value;
- public static bool TextureMirrorClamp => s_TextureMirrorClamp.Value;
- public static bool ViewportArray => s_ViewportArray.Value;
-
- public static bool NvidiaDrvier => s_NvidiaDriver.Value;
-
- private static bool HasExtension(string Name)
- {
- int NumExtensions = GL.GetInteger(GetPName.NumExtensions);
-
- for (int Extension = 0; Extension < NumExtensions; Extension++)
- {
- if (GL.GetString(StringNameIndexed.Extensions, Extension) == Name)
- {
- return true;
- }
- }
-
- Logger.PrintInfo(LogClass.Gpu, $"OpenGL extension {Name} unavailable. You may experience some performance degredation");
-
- return false;
- }
-
- private static bool IsNvidiaDriver()
- {
- return GL.GetString(StringName.Vendor).Equals("NVIDIA Corporation");
- }
-
- public static class Required
- {
- // Public accessors
- public static bool EnhancedLayouts => s_EnhancedLayoutsRequired.Value;
- public static bool TextureMirrorClamp => s_TextureMirrorClampRequired.Value;
- public static bool ViewportArray => s_ViewportArrayRequired.Value;
-
- // Private lazy backing variables
- private static Lazy<bool> s_EnhancedLayoutsRequired = new Lazy<bool>(() => HasExtensionRequired(OGLExtension.EnhancedLayouts, "GL_ARB_enhanced_layouts"));
- private static Lazy<bool> s_TextureMirrorClampRequired = new Lazy<bool>(() => HasExtensionRequired(OGLExtension.TextureMirrorClamp, "GL_EXT_texture_mirror_clamp"));
- private static Lazy<bool> s_ViewportArrayRequired = new Lazy<bool>(() => HasExtensionRequired(OGLExtension.ViewportArray, "GL_ARB_viewport_array"));
-
- private static bool HasExtensionRequired(bool Value, string Name)
- {
- if (Value)
- {
- return true;
- }
-
- Logger.PrintWarning(LogClass.Gpu, $"Required OpenGL extension {Name} unavailable. You may experience some rendering issues");
-
- return false;
- }
- }
- }
-}
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLLimit.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLLimit.cs
deleted file mode 100644
index 6c385bc4..00000000
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLLimit.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using OpenTK.Graphics.OpenGL;
-using System;
-
-namespace Ryujinx.Graphics.Gal.OpenGL
-{
- static class OGLLimit
- {
- private static Lazy<int> s_MaxUboSize = new Lazy<int>(() => GL.GetInteger(GetPName.MaxUniformBlockSize));
-
- public static int MaxUboSize => s_MaxUboSize.Value;
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs
deleted file mode 100644
index c4015d02..00000000
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs
+++ /dev/null
@@ -1,207 +0,0 @@
-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
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs
deleted file mode 100644
index 53cfd4a6..00000000
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs
+++ /dev/null
@@ -1,549 +0,0 @@
-using OpenTK.Graphics.OpenGL;
-using Ryujinx.Graphics.Texture;
-using System;
-
-namespace Ryujinx.Graphics.Gal.OpenGL
-{
- class OGLRenderTarget : IGalRenderTarget
- {
- private const int NativeWidth = 1280;
- private const int NativeHeight = 720;
-
- private const int RenderTargetsCount = GalPipelineState.RenderTargetsCount;
-
- private struct Rect
- {
- public int X { get; private set; }
- public int Y { get; private set; }
- public int Width { get; private set; }
- public int Height { get; private set; }
-
- public Rect(int X, int Y, int Width, int Height)
- {
- this.X = X;
- this.Y = Y;
- this.Width = Width;
- this.Height = Height;
- }
- }
-
- private class FrameBufferAttachments
- {
- public int MapCount { get; set; }
-
- public DrawBuffersEnum[] Map { get; private set; }
-
- public long[] Colors { get; private set; }
-
- public long Zeta { get; set; }
-
- public FrameBufferAttachments()
- {
- Colors = new long[RenderTargetsCount];
-
- Map = new DrawBuffersEnum[RenderTargetsCount];
- }
-
- public void Update(FrameBufferAttachments Source)
- {
- for (int Index = 0; Index < RenderTargetsCount; Index++)
- {
- Map[Index] = Source.Map[Index];
-
- Colors[Index] = Source.Colors[Index];
- }
-
- MapCount = Source.MapCount;
- Zeta = Source.Zeta;
- }
- }
-
- private int[] ColorHandles;
- private int ZetaHandle;
-
- private OGLTexture Texture;
-
- private ImageHandler ReadTex;
-
- private Rect Window;
-
- private float[] Viewports;
-
- private bool FlipX;
- private bool FlipY;
-
- private int CropTop;
- private int CropLeft;
- private int CropRight;
- private int CropBottom;
-
- //This framebuffer is used to attach guest rendertargets,
- //think of it as a dummy OpenGL VAO
- private int DummyFrameBuffer;
-
- //These framebuffers are used to blit images
- private int SrcFb;
- private int DstFb;
-
- private FrameBufferAttachments Attachments;
- private FrameBufferAttachments OldAttachments;
-
- private int CopyPBO;
-
- public bool FramebufferSrgb { get; set; }
-
- public OGLRenderTarget(OGLTexture Texture)
- {
- Attachments = new FrameBufferAttachments();
-
- OldAttachments = new FrameBufferAttachments();
-
- ColorHandles = new int[RenderTargetsCount];
-
- Viewports = new float[RenderTargetsCount * 4];
-
- this.Texture = Texture;
-
- Texture.TextureDeleted += TextureDeletionHandler;
- }
-
- private void TextureDeletionHandler(object Sender, int Handle)
- {
- //Texture was deleted, the handle is no longer valid, so
- //reset all uses of this handle on a render target.
- for (int Attachment = 0; Attachment < RenderTargetsCount; Attachment++)
- {
- if (ColorHandles[Attachment] == Handle)
- {
- ColorHandles[Attachment] = 0;
- }
- }
-
- if (ZetaHandle == Handle)
- {
- ZetaHandle = 0;
- }
- }
-
- public void Bind()
- {
- if (DummyFrameBuffer == 0)
- {
- DummyFrameBuffer = GL.GenFramebuffer();
- }
-
- GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
-
- ImageHandler CachedImage;
-
- for (int Attachment = 0; Attachment < RenderTargetsCount; Attachment++)
- {
- long Key = Attachments.Colors[Attachment];
-
- int Handle = 0;
-
- if (Key != 0 && Texture.TryGetImageHandler(Key, out CachedImage))
- {
- Handle = CachedImage.Handle;
- }
-
- if (Handle == ColorHandles[Attachment])
- {
- continue;
- }
-
- GL.FramebufferTexture(
- FramebufferTarget.DrawFramebuffer,
- FramebufferAttachment.ColorAttachment0 + Attachment,
- Handle,
- 0);
-
- ColorHandles[Attachment] = Handle;
- }
-
- if (Attachments.Zeta != 0 && Texture.TryGetImageHandler(Attachments.Zeta, out CachedImage))
- {
- if (CachedImage.Handle != ZetaHandle)
- {
- if (CachedImage.HasDepth && CachedImage.HasStencil)
- {
- GL.FramebufferTexture(
- FramebufferTarget.DrawFramebuffer,
- FramebufferAttachment.DepthStencilAttachment,
- CachedImage.Handle,
- 0);
- }
- else if (CachedImage.HasDepth)
- {
- GL.FramebufferTexture(
- FramebufferTarget.DrawFramebuffer,
- FramebufferAttachment.DepthAttachment,
- CachedImage.Handle,
- 0);
-
- GL.FramebufferTexture(
- FramebufferTarget.DrawFramebuffer,
- FramebufferAttachment.StencilAttachment,
- 0,
- 0);
- }
- else
- {
- throw new InvalidOperationException("Invalid image format \"" + CachedImage.Format + "\" used as Zeta!");
- }
-
- ZetaHandle = CachedImage.Handle;
- }
- }
- else if (ZetaHandle != 0)
- {
- GL.FramebufferTexture(
- FramebufferTarget.DrawFramebuffer,
- FramebufferAttachment.DepthStencilAttachment,
- 0,
- 0);
-
- ZetaHandle = 0;
- }
-
- if (OGLExtension.ViewportArray)
- {
- GL.ViewportArray(0, RenderTargetsCount, Viewports);
- }
- else
- {
- GL.Viewport(
- (int)Viewports[0],
- (int)Viewports[1],
- (int)Viewports[2],
- (int)Viewports[3]);
- }
-
- if (Attachments.MapCount > 1)
- {
- GL.DrawBuffers(Attachments.MapCount, Attachments.Map);
- }
- else if (Attachments.MapCount == 1)
- {
- GL.DrawBuffer((DrawBufferMode)Attachments.Map[0]);
- }
- else
- {
- GL.DrawBuffer(DrawBufferMode.None);
- }
-
- OldAttachments.Update(Attachments);
- }
-
- public void BindColor(long Key, int Attachment)
- {
- Attachments.Colors[Attachment] = Key;
- }
-
- public void UnbindColor(int Attachment)
- {
- Attachments.Colors[Attachment] = 0;
- }
-
- public void BindZeta(long Key)
- {
- Attachments.Zeta = Key;
- }
-
- public void UnbindZeta()
- {
- Attachments.Zeta = 0;
- }
-
- public void Present(long Key)
- {
- Texture.TryGetImageHandler(Key, out ReadTex);
- }
-
- public void SetMap(int[] Map)
- {
- if (Map != null)
- {
- Attachments.MapCount = Map.Length;
-
- for (int Attachment = 0; Attachment < Attachments.MapCount; Attachment++)
- {
- Attachments.Map[Attachment] = DrawBuffersEnum.ColorAttachment0 + Map[Attachment];
- }
- }
- else
- {
- Attachments.MapCount = 0;
- }
- }
-
- public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom)
- {
- this.FlipX = FlipX;
- this.FlipY = FlipY;
-
- CropTop = Top;
- CropLeft = Left;
- CropRight = Right;
- CropBottom = Bottom;
- }
-
- public void SetWindowSize(int Width, int Height)
- {
- Window = new Rect(0, 0, Width, Height);
- }
-
- public void SetViewport(int Attachment, int X, int Y, int Width, int Height)
- {
- int Offset = Attachment * 4;
-
- Viewports[Offset + 0] = X;
- Viewports[Offset + 1] = Y;
- Viewports[Offset + 2] = Width;
- Viewports[Offset + 3] = Height;
- }
-
- public void Render()
- {
- if (ReadTex == null)
- {
- return;
- }
-
- int SrcX0, SrcX1, SrcY0, SrcY1;
-
- if (CropLeft == 0 && CropRight == 0)
- {
- SrcX0 = 0;
- SrcX1 = ReadTex.Width;
- }
- else
- {
- SrcX0 = CropLeft;
- SrcX1 = CropRight;
- }
-
- if (CropTop == 0 && CropBottom == 0)
- {
- SrcY0 = 0;
- SrcY1 = ReadTex.Height;
- }
- else
- {
- SrcY0 = CropTop;
- SrcY1 = CropBottom;
- }
-
- float RatioX = MathF.Min(1f, (Window.Height * (float)NativeWidth) / ((float)NativeHeight * Window.Width));
- float RatioY = MathF.Min(1f, (Window.Width * (float)NativeHeight) / ((float)NativeWidth * Window.Height));
-
- int DstWidth = (int)(Window.Width * RatioX);
- int DstHeight = (int)(Window.Height * RatioY);
-
- int DstPaddingX = (Window.Width - DstWidth) / 2;
- int DstPaddingY = (Window.Height - DstHeight) / 2;
-
- int DstX0 = FlipX ? Window.Width - DstPaddingX : DstPaddingX;
- int DstX1 = FlipX ? DstPaddingX : Window.Width - DstPaddingX;
-
- int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY;
- int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY;
-
- GL.Viewport(0, 0, Window.Width, Window.Height);
-
- if (SrcFb == 0)
- {
- SrcFb = GL.GenFramebuffer();
- }
-
- GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
- GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
-
- GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, ReadTex.Handle, 0);
-
- GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
-
- GL.Clear(ClearBufferMask.ColorBufferBit);
-
- GL.Disable(EnableCap.FramebufferSrgb);
-
- GL.BlitFramebuffer(
- SrcX0,
- SrcY0,
- SrcX1,
- SrcY1,
- DstX0,
- DstY0,
- DstX1,
- DstY1,
- ClearBufferMask.ColorBufferBit,
- BlitFramebufferFilter.Linear);
-
- if (FramebufferSrgb)
- {
- GL.Enable(EnableCap.FramebufferSrgb);
- }
- }
-
- public void Copy(
- GalImage SrcImage,
- GalImage DstImage,
- long SrcKey,
- long DstKey,
- int SrcLayer,
- int DstLayer,
- int SrcX0,
- int SrcY0,
- int SrcX1,
- int SrcY1,
- int DstX0,
- int DstY0,
- int DstX1,
- int DstY1)
- {
- if (Texture.TryGetImageHandler(SrcKey, out ImageHandler SrcTex) &&
- Texture.TryGetImageHandler(DstKey, out ImageHandler DstTex))
- {
- if (SrcTex.HasColor != DstTex.HasColor ||
- SrcTex.HasDepth != DstTex.HasDepth ||
- SrcTex.HasStencil != DstTex.HasStencil)
- {
- throw new NotImplementedException();
- }
-
- if (SrcFb == 0)
- {
- SrcFb = GL.GenFramebuffer();
- }
-
- if (DstFb == 0)
- {
- DstFb = GL.GenFramebuffer();
- }
-
- GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb);
- GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb);
-
- FramebufferAttachment Attachment = GetAttachment(SrcTex);
-
- if (ImageUtils.IsArray(SrcImage.TextureTarget) && SrcLayer > 0)
- {
- GL.FramebufferTextureLayer(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0, SrcLayer);
- }
- else
- {
- GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0);
- }
-
- if (ImageUtils.IsArray(DstImage.TextureTarget) && DstLayer > 0)
- {
- GL.FramebufferTextureLayer(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0, DstLayer);
- }
- else
- {
- GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0);
- }
-
-
- BlitFramebufferFilter Filter = BlitFramebufferFilter.Nearest;
-
- if (SrcTex.HasColor)
- {
- GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
-
- Filter = BlitFramebufferFilter.Linear;
- }
-
- ClearBufferMask Mask = GetClearMask(SrcTex);
-
- GL.BlitFramebuffer(SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, Mask, Filter);
- }
- }
-
- public void Reinterpret(long Key, GalImage NewImage)
- {
- if (!Texture.TryGetImage(Key, out GalImage OldImage))
- {
- return;
- }
-
- if (NewImage.Format == OldImage.Format &&
- NewImage.Width == OldImage.Width &&
- NewImage.Height == OldImage.Height &&
- NewImage.Depth == OldImage.Depth &&
- NewImage.LayerCount == OldImage.LayerCount &&
- NewImage.TextureTarget == OldImage.TextureTarget)
- {
- return;
- }
-
- if (CopyPBO == 0)
- {
- CopyPBO = GL.GenBuffer();
- }
-
- GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyPBO);
-
- //The buffer should be large enough to hold the largest texture.
- int BufferSize = Math.Max(ImageUtils.GetSize(OldImage),
- ImageUtils.GetSize(NewImage));
-
- GL.BufferData(BufferTarget.PixelPackBuffer, BufferSize, IntPtr.Zero, BufferUsageHint.StreamCopy);
-
- if (!Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
- {
- throw new InvalidOperationException();
- }
-
- (_, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(CachedImage.Format);
-
- TextureTarget Target = ImageUtils.GetTextureTarget(NewImage.TextureTarget);
-
- GL.BindTexture(Target, CachedImage.Handle);
-
- GL.GetTexImage(Target, 0, Format, Type, IntPtr.Zero);
-
- GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
- GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyPBO);
-
- GL.PixelStore(PixelStoreParameter.UnpackRowLength, OldImage.Width);
-
- Texture.Create(Key, ImageUtils.GetSize(NewImage), NewImage);
-
- GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0);
-
- GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0);
- }
-
- private static FramebufferAttachment GetAttachment(ImageHandler CachedImage)
- {
- if (CachedImage.HasColor)
- {
- return FramebufferAttachment.ColorAttachment0;
- }
- else if (CachedImage.HasDepth && CachedImage.HasStencil)
- {
- return FramebufferAttachment.DepthStencilAttachment;
- }
- else if (CachedImage.HasDepth)
- {
- return FramebufferAttachment.DepthAttachment;
- }
- else if (CachedImage.HasStencil)
- {
- return FramebufferAttachment.StencilAttachment;
- }
- else
- {
- throw new InvalidOperationException();
- }
- }
-
- private static ClearBufferMask GetClearMask(ImageHandler CachedImage)
- {
- return (CachedImage.HasColor ? ClearBufferMask.ColorBufferBit : 0) |
- (CachedImage.HasDepth ? ClearBufferMask.DepthBufferBit : 0) |
- (CachedImage.HasStencil ? ClearBufferMask.StencilBufferBit : 0);
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs
deleted file mode 100644
index 14fb9018..00000000
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-
-namespace Ryujinx.Graphics.Gal.OpenGL
-{
- public class OGLRenderer : IGalRenderer
- {
- public IGalConstBuffer Buffer { get; private set; }
-
- public IGalRenderTarget RenderTarget { get; private set; }
-
- public IGalRasterizer Rasterizer { get; private set; }
-
- public IGalShader Shader { get; private set; }
-
- public IGalPipeline Pipeline { get; private set; }
-
- public IGalTexture Texture { get; private set; }
-
- private ConcurrentQueue<Action> ActionsQueue;
-
- public OGLRenderer()
- {
- Buffer = new OGLConstBuffer();
-
- Texture = new OGLTexture();
-
- RenderTarget = new OGLRenderTarget(Texture as OGLTexture);
-
- Rasterizer = new OGLRasterizer();
-
- Shader = new OGLShader(Buffer as OGLConstBuffer);
-
- Pipeline = new OGLPipeline(
- Buffer as OGLConstBuffer,
- RenderTarget as OGLRenderTarget,
- Rasterizer as OGLRasterizer,
- Shader as OGLShader);
-
- ActionsQueue = new ConcurrentQueue<Action>();
- }
-
- public void QueueAction(Action ActionMthd)
- {
- ActionsQueue.Enqueue(ActionMthd);
- }
-
- public void RunActions()
- {
- int Count = ActionsQueue.Count;
-
- while (Count-- > 0 && ActionsQueue.TryDequeue(out Action RenderAction))
- {
- RenderAction();
- }
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
deleted file mode 100644
index dc168ff9..00000000
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
+++ /dev/null
@@ -1,298 +0,0 @@
-using OpenTK.Graphics.OpenGL;
-using Ryujinx.Graphics.Gal.Shader;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Ryujinx.Graphics.Gal.OpenGL
-{
- class OGLShader : IGalShader
- {
- public const int ReservedCbufCount = 1;
-
- private const int ExtraDataSize = 4;
-
- public OGLShaderProgram Current;
-
- private ConcurrentDictionary<long, OGLShaderStage> Stages;
-
- private Dictionary<OGLShaderProgram, int> Programs;
-
- public int CurrentProgramHandle { get; private set; }
-
- private OGLConstBuffer Buffer;
-
- private int ExtraUboHandle;
-
- public OGLShader(OGLConstBuffer Buffer)
- {
- this.Buffer = Buffer;
-
- Stages = new ConcurrentDictionary<long, OGLShaderStage>();
-
- Programs = new Dictionary<OGLShaderProgram, int>();
- }
-
- public void Create(IGalMemory Memory, long Key, GalShaderType Type)
- {
- Stages.GetOrAdd(Key, (Stage) => ShaderStageFactory(Memory, Key, 0, false, Type));
- }
-
- public void Create(IGalMemory Memory, long VpAPos, long Key, GalShaderType Type)
- {
- Stages.GetOrAdd(Key, (Stage) => ShaderStageFactory(Memory, VpAPos, Key, true, Type));
- }
-
- private OGLShaderStage ShaderStageFactory(
- IGalMemory Memory,
- long Position,
- long PositionB,
- bool IsDualVp,
- GalShaderType Type)
- {
- GlslProgram Program;
-
- GlslDecompiler Decompiler = new GlslDecompiler(OGLLimit.MaxUboSize, OGLExtension.NvidiaDrvier);
-
- int ShaderDumpIndex = ShaderDumper.DumpIndex;
-
- if (IsDualVp)
- {
- ShaderDumper.Dump(Memory, Position, Type, "a");
- ShaderDumper.Dump(Memory, PositionB, Type, "b");
-
- Program = Decompiler.Decompile(Memory, Position, PositionB, Type);
- }
- else
- {
- ShaderDumper.Dump(Memory, Position, Type);
-
- Program = Decompiler.Decompile(Memory, Position, Type);
- }
-
- string Code = Program.Code;
-
- if (ShaderDumper.IsDumpEnabled())
- {
- Code = "//Shader " + ShaderDumpIndex + Environment.NewLine + Code;
- }
-
- return new OGLShaderStage(Type, Code, Program.Uniforms, Program.Textures);
- }
-
- public IEnumerable<ShaderDeclInfo> GetConstBufferUsage(long Key)
- {
- if (Stages.TryGetValue(Key, out OGLShaderStage Stage))
- {
- return Stage.ConstBufferUsage;
- }
-
- return Enumerable.Empty<ShaderDeclInfo>();
- }
-
- public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Key)
- {
- if (Stages.TryGetValue(Key, out OGLShaderStage Stage))
- {
- return Stage.TextureUsage;
- }
-
- return Enumerable.Empty<ShaderDeclInfo>();
- }
-
- public unsafe void SetExtraData(float FlipX, float FlipY, int Instance)
- {
- BindProgram();
-
- EnsureExtraBlock();
-
- GL.BindBuffer(BufferTarget.UniformBuffer, ExtraUboHandle);
-
- float* Data = stackalloc float[ExtraDataSize];
- Data[0] = FlipX;
- Data[1] = FlipY;
- Data[2] = BitConverter.Int32BitsToSingle(Instance);
-
- //Invalidate buffer
- GL.BufferData(BufferTarget.UniformBuffer, ExtraDataSize * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw);
-
- GL.BufferSubData(BufferTarget.UniformBuffer, IntPtr.Zero, ExtraDataSize * sizeof(float), (IntPtr)Data);
- }
-
- public void Bind(long Key)
- {
- if (Stages.TryGetValue(Key, out OGLShaderStage Stage))
- {
- Bind(Stage);
- }
- }
-
- private void Bind(OGLShaderStage Stage)
- {
- if (Stage.Type == GalShaderType.Geometry)
- {
- //Enhanced layouts are required for Geometry shaders
- //skip this stage if current driver has no ARB_enhanced_layouts
- if (!OGLExtension.EnhancedLayouts)
- {
- return;
- }
- }
-
- switch (Stage.Type)
- {
- case GalShaderType.Vertex: Current.Vertex = Stage; break;
- case GalShaderType.TessControl: Current.TessControl = Stage; break;
- case GalShaderType.TessEvaluation: Current.TessEvaluation = Stage; break;
- case GalShaderType.Geometry: Current.Geometry = Stage; break;
- case GalShaderType.Fragment: Current.Fragment = Stage; break;
- }
- }
-
- public void Unbind(GalShaderType Type)
- {
- switch (Type)
- {
- case GalShaderType.Vertex: Current.Vertex = null; break;
- case GalShaderType.TessControl: Current.TessControl = null; break;
- case GalShaderType.TessEvaluation: Current.TessEvaluation = null; break;
- case GalShaderType.Geometry: Current.Geometry = null; break;
- case GalShaderType.Fragment: Current.Fragment = null; break;
- }
- }
-
- public void BindProgram()
- {
- if (Current.Vertex == null ||
- Current.Fragment == null)
- {
- return;
- }
-
- if (!Programs.TryGetValue(Current, out int Handle))
- {
- Handle = GL.CreateProgram();
-
- AttachIfNotNull(Handle, Current.Vertex);
- AttachIfNotNull(Handle, Current.TessControl);
- AttachIfNotNull(Handle, Current.TessEvaluation);
- AttachIfNotNull(Handle, Current.Geometry);
- AttachIfNotNull(Handle, Current.Fragment);
-
- GL.LinkProgram(Handle);
-
- CheckProgramLink(Handle);
-
- BindUniformBlocks(Handle);
- BindTextureLocations(Handle);
-
- Programs.Add(Current, Handle);
- }
-
- GL.UseProgram(Handle);
-
- CurrentProgramHandle = Handle;
- }
-
- private void EnsureExtraBlock()
- {
- if (ExtraUboHandle == 0)
- {
- ExtraUboHandle = GL.GenBuffer();
-
- GL.BindBuffer(BufferTarget.UniformBuffer, ExtraUboHandle);
-
- GL.BufferData(BufferTarget.UniformBuffer, ExtraDataSize * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw);
-
- GL.BindBufferBase(BufferRangeTarget.UniformBuffer, 0, ExtraUboHandle);
- }
- }
-
- private void AttachIfNotNull(int ProgramHandle, OGLShaderStage Stage)
- {
- if (Stage != null)
- {
- Stage.Compile();
-
- GL.AttachShader(ProgramHandle, Stage.Handle);
- }
- }
-
- private void BindUniformBlocks(int ProgramHandle)
- {
- int ExtraBlockindex = GL.GetUniformBlockIndex(ProgramHandle, GlslDecl.ExtraUniformBlockName);
-
- GL.UniformBlockBinding(ProgramHandle, ExtraBlockindex, 0);
-
- int FreeBinding = ReservedCbufCount;
-
- void BindUniformBlocksIfNotNull(OGLShaderStage Stage)
- {
- if (Stage != null)
- {
- foreach (ShaderDeclInfo DeclInfo in Stage.ConstBufferUsage)
- {
- int BlockIndex = GL.GetUniformBlockIndex(ProgramHandle, DeclInfo.Name);
-
- if (BlockIndex < 0)
- {
- //It is expected that its found, if it's not then driver might be in a malfunction
- throw new InvalidOperationException();
- }
-
- GL.UniformBlockBinding(ProgramHandle, BlockIndex, FreeBinding);
-
- FreeBinding++;
- }
- }
- }
-
- BindUniformBlocksIfNotNull(Current.Vertex);
- BindUniformBlocksIfNotNull(Current.TessControl);
- BindUniformBlocksIfNotNull(Current.TessEvaluation);
- BindUniformBlocksIfNotNull(Current.Geometry);
- BindUniformBlocksIfNotNull(Current.Fragment);
- }
-
- private void BindTextureLocations(int ProgramHandle)
- {
- int Index = 0;
-
- void BindTexturesIfNotNull(OGLShaderStage Stage)
- {
- if (Stage != null)
- {
- foreach (ShaderDeclInfo Decl in Stage.TextureUsage)
- {
- int Location = GL.GetUniformLocation(ProgramHandle, Decl.Name);
-
- GL.Uniform1(Location, Index);
-
- Index++;
- }
- }
- }
-
- GL.UseProgram(ProgramHandle);
-
- BindTexturesIfNotNull(Current.Vertex);
- BindTexturesIfNotNull(Current.TessControl);
- BindTexturesIfNotNull(Current.TessEvaluation);
- BindTexturesIfNotNull(Current.Geometry);
- BindTexturesIfNotNull(Current.Fragment);
- }
-
- private static void CheckProgramLink(int Handle)
- {
- int Status = 0;
-
- GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out Status);
-
- if (Status == 0)
- {
- throw new ShaderException(GL.GetProgramInfoLog(Handle));
- }
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShaderProgram.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShaderProgram.cs
deleted file mode 100644
index c87b0d40..00000000
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLShaderProgram.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-using OpenTK.Graphics.OpenGL;
-using System;
-using System.Collections.Generic;
-
-namespace Ryujinx.Graphics.Gal.OpenGL
-{
- struct OGLShaderProgram
- {
- public OGLShaderStage Vertex;
- public OGLShaderStage TessControl;
- public OGLShaderStage TessEvaluation;
- public OGLShaderStage Geometry;
- public OGLShaderStage Fragment;
- }
-
- class OGLShaderStage : IDisposable
- {
- public int Handle { get; private set; }
-
- public bool IsCompiled { get; private set; }
-
- public GalShaderType Type { get; private set; }
-
- public string Code { get; private set; }
-
- public IEnumerable<ShaderDeclInfo> ConstBufferUsage { get; private set; }
- public IEnumerable<ShaderDeclInfo> TextureUsage { get; private set; }
-
- public OGLShaderStage(
- GalShaderType Type,
- string Code,
- IEnumerable<ShaderDeclInfo> ConstBufferUsage,
- IEnumerable<ShaderDeclInfo> TextureUsage)
- {
- this.Type = Type;
- this.Code = Code;
- this.ConstBufferUsage = ConstBufferUsage;
- this.TextureUsage = TextureUsage;
- }
-
- public void Compile()
- {
- if (Handle == 0)
- {
- Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type));
-
- CompileAndCheck(Handle, Code);
- }
- }
-
- public void Dispose()
- {
- Dispose(true);
- }
-
- protected virtual void Dispose(bool Disposing)
- {
- if (Disposing && Handle != 0)
- {
- GL.DeleteShader(Handle);
-
- Handle = 0;
- }
- }
-
- public static void CompileAndCheck(int Handle, string Code)
- {
- GL.ShaderSource(Handle, Code);
- GL.CompileShader(Handle);
-
- CheckCompilation(Handle);
- }
-
- private static void CheckCompilation(int Handle)
- {
- int Status = 0;
-
- GL.GetShader(Handle, ShaderParameter.CompileStatus, out Status);
-
- if (Status == 0)
- {
- throw new ShaderException(GL.GetShaderInfoLog(Handle));
- }
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
deleted file mode 100644
index 4fef11d2..00000000
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
+++ /dev/null
@@ -1,381 +0,0 @@
-using OpenTK.Graphics.OpenGL;
-using Ryujinx.Graphics.Texture;
-using System;
-
-namespace Ryujinx.Graphics.Gal.OpenGL
-{
- class OGLTexture : IGalTexture
- {
- private const long MaxTextureCacheSize = 768 * 1024 * 1024;
-
- private OGLCachedResource<ImageHandler> TextureCache;
-
- public EventHandler<int> TextureDeleted { get; set; }
-
- public OGLTexture()
- {
- TextureCache = new OGLCachedResource<ImageHandler>(DeleteTexture, MaxTextureCacheSize);
- }
-
- public void LockCache()
- {
- TextureCache.Lock();
- }
-
- public void UnlockCache()
- {
- TextureCache.Unlock();
- }
-
- private void DeleteTexture(ImageHandler CachedImage)
- {
- TextureDeleted?.Invoke(this, CachedImage.Handle);
-
- GL.DeleteTexture(CachedImage.Handle);
- }
-
- public void Create(long Key, int Size, GalImage Image)
- {
- int Handle = GL.GenTexture();
-
- TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget);
-
- GL.BindTexture(Target, Handle);
-
- const int Level = 0; //TODO: Support mipmap textures.
- const int Border = 0;
-
- TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Size);
-
- if (ImageUtils.IsCompressed(Image.Format))
- {
- throw new InvalidOperationException("Surfaces with compressed formats are not supported!");
- }
-
- (PixelInternalFormat InternalFmt,
- PixelFormat Format,
- PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
-
- switch (Target)
- {
- case TextureTarget.Texture1D:
- GL.TexImage1D(
- Target,
- Level,
- InternalFmt,
- Image.Width,
- Border,
- Format,
- Type,
- IntPtr.Zero);
- break;
-
- case TextureTarget.Texture2D:
- GL.TexImage2D(
- Target,
- Level,
- InternalFmt,
- Image.Width,
- Image.Height,
- Border,
- Format,
- Type,
- IntPtr.Zero);
- break;
- case TextureTarget.Texture3D:
- GL.TexImage3D(
- Target,
- Level,
- InternalFmt,
- Image.Width,
- Image.Height,
- Image.Depth,
- Border,
- Format,
- Type,
- IntPtr.Zero);
- break;
- case TextureTarget.Texture2DArray:
- GL.TexImage3D(
- Target,
- Level,
- InternalFmt,
- Image.Width,
- Image.Height,
- Image.LayerCount,
- Border,
- Format,
- Type,
- IntPtr.Zero);
- break;
- default:
- throw new NotImplementedException($"Unsupported texture target type: {Target}");
- }
- }
-
- public void Create(long Key, byte[] Data, GalImage Image)
- {
- int Handle = GL.GenTexture();
-
- TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget);
-
- GL.BindTexture(Target, Handle);
-
- const int Level = 0; //TODO: Support mipmap textures.
- const int Border = 0;
-
- TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length);
-
- if (ImageUtils.IsCompressed(Image.Format) && !IsAstc(Image.Format))
- {
- InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format);
-
- switch (Target)
- {
- case TextureTarget.Texture1D:
- GL.CompressedTexImage1D(
- Target,
- Level,
- InternalFmt,
- Image.Width,
- Border,
- Data.Length,
- Data);
- break;
- case TextureTarget.Texture2D:
- GL.CompressedTexImage2D(
- Target,
- Level,
- InternalFmt,
- Image.Width,
- Image.Height,
- Border,
- Data.Length,
- Data);
- break;
- case TextureTarget.Texture3D:
- GL.CompressedTexImage3D(
- Target,
- Level,
- InternalFmt,
- Image.Width,
- Image.Height,
- Image.Depth,
- Border,
- Data.Length,
- Data);
- break;
- case TextureTarget.Texture2DArray:
- GL.CompressedTexImage3D(
- Target,
- Level,
- InternalFmt,
- Image.Width,
- Image.Height,
- Image.LayerCount,
- Border,
- Data.Length,
- Data);
- break;
- default:
- throw new NotImplementedException($"Unsupported texture target type: {Target}");
- }
- }
- else
- {
- //TODO: Use KHR_texture_compression_astc_hdr when available
- if (IsAstc(Image.Format))
- {
- int TextureBlockWidth = ImageUtils.GetBlockWidth(Image.Format);
- int TextureBlockHeight = ImageUtils.GetBlockHeight(Image.Format);
- int TextureBlockDepth = ImageUtils.GetBlockDepth(Image.Format);
-
- Data = ASTCDecoder.DecodeToRGBA8888(
- Data,
- TextureBlockWidth,
- TextureBlockHeight,
- TextureBlockDepth,
- Image.Width,
- Image.Height,
- Image.Depth);
-
- Image.Format = GalImageFormat.RGBA8 | (Image.Format & GalImageFormat.TypeMask);
- }
-
- (PixelInternalFormat InternalFmt,
- PixelFormat Format,
- PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
-
-
- switch (Target)
- {
- case TextureTarget.Texture1D:
- GL.TexImage1D(
- Target,
- Level,
- InternalFmt,
- Image.Width,
- Border,
- Format,
- Type,
- Data);
- break;
- case TextureTarget.Texture2D:
- GL.TexImage2D(
- Target,
- Level,
- InternalFmt,
- Image.Width,
- Image.Height,
- Border,
- Format,
- Type,
- Data);
- break;
- case TextureTarget.Texture3D:
- GL.TexImage3D(
- Target,
- Level,
- InternalFmt,
- Image.Width,
- Image.Height,
- Image.Depth,
- Border,
- Format,
- Type,
- Data);
- break;
- case TextureTarget.Texture2DArray:
- GL.TexImage3D(
- Target,
- Level,
- InternalFmt,
- Image.Width,
- Image.Height,
- Image.LayerCount,
- Border,
- Format,
- Type,
- Data);
- break;
- case TextureTarget.TextureCubeMap:
- Span<byte> Array = new Span<byte>(Data);
-
- int FaceSize = ImageUtils.GetSize(Image) / 6;
-
- for (int Face = 0; Face < 6; Face++)
- {
- GL.TexImage2D(
- TextureTarget.TextureCubeMapPositiveX + Face,
- Level,
- InternalFmt,
- Image.Width,
- Image.Height,
- Border,
- Format,
- Type,
- Array.Slice(Face * FaceSize, FaceSize).ToArray());
- }
- break;
- default:
- throw new NotImplementedException($"Unsupported texture target type: {Target}");
- }
- }
- }
-
- private static bool IsAstc(GalImageFormat Format)
- {
- Format &= GalImageFormat.FormatMask;
-
- return Format > GalImageFormat.Astc2DStart && Format < GalImageFormat.Astc2DEnd;
- }
-
- public bool TryGetImage(long Key, out GalImage Image)
- {
- if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
- {
- Image = CachedImage.Image;
-
- return true;
- }
-
- Image = default(GalImage);
-
- return false;
- }
-
- public bool TryGetImageHandler(long Key, out ImageHandler CachedImage)
- {
- if (TextureCache.TryGetValue(Key, out CachedImage))
- {
- return true;
- }
-
- CachedImage = null;
-
- return false;
- }
-
- public void Bind(long Key, int Index, GalImage Image)
- {
- if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
- {
- GL.ActiveTexture(TextureUnit.Texture0 + Index);
-
- TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget);
-
- GL.BindTexture(Target, CachedImage.Handle);
-
- int[] SwizzleRgba = new int[]
- {
- (int)OGLEnumConverter.GetTextureSwizzle(Image.XSource),
- (int)OGLEnumConverter.GetTextureSwizzle(Image.YSource),
- (int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource),
- (int)OGLEnumConverter.GetTextureSwizzle(Image.WSource)
- };
-
- GL.TexParameter(Target, TextureParameterName.TextureSwizzleRgba, SwizzleRgba);
- }
- }
-
- public void SetSampler(GalImage Image, GalTextureSampler Sampler)
- {
- int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU);
- int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV);
- int WrapR = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressP);
-
- int MinFilter = (int)OGLEnumConverter.GetTextureMinFilter(Sampler.MinFilter, Sampler.MipFilter);
- int MagFilter = (int)OGLEnumConverter.GetTextureMagFilter(Sampler.MagFilter);
-
- TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget);
-
- GL.TexParameter(Target, TextureParameterName.TextureWrapS, WrapS);
- GL.TexParameter(Target, TextureParameterName.TextureWrapT, WrapT);
- GL.TexParameter(Target, TextureParameterName.TextureWrapR, WrapR);
-
- GL.TexParameter(Target, TextureParameterName.TextureMinFilter, MinFilter);
- GL.TexParameter(Target, TextureParameterName.TextureMagFilter, MagFilter);
-
- float[] Color = new float[]
- {
- Sampler.BorderColor.Red,
- Sampler.BorderColor.Green,
- Sampler.BorderColor.Blue,
- Sampler.BorderColor.Alpha
- };
-
- GL.TexParameter(Target, TextureParameterName.TextureBorderColor, Color);
-
- if (Sampler.DepthCompare)
- {
- GL.TexParameter(Target, TextureParameterName.TextureCompareMode, (int)All.CompareRToTexture);
- GL.TexParameter(Target, TextureParameterName.TextureCompareFunc, (int)OGLEnumConverter.GetDepthCompareFunc(Sampler.DepthCompareFunc));
- }
- else
- {
- GL.TexParameter(Target, TextureParameterName.TextureCompareMode, (int)All.None);
- GL.TexParameter(Target, TextureParameterName.TextureCompareFunc, (int)All.Never);
- }
- }
- }
-}
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs b/Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs
new file mode 100644
index 00000000..91f0a7e1
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs
@@ -0,0 +1,191 @@
+using Ryujinx.Common;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ class OglCachedResource<T>
+ {
+ public delegate void DeleteValue(T value);
+
+ private const int MinTimeDelta = 5 * 60000;
+ private const int MaxRemovalsPerRun = 10;
+
+ private struct CacheBucket
+ {
+ public T Value { get; private set; }
+
+ public LinkedListNode<long> Node { get; private set; }
+
+ public long DataSize { get; private set; }
+
+ public long Timestamp { get; private set; }
+
+ public CacheBucket(T value, long dataSize, LinkedListNode<long> node)
+ {
+ Value = value;
+ DataSize = dataSize;
+ Node = node;
+
+ Timestamp = PerformanceCounter.ElapsedMilliseconds;
+ }
+ }
+
+ private Dictionary<long, CacheBucket> _cache;
+
+ private LinkedList<long> _sortedCache;
+
+ private DeleteValue _deleteValueCallback;
+
+ private Queue<T> _deletePending;
+
+ private bool _locked;
+
+ private long _maxSize;
+ private long _totalSize;
+
+ public OglCachedResource(DeleteValue deleteValueCallback, long maxSize)
+ {
+ _maxSize = maxSize;
+
+ if (deleteValueCallback == null)
+ {
+ throw new ArgumentNullException(nameof(deleteValueCallback));
+ }
+
+ _deleteValueCallback = deleteValueCallback;
+
+ _cache = new Dictionary<long, CacheBucket>();
+
+ _sortedCache = new LinkedList<long>();
+
+ _deletePending = new Queue<T>();
+ }
+
+ public void Lock()
+ {
+ _locked = true;
+ }
+
+ public void Unlock()
+ {
+ _locked = false;
+
+ while (_deletePending.TryDequeue(out T value))
+ {
+ _deleteValueCallback(value);
+ }
+
+ ClearCacheIfNeeded();
+ }
+
+ public void AddOrUpdate(long key, T value, long size)
+ {
+ if (!_locked)
+ {
+ ClearCacheIfNeeded();
+ }
+
+ LinkedListNode<long> node = _sortedCache.AddLast(key);
+
+ CacheBucket newBucket = new CacheBucket(value, size, node);
+
+ if (_cache.TryGetValue(key, out CacheBucket bucket))
+ {
+ if (_locked)
+ {
+ _deletePending.Enqueue(bucket.Value);
+ }
+ else
+ {
+ _deleteValueCallback(bucket.Value);
+ }
+
+ _sortedCache.Remove(bucket.Node);
+
+ _totalSize -= bucket.DataSize;
+
+ _cache[key] = newBucket;
+ }
+ else
+ {
+ _cache.Add(key, newBucket);
+ }
+
+ _totalSize += size;
+ }
+
+ public bool TryGetValue(long key, out T value)
+ {
+ if (_cache.TryGetValue(key, out CacheBucket bucket))
+ {
+ value = bucket.Value;
+
+ _sortedCache.Remove(bucket.Node);
+
+ LinkedListNode<long> node = _sortedCache.AddLast(key);
+
+ _cache[key] = new CacheBucket(value, bucket.DataSize, node);
+
+ return true;
+ }
+
+ value = default(T);
+
+ return false;
+ }
+
+ public bool TryGetSize(long key, out long size)
+ {
+ if (_cache.TryGetValue(key, out CacheBucket bucket))
+ {
+ size = bucket.DataSize;
+
+ return true;
+ }
+
+ size = 0;
+
+ return false;
+ }
+
+ private void ClearCacheIfNeeded()
+ {
+ long timestamp = PerformanceCounter.ElapsedMilliseconds;
+
+ int count = 0;
+
+ while (count++ < MaxRemovalsPerRun)
+ {
+ LinkedListNode<long> node = _sortedCache.First;
+
+ if (node == null)
+ {
+ break;
+ }
+
+ CacheBucket bucket = _cache[node.Value];
+
+ long timeDelta = timestamp - bucket.Timestamp;
+
+ if (timeDelta <= MinTimeDelta && !UnderMemoryPressure())
+ {
+ break;
+ }
+
+ _sortedCache.Remove(node);
+
+ _cache.Remove(node.Value);
+
+ _deleteValueCallback(bucket.Value);
+
+ _totalSize -= bucket.DataSize;
+ }
+ }
+
+ private bool UnderMemoryPressure()
+ {
+ return _totalSize >= _maxSize;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglConstBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OglConstBuffer.cs
new file mode 100644
index 00000000..e076be33
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OglConstBuffer.cs
@@ -0,0 +1,74 @@
+using OpenTK.Graphics.OpenGL;
+using System;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ class OglConstBuffer : IGalConstBuffer
+ {
+ private const long MaxConstBufferCacheSize = 64 * 1024 * 1024;
+
+ private OglCachedResource<OglStreamBuffer> _cache;
+
+ public OglConstBuffer()
+ {
+ _cache = new OglCachedResource<OglStreamBuffer>(DeleteBuffer, MaxConstBufferCacheSize);
+ }
+
+ public void LockCache()
+ {
+ _cache.Lock();
+ }
+
+ public void UnlockCache()
+ {
+ _cache.Unlock();
+ }
+
+ public void Create(long key, long size)
+ {
+ OglStreamBuffer buffer = new OglStreamBuffer(BufferTarget.UniformBuffer, size);
+
+ _cache.AddOrUpdate(key, buffer, size);
+ }
+
+ public bool IsCached(long key, long size)
+ {
+ return _cache.TryGetSize(key, out long cachedSize) && cachedSize == size;
+ }
+
+ public void SetData(long key, long size, IntPtr hostAddress)
+ {
+ if (_cache.TryGetValue(key, out OglStreamBuffer buffer))
+ {
+ buffer.SetData(size, hostAddress);
+ }
+ }
+
+ public void SetData(long key, byte[] data)
+ {
+ if (_cache.TryGetValue(key, out OglStreamBuffer buffer))
+ {
+ buffer.SetData(data);
+ }
+ }
+
+ public bool TryGetUbo(long key, out int uboHandle)
+ {
+ if (_cache.TryGetValue(key, out OglStreamBuffer buffer))
+ {
+ uboHandle = buffer.Handle;
+
+ return true;
+ }
+
+ uboHandle = 0;
+
+ return false;
+ }
+
+ private static void DeleteBuffer(OglStreamBuffer buffer)
+ {
+ buffer.Dispose();
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OglEnumConverter.cs
index 3a25fff7..a3f9957f 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OglEnumConverter.cs
@@ -3,34 +3,34 @@ using System;
namespace Ryujinx.Graphics.Gal.OpenGL
{
- static class OGLEnumConverter
+ static class OglEnumConverter
{
- public static FrontFaceDirection GetFrontFace(GalFrontFace FrontFace)
+ public static FrontFaceDirection GetFrontFace(GalFrontFace frontFace)
{
- switch (FrontFace)
+ switch (frontFace)
{
- case GalFrontFace.CW: return FrontFaceDirection.Cw;
- case GalFrontFace.CCW: return FrontFaceDirection.Ccw;
+ case GalFrontFace.Cw: return FrontFaceDirection.Cw;
+ case GalFrontFace.Ccw: return FrontFaceDirection.Ccw;
}
- throw new ArgumentException(nameof(FrontFace) + " \"" + FrontFace + "\" is not valid!");
+ throw new ArgumentException(nameof(frontFace) + " \"" + frontFace + "\" is not valid!");
}
- public static CullFaceMode GetCullFace(GalCullFace CullFace)
+ public static CullFaceMode GetCullFace(GalCullFace cullFace)
{
- switch (CullFace)
+ switch (cullFace)
{
case GalCullFace.Front: return CullFaceMode.Front;
case GalCullFace.Back: return CullFaceMode.Back;
case GalCullFace.FrontAndBack: return CullFaceMode.FrontAndBack;
}
- throw new ArgumentException(nameof(CullFace) + " \"" + CullFace + "\" is not valid!");
+ throw new ArgumentException(nameof(cullFace) + " \"" + cullFace + "\" is not valid!");
}
- public static StencilOp GetStencilOp(GalStencilOp Op)
+ public static StencilOp GetStencilOp(GalStencilOp op)
{
- switch (Op)
+ switch (op)
{
case GalStencilOp.Keep: return StencilOp.Keep;
case GalStencilOp.Zero: return StencilOp.Zero;
@@ -42,28 +42,28 @@ namespace Ryujinx.Graphics.Gal.OpenGL
case GalStencilOp.DecrWrap: return StencilOp.DecrWrap;
}
- throw new ArgumentException(nameof(Op) + " \"" + Op + "\" is not valid!");
+ throw new ArgumentException(nameof(op) + " \"" + op + "\" is not valid!");
}
- public static DepthFunction GetDepthFunc(GalComparisonOp Func)
+ public static DepthFunction GetDepthFunc(GalComparisonOp func)
{
- return (DepthFunction)GetFunc(Func);
+ return (DepthFunction)GetFunc(func);
}
- public static StencilFunction GetStencilFunc(GalComparisonOp Func)
+ public static StencilFunction GetStencilFunc(GalComparisonOp func)
{
- return (StencilFunction)GetFunc(Func);
+ return (StencilFunction)GetFunc(func);
}
- private static All GetFunc(GalComparisonOp Func)
+ private static All GetFunc(GalComparisonOp func)
{
- if ((int)Func >= (int)All.Never &&
- (int)Func <= (int)All.Always)
+ if ((int)func >= (int)All.Never &&
+ (int)func <= (int)All.Always)
{
- return (All)Func;
+ return (All)func;
}
- switch (Func)
+ switch (func)
{
case GalComparisonOp.Never: return All.Never;
case GalComparisonOp.Less: return All.Less;
@@ -75,24 +75,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL
case GalComparisonOp.Always: return All.Always;
}
- throw new ArgumentException(nameof(Func) + " \"" + Func + "\" is not valid!");
+ throw new ArgumentException(nameof(func) + " \"" + func + "\" is not valid!");
}
- public static DrawElementsType GetDrawElementsType(GalIndexFormat Format)
+ public static DrawElementsType GetDrawElementsType(GalIndexFormat format)
{
- switch (Format)
+ switch (format)
{
case GalIndexFormat.Byte: return DrawElementsType.UnsignedByte;
case GalIndexFormat.Int16: return DrawElementsType.UnsignedShort;
case GalIndexFormat.Int32: return DrawElementsType.UnsignedInt;
}
- throw new ArgumentException(nameof(Format) + " \"" + Format + "\" is not valid!");
+ throw new ArgumentException(nameof(format) + " \"" + format + "\" is not valid!");
}
- public static PrimitiveType GetPrimitiveType(GalPrimitiveType Type)
+ public static PrimitiveType GetPrimitiveType(GalPrimitiveType type)
{
- switch (Type)
+ switch (type)
{
case GalPrimitiveType.Points: return PrimitiveType.Points;
case GalPrimitiveType.Lines: return PrimitiveType.Lines;
@@ -109,12 +109,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
case GalPrimitiveType.Patches: return PrimitiveType.Patches;
}
- throw new ArgumentException(nameof(Type) + " \"" + Type + "\" is not valid!");
+ throw new ArgumentException(nameof(type) + " \"" + type + "\" is not valid!");
}
- public static ShaderType GetShaderType(GalShaderType Type)
+ public static ShaderType GetShaderType(GalShaderType type)
{
- switch (Type)
+ switch (type)
{
case GalShaderType.Vertex: return ShaderType.VertexShader;
case GalShaderType.TessControl: return ShaderType.TessControlShader;
@@ -123,50 +123,50 @@ namespace Ryujinx.Graphics.Gal.OpenGL
case GalShaderType.Fragment: return ShaderType.FragmentShader;
}
- throw new ArgumentException(nameof(Type) + " \"" + Type + "\" is not valid!");
+ throw new ArgumentException(nameof(type) + " \"" + type + "\" is not valid!");
}
- public static (PixelInternalFormat, PixelFormat, PixelType) GetImageFormat(GalImageFormat Format)
+ public static (PixelInternalFormat, PixelFormat, PixelType) GetImageFormat(GalImageFormat format)
{
- switch (Format)
+ switch (format)
{
- case GalImageFormat.RGBA32 | GalImageFormat.Float: return (PixelInternalFormat.Rgba32f, PixelFormat.Rgba, PixelType.Float);
- case GalImageFormat.RGBA32 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba32i, PixelFormat.RgbaInteger, PixelType.Int);
- case GalImageFormat.RGBA32 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba32ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt);
- case GalImageFormat.RGBA16 | GalImageFormat.Float: return (PixelInternalFormat.Rgba16f, PixelFormat.Rgba, PixelType.HalfFloat);
- case GalImageFormat.RGBA16 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba16i, PixelFormat.RgbaInteger, PixelType.Short);
- case GalImageFormat.RGBA16 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba16ui, PixelFormat.RgbaInteger, PixelType.UnsignedShort);
- case GalImageFormat.RGBA16 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba16, PixelFormat.Rgba, PixelType.UnsignedShort);
- case GalImageFormat.RG32 | GalImageFormat.Float: return (PixelInternalFormat.Rg32f, PixelFormat.Rg, PixelType.Float);
- case GalImageFormat.RG32 | GalImageFormat.Sint: return (PixelInternalFormat.Rg32i, PixelFormat.RgInteger, PixelType.Int);
- case GalImageFormat.RG32 | GalImageFormat.Uint: return (PixelInternalFormat.Rg32ui, PixelFormat.RgInteger, PixelType.UnsignedInt);
- case GalImageFormat.RGBX8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb8, PixelFormat.Rgba, PixelType.UnsignedByte);
- case GalImageFormat.RGBA8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rgba8Snorm, PixelFormat.Rgba, PixelType.Byte);
- case GalImageFormat.RGBA8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte);
- case GalImageFormat.RGBA8 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba8i, PixelFormat.RgbaInteger, PixelType.Byte);
- case GalImageFormat.RGBA8 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba8ui, PixelFormat.RgbaInteger, PixelType.UnsignedByte);
- case GalImageFormat.RGBA8 | GalImageFormat.Srgb: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte);
- case GalImageFormat.BGRA8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Bgra, PixelType.UnsignedByte);
- case GalImageFormat.BGRA8 | GalImageFormat.Srgb: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Bgra, PixelType.UnsignedByte);
- case GalImageFormat.RGBA4 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba4, PixelFormat.Rgba, PixelType.UnsignedShort4444Reversed);
- case GalImageFormat.RGB10A2 | GalImageFormat.Uint: return (PixelInternalFormat.Rgb10A2ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt2101010Reversed);
- case GalImageFormat.RGB10A2 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed);
+ case GalImageFormat.Rgba32 | GalImageFormat.Float: return (PixelInternalFormat.Rgba32f, PixelFormat.Rgba, PixelType.Float);
+ case GalImageFormat.Rgba32 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba32i, PixelFormat.RgbaInteger, PixelType.Int);
+ case GalImageFormat.Rgba32 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba32ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt);
+ case GalImageFormat.Rgba16 | GalImageFormat.Float: return (PixelInternalFormat.Rgba16f, PixelFormat.Rgba, PixelType.HalfFloat);
+ case GalImageFormat.Rgba16 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba16i, PixelFormat.RgbaInteger, PixelType.Short);
+ case GalImageFormat.Rgba16 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba16ui, PixelFormat.RgbaInteger, PixelType.UnsignedShort);
+ case GalImageFormat.Rgba16 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba16, PixelFormat.Rgba, PixelType.UnsignedShort);
+ case GalImageFormat.Rg32 | GalImageFormat.Float: return (PixelInternalFormat.Rg32f, PixelFormat.Rg, PixelType.Float);
+ case GalImageFormat.Rg32 | GalImageFormat.Sint: return (PixelInternalFormat.Rg32i, PixelFormat.RgInteger, PixelType.Int);
+ case GalImageFormat.Rg32 | GalImageFormat.Uint: return (PixelInternalFormat.Rg32ui, PixelFormat.RgInteger, PixelType.UnsignedInt);
+ case GalImageFormat.Rgbx8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb8, PixelFormat.Rgba, PixelType.UnsignedByte);
+ case GalImageFormat.Rgba8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rgba8Snorm, PixelFormat.Rgba, PixelType.Byte);
+ case GalImageFormat.Rgba8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte);
+ case GalImageFormat.Rgba8 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba8i, PixelFormat.RgbaInteger, PixelType.Byte);
+ case GalImageFormat.Rgba8 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba8ui, PixelFormat.RgbaInteger, PixelType.UnsignedByte);
+ case GalImageFormat.Rgba8 | GalImageFormat.Srgb: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte);
+ case GalImageFormat.Bgra8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Bgra, PixelType.UnsignedByte);
+ case GalImageFormat.Bgra8 | GalImageFormat.Srgb: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Bgra, PixelType.UnsignedByte);
+ case GalImageFormat.Rgba4 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba4, PixelFormat.Rgba, PixelType.UnsignedShort4444Reversed);
+ case GalImageFormat.Rgb10A2 | GalImageFormat.Uint: return (PixelInternalFormat.Rgb10A2ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt2101010Reversed);
+ case GalImageFormat.Rgb10A2 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed);
case GalImageFormat.R32 | GalImageFormat.Float: return (PixelInternalFormat.R32f, PixelFormat.Red, PixelType.Float);
case GalImageFormat.R32 | GalImageFormat.Sint: return (PixelInternalFormat.R32i, PixelFormat.Red, PixelType.Int);
case GalImageFormat.R32 | GalImageFormat.Uint: return (PixelInternalFormat.R32ui, PixelFormat.Red, PixelType.UnsignedInt);
- case GalImageFormat.BGR5A1 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551);
- case GalImageFormat.RGB5A1 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed);
- case GalImageFormat.RGB565 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565Reversed);
- case GalImageFormat.BGR565 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565);
- case GalImageFormat.RG16 | GalImageFormat.Float: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat);
- case GalImageFormat.RG16 | GalImageFormat.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short);
- case GalImageFormat.RG16 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Short);
- case GalImageFormat.RG16 | GalImageFormat.Uint: return (PixelInternalFormat.Rg16ui, PixelFormat.RgInteger, PixelType.UnsignedShort);
- case GalImageFormat.RG16 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg16, PixelFormat.Rg, PixelType.UnsignedShort);
- case GalImageFormat.RG8 | GalImageFormat.Sint: return (PixelInternalFormat.Rg8i, PixelFormat.RgInteger, PixelType.Byte);
- case GalImageFormat.RG8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg8Snorm, PixelFormat.Rg, PixelType.Byte);
- case GalImageFormat.RG8 | GalImageFormat.Uint: return (PixelInternalFormat.Rg8ui, PixelFormat.RgInteger, PixelType.UnsignedByte);
- case GalImageFormat.RG8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg8, PixelFormat.Rg, PixelType.UnsignedByte);
+ case GalImageFormat.Bgr5A1 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551);
+ case GalImageFormat.Rgb5A1 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed);
+ case GalImageFormat.Rgb565 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565Reversed);
+ case GalImageFormat.Bgr565 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565);
+ case GalImageFormat.Rg16 | GalImageFormat.Float: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat);
+ case GalImageFormat.Rg16 | GalImageFormat.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short);
+ case GalImageFormat.Rg16 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Short);
+ case GalImageFormat.Rg16 | GalImageFormat.Uint: return (PixelInternalFormat.Rg16ui, PixelFormat.RgInteger, PixelType.UnsignedShort);
+ case GalImageFormat.Rg16 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg16, PixelFormat.Rg, PixelType.UnsignedShort);
+ case GalImageFormat.Rg8 | GalImageFormat.Sint: return (PixelInternalFormat.Rg8i, PixelFormat.RgInteger, PixelType.Byte);
+ case GalImageFormat.Rg8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg8Snorm, PixelFormat.Rg, PixelType.Byte);
+ case GalImageFormat.Rg8 | GalImageFormat.Uint: return (PixelInternalFormat.Rg8ui, PixelFormat.RgInteger, PixelType.UnsignedByte);
+ case GalImageFormat.Rg8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg8, PixelFormat.Rg, PixelType.UnsignedByte);
case GalImageFormat.R16 | GalImageFormat.Float: return (PixelInternalFormat.R16f, PixelFormat.Red, PixelType.HalfFloat);
case GalImageFormat.R16 | GalImageFormat.Sint: return (PixelInternalFormat.R16i, PixelFormat.RedInteger, PixelType.Short);
case GalImageFormat.R16 | GalImageFormat.Snorm: return (PixelInternalFormat.R16Snorm, PixelFormat.Red, PixelType.Short);
@@ -186,12 +186,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
case GalImageFormat.D32S8 | GalImageFormat.Float: return (PixelInternalFormat.Depth32fStencil8, PixelFormat.DepthStencil, PixelType.Float32UnsignedInt248Rev);
}
- throw new NotImplementedException($"{Format & GalImageFormat.FormatMask} {Format & GalImageFormat.TypeMask}");
+ throw new NotImplementedException($"{format & GalImageFormat.FormatMask} {format & GalImageFormat.TypeMask}");
}
- public static All GetDepthCompareFunc(DepthCompareFunc DepthCompareFunc)
+ public static All GetDepthCompareFunc(DepthCompareFunc depthCompareFunc)
{
- switch (DepthCompareFunc)
+ switch (depthCompareFunc)
{
case DepthCompareFunc.LEqual:
return All.Lequal;
@@ -210,13 +210,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
case DepthCompareFunc.Never:
return All.Never;
default:
- throw new ArgumentException(nameof(DepthCompareFunc) + " \"" + DepthCompareFunc + "\" is not valid!");
+ throw new ArgumentException(nameof(depthCompareFunc) + " \"" + depthCompareFunc + "\" is not valid!");
}
}
- public static InternalFormat GetCompressedImageFormat(GalImageFormat Format)
+ public static InternalFormat GetCompressedImageFormat(GalImageFormat format)
{
- switch (Format)
+ switch (format)
{
case GalImageFormat.BptcSfloat | GalImageFormat.Float: return InternalFormat.CompressedRgbBptcSignedFloat;
case GalImageFormat.BptcUfloat | GalImageFormat.Float: return InternalFormat.CompressedRgbBptcUnsignedFloat;
@@ -234,12 +234,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
case GalImageFormat.BC5 | GalImageFormat.Unorm: return InternalFormat.CompressedRgRgtc2;
}
- throw new NotImplementedException($"{Format & GalImageFormat.FormatMask} {Format & GalImageFormat.TypeMask}");
+ throw new NotImplementedException($"{format & GalImageFormat.FormatMask} {format & GalImageFormat.TypeMask}");
}
- public static All GetTextureSwizzle(GalTextureSource Source)
+ public static All GetTextureSwizzle(GalTextureSource source)
{
- switch (Source)
+ switch (source)
{
case GalTextureSource.Zero: return All.Zero;
case GalTextureSource.Red: return All.Red;
@@ -250,12 +250,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
case GalTextureSource.OneFloat: return All.One;
}
- throw new ArgumentException(nameof(Source) + " \"" + Source + "\" is not valid!");
+ throw new ArgumentException(nameof(source) + " \"" + source + "\" is not valid!");
}
- public static TextureWrapMode GetTextureWrapMode(GalTextureWrap Wrap)
+ public static TextureWrapMode GetTextureWrapMode(GalTextureWrap wrap)
{
- switch (Wrap)
+ switch (wrap)
{
case GalTextureWrap.Repeat: return TextureWrapMode.Repeat;
case GalTextureWrap.MirroredRepeat: return TextureWrapMode.MirroredRepeat;
@@ -264,9 +264,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
case GalTextureWrap.Clamp: return TextureWrapMode.Clamp;
}
- if (OGLExtension.TextureMirrorClamp)
+ if (OglExtension.TextureMirrorClamp)
{
- switch (Wrap)
+ switch (wrap)
{
case GalTextureWrap.MirrorClampToEdge: return (TextureWrapMode)ExtTextureMirrorClamp.MirrorClampToEdgeExt;
case GalTextureWrap.MirrorClampToBorder: return (TextureWrapMode)ExtTextureMirrorClamp.MirrorClampToBorderExt;
@@ -276,7 +276,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
else
{
//Fallback to non-mirrored clamps
- switch (Wrap)
+ switch (wrap)
{
case GalTextureWrap.MirrorClampToEdge: return TextureWrapMode.ClampToEdge;
case GalTextureWrap.MirrorClampToBorder: return TextureWrapMode.ClampToBorder;
@@ -284,37 +284,37 @@ namespace Ryujinx.Graphics.Gal.OpenGL
}
}
- throw new ArgumentException(nameof(Wrap) + " \"" + Wrap + "\" is not valid!");
+ throw new ArgumentException(nameof(wrap) + " \"" + wrap + "\" is not valid!");
}
public static TextureMinFilter GetTextureMinFilter(
- GalTextureFilter MinFilter,
- GalTextureMipFilter MipFilter)
+ GalTextureFilter minFilter,
+ GalTextureMipFilter mipFilter)
{
//TODO: Mip (needs mipmap support first).
- switch (MinFilter)
+ switch (minFilter)
{
case GalTextureFilter.Nearest: return TextureMinFilter.Nearest;
case GalTextureFilter.Linear: return TextureMinFilter.Linear;
}
- throw new ArgumentException(nameof(MinFilter) + " \"" + MinFilter + "\" is not valid!");
+ throw new ArgumentException(nameof(minFilter) + " \"" + minFilter + "\" is not valid!");
}
- public static TextureMagFilter GetTextureMagFilter(GalTextureFilter Filter)
+ public static TextureMagFilter GetTextureMagFilter(GalTextureFilter filter)
{
- switch (Filter)
+ switch (filter)
{
case GalTextureFilter.Nearest: return TextureMagFilter.Nearest;
case GalTextureFilter.Linear: return TextureMagFilter.Linear;
}
- throw new ArgumentException(nameof(Filter) + " \"" + Filter + "\" is not valid!");
+ throw new ArgumentException(nameof(filter) + " \"" + filter + "\" is not valid!");
}
- public static BlendEquationMode GetBlendEquation(GalBlendEquation BlendEquation)
+ public static BlendEquationMode GetBlendEquation(GalBlendEquation blendEquation)
{
- switch (BlendEquation)
+ switch (blendEquation)
{
case GalBlendEquation.FuncAdd:
case GalBlendEquation.FuncAddGl:
@@ -337,12 +337,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL
return BlendEquationMode.Max;
}
- throw new ArgumentException(nameof(BlendEquation) + " \"" + BlendEquation + "\" is not valid!");
+ throw new ArgumentException(nameof(blendEquation) + " \"" + blendEquation + "\" is not valid!");
}
- public static BlendingFactor GetBlendFactor(GalBlendFactor BlendFactor)
+ public static BlendingFactor GetBlendFactor(GalBlendFactor blendFactor)
{
- switch (BlendFactor)
+ switch (blendFactor)
{
case GalBlendFactor.Zero:
case GalBlendFactor.ZeroGl:
@@ -421,7 +421,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
return BlendingFactor.ConstantColor;
}
- throw new ArgumentException(nameof(BlendFactor) + " \"" + BlendFactor + "\" is not valid!");
+ throw new ArgumentException(nameof(blendFactor) + " \"" + blendFactor + "\" is not valid!");
}
}
}
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglExtension.cs b/Ryujinx.Graphics/Gal/OpenGL/OglExtension.cs
new file mode 100644
index 00000000..8a1a0510
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OglExtension.cs
@@ -0,0 +1,70 @@
+using OpenTK.Graphics.OpenGL;
+using Ryujinx.Common.Logging;
+using System;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ static class OglExtension
+ {
+ // Private lazy backing variables
+ private static Lazy<bool> _enhancedLayouts = new Lazy<bool>(() => HasExtension("GL_ARB_enhanced_layouts"));
+ private static Lazy<bool> _textureMirrorClamp = new Lazy<bool>(() => HasExtension("GL_EXT_texture_mirror_clamp"));
+ private static Lazy<bool> _viewportArray = new Lazy<bool>(() => HasExtension("GL_ARB_viewport_array"));
+
+ private static Lazy<bool> _nvidiaDriver = new Lazy<bool>(() => IsNvidiaDriver());
+
+ // Public accessors
+ public static bool EnhancedLayouts => _enhancedLayouts.Value;
+ public static bool TextureMirrorClamp => _textureMirrorClamp.Value;
+ public static bool ViewportArray => _viewportArray.Value;
+
+ public static bool NvidiaDriver => _nvidiaDriver.Value;
+
+ private static bool HasExtension(string name)
+ {
+ int numExtensions = GL.GetInteger(GetPName.NumExtensions);
+
+ for (int extension = 0; extension < numExtensions; extension++)
+ {
+ if (GL.GetString(StringNameIndexed.Extensions, extension) == name)
+ {
+ return true;
+ }
+ }
+
+ Logger.PrintInfo(LogClass.Gpu, $"OpenGL extension {name} unavailable. You may experience some performance degradation");
+
+ return false;
+ }
+
+ private static bool IsNvidiaDriver()
+ {
+ return GL.GetString(StringName.Vendor).Equals("NVIDIA Corporation");
+ }
+
+ public static class Required
+ {
+ // Public accessors
+ public static bool EnhancedLayouts => _enhancedLayoutsRequired.Value;
+ public static bool TextureMirrorClamp => _textureMirrorClampRequired.Value;
+ public static bool ViewportArray => _viewportArrayRequired.Value;
+
+ // Private lazy backing variables
+ private static Lazy<bool> _enhancedLayoutsRequired = new Lazy<bool>(() => HasExtensionRequired(OglExtension.EnhancedLayouts, "GL_ARB_enhanced_layouts"));
+ private static Lazy<bool> _textureMirrorClampRequired = new Lazy<bool>(() => HasExtensionRequired(OglExtension.TextureMirrorClamp, "GL_EXT_texture_mirror_clamp"));
+ private static Lazy<bool> _viewportArrayRequired = new Lazy<bool>(() => HasExtensionRequired(OglExtension.ViewportArray, "GL_ARB_viewport_array"));
+
+ private static bool HasExtensionRequired(bool value, string name)
+ {
+ if (value)
+ {
+ return true;
+ }
+
+ Logger.PrintWarning(LogClass.Gpu, $"Required OpenGL extension {name} unavailable. You may experience some rendering issues");
+
+ return false;
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglLimit.cs b/Ryujinx.Graphics/Gal/OpenGL/OglLimit.cs
new file mode 100644
index 00000000..2a227a37
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OglLimit.cs
@@ -0,0 +1,12 @@
+using OpenTK.Graphics.OpenGL;
+using System;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ static class OglLimit
+ {
+ private static Lazy<int> _sMaxUboSize = new Lazy<int>(() => GL.GetInteger(GetPName.MaxUniformBlockSize));
+
+ public static int MaxUboSize => _sMaxUboSize.Value;
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs b/Ryujinx.Graphics/Gal/OpenGL/OglPipeline.cs
index 96d42e02..3c8ada3e 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OglPipeline.cs
@@ -4,9 +4,9 @@ using System.Collections.Generic;
namespace Ryujinx.Graphics.Gal.OpenGL
{
- class OGLPipeline : IGalPipeline
+ class OglPipeline : IGalPipeline
{
- private static Dictionary<GalVertexAttribSize, int> AttribElements =
+ private static Dictionary<GalVertexAttribSize, int> _attribElements =
new Dictionary<GalVertexAttribSize, int>()
{
{ GalVertexAttribSize._32_32_32_32, 4 },
@@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ GalVertexAttribSize._11_11_10, 3 }
};
- private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> FloatAttribTypes =
+ private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> _floatAttribTypes =
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
{
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Float },
@@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ GalVertexAttribSize._16, VertexAttribPointerType.HalfFloat }
};
- private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> SignedAttribTypes =
+ private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> _signedAttribTypes =
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
{
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Int },
@@ -56,7 +56,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ GalVertexAttribSize._10_10_10_2, VertexAttribPointerType.Int2101010Rev }
};
- private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> UnsignedAttribTypes =
+ private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> _unsignedAttribTypes =
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
{
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.UnsignedInt },
@@ -75,30 +75,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ GalVertexAttribSize._11_11_10, VertexAttribPointerType.UnsignedInt10F11F11FRev }
};
- private GalPipelineState Old;
+ private GalPipelineState _old;
- private OGLConstBuffer Buffer;
- private OGLRenderTarget RenderTarget;
- private OGLRasterizer Rasterizer;
- private OGLShader Shader;
+ private OglConstBuffer _buffer;
+ private OglRenderTarget _renderTarget;
+ private OglRasterizer _rasterizer;
+ private OglShader _shader;
- private int VaoHandle;
+ private int _vaoHandle;
- public OGLPipeline(
- OGLConstBuffer Buffer,
- OGLRenderTarget RenderTarget,
- OGLRasterizer Rasterizer,
- OGLShader Shader)
+ public OglPipeline(
+ OglConstBuffer buffer,
+ OglRenderTarget renderTarget,
+ OglRasterizer rasterizer,
+ OglShader shader)
{
- this.Buffer = Buffer;
- this.RenderTarget = RenderTarget;
- this.Rasterizer = Rasterizer;
- this.Shader = Shader;
+ _buffer = buffer;
+ _renderTarget = renderTarget;
+ _rasterizer = rasterizer;
+ _shader = shader;
//These values match OpenGL's defaults
- Old = new GalPipelineState
+ _old = new GalPipelineState
{
- FrontFace = GalFrontFace.CCW,
+ FrontFace = GalFrontFace.Ccw,
CullFaceEnabled = false,
CullFace = GalCullFace.Back,
@@ -133,11 +133,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
PrimitiveRestartIndex = 0
};
- for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
+ for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++)
{
- Old.Blends[Index] = BlendState.Default;
+ _old.Blends[index] = BlendState.Default;
- Old.ColorMasks[Index] = ColorMaskState.Default;
+ _old.ColorMasks[index] = ColorMaskState.Default;
}
}
@@ -147,122 +147,122 @@ namespace Ryujinx.Graphics.Gal.OpenGL
BindVertexLayout(New);
- if (New.FramebufferSrgb != Old.FramebufferSrgb)
+ if (New.FramebufferSrgb != _old.FramebufferSrgb)
{
Enable(EnableCap.FramebufferSrgb, New.FramebufferSrgb);
- RenderTarget.FramebufferSrgb = New.FramebufferSrgb;
+ _renderTarget.FramebufferSrgb = New.FramebufferSrgb;
}
- if (New.FlipX != Old.FlipX || New.FlipY != Old.FlipY || New.Instance != Old.Instance)
+ if (New.FlipX != _old.FlipX || New.FlipY != _old.FlipY || New.Instance != _old.Instance)
{
- Shader.SetExtraData(New.FlipX, New.FlipY, New.Instance);
+ _shader.SetExtraData(New.FlipX, New.FlipY, New.Instance);
}
- if (New.FrontFace != Old.FrontFace)
+ if (New.FrontFace != _old.FrontFace)
{
- GL.FrontFace(OGLEnumConverter.GetFrontFace(New.FrontFace));
+ GL.FrontFace(OglEnumConverter.GetFrontFace(New.FrontFace));
}
- if (New.CullFaceEnabled != Old.CullFaceEnabled)
+ if (New.CullFaceEnabled != _old.CullFaceEnabled)
{
Enable(EnableCap.CullFace, New.CullFaceEnabled);
}
if (New.CullFaceEnabled)
{
- if (New.CullFace != Old.CullFace)
+ if (New.CullFace != _old.CullFace)
{
- GL.CullFace(OGLEnumConverter.GetCullFace(New.CullFace));
+ GL.CullFace(OglEnumConverter.GetCullFace(New.CullFace));
}
}
- if (New.DepthTestEnabled != Old.DepthTestEnabled)
+ if (New.DepthTestEnabled != _old.DepthTestEnabled)
{
Enable(EnableCap.DepthTest, New.DepthTestEnabled);
}
- if (New.DepthWriteEnabled != Old.DepthWriteEnabled)
+ if (New.DepthWriteEnabled != _old.DepthWriteEnabled)
{
GL.DepthMask(New.DepthWriteEnabled);
}
if (New.DepthTestEnabled)
{
- if (New.DepthFunc != Old.DepthFunc)
+ if (New.DepthFunc != _old.DepthFunc)
{
- GL.DepthFunc(OGLEnumConverter.GetDepthFunc(New.DepthFunc));
+ GL.DepthFunc(OglEnumConverter.GetDepthFunc(New.DepthFunc));
}
}
- if (New.DepthRangeNear != Old.DepthRangeNear ||
- New.DepthRangeFar != Old.DepthRangeFar)
+ if (New.DepthRangeNear != _old.DepthRangeNear ||
+ New.DepthRangeFar != _old.DepthRangeFar)
{
GL.DepthRange(New.DepthRangeNear, New.DepthRangeFar);
}
- if (New.StencilTestEnabled != Old.StencilTestEnabled)
+ if (New.StencilTestEnabled != _old.StencilTestEnabled)
{
Enable(EnableCap.StencilTest, New.StencilTestEnabled);
}
- if (New.StencilTwoSideEnabled != Old.StencilTwoSideEnabled)
+ if (New.StencilTwoSideEnabled != _old.StencilTwoSideEnabled)
{
Enable((EnableCap)All.StencilTestTwoSideExt, New.StencilTwoSideEnabled);
}
if (New.StencilTestEnabled)
{
- if (New.StencilBackFuncFunc != Old.StencilBackFuncFunc ||
- New.StencilBackFuncRef != Old.StencilBackFuncRef ||
- New.StencilBackFuncMask != Old.StencilBackFuncMask)
+ if (New.StencilBackFuncFunc != _old.StencilBackFuncFunc ||
+ New.StencilBackFuncRef != _old.StencilBackFuncRef ||
+ New.StencilBackFuncMask != _old.StencilBackFuncMask)
{
GL.StencilFuncSeparate(
StencilFace.Back,
- OGLEnumConverter.GetStencilFunc(New.StencilBackFuncFunc),
+ OglEnumConverter.GetStencilFunc(New.StencilBackFuncFunc),
New.StencilBackFuncRef,
New.StencilBackFuncMask);
}
- if (New.StencilBackOpFail != Old.StencilBackOpFail ||
- New.StencilBackOpZFail != Old.StencilBackOpZFail ||
- New.StencilBackOpZPass != Old.StencilBackOpZPass)
+ if (New.StencilBackOpFail != _old.StencilBackOpFail ||
+ New.StencilBackOpZFail != _old.StencilBackOpZFail ||
+ New.StencilBackOpZPass != _old.StencilBackOpZPass)
{
GL.StencilOpSeparate(
StencilFace.Back,
- OGLEnumConverter.GetStencilOp(New.StencilBackOpFail),
- OGLEnumConverter.GetStencilOp(New.StencilBackOpZFail),
- OGLEnumConverter.GetStencilOp(New.StencilBackOpZPass));
+ OglEnumConverter.GetStencilOp(New.StencilBackOpFail),
+ OglEnumConverter.GetStencilOp(New.StencilBackOpZFail),
+ OglEnumConverter.GetStencilOp(New.StencilBackOpZPass));
}
- if (New.StencilBackMask != Old.StencilBackMask)
+ if (New.StencilBackMask != _old.StencilBackMask)
{
GL.StencilMaskSeparate(StencilFace.Back, New.StencilBackMask);
}
- if (New.StencilFrontFuncFunc != Old.StencilFrontFuncFunc ||
- New.StencilFrontFuncRef != Old.StencilFrontFuncRef ||
- New.StencilFrontFuncMask != Old.StencilFrontFuncMask)
+ if (New.StencilFrontFuncFunc != _old.StencilFrontFuncFunc ||
+ New.StencilFrontFuncRef != _old.StencilFrontFuncRef ||
+ New.StencilFrontFuncMask != _old.StencilFrontFuncMask)
{
GL.StencilFuncSeparate(
StencilFace.Front,
- OGLEnumConverter.GetStencilFunc(New.StencilFrontFuncFunc),
+ OglEnumConverter.GetStencilFunc(New.StencilFrontFuncFunc),
New.StencilFrontFuncRef,
New.StencilFrontFuncMask);
}
- if (New.StencilFrontOpFail != Old.StencilFrontOpFail ||
- New.StencilFrontOpZFail != Old.StencilFrontOpZFail ||
- New.StencilFrontOpZPass != Old.StencilFrontOpZPass)
+ if (New.StencilFrontOpFail != _old.StencilFrontOpFail ||
+ New.StencilFrontOpZFail != _old.StencilFrontOpZFail ||
+ New.StencilFrontOpZPass != _old.StencilFrontOpZPass)
{
GL.StencilOpSeparate(
StencilFace.Front,
- OGLEnumConverter.GetStencilOp(New.StencilFrontOpFail),
- OGLEnumConverter.GetStencilOp(New.StencilFrontOpZFail),
- OGLEnumConverter.GetStencilOp(New.StencilFrontOpZPass));
+ OglEnumConverter.GetStencilOp(New.StencilFrontOpFail),
+ OglEnumConverter.GetStencilOp(New.StencilFrontOpZFail),
+ OglEnumConverter.GetStencilOp(New.StencilFrontOpZPass));
}
- if (New.StencilFrontMask != Old.StencilFrontMask)
+ if (New.StencilFrontMask != _old.StencilFrontMask)
{
GL.StencilMaskSeparate(StencilFace.Front, New.StencilFrontMask);
}
@@ -277,42 +277,42 @@ namespace Ryujinx.Graphics.Gal.OpenGL
int scissorsApplied = 0;
bool applyToAll = false;
- for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
+ for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++)
{
- if (New.ScissorTestEnabled[Index])
+ if (New.ScissorTestEnabled[index])
{
// If viewport arrays are unavailable apply first scissor test to all or
// there is only 1 scissor test and it's the first, the scissor test applies to all viewports
- if (!OGLExtension.Required.ViewportArray || (Index == 0 && New.ScissorTestCount == 1))
+ if (!OglExtension.Required.ViewportArray || (index == 0 && New.ScissorTestCount == 1))
{
GL.Enable(EnableCap.ScissorTest);
applyToAll = true;
}
else
{
- GL.Enable(IndexedEnableCap.ScissorTest, Index);
+ GL.Enable(IndexedEnableCap.ScissorTest, index);
}
- if (New.ScissorTestEnabled[Index] != Old.ScissorTestEnabled[Index] ||
- New.ScissorTestX[Index] != Old.ScissorTestX[Index] ||
- New.ScissorTestY[Index] != Old.ScissorTestY[Index] ||
- New.ScissorTestWidth[Index] != Old.ScissorTestWidth[Index] ||
- New.ScissorTestHeight[Index] != Old.ScissorTestHeight[Index])
+ if (New.ScissorTestEnabled[index] != _old.ScissorTestEnabled[index] ||
+ New.ScissorTestX[index] != _old.ScissorTestX[index] ||
+ New.ScissorTestY[index] != _old.ScissorTestY[index] ||
+ New.ScissorTestWidth[index] != _old.ScissorTestWidth[index] ||
+ New.ScissorTestHeight[index] != _old.ScissorTestHeight[index])
{
if (applyToAll)
{
- GL.Scissor(New.ScissorTestX[Index], New.ScissorTestY[Index],
- New.ScissorTestWidth[Index], New.ScissorTestHeight[Index]);
+ GL.Scissor(New.ScissorTestX[index], New.ScissorTestY[index],
+ New.ScissorTestWidth[index], New.ScissorTestHeight[index]);
}
else
{
- GL.ScissorIndexed(Index, New.ScissorTestX[Index], New.ScissorTestY[Index],
- New.ScissorTestWidth[Index], New.ScissorTestHeight[Index]);
+ GL.ScissorIndexed(index, New.ScissorTestX[index], New.ScissorTestY[index],
+ New.ScissorTestWidth[index], New.ScissorTestHeight[index]);
}
}
- // If all scissor tests have been applied, or viewport arrays are unavailable we can skip remaining itterations
- if (!OGLExtension.Required.ViewportArray || ++scissorsApplied == New.ScissorTestCount)
+ // If all scissor tests have been applied, or viewport arrays are unavailable we can skip remaining iterations
+ if (!OglExtension.Required.ViewportArray || ++scissorsApplied == New.ScissorTestCount)
{
break;
}
@@ -323,26 +323,26 @@ namespace Ryujinx.Graphics.Gal.OpenGL
if (New.BlendIndependent)
{
- for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
+ for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++)
{
- SetBlendState(Index, New.Blends[Index], Old.Blends[Index]);
+ SetBlendState(index, New.Blends[index], _old.Blends[index]);
}
}
else
{
- if (New.BlendIndependent != Old.BlendIndependent)
+ if (New.BlendIndependent != _old.BlendIndependent)
{
SetAllBlendState(New.Blends[0]);
}
else
{
- SetBlendState(New.Blends[0], Old.Blends[0]);
+ SetBlendState(New.Blends[0], _old.Blends[0]);
}
}
if (New.ColorMaskCommon)
{
- if (New.ColorMaskCommon != Old.ColorMaskCommon || !New.ColorMasks[0].Equals(Old.ColorMasks[0]))
+ if (New.ColorMaskCommon != _old.ColorMaskCommon || !New.ColorMasks[0].Equals(_old.ColorMasks[0]))
{
GL.ColorMask(
New.ColorMasks[0].Red,
@@ -353,39 +353,39 @@ namespace Ryujinx.Graphics.Gal.OpenGL
}
else
{
- for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
+ for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++)
{
- if (!New.ColorMasks[Index].Equals(Old.ColorMasks[Index]))
+ if (!New.ColorMasks[index].Equals(_old.ColorMasks[index]))
{
GL.ColorMask(
- Index,
- New.ColorMasks[Index].Red,
- New.ColorMasks[Index].Green,
- New.ColorMasks[Index].Blue,
- New.ColorMasks[Index].Alpha);
+ index,
+ New.ColorMasks[index].Red,
+ New.ColorMasks[index].Green,
+ New.ColorMasks[index].Blue,
+ New.ColorMasks[index].Alpha);
}
}
}
- if (New.PrimitiveRestartEnabled != Old.PrimitiveRestartEnabled)
+ if (New.PrimitiveRestartEnabled != _old.PrimitiveRestartEnabled)
{
Enable(EnableCap.PrimitiveRestart, New.PrimitiveRestartEnabled);
}
if (New.PrimitiveRestartEnabled)
{
- if (New.PrimitiveRestartIndex != Old.PrimitiveRestartIndex)
+ if (New.PrimitiveRestartIndex != _old.PrimitiveRestartIndex)
{
GL.PrimitiveRestartIndex(New.PrimitiveRestartIndex);
}
}
- Old = New;
+ _old = New;
}
- public void Unbind(GalPipelineState State)
+ public void Unbind(GalPipelineState state)
{
- if (State.ScissorTestCount > 0)
+ if (state.ScissorTestCount > 0)
{
GL.Disable(EnableCap.ScissorTest);
}
@@ -400,29 +400,29 @@ namespace Ryujinx.Graphics.Gal.OpenGL
if (New.SeparateAlpha)
{
GL.BlendEquationSeparate(
- OGLEnumConverter.GetBlendEquation(New.EquationRgb),
- OGLEnumConverter.GetBlendEquation(New.EquationAlpha));
+ OglEnumConverter.GetBlendEquation(New.EquationRgb),
+ OglEnumConverter.GetBlendEquation(New.EquationAlpha));
GL.BlendFuncSeparate(
- (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
- (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb),
- (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
- (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstAlpha));
+ (BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
+ (BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb),
+ (BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
+ (BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstAlpha));
}
else
{
- GL.BlendEquation(OGLEnumConverter.GetBlendEquation(New.EquationRgb));
+ GL.BlendEquation(OglEnumConverter.GetBlendEquation(New.EquationRgb));
GL.BlendFunc(
- OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
- OGLEnumConverter.GetBlendFactor(New.FuncDstRgb));
+ OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
+ OglEnumConverter.GetBlendFactor(New.FuncDstRgb));
}
}
}
- private void SetBlendState(BlendState New, BlendState Old)
+ private void SetBlendState(BlendState New, BlendState old)
{
- if (New.Enabled != Old.Enabled)
+ if (New.Enabled != old.Enabled)
{
Enable(EnableCap.Blend, New.Enabled);
}
@@ -431,91 +431,91 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{
if (New.SeparateAlpha)
{
- if (New.EquationRgb != Old.EquationRgb ||
- New.EquationAlpha != Old.EquationAlpha)
+ if (New.EquationRgb != old.EquationRgb ||
+ New.EquationAlpha != old.EquationAlpha)
{
GL.BlendEquationSeparate(
- OGLEnumConverter.GetBlendEquation(New.EquationRgb),
- OGLEnumConverter.GetBlendEquation(New.EquationAlpha));
+ OglEnumConverter.GetBlendEquation(New.EquationRgb),
+ OglEnumConverter.GetBlendEquation(New.EquationAlpha));
}
- if (New.FuncSrcRgb != Old.FuncSrcRgb ||
- New.FuncDstRgb != Old.FuncDstRgb ||
- New.FuncSrcAlpha != Old.FuncSrcAlpha ||
- New.FuncDstAlpha != Old.FuncDstAlpha)
+ if (New.FuncSrcRgb != old.FuncSrcRgb ||
+ New.FuncDstRgb != old.FuncDstRgb ||
+ New.FuncSrcAlpha != old.FuncSrcAlpha ||
+ New.FuncDstAlpha != old.FuncDstAlpha)
{
GL.BlendFuncSeparate(
- (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
- (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb),
- (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
- (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstAlpha));
+ (BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
+ (BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb),
+ (BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
+ (BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstAlpha));
}
}
else
{
- if (New.EquationRgb != Old.EquationRgb)
+ if (New.EquationRgb != old.EquationRgb)
{
- GL.BlendEquation(OGLEnumConverter.GetBlendEquation(New.EquationRgb));
+ GL.BlendEquation(OglEnumConverter.GetBlendEquation(New.EquationRgb));
}
- if (New.FuncSrcRgb != Old.FuncSrcRgb ||
- New.FuncDstRgb != Old.FuncDstRgb)
+ if (New.FuncSrcRgb != old.FuncSrcRgb ||
+ New.FuncDstRgb != old.FuncDstRgb)
{
GL.BlendFunc(
- OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
- OGLEnumConverter.GetBlendFactor(New.FuncDstRgb));
+ OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
+ OglEnumConverter.GetBlendFactor(New.FuncDstRgb));
}
}
}
}
- private void SetBlendState(int Index, BlendState New, BlendState Old)
+ private void SetBlendState(int index, BlendState New, BlendState old)
{
- if (New.Enabled != Old.Enabled)
+ if (New.Enabled != old.Enabled)
{
- Enable(IndexedEnableCap.Blend, Index, New.Enabled);
+ Enable(IndexedEnableCap.Blend, index, New.Enabled);
}
if (New.Enabled)
{
if (New.SeparateAlpha)
{
- if (New.EquationRgb != Old.EquationRgb ||
- New.EquationAlpha != Old.EquationAlpha)
+ if (New.EquationRgb != old.EquationRgb ||
+ New.EquationAlpha != old.EquationAlpha)
{
GL.BlendEquationSeparate(
- Index,
- OGLEnumConverter.GetBlendEquation(New.EquationRgb),
- OGLEnumConverter.GetBlendEquation(New.EquationAlpha));
+ index,
+ OglEnumConverter.GetBlendEquation(New.EquationRgb),
+ OglEnumConverter.GetBlendEquation(New.EquationAlpha));
}
- if (New.FuncSrcRgb != Old.FuncSrcRgb ||
- New.FuncDstRgb != Old.FuncDstRgb ||
- New.FuncSrcAlpha != Old.FuncSrcAlpha ||
- New.FuncDstAlpha != Old.FuncDstAlpha)
+ if (New.FuncSrcRgb != old.FuncSrcRgb ||
+ New.FuncDstRgb != old.FuncDstRgb ||
+ New.FuncSrcAlpha != old.FuncSrcAlpha ||
+ New.FuncDstAlpha != old.FuncDstAlpha)
{
GL.BlendFuncSeparate(
- Index,
- (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
- (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb),
- (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
- (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstAlpha));
+ index,
+ (BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
+ (BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb),
+ (BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcAlpha),
+ (BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstAlpha));
}
}
else
{
- if (New.EquationRgb != Old.EquationRgb)
+ if (New.EquationRgb != old.EquationRgb)
{
- GL.BlendEquation(Index, OGLEnumConverter.GetBlendEquation(New.EquationRgb));
+ GL.BlendEquation(index, OglEnumConverter.GetBlendEquation(New.EquationRgb));
}
- if (New.FuncSrcRgb != Old.FuncSrcRgb ||
- New.FuncDstRgb != Old.FuncDstRgb)
+ if (New.FuncSrcRgb != old.FuncSrcRgb ||
+ New.FuncDstRgb != old.FuncDstRgb)
{
GL.BlendFunc(
- Index,
- (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
- (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb));
+ index,
+ (BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb),
+ (BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb));
}
}
}
@@ -523,310 +523,310 @@ namespace Ryujinx.Graphics.Gal.OpenGL
private void BindConstBuffers(GalPipelineState New)
{
- int FreeBinding = OGLShader.ReservedCbufCount;
+ int freeBinding = OglShader.ReservedCbufCount;
- void BindIfNotNull(OGLShaderStage Stage)
+ void BindIfNotNull(OglShaderStage stage)
{
- if (Stage != null)
+ if (stage != null)
{
- foreach (ShaderDeclInfo DeclInfo in Stage.ConstBufferUsage)
+ foreach (ShaderDeclInfo declInfo in stage.ConstBufferUsage)
{
- long Key = New.ConstBufferKeys[(int)Stage.Type][DeclInfo.Cbuf];
+ long key = New.ConstBufferKeys[(int)stage.Type][declInfo.Cbuf];
- if (Key != 0 && Buffer.TryGetUbo(Key, out int UboHandle))
+ if (key != 0 && _buffer.TryGetUbo(key, out int uboHandle))
{
- GL.BindBufferBase(BufferRangeTarget.UniformBuffer, FreeBinding, UboHandle);
+ GL.BindBufferBase(BufferRangeTarget.UniformBuffer, freeBinding, uboHandle);
}
- FreeBinding++;
+ freeBinding++;
}
}
}
- BindIfNotNull(Shader.Current.Vertex);
- BindIfNotNull(Shader.Current.TessControl);
- BindIfNotNull(Shader.Current.TessEvaluation);
- BindIfNotNull(Shader.Current.Geometry);
- BindIfNotNull(Shader.Current.Fragment);
+ BindIfNotNull(_shader.Current.Vertex);
+ BindIfNotNull(_shader.Current.TessControl);
+ BindIfNotNull(_shader.Current.TessEvaluation);
+ BindIfNotNull(_shader.Current.Geometry);
+ BindIfNotNull(_shader.Current.Fragment);
}
private void BindVertexLayout(GalPipelineState New)
{
- foreach (GalVertexBinding Binding in New.VertexBindings)
+ foreach (GalVertexBinding binding in New.VertexBindings)
{
- if (!Binding.Enabled || !Rasterizer.TryGetVbo(Binding.VboKey, out int VboHandle))
+ if (!binding.Enabled || !_rasterizer.TryGetVbo(binding.VboKey, out int vboHandle))
{
continue;
}
- if (VaoHandle == 0)
+ if (_vaoHandle == 0)
{
- VaoHandle = GL.GenVertexArray();
+ _vaoHandle = GL.GenVertexArray();
//Vertex arrays shouldn't be used anywhere else in OpenGL's backend
//if you want to use it, move this line out of the if
- GL.BindVertexArray(VaoHandle);
+ GL.BindVertexArray(_vaoHandle);
}
- foreach (GalVertexAttrib Attrib in Binding.Attribs)
+ foreach (GalVertexAttrib attrib in binding.Attribs)
{
//Skip uninitialized attributes.
- if (Attrib.Size == 0)
+ if (attrib.Size == 0)
{
continue;
}
- GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
+ GL.BindBuffer(BufferTarget.ArrayBuffer, vboHandle);
- bool Unsigned =
- Attrib.Type == GalVertexAttribType.Unorm ||
- Attrib.Type == GalVertexAttribType.Uint ||
- Attrib.Type == GalVertexAttribType.Uscaled;
+ bool unsigned =
+ attrib.Type == GalVertexAttribType.Unorm ||
+ attrib.Type == GalVertexAttribType.Uint ||
+ attrib.Type == GalVertexAttribType.Uscaled;
- bool Normalize =
- Attrib.Type == GalVertexAttribType.Snorm ||
- Attrib.Type == GalVertexAttribType.Unorm;
+ bool normalize =
+ attrib.Type == GalVertexAttribType.Snorm ||
+ attrib.Type == GalVertexAttribType.Unorm;
- VertexAttribPointerType Type = 0;
+ VertexAttribPointerType type = 0;
- if (Attrib.Type == GalVertexAttribType.Float)
+ if (attrib.Type == GalVertexAttribType.Float)
{
- Type = GetType(FloatAttribTypes, Attrib);
+ type = GetType(_floatAttribTypes, attrib);
}
else
{
- if (Unsigned)
+ if (unsigned)
{
- Type = GetType(UnsignedAttribTypes, Attrib);
+ type = GetType(_unsignedAttribTypes, attrib);
}
else
{
- Type = GetType(SignedAttribTypes, Attrib);
+ type = GetType(_signedAttribTypes, attrib);
}
}
- if (!AttribElements.TryGetValue(Attrib.Size, out int Size))
+ if (!_attribElements.TryGetValue(attrib.Size, out int size))
{
- throw new InvalidOperationException("Invalid attribute size \"" + Attrib.Size + "\"!");
+ throw new InvalidOperationException("Invalid attribute size \"" + attrib.Size + "\"!");
}
- int Offset = Attrib.Offset;
+ int offset = attrib.Offset;
- if (Binding.Stride != 0)
+ if (binding.Stride != 0)
{
- GL.EnableVertexAttribArray(Attrib.Index);
+ GL.EnableVertexAttribArray(attrib.Index);
- if (Attrib.Type == GalVertexAttribType.Sint ||
- Attrib.Type == GalVertexAttribType.Uint)
+ if (attrib.Type == GalVertexAttribType.Sint ||
+ attrib.Type == GalVertexAttribType.Uint)
{
- IntPtr Pointer = new IntPtr(Offset);
+ IntPtr pointer = new IntPtr(offset);
- VertexAttribIntegerType IType = (VertexAttribIntegerType)Type;
+ VertexAttribIntegerType iType = (VertexAttribIntegerType)type;
- GL.VertexAttribIPointer(Attrib.Index, Size, IType, Binding.Stride, Pointer);
+ GL.VertexAttribIPointer(attrib.Index, size, iType, binding.Stride, pointer);
}
else
{
- GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Binding.Stride, Offset);
+ GL.VertexAttribPointer(attrib.Index, size, type, normalize, binding.Stride, offset);
}
}
else
{
- GL.DisableVertexAttribArray(Attrib.Index);
+ GL.DisableVertexAttribArray(attrib.Index);
- SetConstAttrib(Attrib);
+ SetConstAttrib(attrib);
}
- if (Binding.Instanced && Binding.Divisor != 0)
+ if (binding.Instanced && binding.Divisor != 0)
{
- GL.VertexAttribDivisor(Attrib.Index, 1);
+ GL.VertexAttribDivisor(attrib.Index, 1);
}
else
{
- GL.VertexAttribDivisor(Attrib.Index, 0);
+ GL.VertexAttribDivisor(attrib.Index, 0);
}
}
}
}
- private static VertexAttribPointerType GetType(Dictionary<GalVertexAttribSize, VertexAttribPointerType> Dict, GalVertexAttrib Attrib)
+ private static VertexAttribPointerType GetType(Dictionary<GalVertexAttribSize, VertexAttribPointerType> dict, GalVertexAttrib attrib)
{
- if (!Dict.TryGetValue(Attrib.Size, out VertexAttribPointerType Type))
+ if (!dict.TryGetValue(attrib.Size, out VertexAttribPointerType type))
{
- ThrowUnsupportedAttrib(Attrib);
+ ThrowUnsupportedAttrib(attrib);
}
- return Type;
+ return type;
}
- private unsafe static void SetConstAttrib(GalVertexAttrib Attrib)
+ private static unsafe void SetConstAttrib(GalVertexAttrib attrib)
{
- if (Attrib.Size == GalVertexAttribSize._10_10_10_2 ||
- Attrib.Size == GalVertexAttribSize._11_11_10)
+ if (attrib.Size == GalVertexAttribSize._10_10_10_2 ||
+ attrib.Size == GalVertexAttribSize._11_11_10)
{
- ThrowUnsupportedAttrib(Attrib);
+ ThrowUnsupportedAttrib(attrib);
}
- fixed (byte* Ptr = Attrib.Data)
+ fixed (byte* ptr = attrib.Data)
{
- if (Attrib.Type == GalVertexAttribType.Unorm)
+ if (attrib.Type == GalVertexAttribType.Unorm)
{
- switch (Attrib.Size)
+ switch (attrib.Size)
{
case GalVertexAttribSize._8:
case GalVertexAttribSize._8_8:
case GalVertexAttribSize._8_8_8:
case GalVertexAttribSize._8_8_8_8:
- GL.VertexAttrib4N((uint)Attrib.Index, Ptr);
+ GL.VertexAttrib4N((uint)attrib.Index, ptr);
break;
case GalVertexAttribSize._16:
case GalVertexAttribSize._16_16:
case GalVertexAttribSize._16_16_16:
case GalVertexAttribSize._16_16_16_16:
- GL.VertexAttrib4N((uint)Attrib.Index, (ushort*)Ptr);
+ GL.VertexAttrib4N((uint)attrib.Index, (ushort*)ptr);
break;
case GalVertexAttribSize._32:
case GalVertexAttribSize._32_32:
case GalVertexAttribSize._32_32_32:
case GalVertexAttribSize._32_32_32_32:
- GL.VertexAttrib4N((uint)Attrib.Index, (uint*)Ptr);
+ GL.VertexAttrib4N((uint)attrib.Index, (uint*)ptr);
break;
}
}
- else if (Attrib.Type == GalVertexAttribType.Snorm)
+ else if (attrib.Type == GalVertexAttribType.Snorm)
{
- switch (Attrib.Size)
+ switch (attrib.Size)
{
case GalVertexAttribSize._8:
case GalVertexAttribSize._8_8:
case GalVertexAttribSize._8_8_8:
case GalVertexAttribSize._8_8_8_8:
- GL.VertexAttrib4N((uint)Attrib.Index, (sbyte*)Ptr);
+ GL.VertexAttrib4N((uint)attrib.Index, (sbyte*)ptr);
break;
case GalVertexAttribSize._16:
case GalVertexAttribSize._16_16:
case GalVertexAttribSize._16_16_16:
case GalVertexAttribSize._16_16_16_16:
- GL.VertexAttrib4N((uint)Attrib.Index, (short*)Ptr);
+ GL.VertexAttrib4N((uint)attrib.Index, (short*)ptr);
break;
case GalVertexAttribSize._32:
case GalVertexAttribSize._32_32:
case GalVertexAttribSize._32_32_32:
case GalVertexAttribSize._32_32_32_32:
- GL.VertexAttrib4N((uint)Attrib.Index, (int*)Ptr);
+ GL.VertexAttrib4N((uint)attrib.Index, (int*)ptr);
break;
}
}
- else if (Attrib.Type == GalVertexAttribType.Uint)
+ else if (attrib.Type == GalVertexAttribType.Uint)
{
- switch (Attrib.Size)
+ switch (attrib.Size)
{
case GalVertexAttribSize._8:
case GalVertexAttribSize._8_8:
case GalVertexAttribSize._8_8_8:
case GalVertexAttribSize._8_8_8_8:
- GL.VertexAttribI4((uint)Attrib.Index, Ptr);
+ GL.VertexAttribI4((uint)attrib.Index, ptr);
break;
case GalVertexAttribSize._16:
case GalVertexAttribSize._16_16:
case GalVertexAttribSize._16_16_16:
case GalVertexAttribSize._16_16_16_16:
- GL.VertexAttribI4((uint)Attrib.Index, (ushort*)Ptr);
+ GL.VertexAttribI4((uint)attrib.Index, (ushort*)ptr);
break;
case GalVertexAttribSize._32:
case GalVertexAttribSize._32_32:
case GalVertexAttribSize._32_32_32:
case GalVertexAttribSize._32_32_32_32:
- GL.VertexAttribI4((uint)Attrib.Index, (uint*)Ptr);
+ GL.VertexAttribI4((uint)attrib.Index, (uint*)ptr);
break;
}
}
- else if (Attrib.Type == GalVertexAttribType.Sint)
+ else if (attrib.Type == GalVertexAttribType.Sint)
{
- switch (Attrib.Size)
+ switch (attrib.Size)
{
case GalVertexAttribSize._8:
case GalVertexAttribSize._8_8:
case GalVertexAttribSize._8_8_8:
case GalVertexAttribSize._8_8_8_8:
- GL.VertexAttribI4((uint)Attrib.Index, (sbyte*)Ptr);
+ GL.VertexAttribI4((uint)attrib.Index, (sbyte*)ptr);
break;
case GalVertexAttribSize._16:
case GalVertexAttribSize._16_16:
case GalVertexAttribSize._16_16_16:
case GalVertexAttribSize._16_16_16_16:
- GL.VertexAttribI4((uint)Attrib.Index, (short*)Ptr);
+ GL.VertexAttribI4((uint)attrib.Index, (short*)ptr);
break;
case GalVertexAttribSize._32:
case GalVertexAttribSize._32_32:
case GalVertexAttribSize._32_32_32:
case GalVertexAttribSize._32_32_32_32:
- GL.VertexAttribI4((uint)Attrib.Index, (int*)Ptr);
+ GL.VertexAttribI4((uint)attrib.Index, (int*)ptr);
break;
}
}
- else if (Attrib.Type == GalVertexAttribType.Float)
+ else if (attrib.Type == GalVertexAttribType.Float)
{
- switch (Attrib.Size)
+ switch (attrib.Size)
{
case GalVertexAttribSize._32:
case GalVertexAttribSize._32_32:
case GalVertexAttribSize._32_32_32:
case GalVertexAttribSize._32_32_32_32:
- GL.VertexAttrib4(Attrib.Index, (float*)Ptr);
+ GL.VertexAttrib4(attrib.Index, (float*)ptr);
break;
- default: ThrowUnsupportedAttrib(Attrib); break;
+ default: ThrowUnsupportedAttrib(attrib); break;
}
}
}
}
- private static void ThrowUnsupportedAttrib(GalVertexAttrib Attrib)
+ private static void ThrowUnsupportedAttrib(GalVertexAttrib attrib)
{
- throw new NotImplementedException("Unsupported size \"" + Attrib.Size + "\" on type \"" + Attrib.Type + "\"!");
+ throw new NotImplementedException("Unsupported size \"" + attrib.Size + "\" on type \"" + attrib.Type + "\"!");
}
- private void Enable(EnableCap Cap, bool Enabled)
+ private void Enable(EnableCap cap, bool enabled)
{
- if (Enabled)
+ if (enabled)
{
- GL.Enable(Cap);
+ GL.Enable(cap);
}
else
{
- GL.Disable(Cap);
+ GL.Disable(cap);
}
}
- private void Enable(IndexedEnableCap Cap, int Index, bool Enabled)
+ private void Enable(IndexedEnableCap cap, int index, bool enabled)
{
- if (Enabled)
+ if (enabled)
{
- GL.Enable(Cap, Index);
+ GL.Enable(cap, index);
}
else
{
- GL.Disable(Cap, Index);
+ GL.Disable(cap, index);
}
}
public void ResetDepthMask()
{
- Old.DepthWriteEnabled = true;
+ _old.DepthWriteEnabled = true;
}
- public void ResetColorMask(int Index)
+ public void ResetColorMask(int index)
{
- Old.ColorMasks[Index] = ColorMaskState.Default;
+ _old.ColorMasks[index] = ColorMaskState.Default;
}
}
} \ No newline at end of file
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
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglRenderTarget.cs b/Ryujinx.Graphics/Gal/OpenGL/OglRenderTarget.cs
new file mode 100644
index 00000000..d36bac1b
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OglRenderTarget.cs
@@ -0,0 +1,549 @@
+using OpenTK.Graphics.OpenGL;
+using Ryujinx.Graphics.Texture;
+using System;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ class OglRenderTarget : IGalRenderTarget
+ {
+ private const int NativeWidth = 1280;
+ private const int NativeHeight = 720;
+
+ private const int RenderTargetsCount = GalPipelineState.RenderTargetsCount;
+
+ private struct Rect
+ {
+ public int X { get; private set; }
+ public int Y { get; private set; }
+ public int Width { get; private set; }
+ public int Height { get; private set; }
+
+ public Rect(int x, int y, int width, int height)
+ {
+ X = x;
+ Y = y;
+ Width = width;
+ Height = height;
+ }
+ }
+
+ private class FrameBufferAttachments
+ {
+ public int MapCount { get; set; }
+
+ public DrawBuffersEnum[] Map { get; private set; }
+
+ public long[] Colors { get; private set; }
+
+ public long Zeta { get; set; }
+
+ public FrameBufferAttachments()
+ {
+ Colors = new long[RenderTargetsCount];
+
+ Map = new DrawBuffersEnum[RenderTargetsCount];
+ }
+
+ public void Update(FrameBufferAttachments source)
+ {
+ for (int index = 0; index < RenderTargetsCount; index++)
+ {
+ Map[index] = source.Map[index];
+
+ Colors[index] = source.Colors[index];
+ }
+
+ MapCount = source.MapCount;
+ Zeta = source.Zeta;
+ }
+ }
+
+ private int[] _colorHandles;
+ private int _zetaHandle;
+
+ private OglTexture _texture;
+
+ private ImageHandler _readTex;
+
+ private Rect _window;
+
+ private float[] _viewports;
+
+ private bool _flipX;
+ private bool _flipY;
+
+ private int _cropTop;
+ private int _cropLeft;
+ private int _cropRight;
+ private int _cropBottom;
+
+ //This framebuffer is used to attach guest rendertargets,
+ //think of it as a dummy OpenGL VAO
+ private int _dummyFrameBuffer;
+
+ //These framebuffers are used to blit images
+ private int _srcFb;
+ private int _dstFb;
+
+ private FrameBufferAttachments _attachments;
+ private FrameBufferAttachments _oldAttachments;
+
+ private int _copyPbo;
+
+ public bool FramebufferSrgb { get; set; }
+
+ public OglRenderTarget(OglTexture texture)
+ {
+ _attachments = new FrameBufferAttachments();
+
+ _oldAttachments = new FrameBufferAttachments();
+
+ _colorHandles = new int[RenderTargetsCount];
+
+ _viewports = new float[RenderTargetsCount * 4];
+
+ _texture = texture;
+
+ texture.TextureDeleted += TextureDeletionHandler;
+ }
+
+ private void TextureDeletionHandler(object sender, int handle)
+ {
+ //Texture was deleted, the handle is no longer valid, so
+ //reset all uses of this handle on a render target.
+ for (int attachment = 0; attachment < RenderTargetsCount; attachment++)
+ {
+ if (_colorHandles[attachment] == handle)
+ {
+ _colorHandles[attachment] = 0;
+ }
+ }
+
+ if (_zetaHandle == handle)
+ {
+ _zetaHandle = 0;
+ }
+ }
+
+ public void Bind()
+ {
+ if (_dummyFrameBuffer == 0)
+ {
+ _dummyFrameBuffer = GL.GenFramebuffer();
+ }
+
+ GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, _dummyFrameBuffer);
+
+ ImageHandler cachedImage;
+
+ for (int attachment = 0; attachment < RenderTargetsCount; attachment++)
+ {
+ long key = _attachments.Colors[attachment];
+
+ int handle = 0;
+
+ if (key != 0 && _texture.TryGetImageHandler(key, out cachedImage))
+ {
+ handle = cachedImage.Handle;
+ }
+
+ if (handle == _colorHandles[attachment])
+ {
+ continue;
+ }
+
+ GL.FramebufferTexture(
+ FramebufferTarget.DrawFramebuffer,
+ FramebufferAttachment.ColorAttachment0 + attachment,
+ handle,
+ 0);
+
+ _colorHandles[attachment] = handle;
+ }
+
+ if (_attachments.Zeta != 0 && _texture.TryGetImageHandler(_attachments.Zeta, out cachedImage))
+ {
+ if (cachedImage.Handle != _zetaHandle)
+ {
+ if (cachedImage.HasDepth && cachedImage.HasStencil)
+ {
+ GL.FramebufferTexture(
+ FramebufferTarget.DrawFramebuffer,
+ FramebufferAttachment.DepthStencilAttachment,
+ cachedImage.Handle,
+ 0);
+ }
+ else if (cachedImage.HasDepth)
+ {
+ GL.FramebufferTexture(
+ FramebufferTarget.DrawFramebuffer,
+ FramebufferAttachment.DepthAttachment,
+ cachedImage.Handle,
+ 0);
+
+ GL.FramebufferTexture(
+ FramebufferTarget.DrawFramebuffer,
+ FramebufferAttachment.StencilAttachment,
+ 0,
+ 0);
+ }
+ else
+ {
+ throw new InvalidOperationException("Invalid image format \"" + cachedImage.Format + "\" used as Zeta!");
+ }
+
+ _zetaHandle = cachedImage.Handle;
+ }
+ }
+ else if (_zetaHandle != 0)
+ {
+ GL.FramebufferTexture(
+ FramebufferTarget.DrawFramebuffer,
+ FramebufferAttachment.DepthStencilAttachment,
+ 0,
+ 0);
+
+ _zetaHandle = 0;
+ }
+
+ if (OglExtension.ViewportArray)
+ {
+ GL.ViewportArray(0, RenderTargetsCount, _viewports);
+ }
+ else
+ {
+ GL.Viewport(
+ (int)_viewports[0],
+ (int)_viewports[1],
+ (int)_viewports[2],
+ (int)_viewports[3]);
+ }
+
+ if (_attachments.MapCount > 1)
+ {
+ GL.DrawBuffers(_attachments.MapCount, _attachments.Map);
+ }
+ else if (_attachments.MapCount == 1)
+ {
+ GL.DrawBuffer((DrawBufferMode)_attachments.Map[0]);
+ }
+ else
+ {
+ GL.DrawBuffer(DrawBufferMode.None);
+ }
+
+ _oldAttachments.Update(_attachments);
+ }
+
+ public void BindColor(long key, int attachment)
+ {
+ _attachments.Colors[attachment] = key;
+ }
+
+ public void UnbindColor(int attachment)
+ {
+ _attachments.Colors[attachment] = 0;
+ }
+
+ public void BindZeta(long key)
+ {
+ _attachments.Zeta = key;
+ }
+
+ public void UnbindZeta()
+ {
+ _attachments.Zeta = 0;
+ }
+
+ public void Present(long key)
+ {
+ _texture.TryGetImageHandler(key, out _readTex);
+ }
+
+ public void SetMap(int[] map)
+ {
+ if (map != null)
+ {
+ _attachments.MapCount = map.Length;
+
+ for (int attachment = 0; attachment < _attachments.MapCount; attachment++)
+ {
+ _attachments.Map[attachment] = DrawBuffersEnum.ColorAttachment0 + map[attachment];
+ }
+ }
+ else
+ {
+ _attachments.MapCount = 0;
+ }
+ }
+
+ public void SetTransform(bool flipX, bool flipY, int top, int left, int right, int bottom)
+ {
+ _flipX = flipX;
+ _flipY = flipY;
+
+ _cropTop = top;
+ _cropLeft = left;
+ _cropRight = right;
+ _cropBottom = bottom;
+ }
+
+ public void SetWindowSize(int width, int height)
+ {
+ _window = new Rect(0, 0, width, height);
+ }
+
+ public void SetViewport(int attachment, int x, int y, int width, int height)
+ {
+ int offset = attachment * 4;
+
+ _viewports[offset + 0] = x;
+ _viewports[offset + 1] = y;
+ _viewports[offset + 2] = width;
+ _viewports[offset + 3] = height;
+ }
+
+ public void Render()
+ {
+ if (_readTex == null)
+ {
+ return;
+ }
+
+ int srcX0, srcX1, srcY0, srcY1;
+
+ if (_cropLeft == 0 && _cropRight == 0)
+ {
+ srcX0 = 0;
+ srcX1 = _readTex.Width;
+ }
+ else
+ {
+ srcX0 = _cropLeft;
+ srcX1 = _cropRight;
+ }
+
+ if (_cropTop == 0 && _cropBottom == 0)
+ {
+ srcY0 = 0;
+ srcY1 = _readTex.Height;
+ }
+ else
+ {
+ srcY0 = _cropTop;
+ srcY1 = _cropBottom;
+ }
+
+ float ratioX = MathF.Min(1f, (_window.Height * (float)NativeWidth) / ((float)NativeHeight * _window.Width));
+ float ratioY = MathF.Min(1f, (_window.Width * (float)NativeHeight) / ((float)NativeWidth * _window.Height));
+
+ int dstWidth = (int)(_window.Width * ratioX);
+ int dstHeight = (int)(_window.Height * ratioY);
+
+ int dstPaddingX = (_window.Width - dstWidth) / 2;
+ int dstPaddingY = (_window.Height - dstHeight) / 2;
+
+ int dstX0 = _flipX ? _window.Width - dstPaddingX : dstPaddingX;
+ int dstX1 = _flipX ? dstPaddingX : _window.Width - dstPaddingX;
+
+ int dstY0 = _flipY ? dstPaddingY : _window.Height - dstPaddingY;
+ int dstY1 = _flipY ? _window.Height - dstPaddingY : dstPaddingY;
+
+ GL.Viewport(0, 0, _window.Width, _window.Height);
+
+ if (_srcFb == 0)
+ {
+ _srcFb = GL.GenFramebuffer();
+ }
+
+ GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, _srcFb);
+ GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0);
+
+ GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, _readTex.Handle, 0);
+
+ GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
+
+ GL.Clear(ClearBufferMask.ColorBufferBit);
+
+ GL.Disable(EnableCap.FramebufferSrgb);
+
+ GL.BlitFramebuffer(
+ srcX0,
+ srcY0,
+ srcX1,
+ srcY1,
+ dstX0,
+ dstY0,
+ dstX1,
+ dstY1,
+ ClearBufferMask.ColorBufferBit,
+ BlitFramebufferFilter.Linear);
+
+ if (FramebufferSrgb)
+ {
+ GL.Enable(EnableCap.FramebufferSrgb);
+ }
+ }
+
+ public void Copy(
+ GalImage srcImage,
+ GalImage dstImage,
+ long srcKey,
+ long dstKey,
+ int srcLayer,
+ int dstLayer,
+ int srcX0,
+ int srcY0,
+ int srcX1,
+ int srcY1,
+ int dstX0,
+ int dstY0,
+ int dstX1,
+ int dstY1)
+ {
+ if (_texture.TryGetImageHandler(srcKey, out ImageHandler srcTex) &&
+ _texture.TryGetImageHandler(dstKey, out ImageHandler dstTex))
+ {
+ if (srcTex.HasColor != dstTex.HasColor ||
+ srcTex.HasDepth != dstTex.HasDepth ||
+ srcTex.HasStencil != dstTex.HasStencil)
+ {
+ throw new NotImplementedException();
+ }
+
+ if (_srcFb == 0)
+ {
+ _srcFb = GL.GenFramebuffer();
+ }
+
+ if (_dstFb == 0)
+ {
+ _dstFb = GL.GenFramebuffer();
+ }
+
+ GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, _srcFb);
+ GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, _dstFb);
+
+ FramebufferAttachment attachment = GetAttachment(srcTex);
+
+ if (ImageUtils.IsArray(srcImage.TextureTarget) && srcLayer > 0)
+ {
+ GL.FramebufferTextureLayer(FramebufferTarget.ReadFramebuffer, attachment, srcTex.Handle, 0, srcLayer);
+ }
+ else
+ {
+ GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, attachment, srcTex.Handle, 0);
+ }
+
+ if (ImageUtils.IsArray(dstImage.TextureTarget) && dstLayer > 0)
+ {
+ GL.FramebufferTextureLayer(FramebufferTarget.DrawFramebuffer, attachment, dstTex.Handle, 0, dstLayer);
+ }
+ else
+ {
+ GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, attachment, dstTex.Handle, 0);
+ }
+
+
+ BlitFramebufferFilter filter = BlitFramebufferFilter.Nearest;
+
+ if (srcTex.HasColor)
+ {
+ GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
+
+ filter = BlitFramebufferFilter.Linear;
+ }
+
+ ClearBufferMask mask = GetClearMask(srcTex);
+
+ GL.BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+ }
+ }
+
+ public void Reinterpret(long key, GalImage newImage)
+ {
+ if (!_texture.TryGetImage(key, out GalImage oldImage))
+ {
+ return;
+ }
+
+ if (newImage.Format == oldImage.Format &&
+ newImage.Width == oldImage.Width &&
+ newImage.Height == oldImage.Height &&
+ newImage.Depth == oldImage.Depth &&
+ newImage.LayerCount == oldImage.LayerCount &&
+ newImage.TextureTarget == oldImage.TextureTarget)
+ {
+ return;
+ }
+
+ if (_copyPbo == 0)
+ {
+ _copyPbo = GL.GenBuffer();
+ }
+
+ GL.BindBuffer(BufferTarget.PixelPackBuffer, _copyPbo);
+
+ //The buffer should be large enough to hold the largest texture.
+ int bufferSize = Math.Max(ImageUtils.GetSize(oldImage),
+ ImageUtils.GetSize(newImage));
+
+ GL.BufferData(BufferTarget.PixelPackBuffer, bufferSize, IntPtr.Zero, BufferUsageHint.StreamCopy);
+
+ if (!_texture.TryGetImageHandler(key, out ImageHandler cachedImage))
+ {
+ throw new InvalidOperationException();
+ }
+
+ (_, PixelFormat format, PixelType type) = OglEnumConverter.GetImageFormat(cachedImage.Format);
+
+ TextureTarget target = ImageUtils.GetTextureTarget(newImage.TextureTarget);
+
+ GL.BindTexture(target, cachedImage.Handle);
+
+ GL.GetTexImage(target, 0, format, type, IntPtr.Zero);
+
+ GL.BindBuffer(BufferTarget.PixelPackBuffer, 0);
+ GL.BindBuffer(BufferTarget.PixelUnpackBuffer, _copyPbo);
+
+ GL.PixelStore(PixelStoreParameter.UnpackRowLength, oldImage.Width);
+
+ _texture.Create(key, ImageUtils.GetSize(newImage), newImage);
+
+ GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0);
+
+ GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0);
+ }
+
+ private static FramebufferAttachment GetAttachment(ImageHandler cachedImage)
+ {
+ if (cachedImage.HasColor)
+ {
+ return FramebufferAttachment.ColorAttachment0;
+ }
+ else if (cachedImage.HasDepth && cachedImage.HasStencil)
+ {
+ return FramebufferAttachment.DepthStencilAttachment;
+ }
+ else if (cachedImage.HasDepth)
+ {
+ return FramebufferAttachment.DepthAttachment;
+ }
+ else if (cachedImage.HasStencil)
+ {
+ return FramebufferAttachment.StencilAttachment;
+ }
+ else
+ {
+ throw new InvalidOperationException();
+ }
+ }
+
+ private static ClearBufferMask GetClearMask(ImageHandler cachedImage)
+ {
+ return (cachedImage.HasColor ? ClearBufferMask.ColorBufferBit : 0) |
+ (cachedImage.HasDepth ? ClearBufferMask.DepthBufferBit : 0) |
+ (cachedImage.HasStencil ? ClearBufferMask.StencilBufferBit : 0);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OglRenderer.cs
new file mode 100644
index 00000000..1ff8c7ad
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OglRenderer.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Concurrent;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ public class OglRenderer : IGalRenderer
+ {
+ public IGalConstBuffer Buffer { get; private set; }
+
+ public IGalRenderTarget RenderTarget { get; private set; }
+
+ public IGalRasterizer Rasterizer { get; private set; }
+
+ public IGalShader Shader { get; private set; }
+
+ public IGalPipeline Pipeline { get; private set; }
+
+ public IGalTexture Texture { get; private set; }
+
+ private ConcurrentQueue<Action> _actionsQueue;
+
+ public OglRenderer()
+ {
+ Buffer = new OglConstBuffer();
+
+ Texture = new OglTexture();
+
+ RenderTarget = new OglRenderTarget(Texture as OglTexture);
+
+ Rasterizer = new OglRasterizer();
+
+ Shader = new OglShader(Buffer as OglConstBuffer);
+
+ Pipeline = new OglPipeline(
+ Buffer as OglConstBuffer,
+ RenderTarget as OglRenderTarget,
+ Rasterizer as OglRasterizer,
+ Shader as OglShader);
+
+ _actionsQueue = new ConcurrentQueue<Action>();
+ }
+
+ public void QueueAction(Action actionMthd)
+ {
+ _actionsQueue.Enqueue(actionMthd);
+ }
+
+ public void RunActions()
+ {
+ int count = _actionsQueue.Count;
+
+ while (count-- > 0 && _actionsQueue.TryDequeue(out Action renderAction))
+ {
+ renderAction();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OglShader.cs
new file mode 100644
index 00000000..8faa9053
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OglShader.cs
@@ -0,0 +1,298 @@
+using OpenTK.Graphics.OpenGL;
+using Ryujinx.Graphics.Gal.Shader;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ class OglShader : IGalShader
+ {
+ public const int ReservedCbufCount = 1;
+
+ private const int ExtraDataSize = 4;
+
+ public OglShaderProgram Current;
+
+ private ConcurrentDictionary<long, OglShaderStage> _stages;
+
+ private Dictionary<OglShaderProgram, int> _programs;
+
+ public int CurrentProgramHandle { get; private set; }
+
+ private OglConstBuffer _buffer;
+
+ private int _extraUboHandle;
+
+ public OglShader(OglConstBuffer buffer)
+ {
+ _buffer = buffer;
+
+ _stages = new ConcurrentDictionary<long, OglShaderStage>();
+
+ _programs = new Dictionary<OglShaderProgram, int>();
+ }
+
+ public void Create(IGalMemory memory, long key, GalShaderType type)
+ {
+ _stages.GetOrAdd(key, (stage) => ShaderStageFactory(memory, key, 0, false, type));
+ }
+
+ public void Create(IGalMemory memory, long vpAPos, long key, GalShaderType type)
+ {
+ _stages.GetOrAdd(key, (stage) => ShaderStageFactory(memory, vpAPos, key, true, type));
+ }
+
+ private OglShaderStage ShaderStageFactory(
+ IGalMemory memory,
+ long position,
+ long positionB,
+ bool isDualVp,
+ GalShaderType type)
+ {
+ GlslProgram program;
+
+ GlslDecompiler decompiler = new GlslDecompiler(OglLimit.MaxUboSize, OglExtension.NvidiaDriver);
+
+ int shaderDumpIndex = ShaderDumper.DumpIndex;
+
+ if (isDualVp)
+ {
+ ShaderDumper.Dump(memory, position, type, "a");
+ ShaderDumper.Dump(memory, positionB, type, "b");
+
+ program = decompiler.Decompile(memory, position, positionB, type);
+ }
+ else
+ {
+ ShaderDumper.Dump(memory, position, type);
+
+ program = decompiler.Decompile(memory, position, type);
+ }
+
+ string code = program.Code;
+
+ if (ShaderDumper.IsDumpEnabled())
+ {
+ code = "//Shader " + shaderDumpIndex + Environment.NewLine + code;
+ }
+
+ return new OglShaderStage(type, code, program.Uniforms, program.Textures);
+ }
+
+ public IEnumerable<ShaderDeclInfo> GetConstBufferUsage(long key)
+ {
+ if (_stages.TryGetValue(key, out OglShaderStage stage))
+ {
+ return stage.ConstBufferUsage;
+ }
+
+ return Enumerable.Empty<ShaderDeclInfo>();
+ }
+
+ public IEnumerable<ShaderDeclInfo> GetTextureUsage(long key)
+ {
+ if (_stages.TryGetValue(key, out OglShaderStage stage))
+ {
+ return stage.TextureUsage;
+ }
+
+ return Enumerable.Empty<ShaderDeclInfo>();
+ }
+
+ public unsafe void SetExtraData(float flipX, float flipY, int instance)
+ {
+ BindProgram();
+
+ EnsureExtraBlock();
+
+ GL.BindBuffer(BufferTarget.UniformBuffer, _extraUboHandle);
+
+ float* data = stackalloc float[ExtraDataSize];
+ data[0] = flipX;
+ data[1] = flipY;
+ data[2] = BitConverter.Int32BitsToSingle(instance);
+
+ //Invalidate buffer
+ GL.BufferData(BufferTarget.UniformBuffer, ExtraDataSize * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw);
+
+ GL.BufferSubData(BufferTarget.UniformBuffer, IntPtr.Zero, ExtraDataSize * sizeof(float), (IntPtr)data);
+ }
+
+ public void Bind(long key)
+ {
+ if (_stages.TryGetValue(key, out OglShaderStage stage))
+ {
+ Bind(stage);
+ }
+ }
+
+ private void Bind(OglShaderStage stage)
+ {
+ if (stage.Type == GalShaderType.Geometry)
+ {
+ //Enhanced layouts are required for Geometry shaders
+ //skip this stage if current driver has no ARB_enhanced_layouts
+ if (!OglExtension.EnhancedLayouts)
+ {
+ return;
+ }
+ }
+
+ switch (stage.Type)
+ {
+ case GalShaderType.Vertex: Current.Vertex = stage; break;
+ case GalShaderType.TessControl: Current.TessControl = stage; break;
+ case GalShaderType.TessEvaluation: Current.TessEvaluation = stage; break;
+ case GalShaderType.Geometry: Current.Geometry = stage; break;
+ case GalShaderType.Fragment: Current.Fragment = stage; break;
+ }
+ }
+
+ public void Unbind(GalShaderType type)
+ {
+ switch (type)
+ {
+ case GalShaderType.Vertex: Current.Vertex = null; break;
+ case GalShaderType.TessControl: Current.TessControl = null; break;
+ case GalShaderType.TessEvaluation: Current.TessEvaluation = null; break;
+ case GalShaderType.Geometry: Current.Geometry = null; break;
+ case GalShaderType.Fragment: Current.Fragment = null; break;
+ }
+ }
+
+ public void BindProgram()
+ {
+ if (Current.Vertex == null ||
+ Current.Fragment == null)
+ {
+ return;
+ }
+
+ if (!_programs.TryGetValue(Current, out int handle))
+ {
+ handle = GL.CreateProgram();
+
+ AttachIfNotNull(handle, Current.Vertex);
+ AttachIfNotNull(handle, Current.TessControl);
+ AttachIfNotNull(handle, Current.TessEvaluation);
+ AttachIfNotNull(handle, Current.Geometry);
+ AttachIfNotNull(handle, Current.Fragment);
+
+ GL.LinkProgram(handle);
+
+ CheckProgramLink(handle);
+
+ BindUniformBlocks(handle);
+ BindTextureLocations(handle);
+
+ _programs.Add(Current, handle);
+ }
+
+ GL.UseProgram(handle);
+
+ CurrentProgramHandle = handle;
+ }
+
+ private void EnsureExtraBlock()
+ {
+ if (_extraUboHandle == 0)
+ {
+ _extraUboHandle = GL.GenBuffer();
+
+ GL.BindBuffer(BufferTarget.UniformBuffer, _extraUboHandle);
+
+ GL.BufferData(BufferTarget.UniformBuffer, ExtraDataSize * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw);
+
+ GL.BindBufferBase(BufferRangeTarget.UniformBuffer, 0, _extraUboHandle);
+ }
+ }
+
+ private void AttachIfNotNull(int programHandle, OglShaderStage stage)
+ {
+ if (stage != null)
+ {
+ stage.Compile();
+
+ GL.AttachShader(programHandle, stage.Handle);
+ }
+ }
+
+ private void BindUniformBlocks(int programHandle)
+ {
+ int extraBlockindex = GL.GetUniformBlockIndex(programHandle, GlslDecl.ExtraUniformBlockName);
+
+ GL.UniformBlockBinding(programHandle, extraBlockindex, 0);
+
+ int freeBinding = ReservedCbufCount;
+
+ void BindUniformBlocksIfNotNull(OglShaderStage stage)
+ {
+ if (stage != null)
+ {
+ foreach (ShaderDeclInfo declInfo in stage.ConstBufferUsage)
+ {
+ int blockIndex = GL.GetUniformBlockIndex(programHandle, declInfo.Name);
+
+ if (blockIndex < 0)
+ {
+ //It is expected that its found, if it's not then driver might be in a malfunction
+ throw new InvalidOperationException();
+ }
+
+ GL.UniformBlockBinding(programHandle, blockIndex, freeBinding);
+
+ freeBinding++;
+ }
+ }
+ }
+
+ BindUniformBlocksIfNotNull(Current.Vertex);
+ BindUniformBlocksIfNotNull(Current.TessControl);
+ BindUniformBlocksIfNotNull(Current.TessEvaluation);
+ BindUniformBlocksIfNotNull(Current.Geometry);
+ BindUniformBlocksIfNotNull(Current.Fragment);
+ }
+
+ private void BindTextureLocations(int programHandle)
+ {
+ int index = 0;
+
+ void BindTexturesIfNotNull(OglShaderStage stage)
+ {
+ if (stage != null)
+ {
+ foreach (ShaderDeclInfo decl in stage.TextureUsage)
+ {
+ int location = GL.GetUniformLocation(programHandle, decl.Name);
+
+ GL.Uniform1(location, index);
+
+ index++;
+ }
+ }
+ }
+
+ GL.UseProgram(programHandle);
+
+ BindTexturesIfNotNull(Current.Vertex);
+ BindTexturesIfNotNull(Current.TessControl);
+ BindTexturesIfNotNull(Current.TessEvaluation);
+ BindTexturesIfNotNull(Current.Geometry);
+ BindTexturesIfNotNull(Current.Fragment);
+ }
+
+ private static void CheckProgramLink(int handle)
+ {
+ int status = 0;
+
+ GL.GetProgram(handle, GetProgramParameterName.LinkStatus, out status);
+
+ if (status == 0)
+ {
+ throw new ShaderException(GL.GetProgramInfoLog(handle));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs b/Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs
new file mode 100644
index 00000000..9e68a8e6
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs
@@ -0,0 +1,86 @@
+using OpenTK.Graphics.OpenGL;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ struct OglShaderProgram
+ {
+ public OglShaderStage Vertex;
+ public OglShaderStage TessControl;
+ public OglShaderStage TessEvaluation;
+ public OglShaderStage Geometry;
+ public OglShaderStage Fragment;
+ }
+
+ class OglShaderStage : IDisposable
+ {
+ public int Handle { get; private set; }
+
+ public bool IsCompiled { get; private set; }
+
+ public GalShaderType Type { get; private set; }
+
+ public string Code { get; private set; }
+
+ public IEnumerable<ShaderDeclInfo> ConstBufferUsage { get; private set; }
+ public IEnumerable<ShaderDeclInfo> TextureUsage { get; private set; }
+
+ public OglShaderStage(
+ GalShaderType type,
+ string code,
+ IEnumerable<ShaderDeclInfo> constBufferUsage,
+ IEnumerable<ShaderDeclInfo> textureUsage)
+ {
+ Type = type;
+ Code = code;
+ ConstBufferUsage = constBufferUsage;
+ TextureUsage = textureUsage;
+ }
+
+ public void Compile()
+ {
+ if (Handle == 0)
+ {
+ Handle = GL.CreateShader(OglEnumConverter.GetShaderType(Type));
+
+ CompileAndCheck(Handle, Code);
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing && Handle != 0)
+ {
+ GL.DeleteShader(Handle);
+
+ Handle = 0;
+ }
+ }
+
+ public static void CompileAndCheck(int handle, string code)
+ {
+ GL.ShaderSource(handle, code);
+ GL.CompileShader(handle);
+
+ CheckCompilation(handle);
+ }
+
+ private static void CheckCompilation(int handle)
+ {
+ int status = 0;
+
+ GL.GetShader(handle, ShaderParameter.CompileStatus, out status);
+
+ if (status == 0)
+ {
+ throw new ShaderException(GL.GetShaderInfoLog(handle));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLStreamBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OglStreamBuffer.cs
index 411d33aa..58b3ace5 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLStreamBuffer.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OglStreamBuffer.cs
@@ -3,7 +3,7 @@ using System;
namespace Ryujinx.Graphics.Gal.OpenGL
{
- class OGLStreamBuffer : IDisposable
+ class OglStreamBuffer : IDisposable
{
public int Handle { get; protected set; }
@@ -11,30 +11,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL
protected BufferTarget Target { get; private set; }
- public OGLStreamBuffer(BufferTarget Target, long Size)
+ public OglStreamBuffer(BufferTarget target, long size)
{
- this.Target = Target;
- this.Size = Size;
+ Target = target;
+ Size = size;
Handle = GL.GenBuffer();
- GL.BindBuffer(Target, Handle);
+ GL.BindBuffer(target, Handle);
- GL.BufferData(Target, (IntPtr)Size, IntPtr.Zero, BufferUsageHint.StreamDraw);
+ GL.BufferData(target, (IntPtr)size, IntPtr.Zero, BufferUsageHint.StreamDraw);
}
- public void SetData(long Size, IntPtr HostAddress)
+ public void SetData(long size, IntPtr hostAddress)
{
GL.BindBuffer(Target, Handle);
- GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)Size, HostAddress);
+ GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)size, hostAddress);
}
- public void SetData(byte[] Data)
+ public void SetData(byte[] data)
{
GL.BindBuffer(Target, Handle);
- GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)Data.Length, Data);
+ GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)data.Length, data);
}
public void Dispose()
@@ -42,9 +42,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
Dispose(true);
}
- protected virtual void Dispose(bool Disposing)
+ protected virtual void Dispose(bool disposing)
{
- if (Disposing && Handle != 0)
+ if (disposing && Handle != 0)
{
GL.DeleteBuffer(Handle);
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs
new file mode 100644
index 00000000..f836702f
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs
@@ -0,0 +1,381 @@
+using OpenTK.Graphics.OpenGL;
+using Ryujinx.Graphics.Texture;
+using System;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ class OglTexture : IGalTexture
+ {
+ private const long MaxTextureCacheSize = 768 * 1024 * 1024;
+
+ private OglCachedResource<ImageHandler> _textureCache;
+
+ public EventHandler<int> TextureDeleted { get; set; }
+
+ public OglTexture()
+ {
+ _textureCache = new OglCachedResource<ImageHandler>(DeleteTexture, MaxTextureCacheSize);
+ }
+
+ public void LockCache()
+ {
+ _textureCache.Lock();
+ }
+
+ public void UnlockCache()
+ {
+ _textureCache.Unlock();
+ }
+
+ private void DeleteTexture(ImageHandler cachedImage)
+ {
+ TextureDeleted?.Invoke(this, cachedImage.Handle);
+
+ GL.DeleteTexture(cachedImage.Handle);
+ }
+
+ public void Create(long key, int size, GalImage image)
+ {
+ int handle = GL.GenTexture();
+
+ TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
+
+ GL.BindTexture(target, handle);
+
+ const int level = 0; //TODO: Support mipmap textures.
+ const int border = 0;
+
+ _textureCache.AddOrUpdate(key, new ImageHandler(handle, image), (uint)size);
+
+ if (ImageUtils.IsCompressed(image.Format))
+ {
+ throw new InvalidOperationException("Surfaces with compressed formats are not supported!");
+ }
+
+ (PixelInternalFormat internalFmt,
+ PixelFormat format,
+ PixelType type) = OglEnumConverter.GetImageFormat(image.Format);
+
+ switch (target)
+ {
+ case TextureTarget.Texture1D:
+ GL.TexImage1D(
+ target,
+ level,
+ internalFmt,
+ image.Width,
+ border,
+ format,
+ type,
+ IntPtr.Zero);
+ break;
+
+ case TextureTarget.Texture2D:
+ GL.TexImage2D(
+ target,
+ level,
+ internalFmt,
+ image.Width,
+ image.Height,
+ border,
+ format,
+ type,
+ IntPtr.Zero);
+ break;
+ case TextureTarget.Texture3D:
+ GL.TexImage3D(
+ target,
+ level,
+ internalFmt,
+ image.Width,
+ image.Height,
+ image.Depth,
+ border,
+ format,
+ type,
+ IntPtr.Zero);
+ break;
+ case TextureTarget.Texture2DArray:
+ GL.TexImage3D(
+ target,
+ level,
+ internalFmt,
+ image.Width,
+ image.Height,
+ image.LayerCount,
+ border,
+ format,
+ type,
+ IntPtr.Zero);
+ break;
+ default:
+ throw new NotImplementedException($"Unsupported texture target type: {target}");
+ }
+ }
+
+ public void Create(long key, byte[] data, GalImage image)
+ {
+ int handle = GL.GenTexture();
+
+ TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
+
+ GL.BindTexture(target, handle);
+
+ const int level = 0; //TODO: Support mipmap textures.
+ const int border = 0;
+
+ _textureCache.AddOrUpdate(key, new ImageHandler(handle, image), (uint)data.Length);
+
+ if (ImageUtils.IsCompressed(image.Format) && !IsAstc(image.Format))
+ {
+ InternalFormat internalFmt = OglEnumConverter.GetCompressedImageFormat(image.Format);
+
+ switch (target)
+ {
+ case TextureTarget.Texture1D:
+ GL.CompressedTexImage1D(
+ target,
+ level,
+ internalFmt,
+ image.Width,
+ border,
+ data.Length,
+ data);
+ break;
+ case TextureTarget.Texture2D:
+ GL.CompressedTexImage2D(
+ target,
+ level,
+ internalFmt,
+ image.Width,
+ image.Height,
+ border,
+ data.Length,
+ data);
+ break;
+ case TextureTarget.Texture3D:
+ GL.CompressedTexImage3D(
+ target,
+ level,
+ internalFmt,
+ image.Width,
+ image.Height,
+ image.Depth,
+ border,
+ data.Length,
+ data);
+ break;
+ case TextureTarget.Texture2DArray:
+ GL.CompressedTexImage3D(
+ target,
+ level,
+ internalFmt,
+ image.Width,
+ image.Height,
+ image.LayerCount,
+ border,
+ data.Length,
+ data);
+ break;
+ default:
+ throw new NotImplementedException($"Unsupported texture target type: {target}");
+ }
+ }
+ else
+ {
+ //TODO: Use KHR_texture_compression_astc_hdr when available
+ if (IsAstc(image.Format))
+ {
+ int textureBlockWidth = ImageUtils.GetBlockWidth(image.Format);
+ int textureBlockHeight = ImageUtils.GetBlockHeight(image.Format);
+ int textureBlockDepth = ImageUtils.GetBlockDepth(image.Format);
+
+ data = AstcDecoder.DecodeToRgba8888(
+ data,
+ textureBlockWidth,
+ textureBlockHeight,
+ textureBlockDepth,
+ image.Width,
+ image.Height,
+ image.Depth);
+
+ image.Format = GalImageFormat.Rgba8 | (image.Format & GalImageFormat.TypeMask);
+ }
+
+ (PixelInternalFormat internalFmt,
+ PixelFormat format,
+ PixelType type) = OglEnumConverter.GetImageFormat(image.Format);
+
+
+ switch (target)
+ {
+ case TextureTarget.Texture1D:
+ GL.TexImage1D(
+ target,
+ level,
+ internalFmt,
+ image.Width,
+ border,
+ format,
+ type,
+ data);
+ break;
+ case TextureTarget.Texture2D:
+ GL.TexImage2D(
+ target,
+ level,
+ internalFmt,
+ image.Width,
+ image.Height,
+ border,
+ format,
+ type,
+ data);
+ break;
+ case TextureTarget.Texture3D:
+ GL.TexImage3D(
+ target,
+ level,
+ internalFmt,
+ image.Width,
+ image.Height,
+ image.Depth,
+ border,
+ format,
+ type,
+ data);
+ break;
+ case TextureTarget.Texture2DArray:
+ GL.TexImage3D(
+ target,
+ level,
+ internalFmt,
+ image.Width,
+ image.Height,
+ image.LayerCount,
+ border,
+ format,
+ type,
+ data);
+ break;
+ case TextureTarget.TextureCubeMap:
+ Span<byte> array = new Span<byte>(data);
+
+ int faceSize = ImageUtils.GetSize(image) / 6;
+
+ for (int face = 0; face < 6; face++)
+ {
+ GL.TexImage2D(
+ TextureTarget.TextureCubeMapPositiveX + face,
+ level,
+ internalFmt,
+ image.Width,
+ image.Height,
+ border,
+ format,
+ type,
+ array.Slice(face * faceSize, faceSize).ToArray());
+ }
+ break;
+ default:
+ throw new NotImplementedException($"Unsupported texture target type: {target}");
+ }
+ }
+ }
+
+ private static bool IsAstc(GalImageFormat format)
+ {
+ format &= GalImageFormat.FormatMask;
+
+ return format > GalImageFormat.Astc2DStart && format < GalImageFormat.Astc2DEnd;
+ }
+
+ public bool TryGetImage(long key, out GalImage image)
+ {
+ if (_textureCache.TryGetValue(key, out ImageHandler cachedImage))
+ {
+ image = cachedImage.Image;
+
+ return true;
+ }
+
+ image = default(GalImage);
+
+ return false;
+ }
+
+ public bool TryGetImageHandler(long key, out ImageHandler cachedImage)
+ {
+ if (_textureCache.TryGetValue(key, out cachedImage))
+ {
+ return true;
+ }
+
+ cachedImage = null;
+
+ return false;
+ }
+
+ public void Bind(long key, int index, GalImage image)
+ {
+ if (_textureCache.TryGetValue(key, out ImageHandler cachedImage))
+ {
+ GL.ActiveTexture(TextureUnit.Texture0 + index);
+
+ TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
+
+ GL.BindTexture(target, cachedImage.Handle);
+
+ int[] swizzleRgba = new int[]
+ {
+ (int)OglEnumConverter.GetTextureSwizzle(image.XSource),
+ (int)OglEnumConverter.GetTextureSwizzle(image.YSource),
+ (int)OglEnumConverter.GetTextureSwizzle(image.ZSource),
+ (int)OglEnumConverter.GetTextureSwizzle(image.WSource)
+ };
+
+ GL.TexParameter(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba);
+ }
+ }
+
+ public void SetSampler(GalImage image, GalTextureSampler sampler)
+ {
+ int wrapS = (int)OglEnumConverter.GetTextureWrapMode(sampler.AddressU);
+ int wrapT = (int)OglEnumConverter.GetTextureWrapMode(sampler.AddressV);
+ int wrapR = (int)OglEnumConverter.GetTextureWrapMode(sampler.AddressP);
+
+ int minFilter = (int)OglEnumConverter.GetTextureMinFilter(sampler.MinFilter, sampler.MipFilter);
+ int magFilter = (int)OglEnumConverter.GetTextureMagFilter(sampler.MagFilter);
+
+ TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget);
+
+ GL.TexParameter(target, TextureParameterName.TextureWrapS, wrapS);
+ GL.TexParameter(target, TextureParameterName.TextureWrapT, wrapT);
+ GL.TexParameter(target, TextureParameterName.TextureWrapR, wrapR);
+
+ GL.TexParameter(target, TextureParameterName.TextureMinFilter, minFilter);
+ GL.TexParameter(target, TextureParameterName.TextureMagFilter, magFilter);
+
+ float[] color = new float[]
+ {
+ sampler.BorderColor.Red,
+ sampler.BorderColor.Green,
+ sampler.BorderColor.Blue,
+ sampler.BorderColor.Alpha
+ };
+
+ GL.TexParameter(target, TextureParameterName.TextureBorderColor, color);
+
+ if (sampler.DepthCompare)
+ {
+ GL.TexParameter(target, TextureParameterName.TextureCompareMode, (int)All.CompareRToTexture);
+ GL.TexParameter(target, TextureParameterName.TextureCompareFunc, (int)OglEnumConverter.GetDepthCompareFunc(sampler.DepthCompareFunc));
+ }
+ else
+ {
+ GL.TexParameter(target, TextureParameterName.TextureCompareMode, (int)All.None);
+ GL.TexParameter(target, TextureParameterName.TextureCompareFunc, (int)All.Never);
+ }
+ }
+ }
+}