ImageArray.cs
1 using Ryujinx.Graphics.GAL; 2 using Silk.NET.Vulkan; 3 using System; 4 using System.Collections.Generic; 5 6 namespace Ryujinx.Graphics.Vulkan 7 { 8 class ImageArray : ResourceArray, IImageArray 9 { 10 private readonly VulkanRenderer _gd; 11 12 private record struct TextureRef 13 { 14 public TextureStorage Storage; 15 public TextureView View; 16 } 17 18 private readonly TextureRef[] _textureRefs; 19 private readonly TextureBuffer[] _bufferTextureRefs; 20 21 private readonly DescriptorImageInfo[] _textures; 22 private readonly BufferView[] _bufferTextures; 23 24 private HashSet<TextureStorage> _storages; 25 26 private int _cachedCommandBufferIndex; 27 private int _cachedSubmissionCount; 28 29 private readonly bool _isBuffer; 30 31 public ImageArray(VulkanRenderer gd, int size, bool isBuffer) 32 { 33 _gd = gd; 34 35 if (isBuffer) 36 { 37 _bufferTextureRefs = new TextureBuffer[size]; 38 _bufferTextures = new BufferView[size]; 39 } 40 else 41 { 42 _textureRefs = new TextureRef[size]; 43 _textures = new DescriptorImageInfo[size]; 44 } 45 46 _storages = null; 47 48 _cachedCommandBufferIndex = -1; 49 _cachedSubmissionCount = 0; 50 51 _isBuffer = isBuffer; 52 } 53 54 public void SetImages(int index, ITexture[] images) 55 { 56 for (int i = 0; i < images.Length; i++) 57 { 58 ITexture image = images[i]; 59 60 if (image is TextureBuffer textureBuffer) 61 { 62 _bufferTextureRefs[index + i] = textureBuffer; 63 } 64 else if (image is TextureView view) 65 { 66 _textureRefs[index + i].Storage = view.Storage; 67 _textureRefs[index + i].View = view; 68 } 69 else if (!_isBuffer) 70 { 71 _textureRefs[index + i].Storage = null; 72 _textureRefs[index + i].View = default; 73 } 74 else 75 { 76 _bufferTextureRefs[index + i] = null; 77 } 78 } 79 80 SetDirty(); 81 } 82 83 private void SetDirty() 84 { 85 _cachedCommandBufferIndex = -1; 86 _storages = null; 87 SetDirty(_gd, isImage: true); 88 } 89 90 public void QueueWriteToReadBarriers(CommandBufferScoped cbs, PipelineStageFlags stageFlags) 91 { 92 HashSet<TextureStorage> storages = _storages; 93 94 if (storages == null) 95 { 96 storages = new HashSet<TextureStorage>(); 97 98 for (int index = 0; index < _textureRefs.Length; index++) 99 { 100 if (_textureRefs[index].Storage != null) 101 { 102 storages.Add(_textureRefs[index].Storage); 103 } 104 } 105 106 _storages = storages; 107 } 108 109 foreach (TextureStorage storage in storages) 110 { 111 storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stageFlags); 112 } 113 } 114 115 public ReadOnlySpan<DescriptorImageInfo> GetImageInfos(VulkanRenderer gd, CommandBufferScoped cbs, TextureView dummyTexture) 116 { 117 int submissionCount = gd.CommandBufferPool.GetSubmissionCount(cbs.CommandBufferIndex); 118 119 Span<DescriptorImageInfo> textures = _textures; 120 121 if (cbs.CommandBufferIndex == _cachedCommandBufferIndex && submissionCount == _cachedSubmissionCount) 122 { 123 return textures; 124 } 125 126 _cachedCommandBufferIndex = cbs.CommandBufferIndex; 127 _cachedSubmissionCount = submissionCount; 128 129 for (int i = 0; i < textures.Length; i++) 130 { 131 ref var texture = ref textures[i]; 132 ref var refs = ref _textureRefs[i]; 133 134 if (i > 0 && _textureRefs[i - 1].View == refs.View) 135 { 136 texture = textures[i - 1]; 137 138 continue; 139 } 140 141 texture.ImageLayout = ImageLayout.General; 142 texture.ImageView = refs.View?.GetIdentityImageView().Get(cbs).Value ?? default; 143 144 if (texture.ImageView.Handle == 0) 145 { 146 texture.ImageView = dummyTexture.GetImageView().Get(cbs).Value; 147 } 148 } 149 150 return textures; 151 } 152 153 public ReadOnlySpan<BufferView> GetBufferViews(CommandBufferScoped cbs) 154 { 155 Span<BufferView> bufferTextures = _bufferTextures; 156 157 for (int i = 0; i < bufferTextures.Length; i++) 158 { 159 bufferTextures[i] = _bufferTextureRefs[i]?.GetBufferView(cbs, true) ?? default; 160 } 161 162 return bufferTextures; 163 } 164 165 public DescriptorSet[] GetDescriptorSets( 166 Device device, 167 CommandBufferScoped cbs, 168 DescriptorSetTemplateUpdater templateUpdater, 169 ShaderCollection program, 170 int setIndex, 171 TextureView dummyTexture) 172 { 173 if (TryGetCachedDescriptorSets(cbs, program, setIndex, out DescriptorSet[] sets)) 174 { 175 // We still need to ensure the current command buffer holds a reference to all used textures. 176 177 if (!_isBuffer) 178 { 179 GetImageInfos(_gd, cbs, dummyTexture); 180 } 181 else 182 { 183 GetBufferViews(cbs); 184 } 185 186 return sets; 187 } 188 189 DescriptorSetTemplate template = program.Templates[setIndex]; 190 191 DescriptorSetTemplateWriter tu = templateUpdater.Begin(template); 192 193 if (!_isBuffer) 194 { 195 tu.Push(GetImageInfos(_gd, cbs, dummyTexture)); 196 } 197 else 198 { 199 tu.Push(GetBufferViews(cbs)); 200 } 201 202 templateUpdater.Commit(_gd, device, sets[0]); 203 204 return sets; 205 } 206 } 207 }