diff --git a/Ryujinx.Graphics/Gal/GalPipelineState.cs b/Ryujinx.Graphics/Gal/GalPipelineState.cs deleted file mode 100644 index 8630da9cc4..0000000000 --- a/Ryujinx.Graphics/Gal/GalPipelineState.cs +++ /dev/null @@ -1,117 +0,0 @@ -namespace Ryujinx.Graphics.Gal -{ - public struct ColorMaskState - { - private static readonly ColorMaskState _Default = new ColorMaskState() - { - Red = true, - Green = true, - Blue = true, - Alpha = true - }; - - public static ColorMaskState Default => _Default; - - public bool Red; - public bool Green; - public bool Blue; - public bool Alpha; - } - - public struct BlendState - { - private static readonly BlendState _Default = new BlendState() - { - Enabled = false, - SeparateAlpha = false, - EquationRgb = GalBlendEquation.FuncAdd, - FuncSrcRgb = GalBlendFactor.One, - FuncDstRgb = GalBlendFactor.Zero, - EquationAlpha = GalBlendEquation.FuncAdd, - FuncSrcAlpha = GalBlendFactor.One, - FuncDstAlpha = GalBlendFactor.Zero - }; - - public static BlendState Default => _Default; - - public bool Enabled; - public bool SeparateAlpha; - public GalBlendEquation EquationRgb; - public GalBlendFactor FuncSrcRgb; - public GalBlendFactor FuncDstRgb; - public GalBlendEquation EquationAlpha; - public GalBlendFactor FuncSrcAlpha; - public GalBlendFactor FuncDstAlpha; - } - - public class GalPipelineState - { - public const int Stages = 5; - public const int ConstBuffersPerStage = 18; - public const int RenderTargetsCount = 8; - - public long[][] ConstBufferKeys; - - public GalVertexBinding[] VertexBindings; - - public bool FramebufferSrgb; - - public float FlipX; - public float FlipY; - - public int Instance; - - public GalFrontFace FrontFace; - - public bool CullFaceEnabled; - public GalCullFace CullFace; - - public bool DepthTestEnabled; - public bool DepthWriteEnabled; - public GalComparisonOp DepthFunc; - public float DepthRangeNear; - public float DepthRangeFar; - - public bool StencilTestEnabled; - public bool StencilTwoSideEnabled; - - public GalComparisonOp StencilBackFuncFunc; - public int StencilBackFuncRef; - public uint StencilBackFuncMask; - public GalStencilOp StencilBackOpFail; - public GalStencilOp StencilBackOpZFail; - public GalStencilOp StencilBackOpZPass; - public uint StencilBackMask; - - public GalComparisonOp StencilFrontFuncFunc; - public int StencilFrontFuncRef; - public uint StencilFrontFuncMask; - public GalStencilOp StencilFrontOpFail; - public GalStencilOp StencilFrontOpZFail; - public GalStencilOp StencilFrontOpZPass; - public uint StencilFrontMask; - - public bool BlendIndependent; - public BlendState[] Blends; - - public bool ColorMaskCommon; - public ColorMaskState[] ColorMasks; - - public bool PrimitiveRestartEnabled; - public uint PrimitiveRestartIndex; - - public GalPipelineState() - { - ConstBufferKeys = new long[Stages][]; - - for (int Stage = 0; Stage < Stages; Stage++) - { - ConstBufferKeys[Stage] = new long[ConstBuffersPerStage]; - } - - Blends = new BlendState[RenderTargetsCount]; - - ColorMasks = new ColorMaskState[RenderTargetsCount]; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalPipeline.cs b/Ryujinx.Graphics/Gal/IGalPipeline.cs index cba4e7dcc6..2feec78bec 100644 --- a/Ryujinx.Graphics/Gal/IGalPipeline.cs +++ b/Ryujinx.Graphics/Gal/IGalPipeline.cs @@ -2,9 +2,83 @@ { public interface IGalPipeline { - void Bind(GalPipelineState State); + void SetFlip(float FlipX, float FlipY, int Instance); - void ResetDepthMask(); - void ResetColorMask(int Index); + //Depth. + void SetDepthMask(bool DepthTestEnabled, bool DepthWriteEnabled); + + void SetDepthFunc(GalComparisonOp DepthFunc); + + void SetDepthRange(float DepthRangeNear, float DepthRangeFar); + + //Stencil. + void SetStencilTestEnabled(bool Enabled); + + void SetStencilTest( + GalComparisonOp StencilBackFuncFunc, + int StencilBackFuncRef, + uint StencilBackFuncMask, + GalStencilOp StencilBackOpFail, + GalStencilOp StencilBackOpZFail, + GalStencilOp StencilBackOpZPass, + uint StencilBackMask, + GalComparisonOp StencilFrontFuncFunc, + int StencilFrontFuncRef, + uint StencilFrontFuncMask, + GalStencilOp StencilFrontOpFail, + GalStencilOp StencilFrontOpZFail, + GalStencilOp StencilFrontOpZPass, + uint StencilFrontMask); + + //Blend. + void SetBlendEnabled(bool Enabled); + + void SetBlendEnabled(int Index, bool Enabled); + + void SetBlend( + GalBlendEquation EquationRgb, + GalBlendFactor FuncSrcRgb, + GalBlendFactor FuncDstRgb); + + void SetBlend( + int Index, + GalBlendEquation EquationRgb, + GalBlendFactor FuncSrcRgb, + GalBlendFactor FuncDstRgb); + + void SetBlendSeparate( + GalBlendEquation EquationRgb, + GalBlendFactor FuncSrcRgb, + GalBlendFactor FuncDstRgb, + GalBlendEquation EquationAlpha, + GalBlendFactor FuncSrcAlpha, + GalBlendFactor FuncDstAlpha); + + void SetBlendSeparate( + int Index, + GalBlendEquation EquationRgb, + GalBlendFactor FuncSrcRgb, + GalBlendFactor FuncDstRgb, + GalBlendEquation EquationAlpha, + GalBlendFactor FuncSrcAlpha, + GalBlendFactor FuncDstAlpha); + + //Color mask. + void SetColorMask(bool RedMask, bool GreenMask, bool BlueMask, bool AlphaMask); + + void SetColorMask( + int Index, + bool RedMask, + bool GreenMask, + bool BlueMask, + bool AlphaMask); + + //Primitive restart. + void SetPrimitiveRestartEnabled(bool Enabled); + void SetPrimitiveRestartIndex(int Index); + + void SetFramebufferSrgb(bool Enabled); + + void BindConstBuffers(long[][] ConstBufferKeys); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs index f941ccd584..626a415516 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs @@ -2,6 +2,8 @@ namespace Ryujinx.Graphics.Gal { public interface IGalRenderTarget { + bool FramebufferSrgb { get; set; } + void Bind(); void BindColor(long Key, int Attachment); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs index eb7f958b92..7dce2d2cc5 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs @@ -1,468 +1,211 @@ using OpenTK.Graphics.OpenGL; -using System; -using System.Collections.Generic; namespace Ryujinx.Graphics.Gal.OpenGL { class OGLPipeline : IGalPipeline { - private static Dictionary AttribElements = - new Dictionary() + private OGLConstBuffer Buffer; + private OGLShader Shader; + + private float FlipX; + private float FlipY; + private int Instance; + + public OGLPipeline(OGLConstBuffer Buffer, OGLShader Shader) { - { 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 } - }; + this.Buffer = Buffer; + this.Shader = Shader; + } - private static Dictionary FloatAttribTypes = - new Dictionary() + public void SetFlip(float FlipX, float FlipY, int Instance) { - { GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Float }, - { GalVertexAttribSize._32_32_32, VertexAttribPointerType.Float }, - { GalVertexAttribSize._16_16_16_16, VertexAttribPointerType.HalfFloat }, - { GalVertexAttribSize._32_32, VertexAttribPointerType.Float }, - { GalVertexAttribSize._16_16_16, VertexAttribPointerType.HalfFloat }, - { GalVertexAttribSize._16_16, VertexAttribPointerType.HalfFloat }, - { GalVertexAttribSize._32, VertexAttribPointerType.Float }, - { GalVertexAttribSize._16, VertexAttribPointerType.HalfFloat } - }; - - private static Dictionary SignedAttribTypes = - new Dictionary() - { - { 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.Int2101010Rev } - }; - - private static Dictionary UnsignedAttribTypes = - new Dictionary() - { - { GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.UnsignedInt }, - { GalVertexAttribSize._32_32_32, VertexAttribPointerType.UnsignedInt }, - { GalVertexAttribSize._16_16_16_16, VertexAttribPointerType.UnsignedShort }, - { GalVertexAttribSize._32_32, VertexAttribPointerType.UnsignedInt }, - { GalVertexAttribSize._16_16_16, VertexAttribPointerType.UnsignedShort }, - { GalVertexAttribSize._8_8_8_8, VertexAttribPointerType.UnsignedByte }, - { GalVertexAttribSize._16_16, VertexAttribPointerType.UnsignedShort }, - { GalVertexAttribSize._32, VertexAttribPointerType.UnsignedInt }, - { GalVertexAttribSize._8_8_8, VertexAttribPointerType.UnsignedByte }, - { GalVertexAttribSize._8_8, VertexAttribPointerType.UnsignedByte }, - { GalVertexAttribSize._16, VertexAttribPointerType.UnsignedShort }, - { GalVertexAttribSize._8, VertexAttribPointerType.UnsignedByte }, - { GalVertexAttribSize._10_10_10_2, VertexAttribPointerType.UnsignedInt2101010Rev }, - { GalVertexAttribSize._11_11_10, VertexAttribPointerType.UnsignedInt10F11F11FRev } - }; - - private GalPipelineState Old; - - private OGLConstBuffer Buffer; - private OGLRenderTarget RenderTarget; - private OGLRasterizer Rasterizer; - private OGLShader Shader; - - private int VaoHandle; - - public OGLPipeline( - OGLConstBuffer Buffer, - OGLRenderTarget RenderTarget, - OGLRasterizer Rasterizer, - OGLShader Shader) - { - this.Buffer = Buffer; - this.RenderTarget = RenderTarget; - this.Rasterizer = Rasterizer; - this.Shader = Shader; - - //These values match OpenGL's defaults - Old = new GalPipelineState + if (FlipX != this.FlipX || + FlipY != this.FlipY || + Instance != this.Instance) { - FrontFace = GalFrontFace.CCW, + this.FlipX = FlipX; + this.FlipY = FlipY; + this.Instance = Instance; - CullFaceEnabled = false, - CullFace = GalCullFace.Back, - - DepthTestEnabled = false, - DepthWriteEnabled = true, - DepthFunc = GalComparisonOp.Less, - DepthRangeNear = 0, - DepthRangeFar = 1, - - 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, - - BlendIndependent = false, - - PrimitiveRestartEnabled = false, - PrimitiveRestartIndex = 0 - }; - - for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) - { - Old.Blends[Index] = BlendState.Default; - - Old.ColorMasks[Index] = ColorMaskState.Default; + Shader.SetExtraData(FlipX, FlipY, Instance); } } - public void Bind(GalPipelineState New) + public void SetDepthMask(bool DepthTestEnabled, bool DepthWriteEnabled) { - BindConstBuffers(New); + Enable(EnableCap.DepthTest, DepthTestEnabled); - BindVertexLayout(New); - - if (New.FramebufferSrgb != Old.FramebufferSrgb) - { - Enable(EnableCap.FramebufferSrgb, New.FramebufferSrgb); - - RenderTarget.FramebufferSrgb = New.FramebufferSrgb; - } - - if (New.FlipX != Old.FlipX || New.FlipY != Old.FlipY || New.Instance != Old.Instance) - { - Shader.SetExtraData(New.FlipX, New.FlipY, New.Instance); - } - - //Note: Uncomment SetFrontFace and SetCullFace when flipping issues are solved - - //if (New.FrontFace != Old.FrontFace) - //{ - // GL.FrontFace(OGLEnumConverter.GetFrontFace(New.FrontFace)); - //} - - //if (New.CullFaceEnabled != Old.CullFaceEnabled) - //{ - // Enable(EnableCap.CullFace, New.CullFaceEnabled); - //} - - //if (New.CullFaceEnabled) - //{ - // if (New.CullFace != Old.CullFace) - // { - // GL.CullFace(OGLEnumConverter.GetCullFace(New.CullFace)); - // } - //} - - if (New.DepthTestEnabled != Old.DepthTestEnabled) - { - Enable(EnableCap.DepthTest, New.DepthTestEnabled); - } - - if (New.DepthWriteEnabled != Old.DepthWriteEnabled) - { - GL.DepthMask(New.DepthWriteEnabled); - } - - if (New.DepthTestEnabled) - { - if (New.DepthFunc != Old.DepthFunc) - { - GL.DepthFunc(OGLEnumConverter.GetDepthFunc(New.DepthFunc)); - } - } - - if (New.DepthRangeNear != Old.DepthRangeNear || - New.DepthRangeFar != Old.DepthRangeFar) - { - GL.DepthRange(New.DepthRangeNear, New.DepthRangeFar); - } - - if (New.StencilTestEnabled != Old.StencilTestEnabled) - { - Enable(EnableCap.StencilTest, New.StencilTestEnabled); - } - - 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) - { - 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.BlendIndependent) - { - for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) - { - SetBlendState(Index, New.Blends[Index], Old.Blends[Index]); - } - } - else - { - if (New.BlendIndependent != Old.BlendIndependent) - { - SetAllBlendState(New.Blends[0]); - } - else - { - SetBlendState(New.Blends[0], Old.Blends[0]); - } - } - - if (New.ColorMaskCommon) - { - if (New.ColorMaskCommon != Old.ColorMaskCommon || !New.ColorMasks[0].Equals(Old.ColorMasks[0])) - { - GL.ColorMask( - New.ColorMasks[0].Red, - New.ColorMasks[0].Green, - New.ColorMasks[0].Blue, - New.ColorMasks[0].Alpha); - } - } - else - { - for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; 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); - } - } - } - - if (New.PrimitiveRestartEnabled != Old.PrimitiveRestartEnabled) - { - Enable(EnableCap.PrimitiveRestart, New.PrimitiveRestartEnabled); - } - - if (New.PrimitiveRestartEnabled) - { - if (New.PrimitiveRestartIndex != Old.PrimitiveRestartIndex) - { - GL.PrimitiveRestartIndex(New.PrimitiveRestartIndex); - } - } - - Old = New; + GL.DepthMask(DepthWriteEnabled); } - private void SetAllBlendState(BlendState New) + public void SetDepthFunc(GalComparisonOp DepthFunc) { - Enable(EnableCap.Blend, New.Enabled); - - if (New.Enabled) - { - if (New.SeparateAlpha) - { - GL.BlendEquationSeparate( - 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)); - } - else - { - GL.BlendEquation(OGLEnumConverter.GetBlendEquation(New.EquationRgb)); - - GL.BlendFunc( - OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb), - OGLEnumConverter.GetBlendFactor(New.FuncDstRgb)); - } - } + GL.DepthFunc(OGLEnumConverter.GetDepthFunc(DepthFunc)); } - private void SetBlendState(BlendState New, BlendState Old) + public void SetDepthRange(float DepthRangeNear, float DepthRangeFar) { - if (New.Enabled != Old.Enabled) - { - Enable(EnableCap.Blend, New.Enabled); - } - - if (New.Enabled) - { - if (New.SeparateAlpha) - { - if (New.EquationRgb != Old.EquationRgb || - New.EquationAlpha != Old.EquationAlpha) - { - GL.BlendEquationSeparate( - 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) - { - GL.BlendFuncSeparate( - (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) - { - GL.BlendEquation(OGLEnumConverter.GetBlendEquation(New.EquationRgb)); - } - - if (New.FuncSrcRgb != Old.FuncSrcRgb || - New.FuncDstRgb != Old.FuncDstRgb) - { - GL.BlendFunc( - OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb), - OGLEnumConverter.GetBlendFactor(New.FuncDstRgb)); - } - } - } + GL.DepthRange(DepthRangeNear, DepthRangeFar); } - private void SetBlendState(int Index, BlendState New, BlendState Old) + public void SetStencilTestEnabled(bool Enabled) { - if (New.Enabled != Old.Enabled) - { - Enable(IndexedEnableCap.Blend, Index, New.Enabled); - } - - if (New.Enabled) - { - if (New.SeparateAlpha) - { - if (New.EquationRgb != Old.EquationRgb || - New.EquationAlpha != Old.EquationAlpha) - { - GL.BlendEquationSeparate( - 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) - { - GL.BlendFuncSeparate( - 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) - { - GL.BlendEquation(Index, OGLEnumConverter.GetBlendEquation(New.EquationRgb)); - } - - if (New.FuncSrcRgb != Old.FuncSrcRgb || - New.FuncDstRgb != Old.FuncDstRgb) - { - GL.BlendFunc( - Index, - (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb), - (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb)); - } - } - } + Enable(EnableCap.StencilTest, Enabled); } - private void BindConstBuffers(GalPipelineState New) + public void SetStencilTest( + GalComparisonOp StencilBackFuncFunc, + int StencilBackFuncRef, + uint StencilBackFuncMask, + GalStencilOp StencilBackOpFail, + GalStencilOp StencilBackOpZFail, + GalStencilOp StencilBackOpZPass, + uint StencilBackMask, + GalComparisonOp StencilFrontFuncFunc, + int StencilFrontFuncRef, + uint StencilFrontFuncMask, + GalStencilOp StencilFrontOpFail, + GalStencilOp StencilFrontOpZFail, + GalStencilOp StencilFrontOpZPass, + uint StencilFrontMask) + { + GL.StencilFuncSeparate( + StencilFace.Back, + OGLEnumConverter.GetStencilFunc(StencilBackFuncFunc), + StencilBackFuncRef, + StencilBackFuncMask); + + GL.StencilOpSeparate( + StencilFace.Back, + OGLEnumConverter.GetStencilOp(StencilBackOpFail), + OGLEnumConverter.GetStencilOp(StencilBackOpZFail), + OGLEnumConverter.GetStencilOp(StencilBackOpZPass)); + + GL.StencilMaskSeparate(StencilFace.Back, StencilBackMask); + + GL.StencilFuncSeparate( + StencilFace.Front, + OGLEnumConverter.GetStencilFunc(StencilFrontFuncFunc), + StencilFrontFuncRef, + StencilFrontFuncMask); + + GL.StencilOpSeparate( + StencilFace.Front, + OGLEnumConverter.GetStencilOp(StencilFrontOpFail), + OGLEnumConverter.GetStencilOp(StencilFrontOpZFail), + OGLEnumConverter.GetStencilOp(StencilFrontOpZPass)); + + GL.StencilMaskSeparate(StencilFace.Front, StencilFrontMask); + } + + public void SetBlendEnabled(bool Enabled) + { + Enable(EnableCap.Blend, Enabled); + } + + public void SetBlendEnabled(int Index, bool Enabled) + { + Enable(IndexedEnableCap.Blend, Index, Enabled); + } + + public void SetBlend( + GalBlendEquation EquationRgb, + GalBlendFactor FuncSrcRgb, + GalBlendFactor FuncDstRgb) + { + GL.BlendEquation(OGLEnumConverter.GetBlendEquation(EquationRgb)); + + GL.BlendFunc( + OGLEnumConverter.GetBlendFactor(FuncSrcRgb), + OGLEnumConverter.GetBlendFactor(FuncDstRgb)); + } + + public void SetBlend( + int Index, + GalBlendEquation EquationRgb, + GalBlendFactor FuncSrcRgb, + GalBlendFactor FuncDstRgb) + { + GL.BlendEquation(Index, OGLEnumConverter.GetBlendEquation(EquationRgb)); + + GL.BlendFunc( + Index, + (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(FuncSrcRgb), + (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(FuncDstRgb)); + } + + public void SetBlendSeparate( + GalBlendEquation EquationRgb, + GalBlendFactor FuncSrcRgb, + GalBlendFactor FuncDstRgb, + GalBlendEquation EquationAlpha, + GalBlendFactor FuncSrcAlpha, + GalBlendFactor FuncDstAlpha) + { + GL.BlendEquationSeparate( + OGLEnumConverter.GetBlendEquation(EquationRgb), + OGLEnumConverter.GetBlendEquation(EquationAlpha)); + + GL.BlendFuncSeparate( + (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(FuncSrcRgb), + (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(FuncDstRgb), + (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(FuncSrcAlpha), + (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(FuncDstAlpha)); + } + + public void SetBlendSeparate( + int Index, + GalBlendEquation EquationRgb, + GalBlendFactor FuncSrcRgb, + GalBlendFactor FuncDstRgb, + GalBlendEquation EquationAlpha, + GalBlendFactor FuncSrcAlpha, + GalBlendFactor FuncDstAlpha) + { + GL.BlendEquationSeparate( + Index, + OGLEnumConverter.GetBlendEquation(EquationRgb), + OGLEnumConverter.GetBlendEquation(EquationAlpha)); + + GL.BlendFuncSeparate( + Index, + (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(FuncSrcRgb), + (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(FuncDstRgb), + (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(FuncSrcAlpha), + (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(FuncDstAlpha)); + } + + public void SetColorMask(bool RedMask, bool GreenMask, bool BlueMask, bool AlphaMask) + { + GL.ColorMask(RedMask, GreenMask, BlueMask, AlphaMask); + } + + public void SetColorMask( + int Index, + bool RedMask, + bool GreenMask, + bool BlueMask, + bool AlphaMask) + { + GL.ColorMask(Index, RedMask, GreenMask, BlueMask, AlphaMask); + } + + public void SetPrimitiveRestartEnabled(bool Enabled) + { + Enable(EnableCap.PrimitiveRestart, Enabled); + } + + public void SetPrimitiveRestartIndex(int Index) + { + GL.PrimitiveRestartIndex(Index); + } + + public void SetFramebufferSrgb(bool Enabled) + { + Enable(EnableCap.FramebufferSrgb, Enabled); + } + + public void BindConstBuffers(long[][] ConstBufferKeys) { int FreeBinding = OGLShader.ReservedCbufCount; @@ -472,7 +215,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL { foreach (ShaderDeclInfo DeclInfo in Stage.ConstBufferUsage) { - long Key = New.ConstBufferKeys[(int)Stage.Type][DeclInfo.Cbuf]; + long Key = ConstBufferKeys[(int)Stage.Type][DeclInfo.Cbuf]; if (Key != 0 && Buffer.TryGetUbo(Key, out int UboHandle)) { @@ -491,251 +234,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL 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) - { - //Skip uninitialized attributes. - if (Attrib.Size == 0) - { - continue; - } - - 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 = GetType(FloatAttribTypes, Attrib); - } - else - { - if (Unsigned) - { - Type = GetType(UnsignedAttribTypes, Attrib); - } - else - { - Type = GetType(SignedAttribTypes, Attrib); - } - } - - if (!AttribElements.TryGetValue(Attrib.Size, out int Size)) - { - throw new InvalidOperationException("Invalid attribute size \"" + Attrib.Size + "\"!"); - } - - int Offset = Attrib.Offset; - - if (Binding.Stride != 0) - { - GL.EnableVertexAttribArray(Attrib.Index); - - 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); - } - } - else - { - GL.DisableVertexAttribArray(Attrib.Index); - - SetConstAttrib(Attrib); - } - - if (Binding.Instanced && Binding.Divisor != 0) - { - GL.VertexAttribDivisor(Attrib.Index, 1); - } - else - { - GL.VertexAttribDivisor(Attrib.Index, 0); - } - } - } - } - - private static VertexAttribPointerType GetType(Dictionary Dict, GalVertexAttrib Attrib) - { - if (!Dict.TryGetValue(Attrib.Size, out VertexAttribPointerType Type)) - { - ThrowUnsupportedAttrib(Attrib); - } - - return Type; - } - - private unsafe static void SetConstAttrib(GalVertexAttrib Attrib) - { - if (Attrib.Size == GalVertexAttribSize._10_10_10_2 || - Attrib.Size == GalVertexAttribSize._11_11_10) - { - ThrowUnsupportedAttrib(Attrib); - } - - fixed (byte* Ptr = Attrib.Data) - { - if (Attrib.Type == GalVertexAttribType.Unorm) - { - 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); - 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); - 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); - break; - } - } - else if (Attrib.Type == GalVertexAttribType.Snorm) - { - 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); - 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); - 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); - break; - } - } - else if (Attrib.Type == GalVertexAttribType.Uint) - { - 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); - 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); - 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); - break; - } - } - else if (Attrib.Type == GalVertexAttribType.Sint) - { - 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); - 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); - 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); - break; - } - } - else if (Attrib.Type == GalVertexAttribType.Float) - { - 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); - break; - - default: ThrowUnsupportedAttrib(Attrib); break; - } - } - } - } - - private static void ThrowUnsupportedAttrib(GalVertexAttrib Attrib) - { - throw new NotImplementedException("Unsupported size \"" + Attrib.Size + "\" on type \"" + Attrib.Type + "\"!"); - } - private void Enable(EnableCap Cap, bool Enabled) { if (Enabled) @@ -759,15 +257,5 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.Disable(Cap, Index); } } - - public void ResetDepthMask() - { - Old.DepthWriteEnabled = true; - } - - public void ResetColorMask(int Index) - { - Old.ColorMasks[Index] = ColorMaskState.Default; - } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs index ce5364e154..f5968e3ecd 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs @@ -9,7 +9,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL private const int NativeWidth = 1280; private const int NativeHeight = 720; - private const int RenderTargetsCount = GalPipelineState.RenderTargetsCount; + private const int RenderTargetsCount = 8; private struct Rect { diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs index 14fb901809..dd792ba8e6 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs @@ -31,11 +31,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL Shader = new OGLShader(Buffer as OGLConstBuffer); - Pipeline = new OGLPipeline( - Buffer as OGLConstBuffer, - RenderTarget as OGLRenderTarget, - Rasterizer as OGLRasterizer, - Shader as OGLShader); + Pipeline = new OGLPipeline(Buffer as OGLConstBuffer, Shader as OGLShader); ActionsQueue = new ConcurrentQueue(); } diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs index 6fb038acb6..b90e7869bb 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs @@ -9,6 +9,8 @@ namespace Ryujinx.Graphics.Graphics3d { class NvGpuEngine3d : INvGpuEngine { + private const int RenderTargetsCount = 8; + public int[] Registers { get; private set; } private NvGpu Gpu; @@ -24,6 +26,18 @@ namespace Ryujinx.Graphics.Graphics3d private ConstBuffer[][] ConstBuffers; + [Flags] + private enum PipelineState + { + Depth = 1 << 0, + Stencil = 1 << 1, + Blend = 1 << 2, + ColorMask = 1 << 3, + PrimRestart = 1 << 4 + } + + private PipelineState DirtyState; + private int CurrentInstance = 0; public NvGpuEngine3d(NvGpu Gpu) @@ -61,9 +75,9 @@ namespace Ryujinx.Graphics.Graphics3d //FIXME: Is this correct? WriteRegister(NvGpuEngine3dReg.ColorMaskN, 0x1111); - WriteRegister(NvGpuEngine3dReg.FrameBufferSrgb, 1); + Gpu.Renderer.RenderTarget.FramebufferSrgb = true; - for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) + for (int Index = 0; Index < RenderTargetsCount; Index++) { WriteRegister(NvGpuEngine3dReg.IBlendNEquationRgb + Index * 8, (int)GalBlendEquation.FuncAdd); WriteRegister(NvGpuEngine3dReg.IBlendNFuncSrcRgb + Index * 8, (int)GalBlendFactor.One); @@ -90,16 +104,40 @@ namespace Ryujinx.Graphics.Graphics3d { LockCaches(); - GalPipelineState State = new GalPipelineState(); + if ((DirtyState & PipelineState.Depth) == 0) + { + DirtyState |= PipelineState.Depth; - SetFrameBuffer(State); - SetFrontFace(State); - SetCullFace(State); - SetDepth(State); - SetStencil(State); - SetBlending(State); - SetColorMask(State); - SetPrimitiveRestart(State); + UpdateDepth(); + } + + if ((DirtyState & PipelineState.Stencil) == 0) + { + DirtyState |= PipelineState.Stencil; + + UpdateStencil(); + } + + if ((DirtyState & PipelineState.Blend) == 0) + { + DirtyState |= PipelineState.Blend; + + UpdateBlend(); + } + + if ((DirtyState & PipelineState.ColorMask) == 0) + { + DirtyState |= PipelineState.ColorMask; + + UpdateColorMask(); + } + + if ((DirtyState & PipelineState.PrimRestart) == 0) + { + DirtyState |= PipelineState.PrimRestart; + + UpdatePrimRestart(); + } for (int FbIndex = 0; FbIndex < 8; FbIndex++) { @@ -114,11 +152,11 @@ namespace Ryujinx.Graphics.Graphics3d Gpu.Renderer.Shader.BindProgram(); - UploadTextures(Vmm, State, Keys); - UploadConstBuffers(Vmm, State, Keys); - UploadVertexArrays(Vmm, State); + UploadTextures(Vmm, Keys); + UploadConstBuffers(Vmm, Keys); + UploadVertexArrays(Vmm); - DispatchRender(Vmm, State); + DispatchRender(Vmm); UnlockCaches(); } @@ -162,8 +200,8 @@ namespace Ryujinx.Graphics.Graphics3d Gpu.Renderer.Rasterizer.ClearBuffers(Flags, Attachment, Red, Green, Blue, Alpha, Depth, Stencil); - Gpu.Renderer.Pipeline.ResetDepthMask(); - Gpu.Renderer.Pipeline.ResetColorMask(Attachment); + DirtyState &= ~PipelineState.Depth; + DirtyState &= ~PipelineState.ColorMask; } private void SetFrameBuffer(NvGpuVmm Vmm, int FbIndex) @@ -211,23 +249,6 @@ namespace Ryujinx.Graphics.Graphics3d Gpu.Renderer.RenderTarget.SetViewport(FbIndex, VpX, VpY, VpW, VpH); } - private void SetFrameBuffer(GalPipelineState State) - { - State.FramebufferSrgb = ReadRegisterBool(NvGpuEngine3dReg.FrameBufferSrgb); - - State.FlipX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX); - State.FlipY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY); - - int ScreenYControl = ReadRegister(NvGpuEngine3dReg.ScreenYControl); - - bool NegateY = (ScreenYControl & 1) != 0; - - if (NegateY) - { - State.FlipY = -State.FlipY; - } - } - private void SetZeta(NvGpuVmm Vmm) { long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress); @@ -338,115 +359,174 @@ namespace Ryujinx.Graphics.Graphics3d throw new ArgumentOutOfRangeException(nameof(Program)); } - private void SetFrontFace(GalPipelineState State) + private void SetDepth(NvGpuVmm Vmm, GpuMethodCall MethCall) { - float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX); - float SignY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY); + WriteRegister(MethCall); - GalFrontFace FrontFace = (GalFrontFace)ReadRegister(NvGpuEngine3dReg.FrontFace); - - //Flipping breaks facing. Flipping front facing too fixes it - if (SignX != SignY) - { - switch (FrontFace) - { - case GalFrontFace.CW: FrontFace = GalFrontFace.CCW; break; - case GalFrontFace.CCW: FrontFace = GalFrontFace.CW; break; - } - } - - State.FrontFace = FrontFace; + DirtyState &= ~PipelineState.Depth; } - private void SetCullFace(GalPipelineState State) + private void SetStencil(NvGpuVmm Vmm, GpuMethodCall MethCall) { - State.CullFaceEnabled = ReadRegisterBool(NvGpuEngine3dReg.CullFaceEnable); + WriteRegister(MethCall); - if (State.CullFaceEnabled) + DirtyState &= ~PipelineState.Stencil; + } + + private void SetBlend(NvGpuVmm Vmm, GpuMethodCall MethCall) + { + WriteRegister(MethCall); + + DirtyState &= ~PipelineState.Blend; + } + + private void SetColorMask(NvGpuVmm Vmm, GpuMethodCall MethCall) + { + WriteRegister(MethCall); + + DirtyState &= ~PipelineState.ColorMask; + } + + private void SetPrimRestart(NvGpuVmm Vmm, GpuMethodCall MethCall) + { + WriteRegister(MethCall); + + DirtyState &= ~PipelineState.PrimRestart; + } + + private void SetFramebufferSrgb(NvGpuVmm Vmm, GpuMethodCall MethCall) + { + bool FramebufferSrgb = ReadRegisterBool(NvGpuEngine3dReg.FrameBufferSrgb); + + Gpu.Renderer.Pipeline.SetFramebufferSrgb(FramebufferSrgb); + + Gpu.Renderer.RenderTarget.FramebufferSrgb = FramebufferSrgb; + } + + private void UpdateDepth() + { + bool DepthTestEnabled = ReadRegisterBool(NvGpuEngine3dReg.DepthTestEnable); + bool DepthWriteEnabled = ReadRegisterBool(NvGpuEngine3dReg.DepthWriteEnable); + + Gpu.Renderer.Pipeline.SetDepthMask(DepthTestEnabled, DepthWriteEnabled); + + if (DepthTestEnabled) { - State.CullFace = (GalCullFace)ReadRegister(NvGpuEngine3dReg.CullFace); + GalComparisonOp DepthFunc = (GalComparisonOp)ReadRegister(NvGpuEngine3dReg.DepthTestFunction); + + Gpu.Renderer.Pipeline.SetDepthFunc(DepthFunc); + } + + if (DepthTestEnabled || DepthWriteEnabled) + { + float DepthRangeNear = ReadRegisterFloat(NvGpuEngine3dReg.DepthRangeNNear); + float DepthRangeFar = ReadRegisterFloat(NvGpuEngine3dReg.DepthRangeNFar); + + Gpu.Renderer.Pipeline.SetDepthRange(DepthRangeNear, DepthRangeFar); } } - private void SetDepth(GalPipelineState State) + private void UpdateStencil() { - State.DepthTestEnabled = ReadRegisterBool(NvGpuEngine3dReg.DepthTestEnable); + bool StencilTestEnabled = ReadRegisterBool(NvGpuEngine3dReg.StencilEnable); - State.DepthWriteEnabled = ReadRegisterBool(NvGpuEngine3dReg.DepthWriteEnable); + Gpu.Renderer.Pipeline.SetStencilTestEnabled(StencilTestEnabled); - if (State.DepthTestEnabled) + if (StencilTestEnabled) { - State.DepthFunc = (GalComparisonOp)ReadRegister(NvGpuEngine3dReg.DepthTestFunction); - } - - State.DepthRangeNear = ReadRegisterFloat(NvGpuEngine3dReg.DepthRangeNNear); - State.DepthRangeFar = ReadRegisterFloat(NvGpuEngine3dReg.DepthRangeNFar); - } - - private void SetStencil(GalPipelineState State) - { - State.StencilTestEnabled = ReadRegisterBool(NvGpuEngine3dReg.StencilEnable); - - if (State.StencilTestEnabled) - { - State.StencilBackFuncFunc = (GalComparisonOp)ReadRegister(NvGpuEngine3dReg.StencilBackFuncFunc); - State.StencilBackFuncRef = ReadRegister(NvGpuEngine3dReg.StencilBackFuncRef); - State.StencilBackFuncMask = (uint)ReadRegister(NvGpuEngine3dReg.StencilBackFuncMask); - State.StencilBackOpFail = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilBackOpFail); - State.StencilBackOpZFail = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilBackOpZFail); - State.StencilBackOpZPass = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilBackOpZPass); - State.StencilBackMask = (uint)ReadRegister(NvGpuEngine3dReg.StencilBackMask); - - State.StencilFrontFuncFunc = (GalComparisonOp)ReadRegister(NvGpuEngine3dReg.StencilFrontFuncFunc); - State.StencilFrontFuncRef = ReadRegister(NvGpuEngine3dReg.StencilFrontFuncRef); - State.StencilFrontFuncMask = (uint)ReadRegister(NvGpuEngine3dReg.StencilFrontFuncMask); - State.StencilFrontOpFail = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilFrontOpFail); - State.StencilFrontOpZFail = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilFrontOpZFail); - State.StencilFrontOpZPass = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilFrontOpZPass); - State.StencilFrontMask = (uint)ReadRegister(NvGpuEngine3dReg.StencilFrontMask); + Gpu.Renderer.Pipeline.SetStencilTest( + (GalComparisonOp)ReadRegister(NvGpuEngine3dReg.StencilBackFuncFunc), + ReadRegister(NvGpuEngine3dReg.StencilBackFuncRef), + (uint)ReadRegister(NvGpuEngine3dReg.StencilBackFuncMask), + (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilBackOpFail), + (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilBackOpZFail), + (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilBackOpZPass), + (uint)ReadRegister(NvGpuEngine3dReg.StencilBackMask), + (GalComparisonOp)ReadRegister(NvGpuEngine3dReg.StencilFrontFuncFunc), + ReadRegister(NvGpuEngine3dReg.StencilFrontFuncRef), + (uint)ReadRegister(NvGpuEngine3dReg.StencilFrontFuncMask), + (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilFrontOpFail), + (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilFrontOpZFail), + (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilFrontOpZPass), + (uint)ReadRegister(NvGpuEngine3dReg.StencilFrontMask)); } } - private void SetBlending(GalPipelineState State) + private void UpdateBlend() { bool BlendIndependent = ReadRegisterBool(NvGpuEngine3dReg.BlendIndependent); - State.BlendIndependent = BlendIndependent; - - for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) + if (BlendIndependent) { - if (BlendIndependent) + for (int Index = 0; Index < RenderTargetsCount; Index++) { - State.Blends[Index].Enabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable + Index); + bool Enabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable + Index); - if (State.Blends[Index].Enabled) + Gpu.Renderer.Pipeline.SetBlendEnabled(Index, Enabled); + + if (Enabled) { - State.Blends[Index].SeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.IBlendNSeparateAlpha + Index * 8); + bool SeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.IBlendNSeparateAlpha + Index * 8); - State.Blends[Index].EquationRgb = ReadBlendEquation(NvGpuEngine3dReg.IBlendNEquationRgb + Index * 8); - State.Blends[Index].FuncSrcRgb = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncSrcRgb + Index * 8); - State.Blends[Index].FuncDstRgb = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncDstRgb + Index * 8); - State.Blends[Index].EquationAlpha = ReadBlendEquation(NvGpuEngine3dReg.IBlendNEquationAlpha + Index * 8); - State.Blends[Index].FuncSrcAlpha = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncSrcAlpha + Index * 8); - State.Blends[Index].FuncDstAlpha = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncDstAlpha + Index * 8); + GalBlendEquation EquationRgb = ReadBlendEquation(NvGpuEngine3dReg.IBlendNEquationRgb + Index * 8); + GalBlendFactor FuncSrcRgb = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncSrcRgb + Index * 8); + GalBlendFactor FuncDstRgb = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncDstRgb + Index * 8); + + if (SeparateAlpha) + { + GalBlendEquation EquationAlpha = ReadBlendEquation(NvGpuEngine3dReg.IBlendNEquationAlpha + Index * 8); + GalBlendFactor FuncSrcAlpha = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncSrcAlpha + Index * 8); + GalBlendFactor FuncDstAlpha = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncDstAlpha + Index * 8); + + Gpu.Renderer.Pipeline.SetBlendSeparate( + Index, + EquationRgb, + FuncSrcRgb, + FuncDstRgb, + EquationAlpha, + FuncSrcAlpha, + FuncDstAlpha); + } + else + { + Gpu.Renderer.Pipeline.SetBlend(Index, EquationRgb, FuncSrcRgb, FuncDstRgb); + } } } - else + } + else + { + //It seems that even when independent blend is disabled, the first IBlend enable + //register is still set to indicate whenever blend is enabled or not (?). + bool Enabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable); + + Gpu.Renderer.Pipeline.SetBlendEnabled(Enabled); + + if (Enabled) { - //It seems that even when independent blend is disabled, the first IBlend enable - //register is still set to indicate whenever blend is enabled or not (?). - State.Blends[Index].Enabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable); + bool SeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.BlendSeparateAlpha); - if (State.Blends[Index].Enabled) + GalBlendEquation EquationRgb = ReadBlendEquation(NvGpuEngine3dReg.BlendEquationRgb); + GalBlendFactor FuncSrcRgb = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncSrcRgb); + GalBlendFactor FuncDstRgb = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncDstRgb); + + if (SeparateAlpha) { - State.Blends[Index].SeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.BlendSeparateAlpha); + GalBlendEquation EquationAlpha = ReadBlendEquation(NvGpuEngine3dReg.BlendEquationAlpha); + GalBlendFactor FuncSrcAlpha = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncSrcAlpha); + GalBlendFactor FuncDstAlpha = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncDstAlpha); - State.Blends[Index].EquationRgb = ReadBlendEquation(NvGpuEngine3dReg.BlendEquationRgb); - State.Blends[Index].FuncSrcRgb = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncSrcRgb); - State.Blends[Index].FuncDstRgb = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncDstRgb); - State.Blends[Index].EquationAlpha = ReadBlendEquation(NvGpuEngine3dReg.BlendEquationAlpha); - State.Blends[Index].FuncSrcAlpha = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncSrcAlpha); - State.Blends[Index].FuncDstAlpha = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncDstAlpha); + Gpu.Renderer.Pipeline.SetBlendSeparate( + EquationRgb, + FuncSrcRgb, + FuncDstRgb, + EquationAlpha, + FuncSrcAlpha, + FuncDstAlpha); + } + else + { + Gpu.Renderer.Pipeline.SetBlend(EquationRgb, FuncSrcRgb, FuncDstRgb); } } } @@ -462,30 +542,48 @@ namespace Ryujinx.Graphics.Graphics3d return (GalBlendFactor)ReadRegister(Register); } - private void SetColorMask(GalPipelineState State) + private void UpdateColorMask() { bool ColorMaskCommon = ReadRegisterBool(NvGpuEngine3dReg.ColorMaskCommon); - State.ColorMaskCommon = ColorMaskCommon; - - for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) + if (ColorMaskCommon) { - int ColorMask = ReadRegister(NvGpuEngine3dReg.ColorMaskN + (ColorMaskCommon ? 0 : Index)); + int ColorMask = ReadRegister(NvGpuEngine3dReg.ColorMaskN); - State.ColorMasks[Index].Red = ((ColorMask >> 0) & 0xf) != 0; - State.ColorMasks[Index].Green = ((ColorMask >> 4) & 0xf) != 0; - State.ColorMasks[Index].Blue = ((ColorMask >> 8) & 0xf) != 0; - State.ColorMasks[Index].Alpha = ((ColorMask >> 12) & 0xf) != 0; + bool RedMask = ((ColorMask >> 0) & 0xf) != 0; + bool GreenMask = ((ColorMask >> 4) & 0xf) != 0; + bool BlueMask = ((ColorMask >> 8) & 0xf) != 0; + bool AlphaMask = ((ColorMask >> 12) & 0xf) != 0; + + Gpu.Renderer.Pipeline.SetColorMask(RedMask, GreenMask, BlueMask, AlphaMask); + } + else + { + for (int Index = 0; Index < RenderTargetsCount; Index++) + { + int ColorMask = ReadRegister(NvGpuEngine3dReg.ColorMaskN + Index); + + bool RedMask = ((ColorMask >> 0) & 0xf) != 0; + bool GreenMask = ((ColorMask >> 4) & 0xf) != 0; + bool BlueMask = ((ColorMask >> 8) & 0xf) != 0; + bool AlphaMask = ((ColorMask >> 12) & 0xf) != 0; + + Gpu.Renderer.Pipeline.SetColorMask(Index, RedMask, GreenMask, BlueMask, AlphaMask); + } } } - private void SetPrimitiveRestart(GalPipelineState State) + private void UpdatePrimRestart() { - State.PrimitiveRestartEnabled = ReadRegisterBool(NvGpuEngine3dReg.PrimRestartEnable); + bool PrimitiveRestartEnabled = ReadRegisterBool(NvGpuEngine3dReg.PrimRestartEnable); - if (State.PrimitiveRestartEnabled) + Gpu.Renderer.Pipeline.SetPrimitiveRestartEnabled(PrimitiveRestartEnabled); + + if (PrimitiveRestartEnabled) { - State.PrimitiveRestartIndex = (uint)ReadRegister(NvGpuEngine3dReg.PrimRestartIndex); + int Index = ReadRegister(NvGpuEngine3dReg.PrimRestartIndex); + + Gpu.Renderer.Pipeline.SetPrimitiveRestartIndex(Index); } } @@ -517,7 +615,7 @@ namespace Ryujinx.Graphics.Graphics3d } } - private void UploadTextures(NvGpuVmm Vmm, GalPipelineState State, long[] Keys) + private void UploadTextures(NvGpuVmm Vmm, long[] Keys) { long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress); @@ -609,10 +707,14 @@ namespace Ryujinx.Graphics.Graphics3d return (Key, Image, Sampler); } - private void UploadConstBuffers(NvGpuVmm Vmm, GalPipelineState State, long[] Keys) + private void UploadConstBuffers(NvGpuVmm Vmm, long[] Keys) { + long[][] ConstBufferKeys = new long[6][]; + for (int Stage = 0; Stage < Keys.Length; Stage++) { + ConstBufferKeys[Stage] = new long[18]; + foreach (ShaderDeclInfo DeclInfo in Gpu.Renderer.Shader.GetConstBufferUsage(Keys[Stage])) { ConstBuffer Cb = ConstBuffers[Stage][DeclInfo.Cbuf]; @@ -636,13 +738,16 @@ namespace Ryujinx.Graphics.Graphics3d } } - State.ConstBufferKeys[Stage][DeclInfo.Cbuf] = Key; + ConstBufferKeys[Stage][DeclInfo.Cbuf] = Key; } } + + Gpu.Renderer.Pipeline.BindConstBuffers(ConstBufferKeys); } - private void UploadVertexArrays(NvGpuVmm Vmm, GalPipelineState State) + private void UploadVertexArrays(NvGpuVmm Vmm) { + //Upload index buffers. long IbPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress); long IboKey = Vmm.GetPhysicalAddress(IbPosition); @@ -750,8 +855,6 @@ namespace Ryujinx.Graphics.Graphics3d Attribs[ArrayIndex].Add(new GalVertexAttrib(Attr, IsConst, Offset, Data, Size, Type, IsRgba)); } - State.VertexBindings = new GalVertexBinding[32]; - for (int Index = 0; Index < 32; Index++) { if (Attribs[Index] == null) @@ -805,17 +908,10 @@ namespace Ryujinx.Graphics.Graphics3d Gpu.Renderer.Rasterizer.CreateVbo(VboKey, Vmm.ReadBytes(VbPosition, VbSize)); } } - - State.VertexBindings[Index].Enabled = true; - State.VertexBindings[Index].Stride = Stride; - State.VertexBindings[Index].VboKey = VboKey; - State.VertexBindings[Index].Instanced = Instanced; - State.VertexBindings[Index].Divisor = VertexDivisor; - State.VertexBindings[Index].Attribs = Attribs[Index].ToArray(); } } - private void DispatchRender(NvGpuVmm Vmm, GalPipelineState State) + private void DispatchRender(NvGpuVmm Vmm) { int IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount); int PrimCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl); @@ -839,9 +935,19 @@ namespace Ryujinx.Graphics.Graphics3d CurrentInstance = 0; } - State.Instance = CurrentInstance; + float FlipX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX); + float FlipY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY); - Gpu.Renderer.Pipeline.Bind(State); + int ScreenYControl = ReadRegister(NvGpuEngine3dReg.ScreenYControl); + + bool NegateY = (ScreenYControl & 1) != 0; + + if (NegateY) + { + FlipY = -FlipY; + } + + Gpu.Renderer.Pipeline.SetFlip(FlipX, FlipY, CurrentInstance); Gpu.Renderer.RenderTarget.Bind();