Allow texture arrays to use separate descriptor sets on Vulkan (#6870)

* Report base and extra sets from the backend

* Pass texture set index everywhere

* Key textures using set and binding (rather than just binding)

* Start using extra sets for array textures

* Shader cache version bump

* Separate new commands, some PR feedback

* Introduce new manual descriptor set reservation method that prevents it from being used by something else while owned by an array

* Move bind extra sets logic to new method

* Should only use separate array is MaximumExtraSets is not zero

* Format whitespace
This commit is contained in:
gdkchan 2024-05-26 13:30:19 -03:00 committed by GitHub
parent 4cc00bb4b1
commit 53d096e392
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
47 changed files with 996 additions and 262 deletions

View file

@ -19,6 +19,11 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary>
public Format Format { get; }
/// <summary>
/// Shader texture host set index.
/// </summary>
public int Set { get; }
/// <summary>
/// Shader texture host binding point.
/// </summary>
@ -54,15 +59,17 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary>
/// <param name="target">The shader sampler target type</param>
/// <param name="format">Format of the image as declared on the shader</param>
/// <param name="set">Shader texture host set index</param>
/// <param name="binding">The shader texture binding point</param>
/// <param name="arrayLength">For array of textures, this indicates the length of the array. A value of one indicates it is not an array</param>
/// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
/// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
public TextureBindingInfo(Target target, Format format, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags)
public TextureBindingInfo(Target target, Format format, int set, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags)
{
Target = target;
Format = format;
Set = set;
Binding = binding;
ArrayLength = arrayLength;
CbufSlot = cbufSlot;
@ -74,6 +81,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Constructs the texture binding information structure.
/// </summary>
/// <param name="target">The shader sampler target type</param>
/// <param name="set">Shader texture host set index</param>
/// <param name="binding">The shader texture binding point</param>
/// <param name="arrayLength">For array of textures, this indicates the length of the array. A value of one indicates it is not an array</param>
/// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
@ -82,12 +90,13 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="isSamplerOnly">Indicates that the binding is for a sampler</param>
public TextureBindingInfo(
Target target,
int set,
int binding,
int arrayLength,
int cbufSlot,
int handle,
TextureUsageFlags flags,
bool isSamplerOnly) : this(target, 0, binding, arrayLength, cbufSlot, handle, flags)
bool isSamplerOnly) : this(target, 0, set, binding, arrayLength, cbufSlot, handle, flags)
{
IsSamplerOnly = isSamplerOnly;
}

View file

@ -566,7 +566,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int stageIndex,
int textureBufferIndex,
SamplerIndex samplerIndex,
TextureBindingInfo bindingInfo)
in TextureBindingInfo bindingInfo)
{
Update(texturePool, samplerPool, stage, stageIndex, textureBufferIndex, isImage: false, samplerIndex, bindingInfo);
}
@ -579,7 +579,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="stageIndex">Shader stage index where the array is used</param>
/// <param name="textureBufferIndex">Texture constant buffer index</param>
/// <param name="bindingInfo">Array binding information</param>
public void UpdateImageArray(TexturePool texturePool, ShaderStage stage, int stageIndex, int textureBufferIndex, TextureBindingInfo bindingInfo)
public void UpdateImageArray(TexturePool texturePool, ShaderStage stage, int stageIndex, int textureBufferIndex, in TextureBindingInfo bindingInfo)
{
Update(texturePool, null, stage, stageIndex, textureBufferIndex, isImage: true, SamplerIndex.ViaHeaderIndex, bindingInfo);
}
@ -603,7 +603,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int textureBufferIndex,
bool isImage,
SamplerIndex samplerIndex,
TextureBindingInfo bindingInfo)
in TextureBindingInfo bindingInfo)
{
if (IsDirectHandleType(bindingInfo.Handle))
{
@ -623,7 +623,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="stage">Shader stage where the array is used</param>
/// <param name="isImage">Whether the array is a image or texture array</param>
/// <param name="bindingInfo">Array binding information</param>
private void UpdateFromPool(TexturePool texturePool, SamplerPool samplerPool, ShaderStage stage, bool isImage, TextureBindingInfo bindingInfo)
private void UpdateFromPool(TexturePool texturePool, SamplerPool samplerPool, ShaderStage stage, bool isImage, in TextureBindingInfo bindingInfo)
{
CacheEntry entry = GetOrAddEntry(texturePool, samplerPool, bindingInfo, isImage, out bool isNewEntry);
@ -638,11 +638,11 @@ namespace Ryujinx.Graphics.Gpu.Image
if (isImage)
{
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
SetImageArray(stage, bindingInfo, entry.ImageArray);
}
else
{
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
SetTextureArray(stage, bindingInfo, entry.TextureArray);
}
return;
@ -737,14 +737,14 @@ namespace Ryujinx.Graphics.Gpu.Image
entry.ImageArray.SetFormats(0, formats);
entry.ImageArray.SetImages(0, textures);
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
SetImageArray(stage, bindingInfo, entry.ImageArray);
}
else
{
entry.TextureArray.SetSamplers(0, samplers);
entry.TextureArray.SetTextures(0, textures);
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
SetTextureArray(stage, bindingInfo, entry.TextureArray);
}
}
@ -767,7 +767,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int textureBufferIndex,
bool isImage,
SamplerIndex samplerIndex,
TextureBindingInfo bindingInfo)
in TextureBindingInfo bindingInfo)
{
(textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, textureBufferIndex);
@ -800,11 +800,11 @@ namespace Ryujinx.Graphics.Gpu.Image
if (isImage)
{
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
SetImageArray(stage, bindingInfo, entry.ImageArray);
}
else
{
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
SetTextureArray(stage, bindingInfo, entry.TextureArray);
}
return;
@ -829,11 +829,11 @@ namespace Ryujinx.Graphics.Gpu.Image
if (isImage)
{
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
SetImageArray(stage, bindingInfo, entry.ImageArray);
}
else
{
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
SetTextureArray(stage, bindingInfo, entry.TextureArray);
}
return;
@ -950,14 +950,50 @@ namespace Ryujinx.Graphics.Gpu.Image
entry.ImageArray.SetFormats(0, formats);
entry.ImageArray.SetImages(0, textures);
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
SetImageArray(stage, bindingInfo, entry.ImageArray);
}
else
{
entry.TextureArray.SetSamplers(0, samplers);
entry.TextureArray.SetTextures(0, textures);
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
SetTextureArray(stage, bindingInfo, entry.TextureArray);
}
}
/// <summary>
/// Updates a texture array binding on the host.
/// </summary>
/// <param name="stage">Shader stage where the array is used</param>
/// <param name="bindingInfo">Array binding information</param>
/// <param name="array">Texture array</param>
private void SetTextureArray(ShaderStage stage, in TextureBindingInfo bindingInfo, ITextureArray array)
{
if (bindingInfo.Set >= _context.Capabilities.ExtraSetBaseIndex && _context.Capabilities.MaximumExtraSets != 0)
{
_context.Renderer.Pipeline.SetTextureArraySeparate(stage, bindingInfo.Set, array);
}
else
{
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, array);
}
}
/// <summary>
/// Updates a image array binding on the host.
/// </summary>
/// <param name="stage">Shader stage where the array is used</param>
/// <param name="bindingInfo">Array binding information</param>
/// <param name="array">Image array</param>
private void SetImageArray(ShaderStage stage, in TextureBindingInfo bindingInfo, IImageArray array)
{
if (bindingInfo.Set >= _context.Capabilities.ExtraSetBaseIndex && _context.Capabilities.MaximumExtraSets != 0)
{
_context.Renderer.Pipeline.SetImageArraySeparate(stage, bindingInfo.Set, array);
}
else
{
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, array);
}
}
@ -973,7 +1009,7 @@ namespace Ryujinx.Graphics.Gpu.Image
private CacheEntry GetOrAddEntry(
TexturePool texturePool,
SamplerPool samplerPool,
TextureBindingInfo bindingInfo,
in TextureBindingInfo bindingInfo,
bool isImage,
out bool isNew)
{
@ -1015,7 +1051,7 @@ namespace Ryujinx.Graphics.Gpu.Image
private CacheEntryFromBuffer GetOrAddEntry(
TexturePool texturePool,
SamplerPool samplerPool,
TextureBindingInfo bindingInfo,
in TextureBindingInfo bindingInfo,
bool isImage,
ref BufferBounds textureBufferBounds,
out bool isNew)

View file

@ -62,6 +62,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
var result = new TextureBindingInfo(
target,
descriptor.Set,
descriptor.Binding,
descriptor.ArrayLength,
descriptor.CbufSlot,
@ -90,6 +91,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
var result = new TextureBindingInfo(
target,
format,
descriptor.Set,
descriptor.Binding,
descriptor.ArrayLength,
descriptor.CbufSlot,

View file

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

View file

@ -51,7 +51,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
_reservedImages = rrc.ReservedImages;
}
public int CreateConstantBufferBinding(int index)
public SetBindingPair CreateConstantBufferBinding(int index)
{
int binding;
@ -64,10 +64,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
binding = _resourceCounts.UniformBuffersCount++;
}
return binding + _reservedConstantBuffers;
return new SetBindingPair(_context.Capabilities.UniformBufferSetIndex, binding + _reservedConstantBuffers);
}
public int CreateImageBinding(int count, bool isBuffer)
public SetBindingPair CreateImageBinding(int count, bool isBuffer)
{
int binding;
@ -96,10 +96,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
_resourceCounts.ImagesCount += count;
}
return binding + _reservedImages;
return new SetBindingPair(_context.Capabilities.ImageSetIndex, binding + _reservedImages);
}
public int CreateStorageBufferBinding(int index)
public SetBindingPair CreateStorageBufferBinding(int index)
{
int binding;
@ -112,10 +112,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
binding = _resourceCounts.StorageBuffersCount++;
}
return binding + _reservedStorageBuffers;
return new SetBindingPair(_context.Capabilities.StorageBufferSetIndex, binding + _reservedStorageBuffers);
}
public int CreateTextureBinding(int count, bool isBuffer)
public SetBindingPair CreateTextureBinding(int count, bool isBuffer)
{
int binding;
@ -144,7 +144,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
_resourceCounts.TexturesCount += count;
}
return binding + _reservedTextures;
return new SetBindingPair(_context.Capabilities.TextureSetIndex, binding + _reservedTextures);
}
private int GetBindingFromIndex(int index, uint maxPerStage, string resourceName)
@ -183,6 +183,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
return maxPerStage * Constants.ShaderStages;
}
public int CreateExtraSet()
{
if (_resourceCounts.SetsCount >= _context.Capabilities.MaximumExtraSets)
{
return -1;
}
return _context.Capabilities.ExtraSetBaseIndex + _resourceCounts.SetsCount++;
}
public int QueryHostGatherBiasPrecision() => _context.Capabilities.GatherBiasPrecision;
public bool QueryHostReducedPrecision() => _context.Capabilities.ReduceShaderPrecision;

