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.
This commit is contained in:
parent
142cededd4
commit
f0b00c1ae9
8 changed files with 60 additions and 18 deletions
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
|
using Ryujinx.Graphics.Shader;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Image
|
namespace Ryujinx.Graphics.Gpu.Image
|
||||||
{
|
{
|
||||||
|
@ -54,5 +55,27 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
return Target.Texture1D;
|
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
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version of the codegen (to be changed when codegen or guest format change).
|
/// Version of the codegen (to be changed when codegen or guest format change).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const ulong ShaderCodeGenVersion = 2092;
|
private const ulong ShaderCodeGenVersion = 2613;
|
||||||
|
|
||||||
// Progress reporting helpers
|
// Progress reporting helpers
|
||||||
private volatile int _shaderCount;
|
private volatile int _shaderCount;
|
||||||
|
|
|
@ -119,14 +119,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries texture target information.
|
/// Queries sampler type information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="handle">Texture handle</param>
|
/// <param name="handle">Texture handle</param>
|
||||||
/// <param name="cbufSlot">Constant buffer slot for the 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>
|
/// <returns>The sampler type value for the given handle</returns>
|
||||||
public bool QueryIsTextureBuffer(int handle, int cbufSlot = -1)
|
public SamplerType QuerySamplerType(int handle, int cbufSlot = -1)
|
||||||
{
|
{
|
||||||
return GetTextureDescriptor(handle, cbufSlot).UnpackTextureTarget() == TextureTarget.TextureBuffer;
|
return GetTextureDescriptor(handle, cbufSlot).UnpackTextureTarget().ConvertSamplerType();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
namespace Ryujinx.Graphics.Shader
|
using Ryujinx.Graphics.Shader.Decoders;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Shader
|
||||||
{
|
{
|
||||||
public interface IGpuAccessor
|
public interface IGpuAccessor
|
||||||
{
|
{
|
||||||
|
@ -79,9 +81,9 @@
|
||||||
return true;
|
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)
|
bool QueryIsTextureRectangle(int handle, int cbufSlot = -1)
|
||||||
|
|
|
@ -697,7 +697,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
flags = ConvertTextureFlags(tldsOp.Target) | TextureFlags.IntCoords;
|
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;
|
type = SamplerType.TextureBuffer;
|
||||||
flags &= ~TextureFlags.LodLevel;
|
flags &= ~TextureFlags.LodLevel;
|
||||||
|
@ -1306,8 +1306,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
// TODO: Validate and use property.
|
// TODO: Validate and use property.
|
||||||
Instruction inst = Instruction.TextureSize;
|
Instruction inst = Instruction.TextureSize;
|
||||||
|
|
||||||
SamplerType type = SamplerType.Texture2D;
|
|
||||||
|
|
||||||
TextureFlags flags = bindless ? TextureFlags.Bindless : TextureFlags.None;
|
TextureFlags flags = bindless ? TextureFlags.Bindless : TextureFlags.None;
|
||||||
|
|
||||||
int raIndex = op.Ra.Index;
|
int raIndex = op.Ra.Index;
|
||||||
|
@ -1347,6 +1345,17 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
int handle = !bindless ? op.HandleOffset : 0;
|
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++)
|
for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
|
||||||
{
|
{
|
||||||
if ((compMask & 1) != 0)
|
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,
|
// 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.
|
// 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)
|
if (isTypeBuffer)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||||
{
|
{
|
||||||
public const int DefaultCbufSlot = -1;
|
public const int DefaultCbufSlot = -1;
|
||||||
|
|
||||||
public SamplerType Type { get; private set; }
|
public SamplerType Type { get; set; }
|
||||||
public TextureFormat Format { get; set; }
|
public TextureFormat Format { get; set; }
|
||||||
public TextureFlags Flags { get; private set; }
|
public TextureFlags Flags { get; private set; }
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,11 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
texOp.Inst == Instruction.TextureSize)
|
texOp.Inst == Instruction.TextureSize)
|
||||||
{
|
{
|
||||||
Operand bindlessHandle = Utils.FindLastOperation(texOp.GetSource(0), block);
|
Operand bindlessHandle = Utils.FindLastOperation(texOp.GetSource(0), block);
|
||||||
|
bool rewriteSamplerType = texOp.Inst == Instruction.TextureSize;
|
||||||
|
|
||||||
if (bindlessHandle.Type == OperandType.ConstantBuffer)
|
if (bindlessHandle.Type == OperandType.ConstantBuffer)
|
||||||
{
|
{
|
||||||
SetHandle(config, texOp, bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot());
|
SetHandle(config, texOp, bindlessHandle.GetCbufOffset(), bindlessHandle.GetCbufSlot(), rewriteSamplerType);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +60,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
config,
|
config,
|
||||||
texOp,
|
texOp,
|
||||||
src0.GetCbufOffset() | ((src1.GetCbufOffset() + 1) << 16),
|
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 ||
|
else if (texOp.Inst == Instruction.ImageLoad ||
|
||||||
texOp.Inst == Instruction.ImageStore ||
|
texOp.Inst == Instruction.ImageStore ||
|
||||||
|
@ -81,15 +83,21 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
texOp.Format = config.GetTextureFormat(cbufOffset, cbufSlot);
|
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);
|
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);
|
config.SetUsedTexture(texOp.Inst, texOp.Type, texOp.Format, texOp.Flags, cbufSlot, cbufOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -294,7 +294,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
inst &= Instruction.Mask;
|
inst &= Instruction.Mask;
|
||||||
bool isImage = inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
|
bool isImage = inst == Instruction.ImageLoad || inst == Instruction.ImageStore || inst == Instruction.ImageAtomic;
|
||||||
bool isWrite = 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)
|
if (isImage)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue