mirror of
				https://github.com/ryujinx-mirror/ryujinx.git
				synced 2025-11-04 08:59:04 -06:00 
			
		
		
		
	Disable descriptor set template updates for buffer textures on Adreno (#7002)
* Do not use template updates for buffer textures and buffer images * No need to do it for images * Simply buffer texture existence check * Pipeline is now unused on DescriptorSetUpdater
This commit is contained in:
		@@ -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
 | 
			
		||||
                {
 | 
			
		||||
                    SType = StructureType.WriteDescriptorSet,
 | 
			
		||||
                    DstBinding = (uint)baseBinding,
 | 
			
		||||
                    DescriptorType = type,
 | 
			
		||||
                    DescriptorCount = (uint)bufferInfo.Length,
 | 
			
		||||
                    PBufferInfo = pBufferInfo,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                _gd.PushDescriptorApi.CmdPushDescriptorSet(cbs.CommandBuffer, pbp, _program.PipelineLayout, 0, 1, &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)
 | 
			
		||||
                {
 | 
			
		||||
                    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];
 | 
			
		||||
 | 
			
		||||
                            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)]
 | 
			
		||||
 
 | 
			
		||||
@@ -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];
 | 
			
		||||
 
 | 
			
		||||
@@ -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 ||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user