diff --git a/Ryujinx.Graphics/Gal/GalImage.cs b/Ryujinx.Graphics/Gal/GalImage.cs index dc6f02e044..e9691b67b3 100644 --- a/Ryujinx.Graphics/Gal/GalImage.cs +++ b/Ryujinx.Graphics/Gal/GalImage.cs @@ -4,8 +4,10 @@ namespace Ryujinx.Graphics.Gal { public int Width; public int Height; + public int Depth; public GalImageFormat Format; + public GalImageTarget Target; public GalTextureSource XSource; public GalTextureSource YSource; @@ -15,7 +17,9 @@ namespace Ryujinx.Graphics.Gal public GalImage( int Width, int Height, + int Depth, GalImageFormat Format, + GalImageTarget Target, GalTextureSource XSource = GalTextureSource.Red, GalTextureSource YSource = GalTextureSource.Green, GalTextureSource ZSource = GalTextureSource.Blue, @@ -23,7 +27,9 @@ namespace Ryujinx.Graphics.Gal { this.Width = Width; this.Height = Height; + this.Depth = Depth; this.Format = Format; + this.Target = Target; this.XSource = XSource; this.YSource = YSource; this.ZSource = ZSource; diff --git a/Ryujinx.Graphics/Gal/GalImageType.cs b/Ryujinx.Graphics/Gal/GalImageType.cs new file mode 100644 index 0000000000..fae7f8c873 --- /dev/null +++ b/Ryujinx.Graphics/Gal/GalImageType.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.Graphics.Gal +{ + public enum GalImageTarget + { + _1d = 0, + _2d = 1, + _3d = 2, + CubeMap = 3, + _1dArray = 4, + _2dArray = 5, + _1dBuffer = 6, + _2dNoMimap = 7, //GL_TEXTURE_RECTANGLE? + CubeArray = 8, + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs b/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs index 108d3d9b1d..749f1fb07c 100644 --- a/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/IGalFrameBuffer.cs @@ -12,8 +12,6 @@ namespace Ryujinx.Graphics.Gal void UnbindZeta(); - void BindTexture(long Key, int Index); - void Set(long Key); void Set(byte[] Data, int Width, int Height); diff --git a/Ryujinx.Graphics/Gal/IGalTexture.cs b/Ryujinx.Graphics/Gal/IGalTexture.cs index 292f59efa1..a3714ef6da 100644 --- a/Ryujinx.Graphics/Gal/IGalTexture.cs +++ b/Ryujinx.Graphics/Gal/IGalTexture.cs @@ -11,8 +11,6 @@ namespace Ryujinx.Graphics.Gal bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image); - void Bind(long Key, int Index); - - void SetSampler(GalTextureSampler Sampler); + void Bind(long Key, int Index, GalTextureSampler Sampler); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs index 74f18dcd38..1e18fe9303 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs @@ -34,8 +34,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL public ImageHandler(int Handle, GalImage Image) { this.Handle = Handle; - - this.Image = Image; + this.Image = Image; } public void EnsureSetup(GalImage Image) @@ -48,7 +47,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL (PixelInternalFormat InternalFormat, PixelFormat PixelFormat, PixelType PixelType) = OGLEnumConverter.GetImageFormat(Image.Format); - GL.BindTexture(TextureTarget.Texture2D, Handle); + TextureTarget Target = OGLEnumConverter.GetImageTarget(Image.Target); + + GL.BindTexture(Target, Handle); if (Initialized) { @@ -72,7 +73,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.BufferData(BufferTarget.PixelPackBuffer, CurrentSize, IntPtr.Zero, BufferUsageHint.StreamCopy); } - GL.GetTexImage(TextureTarget.Texture2D, 0, this.PixelFormat, this.PixelType, IntPtr.Zero); + GL.GetTexImage(Target, 0, this.PixelFormat, this.PixelType, IntPtr.Zero); GL.DeleteTexture(Handle); @@ -84,22 +85,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL const int MinFilter = (int)TextureMinFilter.Linear; const int MagFilter = (int)TextureMagFilter.Linear; - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter); + GL.TexParameter(Target, TextureParameterName.TextureMinFilter, MinFilter); + GL.TexParameter(Target, TextureParameterName.TextureMagFilter, MagFilter); const int Level = 0; const int Border = 0; - GL.TexImage2D( - TextureTarget.Texture2D, + OGLHelper.TexImage( + Target, Level, InternalFormat, Image.Width, Image.Height, + Image.Depth, Border, PixelFormat, PixelType, - IntPtr.Zero); + null); if (Initialized) { diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs index 07147cc081..eaf97eb86c 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs @@ -317,5 +317,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL throw new ArgumentException(nameof(BlendFactor)); } + + public static TextureTarget GetImageTarget(GalImageTarget Target) + { + switch (Target) + { + case GalImageTarget._1d: return TextureTarget.Texture1D; + case GalImageTarget._2d: return TextureTarget.Texture2D; + case GalImageTarget._2dArray: return TextureTarget.Texture2DArray; + case GalImageTarget._3d: return TextureTarget.Texture3D; + case GalImageTarget.CubeMap: return TextureTarget.TextureCubeMap; + } + + throw new NotImplementedException(Target.ToString()); + } } } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs index 12239c4f06..929d13c400 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs @@ -148,16 +148,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } - public void BindTexture(long Key, int Index) - { - if (Texture.TryGetImage(Key, out ImageHandler Tex)) - { - GL.ActiveTexture(TextureUnit.Texture0 + Index); - - GL.BindTexture(TextureTarget.Texture2D, Tex.Handle); - } - } - public void Set(long Key) { if (Texture.TryGetImage(Key, out ImageHandler Tex)) @@ -173,7 +163,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL RawTex = new ImageHandler(); } - RawTex.EnsureSetup(new GalImage(Width, Height, RawFormat)); + RawTex.EnsureSetup(new GalImage(Width, Height, 1, RawFormat, GalImageTarget._2d)); GL.BindTexture(TextureTarget.Texture2D, RawTex.Handle); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLHelper.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLHelper.cs new file mode 100644 index 0000000000..258baae13b --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLHelper.cs @@ -0,0 +1,193 @@ +using OpenTK.Graphics.OpenGL; +using System; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + public static class OGLHelper + { + public static unsafe void TexImage( + TextureTarget Target, + int Level, + PixelInternalFormat InternalFormat, + int Width, + int Height, + int Depth, + int Border, + PixelFormat PixelFormat, + PixelType PixelType, + byte[] Data) + { + switch (Target) + { + case TextureTarget.Texture1D: + GL.TexImage1D( + Target, + Level, + InternalFormat, + Width, + Border, + PixelFormat, + PixelType, + Data); + break; + + case TextureTarget.Texture2D: + GL.TexImage2D( + Target, + Level, + InternalFormat, + Width, + Height, + Border, + PixelFormat, + PixelType, + Data); + break; + + case TextureTarget.Texture2DArray: + case TextureTarget.Texture3D: + //FIXME: Unstub depth when swizzle is fixed + Depth = 1; + GL.TexImage3D( + Target, + Level, + InternalFormat, + Width, + Height, + Depth, + Border, + PixelFormat, + PixelType, + Data); + break; + + case TextureTarget.TextureCubeMap: + { + long FaceSize = Data.LongLength / 6; + + for (int Face = 0; Face < 6; Face++) + { + fixed (byte* DataPtr = Data) + { + IntPtr Addr; + + if (Data != null) + { + Addr = new IntPtr(DataPtr + FaceSize * Face); + } + else + { + Addr = new IntPtr(0); + } + + GL.TexImage2D( + TextureTarget.TextureCubeMapPositiveX + Face, + Level, + InternalFormat, + Width, + Height, + Border, + PixelFormat, + PixelType, + Addr); + } + } + break; + } + + default: + throw new NotImplementedException(Target.ToString()); + } + } + + public static unsafe void CompressedTexImage( + TextureTarget Target, + int Level, + InternalFormat InternalFormat, + int Width, + int Height, + int Depth, + int Border, + byte[] Data) + { + switch (Target) + { + case TextureTarget.Texture1D: + GL.CompressedTexImage1D( + Target, + Level, + InternalFormat, + Width, + Border, + Data.Length, + Data); + break; + + case TextureTarget.Texture2D: + GL.CompressedTexImage2D( + Target, + Level, + InternalFormat, + Width, + Height, + Border, + Data.Length, + Data); + break; + + case TextureTarget.Texture2DArray: + case TextureTarget.Texture3D: + //FIXME: Unstub depth when swizzle is fixed + Depth = 1; + GL.CompressedTexImage3D( + Target, + Level, + InternalFormat, + Width, + Height, + Depth, + Border, + Data.Length, + Data); + break; + + case TextureTarget.TextureCubeMap: + { + //FIXME: This implies that all 6 faces are equal + int FaceSize = Data.Length / 6; + + for (int Face = 0; Face < 6; Face++) + { + fixed (byte* DataPtr = Data) + { + IntPtr Addr; + + if (Data != null) + { + Addr = new IntPtr(DataPtr + FaceSize * Face); + } + else + { + Addr = new IntPtr(0); + } + + GL.CompressedTexImage2D( + TextureTarget.TextureCubeMapPositiveX + Face, + Level, + InternalFormat, + Width, + Height, + Border, + FaceSize, + Addr); + } + } + break; + } + + default: + throw new NotImplementedException(Target.ToString()); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs index e4d4bd6480..4bf7336b66 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs @@ -34,7 +34,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length); - GL.BindTexture(TextureTarget.Texture2D, Handle); + TextureTarget Target = OGLEnumConverter.GetImageTarget(Image.Target); + + GL.BindTexture(Target, Handle); const int Level = 0; //TODO: Support mipmap textures. const int Border = 0; @@ -43,21 +45,21 @@ namespace Ryujinx.Graphics.Gal.OpenGL { InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format); - GL.CompressedTexImage2D( - TextureTarget.Texture2D, + OGLHelper.CompressedTexImage( + Target, Level, InternalFmt, Image.Width, Image.Height, + Image.Depth, Border, - Data.Length, Data); } else { if (Image.Format >= GalImageFormat.ASTC_BEGIN && Image.Format <= GalImageFormat.ASTC_END) { - int TextureBlockWidth = GetAstcBlockWidth(Image.Format); + int TextureBlockWidth = GetAstcBlockWidth (Image.Format); int TextureBlockHeight = GetAstcBlockHeight(Image.Format); Data = ASTCDecoder.DecodeToRGBA8888( @@ -72,12 +74,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL (PixelInternalFormat InternalFormat, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format); - GL.TexImage2D( - TextureTarget.Texture2D, + OGLHelper.TexImage( + Target, Level, InternalFormat, Image.Width, Image.Height, + Image.Depth, Border, Format, Type, @@ -89,10 +92,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL int SwizzleB = (int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource); int SwizzleA = (int)OGLEnumConverter.GetTextureSwizzle(Image.WSource); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, SwizzleR); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, SwizzleG); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleB, SwizzleB); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, SwizzleA); + GL.TexParameter(Target, TextureParameterName.TextureSwizzleR, SwizzleR); + GL.TexParameter(Target, TextureParameterName.TextureSwizzleG, SwizzleG); + GL.TexParameter(Target, TextureParameterName.TextureSwizzleB, SwizzleB); + GL.TexParameter(Target, TextureParameterName.TextureSwizzleA, SwizzleA); } public void CreateFb(long Key, long Size, GalImage Image) @@ -182,29 +185,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL return false; } - public void Bind(long Key, int Index) + public void Bind(long Key, int Index, GalTextureSampler Sampler) { - if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage)) + if (!TextureCache.TryGetValue(Key, out ImageHandler CachedImage)) { - GL.ActiveTexture(TextureUnit.Texture0 + Index); - - GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle); + return; } - } - public void SetSampler(GalTextureSampler Sampler) - { + TextureTarget Target = OGLEnumConverter.GetImageTarget(CachedImage.Image.Target); + + GL.ActiveTexture(TextureUnit.Texture0 + Index); + + GL.BindTexture(Target, CachedImage.Handle); + int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU); int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV); int MinFilter = (int)OGLEnumConverter.GetTextureMinFilter(Sampler.MinFilter, Sampler.MipFilter); int MagFilter = (int)OGLEnumConverter.GetTextureMagFilter(Sampler.MagFilter); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, WrapS); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, WrapT); + GL.TexParameter(Target, TextureParameterName.TextureWrapS, WrapS); + GL.TexParameter(Target, TextureParameterName.TextureWrapT, WrapT); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter); + GL.TexParameter(Target, TextureParameterName.TextureMinFilter, MinFilter); + GL.TexParameter(Target, TextureParameterName.TextureMagFilter, MagFilter); float[] Color = new float[] { @@ -214,7 +218,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL Sampler.BorderColor.Alpha }; - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, Color); + GL.TexParameter(Target, TextureParameterName.TextureBorderColor, Color); } private static bool IsCompressedTextureFormat(GalImageFormat Format) diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs index c22a282dcc..9dd6cb91d2 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs @@ -63,6 +63,8 @@ namespace Ryujinx.Graphics.Gal.Shader private Dictionary m_Gprs; private Dictionary m_Preds; + private Dictionary m_TextureTypes; + public IReadOnlyDictionary CbTextures => m_CbTextures; public IReadOnlyDictionary Textures => m_Textures; @@ -75,6 +77,8 @@ namespace Ryujinx.Graphics.Gal.Shader public IReadOnlyDictionary Gprs => m_Gprs; public IReadOnlyDictionary Preds => m_Preds; + public IReadOnlyDictionary TextureTypes => m_TextureTypes; + public GalShaderType ShaderType { get; private set; } private GlslDecl(GalShaderType ShaderType) @@ -92,6 +96,8 @@ namespace Ryujinx.Graphics.Gal.Shader m_Gprs = new Dictionary(); m_Preds = new Dictionary(); + + m_TextureTypes = new Dictionary(); } public GlslDecl(ShaderIrBlock[] Blocks, GalShaderType ShaderType, ShaderHeader Header) @@ -221,16 +227,26 @@ namespace Ryujinx.Graphics.Gal.Shader Op.Inst == ShaderIrInst.Texs || Op.Inst == ShaderIrInst.Txlf) { - int Handle = ((ShaderIrOperImm)Op.OperandC).Value; + ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + + Traverse(Nodes, Op, Meta.Index); + + int Handle = ((ShaderIrOperImm)Meta.Index).Value; int Index = Handle - TexStartIndex; string Name = StagePrefix + TextureName + Index; m_Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Handle)); + + m_TextureTypes.TryAdd(Handle, Meta.Type); } else if (Op.Inst == ShaderIrInst.Texb) { + ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + + Traverse(Nodes, Op, Meta.Index); + ShaderIrNode HandleSrc = null; int Index = Array.IndexOf(Nodes, Parent) - 1; @@ -241,7 +257,7 @@ namespace Ryujinx.Graphics.Gal.Shader if (Curr is ShaderIrAsg Asg && Asg.Dst is ShaderIrOperGpr Gpr) { - if (Gpr.Index == ((ShaderIrOperGpr)Op.OperandC).Index) + if (Gpr.Index == ((ShaderIrOperGpr)Meta.Index).Index) { HandleSrc = Asg.Src; @@ -255,6 +271,8 @@ namespace Ryujinx.Graphics.Gal.Shader string Name = StagePrefix + TextureName + "_cb" + Cbuf.Index + "_" + Cbuf.Pos; m_CbTextures.Add(Op, new ShaderDeclInfo(Name, Cbuf.Pos, true, Cbuf.Index)); + + //TODO: Add m_CbTextures to texture types } else { diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index 984684f16b..75ece0f2e8 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -145,8 +145,6 @@ namespace Ryujinx.Graphics.Gal.Shader { SB = new StringBuilder(); - SB.AppendLine("#version 410 core"); - PrintDeclHeader(); PrintDeclTextures(); PrintDeclUniforms(); @@ -185,6 +183,8 @@ namespace Ryujinx.Graphics.Gal.Shader private void PrintDeclHeader() { + SB.AppendLine("#version 410 core"); + if (Decl.ShaderType == GalShaderType.Geometry) { int MaxVertices = Header.MaxOutputVertexCount; @@ -209,9 +209,9 @@ namespace Ryujinx.Graphics.Gal.Shader SB.AppendLine("layout(triangles) in;" + Environment.NewLine); SB.AppendLine($"layout({OutputTopology}, max_vertices = {MaxVertices}) out;"); - - SB.AppendLine(); } + + SB.AppendLine(); } private void PrintDeclTextures() @@ -221,7 +221,16 @@ namespace Ryujinx.Graphics.Gal.Shader SB.AppendLine("uniform sampler2D " + DeclInfo.Name + ";"); } - PrintDecls(Decl.Textures, "uniform sampler2D"); + foreach (ShaderDeclInfo DeclInfo in Decl.Textures.Values.OrderBy(DeclKeySelector)) + { + ShaderTextureType Type = Decl.TextureTypes[DeclInfo.Index]; + + string TypeName = GetSamplerName(Type); + + SB.AppendLine("uniform " + TypeName + " " + DeclInfo.Name + ";"); + } + + SB.AppendLine(); } private IEnumerable IterateCbTextures() @@ -250,11 +259,9 @@ namespace Ryujinx.Graphics.Gal.Shader SB.AppendLine(IdentationStr + "int " + GlslDecl.InstanceUniformName + ";"); - SB.AppendLine("};"); + SB.AppendLine("};" + Environment.NewLine); } - SB.AppendLine(); - foreach (ShaderDeclInfo DeclInfo in Decl.Uniforms.Values.OrderBy(DeclKeySelector)) { SB.AppendLine($"layout (std140) uniform {DeclInfo.Name} {{"); @@ -1188,9 +1195,9 @@ namespace Ryujinx.Graphics.Gal.Shader private string GetTexSamplerName(ShaderIrOp Op) { - ShaderIrOperImm Node = (ShaderIrOperImm)Op.OperandC; + ShaderIrNode Node = ((ShaderIrMetaTex)Op.MetaData).Index; - int Handle = ((ShaderIrOperImm)Op.OperandC).Value; + int Handle = ((ShaderIrOperImm)Node).Value; if (!Decl.Textures.TryGetValue(Handle, out ShaderDeclInfo DeclInfo)) { @@ -1202,14 +1209,40 @@ namespace Ryujinx.Graphics.Gal.Shader private string GetTexSamplerCoords(ShaderIrOp Op) { - return "vec2(" + GetOperExpr(Op, Op.OperandA) + ", " + - GetOperExpr(Op, Op.OperandB) + ")"; + if (Op.OperandC != null) + { + return "vec3(" + GetOperExpr(Op, Op.OperandA) + ", " + + GetOperExpr(Op, Op.OperandB) + ", " + + GetOperExpr(Op, Op.OperandC) + ")"; + } + else if (Op.OperandB != null) + { + return "vec2(" + GetOperExpr(Op, Op.OperandA) + ", " + + GetOperExpr(Op, Op.OperandB) + ")"; + } + else + { + return GetOperExpr(Op, Op.OperandA); + } } private string GetITexSamplerCoords(ShaderIrOp Op) { - return "ivec2(" + GetOperExpr(Op, Op.OperandA) + ", " + - GetOperExpr(Op, Op.OperandB) + ")"; + if (Op.OperandC != null) + { + return "ivec3(" + GetOperExpr(Op, Op.OperandA) + ", " + + GetOperExpr(Op, Op.OperandB) + ", " + + GetOperExpr(Op, Op.OperandC) + ")"; + } + else if (Op.OperandB != null) + { + return "ivec2(" + GetOperExpr(Op, Op.OperandA) + ", " + + GetOperExpr(Op, Op.OperandB) + ")"; + } + else + { + return GetOperExpr(Op, Op.OperandA); + } } private string GetOperExpr(ShaderIrOp Op, ShaderIrNode Oper) @@ -1351,5 +1384,19 @@ namespace Ryujinx.Graphics.Gal.Shader throw new ArgumentException(nameof(Node)); } + + private static string GetSamplerName(ShaderTextureType Type) + { + switch (Type) + { + case ShaderTextureType._1d: return "sampler1D"; + case ShaderTextureType._2d: return "sampler2D"; + case ShaderTextureType._2dArray: return "sampler2DArray"; + case ShaderTextureType._3d: return "sampler3D"; + case ShaderTextureType.Cube: return "samplerCube"; + } + + throw new NotImplementedException(Type.ToString()); + } } } diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs index a183b0c69a..4fbda458d2 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs @@ -31,13 +31,38 @@ namespace Ryujinx.Graphics.Gal.Shader { RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ } }; + private static ShaderTextureType[,] TexTypes = new ShaderTextureType[,] + { + { ShaderTextureType._1d, ShaderTextureType._1dArray }, + { ShaderTextureType._2d, ShaderTextureType._2dArray }, + { ShaderTextureType._3d, ShaderTextureType.Invalid }, + { ShaderTextureType.Cube, ShaderTextureType.Invalid } + }; + + private static int[] TexTypeCoords = new int[] { 1, 2, 3, 3 }; + + private static ShaderTextureType[] TexsTypes = new ShaderTextureType[] + { + ShaderTextureType._1d, + ShaderTextureType._2d, + ShaderTextureType._2d, + ShaderTextureType._2d, + ShaderTextureType._2d, + ShaderTextureType._2d, + ShaderTextureType._2d, + ShaderTextureType._2dArray, + ShaderTextureType._2dArray, + ShaderTextureType._2dArray, + ShaderTextureType._3d, + ShaderTextureType._3d, + ShaderTextureType.Cube, + ShaderTextureType.Cube, + }; + public static void Ld_A(ShaderIrBlock Block, long OpCode) { ShaderIrNode[] Opers = GetOperAbuf20(OpCode); - //Used by GS - ShaderIrOperGpr Vertex = GetOperGpr39(OpCode); - int Index = 0; foreach (ShaderIrNode OperA in Opers) @@ -118,15 +143,15 @@ namespace Ryujinx.Graphics.Gal.Shader ShaderIrNode OperD = GetOperGpr0(OpCode); ShaderIrNode OperA = GetOperGpr8(OpCode); + ShaderIrNode TextureIndex = GetOperImm13_36(OpCode); + ShaderTexqInfo Info = (ShaderTexqInfo)((OpCode >> 22) & 0x1f); - ShaderIrMetaTexq Meta0 = new ShaderIrMetaTexq(Info, 0); - ShaderIrMetaTexq Meta1 = new ShaderIrMetaTexq(Info, 1); + ShaderIrMetaTexq Meta0 = new ShaderIrMetaTexq(Info, ShaderTextureType._2d, TextureIndex, 0); + ShaderIrMetaTexq Meta1 = new ShaderIrMetaTexq(Info, ShaderTextureType._2d, TextureIndex, 1); - ShaderIrNode OperC = GetOperImm13_36(OpCode); - - ShaderIrOp Op0 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta0); - ShaderIrOp Op1 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta1); + ShaderIrOp Op0 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, null, Meta0); + ShaderIrOp Op1 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, null, Meta1); Block.AddNode(GetPredNode(new ShaderIrAsg(OperD, Op0), OpCode)); Block.AddNode(GetPredNode(new ShaderIrAsg(OperA, Op1), OpCode)); //Is this right? @@ -144,14 +169,22 @@ namespace Ryujinx.Graphics.Gal.Shader private static void EmitTex(ShaderIrBlock Block, long OpCode, bool GprHandle) { - //TODO: Support other formats. - ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[2]; + bool IsArray = ((OpCode >> 28) & 1) != 0; - for (int Index = 0; Index < Coords.Length; Index++) + int TypeId = (int)((OpCode >> 29) & 3); + + ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[3]; + + ShaderTextureType Type = TexTypes[TypeId, IsArray ? 1 : 0]; + + if (Type == ShaderTextureType.Invalid) { - Coords[Index] = GetOperGpr8(OpCode); + throw new InvalidOperationException(); + } - Coords[Index].Index += Index; + for (int Index = 0; Index < TexTypeCoords[TypeId] + (IsArray ? 1 : 0); Index++) + { + Coords[Index] = GetOperGpr8(OpCode) + Index; if (Coords[Index].Index > ShaderIrOperGpr.ZRIndex) { @@ -161,7 +194,7 @@ namespace Ryujinx.Graphics.Gal.Shader int ChMask = (int)(OpCode >> 31) & 0xf; - ShaderIrNode OperC = GprHandle + ShaderIrNode TextureIndex = GprHandle ? (ShaderIrNode)GetOperGpr20 (OpCode) : (ShaderIrNode)GetOperImm13_36(OpCode); @@ -171,9 +204,9 @@ namespace Ryujinx.Graphics.Gal.Shader { ShaderIrOperGpr Dst = new ShaderIrOperGpr(TempRegStart + Ch); - ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch); + ShaderIrMetaTex Meta = new ShaderIrMetaTex(Type, TextureIndex, Ch); - ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords[1], OperC, Meta); + ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords[1], Coords[2], Meta); Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Op), OpCode)); } @@ -214,10 +247,7 @@ namespace Ryujinx.Graphics.Gal.Shader private static void EmitTexs(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst) { - //TODO: Support other formats. - ShaderIrNode OperA = GetOperGpr8 (OpCode); - ShaderIrNode OperB = GetOperGpr20 (OpCode); - ShaderIrNode OperC = GetOperImm13_36(OpCode); + ShaderIrNode TextureIndex = GetOperImm13_36(OpCode); int LutIndex; @@ -233,11 +263,50 @@ namespace Ryujinx.Graphics.Gal.Shader int ChMask = MaskLut[LutIndex, (OpCode >> 50) & 7]; + long TypeIndex = (OpCode >> 53) & 0xf; + + ShaderTextureType Type = TexsTypes[TypeIndex]; + + ShaderIrNode OperA = null; + ShaderIrNode OperB = null; + ShaderIrNode OperC = null; + + switch (Type) + { + case ShaderTextureType._2d: + OperA = GetOperGpr8 (OpCode); + OperB = GetOperGpr20(OpCode); + break; + + case ShaderTextureType._2dArray: + OperA = GetOperGpr8 (OpCode) + 1; + OperB = GetOperGpr20(OpCode); + OperC = GetOperGpr8 (OpCode); + break; + + //This layout is copy-pasted, complitely untested + case ShaderTextureType._3d: + OperA = GetOperGpr8(OpCode) + 1; + OperB = GetOperGpr20(OpCode); + OperC = GetOperGpr8(OpCode); + break; + + //Unsure about this layout + case ShaderTextureType.Cube: + OperA = GetOperGpr8 (OpCode); + OperB = GetOperGpr8 (OpCode) + 1; + OperC = GetOperGpr20(OpCode); + break; + + default: + throw new NotImplementedException(Type.ToString()); + } + for (int Ch = 0; Ch < 4; Ch++) { ShaderIrOperGpr Dst = new ShaderIrOperGpr(TempRegStart + Ch); - ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch); + ShaderIrMetaTex Meta = new ShaderIrMetaTex(Type, TextureIndex, Ch); ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta); diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs index 82f3bb774a..3ff8ab39e0 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs @@ -2,11 +2,17 @@ namespace Ryujinx.Graphics.Gal.Shader { class ShaderIrMetaTex : ShaderIrMeta { + public ShaderTextureType Type { get; private set; } + + public ShaderIrNode Index { get; private set; } + public int Elem { get; private set; } - public ShaderIrMetaTex(int Elem) + public ShaderIrMetaTex(ShaderTextureType Type, ShaderIrNode Index, int Elem) { - this.Elem = Elem; + this.Type = Type; + this.Index = Index; + this.Elem = Elem; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs index 92871137f6..db6e8f11db 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs @@ -1,15 +1,13 @@ namespace Ryujinx.Graphics.Gal.Shader { - class ShaderIrMetaTexq : ShaderIrMeta + class ShaderIrMetaTexq : ShaderIrMetaTex { public ShaderTexqInfo Info { get; private set; } - public int Elem { get; private set; } - - public ShaderIrMetaTexq(ShaderTexqInfo Info, int Elem) + public ShaderIrMetaTexq(ShaderTexqInfo Info, ShaderTextureType Type, ShaderIrNode Index, int Elem) + : base(Type, Index, Elem) { this.Info = Info; - this.Elem = Elem; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs index 9dd196e693..eddcf9fb4b 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs @@ -15,6 +15,11 @@ namespace Ryujinx.Graphics.Gal.Shader this.Index = Index; } + public static ShaderIrOperGpr operator+(ShaderIrOperGpr Gpr, int PlusIndex) + { + return new ShaderIrOperGpr(Gpr.Index + PlusIndex); + } + public static ShaderIrOperGpr MakeTemporary(int Index = 0) { return new ShaderIrOperGpr(0x100 + Index); diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderTextureType.cs b/Ryujinx.Graphics/Gal/Shader/ShaderTextureType.cs new file mode 100644 index 0000000000..81059e7e41 --- /dev/null +++ b/Ryujinx.Graphics/Gal/Shader/ShaderTextureType.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Graphics.Gal.Shader +{ + enum ShaderTextureType + { + Invalid, + _1d, + _1dArray, + _2d, + _2dArray, + _3d, + Cube + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs index 2010e43bd2..fd6578d15d 100644 --- a/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs +++ b/Ryujinx.HLE/Gpu/Engines/NvGpuEngine3d.cs @@ -202,7 +202,7 @@ namespace Ryujinx.HLE.Gpu.Engines GalImageFormat ImageFormat = ImageFormatConverter.ConvertFrameBuffer((GalFrameBufferFormat)Format); - GalImage Image = new GalImage(Width, Height, ImageFormat); + GalImage Image = new GalImage(Width, Height, 1, ImageFormat, GalImageTarget._2d); long Size = TextureHelper.GetTextureSize(Image); @@ -234,7 +234,7 @@ namespace Ryujinx.HLE.Gpu.Engines GalImageFormat ImageFormat = ImageFormatConverter.ConvertZeta((GalZetaFormat)Format); - GalImage Image = new GalImage(Width, Height, ImageFormat); + GalImage Image = new GalImage(Width, Height, 1, ImageFormat, GalImageTarget._2d); long Size = TextureHelper.GetTextureSize(Image); @@ -509,47 +509,32 @@ namespace Ryujinx.HLE.Gpu.Engines if (Key == -1) { - //FIXME: Should'nt ignore invalid addresses. + //FIXME: Shouldn't ignore invalid addresses. return; } - if (IsFrameBufferPosition(Key)) - { - //This texture is a frame buffer texture, - //we shouldn't read anything from memory and bind - //the frame buffer texture instead, since we're not - //really writing anything to memory. - Gpu.Renderer.FrameBuffer.BindTexture(Key, TexIndex); - } - else + //If a texture is a rendertarget texture, + //we shouldn't read anything from memory and just bind it + + if (!IsFrameBufferPosition(Key)) { GalImage NewImage = TextureFactory.MakeTexture(Vmm, TicPosition); long Size = (uint)TextureHelper.GetTextureSize(NewImage); - bool HasCachedTexture = false; + bool Exists = Gpu.Renderer.Texture.TryGetCachedTexture(Key, Size, out GalImage Image); - if (Gpu.Renderer.Texture.TryGetCachedTexture(Key, Size, out GalImage Image)) - { - if (NewImage.Equals(Image) && !QueryKeyUpload(Vmm, Key, Size, NvGpuBufferType.Texture)) - { - Gpu.Renderer.Texture.Bind(Key, TexIndex); - - HasCachedTexture = true; - } - } - - if (!HasCachedTexture) + if (!Exists || + !NewImage.Equals(Image) || + QueryKeyUpload(Vmm, Key, Size, NvGpuBufferType.Texture)) { byte[] Data = TextureFactory.GetTextureData(Vmm, TicPosition); Gpu.Renderer.Texture.Create(Key, Data, NewImage); } - - Gpu.Renderer.Texture.Bind(Key, TexIndex); } - Gpu.Renderer.Texture.SetSampler(Sampler); + Gpu.Renderer.Texture.Bind(Key, TexIndex, Sampler); } private void UploadConstBuffers(NvGpuVmm Vmm, GalPipelineState State, long[] Keys) diff --git a/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs b/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs index 0ef33d3b72..2aad803a70 100644 --- a/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs +++ b/Ryujinx.HLE/Gpu/Texture/TextureFactory.cs @@ -24,11 +24,16 @@ namespace Ryujinx.HLE.Gpu.Texture int Width = (Tic[4] & 0xffff) + 1; int Height = (Tic[5] & 0xffff) + 1; + int Depth = ((Tic[5] >> 16) & 0x7fff) + 1; + + GalImageTarget Target = (GalImageTarget)((Tic[4] >> 23) & 0xf); return new GalImage( Width, Height, + Depth, Format, + Target, XSource, YSource, ZSource,