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