Implement textureSamples texture query shader instruction (#5750)

* Implement textureSamples texture query shader instruction

* Shader cache version bump
This commit is contained in:
gdkchan 2023-10-03 19:43:11 -03:00 committed by GitHub
parent 8b2625b0be
commit a2a97e1b11
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 186 additions and 58 deletions

View file

@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2; private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 5682; private const uint CodeGenVersion = 5750;
private const string SharedTocFileName = "shared.toc"; private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data"; private const string SharedDataFileName = "shared.data";

View file

@ -184,8 +184,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
case Instruction.TextureSample: case Instruction.TextureSample:
return TextureSample(context, operation); return TextureSample(context, operation);
case Instruction.TextureSize: case Instruction.TextureQuerySamples:
return TextureSize(context, operation); return TextureQuerySamples(context, operation);
case Instruction.TextureQuerySize:
return TextureQuerySize(context, operation);
case Instruction.UnpackDouble2x32: case Instruction.UnpackDouble2x32:
return UnpackDouble2x32(context, operation); return UnpackDouble2x32(context, operation);

View file

@ -118,7 +118,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
Add(Instruction.Subtract, InstType.OpBinary, "-", 2); Add(Instruction.Subtract, InstType.OpBinary, "-", 2);
Add(Instruction.SwizzleAdd, InstType.CallTernary, HelperFunctionNames.SwizzleAdd); Add(Instruction.SwizzleAdd, InstType.CallTernary, HelperFunctionNames.SwizzleAdd);
Add(Instruction.TextureSample, InstType.Special); Add(Instruction.TextureSample, InstType.Special);
Add(Instruction.TextureSize, InstType.Special); Add(Instruction.TextureQuerySamples, InstType.Special);
Add(Instruction.TextureQuerySize, InstType.Special);
Add(Instruction.Truncate, InstType.CallUnary, "trunc"); Add(Instruction.Truncate, InstType.CallUnary, "trunc");
Add(Instruction.UnpackDouble2x32, InstType.Special); Add(Instruction.UnpackDouble2x32, InstType.Special);
Add(Instruction.UnpackHalf2x16, InstType.Special); Add(Instruction.UnpackHalf2x16, InstType.Special);

View file

@ -517,7 +517,33 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
return texCall; return texCall;
} }
public static string TextureSize(CodeGenContext context, AstOperation operation) public static string TextureQuerySamples(CodeGenContext context, AstOperation operation)
{
AstTextureOperation texOp = (AstTextureOperation)operation;
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
// TODO: Bindless texture support. For now we just return 0.
if (isBindless)
{
return NumberFormatter.FormatInt(0);
}
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
string indexExpr = null;
if (isIndexed)
{
indexExpr = GetSoureExpr(context, texOp.GetSource(0), AggregateType.S32);
}
string samplerName = GetSamplerName(context.Properties, texOp, indexExpr);
return $"textureSamples({samplerName})";
}
public static string TextureQuerySize(CodeGenContext context, AstOperation operation)
{ {
AstTextureOperation texOp = (AstTextureOperation)operation; AstTextureOperation texOp = (AstTextureOperation)operation;

View file

@ -134,7 +134,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
Add(Instruction.Subtract, GenerateSubtract); Add(Instruction.Subtract, GenerateSubtract);
Add(Instruction.SwizzleAdd, GenerateSwizzleAdd); Add(Instruction.SwizzleAdd, GenerateSwizzleAdd);
Add(Instruction.TextureSample, GenerateTextureSample); Add(Instruction.TextureSample, GenerateTextureSample);
Add(Instruction.TextureSize, GenerateTextureSize); Add(Instruction.TextureQuerySamples, GenerateTextureQuerySamples);
Add(Instruction.TextureQuerySize, GenerateTextureQuerySize);
Add(Instruction.Truncate, GenerateTruncate); Add(Instruction.Truncate, GenerateTruncate);
Add(Instruction.UnpackDouble2x32, GenerateUnpackDouble2x32); Add(Instruction.UnpackDouble2x32, GenerateUnpackDouble2x32);
Add(Instruction.UnpackHalf2x16, GenerateUnpackHalf2x16); Add(Instruction.UnpackHalf2x16, GenerateUnpackHalf2x16);
@ -1492,7 +1493,36 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
return new OperationResult(swizzledResultType, result); return new OperationResult(swizzledResultType, result);
} }
private static OperationResult GenerateTextureSize(CodeGenContext context, AstOperation operation) private static OperationResult GenerateTextureQuerySamples(CodeGenContext context, AstOperation operation)
{
AstTextureOperation texOp = (AstTextureOperation)operation;
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
// TODO: Bindless texture support. For now we just return 0.
if (isBindless)
{
return new OperationResult(AggregateType.S32, context.Constant(context.TypeS32(), 0));
}
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
if (isIndexed)
{
context.GetS32(texOp.GetSource(0));
}
(var imageType, var sampledImageType, var sampledImageVariable) = context.Samplers[texOp.Binding];
var image = context.Load(sampledImageType, sampledImageVariable);
image = context.Image(imageType, image);
SpvInstruction result = context.ImageQuerySamples(context.TypeS32(), image);
return new OperationResult(AggregateType.S32, result);
}
private static OperationResult GenerateTextureQuerySize(CodeGenContext context, AstOperation operation)
{ {
AstTextureOperation texOp = (AstTextureOperation)operation; AstTextureOperation texOp = (AstTextureOperation)operation;

View file

@ -1094,7 +1094,14 @@ namespace Ryujinx.Graphics.Shader.Instructions
if (isBindless) if (isBindless)
{ {
type = (componentMask & 4) != 0 ? SamplerType.Texture3D : SamplerType.Texture2D; if (query == TexQuery.TexHeaderTextureType)
{
type = SamplerType.Texture2D | SamplerType.Multisample;
}
else
{
type = (componentMask & 4) != 0 ? SamplerType.Texture3D : SamplerType.Texture2D;
}
} }
else else
{ {
@ -1102,31 +1109,69 @@ namespace Ryujinx.Graphics.Shader.Instructions
} }
TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None; TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None;
int binding;
int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding( switch (query)
Instruction.TextureSize,
type,
TextureFormat.Unknown,
flags,
TextureOperation.DefaultCbufSlot,
imm);
for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
{ {
if ((compMask & 1) != 0) case TexQuery.TexHeaderDimension:
{ binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
Operand d = GetDest(); Instruction.TextureQuerySize,
type,
TextureFormat.Unknown,
flags,
TextureOperation.DefaultCbufSlot,
imm);
if (d == null) for (int compMask = componentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
{ {
break; if ((compMask & 1) != 0)
{
Operand d = GetDest();
if (d == null)
{
break;
}
context.Copy(d, context.TextureQuerySize(type, flags, binding, compIndex, sources));
}
} }
break;
// TODO: Validate and use query parameter. case TexQuery.TexHeaderTextureType:
Operand res = context.TextureSize(type, flags, binding, compIndex, sources); binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
Instruction.TextureQuerySamples,
type,
TextureFormat.Unknown,
flags,
TextureOperation.DefaultCbufSlot,
imm);
context.Copy(d, res); if ((componentMask & 4) != 0)
} {
// Skip first 2 components if necessary.
if ((componentMask & 1) != 0)
{
GetDest();
}
if ((componentMask & 2) != 0)
{
GetDest();
}
Operand d = GetDest();
if (d != null)
{
context.Copy(d, context.TextureQuerySamples(type, flags, binding, sources));
}
}
break;
default:
context.TranslatorContext.GpuAccessor.Log($"Invalid or unsupported query type \"{query}\".");
break;
} }
} }

