#pragma once #include #include "dxvk_bind_mask.h" #include "dxvk_constant_state.h" #include "dxvk_pipecache.h" #include "dxvk_pipelayout.h" #include "dxvk_renderpass.h" #include "dxvk_resource.h" #include "dxvk_shader.h" #include "dxvk_stats.h" namespace dxvk { class DxvkDevice; class DxvkPipelineManager; /** * \brief Flags that describe pipeline properties */ enum class DxvkGraphicsPipelineFlag { HasTransformFeedback, HasFsStorageDescriptors, HasVsStorageDescriptors, }; using DxvkGraphicsPipelineFlags = Flags; /** * \brief Shaders used in graphics pipelines */ struct DxvkGraphicsPipelineShaders { Rc vs; Rc tcs; Rc tes; Rc gs; Rc fs; }; /** * \brief Graphics pipeline state info * * Stores all information that is required to create * a graphics pipeline, except the shader objects * themselves. Also used to identify pipelines using * the current pipeline state vector. */ struct DxvkGraphicsPipelineStateInfo { DxvkGraphicsPipelineStateInfo(); DxvkGraphicsPipelineStateInfo( const DxvkGraphicsPipelineStateInfo& other); DxvkGraphicsPipelineStateInfo& operator = ( const DxvkGraphicsPipelineStateInfo& other); bool operator == (const DxvkGraphicsPipelineStateInfo& other) const; bool operator != (const DxvkGraphicsPipelineStateInfo& other) const; bool useDynamicStencilRef() const { return dsEnableStencilTest; } bool useDynamicDepthBias() const { return rsDepthBiasEnable; } bool useDynamicDepthBounds() const { return dsEnableDepthBoundsTest; } bool useDynamicBlendConstants() const { bool result = false; for (uint32_t i = 0; i < MaxNumRenderTargets && !result; i++) { result |= omBlendAttachments[i].blendEnable && (util::isBlendConstantBlendFactor(omBlendAttachments[i].srcColorBlendFactor) || util::isBlendConstantBlendFactor(omBlendAttachments[i].dstColorBlendFactor) || util::isBlendConstantBlendFactor(omBlendAttachments[i].srcAlphaBlendFactor) || util::isBlendConstantBlendFactor(omBlendAttachments[i].dstAlphaBlendFactor)); } return result; } DxvkBindingMask bsBindingMask; VkPrimitiveTopology iaPrimitiveTopology; VkBool32 iaPrimitiveRestart; uint32_t iaPatchVertexCount; uint32_t ilAttributeCount; uint32_t ilBindingCount; VkVertexInputAttributeDescription ilAttributes[DxvkLimits::MaxNumVertexAttributes]; VkVertexInputBindingDescription ilBindings[DxvkLimits::MaxNumVertexBindings]; uint32_t ilDivisors[DxvkLimits::MaxNumVertexBindings]; VkBool32 rsDepthClipEnable; VkBool32 rsDepthBiasEnable; VkPolygonMode rsPolygonMode; VkCullModeFlags rsCullMode; VkFrontFace rsFrontFace; uint32_t rsViewportCount; VkSampleCountFlags rsSampleCount; VkSampleCountFlags msSampleCount; uint32_t msSampleMask; VkBool32 msEnableAlphaToCoverage; VkBool32 dsEnableDepthTest; VkBool32 dsEnableDepthWrite; VkBool32 dsEnableDepthBoundsTest; VkBool32 dsEnableStencilTest; VkCompareOp dsDepthCompareOp; VkStencilOpState dsStencilOpFront; VkStencilOpState dsStencilOpBack; VkBool32 omEnableLogicOp; VkLogicOp omLogicOp; VkPipelineColorBlendAttachmentState omBlendAttachments[MaxNumRenderTargets]; VkComponentMapping omComponentMapping[MaxNumRenderTargets]; uint32_t scSpecConstants[MaxNumSpecConstants]; }; /** * \brief Common graphics pipeline state * * Non-dynamic pipeline state that cannot * be changed dynamically. */ struct DxvkGraphicsCommonPipelineStateInfo { bool msSampleShadingEnable; float msSampleShadingFactor; }; /** * \brief Graphics pipeline instance * * Stores a state vector and the * corresponding pipeline handle. */ class DxvkGraphicsPipelineInstance { public: DxvkGraphicsPipelineInstance() : m_stateVector (), m_renderPass (VK_NULL_HANDLE), m_pipeline (VK_NULL_HANDLE) { } DxvkGraphicsPipelineInstance( const DxvkGraphicsPipelineStateInfo& state, VkRenderPass rp, VkPipeline pipe) : m_stateVector (state), m_renderPass (rp), m_pipeline (pipe) { } /** * \brief Checks for matching pipeline state * * \param [in] stateVector Graphics pipeline state * \param [in] renderPass Render pass handle * \returns \c true if the specialization is compatible */ bool isCompatible( const DxvkGraphicsPipelineStateInfo& state, VkRenderPass rp) const { return m_stateVector == state && m_renderPass == rp; } /** * \brief Retrieves pipeline * \returns The pipeline handle */ VkPipeline pipeline() const { return m_pipeline; } private: DxvkGraphicsPipelineStateInfo m_stateVector; VkRenderPass m_renderPass; VkPipeline m_pipeline; }; /** * \brief Graphics pipeline * * Stores the pipeline layout as well as methods to * recompile the graphics pipeline against a given * pipeline state vector. */ class DxvkGraphicsPipeline { public: DxvkGraphicsPipeline( DxvkPipelineManager* pipeMgr, DxvkGraphicsPipelineShaders shaders); ~DxvkGraphicsPipeline(); /** * \brief Returns graphics pipeline flags * \returns Graphics pipeline property flags */ DxvkGraphicsPipelineFlags flags() const { return m_flags; } /** * \brief Pipeline layout * * Stores the pipeline layout and the descriptor set * layout, as well as information on the resource * slots used by the pipeline. * \returns Pipeline layout */ DxvkPipelineLayout* layout() const { return m_layout.ptr(); } /** * \brief Queries shader for a given stage * * In case no shader is specified for the * given stage, \c nullptr will be returned. * \param [in] stage The shader stage * \returns Shader of the given stage */ Rc getShader( VkShaderStageFlagBits stage) const; /** * \brief Pipeline handle * * Retrieves a pipeline handle for the given pipeline * state. If necessary, a new pipeline will be created. * \param [in] state Pipeline state vector * \param [in] renderPass The render pass * \returns Pipeline handle */ VkPipeline getPipelineHandle( const DxvkGraphicsPipelineStateInfo& state, const DxvkRenderPass& renderPass); private: struct PipelineStruct { DxvkGraphicsPipelineStateInfo stateVector; VkRenderPass renderPass; VkPipeline pipeline; }; Rc m_vkd; DxvkPipelineManager* m_pipeMgr; DxvkGraphicsPipelineShaders m_shaders; DxvkDescriptorSlotMapping m_slotMapping; Rc m_layout; uint32_t m_vsIn = 0; uint32_t m_fsOut = 0; DxvkGraphicsPipelineFlags m_flags; DxvkGraphicsCommonPipelineStateInfo m_common; // List of pipeline instances, shared between threads alignas(CACHE_LINE_SIZE) sync::Spinlock m_mutex; std::vector m_pipelines; const DxvkGraphicsPipelineInstance* findInstance( const DxvkGraphicsPipelineStateInfo& state, VkRenderPass renderPass) const; VkPipeline compilePipeline( const DxvkGraphicsPipelineStateInfo& state, const DxvkRenderPass& renderPass) const; void destroyPipeline( VkPipeline pipeline) const; DxvkShaderModule createShaderModule( const Rc& shader, const DxvkShaderModuleCreateInfo& info) const; bool validatePipelineState( const DxvkGraphicsPipelineStateInfo& state) const; void writePipelineStateToCache( const DxvkGraphicsPipelineStateInfo& state, const DxvkRenderPassFormat& format) const; void logPipelineState( LogLevel level, const DxvkGraphicsPipelineStateInfo& state) const; }; }