Remove hellovulkanwindow example

The idea being that hellovulkantriangle demonstrates the same things.
As a getting started tutorial hellovulkanwindow is the ideal example,
but then again QVulkanWindow is not something we want to promote much
in Qt 6.

Some of the docs are moved to hellovulkantriangle.

Pick-to: 6.5
Change-Id: Icbfff70b4a4c7e4c0863a937f3c16038c0b03fbe
Reviewed-by: Christian Strømme <christian.stromme@qt.io>
This commit is contained in:
Laszlo Agocs 2023-03-22 16:26:16 +01:00
parent b5b954fac1
commit 0e8d347c6a
11 changed files with 50 additions and 273 deletions

View File

@ -1,7 +1,6 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_example(hellovulkanwindow)
qt_internal_add_example(hellovulkantriangle)
if(TARGET Qt6::Widgets)
qt_internal_add_example(hellovulkanwidget)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -14,6 +14,49 @@
\image hellovulkantriangle.png
\section1 Startup
Each Qt application using Vulkan will have to have a \c{Vulkan instance}
which encapsulates application-level state and initializes a Vulkan library.
A QVulkanWindow must always be associated with a QVulkanInstance and hence
the example performs instance creation before the window. The
QVulkanInstance object must also outlive the window.
\snippet hellovulkantriangle/main.cpp 0
The example enables validation layers, when supported. When the requested
layers are not present, the request will be ignored. Additional layers and
extensions can be enabled in a similar manner.
\snippet hellovulkantriangle/main.cpp 1
Once the instance is ready, it is time to create a window. Note that \c w
lives on the stack and is declared after \c inst.
\section1 The QVulkanWindow Subclass
To add custom functionality to a QVulkanWindow, subclassing is used. This
follows the existing patterns from QOpenGLWindow and QOpenGLWidget.
However, QVulkanWindow utilizes a separate QVulkanWindowRenderer object.
The QVulkanWindow subclass reimplements the factory function
QVulkanWindow::createRenderer(). This simply returns a new instance of the
QVulkanWindowRenderer subclass. In order to be able to access various
Vulkan resources via the window object, a pointer to the window is passed
and stored via the constructor.
\snippet hellovulkantriangle/main.cpp 2
\section1 The Actual Rendering
QVulkanWindow subclasses queue their draw calls in their reimplementation
of QVulkanWindowRenderer::startNextFrame(). Once done, they are required to
call back QVulkanWindow::frameReady(). The example has no asynchronous
command generation, so the frameReady() call is made directly from
startNextFrame(). To get continuous updates, the example simply invokes
QWindow::requestUpdate() in order to schedule a repaint.
The example also demonstrates multisample antialiasing. Based on the
supported sample counts reported by QVulkanWindow::supportedSampleCounts()
the example chooses between 8x, 4x, or no multisampling. Once configured

View File

@ -1,78 +0,0 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\example hellovulkanwindow
\meta installpath vulkan
\title Hello Vulkan Window Example
\ingroup examples-vulkan
\brief Shows the basics of using QVulkanWindow.
The \e{Hello Vulkan Window Example} shows the basics of using QVulkanWindow
in order to display rendering with the Vulkan graphics API on systems that
support this.
\image hellovulkanwindow.png
In this example there will be no actual rendering: it simply begins and
ends a render pass, which results in clearing the buffers to a fixed value.
The color buffer clear value changes on every frame.
\section1 Startup
Each Qt application using Vulkan will have to have a \c{Vulkan instance}
which encapsulates application-level state and initializes a Vulkan library.
A QVulkanWindow must always be associated with a QVulkanInstance and hence
the example performs instance creation before the window. The
QVulkanInstance object must also outlive the window.
\snippet hellovulkanwindow/main.cpp 0
The example enables validation layers, when supported. When the requested
layers are not present, the request will be ignored. Additional layers and
extensions can be enabled in a similar manner.
\snippet hellovulkanwindow/main.cpp 1
Once the instance is ready, it is time to create a window. Note that \c w
lives on the stack and is declared after \c inst.
\section1 The QVulkanWindow Subclass
To add custom functionality to a QVulkanWindow, subclassing is used. This
follows the existing patterns from QOpenGLWindow and QOpenGLWidget.
However, QVulkanWindow utilizes a separate QVulkanWindowRenderer object.
This resembles QQuickFramebufferObject, and allows better separation of the
functions that are supposed to be reimplemented.
\snippet hellovulkanwindow/hellovulkanwindow.h 0
The QVulkanWindow subclass reimplements the factory function
QVulkanWindow::createRenderer(). This simply returns a new instance of the
QVulkanWindowRenderer subclass. In order to be able to access various
Vulkan resources via the window object, a pointer to the window is passed
and stored via the constructor.
\snippet hellovulkanwindow/hellovulkanwindow.cpp 0
Graphics resource creation and destruction is typically done in one of the
init - resource functions.
\snippet hellovulkanwindow/hellovulkanwindow.cpp 1
\section1 The Actual Rendering
QVulkanWindow subclasses queue their draw calls in their reimplementation
of QVulkanWindowRenderer::startNextFrame(). Once done, they are required to
call back QVulkanWindow::frameReady(). The example has no asynchronous
command generation, so the frameReady() call is made directly from
startNextFrame().
\snippet hellovulkanwindow/hellovulkanwindow.cpp 2
To get continuous updates, the example simply invokes
QWindow::requestUpdate() in order to schedule a repaint.
\include examples-run.qdocinc
*/

View File

