/ src / video_core / renderer_vulkan / vk_texture_runtime.h
vk_texture_runtime.h
  1  // Copyright 2023 Citra Emulator Project
  2  // Licensed under GPLv2 or any later version
  3  // Refer to the license.txt file included.
  4  
  5  #pragma once
  6  
  7  #include <deque>
  8  #include <span>
  9  #include "video_core/rasterizer_cache/framebuffer_base.h"
 10  #include "video_core/rasterizer_cache/rasterizer_cache_base.h"
 11  #include "video_core/rasterizer_cache/surface_base.h"
 12  #include "video_core/renderer_vulkan/vk_blit_helper.h"
 13  #include "video_core/renderer_vulkan/vk_instance.h"
 14  #include "video_core/renderer_vulkan/vk_stream_buffer.h"
 15  
 16  VK_DEFINE_HANDLE(VmaAllocation)
 17  
 18  namespace VideoCore {
 19  struct Material;
 20  }
 21  
 22  namespace Vulkan {
 23  
 24  class Instance;
 25  class RenderpassCache;
 26  class DescriptorPool;
 27  class DescriptorSetProvider;
 28  class Surface;
 29  
 30  struct Handle {
 31      VmaAllocation alloc;
 32      vk::Image image;
 33      vk::UniqueImageView image_view;
 34  };
 35  
 36  /**
 37   * Provides texture manipulation functions to the rasterizer cache
 38   * Separating this into a class makes it easier to abstract graphics API code
 39   */
 40  class TextureRuntime {
 41      friend class Surface;
 42  
 43  public:
 44      explicit TextureRuntime(const Instance& instance, Scheduler& scheduler,
 45                              RenderpassCache& renderpass_cache, DescriptorPool& pool,
 46                              DescriptorSetProvider& texture_provider, u32 num_swapchain_images);
 47      ~TextureRuntime();
 48  
 49      const Instance& GetInstance() const {
 50          return instance;
 51      }
 52  
 53      Scheduler& GetScheduler() const {
 54          return scheduler;
 55      }
 56  
 57      RenderpassCache& GetRenderpassCache() {
 58          return renderpass_cache;
 59      }
 60  
 61      /// Returns the removal threshold ticks for the garbage collector
 62      u32 RemoveThreshold();
 63  
 64      /// Submits and waits for current GPU work.
 65      void Finish();
 66  
 67      /// Maps an internal staging buffer of the provided size for pixel uploads/downloads
 68      VideoCore::StagingData FindStaging(u32 size, bool upload);
 69  
 70      /// Attempts to reinterpret a rectangle of source to another rectangle of dest
 71      bool Reinterpret(Surface& source, Surface& dest, const VideoCore::TextureCopy& copy);
 72  
 73      /// Fills the rectangle of the texture with the clear value provided
 74      bool ClearTexture(Surface& surface, const VideoCore::TextureClear& clear);
 75  
 76      /// Copies a rectangle of src_tex to another rectange of dst_rect
 77      bool CopyTextures(Surface& source, Surface& dest, const VideoCore::TextureCopy& copy);
 78  
 79      /// Blits a rectangle of src_tex to another rectange of dst_rect
 80      bool BlitTextures(Surface& surface, Surface& dest, const VideoCore::TextureBlit& blit);
 81  
 82      /// Generates mipmaps for all the available levels of the texture
 83      void GenerateMipmaps(Surface& surface);
 84  
 85      /// Returns true if the provided pixel format needs convertion
 86      bool NeedsConversion(VideoCore::PixelFormat format) const;
 87  
 88      /// Removes any descriptor sets that contain the provided image view.
 89      void FreeDescriptorSetsWithImage(vk::ImageView image_view);
 90  
 91  private:
 92      /// Clears a partial texture rect using a clear rectangle
 93      void ClearTextureWithRenderpass(Surface& surface, const VideoCore::TextureClear& clear);
 94  
 95  private:
 96      const Instance& instance;
 97      Scheduler& scheduler;
 98      RenderpassCache& renderpass_cache;
 99      DescriptorSetProvider& texture_provider;
100      BlitHelper blit_helper;
101      StreamBuffer upload_buffer;
102      StreamBuffer download_buffer;
103      u32 num_swapchain_images;
104  };
105  
106  class Surface : public VideoCore::SurfaceBase {
107      friend class TextureRuntime;
108  
109  public:
110      explicit Surface(TextureRuntime& runtime, const VideoCore::SurfaceParams& params);
111      explicit Surface(TextureRuntime& runtime, const VideoCore::SurfaceBase& surface,
112                       const VideoCore::Material* materal);
113      ~Surface();
114  
115      Surface(const Surface&) = delete;
116      Surface& operator=(const Surface&) = delete;
117  
118      Surface(Surface&& o) noexcept = default;
119      Surface& operator=(Surface&& o) noexcept = default;
120  
121      vk::ImageAspectFlags Aspect() const noexcept {
122          return traits.aspect;
123      }
124  
125      /// Returns the image at index, otherwise the base image
126      vk::Image Image(u32 index = 1) const noexcept;
127  
128      /// Returns the image view at index, otherwise the base view
129      vk::ImageView ImageView(u32 index = 1) const noexcept;
130  
131      /// Returns a copy of the upscaled image handle, used for feedback loops.
132      vk::ImageView CopyImageView() noexcept;
133  
134      /// Returns the framebuffer view of the surface image
135      vk::ImageView FramebufferView() noexcept;
136  
137      /// Returns the depth view of the surface image
138      vk::ImageView DepthView() noexcept;
139  
140      /// Returns the stencil view of the surface image
141      vk::ImageView StencilView() noexcept;
142  
143      /// Returns the R32 image view used for atomic load/store
144      vk::ImageView StorageView() noexcept;
145  
146      /// Returns a framebuffer handle for rendering to this surface
147      vk::Framebuffer Framebuffer() noexcept;
148  
149      /// Uploads pixel data in staging to a rectangle region of the surface texture
150      void Upload(const VideoCore::BufferTextureCopy& upload, const VideoCore::StagingData& staging);
151  
152      /// Uploads the custom material to the surface allocation.
153      void UploadCustom(const VideoCore::Material* material, u32 level);
154  
155      /// Downloads pixel data to staging from a rectangle region of the surface texture
156      void Download(const VideoCore::BufferTextureCopy& download,
157                    const VideoCore::StagingData& staging);
158  
159      /// Scales up the surface to match the new resolution scale.
160      void ScaleUp(u32 new_scale);
161  
162      /// Returns the bpp of the internal surface format
163      u32 GetInternalBytesPerPixel() const;
164  
165      /// Returns the access flags indicative of the surface
166      vk::AccessFlags AccessFlags() const noexcept;
167  
168      /// Returns the pipeline stage flags indicative of the surface
169      vk::PipelineStageFlags PipelineStageFlags() const noexcept;
170  
171  private:
172      /// Performs blit between the scaled/unscaled images
173      void BlitScale(const VideoCore::TextureBlit& blit, bool up_scale);
174  
175      /// Downloads scaled depth stencil data
176      void DepthStencilDownload(const VideoCore::BufferTextureCopy& download,
177                                const VideoCore::StagingData& staging);
178  
179  public:
180      TextureRuntime* runtime;
181      const Instance* instance;
182      Scheduler* scheduler;
183      FormatTraits traits;
184      std::array<Handle, 3> handles{};
185      std::array<vk::UniqueFramebuffer, 2> framebuffers{};
186      Handle copy_handle;
187      vk::UniqueImageView depth_view;
188      vk::UniqueImageView stencil_view;
189      vk::UniqueImageView storage_view;
190      bool is_framebuffer{};
191      bool is_storage{};
192  };
193  
194  class Framebuffer : public VideoCore::FramebufferParams {
195  public:
196      explicit Framebuffer(TextureRuntime& runtime, const VideoCore::FramebufferParams& params,
197                           Surface* color, Surface* depth_stencil);
198      ~Framebuffer();
199  
200      Framebuffer(const Framebuffer&) = delete;
201      Framebuffer& operator=(const Framebuffer&) = delete;
202  
203      Framebuffer(Framebuffer&& o) noexcept = default;
204      Framebuffer& operator=(Framebuffer&& o) noexcept = default;
205  
206      VideoCore::PixelFormat Format(VideoCore::SurfaceType type) const noexcept {
207          return formats[Index(type)];
208      }
209  
210      [[nodiscard]] vk::ImageView ImageView(VideoCore::SurfaceType type) const noexcept {
211          return image_views[Index(type)];
212      }
213  
214      [[nodiscard]] vk::Framebuffer Handle() const noexcept {
215          return framebuffer.get();
216      }
217  
218      [[nodiscard]] std::array<vk::Image, 2> Images() const noexcept {
219          return images;
220      }
221  
222      [[nodiscard]] std::array<vk::ImageAspectFlags, 2> Aspects() const noexcept {
223          return aspects;
224      }
225  
226      [[nodiscard]] vk::RenderPass RenderPass() const noexcept {
227          return render_pass;
228      }
229  
230      u32 Scale() const noexcept {
231          return res_scale;
232      }
233  
234      u32 Width() const noexcept {
235          return width;
236      }
237  
238      u32 Height() const noexcept {
239          return height;
240      }
241  
242  private:
243      std::array<vk::Image, 2> images{};
244      std::array<vk::ImageView, 2> image_views{};
245      vk::UniqueFramebuffer framebuffer;
246      vk::RenderPass render_pass;
247      std::array<vk::ImageAspectFlags, 2> aspects{};
248      std::array<VideoCore::PixelFormat, 2> formats{VideoCore::PixelFormat::Invalid,
249                                                    VideoCore::PixelFormat::Invalid};
250      u32 width{};
251      u32 height{};
252      u32 res_scale{1};
253  };
254  
255  class Sampler {
256  public:
257      Sampler(TextureRuntime& runtime, const VideoCore::SamplerParams& params);
258      ~Sampler();
259  
260      Sampler(const Sampler&) = delete;
261      Sampler& operator=(const Sampler&) = delete;
262  
263      Sampler(Sampler&& o) noexcept = default;
264      Sampler& operator=(Sampler&& o) noexcept = default;
265  
266      [[nodiscard]] vk::Sampler Handle() const noexcept {
267          return sampler.get();
268      }
269  
270  private:
271      vk::UniqueSampler sampler;
272  };
273  
274  class DebugScope {
275  public:
276      template <typename... T>
277      explicit DebugScope(TextureRuntime& runtime, Common::Vec4f color,
278                          fmt::format_string<T...> format, T... args)
279          : DebugScope{runtime, color, fmt::format(format, std::forward<T>(args)...)} {}
280      explicit DebugScope(TextureRuntime& runtime, Common::Vec4f color, std::string_view label);
281      ~DebugScope();
282  
283  private:
284      Scheduler& scheduler;
285      bool has_debug_tool;
286  };
287  
288  struct Traits {
289      using Runtime = Vulkan::TextureRuntime;
290      using Surface = Vulkan::Surface;
291      using Sampler = Vulkan::Sampler;
292      using Framebuffer = Vulkan::Framebuffer;
293      using DebugScope = Vulkan::DebugScope;
294  };
295  
296  using RasterizerCache = VideoCore::RasterizerCache<Traits>;
297  
298  } // namespace Vulkan