View file

@ -24,5 +24,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// Total of images used by the shaders.
/// </summary>
public int ImagesCount;
/// <summary>
/// Total of extra sets used by the shaders.
/// </summary>
public int SetsCount;
}
}

View file

@ -1,5 +1,6 @@
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader;
using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Gpu.Shader
@ -9,13 +10,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary>
class ShaderInfoBuilder
{
private const int TotalSets = 4;
private const int UniformSetIndex = 0;
private const int StorageSetIndex = 1;
private const int TextureSetIndex = 2;
private const int ImageSetIndex = 3;
private const ResourceStages SupportBufferStages =
ResourceStages.Compute |
ResourceStages.Vertex |
@ -36,8 +30,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
private readonly int _reservedTextures;
private readonly int _reservedImages;
private readonly List<ResourceDescriptor>[] _resourceDescriptors;
private readonly List<ResourceUsage>[] _resourceUsages;
private List<ResourceDescriptor>[] _resourceDescriptors;
private List<ResourceUsage>[] _resourceUsages;
/// <summary>
/// Creates a new shader info builder.
@ -51,17 +45,27 @@ namespace Ryujinx.Graphics.Gpu.Shader
_fragmentOutputMap = -1;
_resourceDescriptors = new List<ResourceDescriptor>[TotalSets];
_resourceUsages = new List<ResourceUsage>[TotalSets];
int uniformSetIndex = context.Capabilities.UniformBufferSetIndex;
int storageSetIndex = context.Capabilities.StorageBufferSetIndex;
int textureSetIndex = context.Capabilities.TextureSetIndex;
int imageSetIndex = context.Capabilities.ImageSetIndex;
for (int index = 0; index < TotalSets; index++)
int totalSets = Math.Max(uniformSetIndex, storageSetIndex);
totalSets = Math.Max(totalSets, textureSetIndex);
totalSets = Math.Max(totalSets, imageSetIndex);
totalSets++;
_resourceDescriptors = new List<ResourceDescriptor>[totalSets];
_resourceUsages = new List<ResourceUsage>[totalSets];
for (int index = 0; index < totalSets; index++)
{
_resourceDescriptors[index] = new();
_resourceUsages[index] = new();
}
AddDescriptor(SupportBufferStages, ResourceType.UniformBuffer, UniformSetIndex, 0, 1);
AddUsage(SupportBufferStages, ResourceType.UniformBuffer, UniformSetIndex, 0, 1);
AddDescriptor(SupportBufferStages, ResourceType.UniformBuffer, uniformSetIndex, 0, 1);
AddUsage(SupportBufferStages, ResourceType.UniformBuffer, uniformSetIndex, 0, 1);
ResourceReservationCounts rrc = new(!context.Capabilities.SupportsTransformFeedback && tfEnabled, vertexAsCompute);
@ -73,12 +77,20 @@ namespace Ryujinx.Graphics.Gpu.Shader
// TODO: Handle that better? Maybe we should only set the binding that are really needed on each shader.
ResourceStages stages = vertexAsCompute ? ResourceStages.Compute | ResourceStages.Vertex : VtgStages;
PopulateDescriptorAndUsages(stages, ResourceType.UniformBuffer, UniformSetIndex, 1, rrc.ReservedConstantBuffers - 1);
PopulateDescriptorAndUsages(stages, ResourceType.StorageBuffer, StorageSetIndex, 0, rrc.ReservedStorageBuffers);
PopulateDescriptorAndUsages(stages, ResourceType.BufferTexture, TextureSetIndex, 0, rrc.ReservedTextures);
PopulateDescriptorAndUsages(stages, ResourceType.BufferImage, ImageSetIndex, 0, rrc.ReservedImages);
PopulateDescriptorAndUsages(stages, ResourceType.UniformBuffer, uniformSetIndex, 1, rrc.ReservedConstantBuffers - 1);
PopulateDescriptorAndUsages(stages, ResourceType.StorageBuffer, storageSetIndex, 0, rrc.ReservedStorageBuffers);
PopulateDescriptorAndUsages(stages, ResourceType.BufferTexture, textureSetIndex, 0, rrc.ReservedTextures);
PopulateDescriptorAndUsages(stages, ResourceType.BufferImage, imageSetIndex, 0, rrc.ReservedImages);
}
/// <summary>
/// Populates descriptors and usages for vertex as compute and transform feedback emulation reserved resources.
/// </summary>
/// <param name="stages">Shader stages where the resources are used</param>
/// <param name="type">Resource type</param>
/// <param name="setIndex">Resource set index where the resources are used</param>
/// <param name="start">First binding number</param>
/// <param name="count">Amount of bindings</param>
private void PopulateDescriptorAndUsages(ResourceStages stages, ResourceType type, int setIndex, int start, int count)
{
AddDescriptor(stages, type, setIndex, start, count);
@ -127,18 +139,23 @@ namespace Ryujinx.Graphics.Gpu.Shader
int textureBinding = _reservedTextures + stageIndex * texturesPerStage * 2;
int imageBinding = _reservedImages + stageIndex * imagesPerStage * 2;
AddDescriptor(stages, ResourceType.UniformBuffer, UniformSetIndex, uniformBinding, uniformsPerStage);
AddDescriptor(stages, ResourceType.StorageBuffer, StorageSetIndex, storageBinding, storagesPerStage);
AddDualDescriptor(stages, ResourceType.TextureAndSampler, ResourceType.BufferTexture, TextureSetIndex, textureBinding, texturesPerStage);
AddDualDescriptor(stages, ResourceType.Image, ResourceType.BufferImage, ImageSetIndex, imageBinding, imagesPerStage);
int uniformSetIndex = _context.Capabilities.UniformBufferSetIndex;
int storageSetIndex = _context.Capabilities.StorageBufferSetIndex;
int textureSetIndex = _context.Capabilities.TextureSetIndex;
int imageSetIndex = _context.Capabilities.ImageSetIndex;
AddArrayDescriptors(info.Textures, stages, TextureSetIndex, isImage: false);
AddArrayDescriptors(info.Images, stages, TextureSetIndex, isImage: true);
AddDescriptor(stages, ResourceType.UniformBuffer, uniformSetIndex, uniformBinding, uniformsPerStage);
AddDescriptor(stages, ResourceType.StorageBuffer, storageSetIndex, storageBinding, storagesPerStage);
AddDualDescriptor(stages, ResourceType.TextureAndSampler, ResourceType.BufferTexture, textureSetIndex, textureBinding, texturesPerStage);
AddDualDescriptor(stages, ResourceType.Image, ResourceType.BufferImage, imageSetIndex, imageBinding, imagesPerStage);
AddUsage(info.CBuffers, stages, UniformSetIndex, isStorage: false);
AddUsage(info.SBuffers, stages, StorageSetIndex, isStorage: true);
AddUsage(info.Textures, stages, TextureSetIndex, isImage: false);
AddUsage(info.Images, stages, ImageSetIndex, isImage: true);
AddArrayDescriptors(info.Textures, stages, isImage: false);
AddArrayDescriptors(info.Images, stages, isImage: true);
AddUsage(info.CBuffers, stages, isStorage: false);
AddUsage(info.SBuffers, stages, isStorage: true);
AddUsage(info.Textures, stages, isImage: false);
AddUsage(info.Images, stages, isImage: true);
}
/// <summary>
@ -177,9 +194,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary>
/// <param name="textures">Textures to be added</param>
/// <param name="stages">Stages where the textures are used</param>
/// <param name="setIndex">Descriptor set index where the textures will be bound</param>
/// <param name="isImage">True for images, false for textures</param>
private void AddArrayDescriptors(IEnumerable<TextureDescriptor> textures, ResourceStages stages, int setIndex, bool isImage)
private void AddArrayDescriptors(IEnumerable<TextureDescriptor> textures, ResourceStages stages, bool isImage)
{
foreach (TextureDescriptor texture in textures)
{
@ -187,7 +203,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
ResourceType type = GetTextureResourceType(texture, isImage);
_resourceDescriptors[setIndex].Add(new ResourceDescriptor(texture.Binding, texture.ArrayLength, type, stages));
GetDescriptors(texture.Set).Add(new ResourceDescriptor(texture.Binding, texture.ArrayLength, type, stages));
}
}
}
@ -213,13 +229,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary>
/// <param name="buffers">Buffers to be added</param>
/// <param name="stages">Stages where the buffers are used</param>
/// <param name="setIndex">Descriptor set index where the buffers will be bound</param>
/// <param name="isStorage">True for storage buffers, false for uniform buffers</param>
private void AddUsage(IEnumerable<BufferDescriptor> buffers, ResourceStages stages, int setIndex, bool isStorage)
private void AddUsage(IEnumerable<BufferDescriptor> buffers, ResourceStages stages, bool isStorage)
{
foreach (BufferDescriptor buffer in buffers)
{
_resourceUsages[setIndex].Add(new ResourceUsage(
GetUsages(buffer.Set).Add(new ResourceUsage(
buffer.Binding,
1,
isStorage ? ResourceType.StorageBuffer : ResourceType.UniformBuffer,
@ -232,18 +247,65 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary>
/// <param name="textures">Textures to be added</param>
/// <param name="stages">Stages where the textures are used</param>
/// <param name="setIndex">Descriptor set index where the textures will be bound</param>
/// <param name="isImage">True for images, false for textures</param>
private void AddUsage(IEnumerable<TextureDescriptor> textures, ResourceStages stages, int setIndex, bool isImage)
private void AddUsage(IEnumerable<TextureDescriptor> textures, ResourceStages stages, bool isImage)
{
foreach (TextureDescriptor texture in textures)
{
ResourceType type = GetTextureResourceType(texture, isImage);
_resourceUsages[setIndex].Add(new ResourceUsage(texture.Binding, texture.ArrayLength, type, stages));
GetUsages(texture.Set).Add(new ResourceUsage(texture.Binding, texture.ArrayLength, type, stages));
}
}
/// <summary>
/// Gets the list of resource descriptors for a given set index. A new list will be created if needed.
/// </summary>
/// <param name="setIndex">Resource set index</param>
/// <returns>List of resource descriptors</returns>
private List<ResourceDescriptor> GetDescriptors(int setIndex)
{
if (_resourceDescriptors.Length <= setIndex)
{
int oldLength = _resourceDescriptors.Length;
Array.Resize(ref _resourceDescriptors, setIndex + 1);
for (int index = oldLength; index <= setIndex; index++)
{
_resourceDescriptors[index] = new();
}
}
return _resourceDescriptors[setIndex];
}
/// <summary>
/// Gets the list of resource usages for a given set index. A new list will be created if needed.
/// </summary>
/// <param name="setIndex">Resource set index</param>
/// <returns>List of resource usages</returns>
private List<ResourceUsage> GetUsages(int setIndex)
{
if (_resourceUsages.Length <= setIndex)
{
int oldLength = _resourceUsages.Length;
Array.Resize(ref _resourceUsages, setIndex + 1);
for (int index = oldLength; index <= setIndex; index++)
{
_resourceUsages[index] = new();
}
}
return _resourceUsages[setIndex];
}
/// <summary>
/// Gets a resource type from a texture descriptor.
/// </summary>
/// <param name="texture">Texture descriptor</param>
/// <param name="isImage">Whether the texture is a image texture (writable) or not (sampled)</param>
/// <returns>Resource type</returns>
private static ResourceType GetTextureResourceType(TextureDescriptor texture, bool isImage)
{
bool isBuffer = (texture.Type & SamplerType.Mask) == SamplerType.TextureBuffer;
@ -278,10 +340,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <returns>Shader information</returns>
public ShaderInfo Build(ProgramPipelineState? pipeline, bool fromCache = false)
{
var descriptors = new ResourceDescriptorCollection[TotalSets];
var usages = new ResourceUsageCollection[TotalSets];
int totalSets = _resourceDescriptors.Length;
for (int index = 0; index < TotalSets; index++)
var descriptors = new ResourceDescriptorCollection[totalSets];
var usages = new ResourceUsageCollection[totalSets];
for (int index = 0; index < totalSets; index++)
{
descriptors[index] = new ResourceDescriptorCollection(_resourceDescriptors[index].ToArray().AsReadOnly());
usages[index] = new ResourceUsageCollection(_resourceUsages[index].ToArray().AsReadOnly());