Implment common and independent blend properly (fixes #458) (#485)

* Implment common and independent blend properly

* Nits
This commit is contained in:
gdkchan 2018-11-01 01:22:24 -03:00 committed by GitHub
parent 1e7ea76f14
commit 44c1cf3fe5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 389 additions and 128 deletions

View file

@ -6,6 +6,12 @@ namespace Ryujinx.Graphics.Gal
FuncSubtract = 2, FuncSubtract = 2,
FuncReverseSubtract = 3, FuncReverseSubtract = 3,
Min = 4, Min = 4,
Max = 5 Max = 5,
FuncAddGl = 0x8006,
FuncSubtractGl = 0x8007,
FuncReverseSubtractGl = 0x8008,
MinGl = 0x800a,
MaxGl = 0x800b
} }
} }

View file

@ -21,6 +21,25 @@ namespace Ryujinx.Graphics.Gal
OneMinusConstantColor = 0x62, OneMinusConstantColor = 0x62,
ConstantAlpha = 0x63, ConstantAlpha = 0x63,
OneMinusConstantAlpha = 0x64, OneMinusConstantAlpha = 0x64,
ConstantColorG80 = 0xc001
ZeroGl = 0x4000,
OneGl = 0x4001,
SrcColorGl = 0x4300,
OneMinusSrcColorGl = 0x4301,
SrcAlphaGl = 0x4302,
OneMinusSrcAlphaGl = 0x4303,
DstAlphaGl = 0x4304,
OneMinusDstAlphaGl = 0x4305,
DstColorGl = 0x4306,
OneMinusDstColorGl = 0x4307,
SrcAlphaSaturateGl = 0x4308,
ConstantColorGl = 0xc001,
OneMinusConstantColorGl = 0xc002,
ConstantAlphaGl = 0xc003,
OneMinusConstantAlphaGl = 0xc004,
Src1ColorGl = 0xc900,
OneMinusSrc1ColorGl = 0xc901,
Src1AlphaGl = 0xc902,
OneMinusSrc1AlphaGl = 0xc903
} }
} }

View file

@ -1,8 +1,8 @@
namespace Ryujinx.Graphics.Gal namespace Ryujinx.Graphics.Gal
{ {
public struct ColorMaskRgba public struct ColorMaskState
{ {
private static readonly ColorMaskRgba _Default = new ColorMaskRgba() private static readonly ColorMaskState _Default = new ColorMaskState()
{ {
Red = true, Red = true,
Green = true, Green = true,
@ -10,7 +10,7 @@
Alpha = true Alpha = true
}; };
public static ColorMaskRgba Default => _Default; public static ColorMaskState Default => _Default;
public bool Red; public bool Red;
public bool Green; public bool Green;
@ -18,6 +18,32 @@
public bool Alpha; public bool Alpha;
} }
public struct BlendState
{
private static readonly BlendState _Default = new BlendState()
{
Enabled = false,
SeparateAlpha = false,
EquationRgb = 0,
FuncSrcRgb = GalBlendFactor.One,
FuncDstRgb = GalBlendFactor.Zero,
EquationAlpha = 0,
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 class GalPipelineState
{ {
public const int Stages = 5; public const int Stages = 5;
@ -65,17 +91,11 @@
public GalStencilOp StencilFrontOpZPass; public GalStencilOp StencilFrontOpZPass;
public uint StencilFrontMask; public uint StencilFrontMask;
public bool BlendEnabled; public bool BlendIndependent;
public bool BlendSeparateAlpha; public BlendState[] Blends;
public GalBlendEquation BlendEquationRgb;
public GalBlendFactor BlendFuncSrcRgb;
public GalBlendFactor BlendFuncDstRgb;
public GalBlendEquation BlendEquationAlpha;
public GalBlendFactor BlendFuncSrcAlpha;
public GalBlendFactor BlendFuncDstAlpha;
public bool ColorMaskCommon; public bool ColorMaskCommon;
public ColorMaskRgba[] ColorMasks; public ColorMaskState[] ColorMasks;
public bool PrimitiveRestartEnabled; public bool PrimitiveRestartEnabled;
public uint PrimitiveRestartIndex; public uint PrimitiveRestartIndex;
@ -89,7 +109,9 @@
ConstBufferKeys[Stage] = new long[ConstBuffersPerStage]; ConstBufferKeys[Stage] = new long[ConstBuffersPerStage];
} }
ColorMasks = new ColorMaskRgba[RenderTargetsCount]; Blends = new BlendState[RenderTargetsCount];
ColorMasks = new ColorMaskState[RenderTargetsCount];
} }
} }
} }

