summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/ShaderCache.h
diff options
context:
space:
mode:
authorStenzek <stenzek@gmail.com>2018-02-25 01:15:35 +1000
committerStenzek <stenzek@gmail.com>2018-03-10 15:56:30 +1000
commitdec0c3bce85ceda89ea05f00b94aad00e675598d (patch)
tree8c967a47d8a531ae3f0245e419d7ec652535ee3a /Source/Core/VideoCommon/ShaderCache.h
parent24df896eb8d1520706b086039743ef2dca7ce6df (diff)
Move shader caches to VideoCommon
Diffstat (limited to 'Source/Core/VideoCommon/ShaderCache.h')
-rw-r--r--Source/Core/VideoCommon/ShaderCache.h216
1 files changed, 216 insertions, 0 deletions
diff --git a/Source/Core/VideoCommon/ShaderCache.h b/Source/Core/VideoCommon/ShaderCache.h
new file mode 100644
index 0000000000..922cd4d5fa
--- /dev/null
+++ b/Source/Core/VideoCommon/ShaderCache.h
@@ -0,0 +1,216 @@
+// Copyright 2018 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <cstddef>
+#include <map>
+#include <memory>
+#include <optional>
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+#include "Common/CommonTypes.h"
+#include "Common/LinearDiskCache.h"
+
+#include "VideoCommon/AbstractPipeline.h"
+#include "VideoCommon/AbstractShader.h"
+#include "VideoCommon/NativeVertexFormat.h"
+
+#include "VideoCommon/AsyncShaderCompiler.h"
+#include "VideoCommon/GeometryShaderGen.h"
+#include "VideoCommon/PixelShaderGen.h"
+#include "VideoCommon/RenderState.h"
+#include "VideoCommon/UberShaderPixel.h"
+#include "VideoCommon/UberShaderVertex.h"
+#include "VideoCommon/VertexShaderGen.h"
+
+class NativeVertexFormat;
+
+namespace VideoCommon
+{
+struct GXPipelineConfig
+{
+ const NativeVertexFormat* vertex_format;
+ VertexShaderUid vs_uid;
+ GeometryShaderUid gs_uid;
+ PixelShaderUid ps_uid;
+ RasterizationState rasterization_state;
+ DepthState depth_state;
+ BlendingState blending_state;
+
+ bool operator<(const GXPipelineConfig& rhs) const
+ {
+ return std::tie(vertex_format, vs_uid, gs_uid, ps_uid, rasterization_state.hex, depth_state.hex,
+ blending_state.hex) < std::tie(rhs.vertex_format, rhs.vs_uid, rhs.gs_uid,
+ rhs.ps_uid, rhs.rasterization_state.hex,
+ rhs.depth_state.hex, rhs.blending_state.hex);
+ }
+ bool operator==(const GXPipelineConfig& rhs) const
+ {
+ return std::tie(vertex_format, vs_uid, gs_uid, ps_uid, rasterization_state.hex, depth_state.hex,
+ blending_state.hex) == std::tie(rhs.vertex_format, rhs.vs_uid, rhs.gs_uid,
+ rhs.ps_uid, rhs.rasterization_state.hex,
+ rhs.depth_state.hex, rhs.blending_state.hex);
+ }
+ bool operator!=(const GXPipelineConfig& rhs) const { return !operator==(rhs); }
+};
+struct GXUberPipelineConfig
+{
+ const NativeVertexFormat* vertex_format;
+ UberShader::VertexShaderUid vs_uid;
+ GeometryShaderUid gs_uid;
+ UberShader::PixelShaderUid ps_uid;
+ RasterizationState rasterization_state;
+ DepthState depth_state;
+ BlendingState blending_state;
+
+ bool operator<(const GXUberPipelineConfig& rhs) const
+ {
+ return std::tie(vertex_format, vs_uid, gs_uid, ps_uid, rasterization_state.hex, depth_state.hex,
+ blending_state.hex) < std::tie(rhs.vertex_format, rhs.vs_uid, rhs.gs_uid,
+ rhs.ps_uid, rhs.rasterization_state.hex,
+ rhs.depth_state.hex, rhs.blending_state.hex);
+ }
+ bool operator==(const GXUberPipelineConfig& rhs) const
+ {
+ return std::tie(vertex_format, vs_uid, gs_uid, ps_uid, rasterization_state.hex, depth_state.hex,
+ blending_state.hex) == std::tie(rhs.vertex_format, rhs.vs_uid, rhs.gs_uid,
+ rhs.ps_uid, rhs.rasterization_state.hex,
+ rhs.depth_state.hex, rhs.blending_state.hex);
+ }
+ bool operator!=(const GXUberPipelineConfig& rhs) const { return !operator==(rhs); }
+};
+
+class ShaderCache final
+{
+public:
+ ShaderCache();
+ ~ShaderCache();
+
+ // Perform at startup, create descriptor layouts, compiles all static shaders.
+ bool Initialize();
+ void Shutdown();
+
+ // Changes the shader host config. Shaders will be reloaded if there are changes.
+ void SetHostConfig(const ShaderHostConfig& host_config, u32 efb_multisamples);
+
+ // Reloads/recreates all shaders and pipelines.
+ void Reload();
+
+ // Retrieves all pending shaders/pipelines from the async compiler.
+ void RetrieveAsyncShaders();
+
+ // Get utility shader header based on current config.
+ std::string GetUtilityShaderHeader() const;
+
+ // Accesses ShaderGen shader caches
+ const AbstractPipeline* GetPipelineForUid(const GXPipelineConfig& uid);
+ const AbstractPipeline* GetUberPipelineForUid(const GXUberPipelineConfig& uid);
+
+ // Accesses ShaderGen shader caches asynchronously.
+ // The optional will be empty if this pipeline is now background compiling.
+ std::optional<const AbstractPipeline*> GetPipelineForUidAsync(const GXPipelineConfig& uid);
+
+private:
+ void WaitForAsyncCompiler(const std::string& msg);
+ void LoadShaderCaches();
+ void ClearShaderCaches();
+ void LoadPipelineUIDCache();
+ void CompileMissingPipelines();
+ void InvalidateCachedPipelines();
+ void ClearPipelineCaches();
+ void PrecompileUberShaders();
+
+ // GX shader compiler methods
+ std::unique_ptr<AbstractShader> CompileVertexShader(const VertexShaderUid& uid) const;
+ std::unique_ptr<AbstractShader>
+ CompileVertexUberShader(const UberShader::VertexShaderUid& uid) const;
+ std::unique_ptr<AbstractShader> CompilePixelShader(const PixelShaderUid& uid) const;
+ std::unique_ptr<AbstractShader>
+ CompilePixelUberShader(const UberShader::PixelShaderUid& uid) const;
+ const AbstractShader* InsertVertexShader(const VertexShaderUid& uid,
+ std::unique_ptr<AbstractShader> shader);
+ const AbstractShader* InsertVertexUberShader(const UberShader::VertexShaderUid& uid,
+ std::unique_ptr<AbstractShader> shader);
+ const AbstractShader* InsertPixelShader(const PixelShaderUid& uid,
+ std::unique_ptr<AbstractShader> shader);
+ const AbstractShader* InsertPixelUberShader(const UberShader::PixelShaderUid& uid,
+ std::unique_ptr<AbstractShader> shader);
+ const AbstractShader* CreateGeometryShader(const GeometryShaderUid& uid);
+ bool NeedsGeometryShader(const GeometryShaderUid& uid) 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);
+ std::optional<AbstractPipelineConfig> GetGXPipelineConfig(const GXPipelineConfig& uid);
+ std::optional<AbstractPipelineConfig> GetGXUberPipelineConfig(const GXUberPipelineConfig& uid);
+ const AbstractPipeline* InsertGXPipeline(const GXPipelineConfig& config,
+ std::unique_ptr<AbstractPipeline> pipeline);
+ const AbstractPipeline* InsertGXUberPipeline(const GXUberPipelineConfig& config,
+ std::unique_ptr<AbstractPipeline> pipeline);
+ void AppendGXPipelineUID(const GXPipelineConfig& config);
+
+ // ASync Compiler Methods
+ void QueueVertexShaderCompile(const VertexShaderUid& uid);
+ void QueueVertexUberShaderCompile(const UberShader::VertexShaderUid& uid);
+ void QueuePixelShaderCompile(const PixelShaderUid& uid);
+ void QueuePixelUberShaderCompile(const UberShader::PixelShaderUid& uid);
+ void QueuePipelineCompile(const GXPipelineConfig& uid);
+ void QueueUberPipelineCompile(const GXUberPipelineConfig& uid);
+
+ // Configuration bits.
+ APIType m_api_type = APIType::Nothing;
+ ShaderHostConfig m_host_config = {};
+ u32 m_efb_multisamples = 1;
+ std::unique_ptr<AsyncShaderCompiler> m_async_shader_compiler;
+
+ // GX Shader Caches
+ template <typename Uid>
+ struct ShaderModuleCache
+ {
+ struct Shader
+ {
+ std::unique_ptr<AbstractShader> shader;
+ bool pending;
+ };
+ std::map<Uid, Shader> shader_map;
+ LinearDiskCache<Uid, u8> disk_cache;
+ };
+ ShaderModuleCache<VertexShaderUid> m_vs_cache;
+ ShaderModuleCache<GeometryShaderUid> m_gs_cache;
+ ShaderModuleCache<PixelShaderUid> m_ps_cache;
+ ShaderModuleCache<UberShader::VertexShaderUid> m_uber_vs_cache;
+ ShaderModuleCache<UberShader::PixelShaderUid> m_uber_ps_cache;
+
+ // GX Pipeline Caches - .first - pipeline, .second - pending
+ // TODO: Use unordered_map for speed.
+ std::map<GXPipelineConfig, std::pair<std::unique_ptr<AbstractPipeline>, bool>>
+ m_gx_pipeline_cache;
+ std::map<GXUberPipelineConfig, std::pair<std::unique_ptr<AbstractPipeline>, bool>>
+ m_gx_uber_pipeline_cache;
+
+ // Disk cache of pipeline UIDs
+ // We can't use the whole UID as a type
+ struct GXPipelineDiskCacheUid
+ {
+ PortableVertexDeclaration vertex_decl;
+ VertexShaderUid vs_uid;
+ GeometryShaderUid gs_uid;
+ PixelShaderUid ps_uid;
+ u32 rasterization_state_bits;
+ u32 depth_state_bits;
+ u32 blending_state_bits;
+ };
+ LinearDiskCache<GXPipelineDiskCacheUid, u8> m_gx_pipeline_uid_disk_cache;
+};
+
+} // namespace VideoCommon
+
+extern std::unique_ptr<VideoCommon::ShaderCache> g_shader_cache;