mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-20 19:54:19 +01:00
[dxvk] Try to create cached optimized pipeline whenever possible
This commit is contained in:
parent
df1908f7bf
commit
02aa1736f5
@ -51,6 +51,16 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
bool DxvkDevice::canUsePipelineCacheControl() const {
|
||||
// Don't bother with this unless the device also supports shader module
|
||||
// identifiers, since decoding and hashing the shaders is slow otherwise
|
||||
// and likely provides no benefit over linking pipeline libraries.
|
||||
return m_features.extPipelineCreationCacheControl.pipelineCreationCacheControl
|
||||
&& m_features.extShaderModuleIdentifier.shaderModuleIdentifier
|
||||
&& m_options.enableGraphicsPipelineLibrary != Tristate::True;
|
||||
}
|
||||
|
||||
|
||||
DxvkFramebufferSize DxvkDevice::getDefaultFramebufferSize() const {
|
||||
return DxvkFramebufferSize {
|
||||
m_properties.core.properties.limits.maxFramebufferWidth,
|
||||
|
@ -202,6 +202,12 @@ namespace dxvk {
|
||||
*/
|
||||
bool canUseGraphicsPipelineLibrary() const;
|
||||
|
||||
/**
|
||||
* \brief Checks whether pipeline creation cache control can be used
|
||||
* \returns \c true if all required features are supported.
|
||||
*/
|
||||
bool canUsePipelineCacheControl() const;
|
||||
|
||||
/**
|
||||
* \brief Queries default framebuffer size
|
||||
* \returns Default framebuffer size
|
||||
|
@ -589,7 +589,7 @@ namespace dxvk {
|
||||
|| instance->isCompiling.exchange(VK_TRUE, std::memory_order_acquire))
|
||||
return;
|
||||
|
||||
VkPipeline pipeline = this->createOptimizedPipeline(state);
|
||||
VkPipeline pipeline = this->createOptimizedPipeline(state, 0);
|
||||
instance->fastHandle.store(pipeline, std::memory_order_release);
|
||||
}
|
||||
|
||||
@ -600,18 +600,29 @@ namespace dxvk {
|
||||
VkPipeline fastHandle = VK_NULL_HANDLE;
|
||||
|
||||
if (this->canCreateBasePipeline(state)) {
|
||||
DxvkGraphicsPipelineVertexInputState viState(m_device, state);
|
||||
DxvkGraphicsPipelineFragmentOutputState foState(m_device, state, m_shaders.fs.ptr());
|
||||
// Try to create an optimized pipeline from the cache
|
||||
// first, since this is expected to be the fastest path.
|
||||
if (m_device->canUsePipelineCacheControl()) {
|
||||
fastHandle = this->createOptimizedPipeline(state,
|
||||
VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT);
|
||||
}
|
||||
|
||||
DxvkGraphicsPipelineBaseInstanceKey key;
|
||||
key.viLibrary = m_manager->createVertexInputLibrary(viState);
|
||||
key.foLibrary = m_manager->createFragmentOutputLibrary(foState);
|
||||
key.args.depthClipEnable = state.rs.depthClipEnable();
|
||||
if (!fastHandle) {
|
||||
// If that didn't succeed, link a pipeline using the
|
||||
// pre-compiled fragment and vertex shader libraries.
|
||||
DxvkGraphicsPipelineVertexInputState viState(m_device, state);
|
||||
DxvkGraphicsPipelineFragmentOutputState foState(m_device, state, m_shaders.fs.ptr());
|
||||
|
||||
baseHandle = this->createBaseInstance(key)->handle;
|
||||
DxvkGraphicsPipelineBaseInstanceKey key;
|
||||
key.viLibrary = m_manager->createVertexInputLibrary(viState);
|
||||
key.foLibrary = m_manager->createFragmentOutputLibrary(foState);
|
||||
key.args.depthClipEnable = state.rs.depthClipEnable();
|
||||
|
||||
baseHandle = this->createBaseInstance(key)->handle;
|
||||
}
|
||||
} else {
|
||||
// Create optimized variant right away, no choice
|
||||
fastHandle = this->createOptimizedPipeline(state);
|
||||
fastHandle = this->createOptimizedPipeline(state, 0);
|
||||
}
|
||||
|
||||
m_stats->numGraphicsPipelines += 1;
|
||||
@ -727,7 +738,8 @@ namespace dxvk {
|
||||
|
||||
|
||||
VkPipeline DxvkGraphicsPipeline::createOptimizedPipeline(
|
||||
const DxvkGraphicsPipelineStateInfo& state) const {
|
||||
const DxvkGraphicsPipelineStateInfo& state,
|
||||
VkPipelineCreateFlags flags) const {
|
||||
auto vk = m_device->vkd();
|
||||
|
||||
if (Logger::logLevel() <= LogLevel::Debug) {
|
||||
@ -772,16 +784,24 @@ namespace dxvk {
|
||||
|
||||
// Build stage infos for all provided shaders
|
||||
DxvkShaderStageInfo stageInfo(m_device);
|
||||
stageInfo.addStage(VK_SHADER_STAGE_VERTEX_BIT, getShaderCode(m_shaders.vs, state), &specInfo);
|
||||
|
||||
if (m_shaders.tcs != nullptr)
|
||||
stageInfo.addStage(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, getShaderCode(m_shaders.tcs, state), &specInfo);
|
||||
if (m_shaders.tes != nullptr)
|
||||
stageInfo.addStage(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, getShaderCode(m_shaders.tes, state), &specInfo);
|
||||
if (m_shaders.gs != nullptr)
|
||||
stageInfo.addStage(VK_SHADER_STAGE_GEOMETRY_BIT, getShaderCode(m_shaders.gs, state), &specInfo);
|
||||
if (m_shaders.fs != nullptr)
|
||||
stageInfo.addStage(VK_SHADER_STAGE_FRAGMENT_BIT, getShaderCode(m_shaders.fs, state), &specInfo);
|
||||
if (flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT) {
|
||||
stageInfo.addStage(VK_SHADER_STAGE_VERTEX_BIT, m_vsLibrary->getModuleIdentifier(), &specInfo);
|
||||
|
||||
if (m_shaders.fs != nullptr)
|
||||
stageInfo.addStage(VK_SHADER_STAGE_FRAGMENT_BIT, m_fsLibrary->getModuleIdentifier(), &specInfo);
|
||||
} else {
|
||||
stageInfo.addStage(VK_SHADER_STAGE_VERTEX_BIT, getShaderCode(m_shaders.vs, state), &specInfo);
|
||||
|
||||
if (m_shaders.tcs != nullptr)
|
||||
stageInfo.addStage(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, getShaderCode(m_shaders.tcs, state), &specInfo);
|
||||
if (m_shaders.tes != nullptr)
|
||||
stageInfo.addStage(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, getShaderCode(m_shaders.tes, state), &specInfo);
|
||||
if (m_shaders.gs != nullptr)
|
||||
stageInfo.addStage(VK_SHADER_STAGE_GEOMETRY_BIT, getShaderCode(m_shaders.gs, state), &specInfo);
|
||||
if (m_shaders.fs != nullptr)
|
||||
stageInfo.addStage(VK_SHADER_STAGE_FRAGMENT_BIT, getShaderCode(m_shaders.fs, state), &specInfo);
|
||||
}
|
||||
|
||||
DxvkGraphicsPipelineVertexInputState viState(m_device, state);
|
||||
DxvkGraphicsPipelinePreRasterizationState prState(m_device, state, m_shaders.gs.ptr());
|
||||
@ -793,6 +813,7 @@ namespace dxvk {
|
||||
dyInfo.pDynamicStates = dynamicStates.data();
|
||||
|
||||
VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &foState.rtInfo };
|
||||
info.flags = flags;
|
||||
info.stageCount = stageInfo.getStageCount();
|
||||
info.pStages = stageInfo.getStageInfos();
|
||||
info.pVertexInputState = &viState.viInfo;
|
||||
@ -811,9 +832,16 @@ namespace dxvk {
|
||||
info.pTessellationState = nullptr;
|
||||
|
||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||
if (vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline) != VK_SUCCESS) {
|
||||
Logger::err("DxvkGraphicsPipeline: Failed to compile pipeline");
|
||||
this->logPipelineState(LogLevel::Error, state);
|
||||
VkResult vr = vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
|
||||
|
||||
if (vr != VK_SUCCESS) {
|
||||
// Ignore any error if we're trying to create a cached pipeline. If linking or
|
||||
// compiling an optimized pipeline fail later, we'll still be printing errors.
|
||||
if (!(flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT)) {
|
||||
Logger::err(str::format("DxvkGraphicsPipeline: Failed to compile pipeline: ", vr));
|
||||
this->logPipelineState(LogLevel::Error, state);
|
||||
}
|
||||
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
|
@ -425,7 +425,8 @@ namespace dxvk {
|
||||
const DxvkGraphicsPipelineBaseInstanceKey& key) const;
|
||||
|
||||
VkPipeline createOptimizedPipeline(
|
||||
const DxvkGraphicsPipelineStateInfo& state) const;
|
||||
const DxvkGraphicsPipelineStateInfo& state,
|
||||
VkPipelineCreateFlags flags) const;
|
||||
|
||||
void destroyPipeline(
|
||||
VkPipeline pipeline) const;
|
||||
|
Loading…
x
Reference in New Issue
Block a user