rhi: Make it a QPA-style private but semi-public API

qrhi.h, qshader.h, qshaderdescription.h (and qshaderbaker.h from
shadertools; done separately) become "RHI APIs", following the concept
of QPA APIs.

Mirror completely what is done for QPA headers, but using the "rhi"
prefix for the headers. This involves updating syncqt to handle the
new category of headers. (a note on the regex: matching everything
starting with "qrhi" is not acceptable due to incorrectly matching
existing and future headers, hence specifying the four header names
explicitly)

There is going to be one difference to QPA: the documentation for
everything RHI is going to be public and part of the regular docs, not
hidden with \internal.

In addition to the header renaming and adding the comments and
documentation notes and warnings, there is one significant change
here: there is no longer a need to do API-specific includes, such as
qrhid3d11[_p].h, qrhivulkan[_p].h, etc. These are simply merged into a
single header that is then included from qrhi.h. This means that users
within Qt, and any future applications can just do #include
<rhi/qrhi.h> (or rhi/qshader.h if the QRhi stuff is not relevant), no
other headers are needed.

There are no changes to functionality in this patch. Only the
documentation is expanded, quite a lot, to eliminate all qdoc warnings
and make the generated API docs complete. An example, with a quite
extensive doc page is added as well.

Task-number: QTBUG-113331
Change-Id: I91c749826348f14320cb335b1c83e9d1ea2b1d8b
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Laszlo Agocs 2023-04-27 13:16:29 +02:00
parent 30a8e79243
commit 1dd8b5ceec
97 changed files with 13430 additions and 9022 deletions

View File

@ -72,7 +72,7 @@ function(qt_copy_framework_headers target)
set(options)
set(oneValueArgs)
set(multiValueArgs PUBLIC PRIVATE QPA)
set(multiValueArgs PUBLIC PRIVATE QPA RHI)
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
qt_internal_get_framework_info(fw ${target})
@ -80,10 +80,11 @@ function(qt_copy_framework_headers target)
set(output_dir_PUBLIC "${output_dir}/${fw_versioned_header_dir}")
set(output_dir_PRIVATE "${output_dir}/${fw_private_module_header_dir}/private")
set(output_dir_QPA "${output_dir}/${fw_private_module_header_dir}/qpa")
set(output_dir_RHI "${output_dir}/${fw_private_module_header_dir}/rhi")
set(out_files)
foreach(type IN ITEMS PUBLIC PRIVATE QPA)
foreach(type IN ITEMS PUBLIC PRIVATE QPA RHI)
set(fw_output_header_dir "${output_dir_${type}}")
foreach(hdr IN LISTS arg_${type})
get_filename_component(in_file_path ${hdr} ABSOLUTE)

View File

@ -30,6 +30,7 @@ macro(qt_internal_get_internal_add_module_keywords option_args single_args multi
EXTERNAL_HEADERS_DIR
PRIVATE_HEADER_FILTERS
QPA_HEADER_FILTERS
RHI_HEADER_FILTERS
HEADER_SYNC_SOURCE_DIRECTORY
${__default_target_info_args}
)
@ -115,6 +116,10 @@ endfunction()
# The regular expressions that filter QPA header files out of target sources.
# The value must use the following format 'regex1|regex2|regex3'.
#
# RHI_HEADER_FILTERS
# The regular expressions that filter RHI header files out of target sources.
# The value must use the following format 'regex1|regex2|regex3'.
#
# HEADER_SYNC_SOURCE_DIRECTORY
# The source directory for header sync procedure. Header files outside this directory will be
# ignored by syncqt. The specifying this directory allows to skip the parsing of the whole
@ -447,6 +452,13 @@ function(qt_internal_add_module target)
set_target_properties(${target}
PROPERTIES _qt_module_qpa_headers_filter_regex "${qpa_filter_regex}")
set(rhi_filter_regex "")
if(arg_RHI_HEADER_FILTERS)
set(rhi_filter_regex "${arg_RHI_HEADER_FILTERS}")
endif()
set_target_properties(${target}
PROPERTIES _qt_module_rhi_headers_filter_regex "${rhi_filter_regex}")
set(private_filter_regex ".+_p(ch)?\\.h")
if(arg_PRIVATE_HEADER_FILTERS)
set(private_filter_regex "${private_filter_regex}|${arg_PRIVATE_HEADER_FILTERS}")
@ -892,6 +904,7 @@ function(qt_finalize_module target)
PUBLIC ${module_headers_public} "${module_depends_header}"
PRIVATE ${module_headers_private}
QPA ${module_headers_qpa}
RHI ${module_headers_rhi}
)
qt_finalize_framework_headers_copy(${target})
@ -924,6 +937,7 @@ endfunction()
# * foo_versioned_inner_include_dir with the value "QtCore/6.2.0/QtCore"
# * foo_private_include_dir with the value "QtCore/6.2.0/QtCore/private"
# * foo_qpa_include_dir with the value "QtCore/6.2.0/QtCore/qpa"
# * foo_rhi_include_dir with the value "QtCore/6.2.0/QtCore/rhi"
# * foo_interface_name the interface name of the module stored in _qt_module_interface_name
# property, e.g. Core.
#
@ -946,6 +960,9 @@ endfunction()
# * foo_<build|install>_qpa_include_dir with
# qtbase_build_dir/include/QtCore/6.2.0/QtCore/qpa for build interface and
# include/QtCore/6.2.0/QtCore/qpa for install interface.
# * foo_<build|install>_rhi_include_dir with
# qtbase_build_dir/include/QtCore/6.2.0/QtCore/rhi for build interface and
# include/QtCore/6.2.0/QtCore/rhi for install interface.
# The following values are set by the function and might be useful in caller's scope:
# * repo_install_interface_include_dir contains path to the top-level repository include directory,
# e.g. qtbase_build_dir/include
@ -980,6 +997,8 @@ the different base name for the module info variables.")
"${${result}_versioned_inner_include_dir}/private")
set("${result}_qpa_include_dir"
"${${result}_versioned_inner_include_dir}/qpa")
set("${result}_rhi_include_dir"
"${${result}_versioned_inner_include_dir}/rhi")
# Module build interface directories
set(repo_build_interface_include_dir "${QT_BUILD_DIR}/include")
@ -993,6 +1012,8 @@ the different base name for the module info variables.")
"${repo_build_interface_include_dir}/${${result}_private_include_dir}")
set("${result}_build_interface_qpa_include_dir"
"${repo_build_interface_include_dir}/${${result}_qpa_include_dir}")
set("${result}_build_interface_rhi_include_dir"
"${repo_build_interface_include_dir}/${${result}_rhi_include_dir}")
# Module install interface directories
set(repo_install_interface_include_dir "${INSTALL_INCLUDEDIR}")
@ -1006,6 +1027,8 @@ the different base name for the module info variables.")
"${repo_install_interface_include_dir}/${${result}_private_include_dir}")
set("${result}_install_interface_qpa_include_dir"
"${repo_install_interface_include_dir}/${${result}_qpa_include_dir}")
set("${result}_install_interface_rhi_include_dir"
"${repo_install_interface_include_dir}/${${result}_rhi_include_dir}")
set("${result}" "${module}" PARENT_SCOPE)
set("${result}_versioned" "${module_versioned}" PARENT_SCOPE)
@ -1019,6 +1042,7 @@ the different base name for the module info variables.")
"${${result}_versioned_inner_include_dir}" PARENT_SCOPE)
set("${result}_private_include_dir" "${${result}_private_include_dir}" PARENT_SCOPE)
set("${result}_qpa_include_dir" "${${result}_qpa_include_dir}" PARENT_SCOPE)
set("${result}_rhi_include_dir" "${${result}_rhi_include_dir}" PARENT_SCOPE)
set("${result}_interface_name" "${module_interface_name}" PARENT_SCOPE)
# Setting module build interface directories in parent scope
@ -1033,6 +1057,8 @@ the different base name for the module info variables.")
"${${result}_build_interface_private_include_dir}" PARENT_SCOPE)
set("${result}_build_interface_qpa_include_dir"
"${${result}_build_interface_qpa_include_dir}" PARENT_SCOPE)
set("${result}_build_interface_rhi_include_dir"
"${${result}_build_interface_rhi_include_dir}" PARENT_SCOPE)
# Setting module install interface directories in parent scope
set(repo_install_interface_include_dir "${repo_install_interface_include_dir}" PARENT_SCOPE)
@ -1046,6 +1072,8 @@ the different base name for the module info variables.")
"${${result}_install_interface_private_include_dir}" PARENT_SCOPE)
set("${result}_install_interface_qpa_include_dir"
"${${result}_install_interface_qpa_include_dir}" PARENT_SCOPE)
set("${result}_install_interface_rhi_include_dir"
"${${result}_install_interface_rhi_include_dir}" PARENT_SCOPE)
endfunction()
function(qt_internal_list_to_json_array out_var list_var)
@ -1153,7 +1181,7 @@ endfunction()
function(qt_internal_install_module_headers target)
set(options)
set(one_value_args)
set(multi_value_args PUBLIC PRIVATE QPA)
set(multi_value_args PUBLIC PRIVATE QPA RHI)
cmake_parse_arguments(arg "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
qt_internal_module_info(module ${target})
@ -1178,6 +1206,7 @@ function(qt_internal_install_module_headers target)
PUBLIC ${arg_PUBLIC}
PRIVATE ${arg_PRIVATE}
QPA ${arg_QPA}
RHI ${arg_RHI}
)
else()
if(arg_PUBLIC)
@ -1191,6 +1220,9 @@ function(qt_internal_install_module_headers target)
if(arg_QPA)
qt_install(FILES ${arg_QPA} DESTINATION "${module_install_interface_qpa_include_dir}")
endif()
if(arg_RHI)
qt_install(FILES ${arg_RHI} DESTINATION "${module_install_interface_rhi_include_dir}")
endif()
endif()
endfunction()
@ -1198,6 +1230,7 @@ function(qt_internal_collect_module_headers out_var target)
set(${out_var}_public "")
set(${out_var}_private "")
set(${out_var}_qpa "")
set(${out_var}_rhi "")
set(${out_var}_all "")
qt_internal_get_target_sources(sources ${target})
@ -1215,6 +1248,7 @@ function(qt_internal_collect_module_headers out_var target)
get_target_property(public_filter ${target} _qt_module_public_headers_filter_regex)
get_target_property(private_filter ${target} _qt_module_private_headers_filter_regex)
get_target_property(qpa_filter ${target} _qt_module_qpa_headers_filter_regex)
get_target_property(rhi_filter ${target} _qt_module_rhi_headers_filter_regex)
set(condition_independent_headers_warning "")
foreach(file_path IN LISTS sources)
@ -1259,6 +1293,8 @@ function(qt_internal_collect_module_headers out_var target)
list(APPEND ${out_var}_all "${file_path}")
if(qpa_filter AND file_name MATCHES "${qpa_filter}")
list(APPEND ${out_var}_qpa "${file_path}")
elseif(rhi_filter AND file_name MATCHES "${rhi_filter}")
list(APPEND ${out_var}_rhi "${file_path}")
elseif(private_filter AND file_name MATCHES "${private_filter}")
list(APPEND ${out_var}_private "${file_path}")
elseif((NOT public_filter OR file_name MATCHES "${public_filter}")
@ -1282,7 +1318,7 @@ function(qt_internal_collect_module_headers out_var target)
endif()
set(header_types public private qpa)
set(header_types public private qpa rhi)
set(has_header_types_properties "")
foreach(header_type IN LISTS header_types)
get_target_property(current_propety_value ${target} _qt_module_has_${header_type}_headers)
@ -1304,5 +1340,6 @@ function(qt_internal_collect_module_headers out_var target)
_qt_module_has_public_headers
_qt_module_has_private_headers
_qt_module_has_qpa_headers
_qt_module_has_rhi_headers
)
endfunction()

View File

@ -211,6 +211,7 @@ function(qt_get_qmake_module_name result module)
string(REGEX REPLACE "^Qt6" "" module "${module}")
string(REGEX REPLACE "Private$" "_private" module "${module}")
string(REGEX REPLACE "Qpa$" "_qpa_lib_private" module "${module}")
string(REGEX REPLACE "Rhi$" "_rhi_lib_private" module "${module}")
string(TOLOWER "${module}" module)
set(${result} ${module} PARENT_SCOPE)
endfunction()

View File

@ -79,6 +79,7 @@ function(qt_internal_target_sync_headers target module_headers module_headers_ge
endif()
get_target_property(qpa_filter_regex ${target} _qt_module_qpa_headers_filter_regex)
get_target_property(rhi_filter_regex ${target} _qt_module_rhi_headers_filter_regex)
get_target_property(private_filter_regex ${target} _qt_module_private_headers_filter_regex)
# We need to use the real paths since otherwise it may lead to the invalid work of the
@ -96,6 +97,12 @@ function(qt_internal_target_sync_headers target module_headers module_headers_ge
)
endif()
if(rhi_filter_regex)
set(rhi_filter_argument
-rhiHeadersFilter "${rhi_filter_regex}"
)
endif()
set(common_syncqt_arguments
-module "${module}"
-sourceDir "${source_dir_real}"
@ -104,8 +111,10 @@ function(qt_internal_target_sync_headers target module_headers module_headers_ge
-includeDir "${module_build_interface_include_dir}"
-privateIncludeDir "${module_build_interface_private_include_dir}"
-qpaIncludeDir "${module_build_interface_qpa_include_dir}"
-rhiIncludeDir "${module_build_interface_rhi_include_dir}"
-generatedHeaders ${module_headers_generated}
${qpa_filter_argument}
${rhi_filter_argument}
${public_namespaces_filter}
${non_qt_module_argument}
${internal_module_argument}

View File

@ -5,3 +5,4 @@ if(NOT TARGET Qt6::Gui)
return()
endif()
qt_internal_add_example(rasterwindow)
qt_internal_add_example(rhiwindow)

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@ -0,0 +1,439 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\example rhiwindow
\title RHI Window Example
\brief This example shows how to create a minimal QWindow-based
application using QRhi.
\image rhiwindow_example.jpg
Qt 6.6 starts offering its accelerated 3D API and shader abstraction layer
for application use as well. Applications can now use the same 3D graphics
classes Qt itself uses to implement the Qt Quick scenegraph or the Qt Quick
3D engine. In earlier Qt versions QRhi and the related classes were all
private APIs. From 6.6 on these classes are in a similar category as QPA
family of classes: neither fully public nor private, but something
in-between, with a more limited compatibility promise compared to public
APIs. On the other hand, QRhi and the related classes now come with full
documentation similarly to public APIs.
There are multiple ways to use QRhi, the example here shows the most
low-level approach: targeting a QWindow, while not using Qt Quick, Qt Quick
3D, or Widgets in any form, and setting up all the rendering and windowing
infrastructure in the application.
In contrast, when writing a QML application with Qt Quick or Qt Quick 3D,
and wanting to add QRhi-based rendering to it, such an application is going
to rely on the window and rendering infrastructure Qt Quick has already
initialized, and it is likely going to query an existing QRhi instance from
the QQuickWindow. There dealing with QRhi::create(), platform/API specifics
such as \l{QVulkanInstance}{Vulkan instances}, or correctly handling
\l{QExposeEvent}{expose} and resize events for the window are all managed
by Qt Quick. Whereas in this example, all that is managed and taken care
of by the application itself.
\note For QWidget-based applications in particular, it should be noted that
QWidget::createWindowContainer() allows embedding a QWindow (backed by a
native window) into the widget-based user interface. Therefore, the \c
HelloWindow class from this example is reusable in QWidget-based
applications, assuming the necessary initialization from \c main() is in
place as well.
\section1 3D API Support
The application supports all the current \l{QRhi::Implementation}{QRhi
backends}. When no command-line arguments are specified, platform-specific
defaults are used: Direct 3D 11 on Windows, OpenGL on Linux, Metal on
macOS/iOS.
Running with \c{--help} shows the available command-line options:
\list
\li -d or --d3d11 for Direct 3D 11
\li -D or --d3d12 for Direct 3D 12
\li -m or --metal for Metal
\li -v or --vulkan for Vulkan
\li -g or --opengl for OpenGL or OpenGL ES
\li -n or --null for the \l{QRhi::Null}{Null backend}
\endlist
\section1 Build System Notes
This application relies solely on the Qt GUI module. It does not use Qt
Widgets or Qt Quick.
In order to access the RHI APIs, which are available to all Qt applications
but come with a limited compatibility promise, the \c target_link_libraries
CMake command lists \c{Qt6::GuiPrivate}. This is what enables the
\c{#include <rhi/qrhi.h>} include statement to compile successfully.
\section1 Features
The application features:
\list
\li A resizable QWindow,
\li a swapchain and depth-stencil buffer that properly follows the size of
the window,
\li logic to initialize, render, and tear down at the appropriate time
based on events such as \l QExposeEvent and \l QPlatformSurfaceEvent,
\li rendering a fullscreen textured quad, using a texture the contents of
which is generated in a QImage via QPainter (using the raster paint engine,
i.e. the generating of the image's pixel data is all CPU-based, that data
is then uploaded into a GPU texture),
\li rendering a triangle with blending and depth testing enabled, using a
perspective projection, while applying a model transform that changes on
every frame,
\li an efficient, cross-platform render loop using
\l{QWindow::requestUpdate()}{requestUpdate()}.
\endlist
\section1 Shaders
The application uses two sets of vertex and fragment shader pairs:
\list
\li one for the fullscreen quad, which uses no vertex inputs and the
fragment shader samples a texture (\c quad.vert, \c quad.frag),
\li and another pair for the triangle, where vertex positions and colors
are provided in a vertex buffer and a modelview-projection matrix is
provided in a uniform buffer (\c color.vert, \c color.frag).
\endlist
The shaders are written as Vulkan-compatible GLSL source code.
Due to being a Qt GUI module example, this example cannot have a dependency
on the \l{Qt Shader Tools} module. This means that CMake helper functions
such as \c{qt_add_shaders} are not available for use. Therefore, the
example has the pre-processed \c{.qsb} files included in the
\c{shaders/prebuilt} folder, and they are simply included within the
executable via \c{qt_add_resources}. This approach is not generally
recommended for applications, consider rather using \l{Qt Shader Tools
Build System Integration}{qt_add_shaders}, which avoids the need to
manually generate and manage the \c{.qsb} files.
To generate the \c{.qsb} files for this example, the command \c{qsb --qt6
color.vert -o prebuilt/color.vert.qsb} etc. was used. This leads to
compiling to \l{https://www.khronos.org/spir/}{SPIR-V} and than transpiling
into GLSL (\c{100 es} and \c 120), HLSL (5.0), and MSL (1.2). All the
shader versions are then packed together into a QShader and serialized to
disk.
\section1 API-specific Initialization
For some of the 3D APIs the main() function has to perform the appropriate
API-specific initialiation, e.g. to create a QVulkanInstance when using
Vulkan. For OpenGL we have to ensure a depth buffer is available, this is
done via QSurfaceFormat. These steps are not in the scope of QRhi since
QRhi backends for OpenGL or Vulkan build on the existing Qt facilities such
as QOpenGLContext or QVulkanInstance.
\snippet rhiwindow/main.cpp api-setup
\note For Vulkan, note how
QRhiVulkanInitParams::preferredInstanceExtensions() is taken into account
to ensure the appropriate extensions are enabled.
\c HelloWindow is a subclass of \c RhiWindow, which in turn is a QWindow.
\c RhiWindow contains everything needed to manage a resizable window with
a\ swapchain (and depth-stencil buffer), and is potentially reusable in
other applications as well. \c HelloWindow contains the rendering logic
specific to this particular example application.
In the QWindow subclass constructor the surface type is set based on the
selected 3D API.
\snippet rhiwindow/rhiwindow.cpp rhiwindow-ctor
Creating and initializing a QRhi object is implemented in
RhiWindow::init(). Note that this is invoked only when the window is
\c renderable, which is indicated by an \l{QExposeEvent}{expose event}.
Depending on which 3D API we use, the appropriate InitParams struct needs
to be passed to QRhi::create(). With OpenGL for example, a
QOffscreenSurface (or some other QSurface) must be created by the
application and provided for use to the QRhi. With Vulkan, a successfully
initialized QVulkanInstance is required. Others, such as Direct 3D or Metal
need no additional information to be able to initialize.
\snippet rhiwindow/rhiwindow.cpp rhi-init
Apart from this, everything else, all the rendering code, is fully
cross-platform and has no branching or conditions specific to any of the 3D
API.
\section1 Expose Events
What \c renderable exactly means is platform-specific. For example, on
macOS a window that is fully obscured (fully behind some other window) is
not renderable, whereas on Windows obscuring has no significance.
Fortunately, the application needs no special knowledge about this: Qt's
platform plugins abstract the differences behind the expose event. However,
the \l{QWindow::exposeEvent()}{exposeEvent()} reimplementation also needs
to be aware that an empty output size (e.g. width and height of 0) is also
something that should be treated as a non-renderable situation. On Windows
for example, this is what is going to happen when minimizing the window.
Hence the check based on QRhiSwapChain::surfacePixelSize().
This implementation of expose event handling attempts to be robust, safe,
and portable. Qt Quick itself also implements a very similar logic in its
render loops.
\snippet rhiwindow/rhiwindow.cpp expose
In RhiWindow::render(), which is invoked in response to the
\l{QEvent::UpdateRequest}{UpdateRequest} event generated by
\l{QWindow::requestUpdate()}{requestUpdate()}, the following check is in
place, to prevent attempting to render when the swapchain initialization
failed, or when the window became non-renderable.
\snippet rhiwindow/rhiwindow.cpp render-precheck
\section1 Swapchain, Depth-Stencil buffer, and Resizing
To render to the QWindow, a QRhiSwapChain is needed. In addition, a
QRhiRenderBuffer acting as the depth-stencil buffer is created as well
since the application demonstrates how depth testing can be enabled in a
graphics pipeline. With some legacy 3D APIs managing the depth/stencil
buffer for a window is part of the corresponding windowing system interface
API (EGL, WGL, GLX, etc., meaning the depth/stencil buffer is implicitly
managed together with the \c{window surface}), whereas with modern APIs
managing the depth-stencil buffer for a window-based render target is no
different from offscreen render targets. QRhi abstracts this, but for best
performance it still needs to be indicated that the QRhiRenderBuffer is
\l{QRhiRenderBuffer::UsedWithSwapChainOnly}{used with together with a
QRhiSwapChain}.
The QRhiSwapChain is associated with the QWindow and the depth/stencil
buffer.
\snippet rhiwindow/rhiwindow.cpp swapchain-data
\snippet rhiwindow/rhiwindow.cpp swapchain-init
When the window size changes, the swapchain needs to be resized as well.
This is implemented in resizeSwapChain().
\snippet rhiwindow/rhiwindow.cpp swapchain-resize
Unlike other QRhiResource subclasses, QRhiSwapChain features slightly
different semantics when it comes to its create-function. As the name,
\l{QRhiSwapChain::createOrResize()}{createOrResize()}, suggests, this needs
to be called whenever it is known that the output window size may be out of
sync with what the swapchain was last initialized. The associated
QRhiRenderBuffer for depth-stencil gets its
\l{QRhiRenderBuffer::pixelSize()}{size} set automatically, and
\l{QRhiRenderBuffer::create()}{create()} is called on it implicitly from the
swapchain's createOrResize().
This is also a convenient place to (re)calculate the projection and view
matrices since the perspective projection we set up depends on the output
aspect ratio.
\note To eliminate coordinate system differences, the
\l{QRhi::clipSpaceCorrMatrix()}{a backend/API-specific "correction" matrix}
is queried from QRhi and baked in to the projection matrix. This is what
allows the application to work with OpenGL-style vertex data, assuming a
coordinate system with the origin at the bottom-left.
The resizeSwapChain() function is called from RhiWindow::render() when it
is discovered that the currently reported size is not the same anymore as
what the swapchain was last initialized with.
See QRhiSwapChain::currentPixelSize() and QRhiSwapChain::surfacePixelSize()
for further details.
High DPI support is built-in: the sizes, as the naming indicates, are
always in pixels, taking the window-specific
\l{QWindow::devicePixelRatio()}{scale factor} into account. On the QRhi
(and 3D API) level there is no concept of high DPI scaling, everything is
always in pixels. This means that a QWindow with a size() of 1280x720 and
a devicePixelRatio() of 2 is a render target (swapchain) with a (pixel) size
of 2560x1440.
\snippet rhiwindow/rhiwindow.cpp render-resize
\section1 Render Loop
The application renders continuously, throttled by the presentation rate
(vsync). This is ensured by calling
\l{QWindow::requestUpdate()}{requestUpdate()} from RhiWindow::render() when
the currently recorded frame has been submitted.
\snippet rhiwindow/rhiwindow.cpp request-update
This eventually leads to getting a \l{QEvent::UpdateRequest}{UpdateRequest}
event. This is handled in the reimplementation of event().
\snippet rhiwindow/rhiwindow.cpp event
\section1 Resource and Pipeline Setup
The application records a single render pass that issues two draw calls,
with two different graphics pipelines. One is the "background", with the
texture containing the QPainter-generated image, then a single triangle is
rendered on top with blending enabled.
The vertex and uniform buffer used with the triangle is created like this.
The size of the uniform buffer is 68 bytes since the shader specific a \c
mat4 and a \c float member in the uniform block. Watch out for the
\l{https://registry.khronos.org/OpenGL/specs/gl/glspec45.core.pdf#page=159}{std140
layout rules}. This presents no surprises in this example since the \c
float member that follows the \c mat4 has the correct alignment without any
additional padding, but it may become relevant in other applications,
especially when working with types such as \c vec2 or \c vec3. When in
doubt, consider checking the QShaderDescription for the
\l{QShader::description()}{QShader}, or, what is often more convenient, run
the \c qsb tool on the \c{.qsb} file with the \c{-d} argument to inspect
the metadata in human-readable form. The printed information includes,
among other things, the uniform block member offsets, sizes, and the total
size in bytes of each uniform block.
\snippet rhiwindow/rhiwindow.cpp render-init-1
The vertex and fragment shaders both need a uniform buffer at binding point
0. This is ensured by the QRhiShaderResourceBindings object. The graphics
pipeline is then setup with the shaders and a number of additional
information. The example also relies on a number of convenient defaults,
e.g. the primitive topology is
\l{QRhiGraphicsPipeline::Triangles}{Triangles}, but that is the default,
and therefore it is not explicitly set. See QRhiGraphicsPipeline for
further details.
In addition to specifying the topology and various state, the pipeline must
also be associated with:
\list
\li The vertex input layout in form of a QRhiVertexInputLayout. This
specifies the type and component count for each vertex input location, the
total stride in bytes per vertex, and other related data.
QRhiVertexInputLayout only holds data, not actual native resources, and is
copiable.
\li A valid and successfully initialized QRhiShaderResourceBindings object.
This describes the layout of the resource bindings (uniform buffers,
textures, samplers) the shaders expect. This must either by the
QRhiShaderResourceBindings used when recording the draw calls, or another
that is
\l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible with it}.
This simple application takes the former approach.
\li A valid QRhiRenderPassDescriptor object. This must be retrieved from,
or \l{QRhiRenderPassDescriptor::isCompatible()}{be compatible with} the
render target. The example uses the former, by creating a
QRhiRenderPassDescriptor object via
QRhiSwapChain::newCompatibleRenderPassDescriptor().
\endlist
\snippet rhiwindow/rhiwindow.cpp render-init-2
getShader() is a helper function that loads a \c{.qsb} file and
deserializes a QShader from it.
\snippet rhiwindow/rhiwindow.cpp getshader
The \c{color.vert} shader specifies the following as the vertex inputs:
\badcode
layout(location = 0) in vec4 position;
layout(location = 1) in vec3 color;
\endcode
The C++ code however provides vertex data as 2 floats for position, with 3
floats for the color interleaved. (\c x, \c y, \c r, \c g, \c b for each
vertex) This is why the stride is \c{5 * sizeof(float)} and the inputs for
locations 0 and 1 are specified as \c Float2 and \c Float3, respectively.
This is valid, and the \c z and \c w of the \c vec4 position will get set
automatically.
\section1 Rendering
Recording a frame is started by calling \l{QRhi::beginFrame()} and finished
by calling \l{QRhi::endFrame()}.
\snippet rhiwindow/rhiwindow.cpp beginframe
Some of the resources (buffers, textures) have static data in the
application, meaning the content never changes. The vertex buffer's content
is provided in the initialization step for example, and is not changed
afterwards. These data update operations are recorded in \c
m_initialUpdates. When not yet done, the commands on this resource update
batch are merged into the per-frame batch.
\snippet rhiwindow/rhiwindow.cpp render-1
Having a per-frame resource update batch is necessary since the uniform
buffer contents with the modelview-projection matrix and the opacity
changes on every frame.
\snippet rhiwindow/rhiwindow.cpp render-rotation
\snippet rhiwindow/rhiwindow.cpp render-opacity
To begin recording the render pass, a QRhiCommandBuffer is queried, and the
output size is determined, which will be useful for setting up the viewport
and resizing our fullscreen texture, if needed.
\snippet rhiwindow/rhiwindow.cpp render-cb
Starting a render pass implies clearing the render target's color and
depth-stencil buffers (unless the render target flags indicate otherwise,
but that is only an option for texture-based render targets). Here we
specify black for color, 1.0f for depth, and 0 for stencil (unused). The
last argument, \c resourceUpdates, is what ensures that the data update
commands recorded on the batch get committed. Alternatively, we could have
used QRhiCommandBuffer::resourceUpdate() instead. The render pass targets a
swapchain, hence calling
\l{QRhiSwapChain::currentFrameRenderTarget()}{currentFrameRenderTarget()}
to get a valid QRhiRenderTarget.
\snippet rhiwindow/rhiwindow.cpp render-pass
Recording the draw call for the triangle is straightforward: set the
pipeline, set the shader resources, set the vertex/index buffer(s), and
record the draw call. Here we use a non-indexed draw with just 3 vertices.
\snippet rhiwindow/rhiwindow.cpp render-pass-record
The \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} call
has no arguments given, which implies using \c m_colorTriSrb since that was
associated with the active QRhiGraphicsPipeline (\c m_colorPipeline).
We will not dive into the details of the rendering of the fullscreen
background image. See the example source code for that. It is however worth
noting a common pattern for "resizing" a texture or buffer resource. There
is no such thing as changing the size of an existing native resource, so
changing a texture or buffer size must be followed by a call to create(),
to release and recreate the underlying native resources. To ensure that the
QRhiTexture always has the required size, the application implements the
following logic. Note that \c m_texture stays valid for the entire lifetime
of the window, which means object references to it, e.g. in a
QRhiShaderResourceBindings, continue to be valid all the time. It is only
the underlying native resources that come and go over time.
\snippet rhiwindow/rhiwindow.cpp ensure-texture
Once a QImage is generated and the QPainter-based drawing into it has
finished, we use
\l{QRhiResourceUpdateBatch::uploadTexture()}{uploadTexture()} to record a
texture upload on the resource update batch:
\snippet rhiwindow/rhiwindow.cpp ensure-texture-2
\sa QRhi, QRhiSwapChain, QWindow, QRhiCommandBuffer, QRhiResourceUpdateBatch, QRhiBuffer, QRhiTexture
*/

View File

@ -4,4 +4,5 @@ TEMPLATE = subdirs
QT_FOR_CONFIG += gui
CONFIG += no_docs_target
SUBDIRS += rasterwindow
SUBDIRS += rasterwindow \
rhiwindow

View File

@ -0,0 +1,59 @@
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(rhiwindow LANGUAGES CXX)
if(NOT DEFINED INSTALL_EXAMPLESDIR)
set(INSTALL_EXAMPLESDIR "examples")
endif()
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/gui/rhiwindow")
find_package(Qt6 REQUIRED COMPONENTS Core Gui)
qt_standard_project_setup()
qt_add_executable(rhiwindow
main.cpp
rhiwindow.cpp rhiwindow.h
)
set_target_properties(rhiwindow PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(rhiwindow PRIVATE
Qt6::Core
Qt6::Gui
Qt6::GuiPrivate
)
set_source_files_properties("shaders/prebuilt/color.vert.qsb"
PROPERTIES QT_RESOURCE_ALIAS "color.vert.qsb"
)
set_source_files_properties("shaders/prebuilt/color.frag.qsb"
PROPERTIES QT_RESOURCE_ALIAS "color.frag.qsb"
)
set_source_files_properties("shaders/prebuilt/quad.vert.qsb"
PROPERTIES QT_RESOURCE_ALIAS "quad.vert.qsb"
)
set_source_files_properties("shaders/prebuilt/quad.frag.qsb"
PROPERTIES QT_RESOURCE_ALIAS "quad.frag.qsb"
)
qt_add_resources(rhiwindow "rhiwindow"
PREFIX
"/"
FILES
"shaders/prebuilt/color.vert.qsb"
"shaders/prebuilt/color.frag.qsb"
"shaders/prebuilt/quad.vert.qsb"
"shaders/prebuilt/quad.frag.qsb"
)
install(TARGETS rhiwindow
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)

View File

@ -0,0 +1,100 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QGuiApplication>
#include <QCommandLineParser>
#include "rhiwindow.h"
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
QRhi::Implementation graphicsApi;
// Use platform-specific defaults when no command-line arguments given.
#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"));
cmdLineParser.addOption(glOption);
QCommandLineOption vkOption({ "v", "vulkan" }, QLatin1String("Vulkan"));
cmdLineParser.addOption(vkOption);
QCommandLineOption d3d11Option({ "d", "d3d11" }, QLatin1String("Direct3D 11"));
cmdLineParser.addOption(d3d11Option);
QCommandLineOption d3d12Option({ "D", "d3d12" }, QLatin1String("Direct3D 12"));
cmdLineParser.addOption(d3d12Option);
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(d3d11Option))
graphicsApi = QRhi::D3D11;
if (cmdLineParser.isSet(d3d12Option))
graphicsApi = QRhi::D3D12;
if (cmdLineParser.isSet(mtlOption))
graphicsApi = QRhi::Metal;
//! [api-setup]
// For OpenGL.
QSurfaceFormat fmt;
fmt.setDepthBufferSize(24);
fmt.setStencilBufferSize(8);
QSurfaceFormat::setDefaultFormat(fmt);
// For Vulkan.
#if QT_CONFIG(vulkan)
QVulkanInstance inst;
if (graphicsApi == QRhi::Vulkan) {
// Request validation, if available. This is completely optional
// and has a performance impact, and should be avoided in production use.
inst.setLayers({ "VK_LAYER_KHRONOS_validation" });
// Play nice with QRhi.
inst.setExtensions(QRhiVulkanInitParams::preferredInstanceExtensions());
if (!inst.create()) {
qWarning("Failed to create Vulkan instance, switching to OpenGL");
graphicsApi = QRhi::OpenGLES2;
}
}
#endif
//! [api-setup]
HelloWindow window(graphicsApi);
#if QT_CONFIG(vulkan)
if (graphicsApi == QRhi::Vulkan)
window.setVulkanInstance(&inst);
#endif
window.resize(1280, 720);
window.setTitle(QCoreApplication::applicationName() + QLatin1String(" - ") + window.graphicsApiName());
window.show();
int ret = app.exec();
// RhiWindow::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 (window.handle())
window.releaseSwapChain();
return ret;
}

View File

@ -0,0 +1,435 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "rhiwindow.h"
#include <QPlatformSurfaceEvent>
#include <QPainter>
#include <QFile>
#include <rhi/qshader.h>
//! [rhiwindow-ctor]
RhiWindow::RhiWindow(QRhi::Implementation graphicsApi)
: m_graphicsApi(graphicsApi)
{
switch (graphicsApi) {
case QRhi::OpenGLES2:
setSurfaceType(OpenGLSurface);
break;
case QRhi::Vulkan:
setSurfaceType(VulkanSurface);
break;
case QRhi::D3D11:
case QRhi::D3D12:
setSurfaceType(Direct3DSurface);
break;
case QRhi::Metal:
setSurfaceType(MetalSurface);
break;
case QRhi::Null:
break; // RasterSurface
}
}
//! [rhiwindow-ctor]
QString RhiWindow::graphicsApiName() const
{
switch (m_graphicsApi) {
case QRhi::Null:
return QLatin1String("Null (no output)");
case QRhi::OpenGLES2:
return QLatin1String("OpenGL");
case QRhi::Vulkan:
return QLatin1String("Vulkan");
case QRhi::D3D11:
return QLatin1String("Direct3D 11");
case QRhi::D3D12:
return QLatin1String("Direct3D 12");
case QRhi::Metal:
return QLatin1String("Metal");
}
return QString();
}
//! [expose]
void RhiWindow::exposeEvent(QExposeEvent *)
{
// initialize and start rendering when the window becomes usable for graphics purposes
if (isExposed() && !m_initialized) {
init();
resizeSwapChain();
m_initialized = true;
}
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_initialized && !m_notExposed)
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_initialized && m_notExposed && !surfaceSize.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() && !surfaceSize.isEmpty())
render();
}
//! [expose]
//! [event]
bool RhiWindow::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);
}
//! [event]
//! [rhi-init]
void RhiWindow::init()
{
if (m_graphicsApi == QRhi::Null) {
QRhiNullInitParams params;
m_rhi.reset(QRhi::create(QRhi::Null, &params));
}
#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));
}
#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));
}
#endif
#ifdef Q_OS_WIN
if (m_graphicsApi == QRhi::D3D11) {
QRhiD3D11InitParams params;
// Enable the debug layer, if available. This is optional
// and should be avoided in production builds.
params.enableDebugLayer = true;
m_rhi.reset(QRhi::create(QRhi::D3D11, &params));
} else if (m_graphicsApi == QRhi::D3D12) {
QRhiD3D12InitParams params;
// Enable the debug layer, if available. This is optional
// and should be avoided in production builds.
params.enableDebugLayer = true;
m_rhi.reset(QRhi::create(QRhi::D3D12, &params));
}
#endif
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
if (m_graphicsApi == QRhi::Metal) {
QRhiMetalInitParams params;
m_rhi.reset(QRhi::create(QRhi::Metal, &params));
}
#endif
if (!m_rhi)
qFatal("Failed to create RHI backend");
//! [rhi-init]
//! [swapchain-init]
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());
//! [swapchain-init]
customInit();
}
//! [swapchain-resize]
void RhiWindow::resizeSwapChain()
{
m_hasSwapChain = m_sc->createOrResize(); // also handles m_ds
const QSize outputSize = m_sc->currentPixelSize();
m_viewProjection = m_rhi->clipSpaceCorrMatrix();
m_viewProjection.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
m_viewProjection.translate(0, 0, -4);
}
//! [swapchain-resize]
void RhiWindow::releaseSwapChain()
{
if (m_hasSwapChain) {
m_hasSwapChain = false;
m_sc->destroy();
}
}
//! [render-precheck]
void RhiWindow::render()
{
if (!m_hasSwapChain || m_notExposed)
return;
//! [render-precheck]
//! [render-resize]
// If the window got resized or newly exposed, resize the swapchain. (the
// newly-exposed case is not actually required by some platforms, but is
// here for robustness and portability)
//
// 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;
}
//! [render-resize]
//! [beginframe]
QRhi::FrameOpResult result = m_rhi->beginFrame(m_sc.get());
if (result == QRhi::FrameOpSwapChainOutOfDate) {
resizeSwapChain();
if (!m_hasSwapChain)
return;
result = m_rhi->beginFrame(m_sc.get());
}
if (result != QRhi::FrameOpSuccess) {
qWarning("beginFrame failed with %d, will retry", result);
requestUpdate();
return;
}
customRender();
//! [beginframe]
//! [request-update]
m_rhi->endFrame(m_sc.get());
// Always request the next frame via requestUpdate(). On some platforms this is backed
// by a platform-specific solution, e.g. CVDisplayLink on macOS, which is potentially
// more efficient than a timer, queued metacalls, etc.
requestUpdate();
}
//! [request-update]
static float vertexData[] = {
// Y up (note clipSpaceCorrMatrix in m_viewProjection), 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,
};
//! [getshader]
static QShader getShader(const QString &name)
{
QFile f(name);
if (f.open(QIODevice::ReadOnly))
return QShader::fromSerialized(f.readAll());
return QShader();
}
//! [getshader]
HelloWindow::HelloWindow(QRhi::Implementation graphicsApi)
: RhiWindow(graphicsApi)
{
}
//! [ensure-texture]
void HelloWindow::ensureFullscreenTexture(const QSize &pixelSize, QRhiResourceUpdateBatch *u)
{
if (m_texture && m_texture->pixelSize() == pixelSize)
return;
if (!m_texture)
m_texture.reset(m_rhi->newTexture(QRhiTexture::RGBA8, pixelSize));
else
m_texture->setPixelSize(pixelSize);
m_texture->create();
QImage image(pixelSize, QImage::Format_RGBA8888_Premultiplied);
//! [ensure-texture]
QPainter painter(&image);
painter.fillRect(QRectF(QPointF(0, 0), pixelSize), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f));
painter.setPen(Qt::transparent);
painter.setBrush({ QGradient(QGradient::DeepBlue) });
painter.drawRoundedRect(QRectF(QPointF(20, 20), pixelSize - QSize(40, 40)), 16, 16);
painter.setPen(Qt::black);
QFont font;
font.setPixelSize(0.05 * qMin(pixelSize.width(), pixelSize.height()));
painter.setFont(font);
painter.drawText(QRectF(QPointF(60, 60), pixelSize - QSize(120, 120)), 0,
QLatin1String("Rendering with QRhi to a resizable QWindow.\nThe 3D API is %1.\nUse the command-line options to choose a different API.")
.arg(graphicsApiName()));
painter.end();
if (m_rhi->isYUpInNDC())
image = image.mirrored();
//! [ensure-texture-2]
u->uploadTexture(m_texture.get(), image);
//! [ensure-texture-2]
}
//! [render-init-1]
void HelloWindow::customInit()
{
m_initialUpdates = m_rhi->nextResourceUpdateBatch();
m_vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)));
m_vbuf->create();
m_initialUpdates->uploadStaticBuffer(m_vbuf.get(), vertexData);
static const quint32 UBUF_SIZE = 68;
m_ubuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, UBUF_SIZE));
m_ubuf->create();
//! [render-init-1]
ensureFullscreenTexture(m_sc->surfacePixelSize(), m_initialUpdates);
m_sampler.reset(m_rhi->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
m_sampler->create();
//! [render-init-2]
m_colorTriSrb.reset(m_rhi->newShaderResourceBindings());
static const QRhiShaderResourceBinding::StageFlags visibility =
QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage;
m_colorTriSrb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, visibility, m_ubuf.get())
});
m_colorTriSrb->create();
m_colorPipeline.reset(m_rhi->newGraphicsPipeline());
// Enable depth testing; not quite needed for a simple triangle, but we
// have a depth-stencil buffer so why not.
m_colorPipeline->setDepthTest(true);
m_colorPipeline->setDepthWrite(true);
// Blend factors default to One, OneOneMinusSrcAlpha, which is convenient.
QRhiGraphicsPipeline::TargetBlend premulAlphaBlend;
premulAlphaBlend.enable = true;
m_colorPipeline->setTargetBlends({ premulAlphaBlend });
m_colorPipeline->setShaderStages({
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/color.vert.qsb")) },
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/color.frag.qsb")) }
});
QRhiVertexInputLayout inputLayout;
inputLayout.setBindings({
{ 5 * sizeof(float) }
});
inputLayout.setAttributes({
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
{ 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) }
});
m_colorPipeline->setVertexInputLayout(inputLayout);
m_colorPipeline->setShaderResourceBindings(m_colorTriSrb.get());
m_colorPipeline->setRenderPassDescriptor(m_rp.get());
m_colorPipeline->create();
//! [render-init-2]
m_fullscreenQuadSrb.reset(m_rhi->newShaderResourceBindings());
m_fullscreenQuadSrb->setBindings({
QRhiShaderResourceBinding::sampledTexture(0, QRhiShaderResourceBinding::FragmentStage,
m_texture.get(), m_sampler.get())
});
m_fullscreenQuadSrb->create();
m_fullscreenQuadPipeline.reset(m_rhi->newGraphicsPipeline());
m_fullscreenQuadPipeline->setShaderStages({
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/quad.vert.qsb")) },
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/quad.frag.qsb")) }
});
m_fullscreenQuadPipeline->setVertexInputLayout({});
m_fullscreenQuadPipeline->setShaderResourceBindings(m_fullscreenQuadSrb.get());
m_fullscreenQuadPipeline->setRenderPassDescriptor(m_rp.get());
m_fullscreenQuadPipeline->create();
}
//! [render-1]
void HelloWindow::customRender()
{
QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch();
if (m_initialUpdates) {
resourceUpdates->merge(m_initialUpdates);
m_initialUpdates->release();
m_initialUpdates = nullptr;
}
//! [render-1]
//! [render-rotation]
m_rotation += 1.0f;
QMatrix4x4 modelViewProjection = m_viewProjection;
modelViewProjection.rotate(m_rotation, 0, 1, 0);
resourceUpdates->updateDynamicBuffer(m_ubuf.get(), 0, 64, modelViewProjection.constData());
//! [render-rotation]
//! [render-opacity]
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);
}
resourceUpdates->updateDynamicBuffer(m_ubuf.get(), 64, 4, &m_opacity);
//! [render-opacity]
//! [render-cb]
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
const QSize outputSizeInPixels = m_sc->currentPixelSize();
//! [render-cb]
// (re)create the texture with a size matching the output surface size, when necessary.
ensureFullscreenTexture(outputSizeInPixels, resourceUpdates);
//! [render-pass]
cb->beginPass(m_sc->currentFrameRenderTarget(), Qt::black, { 1.0f, 0 }, resourceUpdates);
//! [render-pass]
cb->setGraphicsPipeline(m_fullscreenQuadPipeline.get());
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
cb->setShaderResources();
cb->draw(3);
//! [render-pass-record]
cb->setGraphicsPipeline(m_colorPipeline.get());
cb->setShaderResources();
const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
cb->setVertexInput(0, 1, &vbufBinding);
cb->draw(3);
cb->endPass();
//! [render-pass-record]
}

