summaryrefslogtreecommitdiffstats
path: root/tests/manual
diff options
context:
space:
mode:
Diffstat (limited to 'tests/manual')
-rw-r--r--tests/manual/foreignwindows/main.cpp24
-rw-r--r--tests/manual/qlocale/calendar.cpp4
-rw-r--r--tests/manual/qlocale/calendar.h4
-rw-r--r--tests/manual/rhi/hellominimalcrossgfxtriangle/CMakeLists.txt8
-rw-r--r--tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.cpp550
-rw-r--r--tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.pro10
-rw-r--r--tests/manual/rhi/hellominimalcrossgfxtriangle/hellowindow.cpp159
-rw-r--r--tests/manual/rhi/hellominimalcrossgfxtriangle/hellowindow.h78
-rw-r--r--tests/manual/rhi/hellominimalcrossgfxtriangle/main.cpp171
-rw-r--r--tests/manual/rhi/hellominimalcrossgfxtriangle/window.cpp255
-rw-r--r--tests/manual/rhi/hellominimalcrossgfxtriangle/window.h111
-rw-r--r--tests/manual/startsystemmove/main.cpp111
-rw-r--r--tests/manual/startsystemmove/startsystemmove.pro4
13 files changed, 916 insertions, 573 deletions
diff --git a/tests/manual/foreignwindows/main.cpp b/tests/manual/foreignwindows/main.cpp
index 44aff54773..5e882b6d9c 100644
--- a/tests/manual/foreignwindows/main.cpp
+++ b/tests/manual/foreignwindows/main.cpp
@@ -59,9 +59,9 @@
QT_USE_NAMESPACE
-typedef QSharedPointer<QWidget> WidgetPtr;
-typedef QList<WidgetPtr> WidgetPtrList;
-typedef QList<WId> WIdList;
+using WidgetPtr = QSharedPointer<QWidget>;
+using WidgetPtrList = QVector<WidgetPtr>;
+using WIdList = QVector<WId>;
// Create some pre-defined Windows controls by class name
static WId createInternalWindow(const QString &name)
@@ -74,7 +74,7 @@ static WId createInternalWindow(const QString &name)
CreateWindowEx(0, reinterpret_cast<const wchar_t *>(name.utf16()),
L"NativeCtrl", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
- 0, 0, GetModuleHandle(NULL), NULL);
+ nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
if (hwnd) {
SetWindowText(hwnd, L"Demo");
result = WId(hwnd);
@@ -179,7 +179,7 @@ void WindowDumper::dump() const
debug << '#' << n++;
if (m_watchedWindows.size() > 1)
debug << '\n';
- foreach (const QWindow *w, m_watchedWindows) {
+ for (const QWindow *w : m_watchedWindows) {
const QPoint globalPos = w->mapToGlobal(QPoint());
debug << " " << w << " pos=" << globalPos.x() << ',' << globalPos.y() << '\n';
}
@@ -212,7 +212,7 @@ struct EventFilterOption
QtDiag::EventFilter::EventCategories categories;
};
-EventFilterOption eventFilterOptions[] = {
+static EventFilterOption eventFilterOptions[] = {
{"mouse-events", "Dump mouse events.", QtDiag::EventFilter::MouseEvents},
{"keyboard-events", "Dump keyboard events.", QtDiag::EventFilter::KeyEvents},
{"state-events", "Dump state/focus change events.", QtDiag::EventFilter::StateChangeEvents | QtDiag::EventFilter::FocusEvents}
@@ -248,11 +248,10 @@ int main(int argc, char *argv[])
parser.addOption(outputAllOption);
QCommandLineOption continuousOption(QStringList() << QStringLiteral("c") << QStringLiteral("continuous"),
QStringLiteral("Output continuously."));
- parser.addOption(outputAllOption);
+ parser.addOption(continuousOption);
QCommandLineOption moveOption(QStringList() << QStringLiteral("m") << QStringLiteral("move"),
QStringLiteral("Move window to top left corner."));
parser.addOption(moveOption);
- parser.addOption(continuousOption);
QCommandLineOption embedOption(QStringList() << QStringLiteral("e") << QStringLiteral("embed"),
QStringLiteral("Embed a foreign window into a Qt widget."));
parser.addOption(embedOption);
@@ -271,7 +270,7 @@ int main(int argc, char *argv[])
}
QWindowList windows;
- foreach (const QString &argument, parser.positionalArguments()) {
+ for (const QString &argument : parser.positionalArguments()) {
bool ok = true;
WId wid = createInternalWindow(argument);
if (!wid)
@@ -295,7 +294,7 @@ int main(int argc, char *argv[])
int exitCode = 0;
if (parser.isSet(embedOption)) {
- QtDiag::EventFilter::EventCategories eventCategories = 0;
+ QtDiag::EventFilter::EventCategories eventCategories;
for (int i = 0; i < eventFilterOptionCount; ++i) {
if (parser.isSet(QLatin1String(eventFilterOptions[i].name)))
eventCategories |= eventFilterOptions[i].categories;
@@ -303,11 +302,11 @@ int main(int argc, char *argv[])
if (eventCategories)
app.installEventFilter(new QtDiag::EventFilter(eventCategories, &app));
- const QRect availableGeometry = QApplication::desktop()->availableGeometry(0);
+ const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry();
QPoint pos = availableGeometry.topLeft() + QPoint(availableGeometry.width(), availableGeometry.height()) / 3;
WidgetPtrList mainWindows;
- foreach (QWindow *window, windows) {
+ for (QWindow *window : qAsConst(windows)) {
WidgetPtr mainWindow(new EmbeddingWindow(window));
mainWindow->move(pos);
mainWindow->resize(availableGeometry.size() / 4);
@@ -324,7 +323,6 @@ int main(int argc, char *argv[])
QObject::connect(timer, &QTimer::timeout, &dumper, &WindowDumper::dump);
timer->start(1000);
exitCode = app.exec();
-
} else {
WindowDumper(windows).dump();
}
diff --git a/tests/manual/qlocale/calendar.cpp b/tests/manual/qlocale/calendar.cpp
index 4295e13342..f127c81656 100644
--- a/tests/manual/qlocale/calendar.cpp
+++ b/tests/manual/qlocale/calendar.cpp
@@ -94,13 +94,13 @@ void CalendarWidget::selectedDateChanged()
currentDateEdit->setDate(calendar->selectedDate());
}
-void CalendarWidget::minimumDateChanged(const QDate &date)
+void CalendarWidget::minimumDateChanged(QDate date)
{
calendar->setMinimumDate(date);
maximumDateEdit->setDate(calendar->maximumDate());
}
-void CalendarWidget::maximumDateChanged(const QDate &date)
+void CalendarWidget::maximumDateChanged(QDate date)
{
calendar->setMaximumDate(date);
minimumDateEdit->setDate(calendar->minimumDate());
diff --git a/tests/manual/qlocale/calendar.h b/tests/manual/qlocale/calendar.h
index aee73ef82a..6a72a4e2d2 100644
--- a/tests/manual/qlocale/calendar.h
+++ b/tests/manual/qlocale/calendar.h
@@ -55,8 +55,8 @@ private slots:
void horizontalHeaderChanged(int index);
void verticalHeaderChanged(int index);
void selectedDateChanged();
- void minimumDateChanged(const QDate &date);
- void maximumDateChanged(const QDate &date);
+ void minimumDateChanged(QDate date);
+ void maximumDateChanged(QDate date);
void updateWeekendDays();
void weekdayFormatChanged();
void weekendFormatChanged();
diff --git a/tests/manual/rhi/hellominimalcrossgfxtriangle/CMakeLists.txt b/tests/manual/rhi/hellominimalcrossgfxtriangle/CMakeLists.txt
index d933d8ae88..8b9d3389f8 100644
--- a/tests/manual/rhi/hellominimalcrossgfxtriangle/CMakeLists.txt
+++ b/tests/manual/rhi/hellominimalcrossgfxtriangle/CMakeLists.txt
@@ -5,13 +5,13 @@
#####################################################################
add_qt_manual_test(hellominimalcrossgfxtriangle
- GUI
SOURCES
- hellominimalcrossgfxtriangle.cpp
- LIBRARIES
- Qt::GuiPrivate
+ hellowindow.cpp hellowindow.h
+ main.cpp
+ window.cpp window.h
PUBLIC_LIBRARIES
Qt::Gui
+ Qt::GuiPrivate
)
# Resources:
diff --git a/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.cpp b/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.cpp
deleted file mode 100644
index 9b03a48bfe..0000000000
--- a/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.cpp
+++ /dev/null
@@ -1,550 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** 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.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-// This is a compact, minimal, single-file demo of deciding the backend at
-// runtime while using the exact same shaders and rendering code without any
-// branching whatsoever once the QWindow is up and the RHI is initialized.
-
-#include <QGuiApplication>
-#include <QCommandLineParser>
-#include <QWindow>
-#include <QPlatformSurfaceEvent>
-#include <QElapsedTimer>
-
-#include <QtGui/private/qshader_p.h>
-#include <QFile>
-
-#include <QtGui/private/qrhinull_p.h>
-
-#ifndef QT_NO_OPENGL
-#include <QtGui/private/qrhigles2_p.h>
-#include <QOffscreenSurface>
-#endif
-
-#if QT_CONFIG(vulkan)
-#include <QLoggingCategory>
-#include <QtGui/private/qrhivulkan_p.h>
-#endif
-
-#ifdef Q_OS_WIN
-#include <QtGui/private/qrhid3d11_p.h>
-#endif
-
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
-#include <QtGui/private/qrhimetal_p.h>
-#endif
-
-static float vertexData[] = {
- // Y up (note clipSpaceCorrMatrix in m_proj), CCW
- 0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
- -0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
- 0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
-};
-
-static QShader getShader(const QString &name)
-{
- QFile f(name);
- if (f.open(QIODevice::ReadOnly))
- return QShader::fromSerialized(f.readAll());
-
- return QShader();
-}
-
-enum GraphicsApi
-{
- OpenGL,
- Vulkan,
- D3D11,
- Metal,
- Null
-};
-
-static GraphicsApi graphicsApi;
-
-static QString graphicsApiName()
-{
- switch (graphicsApi) {
- case OpenGL:
- return QLatin1String("OpenGL 2.x");
- case Vulkan:
- return QLatin1String("Vulkan");
- case D3D11:
- return QLatin1String("Direct3D 11");
- case Metal:
- return QLatin1String("Metal");
- case Null:
- return QLatin1String("Null");
- default:
- break;
- }
- return QString();
-}
-
-class Window : public QWindow
-{
-public:
- Window();
- ~Window();
-
- void init();
- void releaseResources();
- void resizeSwapChain();
- void releaseSwapChain();
- void render();
-
- void exposeEvent(QExposeEvent *) override;
- bool event(QEvent *) override;
-
-private:
- bool m_running = false;
- bool m_notExposed = false;
- bool m_newlyExposed = false;
-
- QRhi *m_r = nullptr;
- bool m_hasSwapChain = false;
- QRhiSwapChain *m_sc = nullptr;
- QRhiRenderBuffer *m_ds = nullptr;
- QRhiRenderPassDescriptor *m_rp = nullptr;
- QRhiBuffer *m_vbuf = nullptr;
- bool m_vbufReady = false;
- QRhiBuffer *m_ubuf = nullptr;
- QRhiShaderResourceBindings *m_srb = nullptr;
- QRhiGraphicsPipeline *m_ps = nullptr;
- QVector<QRhiResource *> releasePool;
-
- QMatrix4x4 m_proj;
- float m_rotation = 0;
- float m_opacity = 1;
- int m_opacityDir = -1;
-
- QElapsedTimer m_timer;
- qint64 m_elapsedMs;
- int m_elapsedCount;
-
-#ifndef QT_NO_OPENGL
- QOffscreenSurface *m_fallbackSurface = nullptr;
-#endif
-};
-
-Window::Window()
-{
- // Tell the platform plugin what we want.
- switch (graphicsApi) {
- case OpenGL:
-#if QT_CONFIG(opengl)
- setSurfaceType(OpenGLSurface);
- setFormat(QRhiGles2InitParams::adjustedFormat());
-#endif
- break;
- case Vulkan:
- setSurfaceType(VulkanSurface);
- break;
- case D3D11:
- setSurfaceType(OpenGLSurface); // not a typo
- break;
- case Metal:
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
- setSurfaceType(MetalSurface);
-#endif
- break;
- default:
- break;
- }
-}
-
-Window::~Window()
-{
- releaseResources();
-}
-
-void Window::exposeEvent(QExposeEvent *)
-{
- // initialize and start rendering when the window becomes usable for graphics purposes
- if (isExposed() && !m_running) {
- m_running = true;
- init();
- resizeSwapChain();
- }
-
- // stop pushing frames when not exposed (or size is 0)
- if ((!isExposed() || (m_hasSwapChain && m_sc->surfacePixelSize().isEmpty())) && m_running)
- m_notExposed = true;
-
- // continue when exposed again and the surface has a valid size.
- // note that the surface size can be (0, 0) even though size() reports a valid one...
- if (isExposed() && m_running && m_notExposed && !m_sc->surfacePixelSize().isEmpty()) {
- m_notExposed = false;
- m_newlyExposed = true;
- }
-
- // always render a frame on exposeEvent() (when exposed) in order to update
- // immediately on window resize.
- if (isExposed() && !m_sc->surfacePixelSize().isEmpty())
- render();
-}
-
-bool Window::event(QEvent *e)
-{
- switch (e->type()) {
- case QEvent::UpdateRequest:
- render();
- break;
-
- case QEvent::PlatformSurface:
- // this is the proper time to tear down the swapchain (while the native window and surface are still around)
- if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)
- releaseSwapChain();
- break;
-
- default:
- break;
- }
-
- return QWindow::event(e);
-}
-
-void Window::init()
-{
- if (graphicsApi == Null) {
- QRhiNullInitParams params;
- m_r = QRhi::create(QRhi::Null, &params);
- }
-
-#ifndef QT_NO_OPENGL
- if (graphicsApi == OpenGL) {
- m_fallbackSurface = QRhiGles2InitParams::newFallbackSurface();
- QRhiGles2InitParams params;
- params.fallbackSurface = m_fallbackSurface;
- params.window = this;
- m_r = QRhi::create(QRhi::OpenGLES2, &params);
- }
-#endif
-
-#if QT_CONFIG(vulkan)
- if (graphicsApi == Vulkan) {
- QRhiVulkanInitParams params;
- params.inst = vulkanInstance();
- params.window = this;
- m_r = QRhi::create(QRhi::Vulkan, &params);
- }
-#endif
-
-#ifdef Q_OS_WIN
- if (graphicsApi == D3D11) {
- QRhiD3D11InitParams params;
- m_r = QRhi::create(QRhi::D3D11, &params);
- }
-#endif
-
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
- if (graphicsApi == Metal) {
- QRhiMetalInitParams params;
- m_r = QRhi::create(QRhi::Metal, &params);
- }
-#endif
-
- if (!m_r)
- qFatal("Failed to create RHI backend");
-
- // now onto the backend-independent init
-
- m_sc = m_r->newSwapChain();
- // allow depth-stencil, although we do not actually enable depth test/write for the triangle
- m_ds = m_r->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
- QSize(), // no need to set the size here, due to UsedWithSwapChainOnly
- 1,
- QRhiRenderBuffer::UsedWithSwapChainOnly);
- releasePool << m_ds;
- m_sc->setWindow(this);
- m_sc->setDepthStencil(m_ds);
- m_rp = m_sc->newCompatibleRenderPassDescriptor();
- releasePool << m_rp;
- m_sc->setRenderPassDescriptor(m_rp);
-
- m_vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData));
- releasePool << m_vbuf;
- m_vbuf->build();
- m_vbufReady = false;
-
- m_ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68);
- releasePool << m_ubuf;
- m_ubuf->build();
-
- m_srb = m_r->newShaderResourceBindings();
- releasePool << m_srb;
- m_srb->setBindings({
- QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, m_ubuf)
- });
- m_srb->build();
-
- m_ps = m_r->newGraphicsPipeline();
- releasePool << m_ps;
-
- QRhiGraphicsPipeline::TargetBlend premulAlphaBlend;
- premulAlphaBlend.enable = true;
- m_ps->setTargetBlends({ premulAlphaBlend });
-
- const QShader vs = getShader(QLatin1String(":/color.vert.qsb"));
- if (!vs.isValid())
- qFatal("Failed to load shader pack (vertex)");
- const QShader fs = getShader(QLatin1String(":/color.frag.qsb"));
- if (!fs.isValid())
- qFatal("Failed to load shader pack (fragment)");
-
- m_ps->setShaderStages({
- { QRhiShaderStage::Vertex, vs },
- { QRhiShaderStage::Fragment, fs }
- });
-
- QRhiVertexInputLayout inputLayout;
- inputLayout.setBindings({
- { 5 * sizeof(float) }
- });
- inputLayout.setAttributes({
- { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
- { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) }
- });
-
- m_ps->setVertexInputLayout(inputLayout);
- m_ps->setShaderResourceBindings(m_srb);
- m_ps->setRenderPassDescriptor(m_rp);
-
- m_ps->build();
-}
-
-void Window::releaseResources()
-{
- qDeleteAll(releasePool);
- releasePool.clear();
-
- delete m_sc; // native swapchain is likely released already
- m_sc = nullptr;
-
- delete m_r;
-
-#ifndef QT_NO_OPENGL
- delete m_fallbackSurface;
-#endif
-}
-
-void Window::resizeSwapChain()
-{
- m_hasSwapChain = m_sc->buildOrResize(); // also handles m_ds
-
- m_elapsedMs = 0;
- m_elapsedCount = 0;
-
- const QSize outputSize = m_sc->currentPixelSize();
- m_proj = m_r->clipSpaceCorrMatrix();
- m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 100.0f);
- m_proj.translate(0, 0, -4);
-}
-
-void Window::releaseSwapChain()
-{
- if (m_hasSwapChain) {
- m_hasSwapChain = false;
- m_sc->release();
- }
-}
-
-void Window::render()
-{
- if (!m_hasSwapChain || m_notExposed)
- return;
-
- // If the window got resized or got newly exposed, resize the swapchain.
- // (the newly-exposed case is not actually required by some
- // platforms/backends, but f.ex. Vulkan on Windows seems to need it)
- if (m_sc->currentPixelSize() != m_sc->surfacePixelSize() || m_newlyExposed) {
- resizeSwapChain();
- if (!m_hasSwapChain)
- return;
- m_newlyExposed = false;
- }
-
- // Start a new frame. This is where we block when too far ahead of
- // GPU/present, and that's what throttles the thread to the refresh rate.
- // (except for OpenGL where it happens either in endFrame or somewhere else
- // depending on the GL implementation)
- QRhi::FrameOpResult r = m_r->beginFrame(m_sc);
- if (r == QRhi::FrameOpSwapChainOutOfDate) {
- resizeSwapChain();
- if (!m_hasSwapChain)
- return;
- r = m_r->beginFrame(m_sc);
- }
- if (r != QRhi::FrameOpSuccess) {
- requestUpdate();
- return;
- }
-
- if (m_elapsedCount)
- m_elapsedMs += m_timer.elapsed();
- m_timer.restart();
- m_elapsedCount += 1;
- if (m_elapsedMs >= 4000) {
- qDebug("%f", m_elapsedCount / 4.0f);
- m_elapsedMs = 0;
- m_elapsedCount = 0;
- }
-
- // Set up buffer updates.
- QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch();
- if (!m_vbufReady) {
- m_vbufReady = true;
- u->uploadStaticBuffer(m_vbuf, vertexData);
- }
- m_rotation += 1.0f;
- QMatrix4x4 mvp = m_proj;
- mvp.rotate(m_rotation, 0, 1, 0);
- u->updateDynamicBuffer(m_ubuf, 0, 64, mvp.constData());
- m_opacity += m_opacityDir * 0.005f;
- if (m_opacity < 0.0f || m_opacity > 1.0f) {
- m_opacityDir *= -1;
- m_opacity = qBound(0.0f, m_opacity, 1.0f);
- }
- u->updateDynamicBuffer(m_ubuf, 64, 4, &m_opacity);
-
- QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
- const QSize outputSizeInPixels = m_sc->currentPixelSize();
-
- // Apply buffer updates, clear, start the renderpass (where applicable).
- cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }, u);
-
- cb->setGraphicsPipeline(m_ps);
- cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
- cb->setShaderResources();
-
- const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf, 0);
- cb->setVertexInput(0, 1, &vbufBinding);
- cb->draw(3);
-
- cb->endPass();
-
- // Submit.
- m_r->endFrame(m_sc);
-
- requestUpdate(); // render continuously, throttled by the presentation rate (due to beginFrame above)
-}
-
-int main(int argc, char **argv)
-{
- QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
- QGuiApplication app(argc, argv);
-
- // Defaults.
-#if defined(Q_OS_WIN)
- graphicsApi = D3D11;
-#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
- graphicsApi = Metal;
-#elif QT_CONFIG(vulkan)
- graphicsApi = Vulkan;
-#else
- graphicsApi = OpenGL;
-#endif
-
- // Allow overriding via the command line.
- QCommandLineParser cmdLineParser;
- cmdLineParser.addHelpOption();
- QCommandLineOption glOption({ "g", "opengl" }, QLatin1String("OpenGL (2.x)"));
- cmdLineParser.addOption(glOption);
- QCommandLineOption vkOption({ "v", "vulkan" }, QLatin1String("Vulkan"));
- cmdLineParser.addOption(vkOption);
- QCommandLineOption d3dOption({ "d", "d3d11" }, QLatin1String("Direct3D 11"));
- cmdLineParser.addOption(d3dOption);
- QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal"));
- cmdLineParser.addOption(mtlOption);
- QCommandLineOption nullOption({ "n", "null" }, QLatin1String("Null"));
- cmdLineParser.addOption(nullOption);
- cmdLineParser.process(app);
- if (cmdLineParser.isSet(glOption))
- graphicsApi = OpenGL;
- if (cmdLineParser.isSet(vkOption))
- graphicsApi = Vulkan;
- if (cmdLineParser.isSet(d3dOption))
- graphicsApi = D3D11;
- if (cmdLineParser.isSet(mtlOption))
- graphicsApi = Metal;
- if (cmdLineParser.isSet(nullOption))
- graphicsApi = Null;
-
- // Vulkan setup.
-#if QT_CONFIG(vulkan)
- QVulkanInstance inst;
- if (graphicsApi == Vulkan) {
- if (!inst.create()) {
- qWarning("Failed to create Vulkan instance, switching to OpenGL");
- graphicsApi = OpenGL;
- }
- }
-#endif
-
- // Create and show the window.
- Window w;
-#if QT_CONFIG(vulkan)
- if (graphicsApi == Vulkan)
- w.setVulkanInstance(&inst);
-#endif
- w.resize(1280, 720);
- w.setTitle(graphicsApiName());
- w.show();
-
- // Window::event() will not get invoked when the
- // PlatformSurfaceAboutToBeDestroyed event is sent during the QWindow
- // destruction. That happens only when exiting via app::quit() instead of
- // the more common QWindow::close(). Take care of it: if the
- // QPlatformWindow is still around (there was no close() yet), get rid of
- // the swapchain while it's not too late.
- if (w.handle())
- w.releaseSwapChain();
-
- return app.exec();
-}
diff --git a/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.pro b/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.pro
index eeef33ff6a..a1093fdaec 100644
--- a/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.pro
+++ b/tests/manual/rhi/hellominimalcrossgfxtriangle/hellominimalcrossgfxtriangle.pro
@@ -1,8 +1,14 @@
TEMPLATE = app
-
+CONFIG += console
QT += gui-private
SOURCES = \
- hellominimalcrossgfxtriangle.cpp
+ main.cpp \
+ window.cpp \
+ hellowindow.cpp
+
+HEADERS = \
+ window.h \
+ hellowindow.h
RESOURCES = hellominimalcrossgfxtriangle.qrc
diff --git a/tests/manual/rhi/hellominimalcrossgfxtriangle/hellowindow.cpp b/tests/manual/rhi/hellominimalcrossgfxtriangle/hellowindow.cpp
new file mode 100644
index 0000000000..96a088adf4
--- /dev/null
+++ b/tests/manual/rhi/hellominimalcrossgfxtriangle/hellowindow.cpp
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "hellowindow.h"
+#include <QFile>
+#include <QtGui/private/qshader_p.h>
+
+static float vertexData[] = {
+ // Y up (note clipSpaceCorrMatrix in m_proj), CCW
+ 0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
+ -0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
+ 0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
+};
+
+HelloWindow::HelloWindow(QRhi::Implementation graphicsApi)
+ : Window(graphicsApi)
+{
+}
+
+QShader HelloWindow::getShader(const QString &name)
+{
+ QFile f(name);
+ if (f.open(QIODevice::ReadOnly))
+ return QShader::fromSerialized(f.readAll());
+
+ return QShader();
+}
+
+void HelloWindow::customInit()
+{
+ m_vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)));
+ m_vbuf->build();
+ m_vbufReady = false;
+
+ m_ubuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68));
+ m_ubuf->build();
+
+ m_srb.reset(m_rhi->newShaderResourceBindings());
+ m_srb->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage,
+ m_ubuf.get())
+ });
+ m_srb->build();
+
+ m_ps.reset(m_rhi->newGraphicsPipeline());
+
+ QRhiGraphicsPipeline::TargetBlend premulAlphaBlend;
+ premulAlphaBlend.enable = true;
+ m_ps->setTargetBlends({ premulAlphaBlend });
+
+ const QShader vs = getShader(QLatin1String(":/color.vert.qsb"));
+ if (!vs.isValid())
+ qFatal("Failed to load shader pack (vertex)");
+ const QShader fs = getShader(QLatin1String(":/color.frag.qsb"));
+ if (!fs.isValid())
+ qFatal("Failed to load shader pack (fragment)");
+
+ m_ps->setShaderStages({
+ { QRhiShaderStage::Vertex, vs },
+ { QRhiShaderStage::Fragment, fs }
+ });
+
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({
+ { 5 * sizeof(float) }
+ });
+ inputLayout.setAttributes({
+ { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
+ { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) }
+ });
+
+ m_ps->setVertexInputLayout(inputLayout);
+ m_ps->setShaderResourceBindings(m_srb.get());
+ m_ps->setRenderPassDescriptor(m_rp.get());
+
+ m_ps->build();
+}
+
+// called once per frame
+void HelloWindow::customRender()
+{
+ QRhiResourceUpdateBatch *u = m_rhi->nextResourceUpdateBatch();
+ if (!m_vbufReady) {
+ m_vbufReady = true;
+ u->uploadStaticBuffer(m_vbuf.get(), vertexData);
+ }
+ m_rotation += 1.0f;
+ QMatrix4x4 mvp = m_proj;
+ mvp.rotate(m_rotation, 0, 1, 0);
+ u->updateDynamicBuffer(m_ubuf.get(), 0, 64, mvp.constData());
+ m_opacity += m_opacityDir * 0.005f;
+ if (m_opacity < 0.0f || m_opacity > 1.0f) {
+ m_opacityDir *= -1;
+ m_opacity = qBound(0.0f, m_opacity, 1.0f);
+ }
+ u->updateDynamicBuffer(m_ubuf.get(), 64, 4, &m_opacity);
+
+ QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
+ const QSize outputSizeInPixels = m_sc->currentPixelSize();
+
+ cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 }, u);
+
+ cb->setGraphicsPipeline(m_ps.get());
+ cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
+ cb->setShaderResources();
+
+ const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
+ cb->setVertexInput(0, 1, &vbufBinding);
+ cb->draw(3);
+
+ cb->endPass();
+}
diff --git a/tests/manual/rhi/hellominimalcrossgfxtriangle/hellowindow.h b/tests/manual/rhi/hellominimalcrossgfxtriangle/hellowindow.h
new file mode 100644
index 0000000000..dd9890f11c
--- /dev/null
+++ b/tests/manual/rhi/hellominimalcrossgfxtriangle/hellowindow.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef HELLOWINDOW_H
+#define HELLOWINDOW_H
+
+#include "window.h"
+
+class HelloWindow : public Window
+{
+public:
+ HelloWindow(QRhi::Implementation graphicsApi);
+
+ void customInit() override;
+ void customRender() override;
+
+private:
+ QShader getShader(const QString &name);
+
+ std::unique_ptr<QRhiBuffer> m_vbuf;
+ bool m_vbufReady = false;
+ std::unique_ptr<QRhiBuffer> m_ubuf;
+ std::unique_ptr<QRhiShaderResourceBindings> m_srb;
+ std::unique_ptr<QRhiGraphicsPipeline> m_ps;
+
+ float m_rotation = 0;
+ float m_opacity = 1;
+ int m_opacityDir = -1;
+};
+
+#endif
diff --git a/tests/manual/rhi/hellominimalcrossgfxtriangle/main.cpp b/tests/manual/rhi/hellominimalcrossgfxtriangle/main.cpp
new file mode 100644
index 0000000000..4ef3359ed0
--- /dev/null
+++ b/tests/manual/rhi/hellominimalcrossgfxtriangle/main.cpp
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This is a compact, minimal demo of deciding the backend at runtime while
+// using the exact same shaders and rendering code without any branching
+// whatsoever once the QWindow is up and the RHI is initialized.
+
+#include <QGuiApplication>
+#include <QCommandLineParser>
+#include "hellowindow.h"
+
+QString graphicsApiName(QRhi::Implementation graphicsApi)
+{
+ switch (graphicsApi) {
+ case QRhi::Null:
+ return QLatin1String("Null (no output)");
+ case QRhi::OpenGLES2:
+ return QLatin1String("OpenGL 2.x");
+ case QRhi::Vulkan:
+ return QLatin1String("Vulkan");
+ case QRhi::D3D11:
+ return QLatin1String("Direct3D 11");
+ case QRhi::Metal:
+ return QLatin1String("Metal");
+ default:
+ break;
+ }
+ return QString();
+}
+
+int main(int argc, char **argv)
+{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QGuiApplication app(argc, argv);
+
+ QRhi::Implementation graphicsApi;
+#if defined(Q_OS_WIN)
+ graphicsApi = QRhi::D3D11;
+#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+ graphicsApi = QRhi::Metal;
+#elif QT_CONFIG(vulkan)
+ graphicsApi = QRhi::Vulkan;
+#else
+ graphicsApi = QRhi::OpenGLES2;
+#endif
+
+ QCommandLineParser cmdLineParser;
+ cmdLineParser.addHelpOption();
+ QCommandLineOption nullOption({ "n", "null" }, QLatin1String("Null"));
+ cmdLineParser.addOption(nullOption);
+ QCommandLineOption glOption({ "g", "opengl" }, QLatin1String("OpenGL (2.x)"));
+ cmdLineParser.addOption(glOption);
+ QCommandLineOption vkOption({ "v", "vulkan" }, QLatin1String("Vulkan"));
+ cmdLineParser.addOption(vkOption);
+ QCommandLineOption d3dOption({ "d", "d3d11" }, QLatin1String("Direct3D 11"));
+ cmdLineParser.addOption(d3dOption);
+ QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal"));
+ cmdLineParser.addOption(mtlOption);
+
+ cmdLineParser.process(app);
+ if (cmdLineParser.isSet(nullOption))
+ graphicsApi = QRhi::Null;
+ if (cmdLineParser.isSet(glOption))
+ graphicsApi = QRhi::OpenGLES2;
+ if (cmdLineParser.isSet(vkOption))
+ graphicsApi = QRhi::Vulkan;
+ if (cmdLineParser.isSet(d3dOption))
+ graphicsApi = QRhi::D3D11;
+ if (cmdLineParser.isSet(mtlOption))
+ graphicsApi = QRhi::Metal;
+
+ qDebug("Selected graphics API is %s", qPrintable(graphicsApiName(graphicsApi)));
+ qDebug("This is a multi-api example, use command line arguments to override:\n%s", qPrintable(cmdLineParser.helpText()));
+
+ QSurfaceFormat fmt;
+ fmt.setDepthBufferSize(24);
+ fmt.setStencilBufferSize(8);
+ QSurfaceFormat::setDefaultFormat(fmt);
+
+#if QT_CONFIG(vulkan)
+ QVulkanInstance inst;
+ if (graphicsApi == QRhi::Vulkan) {
+#ifndef Q_OS_ANDROID
+ inst.setLayers({ "VK_LAYER_LUNARG_standard_validation" });
+#else
+ inst.setLayers({
+ "VK_LAYER_GOOGLE_threading",
+ "VK_LAYER_LUNARG_parameter_validation",
+ "VK_LAYER_LUNARG_object_tracker",
+ "VK_LAYER_LUNARG_core_validation",
+ "VK_LAYER_LUNARG_image",
+ "VK_LAYER_LUNARG_swapchain",
+ "VK_LAYER_GOOGLE_unique_objects"});
+#endif
+ inst.setExtensions({ "VK_KHR_get_physical_device_properties2" });
+ if (!inst.create()) {
+ qWarning("Failed to create Vulkan instance, switching to OpenGL");
+ graphicsApi = QRhi::OpenGLES2;
+ }
+ }
+#endif
+
+ HelloWindow w(graphicsApi);
+#if QT_CONFIG(vulkan)
+ if (graphicsApi == QRhi::Vulkan)
+ w.setVulkanInstance(&inst);
+#endif
+ w.resize(1280, 720);
+ w.setTitle(QCoreApplication::applicationName() + QLatin1String(" - ") + graphicsApiName(graphicsApi));
+ w.show();
+
+ int ret = app.exec();
+
+ // Window::event() will not get invoked when the
+ // PlatformSurfaceAboutToBeDestroyed event is sent during the QWindow
+ // destruction. That happens only when exiting via app::quit() instead of
+ // the more common QWindow::close(). Take care of it: if the QPlatformWindow
+ // is still around (there was no close() yet), get rid of the swapchain
+ // while it's not too late.
+ if (w.handle())
+ w.releaseSwapChain();
+
+ return ret;
+}
diff --git a/tests/manual/rhi/hellominimalcrossgfxtriangle/window.cpp b/tests/manual/rhi/hellominimalcrossgfxtriangle/window.cpp
new file mode 100644
index 0000000000..f3f00e0255
--- /dev/null
+++ b/tests/manual/rhi/hellominimalcrossgfxtriangle/window.cpp
@@ -0,0 +1,255 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "window.h"
+#include <QPlatformSurfaceEvent>
+
+Window::Window(QRhi::Implementation graphicsApi)
+ : m_graphicsApi(graphicsApi)
+{
+ switch (graphicsApi) {
+ case QRhi::OpenGLES2:
+ setSurfaceType(OpenGLSurface);
+#if QT_CONFIG(opengl)
+ setFormat(QRhiGles2InitParams::adjustedFormat());
+#endif
+ break;
+ case QRhi::Vulkan:
+ setSurfaceType(VulkanSurface);
+ break;
+ case QRhi::D3D11:
+ setSurfaceType(OpenGLSurface);
+ break;
+ case QRhi::Metal:
+ setSurfaceType(MetalSurface);
+ break;
+ default:
+ break;
+ }
+}
+
+void Window::exposeEvent(QExposeEvent *)
+{
+ // initialize and start rendering when the window becomes usable for graphics purposes
+ if (isExposed() && !m_running) {
+ qDebug("init");
+ m_running = true;
+ init();
+ resizeSwapChain();
+ }
+
+ const QSize surfaceSize = m_hasSwapChain ? m_sc->surfacePixelSize() : QSize();
+
+ // stop pushing frames when not exposed (or size is 0)
+ if ((!isExposed() || (m_hasSwapChain && surfaceSize.isEmpty())) && m_running && !m_notExposed) {
+ qDebug("not exposed");
+ m_notExposed = true;
+ }
+
+ // Continue when exposed again and the surface has a valid size. Note that
+ // surfaceSize can be (0, 0) even though size() reports a valid one, hence
+ // trusting surfacePixelSize() and not QWindow.
+ if (isExposed() && m_running && m_notExposed && !surfaceSize.isEmpty()) {
+ qDebug("exposed again");
+ m_notExposed = false;
+ m_newlyExposed = true;
+ }
+
+ // always render a frame on exposeEvent() (when exposed) in order to update
+ // immediately on window resize.
+ if (isExposed() && !surfaceSize.isEmpty())
+ render();
+}
+
+bool Window::event(QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::UpdateRequest:
+ render();
+ break;
+
+ case QEvent::PlatformSurface:
+ // this is the proper time to tear down the swapchain (while the native window and surface are still around)
+ if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)
+ releaseSwapChain();
+ break;
+
+ default:
+ break;
+ }
+
+ return QWindow::event(e);
+}
+
+void Window::init()
+{
+ QRhi::Flags rhiFlags = QRhi::EnableDebugMarkers | QRhi::EnableProfiling;
+
+ if (m_graphicsApi == QRhi::Null) {
+ QRhiNullInitParams params;
+ m_rhi.reset(QRhi::create(QRhi::Null, &params, rhiFlags));
+ }
+
+#if QT_CONFIG(opengl)
+ if (m_graphicsApi == QRhi::OpenGLES2) {
+ m_fallbackSurface.reset(QRhiGles2InitParams::newFallbackSurface());
+ QRhiGles2InitParams params;
+ params.fallbackSurface = m_fallbackSurface.get();
+ params.window = this;
+ m_rhi.reset(QRhi::create(QRhi::OpenGLES2, &params, rhiFlags));
+ }
+#endif
+
+#if QT_CONFIG(vulkan)
+ if (m_graphicsApi == QRhi::Vulkan) {
+ QRhiVulkanInitParams params;
+ params.inst = vulkanInstance();
+ params.window = this;
+ m_rhi.reset(QRhi::create(QRhi::Vulkan, &params, rhiFlags));
+ }
+#endif
+
+#ifdef Q_OS_WIN
+ if (m_graphicsApi == QRhi::D3D11) {
+ QRhiD3D11InitParams params;
+ params.enableDebugLayer = true;
+ m_rhi.reset(QRhi::create(QRhi::D3D11, &params, rhiFlags));
+ }
+#endif
+
+#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+ if (m_graphicsApi == QRhi::Metal) {
+ QRhiMetalInitParams params;
+ m_rhi = QRhi::create(QRhi::Metal, &params, rhiFlags);
+ }
+#endif
+
+ if (!m_rhi)
+ qFatal("Failed to create RHI backend");
+
+ m_sc.reset(m_rhi->newSwapChain());
+ m_ds.reset(m_rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
+ QSize(), // no need to set the size here, due to UsedWithSwapChainOnly
+ 1,
+ QRhiRenderBuffer::UsedWithSwapChainOnly));
+ m_sc->setWindow(this);
+ m_sc->setDepthStencil(m_ds.get());
+ m_rp.reset(m_sc->newCompatibleRenderPassDescriptor());
+ m_sc->setRenderPassDescriptor(m_rp.get());
+
+ customInit();
+}
+
+void Window::resizeSwapChain()
+{
+ m_hasSwapChain = m_sc->buildOrResize(); // also handles m_ds
+
+ const QSize outputSize = m_sc->currentPixelSize();
+ m_proj = m_rhi->clipSpaceCorrMatrix();
+ m_proj.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
+ m_proj.translate(0, 0, -4);
+}
+
+void Window::releaseSwapChain()
+{
+ if (m_hasSwapChain) {
+ m_hasSwapChain = false;
+ m_sc->release();
+ }
+}
+
+void Window::render()
+{
+ if (!m_hasSwapChain || m_notExposed)
+ return;
+
+ // If the window got resized or newly exposed, resize the swapchain. (the
+ // newly-exposed case is not actually required by some platforms, but
+ // f.ex. Vulkan on Windows seems to need it)
+ //
+ // This (exposeEvent + the logic here) is the only safe way to perform
+ // resize handling. Note the usage of the RHI's surfacePixelSize(), and
+ // never QWindow::size(). (the two may or may not be the same under the hood,
+ // depending on the backend and platform)
+ //
+ if (m_sc->currentPixelSize() != m_sc->surfacePixelSize() || m_newlyExposed) {
+ resizeSwapChain();
+ if (!m_hasSwapChain)
+ return;
+ m_newlyExposed = false;
+ }
+
+ QRhi::FrameOpResult r = m_rhi->beginFrame(m_sc.get());
+ if (r == QRhi::FrameOpSwapChainOutOfDate) {
+ resizeSwapChain();
+ if (!m_hasSwapChain)
+ return;
+ r = m_rhi->beginFrame(m_sc.get());
+ }
+ if (r != QRhi::FrameOpSuccess) {
+ qDebug("beginFrame failed with %d, retry", r);
+ requestUpdate();
+ return;
+ }
+
+ customRender();
+
+ m_rhi->endFrame(m_sc.get());
+
+ requestUpdate();
+}
+
+void Window::customInit()
+{
+}
+
+void Window::customRender()
+{
+}
diff --git a/tests/manual/rhi/hellominimalcrossgfxtriangle/window.h b/tests/manual/rhi/hellominimalcrossgfxtriangle/window.h
new file mode 100644
index 0000000000..30bfa2492c
--- /dev/null
+++ b/tests/manual/rhi/hellominimalcrossgfxtriangle/window.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <QWindow>
+
+#include <QtGui/private/qrhinull_p.h>
+#if QT_CONFIG(opengl)
+#include <QtGui/private/qrhigles2_p.h>
+#include <QOffscreenSurface>
+#endif
+#if QT_CONFIG(vulkan)
+#include <QtGui/private/qrhivulkan_p.h>
+#endif
+#ifdef Q_OS_WIN
+#include <QtGui/private/qrhid3d11_p.h>
+#endif
+#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#include <QtGui/private/qrhimetal_p.h>
+#endif
+
+class Window : public QWindow
+{
+public:
+ Window(QRhi::Implementation graphicsApi);
+
+ void releaseSwapChain();
+
+protected:
+ virtual void customInit();
+ virtual void customRender();
+
+ // destruction order matters to a certain degree: the fallbackSurface must
+ // outlive the rhi, the rhi must outlive all other resources. The resources
+ // need no special order when destroying.
+#if QT_CONFIG(opengl)
+ std::unique_ptr<QOffscreenSurface> m_fallbackSurface;
+#endif
+ std::unique_ptr<QRhi> m_rhi;
+ std::unique_ptr<QRhiSwapChain> m_sc;
+ std::unique_ptr<QRhiRenderBuffer> m_ds;
+ std::unique_ptr<QRhiRenderPassDescriptor> m_rp;
+
+ bool m_hasSwapChain = false;
+ QMatrix4x4 m_proj;
+
+private:
+ void init();
+ void resizeSwapChain();
+ void render();
+
+ void exposeEvent(QExposeEvent *) override;
+ bool event(QEvent *) override;
+
+ QRhi::Implementation m_graphicsApi;
+
+ bool m_running = false;
+ bool m_notExposed = false;
+ bool m_newlyExposed = false;
+};
+
+#endif
diff --git a/tests/manual/startsystemmove/main.cpp b/tests/manual/startsystemmove/main.cpp
new file mode 100644
index 0000000000..a121d1ed86
--- /dev/null
+++ b/tests/manual/startsystemmove/main.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 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 <QtGui>
+
+constexpr qreal border = 20;
+
+class Window : public QRasterWindow
+{
+public:
+ explicit Window(QWindow *parent = nullptr) : QRasterWindow(parent)
+ {
+ resize(300, 200);
+ setMinimumSize(QSize(border*2, border*2));
+ }
+protected:
+ void resizeOrMove(const QPointF &p);
+ bool event(QEvent *event) override;
+ void paintEvent(QPaintEvent *event) override;
+};
+
+void Window::resizeOrMove(const QPointF &p)
+{
+ Qt::Edges edges;
+ if (p.x() > width() - border)
+ edges |= Qt::RightEdge;
+ if (p.x() < border)
+ edges |= Qt::LeftEdge;
+ if (p.y() < border)
+ edges |= Qt::TopEdge;
+ if (p.y() > height() - border)
+ edges |= Qt::BottomEdge;
+
+ if (edges != 0) {
+ qDebug() << "startSystemResize" << edges;
+ if (startSystemResize(edges))
+ qDebug() << " -> supported";
+ else
+ qDebug() << " -> not supported";
+ } else {
+ qDebug() << "startSystemMove";
+ if (startSystemMove())
+ qDebug() << " -> supported";
+ else
+ qDebug() << " -> not supported";
+ }
+}
+
+bool Window::event(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ qDebug() << "Mouse press";
+ resizeOrMove(static_cast<QMouseEvent *>(event)->localPos());
+ return true;
+ case QEvent::TouchUpdate:
+ qDebug() << "Touch update";
+ resizeOrMove(static_cast<QTouchEvent *>(event)->touchPoints().first().pos());
+ return true;
+ case QEvent::TouchBegin:
+ qDebug() << "Touch begin";
+ resizeOrMove(static_cast<QTouchEvent *>(event)->touchPoints().first().pos());
+ return true;
+ default:
+ return QRasterWindow::event(event);
+ }
+}
+
+void Window::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event);
+ QPainter painter(this);
+ QRect fullRect(0, 0, width(), height());
+ QRect innerRect = fullRect.marginsRemoved(QMargins(border, border, border, border));
+ painter.fillRect(fullRect, QGradient::WarmFlame);
+ painter.fillRect(innerRect, QGradient::NightFade);
+ painter.drawText(QRectF(0, 0, width(), height()), Qt::AlignCenter, QStringLiteral("Click mouse or touch to move window\nDrag along the sides to resize."));
+}
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+ Window window;
+ window.show();
+ return app.exec();
+}
diff --git a/tests/manual/startsystemmove/startsystemmove.pro b/tests/manual/startsystemmove/startsystemmove.pro
new file mode 100644
index 0000000000..568bda343b
--- /dev/null
+++ b/tests/manual/startsystemmove/startsystemmove.pro
@@ -0,0 +1,4 @@
+TEMPLATE = app
+QT = core gui
+SOURCES += main.cpp
+CONFIG += console