forked from Mirror/Ryujinx
Some small gpu improvements and shader improvements, add support for ASTC 4x4 textures (slow!)
This commit is contained in:
parent
aeb1bbf50c
commit
53a6922f87
11 changed files with 332 additions and 100 deletions
|
@ -182,6 +182,13 @@ namespace Ryujinx.Core.Gpu
|
||||||
|
|
||||||
Gpu.Renderer.SetBlendEnable(Enable);
|
Gpu.Renderer.SetBlendEnable(Enable);
|
||||||
|
|
||||||
|
if (!Enable)
|
||||||
|
{
|
||||||
|
//If blend is not enabled, then the other values have no effect.
|
||||||
|
//Note that if it is disabled, the register may contain invalid values.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool BlendSeparateAlpha = (ReadRegister(NvGpuEngine3dReg.IBlendNSeparateAlpha) & 1) != 0;
|
bool BlendSeparateAlpha = (ReadRegister(NvGpuEngine3dReg.IBlendNSeparateAlpha) & 1) != 0;
|
||||||
|
|
||||||
GalBlendEquation EquationRgb = (GalBlendEquation)ReadRegister(NvGpuEngine3dReg.IBlendNEquationRgb);
|
GalBlendEquation EquationRgb = (GalBlendEquation)ReadRegister(NvGpuEngine3dReg.IBlendNEquationRgb);
|
||||||
|
@ -362,6 +369,7 @@ namespace Ryujinx.Core.Gpu
|
||||||
bool Enable = (Control & 0x1000) != 0;
|
bool Enable = (Control & 0x1000) != 0;
|
||||||
|
|
||||||
long VertexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4);
|
long VertexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4);
|
||||||
|
long VertexEndPos = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNEndAddr + Index * 2);
|
||||||
|
|
||||||
if (!Enable)
|
if (!Enable)
|
||||||
{
|
{
|
||||||
|
@ -374,11 +382,7 @@ namespace Ryujinx.Core.Gpu
|
||||||
|
|
||||||
if (IndexCount != 0)
|
if (IndexCount != 0)
|
||||||
{
|
{
|
||||||
Size = GetVertexCountFromIndexBuffer(
|
Size = (VertexEndPos - VertexPosition) + 1;
|
||||||
Vmm,
|
|
||||||
IndexPosition,
|
|
||||||
IndexCount,
|
|
||||||
IndexSize);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -410,62 +414,6 @@ namespace Ryujinx.Core.Gpu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetVertexCountFromIndexBuffer(
|
|
||||||
NvGpuVmm Vmm,
|
|
||||||
long IndexPosition,
|
|
||||||
int IndexCount,
|
|
||||||
int IndexSize)
|
|
||||||
{
|
|
||||||
int MaxIndex = -1;
|
|
||||||
|
|
||||||
if (IndexSize == 2)
|
|
||||||
{
|
|
||||||
while (IndexCount -- > 0)
|
|
||||||
{
|
|
||||||
ushort Value = Vmm.ReadUInt16(IndexPosition);
|
|
||||||
|
|
||||||
IndexPosition += 2;
|
|
||||||
|
|
||||||
if (MaxIndex < Value)
|
|
||||||
{
|
|
||||||
MaxIndex = Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (IndexSize == 1)
|
|
||||||
{
|
|
||||||
while (IndexCount -- > 0)
|
|
||||||
{
|
|
||||||
byte Value = Vmm.ReadByte(IndexPosition++);
|
|
||||||
|
|
||||||
if (MaxIndex < Value)
|
|
||||||
{
|
|
||||||
MaxIndex = Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (IndexSize == 4)
|
|
||||||
{
|
|
||||||
while (IndexCount -- > 0)
|
|
||||||
{
|
|
||||||
uint Value = Vmm.ReadUInt32(IndexPosition);
|
|
||||||
|
|
||||||
IndexPosition += 2;
|
|
||||||
|
|
||||||
if (MaxIndex < Value)
|
|
||||||
{
|
|
||||||
MaxIndex = (int)Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(IndexSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
return MaxIndex + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void QueryControl(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
private void QueryControl(NvGpuVmm Vmm, NvGpuPBEntry PBEntry)
|
||||||
{
|
{
|
||||||
long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.QueryAddress);
|
long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.QueryAddress);
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace Ryujinx.Core.Gpu
|
||||||
case GalTextureFormat.BC3: return Read16Bpt4x4(Memory, Texture);
|
case GalTextureFormat.BC3: return Read16Bpt4x4(Memory, Texture);
|
||||||
case GalTextureFormat.BC4: return Read8Bpt4x4 (Memory, Texture);
|
case GalTextureFormat.BC4: return Read8Bpt4x4 (Memory, Texture);
|
||||||
case GalTextureFormat.BC5: return Read16Bpt4x4(Memory, Texture);
|
case GalTextureFormat.BC5: return Read16Bpt4x4(Memory, Texture);
|
||||||
|
case GalTextureFormat.Astc2D4x4: return Read16Bpt4x4(Memory, Texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException(Texture.Format.ToString());
|
throw new NotImplementedException(Texture.Format.ToString());
|
||||||
|
|
|
@ -14,6 +14,20 @@ namespace Ryujinx.Graphics.Gal
|
||||||
BC2 = 0x25,
|
BC2 = 0x25,
|
||||||
BC3 = 0x26,
|
BC3 = 0x26,
|
||||||
BC4 = 0x27,
|
BC4 = 0x27,
|
||||||
BC5 = 0x28
|
BC5 = 0x28,
|
||||||
|
Astc2D4x4 = 0x40,
|
||||||
|
Astc2D5x5 = 0x41,
|
||||||
|
Astc2D6x6 = 0x42,
|
||||||
|
Astc2D8x8 = 0x44,
|
||||||
|
Astc2D10x10 = 0x45,
|
||||||
|
Astc2D12x12 = 0x46,
|
||||||
|
Astc2D5x4 = 0x50,
|
||||||
|
Astc2D6x5 = 0x51,
|
||||||
|
Astc2D8x6 = 0x52,
|
||||||
|
Astc2D10x8 = 0x53,
|
||||||
|
Astc2D12x10 = 0x54,
|
||||||
|
Astc2D8x5 = 0x55,
|
||||||
|
Astc2D10x5 = 0x56,
|
||||||
|
Astc2D10x6 = 0x57
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,14 +59,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
switch (Format)
|
switch (Format)
|
||||||
{
|
{
|
||||||
case GalTextureFormat.R32G32B32A32: return (PixelFormat.Rgba, PixelType.Float);
|
case GalTextureFormat.A8B8G8R8: return (PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||||
case GalTextureFormat.R16G16B16A16: return (PixelFormat.Rgba, PixelType.HalfFloat);
|
case GalTextureFormat.A1B5G5R5: return (PixelFormat.Rgba, PixelType.UnsignedShort5551);
|
||||||
case GalTextureFormat.A8B8G8R8: return (PixelFormat.Rgba, PixelType.UnsignedByte);
|
case GalTextureFormat.B5G6R5: return (PixelFormat.Rgb, PixelType.UnsignedShort565);
|
||||||
case GalTextureFormat.R32: return (PixelFormat.Red, PixelType.Float);
|
|
||||||
case GalTextureFormat.A1B5G5R5: return (PixelFormat.Rgba, PixelType.UnsignedShort5551);
|
|
||||||
case GalTextureFormat.B5G6R5: return (PixelFormat.Rgb, PixelType.UnsignedShort565);
|
|
||||||
case GalTextureFormat.G8R8: return (PixelFormat.Rg, PixelType.UnsignedByte);
|
|
||||||
case GalTextureFormat.R8: return (PixelFormat.Red, PixelType.UnsignedByte);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException(Format.ToString());
|
throw new NotImplementedException(Format.ToString());
|
||||||
|
@ -150,20 +145,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
switch (BlendEquation)
|
switch (BlendEquation)
|
||||||
{
|
{
|
||||||
default:
|
|
||||||
case GalBlendEquation.FuncAdd: return BlendEquationMode.FuncAdd;
|
case GalBlendEquation.FuncAdd: return BlendEquationMode.FuncAdd;
|
||||||
case GalBlendEquation.FuncSubtract: return BlendEquationMode.FuncSubtract;
|
case GalBlendEquation.FuncSubtract: return BlendEquationMode.FuncSubtract;
|
||||||
case GalBlendEquation.FuncReverseSubtract: return BlendEquationMode.FuncReverseSubtract;
|
case GalBlendEquation.FuncReverseSubtract: return BlendEquationMode.FuncReverseSubtract;
|
||||||
case GalBlendEquation.Min: return BlendEquationMode.Min;
|
case GalBlendEquation.Min: return BlendEquationMode.Min;
|
||||||
case GalBlendEquation.Max: return BlendEquationMode.Max;
|
case GalBlendEquation.Max: return BlendEquationMode.Max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException(nameof(BlendEquation));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlendingFactorSrc GetBlendFactorSrc(GalBlendFactor BlendFactor)
|
public static BlendingFactorSrc GetBlendFactorSrc(GalBlendFactor BlendFactor)
|
||||||
{
|
{
|
||||||
switch (BlendFactor)
|
switch (BlendFactor)
|
||||||
{
|
{
|
||||||
default:
|
|
||||||
case GalBlendFactor.Zero: return BlendingFactorSrc.Zero;
|
case GalBlendFactor.Zero: return BlendingFactorSrc.Zero;
|
||||||
case GalBlendFactor.One: return BlendingFactorSrc.One;
|
case GalBlendFactor.One: return BlendingFactorSrc.One;
|
||||||
case GalBlendFactor.SrcColor: return BlendingFactorSrc.SrcColor;
|
case GalBlendFactor.SrcColor: return BlendingFactorSrc.SrcColor;
|
||||||
|
@ -184,13 +179,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalBlendFactor.Src1Alpha: return BlendingFactorSrc.Src1Alpha;
|
case GalBlendFactor.Src1Alpha: return BlendingFactorSrc.Src1Alpha;
|
||||||
case GalBlendFactor.OneMinusSrc1Alpha: return BlendingFactorSrc.OneMinusSrc1Alpha;
|
case GalBlendFactor.OneMinusSrc1Alpha: return BlendingFactorSrc.OneMinusSrc1Alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException(nameof(BlendFactor));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlendingFactorDest GetBlendFactorDst(GalBlendFactor BlendFactor)
|
public static BlendingFactorDest GetBlendFactorDst(GalBlendFactor BlendFactor)
|
||||||
{
|
{
|
||||||
switch (BlendFactor)
|
switch (BlendFactor)
|
||||||
{
|
{
|
||||||
default:
|
|
||||||
case GalBlendFactor.Zero: return BlendingFactorDest.Zero;
|
case GalBlendFactor.Zero: return BlendingFactorDest.Zero;
|
||||||
case GalBlendFactor.One: return BlendingFactorDest.One;
|
case GalBlendFactor.One: return BlendingFactorDest.One;
|
||||||
case GalBlendFactor.SrcColor: return BlendingFactorDest.SrcColor;
|
case GalBlendFactor.SrcColor: return BlendingFactorDest.SrcColor;
|
||||||
|
@ -211,6 +207,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
case GalBlendFactor.Src1Alpha: return BlendingFactorDest.Src1Alpha;
|
case GalBlendFactor.Src1Alpha: return BlendingFactorDest.Src1Alpha;
|
||||||
case GalBlendFactor.OneMinusSrc1Alpha: return BlendingFactorDest.OneMinusSrc1Alpha;
|
case GalBlendFactor.OneMinusSrc1Alpha: return BlendingFactorDest.OneMinusSrc1Alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException(nameof(BlendFactor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -91,7 +91,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
|
|
||||||
private ShaderStage ShaderStageFactory(IGalMemory Memory, long Position, GalShaderType Type)
|
private ShaderStage ShaderStageFactory(IGalMemory Memory, long Position, GalShaderType Type)
|
||||||
{
|
{
|
||||||
GlslProgram Program = GetGlslProgram(Memory, Position, Type);
|
GlslProgram Program = GetGlslProgram(Memory, Position, Type);
|
||||||
|
|
||||||
return new ShaderStage(
|
return new ShaderStage(
|
||||||
Type,
|
Type,
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using Ryujinx.Graphics.Gal.Texture;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
{
|
{
|
||||||
|
@ -36,6 +38,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (Texture.Format >= GalTextureFormat.Astc2D4x4)
|
||||||
|
{
|
||||||
|
ConvertAstcTextureToRgba(Texture);
|
||||||
|
}
|
||||||
|
|
||||||
const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
|
const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
|
||||||
|
|
||||||
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(Texture.Format);
|
(PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(Texture.Format);
|
||||||
|
@ -63,6 +70,62 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA);
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ConvertAstcTextureToRgba(GalTexture Texture)
|
||||||
|
{
|
||||||
|
Texture.Data = ASTCDecoder.DecodeToRGBA8888(
|
||||||
|
Texture.Data,
|
||||||
|
GetAstcBlockWidth(Texture.Format),
|
||||||
|
GetAstcBlockHeight(Texture.Format), 1,
|
||||||
|
Texture.Width,
|
||||||
|
Texture.Height, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetAstcBlockWidth(GalTextureFormat Format)
|
||||||
|
{
|
||||||
|
switch (Format)
|
||||||
|
{
|
||||||
|
case GalTextureFormat.Astc2D4x4: return 4;
|
||||||
|
case GalTextureFormat.Astc2D5x5: return 5;
|
||||||
|
case GalTextureFormat.Astc2D6x6: return 6;
|
||||||
|
case GalTextureFormat.Astc2D8x8: return 8;
|
||||||
|
case GalTextureFormat.Astc2D10x10: return 10;
|
||||||
|
case GalTextureFormat.Astc2D12x12: return 12;
|
||||||
|
case GalTextureFormat.Astc2D5x4: return 5;
|
||||||
|
case GalTextureFormat.Astc2D6x5: return 6;
|
||||||
|
case GalTextureFormat.Astc2D8x6: return 8;
|
||||||
|
case GalTextureFormat.Astc2D10x8: return 10;
|
||||||
|
case GalTextureFormat.Astc2D12x10: return 12;
|
||||||
|
case GalTextureFormat.Astc2D8x5: return 8;
|
||||||
|
case GalTextureFormat.Astc2D10x5: return 10;
|
||||||
|
case GalTextureFormat.Astc2D10x6: return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException(nameof(Format));
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetAstcBlockHeight(GalTextureFormat Format)
|
||||||
|
{
|
||||||
|
switch (Format)
|
||||||
|
{
|
||||||
|
case GalTextureFormat.Astc2D4x4: return 4;
|
||||||
|
case GalTextureFormat.Astc2D5x5: return 5;
|
||||||
|
case GalTextureFormat.Astc2D6x6: return 6;
|
||||||
|
case GalTextureFormat.Astc2D8x8: return 8;
|
||||||
|
case GalTextureFormat.Astc2D10x10: return 10;
|
||||||
|
case GalTextureFormat.Astc2D12x12: return 12;
|
||||||
|
case GalTextureFormat.Astc2D5x4: return 4;
|
||||||
|
case GalTextureFormat.Astc2D6x5: return 5;
|
||||||
|
case GalTextureFormat.Astc2D8x6: return 6;
|
||||||
|
case GalTextureFormat.Astc2D10x8: return 8;
|
||||||
|
case GalTextureFormat.Astc2D12x10: return 10;
|
||||||
|
case GalTextureFormat.Astc2D8x5: return 5;
|
||||||
|
case GalTextureFormat.Astc2D10x5: return 5;
|
||||||
|
case GalTextureFormat.Astc2D10x6: return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException(nameof(Format));
|
||||||
|
}
|
||||||
|
|
||||||
public void Bind(int Index)
|
public void Bind(int Index)
|
||||||
{
|
{
|
||||||
int Handle = EnsureTextureInitialized(Index);
|
int Handle = EnsureTextureInitialized(Index);
|
||||||
|
|
|
@ -389,6 +389,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
SB.AppendLine(Identation + "gl_Position.xy *= flip;");
|
SB.AppendLine(Identation + "gl_Position.xy *= flip;");
|
||||||
|
|
||||||
SB.AppendLine(Identation + GlslDecl.PositionOutAttrName + " = gl_Position;");
|
SB.AppendLine(Identation + GlslDecl.PositionOutAttrName + " = gl_Position;");
|
||||||
|
SB.AppendLine(Identation + GlslDecl.PositionOutAttrName + ".w = 1;");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -243,6 +243,75 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Psetp(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
bool NegA = ((OpCode >> 15) & 1) != 0;
|
||||||
|
bool NegB = ((OpCode >> 32) & 1) != 0;
|
||||||
|
bool NegP = ((OpCode >> 42) & 1) != 0;
|
||||||
|
|
||||||
|
ShaderIrInst LopInst = GetBLop24(OpCode);
|
||||||
|
|
||||||
|
ShaderIrNode OperA = GetOperPred12(OpCode);
|
||||||
|
ShaderIrNode OperB = GetOperPred29(OpCode);
|
||||||
|
|
||||||
|
if (NegA)
|
||||||
|
{
|
||||||
|
OperA = new ShaderIrOp(ShaderIrInst.Bnot, OperA);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NegB)
|
||||||
|
{
|
||||||
|
OperB = new ShaderIrOp(ShaderIrInst.Bnot, OperB);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderIrOp Op = new ShaderIrOp(LopInst, OperA, OperB);
|
||||||
|
|
||||||
|
ShaderIrOperPred P0Node = GetOperPred3 (OpCode);
|
||||||
|
ShaderIrOperPred P1Node = GetOperPred0 (OpCode);
|
||||||
|
ShaderIrOperPred P2Node = GetOperPred39(OpCode);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode));
|
||||||
|
|
||||||
|
LopInst = GetBLop45(OpCode);
|
||||||
|
|
||||||
|
if (LopInst == ShaderIrInst.Band && P1Node.IsConst && P2Node.IsConst)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderIrNode P2NNode = P2Node;
|
||||||
|
|
||||||
|
if (NegP)
|
||||||
|
{
|
||||||
|
P2NNode = new ShaderIrOp(ShaderIrInst.Bnot, P2NNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
Op = new ShaderIrOp(ShaderIrInst.Bnot, P0Node);
|
||||||
|
|
||||||
|
Op = new ShaderIrOp(LopInst, Op, P2NNode);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(P1Node, Op), OpCode));
|
||||||
|
|
||||||
|
Op = new ShaderIrOp(LopInst, P0Node, P2NNode);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Rro_C(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitRro(Block, OpCode, ShaderOper.CR);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Rro_I(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitRro(Block, OpCode, ShaderOper.Immf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Rro_R(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
EmitRro(Block, OpCode, ShaderOper.RR);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Shl_C(ShaderIrBlock Block, long OpCode)
|
public static void Shl_C(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Lsl);
|
EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Lsl);
|
||||||
|
@ -445,6 +514,33 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EmitIscadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
|
{
|
||||||
|
bool NegB = ((OpCode >> 48) & 1) != 0;
|
||||||
|
bool NegA = ((OpCode >> 49) & 1) != 0;
|
||||||
|
|
||||||
|
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
|
||||||
|
|
||||||
|
ShaderIrOperImm Scale = GetOperImm5_39(OpCode);
|
||||||
|
|
||||||
|
switch (Oper)
|
||||||
|
{
|
||||||
|
case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
|
||||||
|
case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break;
|
||||||
|
case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
|
||||||
|
|
||||||
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
|
}
|
||||||
|
|
||||||
|
OperA = GetAluIneg(OperA, NegA);
|
||||||
|
OperB = GetAluIneg(OperB, NegB);
|
||||||
|
|
||||||
|
ShaderIrOp ScaleOp = new ShaderIrOp(ShaderIrInst.Lsl, OperA, Scale);
|
||||||
|
ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, OperB, ScaleOp);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), AddOp), OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitFmnmx(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
private static void EmitFmnmx(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
{
|
{
|
||||||
EmitMnmx(Block, OpCode, true, Oper);
|
EmitMnmx(Block, OpCode, true, Oper);
|
||||||
|
@ -524,31 +620,27 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitIscadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
public static void EmitRro(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
{
|
{
|
||||||
bool NegB = ((OpCode >> 48) & 1) != 0;
|
//Note: this is a range reduction instruction and is supposed to
|
||||||
bool NegA = ((OpCode >> 49) & 1) != 0;
|
//be used with Mufu, here it just moves the value and ignores the operation.
|
||||||
|
bool NegA = ((OpCode >> 45) & 1) != 0;
|
||||||
|
bool AbsA = ((OpCode >> 49) & 1) != 0;
|
||||||
|
|
||||||
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
|
ShaderIrNode OperA;
|
||||||
|
|
||||||
ShaderIrOperImm Scale = GetOperImm5_39(OpCode);
|
|
||||||
|
|
||||||
switch (Oper)
|
switch (Oper)
|
||||||
{
|
{
|
||||||
case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break;
|
case ShaderOper.CR: OperA = GetOperCbuf34 (OpCode); break;
|
||||||
case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break;
|
case ShaderOper.Immf: OperA = GetOperImmf19_20(OpCode); break;
|
||||||
case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break;
|
case ShaderOper.RR: OperA = GetOperGpr20 (OpCode); break;
|
||||||
|
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
}
|
}
|
||||||
|
|
||||||
OperA = GetAluIneg(OperA, NegA);
|
OperA = GetAluFabsFneg(OperA, AbsA, NegA);
|
||||||
OperB = GetAluIneg(OperB, NegB);
|
|
||||||
|
|
||||||
ShaderIrOp ScaleOp = new ShaderIrOp(ShaderIrInst.Lsl, OperA, Scale);
|
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode));
|
||||||
ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, OperB, ScaleOp);
|
|
||||||
|
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), AddOp), OpCode));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitFset(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
private static void EmitFset(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
|
@ -597,7 +689,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB);
|
ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB);
|
||||||
|
|
||||||
ShaderIrInst LopInst = GetBLop(OpCode);
|
ShaderIrInst LopInst = GetBLop45(OpCode);
|
||||||
|
|
||||||
ShaderIrOperPred PNode = GetOperPred39(OpCode);
|
ShaderIrOperPred PNode = GetOperPred39(OpCode);
|
||||||
|
|
||||||
|
@ -685,7 +777,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode));
|
||||||
|
|
||||||
ShaderIrInst LopInst = GetBLop(OpCode);
|
ShaderIrInst LopInst = GetBLop45(OpCode);
|
||||||
|
|
||||||
if (LopInst == ShaderIrInst.Band && P1Node.IsConst && P2Node.IsConst)
|
if (LopInst == ShaderIrInst.Band && P1Node.IsConst && P2Node.IsConst)
|
||||||
{
|
{
|
||||||
|
|
|
@ -119,14 +119,24 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return new ShaderIrOperImmf(Value);
|
return new ShaderIrOperImmf(Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ShaderIrOperPred GetOperPred0(long OpCode)
|
||||||
|
{
|
||||||
|
return new ShaderIrOperPred((int)(OpCode >> 0) & 7);
|
||||||
|
}
|
||||||
|
|
||||||
public static ShaderIrOperPred GetOperPred3(long OpCode)
|
public static ShaderIrOperPred GetOperPred3(long OpCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperPred((int)(OpCode >> 3) & 7);
|
return new ShaderIrOperPred((int)(OpCode >> 3) & 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrOperPred GetOperPred0(long OpCode)
|
public static ShaderIrOperPred GetOperPred12(long OpCode)
|
||||||
{
|
{
|
||||||
return new ShaderIrOperPred((int)(OpCode >> 0) & 7);
|
return new ShaderIrOperPred((int)(OpCode >> 12) & 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShaderIrOperPred GetOperPred29(long OpCode)
|
||||||
|
{
|
||||||
|
return new ShaderIrOperPred((int)(OpCode >> 29) & 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrNode GetOperPred39N(long OpCode)
|
public static ShaderIrNode GetOperPred39N(long OpCode)
|
||||||
|
@ -184,7 +194,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
throw new ArgumentException(nameof(OpCode));
|
throw new ArgumentException(nameof(OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShaderIrInst GetBLop(long OpCode)
|
public static ShaderIrInst GetBLop45(long OpCode)
|
||||||
{
|
{
|
||||||
switch ((int)(OpCode >> 45) & 3)
|
switch ((int)(OpCode >> 45) & 3)
|
||||||
{
|
{
|
||||||
|
@ -196,6 +206,18 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
throw new ArgumentException(nameof(OpCode));
|
throw new ArgumentException(nameof(OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ShaderIrInst GetBLop24(long OpCode)
|
||||||
|
{
|
||||||
|
switch ((int)(OpCode >> 24) & 3)
|
||||||
|
{
|
||||||
|
case 0: return ShaderIrInst.Band;
|
||||||
|
case 1: return ShaderIrInst.Bor;
|
||||||
|
case 2: return ShaderIrInst.Bxor;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException(nameof(OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
public static ShaderIrNode GetPredNode(ShaderIrNode Node, long OpCode)
|
public static ShaderIrNode GetPredNode(ShaderIrNode Node, long OpCode)
|
||||||
{
|
{
|
||||||
ShaderIrOperPred Pred = GetPredNode(OpCode);
|
ShaderIrOperPred Pred = GetPredNode(OpCode);
|
||||||
|
|
|
@ -6,6 +6,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
static partial class ShaderDecode
|
static partial class ShaderDecode
|
||||||
{
|
{
|
||||||
|
private const int TempRegStart = 0x100;
|
||||||
|
|
||||||
public static void Ld_A(ShaderIrBlock Block, long OpCode)
|
public static void Ld_A(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
ShaderIrNode[] Opers = GetOperAbuf20(OpCode);
|
ShaderIrNode[] Opers = GetOperAbuf20(OpCode);
|
||||||
|
@ -92,6 +94,62 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(OperA, Op1), OpCode)); //Is this right?
|
Block.AddNode(GetPredNode(new ShaderIrAsg(OperA, Op1), OpCode)); //Is this right?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Tex(ShaderIrBlock Block, long OpCode)
|
||||||
|
{
|
||||||
|
//TODO: Support other formats.
|
||||||
|
ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[2];
|
||||||
|
|
||||||
|
for (int Index = 0; Index < Coords.Length; Index++)
|
||||||
|
{
|
||||||
|
Coords[Index] = GetOperGpr8(OpCode);
|
||||||
|
|
||||||
|
Coords[Index].Index += Index;
|
||||||
|
|
||||||
|
if (Coords[Index].Index > ShaderIrOperGpr.ZRIndex)
|
||||||
|
{
|
||||||
|
Coords[Index].Index = ShaderIrOperGpr.ZRIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ChMask = (int)(OpCode >> 31) & 0xf;
|
||||||
|
|
||||||
|
ShaderIrNode OperC = GetOperImm13_36(OpCode);
|
||||||
|
|
||||||
|
for (int Ch = 0; Ch < 4; Ch++)
|
||||||
|
{
|
||||||
|
ShaderIrOperGpr Dst = new ShaderIrOperGpr(TempRegStart + Ch);
|
||||||
|
|
||||||
|
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch);
|
||||||
|
|
||||||
|
ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Texs, Coords[0], Coords[1], OperC, Meta);
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Op), OpCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
int RegInc = 0;
|
||||||
|
|
||||||
|
for (int Ch = 0; Ch < 4; Ch++)
|
||||||
|
{
|
||||||
|
if (!IsChannelUsed(ChMask, Ch))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderIrOperGpr Src = new ShaderIrOperGpr(TempRegStart + Ch);
|
||||||
|
|
||||||
|
ShaderIrOperGpr Dst = GetOperGpr0(OpCode);
|
||||||
|
|
||||||
|
Dst.Index += RegInc++;
|
||||||
|
|
||||||
|
if (Dst.Index >= ShaderIrOperGpr.ZRIndex)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Src), OpCode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Texs(ShaderIrBlock Block, long OpCode)
|
public static void Texs(ShaderIrBlock Block, long OpCode)
|
||||||
{
|
{
|
||||||
EmitTex(Block, OpCode, ShaderIrInst.Texs);
|
EmitTex(Block, OpCode, ShaderIrInst.Texs);
|
||||||
|
@ -109,11 +167,24 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
ShaderIrNode OperB = GetOperGpr20 (OpCode);
|
ShaderIrNode OperB = GetOperGpr20 (OpCode);
|
||||||
ShaderIrNode OperC = GetOperImm13_36(OpCode);
|
ShaderIrNode OperC = GetOperImm13_36(OpCode);
|
||||||
|
|
||||||
|
bool TwoDests = GetOperGpr28(OpCode).Index != ShaderIrOperGpr.ZRIndex;
|
||||||
|
|
||||||
|
int ChMask;
|
||||||
|
|
||||||
|
switch ((OpCode >> 50) & 7)
|
||||||
|
{
|
||||||
|
case 0: ChMask = TwoDests ? 0x7 : 0x1; break;
|
||||||
|
case 1: ChMask = TwoDests ? 0xb : 0x2; break;
|
||||||
|
case 2: ChMask = TwoDests ? 0xd : 0x4; break;
|
||||||
|
case 3: ChMask = TwoDests ? 0xe : 0x8; break;
|
||||||
|
case 4: ChMask = TwoDests ? 0xf : 0x3; break;
|
||||||
|
|
||||||
|
default: throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
for (int Ch = 0; Ch < 4; Ch++)
|
for (int Ch = 0; Ch < 4; Ch++)
|
||||||
{
|
{
|
||||||
//Assign it to a temp because the destination registers
|
ShaderIrOperGpr Dst = new ShaderIrOperGpr(TempRegStart + Ch);
|
||||||
//may be used as texture coord input aswell.
|
|
||||||
ShaderIrOperGpr Dst = new ShaderIrOperGpr(0x100 + Ch);
|
|
||||||
|
|
||||||
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch);
|
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch);
|
||||||
|
|
||||||
|
@ -122,15 +193,22 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Op), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Op), OpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int RegInc = 0;
|
||||||
|
|
||||||
for (int Ch = 0; Ch < 4; Ch++)
|
for (int Ch = 0; Ch < 4; Ch++)
|
||||||
{
|
{
|
||||||
ShaderIrOperGpr Src = new ShaderIrOperGpr(0x100 + Ch);
|
if (!IsChannelUsed(ChMask, Ch))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
ShaderIrOperGpr Dst = (Ch >> 1) != 0
|
ShaderIrOperGpr Src = new ShaderIrOperGpr(TempRegStart + Ch);
|
||||||
|
|
||||||
|
ShaderIrOperGpr Dst = (RegInc >> 1) != 0
|
||||||
? GetOperGpr28(OpCode)
|
? GetOperGpr28(OpCode)
|
||||||
: GetOperGpr0 (OpCode);
|
: GetOperGpr0 (OpCode);
|
||||||
|
|
||||||
Dst.Index += Ch & 1;
|
Dst.Index += RegInc++ & 1;
|
||||||
|
|
||||||
if (Dst.Index >= ShaderIrOperGpr.ZRIndex)
|
if (Dst.Index >= ShaderIrOperGpr.ZRIndex)
|
||||||
{
|
{
|
||||||
|
@ -138,7 +216,17 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
}
|
}
|
||||||
|
|
||||||
Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Src), OpCode));
|
Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Src), OpCode));
|
||||||
|
|
||||||
|
/*if (IsScalar)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsChannelUsed(int ChMask, int Ch)
|
||||||
|
{
|
||||||
|
return (ChMask & (1 << Ch)) != 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -82,6 +82,10 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Set("000000010000xx", ShaderDecode.Mov_I32);
|
Set("000000010000xx", ShaderDecode.Mov_I32);
|
||||||
Set("0101110010011x", ShaderDecode.Mov_R);
|
Set("0101110010011x", ShaderDecode.Mov_R);
|
||||||
Set("0101000010000x", ShaderDecode.Mufu);
|
Set("0101000010000x", ShaderDecode.Mufu);
|
||||||
|
Set("0101000010010x", ShaderDecode.Psetp);
|
||||||
|
Set("0100110010010x", ShaderDecode.Rro_C);
|
||||||
|
Set("0011100x10010x", ShaderDecode.Rro_I);
|
||||||
|
Set("0101110010010x", ShaderDecode.Rro_R);
|
||||||
Set("0100110001001x", ShaderDecode.Shl_C);
|
Set("0100110001001x", ShaderDecode.Shl_C);
|
||||||
Set("0011100x01001x", ShaderDecode.Shl_I);
|
Set("0011100x01001x", ShaderDecode.Shl_I);
|
||||||
Set("0101110001001x", ShaderDecode.Shl_R);
|
Set("0101110001001x", ShaderDecode.Shl_R);
|
||||||
|
@ -89,6 +93,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Set("0011100x00101x", ShaderDecode.Shr_I);
|
Set("0011100x00101x", ShaderDecode.Shr_I);
|
||||||
Set("0101110000101x", ShaderDecode.Shr_R);
|
Set("0101110000101x", ShaderDecode.Shr_R);
|
||||||
Set("1110111111110x", ShaderDecode.St_A);
|
Set("1110111111110x", ShaderDecode.St_A);
|
||||||
|
Set("110000xxxx111x", ShaderDecode.Tex);
|
||||||
Set("1101111101001x", ShaderDecode.Texq);
|
Set("1101111101001x", ShaderDecode.Texq);
|
||||||
Set("1101100xxxxxxx", ShaderDecode.Texs);
|
Set("1101100xxxxxxx", ShaderDecode.Texs);
|
||||||
Set("1101101xxxxxxx", ShaderDecode.Tlds);
|
Set("1101101xxxxxxx", ShaderDecode.Tlds);
|
||||||
|
|
Reference in a new issue