View File

@ -0,0 +1,78 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef WINDOW_H
#define WINDOW_H
#include <QWindow>
#include <QOffscreenSurface>
#include <rhi/qrhi.h>
class RhiWindow : public QWindow
{
public:
RhiWindow(QRhi::Implementation graphicsApi);
QString graphicsApiName() const;
void releaseSwapChain();
protected:
virtual void customInit() = 0;
virtual void customRender() = 0;
// 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;
//! [swapchain-data]
std::unique_ptr<QRhiSwapChain> m_sc;
std::unique_ptr<QRhiRenderBuffer> m_ds;
std::unique_ptr<QRhiRenderPassDescriptor> m_rp;
//! [swapchain-data]
bool m_hasSwapChain = false;
QMatrix4x4 m_viewProjection;
private:
void init();
void resizeSwapChain();
void render();
void exposeEvent(QExposeEvent *) override;
bool event(QEvent *) override;
QRhi::Implementation m_graphicsApi;
bool m_initialized = false;
bool m_notExposed = false;
bool m_newlyExposed = false;
};
class HelloWindow : public RhiWindow
{
public:
HelloWindow(QRhi::Implementation graphicsApi);
void customInit() override;
void customRender() override;
private:
void ensureFullscreenTexture(const QSize &pixelSize, QRhiResourceUpdateBatch *u);
std::unique_ptr<QRhiBuffer> m_vbuf;
std::unique_ptr<QRhiBuffer> m_ubuf;
std::unique_ptr<QRhiTexture> m_texture;
std::unique_ptr<QRhiSampler> m_sampler;
std::unique_ptr<QRhiShaderResourceBindings> m_colorTriSrb;
std::unique_ptr<QRhiGraphicsPipeline> m_colorPipeline;
std::unique_ptr<QRhiShaderResourceBindings> m_fullscreenQuadSrb;
std::unique_ptr<QRhiGraphicsPipeline> m_fullscreenQuadPipeline;
QRhiResourceUpdateBatch *m_initialUpdates = nullptr;
float m_rotation = 0;
float m_opacity = 1;
int m_opacityDir = -1;
};
#endif

View File

@ -0,0 +1,4 @@
INCLUDEPATH += $$PWD
SOURCES += $$PWD/rhiwindow.cpp
HEADERS += $$PWD/rhiwindow.h
RESOURCES += $$PWD/rhiwindow.qrc

View File

@ -0,0 +1,9 @@
include(rhiwindow.pri)
QT += gui-private
SOURCES += \
main.cpp
target.path = $$[QT_INSTALL_EXAMPLES]/gui/rhiwindow
INSTALLS += target

View File

@ -0,0 +1,8 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file alias="color.vert.qsb">shaders/prebuilt/color.vert.qsb</file>
<file alias="color.frag.qsb">shaders/prebuilt/color.frag.qsb</file>
<file alias="quad.vert.qsb">shaders/prebuilt/quad.vert.qsb</file>
<file alias="quad.frag.qsb">shaders/prebuilt/quad.frag.qsb</file>
</qresource>
</RCC>

View File

@ -0,0 +1,15 @@
#version 440
layout(location = 0) in vec3 v_color;
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
mat4 mvp;
float opacity;
};
void main()
{
fragColor = vec4(v_color * opacity, opacity);
}

View File

@ -0,0 +1,17 @@
#version 440
layout(location = 0) in vec4 position;
layout(location = 1) in vec3 color;
layout(location = 0) out vec3 v_color;
layout(std140, binding = 0) uniform buf {
mat4 mvp;
float opacity;
};
void main()
{
v_color = color;
gl_Position = mvp * position;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,11 @@
#version 440
layout(location = 0) in vec2 v_uv;
layout(location = 0) out vec4 fragColor;
layout(binding = 0) uniform sampler2D tex;
void main()
{
vec4 c = texture(tex, v_uv);
fragColor = vec4(c.rgb * c.a, c.a);
}

View File

@ -0,0 +1,10 @@
#version 440
layout (location = 0) out vec2 v_uv;
void main()
{
// https://www.saschawillems.de/blog/2016/08/13/vulkan-tutorial-on-rendering-a-fullscreen-quad-without-buffers/
v_uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
gl_Position = vec4(v_uv * 2.0 - 1.0, 0.0, 1.0);
}

View File

@ -212,14 +212,10 @@ qt_internal_add_module(Gui
painting/qtriangulatingstroker.cpp painting/qtriangulatingstroker_p.h
painting/qtriangulator.cpp painting/qtriangulator_p.h
painting/qvectorpath_p.h
rhi/qrhi.cpp rhi/qrhi_p.h
rhi/qrhi_p_p.h
rhi/qrhi.cpp rhi/qrhi.h rhi/qrhi_platform.h rhi/qrhi_p.h
rhi/qrhinull.cpp rhi/qrhinull_p.h
rhi/qrhinull_p_p.h
rhi/qshader.cpp rhi/qshader_p.h
rhi/qshader_p_p.h
rhi/qshaderdescription.cpp rhi/qshaderdescription_p.h
rhi/qshaderdescription_p_p.h
rhi/qshader.cpp rhi/qshader.h rhi/qshader_p.h
rhi/qshaderdescription.cpp rhi/qshaderdescription.h rhi/qshaderdescription_p.h
text/qabstracttextdocumentlayout.cpp text/qabstracttextdocumentlayout.h text/qabstracttextdocumentlayout_p.h
text/qdistancefield.cpp text/qdistancefield_p.h
text/qfont.cpp text/qfont.h text/qfont_p.h
@ -283,6 +279,8 @@ qt_internal_add_module(Gui
GENERATE_CPP_EXPORTS
QPA_HEADER_FILTERS
"(^|/)qplatform.+\\.h$|(^|/)qwindowsystem.+\\.h$"
RHI_HEADER_FILTERS
"(^|/)qrhi\\.h$|(^|/)qrhi_platform\\.h$|(^|/)qshader\\.h$|(^|/)qshaderdescription\\.h$"
)
# Resources:
@ -358,7 +356,6 @@ qt_internal_extend_target(Gui CONDITION QT_FEATURE_opengl
opengl/qopenglfunctions.cpp
opengl/qopenglprogrambinarycache.cpp opengl/qopenglprogrambinarycache_p.h
rhi/qrhigles2.cpp rhi/qrhigles2_p.h
rhi/qrhigles2_p_p.h
)
qt_internal_extend_target(Gui CONDITION MACOS
@ -409,10 +406,8 @@ qt_internal_extend_target(Gui CONDITION WIN32
platform/windows/qwindowsmimeconverter.h platform/windows/qwindowsmimeconverter.cpp
platform/windows/qwindowsnativeinterface.cpp
rhi/qrhid3d11.cpp rhi/qrhid3d11_p.h
rhi/qrhid3d11_p_p.h
rhi/vs_test_p.h
rhi/qrhid3d12.cpp rhi/qrhid3d12_p.h
rhi/qrhid3d12_p_p.h
rhi/cs_mipmap_p.h
../3rdparty/D3D12MemoryAllocator/D3D12MemAlloc.h
../3rdparty/D3D12MemoryAllocator/D3D12MemAlloc.cpp
@ -832,8 +827,7 @@ qt_internal_extend_target(Gui CONDITION QT_FEATURE_filesystemmodel
qt_internal_extend_target(Gui CONDITION QT_FEATURE_vulkan
SOURCES
rhi/qrhivulkan.cpp rhi/qrhivulkan_p.h
rhi/qrhivulkanext_p.h
rhi/qrhivulkan.cpp rhi/qrhivulkan_p.h rhi/qrhivulkanext_p.h
vulkan/qbasicvulkanplatforminstance.cpp vulkan/qbasicvulkanplatforminstance_p.h
vulkan/qplatformvulkaninstance.cpp vulkan/qplatformvulkaninstance.h
vulkan/qvulkandefaultinstance.cpp vulkan/qvulkandefaultinstance_p.h
@ -969,7 +963,6 @@ qt_internal_extend_target(Gui CONDITION QT_FEATURE_xkbcommon AND UNIX
qt_internal_extend_target(Gui CONDITION IOS OR MACOS
SOURCES
rhi/qrhimetal.mm rhi/qrhimetal_p.h
rhi/qrhimetal_p_p.h
PUBLIC_LIBRARIES
${FWMetal}
)

View File

@ -16,3 +16,8 @@
#include <QtGui/qpa/qplatformscreen_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qkeymapper_p.h>
// rhi
#include <QtGui/rhi/qrhi.h>
#include <QtGui/rhi/qshader.h>
#include <QtGui/rhi/qshaderdescription.h>

View File

@ -0,0 +1,16 @@
//! [0]
#version 440
layout(location = 0) in vec3 v_color;
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
mat4 mvp;
float opacity;
};
void main()
{
fragColor = vec4(v_color * opacity, opacity);
}
//! [0]

View File

@ -0,0 +1,18 @@
//! [0]
#version 440
layout(location = 0) in vec4 position;
layout(location = 1) in vec3 color;
layout(location = 0) out vec3 v_color;
layout(std140, binding = 0) uniform buf {
mat4 mvp;
float opacity;
};
void main()
{
v_color = color;
gl_Position = mvp * position;
}
//! [0]

View File

@ -0,0 +1,151 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
#include <QGuiApplication>
#include <QImage>
#include <QFile>
#include <rhi/qrhi.h>
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
std::unique_ptr<QRhi> rhi;
#if defined(Q_OS_WIN)
QRhiD3D12InitParams params;
rhi.reset(QRhi::create(QRhi::D3D12, &params));
#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
QRhiMetalInitParams params;
rhi.reset(QRhi::create(QRhi::Metal, &params));
#elif QT_CONFIG(vulkan)
QVulkanInstance inst;
inst.setExtensions(QRhiVulkanInitParams::preferredInstanceExtensions());
if (inst.create()) {
QRhiVulkanInitParams params;
params.inst = &inst;
rhi.reset(QRhi::create(QRhi::Vulkan, &params));
} else {
qFatal("Failed to create Vulkan instance");
}
#endif
if (rhi)
qDebug() << rhi->backendName() << rhi->driverInfo();
else
qFatal("Failed to initialize RHI");
float rotation = 0.0f;
float opacity = 1.0f;
int opacityDir = 1;
std::unique_ptr<QRhiTexture> tex(rhi->newTexture(QRhiTexture::RGBA8,
QSize(1280, 720),
1,
QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
tex->create();
std::unique_ptr<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ tex.get() }));
std::unique_ptr<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
rt->setRenderPassDescriptor(rp.get());
rt->create();
QMatrix4x4 viewProjection = rhi->clipSpaceCorrMatrix();
viewProjection.perspective(45.0f, 1280 / 720.f, 0.01f, 1000.0f);
viewProjection.translate(0, 0, -4);
static float vertexData[] = { // Y up, 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,
};
std::unique_ptr<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable,
QRhiBuffer::VertexBuffer,
sizeof(vertexData)));
vbuf->create();
std::unique_ptr<QRhiBuffer> ubuf(rhi->newBuffer(QRhiBuffer::Dynamic,
QRhiBuffer::UniformBuffer,
64 + 4));
ubuf->create();
std::unique_ptr<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
srb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0,
QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage,
ubuf.get())
});
srb->create();
std::unique_ptr<QRhiGraphicsPipeline> ps(rhi->newGraphicsPipeline());
QRhiGraphicsPipeline::TargetBlend premulAlphaBlend;
premulAlphaBlend.enable = true;
ps->setTargetBlends({ premulAlphaBlend });
static auto getShader = [](const QString &name) {
QFile f(name);
if (f.open(QIODevice::ReadOnly))
return QShader::fromSerialized(f.readAll());
return QShader();
};
ps->setShaderStages({
{ QRhiShaderStage::Vertex, getShader(QLatin1String("color.vert.qsb")) },
{ QRhiShaderStage::Fragment, getShader(QLatin1String("color.frag.qsb")) }
});
QRhiVertexInputLayout inputLayout;
inputLayout.setBindings({
{ 5 * sizeof(float) }
});
inputLayout.setAttributes({
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
{ 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) }
});
ps->setVertexInputLayout(inputLayout);
ps->setShaderResourceBindings(srb.get());
ps->setRenderPassDescriptor(rp.get());
ps->create();
QRhiCommandBuffer *cb;
for (int frame = 0; frame < 20; ++frame) {
rhi->beginOffscreenFrame(&cb);
QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch();
if (frame == 0)
u->uploadStaticBuffer(vbuf.get(), vertexData);
QMatrix4x4 mvp = viewProjection;
mvp.rotate(rotation, 0, 1, 0);
u->updateDynamicBuffer(ubuf.get(), 0, 64, mvp.constData());
rotation += 5.0f;
u->updateDynamicBuffer(ubuf.get(), 64, 4, &opacity);
opacity += opacityDir * 0.2f;
if (opacity < 0.0f || opacity > 1.0f) {
opacityDir *= -1;
opacity = qBound(0.0f, opacity, 1.0f);
}
cb->beginPass(rt.get(), Qt::green, { 1.0f, 0 }, u);
cb->setGraphicsPipeline(ps.get());
cb->setViewport({ 0, 0, 1280, 720 });
cb->setShaderResources();
const QRhiCommandBuffer::VertexInput vbufBinding(vbuf.get(), 0);
cb->setVertexInput(0, 1, &vbufBinding);
cb->draw(3);
QRhiReadbackResult readbackResult;
u = rhi->nextResourceUpdateBatch();
u->readBackTexture({ tex.get() }, &readbackResult);
cb->endPass(u);
rhi->endOffscreenFrame();
QImage image(reinterpret_cast<const uchar *>(readbackResult.data.constData()),
readbackResult.pixelSize.width(),
readbackResult.pixelSize.height(),
QImage::Format_RGBA8888_Premultiplied);
if (rhi->isYUpInFramebuffer())
image = image.mirrored();
image.save(QString::asprintf("frame%d.png", frame));
}
return 0;
}
//! [0]

View File

