From 65373792d2918fc7ce81d30d4da0b77cc6ceb527 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Mon, 29 Apr 2024 17:19:36 +0200 Subject: [PATCH] [dxvk] Forward link flags when using shader identifiers Fixes a long-standing bug that now causes validation errors. --- src/dxvk/dxvk_compute.cpp | 2 +- src/dxvk/dxvk_graphics.cpp | 13 +++++---- src/dxvk/dxvk_shader.cpp | 54 +++++++++++++++++++------------------- src/dxvk/dxvk_shader.h | 31 +++++++++++++++------- 4 files changed, 57 insertions(+), 43 deletions(-) diff --git a/src/dxvk/dxvk_compute.cpp b/src/dxvk/dxvk_compute.cpp index 93ebfa5e..2a12806f 100644 --- a/src/dxvk/dxvk_compute.cpp +++ b/src/dxvk/dxvk_compute.cpp @@ -49,7 +49,7 @@ namespace dxvk { // may wait for an ongoing compile job to finish, or // compile the pipeline immediately on the calling thread. m_libraryHandle = m_library->acquirePipelineHandle( - DxvkShaderPipelineLibraryCompileArgs()); + DxvkShaderPipelineLibraryCompileArgs()).handle; return m_libraryHandle; } else { diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index 76df237d..65ef5197 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -1111,7 +1111,8 @@ namespace dxvk { if (doCreateBasePipeline) baseHandle = this->getBasePipeline(state); - else + + if (!baseHandle) fastHandle = this->getOptimizedPipeline(state); // Log pipeline state if requested, or on failure @@ -1236,10 +1237,11 @@ namespace dxvk { const DxvkGraphicsPipelineBaseInstanceKey& key) const { auto vk = m_device->vkd(); + DxvkShaderPipelineLibraryHandle vs = m_vsLibrary->acquirePipelineHandle(key.args); + DxvkShaderPipelineLibraryHandle fs = m_fsLibrary->acquirePipelineHandle(key.args); + std::array libraries = {{ - key.viLibrary->getHandle(), - m_vsLibrary->acquirePipelineHandle(key.args), - m_fsLibrary->acquirePipelineHandle(key.args), + key.viLibrary->getHandle(), vs.handle, fs.handle, key.foLibrary->getHandle(), }}; @@ -1248,13 +1250,14 @@ namespace dxvk { libInfo.pLibraries = libraries.data(); VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &libInfo }; + info.flags = vs.linkFlags | fs.linkFlags; info.layout = m_bindings->getPipelineLayout(true); info.basePipelineIndex = -1; VkPipeline pipeline = VK_NULL_HANDLE; 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)); return pipeline; diff --git a/src/dxvk/dxvk_shader.cpp b/src/dxvk/dxvk_shader.cpp index 2748bc17..aa378cb8 100644 --- a/src/dxvk/dxvk_shader.cpp +++ b/src/dxvk/dxvk_shader.cpp @@ -1042,18 +1042,18 @@ namespace dxvk { } - VkPipeline DxvkShaderPipelineLibrary::acquirePipelineHandle( + DxvkShaderPipelineLibraryHandle DxvkShaderPipelineLibrary::acquirePipelineHandle( const DxvkShaderPipelineLibraryCompileArgs& args) { std::lock_guard lock(m_mutex); if (m_device->mustTrackPipelineLifetime()) m_useCount += 1; - VkPipeline& pipeline = (m_shaders.vs && !args.depthClipEnable) + DxvkShaderPipelineLibraryHandle& pipeline = (m_shaders.vs && !args.depthClipEnable) ? m_pipelineNoDepthClip : m_pipeline; - if (pipeline) + if (pipeline.handle) return pipeline; pipeline = compileShaderPipelineLocked(args); @@ -1079,7 +1079,7 @@ namespace dxvk { return; // Compile the pipeline with default args - VkPipeline pipeline = compileShaderPipelineLocked( + DxvkShaderPipelineLibraryHandle pipeline = compileShaderPipelineLocked( DxvkShaderPipelineLibraryCompileArgs()); // On 32-bit, destroy the pipeline immediately in order to @@ -1087,9 +1087,9 @@ namespace dxvk { // we need to recreate the pipeline. if (m_device->mustTrackPipelineLifetime()) { 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 @@ -1100,34 +1100,34 @@ namespace dxvk { void DxvkShaderPipelineLibrary::destroyShaderPipelinesLocked() { auto vk = m_device->vkd(); - vk->vkDestroyPipeline(vk->device(), m_pipeline, nullptr); - vk->vkDestroyPipeline(vk->device(), m_pipelineNoDepthClip, nullptr); + vk->vkDestroyPipeline(vk->device(), m_pipeline.handle, nullptr); + vk->vkDestroyPipeline(vk->device(), m_pipelineNoDepthClip.handle, nullptr); - m_pipeline = VK_NULL_HANDLE; - m_pipelineNoDepthClip = VK_NULL_HANDLE; + m_pipeline.handle = VK_NULL_HANDLE; + m_pipelineNoDepthClip.handle = VK_NULL_HANDLE; } - VkPipeline DxvkShaderPipelineLibrary::compileShaderPipelineLocked( + DxvkShaderPipelineLibraryHandle DxvkShaderPipelineLibrary::compileShaderPipelineLocked( const DxvkShaderPipelineLibraryCompileArgs& args) { this->notifyLibraryCompile(); // If this is not the first time we're compiling the pipeline, // try to get a cache hit using the shader module identifier // 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()) { pipeline = this->compileShaderPipeline(args, VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT); } - if (!pipeline) + if (!pipeline.handle) pipeline = this->compileShaderPipeline(args, 0); // Well that didn't work - if (!pipeline) - return VK_NULL_HANDLE; + if (!pipeline.handle) + return { VK_NULL_HANDLE, 0 }; // Increment stat counter the first time this // shader pipeline gets compiled successfully @@ -1144,7 +1144,7 @@ namespace dxvk { } - VkPipeline DxvkShaderPipelineLibrary::compileShaderPipeline( + DxvkShaderPipelineLibraryHandle DxvkShaderPipelineLibrary::compileShaderPipeline( const DxvkShaderPipelineLibraryCompileArgs& args, VkPipelineCreateFlags flags) { DxvkShaderStageInfo stageInfo(m_device); @@ -1161,7 +1161,7 @@ namespace dxvk { // Fail if we have no idenfitier for whatever reason, caller // should fall back to the slow path if this happens if (!identifier->identifierSize) - return VK_NULL_HANDLE; + return { VK_NULL_HANDLE, 0 }; stageInfo.addStage(stage, *identifier, nullptr); } else { @@ -1178,17 +1178,17 @@ namespace dxvk { } } + VkPipeline pipeline = VK_NULL_HANDLE; + if (stageMask & VK_SHADER_STAGE_VERTEX_BIT) - return compileVertexShaderPipeline(args, stageInfo, flags); - - if (stageMask & VK_SHADER_STAGE_FRAGMENT_BIT) - return compileFragmentShaderPipeline(stageInfo, flags); - - if (stageMask & VK_SHADER_STAGE_COMPUTE_BIT) - return compileComputeShaderPipeline(stageInfo, flags); + pipeline = compileVertexShaderPipeline(args, stageInfo, flags); + else if (stageMask & VK_SHADER_STAGE_FRAGMENT_BIT) + pipeline = compileFragmentShaderPipeline(stageInfo, flags); + else if (stageMask & VK_SHADER_STAGE_COMPUTE_BIT) + pipeline = compileComputeShaderPipeline(stageInfo, flags); // Should be unreachable - return VK_NULL_HANDLE; + return { pipeline, flags }; } @@ -1266,7 +1266,7 @@ namespace dxvk { VkPipeline pipeline = VK_NULL_HANDLE; 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)); return vr ? VK_NULL_HANDLE : pipeline; @@ -1377,7 +1377,7 @@ namespace dxvk { VkPipeline pipeline = VK_NULL_HANDLE; 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)); return vr ? VK_NULL_HANDLE : pipeline; diff --git a/src/dxvk/dxvk_shader.h b/src/dxvk/dxvk_shader.h index bc138f27..8e21197c 100644 --- a/src/dxvk/dxvk_shader.h +++ b/src/dxvk/dxvk_shader.h @@ -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 * @@ -524,7 +535,7 @@ namespace dxvk { * \param [in] args Compile arguments * \returns Vulkan pipeline handle */ - VkPipeline acquirePipelineHandle( + DxvkShaderPipelineLibraryHandle acquirePipelineHandle( const DxvkShaderPipelineLibraryCompileArgs& args); /** @@ -552,21 +563,21 @@ namespace dxvk { DxvkShaderSet m_shaders; const DxvkBindingLayoutObjects* m_layout; - dxvk::mutex m_mutex; - VkPipeline m_pipeline = VK_NULL_HANDLE; - VkPipeline m_pipelineNoDepthClip = VK_NULL_HANDLE; - uint32_t m_useCount = 0u; - bool m_compiledOnce = false; + dxvk::mutex m_mutex; + DxvkShaderPipelineLibraryHandle m_pipeline = { VK_NULL_HANDLE, 0 }; + DxvkShaderPipelineLibraryHandle m_pipelineNoDepthClip = { VK_NULL_HANDLE, 0 }; + uint32_t m_useCount = 0u; + bool m_compiledOnce = false; - dxvk::mutex m_identifierMutex; - DxvkShaderIdentifierSet m_identifiers; + dxvk::mutex m_identifierMutex; + DxvkShaderIdentifierSet m_identifiers; void destroyShaderPipelinesLocked(); - VkPipeline compileShaderPipelineLocked( + DxvkShaderPipelineLibraryHandle compileShaderPipelineLocked( const DxvkShaderPipelineLibraryCompileArgs& args); - VkPipeline compileShaderPipeline( + DxvkShaderPipelineLibraryHandle compileShaderPipeline( const DxvkShaderPipelineLibraryCompileArgs& args, VkPipelineCreateFlags flags);