Quellcode durchsuchen

Fix TXQ for 3D textures. (#2613)

* Fix TXQ for 3D textures.

Assumes the texture is 3D if the component mask contains Z.

This fixes a bug in UE4 games where parts of the map had garbage pointers to lighting voxels, as the lookup 3D texture was not being initialized. Most notable game is THPS1+2.

May need another PR to keep image store data alive and properly flush it in order using the AutoDeleteCache.

* Get sampler type for TextureSize from bound textures.
riperiperi vor 4 Jahren
Ursprung
Commit
f0b00c1ae9

+ 23 - 0
Ryujinx.Graphics.Gpu/Image/TextureTarget.cs

@@ -1,4 +1,5 @@
 using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Shader;
 
 namespace Ryujinx.Graphics.Gpu.Image
 {
@@ -54,5 +55,27 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             return Target.Texture1D;
         }
+
+        /// <summary>
+        /// Converts the texture target enum to a shader sampler type.
+        /// </summary>
+        /// <param name="target">The target enum to convert</param>
+        /// <returns>The shader sampler type</returns>
+        public static SamplerType ConvertSamplerType(this TextureTarget target)
+        {
+            return target switch
+            {
+                TextureTarget.Texture1D      => SamplerType.Texture1D,
+                TextureTarget.Texture2D      => SamplerType.Texture2D,
+                TextureTarget.Texture3D      => SamplerType.Texture3D,
+                TextureTarget.Cubemap        => SamplerType.TextureCube,
+                TextureTarget.Texture1DArray => SamplerType.Texture1D | SamplerType.Array,
+                TextureTarget.Texture2DArray => SamplerType.Texture2D | SamplerType.Array,
+                TextureTarget.TextureBuffer  => SamplerType.TextureBuffer,
+                TextureTarget.Texture2DRect  => SamplerType.Texture2D,
+                TextureTarget.CubemapArray   => SamplerType.TextureCube | SamplerType.Array,
+                _                            => SamplerType.Texture2D
+            };
+        }
     }
 }

+ 1 - 1
Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs

@@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
         /// <summary>
         /// Version of the codegen (to be changed when codegen or guest format change).
         /// </summary>
-        private const ulong ShaderCodeGenVersion = 2092;
+        private const ulong ShaderCodeGenVersion = 2613;
 
         // Progress reporting helpers
         private volatile int _shaderCount;

+ 4 - 4
Ryujinx.Graphics.Gpu/Shader/TextureDescriptorCapableGpuAccessor.cs

@@ -119,14 +119,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
         }
 
         /// <summary>
-        /// Queries texture target information.
+        /// Queries sampler type information.
         /// </summary>
         /// <param name="handle">Texture handle</param>
         /// <param name="cbufSlot">Constant buffer slot for the texture handle</param>
-        /// <returns>True if the texture is a buffer texture, false otherwise</returns>
-        public bool QueryIsTextureBuffer(int handle, int cbufSlot = -1)
+        /// <returns>The sampler type value for the given handle</returns>
+        public SamplerType QuerySamplerType(int handle, int cbufSlot = -1)
         {
-            return GetTextureDescriptor(handle, cbufSlot).UnpackTextureTarget() == TextureTarget.TextureBuffer;
+            return GetTextureDescriptor(handle, cbufSlot).UnpackTextureTarget().ConvertSamplerType();
         }
 
         /// <summary>

+ 5 - 3
Ryujinx.Graphics.Shader/IGpuAccessor.cs

