aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Gal/OpenGL
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-04-08 16:17:35 -0300
committergdkchan <gab.dark.100@gmail.com>2018-04-08 16:41:38 -0300
commitb9aa3966c00b4bb3ff0292dc28ed53ad26cf284b (patch)
treecd2ab3d65c61ac6c6ceb312116e5d138868a3e18 /Ryujinx.Graphics/Gal/OpenGL
parent7acd0e01226d64d05b2675f6ae07507039a31835 (diff)
Merge shader branch, adding support for GLSL decompilation, a macro
interpreter, and a rewrite of the GPU code.
Diffstat (limited to 'Ryujinx.Graphics/Gal/OpenGL')
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs2
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLBlend.cs49
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs129
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs182
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs231
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs253
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs96
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs321
8 files changed, 1066 insertions, 197 deletions
diff --git a/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs
index b761811f..7e7725d6 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/FrameBuffer.cs
@@ -219,7 +219,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
PixelFormat.Rgba,
PixelType.UnsignedByte,
Pixels);
-
+
GL.ActiveTexture(TextureUnit.Texture0);
GL.BindVertexArray(VaoHandle);
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLBlend.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLBlend.cs
new file mode 100644
index 00000000..97ff8e13
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLBlend.cs
@@ -0,0 +1,49 @@
+using OpenTK.Graphics.OpenGL;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ class OGLBlend
+ {
+ public void Enable()
+ {
+ GL.Enable(EnableCap.Blend);
+ }
+
+ public void Disable()
+ {
+ GL.Disable(EnableCap.Blend);
+ }
+
+ public void Set(
+ GalBlendEquation Equation,
+ GalBlendFactor FuncSrc,
+ GalBlendFactor FuncDst)
+ {
+ GL.BlendEquation(
+ OGLEnumConverter.GetBlendEquation(Equation));
+
+ GL.BlendFunc(
+ OGLEnumConverter.GetBlendFactorSrc(FuncSrc),
+ OGLEnumConverter.GetBlendFactorDst(FuncDst));
+ }
+
+ public void SetSeparate(
+ GalBlendEquation EquationRgb,
+ GalBlendEquation EquationAlpha,
+ GalBlendFactor FuncSrcRgb,
+ GalBlendFactor FuncDstRgb,
+ GalBlendFactor FuncSrcAlpha,
+ GalBlendFactor FuncDstAlpha)
+ {
+ GL.BlendEquationSeparate(
+ OGLEnumConverter.GetBlendEquation(EquationRgb),
+ OGLEnumConverter.GetBlendEquation(EquationAlpha));
+
+ GL.BlendFuncSeparate(
+ OGLEnumConverter.GetBlendFactorSrc(FuncSrcRgb),
+ OGLEnumConverter.GetBlendFactorDst(FuncDstRgb),
+ OGLEnumConverter.GetBlendFactorSrc(FuncSrcAlpha),
+ OGLEnumConverter.GetBlendFactorDst(FuncDstAlpha));
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
new file mode 100644
index 00000000..6518de5f
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
@@ -0,0 +1,129 @@
+using OpenTK.Graphics.OpenGL;
+using System;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ static class OGLEnumConverter
+ {
+ public static DrawElementsType GetDrawElementsType(GalIndexFormat 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));
+ }
+
+ public static PrimitiveType GetPrimitiveType(GalPrimitiveType Type)
+ {
+ switch (Type)
+ {
+ case GalPrimitiveType.Points: return PrimitiveType.Points;
+ case GalPrimitiveType.Lines: return PrimitiveType.Lines;
+ case GalPrimitiveType.LineLoop: return PrimitiveType.LineLoop;
+ case GalPrimitiveType.LineStrip: return PrimitiveType.LineStrip;
+ case GalPrimitiveType.Triangles: return PrimitiveType.Triangles;
+ case GalPrimitiveType.TriangleStrip: return PrimitiveType.TriangleStrip;
+ case GalPrimitiveType.TriangleFan: return PrimitiveType.TriangleFan;
+ case GalPrimitiveType.Quads: return PrimitiveType.Quads;
+ case GalPrimitiveType.QuadStrip: return PrimitiveType.QuadStrip;
+ case GalPrimitiveType.Polygon: return PrimitiveType.Polygon;
+ case GalPrimitiveType.LinesAdjacency: return PrimitiveType.LinesAdjacency;
+ case GalPrimitiveType.LineStripAdjacency: return PrimitiveType.LineStripAdjacency;
+ case GalPrimitiveType.TrianglesAdjacency: return PrimitiveType.TrianglesAdjacency;
+ case GalPrimitiveType.TriangleStripAdjacency: return PrimitiveType.TriangleStripAdjacency;
+ case GalPrimitiveType.Patches: return PrimitiveType.Patches;
+ }
+
+ throw new ArgumentException(nameof(Type));
+ }
+
+ public static ShaderType GetShaderType(GalShaderType Type)
+ {
+ switch (Type)
+ {
+ case GalShaderType.Vertex: return ShaderType.VertexShader;
+ case GalShaderType.TessControl: return ShaderType.TessControlShader;
+ case GalShaderType.TessEvaluation: return ShaderType.TessEvaluationShader;
+ case GalShaderType.Geometry: return ShaderType.GeometryShader;
+ case GalShaderType.Fragment: return ShaderType.FragmentShader;
+ }
+
+ throw new ArgumentException(nameof(Type));
+ }
+
+ public static PixelInternalFormat GetCompressedTextureFormat(GalTextureFormat Format)
+ {
+ switch (Format)
+ {
+ case GalTextureFormat.BC1: return PixelInternalFormat.CompressedRgbaS3tcDxt1Ext;
+ case GalTextureFormat.BC2: return PixelInternalFormat.CompressedRgbaS3tcDxt3Ext;
+ case GalTextureFormat.BC3: return PixelInternalFormat.CompressedRgbaS3tcDxt5Ext;
+ }
+
+ throw new NotImplementedException(Format.ToString());
+ }
+
+ public static TextureWrapMode GetTextureWrapMode(GalTextureWrap Wrap)
+ {
+ switch (Wrap)
+ {
+ case GalTextureWrap.Repeat: return TextureWrapMode.Repeat;
+ case GalTextureWrap.MirroredRepeat: return TextureWrapMode.MirroredRepeat;
+ case GalTextureWrap.ClampToEdge: return TextureWrapMode.ClampToEdge;
+ case GalTextureWrap.ClampToBorder: return TextureWrapMode.ClampToBorder;
+ case GalTextureWrap.Clamp: return TextureWrapMode.Clamp;
+
+ //TODO: Those needs extensions (and are currently wrong).
+ case GalTextureWrap.MirrorClampToEdge: return TextureWrapMode.ClampToEdge;
+ case GalTextureWrap.MirrorClampToBorder: return TextureWrapMode.ClampToBorder;
+ case GalTextureWrap.MirrorClamp: return TextureWrapMode.Clamp;
+ }
+
+ throw new ArgumentException(nameof(Wrap));
+ }
+
+ public static TextureMinFilter GetTextureMinFilter(
+ GalTextureFilter MinFilter,
+ GalTextureMipFilter MipFilter)
+ {
+ //TODO: Mip (needs mipmap support first).
+ switch (MinFilter)
+ {
+ case GalTextureFilter.Nearest: return TextureMinFilter.Nearest;
+ case GalTextureFilter.Linear: return TextureMinFilter.Linear;
+ }
+
+ throw new ArgumentException(nameof(MinFilter));
+ }
+
+ public static TextureMagFilter GetTextureMagFilter(GalTextureFilter Filter)
+ {
+ switch (Filter)
+ {
+ case GalTextureFilter.Nearest: return TextureMagFilter.Nearest;
+ case GalTextureFilter.Linear: return TextureMagFilter.Linear;
+ }
+
+ throw new ArgumentException(nameof(Filter));
+ }
+
+ public static BlendEquationMode GetBlendEquation(GalBlendEquation BlendEquation)
+ {
+ return (BlendEquationMode)BlendEquation;
+ }
+
+ public static BlendingFactorSrc GetBlendFactorSrc(GalBlendFactor BlendFactor)
+ {
+ return (BlendingFactorSrc)(BlendFactor - 0x4000);
+ }
+
+ public static BlendingFactorDest GetBlendFactorDst(GalBlendFactor BlendFactor)
+ {
+ return (BlendingFactorDest)(BlendFactor - 0x4000);
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs
new file mode 100644
index 00000000..f9c42ae0
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs
@@ -0,0 +1,182 @@
+using OpenTK;
+using OpenTK.Graphics.OpenGL;
+using System;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ class OGLFrameBuffer
+ {
+ private struct FrameBuffer
+ {
+ public int FbHandle;
+ public int RbHandle;
+ public int TexHandle;
+ }
+
+ private struct ShaderProgram
+ {
+ public int Handle;
+ public int VpHandle;
+ public int FpHandle;
+ }
+
+ private FrameBuffer[] Fbs;
+
+ private ShaderProgram Shader;
+
+ private bool IsInitialized;
+
+ private int VaoHandle;
+ private int VboHandle;
+
+ public OGLFrameBuffer()
+ {
+ Fbs = new FrameBuffer[16];
+
+ Shader = new ShaderProgram();
+ }
+
+ public void Set(int Index, int Width, int Height)
+ {
+ if (Fbs[Index].FbHandle != 0)
+ {
+ return;
+ }
+
+ Fbs[Index].FbHandle = GL.GenFramebuffer();
+ Fbs[Index].RbHandle = GL.GenRenderbuffer();
+ Fbs[Index].TexHandle = GL.GenTexture();
+
+ GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fbs[Index].FbHandle);
+
+ GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, Fbs[Index].RbHandle);
+
+ GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Depth24Stencil8, 1280, 720);
+
+ GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthStencilAttachment, RenderbufferTarget.Renderbuffer, Fbs[Index].RbHandle);
+
+ GL.BindTexture(TextureTarget.Texture2D, Fbs[Index].TexHandle);
+
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
+
+ GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, 1280, 720, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
+
+ GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, Fbs[Index].TexHandle, 0);
+
+ GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
+ }
+
+ public void Bind(int Index)
+ {
+ if (Fbs[Index].FbHandle == 0)
+ {
+ return;
+ }
+
+ GL.BindFramebuffer(FramebufferTarget.Framebuffer, Fbs[Index].FbHandle);
+ }
+
+ public void Draw(int Index)
+ {
+ if (Fbs[Index].FbHandle == 0)
+ {
+ return;
+ }
+
+ EnsureInitialized();
+
+ GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
+
+ GL.BindTexture(TextureTarget.Texture2D, Fbs[Index].TexHandle);
+
+ GL.ActiveTexture(TextureUnit.Texture0);
+
+ GL.BindVertexArray(VaoHandle);
+
+ GL.UseProgram(Shader.Handle);
+
+ GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
+ }
+
+ private void EnsureInitialized()
+ {
+ if (!IsInitialized)
+ {
+ IsInitialized = true;
+
+ SetupShader();
+ SetupVertex();
+ }
+ }
+
+ private void SetupShader()
+ {
+ Shader.VpHandle = GL.CreateShader(ShaderType.VertexShader);
+ Shader.FpHandle = GL.CreateShader(ShaderType.FragmentShader);
+
+ string VpSource = EmbeddedResource.GetString("GlFbVtxShader");
+ string FpSource = EmbeddedResource.GetString("GlFbFragShader");
+
+ GL.ShaderSource(Shader.VpHandle, VpSource);
+ GL.ShaderSource(Shader.FpHandle, FpSource);
+ GL.CompileShader(Shader.VpHandle);
+ GL.CompileShader(Shader.FpHandle);
+
+ Shader.Handle = GL.CreateProgram();
+
+ GL.AttachShader(Shader.Handle, Shader.VpHandle);
+ GL.AttachShader(Shader.Handle, Shader.FpHandle);
+ GL.LinkProgram(Shader.Handle);
+ GL.UseProgram(Shader.Handle);
+
+ Matrix2 Transform = Matrix2.CreateScale(1, -1);
+
+ int TexUniformLocation = GL.GetUniformLocation(Shader.Handle, "tex");
+
+ GL.Uniform1(TexUniformLocation, 0);
+
+ int WindowSizeUniformLocation = GL.GetUniformLocation(Shader.Handle, "window_size");
+
+ GL.Uniform2(WindowSizeUniformLocation, new Vector2(1280.0f, 720.0f));
+
+ int TransformUniformLocation = GL.GetUniformLocation(Shader.Handle, "transform");
+
+ GL.UniformMatrix2(TransformUniformLocation, false, ref Transform);
+ }
+
+ private void SetupVertex()
+ {
+ VaoHandle = GL.GenVertexArray();
+ VboHandle = GL.GenBuffer();
+
+ float[] Buffer = new float[]
+ {
+ -1, 1, 0, 0,
+ 1, 1, 1, 0,
+ -1, -1, 0, 1,
+ 1, -1, 1, 1
+ };
+
+ IntPtr Length = new IntPtr(Buffer.Length * 4);
+
+ GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
+ GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
+ GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
+
+ GL.BindVertexArray(VaoHandle);
+
+ GL.EnableVertexAttribArray(0);
+
+ GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
+
+ GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 16, 0);
+
+ GL.EnableVertexAttribArray(1);
+
+ GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
+
+ GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 16, 8);
+ }
+ }
+} \ 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..9e0d4523
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs
@@ -0,0 +1,231 @@
+using OpenTK.Graphics.OpenGL;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ class OGLRasterizer
+ {
+ private static Dictionary<GalVertexAttribSize, int> AttribElements =
+ new Dictionary<GalVertexAttribSize, int>()
+ {
+ { GalVertexAttribSize._32_32_32_32, 4 },
+ { GalVertexAttribSize._32_32_32, 3 },
+ { GalVertexAttribSize._16_16_16_16, 4 },
+ { GalVertexAttribSize._32_32, 2 },
+ { GalVertexAttribSize._16_16_16, 3 },
+ { GalVertexAttribSize._8_8_8_8, 4 },
+ { GalVertexAttribSize._16_16, 2 },
+ { GalVertexAttribSize._32, 1 },
+ { GalVertexAttribSize._8_8_8, 3 },
+ { GalVertexAttribSize._8_8, 2 },
+ { GalVertexAttribSize._16, 1 },
+ { GalVertexAttribSize._8, 1 },
+ { GalVertexAttribSize._10_10_10_2, 4 },
+ { GalVertexAttribSize._11_11_10, 3 }
+ };
+
+ private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> AttribTypes =
+ new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
+ {
+ { GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Int },
+ { GalVertexAttribSize._32_32_32, VertexAttribPointerType.Int },
+ { GalVertexAttribSize._16_16_16_16, VertexAttribPointerType.Short },
+ { GalVertexAttribSize._32_32, VertexAttribPointerType.Int },
+ { GalVertexAttribSize._16_16_16, VertexAttribPointerType.Short },
+ { GalVertexAttribSize._8_8_8_8, VertexAttribPointerType.Byte },
+ { GalVertexAttribSize._16_16, VertexAttribPointerType.Short },
+ { GalVertexAttribSize._32, VertexAttribPointerType.Int },
+ { GalVertexAttribSize._8_8_8, VertexAttribPointerType.Byte },
+ { GalVertexAttribSize._8_8, VertexAttribPointerType.Byte },
+ { GalVertexAttribSize._16, VertexAttribPointerType.Short },
+ { GalVertexAttribSize._8, VertexAttribPointerType.Byte },
+ { GalVertexAttribSize._10_10_10_2, VertexAttribPointerType.Int }, //?
+ { GalVertexAttribSize._11_11_10, VertexAttribPointerType.Int } //?
+ };
+
+ private struct VbInfo
+ {
+ public int VaoHandle;
+ public int VboHandle;
+
+ public int PrimCount;
+ }
+
+ private struct IbInfo
+ {
+ public int IboHandle;
+ public int Count;
+
+ public DrawElementsType Type;
+ }
+
+ private VbInfo[] VertexBuffers;
+
+ private IbInfo IndexBuffer;
+
+ public OGLRasterizer()
+ {
+ VertexBuffers = new VbInfo[32];
+
+ IndexBuffer = new IbInfo();
+ }
+
+ public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags)
+ {
+ ClearBufferMask Mask = 0;
+
+ //OpenGL doesn't support clearing just a single color channel,
+ //so we can't just clear all channels...
+ if (Flags.HasFlag(GalClearBufferFlags.ColorRed) &&
+ Flags.HasFlag(GalClearBufferFlags.ColorGreen) &&
+ Flags.HasFlag(GalClearBufferFlags.ColorBlue) &&
+ Flags.HasFlag(GalClearBufferFlags.ColorAlpha))
+ {
+ Mask = ClearBufferMask.ColorBufferBit;
+ }
+
+ if (Flags.HasFlag(GalClearBufferFlags.Depth))
+ {
+ Mask |= ClearBufferMask.DepthBufferBit;
+ }
+
+ if (Flags.HasFlag(GalClearBufferFlags.Stencil))
+ {
+ Mask |= ClearBufferMask.StencilBufferBit;
+ }
+
+ GL.Clear(Mask);
+ }
+
+ public void SetVertexArray(int VbIndex, int Stride, byte[] Buffer, GalVertexAttrib[] Attribs)
+ {
+ EnsureVbInitialized(VbIndex);
+
+ VertexBuffers[VbIndex].PrimCount = Buffer.Length / Stride;
+
+ VbInfo Vb = VertexBuffers[VbIndex];
+
+ IntPtr Length = new IntPtr(Buffer.Length);
+
+ GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle);
+ GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
+ GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
+
+ GL.BindVertexArray(Vb.VaoHandle);
+
+ for (int Attr = 0; Attr < 16; Attr++)
+ {
+ GL.DisableVertexAttribArray(Attr);
+ }
+
+ for (int Index = 0; Index < Attribs.Length; Index++)
+ {
+ GalVertexAttrib Attrib = Attribs[Index];
+
+ GL.EnableVertexAttribArray(Index);
+
+ GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle);
+
+ bool Unsigned =
+ Attrib.Type == GalVertexAttribType.Unorm ||
+ Attrib.Type == GalVertexAttribType.Uint ||
+ Attrib.Type == GalVertexAttribType.Uscaled;
+
+ bool Normalize =
+ Attrib.Type == GalVertexAttribType.Snorm ||
+ Attrib.Type == GalVertexAttribType.Unorm;
+
+ VertexAttribPointerType Type = 0;
+
+ if (Attrib.Type == GalVertexAttribType.Float)
+ {
+ Type = VertexAttribPointerType.Float;
+ }
+ else
+ {
+ Type = AttribTypes[Attrib.Size] + (Unsigned ? 1 : 0);
+ }
+
+ int Size = AttribElements[Attrib.Size];
+ int Offset = Attrib.Offset;
+
+ GL.VertexAttribPointer(Index, Size, Type, Normalize, Stride, Offset);
+ }
+
+ GL.BindVertexArray(0);
+ }
+
+ public void SetIndexArray(byte[] Buffer, GalIndexFormat Format)
+ {
+ EnsureIbInitialized();
+
+ IndexBuffer.Type = OGLEnumConverter.GetDrawElementsType(Format);
+
+ IndexBuffer.Count = Buffer.Length >> (int)Format;
+
+ IntPtr Length = new IntPtr(Buffer.Length);
+
+ GL.BindBuffer(BufferTarget.ElementArrayBuffer, IndexBuffer.IboHandle);
+ GL.BufferData(BufferTarget.ElementArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
+ GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
+ }
+
+ public void DrawArrays(int VbIndex, GalPrimitiveType PrimType)
+ {
+ VbInfo Vb = VertexBuffers[VbIndex];
+
+ if (Vb.PrimCount == 0)
+ {
+ return;
+ }
+
+ GL.BindVertexArray(Vb.VaoHandle);
+
+ GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), 0, Vb.PrimCount);
+ }
+
+ public void DrawElements(int VbIndex, int First, GalPrimitiveType PrimType)
+ {
+ VbInfo Vb = VertexBuffers[VbIndex];
+
+ if (Vb.PrimCount == 0)
+ {
+ return;
+ }
+
+ PrimitiveType Mode = OGLEnumConverter.GetPrimitiveType(PrimType);
+
+ GL.BindVertexArray(Vb.VaoHandle);
+
+ GL.BindBuffer(BufferTarget.ElementArrayBuffer, IndexBuffer.IboHandle);
+
+ GL.DrawElements(Mode, IndexBuffer.Count, IndexBuffer.Type, First);
+ }
+
+ private void EnsureVbInitialized(int VbIndex)
+ {
+ VbInfo Vb = VertexBuffers[VbIndex];
+
+ if (Vb.VaoHandle == 0)
+ {
+ Vb.VaoHandle = GL.GenVertexArray();
+ }
+
+ if (Vb.VboHandle == 0)
+ {
+ Vb.VboHandle = GL.GenBuffer();
+ }
+
+ VertexBuffers[VbIndex] = Vb;
+ }
+
+ private void EnsureIbInitialized()
+ {
+ if (IndexBuffer.IboHandle == 0)
+ {
+ IndexBuffer.IboHandle = GL.GenBuffer();
+ }
+ }
+ }
+} \ 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..6d6ac555
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
@@ -0,0 +1,253 @@
+using OpenTK.Graphics.OpenGL;
+using Ryujinx.Graphics.Gal.Shader;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ class OGLShader
+ {
+ private class ShaderStage : 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> TextureUsage { get; private set; }
+ public IEnumerable<ShaderDeclInfo> UniformUsage { get; private set; }
+
+ public ShaderStage(
+ GalShaderType Type,
+ string Code,
+ IEnumerable<ShaderDeclInfo> TextureUsage,
+ IEnumerable<ShaderDeclInfo> UniformUsage)
+ {
+ this.Type = Type;
+ this.Code = Code;
+ this.TextureUsage = TextureUsage;
+ this.UniformUsage = UniformUsage;
+ }
+
+ 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;
+ }
+ }
+ }
+
+ private struct ShaderProgram
+ {
+ public ShaderStage Vertex;
+ public ShaderStage TessControl;
+ public ShaderStage TessEvaluation;
+ public ShaderStage Geometry;
+ public ShaderStage Fragment;
+ }
+
+ private ShaderProgram Current;
+
+ private ConcurrentDictionary<long, ShaderStage> Stages;
+
+ private Dictionary<ShaderProgram, int> Programs;
+
+ public int CurrentProgramHandle { get; private set; }
+
+ public OGLShader()
+ {
+ Stages = new ConcurrentDictionary<long, ShaderStage>();
+
+ Programs = new Dictionary<ShaderProgram, int>();
+ }
+
+ public void Create(long Tag, GalShaderType Type, byte[] Data)
+ {
+ Stages.GetOrAdd(Tag, (Key) => ShaderStageFactory(Type, Data));
+ }
+
+ private ShaderStage ShaderStageFactory(GalShaderType Type, byte[] Data)
+ {
+ GlslProgram Program = GetGlslProgram(Data, Type);
+
+ return new ShaderStage(
+ Type,
+ Program.Code,
+ Program.Textures,
+ Program.Uniforms);
+ }
+
+ private GlslProgram GetGlslProgram(byte[] Data, GalShaderType Type)
+ {
+ int[] Code = new int[(Data.Length - 0x50) >> 2];
+
+ using (MemoryStream MS = new MemoryStream(Data))
+ {
+ MS.Seek(0x50, SeekOrigin.Begin);
+
+ BinaryReader Reader = new BinaryReader(MS);
+
+ for (int Index = 0; Index < Code.Length; Index++)
+ {
+ Code[Index] = Reader.ReadInt32();
+ }
+ }
+
+ GlslDecompiler Decompiler = new GlslDecompiler();
+
+ return Decompiler.Decompile(Code, Type);
+ }
+
+ public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Tag)
+ {
+ if (Stages.TryGetValue(Tag, out ShaderStage Stage))
+ {
+ return Stage.TextureUsage;
+ }
+
+ return Enumerable.Empty<ShaderDeclInfo>();
+ }
+
+ public void SetConstBuffer(long Tag, int Cbuf, byte[] Data)
+ {
+ BindProgram();
+
+ if (Stages.TryGetValue(Tag, out ShaderStage Stage))
+ {
+ foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage.Where(x => x.Cbuf == Cbuf))
+ {
+ float Value = BitConverter.ToSingle(Data, DeclInfo.Index * 4);
+
+ int Location = GL.GetUniformLocation(CurrentProgramHandle, DeclInfo.Name);
+
+ GL.Uniform1(Location, Value);
+ }
+ }
+ }
+
+ public void SetUniform1(string UniformName, int Value)
+ {
+ BindProgram();
+
+ int Location = GL.GetUniformLocation(CurrentProgramHandle, UniformName);
+
+ GL.Uniform1(Location, Value);
+ }
+
+ public void Bind(long Tag)
+ {
+ if (Stages.TryGetValue(Tag, out ShaderStage Stage))
+ {
+ Bind(Stage);
+ }
+ }
+
+ private void Bind(ShaderStage Stage)
+ {
+ 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 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);
+
+ Programs.Add(Current, Handle);
+ }
+
+ GL.UseProgram(Handle);
+
+ CurrentProgramHandle = Handle;
+ }
+
+ private void AttachIfNotNull(int ProgramHandle, ShaderStage Stage)
+ {
+ if (Stage != null)
+ {
+ Stage.Compile();
+
+ GL.AttachShader(ProgramHandle, Stage.Handle);
+ }
+ }
+
+ 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));
+ }
+ }
+
+ 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/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
new file mode 100644
index 00000000..559e0eda
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
@@ -0,0 +1,96 @@
+using OpenTK.Graphics.OpenGL;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ class OGLTexture
+ {
+ private int[] Textures;
+
+ public OGLTexture()
+ {
+ Textures = new int[80];
+ }
+
+ public void Set(int Index, GalTexture Tex)
+ {
+ GL.ActiveTexture(TextureUnit.Texture0 + Index);
+
+ int Handle = EnsureTextureInitialized(Index);
+
+ GL.BindTexture(TextureTarget.Texture2D, Handle);
+
+ int W = Tex.Width;
+ int H = Tex.Height;
+
+ byte[] Data = Tex.Data;
+
+ int Length = Data.Length;
+
+ if (IsCompressedTextureFormat(Tex.Format))
+ {
+ PixelInternalFormat Pif = OGLEnumConverter.GetCompressedTextureFormat(Tex.Format);
+
+ GL.CompressedTexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Length, Data);
+ }
+ else
+ {
+ //TODO: Get those from Texture format.
+ const PixelInternalFormat Pif = PixelInternalFormat.Rgba;
+
+ const PixelFormat Pf = PixelFormat.Rgba;
+
+ const PixelType Pt = PixelType.UnsignedByte;
+
+ GL.TexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Pf, Pt, Data);
+ }
+ }
+
+ public void Set(int Index, GalTextureSampler Sampler)
+ {
+ int Handle = EnsureTextureInitialized(Index);
+
+ GL.BindTexture(TextureTarget.Texture2D, Handle);
+
+ int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU);
+ int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV);
+
+ int MinFilter = (int)OGLEnumConverter.GetTextureMinFilter(Sampler.MinFilter, Sampler.MipFilter);
+ int MagFilter = (int)OGLEnumConverter.GetTextureMagFilter(Sampler.MagFilter);
+
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, WrapS);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, WrapT);
+
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter);
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter);
+
+ float[] Color = new float[]
+ {
+ Sampler.BorderColor.Red,
+ Sampler.BorderColor.Green,
+ Sampler.BorderColor.Blue,
+ Sampler.BorderColor.Alpha
+ };
+
+ GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, Color);
+ }
+
+ private static bool IsCompressedTextureFormat(GalTextureFormat Format)
+ {
+ return Format == GalTextureFormat.BC1 ||
+ Format == GalTextureFormat.BC2 ||
+ Format == GalTextureFormat.BC3;
+ }
+
+ private int EnsureTextureInitialized(int TexIndex)
+ {
+ int Handle = Textures[TexIndex];
+
+ if (Handle == 0)
+ {
+ Handle = Textures[TexIndex] = GL.GenTexture();
+ }
+
+ return Handle;
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
index 002e54da..0b7bf92a 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
@@ -1,5 +1,4 @@
using OpenTK;
-using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -8,22 +7,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{
public class OpenGLRenderer : IGalRenderer
{
- private struct VertexBuffer
- {
- public int VaoHandle;
- public int VboHandle;
+ private OGLBlend Blend;
- public int PrimCount;
- }
+ private OGLFrameBuffer FrameBuffer;
- private struct Texture
- {
- public int Handle;
- }
+ private OGLRasterizer Rasterizer;
- private List<VertexBuffer> VertexBuffers;
+ private OGLShader Shader;
- private Texture[] Textures;
+ private OGLTexture Texture;
private ConcurrentQueue<Action> ActionsQueue;
@@ -31,9 +23,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public OpenGLRenderer()
{
- VertexBuffers = new List<VertexBuffer>();
+ Blend = new OGLBlend();
+
+ FrameBuffer = new OGLFrameBuffer();
+
+ Rasterizer = new OGLRasterizer();
+
+ Shader = new OGLShader();
- Textures = new Texture[8];
+ Texture = new OGLTexture();
ActionsQueue = new ConcurrentQueue<Action>();
}
@@ -66,18 +64,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public void Render()
{
FbRenderer.Render();
-
- for (int Index = 0; Index < VertexBuffers.Count; Index++)
- {
- VertexBuffer Vb = VertexBuffers[Index];
-
- if (Vb.VaoHandle != 0 &&
- Vb.PrimCount != 0)
- {
- GL.BindVertexArray(Vb.VaoHandle);
- GL.DrawArrays(PrimitiveType.TriangleStrip, 0, Vb.PrimCount);
- }
- }
}
public void SetWindowSize(int Width, int Height)
@@ -106,218 +92,161 @@ namespace Ryujinx.Graphics.Gal.OpenGL
FbRenderer.Set(Fb, Width, Height, Transform, Offs);
}
- public void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs)
+ public void SetBlendEnable(bool Enable)
{
- if (Index < 0)
+ if (Enable)
{
- throw new ArgumentOutOfRangeException(nameof(Index));
+ ActionsQueue.Enqueue(() => Blend.Enable());
}
-
- if (Buffer.Length == 0 || Stride == 0)
+ else
{
- return;
+ ActionsQueue.Enqueue(() => Blend.Disable());
}
+ }
- EnsureVbInitialized(Index);
-
- VertexBuffer Vb = VertexBuffers[Index];
+ public void SetBlend(
+ GalBlendEquation Equation,
+ GalBlendFactor FuncSrc,
+ GalBlendFactor FuncDst)
+ {
+ ActionsQueue.Enqueue(() => Blend.Set(Equation, FuncSrc, FuncDst));
+ }
- Vb.PrimCount = Buffer.Length / Stride;
+ public void SetBlendSeparate(
+ GalBlendEquation EquationRgb,
+ GalBlendEquation EquationAlpha,
+ GalBlendFactor FuncSrcRgb,
+ GalBlendFactor FuncDstRgb,
+ GalBlendFactor FuncSrcAlpha,
+ GalBlendFactor FuncDstAlpha)
+ {
+ ActionsQueue.Enqueue(() =>
+ {
+ Blend.SetSeparate(
+ EquationRgb,
+ EquationAlpha,
+ FuncSrcRgb,
+ FuncDstRgb,
+ FuncSrcAlpha,
+ FuncDstAlpha);
+ });
+ }
- VertexBuffers[Index] = Vb;
+ public void SetFb(int FbIndex, int Width, int Height)
+ {
+ ActionsQueue.Enqueue(() => FrameBuffer.Set(FbIndex, Width, Height));
+ }
- IntPtr Length = new IntPtr(Buffer.Length);
+ public void BindFrameBuffer(int FbIndex)
+ {
+ ActionsQueue.Enqueue(() => FrameBuffer.Bind(FbIndex));
+ }
- GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle);
- GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
- GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
+ public void DrawFrameBuffer(int FbIndex)
+ {
+ ActionsQueue.Enqueue(() => FrameBuffer.Draw(FbIndex));
+ }
- GL.BindVertexArray(Vb.VaoHandle);
+ public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags)
+ {
+ ActionsQueue.Enqueue(() => Rasterizer.ClearBuffers(RtIndex, Flags));
+ }
- for (int Attr = 0; Attr < 16; Attr++)
+ public void SetVertexArray(int VbIndex, int Stride, byte[] Buffer, GalVertexAttrib[] Attribs)
+ {
+ if ((uint)VbIndex > 31)
{
- GL.DisableVertexAttribArray(Attr);
+ throw new ArgumentOutOfRangeException(nameof(VbIndex));
}
- foreach (GalVertexAttrib Attrib in Attribs)
+ ActionsQueue.Enqueue(() => Rasterizer.SetVertexArray(VbIndex, Stride,
+ Buffer ?? throw new ArgumentNullException(nameof(Buffer)),
+ Attribs ?? throw new ArgumentNullException(nameof(Attribs))));
+ }
+
+ public void SetIndexArray(byte[] Buffer, GalIndexFormat Format)
+ {
+ if (Buffer == null)
{
- if (Attrib.Index >= 3) break;
-
- GL.EnableVertexAttribArray(Attrib.Index);
-
- GL.BindBuffer(BufferTarget.ArrayBuffer, Vb.VboHandle);
-
- int Size = 0;
-
- switch (Attrib.Size)
- {
- case GalVertexAttribSize._8:
- case GalVertexAttribSize._16:
- case GalVertexAttribSize._32:
- Size = 1;
- break;
- case GalVertexAttribSize._8_8:
- case GalVertexAttribSize._16_16:
- case GalVertexAttribSize._32_32:
- Size = 2;
- break;
- case GalVertexAttribSize._8_8_8:
- case GalVertexAttribSize._11_11_10:
- case GalVertexAttribSize._16_16_16:
- case GalVertexAttribSize._32_32_32:
- Size = 3;
- break;
- case GalVertexAttribSize._8_8_8_8:
- case GalVertexAttribSize._10_10_10_2:
- case GalVertexAttribSize._16_16_16_16:
- case GalVertexAttribSize._32_32_32_32:
- Size = 4;
- break;
- }
-
- bool Signed =
- Attrib.Type == GalVertexAttribType.Snorm ||
- Attrib.Type == GalVertexAttribType.Sint ||
- Attrib.Type == GalVertexAttribType.Sscaled;
-
- bool Normalize =
- Attrib.Type == GalVertexAttribType.Snorm ||
- Attrib.Type == GalVertexAttribType.Unorm;
-
- VertexAttribPointerType Type = 0;
-
- switch (Attrib.Type)
- {
- case GalVertexAttribType.Snorm:
- case GalVertexAttribType.Unorm:
- case GalVertexAttribType.Sint:
- case GalVertexAttribType.Uint:
- case GalVertexAttribType.Uscaled:
- case GalVertexAttribType.Sscaled:
- {
- switch (Attrib.Size)
- {
- case GalVertexAttribSize._8:
- case GalVertexAttribSize._8_8:
- case GalVertexAttribSize._8_8_8:
- case GalVertexAttribSize._8_8_8_8:
- {
- Type = Signed
- ? VertexAttribPointerType.Byte
- : VertexAttribPointerType.UnsignedByte;
-
- break;
- }
-
- case GalVertexAttribSize._16:
- case GalVertexAttribSize._16_16:
- case GalVertexAttribSize._16_16_16:
- case GalVertexAttribSize._16_16_16_16:
- {
- Type = Signed
- ? VertexAttribPointerType.Short
- : VertexAttribPointerType.UnsignedShort;
-
- break;
- }
-
- case GalVertexAttribSize._10_10_10_2:
- case GalVertexAttribSize._11_11_10:
- case GalVertexAttribSize._32:
- case GalVertexAttribSize._32_32:
- case GalVertexAttribSize._32_32_32:
- case GalVertexAttribSize._32_32_32_32:
- {
- Type = Signed
- ? VertexAttribPointerType.Int
- : VertexAttribPointerType.UnsignedInt;
-
- break;
- }
- }
-
- break;
- }
-
- case GalVertexAttribType.Float:
- {
- Type = VertexAttribPointerType.Float;
-
- break;
- }
- }
-
- GL.VertexAttribPointer(
- Attrib.Index,
- Size,
- Type,
- Normalize,
- Stride,
- Attrib.Offset);
+ throw new ArgumentNullException(nameof(Buffer));
}
- GL.BindVertexArray(0);
+ ActionsQueue.Enqueue(() => Rasterizer.SetIndexArray(Buffer, Format));
}
- public void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height)
+ public void DrawArrays(int VbIndex, GalPrimitiveType PrimType)
{
- EnsureTexInitialized(Index);
-
- GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle);
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
- GL.TexImage2D(TextureTarget.Texture2D,
- 0,
- PixelInternalFormat.Rgba,
- Width,
- Height,
- 0,
- PixelFormat.Rgba,
- PixelType.UnsignedByte,
- Buffer);
+ if ((uint)VbIndex > 31)
+ {
+ throw new ArgumentOutOfRangeException(nameof(VbIndex));
+ }
+
+ ActionsQueue.Enqueue(() => Rasterizer.DrawArrays(VbIndex, PrimType));
}
- public void BindTexture(int Index)
+ public void DrawElements(int VbIndex, int First, GalPrimitiveType PrimType)
{
- GL.ActiveTexture(TextureUnit.Texture0 + Index);
+ if ((uint)VbIndex > 31)
+ {
+ throw new ArgumentOutOfRangeException(nameof(VbIndex));
+ }
- GL.BindTexture(TextureTarget.Texture2D, Textures[Index].Handle);
+ ActionsQueue.Enqueue(() => Rasterizer.DrawElements(VbIndex, First, PrimType));
}
- private void EnsureVbInitialized(int VbIndex)
+ public void CreateShader(long Tag, GalShaderType Type, byte[] Data)
{
- while (VbIndex >= VertexBuffers.Count)
+ if (Data == null)
{
- VertexBuffers.Add(new VertexBuffer());
+ throw new ArgumentNullException(nameof(Data));
}
- VertexBuffer Vb = VertexBuffers[VbIndex];
+ Shader.Create(Tag, Type, Data);
+ }
- if (Vb.VaoHandle == 0)
+ public void SetConstBuffer(long Tag, int Cbuf, byte[] Data)
+ {
+ if (Data == null)
{
- Vb.VaoHandle = GL.GenVertexArray();
+ throw new ArgumentNullException(nameof(Data));
}
- if (Vb.VboHandle == 0)
+ ActionsQueue.Enqueue(() => Shader.SetConstBuffer(Tag, Cbuf, Data));
+ }
+
+ public void SetUniform1(string UniformName, int Value)
+ {
+ if (UniformName == null)
{
- Vb.VboHandle = GL.GenBuffer();
+ throw new ArgumentNullException(nameof(UniformName));
}
- VertexBuffers[VbIndex] = Vb;
+ ActionsQueue.Enqueue(() => Shader.SetUniform1(UniformName, Value));
}
- private void EnsureTexInitialized(int TexIndex)
+ public IEnumerable<ShaderDeclInfo> GetTextureUsage(long Tag)
{
- Texture Tex = Textures[TexIndex];
+ return Shader.GetTextureUsage(Tag);
+ }
- if (Tex.Handle == 0)
- {
- Tex.Handle = GL.GenTexture();
- }
+ public void BindShader(long Tag)
+ {
+ ActionsQueue.Enqueue(() => Shader.Bind(Tag));
+ }
- Textures[TexIndex] = Tex;
+ public void BindProgram()
+ {
+ ActionsQueue.Enqueue(() => Shader.BindProgram());
+ }
+
+ public void SetTexture(int Index, GalTexture Tex)
+ {
+ ActionsQueue.Enqueue(() => Texture.Set(Index, Tex));
+ }
+
+ public void SetSampler(int Index, GalTextureSampler Sampler)
+ {
+ ActionsQueue.Enqueue(() => Texture.Set(Index, Sampler));
}
}
} \ No newline at end of file