View file

@ -47,32 +47,35 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public static DepthFunction GetDepthFunc(GalComparisonOp Func) public static DepthFunction GetDepthFunc(GalComparisonOp Func)
{ {
//Looks like the GPU can take it's own values (described in GalComparisonOp) and OpenGL values alike return (DepthFunction)GetFunc(Func);
if ((int)Func >= (int)DepthFunction.Never &&
(int)Func <= (int)DepthFunction.Always)
{
return (DepthFunction)Func;
}
switch (Func)
{
case GalComparisonOp.Never: return DepthFunction.Never;
case GalComparisonOp.Less: return DepthFunction.Less;
case GalComparisonOp.Equal: return DepthFunction.Equal;
case GalComparisonOp.Lequal: return DepthFunction.Lequal;
case GalComparisonOp.Greater: return DepthFunction.Greater;
case GalComparisonOp.NotEqual: return DepthFunction.Notequal;
case GalComparisonOp.Gequal: return DepthFunction.Gequal;
case GalComparisonOp.Always: return DepthFunction.Always;
}
throw new ArgumentException(nameof(Func) + " \"" + Func + "\" is not valid!");
} }
public static StencilFunction GetStencilFunc(GalComparisonOp Func) public static StencilFunction GetStencilFunc(GalComparisonOp Func)
{ {
//OGL comparison values match, it's just an enum cast return (StencilFunction)GetFunc(Func);
return (StencilFunction)GetDepthFunc(Func); }
private static All GetFunc(GalComparisonOp Func)
{
if ((int)Func >= (int)All.Never &&
(int)Func <= (int)All.Always)
{
return (All)Func;
}
switch (Func)
{
case GalComparisonOp.Never: return All.Never;
case GalComparisonOp.Less: return All.Less;
case GalComparisonOp.Equal: return All.Equal;
case GalComparisonOp.Lequal: return All.Lequal;
case GalComparisonOp.Greater: return All.Greater;
case GalComparisonOp.NotEqual: return All.Notequal;
case GalComparisonOp.Gequal: return All.Gequal;
case GalComparisonOp.Always: return All.Always;
}
throw new ArgumentException(nameof(Func) + " \"" + Func + "\" is not valid!");
} }
public static DrawElementsType GetDrawElementsType(GalIndexFormat Format) public static DrawElementsType GetDrawElementsType(GalIndexFormat Format)
@ -282,11 +285,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ {
switch (BlendEquation) switch (BlendEquation)
{ {
case GalBlendEquation.FuncAdd: return BlendEquationMode.FuncAdd; case GalBlendEquation.FuncAdd:
case GalBlendEquation.FuncSubtract: return BlendEquationMode.FuncSubtract; case GalBlendEquation.FuncAddGl:
case GalBlendEquation.FuncReverseSubtract: return BlendEquationMode.FuncReverseSubtract; return BlendEquationMode.FuncAdd;
case GalBlendEquation.Min: return BlendEquationMode.Min;
case GalBlendEquation.Max: return BlendEquationMode.Max; case GalBlendEquation.FuncSubtract:
case GalBlendEquation.FuncSubtractGl:
return BlendEquationMode.FuncSubtract;
case GalBlendEquation.FuncReverseSubtract:
case GalBlendEquation.FuncReverseSubtractGl:
return BlendEquationMode.FuncReverseSubtract;
case GalBlendEquation.Min:
case GalBlendEquation.MinGl:
return BlendEquationMode.Min;
case GalBlendEquation.Max:
case GalBlendEquation.MaxGl:
return BlendEquationMode.Max;
} }
throw new ArgumentException(nameof(BlendEquation) + " \"" + BlendEquation + "\" is not valid!"); throw new ArgumentException(nameof(BlendEquation) + " \"" + BlendEquation + "\" is not valid!");
@ -296,27 +313,80 @@ namespace Ryujinx.Graphics.Gal.OpenGL
{ {
switch (BlendFactor) switch (BlendFactor)
{ {
case GalBlendFactor.Zero: return BlendingFactor.Zero; case GalBlendFactor.Zero:
case GalBlendFactor.One: return BlendingFactor.One; case GalBlendFactor.ZeroGl:
case GalBlendFactor.SrcColor: return BlendingFactor.SrcColor; return BlendingFactor.Zero;
case GalBlendFactor.OneMinusSrcColor: return BlendingFactor.OneMinusSrcColor;
case GalBlendFactor.DstColor: return BlendingFactor.DstColor; case GalBlendFactor.One:
case GalBlendFactor.OneMinusDstColor: return BlendingFactor.OneMinusDstColor; case GalBlendFactor.OneGl:
case GalBlendFactor.SrcAlpha: return BlendingFactor.SrcAlpha; return BlendingFactor.One;
case GalBlendFactor.OneMinusSrcAlpha: return BlendingFactor.OneMinusSrcAlpha;
case GalBlendFactor.DstAlpha: return BlendingFactor.DstAlpha; case GalBlendFactor.SrcColor:
case GalBlendFactor.OneMinusDstAlpha: return BlendingFactor.OneMinusDstAlpha; case GalBlendFactor.SrcColorGl:
case GalBlendFactor.OneMinusConstantColor: return BlendingFactor.OneMinusConstantColor; return BlendingFactor.SrcColor;
case GalBlendFactor.ConstantAlpha: return BlendingFactor.ConstantAlpha;
case GalBlendFactor.OneMinusConstantAlpha: return BlendingFactor.OneMinusConstantAlpha; case GalBlendFactor.OneMinusSrcColor:
case GalBlendFactor.SrcAlphaSaturate: return BlendingFactor.SrcAlphaSaturate; case GalBlendFactor.OneMinusSrcColorGl:
case GalBlendFactor.Src1Color: return BlendingFactor.Src1Color; return BlendingFactor.OneMinusSrcColor;
case GalBlendFactor.OneMinusSrc1Color: return (BlendingFactor)BlendingFactorSrc.OneMinusSrc1Color;
case GalBlendFactor.Src1Alpha: return BlendingFactor.Src1Alpha; case GalBlendFactor.DstColor:
case GalBlendFactor.OneMinusSrc1Alpha: return (BlendingFactor)BlendingFactorSrc.OneMinusSrc1Alpha; case GalBlendFactor.DstColorGl:
return BlendingFactor.DstColor;
case GalBlendFactor.OneMinusDstColor:
case GalBlendFactor.OneMinusDstColorGl:
return BlendingFactor.OneMinusDstColor;
case GalBlendFactor.SrcAlpha:
case GalBlendFactor.SrcAlphaGl:
return BlendingFactor.SrcAlpha;
case GalBlendFactor.OneMinusSrcAlpha:
case GalBlendFactor.OneMinusSrcAlphaGl:
return BlendingFactor.OneMinusSrcAlpha;
case GalBlendFactor.DstAlpha:
case GalBlendFactor.DstAlphaGl:
return BlendingFactor.DstAlpha;
case GalBlendFactor.OneMinusDstAlpha:
case GalBlendFactor.OneMinusDstAlphaGl:
return BlendingFactor.OneMinusDstAlpha;
case GalBlendFactor.OneMinusConstantColor:
case GalBlendFactor.OneMinusConstantColorGl:
return BlendingFactor.OneMinusConstantColor;
case GalBlendFactor.ConstantAlpha:
case GalBlendFactor.ConstantAlphaGl:
return BlendingFactor.ConstantAlpha;
case GalBlendFactor.OneMinusConstantAlpha:
case GalBlendFactor.OneMinusConstantAlphaGl:
return BlendingFactor.OneMinusConstantAlpha;
case GalBlendFactor.SrcAlphaSaturate:
case GalBlendFactor.SrcAlphaSaturateGl:
return BlendingFactor.SrcAlphaSaturate;
case GalBlendFactor.Src1Color:
case GalBlendFactor.Src1ColorGl:
return BlendingFactor.Src1Color;
case GalBlendFactor.OneMinusSrc1Color:
case GalBlendFactor.OneMinusSrc1ColorGl:
return (BlendingFactor)BlendingFactorSrc.OneMinusSrc1Color;
case GalBlendFactor.Src1Alpha:
case GalBlendFactor.Src1AlphaGl:
return BlendingFactor.Src1Alpha;
case GalBlendFactor.OneMinusSrc1Alpha:
case GalBlendFactor.OneMinusSrc1AlphaGl:
return (BlendingFactor)BlendingFactorSrc.OneMinusSrc1Alpha;
case GalBlendFactor.ConstantColor: case GalBlendFactor.ConstantColor:
case GalBlendFactor.ConstantColorG80: case GalBlendFactor.ConstantColorGl:
return BlendingFactor.ConstantColor; return BlendingFactor.ConstantColor;
} }

View file

@ -121,15 +121,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
StencilFrontOpZPass = GalStencilOp.Keep, StencilFrontOpZPass = GalStencilOp.Keep,
StencilFrontMask = UInt32.MaxValue, StencilFrontMask = UInt32.MaxValue,
BlendEnabled = false, BlendIndependent = false,
BlendSeparateAlpha = false,
BlendEquationRgb = 0,
BlendFuncSrcRgb = GalBlendFactor.One,
BlendFuncDstRgb = GalBlendFactor.Zero,
BlendEquationAlpha = 0,
BlendFuncSrcAlpha = GalBlendFactor.One,
BlendFuncDstAlpha = GalBlendFactor.Zero,
PrimitiveRestartEnabled = false, PrimitiveRestartEnabled = false,
PrimitiveRestartIndex = 0 PrimitiveRestartIndex = 0
@ -137,7 +129,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
{ {
Old.ColorMasks[Index] = ColorMaskRgba.Default; Old.Blends[Index] = BlendState.Default;
Old.ColorMasks[Index] = ColorMaskState.Default;
} }
} }
@ -268,49 +262,22 @@ namespace Ryujinx.Graphics.Gal.OpenGL
} }
} }
if (New.BlendEnabled != Old.BlendEnabled) if (New.BlendIndependent)
{ {
Enable(EnableCap.Blend, New.BlendEnabled); for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
}
if (New.BlendEnabled)
{ {
if (New.BlendSeparateAlpha) SetBlendState(Index, New.Blends[Index], Old.Blends[Index]);
{
if (New.BlendEquationRgb != Old.BlendEquationRgb ||
New.BlendEquationAlpha != Old.BlendEquationAlpha)
{
GL.BlendEquationSeparate(
OGLEnumConverter.GetBlendEquation(New.BlendEquationRgb),
OGLEnumConverter.GetBlendEquation(New.BlendEquationAlpha));
}
if (New.BlendFuncSrcRgb != Old.BlendFuncSrcRgb ||
New.BlendFuncDstRgb != Old.BlendFuncDstRgb ||
New.BlendFuncSrcAlpha != Old.BlendFuncSrcAlpha ||
New.BlendFuncDstAlpha != Old.BlendFuncDstAlpha)
{
GL.BlendFuncSeparate(
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.BlendFuncSrcRgb),
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.BlendFuncDstRgb),
(BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.BlendFuncSrcAlpha),
(BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.BlendFuncDstAlpha));
} }
} }
else else
{ {
if (New.BlendEquationRgb != Old.BlendEquationRgb) if (New.BlendIndependent != Old.BlendIndependent)
{ {
GL.BlendEquation(OGLEnumConverter.GetBlendEquation(New.BlendEquationRgb)); SetAllBlendState(New.Blends[0]);
} }
else
if (New.BlendFuncSrcRgb != Old.BlendFuncSrcRgb ||
New.BlendFuncDstRgb != Old.BlendFuncDstRgb)
{ {
GL.BlendFunc( SetBlendState(New.Blends[0], Old.Blends[0]);
OGLEnumConverter.GetBlendFactor(New.BlendFuncSrcRgb),
OGLEnumConverter.GetBlendFactor(New.BlendFuncDstRgb));
}
} }
} }
@ -357,6 +324,136 @@ namespace Ryujinx.Graphics.Gal.OpenGL
Old = New; Old = New;
} }
private void SetAllBlendState(BlendState New)
{
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));
}
}
}
private void SetBlendState(BlendState New, BlendState Old)
{
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));
}
}
}
}
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(
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));
}
}
}
}
private void BindConstBuffers(GalPipelineState New) private void BindConstBuffers(GalPipelineState New)
{ {
int FreeBinding = OGLShader.ReservedCbufCount; int FreeBinding = OGLShader.ReservedCbufCount;
@ -640,6 +737,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
} }
} }
private void Enable(IndexedEnableCap Cap, int Index, bool Enabled)
{
if (Enabled)
{
GL.Enable(Cap, Index);
}
else
{
GL.Disable(Cap, Index);
}
}
public void ResetDepthMask() public void ResetDepthMask()
{ {
Old.DepthWriteEnabled = true; Old.DepthWriteEnabled = true;
@ -647,7 +756,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
public void ResetColorMask(int Index) public void ResetColorMask(int Index)
{ {
Old.ColorMasks[Index] = ColorMaskRgba.Default; Old.ColorMasks[Index] = ColorMaskState.Default;
} }
} }
} }

