1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-11 19:24:11 +01:00

[dxvk] Forward link flags when using shader identifiers

Fixes a long-standing bug that now causes validation errors.
This commit is contained in:
Philip Rebohle 2024-04-29 17:19:36 +02:00
parent 29253da356
commit 65373792d2
4 changed files with 57 additions and 43 deletions

View File

@ -49,7 +49,7 @@ namespace dxvk {
// may wait for an ongoing compile job to finish, or // may wait for an ongoing compile job to finish, or
// compile the pipeline immediately on the calling thread. // compile the pipeline immediately on the calling thread.
m_libraryHandle = m_library->acquirePipelineHandle( m_libraryHandle = m_library->acquirePipelineHandle(
DxvkShaderPipelineLibraryCompileArgs()); DxvkShaderPipelineLibraryCompileArgs()).handle;
return m_libraryHandle; return m_libraryHandle;
} else { } else {

View File

@ -1111,7 +1111,8 @@ namespace dxvk {
if (doCreateBasePipeline) if (doCreateBasePipeline)
baseHandle = this->getBasePipeline(state); baseHandle = this->getBasePipeline(state);
else
if (!baseHandle)
fastHandle = this->getOptimizedPipeline(state); fastHandle = this->getOptimizedPipeline(state);
// Log pipeline state if requested, or on failure // Log pipeline state if requested, or on failure
@ -1236,10 +1237,11 @@ namespace dxvk {
const DxvkGraphicsPipelineBaseInstanceKey& key) const { const DxvkGraphicsPipelineBaseInstanceKey& key) const {
auto vk = m_device->vkd(); auto vk = m_device->vkd();
DxvkShaderPipelineLibraryHandle vs = m_vsLibrary->acquirePipelineHandle(key.args);
DxvkShaderPipelineLibraryHandle fs = m_fsLibrary->acquirePipelineHandle(key.args);
std::array<VkPipeline, 4> libraries = {{ std::array<VkPipeline, 4> libraries = {{
key.viLibrary->getHandle(), key.viLibrary->getHandle(), vs.handle, fs.handle,
m_vsLibrary->acquirePipelineHandle(key.args),
m_fsLibrary->acquirePipelineHandle(key.args),
key.foLibrary->getHandle(), key.foLibrary->getHandle(),
}}; }};
@ -1248,13 +1250,14 @@ namespace dxvk {
libInfo.pLibraries = libraries.data(); libInfo.pLibraries = libraries.data();
VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &libInfo }; VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &libInfo };
info.flags = vs.linkFlags | fs.linkFlags;
info.layout = m_bindings->getPipelineLayout(true); info.layout = m_bindings->getPipelineLayout(true);
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); VkResult vr = vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
if (vr != VK_SUCCESS) if (vr && vr != VK_PIPELINE_COMPILE_REQUIRED_EXT)
Logger::err(str::format("DxvkGraphicsPipeline: Failed to create base pipeline: ", vr)); Logger::err(str::format("DxvkGraphicsPipeline: Failed to create base pipeline: ", vr));
return pipeline; return pipeline;

View File

@ -1042,18 +1042,18 @@ namespace dxvk {
} }
VkPipeline DxvkShaderPipelineLibrary::acquirePipelineHandle( DxvkShaderPipelineLibraryHandle DxvkShaderPipelineLibrary::acquirePipelineHandle(
const DxvkShaderPipelineLibraryCompileArgs& args) { const DxvkShaderPipelineLibraryCompileArgs& args) {
std::lock_guard lock(m_mutex); std::lock_guard lock(m_mutex);
if (m_device->mustTrackPipelineLifetime()) if (m_device->mustTrackPipelineLifetime())
m_useCount += 1; m_useCount += 1;
VkPipeline& pipeline = (m_shaders.vs && !args.depthClipEnable) DxvkShaderPipelineLibraryHandle& pipeline = (m_shaders.vs && !args.depthClipEnable)
? m_pipelineNoDepthClip ? m_pipelineNoDepthClip
: m_pipeline; : m_pipeline;
if (pipeline) if (pipeline.handle)
return pipeline; return pipeline;
pipeline = compileShaderPipelineLocked(args); pipeline = compileShaderPipelineLocked(args);
@ -1079,7 +1079,7 @@ namespace dxvk {
return; return;
// Compile the pipeline with default args // Compile the pipeline with default args
VkPipeline pipeline = compileShaderPipelineLocked( DxvkShaderPipelineLibraryHandle pipeline = compileShaderPipelineLocked(
DxvkShaderPipelineLibraryCompileArgs()); DxvkShaderPipelineLibraryCompileArgs());
// On 32-bit, destroy the pipeline immediately in order to // On 32-bit, destroy the pipeline immediately in order to
@ -1087,9 +1087,9 @@ namespace dxvk {
// we need to recreate the pipeline. // we need to recreate the pipeline.
if (m_device->mustTrackPipelineLifetime()) { if (m_device->mustTrackPipelineLifetime()) {
auto vk = m_device->vkd(); auto vk = m_device->vkd();
vk->vkDestroyPipeline(vk->device(), pipeline, nullptr); vk->vkDestroyPipeline(vk->device(), pipeline.handle, nullptr);
pipeline = VK_NULL_HANDLE; pipeline.handle = VK_NULL_HANDLE;
} }
// Write back pipeline handle for future use // Write back pipeline handle for future use
@ -1100,34 +1100,34 @@ namespace dxvk {
void DxvkShaderPipelineLibrary::destroyShaderPipelinesLocked() { void DxvkShaderPipelineLibrary::destroyShaderPipelinesLocked() {
auto vk = m_device->vkd(); auto vk = m_device->vkd();
vk->vkDestroyPipeline(vk->device(), m_pipeline, nullptr); vk->vkDestroyPipeline(vk->device(), m_pipeline.handle, nullptr);
vk->vkDestroyPipeline(vk->device(), m_pipelineNoDepthClip, nullptr); vk->vkDestroyPipeline(vk->device(), m_pipelineNoDepthClip.handle, nullptr);
m_pipeline = VK_NULL_HANDLE; m_pipeline.handle = VK_NULL_HANDLE;
m_pipelineNoDepthClip = VK_NULL_HANDLE; m_pipelineNoDepthClip.handle = VK_NULL_HANDLE;
} }
VkPipeline DxvkShaderPipelineLibrary::compileShaderPipelineLocked( DxvkShaderPipelineLibraryHandle DxvkShaderPipelineLibrary::compileShaderPipelineLocked(
const DxvkShaderPipelineLibraryCompileArgs& args) { const DxvkShaderPipelineLibraryCompileArgs& args) {
this->notifyLibraryCompile(); this->notifyLibraryCompile();
// If this is not the first time we're compiling the pipeline, // If this is not the first time we're compiling the pipeline,
// try to get a cache hit using the shader module identifier // try to get a cache hit using the shader module identifier
// so that we don't have to decompress our SPIR-V shader again. // so that we don't have to decompress our SPIR-V shader again.
VkPipeline pipeline = VK_NULL_HANDLE; DxvkShaderPipelineLibraryHandle pipeline = { VK_NULL_HANDLE, 0 };
if (m_compiledOnce && canUsePipelineCacheControl()) { if (m_compiledOnce && canUsePipelineCacheControl()) {
pipeline = this->compileShaderPipeline(args, pipeline = this->compileShaderPipeline(args,
VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT); VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT);
} }
if (!pipeline) if (!pipeline.handle)
pipeline = this->compileShaderPipeline(args, 0); pipeline = this->compileShaderPipeline(args, 0);
// Well that didn't work // Well that didn't work
if (!pipeline) if (!pipeline.handle)
return VK_NULL_HANDLE; return { VK_NULL_HANDLE, 0 };
// Increment stat counter the first time this // Increment stat counter the first time this
// shader pipeline gets compiled successfully // shader pipeline gets compiled successfully
@ -1144,7 +1144,7 @@ namespace dxvk {
} }
VkPipeline DxvkShaderPipelineLibrary::compileShaderPipeline( DxvkShaderPipelineLibraryHandle DxvkShaderPipelineLibrary::compileShaderPipeline(
const DxvkShaderPipelineLibraryCompileArgs& args, const DxvkShaderPipelineLibraryCompileArgs& args,
VkPipelineCreateFlags flags) { VkPipelineCreateFlags flags) {
DxvkShaderStageInfo stageInfo(m_device); DxvkShaderStageInfo stageInfo(m_device);
@ -1161,7 +1161,7 @@ namespace dxvk {
// Fail if we have no idenfitier for whatever reason, caller // Fail if we have no idenfitier for whatever reason, caller
// should fall back to the slow path if this happens // should fall back to the slow path if this happens
if (!identifier->identifierSize) if (!identifier->identifierSize)
return VK_NULL_HANDLE; return { VK_NULL_HANDLE, 0 };
stageInfo.addStage(stage, *identifier, nullptr); stageInfo.addStage(stage, *identifier, nullptr);
} else { } else {
@ -1178,17 +1178,17 @@ namespace dxvk {
} }
} }
VkPipeline pipeline = VK_NULL_HANDLE;
if (stageMask & VK_SHADER_STAGE_VERTEX_BIT) if (stageMask & VK_SHADER_STAGE_VERTEX_BIT)
return compileVertexShaderPipeline(args, stageInfo, flags); pipeline = compileVertexShaderPipeline(args, stageInfo, flags);
else if (stageMask & VK_SHADER_STAGE_FRAGMENT_BIT)
if (stageMask & VK_SHADER_STAGE_FRAGMENT_BIT) pipeline = compileFragmentShaderPipeline(stageInfo, flags);
return compileFragmentShaderPipeline(stageInfo, flags); else if (stageMask & VK_SHADER_STAGE_COMPUTE_BIT)
pipeline = compileComputeShaderPipeline(stageInfo, flags);
if (stageMask & VK_SHADER_STAGE_COMPUTE_BIT)
return compileComputeShaderPipeline(stageInfo, flags);
// Should be unreachable // Should be unreachable
return VK_NULL_HANDLE; return { pipeline, flags };
} }
@ -1266,7 +1266,7 @@ namespace dxvk {
VkPipeline pipeline = VK_NULL_HANDLE; VkPipeline pipeline = VK_NULL_HANDLE;
VkResult vr = vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline); VkResult vr = vk->vkCreateGraphicsPipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
if (vr && !(flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT)) if (vr && vr != VK_PIPELINE_COMPILE_REQUIRED_EXT)
Logger::err(str::format("DxvkShaderPipelineLibrary: Failed to create vertex shader pipeline: ", vr)); Logger::err(str::format("DxvkShaderPipelineLibrary: Failed to create vertex shader pipeline: ", vr));
return vr ? VK_NULL_HANDLE : pipeline; return vr ? VK_NULL_HANDLE : pipeline;
@ -1377,7 +1377,7 @@ namespace dxvk {
VkPipeline pipeline = VK_NULL_HANDLE; VkPipeline pipeline = VK_NULL_HANDLE;
VkResult vr = vk->vkCreateComputePipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline); VkResult vr = vk->vkCreateComputePipelines(vk->device(), VK_NULL_HANDLE, 1, &info, nullptr, &pipeline);
if (vr && !(flags & VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT)) if (vr && vr != VK_PIPELINE_COMPILE_REQUIRED_EXT)
Logger::err(str::format("DxvkShaderPipelineLibrary: Failed to create compute shader pipeline: ", vr)); Logger::err(str::format("DxvkShaderPipelineLibrary: Failed to create compute shader pipeline: ", vr));
return vr ? VK_NULL_HANDLE : pipeline; return vr ? VK_NULL_HANDLE : pipeline;

View File

@ -482,6 +482,17 @@ namespace dxvk {
}; };
/**
* \brief Pipeline library handle
*
* Stores a pipeline library handle and the necessary link flags.
*/
struct DxvkShaderPipelineLibraryHandle {
VkPipeline handle;
VkPipelineCreateFlags linkFlags;
};
/** /**
* \brief Shader pipeline library * \brief Shader pipeline library
* *
@ -524,7 +535,7 @@ namespace dxvk {
* \param [in] args Compile arguments * \param [in] args Compile arguments
* \returns Vulkan pipeline handle * \returns Vulkan pipeline handle
*/ */
VkPipeline acquirePipelineHandle( DxvkShaderPipelineLibraryHandle acquirePipelineHandle(
const DxvkShaderPipelineLibraryCompileArgs& args); const DxvkShaderPipelineLibraryCompileArgs& args);
/** /**
@ -552,21 +563,21 @@ namespace dxvk {
DxvkShaderSet m_shaders; DxvkShaderSet m_shaders;
const DxvkBindingLayoutObjects* m_layout; const DxvkBindingLayoutObjects* m_layout;
dxvk::mutex m_mutex; dxvk::mutex m_mutex;
VkPipeline m_pipeline = VK_NULL_HANDLE; DxvkShaderPipelineLibraryHandle m_pipeline = { VK_NULL_HANDLE, 0 };
VkPipeline m_pipelineNoDepthClip = VK_NULL_HANDLE; DxvkShaderPipelineLibraryHandle m_pipelineNoDepthClip = { VK_NULL_HANDLE, 0 };
uint32_t m_useCount = 0u; uint32_t m_useCount = 0u;
bool m_compiledOnce = false; bool m_compiledOnce = false;
dxvk::mutex m_identifierMutex; dxvk::mutex m_identifierMutex;
DxvkShaderIdentifierSet m_identifiers; DxvkShaderIdentifierSet m_identifiers;
void destroyShaderPipelinesLocked(); void destroyShaderPipelinesLocked();
VkPipeline compileShaderPipelineLocked( DxvkShaderPipelineLibraryHandle compileShaderPipelineLocked(
const DxvkShaderPipelineLibraryCompileArgs& args); const DxvkShaderPipelineLibraryCompileArgs& args);
VkPipeline compileShaderPipeline( DxvkShaderPipelineLibraryHandle compileShaderPipeline(
const DxvkShaderPipelineLibraryCompileArgs& args, const DxvkShaderPipelineLibraryCompileArgs& args,
VkPipelineCreateFlags flags); VkPipelineCreateFlags flags);