mirror of
https://git.ryujinx.app/kenji-nx/ryujinx.git
synced 2025-12-18 01:37:04 +00:00
Stop identifying shader textures with handle and cbuf, use binding instead (#5266)
* Stop identifying shader textures with handle and cbuf, use binding instead * Remove now unused code * Consider image operations as having accurate type information too I don't know why that was not the case before * Fix missing unscale on InsertCoordNormalization, stop calling SetUsageFlagsForTextureQuery when not needed * Shader cache version bump * Change get texture methods to return descriptors created from ResourceManager state This is required to ensure that reserved textures and images will not be bound as a guest texture/image * Fix BindlessElimination.SetHandle inserting coords at the wrong place
This commit is contained in:
parent
3b46bb73f7
commit
1c7a90ef35
25 changed files with 656 additions and 659 deletions
|
|
@ -2,16 +2,12 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
|||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
class ShaderConfig
|
||||
{
|
||||
// TODO: Non-hardcoded array size.
|
||||
public const int SamplerArraySize = 4;
|
||||
|
||||
private const int ThreadsPerWarp = 32;
|
||||
|
||||
public ShaderStage Stage { get; }
|
||||
|
|
@ -110,20 +106,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
public UInt128 NextInputAttributesComponents { get; private set; }
|
||||
public UInt128 ThisInputAttributesComponents { get; private set; }
|
||||
|
||||
private readonly record struct TextureInfo(int CbufSlot, int Handle, bool Indexed, TextureFormat Format);
|
||||
|
||||
private struct TextureMeta
|
||||
{
|
||||
public bool AccurateType;
|
||||
public SamplerType Type;
|
||||
public TextureUsageFlags UsageFlags;
|
||||
}
|
||||
|
||||
private readonly Dictionary<TextureInfo, TextureMeta> _usedTextures;
|
||||
private readonly Dictionary<TextureInfo, TextureMeta> _usedImages;
|
||||
private TextureDescriptor[] _cachedTextureDescriptors;
|
||||
private TextureDescriptor[] _cachedImageDescriptors;
|
||||
|
||||
public ShaderConfig(ShaderStage stage, IGpuAccessor gpuAccessor, TranslationOptions options, int localMemorySize)
|
||||
{
|
||||
Stage = stage;
|
||||
|
|
@ -141,9 +123,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
UsedInputAttributesPerPatch = new HashSet<int>();
|
||||
UsedOutputAttributesPerPatch = new HashSet<int>();
|
||||
|
||||
_usedTextures = new Dictionary<TextureInfo, TextureMeta>();
|
||||
_usedImages = new Dictionary<TextureInfo, TextureMeta>();
|
||||
|
||||
ResourceManager = new ResourceManager(stage, gpuAccessor, new ShaderProperties());
|
||||
|
||||
if (!gpuAccessor.QueryHostSupportsTransformFeedback() && gpuAccessor.QueryTransformFeedbackEnabled())
|
||||
|
|
@ -156,7 +135,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
BufferDefinition tfeInfoBuffer = new(BufferLayout.Std430, 1, Constants.TfeInfoBinding, "tfe_info", tfeInfoStruct);
|
||||
|
||||
Properties.AddStorageBuffer(Constants.TfeInfoBinding, tfeInfoBuffer);
|
||||
Properties.AddOrUpdateStorageBuffer(Constants.TfeInfoBinding, tfeInfoBuffer);
|
||||
|
||||
StructureType tfeDataStruct = new(new StructureField[]
|
||||
{
|
||||
|
|
@ -167,7 +146,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
{
|
||||
int binding = Constants.TfeBufferBaseBinding + i;
|
||||
BufferDefinition tfeDataBuffer = new(BufferLayout.Std430, 1, binding, $"tfe_data{i}", tfeDataStruct);
|
||||
Properties.AddStorageBuffer(binding, tfeDataBuffer);
|
||||
Properties.AddOrUpdateStorageBuffer(binding, tfeDataBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -443,22 +422,6 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
UsedInputAttributes |= other.UsedInputAttributes;
|
||||
UsedOutputAttributes |= other.UsedOutputAttributes;
|
||||
|
||||
foreach (var kv in other._usedTextures)
|
||||
{
|
||||
if (!_usedTextures.TryAdd(kv.Key, kv.Value))
|
||||
{
|
||||
_usedTextures[kv.Key] = MergeTextureMeta(kv.Value, _usedTextures[kv.Key]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var kv in other._usedImages)
|
||||
{
|
||||
if (!_usedImages.TryAdd(kv.Key, kv.Value))
|
||||
{
|
||||
_usedImages[kv.Key] = MergeTextureMeta(kv.Value, _usedImages[kv.Key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetLayerOutputAttribute(int attr)
|
||||
|
|
@ -642,196 +605,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
UsedFeatures |= flags;
|
||||
}
|
||||
|
||||
public void SetUsedTexture(
|
||||
Instruction inst,
|
||||
SamplerType type,
|
||||
TextureFormat format,
|
||||
TextureFlags flags,
|
||||
int cbufSlot,
|
||||
int handle)
|
||||
{
|
||||
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.Lod && inst != Instruction.TextureSize;
|
||||
bool coherent = flags.HasFlag(TextureFlags.Coherent);
|
||||
|
||||
if (isImage)
|
||||
{
|
||||
SetUsedTextureOrImage(_usedImages, cbufSlot, handle, type, format, true, isWrite, false, coherent);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool intCoords = flags.HasFlag(TextureFlags.IntCoords) || inst == Instruction.TextureSize;
|
||||
SetUsedTextureOrImage(_usedTextures, cbufSlot, handle, type, TextureFormat.Unknown, intCoords, false, accurateType, coherent);
|
||||
}
|
||||
|
||||
GpuAccessor.RegisterTexture(handle, cbufSlot);
|
||||
}
|
||||
|
||||
private void SetUsedTextureOrImage(
|
||||
Dictionary<TextureInfo, TextureMeta> dict,
|
||||
int cbufSlot,
|
||||
int handle,
|
||||
SamplerType type,
|
||||
TextureFormat format,
|
||||
bool intCoords,
|
||||
bool write,
|
||||
bool accurateType,
|
||||
bool coherent)
|
||||
{
|
||||
var dimensions = type.GetDimensions();
|
||||
var isIndexed = type.HasFlag(SamplerType.Indexed);
|
||||
|
||||
var usageFlags = TextureUsageFlags.None;
|
||||
|
||||
if (intCoords)
|
||||
{
|
||||
usageFlags |= TextureUsageFlags.NeedsScaleValue;
|
||||
|
||||
var canScale = Stage.SupportsRenderScale() && !isIndexed && !write && dimensions == 2;
|
||||
|
||||
if (!canScale)
|
||||
{
|
||||
// Resolution scaling cannot be applied to this texture right now.
|
||||
// Flag so that we know to blacklist scaling on related textures when binding them.
|
||||
usageFlags |= TextureUsageFlags.ResScaleUnsupported;
|
||||
}
|
||||
}
|
||||
|
||||
if (write)
|
||||
{
|
||||
usageFlags |= TextureUsageFlags.ImageStore;
|
||||
}
|
||||
|
||||
if (coherent)
|
||||
{
|
||||
usageFlags |= TextureUsageFlags.ImageCoherent;
|
||||
}
|
||||
|
||||
int arraySize = isIndexed ? SamplerArraySize : 1;
|
||||
|
||||
for (int layer = 0; layer < arraySize; layer++)
|
||||
{
|
||||
var info = new TextureInfo(cbufSlot, handle + layer * 2, isIndexed, format);
|
||||
var meta = new TextureMeta()
|
||||
{
|
||||
AccurateType = accurateType,
|
||||
Type = type,
|
||||
UsageFlags = usageFlags,
|
||||
};
|
||||
|
||||
if (dict.TryGetValue(info, out var existingMeta))
|
||||
{
|
||||
dict[info] = MergeTextureMeta(meta, existingMeta);
|
||||
}
|
||||
else
|
||||
{
|
||||
dict.Add(info, meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static TextureMeta MergeTextureMeta(TextureMeta meta, TextureMeta existingMeta)
|
||||
{
|
||||
meta.UsageFlags |= existingMeta.UsageFlags;
|
||||
|
||||
// If the texture we have has inaccurate type information, then
|
||||
// we prefer the most accurate one.
|
||||
if (existingMeta.AccurateType)
|
||||
{
|
||||
meta.AccurateType = true;
|
||||
meta.Type = existingMeta.Type;
|
||||
}
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
public TextureDescriptor[] GetTextureDescriptors()
|
||||
{
|
||||
return _cachedTextureDescriptors ??= GetTextureOrImageDescriptors(_usedTextures, GpuAccessor.QueryBindingTexture);
|
||||
}
|
||||
|
||||
public TextureDescriptor[] GetImageDescriptors()
|
||||
{
|
||||
return _cachedImageDescriptors ??= GetTextureOrImageDescriptors(_usedImages, GpuAccessor.QueryBindingImage);
|
||||
}
|
||||
|
||||
private static TextureDescriptor[] GetTextureOrImageDescriptors(Dictionary<TextureInfo, TextureMeta> dict, Func<int, bool, int> getBindingCallback)
|
||||
{
|
||||
var descriptors = new TextureDescriptor[dict.Count];
|
||||
|
||||
int i = 0;
|
||||
foreach (var kv in dict.OrderBy(x => x.Key.Indexed).ThenBy(x => x.Key.Handle))
|
||||
{
|
||||
var info = kv.Key;
|
||||
var meta = kv.Value;
|
||||
|
||||
bool isBuffer = (meta.Type & SamplerType.Mask) == SamplerType.TextureBuffer;
|
||||
int binding = getBindingCallback(i, isBuffer);
|
||||
|
||||
descriptors[i] = new TextureDescriptor(binding, meta.Type, info.Format, info.CbufSlot, info.Handle);
|
||||
descriptors[i].SetFlag(meta.UsageFlags);
|
||||
i++;
|
||||
}
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
public TextureDescriptor FindTextureDescriptor(AstTextureOperation texOp)
|
||||
{
|
||||
TextureDescriptor[] descriptors = GetTextureDescriptors();
|
||||
|
||||
for (int i = 0; i < descriptors.Length; i++)
|
||||
{
|
||||
var descriptor = descriptors[i];
|
||||
|
||||
if (descriptor.CbufSlot == texOp.CbufSlot &&
|
||||
descriptor.HandleIndex == texOp.Handle &&
|
||||
descriptor.Format == texOp.Format)
|
||||
{
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
private static int FindDescriptorIndex(TextureDescriptor[] array, TextureOperation texOp, bool ignoreType = false)
|
||||
{
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
var descriptor = array[i];
|
||||
|
||||
if ((descriptor.Type == texOp.Type || ignoreType) &&
|
||||
descriptor.CbufSlot == texOp.CbufSlot &&
|
||||
descriptor.HandleIndex == texOp.Handle &&
|
||||
descriptor.Format == texOp.Format)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int FindTextureDescriptorIndex(TextureOperation texOp, bool ignoreType = false)
|
||||
{
|
||||
return FindDescriptorIndex(GetTextureDescriptors(), texOp, ignoreType);
|
||||
}
|
||||
|
||||
public int FindImageDescriptorIndex(TextureOperation texOp)
|
||||
{
|
||||
return FindDescriptorIndex(GetImageDescriptors(), texOp);
|
||||
}
|
||||
|
||||
public ShaderProgramInfo CreateProgramInfo(ShaderIdentification identification = ShaderIdentification.None)
|
||||
{
|
||||
return new ShaderProgramInfo(
|
||||
ResourceManager.GetConstantBufferDescriptors(),
|
||||
ResourceManager.GetStorageBufferDescriptors(),
|
||||
GetTextureDescriptors(),
|
||||
GetImageDescriptors(),
|
||||
ResourceManager.GetTextureDescriptors(),
|
||||
ResourceManager.GetImageDescriptors(),
|
||||
identification,
|
||||
GpLayerInputAttribute,
|
||||
Stage,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue