/ src / Ryujinx.Graphics.Vulkan / FramebufferParams.cs
FramebufferParams.cs
  1  using Ryujinx.Graphics.GAL;
  2  using Silk.NET.Vulkan;
  3  using System;
  4  using System.Linq;
  5  using VkFormat = Silk.NET.Vulkan.Format;
  6  
  7  namespace Ryujinx.Graphics.Vulkan
  8  {
  9      class FramebufferParams
 10      {
 11          private readonly Device _device;
 12          private readonly Auto<DisposableImageView>[] _attachments;
 13          private readonly TextureView[] _colors;
 14          private readonly TextureView _depthStencil;
 15          private readonly TextureView[] _colorsCanonical;
 16          private readonly TextureView _baseAttachment;
 17          private readonly uint _validColorAttachments;
 18  
 19          public uint Width { get; }
 20          public uint Height { get; }
 21          public uint Layers { get; }
 22  
 23          public uint[] AttachmentSamples { get; }
 24          public VkFormat[] AttachmentFormats { get; }
 25          public int[] AttachmentIndices { get; }
 26          public uint AttachmentIntegerFormatMask { get; }
 27          public bool LogicOpsAllowed { get; }
 28  
 29          public int AttachmentsCount { get; }
 30          public int MaxColorAttachmentIndex => AttachmentIndices.Length > 0 ? AttachmentIndices[^1] : -1;
 31          public bool HasDepthStencil { get; }
 32          public int ColorAttachmentsCount => AttachmentsCount - (HasDepthStencil ? 1 : 0);
 33  
 34          public FramebufferParams(Device device, TextureView view, uint width, uint height)
 35          {
 36              var format = view.Info.Format;
 37  
 38              bool isDepthStencil = format.IsDepthOrStencil();
 39  
 40              _device = device;
 41              _attachments = new[] { view.GetImageViewForAttachment() };
 42              _validColorAttachments = isDepthStencil ? 0u : 1u;
 43              _baseAttachment = view;
 44  
 45              if (isDepthStencil)
 46              {
 47                  _depthStencil = view;
 48              }
 49              else
 50              {
 51                  _colors = new TextureView[] { view };
 52                  _colorsCanonical = _colors;
 53              }
 54  
 55              Width = width;
 56              Height = height;
 57              Layers = 1;
 58  
 59              AttachmentSamples = new[] { (uint)view.Info.Samples };
 60              AttachmentFormats = new[] { view.VkFormat };
 61              AttachmentIndices = isDepthStencil ? Array.Empty<int>() : new[] { 0 };
 62              AttachmentIntegerFormatMask = format.IsInteger() ? 1u : 0u;
 63              LogicOpsAllowed = !format.IsFloatOrSrgb();
 64  
 65              AttachmentsCount = 1;
 66  
 67              HasDepthStencil = isDepthStencil;
 68          }
 69  
 70          public FramebufferParams(Device device, ITexture[] colors, ITexture depthStencil)
 71          {
 72              _device = device;
 73  
 74              int colorsCount = colors.Count(IsValidTextureView);
 75  
 76              int count = colorsCount + (IsValidTextureView(depthStencil) ? 1 : 0);
 77  
 78              _attachments = new Auto<DisposableImageView>[count];
 79              _colors = new TextureView[colorsCount];
 80              _colorsCanonical = colors.Select(color => color is TextureView view && view.Valid ? view : null).ToArray();
 81  
 82              AttachmentSamples = new uint[count];
 83              AttachmentFormats = new VkFormat[count];
 84              AttachmentIndices = new int[colorsCount];
 85  
 86              uint width = uint.MaxValue;
 87              uint height = uint.MaxValue;
 88              uint layers = uint.MaxValue;
 89  
 90              int index = 0;
 91              int bindIndex = 0;
 92              uint attachmentIntegerFormatMask = 0;
 93              bool allFormatsFloatOrSrgb = colorsCount != 0;
 94  
 95              foreach (ITexture color in colors)
 96              {
 97                  if (IsValidTextureView(color))
 98                  {
 99                      var texture = (TextureView)color;
100  
101                      _attachments[index] = texture.GetImageViewForAttachment();
102                      _colors[index] = texture;
103                      _validColorAttachments |= 1u << bindIndex;
104                      _baseAttachment = texture;
105  
106                      AttachmentSamples[index] = (uint)texture.Info.Samples;
107                      AttachmentFormats[index] = texture.VkFormat;
108                      AttachmentIndices[index] = bindIndex;
109  
110                      var format = texture.Info.Format;
111  
112                      if (format.IsInteger())
113                      {
114                          attachmentIntegerFormatMask |= 1u << bindIndex;
115                      }
116  
117                      allFormatsFloatOrSrgb &= format.IsFloatOrSrgb();
118  
119                      width = Math.Min(width, (uint)texture.Width);
120                      height = Math.Min(height, (uint)texture.Height);
121                      layers = Math.Min(layers, (uint)texture.Layers);
122  
123                      if (++index >= colorsCount)
124                      {
125                          break;
126                      }
127                  }
128  
129                  bindIndex++;
130              }
131  
132              AttachmentIntegerFormatMask = attachmentIntegerFormatMask;
133              LogicOpsAllowed = !allFormatsFloatOrSrgb;
134  
135              if (depthStencil is TextureView dsTexture && dsTexture.Valid)
136              {
137                  _attachments[count - 1] = dsTexture.GetImageViewForAttachment();
138                  _depthStencil = dsTexture;
139                  _baseAttachment ??= dsTexture;
140  
141                  AttachmentSamples[count - 1] = (uint)dsTexture.Info.Samples;
142                  AttachmentFormats[count - 1] = dsTexture.VkFormat;
143  
144                  width = Math.Min(width, (uint)dsTexture.Width);
145                  height = Math.Min(height, (uint)dsTexture.Height);
146                  layers = Math.Min(layers, (uint)dsTexture.Layers);
147  
148                  HasDepthStencil = true;
149              }
150  
151              if (count == 0)
152              {
153                  width = height = layers = 1;
154              }
155  
156              Width = width;
157              Height = height;
158              Layers = layers;
159  
160              AttachmentsCount = count;
161          }
162  
163          public Auto<DisposableImageView> GetAttachment(int index)
164          {
165              if ((uint)index >= _attachments.Length)
166              {
167                  return null;
168              }
169  
170              return _attachments[index];
171          }
172  
173          public Auto<DisposableImageView> GetDepthStencilAttachment()
174          {
175              if (!HasDepthStencil)
176              {
177                  return null;
178              }
179  
180              return _attachments[AttachmentsCount - 1];
181          }
182  
183          public ComponentType GetAttachmentComponentType(int index)
184          {
185              if (_colors != null && (uint)index < _colors.Length)
186              {
187                  var format = _colors[index].Info.Format;
188  
189                  if (format.IsSint())
190                  {
191                      return ComponentType.SignedInteger;
192                  }
193  
194                  if (format.IsUint())
195                  {
196                      return ComponentType.UnsignedInteger;
197                  }
198              }
199  
200              return ComponentType.Float;
201          }
202  
203          public ImageAspectFlags GetDepthStencilAspectFlags()
204          {
205              if (_depthStencil == null)
206              {
207                  return ImageAspectFlags.None;
208              }
209  
210              return _depthStencil.Info.Format.ConvertAspectFlags();
211          }
212  
213          public bool IsValidColorAttachment(int bindIndex)
214          {
215              return (uint)bindIndex < Constants.MaxRenderTargets && (_validColorAttachments & (1u << bindIndex)) != 0;
216          }
217  
218          private static bool IsValidTextureView(ITexture texture)
219          {
220              return texture is TextureView view && view.Valid;
221          }
222  
223          public ClearRect GetClearRect(Rectangle<int> scissor, int layer, int layerCount)
224          {
225              int x = scissor.X;
226              int y = scissor.Y;
227              int width = Math.Min((int)Width - scissor.X, scissor.Width);
228              int height = Math.Min((int)Height - scissor.Y, scissor.Height);
229  
230              return new ClearRect(new Rect2D(new Offset2D(x, y), new Extent2D((uint)width, (uint)height)), (uint)layer, (uint)layerCount);
231          }
232  
233          public unsafe Auto<DisposableFramebuffer> Create(Vk api, CommandBufferScoped cbs, Auto<DisposableRenderPass> renderPass)
234          {
235              ImageView* attachments = stackalloc ImageView[_attachments.Length];
236  
237              for (int i = 0; i < _attachments.Length; i++)
238              {
239                  attachments[i] = _attachments[i].Get(cbs).Value;
240              }
241  
242              var framebufferCreateInfo = new FramebufferCreateInfo
243              {
244                  SType = StructureType.FramebufferCreateInfo,
245                  RenderPass = renderPass.Get(cbs).Value,
246                  AttachmentCount = (uint)_attachments.Length,
247                  PAttachments = attachments,
248                  Width = Width,
249                  Height = Height,
250                  Layers = Layers,
251              };
252  
253              api.CreateFramebuffer(_device, in framebufferCreateInfo, null, out var framebuffer).ThrowOnError();
254              return new Auto<DisposableFramebuffer>(new DisposableFramebuffer(api, _device, framebuffer), null, _attachments);
255          }
256  
257          public TextureView[] GetAttachmentViews()
258          {
259              var result = new TextureView[_attachments.Length];
260  
261              _colors?.CopyTo(result, 0);
262  
263              if (_depthStencil != null)
264              {
265                  result[^1] = _depthStencil;
266              }
267  
268              return result;
269          }
270  
271          public RenderPassCacheKey GetRenderPassCacheKey()
272          {
273              return new RenderPassCacheKey(_depthStencil, _colorsCanonical);
274          }
275  
276          public void InsertLoadOpBarriers(VulkanRenderer gd, CommandBufferScoped cbs)
277          {
278              if (_colors != null)
279              {
280                  foreach (var color in _colors)
281                  {
282                      // If Clear or DontCare were used, this would need to be write bit.
283                      color.Storage?.QueueLoadOpBarrier(cbs, false);
284                  }
285              }
286  
287              _depthStencil?.Storage?.QueueLoadOpBarrier(cbs, true);
288  
289              gd.Barriers.Flush(cbs, false, null, null);
290          }
291  
292          public void AddStoreOpUsage()
293          {
294              if (_colors != null)
295              {
296                  foreach (var color in _colors)
297                  {
298                      color.Storage?.AddStoreOpUsage(false);
299                  }
300              }
301  
302              _depthStencil?.Storage?.AddStoreOpUsage(true);
303          }
304  
305          public void ClearBindings()
306          {
307              _depthStencil?.Storage.ClearBindings();
308  
309              for (int i = 0; i < _colorsCanonical.Length; i++)
310              {
311                  _colorsCanonical[i]?.Storage.ClearBindings();
312              }
313          }
314  
315          public void AddBindings()
316          {
317              _depthStencil?.Storage.AddBinding(_depthStencil);
318  
319              for (int i = 0; i < _colorsCanonical.Length; i++)
320              {
321                  TextureView color = _colorsCanonical[i];
322                  color?.Storage.AddBinding(color);
323              }
324          }
325  
326          public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer(
327              VulkanRenderer gd,
328              Device device,
329              CommandBufferScoped cbs)
330          {
331              return _baseAttachment.GetPassAndFramebuffer(gd, device, cbs, this);
332          }
333  
334          public TextureView GetColorView(int index)
335          {
336              return _colorsCanonical[index];
337          }
338  
339          public TextureView GetDepthStencilView()
340          {
341              return _depthStencil;
342          }
343      }
344  }