// Copyright 2019 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include "common/settings.h" #include "shader_recompiler/shader_info.h" #include "video_core/delayed_destruction_ring.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" #include "video_core/texture_cache/image_view_base.h" #include "video_core/texture_cache/texture_cache_base.h" #include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { using VideoCommon::DelayedDestructionRing; using VideoCommon::ImageId; using VideoCommon::NUM_RT; using VideoCommon::Region2D; using VideoCommon::RenderTargets; using VideoCore::Surface::PixelFormat; class ASTCDecoderPass; class BlitImageHelper; class Device; class Image; class ImageView; class Framebuffer; class RenderPassCache; class StagingBufferPool; class VKScheduler; class TextureCacheRuntime { public: static constexpr size_t TICKS_TO_DESTROY = 6; explicit TextureCacheRuntime(const Device& device_, VKScheduler& scheduler_, MemoryAllocator& memory_allocator_, StagingBufferPool& staging_buffer_pool_, BlitImageHelper& blit_image_helper_, ASTCDecoderPass& astc_decoder_pass_, RenderPassCache& render_pass_cache_); void Finish(); StagingBufferRef UploadStagingBuffer(size_t size); StagingBufferRef DownloadStagingBuffer(size_t size); void TickFrame(); u64 GetDeviceLocalMemory() const; void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, const Region2D& dst_region, const Region2D& src_region, Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Operation operation); void CopyImage(Image& dst, Image& src, std::span copies); void ConvertImage(Framebuffer* dst, ImageView& dst_view, ImageView& src_view); bool CanAccelerateImageUpload(Image&) const noexcept { return false; } void AccelerateImageUpload(Image&, const StagingBufferRef&, std::span); void InsertUploadMemoryBarrier() {} bool HasBrokenTextureViewFormats() const noexcept { // No known Vulkan driver has broken image views return false; } bool HasNativeBgr() const noexcept { // All known Vulkan drivers can natively handle BGR textures return true; } const Device& device; VKScheduler& scheduler; MemoryAllocator& memory_allocator; StagingBufferPool& staging_buffer_pool; BlitImageHelper& blit_image_helper; ASTCDecoderPass& astc_decoder_pass; RenderPassCache& render_pass_cache; DelayedDestructionRing prescaled_images; DelayedDestructionRing prescaled_commits; Settings::ResolutionScalingInfo resolution; bool is_rescaling_on{}; }; class Image : public VideoCommon::ImageBase { public: explicit Image(TextureCacheRuntime&, const VideoCommon::ImageInfo& info, GPUVAddr gpu_addr, VAddr cpu_addr); explicit Image(const VideoCommon::NullImageParams&); ~Image(); Image(const Image&) = delete; Image& operator=(const Image&) = delete; Image(Image&&) = default; Image& operator=(Image&&) = default; void UploadMemory(const StagingBufferRef& map, std::span copies); void DownloadMemory(const StagingBufferRef& map, std::span copies); [[nodiscard]] VkImage Handle() const noexcept { return *image; } [[nodiscard]] VkImageAspectFlags AspectMask() const noexcept { return aspect_mask; } [[nodiscard]] VkImageView StorageImageView(s32 level) const noexcept { return *storage_image_views[level]; } /// Returns true when the image is already initialized and mark it as initialized [[nodiscard]] bool ExchangeInitialization() noexcept { return std::exchange(initialized, true); } bool ScaleUp(bool save_as_backup = false); bool ScaleDown(bool save_as_backup = false); void SwapBackup(); private: VKScheduler* scheduler; vk::Image image; MemoryCommit commit; vk::ImageView image_view; std::vector storage_image_views; VkImageAspectFlags aspect_mask = 0; bool initialized = false; TextureCacheRuntime* runtime; u32 scaling_count{}; vk::Image backup_image{}; MemoryCommit backup_commit{}; bool has_backup{}; }; class ImageView : public VideoCommon::ImageViewBase { public: explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageViewInfo&, ImageId, Image&); explicit ImageView(TextureCacheRuntime&, const VideoCommon::ImageInfo&, const VideoCommon::ImageViewInfo&, GPUVAddr); explicit ImageView(TextureCacheRuntime&, const VideoCommon::NullImageViewParams&); [[nodiscard]] VkImageView DepthView(); [[nodiscard]] VkImageView StencilView(); [[nodiscard]] VkImageView StorageView(Shader::TextureType texture_type, Shader::ImageFormat image_format); [[nodiscard]] VkImageView Handle(Shader::TextureType texture_type) const noexcept { return *image_views[static_cast(texture_type)]; } [[nodiscard]] VkImage ImageHandle() const noexcept { return image_handle; } [[nodiscard]] VkImageView RenderTarget() const noexcept { return render_target; } [[nodiscard]] VkSampleCountFlagBits Samples() const noexcept { return samples; } [[nodiscard]] GPUVAddr GpuAddr() const noexcept { return gpu_addr; } [[nodiscard]] u32 BufferSize() const noexcept { return buffer_size; } private: struct StorageViews { std::array signeds; std::array unsigneds; }; [[nodiscard]] vk::ImageView MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask); const Device* device = nullptr; std::array image_views; std::unique_ptr storage_views; vk::ImageView depth_view; vk::ImageView stencil_view; VkImage image_handle = VK_NULL_HANDLE; VkImageView render_target = VK_NULL_HANDLE; VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; GPUVAddr gpu_addr = 0; u32 buffer_size = 0; }; class ImageAlloc : public VideoCommon::ImageAllocBase {}; class Sampler { public: explicit Sampler(TextureCacheRuntime&, const Tegra::Texture::TSCEntry&); [[nodiscard]] VkSampler Handle() const noexcept { return *sampler; } private: vk::Sampler sampler; }; class Framebuffer { public: explicit Framebuffer(TextureCacheRuntime&, std::span color_buffers, ImageView* depth_buffer, const VideoCommon::RenderTargets& key); [[nodiscard]] VkFramebuffer Handle() const noexcept { return *framebuffer; } [[nodiscard]] VkRenderPass RenderPass() const noexcept { return renderpass; } [[nodiscard]] VkExtent2D RenderArea() const noexcept { return render_area; } [[nodiscard]] VkSampleCountFlagBits Samples() const noexcept { return samples; } [[nodiscard]] u32 NumColorBuffers() const noexcept { return num_color_buffers; } [[nodiscard]] u32 NumImages() const noexcept { return num_images; } [[nodiscard]] const std::array& Images() const noexcept { return images; } [[nodiscard]] const std::array& ImageRanges() const noexcept { return image_ranges; } [[nodiscard]] bool HasAspectColorBit(size_t index) const noexcept { return (image_ranges.at(index).aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0; } [[nodiscard]] bool HasAspectDepthBit() const noexcept { return has_depth; } [[nodiscard]] bool HasAspectStencilBit() const noexcept { return has_stencil; } private: vk::Framebuffer framebuffer; VkRenderPass renderpass{}; VkExtent2D render_area{}; VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; u32 num_color_buffers = 0; u32 num_images = 0; std::array images{}; std::array image_ranges{}; bool has_depth{}; bool has_stencil{}; }; struct TextureCacheParams { static constexpr bool ENABLE_VALIDATION = true; static constexpr bool FRAMEBUFFER_BLITS = false; static constexpr bool HAS_EMULATED_COPIES = false; static constexpr bool HAS_DEVICE_MEMORY_INFO = true; using Runtime = Vulkan::TextureCacheRuntime; using Image = Vulkan::Image; using ImageAlloc = Vulkan::ImageAlloc; using ImageView = Vulkan::ImageView; using Sampler = Vulkan::Sampler; using Framebuffer = Vulkan::Framebuffer; }; using TextureCache = VideoCommon::TextureCache; } // namespace Vulkan