diff --git a/src/dxbc/dxbc_compiler.cpp b/src/dxbc/dxbc_compiler.cpp index e23db876f..061c68e73 100644 --- a/src/dxbc/dxbc_compiler.cpp +++ b/src/dxbc/dxbc_compiler.cpp @@ -183,6 +183,7 @@ namespace dxvk { m_version.shaderStage(), m_resourceSlots.size(), m_resourceSlots.data(), + m_interfaceSlots, m_module.compile()); } @@ -468,6 +469,9 @@ namespace dxvk { if (im == DxbcInterpolationMode::LinearSample || im == DxbcInterpolationMode::LinearNoPerspectiveSample) m_module.decorate(varId, spv::DecorationSample); + + // Declare the input slot as defined + m_interfaceSlots.inputSlots |= 1u << regIdx; } else if (sv != DxbcSystemValue::None) { // Add a new system value mapping if needed m_vMappings.push_back({ regIdx, regMask, sv }); @@ -498,6 +502,9 @@ namespace dxvk { m_entryPointInterfaces.push_back(varId); m_oRegs.at(regIdx) = varId; + + // Declare the output slot as defined + m_interfaceSlots.outputSlots |= 1u << regIdx; } diff --git a/src/dxbc/dxbc_compiler.h b/src/dxbc/dxbc_compiler.h index 1af4a4cc4..305b8b1ff 100644 --- a/src/dxbc/dxbc_compiler.h +++ b/src/dxbc/dxbc_compiler.h @@ -311,6 +311,11 @@ namespace dxvk { std::vector m_entryPointInterfaces; uint32_t m_entryPointId = 0; + //////////////////////////////////////////// + // Inter-stage shader interface slots. Also + // covers vertex input and fragment output. + DxvkInterfaceSlots m_interfaceSlots; + /////////////////////////////////// // Shader-specific data structures DxbcCompilerVsPart m_vs; diff --git a/src/dxgi/dxgi_presenter.cpp b/src/dxgi/dxgi_presenter.cpp index 74620ac9c..0f18b0bc2 100644 --- a/src/dxgi/dxgi_presenter.cpp +++ b/src/dxgi/dxgi_presenter.cpp @@ -438,7 +438,8 @@ namespace dxvk { // Create the actual shader module return m_device->createShader( VK_SHADER_STAGE_VERTEX_BIT, - 0, nullptr, module.compile()); + 0, nullptr, { 0u, 1u }, + module.compile()); } @@ -524,6 +525,7 @@ namespace dxvk { VK_SHADER_STAGE_FRAGMENT_BIT, resourceSlots.size(), resourceSlots.data(), + { 1u, 1u }, module.compile()); } diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 46b9cbe10..c97408619 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -463,9 +463,11 @@ namespace dxvk { uint32_t firstInstance) { this->commitGraphicsState(); - m_cmd->cmdDraw( - vertexCount, instanceCount, - firstVertex, firstInstance); + if (m_gpActivePipeline != VK_NULL_HANDLE) { + m_cmd->cmdDraw( + vertexCount, instanceCount, + firstVertex, firstInstance); + } } @@ -475,10 +477,12 @@ namespace dxvk { uint32_t stride) { this->commitGraphicsState(); - m_cmd->cmdDrawIndirect( - buffer.handle(), - buffer.offset(), - count, stride); + if (m_gpActivePipeline != VK_NULL_HANDLE) { + m_cmd->cmdDrawIndirect( + buffer.handle(), + buffer.offset(), + count, stride); + } } @@ -490,10 +494,12 @@ namespace dxvk { uint32_t firstInstance) { this->commitGraphicsState(); - m_cmd->cmdDrawIndexed( - indexCount, instanceCount, - firstIndex, vertexOffset, - firstInstance); + if (m_gpActivePipeline != VK_NULL_HANDLE) { + m_cmd->cmdDrawIndexed( + indexCount, instanceCount, + firstIndex, vertexOffset, + firstInstance); + } } @@ -503,10 +509,12 @@ namespace dxvk { uint32_t stride) { this->commitGraphicsState(); - m_cmd->cmdDrawIndexedIndirect( - buffer.handle(), - buffer.offset(), - count, stride); + if (m_gpActivePipeline != VK_NULL_HANDLE) { + m_cmd->cmdDrawIndexedIndirect( + buffer.handle(), + buffer.offset(), + count, stride); + } } @@ -997,8 +1005,14 @@ namespace dxvk { for (uint32_t i = m_state.gp.state.ilBindingCount; i < MaxNumVertexBindings; i++) m_state.gp.state.ilBindings[i].stride = 0; - m_cmd->cmdBindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, - m_state.gp.pipeline->getPipelineHandle(m_state.gp.state)); + m_gpActivePipeline = m_state.gp.pipeline + ->getPipelineHandle(m_state.gp.state); + + if (m_gpActivePipeline != VK_NULL_HANDLE) { + m_cmd->cmdBindPipeline( + VK_PIPELINE_BIND_POINT_GRAPHICS, + m_gpActivePipeline); + } } } diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index c9a8405f6..000399a6f 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -485,6 +485,9 @@ namespace dxvk { DxvkContextState m_state; DxvkBarrierSet m_barriers; + VkPipeline m_gpActivePipeline = VK_NULL_HANDLE; +// VkPipeline m_cpActivePipeline = VK_NULL_HANDLE; /* will be used later */ + std::array m_rc; std::array m_descriptors; diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index a3950de7c..cafb28874 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -152,9 +152,10 @@ namespace dxvk { VkShaderStageFlagBits stage, uint32_t slotCount, const DxvkResourceSlot* slotInfos, + const DxvkInterfaceSlots& iface, const SpirvCodeBuffer& code) { return new DxvkShader(stage, - slotCount, slotInfos, code); + slotCount, slotInfos, iface, code); } diff --git a/src/dxvk/dxvk_device.h b/src/dxvk/dxvk_device.h index 42680b82a..fc042d9f5 100644 --- a/src/dxvk/dxvk_device.h +++ b/src/dxvk/dxvk_device.h @@ -201,6 +201,9 @@ namespace dxvk { * \brief Creates a shader module * * \param [in] stage Shader stage + * \param [in] slotCount Resource slot count + * \param [in] slotInfos Resource slot descriptions + * \param [in] iface Inter-stage interface slots * \param [in] code Shader code * \returns New shader module */ @@ -208,6 +211,7 @@ namespace dxvk { VkShaderStageFlagBits stage, uint32_t slotCount, const DxvkResourceSlot* slotInfos, + const DxvkInterfaceSlots& iface, const SpirvCodeBuffer& code); /** diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index 077f11997..0f092778c 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -56,6 +56,9 @@ namespace dxvk { if (tes != nullptr) m_tes = tes->createShaderModule(vkd, slotMapping); if (gs != nullptr) m_gs = gs ->createShaderModule(vkd, slotMapping); if (fs != nullptr) m_fs = fs ->createShaderModule(vkd, slotMapping); + + m_vsIn = vs != nullptr ? vs->interfaceSlots().inputSlots : 0; + m_fsOut = fs != nullptr ? fs->interfaceSlots().outputSlots : 0; } @@ -73,7 +76,10 @@ namespace dxvk { return pair.pipeline; } - VkPipeline pipeline = this->compilePipeline(state, m_basePipeline); + VkPipeline pipeline = this->validatePipelineState(state) + ? this->compilePipeline(state, m_basePipeline) + : VK_NULL_HANDLE; + m_pipelines.push_back({ state, pipeline }); if (m_basePipeline == VK_NULL_HANDLE) @@ -234,4 +240,23 @@ namespace dxvk { m_vkd->vkDestroyPipeline(m_vkd->device(), pair.pipeline, nullptr); } + + bool DxvkGraphicsPipeline::validatePipelineState( + const DxvkGraphicsPipelineStateInfo& state) const { + // Validate vertex input - each input slot consumed by the + // vertex shader must be provided by the input layout. + uint32_t providedVertexInputs = 0; + + for (uint32_t i = 0; i < state.ilAttributeCount; i++) + providedVertexInputs |= 1u << state.ilAttributes[i].location; + + if ((providedVertexInputs & m_vsIn) != m_vsIn) { + Logger::err("DxvkGraphicsPipeline: Input layout mismatches vertex shader input"); + return false; + } + + // No errors + return true; + } + } \ No newline at end of file diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h index 8491b7644..d664d48c2 100644 --- a/src/dxvk/dxvk_graphics.h +++ b/src/dxvk/dxvk_graphics.h @@ -131,6 +131,9 @@ namespace dxvk { Rc m_gs; Rc m_fs; + uint32_t m_vsIn = 0; + uint32_t m_fsOut = 0; + std::mutex m_mutex; std::vector m_pipelines; @@ -139,8 +142,12 @@ namespace dxvk { VkPipeline compilePipeline( const DxvkGraphicsPipelineStateInfo& state, VkPipeline baseHandle) const; + void destroyPipelines(); + bool validatePipelineState( + const DxvkGraphicsPipelineStateInfo& state) const; + }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_shader.cpp b/src/dxvk/dxvk_shader.cpp index 4b5a1da05..91e1e683f 100644 --- a/src/dxvk/dxvk_shader.cpp +++ b/src/dxvk/dxvk_shader.cpp @@ -43,8 +43,9 @@ namespace dxvk { VkShaderStageFlagBits stage, uint32_t slotCount, const DxvkResourceSlot* slotInfos, + const DxvkInterfaceSlots& iface, const SpirvCodeBuffer& code) - : m_stage(stage), m_code(code) { + : m_stage(stage), m_code(code), m_interface(iface) { for (uint32_t i = 0; i < slotCount; i++) m_slots.push_back(slotInfos[i]); } diff --git a/src/dxvk/dxvk_shader.h b/src/dxvk/dxvk_shader.h index ae8821201..561e8ff83 100644 --- a/src/dxvk/dxvk_shader.h +++ b/src/dxvk/dxvk_shader.h @@ -9,6 +9,19 @@ namespace dxvk { + /** + * \brief Shader interface slots + * + * Stores a bit mask of which shader + * interface slots are defined. Used + * purely for validation purposes. + */ + struct DxvkInterfaceSlots { + uint32_t inputSlots = 0; + uint32_t outputSlots = 0; + }; + + /** * \brief Shader module object * @@ -70,6 +83,7 @@ namespace dxvk { VkShaderStageFlagBits stage, uint32_t slotCount, const DxvkResourceSlot* slotInfos, + const DxvkInterfaceSlots& iface, const SpirvCodeBuffer& code); ~DxvkShader(); @@ -96,6 +110,17 @@ namespace dxvk { const Rc& vkd, const DxvkDescriptorSlotMapping& mapping) const; + /** + * \brief Inter-stage interface slots + * + * Retrieves the input and output + * registers used by the shader. + * \returns Shader interface slots + */ + DxvkInterfaceSlots interfaceSlots() const { + return m_interface; + } + /** * \brief Dumps SPIR-V shader * @@ -118,6 +143,7 @@ namespace dxvk { SpirvCodeBuffer m_code; std::vector m_slots; + DxvkInterfaceSlots m_interface; };