@@ -1,4 +1,6 @@
-namespace Ryujinx.Graphics.Shader
+using Ryujinx.Graphics.Shader.Decoders;
+
+namespace Ryujinx.Graphics.Shader
 {
     public interface IGpuAccessor
     {
@@ -79,9 +81,9 @@
             return true;
         }
 
-        bool QueryIsTextureBuffer(int handle, int cbufSlot = -1)
+        SamplerType QuerySamplerType(int handle, int cbufSlot = -1)
         {
-            return false;
+            return SamplerType.Texture2D;
         }
 
         bool QueryIsTextureRectangle(int handle, int cbufSlot = -1)

+ 13 - 4
Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs

@@ -697,7 +697,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
 
                 flags = ConvertTextureFlags(tldsOp.Target) | TextureFlags.IntCoords;
 
-                if (tldsOp.Target == TexelLoadTarget.Texture1DLodZero && context.Config.GpuAccessor.QueryIsTextureBuffer(tldsOp.HandleOffset))
+                if (tldsOp.Target == TexelLoadTarget.Texture1DLodZero && context.Config.GpuAccessor.QuerySamplerType(tldsOp.HandleOffset) == SamplerType.TextureBuffer)
                 {
                     type   = SamplerType.TextureBuffer;
                     flags &= ~TextureFlags.LodLevel;
@@ -1306,8 +1306,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
             // TODO: Validate and use property.
             Instruction inst = Instruction.TextureSize;
 
-            SamplerType type = SamplerType.Texture2D;
-
             TextureFlags flags = bindless ? TextureFlags.Bindless : TextureFlags.None;
 
             int raIndex = op.Ra.Index;
@@ -1347,6 +1345,17 @@ namespace Ryujinx.Graphics.Shader.Instructions
 
             int handle = !bindless ? op.HandleOffset : 0;
 
+            SamplerType type;
+
+            if (bindless)
+            {
+                type = (op.ComponentMask & 4) != 0 ? SamplerType.Texture3D : SamplerType.Texture2D;
+            } 
+            else
+            {
+                type = context.Config.GpuAccessor.QuerySamplerType(handle);
+            }
+
             for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
             {
                 if ((compMask & 1) != 0)
@@ -1422,7 +1431,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
             {
                 // For bindless, we don't have any way to know the texture type,
                 // so we assume it's texture buffer when the sampler type is 1D, since that's more common.
-                bool isTypeBuffer = isBindless || context.Config.GpuAccessor.QueryIsTextureBuffer(op.HandleOffset);
+                bool isTypeBuffer = isBindless || context.Config.GpuAccessor.QuerySamplerType(op.HandleOffset) == SamplerType.TextureBuffer;
 
                 if (isTypeBuffer)
                 {

+ 1 - 1
Ryujinx.Graphics.Shader/IntermediateRepresentation/TextureOperation.cs

@@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
     {
         public const int DefaultCbufSlot = -1;
 
-        public SamplerType Type { get; private set; }
+        public SamplerType Type { get; set; }
         public TextureFormat Format { get; set; }
         public TextureFlags Flags { get; private set; }
 

+ 12 - 4
Ryujinx.Graphics.Shader/Translation/Optimizations/BindlessElimination.cs

@@ -30,10 +30,11 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
                     texOp.Inst == Instruction.TextureSize)
                 {
                     Operand bindlessHandle = Utils.FindLastOperation(texOp.GetSource(0), block);
+                    bool rewriteSamplerType = texOp.Inst == Instruction.TextureSize;
 
                     if (bindlessHandle.Type == OperandType.ConstantBuffer)
                     {
-                        SetHandle(config, texOp, bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot());
+                        SetHandle(config, texOp, bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot(), rewriteSamplerType);
                         continue;
                     }
 
@@ -59,7 +60,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
                         config,
                         texOp,
                         src0.GetCbufOffset() | ((src1.GetCbufOffset() + 1) << 16),
-                        src0.GetCbufSlot() | ((src1.GetCbufSlot() + 1) << 16));
+                        src0.GetCbufSlot() | ((src1.GetCbufSlot() + 1) << 16),
+                        rewriteSamplerType);
                 }
                 else if (texOp.Inst == Instruction.ImageLoad ||
                          texOp.Inst == Instruction.ImageStore ||
@@ -81,15 +83,21 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
                             texOp.Format = config.GetTextureFormat(cbufOffset, cbufSlot);
                         }
 
-                        SetHandle(config, texOp, cbufOffset, cbufSlot);
+                        SetHandle(config, texOp, cbufOffset, cbufSlot, false);
                     }
                 }
             }
         }
 
-        private static void SetHandle(ShaderConfig config, TextureOperation texOp, int cbufOffset, int cbufSlot)
+        private static void SetHandle(ShaderConfig config, TextureOperation texOp, int cbufOffset, int cbufSlot, bool rewriteSamplerType)
         {
             texOp.SetHandle(cbufOffset, cbufSlot);
+            
+            if (rewriteSamplerType)
+            {
+                texOp.Type = config.GpuAccessor.QuerySamplerType(cbufOffset, cbufSlot);
+            }
+
             config.SetUsedTexture(texOp.Inst, texOp.Type, texOp.Format, texOp.Flags, cbufSlot, cbufOffset);
         }
     }

+ 1 - 1
Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs

@@ -294,7 +294,7 @@ namespace Ryujinx.Graphics.Shader.Translation
             inst &= Instruction.Mask;
             bool isImage = inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
             bool isWrite = inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
-            bool accurateType = inst != Instruction.TextureSize && inst != Instruction.Lod;
+            bool accurateType = inst != Instruction.Lod;
 
             if (isImage)
             {