BsVulkanGpuPipelineState.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsVulkanGpuPipelineState.h"
  4. #include "BsVulkanDevice.h"
  5. #include "BsVulkanGpuProgram.h"
  6. #include "BsVulkanFramebuffer.h"
  7. #include "BsVulkanUtility.h"
  8. #include "BsVulkanRenderAPI.h"
  9. #include "BsVulkanGpuPipelineParamInfo.h"
  10. #include "BsVulkanVertexInputManager.h"
  11. #include "BsVulkanCommandBuffer.h"
  12. #include "BsRasterizerState.h"
  13. #include "BsDepthStencilState.h"
  14. #include "BsBlendState.h"
  15. #include "BsRenderStats.h"
  16. namespace bs { namespace ct
  17. {
  18. VulkanPipeline::VulkanPipeline(VulkanResourceManager* owner, VkPipeline pipeline,
  19. const std::array<bool, BS_MAX_MULTIPLE_RENDER_TARGETS>& colorReadOnly, bool depthStencilReadOnly)
  20. : VulkanResource(owner, true), mPipeline(pipeline), mReadOnlyColor(colorReadOnly)
  21. , mReadOnlyDepthStencil(depthStencilReadOnly)
  22. { }
  23. VulkanPipeline::VulkanPipeline(VulkanResourceManager* owner, VkPipeline pipeline)
  24. : VulkanResource(owner, true), mPipeline(pipeline), mReadOnlyColor(), mReadOnlyDepthStencil(false)
  25. { }
  26. VulkanPipeline::~VulkanPipeline()
  27. {
  28. vkDestroyPipeline(mOwner->getDevice().getLogical(), mPipeline, gVulkanAllocator);
  29. }
  30. VulkanGraphicsPipelineState::GpuPipelineKey::GpuPipelineKey(
  31. UINT32 framebufferId, UINT32 vertexInputId, bool readOnlyDepth, DrawOperationType drawOp)
  32. : framebufferId(framebufferId), vertexInputId(vertexInputId), readOnlyDepth(readOnlyDepth)
  33. , drawOp(drawOp)
  34. {
  35. }
  36. size_t VulkanGraphicsPipelineState::HashFunc::operator()(const GpuPipelineKey& key) const
  37. {
  38. size_t hash = 0;
  39. hash_combine(hash, key.framebufferId);
  40. hash_combine(hash, key.vertexInputId);
  41. hash_combine(hash, key.readOnlyDepth);
  42. hash_combine(hash, key.drawOp);
  43. return hash;
  44. }
  45. bool VulkanGraphicsPipelineState::EqualFunc::operator()(const GpuPipelineKey& a, const GpuPipelineKey& b) const
  46. {
  47. if (a.framebufferId != b.framebufferId)
  48. return false;
  49. if (a.vertexInputId != b.vertexInputId)
  50. return false;
  51. if (a.readOnlyDepth != b.readOnlyDepth)
  52. return false;
  53. if (a.drawOp != b.drawOp)
  54. return false;
  55. return true;
  56. }
  57. VulkanGraphicsPipelineState::VulkanGraphicsPipelineState(const PIPELINE_STATE_DESC& desc,
  58. GpuDeviceFlags deviceMask)
  59. :GraphicsPipelineState(desc, deviceMask), mScissorEnabled(false), mDeviceMask(deviceMask)
  60. {
  61. for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
  62. {
  63. mPerDeviceData[i].device = nullptr;
  64. mPerDeviceData[i].pipelineLayout = VK_NULL_HANDLE;
  65. }
  66. }
  67. VulkanGraphicsPipelineState::~VulkanGraphicsPipelineState()
  68. {
  69. for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
  70. {
  71. if (mPerDeviceData[i].device == nullptr)
  72. continue;
  73. for(auto& entry : mPerDeviceData[i].pipelines)
  74. entry.second->destroy();
  75. }
  76. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_PipelineState);
  77. }
  78. void VulkanGraphicsPipelineState::initialize()
  79. {
  80. Lock(mMutex);
  81. GraphicsPipelineState::initialize();
  82. std::pair<VkShaderStageFlagBits, GpuProgram*> stages[] =
  83. {
  84. { VK_SHADER_STAGE_VERTEX_BIT, mData.vertexProgram.get() },
  85. { VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, mData.hullProgram.get() },
  86. { VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, mData.domainProgram.get() },
  87. { VK_SHADER_STAGE_GEOMETRY_BIT, mData.geometryProgram.get() },
  88. { VK_SHADER_STAGE_FRAGMENT_BIT, mData.fragmentProgram.get() }
  89. };
  90. UINT32 stageOutputIdx = 0;
  91. UINT32 numStages = sizeof(stages) / sizeof(stages[0]);
  92. for(UINT32 i = 0; i < numStages; i++)
  93. {
  94. VulkanGpuProgram* program = static_cast<VulkanGpuProgram*>(stages[i].second);
  95. if (program == nullptr)
  96. continue;
  97. VkPipelineShaderStageCreateInfo& stageCI = mShaderStageInfos[stageOutputIdx];
  98. stageCI.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
  99. stageCI.pNext = nullptr;
  100. stageCI.flags = 0;
  101. stageCI.stage = stages[i].first;
  102. stageCI.module = VK_NULL_HANDLE;
  103. stageCI.pName = program->getProperties().getEntryPoint().c_str();
  104. stageCI.pSpecializationInfo = nullptr;
  105. stageOutputIdx++;
  106. }
  107. UINT32 numUsedStages = stageOutputIdx;
  108. bool tesselationEnabled = mData.hullProgram != nullptr && mData.domainProgram != nullptr;
  109. mInputAssemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
  110. mInputAssemblyInfo.pNext = nullptr;
  111. mInputAssemblyInfo.flags = 0;
  112. mInputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; // Assigned at runtime
  113. mInputAssemblyInfo.primitiveRestartEnable = false;
  114. mTesselationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
  115. mTesselationInfo.pNext = nullptr;
  116. mTesselationInfo.flags = 0;
  117. mTesselationInfo.patchControlPoints = 3; // Assigned at runtime
  118. mViewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
  119. mViewportInfo.pNext = nullptr;
  120. mViewportInfo.flags = 0;
  121. mViewportInfo.viewportCount = 1; // Spec says this need to be at least 1...
  122. mViewportInfo.scissorCount = 1;
  123. mViewportInfo.pViewports = nullptr; // Dynamic
  124. mViewportInfo.pScissors = nullptr; // Dynamic
  125. RasterizerState* rasterizerState = getRasterizerState().get();
  126. if (rasterizerState == nullptr)
  127. rasterizerState = RasterizerState::getDefault().get();
  128. BlendState* blendState = getBlendState().get();
  129. if (blendState == nullptr)
  130. blendState = BlendState::getDefault().get();
  131. DepthStencilState* depthStencilState = getDepthStencilState().get();
  132. if (depthStencilState == nullptr)
  133. depthStencilState = DepthStencilState::getDefault().get();
  134. const RasterizerProperties& rstProps = rasterizerState->getProperties();
  135. const BlendProperties& blendProps = blendState->getProperties();
  136. const DepthStencilProperties dsProps = depthStencilState->getProperties();
  137. mRasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
  138. mRasterizationInfo.pNext = nullptr;
  139. mRasterizationInfo.flags = 0;
  140. mRasterizationInfo.depthClampEnable = !rstProps.getDepthClipEnable();
  141. mRasterizationInfo.rasterizerDiscardEnable = VK_FALSE;
  142. mRasterizationInfo.polygonMode = VulkanUtility::getPolygonMode(rstProps.getPolygonMode());
  143. mRasterizationInfo.cullMode = VulkanUtility::getCullMode(rstProps.getCullMode());
  144. mRasterizationInfo.frontFace = VK_FRONT_FACE_CLOCKWISE;
  145. mRasterizationInfo.depthBiasEnable = rstProps.getDepthBias() != 0.0f;
  146. mRasterizationInfo.depthBiasConstantFactor = rstProps.getDepthBias();
  147. mRasterizationInfo.depthBiasSlopeFactor = rstProps.getSlopeScaledDepthBias();
  148. mRasterizationInfo.depthBiasClamp = mRasterizationInfo.depthClampEnable ? rstProps.getDepthBiasClamp() : 0.0f;
  149. mRasterizationInfo.lineWidth = 1.0f;
  150. mMultiSampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
  151. mMultiSampleInfo.pNext = nullptr;
  152. mMultiSampleInfo.flags = 0;
  153. mMultiSampleInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; // Assigned at runtime
  154. mMultiSampleInfo.sampleShadingEnable = VK_FALSE; // When enabled, perform shading per sample instead of per pixel (more expensive, essentially FSAA)
  155. mMultiSampleInfo.minSampleShading = 1.0f; // Minimum percent of samples to run full shading for when sampleShadingEnable is enabled (1.0f to run for all)
  156. mMultiSampleInfo.pSampleMask = nullptr; // Normally one bit for each sample: e.g. 0x0000000F to enable all samples in a 4-sample setup
  157. mMultiSampleInfo.alphaToCoverageEnable = blendProps.getAlphaToCoverageEnabled();
  158. mMultiSampleInfo.alphaToOneEnable = VK_FALSE;
  159. VkStencilOpState stencilFrontInfo;
  160. stencilFrontInfo.compareOp = VulkanUtility::getCompareOp(dsProps.getStencilFrontCompFunc());
  161. stencilFrontInfo.depthFailOp = VulkanUtility::getStencilOp(dsProps.getStencilFrontZFailOp());
  162. stencilFrontInfo.passOp = VulkanUtility::getStencilOp(dsProps.getStencilFrontPassOp());
  163. stencilFrontInfo.failOp = VulkanUtility::getStencilOp(dsProps.getStencilFrontFailOp());
  164. stencilFrontInfo.reference = 0; // Dynamic
  165. stencilFrontInfo.compareMask = (UINT32)dsProps.getStencilReadMask();
  166. stencilFrontInfo.writeMask = (UINT32)dsProps.getStencilWriteMask();
  167. VkStencilOpState stencilBackInfo;
  168. stencilBackInfo.compareOp = VulkanUtility::getCompareOp(dsProps.getStencilBackCompFunc());
  169. stencilBackInfo.depthFailOp = VulkanUtility::getStencilOp(dsProps.getStencilBackZFailOp());
  170. stencilBackInfo.passOp = VulkanUtility::getStencilOp(dsProps.getStencilBackPassOp());
  171. stencilBackInfo.failOp = VulkanUtility::getStencilOp(dsProps.getStencilBackFailOp());
  172. stencilBackInfo.reference = 0; // Dynamic
  173. stencilBackInfo.compareMask = (UINT32)dsProps.getStencilReadMask();
  174. stencilBackInfo.writeMask = (UINT32)dsProps.getStencilWriteMask();
  175. mDepthStencilInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
  176. mDepthStencilInfo.pNext = nullptr;
  177. mDepthStencilInfo.flags = 0;
  178. mDepthStencilInfo.depthBoundsTestEnable = false;
  179. mDepthStencilInfo.minDepthBounds = 0.0f;
  180. mDepthStencilInfo.maxDepthBounds = 1.0f;
  181. mDepthStencilInfo.depthTestEnable = dsProps.getDepthReadEnable();
  182. mDepthStencilInfo.depthWriteEnable = dsProps.getDepthWriteEnable();
  183. mDepthStencilInfo.depthCompareOp = VulkanUtility::getCompareOp(dsProps.getDepthComparisonFunc());
  184. mDepthStencilInfo.front = stencilFrontInfo;
  185. mDepthStencilInfo.back = stencilBackInfo;
  186. mDepthStencilInfo.stencilTestEnable = dsProps.getStencilEnable();
  187. for(UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
  188. {
  189. UINT32 rtIdx = 0;
  190. if (blendProps.getIndependantBlendEnable())
  191. rtIdx = i;
  192. VkPipelineColorBlendAttachmentState& blendState = mAttachmentBlendStates[i];
  193. blendState.blendEnable = blendProps.getBlendEnabled(rtIdx);
  194. blendState.colorBlendOp = VulkanUtility::getBlendOp(blendProps.getBlendOperation(rtIdx));
  195. blendState.srcColorBlendFactor = VulkanUtility::getBlendFactor(blendProps.getSrcBlend(rtIdx));
  196. blendState.dstColorBlendFactor = VulkanUtility::getBlendFactor(blendProps.getDstBlend(rtIdx));
  197. blendState.alphaBlendOp = VulkanUtility::getBlendOp(blendProps.getAlphaBlendOperation(rtIdx));
  198. blendState.srcAlphaBlendFactor = VulkanUtility::getBlendFactor(blendProps.getAlphaSrcBlend(rtIdx));
  199. blendState.dstAlphaBlendFactor = VulkanUtility::getBlendFactor(blendProps.getAlphaDstBlend(rtIdx));
  200. blendState.colorWriteMask = blendProps.getRenderTargetWriteMask(rtIdx) & 0xF;
  201. }
  202. mColorBlendStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
  203. mColorBlendStateInfo.pNext = nullptr;
  204. mColorBlendStateInfo.flags = 0;
  205. mColorBlendStateInfo.logicOpEnable = VK_FALSE;
  206. mColorBlendStateInfo.logicOp = VK_LOGIC_OP_NO_OP;
  207. mColorBlendStateInfo.attachmentCount = 0; // Assigned at runtime
  208. mColorBlendStateInfo.pAttachments = mAttachmentBlendStates;
  209. mColorBlendStateInfo.blendConstants[0] = 0.0f;
  210. mColorBlendStateInfo.blendConstants[1] = 0.0f;
  211. mColorBlendStateInfo.blendConstants[2] = 0.0f;
  212. mColorBlendStateInfo.blendConstants[3] = 0.0f;
  213. mDynamicStates[0] = VK_DYNAMIC_STATE_VIEWPORT;
  214. mDynamicStates[1] = VK_DYNAMIC_STATE_SCISSOR;
  215. mDynamicStates[2] = VK_DYNAMIC_STATE_STENCIL_REFERENCE;
  216. UINT32 numDynamicStates = sizeof(mDynamicStates) / sizeof(mDynamicStates[0]);
  217. assert(numDynamicStates == 3);
  218. mDynamicStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
  219. mDynamicStateInfo.pNext = nullptr;
  220. mDynamicStateInfo.flags = 0;
  221. mDynamicStateInfo.dynamicStateCount = numDynamicStates;
  222. mDynamicStateInfo.pDynamicStates = mDynamicStates;
  223. mPipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
  224. mPipelineInfo.pNext = nullptr;
  225. mPipelineInfo.flags = 0;
  226. mPipelineInfo.stageCount = numUsedStages;
  227. mPipelineInfo.pStages = mShaderStageInfos;
  228. mPipelineInfo.pVertexInputState = nullptr; // Assigned at runtime
  229. mPipelineInfo.pInputAssemblyState = &mInputAssemblyInfo;
  230. mPipelineInfo.pTessellationState = tesselationEnabled ? &mTesselationInfo : nullptr;
  231. mPipelineInfo.pViewportState = &mViewportInfo;
  232. mPipelineInfo.pRasterizationState = &mRasterizationInfo;
  233. mPipelineInfo.pMultisampleState = &mMultiSampleInfo;
  234. mPipelineInfo.pDepthStencilState = nullptr; // Assigned at runtime
  235. mPipelineInfo.pColorBlendState = nullptr; // Assigned at runtime
  236. mPipelineInfo.pDynamicState = &mDynamicStateInfo;
  237. mPipelineInfo.renderPass = VK_NULL_HANDLE; // Assigned at runtime
  238. mPipelineInfo.layout = VK_NULL_HANDLE; // Assigned at runtime
  239. mPipelineInfo.subpass = 0;
  240. mPipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
  241. mPipelineInfo.basePipelineIndex = -1;
  242. mScissorEnabled = rstProps.getScissorEnable();
  243. if(mData.vertexProgram != nullptr)
  244. mVertexDecl = mData.vertexProgram->getInputDeclaration();
  245. VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPI::instance());
  246. VulkanDevice* devices[BS_MAX_DEVICES];
  247. VulkanUtility::getDevices(rapi, mDeviceMask, devices);
  248. for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
  249. {
  250. if (devices[i] == nullptr)
  251. continue;
  252. mPerDeviceData[i].device = devices[i];
  253. VulkanDescriptorManager& descManager = mPerDeviceData[i].device->getDescriptorManager();
  254. VulkanGpuPipelineParamInfo& vkParamInfo = static_cast<VulkanGpuPipelineParamInfo&>(*mParamInfo);
  255. UINT32 numLayouts = vkParamInfo.getNumSets();
  256. VulkanDescriptorLayout** layouts = (VulkanDescriptorLayout**)bs_stack_alloc(sizeof(VulkanDescriptorLayout*) * numLayouts);
  257. for (UINT32 j = 0; j < numLayouts; j++)
  258. layouts[j] = vkParamInfo.getLayout(i, j);
  259. mPerDeviceData[i].pipelineLayout = descManager.getPipelineLayout(layouts, numLayouts);
  260. bs_stack_free(layouts);
  261. }
  262. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_PipelineState);
  263. }
  264. VulkanPipeline* VulkanGraphicsPipelineState::getPipeline(
  265. UINT32 deviceIdx, VulkanFramebuffer* framebuffer, bool readOnlyDepth, DrawOperationType drawOp,
  266. const SPtr<VulkanVertexInput>& vertexInput)
  267. {
  268. Lock(mMutex);
  269. if (mPerDeviceData[deviceIdx].device == nullptr)
  270. return nullptr;
  271. GpuPipelineKey key(framebuffer->getId(), vertexInput->getId(), readOnlyDepth, drawOp);
  272. PerDeviceData& perDeviceData = mPerDeviceData[deviceIdx];
  273. auto iterFind = perDeviceData.pipelines.find(key);
  274. if (iterFind != perDeviceData.pipelines.end())
  275. return iterFind->second;
  276. VulkanPipeline* newPipeline = createPipeline(deviceIdx, framebuffer, readOnlyDepth, drawOp, vertexInput);
  277. perDeviceData.pipelines[key] = newPipeline;
  278. return newPipeline;
  279. }
  280. VkPipelineLayout VulkanGraphicsPipelineState::getPipelineLayout(UINT32 deviceIdx) const
  281. {
  282. return mPerDeviceData[deviceIdx].pipelineLayout;
  283. }
  284. void VulkanGraphicsPipelineState::registerPipelineResources(VulkanCmdBuffer* cmdBuffer)
  285. {
  286. UINT32 deviceIdx = cmdBuffer->getDeviceIdx();
  287. std::array<VulkanGpuProgram*, 5> programs = {
  288. static_cast<VulkanGpuProgram*>(mData.vertexProgram.get()),
  289. static_cast<VulkanGpuProgram*>(mData.hullProgram.get()),
  290. static_cast<VulkanGpuProgram*>(mData.domainProgram.get()),
  291. static_cast<VulkanGpuProgram*>(mData.geometryProgram.get()),
  292. static_cast<VulkanGpuProgram*>(mData.fragmentProgram.get()),
  293. };
  294. for(auto& entry : programs)
  295. {
  296. if (entry != nullptr)
  297. {
  298. VulkanShaderModule* module = entry->getShaderModule(deviceIdx);
  299. if(module != nullptr)
  300. cmdBuffer->registerResource(module, VulkanUseFlag::Read);
  301. }
  302. }
  303. }
  304. VulkanPipeline* VulkanGraphicsPipelineState::createPipeline(UINT32 deviceIdx, VulkanFramebuffer* framebuffer,
  305. bool readOnlyDepth, DrawOperationType drawOp, const SPtr<VulkanVertexInput>& vertexInput)
  306. {
  307. mInputAssemblyInfo.topology = VulkanUtility::getDrawOp(drawOp);
  308. mTesselationInfo.patchControlPoints = 3; // Not provided by our shaders for now
  309. mMultiSampleInfo.rasterizationSamples = framebuffer->getSampleFlags();
  310. mColorBlendStateInfo.attachmentCount = framebuffer->getNumColorAttachments();
  311. DepthStencilState* dsState = getDepthStencilState().get();
  312. if (dsState == nullptr)
  313. dsState = DepthStencilState::getDefault().get();
  314. const DepthStencilProperties dsProps = dsState->getProperties();
  315. bool enableDepthWrites = dsProps.getDepthWriteEnable() && !readOnlyDepth;
  316. mDepthStencilInfo.depthWriteEnable = enableDepthWrites; // If depth stencil attachment is read only, depthWriteEnable must be VK_FALSE
  317. // Save stencil ops as we might need to change them if depth/stencil is read-only
  318. VkStencilOp oldFrontPassOp = mDepthStencilInfo.front.passOp;
  319. VkStencilOp oldFrontFailOp = mDepthStencilInfo.front.failOp;
  320. VkStencilOp oldFrontZFailOp = mDepthStencilInfo.front.depthFailOp;
  321. VkStencilOp oldBackPassOp = mDepthStencilInfo.back.passOp;
  322. VkStencilOp oldBackFailOp = mDepthStencilInfo.back.failOp;
  323. VkStencilOp oldBackZFailOp = mDepthStencilInfo.back.depthFailOp;
  324. if(readOnlyDepth)
  325. {
  326. // Disable any stencil writes
  327. mDepthStencilInfo.front.passOp = VK_STENCIL_OP_KEEP;
  328. mDepthStencilInfo.front.failOp = VK_STENCIL_OP_KEEP;
  329. mDepthStencilInfo.front.depthFailOp = VK_STENCIL_OP_KEEP;
  330. mDepthStencilInfo.back.passOp = VK_STENCIL_OP_KEEP;
  331. mDepthStencilInfo.back.failOp = VK_STENCIL_OP_KEEP;
  332. mDepthStencilInfo.back.depthFailOp = VK_STENCIL_OP_KEEP;
  333. }
  334. // Note: We can use the default render pass here (default clear/load/read flags), even though that might not be the
  335. // exact one currently bound. This is because load/store operations and layout transitions are allowed to differ
  336. // (as per spec 7.2., such render passes are considered compatible).
  337. mPipelineInfo.renderPass = framebuffer->getRenderPass(RT_NONE, RT_NONE, CLEAR_NONE);
  338. mPipelineInfo.layout = mPerDeviceData[deviceIdx].pipelineLayout;
  339. mPipelineInfo.pVertexInputState = vertexInput->getCreateInfo();
  340. bool depthStencilReadOnly;
  341. if (framebuffer->hasDepthAttachment())
  342. {
  343. mPipelineInfo.pDepthStencilState = &mDepthStencilInfo;
  344. depthStencilReadOnly = readOnlyDepth;
  345. }
  346. else
  347. {
  348. mPipelineInfo.pDepthStencilState = nullptr;
  349. depthStencilReadOnly = true;
  350. }
  351. std::array<bool, BS_MAX_MULTIPLE_RENDER_TARGETS> colorReadOnly;
  352. if (framebuffer->getNumColorAttachments() > 0)
  353. {
  354. mPipelineInfo.pColorBlendState = &mColorBlendStateInfo;
  355. for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
  356. {
  357. VkPipelineColorBlendAttachmentState& blendState = mAttachmentBlendStates[i];
  358. colorReadOnly[i] = blendState.colorWriteMask == 0;
  359. }
  360. }
  361. else
  362. {
  363. mPipelineInfo.pColorBlendState = nullptr;
  364. for (UINT32 i = 0; i < BS_MAX_MULTIPLE_RENDER_TARGETS; i++)
  365. {
  366. VkPipelineColorBlendAttachmentState& blendState = mAttachmentBlendStates[i];
  367. colorReadOnly[i] = true;
  368. }
  369. }
  370. std::pair<VkShaderStageFlagBits, GpuProgram*> stages[] =
  371. {
  372. { VK_SHADER_STAGE_VERTEX_BIT, mData.vertexProgram.get() },
  373. { VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, mData.hullProgram.get() },
  374. { VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, mData.domainProgram.get() },
  375. { VK_SHADER_STAGE_GEOMETRY_BIT, mData.geometryProgram.get() },
  376. { VK_SHADER_STAGE_FRAGMENT_BIT, mData.fragmentProgram.get() }
  377. };
  378. UINT32 stageOutputIdx = 0;
  379. UINT32 numStages = sizeof(stages) / sizeof(stages[0]);
  380. for (UINT32 i = 0; i < numStages; i++)
  381. {
  382. VulkanGpuProgram* program = static_cast<VulkanGpuProgram*>(stages[i].second);
  383. if (program == nullptr)
  384. continue;
  385. VkPipelineShaderStageCreateInfo& stageCI = mShaderStageInfos[stageOutputIdx];
  386. VulkanShaderModule* module = program->getShaderModule(deviceIdx);
  387. if (module != nullptr)
  388. stageCI.module = module->getHandle();
  389. else
  390. stageCI.module = VK_NULL_HANDLE;
  391. stageOutputIdx++;
  392. }
  393. VulkanDevice* device = mPerDeviceData[deviceIdx].device;
  394. VkDevice vkDevice = mPerDeviceData[deviceIdx].device->getLogical();
  395. VkPipeline pipeline;
  396. VkResult result = vkCreateGraphicsPipelines(vkDevice, VK_NULL_HANDLE, 1, &mPipelineInfo, gVulkanAllocator, &pipeline);
  397. assert(result == VK_SUCCESS);
  398. // Restore previous stencil op states
  399. mDepthStencilInfo.front.passOp = oldFrontPassOp;
  400. mDepthStencilInfo.front.failOp = oldFrontFailOp;
  401. mDepthStencilInfo.front.depthFailOp = oldFrontZFailOp;
  402. mDepthStencilInfo.back.passOp = oldBackPassOp;
  403. mDepthStencilInfo.back.failOp = oldBackFailOp;
  404. mDepthStencilInfo.back.depthFailOp = oldBackZFailOp;
  405. return device->getResourceManager().create<VulkanPipeline>(pipeline, colorReadOnly, depthStencilReadOnly);
  406. }
  407. VulkanComputePipelineState::VulkanComputePipelineState(const SPtr<GpuProgram>& program,
  408. GpuDeviceFlags deviceMask)
  409. :ComputePipelineState(program, deviceMask), mDeviceMask(deviceMask)
  410. {
  411. bs_zero_out(mPerDeviceData);
  412. }
  413. VulkanComputePipelineState::~VulkanComputePipelineState()
  414. {
  415. for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
  416. {
  417. if (mPerDeviceData[i].device == nullptr)
  418. continue;
  419. mPerDeviceData[i].pipeline->destroy();
  420. }
  421. }
  422. void VulkanComputePipelineState::initialize()
  423. {
  424. ComputePipelineState::initialize();
  425. // This might happen fairly often if shaders with unsupported languages are loaded, in which case the pipeline
  426. // will never get used, and its fine not to initialize it.
  427. if (!mProgram->isCompiled())
  428. return;
  429. VulkanGpuProgram* vkProgram = static_cast<VulkanGpuProgram*>(mProgram.get());
  430. VkPipelineShaderStageCreateInfo stageCI;
  431. stageCI.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
  432. stageCI.pNext = nullptr;
  433. stageCI.flags = 0;
  434. stageCI.stage = VK_SHADER_STAGE_COMPUTE_BIT;
  435. stageCI.module = VK_NULL_HANDLE;
  436. stageCI.pName = vkProgram->getProperties().getEntryPoint().c_str();
  437. stageCI.pSpecializationInfo = nullptr;
  438. VkComputePipelineCreateInfo pipelineCI;
  439. pipelineCI.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
  440. pipelineCI.pNext = nullptr;
  441. pipelineCI.flags = 0;
  442. pipelineCI.stage = stageCI;
  443. pipelineCI.basePipelineHandle = VK_NULL_HANDLE;
  444. pipelineCI.basePipelineIndex = -1;
  445. VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPI::instance());
  446. VulkanDevice* devices[BS_MAX_DEVICES];
  447. VulkanUtility::getDevices(rapi, mDeviceMask, devices);
  448. for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
  449. {
  450. if (devices[i] == nullptr)
  451. continue;
  452. mPerDeviceData[i].device = devices[i];
  453. VulkanDescriptorManager& descManager = devices[i]->getDescriptorManager();
  454. VulkanResourceManager& rescManager = devices[i]->getResourceManager();
  455. VulkanGpuPipelineParamInfo& vkParamInfo = static_cast<VulkanGpuPipelineParamInfo&>(*mParamInfo);
  456. UINT32 numLayouts = vkParamInfo.getNumSets();
  457. VulkanDescriptorLayout** layouts = (VulkanDescriptorLayout**)bs_stack_alloc(sizeof(VulkanDescriptorLayout*) * numLayouts);
  458. for (UINT32 j = 0; j < numLayouts; j++)
  459. layouts[j] = vkParamInfo.getLayout(i, j);
  460. VulkanShaderModule* module = vkProgram->getShaderModule(i);
  461. if (module != nullptr)
  462. pipelineCI.stage.module = module->getHandle();
  463. else
  464. pipelineCI.stage.module = VK_NULL_HANDLE;
  465. pipelineCI.layout = descManager.getPipelineLayout(layouts, numLayouts);
  466. VkPipeline pipeline;
  467. VkResult result = vkCreateComputePipelines(devices[i]->getLogical(), VK_NULL_HANDLE, 1, &pipelineCI,
  468. gVulkanAllocator, &pipeline);
  469. assert(result == VK_SUCCESS);
  470. mPerDeviceData[i].pipeline = rescManager.create<VulkanPipeline>(pipeline);
  471. mPerDeviceData[i].pipelineLayout = pipelineCI.layout;
  472. bs_stack_free(layouts);
  473. }
  474. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_PipelineState);
  475. }
  476. VulkanPipeline* VulkanComputePipelineState::getPipeline(UINT32 deviceIdx) const
  477. {
  478. return mPerDeviceData[deviceIdx].pipeline;
  479. }
  480. VkPipelineLayout VulkanComputePipelineState::getPipelineLayout(UINT32 deviceIdx) const
  481. {
  482. return mPerDeviceData[deviceIdx].pipelineLayout;
  483. }
  484. void VulkanComputePipelineState::registerPipelineResources(VulkanCmdBuffer* cmdBuffer)
  485. {
  486. UINT32 deviceIdx = cmdBuffer->getDeviceIdx();
  487. VulkanGpuProgram* program = static_cast<VulkanGpuProgram*>(mProgram.get());
  488. if(program != nullptr)
  489. {
  490. VulkanShaderModule* module = program->getShaderModule(deviceIdx);
  491. if (module != nullptr)
  492. cmdBuffer->registerResource(module, VulkanUseFlag::Read);
  493. }
  494. }
  495. }}