@ -51,6 +51,56 @@
that prefer more low-level APIs to text and font handling can use classes
like QRawFont and QGlyphRun.
\section1 RHI Graphics
The Qt Rendering Hardware Interface is an abstraction for hardware accelerated
graphics APIs, such as, \l{https://www.khronos.org/opengl/}{OpenGL},
\l{https://www.khronos.org/opengles/}{OpenGL ES},
\l{https://docs.microsoft.com/en-us/windows/desktop/direct3d}{Direct3D},
\l{https://developer.apple.com/metal/}{Metal}, and
\l{https://www.khronos.org/vulkan/}{Vulkan}.
As an alternative to using OpenGL or Vulkan directly to render to a
QWindow, \l QRhi and the related classes provide a portable, cross-platform
3D graphics and compute API complemented by a shader conditioning and
transpiling pipeline. This way applications can avoid directly depending on
a single, and, in some cases, vendor or platform-specific 3D API.
Below is a list of the main RHI-related classes. These are complemented by
a number of additional classes and structs.
\list
\li QRhi
\li QShader
\li QShaderDescription
\li QRhiCommandBuffer
\li QRhiResourceUpdateBatch
\li QRhiBuffer
\li QRhiRenderBuffer
\li QRhiTexture
\li QRhiSampler
\li QRhiTextureRenderTarget
\li QRhiShaderResourceBindings
\li QRhiGraphicsPipeline
\li QRhiComputePipeline
\li QRhiSwapChain
\endlist
See the \l{RHI Window Example} for an introductory example of creating a
portable, cross-platform application that performs accelerated 3D rendering
onto a QWindow using QRhi.
\note The RHI family of APIs are currently offered with a limited
compatibility guarantee, as opposed to regular Qt public APIs. See \l QRhi
for details.
\section1 3D Matrix and Vector Math
The Qt GUI module also contains a few math classes to aid with the most
common mathematical operations related to 3D graphics. These classes
include \l {QMatrix4x4}, \l {QVector2D}, \l {QVector3D}, \l {QVector4D},
and \l {QQuaternion}.
\section1 OpenGL and OpenGL ES Integration
QWindow supports rendering using OpenGL and OpenGL ES, depending on what the
@ -86,10 +136,6 @@
For more information, see the \l {OpenGL Window Example}.
The Qt GUI module also contains a few math classes to aid with the most
common mathematical operations related to 3D graphics. These classes include
\l {QMatrix4x4}, \l {QVector4D}, and \l {QQuaternion}.
A \l {QWindow} created with the \l {QSurface::OpenGLSurface} can be used in
combination with \l QPainter and \l QOpenGLPaintDevice to have OpenGL
hardware-accelerated 2D graphics by sacrificing some of the visual quality.
@ -104,18 +150,21 @@
On Android, Vulkan headers were added in API level 24 of the NDK.
Relevant classes:
The main relevant classes for low-level Vulkan support are:
\list
\li QVulkanDeviceFunctions
\li QVulkanExtension
\li QVulkanFunctions
\li QVulkanInfoVector
\li QVulkanInstance
\li QVulkanWindow
\li QVulkanWindowRenderer
\li QVulkanFunctions
\li QVulkanDeviceFunctions
\endlist
In addition, \l QVulkanWindow provides a convenience subclass of QWindow
that makes it easier to get started with implementing Vulkan-based
rendering targeting a QWindow. Using this helper class is completely
optional; applications with more advanced Vulkan-based renderers may
instead want to use a QWindow with the \l {QSurface::VulkanSurface} type
directly.
For more information, see the \l{Hello Vulkan Widget Example}
and the \l {Hello Vulkan Triangle Example}.

View File

@ -54,6 +54,8 @@
\list
\li \l {Application Windows} {Qt GUI Application Windows}
\li \l {2D Graphics} {Qt GUI 2D Graphics}
\li \l {RHI Graphics} {Qt GUI Accelerated 2D and 3D Graphics using the Qt RHI}
\li \l {3D Matrix and Vector Math} {Qt GUI Matrix and Vector Math}
\li \l {OpenGL and OpenGL ES Integration}
{Qt GUI OpenGL and OpenGL ES Integration}
\li \l {Vulkan Integration} {Qt GUI Vulkan Integration}

View File

@ -69,6 +69,7 @@ QOpenGLContext *qt_gl_global_share_context()
/*!
\class QOpenGLContext
\ingroup painting-3D
\inmodule QtGui
\since 5.0
\brief The QOpenGLContext class represents a native OpenGL context, enabling

View File

@ -20,7 +20,7 @@
#include <QtCore/qmutex.h>
#include <QtCore/QLoggingCategory>
#include <QtGui/private/qopenglcontext_p.h>
#include <QtGui/private/qshader_p.h>
#include <rhi/qshader.h>
QT_BEGIN_NAMESPACE

View File

@ -16,7 +16,7 @@
//
#include <qpa/qplatformbackingstore.h>
#include <QtGui/private/qrhi_p.h>
#include <rhi/qrhi.h>
QT_BEGIN_NAMESPACE

View File

@ -8,20 +8,9 @@
#if QT_CONFIG(opengl)
#include <QtGui/qoffscreensurface.h>
#include <QtGui/private/qopenglcontext_p.h>
#include <QtGui/private/qrhigles2_p.h>
#endif
#ifdef Q_OS_WIN
#include <QtGui/private/qrhid3d11_p.h>
#include <QtGui/private/qrhid3d12_p.h>
#endif
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
#include <QtGui/private/qrhimetal_p.h>
#endif
#if QT_CONFIG(vulkan)
#include <QtGui/private/qrhivulkan_p.h>
#include <QtGui/private/qvulkandefaultinstance_p.h>
#endif

View File

@ -19,7 +19,7 @@
#include <QtGui/qwindow.h>
#include <QtGui/qsurfaceformat.h>
#include <QtGui/qoffscreensurface.h>
#include <QtGui/private/qrhi_p.h>
#include <rhi/qrhi.h>
#include <qpa/qplatformbackingstore.h>
QT_BEGIN_NAMESPACE

File diff suppressed because it is too large Load Diff

1974
src/gui/rhi/qrhi.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,804 +0,0 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRHI_P_H
#define QRHI_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qrhi_p.h"
#include <QBitArray>
#include <QAtomicInt>
#include <QElapsedTimer>
#include <QLoggingCategory>
#include <QtCore/qset.h>
#include <QtCore/qvarlengtharray.h>
QT_BEGIN_NAMESPACE
#define QRHI_RES(t, x) static_cast<t *>(x)
#define QRHI_RES_RHI(t) t *rhiD = static_cast<t *>(m_rhi)
Q_DECLARE_LOGGING_CATEGORY(QRHI_LOG_INFO)
class QRhiImplementation
{
public:
virtual ~QRhiImplementation();
virtual bool create(QRhi::Flags flags) = 0;
virtual void destroy() = 0;
virtual QRhiGraphicsPipeline *createGraphicsPipeline() = 0;
virtual QRhiComputePipeline *createComputePipeline() = 0;
virtual QRhiShaderResourceBindings *createShaderResourceBindings() = 0;
virtual QRhiBuffer *createBuffer(QRhiBuffer::Type type,
QRhiBuffer::UsageFlags usage,
quint32 size) = 0;
virtual QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
int sampleCount,
QRhiRenderBuffer::Flags flags,
QRhiTexture::Format backingFormatHint) = 0;
virtual QRhiTexture *createTexture(QRhiTexture::Format format,
const QSize &pixelSize,
int depth,
int arraySize,
int sampleCount,
QRhiTexture::Flags flags) = 0;
virtual QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
QRhiSampler:: AddressMode u,
QRhiSampler::AddressMode v,
QRhiSampler::AddressMode w) = 0;
virtual QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
QRhiTextureRenderTarget::Flags flags) = 0;
virtual QRhiSwapChain *createSwapChain() = 0;
virtual QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) = 0;
virtual QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) = 0;
virtual QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) = 0;
virtual QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) = 0;
virtual QRhi::FrameOpResult finish() = 0;
virtual void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
virtual void beginPass(QRhiCommandBuffer *cb,
QRhiRenderTarget *rt,
const QColor &colorClearValue,
const QRhiDepthStencilClearValue &depthStencilClearValue,
QRhiResourceUpdateBatch *resourceUpdates,
QRhiCommandBuffer::BeginPassFlags flags) = 0;
virtual void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
virtual void setGraphicsPipeline(QRhiCommandBuffer *cb,
QRhiGraphicsPipeline *ps) = 0;
virtual void setShaderResources(QRhiCommandBuffer *cb,
QRhiShaderResourceBindings *srb,
int dynamicOffsetCount,
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) = 0;
virtual void setVertexInput(QRhiCommandBuffer *cb,
int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
QRhiBuffer *indexBuf, quint32 indexOffset,
QRhiCommandBuffer::IndexFormat indexFormat) = 0;
virtual void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) = 0;
virtual void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) = 0;
virtual void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) = 0;
virtual void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) = 0;
virtual void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) = 0;
virtual void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
quint32 instanceCount, quint32 firstIndex,
qint32 vertexOffset, quint32 firstInstance) = 0;
virtual void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) = 0;
virtual void debugMarkEnd(QRhiCommandBuffer *cb) = 0;
virtual void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) = 0;
virtual void beginComputePass(QRhiCommandBuffer *cb,
QRhiResourceUpdateBatch *resourceUpdates,
QRhiCommandBuffer::BeginPassFlags flags) = 0;
virtual void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
virtual void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) = 0;
virtual void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) = 0;
virtual const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) = 0;
virtual void beginExternal(QRhiCommandBuffer *cb) = 0;
virtual void endExternal(QRhiCommandBuffer *cb) = 0;
virtual double lastCompletedGpuTime(QRhiCommandBuffer *cb) = 0;
virtual QList<int> supportedSampleCounts() const = 0;
virtual int ubufAlignment() const = 0;
virtual bool isYUpInFramebuffer() const = 0;
virtual bool isYUpInNDC() const = 0;
virtual bool isClipDepthZeroToOne() const = 0;
virtual QMatrix4x4 clipSpaceCorrMatrix() const = 0;
virtual bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const = 0;
virtual bool isFeatureSupported(QRhi::Feature feature) const = 0;
virtual int resourceLimit(QRhi::ResourceLimit limit) const = 0;
virtual const QRhiNativeHandles *nativeHandles() = 0;
virtual QRhiDriverInfo driverInfo() const = 0;
virtual QRhiStats statistics() = 0;
virtual bool makeThreadLocalNativeContextCurrent() = 0;
virtual void releaseCachedResources() = 0;
virtual bool isDeviceLost() const = 0;
virtual QByteArray pipelineCacheData() = 0;
virtual void setPipelineCacheData(const QByteArray &data) = 0;
void prepareForCreate(QRhi *rhi, QRhi::Implementation impl, QRhi::Flags flags);
bool isCompressedFormat(QRhiTexture::Format format) const;
void compressedFormatInfo(QRhiTexture::Format format, const QSize &size,
quint32 *bpl, quint32 *byteSize,
QSize *blockDim) const;
void textureFormatInfo(QRhiTexture::Format format, const QSize &size,
quint32 *bpl, quint32 *byteSize, quint32 *bytesPerPixel) const;
void registerResource(QRhiResource *res, bool ownsNativeResources = true)
{
// The ownsNativeResources is relevant for the (graphics resource) leak
// check in ~QRhiImplementation; when false, the registration's sole
// purpose is to automatically null out the resource's m_rhi pointer in
// case the rhi goes away first. (which should not happen in
// well-written applications but we try to be graceful)
resources.insert(res, ownsNativeResources);
}
void unregisterResource(QRhiResource *res)
{
resources.remove(res);
}
void addDeleteLater(QRhiResource *res)
{
if (inFrame)
pendingDeleteResources.insert(res);
else
delete res;
}
void addCleanupCallback(const QRhi::CleanupCallback &callback)
{
cleanupCallbacks.append(callback);
}
bool sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps);
bool sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb);
void updateLayoutDesc(QRhiShaderResourceBindings *srb);
quint32 pipelineCacheRhiId() const
{
const quint32 ver = (QT_VERSION_MAJOR << 16) | (QT_VERSION_MINOR << 8) | (QT_VERSION_PATCH);
return (quint32(implType) << 24) | ver;
}
void pipelineCreationStart()
{
pipelineCreationTimer.start();
}
void pipelineCreationEnd()
{
accumulatedPipelineCreationTime += pipelineCreationTimer.elapsed();
}
qint64 totalPipelineCreationTime() const
{
return accumulatedPipelineCreationTime;
}
QRhiVertexInputAttribute::Format shaderDescVariableFormatToVertexInputFormat(QShaderDescription::VariableType type) const;
quint32 byteSizePerVertexForVertexInputFormat(QRhiVertexInputAttribute::Format format) const;
static const QRhiShaderResourceBinding::Data *shaderResourceBindingData(const QRhiShaderResourceBinding &binding)
{
return &binding.d;
}
static QRhiShaderResourceBinding::Data *shaderResourceBindingData(QRhiShaderResourceBinding &binding)
{
return &binding.d;
}
static bool sortedBindingLessThan(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{
return a.d.binding < b.d.binding;
}
QRhi *q;
static const int MAX_SHADER_CACHE_ENTRIES = 128;
bool debugMarkers = false;
int currentFrameSlot = 0; // for vk, mtl, and similar. unused by gl and d3d11.
bool inFrame = false;
private:
QRhi::Implementation implType;
QThread *implThread;
QVarLengthArray<QRhiResourceUpdateBatch *, 4> resUpdPool;
quint64 resUpdPoolMap = 0;
int lastResUpdIdx = -1;
QHash<QRhiResource *, bool> resources;
QSet<QRhiResource *> pendingDeleteResources;
QVarLengthArray<QRhi::CleanupCallback, 4> cleanupCallbacks;
QElapsedTimer pipelineCreationTimer;
qint64 accumulatedPipelineCreationTime = 0;
friend class QRhi;
friend class QRhiResourceUpdateBatchPrivate;
};
enum QRhiTargetRectBoundMode
{
UnBounded,
Bounded
};
template<QRhiTargetRectBoundMode boundingMode, typename T, size_t N>
bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array<T, N> &r,
T *x, T *y, T *w, T *h)
{
// x,y are bottom-left in QRhiScissor and QRhiViewport but top-left in
// Vulkan/Metal/D3D. Our input is an OpenGL-style scissor rect where both
// negative x or y, and partly or completely out of bounds rects are
// allowed. The only thing the input here cannot have is a negative width
// or height. We must handle all other input gracefully, clamping to a zero
// width or height rect in the worst case, and ensuring the resulting rect
// is inside the rendertarget's bounds because some APIs' validation/debug
// layers are allergic to out of bounds scissor rects.
const T outputWidth = outputSize.width();
const T outputHeight = outputSize.height();
const T inputWidth = r[2];
const T inputHeight = r[3];
if (inputWidth < 0 || inputHeight < 0)
return false;
*x = r[0];
*y = outputHeight - (r[1] + inputHeight);
*w = inputWidth;
*h = inputHeight;
if (boundingMode == Bounded) {
const T widthOffset = *x < 0 ? -*x : 0;
const T heightOffset = *y < 0 ? -*y : 0;
*w = *x < outputWidth ? qMax<T>(0, inputWidth - widthOffset) : 0;
*h = *y < outputHeight ? qMax<T>(0, inputHeight - heightOffset) : 0;
if (outputWidth > 0)
*x = qBound<T>(0, *x, outputWidth - 1);
if (outputHeight > 0)
*y = qBound<T>(0, *y, outputHeight - 1);
if (*x + *w > outputWidth)
*w = qMax<T>(0, outputWidth - *x);
if (*y + *h > outputHeight)
*h = qMax<T>(0, outputHeight - *y);
}
return true;
}
struct QRhiBufferDataPrivate
{
Q_DISABLE_COPY_MOVE(QRhiBufferDataPrivate)
QRhiBufferDataPrivate() { }
~QRhiBufferDataPrivate() { delete[] largeData; }
int ref = 1;
quint32 size = 0;
quint32 largeAlloc = 0;
char *largeData = nullptr;
static constexpr quint32 SMALL_DATA_SIZE = 1024;
char data[SMALL_DATA_SIZE];
};
// no detach-with-contents, no atomic refcount, no shrink
class QRhiBufferData
{
public:
QRhiBufferData() = default;
~QRhiBufferData()
{
if (d && !--d->ref)
delete d;
}
QRhiBufferData(const QRhiBufferData &other)
: d(other.d)
{
if (d)
d->ref += 1;
}
QRhiBufferData &operator=(const QRhiBufferData &other)
{
if (d == other.d)
return *this;
if (other.d)
other.d->ref += 1;
if (d && !--d->ref)
delete d;
d = other.d;
return *this;
}
const char *constData() const
{
return d->size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE ? d->data : d->largeData;
}
quint32 size() const
{
return d->size;
}
void assign(const char *s, quint32 size)
{
if (!d) {
d = new QRhiBufferDataPrivate;
} else if (d->ref != 1) {
d->ref -= 1;
d = new QRhiBufferDataPrivate;
}
d->size = size;
if (size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE) {
memcpy(d->data, s, size);
} else {
if (d->largeAlloc < size) {
delete[] d->largeData;
d->largeAlloc = size;
d->largeData = new char[size];
}
memcpy(d->largeData, s, size);
}
}
private:
QRhiBufferDataPrivate *d = nullptr;
};
Q_DECLARE_TYPEINFO(QRhiBufferData, Q_RELOCATABLE_TYPE);
class QRhiResourceUpdateBatchPrivate
{
public:
struct BufferOp {
enum Type {
DynamicUpdate,
StaticUpload,
Read
};
Type type;
QRhiBuffer *buf;
quint32 offset;
QRhiBufferData data;
quint32 readSize;
QRhiReadbackResult *result;
static BufferOp dynamicUpdate(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
{
BufferOp op = {};
op.type = DynamicUpdate;
op.buf = buf;
op.offset = offset;
const int effectiveSize = size ? size : buf->size();
op.data.assign(reinterpret_cast<const char *>(data), effectiveSize);
return op;
}
static void changeToDynamicUpdate(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
{
op->type = DynamicUpdate;
op->buf = buf;
op->offset = offset;
const int effectiveSize = size ? size : buf->size();
op->data.assign(reinterpret_cast<const char *>(data), effectiveSize);
}
static BufferOp staticUpload(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
{
BufferOp op = {};
op.type = StaticUpload;
op.buf = buf;
op.offset = offset;
const int effectiveSize = size ? size : buf->size();
op.data.assign(reinterpret_cast<const char *>(data), effectiveSize);
return op;
}
static void changeToStaticUpload(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
{
op->type = StaticUpload;
op->buf = buf;
op->offset = offset;
const int effectiveSize = size ? size : buf->size();
op->data.assign(reinterpret_cast<const char *>(data), effectiveSize);
}
static BufferOp read(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiReadbackResult *result)
{
BufferOp op = {};
op.type = Read;
op.buf = buf;
op.offset = offset;
op.readSize = size;
op.result = result;
return op;
}
};
struct TextureOp {
enum Type {
Upload,
Copy,
Read,
GenMips
};
Type type;
QRhiTexture *dst;
// Specifying multiple uploads for a subresource must be supported.
// In the backend this can then end up, where applicable, as a
// single, batched copy operation with only one set of barriers.
// This helps when doing for example glyph cache fills.
using MipLevelUploadList = std::array<QVector<QRhiTextureSubresourceUploadDescription>, QRhi::MAX_MIP_LEVELS>;
QVarLengthArray<MipLevelUploadList, 6> subresDesc;
QRhiTexture *src;
QRhiTextureCopyDescription desc;
QRhiReadbackDescription rb;
QRhiReadbackResult *result;
static TextureOp upload(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
{
TextureOp op = {};
op.type = Upload;
op.dst = tex;
int maxLayer = -1;
for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it) {
if (it->layer() > maxLayer)
maxLayer = it->layer();
}
op.subresDesc.resize(maxLayer + 1);
for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it)
op.subresDesc[it->layer()][it->level()].append(it->description());
return op;
}
static TextureOp copy(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
{
TextureOp op = {};
op.type = Copy;
op.dst = dst;
op.src = src;
op.desc = desc;
return op;
}
static TextureOp read(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
{
TextureOp op = {};
op.type = Read;
op.rb = rb;
op.result = result;
return op;
}
static TextureOp genMips(QRhiTexture *tex)
{
TextureOp op = {};
op.type = GenMips;
op.dst = tex;
return op;
}
};
int activeBufferOpCount = 0; // this is the real number of used elements in bufferOps, not bufferOps.count()
static const int BUFFER_OPS_STATIC_ALLOC = 1024;
QVarLengthArray<BufferOp, BUFFER_OPS_STATIC_ALLOC> bufferOps;
int activeTextureOpCount = 0; // this is the real number of used elements in textureOps, not textureOps.count()
static const int TEXTURE_OPS_STATIC_ALLOC = 256;
QVarLengthArray<TextureOp, TEXTURE_OPS_STATIC_ALLOC> textureOps;
QRhiResourceUpdateBatch *q = nullptr;
QRhiImplementation *rhi = nullptr;
int poolIndex = -1;
void free();
void merge(QRhiResourceUpdateBatchPrivate *other);
bool hasOptimalCapacity() const;
void trimOpLists();
static QRhiResourceUpdateBatchPrivate *get(QRhiResourceUpdateBatch *b) { return b->d; }
};
template<typename T>
struct QRhiBatchedBindings
{
void feed(int binding, T resource) { // binding must be strictly increasing
if (curBinding == -1 || binding > curBinding + 1) {
finish();
curBatch.startBinding = binding;
curBatch.resources.clear();
curBatch.resources.append(resource);
} else {
Q_ASSERT(binding == curBinding + 1);
curBatch.resources.append(resource);
}
curBinding = binding;
}
bool finish() {
if (!curBatch.resources.isEmpty())
batches.append(curBatch);
return !batches.isEmpty();
}
void clear() {
batches.clear();
curBatch.resources.clear();
curBinding = -1;
}
struct Batch {
uint startBinding;
QVarLengthArray<T, 4> resources;
bool operator==(const Batch &other) const
{
return startBinding == other.startBinding && resources == other.resources;
}
bool operator!=(const Batch &other) const
{
return !operator==(other);
}
};
QVarLengthArray<Batch, 4> batches; // sorted by startBinding
bool operator==(const QRhiBatchedBindings<T> &other) const
{
return batches == other.batches;
}
bool operator!=(const QRhiBatchedBindings<T> &other) const
{
return !operator==(other);
}
private:
Batch curBatch;
int curBinding = -1;
};
class QRhiGlobalObjectIdGenerator
{
public:
#ifdef Q_ATOMIC_INT64_IS_SUPPORTED
using Type = quint64;
#else
using Type = quint32;
#endif
static Type newId();
};
class QRhiPassResourceTracker
{
public:
bool isEmpty() const;
void reset();
struct UsageState {
int layout;
int access;
int stage;
};
enum BufferStage {
BufVertexInputStage,
BufVertexStage,
BufTCStage,
BufTEStage,
BufFragmentStage,
BufComputeStage,
BufGeometryStage
};
enum BufferAccess {
BufVertexInput,
BufIndexRead,
BufUniformRead,
BufStorageLoad,
BufStorageStore,
BufStorageLoadStore
};
void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage,
const UsageState &state);
enum TextureStage {
TexVertexStage,
TexTCStage,
TexTEStage,
TexFragmentStage,
TexColorOutputStage,
TexDepthOutputStage,
TexComputeStage,
TexGeometryStage
};
enum TextureAccess {
TexSample,
TexColorOutput,
TexDepthOutput,
TexStorageLoad,
TexStorageStore,
TexStorageLoadStore
};
void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage,
const UsageState &state);
struct Buffer {
int slot;
BufferAccess access;
BufferStage stage;
UsageState stateAtPassBegin;
};
using BufferIterator = QHash<QRhiBuffer *, Buffer>::const_iterator;
BufferIterator cbeginBuffers() const { return m_buffers.cbegin(); }
BufferIterator cendBuffers() const { return m_buffers.cend(); }
struct Texture {
TextureAccess access;
TextureStage stage;
UsageState stateAtPassBegin;
};
using TextureIterator = QHash<QRhiTexture *, Texture>::const_iterator;
TextureIterator cbeginTextures() const { return m_textures.cbegin(); }
TextureIterator cendTextures() const { return m_textures.cend(); }
static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages);
static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages);
private:
QHash<QRhiBuffer *, Buffer> m_buffers;
QHash<QRhiTexture *, Texture> m_textures;
};
Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Buffer, Q_RELOCATABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Texture, Q_RELOCATABLE_TYPE);
template<typename T, int GROW = 1024>
class QRhiBackendCommandList
{
public:
QRhiBackendCommandList() = default;
~QRhiBackendCommandList() { delete[] v; }
inline void reset() { p = 0; }
inline bool isEmpty() const { return p == 0; }
inline T &get() {
if (p == a) {
a += GROW;
T *nv = new T[a];
if (v) {
memcpy(nv, v, p * sizeof(T));
delete[] v;
}
v = nv;
}
return v[p++];
}
inline void unget() { --p; }
inline T *cbegin() const { return v; }
inline T *cend() const { return v + p; }
inline T *begin() { return v; }
inline T *end() { return v + p; }
private:
Q_DISABLE_COPY(QRhiBackendCommandList)
T *v = nullptr;
int a = 0;
int p = 0;
};
struct QRhiRenderTargetAttachmentTracker
{
struct ResId { quint64 id; uint generation; };
using ResIdList = QVarLengthArray<ResId, 8 * 2 + 1>; // color, resolve, ds
template<typename TexType, typename RenderBufferType>
static void updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst);
template<typename TexType, typename RenderBufferType>
static bool isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList &currentResIdList);
};
inline bool operator==(const QRhiRenderTargetAttachmentTracker::ResId &a, const QRhiRenderTargetAttachmentTracker::ResId &b)
{
return a.id == b.id && a.generation == b.generation;
}
inline bool operator!=(const QRhiRenderTargetAttachmentTracker::ResId &a, const QRhiRenderTargetAttachmentTracker::ResId &b)
{
return !(a == b);
}
template<typename TexType, typename RenderBufferType>
void QRhiRenderTargetAttachmentTracker::updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst)
{
const bool hasDepthStencil = desc.depthStencilBuffer() || desc.depthTexture();
dst->resize(desc.colorAttachmentCount() * 2 + (hasDepthStencil ? 1 : 0));
int n = 0;
for (auto it = desc.cbeginColorAttachments(), itEnd = desc.cendColorAttachments(); it != itEnd; ++it, ++n) {
const QRhiColorAttachment &colorAtt(*it);
if (colorAtt.texture()) {
TexType *texD = QRHI_RES(TexType, colorAtt.texture());
(*dst)[n] = { texD->globalResourceId(), texD->generation };
} else if (colorAtt.renderBuffer()) {
RenderBufferType *rbD = QRHI_RES(RenderBufferType, colorAtt.renderBuffer());
(*dst)[n] = { rbD->globalResourceId(), rbD->generation };
} else {
(*dst)[n] = { 0, 0 };
}
++n;
if (colorAtt.resolveTexture()) {
TexType *texD = QRHI_RES(TexType, colorAtt.resolveTexture());
(*dst)[n] = { texD->globalResourceId(), texD->generation };
} else {
(*dst)[n] = { 0, 0 };
}
}
if (hasDepthStencil) {
if (desc.depthTexture()) {
TexType *depthTexD = QRHI_RES(TexType, desc.depthTexture());
(*dst)[n] = { depthTexD->globalResourceId(), depthTexD->generation };
} else if (desc.depthStencilBuffer()) {
RenderBufferType *depthRbD = QRHI_RES(RenderBufferType, desc.depthStencilBuffer());
(*dst)[n] = { depthRbD->globalResourceId(), depthRbD->generation };
} else {
(*dst)[n] = { 0, 0 };
}
}
}
template<typename TexType, typename RenderBufferType>
bool QRhiRenderTargetAttachmentTracker::isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList &currentResIdList)
{
// Just as setShaderResources() recognizes if an srb's referenced
// resources have been rebuilt (got a create() since the srb's
// create()), we should do the same for the textures and renderbuffers
// referenced from the rendertarget. It is not uncommon that a texture
// or ds buffer gets resized due to following a window size in some
// form, which involves a create() on them. It is then nice if the
// render target auto-rebuilds in beginPass().
ResIdList resIdList;
updateResIdList<TexType, RenderBufferType>(desc, &resIdList);
return resIdList == currentResIdList;
}
template<typename T>
inline T *qrhi_objectFromProxyData(QRhiSwapChainProxyData *pd, QWindow *window, QRhi::Implementation impl, uint objectIndex)
{
Q_ASSERT(objectIndex < std::size(pd->reserved));
if (!pd->reserved[objectIndex]) // // was not set, no other choice, do it here, whatever thread this is
*pd = QRhi::updateSwapChainProxyData(impl, window);
return static_cast<T *>(pd->reserved[objectIndex]);
}
QT_END_NAMESPACE
#endif

172
src/gui/rhi/qrhi_platform.h Normal file
View File

@ -0,0 +1,172 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRHIPLATFORM_H
#define QRHIPLATFORM_H
//
// W A R N I N G
// -------------
//
// This file is part of the RHI API, with limited compatibility guarantees.
// Usage of this API may make your code source and binary incompatible with
// future versions of Qt.
//
#include <rhi/qrhi.h>
#if QT_CONFIG(opengl)
#include <QtGui/qsurfaceformat.h>
#endif
#if QT_CONFIG(vulkan)
#include <QtGui/qvulkaninstance.h>
#endif
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) || defined(Q_QDOC)
Q_FORWARD_DECLARE_OBJC_CLASS(MTLDevice);
Q_FORWARD_DECLARE_OBJC_CLASS(MTLCommandQueue);
Q_FORWARD_DECLARE_OBJC_CLASS(MTLCommandBuffer);
Q_FORWARD_DECLARE_OBJC_CLASS(MTLRenderCommandEncoder);
#endif
QT_BEGIN_NAMESPACE
struct Q_GUI_EXPORT QRhiNullInitParams : public QRhiInitParams
{
};
struct Q_GUI_EXPORT QRhiNullNativeHandles : public QRhiNativeHandles
{
};
#if QT_CONFIG(opengl) || defined(Q_QDOC)
class QOpenGLContext;
class QOffscreenSurface;
class QSurface;
class QWindow;
struct Q_GUI_EXPORT QRhiGles2InitParams : public QRhiInitParams
{
QRhiGles2InitParams();
QSurfaceFormat format;
QSurface *fallbackSurface = nullptr;
QWindow *window = nullptr;
QOpenGLContext *shareContext = nullptr;
static QOffscreenSurface *newFallbackSurface(const QSurfaceFormat &format = QSurfaceFormat::defaultFormat());
};
struct Q_GUI_EXPORT QRhiGles2NativeHandles : public QRhiNativeHandles
{
QOpenGLContext *context = nullptr;
};
#endif // opengl/qdoc
#if QT_CONFIG(vulkan) || defined(Q_QDOC)
struct Q_GUI_EXPORT QRhiVulkanInitParams : public QRhiInitParams
{
QVulkanInstance *inst = nullptr;
QWindow *window = nullptr;
QByteArrayList deviceExtensions;
static QByteArrayList preferredInstanceExtensions();
static QByteArrayList preferredExtensionsForImportedDevice();
};
struct Q_GUI_EXPORT QRhiVulkanNativeHandles : public QRhiNativeHandles
{
// to import a physical device (always required)
VkPhysicalDevice physDev = VK_NULL_HANDLE;
// to import a device and queue
VkDevice dev = VK_NULL_HANDLE;
quint32 gfxQueueFamilyIdx = 0;
quint32 gfxQueueIdx = 0;
VkQueue gfxQueue = VK_NULL_HANDLE;
// and optionally, the mem allocator
void *vmemAllocator = nullptr;
};
struct Q_GUI_EXPORT QRhiVulkanCommandBufferNativeHandles : public QRhiNativeHandles
{
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
};
struct Q_GUI_EXPORT QRhiVulkanRenderPassNativeHandles : public QRhiNativeHandles
{
VkRenderPass renderPass = VK_NULL_HANDLE;
};
#endif // vulkan/qdoc
#if defined(Q_OS_WIN) || defined(Q_QDOC)
// no d3d includes here, to prevent precompiled header mess due to COM, hence the void pointers
struct Q_GUI_EXPORT QRhiD3D11InitParams : public QRhiInitParams
{
bool enableDebugLayer = false;
};
struct Q_GUI_EXPORT QRhiD3D11NativeHandles : public QRhiNativeHandles
{
// to import a device and a context
void *dev = nullptr;
void *context = nullptr;
// alternatively, to specify the device feature level and/or the adapter to use
int featureLevel = 0;
quint32 adapterLuidLow = 0;
qint32 adapterLuidHigh = 0;
};
struct Q_GUI_EXPORT QRhiD3D12InitParams : public QRhiInitParams
{
bool enableDebugLayer = false;
};
struct Q_GUI_EXPORT QRhiD3D12NativeHandles : public QRhiNativeHandles
{
// to import a device
void *dev = nullptr;
int minimumFeatureLevel = 0;
// to just specify the adapter to use, set these and leave dev set to null
quint32 adapterLuidLow = 0;
qint32 adapterLuidHigh = 0;
// in addition, can specify the command queue to use
void *commandQueue = nullptr;
};
struct Q_GUI_EXPORT QRhiD3D12CommandBufferNativeHandles : public QRhiNativeHandles
{
void *commandList = nullptr; // ID3D12GraphicsCommandList
};
#endif // WIN/QDOC
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) || defined(Q_QDOC)
struct Q_GUI_EXPORT QRhiMetalInitParams : public QRhiInitParams
{
};
struct Q_GUI_EXPORT QRhiMetalNativeHandles : public QRhiNativeHandles
{
MTLDevice *dev = nullptr;
MTLCommandQueue *cmdQueue = nullptr;
};
struct Q_GUI_EXPORT QRhiMetalCommandBufferNativeHandles : public QRhiNativeHandles
{
MTLCommandBuffer *commandBuffer = nullptr;
MTLRenderCommandEncoder *encoder = nullptr;
};
#endif // MACOS/IOS/QDOC
QT_END_NAMESPACE
#endif

View File

@ -1,8 +1,8 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qrhid3d11_p_p.h"
#include "qshader_p.h"
#include "qrhid3d11_p.h"
#include "qshader.h"
#include "vs_test_p.h"
#include <QWindow>
#include <qmath.h>
@ -28,10 +28,13 @@ using namespace Qt::StringLiterals;
/*!
\class QRhiD3D11InitParams
\internal
\inmodule QtGui
\since 6.6
\brief Direct3D 11 specific initialization parameters.
\note This a RHI API with limited compatibility guarantees, see \l QRhi
for details.
A D3D11-based QRhi needs no special parameters for initialization. If
desired, enableDebugLayer can be set to \c true to enable the Direct3D
debug layer. This can be useful during development, but should be avoided
@ -69,15 +72,45 @@ using namespace Qt::StringLiterals;
Initialization will fail otherwise.
*/
/*!
\variable QRhiD3D11InitParams::enableDebugLayer
When set to true, a debug device is created, assuming the debug layer is
available. The default value is false.
*/
/*!
\class QRhiD3D11NativeHandles
\internal
\inmodule QtGui
\since 6.6
\brief Holds the D3D device and device context used by the QRhi.
\note The class uses \c{void *} as the type since including the COM-based
\c{d3d11.h} headers is not acceptable here. The actual types are
\c{ID3D11Device *} and \c{ID3D11DeviceContext *}.
\note This a RHI API with limited compatibility guarantees, see \l QRhi
for details.
*/
/*!
\variable QRhiD3D11NativeHandles::dev
*/
/*!
\variable QRhiD3D11NativeHandles::context
*/
/*!
\variable QRhiD3D11NativeHandles::featureLevel
*/
/*!
\variable QRhiD3D11NativeHandles::adapterLuidLow
*/
/*!
\variable QRhiD3D11NativeHandles::adapterLuidHigh
*/
// help mingw with its ancient sdk headers

View File

@ -1,8 +1,8 @@
// Copyright (C) 2019 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRHID3D11_H
#define QRHID3D11_H
#ifndef QRHID3D11_P_H
#define QRHID3D11_P_H
//
// W A R N I N G
@ -15,28 +15,838 @@
// We mean it.
//
#include <private/qrhi_p.h>
#include "qrhi_p.h"
#include "qshaderdescription.h"
#include <QWindow>
// no d3d includes here, to prevent precompiled header mess due to COM
#include <d3d11_1.h>
#include <dxgi1_6.h>
#include <dcomp.h>
QT_BEGIN_NAMESPACE
struct Q_GUI_EXPORT QRhiD3D11InitParams : public QRhiInitParams
class QRhiD3D11;
struct QD3D11Buffer : public QRhiBuffer
{
bool enableDebugLayer = false;
QD3D11Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
~QD3D11Buffer();
void destroy() override;
bool create() override;
QRhiBuffer::NativeBuffer nativeBuffer() override;
char *beginFullDynamicBufferUpdateForCurrentFrame() override;
void endFullDynamicBufferUpdateForCurrentFrame() override;
ID3D11UnorderedAccessView *unorderedAccessView(quint32 offset);
ID3D11Buffer *buffer = nullptr;
char *dynBuf = nullptr;
bool hasPendingDynamicUpdates = false;
QHash<quint32, ID3D11UnorderedAccessView *> uavs;
uint generation = 0;
friend class QRhiD3D11;
};
struct Q_GUI_EXPORT QRhiD3D11NativeHandles : public QRhiNativeHandles
struct QD3D11RenderBuffer : public QRhiRenderBuffer
{
// to import a device and a context
void *dev = nullptr;
void *context = nullptr;
// alternatively, to specify the device feature level and/or the adapter to use
int featureLevel = 0;
quint32 adapterLuidLow = 0;
qint32 adapterLuidHigh = 0;
QD3D11RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags,
QRhiTexture::Format backingFormatHint);
~QD3D11RenderBuffer();
void destroy() override;
bool create() override;
QRhiTexture::Format backingFormat() const override;
ID3D11Texture2D *tex = nullptr;
ID3D11DepthStencilView *dsv = nullptr;
ID3D11RenderTargetView *rtv = nullptr;
DXGI_FORMAT dxgiFormat;
DXGI_SAMPLE_DESC sampleDesc;
uint generation = 0;
friend class QRhiD3D11;
};
struct QD3D11Texture : public QRhiTexture
{
QD3D11Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
int arraySize, int sampleCount, Flags flags);
~QD3D11Texture();
void destroy() override;
bool create() override;
bool createFrom(NativeTexture src) override;
NativeTexture nativeTexture() override;
bool prepareCreate(QSize *adjustedSize = nullptr);
bool finishCreate();
ID3D11UnorderedAccessView *unorderedAccessViewForLevel(int level);
ID3D11Resource *textureResource() const
{
if (tex)
return tex;
else if (tex1D)
return tex1D;
return tex3D;
}
ID3D11Texture2D *tex = nullptr;
ID3D11Texture3D *tex3D = nullptr;
ID3D11Texture1D *tex1D = nullptr;
bool owns = true;
ID3D11ShaderResourceView *srv = nullptr;
DXGI_FORMAT dxgiFormat;
uint mipLevelCount = 0;
DXGI_SAMPLE_DESC sampleDesc;
ID3D11UnorderedAccessView *perLevelViews[QRhi::MAX_MIP_LEVELS];
uint generation = 0;
friend class QRhiD3D11;
};
struct QD3D11Sampler : public QRhiSampler
{
QD3D11Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
AddressMode u, AddressMode v, AddressMode w);
~QD3D11Sampler();
void destroy() override;
bool create() override;
ID3D11SamplerState *samplerState = nullptr;
uint generation = 0;
friend class QRhiD3D11;
};
struct QD3D11RenderPassDescriptor : public QRhiRenderPassDescriptor
{
QD3D11RenderPassDescriptor(QRhiImplementation *rhi);
~QD3D11RenderPassDescriptor();
void destroy() override;
bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
QVector<quint32> serializedFormat() const override;
};
struct QD3D11RenderTargetData
{
QD3D11RenderTargetData(QRhiImplementation *)
{
for (int i = 0; i < MAX_COLOR_ATTACHMENTS; ++i)
rtv[i] = nullptr;
}
QD3D11RenderPassDescriptor *rp = nullptr;
QSize pixelSize;
float dpr = 1;
int sampleCount = 1;
int colorAttCount = 0;
int dsAttCount = 0;
static const int MAX_COLOR_ATTACHMENTS = 8;
ID3D11RenderTargetView *rtv[MAX_COLOR_ATTACHMENTS];
ID3D11DepthStencilView *dsv = nullptr;
QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
};
struct QD3D11SwapChainRenderTarget : public QRhiSwapChainRenderTarget
{
QD3D11SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
~QD3D11SwapChainRenderTarget();
void destroy() override;
QSize pixelSize() const override;
float devicePixelRatio() const override;
int sampleCount() const override;
QD3D11RenderTargetData d;
};
struct QD3D11TextureRenderTarget : public QRhiTextureRenderTarget
{
QD3D11TextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
~QD3D11TextureRenderTarget();
void destroy() override;
QSize pixelSize() const override;
float devicePixelRatio() const override;
int sampleCount() const override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
bool create() override;
QD3D11RenderTargetData d;
bool ownsRtv[QD3D11RenderTargetData::MAX_COLOR_ATTACHMENTS];
ID3D11RenderTargetView *rtv[QD3D11RenderTargetData::MAX_COLOR_ATTACHMENTS];
bool ownsDsv = false;
ID3D11DepthStencilView *dsv = nullptr;
friend class QRhiD3D11;
};
struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
{
QD3D11ShaderResourceBindings(QRhiImplementation *rhi);
~QD3D11ShaderResourceBindings();
void destroy() override;
bool create() override;
void updateResources(UpdateFlags flags) override;
bool hasDynamicOffset = false;
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
uint generation = 0;
// Keep track of the generation number of each referenced QRhi* to be able
// to detect that the batched bindings are out of date.
struct BoundUniformBufferData {
quint64 id;
uint generation;
};
struct BoundSampledTextureData {
int count;
struct {
quint64 texId;
uint texGeneration;
quint64 samplerId;
uint samplerGeneration;
} d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE];
};
struct BoundStorageImageData {
quint64 id;
uint generation;
};
struct BoundStorageBufferData {
quint64 id;
uint generation;
};
struct BoundResourceData {
union {
BoundUniformBufferData ubuf;
BoundSampledTextureData stex;
BoundStorageImageData simage;
BoundStorageBufferData sbuf;
};
};
QVarLengthArray<BoundResourceData, 8> boundResourceData;
struct StageUniformBufferBatches {
bool present = false;
QRhiBatchedBindings<ID3D11Buffer *> ubufs;
QRhiBatchedBindings<UINT> ubuforigbindings;
QRhiBatchedBindings<UINT> ubufoffsets;
QRhiBatchedBindings<UINT> ubufsizes;
void finish() {
present = ubufs.finish();
ubuforigbindings.finish();
ubufoffsets.finish();
ubufsizes.finish();
}
void clear() {
ubufs.clear();
ubuforigbindings.clear();
ubufoffsets.clear();
ubufsizes.clear();
}
};
struct StageSamplerBatches {
bool present = false;
QRhiBatchedBindings<ID3D11SamplerState *> samplers;
QRhiBatchedBindings<ID3D11ShaderResourceView *> shaderresources;
void finish() {
present = samplers.finish();
shaderresources.finish();
}
void clear() {
samplers.clear();
shaderresources.clear();
}
};
struct StageUavBatches {
bool present = false;
QRhiBatchedBindings<ID3D11UnorderedAccessView *> uavs;
void finish() {
present = uavs.finish();
}
void clear() {
uavs.clear();
}
};
StageUniformBufferBatches vsUniformBufferBatches;
StageUniformBufferBatches hsUniformBufferBatches;
StageUniformBufferBatches dsUniformBufferBatches;
StageUniformBufferBatches gsUniformBufferBatches;
StageUniformBufferBatches fsUniformBufferBatches;
StageUniformBufferBatches csUniformBufferBatches;
StageSamplerBatches vsSamplerBatches;
StageSamplerBatches hsSamplerBatches;
StageSamplerBatches dsSamplerBatches;
StageSamplerBatches gsSamplerBatches;
StageSamplerBatches fsSamplerBatches;
StageSamplerBatches csSamplerBatches;
StageUavBatches csUavBatches;
friend class QRhiD3D11;
};
Q_DECLARE_TYPEINFO(QD3D11ShaderResourceBindings::BoundResourceData, Q_RELOCATABLE_TYPE);
struct QD3D11GraphicsPipeline : public QRhiGraphicsPipeline
{
QD3D11GraphicsPipeline(QRhiImplementation *rhi);
~QD3D11GraphicsPipeline();
void destroy() override;
bool create() override;
ID3D11DepthStencilState *dsState = nullptr;
ID3D11BlendState *blendState = nullptr;
struct {
ID3D11VertexShader *shader = nullptr;
QShader::NativeResourceBindingMap nativeResourceBindingMap;
} vs;
struct {
ID3D11HullShader *shader = nullptr;
QShader::NativeResourceBindingMap nativeResourceBindingMap;
} hs;
struct {
ID3D11DomainShader *shader = nullptr;
QShader::NativeResourceBindingMap nativeResourceBindingMap;
} ds;
struct {
ID3D11GeometryShader *shader = nullptr;
QShader::NativeResourceBindingMap nativeResourceBindingMap;
} gs;
struct {
ID3D11PixelShader *shader = nullptr;
QShader::NativeResourceBindingMap nativeResourceBindingMap;
} fs;
ID3D11InputLayout *inputLayout = nullptr;
D3D11_PRIMITIVE_TOPOLOGY d3dTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
ID3D11RasterizerState *rastState = nullptr;
uint generation = 0;
friend class QRhiD3D11;
};
struct QD3D11ComputePipeline : public QRhiComputePipeline
{
QD3D11ComputePipeline(QRhiImplementation *rhi);
~QD3D11ComputePipeline();
void destroy() override;
bool create() override;
struct {
ID3D11ComputeShader *shader = nullptr;
QShader::NativeResourceBindingMap nativeResourceBindingMap;
} cs;
uint generation = 0;
friend class QRhiD3D11;
};
struct QD3D11SwapChain;
struct QD3D11CommandBuffer : public QRhiCommandBuffer
{
QD3D11CommandBuffer(QRhiImplementation *rhi);
~QD3D11CommandBuffer();
void destroy() override;
// these must be kept at a reasonably low value otherwise sizeof Command explodes
static const int MAX_DYNAMIC_OFFSET_COUNT = 8;
static const int MAX_VERTEX_BUFFER_BINDING_COUNT = 8;
struct Command {
enum Cmd {
ResetShaderResources,
SetRenderTarget,
Clear,
Viewport,
Scissor,
BindVertexBuffers,
BindIndexBuffer,
BindGraphicsPipeline,
BindShaderResources,
StencilRef,
BlendConstants,
Draw,
DrawIndexed,
UpdateSubRes,
CopySubRes,
ResolveSubRes,
GenMip,
DebugMarkBegin,
DebugMarkEnd,
DebugMarkMsg,
BindComputePipeline,
Dispatch
};
enum ClearFlag { Color = 1, Depth = 2, Stencil = 4 };
Cmd cmd;
// QRhi*/QD3D11* references should be kept at minimum (so no
// QRhiTexture/Buffer/etc. pointers).
union Args {
struct {
QRhiRenderTarget *rt;
} setRenderTarget;
struct {
QRhiRenderTarget *rt;
int mask;
float c[4];
float d;
quint32 s;
} clear;
struct {
float x, y, w, h;
float d0, d1;
} viewport;
struct {
int x, y, w, h;
} scissor;
struct {
int startSlot;
int slotCount;
ID3D11Buffer *buffers[MAX_VERTEX_BUFFER_BINDING_COUNT];
UINT offsets[MAX_VERTEX_BUFFER_BINDING_COUNT];
UINT strides[MAX_VERTEX_BUFFER_BINDING_COUNT];
} bindVertexBuffers;
struct {
ID3D11Buffer *buffer;
quint32 offset;
DXGI_FORMAT format;
} bindIndexBuffer;
struct {
QD3D11GraphicsPipeline *ps;
} bindGraphicsPipeline;
struct {
QD3D11ShaderResourceBindings *srb;
bool offsetOnlyChange;
int dynamicOffsetCount;
uint dynamicOffsetPairs[MAX_DYNAMIC_OFFSET_COUNT * 2]; // binding, offsetInConstants
} bindShaderResources;
struct {
QD3D11GraphicsPipeline *ps;
quint32 ref;
} stencilRef;
struct {
QD3D11GraphicsPipeline *ps;
float c[4];
} blendConstants;
struct {
QD3D11GraphicsPipeline *ps;
quint32 vertexCount;
quint32 instanceCount;
quint32 firstVertex;
quint32 firstInstance;
} draw;
struct {
QD3D11GraphicsPipeline *ps;
quint32 indexCount;
quint32 instanceCount;
quint32 firstIndex;
qint32 vertexOffset;
quint32 firstInstance;
} drawIndexed;
struct {
ID3D11Resource *dst;
UINT dstSubRes;
bool hasDstBox;
D3D11_BOX dstBox;
const void *src; // must come from retain*()
UINT srcRowPitch;
} updateSubRes;
struct {
ID3D11Resource *dst;
UINT dstSubRes;
UINT dstX;
UINT dstY;
UINT dstZ;
ID3D11Resource *src;
UINT srcSubRes;
bool hasSrcBox;
D3D11_BOX srcBox;
} copySubRes;
struct {
ID3D11Resource *dst;
UINT dstSubRes;
ID3D11Resource *src;
UINT srcSubRes;
DXGI_FORMAT format;
} resolveSubRes;
struct {
ID3D11ShaderResourceView *srv;
} genMip;
struct {
char s[64];
} debugMark;
struct {
QD3D11ComputePipeline *ps;
} bindComputePipeline;
struct {
UINT x;
UINT y;
UINT z;
} dispatch;
} args;
};
enum PassType {
NoPass,
RenderPass,
ComputePass
};
QRhiBackendCommandList<Command> commands;
PassType recordingPass;
double lastGpuTime = 0;
QRhiRenderTarget *currentTarget;
QRhiGraphicsPipeline *currentGraphicsPipeline;
QRhiComputePipeline *currentComputePipeline;
uint currentPipelineGeneration;
QRhiShaderResourceBindings *currentGraphicsSrb;
QRhiShaderResourceBindings *currentComputeSrb;
uint currentSrbGeneration;
ID3D11Buffer *currentIndexBuffer;
quint32 currentIndexOffset;
DXGI_FORMAT currentIndexFormat;
ID3D11Buffer *currentVertexBuffers[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
quint32 currentVertexOffsets[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
QVarLengthArray<QByteArray, 4> dataRetainPool;
QVarLengthArray<QRhiBufferData, 4> bufferDataRetainPool;
QVarLengthArray<QImage, 4> imageRetainPool;
// relies heavily on implicit sharing (no copies of the actual data will be made)
const uchar *retainData(const QByteArray &data) {
dataRetainPool.append(data);
return reinterpret_cast<const uchar *>(dataRetainPool.last().constData());
}
const uchar *retainBufferData(const QRhiBufferData &data) {
bufferDataRetainPool.append(data);
return reinterpret_cast<const uchar *>(bufferDataRetainPool.last().constData());
}
const uchar *retainImage(const QImage &image) {
imageRetainPool.append(image);
return imageRetainPool.last().constBits();
}
void resetCommands() {
commands.reset();
dataRetainPool.clear();
bufferDataRetainPool.clear();
imageRetainPool.clear();
}
void resetState() {
recordingPass = NoPass;
// do not zero lastGpuTime
currentTarget = nullptr;
resetCommands();
resetCachedState();
}
void resetCachedState() {
currentGraphicsPipeline = nullptr;
currentComputePipeline = nullptr;
currentPipelineGeneration = 0;
currentGraphicsSrb = nullptr;
currentComputeSrb = nullptr;
currentSrbGeneration = 0;
currentIndexBuffer = nullptr;
currentIndexOffset = 0;
currentIndexFormat = DXGI_FORMAT_R16_UINT;
memset(currentVertexBuffers, 0, sizeof(currentVertexBuffers));
memset(currentVertexOffsets, 0, sizeof(currentVertexOffsets));
}
};
static const int QD3D11_SWAPCHAIN_BUFFER_COUNT = 2;
struct QD3D11Timestamps
{
static const int MAX_TIMESTAMP_PAIRS = QD3D11_SWAPCHAIN_BUFFER_COUNT;
bool active[MAX_TIMESTAMP_PAIRS] = {};
ID3D11Query *disjointQuery[MAX_TIMESTAMP_PAIRS] = {};
ID3D11Query *query[MAX_TIMESTAMP_PAIRS * 2] = {};
int pairCount = 0;
bool prepare(int pairCount, QRhiD3D11 *rhiD);
void destroy();
bool tryQueryTimestamps(int idx, ID3D11DeviceContext *context, double *elapsedSec);
};
struct QD3D11SwapChain : public QRhiSwapChain
{
QD3D11SwapChain(QRhiImplementation *rhi);
~QD3D11SwapChain();
void destroy() override;
QRhiCommandBuffer *currentFrameCommandBuffer() override;
QRhiRenderTarget *currentFrameRenderTarget() override;
QSize surfacePixelSize() override;
bool isFormatSupported(Format f) override;
QRhiSwapChainHdrInfo hdrInfo() override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
bool createOrResize() override;
void releaseBuffers();
bool newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI_SAMPLE_DESC sampleDesc,
ID3D11Texture2D **tex, ID3D11RenderTargetView **rtv) const;
QWindow *window = nullptr;
QSize pixelSize;
QD3D11SwapChainRenderTarget rt;
QD3D11CommandBuffer cb;
DXGI_FORMAT colorFormat;
DXGI_FORMAT srgbAdjustedColorFormat;
IDXGISwapChain *swapChain = nullptr;
UINT swapChainFlags = 0;
ID3D11Texture2D *backBufferTex;
ID3D11RenderTargetView *backBufferRtv;
static const int BUFFER_COUNT = QD3D11_SWAPCHAIN_BUFFER_COUNT;
ID3D11Texture2D *msaaTex[BUFFER_COUNT];
ID3D11RenderTargetView *msaaRtv[BUFFER_COUNT];
DXGI_SAMPLE_DESC sampleDesc;
int currentFrameSlot = 0;
int frameCount = 0;
QD3D11RenderBuffer *ds = nullptr;
UINT swapInterval = 1;
IDCompositionTarget *dcompTarget = nullptr;
IDCompositionVisual *dcompVisual = nullptr;
QD3D11Timestamps timestamps;
};
class QRhiD3D11 : public QRhiImplementation
{
public:
QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *importDevice = nullptr);
bool create(QRhi::Flags flags) override;
void destroy() override;
QRhiGraphicsPipeline *createGraphicsPipeline() override;
QRhiComputePipeline *createComputePipeline() override;
QRhiShaderResourceBindings *createShaderResourceBindings() override;
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
QRhiBuffer::UsageFlags usage,
quint32 size) override;
QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
int sampleCount,
QRhiRenderBuffer::Flags flags,
QRhiTexture::Format backingFormatHint) override;
QRhiTexture *createTexture(QRhiTexture::Format format,
const QSize &pixelSize,
int depth,
int arraySize,
int sampleCount,
QRhiTexture::Flags flags) override;
QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
QRhiSampler:: AddressMode u,
QRhiSampler::AddressMode v,
QRhiSampler::AddressMode w) override;
QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
QRhiTextureRenderTarget::Flags flags) override;
QRhiSwapChain *createSwapChain() override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult finish() override;
void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void beginPass(QRhiCommandBuffer *cb,
QRhiRenderTarget *rt,
const QColor &colorClearValue,
const QRhiDepthStencilClearValue &depthStencilClearValue,
QRhiResourceUpdateBatch *resourceUpdates,
QRhiCommandBuffer::BeginPassFlags flags) override;
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setGraphicsPipeline(QRhiCommandBuffer *cb,
QRhiGraphicsPipeline *ps) override;
void setShaderResources(QRhiCommandBuffer *cb,
QRhiShaderResourceBindings *srb,
int dynamicOffsetCount,
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
void setVertexInput(QRhiCommandBuffer *cb,
int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
QRhiBuffer *indexBuf, quint32 indexOffset,
QRhiCommandBuffer::IndexFormat indexFormat) override;
void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
quint32 instanceCount, quint32 firstIndex,
qint32 vertexOffset, quint32 firstInstance) override;
void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
void debugMarkEnd(QRhiCommandBuffer *cb) override;
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
void beginComputePass(QRhiCommandBuffer *cb,
QRhiResourceUpdateBatch *resourceUpdates,
QRhiCommandBuffer::BeginPassFlags flags) override;
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
void beginExternal(QRhiCommandBuffer *cb) override;
void endExternal(QRhiCommandBuffer *cb) override;
double lastCompletedGpuTime(QRhiCommandBuffer *cb) override;
QList<int> supportedSampleCounts() const override;
int ubufAlignment() const override;
bool isYUpInFramebuffer() const override;
bool isYUpInNDC() const override;
bool isClipDepthZeroToOne() const override;
QMatrix4x4 clipSpaceCorrMatrix() const override;
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
bool isFeatureSupported(QRhi::Feature feature) const override;
int resourceLimit(QRhi::ResourceLimit limit) const override;
const QRhiNativeHandles *nativeHandles() override;
QRhiDriverInfo driverInfo() const override;
QRhiStats statistics() override;
bool makeThreadLocalNativeContextCurrent() override;
void releaseCachedResources() override;
bool isDeviceLost() const override;
QByteArray pipelineCacheData() override;
void setPipelineCacheData(const QByteArray &data) override;
void enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cbD,
int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc);
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]);
void executeBufferHostWrites(QD3D11Buffer *bufD);
void bindShaderResources(QD3D11ShaderResourceBindings *srbD,
const uint *dynOfsPairs, int dynOfsPairCount,
bool offsetOnlyChange);
void resetShaderResources();
void executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain = nullptr);
DXGI_SAMPLE_DESC effectiveSampleCount(int sampleCount) const;
void finishActiveReadbacks();
void reportLiveObjects(ID3D11Device *device);
void clearShaderCache();
QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, uint flags,
QString *error, QShaderKey *usedShaderKey);
bool ensureDirectCompositionDevice();
QRhi::Flags rhiFlags;
bool debugLayer = false;
bool importedDeviceAndContext = false;
ID3D11Device *dev = nullptr;
ID3D11DeviceContext1 *context = nullptr;
D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL(0);
LUID adapterLuid = {};
ID3DUserDefinedAnnotation *annotations = nullptr;
IDXGIAdapter1 *activeAdapter = nullptr;
IDXGIFactory1 *dxgiFactory = nullptr;
IDCompositionDevice *dcompDevice = nullptr;
bool supportsAllowTearing = false;
bool deviceLost = false;
QRhiD3D11NativeHandles nativeHandlesStruct;
QRhiDriverInfo driverInfoStruct;
struct {
int vsHighestActiveVertexBufferBinding = -1;
bool vsHasIndexBufferBound = false;
int vsHighestActiveSrvBinding = -1;
int hsHighestActiveSrvBinding = -1;
int dsHighestActiveSrvBinding = -1;
int gsHighestActiveSrvBinding = -1;
int fsHighestActiveSrvBinding = -1;
int csHighestActiveSrvBinding = -1;
int csHighestActiveUavBinding = -1;
QD3D11SwapChain *currentSwapChain = nullptr;
} contextState;
struct OffscreenFrame {
OffscreenFrame(QRhiImplementation *rhi) : cbWrapper(rhi) { }
bool active = false;
QD3D11CommandBuffer cbWrapper;
QD3D11Timestamps timestamps;
int timestampIdx = 0;
} ofr;
struct TextureReadback {
QRhiReadbackDescription desc;
QRhiReadbackResult *result;
ID3D11Texture2D *stagingTex;
quint32 byteSize;
quint32 bpl;
QSize pixelSize;
QRhiTexture::Format format;
};
QVarLengthArray<TextureReadback, 2> activeTextureReadbacks;
struct BufferReadback {
QRhiReadbackResult *result;
quint32 byteSize;
ID3D11Buffer *stagingBuf;
};
QVarLengthArray<BufferReadback, 2> activeBufferReadbacks;
struct Shader {
Shader() = default;
Shader(IUnknown *s, const QByteArray &bytecode, const QShader::NativeResourceBindingMap &rbm)
: s(s), bytecode(bytecode), nativeResourceBindingMap(rbm) { }
IUnknown *s;
QByteArray bytecode;
QShader::NativeResourceBindingMap nativeResourceBindingMap;
};
QHash<QRhiShaderStage, Shader> m_shaderCache;
// This is what gets exposed as the "pipeline cache", not that that concept
// applies anyway. Here we are just storing the DX bytecode for a shader so
// we can skip the HLSL->DXBC compilation when the QShader has HLSL source
// code and the same shader source has already been compiled before.
// m_shaderCache seemingly does the same, but this here does not care about
// the ID3D11*Shader, this is just about the bytecode and about allowing
// the data to be serialized to persistent storage and then reloaded in
// future runs of the app, or when creating another QRhi, etc.
struct BytecodeCacheKey {
QByteArray sourceHash;
QByteArray target;
QByteArray entryPoint;
uint compileFlags;
};
QHash<BytecodeCacheKey, QByteArray> m_bytecodeCache;
};
Q_DECLARE_TYPEINFO(QRhiD3D11::TextureReadback, Q_RELOCATABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiD3D11::BufferReadback, Q_RELOCATABLE_TYPE);
inline bool operator==(const QRhiD3D11::BytecodeCacheKey &a, const QRhiD3D11::BytecodeCacheKey &b) noexcept
{
return a.sourceHash == b.sourceHash
&& a.target == b.target
&& a.entryPoint == b.entryPoint
&& a.compileFlags == b.compileFlags;
}
inline bool operator!=(const QRhiD3D11::BytecodeCacheKey &a, const QRhiD3D11::BytecodeCacheKey &b) noexcept
{
return !(a == b);
}
inline size_t qHash(const QRhiD3D11::BytecodeCacheKey &k, size_t seed = 0) noexcept
{
return qHash(k.sourceHash, seed) ^ qHash(k.target) ^ qHash(k.entryPoint) ^ k.compileFlags;
}
QT_END_NAMESPACE
#endif

