NvVulkanRenderer.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. /*
  2. * Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of NVIDIA CORPORATION nor the names of its
  13. * contributors may be used to endorse or promote products derived
  14. * from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  19. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  20. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  21. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  22. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  23. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  24. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  26. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #include "NvVulkanRenderer.h"
  29. #include "NvLogging.h"
  30. #include "nvbufsurface.h"
  31. #include <unistd.h>
  32. #include <vector>
  33. #include <bitset>
  34. #include <set>
  35. #include <vulkan/vulkan_xlib.h>
  36. #include <X11/Xlib.h>
  37. #include <X11/Xutil.h>
  38. #define CAT_NAME "VulkanRenderer"
  39. using namespace std;
  40. #define VK_CHECK(f) \
  41. do { \
  42. const VkResult result = (f); \
  43. if (result != VK_SUCCESS) { \
  44. printf("Abort. %s failed at %s:%d. Result = %d\n", #f, __FILE__, __LINE__, result); \
  45. abort(); \
  46. } \
  47. } while (false)
  48. #define CHECK(f) \
  49. do { \
  50. if (!(f)) { \
  51. printf("Abort. %s failed at %s:%d\n", #f, __FILE__, __LINE__); \
  52. abort(); \
  53. } \
  54. } while (false)
  55. NvVulkanRenderer::NvVulkanRenderer(const char *name, uint32_t width, uint32_t height,
  56. uint32_t x_offset, uint32_t y_offset)
  57. : NvElement(name, valid_fields)
  58. {
  59. m_XWindow = 0;
  60. m_XDisplay = NULL;
  61. XInitThreads();
  62. m_XDisplay = XOpenDisplay(NULL);
  63. long visualMask = VisualScreenMask;
  64. int numberOfVisuals;
  65. XVisualInfo vInfoTemplate = {};
  66. vInfoTemplate.screen = DefaultScreen(m_XDisplay);
  67. XVisualInfo *visualInfo = XGetVisualInfo(m_XDisplay, visualMask, &vInfoTemplate, &numberOfVisuals);
  68. Colormap colormap =
  69. XCreateColormap(m_XDisplay, RootWindow(m_XDisplay, vInfoTemplate.screen), visualInfo->visual, AllocNone);
  70. XSetWindowAttributes windowAttributes = {};
  71. windowAttributes.colormap = colormap;
  72. windowAttributes.background_pixel = 0xFFFFFFFF;
  73. windowAttributes.border_pixel = 0;
  74. windowAttributes.event_mask = KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask;
  75. m_XWindow = XCreateWindow(m_XDisplay, RootWindow(m_XDisplay, vInfoTemplate.screen), 0, 0, width,
  76. height, 0, visualInfo->depth, InputOutput, visualInfo->visual,
  77. CWBackPixel | CWBorderPixel | CWEventMask | CWColormap, &windowAttributes);
  78. CHECK(m_XWindow);
  79. XSelectInput(m_XDisplay, m_XWindow, ExposureMask | KeyPressMask);
  80. XMapWindow(m_XDisplay, m_XWindow);
  81. XFlush(m_XDisplay);
  82. // We allocate memory everytime for vkImage binded to foreign FD, destroy the image which is already presented
  83. // for which we keep track of older image memory.
  84. m_vkImageMemoryIndex = -1;
  85. m_oldImageIndex = -1;
  86. }
  87. NvVulkanRenderer*
  88. NvVulkanRenderer::createVulkanRenderer(const char *name, uint32_t width,
  89. uint32_t height, uint32_t x_offset,
  90. uint32_t y_offset)
  91. {
  92. NvVulkanRenderer *renderer = new NvVulkanRenderer(name, width, height,
  93. x_offset, y_offset);
  94. if (renderer->isInError())
  95. {
  96. delete renderer;
  97. return NULL;
  98. }
  99. return renderer;
  100. }
  101. void
  102. NvVulkanRenderer::initVulkan()
  103. {
  104. createInstance();
  105. createSurface();
  106. getPhysicalDevice();
  107. getQueueFamilies();
  108. createDevice();
  109. createSwapChain();
  110. createCommandPool();
  111. createCommandBuffer();
  112. createSyncObjects();
  113. }
  114. #ifdef USE_VALIDATION
  115. static
  116. VKAPI_ATTR VkBool32 VKAPI_CALL debugUtilsCallback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type,
  117. const VkDebugUtilsMessengerCallbackDataEXT* callback_data, void* user_data)
  118. {
  119. if (message_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
  120. COMP_WARN_MSG("Vulkan warning ");
  121. } else if (message_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
  122. COMP_ERROR_MSG("Vulkan error");
  123. } else {
  124. return VK_FALSE;
  125. }
  126. printf("(%d)\n%s\n%s\n\n", callback_data->messageIdNumber, callback_data->pMessageIdName, callback_data->pMessage);
  127. return VK_FALSE;
  128. }
  129. #endif
  130. static
  131. MemoryTypeResult findMemoryType(VkPhysicalDevice physicalDevice, uint32_t typeFilter, VkMemoryPropertyFlags properties)
  132. {
  133. VkPhysicalDeviceMemoryProperties memoryProperties;
  134. vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
  135. MemoryTypeResult result;
  136. result.found = false;
  137. for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; ++i) {
  138. if ((typeFilter & (1 << i)) && (memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) {
  139. result.typeIndex = i;
  140. result.found = true;
  141. break;
  142. }
  143. }
  144. return result;
  145. }
  146. void
  147. NvVulkanRenderer::createSurface()
  148. {
  149. VkXlibSurfaceCreateInfoKHR createInfo;
  150. createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
  151. createInfo.pNext = NULL;
  152. createInfo.flags = 0;
  153. createInfo.dpy = m_XDisplay;
  154. createInfo.window = m_XWindow;
  155. VK_CHECK(vkCreateXlibSurfaceKHR(m_instance, &createInfo, NULL, &m_surface));
  156. COMP_INFO_MSG("Vulkan surface created\n");
  157. }
  158. void
  159. NvVulkanRenderer::createInstance()
  160. {
  161. VkApplicationInfo appInfo{};
  162. appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
  163. appInfo.pApplicationName = "Sample";
  164. appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
  165. appInfo.pEngineName = "";
  166. appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
  167. appInfo.apiVersion = VK_API_VERSION_1_2;
  168. #ifdef USE_VALIDATION
  169. VkDebugUtilsMessengerCreateInfoEXT debugUtilsCreateInfo{};
  170. debugUtilsCreateInfo.pNext = nullptr;
  171. debugUtilsCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
  172. debugUtilsCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
  173. debugUtilsCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
  174. debugUtilsCreateInfo.pfnUserCallback = debugUtilsCallback;
  175. debugUtilsCreateInfo.pUserData = nullptr;
  176. const std::vector<VkValidationFeatureEnableEXT> enabledFeatures{
  177. VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, //
  178. VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT, //
  179. // VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT, //
  180. // VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT, //
  181. VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT, //
  182. };
  183. VkValidationFeaturesEXT validationFeatures{};
  184. validationFeatures.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
  185. validationFeatures.pNext = &debugUtilsCreateInfo;
  186. validationFeatures.enabledValidationFeatureCount = ui32Size(enabledFeatures);
  187. validationFeatures.pEnabledValidationFeatures = enabledFeatures.data();
  188. validationFeatures.disabledValidationFeatureCount = 0;
  189. validationFeatures.pDisabledValidationFeatures = nullptr;
  190. const std::string validationLayerName = "VK_LAYER_KHRONOS_validation";
  191. std::vector<const char*> enabledLayers{validationLayerName.c_str()};
  192. void* pNext = &validationFeatures;
  193. #else
  194. std::vector<const char*> enabledLayers{};
  195. void* pNext = nullptr;
  196. #endif
  197. VkInstanceCreateInfo instanceCreateInfo{};
  198. instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
  199. instanceCreateInfo.pApplicationInfo = &appInfo;
  200. instanceCreateInfo.enabledExtensionCount = ui32Size(m_instanceExtensions);
  201. instanceCreateInfo.ppEnabledExtensionNames = m_instanceExtensions.data();
  202. instanceCreateInfo.enabledLayerCount = ui32Size(enabledLayers);
  203. instanceCreateInfo.ppEnabledLayerNames = enabledLayers.data();
  204. instanceCreateInfo.pNext = pNext;
  205. VK_CHECK(vkCreateInstance(&instanceCreateInfo, nullptr, &m_instance));
  206. #ifdef USE_VALIDATION
  207. auto vkCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(m_instance, "vkCreateDebugUtilsMessengerEXT");
  208. if (vkCreateDebugUtilsMessengerEXT) {
  209. VK_CHECK(vkCreateDebugUtilsMessengerEXT(m_instance, &debugUtilsCreateInfo, nullptr, &m_debugMessenger));
  210. }
  211. #endif
  212. COMP_INFO_MSG("Vulkan instance created");
  213. }
  214. PFN_vkVoidFunction NvVulkanRenderer::getInstanceFunction(VkInstance instance, const char* name)
  215. {
  216. PFN_vkVoidFunction f = vkGetInstanceProcAddr(instance, name);
  217. if (f == nullptr) {
  218. COMP_ERROR_MSG("Could not get instance function pointer");
  219. fprintf(stderr, "%s", name);
  220. }
  221. return f;
  222. }
  223. void
  224. NvVulkanRenderer::getPhysicalDevice()
  225. {
  226. uint32_t deviceCount = 0;
  227. vkEnumeratePhysicalDevices(m_instance, &deviceCount, nullptr);
  228. CHECK(deviceCount);
  229. std::vector<VkPhysicalDevice> devices(deviceCount);
  230. vkEnumeratePhysicalDevices(m_instance, &deviceCount, devices.data());
  231. m_physicalDevice = devices[0];
  232. CHECK(m_physicalDevice != VK_NULL_HANDLE);
  233. }
  234. void
  235. NvVulkanRenderer::getQueueFamilies()
  236. {
  237. uint32_t queueFamilyCount = 0;
  238. vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueFamilyCount, nullptr);
  239. std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
  240. vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &queueFamilyCount, queueFamilies.data());
  241. QueueFamilyIndices indices;
  242. for (unsigned int i = 0; i < queueFamilies.size(); ++i) {
  243. if (queueFamilies[i].queueCount > 0 && queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
  244. indices.graphicsFamily = i;
  245. }
  246. if (queueFamilies[i].queueCount > 0 && queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT) {
  247. indices.computeFamily = i;
  248. }
  249. VkBool32 presentSupport = false;
  250. vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, i, m_surface, &presentSupport);
  251. if (presentSupport) {
  252. indices.presentFamily = i;
  253. }
  254. }
  255. m_queueFamilyIndices = indices;
  256. }
  257. void
  258. NvVulkanRenderer::createDevice()
  259. {
  260. const std::set<int> uniqueQueueFamilies = {m_queueFamilyIndices.graphicsFamily, m_queueFamilyIndices.computeFamily,
  261. m_queueFamilyIndices.presentFamily};
  262. std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
  263. const float queuePriority = 1.0f;
  264. for (int queueFamily : uniqueQueueFamilies) {
  265. VkDeviceQueueCreateInfo queueCreateInfo{};
  266. queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
  267. queueCreateInfo.queueFamilyIndex = queueFamily;
  268. queueCreateInfo.queueCount = 1;
  269. queueCreateInfo.pQueuePriorities = &queuePriority;
  270. queueCreateInfos.push_back(queueCreateInfo);
  271. }
  272. VkPhysicalDeviceFeatures deviceFeatures{};
  273. VkPhysicalDeviceVulkan12Features device12Features{};
  274. device12Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
  275. VkDeviceCreateInfo createInfo{};
  276. createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
  277. createInfo.pNext = &device12Features;
  278. createInfo.queueCreateInfoCount = ui32Size(queueCreateInfos);
  279. createInfo.pQueueCreateInfos = queueCreateInfos.data();
  280. createInfo.pEnabledFeatures = &deviceFeatures;
  281. createInfo.enabledExtensionCount = ui32Size(m_deviceExtensions);
  282. createInfo.ppEnabledExtensionNames = m_deviceExtensions.data();
  283. createInfo.enabledLayerCount = ui32Size(m_validationLayers);
  284. createInfo.ppEnabledLayerNames = m_validationLayers.data();
  285. VK_CHECK(vkCreateDevice(m_physicalDevice, &createInfo, nullptr, &m_device));
  286. vkGetDeviceQueue(m_device, m_queueFamilyIndices.graphicsFamily, 0, &m_graphicsQueue);
  287. vkGetDeviceQueue(m_device, m_queueFamilyIndices.presentFamily, 0, &m_presentQueue);
  288. COMP_INFO_MSG("Vulkan device created\n");
  289. }
  290. void
  291. NvVulkanRenderer::setSize(uint32_t width, uint32_t height)
  292. {
  293. m_windowWidth = width;
  294. m_windowHeight = height;
  295. return;
  296. }
  297. static
  298. VkSurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {
  299. for (const auto& availableFormat : availableFormats) {
  300. if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
  301. return availableFormat;
  302. }
  303. }
  304. return availableFormats[0];
  305. }
  306. static
  307. VkPresentModeKHR chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) {
  308. for (const auto& availablePresentMode : availablePresentModes) {
  309. if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
  310. return availablePresentMode;
  311. }
  312. }
  313. return VK_PRESENT_MODE_FIFO_KHR;
  314. }
  315. static
  316. VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, uint32_t width, uint32_t height) {
  317. if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
  318. return capabilities.currentExtent;
  319. } else {
  320. VkExtent2D actualExtent = {
  321. static_cast<uint32_t>(width),
  322. static_cast<uint32_t>(height)
  323. };
  324. #define CLAMP(x, min, max) \
  325. x = x > max ? max : x; \
  326. x = x < min ? min : x;
  327. CLAMP(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
  328. CLAMP(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
  329. #undef CLAMP
  330. return actualExtent;
  331. }
  332. }
  333. static
  334. SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device, VkSurfaceKHR surface) {
  335. SwapChainSupportDetails details;
  336. vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
  337. uint32_t formatCount;
  338. vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
  339. if (formatCount != 0) {
  340. details.formats.resize(formatCount);
  341. vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
  342. }
  343. uint32_t presentModeCount;
  344. vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
  345. if (presentModeCount != 0) {
  346. details.presentModes.resize(presentModeCount);
  347. vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
  348. }
  349. return details;
  350. }
  351. void
  352. NvVulkanRenderer::createSwapChain()
  353. {
  354. SwapChainSupportDetails swapChainSupport = querySwapChainSupport(m_physicalDevice, m_surface);
  355. VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
  356. VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
  357. VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities, m_windowWidth, m_windowHeight);
  358. uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
  359. if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
  360. imageCount = swapChainSupport.capabilities.maxImageCount;
  361. }
  362. VkSwapchainCreateInfoKHR createInfo{};
  363. createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
  364. createInfo.surface = m_surface;
  365. createInfo.minImageCount = imageCount;
  366. createInfo.imageFormat = surfaceFormat.format;
  367. createInfo.imageColorSpace = surfaceFormat.colorSpace;
  368. createInfo.imageExtent = extent;
  369. createInfo.imageArrayLayers = 1;
  370. createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  371. uint32_t queueFamilyIndices[] = {(uint32_t)m_queueFamilyIndices.graphicsFamily, (uint32_t)m_queueFamilyIndices.presentFamily};
  372. if (m_queueFamilyIndices.graphicsFamily != m_queueFamilyIndices.presentFamily) {
  373. createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
  374. createInfo.queueFamilyIndexCount = 2;
  375. createInfo.pQueueFamilyIndices = queueFamilyIndices;
  376. } else {
  377. createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
  378. }
  379. createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
  380. createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
  381. createInfo.presentMode = presentMode;
  382. createInfo.clipped = VK_TRUE;
  383. VK_CHECK(vkCreateSwapchainKHR(m_device, &createInfo, nullptr, &m_swapChain));
  384. vkGetSwapchainImagesKHR(m_device, m_swapChain, &imageCount, nullptr);
  385. m_swapChainImages.resize(imageCount);
  386. m_vkImageMemory.resize(imageCount);
  387. vkGetSwapchainImagesKHR(m_device, m_swapChain, &imageCount, m_swapChainImages.data());
  388. m_swapChainImageFormat = surfaceFormat.format;
  389. m_swapChainExtent = extent;
  390. COMP_INFO_MSG("Vulkan swapchain created");
  391. }
  392. void
  393. NvVulkanRenderer::createCommandBuffer() {
  394. VkCommandBufferAllocateInfo allocInfo{};
  395. allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
  396. allocInfo.commandPool = m_commandPool;
  397. allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
  398. allocInfo.commandBufferCount = 1;
  399. VK_CHECK(vkAllocateCommandBuffers(m_device, &allocInfo, &m_commandBuffer));
  400. }
  401. void
  402. NvVulkanRenderer::createSyncObjects() {
  403. VkSemaphoreCreateInfo semaphoreInfo{};
  404. semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
  405. VkFenceCreateInfo fenceInfo{};
  406. fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
  407. fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
  408. VK_CHECK(vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_imageAvailableSemaphore));
  409. VK_CHECK(vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_renderFinishedSemaphore));
  410. VK_CHECK(vkCreateFence(m_device, &fenceInfo, nullptr, &m_inFlightFence));
  411. }
  412. void
  413. NvVulkanRenderer::createCommandPool() {
  414. VkCommandPoolCreateInfo poolInfo{};
  415. poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
  416. poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
  417. poolInfo.queueFamilyIndex = m_queueFamilyIndices.graphicsFamily;
  418. VK_CHECK(vkCreateCommandPool(m_device, &poolInfo, nullptr, &m_commandPool));
  419. }
  420. void
  421. NvVulkanRenderer::recordCommandBuffer(VkImage image, uint32_t imageIndex)
  422. {
  423. VkCommandBufferBeginInfo beginInfo{};
  424. beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  425. VK_CHECK(vkBeginCommandBuffer(m_commandBuffer, &beginInfo));
  426. VkImageCopy copyRegion{};
  427. copyRegion.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
  428. copyRegion.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
  429. copyRegion.extent = {m_windowWidth, m_windowHeight, 1};
  430. copyRegion.srcOffset = {0, 0, 0};
  431. copyRegion.dstOffset = {0, 0, 0};
  432. vkCmdCopyImage(
  433. m_commandBuffer, image, VK_IMAGE_LAYOUT_GENERAL, m_swapChainImages[imageIndex], VK_IMAGE_LAYOUT_GENERAL, 1, &copyRegion);
  434. VK_CHECK(vkEndCommandBuffer(m_commandBuffer));
  435. }
  436. void
  437. NvVulkanRenderer::displayFrame(VkImage image)
  438. {
  439. VkResult err;
  440. VK_CHECK(vkWaitForFences(m_device, 1, &m_inFlightFence, VK_TRUE, UINT64_MAX));
  441. VK_CHECK(vkResetFences(m_device, 1, &m_inFlightFence));
  442. uint32_t imageIndex;
  443. err = vkAcquireNextImageKHR(m_device, m_swapChain, UINT64_MAX, m_imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
  444. if (err != VK_SUBOPTIMAL_KHR)
  445. {
  446. /* m_swapChain is not as optimal as it could be, but the platform's presentation engine
  447. * will still present the image correctly, hence do not fail on VK_SUBOPTIMAL_KHR */
  448. VK_CHECK(err);
  449. }
  450. VK_CHECK(vkResetCommandBuffer(m_commandBuffer, /*VkCommandBufferResetFlagBits*/ 0));
  451. recordCommandBuffer(image, imageIndex);
  452. VkSubmitInfo submitInfo{};
  453. submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
  454. VkSemaphore waitSemaphores[] = {m_imageAvailableSemaphore};
  455. VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
  456. submitInfo.waitSemaphoreCount = 1;
  457. submitInfo.pWaitSemaphores = waitSemaphores;
  458. submitInfo.pWaitDstStageMask = waitStages;
  459. submitInfo.commandBufferCount = 1;
  460. submitInfo.pCommandBuffers = &m_commandBuffer;
  461. VkSemaphore signalSemaphores[] = {m_renderFinishedSemaphore};
  462. submitInfo.signalSemaphoreCount = 1;
  463. submitInfo.pSignalSemaphores = signalSemaphores;
  464. VK_CHECK(vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, m_inFlightFence));
  465. VkPresentInfoKHR presentInfo{};
  466. presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
  467. presentInfo.waitSemaphoreCount = 1;
  468. presentInfo.pWaitSemaphores = signalSemaphores;
  469. VkSwapchainKHR swapChains[] = {m_swapChain};
  470. presentInfo.swapchainCount = 1;
  471. presentInfo.pSwapchains = swapChains;
  472. presentInfo.pImageIndices = &imageIndex;
  473. err = vkQueuePresentKHR(m_presentQueue, &presentInfo);
  474. if (err == VK_SUBOPTIMAL_KHR)
  475. {
  476. /* m_swapChain is not as optimal as it could be, but the platform's presentation engine
  477. * will still present the image correctly, hence do not fail on VK_SUBOPTIMAL_KHR */
  478. } else if (err == VK_ERROR_SURFACE_LOST_KHR) {
  479. /* Should we attempt to do something here or on hotplug detection? */
  480. } else {
  481. VK_CHECK(err);
  482. }
  483. }
  484. void
  485. NvVulkanRenderer::createVkImageFromFd(int fd)
  486. {
  487. COMP_DEBUG_MSG("\nCreating vk image from fd");
  488. VkImage vkImage;
  489. uint32_t width = m_windowWidth;
  490. uint32_t height = m_windowHeight;
  491. { // create vk image
  492. VkExternalMemoryImageCreateInfo dmaBufExternalMemoryImageCreateInfo{};
  493. dmaBufExternalMemoryImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
  494. dmaBufExternalMemoryImageCreateInfo.pNext = nullptr;
  495. dmaBufExternalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
  496. VkImageCreateInfo dmaBufImageCreateInfo{};
  497. dmaBufImageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
  498. dmaBufImageCreateInfo.pNext = &dmaBufExternalMemoryImageCreateInfo;
  499. dmaBufImageCreateInfo.flags = 0;
  500. dmaBufImageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
  501. dmaBufImageCreateInfo.format = m_imageFormat;
  502. dmaBufImageCreateInfo.extent = {static_cast<uint32_t>(width), static_cast<uint32_t>(height), 1};
  503. dmaBufImageCreateInfo.mipLevels = 1;
  504. dmaBufImageCreateInfo.arrayLayers = 1;
  505. dmaBufImageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
  506. dmaBufImageCreateInfo.tiling = m_imageTiling;
  507. dmaBufImageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
  508. dmaBufImageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  509. dmaBufImageCreateInfo.queueFamilyIndexCount = 0;
  510. dmaBufImageCreateInfo.pQueueFamilyIndices = nullptr;
  511. dmaBufImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // NOTE Check spec once more!
  512. VK_CHECK(vkCreateImage(m_device, &dmaBufImageCreateInfo, nullptr, &vkImage));
  513. }
  514. { // allocate and bind
  515. const int duppedFd = dup(fd);
  516. (void)(duppedFd);
  517. auto vkGetMemoryFdPropertiesKHR = (PFN_vkGetMemoryFdPropertiesKHR)getInstanceFunction(m_instance, "vkGetMemoryFdPropertiesKHR");
  518. CHECK(vkGetMemoryFdPropertiesKHR);
  519. VkMemoryFdPropertiesKHR dmaBufMemoryProperties{};
  520. dmaBufMemoryProperties.sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR;
  521. dmaBufMemoryProperties.pNext = nullptr;
  522. VK_CHECK(vkGetMemoryFdPropertiesKHR(m_device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, duppedFd, &dmaBufMemoryProperties));
  523. string str = "Fd memory memoryTypeBits: b" + std::bitset<8>(dmaBufMemoryProperties.memoryTypeBits).to_string();
  524. COMP_DEBUG_MSG(str);
  525. VkMemoryRequirements imageMemoryRequirements{};
  526. vkGetImageMemoryRequirements(m_device, vkImage, &imageMemoryRequirements);
  527. str = "Image memoryTypeBits: b" + std::bitset<8>(imageMemoryRequirements.memoryTypeBits).to_string();
  528. COMP_DEBUG_MSG(str);
  529. const uint32_t bits = dmaBufMemoryProperties.memoryTypeBits & imageMemoryRequirements.memoryTypeBits;
  530. CHECK(bits != 0);
  531. const MemoryTypeResult memoryTypeResult = findMemoryType(m_physicalDevice, bits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
  532. CHECK(memoryTypeResult.found);
  533. str = "Memory type index: " + to_string(memoryTypeResult.typeIndex);
  534. COMP_DEBUG_MSG(str);
  535. VkMemoryDedicatedAllocateInfo dedicatedAllocateInfo{};
  536. dedicatedAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
  537. dedicatedAllocateInfo.image = vkImage;
  538. VkImportMemoryFdInfoKHR importFdInfo{};
  539. importFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR;
  540. importFdInfo.pNext = &dedicatedAllocateInfo;
  541. importFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
  542. importFdInfo.fd = duppedFd;
  543. str = "Memory size = " + to_string(imageMemoryRequirements.size);
  544. COMP_DEBUG_MSG(str);
  545. m_oldImageIndex = m_vkImageMemoryIndex;
  546. int size = (int)m_vkImageMemory.size();
  547. m_vkImageMemoryIndex += 1;
  548. m_vkImageMemoryIndex = m_vkImageMemoryIndex % size;
  549. VkMemoryAllocateInfo memoryAllocateInfo{};
  550. memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
  551. memoryAllocateInfo.pNext = &importFdInfo;
  552. memoryAllocateInfo.allocationSize = imageMemoryRequirements.size;
  553. memoryAllocateInfo.memoryTypeIndex = memoryTypeResult.typeIndex;
  554. VK_CHECK(vkAllocateMemory(m_device, &memoryAllocateInfo, nullptr, &m_vkImageMemory[m_vkImageMemoryIndex]));
  555. VK_CHECK(vkBindImageMemory(m_device, vkImage, m_vkImageMemory[m_vkImageMemoryIndex], 0));
  556. }
  557. {
  558. displayFrame(vkImage);
  559. }
  560. if (m_oldImageIndex >= 0) {
  561. vkDestroyImage(m_device, vkImage, nullptr);
  562. vkFreeMemory(m_device, m_vkImageMemory[m_oldImageIndex], nullptr);
  563. }
  564. COMP_DEBUG_MSG("Vulkan image from fd created\n\n");
  565. }
  566. void
  567. NvVulkanRenderer::render(int fd)
  568. {
  569. createVkImageFromFd(fd);
  570. }
  571. NvVulkanRenderer::~NvVulkanRenderer()
  572. {
  573. vkDestroySemaphore(m_device, m_renderFinishedSemaphore, nullptr);
  574. vkDestroySemaphore(m_device, m_imageAvailableSemaphore, nullptr);
  575. vkDestroyFence(m_device, m_inFlightFence, nullptr);
  576. vkDestroyCommandPool(m_device, m_commandPool, nullptr);
  577. vkDestroySwapchainKHR(m_device, m_swapChain, nullptr);
  578. vkDestroyDevice(m_device, nullptr);
  579. vkDestroySurfaceKHR(m_instance, m_surface, nullptr);
  580. vkDestroyInstance(m_instance, nullptr);
  581. }