| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2019 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the QtWaylandCompositor module of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 or (at your option) any later version | 
| 20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by | 
| 21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 | 
| 22 | ** included in the packaging of this file. Please review the following | 
| 23 | ** information to ensure the GNU General Public License requirements will | 
| 24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 25 | ** | 
| 26 | ** $QT_END_LICENSE$ | 
| 27 | ** | 
| 28 | ****************************************************************************/ | 
| 29 |  | 
| 30 | // NOTE: Some of the code below is adapted from the public domain code at https://vulkan-tutorial.com/ | 
| 31 |  | 
| 32 | #define  GL_GLEXT_PROTOTYPES | 
| 33 |  | 
| 34 | #include "vulkanwrapper.h" | 
| 35 |  | 
| 36 | #include <QImage> | 
| 37 | #include <QOpenGLContext> | 
| 38 | #include <QtGui/qopengl.h> | 
| 39 | #include <QtVulkanSupport/private/qvkconvenience_p.h> | 
| 40 |  | 
| 41 | #include <set> | 
| 42 |  | 
| 43 | #include <unistd.h> | 
| 44 |  | 
| 45 | #include <QDebug> | 
| 46 |  | 
| 47 | QT_BEGIN_NAMESPACE | 
| 48 |  | 
| 49 | static constexpr bool  = false; | 
| 50 |  | 
| 51 | #define DECL_VK_FUNCTION(name) \ | 
| 52 |     PFN_ ## name name = nullptr; | 
| 53 |  | 
| 54 | #define IMPL_VK_FUNCTION(name) \ | 
| 55 |     name = reinterpret_cast<PFN_ ## name>(f_glGetVkProcAddrNV(#name)); \ | 
| 56 |     if (!name) { \ | 
| 57 |         qCritical() << "ERROR in Vulkan proc lookup. Could not find " #name; \ | 
| 58 |     } | 
| 59 |  | 
| 60 | struct QueueFamilyIndices { | 
| 61 |     int graphicsFamily = -1; | 
| 62 |     int presentFamily = -1; | 
| 63 |  | 
| 64 |     bool isComplete() { | 
| 65 |         return graphicsFamily >= 0 && presentFamily >= 0; | 
| 66 |     } | 
| 67 | }; | 
| 68 |  | 
| 69 | class VulkanWrapperPrivate | 
| 70 | { | 
| 71 | public: | 
| 72 |     explicit VulkanWrapperPrivate(QOpenGLContext *glContext); | 
| 73 |  | 
| 74 |     VulkanImageWrapper *createTextureImage(const QImage &img); | 
| 75 |     VulkanImageWrapper *createTextureImageFromData(const uchar *pixels, uint bufferSize, const QSize &size, VkFormat vkFormat); | 
| 76 |  | 
| 77 |     void freeTextureImage(VulkanImageWrapper *imageWrapper); | 
| 78 |  | 
| 79 | private: | 
| 80 |     DECL_VK_FUNCTION(vkAllocateCommandBuffers); | 
| 81 |     DECL_VK_FUNCTION(vkAllocateMemory); | 
| 82 |     DECL_VK_FUNCTION(vkBeginCommandBuffer); | 
| 83 |     DECL_VK_FUNCTION(vkBindImageMemory); | 
| 84 |     DECL_VK_FUNCTION(vkCmdCopyBufferToImage); | 
| 85 |     DECL_VK_FUNCTION(vkCmdPipelineBarrier); | 
| 86 |     DECL_VK_FUNCTION(vkCreateImage); | 
| 87 |     DECL_VK_FUNCTION(vkDestroyImage); | 
| 88 |     DECL_VK_FUNCTION(vkDestroyBuffer); | 
| 89 |     DECL_VK_FUNCTION(vkEndCommandBuffer); | 
| 90 |     DECL_VK_FUNCTION(vkFreeCommandBuffers); | 
| 91 |     DECL_VK_FUNCTION(vkFreeMemory); | 
| 92 |     DECL_VK_FUNCTION(vkGetImageMemoryRequirements); | 
| 93 |     DECL_VK_FUNCTION(vkGetPhysicalDeviceMemoryProperties); | 
| 94 |     DECL_VK_FUNCTION(vkMapMemory); | 
| 95 |     DECL_VK_FUNCTION(vkQueueSubmit); | 
| 96 |     DECL_VK_FUNCTION(vkQueueWaitIdle); | 
| 97 |     DECL_VK_FUNCTION(vkUnmapMemory); | 
| 98 |     DECL_VK_FUNCTION(vkCreateBuffer); | 
| 99 |     DECL_VK_FUNCTION(vkGetBufferMemoryRequirements); | 
| 100 |     DECL_VK_FUNCTION(vkBindBufferMemory); | 
| 101 |  | 
| 102 |     DECL_VK_FUNCTION(vkCreateInstance); | 
| 103 |     DECL_VK_FUNCTION(vkEnumeratePhysicalDevices); | 
| 104 |     DECL_VK_FUNCTION(vkGetPhysicalDeviceProperties); | 
| 105 |     DECL_VK_FUNCTION(vkCreateDevice); | 
| 106 |     DECL_VK_FUNCTION(vkGetPhysicalDeviceFormatProperties); | 
| 107 |  | 
| 108 |     DECL_VK_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties); | 
| 109 |     DECL_VK_FUNCTION(vkCreateCommandPool); | 
| 110 |  | 
| 111 |     DECL_VK_FUNCTION(vkGetDeviceQueue); | 
| 112 |     DECL_VK_FUNCTION(vkGetImageMemoryRequirements2KHR); | 
| 113 |     DECL_VK_FUNCTION(vkGetMemoryFdKHR); | 
| 114 |  | 
| 115 |     //DECL_VK_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR); | 
| 116 |  | 
| 117 |     void initFunctions(PFNGLGETVKPROCADDRNVPROC f_glGetVkProcAddrNV) { | 
| 118 |         IMPL_VK_FUNCTION(vkAllocateCommandBuffers); | 
| 119 |         IMPL_VK_FUNCTION(vkAllocateMemory); | 
| 120 |         IMPL_VK_FUNCTION(vkBeginCommandBuffer); | 
| 121 |         IMPL_VK_FUNCTION(vkBindImageMemory); | 
| 122 |         IMPL_VK_FUNCTION(vkCmdCopyBufferToImage); | 
| 123 |         IMPL_VK_FUNCTION(vkCmdPipelineBarrier); | 
| 124 |         IMPL_VK_FUNCTION(vkCreateImage); | 
| 125 |         IMPL_VK_FUNCTION(vkDestroyImage); | 
| 126 |         IMPL_VK_FUNCTION(vkDestroyBuffer); | 
| 127 |         IMPL_VK_FUNCTION(vkEndCommandBuffer); | 
| 128 |         IMPL_VK_FUNCTION(vkFreeCommandBuffers); | 
| 129 |         IMPL_VK_FUNCTION(vkFreeMemory); | 
| 130 |         IMPL_VK_FUNCTION(vkGetImageMemoryRequirements); | 
| 131 |         IMPL_VK_FUNCTION(vkGetPhysicalDeviceMemoryProperties); | 
| 132 |         IMPL_VK_FUNCTION(vkMapMemory); | 
| 133 |         IMPL_VK_FUNCTION(vkQueueSubmit); | 
| 134 |         IMPL_VK_FUNCTION(vkQueueWaitIdle); | 
| 135 |         IMPL_VK_FUNCTION(vkUnmapMemory); | 
| 136 |         IMPL_VK_FUNCTION(vkCreateBuffer); | 
| 137 |         IMPL_VK_FUNCTION(vkGetBufferMemoryRequirements); | 
| 138 |         IMPL_VK_FUNCTION(vkBindBufferMemory); | 
| 139 |  | 
| 140 |         IMPL_VK_FUNCTION(vkCreateInstance); | 
| 141 |         IMPL_VK_FUNCTION(vkEnumeratePhysicalDevices); | 
| 142 |         IMPL_VK_FUNCTION(vkGetPhysicalDeviceProperties); | 
| 143 |         IMPL_VK_FUNCTION(vkCreateDevice); | 
| 144 |         IMPL_VK_FUNCTION(vkGetPhysicalDeviceFormatProperties); | 
| 145 |  | 
| 146 |         IMPL_VK_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties); | 
| 147 |         IMPL_VK_FUNCTION(vkCreateCommandPool); | 
| 148 |  | 
| 149 |         IMPL_VK_FUNCTION(vkGetDeviceQueue); | 
| 150 |         IMPL_VK_FUNCTION(vkGetImageMemoryRequirements2KHR); | 
| 151 |         IMPL_VK_FUNCTION(vkGetMemoryFdKHR); | 
| 152 |  | 
| 153 |         //IMPL_VK_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR); | 
| 154 |     } | 
| 155 |  | 
| 156 |     int findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); | 
| 157 |  | 
| 158 |     VulkanImageWrapper *createImage(VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, const QSize &size, int memSize); | 
| 159 |     bool transitionImageLayout(VkImage image, VkFormat /*format*/, VkImageLayout oldLayout, VkImageLayout newLayout); | 
| 160 |     bool createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory); | 
| 161 |     VkCommandBuffer beginSingleTimeCommands(); | 
| 162 |     void endSingleTimeCommands(VkCommandBuffer commandBuffer); | 
| 163 |     void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height); | 
| 164 |     void createCommandPool(); | 
| 165 |     QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device); | 
| 166 |     bool createLogicalDevice(); | 
| 167 |  | 
| 168 | private: | 
| 169 |     VkInstance m_instance = VK_NULL_HANDLE; | 
| 170 |     VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE; | 
| 171 |     VkDevice m_device = VK_NULL_HANDLE; | 
| 172 |     VkCommandPool m_commandPool = VK_NULL_HANDLE; | 
| 173 |  | 
| 174 |     VkQueue m_graphicsQueue = VK_NULL_HANDLE; | 
| 175 |  | 
| 176 |     bool m_initFailed = false; | 
| 177 | }; | 
| 178 |  | 
| 179 | struct VulkanImageWrapper | 
| 180 | { | 
| 181 |     VkImage textureImage = VK_NULL_HANDLE; | 
| 182 |     int imgMemSize = -1; | 
| 183 |     QSize imgSize; | 
| 184 |     int imgFd = -1; | 
| 185 |     VkDeviceMemory textureImageMemory = VK_NULL_HANDLE; | 
| 186 | }; | 
| 187 |  | 
| 188 | int VulkanWrapperPrivate::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) | 
| 189 | { | 
| 190 |     VkPhysicalDeviceMemoryProperties memProperties; | 
| 191 |     vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &memProperties); | 
| 192 |  | 
| 193 |     for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) { | 
| 194 |         if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) { | 
| 195 |             return i; | 
| 196 |         } | 
| 197 |     } | 
| 198 |  | 
| 199 |     qCritical(msg: "VulkanWrapper: failed to find suitable memory type!" ); | 
| 200 |     return -1; | 
| 201 | } | 
| 202 |  | 
| 203 |  | 
| 204 | VulkanImageWrapper *VulkanWrapperPrivate::createImage(VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, const QSize &size, int memSize) | 
| 205 | { | 
| 206 |     VkImageCreateInfo imageInfo = {}; | 
| 207 |     imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; | 
| 208 |     imageInfo.imageType = VK_IMAGE_TYPE_2D; | 
| 209 |     imageInfo.extent.width = size.width(); | 
| 210 |     imageInfo.extent.height = size.height(); | 
| 211 |     imageInfo.extent.depth = 1; | 
| 212 |     imageInfo.mipLevels = 1; | 
| 213 |     imageInfo.arrayLayers = 1; | 
| 214 |     imageInfo.format = format; | 
| 215 |     imageInfo.tiling = tiling; | 
| 216 |     imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; | 
| 217 |     imageInfo.usage = usage; | 
| 218 |     imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; | 
| 219 |     imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; | 
| 220 |  | 
| 221 |     VkImage image = VK_NULL_HANDLE; | 
| 222 |  | 
| 223 |     if (vkCreateImage(m_device, &imageInfo, nullptr, &image) != VK_SUCCESS) { | 
| 224 |         qCritical(msg: "VulkanWrapper: failed to create image!" ); | 
| 225 |         return nullptr; | 
| 226 |     } | 
| 227 |  | 
| 228 |     QScopedPointer<VulkanImageWrapper> imageWrapper(new VulkanImageWrapper); | 
| 229 |     imageWrapper->textureImage = image; | 
| 230 |     imageWrapper->imgMemSize = memSize; | 
| 231 |     imageWrapper->imgSize = size; | 
| 232 |  | 
| 233 |     VkMemoryRequirements memRequirements; | 
| 234 |     vkGetImageMemoryRequirements(m_device, image, &memRequirements); | 
| 235 |  | 
| 236 |     VkExportMemoryAllocateInfoKHR exportAllocInfo = {}; | 
| 237 |     exportAllocInfo.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR; | 
| 238 |     exportAllocInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; | 
| 239 |  | 
| 240 |     VkMemoryAllocateInfo allocInfo = {}; | 
| 241 |     allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; | 
| 242 |     allocInfo.allocationSize = memRequirements.size; | 
| 243 |     int memoryType = findMemoryType(typeFilter: memRequirements.memoryTypeBits, properties); | 
| 244 |     if (memoryType < 0) | 
| 245 |         return nullptr; | 
| 246 |     allocInfo.memoryTypeIndex = memoryType; | 
| 247 |     allocInfo.pNext = &exportAllocInfo; | 
| 248 |  | 
| 249 |     if (vkAllocateMemory(m_device, &allocInfo, nullptr, &imageWrapper->textureImageMemory) != VK_SUCCESS) { | 
| 250 |         qCritical(msg: "VulkanWrapper: failed to allocate image memory!" ); | 
| 251 |         return nullptr; | 
| 252 |     } | 
| 253 |  | 
| 254 |     int res = vkBindImageMemory(m_device, image, imageWrapper->textureImageMemory, 0); | 
| 255 |     Q_UNUSED(res); | 
| 256 |     if (extraDebug) qDebug() << "vkBindImageMemory res"  << res; | 
| 257 |  | 
| 258 |     VkMemoryGetFdInfoKHR memoryFdInfo = {}; | 
| 259 |     memoryFdInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; | 
| 260 |     memoryFdInfo.memory = imageWrapper->textureImageMemory; | 
| 261 |     memoryFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; | 
| 262 |  | 
| 263 |     res = vkGetMemoryFdKHR(m_device, &memoryFdInfo, &imageWrapper->imgFd); | 
| 264 |     if (extraDebug) qDebug() << "vkGetMemoryFdKHR res"  << res << "fd"  << imageWrapper->imgFd; | 
| 265 |  | 
| 266 |     return imageWrapper.take(); | 
| 267 | } | 
| 268 |  | 
| 269 |  | 
| 270 | bool VulkanWrapperPrivate::transitionImageLayout(VkImage image, VkFormat /*format*/, VkImageLayout oldLayout, VkImageLayout newLayout) | 
| 271 | { | 
| 272 |     VkCommandBuffer commandBuffer = beginSingleTimeCommands(); | 
| 273 |  | 
| 274 |     VkImageMemoryBarrier barrier = {}; | 
| 275 |     barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; | 
| 276 |     barrier.oldLayout = oldLayout; | 
| 277 |     barrier.newLayout = newLayout; | 
| 278 |     barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | 
| 279 |     barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | 
| 280 |     barrier.image = image; | 
| 281 |     barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; | 
| 282 |     barrier.subresourceRange.baseMipLevel = 0; | 
| 283 |     barrier.subresourceRange.levelCount = 1; | 
| 284 |     barrier.subresourceRange.baseArrayLayer = 0; | 
| 285 |     barrier.subresourceRange.layerCount = 1; | 
| 286 |  | 
| 287 |     VkPipelineStageFlags sourceStage; | 
| 288 |     VkPipelineStageFlags destinationStage; | 
| 289 |  | 
| 290 |     if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) { | 
| 291 |         barrier.srcAccessMask = 0; | 
| 292 |         barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | 
| 293 |  | 
| 294 |         sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; | 
| 295 |         destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT; | 
| 296 |     } else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { | 
| 297 |         barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; | 
| 298 |         barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; | 
| 299 |  | 
| 300 |         sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT; | 
| 301 |         destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; | 
| 302 |     } else { | 
| 303 |         qCritical(msg: "VulkanWrapper: unsupported layout transition!" ); | 
| 304 |         return false; | 
| 305 |     } | 
| 306 |  | 
| 307 |     vkCmdPipelineBarrier( | 
| 308 |         commandBuffer, | 
| 309 |         sourceStage, destinationStage, | 
| 310 |         0, | 
| 311 |         0, nullptr, | 
| 312 |         0, nullptr, | 
| 313 |         1, &barrier | 
| 314 |         ); | 
| 315 |  | 
| 316 |     endSingleTimeCommands(commandBuffer); | 
| 317 |     return true; | 
| 318 | } | 
| 319 |  | 
| 320 | bool VulkanWrapperPrivate::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) | 
| 321 | { | 
| 322 |     VkBufferCreateInfo bufferInfo = {}; | 
| 323 |     bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; | 
| 324 |     bufferInfo.size = size; | 
| 325 |     bufferInfo.usage = usage; | 
| 326 |     bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; | 
| 327 |  | 
| 328 |     if (vkCreateBuffer(m_device, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) { | 
| 329 |         qCritical(msg: "VulkanWrapper: failed to create buffer!" ); | 
| 330 |         return false; | 
| 331 |     } | 
| 332 |  | 
| 333 |     VkMemoryRequirements memRequirements; | 
| 334 |     vkGetBufferMemoryRequirements(m_device, buffer, &memRequirements); | 
| 335 |  | 
| 336 |     VkMemoryAllocateInfo allocInfo = {}; | 
| 337 |     allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; | 
| 338 |     allocInfo.allocationSize = memRequirements.size; | 
| 339 |     allocInfo.memoryTypeIndex = findMemoryType(typeFilter: memRequirements.memoryTypeBits, properties); | 
| 340 |  | 
| 341 |     if (vkAllocateMemory(m_device, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) { | 
| 342 |         qCritical(msg: "VulkanWrapper: failed to allocate buffer memory!" ); | 
| 343 |         return false; | 
| 344 |     } | 
| 345 |  | 
| 346 |     vkBindBufferMemory(m_device, buffer, bufferMemory, 0); | 
| 347 |     return true; | 
| 348 | } | 
| 349 |  | 
| 350 |  | 
| 351 | VkCommandBuffer VulkanWrapperPrivate::beginSingleTimeCommands() | 
| 352 | { | 
| 353 |     VkCommandBufferAllocateInfo allocInfo = {}; | 
| 354 |     allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; | 
| 355 |     allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; | 
| 356 |     allocInfo.commandPool = m_commandPool; | 
| 357 |     allocInfo.commandBufferCount = 1; | 
| 358 |  | 
| 359 |     if (extraDebug) qDebug() << "allocating..." ; | 
| 360 |  | 
| 361 |     VkCommandBuffer commandBuffer; | 
| 362 |     int res = vkAllocateCommandBuffers(m_device, &allocInfo, &commandBuffer); | 
| 363 |     Q_UNUSED(res); | 
| 364 |     if (extraDebug) qDebug() << "vkAllocateCommandBuffers res"  << res; | 
| 365 |  | 
| 366 |     VkCommandBufferBeginInfo beginInfo = {}; | 
| 367 |     beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; | 
| 368 |     beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; | 
| 369 |  | 
| 370 |     res = vkBeginCommandBuffer(commandBuffer, &beginInfo); | 
| 371 |     if (extraDebug) qDebug() << "BEGIN res"  << res; | 
| 372 |  | 
| 373 |     return commandBuffer; | 
| 374 | } | 
| 375 |  | 
| 376 | void VulkanWrapperPrivate::endSingleTimeCommands(VkCommandBuffer commandBuffer) | 
| 377 | { | 
| 378 |     int res = vkEndCommandBuffer(commandBuffer); | 
| 379 |     Q_UNUSED(res); | 
| 380 |     if (extraDebug) qDebug() << "END res"  << res; | 
| 381 |  | 
| 382 |     VkSubmitInfo submitInfo = {}; | 
| 383 |     submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; | 
| 384 |     submitInfo.commandBufferCount = 1; | 
| 385 |     submitInfo.pCommandBuffers = &commandBuffer; | 
| 386 |  | 
| 387 |     vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); | 
| 388 |     vkQueueWaitIdle(m_graphicsQueue); | 
| 389 |  | 
| 390 |     vkFreeCommandBuffers(m_device, m_commandPool, 1, &commandBuffer); | 
| 391 | } | 
| 392 |  | 
| 393 | void VulkanWrapperPrivate::copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height) | 
| 394 | { | 
| 395 |     VkCommandBuffer commandBuffer = beginSingleTimeCommands(); | 
| 396 |  | 
| 397 |     VkBufferImageCopy region = {}; | 
| 398 |     region.bufferOffset = 0; | 
| 399 |     region.bufferRowLength = 0; | 
| 400 |     region.bufferImageHeight = 0; | 
| 401 |     region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; | 
| 402 |     region.imageSubresource.mipLevel = 0; | 
| 403 |     region.imageSubresource.baseArrayLayer = 0; | 
| 404 |     region.imageSubresource.layerCount = 1; | 
| 405 |     region.imageOffset = {.x: 0, .y: 0, .z: 0}; | 
| 406 |     region.imageExtent = { | 
| 407 |         .width: width, | 
| 408 |         .height: height, | 
| 409 |         .depth: 1 | 
| 410 |     }; | 
| 411 |  | 
| 412 |     vkCmdCopyBufferToImage(commandBuffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); | 
| 413 |  | 
| 414 |     endSingleTimeCommands(commandBuffer); | 
| 415 | } | 
| 416 |  | 
| 417 | void VulkanWrapperPrivate::createCommandPool() | 
| 418 | { | 
| 419 |     QueueFamilyIndices queueFamilyIndices = findQueueFamilies(device: m_physicalDevice); | 
| 420 |  | 
| 421 |     VkCommandPoolCreateInfo poolInfo = {}; | 
| 422 |     poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; | 
| 423 |     poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; | 
| 424 |  | 
| 425 |     if (vkCreateCommandPool(m_device, &poolInfo, nullptr, &m_commandPool) != VK_SUCCESS) { | 
| 426 |         m_initFailed = true; | 
| 427 |         qCritical(msg: "VulkanWrapperPrivate: could not create command pool" ); | 
| 428 |     } | 
| 429 | } | 
| 430 |  | 
| 431 | QueueFamilyIndices VulkanWrapperPrivate::findQueueFamilies(VkPhysicalDevice device) | 
| 432 | { | 
| 433 |     QueueFamilyIndices indices; | 
| 434 |  | 
| 435 |     uint32_t queueFamilyCount = 0; | 
| 436 |     vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); | 
| 437 |     if (extraDebug) qDebug() << "queueFamilyCount"  << queueFamilyCount; | 
| 438 |  | 
| 439 |  | 
| 440 |     std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount); | 
| 441 |     vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); | 
| 442 |  | 
| 443 | #ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG | 
| 444 |     for (const auto& queueFamily : queueFamilies) { | 
| 445 |         qDebug() << "....q"  << "count"  << queueFamily.queueCount << queueFamily.timestampValidBits  << hex << queueFamily.queueFlags; | 
| 446 |     } | 
| 447 | #endif | 
| 448 |  | 
| 449 |     int i = 0; | 
| 450 |     for (const auto& queueFamily : queueFamilies) { | 
| 451 |         if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) { | 
| 452 |             indices.graphicsFamily = i; | 
| 453 |             break; | 
| 454 |         } | 
| 455 |         i++; | 
| 456 |     } | 
| 457 |  | 
| 458 |     return indices; | 
| 459 | } | 
| 460 |  | 
| 461 | bool VulkanWrapperPrivate::createLogicalDevice() | 
| 462 | { | 
| 463 |     QueueFamilyIndices indices = findQueueFamilies(device: m_physicalDevice); | 
| 464 |  | 
| 465 |     std::vector<VkDeviceQueueCreateInfo> queueCreateInfos; | 
| 466 |     std::set<int> uniqueQueueFamilies = {indices.graphicsFamily}; //////, indices.presentFamily}; | 
| 467 |  | 
| 468 |     float queuePriority = 1.0f; | 
| 469 |     for (int queueFamily : uniqueQueueFamilies) { | 
| 470 |         VkDeviceQueueCreateInfo queueCreateInfo = {}; | 
| 471 |         queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; | 
| 472 |         queueCreateInfo.queueFamilyIndex = queueFamily; | 
| 473 |         queueCreateInfo.queueCount = 1; | 
| 474 |         queueCreateInfo.pQueuePriorities = &queuePriority; | 
| 475 |         queueCreateInfos.push_back(x: queueCreateInfo); | 
| 476 |     } | 
| 477 |  | 
| 478 |     VkPhysicalDeviceFeatures deviceFeatures = {}; | 
| 479 |  | 
| 480 |     VkDeviceCreateInfo createInfo = {}; | 
| 481 |     createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; | 
| 482 |  | 
| 483 |     createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size()); | 
| 484 |     createInfo.pQueueCreateInfos = queueCreateInfos.data(); | 
| 485 |  | 
| 486 |     createInfo.pEnabledFeatures = &deviceFeatures; | 
| 487 |  | 
| 488 |     if (vkCreateDevice(m_physicalDevice, &createInfo, nullptr, &m_device) != VK_SUCCESS) { | 
| 489 |         qCritical(msg: "VulkanWrapper: failed to create logical device!" ); | 
| 490 |         return false; | 
| 491 |     } | 
| 492 |  | 
| 493 |     vkGetDeviceQueue(m_device, indices.graphicsFamily, 0, &m_graphicsQueue); | 
| 494 |     return true; | 
| 495 | } | 
| 496 |  | 
| 497 | VulkanImageWrapper *VulkanWrapperPrivate::createTextureImage(const QImage &img) | 
| 498 | { | 
| 499 |     return createTextureImageFromData(pixels: img.constBits(), bufferSize: img.sizeInBytes(), size: img.size(), vkFormat: VK_FORMAT_R8G8B8A8_UNORM); | 
| 500 | } | 
| 501 |  | 
| 502 | VulkanImageWrapper *VulkanWrapperPrivate::createTextureImageFromData(const uchar *pixels, uint bufferSize, const QSize &size, VkFormat vkFormat) | 
| 503 | { | 
| 504 |     if (m_initFailed) | 
| 505 |         return nullptr; | 
| 506 |  | 
| 507 |     int texWidth = size.width(); | 
| 508 |     int texHeight = size.height(); | 
| 509 |     bool ok; | 
| 510 |     if (extraDebug) qDebug(msg: "image load %p %dx%d" , pixels, texWidth, texHeight); | 
| 511 |     if (!pixels) { | 
| 512 |         qCritical(msg: "VulkanWrapper: failed to load texture image!" ); | 
| 513 |         return nullptr; | 
| 514 |     } | 
| 515 |  | 
| 516 |     VkBuffer stagingBuffer; | 
| 517 |     VkDeviceMemory stagingBufferMemory; | 
| 518 |     ok = createBuffer(size: bufferSize, usage: VK_BUFFER_USAGE_TRANSFER_SRC_BIT, properties: VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, buffer&: stagingBuffer, bufferMemory&: stagingBufferMemory); | 
| 519 |  | 
| 520 |     if (!ok) | 
| 521 |         return nullptr; | 
| 522 |  | 
| 523 |     void* data; | 
| 524 |     vkMapMemory(m_device, stagingBufferMemory, 0, bufferSize, 0, &data); | 
| 525 |     if (extraDebug) qDebug() << "mapped"  << data << bufferSize; | 
| 526 |     memcpy(dest: data, src: pixels, n: static_cast<size_t>(bufferSize)); | 
| 527 |     vkUnmapMemory(m_device, stagingBufferMemory); | 
| 528 |  | 
| 529 |     if (extraDebug) qDebug() << "creating image..." ; | 
| 530 |  | 
| 531 |     QScopedPointer<VulkanImageWrapper> imageWrapper(createImage(format: vkFormat, tiling: VK_IMAGE_TILING_OPTIMAL, usage: VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, properties: VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, size, memSize: bufferSize)); | 
| 532 |     if (imageWrapper.isNull()) | 
| 533 |         return nullptr; | 
| 534 |  | 
| 535 |     if (extraDebug) qDebug() << "transition..." ; | 
| 536 |  | 
| 537 |     const VkImage textureImage = imageWrapper->textureImage; | 
| 538 |  | 
| 539 |     ok = transitionImageLayout(image: textureImage, vkFormat, oldLayout: VK_IMAGE_LAYOUT_UNDEFINED, newLayout: VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); | 
| 540 |  | 
| 541 |     if (!ok) | 
| 542 |         return nullptr; | 
| 543 |  | 
| 544 |     if (extraDebug) qDebug() << "copyBufferToImage..." ; | 
| 545 |     copyBufferToImage(buffer: stagingBuffer, image: textureImage, width: static_cast<uint32_t>(texWidth), height: static_cast<uint32_t>(texHeight)); | 
| 546 |     transitionImageLayout(image: textureImage, vkFormat, oldLayout: VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, newLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); | 
| 547 |  | 
| 548 |     vkDestroyBuffer(m_device, stagingBuffer, nullptr); | 
| 549 |     vkFreeMemory(m_device, stagingBufferMemory, nullptr); | 
| 550 |  | 
| 551 |     return imageWrapper.take(); | 
| 552 | } | 
| 553 |  | 
| 554 | void VulkanWrapperPrivate::freeTextureImage(VulkanImageWrapper *imageWrapper) | 
| 555 | { | 
| 556 |     if (!imageWrapper) | 
| 557 |         return; | 
| 558 |  | 
| 559 |     //"To avoid leaking resources, the application must release ownership of the file descriptor using the close system call" | 
| 560 |     ::close(fd: imageWrapper->imgFd); | 
| 561 |  | 
| 562 |     // clean up the image memory | 
| 563 |     vkDestroyImage(m_device, imageWrapper->textureImage, nullptr); | 
| 564 |     vkFreeMemory(m_device, imageWrapper->textureImageMemory, nullptr); | 
| 565 | } | 
| 566 |  | 
| 567 | VulkanWrapperPrivate::VulkanWrapperPrivate(QOpenGLContext *glContext) | 
| 568 | { | 
| 569 |     if (extraDebug) qDebug(msg: "Creating Vulkan instance" ); | 
| 570 |     VkApplicationInfo applicationInfo = {}; | 
| 571 |     applicationInfo.sType               = VK_STRUCTURE_TYPE_APPLICATION_INFO; | 
| 572 |     applicationInfo.pNext               = nullptr; | 
| 573 |     applicationInfo.pApplicationName    = nullptr; | 
| 574 |     applicationInfo.applicationVersion  = 0; | 
| 575 |     applicationInfo.pEngineName         = nullptr; | 
| 576 |     applicationInfo.engineVersion       = VK_MAKE_VERSION(1, 0, 0); | 
| 577 |     applicationInfo.apiVersion          = VK_MAKE_VERSION(1, 0, 5); | 
| 578 |  | 
| 579 |     VkInstanceCreateInfo instanceCreateInfo = {}; | 
| 580 |     instanceCreateInfo.sType                    = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; | 
| 581 |     instanceCreateInfo.pNext                    = nullptr; | 
| 582 |     instanceCreateInfo.flags                    = 0; | 
| 583 |     instanceCreateInfo.pApplicationInfo         = &applicationInfo; | 
| 584 |     instanceCreateInfo.enabledLayerCount        = 0; | 
| 585 |     instanceCreateInfo.ppEnabledLayerNames      = nullptr; | 
| 586 |     instanceCreateInfo.enabledExtensionCount    = 0; | 
| 587 |     instanceCreateInfo.ppEnabledExtensionNames  = nullptr; | 
| 588 |  | 
| 589 |     auto f_glGetVkProcAddrNV = reinterpret_cast<PFNGLGETVKPROCADDRNVPROC>(glContext->getProcAddress(procName: "glGetVkProcAddrNV" )); | 
| 590 |  | 
| 591 |     if (!f_glGetVkProcAddrNV) { | 
| 592 |         qCritical(msg: "VulkanWrapper: Could not find Vulkan/GL interop function glGetVkProcAddrNV" ); | 
| 593 |         m_initFailed = true; | 
| 594 |         return; | 
| 595 |     } | 
| 596 |  | 
| 597 |     initFunctions(f_glGetVkProcAddrNV); | 
| 598 |  | 
| 599 |     VkResult   instanceCreationResult = vkCreateInstance(&instanceCreateInfo, nullptr, &m_instance); | 
| 600 |  | 
| 601 |     if (extraDebug) qDebug() << "result"  << instanceCreationResult; | 
| 602 |  | 
| 603 |     if (instanceCreationResult != VK_SUCCESS) { | 
| 604 |         qCritical() << "VulkanWrapper: Failed to create Vulkan instance: Error "  | 
| 605 |                  << instanceCreationResult; | 
| 606 |         m_initFailed = true; | 
| 607 |         return; | 
| 608 |     } | 
| 609 |  | 
| 610 |     uint32_t devCount; | 
| 611 |  | 
| 612 |     auto res = vkEnumeratePhysicalDevices(m_instance, &devCount, nullptr); | 
| 613 |     if (extraDebug) qDebug() << "vkEnumeratePhysicalDevices res ="  << res << "count ="  << devCount; | 
| 614 |  | 
| 615 |     QVarLengthArray<VkPhysicalDevice, 5> dev(devCount); | 
| 616 |  | 
| 617 |     res = vkEnumeratePhysicalDevices(m_instance, &devCount, dev.data()); | 
| 618 |     if (extraDebug) qDebug() << "...devs res ="  << res << "count ="  << devCount; | 
| 619 |  | 
| 620 | #ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG | 
| 621 |     VkPhysicalDeviceProperties props; | 
| 622 |  | 
| 623 |     vkGetPhysicalDeviceProperties(dev[0], &props); | 
| 624 |  | 
| 625 |     qDebug() << "Properties "  << hex | 
| 626 |              << "apiVersion"  << props.apiVersion | 
| 627 |              << "driverVersion"  << props.driverVersion | 
| 628 |              << "vendorID"  << props.vendorID | 
| 629 |              << "deviceID"  << props.deviceID | 
| 630 |              << "deviceType"  << props.deviceType | 
| 631 |              << "deviceName"  << props.deviceName; | 
| 632 | #endif | 
| 633 |  | 
| 634 |     m_physicalDevice = dev[0]; //TODO handle the case of multiple GPUs where only some support Vulkan | 
| 635 |  | 
| 636 |     bool ok = createLogicalDevice(); | 
| 637 |     if (!ok) { | 
| 638 |         qCritical(msg: "VulkanWrapperPrivate: could not create logical device" ); | 
| 639 |         m_initFailed = true; | 
| 640 |         return; | 
| 641 |     } | 
| 642 |  | 
| 643 |     VkPhysicalDeviceMemoryProperties memProps; | 
| 644 |  | 
| 645 |  | 
| 646 |     vkGetPhysicalDeviceMemoryProperties(dev[0], &memProps); | 
| 647 |  | 
| 648 | #ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG | 
| 649 |     qDebug() << "Physical memory properties:\n"  << "types:"  << memProps.memoryTypeCount << "heaps:"  << memProps.memoryHeapCount; | 
| 650 |     for (uint i = 0; i < memProps.memoryTypeCount; ++i) | 
| 651 |         qDebug() << "   "  << i << "heap"  << memProps.memoryTypes[i].heapIndex << "flags"  << hex << memProps.memoryTypes[i].propertyFlags; | 
| 652 |  | 
| 653 |     for (uint i = 0; i < memProps.memoryHeapCount; ++i) | 
| 654 |         qDebug() << "   "  << i << "size"  << memProps.memoryHeaps[i].size << "flags"  << hex << memProps.memoryHeaps[i].flags; | 
| 655 | #endif | 
| 656 |  | 
| 657 |     int gpuMemoryType = -1; | 
| 658 |  | 
| 659 |     for (uint i = 0; i < memProps.memoryTypeCount; ++i) { | 
| 660 |         if (memProps.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { | 
| 661 |             gpuMemoryType = i; | 
| 662 |             break; | 
| 663 |         } | 
| 664 |     } | 
| 665 |  | 
| 666 |     if (gpuMemoryType < 0) { | 
| 667 |         qCritical(msg: "VulkanWrapper: Could not find GPU memory!" ); | 
| 668 |         m_initFailed = true; | 
| 669 |         return; | 
| 670 |     } | 
| 671 |  | 
| 672 | #ifdef VULKAN_SERVER_BUFFER_EXTRA_DEBUG | 
| 673 |     qDebug() << "GPU memory type:"  << gpuMemoryType << "heap:"  << memProps.memoryTypes[gpuMemoryType].heapIndex; | 
| 674 |  | 
| 675 |     for (int f = 0; f <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK; f++) | 
| 676 |     { | 
| 677 |         VkFormatProperties formatProps; | 
| 678 |         vkGetPhysicalDeviceFormatProperties(dev[0], VkFormat(f), &formatProps); | 
| 679 |         qDebug() << "format"  << f << "features"  << hex << formatProps.linearTilingFeatures << formatProps.optimalTilingFeatures << formatProps.bufferFeatures; | 
| 680 |     } | 
| 681 | #endif | 
| 682 |     createCommandPool(); | 
| 683 | } | 
| 684 |  | 
| 685 |  | 
| 686 | VulkanWrapper::VulkanWrapper(QOpenGLContext *glContext) | 
| 687 |     : d_ptr(new VulkanWrapperPrivate(glContext)) | 
| 688 | { | 
| 689 | } | 
| 690 |  | 
| 691 | VulkanImageWrapper *VulkanWrapper::createTextureImage(const QImage &img) | 
| 692 | { | 
| 693 |     return d_ptr->createTextureImage(img); | 
| 694 | } | 
| 695 |  | 
| 696 | VulkanImageWrapper *VulkanWrapper::createTextureImageFromData(const uchar *pixels, uint bufferSize, const QSize &size, uint glInternalFormat) | 
| 697 | { | 
| 698 |     VkFormat vkFormat = VkFormat(QVkConvenience::vkFormatFromGlFormat(glFormat: glInternalFormat)); | 
| 699 |     if (vkFormat == VK_FORMAT_UNDEFINED) | 
| 700 |         return nullptr; | 
| 701 |  | 
| 702 |     return d_ptr->createTextureImageFromData(pixels, bufferSize, size, vkFormat); | 
| 703 | } | 
| 704 |  | 
| 705 | int VulkanWrapper::getImageInfo(const VulkanImageWrapper *imgWrapper, int *memSize, int *w, int *h) | 
| 706 | { | 
| 707 |     if (memSize) | 
| 708 |         *memSize = imgWrapper->imgMemSize; | 
| 709 |     if (w) | 
| 710 |         *w = imgWrapper->imgSize.width(); | 
| 711 |     if (h) | 
| 712 |         *h = imgWrapper->imgSize.height(); | 
| 713 |     return imgWrapper->imgFd; | 
| 714 | } | 
| 715 |  | 
| 716 | void VulkanWrapper::freeTextureImage(VulkanImageWrapper *imageWrapper) | 
| 717 | { | 
| 718 |     d_ptr->freeTextureImage(imageWrapper); | 
| 719 | } | 
| 720 |  | 
| 721 | QT_END_NAMESPACE | 
| 722 |  |