View File

@ -1,853 +0,0 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRHID3D11_P_H
#define QRHID3D11_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qrhid3d11_p.h"
#include "qrhi_p_p.h"
#include "qshaderdescription_p.h"
#include <QWindow>
#include <d3d11_1.h>
#include <dxgi1_6.h>
#include <dcomp.h>
QT_BEGIN_NAMESPACE
class QRhiD3D11;
struct QD3D11Buffer : public QRhiBuffer
{
QD3D11Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
~QD3D11Buffer();
void destroy() override;
bool create() override;
QRhiBuffer::NativeBuffer nativeBuffer() override;
char *beginFullDynamicBufferUpdateForCurrentFrame() override;
void endFullDynamicBufferUpdateForCurrentFrame() override;
ID3D11UnorderedAccessView *unorderedAccessView(quint32 offset);
ID3D11Buffer *buffer = nullptr;
char *dynBuf = nullptr;
bool hasPendingDynamicUpdates = false;
QHash<quint32, ID3D11UnorderedAccessView *> uavs;
uint generation = 0;
friend class QRhiD3D11;
};
struct QD3D11RenderBuffer : public QRhiRenderBuffer
{
QD3D11RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags,
QRhiTexture::Format backingFormatHint);
~QD3D11RenderBuffer();
void destroy() override;
bool create() override;
QRhiTexture::Format backingFormat() const override;
ID3D11Texture2D *tex = nullptr;
ID3D11DepthStencilView *dsv = nullptr;
ID3D11RenderTargetView *rtv = nullptr;
DXGI_FORMAT dxgiFormat;
DXGI_SAMPLE_DESC sampleDesc;
uint generation = 0;
friend class QRhiD3D11;
};
struct QD3D11Texture : public QRhiTexture
{
QD3D11Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
int arraySize, int sampleCount, Flags flags);
~QD3D11Texture();
void destroy() override;
bool create() override;
bool createFrom(NativeTexture src) override;
NativeTexture nativeTexture() override;
bool prepareCreate(QSize *adjustedSize = nullptr);
bool finishCreate();
ID3D11UnorderedAccessView *unorderedAccessViewForLevel(int level);
ID3D11Resource *textureResource() const
{
if (tex)
return tex;
else if (tex1D)
return tex1D;
return tex3D;
}
ID3D11Texture2D *tex = nullptr;
ID3D11Texture3D *tex3D = nullptr;
ID3D11Texture1D *tex1D = nullptr;
bool owns = true;
ID3D11ShaderResourceView *srv = nullptr;
DXGI_FORMAT dxgiFormat;
uint mipLevelCount = 0;
DXGI_SAMPLE_DESC sampleDesc;
ID3D11UnorderedAccessView *perLevelViews[QRhi::MAX_MIP_LEVELS];
uint generation = 0;
friend class QRhiD3D11;
};
struct QD3D11Sampler : public QRhiSampler
{
QD3D11Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
AddressMode u, AddressMode v, AddressMode w);
~QD3D11Sampler();
void destroy() override;
bool create() override;
ID3D11SamplerState *samplerState = nullptr;
uint generation = 0;
friend class QRhiD3D11;
};
struct QD3D11RenderPassDescriptor : public QRhiRenderPassDescriptor
{
QD3D11RenderPassDescriptor(QRhiImplementation *rhi);
~QD3D11RenderPassDescriptor();
void destroy() override;
bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
QVector<quint32> serializedFormat() const override;
};
struct QD3D11RenderTargetData
{
QD3D11RenderTargetData(QRhiImplementation *)
{
for (int i = 0; i < MAX_COLOR_ATTACHMENTS; ++i)
rtv[i] = nullptr;
}
QD3D11RenderPassDescriptor *rp = nullptr;
QSize pixelSize;
float dpr = 1;
int sampleCount = 1;
int colorAttCount = 0;
int dsAttCount = 0;
static const int MAX_COLOR_ATTACHMENTS = 8;
ID3D11RenderTargetView *rtv[MAX_COLOR_ATTACHMENTS];
ID3D11DepthStencilView *dsv = nullptr;
QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
};
struct QD3D11SwapChainRenderTarget : public QRhiSwapChainRenderTarget
{
QD3D11SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
~QD3D11SwapChainRenderTarget();
void destroy() override;
QSize pixelSize() const override;
float devicePixelRatio() const override;
int sampleCount() const override;
QD3D11RenderTargetData d;
};
struct QD3D11TextureRenderTarget : public QRhiTextureRenderTarget
{
QD3D11TextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
~QD3D11TextureRenderTarget();
void destroy() override;
QSize pixelSize() const override;
float devicePixelRatio() const override;
int sampleCount() const override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
bool create() override;
QD3D11RenderTargetData d;
bool ownsRtv[QD3D11RenderTargetData::MAX_COLOR_ATTACHMENTS];
ID3D11RenderTargetView *rtv[QD3D11RenderTargetData::MAX_COLOR_ATTACHMENTS];
bool ownsDsv = false;
ID3D11DepthStencilView *dsv = nullptr;
friend class QRhiD3D11;
};
struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
{
QD3D11ShaderResourceBindings(QRhiImplementation *rhi);
~QD3D11ShaderResourceBindings();
void destroy() override;
bool create() override;
void updateResources(UpdateFlags flags) override;
bool hasDynamicOffset = false;
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
uint generation = 0;
// Keep track of the generation number of each referenced QRhi* to be able
// to detect that the batched bindings are out of date.
struct BoundUniformBufferData {
quint64 id;
uint generation;
};
struct BoundSampledTextureData {
int count;
struct {
quint64 texId;
uint texGeneration;
quint64 samplerId;
uint samplerGeneration;
} d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE];
};
struct BoundStorageImageData {
quint64 id;
uint generation;
};
struct BoundStorageBufferData {
quint64 id;
uint generation;
};
struct BoundResourceData {
union {
BoundUniformBufferData ubuf;
BoundSampledTextureData stex;
BoundStorageImageData simage;
BoundStorageBufferData sbuf;
};
};
QVarLengthArray<BoundResourceData, 8> boundResourceData;
struct StageUniformBufferBatches {
bool present = false;
QRhiBatchedBindings<ID3D11Buffer *> ubufs;
QRhiBatchedBindings<UINT> ubuforigbindings;
QRhiBatchedBindings<UINT> ubufoffsets;
QRhiBatchedBindings<UINT> ubufsizes;
void finish() {
present = ubufs.finish();
ubuforigbindings.finish();
ubufoffsets.finish();
ubufsizes.finish();
}
void clear() {
ubufs.clear();
ubuforigbindings.clear();
ubufoffsets.clear();
ubufsizes.clear();
}
};
struct StageSamplerBatches {
bool present = false;
QRhiBatchedBindings<ID3D11SamplerState *> samplers;
QRhiBatchedBindings<ID3D11ShaderResourceView *> shaderresources;
void finish() {
present = samplers.finish();
shaderresources.finish();
}
void clear() {
samplers.clear();
shaderresources.clear();
}
};
struct StageUavBatches {
bool present = false;
QRhiBatchedBindings<ID3D11UnorderedAccessView *> uavs;
void finish() {
present = uavs.finish();
}
void clear() {
uavs.clear();
}
};
StageUniformBufferBatches vsUniformBufferBatches;
StageUniformBufferBatches hsUniformBufferBatches;
StageUniformBufferBatches dsUniformBufferBatches;
StageUniformBufferBatches gsUniformBufferBatches;
StageUniformBufferBatches fsUniformBufferBatches;
StageUniformBufferBatches csUniformBufferBatches;
StageSamplerBatches vsSamplerBatches;
StageSamplerBatches hsSamplerBatches;
StageSamplerBatches dsSamplerBatches;
StageSamplerBatches gsSamplerBatches;
StageSamplerBatches fsSamplerBatches;
StageSamplerBatches csSamplerBatches;
StageUavBatches csUavBatches;
friend class QRhiD3D11;
};
Q_DECLARE_TYPEINFO(QD3D11ShaderResourceBindings::BoundResourceData, Q_RELOCATABLE_TYPE);
struct QD3D11GraphicsPipeline : public QRhiGraphicsPipeline
{
QD3D11GraphicsPipeline(QRhiImplementation *rhi);
~QD3D11GraphicsPipeline();
void destroy() override;
bool create() override;
ID3D11DepthStencilState *dsState = nullptr;
ID3D11BlendState *blendState = nullptr;
struct {
ID3D11VertexShader *shader = nullptr;
QShader::NativeResourceBindingMap nativeResourceBindingMap;
} vs;
struct {
ID3D11HullShader *shader = nullptr;
QShader::NativeResourceBindingMap nativeResourceBindingMap;
} hs;
struct {
ID3D11DomainShader *shader = nullptr;
QShader::NativeResourceBindingMap nativeResourceBindingMap;
} ds;
struct {
ID3D11GeometryShader *shader = nullptr;
QShader::NativeResourceBindingMap nativeResourceBindingMap;
} gs;
struct {
ID3D11PixelShader *shader = nullptr;
QShader::NativeResourceBindingMap nativeResourceBindingMap;
} fs;
ID3D11InputLayout *inputLayout = nullptr;
D3D11_PRIMITIVE_TOPOLOGY d3dTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
ID3D11RasterizerState *rastState = nullptr;
uint generation = 0;
friend class QRhiD3D11;
};
struct QD3D11ComputePipeline : public QRhiComputePipeline
{
QD3D11ComputePipeline(QRhiImplementation *rhi);
~QD3D11ComputePipeline();
void destroy() override;
bool create() override;
struct {
ID3D11ComputeShader *shader = nullptr;
QShader::NativeResourceBindingMap nativeResourceBindingMap;
} cs;
uint generation = 0;
friend class QRhiD3D11;
};
struct QD3D11SwapChain;
struct QD3D11CommandBuffer : public QRhiCommandBuffer
{
QD3D11CommandBuffer(QRhiImplementation *rhi);
~QD3D11CommandBuffer();
void destroy() override;
// these must be kept at a reasonably low value otherwise sizeof Command explodes
static const int MAX_DYNAMIC_OFFSET_COUNT = 8;
static const int MAX_VERTEX_BUFFER_BINDING_COUNT = 8;
struct Command {
enum Cmd {
ResetShaderResources,
SetRenderTarget,
Clear,
Viewport,
Scissor,
BindVertexBuffers,
BindIndexBuffer,
BindGraphicsPipeline,
BindShaderResources,
StencilRef,
BlendConstants,
Draw,
DrawIndexed,
UpdateSubRes,
CopySubRes,
ResolveSubRes,
GenMip,
DebugMarkBegin,
DebugMarkEnd,
DebugMarkMsg,
BindComputePipeline,
Dispatch
};
enum ClearFlag { Color = 1, Depth = 2, Stencil = 4 };
Cmd cmd;
// QRhi*/QD3D11* references should be kept at minimum (so no
// QRhiTexture/Buffer/etc. pointers).
union Args {
struct {
QRhiRenderTarget *rt;
} setRenderTarget;
struct {
QRhiRenderTarget *rt;
int mask;
float c[4];
float d;
quint32 s;
} clear;
struct {
float x, y, w, h;
float d0, d1;
} viewport;
struct {
int x, y, w, h;
} scissor;
struct {
int startSlot;
int slotCount;
ID3D11Buffer *buffers[MAX_VERTEX_BUFFER_BINDING_COUNT];
UINT offsets[MAX_VERTEX_BUFFER_BINDING_COUNT];
UINT strides[MAX_VERTEX_BUFFER_BINDING_COUNT];
} bindVertexBuffers;
struct {
ID3D11Buffer *buffer;
quint32 offset;
DXGI_FORMAT format;
} bindIndexBuffer;
struct {
QD3D11GraphicsPipeline *ps;
} bindGraphicsPipeline;
struct {
QD3D11ShaderResourceBindings *srb;
bool offsetOnlyChange;
int dynamicOffsetCount;
uint dynamicOffsetPairs[MAX_DYNAMIC_OFFSET_COUNT * 2]; // binding, offsetInConstants
} bindShaderResources;
struct {
QD3D11GraphicsPipeline *ps;
quint32 ref;
} stencilRef;
struct {
QD3D11GraphicsPipeline *ps;
float c[4];
} blendConstants;
struct {
QD3D11GraphicsPipeline *ps;
quint32 vertexCount;
quint32 instanceCount;
quint32 firstVertex;
quint32 firstInstance;
} draw;
struct {
QD3D11GraphicsPipeline *ps;
quint32 indexCount;
quint32 instanceCount;
quint32 firstIndex;
qint32 vertexOffset;
quint32 firstInstance;
} drawIndexed;
struct {
ID3D11Resource *dst;
UINT dstSubRes;
bool hasDstBox;
D3D11_BOX dstBox;
const void *src; // must come from retain*()
UINT srcRowPitch;
} updateSubRes;
struct {
ID3D11Resource *dst;
UINT dstSubRes;
UINT dstX;
UINT dstY;
UINT dstZ;
ID3D11Resource *src;
UINT srcSubRes;
bool hasSrcBox;
D3D11_BOX srcBox;
} copySubRes;
struct {
ID3D11Resource *dst;
UINT dstSubRes;
ID3D11Resource *src;
UINT srcSubRes;
DXGI_FORMAT format;
} resolveSubRes;
struct {
ID3D11ShaderResourceView *srv;
} genMip;
struct {
char s[64];
} debugMark;
struct {
QD3D11ComputePipeline *ps;
} bindComputePipeline;
struct {
UINT x;
UINT y;
UINT z;
} dispatch;
} args;
};
enum PassType {
NoPass,
RenderPass,
ComputePass
};
QRhiBackendCommandList<Command> commands;
PassType recordingPass;
double lastGpuTime = 0;
QRhiRenderTarget *currentTarget;
QRhiGraphicsPipeline *currentGraphicsPipeline;
QRhiComputePipeline *currentComputePipeline;
uint currentPipelineGeneration;
QRhiShaderResourceBindings *currentGraphicsSrb;
QRhiShaderResourceBindings *currentComputeSrb;
uint currentSrbGeneration;
ID3D11Buffer *currentIndexBuffer;
quint32 currentIndexOffset;
DXGI_FORMAT currentIndexFormat;
ID3D11Buffer *currentVertexBuffers[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
quint32 currentVertexOffsets[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
QVarLengthArray<QByteArray, 4> dataRetainPool;
QVarLengthArray<QRhiBufferData, 4> bufferDataRetainPool;
QVarLengthArray<QImage, 4> imageRetainPool;
// relies heavily on implicit sharing (no copies of the actual data will be made)
const uchar *retainData(const QByteArray &data) {
dataRetainPool.append(data);
return reinterpret_cast<const uchar *>(dataRetainPool.last().constData());
}
const uchar *retainBufferData(const QRhiBufferData &data) {
bufferDataRetainPool.append(data);
return reinterpret_cast<const uchar *>(bufferDataRetainPool.last().constData());
}
const uchar *retainImage(const QImage &image) {
imageRetainPool.append(image);
return imageRetainPool.last().constBits();
}
void resetCommands() {
commands.reset();
dataRetainPool.clear();
bufferDataRetainPool.clear();
imageRetainPool.clear();
}
void resetState() {
recordingPass = NoPass;
// do not zero lastGpuTime
currentTarget = nullptr;
resetCommands();
resetCachedState();
}
void resetCachedState() {
currentGraphicsPipeline = nullptr;
currentComputePipeline = nullptr;
currentPipelineGeneration = 0;
currentGraphicsSrb = nullptr;
currentComputeSrb = nullptr;
currentSrbGeneration = 0;
currentIndexBuffer = nullptr;
currentIndexOffset = 0;
currentIndexFormat = DXGI_FORMAT_R16_UINT;
memset(currentVertexBuffers, 0, sizeof(currentVertexBuffers));
memset(currentVertexOffsets, 0, sizeof(currentVertexOffsets));
}
};
static const int QD3D11_SWAPCHAIN_BUFFER_COUNT = 2;
struct QD3D11Timestamps
{
static const int MAX_TIMESTAMP_PAIRS = QD3D11_SWAPCHAIN_BUFFER_COUNT;
bool active[MAX_TIMESTAMP_PAIRS] = {};
ID3D11Query *disjointQuery[MAX_TIMESTAMP_PAIRS] = {};
ID3D11Query *query[MAX_TIMESTAMP_PAIRS * 2] = {};
int pairCount = 0;
bool prepare(int pairCount, QRhiD3D11 *rhiD);
void destroy();
bool tryQueryTimestamps(int idx, ID3D11DeviceContext *context, double *elapsedSec);
};
struct QD3D11SwapChain : public QRhiSwapChain
{
QD3D11SwapChain(QRhiImplementation *rhi);
~QD3D11SwapChain();
void destroy() override;
QRhiCommandBuffer *currentFrameCommandBuffer() override;
QRhiRenderTarget *currentFrameRenderTarget() override;
QSize surfacePixelSize() override;
bool isFormatSupported(Format f) override;
QRhiSwapChainHdrInfo hdrInfo() override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
bool createOrResize() override;
void releaseBuffers();
bool newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI_SAMPLE_DESC sampleDesc,
ID3D11Texture2D **tex, ID3D11RenderTargetView **rtv) const;
QWindow *window = nullptr;
QSize pixelSize;
QD3D11SwapChainRenderTarget rt;
QD3D11CommandBuffer cb;
DXGI_FORMAT colorFormat;
DXGI_FORMAT srgbAdjustedColorFormat;
IDXGISwapChain *swapChain = nullptr;
UINT swapChainFlags = 0;
ID3D11Texture2D *backBufferTex;
ID3D11RenderTargetView *backBufferRtv;
static const int BUFFER_COUNT = QD3D11_SWAPCHAIN_BUFFER_COUNT;
ID3D11Texture2D *msaaTex[BUFFER_COUNT];
ID3D11RenderTargetView *msaaRtv[BUFFER_COUNT];
DXGI_SAMPLE_DESC sampleDesc;
int currentFrameSlot = 0;
int frameCount = 0;
QD3D11RenderBuffer *ds = nullptr;
UINT swapInterval = 1;
IDCompositionTarget *dcompTarget = nullptr;
IDCompositionVisual *dcompVisual = nullptr;
QD3D11Timestamps timestamps;
};
class QRhiD3D11 : public QRhiImplementation
{
public:
QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *importDevice = nullptr);
bool create(QRhi::Flags flags) override;
void destroy() override;
QRhiGraphicsPipeline *createGraphicsPipeline() override;
QRhiComputePipeline *createComputePipeline() override;
QRhiShaderResourceBindings *createShaderResourceBindings() override;
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
QRhiBuffer::UsageFlags usage,
quint32 size) override;
QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
int sampleCount,
QRhiRenderBuffer::Flags flags,
QRhiTexture::Format backingFormatHint) override;
QRhiTexture *createTexture(QRhiTexture::Format format,
const QSize &pixelSize,
int depth,
int arraySize,
int sampleCount,
QRhiTexture::Flags flags) override;
QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
QRhiSampler:: AddressMode u,
QRhiSampler::AddressMode v,
QRhiSampler::AddressMode w) override;
QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
QRhiTextureRenderTarget::Flags flags) override;
QRhiSwapChain *createSwapChain() override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult finish() override;
void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void beginPass(QRhiCommandBuffer *cb,
QRhiRenderTarget *rt,
const QColor &colorClearValue,
const QRhiDepthStencilClearValue &depthStencilClearValue,
QRhiResourceUpdateBatch *resourceUpdates,
QRhiCommandBuffer::BeginPassFlags flags) override;
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setGraphicsPipeline(QRhiCommandBuffer *cb,
QRhiGraphicsPipeline *ps) override;
void setShaderResources(QRhiCommandBuffer *cb,
QRhiShaderResourceBindings *srb,
int dynamicOffsetCount,
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
void setVertexInput(QRhiCommandBuffer *cb,
int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
QRhiBuffer *indexBuf, quint32 indexOffset,
QRhiCommandBuffer::IndexFormat indexFormat) override;
void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
quint32 instanceCount, quint32 firstIndex,
qint32 vertexOffset, quint32 firstInstance) override;
void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
void debugMarkEnd(QRhiCommandBuffer *cb) override;
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
void beginComputePass(QRhiCommandBuffer *cb,
QRhiResourceUpdateBatch *resourceUpdates,
QRhiCommandBuffer::BeginPassFlags flags) override;
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
void beginExternal(QRhiCommandBuffer *cb) override;
void endExternal(QRhiCommandBuffer *cb) override;
double lastCompletedGpuTime(QRhiCommandBuffer *cb) override;
QList<int> supportedSampleCounts() const override;
int ubufAlignment() const override;
bool isYUpInFramebuffer() const override;
bool isYUpInNDC() const override;
bool isClipDepthZeroToOne() const override;
QMatrix4x4 clipSpaceCorrMatrix() const override;
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
bool isFeatureSupported(QRhi::Feature feature) const override;
int resourceLimit(QRhi::ResourceLimit limit) const override;
const QRhiNativeHandles *nativeHandles() override;
QRhiDriverInfo driverInfo() const override;
QRhiStats statistics() override;
bool makeThreadLocalNativeContextCurrent() override;
void releaseCachedResources() override;
bool isDeviceLost() const override;
QByteArray pipelineCacheData() override;
void setPipelineCacheData(const QByteArray &data) override;
void enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cbD,
int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc);
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]);
void executeBufferHostWrites(QD3D11Buffer *bufD);
void bindShaderResources(QD3D11ShaderResourceBindings *srbD,
const uint *dynOfsPairs, int dynOfsPairCount,
bool offsetOnlyChange);
void resetShaderResources();
void executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain = nullptr);
DXGI_SAMPLE_DESC effectiveSampleCount(int sampleCount) const;
void finishActiveReadbacks();
void reportLiveObjects(ID3D11Device *device);
void clearShaderCache();
QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, uint flags,
QString *error, QShaderKey *usedShaderKey);
bool ensureDirectCompositionDevice();
QRhi::Flags rhiFlags;
bool debugLayer = false;
bool importedDeviceAndContext = false;
ID3D11Device *dev = nullptr;
ID3D11DeviceContext1 *context = nullptr;
D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL(0);
LUID adapterLuid = {};
ID3DUserDefinedAnnotation *annotations = nullptr;
IDXGIAdapter1 *activeAdapter = nullptr;
IDXGIFactory1 *dxgiFactory = nullptr;
IDCompositionDevice *dcompDevice = nullptr;
bool supportsAllowTearing = false;
bool deviceLost = false;
QRhiD3D11NativeHandles nativeHandlesStruct;
QRhiDriverInfo driverInfoStruct;
struct {
int vsHighestActiveVertexBufferBinding = -1;
bool vsHasIndexBufferBound = false;
int vsHighestActiveSrvBinding = -1;
int hsHighestActiveSrvBinding = -1;
int dsHighestActiveSrvBinding = -1;
int gsHighestActiveSrvBinding = -1;
int fsHighestActiveSrvBinding = -1;
int csHighestActiveSrvBinding = -1;
int csHighestActiveUavBinding = -1;
QD3D11SwapChain *currentSwapChain = nullptr;
} contextState;
struct OffscreenFrame {
OffscreenFrame(QRhiImplementation *rhi) : cbWrapper(rhi) { }
bool active = false;
QD3D11CommandBuffer cbWrapper;
QD3D11Timestamps timestamps;
int timestampIdx = 0;
} ofr;
struct TextureReadback {
QRhiReadbackDescription desc;
QRhiReadbackResult *result;
ID3D11Texture2D *stagingTex;
quint32 byteSize;
quint32 bpl;
QSize pixelSize;
QRhiTexture::Format format;
};
QVarLengthArray<TextureReadback, 2> activeTextureReadbacks;
struct BufferReadback {
QRhiReadbackResult *result;
quint32 byteSize;
ID3D11Buffer *stagingBuf;
};
QVarLengthArray<BufferReadback, 2> activeBufferReadbacks;
struct Shader {
Shader() = default;
Shader(IUnknown *s, const QByteArray &bytecode, const QShader::NativeResourceBindingMap &rbm)
: s(s), bytecode(bytecode), nativeResourceBindingMap(rbm) { }
IUnknown *s;
QByteArray bytecode;
QShader::NativeResourceBindingMap nativeResourceBindingMap;
};
QHash<QRhiShaderStage, Shader> m_shaderCache;
// This is what gets exposed as the "pipeline cache", not that that concept
// applies anyway. Here we are just storing the DX bytecode for a shader so
// we can skip the HLSL->DXBC compilation when the QShader has HLSL source
// code and the same shader source has already been compiled before.
// m_shaderCache seemingly does the same, but this here does not care about
// the ID3D11*Shader, this is just about the bytecode and about allowing
// the data to be serialized to persistent storage and then reloaded in
// future runs of the app, or when creating another QRhi, etc.
struct BytecodeCacheKey {
QByteArray sourceHash;
QByteArray target;
QByteArray entryPoint;
uint compileFlags;
};
QHash<BytecodeCacheKey, QByteArray> m_bytecodeCache;
};
Q_DECLARE_TYPEINFO(QRhiD3D11::TextureReadback, Q_RELOCATABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiD3D11::BufferReadback, Q_RELOCATABLE_TYPE);
inline bool operator==(const QRhiD3D11::BytecodeCacheKey &a, const QRhiD3D11::BytecodeCacheKey &b) noexcept
{
return a.sourceHash == b.sourceHash
&& a.target == b.target
&& a.entryPoint == b.entryPoint
&& a.compileFlags == b.compileFlags;
}
inline bool operator!=(const QRhiD3D11::BytecodeCacheKey &a, const QRhiD3D11::BytecodeCacheKey &b) noexcept
{
return !(a == b);
}
inline size_t qHash(const QRhiD3D11::BytecodeCacheKey &k, size_t seed = 0) noexcept
{
return qHash(k.sourceHash, seed) ^ qHash(k.target) ^ qHash(k.entryPoint) ^ k.compileFlags;
}
QT_END_NAMESPACE
#endif

