mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
Vulkan: Reload pipeline cache when relevant host config changes
This commit is contained in:
@ -446,10 +446,14 @@ void ObjectCache::ClearPipelineCache()
|
|||||||
m_compute_pipeline_objects.clear();
|
m_compute_pipeline_objects.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ObjectCache::GetDiskCacheFileName(const char* type)
|
std::string ObjectCache::GetDiskCacheFileName(const char* type, bool include_gameid,
|
||||||
|
bool include_host_config)
|
||||||
{
|
{
|
||||||
return StringFromFormat("%svulkan-%s-%s.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(),
|
return StringFromFormat(
|
||||||
SConfig::GetInstance().GetGameID().c_str(), type);
|
"%svulkan-%s%s%s%s%s.cache", File::GetUserPath(D_SHADERCACHE_IDX).c_str(), type,
|
||||||
|
include_gameid ? "-" : "", include_gameid ? SConfig::GetInstance().GetGameID().c_str() : "",
|
||||||
|
include_host_config ? "-" : "",
|
||||||
|
include_host_config ? g_ActiveConfig.GetHostConfigFilename().c_str() : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
class PipelineCacheReadCallback : public LinearDiskCacheReader<u32, u8>
|
class PipelineCacheReadCallback : public LinearDiskCacheReader<u32, u8>
|
||||||
@ -475,7 +479,10 @@ public:
|
|||||||
|
|
||||||
bool ObjectCache::CreatePipelineCache()
|
bool ObjectCache::CreatePipelineCache()
|
||||||
{
|
{
|
||||||
m_pipeline_cache_filename = GetDiskCacheFileName("pipeline");
|
// Vulkan pipeline caches can be shared between games for shader compile time reduction.
|
||||||
|
// This assumes that drivers don't create all pipelines in the cache on load time, only
|
||||||
|
// when a lookup occurs that matches a pipeline (or pipeline data) in the cache.
|
||||||
|
m_pipeline_cache_filename = GetDiskCacheFileName("pipeline", false, true);
|
||||||
|
|
||||||
VkPipelineCacheCreateInfo info = {
|
VkPipelineCacheCreateInfo info = {
|
||||||
VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType
|
VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType
|
||||||
@ -498,7 +505,7 @@ bool ObjectCache::LoadPipelineCache()
|
|||||||
{
|
{
|
||||||
// We have to keep the pipeline cache file name around since when we save it
|
// We have to keep the pipeline cache file name around since when we save it
|
||||||
// we delete the old one, by which time the game's unique ID is already cleared.
|
// we delete the old one, by which time the game's unique ID is already cleared.
|
||||||
m_pipeline_cache_filename = GetDiskCacheFileName("pipeline");
|
m_pipeline_cache_filename = GetDiskCacheFileName("pipeline", false, true);
|
||||||
|
|
||||||
std::vector<u8> disk_data;
|
std::vector<u8> disk_data;
|
||||||
LinearDiskCache<u32, u8> disk_cache;
|
LinearDiskCache<u32, u8> disk_cache;
|
||||||
@ -664,15 +671,15 @@ struct ShaderCacheReader : public LinearDiskCacheReader<Uid, u32>
|
|||||||
void ObjectCache::LoadShaderCaches()
|
void ObjectCache::LoadShaderCaches()
|
||||||
{
|
{
|
||||||
ShaderCacheReader<VertexShaderUid> vs_reader(m_vs_cache.shader_map);
|
ShaderCacheReader<VertexShaderUid> vs_reader(m_vs_cache.shader_map);
|
||||||
m_vs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("vs"), vs_reader);
|
m_vs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("vs", true, true), vs_reader);
|
||||||
|
|
||||||
ShaderCacheReader<PixelShaderUid> ps_reader(m_ps_cache.shader_map);
|
ShaderCacheReader<PixelShaderUid> ps_reader(m_ps_cache.shader_map);
|
||||||
m_ps_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("ps"), ps_reader);
|
m_ps_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("ps", true, true), ps_reader);
|
||||||
|
|
||||||
if (g_vulkan_context->SupportsGeometryShaders())
|
if (g_vulkan_context->SupportsGeometryShaders())
|
||||||
{
|
{
|
||||||
ShaderCacheReader<GeometryShaderUid> gs_reader(m_gs_cache.shader_map);
|
ShaderCacheReader<GeometryShaderUid> gs_reader(m_gs_cache.shader_map);
|
||||||
m_gs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("gs"), gs_reader);
|
m_gs_cache.disk_cache.OpenAndRead(GetDiskCacheFileName("gs", true, true), gs_reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
SETSTAT(stats.numPixelShadersCreated, static_cast<int>(m_ps_cache.shader_map.size()));
|
SETSTAT(stats.numPixelShadersCreated, static_cast<int>(m_ps_cache.shader_map.size()));
|
||||||
@ -684,6 +691,7 @@ void ObjectCache::LoadShaderCaches()
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
static void DestroyShaderCache(T& cache)
|
static void DestroyShaderCache(T& cache)
|
||||||
{
|
{
|
||||||
|
cache.disk_cache.Sync();
|
||||||
cache.disk_cache.Close();
|
cache.disk_cache.Close();
|
||||||
for (const auto& it : cache.shader_map)
|
for (const auto& it : cache.shader_map)
|
||||||
{
|
{
|
||||||
@ -825,6 +833,23 @@ void ObjectCache::RecompileSharedShaders()
|
|||||||
PanicAlert("Failed to recompile shared shaders.");
|
PanicAlert("Failed to recompile shared shaders.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectCache::ReloadShaderAndPipelineCaches()
|
||||||
|
{
|
||||||
|
SavePipelineCache();
|
||||||
|
DestroyShaderCaches();
|
||||||
|
DestroyPipelineCache();
|
||||||
|
|
||||||
|
if (g_ActiveConfig.bShaderCache)
|
||||||
|
{
|
||||||
|
LoadShaderCaches();
|
||||||
|
LoadPipelineCache();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CreatePipelineCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool ObjectCache::CreateDescriptorSetLayouts()
|
bool ObjectCache::CreateDescriptorSetLayouts()
|
||||||
{
|
{
|
||||||
static const VkDescriptorSetLayoutBinding ubo_set_bindings[] = {
|
static const VkDescriptorSetLayoutBinding ubo_set_bindings[] = {
|
||||||
|
@ -154,13 +154,16 @@ public:
|
|||||||
// Recompile shared shaders, call when stereo mode changes.
|
// Recompile shared shaders, call when stereo mode changes.
|
||||||
void RecompileSharedShaders();
|
void RecompileSharedShaders();
|
||||||
|
|
||||||
|
// Reload pipeline cache. This will destroy all pipelines.
|
||||||
|
void ReloadShaderAndPipelineCaches();
|
||||||
|
|
||||||
// Shared shader accessors
|
// Shared shader accessors
|
||||||
VkShaderModule GetScreenQuadVertexShader() const { return m_screen_quad_vertex_shader; }
|
VkShaderModule GetScreenQuadVertexShader() const { return m_screen_quad_vertex_shader; }
|
||||||
VkShaderModule GetPassthroughVertexShader() const { return m_passthrough_vertex_shader; }
|
VkShaderModule GetPassthroughVertexShader() const { return m_passthrough_vertex_shader; }
|
||||||
VkShaderModule GetScreenQuadGeometryShader() const { return m_screen_quad_geometry_shader; }
|
VkShaderModule GetScreenQuadGeometryShader() const { return m_screen_quad_geometry_shader; }
|
||||||
VkShaderModule GetPassthroughGeometryShader() const { return m_passthrough_geometry_shader; }
|
VkShaderModule GetPassthroughGeometryShader() const { return m_passthrough_geometry_shader; }
|
||||||
// Gets the filename of the specified type of cache object (e.g. vertex shader, pipeline).
|
// Gets the filename of the specified type of cache object (e.g. vertex shader, pipeline).
|
||||||
std::string GetDiskCacheFileName(const char* type);
|
std::string GetDiskCacheFileName(const char* type, bool include_gameid, bool include_host_config);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool CreatePipelineCache();
|
bool CreatePipelineCache();
|
||||||
|
@ -114,7 +114,7 @@ bool Renderer::Initialize()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure all pipelines previously used by the game have been created.
|
// Ensure all pipelines previously used by the game have been created.
|
||||||
StateTracker::GetInstance()->LoadPipelineUIDCache();
|
StateTracker::GetInstance()->ReloadPipelineUIDCache();
|
||||||
|
|
||||||
// Initialize post processing.
|
// Initialize post processing.
|
||||||
m_post_processor = std::make_unique<VulkanPostProcessing>();
|
m_post_processor = std::make_unique<VulkanPostProcessing>();
|
||||||
@ -1126,13 +1126,11 @@ void Renderer::CheckForSurfaceChange()
|
|||||||
void Renderer::CheckForConfigChanges()
|
void Renderer::CheckForConfigChanges()
|
||||||
{
|
{
|
||||||
// Save the video config so we can compare against to determine which settings have changed.
|
// Save the video config so we can compare against to determine which settings have changed.
|
||||||
u32 old_multisamples = g_ActiveConfig.iMultisamples;
|
u32 old_host_bits = g_ActiveConfig.GetHostConfigBits();
|
||||||
int old_anisotropy = g_ActiveConfig.iMaxAnisotropy;
|
int old_anisotropy = g_ActiveConfig.iMaxAnisotropy;
|
||||||
int old_stereo_mode = g_ActiveConfig.iStereoMode;
|
|
||||||
int old_aspect_ratio = g_ActiveConfig.iAspectRatio;
|
int old_aspect_ratio = g_ActiveConfig.iAspectRatio;
|
||||||
int old_efb_scale = g_ActiveConfig.iEFBScale;
|
int old_efb_scale = g_ActiveConfig.iEFBScale;
|
||||||
bool old_force_filtering = g_ActiveConfig.bForceFiltering;
|
bool old_force_filtering = g_ActiveConfig.bForceFiltering;
|
||||||
bool old_ssaa = g_ActiveConfig.bSSAA;
|
|
||||||
bool old_use_xfb = g_ActiveConfig.bUseXFB;
|
bool old_use_xfb = g_ActiveConfig.bUseXFB;
|
||||||
bool old_use_realxfb = g_ActiveConfig.bUseRealXFB;
|
bool old_use_realxfb = g_ActiveConfig.bUseRealXFB;
|
||||||
|
|
||||||
@ -1142,11 +1140,9 @@ void Renderer::CheckForConfigChanges()
|
|||||||
UpdateActiveConfig();
|
UpdateActiveConfig();
|
||||||
|
|
||||||
// Determine which (if any) settings have changed.
|
// Determine which (if any) settings have changed.
|
||||||
bool msaa_changed = old_multisamples != g_ActiveConfig.iMultisamples;
|
bool host_bits_changed = old_host_bits != g_ActiveConfig.GetHostConfigBits();
|
||||||
bool ssaa_changed = old_ssaa != g_ActiveConfig.bSSAA;
|
|
||||||
bool anisotropy_changed = old_anisotropy != g_ActiveConfig.iMaxAnisotropy;
|
bool anisotropy_changed = old_anisotropy != g_ActiveConfig.iMaxAnisotropy;
|
||||||
bool force_texture_filtering_changed = old_force_filtering != g_ActiveConfig.bForceFiltering;
|
bool force_texture_filtering_changed = old_force_filtering != g_ActiveConfig.bForceFiltering;
|
||||||
bool stereo_changed = old_stereo_mode != g_ActiveConfig.iStereoMode;
|
|
||||||
bool efb_scale_changed = old_efb_scale != g_ActiveConfig.iEFBScale;
|
bool efb_scale_changed = old_efb_scale != g_ActiveConfig.iEFBScale;
|
||||||
bool aspect_changed = old_aspect_ratio != g_ActiveConfig.iAspectRatio;
|
bool aspect_changed = old_aspect_ratio != g_ActiveConfig.iAspectRatio;
|
||||||
bool use_xfb_changed = old_use_xfb != g_ActiveConfig.bUseXFB;
|
bool use_xfb_changed = old_use_xfb != g_ActiveConfig.bUseXFB;
|
||||||
@ -1164,23 +1160,21 @@ void Renderer::CheckForConfigChanges()
|
|||||||
|
|
||||||
// MSAA samples changed, we need to recreate the EFB render pass.
|
// MSAA samples changed, we need to recreate the EFB render pass.
|
||||||
// If the stereoscopy mode changed, we need to recreate the buffers as well.
|
// If the stereoscopy mode changed, we need to recreate the buffers as well.
|
||||||
if (msaa_changed || stereo_changed)
|
// SSAA changed on/off, we have to recompile shaders.
|
||||||
|
// Changing stereoscopy from off<->on also requires shaders to be recompiled.
|
||||||
|
if (host_bits_changed)
|
||||||
{
|
{
|
||||||
|
OSD::AddMessage("Video config changed, reloading shaders.", OSD::Duration::NORMAL);
|
||||||
g_command_buffer_mgr->WaitForGPUIdle();
|
g_command_buffer_mgr->WaitForGPUIdle();
|
||||||
FramebufferManager::GetInstance()->RecreateRenderPass();
|
FramebufferManager::GetInstance()->RecreateRenderPass();
|
||||||
FramebufferManager::GetInstance()->ResizeEFBTextures();
|
FramebufferManager::GetInstance()->ResizeEFBTextures();
|
||||||
BindEFBToStateTracker();
|
BindEFBToStateTracker();
|
||||||
}
|
|
||||||
|
|
||||||
// SSAA changed on/off, we can leave the buffers/render pass, but have to recompile shaders.
|
|
||||||
// Changing stereoscopy from off<->on also requires shaders to be recompiled.
|
|
||||||
if (msaa_changed || ssaa_changed || stereo_changed)
|
|
||||||
{
|
|
||||||
g_command_buffer_mgr->WaitForGPUIdle();
|
|
||||||
RecompileShaders();
|
RecompileShaders();
|
||||||
FramebufferManager::GetInstance()->RecompileShaders();
|
FramebufferManager::GetInstance()->RecompileShaders();
|
||||||
|
g_object_cache->ReloadShaderAndPipelineCaches();
|
||||||
g_object_cache->RecompileSharedShaders();
|
g_object_cache->RecompileSharedShaders();
|
||||||
StateTracker::GetInstance()->LoadPipelineUIDCache();
|
StateTracker::GetInstance()->InvalidateShaderPointers();
|
||||||
|
StateTracker::GetInstance()->ReloadPipelineUIDCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
// For vsync, we need to change the present mode, which means recreating the swap chain.
|
// For vsync, we need to change the present mode, which means recreating the swap chain.
|
||||||
|
@ -115,7 +115,20 @@ bool StateTracker::Initialize()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateTracker::LoadPipelineUIDCache()
|
void StateTracker::InvalidateShaderPointers()
|
||||||
|
{
|
||||||
|
// Clear UIDs, forcing a false match next time.
|
||||||
|
m_vs_uid = {};
|
||||||
|
m_gs_uid = {};
|
||||||
|
m_ps_uid = {};
|
||||||
|
|
||||||
|
// Invalidate shader pointers.
|
||||||
|
m_pipeline_state.vs = VK_NULL_HANDLE;
|
||||||
|
m_pipeline_state.gs = VK_NULL_HANDLE;
|
||||||
|
m_pipeline_state.ps = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StateTracker::ReloadPipelineUIDCache()
|
||||||
{
|
{
|
||||||
class PipelineInserter final : public LinearDiskCacheReader<SerializedPipelineUID, u32>
|
class PipelineInserter final : public LinearDiskCacheReader<SerializedPipelineUID, u32>
|
||||||
{
|
{
|
||||||
@ -130,7 +143,8 @@ void StateTracker::LoadPipelineUIDCache()
|
|||||||
StateTracker* this_ptr;
|
StateTracker* this_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string filename = g_object_cache->GetDiskCacheFileName("pipeline-uid");
|
// UID caches don't contain any host state, so use a single uid cache per gameid.
|
||||||
|
std::string filename = g_object_cache->GetDiskCacheFileName("pipeline-uid", true, false);
|
||||||
PipelineInserter inserter(this);
|
PipelineInserter inserter(this);
|
||||||
|
|
||||||
// OpenAndRead calls Close() first, which will flush all data to disk when reloading.
|
// OpenAndRead calls Close() first, which will flush all data to disk when reloading.
|
||||||
|
@ -117,7 +117,10 @@ public:
|
|||||||
bool IsWithinRenderArea(s32 x, s32 y, u32 width, u32 height) const;
|
bool IsWithinRenderArea(s32 x, s32 y, u32 width, u32 height) const;
|
||||||
|
|
||||||
// Reloads the UID cache, ensuring all pipelines used by the game so far have been created.
|
// Reloads the UID cache, ensuring all pipelines used by the game so far have been created.
|
||||||
void LoadPipelineUIDCache();
|
void ReloadPipelineUIDCache();
|
||||||
|
|
||||||
|
// Clears shader pointers, ensuring that now-deleted modules are not used.
|
||||||
|
void InvalidateShaderPointers();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Serialized version of PipelineInfo, used when loading/saving the pipeline UID cache.
|
// Serialized version of PipelineInfo, used when loading/saving the pipeline UID cache.
|
||||||
|
Reference in New Issue
Block a user