LCOV - code coverage report
Current view: top level - source/renderer/backend/vulkan - PipelineState.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 1 185 0.5 %
Date: 2023-01-19 00:18:29 Functions: 2 11 18.2 %

          Line data    Source code
       1             : /* Copyright (C) 2023 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "PipelineState.h"
      21             : 
      22             : #include "lib/hash.h"
      23             : #include "ps/CLogger.h"
      24             : #include "ps/containers/StaticVector.h"
      25             : #include "renderer/backend/vulkan/Device.h"
      26             : #include "renderer/backend/vulkan/Framebuffer.h"
      27             : #include "renderer/backend/vulkan/Mapping.h"
      28             : #include "renderer/backend/vulkan/ShaderProgram.h"
      29             : #include "renderer/backend/vulkan/Utilities.h"
      30             : 
      31             : #include <algorithm>
      32             : 
      33             : namespace Renderer
      34             : {
      35             : 
      36             : namespace Backend
      37             : {
      38             : 
      39             : namespace Vulkan
      40             : {
      41             : 
      42             : namespace
      43             : {
      44             : 
      45           0 : VkStencilOpState MakeStencilOpState(const SStencilOpState& opState)
      46             : {
      47           0 :     VkStencilOpState result{};
      48           0 :     result.failOp = Mapping::FromStencilOp(opState.failOp);
      49           0 :     result.passOp = Mapping::FromStencilOp(opState.passOp);
      50           0 :     result.depthFailOp = Mapping::FromStencilOp(opState.depthFailOp);
      51           0 :     result.compareOp = Mapping::FromCompareOp(opState.compareOp);
      52           0 :     return result;
      53             : }
      54             : 
      55             : } // anonymous namespace
      56             : 
      57           0 : size_t CGraphicsPipelineState::CacheKeyHash::operator()(const CacheKey& cacheKey) const
      58             : {
      59           0 :     size_t seed = 0;
      60           0 :     hash_combine(seed, cacheKey.vertexInputLayoutUID);
      61           0 :     hash_combine(seed, cacheKey.framebufferUID);
      62           0 :     return seed;
      63             : }
      64             : 
      65           0 : bool CGraphicsPipelineState::CacheKeyEqual::operator()(const CacheKey& lhs, const CacheKey& rhs) const
      66             : {
      67             :     return
      68           0 :         lhs.vertexInputLayoutUID == rhs.vertexInputLayoutUID &&
      69           0 :         lhs.framebufferUID == rhs.framebufferUID;
      70             : }
      71             : 
      72             : // static
      73           0 : std::unique_ptr<CGraphicsPipelineState> CGraphicsPipelineState::Create(
      74             :     CDevice* device, const SGraphicsPipelineStateDesc& desc)
      75             : {
      76           0 :     ENSURE(desc.shaderProgram);
      77           0 :     std::unique_ptr<CGraphicsPipelineState> pipelineState{new CGraphicsPipelineState()};
      78           0 :     pipelineState->m_Device = device;
      79           0 :     pipelineState->m_Desc = desc;
      80           0 :     return pipelineState;
      81             : }
      82             : 
      83           0 : CGraphicsPipelineState::~CGraphicsPipelineState()
      84             : {
      85           0 :     for (const auto& it : m_PipelineMap)
      86             :     {
      87           0 :         if (it.second != VK_NULL_HANDLE)
      88           0 :             m_Device->ScheduleObjectToDestroy(
      89           0 :                 VK_OBJECT_TYPE_PIPELINE, it.second, VK_NULL_HANDLE);
      90             :     }
      91           0 : }
      92             : 
      93           0 : VkPipeline CGraphicsPipelineState::GetOrCreatePipeline(
      94             :     const CVertexInputLayout* vertexInputLayout, CFramebuffer* framebuffer)
      95             : {
      96           0 :     CShaderProgram* shaderProgram = m_Desc.shaderProgram->As<CShaderProgram>();
      97             : 
      98             :     const CacheKey cacheKey =
      99             :     {
     100           0 :         vertexInputLayout->GetUID(), framebuffer->GetUID()
     101           0 :     };
     102           0 :     auto it = m_PipelineMap.find(cacheKey);
     103           0 :     if (it != m_PipelineMap.end())
     104           0 :         return it->second;
     105             : 
     106           0 :     PS::StaticVector<VkVertexInputBindingDescription, 16> attributeBindings;
     107           0 :     PS::StaticVector<VkVertexInputAttributeDescription, 16> attributes;
     108             : 
     109           0 :     const VkPhysicalDeviceLimits& limits = m_Device->GetChoosenPhysicalDevice().properties.limits;
     110           0 :     const uint32_t maxVertexInputAttributes = limits.maxVertexInputAttributes;
     111           0 :     const uint32_t maxVertexInputAttributeOffset = limits.maxVertexInputAttributeOffset;
     112           0 :     for (const SVertexAttributeFormat& vertexAttributeFormat : vertexInputLayout->GetAttributes())
     113             :     {
     114           0 :         ENSURE(vertexAttributeFormat.bindingSlot < maxVertexInputAttributes);
     115           0 :         ENSURE(vertexAttributeFormat.offset < maxVertexInputAttributeOffset);
     116           0 :         const uint32_t streamLocation = shaderProgram->GetStreamLocation(vertexAttributeFormat.stream);
     117           0 :         if (streamLocation == std::numeric_limits<uint32_t>::max())
     118           0 :             continue;
     119           0 :         auto it = std::find_if(attributeBindings.begin(), attributeBindings.end(),
     120           0 :             [slot = vertexAttributeFormat.bindingSlot](const VkVertexInputBindingDescription& desc) -> bool
     121           0 :         {
     122           0 :             return desc.binding == slot;
     123           0 :         });
     124             :         const VkVertexInputBindingDescription desc{
     125           0 :             vertexAttributeFormat.bindingSlot,
     126           0 :             vertexAttributeFormat.stride,
     127           0 :             vertexAttributeFormat.rate == VertexAttributeRate::PER_INSTANCE
     128           0 :                 ? VK_VERTEX_INPUT_RATE_INSTANCE
     129           0 :                 : VK_VERTEX_INPUT_RATE_VERTEX };
     130           0 :         if (it == attributeBindings.end())
     131           0 :             attributeBindings.emplace_back(desc);
     132             :         else
     133             :         {
     134             :             // All attribute sharing the same binding slot should have the same description.
     135           0 :             ENSURE(desc.inputRate == it->inputRate && desc.stride == it->stride);
     136             :         }
     137           0 :         attributes.push_back({
     138             :             streamLocation,
     139           0 :             vertexAttributeFormat.bindingSlot,
     140           0 :             Mapping::FromFormat(vertexAttributeFormat.format),
     141           0 :             vertexAttributeFormat.offset
     142             :             });
     143             :     }
     144             : 
     145           0 :     VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo{};
     146           0 :     vertexInputCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
     147           0 :     vertexInputCreateInfo.vertexBindingDescriptionCount = std::size(attributeBindings);
     148           0 :     vertexInputCreateInfo.pVertexBindingDescriptions = attributeBindings.data();
     149           0 :     vertexInputCreateInfo.vertexAttributeDescriptionCount = std::size(attributes);
     150           0 :     vertexInputCreateInfo.pVertexAttributeDescriptions = attributes.data();
     151             : 
     152           0 :     VkPipelineInputAssemblyStateCreateInfo inputAssemblyCreateInfo{};
     153           0 :     inputAssemblyCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
     154           0 :     inputAssemblyCreateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
     155           0 :     inputAssemblyCreateInfo.primitiveRestartEnable = VK_FALSE;
     156             : 
     157             :     // We don't need to specify sizes for viewports and scissors as they're in
     158             :     // dynamic state.
     159           0 :     VkViewport viewport{};
     160           0 :     viewport.x = 0.0f;
     161           0 :     viewport.y = 0.0f;
     162           0 :     viewport.width = 0.0f;
     163           0 :     viewport.height = 0.0f;
     164           0 :     viewport.minDepth = 0.0f;
     165           0 :     viewport.maxDepth = 1.0f;
     166             : 
     167           0 :     VkRect2D scissor{};
     168             : 
     169           0 :     VkPipelineViewportStateCreateInfo viewportStateCreateInfo{};
     170           0 :     viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
     171           0 :     viewportStateCreateInfo.viewportCount = 1;
     172           0 :     viewportStateCreateInfo.pViewports = &viewport;
     173           0 :     viewportStateCreateInfo.scissorCount = 1;
     174           0 :     viewportStateCreateInfo.pScissors = &scissor;
     175             : 
     176           0 :     VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo{};
     177           0 :     depthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
     178           0 :     depthStencilStateCreateInfo.depthTestEnable =
     179           0 :         m_Desc.depthStencilState.depthTestEnabled ? VK_TRUE : VK_FALSE;
     180           0 :     depthStencilStateCreateInfo.depthWriteEnable =
     181           0 :         m_Desc.depthStencilState.depthWriteEnabled ? VK_TRUE : VK_FALSE;
     182           0 :     depthStencilStateCreateInfo.depthCompareOp =
     183           0 :         Mapping::FromCompareOp(m_Desc.depthStencilState.depthCompareOp);
     184           0 :     depthStencilStateCreateInfo.stencilTestEnable =
     185           0 :         m_Desc.depthStencilState.stencilTestEnabled ? VK_TRUE : VK_FALSE;
     186             : 
     187           0 :     depthStencilStateCreateInfo.front =
     188           0 :         MakeStencilOpState(m_Desc.depthStencilState.stencilFrontFace);
     189           0 :     depthStencilStateCreateInfo.front.reference = m_Desc.depthStencilState.stencilReference;
     190           0 :     depthStencilStateCreateInfo.front.compareMask = m_Desc.depthStencilState.stencilReadMask;
     191           0 :     depthStencilStateCreateInfo.front.writeMask = m_Desc.depthStencilState.stencilWriteMask;
     192             : 
     193           0 :     depthStencilStateCreateInfo.back =
     194           0 :         MakeStencilOpState(m_Desc.depthStencilState.stencilBackFace);
     195           0 :     depthStencilStateCreateInfo.back.reference = m_Desc.depthStencilState.stencilReference;
     196           0 :     depthStencilStateCreateInfo.back.compareMask = m_Desc.depthStencilState.stencilReadMask;
     197           0 :     depthStencilStateCreateInfo.back.writeMask = m_Desc.depthStencilState.stencilWriteMask;
     198             : 
     199           0 :     VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo{};
     200           0 :     rasterizationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
     201           0 :     rasterizationStateCreateInfo.depthClampEnable = VK_FALSE;
     202           0 :     rasterizationStateCreateInfo.rasterizerDiscardEnable = VK_FALSE;
     203             : 
     204           0 :     rasterizationStateCreateInfo.polygonMode =
     205           0 :         Mapping::FromPolygonMode(m_Desc.rasterizationState.polygonMode);
     206           0 :     rasterizationStateCreateInfo.cullMode =
     207           0 :         Mapping::FromCullMode(m_Desc.rasterizationState.cullMode);
     208           0 :     rasterizationStateCreateInfo.frontFace =
     209           0 :         m_Desc.rasterizationState.frontFace == FrontFace::CLOCKWISE
     210           0 :         ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE;
     211             : 
     212           0 :     rasterizationStateCreateInfo.depthBiasEnable =
     213           0 :         m_Desc.rasterizationState.depthBiasEnabled ? VK_TRUE : VK_FALSE;
     214           0 :     rasterizationStateCreateInfo.depthBiasConstantFactor =
     215           0 :         m_Desc.rasterizationState.depthBiasConstantFactor;
     216           0 :     rasterizationStateCreateInfo.depthBiasSlopeFactor =
     217           0 :         m_Desc.rasterizationState.depthBiasSlopeFactor;
     218           0 :     rasterizationStateCreateInfo.lineWidth = 1.0f;
     219             : 
     220           0 :     VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo{};
     221           0 :     multisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
     222           0 :     multisampleStateCreateInfo.rasterizationSamples =
     223           0 :         Mapping::FromSampleCount(framebuffer->GetSampleCount());
     224           0 :     multisampleStateCreateInfo.minSampleShading = 1.0f;
     225             : 
     226           0 :     VkPipelineColorBlendAttachmentState colorBlendAttachmentState{};
     227           0 :     colorBlendAttachmentState.blendEnable = m_Desc.blendState.enabled ? VK_TRUE : VK_FALSE;
     228           0 :     colorBlendAttachmentState.colorBlendOp =
     229           0 :         Mapping::FromBlendOp(m_Desc.blendState.colorBlendOp);
     230           0 :     colorBlendAttachmentState.srcColorBlendFactor =
     231           0 :         Mapping::FromBlendFactor(m_Desc.blendState.srcColorBlendFactor);
     232           0 :     colorBlendAttachmentState.dstColorBlendFactor =
     233           0 :         Mapping::FromBlendFactor(m_Desc.blendState.dstColorBlendFactor);
     234           0 :     colorBlendAttachmentState.alphaBlendOp =
     235           0 :         Mapping::FromBlendOp(m_Desc.blendState.alphaBlendOp);
     236           0 :     colorBlendAttachmentState.srcAlphaBlendFactor =
     237           0 :         Mapping::FromBlendFactor(m_Desc.blendState.srcAlphaBlendFactor);
     238           0 :     colorBlendAttachmentState.dstAlphaBlendFactor =
     239           0 :         Mapping::FromBlendFactor(m_Desc.blendState.dstAlphaBlendFactor);
     240           0 :     colorBlendAttachmentState.colorWriteMask =
     241           0 :         Mapping::FromColorWriteMask(m_Desc.blendState.colorWriteMask);
     242             : 
     243           0 :     VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo{};
     244           0 :     colorBlendStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
     245           0 :     colorBlendStateCreateInfo.logicOpEnable = VK_FALSE;
     246           0 :     colorBlendStateCreateInfo.logicOp = VK_LOGIC_OP_CLEAR;
     247           0 :     colorBlendStateCreateInfo.attachmentCount = 1;
     248           0 :     colorBlendStateCreateInfo.pAttachments = &colorBlendAttachmentState;
     249           0 :     colorBlendStateCreateInfo.blendConstants[0] = m_Desc.blendState.constant.r;
     250           0 :     colorBlendStateCreateInfo.blendConstants[1] = m_Desc.blendState.constant.g;
     251           0 :     colorBlendStateCreateInfo.blendConstants[2] = m_Desc.blendState.constant.b;
     252           0 :     colorBlendStateCreateInfo.blendConstants[3] = m_Desc.blendState.constant.a;
     253             : 
     254           0 :     const VkDynamicState dynamicStates[] =
     255             :     {
     256             :         VK_DYNAMIC_STATE_SCISSOR,
     257             :         VK_DYNAMIC_STATE_VIEWPORT
     258             :     };
     259             : 
     260           0 :     VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo{};
     261           0 :     dynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
     262           0 :     dynamicStateCreateInfo.dynamicStateCount = static_cast<uint32_t>(std::size(dynamicStates));
     263           0 :     dynamicStateCreateInfo.pDynamicStates = dynamicStates;
     264             : 
     265           0 :     VkGraphicsPipelineCreateInfo pipelineCreateInfo{};
     266           0 :     pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
     267             : 
     268           0 :     pipelineCreateInfo.stageCount = shaderProgram->GetStages().size();
     269           0 :     pipelineCreateInfo.pStages = shaderProgram->GetStages().data();
     270             : 
     271           0 :     pipelineCreateInfo.pVertexInputState = &vertexInputCreateInfo;
     272           0 :     pipelineCreateInfo.pInputAssemblyState = &inputAssemblyCreateInfo;
     273           0 :     pipelineCreateInfo.pViewportState = &viewportStateCreateInfo;
     274           0 :     pipelineCreateInfo.pRasterizationState = &rasterizationStateCreateInfo;
     275           0 :     pipelineCreateInfo.pMultisampleState = &multisampleStateCreateInfo;
     276             :     // If renderPass is not VK_NULL_HANDLE, the pipeline is being created with
     277             :     // fragment shader state, and subpass uses a depth/stencil attachment,
     278             :     // pDepthStencilState must be a not null pointer.
     279           0 :     if (framebuffer->GetDepthStencilAttachment())
     280           0 :         pipelineCreateInfo.pDepthStencilState = &depthStencilStateCreateInfo;
     281           0 :     pipelineCreateInfo.pColorBlendState = &colorBlendStateCreateInfo;
     282           0 :     pipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
     283             : 
     284           0 :     pipelineCreateInfo.layout = shaderProgram->GetPipelineLayout();
     285           0 :     pipelineCreateInfo.renderPass = framebuffer->GetRenderPass();
     286           0 :     pipelineCreateInfo.subpass = 0;
     287           0 :     pipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE;
     288           0 :     pipelineCreateInfo.basePipelineIndex = -1;
     289             : 
     290           0 :     VkPipeline pipeline = VK_NULL_HANDLE;
     291           0 :     ENSURE_VK_SUCCESS(vkCreateGraphicsPipelines(
     292             :         m_Device->GetVkDevice(), VK_NULL_HANDLE, 1, &pipelineCreateInfo, nullptr, &pipeline));
     293             : 
     294           0 :     m_PipelineMap[cacheKey] = pipeline;
     295             : 
     296           0 :     return pipeline;
     297             : }
     298             : 
     299           0 : IDevice* CGraphicsPipelineState::GetDevice()
     300             : {
     301           0 :     return m_Device;
     302             : }
     303             : 
     304             : } // namespace Vulkan
     305             : 
     306             : } // namespace Backend
     307             : 
     308           3 : } // namespace Renderer

Generated by: LCOV version 1.13