1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qrhi_p.h"
5#include <qmath.h>
6#include <QLoggingCategory>
7
8#include "qrhinull_p.h"
9#ifndef QT_NO_OPENGL
10#include "qrhigles2_p.h"
11#endif
12#if QT_CONFIG(vulkan)
13#include "qrhivulkan_p.h"
14#endif
15#ifdef Q_OS_WIN
16#include "qrhid3d11_p.h"
17#include "qrhid3d12_p.h"
18#endif
19#if QT_CONFIG(metal)
20#include "qrhimetal_p.h"
21#endif
22
23#include <memory>
24
25QT_BEGIN_NAMESPACE
26
27Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
28Q_LOGGING_CATEGORY(QRHI_LOG_RUB, "qt.rhi.rub")
29
30/*!
31 \class QRhi
32 \ingroup painting-3D
33 \inmodule QtGuiPrivate
34 \inheaderfile rhi/qrhi.h
35 \since 6.6
36
37 \brief Accelerated 2D/3D graphics API abstraction.
38
39 The Qt Rendering Hardware Interface is an abstraction for hardware accelerated
40 graphics APIs, such as, \l{https://www.khronos.org/opengl/}{OpenGL},
41 \l{https://www.khronos.org/opengles/}{OpenGL ES},
42 \l{https://docs.microsoft.com/en-us/windows/desktop/direct3d}{Direct3D},
43 \l{https://developer.apple.com/metal/}{Metal}, and
44 \l{https://www.khronos.org/vulkan/}{Vulkan}.
45
46 \warning The QRhi family of classes in the Qt Gui module, including QShader
47 and QShaderDescription, offer limited compatibility guarantees. There are
48 no source or binary compatibility guarantees for these classes, meaning the
49 API is only guaranteed to work with the Qt version the application was
50 developed against. Source incompatible changes are however aimed to be kept
51 at a minimum and will only be made in minor releases (6.7, 6.8, and so on).
52 To use these classes in an application, link to
53 \c{Qt::GuiPrivate} (if using CMake), and include the headers with the \c
54 rhi prefix, for example \c{#include <rhi/qrhi.h>}.
55
56 Each QRhi instance is backed by a backend for a specific graphics API. The
57 selection of the backend is a run time choice and is up to the application
58 or library that creates the QRhi instance. Some backends are available on
59 multiple platforms (OpenGL, Vulkan, Null), while APIs specific to a given
60 platform are only available when running on the platform in question (Metal
61 on macOS/iOS, Direct3D on Windows).
62
63 The available backends currently are:
64
65 \list
66
67 \li OpenGL 2.1 / OpenGL ES 2.0 or newer. Some extensions and newer core
68 specification features are utilized when present, for example to enable
69 multisample framebuffers or compute shaders. Operating in core profile
70 contexts is supported as well. If necessary, applications can query the
71 \l{QRhi::Feature}{feature flags} at runtime to check for features that are
72 not supported in the OpenGL context backing the QRhi. The OpenGL backend
73 builds on QOpenGLContext, QOpenGLFunctions, and the related cross-platform
74 infrastructure of the Qt GUI module.
75
76 \li Direct3D 11.2 and newer (with DXGI 1.3 and newer), using Shader Model
77 5.0 or newer. When the D3D runtime has no support for 11.2 features or
78 Shader Model 5.0, initialization using an accelerated graphics device will
79 fail, but using the
80 \l{https://learn.microsoft.com/en-us/windows/win32/direct3darticles/directx-warp}{software
81 adapter} is still an option.
82
83 \li Direct3D 12 on Windows 10 version 1703 and newer, with Shader Model 5.0
84 or newer. Qt requires ID3D12Device2 to be present, hence the requirement
85 for at least version 1703 of Windows 10. The D3D12 device is by default
86 created with specifying a minimum feature level of
87 \c{D3D_FEATURE_LEVEL_11_0}.
88
89 \li Metal 1.2 or newer.
90
91 \li Vulkan 1.0 or newer, optionally utilizing some Vulkan 1.1 level
92 features.
93
94 \li Null, a "dummy" backend that issues no graphics calls at all.
95
96 \endlist
97
98 In order to allow shader code to be written once in Qt applications and
99 libraries, all shaders are expected to be written in a single language
100 which is then compiled into SPIR-V. Versions for various shading language
101 are then generated from that, together with reflection information (inputs,
102 outputs, shader resources). This is then packed into easily and efficiently
103 serializable QShader instances. The compilers and tools to generate such
104 shaders are not part of QRhi and the Qt GUI module, but the core classes
105 for using such shaders, QShader and QShaderDescription, are. The APIs and
106 tools for performing compilation and translation are part of the Qt Shader
107 Tools module.
108
109 See the \l{RHI Window Example} for an introductory example of creating a
110 portable, cross-platform application that performs accelerated 3D rendering
111 onto a QWindow using QRhi.
112
113 \section1 An Impression of the API
114
115 To provide a quick look at the API with a short yet complete example that
116 does not involve window-related setup, the following is a complete,
117 runnable cross-platform application that renders 20 frames off-screen, and
118 then saves the generated images to files after reading back the texture
119 contents from the GPU. For an example that renders on-screen, which then
120 involves setting up a QWindow and a swapchain, refer to the
121 \l{RHI Window Example}.
122
123 For brevity, the initialization of the QRhi is done based on the platform:
124 the sample code here chooses Direct 3D 12 on Windows, Metal on macOS and
125 iOS, and Vulkan otherwise. OpenGL and Direct 3D 11 are never used by this
126 application, but support for those could be introduced with a few
127 additional lines.
128
129 \snippet rhioffscreen/main.cpp 0
130
131 The result of the application is 20 \c PNG images (frame0.png -
132 frame19.png). These contain a rotating triangle with varying opacity over a
133 green background.
134
135 The vertex and fragment shaders are expected to be processed and packaged
136 into \c{.qsb} files. The Vulkan-compatible GLSL source code is the
137 following:
138
139 \e color.vert
140 \snippet rhioffscreen/color.vert 0
141
142 \e color.frag
143 \snippet rhioffscreen/color.frag 0
144
145 To manually compile and transpile these shaders to a number of targets
146 (SPIR-V, HLSL, MSL, GLSL) and generate the \c{.qsb} files the application
147 loads at run time, run \c{qsb --qt6 color.vert -o color.vert.qsb} and
148 \c{qsb --qt6 color.frag -o color.frag.qsb}. Alternatively, the Qt Shader
149 Tools module offers build system integration for CMake, the
150 \c qt_add_shaders() CMake function, that can achieve the same at build time.
151
152 \section1 Design Fundamentals
153
154 A QRhi cannot be instantiated directly. Instead, use the create()
155 function. Delete the QRhi instance normally to release the graphics device.
156
157 \section2 Resources
158
159 Instances of classes deriving from QRhiResource, such as, QRhiBuffer,
160 QRhiTexture, etc., encapsulate zero, one, or more native graphics
161 resources. Instances of such classes are always created via the \c new
162 functions of the QRhi, such as, newBuffer(), newTexture(),
163 newTextureRenderTarget(), newSwapChain().
164
165 \code
166 QRhiBuffer *vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData));
167 if (!vbuf->create()) { error(); }
168 // ...
169 delete vbuf;
170 \endcode
171
172 \list
173
174 \li The returned value from functions like newBuffer() is always owned by
175 the caller.
176
177 \li Just creating an instance of a QRhiResource subclass never allocates or
178 initializes any native resources. That is only done when calling the
179 \c create() function of a subclass, for example, QRhiBuffer::create() or
180 QRhiTexture::create().
181
182 \li The exceptions are
183 QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor(),
184 QRhiSwapChain::newCompatibleRenderPassDescriptor(), and
185 QRhiRenderPassDescriptor::newCompatibleRenderPassDescriptor(). There is no
186 \c create() operation for these and the returned object is immediately
187 active.
188
189 \li The resource objects themselves are treated as immutable: once a
190 resource has create() called, changing any parameters via the setters, such as,
191 QRhiTexture::setPixelSize(), has no effect, unless the underlying native
192 resource is released and \c create() is called again. See more about resource
193 reuse in the sections below.
194
195 \li The underlying native resources are scheduled for releasing by the
196 QRhiResource destructor, or by calling QRhiResource::destroy(). Backends
197 often queue release requests and defer executing them to an unspecified
198 time, this is hidden from the applications. This way applications do not
199 have to worry about releasing native resources that may still be in use by
200 an in-flight frame.
201
202 \li Note that this does not mean that a QRhiResource can freely be
203 destroy()'ed or deleted within a frame (that is, in a
204 \l{QRhi::beginFrame()}{beginFrame()} - \l{QRhi::endFrame()}{endFrame()}
205 section). As a general rule, all referenced QRhiResource objects must stay
206 unchanged until the frame is submitted by calling
207 \l{QRhi::endFrame()}{endFrame()}. To ease this,
208 QRhiResource::deleteLater() is provided as a convenience.
209
210 \endlist
211
212 \section2 Command buffers and deferred command execution
213
214 Regardless of the design and capabilities of the underlying graphics API,
215 all QRhi backends implement some level of command buffers. No
216 QRhiCommandBuffer function issues any native bind or draw command (such as,
217 \c glDrawElements) directly. Commands are always recorded in a queue,
218 either native or provided by the QRhi backend. The command buffer is
219 submitted, and so execution starts only upon QRhi::endFrame() or
220 QRhi::finish().
221
222 The deferred nature has consequences for some types of objects. For example,
223 writing to a dynamic buffer multiple times within a frame, in case such
224 buffers are backed by host-visible memory, will result in making the
225 results of all writes are visible to all draw calls in the command buffer
226 of the frame, regardless of when the dynamic buffer update was recorded
227 relative to a draw call.
228
229 Furthermore, instances of QRhiResource subclasses must be treated immutable
230 within a frame in which they are referenced in any way. Create
231 all resources upfront, before starting to record commands for the next
232 frame. Reusing a QRhiResource instance within a frame (by calling \c create()
233 then referencing it again in the same \c{beginFrame - endFrame} section)
234 should be avoided as it may lead to unexpected results, depending on the
235 backend.
236
237 As a general rule, all referenced QRhiResource objects must stay valid and
238 unmodified until the frame is submitted by calling
239 \l{QRhi::endFrame()}{endFrame()}. On the other hand, calling
240 \l{QRhiResource::destroy()}{destroy()} or deleting the QRhiResource are
241 always safe once the frame is submitted, regardless of the status of the
242 underlying native resources (which may still be in use by the GPU - but
243 that is taken care of internally).
244
245 Unlike APIs like OpenGL, upload and copy type of commands cannot be mixed
246 with draw commands. The typical renderer will involve a sequence similar to
247 the following:
248
249 \list
250 \li (re)create resources
251 \li begin frame
252 \li record/issue uploads and copies
253 \li start recording a render pass
254 \li record draw calls
255 \li end render pass
256 \li end frame
257 \endlist
258
259 Recording copy type of operations happens via QRhiResourceUpdateBatch. Such
260 operations are committed typically on
261 \l{QRhiCommandBuffer::beginPass()}{beginPass()}.
262
263 When working with legacy rendering engines designed for OpenGL, the
264 migration to QRhi often involves redesigning from having a single \c render
265 step (that performs copies and uploads, clears buffers, and issues draw
266 calls, all mixed together) to a clearly separated, two phase \c prepare -
267 \c render setup where the \c render step only starts a renderpass and
268 records draw calls, while all resource creation and queuing of updates,
269 uploads and copies happens beforehand, in the \c prepare step.
270
271 QRhi does not at the moment allow freely creating and submitting command
272 buffers. This may be lifted in the future to some extent, in particular if
273 compute support is introduced, but the model of well defined
274 \c{frame-start} and \c{frame-end} points, combined with a dedicated,
275 "frame" command buffer, where \c{frame-end} implies presenting, is going to
276 remain the primary way of operating since this is what fits Qt's various UI
277 technologies best.
278
279 \section2 Threading
280
281 A QRhi instance and the associated resources can be created and used on any
282 thread but all usage must be limited to that one single thread. When
283 rendering to multiple QWindows in an application, having a dedicated thread
284 and QRhi instance for each window is often advisable, as this can eliminate
285 issues with unexpected throttling caused by presenting to multiple windows.
286 Conceptually that is then the same as how Qt Quick scene graph's threaded
287 render loop operates when working directly with OpenGL: one thread for each
288 window, one QOpenGLContext for each thread. When moving onto QRhi,
289 QOpenGLContext is replaced by QRhi, making the migration straightforward.
290
291 When it comes to externally created native objects, such as OpenGL contexts
292 passed in via QRhiGles2NativeHandles, it is up to the application to ensure
293 they are not misused by other threads.
294
295 Resources are not shareable between QRhi instances. This is an intentional
296 choice since QRhi hides most queue, command buffer, and resource
297 synchronization related tasks, and provides no API for them. Safe and
298 efficient concurrent use of graphics resources from multiple threads is
299 tied to those concepts, however, and is thus a topic that is currently out
300 of scope, but may be introduced in the future.
301
302 \note The Metal backend requires that an autorelease pool is available on
303 the rendering thread, ideally wrapping each iteration of the render loop.
304 This needs no action from the users of QRhi when rendering on the main
305 (gui) thread, but becomes important when a separate, dedicated render
306 thread is used.
307
308 \section2 Resource synchronization
309
310 QRhi does not expose APIs for resource barriers or image layout
311 transitions. Such synchronization is done implicitly by the backends, where
312 applicable (for example, Vulkan), by tracking resource usage as necessary.
313 Buffer and image barriers are inserted before render or compute passes
314 transparently to the application.
315
316 \note Resources within a render or compute pass are expected to be bound to
317 a single usage during that pass. For example, a buffer can be used as
318 vertex, index, uniform, or storage buffer, but not a combination of them
319 within a single pass. However, it is perfectly fine to use a buffer as a
320 storage buffer in a compute pass, and then as a vertex buffer in a render
321 pass, for example, assuming the buffer declared both usages upon creation.
322
323 \note Textures have this rule relaxed in certain cases, because using two
324 subresources (typically two different mip levels) of the same texture for
325 different access (one for load, one for store) is supported even within the
326 same pass.
327
328 \section2 Resource reuse
329
330 From the user's point of view a QRhiResource is reusable immediately after
331 calling QRhiResource::destroy(). With the exception of swapchains, calling
332 \c create() on an already created object does an implicit \c destroy(). This
333 provides a handy shortcut to reuse a QRhiResource instance with different
334 parameters, with a new native graphics object underneath.
335
336 The importance of reusing the same object lies in the fact that some
337 objects reference other objects: for example, a QRhiShaderResourceBindings
338 can reference QRhiBuffer, QRhiTexture, and QRhiSampler instances. If in a
339 later frame one of these buffers need to be resized or a sampler parameter
340 needs changing, destroying and creating a whole new QRhiBuffer or
341 QRhiSampler would invalidate all references to the old instance. By just
342 changing the appropriate parameters via QRhiBuffer::setSize() or similar
343 and then calling QRhiBuffer::create(), everything works as expected and
344 there is no need to touch the QRhiShaderResourceBindings at all, even
345 though there is a good chance that under the hood the QRhiBuffer is now
346 backed by a whole new native buffer.
347
348 \code
349 QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256);
350 ubuf->create();
351
352 QRhiShaderResourceBindings *srb = rhi->newShaderResourceBindings()
353 srb->setBindings({
354 QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, ubuf)
355 });
356 srb->create();
357
358 // ...
359
360 // now in a later frame we need to grow the buffer to a larger size
361 ubuf->setSize(512);
362 ubuf->create(); // same as ubuf->destroy(); ubuf->create();
363
364 // srb needs no changes whatsoever, any references in it to ubuf
365 // stay valid. When it comes to internal details, such as that
366 // ubuf may now be backed by a completely different native buffer
367 // resource, that is is recognized and handled automatically by the
368 // next setShaderResources().
369 \endcode
370
371 QRhiTextureRenderTarget offers the same contract: calling
372 QRhiCommandBuffer::beginPass() is safe even when one of the render target's
373 associated textures or renderbuffers has been rebuilt (by calling \c
374 create() on it) since the creation of the render target object. This allows
375 the application to resize a texture by setting a new pixel size on the
376 QRhiTexture and calling create(), thus creating a whole new native texture
377 resource underneath, without having to update the QRhiTextureRenderTarget
378 as that will be done implicitly in beginPass().
379
380 \section2 Pooled objects
381
382 In addition to resources, there are pooled objects as well, such as,
383 QRhiResourceUpdateBatch. An instance is retrieved via a \c next function,
384 such as, nextResourceUpdateBatch(). The caller does not own the returned
385 instance in this case. The only valid way of operating here is calling
386 functions on the QRhiResourceUpdateBatch and then passing it to
387 QRhiCommandBuffer::beginPass() or QRhiCommandBuffer::endPass(). These
388 functions take care of returning the batch to the pool. Alternatively, a
389 batch can be "canceled" and returned to the pool without processing by
390 calling QRhiResourceUpdateBatch::release().
391
392 A typical pattern is thus:
393
394 \code
395 QRhiResourceUpdateBatch *resUpdates = rhi->nextResourceUpdateBatch();
396 // ...
397 resUpdates->updateDynamicBuffer(ubuf, 0, 64, mvp.constData());
398 if (!image.isNull()) {
399 resUpdates->uploadTexture(texture, image);
400 image = QImage();
401 }
402 // ...
403 QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
404 // note the last argument
405 cb->beginPass(swapchain->currentFrameRenderTarget(), clearCol, clearDs, resUpdates);
406 \endcode
407
408 \section2 Swapchain specifics
409
410 QRhiSwapChain features some special semantics due to the peculiar nature of
411 swapchains.
412
413 \list
414
415 \li It has no \c create() but rather a QRhiSwapChain::createOrResize().
416 Repeatedly calling this function is \b not the same as calling
417 QRhiSwapChain::destroy() followed by QRhiSwapChain::createOrResize(). This
418 is because swapchains often have ways to handle the case where buffers need
419 to be resized in a manner that is more efficient than a brute force
420 destroying and recreating from scratch.
421
422 \li An active QRhiSwapChain must be released by calling
423 \l{QRhiSwapChain::destroy()}{destroy()}, or by destroying the object, before
424 the QWindow's underlying QPlatformWindow, and so the associated native
425 window object, is destroyed. It should not be postponed because releasing
426 the swapchain may become problematic (and with some APIs, like Vulkan, is
427 explicitly disallowed) when the native window is not around anymore, for
428 example because the QPlatformWindow got destroyed upon getting a
429 QWindow::close(). Therefore, releasing the swapchain must happen whenever
430 the targeted QWindow sends the
431 QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed event. If the event does
432 not arrive before the destruction of the QWindow - this can happen when
433 using QCoreApplication::quit() -, then check QWindow::handle() after the
434 event loop exits and invoke the swapchain release when non-null (meaning
435 the underlying native window is still around).
436
437 \endlist
438
439 \section2 Ownership
440
441 The general rule is no ownership transfer. Creating a QRhi with an already
442 existing graphics device does not mean the QRhi takes ownership of the
443 device object. Similarly, ownership is not given away when a device or
444 texture object is "exported" via QRhi::nativeHandles() or
445 QRhiTexture::nativeTexture(). Most importantly, passing pointers in structs
446 and via setters does not transfer ownership.
447
448 \section1 Troubleshooting and Profiling
449
450 \section2 Error reporting
451
452 Functions such as \l QRhi::create() and the resource classes' \c create()
453 member functions (e.g., \l QRhiBuffer::create()) indicate failure with the
454 return value (\nullptr or
455 \c false, respectively). When working with QShader, \l QShader::fromSerialized()
456 returns an invalid QShader (for which \l{QShader::isValid()}{isValid()} returns
457 \c false) when the data passed to the function cannot be successfully deserialized.
458 Some functions, beginFrame() in particular, may also sometimes report "soft failures",
459 such as \l FrameOpSwapChainOutOfDate, which do not indicate an unrecoverable error,
460 but rather should be seen as a "try again later" response.
461
462 Warnings and errors may get printed at any time to the debug output via
463 qWarning(). It is therefore always advisable to inspect the output of the
464 application.
465
466 Additional debug messages can be enabled via the following logging
467 categories. Messages from these categories are not printed by default
468 unless explicitly enabled via QLoggingCategory or the \c QT_LOGGING_RULES
469 environment variable. For better interoperation with Qt Quick, the
470 environment variable \c{QSG_INFO} also enables these debug prints.
471
472 \list
473 \li \c{qt.rhi.general}
474 \endlist
475
476 Additionally, applications can query the \l{QRhi::backendName()}{QRhi
477 backend name} and
478 \l{QRhi::driverInfo()}{graphics device information} from a successfully
479 initialized QRhi. This can then be printed to the user or stored in the
480 application logs even in production builds, if desired.
481
482 \section2 Investigating rendering problems
483
484 When the rendering results are not as expected, or the application is
485 experiencing problems, always consider checking with the the native 3D
486 APIs' debug and validation facilities. QRhi itself features limited error
487 checking since replicating the already existing, vast amount of
488 functionality in the underlying layers is not reasonable.
489
490 \list
491
492 \li For Vulkan, controlling the
493 \l{https://github.com/KhronosGroup/Vulkan-ValidationLayers}{Vulkan
494 Validation Layers} is not in the scope of the QRhi, but rather can be
495 achieved by configuring the \l QVulkanInstance with the appropriate layers.
496 For example, call \c{instance.setLayers({ "VK_LAYER_KHRONOS_validation" });}
497 before invoking \l{QVulkanInstance::create()}{create()} on the QVulkanInstance.
498 (note that this assumes that the validation layers are actually installed
499 and available, e.g. from the Vulkan SDK) By default, QVulkanInstance conveniently
500 redirects the Vulkan debug messages to qDebug, meaning the validation messages get
501 printed just like other Qt warnings.
502
503 \li With Direct 3D 11 and 12, a graphics device with the debug layer
504 enabled can be requested by toggling the \c enableDebugLayer flag in the
505 appropriate \l{QRhiD3D11InitParams}{init params struct}. The messages appear on the
506 debug output, which is visible in Qt Creator's messages panel or via a tool
507 such as \l{https://learn.microsoft.com/en-us/sysinternals/downloads/debugview}{DebugView}.
508
509 \li For Metal, controlling Metal Validation is outside of QRhi's scope.
510 Rather, to enable validation, run the application with the environment
511 variable \c{METAL_DEVICE_WRAPPER_TYPE=1} set, or run the application within
512 XCode. There may also be further settings and environment variable in modern
513 XCode and macOS versions. See for instance
514 \l{https://developer.apple.com/documentation/metal/diagnosing_metal_programming_issues_early}{this
515 page}.
516
517 \endlist
518
519 \section2 Frame captures and performance profiling
520
521 A Qt application rendering with QRhi to a window while relying on a 3D API
522 under the hood, is, from the windowing and graphics pipeline perspective at
523 least, no different from any other (non-Qt) applications using the same 3D
524 API. This means that tools and practices for debugging and profiling
525 applications involving 3D graphics, such as games, all apply to such a Qt
526 application as well.
527
528 A few examples of tools that can provide insights into the rendering
529 internals of Qt applications that use QRhi, which includes Qt Quick and Qt
530 Quick 3D based projects as well:
531
532 \list
533
534 \li \l{https://renderdoc.org/}{RenderDoc} allows taking frame captures and
535 introspecting the recorded commands and pipeline state on Windows and Linux
536 for applications using OpenGL, Vulkan, D3D11, or D3D12. When trying to
537 figure out why some parts of the 3D scene do not show up as expected,
538 RenderDoc is often a fast and efficient way to check the pipeline stages
539 and the related state and discover the missing or incorrect value. It is
540 also a tool that is actively used when developing Qt itself.
541
542 \li For NVIDIA-based systems,
543 \l{https://developer.nvidia.com/nsight-graphics}{Nsight Graphics} provides
544 a graphics debugger tool on Windows and Linux. In addition to investigating the commands
545 in the frame and the pipeline, the vendor-specific tools allow looking at timings and
546 hardware performance information, which is not something simple frame captures can provide.
547
548 \li For AMD-based systems, the \l{https://gpuopen.com/rgp/}{Radeon GPU
549 Profiler} can be used to gain deeper insights into the application's
550 rendering and its performance.
551
552 \li As QRhi supports Direct 3D 12, using
553 \l{https://devblogs.microsoft.com/pix/download/}{PIX}, a performance tuning
554 and debugging tool for DirectX 12 games on Windows is an option as well.
555
556 \li On macOS,
557 \l{https://developer.apple.com/documentation/metal/debugging_tools/viewing_your_gpu_workload_with_the_metal_debugger}{the
558 XCode Metal debugger} can be used to take and introspect frame
559 captures, to investigate performance details, and debug shaders. In macOS 13 it is also possible
560 to enable an overlay that displays frame rate and other information for any Metal-based window by
561 setting the environment variable \c{MTL_HUD_ENABLED=1}.
562
563 \endlist
564
565 On mobile and embedded platforms, there may be vendor and platform-specific
566 tools, provided by the GPU or SoC vendor, available to perform performance
567 profiling of application using OpenGL ES or Vulkan.
568
569 When capturing frames, remember that objects and groups of commands can be
570 named via debug markers, as long as \l{QRhi::EnableDebugMarkers}{debug
571 markers were enabled} for the QRhi, and the graphics API in use supports
572 this. To annotate the command stream, call
573 \l{QRhiCommandBuffer::debugMarkBegin()}{debugMarkBegin()},
574 \l{QRhiCommandBuffer::debugMarkEnd()}{debugMarkEnd()} and/or
575 \l{QRhiCommandBuffer::debugMarkMsg()}{debugMarkMsg()}.
576 This can be particularly useful in larger frames with multiple render passes.
577 Resources are named by calling \l{QRhiResource::setName()}{setName()} before create().
578
579 To perform basic timing measurements on the CPU and GPU side within the
580 application, \l QElapsedTimer and
581 \l QRhiCommandBuffer::lastCompletedGpuTime() can be used. The latter is
582 only available with select graphics APIs at the moment and requires opting
583 in via the \l QRhi::EnableTimestamps flag.
584
585 \section2 Resource leak checking
586
587 When destroying a QRhi object without properly destroying all buffers,
588 textures, and other resources created from it, warnings about this are
589 printed to the debug output whenever the application is a debug build, or
590 when the \c QT_RHI_LEAK_CHECK environment variable is set to a non-zero
591 value. This is a simple way to discover design issues around resource
592 handling within the application rendering logic. Note however that some
593 platforms and underlying graphics APIs may perform their own allocation and
594 resource leak detection as well, over which Qt will have no direct control.
595 For example, when using Vulkan, the memory allocator may raise failing
596 assertions in debug builds when resources that own graphics memory
597 allocations are not destroyed before the QRhi. In addition, the Vulkan
598 validation layer, when enabled, will issue warnings about native graphics
599 resources that were not released. Similarly, with Direct 3D warnings may
600 get printed about unreleased COM objects when the application does not
601 destroy the QRhi and its resources in the correct order.
602
603 \sa {RHI Window Example}, QRhiCommandBuffer, QRhiResourceUpdateBatch,
604 QRhiShaderResourceBindings, QShader, QRhiBuffer, QRhiTexture,
605 QRhiRenderBuffer, QRhiSampler, QRhiTextureRenderTarget,
606 QRhiGraphicsPipeline, QRhiComputePipeline, QRhiSwapChain
607 */
608
609/*!
610 \enum QRhi::Implementation
611 Describes which graphics API-specific backend gets used by a QRhi instance.
612
613 \value Null
614 \value Vulkan
615 \value OpenGLES2
616 \value D3D11
617 \value D3D12
618 \value Metal
619 */
620
621/*!
622 \enum QRhi::Flag
623 Describes what special features to enable.
624
625 \value EnableDebugMarkers Enables debug marker groups. Without this frame
626 debugging features like making debug groups and custom resource name
627 visible in external GPU debugging tools will not be available and functions
628 like QRhiCommandBuffer::debugMarkBegin() will become no-ops. Avoid enabling
629 in production builds as it may involve a small performance impact. Has no
630 effect when the QRhi::DebugMarkers feature is not reported as supported.
631
632 \value EnableTimestamps Enables GPU timestamp collection. When not set,
633 QRhiCommandBuffer::lastCompletedGpuTime() always returns 0. Enable this
634 only when needed since there may be a small amount of extra work involved
635 (e.g. timestamp queries), depending on the underlying graphics API. Has no
636 effect when the QRhi::Timestamps feature is not reported as supported.
637
638 \value PreferSoftwareRenderer Indicates that backends should prefer
639 choosing an adapter or physical device that renders in software on the CPU.
640 For example, with Direct3D there is typically a "Basic Render Driver"
641 adapter available with \c{DXGI_ADAPTER_FLAG_SOFTWARE}. Setting this flag
642 requests the backend to choose that adapter over any other, as long as no
643 specific adapter was forced by other backend-specific means. With Vulkan
644 this maps to preferring physical devices with
645 \c{VK_PHYSICAL_DEVICE_TYPE_CPU}. When not available, or when it is not
646 possible to decide if an adapter/device is software-based, this flag is
647 ignored. It may also be ignored with graphics APIs that have no concept and
648 means of enumerating adapters/devices.
649
650 \value EnablePipelineCacheDataSave Enables retrieving the pipeline cache
651 contents, where applicable. When not set, pipelineCacheData() will return
652 an empty blob always. With backends where retrieving and restoring the
653 pipeline cache contents is not supported, the flag has no effect and the
654 serialized cache data is always empty. The flag provides an opt-in
655 mechanism because the cost of maintaining the related data structures is
656 not insignificant with some backends. With Vulkan this feature maps
657 directly to VkPipelineCache, vkGetPipelineCacheData and
658 VkPipelineCacheCreateInfo::pInitialData. With Direct3D 11 there is no real
659 pipline cache, but the results of HLSL->DXBC compilations are stored and
660 can be serialized/deserialized via this mechanism. This allows skipping the
661 time consuming D3DCompile() in future runs of the applications for shaders
662 that come with HLSL source instead of offline pre-compiled bytecode. This
663 can provide a huge boost in startup and load times, if there is a lot of
664 HLSL source compilation happening. With OpenGL the "pipeline cache" is
665 simulated by retrieving and loading shader program binaries (if supported
666 by the driver). With OpenGL there are additional, disk-based caching
667 mechanisms for shader/program binaries provided by Qt. Writing to those may
668 get disabled whenever this flag is set since storing program binaries to
669 multiple caches is not sensible.
670
671 \value SuppressSmokeTestWarnings Indicates that, with backends where this
672 is relevant, certain, non-fatal QRhi::create() failures should not
673 produce qWarning() calls. For example, with D3D11, passing this flag
674 makes a number of warning messages (that appear due to QRhi::create()
675 failing) to become categorized debug prints instead under the commonly used
676 \c{qt.rhi.general} logging category. This can be used by engines, such as
677 Qt Quick, that feature fallback logic, i.e. they retry calling create()
678 with a different set of flags (such as, \l PreferSoftwareRenderer), in order
679 to hide the unconditional warnings from the output that would be printed
680 when the first create() attempt had failed.
681 */
682
683/*!
684 \enum QRhi::FrameOpResult
685 Describes the result of operations that can have a soft failure.
686
687 \value FrameOpSuccess Success
688
689 \value FrameOpError Unspecified error
690
691 \value FrameOpSwapChainOutOfDate The swapchain is in an inconsistent state
692 internally. This can be recoverable by attempting to repeat the operation
693 (such as, beginFrame()) later.
694
695 \value FrameOpDeviceLost The graphics device was lost. This can be
696 recoverable by attempting to repeat the operation (such as, beginFrame())
697 after releasing and reinitializing all objects backed by native graphics
698 resources. See isDeviceLost().
699 */
700
701/*!
702 \enum QRhi::Feature
703 Flag values to indicate what features are supported by the backend currently in use.
704
705 \value MultisampleTexture Indicates that textures with a sample count larger
706 than 1 are supported. In practice this feature will be unsupported with
707 OpenGL ES versions older than 3.1, and OpenGL older than 3.0.
708
709 \value MultisampleRenderBuffer Indicates that renderbuffers with a sample
710 count larger than 1 are supported. In practice this feature will be
711 unsupported with OpenGL ES 2.0, and may also be unsupported with OpenGL 2.x
712 unless the relevant extensions are present.
713
714 \value DebugMarkers Indicates that debug marker groups (and so
715 QRhiCommandBuffer::debugMarkBegin()) are supported.
716
717 \value Timestamps Indicates that command buffer timestamps are supported.
718 Relevant for QRhiCommandBuffer::lastCompletedGpuTime(). This can be
719 expected to be supported on Metal, Vulkan, Direct 3D 11 and 12, and OpenGL
720 contexts of version 3.3 or newer. However, with some of these APIs support
721 for timestamp queries is technically optional, and therefore it cannot be
722 guaranteed that this feature is always supported with every implementation
723 of them.
724
725 \value Instancing Indicates that instanced drawing is supported. In
726 practice this feature will be unsupported with OpenGL ES 2.0 and OpenGL
727 3.2 or older.
728
729 \value CustomInstanceStepRate Indicates that instance step rates other
730 than 1 are supported. In practice this feature will always be unsupported
731 with OpenGL. In addition, running with Vulkan 1.0 without
732 VK_EXT_vertex_attribute_divisor will also lead to reporting false for this
733 feature.
734
735 \value PrimitiveRestart Indicates that restarting the assembly of
736 primitives when encountering an index value of 0xFFFF
737 (\l{QRhiCommandBuffer::IndexUInt16}{IndexUInt16}) or 0xFFFFFFFF
738 (\l{QRhiCommandBuffer::IndexUInt32}{IndexUInt32}) is enabled, for certain
739 primitive topologies at least. QRhi will try to enable this with all
740 backends, but in some cases it will not be supported. Dynamically
741 controlling primitive restart is not possible since with some APIs
742 primitive restart with a fixed index is always on. Applications must assume
743 that whenever this feature is reported as supported, the above mentioned
744 index values \c may be treated specially, depending on the topology. The
745 only two topologies where primitive restart is guaranteed to behave
746 identically across backends, as long as this feature is reported as
747 supported, are \l{QRhiGraphicsPipeline::LineStrip}{LineStrip} and
748 \l{QRhiGraphicsPipeline::TriangleStrip}{TriangleStrip}.
749
750 \value NonDynamicUniformBuffers Indicates that creating buffers with the
751 usage \l{QRhiBuffer::UniformBuffer}{UniformBuffer} and the types
752 \l{QRhiBuffer::Immutable}{Immutable} or \l{QRhiBuffer::Static}{Static} is
753 supported. When reported as unsupported, uniform (constant) buffers must be
754 created as \l{QRhiBuffer::Dynamic}{Dynamic}. (which is recommended
755 regardless)
756
757 \value NonFourAlignedEffectiveIndexBufferOffset Indicates that effective
758 index buffer offsets (\c{indexOffset + firstIndex * indexComponentSize})
759 that are not 4 byte aligned are supported. When not supported, attempting
760 to issue a \l{QRhiCommandBuffer::drawIndexed()}{drawIndexed()} with a
761 non-aligned effective offset may lead to unspecified behavior. Relevant in
762 particular for Metal, where this will be reported as unsupported.
763
764 \value NPOTTextureRepeat Indicates that the
765 \l{QRhiSampler::Repeat}{Repeat} wrap mode and mipmap filtering modes are
766 supported for textures with a non-power-of-two size. In practice this can
767 only be false with OpenGL ES 2.0 implementations without
768 \c{GL_OES_texture_npot}.
769
770 \value RedOrAlpha8IsRed Indicates that the
771 \l{QRhiTexture::RED_OR_ALPHA8}{RED_OR_ALPHA8} format maps to a one
772 component 8-bit \c red format. This is the case for all backends except
773 OpenGL when using either OpenGL ES or a non-core profile context. There
774 \c{GL_ALPHA}, a one component 8-bit \c alpha format, is used
775 instead. Using the special texture format allows having a single code
776 path for creating textures, leaving it up to the backend to decide the
777 actual format, while the feature flag can be used to pick the
778 appropriate shader variant for sampling the texture.
779
780 \value ElementIndexUint Indicates that 32-bit unsigned integer elements are
781 supported in the index buffer. In practice this is true everywhere except
782 when running on plain OpenGL ES 2.0 implementations without the necessary
783 extension. When false, only 16-bit unsigned elements are supported in the
784 index buffer.
785
786 \value Compute Indicates that compute shaders, image load/store, and
787 storage buffers are supported. OpenGL older than 4.3 and OpenGL ES older
788 than 3.1 have no compute support.
789
790 \value WideLines Indicates that lines with a width other than 1 are
791 supported. When reported as not supported, the line width set on the
792 graphics pipeline state is ignored. This can always be false with some
793 backends (D3D11, D3D12, Metal). With Vulkan, the value depends on the
794 implementation. With OpenGL, wide lines are not supported in core profile
795 contexts.
796
797 \value VertexShaderPointSize Indicates that the size of rasterized points
798 set via \c{gl_PointSize} in the vertex shader is taken into account. When
799 reported as not supported, drawing points with a size other than 1 is not
800 supported. Setting \c{gl_PointSize} in the shader is still valid then, but
801 is ignored. (for example, when generating HLSL, the assignment is silently
802 dropped from the generated code) Note that some APIs (Metal, Vulkan)
803 require the point size to be set in the shader explicitly whenever drawing
804 points, even when the size is 1, as they do not automatically default to 1.
805
806 \value BaseVertex Indicates that
807 \l{QRhiCommandBuffer::drawIndexed()}{drawIndexed()} supports the \c
808 vertexOffset argument. When reported as not supported, the vertexOffset
809 value in an indexed draw is ignored. In practice this feature will be
810 unsupported with OpenGL and OpenGL ES versions lower than 3.2, and with
811 Metal on older iOS devices, including the iOS Simulator.
812
813 \value BaseInstance Indicates that instanced draw commands support the \c
814 firstInstance argument. When reported as not supported, the firstInstance
815 value is ignored and the instance ID starts from 0. In practice this feature
816 will be unsupported with OpenGL, and with Metal on older iOS devices,
817 including the iOS Simulator.
818
819 \value TriangleFanTopology Indicates that QRhiGraphicsPipeline::setTopology()
820 supports QRhiGraphicsPipeline::TriangleFan. In practice this feature will be
821 unsupported with Metal and Direct 3D 11/12.
822
823 \value ReadBackNonUniformBuffer Indicates that
824 \l{QRhiResourceUpdateBatch::readBackBuffer()}{reading buffer contents} is
825 supported for QRhiBuffer instances with a usage different than
826 UniformBuffer. In practice this feature will be unsupported with OpenGL ES
827 2.0.
828
829 \value ReadBackNonBaseMipLevel Indicates that specifying a mip level other
830 than 0 is supported when reading back texture contents. When not supported,
831 specifying a non-zero level in QRhiReadbackDescription leads to returning
832 an all-zero image. In practice this feature will be unsupported with OpenGL
833 ES 2.0.
834
835 \value TexelFetch Indicates that texelFetch() and textureLod() are available
836 in shaders. In practice this will be reported as unsupported with OpenGL ES
837 2.0 and OpenGL 2.x contexts, because GLSL 100 es and versions before 130 do
838 not support these functions.
839
840 \value RenderToNonBaseMipLevel Indicates that specifying a mip level other
841 than 0 is supported when creating a QRhiTextureRenderTarget with a
842 QRhiTexture as its color attachment. When not supported, create() will fail
843 whenever the target mip level is not zero. In practice this feature will be
844 unsupported with OpenGL ES 2.0.
845
846 \value IntAttributes Indicates that specifying input attributes with
847 signed and unsigned integer types for a shader pipeline is supported. When
848 not supported, build() will succeed but just show a warning message and the
849 values of the target attributes will be broken. In practice this feature
850 will be unsupported with OpenGL ES 2.0 and OpenGL 2.x.
851
852 \value ScreenSpaceDerivatives Indicates that functions such as dFdx(),
853 dFdy(), and fwidth() are supported in shaders. In practice this feature will
854 be unsupported with OpenGL ES 2.0 without the GL_OES_standard_derivatives
855 extension.
856
857 \value ReadBackAnyTextureFormat Indicates that reading back texture
858 contents can be expected to work for any QRhiTexture::Format. Backends
859 other than OpenGL can be expected to return true for this feature. When
860 reported as false, which will typically happen with OpenGL, only the
861 formats QRhiTexture::RGBA8 and QRhiTexture::BGRA8 are guaranteed to be
862 supported for readbacks. In addition, with OpenGL, but not OpenGL ES,
863 reading back the 1 byte per component formats QRhiTexture::R8 and
864 QRhiTexture::RED_OR_ALPHA8 are supported as well. Reading back floating
865 point formats QRhiTexture::RGBA16F and RGBA32F may work too with OpenGL, as
866 long as the implementation provides support for these, but QRhi can give no
867 guarantees, as indicated by this flag.
868
869 \value PipelineCacheDataLoadSave Indicates that the pipelineCacheData() and
870 setPipelineCacheData() functions are functional. When not supported, the
871 functions will not perform any action, the retrieved blob is always empty,
872 and thus no benefits can be expected from retrieving and, during a
873 subsequent run of the application, reloading the pipeline cache content.
874
875 \value ImageDataStride Indicates that specifying a custom stride (row
876 length) for raw image data in texture uploads is supported. When not
877 supported (which can happen when the underlying API is OpenGL ES 2.0 without
878 support for GL_UNPACK_ROW_LENGTH),
879 QRhiTextureSubresourceUploadDescription::setDataStride() must not be used.
880
881 \value RenderBufferImport Indicates that QRhiRenderBuffer::createFrom() is
882 supported. For most graphics APIs this is not sensible because
883 QRhiRenderBuffer encapsulates texture objects internally, just like
884 QRhiTexture. With OpenGL however, renderbuffer object exist as a separate
885 object type in the API, and in certain environments (for example, where one
886 may want to associated a renderbuffer object with an EGLImage object) it is
887 important to allow wrapping an existing OpenGL renderbuffer object with a
888 QRhiRenderBuffer.
889
890 \value ThreeDimensionalTextures Indicates that 3D textures are supported.
891 In practice this feature will be unsupported with OpenGL and OpenGL ES
892 versions lower than 3.0.
893
894 \value RenderTo3DTextureSlice Indicates that rendering to a slice in a 3D
895 texture is supported. This can be unsupported with Vulkan 1.0 due to
896 relying on VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT which is a Vulkan 1.1
897 feature.
898
899 \value TextureArrays Indicates that texture arrays are supported and
900 QRhi::newTextureArray() is functional. Note that even when texture arrays
901 are not supported, arrays of textures are still available as those are two
902 independent features.
903
904 \value Tessellation Indicates that the tessellation control and evaluation
905 stages are supported. When reported as supported, the topology of a
906 QRhiGraphicsPipeline can be set to
907 \l{QRhiGraphicsPipeline::Patches}{Patches}, the number of control points
908 can be set via
909 \l{QRhiGraphicsPipeline::setPatchControlPointCount()}{setPatchControlPointCount()},
910 and shaders for tessellation control and evaluation can be specified in the
911 QRhiShaderStage list. Tessellation shaders have portability issues between
912 APIs (for example, translating GLSL/SPIR-V to HLSL is problematic due to
913 the way hull shaders are structured, whereas Metal uses a somewhat
914 different tessellation pipeline than others), and therefore unexpected
915 issues may still arise, even though basic functionality is implemented
916 across all the underlying APIs. For Direct 3D in particular, handwritten
917 HLSL hull and domain shaders must be injected into each QShader for the
918 tessellation control and evaluation stages, respectively, since qsb cannot
919 generate these from SPIR-V. Note that isoline tessellation should be
920 avoided as it will not be supported by all backends. The maximum patch
921 control point count portable between backends is 32.
922
923 \value GeometryShader Indicates that the geometry shader stage is
924 supported. When supported, a geometry shader can be specified in the
925 QRhiShaderStage list. Geometry Shaders are considered an experimental
926 feature in QRhi and can only be expected to be supported with Vulkan,
927 Direct 3D, OpenGL (3.2+) and OpenGL ES (3.2+), assuming the implementation
928 reports it as supported at run time. Geometry shaders have portability
929 issues between APIs, and therefore no guarantees can be given for a
930 universal solution. They will never be supported with Metal. Whereas with
931 Direct 3D a handwritten HLSL geometry shader must be injected into each
932 QShader for the geometry stage since qsb cannot generate this from SPIR-V.
933
934 \value TextureArrayRange Indicates that for
935 \l{QRhi::newTextureArray()}{texture arrays} it is possible to specify a
936 range that is exposed to the shaders. Normally all array layers are exposed
937 and it is up to the shader to select the layer (via the third coordinate
938 passed to texture() when sampling the \c sampler2DArray). When supported,
939 calling QRhiTexture::setArrayRangeStart() and
940 QRhiTexture::setArrayRangeLength() before
941 \l{QRhiTexture::create()}{building} or
942 \l{QRhiTexture::createFrom()}{importing} the native texture has an effect,
943 and leads to selecting only the specified range from the array. This will
944 be necessary in special cases, such as when working with accelerated video
945 decoding and Direct 3D 11, because a texture array with both
946 \c{D3D11_BIND_DECODER} and \c{D3D11_BIND_SHADER_RESOURCE} on it is only
947 usable as a shader resource if a single array layer is selected. Note that
948 all this is applicable only when the texture is used as a
949 QRhiShaderResourceBinding::SampledTexture or
950 QRhiShaderResourceBinding::Texture shader resource, and is not compatible
951 with image load/store. This feature is only available with some backends as
952 it does not map well to all graphics APIs, and it is only meant to provide
953 support for special cases anyhow. In practice the feature can be expected to
954 be supported with Direct3D 11/12 and Vulkan.
955
956 \value NonFillPolygonMode Indicates that setting a PolygonMode other than
957 the default Fill is supported for QRhiGraphicsPipeline. A common use case
958 for changing the mode to Line is to get wireframe rendering. This however
959 is not available as a core OpenGL ES feature, and is optional with Vulkan
960 as well as some mobile GPUs may not offer the feature.
961
962 \value OneDimensionalTextures Indicates that 1D textures are supported.
963 In practice this feature will be unsupported on OpenGL ES.
964
965 \value OneDimensionalTextureMipmaps Indicates that generating 1D texture
966 mipmaps are supported. In practice this feature will be unsupported on
967 backends that do not report support for
968 \l{OneDimensionalTextures}, Metal, and Direct 3D 12.
969
970 \value HalfAttributes Indicates that specifying input attributes with half
971 precision (16bit) floating point types for a shader pipeline is supported.
972 When not supported, build() will succeed but just show a warning message
973 and the values of the target attributes will be broken. In practice this
974 feature will be unsupported in some OpenGL ES 2.0 and OpenGL 2.x
975 implementations. Note that while Direct3D 11/12 does support half precision
976 input attributes, it does not support the half3 type. The D3D backends pass
977 half3 attributes as half4. To ensure cross platform compatibility, half3
978 inputs should be padded to 8 bytes.
979
980 \value RenderToOneDimensionalTexture Indicates that 1D texture render
981 targets are supported. In practice this feature will be unsupported on
982 backends that do not report support for
983 \l{OneDimensionalTextures}, and Metal.
984
985 \value ThreeDimensionalTextureMipmaps Indicates that generating 3D texture
986 mipmaps are supported. In practice this feature will be unsupported with
987 Direct 3D 12.
988
989 \value MultiView Indicates that multiview, see e.g.
990 \l{https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_multiview.html}{VK_KHR_multiview}
991 is supported. With OpenGL ES 2.0, Direct 3D 11, and OpenGL (ES)
992 implementations without \c{GL_OVR_multiview2} this feature will not be
993 supported. With Vulkan 1.1 and newer, and Direct 3D 12 multiview is
994 typically supported. When reported as supported, creating a
995 QRhiTextureRenderTarget with a QRhiColorAttachment that references a texture
996 array and has \l{QRhiColorAttachment::setMultiViewCount()}{multiViewCount}
997 set enables recording a render pass that uses multiview rendering. In addition,
998 any QRhiGraphicsPipeline used in that render pass must have
999 \l{QRhiGraphicsPipeline::setMultiViewCount()}{the same view count set}. Note that
1000 multiview is only available in combination with 2D texture arrays. It cannot
1001 be used to optimize the rendering into individual textures (e.g. two, for
1002 the left and right eyes). Rather, the target of a multiview render pass is
1003 always a texture array, automatically rendering to the layer (array element)
1004 corresponding to each view. Therefore this feature implies \l TextureArrays
1005 as well. Multiview rendering is not supported in combination with
1006 tessellation or geometry shaders. See QRhiColorAttachment::setMultiViewCount()
1007 for further details on multiview rendering. This enum value has been introduced in Qt 6.7.
1008
1009 \value TextureViewFormat Indicates that setting a
1010 \l{QRhiTexture::setWriteViewFormat()}{view format} on a QRhiTexture is
1011 effective. When reported as supported, setting the read (sampling) or write
1012 (render target / image load-store) view mode changes the texture's viewing
1013 format. When unsupported, setting a view format has no effect. Note that Qt
1014 has no knowledge or control over format compatibility or resource view rules
1015 in the underlying 3D API and its implementation. Passing in unsuitable,
1016 incompatible formats may lead to errors and unspecified behavior. This is
1017 provided mainly to allow "casting" rendering into a texture created with an
1018 sRGB format to non-sRGB to avoid the unwanted linear->sRGB conversion on
1019 shader writes. Other types of casting may or may not be functional,
1020 depending on the underlying API. Currently implemented for Vulkan and Direct
1021 3D 12. With D3D12 the feature is available only if
1022 \c CastingFullyTypedFormatSupported is supported, see
1023 \l{https://microsoft.github.io/DirectX-Specs/d3d/RelaxedCasting.html} (and
1024 note that QRhi always uses fully typed formats for textures.) This enum
1025 value has been introduced in Qt 6.8.
1026
1027 \value ResolveDepthStencil Indicates that resolving a multisample depth or
1028 depth-stencil texture is supported. Otherwise,
1029 \l{QRhiTextureRenderTargetDescription::setDepthResolveTexture()}{setting a
1030 depth resolve texture} is not functional and must be avoided. Direct 3D 11
1031 and 12 have no support for resolving depth/depth-stencil formats, and
1032 therefore this feature will never be supported with those. Vulkan 1.0 has no
1033 API to request resolving a depth-stencil attachment. Therefore, with Vulkan
1034 this feature will only be supported with Vulkan 1.2 and up, and on 1.1
1035 implementations with the appropriate extensions present. This feature is
1036 provided for the rare case when resolving into a non-multisample depth
1037 texture becomes necessary, for example when rendering into an
1038 OpenXR-provided depth texture (XR_KHR_composition_layer_depth). This enum
1039 value has been introduced in Qt 6.8.
1040 */
1041
1042/*!
1043 \enum QRhi::BeginFrameFlag
1044 Flag values for QRhi::beginFrame()
1045 */
1046
1047/*!
1048 \enum QRhi::EndFrameFlag
1049 Flag values for QRhi::endFrame()
1050
1051 \value SkipPresent Specifies that no present command is to be queued or no
1052 swapBuffers call is to be made. This way no image is presented. Generating
1053 multiple frames with all having this flag set is not recommended (except,
1054 for example, for benchmarking purposes - but keep in mind that backends may
1055 behave differently when it comes to waiting for command completion without
1056 presenting so the results are not comparable between them)
1057 */
1058
1059/*!
1060 \enum QRhi::ResourceLimit
1061 Describes the resource limit to query.
1062
1063 \value TextureSizeMin Minimum texture width and height. This is typically
1064 1. The minimum texture size is handled gracefully, meaning attempting to
1065 create a texture with an empty size will instead create a texture with the
1066 minimum size.
1067
1068 \value TextureSizeMax Maximum texture width and height. This depends on the
1069 graphics API and sometimes the platform or implementation as well.
1070 Typically the value is in the range 4096 - 16384. Attempting to create
1071 textures larger than this is expected to fail.
1072
1073 \value MaxColorAttachments The maximum number of color attachments for a
1074 QRhiTextureRenderTarget, in case multiple render targets are supported. When
1075 MRT is not supported, the value is 1. Otherwise this is typically 8, but
1076 watch out for the fact that OpenGL only mandates 4 as the minimum, and that
1077 is what some OpenGL ES implementations provide.
1078
1079 \value FramesInFlight The number of frames the backend may keep "in
1080 flight": with backends like Vulkan or Metal, it is the responsibility of
1081 QRhi to block whenever starting a new frame and finding the CPU is already
1082 \c{N - 1} frames ahead of the GPU (because the command buffer submitted in
1083 frame no. \c{current} - \c{N} has not yet completed). The value N is what
1084 is returned from here, and is typically 2. This can be relevant to
1085 applications that integrate rendering done directly with the graphics API,
1086 as such rendering code may want to perform double (if the value is 2)
1087 buffering for resources, such as, buffers, similarly to the QRhi backends
1088 themselves. The current frame slot index (a value running 0, 1, .., N-1,
1089 then wrapping around) is retrievable from QRhi::currentFrameSlot(). The
1090 value is 1 for backends where the graphics API offers no such low level
1091 control over the command submission process. Note that pipelining may still
1092 happen even when this value is 1 (some backends, such as D3D11, are
1093 designed to attempt to enable this, for instance, by using an update
1094 strategy for uniform buffers that does not stall the pipeline), but that is
1095 then not controlled by QRhi and so not reflected here in the API.
1096
1097 \value MaxAsyncReadbackFrames The number of \l{QRhi::endFrame()}{submitted}
1098 frames (including the one that contains the readback) after which an
1099 asynchronous texture or buffer readback is guaranteed to complete upon
1100 \l{QRhi::beginFrame()}{starting a new frame}.
1101
1102 \value MaxThreadGroupsPerDimension The maximum number of compute
1103 work/thread groups that can be dispatched. Effectively the maximum value
1104 for the arguments of QRhiCommandBuffer::dispatch(). Typically 65535.
1105
1106 \value MaxThreadsPerThreadGroup The maximum number of invocations in a
1107 single local work group, or in other terminology, the maximum number of
1108 threads in a thread group. Effectively the maximum value for the product of
1109 \c local_size_x, \c local_size_y, and \c local_size_z in the compute
1110 shader. Typical values are 128, 256, 512, 1024, or 1536. Watch out that
1111 both OpenGL ES and Vulkan specify only 128 as the minimum required limit
1112 for implementations. While uncommon for Vulkan, some OpenGL ES 3.1
1113 implementations for mobile/embedded devices only support the spec-mandated
1114 minimum value.
1115
1116 \value MaxThreadGroupX The maximum size of a work/thread group in the X
1117 dimension. Effectively the maximum value of \c local_size_x in the compute
1118 shader. Typically 256 or 1024.
1119
1120 \value MaxThreadGroupY The maximum size of a work/thread group in the Y
1121 dimension. Effectively the maximum value of \c local_size_y in the compute
1122 shader. Typically 256 or 1024.
1123
1124 \value MaxThreadGroupZ The maximum size of a work/thread group in the Z
1125 dimension. Effectively the maximum value of \c local_size_z in the compute
1126 shader. Typically 64 or 256.
1127
1128 \value TextureArraySizeMax Maximum texture array size. Typically in range
1129 256 - 2048. Attempting to \l{QRhi::newTextureArray()}{create a texture
1130 array} with more elements will likely fail.
1131
1132 \value MaxUniformBufferRange The number of bytes that can be exposed from a
1133 uniform buffer to the shaders at once. On OpenGL ES 2.0 and 3.0
1134 implementations this may be as low as 3584 bytes (224 four component, 32
1135 bits per component vectors). Elsewhere the value is typically 16384 (1024
1136 vec4s) or 65536 (4096 vec4s).
1137
1138 \value MaxVertexInputs The number of input attributes to the vertex shader.
1139 The location in a QRhiVertexInputAttribute must be in range \c{[0,
1140 MaxVertexInputs-1]}. The value may be as low as 8 with OpenGL ES 2.0.
1141 Elsewhere, typical values are 16, 31, or 32.
1142
1143 \value MaxVertexOutputs The maximum number of outputs (4 component vector
1144 \c out variables) from the vertex shader. The value may be as low as 8 with
1145 OpenGL ES 2.0, and 15 with OpenGL ES 3.0 and some Metal devices. Elsewhere,
1146 a typical value is 32.
1147 */
1148
1149/*!
1150 \class QRhiInitParams
1151 \inmodule QtGuiPrivate
1152 \inheaderfile rhi/qrhi.h
1153 \since 6.6
1154 \brief Base class for backend-specific initialization parameters.
1155
1156 Contains fields that are relevant to all backends.
1157
1158 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
1159 for details.
1160 */
1161
1162/*!
1163 \class QRhiDepthStencilClearValue
1164 \inmodule QtGuiPrivate
1165 \inheaderfile rhi/qrhi.h
1166 \since 6.6
1167 \brief Specifies clear values for a depth or stencil buffer.
1168
1169 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
1170 for details.
1171 */
1172
1173/*!
1174 \fn QRhiDepthStencilClearValue::QRhiDepthStencilClearValue() = default
1175
1176 Constructs a depth/stencil clear value with depth clear value 1.0f and
1177 stencil clear value 0.
1178 */
1179
1180/*!
1181 Constructs a depth/stencil clear value with depth clear value \a d and
1182 stencil clear value \a s.
1183 */
1184QRhiDepthStencilClearValue::QRhiDepthStencilClearValue(float d, quint32 s)
1185 : m_d(d),
1186 m_s(s)
1187{
1188}
1189
1190/*!
1191 \fn float QRhiDepthStencilClearValue::depthClearValue() const
1192 \return the depth clear value. In most cases this is 1.0f.
1193 */
1194
1195/*!
1196 \fn void QRhiDepthStencilClearValue::setDepthClearValue(float d)
1197 Sets the depth clear value to \a d.
1198 */
1199
1200/*!
1201 \fn quint32 QRhiDepthStencilClearValue::stencilClearValue() const
1202 \return the stencil clear value. In most cases this is 0.
1203 */
1204
1205/*!
1206 \fn void QRhiDepthStencilClearValue::setStencilClearValue(quint32 s)
1207 Sets the stencil clear value to \a s.
1208 */
1209
1210/*!
1211 \fn bool QRhiDepthStencilClearValue::operator==(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept
1212
1213 \return \c true if the values in the two QRhiDepthStencilClearValue objects
1214 \a a and \a b are equal.
1215 */
1216
1217/*!
1218 \fn bool QRhiDepthStencilClearValue::operator!=(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept
1219
1220 \return \c false if the values in the two QRhiDepthStencilClearValue
1221 objects \a a and \a b are equal; otherwise returns \c true.
1222
1223*/
1224
1225/*!
1226 \fn size_t QRhiDepthStencilClearValue::qHash(const QRhiDepthStencilClearValue &key, size_t seed)
1227 \qhash{QRhiDepthStencilClearValue}
1228 */
1229
1230#ifndef QT_NO_DEBUG_STREAM
1231QDebug operator<<(QDebug dbg, const QRhiDepthStencilClearValue &v)
1232{
1233 QDebugStateSaver saver(dbg);
1234 dbg.nospace() << "QRhiDepthStencilClearValue(depth-clear=" << v.depthClearValue()
1235 << " stencil-clear=" << v.stencilClearValue()
1236 << ')';
1237 return dbg;
1238}
1239#endif
1240
1241/*!
1242 \class QRhiViewport
1243 \inmodule QtGuiPrivate
1244 \inheaderfile rhi/qrhi.h
1245 \since 6.6
1246 \brief Specifies a viewport rectangle.
1247
1248 Used with QRhiCommandBuffer::setViewport().
1249
1250 QRhi assumes OpenGL-style viewport coordinates, meaning x and y are
1251 bottom-left. Negative width or height are not allowed.
1252
1253 Typical usage is like the following:
1254
1255 \code
1256 const QSize outputSizeInPixels = swapchain->currentPixelSize();
1257 const QRhiViewport viewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height());
1258 cb->beginPass(swapchain->currentFrameRenderTarget(), Qt::black, { 1.0f, 0 });
1259 cb->setGraphicsPipeline(ps);
1260 cb->setViewport(viewport);
1261 // ...
1262 \endcode
1263
1264 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
1265 for details.
1266
1267 \sa QRhiCommandBuffer::setViewport(), QRhi::clipSpaceCorrMatrix(), QRhiScissor
1268 */
1269
1270/*!
1271 \fn QRhiViewport::QRhiViewport() = default
1272
1273 Constructs a viewport description with an empty rectangle and a depth range
1274 of 0.0f - 1.0f.
1275
1276 \sa QRhi::clipSpaceCorrMatrix()
1277 */
1278
1279/*!
1280 Constructs a viewport description with the rectangle specified by \a x, \a
1281 y, \a w, \a h and the depth range \a minDepth and \a maxDepth.
1282
1283 \note \a x and \a y are assumed to be the bottom-left position. \a w and \a
1284 h should not be negative, the viewport will be ignored by
1285 QRhiCommandBuffer::setViewport() otherwise.
1286
1287 \sa QRhi::clipSpaceCorrMatrix()
1288 */
1289QRhiViewport::QRhiViewport(float x, float y, float w, float h, float minDepth, float maxDepth)
1290 : m_rect { ._M_elems: { x, y, w, h } },
1291 m_minDepth(minDepth),
1292 m_maxDepth(maxDepth)
1293{
1294}
1295
1296/*!
1297 \fn std::array<float, 4> QRhiViewport::viewport() const
1298 \return the viewport x, y, width, and height.
1299 */
1300
1301/*!
1302 \fn void QRhiViewport::setViewport(float x, float y, float w, float h)
1303 Sets the viewport's position and size to \a x, \a y, \a w, and \a h.
1304
1305 \note Viewports are specified in a coordinate system that has its origin in
1306 the bottom-left.
1307 */
1308
1309/*!
1310 \fn float QRhiViewport::minDepth() const
1311 \return the minDepth value of the depth range of the viewport.
1312 */
1313
1314/*!
1315 \fn void QRhiViewport::setMinDepth(float minDepth)
1316 Sets the \a minDepth of the depth range of the viewport.
1317 By default this is set to 0.0f.
1318 */
1319
1320/*!
1321 \fn float QRhiViewport::maxDepth() const
1322 \return the maxDepth value of the depth range of the viewport.
1323 */
1324
1325/*!
1326 \fn void QRhiViewport::setMaxDepth(float maxDepth)
1327 Sets the \a maxDepth of the depth range of the viewport.
1328 By default this is set to 1.0f.
1329 */
1330
1331/*!
1332 \fn bool QRhiViewport::operator==(const QRhiViewport &a, const QRhiViewport &b) noexcept
1333
1334 \return \c true if the values in the two QRhiViewport objects
1335 \a a and \a b are equal.
1336 */
1337
1338/*!
1339 \fn bool QRhiViewport::operator!=(const QRhiViewport &a, const QRhiViewport &b) noexcept
1340
1341 \return \c false if the values in the two QRhiViewport
1342 objects \a a and \a b are equal; otherwise returns \c true.
1343*/
1344
1345/*!
1346 \fn size_t QRhiViewport::qHash(const QRhiViewport &key, size_t seed)
1347 \qhash{QRhiViewport}
1348 */
1349
1350#ifndef QT_NO_DEBUG_STREAM
1351QDebug operator<<(QDebug dbg, const QRhiViewport &v)
1352{
1353 QDebugStateSaver saver(dbg);
1354 const std::array<float, 4> r = v.viewport();
1355 dbg.nospace() << "QRhiViewport(bottom-left-x=" << r[0]
1356 << " bottom-left-y=" << r[1]
1357 << " width=" << r[2]
1358 << " height=" << r[3]
1359 << " minDepth=" << v.minDepth()
1360 << " maxDepth=" << v.maxDepth()
1361 << ')';
1362 return dbg;
1363}
1364#endif
1365
1366/*!
1367 \class QRhiScissor
1368 \inmodule QtGuiPrivate
1369 \inheaderfile rhi/qrhi.h
1370 \since 6.6
1371 \brief Specifies a scissor rectangle.
1372
1373 Used with QRhiCommandBuffer::setScissor(). Setting a scissor rectangle is
1374 only possible with a QRhiGraphicsPipeline that has
1375 QRhiGraphicsPipeline::UsesScissor set.
1376
1377 QRhi assumes OpenGL-style scissor coordinates, meaning x and y are
1378 bottom-left. Negative width or height are not allowed. However, apart from
1379 that, the flexible OpenGL semantics apply: negative x and y, partially out
1380 of bounds rectangles, etc. will be handled gracefully, clamping as
1381 appropriate. Therefore, any rendering logic targeting OpenGL can feed
1382 scissor rectangles into QRhiScissor as-is, without any adaptation.
1383
1384 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
1385 for details.
1386
1387 \sa QRhiCommandBuffer::setScissor(), QRhiViewport
1388 */
1389
1390/*!
1391 \fn QRhiScissor::QRhiScissor() = default
1392
1393 Constructs an empty scissor.
1394 */
1395
1396/*!
1397 Constructs a scissor with the rectangle specified by \a x, \a y, \a w, and
1398 \a h.
1399
1400 \note \a x and \a y are assumed to be the bottom-left position. Negative \a w
1401 or \a h are not allowed, such scissor rectangles will be ignored by
1402 QRhiCommandBuffer. Other than that, the flexible OpenGL semantics apply:
1403 negative x and y, partially out of bounds rectangles, etc. will be handled
1404 gracefully, clamping as appropriate.
1405 */
1406QRhiScissor::QRhiScissor(int x, int y, int w, int h)
1407 : m_rect { ._M_elems: { x, y, w, h } }
1408{
1409}
1410
1411/*!
1412 \fn std::array<int, 4> QRhiScissor::scissor() const
1413 \return the scissor position and size.
1414 */
1415
1416/*!
1417 \fn void QRhiScissor::setScissor(int x, int y, int w, int h)
1418 Sets the scissor position and size to \a x, \a y, \a w, \a h.
1419
1420 \note The position is always expected to be specified in a coordinate
1421 system that has its origin in the bottom-left corner, like OpenGL.
1422 */
1423
1424/*!
1425 \fn bool QRhiScissor::operator==(const QRhiScissor &a, const QRhiScissor &b) noexcept
1426
1427 \return \c true if the values in the two QRhiScissor objects
1428 \a a and \a b are equal.
1429 */
1430
1431/*!
1432 \fn bool QRhiScissor::operator!=(const QRhiScissor &a, const QRhiScissor &b) noexcept
1433
1434 \return \c false if the values in the two QRhiScissor
1435 objects \a a and \a b are equal; otherwise returns \c true.
1436*/
1437
1438/*!
1439 \fn size_t QRhiScissor::qHash(const QRhiScissor &key, size_t seed)
1440 \qhash{QRhiScissor}
1441 */
1442
1443#ifndef QT_NO_DEBUG_STREAM
1444QDebug operator<<(QDebug dbg, const QRhiScissor &s)
1445{
1446 QDebugStateSaver saver(dbg);
1447 const std::array<int, 4> r = s.scissor();
1448 dbg.nospace() << "QRhiScissor(bottom-left-x=" << r[0]
1449 << " bottom-left-y=" << r[1]
1450 << " width=" << r[2]
1451 << " height=" << r[3]
1452 << ')';
1453 return dbg;
1454}
1455#endif
1456
1457/*!
1458 \class QRhiVertexInputBinding
1459 \inmodule QtGuiPrivate
1460 \inheaderfile rhi/qrhi.h
1461 \since 6.6
1462 \brief Describes a vertex input binding.
1463
1464 Specifies the stride (in bytes, must be a multiple of 4), the
1465 classification and optionally the instance step rate.
1466
1467 As an example, assume a vertex shader with the following inputs:
1468
1469 \badcode
1470 layout(location = 0) in vec4 position;
1471 layout(location = 1) in vec2 texcoord;
1472 \endcode
1473
1474 Now let's assume also that 3 component vertex positions \c{(x, y, z)} and 2
1475 component texture coordinates \c{(u, v)} are provided in a non-interleaved
1476 format in a buffer (or separate buffers even). Defining two bindings
1477 could then be done like this:
1478
1479 \code
1480 QRhiVertexInputLayout inputLayout;
1481 inputLayout.setBindings({
1482 { 3 * sizeof(float) },
1483 { 2 * sizeof(float) }
1484 });
1485 \endcode
1486
1487 Only the stride is interesting here since instancing is not used. The
1488 binding number is given by the index of the QRhiVertexInputBinding
1489 element in the bindings vector of the QRhiVertexInputLayout.
1490
1491 Once a graphics pipeline with this vertex input layout is bound, the vertex
1492 inputs could be set up like the following for drawing a cube with 36
1493 vertices, assuming we have a single buffer with first the positions and
1494 then the texture coordinates:
1495
1496 \code
1497 const QRhiCommandBuffer::VertexInput vbufBindings[] = {
1498 { cubeBuf, 0 },
1499 { cubeBuf, 36 * 3 * sizeof(float) }
1500 };
1501 cb->setVertexInput(0, 2, vbufBindings);
1502 \endcode
1503
1504 Note how the index defined by \c {startBinding + i}, where \c i is the
1505 index in the second argument of
1506 \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()}, matches the
1507 index of the corresponding entry in the \c bindings vector of the
1508 QRhiVertexInputLayout.
1509
1510 \note the stride must always be a multiple of 4.
1511
1512 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
1513 for details.
1514
1515 \sa QRhiCommandBuffer::setVertexInput()
1516 */
1517
1518/*!
1519 \enum QRhiVertexInputBinding::Classification
1520 Describes the input data classification.
1521
1522 \value PerVertex Data is per-vertex
1523 \value PerInstance Data is per-instance
1524 */
1525
1526/*!
1527 \fn QRhiVertexInputBinding::QRhiVertexInputBinding() = default
1528
1529 Constructs a default vertex input binding description.
1530 */
1531
1532/*!
1533 Constructs a vertex input binding description with the specified \a stride,
1534 classification \a cls, and instance step rate \a stepRate.
1535
1536 \note \a stepRate other than 1 is only supported when
1537 QRhi::CustomInstanceStepRate is reported to be supported.
1538 */
1539QRhiVertexInputBinding::QRhiVertexInputBinding(quint32 stride, Classification cls, quint32 stepRate)
1540 : m_stride(stride),
1541 m_classification(cls),
1542 m_instanceStepRate(stepRate)
1543{
1544}
1545
1546/*!
1547 \fn quint32 QRhiVertexInputBinding::stride() const
1548 \return the stride in bytes.
1549 */
1550
1551/*!
1552 \fn void QRhiVertexInputBinding::setStride(quint32 s)
1553 Sets the stride to \a s.
1554 */
1555
1556/*!
1557 \fn QRhiVertexInputBinding::Classification QRhiVertexInputBinding::classification() const
1558 \return the input data classification.
1559 */
1560
1561/*!
1562 \fn void QRhiVertexInputBinding::setClassification(Classification c)
1563 Sets the input data classification \a c. By default this is set to PerVertex.
1564 */
1565
1566/*!
1567 \fn quint32 QRhiVertexInputBinding::instanceStepRate() const
1568 \return the instance step rate.
1569 */
1570
1571/*!
1572 \fn void QRhiVertexInputBinding::setInstanceStepRate(quint32 rate)
1573 Sets the instance step \a rate. By default this is set to 1.
1574 */
1575
1576/*!
1577 \fn bool QRhiVertexInputBinding::operator==(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept
1578
1579 \return \c true if the values in the two QRhiVertexInputBinding objects
1580 \a a and \a b are equal.
1581 */
1582
1583/*!
1584 \fn bool QRhiVertexInputBinding::operator!=(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept
1585
1586 \return \c false if the values in the two QRhiVertexInputBinding
1587 objects \a a and \a b are equal; otherwise returns \c true.
1588*/
1589
1590/*!
1591 \fn size_t QRhiVertexInputBinding::qHash(const QRhiVertexInputBinding &key, size_t seed)
1592 \qhash{QRhiVertexInputBinding}
1593 */
1594
1595#ifndef QT_NO_DEBUG_STREAM
1596QDebug operator<<(QDebug dbg, const QRhiVertexInputBinding &b)
1597{
1598 QDebugStateSaver saver(dbg);
1599 dbg.nospace() << "QRhiVertexInputBinding(stride=" << b.stride()
1600 << " cls=" << b.classification()
1601 << " step-rate=" << b.instanceStepRate()
1602 << ')';
1603 return dbg;
1604}
1605#endif
1606
1607/*!
1608 \class QRhiVertexInputAttribute
1609 \inmodule QtGuiPrivate
1610 \inheaderfile rhi/qrhi.h
1611 \since 6.6
1612 \brief Describes a single vertex input element.
1613
1614 The members specify the binding number, location, format, and offset for a
1615 single vertex input element.
1616
1617 \note For HLSL it is assumed that the vertex shader translated from SPIR-V
1618 uses
1619 \c{TEXCOORD<location>} as the semantic for each input. Hence no separate
1620 semantic name and index.
1621
1622 As an example, assume a vertex shader with the following inputs:
1623
1624 \badcode
1625 layout(location = 0) in vec4 position;
1626 layout(location = 1) in vec2 texcoord;
1627 \endcode
1628
1629 Now let's assume that we have 3 component vertex positions \c{(x, y, z)}
1630 and 2 component texture coordinates \c{(u, v)} are provided in a
1631 non-interleaved format in a buffer (or separate buffers even). Once two
1632 bindings are defined, the attributes could be specified as:
1633
1634 \code
1635 QRhiVertexInputLayout inputLayout;
1636 inputLayout.setBindings({
1637 { 3 * sizeof(float) },
1638 { 2 * sizeof(float) }
1639 });
1640 inputLayout.setAttributes({
1641 { 0, 0, QRhiVertexInputAttribute::Float3, 0 },
1642 { 1, 1, QRhiVertexInputAttribute::Float2, 0 }
1643 });
1644 \endcode
1645
1646 Once a graphics pipeline with this vertex input layout is bound, the vertex
1647 inputs could be set up like the following for drawing a cube with 36
1648 vertices, assuming we have a single buffer with first the positions and
1649 then the texture coordinates:
1650
1651 \code
1652 const QRhiCommandBuffer::VertexInput vbufBindings[] = {
1653 { cubeBuf, 0 },
1654 { cubeBuf, 36 * 3 * sizeof(float) }
1655 };
1656 cb->setVertexInput(0, 2, vbufBindings);
1657 \endcode
1658
1659 When working with interleaved data, there will typically be just one
1660 binding, with multiple attributes referring to that same buffer binding
1661 point:
1662
1663 \code
1664 QRhiVertexInputLayout inputLayout;
1665 inputLayout.setBindings({
1666 { 5 * sizeof(float) }
1667 });
1668 inputLayout.setAttributes({
1669 { 0, 0, QRhiVertexInputAttribute::Float3, 0 },
1670 { 0, 1, QRhiVertexInputAttribute::Float2, 3 * sizeof(float) }
1671 });
1672 \endcode
1673
1674 and then:
1675
1676 \code
1677 const QRhiCommandBuffer::VertexInput vbufBinding(interleavedCubeBuf, 0);
1678 cb->setVertexInput(0, 1, &vbufBinding);
1679 \endcode
1680
1681 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
1682 for details.
1683
1684 \sa QRhiCommandBuffer::setVertexInput()
1685 */
1686
1687/*!
1688 \enum QRhiVertexInputAttribute::Format
1689 Specifies the type of the element data.
1690
1691 \value Float4 Four component float vector
1692 \value Float3 Three component float vector
1693 \value Float2 Two component float vector
1694 \value Float Float
1695 \value UNormByte4 Four component normalized unsigned byte vector
1696 \value UNormByte2 Two component normalized unsigned byte vector
1697 \value UNormByte Normalized unsigned byte
1698 \value UInt4 Four component unsigned integer vector
1699 \value UInt3 Three component unsigned integer vector
1700 \value UInt2 Two component unsigned integer vector
1701 \value UInt Unsigned integer
1702 \value SInt4 Four component signed integer vector
1703 \value SInt3 Three component signed integer vector
1704 \value SInt2 Two component signed integer vector
1705 \value SInt Signed integer
1706 \value Half4 Four component half precision (16 bit) float vector
1707 \value Half3 Three component half precision (16 bit) float vector
1708 \value Half2 Two component half precision (16 bit) float vector
1709 \value Half Half precision (16 bit) float
1710 \value UShort4 Four component unsigned short (16 bit) integer vector
1711 \value UShort3 Three component unsigned short (16 bit) integer vector
1712 \value UShort2 Two component unsigned short (16 bit) integer vector
1713 \value UShort Unsigned short (16 bit) integer
1714 \value SShort4 Four component signed short (16 bit) integer vector
1715 \value SShort3 Three component signed short (16 bit) integer vector
1716 \value SShort2 Two component signed short (16 bit) integer vector
1717 \value SShort Signed short (16 bit) integer
1718
1719 \note Support for half precision floating point attributes is indicated at
1720 run time by the QRhi::Feature::HalfAttributes feature flag.
1721
1722 \note Direct3D 11/12 supports 16 bit input attributes, but does not support
1723 the Half3, UShort3 or SShort3 types. The D3D backends pass through Half3 as
1724 Half4, UShort3 as UShort4, and SShort3 as SShort4. To ensure cross platform
1725 compatibility, 16 bit inputs should be padded to 8 bytes.
1726 */
1727
1728/*!
1729 \fn QRhiVertexInputAttribute::QRhiVertexInputAttribute() = default
1730
1731 Constructs a default vertex input attribute description.
1732 */
1733
1734/*!
1735 Constructs a vertex input attribute description with the specified \a
1736 binding number, \a location, \a format, and \a offset.
1737
1738 \a matrixSlice should be -1 except when this attribute corresponds to a row
1739 or column of a matrix (for example, a 4x4 matrix becomes 4 vec4s, consuming
1740 4 consecutive vertex input locations), in which case it is the index of the
1741 row or column. \c{location - matrixSlice} must always be equal to the \c
1742 location for the first row or column of the unrolled matrix.
1743 */
1744QRhiVertexInputAttribute::QRhiVertexInputAttribute(int binding, int location, Format format, quint32 offset, int matrixSlice)
1745 : m_binding(binding),
1746 m_location(location),
1747 m_format(format),
1748 m_offset(offset),
1749 m_matrixSlice(matrixSlice)
1750{
1751}
1752
1753/*!
1754 \fn int QRhiVertexInputAttribute::binding() const
1755 \return the binding point index.
1756 */
1757
1758/*!
1759 \fn void QRhiVertexInputAttribute::setBinding(int b)
1760 Sets the binding point index to \a b.
1761 By default this is set to 0.
1762 */
1763
1764/*!
1765 \fn int QRhiVertexInputAttribute::location() const
1766 \return the location of the vertex input element.
1767 */
1768
1769/*!
1770 \fn void QRhiVertexInputAttribute::setLocation(int loc)
1771 Sets the location of the vertex input element to \a loc.
1772 By default this is set to 0.
1773 */
1774
1775/*!
1776 \fn QRhiVertexInputAttribute::Format QRhiVertexInputAttribute::format() const
1777 \return the format of the vertex input element.
1778 */
1779
1780/*!
1781 \fn void QRhiVertexInputAttribute::setFormat(Format f)
1782 Sets the format of the vertex input element to \a f.
1783 By default this is set to Float4.
1784 */
1785
1786/*!
1787 \fn quint32 QRhiVertexInputAttribute::offset() const
1788 \return the byte offset for the input element.
1789 */
1790
1791/*!
1792 \fn void QRhiVertexInputAttribute::setOffset(quint32 ofs)
1793 Sets the byte offset for the input element to \a ofs.
1794 */
1795
1796/*!
1797 \fn int QRhiVertexInputAttribute::matrixSlice() const
1798
1799 \return the matrix slice if the input element corresponds to a row or
1800 column of a matrix, or -1 if not relevant.
1801 */
1802
1803/*!
1804 \fn void QRhiVertexInputAttribute::setMatrixSlice(int slice)
1805
1806 Sets the matrix \a slice. By default this is set to -1, and should be set
1807 to a >= 0 value only when this attribute corresponds to a row or column of
1808 a matrix (for example, a 4x4 matrix becomes 4 vec4s, consuming 4
1809 consecutive vertex input locations), in which case it is the index of the
1810 row or column. \c{location - matrixSlice} must always be equal to the \c
1811 location for the first row or column of the unrolled matrix.
1812 */
1813
1814/*!
1815 \fn bool QRhiVertexInputAttribute::operator==(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept
1816
1817 \return \c true if the values in the two QRhiVertexInputAttribute objects
1818 \a a and \a b are equal.
1819 */
1820
1821/*!
1822 \fn bool QRhiVertexInputAttribute::operator!=(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept
1823
1824 \return \c false if the values in the two QRhiVertexInputAttribute
1825 objects \a a and \a b are equal; otherwise returns \c true.
1826*/
1827
1828/*!
1829 \fn size_t QRhiVertexInputAttribute::qHash(const QRhiVertexInputAttribute &key, size_t seed)
1830 \qhash{QRhiVertexInputAttribute}
1831 */
1832
1833#ifndef QT_NO_DEBUG_STREAM
1834QDebug operator<<(QDebug dbg, const QRhiVertexInputAttribute &a)
1835{
1836 QDebugStateSaver saver(dbg);
1837 dbg.nospace() << "QRhiVertexInputAttribute(binding=" << a.binding()
1838 << " location=" << a.location()
1839 << " format=" << a.format()
1840 << " offset=" << a.offset()
1841 << ')';
1842 return dbg;
1843}
1844#endif
1845
1846QRhiVertexInputAttribute::Format QRhiImplementation::shaderDescVariableFormatToVertexInputFormat(QShaderDescription::VariableType type) const
1847{
1848 switch (type) {
1849 case QShaderDescription::Vec4:
1850 return QRhiVertexInputAttribute::Float4;
1851 case QShaderDescription::Vec3:
1852 return QRhiVertexInputAttribute::Float3;
1853 case QShaderDescription::Vec2:
1854 return QRhiVertexInputAttribute::Float2;
1855 case QShaderDescription::Float:
1856 return QRhiVertexInputAttribute::Float;
1857
1858 case QShaderDescription::Int4:
1859 return QRhiVertexInputAttribute::SInt4;
1860 case QShaderDescription::Int3:
1861 return QRhiVertexInputAttribute::SInt3;
1862 case QShaderDescription::Int2:
1863 return QRhiVertexInputAttribute::SInt2;
1864 case QShaderDescription::Int:
1865 return QRhiVertexInputAttribute::SInt;
1866
1867 case QShaderDescription::Uint4:
1868 return QRhiVertexInputAttribute::UInt4;
1869 case QShaderDescription::Uint3:
1870 return QRhiVertexInputAttribute::UInt3;
1871 case QShaderDescription::Uint2:
1872 return QRhiVertexInputAttribute::UInt2;
1873 case QShaderDescription::Uint:
1874 return QRhiVertexInputAttribute::UInt;
1875
1876 case QShaderDescription::Half4:
1877 return QRhiVertexInputAttribute::Half4;
1878 case QShaderDescription::Half3:
1879 return QRhiVertexInputAttribute::Half3;
1880 case QShaderDescription::Half2:
1881 return QRhiVertexInputAttribute::Half2;
1882 case QShaderDescription::Half:
1883 return QRhiVertexInputAttribute::Half;
1884
1885 default:
1886 Q_UNREACHABLE_RETURN(QRhiVertexInputAttribute::Float);
1887 }
1888}
1889
1890quint32 QRhiImplementation::byteSizePerVertexForVertexInputFormat(QRhiVertexInputAttribute::Format format) const
1891{
1892 switch (format) {
1893 case QRhiVertexInputAttribute::Float4:
1894 return 4 * sizeof(float);
1895 case QRhiVertexInputAttribute::Float3:
1896 return 4 * sizeof(float); // vec3 still takes 16 bytes
1897 case QRhiVertexInputAttribute::Float2:
1898 return 2 * sizeof(float);
1899 case QRhiVertexInputAttribute::Float:
1900 return sizeof(float);
1901
1902 case QRhiVertexInputAttribute::UNormByte4:
1903 return 4 * sizeof(quint8);
1904 case QRhiVertexInputAttribute::UNormByte2:
1905 return 2 * sizeof(quint8);
1906 case QRhiVertexInputAttribute::UNormByte:
1907 return sizeof(quint8);
1908
1909 case QRhiVertexInputAttribute::UInt4:
1910 return 4 * sizeof(quint32);
1911 case QRhiVertexInputAttribute::UInt3:
1912 return 4 * sizeof(quint32); // ivec3 still takes 16 bytes
1913 case QRhiVertexInputAttribute::UInt2:
1914 return 2 * sizeof(quint32);
1915 case QRhiVertexInputAttribute::UInt:
1916 return sizeof(quint32);
1917
1918 case QRhiVertexInputAttribute::SInt4:
1919 return 4 * sizeof(qint32);
1920 case QRhiVertexInputAttribute::SInt3:
1921 return 4 * sizeof(qint32); // uvec3 still takes 16 bytes
1922 case QRhiVertexInputAttribute::SInt2:
1923 return 2 * sizeof(qint32);
1924 case QRhiVertexInputAttribute::SInt:
1925 return sizeof(qint32);
1926
1927 case QRhiVertexInputAttribute::Half4:
1928 return 4 * sizeof(qfloat16);
1929 case QRhiVertexInputAttribute::Half3:
1930 return 4 * sizeof(qfloat16); // half3 still takes 8 bytes
1931 case QRhiVertexInputAttribute::Half2:
1932 return 2 * sizeof(qfloat16);
1933 case QRhiVertexInputAttribute::Half:
1934 return sizeof(qfloat16);
1935
1936 case QRhiVertexInputAttribute::UShort4:
1937 return 4 * sizeof(quint16);
1938 case QRhiVertexInputAttribute::UShort3:
1939 return 4 * sizeof(quint16); // ivec3 still takes 8 bytes
1940 case QRhiVertexInputAttribute::UShort2:
1941 return 2 * sizeof(quint16);
1942 case QRhiVertexInputAttribute::UShort:
1943 return sizeof(quint16);
1944
1945 case QRhiVertexInputAttribute::SShort4:
1946 return 4 * sizeof(qint16);
1947 case QRhiVertexInputAttribute::SShort3:
1948 return 4 * sizeof(qint16); // uvec3 still takes 8 bytes
1949 case QRhiVertexInputAttribute::SShort2:
1950 return 2 * sizeof(qint16);
1951 case QRhiVertexInputAttribute::SShort:
1952 return sizeof(qint16);
1953
1954 default:
1955 Q_UNREACHABLE_RETURN(1);
1956 }
1957}
1958
1959/*!
1960 \class QRhiVertexInputLayout
1961 \inmodule QtGuiPrivate
1962 \inheaderfile rhi/qrhi.h
1963 \since 6.6
1964 \brief Describes the layout of vertex inputs consumed by a vertex shader.
1965
1966 The vertex input layout is defined by the collections of
1967 QRhiVertexInputBinding and QRhiVertexInputAttribute.
1968
1969 As an example, let's assume that we have a single buffer with 3 component
1970 vertex positions and 2 component UV coordinates interleaved (\c x, \c y, \c
1971 z, \c u, \c v), that the position and UV are expected at input locations 0
1972 and 1 by the vertex shader, and that the vertex buffer will be bound at
1973 binding point 0 using
1974 \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()} later on:
1975
1976 \code
1977 QRhiVertexInputLayout inputLayout;
1978 inputLayout.setBindings({
1979 { 5 * sizeof(float) }
1980 });
1981 inputLayout.setAttributes({
1982 { 0, 0, QRhiVertexInputAttribute::Float3, 0 },
1983 { 0, 1, QRhiVertexInputAttribute::Float2, 3 * sizeof(float) }
1984 });
1985 \endcode
1986
1987 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
1988 for details.
1989 */
1990
1991/*!
1992 \fn QRhiVertexInputLayout::QRhiVertexInputLayout() = default
1993
1994 Constructs an empty vertex input layout description.
1995 */
1996
1997/*!
1998 \fn void QRhiVertexInputLayout::setBindings(std::initializer_list<QRhiVertexInputBinding> list)
1999 Sets the bindings from the specified \a list.
2000 */
2001
2002/*!
2003 \fn template<typename InputIterator> void QRhiVertexInputLayout::setBindings(InputIterator first, InputIterator last)
2004 Sets the bindings using the iterators \a first and \a last.
2005 */
2006
2007/*!
2008 \fn const QRhiVertexInputBinding *QRhiVertexInputLayout::cbeginBindings() const
2009 \return a const iterator pointing to the first item in the binding list.
2010 */
2011
2012/*!
2013 \fn const QRhiVertexInputBinding *QRhiVertexInputLayout::cendBindings() const
2014 \return a const iterator pointing just after the last item in the binding list.
2015 */
2016
2017/*!
2018 \fn const QRhiVertexInputBinding *QRhiVertexInputLayout::bindingAt(qsizetype index) const
2019 \return the binding at the given \a index.
2020 */
2021
2022/*!
2023 \fn qsizetype QRhiVertexInputLayout::bindingCount() const
2024 \return the number of bindings.
2025 */
2026
2027/*!
2028 \fn void QRhiVertexInputLayout::setAttributes(std::initializer_list<QRhiVertexInputAttribute> list)
2029 Sets the attributes from the specified \a list.
2030 */
2031
2032/*!
2033 \fn template<typename InputIterator> void QRhiVertexInputLayout::setAttributes(InputIterator first, InputIterator last)
2034 Sets the attributes using the iterators \a first and \a last.
2035 */
2036
2037/*!
2038 \fn const QRhiVertexInputAttribute *QRhiVertexInputLayout::cbeginAttributes() const
2039 \return a const iterator pointing to the first item in the attribute list.
2040 */
2041
2042/*!
2043 \fn const QRhiVertexInputAttribute *QRhiVertexInputLayout::cendAttributes() const
2044 \return a const iterator pointing just after the last item in the attribute list.
2045 */
2046
2047/*!
2048 \fn const QRhiVertexInputAttribute *QRhiVertexInputLayout::attributeAt(qsizetype index) const
2049 \return the attribute at the given \a index.
2050 */
2051
2052/*!
2053 \fn qsizetype QRhiVertexInputLayout::attributeCount() const
2054 \return the number of attributes.
2055 */
2056
2057/*!
2058 \fn bool QRhiVertexInputLayout::operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept
2059
2060 \return \c true if the values in the two QRhiVertexInputLayout objects
2061 \a a and \a b are equal.
2062 */
2063
2064/*!
2065 \fn bool QRhiVertexInputLayout::operator!=(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept
2066
2067 \return \c false if the values in the two QRhiVertexInputLayout
2068 objects \a a and \a b are equal; otherwise returns \c true.
2069*/
2070
2071/*!
2072 \fn size_t QRhiVertexInputLayout::qHash(const QRhiVertexInputLayout &key, size_t seed)
2073 \qhash{QRhiVertexInputLayout}
2074 */
2075
2076#ifndef QT_NO_DEBUG_STREAM
2077QDebug operator<<(QDebug dbg, const QRhiVertexInputLayout &v)
2078{
2079 QDebugStateSaver saver(dbg);
2080 dbg.nospace() << "QRhiVertexInputLayout(bindings=" << v.m_bindings
2081 << " attributes=" << v.m_attributes
2082 << ')';
2083 return dbg;
2084}
2085#endif
2086
2087/*!
2088 \class QRhiShaderStage
2089 \inmodule QtGuiPrivate
2090 \inheaderfile rhi/qrhi.h
2091 \since 6.6
2092 \brief Specifies the type and the shader code for a shader stage in the pipeline.
2093
2094 When setting up a QRhiGraphicsPipeline, a collection of shader stages are
2095 specified. The QRhiShaderStage contains a QShader and some associated
2096 metadata, such as the graphics pipeline stage, and the
2097 \l{QShader::Variant}{shader variant} to select. There is no need to specify
2098 the shader language or version because the QRhi backend in use at runtime
2099 will take care of choosing the appropriate shader version from the
2100 collection within the QShader.
2101
2102 The typical usage is in combination with
2103 QRhiGraphicsPipeline::setShaderStages(), shown here with a simple approach
2104 to load the QShader from \c{.qsb} files generated offline or at build time:
2105
2106 \code
2107 QShader getShader(const QString &name)
2108 {
2109 QFile f(name);
2110 return f.open(QIODevice::ReadOnly) ? QShader::fromSerialized(f.readAll()) : QShader();
2111 }
2112
2113 QShader vs = getShader("material.vert.qsb");
2114 QShader fs = getShader("material.frag.qsb");
2115 pipeline->setShaderStages({
2116 { QRhiShaderStage::Vertex, vs },
2117 { QRhiShaderStage::Fragment, fs }
2118 });
2119 \endcode
2120
2121 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
2122 for details.
2123 */
2124
2125/*!
2126 \enum QRhiShaderStage::Type
2127 Specifies the type of the shader stage.
2128
2129 \value Vertex Vertex stage
2130
2131 \value TessellationControl Tessellation control (hull shader) stage. Must
2132 be used only when the QRhi::Tessellation feature is supported.
2133
2134 \value TessellationEvaluation Tessellation evaluation (domain shader)
2135 stage. Must be used only when the QRhi::Tessellation feature is supported.
2136
2137 \value Fragment Fragment (pixel shader) stage
2138
2139 \value Compute Compute stage. Must be used only when the QRhi::Compute
2140 feature is supported.
2141
2142 \value Geometry Geometry stage. Must be used only when the
2143 QRhi::GeometryShader feature is supported.
2144 */
2145
2146/*!
2147 \fn QRhiShaderStage::QRhiShaderStage() = default
2148
2149 Constructs a shader stage description for the vertex stage with an empty
2150 QShader.
2151 */
2152
2153/*!
2154 \fn QRhiShaderStage::Type QRhiShaderStage::type() const
2155 \return the type of the stage.
2156 */
2157
2158/*!
2159 \fn void QRhiShaderStage::setType(Type t)
2160
2161 Sets the type of the stage to \a t. Setters should rarely be needed in
2162 pratice. Most applications will likely use the QRhiShaderStage constructor
2163 in most cases.
2164 */
2165
2166/*!
2167 \fn QShader QRhiShaderStage::shader() const
2168 \return the QShader to be used for this stage in the graphics pipeline.
2169 */
2170
2171/*!
2172 \fn void QRhiShaderStage::setShader(const QShader &s)
2173 Sets the shader collection \a s.
2174 */
2175
2176/*!
2177 \fn QShader::Variant QRhiShaderStage::shaderVariant() const
2178 \return the requested shader variant.
2179 */
2180
2181/*!
2182 \fn void QRhiShaderStage::setShaderVariant(QShader::Variant v)
2183 Sets the requested shader variant \a v.
2184 */
2185
2186/*!
2187 Constructs a shader stage description with the \a type of the stage and the
2188 \a shader.
2189
2190 The shader variant \a v defaults to QShader::StandardShader. A
2191 QShader contains multiple source and binary versions of a shader.
2192 In addition, it can also contain variants of the shader with slightly
2193 modified code. \a v can then be used to select the desired variant.
2194 */
2195QRhiShaderStage::QRhiShaderStage(Type type, const QShader &shader, QShader::Variant v)
2196 : m_type(type),
2197 m_shader(shader),
2198 m_shaderVariant(v)
2199{
2200}
2201
2202/*!
2203 \fn bool QRhiShaderStage::operator==(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept
2204
2205 \return \c true if the values in the two QRhiShaderStage objects
2206 \a a and \a b are equal.
2207 */
2208
2209/*!
2210 \fn bool QRhiShaderStage::operator!=(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept
2211
2212 \return \c false if the values in the two QRhiShaderStage
2213 objects \a a and \a b are equal; otherwise returns \c true.
2214*/
2215
2216/*!
2217 \fn size_t QRhiShaderStage::qHash(const QRhiShaderStage &key, size_t seed)
2218 \qhash{QRhiShaderStage}
2219 */
2220
2221#ifndef QT_NO_DEBUG_STREAM
2222QDebug operator<<(QDebug dbg, const QRhiShaderStage &s)
2223{
2224 QDebugStateSaver saver(dbg);
2225 dbg.nospace() << "QRhiShaderStage(type=" << s.type()
2226 << " shader=" << s.shader()
2227 << " variant=" << s.shaderVariant()
2228 << ')';
2229 return dbg;
2230}
2231#endif
2232
2233/*!
2234 \class QRhiColorAttachment
2235 \inmodule QtGuiPrivate
2236 \inheaderfile rhi/qrhi.h
2237 \since 6.6
2238 \brief Describes the a single color attachment of a render target.
2239
2240 A color attachment is either a QRhiTexture or a QRhiRenderBuffer. The
2241 former, i.e. when texture() is set, is used in most cases.
2242 QRhiColorAttachment is commonly used in combination with
2243 QRhiTextureRenderTargetDescription.
2244
2245 \note texture() and renderBuffer() cannot be both set (be non-null at the
2246 same time).
2247
2248 Setting renderBuffer instead is recommended only when multisampling is
2249 needed. Relying on QRhi::MultisampleRenderBuffer is a better choice than
2250 QRhi::MultisampleTexture in practice since the former is available in more
2251 run time configurations (e.g. when running on OpenGL ES 3.0 which has no
2252 support for multisample textures, but does support multisample
2253 renderbuffers).
2254
2255 When targeting a non-multisample texture, the layer() and level() indicate
2256 the targeted layer (face index \c{0-5} for cubemaps) and mip level. For 3D
2257 textures layer() specifies the slice (one 2D image within the 3D texture)
2258 to render to. For texture arrays layer() is the array index.
2259
2260 When texture() or renderBuffer() is multisample, resolveTexture() can be
2261 set optionally. When set, samples are resolved automatically into that
2262 (non-multisample) texture at the end of the render pass. When rendering
2263 into a multisample renderbuffers, this is the only way to get resolved,
2264 non-multisample content out of them. Multisample textures allow sampling in
2265 shaders so for them this is just one option.
2266
2267 \note when resolving is enabled, the multisample data may not be written
2268 out at all. This means that the multisample texture() must not be used
2269 afterwards with shaders for sampling when resolveTexture() is set.
2270
2271 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
2272 for details.
2273
2274 \sa QRhiTextureRenderTargetDescription
2275 */
2276
2277/*!
2278 \fn QRhiColorAttachment::QRhiColorAttachment() = default
2279
2280 Constructs an empty color attachment description.
2281 */
2282
2283/*!
2284 Constructs a color attachment description that specifies \a texture as the
2285 associated color buffer.
2286 */
2287QRhiColorAttachment::QRhiColorAttachment(QRhiTexture *texture)
2288 : m_texture(texture)
2289{
2290}
2291
2292/*!
2293 Constructs a color attachment description that specifies \a renderBuffer as
2294 the associated color buffer.
2295 */
2296QRhiColorAttachment::QRhiColorAttachment(QRhiRenderBuffer *renderBuffer)
2297 : m_renderBuffer(renderBuffer)
2298{
2299}
2300
2301/*!
2302 \fn QRhiTexture *QRhiColorAttachment::texture() const
2303
2304 \return the texture this attachment description references, or \nullptr if
2305 there is none.
2306 */
2307
2308/*!
2309 \fn void QRhiColorAttachment::setTexture(QRhiTexture *tex)
2310
2311 Sets the texture \a tex.
2312
2313 \note texture() and renderBuffer() cannot be both set (be non-null at the
2314 same time).
2315 */
2316
2317/*!
2318 \fn QRhiRenderBuffer *QRhiColorAttachment::renderBuffer() const
2319
2320 \return the renderbuffer this attachment description references, or
2321 \nullptr if there is none.
2322
2323 In practice associating a QRhiRenderBuffer with a QRhiColorAttachment makes
2324 the most sense when setting up multisample rendering via a multisample
2325 \l{QRhiRenderBuffer::Type}{color} renderbuffer that is then resolved into a
2326 non-multisample texture at the end of the render pass.
2327 */
2328
2329/*!
2330 \fn void QRhiColorAttachment::setRenderBuffer(QRhiRenderBuffer *rb)
2331
2332 Sets the renderbuffer \a rb.
2333
2334 \note texture() and renderBuffer() cannot be both set (be non-null at the
2335 same time).
2336 */
2337
2338/*!
2339 \fn int QRhiColorAttachment::layer() const
2340 \return the layer index (cubemap face or array layer). 0 by default.
2341 */
2342
2343/*!
2344 \fn void QRhiColorAttachment::setLayer(int layer)
2345 Sets the \a layer index.
2346 */
2347
2348/*!
2349 \fn int QRhiColorAttachment::level() const
2350 \return the mip level. 0 by default.
2351 */
2352
2353/*!
2354 \fn void QRhiColorAttachment::setLevel(int level)
2355 Sets the mip \a level.
2356 */
2357
2358/*!
2359 \fn QRhiTexture *QRhiColorAttachment::resolveTexture() const
2360
2361 \return the resolve texture this attachment description references, or
2362 \nullptr if there is none.
2363
2364 Setting a non-null resolve texture is applicable when the attachment
2365 references a multisample texture or renderbuffer. The QRhiTexture in the
2366 resolveTexture() is then a non-multisample 2D texture (or texture array)
2367 with the same size (but a sample count of 1). The multisample content is
2368 automatically resolved into this texture at the end of each render pass.
2369 */
2370
2371/*!
2372 \fn void QRhiColorAttachment::setResolveTexture(QRhiTexture *tex)
2373
2374 Sets the resolve texture \a tex.
2375
2376 \a tex is expected to be a 2D texture or a 2D texture array. In either
2377 case, resolving targets a single mip level of a single layer (array
2378 element) of \a tex. The mip level and array layer are specified by
2379 resolveLevel() and resolveLayer().
2380
2381 An exception is \l{setMultiViewCount()}{multiview}: when the color
2382 attachment is associated with a texture array and multiview is enabled, the
2383 resolve texture must also be a texture array with sufficient elements for
2384 all views. In this case all elements that correspond to views are resolved
2385 automatically; the behavior is similar to the following pseudo-code:
2386 \badcode
2387 for (i = 0; i < multiViewCount(); ++i)
2388 resolve texture's layer() + i into resolveTexture's resolveLayer() + i
2389 \endcode
2390
2391 Setting a non-multisample texture to resolve a multisample texture or
2392 renderbuffer automatically at the end of the render pass is often
2393 preferable to working with multisample textures (and not setting a resolve
2394 texture), because it avoids the need for writing dedicated fragment shaders
2395 that work exclusively with multisample textures (\c sampler2DMS, \c
2396 texelFetch, etc.), and rather allows using the same shader as one would if
2397 the attachment's texture was not multisampled to begin with. This comes at
2398 the expense of an additional resource (the non-multisample \a tex).
2399 */
2400
2401/*!
2402 \fn int QRhiColorAttachment::resolveLayer() const
2403 \return the currently set resolve texture layer. Defaults to 0.
2404 */
2405
2406/*!
2407 \fn void QRhiColorAttachment::setResolveLayer(int layer)
2408 Sets the resolve texture \a layer to use.
2409 */
2410
2411/*!
2412 \fn int QRhiColorAttachment::resolveLevel() const
2413 \return the currently set resolve texture mip level. Defaults to 0.
2414 */
2415
2416/*!
2417 \fn void QRhiColorAttachment::setResolveLevel(int level)
2418 Sets the resolve texture mip \a level to use.
2419 */
2420
2421/*!
2422 \fn int QRhiColorAttachment::multiViewCount() const
2423
2424 \return the currently set number of views. Defaults to 0 which indicates
2425 the render target with this color attachment is not going to be used with
2426 multiview rendering.
2427
2428 \since 6.7
2429 */
2430
2431/*!
2432 \fn void QRhiColorAttachment::setMultiViewCount(int count)
2433
2434 Sets the view \a count. Setting a value larger than 1 indicates that the
2435 render target with this color attachment is going to be used with multiview
2436 rendering. The default value is 0. Values smaller than 2 indicate no
2437 multiview rendering.
2438
2439 When \a count is set to \c 2 or greater, the color attachment must be
2440 associated with a 2D texture array. layer() and multiViewCount() together
2441 define the range of texture array elements that are targeted during
2442 multiview rendering.
2443
2444 For example, if \c layer is \c 0 and \c multiViewCount is \c 2, the texture
2445 array must have 2 (or more) elements, and the multiview rendering will
2446 target elements 0 and 1. The \c{gl_ViewIndex} variable in the shaders has a
2447 value of \c 0 or \c 1 then, where view \c 0 corresponds to the texture array
2448 element \c 0, and view \c 1 to the array element \c 1.
2449
2450 \note Setting a \a count larger than 1, using a texture array as texture(),
2451 and calling \l{QRhiCommandBuffer::beginPass()}{beginPass()} on a
2452 QRhiTextureRenderTarget with this color attachment implies multiview
2453 rendering for the entire render pass. multiViewCount() should not be set
2454 unless multiview rendering is wanted. Multiview cannot be used with texture
2455 types other than 2D texture arrays. (although 3D textures may work,
2456 depending on the graphics API and backend; applications are nonetheless
2457 advised not to rely on that and only use 2D texture arrays as the render
2458 targets of multiview rendering)
2459
2460 See
2461 \l{https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview.txt}{GL_OVR_multiview}
2462 for more details regarding multiview rendering. Do note that Qt requires
2463 \l{https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview2.txt}{GL_OVR_multiview2}
2464 as well, when running on OpenGL (ES).
2465
2466 Multiview rendering is available only when the
2467 \l{QRhi::MultiView}{MultiView} feature is reported as supported from
2468 \l{QRhi::isFeatureSupported()}{isFeatureSupported()}.
2469
2470 \note For portability, be aware of limitations that exist for multiview
2471 rendering with some of the graphics APIs. It is recommended that multiview
2472 render passes do not rely on any of the features that
2473 \l{https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview.txt}{GL_OVR_multiview}
2474 declares as unsupported. The one exception is shader stage outputs other
2475 than \c{gl_Position} depending on \c{gl_ViewIndex}: that can be relied on
2476 (even with OpenGL) because QRhi never reports multiview as supported without
2477 \c{GL_OVR_multiview2} also being present.
2478
2479 \note Multiview rendering is not supported in combination with tessellation
2480 or geometry shaders, even though some implementations of some graphics APIs
2481 may allow this.
2482
2483 \since 6.7
2484 */
2485
2486/*!
2487 \class QRhiTextureRenderTargetDescription
2488 \inmodule QtGuiPrivate
2489 \inheaderfile rhi/qrhi.h
2490 \since 6.6
2491 \brief Describes the color and depth or depth/stencil attachments of a render target.
2492
2493 A texture render target has zero or more textures as color attachments,
2494 zero or one renderbuffer as combined depth/stencil buffer or zero or one
2495 texture as depth buffer.
2496
2497 \note depthStencilBuffer() and depthTexture() cannot be both set (cannot be
2498 non-null at the same time).
2499
2500 Let's look at some example usages in combination with
2501 QRhiTextureRenderTarget.
2502
2503 Due to the constructors, the targeting a texture (and no depth/stencil
2504 buffer) is simple:
2505
2506 \code
2507 QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(256, 256), 1, QRhiTexture::RenderTarget);
2508 texture->create();
2509 QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ texture }));
2510 \endcode
2511
2512 The following creates a texture render target that is set up to target mip
2513 level #2 of a texture:
2514
2515 \code
2516 QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget | QRhiTexture::MipMapped);
2517 texture->create();
2518 QRhiColorAttachment colorAtt(texture);
2519 colorAtt.setLevel(2);
2520 QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ colorAtt });
2521 \endcode
2522
2523 Another example, this time to render into a depth texture:
2524
2525 \code
2526 QRhiTexture *shadowMap = rhi->newTexture(QRhiTexture::D32F, QSize(1024, 1024), 1, QRhiTexture::RenderTarget);
2527 shadowMap->create();
2528 QRhiTextureRenderTargetDescription rtDesc;
2529 rtDesc.setDepthTexture(shadowMap);
2530 QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget(rtDesc);
2531 \endcode
2532
2533 A very common case, having a texture as the color attachment and a
2534 renderbuffer as depth/stencil to enable depth testing:
2535
2536 \code
2537 QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget);
2538 texture->create();
2539 QRhiRenderBuffer *depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, QSize(512, 512));
2540 depthStencil->create();
2541 QRhiTextureRenderTargetDescription rtDesc({ texture }, depthStencil);
2542 QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget(rtDesc);
2543 \endcode
2544
2545 Finally, to enable multisample rendering in a portable manner (so also
2546 supporting OpenGL ES 3.0), using a QRhiRenderBuffer as the (multisample)
2547 color buffer and then resolving into a regular (non-multisample) 2D
2548 texture. To enable depth testing, a depth-stencil buffer, which also must
2549 use the same sample count, is used as well:
2550
2551 \code
2552 QRhiRenderBuffer *colorBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::Color, QSize(512, 512), 4); // 4x MSAA
2553 colorBuffer->create();
2554 QRhiRenderBuffer *depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, QSize(512, 512), 4);
2555 depthStencil->create();
2556 QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget);
2557 texture->create();
2558 QRhiColorAttachment colorAtt(colorBuffer);
2559 colorAtt.setResolveTexture(texture);
2560 QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ colorAtt, depthStencil });
2561 \endcode
2562
2563 \note when multisample resolving is enabled, the multisample data may not be
2564 written out at all. This means that the multisample texture in a color
2565 attachment must not be used afterwards with shaders for sampling (or other
2566 purposes) whenever a resolve texture is set, since the multisample color
2567 buffer is merely an intermediate storage then that gets no data written back
2568 on some GPU architectures at all. See
2569 \l{QRhiTextureRenderTarget::Flag}{PreserveColorContents} for more details.
2570
2571 \note When using setDepthTexture(), not setDepthStencilBuffer(), and the
2572 depth (stencil) data is not of interest afterwards, set the
2573 DoNotStoreDepthStencilContents flag on the QRhiTextureRenderTarget. This
2574 allows indicating to the underlying 3D API that the depth/stencil data can
2575 be discarded, leading potentially to better performance with tiled GPU
2576 architectures. When the depth-stencil buffer is a QRhiRenderBuffer (and also
2577 for the multisample color texture, see previous note) this is implicit, but
2578 with a depth (stencil) QRhiTexture the intention needs to be declared
2579 explicitly. By default QRhi assumes that the data is of interest (e.g., the
2580 depth texture is sampled in a shader afterwards).
2581
2582 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
2583 for details.
2584
2585 \sa QRhiColorAttachment, QRhiTextureRenderTarget
2586 */
2587
2588/*!
2589 \fn QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription() = default
2590
2591 Constructs an empty texture render target description.
2592 */
2593
2594/*!
2595 Constructs a texture render target description with one attachment
2596 described by \a colorAttachment.
2597 */
2598QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment)
2599{
2600 m_colorAttachments.append(t: colorAttachment);
2601}
2602
2603/*!
2604 Constructs a texture render target description with two attachments, a
2605 color attachment described by \a colorAttachment, and a depth/stencil
2606 attachment with \a depthStencilBuffer.
2607 */
2608QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment,
2609 QRhiRenderBuffer *depthStencilBuffer)
2610 : m_depthStencilBuffer(depthStencilBuffer)
2611{
2612 m_colorAttachments.append(t: colorAttachment);
2613}
2614
2615/*!
2616 Constructs a texture render target description with two attachments, a
2617 color attachment described by \a colorAttachment, and a depth attachment
2618 with \a depthTexture.
2619
2620 \note \a depthTexture must have a suitable format, such as QRhiTexture::D16
2621 or QRhiTexture::D32F.
2622 */
2623QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment,
2624 QRhiTexture *depthTexture)
2625 : m_depthTexture(depthTexture)
2626{
2627 m_colorAttachments.append(t: colorAttachment);
2628}
2629
2630/*!
2631 \fn void QRhiTextureRenderTargetDescription::setColorAttachments(std::initializer_list<QRhiColorAttachment> list)
2632 Sets the \a list of color attachments.
2633 */
2634
2635/*!
2636 \fn template<typename InputIterator> void QRhiTextureRenderTargetDescription::setColorAttachments(InputIterator first, InputIterator last)
2637 Sets the list of color attachments via the iterators \a first and \a last.
2638 */
2639
2640/*!
2641 \fn const QRhiColorAttachment *QRhiTextureRenderTargetDescription::cbeginColorAttachments() const
2642 \return a const iterator pointing to the first item in the attachment list.
2643 */
2644
2645/*!
2646 \fn const QRhiColorAttachment *QRhiTextureRenderTargetDescription::cendColorAttachments() const
2647 \return a const iterator pointing just after the last item in the attachment list.
2648 */
2649
2650/*!
2651 \fn const QRhiColorAttachment *QRhiTextureRenderTargetDescription::colorAttachmentAt(qsizetype index) const
2652 \return the color attachment at the specified \a index.
2653 */
2654
2655/*!
2656 \fn qsizetype QRhiTextureRenderTargetDescription::colorAttachmentCount() const
2657 \return the number of currently set color attachments.
2658 */
2659
2660/*!
2661 \fn QRhiRenderBuffer *QRhiTextureRenderTargetDescription::depthStencilBuffer() const
2662 \return the renderbuffer used as depth-stencil buffer, or \nullptr if none was set.
2663 */
2664
2665/*!
2666 \fn void QRhiTextureRenderTargetDescription::setDepthStencilBuffer(QRhiRenderBuffer *renderBuffer)
2667
2668 Sets the \a renderBuffer for depth-stencil. Not mandatory, e.g. when no
2669 depth test/write or stencil-related features are used within any graphics
2670 pipelines in any of the render passes for this render target, it can be
2671 left set to \nullptr.
2672
2673 \note depthStencilBuffer() and depthTexture() cannot be both set (cannot be
2674 non-null at the same time).
2675
2676 Using a QRhiRenderBuffer over a 2D QRhiTexture as the depth or
2677 depth/stencil buffer is very common, and is the recommended approach for
2678 applications. Using a QRhiTexture, and so setDepthTexture() becomes
2679 relevant if the depth data is meant to be accessed (e.g. sampled in a
2680 shader) afterwards, or when
2681 \l{QRhiColorAttachment::setMultiViewCount()}{multiview rendering} is
2682 involved (because then the depth texture must be a texture array).
2683
2684 \sa setDepthTexture()
2685 */
2686
2687/*!
2688 \fn QRhiTexture *QRhiTextureRenderTargetDescription::depthTexture() const
2689 \return the currently referenced depth texture, or \nullptr if none was set.
2690 */
2691
2692/*!
2693 \fn void QRhiTextureRenderTargetDescription::setDepthTexture(QRhiTexture *texture)
2694
2695 Sets the \a texture for depth-stencil. This is an alternative to
2696 setDepthStencilBuffer(), where instead of a QRhiRenderBuffer a QRhiTexture
2697 with a suitable type (e.g., QRhiTexture::D32F) is provided.
2698
2699 \note depthStencilBuffer() and depthTexture() cannot be both set (cannot be
2700 non-null at the same time).
2701
2702 \a texture can either be a 2D texture or a 2D texture array (when texture
2703 arrays are supported). Specifying a texture array is relevant in particular
2704 with
2705 \l{QRhiColorAttachment::setMultiViewCount()}{multiview rendering}.
2706
2707 \note If \a texture is a format with a stencil component, such as
2708 \l QRhiTexture::D24S8, it will serve as the stencil buffer as well.
2709
2710 \sa setDepthStencilBuffer()
2711 */
2712
2713/*!
2714 \fn QRhiTexture *QRhiTextureRenderTargetDescription::depthResolveTexture() const
2715
2716 \return the texture to which a multisample depth (or depth-stencil) texture
2717 (or texture array) is resolved to. \nullptr if there is none, which is the
2718 most common case.
2719
2720 \since 6.8
2721 \sa QRhiColorAttachment::resolveTexture(), depthTexture()
2722 */
2723
2724/*!
2725 \fn void QRhiTextureRenderTargetDescription::setDepthResolveTexture(QRhiTexture *tex)
2726
2727 Sets the depth (or depth-stencil) resolve texture \a tex.
2728
2729 \a tex is expected to be a 2D texture or a 2D texture array with a format
2730 matching the texture set via setDepthTexture().
2731
2732 \note Resolving depth (or depth-stencil) data is only functional when the
2733 \l ResolveDepthStencil feature is reported as supported at run time. Support
2734 for depth-stencil resolve is not universally available among the graphics
2735 APIs. Designs assuming unconditional availability of depth-stencil resolve
2736 are therefore non-portable, and should be avoided.
2737
2738 \note As an additional limitation for OpenGL ES in particular, setting a
2739 depth resolve texture may only be functional in combination with
2740 setDepthTexture(), not with setDepthStencilBuffer().
2741
2742 \since 6.8
2743 \sa QRhiColorAttachment::setResolveTexture(), setDepthTexture()
2744 */
2745
2746/*!
2747 \class QRhiTextureSubresourceUploadDescription
2748 \inmodule QtGuiPrivate
2749 \inheaderfile rhi/qrhi.h
2750 \since 6.6
2751 \brief Describes the source for one mip level in a layer in a texture upload operation.
2752
2753 The source content is specified either as a QImage or as a raw blob. The
2754 former is only allowed for uncompressed textures with a format that can be
2755 mapped to QImage, while the latter is supported for all formats, including
2756 floating point and compressed.
2757
2758 \note image() and data() cannot be both set at the same time.
2759
2760 destinationTopLeft() specifies the top-left corner of the target
2761 rectangle. Defaults to (0, 0).
2762
2763 An empty sourceSize() (the default) indicates that size is assumed to be
2764 the size of the subresource. With QImage-based uploads this implies that
2765 the size of the source image() must match the subresource. When providing
2766 raw data instead, sufficient number of bytes must be provided in data().
2767
2768 sourceTopLeft() is supported only for QImage-based uploads, and specifies
2769 the top-left corner of the source rectangle.
2770
2771 \note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy
2772 internally, depending on the format and the backend.
2773
2774 When providing raw data, and the stride is not specified via
2775 setDataStride(), the stride (row pitch, row length in bytes) of the
2776 provided data must be equal to \c{width * pixelSize} where \c pixelSize is
2777 the number of bytes used for one pixel, and there must be no additional
2778 padding between rows. There is no row start alignment requirement.
2779
2780 When there is unused data at the end of each row in the input raw data,
2781 call setDataStride() with the total number of bytes per row. The stride
2782 must always be a multiple of the number of bytes for one pixel. The row
2783 stride is only applicable to image data for textures with an uncompressed
2784 format.
2785
2786 \note The format of the source data must be compatible with the texture
2787 format. With many graphics APIs the data is copied as-is into a staging
2788 buffer, there is no intermediate format conversion provided by QRhi. This
2789 applies to floating point formats as well, with, for example, RGBA16F
2790 requiring half floats in the source data.
2791
2792 \note Setting the stride via setDataStride() is only functional when
2793 QRhi::ImageDataStride is reported as
2794 \l{QRhi::isFeatureSupported()}{supported}. In practice this can be expected
2795 to be supported everywhere except for OpenGL ES 2.0.
2796
2797 \note When a QImage is given, the stride returned from
2798 QImage::bytesPerLine() is taken into account automatically.
2799
2800 \warning When a QImage is given and the QImage does not own the underlying
2801 pixel data, it is up to the caller to ensure that the associated data stays
2802 valid until the end of the frame. (just submitting the resource update batch
2803 is not sufficient, the data must stay valid until QRhi::endFrame() is called
2804 in order to be portable across all backends) If this cannot be ensured, the
2805 caller is strongly encouraged to call QImage::detach() on the image before
2806 passing it to uploadTexture().
2807
2808 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
2809 for details.
2810
2811 \sa QRhiTextureUploadDescription
2812 */
2813
2814/*!
2815 \fn QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription() = default
2816
2817 Constructs an empty subresource description.
2818
2819 \note an empty QRhiTextureSubresourceUploadDescription is not useful on its
2820 own and should not be submitted to a QRhiTextureUploadEntry. At minimum
2821 image or data must be set first.
2822 */
2823
2824/*!
2825 Constructs a mip level description with a \a image.
2826
2827 The \l{QImage::size()}{size} of \a image must match the size of the mip
2828 level. For level 0 that is the \l{QRhiTexture::pixelSize()}{texture size}.
2829
2830 The bit depth of \a image must be compatible with the
2831 \l{QRhiTexture::Format}{texture format}.
2832
2833 To describe a partial upload, call setSourceSize(), setSourceTopLeft(), or
2834 setDestinationTopLeft() afterwards.
2835 */
2836QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription(const QImage &image)
2837 : m_image(image)
2838{
2839}
2840
2841/*!
2842 Constructs a mip level description with the image data is specified by \a
2843 data and \a size. This is suitable for floating point and compressed
2844 formats as well.
2845
2846 \a data can safely be destroyed or changed once this function returns.
2847 */
2848QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription(const void *data, quint32 size)
2849 : m_data(reinterpret_cast<const char *>(data), size)
2850{
2851}
2852
2853/*!
2854 Constructs a mip level description with the image data specified by \a
2855 data. This is suitable for floating point and compressed formats as well.
2856 */
2857QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription(const QByteArray &data)
2858 : m_data(data)
2859{
2860}
2861
2862/*!
2863 \fn QImage QRhiTextureSubresourceUploadDescription::image() const
2864 \return the currently set QImage.
2865 */
2866
2867/*!
2868 \fn void QRhiTextureSubresourceUploadDescription::setImage(const QImage &image)
2869
2870 Sets \a image.
2871 Upon textures loading, the image data will be read as is, with no formats conversions.
2872
2873 \note image() and data() cannot be both set at the same time.
2874 */
2875
2876/*!
2877 \fn QByteArray QRhiTextureSubresourceUploadDescription::data() const
2878 \return the currently set raw pixel data.
2879 */
2880
2881/*!
2882 \fn void QRhiTextureSubresourceUploadDescription::setData(const QByteArray &data)
2883
2884 Sets \a data.
2885
2886 \note image() and data() cannot be both set at the same time.
2887 */
2888
2889/*!
2890 \fn quint32 QRhiTextureSubresourceUploadDescription::dataStride() const
2891 \return the currently set data stride.
2892 */
2893
2894/*!
2895 \fn void QRhiTextureSubresourceUploadDescription::setDataStride(quint32 stride)
2896
2897 Sets the data \a stride in bytes. By default this is 0 and not always
2898 relevant. When providing raw data(), and the stride is not specified via
2899 setDataStride(), the stride (row pitch, row length in bytes) of the
2900 provided data must be equal to \c{width * pixelSize} where \c pixelSize is
2901 the number of bytes used for one pixel, and there must be no additional
2902 padding between rows. Otherwise, if there is additional space between the
2903 lines, set a non-zero \a stride. All this is applicable only when raw image
2904 data is provided, and is not necessary when working QImage since that has
2905 its own \l{QImage::bytesPerLine()}{stride} value.
2906
2907 \note Setting the stride via setDataStride() is only functional when
2908 QRhi::ImageDataStride is reported as
2909 \l{QRhi::isFeatureSupported()}{supported}.
2910
2911 \note When a QImage is given, the stride returned from
2912 QImage::bytesPerLine() is taken into account automatically and therefore
2913 there is no need to set the data stride manually.
2914 */
2915
2916/*!
2917 \fn QPoint QRhiTextureSubresourceUploadDescription::destinationTopLeft() const
2918 \return the currently set destination top-left position. Defaults to (0, 0).
2919 */
2920
2921/*!
2922 \fn void QRhiTextureSubresourceUploadDescription::setDestinationTopLeft(const QPoint &p)
2923 Sets the destination top-left position \a p.
2924 */
2925
2926/*!
2927 \fn QSize QRhiTextureSubresourceUploadDescription::sourceSize() const
2928
2929 \return the source size in pixels. Defaults to a default-constructed QSize,
2930 which indicates the entire subresource.
2931 */
2932
2933/*!
2934 \fn void QRhiTextureSubresourceUploadDescription::setSourceSize(const QSize &size)
2935
2936 Sets the source \a size in pixels.
2937
2938 \note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy
2939 internally, depending on the format and the backend.
2940 */
2941
2942/*!
2943 \fn QPoint QRhiTextureSubresourceUploadDescription::sourceTopLeft() const
2944 \return the currently set source top-left position. Defaults to (0, 0).
2945 */
2946
2947/*!
2948 \fn void QRhiTextureSubresourceUploadDescription::setSourceTopLeft(const QPoint &p)
2949
2950 Sets the source top-left position \a p.
2951
2952 \note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy
2953 internally, depending on the format and the backend.
2954 */
2955
2956/*!
2957 \class QRhiTextureUploadEntry
2958 \inmodule QtGuiPrivate
2959 \inheaderfile rhi/qrhi.h
2960 \since 6.6
2961
2962 \brief Describes one layer (face for cubemaps, slice for 3D textures,
2963 element for texture arrays) in a texture upload operation.
2964
2965 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
2966 for details.
2967 */
2968
2969/*!
2970 \fn QRhiTextureUploadEntry::QRhiTextureUploadEntry()
2971
2972 Constructs an empty QRhiTextureUploadEntry targeting layer 0 and level 0.
2973
2974 \note an empty QRhiTextureUploadEntry should not be submitted without
2975 setting a QRhiTextureSubresourceUploadDescription via setDescription()
2976 first.
2977 */
2978
2979/*!
2980 Constructs a QRhiTextureUploadEntry targeting the given \a layer and mip
2981 \a level, with the subresource contents described by \a desc.
2982 */
2983QRhiTextureUploadEntry::QRhiTextureUploadEntry(int layer, int level,
2984 const QRhiTextureSubresourceUploadDescription &desc)
2985 : m_layer(layer),
2986 m_level(level),
2987 m_desc(desc)
2988{
2989}
2990
2991/*!
2992 \fn int QRhiTextureUploadEntry::layer() const
2993 \return the currently set layer index (cubemap face, array layer). Defaults to 0.
2994 */
2995
2996/*!
2997 \fn void QRhiTextureUploadEntry::setLayer(int layer)
2998 Sets the \a layer.
2999 */
3000
3001/*!
3002 \fn int QRhiTextureUploadEntry::level() const
3003 \return the currently set mip level. Defaults to 0.
3004 */
3005
3006/*!
3007 \fn void QRhiTextureUploadEntry::setLevel(int level)
3008 Sets the mip \a level.
3009 */
3010
3011/*!
3012 \fn QRhiTextureSubresourceUploadDescription QRhiTextureUploadEntry::description() const
3013 \return the currently set subresource description.
3014 */
3015
3016/*!
3017 \fn void QRhiTextureUploadEntry::setDescription(const QRhiTextureSubresourceUploadDescription &desc)
3018 Sets the subresource description \a desc.
3019 */
3020
3021/*!
3022 \class QRhiTextureUploadDescription
3023 \inmodule QtGuiPrivate
3024 \inheaderfile rhi/qrhi.h
3025 \since 6.6
3026 \brief Describes a texture upload operation.
3027
3028 Used with QRhiResourceUpdateBatch::uploadTexture(). That function has two
3029 variants: one taking a QImage and one taking a
3030 QRhiTextureUploadDescription. The former is a convenience version,
3031 internally creating a QRhiTextureUploadDescription with a single image
3032 targeting level 0 for layer 0.
3033
3034 An example of the the common, simple case of wanting to upload the contents
3035 of a QImage to a QRhiTexture with a matching pixel size:
3036
3037 \code
3038 QImage image(256, 256, QImage::Format_RGBA8888);
3039 image.fill(Qt::green); // or could use a QPainter targeting image
3040 QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(256, 256));
3041 texture->create();
3042 QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch();
3043 u->uploadTexture(texture, image);
3044 \endcode
3045
3046 When cubemaps, pre-generated mip images, compressed textures, or partial
3047 uploads are involved, applications will have to use this class instead.
3048
3049 QRhiTextureUploadDescription also enables specifying batched uploads, which
3050 are useful for example when generating an atlas or glyph cache texture:
3051 multiple, partial uploads for the same subresource (meaning the same layer
3052 and level) are supported, and can be, depending on the backend and the
3053 underlying graphics API, more efficient when batched into the same
3054 QRhiTextureUploadDescription as opposed to issuing individual
3055 \l{QRhiResourceUpdateBatch::uploadTexture()}{uploadTexture()} commands for
3056 each of them.
3057
3058 \note Cubemaps have one layer for each of the six faces in the order +X,
3059 -X, +Y, -Y, +Z, -Z.
3060
3061 For example, specifying the faces of a cubemap could look like the following:
3062
3063 \code
3064 QImage faces[6];
3065 // ...
3066 QVarLengthArray<QRhiTextureUploadEntry, 6> entries;
3067 for (int i = 0; i < 6; ++i)
3068 entries.append(QRhiTextureUploadEntry(i, 0, faces[i]));
3069 QRhiTextureUploadDescription desc;
3070 desc.setEntries(entries.cbegin(), entries.cend());
3071 resourceUpdates->uploadTexture(texture, desc);
3072 \endcode
3073
3074 Another example that specifies mip images for a compressed texture:
3075
3076 \code
3077 QList<QRhiTextureUploadEntry> entries;
3078 const int mipCount = rhi->mipLevelsForSize(compressedTexture->pixelSize());
3079 for (int level = 0; level < mipCount; ++level) {
3080 const QByteArray compressedDataForLevel = ..
3081 entries.append(QRhiTextureUploadEntry(0, level, compressedDataForLevel));
3082 }
3083 QRhiTextureUploadDescription desc;
3084 desc.setEntries(entries.cbegin(), entries.cend());
3085 resourceUpdates->uploadTexture(compressedTexture, desc);
3086 \endcode
3087
3088 With partial uploads targeting the same subresource, it is recommended to
3089 batch them into a single upload request, whenever possible:
3090
3091 \code
3092 QRhiTextureSubresourceUploadDescription subresDesc(image);
3093 subresDesc.setSourceSize(QSize(10, 10));
3094 subResDesc.setDestinationTopLeft(QPoint(50, 40));
3095 QRhiTextureUploadEntry entry(0, 0, subresDesc); // layer 0, level 0
3096
3097 QRhiTextureSubresourceUploadDescription subresDesc2(image);
3098 subresDesc2.setSourceSize(QSize(30, 40));
3099 subResDesc2.setDestinationTopLeft(QPoint(100, 200));
3100 QRhiTextureUploadEntry entry2(0, 0, subresDesc2); // layer 0, level 0, i.e. same subresource
3101
3102 QRhiTextureUploadDescription desc({ entry, entry2});
3103 resourceUpdates->uploadTexture(texture, desc);
3104 \endcode
3105
3106 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
3107 for details.
3108
3109 \sa QRhiResourceUpdateBatch
3110 */
3111
3112/*!
3113 \fn QRhiTextureUploadDescription::QRhiTextureUploadDescription()
3114
3115 Constructs an empty texture upload description.
3116 */
3117
3118/*!
3119 Constructs a texture upload description with a single subresource upload
3120 described by \a entry.
3121 */
3122QRhiTextureUploadDescription::QRhiTextureUploadDescription(const QRhiTextureUploadEntry &entry)
3123{
3124 m_entries.append(t: entry);
3125}
3126
3127/*!
3128 Constructs a texture upload description with the specified \a list of entries.
3129
3130 \note \a list can also contain multiple QRhiTextureUploadEntry elements
3131 with the same layer and level. This makes sense when those uploads are
3132 partial, meaning their subresource description has a source size or image
3133 smaller than the subresource dimensions, and can be more efficient than
3134 issuing separate uploadTexture()'s.
3135 */
3136QRhiTextureUploadDescription::QRhiTextureUploadDescription(std::initializer_list<QRhiTextureUploadEntry> list)
3137 : m_entries(list)
3138{
3139}
3140
3141/*!
3142 \fn void QRhiTextureUploadDescription::setEntries(std::initializer_list<QRhiTextureUploadEntry> list)
3143 Sets the \a list of entries.
3144 */
3145
3146/*!
3147 \fn template<typename InputIterator> void QRhiTextureUploadDescription::setEntries(InputIterator first, InputIterator last)
3148 Sets the list of entries using the iterators \a first and \a last.
3149 */
3150
3151/*!
3152 \fn const QRhiTextureUploadEntry *QRhiTextureUploadDescription::cbeginEntries() const
3153 \return a const iterator pointing to the first item in the entry list.
3154 */
3155
3156/*!
3157 \fn const QRhiTextureUploadEntry *QRhiTextureUploadDescription::cendEntries() const
3158 \return a const iterator pointing just after the last item in the entry list.
3159 */
3160
3161/*!
3162 \fn const QRhiTextureUploadEntry *QRhiTextureUploadDescription::entryAt(qsizetype index) const
3163 \return the entry at \a index.
3164 */
3165
3166/*!
3167 \fn qsizetype QRhiTextureUploadDescription::entryCount() const
3168 \return the number of entries.
3169 */
3170
3171/*!
3172 \class QRhiTextureCopyDescription
3173 \inmodule QtGuiPrivate
3174 \inheaderfile rhi/qrhi.h
3175 \since 6.6
3176 \brief Describes a texture-to-texture copy operation.
3177
3178 An empty pixelSize() indicates that the entire subresource is to be copied.
3179 A default constructed copy description therefore leads to copying the
3180 entire subresource at level 0 of layer 0.
3181
3182 \note The source texture must be created with
3183 QRhiTexture::UsedAsTransferSource.
3184
3185 \note The source and destination rectangles defined by pixelSize(),
3186 sourceTopLeft(), and destinationTopLeft() must fit the source and
3187 destination textures, respectively. The behavior is undefined otherwise.
3188
3189 With cubemaps, 3D textures, and texture arrays one face or slice can be
3190 copied at a time. The face or slice is specified by the source and
3191 destination layer indices. With mipmapped textures one mip level can be
3192 copied at a time. The source and destination layer and mip level indices can
3193 differ, but the size and position must be carefully controlled to avoid out
3194 of bounds copies, in which case the behavior is undefined.
3195
3196 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
3197 for details.
3198 */
3199
3200/*!
3201 \fn QRhiTextureCopyDescription::QRhiTextureCopyDescription()
3202
3203 Constructs an empty texture copy description.
3204 */
3205
3206/*!
3207 \fn QSize QRhiTextureCopyDescription::pixelSize() const
3208 \return the size of the region to copy.
3209
3210 \note An empty pixelSize() indicates that the entire subresource is to be
3211 copied. A default constructed copy description therefore leads to copying
3212 the entire subresource at level 0 of layer 0.
3213 */
3214
3215/*!
3216 \fn void QRhiTextureCopyDescription::setPixelSize(const QSize &sz)
3217 Sets the size of the region to copy to \a sz.
3218 */
3219
3220/*!
3221 \fn int QRhiTextureCopyDescription::sourceLayer() const
3222 \return the source array layer (cubemap face or array layer index). Defaults to 0.
3223 */
3224
3225/*!
3226 \fn void QRhiTextureCopyDescription::setSourceLayer(int layer)
3227 Sets the source array \a layer.
3228 */
3229
3230/*!
3231 \fn int QRhiTextureCopyDescription::sourceLevel() const
3232 \return the source mip level. Defaults to 0.
3233 */
3234
3235/*!
3236 \fn void QRhiTextureCopyDescription::setSourceLevel(int level)
3237 Sets the source mip \a level.
3238 */
3239
3240/*!
3241 \fn QPoint QRhiTextureCopyDescription::sourceTopLeft() const
3242 \return the source top-left position (in pixels). Defaults to (0, 0).
3243 */
3244
3245/*!
3246 \fn void QRhiTextureCopyDescription::setSourceTopLeft(const QPoint &p)
3247 Sets the source top-left position to \a p.
3248 */
3249
3250/*!
3251 \fn int QRhiTextureCopyDescription::destinationLayer() const
3252 \return the destination array layer (cubemap face or array layer index). Default to 0.
3253 */
3254
3255/*!
3256 \fn void QRhiTextureCopyDescription::setDestinationLayer(int layer)
3257 Sets the destination array \a layer.
3258 */
3259
3260/*!
3261 \fn int QRhiTextureCopyDescription::destinationLevel() const
3262 \return the destionation mip level. Defaults to 0.
3263 */
3264
3265/*!
3266 \fn void QRhiTextureCopyDescription::setDestinationLevel(int level)
3267 Sets the destination mip \a level.
3268 */
3269
3270/*!
3271 \fn QPoint QRhiTextureCopyDescription::destinationTopLeft() const
3272 \return the destionation top-left position in pixels. Defaults to (0, 0).
3273 */
3274
3275/*!
3276 \fn void QRhiTextureCopyDescription::setDestinationTopLeft(const QPoint &p)
3277 Sets the destination top-left position \a p.
3278 */
3279
3280/*!
3281 \class QRhiReadbackDescription
3282 \inmodule QtGuiPrivate
3283 \inheaderfile rhi/qrhi.h
3284 \since 6.6
3285 \brief Describes a readback (reading back texture contents from possibly GPU-only memory) operation.
3286
3287 The source of the readback operation is either a QRhiTexture or the
3288 current backbuffer of the currently targeted QRhiSwapChain. When
3289 texture() is not set, the swapchain is used. Otherwise the specified
3290 QRhiTexture is treated as the source.
3291
3292 \note Textures used in readbacks must be created with
3293 QRhiTexture::UsedAsTransferSource.
3294
3295 \note Swapchains used in readbacks must be created with
3296 QRhiSwapChain::UsedAsTransferSource.
3297
3298 layer() and level() are only applicable when the source is a QRhiTexture.
3299
3300 \note Multisample textures cannot be read back. Readbacks are supported for
3301 multisample swapchain buffers however.
3302
3303 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
3304 for details.
3305 */
3306
3307/*!
3308 \fn QRhiReadbackDescription::QRhiReadbackDescription() = default
3309
3310 Constructs an empty texture readback description.
3311
3312 \note The source texture is set to null by default, which is still a valid
3313 readback: it specifies that the backbuffer of the current swapchain is to
3314 be read back. (current meaning the frame's target swapchain at the time of
3315 committing the QRhiResourceUpdateBatch with the
3316 \l{QRhiResourceUpdateBatch::readBackTexture()}{texture readback} on it)
3317 */
3318
3319/*!
3320 Constructs an texture readback description that specifies that level 0 of
3321 layer 0 of \a texture is to be read back.
3322
3323 \note \a texture can also be null in which case this constructor is
3324 identical to the argumentless variant.
3325 */
3326QRhiReadbackDescription::QRhiReadbackDescription(QRhiTexture *texture)
3327 : m_texture(texture)
3328{
3329}
3330
3331/*!
3332 \fn QRhiTexture *QRhiReadbackDescription::texture() const
3333
3334 \return the QRhiTexture that is read back. Can be left set to \nullptr
3335 which indicates that the backbuffer of the current swapchain is to be used
3336 instead.
3337 */
3338
3339/*!
3340 \fn void QRhiReadbackDescription::setTexture(QRhiTexture *tex)
3341
3342 Sets the texture \a tex as the source of the readback operation.
3343
3344 Setting \nullptr is valid too, in which case the current swapchain's
3345 current backbuffer is used. (but then the readback cannot be issued in a
3346 non-swapchain-based frame)
3347
3348 \note Multisample textures cannot be read back. Readbacks are supported for
3349 multisample swapchain buffers however.
3350
3351 \note Textures used in readbacks must be created with
3352 QRhiTexture::UsedAsTransferSource.
3353
3354 \note Swapchains used in readbacks must be created with
3355 QRhiSwapChain::UsedAsTransferSource.
3356 */
3357
3358/*!
3359 \fn int QRhiReadbackDescription::layer() const
3360
3361 \return the currently set array layer (cubemap face, array index). Defaults to 0.
3362
3363 Applicable only when the source of the readback is a QRhiTexture.
3364 */
3365
3366/*!
3367 \fn void QRhiReadbackDescription::setLayer(int layer)
3368 Sets the array \a layer to read back.
3369 */
3370
3371/*!
3372 \fn int QRhiReadbackDescription::level() const
3373
3374 \return the currently set mip level. Defaults to 0.
3375
3376 Applicable only when the source of the readback is a QRhiTexture.
3377 */
3378
3379/*!
3380 \fn void QRhiReadbackDescription::setLevel(int level)
3381 Sets the mip \a level to read back.
3382 */
3383
3384/*!
3385 \class QRhiReadbackResult
3386 \inmodule QtGuiPrivate
3387 \inheaderfile rhi/qrhi.h
3388 \since 6.6
3389 \brief Describes the results of a potentially asynchronous buffer or texture readback operation.
3390
3391 When \l completed is set, the function is invoked when the \l data is
3392 available. \l format and \l pixelSize are set upon completion together with
3393 \l data.
3394
3395 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
3396 for details.
3397 */
3398
3399/*!
3400 \variable QRhiReadbackResult::completed
3401
3402 Callback that is invoked upon completion, on the thread the QRhi operates
3403 on. Can be left set to \nullptr, in which case no callback is invoked.
3404 */
3405
3406/*!
3407 \variable QRhiReadbackResult::format
3408
3409 Valid only for textures, the texture format.
3410 */
3411
3412/*!
3413 \variable QRhiReadbackResult::pixelSize
3414
3415 Valid only for textures, the size in pixels.
3416 */
3417
3418/*!
3419 \variable QRhiReadbackResult::data
3420
3421 The buffer or image data.
3422
3423 \sa QRhiResourceUpdateBatch::readBackTexture(), QRhiResourceUpdateBatch::readBackBuffer()
3424 */
3425
3426
3427/*!
3428 \class QRhiNativeHandles
3429 \inmodule QtGuiPrivate
3430 \inheaderfile rhi/qrhi.h
3431 \since 6.6
3432 \brief Base class for classes exposing backend-specific collections of native resource objects.
3433
3434 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
3435 for details.
3436 */
3437
3438/*!
3439 \class QRhiResource
3440 \inmodule QtGuiPrivate
3441 \inheaderfile rhi/qrhi.h
3442 \since 6.6
3443 \brief Base class for classes encapsulating native resource objects.
3444
3445 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
3446 for details.
3447 */
3448
3449/*!
3450 \enum QRhiResource::Type
3451 Specifies type of the resource.
3452
3453 \value Buffer
3454 \value Texture
3455 \value Sampler
3456 \value RenderBuffer
3457 \value RenderPassDescriptor
3458 \value SwapChainRenderTarget
3459 \value TextureRenderTarget
3460 \value ShaderResourceBindings
3461 \value GraphicsPipeline
3462 \value SwapChain
3463 \value ComputePipeline
3464 \value CommandBuffer
3465 */
3466
3467/*!
3468 \fn virtual QRhiResource::Type QRhiResource::resourceType() const = 0
3469
3470 \return the type of the resource.
3471 */
3472
3473/*!
3474 \internal
3475 */
3476QRhiResource::QRhiResource(QRhiImplementation *rhi)
3477 : m_rhi(rhi)
3478{
3479 m_id = QRhiGlobalObjectIdGenerator::newId();
3480}
3481
3482/*!
3483 Destructor.
3484
3485 Releases (or requests deferred releasing of) the underlying native graphics
3486 resources, if there are any.
3487
3488 \note Resources referenced by commands for the current frame should not be
3489 released until the frame is submitted by QRhi::endFrame().
3490
3491 \sa destroy()
3492 */
3493QRhiResource::~QRhiResource()
3494{
3495 // destroy() cannot be called here, due to virtuals; it is up to the
3496 // subclasses to do that.
3497}
3498
3499/*!
3500 \fn virtual void QRhiResource::destroy() = 0
3501
3502 Releases (or requests deferred releasing of) the underlying native graphics
3503 resources. Safe to call multiple times, subsequent invocations will be a
3504 no-op then.
3505
3506 Once destroy() is called, the QRhiResource instance can be reused, by
3507 calling \c create() again. That will then result in creating new native
3508 graphics resources underneath.
3509
3510 \note Resources referenced by commands for the current frame should not be
3511 released until the frame is submitted by QRhi::endFrame().
3512
3513 The QRhiResource destructor also performs the same task, so calling this
3514 function is not necessary before deleting a QRhiResource.
3515
3516 \sa deleteLater()
3517 */
3518
3519/*!
3520 When called without a frame being recorded, this function is equivalent to
3521 deleting the object. Between a QRhi::beginFrame() and QRhi::endFrame()
3522 however the behavior is different: the QRhiResource will not be destroyed
3523 until the frame is submitted via QRhi::endFrame(), thus satisfying the QRhi
3524 requirement of not altering QRhiResource objects that are referenced by the
3525 frame being recorded.
3526
3527 If the QRhi that created this object is already destroyed, the object is
3528 deleted immediately.
3529
3530 Using deleteLater() can be a useful convenience in many cases, and it
3531 complements the low-level guarantee (that the underlying native graphics
3532 objects are never destroyed until it is safe to do so and it is known for
3533 sure that they are not used by the GPU in an still in-flight frame), by
3534 offering a way to make sure the C++ object instances (of QRhiBuffer,
3535 QRhiTexture, etc.) themselves also stay valid until the end of the current
3536 frame.
3537
3538 The following example shows a convenient way of creating a throwaway buffer
3539 that is only used in one frame and gets automatically released in
3540 endFrame(). (when it comes to the underlying native buffer(s), the usual
3541 guarantee applies: the QRhi backend defers the releasing of those until it
3542 is guaranteed that the frame in which the buffer is accessed by the GPU has
3543 completed)
3544
3545 \code
3546 rhi->beginFrame(swapchain);
3547 QRhiBuffer *buf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, 256);
3548 buf->deleteLater(); // !
3549 u = rhi->nextResourceUpdateBatch();
3550 u->uploadStaticBuffer(buf, data);
3551 // ... draw with buf
3552 rhi->endFrame();
3553 \endcode
3554
3555 \sa destroy()
3556 */
3557void QRhiResource::deleteLater()
3558{
3559 if (m_rhi)
3560 m_rhi->addDeleteLater(res: this);
3561 else
3562 delete this;
3563}
3564
3565/*!
3566 \return the currently set object name. By default the name is empty.
3567 */
3568QByteArray QRhiResource::name() const
3569{
3570 return m_objectName;
3571}
3572
3573/*!
3574 Sets a \a name for the object.
3575
3576 This allows getting descriptive names for the native graphics
3577 resources visible in graphics debugging tools, such as
3578 \l{https://renderdoc.org/}{RenderDoc} and
3579 \l{https://developer.apple.com/xcode/}{XCode}.
3580
3581 When it comes to naming native objects by relaying the name via the
3582 appropriate graphics API, note that the name is ignored when
3583 QRhi::DebugMarkers are not supported, and may, depending on the backend,
3584 also be ignored when QRhi::EnableDebugMarkers is not set.
3585
3586 \note The name may be ignored for objects other than buffers,
3587 renderbuffers, and textures, depending on the backend.
3588
3589 \note The name may be modified. For slotted resources, such as a QRhiBuffer
3590 backed by multiple native buffers, QRhi will append a suffix to make the
3591 underlying native buffers easily distinguishable from each other.
3592 */
3593void QRhiResource::setName(const QByteArray &name)
3594{
3595 m_objectName = name;
3596}
3597
3598/*!
3599 \return the global, unique identifier of this QRhiResource.
3600
3601 User code rarely needs to deal with the value directly. It is used
3602 internally for tracking and bookkeeping purposes.
3603 */
3604quint64 QRhiResource::globalResourceId() const
3605{
3606 return m_id;
3607}
3608
3609/*!
3610 \return the QRhi that created this resource.
3611
3612 If the QRhi that created this object is already destroyed, the result is
3613 \nullptr.
3614 */
3615QRhi *QRhiResource::rhi() const
3616{
3617 return m_rhi ? m_rhi->q : nullptr;
3618}
3619
3620/*!
3621 \class QRhiBuffer
3622 \inmodule QtGuiPrivate
3623 \inheaderfile rhi/qrhi.h
3624 \since 6.6
3625 \brief Vertex, index, or uniform (constant) buffer resource.
3626
3627 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
3628 for details.
3629
3630 A QRhiBuffer encapsulates zero, one, or more native buffer objects (such as
3631 a \c VkBuffer or \c MTLBuffer). With some graphics APIs and backends
3632 certain types of buffers may not use a native buffer object at all (e.g.
3633 OpenGL if uniform buffer objects are not used), but this is transparent to
3634 the user of the QRhiBuffer API. Similarly, the fact that some types of
3635 buffers may use two or three native buffers underneath, in order to allow
3636 efficient per-frame content update without stalling the GPU pipeline, is
3637 mostly invisible to the applications and libraries.
3638
3639 A QRhiBuffer instance is always created by calling
3640 \l{QRhi::newBuffer()}{the QRhi's newBuffer() function}. This creates no
3641 native graphics resources. To do that, call create() after setting the
3642 appropriate options, such as the type, usage flags, size, although in most cases these
3643 are already set based on the arguments passed to
3644 \l{QRhi::newBuffer()}{newBuffer()}.
3645
3646 \section2 Example usage
3647
3648 To create a uniform buffer for a shader where the GLSL uniform block
3649 contains a single \c mat4 member, and update the contents:
3650
3651 \code
3652 QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64);
3653 if (!ubuf->create()) { error(); }
3654 QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
3655 QMatrix4x4 mvp;
3656 // ... set up the modelview-projection matrix
3657 batch->updateDynamicBuffer(ubuf, 0, 64, mvp.constData());
3658 // ...
3659 commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call
3660 \endcode
3661
3662 An example of creating a buffer with vertex data:
3663
3664 \code
3665 const float vertices[] = { -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 1.0f };
3666 QRhiBuffer *vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices));
3667 if (!vbuf->create()) { error(); }
3668 QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
3669 batch->uploadStaticBuffer(vbuf, vertices);
3670 // ...
3671 commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call
3672 \endcode
3673
3674 An index buffer:
3675
3676 \code
3677 static const quint16 indices[] = { 0, 1, 2 };
3678 QRhiBuffer *ibuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(indices));
3679 if (!ibuf->create()) { error(); }
3680 QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
3681 batch->uploadStaticBuffer(ibuf, indices);
3682 // ...
3683 commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call
3684 \endcode
3685
3686 \section2 Common patterns
3687
3688 A call to create() destroys any existing native resources if create() was
3689 successfully called before. If those native resources are still in use by
3690 an in-flight frame (i.e., there's a chance they are still read by the GPU),
3691 the destroying of those resources is deferred automatically. Thus a very
3692 common and convenient pattern to safely increase the size of an already
3693 initialized buffer is the following. In practice this drops and creates a
3694 whole new set of native resources underneath, so it is not necessarily a
3695 cheap operation, but is more convenient and still faster than the
3696 alternatives, because by not destroying the \c buf object itself, all
3697 references to it stay valid in other data structures (e.g., in any
3698 QRhiShaderResourceBinding the QRhiBuffer is referenced from).
3699
3700 \code
3701 if (buf->size() < newSize) {
3702 buf->setSize(newSize);
3703 if (!buf->create()) { error(); }
3704 }
3705 // continue using buf, fill it with new data
3706 \endcode
3707
3708 When working with uniform buffers, it will sometimes be necessary to
3709 combine data for multiple draw calls into a single buffer for efficiency
3710 reasons. Be aware of the aligment requirements: with some graphics APIs
3711 offsets for a uniform buffer must be aligned to 256 bytes. This applies
3712 both to QRhiShaderResourceBinding and to the dynamic offsets passed to
3713 \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()}. Use the
3714 \l{QRhi::ubufAlignment()}{ubufAlignment()} and
3715 \l{QRhi::ubufAligned()}{ubufAligned()} functions to create portable code.
3716 As an example, the following is an outline for issuing multiple (\c N) draw
3717 calls with the same pipeline and geometry, but with a different data in the
3718 uniform buffers exposed at binding point 0. This assumes the buffer is
3719 exposed via
3720 \l{QRhiShaderResourceBinding::uniformBufferWithDynamicOffset()}{uniformBufferWithDynamicOffset()}
3721 which allows passing a QRhiCommandBuffer::DynamicOffset list to
3722 \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()}.
3723
3724 \code
3725 const int N = 2;
3726 const int UB_SIZE = 64 + 4; // assuming a uniform block with { mat4 matrix; float opacity; }
3727 const int ONE_UBUF_SIZE = rhi->ubufAligned(UB_SIZE);
3728 const int TOTAL_UBUF_SIZE = N * ONE_UBUF_SIZE;
3729 QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, TOTAL_UBUF_SIZE);
3730 if (!ubuf->create()) { error(); }
3731 QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
3732 for (int i = 0; i < N; ++i) {
3733 batch->updateDynamicBuffer(ubuf, i * ONE_UBUF_SIZE, 64, matrix.constData());
3734 batch->updateDynamicBuffer(ubuf, i * ONE_UBUF_SIZE + 64, 4, &opacity);
3735 }
3736 // ...
3737 // beginPass(), set pipeline, etc., and then:
3738 for (int i = 0; i < N; ++i) {
3739 QRhiCommandBuffer::DynamicOffset dynOfs[] = { { 0, i * ONE_UBUF_SIZE } };
3740 cb->setShaderResources(srb, 1, dynOfs);
3741 cb->draw(36);
3742 }
3743 \endcode
3744
3745 \sa QRhiResourceUpdateBatch, QRhi, QRhiCommandBuffer
3746 */
3747
3748/*!
3749 \enum QRhiBuffer::Type
3750 Specifies storage type of buffer resource.
3751
3752 \value Immutable Indicates that the data is not expected to change ever
3753 after the initial upload. Under the hood such buffer resources are
3754 typically placed in device local (GPU) memory (on systems where
3755 applicable). Uploading new data is possible, but may be expensive. The
3756 upload typically happens by copying to a separate, host visible staging
3757 buffer from which a GPU buffer-to-buffer copy is issued into the actual
3758 GPU-only buffer.
3759
3760 \value Static Indicates that the data is expected to change only
3761 infrequently. Typically placed in device local (GPU) memory, where
3762 applicable. On backends where host visible staging buffers are used for
3763 uploading, the staging buffers are kept around for this type, unlike with
3764 Immutable, so subsequent uploads do not suffer in performance. Frequent
3765 updates, especially updates in consecutive frames, should be avoided.
3766
3767 \value Dynamic Indicates that the data is expected to change frequently.
3768 Not recommended for large buffers. Typically backed by host visible memory
3769 in 2 copies in order to allow for changing without stalling the graphics
3770 pipeline. The double buffering is managed transparently to the applications
3771 and is not exposed in the API here in any form. This is the recommended,
3772 and, with some backends, the only possible, type for buffers with
3773 UniformBuffer usage.
3774 */
3775
3776/*!
3777 \enum QRhiBuffer::UsageFlag
3778 Flag values to specify how the buffer is going to be used.
3779
3780 \value VertexBuffer Vertex buffer. This allows the QRhiBuffer to be used in
3781 \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()}.
3782
3783 \value IndexBuffer Index buffer. This allows the QRhiBuffer to be used in
3784 \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()}.
3785
3786 \value UniformBuffer Uniform buffer (also called constant buffer). This
3787 allows the QRhiBuffer to be used in combination with
3788 \l{QRhiShaderResourceBinding::UniformBuffer}{UniformBuffer}. When
3789 \l{QRhi::NonDynamicUniformBuffers}{NonDynamicUniformBuffers} is reported as
3790 not supported, this usage can only be combined with the type Dynamic.
3791
3792 \value StorageBuffer Storage buffer. This allows the QRhiBuffer to be used
3793 in combination with \l{QRhiShaderResourceBinding::BufferLoad}{BufferLoad},
3794 \l{QRhiShaderResourceBinding::BufferStore}{BufferStore}, or
3795 \l{QRhiShaderResourceBinding::BufferLoadStore}{BufferLoadStore}. This usage
3796 can only be combined with the types Immutable or Static, and is only
3797 available when the \l{QRhi::Compute}{Compute feature} is reported as
3798 supported.
3799 */
3800
3801/*!
3802 \class QRhiBuffer::NativeBuffer
3803 \inmodule QtGuiPrivate
3804 \inheaderfile rhi/qrhi.h
3805 \brief Contains information about the underlying native resources of a buffer.
3806 */
3807
3808/*!
3809 \variable QRhiBuffer::NativeBuffer::objects
3810 \brief an array with pointers to the native object handles.
3811
3812 With OpenGL, the native handle is a GLuint value, so the elements in the \c
3813 objects array are pointers to a GLuint. With Vulkan, the native handle is a
3814 VkBuffer, so the elements of the array are pointers to a VkBuffer. With
3815 Direct3D 11 and Metal the elements are pointers to a ID3D11Buffer or
3816 MTLBuffer pointer, respectively. With Direct3D 12, the elements are
3817 pointers to a ID3D12Resource.
3818
3819 \note Pay attention to the fact that the elements are always pointers to
3820 the native buffer handle type, even if the native type itself is a pointer.
3821 (so the elements are \c{VkBuffer *} on Vulkan, even though VkBuffer itself
3822 is a pointer on 64-bit architectures).
3823 */
3824
3825/*!
3826 \variable QRhiBuffer::NativeBuffer::slotCount
3827 \brief Specifies the number of valid elements in the objects array.
3828
3829 The value can be 0, 1, 2, or 3 in practice. 0 indicates that the QRhiBuffer
3830 is not backed by any native buffer objects. This can happen with
3831 QRhiBuffers with the usage UniformBuffer when the underlying API does not
3832 support (or the backend chooses not to use) native uniform buffers. 1 is
3833 commonly used for Immutable and Static types (but some backends may
3834 differ). 2 or 3 is typical when the type is Dynamic (but some backends may
3835 differ).
3836
3837 \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight
3838 */
3839
3840/*!
3841 \internal
3842 */
3843QRhiBuffer::QRhiBuffer(QRhiImplementation *rhi, Type type_, UsageFlags usage_, quint32 size_)
3844 : QRhiResource(rhi),
3845 m_type(type_), m_usage(usage_), m_size(size_)
3846{
3847}
3848
3849/*!
3850 \return the resource type.
3851 */
3852QRhiResource::Type QRhiBuffer::resourceType() const
3853{
3854 return Buffer;
3855}
3856
3857/*!
3858 \fn virtual bool QRhiBuffer::create() = 0
3859
3860 Creates the corresponding native graphics resources. If there are already
3861 resources present due to an earlier create() with no corresponding
3862 destroy(), then destroy() is called implicitly first.
3863
3864 \return \c true when successful, \c false when a graphics operation failed.
3865 Regardless of the return value, calling destroy() is always safe.
3866 */
3867
3868/*!
3869 \fn QRhiBuffer::Type QRhiBuffer::type() const
3870 \return the buffer type.
3871 */
3872
3873/*!
3874 \fn void QRhiBuffer::setType(Type t)
3875 Sets the buffer's type to \a t.
3876 */
3877
3878/*!
3879 \fn QRhiBuffer::UsageFlags QRhiBuffer::usage() const
3880 \return the buffer's usage flags.
3881 */
3882
3883/*!
3884 \fn void QRhiBuffer::setUsage(UsageFlags u)
3885 Sets the buffer's usage flags to \a u.
3886 */
3887
3888/*!
3889 \fn quint32 QRhiBuffer::size() const
3890
3891 \return the buffer's size in bytes.
3892
3893 This is always the value that was passed to setSize() or QRhi::newBuffer().
3894 Internally, the native buffers may be bigger if that is required by the
3895 underlying graphics API.
3896 */
3897
3898/*!
3899 \fn void QRhiBuffer::setSize(quint32 sz)
3900
3901 Sets the size of the buffer in bytes. The size is normally specified in
3902 QRhi::newBuffer() so this function is only used when the size has to be
3903 changed. As with other setters, the size only takes effect when calling
3904 create(), and for already created buffers this involves releasing the previous
3905 native resource and creating new ones under the hood.
3906
3907 Backends may choose to allocate buffers bigger than \a sz in order to
3908 fulfill alignment requirements. This is hidden from the applications and
3909 size() will always report the size requested in \a sz.
3910 */
3911
3912/*!
3913 \return the underlying native resources for this buffer. The returned value
3914 will be empty if exposing the underlying native resources is not supported by
3915 the backend.
3916
3917 A QRhiBuffer may be backed by multiple native buffer objects, depending on
3918 the type() and the QRhi backend in use. When this is the case, all of them
3919 are returned in the objects array in the returned struct, with slotCount
3920 specifying the number of native buffer objects. While
3921 \l{QRhi::beginFrame()}{recording a frame}, QRhi::currentFrameSlot() can be
3922 used to determine which of the native buffers QRhi is using for operations
3923 that read or write from this QRhiBuffer within the frame being recorded.
3924
3925 In some cases a QRhiBuffer will not be backed by a native buffer object at
3926 all. In this case slotCount will be set to 0 and no valid native objects
3927 are returned. This is not an error, and is perfectly valid when a given
3928 backend does not use native buffers for QRhiBuffers with certain types or
3929 usages.
3930
3931 \note Be aware that QRhi backends may employ various buffer update
3932 strategies. Unlike textures, where uploading image data always means
3933 recording a buffer-to-image (or similar) copy command on the command
3934 buffer, buffers, in particular Dynamic and UniformBuffer ones, can operate
3935 in many different ways. For example, a QRhiBuffer with usage type
3936 UniformBuffer may not even be backed by a native buffer object at all if
3937 uniform buffers are not used or supported by a given backend and graphics
3938 API. There are also differences to how data is written to the buffer and
3939 the type of backing memory used. For buffers backed by host visible memory,
3940 calling this function guarantees that pending host writes are executed for
3941 all the returned native buffers.
3942
3943 \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight
3944 */
3945QRhiBuffer::NativeBuffer QRhiBuffer::nativeBuffer()
3946{
3947 return { .objects: {}, .slotCount: 0 };
3948}
3949
3950/*!
3951 \return a pointer to a memory block with the host visible buffer data.
3952
3953 This is a shortcut for medium-to-large dynamic uniform buffers that have
3954 their \b entire contents (or at least all regions that are read by the
3955 shaders in the current frame) changed \b{in every frame} and the
3956 QRhiResourceUpdateBatch-based update mechanism is seen too heavy due to the
3957 amount of data copying involved.
3958
3959 The call to this function must be eventually followed by a call to
3960 endFullDynamicUniformBufferUpdateForCurrentFrame(), before recording any
3961 render or compute pass that relies on this buffer.
3962
3963 \warning Updating data via this method is not compatible with
3964 QRhiResourceUpdateBatch-based updates and readbacks. Unexpected behavior
3965 may occur when attempting to combine the two update models for the same
3966 buffer. Similarly, the data updated this direct way may not be visible to
3967 \l{QRhiResourceUpdateBatch::readBackBuffer()}{readBackBuffer operations},
3968 depending on the backend.
3969
3970 \warning When updating buffer data via this method, the update must be done
3971 in every frame, otherwise backends that perform double or triple buffering
3972 of resources may end up in unexpected behavior.
3973
3974 \warning Partial updates are not possible with this approach since some
3975 backends may choose a strategy where the previous contents of the buffer is
3976 lost upon calling this function. Data must be written to all regions that
3977 are read by shaders in the frame currently being prepared.
3978
3979 \warning This function can only be called when recording a frame, so
3980 between QRhi::beginFrame() and QRhi::endFrame().
3981
3982 \warning This function can only be called on Dynamic buffers.
3983 */
3984char *QRhiBuffer::beginFullDynamicBufferUpdateForCurrentFrame()
3985{
3986 return nullptr;
3987}
3988
3989/*!
3990 To be called when the entire contents of the buffer data has been updated
3991 in the memory block returned from
3992 beginFullDynamicBufferUpdateForCurrentFrame().
3993 */
3994void QRhiBuffer::endFullDynamicBufferUpdateForCurrentFrame()
3995{
3996}
3997
3998/*!
3999 \internal
4000 */
4001void QRhiBuffer::fullDynamicBufferUpdateForCurrentFrame(const void *data, quint32 size)
4002{
4003 char *p = beginFullDynamicBufferUpdateForCurrentFrame();
4004 if (p) {
4005 memcpy(dest: p, src: data, n: size > 0 ? size : m_size);
4006 endFullDynamicBufferUpdateForCurrentFrame();
4007 }
4008}
4009
4010/*!
4011 \class QRhiRenderBuffer
4012 \inmodule QtGuiPrivate
4013 \inheaderfile rhi/qrhi.h
4014 \since 6.6
4015 \brief Renderbuffer resource.
4016
4017 Renderbuffers cannot be sampled or read but have some benefits over
4018 textures in some cases:
4019
4020 A \l DepthStencil renderbuffer may be lazily allocated and be backed by
4021 transient memory with some APIs. On some platforms this may mean the
4022 depth/stencil buffer uses no physical backing at all.
4023
4024 \l Color renderbuffers are useful since QRhi::MultisampleRenderBuffer may be
4025 supported even when QRhi::MultisampleTexture is not.
4026
4027 How the renderbuffer is implemented by a backend is not exposed to the
4028 applications. In some cases it may be backed by ordinary textures, while in
4029 others there may be a different kind of native resource used.
4030
4031 Renderbuffers that are used as (and are only used as) depth-stencil buffers
4032 in combination with a QRhiSwapChain's color buffers should have the
4033 UsedWithSwapChainOnly flag set. This serves a double purpose: such buffers,
4034 depending on the backend and the underlying APIs, be more efficient, and
4035 QRhi provides automatic sizing behavior to match the color buffers, which
4036 means calling setPixelSize() and create() are not necessary for such
4037 renderbuffers.
4038
4039 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
4040 for details.
4041 */
4042
4043/*!
4044 \enum QRhiRenderBuffer::Type
4045 Specifies the type of the renderbuffer
4046
4047 \value DepthStencil Combined depth/stencil
4048 \value Color Color
4049 */
4050
4051/*!
4052 \struct QRhiRenderBuffer::NativeRenderBuffer
4053 \inmodule QtGuiPrivate
4054 \inheaderfile rhi/qrhi.h
4055 \brief Wraps a native renderbuffer object.
4056 */
4057
4058/*!
4059 \variable QRhiRenderBuffer::NativeRenderBuffer::object
4060 \brief 64-bit integer containing the native object handle.
4061
4062 Used with QRhiRenderBuffer::createFrom().
4063
4064 With OpenGL the native handle is a GLuint value. \c object is expected to
4065 be a valid OpenGL renderbuffer object ID.
4066 */
4067
4068/*!
4069 \enum QRhiRenderBuffer::Flag
4070 Flag values for flags() and setFlags()
4071
4072 \value UsedWithSwapChainOnly For DepthStencil renderbuffers this indicates
4073 that the renderbuffer is only used in combination with a QRhiSwapChain, and
4074 never in any other way. This provides automatic sizing and resource
4075 rebuilding, so calling setPixelSize() or create() is not needed whenever
4076 this flag is set. This flag value may also trigger backend-specific
4077 behavior, for example with OpenGL, where a separate windowing system
4078 interface API is in use (EGL, GLX, etc.), the flag is especially important
4079 as it avoids creating any actual renderbuffer resource as there is already
4080 a windowing system provided depth/stencil buffer as requested by
4081 QSurfaceFormat.
4082 */
4083
4084/*!
4085 \internal
4086 */
4087QRhiRenderBuffer::QRhiRenderBuffer(QRhiImplementation *rhi, Type type_, const QSize &pixelSize_,
4088 int sampleCount_, Flags flags_,
4089 QRhiTexture::Format backingFormatHint_)
4090 : QRhiResource(rhi),
4091 m_type(type_), m_pixelSize(pixelSize_), m_sampleCount(sampleCount_), m_flags(flags_),
4092 m_backingFormatHint(backingFormatHint_)
4093{
4094}
4095
4096/*!
4097 \return the resource type.
4098 */
4099QRhiResource::Type QRhiRenderBuffer::resourceType() const
4100{
4101 return RenderBuffer;
4102}
4103
4104/*!
4105 \fn virtual bool QRhiRenderBuffer::create() = 0
4106
4107 Creates the corresponding native graphics resources. If there are already
4108 resources present due to an earlier create() with no corresponding
4109 destroy(), then destroy() is called implicitly first.
4110
4111 \return \c true when successful, \c false when a graphics operation failed.
4112 Regardless of the return value, calling destroy() is always safe.
4113 */
4114
4115/*!
4116 Similar to create() except that no new native renderbuffer objects are
4117 created. Instead, the native renderbuffer object specified by \a src is
4118 used.
4119
4120 This allows importing an existing renderbuffer object (which must belong to
4121 the same device or sharing context, depending on the graphics API) from an
4122 external graphics engine.
4123
4124 \note This is currently applicable to OpenGL only. This function exists
4125 solely to allow importing a renderbuffer object that is bound to some
4126 special, external object, such as an EGLImageKHR. Once the application
4127 performed the glEGLImageTargetRenderbufferStorageOES call, the renderbuffer
4128 object can be passed to this function to create a wrapping
4129 QRhiRenderBuffer, which in turn can be passed in as a color attachment to
4130 a QRhiTextureRenderTarget to enable rendering to the EGLImage.
4131
4132 \note pixelSize(), sampleCount(), and flags() must still be set correctly.
4133 Passing incorrect sizes and other values to QRhi::newRenderBuffer() and
4134 then following it with a createFrom() expecting that the native
4135 renderbuffer object alone is sufficient to deduce such values is \b wrong
4136 and will lead to problems.
4137
4138 \note QRhiRenderBuffer does not take ownership of the native object, and
4139 destroy() will not release that object.
4140
4141 \note This function is only implemented when the QRhi::RenderBufferImport
4142 feature is reported as \l{QRhi::isFeatureSupported()}{supported}. Otherwise,
4143 the function does nothing and the return value is \c false.
4144
4145 \return \c true when successful, \c false when not supported.
4146 */
4147bool QRhiRenderBuffer::createFrom(NativeRenderBuffer src)
4148{
4149 Q_UNUSED(src);
4150 return false;
4151}
4152
4153/*!
4154 \fn QRhiRenderBuffer::Type QRhiRenderBuffer::type() const
4155 \return the renderbuffer type.
4156 */
4157
4158/*!
4159 \fn void QRhiRenderBuffer::setType(Type t)
4160 Sets the type to \a t.
4161 */
4162
4163/*!
4164 \fn QSize QRhiRenderBuffer::pixelSize() const
4165 \return the pixel size.
4166 */
4167
4168/*!
4169 \fn void QRhiRenderBuffer::setPixelSize(const QSize &sz)
4170 Sets the size (in pixels) to \a sz.
4171 */
4172
4173/*!
4174 \fn int QRhiRenderBuffer::sampleCount() const
4175 \return the sample count. 1 means no multisample antialiasing.
4176 */
4177
4178/*!
4179 \fn void QRhiRenderBuffer::setSampleCount(int s)
4180 Sets the sample count to \a s.
4181 */
4182
4183/*!
4184 \fn QRhiRenderBuffer::Flags QRhiRenderBuffer::flags() const
4185 \return the flags.
4186 */
4187
4188/*!
4189 \fn void QRhiRenderBuffer::setFlags(Flags f)
4190 Sets the flags to \a f.
4191 */
4192
4193/*!
4194 \fn virtual QRhiTexture::Format QRhiRenderBuffer::backingFormat() const = 0
4195
4196 \internal
4197 */
4198
4199/*!
4200 \class QRhiTexture
4201 \inmodule QtGuiPrivate
4202 \inheaderfile rhi/qrhi.h
4203 \since 6.6
4204 \brief Texture resource.
4205
4206 A QRhiTexture encapsulates a native texture object, such as a \c VkImage or
4207 \c MTLTexture.
4208
4209 A QRhiTexture instance is always created by calling
4210 \l{QRhi::newTexture()}{the QRhi's newTexture() function}. This creates no
4211 native graphics resources. To do that, call create() after setting the
4212 appropriate options, such as the format and size, although in most cases
4213 these are already set based on the arguments passed to
4214 \l{QRhi::newTexture()}{newTexture()}.
4215
4216 Setting the \l{QRhiTexture::Flags}{flags} correctly is essential, otherwise
4217 various errors can occur depending on the underlying QRhi backend and
4218 graphics API. For example, when a texture will be rendered into from a
4219 render pass via QRhiTextureRenderTarget, the texture must be created with
4220 the \l RenderTarget flag set. Similarly, when the texture is going to be
4221 \l{QRhiResourceUpdateBatch::readBackTexture()}{read back}, the \l
4222 UsedAsTransferSource flag must be set upfront. Mipmapped textures must have
4223 the MipMapped flag set. And so on. It is not possible to change the flags
4224 once create() has succeeded. To release the existing and create a new
4225 native texture object with the changed settings, call the setters and call
4226 create() again. This then might be a potentially expensive operation.
4227
4228 \section2 Example usage
4229
4230 To create a 2D texture with a size of 512x512 pixels and set its contents to all green:
4231
4232 \code
4233 QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512));
4234 if (!texture->create()) { error(); }
4235 QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
4236 QImage image(512, 512, QImage::Format_RGBA8888);
4237 image.fill(Qt::green);
4238 batch->uploadTexture(texture, image);
4239 // ...
4240 commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call
4241 \endcode
4242
4243 \section2 Common patterns
4244
4245 A call to create() destroys any existing native resources if create() was
4246 successfully called before. If those native resources are still in use by
4247 an in-flight frame (i.e., there's a chance they are still read by the GPU),
4248 the destroying of those resources is deferred automatically. Thus a very
4249 common and convenient pattern to safely change the size of an already
4250 existing texture is the following. In practice this drops and creates a
4251 whole new native texture resource underneath, so it is not necessarily a
4252 cheap operation, but is more convenient and still faster than the
4253 alternatives, because by not destroying the \c texture object itself, all
4254 references to it stay valid in other data structures (e.g., in any
4255 QShaderResourceBinding the QRhiTexture is referenced from).
4256
4257 \code
4258 // determine newSize, e.g. based on the swapchain's output size or other factors
4259 if (texture->pixelSize() != newSize) {
4260 texture->setPixelSize(newSize);
4261 if (!texture->create()) { error(); }
4262 }
4263 // continue using texture, fill it with new data
4264 \endcode
4265
4266 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
4267 for details.
4268
4269 \sa QRhiResourceUpdateBatch, QRhi, QRhiTextureRenderTarget
4270 */
4271
4272/*!
4273 \enum QRhiTexture::Flag
4274
4275 Flag values to specify how the texture is going to be used. Not honoring
4276 the flags set before create() and attempting to use the texture in ways that
4277 was not declared upfront can lead to unspecified behavior or decreased
4278 performance depending on the backend and the underlying graphics API.
4279
4280 \value RenderTarget The texture going to be used in combination with
4281 QRhiTextureRenderTarget.
4282
4283 \value CubeMap The texture is a cubemap. Such textures have 6 layers, one
4284 for each face in the order of +X, -X, +Y, -Y, +Z, -Z. Cubemap textures
4285 cannot be multisample.
4286
4287 \value MipMapped The texture has mipmaps. The appropriate mip count is
4288 calculated automatically and can also be retrieved via
4289 QRhi::mipLevelsForSize(). The images for the mip levels have to be
4290 provided in the texture uploaded or generated via
4291 QRhiResourceUpdateBatch::generateMips(). Multisample textures cannot have
4292 mipmaps.
4293
4294 \value sRGB Use an sRGB format.
4295
4296 \value UsedAsTransferSource The texture is used as the source of a texture
4297 copy or readback, meaning the texture is given as the source in
4298 QRhiResourceUpdateBatch::copyTexture() or
4299 QRhiResourceUpdateBatch::readBackTexture().
4300
4301 \value UsedWithGenerateMips The texture is going to be used with
4302 QRhiResourceUpdateBatch::generateMips().
4303
4304 \value UsedWithLoadStore The texture is going to be used with image
4305 load/store operations, for example, in a compute shader.
4306
4307 \value UsedAsCompressedAtlas The texture has a compressed format and the
4308 dimensions of subresource uploads may not match the texture size.
4309
4310 \value ExternalOES The texture should use the GL_TEXTURE_EXTERNAL_OES
4311 target with OpenGL. This flag is ignored with other graphics APIs.
4312
4313 \value ThreeDimensional The texture is a 3D texture. Such textures should
4314 be created with the QRhi::newTexture() overload taking a depth in addition
4315 to width and height. A 3D texture can have mipmaps but cannot be
4316 multisample. When rendering into, or uploading data to a 3D texture, the \c
4317 layer specified in the render target's color attachment or the upload
4318 description refers to a single slice in range [0..depth-1]. The underlying
4319 graphics API may not support 3D textures at run time. Support is indicated
4320 by the QRhi::ThreeDimensionalTextures feature.
4321
4322 \value TextureRectangleGL The texture should use the GL_TEXTURE_RECTANGLE
4323 target with OpenGL. This flag is ignored with other graphics APIs. Just
4324 like ExternalOES, this flag is useful when working with platform APIs where
4325 native OpenGL texture objects received from the platform are wrapped in a
4326 QRhiTexture, and the platform can only provide textures for a non-2D
4327 texture target.
4328
4329 \value TextureArray The texture is a texture array, i.e. a single texture
4330 object that is a homogeneous array of 2D textures. Texture arrays are
4331 created with QRhi::newTextureArray(). The underlying graphics API may not
4332 support texture array objects at run time. Support is indicated by the
4333 QRhi::TextureArrays feature. When rendering into, or uploading data to a
4334 texture array, the \c layer specified in the render target's color
4335 attachment or the upload description selects a single element in the array.
4336
4337 \value OneDimensional The texture is a 1D texture. Such textures can be
4338 created by passing a 0 height and depth to QRhi::newTexture(). Note that
4339 there can be limitations on one dimensional textures depending on the
4340 underlying graphics API. For example, rendering to them or using them with
4341 mipmap-based filtering may be unsupported. This is indicated by the
4342 QRhi::OneDimensionalTextures and QRhi::OneDimensionalTextureMipmaps
4343 feature flags.
4344 */
4345
4346/*!
4347 \enum QRhiTexture::Format
4348
4349 Specifies the texture format. See also QRhi::isTextureFormatSupported() and
4350 note that flags() can modify the format when QRhiTexture::sRGB is set.
4351
4352 \value UnknownFormat Not a valid format. This cannot be passed to setFormat().
4353
4354 \value RGBA8 Four component, unsigned normalized 8 bit per component. Always supported.
4355
4356 \value BGRA8 Four component, unsigned normalized 8 bit per component.
4357
4358 \value R8 One component, unsigned normalized 8 bit.
4359
4360 \value RG8 Two components, unsigned normalized 8 bit.
4361
4362 \value R16 One component, unsigned normalized 16 bit.
4363
4364 \value RG16 Two component, unsigned normalized 16 bit.
4365
4366 \value RED_OR_ALPHA8 Either same as R8, or is a similar format with the component swizzled to alpha,
4367 depending on \l{QRhi::RedOrAlpha8IsRed}{RedOrAlpha8IsRed}.
4368
4369 \value RGBA16F Four components, 16-bit float per component.
4370
4371 \value RGBA32F Four components, 32-bit float per component.
4372
4373 \value R16F One component, 16-bit float.
4374
4375 \value R32F One component, 32-bit float.
4376
4377 \value RGB10A2 Four components, unsigned normalized 10 bit R, G, and B,
4378 2-bit alpha. This is a packed format so native endianness applies. Note
4379 that there is no BGR10A2. This is because RGB10A2 maps to
4380 DXGI_FORMAT_R10G10B10A2_UNORM with D3D, MTLPixelFormatRGB10A2Unorm with
4381 Metal, VK_FORMAT_A2B10G10R10_UNORM_PACK32 with Vulkan, and
4382 GL_RGB10_A2/GL_RGB/GL_UNSIGNED_INT_2_10_10_10_REV on OpenGL (ES). This is
4383 the only universally supported RGB30 option. The corresponding QImage
4384 formats are QImage::Format_BGR30 and QImage::Format_A2BGR30_Premultiplied.
4385
4386 \value D16 16-bit depth (normalized unsigned integer)
4387
4388 \value D24 24-bit depth (normalized unsigned integer)
4389
4390 \value D24S8 24-bit depth (normalized unsigned integer), 8 bit stencil
4391
4392 \value D32F 32-bit depth (32-bit float)
4393
4394 \value BC1
4395 \value BC2
4396 \value BC3
4397 \value BC4
4398 \value BC5
4399 \value BC6H
4400 \value BC7
4401
4402 \value ETC2_RGB8
4403 \value ETC2_RGB8A1
4404 \value ETC2_RGBA8
4405
4406 \value ASTC_4x4
4407 \value ASTC_5x4
4408 \value ASTC_5x5
4409 \value ASTC_6x5
4410 \value ASTC_6x6
4411 \value ASTC_8x5
4412 \value ASTC_8x6
4413 \value ASTC_8x8
4414 \value ASTC_10x5
4415 \value ASTC_10x6
4416 \value ASTC_10x8
4417 \value ASTC_10x10
4418 \value ASTC_12x10
4419 \value ASTC_12x12
4420 */
4421
4422/*!
4423 \struct QRhiTexture::NativeTexture
4424 \inmodule QtGuiPrivate
4425 \inheaderfile rhi/qrhi.h
4426 \brief Contains information about the underlying native resources of a texture.
4427 */
4428
4429/*!
4430 \variable QRhiTexture::NativeTexture::object
4431 \brief 64-bit integer containing the native object handle.
4432
4433 With OpenGL, the native handle is a GLuint value, so \c object can then be
4434 cast to a GLuint. With Vulkan, the native handle is a VkImage, so \c object
4435 can be cast to a VkImage. With Direct3D 11 and Metal \c object contains a
4436 ID3D11Texture2D or MTLTexture pointer, respectively. With Direct3D 12
4437 \c object contains a ID3D12Resource pointer.
4438 */
4439
4440/*!
4441 \variable QRhiTexture::NativeTexture::layout
4442 \brief Specifies the current image layout for APIs like Vulkan.
4443
4444 For Vulkan, \c layout contains a \c VkImageLayout value.
4445 */
4446
4447/*!
4448 \internal
4449 */
4450QRhiTexture::QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_, int depth_,
4451 int arraySize_, int sampleCount_, Flags flags_)
4452 : QRhiResource(rhi),
4453 m_format(format_), m_pixelSize(pixelSize_), m_depth(depth_),
4454 m_arraySize(arraySize_), m_sampleCount(sampleCount_), m_flags(flags_)
4455{
4456}
4457
4458/*!
4459 \return the resource type.
4460 */
4461QRhiResource::Type QRhiTexture::resourceType() const
4462{
4463 return Texture;
4464}
4465
4466/*!
4467 \fn virtual bool QRhiTexture::create() = 0
4468
4469 Creates the corresponding native graphics resources. If there are already
4470 resources present due to an earlier create() with no corresponding
4471 destroy(), then destroy() is called implicitly first.
4472
4473 \return \c true when successful, \c false when a graphics operation failed.
4474 Regardless of the return value, calling destroy() is always safe.
4475 */
4476
4477/*!
4478 \return the underlying native resources for this texture. The returned value
4479 will be empty if exposing the underlying native resources is not supported by
4480 the backend.
4481
4482 \sa createFrom()
4483 */
4484QRhiTexture::NativeTexture QRhiTexture::nativeTexture()
4485{
4486 return {};
4487}
4488
4489/*!
4490 Similar to create(), except that no new native textures are created.
4491 Instead, the native texture resources specified by \a src is used.
4492
4493 This allows importing an existing native texture object (which must belong
4494 to the same device or sharing context, depending on the graphics API) from
4495 an external graphics engine.
4496
4497 \return true if the specified existing native texture object has been
4498 successfully wrapped as a non-owning QRhiTexture.
4499
4500 \note format(), pixelSize(), sampleCount(), and flags() must still be set
4501 correctly. Passing incorrect sizes and other values to QRhi::newTexture()
4502 and then following it with a createFrom() expecting that the native texture
4503 object alone is sufficient to deduce such values is \b wrong and will lead
4504 to problems.
4505
4506 \note QRhiTexture does not take ownership of the texture object. destroy()
4507 does not free the object or any associated memory.
4508
4509 The opposite of this operation, exposing a QRhiTexture-created native
4510 texture object to a foreign engine, is possible via nativeTexture().
4511
4512 \note When importing a 3D texture, or a texture array object, or, with
4513 OpenGL ES, an external texture, it is then especially important to set the
4514 corresponding flags (ThreeDimensional, TextureArray, ExternalOES) via
4515 setFlags() before calling this function.
4516*/
4517bool QRhiTexture::createFrom(QRhiTexture::NativeTexture src)
4518{
4519 Q_UNUSED(src);
4520 return false;
4521}
4522
4523/*!
4524 With some graphics APIs, such as Vulkan, integrating custom rendering code
4525 that uses the graphics API directly needs special care when it comes to
4526 image layouts. This function allows communicating the expected \a layout the
4527 image backing the QRhiTexture is in after the native rendering commands.
4528
4529 For example, consider rendering into a QRhiTexture's VkImage directly with
4530 Vulkan in a code block enclosed by QRhiCommandBuffer::beginExternal() and
4531 QRhiCommandBuffer::endExternal(), followed by using the image for texture
4532 sampling in a QRhi-based render pass. To avoid potentially incorrect image
4533 layout transitions, this function can be used to indicate what the image
4534 layout will be once the commands recorded in said code block complete.
4535
4536 Calling this function makes sense only after
4537 QRhiCommandBuffer::endExternal() and before a subsequent
4538 QRhiCommandBuffer::beginPass().
4539
4540 This function has no effect with QRhi backends where the underlying
4541 graphics API does not expose a concept of image layouts.
4542
4543 \note With Vulkan \a layout is a \c VkImageLayout. With Direct 3D 12 \a
4544 layout is a value composed of the bits from \c D3D12_RESOURCE_STATES.
4545 */
4546void QRhiTexture::setNativeLayout(int layout)
4547{
4548 Q_UNUSED(layout);
4549}
4550
4551/*!
4552 \fn QRhiTexture::Format QRhiTexture::format() const
4553 \return the texture format.
4554 */
4555
4556/*!
4557 \fn void QRhiTexture::setFormat(QRhiTexture::Format fmt)
4558
4559 Sets the requested texture format to \a fmt.
4560
4561 \note The value set is only taken into account upon the next call to
4562 create(), i.e. when the underlying graphics resource are (re)created.
4563 Setting a new value is futile otherwise and must be avoided since it can
4564 lead to inconsistent state.
4565 */
4566
4567/*!
4568 \fn QSize QRhiTexture::pixelSize() const
4569 \return the size in pixels.
4570 */
4571
4572/*!
4573 \fn void QRhiTexture::setPixelSize(const QSize &sz)
4574
4575 Sets the texture size, specified in pixels, to \a sz.
4576
4577 \note The value set is only taken into account upon the next call to
4578 create(), i.e. when the underlying graphics resource are (re)created.
4579 Setting a new value is futile otherwise and must be avoided since it can
4580 lead to inconsistent state. The same applies to all other setters as well.
4581 */
4582
4583/*!
4584 \fn int QRhiTexture::depth() const
4585 \return the depth for 3D textures.
4586 */
4587
4588/*!
4589 \fn void QRhiTexture::setDepth(int depth)
4590 Sets the \a depth for a 3D texture.
4591 */
4592
4593/*!
4594 \fn int QRhiTexture::arraySize() const
4595 \return the texture array size.
4596 */
4597
4598/*!
4599 \fn void QRhiTexture::setArraySize(int arraySize)
4600 Sets the texture \a arraySize.
4601 */
4602
4603/*!
4604 \fn int QRhiTexture::arrayRangeStart() const
4605
4606 \return the first array layer when setArrayRange() was called.
4607
4608 \sa setArrayRange()
4609 */
4610
4611/*!
4612 \fn int QRhiTexture::arrayRangeLength() const
4613
4614 \return the exposed array range size when setArrayRange() was called.
4615
4616 \sa setArrayRange()
4617*/
4618
4619/*!
4620 \fn void QRhiTexture::setArrayRange(int startIndex, int count)
4621
4622 Normally all array layers are exposed and it is up to the shader to select
4623 the layer via the third coordinate passed to the \c{texture()} GLSL
4624 function when sampling the \c sampler2DArray. When QRhi::TextureArrayRange
4625 is reported as supported, calling setArrayRange() before create() or
4626 createFrom() requests selecting only the specified range, \a count elements
4627 starting from \a startIndex. The shader logic can then be written with this
4628 in mind.
4629
4630 \sa QRhi::TextureArrayRange
4631 */
4632
4633/*!
4634 \fn Flags QRhiTexture::flags() const
4635 \return the texture flags.
4636 */
4637
4638/*!
4639 \fn void QRhiTexture::setFlags(Flags f)
4640 Sets the texture flags to \a f.
4641 */
4642
4643/*!
4644 \fn int QRhiTexture::sampleCount() const
4645 \return the sample count. 1 means no multisample antialiasing.
4646 */
4647
4648/*!
4649 \fn void QRhiTexture::setSampleCount(int s)
4650 Sets the sample count to \a s.
4651 */
4652
4653/*!
4654 \struct QRhiTexture::ViewFormat
4655 \inmodule QtGuiPrivate
4656 \inheaderfile rhi/qrhi.h
4657 \since 6.8
4658 \brief Specifies the view format for reading or writing from or to the texture.
4659
4660 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
4661 for details.
4662 */
4663
4664/*!
4665 \variable QRhiTexture::ViewFormat::format
4666 */
4667
4668/*!
4669 \variable QRhiTexture::ViewFormat::srgb
4670 */
4671
4672/*!
4673 \fn QRhiTexture::ViewFormat QRhiTexture::readViewFormat() const
4674 \since 6.8
4675 \return the view format used when sampling the texture. When not called, the view
4676 format is assumed to be the same as format().
4677 */
4678
4679/*!
4680 \fn void QRhiTexture::setReadViewFormat(const ViewFormat &fmt)
4681 \since 6.8
4682
4683 Sets the shader resource view format (or the format of the view used for
4684 sampling the texture) to \a fmt. By default the same format (and sRGB-ness)
4685 is used as the texture itself, and in most cases this function does not need
4686 to be called.
4687
4688 This setting is only taken into account when the \l TextureViewFormat
4689 feature is reported as supported.
4690
4691 \note This functionality is provided to allow "casting" between
4692 non-sRGB and sRGB in order to get the shader reads perform, or not perform,
4693 the implicit sRGB conversions. Other types of casting may or may not be
4694 functional.
4695 */
4696
4697/*!
4698 \fn QRhiTexture::ViewFormat QRhiTexture::writeViewFormat() const
4699 \since 6.8
4700 \return the view format used when writing to the texture and when using it
4701 with image load/store. When not called, the view format is assumed to be the
4702 same as format().
4703 */
4704
4705/*!
4706 \fn void QRhiTexture::setWriteViewFormat(const ViewFormat &fmt)
4707 \since 6.8
4708
4709 Sets the render target view format to \a fmt. By default the same format
4710 (and sRGB-ness) is used as the texture itself, and in most cases this
4711 function does not need to be called.
4712
4713 One common use case for providing a write view format is working with
4714 externally provided textures that, outside of our control, use an sRGB
4715 format with 3D APIs such as Vulkan or Direct 3D, but the rendering engine is
4716 already prepared to handle linearization and conversion to sRGB at the end
4717 of its shading pipeline. In this case what is wanted when rendering into
4718 such a texture is a render target view (e.g. VkImageView) that has the same,
4719 but non-sRGB format. (if e.g. from an OpenXR implementation one gets a
4720 VK_FORMAT_R8G8B8A8_SRGB texture, it is likely that rendering into it should
4721 be done using a VK_FORMAT_R8G8B8A8_UNORM view, if that is what the rendering
4722 engine's pipeline requires; in this example one would call this function
4723 with a ViewFormat that has a format of QRhiTexture::RGBA8 and \c srgb set to
4724 \c false).
4725
4726 This setting is only taken into account when the \l TextureViewFormat
4727 feature is reported as supported.
4728
4729 \note This functionality is provided to allow "casting" between
4730 non-sRGB and sRGB in order to get the shader write not perform, or perform,
4731 the implicit sRGB conversions. Other types of casting may or may not be
4732 functional.
4733 */
4734
4735/*!
4736 \class QRhiSampler
4737 \inmodule QtGuiPrivate
4738 \inheaderfile rhi/qrhi.h
4739 \since 6.6
4740 \brief Sampler resource.
4741
4742 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
4743 for details.
4744 */
4745
4746/*!
4747 \enum QRhiSampler::Filter
4748 Specifies the minification, magnification, or mipmap filtering
4749
4750 \value None Applicable only for mipmapMode(), indicates no mipmaps to be used
4751 \value Nearest
4752 \value Linear
4753 */
4754
4755/*!
4756 \enum QRhiSampler::AddressMode
4757 Specifies the addressing mode
4758
4759 \value Repeat
4760 \value ClampToEdge
4761 \value Mirror
4762 */
4763
4764/*!
4765 \enum QRhiSampler::CompareOp
4766 Specifies the texture comparison function.
4767
4768 \value Never (default)
4769 \value Less
4770 \value Equal
4771 \value LessOrEqual
4772 \value Greater
4773 \value NotEqual
4774 \value GreaterOrEqual
4775 \value Always
4776 */
4777
4778/*!
4779 \internal
4780 */
4781QRhiSampler::QRhiSampler(QRhiImplementation *rhi,
4782 Filter magFilter_, Filter minFilter_, Filter mipmapMode_,
4783 AddressMode u_, AddressMode v_, AddressMode w_)
4784 : QRhiResource(rhi),
4785 m_magFilter(magFilter_), m_minFilter(minFilter_), m_mipmapMode(mipmapMode_),
4786 m_addressU(u_), m_addressV(v_), m_addressW(w_),
4787 m_compareOp(QRhiSampler::Never)
4788{
4789}
4790
4791/*!
4792 \return the resource type.
4793 */
4794QRhiResource::Type QRhiSampler::resourceType() const
4795{
4796 return Sampler;
4797}
4798
4799/*!
4800 \fn QRhiSampler::Filter QRhiSampler::magFilter() const
4801 \return the magnification filter mode.
4802 */
4803
4804/*!
4805 \fn void QRhiSampler::setMagFilter(Filter f)
4806 Sets the magnification filter mode to \a f.
4807 */
4808
4809/*!
4810 \fn QRhiSampler::Filter QRhiSampler::minFilter() const
4811 \return the minification filter mode.
4812 */
4813
4814/*!
4815 \fn void QRhiSampler::setMinFilter(Filter f)
4816 Sets the minification filter mode to \a f.
4817 */
4818
4819/*!
4820 \fn QRhiSampler::Filter QRhiSampler::mipmapMode() const
4821 \return the mipmap filter mode.
4822 */
4823
4824/*!
4825 \fn void QRhiSampler::setMipmapMode(Filter f)
4826
4827 Sets the mipmap filter mode to \a f.
4828
4829 Leave this set to None when the texture has no mip levels, or when the mip
4830 levels are not to be taken into account.
4831 */
4832
4833/*!
4834 \fn QRhiSampler::AddressMode QRhiSampler::addressU() const
4835 \return the horizontal wrap mode.
4836 */
4837
4838/*!
4839 \fn void QRhiSampler::setAddressU(AddressMode mode)
4840 Sets the horizontal wrap \a mode.
4841 */
4842
4843/*!
4844 \fn QRhiSampler::AddressMode QRhiSampler::addressV() const
4845 \return the vertical wrap mode.
4846 */
4847
4848/*!
4849 \fn void QRhiSampler::setAddressV(AddressMode mode)
4850 Sets the vertical wrap \a mode.
4851 */
4852
4853/*!
4854 \fn QRhiSampler::AddressMode QRhiSampler::addressW() const
4855 \return the depth wrap mode.
4856 */
4857
4858/*!
4859 \fn void QRhiSampler::setAddressW(AddressMode mode)
4860 Sets the depth wrap \a mode.
4861 */
4862
4863/*!
4864 \fn QRhiSampler::CompareOp QRhiSampler::textureCompareOp() const
4865 \return the texture comparison function.
4866 */
4867
4868/*!
4869 \fn void QRhiSampler::setTextureCompareOp(CompareOp op)
4870 Sets the texture comparison function \a op.
4871 */
4872
4873/*!
4874 \class QRhiRenderPassDescriptor
4875 \inmodule QtGuiPrivate
4876 \inheaderfile rhi/qrhi.h
4877 \since 6.6
4878 \brief Render pass resource.
4879
4880 A render pass, if such a concept exists in the underlying graphics API, is
4881 a collection of attachments (color, depth, stencil) and describes how those
4882 attachments are used.
4883
4884 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
4885 for details.
4886 */
4887
4888/*!
4889 \internal
4890 */
4891QRhiRenderPassDescriptor::QRhiRenderPassDescriptor(QRhiImplementation *rhi)
4892 : QRhiResource(rhi)
4893{
4894}
4895
4896/*!
4897 \return the resource type.
4898 */
4899QRhiResource::Type QRhiRenderPassDescriptor::resourceType() const
4900{
4901 return RenderPassDescriptor;
4902}
4903
4904/*!
4905 \fn virtual bool QRhiRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const = 0
4906
4907 \return true if the \a other QRhiRenderPassDescriptor is compatible with
4908 this one, meaning \c this and \a other can be used interchangebly in
4909 QRhiGraphicsPipeline::setRenderPassDescriptor().
4910
4911 The concept of the compatibility of renderpass descriptors is similar to
4912 the \l{QRhiShaderResourceBindings::isLayoutCompatible}{layout
4913 compatibility} of QRhiShaderResourceBindings instances. They allow better
4914 reuse of QRhiGraphicsPipeline instances: for example, a
4915 QRhiGraphicsPipeline instance cache is expected to use these functions to
4916 look for a matching pipeline, instead of just comparing pointers, thus
4917 allowing a different QRhiRenderPassDescriptor and
4918 QRhiShaderResourceBindings to be used in combination with the pipeline, as
4919 long as they are compatible.
4920
4921 The exact details of compatibility depend on the underlying graphics API.
4922 Two renderpass descriptors
4923 \l{QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor()}{created}
4924 from the same QRhiTextureRenderTarget are always compatible.
4925
4926 Similarly to QRhiShaderResourceBindings, compatibility can also be tested
4927 without having two existing objects available. Extracting the opaque blob by
4928 calling serializedFormat() allows testing for compatibility by comparing the
4929 returned vector to another QRhiRenderPassDescriptor's
4930 serializedFormat(). This has benefits in certain situations, because it
4931 allows testing the compatibility of a QRhiRenderPassDescriptor with a
4932 QRhiGraphicsPipeline even when the QRhiRenderPassDescriptor the pipeline was
4933 originally built was is no longer available (but the data returned from its
4934 serializedFormat() still is).
4935
4936 \sa newCompatibleRenderPassDescriptor(), serializedFormat()
4937 */
4938
4939/*!
4940 \fn virtual QRhiRenderPassDescriptor *QRhiRenderPassDescriptor::newCompatibleRenderPassDescriptor() const = 0
4941
4942 \return a new QRhiRenderPassDescriptor that is
4943 \l{isCompatible()}{compatible} with this one.
4944
4945 This function allows cloning a QRhiRenderPassDescriptor. The returned
4946 object is ready to be used, and the ownership is transferred to the caller.
4947 Cloning a QRhiRenderPassDescriptor object can become useful in situations
4948 where the object is stored in data structures related to graphics pipelines
4949 (in order to allow creating new pipelines which in turn requires a
4950 renderpass descriptor object), and the lifetime of the renderpass
4951 descriptor created from a render target may be shorter than the pipelines.
4952 (for example, because the engine manages and destroys renderpasses together
4953 with the textures and render targets it was created from) In such a
4954 situation, it can be beneficial to store a cloned version in the data
4955 structures, and thus transferring ownership as well.
4956
4957 \sa isCompatible()
4958 */
4959
4960/*!
4961 \fn virtual QVector<quint32> QRhiRenderPassDescriptor::serializedFormat() const = 0
4962
4963 \return a vector of integers containing an opaque blob describing the data
4964 relevant for \l{isCompatible()}{compatibility}.
4965
4966 Given two QRhiRenderPassDescriptor objects \c rp1 and \c rp2, if the data
4967 returned from this function is identical, then \c{rp1->isCompatible(rp2)},
4968 and vice versa hold true as well.
4969
4970 \note The returned data is meant to be used for storing in memory and
4971 comparisons during the lifetime of the QRhi the object belongs to. It is not
4972 meant for storing on disk, reusing between processes, or using with multiple
4973 QRhi instances with potentially different backends.
4974
4975 \sa isCompatible()
4976 */
4977
4978/*!
4979 \return a pointer to a backend-specific QRhiNativeHandles subclass, such as
4980 QRhiVulkanRenderPassNativeHandles. The returned value is \nullptr when exposing
4981 the underlying native resources is not supported by the backend.
4982
4983 \sa QRhiVulkanRenderPassNativeHandles
4984 */
4985const QRhiNativeHandles *QRhiRenderPassDescriptor::nativeHandles()
4986{
4987 return nullptr;
4988}
4989
4990/*!
4991 \class QRhiRenderTarget
4992 \inmodule QtGuiPrivate
4993 \inheaderfile rhi/qrhi.h
4994 \since 6.6
4995 \brief Represents an onscreen (swapchain) or offscreen (texture) render target.
4996
4997 Applications do not create an instance of this class directly. Rather, it
4998 is the subclass QRhiTextureRenderTarget that is instantiable by clients of
4999 the API via \l{QRhi::newTextureRenderTarget()}{newTextureRenderTarget()}.
5000 The other subclass is QRhiSwapChainRenderTarget, which is the type
5001 QRhiSwapChain returns when calling
5002 \l{QRhiSwapChain::currentFrameRenderTarget()}{currentFrameRenderTarget()}.
5003
5004 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
5005 for details.
5006
5007 \sa QRhiSwapChainRenderTarget, QRhiTextureRenderTarget
5008 */
5009
5010/*!
5011 \internal
5012 */
5013QRhiRenderTarget::QRhiRenderTarget(QRhiImplementation *rhi)
5014 : QRhiResource(rhi)
5015{
5016}
5017
5018/*!
5019 \fn virtual QSize QRhiRenderTarget::pixelSize() const = 0
5020
5021 \return the size in pixels.
5022
5023 Valid only after create() has been called successfully. Until then the
5024 result is a default-constructed QSize.
5025
5026 With QRhiTextureRenderTarget the returned size is the size of the
5027 associated attachments at the time of create(), in practice the size of the
5028 first color attachment, or the depth/stencil buffer if there are no color
5029 attachments. If the associated textures or renderbuffers are resized and
5030 rebuilt afterwards, then pixelSize() performs an implicit call to create()
5031 in order to rebuild the underlying data structures. This implicit check is
5032 similar to what QRhiCommandBuffer::beginPass() does, and ensures that the
5033 returned size is always up-to-date.
5034 */
5035
5036/*!
5037 \fn virtual float QRhiRenderTarget::devicePixelRatio() const = 0
5038
5039 \return the device pixel ratio. For QRhiTextureRenderTarget this is always
5040 1. For targets retrieved from a QRhiSwapChain the value reflects the
5041 \l{QWindow::devicePixelRatio()}{device pixel ratio} of the targeted
5042 QWindow.
5043 */
5044
5045/*!
5046 \fn virtual int QRhiRenderTarget::sampleCount() const = 0
5047
5048 \return the sample count or 1 if multisample antialiasing is not relevant for
5049 this render target.
5050 */
5051
5052/*!
5053 \fn QRhiRenderPassDescriptor *QRhiRenderTarget::renderPassDescriptor() const
5054
5055 \return the associated QRhiRenderPassDescriptor.
5056 */
5057
5058/*!
5059 \fn void QRhiRenderTarget::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
5060
5061 Sets the QRhiRenderPassDescriptor \a desc for use with this render target.
5062 */
5063
5064/*!
5065 \internal
5066 */
5067QRhiSwapChainRenderTarget::QRhiSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain_)
5068 : QRhiRenderTarget(rhi),
5069 m_swapchain(swapchain_)
5070{
5071}
5072
5073/*!
5074 \class QRhiSwapChainRenderTarget
5075 \inmodule QtGuiPrivate
5076 \inheaderfile rhi/qrhi.h
5077 \since 6.6
5078 \brief Swapchain render target resource.
5079
5080 When targeting the color buffers of a swapchain, active render target is a
5081 QRhiSwapChainRenderTarget. This is what
5082 QRhiSwapChain::currentFrameRenderTarget() returns.
5083
5084 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
5085 for details.
5086
5087 \sa QRhiSwapChain
5088 */
5089
5090/*!
5091 \return the resource type.
5092 */
5093QRhiResource::Type QRhiSwapChainRenderTarget::resourceType() const
5094{
5095 return SwapChainRenderTarget;
5096}
5097
5098/*!
5099 \fn QRhiSwapChain *QRhiSwapChainRenderTarget::swapChain() const
5100
5101 \return the swapchain object.
5102 */
5103
5104/*!
5105 \class QRhiTextureRenderTarget
5106 \inmodule QtGuiPrivate
5107 \inheaderfile rhi/qrhi.h
5108 \since 6.6
5109 \brief Texture render target resource.
5110
5111 A texture render target allows rendering into one or more textures,
5112 optionally with a depth texture or depth/stencil renderbuffer.
5113
5114 For multisample rendering the common approach is to use a renderbuffer as
5115 the color attachment and set the non-multisample destination texture as the
5116 \c{resolve texture}. For more information, read the detailed description of
5117 the \l QRhiColorAttachment class.
5118
5119 \note Textures used in combination with QRhiTextureRenderTarget must be
5120 created with the QRhiTexture::RenderTarget flag.
5121
5122 The simplest example of creating a render target with a texture as its
5123 single color attachment:
5124
5125 \code
5126 QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, size, 1, QRhiTexture::RenderTarget);
5127 texture->create();
5128 QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ texture });
5129 rp = rt->newCompatibleRenderPassDescriptor();
5130 rt->setRenderPassDescriptor(rp);
5131 rt->create();
5132 // rt can now be used with beginPass()
5133 \endcode
5134
5135 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
5136 for details.
5137 */
5138
5139/*!
5140 \enum QRhiTextureRenderTarget::Flag
5141
5142 Flag values describing the load/store behavior for the render target. The
5143 load/store behavior may be baked into native resources under the hood,
5144 depending on the backend, and therefore it needs to be known upfront and
5145 cannot be changed without rebuilding (and so releasing and creating new
5146 native resources).
5147
5148 \value PreserveColorContents Indicates that the contents of the color
5149 attachments is to be loaded when starting a render pass, instead of
5150 clearing. This is potentially more expensive, especially on mobile (tiled)
5151 GPUs, but allows preserving the existing contents between passes. When doing
5152 multisample rendering with a resolve texture set, setting this flag also
5153 requests the multisample color data to be stored (written out) to the
5154 multisample texture or render buffer. (for non-multisample rendering the
5155 color data is always stored, but for MSAA storing the multisample data
5156 decreases efficiency for certain GPU architectures, hence defaulting to not
5157 writing it out) Note however that this is non-portable: in some cases there
5158 is no intermediate multisample texture on the graphics API level, e.g. when
5159 using OpenGL ES's \c{GL_EXT_multisampled_render_to_texture} as it is all
5160 implicit, handled by the OpenGL ES implementation. In that case,
5161 PreserveColorContents will likely have no effect. Therefore, avoid relying
5162 on this flag when using multisample rendering and the color attachment is
5163 using a multisample QRhiTexture (not QRhiRenderBuffer).
5164
5165 \value PreserveDepthStencilContents Indicates that the contents of the
5166 depth texture is to be loaded when starting a render pass, instead
5167 clearing. Only applicable when a texture is used as the depth buffer
5168 (QRhiTextureRenderTargetDescription::depthTexture() is set) because
5169 depth/stencil renderbuffers may not have any physical backing and data may
5170 not be written out in the first place.
5171
5172 \value DoNotStoreDepthStencilContents Indicates that the contents of the
5173 depth texture does not need to be written out. Relevant only when a
5174 QRhiTexture, not QRhiRenderBuffer, is used as the depth-stencil buffer,
5175 because for QRhiRenderBuffer this is implicit. When a depthResolveTexture is
5176 set, the flag is not relevant, because the behavior is then as if the flag
5177 was set. This enum value is introduced in Qt 6.8.
5178 */
5179
5180/*!
5181 \internal
5182 */
5183QRhiTextureRenderTarget::QRhiTextureRenderTarget(QRhiImplementation *rhi,
5184 const QRhiTextureRenderTargetDescription &desc_,
5185 Flags flags_)
5186 : QRhiRenderTarget(rhi),
5187 m_desc(desc_),
5188 m_flags(flags_)
5189{
5190}
5191
5192/*!
5193 \return the resource type.
5194 */
5195QRhiResource::Type QRhiTextureRenderTarget::resourceType() const
5196{
5197 return TextureRenderTarget;
5198}
5199
5200/*!
5201 \fn virtual QRhiRenderPassDescriptor *QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor() = 0
5202
5203 \return a new QRhiRenderPassDescriptor that is compatible with this render
5204 target.
5205
5206 The returned value is used in two ways: it can be passed to
5207 setRenderPassDescriptor() and
5208 QRhiGraphicsPipeline::setRenderPassDescriptor(). A render pass descriptor
5209 describes the attachments (color, depth/stencil) and the load/store
5210 behavior that can be affected by flags(). A QRhiGraphicsPipeline can only
5211 be used in combination with a render target that has a
5212 \l{QRhiRenderPassDescriptor::isCompatible()}{compatible}
5213 QRhiRenderPassDescriptor set.
5214
5215 Two QRhiTextureRenderTarget instances can share the same render pass
5216 descriptor as long as they have the same number and type of attachments.
5217 The associated QRhiTexture or QRhiRenderBuffer instances are not part of
5218 the render pass descriptor so those can differ in the two
5219 QRhiTextureRenderTarget instances.
5220
5221 \note resources, such as QRhiTexture instances, referenced in description()
5222 must already have create() called on them.
5223
5224 \sa create()
5225 */
5226
5227/*!
5228 \fn virtual bool QRhiTextureRenderTarget::create() = 0
5229
5230 Creates the corresponding native graphics resources. If there are already
5231 resources present due to an earlier create() with no corresponding
5232 destroy(), then destroy() is called implicitly first.
5233
5234 \note renderPassDescriptor() must be set before calling create(). To obtain
5235 a QRhiRenderPassDescriptor compatible with the render target, call
5236 newCompatibleRenderPassDescriptor() before create() but after setting all
5237 other parameters, such as description() and flags(). To save resources,
5238 reuse the same QRhiRenderPassDescriptor with multiple
5239 QRhiTextureRenderTarget instances, whenever possible. Sharing the same
5240 render pass descriptor is only possible when the render targets have the
5241 same number and type of attachments (the actual textures can differ) and
5242 the same flags.
5243
5244 \note resources, such as QRhiTexture instances, referenced in description()
5245 must already have create() called on them.
5246
5247 \return \c true when successful, \c false when a graphics operation failed.
5248 Regardless of the return value, calling destroy() is always safe.
5249 */
5250
5251/*!
5252 \fn QRhiTextureRenderTargetDescription QRhiTextureRenderTarget::description() const
5253 \return the render target description.
5254 */
5255
5256/*!
5257 \fn void QRhiTextureRenderTarget::setDescription(const QRhiTextureRenderTargetDescription &desc)
5258 Sets the render target description \a desc.
5259 */
5260
5261/*!
5262 \fn QRhiTextureRenderTarget::Flags QRhiTextureRenderTarget::flags() const
5263 \return the currently set flags.
5264 */
5265
5266/*!
5267 \fn void QRhiTextureRenderTarget::setFlags(Flags f)
5268 Sets the flags to \a f.
5269 */
5270
5271/*!
5272 \class QRhiShaderResourceBindings
5273 \inmodule QtGuiPrivate
5274 \inheaderfile rhi/qrhi.h
5275 \since 6.6
5276 \brief Encapsulates resources for making buffer, texture, sampler resources visible to shaders.
5277
5278 A QRhiShaderResourceBindings is a collection of QRhiShaderResourceBinding
5279 objects, each of which describe a single binding.
5280
5281 Take a fragment shader with the following interface:
5282
5283 \badcode
5284 layout(std140, binding = 0) uniform buf {
5285 mat4 mvp;
5286 int flip;
5287 } ubuf;
5288
5289 layout(binding = 1) uniform sampler2D tex;
5290 \endcode
5291
5292 To make resources visible to the shader, the following
5293 QRhiShaderResourceBindings could be created and then passed to
5294 QRhiGraphicsPipeline::setShaderResourceBindings():
5295
5296 \code
5297 QRhiShaderResourceBindings *srb = rhi->newShaderResourceBindings();
5298 srb->setBindings({
5299 QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, ubuf),
5300 QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, sampler)
5301 });
5302 srb->create();
5303 // ...
5304 QRhiGraphicsPipeline *ps = rhi->newGraphicsPipeline();
5305 // ...
5306 ps->setShaderResourceBindings(srb);
5307 ps->create();
5308 // ...
5309 cb->setGraphicsPipeline(ps);
5310 cb->setShaderResources(); // binds srb
5311 \endcode
5312
5313 This assumes that \c ubuf is a QRhiBuffer, \c texture is a QRhiTexture,
5314 while \a sampler is a QRhiSampler. The example also assumes that the
5315 uniform block is present in the vertex shader as well so the same buffer is
5316 made visible to the vertex stage too.
5317
5318 \section3 Advanced usage
5319
5320 Building on the above example, let's assume that a pass now needs to use
5321 the exact same pipeline and shaders with a different texture. Creating a
5322 whole separate QRhiGraphicsPipeline just for this would be an overkill.
5323 This is why QRhiCommandBuffer::setShaderResources() allows specifying a \a
5324 srb argument. As long as the layouts (so the number of bindings and the
5325 binding points) match between two QRhiShaderResourceBindings, they can both
5326 be used with the same pipeline, assuming the pipeline was created with one of
5327 them in the first place. See isLayoutCompatible() for more details.
5328
5329 \code
5330 QRhiShaderResourceBindings *srb2 = rhi->newShaderResourceBindings();
5331 // ...
5332 cb->setGraphicsPipeline(ps);
5333 cb->setShaderResources(srb2); // binds srb2
5334 \endcode
5335
5336 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
5337 for details.
5338 */
5339
5340/*!
5341 \typedef QRhiShaderResourceBindingSet
5342 \relates QRhi
5343 \since 6.7
5344
5345 Synonym for QRhiShaderResourceBindings.
5346*/
5347
5348/*!
5349 \internal
5350 */
5351QRhiShaderResourceBindings::QRhiShaderResourceBindings(QRhiImplementation *rhi)
5352 : QRhiResource(rhi)
5353{
5354 m_layoutDesc.reserve(asize: BINDING_PREALLOC * QRhiShaderResourceBinding::LAYOUT_DESC_ENTRIES_PER_BINDING);
5355}
5356
5357/*!
5358 \return the resource type.
5359 */
5360QRhiResource::Type QRhiShaderResourceBindings::resourceType() const
5361{
5362 return ShaderResourceBindings;
5363}
5364
5365/*!
5366 \return \c true if the layout is compatible with \a other. The layout does
5367 not include the actual resource (such as, buffer or texture) and related
5368 parameters (such as, offset or size). It does include the binding point,
5369 pipeline stage, and resource type, however. The number and order of the
5370 bindings must also match in order to be compatible.
5371
5372 When there is a QRhiGraphicsPipeline created with this
5373 QRhiShaderResourceBindings, and the function returns \c true, \a other can
5374 then safely be passed to QRhiCommandBuffer::setShaderResources(), and so
5375 be used with the pipeline in place of this QRhiShaderResourceBindings.
5376
5377 \note This function must only be called after a successful create(), because
5378 it relies on data generated during the baking of the underlying data
5379 structures. This way the function can implement a comparison approach that
5380 is more efficient than iterating through two binding lists and calling
5381 QRhiShaderResourceBinding::isLayoutCompatible() on each pair. This becomes
5382 relevant especially when this function is called at a high frequency.
5383
5384 \sa serializedLayoutDescription()
5385 */
5386bool QRhiShaderResourceBindings::isLayoutCompatible(const QRhiShaderResourceBindings *other) const
5387{
5388 if (other == this)
5389 return true;
5390
5391 if (!other)
5392 return false;
5393
5394 // This can become a hot code path. Therefore we do not iterate and call
5395 // isLayoutCompatible() on m_bindings, but rather check a pre-calculated
5396 // hash code and then, if the hash matched, do a uint array comparison
5397 // (that's still more cache friendly).
5398
5399 return m_layoutDescHash == other->m_layoutDescHash
5400 && m_layoutDesc == other->m_layoutDesc;
5401}
5402
5403/*!
5404 \fn QVector<quint32> QRhiShaderResourceBindings::serializedLayoutDescription() const
5405
5406 \return a vector of integers containing an opaque blob describing the layout
5407 of the binding list, i.e. the data relevant for
5408 \l{isLayoutCompatible()}{layout compatibility tests}.
5409
5410 Given two objects \c srb1 and \c srb2, if the data returned from this
5411 function is identical, then \c{srb1->isLayoutCompatible(srb2)}, and vice
5412 versa hold true as well.
5413
5414 \note The returned data is meant to be used for storing in memory and
5415 comparisons during the lifetime of the QRhi the object belongs to. It is not
5416 meant for storing on disk, reusing between processes, or using with multiple
5417 QRhi instances with potentially different backends.
5418
5419 \sa isLayoutCompatible()
5420 */
5421
5422void QRhiImplementation::updateLayoutDesc(QRhiShaderResourceBindings *srb)
5423{
5424 srb->m_layoutDescHash = 0;
5425 srb->m_layoutDesc.clear();
5426 auto layoutDescAppender = std::back_inserter(x&: srb->m_layoutDesc);
5427 for (const QRhiShaderResourceBinding &b : std::as_const(t&: srb->m_bindings)) {
5428 const QRhiShaderResourceBinding::Data *d = &b.d;
5429 srb->m_layoutDescHash ^= uint(d->binding) ^ uint(d->stage) ^ uint(d->type)
5430 ^ uint(d->arraySize());
5431 layoutDescAppender = d->serialize(dst: layoutDescAppender);
5432 }
5433}
5434
5435/*!
5436 \fn void QRhiShaderResourceBindings::setBindings(std::initializer_list<QRhiShaderResourceBinding> list)
5437 Sets the \a list of bindings.
5438 */
5439
5440/*!
5441 \fn template<typename InputIterator> void QRhiShaderResourceBindings::setBindings(InputIterator first, InputIterator last)
5442 Sets the list of bindings from the iterators \a first and \a last.
5443 */
5444
5445/*!
5446 \fn const QRhiShaderResourceBinding *QRhiShaderResourceBindings::cbeginBindings() const
5447 \return a const iterator pointing to the first item in the binding list.
5448 */
5449
5450/*!
5451 \fn const QRhiShaderResourceBinding *QRhiShaderResourceBindings::cendBindings() const
5452 \return a const iterator pointing just after the last item in the binding list.
5453 */
5454
5455/*!
5456 \fn const QRhiShaderResourceBinding *QRhiShaderResourceBindings::bindingAt(qsizetype index) const
5457 \return the binding at the specified \a index.
5458 */
5459
5460/*!
5461 \fn qsizetype QRhiShaderResourceBindings::bindingCount() const
5462 \return the number of bindings.
5463 */
5464
5465/*!
5466 \class QRhiShaderResourceBinding
5467 \inmodule QtGuiPrivate
5468 \inheaderfile rhi/qrhi.h
5469 \since 6.6
5470 \brief Describes the shader resource for a single binding point.
5471
5472 A QRhiShaderResourceBinding cannot be constructed directly. Instead, use the
5473 static functions such as uniformBuffer() or sampledTexture() to get an
5474 instance.
5475
5476 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
5477 for details.
5478 */
5479
5480/*!
5481 \enum QRhiShaderResourceBinding::Type
5482 Specifies type of the shader resource bound to a binding point
5483
5484 \value UniformBuffer Uniform buffer
5485
5486 \value SampledTexture Combined image sampler (a texture and sampler pair).
5487 Even when the shading language associated with the underlying 3D API has no
5488 support for this concept (e.g. D3D and HLSL), this is still supported
5489 because the shader translation layer takes care of the appropriate
5490 translation and remapping of binding points or shader registers.
5491
5492 \value Texture Texture (separate)
5493
5494 \value Sampler Sampler (separate)
5495
5496 \value ImageLoad Image load (with GLSL this maps to doing imageLoad() on a
5497 single level - and either one or all layers - of a texture exposed to the
5498 shader as an image object)
5499
5500 \value ImageStore Image store (with GLSL this maps to doing imageStore() or
5501 imageAtomic*() on a single level - and either one or all layers - of a
5502 texture exposed to the shader as an image object)
5503
5504 \value ImageLoadStore Image load and store
5505
5506 \value BufferLoad Storage buffer store (with GLSL this maps to reading from
5507 a shader storage buffer)
5508
5509 \value BufferStore Storage buffer store (with GLSL this maps to writing to
5510 a shader storage buffer)
5511
5512 \value BufferLoadStore Storage buffer load and store
5513 */
5514
5515/*!
5516 \enum QRhiShaderResourceBinding::StageFlag
5517 Flag values to indicate which stages the shader resource is visible in
5518
5519 \value VertexStage Vertex stage
5520 \value TessellationControlStage Tessellation control (hull shader) stage
5521 \value TessellationEvaluationStage Tessellation evaluation (domain shader) stage
5522 \value FragmentStage Fragment (pixel shader) stage
5523 \value ComputeStage Compute stage
5524 \value GeometryStage Geometry stage
5525 */
5526
5527/*!
5528 \return \c true if the layout is compatible with \a other. The layout does not
5529 include the actual resource (such as, buffer or texture) and related
5530 parameters (such as, offset or size).
5531
5532 For example, \c a and \c b below are not equal, but are compatible layout-wise:
5533
5534 \code
5535 auto a = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, buffer);
5536 auto b = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, someOtherBuffer, 256);
5537 \endcode
5538 */
5539bool QRhiShaderResourceBinding::isLayoutCompatible(const QRhiShaderResourceBinding &other) const
5540{
5541 // everything that goes into a VkDescriptorSetLayoutBinding must match
5542 return d.binding == other.d.binding
5543 && d.stage == other.d.stage
5544 && d.type == other.d.type
5545 && d.arraySize() == other.d.arraySize();
5546}
5547
5548/*!
5549 \return a shader resource binding for the given binding number, pipeline
5550 stages, and buffer specified by \a binding, \a stage, and \a buf.
5551
5552 \note When \a buf is not null, it must have been created with
5553 QRhiBuffer::UniformBuffer.
5554
5555 \note \a buf can be null. It is valid to create a
5556 QRhiShaderResourceBindings with unspecified resources, but such an object
5557 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
5558 suitable for creating pipelines. Such a pipeline must then always be used
5559 together with another, layout compatible QRhiShaderResourceBindings with
5560 resources present passed to QRhiCommandBuffer::setShaderResources().
5561
5562 \note If the size of \a buf exceeds the limit reported for
5563 QRhi::MaxUniformBufferRange, unexpected errors may occur.
5564 */
5565QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
5566 int binding, StageFlags stage, QRhiBuffer *buf)
5567{
5568 QRhiShaderResourceBinding b;
5569 b.d.binding = binding;
5570 b.d.stage = stage;
5571 b.d.type = UniformBuffer;
5572 b.d.u.ubuf.buf = buf;
5573 b.d.u.ubuf.offset = 0;
5574 b.d.u.ubuf.maybeSize = 0; // entire buffer
5575 b.d.u.ubuf.hasDynamicOffset = false;
5576 return b;
5577}
5578
5579/*!
5580 \return a shader resource binding for the given binding number, pipeline
5581 stages, and buffer specified by \a binding, \a stage, and \a buf. This
5582 overload binds a region only, as specified by \a offset and \a size.
5583
5584 \note It is up to the user to ensure the offset is aligned to
5585 QRhi::ubufAlignment().
5586
5587 \note \a size must be greater than 0.
5588
5589 \note When \a buf is not null, it must have been created with
5590 QRhiBuffer::UniformBuffer.
5591
5592 \note \a buf can be null. It is valid to create a
5593 QRhiShaderResourceBindings with unspecified resources, but such an object
5594 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
5595 suitable for creating pipelines. Such a pipeline must then always be used
5596 together with another, layout compatible QRhiShaderResourceBindings with
5597 resources present passed to QRhiCommandBuffer::setShaderResources().
5598
5599 \note If \a size exceeds the limit reported for QRhi::MaxUniformBufferRange,
5600 unexpected errors may occur.
5601 */
5602QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
5603 int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size)
5604{
5605 Q_ASSERT(size > 0);
5606 QRhiShaderResourceBinding b;
5607 b.d.binding = binding;
5608 b.d.stage = stage;
5609 b.d.type = UniformBuffer;
5610 b.d.u.ubuf.buf = buf;
5611 b.d.u.ubuf.offset = offset;
5612 b.d.u.ubuf.maybeSize = size;
5613 b.d.u.ubuf.hasDynamicOffset = false;
5614 return b;
5615}
5616
5617/*!
5618 \return a shader resource binding for the given binding number, pipeline
5619 stages, and buffer specified by \a binding, \a stage, and \a buf. The
5620 uniform buffer is assumed to have dynamic offset. The dynamic offset can be
5621 specified in QRhiCommandBuffer::setShaderResources(), thus allowing using
5622 varying offset values without creating new bindings for the buffer. The
5623 size of the bound region is specified by \a size. Like with non-dynamic
5624 offsets, \c{offset + size} cannot exceed the size of \a buf.
5625
5626 \note When \a buf is not null, it must have been created with
5627 QRhiBuffer::UniformBuffer.
5628
5629 \note \a buf can be null. It is valid to create a
5630 QRhiShaderResourceBindings with unspecified resources, but such an object
5631 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
5632 suitable for creating pipelines. Such a pipeline must then always be used
5633 together with another, layout compatible QRhiShaderResourceBindings with
5634 resources present passed to QRhiCommandBuffer::setShaderResources().
5635
5636 \note If \a size exceeds the limit reported for QRhi::MaxUniformBufferRange,
5637 unexpected errors may occur.
5638 */
5639QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(
5640 int binding, StageFlags stage, QRhiBuffer *buf, quint32 size)
5641{
5642 Q_ASSERT(size > 0);
5643 QRhiShaderResourceBinding b;
5644 b.d.binding = binding;
5645 b.d.stage = stage;
5646 b.d.type = UniformBuffer;
5647 b.d.u.ubuf.buf = buf;
5648 b.d.u.ubuf.offset = 0;
5649 b.d.u.ubuf.maybeSize = size;
5650 b.d.u.ubuf.hasDynamicOffset = true;
5651 return b;
5652}
5653
5654/*!
5655 \return a shader resource binding for the given binding number, pipeline
5656 stages, texture, and sampler specified by \a binding, \a stage, \a tex,
5657 \a sampler.
5658
5659 \note This function is equivalent to calling sampledTextures() with a
5660 \c count of 1.
5661
5662 \note \a tex and \a sampler can be null. It is valid to create a
5663 QRhiShaderResourceBindings with unspecified resources, but such an object
5664 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
5665 suitable for creating pipelines. Such a pipeline must then always be used
5666 together with another, layout compatible QRhiShaderResourceBindings with
5667 resources present passed to QRhiCommandBuffer::setShaderResources().
5668
5669 \note A shader may not be able to consume more than 16 textures/samplers,
5670 depending on the underlying graphics API. This hard limit must be kept in
5671 mind in renderer design. This does not apply to texture arrays which
5672 consume a single binding point (shader register) and can contain 256-2048
5673 textures, depending on the underlying graphics API. Arrays of textures (see
5674 sampledTextures()) are however no different in this regard than using the
5675 same number of individual textures.
5676
5677 \sa sampledTextures()
5678 */
5679QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture(
5680 int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)
5681{
5682 QRhiShaderResourceBinding b;
5683 b.d.binding = binding;
5684 b.d.stage = stage;
5685 b.d.type = SampledTexture;
5686 b.d.u.stex.count = 1;
5687 b.d.u.stex.texSamplers[0] = { .tex: tex, .sampler: sampler };
5688 return b;
5689}
5690
5691/*!
5692 \return a shader resource binding for the given binding number, pipeline
5693 stages, and the array of texture-sampler pairs specified by \a binding, \a
5694 stage, \a count, and \a texSamplers.
5695
5696 \note \a count must be at least 1, and not larger than 16.
5697
5698 \note When \a count is 1, this function is equivalent to sampledTexture().
5699
5700 This function is relevant when arrays of combined image samplers are
5701 involved. For example, in GLSL \c{layout(binding = 5) uniform sampler2D
5702 shadowMaps[8];} declares an array of combined image samplers. The
5703 application is then expected provide a QRhiShaderResourceBinding for
5704 binding point 5, set up by calling this function with \a count set to 8 and
5705 a valid texture and sampler for each element of the array.
5706
5707 \warning All elements of the array must be specified. With the above
5708 example, the only valid, portable approach is calling this function with a
5709 \a count of 8. Additionally, all QRhiTexture and QRhiSampler instances must
5710 be valid, meaning nullptr is not an accepted value. This is due to some of
5711 the underlying APIs, such as, Vulkan, that require a valid image and
5712 sampler object for each element in descriptor arrays. Applications are
5713 advised to provide "dummy" samplers and textures if some array elements are
5714 not relevant (due to not being accessed in the shader).
5715
5716 \note \a texSamplers can be null. It is valid to create a
5717 QRhiShaderResourceBindings with unspecified resources, but such an object
5718 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
5719 suitable for creating pipelines. Such a pipeline must then always be used
5720 together with another, layout compatible QRhiShaderResourceBindings with
5721 resources present passed to QRhiCommandBuffer::setShaderResources().
5722
5723 \sa sampledTexture()
5724 */
5725QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTextures(
5726 int binding, StageFlags stage, int count, const TextureAndSampler *texSamplers)
5727{
5728 Q_ASSERT(count >= 1 && count <= Data::MAX_TEX_SAMPLER_ARRAY_SIZE);
5729 QRhiShaderResourceBinding b;
5730 b.d.binding = binding;
5731 b.d.stage = stage;
5732 b.d.type = SampledTexture;
5733 b.d.u.stex.count = count;
5734 for (int i = 0; i < count; ++i) {
5735 if (texSamplers)
5736 b.d.u.stex.texSamplers[i] = texSamplers[i];
5737 else
5738 b.d.u.stex.texSamplers[i] = { .tex: nullptr, .sampler: nullptr };
5739 }
5740 return b;
5741}
5742
5743/*!
5744 \return a shader resource binding for the given binding number, pipeline
5745 stages, and texture specified by \a binding, \a stage, \a tex.
5746
5747 \note This function is equivalent to calling textures() with a
5748 \c count of 1.
5749
5750 \note \a tex can be null. It is valid to create a
5751 QRhiShaderResourceBindings with unspecified resources, but such an object
5752 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
5753 suitable for creating pipelines. Such a pipeline must then always be used
5754 together with another, layout compatible QRhiShaderResourceBindings with
5755 resources present passed to QRhiCommandBuffer::setShaderResources().
5756
5757 This creates a binding for a separate texture (image) object, whereas
5758 sampledTexture() is suitable for combined image samplers. In
5759 Vulkan-compatible GLSL code separate textures are declared as \c texture2D
5760 as opposed to \c sampler2D: \c{layout(binding = 1) uniform texture2D tex;}
5761
5762 \note A shader may not be able to consume more than 16 textures, depending
5763 on the underlying graphics API. This hard limit must be kept in mind in
5764 renderer design. This does not apply to texture arrays which consume a
5765 single binding point (shader register) and can contain 256-2048 textures,
5766 depending on the underlying graphics API. Arrays of textures (see
5767 sampledTextures()) are however no different in this regard than using the
5768 same number of individual textures.
5769
5770 \sa textures(), sampler()
5771 */
5772QRhiShaderResourceBinding QRhiShaderResourceBinding::texture(int binding, StageFlags stage, QRhiTexture *tex)
5773{
5774 QRhiShaderResourceBinding b;
5775 b.d.binding = binding;
5776 b.d.stage = stage;
5777 b.d.type = Texture;
5778 b.d.u.stex.count = 1;
5779 b.d.u.stex.texSamplers[0] = { .tex: tex, .sampler: nullptr };
5780 return b;
5781}
5782
5783/*!
5784 \return a shader resource binding for the given binding number, pipeline
5785 stages, and the array of (separate) textures specified by \a binding, \a
5786 stage, \a count, and \a tex.
5787
5788 \note \a count must be at least 1, and not larger than 16.
5789
5790 \note When \a count is 1, this function is equivalent to texture().
5791
5792 \warning All elements of the array must be specified.
5793
5794 \note \a tex can be null. It is valid to create a
5795 QRhiShaderResourceBindings with unspecified resources, but such an object
5796 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
5797 suitable for creating pipelines. Such a pipeline must then always be used
5798 together with another, layout compatible QRhiShaderResourceBindings with
5799 resources present passed to QRhiCommandBuffer::setShaderResources().
5800
5801 \sa texture(), sampler()
5802 */
5803QRhiShaderResourceBinding QRhiShaderResourceBinding::textures(int binding, StageFlags stage, int count, QRhiTexture **tex)
5804{
5805 Q_ASSERT(count >= 1 && count <= Data::MAX_TEX_SAMPLER_ARRAY_SIZE);
5806 QRhiShaderResourceBinding b;
5807 b.d.binding = binding;
5808 b.d.stage = stage;
5809 b.d.type = Texture;
5810 b.d.u.stex.count = count;
5811 for (int i = 0; i < count; ++i) {
5812 if (tex)
5813 b.d.u.stex.texSamplers[i] = { .tex: tex[i], .sampler: nullptr };
5814 else
5815 b.d.u.stex.texSamplers[i] = { .tex: nullptr, .sampler: nullptr };
5816 }
5817 return b;
5818}
5819
5820/*!
5821 \return a shader resource binding for the given binding number, pipeline
5822 stages, and sampler specified by \a binding, \a stage, \a sampler.
5823
5824 \note \a sampler can be null. It is valid to create a
5825 QRhiShaderResourceBindings with unspecified resources, but such an object
5826 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
5827 suitable for creating pipelines. Such a pipeline must then always be used
5828 together with another, layout compatible QRhiShaderResourceBindings with
5829 resources present passed to QRhiCommandBuffer::setShaderResources().
5830
5831 Arrays of separate samplers are not supported.
5832
5833 This creates a binding for a separate sampler object, whereas
5834 sampledTexture() is suitable for combined image samplers. In
5835 Vulkan-compatible GLSL code separate samplers are declared as \c sampler
5836 as opposed to \c sampler2D: \c{layout(binding = 2) uniform sampler samp;}
5837
5838 With both a \c texture2D and \c sampler present, they can be used together
5839 to sample the texture: \c{fragColor = texture(sampler2D(tex, samp),
5840 texcoord);}.
5841
5842 \note A shader may not be able to consume more than 16 samplers, depending
5843 on the underlying graphics API. This hard limit must be kept in mind in
5844 renderer design.
5845
5846 \sa texture()
5847 */
5848QRhiShaderResourceBinding QRhiShaderResourceBinding::sampler(int binding, StageFlags stage, QRhiSampler *sampler)
5849{
5850 QRhiShaderResourceBinding b;
5851 b.d.binding = binding;
5852 b.d.stage = stage;
5853 b.d.type = Sampler;
5854 b.d.u.stex.count = 1;
5855 b.d.u.stex.texSamplers[0] = { .tex: nullptr, .sampler: sampler };
5856 return b;
5857}
5858
5859/*!
5860 \return a shader resource binding for a read-only storage image with the
5861 given \a binding number and pipeline \a stage. The image load operations
5862 will have access to all layers of the specified \a level. (so if the texture
5863 is a cubemap, the shader must use imageCube instead of image2D)
5864
5865 \note When \a tex is not null, it must have been created with
5866 QRhiTexture::UsedWithLoadStore.
5867
5868 \note \a tex can be null. It is valid to create a QRhiShaderResourceBindings
5869 with unspecified resources, but such an object cannot be used with
5870 QRhiCommandBuffer::setShaderResources(). It is however suitable for creating
5871 pipelines. Such a pipeline must then always be used together with another,
5872 layout compatible QRhiShaderResourceBindings with resources present passed
5873 to QRhiCommandBuffer::setShaderResources().
5874
5875 \note Image load/store is only guaranteed to be available within a compute
5876 pipeline. While some backends may support using these resources in a
5877 graphics pipeline as well, this is not universally supported, and even when
5878 it is, unexpected problems may arise when it comes to barriers and
5879 synchronization. Therefore, avoid using such resources with shaders other
5880 than compute.
5881 */
5882QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoad(
5883 int binding, StageFlags stage, QRhiTexture *tex, int level)
5884{
5885 QRhiShaderResourceBinding b;
5886 b.d.binding = binding;
5887 b.d.stage = stage;
5888 b.d.type = ImageLoad;
5889 b.d.u.simage.tex = tex;
5890 b.d.u.simage.level = level;
5891 return b;
5892}
5893
5894/*!
5895 \return a shader resource binding for a write-only storage image with the
5896 given \a binding number and pipeline \a stage. The image store operations
5897 will have access to all layers of the specified \a level. (so if the texture
5898 is a cubemap, the shader must use imageCube instead of image2D)
5899
5900 \note When \a tex is not null, it must have been created with
5901 QRhiTexture::UsedWithLoadStore.
5902
5903 \note \a tex can be null. It is valid to create a QRhiShaderResourceBindings
5904 with unspecified resources, but such an object cannot be used with
5905 QRhiCommandBuffer::setShaderResources(). It is however suitable for creating
5906 pipelines. Such a pipeline must then always be used together with another,
5907 layout compatible QRhiShaderResourceBindings with resources present passed
5908 to QRhiCommandBuffer::setShaderResources().
5909
5910 \note Image load/store is only guaranteed to be available within a compute
5911 pipeline. While some backends may support using these resources in a
5912 graphics pipeline as well, this is not universally supported, and even when
5913 it is, unexpected problems may arise when it comes to barriers and
5914 synchronization. Therefore, avoid using such resources with shaders other
5915 than compute.
5916 */
5917QRhiShaderResourceBinding QRhiShaderResourceBinding::imageStore(
5918 int binding, StageFlags stage, QRhiTexture *tex, int level)
5919{
5920 QRhiShaderResourceBinding b;
5921 b.d.binding = binding;
5922 b.d.stage = stage;
5923 b.d.type = ImageStore;
5924 b.d.u.simage.tex = tex;
5925 b.d.u.simage.level = level;
5926 return b;
5927}
5928
5929/*!
5930 \return a shader resource binding for a read/write storage image with the
5931 given \a binding number and pipeline \a stage. The image load/store operations
5932 will have access to all layers of the specified \a level. (so if the texture
5933 is a cubemap, the shader must use imageCube instead of image2D)
5934
5935 \note When \a tex is not null, it must have been created with
5936 QRhiTexture::UsedWithLoadStore.
5937
5938 \note \a tex can be null. It is valid to create a QRhiShaderResourceBindings
5939 with unspecified resources, but such an object cannot be used with
5940 QRhiCommandBuffer::setShaderResources(). It is however suitable for creating
5941 pipelines. Such a pipeline must then always be used together with another,
5942 layout compatible QRhiShaderResourceBindings with resources present passed
5943 to QRhiCommandBuffer::setShaderResources().
5944
5945 \note Image load/store is only guaranteed to be available within a compute
5946 pipeline. While some backends may support using these resources in a
5947 graphics pipeline as well, this is not universally supported, and even when
5948 it is, unexpected problems may arise when it comes to barriers and
5949 synchronization. Therefore, avoid using such resources with shaders other
5950 than compute.
5951 */
5952QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoadStore(
5953 int binding, StageFlags stage, QRhiTexture *tex, int level)
5954{
5955 QRhiShaderResourceBinding b;
5956 b.d.binding = binding;
5957 b.d.stage = stage;
5958 b.d.type = ImageLoadStore;
5959 b.d.u.simage.tex = tex;
5960 b.d.u.simage.level = level;
5961 return b;
5962}
5963
5964/*!
5965 \return a shader resource binding for a read-only storage buffer with the
5966 given \a binding number and pipeline \a stage.
5967
5968 \note When \a buf is not null, must have been created with
5969 QRhiBuffer::StorageBuffer.
5970
5971 \note \a buf can be null. It is valid to create a
5972 QRhiShaderResourceBindings with unspecified resources, but such an object
5973 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
5974 suitable for creating pipelines. Such a pipeline must then always be used
5975 together with another, layout compatible QRhiShaderResourceBindings with
5976 resources present passed to QRhiCommandBuffer::setShaderResources().
5977
5978 \note Buffer load/store is only guaranteed to be available within a compute
5979 pipeline. While some backends may support using these resources in a
5980 graphics pipeline as well, this is not universally supported, and even when
5981 it is, unexpected problems may arise when it comes to barriers and
5982 synchronization. Therefore, avoid using such resources with shaders other
5983 than compute.
5984 */
5985QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
5986 int binding, StageFlags stage, QRhiBuffer *buf)
5987{
5988 QRhiShaderResourceBinding b;
5989 b.d.binding = binding;
5990 b.d.stage = stage;
5991 b.d.type = BufferLoad;
5992 b.d.u.sbuf.buf = buf;
5993 b.d.u.sbuf.offset = 0;
5994 b.d.u.sbuf.maybeSize = 0; // entire buffer
5995 return b;
5996}
5997
5998/*!
5999 \return a shader resource binding for a read-only storage buffer with the
6000 given \a binding number and pipeline \a stage. This overload binds a region
6001 only, as specified by \a offset and \a size.
6002
6003 \note When \a buf is not null, must have been created with
6004 QRhiBuffer::StorageBuffer.
6005
6006 \note \a buf can be null. It is valid to create a
6007 QRhiShaderResourceBindings with unspecified resources, but such an object
6008 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
6009 suitable for creating pipelines. Such a pipeline must then always be used
6010 together with another, layout compatible QRhiShaderResourceBindings with
6011 resources present passed to QRhiCommandBuffer::setShaderResources().
6012
6013 \note Buffer load/store is only guaranteed to be available within a compute
6014 pipeline. While some backends may support using these resources in a
6015 graphics pipeline as well, this is not universally supported, and even when
6016 it is, unexpected problems may arise when it comes to barriers and
6017 synchronization. Therefore, avoid using such resources with shaders other
6018 than compute.
6019 */
6020QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
6021 int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size)
6022{
6023 Q_ASSERT(size > 0);
6024 QRhiShaderResourceBinding b;
6025 b.d.binding = binding;
6026 b.d.stage = stage;
6027 b.d.type = BufferLoad;
6028 b.d.u.sbuf.buf = buf;
6029 b.d.u.sbuf.offset = offset;
6030 b.d.u.sbuf.maybeSize = size;
6031 return b;
6032}
6033
6034/*!
6035 \return a shader resource binding for a write-only storage buffer with the
6036 given \a binding number and pipeline \a stage.
6037
6038 \note When \a buf is not null, must have been created with
6039 QRhiBuffer::StorageBuffer.
6040
6041 \note \a buf can be null. It is valid to create a
6042 QRhiShaderResourceBindings with unspecified resources, but such an object
6043 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
6044 suitable for creating pipelines. Such a pipeline must then always be used
6045 together with another, layout compatible QRhiShaderResourceBindings with
6046 resources present passed to QRhiCommandBuffer::setShaderResources().
6047
6048 \note Buffer load/store is only guaranteed to be available within a compute
6049 pipeline. While some backends may support using these resources in a
6050 graphics pipeline as well, this is not universally supported, and even when
6051 it is, unexpected problems may arise when it comes to barriers and
6052 synchronization. Therefore, avoid using such resources with shaders other
6053 than compute.
6054 */
6055QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
6056 int binding, StageFlags stage, QRhiBuffer *buf)
6057{
6058 QRhiShaderResourceBinding b;
6059 b.d.binding = binding;
6060 b.d.stage = stage;
6061 b.d.type = BufferStore;
6062 b.d.u.sbuf.buf = buf;
6063 b.d.u.sbuf.offset = 0;
6064 b.d.u.sbuf.maybeSize = 0; // entire buffer
6065 return b;
6066}
6067
6068/*!
6069 \return a shader resource binding for a write-only storage buffer with the
6070 given \a binding number and pipeline \a stage. This overload binds a region
6071 only, as specified by \a offset and \a size.
6072
6073 \note When \a buf is not null, must have been created with
6074 QRhiBuffer::StorageBuffer.
6075
6076 \note \a buf can be null. It is valid to create a
6077 QRhiShaderResourceBindings with unspecified resources, but such an object
6078 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
6079 suitable for creating pipelines. Such a pipeline must then always be used
6080 together with another, layout compatible QRhiShaderResourceBindings with
6081 resources present passed to QRhiCommandBuffer::setShaderResources().
6082
6083 \note Buffer load/store is only guaranteed to be available within a compute
6084 pipeline. While some backends may support using these resources in a
6085 graphics pipeline as well, this is not universally supported, and even when
6086 it is, unexpected problems may arise when it comes to barriers and
6087 synchronization. Therefore, avoid using such resources with shaders other
6088 than compute.
6089 */
6090QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
6091 int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size)
6092{
6093 Q_ASSERT(size > 0);
6094 QRhiShaderResourceBinding b;
6095 b.d.binding = binding;
6096 b.d.stage = stage;
6097 b.d.type = BufferStore;
6098 b.d.u.sbuf.buf = buf;
6099 b.d.u.sbuf.offset = offset;
6100 b.d.u.sbuf.maybeSize = size;
6101 return b;
6102}
6103
6104/*!
6105 \return a shader resource binding for a read-write storage buffer with the
6106 given \a binding number and pipeline \a stage.
6107
6108 \note When \a buf is not null, must have been created with
6109 QRhiBuffer::StorageBuffer.
6110
6111 \note \a buf can be null. It is valid to create a
6112 QRhiShaderResourceBindings with unspecified resources, but such an object
6113 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
6114 suitable for creating pipelines. Such a pipeline must then always be used
6115 together with another, layout compatible QRhiShaderResourceBindings with
6116 resources present passed to QRhiCommandBuffer::setShaderResources().
6117
6118 \note Buffer load/store is only guaranteed to be available within a compute
6119 pipeline. While some backends may support using these resources in a
6120 graphics pipeline as well, this is not universally supported, and even when
6121 it is, unexpected problems may arise when it comes to barriers and
6122 synchronization. Therefore, avoid using such resources with shaders other
6123 than compute.
6124 */
6125QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
6126 int binding, StageFlags stage, QRhiBuffer *buf)
6127{
6128 QRhiShaderResourceBinding b;
6129 b.d.binding = binding;
6130 b.d.stage = stage;
6131 b.d.type = BufferLoadStore;
6132 b.d.u.sbuf.buf = buf;
6133 b.d.u.sbuf.offset = 0;
6134 b.d.u.sbuf.maybeSize = 0; // entire buffer
6135 return b;
6136}
6137
6138/*!
6139 \return a shader resource binding for a read-write storage buffer with the
6140 given \a binding number and pipeline \a stage. This overload binds a region
6141 only, as specified by \a offset and \a size.
6142
6143 \note When \a buf is not null, must have been created with
6144 QRhiBuffer::StorageBuffer.
6145
6146 \note \a buf can be null. It is valid to create a
6147 QRhiShaderResourceBindings with unspecified resources, but such an object
6148 cannot be used with QRhiCommandBuffer::setShaderResources(). It is however
6149 suitable for creating pipelines. Such a pipeline must then always be used
6150 together with another, layout compatible QRhiShaderResourceBindings with
6151 resources present passed to QRhiCommandBuffer::setShaderResources().
6152
6153 \note Buffer load/store is only guaranteed to be available within a compute
6154 pipeline. While some backends may support using these resources in a
6155 graphics pipeline as well, this is not universally supported, and even when
6156 it is, unexpected problems may arise when it comes to barriers and
6157 synchronization. Therefore, avoid using such resources with shaders other
6158 than compute.
6159 */
6160QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
6161 int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size)
6162{
6163 Q_ASSERT(size > 0);
6164 QRhiShaderResourceBinding b;
6165 b.d.binding = binding;
6166 b.d.stage = stage;
6167 b.d.type = BufferLoadStore;
6168 b.d.u.sbuf.buf = buf;
6169 b.d.u.sbuf.offset = offset;
6170 b.d.u.sbuf.maybeSize = size;
6171 return b;
6172}
6173
6174/*!
6175 \return \c true if the contents of the two QRhiShaderResourceBinding
6176 objects \a a and \a b are equal. This includes the resources (buffer,
6177 texture) and related parameters (offset, size) as well. To only compare
6178 layouts (binding point, pipeline stage, resource type), use
6179 \l{QRhiShaderResourceBinding::isLayoutCompatible()}{isLayoutCompatible()}
6180 instead.
6181
6182 \relates QRhiShaderResourceBinding
6183 */
6184bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept
6185{
6186 const QRhiShaderResourceBinding::Data *da = QRhiImplementation::shaderResourceBindingData(binding: a);
6187 const QRhiShaderResourceBinding::Data *db = QRhiImplementation::shaderResourceBindingData(binding: b);
6188
6189 if (da == db)
6190 return true;
6191
6192
6193 if (da->binding != db->binding
6194 || da->stage != db->stage
6195 || da->type != db->type)
6196 {
6197 return false;
6198 }
6199
6200 switch (da->type) {
6201 case QRhiShaderResourceBinding::UniformBuffer:
6202 if (da->u.ubuf.buf != db->u.ubuf.buf
6203 || da->u.ubuf.offset != db->u.ubuf.offset
6204 || da->u.ubuf.maybeSize != db->u.ubuf.maybeSize)
6205 {
6206 return false;
6207 }
6208 break;
6209 case QRhiShaderResourceBinding::SampledTexture:
6210 if (da->u.stex.count != db->u.stex.count)
6211 return false;
6212 for (int i = 0; i < da->u.stex.count; ++i) {
6213 if (da->u.stex.texSamplers[i].tex != db->u.stex.texSamplers[i].tex
6214 || da->u.stex.texSamplers[i].sampler != db->u.stex.texSamplers[i].sampler)
6215 {
6216 return false;
6217 }
6218 }
6219 break;
6220 case QRhiShaderResourceBinding::Texture:
6221 if (da->u.stex.count != db->u.stex.count)
6222 return false;
6223 for (int i = 0; i < da->u.stex.count; ++i) {
6224 if (da->u.stex.texSamplers[i].tex != db->u.stex.texSamplers[i].tex)
6225 return false;
6226 }
6227 break;
6228 case QRhiShaderResourceBinding::Sampler:
6229 if (da->u.stex.texSamplers[0].sampler != db->u.stex.texSamplers[0].sampler)
6230 return false;
6231 break;
6232 case QRhiShaderResourceBinding::ImageLoad:
6233 case QRhiShaderResourceBinding::ImageStore:
6234 case QRhiShaderResourceBinding::ImageLoadStore:
6235 if (da->u.simage.tex != db->u.simage.tex
6236 || da->u.simage.level != db->u.simage.level)
6237 {
6238 return false;
6239 }
6240 break;
6241 case QRhiShaderResourceBinding::BufferLoad:
6242 case QRhiShaderResourceBinding::BufferStore:
6243 case QRhiShaderResourceBinding::BufferLoadStore:
6244 if (da->u.sbuf.buf != db->u.sbuf.buf
6245 || da->u.sbuf.offset != db->u.sbuf.offset
6246 || da->u.sbuf.maybeSize != db->u.sbuf.maybeSize)
6247 {
6248 return false;
6249 }
6250 break;
6251 default:
6252 Q_UNREACHABLE_RETURN(false);
6253 }
6254
6255 return true;
6256}
6257
6258/*!
6259 \return \c false if all the bindings in the two QRhiShaderResourceBinding
6260 objects \a a and \a b are equal; otherwise returns \c true.
6261
6262 \relates QRhiShaderResourceBinding
6263 */
6264bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept
6265{
6266 return !(a == b);
6267}
6268
6269/*!
6270 \fn size_t qHash(const QRhiShaderResourceBinding &key, size_t seed)
6271 \qhashold{QRhiShaderResourceBinding}
6272 */
6273size_t qHash(const QRhiShaderResourceBinding &b, size_t seed) noexcept
6274{
6275 const QRhiShaderResourceBinding::Data *d = QRhiImplementation::shaderResourceBindingData(binding: b);
6276 QtPrivate::QHashCombine hash;
6277 seed = hash(seed, d->binding);
6278 seed = hash(seed, d->stage);
6279 seed = hash(seed, d->type);
6280 switch (d->type) {
6281 case QRhiShaderResourceBinding::UniformBuffer:
6282 seed = hash(seed, reinterpret_cast<quintptr>(d->u.ubuf.buf));
6283 break;
6284 case QRhiShaderResourceBinding::SampledTexture:
6285 seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].tex));
6286 seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].sampler));
6287 break;
6288 case QRhiShaderResourceBinding::Texture:
6289 seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].tex));
6290 break;
6291 case QRhiShaderResourceBinding::Sampler:
6292 seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].sampler));
6293 break;
6294 case QRhiShaderResourceBinding::ImageLoad:
6295 case QRhiShaderResourceBinding::ImageStore:
6296 case QRhiShaderResourceBinding::ImageLoadStore:
6297 seed = hash(seed, reinterpret_cast<quintptr>(d->u.simage.tex));
6298 break;
6299 case QRhiShaderResourceBinding::BufferLoad:
6300 case QRhiShaderResourceBinding::BufferStore:
6301 case QRhiShaderResourceBinding::BufferLoadStore:
6302 seed = hash(seed, reinterpret_cast<quintptr>(d->u.sbuf.buf));
6303 break;
6304 }
6305 return seed;
6306}
6307
6308#ifndef QT_NO_DEBUG_STREAM
6309QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
6310{
6311 QDebugStateSaver saver(dbg);
6312 const QRhiShaderResourceBinding::Data *d = QRhiImplementation::shaderResourceBindingData(binding: b);
6313 dbg.nospace() << "QRhiShaderResourceBinding("
6314 << "binding=" << d->binding
6315 << " stage=" << d->stage
6316 << " type=" << d->type;
6317 switch (d->type) {
6318 case QRhiShaderResourceBinding::UniformBuffer:
6319 dbg.nospace() << " UniformBuffer("
6320 << "buffer=" << d->u.ubuf.buf
6321 << " offset=" << d->u.ubuf.offset
6322 << " maybeSize=" << d->u.ubuf.maybeSize
6323 << ')';
6324 break;
6325 case QRhiShaderResourceBinding::SampledTexture:
6326 dbg.nospace() << " SampledTextures("
6327 << "count=" << d->u.stex.count;
6328 for (int i = 0; i < d->u.stex.count; ++i) {
6329 dbg.nospace() << " texture=" << d->u.stex.texSamplers[i].tex
6330 << " sampler=" << d->u.stex.texSamplers[i].sampler;
6331 }
6332 dbg.nospace() << ')';
6333 break;
6334 case QRhiShaderResourceBinding::Texture:
6335 dbg.nospace() << " Textures("
6336 << "count=" << d->u.stex.count;
6337 for (int i = 0; i < d->u.stex.count; ++i)
6338 dbg.nospace() << " texture=" << d->u.stex.texSamplers[i].tex;
6339 dbg.nospace() << ')';
6340 break;
6341 case QRhiShaderResourceBinding::Sampler:
6342 dbg.nospace() << " Sampler("
6343 << " sampler=" << d->u.stex.texSamplers[0].sampler
6344 << ')';
6345 break;
6346 case QRhiShaderResourceBinding::ImageLoad:
6347 dbg.nospace() << " ImageLoad("
6348 << "texture=" << d->u.simage.tex
6349 << " level=" << d->u.simage.level
6350 << ')';
6351 break;
6352 case QRhiShaderResourceBinding::ImageStore:
6353 dbg.nospace() << " ImageStore("
6354 << "texture=" << d->u.simage.tex
6355 << " level=" << d->u.simage.level
6356 << ')';
6357 break;
6358 case QRhiShaderResourceBinding::ImageLoadStore:
6359 dbg.nospace() << " ImageLoadStore("
6360 << "texture=" << d->u.simage.tex
6361 << " level=" << d->u.simage.level
6362 << ')';
6363 break;
6364 case QRhiShaderResourceBinding::BufferLoad:
6365 dbg.nospace() << " BufferLoad("
6366 << "buffer=" << d->u.sbuf.buf
6367 << " offset=" << d->u.sbuf.offset
6368 << " maybeSize=" << d->u.sbuf.maybeSize
6369 << ')';
6370 break;
6371 case QRhiShaderResourceBinding::BufferStore:
6372 dbg.nospace() << " BufferStore("
6373 << "buffer=" << d->u.sbuf.buf
6374 << " offset=" << d->u.sbuf.offset
6375 << " maybeSize=" << d->u.sbuf.maybeSize
6376 << ')';
6377 break;
6378 case QRhiShaderResourceBinding::BufferLoadStore:
6379 dbg.nospace() << " BufferLoadStore("
6380 << "buffer=" << d->u.sbuf.buf
6381 << " offset=" << d->u.sbuf.offset
6382 << " maybeSize=" << d->u.sbuf.maybeSize
6383 << ')';
6384 break;
6385 default:
6386 dbg.nospace() << " UNKNOWN()";
6387 break;
6388 }
6389 dbg.nospace() << ')';
6390 return dbg;
6391}
6392#endif
6393
6394#ifndef QT_NO_DEBUG_STREAM
6395QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb)
6396{
6397 QDebugStateSaver saver(dbg);
6398 dbg.nospace() << "QRhiShaderResourceBindings("
6399 << srb.m_bindings
6400 << ')';
6401 return dbg;
6402}
6403#endif
6404
6405/*!
6406 \class QRhiGraphicsPipeline
6407 \inmodule QtGuiPrivate
6408 \inheaderfile rhi/qrhi.h
6409 \since 6.6
6410 \brief Graphics pipeline state resource.
6411
6412 Represents a graphics pipeline. What exactly this map to in the underlying
6413 native graphics API, varies. Where there is a concept of pipeline objects,
6414 for example with Vulkan, the QRhi backend will create such an object upon
6415 calling create(). Elsewhere, for example with OpenGL, the
6416 QRhiGraphicsPipeline may merely collect the various state, and create()'s
6417 main task is to set up the corresponding shader program, but deferring
6418 looking at any of the requested state to a later point.
6419
6420 As with all QRhiResource subclasses, the two-phased initialization pattern
6421 applies: setting any values via the setters, for example setDepthTest(), is
6422 only effective after calling create(). Avoid changing any values once the
6423 QRhiGraphicsPipeline has been initialized via create(). To change some
6424 state, set the new value and call create() again. However, that will
6425 effectively release all underlying native resources and create new ones. As
6426 a result, it may be a heavy, expensive operation. Rather, prefer creating
6427 multiple pipelines with the different states, and
6428 \l{QRhiCommandBuffer::setGraphicsPipeline()}{switch between them} when
6429 recording the render pass.
6430
6431 \note Setting the shader stages is mandatory. There must be at least one
6432 stage, and there must be a vertex stage.
6433
6434 \note Setting the shader resource bindings is mandatory. The referenced
6435 QRhiShaderResourceBindings must already have create() called on it by the
6436 time create() is called. Associating with a QRhiShaderResourceBindings that
6437 has no bindings is also valid, as long as no shader in any stage expects any
6438 resources. Using a QRhiShaderResourceBindings object that does not specify
6439 any actual resources (i.e., the buffers, textures, etc. for the binding
6440 points are set to \nullptr) is valid as well, as long as a
6441 \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible}
6442 QRhiShaderResourceBindings, that specifies resources for all the bindings,
6443 is going to be set via
6444 \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} when
6445 recording the render pass.
6446
6447 \note Setting the render pass descriptor is mandatory. To obtain a
6448 QRhiRenderPassDescriptor that can be passed to setRenderPassDescriptor(),
6449 use either QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor() or
6450 QRhiSwapChain::newCompatibleRenderPassDescriptor().
6451
6452 \note Setting the vertex input layout is mandatory.
6453
6454 \note sampleCount() defaults to 1 and must match the sample count of the
6455 render target's color and depth stencil attachments.
6456
6457 \note The depth test, depth write, and stencil test are disabled by
6458 default. The face culling mode defaults to no culling.
6459
6460 \note stencilReadMask() and stencilWriteMask() apply to both faces. They
6461 both default to 0xFF.
6462
6463 \section2 Example usage
6464
6465 All settings of a graphics pipeline have defaults which might be suitable
6466 to many applications. Therefore a minimal example of creating a graphics
6467 pipeline could be the following. This assumes that the vertex shader takes
6468 a single \c{vec3 position} input at the input location 0. With the
6469 QRhiShaderResourceBindings and QRhiRenderPassDescriptor objects, plus the
6470 QShader collections for the vertex and fragment stages, a pipeline could be
6471 created like this:
6472
6473 \code
6474 QRhiShaderResourceBindings *srb;
6475 QRhiRenderPassDescriptor *rpDesc;
6476 QShader vs, fs;
6477 // ...
6478
6479 QRhiVertexInputLayout inputLayout;
6480 inputLayout.setBindings({ { 3 * sizeof(float) } });
6481 inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float3, 0 } });
6482
6483 QRhiGraphicsPipeline *ps = rhi->newGraphicsPipeline();
6484 ps->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } });
6485 ps->setVertexInputLayout(inputLayout);
6486 ps->setShaderResourceBindings(srb);
6487 ps->setRenderPassDescriptor(rpDesc);
6488 if (!ps->create()) { error(); }
6489 \endcode
6490
6491 The above code creates a pipeline object that uses the defaults for many
6492 settings and states. For example, it will use a \l Triangles topology, no
6493 backface culling, blending is disabled but color write is enabled for all
6494 four channels, depth test/write are disabled, stencil operations are
6495 disabled.
6496
6497 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
6498 for details.
6499
6500 \sa QRhiCommandBuffer, QRhi
6501 */
6502
6503/*!
6504 \enum QRhiGraphicsPipeline::Flag
6505
6506 Flag values for describing the dynamic state of the pipeline, and other
6507 options. The viewport is always dynamic.
6508
6509 \value UsesBlendConstants Indicates that a blend color constant will be set
6510 via QRhiCommandBuffer::setBlendConstants()
6511
6512 \value UsesStencilRef Indicates that a stencil reference value will be set
6513 via QRhiCommandBuffer::setStencilRef()
6514
6515 \value UsesScissor Indicates that a scissor rectangle will be set via
6516 QRhiCommandBuffer::setScissor()
6517
6518 \value CompileShadersWithDebugInfo Requests compiling shaders with debug
6519 information enabled. This is relevant only when runtime shader compilation
6520 from source code is involved, and only when the underlying infrastructure
6521 supports this. With concrete examples, this is not relevant with Vulkan and
6522 SPIR-V, because the GLSL-to-SPIR-V compilation does not happen at run
6523 time. On the other hand, consider Direct3D and HLSL, where there are
6524 multiple options: when the QShader packages ship with pre-compiled bytecode
6525 (\c DXBC), debug information is to be requested through the tool that
6526 generates the \c{.qsb} file, similarly to the case of Vulkan and
6527 SPIR-V. However, when having HLSL source code in the pre- or
6528 runtime-generated QShader packages, the first phase of compilation (HLSL
6529 source to intermediate format) happens at run time too, with this flag taken
6530 into account. Debug information is relevant in particular with tools like
6531 RenderDoc since it allows seeing the original source code when investigating
6532 the pipeline and when performing vertex or fragment shader debugging.
6533 */
6534
6535/*!
6536 \enum QRhiGraphicsPipeline::Topology
6537 Specifies the primitive topology
6538
6539 \value Triangles (default)
6540 \value TriangleStrip
6541 \value TriangleFan (only available if QRhi::TriangleFanTopology is supported)
6542 \value Lines
6543 \value LineStrip
6544 \value Points
6545
6546 \value Patches (only available if QRhi::Tessellation is supported, and
6547 requires the tessellation stages to be present in the pipeline)
6548 */
6549
6550/*!
6551 \enum QRhiGraphicsPipeline::CullMode
6552 Specifies the culling mode
6553
6554 \value None No culling (default)
6555 \value Front Cull front faces
6556 \value Back Cull back faces
6557 */
6558
6559/*!
6560 \enum QRhiGraphicsPipeline::FrontFace
6561 Specifies the front face winding order
6562
6563 \value CCW Counter clockwise (default)
6564 \value CW Clockwise
6565 */
6566
6567/*!
6568 \enum QRhiGraphicsPipeline::ColorMaskComponent
6569 Flag values for specifying the color write mask
6570
6571 \value R
6572 \value G
6573 \value B
6574 \value A
6575 */
6576
6577/*!
6578 \enum QRhiGraphicsPipeline::BlendFactor
6579 Specifies the blend factor
6580
6581 \value Zero
6582 \value One
6583 \value SrcColor
6584 \value OneMinusSrcColor
6585 \value DstColor
6586 \value OneMinusDstColor
6587 \value SrcAlpha
6588 \value OneMinusSrcAlpha
6589 \value DstAlpha
6590 \value OneMinusDstAlpha
6591 \value ConstantColor
6592 \value OneMinusConstantColor
6593 \value ConstantAlpha
6594 \value OneMinusConstantAlpha
6595 \value SrcAlphaSaturate
6596 \value Src1Color
6597 \value OneMinusSrc1Color
6598 \value Src1Alpha
6599 \value OneMinusSrc1Alpha
6600 */
6601
6602/*!
6603 \enum QRhiGraphicsPipeline::BlendOp
6604 Specifies the blend operation
6605
6606 \value Add
6607 \value Subtract
6608 \value ReverseSubtract
6609 \value Min
6610 \value Max
6611 */
6612
6613/*!
6614 \enum QRhiGraphicsPipeline::CompareOp
6615 Specifies the depth or stencil comparison function
6616
6617 \value Never
6618 \value Less (default for depth)
6619 \value Equal
6620 \value LessOrEqual
6621 \value Greater
6622 \value NotEqual
6623 \value GreaterOrEqual
6624 \value Always (default for stencil)
6625 */
6626
6627/*!
6628 \enum QRhiGraphicsPipeline::StencilOp
6629 Specifies the stencil operation
6630
6631 \value StencilZero
6632 \value Keep (default)
6633 \value Replace
6634 \value IncrementAndClamp
6635 \value DecrementAndClamp
6636 \value Invert
6637 \value IncrementAndWrap
6638 \value DecrementAndWrap
6639 */
6640
6641/*!
6642 \enum QRhiGraphicsPipeline::PolygonMode
6643 \brief Specifies the polygon rasterization mode
6644
6645 Polygon Mode (Triangle Fill Mode in Metal, Fill Mode in D3D) specifies
6646 the fill mode used when rasterizing polygons. Polygons may be drawn as
6647 solids (Fill), or as a wire mesh (Line).
6648
6649 Support for non-fill polygon modes is optional and is indicated by the
6650 QRhi::NonFillPolygonMode feature. With OpenGL ES and some Vulkan
6651 implementations the feature will likely be reported as unsupported, which
6652 then means values other than Fill cannot be used.
6653
6654 \value Fill The interior of the polygon is filled (default)
6655 \value Line Boundary edges of the polygon are drawn as line segments.
6656 */
6657
6658/*!
6659 \struct QRhiGraphicsPipeline::TargetBlend
6660 \inmodule QtGuiPrivate
6661 \inheaderfile rhi/qrhi.h
6662 \since 6.6
6663 \brief Describes the blend state for one color attachment.
6664
6665 Defaults to color write enabled, blending disabled. The blend values are
6666 set up for pre-multiplied alpha (One, OneMinusSrcAlpha, One,
6667 OneMinusSrcAlpha) by default. This means that to get the alpha blending
6668 mode Qt Quick uses, it is enough to set the \c enable flag to true while
6669 leaving other values at their defaults.
6670
6671 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
6672 for details.
6673 */
6674
6675/*!
6676 \variable QRhiGraphicsPipeline::TargetBlend::colorWrite
6677 */
6678
6679/*!
6680 \variable QRhiGraphicsPipeline::TargetBlend::enable
6681 */
6682
6683/*!
6684 \variable QRhiGraphicsPipeline::TargetBlend::srcColor
6685 */
6686
6687/*!
6688 \variable QRhiGraphicsPipeline::TargetBlend::dstColor
6689 */
6690
6691/*!
6692 \variable QRhiGraphicsPipeline::TargetBlend::opColor
6693 */
6694
6695/*!
6696 \variable QRhiGraphicsPipeline::TargetBlend::srcAlpha
6697 */
6698
6699/*!
6700 \variable QRhiGraphicsPipeline::TargetBlend::dstAlpha
6701 */
6702
6703/*!
6704 \variable QRhiGraphicsPipeline::TargetBlend::opAlpha
6705 */
6706
6707/*!
6708 \struct QRhiGraphicsPipeline::StencilOpState
6709 \inmodule QtGuiPrivate
6710 \inheaderfile rhi/qrhi.h
6711 \since 6.6
6712 \brief Describes the stencil operation state.
6713
6714 The default-constructed StencilOpState has the following set:
6715 \list
6716 \li failOp - \l Keep
6717 \li depthFailOp - \l Keep
6718 \li passOp - \l Keep
6719 \li compareOp \l Always
6720 \endlist
6721
6722 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
6723 for details.
6724 */
6725
6726/*!
6727 \variable QRhiGraphicsPipeline::StencilOpState::failOp
6728 */
6729
6730/*!
6731 \variable QRhiGraphicsPipeline::StencilOpState::depthFailOp
6732 */
6733
6734/*!
6735 \variable QRhiGraphicsPipeline::StencilOpState::passOp
6736 */
6737
6738/*!
6739 \variable QRhiGraphicsPipeline::StencilOpState::compareOp
6740 */
6741
6742/*!
6743 \internal
6744 */
6745QRhiGraphicsPipeline::QRhiGraphicsPipeline(QRhiImplementation *rhi)
6746 : QRhiResource(rhi)
6747{
6748}
6749
6750/*!
6751 \return the resource type.
6752 */
6753QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
6754{
6755 return GraphicsPipeline;
6756}
6757
6758/*!
6759 \fn virtual bool QRhiGraphicsPipeline::create() = 0
6760
6761 Creates the corresponding native graphics resources. If there are already
6762 resources present due to an earlier create() with no corresponding
6763 destroy(), then destroy() is called implicitly first.
6764
6765 \return \c true when successful, \c false when a graphics operation failed.
6766 Regardless of the return value, calling destroy() is always safe.
6767
6768 \note This may be, depending on the underlying graphics API, an expensive
6769 operation, especially when shaders get compiled/optimized from source or
6770 from an intermediate bytecode format to the GPU's own instruction set.
6771 Where applicable, the QRhi backend automatically sets up the relevant
6772 non-persistent facilities to accelerate this, for example the Vulkan
6773 backend automatically creates a \c VkPipelineCache to improve data reuse
6774 during the lifetime of the application.
6775
6776 \note Drivers may also employ various persistent (disk-based) caching
6777 strategies for shader and pipeline data, which is hidden to and is outside
6778 of Qt's control. In some cases, depending on the graphics API and the QRhi
6779 backend, there are facilities within QRhi for manually managing such a
6780 cache, allowing the retrieval of a serializable blob that can then be
6781 reloaded in the future runs of the application to ensure faster pipeline
6782 creation times. See QRhi::pipelineCacheData() and
6783 QRhi::setPipelineCacheData() for details. Note also that when working with
6784 a QRhi instance managed by a higher level Qt framework, such as Qt Quick,
6785 it is possible that such disk-based caching is taken care of automatically,
6786 for example QQuickWindow uses a disk-based pipeline cache by default (which
6787 comes in addition to any driver-level caching).
6788 */
6789
6790/*!
6791 \fn QRhiGraphicsPipeline::Flags QRhiGraphicsPipeline::flags() const
6792 \return the currently set flags.
6793 */
6794
6795/*!
6796 \fn void QRhiGraphicsPipeline::setFlags(Flags f)
6797 Sets the flags \a f.
6798 */
6799
6800/*!
6801 \fn QRhiGraphicsPipeline::Topology QRhiGraphicsPipeline::topology() const
6802 \return the currently set primitive topology.
6803 */
6804
6805/*!
6806 \fn void QRhiGraphicsPipeline::setTopology(Topology t)
6807 Sets the primitive topology \a t.
6808 */
6809
6810/*!
6811 \fn QRhiGraphicsPipeline::CullMode QRhiGraphicsPipeline::cullMode() const
6812 \return the currently set face culling mode.
6813 */
6814
6815/*!
6816 \fn void QRhiGraphicsPipeline::setCullMode(CullMode mode)
6817 Sets the specified face culling \a mode.
6818 */
6819
6820/*!
6821 \fn QRhiGraphicsPipeline::FrontFace QRhiGraphicsPipeline::frontFace() const
6822 \return the currently set front face mode.
6823 */
6824
6825/*!
6826 \fn void QRhiGraphicsPipeline::setFrontFace(FrontFace f)
6827 Sets the front face mode \a f.
6828 */
6829
6830/*!
6831 \fn void QRhiGraphicsPipeline::setTargetBlends(std::initializer_list<TargetBlend> list)
6832
6833 Sets the \a list of render target blend settings. This is a list because
6834 when multiple render targets are used (i.e., a QRhiTextureRenderTarget with
6835 more than one QRhiColorAttachment), there needs to be a TargetBlend
6836 structure per render target (color attachment).
6837
6838 By default there is one default-constructed TargetBlend set.
6839
6840 \sa QRhi::MaxColorAttachments
6841 */
6842
6843/*!
6844 \fn template<typename InputIterator> void QRhiGraphicsPipeline::setTargetBlends(InputIterator first, InputIterator last)
6845 Sets the list of render target blend settings from the iterators \a first and \a last.
6846 */
6847
6848/*!
6849 \fn const QRhiGraphicsPipeline::TargetBlend *QRhiGraphicsPipeline::cbeginTargetBlends() const
6850 \return a const iterator pointing to the first item in the render target blend setting list.
6851 */
6852
6853/*!
6854 \fn const QRhiGraphicsPipeline::TargetBlend *QRhiGraphicsPipeline::cendTargetBlends() const
6855 \return a const iterator pointing just after the last item in the render target blend setting list.
6856 */
6857
6858/*!
6859 \fn const QRhiGraphicsPipeline::TargetBlend *QRhiGraphicsPipeline::targetBlendAt(qsizetype index) const
6860 \return the render target blend setting at the specified \a index.
6861 */
6862
6863/*!
6864 \fn qsizetype QRhiGraphicsPipeline::targetBlendCount() const
6865 \return the number of render target blend settings.
6866 */
6867
6868/*!
6869 \fn bool QRhiGraphicsPipeline::hasDepthTest() const
6870 \return true if depth testing is enabled.
6871 */
6872
6873/*!
6874 \fn void QRhiGraphicsPipeline::setDepthTest(bool enable)
6875
6876 Enables or disables depth testing based on \a enable. Both depth test and
6877 the writing out of depth data are disabled by default.
6878
6879 \sa setDepthWrite()
6880 */
6881
6882/*!
6883 \fn bool QRhiGraphicsPipeline::hasDepthWrite() const
6884 \return true if depth write is enabled.
6885 */
6886
6887/*!
6888 \fn void QRhiGraphicsPipeline::setDepthWrite(bool enable)
6889
6890 Controls the writing out of depth data into the depth buffer based on
6891 \a enable. By default this is disabled. Depth write is typically enabled
6892 together with the depth test.
6893
6894 \note Enabling depth write without having depth testing enabled may not
6895 lead to the desired result, and should be avoided.
6896
6897 \sa setDepthTest()
6898 */
6899
6900/*!
6901 \fn QRhiGraphicsPipeline::CompareOp QRhiGraphicsPipeline::depthOp() const
6902 \return the depth comparison function.
6903 */
6904
6905/*!
6906 \fn void QRhiGraphicsPipeline::setDepthOp(CompareOp op)
6907 Sets the depth comparison function \a op.
6908 */
6909
6910/*!
6911 \fn bool QRhiGraphicsPipeline::hasStencilTest() const
6912 \return true if stencil testing is enabled.
6913 */
6914
6915/*!
6916 \fn void QRhiGraphicsPipeline::setStencilTest(bool enable)
6917 Enables or disables stencil tests based on \a enable.
6918 By default this is disabled.
6919 */
6920
6921/*!
6922 \fn QRhiGraphicsPipeline::StencilOpState QRhiGraphicsPipeline::stencilFront() const
6923 \return the current stencil test state for front faces.
6924 */
6925
6926/*!
6927 \fn void QRhiGraphicsPipeline::setStencilFront(const StencilOpState &state)
6928 Sets the stencil test \a state for front faces.
6929 */
6930
6931/*!
6932 \fn QRhiGraphicsPipeline::StencilOpState QRhiGraphicsPipeline::stencilBack() const
6933 \return the current stencil test state for back faces.
6934 */
6935
6936/*!
6937 \fn void QRhiGraphicsPipeline::setStencilBack(const StencilOpState &state)
6938 Sets the stencil test \a state for back faces.
6939 */
6940
6941/*!
6942 \fn quint32 QRhiGraphicsPipeline::stencilReadMask() const
6943 \return the currrent stencil read mask.
6944 */
6945
6946/*!
6947 \fn void QRhiGraphicsPipeline::setStencilReadMask(quint32 mask)
6948 Sets the stencil read \a mask. The default value is 0xFF.
6949 */
6950
6951/*!
6952 \fn quint32 QRhiGraphicsPipeline::stencilWriteMask() const
6953 \return the current stencil write mask.
6954 */
6955
6956/*!
6957 \fn void QRhiGraphicsPipeline::setStencilWriteMask(quint32 mask)
6958 Sets the stencil write \a mask. The default value is 0xFF.
6959 */
6960
6961/*!
6962 \fn int QRhiGraphicsPipeline::sampleCount() const
6963 \return the currently set sample count. 1 means no multisample antialiasing.
6964 */
6965
6966/*!
6967 \fn void QRhiGraphicsPipeline::setSampleCount(int s)
6968
6969 Sets the sample count. Typical values for \a s are 1, 4, or 8. The pipeline
6970 must always be compatible with the render target, i.e. the sample counts
6971 must match.
6972
6973 \sa QRhi::supportedSampleCounts()
6974 */
6975
6976/*!
6977 \fn float QRhiGraphicsPipeline::lineWidth() const
6978 \return the currently set line width. The default is 1.0f.
6979 */
6980
6981/*!
6982 \fn void QRhiGraphicsPipeline::setLineWidth(float width)
6983
6984 Sets the line \a width. If the QRhi::WideLines feature is reported as
6985 unsupported at runtime, values other than 1.0f are ignored.
6986 */
6987
6988/*!
6989 \fn int QRhiGraphicsPipeline::depthBias() const
6990 \return the currently set depth bias.
6991 */
6992
6993/*!
6994 \fn void QRhiGraphicsPipeline::setDepthBias(int bias)
6995 Sets the depth \a bias. The default value is 0.
6996 */
6997
6998/*!
6999 \fn float QRhiGraphicsPipeline::slopeScaledDepthBias() const
7000 \return the currently set slope scaled depth bias.
7001 */
7002
7003/*!
7004 \fn void QRhiGraphicsPipeline::setSlopeScaledDepthBias(float bias)
7005 Sets the slope scaled depth \a bias. The default value is 0.
7006 */
7007
7008/*!
7009 \fn void QRhiGraphicsPipeline::setShaderStages(std::initializer_list<QRhiShaderStage> list)
7010 Sets the \a list of shader stages.
7011 */
7012
7013/*!
7014 \fn template<typename InputIterator> void QRhiGraphicsPipeline::setShaderStages(InputIterator first, InputIterator last)
7015 Sets the list of shader stages from the iterators \a first and \a last.
7016 */
7017
7018/*!
7019 \fn const QRhiShaderStage *QRhiGraphicsPipeline::cbeginShaderStages() const
7020 \return a const iterator pointing to the first item in the shader stage list.
7021 */
7022
7023/*!
7024 \fn const QRhiShaderStage *QRhiGraphicsPipeline::cendShaderStages() const
7025 \return a const iterator pointing just after the last item in the shader stage list.
7026 */
7027
7028/*!
7029 \fn const QRhiShaderStage *QRhiGraphicsPipeline::shaderStageAt(qsizetype index) const
7030 \return the shader stage at the specified \a index.
7031 */
7032
7033/*!
7034 \fn qsizetype QRhiGraphicsPipeline::shaderStageCount() const
7035 \return the number of shader stages in this pipeline.
7036 */
7037
7038/*!
7039 \fn QRhiVertexInputLayout QRhiGraphicsPipeline::vertexInputLayout() const
7040 \return the currently set vertex input layout specification.
7041 */
7042
7043/*!
7044 \fn void QRhiGraphicsPipeline::setVertexInputLayout(const QRhiVertexInputLayout &layout)
7045 Specifies the vertex input \a layout.
7046 */
7047
7048/*!
7049 \fn QRhiShaderResourceBindings *QRhiGraphicsPipeline::shaderResourceBindings() const
7050 \return the currently associated QRhiShaderResourceBindings object.
7051 */
7052
7053/*!
7054 \fn void QRhiGraphicsPipeline::setShaderResourceBindings(QRhiShaderResourceBindings *srb)
7055
7056 Associates with \a srb describing the resource binding layout and the
7057 resources (QRhiBuffer, QRhiTexture) themselves. The latter is optional,
7058 because only the layout matters during pipeline creation. Therefore, the \a
7059 srb passed in here can leave the actual buffer or texture objects
7060 unspecified (\nullptr) as long as there is another,
7061 \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible}
7062 QRhiShaderResourceBindings bound via
7063 \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} before
7064 recording the draw calls.
7065 */
7066
7067/*!
7068 \fn QRhiRenderPassDescriptor *QRhiGraphicsPipeline::renderPassDescriptor() const
7069 \return the currently set QRhiRenderPassDescriptor.
7070 */
7071
7072/*!
7073 \fn void QRhiGraphicsPipeline::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
7074 Associates with the specified QRhiRenderPassDescriptor \a desc.
7075 */
7076
7077/*!
7078 \fn int QRhiGraphicsPipeline::patchControlPointCount() const
7079 \return the currently set patch control point count.
7080 */
7081
7082/*!
7083 \fn void QRhiGraphicsPipeline::setPatchControlPointCount(int count)
7084
7085 Sets the number of patch control points to \a count. The default value is
7086 3. This is used only when the topology is set to \l Patches.
7087 */
7088
7089/*!
7090 \fn QRhiGraphicsPipeline::PolygonMode QRhiGraphicsPipeline::polygonMode() const
7091 \return the polygon mode.
7092 */
7093
7094/*!
7095 \fn void QRhiGraphicsPipeline::setPolygonMode(PolygonMode mode)
7096 Sets the polygon \a mode. The default is Fill.
7097
7098 \sa QRhi::NonFillPolygonMode
7099 */
7100
7101/*!
7102 \fn int QRhiGraphicsPipeline::multiViewCount() const
7103 \return the view count. The default is 0, indicating no multiview rendering.
7104 \since 6.7
7105 */
7106
7107/*!
7108 \fn void QRhiGraphicsPipeline::setMultiViewCount(int count)
7109 Sets the view \a count for multiview rendering. The default is 0,
7110 indicating no multiview rendering.
7111 \a count must be 2 or larger to trigger multiview rendering.
7112
7113 Multiview is only available when the \l{QRhi::MultiView}{MultiView feature}
7114 is reported as supported. The render target must be a 2D texture array, and
7115 the color attachment for the render target must have the same \a count set.
7116
7117 See QRhiColorAttachment::setMultiViewCount() for further details on
7118 multiview rendering.
7119
7120 \since 6.7
7121 \sa QRhi::MultiView, QRhiColorAttachment::setMultiViewCount()
7122 */
7123
7124/*!
7125 \class QRhiSwapChain
7126 \inmodule QtGuiPrivate
7127 \inheaderfile rhi/qrhi.h
7128 \since 6.6
7129 \brief Swapchain resource.
7130
7131 A swapchain enables presenting rendering results to a surface. A swapchain
7132 is typically backed by a set of color buffers. Of these, one is displayed
7133 at a time.
7134
7135 Below is a typical pattern for creating and managing a swapchain and some
7136 associated resources in order to render onto a QWindow:
7137
7138 \code
7139 void init()
7140 {
7141 sc = rhi->newSwapChain();
7142 ds = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil,
7143 QSize(), // no need to set the size here due to UsedWithSwapChainOnly
7144 1,
7145 QRhiRenderBuffer::UsedWithSwapChainOnly);
7146 sc->setWindow(window);
7147 sc->setDepthStencil(ds);
7148 rp = sc->newCompatibleRenderPassDescriptor();
7149 sc->setRenderPassDescriptor(rp);
7150 resizeSwapChain();
7151 }
7152
7153 void resizeSwapChain()
7154 {
7155 hasSwapChain = sc->createOrResize();
7156 }
7157
7158 void render()
7159 {
7160 if (!hasSwapChain || notExposed)
7161 return;
7162
7163 if (sc->currentPixelSize() != sc->surfacePixelSize() || newlyExposed) {
7164 resizeSwapChain();
7165 if (!hasSwapChain)
7166 return;
7167 newlyExposed = false;
7168 }
7169
7170 rhi->beginFrame(sc);
7171 // ...
7172 rhi->endFrame(sc);
7173 }
7174 \endcode
7175
7176 Avoid relying on QWindow resize events to resize swapchains, especially
7177 considering that surface sizes may not always fully match the QWindow
7178 reported dimensions. The safe, cross-platform approach is to do the check
7179 via surfacePixelSize() whenever starting a new frame.
7180
7181 Releasing the swapchain must happen while the QWindow and the underlying
7182 native window is fully up and running. Building on the previous example:
7183
7184 \code
7185 void releaseSwapChain()
7186 {
7187 if (hasSwapChain) {
7188 sc->destroy();
7189 hasSwapChain = false;
7190 }
7191 }
7192
7193 // assuming Window is our QWindow subclass
7194 bool Window::event(QEvent *e)
7195 {
7196 switch (e->type()) {
7197 case QEvent::UpdateRequest: // for QWindow::requestUpdate()
7198 render();
7199 break;
7200 case QEvent::PlatformSurface:
7201 if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)
7202 releaseSwapChain();
7203 break;
7204 default:
7205 break;
7206 }
7207 return QWindow::event(e);
7208 }
7209 \endcode
7210
7211 Initializing the swapchain and starting to render the first frame cannot
7212 start at any time. The safe, cross-platform approach is to rely on expose
7213 events. QExposeEvent is a loosely specified event that is sent whenever a
7214 window gets mapped, obscured, and resized, depending on the platform.
7215
7216 \code
7217 void Window::exposeEvent(QExposeEvent *)
7218 {
7219 // initialize and start rendering when the window becomes usable for graphics purposes
7220 if (isExposed() && !running) {
7221 running = true;
7222 init();
7223 }
7224
7225 // stop pushing frames when not exposed or size becomes 0
7226 if ((!isExposed() || (hasSwapChain && sc->surfacePixelSize().isEmpty())) && running)
7227 notExposed = true;
7228
7229 // continue when exposed again and the surface has a valid size
7230 if (isExposed() && running && notExposed && !sc->surfacePixelSize().isEmpty()) {
7231 notExposed = false;
7232 newlyExposed = true;
7233 }
7234
7235 if (isExposed() && !sc->surfacePixelSize().isEmpty())
7236 render();
7237 }
7238 \endcode
7239
7240 Once the rendering has started, a simple way to request a new frame is
7241 QWindow::requestUpdate(). While on some platforms this is merely a small
7242 timer, on others it has a specific implementation: for instance on macOS or
7243 iOS it may be backed by
7244 \l{https://developer.apple.com/documentation/corevideo/cvdisplaylink?language=objc}{CVDisplayLink}.
7245 The example above is already prepared for update requests by handling
7246 QEvent::UpdateRequest.
7247
7248 While acting as a QRhiRenderTarget, QRhiSwapChain also manages a
7249 QRhiCommandBuffer. Calling QRhi::endFrame() submits the recorded commands
7250 and also enqueues a \c present request. The default behavior is to do this
7251 with a swap interval of 1, meaning synchronizing to the display's vertical
7252 refresh is enabled. Thus the rendering thread calling beginFrame() and
7253 endFrame() will get throttled to vsync. On some backends this can be
7254 disabled by passing QRhiSwapChain:NoVSync in flags().
7255
7256 Multisampling (MSAA) is handled transparently to the applications when
7257 requested via setSampleCount(). Where applicable, QRhiSwapChain will take
7258 care of creating additional color buffers and issuing a multisample resolve
7259 command at the end of a frame. For OpenGL, it is necessary to request the
7260 appropriate sample count also via QSurfaceFormat, by calling
7261 QSurfaceFormat::setDefaultFormat() before initializing the QRhi.
7262
7263 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
7264 for details.
7265 */
7266
7267/*!
7268 \enum QRhiSwapChain::Flag
7269 Flag values to describe swapchain properties
7270
7271 \value SurfaceHasPreMulAlpha Indicates that the target surface has
7272 transparency with premultiplied alpha. For example, this is what Qt Quick
7273 uses when the alpha channel is enabled on the target QWindow, because the
7274 scenegraph rendrerer always outputs fragments with alpha multiplied into
7275 the red, green, and blue values. To ensure identical behavior across
7276 platforms, always set QSurfaceFormat::alphaBufferSize() to a non-zero value
7277 on the target QWindow whenever this flag is set on the swapchain.
7278
7279 \value SurfaceHasNonPreMulAlpha Indicates the target surface has
7280 transparency with non-premultiplied alpha. Be aware that this may not be
7281 supported on some systems, if the system compositor always expects content
7282 with premultiplied alpha. In that case the behavior with this flag set is
7283 expected to be equivalent to SurfaceHasPreMulAlpha.
7284
7285 \value sRGB Requests to pick an sRGB format for the swapchain's color
7286 buffers and/or render target views, where applicable. Note that this
7287 implies that sRGB framebuffer update and blending will get enabled for all
7288 content targeting this swapchain, and opting out is not possible. For
7289 OpenGL, set \l{QSurfaceFormat::sRGBColorSpace}{sRGBColorSpace} on the
7290 QSurfaceFormat of the QWindow in addition. Applicable only when the
7291 swapchain format is set to QRhiSwapChain::SDR.
7292
7293 \value UsedAsTransferSource Indicates the swapchain will be used as the
7294 source of a readback in QRhiResourceUpdateBatch::readBackTexture().
7295
7296 \value NoVSync Requests disabling waiting for vertical sync, also avoiding
7297 throttling the rendering thread. The behavior is backend specific and
7298 applicable only where it is possible to control this. Some may ignore the
7299 request altogether. For OpenGL, try instead setting the swap interval to 0
7300 on the QWindow via QSurfaceFormat::setSwapInterval().
7301
7302 \value MinimalBufferCount Requests creating the swapchain with the minimum
7303 number of buffers, which is in practice 2, unless the graphics
7304 implementation has a higher minimum number than that. Only applicable with
7305 backends where such control is available via the graphics API, for example,
7306 Vulkan. By default it is up to the backend to decide what number of buffers
7307 it requests (in practice this is almost always either 2 or 3), and it is
7308 not the applications' concern. However, on Vulkan for instance the backend
7309 will likely prefer the higher number (3), for example to avoid odd
7310 performance issues with some Vulkan implementations on mobile devices. It
7311 could be that on some platforms it can prove to be beneficial to force the
7312 lower buffer count (2), so this flag allows forcing that. Note that all
7313 this has no effect on the number of frames kept in flight, so the CPU
7314 (QRhi) will still prepare frames at most \c{N - 1} frames ahead of the GPU,
7315 even when the swapchain image buffer count larger than \c N. (\c{N} =
7316 QRhi::FramesInFlight and typically 2).
7317 */
7318
7319/*!
7320 \enum QRhiSwapChain::Format
7321 Describes the swapchain format. The default format is SDR.
7322
7323 This enum is used with
7324 \l{QRhiSwapChain::isFormatSupported()}{isFormatSupported()} to check
7325 upfront if creating the swapchain with the given format is supported by the
7326 platform and the window's associated screen, and with
7327 \l{QRhiSwapChain::setFormat()}{setFormat()}
7328 to set the requested format in the swapchain before calling
7329 \l{QRhiSwapChain::createOrResize()}{createOrResize()} for the first time.
7330
7331 \value SDR 8-bit RGBA or BGRA, depending on the backend and platform. With
7332 OpenGL ES in particular, it could happen that the platform provides less
7333 than 8 bits (e.g. due to EGL and the QSurfaceFormat choosing a 565 or 444
7334 format - this is outside the control of QRhi). Standard dynamic range. May
7335 be combined with setting the QRhiSwapChain::sRGB flag.
7336
7337 \value HDRExtendedSrgbLinear 16-bit float RGBA, high dynamic range,
7338 extended linear sRGB (scRGB) color space. This involves Rec. 709 primaries
7339 (same as SDR/sRGB) and linear colors. Conversion to the display's native
7340 color space (such as, HDR10) is performed by the windowing system. On
7341 Windows this is the canonical color space of the system compositor, and is
7342 the recommended format for HDR swapchains in general on desktop platforms.
7343
7344 \value HDR10 10-bit unsigned int RGB or BGR with 2 bit alpha, high dynamic
7345 range, HDR10 (Rec. 2020) color space with an ST2084 PQ transfer function.
7346
7347 \value HDRExtendedDisplayP3Linear 16-bit float RGBA, high dynamic range,
7348 extended linear Display P3 color space. The primary choice for HDR on
7349 platforms such as iOS and VisionOS.
7350 */
7351
7352/*!
7353 \internal
7354 */
7355QRhiSwapChain::QRhiSwapChain(QRhiImplementation *rhi)
7356 : QRhiResource(rhi)
7357{
7358}
7359
7360/*!
7361 \return the resource type.
7362 */
7363QRhiResource::Type QRhiSwapChain::resourceType() const
7364{
7365 return SwapChain;
7366}
7367
7368/*!
7369 \fn QSize QRhiSwapChain::currentPixelSize() const
7370
7371 \return the size with which the swapchain was last successfully built. Use
7372 this to decide if createOrResize() needs to be called again: if
7373 \c{currentPixelSize() != surfacePixelSize()} then the swapchain needs to be
7374 resized.
7375
7376 \note Typical rendering logic will call this function to get the output
7377 size when starting to prepare a new frame, and base dependent calculations
7378 (such as, the viewport) on the size returned from this function.
7379
7380 While in many cases the value is the same as \c{QWindow::size() *
7381 QWindow::devicePixelRatio()}, relying on the QWindow-reported size is not
7382 guaranteed to be correct on all platforms and graphics API implementations.
7383 Using this function is therefore strongly recommended whenever there is a
7384 need to identify the dimensions, in pixels, of the output layer or surface.
7385
7386 This also has the added benefit of avoiding potential data races when QRhi
7387 is used on a dedicated rendering thread, because the need to call QWindow
7388 functions, that may then access data updated on the main thread, is
7389 avoided.
7390
7391 \sa surfacePixelSize()
7392 */
7393
7394/*!
7395 \fn virtual QSize QRhiSwapChain::surfacePixelSize() = 0
7396
7397 \return The size of the window's associated surface or layer.
7398
7399 \warning Do not assume this is the same as \c{QWindow::size() *
7400 QWindow::devicePixelRatio()}. With some graphics APIs and windowing system
7401 interfaces (for example, Vulkan) there is a theoretical possibility for a
7402 surface to assume a size different from the associated window. To support
7403 these cases, \b{rendering logic must always base size-derived calculations
7404 (such as, viewports) on the size reported from QRhiSwapChain, and never on
7405 the size queried from QWindow}.
7406
7407 \note \b{Can also be called before createOrResize(), if at least window() is
7408 already set. This in combination with currentPixelSize() allows to detect
7409 when a swapchain needs to be resized.} However, watch out for the fact that
7410 the size of the underlying native object (surface, layer, or similar) is
7411 "live", so whenever this function is called, it returns the latest value
7412 reported by the underlying implementation, without any atomicity guarantee.
7413 Therefore, using this function to determine pixel sizes for graphics
7414 resources that are used in a frame is strongly discouraged. Rely on
7415 currentPixelSize() instead which returns a size that is atomic and will not
7416 change between createOrResize() invocations.
7417
7418 \note For depth-stencil buffers used in combination with the swapchain's
7419 color buffers, it is strongly recommended to rely on the automatic sizing
7420 and rebuilding behavior provided by the
7421 QRhiRenderBuffer:UsedWithSwapChainOnly flag. Avoid querying the surface
7422 size via this function just to get a size that can be passed to
7423 QRhiRenderBuffer::setPixelSize() as that would suffer from the lack of
7424 atomicity as described above.
7425
7426 \sa currentPixelSize()
7427 */
7428
7429/*!
7430 \fn virtual bool QRhiSwapChain::isFormatSupported(Format f) = 0
7431
7432 \return true if the given swapchain format \a f is supported. SDR is always
7433 supported.
7434
7435 \note Can be called independently of createOrResize(), but window() must
7436 already be set. Calling without the window set may lead to unexpected
7437 results depending on the backend and platform (most likely false for any
7438 HDR format), because HDR format support is usually tied to the output
7439 (screen) to which the swapchain's associated window belongs at any given
7440 time. If the result is true for a HDR format, then creating the swapchain
7441 with that format is expected to succeed as long as the window is not moved
7442 to another screen in the meantime.
7443
7444 The main use of this function is to call it before the first
7445 createOrResize() after the window is already set. This allow the QRhi
7446 backends to perform platform or windowing system specific queries to
7447 determine if the window (and the screen it is on) is capable of true HDR
7448 output with the specified format.
7449
7450 When the format is reported as supported, call setFormat() to set the
7451 requested format and call createOrResize(). Be aware of the consequences
7452 however: successfully requesting a HDR format will involve having to deal
7453 with a different color space, possibly doing white level correction for
7454 non-HDR-aware content, adjusting tonemapping methods, adjusting offscreen
7455 render target settings, etc.
7456
7457 \sa setFormat()
7458 */
7459
7460/*!
7461 \fn virtual QRhiCommandBuffer *QRhiSwapChain::currentFrameCommandBuffer() = 0
7462
7463 \return a command buffer on which rendering commands and resource updates
7464 can be recorded within a \l{QRhi::beginFrame()}{beginFrame} -
7465 \l{QRhi::endFrame()}{endFrame} block, assuming beginFrame() was called with
7466 this swapchain.
7467
7468 \note The returned object is valid also after endFrame(), up until the next
7469 beginFrame(), but the returned command buffer should not be used to record
7470 any commands then. Rather, it can be used to query data collected during
7471 the frame (or previous frames), for example by calling
7472 \l{QRhiCommandBuffer::lastCompletedGpuTime()}{lastCompletedGpuTime()}.
7473
7474 \note The value must not be cached and reused between frames. The caller
7475 should not hold on to the returned object once
7476 \l{QRhi::beginFrame()}{beginFrame()} is called again. Instead, the command
7477 buffer object should be queried again by calling this function.
7478*/
7479
7480/*!
7481 \fn virtual QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget() = 0
7482
7483 \return a render target that can used with beginPass() in order to render
7484 the swapchain's current backbuffer. Only valid within a
7485 QRhi::beginFrame() - QRhi::endFrame() block where beginFrame() was called
7486 with this swapchain.
7487
7488 \note the value must not be cached and reused between frames
7489 */
7490
7491/*!
7492 \enum QRhiSwapChain::StereoTargetBuffer
7493 Selects the backbuffer to use with a stereoscopic swapchain.
7494
7495 \value LeftBuffer
7496 \value RightBuffer
7497 */
7498
7499/*!
7500 \return a render target that can be used with beginPass() in order to
7501 render to the swapchain's left or right backbuffer. This overload should be
7502 used only with stereoscopic rendering, that is, when the associated QWindow
7503 is backed by two color buffers, one for each eye, instead of just one.
7504
7505 When stereoscopic rendering is not supported, the return value will be
7506 the default target. It is supported by all hardware backends except for Metal, in
7507 combination with \l QSurfaceFormat::StereoBuffers, assuming it is supported
7508 by the graphics and display driver stack at run time. Metal and Null backends
7509 are going to return the default render target from this overload.
7510
7511 \note the value must not be cached and reused between frames
7512 */
7513QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
7514{
7515 Q_UNUSED(targetBuffer);
7516 return currentFrameRenderTarget();
7517}
7518
7519/*!
7520 \fn virtual bool QRhiSwapChain::createOrResize() = 0
7521
7522 Creates the swapchain if not already done and resizes the swapchain buffers
7523 to match the current size of the targeted surface. Call this whenever the
7524 size of the target surface is different than before.
7525
7526 \note call destroy() only when the swapchain needs to be released
7527 completely, typically upon
7528 QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed. To perform resizing, just
7529 call createOrResize().
7530
7531 \return \c true when successful, \c false when a graphics operation failed.
7532 Regardless of the return value, calling destroy() is always safe.
7533 */
7534
7535/*!
7536 \fn QWindow *QRhiSwapChain::window() const
7537 \return the currently set window.
7538 */
7539
7540/*!
7541 \fn void QRhiSwapChain::setWindow(QWindow *window)
7542 Sets the \a window.
7543 */
7544
7545/*!
7546 \fn QRhiSwapChainProxyData QRhiSwapChain::proxyData() const
7547 \return the currently set proxy data.
7548 */
7549
7550/*!
7551 \fn void QRhiSwapChain::setProxyData(const QRhiSwapChainProxyData &d)
7552 Sets the proxy data \a d.
7553
7554 \sa QRhi::updateSwapChainProxyData()
7555 */
7556
7557/*!
7558 \fn QRhiSwapChain::Flags QRhiSwapChain::flags() const
7559 \return the currently set flags.
7560 */
7561
7562/*!
7563 \fn void QRhiSwapChain::setFlags(Flags f)
7564 Sets the flags \a f.
7565 */
7566
7567/*!
7568 \fn QRhiSwapChain::Format QRhiSwapChain::format() const
7569 \return the currently set format.
7570 */
7571
7572/*!
7573 \fn void QRhiSwapChain::setFormat(Format f)
7574 Sets the format \a f.
7575
7576 Avoid setting formats that are reported as unsupported from
7577 isFormatSupported(). Note that support for a given format may depend on the
7578 screen the swapchain's associated window is opened on. On some platforms,
7579 such as Windows and macOS, for HDR output to work it is necessary to have
7580 HDR output enabled in the display settings.
7581
7582 See isFormatSupported(), \l QRhiSwapChainHdrInfo, and \l Format for more
7583 information on high dynamic range output.
7584 */
7585
7586/*!
7587 \fn QRhiRenderBuffer *QRhiSwapChain::depthStencil() const
7588 \return the currently associated renderbuffer for depth-stencil.
7589 */
7590
7591/*!
7592 \fn void QRhiSwapChain::setDepthStencil(QRhiRenderBuffer *ds)
7593 Sets the renderbuffer \a ds for use as a depth-stencil buffer.
7594 */
7595
7596/*!
7597 \fn int QRhiSwapChain::sampleCount() const
7598 \return the currently set sample count. 1 means no multisample antialiasing.
7599 */
7600
7601/*!
7602 \fn void QRhiSwapChain::setSampleCount(int samples)
7603
7604 Sets the sample count. Common values for \a samples are 1 (no MSAA), 4 (4x
7605 MSAA), or 8 (8x MSAA).
7606
7607 \sa QRhi::supportedSampleCounts()
7608 */
7609
7610/*!
7611 \fn QRhiRenderPassDescriptor *QRhiSwapChain::renderPassDescriptor() const
7612 \return the currently associated QRhiRenderPassDescriptor object.
7613 */
7614
7615/*!
7616 \fn void QRhiSwapChain::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
7617 Associates with the QRhiRenderPassDescriptor \a desc.
7618 */
7619
7620/*!
7621 \fn virtual QRhiRenderPassDescriptor *QRhiSwapChain::newCompatibleRenderPassDescriptor() = 0;
7622
7623 \return a new QRhiRenderPassDescriptor that is compatible with this swapchain.
7624
7625 The returned value is used in two ways: it can be passed to
7626 setRenderPassDescriptor() and
7627 QRhiGraphicsPipeline::setRenderPassDescriptor(). A render pass descriptor
7628 describes the attachments (color, depth/stencil) and the load/store
7629 behavior that can be affected by flags(). A QRhiGraphicsPipeline can only
7630 be used in combination with a swapchain that has a
7631 \l{QRhiRenderPassDescriptor::isCompatible()}{compatible}
7632 QRhiRenderPassDescriptor set.
7633
7634 \sa createOrResize()
7635 */
7636
7637/*!
7638 \struct QRhiSwapChainHdrInfo
7639 \inmodule QtGuiPrivate
7640 \inheaderfile rhi/qrhi.h
7641 \since 6.6
7642
7643 \brief Describes the high dynamic range related information of the
7644 swapchain's associated output.
7645
7646 To perform HDR-compatible tonemapping, where the target range is not [0,1],
7647 one often needs to know the maximum luminance of the display the
7648 swapchain's window is associated with. While this is often made
7649 user-configurable (think brightness, gamma and similar settings in games),
7650 it can be highly useful to set defaults based on the values reported by the
7651 display itself, thus providing a decent starting point.
7652
7653 There are some problems however: the information is exposed in different
7654 forms on different platforms, whereas with cross-platform graphics APIs
7655 there is often no associated solution at all, because managing such
7656 information is not in the scope of the API (and may rather be retrievable
7657 via other platform-specific means, if any).
7658
7659 With Metal on macOS/iOS, there is no luminance values exposed in the
7660 platform APIs. Instead, the maximum color component value, that would be
7661 1.0 in a non-HDR setup, is provided. The \c limitsType field indicates what
7662 kind of information is available. It is then up to the clients of QRhi to
7663 access the correct data from the \c limits union and use it as they see
7664 fit.
7665
7666 With an API like Vulkan, where there is no way to get such information, the
7667 values are always the built-in defaults.
7668
7669 Therefore, the struct returned from QRhiSwapChain::hdrInfo() contains
7670 either some hard-coded defaults or real values received from an API such as
7671 DXGI (IDXGIOutput6) or Cocoa (NSScreen). When no platform queries are
7672 available (or needs using platform facilities out of scope for QRhi), the
7673 hard-coded defaults are a maximum luminance of 1000 nits and an SDR white
7674 level of 200.
7675
7676 The struct also exposes the presumed luminance behavior of the platform and
7677 its compositor, to indicate what a color component value of 1.0 is treated
7678 as in a HDR color buffer. In some cases it will be necessary to perform
7679 color correction of non-HDR content composited with HDR content. To enable
7680 this, the SDR white level is queried from the system on some platforms
7681 (Windows) and exposed here.
7682
7683 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
7684 for details.
7685
7686 \sa QRhiSwapChain::hdrInfo()
7687 */
7688
7689/*!
7690 \enum QRhiSwapChainHdrInfo::LimitsType
7691
7692 \value LuminanceInNits Indicates that the \l limits union has its
7693 \c luminanceInNits struct set
7694
7695 \value ColorComponentValue Indicates that the \l limits union has its
7696 \c colorComponentValue struct set
7697*/
7698
7699/*!
7700 \enum QRhiSwapChainHdrInfo::LuminanceBehavior
7701
7702 \value SceneReferred Indicates that the color value of 1.0 is interpreted
7703 as 80 nits. This is the behavior of HDR-enabled windows with the Windows
7704 compositor. See
7705 \l{https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range}{this
7706 page} for more information on HDR on Windows.
7707
7708 \value DisplayReferred Indicates that the color value of 1.0 is interpreted
7709 as the value of the SDR white. (which can be e.g. 200 nits, but will vary
7710 depending on screen brightness) This is the behavior of HDR-enabled windows
7711 on Apple platforms. See
7712 \l{https://developer.apple.com/documentation/metal/hdr_content/displaying_hdr_content_in_a_metal_layer}{this
7713 page} for more information on Apple's EDR system.
7714*/
7715
7716/*!
7717 \variable QRhiSwapChainHdrInfo::limitsType
7718
7719 With Metal on macOS/iOS, there is no luminance values exposed in the
7720 platform APIs. Instead, the maximum color component value, that would be
7721 1.0 in a non-HDR setup, is provided. This value indicates what kind of
7722 information is available in \l limits.
7723
7724 \sa QRhiSwapChain::hdrInfo()
7725*/
7726
7727/*!
7728 \variable QRhiSwapChainHdrInfo::limits
7729
7730 Contains the actual values queried from the graphics API or the platform.
7731 The type of data is indicated by \l limitsType. This is therefore a union.
7732 There are currently two options:
7733
7734 Luminance values in nits:
7735
7736 \code
7737 struct {
7738 float minLuminance;
7739 float maxLuminance;
7740 } luminanceInNits;
7741 \endcode
7742
7743 On Windows the minimum and maximum luminance depends on the screen
7744 brightness. While not relevant for desktops, on laptops the screen
7745 brightness may change at any time. Increasing brightness implies decreased
7746 maximum luminance. In addition, the results may also be dependent on the
7747 HDR Content Brightness set in Windows Settings' System/Display/HDR view,
7748 if there is such a setting.
7749
7750 Note however that the changes made to the laptop screen's brightness or in
7751 the system settings while the application is running are not necessarily
7752 reflected in the returned values, meaning calling hdrInfo() again may still
7753 return the same luminance range as before for the rest of the process'
7754 lifetime. The exact behavior is up to DXGI and Qt has no control over it.
7755
7756 \note The Windows compositor works in scene-referred mode for HDR content.
7757 A color component value of 1.0 corresponds to a luminance of 80 nits. When
7758 rendering non-HDR content (e.g. 2D UI elements), the correction of the
7759 white level is often necessary. (e.g., outputting the fragment color (1, 1,
7760 1) will likely lead to showing a shade of white that is too dim on-screen)
7761 See \l sdrWhiteLevel.
7762
7763 For macOS/iOS, the current maximum and potential maximum color
7764 component values are provided:
7765
7766 \code
7767 struct {
7768 float maxColorComponentValue;
7769 float maxPotentialColorComponentValue;
7770 } colorComponentValue;
7771 \endcode
7772
7773 The value may depend on the screen brightness, which on laptops means that
7774 the result may change in the next call to hdrInfo() if the brightness was
7775 changed in the meantime. The maximum screen brightness implies a maximum
7776 color value of 1.0.
7777
7778 \note Apple's EDR is display-referred. 1.0 corresponds to a luminance level
7779 of SDR white (e.g. 200 nits), the value of which varies based on the screen
7780 brightness and possibly other settings. The exact luminance value for that,
7781 or the maximum luminance of the display, are not exposed to the
7782 applications.
7783
7784 \note It has been observed that the color component values are not set to
7785 the correct larger-than-1 value right away on startup on some macOS
7786 systems, but the values tend to change during or after the first frame.
7787
7788 \sa QRhiSwapChain::hdrInfo()
7789*/
7790
7791/*!
7792 \variable QRhiSwapChainHdrInfo::luminanceBehavior
7793
7794 Describes the platform's presumed behavior with regards to color values.
7795
7796 \sa sdrWhiteLevel
7797 */
7798
7799/*!
7800 \variable QRhiSwapChainHdrInfo::sdrWhiteLevel
7801
7802 On Windows this is the dynamic SDR white level in nits. The value is
7803 dependent on the screen brightness (on laptops), and the SDR or HDR Content
7804 Brightness settings in the Windows settings' System/Display/HDR view.
7805
7806 To perform white level correction for non-HDR (SDR) content, such as 2D UI
7807 elemenents, multiply the final color with sdrWhiteLevel / 80.0 whenever
7808 \l luminanceBehavior is SceneReferred. (assuming Windows and a linear
7809 extended sRGB (scRGB) color space)
7810
7811 On other platforms the value is always a pre-defined value, 200. This may
7812 not match the system's actual SDR white level, but the value of this
7813 variable is not relevant in practice when the \l luminanceBehavior is
7814 DisplayReferred, because then the color component value of 1.0 refers to
7815 the SDR white by default.
7816
7817 \sa luminanceBehavior
7818*/
7819
7820/*!
7821 \return the HDR information for the associated display.
7822
7823 Do not assume that this is a cheap operation. Depending on the platform,
7824 this function makes various platform queries which may have a performance
7825 impact.
7826
7827 \note Can be called before createOrResize() as long as the window is
7828 \l{setWindow()}{set}.
7829
7830 \note What happens when moving a window with an initialized swapchain
7831 between displays (HDR to HDR with different characteristics, HDR to SDR,
7832 etc.) is not currently well-defined and depends heavily on the windowing
7833 system and compositor, with potentially varying behavior between platforms.
7834 Currently QRhi only guarantees that hdrInfo() returns valid data, if
7835 available, for the display to which the swapchain's associated window
7836 belonged at the time of createOrResize().
7837
7838 \sa QRhiSwapChainHdrInfo
7839 */
7840QRhiSwapChainHdrInfo QRhiSwapChain::hdrInfo()
7841{
7842 QRhiSwapChainHdrInfo info;
7843 info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits;
7844 info.limits.luminanceInNits.minLuminance = 0.0f;
7845 info.limits.luminanceInNits.maxLuminance = 1000.0f;
7846 info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred;
7847 info.sdrWhiteLevel = 200.0f;
7848 return info;
7849}
7850
7851#ifndef QT_NO_DEBUG_STREAM
7852QDebug operator<<(QDebug dbg, const QRhiSwapChainHdrInfo &info)
7853{
7854 QDebugStateSaver saver(dbg);
7855 dbg.nospace() << "QRhiSwapChainHdrInfo(";
7856 switch (info.limitsType) {
7857 case QRhiSwapChainHdrInfo::LuminanceInNits:
7858 dbg.nospace() << " minLuminance=" << info.limits.luminanceInNits.minLuminance
7859 << " maxLuminance=" << info.limits.luminanceInNits.maxLuminance;
7860 break;
7861 case QRhiSwapChainHdrInfo::ColorComponentValue:
7862 dbg.nospace() << " maxColorComponentValue=" << info.limits.colorComponentValue.maxColorComponentValue;
7863 dbg.nospace() << " maxPotentialColorComponentValue=" << info.limits.colorComponentValue.maxPotentialColorComponentValue;
7864 break;
7865 }
7866 switch (info.luminanceBehavior) {
7867 case QRhiSwapChainHdrInfo::SceneReferred:
7868 dbg.nospace() << " scene-referred, SDR white level=" << info.sdrWhiteLevel;
7869 break;
7870 case QRhiSwapChainHdrInfo::DisplayReferred:
7871 dbg.nospace() << " display-referred";
7872 break;
7873 }
7874 dbg.nospace() << ')';
7875 return dbg;
7876}
7877#endif
7878
7879/*!
7880 \class QRhiComputePipeline
7881 \inmodule QtGuiPrivate
7882 \inheaderfile rhi/qrhi.h
7883 \since 6.6
7884 \brief Compute pipeline state resource.
7885
7886 \note Setting the shader resource bindings is mandatory. The referenced
7887 QRhiShaderResourceBindings must already have created() called on it by the
7888 time create() is called.
7889
7890 \note Setting the shader is mandatory.
7891
7892 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
7893 for details.
7894 */
7895
7896/*!
7897 \enum QRhiComputePipeline::Flag
7898
7899 Flag values for describing pipeline options.
7900
7901 \value CompileShadersWithDebugInfo Requests compiling shaders with debug
7902 information enabled, when applicable. See
7903 QRhiGraphicsPipeline::CompileShadersWithDebugInfo for more information.
7904 */
7905
7906/*!
7907 \return the resource type.
7908 */
7909QRhiResource::Type QRhiComputePipeline::resourceType() const
7910{
7911 return ComputePipeline;
7912}
7913
7914/*!
7915 \internal
7916 */
7917QRhiComputePipeline::QRhiComputePipeline(QRhiImplementation *rhi)
7918 : QRhiResource(rhi)
7919{
7920}
7921
7922/*!
7923 \fn QRhiComputePipeline::Flags QRhiComputePipeline::flags() const
7924 \return the currently set flags.
7925 */
7926
7927/*!
7928 \fn void QRhiComputePipeline::setFlags(Flags f)
7929 Sets the flags \a f.
7930 */
7931
7932/*!
7933 \fn QRhiShaderStage QRhiComputePipeline::shaderStage() const
7934 \return the currently set shader.
7935 */
7936
7937/*!
7938 \fn void QRhiComputePipeline::setShaderStage(const QRhiShaderStage &stage)
7939
7940 Sets the shader to use. \a stage can only refer to the
7941 \l{QRhiShaderStage::Compute}{compute stage}.
7942 */
7943
7944/*!
7945 \fn QRhiShaderResourceBindings *QRhiComputePipeline::shaderResourceBindings() const
7946 \return the currently associated QRhiShaderResourceBindings object.
7947 */
7948
7949/*!
7950 \fn void QRhiComputePipeline::setShaderResourceBindings(QRhiShaderResourceBindings *srb)
7951
7952 Associates with \a srb describing the resource binding layout and the
7953 resources (QRhiBuffer, QRhiTexture) themselves. The latter is optional. As
7954 with graphics pipelines, the \a srb passed in here can leave the actual
7955 buffer or texture objects unspecified (\nullptr) as long as there is
7956 another,
7957 \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible}
7958 QRhiShaderResourceBindings bound via
7959 \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} before
7960 recording the dispatch call.
7961 */
7962
7963/*!
7964 \class QRhiCommandBuffer
7965 \inmodule QtGuiPrivate
7966 \inheaderfile rhi/qrhi.h
7967 \since 6.6
7968 \brief Command buffer resource.
7969
7970 Not creatable by applications at the moment. The only ways to obtain a
7971 valid QRhiCommandBuffer are to get it from the targeted swapchain via
7972 QRhiSwapChain::currentFrameCommandBuffer(), or, in case of rendering
7973 completely offscreen, initializing one via QRhi::beginOffscreenFrame().
7974
7975 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
7976 for details.
7977 */
7978
7979/*!
7980 \enum QRhiCommandBuffer::IndexFormat
7981 Specifies the index data type
7982
7983 \value IndexUInt16 Unsigned 16-bit (quint16)
7984 \value IndexUInt32 Unsigned 32-bit (quint32)
7985 */
7986
7987/*!
7988 \enum QRhiCommandBuffer::BeginPassFlag
7989 Flag values for QRhi::beginPass()
7990
7991 \value ExternalContent Specifies that there will be a call to
7992 QRhiCommandBuffer::beginExternal() in this pass. Some backends, Vulkan in
7993 particular, will fail if this flag is not set and beginExternal() is still
7994 called.
7995
7996 \value DoNotTrackResourcesForCompute Specifies that there is no need to
7997 track resources used in this pass if the only purpose of such tracking is
7998 to generate barriers for compute. Implies that there are no compute passes
7999 in the frame. This is an optimization hint that may be taken into account
8000 by certain backends, OpenGL in particular, allowing them to skip certain
8001 operations. When this flag is set for a render pass in a frame, calling
8002 \l{QRhiCommandBuffer::beginComputePass()}{beginComputePass()} in that frame
8003 may lead to unexpected behavior, depending on the resource dependencies
8004 between the render and compute passes.
8005 */
8006
8007/*!
8008 \typedef QRhiCommandBuffer::DynamicOffset
8009
8010 Synonym for QPair<int, quint32>. The first entry is the binding, the second
8011 is the offset in the buffer.
8012*/
8013
8014/*!
8015 \typedef QRhiCommandBuffer::VertexInput
8016
8017 Synonym for QPair<QRhiBuffer *, quint32>. The second entry is an offset in
8018 the buffer specified by the first.
8019*/
8020
8021/*!
8022 \internal
8023 */
8024QRhiCommandBuffer::QRhiCommandBuffer(QRhiImplementation *rhi)
8025 : QRhiResource(rhi)
8026{
8027}
8028
8029/*!
8030 \return the resource type.
8031 */
8032QRhiResource::Type QRhiCommandBuffer::resourceType() const
8033{
8034 return CommandBuffer;
8035}
8036
8037static const char *resourceTypeStr(const QRhiResource *res)
8038{
8039 switch (res->resourceType()) {
8040 case QRhiResource::Buffer:
8041 return "Buffer";
8042 case QRhiResource::Texture:
8043 return "Texture";
8044 case QRhiResource::Sampler:
8045 return "Sampler";
8046 case QRhiResource::RenderBuffer:
8047 return "RenderBuffer";
8048 case QRhiResource::RenderPassDescriptor:
8049 return "RenderPassDescriptor";
8050 case QRhiResource::SwapChainRenderTarget:
8051 return "SwapChainRenderTarget";
8052 case QRhiResource::TextureRenderTarget:
8053 return "TextureRenderTarget";
8054 case QRhiResource::ShaderResourceBindings:
8055 return "ShaderResourceBindings";
8056 case QRhiResource::GraphicsPipeline:
8057 return "GraphicsPipeline";
8058 case QRhiResource::SwapChain:
8059 return "SwapChain";
8060 case QRhiResource::ComputePipeline:
8061 return "ComputePipeline";
8062 case QRhiResource::CommandBuffer:
8063 return "CommandBuffer";
8064 }
8065
8066 Q_UNREACHABLE_RETURN("");
8067}
8068
8069QRhiImplementation::~QRhiImplementation()
8070{
8071 qDeleteAll(c: resUpdPool);
8072
8073 // Be nice and show something about leaked stuff. Though we may not get
8074 // this far with some backends where the allocator or the api may check
8075 // and freak out for unfreed graphics objects in the derived dtor already.
8076#ifndef QT_NO_DEBUG
8077 // debug builds: just do it always
8078 static bool leakCheck = true;
8079#else
8080 // release builds: opt-in
8081 static bool leakCheck = qEnvironmentVariableIntValue("QT_RHI_LEAK_CHECK");
8082#endif
8083 if (!resources.isEmpty()) {
8084 if (leakCheck) {
8085 qWarning(msg: "QRhi %p going down with %d unreleased resources that own native graphics objects. This is not nice.",
8086 q, int(resources.size()));
8087 }
8088 for (auto it = resources.cbegin(), end = resources.cend(); it != end; ++it) {
8089 QRhiResource *res = it.key();
8090 const bool ownsNativeResources = it.value();
8091 if (leakCheck && ownsNativeResources)
8092 qWarning(msg: " %s resource %p (%s)", resourceTypeStr(res), res, res->m_objectName.constData());
8093
8094 // Null out the resource's rhi pointer. This is why it makes sense to do null
8095 // checks in the destroy() implementations of the various resource types. It
8096 // allows to survive in bad applications that somehow manage to destroy a
8097 // resource of a QRhi after the QRhi itself.
8098 res->m_rhi = nullptr;
8099 }
8100 }
8101}
8102
8103bool QRhiImplementation::isCompressedFormat(QRhiTexture::Format format) const
8104{
8105 return (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7)
8106 || (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8)
8107 || (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12);
8108}
8109
8110void QRhiImplementation::compressedFormatInfo(QRhiTexture::Format format, const QSize &size,
8111 quint32 *bpl, quint32 *byteSize,
8112 QSize *blockDim) const
8113{
8114 int xdim = 4;
8115 int ydim = 4;
8116 quint32 blockSize = 0;
8117
8118 switch (format) {
8119 case QRhiTexture::BC1:
8120 blockSize = 8;
8121 break;
8122 case QRhiTexture::BC2:
8123 blockSize = 16;
8124 break;
8125 case QRhiTexture::BC3:
8126 blockSize = 16;
8127 break;
8128 case QRhiTexture::BC4:
8129 blockSize = 8;
8130 break;
8131 case QRhiTexture::BC5:
8132 blockSize = 16;
8133 break;
8134 case QRhiTexture::BC6H:
8135 blockSize = 16;
8136 break;
8137 case QRhiTexture::BC7:
8138 blockSize = 16;
8139 break;
8140
8141 case QRhiTexture::ETC2_RGB8:
8142 blockSize = 8;
8143 break;
8144 case QRhiTexture::ETC2_RGB8A1:
8145 blockSize = 8;
8146 break;
8147 case QRhiTexture::ETC2_RGBA8:
8148 blockSize = 16;
8149 break;
8150
8151 case QRhiTexture::ASTC_4x4:
8152 blockSize = 16;
8153 break;
8154 case QRhiTexture::ASTC_5x4:
8155 blockSize = 16;
8156 xdim = 5;
8157 break;
8158 case QRhiTexture::ASTC_5x5:
8159 blockSize = 16;
8160 xdim = ydim = 5;
8161 break;
8162 case QRhiTexture::ASTC_6x5:
8163 blockSize = 16;
8164 xdim = 6;
8165 ydim = 5;
8166 break;
8167 case QRhiTexture::ASTC_6x6:
8168 blockSize = 16;
8169 xdim = ydim = 6;
8170 break;
8171 case QRhiTexture::ASTC_8x5:
8172 blockSize = 16;
8173 xdim = 8;
8174 ydim = 5;
8175 break;
8176 case QRhiTexture::ASTC_8x6:
8177 blockSize = 16;
8178 xdim = 8;
8179 ydim = 6;
8180 break;
8181 case QRhiTexture::ASTC_8x8:
8182 blockSize = 16;
8183 xdim = ydim = 8;
8184 break;
8185 case QRhiTexture::ASTC_10x5:
8186 blockSize = 16;
8187 xdim = 10;
8188 ydim = 5;
8189 break;
8190 case QRhiTexture::ASTC_10x6:
8191 blockSize = 16;
8192 xdim = 10;
8193 ydim = 6;
8194 break;
8195 case QRhiTexture::ASTC_10x8:
8196 blockSize = 16;
8197 xdim = 10;
8198 ydim = 8;
8199 break;
8200 case QRhiTexture::ASTC_10x10:
8201 blockSize = 16;
8202 xdim = ydim = 10;
8203 break;
8204 case QRhiTexture::ASTC_12x10:
8205 blockSize = 16;
8206 xdim = 12;
8207 ydim = 10;
8208 break;
8209 case QRhiTexture::ASTC_12x12:
8210 blockSize = 16;
8211 xdim = ydim = 12;
8212 break;
8213
8214 default:
8215 Q_UNREACHABLE();
8216 break;
8217 }
8218
8219 const quint32 wblocks = uint((size.width() + xdim - 1) / xdim);
8220 const quint32 hblocks = uint((size.height() + ydim - 1) / ydim);
8221
8222 if (bpl)
8223 *bpl = wblocks * blockSize;
8224 if (byteSize)
8225 *byteSize = wblocks * hblocks * blockSize;
8226 if (blockDim)
8227 *blockDim = QSize(xdim, ydim);
8228}
8229
8230void QRhiImplementation::textureFormatInfo(QRhiTexture::Format format, const QSize &size,
8231 quint32 *bpl, quint32 *byteSize, quint32 *bytesPerPixel) const
8232{
8233 if (isCompressedFormat(format)) {
8234 compressedFormatInfo(format, size, bpl, byteSize, blockDim: nullptr);
8235 return;
8236 }
8237
8238 quint32 bpc = 0;
8239 switch (format) {
8240 case QRhiTexture::RGBA8:
8241 bpc = 4;
8242 break;
8243 case QRhiTexture::BGRA8:
8244 bpc = 4;
8245 break;
8246 case QRhiTexture::R8:
8247 bpc = 1;
8248 break;
8249 case QRhiTexture::RG8:
8250 bpc = 2;
8251 break;
8252 case QRhiTexture::R16:
8253 bpc = 2;
8254 break;
8255 case QRhiTexture::RG16:
8256 bpc = 4;
8257 break;
8258 case QRhiTexture::RED_OR_ALPHA8:
8259 bpc = 1;
8260 break;
8261
8262 case QRhiTexture::RGBA16F:
8263 bpc = 8;
8264 break;
8265 case QRhiTexture::RGBA32F:
8266 bpc = 16;
8267 break;
8268 case QRhiTexture::R16F:
8269 bpc = 2;
8270 break;
8271 case QRhiTexture::R32F:
8272 bpc = 4;
8273 break;
8274
8275 case QRhiTexture::RGB10A2:
8276 bpc = 4;
8277 break;
8278
8279 case QRhiTexture::D16:
8280 bpc = 2;
8281 break;
8282 case QRhiTexture::D24:
8283 case QRhiTexture::D24S8:
8284 case QRhiTexture::D32F:
8285 bpc = 4;
8286 break;
8287
8288 default:
8289 Q_UNREACHABLE();
8290 break;
8291 }
8292
8293 if (bpl)
8294 *bpl = uint(size.width()) * bpc;
8295 if (byteSize)
8296 *byteSize = uint(size.width() * size.height()) * bpc;
8297 if (bytesPerPixel)
8298 *bytesPerPixel = bpc;
8299}
8300
8301bool QRhiImplementation::isStencilSupportingFormat(QRhiTexture::Format format) const
8302{
8303 switch (format) {
8304 case QRhiTexture::D24S8:
8305 return true;
8306 default:
8307 break;
8308 }
8309 return false;
8310}
8311
8312bool QRhiImplementation::sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps)
8313{
8314 if (ps->cbeginShaderStages() == ps->cendShaderStages()) {
8315 qWarning(msg: "Cannot build a graphics pipeline without any stages");
8316 return false;
8317 }
8318
8319 bool hasVertexStage = false;
8320 for (auto it = ps->cbeginShaderStages(), itEnd = ps->cendShaderStages(); it != itEnd; ++it) {
8321 if (!it->shader().isValid()) {
8322 qWarning(msg: "Empty shader passed to graphics pipeline");
8323 return false;
8324 }
8325 if (it->type() == QRhiShaderStage::Vertex)
8326 hasVertexStage = true;
8327 }
8328 if (!hasVertexStage) {
8329 qWarning(msg: "Cannot build a graphics pipeline without a vertex stage");
8330 return false;
8331 }
8332
8333 if (!ps->renderPassDescriptor()) {
8334 qWarning(msg: "Cannot build a graphics pipeline without a QRhiRenderPassDescriptor");
8335 return false;
8336 }
8337
8338 if (!ps->shaderResourceBindings()) {
8339 qWarning(msg: "Cannot build a graphics pipeline without QRhiShaderResourceBindings");
8340 return false;
8341 }
8342
8343 return true;
8344}
8345
8346bool QRhiImplementation::sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb)
8347{
8348#ifndef QT_NO_DEBUG
8349 bool bindingsOk = true;
8350 const int CHECKED_BINDINGS_COUNT = 64;
8351 bool bindingSeen[CHECKED_BINDINGS_COUNT] = {};
8352 for (auto it = srb->cbeginBindings(), end = srb->cendBindings(); it != end; ++it) {
8353 const int binding = shaderResourceBindingData(binding: *it)->binding;
8354 if (binding >= CHECKED_BINDINGS_COUNT)
8355 continue;
8356 if (binding < 0) {
8357 qWarning(msg: "Invalid binding number %d", binding);
8358 bindingsOk = false;
8359 continue;
8360 }
8361 switch (shaderResourceBindingData(binding: *it)->type) {
8362 case QRhiShaderResourceBinding::UniformBuffer:
8363 if (!bindingSeen[binding]) {
8364 bindingSeen[binding] = true;
8365 } else {
8366 qWarning(msg: "Uniform buffer duplicates an existing binding number %d", binding);
8367 bindingsOk = false;
8368 }
8369 break;
8370 case QRhiShaderResourceBinding::SampledTexture:
8371 if (!bindingSeen[binding]) {
8372 bindingSeen[binding] = true;
8373 } else {
8374 qWarning(msg: "Combined image sampler duplicates an existing binding number %d", binding);
8375 bindingsOk = false;
8376 }
8377 break;
8378 case QRhiShaderResourceBinding::Texture:
8379 if (!bindingSeen[binding]) {
8380 bindingSeen[binding] = true;
8381 } else {
8382 qWarning(msg: "Texture duplicates an existing binding number %d", binding);
8383 bindingsOk = false;
8384 }
8385 break;
8386 case QRhiShaderResourceBinding::Sampler:
8387 if (!bindingSeen[binding]) {
8388 bindingSeen[binding] = true;
8389 } else {
8390 qWarning(msg: "Sampler duplicates an existing binding number %d", binding);
8391 bindingsOk = false;
8392 }
8393 break;
8394 case QRhiShaderResourceBinding::ImageLoad:
8395 case QRhiShaderResourceBinding::ImageStore:
8396 case QRhiShaderResourceBinding::ImageLoadStore:
8397 if (!bindingSeen[binding]) {
8398 bindingSeen[binding] = true;
8399 } else {
8400 qWarning(msg: "Image duplicates an existing binding number %d", binding);
8401 bindingsOk = false;
8402 }
8403 break;
8404 case QRhiShaderResourceBinding::BufferLoad:
8405 case QRhiShaderResourceBinding::BufferStore:
8406 case QRhiShaderResourceBinding::BufferLoadStore:
8407 if (!bindingSeen[binding]) {
8408 bindingSeen[binding] = true;
8409 } else {
8410 qWarning(msg: "Buffer duplicates an existing binding number %d", binding);
8411 bindingsOk = false;
8412 }
8413 break;
8414 default:
8415 qWarning(msg: "Unknown binding type %d", int(shaderResourceBindingData(binding: *it)->type));
8416 bindingsOk = false;
8417 break;
8418 }
8419 }
8420
8421 if (!bindingsOk) {
8422 qWarning() << *srb;
8423 return false;
8424 }
8425#else
8426 Q_UNUSED(srb);
8427#endif
8428 return true;
8429}
8430
8431int QRhiImplementation::effectiveSampleCount(int sampleCount) const
8432{
8433 // Stay compatible with QSurfaceFormat and friends where samples == 0 means the same as 1.
8434 const int s = qBound(min: 1, val: sampleCount, max: 64);
8435 const QList<int> supported = supportedSampleCounts();
8436 int result = 1;
8437
8438 // Stay compatible with Qt 5 in that requesting an unsupported sample count
8439 // is not an error (although we still do a categorized debug print about
8440 // this), and rather a supported value, preferably a close one, not just 1,
8441 // is used instead. This is actually deviating from Qt 5 as that performs a
8442 // clamping only and does not handle cases such as when sample count 2 is
8443 // not supported but 4 is. (OpenGL handles things like that gracefully,
8444 // other APIs may not, so improve this by picking the next largest, or in
8445 // absence of that, the largest value; this with the goal to not reduce
8446 // quality by rather picking a larger-than-requested value than a smaller one)
8447
8448 for (int i = 0, ie = supported.count(); i != ie; ++i) {
8449 // assumes the 'supported' list is sorted
8450 if (supported[i] >= s) {
8451 result = supported[i];
8452 break;
8453 }
8454 }
8455
8456 if (result != s) {
8457 if (result == 1 && !supported.isEmpty())
8458 result = supported.last();
8459 qCDebug(QRHI_LOG_INFO, "Attempted to set unsupported sample count %d, using %d instead",
8460 sampleCount, result);
8461 }
8462
8463 return result;
8464}
8465
8466/*!
8467 \internal
8468 */
8469QRhi::QRhi()
8470{
8471}
8472
8473/*!
8474 Destructor. Destroys the backend and releases resources.
8475 */
8476QRhi::~QRhi()
8477{
8478 if (!d)
8479 return;
8480
8481 runCleanup();
8482
8483 qDeleteAll(c: d->pendingDeleteResources);
8484 d->pendingDeleteResources.clear();
8485
8486 d->destroy();
8487 delete d;
8488}
8489
8490bool QRhiImplementation::rubLogEnabled = false;
8491
8492void QRhiImplementation::prepareForCreate(QRhi *rhi, QRhi::Implementation impl, QRhi::Flags flags)
8493{
8494 q = rhi;
8495
8496 // Play nice with QSG_INFO since that is still the most commonly used
8497 // way to get graphics info printed from Qt Quick apps, and the Quick
8498 // scenegraph is our primary user.
8499 if (qEnvironmentVariableIsSet(varName: "QSG_INFO"))
8500 const_cast<QLoggingCategory &>(QRHI_LOG_INFO()).setEnabled(type: QtDebugMsg, enable: true);
8501
8502 debugMarkers = flags.testFlag(flag: QRhi::EnableDebugMarkers);
8503
8504 rubLogEnabled = QRHI_LOG_RUB().isDebugEnabled();
8505
8506 implType = impl;
8507 implThread = QThread::currentThread();
8508}
8509
8510/*!
8511 \return a new QRhi instance with a backend for the graphics API specified
8512 by \a impl with the specified \a flags. \return \c nullptr if the
8513 function fails.
8514
8515 \a params must point to an instance of one of the backend-specific
8516 subclasses of QRhiInitParams, such as, QRhiVulkanInitParams,
8517 QRhiMetalInitParams, QRhiD3D11InitParams, QRhiD3D12InitParams,
8518 QRhiGles2InitParams. See these classes for examples on creating a QRhi.
8519
8520 QRhi by design does not implement any fallback logic: if the specified API
8521 cannot be initialized, create() will fail, with warnings printed on the
8522 debug output by the backends. The clients of QRhi, for example Qt Quick,
8523 may however provide additional logic that allow falling back to an API
8524 different than what was requested, depending on the platform. If the
8525 intention is just to test if initialization would succeed when calling
8526 create() at later point, it is preferable to use probe() instead of
8527 create(), because with some backends probing can be implemented in a more
8528 lightweight manner as opposed to create(), which performs full
8529 initialization of the infrastructure and is wasteful if that QRhi instance
8530 is then thrown immediately away.
8531
8532 \a importDevice allows using an already existing graphics device, without
8533 QRhi creating its own. When not null, this parameter must point to an
8534 instance of one of the subclasses of QRhiNativeHandles:
8535 QRhiVulkanNativeHandles, QRhiD3D11NativeHandles, QRhiD3D12NativeHandles,
8536 QRhiMetalNativeHandles, QRhiGles2NativeHandles. The exact details and
8537 semantics depend on the backand and the underlying graphics API.
8538
8539 \sa probe()
8540 */
8541QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRhiNativeHandles *importDevice)
8542{
8543 std::unique_ptr<QRhi> r(new QRhi);
8544
8545 switch (impl) {
8546 case Null:
8547 r->d = new QRhiNull(static_cast<QRhiNullInitParams *>(params));
8548 break;
8549 case Vulkan:
8550#if QT_CONFIG(vulkan)
8551 r->d = new QRhiVulkan(static_cast<QRhiVulkanInitParams *>(params),
8552 static_cast<QRhiVulkanNativeHandles *>(importDevice));
8553 break;
8554#else
8555 Q_UNUSED(importDevice);
8556 qWarning("This build of Qt has no Vulkan support");
8557 break;
8558#endif
8559 case OpenGLES2:
8560#ifndef QT_NO_OPENGL
8561 r->d = new QRhiGles2(static_cast<QRhiGles2InitParams *>(params),
8562 static_cast<QRhiGles2NativeHandles *>(importDevice));
8563 break;
8564#else
8565 qWarning("This build of Qt has no OpenGL support");
8566 break;
8567#endif
8568 case D3D11:
8569#ifdef Q_OS_WIN
8570 r->d = new QRhiD3D11(static_cast<QRhiD3D11InitParams *>(params),
8571 static_cast<QRhiD3D11NativeHandles *>(importDevice));
8572 break;
8573#else
8574 qWarning(msg: "This platform has no Direct3D 11 support");
8575 break;
8576#endif
8577 case Metal:
8578#if QT_CONFIG(metal)
8579 r->d = new QRhiMetal(static_cast<QRhiMetalInitParams *>(params),
8580 static_cast<QRhiMetalNativeHandles *>(importDevice));
8581 break;
8582#else
8583 qWarning(msg: "This platform has no Metal support");
8584 break;
8585#endif
8586 case D3D12:
8587#ifdef Q_OS_WIN
8588#ifdef QRHI_D3D12_AVAILABLE
8589 r->d = new QRhiD3D12(static_cast<QRhiD3D12InitParams *>(params),
8590 static_cast<QRhiD3D12NativeHandles *>(importDevice));
8591 break;
8592#else
8593 qWarning("Qt was built without Direct3D 12 support. "
8594 "This is likely due to having ancient SDK headers (such as d3d12.h) in the Qt build environment. "
8595 "Rebuild Qt with an SDK supporting D3D12 features introduced in Windows 10 version 1703, "
8596 "or use an MSVC build as those typically are built with more up-to-date SDKs.");
8597 break;
8598#endif
8599#else
8600 qWarning(msg: "This platform has no Direct3D 12 support");
8601 break;
8602#endif
8603 }
8604
8605 if (r->d) {
8606 r->d->prepareForCreate(rhi: r.get(), impl, flags);
8607 if (r->d->create(flags))
8608 return r.release();
8609 }
8610
8611 return nullptr;
8612}
8613
8614/*!
8615 \return true if create() can be expected to succeed when called the given
8616 \a impl and \a params.
8617
8618 For some backends this is equivalent to calling create(), checking its
8619 return value, and then destroying the resulting QRhi.
8620
8621 For others, in particular with Metal, there may be a specific probing
8622 implementation, which allows testing in a more lightweight manner without
8623 polluting the debug output with warnings upon failures.
8624
8625 \sa create()
8626 */
8627bool QRhi::probe(QRhi::Implementation impl, QRhiInitParams *params)
8628{
8629 bool ok = false;
8630
8631 // The only place currently where this makes sense is Metal, where the API
8632 // is simple enough so that a special probing function - doing nothing but
8633 // a MTLCreateSystemDefaultDevice - is reasonable. Elsewhere, just call
8634 // create() and then drop the result.
8635
8636 if (impl == Metal) {
8637#if QT_CONFIG(metal)
8638 ok = QRhiMetal::probe(static_cast<QRhiMetalInitParams *>(params));
8639#endif
8640 } else {
8641 QRhi *rhi = create(impl, params);
8642 ok = rhi != nullptr;
8643 delete rhi;
8644 }
8645 return ok;
8646}
8647
8648/*!
8649 \struct QRhiSwapChainProxyData
8650 \inmodule QtGuiPrivate
8651 \inheaderfile rhi/qrhi.h
8652 \since 6.6
8653
8654 \brief Opaque data describing native objects needed to set up a swapchain.
8655
8656 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
8657 for details.
8658
8659 \sa QRhi::updateSwapChainProxyData()
8660 */
8661
8662/*!
8663 Generates and returns a QRhiSwapChainProxyData struct containing opaque
8664 data specific to the backend and graphics API specified by \a impl. \a
8665 window is the QWindow a swapchain is targeting.
8666
8667 The returned struct can be passed to QRhiSwapChain::setProxyData(). This
8668 makes sense in threaded rendering systems: this static function is expected
8669 to be called on the \b{main (gui) thread}, unlike all QRhi operations, then
8670 transferred to the thread working with the QRhi and QRhiSwapChain and passed
8671 on to the swapchain. This allows doing native platform queries that are
8672 only safe to be called on the main thread, for example to query the
8673 CAMetalLayer from a NSView, and then passing on the data to the
8674 QRhiSwapChain living on the rendering thread. With the Metal example, doing
8675 the view.layer access on a dedicated rendering thread causes a warning in
8676 the Xcode Thread Checker. With the data proxy mechanism, this is avoided.
8677
8678 When threads are not involved, generating and passing on the
8679 QRhiSwapChainProxyData is not required: backends are guaranteed to be able
8680 to query whatever is needed on their own, and if everything lives on the
8681 main (gui) thread, that should be sufficient.
8682
8683 \note \a impl should match what the QRhi is created with. For example,
8684 calling with QRhi::Metal on a non-Apple platform will not generate any
8685 useful data.
8686 */
8687QRhiSwapChainProxyData QRhi::updateSwapChainProxyData(QRhi::Implementation impl, QWindow *window)
8688{
8689#if QT_CONFIG(metal)
8690 if (impl == Metal)
8691 return QRhiMetal::updateSwapChainProxyData(window);
8692#else
8693 Q_UNUSED(impl);
8694 Q_UNUSED(window);
8695#endif
8696 return {};
8697}
8698
8699/*!
8700 \return the backend type for this QRhi.
8701 */
8702QRhi::Implementation QRhi::backend() const
8703{
8704 return d->implType;
8705}
8706
8707/*!
8708 \return a friendly name for the backend \a impl, usually the name of the 3D
8709 API in use.
8710 */
8711const char *QRhi::backendName(Implementation impl)
8712{
8713 switch (impl) {
8714 case QRhi::Null:
8715 return "Null";
8716 case QRhi::Vulkan:
8717 return "Vulkan";
8718 case QRhi::OpenGLES2:
8719 return "OpenGL";
8720 case QRhi::D3D11:
8721 return "D3D11";
8722 case QRhi::Metal:
8723 return "Metal";
8724 case QRhi::D3D12:
8725 return "D3D12";
8726 }
8727
8728 Q_UNREACHABLE_RETURN("Unknown");
8729}
8730
8731/*!
8732 \return the backend type as string for this QRhi.
8733 */
8734const char *QRhi::backendName() const
8735{
8736 return backendName(impl: d->implType);
8737}
8738
8739/*!
8740 \enum QRhiDriverInfo::DeviceType
8741 Specifies the graphics device's type, when the information is available.
8742
8743 In practice this is only applicable with Vulkan and Metal. With Direct 3D
8744 11 and 12, using an adapter with the software flag set leads to the value
8745 \c CpuDevice. Otherwise, and with OpenGL, the value is always UnknownDevice.
8746
8747 \value UnknownDevice
8748 \value IntegratedDevice
8749 \value DiscreteDevice
8750 \value ExternalDevice
8751 \value VirtualDevice
8752 \value CpuDevice
8753*/
8754
8755/*!
8756 \struct QRhiDriverInfo
8757 \inmodule QtGuiPrivate
8758 \inheaderfile rhi/qrhi.h
8759 \since 6.6
8760
8761 \brief Describes the physical device, adapter, or graphics API
8762 implementation that is used by an initialized QRhi.
8763
8764 Graphics APIs offer different levels and kinds of information. The only
8765 value that is available across all APIs is the deviceName, which is a
8766 freetext description of the physical device, adapter, or is a combination
8767 of the strings reported for \c{GL_VENDOR} + \c{GL_RENDERER} +
8768 \c{GL_VERSION}. The deviceId is always 0 for OpenGL. vendorId is always 0
8769 for OpenGL and Metal. deviceType is always UnknownDevice for OpenGL and
8770 Direct 3D.
8771
8772 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
8773 for details.
8774 */
8775
8776/*!
8777 \variable QRhiDriverInfo::deviceName
8778
8779 \sa QRhi::driverInfo()
8780*/
8781
8782/*!
8783 \variable QRhiDriverInfo::deviceId
8784
8785 \sa QRhi::driverInfo()
8786*/
8787
8788/*!
8789 \variable QRhiDriverInfo::vendorId
8790
8791 \sa QRhi::driverInfo()
8792*/
8793
8794/*!
8795 \variable QRhiDriverInfo::deviceType
8796
8797 \sa QRhi::driverInfo(), QRhiDriverInfo::DeviceType
8798*/
8799
8800#ifndef QT_NO_DEBUG_STREAM
8801static inline const char *deviceTypeStr(QRhiDriverInfo::DeviceType type)
8802{
8803 switch (type) {
8804 case QRhiDriverInfo::UnknownDevice:
8805 return "Unknown";
8806 case QRhiDriverInfo::IntegratedDevice:
8807 return "Integrated";
8808 case QRhiDriverInfo::DiscreteDevice:
8809 return "Discrete";
8810 case QRhiDriverInfo::ExternalDevice:
8811 return "External";
8812 case QRhiDriverInfo::VirtualDevice:
8813 return "Virtual";
8814 case QRhiDriverInfo::CpuDevice:
8815 return "Cpu";
8816 }
8817
8818 Q_UNREACHABLE_RETURN(nullptr);
8819}
8820QDebug operator<<(QDebug dbg, const QRhiDriverInfo &info)
8821{
8822 QDebugStateSaver saver(dbg);
8823 dbg.nospace() << "QRhiDriverInfo(deviceName=" << info.deviceName
8824 << " deviceId=0x" << Qt::hex << info.deviceId
8825 << " vendorId=0x" << info.vendorId
8826 << " deviceType=" << deviceTypeStr(type: info.deviceType)
8827 << ')';
8828 return dbg;
8829}
8830#endif
8831
8832/*!
8833 \return metadata for the graphics device used by this successfully
8834 initialized QRhi instance.
8835 */
8836QRhiDriverInfo QRhi::driverInfo() const
8837{
8838 return d->driverInfo();
8839}
8840
8841/*!
8842 \return the thread on which the QRhi was \l{QRhi::create()}{initialized}.
8843 */
8844QThread *QRhi::thread() const
8845{
8846 return d->implThread;
8847}
8848
8849/*!
8850 Registers a \a callback that is invoked either when the QRhi is destroyed,
8851 or when runCleanup() is called.
8852
8853 The callback will run with the graphics resource still available, so this
8854 provides an opportunity for the application to cleanly release QRhiResource
8855 instances belonging to the QRhi. This is particularly useful for managing
8856 the lifetime of resources stored in \c cache type of objects, where the
8857 cache holds QRhiResources or objects containing QRhiResources.
8858
8859 \sa runCleanup(), ~QRhi()
8860 */
8861void QRhi::addCleanupCallback(const CleanupCallback &callback)
8862{
8863 d->addCleanupCallback(callback);
8864}
8865
8866/*!
8867 \overload
8868
8869 Registers \a callback to be invoked either when the QRhi is destroyed or
8870 when runCleanup() is called. This overload takes an opaque pointer, \a key,
8871 that is used to ensure that a given callback is registered (and so called)
8872 only once.
8873
8874 \sa removeCleanupCallback()
8875 */
8876void QRhi::addCleanupCallback(const void *key, const CleanupCallback &callback)
8877{
8878 d->addCleanupCallback(key, callback);
8879}
8880
8881/*!
8882 Deregisters the callback with \a key. If no cleanup callback was registered
8883 with \a key, the function does nothing. Callbacks registered without a key
8884 cannot be removed.
8885
8886 \sa addCleanupCallback()
8887 */
8888void QRhi::removeCleanupCallback(const void *key)
8889{
8890 d->removeCleanupCallback(key);
8891}
8892
8893/*!
8894 Invokes all registered cleanup functions. The list of cleanup callbacks it
8895 then cleared. Normally destroying the QRhi does this automatically, but
8896 sometimes it can be useful to trigger cleanup in order to release all
8897 cached, non-essential resources.
8898
8899 \sa addCleanupCallback()
8900 */
8901void QRhi::runCleanup()
8902{
8903 for (const CleanupCallback &f : std::as_const(t&: d->cleanupCallbacks))
8904 f(this);
8905
8906 d->cleanupCallbacks.clear();
8907
8908 for (auto it = d->keyedCleanupCallbacks.cbegin(), end = d->keyedCleanupCallbacks.cend(); it != end; ++it)
8909 it.value()(this);
8910
8911 d->keyedCleanupCallbacks.clear();
8912}
8913
8914/*!
8915 \class QRhiResourceUpdateBatch
8916 \inmodule QtGuiPrivate
8917 \inheaderfile rhi/qrhi.h
8918 \since 6.6
8919 \brief Records upload and copy type of operations.
8920
8921 With QRhi it is no longer possible to perform copy type of operations at
8922 arbitrary times. Instead, all such operations are recorded into batches
8923 that are then passed, most commonly, to QRhiCommandBuffer::beginPass().
8924 What then happens under the hood is hidden from the application: the
8925 underlying implementations can defer and implement these operations in
8926 various different ways.
8927
8928 A resource update batch owns no graphics resources and does not perform any
8929 actual operations on its own. It should rather be viewed as a command
8930 buffer for update, upload, and copy type of commands.
8931
8932 To get an available, empty batch from the pool, call
8933 QRhi::nextResourceUpdateBatch().
8934
8935 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
8936 for details.
8937 */
8938
8939/*!
8940 \internal
8941 */
8942QRhiResourceUpdateBatch::QRhiResourceUpdateBatch(QRhiImplementation *rhi)
8943 : d(new QRhiResourceUpdateBatchPrivate)
8944{
8945 d->q = this;
8946 d->rhi = rhi;
8947}
8948
8949QRhiResourceUpdateBatch::~QRhiResourceUpdateBatch()
8950{
8951 delete d;
8952}
8953
8954/*!
8955 \return the batch to the pool. This should only be used when the batch is
8956 not passed to one of QRhiCommandBuffer::beginPass(),
8957 QRhiCommandBuffer::endPass(), or QRhiCommandBuffer::resourceUpdate()
8958 because these implicitly call destroy().
8959
8960 \note QRhiResourceUpdateBatch instances must never by \c deleted by
8961 applications.
8962 */
8963void QRhiResourceUpdateBatch::release()
8964{
8965 d->free();
8966}
8967
8968/*!
8969 Copies all queued operations from the \a other batch into this one.
8970
8971 \note \a other may no longer contain valid data after the merge operation,
8972 and must not be submitted, but it will still need to be released by calling
8973 release().
8974
8975 This allows for a convenient pattern where resource updates that are
8976 already known during the initialization step are collected into a batch
8977 that is then merged into another when starting to first render pass later
8978 on:
8979
8980 \code
8981 void init()
8982 {
8983 initialUpdates = rhi->nextResourceUpdateBatch();
8984 initialUpdates->uploadStaticBuffer(vbuf, vertexData);
8985 initialUpdates->uploadStaticBuffer(ibuf, indexData);
8986 // ...
8987 }
8988
8989 void render()
8990 {
8991 QRhiResourceUpdateBatch *resUpdates = rhi->nextResourceUpdateBatch();
8992 if (initialUpdates) {
8993 resUpdates->merge(initialUpdates);
8994 initialUpdates->release();
8995 initialUpdates = nullptr;
8996 }
8997 // resUpdates->updateDynamicBuffer(...);
8998 cb->beginPass(rt, clearCol, clearDs, resUpdates);
8999 }
9000 \endcode
9001 */
9002void QRhiResourceUpdateBatch::merge(QRhiResourceUpdateBatch *other)
9003{
9004 d->merge(other: other->d);
9005}
9006
9007/*!
9008 \return true until the number of buffer and texture operations enqueued
9009 onto this batch is below a reasonable limit.
9010
9011 The return value is false when the number of buffer and/or texture
9012 operations added to this batch have reached, or are about to reach, a
9013 certain limit. The batch is fully functional afterwards as well, but may
9014 need to allocate additional memory. Therefore, a renderer that collects
9015 lots of buffer and texture updates in a single batch when preparing a frame
9016 may want to consider \l{QRhiCommandBuffer::resourceUpdate()}{submitting the
9017 batch} and \l{QRhi::nextResourceUpdateBatch()}{starting a new one} when
9018 this function returns false.
9019 */
9020bool QRhiResourceUpdateBatch::hasOptimalCapacity() const
9021{
9022 return d->hasOptimalCapacity();
9023}
9024
9025/*!
9026 Enqueues updating a region of a QRhiBuffer \a buf created with the type
9027 QRhiBuffer::Dynamic.
9028
9029 The region is specified \a offset and \a size. The actual bytes to write
9030 are specified by \a data which must have at least \a size bytes available.
9031 \a data can safely be destroyed or changed once this function returns.
9032
9033 \note If host writes are involved, which is the case with
9034 updateDynamicBuffer() typically as such buffers are backed by host visible
9035 memory with most backends, they may accumulate within a frame. Thus pass 1
9036 reading a region changed by a batch passed to pass 2 may see the changes
9037 specified in pass 2's update batch.
9038
9039 \note QRhi transparently manages double buffering in order to prevent
9040 stalling the graphics pipeline. The fact that a QRhiBuffer may have
9041 multiple native buffer objects underneath can be safely ignored when using
9042 the QRhi and QRhiResourceUpdateBatch.
9043 */
9044void QRhiResourceUpdateBatch::updateDynamicBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
9045{
9046 if (size > 0) {
9047 const int idx = d->activeBufferOpCount++;
9048 const int opListSize = d->bufferOps.size();
9049 if (idx < opListSize)
9050 QRhiResourceUpdateBatchPrivate::BufferOp::changeToDynamicUpdate(op: &d->bufferOps[idx], buf, offset, size, data);
9051 else
9052 d->bufferOps.append(t: QRhiResourceUpdateBatchPrivate::BufferOp::dynamicUpdate(buf, offset, size, data));
9053 }
9054}
9055
9056/*!
9057 Enqueues updating a region of a QRhiBuffer \a buf created with the type
9058 QRhiBuffer::Immutable or QRhiBuffer::Static.
9059
9060 The region is specified \a offset and \a size. The actual bytes to write
9061 are specified by \a data which must have at least \a size bytes available.
9062 \a data can safely be destroyed or changed once this function returns.
9063 */
9064void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
9065{
9066 if (size > 0) {
9067 const int idx = d->activeBufferOpCount++;
9068 if (idx < d->bufferOps.size())
9069 QRhiResourceUpdateBatchPrivate::BufferOp::changeToStaticUpload(op: &d->bufferOps[idx], buf, offset, size, data);
9070 else
9071 d->bufferOps.append(t: QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, offset, size, data));
9072 }
9073}
9074
9075/*!
9076 \overload
9077
9078 Enqueues updating the entire QRhiBuffer \a buf created with the type
9079 QRhiBuffer::Immutable or QRhiBuffer::Static.
9080 */
9081void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *data)
9082{
9083 if (buf->size() > 0) {
9084 const int idx = d->activeBufferOpCount++;
9085 if (idx < d->bufferOps.size())
9086 QRhiResourceUpdateBatchPrivate::BufferOp::changeToStaticUpload(op: &d->bufferOps[idx], buf, offset: 0, size: 0, data);
9087 else
9088 d->bufferOps.append(t: QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, offset: 0, size: 0, data));
9089 }
9090}
9091
9092/*!
9093 Enqueues reading back a region of the QRhiBuffer \a buf. The size of the
9094 region is specified by \a size in bytes, \a offset is the offset in bytes
9095 to start reading from.
9096
9097 A readback is asynchronous. \a result contains a callback that is invoked
9098 when the operation has completed. The data is provided in
9099 QRhiReadbackResult::data. Upon successful completion that QByteArray
9100 will have a size equal to \a size. On failure the QByteArray will be empty.
9101
9102 \note Reading buffers with a usage different than QRhiBuffer::UniformBuffer
9103 is supported only when the QRhi::ReadBackNonUniformBuffer feature is
9104 reported as supported.
9105
9106 \note The asynchronous readback is guaranteed to have completed when one of
9107 the following conditions is met: \l{QRhi::finish()}{finish()} has been
9108 called; or, at least \c N frames have been \l{QRhi::endFrame()}{submitted},
9109 including the frame that issued the readback operation, and the
9110 \l{QRhi::beginFrame()}{recording of a new frame} has been started, where \c
9111 N is the \l{QRhi::resourceLimit()}{resource limit value} returned for
9112 QRhi::MaxAsyncReadbackFrames.
9113
9114 \sa readBackTexture(), QRhi::isFeatureSupported(), QRhi::resourceLimit()
9115 */
9116void QRhiResourceUpdateBatch::readBackBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiReadbackResult *result)
9117{
9118 const int idx = d->activeBufferOpCount++;
9119 if (idx < d->bufferOps.size())
9120 d->bufferOps[idx] = QRhiResourceUpdateBatchPrivate::BufferOp::read(buf, offset, size, result);
9121 else
9122 d->bufferOps.append(t: QRhiResourceUpdateBatchPrivate::BufferOp::read(buf, offset, size, result));
9123}
9124
9125/*!
9126 Enqueues uploading the image data for one or more mip levels in one or more
9127 layers of the texture \a tex.
9128
9129 The details of the copy (source QImage or compressed texture data, regions,
9130 target layers and levels) are described in \a desc.
9131 */
9132void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
9133{
9134 if (desc.cbeginEntries() != desc.cendEntries()) {
9135 const int idx = d->activeTextureOpCount++;
9136 if (idx < d->textureOps.size())
9137 d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::upload(tex, desc);
9138 else
9139 d->textureOps.append(t: QRhiResourceUpdateBatchPrivate::TextureOp::upload(tex, desc));
9140 }
9141}
9142
9143/*!
9144 Enqueues uploading the image data for mip level 0 of layer 0 of the texture
9145 \a tex.
9146
9147 \a tex must have an uncompressed format. Its format must also be compatible
9148 with the QImage::format() of \a image. The source data is given in \a
9149 image.
9150 */
9151void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QImage &image)
9152{
9153 uploadTexture(tex,
9154 desc: QRhiTextureUploadEntry(0, 0, QRhiTextureSubresourceUploadDescription(image)));
9155}
9156
9157/*!
9158 Enqueues a texture-to-texture copy operation from \a src into \a dst as
9159 described by \a desc.
9160
9161 \note The source texture \a src must be created with
9162 QRhiTexture::UsedAsTransferSource.
9163
9164 \note The format of the textures must match. With most graphics
9165 APIs the data is copied as-is without any format conversions. If
9166 \a dst and \a src are created with different formats, unspecified
9167 issues may arise.
9168 */
9169void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
9170{
9171 const int idx = d->activeTextureOpCount++;
9172 if (idx < d->textureOps.size())
9173 d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::copy(dst, src, desc);
9174 else
9175 d->textureOps.append(t: QRhiResourceUpdateBatchPrivate::TextureOp::copy(dst, src, desc));
9176}
9177
9178/*!
9179 Enqueues a texture-to-host copy operation as described by \a rb.
9180
9181 Normally \a rb will specify a QRhiTexture as the source. However, when the
9182 swapchain in the current frame was created with
9183 QRhiSwapChain::UsedAsTransferSource, it can also be the source of the
9184 readback. For this, leave the texture set to null in \a rb.
9185
9186 Unlike other operations, the results here need to be processed by the
9187 application. Therefore, \a result provides not just the data but also a
9188 callback as operations on the batch are asynchronous by nature:
9189
9190 \code
9191 rhi->beginFrame(swapchain);
9192 cb->beginPass(swapchain->currentFrameRenderTarget(), colorClear, dsClear);
9193 // ...
9194 QRhiReadbackResult *rbResult = new QRhiReadbackResult;
9195 rbResult->completed = [rbResult] {
9196 {
9197 const QImage::Format fmt = QImage::Format_RGBA8888_Premultiplied; // fits QRhiTexture::RGBA8
9198 const uchar *p = reinterpret_cast<const uchar *>(rbResult->data.constData());
9199 QImage image(p, rbResult->pixelSize.width(), rbResult->pixelSize.height(), fmt);
9200 image.save("result.png");
9201 }
9202 delete rbResult;
9203 };
9204 QRhiResourceUpdateBatch *u = nextResourceUpdateBatch();
9205 QRhiReadbackDescription rb; // no texture -> uses the current backbuffer of sc
9206 u->readBackTexture(rb, rbResult);
9207 cb->endPass(u);
9208 rhi->endFrame(swapchain);
9209 \endcode
9210
9211 \note The texture must be created with QRhiTexture::UsedAsTransferSource.
9212
9213 \note Multisample textures cannot be read back.
9214
9215 \note The readback returns raw byte data, in order to allow the applications
9216 to interpret it in any way they see fit. Be aware of the blending settings
9217 of rendering code: if the blending is set up to rely on premultiplied alpha,
9218 the results of the readback must also be interpreted as Premultiplied.
9219
9220 \note When interpreting the resulting raw data, be aware that the readback
9221 happens with a byte ordered format. A \l{QRhiTexture::RGBA8}{RGBA8} texture
9222 maps therefore to byte ordered QImage formats, such as,
9223 QImage::Format_RGBA8888.
9224
9225 \note The asynchronous readback is guaranteed to have completed when one of
9226 the following conditions is met: \l{QRhi::finish()}{finish()} has been
9227 called; or, at least \c N frames have been \l{QRhi::endFrame()}{submitted},
9228 including the frame that issued the readback operation, and the
9229 \l{QRhi::beginFrame()}{recording of a new frame} has been started, where \c
9230 N is the \l{QRhi::resourceLimit()}{resource limit value} returned for
9231 QRhi::MaxAsyncReadbackFrames.
9232
9233 A single readback operation copies one mip level of one layer (cubemap face
9234 or 3D slice or texture array element) at a time. The level and layer are
9235 specified by the respective fields in \a rb.
9236
9237 \sa readBackBuffer(), QRhi::resourceLimit()
9238 */
9239void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
9240{
9241 const int idx = d->activeTextureOpCount++;
9242 if (idx < d->textureOps.size())
9243 d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::read(rb, result);
9244 else
9245 d->textureOps.append(t: QRhiResourceUpdateBatchPrivate::TextureOp::read(rb, result));
9246}
9247
9248/*!
9249 Enqueues a mipmap generation operation for the specified texture \a tex.
9250
9251 Both 2D and cube textures are supported.
9252
9253 \note The texture must be created with QRhiTexture::MipMapped and
9254 QRhiTexture::UsedWithGenerateMips.
9255
9256 \warning QRhi cannot guarantee that mipmaps can be generated for all
9257 supported texture formats. For example, QRhiTexture::RGBA32F is not a \c
9258 filterable format in OpenGL ES 3.0 and Metal on iOS, and therefore the
9259 mipmap generation request may fail. RGBA8 and RGBA16F are typically
9260 filterable, so it is recommended to use these formats when mipmap generation
9261 is desired.
9262 */
9263void QRhiResourceUpdateBatch::generateMips(QRhiTexture *tex)
9264{
9265 const int idx = d->activeTextureOpCount++;
9266 if (idx < d->textureOps.size())
9267 d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex);
9268 else
9269 d->textureOps.append(t: QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex));
9270}
9271
9272/*!
9273 \return an available, empty batch to which copy type of operations can be
9274 recorded.
9275
9276 \note the return value is not owned by the caller and must never be
9277 destroyed. Instead, the batch is returned the pool for reuse by passing
9278 it to QRhiCommandBuffer::beginPass(), QRhiCommandBuffer::endPass(), or
9279 QRhiCommandBuffer::resourceUpdate(), or by calling
9280 QRhiResourceUpdateBatch::release() on it.
9281
9282 \note Can be called outside beginFrame() - endFrame() as well since a batch
9283 instance just collects data on its own, it does not perform any operations.
9284
9285 Due to not being tied to a frame being recorded, the following sequence is
9286 valid for example:
9287
9288 \code
9289 rhi->beginFrame(swapchain);
9290 QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch();
9291 u->uploadStaticBuffer(buf, data);
9292 // ... do not commit the batch
9293 rhi->endFrame();
9294 // u stays valid (assuming buf stays valid as well)
9295 rhi->beginFrame(swapchain);
9296 swapchain->currentFrameCommandBuffer()->resourceUpdate(u);
9297 // ... draw with buf
9298 rhi->endFrame();
9299 \endcode
9300
9301 \warning The maximum number of batches per QRhi is 64. When this limit is
9302 reached, the function will return null until a batch is returned to the
9303 pool.
9304 */
9305QRhiResourceUpdateBatch *QRhi::nextResourceUpdateBatch()
9306{
9307 // By default we prefer spreading out the utilization of the worst case 64
9308 // (but typically 4) batches as much as possible, meaning we won't pick the
9309 // first one even if it's free, but prefer picking one after the last picked
9310 // one. Relevant due to implicit sharing (the backend may hold on to the
9311 // QRhiBufferData until frame no. current+FramesInFlight-1, but
9312 // implementations may vary), combined with the desire to reuse container
9313 // and QRhiBufferData allocations in bufferOps instead of flooding every
9314 // frame with allocs. See free(). In typical Qt Quick scenes this leads to
9315 // eventually seeding all 4 (or more) resource batches with buffer operation
9316 // data allocations which may (*) then be reused in subsequent frames. This
9317 // comes at the expense of using more memory, but has proven good results
9318 // when (CPU) profiling typical Quick/Quick3D apps.
9319 //
9320 // (*) Due to implicit sharing(ish), the exact behavior is unpredictable. If
9321 // a backend holds on to the QRhiBufferData for, e.g., a dynamic buffer
9322 // update, and then there is a new assign() for that same QRhiBufferData
9323 // while the refcount is still 2, it will "detach" (without contents) and
9324 // there is no reuse of the alloc. This is mitigated by the 'choose the one
9325 // afer the last picked one' logic when handing out batches.
9326
9327 auto nextFreeBatch = [this]() -> QRhiResourceUpdateBatch * {
9328 auto isFree = [this](int i) -> QRhiResourceUpdateBatch * {
9329 const quint64 mask = 1ULL << quint64(i);
9330 if (!(d->resUpdPoolMap & mask)) {
9331 d->resUpdPoolMap |= mask;
9332 QRhiResourceUpdateBatch *u = d->resUpdPool[i];
9333 QRhiResourceUpdateBatchPrivate::get(b: u)->poolIndex = i;
9334 d->lastResUpdIdx = i;
9335 return u;
9336 }
9337 return nullptr;
9338 };
9339 const int poolSize = d->resUpdPool.size();
9340 for (int i = d->lastResUpdIdx + 1; i < poolSize; ++i) {
9341 if (QRhiResourceUpdateBatch *u = isFree(i))
9342 return u;
9343 }
9344 for (int i = 0; i <= d->lastResUpdIdx; ++i) {
9345 if (QRhiResourceUpdateBatch *u = isFree(i))
9346 return u;
9347 }
9348 return nullptr;
9349 };
9350
9351 QRhiResourceUpdateBatch *u = nextFreeBatch();
9352 if (!u) {
9353 const int oldSize = d->resUpdPool.size();
9354 // 4, 8, 12, ..., up to 64
9355 const int newSize = oldSize + qMin(a: 4, b: qMax(a: 0, b: 64 - oldSize));
9356 d->resUpdPool.resize(sz: newSize);
9357 for (int i = oldSize; i < newSize; ++i)
9358 d->resUpdPool[i] = new QRhiResourceUpdateBatch(d);
9359 u = nextFreeBatch();
9360 if (!u)
9361 qWarning(msg: "Resource update batch pool exhausted (max is 64)");
9362 }
9363
9364 return u;
9365}
9366
9367void QRhiResourceUpdateBatchPrivate::free()
9368{
9369 Q_ASSERT(poolIndex >= 0 && rhi->resUpdPool[poolIndex] == q);
9370
9371 quint32 bufferDataTotal = 0;
9372 quint32 bufferLargeAllocTotal = 0;
9373 for (const BufferOp &op : std::as_const(t&: bufferOps)) {
9374 bufferDataTotal += op.data.size();
9375 bufferLargeAllocTotal += op.data.largeAlloc(); // alloc when > 1 KB
9376 }
9377
9378 if (rhi->rubLogEnabled) {
9379 qDebug() << "[rub] release to pool upd.batch #" << poolIndex
9380 << "/ bufferOps active" << activeBufferOpCount
9381 << "of" << bufferOps.count()
9382 << "data" << bufferDataTotal
9383 << "largeAlloc" << bufferLargeAllocTotal
9384 << "textureOps active" << activeTextureOpCount
9385 << "of" << textureOps.count();
9386 }
9387
9388 activeBufferOpCount = 0;
9389 activeTextureOpCount = 0;
9390
9391 const quint64 mask = 1ULL << quint64(poolIndex);
9392 rhi->resUpdPoolMap &= ~mask;
9393 poolIndex = -1;
9394
9395 // textureOps is cleared, to not keep the potentially large image pixel
9396 // data alive, but it is expected that the container keeps the list alloc
9397 // at least. Only trimOpList() goes for the more aggressive route with squeeze.
9398 textureOps.clear();
9399
9400 // bufferOps is not touched in many cases, to allow reusing allocations
9401 // (incl. in the elements' QRhiBufferData) as much as possible when this
9402 // batch is used again in the future, which is important for performance, in
9403 // particular with Qt Quick where it is easy for scenes to produce lots of,
9404 // typically small buffer changes on every frame.
9405 //
9406 // However, ensure that even in the unlikely case of having the max number
9407 // of batches (64) created in resUpdPool, no more than 64 MB in total is
9408 // used up by buffer data just to help future reuse. For simplicity, if
9409 // there is more than 1 MB data -> clear. Applications with frequent, huge
9410 // buffer updates probably have other bottlenecks anyway.
9411 if (bufferLargeAllocTotal > 1024 * 1024)
9412 bufferOps.clear();
9413}
9414
9415void QRhiResourceUpdateBatchPrivate::merge(QRhiResourceUpdateBatchPrivate *other)
9416{
9417 int combinedSize = activeBufferOpCount + other->activeBufferOpCount;
9418 if (bufferOps.size() < combinedSize)
9419 bufferOps.resize(sz: combinedSize);
9420 for (int i = activeBufferOpCount; i < combinedSize; ++i)
9421 bufferOps[i] = std::move(other->bufferOps[i - activeBufferOpCount]);
9422 activeBufferOpCount += other->activeBufferOpCount;
9423
9424 combinedSize = activeTextureOpCount + other->activeTextureOpCount;
9425 if (textureOps.size() < combinedSize)
9426 textureOps.resize(sz: combinedSize);
9427 for (int i = activeTextureOpCount; i < combinedSize; ++i)
9428 textureOps[i] = std::move(other->textureOps[i - activeTextureOpCount]);
9429 activeTextureOpCount += other->activeTextureOpCount;
9430}
9431
9432bool QRhiResourceUpdateBatchPrivate::hasOptimalCapacity() const
9433{
9434 return activeBufferOpCount < BUFFER_OPS_STATIC_ALLOC - 4
9435 && activeTextureOpCount < TEXTURE_OPS_STATIC_ALLOC - 4;
9436}
9437
9438void QRhiResourceUpdateBatchPrivate::trimOpLists()
9439{
9440 // Unlike free(), this is expected to aggressively deallocate all memory
9441 // used by both the buffer and texture operation lists. (i.e. using
9442 // squeeze() to only keep the stack prealloc of the QVLAs)
9443 //
9444 // This (e.g. just the destruction of bufferOps elements) may have a
9445 // non-negligible performance impact e.g. with Qt Quick with scenes where
9446 // there are lots of buffer operations per frame.
9447
9448 activeBufferOpCount = 0;
9449 bufferOps.clear();
9450 bufferOps.squeeze();
9451
9452 activeTextureOpCount = 0;
9453 textureOps.clear();
9454 textureOps.squeeze();
9455}
9456
9457/*!
9458 Sometimes committing resource updates is necessary or just more convenient
9459 without starting a render pass. Calling this function with \a
9460 resourceUpdates is an alternative to passing \a resourceUpdates to a
9461 beginPass() call (or endPass(), which would be typical in case of readbacks).
9462
9463 \note Cannot be called inside a pass.
9464 */
9465void QRhiCommandBuffer::resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates)
9466{
9467 if (resourceUpdates)
9468 m_rhi->resourceUpdate(cb: this, resourceUpdates);
9469}
9470
9471/*!
9472 Records starting a new render pass targeting the render target \a rt.
9473
9474 \a resourceUpdates, when not null, specifies a resource update batch that
9475 is to be committed and then released.
9476
9477 The color and depth/stencil buffers of the render target are normally
9478 cleared. The clear values are specified in \a colorClearValue and \a
9479 depthStencilClearValue. The exception is when the render target was created
9480 with QRhiTextureRenderTarget::PreserveColorContents and/or
9481 QRhiTextureRenderTarget::PreserveDepthStencilContents. The clear values are
9482 ignored then.
9483
9484 \note Enabling preserved color or depth contents leads to decreased
9485 performance depending on the underlying hardware. Mobile GPUs with tiled
9486 architecture benefit from not having to reload the previous contents into
9487 the tile buffer. Similarly, a QRhiTextureRenderTarget with a QRhiTexture as
9488 the depth buffer is less efficient than a QRhiRenderBuffer since using a
9489 depth texture triggers requiring writing the data out to it, while with
9490 renderbuffers this is not needed (as the API does not allow sampling or
9491 reading from a renderbuffer).
9492
9493 \note Do not assume that any state or resource bindings persist between
9494 passes.
9495
9496 \note The QRhiCommandBuffer's \c set and \c draw functions can only be
9497 called inside a pass. Also, with the exception of setGraphicsPipeline(),
9498 they expect to have a pipeline set already on the command buffer.
9499 Unspecified issues may arise otherwise, depending on the backend.
9500
9501 If \a rt is a QRhiTextureRenderTarget, beginPass() performs a check to see
9502 if the texture and renderbuffer objects referenced from the render target
9503 are up-to-date. This is similar to what setShaderResources() does for
9504 QRhiShaderResourceBindings. If any of the attachments had been rebuilt
9505 since QRhiTextureRenderTarget::create(), an implicit call to create() is
9506 made on \a rt. Therefore, if \a rt has a QRhiTexture color attachment \c
9507 texture, and one needs to make the texture a different size, the following
9508 is then valid:
9509 \code
9510 QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ { texture } });
9511 rt->create();
9512 // ...
9513 texture->setPixelSize(new_size);
9514 texture->create();
9515 cb->beginPass(rt, colorClear, dsClear); // this is ok, no explicit rt->create() is required before
9516 \endcode
9517
9518 \a flags allow controlling certain advanced functionality. One commonly used
9519 flag is \c ExternalContents. This should be specified whenever
9520 beginExternal() will be called within the pass started by this function.
9521
9522 \sa endPass(), BeginPassFlags
9523 */
9524void QRhiCommandBuffer::beginPass(QRhiRenderTarget *rt,
9525 const QColor &colorClearValue,
9526 const QRhiDepthStencilClearValue &depthStencilClearValue,
9527 QRhiResourceUpdateBatch *resourceUpdates,
9528 BeginPassFlags flags)
9529{
9530 m_rhi->beginPass(cb: this, rt, colorClearValue, depthStencilClearValue, resourceUpdates, flags);
9531}
9532
9533/*!
9534 Records ending the current render pass.
9535
9536 \a resourceUpdates, when not null, specifies a resource update batch that
9537 is to be committed and then released.
9538
9539 \sa beginPass()
9540 */
9541void QRhiCommandBuffer::endPass(QRhiResourceUpdateBatch *resourceUpdates)
9542{
9543 m_rhi->endPass(cb: this, resourceUpdates);
9544}
9545
9546/*!
9547 Records setting a new graphics pipeline \a ps.
9548
9549 \note This function must be called before recording other \c set or \c draw
9550 commands on the command buffer.
9551
9552 \note QRhi will optimize out unnecessary invocations within a pass, so
9553 therefore overoptimizing to avoid calls to this function is not necessary
9554 on the applications' side.
9555
9556 \note This function can only be called inside a render pass, meaning
9557 between a beginPass() and endPass() call.
9558
9559 \note The new graphics pipeline \a ps must be a valid pointer.
9560 */
9561void QRhiCommandBuffer::setGraphicsPipeline(QRhiGraphicsPipeline *ps)
9562{
9563 Q_ASSERT(ps != nullptr);
9564 m_rhi->setGraphicsPipeline(cb: this, ps);
9565}
9566
9567/*!
9568 Records binding a set of shader resources, such as, uniform buffers or
9569 textures, that are made visible to one or more shader stages.
9570
9571 \a srb can be null in which case the current graphics or compute pipeline's
9572 associated QRhiShaderResourceBindings is used. When \a srb is non-null, it
9573 must be
9574 \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible},
9575 meaning the layout (number of bindings, the type and binding number of each
9576 binding) must fully match the QRhiShaderResourceBindings that was
9577 associated with the pipeline at the time of calling the pipeline's create().
9578
9579 There are cases when a seemingly unnecessary setShaderResources() call is
9580 mandatory: when rebuilding a resource referenced from \a srb, for example
9581 changing the size of a QRhiBuffer followed by a QRhiBuffer::create(), this
9582 is the place where associated native objects (such as descriptor sets in
9583 case of Vulkan) are updated to refer to the current native resources that
9584 back the QRhiBuffer, QRhiTexture, QRhiSampler objects referenced from \a
9585 srb. In this case setShaderResources() must be called even if \a srb is
9586 the same as in the last call.
9587
9588 When \a srb is not null, the QRhiShaderResourceBindings object the pipeline
9589 was built with in create() is guaranteed to be not accessed in any form. In
9590 fact, it does not need to be valid even at this point: destroying the
9591 pipeline's associated srb after create() and instead explicitly specifying
9592 another, \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout
9593 compatible} one in every setShaderResources() call is valid.
9594
9595 \a dynamicOffsets allows specifying buffer offsets for uniform buffers that
9596 were associated with \a srb via
9597 QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(). This is
9598 different from providing the offset in the \a srb itself: dynamic offsets
9599 do not require building a new QRhiShaderResourceBindings for every
9600 different offset, can avoid writing the underlying descriptors (with
9601 backends where applicable), and so they may be more efficient. Each element
9602 of \a dynamicOffsets is a \c binding - \c offset pair.
9603 \a dynamicOffsetCount specifies the number of elements in \a dynamicOffsets.
9604
9605 \note All offsets in \a dynamicOffsets must be byte aligned to the value
9606 returned from QRhi::ubufAlignment().
9607
9608 \note Some backends may limit the number of supported dynamic offsets.
9609 Avoid using a \a dynamicOffsetCount larger than 8.
9610
9611 \note QRhi will optimize out unnecessary invocations within a pass (taking
9612 the conditions described above into account), so therefore overoptimizing
9613 to avoid calls to this function is not necessary on the applications' side.
9614
9615 \note This function can only be called inside a render or compute pass,
9616 meaning between a beginPass() and endPass(), or beginComputePass() and
9617 endComputePass().
9618 */
9619void QRhiCommandBuffer::setShaderResources(QRhiShaderResourceBindings *srb,
9620 int dynamicOffsetCount,
9621 const DynamicOffset *dynamicOffsets)
9622{
9623 m_rhi->setShaderResources(cb: this, srb, dynamicOffsetCount, dynamicOffsets);
9624}
9625
9626/*!
9627 Records vertex input bindings.
9628
9629 The index buffer used by subsequent drawIndexed() commands is specified by
9630 \a indexBuf, \a indexOffset, and \a indexFormat. \a indexBuf can be set to
9631 null when indexed drawing is not needed.
9632
9633 Vertex buffer bindings are batched. \a startBinding specifies the first
9634 binding number. The recorded command then binds each buffer from \a
9635 bindings to the binding point \c{startBinding + i} where \c i is the index
9636 in \a bindings. Each element in \a bindings specifies a QRhiBuffer and an
9637 offset.
9638
9639 \note Some backends may limit the number of vertex buffer bindings. Avoid
9640 using a \a bindingCount larger than 8.
9641
9642 Superfluous vertex input and index changes in the same pass are ignored
9643 automatically with most backends and therefore applications do not need to
9644 overoptimize to avoid calls to this function.
9645
9646 \note This function can only be called inside a render pass, meaning
9647 between a beginPass() and endPass() call.
9648
9649 As a simple example, take a vertex shader with two inputs:
9650
9651 \badcode
9652 layout(location = 0) in vec4 position;
9653 layout(location = 1) in vec3 color;
9654 \endcode
9655
9656 and assume we have the data available in interleaved format, using only 2
9657 floats for position (so 5 floats per vertex: x, y, r, g, b). A QRhiGraphicsPipeline for
9658 this shader can then be created using the input layout:
9659
9660 \code
9661 QRhiVertexInputLayout inputLayout;
9662 inputLayout.setBindings({
9663 { 5 * sizeof(float) }
9664 });
9665 inputLayout.setAttributes({
9666 { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
9667 { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) }
9668 });
9669 \endcode
9670
9671 Here there is one buffer binding (binding number 0), with two inputs
9672 referencing it. When recording the pass, once the pipeline is set, the
9673 vertex bindings can be specified simply like the following, assuming vbuf
9674 is the QRhiBuffer with all the interleaved position+color data:
9675
9676 \code
9677 const QRhiCommandBuffer::VertexInput vbufBinding(vbuf, 0);
9678 cb->setVertexInput(0, 1, &vbufBinding);
9679 \endcode
9680 */
9681void QRhiCommandBuffer::setVertexInput(int startBinding, int bindingCount, const VertexInput *bindings,
9682 QRhiBuffer *indexBuf, quint32 indexOffset,
9683 IndexFormat indexFormat)
9684{
9685 m_rhi->setVertexInput(cb: this, startBinding, bindingCount, bindings, indexBuf, indexOffset, indexFormat);
9686}
9687
9688/*!
9689 Records setting the active viewport rectangle specified in \a viewport.
9690
9691 With backends where the underlying graphics API has scissoring always
9692 enabled, this function also sets the scissor to match the viewport whenever
9693 the active QRhiGraphicsPipeline does not have
9694 \l{QRhiGraphicsPipeline::UsesScissor}{UsesScissor} set.
9695
9696 \note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are
9697 bottom-left.
9698
9699 \note This function can only be called inside a render pass, meaning
9700 between a beginPass() and endPass() call.
9701 */
9702void QRhiCommandBuffer::setViewport(const QRhiViewport &viewport)
9703{
9704 m_rhi->setViewport(cb: this, viewport);
9705}
9706
9707/*!
9708 Records setting the active scissor rectangle specified in \a scissor.
9709
9710 This can only be called when the bound pipeline has
9711 \l{QRhiGraphicsPipeline::UsesScissor}{UsesScissor} set. When the flag is
9712 set on the active pipeline, this function must be called because scissor
9713 testing will get enabled and so a scissor rectangle must be provided.
9714
9715 \note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are
9716 bottom-left.
9717
9718 \note This function can only be called inside a render pass, meaning
9719 between a beginPass() and endPass() call.
9720 */
9721void QRhiCommandBuffer::setScissor(const QRhiScissor &scissor)
9722{
9723 m_rhi->setScissor(cb: this, scissor);
9724}
9725
9726/*!
9727 Records setting the active blend constants to \a c.
9728
9729 This can only be called when the bound pipeline has
9730 QRhiGraphicsPipeline::UsesBlendConstants set.
9731
9732 \note This function can only be called inside a render pass, meaning
9733 between a beginPass() and endPass() call.
9734 */
9735void QRhiCommandBuffer::setBlendConstants(const QColor &c)
9736{
9737 m_rhi->setBlendConstants(cb: this, c);
9738}
9739
9740/*!
9741 Records setting the active stencil reference value to \a refValue.
9742
9743 This can only be called when the bound pipeline has
9744 QRhiGraphicsPipeline::UsesStencilRef set.
9745
9746 \note This function can only be called inside a render pass, meaning between
9747 a beginPass() and endPass() call.
9748 */
9749void QRhiCommandBuffer::setStencilRef(quint32 refValue)
9750{
9751 m_rhi->setStencilRef(cb: this, refValue);
9752}
9753
9754/*!
9755 Records a non-indexed draw.
9756
9757 The number of vertices is specified in \a vertexCount. For instanced
9758 drawing set \a instanceCount to a value other than 1. \a firstVertex is the
9759 index of the first vertex to draw. When drawing multiple instances, the
9760 first instance ID is specified by \a firstInstance.
9761
9762 \note \a firstInstance may not be supported, and is ignored when the
9763 QRhi::BaseInstance feature is reported as not supported. The first ID is
9764 always 0 in that case.
9765
9766 \note This function can only be called inside a render pass, meaning
9767 between a beginPass() and endPass() call.
9768 */
9769void QRhiCommandBuffer::draw(quint32 vertexCount,
9770 quint32 instanceCount,
9771 quint32 firstVertex,
9772 quint32 firstInstance)
9773{
9774 m_rhi->draw(cb: this, vertexCount, instanceCount, firstVertex, firstInstance);
9775}
9776
9777/*!
9778 Records an indexed draw.
9779
9780 The number of vertices is specified in \a indexCount. \a firstIndex is the
9781 base index. The effective offset in the index buffer is given by
9782 \c{indexOffset + firstIndex * n} where \c n is 2 or 4 depending on the
9783 index element type. \c indexOffset is specified in setVertexInput().
9784
9785 \note The effective offset in the index buffer must be 4 byte aligned with
9786 some backends (for example, Metal). With these backends the
9787 \l{QRhi::NonFourAlignedEffectiveIndexBufferOffset}{NonFourAlignedEffectiveIndexBufferOffset}
9788 feature will be reported as not-supported.
9789
9790 For instanced drawing set \a instanceCount to a value other than 1. When
9791 drawing multiple instances, the first instance ID is specified by \a
9792 firstInstance.
9793
9794 \note \a firstInstance may not be supported, and is ignored when the
9795 QRhi::BaseInstance feature is reported as not supported. The first ID is
9796 always 0 in that case.
9797
9798 \a vertexOffset (also called \c{base vertex}) is a signed value that is
9799 added to the element index before indexing into the vertex buffer. Support
9800 for this is not always available, and the value is ignored when the feature
9801 QRhi::BaseVertex is reported as unsupported.
9802
9803 \note This function can only be called inside a render pass, meaning
9804 between a beginPass() and endPass() call.
9805 */
9806void QRhiCommandBuffer::drawIndexed(quint32 indexCount,
9807 quint32 instanceCount,
9808 quint32 firstIndex,
9809 qint32 vertexOffset,
9810 quint32 firstInstance)
9811{
9812 m_rhi->drawIndexed(cb: this, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
9813}
9814
9815/*!
9816 Records a named debug group on the command buffer with the specified \a
9817 name. This is shown in graphics debugging tools such as
9818 \l{https://renderdoc.org/}{RenderDoc} and
9819 \l{https://developer.apple.com/xcode/}{XCode}. The end of the grouping is
9820 indicated by debugMarkEnd().
9821
9822 \note Ignored when QRhi::DebugMarkers are not supported or
9823 QRhi::EnableDebugMarkers is not set.
9824
9825 \note Can be called anywhere within the frame, both inside and outside of passes.
9826 */
9827void QRhiCommandBuffer::debugMarkBegin(const QByteArray &name)
9828{
9829 m_rhi->debugMarkBegin(cb: this, name);
9830}
9831
9832/*!
9833 Records the end of a debug group.
9834
9835 \note Ignored when QRhi::DebugMarkers are not supported or
9836 QRhi::EnableDebugMarkers is not set.
9837
9838 \note Can be called anywhere within the frame, both inside and outside of passes.
9839 */
9840void QRhiCommandBuffer::debugMarkEnd()
9841{
9842 m_rhi->debugMarkEnd(cb: this);
9843}
9844
9845/*!
9846 Inserts a debug message \a msg into the command stream.
9847
9848 \note Ignored when QRhi::DebugMarkers are not supported or
9849 QRhi::EnableDebugMarkers is not set.
9850
9851 \note With some backends debugMarkMsg() is only supported inside a pass and
9852 is ignored when called outside a pass. With others it is recorded anywhere
9853 within the frame.
9854 */
9855void QRhiCommandBuffer::debugMarkMsg(const QByteArray &msg)
9856{
9857 m_rhi->debugMarkMsg(cb: this, msg);
9858}
9859
9860/*!
9861 Records starting a new compute pass.
9862
9863 \a resourceUpdates, when not null, specifies a resource update batch that
9864 is to be committed and then released.
9865
9866 \note Do not assume that any state or resource bindings persist between
9867 passes.
9868
9869 \note A compute pass can record setComputePipeline(), setShaderResources(),
9870 and dispatch() calls, not graphics ones. General functionality, such as,
9871 debug markers and beginExternal() is available both in render and compute
9872 passes.
9873
9874 \note Compute is only available when the \l{QRhi::Compute}{Compute} feature
9875 is reported as supported.
9876
9877 \a flags is not currently used.
9878 */
9879void QRhiCommandBuffer::beginComputePass(QRhiResourceUpdateBatch *resourceUpdates, BeginPassFlags flags)
9880{
9881 m_rhi->beginComputePass(cb: this, resourceUpdates, flags);
9882}
9883
9884/*!
9885 Records ending the current compute pass.
9886
9887 \a resourceUpdates, when not null, specifies a resource update batch that
9888 is to be committed and then released.
9889 */
9890void QRhiCommandBuffer::endComputePass(QRhiResourceUpdateBatch *resourceUpdates)
9891{
9892 m_rhi->endComputePass(cb: this, resourceUpdates);
9893}
9894
9895/*!
9896 Records setting a new compute pipeline \a ps.
9897
9898 \note This function must be called before recording setShaderResources() or
9899 dispatch() commands on the command buffer.
9900
9901 \note QRhi will optimize out unnecessary invocations within a pass, so
9902 therefore overoptimizing to avoid calls to this function is not necessary
9903 on the applications' side.
9904
9905 \note This function can only be called inside a compute pass, meaning
9906 between a beginComputePass() and endComputePass() call.
9907 */
9908void QRhiCommandBuffer::setComputePipeline(QRhiComputePipeline *ps)
9909{
9910 m_rhi->setComputePipeline(cb: this, ps);
9911}
9912
9913/*!
9914 Records dispatching compute work items, with \a x, \a y, and \a z
9915 specifying the number of local workgroups in the corresponding dimension.
9916
9917 \note This function can only be called inside a compute pass, meaning
9918 between a beginComputePass() and endComputePass() call.
9919
9920 \note \a x, \a y, and \a z must fit the limits from the underlying graphics
9921 API implementation at run time. The maximum values are typically 65535.
9922
9923 \note Watch out for possible limits on the local workgroup size as well.
9924 This is specified in the shader, for example: \c{layout(local_size_x = 16,
9925 local_size_y = 16) in;}. For example, with OpenGL the minimum value mandated
9926 by the specification for the number of invocations in a single local work
9927 group (the product of \c local_size_x, \c local_size_y, and \c local_size_z)
9928 is 1024, while with OpenGL ES (3.1) the value may be as low as 128. This
9929 means that the example given above may be rejected by some OpenGL ES
9930 implementations as the number of invocations is 256.
9931 */
9932void QRhiCommandBuffer::dispatch(int x, int y, int z)
9933{
9934 m_rhi->dispatch(cb: this, x, y, z);
9935}
9936
9937/*!
9938 \return a pointer to a backend-specific QRhiNativeHandles subclass, such as
9939 QRhiVulkanCommandBufferNativeHandles. The returned value is \nullptr when
9940 exposing the underlying native resources is not supported by, or not
9941 applicable to, the backend.
9942
9943 \sa QRhiVulkanCommandBufferNativeHandles,
9944 QRhiMetalCommandBufferNativeHandles, beginExternal(), endExternal()
9945 */
9946const QRhiNativeHandles *QRhiCommandBuffer::nativeHandles()
9947{
9948 return m_rhi->nativeHandles(cb: this);
9949}
9950
9951/*!
9952 To be called when the application before the application is about to
9953 enqueue commands to the current pass' command buffer by calling graphics
9954 API functions directly.
9955
9956 \note This is only available when the intent was declared upfront in
9957 beginPass() or beginComputePass(). Therefore this function must only be
9958 called when the pass recording was started with specifying
9959 QRhiCommandBuffer::ExternalContent.
9960
9961 With Vulkan, Metal, or Direct3D 12 one can query the native command buffer
9962 or encoder objects via nativeHandles() and enqueue commands to them. With
9963 OpenGL or Direct3D 11 the (device) context can be retrieved from
9964 QRhi::nativeHandles(). However, this must never be done without ensuring
9965 the QRhiCommandBuffer's state stays up-to-date. Hence the requirement for
9966 wrapping any externally added command recording between beginExternal() and
9967 endExternal(). Conceptually this is the same as QPainter's
9968 \l{QPainter::beginNativePainting()}{beginNativePainting()} and
9969 \l{QPainter::endNativePainting()}{endNativePainting()} functions.
9970
9971 For OpenGL in particular, this function has an additional task: it makes
9972 sure the context is made current on the current thread.
9973
9974 \note Once beginExternal() is called, no other render pass specific
9975 functions (\c set* or \c draw*) must be called on the
9976 QRhiCommandBuffer until endExternal().
9977
9978 \warning Some backends may return a native command buffer object from
9979 QRhiCommandBuffer::nativeHandles() that is different from the primary one
9980 when inside a beginExternal() - endExternal() block. Therefore it is
9981 important to (re)query the native command buffer object after calling
9982 beginExternal(). In practical terms this means that with Vulkan for example
9983 the externally recorded Vulkan commands are placed onto a secondary command
9984 buffer (with VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT).
9985 nativeHandles() returns this secondary command buffer when called between
9986 begin/endExternal.
9987
9988 \sa endExternal(), nativeHandles()
9989 */
9990void QRhiCommandBuffer::beginExternal()
9991{
9992 m_rhi->beginExternal(cb: this);
9993}
9994
9995/*!
9996 To be called once the externally added commands are recorded to the command
9997 buffer or context.
9998
9999 \note All QRhiCommandBuffer state must be assumed as invalid after calling
10000 this function. Pipelines, vertex and index buffers, and other state must be
10001 set again if more draw calls are recorded after the external commands.
10002
10003 \sa beginExternal(), nativeHandles()
10004 */
10005void QRhiCommandBuffer::endExternal()
10006{
10007 m_rhi->endExternal(cb: this);
10008}
10009
10010/*!
10011 \return the last available timestamp, in seconds, when
10012 \l QRhi::EnableTimestamps was enabled when creating the QRhi. The value
10013 indicates the elapsed time on the GPU during the last completed frame.
10014
10015 \note Do not expect results other than 0 when the QRhi::Timestamps feature
10016 is not reported as supported, or when QRhi::EnableTimestamps was not passed
10017 to QRhi::create(). There are exceptions to this, because with some graphics
10018 APIs (Metal) timings are available without having to perform extra
10019 operations (timestamp queries), but portable applications should always
10020 consciously opt-in to timestamp collection when they know it is needed, and
10021 call this function accordingly.
10022
10023 Care must be exercised with the interpretation of the value, as its
10024 precision and granularity is often not controlled by Qt, and depends on the
10025 underlying graphics API and its implementation. In particular, comparing
10026 the values between different graphics APIs and hardware is discouraged and
10027 may be meaningless.
10028
10029 When the frame was recorded with \l{QRhi::beginFrame()}{beginFrame()} and
10030 \l{QRhi::endFrame()}{endFrame()}, i.e., with a swapchain, the timing values
10031 will likely become available asynchronously. The returned value may
10032 therefore be 0 (e.g., for the first 1-2 frames) or the last known value
10033 referring to some previous frame. The value my also
10034 become 0 again under certain conditions, such as when resizing the window.
10035 It can be expected that the most up-to-date available value is retrieved in
10036 beginFrame() and becomes queriable via this function once beginFrame()
10037 returns.
10038
10039 \note Do not assume that the value refers to the previous
10040 (\c{currently_recorded - 1}) frame. It may refer to \c{currently_recorded -
10041 2} or \c{currently_recorded - 3} as well. The exact behavior may depend on
10042 the graphics API and its implementation.
10043
10044 On the other hand, with offscreen frames the returned value is up-to-date
10045 once \l{QRhi::endOffscreenFrame()}{endOffscreenFrame()} returns, because
10046 offscreen frames reduce GPU pipelining and wait the the commands to be
10047 complete.
10048
10049 \note This means that, unlike with swapchain frames, with offscreen frames
10050 the returned value is guaranteed to refer to the frame that has just been
10051 submitted and completed. (assuming this function is called after
10052 endOffscreenFrame() but before the next beginOffscreenFrame())
10053
10054 Watch out for the consequences of GPU frequency scaling and GPU clock
10055 changes, depending on the platform. For example, on Windows the returned
10056 timing may vary in a quite wide range between frames with modern graphics
10057 cards, even when submitting frames with a similar, or the same workload.
10058 This is out of scope for Qt to control and solve, generally speaking.
10059 However, the D3D12 backend automatically calls
10060 \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-setstablepowerstate}{ID3D12Device::SetStablePowerState()}
10061 whenever the environment variable \c QT_D3D_STABLE_POWER_STATE is set to a
10062 non-zero value. This can greatly stabilize the result. It can also have a
10063 non-insignificant effect on the CPU-side timings measured via QElapsedTimer
10064 for example, especially when offscreen frames are involved.
10065
10066 \note Do not and never ship applications to production with
10067 \c QT_D3D_STABLE_POWER_STATE set. See the Windows API documentation for details.
10068
10069 \sa QRhi::Timestamps, QRhi::EnableTimestamps
10070 */
10071double QRhiCommandBuffer::lastCompletedGpuTime()
10072{
10073 return m_rhi->lastCompletedGpuTime(cb: this);
10074}
10075
10076/*!
10077 \return the value (typically an offset) \a v aligned to the uniform buffer
10078 alignment given by by ubufAlignment().
10079 */
10080int QRhi::ubufAligned(int v) const
10081{
10082 const int byteAlign = ubufAlignment();
10083 return (v + byteAlign - 1) & ~(byteAlign - 1);
10084}
10085
10086/*!
10087 \return the number of mip levels for a given \a size.
10088 */
10089int QRhi::mipLevelsForSize(const QSize &size)
10090{
10091 return qFloor(v: std::log2(x: qMax(a: size.width(), b: size.height()))) + 1;
10092}
10093
10094/*!
10095 \return the texture image size for a given \a mipLevel, calculated based on
10096 the level 0 size given in \a baseLevelSize.
10097 */
10098QSize QRhi::sizeForMipLevel(int mipLevel, const QSize &baseLevelSize)
10099{
10100 const int w = qMax(a: 1, b: baseLevelSize.width() >> mipLevel);
10101 const int h = qMax(a: 1, b: baseLevelSize.height() >> mipLevel);
10102 return QSize(w, h);
10103}
10104
10105/*!
10106 \return \c true if the underlying graphics API has the Y axis pointing up
10107 in framebuffers and images.
10108
10109 In practice this is \c true for OpenGL only.
10110 */
10111bool QRhi::isYUpInFramebuffer() const
10112{
10113 return d->isYUpInFramebuffer();
10114}
10115
10116/*!
10117 \return \c true if the underlying graphics API has the Y axis pointing up
10118 in its normalized device coordinate system.
10119
10120 In practice this is \c false for Vulkan only.
10121
10122 \note clipSpaceCorrMatrix() includes the corresponding adjustment (to make
10123 Y point up) in its returned matrix.
10124 */
10125bool QRhi::isYUpInNDC() const
10126{
10127 return d->isYUpInNDC();
10128}
10129
10130/*!
10131 \return \c true if the underlying graphics API uses depth range [0, 1] in
10132 clip space.
10133
10134 In practice this is \c false for OpenGL only, because OpenGL uses a
10135 post-projection depth range of [-1, 1]. (not to be confused with the
10136 NDC-to-window mapping controlled by glDepthRange(), which uses a range of
10137 [0, 1], unless overridden by the QRhiViewport) In some OpenGL versions
10138 glClipControl() could be used to change this, but the OpenGL backend of
10139 QRhi does not use that function as it is not available in OpenGL ES or
10140 OpenGL versions lower than 4.5.
10141
10142 \note clipSpaceCorrMatrix() includes the corresponding adjustment in its
10143 returned matrix. Therefore, many users of QRhi do not need to take any
10144 further measures apart from pre-multiplying their projection matrices with
10145 clipSpaceCorrMatrix(). However, some graphics techniques, such as, some
10146 types of shadow mapping, involve working with and outputting depth values
10147 in the shaders. These will need to query and take the value of this
10148 function into account as appropriate.
10149 */
10150bool QRhi::isClipDepthZeroToOne() const
10151{
10152 return d->isClipDepthZeroToOne();
10153}
10154
10155/*!
10156 \return a matrix that can be used to allow applications keep using
10157 OpenGL-targeted vertex data and perspective projection matrices (such as,
10158 the ones generated by QMatrix4x4::perspective()), regardless of the active
10159 QRhi backend.
10160
10161 In a typical renderer, once \c{this_matrix * mvp} is used instead of just
10162 \c mvp, vertex data with Y up and viewports with depth range 0 - 1 can be
10163 used without considering what backend (and so graphics API) is going to be
10164 used at run time. This way branching based on isYUpInNDC() and
10165 isClipDepthZeroToOne() can be avoided (although such logic may still become
10166 required when implementing certain advanced graphics techniques).
10167
10168 See
10169 \l{https://matthewwellings.com/blog/the-new-vulkan-coordinate-system/}{this
10170 page} for a discussion of the topic from Vulkan perspective.
10171 */
10172QMatrix4x4 QRhi::clipSpaceCorrMatrix() const
10173{
10174 return d->clipSpaceCorrMatrix();
10175}
10176
10177/*!
10178 \return \c true if the specified texture \a format modified by \a flags is
10179 supported.
10180
10181 The query is supported both for uncompressed and compressed formats.
10182 */
10183bool QRhi::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const
10184{
10185 return d->isTextureFormatSupported(format, flags);
10186}
10187
10188/*!
10189 \return \c true if the specified \a feature is supported
10190 */
10191bool QRhi::isFeatureSupported(QRhi::Feature feature) const
10192{
10193 return d->isFeatureSupported(feature);
10194}
10195
10196/*!
10197 \return the value for the specified resource \a limit.
10198
10199 The values are expected to be queried by the backends upon initialization,
10200 meaning calling this function is a light operation.
10201 */
10202int QRhi::resourceLimit(ResourceLimit limit) const
10203{
10204 return d->resourceLimit(limit);
10205}
10206
10207/*!
10208 \return a pointer to the backend-specific collection of native objects
10209 for the device, context, and similar concepts used by the backend.
10210
10211 Cast to QRhiVulkanNativeHandles, QRhiD3D11NativeHandles,
10212 QRhiD3D12NativeHandles, QRhiGles2NativeHandles, or QRhiMetalNativeHandles
10213 as appropriate.
10214
10215 \note No ownership is transferred, neither for the returned pointer nor for
10216 any native objects.
10217 */
10218const QRhiNativeHandles *QRhi::nativeHandles()
10219{
10220 return d->nativeHandles();
10221}
10222
10223/*!
10224 With OpenGL this makes the OpenGL context current on the current thread.
10225 The function has no effect with other backends.
10226
10227 Calling this function is relevant typically in Qt framework code, when one
10228 has to ensure external OpenGL code provided by the application can still
10229 run like it did before with direct usage of OpenGL, as long as the QRhi is
10230 using the OpenGL backend.
10231
10232 \return false when failed, similarly to QOpenGLContext::makeCurrent(). When
10233 the operation failed, isDeviceLost() can be called to determine if there
10234 was a loss of context situation. Such a check is equivalent to checking via
10235 QOpenGLContext::isValid().
10236
10237 \sa QOpenGLContext::makeCurrent(), QOpenGLContext::isValid()
10238 */
10239bool QRhi::makeThreadLocalNativeContextCurrent()
10240{
10241 return d->makeThreadLocalNativeContextCurrent();
10242}
10243
10244/*!
10245 Attempts to release resources in the backend's caches. This can include both
10246 CPU and GPU resources. Only memory and resources that can be recreated
10247 automatically are in scope. As an example, if the backend's
10248 QRhiGraphicsPipeline implementation maintains a cache of shader compilation
10249 results, calling this function leads to emptying that cache, thus
10250 potentially freeing up memory and graphics resources.
10251
10252 Calling this function makes sense in resource constrained environments,
10253 where at a certain point there is a need to ensure minimal resource usage,
10254 at the expense of performance.
10255 */
10256void QRhi::releaseCachedResources()
10257{
10258 d->releaseCachedResources();
10259
10260 for (QRhiResourceUpdateBatch *u : d->resUpdPool) {
10261 if (u->d->poolIndex < 0)
10262 u->d->trimOpLists();
10263 }
10264}
10265
10266/*!
10267 \return true if the graphics device was lost.
10268
10269 The loss of the device is typically detected in beginFrame(), endFrame() or
10270 QRhiSwapChain::createOrResize(), depending on the backend and the underlying
10271 native APIs. The most common is endFrame() because that is where presenting
10272 happens. With some backends QRhiSwapChain::createOrResize() can also fail
10273 due to a device loss. Therefore this function is provided as a generic way
10274 to check if a device loss was detected by a previous operation.
10275
10276 When the device is lost, no further operations should be done via the QRhi.
10277 Rather, all QRhi resources should be released, followed by destroying the
10278 QRhi. A new QRhi can then be attempted to be created. If successful, all
10279 graphics resources must be reinitialized. If not, try again later,
10280 repeatedly.
10281
10282 While simple applications may decide to not care about device loss,
10283 on the commonly used desktop platforms a device loss can happen
10284 due to a variety of reasons, including physically disconnecting the
10285 graphics adapter, disabling the device or driver, uninstalling or upgrading
10286 the graphics driver, or due to errors that lead to a graphics device reset.
10287 Some of these can happen under perfectly normal circumstances as well, for
10288 example the upgrade of the graphics driver to a newer version is a common
10289 task that can happen at any time while a Qt application is running. Users
10290 may very well expect applications to be able to survive this, even when the
10291 application is actively using an API like OpenGL or Direct3D.
10292
10293 Qt's own frameworks built on top of QRhi, such as, Qt Quick, can be
10294 expected to handle and take appropriate measures when a device loss occurs.
10295 If the data for graphics resources, such as textures and buffers, are still
10296 available on the CPU side, such an event may not be noticeable on the
10297 application level at all since graphics resources can seamlessly be
10298 reinitialized then. However, applications and libraries working directly
10299 with QRhi are expected to be prepared to check and handle device loss
10300 situations themselves.
10301
10302 \note With OpenGL, applications may need to opt-in to context reset
10303 notifications by setting QSurfaceFormat::ResetNotification on the
10304 QOpenGLContext. This is typically done by enabling the flag in
10305 QRhiGles2InitParams::format. Keep in mind however that some systems may
10306 generate context resets situations even when this flag is not set.
10307 */
10308bool QRhi::isDeviceLost() const
10309{
10310 return d->isDeviceLost();
10311}
10312
10313/*!
10314 \return a binary data blob with data collected from the
10315 QRhiGraphicsPipeline and QRhiComputePipeline successfully created during
10316 the lifetime of this QRhi.
10317
10318 By saving and then, in subsequent runs of the same application, reloading
10319 the cache data, pipeline and shader creation times can potentially be
10320 reduced. What exactly the cache and its serialized version includes is not
10321 specified, is always specific to the backend used, and in some cases also
10322 dependent on the particular implementation of the graphics API.
10323
10324 When the PipelineCacheDataLoadSave is reported as unsupported, the returned
10325 QByteArray is empty.
10326
10327 When the EnablePipelineCacheDataSave flag was not specified when calling
10328 create(), the returned QByteArray may be empty, even when the
10329 PipelineCacheDataLoadSave feature is supported.
10330
10331 When the returned data is non-empty, it is always specific to the Qt
10332 version and QRhi backend. In addition, in some cases there is a strong
10333 dependency to the graphics device and the exact driver version used. QRhi
10334 takes care of adding the appropriate header and safeguards that ensure that
10335 the data can always be passed safely to setPipelineCacheData(), therefore
10336 attempting to load data from a run on another version of a driver will be
10337 handled safely and gracefully.
10338
10339 \note Calling releaseCachedResources() may, depending on the backend, clear
10340 the pipeline data collected. A subsequent call to this function may then
10341 not return any data.
10342
10343 See EnablePipelineCacheDataSave for further details about this feature.
10344
10345 \note Minimize the number of calls to this function. Retrieving the blob is
10346 not always a cheap operation, and therefore this function should only be
10347 called at a low frequency, ideally only once e.g. when closing the
10348 application.
10349
10350 \sa setPipelineCacheData(), create(), isFeatureSupported()
10351 */
10352QByteArray QRhi::pipelineCacheData()
10353{
10354 return d->pipelineCacheData();
10355}
10356
10357/*!
10358 Loads \a data into the pipeline cache, when applicable.
10359
10360 When the PipelineCacheDataLoadSave is reported as unsupported, the function
10361 is safe to call, but has no effect.
10362
10363 The blob returned by pipelineCacheData() is always specific to the Qt
10364 version, the QRhi backend, and, in some cases, also to the graphics device,
10365 and a given version of the graphics driver. QRhi takes care of adding the
10366 appropriate header and safeguards that ensure that the data can always be
10367 passed safely to this function. If there is a mismatch, e.g. because the
10368 driver has been upgraded to a newer version, or because the data was
10369 generated from a different QRhi backend, a warning is printed and \a data
10370 is safely ignored.
10371
10372 With Vulkan, this maps directly to VkPipelineCache. Calling this function
10373 creates a new Vulkan pipeline cache object, with its initial data sourced
10374 from \a data. The pipeline cache object is then used by all subsequently
10375 created QRhiGraphicsPipeline and QRhiComputePipeline objects, thus
10376 accelerating, potentially, the pipeline creation.
10377
10378 With other APIs there is no real pipeline cache, but they may provide a
10379 cache with bytecode from shader compilations (D3D) or program binaries
10380 (OpenGL). In applications that perform a lot of shader compilation from
10381 source at run time this can provide a significant boost in subsequent runs
10382 if the "pipeline cache" is pre-seeded from an earlier run using this
10383 function.
10384
10385 \note QRhi cannot give any guarantees that \a data has an effect on the
10386 pipeline and shader creation performance. With APIs like Vulkan, it is up
10387 to the driver to decide if \a data is used for some purpose, or if it is
10388 ignored.
10389
10390 See EnablePipelineCacheDataSave for further details about this feature.
10391
10392 \note This mechanism offered by QRhi is independent of the drivers' own
10393 internal caching mechanism, if any. This means that, depending on the
10394 graphics API and its implementation, the exact effects of retrieving and
10395 then reloading \a data are not predictable. Improved performance may not be
10396 visible at all in case other caching mechanisms outside of Qt's control are
10397 already active.
10398
10399 \note Minimize the number of calls to this function. Loading the blob is
10400 not always a cheap operation, and therefore this function should only be
10401 called at a low frequency, ideally only once e.g. when starting the
10402 application.
10403
10404 \sa pipelineCacheData(), isFeatureSupported()
10405 */
10406void QRhi::setPipelineCacheData(const QByteArray &data)
10407{
10408 d->setPipelineCacheData(data);
10409}
10410
10411/*!
10412 \struct QRhiStats
10413 \inmodule QtGuiPrivate
10414 \inheaderfile rhi/qrhi.h
10415 \since 6.6
10416
10417 \brief Statistics provided from the underlying memory allocator.
10418
10419 \note This is a RHI API with limited compatibility guarantees, see \l QRhi
10420 for details.
10421 */
10422
10423/*!
10424 \variable QRhiStats::totalPipelineCreationTime
10425
10426 The total time in milliseconds spent in graphics and compute pipeline
10427 creation, which usually involves shader compilation or cache lookups, and
10428 potentially expensive processing.
10429
10430 \note The value should not be compared between different backends since the
10431 concept of "pipelines" and what exactly happens under the hood during, for
10432 instance, a call to QRhiGraphicsPipeline::create(), differ greatly between
10433 graphics APIs and their implementations.
10434
10435 \sa QRhi::statistics()
10436*/
10437
10438/*!
10439 \variable QRhiStats::blockCount
10440
10441 Statistic reported from the Vulkan or D3D12 memory allocator.
10442
10443 \sa QRhi::statistics()
10444*/
10445
10446/*!
10447 \variable QRhiStats::allocCount
10448
10449 Statistic reported from the Vulkan or D3D12 memory allocator.
10450
10451 \sa QRhi::statistics()
10452*/
10453
10454/*!
10455 \variable QRhiStats::usedBytes
10456
10457 Statistic reported from the Vulkan or D3D12 memory allocator.
10458
10459 \sa QRhi::statistics()
10460*/
10461
10462/*!
10463 \variable QRhiStats::unusedBytes
10464
10465 Statistic reported from the Vulkan or D3D12 memory allocator.
10466
10467 \sa QRhi::statistics()
10468*/
10469
10470/*!
10471 \variable QRhiStats::totalUsageBytes
10472
10473 Valid only with D3D12 currently. Matches IDXGIAdapter3::QueryVideoMemoryInfo().
10474
10475 \sa QRhi::statistics()
10476*/
10477
10478#ifndef QT_NO_DEBUG_STREAM
10479QDebug operator<<(QDebug dbg, const QRhiStats &info)
10480{
10481 QDebugStateSaver saver(dbg);
10482 dbg.nospace() << "QRhiStats("
10483 << "totalPipelineCreationTime=" << info.totalPipelineCreationTime
10484 << " blockCount=" << info.blockCount
10485 << " allocCount=" << info.allocCount
10486 << " usedBytes=" << info.usedBytes
10487 << " unusedBytes=" << info.unusedBytes
10488 << " totalUsageBytes=" << info.totalUsageBytes
10489 << ')';
10490 return dbg;
10491}
10492#endif
10493
10494/*!
10495 Gathers and returns statistics about the timings and allocations of
10496 graphics resources.
10497
10498 Data about memory allocations is only available with some backends, where
10499 such operations are under Qt's control. With graphics APIs where there is
10500 no lower level control over resource memory allocations, this will never be
10501 supported and all relevant fields in the results are 0.
10502
10503 With Vulkan in particular, the values are valid always, and are queried
10504 from the underlying memory allocator library. This gives an insight into
10505 the memory requirements of the active buffers and textures.
10506
10507 The same is true for Direct 3D 12. In addition to the memory allocator
10508 library's statistics, here the result also includes a \c totalUsageBytes
10509 field which reports the total size including additional resources that are
10510 not under the memory allocator library's control (swapchain buffers,
10511 descriptor heaps, etc.), as reported by DXGI.
10512
10513 The values correspond to all types of memory used, combined. (i.e. video +
10514 system in case of a discreet GPU)
10515
10516 Additional data, such as the total time in milliseconds spent in graphics
10517 and compute pipeline creation (which usually involves shader compilation or
10518 cache lookups, and potentially expensive processing) is available with most
10519 backends.
10520
10521 \note The elapsed times for operations such as pipeline creation may be
10522 affected by various factors. The results should not be compared between
10523 different backends since the concept of "pipelines" and what exactly
10524 happens under the hood during, for instance, a call to
10525 QRhiGraphicsPipeline::create(), differ greatly between graphics APIs and
10526 their implementations.
10527
10528 \note Additionally, many drivers will likely employ various caching
10529 strategies for shaders, programs, pipelines. (independently of Qt's own
10530 similar facilities, such as setPipelineCacheData() or the OpenGL-specific
10531 program binary disk cache). Because such internal behavior is transparent
10532 to the API client, Qt and QRhi have no knowledge or control over the exact
10533 caching strategy, persistency, invalidation of the cached data, etc. When
10534 reading timings, such as the time spent on pipeline creation, the potential
10535 presence and unspecified behavior of driver-level caching mechanisms should
10536 be kept in mind.
10537 */
10538QRhiStats QRhi::statistics() const
10539{
10540 return d->statistics();
10541}
10542
10543/*!
10544 \return a new graphics pipeline resource.
10545
10546 \sa QRhiResource::destroy()
10547 */
10548QRhiGraphicsPipeline *QRhi::newGraphicsPipeline()
10549{
10550 return d->createGraphicsPipeline();
10551}
10552
10553/*!
10554 \return a new compute pipeline resource.
10555
10556 \note Compute is only available when the \l{QRhi::Compute}{Compute} feature
10557 is reported as supported.
10558
10559 \sa QRhiResource::destroy()
10560 */
10561QRhiComputePipeline *QRhi::newComputePipeline()
10562{
10563 return d->createComputePipeline();
10564}
10565
10566/*!
10567 \return a new shader resource binding collection resource.
10568
10569 \sa QRhiResource::destroy()
10570 */
10571QRhiShaderResourceBindings *QRhi::newShaderResourceBindings()
10572{
10573 return d->createShaderResourceBindings();
10574}
10575
10576/*!
10577 \return a new buffer with the specified \a type, \a usage, and \a size.
10578
10579 \note Some \a usage and \a type combinations may not be supported by all
10580 backends. See \l{QRhiBuffer::UsageFlag}{UsageFlags} and
10581 \l{QRhi::NonDynamicUniformBuffers}{the feature flags}.
10582
10583 \note Backends may choose to allocate buffers bigger than \a size. This is
10584 done transparently to applications, so there are no special restrictions on
10585 the value of \a size. QRhiBuffer::size() will always report back the value
10586 that was requested in \a size.
10587
10588 \sa QRhiResource::destroy()
10589 */
10590QRhiBuffer *QRhi::newBuffer(QRhiBuffer::Type type,
10591 QRhiBuffer::UsageFlags usage,
10592 quint32 size)
10593{
10594 return d->createBuffer(type, usage, size);
10595}
10596
10597/*!
10598 \return a new renderbuffer with the specified \a type, \a pixelSize, \a
10599 sampleCount, and \a flags.
10600
10601 When \a backingFormatHint is set to a texture format other than
10602 QRhiTexture::UnknownFormat, it may be used by the backend to decide what
10603 format to use for the storage backing the renderbuffer.
10604
10605 \note \a backingFormatHint becomes relevant typically when multisampling
10606 and floating point texture formats are involved: rendering into a
10607 multisample QRhiRenderBuffer and then resolving into a non-RGBA8
10608 QRhiTexture implies (with some graphics APIs) that the storage backing the
10609 QRhiRenderBuffer uses the matching non-RGBA8 format. That means that
10610 passing a format like QRhiTexture::RGBA32F is important, because backends
10611 will typically opt for QRhiTexture::RGBA8 by default, which would then
10612 break later on due to attempting to set up RGBA8->RGBA32F multisample
10613 resolve in the color attachment(s) of the QRhiTextureRenderTarget.
10614
10615 \sa QRhiResource::destroy()
10616 */
10617QRhiRenderBuffer *QRhi::newRenderBuffer(QRhiRenderBuffer::Type type,
10618 const QSize &pixelSize,
10619 int sampleCount,
10620 QRhiRenderBuffer::Flags flags,
10621 QRhiTexture::Format backingFormatHint)
10622{
10623 return d->createRenderBuffer(type, pixelSize, sampleCount, flags, backingFormatHint);
10624}
10625
10626/*!
10627 \return a new 1D or 2D texture with the specified \a format, \a pixelSize, \a
10628 sampleCount, and \a flags.
10629
10630 A 1D texture array must have QRhiTexture::OneDimensional set in \a flags. This
10631 function will implicitly set this flag if the \a pixelSize height is 0.
10632
10633 \note \a format specifies the requested internal and external format,
10634 meaning the data to be uploaded to the texture will need to be in a
10635 compatible format, while the native texture may (but is not guaranteed to,
10636 in case of OpenGL at least) use this format internally.
10637
10638 \note 1D textures are only functional when the OneDimensionalTextures feature is
10639 reported as supported at run time. Further, mipmaps on 1D textures are only
10640 functional when the OneDimensionalTextureMipmaps feature is reported at run time.
10641
10642 \sa QRhiResource::destroy()
10643 */
10644QRhiTexture *QRhi::newTexture(QRhiTexture::Format format,
10645 const QSize &pixelSize,
10646 int sampleCount,
10647 QRhiTexture::Flags flags)
10648{
10649 if (pixelSize.height() == 0)
10650 flags |= QRhiTexture::OneDimensional;
10651
10652 return d->createTexture(format, pixelSize, depth: 1, arraySize: 0, sampleCount, flags);
10653}
10654
10655/*!
10656 \return a new 1D, 2D or 3D texture with the specified \a format, \a width, \a
10657 height, \a depth, \a sampleCount, and \a flags.
10658
10659 This overload is suitable for 3D textures because it allows specifying \a
10660 depth. A 3D texture must have QRhiTexture::ThreeDimensional set in \a
10661 flags, but using this overload that can be omitted because the flag is set
10662 implicitly whenever \a depth is greater than 0. For 1D, 2D and cube textures \a
10663 depth should be set to 0.
10664
10665 A 1D texture must have QRhiTexture::OneDimensional set in \a flags. This overload
10666 will implicitly set this flag if both \a height and \a depth are 0.
10667
10668 \note 3D textures are only functional when the ThreeDimensionalTextures
10669 feature is reported as supported at run time.
10670
10671 \note 1D textures are only functional when the OneDimensionalTextures feature is
10672 reported as supported at run time. Further, mipmaps on 1D textures are only
10673 functional when the OneDimensionalTextureMipmaps feature is reported at run time.
10674
10675 \overload
10676 */
10677QRhiTexture *QRhi::newTexture(QRhiTexture::Format format,
10678 int width, int height, int depth,
10679 int sampleCount,
10680 QRhiTexture::Flags flags)
10681{
10682 if (depth > 0)
10683 flags |= QRhiTexture::ThreeDimensional;
10684
10685 if (height == 0 && depth == 0)
10686 flags |= QRhiTexture::OneDimensional;
10687
10688 return d->createTexture(format, pixelSize: QSize(width, height), depth, arraySize: 0, sampleCount, flags);
10689}
10690
10691/*!
10692 \return a new 1D or 2D texture array with the specified \a format, \a arraySize,
10693 \a pixelSize, \a sampleCount, and \a flags.
10694
10695 This function implicitly sets QRhiTexture::TextureArray in \a flags.
10696
10697 A 1D texture array must have QRhiTexture::OneDimensional set in \a flags. This
10698 function will implicitly set this flag if the \a pixelSize height is 0.
10699
10700 \note Do not confuse texture arrays with arrays of textures. A QRhiTexture
10701 created by this function is usable with 1D or 2D array samplers in the shader, for
10702 example: \c{layout(binding = 1) uniform sampler2DArray texArr;}. Arrays of
10703 textures refers to a list of textures that are exposed to the shader via
10704 QRhiShaderResourceBinding::sampledTextures() and a count > 1, and declared
10705 in the shader for example like this: \c{layout(binding = 1) uniform
10706 sampler2D textures[4];}
10707
10708 \note This is only functional when the TextureArrays feature is reported as
10709 supported at run time.
10710
10711 \note 1D textures are only functional when the OneDimensionalTextures feature is
10712 reported as supported at run time. Further, mipmaps on 1D textures are only
10713 functional when the OneDimensionalTextureMipmaps feature is reported at run time.
10714
10715
10716 \sa newTexture()
10717 */
10718QRhiTexture *QRhi::newTextureArray(QRhiTexture::Format format,
10719 int arraySize,
10720 const QSize &pixelSize,
10721 int sampleCount,
10722 QRhiTexture::Flags flags)
10723{
10724 flags |= QRhiTexture::TextureArray;
10725
10726 if (pixelSize.height() == 0)
10727 flags |= QRhiTexture::OneDimensional;
10728
10729 return d->createTexture(format, pixelSize, depth: 1, arraySize, sampleCount, flags);
10730}
10731
10732/*!
10733 \return a new sampler with the specified magnification filter \a magFilter,
10734 minification filter \a minFilter, mipmapping mode \a mipmapMode, and the
10735 addressing (wrap) modes \a addressU, \a addressV, and \a addressW.
10736
10737 \note Setting \a mipmapMode to a value other than \c None implies that
10738 images for all relevant mip levels will be provided either via
10739 \l{QRhiResourceUpdateBatch::uploadTexture()}{texture uploads} or by calling
10740 \l{QRhiResourceUpdateBatch::generateMips()}{generateMips()} on the texture
10741 that is used with this sampler. Attempting to use the sampler with a
10742 texture that has no data for all relevant mip levels will lead to rendering
10743 errors, with the exact behavior dependent on the underlying graphics API.
10744
10745 \sa QRhiResource::destroy()
10746 */
10747QRhiSampler *QRhi::newSampler(QRhiSampler::Filter magFilter,
10748 QRhiSampler::Filter minFilter,
10749 QRhiSampler::Filter mipmapMode,
10750 QRhiSampler::AddressMode addressU,
10751 QRhiSampler::AddressMode addressV,
10752 QRhiSampler::AddressMode addressW)
10753{
10754 return d->createSampler(magFilter, minFilter, mipmapMode, u: addressU, v: addressV, w: addressW);
10755}
10756
10757/*!
10758 \return a new texture render target with color and depth/stencil
10759 attachments given in \a desc, and with the specified \a flags.
10760
10761 \sa QRhiResource::destroy()
10762 */
10763
10764QRhiTextureRenderTarget *QRhi::newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
10765 QRhiTextureRenderTarget::Flags flags)
10766{
10767 return d->createTextureRenderTarget(desc, flags);
10768}
10769
10770/*!
10771 \return a new swapchain.
10772
10773 \sa QRhiResource::destroy(), QRhiSwapChain::createOrResize()
10774 */
10775QRhiSwapChain *QRhi::newSwapChain()
10776{
10777 return d->createSwapChain();
10778}
10779
10780/*!
10781 Starts a new frame targeting the next available buffer of \a swapChain.
10782
10783 A frame consists of resource updates and one or more render and compute
10784 passes.
10785
10786 \a flags can indicate certain special cases.
10787
10788 The high level pattern of rendering into a QWindow using a swapchain:
10789
10790 \list
10791
10792 \li Create a swapchain.
10793
10794 \li Call QRhiSwapChain::createOrResize() whenever the surface size is
10795 different than before.
10796
10797 \li Call QRhiSwapChain::destroy() on
10798 QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed.
10799
10800 \li Then on every frame:
10801 \badcode
10802 beginFrame(sc);
10803 updates = nextResourceUpdateBatch();
10804 updates->...
10805 QRhiCommandBuffer *cb = sc->currentFrameCommandBuffer();
10806 cb->beginPass(sc->currentFrameRenderTarget(), colorClear, dsClear, updates);
10807 ...
10808 cb->endPass();
10809 ... // more passes as necessary
10810 endFrame(sc);
10811 \endcode
10812
10813 \endlist
10814
10815 \return QRhi::FrameOpSuccess on success, or another QRhi::FrameOpResult
10816 value on failure. Some of these should be treated as soft, "try again
10817 later" type of errors: When QRhi::FrameOpSwapChainOutOfDate is returned,
10818 the swapchain is to be resized or updated by calling
10819 QRhiSwapChain::createOrResize(). The application should then attempt to
10820 generate a new frame. QRhi::FrameOpDeviceLost means the graphics device is
10821 lost but this may also be recoverable by releasing all resources, including
10822 the QRhi itself, and then recreating all resources. See isDeviceLost() for
10823 further discussion.
10824
10825 \sa endFrame(), beginOffscreenFrame(), isDeviceLost()
10826 */
10827QRhi::FrameOpResult QRhi::beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags flags)
10828{
10829 if (d->inFrame)
10830 qWarning(msg: "Attempted to call beginFrame() within a still active frame; ignored");
10831
10832 if (d->rubLogEnabled)
10833 qDebug(msg: "[rub] new frame");
10834
10835 QRhi::FrameOpResult r = !d->inFrame ? d->beginFrame(swapChain, flags) : FrameOpSuccess;
10836 if (r == FrameOpSuccess)
10837 d->inFrame = true;
10838
10839 return r;
10840}
10841
10842/*!
10843 Ends, commits, and presents a frame that was started in the last
10844 beginFrame() on \a swapChain.
10845
10846 Double (or triple) buffering is managed internally by the QRhiSwapChain and
10847 QRhi.
10848
10849 \a flags can optionally be used to change the behavior in certain ways.
10850 Passing QRhi::SkipPresent skips queuing the Present command or calling
10851 swapBuffers.
10852
10853 \return QRhi::FrameOpSuccess on success, or another QRhi::FrameOpResult
10854 value on failure. Some of these should be treated as soft, "try again
10855 later" type of errors: When QRhi::FrameOpSwapChainOutOfDate is returned,
10856 the swapchain is to be resized or updated by calling
10857 QRhiSwapChain::createOrResize(). The application should then attempt to
10858 generate a new frame. QRhi::FrameOpDeviceLost means the graphics device is
10859 lost but this may also be recoverable by releasing all resources, including
10860 the QRhi itself, and then recreating all resources. See isDeviceLost() for
10861 further discussion.
10862
10863 \sa beginFrame(), isDeviceLost()
10864 */
10865QRhi::FrameOpResult QRhi::endFrame(QRhiSwapChain *swapChain, EndFrameFlags flags)
10866{
10867 if (!d->inFrame)
10868 qWarning(msg: "Attempted to call endFrame() without an active frame; ignored");
10869
10870 QRhi::FrameOpResult r = d->inFrame ? d->endFrame(swapChain, flags) : FrameOpSuccess;
10871 d->inFrame = false;
10872 // deleteLater is a high level QRhi concept the backends know
10873 // nothing about - handle it here.
10874 qDeleteAll(c: d->pendingDeleteResources);
10875 d->pendingDeleteResources.clear();
10876
10877 return r;
10878}
10879
10880/*!
10881 \return true when there is an active frame, meaning there was a
10882 beginFrame() (or beginOffscreenFrame()) with no corresponding endFrame()
10883 (or endOffscreenFrame()) yet.
10884
10885 \sa currentFrameSlot(), beginFrame(), endFrame()
10886 */
10887bool QRhi::isRecordingFrame() const
10888{
10889 return d->inFrame;
10890}
10891
10892/*!
10893 \return the current frame slot index while recording a frame. Unspecified
10894 when called outside an active frame (that is, when isRecordingFrame() is \c
10895 false).
10896
10897 With backends like Vulkan or Metal, it is the responsibility of the QRhi
10898 backend to block whenever starting a new frame and finding the CPU is
10899 already \c{FramesInFlight - 1} frames ahead of the GPU (because the command
10900 buffer submitted in frame no. \c{current} - \c{FramesInFlight} has not yet
10901 completed).
10902
10903 Resources that tend to change between frames (such as, the native buffer
10904 object backing a QRhiBuffer with type QRhiBuffer::Dynamic) exist in
10905 multiple versions, so that each frame, that can be submitted while a
10906 previous one is still being processed, works with its own copy, thus
10907 avoiding the need to stall the pipeline when preparing the frame. (The
10908 contents of a resource that may still be in use in the GPU should not be
10909 touched, but simply always waiting for the previous frame to finish would
10910 reduce GPU utilization and ultimately, performance and efficiency.)
10911
10912 Conceptually this is somewhat similar to copy-on-write schemes used by some
10913 C++ containers and other types. It may also be similar to what an OpenGL or
10914 Direct 3D 11 implementation performs internally for certain type of objects.
10915
10916 In practice, such double (or triple) buffering resources is realized in
10917 the Vulkan, Metal, and similar QRhi backends by having a fixed number of
10918 native resource (such as, VkBuffer) \c slots behind a QRhiResource. That
10919 can then be indexed by a frame slot index running 0, 1, ..,
10920 FramesInFlight-1, and then wrapping around.
10921
10922 All this is managed transparently to the users of QRhi. However,
10923 applications that integrate rendering done directly with the graphics API
10924 may want to perform a similar double or triple buffering of their own
10925 graphics resources. That is then most easily achieved by knowing the values
10926 of the maximum number of in-flight frames (retrievable via resourceLimit())
10927 and the current frame (slot) index (returned by this function).
10928
10929 \sa isRecordingFrame(), beginFrame(), endFrame()
10930 */
10931int QRhi::currentFrameSlot() const
10932{
10933 return d->currentFrameSlot;
10934}
10935
10936/*!
10937 Starts a new offscreen frame. Provides a command buffer suitable for
10938 recording rendering commands in \a cb. \a flags is used to indicate
10939 certain special cases, just like with beginFrame().
10940
10941 \note The QRhiCommandBuffer stored to *cb is not owned by the caller.
10942
10943 Rendering without a swapchain is possible as well. The typical use case is
10944 to use it in completely offscreen applications, e.g. to generate image
10945 sequences by rendering and reading back without ever showing a window.
10946
10947 Usage in on-screen applications (so beginFrame, endFrame,
10948 beginOffscreenFrame, endOffscreenFrame, beginFrame, ...) is possible too
10949 but it does reduce parallelism so it should be done only infrequently.
10950
10951 Offscreen frames do not let the CPU potentially generate another frame
10952 while the GPU is still processing the previous one. This has the side
10953 effect that if readbacks are scheduled, the results are guaranteed to be
10954 available once endOffscreenFrame() returns. That is not the case with
10955 frames targeting a swapchain: there the GPU is potentially better utilized,
10956 but working with readback operations needs more care from the application
10957 because endFrame(), unlike endOffscreenFrame(), does not guarantee that the
10958 results from the readback are available at that point.
10959
10960 The skeleton of rendering a frame without a swapchain and then reading the
10961 frame contents back could look like the following:
10962
10963 \code
10964 QRhiReadbackResult rbResult;
10965 QRhiCommandBuffer *cb;
10966 rhi->beginOffscreenFrame(&cb);
10967 cb->beginPass(rt, colorClear, dsClear);
10968 // ...
10969 u = nextResourceUpdateBatch();
10970 u->readBackTexture(rb, &rbResult);
10971 cb->endPass(u);
10972 rhi->endOffscreenFrame();
10973 // image data available in rbResult
10974 \endcode
10975
10976 \sa endOffscreenFrame(), beginFrame()
10977 */
10978QRhi::FrameOpResult QRhi::beginOffscreenFrame(QRhiCommandBuffer **cb, BeginFrameFlags flags)
10979{
10980 if (d->inFrame)
10981 qWarning(msg: "Attempted to call beginOffscreenFrame() within a still active frame; ignored");
10982
10983 if (d->rubLogEnabled)
10984 qDebug(msg: "[rub] new offscreen frame");
10985
10986 QRhi::FrameOpResult r = !d->inFrame ? d->beginOffscreenFrame(cb, flags) : FrameOpSuccess;
10987 if (r == FrameOpSuccess)
10988 d->inFrame = true;
10989
10990 return r;
10991}
10992
10993/*!
10994 Ends, submits, and waits for the offscreen frame.
10995
10996 \a flags is not currently used.
10997
10998 \sa beginOffscreenFrame()
10999 */
11000QRhi::FrameOpResult QRhi::endOffscreenFrame(EndFrameFlags flags)
11001{
11002 if (!d->inFrame)
11003 qWarning(msg: "Attempted to call endOffscreenFrame() without an active frame; ignored");
11004
11005 QRhi::FrameOpResult r = d->inFrame ? d->endOffscreenFrame(flags) : FrameOpSuccess;
11006 d->inFrame = false;
11007 qDeleteAll(c: d->pendingDeleteResources);
11008 d->pendingDeleteResources.clear();
11009
11010 return r;
11011}
11012
11013/*!
11014 Waits for any work on the graphics queue (where applicable) to complete,
11015 then executes all deferred operations, like completing readbacks and
11016 resource releases. Can be called inside and outside of a frame, but not
11017 inside a pass. Inside a frame it implies submitting any work on the
11018 command buffer.
11019
11020 \note Avoid this function. One case where it may be needed is when the
11021 results of an enqueued readback in a swapchain-based frame are needed at a
11022 fixed given point and so waiting for the results is desired.
11023 */
11024QRhi::FrameOpResult QRhi::finish()
11025{
11026 return d->finish();
11027}
11028
11029/*!
11030 \return the list of supported sample counts.
11031
11032 A typical example would be (1, 2, 4, 8).
11033
11034 With some backend this list of supported values is fixed in advance, while
11035 with some others the (physical) device properties indicate what is
11036 supported at run time.
11037
11038 \sa QRhiRenderBuffer::setSampleCount(), QRhiTexture::setSampleCount(),
11039 QRhiGraphicsPipeline::setSampleCount(), QRhiSwapChain::setSampleCount()
11040 */
11041QList<int> QRhi::supportedSampleCounts() const
11042{
11043 return d->supportedSampleCounts();
11044}
11045
11046/*!
11047 \return the minimum uniform buffer offset alignment in bytes. This is
11048 typically 256.
11049
11050 Attempting to bind a uniform buffer region with an offset not aligned to
11051 this value will lead to failures depending on the backend and the
11052 underlying graphics API.
11053
11054 \sa ubufAligned()
11055 */
11056int QRhi::ubufAlignment() const
11057{
11058 return d->ubufAlignment();
11059}
11060
11061Q_CONSTINIT static QBasicAtomicInteger<QRhiGlobalObjectIdGenerator::Type> counter = Q_BASIC_ATOMIC_INITIALIZER(0);
11062
11063QRhiGlobalObjectIdGenerator::Type QRhiGlobalObjectIdGenerator::newId()
11064{
11065 return counter.fetchAndAddRelaxed(valueToAdd: 1) + 1;
11066}
11067
11068bool QRhiPassResourceTracker::isEmpty() const
11069{
11070 return m_buffers.isEmpty() && m_textures.isEmpty();
11071}
11072
11073void QRhiPassResourceTracker::reset()
11074{
11075 m_buffers.clear();
11076 m_textures.clear();
11077}
11078
11079static inline QRhiPassResourceTracker::BufferStage earlierStage(QRhiPassResourceTracker::BufferStage a,
11080 QRhiPassResourceTracker::BufferStage b)
11081{
11082 return QRhiPassResourceTracker::BufferStage(qMin(a: int(a), b: int(b)));
11083}
11084
11085void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage,
11086 const UsageState &state)
11087{
11088 auto it = m_buffers.find(key: buf);
11089 if (it != m_buffers.end()) {
11090 if (it->access != *access) {
11091 const QByteArray name = buf->name();
11092 qWarning(msg: "Buffer %p (%s) used with different accesses within the same pass, this is not allowed.",
11093 buf, name.constData());
11094 return;
11095 }
11096 if (it->stage != *stage) {
11097 it->stage = earlierStage(a: it->stage, b: *stage);
11098 *stage = it->stage;
11099 }
11100 return;
11101 }
11102
11103 Buffer b;
11104 b.slot = slot;
11105 b.access = *access;
11106 b.stage = *stage;
11107 b.stateAtPassBegin = state; // first use -> initial state
11108 m_buffers.insert(key: buf, value: b);
11109}
11110
11111static inline QRhiPassResourceTracker::TextureStage earlierStage(QRhiPassResourceTracker::TextureStage a,
11112 QRhiPassResourceTracker::TextureStage b)
11113{
11114 return QRhiPassResourceTracker::TextureStage(qMin(a: int(a), b: int(b)));
11115}
11116
11117static inline bool isImageLoadStore(QRhiPassResourceTracker::TextureAccess access)
11118{
11119 return access == QRhiPassResourceTracker::TexStorageLoad
11120 || access == QRhiPassResourceTracker::TexStorageStore
11121 || access == QRhiPassResourceTracker::TexStorageLoadStore;
11122}
11123
11124void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage,
11125 const UsageState &state)
11126{
11127 auto it = m_textures.find(key: tex);
11128 if (it != m_textures.end()) {
11129 if (it->access != *access) {
11130 // Different subresources of a texture may be used for both load
11131 // and store in the same pass. (think reading from one mip level
11132 // and writing to another one in a compute shader) This we can
11133 // handle by treating the entire resource as read-write.
11134 if (isImageLoadStore(access: it->access) && isImageLoadStore(access: *access)) {
11135 it->access = QRhiPassResourceTracker::TexStorageLoadStore;
11136 *access = it->access;
11137 } else {
11138 const QByteArray name = tex->name();
11139 qWarning(msg: "Texture %p (%s) used with different accesses within the same pass, this is not allowed.",
11140 tex, name.constData());
11141 }
11142 }
11143 if (it->stage != *stage) {
11144 it->stage = earlierStage(a: it->stage, b: *stage);
11145 *stage = it->stage;
11146 }
11147 return;
11148 }
11149
11150 Texture t;
11151 t.access = *access;
11152 t.stage = *stage;
11153 t.stateAtPassBegin = state; // first use -> initial state
11154 m_textures.insert(key: tex, value: t);
11155}
11156
11157QRhiPassResourceTracker::BufferStage QRhiPassResourceTracker::toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages)
11158{
11159 // pick the earlier stage (as this is going to be dstAccessMask)
11160 if (stages.testFlag(flag: QRhiShaderResourceBinding::VertexStage))
11161 return QRhiPassResourceTracker::BufVertexStage;
11162 if (stages.testFlag(flag: QRhiShaderResourceBinding::TessellationControlStage))
11163 return QRhiPassResourceTracker::BufTCStage;
11164 if (stages.testFlag(flag: QRhiShaderResourceBinding::TessellationEvaluationStage))
11165 return QRhiPassResourceTracker::BufTEStage;
11166 if (stages.testFlag(flag: QRhiShaderResourceBinding::FragmentStage))
11167 return QRhiPassResourceTracker::BufFragmentStage;
11168 if (stages.testFlag(flag: QRhiShaderResourceBinding::ComputeStage))
11169 return QRhiPassResourceTracker::BufComputeStage;
11170 if (stages.testFlag(flag: QRhiShaderResourceBinding::GeometryStage))
11171 return QRhiPassResourceTracker::BufGeometryStage;
11172
11173 Q_UNREACHABLE_RETURN(QRhiPassResourceTracker::BufVertexStage);
11174}
11175
11176QRhiPassResourceTracker::TextureStage QRhiPassResourceTracker::toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages)
11177{
11178 // pick the earlier stage (as this is going to be dstAccessMask)
11179 if (stages.testFlag(flag: QRhiShaderResourceBinding::VertexStage))
11180 return QRhiPassResourceTracker::TexVertexStage;
11181 if (stages.testFlag(flag: QRhiShaderResourceBinding::TessellationControlStage))
11182 return QRhiPassResourceTracker::TexTCStage;
11183 if (stages.testFlag(flag: QRhiShaderResourceBinding::TessellationEvaluationStage))
11184 return QRhiPassResourceTracker::TexTEStage;
11185 if (stages.testFlag(flag: QRhiShaderResourceBinding::FragmentStage))
11186 return QRhiPassResourceTracker::TexFragmentStage;
11187 if (stages.testFlag(flag: QRhiShaderResourceBinding::ComputeStage))
11188 return QRhiPassResourceTracker::TexComputeStage;
11189 if (stages.testFlag(flag: QRhiShaderResourceBinding::GeometryStage))
11190 return QRhiPassResourceTracker::TexGeometryStage;
11191
11192 Q_UNREACHABLE_RETURN(QRhiPassResourceTracker::TexVertexStage);
11193}
11194
11195QT_END_NAMESPACE
11196

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtbase/src/gui/rhi/qrhi.cpp