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 (
auto ext : reqExts)
686 envExtList.removeAll(ext);
687 reqExts.append(envExtList);
690 for (
const QByteArray &ext : 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;
725 uint32_t apiVersion = physDevProps[physDevIndex].apiVersion;
726 if (VK_VERSION_MAJOR(apiVersion) == 1
727 && VK_VERSION_MINOR(apiVersion) == 0
728 && VK_VERSION_PATCH(apiVersion) <= 13)
731 const QByteArray stdValName = QByteArrayLiteral(
"VK_LAYER_KHRONOS_validation");
732 const char *stdValNamePtr = stdValName.constData();
733 if (inst->layers().contains(stdValName)) {
735 VkResult err = f->vkEnumerateDeviceLayerProperties(physDev, &count,
nullptr);
736 if (err == VK_SUCCESS) {
737 QList<VkLayerProperties> layerProps(count);
738 err = f->vkEnumerateDeviceLayerProperties(physDev, &count, layerProps.data());
739 if (err == VK_SUCCESS) {
740 for (
const VkLayerProperties &prop : layerProps) {
741 if (!strncmp(prop.layerName, stdValNamePtr, stdValName.size())) {
742 devInfo.enabledLayerCount = 1;
743 devInfo.ppEnabledLayerNames = &stdValNamePtr;
752 VkResult err = f->vkCreateDevice(physDev, &devInfo,
nullptr, &dev);
753 if (err == VK_ERROR_DEVICE_LOST) {
754 qWarning(
"QVulkanWindow: Physical device lost");
756 renderer->physicalDeviceLost();
759 physDevProps.clear();
760 status = StatusUninitialized;
761 qCDebug(lcGuiVk,
"Attempting to restart in 2 seconds");
762 QTimer::singleShot(2000, q, [
this]() { ensureStarted(); });
765 if (err != VK_SUCCESS) {
766 qWarning(
"QVulkanWindow: Failed to create device: %d", err);
771 devFuncs = inst->deviceFunctions(dev);
774 devFuncs->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, 0, &gfxQueue);
775 if (gfxQueueFamilyIdx == presQueueFamilyIdx)
776 presQueue = gfxQueue;
778 devFuncs->vkGetDeviceQueue(dev, presQueueFamilyIdx, 0, &presQueue);
780 VkCommandPoolCreateInfo poolInfo;
781 memset(&poolInfo, 0,
sizeof(poolInfo));
782 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
783 poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
784 err = devFuncs->vkCreateCommandPool(dev, &poolInfo,
nullptr, &cmdPool);
785 if (err != VK_SUCCESS) {
786 qWarning(
"QVulkanWindow: Failed to create command pool: %d", err);
790 if (gfxQueueFamilyIdx != presQueueFamilyIdx) {
791 poolInfo.queueFamilyIndex = presQueueFamilyIdx;
792 err = devFuncs->vkCreateCommandPool(dev, &poolInfo,
nullptr, &presCmdPool);
793 if (err != VK_SUCCESS) {
794 qWarning(
"QVulkanWindow: Failed to create command pool for present queue: %d", err);
800 hostVisibleMemIndex = 0;
801 VkPhysicalDeviceMemoryProperties physDevMemProps;
802 bool hostVisibleMemIndexSet =
false;
803 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
804 for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
805 const VkMemoryType *memType = physDevMemProps.memoryTypes;
806 qCDebug(lcGuiVk,
"memtype %d: flags=0x%x", i, memType[i].propertyFlags);
809 const int hostVisibleAndCoherent = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
810 if ((memType[i].propertyFlags & hostVisibleAndCoherent) == hostVisibleAndCoherent) {
811 if (!hostVisibleMemIndexSet
812 || (memType[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT)) {
813 hostVisibleMemIndexSet =
true;
814 hostVisibleMemIndex = i;
818 qCDebug(lcGuiVk,
"Picked memtype %d for host visible memory", hostVisibleMemIndex);
819 deviceLocalMemIndex = 0;
820 for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
821 const VkMemoryType *memType = physDevMemProps.memoryTypes;
823 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
824 deviceLocalMemIndex = i;
828 qCDebug(lcGuiVk,
"Picked memtype %d for device local memory", deviceLocalMemIndex);
830 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR || !vkGetPhysicalDeviceSurfaceFormatsKHR) {
831 vkGetPhysicalDeviceSurfaceCapabilitiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
832 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
833 vkGetPhysicalDeviceSurfaceFormatsKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
834 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceFormatsKHR"));
835 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR || !vkGetPhysicalDeviceSurfaceFormatsKHR) {
836 qWarning(
"QVulkanWindow: Physical device surface queries not available");
847 uint32_t formatCount = 0;
848 vkGetPhysicalDeviceSurfaceFormatsKHR(physDev, surface, &formatCount,
nullptr);
849 QList<VkSurfaceFormatKHR> formats(formatCount);
851 vkGetPhysicalDeviceSurfaceFormatsKHR(physDev, surface, &formatCount, formats.data());
853 colorFormat = VK_FORMAT_B8G8R8A8_UNORM;
854 colorSpace = VkColorSpaceKHR(0);
857 if (!formats.isEmpty() && formats[0].format != VK_FORMAT_UNDEFINED) {
858 colorFormat = formats[0].format;
859 colorSpace = formats[0].colorSpace;
863 if (!formats.isEmpty() && !requestedColorFormats.isEmpty()) {
864 for (VkFormat reqFmt : std::as_const(requestedColorFormats)) {
865 auto r = std::find_if(formats.cbegin(), formats.cend(),
866 [reqFmt](
const VkSurfaceFormatKHR &sfmt) {
return sfmt.format == reqFmt; });
867 if (r != formats.cend()) {
868 colorFormat = r->format;
869 colorSpace = r->colorSpace;
875#if QT_CONFIG(wayland)
880 const bool hasPassthrough = std::any_of(formats.cbegin(), formats.cend(), [
this](
const VkSurfaceFormatKHR &format) {
881 return format.format == colorFormat && format.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT;
883 if (hasPassthrough) {
884 colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
888 const VkFormat dsFormatCandidates[] = {
889 VK_FORMAT_D24_UNORM_S8_UINT,
890 VK_FORMAT_D32_SFLOAT_S8_UINT,
891 VK_FORMAT_D16_UNORM_S8_UINT
893 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
895 while (dsFormatIdx < dsFormatCandidateCount) {
896 dsFormat = dsFormatCandidates[dsFormatIdx];
897 VkFormatProperties fmtProp;
898 f->vkGetPhysicalDeviceFormatProperties(physDev, dsFormat, &fmtProp);
899 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
903 if (dsFormatIdx == dsFormatCandidateCount)
904 qWarning(
"QVulkanWindow: Failed to find an optimal depth-stencil format");
906 qCDebug(lcGuiVk,
"Color format: %d Depth-stencil format: %d", colorFormat, dsFormat);
908 if (!createDefaultRenderPass())
912 renderer->initResources();
914 status = StatusDeviceReady;
917void QVulkanWindowPrivate::reset()
922 qCDebug(lcGuiVk,
"QVulkanWindow reset");
924 devFuncs->vkDeviceWaitIdle(dev);
927 renderer->releaseResources();
928 devFuncs->vkDeviceWaitIdle(dev);
931 if (defaultRenderPass) {
932 devFuncs->vkDestroyRenderPass(dev, defaultRenderPass,
nullptr);
933 defaultRenderPass = VK_NULL_HANDLE;
937 devFuncs->vkDestroyCommandPool(dev, cmdPool,
nullptr);
938 cmdPool = VK_NULL_HANDLE;
942 devFuncs->vkDestroyCommandPool(dev, presCmdPool,
nullptr);
943 presCmdPool = VK_NULL_HANDLE;
946 if (frameGrabImage) {
947 devFuncs->vkDestroyImage(dev, frameGrabImage,
nullptr);
948 frameGrabImage = VK_NULL_HANDLE;
951 if (frameGrabImageMem) {
952 devFuncs->vkFreeMemory(dev, frameGrabImageMem,
nullptr);
953 frameGrabImageMem = VK_NULL_HANDLE;
957 devFuncs->vkDestroyDevice(dev,
nullptr);
958 inst->resetDeviceFunctions(dev);
959 dev = VK_NULL_HANDLE;
960 vkCreateSwapchainKHR =
nullptr;
963 surface = VK_NULL_HANDLE;
965 status = StatusUninitialized;
968bool QVulkanWindowPrivate::createDefaultRenderPass()
970 VkAttachmentDescription attDesc[3];
971 memset(attDesc, 0,
sizeof(attDesc));
973 const bool msaa = sampleCount > VK_SAMPLE_COUNT_1_BIT;
976 attDesc[0].format = colorFormat;
977 attDesc[0].samples = VK_SAMPLE_COUNT_1_BIT;
978 attDesc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
979 attDesc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
980 attDesc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
981 attDesc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
982 attDesc[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
983 attDesc[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
985 attDesc[1].format = dsFormat;
986 attDesc[1].samples = sampleCount;
987 attDesc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
988 attDesc[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
989 attDesc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
990 attDesc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
991 attDesc[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
992 attDesc[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
996 attDesc[2].format = colorFormat;
997 attDesc[2].samples = sampleCount;
998 attDesc[2].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
999 attDesc[2].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
1000 attDesc[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1001 attDesc[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1002 attDesc[2].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1003 attDesc[2].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1006 VkAttachmentReference colorRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
1007 VkAttachmentReference resolveRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
1008 VkAttachmentReference dsRef = { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
1010 VkSubpassDescription subPassDesc;
1011 memset(&subPassDesc, 0,
sizeof(subPassDesc));
1012 subPassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1013 subPassDesc.colorAttachmentCount = 1;
1014 subPassDesc.pColorAttachments = &colorRef;
1015 subPassDesc.pDepthStencilAttachment = &dsRef;
1017 VkRenderPassCreateInfo rpInfo;
1018 memset(&rpInfo, 0,
sizeof(rpInfo));
1019 rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1020 rpInfo.attachmentCount = 2;
1021 rpInfo.pAttachments = attDesc;
1022 rpInfo.subpassCount = 1;
1023 rpInfo.pSubpasses = &subPassDesc;
1026 colorRef.attachment = 2;
1027 subPassDesc.pResolveAttachments = &resolveRef;
1028 rpInfo.attachmentCount = 3;
1031 VkResult err = devFuncs->vkCreateRenderPass(dev, &rpInfo,
nullptr, &defaultRenderPass);
1032 if (err != VK_SUCCESS) {
1033 qWarning(
"QVulkanWindow: Failed to create renderpass: %d", err);
1040void QVulkanWindowPrivate::recreateSwapChain()
1043 Q_ASSERT(status >= StatusDeviceReady);
1045 swapChainImageSize = q->size() * q->devicePixelRatio();
1047 if (swapChainImageSize.isEmpty())
1050 QVulkanInstance *inst = q->vulkanInstance();
1051 QVulkanFunctions *f = inst->functions();
1052 devFuncs->vkDeviceWaitIdle(dev);
1054 if (!vkCreateSwapchainKHR) {
1055 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
1056 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
1057 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
1058 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
1059 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
1062 VkPhysicalDevice physDev = physDevs.at(physDevIndex);
1063 VkSurfaceCapabilitiesKHR surfaceCaps;
1064 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, surface, &surfaceCaps);
1065 uint32_t reqBufferCount;
1066 if (surfaceCaps.maxImageCount == 0)
1067 reqBufferCount = qMax<uint32_t>(2, surfaceCaps.minImageCount);
1069 reqBufferCount = qMax(qMin<uint32_t>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
1071 VkExtent2D bufferSize = surfaceCaps.currentExtent;
1072 if (bufferSize.width == uint32_t(-1)) {
1073 Q_ASSERT(bufferSize.height == uint32_t(-1));
1074 bufferSize.width = swapChainImageSize.width();
1075 bufferSize.height = swapChainImageSize.height();
1077 swapChainImageSize = QSize(bufferSize.width, bufferSize.height);
1080 VkSurfaceTransformFlagBitsKHR preTransform =
1081 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
1082 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
1083 : surfaceCaps.currentTransform;
1085 VkCompositeAlphaFlagBitsKHR compositeAlpha =
1086 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
1087 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
1088 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
1090 if (q->requestedFormat().hasAlpha()) {
1091 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
1092 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
1093 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
1094 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
1097 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1098 swapChainSupportsReadBack = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1099 if (swapChainSupportsReadBack)
1100 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1102 VkSwapchainKHR oldSwapChain = swapChain;
1103 VkSwapchainCreateInfoKHR swapChainInfo;
1104 memset(&swapChainInfo, 0,
sizeof(swapChainInfo));
1105 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
1106 swapChainInfo.surface = surface;
1107 swapChainInfo.minImageCount = reqBufferCount;
1108 swapChainInfo.imageFormat = colorFormat;
1109 swapChainInfo.imageColorSpace = colorSpace;
1110 swapChainInfo.imageExtent = bufferSize;
1111 swapChainInfo.imageArrayLayers = 1;
1112 swapChainInfo.imageUsage = usage;
1113 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
1114 swapChainInfo.preTransform = preTransform;
1115 swapChainInfo.compositeAlpha = compositeAlpha;
1116 swapChainInfo.presentMode = presentMode;
1117 swapChainInfo.clipped =
true;
1118 swapChainInfo.oldSwapchain = oldSwapChain;
1120 qCDebug(lcGuiVk,
"Creating new swap chain of %d buffers, size %dx%d", reqBufferCount, bufferSize.width, bufferSize.height);
1122 VkSwapchainKHR newSwapChain;
1123 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
1124 if (err != VK_SUCCESS) {
1125 qWarning(
"QVulkanWindow: Failed to create swap chain: %d", err);
1132 swapChain = newSwapChain;
1134 uint32_t actualSwapChainBufferCount = 0;
1135 err = vkGetSwapchainImagesKHR(dev, swapChain, &actualSwapChainBufferCount,
nullptr);
1136 if (err != VK_SUCCESS || actualSwapChainBufferCount < 2) {
1137 qWarning(
"QVulkanWindow: Failed to get swapchain images: %d (count=%d)", err, actualSwapChainBufferCount);
1141 qCDebug(lcGuiVk,
"Actual swap chain buffer count: %d (supportsReadback=%d)",
1142 actualSwapChainBufferCount, swapChainSupportsReadBack);
1143 if (actualSwapChainBufferCount > MAX_SWAPCHAIN_BUFFER_COUNT) {
1144 qWarning(
"QVulkanWindow: Too many swapchain buffers (%d)", actualSwapChainBufferCount);
1147 swapChainBufferCount = actualSwapChainBufferCount;
1149 VkImage swapChainImages[MAX_SWAPCHAIN_BUFFER_COUNT];
1150 err = vkGetSwapchainImagesKHR(dev, swapChain, &actualSwapChainBufferCount, swapChainImages);
1151 if (err != VK_SUCCESS) {
1152 qWarning(
"QVulkanWindow: Failed to get swapchain images: %d", err);
1156 if (!createTransientImage(dsFormat,
1157 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
1158 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
1167 const bool msaa = sampleCount > VK_SAMPLE_COUNT_1_BIT;
1168 VkImage msaaImages[MAX_SWAPCHAIN_BUFFER_COUNT];
1169 VkImageView msaaViews[MAX_SWAPCHAIN_BUFFER_COUNT];
1172 if (!createTransientImage(colorFormat,
1173 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1174 VK_IMAGE_ASPECT_COLOR_BIT,
1178 swapChainBufferCount))
1184 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
nullptr, VK_FENCE_CREATE_SIGNALED_BIT };
1186 for (
int i = 0; i < swapChainBufferCount; ++i) {
1187 ImageResources &image(imageRes[i]);
1188 image.image = swapChainImages[i];
1191 image.msaaImage = msaaImages[i];
1192 image.msaaImageView = msaaViews[i];
1195 VkImageViewCreateInfo imgViewInfo;
1196 memset(&imgViewInfo, 0,
sizeof(imgViewInfo));
1197 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1198 imgViewInfo.image = swapChainImages[i];
1199 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1200 imgViewInfo.format = colorFormat;
1201 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1202 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1203 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1204 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1205 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1206 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1207 err = devFuncs->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
1208 if (err != VK_SUCCESS) {
1209 qWarning(
"QVulkanWindow: Failed to create swapchain image view %d: %d", i, err);
1213 VkImageView views[3] = { image.imageView,
1215 msaa ? image.msaaImageView : VK_NULL_HANDLE };
1216 VkFramebufferCreateInfo fbInfo;
1217 memset(&fbInfo, 0,
sizeof(fbInfo));
1218 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
1219 fbInfo.renderPass = defaultRenderPass;
1220 fbInfo.attachmentCount = msaa ? 3 : 2;
1221 fbInfo.pAttachments = views;
1222 fbInfo.width = swapChainImageSize.width();
1223 fbInfo.height = swapChainImageSize.height();
1225 VkResult err = devFuncs->vkCreateFramebuffer(dev, &fbInfo,
nullptr, &image.fb);
1226 if (err != VK_SUCCESS) {
1227 qWarning(
"QVulkanWindow: Failed to create framebuffer: %d", err);
1231 if (gfxQueueFamilyIdx != presQueueFamilyIdx) {
1233 VkCommandBufferAllocateInfo cmdBufInfo = {
1234 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
nullptr, presCmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1 };
1235 err = devFuncs->vkAllocateCommandBuffers(dev, &cmdBufInfo, &image.presTransCmdBuf);
1236 if (err != VK_SUCCESS) {
1237 qWarning(
"QVulkanWindow: Failed to allocate acquire-on-present-queue command buffer: %d", err);
1240 VkCommandBufferBeginInfo cmdBufBeginInfo = {
1241 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
nullptr,
1242 VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
nullptr };
1243 err = devFuncs->vkBeginCommandBuffer(image.presTransCmdBuf, &cmdBufBeginInfo);
1244 if (err != VK_SUCCESS) {
1245 qWarning(
"QVulkanWindow: Failed to begin acquire-on-present-queue command buffer: %d", err);
1248 VkImageMemoryBarrier presTrans;
1249 memset(&presTrans, 0,
sizeof(presTrans));
1250 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1251 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1252 presTrans.oldLayout = presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1253 presTrans.srcQueueFamilyIndex = gfxQueueFamilyIdx;
1254 presTrans.dstQueueFamilyIndex = presQueueFamilyIdx;
1255 presTrans.image = image.image;
1256 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1257 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
1258 devFuncs->vkCmdPipelineBarrier(image.presTransCmdBuf,
1259 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1260 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1261 0, 0,
nullptr, 0,
nullptr,
1263 err = devFuncs->vkEndCommandBuffer(image.presTransCmdBuf);
1264 if (err != VK_SUCCESS) {
1265 qWarning(
"QVulkanWindow: Failed to end acquire-on-present-queue command buffer: %d", err);
1273 VkSemaphoreCreateInfo semInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
nullptr, 0 };
1274 for (
int i = 0; i < frameLag; ++i) {
1275 FrameResources &frame(frameRes[i]);
1277 frame.imageAcquired =
false;
1278 frame.imageSemWaitable =
false;
1280 devFuncs->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
1281 devFuncs->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.drawSem);
1282 if (gfxQueueFamilyIdx != presQueueFamilyIdx)
1283 devFuncs->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.presTransSem);
1285 err = devFuncs->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
1286 if (err != VK_SUCCESS) {
1287 qWarning(
"QVulkanWindow: Failed to create command buffer fence: %d", err);
1290 frame.cmdFenceWaitable =
true;
1296 renderer->initSwapChainResources();
1298 status = StatusReady;
1301uint32_t QVulkanWindowPrivate::chooseTransientImageMemType(VkImage img, uint32_t startIndex)
1303 VkPhysicalDeviceMemoryProperties physDevMemProps;
1304 inst->functions()->vkGetPhysicalDeviceMemoryProperties(physDevs[physDevIndex], &physDevMemProps);
1306 VkMemoryRequirements memReq;
1307 devFuncs->vkGetImageMemoryRequirements(dev, img, &memReq);
1308 uint32_t memTypeIndex = uint32_t(-1);
1310 if (memReq.memoryTypeBits) {
1312 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1313 bool foundDevLocal =
false;
1314 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1315 if (memReq.memoryTypeBits & (1 << i)) {
1316 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1317 if (!foundDevLocal) {
1318 foundDevLocal =
true;
1321 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1330 return memTypeIndex;
1335 return (v + byteAlign - 1) & ~(byteAlign - 1);
1338bool QVulkanWindowPrivate::createTransientImage(VkFormat format,
1339 VkImageUsageFlags usage,
1340 VkImageAspectFlags aspectMask,
1342 VkDeviceMemory *mem,
1346 VkMemoryRequirements memReq;
1349 Q_ASSERT(count > 0);
1350 for (
int i = 0; i < count; ++i) {
1351 VkImageCreateInfo imgInfo;
1352 memset(&imgInfo, 0,
sizeof(imgInfo));
1353 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1354 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1355 imgInfo.format = format;
1356 imgInfo.extent.width = swapChainImageSize.width();
1357 imgInfo.extent.height = swapChainImageSize.height();
1358 imgInfo.extent.depth = 1;
1359 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1360 imgInfo.samples = sampleCount;
1361 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1362 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1364 err = devFuncs->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1365 if (err != VK_SUCCESS) {
1366 qWarning(
"QVulkanWindow: Failed to create image: %d", err);
1373 devFuncs->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1376 VkMemoryAllocateInfo memInfo;
1377 memset(&memInfo, 0,
sizeof(memInfo));
1378 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1379 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * count;
1381 uint32_t startIndex = 0;
1383 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1384 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1385 qWarning(
"QVulkanWindow: No suitable memory type found");
1388 startIndex = memInfo.memoryTypeIndex + 1;
1389 qCDebug(lcGuiVk,
"Allocating %u bytes for transient image (memtype %u)",
1390 uint32_t(memInfo.allocationSize), memInfo.memoryTypeIndex);
1391 err = devFuncs->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1392 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1393 qWarning(
"QVulkanWindow: Failed to allocate image memory: %d", err);
1396 }
while (err != VK_SUCCESS);
1398 VkDeviceSize ofs = 0;
1399 for (
int i = 0; i < count; ++i) {
1400 err = devFuncs->vkBindImageMemory(dev, images[i], *mem, ofs);
1401 if (err != VK_SUCCESS) {
1402 qWarning(
"QVulkanWindow: Failed to bind image memory: %d", err);
1405 ofs += aligned(memReq.size, memReq.alignment);
1407 VkImageViewCreateInfo imgViewInfo;
1408 memset(&imgViewInfo, 0,
sizeof(imgViewInfo));
1409 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1410 imgViewInfo.image = images[i];
1411 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1412 imgViewInfo.format = format;
1413 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1414 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1415 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1416 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1417 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1418 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1420 err = devFuncs->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1421 if (err != VK_SUCCESS) {
1422 qWarning(
"QVulkanWindow: Failed to create image view: %d", err);
1430void QVulkanWindowPrivate::releaseSwapChain()
1432 if (!dev || !swapChain)
1435 qCDebug(lcGuiVk,
"Releasing swapchain");
1437 devFuncs->vkDeviceWaitIdle(dev);
1440 renderer->releaseSwapChainResources();
1441 devFuncs->vkDeviceWaitIdle(dev);
1444 for (
int i = 0; i < frameLag; ++i) {
1445 FrameResources &frame(frameRes[i]);
1447 devFuncs->vkFreeCommandBuffers(dev, cmdPool, 1, &frame.cmdBuf);
1448 frame.cmdBuf = VK_NULL_HANDLE;
1450 if (frame.imageSem) {
1451 devFuncs->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
1452 frame.imageSem = VK_NULL_HANDLE;
1454 if (frame.drawSem) {
1455 devFuncs->vkDestroySemaphore(dev, frame.drawSem,
nullptr);
1456 frame.drawSem = VK_NULL_HANDLE;
1458 if (frame.presTransSem) {
1459 devFuncs->vkDestroySemaphore(dev, frame.presTransSem,
nullptr);
1460 frame.presTransSem = VK_NULL_HANDLE;
1462 if (frame.cmdFence) {
1463 if (frame.cmdFenceWaitable)
1464 devFuncs->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
1465 devFuncs->vkDestroyFence(dev, frame.cmdFence,
nullptr);
1466 frame.cmdFence = VK_NULL_HANDLE;
1467 frame.cmdFenceWaitable =
false;
1471 for (
int i = 0; i < swapChainBufferCount; ++i) {
1472 ImageResources &image(imageRes[i]);
1474 devFuncs->vkDestroyFramebuffer(dev, image.fb,
nullptr);
1475 image.fb = VK_NULL_HANDLE;
1477 if (image.imageView) {
1478 devFuncs->vkDestroyImageView(dev, image.imageView,
nullptr);
1479 image.imageView = VK_NULL_HANDLE;
1481 if (image.presTransCmdBuf) {
1482 devFuncs->vkFreeCommandBuffers(dev, presCmdPool, 1, &image.presTransCmdBuf);
1483 image.presTransCmdBuf = VK_NULL_HANDLE;
1485 if (image.msaaImageView) {
1486 devFuncs->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
1487 image.msaaImageView = VK_NULL_HANDLE;
1489 if (image.msaaImage) {
1490 devFuncs->vkDestroyImage(dev, image.msaaImage,
nullptr);
1491 image.msaaImage = VK_NULL_HANDLE;
1496 devFuncs->vkFreeMemory(dev, msaaImageMem,
nullptr);
1497 msaaImageMem = VK_NULL_HANDLE;
1501 devFuncs->vkDestroyImageView(dev, dsView,
nullptr);
1502 dsView = VK_NULL_HANDLE;
1505 devFuncs->vkDestroyImage(dev, dsImage,
nullptr);
1506 dsImage = VK_NULL_HANDLE;
1509 devFuncs->vkFreeMemory(dev, dsMem,
nullptr);
1510 dsMem = VK_NULL_HANDLE;
1514 vkDestroySwapchainKHR(dev, swapChain,
nullptr);
1515 swapChain = VK_NULL_HANDLE;
1518 if (status == StatusReady)
1519 status = StatusDeviceReady;
1523
1524
1525void QVulkanWindow::exposeEvent(QExposeEvent *)
1532 if (!d->flags.testFlag(PersistentResources)) {
1533 d->releaseSwapChain();
1539void QVulkanWindowPrivate::ensureStarted()
1542 if (status == QVulkanWindowPrivate::StatusFailRetry)
1543 status = QVulkanWindowPrivate::StatusUninitialized;
1544 if (status == QVulkanWindowPrivate::StatusUninitialized) {
1546 if (status == QVulkanWindowPrivate::StatusDeviceReady)
1547 recreateSwapChain();
1549 if (status == QVulkanWindowPrivate::StatusReady)
1554
1555
1556void QVulkanWindow::resizeEvent(QResizeEvent *)
1562
1563
1564bool QVulkanWindow::event(QEvent *e)
1568 switch (e->type()) {
1570 case QEvent::UpdateRequest:
1578 case QEvent::PlatformSurface:
1579 if (
static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) {
1580 d->releaseSwapChain();
1589 return QWindow::event(e);
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1612
1613
1614
1615
1616
1617
1618void QVulkanWindow::setQueueCreateInfoModifier(
const QueueCreateInfoModifier &modifier)
1621 d->queueCreateInfoModifier = modifier;
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658void QVulkanWindow::setEnabledFeaturesModifier(
const EnabledFeaturesModifier &modifier)
1661 d->enabledFeaturesModifier = modifier;
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1692
1693
1694
1695
1696
1697void QVulkanWindow::setEnabledFeaturesModifier(EnabledFeatures2Modifier modifier)
1700 d->enabledFeatures2Modifier = std::move(modifier);
1704
1705
1706
1707
1708
1709
1710bool QVulkanWindow::isValid()
const
1712 Q_D(
const QVulkanWindow);
1713 return d->status == QVulkanWindowPrivate::StatusReady;
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727QVulkanWindowRenderer *QVulkanWindow::createRenderer()
1733
1734
1735QVulkanWindowRenderer::~QVulkanWindowRenderer()
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755void QVulkanWindowRenderer::preInitResources()
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774void QVulkanWindowRenderer::initResources()
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796void QVulkanWindowRenderer::initSwapChainResources()
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819void QVulkanWindowRenderer::releaseSwapChainResources()
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835void QVulkanWindowRenderer::releaseResources()
1840
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
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880void QVulkanWindowRenderer::physicalDeviceLost()
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899void QVulkanWindowRenderer::logicalDeviceLost()
1903QSize QVulkanWindowPrivate::surfacePixelSize()
const
1905 Q_Q(
const QVulkanWindow);
1906 VkSurfaceCapabilitiesKHR surfaceCaps = {};
1907 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDevs.at(physDevIndex), surface, &surfaceCaps);
1908 VkExtent2D bufferSize = surfaceCaps.currentExtent;
1909 if (bufferSize.width == uint32_t(-1)) {
1910 Q_ASSERT(bufferSize.height == uint32_t(-1));
1911 return q->size() * q->devicePixelRatio();
1913 return QSize(
int(bufferSize.width),
int(bufferSize.height));
1916void QVulkanWindowPrivate::beginFrame()
1918 if (!swapChain || framePending)
1922 if (swapChainImageSize != surfacePixelSize()) {
1923 recreateSwapChain();
1929 FrameResources &frame(frameRes[currentFrame]);
1930 if (frame.cmdFenceWaitable) {
1931 devFuncs->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
1932 devFuncs->vkResetFences(dev, 1, &frame.cmdFence);
1933 frame.cmdFenceWaitable =
false;
1937 if (!frame.imageAcquired) {
1938 VkResult err = vkAcquireNextImageKHR(dev, swapChain, UINT64_MAX,
1939 frame.imageSem, VK_NULL_HANDLE, ¤tImage);
1940 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
1941 frame.imageSemWaitable =
true;
1942 frame.imageAcquired =
true;
1943 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
1944 recreateSwapChain();
1948 if (!checkDeviceLost(err))
1949 qWarning(
"QVulkanWindow: Failed to acquire next swapchain image: %d", err);
1957 devFuncs->vkFreeCommandBuffers(dev, cmdPool, 1, &frame.cmdBuf);
1958 frame.cmdBuf =
nullptr;
1961 VkCommandBufferAllocateInfo cmdBufInfo = {
1962 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
nullptr, cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1 };
1963 VkResult err = devFuncs->vkAllocateCommandBuffers(dev, &cmdBufInfo, &frame.cmdBuf);
1964 if (err != VK_SUCCESS) {
1965 if (!checkDeviceLost(err))
1966 qWarning(
"QVulkanWindow: Failed to allocate frame command buffer: %d", err);
1970 VkCommandBufferBeginInfo cmdBufBeginInfo = {
1971 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
nullptr, 0,
nullptr };
1972 err = devFuncs->vkBeginCommandBuffer(frame.cmdBuf, &cmdBufBeginInfo);
1973 if (err != VK_SUCCESS) {
1974 if (!checkDeviceLost(err))
1975 qWarning(
"QVulkanWindow: Failed to begin frame command buffer: %d", err);
1980 frameGrabTargetImage = QImage(swapChainImageSize, QImage::Format_RGBA8888);
1982 ImageResources &image(imageRes[currentImage]);
1984 framePending =
true;
1985 renderer->startNextFrame();
1988 VkClearColorValue clearColor = { { 0.0f, 0.0f, 0.0f, 1.0f } };
1989 VkClearDepthStencilValue clearDS = { 1.0f, 0 };
1990 VkClearValue clearValues[3];
1991 memset(clearValues, 0,
sizeof(clearValues));
1992 clearValues[0].color = clearValues[2].color = clearColor;
1993 clearValues[1].depthStencil = clearDS;
1995 VkRenderPassBeginInfo rpBeginInfo;
1996 memset(&rpBeginInfo, 0,
sizeof(rpBeginInfo));
1997 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1998 rpBeginInfo.renderPass = defaultRenderPass;
1999 rpBeginInfo.framebuffer = image.fb;
2000 rpBeginInfo.renderArea.extent.width = swapChainImageSize.width();
2001 rpBeginInfo.renderArea.extent.height = swapChainImageSize.height();
2002 rpBeginInfo.clearValueCount = sampleCount > VK_SAMPLE_COUNT_1_BIT ? 3 : 2;
2003 rpBeginInfo.pClearValues = clearValues;
2004 devFuncs->vkCmdBeginRenderPass(frame.cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
2005 devFuncs->vkCmdEndRenderPass(frame.cmdBuf);
2011void QVulkanWindowPrivate::endFrame()
2015 FrameResources &frame(frameRes[currentFrame]);
2016 ImageResources &image(imageRes[currentImage]);
2018 if (gfxQueueFamilyIdx != presQueueFamilyIdx && !frameGrabbing) {
2021 VkImageMemoryBarrier presTrans;
2022 memset(&presTrans, 0,
sizeof(presTrans));
2023 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2024 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2025 presTrans.oldLayout = presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2026 presTrans.srcQueueFamilyIndex = gfxQueueFamilyIdx;
2027 presTrans.dstQueueFamilyIndex = presQueueFamilyIdx;
2028 presTrans.image = image.image;
2029 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2030 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2031 devFuncs->vkCmdPipelineBarrier(frame.cmdBuf,
2032 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2033 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2034 0, 0,
nullptr, 0,
nullptr,
2042 VkResult err = devFuncs->vkEndCommandBuffer(frame.cmdBuf);
2043 if (err != VK_SUCCESS) {
2044 if (!checkDeviceLost(err))
2045 qWarning(
"QVulkanWindow: Failed to end frame command buffer: %d", err);
2050 VkSubmitInfo submitInfo;
2051 memset(&submitInfo, 0,
sizeof(submitInfo));
2052 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2053 submitInfo.commandBufferCount = 1;
2054 submitInfo.pCommandBuffers = &frame.cmdBuf;
2055 if (frame.imageSemWaitable) {
2056 submitInfo.waitSemaphoreCount = 1;
2057 submitInfo.pWaitSemaphores = &frame.imageSem;
2059 if (!frameGrabbing) {
2060 submitInfo.signalSemaphoreCount = 1;
2061 submitInfo.pSignalSemaphores = &frame.drawSem;
2063 VkPipelineStageFlags psf = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2064 submitInfo.pWaitDstStageMask = &psf;
2066 Q_ASSERT(!frame.cmdFenceWaitable);
2068 err = devFuncs->vkQueueSubmit(gfxQueue, 1, &submitInfo, frame.cmdFence);
2069 if (err == VK_SUCCESS) {
2070 frame.imageSemWaitable =
false;
2071 frame.cmdFenceWaitable =
true;
2073 if (!checkDeviceLost(err))
2074 qWarning(
"QVulkanWindow: Failed to submit to graphics queue: %d", err);
2079 if (frameGrabbing) {
2080 finishBlockingReadback();
2081 frameGrabbing =
false;
2084 emit q->frameGrabbed(frameGrabTargetImage);
2088 if (gfxQueueFamilyIdx != presQueueFamilyIdx) {
2090 submitInfo.pWaitSemaphores = &frame.drawSem;
2091 submitInfo.pSignalSemaphores = &frame.presTransSem;
2092 submitInfo.pCommandBuffers = &image.presTransCmdBuf;
2093 err = devFuncs->vkQueueSubmit(presQueue, 1, &submitInfo, VK_NULL_HANDLE);
2094 if (err != VK_SUCCESS) {
2095 if (!checkDeviceLost(err))
2096 qWarning(
"QVulkanWindow: Failed to submit to present queue: %d", err);
2102 VkPresentInfoKHR presInfo;
2103 memset(&presInfo, 0,
sizeof(presInfo));
2104 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2105 presInfo.swapchainCount = 1;
2106 presInfo.pSwapchains = &swapChain;
2107 presInfo.pImageIndices = ¤tImage;
2108 presInfo.waitSemaphoreCount = 1;
2109 presInfo.pWaitSemaphores = gfxQueueFamilyIdx == presQueueFamilyIdx ? &frame.drawSem : &frame.presTransSem;
2113 inst->presentAboutToBeQueued(q);
2115 err = vkQueuePresentKHR(presQueue, &presInfo);
2116 if (err != VK_SUCCESS) {
2117 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2118 recreateSwapChain();
2121 }
else if (err != VK_SUBOPTIMAL_KHR) {
2122 if (!checkDeviceLost(err))
2123 qWarning(
"QVulkanWindow: Failed to present: %d", err);
2128 frame.imageAcquired =
false;
2130 inst->presentQueued(q);
2132 currentFrame = (currentFrame + 1) % frameLag;
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148void QVulkanWindow::frameReady()
2150 Q_ASSERT_X(QThread::isMainThread(),
2151 "QVulkanWindow",
"frameReady() can only be called from the GUI (main) thread");
2155 if (!d->framePending) {
2156 qWarning(
"QVulkanWindow: frameReady() called without a corresponding startNextFrame()");
2160 d->framePending =
false;
2165bool QVulkanWindowPrivate::checkDeviceLost(VkResult err)
2167 if (err == VK_ERROR_DEVICE_LOST) {
2168 qWarning(
"QVulkanWindow: Device lost");
2170 renderer->logicalDeviceLost();
2171 qCDebug(lcGuiVk,
"Releasing all resources due to device lost");
2174 qCDebug(lcGuiVk,
"Restarting");
2181void QVulkanWindowPrivate::addReadback()
2183 VkImageCreateInfo imageInfo;
2184 memset(&imageInfo, 0,
sizeof(imageInfo));
2185 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
2186 imageInfo.imageType = VK_IMAGE_TYPE_2D;
2187 imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
2188 imageInfo.extent.width = frameGrabTargetImage.width();
2189 imageInfo.extent.height = frameGrabTargetImage.height();
2190 imageInfo.extent.depth = 1;
2191 imageInfo.mipLevels = 1;
2192 imageInfo.arrayLayers = 1;
2193 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
2194 imageInfo.tiling = VK_IMAGE_TILING_LINEAR;
2195 imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2196 imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
2198 VkResult err = devFuncs->vkCreateImage(dev, &imageInfo,
nullptr, &frameGrabImage);
2199 if (err != VK_SUCCESS) {
2200 qWarning(
"QVulkanWindow: Failed to create image for readback: %d", err);
2204 VkMemoryRequirements memReq;
2205 devFuncs->vkGetImageMemoryRequirements(dev, frameGrabImage, &memReq);
2207 VkMemoryAllocateInfo allocInfo = {
2208 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
2214 err = devFuncs->vkAllocateMemory(dev, &allocInfo,
nullptr, &frameGrabImageMem);
2215 if (err != VK_SUCCESS) {
2216 qWarning(
"QVulkanWindow: Failed to allocate memory for readback image: %d", err);
2220 err = devFuncs->vkBindImageMemory(dev, frameGrabImage, frameGrabImageMem, 0);
2221 if (err != VK_SUCCESS) {
2222 qWarning(
"QVulkanWindow: Failed to bind readback image memory: %d", err);
2226 FrameResources &frame(frameRes[currentFrame]);
2227 ImageResources &image(imageRes[currentImage]);
2229 VkImageMemoryBarrier barrier;
2230 memset(&barrier, 0,
sizeof(barrier));
2231 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2232 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2233 barrier.subresourceRange.levelCount = barrier.subresourceRange.layerCount = 1;
2235 barrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2236 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2237 barrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
2238 barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2239 barrier.image = image.image;
2241 devFuncs->vkCmdPipelineBarrier(frame.cmdBuf,
2242 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2243 VK_PIPELINE_STAGE_TRANSFER_BIT,
2244 0, 0,
nullptr, 0,
nullptr,
2247 barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
2248 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2249 barrier.srcAccessMask = 0;
2250 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
2251 barrier.image = frameGrabImage;
2253 devFuncs->vkCmdPipelineBarrier(frame.cmdBuf,
2254 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2255 VK_PIPELINE_STAGE_TRANSFER_BIT,
2256 0, 0,
nullptr, 0,
nullptr,
2259 VkImageCopy copyInfo;
2260 memset(©Info, 0,
sizeof(copyInfo));
2261 copyInfo.srcSubresource.aspectMask = copyInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2262 copyInfo.srcSubresource.layerCount = copyInfo.dstSubresource.layerCount = 1;
2263 copyInfo.extent.width = frameGrabTargetImage.width();
2264 copyInfo.extent.height = frameGrabTargetImage.height();
2265 copyInfo.extent.depth = 1;
2267 devFuncs->vkCmdCopyImage(frame.cmdBuf, image.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2268 frameGrabImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Info);
2270 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2271 barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
2272 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
2273 barrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
2274 barrier.image = frameGrabImage;
2276 devFuncs->vkCmdPipelineBarrier(frame.cmdBuf,
2277 VK_PIPELINE_STAGE_TRANSFER_BIT,
2278 VK_PIPELINE_STAGE_HOST_BIT,
2279 0, 0,
nullptr, 0,
nullptr,
2283void QVulkanWindowPrivate::finishBlockingReadback()
2287 FrameResources &frame(frameRes[currentFrame]);
2288 if (frame.cmdFenceWaitable) {
2289 devFuncs->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2290 devFuncs->vkResetFences(dev, 1, &frame.cmdFence);
2291 frame.cmdFenceWaitable =
false;
2294 VkImageSubresource subres = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 };
2295 VkSubresourceLayout layout;
2296 devFuncs->vkGetImageSubresourceLayout(dev, frameGrabImage, &subres, &layout);
2299 VkResult err = devFuncs->vkMapMemory(dev, frameGrabImageMem, layout.offset, layout.size, 0,
reinterpret_cast<
void **>(&p));
2300 if (err != VK_SUCCESS) {
2301 qWarning(
"QVulkanWindow: Failed to map readback image memory after transfer: %d", err);
2305 for (
int y = 0; y < frameGrabTargetImage.height(); ++y) {
2306 memcpy(frameGrabTargetImage.scanLine(y), p, frameGrabTargetImage.width() * 4);
2307 p += layout.rowPitch;
2310 devFuncs->vkUnmapMemory(dev, frameGrabImageMem);
2312 devFuncs->vkDestroyImage(dev, frameGrabImage,
nullptr);
2313 frameGrabImage = VK_NULL_HANDLE;
2314 devFuncs->vkFreeMemory(dev, frameGrabImageMem,
nullptr);
2315 frameGrabImageMem = VK_NULL_HANDLE;
2319
2320
2321
2322
2323
2324
2325VkPhysicalDevice QVulkanWindow::physicalDevice()
const
2327 Q_D(
const QVulkanWindow);
2328 if (d->physDevIndex < d->physDevs.size())
2329 return d->physDevs[d->physDevIndex];
2330 qWarning(
"QVulkanWindow: Physical device not available");
2331 return VK_NULL_HANDLE;
2335
2336
2337
2338
2339
2340
2341const VkPhysicalDeviceProperties *QVulkanWindow::physicalDeviceProperties()
const
2343 Q_D(
const QVulkanWindow);
2344 if (d->physDevIndex < d->physDevProps.size())
2345 return &d->physDevProps[d->physDevIndex];
2346 qWarning(
"QVulkanWindow: Physical device properties not available");
2351
2352
2353
2354
2355
2356
2357VkDevice QVulkanWindow::device()
const
2359 Q_D(
const QVulkanWindow);
2364
2365
2366
2367
2368
2369
2370VkQueue QVulkanWindow::graphicsQueue()
const
2372 Q_D(
const QVulkanWindow);
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387uint32_t QVulkanWindow::graphicsQueueFamilyIndex()
const
2389 Q_D(
const QVulkanWindow);
2390 return d->gfxQueueFamilyIdx;
2394
2395
2396
2397
2398
2399
2400VkCommandPool QVulkanWindow::graphicsCommandPool()
const
2402 Q_D(
const QVulkanWindow);
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416uint32_t QVulkanWindow::hostVisibleMemoryIndex()
const
2418 Q_D(
const QVulkanWindow);
2419 return d->hostVisibleMemIndex;
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434uint32_t QVulkanWindow::deviceLocalMemoryIndex()
const
2436 Q_D(
const QVulkanWindow);
2437 return d->deviceLocalMemIndex;
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458VkRenderPass QVulkanWindow::defaultRenderPass()
const
2460 Q_D(
const QVulkanWindow);
2461 return d->defaultRenderPass;
2465
2466
2467
2468
2469
2470
2471
2472
2473VkFormat QVulkanWindow::colorFormat()
const
2475 Q_D(
const QVulkanWindow);
2476 return d->colorFormat;
2480
2481
2482
2483
2484
2485
2486VkFormat QVulkanWindow::depthStencilFormat()
const
2488 Q_D(
const QVulkanWindow);
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515QSize QVulkanWindow::swapChainImageSize()
const
2517 Q_D(
const QVulkanWindow);
2518 return d->swapChainImageSize;
2522
2523
2524
2525
2526
2527
2528
2529VkCommandBuffer QVulkanWindow::currentCommandBuffer()
const
2531 Q_D(
const QVulkanWindow);
2532 if (!d->framePending) {
2533 qWarning(
"QVulkanWindow: Attempted to call currentCommandBuffer() without an active frame");
2534 return VK_NULL_HANDLE;
2536 return d->frameRes[d->currentFrame].cmdBuf;
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558VkFramebuffer QVulkanWindow::currentFramebuffer()
const
2560 Q_D(
const QVulkanWindow);
2561 if (!d->framePending) {
2562 qWarning(
"QVulkanWindow: Attempted to call currentFramebuffer() without an active frame");
2563 return VK_NULL_HANDLE;
2565 return d->imageRes[d->currentImage].fb;
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589int QVulkanWindow::currentFrame()
const
2591 Q_D(
const QVulkanWindow);
2592 if (!d->framePending)
2593 qWarning(
"QVulkanWindow: Attempted to call currentFrame() without an active frame");
2594 return d->currentFrame;
2598
2599
2600
2601
2602
2605
2606
2607
2608
2609
2610
2611
2612
2613int QVulkanWindow::concurrentFrameCount()
const
2615 Q_D(
const QVulkanWindow);
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630int QVulkanWindow::swapChainImageCount()
const
2632 Q_D(
const QVulkanWindow);
2633 return d->swapChainBufferCount;
2637
2638
2639
2640
2641
2642int QVulkanWindow::currentSwapChainImageIndex()
const
2644 Q_D(
const QVulkanWindow);
2645 if (!d->framePending)
2646 qWarning(
"QVulkanWindow: Attempted to call currentSwapChainImageIndex() without an active frame");
2647 return d->currentImage;
2651
2652
2653
2654
2655
2656
2657
2658
2659VkImage QVulkanWindow::swapChainImage(
int idx)
const
2661 Q_D(
const QVulkanWindow);
2662 return idx >= 0 && idx < d->swapChainBufferCount ? d->imageRes[idx].image : VK_NULL_HANDLE;
2666
2667
2668
2669
2670
2671
2672
2673
2674VkImageView QVulkanWindow::swapChainImageView(
int idx)
const
2676 Q_D(
const QVulkanWindow);
2677 return idx >= 0 && idx < d->swapChainBufferCount ? d->imageRes[idx].imageView : VK_NULL_HANDLE;
2681
2682
2683
2684
2685
2686
2687VkImage QVulkanWindow::depthStencilImage()
const
2689 Q_D(
const QVulkanWindow);
2694
2695
2696
2697
2698
2699
2700VkImageView QVulkanWindow::depthStencilImageView()
const
2702 Q_D(
const QVulkanWindow);
2707
2708
2709
2710
2711
2712
2713
2714VkSampleCountFlagBits QVulkanWindow::sampleCountFlagBits()
const
2716 Q_D(
const QVulkanWindow);
2717 return d->sampleCount;
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730VkImage QVulkanWindow::msaaColorImage(
int idx)
const
2732 Q_D(
const QVulkanWindow);
2733 return idx >= 0 && idx < d->swapChainBufferCount ? d->imageRes[idx].msaaImage : VK_NULL_HANDLE;
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746VkImageView QVulkanWindow::msaaColorImageView(
int idx)
const
2748 Q_D(
const QVulkanWindow);
2749 return idx >= 0 && idx < d->swapChainBufferCount ? d->imageRes[idx].msaaImageView : VK_NULL_HANDLE;
2753
2754
2755
2756
2757
2758
2759
2760bool QVulkanWindow::supportsGrab()
const
2762 Q_D(
const QVulkanWindow);
2763 return d->swapChainSupportsReadBack;
2767
2768
2769
2770
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797QImage QVulkanWindow::grab()
2800 if (!d->swapChain) {
2801 qWarning(
"QVulkanWindow: Attempted to call grab() without a swapchain");
2804 if (d->framePending) {
2805 qWarning(
"QVulkanWindow: Attempted to call grab() while a frame is still pending");
2808 if (!d->swapChainSupportsReadBack) {
2809 qWarning(
"QVulkanWindow: Attempted to call grab() with a swapchain that does not support usage as transfer source");
2813 d->frameGrabbing =
true;
2816 if (d->colorFormat == VK_FORMAT_B8G8R8A8_UNORM)
2817 d->frameGrabTargetImage = std::move(d->frameGrabTargetImage).rgbSwapped();
2819 return d->frameGrabTargetImage;
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833QMatrix4x4 QVulkanWindow::clipCorrectionMatrix()
2836 if (d->m_clipCorrect.isIdentity()) {
2838 d->m_clipCorrect = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
2839 0.0f, -1.0f, 0.0f, 0.0f,
2840 0.0f, 0.0f, 0.5f, 0.5f,
2841 0.0f, 0.0f, 0.0f, 1.0f);
2843 return d->m_clipCorrect;
2848#include "moc_qvulkanwindow.cpp"
Combined button and popup list for selecting options.
VkSampleCountFlagBits mask
static VkDeviceSize aligned(VkDeviceSize v, VkDeviceSize byteAlign)