View File

@ -1,8 +1,8 @@
// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qrhid3d12_p_p.h"
#include "qshader_p.h"
#include "qrhid3d12_p.h"
#include "qshader.h"
#include <QWindow>
#include <qmath.h>
#include <private/qsystemlibrary_p.h>
@ -30,6 +30,9 @@ QT_BEGIN_NAMESPACE
\inmodule QtGui
\brief Direct3D 12 specific initialization parameters.
\note This a RHI API with limited compatibility guarantees, see \l QRhi
for details.
A D3D12-based QRhi needs no special parameters for initialization. If
desired, enableDebugLayer can be set to \c true to enable the Direct3D
debug layer. This can be useful during development, but should be avoided
@ -62,14 +65,44 @@ QT_BEGIN_NAMESPACE
commandQueue to a non-null value.
*/
/*!
\variable QRhiD3D12InitParams::enableDebugLayer
When set to true, the debug layer is enabled, if installed and available.
The default value is false.
*/
/*!
\class QRhiD3D12NativeHandles
\inmodule QtGui
\brief Holds the D3D12 device used by the QRhi.
\note The class uses \c{void *} as the type since including the COM-based
\c{d3d12.h} headers is not acceptable here. The actual type is
\c{ID3D12Device *}.
\c{d3d12.h} headers is not acceptable here. The actual types are
\c{ID3D12Device *} and \c{ID3D12CommandQueue *}.
\note This a RHI API with limited compatibility guarantees, see \l QRhi
for details.
*/
/*!
\variable QRhiD3D12NativeHandles::dev
*/
/*!
\variable QRhiD3D12NativeHandles::minimumFeatureLevel
*/
/*!
\variable QRhiD3D12NativeHandles::adapterLuidLow
*/
/*!
\variable QRhiD3D12NativeHandles::adapterLuidHigh
*/
/*!
\variable QRhiD3D12NativeHandles::commandQueue
*/
/*!
@ -82,6 +115,13 @@ QT_BEGIN_NAMESPACE
\l{QRhi::beginFrame()}{beginFrame()} - \l{QRhi::endFrame()}{endFrame()} or
\l{QRhi::beginOffscreenFrame()}{beginOffscreenFrame()} -
\l{QRhi::endOffscreenFrame()}{endOffscreenFrame()} pair.
\note This a RHI API with limited compatibility guarantees, see \l QRhi
for details.
*/
/*!
\variable QRhiD3D12CommandBufferNativeHandles::commandList
*/
// https://learn.microsoft.com/en-us/windows/win32/direct3d12/hardware-feature-levels

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
// Copyright (C) 2021 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qrhigles2_p_p.h"
#include "qrhigles2_p.h"
#include <QOffscreenSurface>
#include <QOpenGLContext>
#include <QtCore/qmap.h>
@ -27,10 +27,13 @@ QT_BEGIN_NAMESPACE
/*!
\class QRhiGles2InitParams
\internal
\inmodule QtGui
\since 6.6
\brief OpenGL specific initialization parameters.
\note This a RHI API with limited compatibility guarantees, see \l QRhi
for details.
An OpenGL-based QRhi needs an already created QSurface that can be used in
combination with QOpenGLContext. Most commonly, this is a QOffscreenSurface
in practice. Additionally, while optional, it is recommended that the QWindow
@ -103,11 +106,49 @@ QT_BEGIN_NAMESPACE
QRhiGles2NativeHandles.
*/
/*!
\variable QRhiGles2InitParams::format
The QSurfaceFormat, initialized to QSurfaceFormat::defaultFormat() by default.
*/
/*!
\variable QRhiGles2InitParams::fallbackSurface
A QSurface compatible with \l format. Typically a QOffscreenSurface.
Providing this is mandatory. Be aware of the threading implications: a
QOffscreenSurface, like QWindow, must only ever be created and destroyed on
the main (gui) thread, even if the QRhi is created and operates on another
thread.
*/
/*!
\variable QRhiGles2InitParams::window
Optional, but setting it is recommended when targeting a QWindow with the
QRhi.
*/
/*!
\variable QRhiGles2InitParams::shareContext
Optional, the QOpenGLContext to share resource with. QRhi creates its own
context, and setting this member to a valid QOpenGLContext leads to calling
\l{QOpenGLContext::setShareContext()}{setShareContext()} with it.
*/
/*!
\class QRhiGles2NativeHandles
\internal
\inmodule QtGui
\since 6.6
\brief Holds the OpenGL context used by the QRhi.
\note This a RHI API with limited compatibility guarantees, see \l QRhi
for details.
*/
/*!
\variable QRhiGles2NativeHandles::context
*/
#ifndef GL_BGRA

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
// Copyright (C) 2019 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qrhimetal_p_p.h"
#include <QtGui/private/qshader_p_p.h>
#include "qrhimetal_p.h"
#include "qshader_p.h"
#include <QGuiApplication>
#include <QWindow>
#include <QUrl>
@ -50,9 +50,12 @@ QT_BEGIN_NAMESPACE
/*!
\class QRhiMetalInitParams
\inmodule QtRhi
\internal
\since 6.6
\brief Metal specific initialization parameters.
\note This an RHI API with limited compatibility guarantees, see \l QRhi
for details.
A Metal-based QRhi needs no special parameters for initialization.
\badcode
@ -85,14 +88,25 @@ QT_BEGIN_NAMESPACE
/*!
\class QRhiMetalNativeHandles
\inmodule QtRhi
\internal
\since 6.6
\brief Holds the Metal device used by the QRhi.
\note This an RHI API with limited compatibility guarantees, see \l QRhi
for details.
*/
/*!
\variable QRhiMetalNativeHandles::dev
*/
/*!
\variable QRhiMetalNativeHandles::cmdQueue
*/
/*!
\class QRhiMetalCommandBufferNativeHandles
\inmodule QtRhi
\internal
\since 6.6
\brief Holds the MTLCommandBuffer and MTLRenderCommandEncoder objects that are backing a QRhiCommandBuffer.
\note The command buffer object is only guaranteed to be valid while
@ -104,6 +118,17 @@ QT_BEGIN_NAMESPACE
\note The command encoder is only valid while recording a pass, that is,
between \l{QRhiCommandBuffer::beginPass()} -
\l{QRhiCommandBuffer::endPass()}.
\note This an RHI API with limited compatibility guarantees, see \l QRhi
for details.
*/
/*!
\variable QRhiMetalCommandBufferNativeHandles::commandBuffer
*/
/*!
\variable QRhiMetalCommandBufferNativeHandles::encoder
*/
struct QMetalShader

View File

@ -1,8 +1,8 @@
// Copyright (C) 2019 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRHIMETAL_H
#define QRHIMETAL_H
#ifndef QRHIMETAL_P_H
#define QRHIMETAL_P_H
//
// W A R N I N G
@ -15,29 +15,493 @@
// We mean it.
//
#include <private/qrhi_p.h>
Q_FORWARD_DECLARE_OBJC_CLASS(MTLDevice);
Q_FORWARD_DECLARE_OBJC_CLASS(MTLCommandQueue);
Q_FORWARD_DECLARE_OBJC_CLASS(MTLCommandBuffer);
Q_FORWARD_DECLARE_OBJC_CLASS(MTLRenderCommandEncoder);
#include "qrhi_p.h"
#include <QWindow>
QT_BEGIN_NAMESPACE
struct Q_GUI_EXPORT QRhiMetalInitParams : public QRhiInitParams
static const int QMTL_FRAMES_IN_FLIGHT = 2;
// have to hide the ObjC stuff, this header cannot contain MTL* at all
struct QMetalBufferData;
struct QMetalBuffer : public QRhiBuffer
{
QMetalBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
~QMetalBuffer();
void destroy() override;
bool create() override;
QRhiBuffer::NativeBuffer nativeBuffer() override;
char *beginFullDynamicBufferUpdateForCurrentFrame() override;
void endFullDynamicBufferUpdateForCurrentFrame() override;
QMetalBufferData *d;
uint generation = 0;
int lastActiveFrameSlot = -1;
friend class QRhiMetal;
friend struct QMetalShaderResourceBindings;
static constexpr int WorkBufPoolUsage = 1 << 8;
static_assert(WorkBufPoolUsage > QRhiBuffer::StorageBuffer);
};
struct Q_GUI_EXPORT QRhiMetalNativeHandles : public QRhiNativeHandles
struct QMetalRenderBufferData;
struct QMetalRenderBuffer : public QRhiRenderBuffer
{
MTLDevice *dev = nullptr;
MTLCommandQueue *cmdQueue = nullptr;
QMetalRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags,
QRhiTexture::Format backingFormatHint);
~QMetalRenderBuffer();
void destroy() override;
bool create() override;
QRhiTexture::Format backingFormat() const override;
QMetalRenderBufferData *d;
int samples = 1;
uint generation = 0;
int lastActiveFrameSlot = -1;
friend class QRhiMetal;
};
struct Q_GUI_EXPORT QRhiMetalCommandBufferNativeHandles : public QRhiNativeHandles
struct QMetalTextureData;
struct QMetalTexture : public QRhiTexture
{
MTLCommandBuffer *commandBuffer = nullptr;
MTLRenderCommandEncoder *encoder = nullptr;
QMetalTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
int arraySize, int sampleCount, Flags flags);
~QMetalTexture();
void destroy() override;
bool create() override;
bool createFrom(NativeTexture src) override;
NativeTexture nativeTexture() override;
bool prepareCreate(QSize *adjustedSize = nullptr);
QMetalTextureData *d;
int mipLevelCount = 0;
int samples = 1;
uint generation = 0;
int lastActiveFrameSlot = -1;
friend class QRhiMetal;
friend struct QMetalShaderResourceBindings;
friend struct QMetalTextureData;
};
struct QMetalSamplerData;
struct QMetalSampler : public QRhiSampler
{
QMetalSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
AddressMode u, AddressMode v, AddressMode w);
~QMetalSampler();
void destroy() override;
bool create() override;
QMetalSamplerData *d;
uint generation = 0;
int lastActiveFrameSlot = -1;
friend class QRhiMetal;
friend struct QMetalShaderResourceBindings;
};
struct QMetalRenderPassDescriptor : public QRhiRenderPassDescriptor
{
QMetalRenderPassDescriptor(QRhiImplementation *rhi);
~QMetalRenderPassDescriptor();
void destroy() override;
bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
QVector<quint32> serializedFormat() const override;
void updateSerializedFormat();
// there is no MTLRenderPassDescriptor here as one will be created for each pass in beginPass()
// but the things needed for the render pipeline descriptor have to be provided
static const int MAX_COLOR_ATTACHMENTS = 8;
int colorAttachmentCount = 0;
bool hasDepthStencil = false;
int colorFormat[MAX_COLOR_ATTACHMENTS];
int dsFormat;
QVector<quint32> serializedFormatData;
};
struct QMetalRenderTargetData;
struct QMetalSwapChainRenderTarget : public QRhiSwapChainRenderTarget
{
QMetalSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
~QMetalSwapChainRenderTarget();
void destroy() override;
QSize pixelSize() const override;
float devicePixelRatio() const override;
int sampleCount() const override;
QMetalRenderTargetData *d;
};
struct QMetalTextureRenderTarget : public QRhiTextureRenderTarget
{
QMetalTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
~QMetalTextureRenderTarget();
void destroy() override;
QSize pixelSize() const override;
float devicePixelRatio() const override;
int sampleCount() const override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
bool create() override;
QMetalRenderTargetData *d;
friend class QRhiMetal;
};
struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
{
QMetalShaderResourceBindings(QRhiImplementation *rhi);
~QMetalShaderResourceBindings();
void destroy() override;
bool create() override;
void updateResources(UpdateFlags flags) override;
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
int maxBinding = -1;
struct BoundUniformBufferData {
quint64 id;
uint generation;
};
struct BoundSampledTextureData {
int count;
struct {
quint64 texId;
uint texGeneration;
quint64 samplerId;
uint samplerGeneration;
} d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE];
};
struct BoundStorageImageData {
quint64 id;
uint generation;
};
struct BoundStorageBufferData {
quint64 id;
uint generation;
};
struct BoundResourceData {
union {
BoundUniformBufferData ubuf;
BoundSampledTextureData stex;
BoundStorageImageData simage;
BoundStorageBufferData sbuf;
};
};
QVarLengthArray<BoundResourceData, 8> boundResourceData;
uint generation = 0;
friend class QRhiMetal;
};
struct QMetalGraphicsPipelineData;
struct QMetalCommandBuffer;
struct QMetalGraphicsPipeline : public QRhiGraphicsPipeline
{
QMetalGraphicsPipeline(QRhiImplementation *rhi);
~QMetalGraphicsPipeline();
void destroy() override;
bool create() override;
void makeActiveForCurrentRenderPassEncoder(QMetalCommandBuffer *cbD);
void setupAttachmentsInMetalRenderPassDescriptor(void *metalRpDesc, QMetalRenderPassDescriptor *rpD);
void setupMetalDepthStencilDescriptor(void *metalDsDesc);
void mapStates();
bool createVertexFragmentPipeline();
bool createTessellationPipelines(const QShader &tessVert, const QShader &tesc, const QShader &tese, const QShader &tessFrag);
QMetalGraphicsPipelineData *d;
uint generation = 0;
int lastActiveFrameSlot = -1;
friend class QRhiMetal;
};
struct QMetalComputePipelineData;
struct QMetalComputePipeline : public QRhiComputePipeline
{
QMetalComputePipeline(QRhiImplementation *rhi);
~QMetalComputePipeline();
void destroy() override;
bool create() override;
QMetalComputePipelineData *d;
uint generation = 0;
int lastActiveFrameSlot = -1;
friend class QRhiMetal;
};
struct QMetalCommandBufferData;
struct QMetalSwapChain;
struct QMetalCommandBuffer : public QRhiCommandBuffer
{
QMetalCommandBuffer(QRhiImplementation *rhi);
~QMetalCommandBuffer();
void destroy() override;
QMetalCommandBufferData *d = nullptr;
QRhiMetalCommandBufferNativeHandles nativeHandlesStruct;
enum PassType {
NoPass,
RenderPass,
ComputePass
};
// per-pass (render or compute command encoder) persistent state
PassType recordingPass;
QRhiRenderTarget *currentTarget;
// per-pass (render or compute command encoder) volatile (cached) state
QMetalGraphicsPipeline *currentGraphicsPipeline;
QMetalComputePipeline *currentComputePipeline;
uint currentPipelineGeneration;
QMetalShaderResourceBindings *currentGraphicsSrb;
QMetalShaderResourceBindings *currentComputeSrb;
uint currentSrbGeneration;
int currentResSlot;
QMetalBuffer *currentIndexBuffer;
quint32 currentIndexOffset;
QRhiCommandBuffer::IndexFormat currentIndexFormat;
int currentCullMode;
int currentTriangleFillMode;
int currentFrontFaceWinding;
QPair<float, float> currentDepthBiasValues;
const QRhiNativeHandles *nativeHandles();
void resetState(double lastGpuTime = 0);
void resetPerPassState();
void resetPerPassCachedState();
};
struct QMetalSwapChainData;
struct QMetalSwapChain : public QRhiSwapChain
{
QMetalSwapChain(QRhiImplementation *rhi);
~QMetalSwapChain();
void destroy() override;
QRhiCommandBuffer *currentFrameCommandBuffer() override;
QRhiRenderTarget *currentFrameRenderTarget() override;
QSize surfacePixelSize() override;
bool isFormatSupported(Format f) override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
bool createOrResize() override;
virtual QRhiSwapChainHdrInfo hdrInfo() override;
void chooseFormats();
void waitUntilCompleted(int slot);
QWindow *window = nullptr;
QSize pixelSize;
int currentFrameSlot = 0; // 0..QMTL_FRAMES_IN_FLIGHT-1
int frameCount = 0;
int samples = 1;
QMetalSwapChainRenderTarget rtWrapper;
QMetalCommandBuffer cbWrapper;
QMetalRenderBuffer *ds = nullptr;
QMetalSwapChainData *d = nullptr;
};
struct QRhiMetalData;
class QRhiMetal : public QRhiImplementation
{
public:
QRhiMetal(QRhiMetalInitParams *params, QRhiMetalNativeHandles *importDevice = nullptr);
~QRhiMetal();
static bool probe(QRhiMetalInitParams *params);
static QRhiSwapChainProxyData updateSwapChainProxyData(QWindow *window);
bool create(QRhi::Flags flags) override;
void destroy() override;
QRhiGraphicsPipeline *createGraphicsPipeline() override;
QRhiComputePipeline *createComputePipeline() override;
QRhiShaderResourceBindings *createShaderResourceBindings() override;
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
QRhiBuffer::UsageFlags usage,
quint32 size) override;
QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
int sampleCount,
QRhiRenderBuffer::Flags flags,
QRhiTexture::Format backingFormatHint) override;
QRhiTexture *createTexture(QRhiTexture::Format format,
const QSize &pixelSize,
int depth,
int arraySize,
int sampleCount,
QRhiTexture::Flags flags) override;
QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
QRhiSampler:: AddressMode u,
QRhiSampler::AddressMode v,
QRhiSampler::AddressMode w) override;
QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
QRhiTextureRenderTarget::Flags flags) override;
QRhiSwapChain *createSwapChain() override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult finish() override;
void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void beginPass(QRhiCommandBuffer *cb,
QRhiRenderTarget *rt,
const QColor &colorClearValue,
const QRhiDepthStencilClearValue &depthStencilClearValue,
QRhiResourceUpdateBatch *resourceUpdates,
QRhiCommandBuffer::BeginPassFlags flags) override;
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setGraphicsPipeline(QRhiCommandBuffer *cb,
QRhiGraphicsPipeline *ps) override;
void setShaderResources(QRhiCommandBuffer *cb,
QRhiShaderResourceBindings *srb,
int dynamicOffsetCount,
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
void setVertexInput(QRhiCommandBuffer *cb,
int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
QRhiBuffer *indexBuf, quint32 indexOffset,
QRhiCommandBuffer::IndexFormat indexFormat) override;
void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
quint32 instanceCount, quint32 firstIndex,
qint32 vertexOffset, quint32 firstInstance) override;
void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
void debugMarkEnd(QRhiCommandBuffer *cb) override;
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
void beginComputePass(QRhiCommandBuffer *cb,
QRhiResourceUpdateBatch *resourceUpdates,
QRhiCommandBuffer::BeginPassFlags flags) override;
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
void beginExternal(QRhiCommandBuffer *cb) override;
void endExternal(QRhiCommandBuffer *cb) override;
double lastCompletedGpuTime(QRhiCommandBuffer *cb) override;
QList<int> supportedSampleCounts() const override;
int ubufAlignment() const override;
bool isYUpInFramebuffer() const override;
bool isYUpInNDC() const override;
bool isClipDepthZeroToOne() const override;
QMatrix4x4 clipSpaceCorrMatrix() const override;
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
bool isFeatureSupported(QRhi::Feature feature) const override;
int resourceLimit(QRhi::ResourceLimit limit) const override;
const QRhiNativeHandles *nativeHandles() override;
QRhiDriverInfo driverInfo() const override;
QRhiStats statistics() override;
bool makeThreadLocalNativeContextCurrent() override;
void releaseCachedResources() override;
bool isDeviceLost() const override;
QByteArray pipelineCacheData() override;
void setPipelineCacheData(const QByteArray &data) override;
void executeDeferredReleases(bool forced = false);
void finishActiveReadbacks(bool forced = false);
qsizetype subresUploadByteSize(const QRhiTextureSubresourceUploadDescription &subresDesc) const;
void enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEncPtr,
int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc,
qsizetype *curOfs);
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
void executeBufferHostWritesForSlot(QMetalBuffer *bufD, int slot);
void executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD);
static const int SUPPORTED_STAGES = 5;
void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD,
QMetalCommandBuffer *cbD,
int dynamicOffsetCount,
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets,
bool offsetOnlyChange,
const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[SUPPORTED_STAGES]);
int effectiveSampleCount(int sampleCount) const;
struct TessDrawArgs {
QMetalCommandBuffer *cbD;
enum {
NonIndexed,
U16Indexed,
U32Indexed
} type;
struct NonIndexedArgs {
quint32 vertexCount;
quint32 instanceCount;
quint32 firstVertex;
quint32 firstInstance;
};
struct IndexedArgs {
quint32 indexCount;
quint32 instanceCount;
quint32 firstIndex;
qint32 vertexOffset;
quint32 firstInstance;
void *indexBuffer;
};
union {
NonIndexedArgs draw;
IndexedArgs drawIndexed;
};
};
void tessellatedDraw(const TessDrawArgs &args);
QRhi::Flags rhiFlags;
bool importedDevice = false;
bool importedCmdQueue = false;
QMetalSwapChain *currentSwapChain = nullptr;
QSet<QMetalSwapChain *> swapchains;
QRhiMetalNativeHandles nativeHandlesStruct;
QRhiDriverInfo driverInfoStruct;
quint32 osMajor = 0;
quint32 osMinor = 0;
struct {
int maxTextureSize = 4096;
bool baseVertexAndInstance = true;
QVector<int> supportedSampleCounts;
bool isAppleGPU = false;
int maxThreadGroupSize = 512;
} caps;
QRhiMetalData *d = nullptr;
};
QT_END_NAMESPACE

View File

@ -1,510 +0,0 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRHIMETAL_P_H
#define QRHIMETAL_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qrhimetal_p.h"
#include "qrhi_p_p.h"
#include <QWindow>
QT_BEGIN_NAMESPACE
static const int QMTL_FRAMES_IN_FLIGHT = 2;
// have to hide the ObjC stuff, this header cannot contain MTL* at all
struct QMetalBufferData;
struct QMetalBuffer : public QRhiBuffer
{
QMetalBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
~QMetalBuffer();
void destroy() override;
bool create() override;
QRhiBuffer::NativeBuffer nativeBuffer() override;
char *beginFullDynamicBufferUpdateForCurrentFrame() override;
void endFullDynamicBufferUpdateForCurrentFrame() override;
QMetalBufferData *d;
uint generation = 0;
int lastActiveFrameSlot = -1;
friend class QRhiMetal;
friend struct QMetalShaderResourceBindings;
static constexpr int WorkBufPoolUsage = 1 << 8;
static_assert(WorkBufPoolUsage > QRhiBuffer::StorageBuffer);
};
struct QMetalRenderBufferData;
struct QMetalRenderBuffer : public QRhiRenderBuffer
{
QMetalRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags,
QRhiTexture::Format backingFormatHint);
~QMetalRenderBuffer();
void destroy() override;
bool create() override;
QRhiTexture::Format backingFormat() const override;
QMetalRenderBufferData *d;
int samples = 1;
uint generation = 0;
int lastActiveFrameSlot = -1;
friend class QRhiMetal;
};
struct QMetalTextureData;
struct QMetalTexture : public QRhiTexture
{
QMetalTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
int arraySize, int sampleCount, Flags flags);
~QMetalTexture();
void destroy() override;
bool create() override;
bool createFrom(NativeTexture src) override;
NativeTexture nativeTexture() override;
bool prepareCreate(QSize *adjustedSize = nullptr);
QMetalTextureData *d;
int mipLevelCount = 0;
int samples = 1;
uint generation = 0;
int lastActiveFrameSlot = -1;
friend class QRhiMetal;
friend struct QMetalShaderResourceBindings;
friend struct QMetalTextureData;
};
struct QMetalSamplerData;
struct QMetalSampler : public QRhiSampler
{
QMetalSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
AddressMode u, AddressMode v, AddressMode w);
~QMetalSampler();
void destroy() override;
bool create() override;
QMetalSamplerData *d;
uint generation = 0;
int lastActiveFrameSlot = -1;
friend class QRhiMetal;
friend struct QMetalShaderResourceBindings;
};
struct QMetalRenderPassDescriptor : public QRhiRenderPassDescriptor
{
QMetalRenderPassDescriptor(QRhiImplementation *rhi);
~QMetalRenderPassDescriptor();
void destroy() override;
bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
QVector<quint32> serializedFormat() const override;
void updateSerializedFormat();
// there is no MTLRenderPassDescriptor here as one will be created for each pass in beginPass()
// but the things needed for the render pipeline descriptor have to be provided
static const int MAX_COLOR_ATTACHMENTS = 8;
int colorAttachmentCount = 0;
bool hasDepthStencil = false;
int colorFormat[MAX_COLOR_ATTACHMENTS];
int dsFormat;
QVector<quint32> serializedFormatData;
};
struct QMetalRenderTargetData;
struct QMetalSwapChainRenderTarget : public QRhiSwapChainRenderTarget
{
QMetalSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
~QMetalSwapChainRenderTarget();
void destroy() override;
QSize pixelSize() const override;
float devicePixelRatio() const override;
int sampleCount() const override;
QMetalRenderTargetData *d;
};
struct QMetalTextureRenderTarget : public QRhiTextureRenderTarget
{
QMetalTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
~QMetalTextureRenderTarget();
void destroy() override;
QSize pixelSize() const override;
float devicePixelRatio() const override;
int sampleCount() const override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
bool create() override;
QMetalRenderTargetData *d;
friend class QRhiMetal;
};
struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
{
QMetalShaderResourceBindings(QRhiImplementation *rhi);
~QMetalShaderResourceBindings();
void destroy() override;
bool create() override;
void updateResources(UpdateFlags flags) override;
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
int maxBinding = -1;
struct BoundUniformBufferData {
quint64 id;
uint generation;
};
struct BoundSampledTextureData {
int count;
struct {
quint64 texId;
uint texGeneration;
quint64 samplerId;
uint samplerGeneration;
} d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE];
};
struct BoundStorageImageData {
quint64 id;
uint generation;
};
struct BoundStorageBufferData {
quint64 id;
uint generation;
};
struct BoundResourceData {
union {
BoundUniformBufferData ubuf;
BoundSampledTextureData stex;
BoundStorageImageData simage;
BoundStorageBufferData sbuf;
};
};
QVarLengthArray<BoundResourceData, 8> boundResourceData;
uint generation = 0;
friend class QRhiMetal;
};
struct QMetalGraphicsPipelineData;
struct QMetalCommandBuffer;
struct QMetalGraphicsPipeline : public QRhiGraphicsPipeline
{
QMetalGraphicsPipeline(QRhiImplementation *rhi);
~QMetalGraphicsPipeline();
void destroy() override;
bool create() override;
void makeActiveForCurrentRenderPassEncoder(QMetalCommandBuffer *cbD);
void setupAttachmentsInMetalRenderPassDescriptor(void *metalRpDesc, QMetalRenderPassDescriptor *rpD);
void setupMetalDepthStencilDescriptor(void *metalDsDesc);
void mapStates();
bool createVertexFragmentPipeline();
bool createTessellationPipelines(const QShader &tessVert, const QShader &tesc, const QShader &tese, const QShader &tessFrag);
QMetalGraphicsPipelineData *d;
uint generation = 0;
int lastActiveFrameSlot = -1;
friend class QRhiMetal;
};
struct QMetalComputePipelineData;
struct QMetalComputePipeline : public QRhiComputePipeline
{
QMetalComputePipeline(QRhiImplementation *rhi);
~QMetalComputePipeline();
void destroy() override;
bool create() override;
QMetalComputePipelineData *d;
uint generation = 0;
int lastActiveFrameSlot = -1;
friend class QRhiMetal;
};
struct QMetalCommandBufferData;
struct QMetalSwapChain;
struct QMetalCommandBuffer : public QRhiCommandBuffer
{
QMetalCommandBuffer(QRhiImplementation *rhi);
~QMetalCommandBuffer();
void destroy() override;
QMetalCommandBufferData *d = nullptr;
QRhiMetalCommandBufferNativeHandles nativeHandlesStruct;
enum PassType {
NoPass,
RenderPass,
ComputePass
};
// per-pass (render or compute command encoder) persistent state
PassType recordingPass;
QRhiRenderTarget *currentTarget;
// per-pass (render or compute command encoder) volatile (cached) state
QMetalGraphicsPipeline *currentGraphicsPipeline;
QMetalComputePipeline *currentComputePipeline;
uint currentPipelineGeneration;
QMetalShaderResourceBindings *currentGraphicsSrb;
QMetalShaderResourceBindings *currentComputeSrb;
uint currentSrbGeneration;
int currentResSlot;
QMetalBuffer *currentIndexBuffer;
quint32 currentIndexOffset;
QRhiCommandBuffer::IndexFormat currentIndexFormat;
int currentCullMode;
int currentTriangleFillMode;
int currentFrontFaceWinding;
QPair<float, float> currentDepthBiasValues;
const QRhiNativeHandles *nativeHandles();
void resetState(double lastGpuTime = 0);
void resetPerPassState();
void resetPerPassCachedState();
};
struct QMetalSwapChainData;
struct QMetalSwapChain : public QRhiSwapChain
{
QMetalSwapChain(QRhiImplementation *rhi);
~QMetalSwapChain();
void destroy() override;
QRhiCommandBuffer *currentFrameCommandBuffer() override;
QRhiRenderTarget *currentFrameRenderTarget() override;
QSize surfacePixelSize() override;
bool isFormatSupported(Format f) override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
bool createOrResize() override;
virtual QRhiSwapChainHdrInfo hdrInfo() override;
void chooseFormats();
void waitUntilCompleted(int slot);
QWindow *window = nullptr;
QSize pixelSize;
int currentFrameSlot = 0; // 0..QMTL_FRAMES_IN_FLIGHT-1
int frameCount = 0;
int samples = 1;
QMetalSwapChainRenderTarget rtWrapper;
QMetalCommandBuffer cbWrapper;
QMetalRenderBuffer *ds = nullptr;
QMetalSwapChainData *d = nullptr;
};
struct QRhiMetalData;
class QRhiMetal : public QRhiImplementation
{
public:
QRhiMetal(QRhiMetalInitParams *params, QRhiMetalNativeHandles *importDevice = nullptr);
~QRhiMetal();
static bool probe(QRhiMetalInitParams *params);
static QRhiSwapChainProxyData updateSwapChainProxyData(QWindow *window);
bool create(QRhi::Flags flags) override;
void destroy() override;
QRhiGraphicsPipeline *createGraphicsPipeline() override;
QRhiComputePipeline *createComputePipeline() override;
QRhiShaderResourceBindings *createShaderResourceBindings() override;
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
QRhiBuffer::UsageFlags usage,
quint32 size) override;
QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
int sampleCount,
QRhiRenderBuffer::Flags flags,
QRhiTexture::Format backingFormatHint) override;
QRhiTexture *createTexture(QRhiTexture::Format format,
const QSize &pixelSize,
int depth,
int arraySize,
int sampleCount,
QRhiTexture::Flags flags) override;
QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
QRhiSampler:: AddressMode u,
QRhiSampler::AddressMode v,
QRhiSampler::AddressMode w) override;
QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
QRhiTextureRenderTarget::Flags flags) override;
QRhiSwapChain *createSwapChain() override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult finish() override;
void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void beginPass(QRhiCommandBuffer *cb,
QRhiRenderTarget *rt,
const QColor &colorClearValue,
const QRhiDepthStencilClearValue &depthStencilClearValue,
QRhiResourceUpdateBatch *resourceUpdates,
QRhiCommandBuffer::BeginPassFlags flags) override;
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setGraphicsPipeline(QRhiCommandBuffer *cb,
QRhiGraphicsPipeline *ps) override;
void setShaderResources(QRhiCommandBuffer *cb,
QRhiShaderResourceBindings *srb,
int dynamicOffsetCount,
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
void setVertexInput(QRhiCommandBuffer *cb,
int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
QRhiBuffer *indexBuf, quint32 indexOffset,
QRhiCommandBuffer::IndexFormat indexFormat) override;
void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
quint32 instanceCount, quint32 firstIndex,
qint32 vertexOffset, quint32 firstInstance) override;
void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
void debugMarkEnd(QRhiCommandBuffer *cb) override;
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
void beginComputePass(QRhiCommandBuffer *cb,
QRhiResourceUpdateBatch *resourceUpdates,
QRhiCommandBuffer::BeginPassFlags flags) override;
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
void beginExternal(QRhiCommandBuffer *cb) override;
void endExternal(QRhiCommandBuffer *cb) override;
double lastCompletedGpuTime(QRhiCommandBuffer *cb) override;
QList<int> supportedSampleCounts() const override;
int ubufAlignment() const override;
bool isYUpInFramebuffer() const override;
bool isYUpInNDC() const override;
bool isClipDepthZeroToOne() const override;
QMatrix4x4 clipSpaceCorrMatrix() const override;
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
bool isFeatureSupported(QRhi::Feature feature) const override;
int resourceLimit(QRhi::ResourceLimit limit) const override;
const QRhiNativeHandles *nativeHandles() override;
QRhiDriverInfo driverInfo() const override;
QRhiStats statistics() override;
bool makeThreadLocalNativeContextCurrent() override;
void releaseCachedResources() override;
bool isDeviceLost() const override;
QByteArray pipelineCacheData() override;
void setPipelineCacheData(const QByteArray &data) override;
void executeDeferredReleases(bool forced = false);
void finishActiveReadbacks(bool forced = false);
qsizetype subresUploadByteSize(const QRhiTextureSubresourceUploadDescription &subresDesc) const;
void enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEncPtr,
int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc,
qsizetype *curOfs);
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
void executeBufferHostWritesForSlot(QMetalBuffer *bufD, int slot);
void executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD);
static const int SUPPORTED_STAGES = 5;
void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD,
QMetalCommandBuffer *cbD,
int dynamicOffsetCount,
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets,
bool offsetOnlyChange,
const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[SUPPORTED_STAGES]);
int effectiveSampleCount(int sampleCount) const;
struct TessDrawArgs {
QMetalCommandBuffer *cbD;
enum {
NonIndexed,
U16Indexed,
U32Indexed
} type;
struct NonIndexedArgs {
quint32 vertexCount;
quint32 instanceCount;
quint32 firstVertex;
quint32 firstInstance;
};
struct IndexedArgs {
quint32 indexCount;
quint32 instanceCount;
quint32 firstIndex;
qint32 vertexOffset;
quint32 firstInstance;
void *indexBuffer;
};
union {
NonIndexedArgs draw;
IndexedArgs drawIndexed;
};
};
void tessellatedDraw(const TessDrawArgs &args);
QRhi::Flags rhiFlags;
bool importedDevice = false;
bool importedCmdQueue = false;
QMetalSwapChain *currentSwapChain = nullptr;
QSet<QMetalSwapChain *> swapchains;
QRhiMetalNativeHandles nativeHandlesStruct;
QRhiDriverInfo driverInfoStruct;
quint32 osMajor = 0;
quint32 osMinor = 0;
struct {
int maxTextureSize = 4096;
bool baseVertexAndInstance = true;
QVector<int> supportedSampleCounts;
bool isAppleGPU = false;
int maxThreadGroupSize = 512;
} caps;
QRhiMetalData *d = nullptr;
};
QT_END_NAMESPACE
#endif

