D3DNativeVertexFormat.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Copyright 2010 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <array>
  4. #include "Common/Assert.h"
  5. #include "Common/EnumMap.h"
  6. #include "VideoBackends/D3D/D3DBase.h"
  7. #include "VideoBackends/D3D/D3DGfx.h"
  8. #include "VideoBackends/D3D/D3DState.h"
  9. #include "VideoBackends/D3D/D3DVertexManager.h"
  10. #include "VideoBackends/D3D/DXShader.h"
  11. #include "VideoCommon/NativeVertexFormat.h"
  12. namespace DX11
  13. {
  14. std::mutex s_input_layout_lock;
  15. std::unique_ptr<NativeVertexFormat>
  16. Gfx::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl)
  17. {
  18. return std::make_unique<D3DVertexFormat>(vtx_decl);
  19. }
  20. DXGI_FORMAT VarToD3D(ComponentFormat t, int size, bool integer)
  21. {
  22. using FormatMap = Common::EnumMap<DXGI_FORMAT, ComponentFormat::InvalidFloat7>;
  23. static constexpr auto f = [](FormatMap a) { return a; }; // Deduction helper
  24. static constexpr std::array<FormatMap, 4> d3d_float_format_lookup = {
  25. f({
  26. DXGI_FORMAT_R8_UNORM,
  27. DXGI_FORMAT_R8_SNORM,
  28. DXGI_FORMAT_R16_UNORM,
  29. DXGI_FORMAT_R16_SNORM,
  30. DXGI_FORMAT_R32_FLOAT,
  31. DXGI_FORMAT_R32_FLOAT,
  32. DXGI_FORMAT_R32_FLOAT,
  33. DXGI_FORMAT_R32_FLOAT,
  34. }),
  35. f({
  36. DXGI_FORMAT_R8G8_UNORM,
  37. DXGI_FORMAT_R8G8_SNORM,
  38. DXGI_FORMAT_R16G16_UNORM,
  39. DXGI_FORMAT_R16G16_SNORM,
  40. DXGI_FORMAT_R32G32_FLOAT,
  41. DXGI_FORMAT_R32G32_FLOAT,
  42. DXGI_FORMAT_R32G32_FLOAT,
  43. DXGI_FORMAT_R32G32_FLOAT,
  44. }),
  45. f({
  46. DXGI_FORMAT_UNKNOWN,
  47. DXGI_FORMAT_UNKNOWN,
  48. DXGI_FORMAT_UNKNOWN,
  49. DXGI_FORMAT_UNKNOWN,
  50. DXGI_FORMAT_R32G32B32_FLOAT,
  51. DXGI_FORMAT_R32G32B32_FLOAT,
  52. DXGI_FORMAT_R32G32B32_FLOAT,
  53. DXGI_FORMAT_R32G32B32_FLOAT,
  54. }),
  55. f({
  56. DXGI_FORMAT_R8G8B8A8_UNORM,
  57. DXGI_FORMAT_R8G8B8A8_SNORM,
  58. DXGI_FORMAT_R16G16B16A16_UNORM,
  59. DXGI_FORMAT_R16G16B16A16_SNORM,
  60. DXGI_FORMAT_R32G32B32A32_FLOAT,
  61. DXGI_FORMAT_R32G32B32A32_FLOAT,
  62. DXGI_FORMAT_R32G32B32A32_FLOAT,
  63. DXGI_FORMAT_R32G32B32A32_FLOAT,
  64. }),
  65. };
  66. static constexpr std::array<FormatMap, 4> d3d_integer_format_lookup = {
  67. f({
  68. DXGI_FORMAT_R8_UINT,
  69. DXGI_FORMAT_R8_SINT,
  70. DXGI_FORMAT_R16_UINT,
  71. DXGI_FORMAT_R16_SINT,
  72. DXGI_FORMAT_UNKNOWN,
  73. DXGI_FORMAT_UNKNOWN,
  74. DXGI_FORMAT_UNKNOWN,
  75. DXGI_FORMAT_UNKNOWN,
  76. }),
  77. f({
  78. DXGI_FORMAT_R8G8_UINT,
  79. DXGI_FORMAT_R8G8_SINT,
  80. DXGI_FORMAT_R16G16_UINT,
  81. DXGI_FORMAT_R16G16_SINT,
  82. DXGI_FORMAT_UNKNOWN,
  83. DXGI_FORMAT_UNKNOWN,
  84. DXGI_FORMAT_UNKNOWN,
  85. DXGI_FORMAT_UNKNOWN,
  86. }),
  87. f({
  88. DXGI_FORMAT_UNKNOWN,
  89. DXGI_FORMAT_UNKNOWN,
  90. DXGI_FORMAT_UNKNOWN,
  91. DXGI_FORMAT_UNKNOWN,
  92. DXGI_FORMAT_UNKNOWN,
  93. DXGI_FORMAT_UNKNOWN,
  94. DXGI_FORMAT_UNKNOWN,
  95. DXGI_FORMAT_UNKNOWN,
  96. }),
  97. f({
  98. DXGI_FORMAT_R8G8B8A8_UINT,
  99. DXGI_FORMAT_R8G8B8A8_SINT,
  100. DXGI_FORMAT_R16G16B16A16_UINT,
  101. DXGI_FORMAT_R16G16B16A16_SINT,
  102. DXGI_FORMAT_UNKNOWN,
  103. DXGI_FORMAT_UNKNOWN,
  104. DXGI_FORMAT_UNKNOWN,
  105. DXGI_FORMAT_UNKNOWN,
  106. }),
  107. };
  108. DXGI_FORMAT retval =
  109. integer ? d3d_integer_format_lookup[size - 1][t] : d3d_float_format_lookup[size - 1][t];
  110. if (retval == DXGI_FORMAT_UNKNOWN)
  111. {
  112. PanicAlertFmt("VarToD3D: Invalid type/size combo {}, {}, {}", t, size, integer);
  113. }
  114. return retval;
  115. }
  116. D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& vtx_decl)
  117. : NativeVertexFormat(vtx_decl)
  118. {
  119. AddAttribute(vtx_decl.position, ShaderAttrib::Position);
  120. for (u32 i = 0; i < 3; i++)
  121. AddAttribute(vtx_decl.normals[i], ShaderAttrib::Normal + i);
  122. for (u32 i = 0; i < 2; i++)
  123. AddAttribute(vtx_decl.colors[i], ShaderAttrib::Color0 + i);
  124. for (u32 i = 0; i < 8; i++)
  125. AddAttribute(vtx_decl.texcoords[i], ShaderAttrib::TexCoord0 + i);
  126. AddAttribute(vtx_decl.posmtx, ShaderAttrib::PositionMatrix);
  127. }
  128. D3DVertexFormat::~D3DVertexFormat()
  129. {
  130. ID3D11InputLayout* layout = m_layout.load();
  131. if (layout)
  132. layout->Release();
  133. }
  134. ID3D11InputLayout* D3DVertexFormat::GetInputLayout(const void* vs_bytecode, size_t vs_bytecode_size)
  135. {
  136. // CreateInputLayout requires a shader input, but it only looks at the signature of the shader,
  137. // so we don't need to recompute it if the shader changes.
  138. ID3D11InputLayout* layout = m_layout.load();
  139. if (layout)
  140. return layout;
  141. HRESULT hr = D3D::device->CreateInputLayout(m_elems.data(), m_num_elems, vs_bytecode,
  142. vs_bytecode_size, &layout);
  143. ASSERT_MSG(VIDEO, SUCCEEDED(hr), "Failed to create input layout: {}", DX11HRWrap(hr));
  144. // This method can be called from multiple threads, so ensure that only one thread sets the
  145. // cached input layout pointer. If another thread beats this thread, use the existing layout.
  146. ID3D11InputLayout* expected = nullptr;
  147. if (!m_layout.compare_exchange_strong(expected, layout))
  148. {
  149. if (layout)
  150. layout->Release();
  151. layout = expected;
  152. }
  153. return layout;
  154. }
  155. void D3DVertexFormat::AddAttribute(const AttributeFormat& format, ShaderAttrib semantic_index)
  156. {
  157. if (format.enable)
  158. {
  159. m_elems[m_num_elems].SemanticName = "TEXCOORD";
  160. m_elems[m_num_elems].SemanticIndex = static_cast<u32>(semantic_index);
  161. m_elems[m_num_elems].AlignedByteOffset = format.offset;
  162. m_elems[m_num_elems].Format = VarToD3D(format.type, format.components, format.integer);
  163. m_elems[m_num_elems].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
  164. ++m_num_elems;
  165. }
  166. }
  167. } // namespace DX11