5#include "qvulkanfunctions.h"
6#include <QLoggingCategory>
9#include <QCoreApplication>
214QVulkanWindow::QVulkanWindow(
QWindow *parent)
215 :
QWindow(*(new QVulkanWindowPrivate), parent)
223QVulkanWindow::~QVulkanWindow()
227QVulkanWindowPrivate::~QVulkanWindowPrivate()
255 if (
d->status != QVulkanWindowPrivate::StatusUninitialized) {
256 qWarning(
"QVulkanWindow: Attempted to set flags when already initialized");
265QVulkanWindow::Flags QVulkanWindow::flags()
const
276QList<VkPhysicalDeviceProperties> QVulkanWindow::availablePhysicalDevices()
279 if (!
d->physDevs.isEmpty() && !
d->physDevProps.isEmpty())
280 return d->physDevProps;
284 qWarning(
"QVulkanWindow: Attempted to call availablePhysicalDevices() without a QVulkanInstance");
285 return d->physDevProps;
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;
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;
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;
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);
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) {
376 ext.name = prop.extensionName;
377 ext.version = prop.specVersion;
380 d->supportedDevExtensions.insert(physDev, exts);
381 qDebug(lcGuiVk) <<
"Supported device extensions:" << exts;
386 qWarning(
"QVulkanWindow: Failed to query device extension count: %d", err);
387 return QVulkanInfoVector<QVulkanExtension>();
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;
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");
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 }
473QList<int> QVulkanWindow::supportedSampleCounts()
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;
491 if ((
color & qvk_sampleCount.mask)
492 && (
depth & qvk_sampleCount.mask)
493 && (
stencil & qvk_sampleCount.mask))
495 result.append(qvk_sampleCount.count);
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);
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;
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);
593 VkPhysicalDevice physDev = physDevs.at(physDevIndex);
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");
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();
680 reqExts.append(
"VK_KHR_swapchain");
683 if (!envExts.isEmpty()) {
685 for (
auto ext : reqExts)
686 envExtList.removeAll(ext);
687 reqExts.append(envExtList);
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)
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");
759 physDevProps.clear();
760 status = StatusUninitialized;
761 qCDebug(lcGuiVk,
"Attempting to restart in 2 seconds");
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());
854 colorSpace = VkColorSpaceKHR(0);
857 if (!
formats.isEmpty() &&
formats[0].format != VK_FORMAT_UNDEFINED) {
859 colorSpace =
formats[0].colorSpace;
863 if (!
formats.isEmpty() && !requestedColorFormats.isEmpty()) {
864 for (VkFormat reqFmt :
std::as_const(requestedColorFormats)) {
866 [reqFmt](
const VkSurfaceFormatKHR &sfmt) { return sfmt.format == reqFmt; });
869 colorSpace =
r->colorSpace;
875 const VkFormat dsFormatCandidates[] = {
876 VK_FORMAT_D24_UNORM_S8_UINT,
877 VK_FORMAT_D32_SFLOAT_S8_UINT,
878 VK_FORMAT_D16_UNORM_S8_UINT
880 const int dsFormatCandidateCount =
sizeof(dsFormatCandidates) /
sizeof(VkFormat);
882 while (dsFormatIdx < dsFormatCandidateCount) {
883 dsFormat = dsFormatCandidates[dsFormatIdx];
884 VkFormatProperties fmtProp;
885 f->vkGetPhysicalDeviceFormatProperties(physDev, dsFormat, &fmtProp);
886 if (fmtProp.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
890 if (dsFormatIdx == dsFormatCandidateCount)
891 qWarning(
"QVulkanWindow: Failed to find an optimal depth-stencil format");
895 if (!createDefaultRenderPass())
901 status = StatusDeviceReady;
904void QVulkanWindowPrivate::reset()
909 qCDebug(lcGuiVk,
"QVulkanWindow reset");
911 devFuncs->vkDeviceWaitIdle(dev);
915 devFuncs->vkDeviceWaitIdle(dev);
918 if (defaultRenderPass) {
919 devFuncs->vkDestroyRenderPass(dev, defaultRenderPass,
nullptr);
920 defaultRenderPass = VK_NULL_HANDLE;
924 devFuncs->vkDestroyCommandPool(dev, cmdPool,
nullptr);
925 cmdPool = VK_NULL_HANDLE;
929 devFuncs->vkDestroyCommandPool(dev, presCmdPool,
nullptr);
930 presCmdPool = VK_NULL_HANDLE;
933 if (frameGrabImage) {
934 devFuncs->vkDestroyImage(dev, frameGrabImage,
nullptr);
935 frameGrabImage = VK_NULL_HANDLE;
938 if (frameGrabImageMem) {
939 devFuncs->vkFreeMemory(dev, frameGrabImageMem,
nullptr);
940 frameGrabImageMem = VK_NULL_HANDLE;
944 devFuncs->vkDestroyDevice(dev,
nullptr);
945 inst->resetDeviceFunctions(dev);
946 dev = VK_NULL_HANDLE;
947 vkCreateSwapchainKHR =
nullptr;
950 surface = VK_NULL_HANDLE;
952 status = StatusUninitialized;
955bool QVulkanWindowPrivate::createDefaultRenderPass()
957 VkAttachmentDescription attDesc[3];
958 memset(attDesc, 0,
sizeof(attDesc));
960 const bool msaa = sampleCount > VK_SAMPLE_COUNT_1_BIT;
964 attDesc[0].samples = VK_SAMPLE_COUNT_1_BIT;
965 attDesc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
966 attDesc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
967 attDesc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
968 attDesc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
969 attDesc[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
970 attDesc[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
972 attDesc[1].format = dsFormat;
973 attDesc[1].samples = sampleCount;
974 attDesc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
975 attDesc[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
976 attDesc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
977 attDesc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
978 attDesc[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
979 attDesc[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
984 attDesc[2].samples = sampleCount;
985 attDesc[2].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
986 attDesc[2].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
987 attDesc[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
988 attDesc[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
989 attDesc[2].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
990 attDesc[2].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
993 VkAttachmentReference colorRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
994 VkAttachmentReference resolveRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
995 VkAttachmentReference dsRef = { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
997 VkSubpassDescription subPassDesc;
998 memset(&subPassDesc, 0,
sizeof(subPassDesc));
999 subPassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1000 subPassDesc.colorAttachmentCount = 1;
1001 subPassDesc.pColorAttachments = &colorRef;
1002 subPassDesc.pDepthStencilAttachment = &dsRef;
1004 VkRenderPassCreateInfo rpInfo;
1005 memset(&rpInfo, 0,
sizeof(rpInfo));
1006 rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1007 rpInfo.attachmentCount = 2;
1008 rpInfo.pAttachments = attDesc;
1009 rpInfo.subpassCount = 1;
1010 rpInfo.pSubpasses = &subPassDesc;
1013 colorRef.attachment = 2;
1014 subPassDesc.pResolveAttachments = &resolveRef;
1015 rpInfo.attachmentCount = 3;
1018 VkResult err = devFuncs->vkCreateRenderPass(dev, &rpInfo,
nullptr, &defaultRenderPass);
1019 if (err != VK_SUCCESS) {
1020 qWarning(
"QVulkanWindow: Failed to create renderpass: %d", err);
1027void QVulkanWindowPrivate::recreateSwapChain()
1030 Q_ASSERT(status >= StatusDeviceReady);
1032 swapChainImageSize =
q->size() *
q->devicePixelRatio();
1034 if (swapChainImageSize.isEmpty())
1039 devFuncs->vkDeviceWaitIdle(dev);
1041 if (!vkCreateSwapchainKHR) {
1042 vkCreateSwapchainKHR =
reinterpret_cast<PFN_vkCreateSwapchainKHR
>(
f->vkGetDeviceProcAddr(dev,
"vkCreateSwapchainKHR"));
1043 vkDestroySwapchainKHR =
reinterpret_cast<PFN_vkDestroySwapchainKHR
>(
f->vkGetDeviceProcAddr(dev,
"vkDestroySwapchainKHR"));
1044 vkGetSwapchainImagesKHR =
reinterpret_cast<PFN_vkGetSwapchainImagesKHR
>(
f->vkGetDeviceProcAddr(dev,
"vkGetSwapchainImagesKHR"));
1045 vkAcquireNextImageKHR =
reinterpret_cast<PFN_vkAcquireNextImageKHR
>(
f->vkGetDeviceProcAddr(dev,
"vkAcquireNextImageKHR"));
1046 vkQueuePresentKHR =
reinterpret_cast<PFN_vkQueuePresentKHR
>(
f->vkGetDeviceProcAddr(dev,
"vkQueuePresentKHR"));
1049 VkPhysicalDevice physDev = physDevs.at(physDevIndex);
1050 VkSurfaceCapabilitiesKHR surfaceCaps;
1051 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDev, surface, &surfaceCaps);
1052 uint32_t reqBufferCount;
1053 if (surfaceCaps.maxImageCount == 0)
1054 reqBufferCount = qMax<uint32_t>(2, surfaceCaps.minImageCount);
1056 reqBufferCount =
qMax(qMin<uint32_t>(surfaceCaps.maxImageCount, 3), surfaceCaps.minImageCount);
1058 VkExtent2D bufferSize = surfaceCaps.currentExtent;
1059 if (bufferSize.width == uint32_t(-1)) {
1060 Q_ASSERT(bufferSize.height == uint32_t(-1));
1061 bufferSize.width = swapChainImageSize.width();
1062 bufferSize.height = swapChainImageSize.height();
1064 swapChainImageSize =
QSize(bufferSize.width, bufferSize.height);
1067 VkSurfaceTransformFlagBitsKHR preTransform =
1068 (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
1069 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
1070 : surfaceCaps.currentTransform;
1072 VkCompositeAlphaFlagBitsKHR compositeAlpha =
1073 (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
1074 ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
1075 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
1077 if (
q->requestedFormat().hasAlpha()) {
1078 if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
1079 compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
1080 else if (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
1081 compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
1084 VkImageUsageFlags
usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1085 swapChainSupportsReadBack = (surfaceCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1086 if (swapChainSupportsReadBack)
1087 usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1089 VkSwapchainKHR oldSwapChain = swapChain;
1090 VkSwapchainCreateInfoKHR swapChainInfo;
1091 memset(&swapChainInfo, 0,
sizeof(swapChainInfo));
1092 swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
1093 swapChainInfo.surface = surface;
1094 swapChainInfo.minImageCount = reqBufferCount;
1096 swapChainInfo.imageColorSpace = colorSpace;
1097 swapChainInfo.imageExtent = bufferSize;
1098 swapChainInfo.imageArrayLayers = 1;
1099 swapChainInfo.imageUsage =
usage;
1100 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
1101 swapChainInfo.preTransform = preTransform;
1102 swapChainInfo.compositeAlpha = compositeAlpha;
1103 swapChainInfo.presentMode = presentMode;
1104 swapChainInfo.clipped =
true;
1105 swapChainInfo.oldSwapchain = oldSwapChain;
1107 qCDebug(lcGuiVk,
"Creating new swap chain of %d buffers, size %dx%d", reqBufferCount, bufferSize.width, bufferSize.height);
1109 VkSwapchainKHR newSwapChain;
1110 VkResult err = vkCreateSwapchainKHR(dev, &swapChainInfo,
nullptr, &newSwapChain);
1111 if (err != VK_SUCCESS) {
1112 qWarning(
"QVulkanWindow: Failed to create swap chain: %d", err);
1119 swapChain = newSwapChain;
1121 uint32_t actualSwapChainBufferCount = 0;
1122 err = vkGetSwapchainImagesKHR(dev, swapChain, &actualSwapChainBufferCount,
nullptr);
1123 if (err != VK_SUCCESS || actualSwapChainBufferCount < 2) {
1124 qWarning(
"QVulkanWindow: Failed to get swapchain images: %d (count=%d)", err, actualSwapChainBufferCount);
1128 qCDebug(lcGuiVk,
"Actual swap chain buffer count: %d (supportsReadback=%d)",
1129 actualSwapChainBufferCount, swapChainSupportsReadBack);
1130 if (actualSwapChainBufferCount > MAX_SWAPCHAIN_BUFFER_COUNT) {
1131 qWarning(
"QVulkanWindow: Too many swapchain buffers (%d)", actualSwapChainBufferCount);
1134 swapChainBufferCount = actualSwapChainBufferCount;
1136 VkImage swapChainImages[MAX_SWAPCHAIN_BUFFER_COUNT];
1137 err = vkGetSwapchainImagesKHR(dev, swapChain, &actualSwapChainBufferCount, swapChainImages);
1138 if (err != VK_SUCCESS) {
1139 qWarning(
"QVulkanWindow: Failed to get swapchain images: %d", err);
1143 if (!createTransientImage(dsFormat,
1144 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
1145 VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
1154 const bool msaa = sampleCount > VK_SAMPLE_COUNT_1_BIT;
1155 VkImage msaaImages[MAX_SWAPCHAIN_BUFFER_COUNT];
1156 VkImageView msaaViews[MAX_SWAPCHAIN_BUFFER_COUNT];
1160 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1161 VK_IMAGE_ASPECT_COLOR_BIT,
1165 swapChainBufferCount))
1171 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
nullptr, VK_FENCE_CREATE_SIGNALED_BIT };
1173 for (
int i = 0;
i < swapChainBufferCount; ++
i) {
1174 ImageResources &
image(imageRes[
i]);
1175 image.image = swapChainImages[
i];
1178 image.msaaImage = msaaImages[
i];
1179 image.msaaImageView = msaaViews[
i];
1182 VkImageViewCreateInfo imgViewInfo;
1183 memset(&imgViewInfo, 0,
sizeof(imgViewInfo));
1184 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1185 imgViewInfo.image = swapChainImages[
i];
1186 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1188 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1189 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1190 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1191 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1192 imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1193 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1194 err = devFuncs->vkCreateImageView(dev, &imgViewInfo,
nullptr, &
image.imageView);
1195 if (err != VK_SUCCESS) {
1196 qWarning(
"QVulkanWindow: Failed to create swapchain image view %d: %d",
i, err);
1200 err = devFuncs->vkCreateFence(dev, &fenceInfo,
nullptr, &
image.cmdFence);
1201 if (err != VK_SUCCESS) {
1202 qWarning(
"QVulkanWindow: Failed to create command buffer fence: %d", err);
1205 image.cmdFenceWaitable =
true;
1207 VkImageView views[3] = {
image.imageView,
1209 msaa ?
image.msaaImageView : VK_NULL_HANDLE };
1210 VkFramebufferCreateInfo fbInfo;
1211 memset(&fbInfo, 0,
sizeof(fbInfo));
1212 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
1213 fbInfo.renderPass = defaultRenderPass;
1214 fbInfo.attachmentCount = msaa ? 3 : 2;
1215 fbInfo.pAttachments = views;
1216 fbInfo.width = swapChainImageSize.width();
1217 fbInfo.height = swapChainImageSize.height();
1219 VkResult err = devFuncs->vkCreateFramebuffer(dev, &fbInfo,
nullptr, &
image.fb);
1220 if (err != VK_SUCCESS) {
1221 qWarning(
"QVulkanWindow: Failed to create framebuffer: %d", err);
1225 if (gfxQueueFamilyIdx != presQueueFamilyIdx) {
1228 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
nullptr, presCmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1 };
1229 err = devFuncs->vkAllocateCommandBuffers(dev, &cmdBufInfo, &
image.presTransCmdBuf);
1230 if (err != VK_SUCCESS) {
1231 qWarning(
"QVulkanWindow: Failed to allocate acquire-on-present-queue command buffer: %d", err);
1234 VkCommandBufferBeginInfo cmdBufBeginInfo = {
1235 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
nullptr,
1236 VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
nullptr };
1237 err = devFuncs->vkBeginCommandBuffer(
image.presTransCmdBuf, &cmdBufBeginInfo);
1238 if (err != VK_SUCCESS) {
1239 qWarning(
"QVulkanWindow: Failed to begin acquire-on-present-queue command buffer: %d", err);
1242 VkImageMemoryBarrier presTrans;
1243 memset(&presTrans, 0,
sizeof(presTrans));
1244 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1245 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1246 presTrans.oldLayout = presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1247 presTrans.srcQueueFamilyIndex = gfxQueueFamilyIdx;
1248 presTrans.dstQueueFamilyIndex = presQueueFamilyIdx;
1249 presTrans.image =
image.image;
1250 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1251 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
1252 devFuncs->vkCmdPipelineBarrier(
image.presTransCmdBuf,
1253 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1254 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1255 0, 0,
nullptr, 0,
nullptr,
1257 err = devFuncs->vkEndCommandBuffer(
image.presTransCmdBuf);
1258 if (err != VK_SUCCESS) {
1259 qWarning(
"QVulkanWindow: Failed to end acquire-on-present-queue command buffer: %d", err);
1267 VkSemaphoreCreateInfo semInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
nullptr, 0 };
1268 for (
int i = 0;
i < frameLag; ++
i) {
1269 FrameResources &
frame(frameRes[
i]);
1271 frame.imageAcquired =
false;
1272 frame.imageSemWaitable =
false;
1274 devFuncs->vkCreateFence(dev, &fenceInfo,
nullptr, &
frame.fence);
1275 frame.fenceWaitable =
true;
1277 devFuncs->vkCreateSemaphore(dev, &semInfo,
nullptr, &
frame.imageSem);
1278 devFuncs->vkCreateSemaphore(dev, &semInfo,
nullptr, &
frame.drawSem);
1279 if (gfxQueueFamilyIdx != presQueueFamilyIdx)
1280 devFuncs->vkCreateSemaphore(dev, &semInfo,
nullptr, &
frame.presTransSem);
1286 renderer->initSwapChainResources();
1288 status = StatusReady;
1291uint32_t QVulkanWindowPrivate::chooseTransientImageMemType(VkImage
img, uint32_t startIndex)
1293 VkPhysicalDeviceMemoryProperties physDevMemProps;
1294 inst->functions()->vkGetPhysicalDeviceMemoryProperties(physDevs[physDevIndex], &physDevMemProps);
1296 VkMemoryRequirements memReq;
1297 devFuncs->vkGetImageMemoryRequirements(dev,
img, &memReq);
1298 uint32_t memTypeIndex = uint32_t(-1);
1300 if (memReq.memoryTypeBits) {
1302 const VkMemoryType *memType = physDevMemProps.memoryTypes;
1303 bool foundDevLocal =
false;
1304 for (uint32_t
i = startIndex;
i < physDevMemProps.memoryTypeCount; ++
i) {
1305 if (memReq.memoryTypeBits & (1 <<
i)) {
1306 if (memType[
i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
1307 if (!foundDevLocal) {
1308 foundDevLocal =
true;
1311 if (memType[
i].propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
1320 return memTypeIndex;
1323static inline VkDeviceSize
aligned(VkDeviceSize
v, VkDeviceSize byteAlign)
1325 return (
v + byteAlign - 1) & ~(byteAlign - 1);
1328bool QVulkanWindowPrivate::createTransientImage(VkFormat
format,
1329 VkImageUsageFlags
usage,
1330 VkImageAspectFlags aspectMask,
1332 VkDeviceMemory *mem,
1336 VkMemoryRequirements memReq;
1341 VkImageCreateInfo imgInfo;
1342 memset(&imgInfo, 0,
sizeof(imgInfo));
1343 imgInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1344 imgInfo.imageType = VK_IMAGE_TYPE_2D;
1346 imgInfo.extent.width = swapChainImageSize.width();
1347 imgInfo.extent.height = swapChainImageSize.height();
1348 imgInfo.extent.depth = 1;
1349 imgInfo.mipLevels = imgInfo.arrayLayers = 1;
1350 imgInfo.samples = sampleCount;
1351 imgInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1352 imgInfo.usage =
usage | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
1354 err = devFuncs->vkCreateImage(dev, &imgInfo,
nullptr,
images +
i);
1355 if (err != VK_SUCCESS) {
1356 qWarning(
"QVulkanWindow: Failed to create image: %d", err);
1363 devFuncs->vkGetImageMemoryRequirements(dev,
images[
i], &memReq);
1366 VkMemoryAllocateInfo memInfo;
1367 memset(&memInfo, 0,
sizeof(memInfo));
1368 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1369 memInfo.allocationSize =
aligned(memReq.size, memReq.alignment) *
count;
1371 uint32_t startIndex = 0;
1373 memInfo.memoryTypeIndex = chooseTransientImageMemType(
images[0], startIndex);
1374 if (memInfo.memoryTypeIndex == uint32_t(-1)) {
1375 qWarning(
"QVulkanWindow: No suitable memory type found");
1378 startIndex = memInfo.memoryTypeIndex + 1;
1379 qCDebug(lcGuiVk,
"Allocating %u bytes for transient image (memtype %u)",
1380 uint32_t(memInfo.allocationSize), memInfo.memoryTypeIndex);
1381 err = devFuncs->vkAllocateMemory(dev, &memInfo,
nullptr, mem);
1382 if (err != VK_SUCCESS && err != VK_ERROR_OUT_OF_DEVICE_MEMORY) {
1383 qWarning(
"QVulkanWindow: Failed to allocate image memory: %d", err);
1386 }
while (err != VK_SUCCESS);
1388 VkDeviceSize ofs = 0;
1390 err = devFuncs->vkBindImageMemory(dev,
images[
i], *mem, ofs);
1391 if (err != VK_SUCCESS) {
1392 qWarning(
"QVulkanWindow: Failed to bind image memory: %d", err);
1395 ofs +=
aligned(memReq.size, memReq.alignment);
1397 VkImageViewCreateInfo imgViewInfo;
1398 memset(&imgViewInfo, 0,
sizeof(imgViewInfo));
1399 imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1400 imgViewInfo.image =
images[
i];
1401 imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1402 imgViewInfo.format =
format;
1403 imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
1404 imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
1405 imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
1406 imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
1407 imgViewInfo.subresourceRange.aspectMask = aspectMask;
1408 imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
1410 err = devFuncs->vkCreateImageView(dev, &imgViewInfo,
nullptr, views +
i);
1411 if (err != VK_SUCCESS) {
1412 qWarning(
"QVulkanWindow: Failed to create image view: %d", err);
1420void QVulkanWindowPrivate::releaseSwapChain()
1422 if (!dev || !swapChain)
1425 qCDebug(lcGuiVk,
"Releasing swapchain");
1427 devFuncs->vkDeviceWaitIdle(dev);
1430 renderer->releaseSwapChainResources();
1431 devFuncs->vkDeviceWaitIdle(dev);
1434 for (
int i = 0;
i < frameLag; ++
i) {
1435 FrameResources &
frame(frameRes[
i]);
1437 if (
frame.fenceWaitable)
1438 devFuncs->vkWaitForFences(dev, 1, &
frame.fence, VK_TRUE, UINT64_MAX);
1439 devFuncs->vkDestroyFence(dev,
frame.fence,
nullptr);
1440 frame.fence = VK_NULL_HANDLE;
1441 frame.fenceWaitable =
false;
1443 if (
frame.imageSem) {
1444 devFuncs->vkDestroySemaphore(dev,
frame.imageSem,
nullptr);
1445 frame.imageSem = VK_NULL_HANDLE;
1447 if (
frame.drawSem) {
1448 devFuncs->vkDestroySemaphore(dev,
frame.drawSem,
nullptr);
1449 frame.drawSem = VK_NULL_HANDLE;
1451 if (
frame.presTransSem) {
1452 devFuncs->vkDestroySemaphore(dev,
frame.presTransSem,
nullptr);
1453 frame.presTransSem = VK_NULL_HANDLE;
1457 for (
int i = 0;
i < swapChainBufferCount; ++
i) {
1458 ImageResources &
image(imageRes[
i]);
1459 if (
image.cmdFence) {
1460 if (
image.cmdFenceWaitable)
1461 devFuncs->vkWaitForFences(dev, 1, &
image.cmdFence, VK_TRUE, UINT64_MAX);
1462 devFuncs->vkDestroyFence(dev,
image.cmdFence,
nullptr);
1463 image.cmdFence = VK_NULL_HANDLE;
1464 image.cmdFenceWaitable =
false;
1467 devFuncs->vkDestroyFramebuffer(dev,
image.fb,
nullptr);
1468 image.fb = VK_NULL_HANDLE;
1470 if (
image.imageView) {
1471 devFuncs->vkDestroyImageView(dev,
image.imageView,
nullptr);
1472 image.imageView = VK_NULL_HANDLE;
1475 devFuncs->vkFreeCommandBuffers(dev, cmdPool, 1, &
image.cmdBuf);
1476 image.cmdBuf = VK_NULL_HANDLE;
1478 if (
image.presTransCmdBuf) {
1479 devFuncs->vkFreeCommandBuffers(dev, presCmdPool, 1, &
image.presTransCmdBuf);
1480 image.presTransCmdBuf = VK_NULL_HANDLE;
1482 if (
image.msaaImageView) {
1483 devFuncs->vkDestroyImageView(dev,
image.msaaImageView,
nullptr);
1484 image.msaaImageView = VK_NULL_HANDLE;
1486 if (
image.msaaImage) {
1487 devFuncs->vkDestroyImage(dev,
image.msaaImage,
nullptr);
1488 image.msaaImage = VK_NULL_HANDLE;
1493 devFuncs->vkFreeMemory(dev, msaaImageMem,
nullptr);
1494 msaaImageMem = VK_NULL_HANDLE;
1498 devFuncs->vkDestroyImageView(dev, dsView,
nullptr);
1499 dsView = VK_NULL_HANDLE;
1502 devFuncs->vkDestroyImage(dev, dsImage,
nullptr);
1503 dsImage = VK_NULL_HANDLE;
1506 devFuncs->vkFreeMemory(dev, dsMem,
nullptr);
1507 dsMem = VK_NULL_HANDLE;
1511 vkDestroySwapchainKHR(dev, swapChain,
nullptr);
1512 swapChain = VK_NULL_HANDLE;
1515 if (status == StatusReady)
1516 status = StatusDeviceReady;
1529 if (!
d->flags.testFlag(PersistentResources)) {
1530 d->releaseSwapChain();
1536void QVulkanWindowPrivate::ensureStarted()
1539 if (status == QVulkanWindowPrivate::StatusFailRetry)
1540 status = QVulkanWindowPrivate::StatusUninitialized;
1541 if (status == QVulkanWindowPrivate::StatusUninitialized) {
1543 if (status == QVulkanWindowPrivate::StatusDeviceReady)
1544 recreateSwapChain();
1546 if (status == QVulkanWindowPrivate::StatusReady)
1561bool QVulkanWindow::event(
QEvent *e)
1565 switch (e->
type()) {
1576 d->releaseSwapChain();
1614void QVulkanWindow::setQueueCreateInfoModifier(
const QueueCreateInfoModifier &modifier)
1617 d->queueCreateInfoModifier = modifier;
1654void QVulkanWindow::setEnabledFeaturesModifier(
const EnabledFeaturesModifier &modifier)
1657 d->enabledFeaturesModifier = modifier;
1693void QVulkanWindow::setEnabledFeaturesModifier(EnabledFeatures2Modifier modifier)
1696 d->enabledFeatures2Modifier = std::move(modifier);
1706bool QVulkanWindow::isValid()
const
1709 return d->status == QVulkanWindowPrivate::StatusReady;
1731QVulkanWindowRenderer::~QVulkanWindowRenderer()
1751void QVulkanWindowRenderer::preInitResources()
1770void QVulkanWindowRenderer::initResources()
1792void QVulkanWindowRenderer::initSwapChainResources()
1815void QVulkanWindowRenderer::releaseSwapChainResources()
1831void QVulkanWindowRenderer::releaseResources()
1876void QVulkanWindowRenderer::physicalDeviceLost()
1895void QVulkanWindowRenderer::logicalDeviceLost()
1899QSize QVulkanWindowPrivate::surfacePixelSize()
const
1902 VkSurfaceCapabilitiesKHR surfaceCaps = {};
1903 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDevs.at(physDevIndex), surface, &surfaceCaps);
1904 VkExtent2D bufferSize = surfaceCaps.currentExtent;
1905 if (bufferSize.width == uint32_t(-1)) {
1906 Q_ASSERT(bufferSize.height == uint32_t(-1));
1907 return q->size() *
q->devicePixelRatio();
1909 return QSize(
int(bufferSize.width),
int(bufferSize.height));
1912void QVulkanWindowPrivate::beginFrame()
1914 if (!swapChain || framePending)
1918 if (swapChainImageSize != surfacePixelSize()) {
1919 recreateSwapChain();
1924 FrameResources &
frame(frameRes[currentFrame]);
1926 if (!
frame.imageAcquired) {
1929 if (
frame.fenceWaitable) {
1930 devFuncs->vkWaitForFences(dev, 1, &
frame.fence, VK_TRUE, UINT64_MAX);
1931 devFuncs->vkResetFences(dev, 1, &
frame.fence);
1932 frame.fenceWaitable =
false;
1936 VkResult err = vkAcquireNextImageKHR(dev, swapChain, UINT64_MAX,
1938 if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) {
1939 frame.imageSemWaitable =
true;
1940 frame.imageAcquired =
true;
1941 frame.fenceWaitable =
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);
1955 ImageResources &
image(imageRes[currentImage]);
1956 if (
image.cmdFenceWaitable) {
1957 devFuncs->vkWaitForFences(dev, 1, &
image.cmdFence, VK_TRUE, UINT64_MAX);
1958 devFuncs->vkResetFences(dev, 1, &
image.cmdFence);
1959 image.cmdFenceWaitable =
false;
1964 devFuncs->vkFreeCommandBuffers(dev, cmdPool, 1, &
image.cmdBuf);
1965 image.cmdBuf =
nullptr;
1969 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
nullptr, cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1 };
1970 VkResult err = devFuncs->vkAllocateCommandBuffers(dev, &cmdBufInfo, &
image.cmdBuf);
1971 if (err != VK_SUCCESS) {
1972 if (!checkDeviceLost(err))
1973 qWarning(
"QVulkanWindow: Failed to allocate frame command buffer: %d", err);
1977 VkCommandBufferBeginInfo cmdBufBeginInfo = {
1978 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
nullptr, 0,
nullptr };
1979 err = devFuncs->vkBeginCommandBuffer(
image.cmdBuf, &cmdBufBeginInfo);
1980 if (err != VK_SUCCESS) {
1981 if (!checkDeviceLost(err))
1982 qWarning(
"QVulkanWindow: Failed to begin frame command buffer: %d", err);
1990 framePending =
true;
1994 VkClearColorValue clearColor = { { 0.0f, 0.0f, 0.0f, 1.0f } };
1995 VkClearDepthStencilValue clearDS = { 1.0f, 0 };
1996 VkClearValue clearValues[3];
1997 memset(clearValues, 0,
sizeof(clearValues));
1998 clearValues[0].color = clearValues[2].color = clearColor;
1999 clearValues[1].depthStencil = clearDS;
2001 VkRenderPassBeginInfo rpBeginInfo;
2002 memset(&rpBeginInfo, 0,
sizeof(rpBeginInfo));
2003 rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
2004 rpBeginInfo.renderPass = defaultRenderPass;
2005 rpBeginInfo.framebuffer =
image.fb;
2006 rpBeginInfo.renderArea.extent.width = swapChainImageSize.width();
2007 rpBeginInfo.renderArea.extent.height = swapChainImageSize.height();
2008 rpBeginInfo.clearValueCount = sampleCount > VK_SAMPLE_COUNT_1_BIT ? 3 : 2;
2009 rpBeginInfo.pClearValues = clearValues;
2010 devFuncs->vkCmdBeginRenderPass(
image.cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
2011 devFuncs->vkCmdEndRenderPass(
image.cmdBuf);
2017void QVulkanWindowPrivate::endFrame()
2021 FrameResources &
frame(frameRes[currentFrame]);
2022 ImageResources &
image(imageRes[currentImage]);
2024 if (gfxQueueFamilyIdx != presQueueFamilyIdx && !frameGrabbing) {
2027 VkImageMemoryBarrier presTrans;
2028 memset(&presTrans, 0,
sizeof(presTrans));
2029 presTrans.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2030 presTrans.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2031 presTrans.oldLayout = presTrans.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2032 presTrans.srcQueueFamilyIndex = gfxQueueFamilyIdx;
2033 presTrans.dstQueueFamilyIndex = presQueueFamilyIdx;
2034 presTrans.image =
image.image;
2035 presTrans.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2036 presTrans.subresourceRange.levelCount = presTrans.subresourceRange.layerCount = 1;
2037 devFuncs->vkCmdPipelineBarrier(
image.cmdBuf,
2038 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2039 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
2040 0, 0,
nullptr, 0,
nullptr,
2048 VkResult err = devFuncs->vkEndCommandBuffer(
image.cmdBuf);
2049 if (err != VK_SUCCESS) {
2050 if (!checkDeviceLost(err))
2051 qWarning(
"QVulkanWindow: Failed to end frame command buffer: %d", err);
2056 VkSubmitInfo submitInfo;
2057 memset(&submitInfo, 0,
sizeof(submitInfo));
2058 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
2059 submitInfo.commandBufferCount = 1;
2060 submitInfo.pCommandBuffers = &
image.cmdBuf;
2061 if (
frame.imageSemWaitable) {
2062 submitInfo.waitSemaphoreCount = 1;
2063 submitInfo.pWaitSemaphores = &
frame.imageSem;
2065 if (!frameGrabbing) {
2066 submitInfo.signalSemaphoreCount = 1;
2067 submitInfo.pSignalSemaphores = &
frame.drawSem;
2069 VkPipelineStageFlags psf = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2070 submitInfo.pWaitDstStageMask = &psf;
2074 err = devFuncs->vkQueueSubmit(gfxQueue, 1, &submitInfo,
image.cmdFence);
2075 if (err == VK_SUCCESS) {
2076 frame.imageSemWaitable =
false;
2077 image.cmdFenceWaitable =
true;
2079 if (!checkDeviceLost(err))
2080 qWarning(
"QVulkanWindow: Failed to submit to graphics queue: %d", err);
2085 if (frameGrabbing) {
2086 finishBlockingReadback();
2087 frameGrabbing =
false;
2090 emit q->frameGrabbed(frameGrabTargetImage);
2094 if (gfxQueueFamilyIdx != presQueueFamilyIdx) {
2096 submitInfo.pWaitSemaphores = &
frame.drawSem;
2097 submitInfo.pSignalSemaphores = &
frame.presTransSem;
2098 submitInfo.pCommandBuffers = &
image.presTransCmdBuf;
2099 err = devFuncs->vkQueueSubmit(presQueue, 1, &submitInfo, VK_NULL_HANDLE);
2100 if (err != VK_SUCCESS) {
2101 if (!checkDeviceLost(err))
2102 qWarning(
"QVulkanWindow: Failed to submit to present queue: %d", err);
2108 VkPresentInfoKHR presInfo;
2109 memset(&presInfo, 0,
sizeof(presInfo));
2110 presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2111 presInfo.swapchainCount = 1;
2112 presInfo.pSwapchains = &swapChain;
2113 presInfo.pImageIndices = ¤tImage;
2114 presInfo.waitSemaphoreCount = 1;
2115 presInfo.pWaitSemaphores = gfxQueueFamilyIdx == presQueueFamilyIdx ? &
frame.drawSem : &
frame.presTransSem;
2119 inst->presentAboutToBeQueued(
q);
2121 err = vkQueuePresentKHR(presQueue, &presInfo);
2122 if (err != VK_SUCCESS) {
2123 if (err == VK_ERROR_OUT_OF_DATE_KHR) {
2124 recreateSwapChain();
2127 }
else if (err != VK_SUBOPTIMAL_KHR) {
2128 if (!checkDeviceLost(err))
2129 qWarning(
"QVulkanWindow: Failed to present: %d", err);
2134 frame.imageAcquired =
false;
2136 inst->presentQueued(
q);
2138 currentFrame = (currentFrame + 1) % frameLag;
2154void QVulkanWindow::frameReady()
2157 "QVulkanWindow",
"frameReady() can only be called from the GUI (main) thread");
2161 if (!
d->framePending) {
2162 qWarning(
"QVulkanWindow: frameReady() called without a corresponding startNextFrame()");
2166 d->framePending =
false;
2171bool QVulkanWindowPrivate::checkDeviceLost(VkResult err)
2173 if (err == VK_ERROR_DEVICE_LOST) {
2174 qWarning(
"QVulkanWindow: Device lost");
2177 qCDebug(lcGuiVk,
"Releasing all resources due to device lost");
2180 qCDebug(lcGuiVk,
"Restarting");
2187void QVulkanWindowPrivate::addReadback()
2189 VkImageCreateInfo imageInfo;
2190 memset(&imageInfo, 0,
sizeof(imageInfo));
2191 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
2192 imageInfo.imageType = VK_IMAGE_TYPE_2D;
2193 imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
2194 imageInfo.extent.width = frameGrabTargetImage.width();
2195 imageInfo.extent.height = frameGrabTargetImage.height();
2196 imageInfo.extent.depth = 1;
2197 imageInfo.mipLevels = 1;
2198 imageInfo.arrayLayers = 1;
2199 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
2200 imageInfo.tiling = VK_IMAGE_TILING_LINEAR;
2201 imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
2202 imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
2204 VkResult err = devFuncs->vkCreateImage(dev, &imageInfo,
nullptr, &frameGrabImage);
2205 if (err != VK_SUCCESS) {
2206 qWarning(
"QVulkanWindow: Failed to create image for readback: %d", err);
2210 VkMemoryRequirements memReq;
2211 devFuncs->vkGetImageMemoryRequirements(dev, frameGrabImage, &memReq);
2213 VkMemoryAllocateInfo allocInfo = {
2214 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
2220 err = devFuncs->vkAllocateMemory(dev, &allocInfo,
nullptr, &frameGrabImageMem);
2221 if (err != VK_SUCCESS) {
2222 qWarning(
"QVulkanWindow: Failed to allocate memory for readback image: %d", err);
2226 err = devFuncs->vkBindImageMemory(dev, frameGrabImage, frameGrabImageMem, 0);
2227 if (err != VK_SUCCESS) {
2228 qWarning(
"QVulkanWindow: Failed to bind readback image memory: %d", err);
2232 ImageResources &
image(imageRes[currentImage]);
2234 VkImageMemoryBarrier barrier;
2235 memset(&barrier, 0,
sizeof(barrier));
2236 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2237 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2238 barrier.subresourceRange.levelCount = barrier.subresourceRange.layerCount = 1;
2240 barrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2241 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2242 barrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
2243 barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
2244 barrier.image =
image.image;
2246 devFuncs->vkCmdPipelineBarrier(
image.cmdBuf,
2247 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2248 VK_PIPELINE_STAGE_TRANSFER_BIT,
2249 0, 0,
nullptr, 0,
nullptr,
2252 barrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
2253 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2254 barrier.srcAccessMask = 0;
2255 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
2256 barrier.image = frameGrabImage;
2258 devFuncs->vkCmdPipelineBarrier(
image.cmdBuf,
2259 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
2260 VK_PIPELINE_STAGE_TRANSFER_BIT,
2261 0, 0,
nullptr, 0,
nullptr,
2264 VkImageCopy copyInfo;
2265 memset(©Info, 0,
sizeof(copyInfo));
2266 copyInfo.srcSubresource.aspectMask = copyInfo.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2267 copyInfo.srcSubresource.layerCount = copyInfo.dstSubresource.layerCount = 1;
2268 copyInfo.extent.width = frameGrabTargetImage.width();
2269 copyInfo.extent.height = frameGrabTargetImage.height();
2270 copyInfo.extent.depth = 1;
2272 devFuncs->vkCmdCopyImage(
image.cmdBuf,
image.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
2273 frameGrabImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Info);
2275 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2276 barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
2277 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
2278 barrier.dstAccessMask = VK_ACCESS_HOST_READ_BIT;
2279 barrier.image = frameGrabImage;
2281 devFuncs->vkCmdPipelineBarrier(
image.cmdBuf,
2282 VK_PIPELINE_STAGE_TRANSFER_BIT,
2283 VK_PIPELINE_STAGE_HOST_BIT,
2284 0, 0,
nullptr, 0,
nullptr,
2288void QVulkanWindowPrivate::finishBlockingReadback()
2290 ImageResources &
image(imageRes[currentImage]);
2294 devFuncs->vkWaitForFences(dev, 1, &
image.cmdFence, VK_TRUE, UINT64_MAX);
2295 devFuncs->vkResetFences(dev, 1, &
image.cmdFence);
2297 image.cmdFenceWaitable =
false;
2299 VkImageSubresource subres = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 };
2300 VkSubresourceLayout
layout;
2301 devFuncs->vkGetImageSubresourceLayout(dev, frameGrabImage, &subres, &
layout);
2304 VkResult err = devFuncs->vkMapMemory(dev, frameGrabImageMem,
layout.offset,
layout.size, 0,
reinterpret_cast<void **
>(&
p));
2305 if (err != VK_SUCCESS) {
2306 qWarning(
"QVulkanWindow: Failed to map readback image memory after transfer: %d", err);
2310 for (
int y = 0;
y < frameGrabTargetImage.height(); ++
y) {
2311 memcpy(frameGrabTargetImage.scanLine(
y),
p, frameGrabTargetImage.width() * 4);
2315 devFuncs->vkUnmapMemory(dev, frameGrabImageMem);
2317 devFuncs->vkDestroyImage(dev, frameGrabImage,
nullptr);
2318 frameGrabImage = VK_NULL_HANDLE;
2319 devFuncs->vkFreeMemory(dev, frameGrabImageMem,
nullptr);
2320 frameGrabImageMem = VK_NULL_HANDLE;
2330VkPhysicalDevice QVulkanWindow::physicalDevice()
const
2333 if (
d->physDevIndex <
d->physDevs.size())
2334 return d->physDevs[
d->physDevIndex];
2335 qWarning(
"QVulkanWindow: Physical device not available");
2336 return VK_NULL_HANDLE;
2346const VkPhysicalDeviceProperties *QVulkanWindow::physicalDeviceProperties()
const
2349 if (
d->physDevIndex <
d->physDevProps.size())
2350 return &
d->physDevProps[
d->physDevIndex];
2351 qWarning(
"QVulkanWindow: Physical device properties not available");
2362VkDevice QVulkanWindow::device()
const
2375VkQueue QVulkanWindow::graphicsQueue()
const
2392uint32_t QVulkanWindow::graphicsQueueFamilyIndex()
const
2395 return d->gfxQueueFamilyIdx;
2405VkCommandPool QVulkanWindow::graphicsCommandPool()
const
2421uint32_t QVulkanWindow::hostVisibleMemoryIndex()
const
2424 return d->hostVisibleMemIndex;
2439uint32_t QVulkanWindow::deviceLocalMemoryIndex()
const
2442 return d->deviceLocalMemIndex;
2463VkRenderPass QVulkanWindow::defaultRenderPass()
const
2466 return d->defaultRenderPass;
2478VkFormat QVulkanWindow::colorFormat()
const
2481 return d->colorFormat;
2491VkFormat QVulkanWindow::depthStencilFormat()
const
2520QSize QVulkanWindow::swapChainImageSize()
const
2523 return d->swapChainImageSize;
2534VkCommandBuffer QVulkanWindow::currentCommandBuffer()
const
2537 if (!
d->framePending) {
2538 qWarning(
"QVulkanWindow: Attempted to call currentCommandBuffer() without an active frame");
2539 return VK_NULL_HANDLE;
2541 return d->imageRes[
d->currentImage].cmdBuf;
2563VkFramebuffer QVulkanWindow::currentFramebuffer()
const
2566 if (!
d->framePending) {
2567 qWarning(
"QVulkanWindow: Attempted to call currentFramebuffer() without an active frame");
2568 return VK_NULL_HANDLE;
2570 return d->imageRes[
d->currentImage].fb;
2594int QVulkanWindow::currentFrame()
const
2597 if (!
d->framePending)
2598 qWarning(
"QVulkanWindow: Attempted to call currentFrame() without an active frame");
2599 return d->currentFrame;
2618int QVulkanWindow::concurrentFrameCount()
const
2635int QVulkanWindow::swapChainImageCount()
const
2638 return d->swapChainBufferCount;
2647int QVulkanWindow::currentSwapChainImageIndex()
const
2650 if (!
d->framePending)
2651 qWarning(
"QVulkanWindow: Attempted to call currentSwapChainImageIndex() without an active frame");
2652 return d->currentImage;
2664VkImage QVulkanWindow::swapChainImage(
int idx)
const
2667 return idx >= 0 && idx <
d->swapChainBufferCount ?
d->imageRes[idx].image : VK_NULL_HANDLE;
2679VkImageView QVulkanWindow::swapChainImageView(
int idx)
const
2682 return idx >= 0 && idx <
d->swapChainBufferCount ?
d->imageRes[idx].imageView : VK_NULL_HANDLE;
2692VkImage QVulkanWindow::depthStencilImage()
const
2705VkImageView QVulkanWindow::depthStencilImageView()
const
2719VkSampleCountFlagBits QVulkanWindow::sampleCountFlagBits()
const
2722 return d->sampleCount;
2735VkImage QVulkanWindow::msaaColorImage(
int idx)
const
2738 return idx >= 0 && idx <
d->swapChainBufferCount ?
d->imageRes[idx].msaaImage : VK_NULL_HANDLE;
2751VkImageView QVulkanWindow::msaaColorImageView(
int idx)
const
2754 return idx >= 0 && idx <
d->swapChainBufferCount ?
d->imageRes[idx].msaaImageView : VK_NULL_HANDLE;
2765bool QVulkanWindow::supportsGrab()
const
2768 return d->swapChainSupportsReadBack;
2802QImage QVulkanWindow::grab()
2805 if (!
d->swapChain) {
2806 qWarning(
"QVulkanWindow: Attempted to call grab() without a swapchain");
2809 if (
d->framePending) {
2810 qWarning(
"QVulkanWindow: Attempted to call grab() while a frame is still pending");
2813 if (!
d->swapChainSupportsReadBack) {
2814 qWarning(
"QVulkanWindow: Attempted to call grab() with a swapchain that does not support usage as transfer source");
2818 d->frameGrabbing =
true;
2821 if (
d->colorFormat == VK_FORMAT_B8G8R8A8_UNORM)
2822 d->frameGrabTargetImage = std::move(
d->frameGrabTargetImage).rgbSwapped();
2824 return d->frameGrabTargetImage;
2838QMatrix4x4 QVulkanWindow::clipCorrectionMatrix()
2841 if (
d->m_clipCorrect.isIdentity()) {
2843 d->m_clipCorrect =
QMatrix4x4(1.0f, 0.0f, 0.0f, 0.0f,
2844 0.0f, -1.0f, 0.0f, 0.0f,
2845 0.0f, 0.0f, 0.5f, 0.5f,
2846 0.0f, 0.0f, 0.0f, 1.0f);
2848 return d->m_clipCorrect;
2853#include "moc_qvulkanwindow.cpp"
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
Type type() const
Returns the event type.
The QExposeEvent class contains event parameters for expose events. \inmodule QtGui.
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
The QResizeEvent class contains event parameters for resize events.
static QThread * currentThread()
bool singleShot
whether the timer is a single-shot timer
The QVulkanFunctions class provides cross-platform access to the instance level core Vulkan 1....
The QVulkanInstance class represents a native Vulkan instance, enabling Vulkan rendering onto a QSurf...
virtual bool event(QEvent *) override
Override this to handle any event (ev) sent to the window.
Combined button and popup list for selecting options.
VkCommandBufferAllocateInfo cmdBufInfo
#define QByteArrayLiteral(str)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
constexpr const T & qBound(const T &min, const T &val, const T &max)
constexpr const T & qMax(const T &a, const T &b)
static bool contains(const QJsonArray &haystack, unsigned needle)
GLsizei const GLfloat * v
[13]
GLint GLenum GLsizei GLsizei GLsizei depth
GLenum GLenum GLsizei count
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLint GLsizei GLsizei GLenum format
GLdouble GLdouble GLdouble GLdouble q
GLint GLfloat GLint stencil
GLenum GLenum colorFormat
GLsizeiptr const void GLenum usage
#define Q_ASSERT_X(cond, x, msg)
Int aligned(Int v, Int byteAlign)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
static struct @397 q_vk_sampleCounts[]
QList< QImage > images
[6]
QSvgRenderer * renderer
[0]