View file

@ -1,10 +1,8 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{ {
[Flags] [Flags]
[SuppressMessage("Design", "CA1069: Enums values should not be duplicated")]
enum Instruction enum Instruction
{ {
Absolute = 1, Absolute = 1,
@ -118,7 +116,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
Subtract, Subtract,
SwizzleAdd, SwizzleAdd,
TextureSample, TextureSample,
TextureSize, TextureQuerySamples,
TextureQuerySize,
Truncate, Truncate,
UnpackDouble2x32, UnpackDouble2x32,
UnpackHalf2x16, UnpackHalf2x16,
@ -160,7 +159,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
public static bool IsTextureQuery(this Instruction inst) public static bool IsTextureQuery(this Instruction inst)
{ {
inst &= Instruction.Mask; inst &= Instruction.Mask;
return inst == Instruction.Lod || inst == Instruction.TextureSize; return inst == Instruction.Lod || inst == Instruction.TextureQuerySamples || inst == Instruction.TextureQuerySize;
} }
} }
} }

View file

@ -124,7 +124,8 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
Add(Instruction.Subtract, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar); Add(Instruction.Subtract, AggregateType.Scalar, AggregateType.Scalar, AggregateType.Scalar);
Add(Instruction.SwizzleAdd, AggregateType.FP32, AggregateType.FP32, AggregateType.FP32, AggregateType.S32); Add(Instruction.SwizzleAdd, AggregateType.FP32, AggregateType.FP32, AggregateType.FP32, AggregateType.S32);
Add(Instruction.TextureSample, AggregateType.FP32); Add(Instruction.TextureSample, AggregateType.FP32);
Add(Instruction.TextureSize, AggregateType.S32, AggregateType.S32, AggregateType.S32); Add(Instruction.TextureQuerySamples, AggregateType.S32, AggregateType.S32);
Add(Instruction.TextureQuerySize, AggregateType.S32, AggregateType.S32, AggregateType.S32);
Add(Instruction.Truncate, AggregateType.Scalar, AggregateType.Scalar); Add(Instruction.Truncate, AggregateType.Scalar, AggregateType.Scalar);
Add(Instruction.UnpackDouble2x32, AggregateType.U32, AggregateType.FP64); Add(Instruction.UnpackDouble2x32, AggregateType.U32, AggregateType.FP64);
Add(Instruction.UnpackHalf2x16, AggregateType.FP32, AggregateType.U32); Add(Instruction.UnpackHalf2x16, AggregateType.FP32, AggregateType.U32);

