// Copyright 2023 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include #include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" #include "video_core/shader/generator/pica_fs_config.h" #include "video_core/shader/generator/profile.h" #include "video_core/shader/generator/shader_gen.h" namespace Pica { struct RegsInternal; struct ShaderSetup; } // namespace Pica namespace Vulkan { class Instance; class Scheduler; class RenderpassCache; class DescriptorPool; constexpr u32 NUM_RASTERIZER_SETS = 3; constexpr u32 NUM_DYNAMIC_OFFSETS = 3; /** * Stores a collection of rasterizer pipelines used during rendering. */ class PipelineCache { public: explicit PipelineCache(const Instance& instance, Scheduler& scheduler, RenderpassCache& renderpass_cache, DescriptorPool& pool); ~PipelineCache(); [[nodiscard]] DescriptorSetProvider& TextureProvider() noexcept { return descriptor_set_providers[1]; } /// Loads the pipeline cache stored to disk void LoadDiskCache(); /// Stores the generated pipeline cache to disk void SaveDiskCache(); /// Binds a pipeline using the provided information bool BindPipeline(const PipelineInfo& info, bool wait_built = false); /// Binds a PICA decompiled vertex shader bool UseProgrammableVertexShader(const Pica::RegsInternal& regs, Pica::ShaderSetup& setup, const VertexLayout& layout); /// Binds a passthrough vertex shader void UseTrivialVertexShader(); /// Binds a PICA decompiled geometry shader bool UseFixedGeometryShader(const Pica::RegsInternal& regs); /// Binds a passthrough geometry shader void UseTrivialGeometryShader(); /// Binds a fragment shader generated from PICA state void UseFragmentShader(const Pica::RegsInternal& regs, const Pica::Shader::UserConfig& user); /// Binds a texture to the specified binding void BindTexture(u32 binding, vk::ImageView image_view, vk::Sampler sampler); /// Binds a storage image to the specified binding void BindStorageImage(u32 binding, vk::ImageView image_view); /// Binds a buffer to the specified binding void BindBuffer(u32 binding, vk::Buffer buffer, u32 offset, u32 size); /// Binds a buffer to the specified binding void BindTexelBuffer(u32 binding, vk::BufferView buffer_view); /// Sets the dynamic offset for the uniform buffer at binding void SetBufferOffset(u32 binding, size_t offset); private: /// Builds the rasterizer pipeline layout void BuildLayout(); /// Returns true when the disk data can be used by the current driver bool IsCacheValid(std::span cache_data) const; /// Create shader disk cache directories. Returns true on success. bool EnsureDirectories() const; /// Returns the pipeline cache storage dir std::string GetPipelineCacheDir() const; private: const Instance& instance; Scheduler& scheduler; RenderpassCache& renderpass_cache; DescriptorPool& pool; Pica::Shader::Profile profile{}; vk::UniquePipelineCache pipeline_cache; vk::UniquePipelineLayout pipeline_layout; std::size_t num_worker_threads; Common::ThreadWorker workers; PipelineInfo current_info{}; GraphicsPipeline* current_pipeline{}; tsl::robin_map, Common::IdentityHash> graphics_pipelines; std::array descriptor_set_providers; std::array update_data{}; std::array bound_descriptor_sets{}; std::array offsets{}; std::bitset set_dirty{}; std::array shader_hashes; std::array current_shaders; std::unordered_map programmable_vertex_map; std::unordered_map programmable_vertex_cache; std::unordered_map fixed_geometry_shaders; std::unordered_map fragment_shaders; Shader trivial_vertex_shader; }; } // namespace Vulkan