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
47QT_BEGIN_NAMESPACE
48
49static constexpr bool extraDebug = 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
60struct QueueFamilyIndices {
61 int graphicsFamily = -1;
62 int presentFamily = -1;
63
64 bool isComplete() {
65 return graphicsFamily >= 0 && presentFamily >= 0;
66 }
67};
68
69class VulkanWrapperPrivate
70{
71public:
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
79private:
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
168private:
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
179struct 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
188int 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
204VulkanImageWrapper *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
270bool 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
320bool 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
351VkCommandBuffer 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
376void 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
393void 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, &region);
413
414 endSingleTimeCommands(commandBuffer);
415}
416
417void 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
431QueueFamilyIndices 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
461bool 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
497VulkanImageWrapper *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
502VulkanImageWrapper *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
554void 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
567VulkanWrapperPrivate::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
686VulkanWrapper::VulkanWrapper(QOpenGLContext *glContext)
687 : d_ptr(new VulkanWrapperPrivate(glContext))
688{
689}
690
691VulkanImageWrapper *VulkanWrapper::createTextureImage(const QImage &img)
692{
693 return d_ptr->createTextureImage(img);
694}
695
696VulkanImageWrapper *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
705int 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
716void VulkanWrapper::freeTextureImage(VulkanImageWrapper *imageWrapper)
717{
718 d_ptr->freeTextureImage(imageWrapper);
719}
720
721QT_END_NAMESPACE
722

source code of qtwayland/src/hardwareintegration/compositor/vulkan-server/vulkanwrapper.cpp