Add support for saturation on some shader instructions, fix ReadTexture alignment and add ColorMask support (#451)
* Add support for saturation on some shader instructions, fix ReadTexture alignment * Add ColorMask support, other tweaks
This commit is contained in:
parent
894459fcd7
commit
72317d7777
@ -26,6 +26,7 @@
|
|||||||
public GalComparisonOp DepthFunc;
|
public GalComparisonOp DepthFunc;
|
||||||
|
|
||||||
public bool StencilTestEnabled;
|
public bool StencilTestEnabled;
|
||||||
|
public bool StencilTwoSideEnabled;
|
||||||
|
|
||||||
public GalComparisonOp StencilBackFuncFunc;
|
public GalComparisonOp StencilBackFuncFunc;
|
||||||
public int StencilBackFuncRef;
|
public int StencilBackFuncRef;
|
||||||
@ -52,6 +53,11 @@
|
|||||||
public GalBlendFactor BlendFuncSrcAlpha;
|
public GalBlendFactor BlendFuncSrcAlpha;
|
||||||
public GalBlendFactor BlendFuncDstAlpha;
|
public GalBlendFactor BlendFuncDstAlpha;
|
||||||
|
|
||||||
|
public bool ColorMaskR;
|
||||||
|
public bool ColorMaskG;
|
||||||
|
public bool ColorMaskB;
|
||||||
|
public bool ColorMaskA;
|
||||||
|
|
||||||
public bool PrimitiveRestartEnabled;
|
public bool PrimitiveRestartEnabled;
|
||||||
public uint PrimitiveRestartIndex;
|
public uint PrimitiveRestartIndex;
|
||||||
|
|
||||||
|
@ -195,6 +195,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||||||
Enable(EnableCap.StencilTest, New.StencilTestEnabled);
|
Enable(EnableCap.StencilTest, New.StencilTestEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (New.StencilTwoSideEnabled != Old.StencilTwoSideEnabled)
|
||||||
|
{
|
||||||
|
Enable((EnableCap)All.StencilTestTwoSideExt, New.StencilTwoSideEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
if (New.StencilTestEnabled)
|
if (New.StencilTestEnabled)
|
||||||
{
|
{
|
||||||
if (New.StencilBackFuncFunc != Old.StencilBackFuncFunc ||
|
if (New.StencilBackFuncFunc != Old.StencilBackFuncFunc ||
|
||||||
@ -298,6 +303,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (New.ColorMaskR != Old.ColorMaskR ||
|
||||||
|
New.ColorMaskG != Old.ColorMaskG ||
|
||||||
|
New.ColorMaskB != Old.ColorMaskB ||
|
||||||
|
New.ColorMaskA != Old.ColorMaskA)
|
||||||
|
{
|
||||||
|
GL.ColorMask(
|
||||||
|
New.ColorMaskR,
|
||||||
|
New.ColorMaskG,
|
||||||
|
New.ColorMaskB,
|
||||||
|
New.ColorMaskA);
|
||||||
|
}
|
||||||
|
|
||||||
if (New.PrimitiveRestartEnabled != Old.PrimitiveRestartEnabled)
|
if (New.PrimitiveRestartEnabled != Old.PrimitiveRestartEnabled)
|
||||||
{
|
{
|
||||||
Enable(EnableCap.PrimitiveRestart, New.PrimitiveRestartEnabled);
|
Enable(EnableCap.PrimitiveRestart, New.PrimitiveRestartEnabled);
|
||||||
|
@ -585,6 +585,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||||||
bool AbsA = OpCode.Read(46);
|
bool AbsA = OpCode.Read(46);
|
||||||
bool NegA = OpCode.Read(48);
|
bool NegA = OpCode.Read(48);
|
||||||
bool AbsB = OpCode.Read(49);
|
bool AbsB = OpCode.Read(49);
|
||||||
|
bool Sat = OpCode.Read(50);
|
||||||
|
|
||||||
ShaderIrNode OperA = OpCode.Gpr8(), OperB;
|
ShaderIrNode OperA = OpCode.Gpr8(), OperB;
|
||||||
|
|
||||||
@ -603,12 +604,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||||||
|
|
||||||
ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fadd, OperA, OperB);
|
ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fadd, OperA, OperB);
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat))));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitFmul(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
private static void EmitFmul(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
{
|
{
|
||||||
bool NegB = OpCode.Read(48);
|
bool NegB = OpCode.Read(48);
|
||||||
|
bool Sat = OpCode.Read(50);
|
||||||
|
|
||||||
ShaderIrNode OperA = OpCode.Gpr8(), OperB;
|
ShaderIrNode OperA = OpCode.Gpr8(), OperB;
|
||||||
|
|
||||||
@ -625,13 +627,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||||||
|
|
||||||
ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fmul, OperA, OperB);
|
ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fmul, OperA, OperB);
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat))));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitFfma(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
private static void EmitFfma(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
{
|
{
|
||||||
bool NegB = OpCode.Read(48);
|
bool NegB = OpCode.Read(48);
|
||||||
bool NegC = OpCode.Read(49);
|
bool NegC = OpCode.Read(49);
|
||||||
|
bool Sat = OpCode.Read(50);
|
||||||
|
|
||||||
ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC;
|
ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC;
|
||||||
|
|
||||||
@ -658,7 +661,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||||||
|
|
||||||
ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ffma, OperA, OperB, OperC);
|
ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ffma, OperA, OperB, OperC);
|
||||||
|
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat))));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitIadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
private static void EmitIadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
|
@ -2,6 +2,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||||||
{
|
{
|
||||||
static class ShaderDecodeHelper
|
static class ShaderDecodeHelper
|
||||||
{
|
{
|
||||||
|
private static readonly ShaderIrOperImmf ImmfZero = new ShaderIrOperImmf(0);
|
||||||
|
private static readonly ShaderIrOperImmf ImmfOne = new ShaderIrOperImmf(1);
|
||||||
|
|
||||||
public static ShaderIrNode GetAluFabsFneg(ShaderIrNode Node, bool Abs, bool Neg)
|
public static ShaderIrNode GetAluFabsFneg(ShaderIrNode Node, bool Abs, bool Neg)
|
||||||
{
|
{
|
||||||
return GetAluFneg(GetAluFabs(Node, Abs), Neg);
|
return GetAluFneg(GetAluFabs(Node, Abs), Neg);
|
||||||
@ -17,6 +20,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||||||
return Neg ? new ShaderIrOp(ShaderIrInst.Fneg, Node) : Node;
|
return Neg ? new ShaderIrOp(ShaderIrInst.Fneg, Node) : Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ShaderIrNode GetAluFsat(ShaderIrNode Node, bool Sat)
|
||||||
|
{
|
||||||
|
return Sat ? new ShaderIrOp(ShaderIrInst.Fclamp, Node, ImmfZero, ImmfOne) : Node;
|
||||||
|
}
|
||||||
|
|
||||||
public static ShaderIrNode GetAluIabsIneg(ShaderIrNode Node, bool Abs, bool Neg)
|
public static ShaderIrNode GetAluIabsIneg(ShaderIrNode Node, bool Abs, bool Neg)
|
||||||
{
|
{
|
||||||
return GetAluIneg(GetAluIabs(Node, Abs), Neg);
|
return GetAluIneg(GetAluIabs(Node, Abs), Neg);
|
||||||
|
@ -97,7 +97,8 @@ namespace Ryujinx.Graphics
|
|||||||
SetCullFace(State);
|
SetCullFace(State);
|
||||||
SetDepth(State);
|
SetDepth(State);
|
||||||
SetStencil(State);
|
SetStencil(State);
|
||||||
SetAlphaBlending(State);
|
SetBlending(State);
|
||||||
|
SetColorMask(State);
|
||||||
SetPrimitiveRestart(State);
|
SetPrimitiveRestart(State);
|
||||||
|
|
||||||
for (int FbIndex = 0; FbIndex < 8; FbIndex++)
|
for (int FbIndex = 0; FbIndex < 8; FbIndex++)
|
||||||
@ -403,7 +404,7 @@ namespace Ryujinx.Graphics
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetAlphaBlending(GalPipelineState State)
|
private void SetBlending(GalPipelineState State)
|
||||||
{
|
{
|
||||||
//TODO: Support independent blend properly.
|
//TODO: Support independent blend properly.
|
||||||
State.BlendEnabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable);
|
State.BlendEnabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable);
|
||||||
@ -421,6 +422,16 @@ namespace Ryujinx.Graphics
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetColorMask(GalPipelineState State)
|
||||||
|
{
|
||||||
|
int ColorMask = ReadRegister(NvGpuEngine3dReg.ColorMask);
|
||||||
|
|
||||||
|
State.ColorMaskR = ((ColorMask >> 0) & 0xf) != 0;
|
||||||
|
State.ColorMaskG = ((ColorMask >> 4) & 0xf) != 0;
|
||||||
|
State.ColorMaskB = ((ColorMask >> 8) & 0xf) != 0;
|
||||||
|
State.ColorMaskA = ((ColorMask >> 12) & 0xf) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
private void SetPrimitiveRestart(GalPipelineState State)
|
private void SetPrimitiveRestart(GalPipelineState State)
|
||||||
{
|
{
|
||||||
State.PrimitiveRestartEnabled = ReadRegisterBool(NvGpuEngine3dReg.PrimRestartEnable);
|
State.PrimitiveRestartEnabled = ReadRegisterBool(NvGpuEngine3dReg.PrimRestartEnable);
|
||||||
|
@ -78,6 +78,7 @@ namespace Ryujinx.Graphics
|
|||||||
CullFaceEnable = 0x646,
|
CullFaceEnable = 0x646,
|
||||||
FrontFace = 0x647,
|
FrontFace = 0x647,
|
||||||
CullFace = 0x648,
|
CullFace = 0x648,
|
||||||
|
ColorMask = 0x680,
|
||||||
QueryAddress = 0x6c0,
|
QueryAddress = 0x6c0,
|
||||||
QuerySequence = 0x6c2,
|
QuerySequence = 0x6c2,
|
||||||
QueryControl = 0x6c3,
|
QueryControl = 0x6c3,
|
||||||
|
@ -235,11 +235,15 @@ namespace Ryujinx.Graphics.Texture
|
|||||||
|
|
||||||
int BytesPerPixel = Desc.BytesPerPixel;
|
int BytesPerPixel = Desc.BytesPerPixel;
|
||||||
|
|
||||||
int OutOffs = 0;
|
//Note: Each row of the texture needs to be aligned to 4 bytes.
|
||||||
|
int Pitch = (Width * BytesPerPixel + 3) & ~3;
|
||||||
|
|
||||||
byte[] Data = new byte[Width * Height * BytesPerPixel];
|
byte[] Data = new byte[Height * Pitch];
|
||||||
|
|
||||||
for (int Y = 0; Y < Height; Y++)
|
for (int Y = 0; Y < Height; Y++)
|
||||||
|
{
|
||||||
|
int OutOffs = Y * Pitch;
|
||||||
|
|
||||||
for (int X = 0; X < Width; X++)
|
for (int X = 0; X < Width; X++)
|
||||||
{
|
{
|
||||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||||
@ -248,6 +252,7 @@ namespace Ryujinx.Graphics.Texture
|
|||||||
|
|
||||||
OutOffs += BytesPerPixel;
|
OutOffs += BytesPerPixel;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Data;
|
return Data;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user