From 53a6922f872b9380d6c2867254a2465dc7c1ea92 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sat, 2 Jun 2018 00:50:56 -0300 Subject: [PATCH] Some small gpu improvements and shader improvements, add support for ASTC 4x4 textures (slow!) --- Ryujinx.Core/Gpu/NvGpuEngine3d.cs | 70 ++-------- Ryujinx.Core/Gpu/TextureReader.cs | 1 + Ryujinx.Graphics/Gal/GalTextureFormat.cs | 16 ++- .../Gal/OpenGL/OGLEnumConverter.cs | 20 ++- Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs | 2 +- Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs | 63 +++++++++ Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs | 1 + .../Gal/Shader/ShaderDecodeAlu.cs | 126 +++++++++++++++--- .../Gal/Shader/ShaderDecodeHelper.cs | 28 +++- .../Gal/Shader/ShaderDecodeMem.cs | 100 +++++++++++++- .../Gal/Shader/ShaderOpCodeTable.cs | 5 + 11 files changed, 332 insertions(+), 100 deletions(-) diff --git a/Ryujinx.Core/Gpu/NvGpuEngine3d.cs b/Ryujinx.Core/Gpu/NvGpuEngine3d.cs index 5639dd02..b827debe 100644 --- a/Ryujinx.Core/Gpu/NvGpuEngine3d.cs +++ b/Ryujinx.Core/Gpu/NvGpuEngine3d.cs @@ -182,6 +182,13 @@ namespace Ryujinx.Core.Gpu 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; GalBlendEquation EquationRgb = (GalBlendEquation)ReadRegister(NvGpuEngine3dReg.IBlendNEquationRgb); @@ -362,6 +369,7 @@ namespace Ryujinx.Core.Gpu bool Enable = (Control & 0x1000) != 0; long VertexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4); + long VertexEndPos = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNEndAddr + Index * 2); if (!Enable) { @@ -374,11 +382,7 @@ namespace Ryujinx.Core.Gpu if (IndexCount != 0) { - Size = GetVertexCountFromIndexBuffer( - Vmm, - IndexPosition, - IndexCount, - IndexSize); + Size = (VertexEndPos - VertexPosition) + 1; } 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) { long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.QueryAddress); diff --git a/Ryujinx.Core/Gpu/TextureReader.cs b/Ryujinx.Core/Gpu/TextureReader.cs index 0c1c83d5..ae3b0000 100644 --- a/Ryujinx.Core/Gpu/TextureReader.cs +++ b/Ryujinx.Core/Gpu/TextureReader.cs @@ -23,6 +23,7 @@ namespace Ryujinx.Core.Gpu case GalTextureFormat.BC3: return Read16Bpt4x4(Memory, Texture); case GalTextureFormat.BC4: return Read8Bpt4x4 (Memory, Texture); case GalTextureFormat.BC5: return Read16Bpt4x4(Memory, Texture); + case GalTextureFormat.Astc2D4x4: return Read16Bpt4x4(Memory, Texture); } throw new NotImplementedException(Texture.Format.ToString()); diff --git a/Ryujinx.Graphics/Gal/GalTextureFormat.cs b/Ryujinx.Graphics/Gal/GalTextureFormat.cs index b3d8b03d..d61495eb 100644 --- a/Ryujinx.Graphics/Gal/GalTextureFormat.cs +++ b/Ryujinx.Graphics/Gal/GalTextureFormat.cs @@ -14,6 +14,20 @@ namespace Ryujinx.Graphics.Gal BC2 = 0x25, BC3 = 0x26, 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 } } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs index ee697097..d266a87a 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs @@ -59,14 +59,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL { switch (Format) { - case GalTextureFormat.R32G32B32A32: return (PixelFormat.Rgba, PixelType.Float); - case GalTextureFormat.R16G16B16A16: return (PixelFormat.Rgba, PixelType.HalfFloat); - case GalTextureFormat.A8B8G8R8: return (PixelFormat.Rgba, PixelType.UnsignedByte); - 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); + case GalTextureFormat.A8B8G8R8: return (PixelFormat.Rgba, PixelType.UnsignedByte); + case GalTextureFormat.A1B5G5R5: return (PixelFormat.Rgba, PixelType.UnsignedShort5551); + case GalTextureFormat.B5G6R5: return (PixelFormat.Rgb, PixelType.UnsignedShort565); } throw new NotImplementedException(Format.ToString()); @@ -150,20 +145,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL { switch (BlendEquation) { - default: case GalBlendEquation.FuncAdd: return BlendEquationMode.FuncAdd; case GalBlendEquation.FuncSubtract: return BlendEquationMode.FuncSubtract; case GalBlendEquation.FuncReverseSubtract: return BlendEquationMode.FuncReverseSubtract; case GalBlendEquation.Min: return BlendEquationMode.Min; case GalBlendEquation.Max: return BlendEquationMode.Max; } + + throw new ArgumentException(nameof(BlendEquation)); } public static BlendingFactorSrc GetBlendFactorSrc(GalBlendFactor BlendFactor) { switch (BlendFactor) { - default: case GalBlendFactor.Zero: return BlendingFactorSrc.Zero; case GalBlendFactor.One: return BlendingFactorSrc.One; case GalBlendFactor.SrcColor: return BlendingFactorSrc.SrcColor; @@ -184,13 +179,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL case GalBlendFactor.Src1Alpha: return BlendingFactorSrc.Src1Alpha; case GalBlendFactor.OneMinusSrc1Alpha: return BlendingFactorSrc.OneMinusSrc1Alpha; } + + throw new ArgumentException(nameof(BlendFactor)); } public static BlendingFactorDest GetBlendFactorDst(GalBlendFactor BlendFactor) { switch (BlendFactor) { - default: case GalBlendFactor.Zero: return BlendingFactorDest.Zero; case GalBlendFactor.One: return BlendingFactorDest.One; case GalBlendFactor.SrcColor: return BlendingFactorDest.SrcColor; @@ -211,6 +207,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL case GalBlendFactor.Src1Alpha: return BlendingFactorDest.Src1Alpha; case GalBlendFactor.OneMinusSrc1Alpha: return BlendingFactorDest.OneMinusSrc1Alpha; } + + throw new ArgumentException(nameof(BlendFactor)); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs index a8941d69..be1bb20b 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs @@ -91,7 +91,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL private ShaderStage ShaderStageFactory(IGalMemory Memory, long Position, GalShaderType Type) { - GlslProgram Program = GetGlslProgram(Memory, Position, Type); + GlslProgram Program = GetGlslProgram(Memory, Position, Type); return new ShaderStage( Type, diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs index 8dcfb2bd..75f09faa 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs @@ -1,4 +1,6 @@ using OpenTK.Graphics.OpenGL; +using Ryujinx.Graphics.Gal.Texture; +using System; namespace Ryujinx.Graphics.Gal.OpenGL { @@ -36,6 +38,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL } else { + if (Texture.Format >= GalTextureFormat.Astc2D4x4) + { + ConvertAstcTextureToRgba(Texture); + } + const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba; (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(Texture.Format); @@ -63,6 +70,62 @@ namespace Ryujinx.Graphics.Gal.OpenGL 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) { int Handle = EnsureTextureInitialized(Index); diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index 5c4537fe..71a53a5a 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -389,6 +389,7 @@ namespace Ryujinx.Graphics.Gal.Shader SB.AppendLine(Identation + "gl_Position.xy *= flip;"); SB.AppendLine(Identation + GlslDecl.PositionOutAttrName + " = gl_Position;"); + SB.AppendLine(Identation + GlslDecl.PositionOutAttrName + ".w = 1;"); } } diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs index ddd3e3e8..2e3fb6dd 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs @@ -243,6 +243,75 @@ namespace Ryujinx.Graphics.Gal.Shader 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) { 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)); } + 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) { 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; - bool NegA = ((OpCode >> 49) & 1) != 0; + //Note: this is a range reduction instruction and is supposed to + //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; - - ShaderIrOperImm Scale = GetOperImm5_39(OpCode); + ShaderIrNode OperA; switch (Oper) { - case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break; - case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break; - case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break; + case ShaderOper.CR: OperA = GetOperCbuf34 (OpCode); break; + case ShaderOper.Immf: OperA = GetOperImmf19_20(OpCode); break; + case ShaderOper.RR: OperA = GetOperGpr20 (OpCode); break; default: throw new ArgumentException(nameof(Oper)); } - OperA = GetAluIneg(OperA, NegA); - OperB = GetAluIneg(OperB, NegB); + OperA = GetAluFabsFneg(OperA, AbsA, NegA); - 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)); + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode)); } 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); - ShaderIrInst LopInst = GetBLop(OpCode); + ShaderIrInst LopInst = GetBLop45(OpCode); ShaderIrOperPred PNode = GetOperPred39(OpCode); @@ -685,7 +777,7 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode)); - ShaderIrInst LopInst = GetBLop(OpCode); + ShaderIrInst LopInst = GetBLop45(OpCode); if (LopInst == ShaderIrInst.Band && P1Node.IsConst && P2Node.IsConst) { diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs index 73775cca..3299ebab 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs @@ -119,14 +119,24 @@ namespace Ryujinx.Graphics.Gal.Shader return new ShaderIrOperImmf(Value); } + public static ShaderIrOperPred GetOperPred0(long OpCode) + { + return new ShaderIrOperPred((int)(OpCode >> 0) & 7); + } + public static ShaderIrOperPred GetOperPred3(long OpCode) { 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) @@ -184,7 +194,7 @@ namespace Ryujinx.Graphics.Gal.Shader throw new ArgumentException(nameof(OpCode)); } - public static ShaderIrInst GetBLop(long OpCode) + public static ShaderIrInst GetBLop45(long OpCode) { switch ((int)(OpCode >> 45) & 3) { @@ -196,6 +206,18 @@ namespace Ryujinx.Graphics.Gal.Shader 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) { ShaderIrOperPred Pred = GetPredNode(OpCode); diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs index 5ca485a3..ec03622d 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs @@ -6,6 +6,8 @@ namespace Ryujinx.Graphics.Gal.Shader { static partial class ShaderDecode { + private const int TempRegStart = 0x100; + public static void Ld_A(ShaderIrBlock Block, long 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? } + 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) { EmitTex(Block, OpCode, ShaderIrInst.Texs); @@ -109,11 +167,24 @@ namespace Ryujinx.Graphics.Gal.Shader ShaderIrNode OperB = GetOperGpr20 (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++) { - //Assign it to a temp because the destination registers - //may be used as texture coord input aswell. - ShaderIrOperGpr Dst = new ShaderIrOperGpr(0x100 + Ch); + ShaderIrOperGpr Dst = new ShaderIrOperGpr(TempRegStart + Ch); ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch); @@ -122,15 +193,22 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Op), OpCode)); } + int RegInc = 0; + 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) : GetOperGpr0 (OpCode); - Dst.Index += Ch & 1; + Dst.Index += RegInc++ & 1; if (Dst.Index >= ShaderIrOperGpr.ZRIndex) { @@ -138,7 +216,17 @@ namespace Ryujinx.Graphics.Gal.Shader } Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Src), OpCode)); + + /*if (IsScalar) + { + break; + }*/ } } + + private static bool IsChannelUsed(int ChMask, int Ch) + { + return (ChMask & (1 << Ch)) != 0; + } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs index 51197fd4..074cfbb2 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs @@ -82,6 +82,10 @@ namespace Ryujinx.Graphics.Gal.Shader Set("000000010000xx", ShaderDecode.Mov_I32); Set("0101110010011x", ShaderDecode.Mov_R); 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("0011100x01001x", ShaderDecode.Shl_I); Set("0101110001001x", ShaderDecode.Shl_R); @@ -89,6 +93,7 @@ namespace Ryujinx.Graphics.Gal.Shader Set("0011100x00101x", ShaderDecode.Shr_I); Set("0101110000101x", ShaderDecode.Shr_R); Set("1110111111110x", ShaderDecode.St_A); + Set("110000xxxx111x", ShaderDecode.Tex); Set("1101111101001x", ShaderDecode.Texq); Set("1101100xxxxxxx", ShaderDecode.Texs); Set("1101101xxxxxxx", ShaderDecode.Tlds);