summaryrefslogtreecommitdiffstats
path: root/tests/manual
diff options
context:
space:
mode:
Diffstat (limited to 'tests/manual')
-rw-r--r--tests/manual/cocoa/qt_on_cocoa/main.mm50
-rw-r--r--tests/manual/cocoa/qt_on_cocoa/rasterwindow.cpp32
-rw-r--r--tests/manual/cocoa/qt_on_cocoa/rasterwindow.h3
-rw-r--r--tests/manual/filetest/main.cpp55
-rw-r--r--tests/manual/manual.pro2
-rw-r--r--tests/manual/network_remote_stresstest/tst_network_remote_stresstest.cpp2
-rw-r--r--tests/manual/network_stresstest/tst_network_stresstest.cpp2
-rw-r--r--tests/manual/qtabletevent/regular_widgets/main.cpp72
-rw-r--r--tests/manual/qvulkaninstance/main.cpp713
-rw-r--r--tests/manual/qvulkaninstance/qvulkaninstance.pro6
-rw-r--r--tests/manual/widgets/itemviews/qtreewidget/main.cpp13
-rw-r--r--tests/manual/windowflags/controllerwindow.cpp102
-rw-r--r--tests/manual/windowflags/controllerwindow.h11
-rw-r--r--tests/manual/windowflags/main.cpp1
-rw-r--r--tests/manual/windowflags/previewwindow.cpp20
-rw-r--r--tests/manual/windowflags/previewwindow.h4
16 files changed, 982 insertions, 106 deletions
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/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/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);