View file

@ -897,7 +897,21 @@ namespace Ryujinx.Graphics.Shader.Translation
context.Add(new TextureOperation(Instruction.TextureSample, type, TextureFormat.Unknown, flags, binding, compMask, dests, sources)); context.Add(new TextureOperation(Instruction.TextureSample, type, TextureFormat.Unknown, flags, binding, compMask, dests, sources));
} }
public static Operand TextureSize( public static Operand TextureQuerySamples(
this EmitterContext context,
SamplerType type,
TextureFlags flags,
int binding,
Operand[] sources)
{
Operand dest = Local();
context.Add(new TextureOperation(Instruction.TextureQuerySamples, type, TextureFormat.Unknown, flags, binding, 0, new[] { dest }, sources));
return dest;
}
public static Operand TextureQuerySize(
this EmitterContext context, this EmitterContext context,
SamplerType type, SamplerType type,
TextureFlags flags, TextureFlags flags,
@ -907,7 +921,7 @@ namespace Ryujinx.Graphics.Shader.Translation
{ {
Operand dest = Local(); Operand dest = Local();
context.Add(new TextureOperation(Instruction.TextureSize, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources)); context.Add(new TextureOperation(Instruction.TextureQuerySize, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources));
return dest; return dest;
} }

View file

@ -27,9 +27,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
continue; continue;
} }
if (texOp.Inst == Instruction.Lod || if (texOp.Inst == Instruction.TextureSample || texOp.Inst.IsTextureQuery())
texOp.Inst == Instruction.TextureSample ||
texOp.Inst == Instruction.TextureSize)
{ {
Operand bindlessHandle = Utils.FindLastOperation(texOp.GetSource(0), block); Operand bindlessHandle = Utils.FindLastOperation(texOp.GetSource(0), block);
@ -40,7 +38,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
// as long bindless elimination is successful and we know where the texture descriptor is located. // as long bindless elimination is successful and we know where the texture descriptor is located.
bool rewriteSamplerType = bool rewriteSamplerType =
texOp.Type == SamplerType.TextureBuffer || texOp.Type == SamplerType.TextureBuffer ||
texOp.Inst == Instruction.TextureSize; texOp.Inst == Instruction.TextureQuerySamples ||
texOp.Inst == Instruction.TextureQuerySize;
if (bindlessHandle.Type == OperandType.ConstantBuffer) if (bindlessHandle.Type == OperandType.ConstantBuffer)
{ {

View file

@ -232,8 +232,8 @@ 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.Lod && inst != Instruction.TextureSize; bool accurateType = !inst.IsTextureQuery();
bool intCoords = isImage || flags.HasFlag(TextureFlags.IntCoords) || inst == Instruction.TextureSize; bool intCoords = isImage || flags.HasFlag(TextureFlags.IntCoords) || inst == Instruction.TextureQuerySize;
bool coherent = flags.HasFlag(TextureFlags.Coherent); bool coherent = flags.HasFlag(TextureFlags.Coherent);
if (!isImage) if (!isImage)

View file

@ -23,7 +23,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
{ {
node = InsertCoordNormalization(context.Hfm, node, context.ResourceManager, context.GpuAccessor, context.Stage); node = InsertCoordNormalization(context.Hfm, node, context.ResourceManager, context.GpuAccessor, context.Stage);
node = InsertCoordGatherBias(node, context.ResourceManager, context.GpuAccessor); node = InsertCoordGatherBias(node, context.ResourceManager, context.GpuAccessor);
node = InsertConstOffsets(node, context.ResourceManager, context.GpuAccessor); node = InsertConstOffsets(node, context.GpuAccessor, context.Stage);
if (texOp.Type == SamplerType.TextureBuffer && !context.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat()) if (texOp.Type == SamplerType.TextureBuffer && !context.GpuAccessor.QueryHostSupportsSnormBufferTextureFormat())
{ {
@ -99,7 +99,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0;
bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0; bool isIndexed = (texOp.Type & SamplerType.Indexed) != 0;
if (texOp.Inst == Instruction.TextureSize && if (texOp.Inst == Instruction.TextureQuerySize &&
texOp.Index < 2 && texOp.Index < 2 &&
!isBindless && !isBindless &&
!isIndexed && !isIndexed &&
@ -190,7 +190,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
} }
LinkedListNode<INode> textureSizeNode = node.List.AddBefore(node, new TextureOperation( LinkedListNode<INode> textureSizeNode = node.List.AddBefore(node, new TextureOperation(
Instruction.TextureSize, Instruction.TextureQuerySize,
texOp.Type, texOp.Type,
texOp.Format, texOp.Format,
texOp.Flags, texOp.Flags,
@ -259,7 +259,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
} }
node.List.AddBefore(node, new TextureOperation( node.List.AddBefore(node, new TextureOperation(
Instruction.TextureSize, Instruction.TextureQuerySize,
texOp.Type, texOp.Type,
texOp.Format, texOp.Format,
texOp.Flags, texOp.Flags,
@ -287,7 +287,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
return node; return node;
} }
private static LinkedListNode<INode> InsertConstOffsets(LinkedListNode<INode> node, ResourceManager resourceManager, IGpuAccessor gpuAccessor) private static LinkedListNode<INode> InsertConstOffsets(LinkedListNode<INode> node, IGpuAccessor gpuAccessor, ShaderStage stage)
{ {
// Non-constant texture offsets are not allowed (according to the spec), // Non-constant texture offsets are not allowed (according to the spec),
// however some GPUs does support that. // however some GPUs does support that.
@ -440,7 +440,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
sources.CopyTo(newSources, 0); sources.CopyTo(newSources, 0);
Operand[] texSizes = InsertTextureLod(node, texOp, lodSources, bindlessHandle, coordsCount); Operand[] texSizes = InsertTextureLod(node, texOp, lodSources, bindlessHandle, coordsCount, stage);
int destIndex = 0; int destIndex = 0;
@ -502,7 +502,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
} }
else else
{ {
Operand[] texSizes = InsertTextureLod(node, texOp, lodSources, bindlessHandle, coordsCount); Operand[] texSizes = InsertTextureLod(node, texOp, lodSources, bindlessHandle, coordsCount, stage);
for (int index = 0; index < coordsCount; index++) for (int index = 0; index < coordsCount; index++)
{ {
@ -554,21 +554,31 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
TextureOperation texOp, TextureOperation texOp,
Operand[] lodSources, Operand[] lodSources,
Operand bindlessHandle, Operand bindlessHandle,
int coordsCount) int coordsCount,
ShaderStage stage)
{ {
Operand[] texSizes = new Operand[coordsCount]; Operand[] texSizes = new Operand[coordsCount];
Operand lod = Local(); Operand lod;
node.List.AddBefore(node, new TextureOperation( if (stage == ShaderStage.Fragment)
Instruction.Lod, {
texOp.Type, lod = Local();
texOp.Format,
texOp.Flags, node.List.AddBefore(node, new TextureOperation(
texOp.Binding, Instruction.Lod,
0, texOp.Type,
new[] { lod }, texOp.Format,
lodSources)); texOp.Flags,
texOp.Binding,
0,
new[] { lod },
lodSources));
}
else
{
lod = Const(0);
}
for (int index = 0; index < coordsCount; index++) for (int index = 0; index < coordsCount; index++)
{ {
@ -586,7 +596,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
} }
node.List.AddBefore(node, new TextureOperation( node.List.AddBefore(node, new TextureOperation(
Instruction.TextureSize, Instruction.TextureQuerySize,
texOp.Type, texOp.Type,
texOp.Format, texOp.Format,
texOp.Flags, texOp.Flags,