View File

@ -1,7 +1,7 @@
// Copyright (C) 2019 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qrhinull_p_p.h"
#include "qrhinull_p.h"
#include <qmath.h>
#include <QPainter>
@ -9,10 +9,13 @@ QT_BEGIN_NAMESPACE
/*!
\class QRhiNullInitParams
\internal
\inmodule QtGui
\since 6.6
\brief Null backend specific initialization parameters.
\note This a RHI API with limited compatibility guarantees, see \l QRhi
for details.
A Null QRhi needs no special parameters for initialization.
\badcode
@ -28,9 +31,12 @@ QT_BEGIN_NAMESPACE
/*!
\class QRhiNullNativeHandles
\internal
\inmodule QtGui
\since 6.6
\brief Empty.
\note This a RHI API with limited compatibility guarantees, see \l QRhi
for details.
*/
QRhiNull::QRhiNull(QRhiNullInitParams *params)

View File

@ -1,8 +1,8 @@
// Copyright (C) 2019 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRHINULL_H
#define QRHINULL_H
#ifndef QRHINULL_P_H
#define QRHINULL_P_H
//
// W A R N I N G
@ -15,16 +15,279 @@
// We mean it.
//
#include <private/qrhi_p.h>
#include "qrhi_p.h"
QT_BEGIN_NAMESPACE
struct Q_GUI_EXPORT QRhiNullInitParams : public QRhiInitParams
struct QNullBuffer : public QRhiBuffer
{
QNullBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
~QNullBuffer();
void destroy() override;
bool create() override;
char *beginFullDynamicBufferUpdateForCurrentFrame() override;
char *data = nullptr;
};
struct Q_GUI_EXPORT QRhiNullNativeHandles : public QRhiNativeHandles
struct QNullRenderBuffer : public QRhiRenderBuffer
{
QNullRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags,
QRhiTexture::Format backingFormatHint);
~QNullRenderBuffer();
void destroy() override;
bool create() override;
QRhiTexture::Format backingFormat() const override;
bool valid = false;
uint generation = 0;
};
struct QNullTexture : public QRhiTexture
{
QNullTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
int arraySize, int sampleCount, Flags flags);
~QNullTexture();
void destroy() override;
bool create() override;
bool createFrom(NativeTexture src) override;
bool valid = false;
QVarLengthArray<std::array<QImage, QRhi::MAX_MIP_LEVELS>, 6> image;
uint generation = 0;
};
struct QNullSampler : public QRhiSampler
{
QNullSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
AddressMode u, AddressMode v, AddressMode w);
~QNullSampler();
void destroy() override;
bool create() override;
};
struct QNullRenderPassDescriptor : public QRhiRenderPassDescriptor
{
QNullRenderPassDescriptor(QRhiImplementation *rhi);
~QNullRenderPassDescriptor();
void destroy() override;
bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
QVector<quint32> serializedFormat() const override;
};
struct QNullRenderTargetData
{
QNullRenderTargetData(QRhiImplementation *) { }
QNullRenderPassDescriptor *rp = nullptr;
QSize pixelSize;
float dpr = 1;
QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
};
struct QNullSwapChainRenderTarget : public QRhiSwapChainRenderTarget
{
QNullSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
~QNullSwapChainRenderTarget();
void destroy() override;
QSize pixelSize() const override;
float devicePixelRatio() const override;
int sampleCount() const override;
QNullRenderTargetData d;
};
struct QNullTextureRenderTarget : public QRhiTextureRenderTarget
{
QNullTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
~QNullTextureRenderTarget();
void destroy() override;
QSize pixelSize() const override;
float devicePixelRatio() const override;
int sampleCount() const override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
bool create() override;
QNullRenderTargetData d;
};
struct QNullShaderResourceBindings : public QRhiShaderResourceBindings
{
QNullShaderResourceBindings(QRhiImplementation *rhi);
~QNullShaderResourceBindings();
void destroy() override;
bool create() override;
void updateResources(UpdateFlags flags) override;
};
struct QNullGraphicsPipeline : public QRhiGraphicsPipeline
{
QNullGraphicsPipeline(QRhiImplementation *rhi);
~QNullGraphicsPipeline();
void destroy() override;
bool create() override;
};
struct QNullComputePipeline : public QRhiComputePipeline
{
QNullComputePipeline(QRhiImplementation *rhi);
~QNullComputePipeline();
void destroy() override;
bool create() override;
};
struct QNullCommandBuffer : public QRhiCommandBuffer
{
QNullCommandBuffer(QRhiImplementation *rhi);
~QNullCommandBuffer();
void destroy() override;
};
struct QNullSwapChain : public QRhiSwapChain
{
QNullSwapChain(QRhiImplementation *rhi);
~QNullSwapChain();
void destroy() override;
QRhiCommandBuffer *currentFrameCommandBuffer() override;
QRhiRenderTarget *currentFrameRenderTarget() override;
QSize surfacePixelSize() override;
bool isFormatSupported(Format f) override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
bool createOrResize() override;
QWindow *window = nullptr;
QNullSwapChainRenderTarget rt;
QNullCommandBuffer cb;
int frameCount = 0;
};
class QRhiNull : public QRhiImplementation
{
public:
QRhiNull(QRhiNullInitParams *params);
bool create(QRhi::Flags flags) override;
void destroy() override;
QRhiGraphicsPipeline *createGraphicsPipeline() override;
QRhiComputePipeline *createComputePipeline() override;
QRhiShaderResourceBindings *createShaderResourceBindings() override;
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
QRhiBuffer::UsageFlags usage,
quint32 size) override;
QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
int sampleCount,
QRhiRenderBuffer::Flags flags,
QRhiTexture::Format backingFormatHint) override;
QRhiTexture *createTexture(QRhiTexture::Format format,
const QSize &pixelSize,
int depth,
int arraySize,
int sampleCount,
QRhiTexture::Flags flags) override;
QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
QRhiSampler:: AddressMode u,
QRhiSampler::AddressMode v,
QRhiSampler::AddressMode w) override;
QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
QRhiTextureRenderTarget::Flags flags) override;
QRhiSwapChain *createSwapChain() override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult finish() override;
void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void beginPass(QRhiCommandBuffer *cb,
QRhiRenderTarget *rt,
const QColor &colorClearValue,
const QRhiDepthStencilClearValue &depthStencilClearValue,
QRhiResourceUpdateBatch *resourceUpdates,
QRhiCommandBuffer::BeginPassFlags flags) override;
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setGraphicsPipeline(QRhiCommandBuffer *cb,
QRhiGraphicsPipeline *ps) override;
void setShaderResources(QRhiCommandBuffer *cb,
QRhiShaderResourceBindings *srb,
int dynamicOffsetCount,
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
void setVertexInput(QRhiCommandBuffer *cb,
int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
QRhiBuffer *indexBuf, quint32 indexOffset,
QRhiCommandBuffer::IndexFormat indexFormat) override;
void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
quint32 instanceCount, quint32 firstIndex,
qint32 vertexOffset, quint32 firstInstance) override;
void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
void debugMarkEnd(QRhiCommandBuffer *cb) override;
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
void beginComputePass(QRhiCommandBuffer *cb,
QRhiResourceUpdateBatch *resourceUpdates,
QRhiCommandBuffer::BeginPassFlags flags) override;
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
void beginExternal(QRhiCommandBuffer *cb) override;
void endExternal(QRhiCommandBuffer *cb) override;
double lastCompletedGpuTime(QRhiCommandBuffer *cb) override;
QList<int> supportedSampleCounts() const override;
int ubufAlignment() const override;
bool isYUpInFramebuffer() const override;
bool isYUpInNDC() const override;
bool isClipDepthZeroToOne() const override;
QMatrix4x4 clipSpaceCorrMatrix() const override;
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
bool isFeatureSupported(QRhi::Feature feature) const override;
int resourceLimit(QRhi::ResourceLimit limit) const override;
const QRhiNativeHandles *nativeHandles() override;
QRhiDriverInfo driverInfo() const override;
QRhiStats statistics() override;
bool makeThreadLocalNativeContextCurrent() override;
void releaseCachedResources() override;
bool isDeviceLost() const override;
QByteArray pipelineCacheData() override;
void setPipelineCacheData(const QByteArray &data) override;
void simulateTextureUpload(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
void simulateTextureCopy(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
void simulateTextureGenMips(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
QRhiNullNativeHandles nativeHandlesStruct;
QRhiSwapChain *currentSwapChain = nullptr;
QNullCommandBuffer offscreenCommandBuffer;
};
QT_END_NAMESPACE

View File

@ -1,296 +0,0 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRHINULL_P_H
#define QRHINULL_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qrhinull_p.h"
#include "qrhi_p_p.h"
QT_BEGIN_NAMESPACE
struct QNullBuffer : public QRhiBuffer
{
QNullBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
~QNullBuffer();
void destroy() override;
bool create() override;
char *beginFullDynamicBufferUpdateForCurrentFrame() override;
char *data = nullptr;
};
struct QNullRenderBuffer : public QRhiRenderBuffer
{
QNullRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags,
QRhiTexture::Format backingFormatHint);
~QNullRenderBuffer();
void destroy() override;
bool create() override;
QRhiTexture::Format backingFormat() const override;
bool valid = false;
uint generation = 0;
};
struct QNullTexture : public QRhiTexture
{
QNullTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
int arraySize, int sampleCount, Flags flags);
~QNullTexture();
void destroy() override;
bool create() override;
bool createFrom(NativeTexture src) override;
bool valid = false;
QVarLengthArray<std::array<QImage, QRhi::MAX_MIP_LEVELS>, 6> image;
uint generation = 0;
};
struct QNullSampler : public QRhiSampler
{
QNullSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
AddressMode u, AddressMode v, AddressMode w);
~QNullSampler();
void destroy() override;
bool create() override;
};
struct QNullRenderPassDescriptor : public QRhiRenderPassDescriptor
{
QNullRenderPassDescriptor(QRhiImplementation *rhi);
~QNullRenderPassDescriptor();
void destroy() override;
bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
QVector<quint32> serializedFormat() const override;
};
struct QNullRenderTargetData
{
QNullRenderTargetData(QRhiImplementation *) { }
QNullRenderPassDescriptor *rp = nullptr;
QSize pixelSize;
float dpr = 1;
QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
};
struct QNullSwapChainRenderTarget : public QRhiSwapChainRenderTarget
{
QNullSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
~QNullSwapChainRenderTarget();
void destroy() override;
QSize pixelSize() const override;
float devicePixelRatio() const override;
int sampleCount() const override;
QNullRenderTargetData d;
};
struct QNullTextureRenderTarget : public QRhiTextureRenderTarget
{
QNullTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
~QNullTextureRenderTarget();
void destroy() override;
QSize pixelSize() const override;
float devicePixelRatio() const override;
int sampleCount() const override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
bool create() override;
QNullRenderTargetData d;
};
struct QNullShaderResourceBindings : public QRhiShaderResourceBindings
{
QNullShaderResourceBindings(QRhiImplementation *rhi);
~QNullShaderResourceBindings();
void destroy() override;
bool create() override;
void updateResources(UpdateFlags flags) override;
};
struct QNullGraphicsPipeline : public QRhiGraphicsPipeline
{
QNullGraphicsPipeline(QRhiImplementation *rhi);
~QNullGraphicsPipeline();
void destroy() override;
bool create() override;
};
struct QNullComputePipeline : public QRhiComputePipeline
{
QNullComputePipeline(QRhiImplementation *rhi);
~QNullComputePipeline();
void destroy() override;
bool create() override;
};
struct QNullCommandBuffer : public QRhiCommandBuffer
{
QNullCommandBuffer(QRhiImplementation *rhi);
~QNullCommandBuffer();
void destroy() override;
};
struct QNullSwapChain : public QRhiSwapChain
{
QNullSwapChain(QRhiImplementation *rhi);
~QNullSwapChain();
void destroy() override;
QRhiCommandBuffer *currentFrameCommandBuffer() override;
QRhiRenderTarget *currentFrameRenderTarget() override;
QSize surfacePixelSize() override;
bool isFormatSupported(Format f) override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
bool createOrResize() override;
QWindow *window = nullptr;
QNullSwapChainRenderTarget rt;
QNullCommandBuffer cb;
int frameCount = 0;
};
class QRhiNull : public QRhiImplementation
{
public:
QRhiNull(QRhiNullInitParams *params);
bool create(QRhi::Flags flags) override;
void destroy() override;
QRhiGraphicsPipeline *createGraphicsPipeline() override;
QRhiComputePipeline *createComputePipeline() override;
QRhiShaderResourceBindings *createShaderResourceBindings() override;
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
QRhiBuffer::UsageFlags usage,
quint32 size) override;
QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
const QSize &pixelSize,
int sampleCount,
QRhiRenderBuffer::Flags flags,
QRhiTexture::Format backingFormatHint) override;
QRhiTexture *createTexture(QRhiTexture::Format format,
const QSize &pixelSize,
int depth,
int arraySize,
int sampleCount,
QRhiTexture::Flags flags) override;
QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
QRhiSampler:: AddressMode u,
QRhiSampler::AddressMode v,
QRhiSampler::AddressMode w) override;
QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
QRhiTextureRenderTarget::Flags flags) override;
QRhiSwapChain *createSwapChain() override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult finish() override;
void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void beginPass(QRhiCommandBuffer *cb,
QRhiRenderTarget *rt,
const QColor &colorClearValue,
const QRhiDepthStencilClearValue &depthStencilClearValue,
QRhiResourceUpdateBatch *resourceUpdates,
QRhiCommandBuffer::BeginPassFlags flags) override;
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setGraphicsPipeline(QRhiCommandBuffer *cb,
QRhiGraphicsPipeline *ps) override;
void setShaderResources(QRhiCommandBuffer *cb,
QRhiShaderResourceBindings *srb,
int dynamicOffsetCount,
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
void setVertexInput(QRhiCommandBuffer *cb,
int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
QRhiBuffer *indexBuf, quint32 indexOffset,
QRhiCommandBuffer::IndexFormat indexFormat) override;
void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
quint32 instanceCount, quint32 firstIndex,
qint32 vertexOffset, quint32 firstInstance) override;
void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
void debugMarkEnd(QRhiCommandBuffer *cb) override;
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
void beginComputePass(QRhiCommandBuffer *cb,
QRhiResourceUpdateBatch *resourceUpdates,
QRhiCommandBuffer::BeginPassFlags flags) override;
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
void beginExternal(QRhiCommandBuffer *cb) override;
void endExternal(QRhiCommandBuffer *cb) override;
double lastCompletedGpuTime(QRhiCommandBuffer *cb) override;
QList<int> supportedSampleCounts() const override;
int ubufAlignment() const override;
bool isYUpInFramebuffer() const override;
bool isYUpInNDC() const override;
bool isClipDepthZeroToOne() const override;
QMatrix4x4 clipSpaceCorrMatrix() const override;
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
bool isFeatureSupported(QRhi::Feature feature) const override;
int resourceLimit(QRhi::ResourceLimit limit) const override;
const QRhiNativeHandles *nativeHandles() override;
QRhiDriverInfo driverInfo() const override;
QRhiStats statistics() override;
bool makeThreadLocalNativeContextCurrent() override;
void releaseCachedResources() override;
bool isDeviceLost() const override;
QByteArray pipelineCacheData() override;
void setPipelineCacheData(const QByteArray &data) override;
void simulateTextureUpload(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
void simulateTextureCopy(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
void simulateTextureGenMips(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
QRhiNullNativeHandles nativeHandlesStruct;
QRhiSwapChain *currentSwapChain = nullptr;
QNullCommandBuffer offscreenCommandBuffer;
};
QT_END_NAMESPACE
#endif

View File

@ -1,7 +1,7 @@
// Copyright (C) 2019 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qrhivulkan_p_p.h"
#include "qrhivulkan_p.h"
#include "qrhivulkanext_p.h"
#include <qpa/qplatformvulkaninstance.h>
@ -60,10 +60,13 @@ QT_BEGIN_NAMESPACE
/*!
\class QRhiVulkanInitParams
\internal
\inmodule QtGui
\since 6.6
\brief Vulkan specific initialization parameters.
\note This a RHI API with limited compatibility guarantees, see \l QRhi
for details.
A Vulkan-based QRhi needs at minimum a valid QVulkanInstance. It is up to
the user to ensure this is available and initialized. This is typically
done in main() similarly to the following:
@ -165,19 +168,81 @@ QT_BEGIN_NAMESPACE
available.
*/
/*!
\variable QRhiVulkanInitParams::inst
The QVulkanInstance that has already been successfully
\l{QVulkanInstance::create()}{created}, required.
*/
/*!
\variable QRhiVulkanInitParams::window
Optional, but recommended when targeting a QWindow.
*/
/*!
\variable QRhiVulkanInitParams::deviceExtensions
Optional, empty by default. The list of Vulkan device extensions to enable.
Unsupported extensions are ignored gracefully.
*/
/*!
\class QRhiVulkanNativeHandles
\internal
\inmodule QtGui
\since 6.6
\brief Collects device, queue, and other Vulkan objects that are used by the QRhi.
\note Ownership of the Vulkan objects is never transferred.
\note This a RHI API with limited compatibility guarantees, see \l QRhi
for details.
*/
/*!
\variable QRhiVulkanNativeHandles::physDev
When different from \nullptr, specifies the Vulkan physical device to use.
*/
/*!
\variable QRhiVulkanNativeHandles::dev
When wanting to import not just a physical device, but also use an already
existing VkDevice, set this and the graphics queue index and family index.
*/
/*!
\variable QRhiVulkanNativeHandles::gfxQueueFamilyIdx
Graphics queue family index.
*/
/*!
\variable QRhiVulkanNativeHandles::gfxQueueIdx
Graphics queue index.
*/
/*!
\variable QRhiVulkanNativeHandles::gfxQueue
Output only, not used by QRhi::create(), only set by the
QRhi::nativeHandles() accessor. The graphics VkQueue used by the QRhi.
*/
/*!
\variable QRhiVulkanNativeHandles::vmemAllocator
Relevant only when importing an existing memory allocator object,
leave it set to \nullptr otherwise.
*/
/*!
\class QRhiVulkanCommandBufferNativeHandles
\internal
\inmodule QtGui
\since 6.6
\brief Holds the Vulkan command buffer object that is backing a QRhiCommandBuffer.
\note The Vulkan command buffer object is only guaranteed to be valid, and
@ -185,13 +250,31 @@ QT_BEGIN_NAMESPACE
\l{QRhi::beginFrame()}{beginFrame()} - \l{QRhi::endFrame()}{endFrame()} or
\l{QRhi::beginOffscreenFrame()}{beginOffscreenFrame()} -
\l{QRhi::endOffscreenFrame()}{endOffscreenFrame()} pair.
\note This a RHI API with limited compatibility guarantees, see \l QRhi
for details.
*/
/*!
\variable QRhiVulkanCommandBufferNativeHandles::commandBuffer
The VkCommandBuffer object.
*/
/*!
\class QRhiVulkanRenderPassNativeHandles
\internal
\inmodule QtGui
\since 6.6
\brief Holds the Vulkan render pass object backing a QRhiRenderPassDescriptor.
\note This a RHI API with limited compatibility guarantees, see \l QRhi
for details.
*/
/*!
\variable QRhiVulkanRenderPassNativeHandles::renderPass
The VkRenderPass object.
*/
template <class Int>
@ -222,6 +305,13 @@ static inline VmaAllocator toVmaAllocator(QVkAllocator a)
return reinterpret_cast<VmaAllocator>(a);
}
/*!
\return the list of instance extensions that are expected to be enabled on
the QVulkanInstance that is used for the Vulkan-based QRhi.
The returned list can be safely passed to QVulkanInstance::setExtensions()
as-is, because unsupported extensions are filtered out automatically.
*/
QByteArrayList QRhiVulkanInitParams::preferredInstanceExtensions()
{
return {
@ -229,6 +319,11 @@ QByteArrayList QRhiVulkanInitParams::preferredInstanceExtensions()
};
}
/*!
\return the list of device extensions that are expected to be enabled on the
\c VkDevice when creating a Vulkan-based QRhi with an externally created
\c VkDevice object.
*/
QByteArrayList QRhiVulkanInitParams::preferredExtensionsForImportedDevice()
{
return {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
// Copyright (C) 2019 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qshader_p_p.h"
#include "qshader_p.h"
#include <QDataStream>
#include <QBuffer>
@ -9,8 +9,9 @@ QT_BEGIN_NAMESPACE
/*!
\class QShader
\internal
\ingroup painting-3D
\inmodule QtGui
\since 6.6
\brief Contains multiple versions of a shader translated to multiple shading languages,
together with reflection metadata.
@ -21,6 +22,16 @@ QT_BEGIN_NAMESPACE
as, Vulkan, Metal, Direct3D, and OpenGL, take QShader as their input
whenever a shader needs to be specified.
\warning The QRhi family of classes in the Qt Gui module, including QShader
and QShaderDescription, offer limited compatibility guarantees. There are
no source or binary compatibility guarantees for these classes, meaning the
API is only guaranteed to work with the Qt version the application was
developed against. Source incompatible changes are however aimed to be kept
at a minimum and will only be made in minor releases (6.7, 6.8, and so on).
To use these classes in an application, link to
\c{Qt::GuiPrivate} (if using CMake), and include the headers with the \c
rhi prefix, for example \c{#include <rhi/qshader.h>}.
A QShader instance is empty and thus invalid by default. To get a useful
instance, the two typical methods are:
@ -68,8 +79,9 @@ QT_BEGIN_NAMESPACE
can be returned or passed by value. Detach happens implicitly when calling
a setter.
For reference, QRhi expects that a QShader suitable for all its
backends contains at least the following:
For reference, a typical, portable QRhi expects that a QShader suitable for
all its backends contains at least the following. (this excludes support
for core profile OpenGL contexts, add GLSL 150 or newer for that)
\list
@ -77,11 +89,11 @@ QT_BEGIN_NAMESPACE
\li GLSL/ES 100 source code suitable for OpenGL ES 2.0 or newer
\li GLSL 120 source code suitable for OpenGL 2.1
\li GLSL 120 source code suitable for OpenGL 2.1 or newer
\li HLSL Shader Model 5.0 source code or the corresponding DXBC bytecode suitable for Direct3D 11
\li HLSL Shader Model 5.0 source code or the corresponding DXBC bytecode suitable for Direct3D 11/12
\li Metal Shading Language 1.2 source code or the corresponding bytecode suitable for Metal
\li Metal Shading Language 1.2 source code or the corresponding bytecode suitable for Metal 1.2 or newer
\endlist
@ -102,8 +114,8 @@ QT_BEGIN_NAMESPACE
/*!
\class QShaderVersion
\internal
\inmodule QtGui
\since 6.6
\brief Specifies the shading language version.
@ -128,6 +140,9 @@ QT_BEGIN_NAMESPACE
A default constructed QShaderVersion contains a version of 100 and no
flags set.
\note This a RHI API with limited compatibility guarantees, see \l QShader
for details.
*/
/*!
@ -140,13 +155,16 @@ QT_BEGIN_NAMESPACE
/*!
\class QShaderKey
\internal
\inmodule QtGui
\since 6.6
\brief Specifies the shading language, the version with flags, and the variant.
A default constructed QShaderKey has source set to SpirvShader and
sourceVersion set to 100. sourceVariant defaults to StandardShader.
\note This a RHI API with limited compatibility guarantees, see \l QShader
for details.
*/
/*!
@ -197,13 +215,16 @@ QT_BEGIN_NAMESPACE
/*!
\class QShaderCode
\internal
\inmodule QtGui
\since 6.6
\brief Contains source or binary code for a shader and additional metadata.
When shader() is empty after retrieving a QShaderCode instance from
QShader, it indicates no shader code was found for the requested key.
\note This a RHI API with limited compatibility guarantees, see \l QShader
for details.
*/
/*!
@ -226,7 +247,7 @@ void QShader::detach()
}
/*!
\internal
Constructs a copy of \a other.
*/
QShader::QShader(const QShader &other)
: d(other.d)
@ -236,7 +257,7 @@ QShader::QShader(const QShader &other)
}
/*!
\internal
Assigns \a other to this object.
*/
QShader &QShader::operator=(const QShader &other)
{
@ -577,16 +598,79 @@ QShader QShader::fromSerialized(const QByteArray &data)
return bs;
}
/*!
\fn QShaderVersion::QShaderVersion() = default
*/
/*!
Constructs a new QShaderVersion with version \a v and flags \a f.
*/
QShaderVersion::QShaderVersion(int v, Flags f)
: m_version(v), m_flags(f)
{
}
/*!
\fn int QShaderVersion::version() const
\return the version.
*/
/*!
\fn void QShaderVersion::setVersion(int v)
Sets the shading language version to \a v.
*/
/*!
\fn QShaderVersion::Flags QShaderVersion::flags() const
\return the flags.
*/
/*!
\fn void QShaderVersion::setFlags(Flags f)
Sets the flags \a f.
*/
/*!
\fn QShaderCode::QShaderCode() = default
*/
/*!
Constructs a new QShaderCode with the specified shader source \a code and
\a entry point name.
*/
QShaderCode::QShaderCode(const QByteArray &code, const QByteArray &entry)
: m_shader(code), m_entryPoint(entry)
{
}
/*!
\fn QByteArray QShaderCode::shader() const
\return the shader source or bytecode.
*/
/*!
\fn void QShaderCode::setShader(const QByteArray &code)
Sets the shader source or byte \a code.
*/
/*!
\fn QByteArray QShaderCode::entryPoint() const
\return the entry point name.
*/
/*!
\fn void QShaderCode::setEntryPoint(const QByteArray &entry)
Sets the \a entry point name.
*/
/*!
\fn QShaderKey::QShaderKey() = default
*/
/*!
Constructs a new QShaderKey with shader type \a s, version \a sver, and
variant \a svar.
*/
QShaderKey::QShaderKey(QShader::Source s,
const QShaderVersion &sver,
QShader::Variant svar)
@ -596,6 +680,36 @@ QShaderKey::QShaderKey(QShader::Source s,
{
}
/*!
\fn QShader::Source QShaderKey::source() const
\return the shader type.
*/
/*!
\fn void QShaderKey::setSource(QShader::Source s)
Sets the shader type \a s.
*/
/*!
\fn QShaderVersion QShaderKey::sourceVersion() const
\return the shading language version.
*/
/*!
\fn void QShaderKey::setSourceVersion(const QShaderVersion &sver)
Sets the shading language version \a sver.
*/
/*!
\fn QShader::Variant QShaderKey::sourceVariant() const
\return the type of the variant to use.
*/
/*!
\fn void QShaderKey::setSourceVariant(QShader::Variant svar)
Sets the type of variant to use to \a svar.
*/
/*!
Returns \c true if the two QShader objects \a lhs and \a rhs are equal,
meaning they are for the same stage with matching sets of shader source or
@ -614,10 +728,9 @@ bool operator==(const QShader &lhs, const QShader &rhs) noexcept
}
/*!
\internal
\fn bool operator!=(const QShader &lhs, const QShader &rhs)
Returns \c false if the values in the two QShader objects \a a and \a b
Returns \c false if the values in the two QShader objects \a lhs and \a rhs
are equal; otherwise returns \c true.
\relates QShader
@ -660,6 +773,8 @@ size_t qHash(const QShaderVersion &s, size_t seed) noexcept
#endif
/*!
\return true if \a lhs is smaller than \a rhs.
Establishes a sorting order between the two QShaderVersion \a lhs and \a rhs.
\relates QShaderVersion
@ -676,11 +791,10 @@ bool operator<(const QShaderVersion &lhs, const QShaderVersion &rhs) noexcept
}
/*!
\internal
\fn bool operator!=(const QShaderVersion &lhs, const QShaderVersion &rhs)
Returns \c false if the values in the two QShaderVersion objects \a a
and \a b are equal; otherwise returns \c true.
Returns \c false if the values in the two QShaderVersion objects \a lhs
and \a rhs are equal; otherwise returns \c true.
\relates QShaderVersion
*/
@ -697,6 +811,8 @@ bool operator==(const QShaderKey &lhs, const QShaderKey &rhs) noexcept
}
/*!
\return true if \a lhs is smaller than \a rhs.
Establishes a sorting order between the two keys \a lhs and \a rhs.
\relates QShaderKey
@ -719,11 +835,10 @@ bool operator<(const QShaderKey &lhs, const QShaderKey &rhs) noexcept
}
/*!
\internal
\fn bool operator!=(const QShaderKey &lhs, const QShaderKey &rhs)
Returns \c false if the values in the two QShaderKey objects \a a
and \a b are equal; otherwise returns \c true.
Returns \c false if the values in the two QShaderKey objects \a lhs
and \a rhs are equal; otherwise returns \c true.
\relates QShaderKey
*/
@ -753,11 +868,10 @@ bool operator==(const QShaderCode &lhs, const QShaderCode &rhs) noexcept
}
/*!
\internal
\fn bool operator!=(const QShaderCode &lhs, const QShaderCode &rhs)
Returns \c false if the values in the two QShaderCode objects \a a
and \a b are equal; otherwise returns \c true.
Returns \c false if the values in the two QShaderCode objects \a lhs
and \a rhs are equal; otherwise returns \c true.
\relates QShaderCode
*/
@ -895,6 +1009,7 @@ void QShader::removeResourceBindingMap(const QShaderKey &key)
/*!
\struct QShader::SeparateToCombinedImageSamplerMapping
\brief Mapping metadata for sampler uniforms.
Describes a mapping from a traditional combined image sampler uniform to
binding points for a separate texture and sampler.
@ -904,6 +1019,21 @@ void QShader::removeResourceBindingMap(const QShaderKey &key)
contains a \c sampler2D (or sampler3D, etc.) uniform with the name of
\c{_54} which corresponds to two separate resource bindings (\c 1 and \c 2)
in the original shader.
\note This a RHI API with limited compatibility guarantees, see \l QShader
for details.
*/
/*!
\variable QShader::SeparateToCombinedImageSamplerMapping::combinedSamplerName
*/
/*!
\variable QShader::SeparateToCombinedImageSamplerMapping::textureBinding
*/
/*!
\variable QShader::SeparateToCombinedImageSamplerMapping::samplerBinding
*/
/*!
@ -953,6 +1083,7 @@ void QShader::removeSeparateToCombinedImageSamplerMappingList(const QShaderKey &
/*!
\struct QShader::NativeShaderInfo
\brief Additional metadata about the native shader code.
Describes information about the native shader code, if applicable. This
becomes relevant with certain shader languages for certain shader stages,
@ -969,6 +1100,17 @@ void QShader::removeSeparateToCombinedImageSamplerMappingList(const QShaderKey &
not be present at all if per-patch output variables were not used. The fact
that the shader code relies on such a buffer present can be indicated by
the data in this struct.
\note This a RHI API with limited compatibility guarantees, see \l QShader
for details.
*/
/*!
\variable QShader::NativeShaderInfo::flags
*/
/*!
\variable QShader::NativeShaderInfo::extraBufferBindings
*/
/*!

237
src/gui/rhi/qshader.h Normal file
View File

@ -0,0 +1,237 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSHADER_H
#define QSHADER_H
//
// W A R N I N G
// -------------
//
// This file is part of the RHI API, with limited compatibility guarantees.
// Usage of this API may make your code source and binary incompatible with
// future versions of Qt.
//
#include <QtGui/qtguiglobal.h>
#include <QtCore/qhash.h>
#include <QtCore/qmap.h>
#include <rhi/qshaderdescription.h>
QT_BEGIN_NAMESPACE
struct QShaderPrivate;
class QShaderKey;
#ifdef Q_OS_INTEGRITY
class QShaderVersion;
size_t qHash(const QShaderVersion &, size_t = 0) noexcept;
#endif
class Q_GUI_EXPORT QShaderVersion
{
public:
enum Flag {
GlslEs = 0x01
};
Q_DECLARE_FLAGS(Flags, Flag)
QShaderVersion() = default;
QShaderVersion(int v, Flags f = Flags());
int version() const { return m_version; }
void setVersion(int v) { m_version = v; }
Flags flags() const { return m_flags; }
void setFlags(Flags f) { m_flags = f; }
private:
int m_version = 100;
Flags m_flags;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderVersion::Flags)
Q_DECLARE_TYPEINFO(QShaderVersion, Q_RELOCATABLE_TYPE);
class QShaderCode;
Q_GUI_EXPORT size_t qHash(const QShaderCode &, size_t = 0) noexcept;
class Q_GUI_EXPORT QShaderCode
{
public:
QShaderCode() = default;
QShaderCode(const QByteArray &code, const QByteArray &entry = QByteArray());
QByteArray shader() const { return m_shader; }
void setShader(const QByteArray &code) { m_shader = code; }
QByteArray entryPoint() const { return m_entryPoint; }
void setEntryPoint(const QByteArray &entry) { m_entryPoint = entry; }
private:
friend Q_GUI_EXPORT size_t qHash(const QShaderCode &, size_t) noexcept;
QByteArray m_shader;
QByteArray m_entryPoint;
};
Q_DECLARE_TYPEINFO(QShaderCode, Q_RELOCATABLE_TYPE);
class Q_GUI_EXPORT QShader
{
public:
enum Stage {
VertexStage = 0,
TessellationControlStage,
TessellationEvaluationStage,
GeometryStage,
FragmentStage,
ComputeStage
};
enum Source {
SpirvShader = 0,
GlslShader,
HlslShader,
DxbcShader, // fxc
MslShader,
DxilShader, // dxc
MetalLibShader, // xcrun metal + xcrun metallib
WgslShader
};
enum Variant {
StandardShader = 0,
BatchableVertexShader,
UInt16IndexedVertexAsComputeShader,
UInt32IndexedVertexAsComputeShader,
NonIndexedVertexAsComputeShader
};
enum class SerializedFormatVersion {
Latest = 0,
Qt_6_5,
Qt_6_4
};
QShader();
QShader(const QShader &other);
QShader &operator=(const QShader &other);
~QShader();
void detach();
bool isValid() const;
Stage stage() const;
void setStage(Stage stage);
QShaderDescription description() const;
void setDescription(const QShaderDescription &desc);
QList<QShaderKey> availableShaders() const;
QShaderCode shader(const QShaderKey &key) const;
void setShader(const QShaderKey &key, const QShaderCode &shader);
void removeShader(const QShaderKey &key);
QByteArray serialized(SerializedFormatVersion version = SerializedFormatVersion::Latest) const;
static QShader fromSerialized(const QByteArray &data);
using NativeResourceBindingMap = QMap<int, QPair<int, int> >; // binding -> native_binding[, native_binding]
NativeResourceBindingMap nativeResourceBindingMap(const QShaderKey &key) const;
void setResourceBindingMap(const QShaderKey &key, const NativeResourceBindingMap &map);
void removeResourceBindingMap(const QShaderKey &key);
struct SeparateToCombinedImageSamplerMapping {
QByteArray combinedSamplerName;
int textureBinding;
int samplerBinding;
};
using SeparateToCombinedImageSamplerMappingList = QList<SeparateToCombinedImageSamplerMapping>;
SeparateToCombinedImageSamplerMappingList separateToCombinedImageSamplerMappingList(const QShaderKey &key) const;
void setSeparateToCombinedImageSamplerMappingList(const QShaderKey &key,
const SeparateToCombinedImageSamplerMappingList &list);
void removeSeparateToCombinedImageSamplerMappingList(const QShaderKey &key);
struct NativeShaderInfo {
int flags = 0;
QMap<int, int> extraBufferBindings;
};
NativeShaderInfo nativeShaderInfo(const QShaderKey &key) const;
void setNativeShaderInfo(const QShaderKey &key, const NativeShaderInfo &info);
void removeNativeShaderInfo(const QShaderKey &key);
private:
QShaderPrivate *d;
friend struct QShaderPrivate;
friend Q_GUI_EXPORT bool operator==(const QShader &, const QShader &) noexcept;
friend Q_GUI_EXPORT size_t qHash(const QShader &, size_t) noexcept;
#ifndef QT_NO_DEBUG_STREAM
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QShader &);
#endif
};
class Q_GUI_EXPORT QShaderKey
{
public:
QShaderKey() = default;
QShaderKey(QShader::Source s,
const QShaderVersion &sver,
QShader::Variant svar = QShader::StandardShader);
QShader::Source source() const { return m_source; }
void setSource(QShader::Source s) { m_source = s; }
QShaderVersion sourceVersion() const { return m_sourceVersion; }
void setSourceVersion(const QShaderVersion &sver) { m_sourceVersion = sver; }
QShader::Variant sourceVariant() const { return m_sourceVariant; }
void setSourceVariant(QShader::Variant svar) { m_sourceVariant = svar; }
private:
QShader::Source m_source = QShader::SpirvShader;
QShaderVersion m_sourceVersion;
QShader::Variant m_sourceVariant = QShader::StandardShader;
};
Q_DECLARE_TYPEINFO(QShaderKey, Q_RELOCATABLE_TYPE);
Q_GUI_EXPORT bool operator==(const QShader &lhs, const QShader &rhs) noexcept;
Q_GUI_EXPORT size_t qHash(const QShader &s, size_t seed = 0) noexcept;
inline bool operator!=(const QShader &lhs, const QShader &rhs) noexcept
{
return !(lhs == rhs);
}
Q_GUI_EXPORT bool operator==(const QShaderVersion &lhs, const QShaderVersion &rhs) noexcept;
Q_GUI_EXPORT bool operator<(const QShaderVersion &lhs, const QShaderVersion &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderKey &lhs, const QShaderKey &rhs) noexcept;
Q_GUI_EXPORT bool operator<(const QShaderKey &lhs, const QShaderKey &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderCode &lhs, const QShaderCode &rhs) noexcept;
inline bool operator!=(const QShaderVersion &lhs, const QShaderVersion &rhs) noexcept
{
return !(lhs == rhs);
}
inline bool operator!=(const QShaderKey &lhs, const QShaderKey &rhs) noexcept
{
return !(lhs == rhs);
}
inline bool operator!=(const QShaderCode &lhs, const QShaderCode &rhs) noexcept
{
return !(lhs == rhs);
}
Q_GUI_EXPORT size_t qHash(const QShaderKey &k, size_t seed = 0) noexcept;
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShader &);
Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QShaderKey &k);
Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QShaderVersion &v);
#endif
QT_END_NAMESPACE
#endif

View File

@ -1,4 +1,4 @@
// Copyright (C) 2019 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSHADER_P_H
@ -15,224 +15,75 @@
// We mean it.
//
#include <QtGui/qtguiglobal.h>
#include <QtCore/qhash.h>
#include <QtCore/qmap.h>
#include <private/qshaderdescription_p.h>
#include <rhi/qshader.h>
#include <QtCore/QAtomicInt>
#include <QtCore/QMap>
#include <QtCore/QDebug>
QT_BEGIN_NAMESPACE
struct QShaderPrivate;
class QShaderKey;
#ifdef Q_OS_INTEGRITY
class QShaderVersion;
size_t qHash(const QShaderVersion &, size_t = 0) noexcept;
#endif
class Q_GUI_EXPORT QShaderVersion
struct Q_GUI_EXPORT QShaderPrivate
{
public:
enum Flag {
GlslEs = 0x01
};
Q_DECLARE_FLAGS(Flags, Flag)
static const int QSB_VERSION = 9;
static const int QSB_VERSION_WITHOUT_INPUT_OUTPUT_INTERFACE_BLOCKS = 8;
static const int QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO = 7;
static const int QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO = 6;
static const int QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS = 5;
static const int QSB_VERSION_WITHOUT_VAR_ARRAYDIMS = 4;
static const int QSB_VERSION_WITH_CBOR = 3;
static const int QSB_VERSION_WITH_BINARY_JSON = 2;
static const int QSB_VERSION_WITHOUT_BINDINGS = 1;
QShaderVersion() = default;
QShaderVersion(int v, Flags f = Flags());
int version() const { return m_version; }
void setVersion(int v) { m_version = v; }
Flags flags() const { return m_flags; }
void setFlags(Flags f) { m_flags = f; }
private:
int m_version = 100;
Flags m_flags;
enum MslNativeShaderInfoExtraBufferBindings {
MslTessVertIndicesBufferBinding = 0,
MslTessVertTescOutputBufferBinding,
MslTessTescTessLevelBufferBinding,
MslTessTescPatchOutputBufferBinding,
MslTessTescParamsBufferBinding,
MslTessTescInputBufferBinding,
MslBufferSizeBufferBinding
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderVersion::Flags)
Q_DECLARE_TYPEINFO(QShaderVersion, Q_RELOCATABLE_TYPE);
class QShaderCode;
Q_GUI_EXPORT size_t qHash(const QShaderCode &, size_t = 0) noexcept;
class Q_GUI_EXPORT QShaderCode
QShaderPrivate()
: ref(1)
{
public:
QShaderCode() = default;
QShaderCode(const QByteArray &code, const QByteArray &entry = QByteArray());
QByteArray shader() const { return m_shader; }
void setShader(const QByteArray &code) { m_shader = code; }
QByteArray entryPoint() const { return m_entryPoint; }
void setEntryPoint(const QByteArray &entry) { m_entryPoint = entry; }
private:
friend Q_GUI_EXPORT size_t qHash(const QShaderCode &, size_t) noexcept;
QByteArray m_shader;
QByteArray m_entryPoint;
};
Q_DECLARE_TYPEINFO(QShaderCode, Q_RELOCATABLE_TYPE);
class Q_GUI_EXPORT QShader
{
public:
enum Stage {
VertexStage = 0,
TessellationControlStage,
TessellationEvaluationStage,
GeometryStage,
FragmentStage,
ComputeStage
};
enum Source {
SpirvShader = 0,
GlslShader,
HlslShader,
DxbcShader, // fxc
MslShader,
DxilShader, // dxc
MetalLibShader, // xcrun metal + xcrun metallib
WgslShader
};
enum Variant {
StandardShader = 0,
BatchableVertexShader,
UInt16IndexedVertexAsComputeShader,
UInt32IndexedVertexAsComputeShader,
NonIndexedVertexAsComputeShader
};
enum class SerializedFormatVersion {
Latest = 0,
Qt_6_5,
Qt_6_4
};
QShader();
QShader(const QShader &other);
QShader &operator=(const QShader &other);
~QShader();
void detach();
bool isValid() const;
Stage stage() const;
void setStage(Stage stage);
QShaderDescription description() const;
void setDescription(const QShaderDescription &desc);
QList<QShaderKey> availableShaders() const;
QShaderCode shader(const QShaderKey &key) const;
void setShader(const QShaderKey &key, const QShaderCode &shader);
void removeShader(const QShaderKey &key);
QByteArray serialized(SerializedFormatVersion version = SerializedFormatVersion::Latest) const;
static QShader fromSerialized(const QByteArray &data);
using NativeResourceBindingMap = QMap<int, QPair<int, int> >; // binding -> native_binding[, native_binding]
NativeResourceBindingMap nativeResourceBindingMap(const QShaderKey &key) const;
void setResourceBindingMap(const QShaderKey &key, const NativeResourceBindingMap &map);
void removeResourceBindingMap(const QShaderKey &key);
struct SeparateToCombinedImageSamplerMapping {
QByteArray combinedSamplerName;
int textureBinding;
int samplerBinding;
};
using SeparateToCombinedImageSamplerMappingList = QList<SeparateToCombinedImageSamplerMapping>;
SeparateToCombinedImageSamplerMappingList separateToCombinedImageSamplerMappingList(const QShaderKey &key) const;
void setSeparateToCombinedImageSamplerMappingList(const QShaderKey &key,
const SeparateToCombinedImageSamplerMappingList &list);
void removeSeparateToCombinedImageSamplerMappingList(const QShaderKey &key);
struct NativeShaderInfo {
int flags = 0;
QMap<int, int> extraBufferBindings;
};
NativeShaderInfo nativeShaderInfo(const QShaderKey &key) const;
void setNativeShaderInfo(const QShaderKey &key, const NativeShaderInfo &info);
void removeNativeShaderInfo(const QShaderKey &key);
private:
QShaderPrivate *d;
friend struct QShaderPrivate;
friend Q_GUI_EXPORT bool operator==(const QShader &, const QShader &) noexcept;
friend Q_GUI_EXPORT size_t qHash(const QShader &, size_t) noexcept;
#ifndef QT_NO_DEBUG_STREAM
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QShader &);
#endif
};
class Q_GUI_EXPORT QShaderKey
{
public:
QShaderKey() = default;
QShaderKey(QShader::Source s,
const QShaderVersion &sver,
QShader::Variant svar = QShader::StandardShader);
QShader::Source source() const { return m_source; }
void setSource(QShader::Source s) { m_source = s; }
QShaderVersion sourceVersion() const { return m_sourceVersion; }
void setSourceVersion(const QShaderVersion &sver) { m_sourceVersion = sver; }
QShader::Variant sourceVariant() const { return m_sourceVariant; }
void setSourceVariant(QShader::Variant svar) { m_sourceVariant = svar; }
private:
QShader::Source m_source = QShader::SpirvShader;
QShaderVersion m_sourceVersion;
QShader::Variant m_sourceVariant = QShader::StandardShader;
};
Q_DECLARE_TYPEINFO(QShaderKey, Q_RELOCATABLE_TYPE);
Q_GUI_EXPORT bool operator==(const QShader &lhs, const QShader &rhs) noexcept;
Q_GUI_EXPORT size_t qHash(const QShader &s, size_t seed = 0) noexcept;
inline bool operator!=(const QShader &lhs, const QShader &rhs) noexcept
{
return !(lhs == rhs);
}
Q_GUI_EXPORT bool operator==(const QShaderVersion &lhs, const QShaderVersion &rhs) noexcept;
Q_GUI_EXPORT bool operator<(const QShaderVersion &lhs, const QShaderVersion &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderKey &lhs, const QShaderKey &rhs) noexcept;
Q_GUI_EXPORT bool operator<(const QShaderKey &lhs, const QShaderKey &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderCode &lhs, const QShaderCode &rhs) noexcept;
inline bool operator!=(const QShaderVersion &lhs, const QShaderVersion &rhs) noexcept
QShaderPrivate(const QShaderPrivate &other)
: ref(1),
qsbVersion(other.qsbVersion),
stage(other.stage),
desc(other.desc),
shaders(other.shaders),
bindings(other.bindings),
combinedImageMap(other.combinedImageMap),
nativeShaderInfoMap(other.nativeShaderInfoMap)
{
return !(lhs == rhs);
}
inline bool operator!=(const QShaderKey &lhs, const QShaderKey &rhs) noexcept
{
return !(lhs == rhs);
static QShaderPrivate *get(QShader *s) { return s->d; }
static const QShaderPrivate *get(const QShader *s) { return s->d; }
static int qtQsbVersion(QShader::SerializedFormatVersion qtVersion) {
switch (qtVersion) {
case QShader::SerializedFormatVersion::Qt_6_4:
return (QShaderPrivate::QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS + 1);
case QShader::SerializedFormatVersion::Qt_6_5:
return (QShaderPrivate::QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO + 1);
default:
return QShaderPrivate::QSB_VERSION;
}
}
inline bool operator!=(const QShaderCode &lhs, const QShaderCode &rhs) noexcept
{
return !(lhs == rhs);
}
Q_GUI_EXPORT size_t qHash(const QShaderKey &k, size_t seed = 0) noexcept;
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShader &);
Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QShaderKey &k);
Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QShaderVersion &v);
#endif
QAtomicInt ref;
int qsbVersion = QSB_VERSION;
QShader::Stage stage = QShader::VertexStage;
QShaderDescription desc;
// QMap not QHash because we need to be able to iterate based on sorted keys
QMap<QShaderKey, QShaderCode> shaders;
QMap<QShaderKey, QShader::NativeResourceBindingMap> bindings;
QMap<QShaderKey, QShader::SeparateToCombinedImageSamplerMappingList> combinedImageMap;
QMap<QShaderKey, QShader::NativeShaderInfo> nativeShaderInfoMap;
};
QT_END_NAMESPACE

View File

@ -1,90 +0,0 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSHADER_P_P_H
#define QSHADER_P_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of a number of Qt sources files. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include "qshader_p.h"
#include <QtCore/QAtomicInt>
#include <QtCore/QMap>
#include <QtCore/QDebug>
QT_BEGIN_NAMESPACE
struct Q_GUI_EXPORT QShaderPrivate
{
static const int QSB_VERSION = 9;
static const int QSB_VERSION_WITHOUT_INPUT_OUTPUT_INTERFACE_BLOCKS = 8;
static const int QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO = 7;
static const int QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO = 6;
static const int QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS = 5;
static const int QSB_VERSION_WITHOUT_VAR_ARRAYDIMS = 4;
static const int QSB_VERSION_WITH_CBOR = 3;
static const int QSB_VERSION_WITH_BINARY_JSON = 2;
static const int QSB_VERSION_WITHOUT_BINDINGS = 1;
enum MslNativeShaderInfoExtraBufferBindings {
MslTessVertIndicesBufferBinding = 0,
MslTessVertTescOutputBufferBinding,
MslTessTescTessLevelBufferBinding,
MslTessTescPatchOutputBufferBinding,
MslTessTescParamsBufferBinding,
MslTessTescInputBufferBinding,
MslBufferSizeBufferBinding
};
QShaderPrivate()
: ref(1)
{
}
QShaderPrivate(const QShaderPrivate &other)
: ref(1),
qsbVersion(other.qsbVersion),
stage(other.stage),
desc(other.desc),
shaders(other.shaders),
bindings(other.bindings),
combinedImageMap(other.combinedImageMap),
nativeShaderInfoMap(other.nativeShaderInfoMap)
{
}
static QShaderPrivate *get(QShader *s) { return s->d; }
static const QShaderPrivate *get(const QShader *s) { return s->d; }
static int qtQsbVersion(QShader::SerializedFormatVersion qtVersion) {
switch (qtVersion) {
case QShader::SerializedFormatVersion::Qt_6_4:
return (QShaderPrivate::QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS + 1);
case QShader::SerializedFormatVersion::Qt_6_5:
return (QShaderPrivate::QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO + 1);
default:
return QShaderPrivate::QSB_VERSION;
}
}
QAtomicInt ref;
int qsbVersion = QSB_VERSION;
QShader::Stage stage = QShader::VertexStage;
QShaderDescription desc;
// QMap not QHash because we need to be able to iterate based on sorted keys
QMap<QShaderKey, QShaderCode> shaders;
QMap<QShaderKey, QShader::NativeResourceBindingMap> bindings;
QMap<QShaderKey, QShader::SeparateToCombinedImageSamplerMappingList> combinedImageMap;
QMap<QShaderKey, QShader::NativeShaderInfo> nativeShaderInfoMap;
};
QT_END_NAMESPACE
#endif

View File

@ -1,8 +1,8 @@
// Copyright (C) 2019 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qshaderdescription_p_p.h"
#include "qshader_p_p.h"
#include "qshaderdescription_p.h"
#include "qshader_p.h"
#include <QDebug>
#include <QDataStream>
#include <QJsonObject>
@ -12,11 +12,22 @@ QT_BEGIN_NAMESPACE
/*!
\class QShaderDescription
\internal
\ingroup painting-3D
\inmodule QtGui
\since 6.6
\brief Describes the interface of a shader.
\warning The QRhi family of classes in the Qt Gui module, including QShader
and QShaderDescription, offer limited compatibility guarantees. There are
no source or binary compatibility guarantees for these classes, meaning the
API is only guaranteed to work with the Qt version the application was
developed against. Source incompatible changes are however aimed to be kept
at a minimum and will only be made in minor releases (6.7, 6.8, and so on).
To use these classes in an application, link to
\c{Qt::GuiPrivate} (if using CMake), and include the headers with the \c
rhi prefix, for example \c{#include <rhi/qshaderdescription.h>}.
A shader typically has a set of inputs and outputs. A vertex shader for
example has a number of input variables and may use one or more uniform
buffers to access data (e.g. a modelview matrix) provided by the
@ -51,8 +62,6 @@ QT_BEGIN_NAMESPACE
float opacity;
} ubuf;
out gl_PerVertex { vec4 gl_Position; };
void main()
{
v_color = color;
@ -200,28 +209,179 @@ QT_BEGIN_NAMESPACE
\value ImageRect
\value ImageBuffer
\value Struct
\value Half
\value Half2
\value Half3
\value Half4
*/
/*!
\class QShaderDescription::InOutVariable
\internal
\enum QShaderDescription::ImageFormat
Image format.
\value ImageFormatUnknown
\value ImageFormatRgba32f
\value ImageFormatRgba16f
\value ImageFormatR32f
\value ImageFormatRgba8
\value ImageFormatRgba8Snorm
\value ImageFormatRg32f
\value ImageFormatRg16f
\value ImageFormatR11fG11fB10f
\value ImageFormatR16f
\value ImageFormatRgba16
\value ImageFormatRgb10A2
\value ImageFormatRg16
\value ImageFormatRg8
\value ImageFormatR16
\value ImageFormatR8
\value ImageFormatRgba16Snorm
\value ImageFormatRg16Snorm
\value ImageFormatRg8Snorm
\value ImageFormatR16Snorm
\value ImageFormatR8Snorm
\value ImageFormatRgba32i
\value ImageFormatRgba16i
\value ImageFormatRgba8i
\value ImageFormatR32i
\value ImageFormatRg32i
\value ImageFormatRg16i
\value ImageFormatRg8i
\value ImageFormatR16i
\value ImageFormatR8i
\value ImageFormatRgba32ui
\value ImageFormatRgba16ui
\value ImageFormatRgba8ui
\value ImageFormatR32ui
\value ImageFormatRgb10a2ui
\value ImageFormatRg32ui
\value ImageFormatRg16ui
\value ImageFormatRg8ui
\value ImageFormatR16ui
\value ImageFormatR8ui
*/
/*!
\enum QShaderDescription::ImageFlag
Image flags.
\value ReadOnlyImage
\value WriteOnlyImage
*/
/*!
\enum QShaderDescription::QualifierFlag
Qualifier flags.
\value QualifierReadOnly
\value QualifierWriteOnly
\value QualifierCoherent
\value QualifierVolatile
\value QualifierRestrict
*/
/*!
\struct QShaderDescription::InOutVariable
\inmodule QtGui
\since 6.6
\brief Describes an input or output variable in the shader.
\note This a RHI API with limited compatibility guarantees, see \l QShaderDescription
for details.
*/
/*!
\class QShaderDescription::BlockVariable
\internal
\variable QShaderDescription::InOutVariable::name
*/
/*!
\variable QShaderDescription::InOutVariable::type
*/
/*!
\variable QShaderDescription::InOutVariable::location
*/
/*!
\variable QShaderDescription::InOutVariable::binding
*/
/*!
\variable QShaderDescription::InOutVariable::descriptorSet
*/
/*!
\variable QShaderDescription::InOutVariable::imageFormat
*/
/*!
\variable QShaderDescription::InOutVariable::imageFlags
*/
/*!
\variable QShaderDescription::InOutVariable::arrayDims
*/
/*!
\variable QShaderDescription::InOutVariable::perPatch
*/
/*!
\variable QShaderDescription::InOutVariable::structMembers
*/
/*!
\struct QShaderDescription::BlockVariable
\inmodule QtGui
\since 6.6
\brief Describes a member of a uniform or push constant block.
\note This a RHI API with limited compatibility guarantees, see \l QShaderDescription
for details.
*/
/*!
\class QShaderDescription::UniformBlock
\internal
\variable QShaderDescription::BlockVariable::name
*/
/*!
\variable QShaderDescription::BlockVariable::type
*/
/*!
\variable QShaderDescription::BlockVariable::offset
*/
/*!
\variable QShaderDescription::BlockVariable::size
*/
/*!
\variable QShaderDescription::BlockVariable::arrayDims
*/
/*!
\variable QShaderDescription::BlockVariable::arrayStride
*/
/*!
\variable QShaderDescription::BlockVariable::matrixStride
*/
/*!
\variable QShaderDescription::BlockVariable::matrixIsRowMajor
*/
/*!
\variable QShaderDescription::BlockVariable::structMembers
*/
/*!
\struct QShaderDescription::UniformBlock
\inmodule QtGui
\since 6.6
\brief Describes a uniform block.
@ -229,22 +389,157 @@ QT_BEGIN_NAMESPACE
(like GLSL 120 or GLSL/ES 100), uniform blocks are replaced with ordinary
uniforms in a struct. The name of the struct, and so the prefix for the
uniforms generated from the block members, is given by structName.
\note This a RHI API with limited compatibility guarantees, see \l QShaderDescription
for details.
*/
/*!
\class QShaderDescription::PushConstantBlock
\internal
\variable QShaderDescription::UniformBlock::blockName
*/
/*!
\variable QShaderDescription::UniformBlock::structName
*/
/*!
\variable QShaderDescription::UniformBlock::size
*/
/*!
\variable QShaderDescription::UniformBlock::binding
*/
/*!
\variable QShaderDescription::UniformBlock::descriptorSet
*/
/*!
\variable QShaderDescription::UniformBlock::members
*/
/*!
\struct QShaderDescription::PushConstantBlock
\inmodule QtGui
\since 6.6
\brief Describes a push constant block.
\note This a RHI API with limited compatibility guarantees, see \l QShaderDescription
for details.
*/
/*!
\class QShaderDescription::StorageBlock
\internal
\variable QShaderDescription::PushConstantBlock::name
*/
/*!
\variable QShaderDescription::PushConstantBlock::size
*/
/*!
\variable QShaderDescription::PushConstantBlock::members
*/
/*!
\struct QShaderDescription::StorageBlock
\inmodule QtGui
\since 6.6
\brief Describes a shader storage block.
\note This a RHI API with limited compatibility guarantees, see \l QShaderDescription
for details.
*/
/*!
\variable QShaderDescription::StorageBlock::blockName
*/
/*!
\variable QShaderDescription::StorageBlock::instanceName
*/
/*!
\variable QShaderDescription::StorageBlock::knownSize
*/
/*!
\variable QShaderDescription::StorageBlock::binding
*/
/*!
\variable QShaderDescription::StorageBlock::descriptorSet
*/
/*!
\variable QShaderDescription::StorageBlock::members
*/
/*!
\variable QShaderDescription::StorageBlock::runtimeArrayStride
*/
/*!
\variable QShaderDescription::StorageBlock::qualifierFlags
*/
/*!
\struct QShaderDescription::BuiltinVariable
\inmodule QtGui
\since 6.6
\brief Describes a built-in variable.
\note This a RHI API with limited compatibility guarantees, see \l QShaderDescription
for details.
*/
/*!
\variable QShaderDescription::BuiltinVariable::type
*/
/*!
\variable QShaderDescription::BuiltinVariable::varType
*/
/*!
\variable QShaderDescription::BuiltinVariable::arrayDims
*/
/*!
\enum QShaderDescription::BuiltinType
Built-in variable type.
\value PositionBuiltin
\value PointSizeBuiltin
\value ClipDistanceBuiltin
\value CullDistanceBuiltin
\value VertexIdBuiltin
\value InstanceIdBuiltin
\value PrimitiveIdBuiltin
\value InvocationIdBuiltin
\value LayerBuiltin
\value ViewportIndexBuiltin
\value TessLevelOuterBuiltin
\value TessLevelInnerBuiltin
\value TessCoordBuiltin
\value PatchVerticesBuiltin
\value FragCoordBuiltin
\value PointCoordBuiltin
\value FrontFacingBuiltin
\value SampleIdBuiltin
\value SamplePositionBuiltin
\value SampleMaskBuiltin
\value FragDepthBuiltin
\value NumWorkGroupsBuiltin
\value WorkgroupSizeBuiltin
\value WorkgroupIdBuiltin
\value LocalInvocationIdBuiltin
\value GlobalInvocationIdBuiltin
\value LocalInvocationIndexBuiltin
\value VertexIndexBuiltin
\value InstanceIndexBuiltin
*/
/*!
@ -267,7 +562,7 @@ void QShaderDescription::detach()
}
/*!
\internal
Constructs a copy of \a other.
*/
QShaderDescription::QShaderDescription(const QShaderDescription &other)
: d(other.d)
@ -276,7 +571,7 @@ QShaderDescription::QShaderDescription(const QShaderDescription &other)
}
/*!
\internal
Assigns \a other to this object.
*/
QShaderDescription &QShaderDescription::operator=(const QShaderDescription &other)
{
@ -574,7 +869,7 @@ uint QShaderDescription::tessellationOutputVertexCount() const
\value UnknownTessellationMode
\value TrianglesTessellationMode
\value QuadTessellationMode
\value IsolinesTessellationMode
\value IsolineTessellationMode
*/
/*!

View File

@ -0,0 +1,386 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSHADERDESCRIPTION_H
#define QSHADERDESCRIPTION_H
//
// W A R N I N G
// -------------
//
// This file is part of the RHI API, with limited compatibility guarantees.
// Usage of this API may make your code source and binary incompatible with
// future versions of Qt.
//
#include <QtGui/qtguiglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
#include <array>
QT_BEGIN_NAMESPACE
struct QShaderDescriptionPrivate;
class QDataStream;
class Q_GUI_EXPORT QShaderDescription
{
public:
QShaderDescription();
QShaderDescription(const QShaderDescription &other);
QShaderDescription &operator=(const QShaderDescription &other);
~QShaderDescription();
void detach();
bool isValid() const;
void serialize(QDataStream *stream, int version) const;
QByteArray toJson() const;
static QShaderDescription deserialize(QDataStream *stream, int version);
enum VariableType {
Unknown = 0,
// do not reorder
Float,
Vec2,
Vec3,
Vec4,
Mat2,
Mat2x3,
Mat2x4,
Mat3,
Mat3x2,
Mat3x4,
Mat4,
Mat4x2,
Mat4x3,
Int,
Int2,
Int3,
Int4,
Uint,
Uint2,
Uint3,
Uint4,
Bool,
Bool2,
Bool3,
Bool4,
Double,
Double2,
Double3,
Double4,
DMat2,
DMat2x3,
DMat2x4,
DMat3,
DMat3x2,
DMat3x4,
DMat4,
DMat4x2,
DMat4x3,
Sampler1D,
Sampler2D,
Sampler2DMS,
Sampler3D,
SamplerCube,
Sampler1DArray,
Sampler2DArray,
Sampler2DMSArray,
Sampler3DArray,
SamplerCubeArray,
SamplerRect,
SamplerBuffer,
SamplerExternalOES,
Sampler,
Image1D,
Image2D,
Image2DMS,
Image3D,
ImageCube,
Image1DArray,
Image2DArray,
Image2DMSArray,
Image3DArray,
ImageCubeArray,
ImageRect,
ImageBuffer,
Struct,
Half,
Half2,
Half3,
Half4
};
enum ImageFormat {
// must match SPIR-V's ImageFormat
ImageFormatUnknown = 0,
ImageFormatRgba32f = 1,
ImageFormatRgba16f = 2,
ImageFormatR32f = 3,
ImageFormatRgba8 = 4,
ImageFormatRgba8Snorm = 5,
ImageFormatRg32f = 6,
ImageFormatRg16f = 7,
ImageFormatR11fG11fB10f = 8,
ImageFormatR16f = 9,
ImageFormatRgba16 = 10,
ImageFormatRgb10A2 = 11,
ImageFormatRg16 = 12,
ImageFormatRg8 = 13,
ImageFormatR16 = 14,
ImageFormatR8 = 15,
ImageFormatRgba16Snorm = 16,
ImageFormatRg16Snorm = 17,
ImageFormatRg8Snorm = 18,
ImageFormatR16Snorm = 19,
ImageFormatR8Snorm = 20,
ImageFormatRgba32i = 21,
ImageFormatRgba16i = 22,
ImageFormatRgba8i = 23,
ImageFormatR32i = 24,
ImageFormatRg32i = 25,
ImageFormatRg16i = 26,
ImageFormatRg8i = 27,
ImageFormatR16i = 28,
ImageFormatR8i = 29,
ImageFormatRgba32ui = 30,
ImageFormatRgba16ui = 31,
ImageFormatRgba8ui = 32,
ImageFormatR32ui = 33,
ImageFormatRgb10a2ui = 34,
ImageFormatRg32ui = 35,
ImageFormatRg16ui = 36,
ImageFormatRg8ui = 37,
ImageFormatR16ui = 38,
ImageFormatR8ui = 39
};
enum ImageFlag {
ReadOnlyImage = 1 << 0,
WriteOnlyImage = 1 << 1
};
Q_DECLARE_FLAGS(ImageFlags, ImageFlag)
enum QualifierFlag {
QualifierReadOnly = 1 << 0,
QualifierWriteOnly = 1 << 1,
QualifierCoherent = 1 << 2,
QualifierVolatile = 1 << 3,
QualifierRestrict = 1 << 4,
};
Q_DECLARE_FLAGS(QualifierFlags, QualifierFlag)
// Optional data (like decorations) usually default to an otherwise invalid value (-1 or 0). This is intentional.
struct BlockVariable {
QByteArray name;
VariableType type = Unknown;
int offset = 0;
int size = 0;
QList<int> arrayDims;
int arrayStride = 0;
int matrixStride = 0;
bool matrixIsRowMajor = false;
QList<BlockVariable> structMembers;
};
struct InOutVariable {
QByteArray name;
VariableType type = Unknown;
int location = -1;
int binding = -1;
int descriptorSet = -1;
ImageFormat imageFormat = ImageFormatUnknown;
ImageFlags imageFlags;
QList<int> arrayDims;
bool perPatch = false;
QList<BlockVariable> structMembers;
};
struct UniformBlock {
QByteArray blockName;
QByteArray structName; // instanceName
int size = 0;
int binding = -1;
int descriptorSet = -1;
QList<BlockVariable> members;
};
struct PushConstantBlock {
QByteArray name;
int size = 0;
QList<BlockVariable> members;
};
struct StorageBlock {
QByteArray blockName;
QByteArray instanceName;
int knownSize = 0;
int binding = -1;
int descriptorSet = -1;
QList<BlockVariable> members;
int runtimeArrayStride = 0;
QualifierFlags qualifierFlags;
};
QList<InOutVariable> inputVariables() const;
QList<InOutVariable> outputVariables() const;
QList<UniformBlock> uniformBlocks() const;
QList<PushConstantBlock> pushConstantBlocks() const;
QList<StorageBlock> storageBlocks() const;
QList<InOutVariable> combinedImageSamplers() const;
QList<InOutVariable> separateImages() const;
QList<InOutVariable> separateSamplers() const;
QList<InOutVariable> storageImages() const;
enum BuiltinType {
// must match SpvBuiltIn
PositionBuiltin = 0,
PointSizeBuiltin = 1,
ClipDistanceBuiltin = 3,
CullDistanceBuiltin = 4,
VertexIdBuiltin = 5,
InstanceIdBuiltin = 6,
PrimitiveIdBuiltin = 7,
InvocationIdBuiltin = 8,
LayerBuiltin = 9,
ViewportIndexBuiltin = 10,
TessLevelOuterBuiltin = 11,
TessLevelInnerBuiltin = 12,
TessCoordBuiltin = 13,
PatchVerticesBuiltin = 14,
FragCoordBuiltin = 15,
PointCoordBuiltin = 16,
FrontFacingBuiltin = 17,
SampleIdBuiltin = 18,
SamplePositionBuiltin = 19,
SampleMaskBuiltin = 20,
FragDepthBuiltin = 22,
NumWorkGroupsBuiltin = 24,
WorkgroupSizeBuiltin = 25,
WorkgroupIdBuiltin = 26,
LocalInvocationIdBuiltin = 27,
GlobalInvocationIdBuiltin = 28,
LocalInvocationIndexBuiltin = 29,
VertexIndexBuiltin = 42,
InstanceIndexBuiltin = 43
};
struct BuiltinVariable {
BuiltinType type;
VariableType varType;
QList<int> arrayDims;
};
QList<BuiltinVariable> inputBuiltinVariables() const;
QList<BuiltinVariable> outputBuiltinVariables() const;
std::array<uint, 3> computeShaderLocalSize() const;
uint tessellationOutputVertexCount() const;
enum TessellationMode {
UnknownTessellationMode,
TrianglesTessellationMode,
QuadTessellationMode,
IsolineTessellationMode
};
TessellationMode tessellationMode() const;
enum TessellationWindingOrder {
UnknownTessellationWindingOrder,
CwTessellationWindingOrder,
CcwTessellationWindingOrder
};
TessellationWindingOrder tessellationWindingOrder() const;
enum TessellationPartitioning {
UnknownTessellationPartitioning,
EqualTessellationPartitioning,
FractionalEvenTessellationPartitioning,
FractionalOddTessellationPartitioning
};
TessellationPartitioning tessellationPartitioning() const;
private:
QShaderDescriptionPrivate *d;
friend struct QShaderDescriptionPrivate;
#ifndef QT_NO_DEBUG_STREAM
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription &);
#endif
friend Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) noexcept;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::ImageFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::QualifierFlags)
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription &);
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::InOutVariable &);
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::BlockVariable &);
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::UniformBlock &);
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::PushConstantBlock &);
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::StorageBlock &);
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::BuiltinVariable &);
#endif
Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderDescription::BuiltinVariable &lhs, const QShaderDescription::BuiltinVariable &rhs) noexcept;
inline bool operator!=(const QShaderDescription &lhs, const QShaderDescription &rhs) noexcept
{
return !(lhs == rhs);
}
inline bool operator!=(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) noexcept
{
return !(lhs == rhs);
}
inline bool operator!=(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) noexcept
{
return !(lhs == rhs);
}
inline bool operator!=(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) noexcept
{
return !(lhs == rhs);
}
inline bool operator!=(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) noexcept
{
return !(lhs == rhs);
}
inline bool operator!=(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) noexcept
{
return !(lhs == rhs);
}
inline bool operator!=(const QShaderDescription::BuiltinVariable &lhs, const QShaderDescription::BuiltinVariable &rhs) noexcept
{
return !(lhs == rhs);
}
QT_END_NAMESPACE
#endif

View File

@ -1,8 +1,8 @@
// Copyright (C) 2021 The Qt Company Ltd.
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSHADERDESCRIPTION_H
#define QSHADERDESCRIPTION_H
#ifndef QSHADERDESCRIPTION_P_H
#define QSHADERDESCRIPTION_P_H
//
// W A R N I N G
@ -15,375 +15,66 @@
// We mean it.
//
#include <QtGui/qtguiglobal.h>
#include <QtCore/QString>
#include <rhi/qshaderdescription.h>
#include <QtCore/QList>
#include <QtCore/private/qglobal_p.h>
#include <array>
#include <QtCore/QAtomicInt>
#include <QtCore/QJsonDocument>
QT_BEGIN_NAMESPACE
struct QShaderDescriptionPrivate;
class QDataStream;
class Q_GUI_EXPORT QShaderDescription
struct Q_GUI_EXPORT QShaderDescriptionPrivate
{
public:
QShaderDescription();
QShaderDescription(const QShaderDescription &other);
QShaderDescription &operator=(const QShaderDescription &other);
~QShaderDescription();
void detach();
bool isValid() const;
void serialize(QDataStream *stream, int version) const;
QByteArray toJson() const;
static QShaderDescription deserialize(QDataStream *stream, int version);
enum VariableType {
Unknown = 0,
// do not reorder
Float,
Vec2,
Vec3,
Vec4,
Mat2,
Mat2x3,
Mat2x4,
Mat3,
Mat3x2,
Mat3x4,
Mat4,
Mat4x2,
Mat4x3,
Int,
Int2,
Int3,
Int4,
Uint,
Uint2,
Uint3,
Uint4,
Bool,
Bool2,
Bool3,
Bool4,
Double,
Double2,
Double3,
Double4,
DMat2,
DMat2x3,
DMat2x4,
DMat3,
DMat3x2,
DMat3x4,
DMat4,
DMat4x2,
DMat4x3,
Sampler1D,
Sampler2D,
Sampler2DMS,
Sampler3D,
SamplerCube,
Sampler1DArray,
Sampler2DArray,
Sampler2DMSArray,
Sampler3DArray,
SamplerCubeArray,
SamplerRect,
SamplerBuffer,
SamplerExternalOES,
Sampler,
Image1D,
Image2D,
Image2DMS,
Image3D,
ImageCube,
Image1DArray,
Image2DArray,
Image2DMSArray,
Image3DArray,
ImageCubeArray,
ImageRect,
ImageBuffer,
Struct,
Half,
Half2,
Half3,
Half4
};
enum ImageFormat {
// must match SPIR-V's ImageFormat
ImageFormatUnknown = 0,
ImageFormatRgba32f = 1,
ImageFormatRgba16f = 2,
ImageFormatR32f = 3,
ImageFormatRgba8 = 4,
ImageFormatRgba8Snorm = 5,
ImageFormatRg32f = 6,
ImageFormatRg16f = 7,
ImageFormatR11fG11fB10f = 8,
ImageFormatR16f = 9,
ImageFormatRgba16 = 10,
ImageFormatRgb10A2 = 11,
ImageFormatRg16 = 12,
ImageFormatRg8 = 13,
ImageFormatR16 = 14,
ImageFormatR8 = 15,
ImageFormatRgba16Snorm = 16,
ImageFormatRg16Snorm = 17,
ImageFormatRg8Snorm = 18,
ImageFormatR16Snorm = 19,
ImageFormatR8Snorm = 20,
ImageFormatRgba32i = 21,
ImageFormatRgba16i = 22,
ImageFormatRgba8i = 23,
ImageFormatR32i = 24,
ImageFormatRg32i = 25,
ImageFormatRg16i = 26,
ImageFormatRg8i = 27,
ImageFormatR16i = 28,
ImageFormatR8i = 29,
ImageFormatRgba32ui = 30,
ImageFormatRgba16ui = 31,
ImageFormatRgba8ui = 32,
ImageFormatR32ui = 33,
ImageFormatRgb10a2ui = 34,
ImageFormatRg32ui = 35,
ImageFormatRg16ui = 36,
ImageFormatRg8ui = 37,
ImageFormatR16ui = 38,
ImageFormatR8ui = 39
};
enum ImageFlag {
ReadOnlyImage = 1 << 0,
WriteOnlyImage = 1 << 1
};
Q_DECLARE_FLAGS(ImageFlags, ImageFlag)
enum QualifierFlag {
QualifierReadOnly = 1 << 0,
QualifierWriteOnly = 1 << 1,
QualifierCoherent = 1 << 2,
QualifierVolatile = 1 << 3,
QualifierRestrict = 1 << 4,
};
Q_DECLARE_FLAGS(QualifierFlags, QualifierFlag)
// Optional data (like decorations) usually default to an otherwise invalid value (-1 or 0). This is intentional.
struct BlockVariable
QShaderDescriptionPrivate()
: ref(1)
{
QByteArray name;
VariableType type = Unknown;
int offset = 0;
int size = 0;
QList<int> arrayDims;
int arrayStride = 0;
int matrixStride = 0;
bool matrixIsRowMajor = false;
QList<BlockVariable> structMembers;
};
struct InOutVariable {
QByteArray name;
VariableType type = Unknown;
int location = -1;
int binding = -1;
int descriptorSet = -1;
ImageFormat imageFormat = ImageFormatUnknown;
ImageFlags imageFlags;
QList<int> arrayDims;
bool perPatch = false;
QList<BlockVariable> structMembers;
};
struct UniformBlock {
QByteArray blockName;
QByteArray structName; // instanceName
int size = 0;
int binding = -1;
int descriptorSet = -1;
QList<BlockVariable> members;
};
struct PushConstantBlock {
QByteArray name;
int size = 0;
QList<BlockVariable> members;
};
struct StorageBlock {
QByteArray blockName;
QByteArray instanceName;
int knownSize = 0;
int binding = -1;
int descriptorSet = -1;
QList<BlockVariable> members;
int runtimeArrayStride = 0;
QualifierFlags qualifierFlags;
};
QList<InOutVariable> inputVariables() const;
QList<InOutVariable> outputVariables() const;
QList<UniformBlock> uniformBlocks() const;
QList<PushConstantBlock> pushConstantBlocks() const;
QList<StorageBlock> storageBlocks() const;
QList<InOutVariable> combinedImageSamplers() const;
QList<InOutVariable> separateImages() const;
QList<InOutVariable> separateSamplers() const;
QList<InOutVariable> storageImages() const;
enum BuiltinType {
// must match SpvBuiltIn
PositionBuiltin = 0,
PointSizeBuiltin = 1,
ClipDistanceBuiltin = 3,
CullDistanceBuiltin = 4,
VertexIdBuiltin = 5,
InstanceIdBuiltin = 6,
PrimitiveIdBuiltin = 7,
InvocationIdBuiltin = 8,
LayerBuiltin = 9,
ViewportIndexBuiltin = 10,
TessLevelOuterBuiltin = 11,
TessLevelInnerBuiltin = 12,
TessCoordBuiltin = 13,
PatchVerticesBuiltin = 14,
FragCoordBuiltin = 15,
PointCoordBuiltin = 16,
FrontFacingBuiltin = 17,
SampleIdBuiltin = 18,
SamplePositionBuiltin = 19,
SampleMaskBuiltin = 20,
FragDepthBuiltin = 22,
NumWorkGroupsBuiltin = 24,
WorkgroupSizeBuiltin = 25,
WorkgroupIdBuiltin = 26,
LocalInvocationIdBuiltin = 27,
GlobalInvocationIdBuiltin = 28,
LocalInvocationIndexBuiltin = 29,
VertexIndexBuiltin = 42,
InstanceIndexBuiltin = 43
};
struct BuiltinVariable {
BuiltinType type;
VariableType varType;
QList<int> arrayDims;
};
QList<BuiltinVariable> inputBuiltinVariables() const;
QList<BuiltinVariable> outputBuiltinVariables() const;
std::array<uint, 3> computeShaderLocalSize() const;
uint tessellationOutputVertexCount() const;
enum TessellationMode {
UnknownTessellationMode,
TrianglesTessellationMode,
QuadTessellationMode,
IsolineTessellationMode
};
TessellationMode tessellationMode() const;
enum TessellationWindingOrder {
UnknownTessellationWindingOrder,
CwTessellationWindingOrder,
CcwTessellationWindingOrder
};
TessellationWindingOrder tessellationWindingOrder() const;
enum TessellationPartitioning {
UnknownTessellationPartitioning,
EqualTessellationPartitioning,
FractionalEvenTessellationPartitioning,
FractionalOddTessellationPartitioning
};
TessellationPartitioning tessellationPartitioning() const;
private:
QShaderDescriptionPrivate *d;
friend struct QShaderDescriptionPrivate;
#ifndef QT_NO_DEBUG_STREAM
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription &);
#endif
friend Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) noexcept;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::ImageFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::QualifierFlags)
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription &);
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::InOutVariable &);
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::BlockVariable &);
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::UniformBlock &);
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::PushConstantBlock &);
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::StorageBlock &);
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::BuiltinVariable &);
#endif
Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) noexcept;
Q_GUI_EXPORT bool operator==(const QShaderDescription::BuiltinVariable &lhs, const QShaderDescription::BuiltinVariable &rhs) noexcept;
inline bool operator!=(const QShaderDescription &lhs, const QShaderDescription &rhs) noexcept
{
return !(lhs == rhs);
}
inline bool operator!=(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) noexcept
QShaderDescriptionPrivate(const QShaderDescriptionPrivate &other)
: ref(1),
inVars(other.inVars),
outVars(other.outVars),
uniformBlocks(other.uniformBlocks),
pushConstantBlocks(other.pushConstantBlocks),
storageBlocks(other.storageBlocks),
combinedImageSamplers(other.combinedImageSamplers),
separateImages(other.separateImages),
separateSamplers(other.separateSamplers),
storageImages(other.storageImages),
inBuiltins(other.inBuiltins),
outBuiltins(other.outBuiltins),
localSize(other.localSize),
tessOutVertCount(other.tessOutVertCount),
tessMode(other.tessMode),
tessWind(other.tessWind),
tessPart(other.tessPart)
{
return !(lhs == rhs);
}
inline bool operator!=(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) noexcept
{
return !(lhs == rhs);
}
static QShaderDescriptionPrivate *get(QShaderDescription *desc) { return desc->d; }
static const QShaderDescriptionPrivate *get(const QShaderDescription *desc) { return desc->d; }
inline bool operator!=(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) noexcept
{
return !(lhs == rhs);
}
QJsonDocument makeDoc();
void writeToStream(QDataStream *stream, int version);
void loadFromStream(QDataStream *stream, int version);
inline bool operator!=(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) noexcept
{
return !(lhs == rhs);
}
inline bool operator!=(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) noexcept
{
return !(lhs == rhs);
}
inline bool operator!=(const QShaderDescription::BuiltinVariable &lhs, const QShaderDescription::BuiltinVariable &rhs) noexcept
{
return !(lhs == rhs);
}
QAtomicInt ref;
QList<QShaderDescription::InOutVariable> inVars;
QList<QShaderDescription::InOutVariable> outVars;
QList<QShaderDescription::UniformBlock> uniformBlocks;
QList<QShaderDescription::PushConstantBlock> pushConstantBlocks;
QList<QShaderDescription::StorageBlock> storageBlocks;
QList<QShaderDescription::InOutVariable> combinedImageSamplers;
QList<QShaderDescription::InOutVariable> separateImages;
QList<QShaderDescription::InOutVariable> separateSamplers;
QList<QShaderDescription::InOutVariable> storageImages;
QList<QShaderDescription::BuiltinVariable> inBuiltins;
QList<QShaderDescription::BuiltinVariable> outBuiltins;
std::array<uint, 3> localSize = {};
uint tessOutVertCount = 0;
QShaderDescription::TessellationMode tessMode = QShaderDescription::UnknownTessellationMode;
QShaderDescription::TessellationWindingOrder tessWind = QShaderDescription::UnknownTessellationWindingOrder;
QShaderDescription::TessellationPartitioning tessPart = QShaderDescription::UnknownTessellationPartitioning;
};
QT_END_NAMESPACE

View File

@ -1,81 +0,0 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSHADERDESCRIPTION_P_H
#define QSHADERDESCRIPTION_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of a number of Qt sources files. This header file may change from
// version to version without notice, or even be removed.
//
// We mean it.
//
#include "qshaderdescription_p.h"
#include <QtCore/QList>
#include <QtCore/QAtomicInt>
#include <QtCore/QJsonDocument>
QT_BEGIN_NAMESPACE
struct Q_GUI_EXPORT QShaderDescriptionPrivate
{
QShaderDescriptionPrivate()
: ref(1)
{
}
QShaderDescriptionPrivate(const QShaderDescriptionPrivate &other)
: ref(1),
inVars(other.inVars),
outVars(other.outVars),
uniformBlocks(other.uniformBlocks),
pushConstantBlocks(other.pushConstantBlocks),
storageBlocks(other.storageBlocks),
combinedImageSamplers(other.combinedImageSamplers),
separateImages(other.separateImages),
separateSamplers(other.separateSamplers),
storageImages(other.storageImages),
inBuiltins(other.inBuiltins),
outBuiltins(other.outBuiltins),
localSize(other.localSize),
tessOutVertCount(other.tessOutVertCount),
tessMode(other.tessMode),
tessWind(other.tessWind),
tessPart(other.tessPart)
{
}
static QShaderDescriptionPrivate *get(QShaderDescription *desc) { return desc->d; }
static const QShaderDescriptionPrivate *get(const QShaderDescription *desc) { return desc->d; }
QJsonDocument makeDoc();
void writeToStream(QDataStream *stream, int version);
void loadFromStream(QDataStream *stream, int version);
QAtomicInt ref;
QList<QShaderDescription::InOutVariable> inVars;
QList<QShaderDescription::InOutVariable> outVars;
QList<QShaderDescription::UniformBlock> uniformBlocks;
QList<QShaderDescription::PushConstantBlock> pushConstantBlocks;
QList<QShaderDescription::StorageBlock> storageBlocks;
QList<QShaderDescription::InOutVariable> combinedImageSamplers;
QList<QShaderDescription::InOutVariable> separateImages;
QList<QShaderDescription::InOutVariable> separateSamplers;
QList<QShaderDescription::InOutVariable> storageImages;
QList<QShaderDescription::BuiltinVariable> inBuiltins;
QList<QShaderDescription::BuiltinVariable> outBuiltins;
std::array<uint, 3> localSize = {};
uint tessOutVertCount = 0;
QShaderDescription::TessellationMode tessMode = QShaderDescription::UnknownTessellationMode;
QShaderDescription::TessellationWindingOrder tessWind = QShaderDescription::UnknownTessellationWindingOrder;
QShaderDescription::TessellationPartitioning tessPart = QShaderDescription::UnknownTessellationPartitioning;
};
QT_END_NAMESPACE
#endif

View File

@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qvulkandefaultinstance_p.h"
#include <private/qrhivulkan_p.h>
#include <rhi/qrhi.h>
#include <QLoggingCategory>
QT_BEGIN_NAMESPACE

View File

@ -12,6 +12,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QVulkanInstance
\since 5.10
\ingroup painting-3D
\inmodule QtGui
\brief The QVulkanInstance class represents a native Vulkan instance, enabling

View File

@ -4,7 +4,7 @@
#include <QtOpenGL/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLContext>
#include <QtGui/QWindow>
#include <QtGui/private/qrhi_p.h>
#include <rhi/qrhi.h>
#include <qpa/qplatformbackingstore.h>
#include "qopenglcompositor_p.h"

View File

@ -6,7 +6,7 @@
#include <QtGui/QPainter>
#include <qpa/qplatformbackingstore.h>
#include <private/qwindow_p.h>
#include <private/qrhi_p.h>
#include <rhi/qrhi.h>
#include "qopenglcompositorbackingstore_p.h"
#include "qopenglcompositor_p.h"

View File

@ -23,8 +23,7 @@
#include <QtWidgets/private/qwidget_p.h>
#include <QtWidgets/private/qwidgetrepaintmanager_p.h>
#include <QtGui/private/qrhi_p.h>
#include <QtGui/private/qrhigles2_p.h>
#include <rhi/qrhi.h>
QT_BEGIN_NAMESPACE

View File

@ -149,6 +149,8 @@ public:
const std::string &qpaIncludeDir() const { return m_qpaIncludeDir; }
const std::string &rhiIncludeDir() const { return m_rhiIncludeDir; }
const std::string &stagingDir() const { return m_stagingDir; }
const std::string &versionScriptFile() const { return m_versionScriptFile; }
@ -157,6 +159,8 @@ public:
const std::regex &qpaHeadersRegex() const { return m_qpaHeadersRegex; }
const std::regex &rhiHeadersRegex() const { return m_rhiHeadersRegex; }
const std::regex &privateHeadersRegex() const { return m_privateHeadersRegex; }
const std::regex &publicNamespaceRegex() const { return m_publicNamespaceRegex; }
@ -188,9 +192,9 @@ public:
void printHelp() const
{
std::cout << "Usage: syncqt -sourceDir <dir> -binaryDir <dir> -module <module name>"
" -includeDir <dir> -privateIncludeDir <dir> -qpaIncludeDir <dir>"
" -includeDir <dir> -privateIncludeDir <dir> -qpaIncludeDir <dir> -rhiIncludeDir <dir>"
" -stagingDir <dir> <-headers <header list>|-all> [-debug]"
" [-versionScript <path>] [-qpaHeadersFilter <regex>]"
" [-versionScript <path>] [-qpaHeadersFilter <regex>] [-rhiHeadersFilter <regex>]"
" [-framework [-frameworkIncludeDir <dir>]]"
" [-knownModules <module1> <module2>... <moduleN>]"
" [-nonQt] [-internal] [-copy]\n"
@ -212,6 +216,8 @@ public:
" generated private header files.\n"
" -qpaIncludeDir Module include directory for the \n"
" generated QPA header files.\n"
" -rhiIncludeDir Module include directory for the \n"
" generated RHI header files.\n"
" -stagingDir Temporary staging directory to collect\n"
" artifacts that need to be installed.\n"
" -knownModules list of known modules. syncqt uses the\n"
@ -225,6 +231,8 @@ public:
" from the list of 'headers'.\n"
" -qpaHeadersFilter Regex that filters qpa header files from.\n"
" the list of 'headers'.\n"
" -rhiHeadersFilter Regex that filters rhi header files from.\n"
" the list of 'headers'.\n"
" -publicNamespaceFilter Symbols that are in the specified\n"
" namespace.\n"
" are treated as public symbols.\n"
@ -262,6 +270,7 @@ private:
[[nodiscard]] bool parseArguments(int argc, char *argv[])
{
std::string qpaHeadersFilter;
std::string rhiHeadersFilter;
std::string privateHeadersFilter;
std::string publicNamespaceFilter;
static std::unordered_map<std::string, CommandLineOption<std::string>> stringArgumentMap = {
@ -270,9 +279,11 @@ private:
{ "-binaryDir", { &m_binaryDir } },
{ "-privateHeadersFilter", { &privateHeadersFilter, true } },
{ "-qpaHeadersFilter", { &qpaHeadersFilter, true } },
{ "-rhiHeadersFilter", { &rhiHeadersFilter, true } },
{ "-includeDir", { &m_includeDir } },
{ "-privateIncludeDir", { &m_privateIncludeDir } },
{ "-qpaIncludeDir", { &m_qpaIncludeDir } },
{ "-rhiIncludeDir", { &m_rhiIncludeDir } },
{ "-stagingDir", { &m_stagingDir, true } },
{ "-versionScript", { &m_versionScriptFile, true } },
{ "-frameworkIncludeDir", { &m_frameworkIncludeDir, true } },
@ -386,6 +397,9 @@ private:
if (!qpaHeadersFilter.empty())
m_qpaHeadersRegex = std::regex(qpaHeadersFilter);
if (!rhiHeadersFilter.empty())
m_rhiHeadersRegex = std::regex(rhiHeadersFilter);
if (!privateHeadersFilter.empty())
m_privateHeadersRegex = std::regex(privateHeadersFilter);
@ -418,9 +432,10 @@ private:
// Convert all paths from command line to a generic one.
void normilizePaths()
{
static std::array<std::string *, 8> paths = {
static std::array<std::string *, 9> paths = {
&m_sourceDir, &m_binaryDir, &m_includeDir, &m_privateIncludeDir,
&m_qpaIncludeDir, &m_stagingDir, &m_versionScriptFile, &m_frameworkIncludeDir
&m_qpaIncludeDir, &m_rhiIncludeDir, &m_stagingDir,
&m_versionScriptFile, &m_frameworkIncludeDir
};
for (auto path : paths) {
if (!path->empty())
@ -434,6 +449,7 @@ private:
std::string m_includeDir;
std::string m_privateIncludeDir;
std::string m_qpaIncludeDir;
std::string m_rhiIncludeDir;
std::string m_stagingDir;
std::string m_versionScriptFile;
std::string m_frameworkIncludeDir;
@ -451,6 +467,7 @@ private:
bool m_showOnly = false;
bool m_warningsAreErrors = false;
std::regex m_qpaHeadersRegex;
std::regex m_rhiHeadersRegex;
std::regex m_privateHeadersRegex;
std::regex m_publicNamespaceRegex;
@ -522,7 +539,7 @@ class SyncScanner
size_t m_currentFileLineNumber = 0;
bool m_currentFileInSourceDir = false;
enum FileType { PublicHeader = 0, PrivateHeader = 1, QpaHeader = 2, ExportHeader = 4 };
enum FileType { PublicHeader = 0, PrivateHeader = 1, QpaHeader = 2, ExportHeader = 4, RhiHeader = 8 };
unsigned int m_currentFileType = PublicHeader;
int m_criticalChecks = CriticalChecks;
@ -725,6 +742,9 @@ public:
if (isHeaderQpa(m_currentFilename))
m_currentFileType = QpaHeader | PrivateHeader;
if (isHeaderRhi(m_currentFilename))
m_currentFileType = RhiHeader | PrivateHeader;
if (std::regex_match(m_currentFilename, ExportsHeaderRegex))
m_currentFileType |= ExportHeader;
}
@ -762,12 +782,14 @@ public:
bool isPrivate = m_currentFileType & PrivateHeader;
bool isQpa = m_currentFileType & QpaHeader;
bool isRhi = m_currentFileType & RhiHeader;
bool isExport = m_currentFileType & ExportHeader;
scannerDebug()
<< "processHeader:start: " << headerFile
<< " m_currentFilename: " << m_currentFilename
<< " isPrivate: " << isPrivate
<< " isQpa: " << isQpa
<< " isRhi: " << isRhi
<< std::endl;
// Chose the directory where to generate the header aliases or to copy header file if
@ -775,6 +797,8 @@ public:
std::string outputDir = m_commandLineArgs->includeDir();
if (isQpa)
outputDir = m_commandLineArgs->qpaIncludeDir();
else if (isRhi)
outputDir = m_commandLineArgs->rhiIncludeDir();
else if (isPrivate)
outputDir = m_commandLineArgs->privateIncludeDir();
@ -826,7 +850,7 @@ public:
unsigned int skipChecks = m_commandLineArgs->scanAllMode() ? AllChecks : NoChecks;
// Collect checks that should skipped for the header file.
if (m_commandLineArgs->isNonQtModule() || is3rdParty || isQpa
if (m_commandLineArgs->isNonQtModule() || is3rdParty || isQpa || isRhi
|| !m_currentFileInSourceDir || isGenerated) {
skipChecks = AllChecks;
} else {
@ -847,7 +871,7 @@ public:
ParsingResult parsingResult;
parsingResult.masterInclude = m_currentFileInSourceDir && !isExport && !is3rdParty
&& !isQpa && !isPrivate && !isGenerated;
&& !isQpa && !isRhi && !isPrivate && !isGenerated;
if (!parseHeader(headerFile, parsingResult, skipChecks)) {
scannerDebug() << "parseHeader failed: " << headerFile << std::endl;
return false;
@ -864,7 +888,7 @@ public:
// Add the '#if QT_CONFIG(<feature>)' check for header files that supposed to be
// included into the module master header only if corresponding feature is enabled.
bool willBeInModuleMasterHeader = false;
if (!isQpa && !isPrivate) {
if (!isQpa && !isRhi && !isPrivate) {
if (m_currentFilename.find('_') == std::string::npos
&& parsingResult.masterInclude) {
m_masterHeaderContents[m_currentFilename] = parsingResult.requireConfig;
@ -1150,7 +1174,7 @@ public:
++linesProcessed;
bool skipSymbols =
(m_currentFileType & PrivateHeader) || (m_currentFileType & QpaHeader);
(m_currentFileType & PrivateHeader) || (m_currentFileType & QpaHeader) || (m_currentFileType & RhiHeader);
// Parse pragmas
if (std::regex_match(buffer, MacroRegex)) {
@ -1331,6 +1355,11 @@ public:
return std::regex_match(headerFileName, m_commandLineArgs->qpaHeadersRegex());
}
[[nodiscard]] bool isHeaderRhi(const std::string &headerFileName)
{
return std::regex_match(headerFileName, m_commandLineArgs->rhiHeadersRegex());
}
[[nodiscard]] bool isHeaderPrivate(const std::string &headerFile)
{
return std::regex_match(headerFile, m_commandLineArgs->privateHeadersRegex());

View File

@ -73,6 +73,7 @@
);
@qpa_headers = ( qr/^qplatform/, qr/^qwindowsystem/ );
@rhi_headers = ( "qrhi.h", "qrhi_platform.h", "qshader.h", "qshaderdescription.h");
my @internal_zlib_headers = ( "crc32.h", "deflate.h", "gzguts.h", "inffast.h", "inffixed.h", "inflate.h", "inftrees.h", "trees.h", "zutil.h" );
my @zlib_headers = ( "zconf.h", "zlib.h" );
@ignore_headers = ( @internal_zlib_headers );

View File

@ -9,14 +9,11 @@
#include <qrgbafloat.h>
#include <qrgba64.h>
#include <QtGui/private/qrhi_p.h>
#include <QtGui/private/qrhi_p_p.h>
#include <QtGui/private/qrhinull_p.h>
#include <private/qrhi_p.h>
#if QT_CONFIG(opengl)
# include <QOpenGLContext>
# include <QOpenGLFunctions>
# include <QtGui/private/qrhigles2_p.h>
# include <QtGui/private/qguiapplication_p.h>
# include <qpa/qplatformintegration.h>
# define TST_GL
@ -25,19 +22,15 @@
#if QT_CONFIG(vulkan)
# include <QVulkanInstance>
# include <QVulkanFunctions>
# include <QtGui/private/qrhivulkan_p.h>
# define TST_VK
#endif
#ifdef Q_OS_WIN
#include <QtGui/private/qrhid3d11_p.h>
#include <QtGui/private/qrhid3d12_p.h>
# define TST_D3D11
# define TST_D3D12
#endif
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
# include <QtGui/private/qrhimetal_p.h>
# define TST_MTL
#endif

View File

@ -5,8 +5,8 @@
#include <QFile>
#include <QBuffer>
#include <QtGui/private/qshaderdescription_p_p.h>
#include <QtGui/private/qshader_p_p.h>
#include <private/qshaderdescription_p.h>
#include <private/qshader_p.h>
class tst_QShader : public QObject
{

View File

@ -24,8 +24,7 @@
#include <private/qguiapplication_p.h>
#include <qpa/qplatformbackingstore.h>
#include <qpa/qplatformintegration.h>
#include <private/qrhi_p.h>
#include <private/qrhigles2_p.h>
#include <rhi/qrhi.h>
class tst_QOpenGLWidget : public QObject
{

View File

@ -3,7 +3,7 @@
#include "hellowindow.h"
#include <QFile>
#include <QtGui/private/qshader_p.h>
#include <rhi/qshader.h>
static float vertexData[] = {
// Y up (note clipSpaceCorrMatrix in m_proj), CCW

View File

@ -5,22 +5,8 @@
#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>
#include <QtGui/private/qrhid3d12_p.h>
#endif
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
#include <QtGui/private/qrhimetal_p.h>
#endif
#include <rhi/qrhi.h>
class Window : public QWindow
{

View File

@ -13,33 +13,17 @@
#include <QWindow>
#include <QPlatformSurfaceEvent>
#include <QElapsedTimer>
#include <QtGui/private/qshader_p.h>
#include <QFile>
#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
#include <QOffscreenSurface>
#include <rhi/qrhi.h>
enum GraphicsApi
{
OpenGL,
Vulkan,
D3D11,
D3D12,
Metal
};
@ -54,6 +38,8 @@ static QString graphicsApiName()
return QLatin1String("Vulkan");
case D3D11:
return QLatin1String("Direct3D 11");
case D3D12:
return QLatin1String("Direct3D 12");
case Metal:
return QLatin1String("Metal");
default:
@ -98,6 +84,10 @@ void createRhi()
QRhiD3D11InitParams params;
params.enableDebugLayer = true;
r.r = QRhi::create(QRhi::D3D11, &params);
} else if (graphicsApi == D3D12) {
QRhiD3D12InitParams params;
params.enableDebugLayer = true;
r.r = QRhi::create(QRhi::D3D12, &params);
}
#endif
@ -281,6 +271,7 @@ Window::Window(const QString &title, const QColor &bgColor, int axis, bool noVSy
#endif
break;
case D3D11:
case D3D12:
setSurfaceType(Direct3DSurface);
break;
case Metal:
@ -494,6 +485,8 @@ int main(int argc, char **argv)
cmdLineParser.addOption(vkOption);
QCommandLineOption d3dOption({ "d", "d3d11" }, QLatin1String("Direct3D 11"));
cmdLineParser.addOption(d3dOption);
QCommandLineOption d3d12Option({ "D", "d3d12" }, QLatin1String("Direct3D 12"));
cmdLineParser.addOption(d3d12Option);
QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal"));
cmdLineParser.addOption(mtlOption);
cmdLineParser.process(app);
@ -503,6 +496,8 @@ int main(int argc, char **argv)
graphicsApi = Vulkan;
if (cmdLineParser.isSet(d3dOption))
graphicsApi = D3D11;
if (cmdLineParser.isSet(d3d12Option))
graphicsApi = D3D12;
if (cmdLineParser.isSet(mtlOption))
graphicsApi = Metal;
@ -517,6 +512,7 @@ int main(int argc, char **argv)
r.instance = new QVulkanInstance;
if (graphicsApi == Vulkan) {
r.instance->setLayers({ "VK_LAYER_KHRONOS_validation" });
r.instance->setExtensions(QRhiVulkanInitParams::preferredInstanceExtensions());
if (!r.instance->create()) {
qWarning("Failed to create Vulkan instance, switching to OpenGL");
graphicsApi = OpenGL;

View File

@ -16,27 +16,10 @@
#include <QEvent>
#include <QCommandLineParser>
#include <QElapsedTimer>
#include <QtGui/private/qshader_p.h>
#include <QFile>
#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
#include <QOffscreenSurface>
#include <rhi/qrhi.h>
#ifdef Q_OS_DARWIN
#include <QtCore/private/qcore_mac_p.h>
@ -66,6 +49,8 @@ static QString graphicsApiName()
return QLatin1String("Vulkan");
case D3D11:
return QLatin1String("Direct3D 11");
case D3D12:
return QLatin1String("Direct3D 12");
case Metal:
return QLatin1String("Metal");
default:
@ -329,6 +314,10 @@ void Renderer::createRhi()
QRhiD3D11InitParams params;
params.enableDebugLayer = true;
r = QRhi::create(QRhi::D3D11, &params, rhiFlags);
} else if (graphicsApi == D3D12) {
QRhiD3D12InitParams params;
params.enableDebugLayer = true;
r = QRhi::create(QRhi::D3D12, &params, rhiFlags);
}
#endif
@ -681,6 +670,8 @@ int main(int argc, char **argv)
cmdLineParser.addOption(vkOption);
QCommandLineOption d3dOption({ "d", "d3d11" }, QLatin1String("Direct3D 11"));
cmdLineParser.addOption(d3dOption);
QCommandLineOption d3d12Option({ "D", "d3d12" }, QLatin1String("Direct3D 12"));
cmdLineParser.addOption(d3d12Option);
QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal"));
cmdLineParser.addOption(mtlOption);
cmdLineParser.process(app);
@ -690,6 +681,8 @@ int main(int argc, char **argv)
graphicsApi = Vulkan;
if (cmdLineParser.isSet(d3dOption))
graphicsApi = D3D11;
if (cmdLineParser.isSet(d3d12Option))
graphicsApi = D3D12;
if (cmdLineParser.isSet(mtlOption))
graphicsApi = Metal;

View File

@ -4,10 +4,6 @@
#include "window.h"
#include <QPlatformSurfaceEvent>
#ifndef QT_NO_OPENGL
#include <QtGui/private/qrhigles2_p.h>
#endif
#if QT_CONFIG(vulkan)
extern QVulkanInstance *instance;
#endif
@ -25,6 +21,7 @@ Window::Window(const QString &title, GraphicsApi api)
#endif
break;
case D3D11:
case D3D12:
setSurfaceType(Direct3DSurface);
break;
case Metal:

View File

@ -11,6 +11,7 @@ enum GraphicsApi
OpenGL,
Vulkan,
D3D11,
D3D12,
Metal
};

View File

@ -7,28 +7,10 @@
#include <QFile>
#include <QLoggingCategory>
#include <QCommandLineParser>
#include <QtGui/private/qshader_p.h>
#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
#include <QOffscreenSurface>
#ifdef Q_OS_WIN
#include <QtGui/private/qrhid3d11_p.h>
#include <QtGui/private/qrhid3d12_p.h>
#endif
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
#include <QtGui/private/qrhimetal_p.h>
#endif
#include <rhi/qrhi.h>
//#define TEST_FINISH

View File

@ -5,7 +5,7 @@
#define EXAMPLEWIDGET_H
#include "rhiwidget.h"
#include <QtGui/private/qrhi_p.h>
#include <rhi/qrhi.h>
class ExampleRhiWidget : public QRhiWidget
{

View File

@ -5,7 +5,7 @@
#define RHIWIDGET_H
#include <QWidget>
#include <QtGui/private/qrhi_p.h>
#include <rhi/qrhi.h>
class QRhiWidgetPrivate;

View File

@ -13,28 +13,9 @@
#include <QTimer>
#include <QLoggingCategory>
#include <QColorSpace>
#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 <QtGui/private/qrhivulkan_p.h>
#endif
#ifdef Q_OS_WIN
#include <QtGui/private/qrhid3d11_p.h>
#include <QtGui/private/qrhid3d12_p.h>
#endif
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
#include <QtGui/private/qrhimetal_p.h>
#endif
#include <rhi/qrhi.h>
#ifdef EXAMPLEFW_IMGUI
#include "qrhiimgui_p.h"

View File

@ -4,7 +4,7 @@
#ifndef QRHIIMGUI_P_H
#define QRHIIMGUI_P_H
#include <QtGui/private/qrhi_p.h>
#include <rhi/qrhi.h>
QT_BEGIN_NAMESPACE

View File

@ -5,7 +5,7 @@
#include <QPlatformSurfaceEvent>
#include <QTimer>
#include <QFile>
#include <QtGui/private/qshader_p.h>
#include <rhi/qshader.h>
#include "../shared/cube.h"
Window::Window()

View File

@ -5,8 +5,8 @@
#define WINDOW_H
#include <QWindow>
#include <QtGui/private/qrhigles2_p.h>
#include <QOffscreenSurface>
#include <rhi/qrhi.h>
class Window : public QWindow
{

View File

@ -3,7 +3,7 @@
#include "quadrenderer.h"
#include <QFile>
#include <QtGui/private/qshader_p.h>
#include <rhi/qshader.h>
// Renders a quad using indexed drawing. No QRhiGraphicsPipeline is created, it
// expects to reuse the one created by TriangleRenderer. A separate

View File

@ -4,7 +4,7 @@
#ifndef QUADRENDERER_H
#define QUADRENDERER_H
#include <QtGui/private/qrhi_p.h>
#include <rhi/qrhi.h>
class QuadRenderer
{

View File

@ -3,7 +3,7 @@
#include "texturedcuberenderer.h"
#include <QFile>
#include <QtGui/private/qshader_p.h>
#include <rhi/qshader.h>
#include "../shared/cube.h"

View File

@ -4,7 +4,7 @@
#ifndef TEXTUREDCUBERENDERER_H
#define TEXTUREDCUBERENDERER_H
#include <QtGui/private/qrhi_p.h>
#include <rhi/qrhi.h>
class TexturedCubeRenderer
{

View File

@ -3,7 +3,7 @@
#include "triangleoncuberenderer.h"
#include <QFile>
#include <QtGui/private/qshader_p.h>
#include <rhi/qshader.h>
// toggle to test the preserved content (no clear) path
const bool IMAGE_UNDER_OFFSCREEN_RENDERING = false;

View File

@ -3,7 +3,7 @@
#include "trianglerenderer.h"
#include <QFile>
#include <QtGui/private/qshader_p.h>
#include <rhi/qshader.h>
//#define VBUF_IS_DYNAMIC

View File

@ -4,7 +4,7 @@
#ifndef TRIANGLERENDERER_H
#define TRIANGLERENDERER_H
#include <QtGui/private/qrhi_p.h>
#include <rhi/qrhi.h>
class TriangleRenderer
{

View File

@ -7,7 +7,7 @@
#include <QtGui/qguiapplication.h>
#include <QtGui/qoffscreensurface.h>
#include <QtGui/qpa/qwindowsysteminterface.h>
#include <QtGui/private/qrhigles2_p.h>
#include <QtGui/rhi/qrhi.h>
#include <qtwasmtestlib.h>