GraphicsDeviceContainer.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. #include "pch.h"
  2. #include "GraphicsDevice/GraphicsDevice.h"
  3. #include "GraphicsDeviceContainer.h"
  4. #if SUPPORT_D3D11
  5. #include "GraphicsDevice/D3D12/D3D12GraphicsDevice.h"
  6. #endif
  7. #if SUPPORT_METAL
  8. #include "GraphicsDevice/Metal/MetalDevice.h"
  9. #endif
  10. #if SUPPORT_OPENGL_CORE
  11. #include "GraphicsDevice/OpenGL/OpenGLContext.h"
  12. #include <GLFW/glfw3.h>
  13. #include <sanitizer/lsan_interface.h>
  14. #endif
  15. #if SUPPORT_OPENGL_ES
  16. #include "GraphicsDevice/OpenGL/OpenGLContext.h"
  17. #endif
  18. #if SUPPORT_VULKAN
  19. #if CUDA_PLATFORM
  20. #include "GraphicsDevice/Cuda/CudaContext.h"
  21. #include "NvCodecUtils.h"
  22. #endif
  23. #include "GraphicsDevice/Vulkan/VulkanUtility.h"
  24. #endif
  25. #if _WIN32
  26. // nonstandard extension used : class rvalue used as lvalue
  27. #pragma clang diagnostic ignored "-Wlanguage-extension-token"
  28. #endif
  29. namespace unity
  30. {
  31. namespace webrtc
  32. {
  33. #if defined(SUPPORT_D3D11) // D3D11
  34. using namespace Microsoft::WRL;
  35. ComPtr<IDXGIFactory1> pFactory;
  36. ComPtr<IDXGIAdapter> pAdapter;
  37. ComPtr<ID3D11Device> pD3D11Device;
  38. ComPtr<ID3D11DeviceContext> pD3D11DeviceContext;
  39. ComPtr<IDXGIAdapter1> pAdapter1;
  40. ComPtr<IDXGIFactory4> pFactory4;
  41. ComPtr<ID3D12Device5> pD3D12Device;
  42. ComPtr<ID3D12CommandQueue> pCommandQueue;
  43. const int kD3D12NodeMask = 0;
  44. //---------------------------------------------------------------------------------------------------------------------
  45. static void* CreateDeviceD3D11()
  46. {
  47. // recycle device
  48. if (pD3D11Device.Get() != nullptr)
  49. return pD3D11Device.Get();
  50. auto hr = CreateDXGIFactory1(IID_PPV_ARGS(&pFactory));
  51. EXPECT_TRUE(SUCCEEDED(hr));
  52. EXPECT_NE(nullptr, pFactory.Get());
  53. hr = pFactory->EnumAdapters(0, pAdapter.GetAddressOf());
  54. EXPECT_TRUE(SUCCEEDED(hr));
  55. EXPECT_NE(nullptr, pAdapter.Get());
  56. hr = D3D11CreateDevice(
  57. pAdapter.Get(),
  58. D3D_DRIVER_TYPE_UNKNOWN,
  59. nullptr,
  60. 0,
  61. nullptr,
  62. 0,
  63. D3D11_SDK_VERSION,
  64. pD3D11Device.GetAddressOf(),
  65. nullptr,
  66. pD3D11DeviceContext.GetAddressOf());
  67. EXPECT_TRUE(SUCCEEDED(hr));
  68. EXPECT_NE(nullptr, pD3D11Device.Get());
  69. return pD3D11Device.Get();
  70. }
  71. // Helper function for acquiring the first available hardware adapter that supports Direct3D 12.
  72. // If no such adapter can be found, *ppAdapter will be set to nullptr.
  73. static void GetHardwareAdapter(IDXGIFactory2* pDXGIFactory2, IDXGIAdapter1** ppAdapter)
  74. {
  75. Microsoft::WRL::ComPtr<IDXGIAdapter1> adapter;
  76. *ppAdapter = nullptr;
  77. for (UINT adapterIndex = 0; DXGI_ERROR_NOT_FOUND != pDXGIFactory2->EnumAdapters1(adapterIndex, &adapter);
  78. ++adapterIndex)
  79. {
  80. DXGI_ADAPTER_DESC1 desc;
  81. adapter->GetDesc1(&desc);
  82. if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
  83. {
  84. // Don't select the Basic Render Driver adapter.
  85. // If you want a software adapter, pass in "/warp" on the command line.
  86. continue;
  87. }
  88. // Check to see if the adapter supports Direct3D 12, but don't create the
  89. // actual device yet.
  90. if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_12_0, _uuidof(ID3D12Device), nullptr)))
  91. {
  92. break;
  93. }
  94. }
  95. *ppAdapter = adapter.Detach();
  96. }
  97. static void* CreateDeviceD3D12()
  98. {
  99. auto hr = CreateDXGIFactory2(0, IID_PPV_ARGS(&pFactory4));
  100. EXPECT_TRUE(SUCCEEDED(hr));
  101. EXPECT_NE(nullptr, pFactory4.Get());
  102. GetHardwareAdapter(pFactory4.Get(), &pAdapter1);
  103. EXPECT_NE(nullptr, pAdapter1.Get());
  104. hr = D3D12CreateDevice(pAdapter1.Get(), D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(&pD3D12Device));
  105. EXPECT_TRUE(SUCCEEDED(hr));
  106. EXPECT_NE(nullptr, pD3D12Device.Get());
  107. D3D12_FEATURE_DATA_D3D12_OPTIONS3 options = {};
  108. hr = pD3D12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options, sizeof(options));
  109. EXPECT_TRUE(SUCCEEDED(hr));
  110. EXPECT_TRUE(options.WriteBufferImmediateSupportFlags & (1 << D3D12_COMMAND_LIST_TYPE_DIRECT));
  111. D3D12_COMMAND_QUEUE_DESC queueDesc = {};
  112. queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_DISABLE_GPU_TIMEOUT;
  113. queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
  114. queueDesc.NodeMask = kD3D12NodeMask;
  115. hr = pD3D12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&pCommandQueue));
  116. EXPECT_TRUE(SUCCEEDED(hr));
  117. EXPECT_NE(nullptr, pCommandQueue.Get());
  118. return pD3D12Device.Get();
  119. }
  120. #endif
  121. #if defined(SUPPORT_VULKAN) // Vulkan
  122. static LIBRARY_TYPE s_library = nullptr;
  123. static bool LoadVulkanModule()
  124. {
  125. if (!LoadVulkanLibrary(s_library))
  126. return false;
  127. if (!LoadExportedVulkanFunction(s_library))
  128. return false;
  129. return LoadGlobalVulkanFunction();
  130. }
  131. static int32_t
  132. GetPhysicalDeviceIndex(VkInstance instance, std::vector<VkPhysicalDevice>& list, bool findCudaDevice, bool* found)
  133. {
  134. std::array<uint8_t, VK_UUID_SIZE> deviceUUID;
  135. for (size_t i = 0; i < list.size(); ++i)
  136. {
  137. VkPhysicalDevice physicalDevice = list[i];
  138. if (!VulkanUtility::GetPhysicalDeviceUUIDInto(instance, physicalDevice, &deviceUUID))
  139. {
  140. continue;
  141. }
  142. #if CUDA_PLATFORM
  143. if (findCudaDevice && CudaContext::FindCudaDevice(deviceUUID.data(), nullptr) != CUDA_SUCCESS)
  144. {
  145. continue;
  146. }
  147. #endif
  148. *found = true;
  149. return static_cast<int32_t>(i);
  150. }
  151. *found = false;
  152. return 0;
  153. }
  154. static void* CreateDeviceVulkan()
  155. {
  156. // Extension
  157. std::vector<const char*> instanceExtensions =
  158. {
  159. VK_KHR_SURFACE_EXTENSION_NAME,
  160. #ifdef _WIN32
  161. VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
  162. #endif
  163. #if defined(_DEBUG)
  164. VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
  165. #endif
  166. VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
  167. };
  168. std::vector<const char*> deviceExtensions = {
  169. #ifndef _WIN32
  170. VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME
  171. #else
  172. VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, // vkGetMemoryWin32HandleKHR()
  173. VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME
  174. #endif
  175. };
  176. VkApplicationInfo appInfo {};
  177. appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
  178. appInfo.pApplicationName = "test";
  179. #if UNITY_ANDROID
  180. // Android platform doesn't support vulkan api version 1.1.
  181. appInfo.apiVersion = VK_API_VERSION_1_0;
  182. #else
  183. appInfo.apiVersion = VK_API_VERSION_1_1;
  184. #endif
  185. appInfo.engineVersion = 1;
  186. if (!LoadVulkanModule())
  187. {
  188. RTC_LOG(LS_INFO) << "failed loading vulkan module";
  189. return nullptr;
  190. }
  191. VkInstanceCreateInfo instanceInfo {};
  192. instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
  193. instanceInfo.enabledExtensionCount = static_cast<uint32_t>(instanceExtensions.size());
  194. instanceInfo.ppEnabledExtensionNames = instanceExtensions.data();
  195. instanceInfo.pApplicationInfo = &appInfo;
  196. VkInstance instance = nullptr;
  197. VkResult result = vkCreateInstance(&instanceInfo, nullptr, &instance);
  198. if (result != VK_SUCCESS)
  199. {
  200. RTC_LOG(LS_INFO) << "vkCreateInstance failed. error:" << result;
  201. return nullptr;
  202. }
  203. if (!LoadInstanceVulkanFunction(instance))
  204. {
  205. RTC_LOG(LS_INFO) << "LoadInstanceVulkanFunction failed";
  206. return nullptr;
  207. }
  208. // create physical device
  209. uint32_t devCount = 0;
  210. result = vkEnumeratePhysicalDevices(instance, &devCount, nullptr);
  211. if (result != VK_SUCCESS)
  212. {
  213. RTC_LOG(LS_INFO) << "vkEnumeratePhysicalDevices failed. error:" << result;
  214. return nullptr;
  215. }
  216. std::vector<VkPhysicalDevice> physicalDeviceList(devCount);
  217. result = vkEnumeratePhysicalDevices(instance, &devCount, physicalDeviceList.data());
  218. if (result != VK_SUCCESS)
  219. {
  220. RTC_LOG(LS_INFO) << "vkEnumeratePhysicalDevices failed. error:" << result;
  221. return nullptr;
  222. }
  223. if (!VulkanUtility::LoadInstanceFunctions(instance))
  224. {
  225. return nullptr;
  226. }
  227. bool found = false;
  228. // todo:: Add test pattern for HWA codecs.
  229. bool findCudaDevice = false;
  230. int32_t physicalDeviceIndex = GetPhysicalDeviceIndex(instance, physicalDeviceList, findCudaDevice, &found);
  231. if (!found)
  232. {
  233. RTC_LOG(LS_INFO) << "GetPhysicalDeviceIndex device not found.";
  234. return nullptr;
  235. }
  236. const VkPhysicalDevice physicalDevice = physicalDeviceList[static_cast<size_t>(physicalDeviceIndex)];
  237. VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
  238. vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties);
  239. // create logical device
  240. uint32_t extensionCount = 0;
  241. result = vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr);
  242. if (result != VK_SUCCESS)
  243. {
  244. RTC_LOG(LS_INFO) << "vkEnumerateDeviceExtensionProperties failed. error:" << result;
  245. return nullptr;
  246. }
  247. std::vector<VkExtensionProperties> extensionPropertiesList(extensionCount);
  248. result = vkEnumerateDeviceExtensionProperties(
  249. physicalDevice, nullptr, &extensionCount, extensionPropertiesList.data());
  250. if (result != VK_SUCCESS)
  251. {
  252. RTC_LOG(LS_INFO) << "vkEnumerateDeviceExtensionProperties failed. error:" << result;
  253. return nullptr;
  254. }
  255. std::vector<const char*> availableExtensions;
  256. for (const auto& v : extensionPropertiesList)
  257. {
  258. availableExtensions.push_back(v.extensionName);
  259. }
  260. // queueFamilyIndex
  261. uint32_t propertiesCount = 0;
  262. vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &propertiesCount, nullptr);
  263. std::vector<VkQueueFamilyProperties> properies(propertiesCount);
  264. vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &propertiesCount, properies.data());
  265. uint32_t queueFamilyIndex = 0;
  266. for (uint32_t i = 0; i < propertiesCount; i++)
  267. {
  268. if (properies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
  269. {
  270. queueFamilyIndex = i;
  271. break;
  272. }
  273. }
  274. // create device queue create info
  275. const float defaultQueuePriority = 1.0f;
  276. VkDeviceQueueCreateInfo deviceQueueCreateInfo = {};
  277. deviceQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
  278. deviceQueueCreateInfo.queueFamilyIndex = queueFamilyIndex;
  279. deviceQueueCreateInfo.pNext = nullptr;
  280. deviceQueueCreateInfo.queueCount = 1;
  281. deviceQueueCreateInfo.pQueuePriorities = &defaultQueuePriority;
  282. // create device create info
  283. VkDeviceCreateInfo deviceCreateInfo = {};
  284. deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
  285. deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data();
  286. deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
  287. deviceCreateInfo.pQueueCreateInfos = &deviceQueueCreateInfo;
  288. deviceCreateInfo.queueCreateInfoCount = 1;
  289. VkDevice device;
  290. result = vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device);
  291. if (result != VK_SUCCESS)
  292. {
  293. RTC_LOG(LS_INFO) << "vkCreateDevice failed. error:" << result;
  294. return nullptr;
  295. }
  296. if (!LoadDeviceVulkanFunction(device))
  297. {
  298. RTC_LOG(LS_INFO) << "Failed loading vulkan module";
  299. return nullptr;
  300. }
  301. VkQueue queue;
  302. vkGetDeviceQueue(device, queueFamilyIndex, 0, &queue);
  303. UnityVulkanInstance* pVkInstance = new UnityVulkanInstance;
  304. pVkInstance->instance = instance;
  305. pVkInstance->physicalDevice = physicalDevice;
  306. pVkInstance->device = device;
  307. pVkInstance->queueFamilyIndex = queueFamilyIndex;
  308. pVkInstance->graphicsQueue = queue;
  309. return pVkInstance;
  310. }
  311. static void DestroyDeviceVulkan(void* pGfxDevice)
  312. {
  313. UnityVulkanInstance* pVkInstance = static_cast<UnityVulkanInstance*>(pGfxDevice);
  314. vkDestroyDevice(pVkInstance->device, nullptr);
  315. delete pVkInstance;
  316. pVkInstance = nullptr;
  317. }
  318. #endif
  319. #if SUPPORT_METAL
  320. static void* CreateDeviceMetal() { return MetalDevice::CreateForTest().release(); }
  321. static void DestroyDeviceMetalDevice(void* ptr)
  322. {
  323. MetalDevice* device = static_cast<MetalDevice*>(ptr);
  324. delete device;
  325. }
  326. #endif
  327. #if SUPPORT_OPENGL_CORE
  328. static bool s_glfwInitialized;
  329. static GLFWwindow* s_window;
  330. static void* CreateDeviceGLCore()
  331. {
  332. if (!s_glfwInitialized)
  333. {
  334. glfwInit();
  335. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  336. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
  337. glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  338. const GLuint kWidth = 320;
  339. const GLuint kHeight = 240;
  340. __lsan_disable();
  341. s_window = glfwCreateWindow(kWidth, kHeight, "test", nullptr, nullptr);
  342. __lsan_enable();
  343. glfwMakeContextCurrent(s_window);
  344. s_glfwInitialized = true;
  345. }
  346. OpenGLContext::Init();
  347. std::unique_ptr<OpenGLContext> context = OpenGLContext::CreateGLContext();
  348. return context.release();
  349. }
  350. static void DestroyDeviceGLCore(void* pGfxDevice)
  351. {
  352. OpenGLContext* context = static_cast<OpenGLContext*>(pGfxDevice);
  353. delete context;
  354. glfwSetWindowShouldClose(s_window, GL_TRUE);
  355. glfwTerminate();
  356. s_glfwInitialized = false;
  357. }
  358. #endif
  359. #if SUPPORT_OPENGL_ES
  360. static void* CreateDeviceGLES()
  361. {
  362. OpenGLContext::Init();
  363. std::unique_ptr<OpenGLContext> context = OpenGLContext::CreateGLContext();
  364. return context.release();
  365. }
  366. static void DestroyDeviceGLES(void* pGfxDevice)
  367. {
  368. OpenGLContext* context = static_cast<OpenGLContext*>(pGfxDevice);
  369. delete context;
  370. }
  371. #endif
  372. //---------------------------------------------------------------------------------------------------------------------
  373. static void* CreateNativeGfxDevice(UnityGfxRenderer renderer)
  374. {
  375. switch (renderer)
  376. {
  377. #if SUPPORT_D3D11
  378. case kUnityGfxRendererD3D11:
  379. return CreateDeviceD3D11();
  380. #endif
  381. #if SUPPORT_D3D12
  382. case kUnityGfxRendererD3D12:
  383. return CreateDeviceD3D12();
  384. #endif
  385. #if SUPPORT_OPENGL_CORE
  386. case kUnityGfxRendererOpenGLCore:
  387. return CreateDeviceGLCore();
  388. #endif
  389. #if SUPPORT_OPENGL_ES
  390. case kUnityGfxRendererOpenGLES20:
  391. case kUnityGfxRendererOpenGLES30:
  392. return CreateDeviceGLES();
  393. #endif
  394. #if SUPPORT_VULKAN
  395. case kUnityGfxRendererVulkan:
  396. return CreateDeviceVulkan();
  397. #endif
  398. #if SUPPORT_METAL
  399. case kUnityGfxRendererMetal:
  400. return CreateDeviceMetal();
  401. #endif
  402. default:
  403. return nullptr;
  404. }
  405. }
  406. //---------------------------------------------------------------------------------------------------------------------
  407. static void DestroyNativeGfxDevice(void* pGfxDevice, UnityGfxRenderer renderer)
  408. {
  409. switch (renderer)
  410. {
  411. #if SUPPORT_D3D11
  412. case kUnityGfxRendererD3D11:
  413. return;
  414. #endif
  415. #if SUPPORT_D3D12
  416. case kUnityGfxRendererD3D12:
  417. return;
  418. #endif
  419. #if SUPPORT_OPENGL_CORE
  420. case kUnityGfxRendererOpenGLCore:
  421. DestroyDeviceGLCore(pGfxDevice);
  422. return;
  423. #endif
  424. #if SUPPORT_OPENGL_ES
  425. case kUnityGfxRendererOpenGLES20:
  426. case kUnityGfxRendererOpenGLES30:
  427. DestroyDeviceGLES(pGfxDevice);
  428. return;
  429. #endif
  430. #if SUPPORT_VULKAN
  431. case kUnityGfxRendererVulkan:
  432. DestroyDeviceVulkan(pGfxDevice);
  433. return;
  434. #endif
  435. #if SUPPORT_METAL
  436. case kUnityGfxRendererMetal:
  437. DestroyDeviceMetalDevice(pGfxDevice);
  438. return;
  439. #endif
  440. default:
  441. return;
  442. }
  443. }
  444. GraphicsDeviceContainer::GraphicsDeviceContainer(UnityGfxRenderer renderer)
  445. : device_(nullptr)
  446. , nativeGfxDevice_(nullptr)
  447. {
  448. nativeGfxDevice_ = CreateNativeGfxDevice(renderer);
  449. renderer_ = renderer;
  450. // native graphics device is not initialized.
  451. if (!nativeGfxDevice_)
  452. return;
  453. IGraphicsDevice* device = nullptr;
  454. if (renderer == kUnityGfxRendererD3D12)
  455. {
  456. #if defined(SUPPORT_D3D12)
  457. device =
  458. new D3D12GraphicsDevice(static_cast<ID3D12Device*>(nativeGfxDevice_), pCommandQueue.Get(), renderer, nullptr);
  459. #endif
  460. }
  461. else
  462. {
  463. device = GraphicsDevice::GetInstance().Init(renderer, nativeGfxDevice_, nullptr, nullptr);
  464. }
  465. device_ = std::unique_ptr<IGraphicsDevice>(device);
  466. EXPECT_TRUE(device_->InitV());
  467. }
  468. GraphicsDeviceContainer::~GraphicsDeviceContainer()
  469. {
  470. if (device_)
  471. device_->ShutdownV();
  472. if (nativeGfxDevice_)
  473. DestroyNativeGfxDevice(nativeGfxDevice_, renderer_);
  474. }
  475. std::unique_ptr<GraphicsDeviceContainer> CreateGraphicsDeviceContainer(UnityGfxRenderer renderer)
  476. {
  477. return std::make_unique<GraphicsDeviceContainer>(renderer);
  478. }
  479. }
  480. }