@ -8,11 +8,13 @@
Q_LOGGING_CATEGORY(lcVk, "qt.vulkan")
//! [2]
class VulkanWindow : public QVulkanWindow
{
public:
QVulkanWindowRenderer *createRenderer() override;
};
//! [2]
QVulkanWindowRenderer *VulkanWindow::createRenderer()
{
@ -25,17 +27,20 @@ int main(int argc, char *argv[])
QLoggingCategory::setFilterRules(QStringLiteral("qt.vulkan=true"));
//! [0]
QVulkanInstance inst;
inst.setLayers({ "VK_LAYER_KHRONOS_validation" });
if (!inst.create())
qFatal("Failed to create Vulkan instance: %d", inst.errorCode());
//! [0]
//! [1]
VulkanWindow w;
w.setVulkanInstance(&inst);
w.resize(1024, 768);
w.show();
//! [1]
return app.exec();
}

View File

@ -1,36 +0,0 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(hellovulkanwindow LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/vulkan/hellovulkanwindow")
find_package(Qt6 REQUIRED COMPONENTS Core Gui)
qt_standard_project_setup()
qt_add_executable(hellovulkanwindow
hellovulkanwindow.cpp hellovulkanwindow.h
main.cpp
)
set_target_properties(hellovulkanwindow PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(hellovulkanwindow PRIVATE
Qt6::Core
Qt6::Gui
)
install(TARGETS hellovulkanwindow
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -1,81 +0,0 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "hellovulkanwindow.h"
#include <QVulkanFunctions>
//! [0]
QVulkanWindowRenderer *VulkanWindow::createRenderer()
{
return new VulkanRenderer(this);
}
VulkanRenderer::VulkanRenderer(QVulkanWindow *w)
: m_window(w)
{
}
//! [0]
//! [1]
void VulkanRenderer::initResources()
{
qDebug("initResources");
m_devFuncs = m_window->vulkanInstance()->deviceFunctions(m_window->device());
}
//! [1]
void VulkanRenderer::initSwapChainResources()
{
qDebug("initSwapChainResources");
}
void VulkanRenderer::releaseSwapChainResources()
{
qDebug("releaseSwapChainResources");
}
void VulkanRenderer::releaseResources()
{
qDebug("releaseResources");
}
//! [2]
void VulkanRenderer::startNextFrame()
{
m_green += 0.005f;
if (m_green > 1.0f)
m_green = 0.0f;
VkClearColorValue clearColor = {{ 0.0f, m_green, 0.0f, 1.0f }};
VkClearDepthStencilValue clearDS = { 1.0f, 0 };
VkClearValue clearValues[2];
memset(clearValues, 0, sizeof(clearValues));
clearValues[0].color = clearColor;
clearValues[1].depthStencil = clearDS;
VkRenderPassBeginInfo rpBeginInfo;
memset(&rpBeginInfo, 0, sizeof(rpBeginInfo));
rpBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rpBeginInfo.renderPass = m_window->defaultRenderPass();
rpBeginInfo.framebuffer = m_window->currentFramebuffer();
const QSize sz = m_window->swapChainImageSize();
rpBeginInfo.renderArea.extent.width = sz.width();
rpBeginInfo.renderArea.extent.height = sz.height();
rpBeginInfo.clearValueCount = 2;
rpBeginInfo.pClearValues = clearValues;
VkCommandBuffer cmdBuf = m_window->currentCommandBuffer();
m_devFuncs->vkCmdBeginRenderPass(cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
// Do nothing else. We will just clear to green, changing the component on
// every invocation. This also helps verifying the rate to which the thread
// is throttled to. (The elapsed time between startNextFrame calls should
// typically be around 16 ms. Note that rendering is 2 frames ahead of what
// is displayed.)
m_devFuncs->vkCmdEndRenderPass(cmdBuf);
m_window->frameReady();
m_window->requestUpdate(); // render continuously, throttled by the presentation rate
}
//! [2]

View File

@ -1,35 +0,0 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef HELLOVULKANWINDOW_H
#define HELLOVULKANWINDOW_H
#include <QVulkanWindow>
//! [0]
class VulkanRenderer : public QVulkanWindowRenderer
{
public:
VulkanRenderer(QVulkanWindow *w);
void initResources() override;
void initSwapChainResources() override;
void releaseSwapChainResources() override;
void releaseResources() override;
void startNextFrame() override;
private:
QVulkanWindow *m_window;
QVulkanDeviceFunctions *m_devFuncs;
float m_green = 0;
};
class VulkanWindow : public QVulkanWindow
{
public:
QVulkanWindowRenderer *createRenderer() override;
};
//! [0]
#endif // HELLOVULKANWINDOW_H

View File

@ -1,6 +0,0 @@
HEADERS += hellovulkanwindow.h
SOURCES += hellovulkanwindow.cpp main.cpp
# install
target.path = $$[QT_INSTALL_EXAMPLES]/vulkan/hellovulkanwindow
INSTALLS += target

View File

@ -1,33 +0,0 @@
// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QGuiApplication>
#include <QVulkanInstance>
#include <QLoggingCategory>
#include "hellovulkanwindow.h"
Q_LOGGING_CATEGORY(lcVk, "qt.vulkan")
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QLoggingCategory::setFilterRules(QStringLiteral("qt.vulkan=true"));
//! [0]
QVulkanInstance inst;
inst.setLayers({ "VK_LAYER_KHRONOS_validation" });
if (!inst.create())
qFatal("Failed to create Vulkan instance: %d", inst.errorCode());
//! [0]
//! [1]
VulkanWindow w;
w.setVulkanInstance(&inst);
w.resize(1024, 768);
w.show();
//! [1]
return app.exec();
}

View File

@ -1,7 +1,6 @@
TEMPLATE = subdirs
SUBDIRS = hellovulkanwindow \
hellovulkantriangle
SUBDIRS = hellovulkantriangle
qtHaveModule(widgets) {
SUBDIRS += hellovulkanwidget