5#include "qvulkanfunctions.h"
7#include <QLoggingCategory>
10#include <QCoreApplication>
17
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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
209
210
211
212
213QVulkanWindow::QVulkanWindow(QWindow *parent)
214 : QWindow(*(
new QVulkanWindowPrivate), parent)
216 setSurfaceType(QSurface::VulkanSurface);
220
221
222QVulkanWindow::~QVulkanWindow()
226QVulkanWindowPrivate::~QVulkanWindowPrivate()
235
236
237
238
239
240
241
242
245
246
247
248
249
250
251void QVulkanWindow::setFlags(Flags flags)
254 if (d->status != QVulkanWindowPrivate::StatusUninitialized) {
255 qWarning(
"QVulkanWindow: Attempted to set flags when already initialized");
262
263
264QVulkanWindow::Flags QVulkanWindow::flags()
const
266 Q_D(
const QVulkanWindow);
271
272
273
274
275QList<VkPhysicalDeviceProperties> QVulkanWindow::availablePhysicalDevices()
278 if (!d->physDevs.isEmpty() && !d->physDevProps.isEmpty())
279 return d->physDevProps;
281 QVulkanInstance *inst = vulkanInstance();
283 qWarning(
"QVulkanWindow: Attempted to call availablePhysicalDevices() without a QVulkanInstance");
284 return d->physDevProps;
287 QVulkanFunctions *f = inst->functions();
289 VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &count,
nullptr);
290 if (err != VK_SUCCESS) {
291 qWarning(
"QVulkanWindow: Failed to get physical device count: %d", err);
292 return d->physDevProps;
295 qCDebug(lcGuiVk,
"%d physical devices", count);
297 return d->physDevProps;
299 QList<VkPhysicalDevice> devs(count);
300 err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &count, devs.data());
301 if (err != VK_SUCCESS) {
302 qWarning(
"QVulkanWindow: Failed to enumerate physical devices: %d", err);
303 return d->physDevProps;
307 d->physDevProps.resize(count);
308 for (uint32_t i = 0; i < count; ++i) {
309 VkPhysicalDeviceProperties *p = &d->physDevProps[i];
310 f->vkGetPhysicalDeviceProperties(d->physDevs.at(i), p);
311 qCDebug(lcGuiVk,
"Physical device [%d]: name '%s' version %d.%d.%d", i, p->deviceName,
312 VK_VERSION_MAJOR(p->driverVersion), VK_VERSION_MINOR(p->driverVersion),
313 VK_VERSION_PATCH(p->driverVersion));
316 return d->physDevProps;
320
321
322
323
324
325
326
327
328
329void QVulkanWindow::setPhysicalDeviceIndex(
int idx)
332 if (d->status != QVulkanWindowPrivate::StatusUninitialized) {
333 qWarning(
"QVulkanWindow: Attempted to set physical device when already initialized");
336 const int count = availablePhysicalDevices().size();
337 if (idx < 0 || idx >= count) {
338 qWarning(
"QVulkanWindow: Invalid physical device index %d (total physical devices: %d)", idx, count);
341 d->physDevIndex = idx;
345
346
347
348
349
350QVulkanInfoVector<QVulkanExtension> QVulkanWindow::supportedDeviceExtensions()
354 availablePhysicalDevices();
356 if (d->physDevs.isEmpty()) {
357 qWarning(
"QVulkanWindow: No physical devices found");
358 return QVulkanInfoVector<QVulkanExtension>();
361 VkPhysicalDevice physDev = d->physDevs.at(d->physDevIndex);
362 if (d->supportedDevExtensions.contains(physDev))
363 return d->supportedDevExtensions.value(physDev);
365 QVulkanFunctions *f = vulkanInstance()->functions();
367 VkResult err = f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &count,
nullptr);
368 if (err == VK_SUCCESS) {
369 QList<VkExtensionProperties> extProps(count);
370 err = f->vkEnumerateDeviceExtensionProperties(physDev,
nullptr, &count, extProps.data());
371 if (err == VK_SUCCESS) {
372 QVulkanInfoVector<QVulkanExtension> exts;
373 for (
const VkExtensionProperties &prop : extProps) {
374 QVulkanExtension ext;
375 ext.name = prop.extensionName;
376 ext.version = prop.specVersion;
379 d->supportedDevExtensions.insert(physDev, exts);
380 qCDebug(lcGuiVk) <<
"Supported device extensions:" << exts;
385 qWarning(
"QVulkanWindow: Failed to query device extension count: %d", err);
386 return QVulkanInfoVector<QVulkanExtension>();
390
391
392
393
394
395
396
397
398
399
400
401void QVulkanWindow::setDeviceExtensions(
const QByteArrayList &extensions)
404 if (d->status != QVulkanWindowPrivate::StatusUninitialized) {
405 qWarning(
"QVulkanWindow: Attempted to set device extensions when already initialized");
408 d->requestedDevExtensions = extensions;
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436void QVulkanWindow::setPreferredColorFormats(
const QList<VkFormat> &formats)
439 if (d->status != QVulkanWindowPrivate::StatusUninitialized) {
440 qWarning(
"QVulkanWindow: Attempted to set preferred color format when already initialized");
443 d->requestedColorFormats = formats;
449} q_vk_sampleCounts[] = {
451 { VK_SAMPLE_COUNT_1_BIT, 1 },
452 { VK_SAMPLE_COUNT_2_BIT, 2 },
453 { VK_SAMPLE_COUNT_4_BIT, 4 },
454 { VK_SAMPLE_COUNT_8_BIT, 8 },
455 { VK_SAMPLE_COUNT_16_BIT, 16 },
456 { VK_SAMPLE_COUNT_32_BIT, 32 },
457 { VK_SAMPLE_COUNT_64_BIT, 64 }
461
462
463
464
465
466
467
468
469
470
471
472QList<
int> QVulkanWindow::supportedSampleCounts()
474 Q_D(
const QVulkanWindow);
477 availablePhysicalDevices();
479 if (d->physDevs.isEmpty()) {
480 qWarning(
"QVulkanWindow: No physical devices found");
484 const VkPhysicalDeviceLimits *limits = &d->physDevProps[d->physDevIndex].limits;
485 VkSampleCountFlags color = limits->framebufferColorSampleCounts;
486 VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
487 VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
489 for (
const auto &qvk_sampleCount : q_vk_sampleCounts) {
490 if ((color & qvk_sampleCount.mask)
491 && (depth & qvk_sampleCount.mask)
492 && (stencil & qvk_sampleCount.mask))
494 result.append(qvk_sampleCount.count);
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522void QVulkanWindow::setSampleCount(
int sampleCount)
525 if (d->status != QVulkanWindowPrivate::StatusUninitialized) {
526 qWarning(
"QVulkanWindow: Attempted to set sample count when already initialized");
531 sampleCount = qBound(1, sampleCount, 64);
533 if (!supportedSampleCounts().contains(sampleCount)) {
534 qWarning(
"QVulkanWindow: Attempted to set unsupported sample count %d", sampleCount);
538 for (
const auto &qvk_sampleCount : q_vk_sampleCounts) {
539 if (qvk_sampleCount.count == sampleCount) {
540 d->sampleCount = qvk_sampleCount.mask;
548void QVulkanWindowPrivate::init()
551 Q_ASSERT(status == StatusUninitialized);
553 qCDebug(lcGuiVk,
"QVulkanWindow init");
555 inst = q->vulkanInstance();
557 qWarning(
"QVulkanWindow: Attempted to initialize without a QVulkanInstance");
560 status = StatusFailRetry;
565 renderer = q->createRenderer();
567 surface = QVulkanInstance::surfaceForWindow(q);
568 if (surface == VK_NULL_HANDLE) {
569 qWarning(
"QVulkanWindow: Failed to retrieve Vulkan surface for window");
570 status = StatusFailRetry;
574 q->availablePhysicalDevices();
576 if (physDevs.isEmpty()) {
577 qWarning(
"QVulkanWindow: No physical devices found");
582 if (physDevIndex < 0 || physDevIndex >= physDevs.size()) {
583 qWarning(
"QVulkanWindow: Invalid physical device index; defaulting to 0");
586 qCDebug(lcGuiVk,
"Using physical device [%d]", physDevIndex);
590 renderer->preInitResources();
592 VkPhysicalDevice physDev = physDevs.at(physDevIndex);
593 QVulkanFunctions *f = inst->functions();
595 uint32_t queueCount = 0;
596 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount,
nullptr);
597 QList<VkQueueFamilyProperties> queueFamilyProps(queueCount);
598 f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
599 gfxQueueFamilyIdx = uint32_t(-1);
600 presQueueFamilyIdx = uint32_t(-1);
601 for (
int i = 0; i < queueFamilyProps.size(); ++i) {
602 const bool supportsPresent = inst->supportsPresent(physDev, i, q);
603 qCDebug(lcGuiVk,
"queue family %d: flags=0x%x count=%d supportsPresent=%d", i,
604 queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount, supportsPresent);
605 if (gfxQueueFamilyIdx == uint32_t(-1)
606 && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
608 gfxQueueFamilyIdx = i;
610 if (gfxQueueFamilyIdx != uint32_t(-1)) {
611 presQueueFamilyIdx = gfxQueueFamilyIdx;
613 qCDebug(lcGuiVk,
"No queue with graphics+present; trying separate queues");
614 for (
int i = 0; i < queueFamilyProps.size(); ++i) {
615 if (gfxQueueFamilyIdx == uint32_t(-1) && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT))
616 gfxQueueFamilyIdx = i;
617 if (presQueueFamilyIdx == uint32_t(-1) && inst->supportsPresent(physDev, i, q))
618 presQueueFamilyIdx = i;
621 if (gfxQueueFamilyIdx == uint32_t(-1)) {
622 qWarning(
"QVulkanWindow: No graphics queue family found");
626 if (presQueueFamilyIdx == uint32_t(-1)) {
627 qWarning(
"QVulkanWindow: No present queue family found");
633 if (qEnvironmentVariableIsSet(
"QT_VK_PRESENT_QUEUE_INDEX"))
634 presQueueFamilyIdx = qEnvironmentVariableIntValue(
"QT_VK_PRESENT_QUEUE_INDEX");
636 qCDebug(lcGuiVk,
"Using queue families: graphics = %u present = %u", gfxQueueFamilyIdx, presQueueFamilyIdx);
638 QList<VkDeviceQueueCreateInfo> queueInfo;
639 queueInfo.reserve(2);
640 const float prio[] = { 0 };
641 VkDeviceQueueCreateInfo addQueueInfo;
642 memset(&addQueueInfo, 0,
sizeof(addQueueInfo));
643 addQueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
644 addQueueInfo.queueFamilyIndex = gfxQueueFamilyIdx;
645 addQueueInfo.queueCount = 1;
646 addQueueInfo.pQueuePriorities = prio;
647 queueInfo.append(addQueueInfo);
648 if (gfxQueueFamilyIdx != presQueueFamilyIdx) {
649 addQueueInfo.queueFamilyIndex = presQueueFamilyIdx;
650 addQueueInfo.queueCount = 1;
651 addQueueInfo.pQueuePriorities = prio;
652 queueInfo.append(addQueueInfo);
654 if (queueCreateInfoModifier) {
655 queueCreateInfoModifier(queueFamilyProps.constData(), queueCount, queueInfo);
656 bool foundGfxQueue =
false;
657 bool foundPresQueue =
false;
658 for (
const VkDeviceQueueCreateInfo& createInfo : std::as_const(queueInfo)) {
659 foundGfxQueue |= createInfo.queueFamilyIndex == gfxQueueFamilyIdx;
660 foundPresQueue |= createInfo.queueFamilyIndex == presQueueFamilyIdx;
662 if (!foundGfxQueue) {
663 qWarning(
"QVulkanWindow: Graphics queue missing after call to queueCreateInfoModifier");
667 if (!foundPresQueue) {
668 qWarning(
"QVulkanWindow: Present queue missing after call to queueCreateInfoModifier");
676 QList<
const char *> devExts;
677 QVulkanInfoVector<QVulkanExtension> supportedExtensions = q->supportedDeviceExtensions();
678 QByteArrayList reqExts = requestedDevExtensions;
679 reqExts.append(
"VK_KHR_swapchain");
681 QByteArray envExts = qgetenv(
"QT_VULKAN_DEVICE_EXTENSIONS");
682 if (!envExts.isEmpty()) {
683 QByteArrayList envExtList = envExts.split(
';');
684 for (
auto ext : reqExts)
685 envExtList.removeAll(ext);
686 reqExts.append(envExtList);
689 for (
const QByteArray &ext : reqExts) {
690 if (supportedExtensions.contains(ext))
691 devExts.append(ext.constData());
693 qCDebug(lcGuiVk) <<
"Enabling device extensions:" << devExts;
695 VkDeviceCreateInfo devInfo;
696 memset(&devInfo, 0,
sizeof(devInfo));
697 devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
698 devInfo.queueCreateInfoCount = queueInfo.size();
699 devInfo.pQueueCreateInfos = queueInfo.constData();
700 devInfo.enabledExtensionCount = devExts.size();
701 devInfo.ppEnabledExtensionNames = devExts.constData();
703 VkPhysicalDeviceFeatures features = {};
704 VkPhysicalDeviceFeatures2 features2 = {};
705 if (enabledFeatures2Modifier) {
706 features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
707 enabledFeatures2Modifier(features2);
708 devInfo.pNext = &features2;
709 }
else if (enabledFeaturesModifier) {
710 enabledFeaturesModifier(features);
711 devInfo.pEnabledFeatures = &features;
715 f->vkGetPhysicalDeviceFeatures(physDev, &features);
716 features.robustBufferAccess = VK_FALSE;
717 devInfo.pEnabledFeatures = &features;
724 uint32_t apiVersion = physDevProps[physDevIndex].apiVersion;
725 if (VK_VERSION_MAJOR(apiVersion) == 1
726 && VK_VERSION_MINOR(apiVersion) == 0
727 && VK_VERSION_PATCH(apiVersion) <= 13)
730 const QByteArray stdValName = QByteArrayLiteral(
"VK_LAYER_KHRONOS_validation");
731 const char *stdValNamePtr = stdValName.constData();
732 if (inst->layers().contains(stdValName)) {
734 VkResult err = f->vkEnumerateDeviceLayerProperties(physDev, &count,
nullptr);
735 if (err == VK_SUCCESS) {
736 QList<VkLayerProperties> layerProps(count);
737 err = f->vkEnumerateDeviceLayerProperties(physDev, &count, layerProps.data());
738 if (err == VK_SUCCESS) {
739 for (
const VkLayerProperties &prop : layerProps) {
740 if (!strncmp(prop.layerName, stdValNamePtr, stdValName.size())) {
741 devInfo.enabledLayerCount = 1;
742 devInfo.ppEnabledLayerNames = &stdValNamePtr;
751 VkResult err = f->vkCreateDevice(physDev, &devInfo,
nullptr, &dev);
752 if (err == VK_ERROR_DEVICE_LOST) {
753 qWarning(
"QVulkanWindow: Physical device lost");
755 renderer->physicalDeviceLost();
758 physDevProps.clear();
759 status = StatusUninitialized;
760 qCDebug(lcGuiVk,
"Attempting to restart in 2 seconds");
761 QTimer::singleShot(2000, q, [
this]() { ensureStarted(); });
764 if (err != VK_SUCCESS) {
765 qWarning(
"QVulkanWindow: Failed to create device: %d", err);
770 devFuncs = inst->deviceFunctions(dev);
773 devFuncs->vkGetDeviceQueue(dev, gfxQueueFamilyIdx, 0, &gfxQueue);
774 if (gfxQueueFamilyIdx == presQueueFamilyIdx)
775 presQueue = gfxQueue;
777 devFuncs->vkGetDeviceQueue(dev, presQueueFamilyIdx, 0, &presQueue);
779 VkCommandPoolCreateInfo poolInfo;
780 memset(&poolInfo, 0,
sizeof(poolInfo));
781 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
782 poolInfo.queueFamilyIndex = gfxQueueFamilyIdx;
783 err = devFuncs->vkCreateCommandPool(dev, &poolInfo,
nullptr, &cmdPool);
784 if (err != VK_SUCCESS) {
785 qWarning(
"QVulkanWindow: Failed to create command pool: %d", err);
789 if (gfxQueueFamilyIdx != presQueueFamilyIdx) {
790 poolInfo.queueFamilyIndex = presQueueFamilyIdx;
791 err = devFuncs->vkCreateCommandPool(dev, &poolInfo,
nullptr, &presCmdPool);
792 if (err != VK_SUCCESS) {
793 qWarning(
"QVulkanWindow: Failed to create command pool for present queue: %d", err);
799 hostVisibleMemIndex = 0;
800 VkPhysicalDeviceMemoryProperties physDevMemProps;
801 bool hostVisibleMemIndexSet =
false;
802 f->vkGetPhysicalDeviceMemoryProperties(physDev, &physDevMemProps);
803 for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
804 const VkMemoryType *memType = physDevMemProps.memoryTypes;
805 qCDebug(lcGuiVk,
"memtype %d: flags=0x%x", i, memType[i].propertyFlags);
808 const int hostVisibleAndCoherent = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
809 if ((memType[i].propertyFlags & hostVisibleAndCoherent) == hostVisibleAndCoherent) {
810 if (!hostVisibleMemIndexSet
811 || (memType[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT)) {
812 hostVisibleMemIndexSet =
true;
813 hostVisibleMemIndex = i;
817 qCDebug(lcGuiVk,
"Picked memtype %d for host visible memory", hostVisibleMemIndex);
818 deviceLocalMemIndex = 0;
819 for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
820 const VkMemoryType *memType = physDevMemProps.memoryTypes;
822 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
823 deviceLocalMemIndex = i;
827 qCDebug(lcGuiVk,
"Picked memtype %d for device local memory", deviceLocalMemIndex);
829 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR || !vkGetPhysicalDeviceSurfaceFormatsKHR) {
830 vkGetPhysicalDeviceSurfaceCapabilitiesKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
831 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR"));
832 vkGetPhysicalDeviceSurfaceFormatsKHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>(
833 inst->getInstanceProcAddr(
"vkGetPhysicalDeviceSurfaceFormatsKHR"));
834 if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR || !vkGetPhysicalDeviceSurfaceFormatsKHR) {
835 qWarning(
"QVulkanWindow: Physical device surface queries not available");
846 uint32_t formatCount = 0;
847 vkGetPhysicalDeviceSurfaceFormatsKHR(physDev, surface, &formatCount,
nullptr);
848 QList<VkSurfaceFormatKHR> formats(formatCount);
850 vkGetPhysicalDeviceSurfaceFormatsKHR(physDev, surface, &formatCount, formats.data());
852 colorFormat = VK_FORMAT_B8G8R8A8_UNORM;
853 colorSpace = VkColorSpaceKHR(0);
856 if (!formats.isEmpty() && formats[0].format != VK_FORMAT_UNDEFINED) {
857 colorFormat = formats[0].format;
858 colorSpace = formats[0].colorSpace;
862 if (!formats.isEmpty() && !requestedColorFormats.isEmpty()) {
863 for (VkFormat reqFmt : std::as_const(requestedColorFormats)) {
864 auto r = std::find_if(formats.cbegin(), formats.cend(),
865 [reqFmt](
const VkSurfaceFormatKHR &sfmt) {
return sfmt.format == reqFmt; });
866 if (r != formats.cend()) {
867 colorFormat = r->format;
868 colorSpace = r->colorSpace;
874#if QT_CONFIG(wayland)
879 const bool hasPassthrough = std::any_of(formats.cbegin(), formats.cend(), [
this](
const VkSurfaceFormatKHR &format) {
880 return format.format == colorFormat && format.colorSpace == VK_COLOR_SPACE_PASS_THROUGH_EXT;
882 if (hasPassthrough) {
883 colorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
887 const VkFormat dsFormatCandidates[] = {
888 VK_FORMAT_D24_UNORM_S8_UINT,
889 VK_FORMAT_D32_SFLOAT_S8_UINT,
890 VK_FORMAT_D16_UNORM_S8_UINT
892 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
894 while (dsFormatIdx < dsFormatCandidateCount) {
895 dsFormat = dsFormatCandidates[dsFormatIdx];
896 VkFormatProperties fmtProp;
897 f->vkGetPhysicalDeviceFormatProperties(physDev, dsFormat, &fmtProp);
898 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
902 if (dsFormatIdx == dsFormatCandidateCount)
903 qWarning(
"QVulkanWindow: Failed to find an optimal depth-stencil format");
905 qCDebug(lcGuiVk,
"Color format: %d Depth-stencil format: %d", colorFormat, dsFormat);
907 if (!createDefaultRenderPass())
911 renderer->initResources();
913 status = StatusDeviceReady;
916void QVulkanWindowPrivate::reset()
921 qCDebug(lcGuiVk,
"QVulkanWindow reset");
923 devFuncs->vkDeviceWaitIdle(dev);
926 renderer->releaseResources();
927 devFuncs->vkDeviceWaitIdle(dev);
930 if (defaultRenderPass) {
931 devFuncs->vkDestroyRenderPass(dev, defaultRenderPass,
nullptr);
932 defaultRenderPass = VK_NULL_HANDLE;
936 devFuncs->vkDestroyCommandPool(dev, cmdPool,
nullptr);
937 cmdPool = VK_NULL_HANDLE;
941 devFuncs->vkDestroyCommandPool(dev, presCmdPool,
nullptr);
942 presCmdPool = VK_NULL_HANDLE;
945 if (frameGrabImage) {
946 devFuncs->vkDestroyImage(dev, frameGrabImage,
nullptr);
947 frameGrabImage = VK_NULL_HANDLE;
950 if (frameGrabImageMem) {
951 devFuncs->vkFreeMemory(dev, frameGrabImageMem,
nullptr);
952 frameGrabImageMem = VK_NULL_HANDLE;
956 devFuncs->vkDestroyDevice(dev,
nullptr);
957 inst->resetDeviceFunctions(dev);
958 dev = VK_NULL_HANDLE;
959 vkCreateSwapchainKHR =
nullptr;
962 surface = VK_NULL_HANDLE;
964 status = StatusUninitialized;
967bool QVulkanWindowPrivate::createDefaultRenderPass()
969 VkAttachmentDescription attDesc[3];
970 memset(attDesc, 0,
sizeof(attDesc));
972 const bool msaa = sampleCount > VK_SAMPLE_COUNT_1_BIT;
975 attDesc[0].format = colorFormat;
976 attDesc[0].samples = VK_SAMPLE_COUNT_1_BIT;
977 attDesc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
978 attDesc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
979 attDesc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
980 attDesc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
981 attDesc[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
982 attDesc[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
984 attDesc[1].format = dsFormat;
985 attDesc[1].samples = sampleCount;
986 attDesc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
987 attDesc[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
988 attDesc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
989 attDesc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
990 attDesc[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
991 attDesc[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
995 attDesc[2].format = colorFormat;
996 attDesc[2].samples = sampleCount;
997 attDesc[2].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
998 attDesc[2].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
999 attDesc[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1000 attDesc[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1001 attDesc[2].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1002 attDesc[2].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1005 VkAttachmentReference colorRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
1006 VkAttachmentReference resolveRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
1007 VkAttachmentReference dsRef = { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
1009 VkSubpassDescription subPassDesc;
1010 memset(&subPassDesc, 0,
sizeof(subPassDesc));
1011 subPassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1012 subPassDesc.colorAttachmentCount = 1;
1013 subPassDesc.pColorAttachments = &colorRef;
1014 subPassDesc.pDepthStencilAttachment = &dsRef;
1016 VkRenderPassCreateInfo rpInfo;
1017 memset(&rpInfo, 0,
sizeof(rpInfo));
1018 rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1019 rpInfo.attachmentCount = 2;
1020 rpInfo.pAttachments = attDesc;
1021 rpInfo.subpassCount = 1;
1022 rpInfo.pSubpasses = &subPassDesc;
1025 colorRef.attachment = 2;
1026 subPassDesc.pResolveAttachments = &resolveRef;
1027 rpInfo.attachmentCount = 3;
1030 VkResult err = devFuncs->vkCreateRenderPass(dev, &rpInfo,
nullptr, &defaultRenderPass);
1031 if (err != VK_SUCCESS) {
1032 qWarning(
"QVulkanWindow: Failed to create renderpass: %d", err);
1039void QVulkanWindowPrivate::recreateSwapChain()
1042 Q_ASSERT(status >= StatusDeviceReady);
1044 swapChainImageSize = q->size() * q->devicePixelRatio();
1046 if (swapChainImageSize.isEmpty())
1049 QVulkanInstance *inst = q->vulkanInstance();
1050 QVulkanFunctions *f = inst->functions();
1051 devFuncs->vkDeviceWaitIdle(dev);
1053 if (!vkCreateSwapchainKHR) {
1054 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
1055 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
1056 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
1057 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
1058 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
1061 VkPhysicalDevice physDev = physDevs.at(physDevIndex);
1062 VkSurfaceCapabilitiesKHR surfaceCaps;
1063 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, surface, &surfaceCaps);
1064 uint32_t reqBufferCount;
1065 if (surfaceCaps.maxImageCount == 0)
1066 reqBufferCount = qMax<uint32_t>(2, surfaceCaps.minImageCount);
1068 reqBufferCount = qMax(qMin<uint32_t>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
1070 VkExtent2D bufferSize = surfaceCaps.currentExtent;
1071 if (bufferSize.width == uint32_t(-1)) {
1072 Q_ASSERT(bufferSize.height == uint32_t(-1));
1073 bufferSize.width = swapChainImageSize.width();
1074 bufferSize.height = swapChainImageSize.height();
1076 swapChainImageSize = QSize(bufferSize.width, bufferSize.height);
1079 VkSurfaceTransformFlagBitsKHR preTransform =
1080 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
1081 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
1082 : surfaceCaps.currentTransform;
1084 VkCompositeAlphaFlagBitsKHR compositeAlpha =
1085 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
1086 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
1087 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
1089 if (q->requestedFormat().hasAlpha()) {
1090 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
1091 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
1092 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
1093 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
1096 VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1097 swapChainSupportsReadBack = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1098 if (swapChainSupportsReadBack)
1099 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1101 VkSwapchainKHR oldSwapChain = swapChain;
1102 VkSwapchainCreateInfoKHR swapChainInfo;
1103 memset(&swapChainInfo, 0,
sizeof(swapChainInfo));
1104 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
1105 swapChainInfo.surface = surface;
1106 swapChainInfo.minImageCount = reqBufferCount;
1107 swapChainInfo.imageFormat = colorFormat;
1108 swapChainInfo.imageColorSpace = colorSpace;
1109 swapChainInfo.imageExtent = bufferSize;
1110 swapChainInfo.imageArrayLayers = 1;
1111 swapChainInfo.imageUsage = usage;
1112 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
1113 swapChainInfo.preTransform = preTransform;
1114 swapChainInfo.compositeAlpha = compositeAlpha;
1115 swapChainInfo.presentMode = presentMode;
1116 swapChainInfo.clipped =
true;
1117 swapChainInfo.oldSwapchain = oldSwapChain;
1119 qCDebug(lcGuiVk,
"Creating new swap chain of %d buffers, size %dx%d", reqBufferCount, bufferSize.width, bufferSize.height);
1121 VkSwapchainKHR newSwapChain;
1122 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
1123 if (err != VK_SUCCESS) {
1124 qWarning(
"QVulkanWindow: Failed to create swap chain: %d", err);
1131 swapChain = newSwapChain;
1133 uint32_t actualSwapChainBufferCount = 0;
1134 err = vkGetSwapchainImagesKHR(dev, swapChain, &actualSwapChainBufferCount,
nullptr);
1135 if (err != VK_SUCCESS || actualSwapChainBufferCount < 2) {
1136 qWarning(
"QVulkanWindow: Failed to get swapchain images: %d (count=%d)", err, actualSwapChainBufferCount);
1140 qCDebug(lcGuiVk,
"Actual swap chain buffer count: %d (supportsReadback=%d)",
1141 actualSwapChainBufferCount, swapChainSupportsReadBack);
1142 if (actualSwapChainBufferCount > MAX_SWAPCHAIN_BUFFER_COUNT) {
1143 qWarning(
"QVulkanWindow: Too many swapchain buffers (%d)", actualSwapChainBufferCount);
1146 swapChainBufferCount = actualSwapChainBufferCount;
1148 VkImage swapChainImages[MAX_SWAPCHAIN_BUFFER_COUNT];
1149 err = vkGetSwapchainImagesKHR(dev, swapChain, &actualSwapChainBufferCount, swapChainImages);
1150 if (err != VK_SUCCESS) {
1151 qWarning(
"QVulkanWindow: Failed to get swapchain images: %d", err);
1155 if (!createTransientImage(dsFormat,
1156 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
1157 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
1166 const bool msaa = sampleCount > VK_SAMPLE_COUNT_1_BIT;
1167 VkImage msaaImages[MAX_SWAPCHAIN_BUFFER_COUNT];
1168 VkImageView msaaViews[MAX_SWAPCHAIN_BUFFER_COUNT];
1171 if (!createTransientImage(colorFormat,
1172 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1173 VK_IMAGE_ASPECT_COLOR_BIT,
1177 swapChainBufferCount))
1183 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
nullptr, VK_FENCE_CREATE_SIGNALED_BIT };
1185 for (
int i = 0; i < swapChainBufferCount; ++i) {
1186 ImageResources &image(imageRes[i]);
1187 image.image = swapChainImages[i];
1190 image.msaaImage = msaaImages[i];
1191 image.msaaImageView = msaaViews[i];
1194 VkImageViewCreateInfo imgViewInfo;
1195 memset(&imgViewInfo, 0,
sizeof(imgViewInfo));
1196 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1197 imgViewInfo.image = swapChainImages[i];
1198 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1199 imgViewInfo.format = colorFormat;
1200 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1201 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1202 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1203 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1204 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1205 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1206 err = devFuncs->vkCreateImageView(dev, &imgViewInfo,
nullptr, &image.imageView);
1207 if (err != VK_SUCCESS) {
1208 qWarning(
"QVulkanWindow: Failed to create swapchain image view %d: %d", i, err);
1212 VkImageView views[3] = { image.imageView,
1214 msaa ? image.msaaImageView : VK_NULL_HANDLE };
1215 VkFramebufferCreateInfo fbInfo;
1216 memset(&fbInfo, 0,
sizeof(fbInfo));
1217 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
1218 fbInfo.renderPass = defaultRenderPass;
1219 fbInfo.attachmentCount = msaa ? 3 : 2;
1220 fbInfo.pAttachments = views;
1221 fbInfo.width = swapChainImageSize.width();
1222 fbInfo.height = swapChainImageSize.height();
1224 VkResult err = devFuncs->vkCreateFramebuffer(dev, &fbInfo,
nullptr, &image.fb);
1225 if (err != VK_SUCCESS) {
1226 qWarning(
"QVulkanWindow: Failed to create framebuffer: %d", err);
1230 if (gfxQueueFamilyIdx != presQueueFamilyIdx) {
1232 VkCommandBufferAllocateInfo cmdBufInfo = {
1233 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
nullptr, presCmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1 };
1234 err = devFuncs->vkAllocateCommandBuffers(dev, &cmdBufInfo, &image.presTransCmdBuf);
1235 if (err != VK_SUCCESS) {
1236 qWarning(
"QVulkanWindow: Failed to allocate acquire-on-present-queue command buffer: %d", err);
1239 VkCommandBufferBeginInfo cmdBufBeginInfo = {
1240 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
nullptr,
1241 VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
nullptr };
1242 err = devFuncs->vkBeginCommandBuffer(image.presTransCmdBuf, &cmdBufBeginInfo);
1243 if (err != VK_SUCCESS) {
1244 qWarning(
"QVulkanWindow: Failed to begin acquire-on-present-queue command buffer: %d", err);
1247 VkImageMemoryBarrier presTrans;
1248 memset(&presTrans, 0,
sizeof(presTrans));
1249 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1250 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1251 presTrans.oldLayout = presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1252 presTrans.srcQueueFamilyIndex = gfxQueueFamilyIdx;
1253 presTrans.dstQueueFamilyIndex = presQueueFamilyIdx;
1254 presTrans.image = image.image;
1255 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1256 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
1257 devFuncs->vkCmdPipelineBarrier(image.presTransCmdBuf,
1258 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1259 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1260 0, 0,
nullptr, 0,
nullptr,
1262 err = devFuncs->vkEndCommandBuffer(image.presTransCmdBuf);
1263 if (err != VK_SUCCESS) {
1264 qWarning(
"QVulkanWindow: Failed to end acquire-on-present-queue command buffer: %d", err);
1272 VkSemaphoreCreateInfo semInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
nullptr, 0 };
1273 for (
int i = 0; i < frameLag; ++i) {
1274 FrameResources &frame(frameRes[i]);
1276 frame.imageAcquired =
false;
1277 frame.imageSemWaitable =
false;
1279 devFuncs->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.imageSem);
1280 devFuncs->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.drawSem);
1281 if (gfxQueueFamilyIdx != presQueueFamilyIdx)
1282 devFuncs->vkCreateSemaphore(dev, &semInfo,
nullptr, &frame.presTransSem);
1284 err = devFuncs->vkCreateFence(dev, &fenceInfo,
nullptr, &frame.cmdFence);
1285 if (err != VK_SUCCESS) {
1286 qWarning(
"QVulkanWindow: Failed to create command buffer fence: %d", err);
1289 frame.cmdFenceWaitable =
true;
1295 renderer->initSwapChainResources();
1297 status = StatusReady;
1300uint32_t QVulkanWindowPrivate::chooseTransientImageMemType(VkImage img, uint32_t startIndex)
1302 VkPhysicalDeviceMemoryProperties physDevMemProps;
1303 inst->functions()->vkGetPhysicalDeviceMemoryProperties(physDevs[physDevIndex], &physDevMemProps);
1305 VkMemoryRequirements memReq;
1306 devFuncs->vkGetImageMemoryRequirements(dev, img, &memReq);
1307 uint32_t memTypeIndex = uint32_t(-1);
1309 if (memReq.memoryTypeBits) {
1311 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1312 bool foundDevLocal =
false;
1313 for (uint32_t i = startIndex; i < physDevMemProps.memoryTypeCount; ++i) {
1314 if (memReq.memoryTypeBits & (1 << i)) {
1315 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1316 if (!foundDevLocal) {
1317 foundDevLocal =
true;
1320 if (memType[i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1329 return memTypeIndex;
1334 return (v + byteAlign - 1) & ~(byteAlign - 1);
1337bool QVulkanWindowPrivate::createTransientImage(VkFormat format,
1338 VkImageUsageFlags usage,
1339 VkImageAspectFlags aspectMask,
1341 VkDeviceMemory *mem,
1345 VkMemoryRequirements memReq;
1348 Q_ASSERT(count > 0);
1349 for (
int i = 0; i < count; ++i) {
1350 VkImageCreateInfo imgInfo;
1351 memset(&imgInfo, 0,
sizeof(imgInfo));
1352 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1353 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1354 imgInfo.format = format;
1355 imgInfo.extent.width = swapChainImageSize.width();
1356 imgInfo.extent.height = swapChainImageSize.height();
1357 imgInfo.extent.depth = 1;
1358 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1359 imgInfo.samples = sampleCount;
1360 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1361 imgInfo.usage = usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1363 err = devFuncs->vkCreateImage(dev, &imgInfo,
nullptr, images + i);
1364 if (err != VK_SUCCESS) {
1365 qWarning(
"QVulkanWindow: Failed to create image: %d", err);
1372 devFuncs->vkGetImageMemoryRequirements(dev, images[i], &memReq);
1375 VkMemoryAllocateInfo memInfo;
1376 memset(&memInfo, 0,
sizeof(memInfo));
1377 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1378 memInfo.allocationSize = aligned(memReq.size, memReq.alignment) * count;
1380 uint32_t startIndex = 0;
1382 memInfo.memoryTypeIndex = chooseTransientImageMemType(images[0], startIndex);
1383 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1384 qWarning(
"QVulkanWindow: No suitable memory type found");
1387 startIndex = memInfo.memoryTypeIndex + 1;
1388 qCDebug(lcGuiVk,
"Allocating %u bytes for transient image (memtype %u)",
1389 uint32_t(memInfo.allocationSize), memInfo.memoryTypeIndex);
1390 err = devFuncs->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1391 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1392 qWarning(
"QVulkanWindow: Failed to allocate image memory: %d", err);
1395 }
while (err != VK_SUCCESS);
1397 VkDeviceSize ofs = 0;
1398 for (
int i = 0; i < count; ++i) {
1399 err = devFuncs->vkBindImageMemory(dev, images[i], *mem, ofs);
1400 if (err != VK_SUCCESS) {
1401 qWarning(
"QVulkanWindow: Failed to bind image memory: %d", err);
1404 ofs += aligned(memReq.size, memReq.alignment);
1406 VkImageViewCreateInfo imgViewInfo;
1407 memset(&imgViewInfo, 0,
sizeof(imgViewInfo));
1408 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1409 imgViewInfo.image = images[i];
1410 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1411 imgViewInfo.format = format;
1412 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1413 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1414 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1415 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1416 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1417 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1419 err = devFuncs->vkCreateImageView(dev, &imgViewInfo,
nullptr, views + i);
1420 if (err != VK_SUCCESS) {
1421 qWarning(
"QVulkanWindow: Failed to create image view: %d", err);
1429void QVulkanWindowPrivate::releaseSwapChain()
1431 if (!dev || !swapChain)
1434 qCDebug(lcGuiVk,
"Releasing swapchain");
1436 devFuncs->vkDeviceWaitIdle(dev);
1439 renderer->releaseSwapChainResources();
1440 devFuncs->vkDeviceWaitIdle(dev);
1443 for (
int i = 0; i < frameLag; ++i) {
1444 FrameResources &frame(frameRes[i]);
1446 devFuncs->vkFreeCommandBuffers(dev, cmdPool, 1, &frame.cmdBuf);
1447 frame.cmdBuf = VK_NULL_HANDLE;
1449 if (frame.imageSem) {
1450 devFuncs->vkDestroySemaphore(dev, frame.imageSem,
nullptr);
1451 frame.imageSem = VK_NULL_HANDLE;
1453 if (frame.drawSem) {
1454 devFuncs->vkDestroySemaphore(dev, frame.drawSem,
nullptr);
1455 frame.drawSem = VK_NULL_HANDLE;
1457 if (frame.presTransSem) {
1458 devFuncs->vkDestroySemaphore(dev, frame.presTransSem,
nullptr);
1459 frame.presTransSem = VK_NULL_HANDLE;
1461 if (frame.cmdFence) {
1462 if (frame.cmdFenceWaitable)
1463 devFuncs->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
1464 devFuncs->vkDestroyFence(dev, frame.cmdFence,
nullptr);
1465 frame.cmdFence = VK_NULL_HANDLE;
1466 frame.cmdFenceWaitable =
false;
1470 for (
int i = 0; i < swapChainBufferCount; ++i) {
1471 ImageResources &image(imageRes[i]);
1473 devFuncs->vkDestroyFramebuffer(dev, image.fb,
nullptr);
1474 image.fb = VK_NULL_HANDLE;
1476 if (image.imageView) {
1477 devFuncs->vkDestroyImageView(dev, image.imageView,
nullptr);
1478 image.imageView = VK_NULL_HANDLE;
1480 if (image.presTransCmdBuf) {
1481 devFuncs->vkFreeCommandBuffers(dev, presCmdPool, 1, &image.presTransCmdBuf);
1482 image.presTransCmdBuf = VK_NULL_HANDLE;
1484 if (image.msaaImageView) {
1485 devFuncs->vkDestroyImageView(dev, image.msaaImageView,
nullptr);
1486 image.msaaImageView = VK_NULL_HANDLE;
1488 if (image.msaaImage) {
1489 devFuncs->vkDestroyImage(dev, image.msaaImage,
nullptr);
1490 image.msaaImage = VK_NULL_HANDLE;
1495 devFuncs->vkFreeMemory(dev, msaaImageMem,
nullptr);
1496 msaaImageMem = VK_NULL_HANDLE;
1500 devFuncs->vkDestroyImageView(dev, dsView,
nullptr);
1501 dsView = VK_NULL_HANDLE;
1504 devFuncs->vkDestroyImage(dev, dsImage,
nullptr);
1505 dsImage = VK_NULL_HANDLE;
1508 devFuncs->vkFreeMemory(dev, dsMem,
nullptr);
1509 dsMem = VK_NULL_HANDLE;
1513 vkDestroySwapchainKHR(dev, swapChain,
nullptr);
1514 swapChain = VK_NULL_HANDLE;
1517 if (status == StatusReady)
1518 status = StatusDeviceReady;
1522
1523
1524void QVulkanWindow::exposeEvent(QExposeEvent *)
1531 if (!d->flags.testFlag(PersistentResources)) {
1532 d->releaseSwapChain();
1538void QVulkanWindowPrivate::ensureStarted()
1541 if (status == QVulkanWindowPrivate::StatusFailRetry)
1542 status = QVulkanWindowPrivate::StatusUninitialized;
1543 if (status == QVulkanWindowPrivate::StatusUninitialized) {
1545 if (status == QVulkanWindowPrivate::StatusDeviceReady)
1546 recreateSwapChain();
1548 if (status == QVulkanWindowPrivate::StatusReady)
1553
1554
1555void QVulkanWindow::resizeEvent(QResizeEvent *)
1561
1562
1563bool QVulkanWindow::event(QEvent *e)
1567 switch (e->type()) {
1569 case QEvent::UpdateRequest:
1577 case QEvent::PlatformSurface:
1578 if (
static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) {
1579 d->releaseSwapChain();
1588 return QWindow::event(e);
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1611
1612
1613
1614
1615
1616
1617void QVulkanWindow::setQueueCreateInfoModifier(
const QueueCreateInfoModifier &modifier)
1620 d->queueCreateInfoModifier = modifier;
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657void QVulkanWindow::setEnabledFeaturesModifier(
const EnabledFeaturesModifier &modifier)
1660 d->enabledFeaturesModifier = modifier;
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1691
1692
1693
1694
1695
1696void QVulkanWindow::setEnabledFeaturesModifier(EnabledFeatures2Modifier modifier)
1699 d->enabledFeatures2Modifier = std::move(modifier);
1703
1704
1705
1706
1707
1708
1709bool QVulkanWindow::isValid()
const
1711 Q_D(
const QVulkanWindow);
1712 return d->status == QVulkanWindowPrivate::StatusReady;
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726QVulkanWindowRenderer *QVulkanWindow::createRenderer()
1732
1733
1734QVulkanWindowRenderer::~QVulkanWindowRenderer()
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754void QVulkanWindowRenderer::preInitResources()
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773void QVulkanWindowRenderer::initResources()
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795void QVulkanWindowRenderer::initSwapChainResources()
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818void QVulkanWindowRenderer::releaseSwapChainResources()
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834void QVulkanWindowRenderer::releaseResources()
1839
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
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879void QVulkanWindowRenderer::physicalDeviceLost()
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898void QVulkanWindowRenderer::logicalDeviceLost()
1902QSize QVulkanWindowPrivate::surfacePixelSize()
const
1904 Q_Q(
const QVulkanWindow);
1905 VkSurfaceCapabilitiesKHR surfaceCaps = {};
1906 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDevs.at(physDevIndex), surface, &surfaceCaps);
1907 VkExtent2D bufferSize = surfaceCaps.currentExtent;
1908 if (bufferSize.width == uint32_t(-1)) {
1909 Q_ASSERT(bufferSize.height == uint32_t(-1));
1910 return q->size() * q->devicePixelRatio();
1912 return QSize(
int(bufferSize.width),
int(bufferSize.height));
1915void QVulkanWindowPrivate::beginFrame()
1917 if (!swapChain || framePending)
1921 if (swapChainImageSize != surfacePixelSize()) {
1922 recreateSwapChain();
1928 FrameResources &frame(frameRes[currentFrame]);
1929 if (frame.cmdFenceWaitable) {
1930 devFuncs->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
1931 devFuncs->vkResetFences(dev, 1, &frame.cmdFence);
1932 frame.cmdFenceWaitable =
false;
1936 if (!frame.imageAcquired) {
1937 VkResult err = vkAcquireNextImageKHR(dev, swapChain, UINT64_MAX,
1938 frame.imageSem, VK_NULL_HANDLE, ¤tImage);
1939 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
1940 frame.imageSemWaitable =
true;
1941 frame.imageAcquired =
true;
1942 }
else if (err == VK_ERROR_OUT_OF_DATE_KHR) {
1943 recreateSwapChain();
1947 if (!checkDeviceLost(err))
1948 qWarning(
"QVulkanWindow: Failed to acquire next swapchain image: %d", err);
1956 devFuncs->vkFreeCommandBuffers(dev, cmdPool, 1, &frame.cmdBuf);
1957 frame.cmdBuf =
nullptr;
1960 VkCommandBufferAllocateInfo cmdBufInfo = {
1961 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
nullptr, cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1 };
1962 VkResult err = devFuncs->vkAllocateCommandBuffers(dev, &cmdBufInfo, &frame.cmdBuf);
1963 if (err != VK_SUCCESS) {
1964 if (!checkDeviceLost(err))
1965 qWarning(
"QVulkanWindow: Failed to allocate frame command buffer: %d", err);
1969 VkCommandBufferBeginInfo cmdBufBeginInfo = {
1970 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
nullptr, 0,
nullptr };
1971 err = devFuncs->vkBeginCommandBuffer(frame.cmdBuf, &cmdBufBeginInfo);
1972 if (err != VK_SUCCESS) {
1973 if (!checkDeviceLost(err))
1974 qWarning(
"QVulkanWindow: Failed to begin frame command buffer: %d", err);
1979 frameGrabTargetImage = QImage(swapChainImageSize, QImage::Format_RGBA8888);
1981 ImageResources &image(imageRes[currentImage]);
1983 framePending =
true;
1984 renderer->startNextFrame();
1987 VkClearColorValue clearColor = { { 0.0f, 0.0f, 0.0f, 1.0f } };
1988 VkClearDepthStencilValue clearDS = { 1.0f, 0 };
1989 VkClearValue clearValues[3];
1990 memset(clearValues, 0,
sizeof(clearValues));
1991 clearValues[0].color = clearValues[2].color = clearColor;
1992 clearValues[1].depthStencil = clearDS;
1994 VkRenderPassBeginInfo rpBeginInfo;
1995 memset(&rpBeginInfo, 0,
sizeof(rpBeginInfo));
1996 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1997 rpBeginInfo.renderPass = defaultRenderPass;
1998 rpBeginInfo.framebuffer = image.fb;
1999 rpBeginInfo.renderArea.extent.width = swapChainImageSize.width();
2000 rpBeginInfo.renderArea.extent.height = swapChainImageSize.height();
2001 rpBeginInfo.clearValueCount = sampleCount > VK_SAMPLE_COUNT_1_BIT ? 3 : 2;
2002 rpBeginInfo.pClearValues = clearValues;
2003 devFuncs->vkCmdBeginRenderPass(frame.cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
2004 devFuncs->vkCmdEndRenderPass(frame.cmdBuf);
2010void QVulkanWindowPrivate::endFrame()
2014 FrameResources &frame(frameRes[currentFrame]);
2015 ImageResources &image(imageRes[currentImage]);
2017 if (gfxQueueFamilyIdx != presQueueFamilyIdx && !frameGrabbing) {
2020 VkImageMemoryBarrier presTrans;
2021 memset(&presTrans, 0,
sizeof(presTrans));
2022 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2023 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2024 presTrans.oldLayout = presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2025 presTrans.srcQueueFamilyIndex = gfxQueueFamilyIdx;
2026 presTrans.dstQueueFamilyIndex = presQueueFamilyIdx;
2027 presTrans.image = image.image;
2028 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2029 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2030 devFuncs->vkCmdPipelineBarrier(frame.cmdBuf,
2031 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2032 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2033 0, 0,
nullptr, 0,
nullptr,
2041 VkResult err = devFuncs->vkEndCommandBuffer(frame.cmdBuf);
2042 if (err != VK_SUCCESS) {
2043 if (!checkDeviceLost(err))
2044 qWarning(
"QVulkanWindow: Failed to end frame command buffer: %d", err);
2049 VkSubmitInfo submitInfo;
2050 memset(&submitInfo, 0,
sizeof(submitInfo));
2051 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2052 submitInfo.commandBufferCount = 1;
2053 submitInfo.pCommandBuffers = &frame.cmdBuf;
2054 if (frame.imageSemWaitable) {
2055 submitInfo.waitSemaphoreCount = 1;
2056 submitInfo.pWaitSemaphores = &frame.imageSem;
2058 if (!frameGrabbing) {
2059 submitInfo.signalSemaphoreCount = 1;
2060 submitInfo.pSignalSemaphores = &frame.drawSem;
2062 VkPipelineStageFlags psf = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2063 submitInfo.pWaitDstStageMask = &psf;
2065 Q_ASSERT(!frame.cmdFenceWaitable);
2067 err = devFuncs->vkQueueSubmit(gfxQueue, 1, &submitInfo, frame.cmdFence);
2068 if (err == VK_SUCCESS) {
2069 frame.imageSemWaitable =
false;
2070 frame.cmdFenceWaitable =
true;
2072 if (!checkDeviceLost(err))
2073 qWarning(
"QVulkanWindow: Failed to submit to graphics queue: %d", err);
2078 if (frameGrabbing) {
2079 finishBlockingReadback();
2080 frameGrabbing =
false;
2083 emit q->frameGrabbed(frameGrabTargetImage);
2087 if (gfxQueueFamilyIdx != presQueueFamilyIdx) {
2089 submitInfo.pWaitSemaphores = &frame.drawSem;
2090 submitInfo.pSignalSemaphores = &frame.presTransSem;
2091 submitInfo.pCommandBuffers = &image.presTransCmdBuf;
2092 err = devFuncs->vkQueueSubmit(presQueue, 1, &submitInfo, VK_NULL_HANDLE);
2093 if (err != VK_SUCCESS) {
2094 if (!checkDeviceLost(err))
2095 qWarning(
"QVulkanWindow: Failed to submit to present queue: %d", err);
2101 VkPresentInfoKHR presInfo;
2102 memset(&presInfo, 0,
sizeof(presInfo));
2103 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2104 presInfo.swapchainCount = 1;
2105 presInfo.pSwapchains = &swapChain;
2106 presInfo.pImageIndices = ¤tImage;
2107 presInfo.waitSemaphoreCount = 1;
2108 presInfo.pWaitSemaphores = gfxQueueFamilyIdx == presQueueFamilyIdx ? &frame.drawSem : &frame.presTransSem;
2112 inst->presentAboutToBeQueued(q);
2114 err = vkQueuePresentKHR(presQueue, &presInfo);
2115 if (err != VK_SUCCESS) {
2116 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2117 recreateSwapChain();
2120 }
else if (err != VK_SUBOPTIMAL_KHR) {
2121 if (!checkDeviceLost(err))
2122 qWarning(
"QVulkanWindow: Failed to present: %d", err);
2127 frame.imageAcquired =
false;
2129 inst->presentQueued(q);
2131 currentFrame = (currentFrame + 1) % frameLag;
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147void QVulkanWindow::frameReady()
2149 Q_ASSERT_X(QThread::isMainThread(),
2150 "QVulkanWindow",
"frameReady() can only be called from the GUI (main) thread");
2154 if (!d->framePending) {
2155 qWarning(
"QVulkanWindow: frameReady() called without a corresponding startNextFrame()");
2159 d->framePending =
false;
2164bool QVulkanWindowPrivate::checkDeviceLost(VkResult err)
2166 if (err == VK_ERROR_DEVICE_LOST) {
2167 qWarning(
"QVulkanWindow: Device lost");
2169 renderer->logicalDeviceLost();
2170 qCDebug(lcGuiVk,
"Releasing all resources due to device lost");
2173 qCDebug(lcGuiVk,
"Restarting");
2180void QVulkanWindowPrivate::addReadback()
2182 VkImageCreateInfo imageInfo;
2183 memset(&imageInfo, 0,
sizeof(imageInfo));
2184 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
2185 imageInfo.imageType = VK_IMAGE_TYPE_2D;
2186 imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
2187 imageInfo.extent.width = frameGrabTargetImage.width();
2188 imageInfo.extent.height = frameGrabTargetImage.height();
2189 imageInfo.extent.depth = 1;
2190 imageInfo.mipLevels = 1;
2191 imageInfo.arrayLayers = 1;
2192 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
2193 imageInfo.tiling = VK_IMAGE_TILING_LINEAR;
2194 imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2195 imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
2197 VkResult err = devFuncs->vkCreateImage(dev, &imageInfo,
nullptr, &frameGrabImage);
2198 if (err != VK_SUCCESS) {
2199 qWarning(
"QVulkanWindow: Failed to create image for readback: %d", err);
2203 VkMemoryRequirements memReq;
2204 devFuncs->vkGetImageMemoryRequirements(dev, frameGrabImage, &memReq);
2206 VkMemoryAllocateInfo allocInfo = {
2207 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
2213 err = devFuncs->vkAllocateMemory(dev, &allocInfo,
nullptr, &frameGrabImageMem);
2214 if (err != VK_SUCCESS) {
2215 qWarning(
"QVulkanWindow: Failed to allocate memory for readback image: %d", err);
2219 err = devFuncs->vkBindImageMemory(dev, frameGrabImage, frameGrabImageMem, 0);
2220 if (err != VK_SUCCESS) {
2221 qWarning(
"QVulkanWindow: Failed to bind readback image memory: %d", err);
2225 FrameResources &frame(frameRes[currentFrame]);
2226 ImageResources &image(imageRes[currentImage]);
2228 VkImageMemoryBarrier barrier;
2229 memset(&barrier, 0,
sizeof(barrier));
2230 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2231 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2232 barrier.subresourceRange.levelCount = barrier.subresourceRange.layerCount = 1;
2234 barrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2235 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2236 barrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
2237 barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2238 barrier.image = image.image;
2240 devFuncs->vkCmdPipelineBarrier(frame.cmdBuf,
2241 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2242 VK_PIPELINE_STAGE_TRANSFER_BIT,
2243 0, 0,
nullptr, 0,
nullptr,
2246 barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
2247 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2248 barrier.srcAccessMask = 0;
2249 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
2250 barrier.image = frameGrabImage;
2252 devFuncs->vkCmdPipelineBarrier(frame.cmdBuf,
2253 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2254 VK_PIPELINE_STAGE_TRANSFER_BIT,
2255 0, 0,
nullptr, 0,
nullptr,
2258 VkImageCopy copyInfo;
2259 memset(©Info, 0,
sizeof(copyInfo));
2260 copyInfo.srcSubresource.aspectMask = copyInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2261 copyInfo.srcSubresource.layerCount = copyInfo.dstSubresource.layerCount = 1;
2262 copyInfo.extent.width = frameGrabTargetImage.width();
2263 copyInfo.extent.height = frameGrabTargetImage.height();
2264 copyInfo.extent.depth = 1;
2266 devFuncs->vkCmdCopyImage(frame.cmdBuf, image.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2267 frameGrabImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Info);
2269 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2270 barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
2271 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
2272 barrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
2273 barrier.image = frameGrabImage;
2275 devFuncs->vkCmdPipelineBarrier(frame.cmdBuf,
2276 VK_PIPELINE_STAGE_TRANSFER_BIT,
2277 VK_PIPELINE_STAGE_HOST_BIT,
2278 0, 0,
nullptr, 0,
nullptr,
2282void QVulkanWindowPrivate::finishBlockingReadback()
2286 FrameResources &frame(frameRes[currentFrame]);
2287 if (frame.cmdFenceWaitable) {
2288 devFuncs->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
2289 devFuncs->vkResetFences(dev, 1, &frame.cmdFence);
2290 frame.cmdFenceWaitable =
false;
2293 VkImageSubresource subres = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 };
2294 VkSubresourceLayout layout;
2295 devFuncs->vkGetImageSubresourceLayout(dev, frameGrabImage, &subres, &layout);
2298 VkResult err = devFuncs->vkMapMemory(dev, frameGrabImageMem, layout.offset, layout.size, 0,
reinterpret_cast<
void **>(&p));
2299 if (err != VK_SUCCESS) {
2300 qWarning(
"QVulkanWindow: Failed to map readback image memory after transfer: %d", err);
2304 for (
int y = 0; y < frameGrabTargetImage.height(); ++y) {
2305 memcpy(frameGrabTargetImage.scanLine(y), p, frameGrabTargetImage.width() * 4);
2306 p += layout.rowPitch;
2309 devFuncs->vkUnmapMemory(dev, frameGrabImageMem);
2311 devFuncs->vkDestroyImage(dev, frameGrabImage,
nullptr);
2312 frameGrabImage = VK_NULL_HANDLE;
2313 devFuncs->vkFreeMemory(dev, frameGrabImageMem,
nullptr);
2314 frameGrabImageMem = VK_NULL_HANDLE;
2318
2319
2320
2321
2322
2323
2324VkPhysicalDevice QVulkanWindow::physicalDevice()
const
2326 Q_D(
const QVulkanWindow);
2327 if (d->physDevIndex < d->physDevs.size())
2328 return d->physDevs[d->physDevIndex];
2329 qWarning(
"QVulkanWindow: Physical device not available");
2330 return VK_NULL_HANDLE;
2334
2335
2336
2337
2338
2339
2340const VkPhysicalDeviceProperties *QVulkanWindow::physicalDeviceProperties()
const
2342 Q_D(
const QVulkanWindow);
2343 if (d->physDevIndex < d->physDevProps.size())
2344 return &d->physDevProps[d->physDevIndex];
2345 qWarning(
"QVulkanWindow: Physical device properties not available");
2350
2351
2352
2353
2354
2355
2356VkDevice QVulkanWindow::device()
const
2358 Q_D(
const QVulkanWindow);
2363
2364
2365
2366
2367
2368
2369VkQueue QVulkanWindow::graphicsQueue()
const
2371 Q_D(
const QVulkanWindow);
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386uint32_t QVulkanWindow::graphicsQueueFamilyIndex()
const
2388 Q_D(
const QVulkanWindow);
2389 return d->gfxQueueFamilyIdx;
2393
2394
2395
2396
2397
2398
2399VkCommandPool QVulkanWindow::graphicsCommandPool()
const
2401 Q_D(
const QVulkanWindow);
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415uint32_t QVulkanWindow::hostVisibleMemoryIndex()
const
2417 Q_D(
const QVulkanWindow);
2418 return d->hostVisibleMemIndex;
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433uint32_t QVulkanWindow::deviceLocalMemoryIndex()
const
2435 Q_D(
const QVulkanWindow);
2436 return d->deviceLocalMemIndex;
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457VkRenderPass QVulkanWindow::defaultRenderPass()
const
2459 Q_D(
const QVulkanWindow);
2460 return d->defaultRenderPass;
2464
2465
2466
2467
2468
2469
2470
2471
2472VkFormat QVulkanWindow::colorFormat()
const
2474 Q_D(
const QVulkanWindow);
2475 return d->colorFormat;
2479
2480
2481
2482
2483
2484
2485VkFormat QVulkanWindow::depthStencilFormat()
const
2487 Q_D(
const QVulkanWindow);
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514QSize QVulkanWindow::swapChainImageSize()
const
2516 Q_D(
const QVulkanWindow);
2517 return d->swapChainImageSize;
2521
2522
2523
2524
2525
2526
2527
2528VkCommandBuffer QVulkanWindow::currentCommandBuffer()
const
2530 Q_D(
const QVulkanWindow);
2531 if (!d->framePending) {
2532 qWarning(
"QVulkanWindow: Attempted to call currentCommandBuffer() without an active frame");
2533 return VK_NULL_HANDLE;
2535 return d->frameRes[d->currentFrame].cmdBuf;
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557VkFramebuffer QVulkanWindow::currentFramebuffer()
const
2559 Q_D(
const QVulkanWindow);
2560 if (!d->framePending) {
2561 qWarning(
"QVulkanWindow: Attempted to call currentFramebuffer() without an active frame");
2562 return VK_NULL_HANDLE;
2564 return d->imageRes[d->currentImage].fb;
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588int QVulkanWindow::currentFrame()
const
2590 Q_D(
const QVulkanWindow);
2591 if (!d->framePending)
2592 qWarning(
"QVulkanWindow: Attempted to call currentFrame() without an active frame");
2593 return d->currentFrame;
2597
2598
2599
2600
2601
2604
2605
2606
2607
2608
2609
2610
2611
2612int QVulkanWindow::concurrentFrameCount()
const
2614 Q_D(
const QVulkanWindow);
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629int QVulkanWindow::swapChainImageCount()
const
2631 Q_D(
const QVulkanWindow);
2632 return d->swapChainBufferCount;
2636
2637
2638
2639
2640
2641int QVulkanWindow::currentSwapChainImageIndex()
const
2643 Q_D(
const QVulkanWindow);
2644 if (!d->framePending)
2645 qWarning(
"QVulkanWindow: Attempted to call currentSwapChainImageIndex() without an active frame");
2646 return d->currentImage;
2650
2651
2652
2653
2654
2655
2656
2657
2658VkImage QVulkanWindow::swapChainImage(
int idx)
const
2660 Q_D(
const QVulkanWindow);
2661 return idx >= 0 && idx < d->swapChainBufferCount ? d->imageRes[idx].image : VK_NULL_HANDLE;
2665
2666
2667
2668
2669
2670
2671
2672
2673VkImageView QVulkanWindow::swapChainImageView(
int idx)
const
2675 Q_D(
const QVulkanWindow);
2676 return idx >= 0 && idx < d->swapChainBufferCount ? d->imageRes[idx].imageView : VK_NULL_HANDLE;
2680
2681
2682
2683
2684
2685
2686VkImage QVulkanWindow::depthStencilImage()
const
2688 Q_D(
const QVulkanWindow);
2693
2694
2695
2696
2697
2698
2699VkImageView QVulkanWindow::depthStencilImageView()
const
2701 Q_D(
const QVulkanWindow);
2706
2707
2708
2709
2710
2711
2712
2713VkSampleCountFlagBits QVulkanWindow::sampleCountFlagBits()
const
2715 Q_D(
const QVulkanWindow);
2716 return d->sampleCount;
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729VkImage QVulkanWindow::msaaColorImage(
int idx)
const
2731 Q_D(
const QVulkanWindow);
2732 return idx >= 0 && idx < d->swapChainBufferCount ? d->imageRes[idx].msaaImage : VK_NULL_HANDLE;
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745VkImageView QVulkanWindow::msaaColorImageView(
int idx)
const
2747 Q_D(
const QVulkanWindow);
2748 return idx >= 0 && idx < d->swapChainBufferCount ? d->imageRes[idx].msaaImageView : VK_NULL_HANDLE;
2752
2753
2754
2755
2756
2757
2758
2759bool QVulkanWindow::supportsGrab()
const
2761 Q_D(
const QVulkanWindow);
2762 return d->swapChainSupportsReadBack;
2766
2767
2768
2769
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796QImage QVulkanWindow::grab()
2799 if (!d->swapChain) {
2800 qWarning(
"QVulkanWindow: Attempted to call grab() without a swapchain");
2803 if (d->framePending) {
2804 qWarning(
"QVulkanWindow: Attempted to call grab() while a frame is still pending");
2807 if (!d->swapChainSupportsReadBack) {
2808 qWarning(
"QVulkanWindow: Attempted to call grab() with a swapchain that does not support usage as transfer source");
2812 d->frameGrabbing =
true;
2815 if (d->colorFormat == VK_FORMAT_B8G8R8A8_UNORM)
2816 d->frameGrabTargetImage = std::move(d->frameGrabTargetImage).rgbSwapped();
2818 return d->frameGrabTargetImage;
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832QMatrix4x4 QVulkanWindow::clipCorrectionMatrix()
2835 if (d->m_clipCorrect.isIdentity()) {
2837 d->m_clipCorrect = QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
2838 0.0f, -1.0f, 0.0f, 0.0f,
2839 0.0f, 0.0f, 0.5f, 0.5f,
2840 0.0f, 0.0f, 0.0f, 1.0f);
2842 return d->m_clipCorrect;
2847#include "moc_qvulkanwindow.cpp"
Combined button and popup list for selecting options.
VkSampleCountFlagBits mask
static VkDeviceSize aligned(VkDeviceSize v, VkDeviceSize byteAlign)