diff --git a/Ryujinx.Graphics/DepthCompareFunc.cs b/Ryujinx.Graphics/DepthCompareFunc.cs new file mode 100644 index 0000000000..24c8854a4b --- /dev/null +++ b/Ryujinx.Graphics/DepthCompareFunc.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.Graphics +{ + public enum DepthCompareFunc + { + Never = 0, + Less = 1, + Equal = 2, + LEqual = 3, + Greater = 4, + NotEqual = 5, + GEqual = 6, + Always = 7 + } +} diff --git a/Ryujinx.Graphics/Gal/GalTextureSampler.cs b/Ryujinx.Graphics/Gal/GalTextureSampler.cs index b9e5c7658d..cfe1f5bfab 100644 --- a/Ryujinx.Graphics/Gal/GalTextureSampler.cs +++ b/Ryujinx.Graphics/Gal/GalTextureSampler.cs @@ -12,6 +12,9 @@ namespace Ryujinx.Graphics.Gal public GalColorF BorderColor { get; private set; } + public bool DepthCompare { get; private set; } + public DepthCompareFunc DepthCompareFunc { get; private set; } + public GalTextureSampler( GalTextureWrap AddressU, GalTextureWrap AddressV, @@ -19,7 +22,9 @@ namespace Ryujinx.Graphics.Gal GalTextureFilter MinFilter, GalTextureFilter MagFilter, GalTextureMipFilter MipFilter, - GalColorF BorderColor) + GalColorF BorderColor, + bool DepthCompare, + DepthCompareFunc DepthCompareFunc) { this.AddressU = AddressU; this.AddressV = AddressV; @@ -28,6 +33,9 @@ namespace Ryujinx.Graphics.Gal this.MagFilter = MagFilter; this.MipFilter = MipFilter; this.BorderColor = BorderColor; + + this.DepthCompare = DepthCompare; + this.DepthCompareFunc = DepthCompareFunc; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs index f2afe7b556..3a25fff7a5 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs @@ -189,6 +189,31 @@ namespace Ryujinx.Graphics.Gal.OpenGL throw new NotImplementedException($"{Format & GalImageFormat.FormatMask} {Format & GalImageFormat.TypeMask}"); } + public static All GetDepthCompareFunc(DepthCompareFunc DepthCompareFunc) + { + switch (DepthCompareFunc) + { + case DepthCompareFunc.LEqual: + return All.Lequal; + case DepthCompareFunc.GEqual: + return All.Gequal; + case DepthCompareFunc.Less: + return All.Less; + case DepthCompareFunc.Greater: + return All.Greater; + case DepthCompareFunc.Equal: + return All.Equal; + case DepthCompareFunc.NotEqual: + return All.Notequal; + case DepthCompareFunc.Always: + return All.Always; + case DepthCompareFunc.Never: + return All.Never; + default: + throw new ArgumentException(nameof(DepthCompareFunc) + " \"" + DepthCompareFunc + "\" is not valid!"); + } + } + public static InternalFormat GetCompressedImageFormat(GalImageFormat Format) { switch (Format) diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs index e26c59c8ea..ad8902f481 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs @@ -370,6 +370,17 @@ namespace Ryujinx.Graphics.Gal.OpenGL }; GL.TexParameter(Target, TextureParameterName.TextureBorderColor, Color); + + if (Sampler.DepthCompare) + { + GL.TexParameter(Target, TextureParameterName.TextureCompareMode, (int)All.CompareRToTexture); + GL.TexParameter(Target, TextureParameterName.TextureCompareFunc, (int)OGLEnumConverter.GetDepthCompareFunc(Sampler.DepthCompareFunc)); + } + else + { + GL.TexParameter(Target, TextureParameterName.TextureCompareMode, (int)All.None); + GL.TexParameter(Target, TextureParameterName.TextureCompareFunc, (int)All.Never); + } } } } diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs index bd422657fd..e769d6d206 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs @@ -235,18 +235,24 @@ namespace Ryujinx.Graphics.Gal.Shader string Name = StagePrefix + TextureName + Index; TextureType TextureType; + + TextureInstructionSuffix TextureInstructionSuffix; // TODO: non 2d texture type for TEXQ? if (Op.Inst == ShaderIrInst.Texq) { TextureType = TextureType.TwoD; + TextureInstructionSuffix = TextureInstructionSuffix.None; } else { - TextureType = ((ShaderIrMetaTex)Op.MetaData).TextureType; + ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData); + + TextureType = Meta.TextureType; + TextureInstructionSuffix = Meta.TextureInstructionSuffix; } - m_Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Handle, false, 0, 1, TextureType)); + m_Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Handle, false, 0, 1, TextureType, TextureInstructionSuffix)); } else if (Op.Inst == ShaderIrInst.Texb) { @@ -271,9 +277,10 @@ namespace Ryujinx.Graphics.Gal.Shader if (HandleSrc != null && HandleSrc is ShaderIrOperCbuf Cbuf) { + ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData); string Name = StagePrefix + TextureName + "_cb" + Cbuf.Index + "_" + Cbuf.Pos; - m_CbTextures.Add(Op, new ShaderDeclInfo(Name, Cbuf.Pos, true, Cbuf.Index, 1, ((ShaderIrMetaTex)Op.MetaData).TextureType)); + m_CbTextures.Add(Op, new ShaderDeclInfo(Name, Cbuf.Pos, true, Cbuf.Index, 1, Meta.TextureType, Meta.TextureInstructionSuffix)); } else { diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index 28e66eb714..d5ffa0f0ec 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -221,35 +221,54 @@ namespace Ryujinx.Graphics.Gal.Shader } } - private string GetSamplerType(TextureTarget TextureTarget) + private string GetSamplerType(TextureTarget TextureTarget, bool HasShadow) { + string Result; + switch (TextureTarget) { case TextureTarget.Texture1D: - return "sampler1D"; + Result = "sampler1D"; + break; case TextureTarget.Texture2D: - return "sampler2D"; + Result = "sampler2D"; + break; case TextureTarget.Texture3D: - return "sampler3D"; + Result = "sampler3D"; + break; case TextureTarget.TextureCubeMap: - return "samplerCube"; + Result = "samplerCube"; + break; case TextureTarget.TextureRectangle: - return "sampler2DRect"; + Result = "sampler2DRect"; + break; case TextureTarget.Texture1DArray: - return "sampler1DArray"; + Result = "sampler1DArray"; + break; case TextureTarget.Texture2DArray: - return "sampler2DArray"; + Result = "sampler2DArray"; + break; case TextureTarget.TextureCubeMapArray: - return "samplerCubeArray"; + Result = "samplerCubeArray"; + break; case TextureTarget.TextureBuffer: - return "samplerBuffer"; + Result = "samplerBuffer"; + break; case TextureTarget.Texture2DMultisample: - return "sampler2DMS"; + Result = "sampler2DMS"; + break; case TextureTarget.Texture2DMultisampleArray: - return "sampler2DMSArray"; + Result = "sampler2DMSArray"; + break; default: throw new NotSupportedException(); } + + if (HasShadow) + Result += "Shadow"; + + + return Result; } private void PrintDeclTextures() @@ -257,15 +276,15 @@ namespace Ryujinx.Graphics.Gal.Shader foreach (ShaderDeclInfo DeclInfo in IterateCbTextures()) { TextureTarget Target = ImageUtils.GetTextureTarget(DeclInfo.TextureType); - - SB.AppendLine("uniform " + GetSamplerType(Target) + " " + DeclInfo.Name + ";"); + SB.AppendLine($"// {DeclInfo.TextureSuffix}"); + SB.AppendLine("uniform " + GetSamplerType(Target, (DeclInfo.TextureSuffix & TextureInstructionSuffix.DC) != 0) + " " + DeclInfo.Name + ";"); } foreach (ShaderDeclInfo DeclInfo in Decl.Textures.Values.OrderBy(DeclKeySelector)) { TextureTarget Target = ImageUtils.GetTextureTarget(DeclInfo.TextureType); - - SB.AppendLine("uniform " + GetSamplerType(Target) + " " + DeclInfo.Name + ";"); + SB.AppendLine($"// {DeclInfo.TextureSuffix}"); + SB.AppendLine("uniform " + GetSamplerType(Target, (DeclInfo.TextureSuffix & TextureInstructionSuffix.DC) != 0) + " " + DeclInfo.Name + ";"); } } @@ -1303,10 +1322,13 @@ namespace Ryujinx.Graphics.Gal.Shader { ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + bool HasDepth = (Meta.TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0; + int Coords = ImageUtils.GetCoordsCountTextureType(Meta.TextureType); bool IsArray = ImageUtils.IsArray(Meta.TextureType); + string GetLastArgument(ShaderIrNode Node) { string Result = GetOperExpr(Op, Node); @@ -1321,23 +1343,35 @@ namespace Ryujinx.Graphics.Gal.Shader } string LastArgument; + string DepthArgument = ""; + + int VecSize = Coords; + if (HasDepth) + { + VecSize++; + DepthArgument = $", {GetOperExpr(Op, Meta.DepthCompare)}"; + } switch (Coords) { case 1: + if (HasDepth) + { + return $"vec2({GetOperExpr(Op, Meta.Coordinates[0])}{DepthArgument})"; + } return GetOperExpr(Op, Meta.Coordinates[0]); case 2: LastArgument = GetLastArgument(Meta.Coordinates[1]); - return "vec2(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + LastArgument + ")"; + return $"vec{VecSize}({GetOperExpr(Op, Meta.Coordinates[0])}, {LastArgument}{DepthArgument})"; case 3: LastArgument = GetLastArgument(Meta.Coordinates[2]); - return "vec3(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ", " + LastArgument + ")"; + return $"vec{VecSize}({GetOperExpr(Op, Meta.Coordinates[0])}, {GetOperExpr(Op, Meta.Coordinates[1])}, {LastArgument}{DepthArgument})"; case 4: LastArgument = GetLastArgument(Meta.Coordinates[3]); - return "vec4(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ", " + GetOperExpr(Op, Meta.Coordinates[2]) + ", " + LastArgument + ")"; + return $"vec4({GetOperExpr(Op, Meta.Coordinates[0])}, {GetOperExpr(Op, Meta.Coordinates[1])}, {GetOperExpr(Op, Meta.Coordinates[2])}, {LastArgument}){DepthArgument}"; default: throw new InvalidOperationException(); } @@ -1378,6 +1412,13 @@ namespace Ryujinx.Graphics.Gal.Shader TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix; + string ChString = "." + Ch; + + if ((Suffix & TextureInstructionSuffix.DC) != 0) + { + ChString = ""; + } + // TODO: support LBA and LLA and DC if ((Suffix & TextureInstructionSuffix.LZ) != 0) { @@ -1385,10 +1426,10 @@ namespace Ryujinx.Graphics.Gal.Shader { string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); - return "textureLodOffset(" + Sampler + ", " + Coords + ", 0.0, " + Offset + ")." + Ch; + return "textureLodOffset(" + Sampler + ", " + Coords + ", 0.0, " + Offset + ")" + ChString; } - return "textureLod(" + Sampler + ", " + Coords + ", 0.0)." + Ch; + return "textureLod(" + Sampler + ", " + Coords + ", 0.0)" + ChString; } else if ((Suffix & TextureInstructionSuffix.LB) != 0) { @@ -1396,10 +1437,10 @@ namespace Ryujinx.Graphics.Gal.Shader { string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); - return "textureOffset(" + Sampler + ", " + Coords + ", " + Offset + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")." + Ch; + return "textureOffset(" + Sampler + ", " + Coords + ", " + Offset + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")" + ChString; } - return "texture(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")." + Ch; + return "texture(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")" + ChString; } else if ((Suffix & TextureInstructionSuffix.LL) != 0) { @@ -1407,22 +1448,22 @@ namespace Ryujinx.Graphics.Gal.Shader { string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); - return "textureLodOffset(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ", " + Offset + ")." + Ch; + return "textureLodOffset(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ", " + Offset + ")" + ChString; } - return "textureLod(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")." + Ch; + return "textureLod(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")" + ChString; } else if (Suffix == TextureInstructionSuffix.AOFFI) { string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); - return "textureOffset(" + Sampler + ", " + Coords + ", " + Offset + ")." + Ch; + return "textureOffset(" + Sampler + ", " + Coords + ", " + Offset + ")" + ChString; } - else if (Suffix == TextureInstructionSuffix.None || Suffix == TextureInstructionSuffix.DC) + else { // FIXME: implement DC // Load Standard - return "texture(" + Sampler + ", " + Coords + ")." + Ch; + return "texture(" + Sampler + ", " + Coords + ")" + ChString; } throw new NotImplementedException($"Texture Suffix {Meta.TextureInstructionSuffix} is not implemented"); diff --git a/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs b/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs index 486716d076..48ffa14014 100644 --- a/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs +++ b/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs @@ -13,13 +13,16 @@ namespace Ryujinx.Graphics.Gal public TextureType TextureType { get; private set; } + public TextureInstructionSuffix TextureSuffix { get; private set; } + public ShaderDeclInfo( string Name, int Index, bool IsCb = false, int Cbuf = 0, int Size = 1, - TextureType TextureType = TextureType.TwoD) + TextureType TextureType = TextureType.TwoD, + TextureInstructionSuffix TextureSuffix = TextureInstructionSuffix.None) { this.Name = Name; this.Index = Index; @@ -27,6 +30,8 @@ namespace Ryujinx.Graphics.Gal this.Cbuf = Cbuf; this.Size = Size; this.TextureType = TextureType; + + this.TextureSuffix = TextureSuffix; } internal void Enlarge(int NewSize) diff --git a/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs b/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs index f5c70b1303..efad86babd 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs @@ -94,6 +94,10 @@ namespace Ryujinx.Graphics.Texture GalTextureWrap AddressV = (GalTextureWrap)((Tsc[0] >> 3) & 7); GalTextureWrap AddressP = (GalTextureWrap)((Tsc[0] >> 6) & 7); + bool DepthCompare = ((Tsc[0] >> 9) & 1) == 1; + + DepthCompareFunc DepthCompareFunc = (DepthCompareFunc)((Tsc[0] >> 10) & 7); + GalTextureFilter MagFilter = (GalTextureFilter) ((Tsc[1] >> 0) & 3); GalTextureFilter MinFilter = (GalTextureFilter) ((Tsc[1] >> 4) & 3); GalTextureMipFilter MipFilter = (GalTextureMipFilter)((Tsc[1] >> 6) & 3); @@ -111,7 +115,9 @@ namespace Ryujinx.Graphics.Texture MinFilter, MagFilter, MipFilter, - BorderColor); + BorderColor, + DepthCompare, + DepthCompareFunc); } private static GalImageFormat GetImageFormat(int[] Tic) diff --git a/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs b/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs index fd3c6877c9..5fcafe385a 100644 --- a/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs +++ b/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs @@ -3,7 +3,7 @@ namespace Ryujinx.Graphics.Texture { [Flags] - enum TextureInstructionSuffix + public enum TextureInstructionSuffix { None = 0x00, // No Modifier LZ = 0x02, // Load LOD Zero