Pipeline state changes

This commit is contained in:
gdkchan 2018-12-11 09:34:07 +01:00 committed by Roderick Sieben
parent 2e143365eb
commit a5599e1007
7 changed files with 510 additions and 961 deletions

View file

@ -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];
}
}
}

View file

@ -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);
}
}

View file

@ -2,6 +2,8 @@ namespace Ryujinx.Graphics.Gal
{
public interface IGalRenderTarget
{
bool FramebufferSrgb { get; set; }
void Bind();
void BindColor(long Key, int Attachment);

View file

@ -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<GalVertexAttribSize, int> AttribElements =
new Dictionary<GalVertexAttribSize, int>()
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<GalVertexAttribSize, VertexAttribPointerType> FloatAttribTypes =
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
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<GalVertexAttribSize, VertexAttribPointerType> SignedAttribTypes =
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.Int2101010Rev }
};
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> UnsignedAttribTypes =
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
{
{ 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<GalVertexAttribSize, VertexAttribPointerType> 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;
}
}
}

View file

@ -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
{

View file

@ -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<Action>();
}

View file

@ -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();