6#include "qvulkanfunctions.h"
8#include <QLoggingCategory>
11#include <QCoreApplication>
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
210
211
212
213
214QVulkanWindow::QVulkanWindow(QWindow *parent)
215 : QWindow(*(
new QVulkanWindowPrivate), parent)
217 setSurfaceType(QSurface::VulkanSurface);
221
222
223QVulkanWindow::~QVulkanWindow()
227QVulkanWindowPrivate::~QVulkanWindowPrivate()
236
237
238
239
240
241
242
243
246
247
248
249
250
251
252void QVulkanWindow::setFlags(Flags flags)
255 if (d->status != QVulkanWindowPrivate::StatusUninitialized) {
256 qWarning(
"QVulkanWindow: Attempted to set flags when already initialized");
263
264
265QVulkanWindow::Flags QVulkanWindow::flags()
const
267 Q_D(
const QVulkanWindow);
272
273
274
275
276QList<VkPhysicalDeviceProperties> QVulkanWindow::availablePhysicalDevices()
279 if (!d->physDevs.isEmpty() && !d->physDevProps.isEmpty())
280 return d->physDevProps;
282 QVulkanInstance *inst = vulkanInstance();
284 qWarning(
"QVulkanWindow: Attempted to call availablePhysicalDevices() without a QVulkanInstance");
285 return d->physDevProps;
288 QVulkanFunctions *f = inst->functions();
290 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &count,
nullptr);
291 if (err != VK_SUCCESS) {
292 qWarning(
"QVulkanWindow: Failed to get physical device count: %d", err);
293 return d->physDevProps;
296 qCDebug(lcGuiVk,
"%d physical devices", count);
298 return d->physDevProps;
300 QList<VkPhysicalDevice> devs(count);
301 err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &count, devs.data());
302 if (err != VK_SUCCESS) {
303 qWarning(
"QVulkanWindow: Failed to enumerate physical devices: %d", err);
304 return d->physDevProps;
308 d->physDevProps.resize(count);
309 for (uint32_t i = 0; i < count; ++i) {
310 VkPhysicalDeviceProperties *p = &d->physDevProps[i];
311 f->vkGetPhysicalDeviceProperties(d->physDevs.at(i), p);
312 qCDebug(lcGuiVk,
"Physical device [%d]: name '%s' version %d.%d.%d", i, p->deviceName,
313 VK_VERSION_MAJOR(p->driverVersion), VK_VERSION_MINOR(p->driverVersion),
314 VK_VERSION_PATCH(p->driverVersion));
317 return d->physDevProps;
321
322
323
324
325
326
327
328
329
330void QVulkanWindow::setPhysicalDeviceIndex(
int idx)
333 if (d->status != QVulkanWindowPrivate::StatusUninitialized) {
334 qWarning(
"QVulkanWindow: Attempted to set physical device when already initialized");
337 const int count = availablePhysicalDevices().size();
338 if (idx < 0 || idx >= count) {
339 qWarning(
"QVulkanWindow: Invalid physical device index %d (total physical devices: %d)", idx, count);
342 d->physDevIndex = idx;
346
347
348
349
350
351QVulkanInfoVector<QVulkanExtension> QVulkanWindow::supportedDeviceExtensions()
355 availablePhysicalDevices();
357 if (d->physDevs.isEmpty()) {
358 qWarning(
"QVulkanWindow: No physical devices found");
359 return QVulkanInfoVector<QVulkanExtension>();
362 VkPhysicalDevice physDev = d->physDevs.at(d->physDevIndex);
363 if (d->supportedDevExtensions.contains(physDev))
364 return d->supportedDevExtensions.value(physDev);
366 QVulkanFunctions *f = vulkanInstance()->functions();
368 VkResult err = f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &count,
nullptr);
369 if (err == VK_SUCCESS) {
370 QList<VkExtensionProperties> extProps(count);
371 err = f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &count, extProps.data());
372 if (err == VK_SUCCESS) {
373 QVulkanInfoVector<QVulkanExtension> exts;
374 for (
const VkExtensionProperties &prop : extProps) {
375 QVulkanExtension ext;
376 ext.name = prop.extensionName;
377 ext.version = prop.specVersion;
380 d->supportedDevExtensions.insert(physDev, exts);
381 qCDebug(lcGuiVk) <<
"Supported device extensions:" << exts;
386 qWarning(
"QVulkanWindow: Failed to query device extension count: %d", err);
387 return QVulkanInfoVector<QVulkanExtension>();
391
392
393
394
395
396
397
398
399
400
401
402void QVulkanWindow::setDeviceExtensions(
const QByteArrayList &extensions)
405 if (d->status != QVulkanWindowPrivate::StatusUninitialized) {
406 qWarning(
"QVulkanWindow: Attempted to set device extensions when already initialized");
409 d->requestedDevExtensions = extensions;
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437void QVulkanWindow::setPreferredColorFormats(
const QList<VkFormat> &formats)
440 if (d->status != QVulkanWindowPrivate::StatusUninitialized) {
441 qWarning(
"QVulkanWindow: Attempted to set preferred color format when already initialized");
444 d->requestedColorFormats = formats;
450} q_vk_sampleCounts[] = {
452 { VK_SAMPLE_COUNT_1_BIT, 1 },
453 { VK_SAMPLE_COUNT_2_BIT, 2 },
454 { VK_SAMPLE_COUNT_4_BIT, 4 },
455 { VK_SAMPLE_COUNT_8_BIT, 8 },
456 { VK_SAMPLE_COUNT_16_BIT, 16 },
457 { VK_SAMPLE_COUNT_32_BIT, 32 },
458 { VK_SAMPLE_COUNT_64_BIT, 64 }
462
463
464
465
466
467
468
469
470
471
472
473QList<
int> QVulkanWindow::supportedSampleCounts()
475 Q_D(
const QVulkanWindow);
478 availablePhysicalDevices();
480 if (d->physDevs.isEmpty()) {
481 qWarning(
"QVulkanWindow: No physical devices found");
485 const VkPhysicalDeviceLimits *limits = &d->physDevProps[d->physDevIndex].limits;
486 VkSampleCountFlags color = limits->framebufferColorSampleCounts;
487 VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
488 VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
490 for (
const auto &qvk_sampleCount : q_vk_sampleCounts) {
491 if ((color & qvk_sampleCount.mask)
492 && (depth & qvk_sampleCount.mask)
493 && (stencil & qvk_sampleCount.mask))
495 result.append(qvk_sampleCount.count);
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523void QVulkanWindow::setSampleCount(
int sampleCount)
526 if (d->status != QVulkanWindowPrivate::StatusUninitialized) {
527 qWarning(
"QVulkanWindow: Attempted to set sample count when already initialized");
532 sampleCount = qBound(1, sampleCount, 64);
534 if (!supportedSampleCounts().contains(sampleCount)) {
535 qWarning(
"QVulkanWindow: Attempted to set unsupported sample count %d", sampleCount);
539 for (
const auto &qvk_sampleCount : q_vk_sampleCounts) {
540 if (qvk_sampleCount.count == sampleCount) {
541 d->sampleCount = qvk_sampleCount.mask;
549void QVulkanWindowPrivate::init()
552 Q_ASSERT(status == StatusUninitialized);
554 qCDebug(lcGuiVk,
"QVulkanWindow init");
556 inst = q->vulkanInstance();
558 qWarning(
"QVulkanWindow: Attempted to initialize without a QVulkanInstance");
561 status = StatusFailRetry;
566 renderer = q->createRenderer();
568 surface = QVulkanInstance::surfaceForWindow(q);
569 if (surface == VK_NULL_HANDLE) {
570 qWarning(
"QVulkanWindow: Failed to retrieve Vulkan surface for window");
571 status = StatusFailRetry;
575 q->availablePhysicalDevices();
577 if (physDevs.isEmpty()) {
578 qWarning(
"QVulkanWindow: No physical devices found");
583 if (physDevIndex < 0 || physDevIndex >= physDevs.size()) {
584 qWarning(
"QVulkanWindow: Invalid physical device index; defaulting to 0");
587 qCDebug(lcGuiVk,
"Using physical device [%d]", physDevIndex);
591 renderer->preInitResources();
593 VkPhysicalDevice physDev = physDevs.at(physDevIndex);
594 QVulkanFunctions *f = inst->functions();
596 uint32_t queueCount = 0;
597 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount,
nullptr);
598 QList<VkQueueFamilyProperties> queueFamilyProps(queueCount);
599 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
600 gfxQueueFamilyIdx = uint32_t(-1);
601 presQueueFamilyIdx = uint32_t(-1);
602 for (
int i = 0; i < queueFamilyProps.size(); ++i) {
603 const bool supportsPresent = inst->supportsPresent(physDev, i, q);
604 qCDebug(lcGuiVk,
"queue family %d: flags=0x%x count=%d supportsPresent=%d", i,
605 queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount, supportsPresent);
606 if (gfxQueueFamilyIdx == uint32_t(-1)
607 && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
609 gfxQueueFamilyIdx = i;
611 if (gfxQueueFamilyIdx != uint32_t(-1)) {
612 presQueueFamilyIdx = gfxQueueFamilyIdx;
614 qCDebug(lcGuiVk,
"No queue with graphics+present; trying separate queues");
615 for (
int i = 0; i < queueFamilyProps.size(); ++i) {
616 if (gfxQueueFamilyIdx == uint32_t(-1) && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT))
617 gfxQueueFamilyIdx = i;
618 if (presQueueFamilyIdx == uint32_t(-1) && inst->supportsPresent(physDev, i, q))
619 presQueueFamilyIdx = i;
622 if (gfxQueueFamilyIdx == uint32_t(-1)) {
623 qWarning(
"QVulkanWindow: No graphics queue family found");
627 if (presQueueFamilyIdx == uint32_t(-1)) {
628 qWarning(
"QVulkanWindow: No present queue family found");
634 if (qEnvironmentVariableIsSet(
"QT_VK_PRESENT_QUEUE_INDEX"))
635 presQueueFamilyIdx = qEnvironmentVariableIntValue(
"QT_VK_PRESENT_QUEUE_INDEX");
637 qCDebug(lcGuiVk,
"Using queue families: graphics = %u present = %u", gfxQueueFamilyIdx, presQueueFamilyIdx);
639 QList<VkDeviceQueueCreateInfo> queueInfo;
640 queueInfo.reserve(2);
641 const float prio[] = { 0 };
642 VkDeviceQueueCreateInfo addQueueInfo;
643 memset(&addQueueInfo, 0,
sizeof(addQueueInfo));
644 addQueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
645 addQueueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
646 addQueueInfo.queueCount = 1;
647 addQueueInfo.pQueuePriorities = prio;
648 queueInfo.append(addQueueInfo);
649 if (gfxQueueFamilyIdx != presQueueFamilyIdx) {
650 addQueueInfo.queueFamilyIndex = presQueueFamilyIdx;
651 addQueueInfo.queueCount = 1;
652 addQueueInfo.pQueuePriorities = prio;
653 queueInfo.append(addQueueInfo);
655 if (queueCreateInfoModifier) {
656 queueCreateInfoModifier(queueFamilyProps.constData(), queueCount, queueInfo);
657 bool foundGfxQueue =
false;
658 bool foundPresQueue =
false;
659 for (
const VkDeviceQueueCreateInfo& createInfo : std::as_const(queueInfo)) {
660 foundGfxQueue |= createInfo.queueFamilyIndex == gfxQueueFamilyIdx;
661 foundPresQueue |= createInfo.queueFamilyIndex == presQueueFamilyIdx;
663 if (!foundGfxQueue) {
664 qWarning(
"QVulkanWindow: Graphics queue missing after call to queueCreateInfoModifier");
668 if (!foundPresQueue) {
669 qWarning(
"QVulkanWindow: Present queue missing after call to queueCreateInfoModifier");
677 QList<
const char *> devExts;
678 QVulkanInfoVector<QVulkanExtension> supportedExtensions = q->supportedDeviceExtensions();
679 QByteArrayList reqExts = requestedDevExtensions;
680 reqExts.append(
"VK_KHR_swapchain");
682 QByteArray envExts = qgetenv(
"QT_VULKAN_DEVICE_EXTENSIONS");
683 if (!envExts.isEmpty()) {
684 QByteArrayList envExtList = envExts.split(
';');
685 for (
const QByteArray &ext : std::as_const(reqExts))
686 envExtList.removeAll(ext);
687 reqExts.append(envExtList);
690 for (
const QByteArray &ext : std::as_const(reqExts)) {
691 if (supportedExtensions.contains(ext))
692 devExts.append(ext.constData());
694 qCDebug(lcGuiVk) <<
"Enabling device extensions:" << devExts;
696 VkDeviceCreateInfo devInfo;
697 memset(&devInfo, 0,
sizeof(devInfo));
698 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
699 devInfo.queueCreateInfoCount = queueInfo.size();
700 devInfo.pQueueCreateInfos = queueInfo.constData();
701 devInfo.enabledExtensionCount = devExts.size();
702 devInfo.ppEnabledExtensionNames = devExts.constData();
704 VkPhysicalDeviceFeatures features = {};
705 VkPhysicalDeviceFeatures2 features2 = {};
706 if (enabledFeatures2Modifier) {
707 features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
708 enabledFeatures2Modifier(features2);
709 devInfo.pNext = &features2;
710 }
else if (enabledFeaturesModifier) {
711 enabledFeaturesModifier(features);
712 devInfo.pEnabledFeatures = &features;
716 f->vkGetPhysicalDeviceFeatures(physDev, &features);
717 features.robustBufferAccess = VK_FALSE;
718 devInfo.pEnabledFeatures = &features;
721 const QByteArray stdValName = QByteArrayLiteral(
"VK_LAYER_KHRONOS_validation");
722 const char *stdValNamePtr = stdValName.constData();
728 uint32_t apiVersion = physDevProps[physDevIndex].apiVersion;
729 if (VK_VERSION_MAJOR(apiVersion) == 1
730 && VK_VERSION_MINOR(apiVersion) == 0
731 && VK_VERSION_PATCH(apiVersion) <= 13)
734 if (inst->layers().contains(stdValName)) {
736 VkResult err = f->vkEnumerateDeviceLayerProperties(physDev, &count,
nullptr);
737 if (err == VK_SUCCESS) {
738 QList<VkLayerProperties> layerProps(count);
739 err = f->vkEnumerateDeviceLayerProperties(physDev, &count, layerProps.data());
740 if (err == VK_SUCCESS) {
741 for (
const VkLayerProperties &prop : layerProps) {
742 if (!strncmp(prop.layerName, stdValNamePtr, stdValName.size())) {
743 devInfo.enabledLayerCount = 1;
744 devInfo.ppEnabledLayerNames = &stdValNamePtr;
753 VkResult err = f->vkCreateDevice(physDev, &devInfo,
nullptr, &dev);
754 if (err == VK_ERROR_DEVICE_LOST) {
755 qWarning(
"QVulkanWindow: Physical device lost");
757 renderer->physicalDeviceLost();
760 physDevProps.clear();
761 status = StatusUninitialized;
762 qCDebug(lcGuiVk,
"Attempting to restart in 2 seconds");
763 QTimer::singleShot(2000, q, [
this]() { ensureStarted(); });
766 if (err != VK_SUCCESS) {
767 qWarning(
"QVulkanWindow: Failed to create device: %d", err);
772 devFuncs = inst->deviceFunctions(dev);
775 devFuncs->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, 0, &gfxQueue);
776 if (gfxQueueFamilyIdx == presQueueFamilyIdx)
777 presQueue = gfxQueue;
779 devFuncs->vkGetDeviceQueue(dev, presQueueFamilyIdx, 0, &presQueue);
781 VkCommandPoolCreateInfo poolInfo;
782 memset(&poolInfo, 0,
sizeof(poolInfo));
783 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
784 poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
785 err = devFuncs->vkCreateCommandPool(dev, &poolInfo,
nullptr, &cmdPool);
786 if (err != VK_SUCCESS) {
787 qWarning(
"QVulkanWindow: Failed to create command pool: %d", err);
791 if (gfxQueueFamilyIdx != presQueueFamilyIdx) {
792 poolInfo.queueFamilyIndex = presQueueFamilyIdx;
793 err = devFuncs->vkCreateCommandPool(dev, &poolInfo,
nullptr, &presCmdPool);
794 if (err != VK_SUCCESS) {
795 qWarning(
"QVulkanWindow: Failed to create command pool for present queue: %d", err);
801 hostVisibleMemIndex = 0;
802 VkPhysicalDeviceMemoryProperties physDevMemProps;
803 bool hostVisibleMemIndexSet =
false;
804 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
805 for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
806 const VkMemoryType *memType = physDevMemProps.memoryTypes;
807 qCDebug(lcGuiVk,
"memtype %d: flags=0x%x", i, memType[i].propertyFlags);
810 const int hostVisibleAndCoherent = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
811 if ((memType[i].propertyFlags & hostVisibleAndCoherent) == hostVisibleAndCoherent) {
812 if (!hostVisibleMemIndexSet
813 || (memType[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT)) {
814 hostVisibleMemIndexSet =
true;
815 hostVisibleMemIndex = i;
819 qCDebug(lcGuiVk,
"Picked memtype %d for host visible memory", hostVisibleMemIndex);
820 deviceLocalMemIndex = 0;
821 for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
822 const VkMemoryType *memType = physDevMemProps.memoryTypes;
824 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
825 deviceLocalMemIndex = i;
829 qCDebug(lcGuiVk,
"Picked memtype %d for device local memory", deviceLocalMemIndex);
831 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR || !vkGetPhysicalDeviceSurfaceFormatsKHR) {
832 vkGetPhysicalDeviceSurfaceCapabilitiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
833 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
834 vkGetPhysicalDeviceSurfaceFormatsKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
835 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceFormatsKHR"));
836 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR || !vkGetPhysicalDeviceSurfaceFormatsKHR) {
837 qWarning(
"QVulkanWindow: Physical device surface queries not available");
848 uint32_t formatCount = 0;
849 vkGetPhysicalDeviceSurfaceFormatsKHR(physDev, surface, &formatCount,
nullptr);
850 QList<VkSurfaceFormatKHR> formats(formatCount);
852 vkGetPhysicalDeviceSurfaceFormatsKHR(physDev, surface, &formatCount, formats.data());
854 colorFormat = VK_FORMAT_B8G8R8A8_UNORM;
855 colorSpace = VkColorSpaceKHR(0);
858 if (!formats.isEmpty() && formats[0].format != VK_FORMAT_UNDEFINED) {
859 colorFormat = formats[0].format;
860 colorSpace = formats[0].colorSpace;
864 if (!formats.isEmpty() && !requestedColorFormats.isEmpty()) {
865 for (VkFormat reqFmt : std::as_const(requestedColorFormats)) {
866 auto r = std::find_if(formats.cbegin(), formats.cend(),
867 [reqFmt](
const VkSurfaceFormatKHR &sfmt) {
return sfmt.format == reqFmt; });
868 if (r != formats.cend()) {
869 colorFormat = r->format;
870 colorSpace = r->colorSpace;
876#if QT_CONFIG(wayland)
881 const bool hasPassthrough = std::any_of(formats.cbegin(), formats.cend(), [
this](
const VkSurfaceFormatKHR &format) {
882 return format.format == colorFormat && format.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT;
884 if (hasPassthrough) {
885 colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
889 const VkFormat dsFormatCandidates[] = {
890 VK_FORMAT_D24_UNORM_S8_UINT,
891 VK_FORMAT_D32_SFLOAT_S8_UINT,
892 VK_FORMAT_D16_UNORM_S8_UINT
894 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
896 while (dsFormatIdx < dsFormatCandidateCount) {
897 dsFormat = dsFormatCandidates[dsFormatIdx];
898 VkFormatProperties fmtProp;
899 f->vkGetPhysicalDeviceFormatProperties(physDev, dsFormat, &fmtProp);
900 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
904 if (dsFormatIdx == dsFormatCandidateCount)
905 qWarning(
"QVulkanWindow: Failed to find an optimal depth-stencil format");
907 qCDebug(lcGuiVk,
"Color format: %d Depth-stencil format: %d", colorFormat, dsFormat);
909 if (!createDefaultRenderPass())
913 renderer->initResources();
915 status = StatusDeviceReady;
918void QVulkanWindowPrivate::reset()
923 qCDebug(lcGuiVk,
"QVulkanWindow reset");
925 devFuncs->vkDeviceWaitIdle(dev);
928 renderer->releaseResources();
929 devFuncs->vkDeviceWaitIdle(dev);
932 if (defaultRenderPass) {
933 devFuncs->vkDestroyRenderPass(dev, defaultRenderPass,
nullptr);
934 defaultRenderPass = VK_NULL_HANDLE;
938 devFuncs->vkDestroyCommandPool(dev, cmdPool,
nullptr);
939 cmdPool = VK_NULL_HANDLE;
943 devFuncs->vkDestroyCommandPool(dev, presCmdPool,
nullptr);
944 presCmdPool = VK_NULL_HANDLE;
947 if (frameGrabImage) {
948 devFuncs->vkDestroyImage(dev, frameGrabImage,
nullptr);
949 frameGrabImage = VK_NULL_HANDLE;
952 if (frameGrabImageMem) {
953 devFuncs->vkFreeMemory(dev, frameGrabImageMem,
nullptr);
954 frameGrabImageMem = VK_NULL_HANDLE;
958 devFuncs->vkDestroyDevice(dev,
nullptr);
959 inst->resetDeviceFunctions(dev);
960 dev = VK_NULL_HANDLE;
961 vkCreateSwapchainKHR =
nullptr;
964 surface = VK_NULL_HANDLE;
966 status = StatusUninitialized;
969bool QVulkanWindowPrivate::createDefaultRenderPass()
971 VkAttachmentDescription attDesc[3];
972 memset(attDesc, 0,
sizeof(attDesc));
974 const bool msaa = sampleCount > VK_SAMPLE_COUNT_1_BIT;
977 attDesc[0].format = colorFormat;
978 attDesc[0].samples = VK_SAMPLE_COUNT_1_BIT;
979 attDesc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
980 attDesc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
981 attDesc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
982 attDesc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
983 attDesc[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
984 attDesc[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
986 attDesc[1].format = dsFormat;
987 attDesc[1].samples = sampleCount;
988 attDesc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
989 attDesc[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
990 attDesc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
991 attDesc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
992 attDesc[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
993 attDesc[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
997 attDesc[2].format = colorFormat;
998 attDesc[2].samples = sampleCount;
999 attDesc[2].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1000 attDesc[2].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
1001 attDesc[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1002 attDesc[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1003 attDesc[2].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1004 attDesc[2].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1007 VkAttachmentReference colorRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
1008 VkAttachmentReference resolveRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
1009 VkAttachmentReference dsRef = { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
1011 VkSubpassDescription subPassDesc;
1012 memset(&subPassDesc, 0,
sizeof(subPassDesc));
1013 subPassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1014 subPassDesc.colorAttachmentCount = 1;
1015 subPassDesc.pColorAttachments = &colorRef;
1016 subPassDesc.pDepthStencilAttachment = &dsRef;
1018 VkRenderPassCreateInfo rpInfo;
1019 memset(&rpInfo, 0,
sizeof(rpInfo));
1020 rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1021 rpInfo.attachmentCount = 2;
1022 rpInfo.pAttachments = attDesc;
1023 rpInfo.subpassCount = 1;
1024 rpInfo.pSubpasses = &subPassDesc;
1027 colorRef.attachment = 2;
1028 subPassDesc.pResolveAttachments = &resolveRef;
1029 rpInfo.attachmentCount = 3;
1032 VkResult err = devFuncs->vkCreateRenderPass(dev, &rpInfo,
nullptr, &defaultRenderPass);
1033 if (err != VK_SUCCESS) {
1034 qWarning(
"QVulkanWindow: Failed to create renderpass: %d", err);
1041void QVulkanWindowPrivate::recreateSwapChain()
1044 Q_ASSERT(status >= StatusDeviceReady);
1046 swapChainImageSize = q->size() * q->devicePixelRatio();
1048 if (swapChainImageSize.isEmpty())
1051 QVulkanInstance *inst = q->vulkanInstance();
1052 QVulkanFunctions *f = inst->functions();
1053 devFuncs->vkDeviceWaitIdle(dev);
1055 if (!vkCreateSwapchainKHR) {
1056 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
1057 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
1058 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
1059 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
1060 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
1063 VkPhysicalDevice physDev = physDevs.at(physDevIndex);
1064 VkSurfaceCapabilitiesKHR surfaceCaps;
1065 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, surface, &surfaceCaps);
1066 uint32_t reqBufferCount;
1067 if (surfaceCaps.maxImageCount == 0)
1068 reqBufferCount = qMax<uint32_t>(2, surfaceCaps.minImageCount);
1070 reqBufferCount = qMax(qMin<uint32_t>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
1072 VkExtent2D bufferSize = surfaceCaps.currentExtent;
1073 if (bufferSize.width == uint32_t(-1)) {
1074 Q_ASSERT(bufferSize.height == uint32_t(-1));
1075 bufferSize.width = swapChainImageSize.width();
1076 bufferSize.height = swapChainImageSize.height();
1078 swapChainImageSize = QSize(bufferSize.width, bufferSize.height);
1081 VkSurfaceTransformFlagBitsKHR preTransform =
1082 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
1083 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
1084 : surfaceCaps.currentTransform;
1086 VkCompositeAlphaFlagBitsKHR compositeAlpha =
1087 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
1088 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
1089 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
1091 if (q->requestedFormat().hasAlpha()) {
1092 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
1093 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
1094 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
1095 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
1098 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1099 swapChainSupportsReadBack = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1100 if (swapChainSupportsReadBack)
1101 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1103 VkSwapchainKHR oldSwapChain = swapChain;
1104 VkSwapchainCreateInfoKHR swapChainInfo;
1105 memset(&swapChainInfo, 0,
sizeof(swapChainInfo));
1106 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
1107 swapChainInfo.surface = surface;
1108 swapChainInfo.minImageCount = reqBufferCount;
1109 swapChainInfo.imageFormat = colorFormat;
1110 swapChainInfo.imageColorSpace = colorSpace;
1111 swapChainInfo.imageExtent = bufferSize;
1112 swapChainInfo.imageArrayLayers = 1;
1113 swapChainInfo.imageUsage = usage;
1114 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
1115 swapChainInfo.preTransform = preTransform;
1116 swapChainInfo.compositeAlpha = compositeAlpha;
1117 swapChainInfo.presentMode = presentMode;
1118 swapChainInfo.clipped =
true;
1119 swapChainInfo.oldSwapchain = oldSwapChain;
1121 qCDebug(lcGuiVk,
"Creating new swap chain of %d buffers, size %dx%d", reqBufferCount, bufferSize.width, bufferSize.height);
1123 VkSwapchainKHR newSwapChain;
1124 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
1125 if (err != VK_SUCCESS) {
1126 qWarning(
"QVulkanWindow: Failed to create swap chain: %d", err);
1133 swapChain = newSwapChain;
1135 uint32_t actualSwapChainBufferCount = 0;
1136 err = vkGetSwapchainImagesKHR(dev, swapChain, &actualSwapChainBufferCount,
nullptr);
1137 if (err != VK_SUCCESS || actualSwapChainBufferCount < 2) {
1138 qWarning(
"QVulkanWindow: Failed to get swapchain images: %d (count=%d)", err, actualSwapChainBufferCount);
1142 qCDebug(lcGuiVk,
"Actual swap chain buffer count: %d (supportsReadback=%d)",
1143 actualSwapChainBufferCount, swapChainSupportsReadBack);
1144 if (actualSwapChainBufferCount > MAX_SWAPCHAIN_BUFFER_COUNT) {
1145 qWarning(
"QVulkanWindow: Too many swapchain buffers (%d)", actualSwapChainBufferCount);
1148 swapChainBufferCount = actualSwapChainBufferCount;
1150 VkImage swapChainImages[MAX_SWAPCHAIN_BUFFER_COUNT];
1151 err = vkGetSwapchainImagesKHR(dev, swapChain, &actualSwapChainBufferCount, swapChainImages);
1152 if (err != VK_SUCCESS) {
1153 qWarning(
"QVulkanWindow: Failed to get swapchain images: %d", err);
1157 if (!createTransientImage(dsFormat,
1158 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
1159 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
1168 const bool msaa = sampleCount > VK_SAMPLE_COUNT_1_BIT;
1169 VkImage msaaImages[MAX_SWAPCHAIN_BUFFER_COUNT];
1170 VkImageView msaaViews[MAX_SWAPCHAIN_BUFFER_COUNT];
1173 if (!createTransientImage(colorFormat,
1174 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1175 VK_IMAGE_ASPECT_COLOR_BIT,
1179 swapChainBufferCount))
1185 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
nullptr, VK_FENCE_CREATE_SIGNALED_BIT };
1187 for (
int i = 0; i < swapChainBufferCount; ++i) {
1188 ImageResources &image(imageRes[i]);
1189 image.image = swapChainImages[i];
1192 image.msaaImage = msaaImages[i];
1193 image.msaaImageView = msaaViews[i];
1196 VkImageViewCreateInfo imgViewInfo;
1197 memset(&imgViewInfo, 0,
sizeof(imgViewInfo));
1198 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1199 imgViewInfo.image = swapChainImages[i];
1200 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1201 imgViewInfo.format = colorFormat;
1202 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1203 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1204 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1205 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1206 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1207 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1208 err = devFuncs->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
1209 if (err != VK_SUCCESS) {
1210 qWarning(
"QVulkanWindow: Failed to create swapchain image view %d: %d", i, err);
1214 VkImageView views[3] = { image.imageView,
1216 msaa ? image.msaaImageView : VK_NULL_HANDLE };
1217 VkFramebufferCreateInfo fbInfo;
1218 memset(&fbInfo, 0,
sizeof(fbInfo));
1219 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
1220 fbInfo.renderPass = defaultRenderPass;
1221 fbInfo.attachmentCount = msaa ? 3 : 2;
1222 fbInfo.pAttachments = views;
1223 fbInfo.width = swapChainImageSize.width();
1224 fbInfo.height = swapChainImageSize.height();
1226 VkResult err = devFuncs->vkCreateFramebuffer(dev, &fbInfo,
nullptr, &image.fb);
1227 if (err != VK_SUCCESS) {
1228 qWarning(
"QVulkanWindow: Failed to create framebuffer: %d", err);
1232 if (gfxQueueFamilyIdx != presQueueFamilyIdx) {
1234 VkCommandBufferAllocateInfo cmdBufInfo = {
1235 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
nullptr, presCmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1 };
1236 err = devFuncs->vkAllocateCommandBuffers(dev, &cmdBufInfo, &image.presTransCmdBuf);
1237 if (err != VK_SUCCESS) {
1238 qWarning(
"QVulkanWindow: Failed to allocate acquire-on-present-queue command buffer: %d", err);
1241 VkCommandBufferBeginInfo cmdBufBeginInfo = {
1242 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
nullptr,
1243 VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
nullptr };
1244 err = devFuncs->vkBeginCommandBuffer(image.presTransCmdBuf, &cmdBufBeginInfo);
1245 if (err != VK_SUCCESS) {
1246 qWarning(
"QVulkanWindow: Failed to begin acquire-on-present-queue command buffer: %d", err);
1249 VkImageMemoryBarrier presTrans;
1250 memset(&presTrans, 0,
sizeof(presTrans));
1251 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1252 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1253 presTrans.oldLayout = presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1254 presTrans.srcQueueFamilyIndex = gfxQueueFamilyIdx;
1255 presTrans.dstQueueFamilyIndex = presQueueFamilyIdx;
1256 presTrans.image = image.image;
1257 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1258 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
1259 devFuncs->vkCmdPipelineBarrier(image.presTransCmdBuf,
1260 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1261 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1262 0, 0,
nullptr, 0,
nullptr,
1264 err = devFuncs->vkEndCommandBuffer(image.presTransCmdBuf);
1265 if (err != VK_SUCCESS) {
1266 qWarning(
"QVulkanWindow: Failed to end acquire-on-present-queue command buffer: %d", err);
1274 VkSemaphoreCreateInfo semInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
nullptr, 0 };
1275 for (
int i = 0; i < frameLag; ++i) {
1276 FrameResources &frame(frameRes[i]);
1278 frame.imageAcquired =
false;
1279 frame.imageSemWaitable =
false;
1281 devFuncs->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
1282 devFuncs->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.drawSem);
1283 if (gfxQueueFamilyIdx != presQueueFamilyIdx)
1284 devFuncs->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.presTransSem);
1286 err = devFuncs->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
1287 if (err != VK_SUCCESS) {
1288 qWarning(
"QVulkanWindow: Failed to create command buffer fence: %d", err);
1291 frame.cmdFenceWaitable =
true;
1297 renderer->initSwapChainResources();
1299 status = StatusReady;
1302uint32_t QVulkanWindowPrivate::chooseTransientImageMemType(VkImage img, uint32_t startIndex)
1304 VkPhysicalDeviceMemoryProperties physDevMemProps;
1305 inst->functions()->vkGetPhysicalDeviceMemoryProperties(physDevs[physDevIndex], &physDevMemProps);
1307 VkMemoryRequirements memReq;
1308 devFuncs->vkGetImageMemoryRequirements(dev, img, &memReq);
1309 uint32_t memTypeIndex = uint32_t(-1);
1311 if (memReq.memoryTypeBits) {
1313 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1314 bool foundDevLocal =
false;
1315 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1316 if (memReq.memoryTypeBits & (1 << i)) {
1317 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1318 if (!foundDevLocal) {
1319 foundDevLocal =
true;
1322 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1331 return memTypeIndex;
1336 return (v + byteAlign - 1) & ~(byteAlign - 1);
1339bool QVulkanWindowPrivate::createTransientImage(VkFormat format,
1340 VkImageUsageFlags usage,
1341 VkImageAspectFlags aspectMask,
1343 VkDeviceMemory *mem,
1347 VkMemoryRequirements memReq;
1350 Q_ASSERT(count > 0);
1351 for (
int i = 0; i < count; ++i) {
1352 VkImageCreateInfo imgInfo;
1353 memset(&imgInfo, 0,
sizeof(imgInfo));
1354 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1355 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1356 imgInfo.format = format;
1357 imgInfo.extent.width = swapChainImageSize.width();
1358 imgInfo.extent.height = swapChainImageSize.height();
1359 imgInfo.extent.depth = 1;
1360 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1361 imgInfo.samples = sampleCount;
1362 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1363 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1365 err = devFuncs->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1366 if (err != VK_SUCCESS) {
1367 qWarning(
"QVulkanWindow: Failed to create image: %d", err);
1374 devFuncs->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1377 VkMemoryAllocateInfo memInfo;
1378 memset(&memInfo, 0,
sizeof(memInfo));
1379 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1380 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * count;
1382 uint32_t startIndex = 0;
1384 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1385 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1386 qWarning(
"QVulkanWindow: No suitable memory type found");
1389 startIndex = memInfo.memoryTypeIndex + 1;
1390 qCDebug(lcGuiVk,
"Allocating %u bytes for transient image (memtype %u)",
1391 uint32_t(memInfo.allocationSize), memInfo.memoryTypeIndex);
1392 err = devFuncs->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1393 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1394 qWarning(
"QVulkanWindow: Failed to allocate image memory: %d", err);
1397 }
while (err != VK_SUCCESS);
1399 VkDeviceSize ofs = 0;
1400 for (
int i = 0; i < count; ++i) {
1401 err = devFuncs->vkBindImageMemory(dev, images[i], *mem, ofs);
1402 if (err != VK_SUCCESS) {
1403 qWarning(
"QVulkanWindow: Failed to bind image memory: %d", err);
1406 ofs += aligned(memReq.size, memReq.alignment);
1408 VkImageViewCreateInfo imgViewInfo;
1409 memset(&imgViewInfo, 0,
sizeof(imgViewInfo));
1410 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1411 imgViewInfo.image = images[i];
1412 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1413 imgViewInfo.format = format;
1414 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1415 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1416 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1417 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1418 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1419 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1421 err = devFuncs->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1422 if (err != VK_SUCCESS) {
1423 qWarning(
"QVulkanWindow: Failed to create image view: %d", err);
1431void QVulkanWindowPrivate::releaseSwapChain()
1433 if (!dev || !swapChain)
1436 qCDebug(lcGuiVk,
"Releasing swapchain");
1438 devFuncs->vkDeviceWaitIdle(dev);
1441 renderer->releaseSwapChainResources();
1442 devFuncs->vkDeviceWaitIdle(dev);
1445 for (
int i = 0; i < frameLag; ++i) {
1446 FrameResources &frame(frameRes[i]);
1448 devFuncs->vkFreeCommandBuffers(dev, cmdPool, 1, &frame.cmdBuf);
1449 frame.cmdBuf = VK_NULL_HANDLE;
1451 if (frame.imageSem) {
1452 devFuncs->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
1453 frame.imageSem = VK_NULL_HANDLE;
1455 if (frame.drawSem) {
1456 devFuncs->vkDestroySemaphore(dev, frame.drawSem,
nullptr);
1457 frame.drawSem = VK_NULL_HANDLE;
1459 if (frame.presTransSem) {
1460 devFuncs->vkDestroySemaphore(dev, frame.presTransSem,
nullptr);
1461 frame.presTransSem = VK_NULL_HANDLE;
1463 if (frame.cmdFence) {
1464 if (frame.cmdFenceWaitable)
1465 devFuncs->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
1466 devFuncs->vkDestroyFence(dev, frame.cmdFence,
nullptr);
1467 frame.cmdFence = VK_NULL_HANDLE;
1468 frame.cmdFenceWaitable =
false;
1472 for (
int i = 0; i < swapChainBufferCount; ++i) {
1473 ImageResources &image(imageRes[i]);
1475 devFuncs->vkDestroyFramebuffer(dev, image.fb,
nullptr);
1476 image.fb = VK_NULL_HANDLE;
1478 if (image.imageView) {
1479 devFuncs->vkDestroyImageView(dev, image.imageView,
nullptr);
1480 image.imageView = VK_NULL_HANDLE;
1482 if (image.presTransCmdBuf) {
1483 devFuncs->vkFreeCommandBuffers(dev, presCmdPool, 1, &image.presTransCmdBuf);
1484 image.presTransCmdBuf = VK_NULL_HANDLE;
1486 if (image.msaaImageView) {
1487 devFuncs->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
1488 image.msaaImageView = VK_NULL_HANDLE;
1490 if (image.msaaImage) {
1491 devFuncs->vkDestroyImage(dev, image.msaaImage,
nullptr);
1492 image.msaaImage = VK_NULL_HANDLE;
1497 devFuncs->vkFreeMemory(dev, msaaImageMem,
nullptr);
1498 msaaImageMem = VK_NULL_HANDLE;
1502 devFuncs->vkDestroyImageView(dev, dsView,
nullptr);
1503 dsView = VK_NULL_HANDLE;
1506 devFuncs->vkDestroyImage(dev, dsImage,
nullptr);
1507 dsImage = VK_NULL_HANDLE;
1510 devFuncs->vkFreeMemory(dev, dsMem,
nullptr);
1511 dsMem = VK_NULL_HANDLE;
1515 vkDestroySwapchainKHR(dev, swapChain,
nullptr);
1516 swapChain = VK_NULL_HANDLE;
1519 if (status == StatusReady)
1520 status = StatusDeviceReady;
1524
1525
1526void QVulkanWindow::exposeEvent(QExposeEvent *)
1533 if (!d->flags.testFlag(PersistentResources)) {
1534 d->releaseSwapChain();
1540void QVulkanWindowPrivate::ensureStarted()
1543 if (status == QVulkanWindowPrivate::StatusFailRetry)
1544 status = QVulkanWindowPrivate::StatusUninitialized;
1545 if (status == QVulkanWindowPrivate::StatusUninitialized) {
1547 if (status == QVulkanWindowPrivate::StatusDeviceReady)
1548 recreateSwapChain();
1550 if (status == QVulkanWindowPrivate::StatusReady)
1555
1556
1557void QVulkanWindow::resizeEvent(QResizeEvent *)
1563
1564
1565bool QVulkanWindow::event(QEvent *e)
1569 switch (e->type()) {
1571 case QEvent::UpdateRequest:
1579 case QEvent::PlatformSurface:
1580 if (
static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) {
1581 d->releaseSwapChain();
1590 return QWindow::event(e);
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1613
1614
1615
1616
1617
1618
1619void QVulkanWindow::setQueueCreateInfoModifier(
const QueueCreateInfoModifier &modifier)
1622 d->queueCreateInfoModifier = modifier;
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659void QVulkanWindow::setEnabledFeaturesModifier(
const EnabledFeaturesModifier &modifier)
1662 d->enabledFeaturesModifier = modifier;
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1693
1694
1695
1696
1697
1698void QVulkanWindow::setEnabledFeaturesModifier(EnabledFeatures2Modifier modifier)
1701 d->enabledFeatures2Modifier = std::move(modifier);
1705
1706
1707
1708
1709
1710
1711bool QVulkanWindow::isValid()
const
1713 Q_D(
const QVulkanWindow);
1714 return d->status == QVulkanWindowPrivate::StatusReady;
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728QVulkanWindowRenderer *QVulkanWindow::createRenderer()
1734
1735
1736QVulkanWindowRenderer::~QVulkanWindowRenderer()
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756void QVulkanWindowRenderer::preInitResources()
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775void QVulkanWindowRenderer::initResources()
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797void QVulkanWindowRenderer::initSwapChainResources()
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820void QVulkanWindowRenderer::releaseSwapChainResources()
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836void QVulkanWindowRenderer::releaseResources()
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881void QVulkanWindowRenderer::physicalDeviceLost()
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900void QVulkanWindowRenderer::logicalDeviceLost()
1904QSize QVulkanWindowPrivate::surfacePixelSize()
const
1906 Q_Q(
const QVulkanWindow);
1907 VkSurfaceCapabilitiesKHR surfaceCaps = {};
1908 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDevs.at(physDevIndex), surface, &surfaceCaps);
1909 VkExtent2D bufferSize = surfaceCaps.currentExtent;
1910 if (bufferSize.width == uint32_t(-1)) {
1911 Q_ASSERT(bufferSize.height == uint32_t(-1));
1912 return q->size() * q->devicePixelRatio();
1914 return QSize(
int(bufferSize.width),
int(bufferSize.height));
1917void QVulkanWindowPrivate::beginFrame()
1919 if (!swapChain || framePending)
1923 if (swapChainImageSize != surfacePixelSize()) {
1924 recreateSwapChain();
1930 FrameResources &frame(frameRes[currentFrame]);
1931 if (frame.cmdFenceWaitable) {
1932 devFuncs->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
1933 devFuncs->vkResetFences(dev, 1, &frame.cmdFence);
1934 frame.cmdFenceWaitable =
false;
1938 if (!frame.imageAcquired) {
1939 VkResult err = vkAcquireNextImageKHR(dev, swapChain, UINT64_MAX,
1940 frame.imageSem, VK_NULL_HANDLE, ¤tImage);
1941 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
1942 frame.imageSemWaitable =
true;
1943 frame.imageAcquired =
true;
1944 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
1945 recreateSwapChain();
1949 if (!checkDeviceLost(err))
1950 qWarning(
"QVulkanWindow: Failed to acquire next swapchain image: %d", err);
1958 devFuncs->vkFreeCommandBuffers(dev, cmdPool, 1, &frame.cmdBuf);
1959 frame.cmdBuf =
nullptr;
1962 VkCommandBufferAllocateInfo cmdBufInfo = {
1963 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
nullptr, cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1 };
1964 VkResult err = devFuncs->vkAllocateCommandBuffers(dev, &cmdBufInfo, &frame.cmdBuf);
1965 if (err != VK_SUCCESS) {
1966 if (!checkDeviceLost(err))
1967 qWarning(
"QVulkanWindow: Failed to allocate frame command buffer: %d", err);
1971 VkCommandBufferBeginInfo cmdBufBeginInfo = {
1972 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
nullptr, 0,
nullptr };
1973 err = devFuncs->vkBeginCommandBuffer(frame.cmdBuf, &cmdBufBeginInfo);
1974 if (err != VK_SUCCESS) {
1975 if (!checkDeviceLost(err))
1976 qWarning(
"QVulkanWindow: Failed to begin frame command buffer: %d", err);
1981 frameGrabTargetImage = QImage(swapChainImageSize, QImage::Format_RGBA8888);
1983 ImageResources &image(imageRes[currentImage]);
1985 framePending =
true;
1986 renderer->startNextFrame();
1989 VkClearColorValue clearColor = { { 0.0f, 0.0f, 0.0f, 1.0f } };
1990 VkClearDepthStencilValue clearDS = { 1.0f, 0 };
1991 VkClearValue clearValues[3];
1992 memset(clearValues, 0,
sizeof(clearValues));
1993 clearValues[0].color = clearValues[2].color = clearColor;
1994 clearValues[1].depthStencil = clearDS;
1996 VkRenderPassBeginInfo rpBeginInfo;
1997 memset(&rpBeginInfo, 0,
sizeof(rpBeginInfo));
1998 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1999 rpBeginInfo.renderPass = defaultRenderPass;
2000 rpBeginInfo.framebuffer = image.fb;
2001 rpBeginInfo.renderArea.extent.width = swapChainImageSize.width();
2002 rpBeginInfo.renderArea.extent.height = swapChainImageSize.height();
2003 rpBeginInfo.clearValueCount = sampleCount > VK_SAMPLE_COUNT_1_BIT ? 3 : 2;
2004 rpBeginInfo.pClearValues = clearValues;
2005 devFuncs->vkCmdBeginRenderPass(frame.cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
2006 devFuncs->vkCmdEndRenderPass(frame.cmdBuf);
2012void QVulkanWindowPrivate::endFrame()
2016 FrameResources &frame(frameRes[currentFrame]);
2017 ImageResources &image(imageRes[currentImage]);
2019 if (gfxQueueFamilyIdx != presQueueFamilyIdx && !frameGrabbing) {
2022 VkImageMemoryBarrier presTrans;
2023 memset(&presTrans, 0,
sizeof(presTrans));
2024 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2025 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2026 presTrans.oldLayout = presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2027 presTrans.srcQueueFamilyIndex = gfxQueueFamilyIdx;
2028 presTrans.dstQueueFamilyIndex = presQueueFamilyIdx;
2029 presTrans.image = image.image;
2030 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2031 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2032 devFuncs->vkCmdPipelineBarrier(frame.cmdBuf,
2033 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2034 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2035 0, 0,
nullptr, 0,
nullptr,
2043 VkResult err = devFuncs->vkEndCommandBuffer(frame.cmdBuf);
2044 if (err != VK_SUCCESS) {
2045 if (!checkDeviceLost(err))
2046 qWarning(
"QVulkanWindow: Failed to end frame command buffer: %d", err);
2051 VkSubmitInfo submitInfo;
2052 memset(&submitInfo, 0,
sizeof(submitInfo));
2053 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2054 submitInfo.commandBufferCount = 1;
2055 submitInfo.pCommandBuffers = &frame.cmdBuf;
2056 if (frame.imageSemWaitable) {
2057 submitInfo.waitSemaphoreCount = 1;
2058 submitInfo.pWaitSemaphores = &frame.imageSem;
2060 if (!frameGrabbing) {
2061 submitInfo.signalSemaphoreCount = 1;
2062 submitInfo.pSignalSemaphores = &frame.drawSem;
2064 VkPipelineStageFlags psf = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2065 submitInfo.pWaitDstStageMask = &psf;
2067 Q_ASSERT(!frame.cmdFenceWaitable);
2069 err = devFuncs->vkQueueSubmit(gfxQueue, 1, &submitInfo, frame.cmdFence);
2070 if (err == VK_SUCCESS) {
2071 frame.imageSemWaitable =
false;
2072 frame.cmdFenceWaitable =
true;
2074 if (!checkDeviceLost(err))
2075 qWarning(
"QVulkanWindow: Failed to submit to graphics queue: %d", err);
2080 if (frameGrabbing) {
2081 finishBlockingReadback();
2082 frameGrabbing =
false;
2085 emit q->frameGrabbed(frameGrabTargetImage);
2089 if (gfxQueueFamilyIdx != presQueueFamilyIdx) {
2091 submitInfo.pWaitSemaphores = &frame.drawSem;
2092 submitInfo.pSignalSemaphores = &frame.presTransSem;
2093 submitInfo.pCommandBuffers = &image.presTransCmdBuf;
2094 err = devFuncs->vkQueueSubmit(presQueue, 1, &submitInfo, VK_NULL_HANDLE);
2095 if (err != VK_SUCCESS) {
2096 if (!checkDeviceLost(err))
2097 qWarning(
"QVulkanWindow: Failed to submit to present queue: %d", err);
2103 VkPresentInfoKHR presInfo;
2104 memset(&presInfo, 0,
sizeof(presInfo));
2105 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2106 presInfo.swapchainCount = 1;
2107 presInfo.pSwapchains = &swapChain;
2108 presInfo.pImageIndices = ¤tImage;
2109 presInfo.waitSemaphoreCount = 1;
2110 presInfo.pWaitSemaphores = gfxQueueFamilyIdx == presQueueFamilyIdx ? &frame.drawSem : &frame.presTransSem;
2114 inst->presentAboutToBeQueued(q);
2116 err = vkQueuePresentKHR(presQueue, &presInfo);
2117 if (err != VK_SUCCESS) {
2118 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2119 recreateSwapChain();
2122 }
else if (err != VK_SUBOPTIMAL_KHR) {
2123 if (!checkDeviceLost(err))
2124 qWarning(
"QVulkanWindow: Failed to present: %d", err);
2129 frame.imageAcquired =
false;
2131 inst->presentQueued(q);
2133 currentFrame = (currentFrame + 1) % frameLag;
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149void QVulkanWindow::frameReady()
2151 Q_ASSERT_X(QThread::isMainThread(),
2152 "QVulkanWindow",
"frameReady() can only be called from the GUI (main) thread");
2156 if (!d->framePending) {
2157 qWarning(
"QVulkanWindow: frameReady() called without a corresponding startNextFrame()");
2161 d->framePending =
false;
2166bool QVulkanWindowPrivate::checkDeviceLost(VkResult err)
2168 if (err == VK_ERROR_DEVICE_LOST) {
2169 qWarning(
"QVulkanWindow: Device lost");
2171 renderer->logicalDeviceLost();
2172 qCDebug(lcGuiVk,
"Releasing all resources due to device lost");
2175 qCDebug(lcGuiVk,
"Restarting");
2182void QVulkanWindowPrivate::addReadback()
2184 VkImageCreateInfo imageInfo;
2185 memset(&imageInfo, 0,
sizeof(imageInfo));
2186 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
2187 imageInfo.imageType = VK_IMAGE_TYPE_2D;
2188 imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
2189 imageInfo.extent.width = frameGrabTargetImage.width();
2190 imageInfo.extent.height = frameGrabTargetImage.height();
2191 imageInfo.extent.depth = 1;
2192 imageInfo.mipLevels = 1;
2193 imageInfo.arrayLayers = 1;
2194 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
2195 imageInfo.tiling = VK_IMAGE_TILING_LINEAR;
2196 imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2197 imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
2199 VkResult err = devFuncs->vkCreateImage(dev, &imageInfo,
nullptr, &frameGrabImage);
2200 if (err != VK_SUCCESS) {
2201 qWarning(
"QVulkanWindow: Failed to create image for readback: %d", err);
2205 VkMemoryRequirements memReq;
2206 devFuncs->vkGetImageMemoryRequirements(dev, frameGrabImage, &memReq);
2208 VkMemoryAllocateInfo allocInfo = {
2209 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
2215 err = devFuncs->vkAllocateMemory(dev, &allocInfo,
nullptr, &frameGrabImageMem);
2216 if (err != VK_SUCCESS) {
2217 qWarning(
"QVulkanWindow: Failed to allocate memory for readback image: %d", err);
2221 err = devFuncs->vkBindImageMemory(dev, frameGrabImage, frameGrabImageMem, 0);
2222 if (err != VK_SUCCESS) {
2223 qWarning(
"QVulkanWindow: Failed to bind readback image memory: %d", err);
2227 FrameResources &frame(frameRes[currentFrame]);
2228 ImageResources &image(imageRes[currentImage]);
2230 VkImageMemoryBarrier barrier;
2231 memset(&barrier, 0,
sizeof(barrier));
2232 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2233 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2234 barrier.subresourceRange.levelCount = barrier.subresourceRange.layerCount = 1;
2236 barrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2237 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2238 barrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
2239 barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2240 barrier.image = image.image;
2242 devFuncs->vkCmdPipelineBarrier(frame.cmdBuf,
2243 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2244 VK_PIPELINE_STAGE_TRANSFER_BIT,
2245 0, 0,
nullptr, 0,
nullptr,
2248 barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
2249 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2250 barrier.srcAccessMask = 0;
2251 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
2252 barrier.image = frameGrabImage;
2254 devFuncs->vkCmdPipelineBarrier(frame.cmdBuf,
2255 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2256 VK_PIPELINE_STAGE_TRANSFER_BIT,
2257 0, 0,
nullptr, 0,
nullptr,
2260 VkImageCopy copyInfo;
2261 memset(©Info, 0,
sizeof(copyInfo));
2262 copyInfo.srcSubresource.aspectMask = copyInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2263 copyInfo.srcSubresource.layerCount = copyInfo.dstSubresource.layerCount = 1;
2264 copyInfo.extent.width = frameGrabTargetImage.width();
2265 copyInfo.extent.height = frameGrabTargetImage.height();
2266 copyInfo.extent.depth = 1;
2268 devFuncs->vkCmdCopyImage(frame.cmdBuf, image.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2269 frameGrabImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Info);
2271 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2272 barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
2273 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
2274 barrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
2275 barrier.image = frameGrabImage;
2277 devFuncs->vkCmdPipelineBarrier(frame.cmdBuf,
2278 VK_PIPELINE_STAGE_TRANSFER_BIT,
2279 VK_PIPELINE_STAGE_HOST_BIT,
2280 0, 0,
nullptr, 0,
nullptr,
2284void QVulkanWindowPrivate::finishBlockingReadback()
2288 FrameResources &frame(frameRes[currentFrame]);
2289 if (frame.cmdFenceWaitable) {
2290 devFuncs->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2291 devFuncs->vkResetFences(dev, 1, &frame.cmdFence);
2292 frame.cmdFenceWaitable =
false;
2295 VkImageSubresource subres = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 };
2296 VkSubresourceLayout layout;
2297 devFuncs->vkGetImageSubresourceLayout(dev, frameGrabImage, &subres, &layout);
2300 VkResult err = devFuncs->vkMapMemory(dev, frameGrabImageMem, layout.offset, layout.size, 0,
reinterpret_cast<
void **>(&p));
2301 if (err != VK_SUCCESS) {
2302 qWarning(
"QVulkanWindow: Failed to map readback image memory after transfer: %d", err);
2306 for (
int y = 0; y < frameGrabTargetImage.height(); ++y) {
2307 memcpy(frameGrabTargetImage.scanLine(y), p, frameGrabTargetImage.width() * 4);
2308 p += layout.rowPitch;
2311 devFuncs->vkUnmapMemory(dev, frameGrabImageMem);
2313 devFuncs->vkDestroyImage(dev, frameGrabImage,
nullptr);
2314 frameGrabImage = VK_NULL_HANDLE;
2315 devFuncs->vkFreeMemory(dev, frameGrabImageMem,
nullptr);
2316 frameGrabImageMem = VK_NULL_HANDLE;
2320
2321
2322
2323
2324
2325
2326VkPhysicalDevice QVulkanWindow::physicalDevice()
const
2328 Q_D(
const QVulkanWindow);
2329 if (d->physDevIndex < d->physDevs.size())
2330 return d->physDevs[d->physDevIndex];
2331 qWarning(
"QVulkanWindow: Physical device not available");
2332 return VK_NULL_HANDLE;
2336
2337
2338
2339
2340
2341
2342const VkPhysicalDeviceProperties *QVulkanWindow::physicalDeviceProperties()
const
2344 Q_D(
const QVulkanWindow);
2345 if (d->physDevIndex < d->physDevProps.size())
2346 return &d->physDevProps[d->physDevIndex];
2347 qWarning(
"QVulkanWindow: Physical device properties not available");
2352
2353
2354
2355
2356
2357
2358VkDevice QVulkanWindow::device()
const
2360 Q_D(
const QVulkanWindow);
2365
2366
2367
2368
2369
2370
2371VkQueue QVulkanWindow::graphicsQueue()
const
2373 Q_D(
const QVulkanWindow);
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388uint32_t QVulkanWindow::graphicsQueueFamilyIndex()
const
2390 Q_D(
const QVulkanWindow);
2391 return d->gfxQueueFamilyIdx;
2395
2396
2397
2398
2399
2400
2401VkCommandPool QVulkanWindow::graphicsCommandPool()
const
2403 Q_D(
const QVulkanWindow);
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417uint32_t QVulkanWindow::hostVisibleMemoryIndex()
const
2419 Q_D(
const QVulkanWindow);
2420 return d->hostVisibleMemIndex;
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435uint32_t QVulkanWindow::deviceLocalMemoryIndex()
const
2437 Q_D(
const QVulkanWindow);
2438 return d->deviceLocalMemIndex;
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459VkRenderPass QVulkanWindow::defaultRenderPass()
const
2461 Q_D(
const QVulkanWindow);
2462 return d->defaultRenderPass;
2466
2467
2468
2469
2470
2471
2472
2473
2474VkFormat QVulkanWindow::colorFormat()
const
2476 Q_D(
const QVulkanWindow);
2477 return d->colorFormat;
2481
2482
2483
2484
2485
2486
2487VkFormat QVulkanWindow::depthStencilFormat()
const
2489 Q_D(
const QVulkanWindow);
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516QSize QVulkanWindow::swapChainImageSize()
const
2518 Q_D(
const QVulkanWindow);
2519 return d->swapChainImageSize;
2523
2524
2525
2526
2527
2528
2529
2530VkCommandBuffer QVulkanWindow::currentCommandBuffer()
const
2532 Q_D(
const QVulkanWindow);
2533 if (!d->framePending) {
2534 qWarning(
"QVulkanWindow: Attempted to call currentCommandBuffer() without an active frame");
2535 return VK_NULL_HANDLE;
2537 return d->frameRes[d->currentFrame].cmdBuf;
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559VkFramebuffer QVulkanWindow::currentFramebuffer()
const
2561 Q_D(
const QVulkanWindow);
2562 if (!d->framePending) {
2563 qWarning(
"QVulkanWindow: Attempted to call currentFramebuffer() without an active frame");
2564 return VK_NULL_HANDLE;
2566 return d->imageRes[d->currentImage].fb;
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590int QVulkanWindow::currentFrame()
const
2592 Q_D(
const QVulkanWindow);
2593 if (!d->framePending)
2594 qWarning(
"QVulkanWindow: Attempted to call currentFrame() without an active frame");
2595 return d->currentFrame;
2599
2600
2601
2602
2603
2606
2607
2608
2609
2610
2611
2612
2613
2614int QVulkanWindow::concurrentFrameCount()
const
2616 Q_D(
const QVulkanWindow);
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631int QVulkanWindow::swapChainImageCount()
const
2633 Q_D(
const QVulkanWindow);
2634 return d->swapChainBufferCount;
2638
2639
2640
2641
2642
2643int QVulkanWindow::currentSwapChainImageIndex()
const
2645 Q_D(
const QVulkanWindow);
2646 if (!d->framePending)
2647 qWarning(
"QVulkanWindow: Attempted to call currentSwapChainImageIndex() without an active frame");
2648 return d->currentImage;
2652
2653
2654
2655
2656
2657
2658
2659
2660VkImage QVulkanWindow::swapChainImage(
int idx)
const
2662 Q_D(
const QVulkanWindow);
2663 return idx >= 0 && idx < d->swapChainBufferCount ? d->imageRes[idx].image : VK_NULL_HANDLE;
2667
2668
2669
2670
2671
2672
2673
2674
2675VkImageView QVulkanWindow::swapChainImageView(
int idx)
const
2677 Q_D(
const QVulkanWindow);
2678 return idx >= 0 && idx < d->swapChainBufferCount ? d->imageRes[idx].imageView : VK_NULL_HANDLE;
2682
2683
2684
2685
2686
2687
2688VkImage QVulkanWindow::depthStencilImage()
const
2690 Q_D(
const QVulkanWindow);
2695
2696
2697
2698
2699
2700
2701VkImageView QVulkanWindow::depthStencilImageView()
const
2703 Q_D(
const QVulkanWindow);
2708
2709
2710
2711
2712
2713
2714
2715VkSampleCountFlagBits QVulkanWindow::sampleCountFlagBits()
const
2717 Q_D(
const QVulkanWindow);
2718 return d->sampleCount;
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731VkImage QVulkanWindow::msaaColorImage(
int idx)
const
2733 Q_D(
const QVulkanWindow);
2734 return idx >= 0 && idx < d->swapChainBufferCount ? d->imageRes[idx].msaaImage : VK_NULL_HANDLE;
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747VkImageView QVulkanWindow::msaaColorImageView(
int idx)
const
2749 Q_D(
const QVulkanWindow);
2750 return idx >= 0 && idx < d->swapChainBufferCount ? d->imageRes[idx].msaaImageView : VK_NULL_HANDLE;
2754
2755
2756
2757
2758
2759
2760
2761bool QVulkanWindow::supportsGrab()
const
2763 Q_D(
const QVulkanWindow);
2764 return d->swapChainSupportsReadBack;
2768
2769
2770
2771
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798QImage QVulkanWindow::grab()
2801 if (!d->swapChain) {
2802 qWarning(
"QVulkanWindow: Attempted to call grab() without a swapchain");
2805 if (d->framePending) {
2806 qWarning(
"QVulkanWindow: Attempted to call grab() while a frame is still pending");
2809 if (!d->swapChainSupportsReadBack) {
2810 qWarning(
"QVulkanWindow: Attempted to call grab() with a swapchain that does not support usage as transfer source");
2814 d->frameGrabbing =
true;
2817 if (d->colorFormat == VK_FORMAT_B8G8R8A8_UNORM)
2818 d->frameGrabTargetImage = std::move(d->frameGrabTargetImage).rgbSwapped();
2820 return d->frameGrabTargetImage;
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834QMatrix4x4 QVulkanWindow::clipCorrectionMatrix()
2837 if (d->m_clipCorrect.isIdentity()) {
2839 d->m_clipCorrect = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
2840 0.0f, -1.0f, 0.0f, 0.0f,
2841 0.0f, 0.0f, 0.5f, 0.5f,
2842 0.0f, 0.0f, 0.0f, 1.0f);
2844 return d->m_clipCorrect;
2849#include "moc_qvulkanwindow.cpp"
Combined button and popup list for selecting options.
VkSampleCountFlagBits mask
static VkDeviceSize aligned(VkDeviceSize v, VkDeviceSize byteAlign)