Pipeline state changes

This commit is contained in:
gdkchan 2018-12-11 09:34:07 +01:00 committed by Roderick Sieben
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 public interface IGalPipeline
{ {
void Bind(GalPipelineState State); void SetFlip(float FlipX, float FlipY, int Instance);
void ResetDepthMask(); //Depth.
void ResetColorMask(int Index); 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 public interface IGalRenderTarget
{ {
bool FramebufferSrgb { get; set; }
void Bind(); void Bind();
void BindColor(long Key, int Attachment); void BindColor(long Key, int Attachment);

View file

@ -1,468 +1,211 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Gal.OpenGL namespace Ryujinx.Graphics.Gal.OpenGL
{ {
class OGLPipeline : IGalPipeline class OGLPipeline : IGalPipeline
{ {
private static Dictionary<GalVertexAttribSize, int> AttribElements =
new Dictionary<GalVertexAttribSize, int>()
{
{ GalVertexAttribSize._32_32_32_32, 4 },
{ GalVertexAttribSize._32_32_32, 3 },
{ GalVertexAttribSize._16_16_16_16, 4 },
{ GalVertexAttribSize._32_32, 2 },
{ GalVertexAttribSize._16_16_16, 3 },
{ GalVertexAttribSize._8_8_8_8, 4 },
{ GalVertexAttribSize._16_16, 2 },
{ GalVertexAttribSize._32, 1 },
{ GalVertexAttribSize._8_8_8, 3 },
{ GalVertexAttribSize._8_8, 2 },
{ GalVertexAttribSize._16, 1 },
{ GalVertexAttribSize._8, 1 },
{ GalVertexAttribSize._10_10_10_2, 4 },
{ GalVertexAttribSize._11_11_10, 3 }
};
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> FloatAttribTypes =
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
{
{ 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 OGLConstBuffer Buffer;
private OGLRenderTarget RenderTarget;
private OGLRasterizer Rasterizer;
private OGLShader Shader; private OGLShader Shader;
private int VaoHandle; private float FlipX;
private float FlipY;
private int Instance;
public OGLPipeline( public OGLPipeline(OGLConstBuffer Buffer, OGLShader Shader)
OGLConstBuffer Buffer,
OGLRenderTarget RenderTarget,
OGLRasterizer Rasterizer,
OGLShader Shader)
{ {
this.Buffer = Buffer; this.Buffer = Buffer;
this.RenderTarget = RenderTarget;
this.Rasterizer = Rasterizer;
this.Shader = Shader; this.Shader = Shader;
}
//These values match OpenGL's defaults public void SetFlip(float FlipX, float FlipY, int Instance)
Old = new GalPipelineState
{ {
FrontFace = GalFrontFace.CCW, if (FlipX != this.FlipX ||
FlipY != this.FlipY ||
CullFaceEnabled = false, Instance != this.Instance)
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; this.FlipX = FlipX;
this.FlipY = FlipY;
this.Instance = Instance;
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); GL.DepthMask(DepthWriteEnabled);
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) public void SetDepthFunc(GalComparisonOp DepthFunc)
{ {
Shader.SetExtraData(New.FlipX, New.FlipY, New.Instance); GL.DepthFunc(OGLEnumConverter.GetDepthFunc(DepthFunc));
} }
//Note: Uncomment SetFrontFace and SetCullFace when flipping issues are solved public void SetDepthRange(float DepthRangeNear, float DepthRangeFar)
//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); GL.DepthRange(DepthRangeNear, DepthRangeFar);
} }
if (New.DepthWriteEnabled != Old.DepthWriteEnabled) public void SetStencilTestEnabled(bool Enabled)
{ {
GL.DepthMask(New.DepthWriteEnabled); Enable(EnableCap.StencilTest, Enabled);
} }
if (New.DepthTestEnabled) public void SetStencilTest(
{ GalComparisonOp StencilBackFuncFunc,
if (New.DepthFunc != Old.DepthFunc) int StencilBackFuncRef,
{ uint StencilBackFuncMask,
GL.DepthFunc(OGLEnumConverter.GetDepthFunc(New.DepthFunc)); GalStencilOp StencilBackOpFail,
} GalStencilOp StencilBackOpZFail,
} GalStencilOp StencilBackOpZPass,
uint StencilBackMask,
if (New.DepthRangeNear != Old.DepthRangeNear || GalComparisonOp StencilFrontFuncFunc,
New.DepthRangeFar != Old.DepthRangeFar) int StencilFrontFuncRef,
{ uint StencilFrontFuncMask,
GL.DepthRange(New.DepthRangeNear, New.DepthRangeFar); GalStencilOp StencilFrontOpFail,
} GalStencilOp StencilFrontOpZFail,
GalStencilOp StencilFrontOpZPass,
if (New.StencilTestEnabled != Old.StencilTestEnabled) uint StencilFrontMask)
{
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( GL.StencilFuncSeparate(
StencilFace.Back, StencilFace.Back,
OGLEnumConverter.GetStencilFunc(New.StencilBackFuncFunc), OGLEnumConverter.GetStencilFunc(StencilBackFuncFunc),
New.StencilBackFuncRef, StencilBackFuncRef,
New.StencilBackFuncMask); StencilBackFuncMask);
}
if (New.StencilBackOpFail != Old.StencilBackOpFail ||
New.StencilBackOpZFail != Old.StencilBackOpZFail ||
New.StencilBackOpZPass != Old.StencilBackOpZPass)
{
GL.StencilOpSeparate( GL.StencilOpSeparate(
StencilFace.Back, StencilFace.Back,
OGLEnumConverter.GetStencilOp(New.StencilBackOpFail), OGLEnumConverter.GetStencilOp(StencilBackOpFail),
OGLEnumConverter.GetStencilOp(New.StencilBackOpZFail), OGLEnumConverter.GetStencilOp(StencilBackOpZFail),
OGLEnumConverter.GetStencilOp(New.StencilBackOpZPass)); OGLEnumConverter.GetStencilOp(StencilBackOpZPass));
}
if (New.StencilBackMask != Old.StencilBackMask) GL.StencilMaskSeparate(StencilFace.Back, StencilBackMask);
{
GL.StencilMaskSeparate(StencilFace.Back, New.StencilBackMask);
}
if (New.StencilFrontFuncFunc != Old.StencilFrontFuncFunc ||
New.StencilFrontFuncRef != Old.StencilFrontFuncRef ||
New.StencilFrontFuncMask != Old.StencilFrontFuncMask)
{
GL.StencilFuncSeparate( GL.StencilFuncSeparate(
StencilFace.Front, StencilFace.Front,
OGLEnumConverter.GetStencilFunc(New.StencilFrontFuncFunc), OGLEnumConverter.GetStencilFunc(StencilFrontFuncFunc),
New.StencilFrontFuncRef, StencilFrontFuncRef,
New.StencilFrontFuncMask); StencilFrontFuncMask);
}
if (New.StencilFrontOpFail != Old.StencilFrontOpFail ||
New.StencilFrontOpZFail != Old.StencilFrontOpZFail ||
New.StencilFrontOpZPass != Old.StencilFrontOpZPass)
{
GL.StencilOpSeparate( GL.StencilOpSeparate(
StencilFace.Front, StencilFace.Front,
OGLEnumConverter.GetStencilOp(New.StencilFrontOpFail), OGLEnumConverter.GetStencilOp(StencilFrontOpFail),
OGLEnumConverter.GetStencilOp(New.StencilFrontOpZFail), OGLEnumConverter.GetStencilOp(StencilFrontOpZFail),
OGLEnumConverter.GetStencilOp(New.StencilFrontOpZPass)); OGLEnumConverter.GetStencilOp(StencilFrontOpZPass));
GL.StencilMaskSeparate(StencilFace.Front, StencilFrontMask);
} }
if (New.StencilFrontMask != Old.StencilFrontMask) public void SetBlendEnabled(bool Enabled)
{ {
GL.StencilMaskSeparate(StencilFace.Front, New.StencilFrontMask); Enable(EnableCap.Blend, Enabled);
}
} }
if (New.BlendIndependent) public void SetBlendEnabled(int Index, bool Enabled)
{ {
for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) Enable(IndexedEnableCap.Blend, Index, Enabled);
{
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) public void SetBlend(
GalBlendEquation EquationRgb,
GalBlendFactor FuncSrcRgb,
GalBlendFactor FuncDstRgb)
{ {
if (New.ColorMaskCommon != Old.ColorMaskCommon || !New.ColorMasks[0].Equals(Old.ColorMasks[0])) GL.BlendEquation(OGLEnumConverter.GetBlendEquation(EquationRgb));
{
GL.ColorMask( GL.BlendFunc(
New.ColorMasks[0].Red, OGLEnumConverter.GetBlendFactor(FuncSrcRgb),
New.ColorMasks[0].Green, OGLEnumConverter.GetBlendFactor(FuncDstRgb));
New.ColorMasks[0].Blue,
New.ColorMasks[0].Alpha);
} }
}
else public void SetBlend(
int Index,
GalBlendEquation EquationRgb,
GalBlendFactor FuncSrcRgb,
GalBlendFactor FuncDstRgb)
{ {
for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) GL.BlendEquation(Index, OGLEnumConverter.GetBlendEquation(EquationRgb));
{
if (!New.ColorMasks[Index].Equals(Old.ColorMasks[Index])) GL.BlendFunc(
{
GL.ColorMask(
Index, Index,
New.ColorMasks[Index].Red, (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(FuncSrcRgb),
New.ColorMasks[Index].Green, (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(FuncDstRgb));
New.ColorMasks[Index].Blue,
New.ColorMasks[Index].Alpha);
}
}
} }
if (New.PrimitiveRestartEnabled != Old.PrimitiveRestartEnabled) public void SetBlendSeparate(
{ GalBlendEquation EquationRgb,
Enable(EnableCap.PrimitiveRestart, New.PrimitiveRestartEnabled); GalBlendFactor FuncSrcRgb,
} GalBlendFactor FuncDstRgb,
GalBlendEquation EquationAlpha,
if (New.PrimitiveRestartEnabled) GalBlendFactor FuncSrcAlpha,
{ GalBlendFactor FuncDstAlpha)
if (New.PrimitiveRestartIndex != Old.PrimitiveRestartIndex)
{
GL.PrimitiveRestartIndex(New.PrimitiveRestartIndex);
}
}
Old = New;
}
private void SetAllBlendState(BlendState New)
{
Enable(EnableCap.Blend, New.Enabled);
if (New.Enabled)
{
if (New.SeparateAlpha)
{ {
GL.BlendEquationSeparate( GL.BlendEquationSeparate(
OGLEnumConverter.GetBlendEquation(New.EquationRgb), OGLEnumConverter.GetBlendEquation(EquationRgb),
OGLEnumConverter.GetBlendEquation(New.EquationAlpha)); OGLEnumConverter.GetBlendEquation(EquationAlpha));
GL.BlendFuncSeparate( GL.BlendFuncSeparate(
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb), (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(FuncSrcRgb),
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb), (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(FuncDstRgb),
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcAlpha), (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(FuncSrcAlpha),
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstAlpha)); (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(FuncDstAlpha));
}
else
{
GL.BlendEquation(OGLEnumConverter.GetBlendEquation(New.EquationRgb));
GL.BlendFunc(
OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
OGLEnumConverter.GetBlendFactor(New.FuncDstRgb));
}
}
} }
private void SetBlendState(BlendState New, BlendState Old) public void SetBlendSeparate(
{ int Index,
if (New.Enabled != Old.Enabled) GalBlendEquation EquationRgb,
{ GalBlendFactor FuncSrcRgb,
Enable(EnableCap.Blend, New.Enabled); GalBlendFactor FuncDstRgb,
} GalBlendEquation EquationAlpha,
GalBlendFactor FuncSrcAlpha,
if (New.Enabled) GalBlendFactor FuncDstAlpha)
{
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));
}
}
}
}
private void SetBlendState(int Index, BlendState New, BlendState Old)
{
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( GL.BlendEquationSeparate(
Index, Index,
OGLEnumConverter.GetBlendEquation(New.EquationRgb), OGLEnumConverter.GetBlendEquation(EquationRgb),
OGLEnumConverter.GetBlendEquation(New.EquationAlpha)); OGLEnumConverter.GetBlendEquation(EquationAlpha));
}
if (New.FuncSrcRgb != Old.FuncSrcRgb ||
New.FuncDstRgb != Old.FuncDstRgb ||
New.FuncSrcAlpha != Old.FuncSrcAlpha ||
New.FuncDstAlpha != Old.FuncDstAlpha)
{
GL.BlendFuncSeparate( GL.BlendFuncSeparate(
Index, Index,
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb), (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(FuncSrcRgb),
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb), (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(FuncDstRgb),
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcAlpha), (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(FuncSrcAlpha),
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstAlpha)); (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(FuncDstAlpha));
}
}
else
{
if (New.EquationRgb != Old.EquationRgb)
{
GL.BlendEquation(Index, OGLEnumConverter.GetBlendEquation(New.EquationRgb));
} }
if (New.FuncSrcRgb != Old.FuncSrcRgb || public void SetColorMask(bool RedMask, bool GreenMask, bool BlueMask, bool AlphaMask)
New.FuncDstRgb != Old.FuncDstRgb)
{ {
GL.BlendFunc( GL.ColorMask(RedMask, GreenMask, BlueMask, AlphaMask);
Index,
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb),
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb));
}
}
}
} }
private void BindConstBuffers(GalPipelineState New) 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; int FreeBinding = OGLShader.ReservedCbufCount;
@ -472,7 +215,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ {
foreach (ShaderDeclInfo DeclInfo in Stage.ConstBufferUsage) 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)) if (Key != 0 && Buffer.TryGetUbo(Key, out int UboHandle))
{ {
@ -491,251 +234,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
BindIfNotNull(Shader.Current.Fragment); 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) private void Enable(EnableCap Cap, bool Enabled)
{ {
if (Enabled) if (Enabled)
@ -759,15 +257,5 @@ namespace Ryujinx.Graphics.Gal.OpenGL
GL.Disable(Cap, Index); 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 NativeWidth = 1280;
private const int NativeHeight = 720; private const int NativeHeight = 720;
private const int RenderTargetsCount = GalPipelineState.RenderTargetsCount; private const int RenderTargetsCount = 8;
private struct Rect private struct Rect
{ {

View file

@ -31,11 +31,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
Shader = new OGLShader(Buffer as OGLConstBuffer); Shader = new OGLShader(Buffer as OGLConstBuffer);
Pipeline = new OGLPipeline( Pipeline = new OGLPipeline(Buffer as OGLConstBuffer, Shader as OGLShader);
Buffer as OGLConstBuffer,
RenderTarget as OGLRenderTarget,
Rasterizer as OGLRasterizer,
Shader as OGLShader);
ActionsQueue = new ConcurrentQueue<Action>(); ActionsQueue = new ConcurrentQueue<Action>();
} }

View file

@ -9,6 +9,8 @@ namespace Ryujinx.Graphics.Graphics3d
{ {
class NvGpuEngine3d : INvGpuEngine class NvGpuEngine3d : INvGpuEngine
{ {
private const int RenderTargetsCount = 8;
public int[] Registers { get; private set; } public int[] Registers { get; private set; }
private NvGpu Gpu; private NvGpu Gpu;
@ -24,6 +26,18 @@ namespace Ryujinx.Graphics.Graphics3d
private ConstBuffer[][] ConstBuffers; 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; private int CurrentInstance = 0;
public NvGpuEngine3d(NvGpu Gpu) public NvGpuEngine3d(NvGpu Gpu)
@ -61,9 +75,9 @@ namespace Ryujinx.Graphics.Graphics3d
//FIXME: Is this correct? //FIXME: Is this correct?
WriteRegister(NvGpuEngine3dReg.ColorMaskN, 0x1111); 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.IBlendNEquationRgb + Index * 8, (int)GalBlendEquation.FuncAdd);
WriteRegister(NvGpuEngine3dReg.IBlendNFuncSrcRgb + Index * 8, (int)GalBlendFactor.One); WriteRegister(NvGpuEngine3dReg.IBlendNFuncSrcRgb + Index * 8, (int)GalBlendFactor.One);
@ -90,16 +104,40 @@ namespace Ryujinx.Graphics.Graphics3d
{ {
LockCaches(); LockCaches();
GalPipelineState State = new GalPipelineState(); if ((DirtyState & PipelineState.Depth) == 0)
{
DirtyState |= PipelineState.Depth;
SetFrameBuffer(State); UpdateDepth();
SetFrontFace(State); }
SetCullFace(State);
SetDepth(State); if ((DirtyState & PipelineState.Stencil) == 0)
SetStencil(State); {
SetBlending(State); DirtyState |= PipelineState.Stencil;
SetColorMask(State);
SetPrimitiveRestart(State); 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++) for (int FbIndex = 0; FbIndex < 8; FbIndex++)
{ {
@ -114,11 +152,11 @@ namespace Ryujinx.Graphics.Graphics3d
Gpu.Renderer.Shader.BindProgram(); Gpu.Renderer.Shader.BindProgram();
UploadTextures(Vmm, State, Keys); UploadTextures(Vmm, Keys);
UploadConstBuffers(Vmm, State, Keys); UploadConstBuffers(Vmm, Keys);
UploadVertexArrays(Vmm, State); UploadVertexArrays(Vmm);
DispatchRender(Vmm, State); DispatchRender(Vmm);
UnlockCaches(); UnlockCaches();
} }
@ -162,8 +200,8 @@ namespace Ryujinx.Graphics.Graphics3d
Gpu.Renderer.Rasterizer.ClearBuffers(Flags, Attachment, Red, Green, Blue, Alpha, Depth, Stencil); Gpu.Renderer.Rasterizer.ClearBuffers(Flags, Attachment, Red, Green, Blue, Alpha, Depth, Stencil);
Gpu.Renderer.Pipeline.ResetDepthMask(); DirtyState &= ~PipelineState.Depth;
Gpu.Renderer.Pipeline.ResetColorMask(Attachment); DirtyState &= ~PipelineState.ColorMask;
} }
private void SetFrameBuffer(NvGpuVmm Vmm, int FbIndex) private void SetFrameBuffer(NvGpuVmm Vmm, int FbIndex)
@ -211,23 +249,6 @@ namespace Ryujinx.Graphics.Graphics3d
Gpu.Renderer.RenderTarget.SetViewport(FbIndex, VpX, VpY, VpW, VpH); 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) private void SetZeta(NvGpuVmm Vmm)
{ {
long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress); long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress);
@ -338,115 +359,174 @@ namespace Ryujinx.Graphics.Graphics3d
throw new ArgumentOutOfRangeException(nameof(Program)); throw new ArgumentOutOfRangeException(nameof(Program));
} }
private void SetFrontFace(GalPipelineState State) private void SetDepth(NvGpuVmm Vmm, GpuMethodCall MethCall)
{ {
float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX); WriteRegister(MethCall);
float SignY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY);
GalFrontFace FrontFace = (GalFrontFace)ReadRegister(NvGpuEngine3dReg.FrontFace); DirtyState &= ~PipelineState.Depth;
}
//Flipping breaks facing. Flipping front facing too fixes it private void SetStencil(NvGpuVmm Vmm, GpuMethodCall MethCall)
if (SignX != SignY)
{ {
switch (FrontFace) WriteRegister(MethCall);
DirtyState &= ~PipelineState.Stencil;
}
private void SetBlend(NvGpuVmm Vmm, GpuMethodCall MethCall)
{ {
case GalFrontFace.CW: FrontFace = GalFrontFace.CCW; break; WriteRegister(MethCall);
case GalFrontFace.CCW: FrontFace = GalFrontFace.CW; break;
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)
{
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);
} }
} }
State.FrontFace = FrontFace; private void UpdateStencil()
}
private void SetCullFace(GalPipelineState State)
{ {
State.CullFaceEnabled = ReadRegisterBool(NvGpuEngine3dReg.CullFaceEnable); bool StencilTestEnabled = ReadRegisterBool(NvGpuEngine3dReg.StencilEnable);
if (State.CullFaceEnabled) Gpu.Renderer.Pipeline.SetStencilTestEnabled(StencilTestEnabled);
if (StencilTestEnabled)
{ {
State.CullFace = (GalCullFace)ReadRegister(NvGpuEngine3dReg.CullFace); 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 SetDepth(GalPipelineState State) private void UpdateBlend()
{
State.DepthTestEnabled = ReadRegisterBool(NvGpuEngine3dReg.DepthTestEnable);
State.DepthWriteEnabled = ReadRegisterBool(NvGpuEngine3dReg.DepthWriteEnable);
if (State.DepthTestEnabled)
{
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);
}
}
private void SetBlending(GalPipelineState State)
{ {
bool BlendIndependent = ReadRegisterBool(NvGpuEngine3dReg.BlendIndependent); bool BlendIndependent = ReadRegisterBool(NvGpuEngine3dReg.BlendIndependent);
State.BlendIndependent = BlendIndependent;
for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
{
if (BlendIndependent) if (BlendIndependent)
{ {
State.Blends[Index].Enabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable + Index); for (int Index = 0; Index < RenderTargetsCount; Index++)
if (State.Blends[Index].Enabled)
{ {
State.Blends[Index].SeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.IBlendNSeparateAlpha + Index * 8); bool Enabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable + Index);
State.Blends[Index].EquationRgb = ReadBlendEquation(NvGpuEngine3dReg.IBlendNEquationRgb + Index * 8); Gpu.Renderer.Pipeline.SetBlendEnabled(Index, Enabled);
State.Blends[Index].FuncSrcRgb = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncSrcRgb + Index * 8);
State.Blends[Index].FuncDstRgb = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncDstRgb + Index * 8); if (Enabled)
State.Blends[Index].EquationAlpha = ReadBlendEquation(NvGpuEngine3dReg.IBlendNEquationAlpha + Index * 8); {
State.Blends[Index].FuncSrcAlpha = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncSrcAlpha + Index * 8); bool SeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.IBlendNSeparateAlpha + 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 //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 (?). //register is still set to indicate whenever blend is enabled or not (?).
State.Blends[Index].Enabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable); bool Enabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable);
if (State.Blends[Index].Enabled) Gpu.Renderer.Pipeline.SetBlendEnabled(Enabled);
if (Enabled)
{ {
State.Blends[Index].SeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.BlendSeparateAlpha); bool SeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.BlendSeparateAlpha);
State.Blends[Index].EquationRgb = ReadBlendEquation(NvGpuEngine3dReg.BlendEquationRgb); GalBlendEquation EquationRgb = ReadBlendEquation(NvGpuEngine3dReg.BlendEquationRgb);
State.Blends[Index].FuncSrcRgb = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncSrcRgb); GalBlendFactor FuncSrcRgb = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncSrcRgb);
State.Blends[Index].FuncDstRgb = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncDstRgb); GalBlendFactor FuncDstRgb = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncDstRgb);
State.Blends[Index].EquationAlpha = ReadBlendEquation(NvGpuEngine3dReg.BlendEquationAlpha);
State.Blends[Index].FuncSrcAlpha = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncSrcAlpha); if (SeparateAlpha)
State.Blends[Index].FuncDstAlpha = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncDstAlpha); {
GalBlendEquation EquationAlpha = ReadBlendEquation(NvGpuEngine3dReg.BlendEquationAlpha);
GalBlendFactor FuncSrcAlpha = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncSrcAlpha);
GalBlendFactor 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); return (GalBlendFactor)ReadRegister(Register);
} }
private void SetColorMask(GalPipelineState State) private void UpdateColorMask()
{ {
bool ColorMaskCommon = ReadRegisterBool(NvGpuEngine3dReg.ColorMaskCommon); bool ColorMaskCommon = ReadRegisterBool(NvGpuEngine3dReg.ColorMaskCommon);
State.ColorMaskCommon = ColorMaskCommon; if (ColorMaskCommon)
for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
{ {
int ColorMask = ReadRegister(NvGpuEngine3dReg.ColorMaskN + (ColorMaskCommon ? 0 : Index)); int ColorMask = ReadRegister(NvGpuEngine3dReg.ColorMaskN);
State.ColorMasks[Index].Red = ((ColorMask >> 0) & 0xf) != 0; bool RedMask = ((ColorMask >> 0) & 0xf) != 0;
State.ColorMasks[Index].Green = ((ColorMask >> 4) & 0xf) != 0; bool GreenMask = ((ColorMask >> 4) & 0xf) != 0;
State.ColorMasks[Index].Blue = ((ColorMask >> 8) & 0xf) != 0; bool BlueMask = ((ColorMask >> 8) & 0xf) != 0;
State.ColorMasks[Index].Alpha = ((ColorMask >> 12) & 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); long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
@ -609,10 +707,14 @@ namespace Ryujinx.Graphics.Graphics3d
return (Key, Image, Sampler); 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++) for (int Stage = 0; Stage < Keys.Length; Stage++)
{ {
ConstBufferKeys[Stage] = new long[18];
foreach (ShaderDeclInfo DeclInfo in Gpu.Renderer.Shader.GetConstBufferUsage(Keys[Stage])) foreach (ShaderDeclInfo DeclInfo in Gpu.Renderer.Shader.GetConstBufferUsage(Keys[Stage]))
{ {
ConstBuffer Cb = ConstBuffers[Stage][DeclInfo.Cbuf]; 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;
}
} }
} }
private void UploadVertexArrays(NvGpuVmm Vmm, GalPipelineState State) Gpu.Renderer.Pipeline.BindConstBuffers(ConstBufferKeys);
}
private void UploadVertexArrays(NvGpuVmm Vmm)
{ {
//Upload index buffers.
long IbPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress); long IbPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress);
long IboKey = Vmm.GetPhysicalAddress(IbPosition); 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)); Attribs[ArrayIndex].Add(new GalVertexAttrib(Attr, IsConst, Offset, Data, Size, Type, IsRgba));
} }
State.VertexBindings = new GalVertexBinding[32];
for (int Index = 0; Index < 32; Index++) for (int Index = 0; Index < 32; Index++)
{ {
if (Attribs[Index] == null) if (Attribs[Index] == null)
@ -805,17 +908,10 @@ namespace Ryujinx.Graphics.Graphics3d
Gpu.Renderer.Rasterizer.CreateVbo(VboKey, Vmm.ReadBytes(VbPosition, VbSize)); 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 IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount);
int PrimCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl); int PrimCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl);
@ -839,9 +935,19 @@ namespace Ryujinx.Graphics.Graphics3d
CurrentInstance = 0; 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(); Gpu.Renderer.RenderTarget.Bind();