aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs
diff options
context:
space:
mode:
authorReinUsesLisp <reinuseslisp@airmail.cc>2018-08-10 01:09:40 -0300
committergdkchan <gab.dark.100@gmail.com>2018-08-10 01:09:40 -0300
commit25dd5f4238d898120f2f65c4d5d5b9c192ce1e10 (patch)
tree347a58054594d9236fd9c3fa1432e0ee45b99949 /Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs
parent652238f526509ed54e1c0ba2e953097ef7b2501c (diff)
Low level graphics API prerequisites (#319)
* Add GalPipelineState and IGalPipeline * Separate UploadVertex call * Add ConstBuffer cache * Move Vertex Assembly into GalPipelineState * Move Uniform binds to GalPipelineState * Move framebuffer flip into a buffer * Rebase * Fix regression * Move clear values from VertexEndGl to ClearBuffers * Rename obscure names O->Old S->New
Diffstat (limited to 'Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs')
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs379
1 files changed, 379 insertions, 0 deletions
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs
new file mode 100644
index 00000000..54f984cd
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs
@@ -0,0 +1,379 @@
+using OpenTK.Graphics.OpenGL;
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+ class OGLPipeline : IGalPipeline
+ {
+ 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 GalPipelineState Old;
+
+ private OGLConstBuffer Buffer;
+ private OGLRasterizer Rasterizer;
+ private OGLShader Shader;
+
+ private int VaoHandle;
+
+ public OGLPipeline(OGLConstBuffer Buffer, OGLRasterizer Rasterizer, OGLShader Shader)
+ {
+ this.Buffer = Buffer;
+ this.Rasterizer = Rasterizer;
+ this.Shader = Shader;
+
+ //These values match OpenGL's defaults
+ Old = new GalPipelineState
+ {
+ FrontFace = GalFrontFace.CCW,
+
+ CullFaceEnabled = false,
+ CullFace = GalCullFace.Back,
+
+ DepthTestEnabled = false,
+ DepthFunc = GalComparisonOp.Less,
+
+ StencilTestEnabled = false,
+
+ StencilBackFuncFunc = GalComparisonOp.Always,
+ StencilBackFuncRef = 0,
+ StencilBackFuncMask = UInt32.MaxValue,
+ StencilBackOpFail = GalStencilOp.Keep,
+ StencilBackOpZFail = GalStencilOp.Keep,
+ StencilBackOpZPass = GalStencilOp.Keep,
+ StencilBackMask = UInt32.MaxValue,
+
+ StencilFrontFuncFunc = GalComparisonOp.Always,
+ StencilFrontFuncRef = 0,
+ StencilFrontFuncMask = UInt32.MaxValue,
+ StencilFrontOpFail = GalStencilOp.Keep,
+ StencilFrontOpZFail = GalStencilOp.Keep,
+ StencilFrontOpZPass = GalStencilOp.Keep,
+ StencilFrontMask = UInt32.MaxValue,
+
+ BlendEnabled = false,
+ BlendSeparateAlpha = false,
+
+ BlendEquationRgb = 0,
+ BlendFuncSrcRgb = GalBlendFactor.One,
+ BlendFuncDstRgb = GalBlendFactor.Zero,
+ BlendEquationAlpha = 0,
+ BlendFuncSrcAlpha = GalBlendFactor.One,
+ BlendFuncDstAlpha = GalBlendFactor.Zero,
+
+ PrimitiveRestartEnabled = false,
+ PrimitiveRestartIndex = 0
+ };
+ }
+
+ public void Bind(GalPipelineState New)
+ {
+ BindConstBuffers(New);
+
+ BindVertexLayout(New);
+
+ if (New.FlipX != Old.FlipX || New.FlipY != Old.FlipY)
+ {
+ Shader.SetFlip(New.FlipX, New.FlipY);
+ }
+
+ //Note: Uncomment SetFrontFace and SetCullFace when flipping issues are solved
+
+ //if (New.FrontFace != O.FrontFace)
+ //{
+ // GL.FrontFace(OGLEnumConverter.GetFrontFace(New.FrontFace));
+ //}
+
+ //if (New.CullFaceEnabled != O.CullFaceEnabled)
+ //{
+ // Enable(EnableCap.CullFace, New.CullFaceEnabled);
+ //}
+
+ //if (New.CullFaceEnabled)
+ //{
+ // if (New.CullFace != O.CullFace)
+ // {
+ // GL.CullFace(OGLEnumConverter.GetCullFace(New.CullFace));
+ // }
+ //}
+
+ if (New.DepthTestEnabled != Old.DepthTestEnabled)
+ {
+ Enable(EnableCap.DepthTest, New.DepthTestEnabled);
+ }
+
+ if (New.DepthTestEnabled)
+ {
+ if (New.DepthFunc != Old.DepthFunc)
+ {
+ GL.DepthFunc(OGLEnumConverter.GetDepthFunc(New.DepthFunc));
+ }
+ }
+
+ if (New.StencilTestEnabled != Old.StencilTestEnabled)
+ {
+ Enable(EnableCap.StencilTest, New.StencilTestEnabled);
+ }
+
+ if (New.StencilTestEnabled)
+ {
+ if (New.StencilBackFuncFunc != Old.StencilBackFuncFunc ||
+ New.StencilBackFuncRef != Old.StencilBackFuncRef ||
+ New.StencilBackFuncMask != Old.StencilBackFuncMask)
+ {
+ GL.StencilFuncSeparate(
+ StencilFace.Back,
+ OGLEnumConverter.GetStencilFunc(New.StencilBackFuncFunc),
+ New.StencilBackFuncRef,
+ New.StencilBackFuncMask);
+ }
+
+ 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));
+ }
+
+ if (New.StencilBackMask != Old.StencilBackMask)
+ {
+ GL.StencilMaskSeparate(StencilFace.Back, New.StencilBackMask);
+ }
+
+ if (New.StencilFrontFuncFunc != Old.StencilFrontFuncFunc ||
+ New.StencilFrontFuncRef != Old.StencilFrontFuncRef ||
+ New.StencilFrontFuncMask != Old.StencilFrontFuncMask)
+ {
+ GL.StencilFuncSeparate(
+ StencilFace.Front,
+ OGLEnumConverter.GetStencilFunc(New.StencilFrontFuncFunc),
+ New.StencilFrontFuncRef,
+ New.StencilFrontFuncMask);
+ }
+
+ 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));
+ }
+
+ if (New.StencilFrontMask != Old.StencilFrontMask)
+ {
+ GL.StencilMaskSeparate(StencilFace.Front, New.StencilFrontMask);
+ }
+ }
+
+ if (New.BlendEnabled != Old.BlendEnabled)
+ {
+ Enable(EnableCap.Blend, New.BlendEnabled);
+ }
+
+ if (New.BlendEnabled)
+ {
+ if (New.BlendSeparateAlpha)
+ {
+ if (New.BlendEquationRgb != Old.BlendEquationRgb ||
+ New.BlendEquationAlpha != Old.BlendEquationAlpha)
+ {
+ GL.BlendEquationSeparate(
+ OGLEnumConverter.GetBlendEquation(New.BlendEquationRgb),
+ OGLEnumConverter.GetBlendEquation(New.BlendEquationAlpha));
+ }
+
+ if (New.BlendFuncSrcRgb != Old.BlendFuncSrcRgb ||
+ New.BlendFuncDstRgb != Old.BlendFuncDstRgb ||
+ New.BlendFuncSrcAlpha != Old.BlendFuncSrcAlpha ||
+ New.BlendFuncDstAlpha != Old.BlendFuncDstAlpha)
+ {
+ GL.BlendFuncSeparate(
+ (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.BlendFuncSrcRgb),
+ (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.BlendFuncDstRgb),
+ (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.BlendFuncSrcAlpha),
+ (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.BlendFuncDstAlpha));
+ }
+ }
+ else
+ {
+ if (New.BlendEquationRgb != Old.BlendEquationRgb)
+ {
+ GL.BlendEquation(OGLEnumConverter.GetBlendEquation(New.BlendEquationRgb));
+ }
+
+ if (New.BlendFuncSrcRgb != Old.BlendFuncSrcRgb ||
+ New.BlendFuncDstRgb != Old.BlendFuncDstRgb)
+ {
+ GL.BlendFunc(
+ OGLEnumConverter.GetBlendFactor(New.BlendFuncSrcRgb),
+ OGLEnumConverter.GetBlendFactor(New.BlendFuncDstRgb));
+ }
+ }
+ }
+
+ if (New.PrimitiveRestartEnabled != Old.PrimitiveRestartEnabled)
+ {
+ Enable(EnableCap.PrimitiveRestart, New.PrimitiveRestartEnabled);
+ }
+
+ if (New.PrimitiveRestartEnabled)
+ {
+ if (New.PrimitiveRestartIndex != Old.PrimitiveRestartIndex)
+ {
+ GL.PrimitiveRestartIndex(New.PrimitiveRestartIndex);
+ }
+ }
+
+ Old = New;
+ }
+
+ private void BindConstBuffers(GalPipelineState New)
+ {
+ //Index 0 is reserved
+ int FreeBinding = 1;
+
+ void BindIfNotNull(OGLShaderStage Stage)
+ {
+ if (Stage != null)
+ {
+ foreach (ShaderDeclInfo DeclInfo in Stage.UniformUsage)
+ {
+ long Key = New.ConstBufferKeys[(int)Stage.Type][DeclInfo.Cbuf];
+
+ if (Key != 0 && Buffer.TryGetUbo(Key, out int UboHandle))
+ {
+ GL.BindBufferBase(BufferRangeTarget.UniformBuffer, FreeBinding, UboHandle);
+ }
+
+ FreeBinding++;
+ }
+ }
+ }
+
+ 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)
+ {
+ if (!Binding.Enabled || !Rasterizer.TryGetVbo(Binding.VboKey, out int VboHandle))
+ {
+ continue;
+ }
+
+ if (VaoHandle == 0)
+ {
+ 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);
+ }
+
+ foreach (GalVertexAttrib Attrib in Binding.Attribs)
+ {
+ GL.EnableVertexAttribArray(Attrib.Index);
+
+ GL.BindBuffer(BufferTarget.ArrayBuffer, 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;
+
+ if (Attrib.Type == GalVertexAttribType.Sint ||
+ Attrib.Type == GalVertexAttribType.Uint)
+ {
+ IntPtr Pointer = new IntPtr(Offset);
+
+ VertexAttribIntegerType IType = (VertexAttribIntegerType)Type;
+
+ GL.VertexAttribIPointer(Attrib.Index, Size, IType, Binding.Stride, Pointer);
+ }
+ else
+ {
+ GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Binding.Stride, Offset);
+ }
+ }
+ }
+ }
+
+ private void Enable(EnableCap Cap, bool Enabled)
+ {
+ if (Enabled)
+ {
+ GL.Enable(Cap);
+ }
+ else
+ {
+ GL.Disable(Cap);
+ }
+ }
+ }
+} \ No newline at end of file