D3DGraphicsState.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Gr/D3D/D3DGraphicsState.h>
  6. #include <AnKi/Gr/BackendCommon/Functions.h>
  7. namespace anki {
  8. static void getVertexAttributeSemanticInfo(VertexAttributeSemantic x, const Char*& str, U32& idx)
  9. {
  10. switch(x)
  11. {
  12. case VertexAttributeSemantic::kPosition:
  13. str = "POSITION";
  14. idx = 0;
  15. break;
  16. case VertexAttributeSemantic::kNormal:
  17. str = "NORMAL";
  18. idx = 0;
  19. break;
  20. case VertexAttributeSemantic::kTexCoord:
  21. str = "TEX_COORD";
  22. idx = 0;
  23. break;
  24. case VertexAttributeSemantic::kColor:
  25. str = "COLOR";
  26. idx = 0;
  27. break;
  28. case VertexAttributeSemantic::kMisc0:
  29. str = "MISC";
  30. idx = 0;
  31. break;
  32. case VertexAttributeSemantic::kMisc1:
  33. str = "MISC";
  34. idx = 1;
  35. break;
  36. case VertexAttributeSemantic::kMisc2:
  37. str = "MISC";
  38. idx = 2;
  39. break;
  40. case VertexAttributeSemantic::kMisc3:
  41. str = "MISC";
  42. idx = 3;
  43. break;
  44. default:
  45. ANKI_ASSERT(0);
  46. };
  47. }
  48. Bool GraphicsStateTracker::updateHashes()
  49. {
  50. if(m_hashes.m_vert == 0)
  51. {
  52. if(m_state.m_vert.m_activeAttribs.getAnySet())
  53. {
  54. m_hashes.m_vert = 0xC0FEE;
  55. for(VertexAttributeSemantic i : EnumIterable<VertexAttributeSemantic>())
  56. {
  57. if(!m_state.m_vert.m_activeAttribs.get(i))
  58. {
  59. continue;
  60. }
  61. ANKI_ASSERT(m_state.m_vert.m_attribsSetMask.get(i) && "Forgot to set the vert attribute");
  62. m_hashes.m_vert = appendObjectHash(m_state.m_vert.m_attribs[i], m_hashes.m_vert);
  63. ANKI_ASSERT(m_state.m_vert.m_bindingsSetMask.get(m_state.m_vert.m_attribs[i].m_binding) && "Forgot to inform about the vert binding");
  64. m_hashes.m_vert = appendObjectHash(m_state.m_vert.m_bindings[m_state.m_vert.m_attribs[i].m_binding], m_hashes.m_vert);
  65. }
  66. }
  67. else
  68. {
  69. m_hashes.m_vert = 0xC0FEE;
  70. }
  71. }
  72. if(m_hashes.m_rast == 0)
  73. {
  74. m_hashes.m_rast = computeObjectHash(&m_state.m_rast);
  75. }
  76. if(m_hashes.m_depthStencil == 0)
  77. {
  78. const Bool hasStencil =
  79. m_state.m_misc.m_depthStencilFormat != Format::kNone && getFormatInfo(m_state.m_misc.m_depthStencilFormat).isStencil();
  80. const Bool hasDepth = m_state.m_misc.m_depthStencilFormat != Format::kNone && getFormatInfo(m_state.m_misc.m_depthStencilFormat).isDepth();
  81. m_hashes.m_depthStencil = 0xC0FEE;
  82. if(hasStencil)
  83. {
  84. m_hashes.m_depthStencil = appendObjectHash(m_state.m_stencil, m_hashes.m_depthStencil);
  85. }
  86. if(hasDepth)
  87. {
  88. m_hashes.m_depthStencil = appendObjectHash(m_state.m_depth, m_hashes.m_depthStencil);
  89. }
  90. }
  91. if(m_hashes.m_blend == 0)
  92. {
  93. if(m_state.m_misc.m_colorRtMask.getAnySet())
  94. {
  95. m_hashes.m_blend = m_state.m_blend.m_alphaToCoverage;
  96. for(U32 i = 0; i < kMaxColorRenderTargets; ++i)
  97. {
  98. if(m_state.m_misc.m_colorRtMask.get(i))
  99. {
  100. m_hashes.m_blend = appendObjectHash(m_state.m_blend.m_colorRts[i], m_hashes.m_blend);
  101. }
  102. }
  103. }
  104. else
  105. {
  106. m_hashes.m_blend = 0xC0FFE;
  107. }
  108. }
  109. if(m_hashes.m_misc == 0)
  110. {
  111. Array<U32, kMaxColorRenderTargets + 3> toHash;
  112. U32 toHashCount = 0;
  113. toHash[toHashCount++] = m_state.m_misc.m_colorRtMask.getData()[0];
  114. for(U32 i = 0; i < kMaxColorRenderTargets; ++i)
  115. {
  116. if(m_state.m_misc.m_colorRtMask.get(i))
  117. {
  118. toHash[toHashCount++] = U32(m_state.m_misc.m_colorRtFormats[i]);
  119. }
  120. }
  121. if(m_state.m_misc.m_depthStencilFormat != Format::kNone)
  122. {
  123. toHash[toHashCount++] = U32(m_state.m_misc.m_depthStencilFormat);
  124. }
  125. toHash[toHashCount++] = U32(m_state.m_misc.m_topology);
  126. m_hashes.m_misc = computeHash(toHash.getBegin(), sizeof(toHash[0]) * toHashCount);
  127. }
  128. if(m_hashes.m_shaderProg == 0)
  129. {
  130. m_hashes.m_shaderProg = m_state.m_shaderProg->getUuid();
  131. }
  132. // Compute complete hash
  133. const U64 globalHash = computeObjectHash(m_hashes);
  134. if(globalHash != m_globalHash)
  135. {
  136. m_globalHash = globalHash;
  137. return true;
  138. }
  139. else
  140. {
  141. return false;
  142. }
  143. }
  144. GraphicsPipelineFactory::~GraphicsPipelineFactory()
  145. {
  146. for(auto pso : m_map)
  147. {
  148. safeRelease(pso);
  149. }
  150. }
  151. void GraphicsPipelineFactory::flushState(GraphicsStateTracker& state, D3D12GraphicsCommandListX& cmdList)
  152. {
  153. // Set dynamic state
  154. if(state.m_dynState.m_stencilRefMaskDirty && state.m_state.m_misc.m_depthStencilFormat != Format::kNone
  155. && getFormatInfo(state.m_state.m_misc.m_depthStencilFormat).isStencil())
  156. {
  157. state.m_dynState.m_stencilRefMaskDirty = false;
  158. cmdList.OMSetStencilRef(state.m_dynState.m_stencilRefMask);
  159. }
  160. if(state.m_dynState.m_topologyDirty)
  161. {
  162. state.m_dynState.m_topologyDirty = false;
  163. cmdList.IASetPrimitiveTopology(convertPrimitiveTopology2(state.m_dynState.m_topology));
  164. }
  165. if(state.m_dynState.m_viewportDirty)
  166. {
  167. state.m_dynState.m_viewportDirty = false;
  168. const D3D12_VIEWPORT vp = {.TopLeftX = F32(state.m_dynState.m_viewport[0]),
  169. .TopLeftY = F32(state.m_dynState.m_viewport[1]),
  170. .Width = F32(state.m_dynState.m_viewport[2]),
  171. .Height = F32(state.m_dynState.m_viewport[3]),
  172. .MinDepth = 0.0f,
  173. .MaxDepth = 1.0f};
  174. cmdList.RSSetViewports(1, &vp);
  175. }
  176. if(state.m_dynState.m_scissorDirty)
  177. {
  178. state.m_dynState.m_scissorDirty = false;
  179. const U32 minx = max(state.m_dynState.m_scissor[0], state.m_dynState.m_viewport[0]);
  180. const U32 miny = max(state.m_dynState.m_scissor[1], state.m_dynState.m_viewport[1]);
  181. const U32 right =
  182. min(state.m_dynState.m_scissor[0] + state.m_dynState.m_scissor[2], state.m_dynState.m_viewport[0] + state.m_dynState.m_viewport[2]);
  183. const U32 bottom =
  184. min(state.m_dynState.m_scissor[1] + state.m_dynState.m_scissor[3], state.m_dynState.m_viewport[1] + state.m_dynState.m_viewport[3]);
  185. const D3D12_RECT rect = {.left = I32(minx), .top = I32(miny), .right = I32(right), .bottom = I32(bottom)};
  186. cmdList.RSSetScissorRects(1, &rect);
  187. }
  188. const Bool rebindPso = state.updateHashes();
  189. // Find the PSO
  190. ID3D12PipelineState* pso = nullptr;
  191. {
  192. RLockGuard lock(m_mtx);
  193. auto it = m_map.find(state.m_globalHash);
  194. if(it != m_map.getEnd())
  195. {
  196. pso = *it;
  197. }
  198. }
  199. if(pso) [[likely]]
  200. {
  201. if(rebindPso)
  202. {
  203. cmdList.SetPipelineState(pso);
  204. }
  205. return;
  206. }
  207. // PSO not found, proactively create it WITHOUT a lock (we dont't want to serialize pipeline creation)
  208. const ShaderProgramImpl& prog = *state.m_state.m_shaderProg;
  209. // Vertex input
  210. Array<D3D12_INPUT_ELEMENT_DESC, U32(VertexAttributeSemantic::kCount)> inputElementDescs;
  211. U32 inputElementDescCount = 0;
  212. for(VertexAttributeSemantic i : EnumIterable<VertexAttributeSemantic>())
  213. {
  214. if(state.m_state.m_vert.m_activeAttribs.get(i))
  215. {
  216. D3D12_INPUT_ELEMENT_DESC& elem = inputElementDescs[inputElementDescCount++];
  217. getVertexAttributeSemanticInfo(i, elem.SemanticName, elem.SemanticIndex);
  218. elem.Format = DXGI_FORMAT(state.m_state.m_vert.m_attribs[i].m_fmt);
  219. elem.InputSlot = state.m_state.m_vert.m_attribs[i].m_binding;
  220. elem.AlignedByteOffset = state.m_state.m_vert.m_attribs[i].m_relativeOffset;
  221. elem.InputSlotClass = (state.m_state.m_vert.m_bindings[state.m_state.m_vert.m_attribs[i].m_binding].m_stepRate == VertexStepRate::kVertex)
  222. ? D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA
  223. : D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
  224. elem.InstanceDataStepRate = (elem.InputSlotClass == D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA) ? 0 : 1;
  225. }
  226. }
  227. // Blending
  228. D3D12_BLEND_DESC blendDesc = {.AlphaToCoverageEnable = state.m_state.m_blend.m_alphaToCoverage, .IndependentBlendEnable = true};
  229. for(U32 i = 0; i < kMaxColorRenderTargets; ++i)
  230. {
  231. if(state.m_state.m_misc.m_colorRtMask.get(i))
  232. {
  233. const auto& in = state.m_state.m_blend.m_colorRts[i];
  234. D3D12_RENDER_TARGET_BLEND_DESC& out = blendDesc.RenderTarget[i];
  235. out.BlendEnable = blendingDisabled(in.m_srcRgb, in.m_dstRgb, in.m_srcA, in.m_dstA, in.m_funcRgb, in.m_funcA);
  236. out.SrcBlend = convertBlendFactor(in.m_srcRgb);
  237. out.DestBlend = convertBlendFactor(in.m_dstRgb);
  238. out.BlendOp = convertBlendOperation(in.m_funcRgb);
  239. out.SrcBlendAlpha = convertBlendFactor(in.m_srcA);
  240. out.DestBlendAlpha = convertBlendFactor(in.m_dstA);
  241. out.BlendOpAlpha = convertBlendOperation(in.m_funcA);
  242. out.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
  243. }
  244. }
  245. // DS
  246. D3D12_DEPTH_STENCIL_DESC2 dsDesc = {};
  247. if(state.m_state.m_misc.m_depthStencilFormat != Format::kNone)
  248. {
  249. const Bool stencilEnabled = !stencilTestDisabled(state.m_state.m_stencil.m_fail[0], state.m_state.m_stencil.m_stencilPassDepthFail[0],
  250. state.m_state.m_stencil.m_stencilPassDepthPass[0], state.m_state.m_stencil.m_compare[0])
  251. || !stencilTestDisabled(state.m_state.m_stencil.m_fail[1], state.m_state.m_stencil.m_stencilPassDepthFail[1],
  252. state.m_state.m_stencil.m_stencilPassDepthPass[1], state.m_state.m_stencil.m_compare[1]);
  253. Array<D3D12_DEPTH_STENCILOP_DESC1, 2> stencilDescs;
  254. for(U32 w = 0; w < 2; ++w)
  255. {
  256. stencilDescs[w].StencilFailOp = convertStencilOperation(state.m_state.m_stencil.m_fail[w]);
  257. stencilDescs[w].StencilDepthFailOp = convertStencilOperation(state.m_state.m_stencil.m_stencilPassDepthFail[w]);
  258. stencilDescs[w].StencilPassOp = convertStencilOperation(state.m_state.m_stencil.m_stencilPassDepthPass[w]);
  259. stencilDescs[w].StencilFunc = convertComparisonFunc(state.m_state.m_stencil.m_compare[w]);
  260. stencilDescs[w].StencilReadMask = U8(state.m_state.m_stencil.m_compareMask[w]);
  261. stencilDescs[w].StencilWriteMask = U8(state.m_state.m_stencil.m_writeMask[w]);
  262. }
  263. dsDesc = {.DepthEnable = state.m_state.m_depth.m_compare != CompareOperation::kAlways || state.m_state.m_depth.m_writeEnabled,
  264. .DepthWriteMask = state.m_state.m_depth.m_writeEnabled ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO,
  265. .DepthFunc = convertCompareOperation(state.m_state.m_depth.m_compare),
  266. .StencilEnable = stencilEnabled,
  267. .FrontFace = stencilDescs[0],
  268. .BackFace = stencilDescs[1],
  269. .DepthBoundsTestEnable = false};
  270. }
  271. // Rast state
  272. const D3D12_RASTERIZER_DESC2 rastDesc = {.FillMode = convertFillMode(state.m_state.m_rast.m_fillMode),
  273. .CullMode = convertCullMode(state.m_state.m_rast.m_cullMode),
  274. .FrontCounterClockwise = true,
  275. .DepthBias = state.m_state.m_rast.m_depthBias,
  276. .DepthBiasClamp = state.m_state.m_rast.m_depthBiasClamp,
  277. .SlopeScaledDepthBias = state.m_state.m_rast.m_slopeScaledDepthBias};
  278. // Misc
  279. D3D12_RT_FORMAT_ARRAY rtFormats = {};
  280. for(U32 i = 0; i < kMaxColorRenderTargets; ++i)
  281. {
  282. if(state.m_state.m_misc.m_colorRtMask.get(i))
  283. {
  284. rtFormats.RTFormats[i] = DXGI_FORMAT(state.m_state.m_misc.m_colorRtFormats[i]);
  285. rtFormats.NumRenderTargets = i + 1;
  286. }
  287. }
  288. const DXGI_SAMPLE_DESC sampleDesc = {.Count = 1, .Quality = 0};
  289. // Main descriptor
  290. #define ANKI_SET_IR(member, stage) \
  291. if(!!(prog.getShaderTypes() & ShaderTypeBit::stage)) \
  292. { \
  293. desc.member = prog.m_graphics.m_shaderCreateInfos[ShaderType::stage]; \
  294. }
  295. CD3DX12_PIPELINE_STATE_STREAM5 desc = {};
  296. desc.Flags = D3D12_PIPELINE_STATE_FLAG_DYNAMIC_DEPTH_BIAS;
  297. desc.pRootSignature = &state.m_state.m_shaderProg->m_rootSignature->getD3DRootSignature();
  298. desc.InputLayout = D3D12_INPUT_LAYOUT_DESC{.pInputElementDescs = inputElementDescs.getBegin(), .NumElements = inputElementDescCount};
  299. desc.PrimitiveTopologyType = convertPrimitiveTopology(state.m_state.m_misc.m_topology);
  300. ANKI_SET_IR(VS, kVertex)
  301. ANKI_SET_IR(GS, kGeometry)
  302. ANKI_SET_IR(HS, kTessellationControl)
  303. ANKI_SET_IR(DS, kTessellationEvaluation)
  304. ANKI_SET_IR(PS, kFragment)
  305. ANKI_SET_IR(AS, kTask)
  306. ANKI_SET_IR(MS, kMesh)
  307. desc.BlendState = CD3DX12_BLEND_DESC(blendDesc);
  308. desc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC2(dsDesc);
  309. desc.DSVFormat = DXGI_FORMAT(state.m_state.m_misc.m_depthStencilFormat);
  310. desc.RasterizerState = CD3DX12_RASTERIZER_DESC2(rastDesc);
  311. desc.RTVFormats = rtFormats;
  312. desc.SampleDesc = sampleDesc;
  313. desc.SampleMask = kMaxU32;
  314. #undef ANKI_SET_IR
  315. // Create the PSO
  316. const D3D12_PIPELINE_STATE_STREAM_DESC streamDec = {.SizeInBytes = sizeof(desc), .pPipelineStateSubobjectStream = &desc};
  317. ANKI_D3D_CHECKF(getDevice().CreatePipelineState(&streamDec, IID_PPV_ARGS(&pso)));
  318. // Now try to add the PSO to the hashmap
  319. {
  320. WLockGuard lock(m_mtx);
  321. auto it = m_map.find(state.m_globalHash);
  322. if(it == m_map.getEnd())
  323. {
  324. // Not found, add it
  325. m_map.emplace(state.m_globalHash, pso);
  326. }
  327. else
  328. {
  329. // Found, remove the PSO that was proactively created and use the old one
  330. safeRelease(pso);
  331. pso = *it;
  332. }
  333. }
  334. // Final thing, bind the PSO
  335. cmdList.SetPipelineState(pso);
  336. }
  337. } // end namespace anki