// Copyright 2018 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once #include #include #include #include #include #include #include #include #include #include "Common/CommonTypes.h" #include "Common/IOFile.h" #include "Common/LinearDiskCache.h" #include "VideoCommon/AbstractPipeline.h" #include "VideoCommon/AbstractShader.h" #include "VideoCommon/AsyncShaderCompiler.h" #include "VideoCommon/GXPipelineTypes.h" #include "VideoCommon/GeometryShaderGen.h" #include "VideoCommon/PixelShaderGen.h" #include "VideoCommon/RenderState.h" #include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/TextureConversionShader.h" #include "VideoCommon/TextureConverterShaderGen.h" #include "VideoCommon/UberShaderPixel.h" #include "VideoCommon/UberShaderVertex.h" #include "VideoCommon/VertexShaderGen.h" #include "VideoCommon/VideoEvents.h" class NativeVertexFormat; enum class AbstractTextureFormat : u32; enum class APIType; enum class TextureFormat; enum class TLUTFormat; namespace VideoCommon { class ShaderCache final { public: ShaderCache(); ~ShaderCache(); // Perform at startup, create descriptor layouts, compiles all static shaders. bool Initialize(); void Shutdown(); // Compiles/loads cached shaders. void InitializeShaderCache(); // Changes the shader host config. Shaders should be reloaded afterwards. void SetHostConfig(const ShaderHostConfig& host_config) { m_host_config.bits = host_config.bits; } // Reloads/recreates all shaders and pipelines. void Reload(); // Retrieves all pending shaders/pipelines from the async compiler. void RetrieveAsyncShaders(); // Accesses ShaderGen shader caches const AbstractPipeline* GetPipelineForUid(const GXPipelineUid& uid); const AbstractPipeline* GetUberPipelineForUid(const GXUberPipelineUid& uid); // Accesses ShaderGen shader caches asynchronously. // The optional will be empty if this pipeline is now background compiling. std::optional GetPipelineForUidAsync(const GXPipelineUid& uid); // Shared shaders const AbstractShader* GetScreenQuadVertexShader() const { return m_screen_quad_vertex_shader.get(); } const AbstractShader* GetTextureCopyVertexShader() const { return m_texture_copy_vertex_shader.get(); } const AbstractShader* GetEFBCopyVertexShader() const { return m_efb_copy_vertex_shader.get(); } const AbstractShader* GetTexcoordGeometryShader() const { return m_texcoord_geometry_shader.get(); } const AbstractShader* GetTextureCopyPixelShader() const { return m_texture_copy_pixel_shader.get(); } const AbstractShader* GetColorGeometryShader() const { return m_color_geometry_shader.get(); } const AbstractShader* GetColorPixelShader() const { return m_color_pixel_shader.get(); } // EFB copy to RAM/VRAM pipelines const AbstractPipeline* GetEFBCopyToVRAMPipeline(const TextureConversionShaderGen::TCShaderUid& uid); const AbstractPipeline* GetEFBCopyToRAMPipeline(const EFBCopyParams& uid); // RGBA8 framebuffer copy pipelines const AbstractPipeline* GetRGBA8CopyPipeline() const { return m_copy_rgba8_pipeline.get(); } const AbstractPipeline* GetRGBA8StereoCopyPipeline() const { return m_rgba8_stereo_copy_pipeline.get(); } // Palette texture conversion pipelines const AbstractPipeline* GetPaletteConversionPipeline(TLUTFormat format); // Texture reinterpret pipelines const AbstractPipeline* GetTextureReinterpretPipeline(TextureFormat from_format, TextureFormat to_format); // Texture decoding compute shaders const AbstractShader* GetTextureDecodingShader(TextureFormat format, std::optional palette_format); private: static constexpr size_t NUM_PALETTE_CONVERSION_SHADERS = 3; void WaitForAsyncCompiler(); void LoadCaches(); void ClearCaches(); void LoadPipelineUIDCache(); void ClosePipelineUIDCache(); void CompileMissingPipelines(); void QueueUberShaderPipelines(); bool CompileSharedPipelines(); // GX shader compiler methods std::unique_ptr CompileVertexShader(const VertexShaderUid& uid) const; std::unique_ptr CompileVertexUberShader(const UberShader::VertexShaderUid& uid) const; std::unique_ptr CompilePixelShader(const PixelShaderUid& uid) const; std::unique_ptr CompilePixelUberShader(const UberShader::PixelShaderUid& uid) const; const AbstractShader* InsertVertexShader(const VertexShaderUid& uid, std::unique_ptr shader); const AbstractShader* InsertVertexUberShader(const UberShader::VertexShaderUid& uid, std::unique_ptr shader); const AbstractShader* InsertPixelShader(const PixelShaderUid& uid, std::unique_ptr shader); const AbstractShader* InsertPixelUberShader(const UberShader::PixelShaderUid& uid, std::unique_ptr shader); const AbstractShader* CreateGeometryShader(const GeometryShaderUid& uid); bool NeedsGeometryShader(const GeometryShaderUid& uid) const; // Should we use geometry shaders for EFB copies? bool UseGeometryShaderForEFBCopies() const; // GX pipeline compiler methods AbstractPipelineConfig GetGXPipelineConfig(const NativeVertexFormat* vertex_format, const AbstractShader* vertex_shader, const AbstractShader* geometry_shader, const AbstractShader* pixel_shader, const RasterizationState& rasterization_state, const DepthState& depth_state, const BlendingState& blending_state, AbstractPipelineUsage usage); std::optional GetGXPipelineConfig(const GXPipelineUid& uid); std::optional GetGXPipelineConfig(const GXUberPipelineUid& uid); const AbstractPipeline* InsertGXPipeline(const GXPipelineUid& config, std::unique_ptr pipeline); const AbstractPipeline* InsertGXUberPipeline(const GXUberPipelineUid& config, std::unique_ptr pipeline); void AddSerializedGXPipelineUID(const SerializedGXPipelineUid& uid); void AppendGXPipelineUID(const GXPipelineUid& config); // ASync Compiler Methods void QueueVertexShaderCompile(const VertexShaderUid& uid, u32 priority); void QueueVertexUberShaderCompile(const UberShader::VertexShaderUid& uid, u32 priority); void QueuePixelShaderCompile(const PixelShaderUid& uid, u32 priority); void QueuePixelUberShaderCompile(const UberShader::PixelShaderUid& uid, u32 priority); void QueuePipelineCompile(const GXPipelineUid& uid, u32 priority); void QueueUberPipelineCompile(const GXUberPipelineUid& uid, u32 priority); // Populating various caches. template void LoadShaderCache(T& cache, APIType api_type, const char* type, bool include_gameid); template void ClearShaderCache(T& cache); template void LoadPipelineCache(T& cache, LinearDiskCache& disk_cache, APIType api_type, const char* type, bool include_gameid); template void ClearPipelineCache(T& cache, Y& disk_cache); // Priorities for compiling. The lower the value, the sooner the pipeline is compiled. // The shader cache is compiled last, as it is the least likely to be required. On demand // shaders are always compiled before pending ubershaders, as we want to use the ubershader // for as few frames as possible, otherwise we risk framerate drops. enum : u32 { COMPILE_PRIORITY_ONDEMAND_PIPELINE = 100, COMPILE_PRIORITY_UBERSHADER_PIPELINE = 200, COMPILE_PRIORITY_SHADERCACHE_PIPELINE = 300 }; // Configuration bits. APIType m_api_type; ShaderHostConfig m_host_config = {}; std::unique_ptr m_async_shader_compiler; // Shared shaders std::unique_ptr m_screen_quad_vertex_shader; std::unique_ptr m_texture_copy_vertex_shader; std::unique_ptr m_efb_copy_vertex_shader; std::unique_ptr m_texcoord_geometry_shader; std::unique_ptr m_color_geometry_shader; std::unique_ptr m_texture_copy_pixel_shader; std::unique_ptr m_color_pixel_shader; // GX Shader Caches template struct ShaderModuleCache { struct Shader { std::unique_ptr shader; bool pending = false; }; std::map shader_map; LinearDiskCache disk_cache; }; ShaderModuleCache m_vs_cache; ShaderModuleCache m_gs_cache; ShaderModuleCache m_ps_cache; ShaderModuleCache m_uber_vs_cache; ShaderModuleCache m_uber_ps_cache; // GX Pipeline Caches - .first - pipeline, .second - pending std::map, bool>> m_gx_pipeline_cache; std::map, bool>> m_gx_uber_pipeline_cache; File::IOFile m_gx_pipeline_uid_cache_file; LinearDiskCache m_gx_pipeline_disk_cache; LinearDiskCache m_gx_uber_pipeline_disk_cache; // EFB copy to VRAM/RAM pipelines std::map> m_efb_copy_to_vram_pipelines; std::map> m_efb_copy_to_ram_pipelines; // Copy pipeline for RGBA8 textures std::unique_ptr m_copy_rgba8_pipeline; std::unique_ptr m_rgba8_stereo_copy_pipeline; // Palette conversion pipelines std::array, NUM_PALETTE_CONVERSION_SHADERS> m_palette_conversion_pipelines; // Texture reinterpreting pipeline std::map, std::unique_ptr> m_texture_reinterpret_pipelines; // Texture decoding shaders std::map, std::unique_ptr> m_texture_decoding_shaders; Common::EventHook m_frame_end_handler; }; } // namespace VideoCommon extern std::unique_ptr g_shader_cache;