forked from Mirror/Ryujinx
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:
parent
4cc00bb4b1
commit
53d096e392
47 changed files with 996 additions and 262 deletions
|
@ -51,6 +51,13 @@ namespace Ryujinx.Graphics.GAL
|
||||||
public readonly bool SupportsIndirectParameters;
|
public readonly bool SupportsIndirectParameters;
|
||||||
public readonly bool SupportsDepthClipControl;
|
public readonly bool SupportsDepthClipControl;
|
||||||
|
|
||||||
|
public readonly int UniformBufferSetIndex;
|
||||||
|
public readonly int StorageBufferSetIndex;
|
||||||
|
public readonly int TextureSetIndex;
|
||||||
|
public readonly int ImageSetIndex;
|
||||||
|
public readonly int ExtraSetBaseIndex;
|
||||||
|
public readonly int MaximumExtraSets;
|
||||||
|
|
||||||
public readonly uint MaximumUniformBuffersPerStage;
|
public readonly uint MaximumUniformBuffersPerStage;
|
||||||
public readonly uint MaximumStorageBuffersPerStage;
|
public readonly uint MaximumStorageBuffersPerStage;
|
||||||
public readonly uint MaximumTexturesPerStage;
|
public readonly uint MaximumTexturesPerStage;
|
||||||
|
@ -109,6 +116,12 @@ namespace Ryujinx.Graphics.GAL
|
||||||
bool supportsViewportSwizzle,
|
bool supportsViewportSwizzle,
|
||||||
bool supportsIndirectParameters,
|
bool supportsIndirectParameters,
|
||||||
bool supportsDepthClipControl,
|
bool supportsDepthClipControl,
|
||||||
|
int uniformBufferSetIndex,
|
||||||
|
int storageBufferSetIndex,
|
||||||
|
int textureSetIndex,
|
||||||
|
int imageSetIndex,
|
||||||
|
int extraSetBaseIndex,
|
||||||
|
int maximumExtraSets,
|
||||||
uint maximumUniformBuffersPerStage,
|
uint maximumUniformBuffersPerStage,
|
||||||
uint maximumStorageBuffersPerStage,
|
uint maximumStorageBuffersPerStage,
|
||||||
uint maximumTexturesPerStage,
|
uint maximumTexturesPerStage,
|
||||||
|
@ -164,6 +177,12 @@ namespace Ryujinx.Graphics.GAL
|
||||||
SupportsViewportSwizzle = supportsViewportSwizzle;
|
SupportsViewportSwizzle = supportsViewportSwizzle;
|
||||||
SupportsIndirectParameters = supportsIndirectParameters;
|
SupportsIndirectParameters = supportsIndirectParameters;
|
||||||
SupportsDepthClipControl = supportsDepthClipControl;
|
SupportsDepthClipControl = supportsDepthClipControl;
|
||||||
|
UniformBufferSetIndex = uniformBufferSetIndex;
|
||||||
|
StorageBufferSetIndex = storageBufferSetIndex;
|
||||||
|
TextureSetIndex = textureSetIndex;
|
||||||
|
ImageSetIndex = imageSetIndex;
|
||||||
|
ExtraSetBaseIndex = extraSetBaseIndex;
|
||||||
|
MaximumExtraSets = maximumExtraSets;
|
||||||
MaximumUniformBuffersPerStage = maximumUniformBuffersPerStage;
|
MaximumUniformBuffersPerStage = maximumUniformBuffersPerStage;
|
||||||
MaximumStorageBuffersPerStage = maximumStorageBuffersPerStage;
|
MaximumStorageBuffersPerStage = maximumStorageBuffersPerStage;
|
||||||
MaximumTexturesPerStage = maximumTexturesPerStage;
|
MaximumTexturesPerStage = maximumTexturesPerStage;
|
||||||
|
|
|
@ -60,6 +60,7 @@ namespace Ryujinx.Graphics.GAL
|
||||||
|
|
||||||
void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat);
|
void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat);
|
||||||
void SetImageArray(ShaderStage stage, int binding, IImageArray array);
|
void SetImageArray(ShaderStage stage, int binding, IImageArray array);
|
||||||
|
void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array);
|
||||||
|
|
||||||
void SetLineParameters(float width, bool smooth);
|
void SetLineParameters(float width, bool smooth);
|
||||||
|
|
||||||
|
@ -91,6 +92,7 @@ namespace Ryujinx.Graphics.GAL
|
||||||
|
|
||||||
void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler);
|
void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler);
|
||||||
void SetTextureArray(ShaderStage stage, int binding, ITextureArray array);
|
void SetTextureArray(ShaderStage stage, int binding, ITextureArray array);
|
||||||
|
void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array);
|
||||||
|
|
||||||
void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
|
void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
|
||||||
void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers);
|
void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers);
|
||||||
|
|
|
@ -124,6 +124,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||||
Register<SetUniformBuffersCommand>(CommandType.SetUniformBuffers);
|
Register<SetUniformBuffersCommand>(CommandType.SetUniformBuffers);
|
||||||
Register<SetImageCommand>(CommandType.SetImage);
|
Register<SetImageCommand>(CommandType.SetImage);
|
||||||
Register<SetImageArrayCommand>(CommandType.SetImageArray);
|
Register<SetImageArrayCommand>(CommandType.SetImageArray);
|
||||||
|
Register<SetImageArraySeparateCommand>(CommandType.SetImageArraySeparate);
|
||||||
Register<SetIndexBufferCommand>(CommandType.SetIndexBuffer);
|
Register<SetIndexBufferCommand>(CommandType.SetIndexBuffer);
|
||||||
Register<SetLineParametersCommand>(CommandType.SetLineParameters);
|
Register<SetLineParametersCommand>(CommandType.SetLineParameters);
|
||||||
Register<SetLogicOpStateCommand>(CommandType.SetLogicOpState);
|
Register<SetLogicOpStateCommand>(CommandType.SetLogicOpState);
|
||||||
|
@ -141,6 +142,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||||
Register<SetStencilTestCommand>(CommandType.SetStencilTest);
|
Register<SetStencilTestCommand>(CommandType.SetStencilTest);
|
||||||
Register<SetTextureAndSamplerCommand>(CommandType.SetTextureAndSampler);
|
Register<SetTextureAndSamplerCommand>(CommandType.SetTextureAndSampler);
|
||||||
Register<SetTextureArrayCommand>(CommandType.SetTextureArray);
|
Register<SetTextureArrayCommand>(CommandType.SetTextureArray);
|
||||||
|
Register<SetTextureArraySeparateCommand>(CommandType.SetTextureArraySeparate);
|
||||||
Register<SetUserClipDistanceCommand>(CommandType.SetUserClipDistance);
|
Register<SetUserClipDistanceCommand>(CommandType.SetUserClipDistance);
|
||||||
Register<SetVertexAttribsCommand>(CommandType.SetVertexAttribs);
|
Register<SetVertexAttribsCommand>(CommandType.SetVertexAttribs);
|
||||||
Register<SetVertexBuffersCommand>(CommandType.SetVertexBuffers);
|
Register<SetVertexBuffersCommand>(CommandType.SetVertexBuffers);
|
||||||
|
|
|
@ -84,6 +84,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||||
SetUniformBuffers,
|
SetUniformBuffers,
|
||||||
SetImage,
|
SetImage,
|
||||||
SetImageArray,
|
SetImageArray,
|
||||||
|
SetImageArraySeparate,
|
||||||
SetIndexBuffer,
|
SetIndexBuffer,
|
||||||
SetLineParameters,
|
SetLineParameters,
|
||||||
SetLogicOpState,
|
SetLogicOpState,
|
||||||
|
@ -101,6 +102,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||||
SetStencilTest,
|
SetStencilTest,
|
||||||
SetTextureAndSampler,
|
SetTextureAndSampler,
|
||||||
SetTextureArray,
|
SetTextureArray,
|
||||||
|
SetTextureArraySeparate,
|
||||||
SetUserClipDistance,
|
SetUserClipDistance,
|
||||||
SetVertexAttribs,
|
SetVertexAttribs,
|
||||||
SetVertexBuffers,
|
SetVertexBuffers,
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
using Ryujinx.Graphics.GAL.Multithreading.Model;
|
||||||
|
using Ryujinx.Graphics.GAL.Multithreading.Resources;
|
||||||
|
using Ryujinx.Graphics.Shader;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||||
|
{
|
||||||
|
struct SetImageArraySeparateCommand : IGALCommand, IGALCommand<SetImageArraySeparateCommand>
|
||||||
|
{
|
||||||
|
public readonly CommandType CommandType => CommandType.SetImageArraySeparate;
|
||||||
|
private ShaderStage _stage;
|
||||||
|
private int _setIndex;
|
||||||
|
private TableRef<IImageArray> _array;
|
||||||
|
|
||||||
|
public void Set(ShaderStage stage, int setIndex, TableRef<IImageArray> array)
|
||||||
|
{
|
||||||
|
_stage = stage;
|
||||||
|
_setIndex = setIndex;
|
||||||
|
_array = array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Run(ref SetImageArraySeparateCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||||
|
{
|
||||||
|
renderer.Pipeline.SetImageArraySeparate(command._stage, command._setIndex, command._array.GetAs<ThreadedImageArray>(threaded)?.Base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
using Ryujinx.Graphics.GAL.Multithreading.Model;
|
||||||
|
using Ryujinx.Graphics.GAL.Multithreading.Resources;
|
||||||
|
using Ryujinx.Graphics.Shader;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||||
|
{
|
||||||
|
struct SetTextureArraySeparateCommand : IGALCommand, IGALCommand<SetTextureArraySeparateCommand>
|
||||||
|
{
|
||||||
|
public readonly CommandType CommandType => CommandType.SetTextureArraySeparate;
|
||||||
|
private ShaderStage _stage;
|
||||||
|
private int _setIndex;
|
||||||
|
private TableRef<ITextureArray> _array;
|
||||||
|
|
||||||
|
public void Set(ShaderStage stage, int setIndex, TableRef<ITextureArray> array)
|
||||||
|
{
|
||||||
|
_stage = stage;
|
||||||
|
_setIndex = setIndex;
|
||||||
|
_array = array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Run(ref SetTextureArraySeparateCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||||
|
{
|
||||||
|
renderer.Pipeline.SetTextureArraySeparate(command._stage, command._setIndex, command._array.GetAs<ThreadedTextureArray>(threaded)?.Base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -189,6 +189,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
|
||||||
|
{
|
||||||
|
_renderer.New<SetImageArraySeparateCommand>().Set(stage, setIndex, Ref(array));
|
||||||
|
_renderer.QueueCommand();
|
||||||
|
}
|
||||||
|
|
||||||
public void SetIndexBuffer(BufferRange buffer, IndexType type)
|
public void SetIndexBuffer(BufferRange buffer, IndexType type)
|
||||||
{
|
{
|
||||||
_renderer.New<SetIndexBufferCommand>().Set(buffer, type);
|
_renderer.New<SetIndexBufferCommand>().Set(buffer, type);
|
||||||
|
@ -297,6 +303,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||||
_renderer.QueueCommand();
|
_renderer.QueueCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
|
||||||
|
{
|
||||||
|
_renderer.New<SetTextureArraySeparateCommand>().Set(stage, setIndex, Ref(array));
|
||||||
|
_renderer.QueueCommand();
|
||||||
|
}
|
||||||
|
|
||||||
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
|
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
|
||||||
{
|
{
|
||||||
_renderer.New<SetTransformFeedbackBuffersCommand>().Set(_renderer.CopySpan(buffers));
|
_renderer.New<SetTransformFeedbackBuffersCommand>().Set(_renderer.CopySpan(buffers));
|
||||||
|
|
|
@ -19,6 +19,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Format Format { get; }
|
public Format Format { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shader texture host set index.
|
||||||
|
/// </summary>
|
||||||
|
public int Set { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shader texture host binding point.
|
/// Shader texture host binding point.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -54,15 +59,17 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="target">The shader sampler target type</param>
|
/// <param name="target">The shader sampler target type</param>
|
||||||
/// <param name="format">Format of the image as declared on the shader</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="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="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="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="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>
|
/// <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;
|
Target = target;
|
||||||
Format = format;
|
Format = format;
|
||||||
|
Set = set;
|
||||||
Binding = binding;
|
Binding = binding;
|
||||||
ArrayLength = arrayLength;
|
ArrayLength = arrayLength;
|
||||||
CbufSlot = cbufSlot;
|
CbufSlot = cbufSlot;
|
||||||
|
@ -74,6 +81,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
/// Constructs the texture binding information structure.
|
/// Constructs the texture binding information structure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="target">The shader sampler target type</param>
|
/// <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="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="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="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>
|
/// <param name="isSamplerOnly">Indicates that the binding is for a sampler</param>
|
||||||
public TextureBindingInfo(
|
public TextureBindingInfo(
|
||||||
Target target,
|
Target target,
|
||||||
|
int set,
|
||||||
int binding,
|
int binding,
|
||||||
int arrayLength,
|
int arrayLength,
|
||||||
int cbufSlot,
|
int cbufSlot,
|
||||||
int handle,
|
int handle,
|
||||||
TextureUsageFlags flags,
|
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;
|
IsSamplerOnly = isSamplerOnly;
|
||||||
}
|
}
|
||||||
|
|
|
@ -566,7 +566,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
int stageIndex,
|
int stageIndex,
|
||||||
int textureBufferIndex,
|
int textureBufferIndex,
|
||||||
SamplerIndex samplerIndex,
|
SamplerIndex samplerIndex,
|
||||||
TextureBindingInfo bindingInfo)
|
in TextureBindingInfo bindingInfo)
|
||||||
{
|
{
|
||||||
Update(texturePool, samplerPool, stage, stageIndex, textureBufferIndex, isImage: false, samplerIndex, 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="stageIndex">Shader stage index where the array is used</param>
|
||||||
/// <param name="textureBufferIndex">Texture constant buffer index</param>
|
/// <param name="textureBufferIndex">Texture constant buffer index</param>
|
||||||
/// <param name="bindingInfo">Array binding information</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);
|
Update(texturePool, null, stage, stageIndex, textureBufferIndex, isImage: true, SamplerIndex.ViaHeaderIndex, bindingInfo);
|
||||||
}
|
}
|
||||||
|
@ -603,7 +603,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
int textureBufferIndex,
|
int textureBufferIndex,
|
||||||
bool isImage,
|
bool isImage,
|
||||||
SamplerIndex samplerIndex,
|
SamplerIndex samplerIndex,
|
||||||
TextureBindingInfo bindingInfo)
|
in TextureBindingInfo bindingInfo)
|
||||||
{
|
{
|
||||||
if (IsDirectHandleType(bindingInfo.Handle))
|
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="stage">Shader stage where the array is used</param>
|
||||||
/// <param name="isImage">Whether the array is a image or texture array</param>
|
/// <param name="isImage">Whether the array is a image or texture array</param>
|
||||||
/// <param name="bindingInfo">Array binding information</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);
|
CacheEntry entry = GetOrAddEntry(texturePool, samplerPool, bindingInfo, isImage, out bool isNewEntry);
|
||||||
|
|
||||||
|
@ -638,11 +638,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
if (isImage)
|
if (isImage)
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
|
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
|
SetTextureArray(stage, bindingInfo, entry.TextureArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -737,14 +737,14 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
entry.ImageArray.SetFormats(0, formats);
|
entry.ImageArray.SetFormats(0, formats);
|
||||||
entry.ImageArray.SetImages(0, textures);
|
entry.ImageArray.SetImages(0, textures);
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
|
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
entry.TextureArray.SetSamplers(0, samplers);
|
entry.TextureArray.SetSamplers(0, samplers);
|
||||||
entry.TextureArray.SetTextures(0, textures);
|
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,
|
int textureBufferIndex,
|
||||||
bool isImage,
|
bool isImage,
|
||||||
SamplerIndex samplerIndex,
|
SamplerIndex samplerIndex,
|
||||||
TextureBindingInfo bindingInfo)
|
in TextureBindingInfo bindingInfo)
|
||||||
{
|
{
|
||||||
(textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, textureBufferIndex);
|
(textureBufferIndex, int samplerBufferIndex) = TextureHandle.UnpackSlots(bindingInfo.CbufSlot, textureBufferIndex);
|
||||||
|
|
||||||
|
@ -800,11 +800,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
if (isImage)
|
if (isImage)
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
|
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
|
SetTextureArray(stage, bindingInfo, entry.TextureArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -829,11 +829,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
|
|
||||||
if (isImage)
|
if (isImage)
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
|
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_context.Renderer.Pipeline.SetTextureArray(stage, bindingInfo.Binding, entry.TextureArray);
|
SetTextureArray(stage, bindingInfo, entry.TextureArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -950,14 +950,50 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
entry.ImageArray.SetFormats(0, formats);
|
entry.ImageArray.SetFormats(0, formats);
|
||||||
entry.ImageArray.SetImages(0, textures);
|
entry.ImageArray.SetImages(0, textures);
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetImageArray(stage, bindingInfo.Binding, entry.ImageArray);
|
SetImageArray(stage, bindingInfo, entry.ImageArray);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
entry.TextureArray.SetSamplers(0, samplers);
|
entry.TextureArray.SetSamplers(0, samplers);
|
||||||
entry.TextureArray.SetTextures(0, textures);
|
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(
|
private CacheEntry GetOrAddEntry(
|
||||||
TexturePool texturePool,
|
TexturePool texturePool,
|
||||||
SamplerPool samplerPool,
|
SamplerPool samplerPool,
|
||||||
TextureBindingInfo bindingInfo,
|
in TextureBindingInfo bindingInfo,
|
||||||
bool isImage,
|
bool isImage,
|
||||||
out bool isNew)
|
out bool isNew)
|
||||||
{
|
{
|
||||||
|
@ -1015,7 +1051,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||||
private CacheEntryFromBuffer GetOrAddEntry(
|
private CacheEntryFromBuffer GetOrAddEntry(
|
||||||
TexturePool texturePool,
|
TexturePool texturePool,
|
||||||
SamplerPool samplerPool,
|
SamplerPool samplerPool,
|
||||||
TextureBindingInfo bindingInfo,
|
in TextureBindingInfo bindingInfo,
|
||||||
bool isImage,
|
bool isImage,
|
||||||
ref BufferBounds textureBufferBounds,
|
ref BufferBounds textureBufferBounds,
|
||||||
out bool isNew)
|
out bool isNew)
|
||||||
|
|
|
@ -62,6 +62,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
var result = new TextureBindingInfo(
|
var result = new TextureBindingInfo(
|
||||||
target,
|
target,
|
||||||
|
descriptor.Set,
|
||||||
descriptor.Binding,
|
descriptor.Binding,
|
||||||
descriptor.ArrayLength,
|
descriptor.ArrayLength,
|
||||||
descriptor.CbufSlot,
|
descriptor.CbufSlot,
|
||||||
|
@ -90,6 +91,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
var result = new TextureBindingInfo(
|
var result = new TextureBindingInfo(
|
||||||
target,
|
target,
|
||||||
format,
|
format,
|
||||||
|
descriptor.Set,
|
||||||
descriptor.Binding,
|
descriptor.Binding,
|
||||||
descriptor.ArrayLength,
|
descriptor.ArrayLength,
|
||||||
descriptor.CbufSlot,
|
descriptor.CbufSlot,
|
||||||
|
|
|
@ -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 = 5936;
|
private const uint CodeGenVersion = 6870;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
|
|
@ -51,7 +51,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
_reservedImages = rrc.ReservedImages;
|
_reservedImages = rrc.ReservedImages;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CreateConstantBufferBinding(int index)
|
public SetBindingPair CreateConstantBufferBinding(int index)
|
||||||
{
|
{
|
||||||
int binding;
|
int binding;
|
||||||
|
|
||||||
|
@ -64,10 +64,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
binding = _resourceCounts.UniformBuffersCount++;
|
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;
|
int binding;
|
||||||
|
|
||||||
|
@ -96,10 +96,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
_resourceCounts.ImagesCount += count;
|
_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;
|
int binding;
|
||||||
|
|
||||||
|
@ -112,10 +112,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
binding = _resourceCounts.StorageBuffersCount++;
|
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;
|
int binding;
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
_resourceCounts.TexturesCount += count;
|
_resourceCounts.TexturesCount += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
return binding + _reservedTextures;
|
return new SetBindingPair(_context.Capabilities.TextureSetIndex, binding + _reservedTextures);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetBindingFromIndex(int index, uint maxPerStage, string resourceName)
|
private int GetBindingFromIndex(int index, uint maxPerStage, string resourceName)
|
||||||
|
@ -183,6 +183,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
return maxPerStage * Constants.ShaderStages;
|
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 int QueryHostGatherBiasPrecision() => _context.Capabilities.GatherBiasPrecision;
|
||||||
|
|
||||||
public bool QueryHostReducedPrecision() => _context.Capabilities.ReduceShaderPrecision;
|
public bool QueryHostReducedPrecision() => _context.Capabilities.ReduceShaderPrecision;
|
||||||
|
|
|
@ -24,5 +24,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// Total of images used by the shaders.
|
/// Total of images used by the shaders.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ImagesCount;
|
public int ImagesCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total of extra sets used by the shaders.
|
||||||
|
/// </summary>
|
||||||
|
public int SetsCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Shader
|
namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
@ -9,13 +10,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class ShaderInfoBuilder
|
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 =
|
private const ResourceStages SupportBufferStages =
|
||||||
ResourceStages.Compute |
|
ResourceStages.Compute |
|
||||||
ResourceStages.Vertex |
|
ResourceStages.Vertex |
|
||||||
|
@ -36,8 +30,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
private readonly int _reservedTextures;
|
private readonly int _reservedTextures;
|
||||||
private readonly int _reservedImages;
|
private readonly int _reservedImages;
|
||||||
|
|
||||||
private readonly List<ResourceDescriptor>[] _resourceDescriptors;
|
private List<ResourceDescriptor>[] _resourceDescriptors;
|
||||||
private readonly List<ResourceUsage>[] _resourceUsages;
|
private List<ResourceUsage>[] _resourceUsages;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new shader info builder.
|
/// Creates a new shader info builder.
|
||||||
|
@ -51,17 +45,27 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
|
|
||||||
_fragmentOutputMap = -1;
|
_fragmentOutputMap = -1;
|
||||||
|
|
||||||
_resourceDescriptors = new List<ResourceDescriptor>[TotalSets];
|
int uniformSetIndex = context.Capabilities.UniformBufferSetIndex;
|
||||||
_resourceUsages = new List<ResourceUsage>[TotalSets];
|
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();
|
_resourceDescriptors[index] = new();
|
||||||
_resourceUsages[index] = new();
|
_resourceUsages[index] = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
AddDescriptor(SupportBufferStages, ResourceType.UniformBuffer, UniformSetIndex, 0, 1);
|
AddDescriptor(SupportBufferStages, ResourceType.UniformBuffer, uniformSetIndex, 0, 1);
|
||||||
AddUsage(SupportBufferStages, ResourceType.UniformBuffer, UniformSetIndex, 0, 1);
|
AddUsage(SupportBufferStages, ResourceType.UniformBuffer, uniformSetIndex, 0, 1);
|
||||||
|
|
||||||
ResourceReservationCounts rrc = new(!context.Capabilities.SupportsTransformFeedback && tfEnabled, vertexAsCompute);
|
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.
|
// 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;
|
ResourceStages stages = vertexAsCompute ? ResourceStages.Compute | ResourceStages.Vertex : VtgStages;
|
||||||
|
|
||||||
PopulateDescriptorAndUsages(stages, ResourceType.UniformBuffer, UniformSetIndex, 1, rrc.ReservedConstantBuffers - 1);
|
PopulateDescriptorAndUsages(stages, ResourceType.UniformBuffer, uniformSetIndex, 1, rrc.ReservedConstantBuffers - 1);
|
||||||
PopulateDescriptorAndUsages(stages, ResourceType.StorageBuffer, StorageSetIndex, 0, rrc.ReservedStorageBuffers);
|
PopulateDescriptorAndUsages(stages, ResourceType.StorageBuffer, storageSetIndex, 0, rrc.ReservedStorageBuffers);
|
||||||
PopulateDescriptorAndUsages(stages, ResourceType.BufferTexture, TextureSetIndex, 0, rrc.ReservedTextures);
|
PopulateDescriptorAndUsages(stages, ResourceType.BufferTexture, textureSetIndex, 0, rrc.ReservedTextures);
|
||||||
PopulateDescriptorAndUsages(stages, ResourceType.BufferImage, ImageSetIndex, 0, rrc.ReservedImages);
|
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)
|
private void PopulateDescriptorAndUsages(ResourceStages stages, ResourceType type, int setIndex, int start, int count)
|
||||||
{
|
{
|
||||||
AddDescriptor(stages, type, setIndex, start, count);
|
AddDescriptor(stages, type, setIndex, start, count);
|
||||||
|
@ -127,18 +139,23 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
int textureBinding = _reservedTextures + stageIndex * texturesPerStage * 2;
|
int textureBinding = _reservedTextures + stageIndex * texturesPerStage * 2;
|
||||||
int imageBinding = _reservedImages + stageIndex * imagesPerStage * 2;
|
int imageBinding = _reservedImages + stageIndex * imagesPerStage * 2;
|
||||||
|
|
||||||
AddDescriptor(stages, ResourceType.UniformBuffer, UniformSetIndex, uniformBinding, uniformsPerStage);
|
int uniformSetIndex = _context.Capabilities.UniformBufferSetIndex;
|
||||||
AddDescriptor(stages, ResourceType.StorageBuffer, StorageSetIndex, storageBinding, storagesPerStage);
|
int storageSetIndex = _context.Capabilities.StorageBufferSetIndex;
|
||||||
AddDualDescriptor(stages, ResourceType.TextureAndSampler, ResourceType.BufferTexture, TextureSetIndex, textureBinding, texturesPerStage);
|
int textureSetIndex = _context.Capabilities.TextureSetIndex;
|
||||||
AddDualDescriptor(stages, ResourceType.Image, ResourceType.BufferImage, ImageSetIndex, imageBinding, imagesPerStage);
|
int imageSetIndex = _context.Capabilities.ImageSetIndex;
|
||||||
|
|
||||||
AddArrayDescriptors(info.Textures, stages, TextureSetIndex, isImage: false);
|
AddDescriptor(stages, ResourceType.UniformBuffer, uniformSetIndex, uniformBinding, uniformsPerStage);
|
||||||
AddArrayDescriptors(info.Images, stages, TextureSetIndex, isImage: true);
|
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);
|
AddArrayDescriptors(info.Textures, stages, isImage: false);
|
||||||
AddUsage(info.SBuffers, stages, StorageSetIndex, isStorage: true);
|
AddArrayDescriptors(info.Images, stages, isImage: true);
|
||||||
AddUsage(info.Textures, stages, TextureSetIndex, isImage: false);
|
|
||||||
AddUsage(info.Images, stages, ImageSetIndex, 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>
|
/// <summary>
|
||||||
|
@ -177,9 +194,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="textures">Textures to be added</param>
|
/// <param name="textures">Textures to be added</param>
|
||||||
/// <param name="stages">Stages where the textures are used</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>
|
/// <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)
|
foreach (TextureDescriptor texture in textures)
|
||||||
{
|
{
|
||||||
|
@ -187,7 +203,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
{
|
{
|
||||||
ResourceType type = GetTextureResourceType(texture, isImage);
|
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>
|
/// </summary>
|
||||||
/// <param name="buffers">Buffers to be added</param>
|
/// <param name="buffers">Buffers to be added</param>
|
||||||
/// <param name="stages">Stages where the buffers are used</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>
|
/// <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)
|
foreach (BufferDescriptor buffer in buffers)
|
||||||
{
|
{
|
||||||
_resourceUsages[setIndex].Add(new ResourceUsage(
|
GetUsages(buffer.Set).Add(new ResourceUsage(
|
||||||
buffer.Binding,
|
buffer.Binding,
|
||||||
1,
|
1,
|
||||||
isStorage ? ResourceType.StorageBuffer : ResourceType.UniformBuffer,
|
isStorage ? ResourceType.StorageBuffer : ResourceType.UniformBuffer,
|
||||||
|
@ -232,18 +247,65 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="textures">Textures to be added</param>
|
/// <param name="textures">Textures to be added</param>
|
||||||
/// <param name="stages">Stages where the textures are used</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>
|
/// <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)
|
foreach (TextureDescriptor texture in textures)
|
||||||
{
|
{
|
||||||
ResourceType type = GetTextureResourceType(texture, isImage);
|
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)
|
private static ResourceType GetTextureResourceType(TextureDescriptor texture, bool isImage)
|
||||||
{
|
{
|
||||||
bool isBuffer = (texture.Type & SamplerType.Mask) == SamplerType.TextureBuffer;
|
bool isBuffer = (texture.Type & SamplerType.Mask) == SamplerType.TextureBuffer;
|
||||||
|
@ -278,10 +340,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
/// <returns>Shader information</returns>
|
/// <returns>Shader information</returns>
|
||||||
public ShaderInfo Build(ProgramPipelineState? pipeline, bool fromCache = false)
|
public ShaderInfo Build(ProgramPipelineState? pipeline, bool fromCache = false)
|
||||||
{
|
{
|
||||||
var descriptors = new ResourceDescriptorCollection[TotalSets];
|
int totalSets = _resourceDescriptors.Length;
|
||||||
var usages = new ResourceUsageCollection[TotalSets];
|
|
||||||
|
|
||||||
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());
|
descriptors[index] = new ResourceDescriptorCollection(_resourceDescriptors[index].ToArray().AsReadOnly());
|
||||||
usages[index] = new ResourceUsageCollection(_resourceUsages[index].ToArray().AsReadOnly());
|
usages[index] = new ResourceUsageCollection(_resourceUsages[index].ToArray().AsReadOnly());
|
||||||
|
|
|
@ -187,6 +187,12 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
|
supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
|
||||||
supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
|
supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
|
||||||
supportsDepthClipControl: true,
|
supportsDepthClipControl: true,
|
||||||
|
uniformBufferSetIndex: 0,
|
||||||
|
storageBufferSetIndex: 1,
|
||||||
|
textureSetIndex: 2,
|
||||||
|
imageSetIndex: 3,
|
||||||
|
extraSetBaseIndex: 0,
|
||||||
|
maximumExtraSets: 0,
|
||||||
maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver?
|
maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver?
|
||||||
maximumStorageBuffersPerStage: 16,
|
maximumStorageBuffersPerStage: 16,
|
||||||
maximumTexturesPerStage: 32,
|
maximumTexturesPerStage: 32,
|
||||||
|
|
|
@ -963,6 +963,11 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
(array as ImageArray).Bind(binding);
|
(array as ImageArray).Bind(binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("OpenGL does not support descriptor sets.");
|
||||||
|
}
|
||||||
|
|
||||||
public void SetIndexBuffer(BufferRange buffer, IndexType type)
|
public void SetIndexBuffer(BufferRange buffer, IndexType type)
|
||||||
{
|
{
|
||||||
_elementsType = type.Convert();
|
_elementsType = type.Convert();
|
||||||
|
@ -1312,6 +1317,11 @@ namespace Ryujinx.Graphics.OpenGL
|
||||||
(array as TextureArray).Bind(binding);
|
(array as TextureArray).Bind(binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("OpenGL does not support descriptor sets.");
|
||||||
|
}
|
||||||
|
|
||||||
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
|
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
|
||||||
{
|
{
|
||||||
if (_tfEnabled)
|
if (_tfEnabled)
|
||||||
|
|
|
@ -4,14 +4,16 @@ namespace Ryujinx.Graphics.Shader
|
||||||
{
|
{
|
||||||
// New fields should be added to the end of the struct to keep disk shader cache compatibility.
|
// New fields should be added to the end of the struct to keep disk shader cache compatibility.
|
||||||
|
|
||||||
|
public readonly int Set;
|
||||||
public readonly int Binding;
|
public readonly int Binding;
|
||||||
public readonly byte Slot;
|
public readonly byte Slot;
|
||||||
public readonly byte SbCbSlot;
|
public readonly byte SbCbSlot;
|
||||||
public readonly ushort SbCbOffset;
|
public readonly ushort SbCbOffset;
|
||||||
public readonly BufferUsageFlags Flags;
|
public readonly BufferUsageFlags Flags;
|
||||||
|
|
||||||
public BufferDescriptor(int binding, int slot)
|
public BufferDescriptor(int set, int binding, int slot)
|
||||||
{
|
{
|
||||||
|
Set = set;
|
||||||
Binding = binding;
|
Binding = binding;
|
||||||
Slot = (byte)slot;
|
Slot = (byte)slot;
|
||||||
SbCbSlot = 0;
|
SbCbSlot = 0;
|
||||||
|
@ -19,8 +21,9 @@ namespace Ryujinx.Graphics.Shader
|
||||||
Flags = BufferUsageFlags.None;
|
Flags = BufferUsageFlags.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BufferDescriptor(int binding, int slot, int sbCbSlot, int sbCbOffset, BufferUsageFlags flags)
|
public BufferDescriptor(int set, int binding, int slot, int sbCbSlot, int sbCbOffset, BufferUsageFlags flags)
|
||||||
{
|
{
|
||||||
|
Set = set;
|
||||||
Binding = binding;
|
Binding = binding;
|
||||||
Slot = (byte)slot;
|
Slot = (byte)slot;
|
||||||
SbCbSlot = (byte)sbCbSlot;
|
SbCbSlot = (byte)sbCbSlot;
|
||||||
|
|
|
@ -462,7 +462,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
context.Properties.Textures.TryGetValue(texOp.Binding, out TextureDefinition definition);
|
context.Properties.Textures.TryGetValue(texOp.GetTextureSetAndBinding(), out TextureDefinition definition);
|
||||||
bool hasLod = !definition.Type.HasFlag(SamplerType.Multisample) && (definition.Type & SamplerType.Mask) != SamplerType.TextureBuffer;
|
bool hasLod = !definition.Type.HasFlag(SamplerType.Multisample) && (definition.Type & SamplerType.Mask) != SamplerType.TextureBuffer;
|
||||||
string texCall;
|
string texCall;
|
||||||
|
|
||||||
|
@ -639,7 +639,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
|
|
||||||
private static string GetSamplerName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex)
|
private static string GetSamplerName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex)
|
||||||
{
|
{
|
||||||
TextureDefinition textureDefinition = context.Properties.Textures[texOp.Binding];
|
TextureDefinition textureDefinition = context.Properties.Textures[texOp.GetTextureSetAndBinding()];
|
||||||
string name = textureDefinition.Name;
|
string name = textureDefinition.Name;
|
||||||
|
|
||||||
if (textureDefinition.ArrayLength != 1)
|
if (textureDefinition.ArrayLength != 1)
|
||||||
|
@ -649,7 +649,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
|
|
||||||
if (texOp.IsSeparate)
|
if (texOp.IsSeparate)
|
||||||
{
|
{
|
||||||
TextureDefinition samplerDefinition = context.Properties.Textures[texOp.SamplerBinding];
|
TextureDefinition samplerDefinition = context.Properties.Textures[texOp.GetSamplerSetAndBinding()];
|
||||||
string samplerName = samplerDefinition.Name;
|
string samplerName = samplerDefinition.Name;
|
||||||
|
|
||||||
if (samplerDefinition.ArrayLength != 1)
|
if (samplerDefinition.ArrayLength != 1)
|
||||||
|
@ -665,7 +665,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
||||||
|
|
||||||
private static string GetImageName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex)
|
private static string GetImageName(CodeGenContext context, AstTextureOperation texOp, ref int srcIndex)
|
||||||
{
|
{
|
||||||
TextureDefinition definition = context.Properties.Images[texOp.Binding];
|
TextureDefinition definition = context.Properties.Images[texOp.GetTextureSetAndBinding()];
|
||||||
string name = definition.Name;
|
string name = definition.Name;
|
||||||
|
|
||||||
if (definition.ArrayLength != 1)
|
if (definition.ArrayLength != 1)
|
||||||
|
|
|
@ -33,9 +33,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
public Dictionary<int, Instruction> LocalMemories { get; } = new();
|
public Dictionary<int, Instruction> LocalMemories { get; } = new();
|
||||||
public Dictionary<int, Instruction> SharedMemories { get; } = new();
|
public Dictionary<int, Instruction> SharedMemories { get; } = new();
|
||||||
|
|
||||||
public Dictionary<int, SamplerType> SamplersTypes { get; } = new();
|
public Dictionary<SetBindingPair, SamplerType> SamplersTypes { get; } = new();
|
||||||
public Dictionary<int, SamplerDeclaration> Samplers { get; } = new();
|
public Dictionary<SetBindingPair, SamplerDeclaration> Samplers { get; } = new();
|
||||||
public Dictionary<int, ImageDeclaration> Images { get; } = new();
|
public Dictionary<SetBindingPair, ImageDeclaration> Images { get; } = new();
|
||||||
|
|
||||||
public Dictionary<IoDefinition, Instruction> Inputs { get; } = new();
|
public Dictionary<IoDefinition, Instruction> Inputs { get; } = new();
|
||||||
public Dictionary<IoDefinition, Instruction> Outputs { get; } = new();
|
public Dictionary<IoDefinition, Instruction> Outputs { get; } = new();
|
||||||
|
|
|
@ -208,13 +208,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
|
|
||||||
var sampledImageVariable = context.Variable(sampledImageArrayPointerType, StorageClass.UniformConstant);
|
var sampledImageVariable = context.Variable(sampledImageArrayPointerType, StorageClass.UniformConstant);
|
||||||
|
|
||||||
context.Samplers.Add(sampler.Binding, new SamplerDeclaration(
|
context.Samplers.Add(new(sampler.Set, sampler.Binding), new SamplerDeclaration(
|
||||||
imageType,
|
imageType,
|
||||||
sampledImageType,
|
sampledImageType,
|
||||||
sampledImagePointerType,
|
sampledImagePointerType,
|
||||||
sampledImageVariable,
|
sampledImageVariable,
|
||||||
sampler.ArrayLength != 1));
|
sampler.ArrayLength != 1));
|
||||||
context.SamplersTypes.Add(sampler.Binding, sampler.Type);
|
context.SamplersTypes.Add(new(sampler.Set, sampler.Binding), sampler.Type);
|
||||||
|
|
||||||
context.Name(sampledImageVariable, sampler.Name);
|
context.Name(sampledImageVariable, sampler.Name);
|
||||||
context.Decorate(sampledImageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
|
context.Decorate(sampledImageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
|
||||||
|
@ -256,7 +256,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
|
|
||||||
var imageVariable = context.Variable(imageArrayPointerType, StorageClass.UniformConstant);
|
var imageVariable = context.Variable(imageArrayPointerType, StorageClass.UniformConstant);
|
||||||
|
|
||||||
context.Images.Add(image.Binding, new ImageDeclaration(imageType, imagePointerType, imageVariable, image.ArrayLength != 1));
|
context.Images.Add(new(image.Set, image.Binding), new ImageDeclaration(imageType, imagePointerType, imageVariable, image.ArrayLength != 1));
|
||||||
|
|
||||||
context.Name(imageVariable, image.Name);
|
context.Name(imageVariable, image.Name);
|
||||||
context.Decorate(imageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
|
context.Decorate(imageVariable, Decoration.DescriptorSet, (LiteralInteger)setIndex);
|
||||||
|
|
|
@ -602,7 +602,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
return context.Get(type, texOp.GetSource(srcIndex++));
|
return context.Get(type, texOp.GetSource(srcIndex++));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageDeclaration declaration = context.Images[texOp.Binding];
|
ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()];
|
||||||
SpvInstruction image = declaration.Image;
|
SpvInstruction image = declaration.Image;
|
||||||
|
|
||||||
SpvInstruction resultType = context.GetType(componentType);
|
SpvInstruction resultType = context.GetType(componentType);
|
||||||
|
@ -681,7 +681,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
return context.Get(type, texOp.GetSource(srcIndex++));
|
return context.Get(type, texOp.GetSource(srcIndex++));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageDeclaration declaration = context.Images[texOp.Binding];
|
ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()];
|
||||||
SpvInstruction image = declaration.Image;
|
SpvInstruction image = declaration.Image;
|
||||||
|
|
||||||
if (declaration.IsIndexed)
|
if (declaration.IsIndexed)
|
||||||
|
@ -738,7 +738,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
return context.Get(type, texOp.GetSource(srcIndex++));
|
return context.Get(type, texOp.GetSource(srcIndex++));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageDeclaration declaration = context.Images[texOp.Binding];
|
ImageDeclaration declaration = context.Images[texOp.GetTextureSetAndBinding()];
|
||||||
SpvInstruction image = declaration.Image;
|
SpvInstruction image = declaration.Image;
|
||||||
|
|
||||||
if (declaration.IsIndexed)
|
if (declaration.IsIndexed)
|
||||||
|
@ -837,7 +837,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
return context.Get(type, texOp.GetSource(srcIndex++));
|
return context.Get(type, texOp.GetSource(srcIndex++));
|
||||||
}
|
}
|
||||||
|
|
||||||
SamplerDeclaration declaration = context.Samplers[texOp.Binding];
|
SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
|
||||||
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
|
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
|
||||||
|
|
||||||
int pCount = texOp.Type.GetDimensions();
|
int pCount = texOp.Type.GetDimensions();
|
||||||
|
@ -1161,7 +1161,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
return context.Get(type, texOp.GetSource(srcIndex++));
|
return context.Get(type, texOp.GetSource(srcIndex++));
|
||||||
}
|
}
|
||||||
|
|
||||||
SamplerDeclaration declaration = context.Samplers[texOp.Binding];
|
SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
|
||||||
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
|
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
|
||||||
|
|
||||||
int coordsCount = texOp.Type.GetDimensions();
|
int coordsCount = texOp.Type.GetDimensions();
|
||||||
|
@ -1433,7 +1433,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
|
|
||||||
int srcIndex = 0;
|
int srcIndex = 0;
|
||||||
|
|
||||||
SamplerDeclaration declaration = context.Samplers[texOp.Binding];
|
SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
|
||||||
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
|
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
|
||||||
|
|
||||||
image = context.Image(declaration.ImageType, image);
|
image = context.Image(declaration.ImageType, image);
|
||||||
|
@ -1449,7 +1449,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
|
|
||||||
int srcIndex = 0;
|
int srcIndex = 0;
|
||||||
|
|
||||||
SamplerDeclaration declaration = context.Samplers[texOp.Binding];
|
SamplerDeclaration declaration = context.Samplers[texOp.GetTextureSetAndBinding()];
|
||||||
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
|
SpvInstruction image = GenerateSampledImageLoad(context, texOp, declaration, ref srcIndex);
|
||||||
|
|
||||||
image = context.Image(declaration.ImageType, image);
|
image = context.Image(declaration.ImageType, image);
|
||||||
|
@ -1460,7 +1460,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var type = context.SamplersTypes[texOp.Binding];
|
var type = context.SamplersTypes[texOp.GetTextureSetAndBinding()];
|
||||||
bool hasLod = !type.HasFlag(SamplerType.Multisample) && type != SamplerType.TextureBuffer;
|
bool hasLod = !type.HasFlag(SamplerType.Multisample) && type != SamplerType.TextureBuffer;
|
||||||
|
|
||||||
int dimensions = (type & SamplerType.Mask) == SamplerType.TextureCube ? 2 : type.GetDimensions();
|
int dimensions = (type & SamplerType.Mask) == SamplerType.TextureCube ? 2 : type.GetDimensions();
|
||||||
|
@ -1889,7 +1889,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||||
{
|
{
|
||||||
image = context.Load(declaration.ImageType, image);
|
image = context.Load(declaration.ImageType, image);
|
||||||
|
|
||||||
SamplerDeclaration samplerDeclaration = context.Samplers[texOp.SamplerBinding];
|
SamplerDeclaration samplerDeclaration = context.Samplers[texOp.GetSamplerSetAndBinding()];
|
||||||
|
|
||||||
SpvInstruction sampler = samplerDeclaration.Image;
|
SpvInstruction sampler = samplerDeclaration.Image;
|
||||||
|
|
||||||
|
|
|
@ -27,34 +27,43 @@ namespace Ryujinx.Graphics.Shader
|
||||||
ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize);
|
ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries the binding number of a constant buffer.
|
/// Gets the binding number of a constant buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">Constant buffer index</param>
|
/// <param name="index">Constant buffer index</param>
|
||||||
/// <returns>Binding number</returns>
|
/// <returns>Binding number</returns>
|
||||||
int CreateConstantBufferBinding(int index);
|
SetBindingPair CreateConstantBufferBinding(int index);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries the binding number of an image.
|
/// Gets the binding number of an image.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="count">For array of images, the number of elements of the array, otherwise it should be 1</param>
|
/// <param name="count">For array of images, the number of elements of the array, otherwise it should be 1</param>
|
||||||
/// <param name="isBuffer">Indicates if the image is a buffer image</param>
|
/// <param name="isBuffer">Indicates if the image is a buffer image</param>
|
||||||
/// <returns>Binding number</returns>
|
/// <returns>Binding number</returns>
|
||||||
int CreateImageBinding(int count, bool isBuffer);
|
SetBindingPair CreateImageBinding(int count, bool isBuffer);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries the binding number of a storage buffer.
|
/// Gets the binding number of a storage buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">Storage buffer index</param>
|
/// <param name="index">Storage buffer index</param>
|
||||||
/// <returns>Binding number</returns>
|
/// <returns>Binding number</returns>
|
||||||
int CreateStorageBufferBinding(int index);
|
SetBindingPair CreateStorageBufferBinding(int index);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries the binding number of a texture.
|
/// Gets the binding number of a texture.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="count">For array of textures, the number of elements of the array, otherwise it should be 1</param>
|
/// <param name="count">For array of textures, the number of elements of the array, otherwise it should be 1</param>
|
||||||
/// <param name="isBuffer">Indicates if the texture is a buffer texture</param>
|
/// <param name="isBuffer">Indicates if the texture is a buffer texture</param>
|
||||||
/// <returns>Binding number</returns>
|
/// <returns>Binding number</returns>
|
||||||
int CreateTextureBinding(int count, bool isBuffer);
|
SetBindingPair CreateTextureBinding(int count, bool isBuffer);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the set index for an additional set, or -1 if there's no extra set available.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Extra set index, or -1 if not available</returns>
|
||||||
|
int CreateExtraSet()
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Queries Local Size X for compute shaders.
|
/// Queries Local Size X for compute shaders.
|
||||||
|
|
|
@ -278,7 +278,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
flags |= TextureFlags.Bindless;
|
flags |= TextureFlags.Bindless;
|
||||||
}
|
}
|
||||||
|
|
||||||
int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||||
Instruction.ImageAtomic,
|
Instruction.ImageAtomic,
|
||||||
type,
|
type,
|
||||||
format,
|
format,
|
||||||
|
@ -286,7 +286,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
TextureOperation.DefaultCbufSlot,
|
TextureOperation.DefaultCbufSlot,
|
||||||
imm);
|
imm);
|
||||||
|
|
||||||
Operand res = context.ImageAtomic(type, format, flags, binding, sources);
|
Operand res = context.ImageAtomic(type, format, flags, setAndBinding, sources);
|
||||||
|
|
||||||
context.Copy(d, res);
|
context.Copy(d, res);
|
||||||
}
|
}
|
||||||
|
@ -389,7 +389,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
TextureFormat format = isBindless ? TextureFormat.Unknown : ShaderProperties.GetTextureFormat(context.TranslatorContext.GpuAccessor, handle);
|
TextureFormat format = isBindless ? TextureFormat.Unknown : ShaderProperties.GetTextureFormat(context.TranslatorContext.GpuAccessor, handle);
|
||||||
|
|
||||||
int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||||
Instruction.ImageLoad,
|
Instruction.ImageLoad,
|
||||||
type,
|
type,
|
||||||
format,
|
format,
|
||||||
|
@ -397,7 +397,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
TextureOperation.DefaultCbufSlot,
|
TextureOperation.DefaultCbufSlot,
|
||||||
handle);
|
handle);
|
||||||
|
|
||||||
context.ImageLoad(type, format, flags, binding, (int)componentMask, dests, sources);
|
context.ImageLoad(type, format, flags, setAndBinding, (int)componentMask, dests, sources);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -432,7 +432,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
TextureFormat format = GetTextureFormat(size);
|
TextureFormat format = GetTextureFormat(size);
|
||||||
|
|
||||||
int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||||
Instruction.ImageLoad,
|
Instruction.ImageLoad,
|
||||||
type,
|
type,
|
||||||
format,
|
format,
|
||||||
|
@ -440,7 +440,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
TextureOperation.DefaultCbufSlot,
|
TextureOperation.DefaultCbufSlot,
|
||||||
handle);
|
handle);
|
||||||
|
|
||||||
context.ImageLoad(type, format, flags, binding, compMask, dests, sources);
|
context.ImageLoad(type, format, flags, setAndBinding, compMask, dests, sources);
|
||||||
|
|
||||||
switch (size)
|
switch (size)
|
||||||
{
|
{
|
||||||
|
@ -552,7 +552,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
flags |= TextureFlags.Bindless;
|
flags |= TextureFlags.Bindless;
|
||||||
}
|
}
|
||||||
|
|
||||||
int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||||
Instruction.ImageAtomic,
|
Instruction.ImageAtomic,
|
||||||
type,
|
type,
|
||||||
format,
|
format,
|
||||||
|
@ -560,7 +560,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
TextureOperation.DefaultCbufSlot,
|
TextureOperation.DefaultCbufSlot,
|
||||||
imm);
|
imm);
|
||||||
|
|
||||||
context.ImageAtomic(type, format, flags, binding, sources);
|
context.ImageAtomic(type, format, flags, setAndBinding, sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitSust(
|
private static void EmitSust(
|
||||||
|
@ -679,7 +679,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
flags |= TextureFlags.Coherent;
|
flags |= TextureFlags.Coherent;
|
||||||
}
|
}
|
||||||
|
|
||||||
int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||||
Instruction.ImageStore,
|
Instruction.ImageStore,
|
||||||
type,
|
type,
|
||||||
format,
|
format,
|
||||||
|
@ -687,7 +687,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
TextureOperation.DefaultCbufSlot,
|
TextureOperation.DefaultCbufSlot,
|
||||||
handle);
|
handle);
|
||||||
|
|
||||||
context.ImageStore(type, format, flags, binding, sources);
|
context.ImageStore(type, format, flags, setAndBinding, sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetComponentSizeInBytesLog2(SuatomSize size)
|
private static int GetComponentSizeInBytesLog2(SuatomSize size)
|
||||||
|
|
|
@ -885,7 +885,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
return Register(dest++, RegisterType.Gpr);
|
return Register(dest++, RegisterType.Gpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
SetBindingPair setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||||
Instruction.Lod,
|
Instruction.Lod,
|
||||||
type,
|
type,
|
||||||
TextureFormat.Unknown,
|
TextureFormat.Unknown,
|
||||||
|
@ -913,7 +913,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The instruction component order is the inverse of GLSL's.
|
// The instruction component order is the inverse of GLSL's.
|
||||||
Operand res = context.Lod(type, flags, binding, compIndex ^ 1, sources);
|
Operand res = context.Lod(type, flags, setAndBinding, compIndex ^ 1, sources);
|
||||||
|
|
||||||
res = context.FPMultiply(res, ConstF(256.0f));
|
res = context.FPMultiply(res, ConstF(256.0f));
|
||||||
|
|
||||||
|
@ -1116,12 +1116,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None;
|
TextureFlags flags = isBindless ? TextureFlags.Bindless : TextureFlags.None;
|
||||||
int binding;
|
SetBindingPair setAndBinding;
|
||||||
|
|
||||||
switch (query)
|
switch (query)
|
||||||
{
|
{
|
||||||
case TexQuery.TexHeaderDimension:
|
case TexQuery.TexHeaderDimension:
|
||||||
binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||||
Instruction.TextureQuerySize,
|
Instruction.TextureQuerySize,
|
||||||
type,
|
type,
|
||||||
TextureFormat.Unknown,
|
TextureFormat.Unknown,
|
||||||
|
@ -1140,13 +1140,13 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Copy(d, context.TextureQuerySize(type, flags, binding, compIndex, sources));
|
context.Copy(d, context.TextureQuerySize(type, flags, setAndBinding, compIndex, sources));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TexQuery.TexHeaderTextureType:
|
case TexQuery.TexHeaderTextureType:
|
||||||
binding = isBindless ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
setAndBinding = isBindless ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||||
Instruction.TextureQuerySamples,
|
Instruction.TextureQuerySamples,
|
||||||
type,
|
type,
|
||||||
TextureFormat.Unknown,
|
TextureFormat.Unknown,
|
||||||
|
@ -1171,7 +1171,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
|
||||||
if (d != null)
|
if (d != null)
|
||||||
{
|
{
|
||||||
context.Copy(d, context.TextureQuerySamples(type, flags, binding, sources));
|
context.Copy(d, context.TextureQuerySamples(type, flags, setAndBinding, sources));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1191,7 +1191,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
Operand[] dests,
|
Operand[] dests,
|
||||||
Operand[] sources)
|
Operand[] sources)
|
||||||
{
|
{
|
||||||
int binding = flags.HasFlag(TextureFlags.Bindless) ? 0 : context.ResourceManager.GetTextureOrImageBinding(
|
SetBindingPair setAndBinding = flags.HasFlag(TextureFlags.Bindless) ? default : context.ResourceManager.GetTextureOrImageBinding(
|
||||||
Instruction.TextureSample,
|
Instruction.TextureSample,
|
||||||
type,
|
type,
|
||||||
TextureFormat.Unknown,
|
TextureFormat.Unknown,
|
||||||
|
@ -1199,7 +1199,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
TextureOperation.DefaultCbufSlot,
|
TextureOperation.DefaultCbufSlot,
|
||||||
handle);
|
handle);
|
||||||
|
|
||||||
context.TextureSample(type, flags, binding, componentMask, dests, sources);
|
context.TextureSample(type, flags, setAndBinding, componentMask, dests, sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SamplerType ConvertSamplerType(TexDim dimensions)
|
private static SamplerType ConvertSamplerType(TexDim dimensions)
|
||||||
|
|
|
@ -8,7 +8,9 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||||
public TextureFormat Format { get; set; }
|
public TextureFormat Format { get; set; }
|
||||||
public TextureFlags Flags { get; private set; }
|
public TextureFlags Flags { get; private set; }
|
||||||
|
|
||||||
|
public int Set { get; private set; }
|
||||||
public int Binding { get; private set; }
|
public int Binding { get; private set; }
|
||||||
|
public int SamplerSet { get; private set; }
|
||||||
public int SamplerBinding { get; private set; }
|
public int SamplerBinding { get; private set; }
|
||||||
|
|
||||||
public TextureOperation(
|
public TextureOperation(
|
||||||
|
@ -16,6 +18,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||||
SamplerType type,
|
SamplerType type,
|
||||||
TextureFormat format,
|
TextureFormat format,
|
||||||
TextureFlags flags,
|
TextureFlags flags,
|
||||||
|
int set,
|
||||||
int binding,
|
int binding,
|
||||||
int compIndex,
|
int compIndex,
|
||||||
Operand[] dests,
|
Operand[] dests,
|
||||||
|
@ -24,24 +27,28 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||||
Type = type;
|
Type = type;
|
||||||
Format = format;
|
Format = format;
|
||||||
Flags = flags;
|
Flags = flags;
|
||||||
|
Set = set;
|
||||||
Binding = binding;
|
Binding = binding;
|
||||||
|
SamplerSet = -1;
|
||||||
SamplerBinding = -1;
|
SamplerBinding = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TurnIntoArray(int binding)
|
public void TurnIntoArray(SetBindingPair setAndBinding)
|
||||||
{
|
{
|
||||||
Flags &= ~TextureFlags.Bindless;
|
Flags &= ~TextureFlags.Bindless;
|
||||||
Binding = binding;
|
Set = setAndBinding.SetIndex;
|
||||||
|
Binding = setAndBinding.Binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TurnIntoArray(int textureBinding, int samplerBinding)
|
public void TurnIntoArray(SetBindingPair textureSetAndBinding, SetBindingPair samplerSetAndBinding)
|
||||||
{
|
{
|
||||||
TurnIntoArray(textureBinding);
|
TurnIntoArray(textureSetAndBinding);
|
||||||
|
|
||||||
SamplerBinding = samplerBinding;
|
SamplerSet = samplerSetAndBinding.SetIndex;
|
||||||
|
SamplerBinding = samplerSetAndBinding.Binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetBinding(int binding)
|
public void SetBinding(SetBindingPair setAndBinding)
|
||||||
{
|
{
|
||||||
if ((Flags & TextureFlags.Bindless) != 0)
|
if ((Flags & TextureFlags.Bindless) != 0)
|
||||||
{
|
{
|
||||||
|
@ -50,7 +57,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
||||||
RemoveSource(0);
|
RemoveSource(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Binding = binding;
|
Set = setAndBinding.SetIndex;
|
||||||
|
Binding = setAndBinding.Binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetLodLevelFlag()
|
public void SetLodLevelFlag()
|
||||||
|
|
4
src/Ryujinx.Graphics.Shader/SetBindingPair.cs
Normal file
4
src/Ryujinx.Graphics.Shader/SetBindingPair.cs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
namespace Ryujinx.Graphics.Shader
|
||||||
|
{
|
||||||
|
public readonly record struct SetBindingPair(int SetIndex, int Binding);
|
||||||
|
}
|
|
@ -8,7 +8,9 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
public TextureFormat Format { get; }
|
public TextureFormat Format { get; }
|
||||||
public TextureFlags Flags { get; }
|
public TextureFlags Flags { get; }
|
||||||
|
|
||||||
|
public int Set { get; }
|
||||||
public int Binding { get; }
|
public int Binding { get; }
|
||||||
|
public int SamplerSet { get; }
|
||||||
public int SamplerBinding { get; }
|
public int SamplerBinding { get; }
|
||||||
|
|
||||||
public bool IsSeparate => SamplerBinding >= 0;
|
public bool IsSeparate => SamplerBinding >= 0;
|
||||||
|
@ -18,7 +20,9 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
SamplerType type,
|
SamplerType type,
|
||||||
TextureFormat format,
|
TextureFormat format,
|
||||||
TextureFlags flags,
|
TextureFlags flags,
|
||||||
|
int set,
|
||||||
int binding,
|
int binding,
|
||||||
|
int samplerSet,
|
||||||
int samplerBinding,
|
int samplerBinding,
|
||||||
int index,
|
int index,
|
||||||
params IAstNode[] sources) : base(inst, StorageKind.None, false, index, sources, sources.Length)
|
params IAstNode[] sources) : base(inst, StorageKind.None, false, index, sources, sources.Length)
|
||||||
|
@ -26,8 +30,20 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
Type = type;
|
Type = type;
|
||||||
Format = format;
|
Format = format;
|
||||||
Flags = flags;
|
Flags = flags;
|
||||||
|
Set = set;
|
||||||
Binding = binding;
|
Binding = binding;
|
||||||
|
SamplerSet = samplerSet;
|
||||||
SamplerBinding = samplerBinding;
|
SamplerBinding = samplerBinding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SetBindingPair GetTextureSetAndBinding()
|
||||||
|
{
|
||||||
|
return new SetBindingPair(Set, Binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SetBindingPair GetSamplerSetAndBinding()
|
||||||
|
{
|
||||||
|
return new SetBindingPair(SamplerSet, SamplerBinding);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,15 +6,15 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
{
|
{
|
||||||
private readonly Dictionary<int, BufferDefinition> _constantBuffers;
|
private readonly Dictionary<int, BufferDefinition> _constantBuffers;
|
||||||
private readonly Dictionary<int, BufferDefinition> _storageBuffers;
|
private readonly Dictionary<int, BufferDefinition> _storageBuffers;
|
||||||
private readonly Dictionary<int, TextureDefinition> _textures;
|
private readonly Dictionary<SetBindingPair, TextureDefinition> _textures;
|
||||||
private readonly Dictionary<int, TextureDefinition> _images;
|
private readonly Dictionary<SetBindingPair, TextureDefinition> _images;
|
||||||
private readonly Dictionary<int, MemoryDefinition> _localMemories;
|
private readonly Dictionary<int, MemoryDefinition> _localMemories;
|
||||||
private readonly Dictionary<int, MemoryDefinition> _sharedMemories;
|
private readonly Dictionary<int, MemoryDefinition> _sharedMemories;
|
||||||
|
|
||||||
public IReadOnlyDictionary<int, BufferDefinition> ConstantBuffers => _constantBuffers;
|
public IReadOnlyDictionary<int, BufferDefinition> ConstantBuffers => _constantBuffers;
|
||||||
public IReadOnlyDictionary<int, BufferDefinition> StorageBuffers => _storageBuffers;
|
public IReadOnlyDictionary<int, BufferDefinition> StorageBuffers => _storageBuffers;
|
||||||
public IReadOnlyDictionary<int, TextureDefinition> Textures => _textures;
|
public IReadOnlyDictionary<SetBindingPair, TextureDefinition> Textures => _textures;
|
||||||
public IReadOnlyDictionary<int, TextureDefinition> Images => _images;
|
public IReadOnlyDictionary<SetBindingPair, TextureDefinition> Images => _images;
|
||||||
public IReadOnlyDictionary<int, MemoryDefinition> LocalMemories => _localMemories;
|
public IReadOnlyDictionary<int, MemoryDefinition> LocalMemories => _localMemories;
|
||||||
public IReadOnlyDictionary<int, MemoryDefinition> SharedMemories => _sharedMemories;
|
public IReadOnlyDictionary<int, MemoryDefinition> SharedMemories => _sharedMemories;
|
||||||
|
|
||||||
|
@ -22,8 +22,8 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
{
|
{
|
||||||
_constantBuffers = new Dictionary<int, BufferDefinition>();
|
_constantBuffers = new Dictionary<int, BufferDefinition>();
|
||||||
_storageBuffers = new Dictionary<int, BufferDefinition>();
|
_storageBuffers = new Dictionary<int, BufferDefinition>();
|
||||||
_textures = new Dictionary<int, TextureDefinition>();
|
_textures = new Dictionary<SetBindingPair, TextureDefinition>();
|
||||||
_images = new Dictionary<int, TextureDefinition>();
|
_images = new Dictionary<SetBindingPair, TextureDefinition>();
|
||||||
_localMemories = new Dictionary<int, MemoryDefinition>();
|
_localMemories = new Dictionary<int, MemoryDefinition>();
|
||||||
_sharedMemories = new Dictionary<int, MemoryDefinition>();
|
_sharedMemories = new Dictionary<int, MemoryDefinition>();
|
||||||
}
|
}
|
||||||
|
@ -40,12 +40,12 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
|
|
||||||
public void AddOrUpdateTexture(TextureDefinition definition)
|
public void AddOrUpdateTexture(TextureDefinition definition)
|
||||||
{
|
{
|
||||||
_textures[definition.Binding] = definition;
|
_textures[new(definition.Set, definition.Binding)] = definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddOrUpdateImage(TextureDefinition definition)
|
public void AddOrUpdateImage(TextureDefinition definition)
|
||||||
{
|
{
|
||||||
_images[definition.Binding] = definition;
|
_images[new(definition.Set, definition.Binding)] = definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int AddLocalMemory(MemoryDefinition definition)
|
public int AddLocalMemory(MemoryDefinition definition)
|
||||||
|
|
|
@ -169,7 +169,17 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||||
|
|
||||||
AstTextureOperation GetAstTextureOperation(TextureOperation texOp)
|
AstTextureOperation GetAstTextureOperation(TextureOperation texOp)
|
||||||
{
|
{
|
||||||
return new AstTextureOperation(inst, texOp.Type, texOp.Format, texOp.Flags, texOp.Binding, texOp.SamplerBinding, texOp.Index, sources);
|
return new AstTextureOperation(
|
||||||
|
inst,
|
||||||
|
texOp.Type,
|
||||||
|
texOp.Format,
|
||||||
|
texOp.Flags,
|
||||||
|
texOp.Set,
|
||||||
|
texOp.Binding,
|
||||||
|
texOp.SamplerSet,
|
||||||
|
texOp.SamplerBinding,
|
||||||
|
texOp.Index,
|
||||||
|
sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
int componentsCount = BitOperations.PopCount((uint)operation.Index);
|
int componentsCount = BitOperations.PopCount((uint)operation.Index);
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
{
|
{
|
||||||
// New fields should be added to the end of the struct to keep disk shader cache compatibility.
|
// New fields should be added to the end of the struct to keep disk shader cache compatibility.
|
||||||
|
|
||||||
|
public readonly int Set;
|
||||||
public readonly int Binding;
|
public readonly int Binding;
|
||||||
|
|
||||||
public readonly SamplerType Type;
|
public readonly SamplerType Type;
|
||||||
|
@ -18,6 +19,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
public readonly TextureUsageFlags Flags;
|
public readonly TextureUsageFlags Flags;
|
||||||
|
|
||||||
public TextureDescriptor(
|
public TextureDescriptor(
|
||||||
|
int set,
|
||||||
int binding,
|
int binding,
|
||||||
SamplerType type,
|
SamplerType type,
|
||||||
TextureFormat format,
|
TextureFormat format,
|
||||||
|
@ -27,6 +29,7 @@ namespace Ryujinx.Graphics.Shader
|
||||||
bool separate,
|
bool separate,
|
||||||
TextureUsageFlags flags)
|
TextureUsageFlags flags)
|
||||||
{
|
{
|
||||||
|
Set = set;
|
||||||
Binding = binding;
|
Binding = binding;
|
||||||
Type = type;
|
Type = type;
|
||||||
Format = format;
|
Format = format;
|
||||||
|
|
|
@ -124,7 +124,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
this.TextureSample(
|
this.TextureSample(
|
||||||
SamplerType.TextureBuffer,
|
SamplerType.TextureBuffer,
|
||||||
TextureFlags.IntCoords,
|
TextureFlags.IntCoords,
|
||||||
ResourceManager.Reservations.IndexBufferTextureBinding,
|
ResourceManager.Reservations.GetIndexBufferTextureSetAndBinding(),
|
||||||
1,
|
1,
|
||||||
new[] { vertexIndexVr },
|
new[] { vertexIndexVr },
|
||||||
new[] { this.IAdd(ibBaseOffset, outputVertexOffset) });
|
new[] { this.IAdd(ibBaseOffset, outputVertexOffset) });
|
||||||
|
@ -145,7 +145,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
this.TextureSample(
|
this.TextureSample(
|
||||||
SamplerType.TextureBuffer,
|
SamplerType.TextureBuffer,
|
||||||
TextureFlags.IntCoords,
|
TextureFlags.IntCoords,
|
||||||
ResourceManager.Reservations.TopologyRemapBufferTextureBinding,
|
ResourceManager.Reservations.GetTopologyRemapBufferTextureSetAndBinding(),
|
||||||
1,
|
1,
|
||||||
new[] { vertexIndex },
|
new[] { vertexIndex },
|
||||||
new[] { this.IAdd(baseVertex, Const(index)) });
|
new[] { this.IAdd(baseVertex, Const(index)) });
|
||||||
|
|
|
@ -618,12 +618,21 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
SamplerType type,
|
SamplerType type,
|
||||||
TextureFormat format,
|
TextureFormat format,
|
||||||
TextureFlags flags,
|
TextureFlags flags,
|
||||||
int binding,
|
SetBindingPair setAndBinding,
|
||||||
Operand[] sources)
|
Operand[] sources)
|
||||||
{
|
{
|
||||||
Operand dest = Local();
|
Operand dest = Local();
|
||||||
|
|
||||||
context.Add(new TextureOperation(Instruction.ImageAtomic, type, format, flags, binding, 0, new[] { dest }, sources));
|
context.Add(new TextureOperation(
|
||||||
|
Instruction.ImageAtomic,
|
||||||
|
type,
|
||||||
|
format,
|
||||||
|
flags,
|
||||||
|
setAndBinding.SetIndex,
|
||||||
|
setAndBinding.Binding,
|
||||||
|
0,
|
||||||
|
new[] { dest },
|
||||||
|
sources));
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
@ -633,12 +642,21 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
SamplerType type,
|
SamplerType type,
|
||||||
TextureFormat format,
|
TextureFormat format,
|
||||||
TextureFlags flags,
|
TextureFlags flags,
|
||||||
int binding,
|
SetBindingPair setAndBinding,
|
||||||
int compMask,
|
int compMask,
|
||||||
Operand[] dests,
|
Operand[] dests,
|
||||||
Operand[] sources)
|
Operand[] sources)
|
||||||
{
|
{
|
||||||
context.Add(new TextureOperation(Instruction.ImageLoad, type, format, flags, binding, compMask, dests, sources));
|
context.Add(new TextureOperation(
|
||||||
|
Instruction.ImageLoad,
|
||||||
|
type,
|
||||||
|
format,
|
||||||
|
flags,
|
||||||
|
setAndBinding.SetIndex,
|
||||||
|
setAndBinding.Binding,
|
||||||
|
compMask,
|
||||||
|
dests,
|
||||||
|
sources));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ImageStore(
|
public static void ImageStore(
|
||||||
|
@ -646,10 +664,19 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
SamplerType type,
|
SamplerType type,
|
||||||
TextureFormat format,
|
TextureFormat format,
|
||||||
TextureFlags flags,
|
TextureFlags flags,
|
||||||
int binding,
|
SetBindingPair setAndBinding,
|
||||||
Operand[] sources)
|
Operand[] sources)
|
||||||
{
|
{
|
||||||
context.Add(new TextureOperation(Instruction.ImageStore, type, format, flags, binding, 0, null, sources));
|
context.Add(new TextureOperation(
|
||||||
|
Instruction.ImageStore,
|
||||||
|
type,
|
||||||
|
format,
|
||||||
|
flags,
|
||||||
|
setAndBinding.SetIndex,
|
||||||
|
setAndBinding.Binding,
|
||||||
|
0,
|
||||||
|
null,
|
||||||
|
sources));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Operand IsNan(this EmitterContext context, Operand a, Instruction fpType = Instruction.FP32)
|
public static Operand IsNan(this EmitterContext context, Operand a, Instruction fpType = Instruction.FP32)
|
||||||
|
@ -718,13 +745,22 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
this EmitterContext context,
|
this EmitterContext context,
|
||||||
SamplerType type,
|
SamplerType type,
|
||||||
TextureFlags flags,
|
TextureFlags flags,
|
||||||
int binding,
|
SetBindingPair setAndBinding,
|
||||||
int compIndex,
|
int compIndex,
|
||||||
Operand[] sources)
|
Operand[] sources)
|
||||||
{
|
{
|
||||||
Operand dest = Local();
|
Operand dest = Local();
|
||||||
|
|
||||||
context.Add(new TextureOperation(Instruction.Lod, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources));
|
context.Add(new TextureOperation(
|
||||||
|
Instruction.Lod,
|
||||||
|
type,
|
||||||
|
TextureFormat.Unknown,
|
||||||
|
flags,
|
||||||
|
setAndBinding.SetIndex,
|
||||||
|
setAndBinding.Binding,
|
||||||
|
compIndex,
|
||||||
|
new[] { dest },
|
||||||
|
sources));
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
@ -889,24 +925,42 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
this EmitterContext context,
|
this EmitterContext context,
|
||||||
SamplerType type,
|
SamplerType type,
|
||||||
TextureFlags flags,
|
TextureFlags flags,
|
||||||
int binding,
|
SetBindingPair setAndBinding,
|
||||||
int compMask,
|
int compMask,
|
||||||
Operand[] dests,
|
Operand[] dests,
|
||||||
Operand[] sources)
|
Operand[] sources)
|
||||||
{
|
{
|
||||||
context.Add(new TextureOperation(Instruction.TextureSample, type, TextureFormat.Unknown, flags, binding, compMask, dests, sources));
|
context.Add(new TextureOperation(
|
||||||
|
Instruction.TextureSample,
|
||||||
|
type,
|
||||||
|
TextureFormat.Unknown,
|
||||||
|
flags,
|
||||||
|
setAndBinding.SetIndex,
|
||||||
|
setAndBinding.Binding,
|
||||||
|
compMask,
|
||||||
|
dests,
|
||||||
|
sources));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Operand TextureQuerySamples(
|
public static Operand TextureQuerySamples(
|
||||||
this EmitterContext context,
|
this EmitterContext context,
|
||||||
SamplerType type,
|
SamplerType type,
|
||||||
TextureFlags flags,
|
TextureFlags flags,
|
||||||
int binding,
|
SetBindingPair setAndBinding,
|
||||||
Operand[] sources)
|
Operand[] sources)
|
||||||
{
|
{
|
||||||
Operand dest = Local();
|
Operand dest = Local();
|
||||||
|
|
||||||
context.Add(new TextureOperation(Instruction.TextureQuerySamples, type, TextureFormat.Unknown, flags, binding, 0, new[] { dest }, sources));
|
context.Add(new TextureOperation(
|
||||||
|
Instruction.TextureQuerySamples,
|
||||||
|
type,
|
||||||
|
TextureFormat.Unknown,
|
||||||
|
flags,
|
||||||
|
setAndBinding.SetIndex,
|
||||||
|
setAndBinding.Binding,
|
||||||
|
0,
|
||||||
|
new[] { dest },
|
||||||
|
sources));
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
@ -915,13 +969,22 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
this EmitterContext context,
|
this EmitterContext context,
|
||||||
SamplerType type,
|
SamplerType type,
|
||||||
TextureFlags flags,
|
TextureFlags flags,
|
||||||
int binding,
|
SetBindingPair setAndBinding,
|
||||||
int compIndex,
|
int compIndex,
|
||||||
Operand[] sources)
|
Operand[] sources)
|
||||||
{
|
{
|
||||||
Operand dest = Local();
|
Operand dest = Local();
|
||||||
|
|
||||||
context.Add(new TextureOperation(Instruction.TextureQuerySize, type, TextureFormat.Unknown, flags, binding, compIndex, new[] { dest }, sources));
|
context.Add(new TextureOperation(
|
||||||
|
Instruction.TextureQuerySize,
|
||||||
|
type,
|
||||||
|
TextureFormat.Unknown,
|
||||||
|
flags,
|
||||||
|
setAndBinding.SetIndex,
|
||||||
|
setAndBinding.Binding,
|
||||||
|
compIndex,
|
||||||
|
new[] { dest },
|
||||||
|
sources));
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
|
|
||||||
bool hasSampler = !texOp.Inst.IsImage();
|
bool hasSampler = !texOp.Inst.IsImage();
|
||||||
|
|
||||||
int textureBinding = resourceManager.GetTextureOrImageBinding(
|
SetBindingPair textureSetAndBinding = resourceManager.GetTextureOrImageBinding(
|
||||||
texOp.Inst,
|
texOp.Inst,
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
|
@ -111,7 +111,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
|
|
||||||
texOp.InsertSource(1, samplerIndex);
|
texOp.InsertSource(1, samplerIndex);
|
||||||
|
|
||||||
int samplerBinding = resourceManager.GetTextureOrImageBinding(
|
SetBindingPair samplerSetAndBinding = resourceManager.GetTextureOrImageBinding(
|
||||||
texOp.Inst,
|
texOp.Inst,
|
||||||
SamplerType.None,
|
SamplerType.None,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
|
@ -120,11 +120,11 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
TextureHandle.PackOffsets(0, 0, TextureHandleType.Direct),
|
TextureHandle.PackOffsets(0, 0, TextureHandleType.Direct),
|
||||||
samplerPoolLength);
|
samplerPoolLength);
|
||||||
|
|
||||||
texOp.TurnIntoArray(textureBinding, samplerBinding);
|
texOp.TurnIntoArray(textureSetAndBinding, samplerSetAndBinding);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
texOp.TurnIntoArray(textureBinding);
|
texOp.TurnIntoArray(textureSetAndBinding);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -445,7 +445,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int binding = resourceManager.GetTextureOrImageBinding(
|
SetBindingPair setAndBinding = resourceManager.GetTextureOrImageBinding(
|
||||||
texOp.Inst,
|
texOp.Inst,
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
|
@ -453,7 +453,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
cbufSlot,
|
cbufSlot,
|
||||||
cbufOffset);
|
cbufOffset);
|
||||||
|
|
||||||
texOp.SetBinding(binding);
|
texOp.SetBinding(setAndBinding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,7 +221,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
|
|
||||||
private static void TurnIntoArray(ResourceManager resourceManager, TextureOperation texOp, int cbufSlot, int handleIndex, int length)
|
private static void TurnIntoArray(ResourceManager resourceManager, TextureOperation texOp, int cbufSlot, int handleIndex, int length)
|
||||||
{
|
{
|
||||||
int binding = resourceManager.GetTextureOrImageBinding(
|
SetBindingPair setAndBinding = resourceManager.GetTextureOrImageBinding(
|
||||||
texOp.Inst,
|
texOp.Inst,
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
|
@ -230,7 +230,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||||
handleIndex,
|
handleIndex,
|
||||||
length);
|
length);
|
||||||
|
|
||||||
texOp.TurnIntoArray(binding);
|
texOp.TurnIntoArray(setAndBinding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
private readonly ShaderStage _stage;
|
private readonly ShaderStage _stage;
|
||||||
private readonly string _stagePrefix;
|
private readonly string _stagePrefix;
|
||||||
|
|
||||||
private readonly int[] _cbSlotToBindingMap;
|
private readonly SetBindingPair[] _cbSlotToBindingMap;
|
||||||
private readonly int[] _sbSlotToBindingMap;
|
private readonly SetBindingPair[] _sbSlotToBindingMap;
|
||||||
private uint _sbSlotWritten;
|
private uint _sbSlotWritten;
|
||||||
|
|
||||||
private readonly Dictionary<int, int> _sbSlots;
|
private readonly Dictionary<int, int> _sbSlots;
|
||||||
|
@ -33,6 +33,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
private struct TextureMeta
|
private struct TextureMeta
|
||||||
{
|
{
|
||||||
|
public int Set;
|
||||||
public int Binding;
|
public int Binding;
|
||||||
public bool AccurateType;
|
public bool AccurateType;
|
||||||
public SamplerType Type;
|
public SamplerType Type;
|
||||||
|
@ -64,10 +65,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
_stage = stage;
|
_stage = stage;
|
||||||
_stagePrefix = GetShaderStagePrefix(stage);
|
_stagePrefix = GetShaderStagePrefix(stage);
|
||||||
|
|
||||||
_cbSlotToBindingMap = new int[18];
|
_cbSlotToBindingMap = new SetBindingPair[18];
|
||||||
_sbSlotToBindingMap = new int[16];
|
_sbSlotToBindingMap = new SetBindingPair[16];
|
||||||
_cbSlotToBindingMap.AsSpan().Fill(-1);
|
_cbSlotToBindingMap.AsSpan().Fill(new(-1, -1));
|
||||||
_sbSlotToBindingMap.AsSpan().Fill(-1);
|
_sbSlotToBindingMap.AsSpan().Fill(new(-1, -1));
|
||||||
|
|
||||||
_sbSlots = new();
|
_sbSlots = new();
|
||||||
_sbSlotsReverse = new();
|
_sbSlotsReverse = new();
|
||||||
|
@ -146,16 +147,16 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
public int GetConstantBufferBinding(int slot)
|
public int GetConstantBufferBinding(int slot)
|
||||||
{
|
{
|
||||||
int binding = _cbSlotToBindingMap[slot];
|
SetBindingPair setAndBinding = _cbSlotToBindingMap[slot];
|
||||||
if (binding < 0)
|
if (setAndBinding.Binding < 0)
|
||||||
{
|
{
|
||||||
binding = _gpuAccessor.CreateConstantBufferBinding(slot);
|
setAndBinding = _gpuAccessor.CreateConstantBufferBinding(slot);
|
||||||
_cbSlotToBindingMap[slot] = binding;
|
_cbSlotToBindingMap[slot] = setAndBinding;
|
||||||
string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
|
string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
|
||||||
AddNewConstantBuffer(binding, $"{_stagePrefix}_c{slotNumber}");
|
AddNewConstantBuffer(setAndBinding.SetIndex, setAndBinding.Binding, $"{_stagePrefix}_c{slotNumber}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return binding;
|
return setAndBinding.Binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetStorageBufferBinding(int sbCbSlot, int sbCbOffset, bool write, out int binding)
|
public bool TryGetStorageBufferBinding(int sbCbSlot, int sbCbOffset, bool write, out int binding)
|
||||||
|
@ -166,14 +167,14 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
binding = _sbSlotToBindingMap[slot];
|
SetBindingPair setAndBinding = _sbSlotToBindingMap[slot];
|
||||||
|
|
||||||
if (binding < 0)
|
if (setAndBinding.Binding < 0)
|
||||||
{
|
{
|
||||||
binding = _gpuAccessor.CreateStorageBufferBinding(slot);
|
setAndBinding = _gpuAccessor.CreateStorageBufferBinding(slot);
|
||||||
_sbSlotToBindingMap[slot] = binding;
|
_sbSlotToBindingMap[slot] = setAndBinding;
|
||||||
string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
|
string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
|
||||||
AddNewStorageBuffer(binding, $"{_stagePrefix}_s{slotNumber}");
|
AddNewStorageBuffer(setAndBinding.SetIndex, setAndBinding.Binding, $"{_stagePrefix}_s{slotNumber}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (write)
|
if (write)
|
||||||
|
@ -181,6 +182,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
_sbSlotWritten |= 1u << slot;
|
_sbSlotWritten |= 1u << slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding = setAndBinding.Binding;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +210,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
{
|
{
|
||||||
for (slot = 0; slot < _cbSlotToBindingMap.Length; slot++)
|
for (slot = 0; slot < _cbSlotToBindingMap.Length; slot++)
|
||||||
{
|
{
|
||||||
if (_cbSlotToBindingMap[slot] == binding)
|
if (_cbSlotToBindingMap[slot].Binding == binding)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -218,7 +220,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetTextureOrImageBinding(
|
public SetBindingPair GetTextureOrImageBinding(
|
||||||
Instruction inst,
|
Instruction inst,
|
||||||
SamplerType type,
|
SamplerType type,
|
||||||
TextureFormat format,
|
TextureFormat format,
|
||||||
|
@ -240,7 +242,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
format = TextureFormat.Unknown;
|
format = TextureFormat.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
int binding = GetTextureOrImageBinding(
|
SetBindingPair setAndBinding = GetTextureOrImageBinding(
|
||||||
cbufSlot,
|
cbufSlot,
|
||||||
handle,
|
handle,
|
||||||
arrayLength,
|
arrayLength,
|
||||||
|
@ -255,10 +257,10 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
_gpuAccessor.RegisterTexture(handle, cbufSlot);
|
_gpuAccessor.RegisterTexture(handle, cbufSlot);
|
||||||
|
|
||||||
return binding;
|
return setAndBinding;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetTextureOrImageBinding(
|
private SetBindingPair GetTextureOrImageBinding(
|
||||||
int cbufSlot,
|
int cbufSlot,
|
||||||
int handle,
|
int handle,
|
||||||
int arrayLength,
|
int arrayLength,
|
||||||
|
@ -311,21 +313,38 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
UsageFlags = usageFlags,
|
UsageFlags = usageFlags,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int setIndex;
|
||||||
int binding;
|
int binding;
|
||||||
|
|
||||||
if (dict.TryGetValue(info, out var existingMeta))
|
if (dict.TryGetValue(info, out var existingMeta))
|
||||||
{
|
{
|
||||||
dict[info] = MergeTextureMeta(meta, existingMeta);
|
dict[info] = MergeTextureMeta(meta, existingMeta);
|
||||||
|
setIndex = existingMeta.Set;
|
||||||
binding = existingMeta.Binding;
|
binding = existingMeta.Binding;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (arrayLength > 1 && (setIndex = _gpuAccessor.CreateExtraSet()) >= 0)
|
||||||
|
{
|
||||||
|
// We reserved an "extra set" for the array.
|
||||||
|
// In this case the binding is always the first one (0).
|
||||||
|
// Using separate sets for array is better as we need to do less descriptor set updates.
|
||||||
|
|
||||||
|
binding = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
bool isBuffer = (type & SamplerType.Mask) == SamplerType.TextureBuffer;
|
bool isBuffer = (type & SamplerType.Mask) == SamplerType.TextureBuffer;
|
||||||
|
|
||||||
binding = isImage
|
SetBindingPair setAndBinding = isImage
|
||||||
? _gpuAccessor.CreateImageBinding(arrayLength, isBuffer)
|
? _gpuAccessor.CreateImageBinding(arrayLength, isBuffer)
|
||||||
: _gpuAccessor.CreateTextureBinding(arrayLength, isBuffer);
|
: _gpuAccessor.CreateTextureBinding(arrayLength, isBuffer);
|
||||||
|
|
||||||
|
setIndex = setAndBinding.SetIndex;
|
||||||
|
binding = setAndBinding.Binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
meta.Set = setIndex;
|
||||||
meta.Binding = binding;
|
meta.Binding = binding;
|
||||||
|
|
||||||
dict.Add(info, meta);
|
dict.Add(info, meta);
|
||||||
|
@ -355,7 +374,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
}
|
}
|
||||||
|
|
||||||
var definition = new TextureDefinition(
|
var definition = new TextureDefinition(
|
||||||
isImage ? 3 : 2,
|
setIndex,
|
||||||
binding,
|
binding,
|
||||||
arrayLength,
|
arrayLength,
|
||||||
separate,
|
separate,
|
||||||
|
@ -373,11 +392,12 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
Properties.AddOrUpdateTexture(definition);
|
Properties.AddOrUpdateTexture(definition);
|
||||||
}
|
}
|
||||||
|
|
||||||
return binding;
|
return new SetBindingPair(setIndex, binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TextureMeta MergeTextureMeta(TextureMeta meta, TextureMeta existingMeta)
|
private static TextureMeta MergeTextureMeta(TextureMeta meta, TextureMeta existingMeta)
|
||||||
{
|
{
|
||||||
|
meta.Set = existingMeta.Set;
|
||||||
meta.Binding = existingMeta.Binding;
|
meta.Binding = existingMeta.Binding;
|
||||||
meta.UsageFlags |= existingMeta.UsageFlags;
|
meta.UsageFlags |= existingMeta.UsageFlags;
|
||||||
|
|
||||||
|
@ -440,11 +460,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
for (int slot = 0; slot < _cbSlotToBindingMap.Length; slot++)
|
for (int slot = 0; slot < _cbSlotToBindingMap.Length; slot++)
|
||||||
{
|
{
|
||||||
int binding = _cbSlotToBindingMap[slot];
|
SetBindingPair setAndBinding = _cbSlotToBindingMap[slot];
|
||||||
|
|
||||||
if (binding >= 0 && _usedConstantBufferBindings.Contains(binding))
|
if (setAndBinding.Binding >= 0 && _usedConstantBufferBindings.Contains(setAndBinding.Binding))
|
||||||
{
|
{
|
||||||
descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot);
|
descriptors[descriptorIndex++] = new BufferDescriptor(setAndBinding.SetIndex, setAndBinding.Binding, slot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,13 +484,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
foreach ((int key, int slot) in _sbSlots)
|
foreach ((int key, int slot) in _sbSlots)
|
||||||
{
|
{
|
||||||
int binding = _sbSlotToBindingMap[slot];
|
SetBindingPair setAndBinding = _sbSlotToBindingMap[slot];
|
||||||
|
|
||||||
if (binding >= 0)
|
if (setAndBinding.Binding >= 0)
|
||||||
{
|
{
|
||||||
(int sbCbSlot, int sbCbOffset) = UnpackSbCbInfo(key);
|
(int sbCbSlot, int sbCbOffset) = UnpackSbCbInfo(key);
|
||||||
BufferUsageFlags flags = (_sbSlotWritten & (1u << slot)) != 0 ? BufferUsageFlags.Write : BufferUsageFlags.None;
|
BufferUsageFlags flags = (_sbSlotWritten & (1u << slot)) != 0 ? BufferUsageFlags.Write : BufferUsageFlags.None;
|
||||||
descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot, sbCbSlot, sbCbOffset, flags);
|
descriptors[descriptorIndex++] = new BufferDescriptor(setAndBinding.SetIndex, setAndBinding.Binding, slot, sbCbSlot, sbCbOffset, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,6 +527,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptors.Add(new TextureDescriptor(
|
descriptors.Add(new TextureDescriptor(
|
||||||
|
meta.Set,
|
||||||
meta.Binding,
|
meta.Binding,
|
||||||
meta.Type,
|
meta.Type,
|
||||||
info.Format,
|
info.Format,
|
||||||
|
@ -527,6 +548,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptors.Add(new TextureDescriptor(
|
descriptors.Add(new TextureDescriptor(
|
||||||
|
meta.Set,
|
||||||
meta.Binding,
|
meta.Binding,
|
||||||
meta.Type,
|
meta.Type,
|
||||||
info.Format,
|
info.Format,
|
||||||
|
@ -587,24 +609,24 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddNewConstantBuffer(int binding, string name)
|
private void AddNewConstantBuffer(int setIndex, int binding, string name)
|
||||||
{
|
{
|
||||||
StructureType type = new(new[]
|
StructureType type = new(new[]
|
||||||
{
|
{
|
||||||
new StructureField(AggregateType.Array | AggregateType.Vector4 | AggregateType.FP32, "data", Constants.ConstantBufferSize / 16),
|
new StructureField(AggregateType.Array | AggregateType.Vector4 | AggregateType.FP32, "data", Constants.ConstantBufferSize / 16),
|
||||||
});
|
});
|
||||||
|
|
||||||
Properties.AddOrUpdateConstantBuffer(new(BufferLayout.Std140, 0, binding, name, type));
|
Properties.AddOrUpdateConstantBuffer(new(BufferLayout.Std140, setIndex, binding, name, type));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddNewStorageBuffer(int binding, string name)
|
private void AddNewStorageBuffer(int setIndex, int binding, string name)
|
||||||
{
|
{
|
||||||
StructureType type = new(new[]
|
StructureType type = new(new[]
|
||||||
{
|
{
|
||||||
new StructureField(AggregateType.Array | AggregateType.U32, "data", 0),
|
new StructureField(AggregateType.Array | AggregateType.U32, "data", 0),
|
||||||
});
|
});
|
||||||
|
|
||||||
Properties.AddOrUpdateStorageBuffer(new(BufferLayout.Std430, 1, binding, name, type));
|
Properties.AddOrUpdateStorageBuffer(new(BufferLayout.Std430, setIndex, binding, name, type));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetShaderStagePrefix(ShaderStage stage)
|
public static string GetShaderStagePrefix(ShaderStage stage)
|
||||||
|
|
|
@ -11,6 +11,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
public const int MaxVertexBufferTextures = 32;
|
public const int MaxVertexBufferTextures = 32;
|
||||||
|
|
||||||
|
private const int TextureSetIndex = 2; // TODO: Get from GPU accessor.
|
||||||
|
|
||||||
public int VertexInfoConstantBufferBinding { get; }
|
public int VertexInfoConstantBufferBinding { get; }
|
||||||
public int VertexOutputStorageBufferBinding { get; }
|
public int VertexOutputStorageBufferBinding { get; }
|
||||||
public int GeometryVertexOutputStorageBufferBinding { get; }
|
public int GeometryVertexOutputStorageBufferBinding { get; }
|
||||||
|
@ -163,6 +165,21 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
return _vertexBufferTextureBaseBinding + vaLocation;
|
return _vertexBufferTextureBaseBinding + vaLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SetBindingPair GetVertexBufferTextureSetAndBinding(int vaLocation)
|
||||||
|
{
|
||||||
|
return new SetBindingPair(TextureSetIndex, GetVertexBufferTextureBinding(vaLocation));
|
||||||
|
}
|
||||||
|
|
||||||
|
public SetBindingPair GetIndexBufferTextureSetAndBinding()
|
||||||
|
{
|
||||||
|
return new SetBindingPair(TextureSetIndex, IndexBufferTextureBinding);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SetBindingPair GetTopologyRemapBufferTextureSetAndBinding()
|
||||||
|
{
|
||||||
|
return new SetBindingPair(TextureSetIndex, TopologyRemapBufferTextureBinding);
|
||||||
|
}
|
||||||
|
|
||||||
internal bool TryGetOffset(StorageKind storageKind, int location, int component, out int offset)
|
internal bool TryGetOffset(StorageKind storageKind, int location, int component, out int offset)
|
||||||
{
|
{
|
||||||
return _offsets.TryGetValue(new IoDefinition(storageKind, IoVariable.UserDefined, location, component), out offset);
|
return _offsets.TryGetValue(new IoDefinition(storageKind, IoVariable.UserDefined, location, component), out offset);
|
||||||
|
|
|
@ -182,6 +182,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
texOp.Flags,
|
texOp.Flags,
|
||||||
|
texOp.Set,
|
||||||
texOp.Binding,
|
texOp.Binding,
|
||||||
index,
|
index,
|
||||||
new[] { coordSize },
|
new[] { coordSize },
|
||||||
|
@ -251,6 +252,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
texOp.Flags,
|
texOp.Flags,
|
||||||
|
texOp.Set,
|
||||||
texOp.Binding,
|
texOp.Binding,
|
||||||
index,
|
index,
|
||||||
new[] { coordSize },
|
new[] { coordSize },
|
||||||
|
@ -471,6 +473,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
|
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
|
||||||
|
texOp.Set,
|
||||||
texOp.Binding,
|
texOp.Binding,
|
||||||
1 << 3, // W component: i=0, j=0
|
1 << 3, // W component: i=0, j=0
|
||||||
new[] { dests[destIndex++] },
|
new[] { dests[destIndex++] },
|
||||||
|
@ -527,6 +530,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
|
texOp.Flags & ~(TextureFlags.Offset | TextureFlags.Offsets),
|
||||||
|
texOp.Set,
|
||||||
texOp.Binding,
|
texOp.Binding,
|
||||||
componentIndex,
|
componentIndex,
|
||||||
dests,
|
dests,
|
||||||
|
@ -573,6 +577,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
texOp.Flags,
|
texOp.Flags,
|
||||||
|
texOp.Set,
|
||||||
texOp.Binding,
|
texOp.Binding,
|
||||||
index,
|
index,
|
||||||
new[] { texSizes[index] },
|
new[] { texSizes[index] },
|
||||||
|
@ -603,6 +608,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
texOp.Flags,
|
texOp.Flags,
|
||||||
|
texOp.Set,
|
||||||
texOp.Binding,
|
texOp.Binding,
|
||||||
0,
|
0,
|
||||||
new[] { lod },
|
new[] { lod },
|
||||||
|
@ -633,6 +639,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
texOp.Type,
|
texOp.Type,
|
||||||
texOp.Format,
|
texOp.Format,
|
||||||
texOp.Flags,
|
texOp.Flags,
|
||||||
|
texOp.Set,
|
||||||
texOp.Binding,
|
texOp.Binding,
|
||||||
index,
|
index,
|
||||||
new[] { texSizes[index] },
|
new[] { texSizes[index] },
|
||||||
|
|
|
@ -54,6 +54,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
{
|
{
|
||||||
bool needsSextNorm = context.Definitions.IsAttributePackedRgb10A2Signed(location);
|
bool needsSextNorm = context.Definitions.IsAttributePackedRgb10A2Signed(location);
|
||||||
|
|
||||||
|
SetBindingPair setAndBinding = context.ResourceManager.Reservations.GetVertexBufferTextureSetAndBinding(location);
|
||||||
Operand temp = needsSextNorm ? Local() : dest;
|
Operand temp = needsSextNorm ? Local() : dest;
|
||||||
Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, location, 0);
|
Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, location, 0);
|
||||||
|
|
||||||
|
@ -62,7 +63,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
SamplerType.TextureBuffer,
|
SamplerType.TextureBuffer,
|
||||||
TextureFormat.Unknown,
|
TextureFormat.Unknown,
|
||||||
TextureFlags.IntCoords,
|
TextureFlags.IntCoords,
|
||||||
context.ResourceManager.Reservations.GetVertexBufferTextureBinding(location),
|
setAndBinding.SetIndex,
|
||||||
|
setAndBinding.Binding,
|
||||||
1 << component,
|
1 << component,
|
||||||
new[] { temp },
|
new[] { temp },
|
||||||
new[] { vertexElemOffset }));
|
new[] { vertexElemOffset }));
|
||||||
|
@ -75,6 +77,7 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
SetBindingPair setAndBinding = context.ResourceManager.Reservations.GetVertexBufferTextureSetAndBinding(location);
|
||||||
Operand temp = component > 0 ? Local() : dest;
|
Operand temp = component > 0 ? Local() : dest;
|
||||||
Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, location, component);
|
Operand vertexElemOffset = GenerateVertexOffset(context.ResourceManager, node, location, component);
|
||||||
|
|
||||||
|
@ -83,7 +86,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Transforms
|
||||||
SamplerType.TextureBuffer,
|
SamplerType.TextureBuffer,
|
||||||
TextureFormat.Unknown,
|
TextureFormat.Unknown,
|
||||||
TextureFlags.IntCoords,
|
TextureFlags.IntCoords,
|
||||||
context.ResourceManager.Reservations.GetVertexBufferTextureBinding(location),
|
setAndBinding.SetIndex,
|
||||||
|
setAndBinding.Binding,
|
||||||
1,
|
1,
|
||||||
new[] { temp },
|
new[] { temp },
|
||||||
new[] { vertexElemOffset }));
|
new[] { vertexElemOffset }));
|
||||||
|
|
|
@ -412,8 +412,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
|
|
||||||
if (Stage == ShaderStage.Vertex)
|
if (Stage == ShaderStage.Vertex)
|
||||||
{
|
{
|
||||||
int ibBinding = resourceManager.Reservations.IndexBufferTextureBinding;
|
SetBindingPair ibSetAndBinding = resourceManager.Reservations.GetIndexBufferTextureSetAndBinding();
|
||||||
TextureDefinition indexBuffer = new(2, ibBinding, "ib_data", SamplerType.TextureBuffer);
|
TextureDefinition indexBuffer = new(ibSetAndBinding.SetIndex, ibSetAndBinding.Binding, "ib_data", SamplerType.TextureBuffer);
|
||||||
resourceManager.Properties.AddOrUpdateTexture(indexBuffer);
|
resourceManager.Properties.AddOrUpdateTexture(indexBuffer);
|
||||||
|
|
||||||
int inputMap = _program.AttributeUsage.UsedInputAttributes;
|
int inputMap = _program.AttributeUsage.UsedInputAttributes;
|
||||||
|
@ -421,8 +421,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
while (inputMap != 0)
|
while (inputMap != 0)
|
||||||
{
|
{
|
||||||
int location = BitOperations.TrailingZeroCount(inputMap);
|
int location = BitOperations.TrailingZeroCount(inputMap);
|
||||||
int binding = resourceManager.Reservations.GetVertexBufferTextureBinding(location);
|
SetBindingPair setAndBinding = resourceManager.Reservations.GetVertexBufferTextureSetAndBinding(location);
|
||||||
TextureDefinition vaBuffer = new(2, binding, $"vb_data{location}", SamplerType.TextureBuffer);
|
TextureDefinition vaBuffer = new(setAndBinding.SetIndex, setAndBinding.Binding, $"vb_data{location}", SamplerType.TextureBuffer);
|
||||||
resourceManager.Properties.AddOrUpdateTexture(vaBuffer);
|
resourceManager.Properties.AddOrUpdateTexture(vaBuffer);
|
||||||
|
|
||||||
inputMap &= ~(1 << location);
|
inputMap &= ~(1 << location);
|
||||||
|
@ -430,8 +430,8 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||||
}
|
}
|
||||||
else if (Stage == ShaderStage.Geometry)
|
else if (Stage == ShaderStage.Geometry)
|
||||||
{
|
{
|
||||||
int trbBinding = resourceManager.Reservations.TopologyRemapBufferTextureBinding;
|
SetBindingPair trbSetAndBinding = resourceManager.Reservations.GetTopologyRemapBufferTextureSetAndBinding();
|
||||||
TextureDefinition remapBuffer = new(2, trbBinding, "trb_data", SamplerType.TextureBuffer);
|
TextureDefinition remapBuffer = new(trbSetAndBinding.SetIndex, trbSetAndBinding.Binding, "trb_data", SamplerType.TextureBuffer);
|
||||||
resourceManager.Properties.AddOrUpdateTexture(remapBuffer);
|
resourceManager.Properties.AddOrUpdateTexture(remapBuffer);
|
||||||
|
|
||||||
int geometryVbOutputSbBinding = resourceManager.Reservations.GeometryVertexOutputStorageBufferBinding;
|
int geometryVbOutputSbBinding = resourceManager.Reservations.GeometryVertexOutputStorageBufferBinding;
|
||||||
|
|
|
@ -69,17 +69,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private record struct ArrayRef<T>
|
private readonly record struct ArrayRef<T>(ShaderStage Stage, T Array);
|
||||||
{
|
|
||||||
public ShaderStage Stage;
|
|
||||||
public T Array;
|
|
||||||
|
|
||||||
public ArrayRef(ShaderStage stage, T array)
|
|
||||||
{
|
|
||||||
Stage = stage;
|
|
||||||
Array = array;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly VulkanRenderer _gd;
|
private readonly VulkanRenderer _gd;
|
||||||
private readonly Device _device;
|
private readonly Device _device;
|
||||||
|
@ -97,6 +87,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private ArrayRef<TextureArray>[] _textureArrayRefs;
|
private ArrayRef<TextureArray>[] _textureArrayRefs;
|
||||||
private ArrayRef<ImageArray>[] _imageArrayRefs;
|
private ArrayRef<ImageArray>[] _imageArrayRefs;
|
||||||
|
|
||||||
|
private ArrayRef<TextureArray>[] _textureArrayExtraRefs;
|
||||||
|
private ArrayRef<ImageArray>[] _imageArrayExtraRefs;
|
||||||
|
|
||||||
private readonly DescriptorBufferInfo[] _uniformBuffers;
|
private readonly DescriptorBufferInfo[] _uniformBuffers;
|
||||||
private readonly DescriptorBufferInfo[] _storageBuffers;
|
private readonly DescriptorBufferInfo[] _storageBuffers;
|
||||||
private readonly DescriptorImageInfo[] _textures;
|
private readonly DescriptorImageInfo[] _textures;
|
||||||
|
@ -152,6 +145,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_textureArrayRefs = Array.Empty<ArrayRef<TextureArray>>();
|
_textureArrayRefs = Array.Empty<ArrayRef<TextureArray>>();
|
||||||
_imageArrayRefs = Array.Empty<ArrayRef<ImageArray>>();
|
_imageArrayRefs = Array.Empty<ArrayRef<ImageArray>>();
|
||||||
|
|
||||||
|
_textureArrayExtraRefs = Array.Empty<ArrayRef<TextureArray>>();
|
||||||
|
_imageArrayExtraRefs = Array.Empty<ArrayRef<ImageArray>>();
|
||||||
|
|
||||||
_uniformBuffers = new DescriptorBufferInfo[Constants.MaxUniformBufferBindings];
|
_uniformBuffers = new DescriptorBufferInfo[Constants.MaxUniformBufferBindings];
|
||||||
_storageBuffers = new DescriptorBufferInfo[Constants.MaxStorageBufferBindings];
|
_storageBuffers = new DescriptorBufferInfo[Constants.MaxStorageBufferBindings];
|
||||||
_textures = new DescriptorImageInfo[Constants.MaxTexturesPerStage];
|
_textures = new DescriptorImageInfo[Constants.MaxTexturesPerStage];
|
||||||
|
@ -495,25 +491,39 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
public void SetTextureArray(CommandBufferScoped cbs, ShaderStage stage, int binding, ITextureArray array)
|
public void SetTextureArray(CommandBufferScoped cbs, ShaderStage stage, int binding, ITextureArray array)
|
||||||
{
|
{
|
||||||
if (_textureArrayRefs.Length <= binding)
|
ref ArrayRef<TextureArray> arrayRef = ref GetArrayRef(ref _textureArrayRefs, binding, ArrayGrowthSize);
|
||||||
{
|
|
||||||
Array.Resize(ref _textureArrayRefs, binding + ArrayGrowthSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_textureArrayRefs[binding].Stage != stage || _textureArrayRefs[binding].Array != array)
|
if (arrayRef.Stage != stage || arrayRef.Array != array)
|
||||||
{
|
{
|
||||||
if (_textureArrayRefs[binding].Array != null)
|
arrayRef.Array?.DecrementBindCount();
|
||||||
{
|
|
||||||
_textureArrayRefs[binding].Array.Bound = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array is TextureArray textureArray)
|
if (array is TextureArray textureArray)
|
||||||
{
|
{
|
||||||
textureArray.Bound = true;
|
textureArray.IncrementBindCount();
|
||||||
textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
|
textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
|
||||||
}
|
}
|
||||||
|
|
||||||
_textureArrayRefs[binding] = new ArrayRef<TextureArray>(stage, array as TextureArray);
|
arrayRef = new ArrayRef<TextureArray>(stage, array as TextureArray);
|
||||||
|
|
||||||
|
SignalDirty(DirtyFlags.Texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTextureArraySeparate(CommandBufferScoped cbs, ShaderStage stage, int setIndex, ITextureArray array)
|
||||||
|
{
|
||||||
|
ref ArrayRef<TextureArray> arrayRef = ref GetArrayRef(ref _textureArrayExtraRefs, setIndex - PipelineBase.DescriptorSetLayouts);
|
||||||
|
|
||||||
|
if (arrayRef.Stage != stage || arrayRef.Array != array)
|
||||||
|
{
|
||||||
|
arrayRef.Array?.DecrementBindCount();
|
||||||
|
|
||||||
|
if (array is TextureArray textureArray)
|
||||||
|
{
|
||||||
|
textureArray.IncrementBindCount();
|
||||||
|
textureArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
|
||||||
|
}
|
||||||
|
|
||||||
|
arrayRef = new ArrayRef<TextureArray>(stage, array as TextureArray);
|
||||||
|
|
||||||
SignalDirty(DirtyFlags.Texture);
|
SignalDirty(DirtyFlags.Texture);
|
||||||
}
|
}
|
||||||
|
@ -521,30 +531,56 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
public void SetImageArray(CommandBufferScoped cbs, ShaderStage stage, int binding, IImageArray array)
|
public void SetImageArray(CommandBufferScoped cbs, ShaderStage stage, int binding, IImageArray array)
|
||||||
{
|
{
|
||||||
if (_imageArrayRefs.Length <= binding)
|
ref ArrayRef<ImageArray> arrayRef = ref GetArrayRef(ref _imageArrayRefs, binding, ArrayGrowthSize);
|
||||||
{
|
|
||||||
Array.Resize(ref _imageArrayRefs, binding + ArrayGrowthSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_imageArrayRefs[binding].Stage != stage || _imageArrayRefs[binding].Array != array)
|
if (arrayRef.Stage != stage || arrayRef.Array != array)
|
||||||
{
|
{
|
||||||
if (_imageArrayRefs[binding].Array != null)
|
arrayRef.Array?.DecrementBindCount();
|
||||||
{
|
|
||||||
_imageArrayRefs[binding].Array.Bound = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array is ImageArray imageArray)
|
if (array is ImageArray imageArray)
|
||||||
{
|
{
|
||||||
imageArray.Bound = true;
|
imageArray.IncrementBindCount();
|
||||||
imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
|
imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
|
||||||
}
|
}
|
||||||
|
|
||||||
_imageArrayRefs[binding] = new ArrayRef<ImageArray>(stage, array as ImageArray);
|
arrayRef = new ArrayRef<ImageArray>(stage, array as ImageArray);
|
||||||
|
|
||||||
SignalDirty(DirtyFlags.Image);
|
SignalDirty(DirtyFlags.Image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetImageArraySeparate(CommandBufferScoped cbs, ShaderStage stage, int setIndex, IImageArray array)
|
||||||
|
{
|
||||||
|
ref ArrayRef<ImageArray> arrayRef = ref GetArrayRef(ref _imageArrayExtraRefs, setIndex - PipelineBase.DescriptorSetLayouts);
|
||||||
|
|
||||||
|
if (arrayRef.Stage != stage || arrayRef.Array != array)
|
||||||
|
{
|
||||||
|
arrayRef.Array?.DecrementBindCount();
|
||||||
|
|
||||||
|
if (array is ImageArray imageArray)
|
||||||
|
{
|
||||||
|
imageArray.IncrementBindCount();
|
||||||
|
imageArray.QueueWriteToReadBarriers(cbs, stage.ConvertToPipelineStageFlags());
|
||||||
|
}
|
||||||
|
|
||||||
|
arrayRef = new ArrayRef<ImageArray>(stage, array as ImageArray);
|
||||||
|
|
||||||
|
SignalDirty(DirtyFlags.Image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ref ArrayRef<T> GetArrayRef<T>(ref ArrayRef<T>[] array, int index, int growthSize = 1)
|
||||||
|
{
|
||||||
|
ArgumentOutOfRangeException.ThrowIfNegative(index);
|
||||||
|
|
||||||
|
if (array.Length <= index)
|
||||||
|
{
|
||||||
|
Array.Resize(ref array, index + growthSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ref array[index];
|
||||||
|
}
|
||||||
|
|
||||||
public void SetUniformBuffers(CommandBuffer commandBuffer, ReadOnlySpan<BufferAssignment> buffers)
|
public void SetUniformBuffers(CommandBuffer commandBuffer, ReadOnlySpan<BufferAssignment> buffers)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < buffers.Length; i++)
|
for (int i = 0; i < buffers.Length; i++)
|
||||||
|
@ -594,31 +630,40 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var program = _program;
|
||||||
|
|
||||||
if (_dirty.HasFlag(DirtyFlags.Uniform))
|
if (_dirty.HasFlag(DirtyFlags.Uniform))
|
||||||
{
|
{
|
||||||
if (_program.UsePushDescriptors)
|
if (program.UsePushDescriptors)
|
||||||
{
|
{
|
||||||
UpdateAndBindUniformBufferPd(cbs, pbp);
|
UpdateAndBindUniformBufferPd(cbs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UpdateAndBind(cbs, PipelineBase.UniformSetIndex, pbp);
|
UpdateAndBind(cbs, program, PipelineBase.UniformSetIndex, pbp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_dirty.HasFlag(DirtyFlags.Storage))
|
if (_dirty.HasFlag(DirtyFlags.Storage))
|
||||||
{
|
{
|
||||||
UpdateAndBind(cbs, PipelineBase.StorageSetIndex, pbp);
|
UpdateAndBind(cbs, program, PipelineBase.StorageSetIndex, pbp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_dirty.HasFlag(DirtyFlags.Texture))
|
if (_dirty.HasFlag(DirtyFlags.Texture))
|
||||||
{
|
{
|
||||||
UpdateAndBind(cbs, PipelineBase.TextureSetIndex, pbp);
|
UpdateAndBind(cbs, program, PipelineBase.TextureSetIndex, pbp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_dirty.HasFlag(DirtyFlags.Image))
|
if (_dirty.HasFlag(DirtyFlags.Image))
|
||||||
{
|
{
|
||||||
UpdateAndBind(cbs, PipelineBase.ImageSetIndex, pbp);
|
UpdateAndBind(cbs, program, PipelineBase.ImageSetIndex, pbp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (program.BindingSegments.Length > PipelineBase.DescriptorSetLayouts)
|
||||||
|
{
|
||||||
|
// Program is using extra sets, we need to bind those too.
|
||||||
|
|
||||||
|
BindExtraSets(cbs, program, pbp);
|
||||||
}
|
}
|
||||||
|
|
||||||
_dirty = DirtyFlags.None;
|
_dirty = DirtyFlags.None;
|
||||||
|
@ -658,9 +703,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void UpdateAndBind(CommandBufferScoped cbs, int setIndex, PipelineBindPoint pbp)
|
private void UpdateAndBind(CommandBufferScoped cbs, ShaderCollection program, int setIndex, PipelineBindPoint pbp)
|
||||||
{
|
{
|
||||||
var program = _program;
|
|
||||||
var bindingSegments = program.BindingSegments[setIndex];
|
var bindingSegments = program.BindingSegments[setIndex];
|
||||||
|
|
||||||
if (bindingSegments.Length == 0)
|
if (bindingSegments.Length == 0)
|
||||||
|
@ -869,7 +913,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void UpdateAndBindUniformBufferPd(CommandBufferScoped cbs, PipelineBindPoint pbp)
|
private void UpdateAndBindUniformBufferPd(CommandBufferScoped cbs)
|
||||||
{
|
{
|
||||||
int sequence = _pdSequence;
|
int sequence = _pdSequence;
|
||||||
var bindingSegments = _program.BindingSegments[PipelineBase.UniformSetIndex];
|
var bindingSegments = _program.BindingSegments[PipelineBase.UniformSetIndex];
|
||||||
|
@ -933,6 +977,56 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void BindExtraSets(CommandBufferScoped cbs, ShaderCollection program, PipelineBindPoint pbp)
|
||||||
|
{
|
||||||
|
for (int setIndex = PipelineBase.DescriptorSetLayouts; setIndex < program.BindingSegments.Length; setIndex++)
|
||||||
|
{
|
||||||
|
var bindingSegments = program.BindingSegments[setIndex];
|
||||||
|
|
||||||
|
if (bindingSegments.Length == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceBindingSegment segment = bindingSegments[0];
|
||||||
|
|
||||||
|
if (segment.IsArray)
|
||||||
|
{
|
||||||
|
DescriptorSet[] sets = null;
|
||||||
|
|
||||||
|
if (segment.Type == ResourceType.Texture ||
|
||||||
|
segment.Type == ResourceType.Sampler ||
|
||||||
|
segment.Type == ResourceType.TextureAndSampler ||
|
||||||
|
segment.Type == ResourceType.BufferTexture)
|
||||||
|
{
|
||||||
|
sets = _textureArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts].Array.GetDescriptorSets(
|
||||||
|
_device,
|
||||||
|
cbs,
|
||||||
|
_templateUpdater,
|
||||||
|
program,
|
||||||
|
setIndex,
|
||||||
|
_dummyTexture,
|
||||||
|
_dummySampler);
|
||||||
|
}
|
||||||
|
else if (segment.Type == ResourceType.Image || segment.Type == ResourceType.BufferImage)
|
||||||
|
{
|
||||||
|
sets = _imageArrayExtraRefs[setIndex - PipelineBase.DescriptorSetLayouts].Array.GetDescriptorSets(
|
||||||
|
_device,
|
||||||
|
cbs,
|
||||||
|
_templateUpdater,
|
||||||
|
program,
|
||||||
|
setIndex,
|
||||||
|
_dummyTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sets != null)
|
||||||
|
{
|
||||||
|
_gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void SignalCommandBufferChange()
|
public void SignalCommandBufferChange()
|
||||||
{
|
{
|
||||||
_updateDescriptorCacheCbIndex = true;
|
_updateDescriptorCacheCbIndex = true;
|
||||||
|
|
|
@ -2,6 +2,7 @@ using Ryujinx.Graphics.GAL;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
|
@ -24,12 +25,18 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
private HashSet<TextureStorage> _storages;
|
private HashSet<TextureStorage> _storages;
|
||||||
|
|
||||||
|
private DescriptorSet[] _cachedDescriptorSets;
|
||||||
|
|
||||||
private int _cachedCommandBufferIndex;
|
private int _cachedCommandBufferIndex;
|
||||||
private int _cachedSubmissionCount;
|
private int _cachedSubmissionCount;
|
||||||
|
|
||||||
|
private ShaderCollection _cachedDscProgram;
|
||||||
|
private int _cachedDscSetIndex;
|
||||||
|
private int _cachedDscIndex;
|
||||||
|
|
||||||
private readonly bool _isBuffer;
|
private readonly bool _isBuffer;
|
||||||
|
|
||||||
public bool Bound;
|
private int _bindCount;
|
||||||
|
|
||||||
public ImageArray(VulkanRenderer gd, int size, bool isBuffer)
|
public ImageArray(VulkanRenderer gd, int size, bool isBuffer)
|
||||||
{
|
{
|
||||||
|
@ -97,9 +104,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
_cachedCommandBufferIndex = -1;
|
_cachedCommandBufferIndex = -1;
|
||||||
_storages = null;
|
_storages = null;
|
||||||
|
_cachedDescriptorSets = null;
|
||||||
|
|
||||||
|
if (_bindCount != 0)
|
||||||
|
{
|
||||||
_gd.PipelineInternal.ForceImageDirty();
|
_gd.PipelineInternal.ForceImageDirty();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags)
|
public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags)
|
||||||
{
|
{
|
||||||
|
@ -175,5 +186,65 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
return bufferTextures;
|
return bufferTextures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DescriptorSet[] GetDescriptorSets(
|
||||||
|
Device device,
|
||||||
|
CommandBufferScoped cbs,
|
||||||
|
DescriptorSetTemplateUpdater templateUpdater,
|
||||||
|
ShaderCollection program,
|
||||||
|
int setIndex,
|
||||||
|
TextureView dummyTexture)
|
||||||
|
{
|
||||||
|
if (_cachedDescriptorSets != null)
|
||||||
|
{
|
||||||
|
// We still need to ensure the current command buffer holds a reference to all used textures.
|
||||||
|
|
||||||
|
if (!_isBuffer)
|
||||||
|
{
|
||||||
|
GetImageInfos(_gd, cbs, dummyTexture);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GetBufferViews(cbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _cachedDescriptorSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cachedDscProgram?.ReleaseManualDescriptorSetCollection(_cachedDscSetIndex, _cachedDscIndex);
|
||||||
|
var dsc = program.GetNewManualDescriptorSetCollection(cbs.CommandBufferIndex, setIndex, out _cachedDscIndex).Get(cbs);
|
||||||
|
|
||||||
|
DescriptorSetTemplate template = program.Templates[setIndex];
|
||||||
|
|
||||||
|
DescriptorSetTemplateWriter tu = templateUpdater.Begin(template);
|
||||||
|
|
||||||
|
if (!_isBuffer)
|
||||||
|
{
|
||||||
|
tu.Push(GetImageInfos(_gd, cbs, dummyTexture));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tu.Push(GetBufferViews(cbs));
|
||||||
|
}
|
||||||
|
|
||||||
|
var sets = dsc.GetSets();
|
||||||
|
templateUpdater.Commit(_gd, device, sets[0]);
|
||||||
|
_cachedDescriptorSets = sets;
|
||||||
|
_cachedDscProgram = program;
|
||||||
|
_cachedDscSetIndex = setIndex;
|
||||||
|
|
||||||
|
return sets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void IncrementBindCount()
|
||||||
|
{
|
||||||
|
_bindCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DecrementBindCount()
|
||||||
|
{
|
||||||
|
int newBindCount = --_bindCount;
|
||||||
|
Debug.Assert(newBindCount >= 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -751,14 +751,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_vertexBufferUpdater.Commit(Cbs);
|
_vertexBufferUpdater.Commit(Cbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public void SetAlphaTest(bool enable, float reference, CompareOp op)
|
public void SetAlphaTest(bool enable, float reference, CompareOp op)
|
||||||
{
|
{
|
||||||
// This is currently handled using shader specialization, as Vulkan does not support alpha test.
|
// This is currently handled using shader specialization, as Vulkan does not support alpha test.
|
||||||
// In the future, we may want to use this to write the reference value into the support buffer,
|
// In the future, we may want to use this to write the reference value into the support buffer,
|
||||||
// to avoid creating one version of the shader per reference value used.
|
// to avoid creating one version of the shader per reference value used.
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
public void SetBlendState(AdvancedBlendDescriptor blend)
|
public void SetBlendState(AdvancedBlendDescriptor blend)
|
||||||
{
|
{
|
||||||
|
@ -903,6 +901,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_descriptorSetUpdater.SetImageArray(Cbs, stage, binding, array);
|
_descriptorSetUpdater.SetImageArray(Cbs, stage, binding, array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
|
||||||
|
{
|
||||||
|
_descriptorSetUpdater.SetImageArraySeparate(Cbs, stage, setIndex, array);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetIndexBuffer(BufferRange buffer, IndexType type)
|
public void SetIndexBuffer(BufferRange buffer, IndexType type)
|
||||||
{
|
{
|
||||||
if (buffer.Handle != BufferHandle.Null)
|
if (buffer.Handle != BufferHandle.Null)
|
||||||
|
@ -945,7 +948,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
// TODO: Default levels (likely needs emulation on shaders?)
|
// TODO: Default levels (likely needs emulation on shaders?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public void SetPointParameters(float size, bool isProgramPointSize, bool enablePointSprite, Origin origin)
|
public void SetPointParameters(float size, bool isProgramPointSize, bool enablePointSprite, Origin origin)
|
||||||
{
|
{
|
||||||
// TODO.
|
// TODO.
|
||||||
|
@ -955,7 +957,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
// TODO.
|
// TODO.
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
public void SetPrimitiveRestart(bool enable, int index)
|
public void SetPrimitiveRestart(bool enable, int index)
|
||||||
{
|
{
|
||||||
|
@ -1156,6 +1157,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_descriptorSetUpdater.SetTextureArray(Cbs, stage, binding, array);
|
_descriptorSetUpdater.SetTextureArray(Cbs, stage, binding, array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
|
||||||
|
{
|
||||||
|
_descriptorSetUpdater.SetTextureArraySeparate(Cbs, stage, setIndex, array);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
|
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
|
||||||
{
|
{
|
||||||
PauseTransformFeedbackInternal();
|
PauseTransformFeedbackInternal();
|
||||||
|
@ -1186,12 +1192,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_descriptorSetUpdater.SetUniformBuffers(CommandBuffer, buffers);
|
_descriptorSetUpdater.SetUniformBuffers(CommandBuffer, buffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable CA1822 // Mark member as static
|
|
||||||
public void SetUserClipDistance(int index, bool enableClip)
|
public void SetUserClipDistance(int index, bool enableClip)
|
||||||
{
|
{
|
||||||
// TODO.
|
// TODO.
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1822
|
|
||||||
|
|
||||||
public void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
|
public void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,7 @@ using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
|
@ -27,6 +28,24 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
private int _dsLastCbIndex;
|
private int _dsLastCbIndex;
|
||||||
private int _dsLastSubmissionCount;
|
private int _dsLastSubmissionCount;
|
||||||
|
|
||||||
|
private struct ManualDescriptorSetEntry
|
||||||
|
{
|
||||||
|
public Auto<DescriptorSetCollection> DescriptorSet;
|
||||||
|
public int CbIndex;
|
||||||
|
public int CbSubmissionCount;
|
||||||
|
public bool InUse;
|
||||||
|
|
||||||
|
public ManualDescriptorSetEntry(Auto<DescriptorSetCollection> descriptorSet, int cbIndex, int cbSubmissionCount, bool inUse)
|
||||||
|
{
|
||||||
|
DescriptorSet = descriptorSet;
|
||||||
|
CbIndex = cbIndex;
|
||||||
|
CbSubmissionCount = cbSubmissionCount;
|
||||||
|
InUse = inUse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly List<ManualDescriptorSetEntry>[] _manualDsCache;
|
||||||
|
|
||||||
private readonly Dictionary<long, DescriptorSetTemplate> _pdTemplates;
|
private readonly Dictionary<long, DescriptorSetTemplate> _pdTemplates;
|
||||||
private readonly ResourceDescriptorCollection _pdDescriptors;
|
private readonly ResourceDescriptorCollection _pdDescriptors;
|
||||||
private long _lastPdUsage;
|
private long _lastPdUsage;
|
||||||
|
@ -50,6 +69,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
|
|
||||||
_dsCacheCursor = new int[setsCount];
|
_dsCacheCursor = new int[setsCount];
|
||||||
|
_manualDsCache = new List<ManualDescriptorSetEntry>[setsCount];
|
||||||
}
|
}
|
||||||
|
|
||||||
public PipelineLayoutCacheEntry(
|
public PipelineLayoutCacheEntry(
|
||||||
|
@ -124,6 +144,51 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
return list[index];
|
return list[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Auto<DescriptorSetCollection> GetNewManualDescriptorSetCollection(int commandBufferIndex, int setIndex, out int cacheIndex)
|
||||||
|
{
|
||||||
|
int submissionCount = _gd.CommandBufferPool.GetSubmissionCount(commandBufferIndex);
|
||||||
|
|
||||||
|
var list = _manualDsCache[setIndex] ??= new();
|
||||||
|
var span = CollectionsMarshal.AsSpan(list);
|
||||||
|
|
||||||
|
for (int index = 0; index < span.Length; index++)
|
||||||
|
{
|
||||||
|
ref ManualDescriptorSetEntry entry = ref span[index];
|
||||||
|
|
||||||
|
if (!entry.InUse && (entry.CbIndex != commandBufferIndex || entry.CbSubmissionCount != submissionCount))
|
||||||
|
{
|
||||||
|
entry.InUse = true;
|
||||||
|
entry.CbIndex = commandBufferIndex;
|
||||||
|
entry.CbSubmissionCount = submissionCount;
|
||||||
|
|
||||||
|
cacheIndex = index;
|
||||||
|
|
||||||
|
return entry.DescriptorSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var dsc = _descriptorSetManager.AllocateDescriptorSet(
|
||||||
|
_gd.Api,
|
||||||
|
DescriptorSetLayouts[setIndex],
|
||||||
|
_poolSizes[setIndex],
|
||||||
|
setIndex,
|
||||||
|
_consumedDescriptorsPerSet[setIndex],
|
||||||
|
false);
|
||||||
|
|
||||||
|
cacheIndex = list.Count;
|
||||||
|
list.Add(new ManualDescriptorSetEntry(dsc, commandBufferIndex, submissionCount, inUse: true));
|
||||||
|
|
||||||
|
return dsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReleaseManualDescriptorSetCollection(int setIndex, int cacheIndex)
|
||||||
|
{
|
||||||
|
var list = _manualDsCache[setIndex];
|
||||||
|
var span = CollectionsMarshal.AsSpan(list);
|
||||||
|
|
||||||
|
span[cacheIndex].InUse = false;
|
||||||
|
}
|
||||||
|
|
||||||
private static Span<DescriptorPoolSize> GetDescriptorPoolSizes(Span<DescriptorPoolSize> output, ResourceDescriptorCollection setDescriptor, uint multiplier)
|
private static Span<DescriptorPoolSize> GetDescriptorPoolSizes(Span<DescriptorPoolSize> output, ResourceDescriptorCollection setDescriptor, uint multiplier)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -204,6 +269,21 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < _manualDsCache.Length; i++)
|
||||||
|
{
|
||||||
|
if (_manualDsCache[i] == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < _manualDsCache[i].Count; j++)
|
||||||
|
{
|
||||||
|
_manualDsCache[i][j].DescriptorSet.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_manualDsCache[i].Clear();
|
||||||
|
}
|
||||||
|
|
||||||
_gd.Api.DestroyPipelineLayout(_device, PipelineLayout, null);
|
_gd.Api.DestroyPipelineLayout(_device, PipelineLayout, null);
|
||||||
|
|
||||||
for (int i = 0; i < DescriptorSetLayouts.Length; i++)
|
for (int i = 0; i < DescriptorSetLayouts.Length; i++)
|
||||||
|
|
|
@ -604,6 +604,16 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
return _plce.GetNewDescriptorSetCollection(setIndex, out isNew);
|
return _plce.GetNewDescriptorSetCollection(setIndex, out isNew);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Auto<DescriptorSetCollection> GetNewManualDescriptorSetCollection(int commandBufferIndex, int setIndex, out int cacheIndex)
|
||||||
|
{
|
||||||
|
return _plce.GetNewManualDescriptorSetCollection(commandBufferIndex, setIndex, out cacheIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReleaseManualDescriptorSetCollection(int setIndex, int cacheIndex)
|
||||||
|
{
|
||||||
|
_plce.ReleaseManualDescriptorSetCollection(setIndex, cacheIndex);
|
||||||
|
}
|
||||||
|
|
||||||
public bool HasSameLayout(ShaderCollection other)
|
public bool HasSameLayout(ShaderCollection other)
|
||||||
{
|
{
|
||||||
return other != null && _plce == other._plce;
|
return other != null && _plce == other._plce;
|
||||||
|
|
|
@ -2,6 +2,7 @@ using Ryujinx.Graphics.GAL;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
|
@ -24,12 +25,18 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
private HashSet<TextureStorage> _storages;
|
private HashSet<TextureStorage> _storages;
|
||||||
|
|
||||||
|
private DescriptorSet[] _cachedDescriptorSets;
|
||||||
|
|
||||||
private int _cachedCommandBufferIndex;
|
private int _cachedCommandBufferIndex;
|
||||||
private int _cachedSubmissionCount;
|
private int _cachedSubmissionCount;
|
||||||
|
|
||||||
|
private ShaderCollection _cachedDscProgram;
|
||||||
|
private int _cachedDscSetIndex;
|
||||||
|
private int _cachedDscIndex;
|
||||||
|
|
||||||
private readonly bool _isBuffer;
|
private readonly bool _isBuffer;
|
||||||
|
|
||||||
public bool Bound;
|
private int _bindCount;
|
||||||
|
|
||||||
public TextureArray(VulkanRenderer gd, int size, bool isBuffer)
|
public TextureArray(VulkanRenderer gd, int size, bool isBuffer)
|
||||||
{
|
{
|
||||||
|
@ -106,9 +113,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
_cachedCommandBufferIndex = -1;
|
_cachedCommandBufferIndex = -1;
|
||||||
_storages = null;
|
_storages = null;
|
||||||
|
_cachedDescriptorSets = null;
|
||||||
|
|
||||||
|
if (_bindCount != 0)
|
||||||
|
{
|
||||||
_gd.PipelineInternal.ForceTextureDirty();
|
_gd.PipelineInternal.ForceTextureDirty();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags)
|
public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags)
|
||||||
{
|
{
|
||||||
|
@ -190,5 +201,66 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
return bufferTextures;
|
return bufferTextures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DescriptorSet[] GetDescriptorSets(
|
||||||
|
Device device,
|
||||||
|
CommandBufferScoped cbs,
|
||||||
|
DescriptorSetTemplateUpdater templateUpdater,
|
||||||
|
ShaderCollection program,
|
||||||
|
int setIndex,
|
||||||
|
TextureView dummyTexture,
|
||||||
|
SamplerHolder dummySampler)
|
||||||
|
{
|
||||||
|
if (_cachedDescriptorSets != null)
|
||||||
|
{
|
||||||
|
// We still need to ensure the current command buffer holds a reference to all used textures.
|
||||||
|
|
||||||
|
if (!_isBuffer)
|
||||||
|
{
|
||||||
|
GetImageInfos(_gd, cbs, dummyTexture, dummySampler);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GetBufferViews(cbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _cachedDescriptorSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cachedDscProgram?.ReleaseManualDescriptorSetCollection(_cachedDscSetIndex, _cachedDscIndex);
|
||||||
|
var dsc = program.GetNewManualDescriptorSetCollection(cbs.CommandBufferIndex, setIndex, out _cachedDscIndex).Get(cbs);
|
||||||
|
|
||||||
|
DescriptorSetTemplate template = program.Templates[setIndex];
|
||||||
|
|
||||||
|
DescriptorSetTemplateWriter tu = templateUpdater.Begin(template);
|
||||||
|
|
||||||
|
if (!_isBuffer)
|
||||||
|
{
|
||||||
|
tu.Push(GetImageInfos(_gd, cbs, dummyTexture, dummySampler));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tu.Push(GetBufferViews(cbs));
|
||||||
|
}
|
||||||
|
|
||||||
|
var sets = dsc.GetSets();
|
||||||
|
templateUpdater.Commit(_gd, device, sets[0]);
|
||||||
|
_cachedDescriptorSets = sets;
|
||||||
|
_cachedDscProgram = program;
|
||||||
|
_cachedDscSetIndex = setIndex;
|
||||||
|
|
||||||
|
return sets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void IncrementBindCount()
|
||||||
|
{
|
||||||
|
_bindCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DecrementBindCount()
|
||||||
|
{
|
||||||
|
int newBindCount = --_bindCount;
|
||||||
|
Debug.Assert(newBindCount >= 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -728,6 +728,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
supportsViewportSwizzle: false,
|
supportsViewportSwizzle: false,
|
||||||
supportsIndirectParameters: true,
|
supportsIndirectParameters: true,
|
||||||
supportsDepthClipControl: Capabilities.SupportsDepthClipControl,
|
supportsDepthClipControl: Capabilities.SupportsDepthClipControl,
|
||||||
|
uniformBufferSetIndex: PipelineBase.UniformSetIndex,
|
||||||
|
storageBufferSetIndex: PipelineBase.StorageSetIndex,
|
||||||
|
textureSetIndex: PipelineBase.TextureSetIndex,
|
||||||
|
imageSetIndex: PipelineBase.ImageSetIndex,
|
||||||
|
extraSetBaseIndex: PipelineBase.DescriptorSetLayouts,
|
||||||
|
maximumExtraSets: Math.Max(0, (int)limits.MaxBoundDescriptorSets - PipelineBase.DescriptorSetLayouts),
|
||||||
maximumUniformBuffersPerStage: Constants.MaxUniformBuffersPerStage,
|
maximumUniformBuffersPerStage: Constants.MaxUniformBuffersPerStage,
|
||||||
maximumStorageBuffersPerStage: Constants.MaxStorageBuffersPerStage,
|
maximumStorageBuffersPerStage: Constants.MaxStorageBuffersPerStage,
|
||||||
maximumTexturesPerStage: Constants.MaxTexturesPerStage,
|
maximumTexturesPerStage: Constants.MaxTexturesPerStage,
|
||||||
|
|
|
@ -25,32 +25,32 @@ namespace Ryujinx.ShaderTools
|
||||||
_imagesCount = 0;
|
_imagesCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CreateConstantBufferBinding(int index)
|
public SetBindingPair CreateConstantBufferBinding(int index)
|
||||||
{
|
{
|
||||||
return index + 1;
|
return new SetBindingPair(0, index + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CreateImageBinding(int count, bool isBuffer)
|
public SetBindingPair CreateImageBinding(int count, bool isBuffer)
|
||||||
{
|
{
|
||||||
int binding = _imagesCount;
|
int binding = _imagesCount;
|
||||||
|
|
||||||
_imagesCount += count;
|
_imagesCount += count;
|
||||||
|
|
||||||
return binding;
|
return new SetBindingPair(3, binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CreateStorageBufferBinding(int index)
|
public SetBindingPair CreateStorageBufferBinding(int index)
|
||||||
{
|
{
|
||||||
return index;
|
return new SetBindingPair(1, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CreateTextureBinding(int count, bool isBuffer)
|
public SetBindingPair CreateTextureBinding(int count, bool isBuffer)
|
||||||
{
|
{
|
||||||
int binding = _texturesCount;
|
int binding = _texturesCount;
|
||||||
|
|
||||||
_texturesCount += count;
|
_texturesCount += count;
|
||||||
|
|
||||||
return binding;
|
return new SetBindingPair(2, binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize)
|
public ReadOnlySpan<ulong> GetCode(ulong address, int minimumSize)
|
||||||
|
|
Loading…
Reference in a new issue