diff options
Diffstat (limited to 'tests/manual')
19 files changed, 1001 insertions, 128 deletions
diff --git a/tests/manual/cocoa/nativewidgets/main.cpp b/tests/manual/cocoa/nativewidgets/main.cpp index bfa97aa62f..3923e30de7 100644 --- a/tests/manual/cocoa/nativewidgets/main.cpp +++ b/tests/manual/cocoa/nativewidgets/main.cpp @@ -37,7 +37,7 @@ class ColorWidget : public QWidget void changeColor() { - color.setHsv((qreal(qrand()) / RAND_MAX) * 50 + 200, s, s); + color.setHsv(QRandomGenerator::global()->bounded(50) + 200, s, s); } public: diff --git a/tests/manual/cocoa/qt_on_cocoa/main.mm b/tests/manual/cocoa/qt_on_cocoa/main.mm index 4ec1ce1e0d..805ef0d7c2 100644 --- a/tests/manual/cocoa/qt_on_cocoa/main.mm +++ b/tests/manual/cocoa/qt_on_cocoa/main.mm @@ -33,6 +33,23 @@ #include <AppKit/AppKit.h> + +@interface ContentView : NSView +@end + +@implementation ContentView +- (void)drawRect:(NSRect)dirtyRect { + [[NSColor whiteColor] setFill]; + NSRectFill(dirtyRect); +} + +- (void)cursorUpdate:(NSEvent *)theEvent +{ + Q_UNUSED(theEvent); + [[NSCursor pointingHandCursor] set]; +} +@end + @interface AppDelegate : NSObject <NSApplicationDelegate> { QGuiApplication *m_app; QWindow *m_window; @@ -65,12 +82,35 @@ [window setTitle:title]; [window setBackgroundColor:[NSColor blueColor]]; - // Create the QWindow, use its NSView as the content view - m_window = new RasterWindow(); - [window setContentView:reinterpret_cast<NSView *>(m_window->winId())]; + NSView *contentView = [[[ContentView alloc] initWithFrame:frame] autorelease]; + [contentView addTrackingArea:[[NSTrackingArea alloc] initWithRect:[contentView frame] + options:NSTrackingActiveInActiveApp | NSTrackingInVisibleRect | NSTrackingCursorUpdate + owner:contentView userInfo:nil]]; + + // Create the QWindow, add its NSView to the content view + m_window = new RasterWindow; + m_window->setObjectName("RasterWindow"); + m_window->setCursor(Qt::CrossCursor); + m_window->setGeometry(QRect(0, 0, 300, 300)); + + QWindow *childWindow = new RasterWindow; + childWindow->setObjectName("RasterWindowChild"); + childWindow->setParent(m_window); + childWindow->setCursor(Qt::BusyCursor); + childWindow->setGeometry(50, 50, 100, 100); + + NSTextField *textField = [[NSTextField alloc] initWithFrame:NSMakeRect(10, 10, 80, 25)]; + [(NSView*)childWindow->winId() addSubview:textField]; + + [contentView addSubview:reinterpret_cast<NSView *>(m_window->winId())]; + + window.contentView = contentView; - // Show the NSWindow - [window makeKeyAndOrderFront:NSApp]; + // Show the NSWindow delayed, so that we can verify that Qt picks up the right + // notifications to expose the window when it does become visible. + dispatch_async(dispatch_get_main_queue(), ^{ + [window makeKeyAndOrderFront:NSApp]; + }); } - (void)applicationWillTerminate:(NSNotification *)notification diff --git a/tests/manual/cocoa/qt_on_cocoa/rasterwindow.cpp b/tests/manual/cocoa/qt_on_cocoa/rasterwindow.cpp index ca09af9964..6d7cb3e305 100644 --- a/tests/manual/cocoa/qt_on_cocoa/rasterwindow.cpp +++ b/tests/manual/cocoa/qt_on_cocoa/rasterwindow.cpp @@ -52,17 +52,6 @@ RasterWindow::RasterWindow(QRasterWindow *parent) void RasterWindow::initialize() { - if (parent()) - setGeometry(QRect(160, 120, 320, 240)); - else { - setGeometry(QRect(10, 10, 640, 480)); - - setSizeIncrement(QSize(10, 10)); - setBaseSize(QSize(640, 480)); - setMinimumSize(QSize(240, 160)); - setMaximumSize(QSize(800, 600)); - } - create(); m_backingStore = new QBackingStore(this); @@ -70,12 +59,12 @@ void RasterWindow::initialize() m_image.fill(colorTable[m_backgroundColorIndex % (sizeof(colorTable) / sizeof(colorTable[0]))].rgba()); m_lastPos = QPoint(-1, -1); - m_renderTimer = 0; } void RasterWindow::mousePressEvent(QMouseEvent *event) { m_lastPos = event->pos(); + unsetCursor(); } void RasterWindow::mouseMoveEvent(QMouseEvent *event) @@ -104,7 +93,7 @@ void RasterWindow::mouseReleaseEvent(QMouseEvent *event) void RasterWindow::exposeEvent(QExposeEvent *) { - scheduleRender(); + render(); } void RasterWindow::resizeEvent(QResizeEvent *) @@ -146,19 +135,24 @@ void RasterWindow::keyPressEvent(QKeyEvent *event) void RasterWindow::scheduleRender() { - if (!m_renderTimer) - m_renderTimer = startTimer(1); + requestUpdate(); } -void RasterWindow::timerEvent(QTimerEvent *) +bool RasterWindow::event(QEvent *e) { - render(); - killTimer(m_renderTimer); - m_renderTimer = 0; + if (e->type() == QEvent::UpdateRequest) + render(); + + return QWindow::event(e); } void RasterWindow::render() { + if (!isExposed()) { + qDebug() << "Skipping render, not exposed"; + return; + } + QRect rect(QPoint(), geometry().size()); m_backingStore->resize(rect.size()); diff --git a/tests/manual/cocoa/qt_on_cocoa/rasterwindow.h b/tests/manual/cocoa/qt_on_cocoa/rasterwindow.h index eff2addb70..5262300b12 100644 --- a/tests/manual/cocoa/qt_on_cocoa/rasterwindow.h +++ b/tests/manual/cocoa/qt_on_cocoa/rasterwindow.h @@ -44,7 +44,7 @@ protected: void exposeEvent(QExposeEvent *); void resizeEvent(QResizeEvent *); - void timerEvent(QTimerEvent *); + bool event(QEvent *); private: void render(); @@ -56,5 +56,4 @@ private: QPoint m_lastPos; int m_backgroundColorIndex; QBackingStore *m_backingStore; - int m_renderTimer; }; diff --git a/tests/manual/filetest/main.cpp b/tests/manual/filetest/main.cpp index 396fcdb24b..c278fd87ce 100644 --- a/tests/manual/filetest/main.cpp +++ b/tests/manual/filetest/main.cpp @@ -26,6 +26,7 @@ ** ****************************************************************************/ +#include <QDateTime> #include <QDebug> #include <QCoreApplication> #include <QFileInfo> @@ -40,12 +41,25 @@ static const char usage1[] = "Usage: "; static const char usage2[] =" [KEYWORD] [ARGUMENTS]\n\n" "Keywords: ls FILES list file information\n" +" stat FILES print detailed file information\n" " mv SOURCE TARGET rename files using QFile::rename\n" " cp SOURCE TARGET copy files using QFile::copy\n" " rm FILE remove file using QFile::remove\n" " rmr DIR remove directory recursively\n" " using QDir::removeRecursively\n"; +std::ostream &operator<<(std::ostream &o, const QString &str) +{ + return o << qPrintable(str); +} + +std::ostream &operator<<(std::ostream &o, const QDateTime &dt) +{ + if (dt.isValid()) + return o << dt.toString(Qt::ISODateWithMs); + return o << '-'; +} + static inline std::string permissions(QFile::Permissions permissions) { std::string result(10, '-'); @@ -102,6 +116,44 @@ static int ls(int argCount, char **args) return 0; } +static int stat(int argCount, char **args) +{ + for (int i = 0 ; i < argCount; ++i) { + const QFileInfo fi(QFile::decodeName(args[i])); + std::cout << "Name:\t" << fi.fileName() << std::endl; + std::cout << "Path:\t" << QDir::toNativeSeparators(fi.path()) + << " (" << QDir::toNativeSeparators(fi.absolutePath()) << ')' << std::endl; + std::cout << "Size:\t" << fi.size() + << "\tType: " + << (fi.isSymLink() && !fi.exists() ? "Broken symlink" : + !fi.exists() ? "Non-existent" : + fi.isSymLink() ? "Symlink to " : "") + << (!fi.exists() ? "" : + fi.isFile() ? "Regular file" : + fi.isDir() ? "Directory" : "Special node") + << std::endl; + if (fi.isSymLink()) + std::cout << "Target:\t" << fi.symLinkTarget() << std::endl; + std::cout << "Attrs: " + << (fi.isReadable() ? " readable" : "") + << (fi.isWritable() ? " writable" : "") + << (fi.isExecutable() ? " executable" : "") + << (fi.isHidden() ? " hidden" : "") + << (fi.isNativePath() ? " nativepath" : "") + << (fi.isRoot() ? " root" : "") + << (fi.isBundle() ? " bundle" : "") + << std::endl; + std::cout << "Mode:\t" << permissions(fi) << std::endl; + std::cout << "Owner:\t" << fi.owner() << " (" << fi.ownerId() + << ")\tGroup:\t" << fi.group() << " (" << fi.groupId() << ')' << std::endl; + std::cout << "Access:\t" << fi.lastRead() << std::endl; + std::cout << "Birth:\t" << fi.birthTime() << std::endl; + std::cout << "Change:\t" << fi.metadataChangeTime() << std::endl; + std::cout << "Modified: " << fi.lastModified() << std::endl; + } + return 0; +} + static int mv(const char *sourceFileName, const char *targetFileName) { QFile sourceFile(QString::fromLocal8Bit(sourceFileName)); @@ -155,6 +207,9 @@ int main(int argc, char *argv[]) if (argc >= 3 && !qstrcmp(argv[1], "ls")) return ls(argc -2, argv + 2); + if (argc >= 3 && !qstrcmp(argv[1], "stat")) + return stat(argc -2, argv + 2); + if (argc == 4 && !qstrcmp(argv[1], "mv")) return mv(argv[2], argv[3]); diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index a9d27fa488..ab00a5ef60 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -67,3 +67,5 @@ win32: SUBDIRS -= network_remote_stresstest network_stresstest lessThan(QT_MAJOR_VERSION, 5): SUBDIRS -= bearerex lance qnetworkaccessmanager/qget qmimedatabase qnetworkreply \ qpainfo qscreen socketengine xembed-raster xembed-widgets windowtransparency \ embeddedintoforeignwindow foreignwindows + +qtConfig(vulkan): SUBDIRS += qvulkaninstance diff --git a/tests/manual/network_remote_stresstest/tst_network_remote_stresstest.cpp b/tests/manual/network_remote_stresstest/tst_network_remote_stresstest.cpp index 99e3d148df..f5c3bfde34 100644 --- a/tests/manual/network_remote_stresstest/tst_network_remote_stresstest.cpp +++ b/tests/manual/network_remote_stresstest/tst_network_remote_stresstest.cpp @@ -156,7 +156,7 @@ void tst_NetworkRemoteStressTest::clearManager() bool nativeLookup(const char *hostname, int port, QByteArray &buf) { -#if !defined(QT_NO_GETADDRINFO) && 0 +#if 0 addrinfo *res = 0; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); diff --git a/tests/manual/network_stresstest/tst_network_stresstest.cpp b/tests/manual/network_stresstest/tst_network_stresstest.cpp index d46703c671..03df1633d5 100644 --- a/tests/manual/network_stresstest/tst_network_stresstest.cpp +++ b/tests/manual/network_stresstest/tst_network_stresstest.cpp @@ -147,7 +147,7 @@ void tst_NetworkStressTest::clearManager() bool nativeLookup(const char *hostname, int port, QByteArray &buf) { -#if !defined(QT_NO_GETADDRINFO) && 0 +#if 0 addrinfo *res = 0; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); diff --git a/tests/manual/qtabletevent/regular_widgets/main.cpp b/tests/manual/qtabletevent/regular_widgets/main.cpp index fd3c385b97..339d1d3633 100644 --- a/tests/manual/qtabletevent/regular_widgets/main.cpp +++ b/tests/manual/qtabletevent/regular_widgets/main.cpp @@ -59,50 +59,59 @@ struct TabletPoint qreal angle; }; +class ProximityEventFilter : public QObject +{ +public: + explicit ProximityEventFilter(QObject *parent) : QObject(parent) { } + + bool eventFilter(QObject *, QEvent *event) override + { + switch (event->type()) { + case QEvent::TabletEnterProximity: + case QEvent::TabletLeaveProximity: + qDebug() << event; + break; + default: + break; + } + return false; + } +}; + class EventReportWidget : public QWidget { Q_OBJECT public: - EventReportWidget(); + EventReportWidget() { startTimer(1000); } public slots: void clearPoints() { m_points.clear(); update(); } signals: - void stats(QString s); + void stats(QString s, int timeOut = 0); protected: - void mouseDoubleClickEvent(QMouseEvent *event) { outputMouseEvent(event); } - void mouseMoveEvent(QMouseEvent *event) { outputMouseEvent(event); } - void mousePressEvent(QMouseEvent *event) { outputMouseEvent(event); } - void mouseReleaseEvent(QMouseEvent *event) { outputMouseEvent(event); } + void mouseDoubleClickEvent(QMouseEvent *event) override { outputMouseEvent(event); } + void mouseMoveEvent(QMouseEvent *event) override { outputMouseEvent(event); } + void mousePressEvent(QMouseEvent *event) override { outputMouseEvent(event); } + void mouseReleaseEvent(QMouseEvent *event) override { outputMouseEvent(event); } - void tabletEvent(QTabletEvent *); + void tabletEvent(QTabletEvent *) override; - void paintEvent(QPaintEvent *); - void timerEvent(QTimerEvent *); + void paintEvent(QPaintEvent *) override; + void timerEvent(QTimerEvent *) override; private: void outputMouseEvent(QMouseEvent *event); - bool m_lastIsMouseMove; - bool m_lastIsTabletMove; - Qt::MouseButton m_lastButton; + bool m_lastIsMouseMove = false; + bool m_lastIsTabletMove = false; + Qt::MouseButton m_lastButton = Qt::NoButton; QVector<TabletPoint> m_points; - int m_tabletMoveCount; - int m_paintEventCount; + int m_tabletMoveCount = 0; + int m_paintEventCount = 0; }; -EventReportWidget::EventReportWidget() - : m_lastIsMouseMove(false) - , m_lastIsTabletMove(false) - , m_lastButton(Qt::NoButton) - , m_tabletMoveCount(0) - , m_paintEventCount(0) -{ - startTimer(1000); -} - void EventReportWidget::paintEvent(QPaintEvent *) { QPainter p(this); @@ -114,7 +123,7 @@ void EventReportWidget::paintEvent(QPaintEvent *) p.setPen(Qt::white); QPainterPath ellipse; ellipse.addEllipse(0, 0, halfLineSpacing * 5, halfLineSpacing); - foreach (const TabletPoint &t, m_points) { + for (const TabletPoint &t : qAsConst(m_points)) { if (geom.contains(t.pos)) { QPainterPath pp; pp.addEllipse(t.pos, halfLineSpacing, halfLineSpacing); @@ -159,10 +168,6 @@ void EventReportWidget::tabletEvent(QTabletEvent *event) QWidget::tabletEvent(event); bool isMove = false; switch (event->type()) { - case QEvent::TabletEnterProximity: - case QEvent::TabletLeaveProximity: - qDebug() << "proximity" << event; - break; case QEvent::TabletMove: m_points.push_back(TabletPoint(event->pos(), TabletMove, m_lastButton, event->pointerType(), event->pressure(), event->rotation())); update(); @@ -213,15 +218,16 @@ void EventReportWidget::timerEvent(QTimerEvent *) int main(int argc, char *argv[]) { QApplication app(argc, argv); + app.installEventFilter(new ProximityEventFilter(&app)); QMainWindow mainWindow; mainWindow.setWindowTitle(QString::fromLatin1("Tablet Test %1").arg(QT_VERSION_STR)); EventReportWidget *widget = new EventReportWidget; widget->setMinimumSize(640, 480); QMenu *fileMenu = mainWindow.menuBar()->addMenu("File"); - QObject::connect(fileMenu->addAction("Clear"), SIGNAL(triggered()), widget, SLOT(clearPoints())); - QObject::connect(widget, SIGNAL(stats(QString)), mainWindow.statusBar(), SLOT(showMessage(QString))); - QAction *quitAction = fileMenu->addAction("Quit"); - QObject::connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); + fileMenu->addAction("Clear", widget, &EventReportWidget::clearPoints); + QObject::connect(widget, &EventReportWidget::stats, + mainWindow.statusBar(), &QStatusBar::showMessage); + QAction *quitAction = fileMenu->addAction("Quit", qApp, &QCoreApplication::quit); quitAction->setShortcut(Qt::CTRL + Qt::Key_Q); mainWindow.setCentralWidget(widget); mainWindow.show(); diff --git a/tests/manual/qvulkaninstance/main.cpp b/tests/manual/qvulkaninstance/main.cpp new file mode 100644 index 0000000000..9b5f0ad072 --- /dev/null +++ b/tests/manual/qvulkaninstance/main.cpp @@ -0,0 +1,713 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QGuiApplication> +#include <QVulkanInstance> +#include <QVulkanFunctions> +#include <QWindow> +#include <QLoggingCategory> +#include <qevent.h> + +static const int SWAPCHAIN_BUFFER_COUNT = 2; +static const int FRAME_LAG = 2; + +class VWindow : public QWindow +{ +public: + VWindow() { setSurfaceType(VulkanSurface); } + ~VWindow() { releaseResources(); } + +private: + void exposeEvent(QExposeEvent *) override; + void resizeEvent(QResizeEvent *) override; + bool event(QEvent *) override; + + void init(); + void releaseResources(); + void recreateSwapChain(); + void createDefaultRenderPass(); + void releaseSwapChain(); + void render(); + void buildDrawCalls(); + + bool m_inited = false; + VkSurfaceKHR m_vkSurface; + VkPhysicalDevice m_vkPhysDev; + VkPhysicalDeviceProperties m_physDevProps; + VkDevice m_vkDev = 0; + QVulkanDeviceFunctions *m_devFuncs; + VkQueue m_vkGfxQueue; + VkQueue m_vkPresQueue; + VkCommandPool m_vkCmdPool = 0; + + PFN_vkCreateSwapchainKHR m_vkCreateSwapchainKHR = nullptr; + PFN_vkDestroySwapchainKHR m_vkDestroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR m_vkGetSwapchainImagesKHR; + PFN_vkAcquireNextImageKHR m_vkAcquireNextImageKHR; + PFN_vkQueuePresentKHR m_vkQueuePresentKHR; + PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR m_vkGetPhysicalDeviceSurfaceCapabilitiesKHR; + PFN_vkGetPhysicalDeviceSurfaceFormatsKHR m_vkGetPhysicalDeviceSurfaceFormatsKHR; + + QSize m_swapChainImageSize; + VkFormat m_colorFormat; + VkSwapchainKHR m_swapChain = 0; + uint32_t m_swapChainBufferCount = 0; + + struct ImageResources { + VkImage image = 0; + VkImageView imageView = 0; + VkCommandBuffer cmdBuf = 0; + VkFence cmdFence = 0; + bool cmdFenceWaitable = false; + VkFramebuffer fb = 0; + } m_imageRes[SWAPCHAIN_BUFFER_COUNT]; + + uint32_t m_currentImage; + + struct FrameResources { + VkFence fence = 0; + bool fenceWaitable = false; + VkSemaphore imageSem = 0; + VkSemaphore drawSem = 0; + } m_frameRes[FRAME_LAG]; + + uint32_t m_currentFrame; + + VkRenderPass m_defaultRenderPass = 0; +}; + +void VWindow::exposeEvent(QExposeEvent *) +{ + if (isExposed() && !m_inited) { + qDebug("initializing"); + m_inited = true; + init(); + recreateSwapChain(); + render(); + } + + // Release everything when unexposed - the meaning of which is platform specific. + // Can be essential on mobile, to release resources while in background. +#if 1 + if (!isExposed() && m_inited) { + m_inited = false; + releaseSwapChain(); + releaseResources(); + } +#endif +} + +void VWindow::resizeEvent(QResizeEvent *) +{ + // Nothing to do here - recreating the swapchain is handled in render(), + // in fact calling recreateSwapChain() from here leads to problems. +} + +bool VWindow::event(QEvent *e) +{ + switch (e->type()) { + case QEvent::UpdateRequest: + render(); + break; + + // Now the fun part: the swapchain must be destroyed before the surface as per + // spec. This is not ideal for us because the surface is managed by the + // QPlatformWindow which may be gone already when the unexpose comes, making the + // validation layer scream. The solution is to listen to the PlatformSurface events. + case QEvent::PlatformSurface: + if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) + releaseSwapChain(); + break; + + default: + break; + } + + return QWindow::event(e); +} + +void VWindow::init() +{ + m_vkSurface = QVulkanInstance::surfaceForWindow(this); + if (!m_vkSurface) + qFatal("Failed to get surface for window"); + + QVulkanInstance *inst = vulkanInstance(); + QVulkanFunctions *f = inst->functions(); + uint32_t devCount = 0; + f->vkEnumeratePhysicalDevices(inst->vkInstance(), &devCount, nullptr); + qDebug("%d physical devices", devCount); + if (!devCount) + qFatal("No physical devices"); + + // Just pick the first physical device for now. + devCount = 1; + VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &devCount, &m_vkPhysDev); + if (err != VK_SUCCESS) + qFatal("Failed to enumerate physical devices: %d", err); + + f->vkGetPhysicalDeviceProperties(m_vkPhysDev, &m_physDevProps); + qDebug("Device name: %s Driver version: %d.%d.%d", m_physDevProps.deviceName, + VK_VERSION_MAJOR(m_physDevProps.driverVersion), VK_VERSION_MINOR(m_physDevProps.driverVersion), + VK_VERSION_PATCH(m_physDevProps.driverVersion)); + + uint32_t queueCount = 0; + f->vkGetPhysicalDeviceQueueFamilyProperties(m_vkPhysDev, &queueCount, nullptr); + QVector<VkQueueFamilyProperties> queueFamilyProps(queueCount); + f->vkGetPhysicalDeviceQueueFamilyProperties(m_vkPhysDev, &queueCount, queueFamilyProps.data()); + int gfxQueueFamilyIdx = -1; + int presQueueFamilyIdx = -1; + // First look for a queue that supports both. + for (int i = 0; i < queueFamilyProps.count(); ++i) { + qDebug("queue family %d: flags=0x%x count=%d", i, queueFamilyProps[i].queueFlags, queueFamilyProps[i].queueCount); + if (gfxQueueFamilyIdx == -1 + && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + && inst->supportsPresent(m_vkPhysDev, i, this)) + gfxQueueFamilyIdx = i; + } + if (gfxQueueFamilyIdx != -1) { + presQueueFamilyIdx = gfxQueueFamilyIdx; + } else { + // Separate queues then. + qDebug("No queue with graphics+present; trying separate queues"); + for (int i = 0; i < queueFamilyProps.count(); ++i) { + if (gfxQueueFamilyIdx == -1 && (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) + gfxQueueFamilyIdx = i; + if (presQueueFamilyIdx == -1 && inst->supportsPresent(m_vkPhysDev, i, this)) + presQueueFamilyIdx = i; + } + } + if (gfxQueueFamilyIdx == -1) + qFatal("No graphics queue family found"); + if (presQueueFamilyIdx == -1) + qFatal("No present queue family found"); + + VkDeviceQueueCreateInfo queueInfo[2]; + const float prio[] = { 0 }; + memset(queueInfo, 0, sizeof(queueInfo)); + queueInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueInfo[0].queueFamilyIndex = gfxQueueFamilyIdx; + queueInfo[0].queueCount = 1; + queueInfo[0].pQueuePriorities = prio; + if (gfxQueueFamilyIdx != presQueueFamilyIdx) { + queueInfo[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueInfo[1].queueFamilyIndex = presQueueFamilyIdx; + queueInfo[1].queueCount = 1; + queueInfo[1].pQueuePriorities = prio; + } + + QVector<const char *> devLayers; + if (inst->layers().contains("VK_LAYER_LUNARG_standard_validation")) + devLayers.append("VK_LAYER_LUNARG_standard_validation"); + + QVector<const char *> devExts; + devExts.append("VK_KHR_swapchain"); + + VkDeviceCreateInfo devInfo; + memset(&devInfo, 0, sizeof(devInfo)); + devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + devInfo.queueCreateInfoCount = gfxQueueFamilyIdx == presQueueFamilyIdx ? 1 : 2; + devInfo.pQueueCreateInfos = queueInfo; + devInfo.enabledLayerCount = devLayers.count(); + devInfo.ppEnabledLayerNames = devLayers.constData(); + devInfo.enabledExtensionCount = devExts.count(); + devInfo.ppEnabledExtensionNames = devExts.constData(); + + err = f->vkCreateDevice(m_vkPhysDev, &devInfo, nullptr, &m_vkDev); + if (err != VK_SUCCESS) + qFatal("Failed to create device: %d", err); + + m_devFuncs = inst->deviceFunctions(m_vkDev); + + m_devFuncs->vkGetDeviceQueue(m_vkDev, gfxQueueFamilyIdx, 0, &m_vkGfxQueue); + if (gfxQueueFamilyIdx == presQueueFamilyIdx) + m_vkPresQueue = m_vkGfxQueue; + else + m_devFuncs->vkGetDeviceQueue(m_vkDev, presQueueFamilyIdx, 0, &m_vkPresQueue); + + VkCommandPoolCreateInfo poolInfo; + memset(&poolInfo, 0, sizeof(poolInfo)); + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.queueFamilyIndex = gfxQueueFamilyIdx; + err = m_devFuncs->vkCreateCommandPool(m_vkDev, &poolInfo, nullptr, &m_vkCmdPool); + if (err != VK_SUCCESS) + qFatal("Failed to create command pool: %d", err); + + m_colorFormat = VK_FORMAT_B8G8R8A8_UNORM; // may get changed later when setting up the swapchain +} + +void VWindow::releaseResources() +{ + if (!m_vkDev) + return; + + m_devFuncs->vkDeviceWaitIdle(m_vkDev); + + if (m_vkCmdPool) { + m_devFuncs->vkDestroyCommandPool(m_vkDev, m_vkCmdPool, nullptr); + m_vkCmdPool = 0; + } + + if (m_vkDev) { + m_devFuncs->vkDestroyDevice(m_vkDev, nullptr); + + // Play nice and notify QVulkanInstance that the QVulkanDeviceFunctions + // for m_vkDev needs to be invalidated. + vulkanInstance()->resetDeviceFunctions(m_vkDev); + + m_vkDev = 0; + } + + m_vkSurface = 0; +} + +void VWindow::recreateSwapChain() +{ + m_swapChainImageSize = size(); + + if (m_swapChainImageSize.isEmpty()) + return; + + QVulkanInstance *inst = vulkanInstance(); + QVulkanFunctions *f = inst->functions(); + m_devFuncs->vkDeviceWaitIdle(m_vkDev); + + if (!m_vkCreateSwapchainKHR) { + m_vkGetPhysicalDeviceSurfaceCapabilitiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>( + inst->getInstanceProcAddr("vkGetPhysicalDeviceSurfaceCapabilitiesKHR")); + m_vkGetPhysicalDeviceSurfaceFormatsKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR>( + inst->getInstanceProcAddr("vkGetPhysicalDeviceSurfaceFormatsKHR")); + // note: device-specific functions + m_vkCreateSwapchainKHR = reinterpret_cast<PFN_vkCreateSwapchainKHR>(f->vkGetDeviceProcAddr(m_vkDev, "vkCreateSwapchainKHR")); + m_vkDestroySwapchainKHR = reinterpret_cast<PFN_vkDestroySwapchainKHR>(f->vkGetDeviceProcAddr(m_vkDev, "vkDestroySwapchainKHR")); + m_vkGetSwapchainImagesKHR = reinterpret_cast<PFN_vkGetSwapchainImagesKHR>(f->vkGetDeviceProcAddr(m_vkDev, "vkGetSwapchainImagesKHR")); + m_vkAcquireNextImageKHR = reinterpret_cast<PFN_vkAcquireNextImageKHR>(f->vkGetDeviceProcAddr(m_vkDev, "vkAcquireNextImageKHR")); + m_vkQueuePresentKHR = reinterpret_cast<PFN_vkQueuePresentKHR>(f->vkGetDeviceProcAddr(m_vkDev, "vkQueuePresentKHR")); + } + + VkColorSpaceKHR colorSpace = VkColorSpaceKHR(0); + uint32_t formatCount = 0; + m_vkGetPhysicalDeviceSurfaceFormatsKHR(m_vkPhysDev, m_vkSurface, &formatCount, nullptr); + if (formatCount) { + QVector<VkSurfaceFormatKHR> formats(formatCount); + m_vkGetPhysicalDeviceSurfaceFormatsKHR(m_vkPhysDev, m_vkSurface, &formatCount, formats.data()); + if (formats[0].format != VK_FORMAT_UNDEFINED) { + m_colorFormat = formats[0].format; + colorSpace = formats[0].colorSpace; + } + } + + VkSurfaceCapabilitiesKHR surfaceCaps; + m_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_vkPhysDev, m_vkSurface, &surfaceCaps); + uint32_t reqBufferCount = SWAPCHAIN_BUFFER_COUNT; + if (surfaceCaps.maxImageCount) + reqBufferCount = qBound(surfaceCaps.minImageCount, reqBufferCount, surfaceCaps.maxImageCount); + + VkExtent2D bufferSize = surfaceCaps.currentExtent; + if (bufferSize.width == uint32_t(-1)) + bufferSize.width = m_swapChainImageSize.width(); + if (bufferSize.height == uint32_t(-1)) + bufferSize.height = m_swapChainImageSize.height(); + + VkSurfaceTransformFlagBitsKHR preTransform = + (surfaceCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) + ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR + : surfaceCaps.currentTransform; + + VkCompositeAlphaFlagBitsKHR compositeAlpha = + (surfaceCaps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) + ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR + : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + + VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; + + VkSwapchainKHR oldSwapChain = m_swapChain; + VkSwapchainCreateInfoKHR swapChainInfo; + memset(&swapChainInfo, 0, sizeof(swapChainInfo)); + swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapChainInfo.surface = m_vkSurface; + swapChainInfo.minImageCount = reqBufferCount; + swapChainInfo.imageFormat = m_colorFormat; + swapChainInfo.imageColorSpace = colorSpace; + swapChainInfo.imageExtent = bufferSize; + swapChainInfo.imageArrayLayers = 1; + swapChainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapChainInfo.preTransform = preTransform; + swapChainInfo.compositeAlpha = compositeAlpha; + swapChainInfo.presentMode = presentMode; + swapChainInfo.clipped = true; + swapChainInfo.oldSwapchain = oldSwapChain; + + qDebug("creating new swap chain of %d buffers, size %dx%d", reqBufferCount, bufferSize.width, bufferSize.height); + + VkSwapchainKHR newSwapChain; + VkResult err = m_vkCreateSwapchainKHR(m_vkDev, &swapChainInfo, nullptr, &newSwapChain); + if (err != VK_SUCCESS) + qFatal("Failed to create swap chain: %d", err); + + if (oldSwapChain) + releaseSwapChain(); + + m_swapChain = newSwapChain; + + m_swapChainBufferCount = 0; + err = m_vkGetSwapchainImagesKHR(m_vkDev, m_swapChain, &m_swapChainBufferCount, nullptr); + if (err != VK_SUCCESS || m_swapChainBufferCount < 2) + qFatal("Failed to get swapchain images: %d (count=%d)", err, m_swapChainBufferCount); + + qDebug("actual swap chain buffer count: %d", m_swapChainBufferCount); + Q_ASSERT(m_swapChainBufferCount <= SWAPCHAIN_BUFFER_COUNT); + + VkImage swapChainImages[SWAPCHAIN_BUFFER_COUNT]; + err = m_vkGetSwapchainImagesKHR(m_vkDev, m_swapChain, &m_swapChainBufferCount, swapChainImages); + if (err != VK_SUCCESS) + qFatal("Failed to get swapchain images: %d", err); + + // Now that we know m_colorFormat, create the default renderpass, the framebuffers will need it. + createDefaultRenderPass(); + + VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, nullptr, VK_FENCE_CREATE_SIGNALED_BIT }; + + for (uint32_t i = 0; i < m_swapChainBufferCount; ++i) { + ImageResources &image(m_imageRes[i]); + image.image = swapChainImages[i]; + + VkImageViewCreateInfo imgViewInfo; + memset(&imgViewInfo, 0, sizeof(imgViewInfo)); + imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imgViewInfo.image = swapChainImages[i]; + imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + imgViewInfo.format = m_colorFormat; + imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R; + imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G; + imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B; + imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A; + imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1; + err = m_devFuncs->vkCreateImageView(m_vkDev, &imgViewInfo, nullptr, &image.imageView); + if (err != VK_SUCCESS) + qFatal("Failed to create swapchain image view %d: %d", i, err); + + err = m_devFuncs->vkCreateFence(m_vkDev, &fenceInfo, nullptr, &image.cmdFence); + if (err != VK_SUCCESS) + qFatal("Failed to create command buffer fence: %d", err); + image.cmdFenceWaitable = true; + + VkImageView views[1] = { image.imageView }; + VkFramebufferCreateInfo fbInfo; + memset(&fbInfo, 0, sizeof(fbInfo)); + fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fbInfo.renderPass = m_defaultRenderPass; + fbInfo.attachmentCount = 1; + fbInfo.pAttachments = views; + fbInfo.width = m_swapChainImageSize.width(); + fbInfo.height = m_swapChainImageSize.height(); + fbInfo.layers = 1; + VkResult err = m_devFuncs->vkCreateFramebuffer(m_vkDev, &fbInfo, nullptr, &image.fb); + if (err != VK_SUCCESS) + qFatal("Failed to create framebuffer: %d", err); + } + + m_currentImage = 0; + + VkSemaphoreCreateInfo semInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0 }; + for (uint32_t i = 0; i < FRAME_LAG; ++i) { + FrameResources &frame(m_frameRes[i]); + m_devFuncs->vkCreateFence(m_vkDev, &fenceInfo, nullptr, &frame.fence); + frame.fenceWaitable = true; + m_devFuncs->vkCreateSemaphore(m_vkDev, &semInfo, nullptr, &frame.imageSem); + m_devFuncs->vkCreateSemaphore(m_vkDev, &semInfo, nullptr, &frame.drawSem); + } + + m_currentFrame = 0; +} + +void VWindow::createDefaultRenderPass() +{ + VkAttachmentDescription attDesc[1]; + memset(attDesc, 0, sizeof(attDesc)); + attDesc[0].format = m_colorFormat; + attDesc[0].samples = VK_SAMPLE_COUNT_1_BIT; + attDesc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attDesc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attDesc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + attDesc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + attDesc[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attDesc[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + VkAttachmentReference colorRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + + VkSubpassDescription subPassDesc; + memset(&subPassDesc, 0, sizeof(subPassDesc)); + subPassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subPassDesc.colorAttachmentCount = 1; + subPassDesc.pColorAttachments = &colorRef; + + VkRenderPassCreateInfo rpInfo; + memset(&rpInfo, 0, sizeof(rpInfo)); + rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + rpInfo.attachmentCount = 1; + rpInfo.pAttachments = attDesc; + rpInfo.subpassCount = 1; + rpInfo.pSubpasses = &subPassDesc; + VkResult err = m_devFuncs->vkCreateRenderPass(m_vkDev, &rpInfo, nullptr, &m_defaultRenderPass); + if (err != VK_SUCCESS) + qFatal("Failed to create renderpass: %d", err); +} + +void VWindow::releaseSwapChain() +{ + if (!m_vkDev) + return; + + m_devFuncs->vkDeviceWaitIdle(m_vkDev); + + if (m_defaultRenderPass) { + m_devFuncs->vkDestroyRenderPass(m_vkDev, m_defaultRenderPass, nullptr); + m_defaultRenderPass = 0; + } + + for (uint32_t i = 0; i < FRAME_LAG; ++i) { + FrameResources &frame(m_frameRes[i]); + if (frame.fence) { + if (frame.fenceWaitable) + m_devFuncs->vkWaitForFences(m_vkDev, 1, &frame.fence, VK_TRUE, UINT64_MAX); + m_devFuncs->vkDestroyFence(m_vkDev, frame.fence, nullptr); + frame.fence = 0; + frame.fenceWaitable = false; + } + if (frame.imageSem) { + m_devFuncs->vkDestroySemaphore(m_vkDev, frame.imageSem, nullptr); + frame.imageSem = 0; + } + if (frame.drawSem) { + m_devFuncs->vkDestroySemaphore(m_vkDev, frame.drawSem, nullptr); + frame.drawSem = 0; + } + } + + for (uint32_t i = 0; i < m_swapChainBufferCount; ++i) { + ImageResources &image(m_imageRes[i]); + if (image.cmdFence) { + if (image.cmdFenceWaitable) + m_devFuncs->vkWaitForFences(m_vkDev, 1, &image.cmdFence, VK_TRUE, UINT64_MAX); + m_devFuncs->vkDestroyFence(m_vkDev, image.cmdFence, nullptr); + image.cmdFence = 0; + image.cmdFenceWaitable = false; + } + if (image.fb) { + m_devFuncs->vkDestroyFramebuffer(m_vkDev, image.fb, nullptr); + image.fb = 0; + } + if (image.imageView) { + m_devFuncs->vkDestroyImageView(m_vkDev, image.imageView, nullptr); + image.imageView = 0; + } + if (image.cmdBuf) { + m_devFuncs->vkFreeCommandBuffers(m_vkDev, m_vkCmdPool, 1, &image.cmdBuf); + image.cmdBuf = 0; + } + } + + if (m_swapChain) { + m_vkDestroySwapchainKHR(m_vkDev, m_swapChain, nullptr); + m_swapChain = 0; + } +} + +void VWindow::render() +{ + if (!m_swapChain) + return; + + if (size() != m_swapChainImageSize) { + recreateSwapChain(); + if (!m_swapChain) + return; + } + + FrameResources &frame(m_frameRes[m_currentFrame]); + + // Wait if we are too far ahead, i.e. the thread gets throttled based on the presentation rate + // (note that we are using FIFO mode -> vsync) + if (frame.fenceWaitable) { + m_devFuncs->vkWaitForFences(m_vkDev, 1, &frame.fence, VK_TRUE, UINT64_MAX); + m_devFuncs->vkResetFences(m_vkDev, 1, &frame.fence); + } + + // move on to next swapchain image + VkResult err = m_vkAcquireNextImageKHR(m_vkDev, m_swapChain, UINT64_MAX, + frame.imageSem, frame.fence, &m_currentImage); + if (err == VK_SUCCESS || err == VK_SUBOPTIMAL_KHR) { + frame.fenceWaitable = true; + } else if (err == VK_ERROR_OUT_OF_DATE_KHR) { + frame.fenceWaitable = false; + recreateSwapChain(); + requestUpdate(); + return; + } else { + qWarning("Failed to acquire next swapchain image: %d", err); + frame.fenceWaitable = false; + requestUpdate(); + return; + } + + // make sure the previous draw for the same image has finished + ImageResources &image(m_imageRes[m_currentImage]); + if (image.cmdFenceWaitable) { + m_devFuncs->vkWaitForFences(m_vkDev, 1, &image.cmdFence, VK_TRUE, UINT64_MAX); + m_devFuncs->vkResetFences(m_vkDev, 1, &image.cmdFence); + } + + // build new draw command buffer + buildDrawCalls(); + + // submit draw calls + VkSubmitInfo submitInfo; + memset(&submitInfo, 0, sizeof(submitInfo)); + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &image.cmdBuf; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = &frame.imageSem; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &frame.drawSem; + VkPipelineStageFlags psf = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + submitInfo.pWaitDstStageMask = &psf; + + err = m_devFuncs->vkQueueSubmit(m_vkGfxQueue, 1, &submitInfo, image.cmdFence); + if (err == VK_SUCCESS) { + image.cmdFenceWaitable = true; + } else { + qWarning("Failed to submit to command queue: %d", err); + image.cmdFenceWaitable = false; + } + + // queue present + VkPresentInfoKHR presInfo; + memset(&presInfo, 0, sizeof(presInfo)); + presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presInfo.swapchainCount = 1; + presInfo.pSwapchains = &m_swapChain; + presInfo.pImageIndices = &m_currentImage; + presInfo.waitSemaphoreCount = 1; + presInfo.pWaitSemaphores = &frame.drawSem; + + // we do not currently handle the case when the present queue is separate + Q_ASSERT(m_vkGfxQueue == m_vkPresQueue); + + err = m_vkQueuePresentKHR(m_vkGfxQueue, &presInfo); + if (err != VK_SUCCESS) { + if (err == VK_ERROR_OUT_OF_DATE_KHR) { + recreateSwapChain(); + requestUpdate(); + return; + } else if (err != VK_SUBOPTIMAL_KHR) { + qWarning("Failed to present: %d", err); + } + } + + vulkanInstance()->presentQueued(this); + + m_currentFrame = (m_currentFrame + 1) % FRAME_LAG; + requestUpdate(); +} + +void VWindow::buildDrawCalls() +{ + ImageResources &image(m_imageRes[m_currentImage]); + + if (image.cmdBuf) { + m_devFuncs->vkFreeCommandBuffers(m_vkDev, m_vkCmdPool, 1, &image.cmdBuf); + image.cmdBuf = 0; + } + + VkCommandBufferAllocateInfo cmdBufInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, nullptr, m_vkCmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1 }; + VkResult err = m_devFuncs->vkAllocateCommandBuffers(m_vkDev, &cmdBufInfo, &image.cmdBuf); + if (err != VK_SUCCESS) + qFatal("Failed to allocate frame command buffer: %d", err); + + VkCommandBufferBeginInfo cmdBufBeginInfo = { + VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr, 0, nullptr }; + err = m_devFuncs->vkBeginCommandBuffer(image.cmdBuf, &cmdBufBeginInfo); + if (err != VK_SUCCESS) + qFatal("Failed to begin frame command buffer: %d", err); + + static float g = 0; + g += 0.005f; + if (g > 1.0f) + g = 0.0f; + VkClearColorValue clearColor = { 0.0f, g, 0.0f, 1.0f }; + VkClearValue clearValues[1]; + clearValues[0].color = clearColor; + + VkRenderPassBeginInfo rpBeginInfo; + memset(&rpBeginInfo, 0, sizeof(rpBeginInfo)); + rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rpBeginInfo.renderPass = m_defaultRenderPass; + rpBeginInfo.framebuffer = image.fb; + rpBeginInfo.renderArea.extent.width = m_swapChainImageSize.width(); + rpBeginInfo.renderArea.extent.height = m_swapChainImageSize.height(); + rpBeginInfo.clearValueCount = 1; + rpBeginInfo.pClearValues = clearValues; + m_devFuncs->vkCmdBeginRenderPass(image.cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + m_devFuncs->vkCmdEndRenderPass(image.cmdBuf); + + err = m_devFuncs->vkEndCommandBuffer(image.cmdBuf); + if (err != VK_SUCCESS) + qFatal("Failed to end frame command buffer: %d", err); +} + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + QLoggingCategory::setFilterRules(QStringLiteral("qt.vulkan=true")); + + QVulkanInstance inst; + // Test the early queries for supported layers/exts. + qDebug() << inst.supportedLayers() << inst.supportedExtensions(); + + // Enable validation layer, if supported. + inst.setLayers(QByteArrayList() << "VK_LAYER_LUNARG_standard_validation"); + + bool ok = inst.create(); + qDebug("QVulkanInstance::create() returned %d", ok); + if (!ok) + return 1; + + VWindow w; + w.setVulkanInstance(&inst); + w.resize(1024, 768); + w.show(); + + return app.exec(); +} diff --git a/tests/manual/qvulkaninstance/qvulkaninstance.pro b/tests/manual/qvulkaninstance/qvulkaninstance.pro new file mode 100644 index 0000000000..7305da53c1 --- /dev/null +++ b/tests/manual/qvulkaninstance/qvulkaninstance.pro @@ -0,0 +1,6 @@ +TEMPLATE = app +TARGET = qvulkaninstance + +QT += gui-private + +SOURCES += main.cpp diff --git a/tests/manual/textrendering/textperformance/main.cpp b/tests/manual/textrendering/textperformance/main.cpp index 9bd6d036af..eb6d09b9c8 100644 --- a/tests/manual/textrendering/textperformance/main.cpp +++ b/tests/manual/textrendering/textperformance/main.cpp @@ -30,6 +30,7 @@ #include <QDialog> #include <QFontDatabase> #include <QPainter> +#include <QRandomGenerator> #include <QTime> #include <QTimer> @@ -93,17 +94,17 @@ public: static const QString text = QLatin1String("Qt rocks!!!"); static const int textsPerPaint = 30; for (int i = 0; i < textsPerPaint; i++) { - const int fontSize = 4 + (qrand() % 5); - const int fontWeight = (qrand() % 2) == 1 ? QFont::Normal : QFont::Bold; - const bool fontItalic = (qrand() % 2) == 1; + const int fontSize = 4 + QRandomGenerator::global()->bounded(5); + const int fontWeight = QRandomGenerator::global()->bounded(2) == 1 ? QFont::Normal : QFont::Bold; + const bool fontItalic = QRandomGenerator::global()->bounded(2) == 1; const QFont font("Default", fontSize, fontWeight, fontItalic); p.setFont(font); - p.setPen(QColor::fromHsv(qrand() % 359, 155 + qrand() % 100, - 155 + qrand() % 100, 100 + qrand() % 155)); + p.setPen(QColor::fromHsv(QRandomGenerator::global()->bounded(359), 155 + QRandomGenerator::global()->bounded(100), + 155 + QRandomGenerator::global()->bounded(100), 100 + QRandomGenerator::global()->bounded(155))); const QSize textSize(p.fontMetrics().boundingRect(text).size()); const QPoint position( - -textSize.width() / 2 + (qrand() % size.width()), - textSize.height() / 2 + (qrand() % size.height())); + -textSize.width() / 2 + QRandomGenerator::global()->bounded(size.width()), + textSize.height() / 2 + QRandomGenerator::global()->bounded(size.height())); p.drawText(position, text); } } @@ -126,8 +127,8 @@ public: QString text; for (int i = 0; i < piecesPerPaint; ++i) { - QString piece = QLatin1String(pieces[qrand() % piecesCount]); - if (i == 0 || qrand() % 2) { + QString piece = QLatin1String(pieces[QRandomGenerator::global()->bounded(piecesCount)]); + if (i == 0 || QRandomGenerator::global()->bounded(2)) { // Make this piece the beginning of a new sentence. piece[0] = piece[0].toUpper(); if (i > 0) @@ -160,7 +161,7 @@ public: for (int i = 0; i < systemsPerPaint; i++) { if (i > 0) text.append(QLatin1Char(' ')); - text.append(samples.at(qrand() % samples.count())); + text.append(samples.at(QRandomGenerator::global()->bounded(samples.count()))); } p.drawText(QRectF(QPointF(0, 0), QSizeF(size)), Qt::AlignTop | Qt::AlignAbsolute | Qt::TextWordWrap, text); diff --git a/tests/manual/widgets/itemviews/qtreewidget/main.cpp b/tests/manual/widgets/itemviews/qtreewidget/main.cpp index 5d129101fd..fb72c404a5 100644 --- a/tests/manual/widgets/itemviews/qtreewidget/main.cpp +++ b/tests/manual/widgets/itemviews/qtreewidget/main.cpp @@ -95,6 +95,18 @@ public: item5sl.append("Approver"); /* QTreeWidgetItem *item4 =*/ new QTreeWidgetItem(item4, item5sl); + treeWidget->setDragEnabled(true); + treeWidget->viewport()->setAcceptDrops(true); + treeWidget->setDragDropMode(QAbstractItemView::InternalMove); + + for (int u = 0; u < 12; ++u) { + const QString username = QString("Anonymous User %1").arg(u + 1); + QStringList info; + info << username << username << QString::number(u + 1) << QStringLiteral("Test user"); + new QTreeWidgetItem(item4, info); + } + + treeWidget->expandAll(); treeWidget->setColumnCount(item2sl.size()); QStringList itemInfo("First Name"); itemInfo.append("Last Name"); @@ -133,6 +145,7 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); ExampleDlg d; + d.resize(d.sizeHint() * 3); d.show(); app.exec(); } diff --git a/tests/manual/windowchildgeometry/controllerwidget.cpp b/tests/manual/windowchildgeometry/controllerwidget.cpp index 1d18c5d51b..871313d983 100644 --- a/tests/manual/windowchildgeometry/controllerwidget.cpp +++ b/tests/manual/windowchildgeometry/controllerwidget.cpp @@ -29,16 +29,12 @@ #include "controllerwidget.h" #include <controls.h> -#if QT_VERSION >= 0x050000 -# include <QtWidgets> -# include <QWindow> -# include <QBackingStore> -# include <QPaintDevice> -# include <QPainter> -#else -# include <QtGui> -#endif - +#include <QtWidgets> +#include <QWindow> +#include <QBackingStore> +#include <QPaintDevice> +#include <QPainter> +#include <QRandomGenerator> #include <QResizeEvent> CoordinateControl::CoordinateControl(const QString &sep) : m_x(new QSpinBox), m_y(new QSpinBox) @@ -280,7 +276,7 @@ public: explicit Window(QWindow *parent = 0) : QWindow(parent) , m_backingStore(new QBackingStore(this)) - , m_color(Qt::GlobalColor(qrand() % 18)) + , m_color(Qt::GlobalColor(QRandomGenerator::global()->bounded(18))) { setObjectName(QStringLiteral("window")); setTitle(tr("TestWindow")); diff --git a/tests/manual/windowflags/controllerwindow.cpp b/tests/manual/windowflags/controllerwindow.cpp index 9a12c8b2c9..4b380d5355 100644 --- a/tests/manual/windowflags/controllerwindow.cpp +++ b/tests/manual/windowflags/controllerwindow.cpp @@ -59,24 +59,26 @@ ControllerWidget::ControllerWidget(QWidget *parent) QLabel *label = new QLabel(tr("Parent window")); parentWindow->setCentralWidget(label); - previewWindow = new PreviewWindow; + previewWindow = new QWindow; previewWindow->installEventFilter(this); + previewWidget = new PreviewWidget; + previewWidget->installEventFilter(this); previewDialog = new PreviewDialog; previewDialog->installEventFilter(this); createTypeGroupBox(); hintsControl = new HintControl; - hintsControl->setHints(previewWindow->windowFlags()); + hintsControl->setHints(previewWidget->windowFlags()); connect(hintsControl, SIGNAL(changed(Qt::WindowFlags)), this, SLOT(updatePreview())); statesControl = new WindowStatesControl; - statesControl->setStates(previewWindow->windowState()); + statesControl->setStates(previewWidget->windowState()); statesControl->setVisibleValue(true); connect(statesControl, SIGNAL(changed()), this, SLOT(updatePreview())); typeControl = new TypeControl; - typeControl->setType(previewWindow->windowFlags()); + typeControl->setType(previewWidget->windowFlags()); connect(typeControl, SIGNAL(changed(Qt::WindowFlags)), this, SLOT(updatePreview())); QVBoxLayout *mainLayout = new QVBoxLayout(this); @@ -98,61 +100,99 @@ bool ControllerWidget::eventFilter(QObject *, QEvent *e) void ControllerWidget::updateStateControl() { - if (previewWidget) - statesControl->setStates(previewWidget->windowState()); + if (activePreview) + statesControl->setStates(activePreview->windowStates()); } -void ControllerWidget::updatePreview() +void ControllerWidget::updatePreview(QWindow *preview) { - const Qt::WindowFlags flags = typeControl->type() | hintsControl->hints(); + activePreview = preview; - if (previewWidgetButton->isChecked()) { - previewWidget = previewWindow; - previewDialog->hide(); - } else { - previewWidget = previewDialog; - previewWindow->hide(); - } + const Qt::WindowFlags flags = typeControl->type() | hintsControl->hints(); if (modalWindowCheckBox->isChecked()) { parentWindow->show(); - previewWidget->setWindowModality(Qt::WindowModal); - previewWidget->setParent(parentWindow); + preview->setModality(Qt::WindowModal); + preview->setParent(parentWindow->windowHandle()); } else { - previewWidget->setWindowModality(Qt::NonModal); - previewWidget->setParent(0); + preview->setModality(Qt::NonModal); + preview->setParent(0); parentWindow->hide(); } - if (previewWidgetButton->isChecked()) - previewWindow->setWindowFlags(flags); - else - previewDialog->setWindowFlags(flags); + preview->setFlags(flags); if (fixedSizeWindowCheckBox->isChecked()) { - previewWidget->setFixedSize(300, 300); + preview->setMinimumSize(QSize(300, 300)); + preview->setMaximumSize(QSize(300, 300)); } else { - previewWidget->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + preview->setMinimumSize(QSize(0, 0)); + preview->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); } - QPoint pos = previewWidget->pos(); + preview->setWindowStates(statesControl->states()); + preview->setVisible(statesControl->visibleValue()); +} + +void ControllerWidget::updatePreview(QWidget *preview) +{ + activePreview = preview->windowHandle(); + + const Qt::WindowFlags flags = typeControl->type() | hintsControl->hints(); + + if (modalWindowCheckBox->isChecked()) { + parentWindow->show(); + preview->setWindowModality(Qt::WindowModal); + preview->setParent(parentWindow); + } else { + preview->setWindowModality(Qt::NonModal); + preview->setParent(0); + parentWindow->hide(); + } + + preview->setWindowFlags(flags); + + QSize fixedSize = fixedSizeWindowCheckBox->isChecked() ? + QSize(300, 300) : QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + preview->setFixedSize(fixedSize); + + QPoint pos = preview->pos(); if (pos.x() < 0) pos.setX(0); if (pos.y() < 0) pos.setY(0); - previewWidget->move(pos); + preview->move(pos); + + preview->setWindowState(statesControl->states()); + preview->setVisible(statesControl->visibleValue()); +} - previewWidget->setWindowState(statesControl->states()); - previewWidget->setVisible(statesControl->visibleValue()); +void ControllerWidget::updatePreview() +{ + if (previewWindowButton->isChecked()) { + previewDialog->hide(); + previewWidget->close(); + updatePreview(previewWindow); + } else if (previewWidgetButton->isChecked()) { + previewWindow->hide(); + previewDialog->hide(); + updatePreview(previewWidget); + } else { + previewWindow->hide(); + previewWidget->close(); + updatePreview(previewDialog); + } } void ControllerWidget::createTypeGroupBox() { - widgetTypeGroupBox = new QGroupBox(tr("Widget Type")); + widgetTypeGroupBox = new QGroupBox(tr("Window Type")); + previewWindowButton = createRadioButton(tr("QWindow")); previewWidgetButton = createRadioButton(tr("QWidget")); - previewWidgetButton->setChecked(true); previewDialogButton = createRadioButton(tr("QDialog")); + previewWindowButton->setChecked(true); QHBoxLayout *l = new QHBoxLayout; + l->addWidget(previewWindowButton); l->addWidget(previewWidgetButton); l->addWidget(previewDialogButton); widgetTypeGroupBox->setLayout(l); diff --git a/tests/manual/windowflags/controllerwindow.h b/tests/manual/windowflags/controllerwindow.h index 43a125a9ae..c623256112 100644 --- a/tests/manual/windowflags/controllerwindow.h +++ b/tests/manual/windowflags/controllerwindow.h @@ -60,20 +60,27 @@ private slots: void updateStateControl(); private: + void updatePreview(QWindow *); + void updatePreview(QWidget *); void createTypeGroupBox(); QCheckBox *createCheckBox(const QString &text); QRadioButton *createRadioButton(const QString &text); QMainWindow *parentWindow; - PreviewWindow *previewWindow; + + QWindow *previewWindow; + PreviewWidget *previewWidget; PreviewDialog *previewDialog; - QWidget *previewWidget; + + QWindow *activePreview; + QGroupBox *widgetTypeGroupBox; QGroupBox *additionalOptionsGroupBox; TypeControl *typeControl; HintControl *hintsControl; WindowStatesControl *statesControl; + QRadioButton *previewWindowButton; QRadioButton *previewWidgetButton; QRadioButton *previewDialogButton; QCheckBox *modalWindowCheckBox; diff --git a/tests/manual/windowflags/main.cpp b/tests/manual/windowflags/main.cpp index a7d7307525..4da878d8cc 100644 --- a/tests/manual/windowflags/main.cpp +++ b/tests/manual/windowflags/main.cpp @@ -43,5 +43,6 @@ int main(int argc, char *argv[]) if (!arguments.contains(QLatin1String("-e"))) controller.registerEventFilter(); controller.show(); + controller.lower(); return app.exec(); } diff --git a/tests/manual/windowflags/previewwindow.cpp b/tests/manual/windowflags/previewwindow.cpp index 65a287f788..19473c9eee 100644 --- a/tests/manual/windowflags/previewwindow.cpp +++ b/tests/manual/windowflags/previewwindow.cpp @@ -172,37 +172,37 @@ static QPlainTextEdit *createControlPanel(QWidget *widget) QGridLayout *buttonLayout = new QGridLayout; bottomLayout->addStretch(); bottomLayout->addLayout(buttonLayout); - QPushButton *showNormalButton = new QPushButton(PreviewWindow::tr("Show normal")); + QPushButton *showNormalButton = new QPushButton(PreviewWidget::tr("Show normal")); QObject::connect(showNormalButton, SIGNAL(clicked()), widget, SLOT(showNormal())); buttonLayout->addWidget(showNormalButton, 0, 0); - QPushButton *showMinimizedButton = new QPushButton(PreviewWindow::tr("Show minimized")); + QPushButton *showMinimizedButton = new QPushButton(PreviewWidget::tr("Show minimized")); QObject::connect(showMinimizedButton, SIGNAL(clicked()), widget, SLOT(showMinimized())); buttonLayout->addWidget(showMinimizedButton, 0, 1); - QPushButton *showMaximizedButton = new QPushButton(PreviewWindow::tr("Show maximized")); + QPushButton *showMaximizedButton = new QPushButton(PreviewWidget::tr("Show maximized")); QObject::connect(showMaximizedButton, SIGNAL(clicked()), widget, SLOT(showMaximized())); buttonLayout->addWidget(showMaximizedButton, 0, 2); - QPushButton *showFullScreenButton = new QPushButton(PreviewWindow::tr("Show fullscreen")); + QPushButton *showFullScreenButton = new QPushButton(PreviewWidget::tr("Show fullscreen")); QObject::connect(showFullScreenButton, SIGNAL(clicked()), widget, SLOT(showFullScreen())); buttonLayout->addWidget(showFullScreenButton, 0, 3); - QPushButton *updateInfoButton = new QPushButton(PreviewWindow::tr("&Update Info")); + QPushButton *updateInfoButton = new QPushButton(PreviewWidget::tr("&Update Info")); QObject::connect(updateInfoButton, SIGNAL(clicked()), widget, SLOT(updateInfo())); buttonLayout->addWidget(updateInfoButton, 1, 0); - QPushButton *closeButton = new QPushButton(PreviewWindow::tr("&Close")); + QPushButton *closeButton = new QPushButton(PreviewWidget::tr("&Close")); QObject::connect(closeButton, SIGNAL(clicked()), widget, SLOT(close())); buttonLayout->addWidget(closeButton, 1, 3); return textEdit; } -PreviewWindow::PreviewWindow(QWidget *parent) +PreviewWidget::PreviewWidget(QWidget *parent) : QWidget(parent) { textEdit = createControlPanel(this); setWindowTitle(tr("Preview <QWidget> Qt %1").arg(QLatin1String(QT_VERSION_STR))); } -bool PreviewWindow::event(QEvent *event) +bool PreviewWidget::event(QEvent *event) { const bool ret = QWidget::event(event); @@ -219,7 +219,7 @@ bool PreviewWindow::event(QEvent *event) return ret; } -void PreviewWindow::setWindowFlags(Qt::WindowFlags flags) +void PreviewWidget::setWindowFlags(Qt::WindowFlags flags) { if (flags == windowFlags()) return; @@ -227,7 +227,7 @@ void PreviewWindow::setWindowFlags(Qt::WindowFlags flags) QTimer::singleShot(0, this, SLOT(updateInfo())); } -void PreviewWindow::updateInfo() +void PreviewWidget::updateInfo() { textEdit->setPlainText(formatWidgetInfo(this)); } diff --git a/tests/manual/windowflags/previewwindow.h b/tests/manual/windowflags/previewwindow.h index 9730e7a3f9..023ddd910c 100644 --- a/tests/manual/windowflags/previewwindow.h +++ b/tests/manual/windowflags/previewwindow.h @@ -35,12 +35,12 @@ QT_BEGIN_NAMESPACE class QPlainTextEdit; QT_END_NAMESPACE -class PreviewWindow : public QWidget +class PreviewWidget : public QWidget { Q_OBJECT public: - PreviewWindow(QWidget *parent = 0); + PreviewWidget(QWidget *parent = 0); void setWindowFlags(Qt::WindowFlags flags); |