View file

@ -407,21 +407,58 @@ namespace Ryujinx.Graphics
private void SetBlending(GalPipelineState State) private void SetBlending(GalPipelineState State)
{ {
//TODO: Support independent blend properly. bool BlendIndependent = ReadRegisterBool(NvGpuEngine3dReg.BlendIndependent);
State.BlendEnabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable);
if (State.BlendEnabled) State.BlendIndependent = BlendIndependent;
for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
{ {
State.BlendSeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.IBlendNSeparateAlpha); if (BlendIndependent)
{
State.Blends[Index].Enabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable + Index);
State.BlendEquationRgb = (GalBlendEquation)ReadRegister(NvGpuEngine3dReg.IBlendNEquationRgb); if (State.Blends[Index].Enabled)
State.BlendFuncSrcRgb = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.IBlendNFuncSrcRgb); {
State.BlendFuncDstRgb = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.IBlendNFuncDstRgb); State.Blends[Index].SeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.IBlendNSeparateAlpha + Index * 8);
State.BlendEquationAlpha = (GalBlendEquation)ReadRegister(NvGpuEngine3dReg.IBlendNEquationAlpha);
State.BlendFuncSrcAlpha = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.IBlendNFuncSrcAlpha); State.Blends[Index].EquationRgb = ReadBlendEquation(NvGpuEngine3dReg.IBlendNEquationRgb + Index * 8);
State.BlendFuncDstAlpha = (GalBlendFactor)ReadRegister(NvGpuEngine3dReg.IBlendNFuncDstAlpha); 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);
} }
} }
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 (?).
State.Blends[Index].Enabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable);
if (State.Blends[Index].Enabled)
{
State.Blends[Index].SeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.BlendSeparateAlpha);
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);
}
}
}
}
private GalBlendEquation ReadBlendEquation(NvGpuEngine3dReg Register)
{
return (GalBlendEquation)ReadRegister(Register);
}
private GalBlendFactor ReadBlendFactor(NvGpuEngine3dReg Register)
{
return (GalBlendFactor)ReadRegister(Register);
}
private void SetColorMask(GalPipelineState State) private void SetColorMask(GalPipelineState State)
{ {
@ -514,10 +551,8 @@ namespace Ryujinx.Graphics
{ {
if (TextureHandle == 0) if (TextureHandle == 0)
{ {
//TODO: Is this correct? //FIXME: Some games like puyo puyo will use handles with the value 0.
//Some games like puyo puyo will have 0 handles. //This is a bug, most likely caused by sync issues.
//It may be just normal behaviour or a bug caused by sync issues.
//The game does initialize the value properly after through.
return; return;
} }
@ -603,7 +638,7 @@ namespace Ryujinx.Graphics
if (IndexEntrySize > 4) if (IndexEntrySize > 4)
{ {
throw new InvalidOperationException(); throw new InvalidOperationException("Invalid index entry size \"" + IndexEntrySize + "\"!");
} }
if (IndexCount != 0) if (IndexCount != 0)

View file

@ -37,7 +37,7 @@ namespace Ryujinx.Graphics
ZetaVert = 0x48b, ZetaVert = 0x48b,
ZetaArrayMode = 0x48c, ZetaArrayMode = 0x48c,
DepthTestEnable = 0x4b3, DepthTestEnable = 0x4b3,
IBlendEnable = 0x4b9, BlendIndependent = 0x4b9,
DepthWriteEnable = 0x4ba, DepthWriteEnable = 0x4ba,
DepthTestFunction = 0x4c3, DepthTestFunction = 0x4c3,
BlendSeparateAlpha = 0x4cf, BlendSeparateAlpha = 0x4cf,
@ -47,7 +47,7 @@ namespace Ryujinx.Graphics
BlendEquationAlpha = 0x4d3, BlendEquationAlpha = 0x4d3,
BlendFuncSrcAlpha = 0x4d4, BlendFuncSrcAlpha = 0x4d4,
BlendFuncDstAlpha = 0x4d6, BlendFuncDstAlpha = 0x4d6,
BlendEnableMaster = 0x4d7, BlendEnable = 0x4d7,
IBlendNEnable = 0x4d8, IBlendNEnable = 0x4d8,
StencilEnable = 0x4e0, StencilEnable = 0x4e0,
StencilFrontOpFail = 0x4e1, StencilFrontOpFail = 0x4e1,