ComputeSystemDX12Impl.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2025 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <Jolt/Jolt.h>
  5. #ifdef JPH_USE_DX12
  6. #include <Jolt/Compute/DX12/ComputeSystemDX12Impl.h>
  7. #ifdef JPH_DEBUG
  8. #include <d3d12sdklayers.h>
  9. #endif
  10. JPH_NAMESPACE_BEGIN
  11. JPH_IMPLEMENT_RTTI_VIRTUAL(ComputeSystemDX12Impl)
  12. {
  13. JPH_ADD_BASE_CLASS(ComputeSystemDX12Impl, ComputeSystemDX12)
  14. }
  15. ComputeSystemDX12Impl::~ComputeSystemDX12Impl()
  16. {
  17. Shutdown();
  18. mDXGIFactory.Reset();
  19. #ifdef JPH_DEBUG
  20. // Test for leaks
  21. ComPtr<IDXGIDebug1> dxgi_debug;
  22. if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgi_debug))))
  23. dxgi_debug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL);
  24. #endif
  25. }
  26. bool ComputeSystemDX12Impl::Initialize(ComputeSystemResult &outResult)
  27. {
  28. #if defined(JPH_DEBUG)
  29. // Enable the D3D12 debug layer
  30. ComPtr<ID3D12Debug> debug_controller;
  31. if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debug_controller))))
  32. debug_controller->EnableDebugLayer();
  33. #endif
  34. // Create DXGI factory
  35. if (HRFailed(CreateDXGIFactory1(IID_PPV_ARGS(&mDXGIFactory)), outResult))
  36. return false;
  37. // Find adapter
  38. ComPtr<IDXGIAdapter1> adapter;
  39. ComPtr<ID3D12Device> device;
  40. HRESULT result = E_FAIL;
  41. // First check if we have the Windows 1803 IDXGIFactory6 interface
  42. ComPtr<IDXGIFactory6> factory6;
  43. if (SUCCEEDED(mDXGIFactory->QueryInterface(IID_PPV_ARGS(&factory6))))
  44. {
  45. for (int search_software = 0; search_software < 2 && device == nullptr; ++search_software)
  46. for (UINT index = 0; factory6->EnumAdapterByGpuPreference(index, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, IID_PPV_ARGS(&adapter)) != DXGI_ERROR_NOT_FOUND; ++index)
  47. {
  48. DXGI_ADAPTER_DESC1 desc;
  49. adapter->GetDesc1(&desc);
  50. // We don't want software renderers in the first pass
  51. int is_software = (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) != 0? 1 : 0;
  52. if (search_software != is_software)
  53. continue;
  54. // Check to see whether the adapter supports Direct3D 12
  55. #if defined(JPH_PLATFORM_WINDOWS) && defined(_DEBUG)
  56. int prev_state = _CrtSetDbgFlag(0); // Temporarily disable leak detection as this call reports false positives
  57. #endif
  58. result = D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device));
  59. #if defined(JPH_PLATFORM_WINDOWS) && defined(_DEBUG)
  60. _CrtSetDbgFlag(prev_state);
  61. #endif
  62. if (SUCCEEDED(result))
  63. break;
  64. }
  65. }
  66. else
  67. {
  68. // Fall back to the older method that may not get the fastest GPU
  69. for (int search_software = 0; search_software < 2 && device == nullptr; ++search_software)
  70. for (UINT index = 0; mDXGIFactory->EnumAdapters1(index, &adapter) != DXGI_ERROR_NOT_FOUND; ++index)
  71. {
  72. DXGI_ADAPTER_DESC1 desc;
  73. adapter->GetDesc1(&desc);
  74. // We don't want software renderers in the first pass
  75. int is_software = (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) != 0? 1 : 0;
  76. if (search_software != is_software)
  77. continue;
  78. // Check to see whether the adapter supports Direct3D 12
  79. #if defined(JPH_PLATFORM_WINDOWS) && defined(_DEBUG)
  80. int prev_state = _CrtSetDbgFlag(0); // Temporarily disable leak detection as this call reports false positives
  81. #endif
  82. result = D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device));
  83. #if defined(JPH_PLATFORM_WINDOWS) && defined(_DEBUG)
  84. _CrtSetDbgFlag(prev_state);
  85. #endif
  86. if (SUCCEEDED(result))
  87. break;
  88. }
  89. }
  90. // Check if we managed to obtain a device
  91. if (HRFailed(result, outResult))
  92. return false;
  93. // Initialize the compute interface
  94. ComputeSystemDX12::Initialize(device.Get(), EDebug::DebugSymbols);
  95. #ifdef JPH_DEBUG
  96. // Enable breaking on errors
  97. ComPtr<ID3D12InfoQueue> info_queue;
  98. if (SUCCEEDED(device.As(&info_queue)))
  99. {
  100. info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE);
  101. info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE);
  102. info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, TRUE);
  103. // Disable an error that triggers on Windows 11 with a hybrid graphic system
  104. // See: https://stackoverflow.com/questions/69805245/directx-12-application-is-crashing-in-windows-11
  105. D3D12_MESSAGE_ID hide[] =
  106. {
  107. D3D12_MESSAGE_ID_RESOURCE_BARRIER_MISMATCHING_COMMAND_LIST_TYPE,
  108. };
  109. D3D12_INFO_QUEUE_FILTER filter = { };
  110. filter.DenyList.NumIDs = static_cast<UINT>(std::size(hide));
  111. filter.DenyList.pIDList = hide;
  112. info_queue->AddStorageFilterEntries(&filter);
  113. }
  114. #endif // JPH_DEBUG
  115. return true;
  116. }
  117. ComputeSystemResult CreateComputeSystemDX12()
  118. {
  119. ComputeSystemResult result;
  120. Ref<ComputeSystemDX12Impl> compute = new ComputeSystemDX12Impl();
  121. if (!compute->Initialize(result))
  122. return result;
  123. result.Set(compute.GetPtr());
  124. return result;
  125. }
  126. JPH_NAMESPACE_END
  127. #endif // JPH_USE_DX12