mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-12 22:08:59 +01:00
[dxvk] Use shader module identifier for subsequent pipeline libary compiles
Should further reduce the hit we take from destroying pipeline libraries.
This commit is contained in:
parent
4bc2d713fb
commit
b97dba3712
@ -960,28 +960,24 @@ namespace dxvk {
|
|||||||
VkShaderStageFlagBits stage = getShaderStage();
|
VkShaderStageFlagBits stage = getShaderStage();
|
||||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||||
|
|
||||||
// Compile pipeline of the appropriate type
|
// If this is not the first time we're compiling the pipeline,
|
||||||
switch (stage) {
|
// try to get a cache hit using the shader module identifier
|
||||||
case VK_SHADER_STAGE_VERTEX_BIT:
|
// so that we don't have to decompress our SPIR-V shader again.
|
||||||
pipeline = compileVertexShaderPipeline(args);
|
if (m_compiledOnce && canUsePipelineCacheControl()) {
|
||||||
break;
|
pipeline = this->compileShaderPipeline(args, stage,
|
||||||
|
VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT);
|
||||||
case VK_SHADER_STAGE_FRAGMENT_BIT:
|
|
||||||
pipeline = compileFragmentShaderPipeline();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VK_SHADER_STAGE_COMPUTE_BIT:
|
|
||||||
pipeline = compileComputeShaderPipeline();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Should be unreachable
|
|
||||||
return VK_NULL_HANDLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!pipeline)
|
||||||
|
pipeline = this->compileShaderPipeline(args, stage, 0);
|
||||||
|
|
||||||
|
// Well that didn't work
|
||||||
|
if (!pipeline)
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
|
||||||
// Increment stat counter the first time this
|
// Increment stat counter the first time this
|
||||||
// shader pipeline gets compiled successfully
|
// shader pipeline gets compiled successfully
|
||||||
if (!m_compiledOnce && pipeline) {
|
if (!m_compiledOnce) {
|
||||||
if (stage == VK_SHADER_STAGE_COMPUTE_BIT)
|
if (stage == VK_SHADER_STAGE_COMPUTE_BIT)
|
||||||
m_stats->numComputePipelines += 1;
|
m_stats->numComputePipelines += 1;
|
||||||
else
|
else
|
||||||
@ -994,16 +990,56 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VkPipeline DxvkShaderPipelineLibrary::compileVertexShaderPipeline(
|
VkPipeline DxvkShaderPipelineLibrary::compileShaderPipeline(
|
||||||
const DxvkShaderPipelineLibraryCompileArgs& args) {
|
const DxvkShaderPipelineLibraryCompileArgs& args,
|
||||||
auto vk = m_device->vkd();
|
VkShaderStageFlagBits stage,
|
||||||
|
VkPipelineCreateFlags flags) {
|
||||||
SpirvCodeBuffer spirvCode = this->getShaderCode();
|
|
||||||
this->generateModuleIdentifier(spirvCode);
|
|
||||||
|
|
||||||
// Set up shader stage info
|
|
||||||
DxvkShaderStageInfo stageInfo(m_device);
|
DxvkShaderStageInfo stageInfo(m_device);
|
||||||
stageInfo.addStage(VK_SHADER_STAGE_VERTEX_BIT, std::move(spirvCode), nullptr);
|
|
||||||
|
{ std::lock_guard lock(m_identifierMutex);
|
||||||
|
|
||||||
|
if (flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT) {
|
||||||
|
// Fail if we have no idenfitier for whatever reason, caller
|
||||||
|
// should fall back to the slow path if this happens
|
||||||
|
if (!m_identifier.identifierSize)
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
stageInfo.addStage(stage, m_identifier, nullptr);
|
||||||
|
} else {
|
||||||
|
// Decompress code and generate identifier as needed
|
||||||
|
SpirvCodeBuffer spirvCode = this->getShaderCode();
|
||||||
|
|
||||||
|
if (!m_identifier.identifierSize)
|
||||||
|
this->generateModuleIdentifierLocked(spirvCode);
|
||||||
|
|
||||||
|
stageInfo.addStage(stage, std::move(spirvCode), nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (stage) {
|
||||||
|
case VK_SHADER_STAGE_VERTEX_BIT:
|
||||||
|
return compileVertexShaderPipeline(args, stageInfo, flags);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VK_SHADER_STAGE_FRAGMENT_BIT:
|
||||||
|
return compileFragmentShaderPipeline(stageInfo, flags);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VK_SHADER_STAGE_COMPUTE_BIT:
|
||||||
|
return compileComputeShaderPipeline(stageInfo, flags);
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Should be unreachable
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VkPipeline DxvkShaderPipelineLibrary::compileVertexShaderPipeline(
|
||||||
|
const DxvkShaderPipelineLibraryCompileArgs& args,
|
||||||
|
const DxvkShaderStageInfo& stageInfo,
|
||||||
|
VkPipelineCreateFlags flags) {
|
||||||
|
auto vk = m_device->vkd();
|
||||||
|
|
||||||
// Set up dynamic state. We do not know any pipeline state
|
// Set up dynamic state. We do not know any pipeline state
|
||||||
// at this time, so make as much state dynamic as we can.
|
// at this time, so make as much state dynamic as we can.
|
||||||
@ -1047,7 +1083,7 @@ namespace dxvk {
|
|||||||
libInfo.flags = VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT;
|
libInfo.flags = VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT;
|
||||||
|
|
||||||
VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &libInfo };
|
VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &libInfo };
|
||||||
info.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR;
|
info.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR | flags;
|
||||||
info.stageCount = stageInfo.getStageCount();
|
info.stageCount = stageInfo.getStageCount();
|
||||||
info.pStages = stageInfo.getStageInfos();
|
info.pStages = stageInfo.getStageInfos();
|
||||||
info.pViewportState = &vpInfo;
|
info.pViewportState = &vpInfo;
|
||||||
@ -1057,24 +1093,20 @@ namespace dxvk {
|
|||||||
info.basePipelineIndex = -1;
|
info.basePipelineIndex = -1;
|
||||||
|
|
||||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||||
|
VkResult vr = vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
|
||||||
|
|
||||||
if (vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline))
|
if (vr && !(flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT))
|
||||||
throw DxvkError("DxvkShaderPipelineLibrary: Failed to create compute pipeline");
|
throw DxvkError(str::format("DxvkShaderPipelineLibrary: Failed to create vertex shader pipeline: ", vr));
|
||||||
|
|
||||||
return pipeline;
|
return pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VkPipeline DxvkShaderPipelineLibrary::compileFragmentShaderPipeline() {
|
VkPipeline DxvkShaderPipelineLibrary::compileFragmentShaderPipeline(
|
||||||
|
const DxvkShaderStageInfo& stageInfo,
|
||||||
|
VkPipelineCreateFlags flags) {
|
||||||
auto vk = m_device->vkd();
|
auto vk = m_device->vkd();
|
||||||
|
|
||||||
SpirvCodeBuffer spirvCode = this->getShaderCode();
|
|
||||||
this->generateModuleIdentifier(spirvCode);
|
|
||||||
|
|
||||||
// Set up shader stage info with the given code
|
|
||||||
DxvkShaderStageInfo stageInfo(m_device);
|
|
||||||
stageInfo.addStage(VK_SHADER_STAGE_FRAGMENT_BIT, std::move(spirvCode), nullptr);
|
|
||||||
|
|
||||||
// Set up dynamic state. We do not know any pipeline state
|
// Set up dynamic state. We do not know any pipeline state
|
||||||
// at this time, so make as much state dynamic as we can.
|
// at this time, so make as much state dynamic as we can.
|
||||||
uint32_t dynamicStateCount = 0;
|
uint32_t dynamicStateCount = 0;
|
||||||
@ -1120,7 +1152,7 @@ namespace dxvk {
|
|||||||
libInfo.flags = VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT;
|
libInfo.flags = VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT;
|
||||||
|
|
||||||
VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &libInfo };
|
VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &libInfo };
|
||||||
info.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR;
|
info.flags = VK_PIPELINE_CREATE_LIBRARY_BIT_KHR | flags;
|
||||||
info.stageCount = stageInfo.getStageCount();
|
info.stageCount = stageInfo.getStageCount();
|
||||||
info.pStages = stageInfo.getStageInfos();
|
info.pStages = stageInfo.getStageInfos();
|
||||||
info.pDepthStencilState = &dsInfo;
|
info.pDepthStencilState = &dsInfo;
|
||||||
@ -1132,34 +1164,32 @@ namespace dxvk {
|
|||||||
info.pMultisampleState = &msInfo;
|
info.pMultisampleState = &msInfo;
|
||||||
|
|
||||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||||
|
VkResult vr = vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
|
||||||
|
|
||||||
if (vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline))
|
if (vr && !(flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT))
|
||||||
throw DxvkError("DxvkShaderPipelineLibrary: Failed to create compute pipeline");
|
throw DxvkError(str::format("DxvkShaderPipelineLibrary: Failed to create fragment shader pipeline: ", vr));
|
||||||
|
|
||||||
return pipeline;
|
return pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VkPipeline DxvkShaderPipelineLibrary::compileComputeShaderPipeline() {
|
VkPipeline DxvkShaderPipelineLibrary::compileComputeShaderPipeline(
|
||||||
|
const DxvkShaderStageInfo& stageInfo,
|
||||||
|
VkPipelineCreateFlags flags) {
|
||||||
auto vk = m_device->vkd();
|
auto vk = m_device->vkd();
|
||||||
|
|
||||||
SpirvCodeBuffer spirvCode = this->getShaderCode();
|
|
||||||
this->generateModuleIdentifier(spirvCode);
|
|
||||||
|
|
||||||
// Set up shader stage info
|
|
||||||
DxvkShaderStageInfo stageInfo(m_device);
|
|
||||||
stageInfo.addStage(VK_SHADER_STAGE_COMPUTE_BIT, std::move(spirvCode), nullptr);
|
|
||||||
|
|
||||||
// Compile the compute pipeline as normal
|
// Compile the compute pipeline as normal
|
||||||
VkComputePipelineCreateInfo info = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
|
VkComputePipelineCreateInfo info = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
|
||||||
|
info.flags = flags;
|
||||||
info.stage = *stageInfo.getStageInfos();
|
info.stage = *stageInfo.getStageInfos();
|
||||||
info.layout = m_layout->getPipelineLayout(false);
|
info.layout = m_layout->getPipelineLayout(false);
|
||||||
info.basePipelineIndex = -1;
|
info.basePipelineIndex = -1;
|
||||||
|
|
||||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||||
|
VkResult vr = vk->vkCreateComputePipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
|
||||||
|
|
||||||
if (vk->vkCreateComputePipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline))
|
if (vr && !(flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT))
|
||||||
throw DxvkError("DxvkShaderPipelineLibrary: Failed to create compute pipeline");
|
throw DxvkError(str::format("DxvkShaderPipelineLibrary: Failed to create compute shader pipeline: ", vr));
|
||||||
|
|
||||||
return pipeline;
|
return pipeline;
|
||||||
}
|
}
|
||||||
@ -1177,22 +1207,13 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DxvkShaderPipelineLibrary::generateModuleIdentifier(
|
|
||||||
const SpirvCodeBuffer& spirvCode) {
|
|
||||||
if (!m_device->features().extShaderModuleIdentifier.shaderModuleIdentifier)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::lock_guard lock(m_identifierMutex);
|
|
||||||
|
|
||||||
if (!m_identifier.identifierSize)
|
|
||||||
this->generateModuleIdentifierLocked(spirvCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DxvkShaderPipelineLibrary::generateModuleIdentifierLocked(
|
void DxvkShaderPipelineLibrary::generateModuleIdentifierLocked(
|
||||||
const SpirvCodeBuffer& spirvCode) {
|
const SpirvCodeBuffer& spirvCode) {
|
||||||
auto vk = m_device->vkd();
|
auto vk = m_device->vkd();
|
||||||
|
|
||||||
|
if (!canUsePipelineCacheControl())
|
||||||
|
return;
|
||||||
|
|
||||||
VkShaderModuleCreateInfo info = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
|
VkShaderModuleCreateInfo info = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
|
||||||
info.codeSize = spirvCode.size();
|
info.codeSize = spirvCode.size();
|
||||||
info.pCode = spirvCode.data();
|
info.pCode = spirvCode.data();
|
||||||
@ -1211,4 +1232,12 @@ namespace dxvk {
|
|||||||
return stage;
|
return stage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DxvkShaderPipelineLibrary::canUsePipelineCacheControl() const {
|
||||||
|
const auto& features = m_device->features();
|
||||||
|
|
||||||
|
return features.vk13.pipelineCreationCacheControl
|
||||||
|
&& features.extShaderModuleIdentifier.shaderModuleIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -433,23 +433,33 @@ namespace dxvk {
|
|||||||
VkPipeline compileShaderPipelineLocked(
|
VkPipeline compileShaderPipelineLocked(
|
||||||
const DxvkShaderPipelineLibraryCompileArgs& args);
|
const DxvkShaderPipelineLibraryCompileArgs& args);
|
||||||
|
|
||||||
|
VkPipeline compileShaderPipeline(
|
||||||
|
const DxvkShaderPipelineLibraryCompileArgs& args,
|
||||||
|
VkShaderStageFlagBits stage,
|
||||||
|
VkPipelineCreateFlags flags);
|
||||||
|
|
||||||
VkPipeline compileVertexShaderPipeline(
|
VkPipeline compileVertexShaderPipeline(
|
||||||
const DxvkShaderPipelineLibraryCompileArgs& args);
|
const DxvkShaderPipelineLibraryCompileArgs& args,
|
||||||
|
const DxvkShaderStageInfo& stageInfo,
|
||||||
|
VkPipelineCreateFlags flags);
|
||||||
|
|
||||||
VkPipeline compileFragmentShaderPipeline();
|
VkPipeline compileFragmentShaderPipeline(
|
||||||
|
const DxvkShaderStageInfo& stageInfo,
|
||||||
|
VkPipelineCreateFlags flags);
|
||||||
|
|
||||||
VkPipeline compileComputeShaderPipeline();
|
VkPipeline compileComputeShaderPipeline(
|
||||||
|
const DxvkShaderStageInfo& stageInfo,
|
||||||
|
VkPipelineCreateFlags flags);
|
||||||
|
|
||||||
SpirvCodeBuffer getShaderCode() const;
|
SpirvCodeBuffer getShaderCode() const;
|
||||||
|
|
||||||
void generateModuleIdentifier(
|
|
||||||
const SpirvCodeBuffer& spirvCode);
|
|
||||||
|
|
||||||
void generateModuleIdentifierLocked(
|
void generateModuleIdentifierLocked(
|
||||||
const SpirvCodeBuffer& spirvCode);
|
const SpirvCodeBuffer& spirvCode);
|
||||||
|
|
||||||
VkShaderStageFlagBits getShaderStage() const;
|
VkShaderStageFlagBits getShaderStage() const;
|
||||||
|
|
||||||
|
bool canUsePipelineCacheControl() const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user