d3d12_context.cpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136
  1. /**************************************************************************/
  2. /* d3d12_context.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "d3d12_context.h"
  31. #include "core/config/engine.h"
  32. #include "core/config/project_settings.h"
  33. #include "core/string/ustring.h"
  34. #include "core/templates/local_vector.h"
  35. #include "core/version.h"
  36. #include "servers/rendering/rendering_device.h"
  37. #if defined(__GNUC__) && !defined(__clang__)
  38. #pragma GCC diagnostic push
  39. #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
  40. #pragma GCC diagnostic ignored "-Wshadow"
  41. #pragma GCC diagnostic ignored "-Wswitch"
  42. #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
  43. #endif
  44. #include "dxcapi.h"
  45. #if defined(__GNUC__) && !defined(__clang__)
  46. #pragma GCC diagnostic pop
  47. #endif
  48. #if !defined(_MSC_VER)
  49. #include <guiddef.h>
  50. #include <dxguids.h>
  51. #endif
  52. // Note: symbol is not available in MinGW and old MSVC import libraries.
  53. const CLSID CLSID_D3D12DeviceFactoryGodot = __uuidof(ID3D12DeviceFactory);
  54. extern "C" {
  55. char godot_nir_arch_name[32];
  56. }
  57. #ifdef PIX_ENABLED
  58. #if defined(__GNUC__)
  59. #define _MSC_VER 1800
  60. #endif
  61. #define USE_PIX
  62. #include "WinPixEventRuntime/pix3.h"
  63. #if defined(__GNUC__)
  64. #undef _MSC_VER
  65. #endif
  66. #endif
  67. #define D3D12_DEBUG_LAYER_BREAK_ON_ERROR 0
  68. void D3D12Context::_debug_message_func(
  69. D3D12_MESSAGE_CATEGORY p_category,
  70. D3D12_MESSAGE_SEVERITY p_severity,
  71. D3D12_MESSAGE_ID p_id,
  72. LPCSTR p_description,
  73. void *p_context) {
  74. String type_string;
  75. switch (p_category) {
  76. case D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED:
  77. type_string = "APPLICATION_DEFINED";
  78. break;
  79. case D3D12_MESSAGE_CATEGORY_MISCELLANEOUS:
  80. type_string = "MISCELLANEOUS";
  81. break;
  82. case D3D12_MESSAGE_CATEGORY_INITIALIZATION:
  83. type_string = "INITIALIZATION";
  84. break;
  85. case D3D12_MESSAGE_CATEGORY_CLEANUP:
  86. type_string = "CLEANUP";
  87. break;
  88. case D3D12_MESSAGE_CATEGORY_COMPILATION:
  89. type_string = "COMPILATION";
  90. break;
  91. case D3D12_MESSAGE_CATEGORY_STATE_CREATION:
  92. type_string = "STATE_CREATION";
  93. break;
  94. case D3D12_MESSAGE_CATEGORY_STATE_SETTING:
  95. type_string = "STATE_SETTING";
  96. break;
  97. case D3D12_MESSAGE_CATEGORY_STATE_GETTING:
  98. type_string = "STATE_GETTING";
  99. break;
  100. case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION:
  101. type_string = "RESOURCE_MANIPULATION";
  102. break;
  103. case D3D12_MESSAGE_CATEGORY_EXECUTION:
  104. type_string = "EXECUTION";
  105. break;
  106. case D3D12_MESSAGE_CATEGORY_SHADER:
  107. type_string = "SHADER";
  108. break;
  109. }
  110. String error_message(type_string +
  111. " - Message Id Number: " + String::num_int64(p_id) +
  112. "\n\t" + p_description);
  113. // Convert D3D12 severity to our own log macros.
  114. switch (p_severity) {
  115. case D3D12_MESSAGE_SEVERITY_MESSAGE:
  116. print_verbose(error_message);
  117. break;
  118. case D3D12_MESSAGE_SEVERITY_INFO:
  119. print_line(error_message);
  120. break;
  121. case D3D12_MESSAGE_SEVERITY_WARNING:
  122. WARN_PRINT(error_message);
  123. break;
  124. case D3D12_MESSAGE_SEVERITY_ERROR:
  125. case D3D12_MESSAGE_SEVERITY_CORRUPTION:
  126. ERR_PRINT(error_message);
  127. CRASH_COND_MSG(Engine::get_singleton()->is_abort_on_gpu_errors_enabled(),
  128. "Crashing, because abort on GPU errors is enabled.");
  129. break;
  130. }
  131. }
  132. uint32_t D3D12Context::SubgroupCapabilities::supported_stages_flags_rd() const {
  133. // If there's a way to check exactly which are supported, I have yet to find it.
  134. return (
  135. RenderingDevice::ShaderStage::SHADER_STAGE_FRAGMENT_BIT |
  136. RenderingDevice::ShaderStage::SHADER_STAGE_COMPUTE_BIT);
  137. }
  138. uint32_t D3D12Context::SubgroupCapabilities::supported_operations_flags_rd() const {
  139. if (!wave_ops_supported) {
  140. return 0;
  141. } else {
  142. return (
  143. RenderingDevice::SubgroupOperations::SUBGROUP_BASIC_BIT |
  144. RenderingDevice::SubgroupOperations::SUBGROUP_BALLOT_BIT |
  145. RenderingDevice::SubgroupOperations::SUBGROUP_VOTE_BIT |
  146. RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_BIT |
  147. RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_RELATIVE_BIT |
  148. RenderingDevice::SubgroupOperations::SUBGROUP_QUAD_BIT |
  149. RenderingDevice::SubgroupOperations::SUBGROUP_ARITHMETIC_BIT |
  150. RenderingDevice::SubgroupOperations::SUBGROUP_CLUSTERED_BIT);
  151. }
  152. }
  153. Error D3D12Context::_check_capabilities() {
  154. // Assume not supported until proven otherwise.
  155. vrs_capabilities.draw_call_supported = false;
  156. vrs_capabilities.primitive_supported = false;
  157. vrs_capabilities.primitive_in_multiviewport = false;
  158. vrs_capabilities.ss_image_supported = false;
  159. vrs_capabilities.ss_image_tile_size = 1;
  160. vrs_capabilities.additional_rates_supported = false;
  161. multiview_capabilities.is_supported = false;
  162. multiview_capabilities.geometry_shader_is_supported = false;
  163. multiview_capabilities.tessellation_shader_is_supported = false;
  164. multiview_capabilities.max_view_count = 0;
  165. multiview_capabilities.max_instance_count = 0;
  166. multiview_capabilities.is_supported = false;
  167. subgroup_capabilities.size = 0;
  168. subgroup_capabilities.wave_ops_supported = false;
  169. shader_capabilities.shader_model = D3D_SHADER_MODEL_6_0;
  170. shader_capabilities.native_16bit_ops = false;
  171. storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = false;
  172. format_capabilities.relaxed_casting_supported = false;
  173. {
  174. D3D12_FEATURE_DATA_SHADER_MODEL shader_model = {};
  175. shader_model.HighestShaderModel = MIN(D3D_HIGHEST_SHADER_MODEL, D3D_SHADER_MODEL_6_6);
  176. HRESULT res = md.device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shader_model, sizeof(shader_model));
  177. ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
  178. shader_capabilities.shader_model = shader_model.HighestShaderModel;
  179. }
  180. print_verbose("- Shader:");
  181. print_verbose(" model: " + itos(shader_capabilities.shader_model >> 4) + "." + itos(shader_capabilities.shader_model & 0xf));
  182. D3D12_FEATURE_DATA_D3D12_OPTIONS options = {};
  183. HRESULT res = md.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options));
  184. if (SUCCEEDED(res)) {
  185. storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = options.TypedUAVLoadAdditionalFormats;
  186. }
  187. D3D12_FEATURE_DATA_D3D12_OPTIONS1 options1 = {};
  188. res = md.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS1, &options1, sizeof(options1));
  189. if (SUCCEEDED(res)) {
  190. subgroup_capabilities.size = options1.WaveLaneCountMin;
  191. subgroup_capabilities.wave_ops_supported = options1.WaveOps;
  192. }
  193. D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
  194. res = md.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3, sizeof(options3));
  195. if (SUCCEEDED(res)) {
  196. // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_view_instancing_tier
  197. // https://microsoft.github.io/DirectX-Specs/d3d/ViewInstancing.html#sv_viewid
  198. if (options3.ViewInstancingTier >= D3D12_VIEW_INSTANCING_TIER_1) {
  199. multiview_capabilities.is_supported = true;
  200. multiview_capabilities.geometry_shader_is_supported = options3.ViewInstancingTier >= D3D12_VIEW_INSTANCING_TIER_3;
  201. multiview_capabilities.tessellation_shader_is_supported = options3.ViewInstancingTier >= D3D12_VIEW_INSTANCING_TIER_3;
  202. multiview_capabilities.max_view_count = D3D12_MAX_VIEW_INSTANCE_COUNT;
  203. multiview_capabilities.max_instance_count = UINT32_MAX;
  204. }
  205. }
  206. D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {};
  207. res = md.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6, sizeof(options6));
  208. if (SUCCEEDED(res)) {
  209. if (options6.VariableShadingRateTier >= D3D12_VARIABLE_SHADING_RATE_TIER_1) {
  210. vrs_capabilities.draw_call_supported = true;
  211. if (options6.VariableShadingRateTier >= D3D12_VARIABLE_SHADING_RATE_TIER_2) {
  212. vrs_capabilities.primitive_supported = true;
  213. vrs_capabilities.primitive_in_multiviewport = options6.PerPrimitiveShadingRateSupportedWithViewportIndexing;
  214. vrs_capabilities.ss_image_supported = true;
  215. vrs_capabilities.ss_image_tile_size = options6.ShadingRateImageTileSize;
  216. vrs_capabilities.additional_rates_supported = options6.AdditionalShadingRatesSupported;
  217. }
  218. }
  219. }
  220. D3D12_FEATURE_DATA_D3D12_OPTIONS12 options12 = {};
  221. res = md.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS12, &options12, sizeof(options12));
  222. if (SUCCEEDED(res)) {
  223. format_capabilities.relaxed_casting_supported = options12.RelaxedFormatCastingSupported;
  224. }
  225. if (vrs_capabilities.draw_call_supported || vrs_capabilities.primitive_supported || vrs_capabilities.ss_image_supported) {
  226. print_verbose("- D3D12 Variable Rate Shading supported:");
  227. if (vrs_capabilities.draw_call_supported) {
  228. print_verbose(" Draw call");
  229. }
  230. if (vrs_capabilities.primitive_supported) {
  231. print_verbose(String(" Per-primitive (multi-viewport: ") + (vrs_capabilities.primitive_in_multiviewport ? "yes" : "no") + ")");
  232. }
  233. if (vrs_capabilities.ss_image_supported) {
  234. print_verbose(String(" Screen-space image (tile size: ") + itos(vrs_capabilities.ss_image_tile_size) + ")");
  235. }
  236. if (vrs_capabilities.additional_rates_supported) {
  237. print_verbose(String(" Additional rates: ") + (vrs_capabilities.additional_rates_supported ? "yes" : "no"));
  238. }
  239. } else {
  240. print_verbose("- D3D12 Variable Rate Shading not supported");
  241. }
  242. if (multiview_capabilities.is_supported) {
  243. print_verbose("- D3D12 multiview supported:");
  244. print_verbose(" max view count: " + itos(multiview_capabilities.max_view_count));
  245. //print_verbose(" max instances: " + itos(multiview_capabilities.max_instance_count)); // Hardcoded; not very useful at the moment.
  246. } else {
  247. print_verbose("- D3D12 multiview not supported");
  248. }
  249. if (format_capabilities.relaxed_casting_supported) {
  250. print_verbose("- Relaxed casting supported");
  251. } else {
  252. print_verbose("- Relaxed casting not supported");
  253. }
  254. return OK;
  255. }
  256. Error D3D12Context::_initialize_debug_layers() {
  257. ComPtr<ID3D12Debug> debug_controller;
  258. HRESULT res;
  259. if (device_factory) {
  260. res = device_factory->GetConfigurationInterface(CLSID_D3D12Debug, IID_PPV_ARGS(&debug_controller));
  261. } else {
  262. res = D3D12GetDebugInterface(IID_PPV_ARGS(&debug_controller));
  263. }
  264. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_QUERY_FAILED);
  265. debug_controller->EnableDebugLayer();
  266. return OK;
  267. }
  268. Error D3D12Context::_select_adapter(int &r_index) {
  269. {
  270. UINT flags = _use_validation_layers() ? DXGI_CREATE_FACTORY_DEBUG : 0;
  271. HRESULT res = CreateDXGIFactory2(flags, IID_PPV_ARGS(&dxgi_factory));
  272. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
  273. }
  274. ComPtr<IDXGIFactory6> factory6;
  275. dxgi_factory.As(&factory6);
  276. // TODO: Use IDXCoreAdapterList, which gives more comprehensive information.
  277. LocalVector<IDXGIAdapter1 *> adapters;
  278. while (true) {
  279. IDXGIAdapter1 *curr_adapter = nullptr;
  280. if (factory6) {
  281. if (factory6->EnumAdapterByGpuPreference(adapters.size(), DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, IID_PPV_ARGS(&curr_adapter)) == DXGI_ERROR_NOT_FOUND) {
  282. break;
  283. }
  284. } else {
  285. if (dxgi_factory->EnumAdapters1(adapters.size(), &curr_adapter) == DXGI_ERROR_NOT_FOUND) {
  286. break;
  287. }
  288. }
  289. adapters.push_back(curr_adapter);
  290. }
  291. ERR_FAIL_COND_V_MSG(adapters.size() == 0, ERR_CANT_CREATE, "Adapters enumeration reported zero accessible devices.");
  292. // The device should really be a preference, but for now choosing a discrete GPU over the
  293. // integrated one is better than the default.
  294. int32_t adapter_index = -1;
  295. int type_selected = -1;
  296. LocalVector<RenderingDevice::DeviceType> adapter_types;
  297. print_verbose("D3D12 devices:");
  298. for (uint32_t i = 0; i < adapters.size(); ++i) {
  299. DXGI_ADAPTER_DESC1 desc = {};
  300. adapters[i]->GetDesc1(&desc);
  301. String name = desc.Description;
  302. String dev_type;
  303. RenderingDevice::DeviceType type = {};
  304. if (((desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE))) {
  305. type = RenderingDevice::DEVICE_TYPE_CPU;
  306. } else {
  307. type = desc.DedicatedVideoMemory ? RenderingDevice::DEVICE_TYPE_DISCRETE_GPU : RenderingDevice::DEVICE_TYPE_INTEGRATED_GPU;
  308. }
  309. adapter_types.push_back(type);
  310. switch (type) {
  311. case RenderingDevice::DEVICE_TYPE_DISCRETE_GPU: {
  312. dev_type = "Discrete";
  313. } break;
  314. case RenderingDevice::DEVICE_TYPE_INTEGRATED_GPU: {
  315. dev_type = "Integrated";
  316. } break;
  317. case RenderingDevice::DEVICE_TYPE_VIRTUAL_GPU: {
  318. dev_type = "Virtual";
  319. } break;
  320. case RenderingDevice::DEVICE_TYPE_CPU: {
  321. dev_type = "CPU";
  322. } break;
  323. default: {
  324. dev_type = "Other";
  325. } break;
  326. }
  327. print_verbose(" #" + itos(i) + ": " + name + ", " + dev_type);
  328. switch (type) {
  329. case RenderingDevice::DEVICE_TYPE_DISCRETE_GPU: {
  330. if (type_selected < 4) {
  331. type_selected = 4;
  332. adapter_index = i;
  333. }
  334. } break;
  335. case RenderingDevice::DEVICE_TYPE_INTEGRATED_GPU: {
  336. if (type_selected < 3) {
  337. type_selected = 3;
  338. adapter_index = i;
  339. }
  340. } break;
  341. case RenderingDevice::DEVICE_TYPE_VIRTUAL_GPU: {
  342. if (type_selected < 2) {
  343. type_selected = 2;
  344. adapter_index = i;
  345. }
  346. } break;
  347. case RenderingDevice::DEVICE_TYPE_CPU: {
  348. if (type_selected < 1) {
  349. type_selected = 1;
  350. adapter_index = i;
  351. }
  352. } break;
  353. default: {
  354. if (type_selected < 0) {
  355. type_selected = 0;
  356. adapter_index = i;
  357. }
  358. } break;
  359. }
  360. }
  361. int32_t user_adapter_index = Engine::get_singleton()->get_gpu_index(); // Force user selected GPU.
  362. if (user_adapter_index >= 0 && user_adapter_index < (int32_t)adapters.size()) {
  363. adapter_index = user_adapter_index;
  364. }
  365. ERR_FAIL_COND_V_MSG(adapter_index == -1, ERR_CANT_CREATE, "None of D3D12 devices supports hardware rendering.");
  366. gpu = adapters[adapter_index];
  367. for (uint32_t i = 0; i < adapters.size(); ++i) {
  368. adapters[i]->Release();
  369. }
  370. adapter_type = adapter_types[adapter_index];
  371. ComPtr<IDXGIFactory5> factory5;
  372. dxgi_factory.As(&factory5);
  373. if (factory5) {
  374. BOOL result = FALSE; // sizeof(bool) != sizeof(BOOL), in general.
  375. HRESULT res = factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &result, sizeof(result));
  376. if (SUCCEEDED(res)) {
  377. tearing_supported = result;
  378. } else {
  379. ERR_PRINT("CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
  380. }
  381. }
  382. r_index = adapter_index;
  383. return OK;
  384. }
  385. void D3D12Context::_dump_adapter_info(int p_index) {
  386. {
  387. const D3D_FEATURE_LEVEL FEATURE_LEVELS[] = {
  388. D3D_FEATURE_LEVEL_11_0,
  389. D3D_FEATURE_LEVEL_11_1,
  390. D3D_FEATURE_LEVEL_12_0,
  391. D3D_FEATURE_LEVEL_12_1,
  392. D3D_FEATURE_LEVEL_12_2,
  393. };
  394. D3D12_FEATURE_DATA_FEATURE_LEVELS feat_levels = {};
  395. feat_levels.NumFeatureLevels = ARRAY_SIZE(FEATURE_LEVELS);
  396. feat_levels.pFeatureLevelsRequested = FEATURE_LEVELS;
  397. HRESULT res = md.device->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &feat_levels, sizeof(feat_levels));
  398. ERR_FAIL_COND_MSG(!SUCCEEDED(res), "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
  399. // Example: D3D_FEATURE_LEVEL_12_1 = 0xc100.
  400. uint32_t feat_level_major = feat_levels.MaxSupportedFeatureLevel >> 12;
  401. uint32_t feat_level_minor = (feat_levels.MaxSupportedFeatureLevel >> 16) & 0xff;
  402. feature_level = feat_level_major * 10 + feat_level_minor;
  403. }
  404. String rendering_method;
  405. if (OS::get_singleton()->get_current_rendering_method() == "mobile") {
  406. rendering_method = "Forward Mobile";
  407. } else {
  408. rendering_method = "Forward+";
  409. }
  410. static const struct {
  411. uint32_t id;
  412. const char *name;
  413. } vendor_names[] = {
  414. { 0x1002, "AMD" },
  415. { 0x1010, "ImgTec" },
  416. { 0x106B, "Apple" },
  417. { 0x10DE, "NVIDIA" },
  418. { 0x13B5, "ARM" },
  419. { 0x1414, "Microsoft" },
  420. { 0x5143, "Qualcomm" },
  421. { 0x8086, "Intel" },
  422. { 0, nullptr },
  423. };
  424. DXGI_ADAPTER_DESC gpu_desc = {};
  425. gpu->GetDesc(&gpu_desc);
  426. adapter_name = gpu_desc.Description;
  427. pipeline_cache_id = String::hex_encode_buffer((uint8_t *)&gpu_desc.AdapterLuid, sizeof(LUID));
  428. pipeline_cache_id += "-driver-" + itos(gpu_desc.Revision);
  429. {
  430. adapter_vendor = "Unknown";
  431. uint32_t vendor_idx = 0;
  432. while (vendor_names[vendor_idx].name != nullptr) {
  433. if (gpu_desc.VendorId == vendor_names[vendor_idx].id) {
  434. adapter_vendor = vendor_names[vendor_idx].name;
  435. break;
  436. }
  437. vendor_idx++;
  438. }
  439. }
  440. print_line(vformat("D3D12 feature level %s - %s - Using D3D12 Adapter #%d: %s", get_device_api_version(), rendering_method, p_index, adapter_name));
  441. }
  442. Error D3D12Context::_create_device(DeviceBasics &r_basics) {
  443. HRESULT res;
  444. if (device_factory) {
  445. res = device_factory->CreateDevice(gpu.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(r_basics.device.GetAddressOf()));
  446. } else {
  447. res = D3D12CreateDevice(gpu.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(r_basics.device.GetAddressOf()));
  448. }
  449. ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "D3D12CreateDevice failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
  450. // Create direct command queue.
  451. D3D12_COMMAND_QUEUE_DESC queue_desc = {};
  452. queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
  453. queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
  454. res = r_basics.device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(r_basics.queue.GetAddressOf()));
  455. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
  456. // Create sync objects.
  457. res = r_basics.device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(r_basics.fence.GetAddressOf()));
  458. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
  459. r_basics.fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
  460. ERR_FAIL_NULL_V(r_basics.fence_event, ERR_CANT_CREATE);
  461. if (_use_validation_layers()) {
  462. ComPtr<ID3D12InfoQueue> info_queue;
  463. res = r_basics.device.As(&info_queue);
  464. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
  465. #if 0 // This causes crashes. Needs investigation.
  466. ComPtr<ID3D12InfoQueue1> info_queue_1;
  467. device.As(&info_queue_1);
  468. if (info_queue_1) {
  469. // Custom printing supported (added in Windows 10 Release Preview build 20236).
  470. info_queue_1->SetMuteDebugOutput(TRUE);
  471. res = info_queue_1->RegisterMessageCallback(&_debug_message_func, D3D12_MESSAGE_CALLBACK_IGNORE_FILTERS, nullptr, 0);
  472. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
  473. } else
  474. #endif
  475. {
  476. // Rely on D3D12's own debug printing.
  477. if (Engine::get_singleton()->is_abort_on_gpu_errors_enabled()) {
  478. res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, TRUE);
  479. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
  480. res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE);
  481. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
  482. res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE);
  483. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
  484. }
  485. }
  486. D3D12_MESSAGE_SEVERITY severities_to_mute[] = {
  487. D3D12_MESSAGE_SEVERITY_INFO,
  488. };
  489. D3D12_MESSAGE_ID messages_to_mute[] = {
  490. D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
  491. D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE,
  492. // These happen due to how D3D12MA manages buffers; seem bening.
  493. D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_HAS_NO_RESOURCE,
  494. D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_INTERSECTS_MULTIPLE_BUFFERS,
  495. };
  496. D3D12_INFO_QUEUE_FILTER filter = {};
  497. filter.DenyList.NumSeverities = ARRAY_SIZE(severities_to_mute);
  498. filter.DenyList.pSeverityList = severities_to_mute;
  499. filter.DenyList.NumIDs = ARRAY_SIZE(messages_to_mute);
  500. filter.DenyList.pIDList = messages_to_mute;
  501. res = info_queue->PushStorageFilter(&filter);
  502. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
  503. #if D3D12_DEBUG_LAYER_BREAK_ON_ERROR
  504. res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);
  505. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
  506. #endif
  507. }
  508. return OK;
  509. }
  510. Error D3D12Context::_get_device_limits() {
  511. D3D12_FEATURE_DATA_D3D12_OPTIONS options = {};
  512. HRESULT res = md.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options));
  513. ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_UNAVAILABLE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
  514. // https://docs.microsoft.com/en-us/windows/win32/direct3d12/hardware-support
  515. gpu_limits.max_srvs_per_shader_stage = options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1 ? 128 : UINT64_MAX;
  516. gpu_limits.max_cbvs_per_shader_stage = options.ResourceBindingTier <= D3D12_RESOURCE_BINDING_TIER_2 ? 14 : UINT64_MAX;
  517. gpu_limits.max_samplers_across_all_stages = options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1 ? 16 : 2048;
  518. if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1) {
  519. gpu_limits.max_uavs_across_all_stages = feature_level <= 110 ? 8 : 64;
  520. } else if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_2) {
  521. gpu_limits.max_uavs_across_all_stages = 64;
  522. } else {
  523. gpu_limits.max_uavs_across_all_stages = UINT64_MAX;
  524. }
  525. md.queue->GetTimestampFrequency(&gpu_limits.timestamp_frequency);
  526. return OK;
  527. }
  528. bool D3D12Context::_use_validation_layers() {
  529. return Engine::get_singleton()->is_validation_layers_enabled();
  530. }
  531. Error D3D12Context::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
  532. ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER);
  533. Window window;
  534. window.hwnd = ((const WindowPlatformData *)p_platform_data)->window;
  535. window.width = p_width;
  536. window.height = p_height;
  537. window.vsync_mode = p_vsync_mode;
  538. {
  539. RDD::Attachment attachment;
  540. attachment.samples = RD::TEXTURE_SAMPLES_1;
  541. attachment.load_op = RDD::ATTACHMENT_LOAD_OP_CLEAR;
  542. attachment.store_op = RDD::ATTACHMENT_STORE_OP_STORE;
  543. window.render_pass.attachments.push_back(attachment);
  544. RDD::Subpass subpass;
  545. {
  546. RDD::AttachmentReference color_ref;
  547. color_ref.attachment = 0;
  548. color_ref.aspect.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);
  549. subpass.color_references.push_back(color_ref);
  550. }
  551. window.render_pass.subpasses.push_back(subpass);
  552. }
  553. for (uint32_t i = 0; i < IMAGE_COUNT; i++) {
  554. Error err = window.framebuffers[i].rtv_heap.allocate(md.device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1, false);
  555. ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
  556. window.framebuffers[i].is_screen = true;
  557. window.framebuffers[i].attachments_handle_inds.push_back(0);
  558. }
  559. Error err = _update_swap_chain(&window);
  560. ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
  561. windows[p_window_id] = window;
  562. return OK;
  563. }
  564. void D3D12Context::window_resize(DisplayServer::WindowID p_window, int p_width, int p_height) {
  565. ERR_FAIL_COND(!windows.has(p_window));
  566. windows[p_window].width = p_width;
  567. windows[p_window].height = p_height;
  568. _update_swap_chain(&windows[p_window]);
  569. }
  570. int D3D12Context::window_get_width(DisplayServer::WindowID p_window) {
  571. ERR_FAIL_COND_V(!windows.has(p_window), -1);
  572. return windows[p_window].width;
  573. }
  574. int D3D12Context::window_get_height(DisplayServer::WindowID p_window) {
  575. ERR_FAIL_COND_V(!windows.has(p_window), -1);
  576. return windows[p_window].height;
  577. }
  578. bool D3D12Context::window_is_valid_swapchain(DisplayServer::WindowID p_window) {
  579. ERR_FAIL_COND_V(!windows.has(p_window), false);
  580. Window *w = &windows[p_window];
  581. return (bool)w->swapchain;
  582. }
  583. RDD::RenderPassID D3D12Context::window_get_render_pass(DisplayServer::WindowID p_window) {
  584. ERR_FAIL_COND_V(!windows.has(p_window), RDD::RenderPassID());
  585. Window *w = &windows[p_window];
  586. return RDD::RenderPassID(&w->render_pass);
  587. }
  588. RDD::FramebufferID D3D12Context::window_get_framebuffer(DisplayServer::WindowID p_window) {
  589. ERR_FAIL_COND_V(!windows.has(p_window), RDD::FramebufferID());
  590. ERR_FAIL_COND_V(!buffers_prepared, RDD::FramebufferID());
  591. Window *w = &windows[p_window];
  592. if (w->swapchain) {
  593. return RDD::FramebufferID(&w->framebuffers[w->current_buffer]);
  594. } else {
  595. return RDD::FramebufferID();
  596. }
  597. }
  598. void D3D12Context::window_destroy(DisplayServer::WindowID p_window_id) {
  599. ERR_FAIL_COND(!windows.has(p_window_id));
  600. _wait_for_idle_queue(md.queue.Get());
  601. windows.erase(p_window_id);
  602. }
  603. Error D3D12Context::_update_swap_chain(Window *window) {
  604. if (window->width == 0 || window->height == 0) {
  605. // Likely window minimized, no swapchain created.
  606. return ERR_SKIP;
  607. }
  608. DisplayServer::VSyncMode curr_vsync_mode = window->vsync_mode;
  609. bool vsync_mode_available = false;
  610. UINT swapchain_flags = 0;
  611. do {
  612. switch (window->vsync_mode) {
  613. case DisplayServer::VSYNC_MAILBOX: {
  614. window->sync_interval = 1;
  615. window->present_flags = DXGI_PRESENT_RESTART;
  616. swapchain_flags = 0;
  617. vsync_mode_available = true;
  618. } break;
  619. case DisplayServer::VSYNC_ADAPTIVE: {
  620. vsync_mode_available = false; // I don't know how to set this up.
  621. } break;
  622. case DisplayServer::VSYNC_ENABLED: {
  623. window->sync_interval = 1;
  624. window->present_flags = 0;
  625. swapchain_flags = 0;
  626. vsync_mode_available = true;
  627. } break;
  628. case DisplayServer::VSYNC_DISABLED: {
  629. window->sync_interval = 0;
  630. window->present_flags = tearing_supported ? DXGI_PRESENT_ALLOW_TEARING : 0;
  631. swapchain_flags = tearing_supported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
  632. vsync_mode_available = true;
  633. } break;
  634. }
  635. // Set the windows swap effect if it is available, otherwise FLIP_DISCARD is used.
  636. if (vsync_mode_available) {
  637. if (window->vsync_mode != curr_vsync_mode || !window->swapchain) {
  638. window->vsync_mode = curr_vsync_mode;
  639. print_verbose("Using swapchain flags: " + itos(swapchain_flags) + ", sync interval: " + itos(window->sync_interval) + ", present flags: " + itos(window->present_flags));
  640. }
  641. } else {
  642. String present_mode_string;
  643. switch (window->vsync_mode) {
  644. case DisplayServer::VSYNC_MAILBOX:
  645. present_mode_string = "Mailbox";
  646. break;
  647. case DisplayServer::VSYNC_ADAPTIVE:
  648. present_mode_string = "Adaptive";
  649. break;
  650. case DisplayServer::VSYNC_ENABLED:
  651. present_mode_string = "Enabled";
  652. break;
  653. case DisplayServer::VSYNC_DISABLED:
  654. present_mode_string = "Disabled";
  655. break;
  656. }
  657. WARN_PRINT(vformat("The requested V-Sync mode %s is not available. Falling back to V-Sync mode Enabled.", present_mode_string));
  658. window->vsync_mode = DisplayServer::VSYNC_ENABLED; // Set to default.
  659. }
  660. } while (!vsync_mode_available);
  661. if (window->swapchain) {
  662. _wait_for_idle_queue(md.queue.Get());
  663. for (uint32_t i = 0; i < IMAGE_COUNT; i++) {
  664. window->render_targets[i].Reset();
  665. }
  666. // D3D12 docs: "IDXGISwapChain::ResizeBuffers can't be used to add or remove this flag."
  667. bool allow_tearing_flag_changed = (swapchain_flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) != (window->swapchain_flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING);
  668. if (allow_tearing_flag_changed) {
  669. window->swapchain.Reset();
  670. }
  671. }
  672. if (!window->swapchain) {
  673. DXGI_SWAP_CHAIN_DESC1 swapchain_desc = {};
  674. swapchain_desc.BufferCount = IMAGE_COUNT;
  675. swapchain_desc.Width = 0;
  676. swapchain_desc.Height = 0;
  677. swapchain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
  678. swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
  679. swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
  680. swapchain_desc.SampleDesc.Count = 1;
  681. swapchain_desc.Flags = swapchain_flags;
  682. swapchain_desc.Scaling = DXGI_SCALING_NONE;
  683. ComPtr<IDXGISwapChain1> swapchain;
  684. HRESULT res = dxgi_factory->CreateSwapChainForHwnd(md.queue.Get(), window->hwnd, &swapchain_desc, nullptr, nullptr, swapchain.GetAddressOf());
  685. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
  686. swapchain.As(&window->swapchain);
  687. ERR_FAIL_NULL_V(window->swapchain, ERR_CANT_CREATE);
  688. format = swapchain_desc.Format;
  689. res = dxgi_factory->MakeWindowAssociation(window->hwnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES);
  690. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
  691. res = window->swapchain->GetDesc1(&swapchain_desc);
  692. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
  693. ERR_FAIL_COND_V(swapchain_desc.BufferCount != IMAGE_COUNT, ERR_BUG);
  694. window->width = swapchain_desc.Width;
  695. window->height = swapchain_desc.Height;
  696. } else {
  697. HRESULT res = window->swapchain->ResizeBuffers(IMAGE_COUNT, window->width, window->height, DXGI_FORMAT_UNKNOWN, swapchain_flags);
  698. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_UNAVAILABLE);
  699. }
  700. window->swapchain_flags = swapchain_flags;
  701. window->current_buffer = window->swapchain->GetCurrentBackBufferIndex();
  702. for (uint32_t i = 0; i < IMAGE_COUNT; i++) {
  703. RenderingDeviceDriverD3D12::FramebufferInfo *fb_info = &window->framebuffers[i];
  704. RenderingDeviceDriverD3D12::DescriptorsHeap::Walker walker = fb_info->rtv_heap.make_walker();
  705. HRESULT res = window->swapchain->GetBuffer(i, IID_PPV_ARGS(&window->render_targets[i]));
  706. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
  707. md.device->CreateRenderTargetView(window->render_targets[i].Get(), nullptr, walker.get_curr_cpu_handle());
  708. }
  709. return OK;
  710. }
  711. void D3D12Context::_init_device_factory() {
  712. uint32_t agility_sdk_version = GLOBAL_GET("rendering/rendering_device/d3d12/agility_sdk_version");
  713. String agility_sdk_path = String(".\\") + Engine::get_singleton()->get_architecture_name();
  714. // Note: symbol is not available in MinGW import library.
  715. PFN_D3D12_GET_INTERFACE d3d_D3D12GetInterface = (PFN_D3D12_GET_INTERFACE)GetProcAddress(LoadLibraryW(L"D3D12.dll"), "D3D12GetInterface");
  716. ERR_FAIL_COND(!d3d_D3D12GetInterface);
  717. ID3D12SDKConfiguration *sdk_config = nullptr;
  718. if (SUCCEEDED(d3d_D3D12GetInterface(CLSID_D3D12SDKConfiguration, IID_PPV_ARGS(&sdk_config)))) {
  719. ID3D12SDKConfiguration1 *sdk_config1 = nullptr;
  720. if (SUCCEEDED(sdk_config->QueryInterface(&sdk_config1))) {
  721. if (SUCCEEDED(sdk_config1->CreateDeviceFactory(agility_sdk_version, agility_sdk_path.ascii().get_data(), IID_PPV_ARGS(device_factory.GetAddressOf())))) {
  722. d3d_D3D12GetInterface(CLSID_D3D12DeviceFactoryGodot, IID_PPV_ARGS(device_factory.GetAddressOf()));
  723. } else if (SUCCEEDED(sdk_config1->CreateDeviceFactory(agility_sdk_version, ".\\", IID_PPV_ARGS(device_factory.GetAddressOf())))) {
  724. d3d_D3D12GetInterface(CLSID_D3D12DeviceFactoryGodot, IID_PPV_ARGS(device_factory.GetAddressOf()));
  725. }
  726. sdk_config1->Release();
  727. }
  728. sdk_config->Release();
  729. }
  730. }
  731. Error D3D12Context::initialize() {
  732. _init_device_factory();
  733. if (_use_validation_layers()) {
  734. Error err = _initialize_debug_layers();
  735. ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
  736. }
  737. int adapter_index = 0;
  738. Error err = _select_adapter(adapter_index);
  739. ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
  740. err = _create_device(md);
  741. ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
  742. _dump_adapter_info(adapter_index);
  743. err = _check_capabilities();
  744. ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
  745. err = _get_device_limits();
  746. ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
  747. {
  748. HRESULT res = md.device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(frame_fence.GetAddressOf()));
  749. ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
  750. frame_fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
  751. ERR_FAIL_NULL_V(frame_fence_event, ERR_CANT_CREATE);
  752. }
  753. md.driver = memnew(RenderingDeviceDriverD3D12(this, md.device.Get(), IMAGE_COUNT + 1));
  754. return OK;
  755. }
  756. void D3D12Context::set_setup_buffer(RDD::CommandBufferID p_command_buffer) {
  757. const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
  758. command_list_queue[0] = cmd_buf_info->cmd_list.Get();
  759. }
  760. void D3D12Context::append_command_buffer(RDD::CommandBufferID p_command_buffer) {
  761. if (command_list_queue.size() <= command_list_count) {
  762. command_list_queue.resize(command_list_count + 1);
  763. }
  764. const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
  765. command_list_queue[command_list_count] = cmd_buf_info->cmd_list.Get();
  766. command_list_count++;
  767. }
  768. void D3D12Context::_wait_for_idle_queue(ID3D12CommandQueue *p_queue) {
  769. md.fence_value++;
  770. p_queue->Signal(md.fence.Get(), md.fence_value);
  771. md.fence->SetEventOnCompletion(md.fence_value, md.fence_event);
  772. WaitForSingleObjectEx(md.fence_event, INFINITE, FALSE);
  773. #ifdef PIX_ENABLED
  774. PIXNotifyWakeFromFenceSignal(md.fence_event);
  775. #endif
  776. }
  777. void D3D12Context::flush(bool p_flush_setup, bool p_flush_pending, bool p_sync) {
  778. ERR_FAIL_COND_MSG(!p_sync, "Flush without sync is not supported."); // This is a special case for Vulkan on mobile XR hardware, not applicable to D3D12
  779. if (p_flush_setup && command_list_queue[0]) {
  780. md.queue->ExecuteCommandLists(1, command_list_queue.ptr());
  781. command_list_queue[0] = nullptr;
  782. }
  783. if (p_flush_pending && command_list_count > 1) {
  784. md.queue->ExecuteCommandLists(command_list_count - 1, command_list_queue.ptr() + 1);
  785. command_list_count = 1;
  786. }
  787. if (p_flush_setup || p_flush_pending) {
  788. _wait_for_idle_queue(md.queue.Get());
  789. }
  790. }
  791. Error D3D12Context::prepare_buffers(RDD::CommandBufferID p_command_buffer) {
  792. // Ensure no more than FRAME_LAG renderings are outstanding.
  793. if (frame >= IMAGE_COUNT) {
  794. UINT64 min_value = frame - IMAGE_COUNT;
  795. if (frame_fence->GetCompletedValue() < min_value) {
  796. frame_fence->SetEventOnCompletion(min_value, frame_fence_event);
  797. WaitForSingleObjectEx(frame_fence_event, INFINITE, FALSE);
  798. #ifdef PIX_ENABLED
  799. PIXNotifyWakeFromFenceSignal(frame_fence_event);
  800. #endif
  801. }
  802. }
  803. D3D12_RESOURCE_BARRIER *barriers = (D3D12_RESOURCE_BARRIER *)alloca(windows.size() * sizeof(D3D12_RESOURCE_BARRIER));
  804. uint32_t n = 0;
  805. for (KeyValue<int, Window> &E : windows) {
  806. Window *w = &E.value;
  807. w->current_buffer = w->swapchain->GetCurrentBackBufferIndex();
  808. barriers[n++] = CD3DX12_RESOURCE_BARRIER::Transition(w->render_targets[w->current_buffer].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
  809. }
  810. const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
  811. cmd_buf_info->cmd_list->ResourceBarrier(n, barriers);
  812. buffers_prepared = true;
  813. return OK;
  814. }
  815. void D3D12Context::postpare_buffers(RDD::CommandBufferID p_command_buffer) {
  816. D3D12_RESOURCE_BARRIER *barriers = (D3D12_RESOURCE_BARRIER *)alloca(windows.size() * sizeof(D3D12_RESOURCE_BARRIER));
  817. uint32_t n = 0;
  818. for (KeyValue<int, Window> &E : windows) {
  819. Window *w = &E.value;
  820. barriers[n++] = CD3DX12_RESOURCE_BARRIER::Transition(w->render_targets[w->current_buffer].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
  821. }
  822. const RenderingDeviceDriverD3D12::CommandBufferInfo *cmd_buf_info = (const RenderingDeviceDriverD3D12::CommandBufferInfo *)p_command_buffer.id;
  823. cmd_buf_info->cmd_list->ResourceBarrier(n, barriers);
  824. }
  825. Error D3D12Context::swap_buffers() {
  826. ID3D12CommandList *const *commands_ptr = nullptr;
  827. UINT commands_to_submit = 0;
  828. if (command_list_queue[0] == nullptr) {
  829. // No setup command, but commands to submit, submit from the first and skip command.
  830. if (command_list_count > 1) {
  831. commands_ptr = command_list_queue.ptr() + 1;
  832. commands_to_submit = command_list_count - 1;
  833. }
  834. } else {
  835. commands_ptr = command_list_queue.ptr();
  836. commands_to_submit = command_list_count;
  837. }
  838. md.queue->ExecuteCommandLists(commands_to_submit, commands_ptr);
  839. command_list_queue[0] = nullptr;
  840. command_list_count = 1;
  841. for (KeyValue<int, Window> &E : windows) {
  842. Window *w = &E.value;
  843. if (!w->swapchain) {
  844. continue;
  845. }
  846. HRESULT res = w->swapchain->Present(w->sync_interval, w->present_flags);
  847. if (!SUCCEEDED(res)) {
  848. print_verbose("D3D12: Presenting swapchain of window " + itos(E.key) + " failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
  849. }
  850. }
  851. md.queue->Signal(frame_fence.Get(), frame);
  852. frame++;
  853. buffers_prepared = false;
  854. return OK;
  855. }
  856. void D3D12Context::resize_notify() {
  857. }
  858. RenderingDevice::Capabilities D3D12Context::get_device_capabilities() const {
  859. RenderingDevice::Capabilities c;
  860. c.device_family = RenderingDevice::DEVICE_DIRECTX;
  861. c.version_major = feature_level / 10;
  862. c.version_minor = feature_level % 10;
  863. return c;
  864. }
  865. ID3D12Device *D3D12Context::get_device() {
  866. return md.device.Get();
  867. }
  868. IDXGIAdapter *D3D12Context::get_adapter() {
  869. return gpu.Get();
  870. }
  871. int D3D12Context::get_swapchain_image_count() const {
  872. return IMAGE_COUNT;
  873. }
  874. DXGI_FORMAT D3D12Context::get_screen_format() const {
  875. return format;
  876. }
  877. const D3D12Context::DeviceLimits &D3D12Context::get_device_limits() const {
  878. return gpu_limits;
  879. }
  880. RID D3D12Context::local_device_create() {
  881. LocalDevice ld;
  882. _create_device(ld);
  883. ld.driver = memnew(RenderingDeviceDriverD3D12(this, ld.device.Get(), 1));
  884. return local_device_owner.make_rid(ld);
  885. }
  886. void D3D12Context::local_device_push_command_buffers(RID p_local_device, const RDD::CommandBufferID *p_buffers, int p_count) {
  887. LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
  888. ERR_FAIL_COND(ld->waiting);
  889. ld->queue->ExecuteCommandLists(p_count, (ID3D12CommandList *const *)p_buffers);
  890. ld->waiting = true;
  891. }
  892. void D3D12Context::local_device_sync(RID p_local_device) {
  893. LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
  894. ERR_FAIL_COND(!ld->waiting);
  895. ld->fence_value++;
  896. ld->queue->Signal(ld->fence.Get(), ld->fence_value);
  897. ld->fence->SetEventOnCompletion(ld->fence_value, ld->fence_event);
  898. WaitForSingleObjectEx(ld->fence_event, INFINITE, FALSE);
  899. #ifdef PIX_ENABLED
  900. PIXNotifyWakeFromFenceSignal(ld->fence_event);
  901. #endif
  902. ld->waiting = false;
  903. }
  904. void D3D12Context::local_device_free(RID p_local_device) {
  905. LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
  906. memdelete(ld->driver);
  907. CloseHandle(ld->fence_event);
  908. local_device_owner.free(p_local_device);
  909. }
  910. void D3D12Context::set_object_name(ID3D12Object *p_object, String p_object_name) {
  911. ERR_FAIL_NULL(p_object);
  912. int name_len = p_object_name.size();
  913. WCHAR *name_w = (WCHAR *)alloca(sizeof(WCHAR) * (name_len + 1));
  914. MultiByteToWideChar(CP_UTF8, 0, p_object_name.utf8().get_data(), -1, name_w, name_len);
  915. p_object->SetName(name_w);
  916. }
  917. String D3D12Context::get_device_vendor_name() const {
  918. return adapter_vendor;
  919. }
  920. String D3D12Context::get_device_name() const {
  921. return adapter_name;
  922. }
  923. RenderingDevice::DeviceType D3D12Context::get_device_type() const {
  924. return adapter_type;
  925. }
  926. String D3D12Context::get_device_api_version() const {
  927. return vformat("%d_%d", feature_level / 10, feature_level % 10);
  928. }
  929. String D3D12Context::get_device_pipeline_cache_uuid() const {
  930. return pipeline_cache_id;
  931. }
  932. DisplayServer::VSyncMode D3D12Context::get_vsync_mode(DisplayServer::WindowID p_window) const {
  933. ERR_FAIL_COND_V_MSG(!windows.has(p_window), DisplayServer::VSYNC_ENABLED, "Could not get V-Sync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
  934. return windows[p_window].vsync_mode;
  935. }
  936. void D3D12Context::set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode) {
  937. ERR_FAIL_COND_MSG(!windows.has(p_window), "Could not set V-Sync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
  938. windows[p_window].vsync_mode = p_mode;
  939. _update_swap_chain(&windows[p_window]);
  940. }
  941. RenderingDeviceDriver *D3D12Context::get_driver(RID p_local_device) {
  942. if (p_local_device.is_valid()) {
  943. LocalDevice *ld = local_device_owner.get_or_null(p_local_device);
  944. ERR_FAIL_NULL_V(ld, nullptr);
  945. return ld->driver;
  946. } else {
  947. return md.driver;
  948. }
  949. }
  950. bool D3D12Context::is_debug_utils_enabled() const {
  951. #ifdef PIX_ENABLED
  952. return true;
  953. #else
  954. return false;
  955. #endif
  956. }
  957. D3D12Context::D3D12Context() {
  958. command_list_queue.resize(1); // First one is always the setup command.
  959. command_list_queue[0] = nullptr;
  960. CharString cs = Engine::get_singleton()->get_architecture_name().ascii();
  961. memcpy(godot_nir_arch_name, (const char *)cs.get_data(), cs.size());
  962. }
  963. D3D12Context::~D3D12Context() {
  964. if (md.fence_event) {
  965. CloseHandle(md.fence_event);
  966. }
  967. if (frame_fence_event) {
  968. CloseHandle(frame_fence_event);
  969. }
  970. }