aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs98
-rw-r--r--src/Ryujinx.Graphics.Vulkan/PipelineBase.cs2
-rw-r--r--src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs16
3 files changed, 93 insertions, 23 deletions
diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs
index 3590d5d0..75ffca2c 100644
--- a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs
+++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs
@@ -73,7 +73,6 @@ namespace Ryujinx.Graphics.Vulkan
private readonly VulkanRenderer _gd;
private readonly Device _device;
- private readonly PipelineBase _pipeline;
private ShaderCollection _program;
private readonly BufferRef[] _uniformBufferRefs;
@@ -125,11 +124,10 @@ namespace Ryujinx.Graphics.Vulkan
private readonly TextureView _dummyTexture;
private readonly SamplerHolder _dummySampler;
- public DescriptorSetUpdater(VulkanRenderer gd, Device device, PipelineBase pipeline)
+ public DescriptorSetUpdater(VulkanRenderer gd, Device device)
{
_gd = gd;
_device = device;
- _pipeline = pipeline;
// Some of the bindings counts needs to be multiplied by 2 because we have buffer and
// regular textures/images interleaved on the same descriptor set.
@@ -684,7 +682,14 @@ namespace Ryujinx.Graphics.Vulkan
if (_dirty.HasFlag(DirtyFlags.Texture))
{
- UpdateAndBind(cbs, program, PipelineBase.TextureSetIndex, pbp);
+ if (program.UpdateTexturesWithoutTemplate)
+ {
+ UpdateAndBindTexturesWithoutTemplate(cbs, program, pbp);
+ }
+ else
+ {
+ UpdateAndBind(cbs, program, PipelineBase.TextureSetIndex, pbp);
+ }
}
if (_dirty.HasFlag(DirtyFlags.Image))
@@ -918,31 +923,84 @@ namespace Ryujinx.Graphics.Vulkan
_gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
}
- private unsafe void UpdateBuffers(
- CommandBufferScoped cbs,
- PipelineBindPoint pbp,
- int baseBinding,
- ReadOnlySpan<DescriptorBufferInfo> bufferInfo,
- DescriptorType type)
+ private void UpdateAndBindTexturesWithoutTemplate(CommandBufferScoped cbs, ShaderCollection program, PipelineBindPoint pbp)
{
- if (bufferInfo.Length == 0)
+ int setIndex = PipelineBase.TextureSetIndex;
+ var bindingSegments = program.BindingSegments[setIndex];
+
+ if (bindingSegments.Length == 0)
{
return;
}
- fixed (DescriptorBufferInfo* pBufferInfo = bufferInfo)
+ if (_updateDescriptorCacheCbIndex)
{
- var writeDescriptorSet = new WriteDescriptorSet
+ _updateDescriptorCacheCbIndex = false;
+ program.UpdateDescriptorCacheCommandBufferIndex(cbs.CommandBufferIndex);
+ }
+
+ var dsc = program.GetNewDescriptorSetCollection(setIndex, out _).Get(cbs);
+
+ foreach (ResourceBindingSegment segment in bindingSegments)
+ {
+ int binding = segment.Binding;
+ int count = segment.Count;
+
+ if (!segment.IsArray)
{
- SType = StructureType.WriteDescriptorSet,
- DstBinding = (uint)baseBinding,
- DescriptorType = type,
- DescriptorCount = (uint)bufferInfo.Length,
- PBufferInfo = pBufferInfo,
- };
+ if (segment.Type != ResourceType.BufferTexture)
+ {
+ Span<DescriptorImageInfo> textures = _textures;
+
+ for (int i = 0; i < count; i++)
+ {
+ ref var texture = ref textures[i];
+ ref var refs = ref _textureRefs[binding + i];
- _gd.PushDescriptorApi.CmdPushDescriptorSet(cbs.CommandBuffer, pbp, _program.PipelineLayout, 0, 1, &writeDescriptorSet);
+ texture.ImageView = refs.View?.Get(cbs).Value ?? default;
+ texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
+
+ if (texture.ImageView.Handle == 0)
+ {
+ texture.ImageView = _dummyTexture.GetImageView().Get(cbs).Value;
+ }
+
+ if (texture.Sampler.Handle == 0)
+ {
+ texture.Sampler = _dummySampler.GetSampler().Get(cbs).Value;
+ }
+ }
+
+ dsc.UpdateImages(0, binding, textures[..count], DescriptorType.CombinedImageSampler);
+ }
+ else
+ {
+ Span<BufferView> bufferTextures = _bufferTextures;
+
+ for (int i = 0; i < count; i++)
+ {
+ bufferTextures[i] = _bufferTextureRefs[binding + i]?.GetBufferView(cbs, false) ?? default;
+ }
+
+ dsc.UpdateBufferImages(0, binding, bufferTextures[..count], DescriptorType.UniformTexelBuffer);
+ }
+ }
+ else
+ {
+ if (segment.Type != ResourceType.BufferTexture)
+ {
+ dsc.UpdateImages(0, binding, _textureArrayRefs[binding].Array.GetImageInfos(_gd, cbs, _dummyTexture, _dummySampler), DescriptorType.CombinedImageSampler);
+ }
+ else
+ {
+ dsc.UpdateBufferImages(0, binding, _textureArrayRefs[binding].Array.GetBufferViews(cbs), DescriptorType.UniformTexelBuffer);
+ }
+ }
}
+
+ var sets = dsc.GetSets();
+
+ _gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs
index 918de59b..8d7cd547 100644
--- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs
+++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs
@@ -105,7 +105,7 @@ namespace Ryujinx.Graphics.Vulkan
gd.Api.CreatePipelineCache(device, pipelineCacheCreateInfo, null, out PipelineCache).ThrowOnError();
- _descriptorSetUpdater = new DescriptorSetUpdater(gd, device, this);
+ _descriptorSetUpdater = new DescriptorSetUpdater(gd, device);
_vertexBufferUpdater = new VertexBufferUpdater(gd);
_transformFeedbackBuffers = new BufferState[Constants.MaxTransformFeedbackBuffers];
diff --git a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs
index f9637789..eec2a318 100644
--- a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs
+++ b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs
@@ -23,6 +23,8 @@ namespace Ryujinx.Graphics.Vulkan
public bool IsCompute { get; }
public bool HasTessellationControlShader => (Stages & (1u << 3)) != 0;
+ public bool UpdateTexturesWithoutTemplate { get; }
+
public uint Stages { get; }
public ResourceBindingSegment[][] ClearSegments { get; }
@@ -127,9 +129,12 @@ namespace Ryujinx.Graphics.Vulkan
Stages = stages;
ClearSegments = BuildClearSegments(sets);
- BindingSegments = BuildBindingSegments(resourceLayout.SetUsages);
+ BindingSegments = BuildBindingSegments(resourceLayout.SetUsages, out bool usesBufferTextures);
Templates = BuildTemplates(usePushDescriptors);
+ // Updating buffer texture bindings using template updates crashes the Adreno driver on Windows.
+ UpdateTexturesWithoutTemplate = gd.Vendor == Vendor.Qualcomm && usesBufferTextures;
+
_compileTask = Task.CompletedTask;
_firstBackgroundUse = false;
}
@@ -280,8 +285,10 @@ namespace Ryujinx.Graphics.Vulkan
return segments;
}
- private static ResourceBindingSegment[][] BuildBindingSegments(ReadOnlyCollection<ResourceUsageCollection> setUsages)
+ private static ResourceBindingSegment[][] BuildBindingSegments(ReadOnlyCollection<ResourceUsageCollection> setUsages, out bool usesBufferTextures)
{
+ usesBufferTextures = false;
+
ResourceBindingSegment[][] segments = new ResourceBindingSegment[setUsages.Count][];
for (int setIndex = 0; setIndex < setUsages.Count; setIndex++)
@@ -295,6 +302,11 @@ namespace Ryujinx.Graphics.Vulkan
{
ResourceUsage usage = setUsages[setIndex].Usages[index];
+ if (usage.Type == ResourceType.BufferTexture)
+ {
+ usesBufferTextures = true;
+ }
+
if (currentUsage.Binding + currentCount != usage.Binding ||
currentUsage.Type != usage.Type ||
currentUsage.Stages != usage.Stages ||