mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-21 22:54:16 +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 {
|
DxvkFramebufferSize DxvkDevice::getDefaultFramebufferSize() const {
|
||||||
return DxvkFramebufferSize {
|
return DxvkFramebufferSize {
|
||||||
m_properties.core.properties.limits.maxFramebufferWidth,
|
m_properties.core.properties.limits.maxFramebufferWidth,
|
||||||
|
@ -202,6 +202,12 @@ namespace dxvk {
|
|||||||
*/
|
*/
|
||||||
bool canUseGraphicsPipelineLibrary() const;
|
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
|
* \brief Queries default framebuffer size
|
||||||
* \returns Default framebuffer size
|
* \returns Default framebuffer size
|
||||||
|
@ -589,7 +589,7 @@ namespace dxvk {
|
|||||||
|| instance->isCompiling.exchange(VK_TRUE, std::memory_order_acquire))
|
|| instance->isCompiling.exchange(VK_TRUE, std::memory_order_acquire))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
VkPipeline pipeline = this->createOptimizedPipeline(state);
|
VkPipeline pipeline = this->createOptimizedPipeline(state, 0);
|
||||||
instance->fastHandle.store(pipeline, std::memory_order_release);
|
instance->fastHandle.store(pipeline, std::memory_order_release);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,18 +600,29 @@ namespace dxvk {
|
|||||||
VkPipeline fastHandle = VK_NULL_HANDLE;
|
VkPipeline fastHandle = VK_NULL_HANDLE;
|
||||||
|
|
||||||
if (this->canCreateBasePipeline(state)) {
|
if (this->canCreateBasePipeline(state)) {
|
||||||
DxvkGraphicsPipelineVertexInputState viState(m_device, state);
|
// Try to create an optimized pipeline from the cache
|
||||||
DxvkGraphicsPipelineFragmentOutputState foState(m_device, state, m_shaders.fs.ptr());
|
// 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;
|
if (!fastHandle) {
|
||||||
key.viLibrary = m_manager->createVertexInputLibrary(viState);
|
// If that didn't succeed, link a pipeline using the
|
||||||
key.foLibrary = m_manager->createFragmentOutputLibrary(foState);
|
// pre-compiled fragment and vertex shader libraries.
|
||||||
key.args.depthClipEnable = state.rs.depthClipEnable();
|
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 {
|
} else {
|
||||||
// Create optimized variant right away, no choice
|
// Create optimized variant right away, no choice
|
||||||
fastHandle = this->createOptimizedPipeline(state);
|
fastHandle = this->createOptimizedPipeline(state, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_stats->numGraphicsPipelines += 1;
|
m_stats->numGraphicsPipelines += 1;
|
||||||
@ -727,7 +738,8 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
VkPipeline DxvkGraphicsPipeline::createOptimizedPipeline(
|
VkPipeline DxvkGraphicsPipeline::createOptimizedPipeline(
|
||||||
const DxvkGraphicsPipelineStateInfo& state) const {
|
const DxvkGraphicsPipelineStateInfo& state,
|
||||||
|
VkPipelineCreateFlags flags) const {
|
||||||
auto vk = m_device->vkd();
|
auto vk = m_device->vkd();
|
||||||
|
|
||||||
if (Logger::logLevel() <= LogLevel::Debug) {
|
if (Logger::logLevel() <= LogLevel::Debug) {
|
||||||
@ -772,16 +784,24 @@ namespace dxvk {
|
|||||||
|
|
||||||
// Build stage infos for all provided shaders
|
// Build stage infos for all provided shaders
|
||||||
DxvkShaderStageInfo stageInfo(m_device);
|
DxvkShaderStageInfo stageInfo(m_device);
|
||||||
stageInfo.addStage(VK_SHADER_STAGE_VERTEX_BIT, getShaderCode(m_shaders.vs, state), &specInfo);
|
|
||||||
|
|
||||||
if (m_shaders.tcs != nullptr)
|
if (flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT) {
|
||||||
stageInfo.addStage(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, getShaderCode(m_shaders.tcs, state), &specInfo);
|
stageInfo.addStage(VK_SHADER_STAGE_VERTEX_BIT, m_vsLibrary->getModuleIdentifier(), &specInfo);
|
||||||
if (m_shaders.tes != nullptr)
|
|
||||||
stageInfo.addStage(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, getShaderCode(m_shaders.tes, state), &specInfo);
|
if (m_shaders.fs != nullptr)
|
||||||
if (m_shaders.gs != nullptr)
|
stageInfo.addStage(VK_SHADER_STAGE_FRAGMENT_BIT, m_fsLibrary->getModuleIdentifier(), &specInfo);
|
||||||
stageInfo.addStage(VK_SHADER_STAGE_GEOMETRY_BIT, getShaderCode(m_shaders.gs, state), &specInfo);
|
} else {
|
||||||
if (m_shaders.fs != nullptr)
|
stageInfo.addStage(VK_SHADER_STAGE_VERTEX_BIT, getShaderCode(m_shaders.vs, state), &specInfo);
|
||||||
stageInfo.addStage(VK_SHADER_STAGE_FRAGMENT_BIT, getShaderCode(m_shaders.fs, 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);
|
DxvkGraphicsPipelineVertexInputState viState(m_device, state);
|
||||||
DxvkGraphicsPipelinePreRasterizationState prState(m_device, state, m_shaders.gs.ptr());
|
DxvkGraphicsPipelinePreRasterizationState prState(m_device, state, m_shaders.gs.ptr());
|
||||||
@ -793,6 +813,7 @@ namespace dxvk {
|
|||||||
dyInfo.pDynamicStates = dynamicStates.data();
|
dyInfo.pDynamicStates = dynamicStates.data();
|
||||||
|
|
||||||
VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &foState.rtInfo };
|
VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &foState.rtInfo };
|
||||||
|
info.flags = flags;
|
||||||
info.stageCount = stageInfo.getStageCount();
|
info.stageCount = stageInfo.getStageCount();
|
||||||
info.pStages = stageInfo.getStageInfos();
|
info.pStages = stageInfo.getStageInfos();
|
||||||
info.pVertexInputState = &viState.viInfo;
|
info.pVertexInputState = &viState.viInfo;
|
||||||
@ -811,9 +832,16 @@ namespace dxvk {
|
|||||||
info.pTessellationState = nullptr;
|
info.pTessellationState = nullptr;
|
||||||
|
|
||||||
VkPipeline pipeline = VK_NULL_HANDLE;
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||||
if (vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline) != VK_SUCCESS) {
|
VkResult vr = vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
|
||||||
Logger::err("DxvkGraphicsPipeline: Failed to compile pipeline");
|
|
||||||
this->logPipelineState(LogLevel::Error, state);
|
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;
|
return VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,7 +425,8 @@ namespace dxvk {
|
|||||||
const DxvkGraphicsPipelineBaseInstanceKey& key) const;
|
const DxvkGraphicsPipelineBaseInstanceKey& key) const;
|
||||||
|
|
||||||
VkPipeline createOptimizedPipeline(
|
VkPipeline createOptimizedPipeline(
|
||||||
const DxvkGraphicsPipelineStateInfo& state) const;
|
const DxvkGraphicsPipelineStateInfo& state,
|
||||||
|
VkPipelineCreateFlags flags) const;
|
||||||
|
|
||||||
void destroyPipeline(
|
void destroyPipeline(
|
||||||
VkPipeline pipeline) const;
|
VkPipeline pipeline) const;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user