D3DState.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. // Copyright 2014 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "VideoBackends/D3D/D3DState.h"
  4. #include <algorithm>
  5. #include <array>
  6. #include <bit>
  7. #include "Common/Assert.h"
  8. #include "Common/CommonTypes.h"
  9. #include "Common/Logging/Log.h"
  10. #include "Common/MsgHandler.h"
  11. #include "VideoBackends/D3D/D3DBase.h"
  12. #include "VideoBackends/D3D/DXTexture.h"
  13. #include "VideoBackends/D3DCommon/D3DCommon.h"
  14. #include "VideoCommon/VideoConfig.h"
  15. namespace DX11
  16. {
  17. namespace D3D
  18. {
  19. std::unique_ptr<StateManager> stateman;
  20. StateManager::StateManager() = default;
  21. StateManager::~StateManager() = default;
  22. void StateManager::Apply()
  23. {
  24. if (m_dirtyFlags.none())
  25. return;
  26. // Framebuffer changes must occur before texture changes, otherwise the D3D runtime messes with
  27. // our bindings and sets them to null to prevent hazards.
  28. if (m_dirtyFlags.test(DirtyFlag_Framebuffer))
  29. {
  30. if (g_ActiveConfig.backend_info.bSupportsBBox)
  31. {
  32. D3D::context->OMSetRenderTargetsAndUnorderedAccessViews(
  33. m_pending.framebuffer->GetNumRTVs(),
  34. m_pending.use_integer_rtv ? m_pending.framebuffer->GetIntegerRTVArray() :
  35. m_pending.framebuffer->GetRTVArray(),
  36. m_pending.framebuffer->GetDSV(), m_pending.framebuffer->GetNumRTVs() + 1, 1,
  37. &m_pending.uav, nullptr);
  38. }
  39. else
  40. {
  41. D3D::context->OMSetRenderTargets(m_pending.framebuffer->GetNumRTVs(),
  42. m_pending.use_integer_rtv ?
  43. m_pending.framebuffer->GetIntegerRTVArray() :
  44. m_pending.framebuffer->GetRTVArray(),
  45. m_pending.framebuffer->GetDSV());
  46. }
  47. m_current.framebuffer = m_pending.framebuffer;
  48. m_current.uav = m_pending.uav;
  49. m_current.use_integer_rtv = m_pending.use_integer_rtv;
  50. }
  51. const bool dirtyConstants = m_dirtyFlags.test(DirtyFlag_PixelConstants) ||
  52. m_dirtyFlags.test(DirtyFlag_VertexConstants) ||
  53. m_dirtyFlags.test(DirtyFlag_GeometryConstants);
  54. const bool dirtyShaders = m_dirtyFlags.test(DirtyFlag_PixelShader) ||
  55. m_dirtyFlags.test(DirtyFlag_VertexShader) ||
  56. m_dirtyFlags.test(DirtyFlag_GeometryShader);
  57. const bool dirtyBuffers =
  58. m_dirtyFlags.test(DirtyFlag_VertexBuffer) || m_dirtyFlags.test(DirtyFlag_IndexBuffer);
  59. if (dirtyConstants)
  60. {
  61. if (m_current.pixelConstants[0] != m_pending.pixelConstants[0] ||
  62. m_current.pixelConstants[1] != m_pending.pixelConstants[1] ||
  63. m_current.pixelConstants[2] != m_pending.pixelConstants[2])
  64. {
  65. u32 count = 1;
  66. if (m_pending.pixelConstants[1])
  67. count++;
  68. if (m_pending.pixelConstants[2])
  69. count++;
  70. D3D::context->PSSetConstantBuffers(0, count, m_pending.pixelConstants.data());
  71. m_current.pixelConstants[0] = m_pending.pixelConstants[0];
  72. m_current.pixelConstants[1] = m_pending.pixelConstants[1];
  73. m_current.pixelConstants[2] = m_pending.pixelConstants[2];
  74. }
  75. if (m_current.vertexConstants != m_pending.vertexConstants)
  76. {
  77. D3D::context->VSSetConstantBuffers(0, 1, &m_pending.vertexConstants);
  78. D3D::context->VSSetConstantBuffers(1, 1, &m_pending.vertexConstants);
  79. m_current.vertexConstants = m_pending.vertexConstants;
  80. }
  81. if (m_current.geometryConstants != m_pending.geometryConstants)
  82. {
  83. D3D::context->GSSetConstantBuffers(0, 1, &m_pending.geometryConstants);
  84. m_current.geometryConstants = m_pending.geometryConstants;
  85. }
  86. }
  87. if (dirtyBuffers || (m_dirtyFlags.test(DirtyFlag_InputAssembler)))
  88. {
  89. if (m_current.vertexBuffer != m_pending.vertexBuffer ||
  90. m_current.vertexBufferStride != m_pending.vertexBufferStride ||
  91. m_current.vertexBufferOffset != m_pending.vertexBufferOffset)
  92. {
  93. D3D::context->IASetVertexBuffers(0, 1, &m_pending.vertexBuffer, &m_pending.vertexBufferStride,
  94. &m_pending.vertexBufferOffset);
  95. m_current.vertexBuffer = m_pending.vertexBuffer;
  96. m_current.vertexBufferStride = m_pending.vertexBufferStride;
  97. m_current.vertexBufferOffset = m_pending.vertexBufferOffset;
  98. }
  99. if (m_current.indexBuffer != m_pending.indexBuffer)
  100. {
  101. D3D::context->IASetIndexBuffer(m_pending.indexBuffer, DXGI_FORMAT_R16_UINT, 0);
  102. m_current.indexBuffer = m_pending.indexBuffer;
  103. }
  104. if (m_current.topology != m_pending.topology)
  105. {
  106. D3D::context->IASetPrimitiveTopology(m_pending.topology);
  107. m_current.topology = m_pending.topology;
  108. }
  109. if (m_current.inputLayout != m_pending.inputLayout)
  110. {
  111. D3D::context->IASetInputLayout(m_pending.inputLayout);
  112. m_current.inputLayout = m_pending.inputLayout;
  113. }
  114. }
  115. if (dirtyShaders)
  116. {
  117. if (m_current.pixelShader != m_pending.pixelShader)
  118. {
  119. D3D::context->PSSetShader(m_pending.pixelShader, nullptr, 0);
  120. m_current.pixelShader = m_pending.pixelShader;
  121. }
  122. if (m_current.vertexShader != m_pending.vertexShader)
  123. {
  124. D3D::context->VSSetShader(m_pending.vertexShader, nullptr, 0);
  125. m_current.vertexShader = m_pending.vertexShader;
  126. }
  127. if (m_current.geometryShader != m_pending.geometryShader)
  128. {
  129. D3D::context->GSSetShader(m_pending.geometryShader, nullptr, 0);
  130. m_current.geometryShader = m_pending.geometryShader;
  131. }
  132. }
  133. if (m_dirtyFlags.test(DirtyFlag_BlendState))
  134. {
  135. D3D::context->OMSetBlendState(m_pending.blendState, nullptr, 0xFFFFFFFF);
  136. m_current.blendState = m_pending.blendState;
  137. }
  138. if (m_dirtyFlags.test(DirtyFlag_DepthState))
  139. {
  140. D3D::context->OMSetDepthStencilState(m_pending.depthState, 0);
  141. m_current.depthState = m_pending.depthState;
  142. }
  143. if (m_dirtyFlags.test(DirtyFlag_RasterizerState))
  144. {
  145. D3D::context->RSSetState(m_pending.rasterizerState);
  146. m_current.rasterizerState = m_pending.rasterizerState;
  147. }
  148. ApplyTextures();
  149. m_dirtyFlags = 0;
  150. }
  151. void StateManager::ApplyTextures()
  152. {
  153. for (u32 i = 0; i < VideoCommon::MAX_PIXEL_SHADER_SAMPLERS; i++)
  154. {
  155. const u32 flag = i;
  156. if (m_dirtyFlags.test(flag))
  157. {
  158. if (m_current.textures[i] != m_pending.textures[i])
  159. {
  160. D3D::context->PSSetShaderResources(i, 1, &m_pending.textures[i]);
  161. m_current.textures[i] = m_pending.textures[i];
  162. }
  163. m_dirtyFlags.reset(flag);
  164. }
  165. }
  166. for (u32 i = 0; i < VideoCommon::MAX_PIXEL_SHADER_SAMPLERS; i++)
  167. {
  168. const u32 flag = i + VideoCommon::MAX_PIXEL_SHADER_SAMPLERS;
  169. if (m_dirtyFlags.test(flag))
  170. {
  171. if (m_current.samplers[i] != m_pending.samplers[i])
  172. {
  173. D3D::context->PSSetSamplers(i, 1, &m_pending.samplers[i]);
  174. m_current.samplers[i] = m_pending.samplers[i];
  175. }
  176. m_dirtyFlags.reset(flag);
  177. }
  178. }
  179. }
  180. u32 StateManager::UnsetTexture(ID3D11ShaderResourceView* srv)
  181. {
  182. u32 mask = 0;
  183. for (u32 index = 0; index < VideoCommon::MAX_PIXEL_SHADER_SAMPLERS; ++index)
  184. {
  185. if (m_current.textures[index] == srv)
  186. {
  187. SetTexture(index, nullptr);
  188. mask |= 1 << index;
  189. }
  190. }
  191. return mask;
  192. }
  193. void StateManager::SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceView* srv)
  194. {
  195. while (textureSlotMask)
  196. {
  197. const int index = std::countr_zero(textureSlotMask);
  198. SetTexture(index, srv);
  199. textureSlotMask &= ~(1 << index);
  200. }
  201. }
  202. void StateManager::SetComputeUAV(u32 index, ID3D11UnorderedAccessView* uav)
  203. {
  204. if (m_compute_images[index] == uav)
  205. return;
  206. m_compute_images[index] = uav;
  207. D3D::context->CSSetUnorderedAccessViews(0, static_cast<u32>(m_compute_images.size()),
  208. m_compute_images.data(), nullptr);
  209. }
  210. void StateManager::SetComputeShader(ID3D11ComputeShader* shader)
  211. {
  212. if (m_compute_shader == shader)
  213. return;
  214. m_compute_shader = shader;
  215. D3D::context->CSSetShader(shader, nullptr, 0);
  216. }
  217. void StateManager::SyncComputeBindings()
  218. {
  219. if (m_compute_constants != m_pending.pixelConstants[0])
  220. {
  221. m_compute_constants = m_pending.pixelConstants[0];
  222. D3D::context->CSSetConstantBuffers(0, 1, &m_compute_constants);
  223. }
  224. for (u32 start = 0; start < static_cast<u32>(m_compute_textures.size());)
  225. {
  226. if (m_compute_textures[start] == m_pending.textures[start])
  227. {
  228. start++;
  229. continue;
  230. }
  231. m_compute_textures[start] = m_pending.textures[start];
  232. u32 end = start + 1;
  233. for (; end < static_cast<u32>(m_compute_textures.size()); end++)
  234. {
  235. if (m_compute_textures[end] == m_pending.textures[end])
  236. break;
  237. m_compute_textures[end] = m_pending.textures[end];
  238. }
  239. D3D::context->CSSetShaderResources(start, end - start, &m_compute_textures[start]);
  240. start = end;
  241. }
  242. for (u32 start = 0; start < static_cast<u32>(m_compute_samplers.size());)
  243. {
  244. if (m_compute_samplers[start] == m_pending.samplers[start])
  245. {
  246. start++;
  247. continue;
  248. }
  249. m_compute_samplers[start] = m_pending.samplers[start];
  250. u32 end = start + 1;
  251. for (; end < static_cast<u32>(m_compute_samplers.size()); end++)
  252. {
  253. if (m_compute_samplers[end] == m_pending.samplers[end])
  254. break;
  255. m_compute_samplers[end] = m_pending.samplers[end];
  256. }
  257. D3D::context->CSSetSamplers(start, end - start, &m_compute_samplers[start]);
  258. start = end;
  259. }
  260. }
  261. } // namespace D3D
  262. StateCache::~StateCache() = default;
  263. ID3D11SamplerState* StateCache::Get(SamplerState state)
  264. {
  265. std::lock_guard<std::mutex> guard(m_lock);
  266. auto it = m_sampler.find(state);
  267. if (it != m_sampler.end())
  268. return it->second.Get();
  269. D3D11_SAMPLER_DESC sampdc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
  270. if (state.tm0.mipmap_filter == FilterMode::Linear)
  271. {
  272. if (state.tm0.min_filter == FilterMode::Linear)
  273. sampdc.Filter = (state.tm0.mag_filter == FilterMode::Linear) ?
  274. D3D11_FILTER_MIN_MAG_MIP_LINEAR :
  275. D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
  276. else
  277. sampdc.Filter = (state.tm0.mag_filter == FilterMode::Linear) ?
  278. D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR :
  279. D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR;
  280. }
  281. else
  282. {
  283. if (state.tm0.min_filter == FilterMode::Linear)
  284. sampdc.Filter = (state.tm0.mag_filter == FilterMode::Linear) ?
  285. D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT :
  286. D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
  287. else
  288. sampdc.Filter = (state.tm0.mag_filter == FilterMode::Linear) ?
  289. D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT :
  290. D3D11_FILTER_MIN_MAG_MIP_POINT;
  291. }
  292. static constexpr std::array<D3D11_TEXTURE_ADDRESS_MODE, 3> address_modes = {
  293. {D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_WRAP, D3D11_TEXTURE_ADDRESS_MIRROR}};
  294. sampdc.AddressU = address_modes[static_cast<u32>(state.tm0.wrap_u.Value())];
  295. sampdc.AddressV = address_modes[static_cast<u32>(state.tm0.wrap_v.Value())];
  296. sampdc.MaxLOD = state.tm1.max_lod / 16.f;
  297. sampdc.MinLOD = state.tm1.min_lod / 16.f;
  298. sampdc.MipLODBias = state.tm0.lod_bias / 256.f;
  299. if (state.tm0.anisotropic_filtering)
  300. {
  301. sampdc.Filter = D3D11_FILTER_ANISOTROPIC;
  302. sampdc.MaxAnisotropy = 1u << g_ActiveConfig.iMaxAnisotropy;
  303. }
  304. ComPtr<ID3D11SamplerState> res;
  305. HRESULT hr = D3D::device->CreateSamplerState(&sampdc, res.GetAddressOf());
  306. ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating D3D sampler state failed: {}", DX11HRWrap(hr));
  307. return m_sampler.emplace(state, std::move(res)).first->second.Get();
  308. }
  309. ID3D11BlendState* StateCache::Get(BlendingState state)
  310. {
  311. std::lock_guard<std::mutex> guard(m_lock);
  312. auto it = m_blend.find(state.hex);
  313. if (it != m_blend.end())
  314. return it->second.Get();
  315. if (state.logicopenable && g_ActiveConfig.backend_info.bSupportsLogicOp)
  316. {
  317. D3D11_BLEND_DESC1 desc = {};
  318. D3D11_RENDER_TARGET_BLEND_DESC1& tdesc = desc.RenderTarget[0];
  319. if (state.colorupdate)
  320. tdesc.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN |
  321. D3D11_COLOR_WRITE_ENABLE_BLUE;
  322. else
  323. tdesc.RenderTargetWriteMask = 0;
  324. if (state.alphaupdate)
  325. tdesc.RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_ALPHA;
  326. static constexpr std::array<D3D11_LOGIC_OP, 16> logic_ops = {
  327. {D3D11_LOGIC_OP_CLEAR, D3D11_LOGIC_OP_AND, D3D11_LOGIC_OP_AND_REVERSE, D3D11_LOGIC_OP_COPY,
  328. D3D11_LOGIC_OP_AND_INVERTED, D3D11_LOGIC_OP_NOOP, D3D11_LOGIC_OP_XOR, D3D11_LOGIC_OP_OR,
  329. D3D11_LOGIC_OP_NOR, D3D11_LOGIC_OP_EQUIV, D3D11_LOGIC_OP_INVERT, D3D11_LOGIC_OP_OR_REVERSE,
  330. D3D11_LOGIC_OP_COPY_INVERTED, D3D11_LOGIC_OP_OR_INVERTED, D3D11_LOGIC_OP_NAND,
  331. D3D11_LOGIC_OP_SET}};
  332. tdesc.LogicOpEnable = TRUE;
  333. tdesc.LogicOp = logic_ops[u32(state.logicmode.Value())];
  334. ComPtr<ID3D11BlendState1> res;
  335. HRESULT hr = D3D::device1->CreateBlendState1(&desc, res.GetAddressOf());
  336. if (SUCCEEDED(hr))
  337. {
  338. return m_blend.emplace(state.hex, std::move(res)).first->second.Get();
  339. }
  340. WARN_LOG_FMT(VIDEO, "Creating D3D blend state failed with an error: {}", DX11HRWrap(hr));
  341. }
  342. D3D11_BLEND_DESC desc = {};
  343. desc.AlphaToCoverageEnable = FALSE;
  344. desc.IndependentBlendEnable = FALSE;
  345. D3D11_RENDER_TARGET_BLEND_DESC& tdesc = desc.RenderTarget[0];
  346. tdesc.BlendEnable = state.blendenable;
  347. if (state.colorupdate)
  348. tdesc.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN |
  349. D3D11_COLOR_WRITE_ENABLE_BLUE;
  350. else
  351. tdesc.RenderTargetWriteMask = 0;
  352. if (state.alphaupdate)
  353. tdesc.RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_ALPHA;
  354. const bool use_dual_source = state.usedualsrc;
  355. const std::array<D3D11_BLEND, 8> src_factors = {
  356. {D3D11_BLEND_ZERO, D3D11_BLEND_ONE, D3D11_BLEND_DEST_COLOR, D3D11_BLEND_INV_DEST_COLOR,
  357. use_dual_source ? D3D11_BLEND_SRC1_ALPHA : D3D11_BLEND_SRC_ALPHA,
  358. use_dual_source ? D3D11_BLEND_INV_SRC1_ALPHA : D3D11_BLEND_INV_SRC_ALPHA,
  359. D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_INV_DEST_ALPHA}};
  360. const std::array<D3D11_BLEND, 8> dst_factors = {
  361. {D3D11_BLEND_ZERO, D3D11_BLEND_ONE, D3D11_BLEND_SRC_COLOR, D3D11_BLEND_INV_SRC_COLOR,
  362. use_dual_source ? D3D11_BLEND_SRC1_ALPHA : D3D11_BLEND_SRC_ALPHA,
  363. use_dual_source ? D3D11_BLEND_INV_SRC1_ALPHA : D3D11_BLEND_INV_SRC_ALPHA,
  364. D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_INV_DEST_ALPHA}};
  365. tdesc.SrcBlend = src_factors[u32(state.srcfactor.Value())];
  366. tdesc.SrcBlendAlpha = src_factors[u32(state.srcfactoralpha.Value())];
  367. tdesc.DestBlend = dst_factors[u32(state.dstfactor.Value())];
  368. tdesc.DestBlendAlpha = dst_factors[u32(state.dstfactoralpha.Value())];
  369. tdesc.BlendOp = state.subtract ? D3D11_BLEND_OP_REV_SUBTRACT : D3D11_BLEND_OP_ADD;
  370. tdesc.BlendOpAlpha = state.subtractAlpha ? D3D11_BLEND_OP_REV_SUBTRACT : D3D11_BLEND_OP_ADD;
  371. ComPtr<ID3D11BlendState> res;
  372. HRESULT hr = D3D::device->CreateBlendState(&desc, res.GetAddressOf());
  373. ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating D3D blend state failed: {}", DX11HRWrap(hr));
  374. return m_blend.emplace(state.hex, std::move(res)).first->second.Get();
  375. }
  376. ID3D11RasterizerState* StateCache::Get(RasterizationState state)
  377. {
  378. std::lock_guard<std::mutex> guard(m_lock);
  379. auto it = m_raster.find(state.hex);
  380. if (it != m_raster.end())
  381. return it->second.Get();
  382. static constexpr std::array<D3D11_CULL_MODE, 4> cull_modes = {
  383. {D3D11_CULL_NONE, D3D11_CULL_BACK, D3D11_CULL_FRONT, D3D11_CULL_BACK}};
  384. D3D11_RASTERIZER_DESC desc = {};
  385. desc.FillMode = D3D11_FILL_SOLID;
  386. desc.CullMode = cull_modes[u32(state.cullmode.Value())];
  387. desc.ScissorEnable = TRUE;
  388. ComPtr<ID3D11RasterizerState> res;
  389. HRESULT hr = D3D::device->CreateRasterizerState(&desc, res.GetAddressOf());
  390. ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating D3D rasterizer state failed: {}", DX11HRWrap(hr));
  391. return m_raster.emplace(state.hex, std::move(res)).first->second.Get();
  392. }
  393. ID3D11DepthStencilState* StateCache::Get(DepthState state)
  394. {
  395. std::lock_guard<std::mutex> guard(m_lock);
  396. auto it = m_depth.find(state.hex);
  397. if (it != m_depth.end())
  398. return it->second.Get();
  399. D3D11_DEPTH_STENCIL_DESC depthdc = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT());
  400. depthdc.DepthEnable = TRUE;
  401. depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
  402. depthdc.DepthFunc = D3D11_COMPARISON_GREATER;
  403. depthdc.StencilEnable = FALSE;
  404. depthdc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
  405. depthdc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
  406. // Less/greater are swapped due to inverted depth.
  407. const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] = {
  408. D3D11_COMPARISON_NEVER, D3D11_COMPARISON_GREATER, D3D11_COMPARISON_EQUAL,
  409. D3D11_COMPARISON_GREATER_EQUAL, D3D11_COMPARISON_LESS, D3D11_COMPARISON_NOT_EQUAL,
  410. D3D11_COMPARISON_LESS_EQUAL, D3D11_COMPARISON_ALWAYS};
  411. if (state.testenable)
  412. {
  413. depthdc.DepthEnable = TRUE;
  414. depthdc.DepthWriteMask =
  415. state.updateenable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
  416. depthdc.DepthFunc = d3dCmpFuncs[u32(state.func.Value())];
  417. }
  418. else
  419. {
  420. // if the test is disabled write is disabled too
  421. depthdc.DepthEnable = FALSE;
  422. depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
  423. }
  424. ComPtr<ID3D11DepthStencilState> res;
  425. HRESULT hr = D3D::device->CreateDepthStencilState(&depthdc, res.GetAddressOf());
  426. ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Creating D3D depth stencil state failed: {}", DX11HRWrap(hr));
  427. return m_depth.emplace(state.hex, std::move(res)).first->second.Get();
  428. }
  429. D3D11_PRIMITIVE_TOPOLOGY StateCache::GetPrimitiveTopology(PrimitiveType primitive)
  430. {
  431. static constexpr std::array<D3D11_PRIMITIVE_TOPOLOGY, 4> primitives = {
  432. {D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, D3D11_PRIMITIVE_TOPOLOGY_LINELIST,
  433. D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP}};
  434. return primitives[static_cast<u32>(primitive)];
  435. }
  436. } // namespace DX11