1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "hellovulkanwidget.h"
52#include <QVulkanFunctions>
53#include <QApplication>
54#include <QVBoxLayout>
55#include <QPlainTextEdit>
56#include <QPushButton>
57#include <QLCDNumber>
58#include <QFileDialog>
59#include <QMessageBox>
60#include <QTabWidget>
61
62MainWindow::MainWindow(VulkanWindow *w, QPlainTextEdit *logWidget)
63 : m_window(w)
64{
65 QWidget *wrapper = QWidget::createWindowContainer(w);
66
67 m_info = new QPlainTextEdit;
68 m_info->setReadOnly(true);
69
70 m_number = new QLCDNumber(3);
71 m_number->setSegmentStyle(QLCDNumber::Filled);
72
73 QPushButton *grabButton = new QPushButton(tr("&Grab"));
74 grabButton->setFocusPolicy(Qt::NoFocus);
75
76 connect(grabButton, &QPushButton::clicked, this, &MainWindow::onGrabRequested);
77
78 QPushButton *quitButton = new QPushButton(tr("&Quit"));
79 quitButton->setFocusPolicy(Qt::NoFocus);
80
81 connect(quitButton, &QPushButton::clicked, qApp, &QCoreApplication::quit);
82
83 QVBoxLayout *layout = new QVBoxLayout;
84 m_infoTab = new QTabWidget(this);
85 m_infoTab->addTab(m_info, tr("Vulkan Info"));
86 m_infoTab->addTab(logWidget, tr("Debug Log"));
87 layout->addWidget(m_infoTab, 2);
88 layout->addWidget(m_number, 1);
89 layout->addWidget(wrapper, 5);
90 layout->addWidget(grabButton, 1);
91 layout->addWidget(quitButton, 1);
92 setLayout(layout);
93}
94
95void MainWindow::onVulkanInfoReceived(const QString &text)
96{
97 m_info->setPlainText(text);
98}
99
100void MainWindow::onFrameQueued(int colorValue)
101{
102 m_number->display(colorValue);
103}
104
105void MainWindow::onGrabRequested()
106{
107 if (!m_window->supportsGrab()) {
108 QMessageBox::warning(this, tr("Cannot grab"), tr("This swapchain does not support readbacks."));
109 return;
110 }
111
112 QImage img = m_window->grab();
113
114 // Our startNextFrame() implementation is synchronous so img is ready to be
115 // used right here.
116
117 QFileDialog fd(this);
118 fd.setAcceptMode(QFileDialog::AcceptSave);
119 fd.setDefaultSuffix("png");
120 fd.selectFile("test.png");
121 if (fd.exec() == QDialog::Accepted)
122 img.save(fd.selectedFiles().first());
123}
124
125QVulkanWindowRenderer *VulkanWindow::createRenderer()
126{
127 return new VulkanRenderer(this);
128}
129
130VulkanRenderer::VulkanRenderer(VulkanWindow *w)
131 : TriangleRenderer(w)
132{
133}
134
135void VulkanRenderer::initResources()
136{
137 TriangleRenderer::initResources();
138
139 QVulkanInstance *inst = m_window->vulkanInstance();
140 m_devFuncs = inst->deviceFunctions(m_window->device());
141
142 QString info;
143 info += QString::asprintf("Number of physical devices: %d\n", int(m_window->availablePhysicalDevices().count()));
144
145 QVulkanFunctions *f = inst->functions();
146 VkPhysicalDeviceProperties props;
147 f->vkGetPhysicalDeviceProperties(m_window->physicalDevice(), &props);
148 info += QString::asprintf("Active physical device name: '%s' version %d.%d.%d\nAPI version %d.%d.%d\n",
149 props.deviceName,
150 VK_VERSION_MAJOR(props.driverVersion), VK_VERSION_MINOR(props.driverVersion),
151 VK_VERSION_PATCH(props.driverVersion),
152 VK_VERSION_MAJOR(props.apiVersion), VK_VERSION_MINOR(props.apiVersion),
153 VK_VERSION_PATCH(props.apiVersion));
154
155 info += QStringLiteral("Supported instance layers:\n");
156 for (const QVulkanLayer &layer : inst->supportedLayers())
157 info += QString::asprintf(" %s v%u\n", layer.name.constData(), layer.version);
158 info += QStringLiteral("Enabled instance layers:\n");
159 for (const QByteArray &layer : inst->layers())
160 info += QString::asprintf(" %s\n", layer.constData());
161
162 info += QStringLiteral("Supported instance extensions:\n");
163 for (const QVulkanExtension &ext : inst->supportedExtensions())
164 info += QString::asprintf(" %s v%u\n", ext.name.constData(), ext.version);
165 info += QStringLiteral("Enabled instance extensions:\n");
166 for (const QByteArray &ext : inst->extensions())
167 info += QString::asprintf(" %s\n", ext.constData());
168
169 info += QString::asprintf("Color format: %u\nDepth-stencil format: %u\n",
170 m_window->colorFormat(), m_window->depthStencilFormat());
171
172 info += QStringLiteral("Supported sample counts:");
173 const QList<int> sampleCounts = m_window->supportedSampleCounts();
174 for (int count : sampleCounts)
175 info += QLatin1Char(' ') + QString::number(count);
176 info += QLatin1Char('\n');
177
178 emit static_cast<VulkanWindow *>(m_window)->vulkanInfoReceived(info);
179}
180
181void VulkanRenderer::startNextFrame()
182{
183 TriangleRenderer::startNextFrame();
184 emit static_cast<VulkanWindow *>(m_window)->frameQueued(int(m_rotation) % 360);
185}
186