[dxvk] Destroy shader pipeline libraries after initial compile on 32-bit

This alone saves ~700 MiB of address space in the Resident Evil 6 main
menu on Nvidia.
This commit is contained in:
Philip Rebohle 2022-08-08 14:25:34 +02:00 committed by Philip Rebohle
parent 915b03ba7b
commit 4bc2d713fb
2 changed files with 64 additions and 22 deletions

View File

@ -915,10 +915,7 @@ namespace dxvk {
const DxvkShaderPipelineLibraryCompileArgs& args) {
std::lock_guard lock(m_mutex);
VkShaderStageFlagBits stage = VK_SHADER_STAGE_FRAGMENT_BIT;
if (m_shader)
stage = m_shader->info().stage;
VkShaderStageFlagBits stage = getShaderStage();
VkPipeline& pipeline = (stage == VK_SHADER_STAGE_VERTEX_BIT && !args.depthClipEnable)
? m_pipelineNoDepthClip
@ -927,28 +924,54 @@ namespace dxvk {
if (pipeline)
return pipeline;
bool usesDefaultArgs = (args == DxvkShaderPipelineLibraryCompileArgs());
pipeline = compileShaderPipelineLocked(args);
return pipeline;
}
void DxvkShaderPipelineLibrary::compilePipeline() {
std::lock_guard lock(m_mutex);
// Skip if a pipeline has already been compiled
if (m_pipeline)
return;
// Compile the pipeline with default args
VkPipeline pipeline = compileShaderPipelineLocked(
DxvkShaderPipelineLibraryCompileArgs());
// On 32-bit, destroy the pipeline immediately in order to
// save memory. We should hit the driver's disk cache once
// we need to recreate the pipeline.
if (m_device->mustTrackPipelineLifetime()) {
auto vk = m_device->vkd();
vk->vkDestroyPipeline(vk->device(), pipeline, nullptr);
pipeline = VK_NULL_HANDLE;
}
// Write back pipeline handle for future use
m_pipeline = pipeline;
}
VkPipeline DxvkShaderPipelineLibrary::compileShaderPipelineLocked(
const DxvkShaderPipelineLibraryCompileArgs& args) {
VkShaderStageFlagBits stage = getShaderStage();
VkPipeline pipeline = VK_NULL_HANDLE;
// Compile pipeline of the appropriate type
switch (stage) {
case VK_SHADER_STAGE_VERTEX_BIT:
pipeline = compileVertexShaderPipeline(args);
if (usesDefaultArgs)
m_stats->numGraphicsLibraries += 1;
break;
case VK_SHADER_STAGE_FRAGMENT_BIT:
pipeline = compileFragmentShaderPipeline();
if (usesDefaultArgs)
m_stats->numGraphicsLibraries += 1;
break;
case VK_SHADER_STAGE_COMPUTE_BIT:
pipeline = compileComputeShaderPipeline();
if (usesDefaultArgs)
m_stats->numComputePipelines += 1;
break;
default:
@ -956,18 +979,21 @@ namespace dxvk {
return VK_NULL_HANDLE;
}
// Increment stat counter the first time this
// shader pipeline gets compiled successfully
if (!m_compiledOnce && pipeline) {
if (stage == VK_SHADER_STAGE_COMPUTE_BIT)
m_stats->numComputePipelines += 1;
else
m_stats->numGraphicsLibraries += 1;
m_compiledOnce = true;
}
return pipeline;
}
void DxvkShaderPipelineLibrary::compilePipeline() {
// Just compile the pipeline with default args. Implicitly skips
// this step if another thread has compiled the pipeline in the
// meantime, in order to avoid duplicate work.
getPipelineHandle(DxvkShaderPipelineLibraryCompileArgs());
}
VkPipeline DxvkShaderPipelineLibrary::compileVertexShaderPipeline(
const DxvkShaderPipelineLibraryCompileArgs& args) {
auto vk = m_device->vkd();
@ -1175,4 +1201,14 @@ namespace dxvk {
vk->device(), &info, &m_identifier);
}
VkShaderStageFlagBits DxvkShaderPipelineLibrary::getShaderStage() const {
VkShaderStageFlagBits stage = VK_SHADER_STAGE_FRAGMENT_BIT;
if (m_shader != nullptr)
stage = m_shader->info().stage;
return stage;
}
}

View File

@ -425,10 +425,14 @@ namespace dxvk {
dxvk::mutex m_mutex;
VkPipeline m_pipeline = VK_NULL_HANDLE;
VkPipeline m_pipelineNoDepthClip = VK_NULL_HANDLE;
bool m_compiledOnce = false;
dxvk::mutex m_identifierMutex;
VkShaderModuleIdentifierEXT m_identifier = { VK_STRUCTURE_TYPE_SHADER_MODULE_IDENTIFIER_EXT };
VkPipeline compileShaderPipelineLocked(
const DxvkShaderPipelineLibraryCompileArgs& args);
VkPipeline compileVertexShaderPipeline(
const DxvkShaderPipelineLibraryCompileArgs& args);
@ -444,6 +448,8 @@ namespace dxvk {
void generateModuleIdentifierLocked(
const SpirvCodeBuffer& spirvCode);
VkShaderStageFlagBits getShaderStage() const;
};
}