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 defined(Q_OS_MACOS) || defined(Q_OS_IOS) |
20 | #include "qrhimetal_p.h" |
21 | #endif |
22 | |
23 | #include <memory> |
24 | |
25 | QT_BEGIN_NAMESPACE |
26 | |
27 | Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general" ) |
28 | |
29 | /*! |
30 | \class QRhi |
31 | \ingroup painting-3D |
32 | \inmodule QtGui |
33 | \since 6.6 |
34 | |
35 | \brief Accelerated 2D/3D graphics API abstraction. |
36 | |
37 | The Qt Rendering Hardware Interface is an abstraction for hardware accelerated |
38 | graphics APIs, such as, \l{https://www.khronos.org/opengl/}{OpenGL}, |
39 | \l{https://www.khronos.org/opengles/}{OpenGL ES}, |
40 | \l{https://docs.microsoft.com/en-us/windows/desktop/direct3d}{Direct3D}, |
41 | \l{https://developer.apple.com/metal/}{Metal}, and |
42 | \l{https://www.khronos.org/vulkan/}{Vulkan}. |
43 | |
44 | \warning The QRhi family of classes in the Qt Gui module, including QShader |
45 | and QShaderDescription, offer limited compatibility guarantees. There are |
46 | no source or binary compatibility guarantees for these classes, meaning the |
47 | API is only guaranteed to work with the Qt version the application was |
48 | developed against. Source incompatible changes are however aimed to be kept |
49 | at a minimum and will only be made in minor releases (6.7, 6.8, and so on). |
50 | To use these classes in an application, link to |
51 | \c{Qt::GuiPrivate} (if using CMake), and include the headers with the \c |
52 | rhi prefix, for example \c{#include <rhi/qrhi.h>}. |
53 | |
54 | Each QRhi instance is backed by a backend for a specific graphics API. The |
55 | selection of the backend is a run time choice and is up to the application |
56 | or library that creates the QRhi instance. Some backends are available on |
57 | multiple platforms (OpenGL, Vulkan, Null), while APIs specific to a given |
58 | platform are only available when running on the platform in question (Metal |
59 | on macOS/iOS, Direct3D on Windows). |
60 | |
61 | The available backends currently are: |
62 | |
63 | \list |
64 | |
65 | \li OpenGL 2.1 / OpenGL ES 2.0 or newer. Some extensions and newer core |
66 | specification features are utilized when present, for example to enable |
67 | multisample framebuffers or compute shaders. Operating in core profile |
68 | contexts is supported as well. If necessary, applications can query the |
69 | \l{QRhi::Feature}{feature flags} at runtime to check for features that are |
70 | not supported in the OpenGL context backing the QRhi. The OpenGL backend |
71 | builds on QOpenGLContext, QOpenGLFunctions, and the related cross-platform |
72 | infrastructure of the Qt GUI module. |
73 | |
74 | \li Direct3D 11.1 or newer, with Shader Model 5.0 or newer. When the D3D |
75 | runtime has no support for 11.1 features or Shader Model 5.0, |
76 | initialization using an accelerated graphics device will fail, but using |
77 | the |
78 | \l{https://learn.microsoft.com/en-us/windows/win32/direct3darticles/directx-warp}{software |
79 | adapter} is still an option. |
80 | |
81 | \li Direct3D 12.0 or newer, with Shader Model 5.0 or newer. The D3D12 |
82 | device is by default created with specifying a minimum feature level of |
83 | \c{D3D_FEATURE_LEVEL_11_0}. |
84 | |
85 | \li Metal 1.2 or newer. |
86 | |
87 | \li Vulkan 1.0 or newer, optionally utilizing some Vulkan 1.1 level |
88 | features. |
89 | |
90 | \li Null, a "dummy" backend that issues no graphics calls at all. |
91 | |
92 | \endlist |
93 | |
94 | In order to allow shader code to be written once in Qt applications and |
95 | libraries, all shaders are expected to be written in a single language |
96 | which is then compiled into SPIR-V. Versions for various shading language |
97 | are then generated from that, together with reflection information (inputs, |
98 | outputs, shader resources). This is then packed into easily and efficiently |
99 | serializable QShader instances. The compilers and tools to generate such |
100 | shaders are not part of QRhi and the Qt GUI module, but the core classes |
101 | for using such shaders, QShader and QShaderDescription, are. The APIs and |
102 | tools for performing compilation and translation are part of the Qt Shader |
103 | Tools module. |
104 | |
105 | See the \l{RHI Window Example} for an introductory example of creating a |
106 | portable, cross-platform application that performs accelerated 3D rendering |
107 | onto a QWindow using QRhi. |
108 | |
109 | \section1 An Impression of the API |
110 | |
111 | To provide a quick look at the API with a short yet complete example that |
112 | does not involve window-related setup, the following is a complete, |
113 | runnable cross-platform application that renders 20 frames off-screen, and |
114 | then saves the generated images to files after reading back the texture |
115 | contents from the GPU. For an example that renders on-screen, which then |
116 | involves setting up a QWindow and a swapchain, refer to the |
117 | \l{RHI Window Example}. |
118 | |
119 | For brevity, the initialization of the QRhi is done based on the platform: |
120 | the sample code here chooses Direct 3D 12 on Windows, Metal on macOS and |
121 | iOS, and Vulkan otherwise. OpenGL and Direct 3D 11 are never used by this |
122 | application, but support for those could be introduced with a few |
123 | additional lines. |
124 | |
125 | \snippet rhioffscreen/main.cpp 0 |
126 | |
127 | The result of the application is 20 \c PNG images (frame0.png - |
128 | frame19.png). These contain a rotating triangle with varying opacity over a |
129 | green background. |
130 | |
131 | The vertex and fragment shaders are expected to be processed and packaged |
132 | into \c{.qsb} files. The Vulkan-compatible GLSL source code is the |
133 | following: |
134 | |
135 | \e color.vert |
136 | \snippet rhioffscreen/color.vert 0 |
137 | |
138 | \e color.frag |
139 | \snippet rhioffscreen/color.frag 0 |
140 | |
141 | To manually compile and transpile these shaders to a number of targets |
142 | (SPIR-V, HLSL, MSL, GLSL) and generate the \c{.qsb} files the application |
143 | loads at run time, run \c{qsb --qt6 color.vert -o color.vert.qsb} and |
144 | \c{qsb --qt6 color.frag -o color.frag.qsb}. Alternatively, the Qt Shader |
145 | Tools module offers build system integration for CMake, the |
146 | \c qt_add_shaders() CMake function, that can achieve the same at build time. |
147 | |
148 | \section1 Design Fundamentals |
149 | |
150 | A QRhi cannot be instantiated directly. Instead, use the create() |
151 | function. Delete the QRhi instance normally to release the graphics device. |
152 | |
153 | \section2 Resources |
154 | |
155 | Instances of classes deriving from QRhiResource, such as, QRhiBuffer, |
156 | QRhiTexture, etc., encapsulate zero, one, or more native graphics |
157 | resources. Instances of such classes are always created via the \c new |
158 | functions of the QRhi, such as, newBuffer(), newTexture(), |
159 | newTextureRenderTarget(), newSwapChain(). |
160 | |
161 | \code |
162 | QRhiBuffer *vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)); |
163 | if (!vbuf->create()) { error(); } |
164 | // ... |
165 | delete vbuf; |
166 | \endcode |
167 | |
168 | \list |
169 | |
170 | \li The returned value from functions like newBuffer() is always owned by |
171 | the caller. |
172 | |
173 | \li Just creating an instance of a QRhiResource subclass never allocates or |
174 | initializes any native resources. That is only done when calling the |
175 | \c create() function of a subclass, for example, QRhiBuffer::create() or |
176 | QRhiTexture::create(). |
177 | |
178 | \li The exceptions are |
179 | QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor(), |
180 | QRhiSwapChain::newCompatibleRenderPassDescriptor(), and |
181 | QRhiRenderPassDescriptor::newCompatibleRenderPassDescriptor(). There is no |
182 | \c create() operation for these and the returned object is immediately |
183 | active. |
184 | |
185 | \li The resource objects themselves are treated as immutable: once a |
186 | resource has create() called, changing any parameters via the setters, such as, |
187 | QRhiTexture::setPixelSize(), has no effect, unless the underlying native |
188 | resource is released and \c create() is called again. See more about resource |
189 | reuse in the sections below. |
190 | |
191 | \li The underlying native resources are scheduled for releasing by the |
192 | QRhiResource destructor, or by calling QRhiResource::destroy(). Backends |
193 | often queue release requests and defer executing them to an unspecified |
194 | time, this is hidden from the applications. This way applications do not |
195 | have to worry about releasing native resources that may still be in use by |
196 | an in-flight frame. |
197 | |
198 | \li Note that this does not mean that a QRhiResource can freely be |
199 | destroy()'ed or deleted within a frame (that is, in a |
200 | \l{QRhi::beginFrame()}{beginFrame()} - \l{QRhi::endFrame()}{endFrame()} |
201 | section). As a general rule, all referenced QRhiResource objects must stay |
202 | unchanged until the frame is submitted by calling |
203 | \l{QRhi::endFrame()}{endFrame()}. To ease this, |
204 | QRhiResource::deleteLater() is provided as a convenience. |
205 | |
206 | \endlist |
207 | |
208 | \section2 Command buffers and deferred command execution |
209 | |
210 | Regardless of the design and capabilities of the underlying graphics API, |
211 | all QRhi backends implement some level of command buffers. No |
212 | QRhiCommandBuffer function issues any native bind or draw command (such as, |
213 | \c glDrawElements) directly. Commands are always recorded in a queue, |
214 | either native or provided by the QRhi backend. The command buffer is |
215 | submitted, and so execution starts only upon QRhi::endFrame() or |
216 | QRhi::finish(). |
217 | |
218 | The deferred nature has consequences for some types of objects. For example, |
219 | writing to a dynamic buffer multiple times within a frame, in case such |
220 | buffers are backed by host-visible memory, will result in making the |
221 | results of all writes are visible to all draw calls in the command buffer |
222 | of the frame, regardless of when the dynamic buffer update was recorded |
223 | relative to a draw call. |
224 | |
225 | Furthermore, instances of QRhiResource subclasses must be treated immutable |
226 | within a frame in which they are referenced in any way. Create |
227 | all resources upfront, before starting to record commands for the next |
228 | frame. Reusing a QRhiResource instance within a frame (by calling \c create() |
229 | then referencing it again in the same \c{beginFrame - endFrame} section) |
230 | should be avoided as it may lead to unexpected results, depending on the |
231 | backend. |
232 | |
233 | As a general rule, all referenced QRhiResource objects must stay valid and |
234 | unmodified until the frame is submitted by calling |
235 | \l{QRhi::endFrame()}{endFrame()}. On the other hand, calling |
236 | \l{QRhiResource::destroy()}{destroy()} or deleting the QRhiResource are |
237 | always safe once the frame is submitted, regardless of the status of the |
238 | underlying native resources (which may still be in use by the GPU - but |
239 | that is taken care of internally). |
240 | |
241 | Unlike APIs like OpenGL, upload and copy type of commands cannot be mixed |
242 | with draw commands. The typical renderer will involve a sequence similar to |
243 | the following: |
244 | |
245 | \list |
246 | \li (re)create resources |
247 | \li begin frame |
248 | \li record/issue uploads and copies |
249 | \li start recording a render pass |
250 | \li record draw calls |
251 | \li end render pass |
252 | \li end frame |
253 | \endlist |
254 | |
255 | Recording copy type of operations happens via QRhiResourceUpdateBatch. Such |
256 | operations are committed typically on |
257 | \l{QRhiCommandBuffer::beginPass()}{beginPass()}. |
258 | |
259 | When working with legacy rendering engines designed for OpenGL, the |
260 | migration to QRhi often involves redesigning from having a single \c render |
261 | step (that performs copies and uploads, clears buffers, and issues draw |
262 | calls, all mixed together) to a clearly separated, two phase \c prepare - |
263 | \c render setup where the \c render step only starts a renderpass and |
264 | records draw calls, while all resource creation and queuing of updates, |
265 | uploads and copies happens beforehand, in the \c prepare step. |
266 | |
267 | QRhi does not at the moment allow freely creating and submitting command |
268 | buffers. This may be lifted in the future to some extent, in particular if |
269 | compute support is introduced, but the model of well defined |
270 | \c{frame-start} and \c{frame-end} points, combined with a dedicated, |
271 | "frame" command buffer, where \c{frame-end} implies presenting, is going to |
272 | remain the primary way of operating since this is what fits Qt's various UI |
273 | technologies best. |
274 | |
275 | \section2 Threading |
276 | |
277 | A QRhi instance and the associated resources can be created and used on any |
278 | thread but all usage must be limited to that one single thread. When |
279 | rendering to multiple QWindows in an application, having a dedicated thread |
280 | and QRhi instance for each window is often advisable, as this can eliminate |
281 | issues with unexpected throttling caused by presenting to multiple windows. |
282 | Conceptually that is then the same as how Qt Quick scene graph's threaded |
283 | render loop operates when working directly with OpenGL: one thread for each |
284 | window, one QOpenGLContext for each thread. When moving onto QRhi, |
285 | QOpenGLContext is replaced by QRhi, making the migration straightforward. |
286 | |
287 | When it comes to externally created native objects, such as OpenGL contexts |
288 | passed in via QRhiGles2NativeHandles, it is up to the application to ensure |
289 | they are not misused by other threads. |
290 | |
291 | Resources are not shareable between QRhi instances. This is an intentional |
292 | choice since QRhi hides most queue, command buffer, and resource |
293 | synchronization related tasks, and provides no API for them. Safe and |
294 | efficient concurrent use of graphics resources from multiple threads is |
295 | tied to those concepts, however, and is thus a topic that is currently out |
296 | of scope, but may be introduced in the future. |
297 | |
298 | \note The Metal backend requires that an autorelease pool is available on |
299 | the rendering thread, ideally wrapping each iteration of the render loop. |
300 | This needs no action from the users of QRhi when rendering on the main |
301 | (gui) thread, but becomes important when a separate, dedicated render |
302 | thread is used. |
303 | |
304 | \section2 Resource synchronization |
305 | |
306 | QRhi does not expose APIs for resource barriers or image layout |
307 | transitions. Such synchronization is done implicitly by the backends, where |
308 | applicable (for example, Vulkan), by tracking resource usage as necessary. |
309 | Buffer and image barriers are inserted before render or compute passes |
310 | transparently to the application. |
311 | |
312 | \note Resources within a render or compute pass are expected to be bound to |
313 | a single usage during that pass. For example, a buffer can be used as |
314 | vertex, index, uniform, or storage buffer, but not a combination of them |
315 | within a single pass. However, it is perfectly fine to use a buffer as a |
316 | storage buffer in a compute pass, and then as a vertex buffer in a render |
317 | pass, for example, assuming the buffer declared both usages upon creation. |
318 | |
319 | \note Textures have this rule relaxed in certain cases, because using two |
320 | subresources (typically two different mip levels) of the same texture for |
321 | different access (one for load, one for store) is supported even within the |
322 | same pass. |
323 | |
324 | \section2 Resource reuse |
325 | |
326 | From the user's point of view a QRhiResource is reusable immediately after |
327 | calling QRhiResource::destroy(). With the exception of swapchains, calling |
328 | \c create() on an already created object does an implicit \c destroy(). This |
329 | provides a handy shortcut to reuse a QRhiResource instance with different |
330 | parameters, with a new native graphics object underneath. |
331 | |
332 | The importance of reusing the same object lies in the fact that some |
333 | objects reference other objects: for example, a QRhiShaderResourceBindings |
334 | can reference QRhiBuffer, QRhiTexture, and QRhiSampler instances. If in a |
335 | later frame one of these buffers need to be resized or a sampler parameter |
336 | needs changing, destroying and creating a whole new QRhiBuffer or |
337 | QRhiSampler would invalidate all references to the old instance. By just |
338 | changing the appropriate parameters via QRhiBuffer::setSize() or similar |
339 | and then calling QRhiBuffer::create(), everything works as expected and |
340 | there is no need to touch the QRhiShaderResourceBindings at all, even |
341 | though there is a good chance that under the hood the QRhiBuffer is now |
342 | backed by a whole new native buffer. |
343 | |
344 | \code |
345 | QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256); |
346 | ubuf->create(); |
347 | |
348 | QRhiShaderResourceBindings *srb = rhi->newShaderResourceBindings() |
349 | srb->setBindings({ |
350 | QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, ubuf) |
351 | }); |
352 | srb->create(); |
353 | |
354 | // ... |
355 | |
356 | // now in a later frame we need to grow the buffer to a larger size |
357 | ubuf->setSize(512); |
358 | ubuf->create(); // same as ubuf->destroy(); ubuf->create(); |
359 | |
360 | // srb needs no changes whatsoever, any references in it to ubuf |
361 | // stay valid. When it comes to internal details, such as that |
362 | // ubuf may now be backed by a completely different native buffer |
363 | // resource, that is is recognized and handled automatically by the |
364 | // next setShaderResources(). |
365 | \endcode |
366 | |
367 | QRhiTextureRenderTarget offers the same contract: calling |
368 | QRhiCommandBuffer::beginPass() is safe even when one of the render target's |
369 | associated textures or renderbuffers has been rebuilt (by calling \c |
370 | create() on it) since the creation of the render target object. This allows |
371 | the application to resize a texture by setting a new pixel size on the |
372 | QRhiTexture and calling create(), thus creating a whole new native texture |
373 | resource underneath, without having to update the QRhiTextureRenderTarget |
374 | as that will be done implicitly in beginPass(). |
375 | |
376 | \section2 Pooled objects |
377 | |
378 | In addition to resources, there are pooled objects as well, such as, |
379 | QRhiResourceUpdateBatch. An instance is retrieved via a \c next function, |
380 | such as, nextResourceUpdateBatch(). The caller does not own the returned |
381 | instance in this case. The only valid way of operating here is calling |
382 | functions on the QRhiResourceUpdateBatch and then passing it to |
383 | QRhiCommandBuffer::beginPass() or QRhiCommandBuffer::endPass(). These |
384 | functions take care of returning the batch to the pool. Alternatively, a |
385 | batch can be "canceled" and returned to the pool without processing by |
386 | calling QRhiResourceUpdateBatch::release(). |
387 | |
388 | A typical pattern is thus: |
389 | |
390 | \code |
391 | QRhiResourceUpdateBatch *resUpdates = rhi->nextResourceUpdateBatch(); |
392 | // ... |
393 | resUpdates->updateDynamicBuffer(ubuf, 0, 64, mvp.constData()); |
394 | if (!image.isNull()) { |
395 | resUpdates->uploadTexture(texture, image); |
396 | image = QImage(); |
397 | } |
398 | // ... |
399 | QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); |
400 | // note the last argument |
401 | cb->beginPass(swapchain->currentFrameRenderTarget(), clearCol, clearDs, resUpdates); |
402 | \endcode |
403 | |
404 | \section2 Swapchain specifics |
405 | |
406 | QRhiSwapChain features some special semantics due to the peculiar nature of |
407 | swapchains. |
408 | |
409 | \list |
410 | |
411 | \li It has no \c create() but rather a QRhiSwapChain::createOrResize(). |
412 | Repeatedly calling this function is \b not the same as calling |
413 | QRhiSwapChain::destroy() followed by QRhiSwapChain::createOrResize(). This |
414 | is because swapchains often have ways to handle the case where buffers need |
415 | to be resized in a manner that is more efficient than a brute force |
416 | destroying and recreating from scratch. |
417 | |
418 | \li An active QRhiSwapChain must be released by calling |
419 | \l{QRhiSwapChain::destroy()}{destroy()}, or by destroying the object, before |
420 | the QWindow's underlying QPlatformWindow, and so the associated native |
421 | window object, is destroyed. It should not be postponed because releasing |
422 | the swapchain may become problematic (and with some APIs, like Vulkan, is |
423 | explicitly disallowed) when the native window is not around anymore, for |
424 | example because the QPlatformWindow got destroyed upon getting a |
425 | QWindow::close(). Therefore, releasing the swapchain must happen whenever |
426 | the targeted QWindow sends the |
427 | QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed event. If the event does |
428 | not arrive before the destruction of the QWindow - this can happen when |
429 | using QCoreApplication::quit() -, then check QWindow::handle() after the |
430 | event loop exits and invoke the swapchain release when non-null (meaning |
431 | the underlying native window is still around). |
432 | |
433 | \endlist |
434 | |
435 | \section2 Ownership |
436 | |
437 | The general rule is no ownership transfer. Creating a QRhi with an already |
438 | existing graphics device does not mean the QRhi takes ownership of the |
439 | device object. Similarly, ownership is not given away when a device or |
440 | texture object is "exported" via QRhi::nativeHandles() or |
441 | QRhiTexture::nativeTexture(). Most importantly, passing pointers in structs |
442 | and via setters does not transfer ownership. |
443 | |
444 | \section1 Troubleshooting and Profiling |
445 | |
446 | \section2 Error reporting |
447 | |
448 | Functions such as \l QRhi::create() and the resource classes' \c create() |
449 | member functions (e.g., \l QRhiBuffer::create()) indicate failure with the |
450 | return value (\nullptr or |
451 | \c false, respectively). When working with QShader, \l QShader::fromSerialized() |
452 | returns an invalid QShader (for which \l{QShader::isValid()}{isValid()} returns |
453 | \c false) when the data passed to the function cannot be successfully deserialized. |
454 | Some functions, beginFrame() in particular, may also sometimes report "soft failures", |
455 | such as \l FrameOpSwapChainOutOfDate, which do not indicate an unrecoverable error, |
456 | but rather should be seen as a "try again later" response. |
457 | |
458 | Warnings and errors may get printed at any time to the debug output via |
459 | qWarning(). It is therefore always advisable to inspect the output of the |
460 | application. |
461 | |
462 | Additional debug messages can be enabled via the following logging |
463 | categories. Messages from these categories are not printed by default |
464 | unless explicitly enabled via QLoggingCategory or the \c QT_LOGGING_RULES |
465 | environment variable. For better interoperation with Qt Quick, the |
466 | environment variable \c{QSG_INFO} also enables these debug prints. |
467 | |
468 | \list |
469 | \li \c{qt.rhi.general} |
470 | \endlist |
471 | |
472 | Additionally, applications can query the \l{QRhi::backendName()}{QRhi |
473 | backend name} and |
474 | \l{QRhi::driverInfo()}{graphics device information} from a successfully |
475 | initialized QRhi. This can then be printed to the user or stored in the |
476 | application logs even in production builds, if desired. |
477 | |
478 | \section2 Investigating rendering problems |
479 | |
480 | When the rendering results are not as expected, or the application is |
481 | experiencing problems, always consider checking with the the native 3D |
482 | APIs' debug and validation facilities. QRhi itself features limited error |
483 | checking since replicating the already existing, vast amount of |
484 | functionality in the underlying layers is not reasonable. |
485 | |
486 | \list |
487 | |
488 | \li For Vulkan, controlling the |
489 | \l{https://github.com/KhronosGroup/Vulkan-ValidationLayers}{Vulkan |
490 | Validation Layers} is not in the scope of the QRhi, but rather can be |
491 | achieved by configuring the \l QVulkanInstance with the appropriate layers. |
492 | For example, call \c{instance.setLayers({ "VK_LAYER_KHRONOS_validation" });} |
493 | before invoking \l{QVulkanInstance::create()}{create()} on the QVulkanInstance. |
494 | (note that this assumes that the validation layers are actually installed |
495 | and available, e.g. from the Vulkan SDK) By default, QVulkanInstance conveniently |
496 | redirects the Vulkan debug messages to qDebug, meaning the validation messages get |
497 | printed just like other Qt warnings. |
498 | |
499 | \li With Direct 3D 11 and 12, a graphics device with the debug layer |
500 | enabled can be requested by toggling the \c enableDebugLayer flag in the |
501 | appropriate \l{QRhiD3D11InitParams}{init params struct}. The messages appear on the |
502 | debug output, which is visible in Qt Creator's messages panel or via a tool |
503 | such as \l{https://learn.microsoft.com/en-us/sysinternals/downloads/debugview}{DebugView}. |
504 | |
505 | \li For Metal, controlling Metal Validation is outside of QRhi's scope. |
506 | Rather, to enable validation, run the application with the environment |
507 | variable \c{METAL_DEVICE_WRAPPER_TYPE=1} set, or run the application within |
508 | XCode. There may also be further settings and environment variable in modern |
509 | XCode and macOS versions. See for instance |
510 | \l{https://developer.apple.com/documentation/metal/diagnosing_metal_programming_issues_early}{this |
511 | page}. |
512 | |
513 | \endlist |
514 | |
515 | \section2 Frame captures and performance profiling |
516 | |
517 | A Qt application rendering with QRhi to a window while relying on a 3D API |
518 | under the hood, is, from the windowing and graphics pipeline perspective at |
519 | least, no different from any other (non-Qt) applications using the same 3D |
520 | API. This means that tools and practices for debugging and profiling |
521 | applications involving 3D graphics, such as games, all apply to such a Qt |
522 | application as well. |
523 | |
524 | A few examples of tools that can provide insights into the rendering |
525 | internals of Qt applications that use QRhi, which includes Qt Quick and Qt |
526 | Quick 3D based projects as well: |
527 | |
528 | \list |
529 | |
530 | \li \l{https://renderdoc.org/}{RenderDoc} allows taking frame captures and |
531 | introspecting the recorded commands and pipeline state on Windows and Linux |
532 | for applications using OpenGL, Vulkan, D3D11, or D3D12. When trying to |
533 | figure out why some parts of the 3D scene do not show up as expected, |
534 | RenderDoc is often a fast and efficient way to check the pipeline stages |
535 | and the related state and discover the missing or incorrect value. It is |
536 | also a tool that is actively used when developing Qt itself. |
537 | |
538 | \li For NVIDIA-based systems, |
539 | \l{https://developer.nvidia.com/nsight-graphics}{Nsight Graphics} provides |
540 | a graphics debugger tool on Windows and Linux. In addition to investigating the commands |
541 | in the frame and the pipeline, the vendor-specific tools allow looking at timings and |
542 | hardware performance information, which is not something simple frame captures can provide. |
543 | |
544 | \li For AMD-based systems, the \l{https://gpuopen.com/rgp/}{Radeon GPU |
545 | Profiler} can be used to gain deeper insights into the application's |
546 | rendering and its performance. |
547 | |
548 | \li As QRhi supports Direct 3D 12, using |
549 | \l{https://devblogs.microsoft.com/pix/download/}{PIX}, a performance tuning |
550 | and debugging tool for DirectX 12 games on Windows is an option as well. |
551 | |
552 | \li On macOS, |
553 | \l{https://developer.apple.com/documentation/metal/debugging_tools/viewing_your_gpu_workload_with_the_metal_debugger}{the |
554 | XCode Metal debugger} can be used to take and introspect frame |
555 | captures, to investigate performance details, and debug shaders. In macOS 13 it is also possible |
556 | to enable an overlay that displays frame rate and other information for any Metal-based window by |
557 | setting the environment variable \c{MTL_HUD_ENABLED=1}. |
558 | |
559 | \endlist |
560 | |
561 | On mobile and embedded platforms, there may be vendor and platform-specific |
562 | tools, provided by the GPU or SoC vendor, available to perform performance |
563 | profiling of application using OpenGL ES or Vulkan. |
564 | |
565 | When capturing frames, remember that objects and groups of commands can be |
566 | named via debug markers, as long as \l{QRhi::EnableDebugMarkers}{debug |
567 | markers were enabled} for the QRhi, and the graphics API in use supports |
568 | this. To annotate the command stream, call |
569 | \l{QRhiCommandBuffer::debugMarkBegin()}{debugMarkBegin()}, |
570 | \l{QRhiCommandBuffer::debugMarkEnd()}{debugMarkEnd()} and/or |
571 | \l{QRhiCommandBuffer::debugMarkMsg()}{debugMarkMsg()}. |
572 | This can be particularly useful in larger frames with multiple render passes. |
573 | Resources are named by calling \l{QRhiResource::setName()}{setName()} before create(). |
574 | |
575 | To perform basic timing measurements on the CPU and GPU side within the |
576 | application, \l QElapsedTimer and |
577 | \l QRhiCommandBuffer::lastCompletedGpuTime() can be used. The latter is |
578 | only available with select graphics APIs at the moment and requires opting |
579 | in via the \l QRhi::EnableTimestamps flag. |
580 | |
581 | \section2 Resource leak checking |
582 | |
583 | When destroying a QRhi object without properly destroying all buffers, |
584 | textures, and other resources created from it, warnings about this are |
585 | printed to the debug output whenever the application is a debug build, or |
586 | when the \c QT_RHI_LEAK_CHECK environment variable is set to a non-zero |
587 | value. This is a simple way to discover design issues around resource |
588 | handling within the application rendering logic. Note however that some |
589 | platforms and underlying graphics APIs may perform their own allocation and |
590 | resource leak detection as well, over which Qt will have no direct control. |
591 | For example, when using Vulkan, the memory allocator may raise failing |
592 | assertions in debug builds when resources that own graphics memory |
593 | allocations are not destroyed before the QRhi. In addition, the Vulkan |
594 | validation layer, when enabled, will issue warnings about native graphics |
595 | resources that were not released. Similarly, with Direct 3D warnings may |
596 | get printed about unreleased COM objects when the application does not |
597 | destroy the QRhi and its resources in the correct order. |
598 | |
599 | \sa {RHI Window Example}, QRhiCommandBuffer, QRhiResourceUpdateBatch, |
600 | QRhiShaderResourceBindings, QShader, QRhiBuffer, QRhiTexture, |
601 | QRhiRenderBuffer, QRhiSampler, QRhiTextureRenderTarget, |
602 | QRhiGraphicsPipeline, QRhiComputePipeline, QRhiSwapChain |
603 | */ |
604 | |
605 | /*! |
606 | \enum QRhi::Implementation |
607 | Describes which graphics API-specific backend gets used by a QRhi instance. |
608 | |
609 | \value Null |
610 | \value Vulkan |
611 | \value OpenGLES2 |
612 | \value D3D11 |
613 | \value D3D12 |
614 | \value Metal |
615 | */ |
616 | |
617 | /*! |
618 | \enum QRhi::Flag |
619 | Describes what special features to enable. |
620 | |
621 | \value EnableDebugMarkers Enables debug marker groups. Without this frame |
622 | debugging features like making debug groups and custom resource name |
623 | visible in external GPU debugging tools will not be available and functions |
624 | like QRhiCommandBuffer::debugMarkBegin() will become no-ops. Avoid enabling |
625 | in production builds as it may involve a small performance impact. Has no |
626 | effect when the QRhi::DebugMarkers feature is not reported as supported. |
627 | |
628 | \value EnableTimestamps Enables GPU timestamp collection. When not set, |
629 | QRhiCommandBuffer::lastCompletedGpuTime() always returns 0. Enable this |
630 | only when needed since there may be a small amount of extra work involved |
631 | (e.g. timestamp queries), depending on the underlying graphics API. Has no |
632 | effect when the QRhi::Timestamps feature is not reported as supported. |
633 | |
634 | \value PreferSoftwareRenderer Indicates that backends should prefer |
635 | choosing an adapter or physical device that renders in software on the CPU. |
636 | For example, with Direct3D there is typically a "Basic Render Driver" |
637 | adapter available with \c{DXGI_ADAPTER_FLAG_SOFTWARE}. Setting this flag |
638 | requests the backend to choose that adapter over any other, as long as no |
639 | specific adapter was forced by other backend-specific means. With Vulkan |
640 | this maps to preferring physical devices with |
641 | \c{VK_PHYSICAL_DEVICE_TYPE_CPU}. When not available, or when it is not |
642 | possible to decide if an adapter/device is software-based, this flag is |
643 | ignored. It may also be ignored with graphics APIs that have no concept and |
644 | means of enumerating adapters/devices. |
645 | |
646 | \value EnablePipelineCacheDataSave Enables retrieving the pipeline cache |
647 | contents, where applicable. When not set, pipelineCacheData() will return |
648 | an empty blob always. With backends where retrieving and restoring the |
649 | pipeline cache contents is not supported, the flag has no effect and the |
650 | serialized cache data is always empty. The flag provides an opt-in |
651 | mechanism because the cost of maintaining the related data structures is |
652 | not insignificant with some backends. With Vulkan this feature maps |
653 | directly to VkPipelineCache, vkGetPipelineCacheData and |
654 | VkPipelineCacheCreateInfo::pInitialData. With Direct3D 11 there is no real |
655 | pipline cache, but the results of HLSL->DXBC compilations are stored and |
656 | can be serialized/deserialized via this mechanism. This allows skipping the |
657 | time consuming D3DCompile() in future runs of the applications for shaders |
658 | that come with HLSL source instead of offline pre-compiled bytecode. This |
659 | can provide a huge boost in startup and load times, if there is a lot of |
660 | HLSL source compilation happening. With OpenGL the "pipeline cache" is |
661 | simulated by retrieving and loading shader program binaries (if supported |
662 | by the driver). With OpenGL there are additional, disk-based caching |
663 | mechanisms for shader/program binaries provided by Qt. Writing to those may |
664 | get disabled whenever this flag is set since storing program binaries to |
665 | multiple caches is not sensible. |
666 | */ |
667 | |
668 | /*! |
669 | \enum QRhi::FrameOpResult |
670 | Describes the result of operations that can have a soft failure. |
671 | |
672 | \value FrameOpSuccess Success |
673 | |
674 | \value FrameOpError Unspecified error |
675 | |
676 | \value FrameOpSwapChainOutOfDate The swapchain is in an inconsistent state |
677 | internally. This can be recoverable by attempting to repeat the operation |
678 | (such as, beginFrame()) later. |
679 | |
680 | \value FrameOpDeviceLost The graphics device was lost. This can be |
681 | recoverable by attempting to repeat the operation (such as, beginFrame()) |
682 | after releasing and reinitializing all objects backed by native graphics |
683 | resources. See isDeviceLost(). |
684 | */ |
685 | |
686 | /*! |
687 | \enum QRhi::Feature |
688 | Flag values to indicate what features are supported by the backend currently in use. |
689 | |
690 | \value MultisampleTexture Indicates that textures with a sample count larger |
691 | than 1 are supported. In practice this feature will be unsupported with |
692 | OpenGL ES versions older than 3.1, and OpenGL older than 3.0. |
693 | |
694 | \value MultisampleRenderBuffer Indicates that renderbuffers with a sample |
695 | count larger than 1 are supported. In practice this feature will be |
696 | unsupported with OpenGL ES 2.0, and may also be unsupported with OpenGL 2.x |
697 | unless the relevant extensions are present. |
698 | |
699 | \value DebugMarkers Indicates that debug marker groups (and so |
700 | QRhiCommandBuffer::debugMarkBegin()) are supported. |
701 | |
702 | \value Timestamps Indicates that command buffer timestamps are supported. |
703 | Relevant for QRhiCommandBuffer::lastCompletedGpuTime(). Can be expected to |
704 | be supported on Metal, Vulkan, and Direct 3D, assuming the underlying |
705 | implementation supports timestamp queries or similar. |
706 | |
707 | \value Instancing Indicates that instanced drawing is supported. In |
708 | practice this feature will be unsupported with OpenGL ES 2.0 and OpenGL |
709 | 3.2 or older. |
710 | |
711 | \value CustomInstanceStepRate Indicates that instance step rates other |
712 | than 1 are supported. In practice this feature will always be unsupported |
713 | with OpenGL. In addition, running with Vulkan 1.0 without |
714 | VK_EXT_vertex_attribute_divisor will also lead to reporting false for this |
715 | feature. |
716 | |
717 | \value PrimitiveRestart Indicates that restarting the assembly of |
718 | primitives when encountering an index value of 0xFFFF |
719 | (\l{QRhiCommandBuffer::IndexUInt16}{IndexUInt16}) or 0xFFFFFFFF |
720 | (\l{QRhiCommandBuffer::IndexUInt32}{IndexUInt32}) is enabled, for certain |
721 | primitive topologies at least. QRhi will try to enable this with all |
722 | backends, but in some cases it will not be supported. Dynamically |
723 | controlling primitive restart is not possible since with some APIs |
724 | primitive restart with a fixed index is always on. Applications must assume |
725 | that whenever this feature is reported as supported, the above mentioned |
726 | index values \c may be treated specially, depending on the topology. The |
727 | only two topologies where primitive restart is guaranteed to behave |
728 | identically across backends, as long as this feature is reported as |
729 | supported, are \l{QRhiGraphicsPipeline::LineStrip}{LineStrip} and |
730 | \l{QRhiGraphicsPipeline::TriangleStrip}{TriangleStrip}. |
731 | |
732 | \value NonDynamicUniformBuffers Indicates that creating buffers with the |
733 | usage \l{QRhiBuffer::UniformBuffer}{UniformBuffer} and the types |
734 | \l{QRhiBuffer::Immutable}{Immutable} or \l{QRhiBuffer::Static}{Static} is |
735 | supported. When reported as unsupported, uniform (constant) buffers must be |
736 | created as \l{QRhiBuffer::Dynamic}{Dynamic}. (which is recommended |
737 | regardless) |
738 | |
739 | \value NonFourAlignedEffectiveIndexBufferOffset Indicates that effective |
740 | index buffer offsets (\c{indexOffset + firstIndex * indexComponentSize}) |
741 | that are not 4 byte aligned are supported. When not supported, attempting |
742 | to issue a \l{QRhiCommandBuffer::drawIndexed()}{drawIndexed()} with a |
743 | non-aligned effective offset may lead to unspecified behavior. Relevant in |
744 | particular for Metal, where this will be reported as unsupported. |
745 | |
746 | \value NPOTTextureRepeat Indicates that the |
747 | \l{QRhiSampler::Repeat}{Repeat} wrap mode and mipmap filtering modes are |
748 | supported for textures with a non-power-of-two size. In practice this can |
749 | only be false with OpenGL ES 2.0 implementations without |
750 | \c{GL_OES_texture_npot}. |
751 | |
752 | \value RedOrAlpha8IsRed Indicates that the |
753 | \l{QRhiTexture::RED_OR_ALPHA8}{RED_OR_ALPHA8} format maps to a one |
754 | component 8-bit \c red format. This is the case for all backends except |
755 | OpenGL when using either OpenGL ES or a non-core profile context. There |
756 | \c{GL_ALPHA}, a one component 8-bit \c alpha format, is used |
757 | instead. Using the special texture format allows having a single code |
758 | path for creating textures, leaving it up to the backend to decide the |
759 | actual format, while the feature flag can be used to pick the |
760 | appropriate shader variant for sampling the texture. |
761 | |
762 | \value ElementIndexUint Indicates that 32-bit unsigned integer elements are |
763 | supported in the index buffer. In practice this is true everywhere except |
764 | when running on plain OpenGL ES 2.0 implementations without the necessary |
765 | extension. When false, only 16-bit unsigned elements are supported in the |
766 | index buffer. |
767 | |
768 | \value Compute Indicates that compute shaders, image load/store, and |
769 | storage buffers are supported. OpenGL older than 4.3 and OpenGL ES older |
770 | than 3.1 have no compute support. |
771 | |
772 | \value WideLines Indicates that lines with a width other than 1 are |
773 | supported. When reported as not supported, the line width set on the |
774 | graphics pipeline state is ignored. This can always be false with some |
775 | backends (D3D11, D3D12, Metal). With Vulkan, the value depends on the |
776 | implementation. With OpenGL, wide lines are not supported in core profile |
777 | contexts. |
778 | |
779 | \value VertexShaderPointSize Indicates that the size of rasterized points |
780 | set via \c{gl_PointSize} in the vertex shader is taken into account. When |
781 | reported as not supported, drawing points with a size other than 1 is not |
782 | supported. Setting \c{gl_PointSize} in the shader is still valid then, but |
783 | is ignored. (for example, when generating HLSL, the assignment is silently |
784 | dropped from the generated code) Note that some APIs (Metal, Vulkan) |
785 | require the point size to be set in the shader explicitly whenever drawing |
786 | points, even when the size is 1, as they do not automatically default to 1. |
787 | |
788 | \value BaseVertex Indicates that |
789 | \l{QRhiCommandBuffer::drawIndexed()}{drawIndexed()} supports the \c |
790 | vertexOffset argument. When reported as not supported, the vertexOffset |
791 | value in an indexed draw is ignored. In practice this feature will be |
792 | unsupported with OpenGL and OpenGL ES versions lower than 3.2, and with |
793 | Metal on older iOS devices, including the iOS Simulator. |
794 | |
795 | \value BaseInstance Indicates that instanced draw commands support the \c |
796 | firstInstance argument. When reported as not supported, the firstInstance |
797 | value is ignored and the instance ID starts from 0. In practice this feature |
798 | will be unsupported with OpenGL, and with Metal on older iOS devices, |
799 | including the iOS Simulator. |
800 | |
801 | \value TriangleFanTopology Indicates that QRhiGraphicsPipeline::setTopology() |
802 | supports QRhiGraphicsPipeline::TriangleFan. In practice this feature will be |
803 | unsupported with Metal and Direct 3D 11/12. |
804 | |
805 | \value ReadBackNonUniformBuffer Indicates that |
806 | \l{QRhiResourceUpdateBatch::readBackBuffer()}{reading buffer contents} is |
807 | supported for QRhiBuffer instances with a usage different than |
808 | UniformBuffer. In practice this feature will be unsupported with OpenGL ES |
809 | 2.0. |
810 | |
811 | \value ReadBackNonBaseMipLevel Indicates that specifying a mip level other |
812 | than 0 is supported when reading back texture contents. When not supported, |
813 | specifying a non-zero level in QRhiReadbackDescription leads to returning |
814 | an all-zero image. In practice this feature will be unsupported with OpenGL |
815 | ES 2.0. |
816 | |
817 | \value TexelFetch Indicates that texelFetch() and textureLod() are available |
818 | in shaders. In practice this will be reported as unsupported with OpenGL ES |
819 | 2.0 and OpenGL 2.x contexts, because GLSL 100 es and versions before 130 do |
820 | not support these functions. |
821 | |
822 | \value RenderToNonBaseMipLevel Indicates that specifying a mip level other |
823 | than 0 is supported when creating a QRhiTextureRenderTarget with a |
824 | QRhiTexture as its color attachment. When not supported, create() will fail |
825 | whenever the target mip level is not zero. In practice this feature will be |
826 | unsupported with OpenGL ES 2.0. |
827 | |
828 | \value IntAttributes Indicates that specifying input attributes with |
829 | signed and unsigned integer types for a shader pipeline is supported. When |
830 | not supported, build() will succeed but just show a warning message and the |
831 | values of the target attributes will be broken. In practice this feature |
832 | will be unsupported with OpenGL ES 2.0 and OpenGL 2.x. |
833 | |
834 | \value ScreenSpaceDerivatives Indicates that functions such as dFdx(), |
835 | dFdy(), and fwidth() are supported in shaders. In practice this feature will |
836 | be unsupported with OpenGL ES 2.0 without the GL_OES_standard_derivatives |
837 | extension. |
838 | |
839 | \value ReadBackAnyTextureFormat Indicates that reading back texture |
840 | contents can be expected to work for any QRhiTexture::Format. Backends |
841 | other than OpenGL can be expected to return true for this feature. When |
842 | reported as false, which will typically happen with OpenGL, only the |
843 | formats QRhiTexture::RGBA8 and QRhiTexture::BGRA8 are guaranteed to be |
844 | supported for readbacks. In addition, with OpenGL, but not OpenGL ES, |
845 | reading back the 1 byte per component formats QRhiTexture::R8 and |
846 | QRhiTexture::RED_OR_ALPHA8 are supported as well. Reading back floating |
847 | point formats QRhiTexture::RGBA16F and RGBA32F may work too with OpenGL, as |
848 | long as the implementation provides support for these, but QRhi can give no |
849 | guarantees, as indicated by this flag. |
850 | |
851 | \value PipelineCacheDataLoadSave Indicates that the pipelineCacheData() and |
852 | setPipelineCacheData() functions are functional. When not supported, the |
853 | functions will not perform any action, the retrieved blob is always empty, |
854 | and thus no benefits can be expected from retrieving and, during a |
855 | subsequent run of the application, reloading the pipeline cache content. |
856 | |
857 | \value ImageDataStride Indicates that specifying a custom stride (row |
858 | length) for raw image data in texture uploads is supported. When not |
859 | supported (which can happen when the underlying API is OpenGL ES 2.0 without |
860 | support for GL_UNPACK_ROW_LENGTH), |
861 | QRhiTextureSubresourceUploadDescription::setDataStride() must not be used. |
862 | |
863 | \value RenderBufferImport Indicates that QRhiRenderBuffer::createFrom() is |
864 | supported. For most graphics APIs this is not sensible because |
865 | QRhiRenderBuffer encapsulates texture objects internally, just like |
866 | QRhiTexture. With OpenGL however, renderbuffer object exist as a separate |
867 | object type in the API, and in certain environments (for example, where one |
868 | may want to associated a renderbuffer object with an EGLImage object) it is |
869 | important to allow wrapping an existing OpenGL renderbuffer object with a |
870 | QRhiRenderBuffer. |
871 | |
872 | \value ThreeDimensionalTextures Indicates that 3D textures are supported. |
873 | In practice this feature will be unsupported with OpenGL and OpenGL ES |
874 | versions lower than 3.0. |
875 | |
876 | \value RenderTo3DTextureSlice Indicates that rendering to a slice in a 3D |
877 | texture is supported. This can be unsupported with Vulkan 1.0 due to |
878 | relying on VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT which is a Vulkan 1.1 |
879 | feature. |
880 | |
881 | \value TextureArrays Indicates that texture arrays are supported and |
882 | QRhi::newTextureArray() is functional. Note that even when texture arrays |
883 | are not supported, arrays of textures are still available as those are two |
884 | independent features. |
885 | |
886 | \value Tessellation Indicates that the tessellation control and evaluation |
887 | stages are supported. When reported as supported, the topology of a |
888 | QRhiGraphicsPipeline can be set to |
889 | \l{QRhiGraphicsPipeline::Patches}{Patches}, the number of control points |
890 | can be set via |
891 | \l{QRhiGraphicsPipeline::setPatchControlPointCount()}{setPatchControlPointCount()}, |
892 | and shaders for tessellation control and evaluation can be specified in the |
893 | QRhiShaderStage list. Tessellation shaders have portability issues between |
894 | APIs (for example, translating GLSL/SPIR-V to HLSL is problematic due to |
895 | the way hull shaders are structured, whereas Metal uses a somewhat |
896 | different tessellation pipeline than others), and therefore unexpected |
897 | issues may still arise, even though basic functionality is implemented |
898 | across all the underlying APIs. For Direct 3D in particular, handwritten |
899 | HLSL hull and domain shaders must be injected into each QShader for the |
900 | tessellation control and evaluation stages, respectively, since qsb cannot |
901 | generate these from SPIR-V. Note that isoline tessellation should be |
902 | avoided as it will not be supported by all backends. The maximum patch |
903 | control point count portable between backends is 32. |
904 | |
905 | \value GeometryShader Indicates that the geometry shader stage is |
906 | supported. When supported, a geometry shader can be specified in the |
907 | QRhiShaderStage list. Geometry Shaders are considered an experimental |
908 | feature in QRhi and can only be expected to be supported with Vulkan, |
909 | Direct 3D, OpenGL (3.2+) and OpenGL ES (3.2+), assuming the implementation |
910 | reports it as supported at run time. Geometry shaders have portability |
911 | issues between APIs, and therefore no guarantees can be given for a |
912 | universal solution. They will never be supported with Metal. Whereas with |
913 | Direct 3D a handwritten HLSL geometry shader must be injected into each |
914 | QShader for the geometry stage since qsb cannot generate this from SPIR-V. |
915 | |
916 | \value TextureArrayRange Indicates that for |
917 | \l{QRhi::newTextureArray()}{texture arrays} it is possible to specify a |
918 | range that is exposed to the shaders. Normally all array layers are exposed |
919 | and it is up to the shader to select the layer (via the third coordinate |
920 | passed to texture() when sampling the \c sampler2DArray). When supported, |
921 | calling QRhiTexture::setArrayRangeStart() and |
922 | QRhiTexture::setArrayRangeLength() before |
923 | \l{QRhiTexture::create()}{building} or |
924 | \l{QRhiTexture::createFrom()}{importing} the native texture has an effect, |
925 | and leads to selecting only the specified range from the array. This will |
926 | be necessary in special cases, such as when working with accelerated video |
927 | decoding and Direct 3D 11, because a texture array with both |
928 | \c{D3D11_BIND_DECODER} and \c{D3D11_BIND_SHADER_RESOURCE} on it is only |
929 | usable as a shader resource if a single array layer is selected. Note that |
930 | all this is applicable only when the texture is used as a |
931 | QRhiShaderResourceBinding::SampledTexture or |
932 | QRhiShaderResourceBinding::Texture shader resource, and is not compatible |
933 | with image load/store. This feature is only available with some backends as |
934 | it does not map well to all graphics APIs, and it is only meant to provide |
935 | support for special cases anyhow. In practice the feature can be expected to |
936 | be supported with Direct3D 11/12 and Vulkan. |
937 | |
938 | \value NonFillPolygonMode Indicates that setting a PolygonMode other than |
939 | the default Fill is supported for QRhiGraphicsPipeline. A common use case |
940 | for changing the mode to Line is to get wireframe rendering. This however |
941 | is not available as a core OpenGL ES feature, and is optional with Vulkan |
942 | as well as some mobile GPUs may not offer the feature. |
943 | |
944 | \value OneDimensionalTextures Indicates that 1D textures are supported. |
945 | In practice this feature will be unsupported on OpenGL ES. |
946 | |
947 | \value OneDimensionalTextureMipmaps Indicates that generating 1D texture |
948 | mipmaps are supported. In practice this feature will be unsupported on |
949 | backends that do not report support for |
950 | \l{OneDimensionalTextures}, Metal, and Direct 3D 12. |
951 | |
952 | \value HalfAttributes Indicates that specifying input attributes with half |
953 | precision (16bit) floating point types for a shader pipeline is supported. |
954 | When not supported, build() will succeed but just show a warning message |
955 | and the values of the target attributes will be broken. In practice this |
956 | feature will be unsupported in some OpenGL ES 2.0 and OpenGL 2.x |
957 | implementations. Note that while Direct3D 11/12 does support half precision |
958 | input attributes, it does not support the half3 type. The D3D backends pass |
959 | half3 attributes as half4. To ensure cross platform compatibility, half3 |
960 | inputs should be padded to 8 bytes. |
961 | |
962 | \value RenderToOneDimensionalTexture Indicates that 1D texture render |
963 | targets are supported. In practice this feature will be unsupported on |
964 | backends that do not report support for |
965 | \l{OneDimensionalTextures}, and Metal. |
966 | |
967 | \value ThreeDimensionalTextureMipmaps Indicates that generating 3D texture |
968 | mipmaps are supported. In practice this feature will be unsupported with |
969 | Direct 3D 12. |
970 | */ |
971 | |
972 | /*! |
973 | \enum QRhi::BeginFrameFlag |
974 | Flag values for QRhi::beginFrame() |
975 | */ |
976 | |
977 | /*! |
978 | \enum QRhi::EndFrameFlag |
979 | Flag values for QRhi::endFrame() |
980 | |
981 | \value SkipPresent Specifies that no present command is to be queued or no |
982 | swapBuffers call is to be made. This way no image is presented. Generating |
983 | multiple frames with all having this flag set is not recommended (except, |
984 | for example, for benchmarking purposes - but keep in mind that backends may |
985 | behave differently when it comes to waiting for command completion without |
986 | presenting so the results are not comparable between them) |
987 | */ |
988 | |
989 | /*! |
990 | \enum QRhi::ResourceLimit |
991 | Describes the resource limit to query. |
992 | |
993 | \value TextureSizeMin Minimum texture width and height. This is typically |
994 | 1. The minimum texture size is handled gracefully, meaning attempting to |
995 | create a texture with an empty size will instead create a texture with the |
996 | minimum size. |
997 | |
998 | \value TextureSizeMax Maximum texture width and height. This depends on the |
999 | graphics API and sometimes the platform or implementation as well. |
1000 | Typically the value is in the range 4096 - 16384. Attempting to create |
1001 | textures larger than this is expected to fail. |
1002 | |
1003 | \value MaxColorAttachments The maximum number of color attachments for a |
1004 | QRhiTextureRenderTarget, in case multiple render targets are supported. When |
1005 | MRT is not supported, the value is 1. Otherwise this is typically 8, but |
1006 | watch out for the fact that OpenGL only mandates 4 as the minimum, and that |
1007 | is what some OpenGL ES implementations provide. |
1008 | |
1009 | \value FramesInFlight The number of frames the backend may keep "in |
1010 | flight": with backends like Vulkan or Metal, it is the responsibility of |
1011 | QRhi to block whenever starting a new frame and finding the CPU is already |
1012 | \c{N - 1} frames ahead of the GPU (because the command buffer submitted in |
1013 | frame no. \c{current} - \c{N} has not yet completed). The value N is what |
1014 | is returned from here, and is typically 2. This can be relevant to |
1015 | applications that integrate rendering done directly with the graphics API, |
1016 | as such rendering code may want to perform double (if the value is 2) |
1017 | buffering for resources, such as, buffers, similarly to the QRhi backends |
1018 | themselves. The current frame slot index (a value running 0, 1, .., N-1, |
1019 | then wrapping around) is retrievable from QRhi::currentFrameSlot(). The |
1020 | value is 1 for backends where the graphics API offers no such low level |
1021 | control over the command submission process. Note that pipelining may still |
1022 | happen even when this value is 1 (some backends, such as D3D11, are |
1023 | designed to attempt to enable this, for instance, by using an update |
1024 | strategy for uniform buffers that does not stall the pipeline), but that is |
1025 | then not controlled by QRhi and so not reflected here in the API. |
1026 | |
1027 | \value MaxAsyncReadbackFrames The number of \l{QRhi::endFrame()}{submitted} |
1028 | frames (including the one that contains the readback) after which an |
1029 | asynchronous texture or buffer readback is guaranteed to complete upon |
1030 | \l{QRhi::beginFrame()}{starting a new frame}. |
1031 | |
1032 | \value MaxThreadGroupsPerDimension The maximum number of compute |
1033 | work/thread groups that can be dispatched. Effectively the maximum value |
1034 | for the arguments of QRhiCommandBuffer::dispatch(). Typically 65535. |
1035 | |
1036 | \value MaxThreadsPerThreadGroup The maximum number of invocations in a |
1037 | single local work group, or in other terminology, the maximum number of |
1038 | threads in a thread group. Effectively the maximum value for the product of |
1039 | \c local_size_x, \c local_size_y, and \c local_size_z in the compute |
1040 | shader. Typical values are 128, 256, 512, 1024, or 1536. Watch out that |
1041 | both OpenGL ES and Vulkan specify only 128 as the minimum required limit |
1042 | for implementations. While uncommon for Vulkan, some OpenGL ES 3.1 |
1043 | implementations for mobile/embedded devices only support the spec-mandated |
1044 | minimum value. |
1045 | |
1046 | \value MaxThreadGroupX The maximum size of a work/thread group in the X |
1047 | dimension. Effectively the maximum value of \c local_size_x in the compute |
1048 | shader. Typically 256 or 1024. |
1049 | |
1050 | \value MaxThreadGroupY The maximum size of a work/thread group in the Y |
1051 | dimension. Effectively the maximum value of \c local_size_y in the compute |
1052 | shader. Typically 256 or 1024. |
1053 | |
1054 | \value MaxThreadGroupZ The maximum size of a work/thread group in the Z |
1055 | dimension. Effectively the maximum value of \c local_size_z in the compute |
1056 | shader. Typically 64 or 256. |
1057 | |
1058 | \value TextureArraySizeMax Maximum texture array size. Typically in range |
1059 | 256 - 2048. Attempting to \l{QRhi::newTextureArray()}{create a texture |
1060 | array} with more elements will likely fail. |
1061 | |
1062 | \value MaxUniformBufferRange The number of bytes that can be exposed from a |
1063 | uniform buffer to the shaders at once. On OpenGL ES 2.0 and 3.0 |
1064 | implementations this may be as low as 3584 bytes (224 four component, 32 |
1065 | bits per component vectors). Elsewhere the value is typically 16384 (1024 |
1066 | vec4s) or 65536 (4096 vec4s). |
1067 | |
1068 | \value MaxVertexInputs The number of input attributes to the vertex shader. |
1069 | The location in a QRhiVertexInputAttribute must be in range \c{[0, |
1070 | MaxVertexInputs-1]}. The value may be as low as 8 with OpenGL ES 2.0. |
1071 | Elsewhere, typical values are 16, 31, or 32. |
1072 | |
1073 | \value MaxVertexOutputs The maximum number of outputs (4 component vector |
1074 | \c out variables) from the vertex shader. The value may be as low as 8 with |
1075 | OpenGL ES 2.0, and 15 with OpenGL ES 3.0 and some Metal devices. Elsewhere, |
1076 | a typical value is 32. |
1077 | */ |
1078 | |
1079 | /*! |
1080 | \class QRhiInitParams |
1081 | \inmodule QtGui |
1082 | \since 6.6 |
1083 | \brief Base class for backend-specific initialization parameters. |
1084 | |
1085 | Contains fields that are relevant to all backends. |
1086 | |
1087 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1088 | for details. |
1089 | */ |
1090 | |
1091 | /*! |
1092 | \class QRhiDepthStencilClearValue |
1093 | \inmodule QtGui |
1094 | \since 6.6 |
1095 | \brief Specifies clear values for a depth or stencil buffer. |
1096 | |
1097 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1098 | for details. |
1099 | */ |
1100 | |
1101 | /*! |
1102 | \fn QRhiDepthStencilClearValue::QRhiDepthStencilClearValue() = default |
1103 | |
1104 | Constructs a depth/stencil clear value with depth clear value 1.0f and |
1105 | stencil clear value 0. |
1106 | */ |
1107 | |
1108 | /*! |
1109 | Constructs a depth/stencil clear value with depth clear value \a d and |
1110 | stencil clear value \a s. |
1111 | */ |
1112 | QRhiDepthStencilClearValue::QRhiDepthStencilClearValue(float d, quint32 s) |
1113 | : m_d(d), |
1114 | m_s(s) |
1115 | { |
1116 | } |
1117 | |
1118 | /*! |
1119 | \fn float QRhiDepthStencilClearValue::depthClearValue() const |
1120 | \return the depth clear value. In most cases this is 1.0f. |
1121 | */ |
1122 | |
1123 | /*! |
1124 | \fn void QRhiDepthStencilClearValue::setDepthClearValue(float d) |
1125 | Sets the depth clear value to \a d. |
1126 | */ |
1127 | |
1128 | /*! |
1129 | \fn quint32 QRhiDepthStencilClearValue::stencilClearValue() const |
1130 | \return the stencil clear value. In most cases this is 0. |
1131 | */ |
1132 | |
1133 | /*! |
1134 | \fn void QRhiDepthStencilClearValue::setStencilClearValue(quint32 s) |
1135 | Sets the stencil clear value to \a s. |
1136 | */ |
1137 | |
1138 | /*! |
1139 | \fn bool QRhiDepthStencilClearValue::operator==(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept |
1140 | |
1141 | \return \c true if the values in the two QRhiDepthStencilClearValue objects |
1142 | \a a and \a b are equal. |
1143 | */ |
1144 | |
1145 | /*! |
1146 | \fn bool QRhiDepthStencilClearValue::operator!=(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept |
1147 | |
1148 | \return \c false if the values in the two QRhiDepthStencilClearValue |
1149 | objects \a a and \a b are equal; otherwise returns \c true. |
1150 | |
1151 | */ |
1152 | |
1153 | /*! |
1154 | \fn size_t QRhiDepthStencilClearValue::qHash(const QRhiDepthStencilClearValue &v, size_t seed = 0) noexcept |
1155 | |
1156 | \return the hash value for \a v, using \a seed to seed the calculation. |
1157 | */ |
1158 | |
1159 | #ifndef QT_NO_DEBUG_STREAM |
1160 | QDebug operator<<(QDebug dbg, const QRhiDepthStencilClearValue &v) |
1161 | { |
1162 | QDebugStateSaver saver(dbg); |
1163 | dbg.nospace() << "QRhiDepthStencilClearValue(depth-clear=" << v.depthClearValue() |
1164 | << " stencil-clear=" << v.stencilClearValue() |
1165 | << ')'; |
1166 | return dbg; |
1167 | } |
1168 | #endif |
1169 | |
1170 | /*! |
1171 | \class QRhiViewport |
1172 | \inmodule QtGui |
1173 | \since 6.6 |
1174 | \brief Specifies a viewport rectangle. |
1175 | |
1176 | Used with QRhiCommandBuffer::setViewport(). |
1177 | |
1178 | QRhi assumes OpenGL-style viewport coordinates, meaning x and y are |
1179 | bottom-left. Negative width or height are not allowed. |
1180 | |
1181 | Typical usage is like the following: |
1182 | |
1183 | \code |
1184 | const QSize outputSizeInPixels = swapchain->currentPixelSize(); |
1185 | const QRhiViewport viewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height()); |
1186 | cb->beginPass(swapchain->currentFrameRenderTarget(), Qt::black, { 1.0f, 0 }); |
1187 | cb->setGraphicsPipeline(ps); |
1188 | cb->setViewport(viewport); |
1189 | // ... |
1190 | \endcode |
1191 | |
1192 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1193 | for details. |
1194 | |
1195 | \sa QRhiCommandBuffer::setViewport(), QRhi::clipSpaceCorrMatrix(), QRhiScissor |
1196 | */ |
1197 | |
1198 | /*! |
1199 | \fn QRhiViewport::QRhiViewport() = default |
1200 | |
1201 | Constructs a viewport description with an empty rectangle and a depth range |
1202 | of 0.0f - 1.0f. |
1203 | |
1204 | \sa QRhi::clipSpaceCorrMatrix() |
1205 | */ |
1206 | |
1207 | /*! |
1208 | Constructs a viewport description with the rectangle specified by \a x, \a |
1209 | y, \a w, \a h and the depth range \a minDepth and \a maxDepth. |
1210 | |
1211 | \note \a x and \a y are assumed to be the bottom-left position. \a w and \a |
1212 | h should not be negative, the viewport will be ignored by |
1213 | QRhiCommandBuffer::setViewport() otherwise. |
1214 | |
1215 | \sa QRhi::clipSpaceCorrMatrix() |
1216 | */ |
1217 | QRhiViewport::QRhiViewport(float x, float y, float w, float h, float minDepth, float maxDepth) |
1218 | : m_rect { ._M_elems: { x, y, w, h } }, |
1219 | m_minDepth(minDepth), |
1220 | m_maxDepth(maxDepth) |
1221 | { |
1222 | } |
1223 | |
1224 | /*! |
1225 | \fn std::array<float, 4> QRhiViewport::viewport() const |
1226 | \return the viewport x, y, width, and height. |
1227 | */ |
1228 | |
1229 | /*! |
1230 | \fn void QRhiViewport::setViewport(float x, float y, float w, float h) |
1231 | Sets the viewport's position and size to \a x, \a y, \a w, and \a h. |
1232 | |
1233 | \note Viewports are specified in a coordinate system that has its origin in |
1234 | the bottom-left. |
1235 | */ |
1236 | |
1237 | /*! |
1238 | \fn float QRhiViewport::minDepth() const |
1239 | \return the minDepth value of the depth range of the viewport. |
1240 | */ |
1241 | |
1242 | /*! |
1243 | \fn void QRhiViewport::setMinDepth(float minDepth) |
1244 | Sets the \a minDepth of the depth range of the viewport. |
1245 | By default this is set to 0.0f. |
1246 | */ |
1247 | |
1248 | /*! |
1249 | \fn float QRhiViewport::maxDepth() const |
1250 | \return the maxDepth value of the depth range of the viewport. |
1251 | */ |
1252 | |
1253 | /*! |
1254 | \fn void QRhiViewport::setMaxDepth(float maxDepth) |
1255 | Sets the \a maxDepth of the depth range of the viewport. |
1256 | By default this is set to 1.0f. |
1257 | */ |
1258 | |
1259 | /*! |
1260 | \fn bool QRhiViewport::operator==(const QRhiViewport &a, const QRhiViewport &b) noexcept |
1261 | |
1262 | \return \c true if the values in the two QRhiViewport objects |
1263 | \a a and \a b are equal. |
1264 | */ |
1265 | |
1266 | /*! |
1267 | \fn bool QRhiViewport::operator!=(const QRhiViewport &a, const QRhiViewport &b) noexcept |
1268 | |
1269 | \return \c false if the values in the two QRhiViewport |
1270 | objects \a a and \a b are equal; otherwise returns \c true. |
1271 | */ |
1272 | |
1273 | /*! |
1274 | \fn size_t QRhiViewport::qHash(const QRhiViewport &v, size_t seed = 0) noexcept |
1275 | |
1276 | \return the hash value for \a v, using \a seed to seed the calculation. |
1277 | */ |
1278 | |
1279 | #ifndef QT_NO_DEBUG_STREAM |
1280 | QDebug operator<<(QDebug dbg, const QRhiViewport &v) |
1281 | { |
1282 | QDebugStateSaver saver(dbg); |
1283 | const std::array<float, 4> r = v.viewport(); |
1284 | dbg.nospace() << "QRhiViewport(bottom-left-x=" << r[0] |
1285 | << " bottom-left-y=" << r[1] |
1286 | << " width=" << r[2] |
1287 | << " height=" << r[3] |
1288 | << " minDepth=" << v.minDepth() |
1289 | << " maxDepth=" << v.maxDepth() |
1290 | << ')'; |
1291 | return dbg; |
1292 | } |
1293 | #endif |
1294 | |
1295 | /*! |
1296 | \class QRhiScissor |
1297 | \inmodule QtGui |
1298 | \since 6.6 |
1299 | \brief Specifies a scissor rectangle. |
1300 | |
1301 | Used with QRhiCommandBuffer::setScissor(). Setting a scissor rectangle is |
1302 | only possible with a QRhiGraphicsPipeline that has |
1303 | QRhiGraphicsPipeline::UsesScissor set. |
1304 | |
1305 | QRhi assumes OpenGL-style scissor coordinates, meaning x and y are |
1306 | bottom-left. Negative width or height are not allowed. However, apart from |
1307 | that, the flexible OpenGL semantics apply: negative x and y, partially out |
1308 | of bounds rectangles, etc. will be handled gracefully, clamping as |
1309 | appropriate. Therefore, any rendering logic targeting OpenGL can feed |
1310 | scissor rectangles into QRhiScissor as-is, without any adaptation. |
1311 | |
1312 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1313 | for details. |
1314 | |
1315 | \sa QRhiCommandBuffer::setScissor(), QRhiViewport |
1316 | */ |
1317 | |
1318 | /*! |
1319 | \fn QRhiScissor::QRhiScissor() = default |
1320 | |
1321 | Constructs an empty scissor. |
1322 | */ |
1323 | |
1324 | /*! |
1325 | Constructs a scissor with the rectangle specified by \a x, \a y, \a w, and |
1326 | \a h. |
1327 | |
1328 | \note \a x and \a y are assumed to be the bottom-left position. Negative \a w |
1329 | or \a h are not allowed, such scissor rectangles will be ignored by |
1330 | QRhiCommandBuffer. Other than that, the flexible OpenGL semantics apply: |
1331 | negative x and y, partially out of bounds rectangles, etc. will be handled |
1332 | gracefully, clamping as appropriate. |
1333 | */ |
1334 | QRhiScissor::QRhiScissor(int x, int y, int w, int h) |
1335 | : m_rect { ._M_elems: { x, y, w, h } } |
1336 | { |
1337 | } |
1338 | |
1339 | /*! |
1340 | \fn std::array<int, 4> QRhiScissor::scissor() const |
1341 | \return the scissor position and size. |
1342 | */ |
1343 | |
1344 | /*! |
1345 | \fn void QRhiScissor::setScissor(int x, int y, int w, int h) |
1346 | Sets the scissor position and size to \a x, \a y, \a w, \a h. |
1347 | |
1348 | \note The position is always expected to be specified in a coordinate |
1349 | system that has its origin in the bottom-left corner, like OpenGL. |
1350 | */ |
1351 | |
1352 | /*! |
1353 | \fn bool QRhiScissor::operator==(const QRhiScissor &a, const QRhiScissor &b) noexcept |
1354 | |
1355 | \return \c true if the values in the two QRhiScissor objects |
1356 | \a a and \a b are equal. |
1357 | */ |
1358 | |
1359 | /*! |
1360 | \fn bool QRhiScissor::operator!=(const QRhiScissor &a, const QRhiScissor &b) noexcept |
1361 | |
1362 | \return \c false if the values in the two QRhiScissor |
1363 | objects \a a and \a b are equal; otherwise returns \c true. |
1364 | */ |
1365 | |
1366 | /*! |
1367 | \fn size_t QRhiScissor::qHash(const QRhiScissor &v, size_t seed = 0) noexcept |
1368 | |
1369 | \return the hash value for \a v, using \a seed to seed the calculation. |
1370 | */ |
1371 | |
1372 | #ifndef QT_NO_DEBUG_STREAM |
1373 | QDebug operator<<(QDebug dbg, const QRhiScissor &s) |
1374 | { |
1375 | QDebugStateSaver saver(dbg); |
1376 | const std::array<int, 4> r = s.scissor(); |
1377 | dbg.nospace() << "QRhiScissor(bottom-left-x=" << r[0] |
1378 | << " bottom-left-y=" << r[1] |
1379 | << " width=" << r[2] |
1380 | << " height=" << r[3] |
1381 | << ')'; |
1382 | return dbg; |
1383 | } |
1384 | #endif |
1385 | |
1386 | /*! |
1387 | \class QRhiVertexInputBinding |
1388 | \inmodule QtGui |
1389 | \since 6.6 |
1390 | \brief Describes a vertex input binding. |
1391 | |
1392 | Specifies the stride (in bytes, must be a multiple of 4), the |
1393 | classification and optionally the instance step rate. |
1394 | |
1395 | As an example, assume a vertex shader with the following inputs: |
1396 | |
1397 | \badcode |
1398 | layout(location = 0) in vec4 position; |
1399 | layout(location = 1) in vec2 texcoord; |
1400 | \endcode |
1401 | |
1402 | Now let's assume also that 3 component vertex positions \c{(x, y, z)} and 2 |
1403 | component texture coordinates \c{(u, v)} are provided in a non-interleaved |
1404 | format in a buffer (or separate buffers even). Defining two bindings |
1405 | could then be done like this: |
1406 | |
1407 | \code |
1408 | QRhiVertexInputLayout inputLayout; |
1409 | inputLayout.setBindings({ |
1410 | { 3 * sizeof(float) }, |
1411 | { 2 * sizeof(float) } |
1412 | }); |
1413 | \endcode |
1414 | |
1415 | Only the stride is interesting here since instancing is not used. The |
1416 | binding number is given by the index of the QRhiVertexInputBinding |
1417 | element in the bindings vector of the QRhiVertexInputLayout. |
1418 | |
1419 | Once a graphics pipeline with this vertex input layout is bound, the vertex |
1420 | inputs could be set up like the following for drawing a cube with 36 |
1421 | vertices, assuming we have a single buffer with first the positions and |
1422 | then the texture coordinates: |
1423 | |
1424 | \code |
1425 | const QRhiCommandBuffer::VertexInput vbufBindings[] = { |
1426 | { cubeBuf, 0 }, |
1427 | { cubeBuf, 36 * 3 * sizeof(float) } |
1428 | }; |
1429 | cb->setVertexInput(0, 2, vbufBindings); |
1430 | \endcode |
1431 | |
1432 | Note how the index defined by \c {startBinding + i}, where \c i is the |
1433 | index in the second argument of |
1434 | \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()}, matches the |
1435 | index of the corresponding entry in the \c bindings vector of the |
1436 | QRhiVertexInputLayout. |
1437 | |
1438 | \note the stride must always be a multiple of 4. |
1439 | |
1440 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1441 | for details. |
1442 | |
1443 | \sa QRhiCommandBuffer::setVertexInput() |
1444 | */ |
1445 | |
1446 | /*! |
1447 | \enum QRhiVertexInputBinding::Classification |
1448 | Describes the input data classification. |
1449 | |
1450 | \value PerVertex Data is per-vertex |
1451 | \value PerInstance Data is per-instance |
1452 | */ |
1453 | |
1454 | /*! |
1455 | \fn QRhiVertexInputBinding::QRhiVertexInputBinding() = default |
1456 | |
1457 | Constructs a default vertex input binding description. |
1458 | */ |
1459 | |
1460 | /*! |
1461 | Constructs a vertex input binding description with the specified \a stride, |
1462 | classification \a cls, and instance step rate \a stepRate. |
1463 | |
1464 | \note \a stepRate other than 1 is only supported when |
1465 | QRhi::CustomInstanceStepRate is reported to be supported. |
1466 | */ |
1467 | QRhiVertexInputBinding::QRhiVertexInputBinding(quint32 stride, Classification cls, quint32 stepRate) |
1468 | : m_stride(stride), |
1469 | m_classification(cls), |
1470 | m_instanceStepRate(stepRate) |
1471 | { |
1472 | } |
1473 | |
1474 | /*! |
1475 | \fn quint32 QRhiVertexInputBinding::stride() const |
1476 | \return the stride in bytes. |
1477 | */ |
1478 | |
1479 | /*! |
1480 | \fn void QRhiVertexInputBinding::setStride(quint32 s) |
1481 | Sets the stride to \a s. |
1482 | */ |
1483 | |
1484 | /*! |
1485 | \fn QRhiVertexInputBinding::Classification QRhiVertexInputBinding::classification() const |
1486 | \return the input data classification. |
1487 | */ |
1488 | |
1489 | /*! |
1490 | \fn void QRhiVertexInputBinding::setClassification(Classification c) |
1491 | Sets the input data classification \a c. By default this is set to PerVertex. |
1492 | */ |
1493 | |
1494 | /*! |
1495 | \fn quint32 QRhiVertexInputBinding::instanceStepRate() const |
1496 | \return the instance step rate. |
1497 | */ |
1498 | |
1499 | /*! |
1500 | \fn void QRhiVertexInputBinding::setInstanceStepRate(quint32 rate) |
1501 | Sets the instance step \a rate. By default this is set to 1. |
1502 | */ |
1503 | |
1504 | /*! |
1505 | \fn bool QRhiVertexInputBinding::operator==(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept |
1506 | |
1507 | \return \c true if the values in the two QRhiVertexInputBinding objects |
1508 | \a a and \a b are equal. |
1509 | */ |
1510 | |
1511 | /*! |
1512 | \fn bool QRhiVertexInputBinding::operator!=(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept |
1513 | |
1514 | \return \c false if the values in the two QRhiVertexInputBinding |
1515 | objects \a a and \a b are equal; otherwise returns \c true. |
1516 | */ |
1517 | |
1518 | /*! |
1519 | \fn size_t QRhiVertexInputBinding::qHash(const QRhiVertexInputBinding &v, size_t seed = 0) noexcept |
1520 | |
1521 | \return the hash value for \a v, using \a seed to seed the calculation. |
1522 | */ |
1523 | |
1524 | #ifndef QT_NO_DEBUG_STREAM |
1525 | QDebug operator<<(QDebug dbg, const QRhiVertexInputBinding &b) |
1526 | { |
1527 | QDebugStateSaver saver(dbg); |
1528 | dbg.nospace() << "QRhiVertexInputBinding(stride=" << b.stride() |
1529 | << " cls=" << b.classification() |
1530 | << " step-rate=" << b.instanceStepRate() |
1531 | << ')'; |
1532 | return dbg; |
1533 | } |
1534 | #endif |
1535 | |
1536 | /*! |
1537 | \class QRhiVertexInputAttribute |
1538 | \inmodule QtGui |
1539 | \since 6.6 |
1540 | \brief Describes a single vertex input element. |
1541 | |
1542 | The members specify the binding number, location, format, and offset for a |
1543 | single vertex input element. |
1544 | |
1545 | \note For HLSL it is assumed that the vertex shader translated from SPIR-V |
1546 | uses |
1547 | \c{TEXCOORD<location>} as the semantic for each input. Hence no separate |
1548 | semantic name and index. |
1549 | |
1550 | As an example, assume a vertex shader with the following inputs: |
1551 | |
1552 | \badcode |
1553 | layout(location = 0) in vec4 position; |
1554 | layout(location = 1) in vec2 texcoord; |
1555 | \endcode |
1556 | |
1557 | Now let's assume that we have 3 component vertex positions \c{(x, y, z)} |
1558 | and 2 component texture coordinates \c{(u, v)} are provided in a |
1559 | non-interleaved format in a buffer (or separate buffers even). Once two |
1560 | bindings are defined, the attributes could be specified as: |
1561 | |
1562 | \code |
1563 | QRhiVertexInputLayout inputLayout; |
1564 | inputLayout.setBindings({ |
1565 | { 3 * sizeof(float) }, |
1566 | { 2 * sizeof(float) } |
1567 | }); |
1568 | inputLayout.setAttributes({ |
1569 | { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, |
1570 | { 1, 1, QRhiVertexInputAttribute::Float2, 0 } |
1571 | }); |
1572 | \endcode |
1573 | |
1574 | Once a graphics pipeline with this vertex input layout is bound, the vertex |
1575 | inputs could be set up like the following for drawing a cube with 36 |
1576 | vertices, assuming we have a single buffer with first the positions and |
1577 | then the texture coordinates: |
1578 | |
1579 | \code |
1580 | const QRhiCommandBuffer::VertexInput vbufBindings[] = { |
1581 | { cubeBuf, 0 }, |
1582 | { cubeBuf, 36 * 3 * sizeof(float) } |
1583 | }; |
1584 | cb->setVertexInput(0, 2, vbufBindings); |
1585 | \endcode |
1586 | |
1587 | When working with interleaved data, there will typically be just one |
1588 | binding, with multiple attributes referring to that same buffer binding |
1589 | point: |
1590 | |
1591 | \code |
1592 | QRhiVertexInputLayout inputLayout; |
1593 | inputLayout.setBindings({ |
1594 | { 5 * sizeof(float) } |
1595 | }); |
1596 | inputLayout.setAttributes({ |
1597 | { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, |
1598 | { 0, 1, QRhiVertexInputAttribute::Float2, 3 * sizeof(float) } |
1599 | }); |
1600 | \endcode |
1601 | |
1602 | and then: |
1603 | |
1604 | \code |
1605 | const QRhiCommandBuffer::VertexInput vbufBinding(interleavedCubeBuf, 0); |
1606 | cb->setVertexInput(0, 1, &vbufBinding); |
1607 | \endcode |
1608 | |
1609 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1610 | for details. |
1611 | |
1612 | \sa QRhiCommandBuffer::setVertexInput() |
1613 | */ |
1614 | |
1615 | /*! |
1616 | \enum QRhiVertexInputAttribute::Format |
1617 | Specifies the type of the element data. |
1618 | |
1619 | \value Float4 Four component float vector |
1620 | \value Float3 Three component float vector |
1621 | \value Float2 Two component float vector |
1622 | \value Float Float |
1623 | \value UNormByte4 Four component normalized unsigned byte vector |
1624 | \value UNormByte2 Two component normalized unsigned byte vector |
1625 | \value UNormByte Normalized unsigned byte |
1626 | \value UInt4 Four component unsigned integer vector |
1627 | \value UInt3 Three component unsigned integer vector |
1628 | \value UInt2 Two component unsigned integer vector |
1629 | \value UInt Unsigned integer |
1630 | \value SInt4 Four component signed integer vector |
1631 | \value SInt3 Three component signed integer vector |
1632 | \value SInt2 Two component signed integer vector |
1633 | \value SInt Signed integer |
1634 | \value Half4 Four component half precision (16 bit) float vector |
1635 | \value Half3 Three component half precision (16 bit) float vector |
1636 | \value Half2 Two component half precision (16 bit) float vector |
1637 | \value Half Half precision (16 bit) float |
1638 | |
1639 | \note Support for half precision floating point attributes is indicated at |
1640 | run time by the QRhi::Feature::HalfAttributes feature flag. Note that |
1641 | Direct3D 11/12 supports half input attributes, but does not support the |
1642 | Half3 type. The D3D backends pass through Half3 as Half4. To ensure cross |
1643 | platform compatibility, Half3 inputs should be padded to 8 bytes. |
1644 | */ |
1645 | |
1646 | /*! |
1647 | \fn QRhiVertexInputAttribute::QRhiVertexInputAttribute() = default |
1648 | |
1649 | Constructs a default vertex input attribute description. |
1650 | */ |
1651 | |
1652 | /*! |
1653 | Constructs a vertex input attribute description with the specified \a |
1654 | binding number, \a location, \a format, and \a offset. |
1655 | |
1656 | \a matrixSlice should be -1 except when this attribute corresponds to a row |
1657 | or column of a matrix (for example, a 4x4 matrix becomes 4 vec4s, consuming |
1658 | 4 consecutive vertex input locations), in which case it is the index of the |
1659 | row or column. \c{location - matrixSlice} must always be equal to the \c |
1660 | location for the first row or column of the unrolled matrix. |
1661 | */ |
1662 | QRhiVertexInputAttribute::QRhiVertexInputAttribute(int binding, int location, Format format, quint32 offset, int matrixSlice) |
1663 | : m_binding(binding), |
1664 | m_location(location), |
1665 | m_format(format), |
1666 | m_offset(offset), |
1667 | m_matrixSlice(matrixSlice) |
1668 | { |
1669 | } |
1670 | |
1671 | /*! |
1672 | \fn int QRhiVertexInputAttribute::binding() const |
1673 | \return the binding point index. |
1674 | */ |
1675 | |
1676 | /*! |
1677 | \fn void QRhiVertexInputAttribute::setBinding(int b) |
1678 | Sets the binding point index to \a b. |
1679 | By default this is set to 0. |
1680 | */ |
1681 | |
1682 | /*! |
1683 | \fn int QRhiVertexInputAttribute::location() const |
1684 | \return the location of the vertex input element. |
1685 | */ |
1686 | |
1687 | /*! |
1688 | \fn void QRhiVertexInputAttribute::setLocation(int loc) |
1689 | Sets the location of the vertex input element to \a loc. |
1690 | By default this is set to 0. |
1691 | */ |
1692 | |
1693 | /*! |
1694 | \fn QRhiVertexInputAttribute::Format QRhiVertexInputAttribute::format() const |
1695 | \return the format of the vertex input element. |
1696 | */ |
1697 | |
1698 | /*! |
1699 | \fn void QRhiVertexInputAttribute::setFormat(Format f) |
1700 | Sets the format of the vertex input element to \a f. |
1701 | By default this is set to Float4. |
1702 | */ |
1703 | |
1704 | /*! |
1705 | \fn quint32 QRhiVertexInputAttribute::offset() const |
1706 | \return the byte offset for the input element. |
1707 | */ |
1708 | |
1709 | /*! |
1710 | \fn void QRhiVertexInputAttribute::setOffset(quint32 ofs) |
1711 | Sets the byte offset for the input element to \a ofs. |
1712 | */ |
1713 | |
1714 | /*! |
1715 | \fn int QRhiVertexInputAttribute::matrixSlice() const |
1716 | |
1717 | \return the matrix slice if the input element corresponds to a row or |
1718 | column of a matrix, or -1 if not relevant. |
1719 | */ |
1720 | |
1721 | /*! |
1722 | \fn void QRhiVertexInputAttribute::setMatrixSlice(int slice) |
1723 | |
1724 | Sets the matrix \a slice. By default this is set to -1, and should be set |
1725 | to a >= 0 value only when this attribute corresponds to a row or column of |
1726 | a matrix (for example, a 4x4 matrix becomes 4 vec4s, consuming 4 |
1727 | consecutive vertex input locations), in which case it is the index of the |
1728 | row or column. \c{location - matrixSlice} must always be equal to the \c |
1729 | location for the first row or column of the unrolled matrix. |
1730 | */ |
1731 | |
1732 | /*! |
1733 | \fn bool QRhiVertexInputAttribute::operator==(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept |
1734 | |
1735 | \return \c true if the values in the two QRhiVertexInputAttribute objects |
1736 | \a a and \a b are equal. |
1737 | */ |
1738 | |
1739 | /*! |
1740 | \fn bool QRhiVertexInputAttribute::operator!=(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept |
1741 | |
1742 | \return \c false if the values in the two QRhiVertexInputAttribute |
1743 | objects \a a and \a b are equal; otherwise returns \c true. |
1744 | */ |
1745 | |
1746 | /*! |
1747 | \fn size_t QRhiVertexInputAttribute::qHash(const QRhiVertexInputAttribute &v, size_t seed = 0) noexcept |
1748 | |
1749 | \return the hash value for \a v, using \a seed to seed the calculation. |
1750 | */ |
1751 | |
1752 | #ifndef QT_NO_DEBUG_STREAM |
1753 | QDebug operator<<(QDebug dbg, const QRhiVertexInputAttribute &a) |
1754 | { |
1755 | QDebugStateSaver saver(dbg); |
1756 | dbg.nospace() << "QRhiVertexInputAttribute(binding=" << a.binding() |
1757 | << " location=" << a.location() |
1758 | << " format=" << a.format() |
1759 | << " offset=" << a.offset() |
1760 | << ')'; |
1761 | return dbg; |
1762 | } |
1763 | #endif |
1764 | |
1765 | QRhiVertexInputAttribute::Format QRhiImplementation::shaderDescVariableFormatToVertexInputFormat(QShaderDescription::VariableType type) const |
1766 | { |
1767 | switch (type) { |
1768 | case QShaderDescription::Vec4: |
1769 | return QRhiVertexInputAttribute::Float4; |
1770 | case QShaderDescription::Vec3: |
1771 | return QRhiVertexInputAttribute::Float3; |
1772 | case QShaderDescription::Vec2: |
1773 | return QRhiVertexInputAttribute::Float2; |
1774 | case QShaderDescription::Float: |
1775 | return QRhiVertexInputAttribute::Float; |
1776 | |
1777 | case QShaderDescription::Int4: |
1778 | return QRhiVertexInputAttribute::SInt4; |
1779 | case QShaderDescription::Int3: |
1780 | return QRhiVertexInputAttribute::SInt3; |
1781 | case QShaderDescription::Int2: |
1782 | return QRhiVertexInputAttribute::SInt2; |
1783 | case QShaderDescription::Int: |
1784 | return QRhiVertexInputAttribute::SInt; |
1785 | |
1786 | case QShaderDescription::Uint4: |
1787 | return QRhiVertexInputAttribute::UInt4; |
1788 | case QShaderDescription::Uint3: |
1789 | return QRhiVertexInputAttribute::UInt3; |
1790 | case QShaderDescription::Uint2: |
1791 | return QRhiVertexInputAttribute::UInt2; |
1792 | case QShaderDescription::Uint: |
1793 | return QRhiVertexInputAttribute::UInt; |
1794 | |
1795 | case QShaderDescription::Half4: |
1796 | return QRhiVertexInputAttribute::Half4; |
1797 | case QShaderDescription::Half3: |
1798 | return QRhiVertexInputAttribute::Half3; |
1799 | case QShaderDescription::Half2: |
1800 | return QRhiVertexInputAttribute::Half2; |
1801 | case QShaderDescription::Half: |
1802 | return QRhiVertexInputAttribute::Half; |
1803 | |
1804 | default: |
1805 | Q_UNREACHABLE_RETURN(QRhiVertexInputAttribute::Float); |
1806 | } |
1807 | } |
1808 | |
1809 | quint32 QRhiImplementation::byteSizePerVertexForVertexInputFormat(QRhiVertexInputAttribute::Format format) const |
1810 | { |
1811 | switch (format) { |
1812 | case QRhiVertexInputAttribute::Float4: |
1813 | return 4 * sizeof(float); |
1814 | case QRhiVertexInputAttribute::Float3: |
1815 | return 4 * sizeof(float); // vec3 still takes 16 bytes |
1816 | case QRhiVertexInputAttribute::Float2: |
1817 | return 2 * sizeof(float); |
1818 | case QRhiVertexInputAttribute::Float: |
1819 | return sizeof(float); |
1820 | |
1821 | case QRhiVertexInputAttribute::UNormByte4: |
1822 | return 4 * sizeof(quint8); |
1823 | case QRhiVertexInputAttribute::UNormByte2: |
1824 | return 2 * sizeof(quint8); |
1825 | case QRhiVertexInputAttribute::UNormByte: |
1826 | return sizeof(quint8); |
1827 | |
1828 | case QRhiVertexInputAttribute::UInt4: |
1829 | return 4 * sizeof(quint32); |
1830 | case QRhiVertexInputAttribute::UInt3: |
1831 | return 4 * sizeof(quint32); // ivec3 still takes 16 bytes |
1832 | case QRhiVertexInputAttribute::UInt2: |
1833 | return 2 * sizeof(quint32); |
1834 | case QRhiVertexInputAttribute::UInt: |
1835 | return sizeof(quint32); |
1836 | |
1837 | case QRhiVertexInputAttribute::SInt4: |
1838 | return 4 * sizeof(qint32); |
1839 | case QRhiVertexInputAttribute::SInt3: |
1840 | return 4 * sizeof(qint32); // uvec3 still takes 16 bytes |
1841 | case QRhiVertexInputAttribute::SInt2: |
1842 | return 2 * sizeof(qint32); |
1843 | case QRhiVertexInputAttribute::SInt: |
1844 | return sizeof(qint32); |
1845 | |
1846 | case QRhiVertexInputAttribute::Half4: |
1847 | return 4 * sizeof(qfloat16); |
1848 | case QRhiVertexInputAttribute::Half3: |
1849 | return 4 * sizeof(qfloat16); // half3 still takes 8 bytes |
1850 | case QRhiVertexInputAttribute::Half2: |
1851 | return 2 * sizeof(qfloat16); |
1852 | case QRhiVertexInputAttribute::Half: |
1853 | return sizeof(qfloat16); |
1854 | |
1855 | default: |
1856 | Q_UNREACHABLE_RETURN(1); |
1857 | } |
1858 | } |
1859 | |
1860 | /*! |
1861 | \class QRhiVertexInputLayout |
1862 | \inmodule QtGui |
1863 | \since 6.6 |
1864 | \brief Describes the layout of vertex inputs consumed by a vertex shader. |
1865 | |
1866 | The vertex input layout is defined by the collections of |
1867 | QRhiVertexInputBinding and QRhiVertexInputAttribute. |
1868 | |
1869 | As an example, let's assume that we have a single buffer with 3 component |
1870 | vertex positions and 2 component UV coordinates interleaved (\c x, \c y, \c |
1871 | z, \c u, \c v), that the position and UV are expected at input locations 0 |
1872 | and 1 by the vertex shader, and that the vertex buffer will be bound at |
1873 | binding point 0 using |
1874 | \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()} later on: |
1875 | |
1876 | \code |
1877 | QRhiVertexInputLayout inputLayout; |
1878 | inputLayout.setBindings({ |
1879 | { 5 * sizeof(float) } |
1880 | }); |
1881 | inputLayout.setAttributes({ |
1882 | { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, |
1883 | { 0, 1, QRhiVertexInputAttribute::Float2, 3 * sizeof(float) } |
1884 | }); |
1885 | \endcode |
1886 | |
1887 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1888 | for details. |
1889 | */ |
1890 | |
1891 | /*! |
1892 | \fn QRhiVertexInputLayout::QRhiVertexInputLayout() = default |
1893 | |
1894 | Constructs an empty vertex input layout description. |
1895 | */ |
1896 | |
1897 | /*! |
1898 | \fn void QRhiVertexInputLayout::setBindings(std::initializer_list<QRhiVertexInputBinding> list) |
1899 | Sets the bindings from the specified \a list. |
1900 | */ |
1901 | |
1902 | /*! |
1903 | \fn template<typename InputIterator> void QRhiVertexInputLayout::setBindings(InputIterator first, InputIterator last) |
1904 | Sets the bindings using the iterators \a first and \a last. |
1905 | */ |
1906 | |
1907 | /*! |
1908 | \fn const QRhiVertexInputBinding *QRhiVertexInputLayout::cbeginBindings() const |
1909 | \return a const iterator pointing to the first item in the binding list. |
1910 | */ |
1911 | |
1912 | /*! |
1913 | \fn const QRhiVertexInputBinding *QRhiVertexInputLayout::cendBindings() const |
1914 | \return a const iterator pointing just after the last item in the binding list. |
1915 | */ |
1916 | |
1917 | /*! |
1918 | \fn const QRhiVertexInputBinding *QRhiVertexInputLayout::bindingAt(qsizetype index) const |
1919 | \return the binding at the given \a index. |
1920 | */ |
1921 | |
1922 | /*! |
1923 | \fn qsizetype QRhiVertexInputLayout::bindingCount() const |
1924 | \return the number of bindings. |
1925 | */ |
1926 | |
1927 | /*! |
1928 | \fn void QRhiVertexInputLayout::setAttributes(std::initializer_list<QRhiVertexInputAttribute> list) |
1929 | Sets the attributes from the specified \a list. |
1930 | */ |
1931 | |
1932 | /*! |
1933 | \fn template<typename InputIterator> void QRhiVertexInputLayout::setAttributes(InputIterator first, InputIterator last) |
1934 | Sets the attributes using the iterators \a first and \a last. |
1935 | */ |
1936 | |
1937 | /*! |
1938 | \fn const QRhiVertexInputAttribute *QRhiVertexInputLayout::cbeginAttributes() const |
1939 | \return a const iterator pointing to the first item in the attribute list. |
1940 | */ |
1941 | |
1942 | /*! |
1943 | \fn const QRhiVertexInputAttribute *QRhiVertexInputLayout::cendAttributes() const |
1944 | \return a const iterator pointing just after the last item in the attribute list. |
1945 | */ |
1946 | |
1947 | /*! |
1948 | \fn const QRhiVertexInputAttribute *QRhiVertexInputLayout::attributeAt(qsizetype index) const |
1949 | \return the attribute at the given \a index. |
1950 | */ |
1951 | |
1952 | /*! |
1953 | \fn qsizetype QRhiVertexInputLayout::attributeCount() const |
1954 | \return the number of attributes. |
1955 | */ |
1956 | |
1957 | /*! |
1958 | \fn bool QRhiVertexInputLayout::operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept |
1959 | |
1960 | \return \c true if the values in the two QRhiVertexInputLayout objects |
1961 | \a a and \a b are equal. |
1962 | */ |
1963 | |
1964 | /*! |
1965 | \fn bool QRhiVertexInputLayout::operator!=(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept |
1966 | |
1967 | \return \c false if the values in the two QRhiVertexInputLayout |
1968 | objects \a a and \a b are equal; otherwise returns \c true. |
1969 | */ |
1970 | |
1971 | /*! |
1972 | \fn size_t QRhiVertexInputLayout::qHash(const QRhiVertexInputLayout &v, size_t seed = 0) noexcept |
1973 | |
1974 | \return the hash value for \a v, using \a seed to seed the calculation. |
1975 | */ |
1976 | |
1977 | #ifndef QT_NO_DEBUG_STREAM |
1978 | QDebug operator<<(QDebug dbg, const QRhiVertexInputLayout &v) |
1979 | { |
1980 | QDebugStateSaver saver(dbg); |
1981 | dbg.nospace() << "QRhiVertexInputLayout(bindings=" << v.m_bindings |
1982 | << " attributes=" << v.m_attributes |
1983 | << ')'; |
1984 | return dbg; |
1985 | } |
1986 | #endif |
1987 | |
1988 | /*! |
1989 | \class QRhiShaderStage |
1990 | \inmodule QtGui |
1991 | \since 6.6 |
1992 | \brief Specifies the type and the shader code for a shader stage in the pipeline. |
1993 | |
1994 | When setting up a QRhiGraphicsPipeline, a collection of shader stages are |
1995 | specified. The QRhiShaderStage contains a QShader and some associated |
1996 | metadata, such as the graphics pipeline stage, and the |
1997 | \l{QShader::Variant}{shader variant} to select. There is no need to specify |
1998 | the shader language or version because the QRhi backend in use at runtime |
1999 | will take care of choosing the appropriate shader version from the |
2000 | collection within the QShader. |
2001 | |
2002 | The typical usage is in combination with |
2003 | QRhiGraphicsPipeline::setShaderStages(), shown here with a simple approach |
2004 | to load the QShader from \c{.qsb} files generated offline or at build time: |
2005 | |
2006 | \code |
2007 | QShader getShader(const QString &name) |
2008 | { |
2009 | QFile f(name); |
2010 | return f.open(QIODevice::ReadOnly) ? QShader::fromSerialized(f.readAll()) : QShader(); |
2011 | } |
2012 | |
2013 | QShader vs = getShader("material.vert.qsb"); |
2014 | QShader fs = getShader("material.frag.qsb"); |
2015 | pipeline->setShaderStages({ |
2016 | { QRhiShaderStage::Vertex, vs }, |
2017 | { QRhiShaderStage::Fragment, fs } |
2018 | }); |
2019 | \endcode |
2020 | |
2021 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2022 | for details. |
2023 | */ |
2024 | |
2025 | /*! |
2026 | \enum QRhiShaderStage::Type |
2027 | Specifies the type of the shader stage. |
2028 | |
2029 | \value Vertex Vertex stage |
2030 | |
2031 | \value TessellationControl Tessellation control (hull shader) stage. Must |
2032 | be used only when the QRhi::Tessellation feature is supported. |
2033 | |
2034 | \value TessellationEvaluation Tessellation evaluation (domain shader) |
2035 | stage. Must be used only when the QRhi::Tessellation feature is supported. |
2036 | |
2037 | \value Fragment Fragment (pixel shader) stage |
2038 | |
2039 | \value Compute Compute stage. Must be used only when the QRhi::Compute |
2040 | feature is supported. |
2041 | |
2042 | \value Geometry Geometry stage. Must be used only when the |
2043 | QRhi::GeometryShader feature is supported. |
2044 | */ |
2045 | |
2046 | /*! |
2047 | \fn QRhiShaderStage::QRhiShaderStage() = default |
2048 | |
2049 | Constructs a shader stage description for the vertex stage with an empty |
2050 | QShader. |
2051 | */ |
2052 | |
2053 | /*! |
2054 | \fn QRhiShaderStage::Type QRhiShaderStage::type() const |
2055 | \return the type of the stage. |
2056 | */ |
2057 | |
2058 | /*! |
2059 | \fn void QRhiShaderStage::setType(Type t) |
2060 | |
2061 | Sets the type of the stage to \a t. Setters should rarely be needed in |
2062 | pratice. Most applications will likely use the QRhiShaderStage constructor |
2063 | in most cases. |
2064 | */ |
2065 | |
2066 | /*! |
2067 | \fn QShader QRhiShaderStage::shader() const |
2068 | \return the QShader to be used for this stage in the graphics pipeline. |
2069 | */ |
2070 | |
2071 | /*! |
2072 | \fn void QRhiShaderStage::setShader(const QShader &s) |
2073 | Sets the shader collection \a s. |
2074 | */ |
2075 | |
2076 | /*! |
2077 | \fn QShader::Variant QRhiShaderStage::shaderVariant() const |
2078 | \return the requested shader variant. |
2079 | */ |
2080 | |
2081 | /*! |
2082 | \fn void QRhiShaderStage::setShaderVariant(QShader::Variant v) |
2083 | Sets the requested shader variant \a v. |
2084 | */ |
2085 | |
2086 | /*! |
2087 | Constructs a shader stage description with the \a type of the stage and the |
2088 | \a shader. |
2089 | |
2090 | The shader variant \a v defaults to QShader::StandardShader. A |
2091 | QShader contains multiple source and binary versions of a shader. |
2092 | In addition, it can also contain variants of the shader with slightly |
2093 | modified code. \a v can then be used to select the desired variant. |
2094 | */ |
2095 | QRhiShaderStage::QRhiShaderStage(Type type, const QShader &shader, QShader::Variant v) |
2096 | : m_type(type), |
2097 | m_shader(shader), |
2098 | m_shaderVariant(v) |
2099 | { |
2100 | } |
2101 | |
2102 | /*! |
2103 | \fn bool QRhiShaderStage::operator==(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept |
2104 | |
2105 | \return \c true if the values in the two QRhiShaderStage objects |
2106 | \a a and \a b are equal. |
2107 | */ |
2108 | |
2109 | /*! |
2110 | \fn bool QRhiShaderStage::operator!=(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept |
2111 | |
2112 | \return \c false if the values in the two QRhiShaderStage |
2113 | objects \a a and \a b are equal; otherwise returns \c true. |
2114 | */ |
2115 | |
2116 | /*! |
2117 | \fn size_t QRhiShaderStage::qHash(const QRhiShaderStage &v, size_t seed = 0) noexcept |
2118 | |
2119 | \return the hash value for \a v, using \a seed to seed the calculation. |
2120 | */ |
2121 | |
2122 | #ifndef QT_NO_DEBUG_STREAM |
2123 | QDebug operator<<(QDebug dbg, const QRhiShaderStage &s) |
2124 | { |
2125 | QDebugStateSaver saver(dbg); |
2126 | dbg.nospace() << "QRhiShaderStage(type=" << s.type() |
2127 | << " shader=" << s.shader() |
2128 | << " variant=" << s.shaderVariant() |
2129 | << ')'; |
2130 | return dbg; |
2131 | } |
2132 | #endif |
2133 | |
2134 | /*! |
2135 | \class QRhiColorAttachment |
2136 | \inmodule QtGui |
2137 | \since 6.6 |
2138 | \brief Describes the a single color attachment of a render target. |
2139 | |
2140 | A color attachment is either a QRhiTexture or a QRhiRenderBuffer. The |
2141 | former, i.e. when texture() is set, is used in most cases. |
2142 | QRhiColorAttachment is commonly used in combination with |
2143 | QRhiTextureRenderTargetDescription. |
2144 | |
2145 | \note texture() and renderBuffer() cannot be both set (be non-null at the |
2146 | same time). |
2147 | |
2148 | Setting renderBuffer instead is recommended only when multisampling is |
2149 | needed. Relying on QRhi::MultisampleRenderBuffer is a better choice than |
2150 | QRhi::MultisampleTexture in practice since the former is available in more |
2151 | run time configurations (e.g. when running on OpenGL ES 3.0 which has no |
2152 | support for multisample textures, but does support multisample |
2153 | renderbuffers). |
2154 | |
2155 | When targeting a non-multisample texture, the layer() and level() indicate |
2156 | the targeted layer (face index \c{0-5} for cubemaps) and mip level. For 3D |
2157 | textures layer() specifies the slice (one 2D image within the 3D texture) |
2158 | to render to. For texture arrays layer() is the array index. |
2159 | |
2160 | When texture() or renderBuffer() is multisample, resolveTexture() can be |
2161 | set optionally. When set, samples are resolved automatically into that |
2162 | (non-multisample) texture at the end of the render pass. When rendering |
2163 | into a multisample renderbuffers, this is the only way to get resolved, |
2164 | non-multisample content out of them. Multisample textures allow sampling in |
2165 | shaders so for them this is just one option. |
2166 | |
2167 | \note when resolving is enabled, the multisample data may not be written |
2168 | out at all. This means that the multisample texture() must not be used |
2169 | afterwards with shaders for sampling when resolveTexture() is set. |
2170 | |
2171 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2172 | for details. |
2173 | |
2174 | \sa QRhiTextureRenderTargetDescription |
2175 | */ |
2176 | |
2177 | /*! |
2178 | \fn QRhiColorAttachment::QRhiColorAttachment() = default |
2179 | |
2180 | Constructs an empty color attachment description. |
2181 | */ |
2182 | |
2183 | /*! |
2184 | Constructs a color attachment description that specifies \a texture as the |
2185 | associated color buffer. |
2186 | */ |
2187 | QRhiColorAttachment::QRhiColorAttachment(QRhiTexture *texture) |
2188 | : m_texture(texture) |
2189 | { |
2190 | } |
2191 | |
2192 | /*! |
2193 | Constructs a color attachment description that specifies \a renderBuffer as |
2194 | the associated color buffer. |
2195 | */ |
2196 | QRhiColorAttachment::QRhiColorAttachment(QRhiRenderBuffer *renderBuffer) |
2197 | : m_renderBuffer(renderBuffer) |
2198 | { |
2199 | } |
2200 | |
2201 | /*! |
2202 | \fn QRhiTexture *QRhiColorAttachment::texture() const |
2203 | |
2204 | \return the texture this attachment description references, or \nullptr if |
2205 | there is none. |
2206 | */ |
2207 | |
2208 | /*! |
2209 | \fn void QRhiColorAttachment::setTexture(QRhiTexture *tex) |
2210 | |
2211 | Sets the texture \a tex. |
2212 | |
2213 | \note texture() and renderBuffer() cannot be both set (be non-null at the |
2214 | same time). |
2215 | */ |
2216 | |
2217 | /*! |
2218 | \fn QRhiRenderBuffer *QRhiColorAttachment::renderBuffer() const |
2219 | |
2220 | \return the renderbuffer this attachment description references, or |
2221 | \nullptr if there is none. |
2222 | |
2223 | In practice associating a QRhiRenderBuffer with a QRhiColorAttachment makes |
2224 | the most sense when setting up multisample rendering via a multisample |
2225 | \l{QRhiRenderBuffer::Type}{color} renderbuffer that is then resolved into a |
2226 | non-multisample texture at the end of the render pass. |
2227 | */ |
2228 | |
2229 | /*! |
2230 | \fn void QRhiColorAttachment::setRenderBuffer(QRhiRenderBuffer *rb) |
2231 | |
2232 | Sets the renderbuffer \a rb. |
2233 | |
2234 | \note texture() and renderBuffer() cannot be both set (be non-null at the |
2235 | same time). |
2236 | */ |
2237 | |
2238 | /*! |
2239 | \fn int QRhiColorAttachment::layer() const |
2240 | \return the layer index (cubemap face or array layer). 0 by default. |
2241 | */ |
2242 | |
2243 | /*! |
2244 | \fn void QRhiColorAttachment::setLayer(int layer) |
2245 | Sets the \a layer index. |
2246 | */ |
2247 | |
2248 | /*! |
2249 | \fn int QRhiColorAttachment::level() const |
2250 | \return the mip level. 0 by default. |
2251 | */ |
2252 | |
2253 | /*! |
2254 | \fn void QRhiColorAttachment::setLevel(int level) |
2255 | Sets the mip \a level. |
2256 | */ |
2257 | |
2258 | /*! |
2259 | \fn QRhiTexture *QRhiColorAttachment::resolveTexture() const |
2260 | |
2261 | \return the resolve texture this attachment description references, or |
2262 | \nullptr if there is none. |
2263 | |
2264 | Setting a non-null resolve texture is applicable when the attachment |
2265 | references a multisample, color renderbuffer. (i.e., renderBuffer() is set) |
2266 | The QRhiTexture in the resolveTexture() is then a regular, 2D, |
2267 | non-multisample texture with the same size (but a sample count of 1). The |
2268 | multisample content is automatically resolved into this texture at the end |
2269 | of each render pass. |
2270 | */ |
2271 | |
2272 | /*! |
2273 | \fn void QRhiColorAttachment::setResolveTexture(QRhiTexture *tex) |
2274 | Sets the resolve texture \a tex. |
2275 | */ |
2276 | |
2277 | /*! |
2278 | \fn int QRhiColorAttachment::resolveLayer() const |
2279 | \return the currently set resolve texture layer. Defaults to 0. |
2280 | */ |
2281 | |
2282 | /*! |
2283 | \fn void QRhiColorAttachment::setResolveLayer(int layer) |
2284 | Sets the resolve texture \a layer to use. |
2285 | */ |
2286 | |
2287 | /*! |
2288 | \fn int QRhiColorAttachment::resolveLevel() const |
2289 | \return the currently set resolve texture mip level. Defaults to 0. |
2290 | */ |
2291 | |
2292 | /*! |
2293 | \fn void QRhiColorAttachment::setResolveLevel(int level) |
2294 | Sets the resolve texture mip \a level to use. |
2295 | */ |
2296 | |
2297 | /*! |
2298 | \class QRhiTextureRenderTargetDescription |
2299 | \inmodule QtGui |
2300 | \since 6.6 |
2301 | \brief Describes the color and depth or depth/stencil attachments of a render target. |
2302 | |
2303 | A texture render target has zero or more textures as color attachments, |
2304 | zero or one renderbuffer as combined depth/stencil buffer or zero or one |
2305 | texture as depth buffer. |
2306 | |
2307 | \note depthStencilBuffer() and depthTexture() cannot be both set (cannot be |
2308 | non-null at the same time). |
2309 | |
2310 | Let's look at some example usages in combination with |
2311 | QRhiTextureRenderTarget. |
2312 | |
2313 | Due to the constructors, the targeting a texture (and no depth/stencil |
2314 | buffer) is simple: |
2315 | |
2316 | \code |
2317 | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(256, 256), 1, QRhiTexture::RenderTarget); |
2318 | texture->create(); |
2319 | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ texture })); |
2320 | \endcode |
2321 | |
2322 | The following creates a texture render target that is set up to target mip |
2323 | level #2 of a texture: |
2324 | |
2325 | \code |
2326 | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget | QRhiTexture::MipMapped); |
2327 | texture->create(); |
2328 | QRhiColorAttachment colorAtt(texture); |
2329 | colorAtt.setLevel(2); |
2330 | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ colorAtt }); |
2331 | \endcode |
2332 | |
2333 | Another example, this time to render into a depth texture: |
2334 | |
2335 | \code |
2336 | QRhiTexture *shadowMap = rhi->newTexture(QRhiTexture::D32F, QSize(1024, 1024), 1, QRhiTexture::RenderTarget); |
2337 | shadowMap->create(); |
2338 | QRhiTextureRenderTargetDescription rtDesc; |
2339 | rtDesc.setDepthTexture(shadowMap); |
2340 | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget(rtDesc); |
2341 | \endcode |
2342 | |
2343 | A very common case, having a texture as the color attachment and a |
2344 | renderbuffer as depth/stencil to enable depth testing: |
2345 | |
2346 | \code |
2347 | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1. QRhiTexture::RenderTarget); |
2348 | texture->create(); |
2349 | QRhiRenderBuffer *depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, QSize(512, 512)); |
2350 | depthStencil->create(); |
2351 | QRhiTextureRenderTargetDescription rtDesc({ texture }, depthStencil); |
2352 | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget(rtDesc); |
2353 | \endcode |
2354 | |
2355 | Finally, to enable multisample rendering in a portable manner (so also |
2356 | supporting OpenGL ES 3.0), using a QRhiRenderBuffer as the (multisample) |
2357 | color buffer and then resolving into a regular (non-multisample) 2D |
2358 | texture. To enable depth testing, a depth-stencil buffer, which also must |
2359 | use the same sample count, is used as well: |
2360 | |
2361 | \code |
2362 | QRhiRenderBuffer *colorBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::Color, QSize(512, 512), 4); // 4x MSAA |
2363 | colorBuffer->create(); |
2364 | QRhiRenderBuffer *depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, QSize(512, 512), 4); |
2365 | depthStencil->create(); |
2366 | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget); |
2367 | texture->create(); |
2368 | QRhiColorAttachment colorAtt(colorBuffer); |
2369 | colorAtt.setResolveTexture(texture); |
2370 | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ colorAtt, depthStencil }); |
2371 | \endcode |
2372 | |
2373 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2374 | for details. |
2375 | |
2376 | \sa QRhiColorAttachment, QRhiTextureRenderTarget |
2377 | */ |
2378 | |
2379 | /*! |
2380 | \fn QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription() = default |
2381 | |
2382 | Constructs an empty texture render target description. |
2383 | */ |
2384 | |
2385 | /*! |
2386 | Constructs a texture render target description with one attachment |
2387 | described by \a colorAttachment. |
2388 | */ |
2389 | QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment) |
2390 | { |
2391 | m_colorAttachments.append(t: colorAttachment); |
2392 | } |
2393 | |
2394 | /*! |
2395 | Constructs a texture render target description with two attachments, a |
2396 | color attachment described by \a colorAttachment, and a depth/stencil |
2397 | attachment with \a depthStencilBuffer. |
2398 | */ |
2399 | QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, |
2400 | QRhiRenderBuffer *depthStencilBuffer) |
2401 | : m_depthStencilBuffer(depthStencilBuffer) |
2402 | { |
2403 | m_colorAttachments.append(t: colorAttachment); |
2404 | } |
2405 | |
2406 | /*! |
2407 | Constructs a texture render target description with two attachments, a |
2408 | color attachment described by \a colorAttachment, and a depth attachment |
2409 | with \a depthTexture. |
2410 | |
2411 | \note \a depthTexture must have a suitable format, such as QRhiTexture::D16 |
2412 | or QRhiTexture::D32F. |
2413 | */ |
2414 | QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, |
2415 | QRhiTexture *depthTexture) |
2416 | : m_depthTexture(depthTexture) |
2417 | { |
2418 | m_colorAttachments.append(t: colorAttachment); |
2419 | } |
2420 | |
2421 | /*! |
2422 | \fn void QRhiTextureRenderTargetDescription::setColorAttachments(std::initializer_list<QRhiColorAttachment> list) |
2423 | Sets the \a list of color attachments. |
2424 | */ |
2425 | |
2426 | /*! |
2427 | \fn template<typename InputIterator> void QRhiTextureRenderTargetDescription::setColorAttachments(InputIterator first, InputIterator last) |
2428 | Sets the list of color attachments via the iterators \a first and \a last. |
2429 | */ |
2430 | |
2431 | /*! |
2432 | \fn const QRhiColorAttachment *QRhiTextureRenderTargetDescription::cbeginColorAttachments() const |
2433 | \return a const iterator pointing to the first item in the attachment list. |
2434 | */ |
2435 | |
2436 | /*! |
2437 | \fn const QRhiColorAttachment *QRhiTextureRenderTargetDescription::cendColorAttachments() const |
2438 | \return a const iterator pointing just after the last item in the attachment list. |
2439 | */ |
2440 | |
2441 | /*! |
2442 | \fn const QRhiColorAttachment *QRhiTextureRenderTargetDescription::colorAttachmentAt(qsizetype index) const |
2443 | \return the color attachment at the specified \a index. |
2444 | */ |
2445 | |
2446 | /*! |
2447 | \fn qsizetype QRhiTextureRenderTargetDescription::colorAttachmentCount() const |
2448 | \return the number of currently set color attachments. |
2449 | */ |
2450 | |
2451 | /*! |
2452 | \fn QRhiRenderBuffer *QRhiTextureRenderTargetDescription::depthStencilBuffer() const |
2453 | \return the renderbuffer used as depth-stencil buffer, or \nullptr if none was set. |
2454 | */ |
2455 | |
2456 | /*! |
2457 | \fn void QRhiTextureRenderTargetDescription::setDepthStencilBuffer(QRhiRenderBuffer *renderBuffer) |
2458 | |
2459 | Sets the \a renderBuffer for depth-stencil. Not mandatory, e.g. when no |
2460 | depth test/write or stencil-related features are used within any graphics |
2461 | pipelines in any of the render passes for this render target, it can be |
2462 | left set to \nullptr. |
2463 | |
2464 | \note depthStencilBuffer() and depthTexture() cannot be both set (cannot be |
2465 | non-null at the same time). |
2466 | */ |
2467 | |
2468 | /*! |
2469 | \fn QRhiTexture *QRhiTextureRenderTargetDescription::depthTexture() const |
2470 | \return the currently referenced depth texture, or \nullptr if none was set. |
2471 | */ |
2472 | |
2473 | /*! |
2474 | \fn void QRhiTextureRenderTargetDescription::setDepthTexture(QRhiTexture *texture) |
2475 | |
2476 | Sets the \a texture for depth-stencil. This is an alternative to |
2477 | setDepthStencilBuffer(), where instead of a QRhiRenderBuffer a QRhiTexture |
2478 | with a suitable type (e.g., QRhiTexture::D32F) is provided. |
2479 | |
2480 | \note depthStencilBuffer() and depthTexture() cannot be both set (cannot be |
2481 | non-null at the same time). |
2482 | */ |
2483 | |
2484 | /*! |
2485 | \class QRhiTextureSubresourceUploadDescription |
2486 | \inmodule QtGui |
2487 | \since 6.6 |
2488 | \brief Describes the source for one mip level in a layer in a texture upload operation. |
2489 | |
2490 | The source content is specified either as a QImage or as a raw blob. The |
2491 | former is only allowed for uncompressed textures with a format that can be |
2492 | mapped to QImage, while the latter is supported for all formats, including |
2493 | floating point and compressed. |
2494 | |
2495 | \note image() and data() cannot be both set at the same time. |
2496 | |
2497 | destinationTopLeft() specifies the top-left corner of the target |
2498 | rectangle. Defaults to (0, 0). |
2499 | |
2500 | An empty sourceSize() (the default) indicates that size is assumed to be |
2501 | the size of the subresource. With QImage-based uploads this implies that |
2502 | the size of the source image() must match the subresource. When providing |
2503 | raw data instead, sufficient number of bytes must be provided in data(). |
2504 | |
2505 | sourceTopLeft() is supported only for QImage-based uploads, and specifies |
2506 | the top-left corner of the source rectangle. |
2507 | |
2508 | \note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy |
2509 | internally, depending on the format and the backend. |
2510 | |
2511 | When providing raw data, and the stride is not specified via |
2512 | setDataStride(), the stride (row pitch, row length in bytes) of the |
2513 | provided data must be equal to \c{width * pixelSize} where \c pixelSize is |
2514 | the number of bytes used for one pixel, and there must be no additional |
2515 | padding between rows. There is no row start alignment requirement. |
2516 | |
2517 | When there is unused data at the end of each row in the input raw data, |
2518 | call setDataStride() with the total number of bytes per row. The stride |
2519 | must always be a multiple of the number of bytes for one pixel. The row |
2520 | stride is only applicable to image data for textures with an uncompressed |
2521 | format. |
2522 | |
2523 | \note The format of the source data must be compatible with the texture |
2524 | format. With many graphics APIs the data is copied as-is into a staging |
2525 | buffer, there is no intermediate format conversion provided by QRhi. This |
2526 | applies to floating point formats as well, with, for example, RGBA16F |
2527 | requiring half floats in the source data. |
2528 | |
2529 | \note Setting the stride via setDataStride() is only functional when |
2530 | QRhi::ImageDataStride is reported as |
2531 | \l{QRhi::isFeatureSupported()}{supported}. In practice this can be expected |
2532 | to be supported everywhere except for OpenGL ES 2.0. |
2533 | |
2534 | \note When a QImage is given, the stride returned from |
2535 | QImage::bytesPerLine() is taken into account automatically. |
2536 | |
2537 | \warning When a QImage is given and the QImage does not own the underlying |
2538 | pixel data, it is up to the caller to ensure that the associated data stays |
2539 | valid until the end of the frame. (just submitting the resource update batch |
2540 | is not sufficient, the data must stay valid until QRhi::endFrame() is called |
2541 | in order to be portable across all backends) If this cannot be ensured, the |
2542 | caller is strongly encouraged to call QImage::detach() on the image before |
2543 | passing it to uploadTexture(). |
2544 | |
2545 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2546 | for details. |
2547 | |
2548 | \sa QRhiTextureUploadDescription |
2549 | */ |
2550 | |
2551 | /*! |
2552 | \fn QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription() = default |
2553 | |
2554 | Constructs an empty subresource description. |
2555 | |
2556 | \note an empty QRhiTextureSubresourceUploadDescription is not useful on its |
2557 | own and should not be submitted to a QRhiTextureUploadEntry. At minimum |
2558 | image or data must be set first. |
2559 | */ |
2560 | |
2561 | /*! |
2562 | Constructs a mip level description with a \a image. |
2563 | |
2564 | The \l{QImage::size()}{size} of \a image must match the size of the mip |
2565 | level. For level 0 that is the \l{QRhiTexture::pixelSize()}{texture size}. |
2566 | |
2567 | The bit depth of \a image must be compatible with the |
2568 | \l{QRhiTexture::Format}{texture format}. |
2569 | |
2570 | To describe a partial upload, call setSourceSize(), setSourceTopLeft(), or |
2571 | setDestinationTopLeft() afterwards. |
2572 | */ |
2573 | QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription(const QImage &image) |
2574 | : m_image(image) |
2575 | { |
2576 | } |
2577 | |
2578 | /*! |
2579 | Constructs a mip level description with the image data is specified by \a |
2580 | data and \a size. This is suitable for floating point and compressed |
2581 | formats as well. |
2582 | |
2583 | \a data can safely be destroyed or changed once this function returns. |
2584 | */ |
2585 | QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription(const void *data, quint32 size) |
2586 | : m_data(reinterpret_cast<const char *>(data), size) |
2587 | { |
2588 | } |
2589 | |
2590 | /*! |
2591 | Constructs a mip level description with the image data specified by \a |
2592 | data. This is suitable for floating point and compressed formats as well. |
2593 | */ |
2594 | QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription(const QByteArray &data) |
2595 | : m_data(data) |
2596 | { |
2597 | } |
2598 | |
2599 | /*! |
2600 | \fn QImage QRhiTextureSubresourceUploadDescription::image() const |
2601 | \return the currently set QImage. |
2602 | */ |
2603 | |
2604 | /*! |
2605 | \fn void QRhiTextureSubresourceUploadDescription::setImage(const QImage &image) |
2606 | |
2607 | Sets \a image. |
2608 | |
2609 | \note image() and data() cannot be both set at the same time. |
2610 | */ |
2611 | |
2612 | /*! |
2613 | \fn QByteArray QRhiTextureSubresourceUploadDescription::data() const |
2614 | \return the currently set raw pixel data. |
2615 | */ |
2616 | |
2617 | /*! |
2618 | \fn void QRhiTextureSubresourceUploadDescription::setData(const QByteArray &data) |
2619 | |
2620 | Sets \a data. |
2621 | |
2622 | \note image() and data() cannot be both set at the same time. |
2623 | */ |
2624 | |
2625 | /*! |
2626 | \fn quint32 QRhiTextureSubresourceUploadDescription::dataStride() const |
2627 | \return the currently set data stride. |
2628 | */ |
2629 | |
2630 | /*! |
2631 | \fn void QRhiTextureSubresourceUploadDescription::setDataStride(quint32 stride) |
2632 | |
2633 | Sets the data \a stride in bytes. By default this is 0 and not always |
2634 | relevant. When providing raw data(), and the stride is not specified via |
2635 | setDataStride(), the stride (row pitch, row length in bytes) of the |
2636 | provided data must be equal to \c{width * pixelSize} where \c pixelSize is |
2637 | the number of bytes used for one pixel, and there must be no additional |
2638 | padding between rows. Otherwise, if there is additional space between the |
2639 | lines, set a non-zero \a stride. All this is applicable only when raw image |
2640 | data is provided, and is not necessary when working QImage since that has |
2641 | its own \l{QImage::bytesPerLine()}{stride} value. |
2642 | |
2643 | \note Setting the stride via setDataStride() is only functional when |
2644 | QRhi::ImageDataStride is reported as |
2645 | \l{QRhi::isFeatureSupported()}{supported}. |
2646 | |
2647 | \note When a QImage is given, the stride returned from |
2648 | QImage::bytesPerLine() is taken into account automatically and therefore |
2649 | there is no need to set the data stride manually. |
2650 | */ |
2651 | |
2652 | /*! |
2653 | \fn QPoint QRhiTextureSubresourceUploadDescription::destinationTopLeft() const |
2654 | \return the currently set destination top-left position. Defaults to (0, 0). |
2655 | */ |
2656 | |
2657 | /*! |
2658 | \fn void QRhiTextureSubresourceUploadDescription::setDestinationTopLeft(const QPoint &p) |
2659 | Sets the destination top-left position \a p. |
2660 | */ |
2661 | |
2662 | /*! |
2663 | \fn QSize QRhiTextureSubresourceUploadDescription::sourceSize() const |
2664 | |
2665 | \return the source size in pixels. Defaults to a default-constructed QSize, |
2666 | which indicates the entire subresource. |
2667 | */ |
2668 | |
2669 | /*! |
2670 | \fn void QRhiTextureSubresourceUploadDescription::setSourceSize(const QSize &size) |
2671 | |
2672 | Sets the source \a size in pixels. |
2673 | |
2674 | \note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy |
2675 | internally, depending on the format and the backend. |
2676 | */ |
2677 | |
2678 | /*! |
2679 | \fn QPoint QRhiTextureSubresourceUploadDescription::sourceTopLeft() const |
2680 | \return the currently set source top-left position. Defaults to (0, 0). |
2681 | */ |
2682 | |
2683 | /*! |
2684 | \fn void QRhiTextureSubresourceUploadDescription::setSourceTopLeft(const QPoint &p) |
2685 | |
2686 | Sets the source top-left position \a p. |
2687 | |
2688 | \note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy |
2689 | internally, depending on the format and the backend. |
2690 | */ |
2691 | |
2692 | /*! |
2693 | \class QRhiTextureUploadEntry |
2694 | \inmodule QtGui |
2695 | \since 6.6 |
2696 | |
2697 | \brief Describes one layer (face for cubemaps, slice for 3D textures, |
2698 | element for texture arrays) in a texture upload operation. |
2699 | |
2700 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2701 | for details. |
2702 | */ |
2703 | |
2704 | /*! |
2705 | \fn QRhiTextureUploadEntry::QRhiTextureUploadEntry() |
2706 | |
2707 | Constructs an empty QRhiTextureUploadEntry targeting layer 0 and level 0. |
2708 | |
2709 | \note an empty QRhiTextureUploadEntry should not be submitted without |
2710 | setting a QRhiTextureSubresourceUploadDescription via setDescription() |
2711 | first. |
2712 | */ |
2713 | |
2714 | /*! |
2715 | Constructs a QRhiTextureUploadEntry targeting the given \a layer and mip |
2716 | \a level, with the subresource contents described by \a desc. |
2717 | */ |
2718 | QRhiTextureUploadEntry::QRhiTextureUploadEntry(int layer, int level, |
2719 | const QRhiTextureSubresourceUploadDescription &desc) |
2720 | : m_layer(layer), |
2721 | m_level(level), |
2722 | m_desc(desc) |
2723 | { |
2724 | } |
2725 | |
2726 | /*! |
2727 | \fn int QRhiTextureUploadEntry::layer() const |
2728 | \return the currently set layer index (cubemap face, array layer). Defaults to 0. |
2729 | */ |
2730 | |
2731 | /*! |
2732 | \fn void QRhiTextureUploadEntry::setLayer(int layer) |
2733 | Sets the \a layer. |
2734 | */ |
2735 | |
2736 | /*! |
2737 | \fn int QRhiTextureUploadEntry::level() const |
2738 | \return the currently set mip level. Defaults to 0. |
2739 | */ |
2740 | |
2741 | /*! |
2742 | \fn void QRhiTextureUploadEntry::setLevel(int level) |
2743 | Sets the mip \a level. |
2744 | */ |
2745 | |
2746 | /*! |
2747 | \fn QRhiTextureSubresourceUploadDescription QRhiTextureUploadEntry::description() const |
2748 | \return the currently set subresource description. |
2749 | */ |
2750 | |
2751 | /*! |
2752 | \fn void QRhiTextureUploadEntry::setDescription(const QRhiTextureSubresourceUploadDescription &desc) |
2753 | Sets the subresource description \a desc. |
2754 | */ |
2755 | |
2756 | /*! |
2757 | \class QRhiTextureUploadDescription |
2758 | \inmodule QtGui |
2759 | \since 6.6 |
2760 | \brief Describes a texture upload operation. |
2761 | |
2762 | Used with QRhiResourceUpdateBatch::uploadTexture(). That function has two |
2763 | variants: one taking a QImage and one taking a |
2764 | QRhiTextureUploadDescription. The former is a convenience version, |
2765 | internally creating a QRhiTextureUploadDescription with a single image |
2766 | targeting level 0 for layer 0. |
2767 | |
2768 | An example of the the common, simple case of wanting to upload the contents |
2769 | of a QImage to a QRhiTexture with a matching pixel size: |
2770 | |
2771 | \code |
2772 | QImage image(256, 256, QImage::Format_RGBA8888); |
2773 | image.fill(Qt::green); // or could use a QPainter targeting image |
2774 | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(256, 256)); |
2775 | texture->create(); |
2776 | QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch(); |
2777 | u->uploadTexture(texture, image); |
2778 | \endcode |
2779 | |
2780 | When cubemaps, pre-generated mip images, compressed textures, or partial |
2781 | uploads are involved, applications will have to use this class instead. |
2782 | |
2783 | QRhiTextureUploadDescription also enables specifying batched uploads, which |
2784 | are useful for example when generating an atlas or glyph cache texture: |
2785 | multiple, partial uploads for the same subresource (meaning the same layer |
2786 | and level) are supported, and can be, depending on the backend and the |
2787 | underlying graphics API, more efficient when batched into the same |
2788 | QRhiTextureUploadDescription as opposed to issuing individual |
2789 | \l{QRhiResourceUpdateBatch::uploadTexture()}{uploadTexture()} commands for |
2790 | each of them. |
2791 | |
2792 | \note Cubemaps have one layer for each of the six faces in the order +X, |
2793 | -X, +Y, -Y, +Z, -Z. |
2794 | |
2795 | For example, specifying the faces of a cubemap could look like the following: |
2796 | |
2797 | \code |
2798 | QImage faces[6]; |
2799 | // ... |
2800 | QVarLengthArray<QRhiTextureUploadEntry, 6> entries; |
2801 | for (int i = 0; i < 6; ++i) |
2802 | entries.append(QRhiTextureUploadEntry(i, 0, faces[i])); |
2803 | QRhiTextureUploadDescription desc; |
2804 | desc.setEntries(entries.cbegin(), entries.cend()); |
2805 | resourceUpdates->uploadTexture(texture, desc); |
2806 | \endcode |
2807 | |
2808 | Another example that specifies mip images for a compressed texture: |
2809 | |
2810 | \code |
2811 | QList<QRhiTextureUploadEntry> entries; |
2812 | const int mipCount = rhi->mipLevelsForSize(compressedTexture->pixelSize()); |
2813 | for (int level = 0; level < mipCount; ++level) { |
2814 | const QByteArray compressedDataForLevel = .. |
2815 | entries.append(QRhiTextureUploadEntry(0, level, compressedDataForLevel)); |
2816 | } |
2817 | QRhiTextureUploadDescription desc; |
2818 | desc.setEntries(entries.cbegin(), entries.cend()); |
2819 | resourceUpdates->uploadTexture(compressedTexture, desc); |
2820 | \endcode |
2821 | |
2822 | With partial uploads targeting the same subresource, it is recommended to |
2823 | batch them into a single upload request, whenever possible: |
2824 | |
2825 | \code |
2826 | QRhiTextureSubresourceUploadDescription subresDesc(image); |
2827 | subresDesc.setSourceSize(QSize(10, 10)); |
2828 | subResDesc.setDestinationTopLeft(QPoint(50, 40)); |
2829 | QRhiTextureUploadEntry entry(0, 0, subresDesc); // layer 0, level 0 |
2830 | |
2831 | QRhiTextureSubresourceUploadDescription subresDesc2(image); |
2832 | subresDesc2.setSourceSize(QSize(30, 40)); |
2833 | subResDesc2.setDestinationTopLeft(QPoint(100, 200)); |
2834 | QRhiTextureUploadEntry entry2(0, 0, subresDesc2); // layer 0, level 0, i.e. same subresource |
2835 | |
2836 | QRhiTextureUploadDescription desc({ entry, entry2}); |
2837 | resourceUpdates->uploadTexture(texture, desc); |
2838 | \endcode |
2839 | |
2840 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2841 | for details. |
2842 | |
2843 | \sa QRhiResourceUpdateBatch |
2844 | */ |
2845 | |
2846 | /*! |
2847 | \fn QRhiTextureUploadDescription::QRhiTextureUploadDescription() |
2848 | |
2849 | Constructs an empty texture upload description. |
2850 | */ |
2851 | |
2852 | /*! |
2853 | Constructs a texture upload description with a single subresource upload |
2854 | described by \a entry. |
2855 | */ |
2856 | QRhiTextureUploadDescription::QRhiTextureUploadDescription(const QRhiTextureUploadEntry &entry) |
2857 | { |
2858 | m_entries.append(t: entry); |
2859 | } |
2860 | |
2861 | /*! |
2862 | Constructs a texture upload description with the specified \a list of entries. |
2863 | |
2864 | \note \a list can also contain multiple QRhiTextureUploadEntry elements |
2865 | with the same layer and level. This makes sense when those uploads are |
2866 | partial, meaning their subresource description has a source size or image |
2867 | smaller than the subresource dimensions, and can be more efficient than |
2868 | issuing separate uploadTexture()'s. |
2869 | */ |
2870 | QRhiTextureUploadDescription::QRhiTextureUploadDescription(std::initializer_list<QRhiTextureUploadEntry> list) |
2871 | : m_entries(list) |
2872 | { |
2873 | } |
2874 | |
2875 | /*! |
2876 | \fn void QRhiTextureUploadDescription::setEntries(std::initializer_list<QRhiTextureUploadEntry> list) |
2877 | Sets the \a list of entries. |
2878 | */ |
2879 | |
2880 | /*! |
2881 | \fn template<typename InputIterator> void QRhiTextureUploadDescription::setEntries(InputIterator first, InputIterator last) |
2882 | Sets the list of entries using the iterators \a first and \a last. |
2883 | */ |
2884 | |
2885 | /*! |
2886 | \fn const QRhiTextureUploadEntry *QRhiTextureUploadDescription::cbeginEntries() const |
2887 | \return a const iterator pointing to the first item in the entry list. |
2888 | */ |
2889 | |
2890 | /*! |
2891 | \fn const QRhiTextureUploadEntry *QRhiTextureUploadDescription::cendEntries() const |
2892 | \return a const iterator pointing just after the last item in the entry list. |
2893 | */ |
2894 | |
2895 | /*! |
2896 | \fn const QRhiTextureUploadEntry *QRhiTextureUploadDescription::entryAt(qsizetype index) const |
2897 | \return the entry at \a index. |
2898 | */ |
2899 | |
2900 | /*! |
2901 | \fn qsizetype QRhiTextureUploadDescription::entryCount() const |
2902 | \return the number of entries. |
2903 | */ |
2904 | |
2905 | /*! |
2906 | \class QRhiTextureCopyDescription |
2907 | \inmodule QtGui |
2908 | \since 6.6 |
2909 | \brief Describes a texture-to-texture copy operation. |
2910 | |
2911 | An empty pixelSize() indicates that the entire subresource is to be copied. |
2912 | A default constructed copy description therefore leads to copying the |
2913 | entire subresource at level 0 of layer 0. |
2914 | |
2915 | \note The source texture must be created with |
2916 | QRhiTexture::UsedAsTransferSource. |
2917 | |
2918 | \note The source and destination rectangles defined by pixelSize(), |
2919 | sourceTopLeft(), and destinationTopLeft() must fit the source and |
2920 | destination textures, respectively. The behavior is undefined otherwise. |
2921 | |
2922 | With cubemaps, 3D textures, and texture arrays one face or slice can be |
2923 | copied at a time. The face or slice is specified by the source and |
2924 | destination layer indices. With mipmapped textures one mip level can be |
2925 | copied at a time. The source and destination layer and mip level indices can |
2926 | differ, but the size and position must be carefully controlled to avoid out |
2927 | of bounds copies, in which case the behavior is undefined. |
2928 | |
2929 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2930 | for details. |
2931 | */ |
2932 | |
2933 | /*! |
2934 | \fn QRhiTextureCopyDescription::QRhiTextureCopyDescription() |
2935 | |
2936 | Constructs an empty texture copy description. |
2937 | */ |
2938 | |
2939 | /*! |
2940 | \fn QSize QRhiTextureCopyDescription::pixelSize() const |
2941 | \return the size of the region to copy. |
2942 | |
2943 | \note An empty pixelSize() indicates that the entire subresource is to be |
2944 | copied. A default constructed copy description therefore leads to copying |
2945 | the entire subresource at level 0 of layer 0. |
2946 | */ |
2947 | |
2948 | /*! |
2949 | \fn void QRhiTextureCopyDescription::setPixelSize(const QSize &sz) |
2950 | Sets the size of the region to copy to \a sz. |
2951 | */ |
2952 | |
2953 | /*! |
2954 | \fn int QRhiTextureCopyDescription::sourceLayer() const |
2955 | \return the source array layer (cubemap face or array layer index). Defaults to 0. |
2956 | */ |
2957 | |
2958 | /*! |
2959 | \fn void QRhiTextureCopyDescription::setSourceLayer(int layer) |
2960 | Sets the source array \a layer. |
2961 | */ |
2962 | |
2963 | /*! |
2964 | \fn int QRhiTextureCopyDescription::sourceLevel() const |
2965 | \return the source mip level. Defaults to 0. |
2966 | */ |
2967 | |
2968 | /*! |
2969 | \fn void QRhiTextureCopyDescription::setSourceLevel(int level) |
2970 | Sets the source mip \a level. |
2971 | */ |
2972 | |
2973 | /*! |
2974 | \fn QPoint QRhiTextureCopyDescription::sourceTopLeft() const |
2975 | \return the source top-left position (in pixels). Defaults to (0, 0). |
2976 | */ |
2977 | |
2978 | /*! |
2979 | \fn void QRhiTextureCopyDescription::setSourceTopLeft(const QPoint &p) |
2980 | Sets the source top-left position to \a p. |
2981 | */ |
2982 | |
2983 | /*! |
2984 | \fn int QRhiTextureCopyDescription::destinationLayer() const |
2985 | \return the destination array layer (cubemap face or array layer index). Default to 0. |
2986 | */ |
2987 | |
2988 | /*! |
2989 | \fn void QRhiTextureCopyDescription::setDestinationLayer(int layer) |
2990 | Sets the destination array \a layer. |
2991 | */ |
2992 | |
2993 | /*! |
2994 | \fn int QRhiTextureCopyDescription::destinationLevel() const |
2995 | \return the destionation mip level. Defaults to 0. |
2996 | */ |
2997 | |
2998 | /*! |
2999 | \fn void QRhiTextureCopyDescription::setDestinationLevel(int level) |
3000 | Sets the destination mip \a level. |
3001 | */ |
3002 | |
3003 | /*! |
3004 | \fn QPoint QRhiTextureCopyDescription::destinationTopLeft() const |
3005 | \return the destionation top-left position in pixels. Defaults to (0, 0). |
3006 | */ |
3007 | |
3008 | /*! |
3009 | \fn void QRhiTextureCopyDescription::setDestinationTopLeft(const QPoint &p) |
3010 | Sets the destination top-left position \a p. |
3011 | */ |
3012 | |
3013 | /*! |
3014 | \class QRhiReadbackDescription |
3015 | \inmodule QtGui |
3016 | \since 6.6 |
3017 | \brief Describes a readback (reading back texture contents from possibly GPU-only memory) operation. |
3018 | |
3019 | The source of the readback operation is either a QRhiTexture or the |
3020 | current backbuffer of the currently targeted QRhiSwapChain. When |
3021 | texture() is not set, the swapchain is used. Otherwise the specified |
3022 | QRhiTexture is treated as the source. |
3023 | |
3024 | \note Textures used in readbacks must be created with |
3025 | QRhiTexture::UsedAsTransferSource. |
3026 | |
3027 | \note Swapchains used in readbacks must be created with |
3028 | QRhiSwapChain::UsedAsTransferSource. |
3029 | |
3030 | layer() and level() are only applicable when the source is a QRhiTexture. |
3031 | |
3032 | \note Multisample textures cannot be read back. Readbacks are supported for |
3033 | multisample swapchain buffers however. |
3034 | |
3035 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3036 | for details. |
3037 | */ |
3038 | |
3039 | /*! |
3040 | \fn QRhiReadbackDescription::QRhiReadbackDescription() = default |
3041 | |
3042 | Constructs an empty texture readback description. |
3043 | |
3044 | \note The source texture is set to null by default, which is still a valid |
3045 | readback: it specifies that the backbuffer of the current swapchain is to |
3046 | be read back. (current meaning the frame's target swapchain at the time of |
3047 | committing the QRhiResourceUpdateBatch with the |
3048 | \l{QRhiResourceUpdateBatch::readBackTexture()}{texture readback} on it) |
3049 | */ |
3050 | |
3051 | /*! |
3052 | Constructs an texture readback description that specifies that level 0 of |
3053 | layer 0 of \a texture is to be read back. |
3054 | |
3055 | \note \a texture can also be null in which case this constructor is |
3056 | identical to the argumentless variant. |
3057 | */ |
3058 | QRhiReadbackDescription::QRhiReadbackDescription(QRhiTexture *texture) |
3059 | : m_texture(texture) |
3060 | { |
3061 | } |
3062 | |
3063 | /*! |
3064 | \fn QRhiTexture *QRhiReadbackDescription::texture() const |
3065 | |
3066 | \return the QRhiTexture that is read back. Can be left set to \nullptr |
3067 | which indicates that the backbuffer of the current swapchain is to be used |
3068 | instead. |
3069 | */ |
3070 | |
3071 | /*! |
3072 | \fn void QRhiReadbackDescription::setTexture(QRhiTexture *tex) |
3073 | |
3074 | Sets the texture \a tex as the source of the readback operation. |
3075 | |
3076 | Setting \nullptr is valid too, in which case the current swapchain's |
3077 | current backbuffer is used. (but then the readback cannot be issued in a |
3078 | non-swapchain-based frame) |
3079 | |
3080 | \note Multisample textures cannot be read back. Readbacks are supported for |
3081 | multisample swapchain buffers however. |
3082 | |
3083 | \note Textures used in readbacks must be created with |
3084 | QRhiTexture::UsedAsTransferSource. |
3085 | |
3086 | \note Swapchains used in readbacks must be created with |
3087 | QRhiSwapChain::UsedAsTransferSource. |
3088 | */ |
3089 | |
3090 | /*! |
3091 | \fn int QRhiReadbackDescription::layer() const |
3092 | |
3093 | \return the currently set array layer (cubemap face, array index). Defaults to 0. |
3094 | |
3095 | Applicable only when the source of the readback is a QRhiTexture. |
3096 | */ |
3097 | |
3098 | /*! |
3099 | \fn void QRhiReadbackDescription::setLayer(int layer) |
3100 | Sets the array \a layer to read back. |
3101 | */ |
3102 | |
3103 | /*! |
3104 | \fn int QRhiReadbackDescription::level() const |
3105 | |
3106 | \return the currently set mip level. Defaults to 0. |
3107 | |
3108 | Applicable only when the source of the readback is a QRhiTexture. |
3109 | */ |
3110 | |
3111 | /*! |
3112 | \fn void QRhiReadbackDescription::setLevel(int level) |
3113 | Sets the mip \a level to read back. |
3114 | */ |
3115 | |
3116 | /*! |
3117 | \class QRhiReadbackResult |
3118 | \inmodule QtGui |
3119 | \since 6.6 |
3120 | \brief Describes the results of a potentially asynchronous buffer or texture readback operation. |
3121 | |
3122 | When \l completed is set, the function is invoked when the \l data is |
3123 | available. \l format and \l pixelSize are set upon completion together with |
3124 | \l data. |
3125 | |
3126 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3127 | for details. |
3128 | */ |
3129 | |
3130 | /*! |
3131 | \variable QRhiReadbackResult::completed |
3132 | |
3133 | Callback that is invoked upon completion, on the thread the QRhi operates |
3134 | on. Can be left set to \nullptr, in which case no callback is invoked. |
3135 | */ |
3136 | |
3137 | /*! |
3138 | \variable QRhiReadbackResult::format |
3139 | |
3140 | Valid only for textures, the texture format. |
3141 | */ |
3142 | |
3143 | /*! |
3144 | \variable QRhiReadbackResult::pixelSize |
3145 | |
3146 | Valid only for textures, the size in pixels. |
3147 | */ |
3148 | |
3149 | /*! |
3150 | \variable QRhiReadbackResult::data |
3151 | |
3152 | The buffer or image data. |
3153 | |
3154 | \sa QRhiResourceUpdateBatch::readBackTexture(), QRhiResourceUpdateBatch::readBackBuffer() |
3155 | */ |
3156 | |
3157 | |
3158 | /*! |
3159 | \class QRhiNativeHandles |
3160 | \inmodule QtGui |
3161 | \since 6.6 |
3162 | \brief Base class for classes exposing backend-specific collections of native resource objects. |
3163 | |
3164 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3165 | for details. |
3166 | */ |
3167 | |
3168 | /*! |
3169 | \class QRhiResource |
3170 | \inmodule QtGui |
3171 | \since 6.6 |
3172 | \brief Base class for classes encapsulating native resource objects. |
3173 | |
3174 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3175 | for details. |
3176 | */ |
3177 | |
3178 | /*! |
3179 | \enum QRhiResource::Type |
3180 | Specifies type of the resource. |
3181 | |
3182 | \value Buffer |
3183 | \value Texture |
3184 | \value Sampler |
3185 | \value RenderBuffer |
3186 | \value RenderPassDescriptor |
3187 | \value SwapChainRenderTarget |
3188 | \value TextureRenderTarget |
3189 | \value ShaderResourceBindings |
3190 | \value GraphicsPipeline |
3191 | \value SwapChain |
3192 | \value ComputePipeline |
3193 | \value CommandBuffer |
3194 | */ |
3195 | |
3196 | /*! |
3197 | \fn virtual QRhiResource::Type QRhiResource::resourceType() const = 0 |
3198 | |
3199 | \return the type of the resource. |
3200 | */ |
3201 | |
3202 | /*! |
3203 | \internal |
3204 | */ |
3205 | QRhiResource::QRhiResource(QRhiImplementation *rhi) |
3206 | : m_rhi(rhi) |
3207 | { |
3208 | m_id = QRhiGlobalObjectIdGenerator::newId(); |
3209 | } |
3210 | |
3211 | /*! |
3212 | Destructor. |
3213 | |
3214 | Releases (or requests deferred releasing of) the underlying native graphics |
3215 | resources, if there are any. |
3216 | |
3217 | \note Resources referenced by commands for the current frame should not be |
3218 | released until the frame is submitted by QRhi::endFrame(). |
3219 | |
3220 | \sa destroy() |
3221 | */ |
3222 | QRhiResource::~QRhiResource() |
3223 | { |
3224 | // destroy() cannot be called here, due to virtuals; it is up to the |
3225 | // subclasses to do that. |
3226 | } |
3227 | |
3228 | /*! |
3229 | \fn virtual void QRhiResource::destroy() = 0 |
3230 | |
3231 | Releases (or requests deferred releasing of) the underlying native graphics |
3232 | resources. Safe to call multiple times, subsequent invocations will be a |
3233 | no-op then. |
3234 | |
3235 | Once destroy() is called, the QRhiResource instance can be reused, by |
3236 | calling \c create() again. That will then result in creating new native |
3237 | graphics resources underneath. |
3238 | |
3239 | \note Resources referenced by commands for the current frame should not be |
3240 | released until the frame is submitted by QRhi::endFrame(). |
3241 | |
3242 | The QRhiResource destructor also performs the same task, so calling this |
3243 | function is not necessary before deleting a QRhiResource. |
3244 | |
3245 | \sa deleteLater() |
3246 | */ |
3247 | |
3248 | /*! |
3249 | When called without a frame being recorded, this function is equivalent to |
3250 | deleting the object. Between a QRhi::beginFrame() and QRhi::endFrame() |
3251 | however the behavior is different: the QRhiResource will not be destroyed |
3252 | until the frame is submitted via QRhi::endFrame(), thus satisfying the QRhi |
3253 | requirement of not altering QRhiResource objects that are referenced by the |
3254 | frame being recorded. |
3255 | |
3256 | If the QRhi that created this object is already destroyed, the object is |
3257 | deleted immediately. |
3258 | |
3259 | Using deleteLater() can be a useful convenience in many cases, and it |
3260 | complements the low-level guarantee (that the underlying native graphics |
3261 | objects are never destroyed until it is safe to do so and it is known for |
3262 | sure that they are not used by the GPU in an still in-flight frame), by |
3263 | offering a way to make sure the C++ object instances (of QRhiBuffer, |
3264 | QRhiTexture, etc.) themselves also stay valid until the end of the current |
3265 | frame. |
3266 | |
3267 | The following example shows a convenient way of creating a throwaway buffer |
3268 | that is only used in one frame and gets automatically released in |
3269 | endFrame(). (when it comes to the underlying native buffer(s), the usual |
3270 | guarantee applies: the QRhi backend defers the releasing of those until it |
3271 | is guaranteed that the frame in which the buffer is accessed by the GPU has |
3272 | completed) |
3273 | |
3274 | \code |
3275 | rhi->beginFrame(swapchain); |
3276 | QRhiBuffer *buf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, 256); |
3277 | buf->deleteLater(); // ! |
3278 | u = rhi->nextResourceUpdateBatch(); |
3279 | u->uploadStaticBuffer(buf, data); |
3280 | // ... draw with buf |
3281 | rhi->endFrame(); |
3282 | \endcode |
3283 | |
3284 | \sa destroy() |
3285 | */ |
3286 | void QRhiResource::deleteLater() |
3287 | { |
3288 | if (m_rhi) |
3289 | m_rhi->addDeleteLater(res: this); |
3290 | else |
3291 | delete this; |
3292 | } |
3293 | |
3294 | /*! |
3295 | \return the currently set object name. By default the name is empty. |
3296 | */ |
3297 | QByteArray QRhiResource::name() const |
3298 | { |
3299 | return m_objectName; |
3300 | } |
3301 | |
3302 | /*! |
3303 | Sets a \a name for the object. |
3304 | |
3305 | This allows getting descriptive names for the native graphics |
3306 | resources visible in graphics debugging tools, such as |
3307 | \l{https://renderdoc.org/}{RenderDoc} and |
3308 | \l{https://developer.apple.com/xcode/}{XCode}. |
3309 | |
3310 | When it comes to naming native objects by relaying the name via the |
3311 | appropriate graphics API, note that the name is ignored when |
3312 | QRhi::DebugMarkers are not supported, and may, depending on the backend, |
3313 | also be ignored when QRhi::EnableDebugMarkers is not set. |
3314 | |
3315 | \note The name may be ignored for objects other than buffers, |
3316 | renderbuffers, and textures, depending on the backend. |
3317 | |
3318 | \note The name may be modified. For slotted resources, such as a QRhiBuffer |
3319 | backed by multiple native buffers, QRhi will append a suffix to make the |
3320 | underlying native buffers easily distinguishable from each other. |
3321 | */ |
3322 | void QRhiResource::setName(const QByteArray &name) |
3323 | { |
3324 | m_objectName = name; |
3325 | } |
3326 | |
3327 | /*! |
3328 | \return the global, unique identifier of this QRhiResource. |
3329 | |
3330 | User code rarely needs to deal with the value directly. It is used |
3331 | internally for tracking and bookkeeping purposes. |
3332 | */ |
3333 | quint64 QRhiResource::globalResourceId() const |
3334 | { |
3335 | return m_id; |
3336 | } |
3337 | |
3338 | /*! |
3339 | \return the QRhi that created this resource. |
3340 | |
3341 | If the QRhi that created this object is already destroyed, the result is |
3342 | \nullptr. |
3343 | */ |
3344 | QRhi *QRhiResource::rhi() const |
3345 | { |
3346 | return m_rhi ? m_rhi->q : nullptr; |
3347 | } |
3348 | |
3349 | /*! |
3350 | \class QRhiBuffer |
3351 | \inmodule QtGui |
3352 | \since 6.6 |
3353 | \brief Vertex, index, or uniform (constant) buffer resource. |
3354 | |
3355 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3356 | for details. |
3357 | |
3358 | A QRhiBuffer encapsulates zero, one, or more native buffer objects (such as |
3359 | a \c VkBuffer or \c MTLBuffer). With some graphics APIs and backends |
3360 | certain types of buffers may not use a native buffer object at all (e.g. |
3361 | OpenGL if uniform buffer objects are not used), but this is transparent to |
3362 | the user of the QRhiBuffer API. Similarly, the fact that some types of |
3363 | buffers may use two or three native buffers underneath, in order to allow |
3364 | efficient per-frame content update without stalling the GPU pipeline, is |
3365 | mostly invisible to the applications and libraries. |
3366 | |
3367 | A QRhiBuffer instance is always created by calling |
3368 | \l{QRhi::newBuffer()}{the QRhi's newBuffer() function}. This creates no |
3369 | native graphics resources. To do that, call create() after setting the |
3370 | appropriate options, such as the type, usage flags, size, although in most cases these |
3371 | are already set based on the arguments passed to |
3372 | \l{QRhi::newBuffer()}{newBuffer()}. |
3373 | |
3374 | \section2 Example usage |
3375 | |
3376 | To create a uniform buffer for a shader where the GLSL uniform block |
3377 | contains a single \c mat4 member, and update the contents: |
3378 | |
3379 | \code |
3380 | QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64); |
3381 | if (!ubuf->create()) { error(); } |
3382 | QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); |
3383 | QMatrix4x4 mvp; |
3384 | // ... set up the modelview-projection matrix |
3385 | batch->updateDynamicBuffer(ubuf, 0, 64, mvp.constData()); |
3386 | // ... |
3387 | commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call |
3388 | \endcode |
3389 | |
3390 | An example of creating a buffer with vertex data: |
3391 | |
3392 | \code |
3393 | const float vertices[] = { -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 1.0f }; |
3394 | QRhiBuffer *vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices)); |
3395 | if (!vbuf->create()) { error(); } |
3396 | QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); |
3397 | batch->uploadStaticBuffer(vbuf, vertices); |
3398 | // ... |
3399 | commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call |
3400 | \endcode |
3401 | |
3402 | An index buffer: |
3403 | |
3404 | \code |
3405 | static const quint16 indices[] = { 0, 1, 2 }; |
3406 | QRhiBuffer *ibuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(indices)); |
3407 | if (!ibuf->create()) { error(); } |
3408 | QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); |
3409 | batch->uploadStaticBuffer(ibuf, indices); |
3410 | // ... |
3411 | commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call |
3412 | \endcode |
3413 | |
3414 | \section2 Common patterns |
3415 | |
3416 | A call to create() destroys any existing native resources if create() was |
3417 | successfully called before. If those native resources are still in use by |
3418 | an in-flight frame (i.e., there's a chance they are still read by the GPU), |
3419 | the destroying of those resources is deferred automatically. Thus a very |
3420 | common and convenient pattern to safely increase the size of an already |
3421 | initialized buffer is the following. In practice this drops and creates a |
3422 | whole new set of native resources underneath, so it is not necessarily a |
3423 | cheap operation, but is more convenient and still faster than the |
3424 | alternatives, because by not destroying the \c buf object itself, all |
3425 | references to it stay valid in other data structures (e.g., in any |
3426 | QRhiShaderResourceBinding the QRhiBuffer is referenced from). |
3427 | |
3428 | \code |
3429 | if (buf->size() < newSize) { |
3430 | buf->setSize(newSize); |
3431 | if (!buf->create()) { error(); } |
3432 | } |
3433 | // continue using buf, fill it with new data |
3434 | \endcode |
3435 | |
3436 | When working with uniform buffers, it will sometimes be necessary to |
3437 | combine data for multiple draw calls into a single buffer for efficiency |
3438 | reasons. Be aware of the aligment requirements: with some graphics APIs |
3439 | offsets for a uniform buffer must be aligned to 256 bytes. This applies |
3440 | both to QRhiShaderResourceBinding and to the dynamic offsets passed to |
3441 | \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()}. Use the |
3442 | \l{QRhi::ubufAlignment()}{ubufAlignment()} and |
3443 | \l{QRhi::ubufAligned()}{ubufAligned()} functions to create portable code. |
3444 | As an example, the following is an outline for issuing multiple (\c N) draw |
3445 | calls with the same pipeline and geometry, but with a different data in the |
3446 | uniform buffers exposed at binding point 0. This assumes the buffer is |
3447 | exposed via |
3448 | \l{QRhiShaderResourceBinding::uniformBufferWithDynamicOffset()}{uniformBufferWithDynamicOffset()} |
3449 | which allows passing a QRhiCommandBuffer::DynamicOffset list to |
3450 | \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()}. |
3451 | |
3452 | \code |
3453 | const int N = 2; |
3454 | const int UB_SIZE = 64 + 4; // assuming a uniform block with { mat4 matrix; float opacity; } |
3455 | const int ONE_UBUF_SIZE = rhi->ubufAligned(UB_SIZE); |
3456 | const int TOTAL_UBUF_SIZE = N * ONE_UBUF_SIZE; |
3457 | QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, TOTAL_UBUF_SIZE); |
3458 | if (!ubuf->create()) { error(); } |
3459 | QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); |
3460 | for (int i = 0; i < N; ++i) { |
3461 | batch->updateDynamicBuffer(ubuf, i * ONE_UBUF_SIZE, 64, matrix.constData()); |
3462 | updates->updateDynamicBuffer(ubuf, i * ONE_UBUF_SIZE + 64, 4, &opacity); |
3463 | } |
3464 | // ... |
3465 | // beginPass(), set pipeline, etc., and then: |
3466 | for (int i = 0; i < N; ++i) { |
3467 | QRhiCommandBuffer::DynamicOffset dynOfs[] = { { 0, i * ONE_UBUF_SIZE } }; |
3468 | cb->setShaderResources(srb, 1, dynOfs); |
3469 | cb->draw(36); |
3470 | } |
3471 | \endcode |
3472 | |
3473 | \sa QRhiResourceUpdateBatch, QRhi, QRhiCommandBuffer |
3474 | */ |
3475 | |
3476 | /*! |
3477 | \enum QRhiBuffer::Type |
3478 | Specifies storage type of buffer resource. |
3479 | |
3480 | \value Immutable Indicates that the data is not expected to change ever |
3481 | after the initial upload. Under the hood such buffer resources are |
3482 | typically placed in device local (GPU) memory (on systems where |
3483 | applicable). Uploading new data is possible, but may be expensive. The |
3484 | upload typically happens by copying to a separate, host visible staging |
3485 | buffer from which a GPU buffer-to-buffer copy is issued into the actual |
3486 | GPU-only buffer. |
3487 | |
3488 | \value Static Indicates that the data is expected to change only |
3489 | infrequently. Typically placed in device local (GPU) memory, where |
3490 | applicable. On backends where host visible staging buffers are used for |
3491 | uploading, the staging buffers are kept around for this type, unlike with |
3492 | Immutable, so subsequent uploads do not suffer in performance. Frequent |
3493 | updates, especially updates in consecutive frames, should be avoided. |
3494 | |
3495 | \value Dynamic Indicates that the data is expected to change frequently. |
3496 | Not recommended for large buffers. Typically backed by host visible memory |
3497 | in 2 copies in order to allow for changing without stalling the graphics |
3498 | pipeline. The double buffering is managed transparently to the applications |
3499 | and is not exposed in the API here in any form. This is the recommended, |
3500 | and, with some backends, the only possible, type for buffers with |
3501 | UniformBuffer usage. |
3502 | */ |
3503 | |
3504 | /*! |
3505 | \enum QRhiBuffer::UsageFlag |
3506 | Flag values to specify how the buffer is going to be used. |
3507 | |
3508 | \value VertexBuffer Vertex buffer. This allows the QRhiBuffer to be used in |
3509 | \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()}. |
3510 | |
3511 | \value IndexBuffer Index buffer. This allows the QRhiBuffer to be used in |
3512 | \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()}. |
3513 | |
3514 | \value UniformBuffer Uniform buffer (also called constant buffer). This |
3515 | allows the QRhiBuffer to be used in combination with |
3516 | \l{QRhiShaderResourceBinding::UniformBuffer}{UniformBuffer}. When |
3517 | \l{QRhi::NonDynamicUniformBuffers}{NonDynamicUniformBuffers} is reported as |
3518 | not supported, this usage can only be combined with the type Dynamic. |
3519 | |
3520 | \value StorageBuffer Storage buffer. This allows the QRhiBuffer to be used |
3521 | in combination with \l{QRhiShaderResourceBinding::BufferLoad}{BufferLoad}, |
3522 | \l{QRhiShaderResourceBinding::BufferStore}{BufferStore}, or |
3523 | \l{QRhiShaderResourceBinding::BufferLoadStore}{BufferLoadStore}. This usage |
3524 | can only be combined with the types Immutable or Static, and is only |
3525 | available when the \l{QRhi::Compute}{Compute feature} is reported as |
3526 | supported. |
3527 | */ |
3528 | |
3529 | /*! |
3530 | \class QRhiBuffer::NativeBuffer |
3531 | \inmodule QtGui |
3532 | \brief Contains information about the underlying native resources of a buffer. |
3533 | */ |
3534 | |
3535 | /*! |
3536 | \variable QRhiBuffer::NativeBuffer::objects |
3537 | \brief an array with pointers to the native object handles. |
3538 | |
3539 | With OpenGL, the native handle is a GLuint value, so the elements in the \c |
3540 | objects array are pointers to a GLuint. With Vulkan, the native handle is a |
3541 | VkBuffer, so the elements of the array are pointers to a VkBuffer. With |
3542 | Direct3D 11 and Metal the elements are pointers to a ID3D11Buffer or |
3543 | MTLBuffer pointer, respectively. With Direct3D 12, the elements are |
3544 | pointers to a ID3D12Resource. |
3545 | |
3546 | \note Pay attention to the fact that the elements are always pointers to |
3547 | the native buffer handle type, even if the native type itself is a pointer. |
3548 | (so the elements are \c{VkBuffer *} on Vulkan, even though VkBuffer itself |
3549 | is a pointer on 64-bit architectures). |
3550 | */ |
3551 | |
3552 | /*! |
3553 | \variable QRhiBuffer::NativeBuffer::slotCount |
3554 | \brief Specifies the number of valid elements in the objects array. |
3555 | |
3556 | The value can be 0, 1, 2, or 3 in practice. 0 indicates that the QRhiBuffer |
3557 | is not backed by any native buffer objects. This can happen with |
3558 | QRhiBuffers with the usage UniformBuffer when the underlying API does not |
3559 | support (or the backend chooses not to use) native uniform buffers. 1 is |
3560 | commonly used for Immutable and Static types (but some backends may |
3561 | differ). 2 or 3 is typical when the type is Dynamic (but some backends may |
3562 | differ). |
3563 | |
3564 | \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight |
3565 | */ |
3566 | |
3567 | /*! |
3568 | \internal |
3569 | */ |
3570 | QRhiBuffer::QRhiBuffer(QRhiImplementation *rhi, Type type_, UsageFlags usage_, quint32 size_) |
3571 | : QRhiResource(rhi), |
3572 | m_type(type_), m_usage(usage_), m_size(size_) |
3573 | { |
3574 | } |
3575 | |
3576 | /*! |
3577 | \return the resource type. |
3578 | */ |
3579 | QRhiResource::Type QRhiBuffer::resourceType() const |
3580 | { |
3581 | return Buffer; |
3582 | } |
3583 | |
3584 | /*! |
3585 | \fn virtual bool QRhiBuffer::create() = 0 |
3586 | |
3587 | Creates the corresponding native graphics resources. If there are already |
3588 | resources present due to an earlier create() with no corresponding |
3589 | destroy(), then destroy() is called implicitly first. |
3590 | |
3591 | \return \c true when successful, \c false when a graphics operation failed. |
3592 | Regardless of the return value, calling destroy() is always safe. |
3593 | */ |
3594 | |
3595 | /*! |
3596 | \fn QRhiBuffer::Type QRhiBuffer::type() const |
3597 | \return the buffer type. |
3598 | */ |
3599 | |
3600 | /*! |
3601 | \fn void QRhiBuffer::setType(Type t) |
3602 | Sets the buffer's type to \a t. |
3603 | */ |
3604 | |
3605 | /*! |
3606 | \fn QRhiBuffer::UsageFlags QRhiBuffer::usage() const |
3607 | \return the buffer's usage flags. |
3608 | */ |
3609 | |
3610 | /*! |
3611 | \fn void QRhiBuffer::setUsage(UsageFlags u) |
3612 | Sets the buffer's usage flags to \a u. |
3613 | */ |
3614 | |
3615 | /*! |
3616 | \fn quint32 QRhiBuffer::size() const |
3617 | |
3618 | \return the buffer's size in bytes. |
3619 | |
3620 | This is always the value that was passed to setSize() or QRhi::newBuffer(). |
3621 | Internally, the native buffers may be bigger if that is required by the |
3622 | underlying graphics API. |
3623 | */ |
3624 | |
3625 | /*! |
3626 | \fn void QRhiBuffer::setSize(quint32 sz) |
3627 | |
3628 | Sets the size of the buffer in bytes. The size is normally specified in |
3629 | QRhi::newBuffer() so this function is only used when the size has to be |
3630 | changed. As with other setters, the size only takes effect when calling |
3631 | create(), and for already created buffers this involves releasing the previous |
3632 | native resource and creating new ones under the hood. |
3633 | |
3634 | Backends may choose to allocate buffers bigger than \a sz in order to |
3635 | fulfill alignment requirements. This is hidden from the applications and |
3636 | size() will always report the size requested in \a sz. |
3637 | */ |
3638 | |
3639 | /*! |
3640 | \return the underlying native resources for this buffer. The returned value |
3641 | will be empty if exposing the underlying native resources is not supported by |
3642 | the backend. |
3643 | |
3644 | A QRhiBuffer may be backed by multiple native buffer objects, depending on |
3645 | the type() and the QRhi backend in use. When this is the case, all of them |
3646 | are returned in the objects array in the returned struct, with slotCount |
3647 | specifying the number of native buffer objects. While |
3648 | \l{QRhi::beginFrame()}{recording a frame}, QRhi::currentFrameSlot() can be |
3649 | used to determine which of the native buffers QRhi is using for operations |
3650 | that read or write from this QRhiBuffer within the frame being recorded. |
3651 | |
3652 | In some cases a QRhiBuffer will not be backed by a native buffer object at |
3653 | all. In this case slotCount will be set to 0 and no valid native objects |
3654 | are returned. This is not an error, and is perfectly valid when a given |
3655 | backend does not use native buffers for QRhiBuffers with certain types or |
3656 | usages. |
3657 | |
3658 | \note Be aware that QRhi backends may employ various buffer update |
3659 | strategies. Unlike textures, where uploading image data always means |
3660 | recording a buffer-to-image (or similar) copy command on the command |
3661 | buffer, buffers, in particular Dynamic and UniformBuffer ones, can operate |
3662 | in many different ways. For example, a QRhiBuffer with usage type |
3663 | UniformBuffer may not even be backed by a native buffer object at all if |
3664 | uniform buffers are not used or supported by a given backend and graphics |
3665 | API. There are also differences to how data is written to the buffer and |
3666 | the type of backing memory used. For buffers backed by host visible memory, |
3667 | calling this function guarantees that pending host writes are executed for |
3668 | all the returned native buffers. |
3669 | |
3670 | \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight |
3671 | */ |
3672 | QRhiBuffer::NativeBuffer QRhiBuffer::nativeBuffer() |
3673 | { |
3674 | return {}; |
3675 | } |
3676 | |
3677 | /*! |
3678 | \return a pointer to a memory block with the host visible buffer data. |
3679 | |
3680 | This is a shortcut for medium-to-large dynamic uniform buffers that have |
3681 | their \b entire contents (or at least all regions that are read by the |
3682 | shaders in the current frame) changed \b{in every frame} and the |
3683 | QRhiResourceUpdateBatch-based update mechanism is seen too heavy due to the |
3684 | amount of data copying involved. |
3685 | |
3686 | The call to this function must be eventually followed by a call to |
3687 | endFullDynamicUniformBufferUpdateForCurrentFrame(), before recording any |
3688 | render or compute pass that relies on this buffer. |
3689 | |
3690 | \warning Updating data via this method is not compatible with |
3691 | QRhiResourceUpdateBatch-based updates and readbacks. Unexpected behavior |
3692 | may occur when attempting to combine the two update models for the same |
3693 | buffer. Similarly, the data updated this direct way may not be visible to |
3694 | \l{QRhiResourceUpdateBatch::readBackBuffer()}{readBackBuffer operations}, |
3695 | depending on the backend. |
3696 | |
3697 | \warning When updating buffer data via this method, the update must be done |
3698 | in every frame, otherwise backends that perform double or triple buffering |
3699 | of resources may end up in unexpected behavior. |
3700 | |
3701 | \warning Partial updates are not possible with this approach since some |
3702 | backends may choose a strategy where the previous contents of the buffer is |
3703 | lost upon calling this function. Data must be written to all regions that |
3704 | are read by shaders in the frame currently being prepared. |
3705 | |
3706 | \warning This function can only be called when recording a frame, so |
3707 | between QRhi::beginFrame() and QRhi::endFrame(). |
3708 | |
3709 | \warning This function can only be called on Dynamic buffers. |
3710 | */ |
3711 | char *QRhiBuffer::beginFullDynamicBufferUpdateForCurrentFrame() |
3712 | { |
3713 | return nullptr; |
3714 | } |
3715 | |
3716 | /*! |
3717 | To be called when the entire contents of the buffer data has been updated |
3718 | in the memory block returned from |
3719 | beginFullDynamicBufferUpdateForCurrentFrame(). |
3720 | */ |
3721 | void QRhiBuffer::endFullDynamicBufferUpdateForCurrentFrame() |
3722 | { |
3723 | } |
3724 | |
3725 | /*! |
3726 | \class QRhiRenderBuffer |
3727 | \inmodule QtGui |
3728 | \since 6.6 |
3729 | \brief Renderbuffer resource. |
3730 | |
3731 | Renderbuffers cannot be sampled or read but have some benefits over |
3732 | textures in some cases: |
3733 | |
3734 | A \l DepthStencil renderbuffer may be lazily allocated and be backed by |
3735 | transient memory with some APIs. On some platforms this may mean the |
3736 | depth/stencil buffer uses no physical backing at all. |
3737 | |
3738 | \l Color renderbuffers are useful since QRhi::MultisampleRenderBuffer may be |
3739 | supported even when QRhi::MultisampleTexture is not. |
3740 | |
3741 | How the renderbuffer is implemented by a backend is not exposed to the |
3742 | applications. In some cases it may be backed by ordinary textures, while in |
3743 | others there may be a different kind of native resource used. |
3744 | |
3745 | Renderbuffers that are used as (and are only used as) depth-stencil buffers |
3746 | in combination with a QRhiSwapChain's color buffers should have the |
3747 | UsedWithSwapChainOnly flag set. This serves a double purpose: such buffers, |
3748 | depending on the backend and the underlying APIs, be more efficient, and |
3749 | QRhi provides automatic sizing behavior to match the color buffers, which |
3750 | means calling setPixelSize() and create() are not necessary for such |
3751 | renderbuffers. |
3752 | |
3753 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3754 | for details. |
3755 | */ |
3756 | |
3757 | /*! |
3758 | \enum QRhiRenderBuffer::Type |
3759 | Specifies the type of the renderbuffer |
3760 | |
3761 | \value DepthStencil Combined depth/stencil |
3762 | \value Color Color |
3763 | */ |
3764 | |
3765 | /*! |
3766 | \struct QRhiRenderBuffer::NativeRenderBuffer |
3767 | \inmodule QtGui |
3768 | \brief Wraps a native renderbuffer object. |
3769 | */ |
3770 | |
3771 | /*! |
3772 | \variable QRhiRenderBuffer::NativeRenderBuffer::object |
3773 | \brief 64-bit integer containing the native object handle. |
3774 | |
3775 | Used with QRhiRenderBuffer::createFrom(). |
3776 | |
3777 | With OpenGL the native handle is a GLuint value. \c object is expected to |
3778 | be a valid OpenGL renderbuffer object ID. |
3779 | */ |
3780 | |
3781 | /*! |
3782 | \enum QRhiRenderBuffer::Flag |
3783 | Flag values for flags() and setFlags() |
3784 | |
3785 | \value UsedWithSwapChainOnly For DepthStencil renderbuffers this indicates |
3786 | that the renderbuffer is only used in combination with a QRhiSwapChain, and |
3787 | never in any other way. This provides automatic sizing and resource |
3788 | rebuilding, so calling setPixelSize() or create() is not needed whenever |
3789 | this flag is set. This flag value may also trigger backend-specific |
3790 | behavior, for example with OpenGL, where a separate windowing system |
3791 | interface API is in use (EGL, GLX, etc.), the flag is especially important |
3792 | as it avoids creating any actual renderbuffer resource as there is already |
3793 | a windowing system provided depth/stencil buffer as requested by |
3794 | QSurfaceFormat. |
3795 | */ |
3796 | |
3797 | /*! |
3798 | \internal |
3799 | */ |
3800 | QRhiRenderBuffer::QRhiRenderBuffer(QRhiImplementation *rhi, Type type_, const QSize &pixelSize_, |
3801 | int sampleCount_, Flags flags_, |
3802 | QRhiTexture::Format backingFormatHint_) |
3803 | : QRhiResource(rhi), |
3804 | m_type(type_), m_pixelSize(pixelSize_), m_sampleCount(sampleCount_), m_flags(flags_), |
3805 | m_backingFormatHint(backingFormatHint_) |
3806 | { |
3807 | } |
3808 | |
3809 | /*! |
3810 | \return the resource type. |
3811 | */ |
3812 | QRhiResource::Type QRhiRenderBuffer::resourceType() const |
3813 | { |
3814 | return RenderBuffer; |
3815 | } |
3816 | |
3817 | /*! |
3818 | \fn virtual bool QRhiRenderBuffer::create() = 0 |
3819 | |
3820 | Creates the corresponding native graphics resources. If there are already |
3821 | resources present due to an earlier create() with no corresponding |
3822 | destroy(), then destroy() is called implicitly first. |
3823 | |
3824 | \return \c true when successful, \c false when a graphics operation failed. |
3825 | Regardless of the return value, calling destroy() is always safe. |
3826 | */ |
3827 | |
3828 | /*! |
3829 | Similar to create() except that no new native renderbuffer objects are |
3830 | created. Instead, the native renderbuffer object specified by \a src is |
3831 | used. |
3832 | |
3833 | This allows importing an existing renderbuffer object (which must belong to |
3834 | the same device or sharing context, depending on the graphics API) from an |
3835 | external graphics engine. |
3836 | |
3837 | \note This is currently applicable to OpenGL only. This function exists |
3838 | solely to allow importing a renderbuffer object that is bound to some |
3839 | special, external object, such as an EGLImageKHR. Once the application |
3840 | performed the glEGLImageTargetRenderbufferStorageOES call, the renderbuffer |
3841 | object can be passed to this function to create a wrapping |
3842 | QRhiRenderBuffer, which in turn can be passed in as a color attachment to |
3843 | a QRhiTextureRenderTarget to enable rendering to the EGLImage. |
3844 | |
3845 | \note pixelSize(), sampleCount(), and flags() must still be set correctly. |
3846 | Passing incorrect sizes and other values to QRhi::newRenderBuffer() and |
3847 | then following it with a createFrom() expecting that the native |
3848 | renderbuffer object alone is sufficient to deduce such values is \b wrong |
3849 | and will lead to problems. |
3850 | |
3851 | \note QRhiRenderBuffer does not take ownership of the native object, and |
3852 | destroy() will not release that object. |
3853 | |
3854 | \note This function is only implemented when the QRhi::RenderBufferImport |
3855 | feature is reported as \l{QRhi::isFeatureSupported()}{supported}. Otherwise, |
3856 | the function does nothing and the return value is \c false. |
3857 | |
3858 | \return \c true when successful, \c false when not supported. |
3859 | */ |
3860 | bool QRhiRenderBuffer::createFrom(NativeRenderBuffer src) |
3861 | { |
3862 | Q_UNUSED(src); |
3863 | return false; |
3864 | } |
3865 | |
3866 | /*! |
3867 | \fn QRhiRenderBuffer::Type QRhiRenderBuffer::type() const |
3868 | \return the renderbuffer type. |
3869 | */ |
3870 | |
3871 | /*! |
3872 | \fn void QRhiRenderBuffer::setType(Type t) |
3873 | Sets the type to \a t. |
3874 | */ |
3875 | |
3876 | /*! |
3877 | \fn QSize QRhiRenderBuffer::pixelSize() const |
3878 | \return the pixel size. |
3879 | */ |
3880 | |
3881 | /*! |
3882 | \fn void QRhiRenderBuffer::setPixelSize(const QSize &sz) |
3883 | Sets the size (in pixels) to \a sz. |
3884 | */ |
3885 | |
3886 | /*! |
3887 | \fn int QRhiRenderBuffer::sampleCount() const |
3888 | \return the sample count. 1 means no multisample antialiasing. |
3889 | */ |
3890 | |
3891 | /*! |
3892 | \fn void QRhiRenderBuffer::setSampleCount(int s) |
3893 | Sets the sample count to \a s. |
3894 | */ |
3895 | |
3896 | /*! |
3897 | \fn QRhiRenderBuffer::Flags QRhiRenderBuffer::flags() const |
3898 | \return the flags. |
3899 | */ |
3900 | |
3901 | /*! |
3902 | \fn void QRhiRenderBuffer::setFlags(Flags f) |
3903 | Sets the flags to \a f. |
3904 | */ |
3905 | |
3906 | /*! |
3907 | \fn virtual QRhiTexture::Format QRhiRenderBuffer::backingFormat() const = 0 |
3908 | |
3909 | \internal |
3910 | */ |
3911 | |
3912 | /*! |
3913 | \class QRhiTexture |
3914 | \inmodule QtGui |
3915 | \since 6.6 |
3916 | \brief Texture resource. |
3917 | |
3918 | A QRhiTexture encapsulates a native texture object, such as a \c VkImage or |
3919 | \c MTLTexture. |
3920 | |
3921 | A QRhiTexture instance is always created by calling |
3922 | \l{QRhi::newTexture()}{the QRhi's newTexture() function}. This creates no |
3923 | native graphics resources. To do that, call create() after setting the |
3924 | appropriate options, such as the format and size, although in most cases |
3925 | these are already set based on the arguments passed to |
3926 | \l{QRhi::newTexture()}{newTexture()}. |
3927 | |
3928 | Setting the \l{QRhiTexture::Flags}{flags} correctly is essential, otherwise |
3929 | various errors can occur depending on the underlying QRhi backend and |
3930 | graphics API. For example, when a texture will be rendered into from a |
3931 | render pass via QRhiTextureRenderTarget, the texture must be created with |
3932 | the \l RenderTarget flag set. Similarly, when the texture is going to be |
3933 | \l{QRhiResourceUpdateBatch::readBackTexture()}{read back}, the \l |
3934 | UsedAsTransferSource flag must be set upfront. Mipmapped textures must have |
3935 | the MipMapped flag set. And so on. It is not possible to change the flags |
3936 | once create() has succeeded. To release the existing and create a new |
3937 | native texture object with the changed settings, call the setters and call |
3938 | create() again. This then might be a potentially expensive operation. |
3939 | |
3940 | \section2 Example usage |
3941 | |
3942 | To create a 2D texture with a size of 512x512 pixels and set its contents to all green: |
3943 | |
3944 | \code |
3945 | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512)); |
3946 | if (!texture->create()) { error(); } |
3947 | QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); |
3948 | QImage image(512, 512, QImage::Format_RGBA8888); |
3949 | image.fill(Qt::green); |
3950 | batch->uploadTexture(texture, image); |
3951 | // ... |
3952 | commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call |
3953 | \endcode |
3954 | |
3955 | \section2 Common patterns |
3956 | |
3957 | A call to create() destroys any existing native resources if create() was |
3958 | successfully called before. If those native resources are still in use by |
3959 | an in-flight frame (i.e., there's a chance they are still read by the GPU), |
3960 | the destroying of those resources is deferred automatically. Thus a very |
3961 | common and convenient pattern to safely change the size of an already |
3962 | existing texture is the following. In practice this drops and creates a |
3963 | whole new native texture resource underneath, so it is not necessarily a |
3964 | cheap operation, but is more convenient and still faster than the |
3965 | alternatives, because by not destroying the \c texture object itself, all |
3966 | references to it stay valid in other data structures (e.g., in any |
3967 | QShaderResourceBinding the QRhiTexture is referenced from). |
3968 | |
3969 | \code |
3970 | // determine newSize, e.g. based on the swapchain's output size or other factors |
3971 | if (texture->pixelSize() != newSize) { |
3972 | texture->setPixelSize(newSize); |
3973 | if (!texture->create()) { error(); } |
3974 | } |
3975 | // continue using texture, fill it with new data |
3976 | \endcode |
3977 | |
3978 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3979 | for details. |
3980 | |
3981 | \sa QRhiResourceUpdateBatch, QRhi, QRhiTextureRenderTarget |
3982 | */ |
3983 | |
3984 | /*! |
3985 | \enum QRhiTexture::Flag |
3986 | |
3987 | Flag values to specify how the texture is going to be used. Not honoring |
3988 | the flags set before create() and attempting to use the texture in ways that |
3989 | was not declared upfront can lead to unspecified behavior or decreased |
3990 | performance depending on the backend and the underlying graphics API. |
3991 | |
3992 | \value RenderTarget The texture going to be used in combination with |
3993 | QRhiTextureRenderTarget. |
3994 | |
3995 | \value CubeMap The texture is a cubemap. Such textures have 6 layers, one |
3996 | for each face in the order of +X, -X, +Y, -Y, +Z, -Z. Cubemap textures |
3997 | cannot be multisample. |
3998 | |
3999 | \value MipMapped The texture has mipmaps. The appropriate mip count is |
4000 | calculated automatically and can also be retrieved via |
4001 | QRhi::mipLevelsForSize(). The images for the mip levels have to be |
4002 | provided in the texture uploaded or generated via |
4003 | QRhiResourceUpdateBatch::generateMips(). Multisample textures cannot have |
4004 | mipmaps. |
4005 | |
4006 | \value sRGB Use an sRGB format. |
4007 | |
4008 | \value UsedAsTransferSource The texture is used as the source of a texture |
4009 | copy or readback, meaning the texture is given as the source in |
4010 | QRhiResourceUpdateBatch::copyTexture() or |
4011 | QRhiResourceUpdateBatch::readBackTexture(). |
4012 | |
4013 | \value UsedWithGenerateMips The texture is going to be used with |
4014 | QRhiResourceUpdateBatch::generateMips(). |
4015 | |
4016 | \value UsedWithLoadStore The texture is going to be used with image |
4017 | load/store operations, for example, in a compute shader. |
4018 | |
4019 | \value UsedAsCompressedAtlas The texture has a compressed format and the |
4020 | dimensions of subresource uploads may not match the texture size. |
4021 | |
4022 | \value ExternalOES The texture should use the GL_TEXTURE_EXTERNAL_OES |
4023 | target with OpenGL. This flag is ignored with other graphics APIs. |
4024 | |
4025 | \value ThreeDimensional The texture is a 3D texture. Such textures should |
4026 | be created with the QRhi::newTexture() overload taking a depth in addition |
4027 | to width and height. A 3D texture can have mipmaps but cannot be |
4028 | multisample. When rendering into, or uploading data to a 3D texture, the \c |
4029 | layer specified in the render target's color attachment or the upload |
4030 | description refers to a single slice in range [0..depth-1]. The underlying |
4031 | graphics API may not support 3D textures at run time. Support is indicated |
4032 | by the QRhi::ThreeDimensionalTextures feature. |
4033 | |
4034 | \value TextureRectangleGL The texture should use the GL_TEXTURE_RECTANGLE |
4035 | target with OpenGL. This flag is ignored with other graphics APIs. Just |
4036 | like ExternalOES, this flag is useful when working with platform APIs where |
4037 | native OpenGL texture objects received from the platform are wrapped in a |
4038 | QRhiTexture, and the platform can only provide textures for a non-2D |
4039 | texture target. |
4040 | |
4041 | \value TextureArray The texture is a texture array, i.e. a single texture |
4042 | object that is a homogeneous array of 2D textures. Texture arrays are |
4043 | created with QRhi::newTextureArray(). The underlying graphics API may not |
4044 | support texture array objects at run time. Support is indicated by the |
4045 | QRhi::TextureArrays feature. When rendering into, or uploading data to a |
4046 | texture array, the \c layer specified in the render target's color |
4047 | attachment or the upload description selects a single element in the array. |
4048 | |
4049 | \value OneDimensional The texture is a 1D texture. Such textures can be |
4050 | created by passing a 0 height and depth to QRhi::newTexture(). Note that |
4051 | there can be limitations on one dimensional textures depending on the |
4052 | underlying graphics API. For example, rendering to them or using them with |
4053 | mipmap-based filtering may be unsupported. This is indicated by the |
4054 | QRhi::OneDimensionalTextures and QRhi::OneDimensionalTextureMipmaps |
4055 | feature flags. |
4056 | */ |
4057 | |
4058 | /*! |
4059 | \enum QRhiTexture::Format |
4060 | |
4061 | Specifies the texture format. See also QRhi::isTextureFormatSupported() and |
4062 | note that flags() can modify the format when QRhiTexture::sRGB is set. |
4063 | |
4064 | \value UnknownFormat Not a valid format. This cannot be passed to setFormat(). |
4065 | |
4066 | \value RGBA8 Four component, unsigned normalized 8 bit per component. Always supported. |
4067 | |
4068 | \value BGRA8 Four component, unsigned normalized 8 bit per component. |
4069 | |
4070 | \value R8 One component, unsigned normalized 8 bit. |
4071 | |
4072 | \value RG8 Two components, unsigned normalized 8 bit. |
4073 | |
4074 | \value R16 One component, unsigned normalized 16 bit. |
4075 | |
4076 | \value RG16 Two component, unsigned normalized 16 bit. |
4077 | |
4078 | \value RED_OR_ALPHA8 Either same as R8, or is a similar format with the component swizzled to alpha, |
4079 | depending on \l{QRhi::RedOrAlpha8IsRed}{RedOrAlpha8IsRed}. |
4080 | |
4081 | \value RGBA16F Four components, 16-bit float per component. |
4082 | |
4083 | \value RGBA32F Four components, 32-bit float per component. |
4084 | |
4085 | \value R16F One component, 16-bit float. |
4086 | |
4087 | \value R32F One component, 32-bit float. |
4088 | |
4089 | \value RGB10A2 Four components, unsigned normalized 10 bit R, G, and B, |
4090 | 2-bit alpha. This is a packed format so native endianness applies. Note |
4091 | that there is no BGR10A2. This is because RGB10A2 maps to |
4092 | DXGI_FORMAT_R10G10B10A2_UNORM with D3D, MTLPixelFormatRGB10A2Unorm with |
4093 | Metal, VK_FORMAT_A2B10G10R10_UNORM_PACK32 with Vulkan, and |
4094 | GL_RGB10_A2/GL_RGB/GL_UNSIGNED_INT_2_10_10_10_REV on OpenGL (ES). This is |
4095 | the only universally supported RGB30 option. The corresponding QImage |
4096 | formats are QImage::Format_BGR30 and QImage::Format_A2BGR30_Premultiplied. |
4097 | |
4098 | \value D16 16-bit depth (normalized unsigned integer) |
4099 | |
4100 | \value D24 24-bit depth (normalized unsigned integer) |
4101 | |
4102 | \value D24S8 24-bit depth (normalized unsigned integer), 8 bit stencil |
4103 | |
4104 | \value D32F 32-bit depth (32-bit float) |
4105 | |
4106 | \value BC1 |
4107 | \value BC2 |
4108 | \value BC3 |
4109 | \value BC4 |
4110 | \value BC5 |
4111 | \value BC6H |
4112 | \value BC7 |
4113 | |
4114 | \value ETC2_RGB8 |
4115 | \value ETC2_RGB8A1 |
4116 | \value ETC2_RGBA8 |
4117 | |
4118 | \value ASTC_4x4 |
4119 | \value ASTC_5x4 |
4120 | \value ASTC_5x5 |
4121 | \value ASTC_6x5 |
4122 | \value ASTC_6x6 |
4123 | \value ASTC_8x5 |
4124 | \value ASTC_8x6 |
4125 | \value ASTC_8x8 |
4126 | \value ASTC_10x5 |
4127 | \value ASTC_10x6 |
4128 | \value ASTC_10x8 |
4129 | \value ASTC_10x10 |
4130 | \value ASTC_12x10 |
4131 | \value ASTC_12x12 |
4132 | */ |
4133 | |
4134 | /*! |
4135 | \struct QRhiTexture::NativeTexture |
4136 | \inmodule QtGui |
4137 | \brief Contains information about the underlying native resources of a texture. |
4138 | */ |
4139 | |
4140 | /*! |
4141 | \variable QRhiTexture::NativeTexture::object |
4142 | \brief 64-bit integer containing the native object handle. |
4143 | |
4144 | With OpenGL, the native handle is a GLuint value, so \c object can then be |
4145 | cast to a GLuint. With Vulkan, the native handle is a VkImage, so \c object |
4146 | can be cast to a VkImage. With Direct3D 11 and Metal \c object contains a |
4147 | ID3D11Texture2D or MTLTexture pointer, respectively. With Direct3D 12 |
4148 | \c object contains a ID3D12Resource pointer. |
4149 | */ |
4150 | |
4151 | /*! |
4152 | \variable QRhiTexture::NativeTexture::layout |
4153 | \brief Specifies the current image layout for APIs like Vulkan. |
4154 | |
4155 | For Vulkan, \c layout contains a \c VkImageLayout value. |
4156 | */ |
4157 | |
4158 | /*! |
4159 | \internal |
4160 | */ |
4161 | QRhiTexture::QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_, int depth_, |
4162 | int arraySize_, int sampleCount_, Flags flags_) |
4163 | : QRhiResource(rhi), |
4164 | m_format(format_), m_pixelSize(pixelSize_), m_depth(depth_), |
4165 | m_arraySize(arraySize_), m_sampleCount(sampleCount_), m_flags(flags_) |
4166 | { |
4167 | } |
4168 | |
4169 | /*! |
4170 | \return the resource type. |
4171 | */ |
4172 | QRhiResource::Type QRhiTexture::resourceType() const |
4173 | { |
4174 | return Texture; |
4175 | } |
4176 | |
4177 | /*! |
4178 | \fn virtual bool QRhiTexture::create() = 0 |
4179 | |
4180 | Creates the corresponding native graphics resources. If there are already |
4181 | resources present due to an earlier create() with no corresponding |
4182 | destroy(), then destroy() is called implicitly first. |
4183 | |
4184 | \return \c true when successful, \c false when a graphics operation failed. |
4185 | Regardless of the return value, calling destroy() is always safe. |
4186 | */ |
4187 | |
4188 | /*! |
4189 | \return the underlying native resources for this texture. The returned value |
4190 | will be empty if exposing the underlying native resources is not supported by |
4191 | the backend. |
4192 | |
4193 | \sa createFrom() |
4194 | */ |
4195 | QRhiTexture::NativeTexture QRhiTexture::nativeTexture() |
4196 | { |
4197 | return {}; |
4198 | } |
4199 | |
4200 | /*! |
4201 | Similar to create(), except that no new native textures are created. |
4202 | Instead, the native texture resources specified by \a src is used. |
4203 | |
4204 | This allows importing an existing native texture object (which must belong |
4205 | to the same device or sharing context, depending on the graphics API) from |
4206 | an external graphics engine. |
4207 | |
4208 | \return true if the specified existing native texture object has been |
4209 | successfully wrapped as a non-owning QRhiTexture. |
4210 | |
4211 | \note format(), pixelSize(), sampleCount(), and flags() must still be set |
4212 | correctly. Passing incorrect sizes and other values to QRhi::newTexture() |
4213 | and then following it with a createFrom() expecting that the native texture |
4214 | object alone is sufficient to deduce such values is \b wrong and will lead |
4215 | to problems. |
4216 | |
4217 | \note QRhiTexture does not take ownership of the texture object. destroy() |
4218 | does not free the object or any associated memory. |
4219 | |
4220 | The opposite of this operation, exposing a QRhiTexture-created native |
4221 | texture object to a foreign engine, is possible via nativeTexture(). |
4222 | |
4223 | \note When importing a 3D texture, or a texture array object, or, with |
4224 | OpenGL ES, an external texture, it is then especially important to set the |
4225 | corresponding flags (ThreeDimensional, TextureArray, ExternalOES) via |
4226 | setFlags() before calling this function. |
4227 | */ |
4228 | bool QRhiTexture::createFrom(QRhiTexture::NativeTexture src) |
4229 | { |
4230 | Q_UNUSED(src); |
4231 | return false; |
4232 | } |
4233 | |
4234 | /*! |
4235 | With some graphics APIs, such as Vulkan, integrating custom rendering code |
4236 | that uses the graphics API directly needs special care when it comes to |
4237 | image layouts. This function allows communicating the expected \a layout the |
4238 | image backing the QRhiTexture is in after the native rendering commands. |
4239 | |
4240 | For example, consider rendering into a QRhiTexture's VkImage directly with |
4241 | Vulkan in a code block enclosed by QRhiCommandBuffer::beginExternal() and |
4242 | QRhiCommandBuffer::endExternal(), followed by using the image for texture |
4243 | sampling in a QRhi-based render pass. To avoid potentially incorrect image |
4244 | layout transitions, this function can be used to indicate what the image |
4245 | layout will be once the commands recorded in said code block complete. |
4246 | |
4247 | Calling this function makes sense only after |
4248 | QRhiCommandBuffer::endExternal() and before a subsequent |
4249 | QRhiCommandBuffer::beginPass(). |
4250 | |
4251 | This function has no effect with QRhi backends where the underlying |
4252 | graphics API does not expose a concept of image layouts. |
4253 | |
4254 | \note With Vulkan \a layout is a \c VkImageLayout. With Direct 3D 12 \a |
4255 | layout is a value composed of the bits from \c D3D12_RESOURCE_STATES. |
4256 | */ |
4257 | void QRhiTexture::setNativeLayout(int layout) |
4258 | { |
4259 | Q_UNUSED(layout); |
4260 | } |
4261 | |
4262 | /*! |
4263 | \fn QRhiTexture::Format QRhiTexture::format() const |
4264 | \return the texture format. |
4265 | */ |
4266 | |
4267 | /*! |
4268 | \fn void QRhiTexture::setFormat(QRhiTexture::Format fmt) |
4269 | |
4270 | Sets the requested texture format to \a fmt. |
4271 | |
4272 | \note The value set is only taken into account upon the next call to |
4273 | create(), i.e. when the underlying graphics resource are (re)created. |
4274 | Setting a new value is futile otherwise and must be avoided since it can |
4275 | lead to inconsistent state. |
4276 | */ |
4277 | |
4278 | /*! |
4279 | \fn QSize QRhiTexture::pixelSize() const |
4280 | \return the size in pixels. |
4281 | */ |
4282 | |
4283 | /*! |
4284 | \fn void QRhiTexture::setPixelSize(const QSize &sz) |
4285 | |
4286 | Sets the texture size, specified in pixels, to \a sz. |
4287 | |
4288 | \note The value set is only taken into account upon the next call to |
4289 | create(), i.e. when the underlying graphics resource are (re)created. |
4290 | Setting a new value is futile otherwise and must be avoided since it can |
4291 | lead to inconsistent state. The same applies to all other setters as well. |
4292 | */ |
4293 | |
4294 | /*! |
4295 | \fn int QRhiTexture::depth() const |
4296 | \return the depth for 3D textures. |
4297 | */ |
4298 | |
4299 | /*! |
4300 | \fn void QRhiTexture::setDepth(int depth) |
4301 | Sets the \a depth for a 3D texture. |
4302 | */ |
4303 | |
4304 | /*! |
4305 | \fn int QRhiTexture::arraySize() const |
4306 | \return the texture array size. |
4307 | */ |
4308 | |
4309 | /*! |
4310 | \fn void QRhiTexture::setArraySize(int arraySize) |
4311 | Sets the texture \a arraySize. |
4312 | */ |
4313 | |
4314 | /*! |
4315 | \fn int QRhiTexture::arrayRangeStart() const |
4316 | |
4317 | \return the first array layer when setArrayRange() was called. |
4318 | |
4319 | \sa setArrayRange() |
4320 | */ |
4321 | |
4322 | /*! |
4323 | \fn int QRhiTexture::arrayRangeLength() const |
4324 | |
4325 | \return the exposed array range size when setArrayRange() was called. |
4326 | |
4327 | \sa setArrayRange() |
4328 | */ |
4329 | |
4330 | /*! |
4331 | \fn void QRhiTexture::setArrayRange(int startIndex, int count) |
4332 | |
4333 | Normally all array layers are exposed and it is up to the shader to select |
4334 | the layer via the third coordinate passed to the \c{texture()} GLSL |
4335 | function when sampling the \c sampler2DArray. When QRhi::TextureArrayRange |
4336 | is reported as supported, calling setArrayRange() before create() or |
4337 | createFrom() requests selecting only the specified range, \a count elements |
4338 | starting from \a startIndex. The shader logic can then be written with this |
4339 | in mind. |
4340 | |
4341 | \sa QRhi::TextureArrayRange |
4342 | */ |
4343 | |
4344 | /*! |
4345 | \fn Flags QRhiTexture::flags() const |
4346 | \return the texture flags. |
4347 | */ |
4348 | |
4349 | /*! |
4350 | \fn void QRhiTexture::setFlags(Flags f) |
4351 | Sets the texture flags to \a f. |
4352 | */ |
4353 | |
4354 | /*! |
4355 | \fn int QRhiTexture::sampleCount() const |
4356 | \return the sample count. 1 means no multisample antialiasing. |
4357 | */ |
4358 | |
4359 | /*! |
4360 | \fn void QRhiTexture::setSampleCount(int s) |
4361 | Sets the sample count to \a s. |
4362 | */ |
4363 | |
4364 | /*! |
4365 | \class QRhiSampler |
4366 | \inmodule QtGui |
4367 | \since 6.6 |
4368 | \brief Sampler resource. |
4369 | |
4370 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
4371 | for details. |
4372 | */ |
4373 | |
4374 | /*! |
4375 | \enum QRhiSampler::Filter |
4376 | Specifies the minification, magnification, or mipmap filtering |
4377 | |
4378 | \value None Applicable only for mipmapMode(), indicates no mipmaps to be used |
4379 | \value Nearest |
4380 | \value Linear |
4381 | */ |
4382 | |
4383 | /*! |
4384 | \enum QRhiSampler::AddressMode |
4385 | Specifies the addressing mode |
4386 | |
4387 | \value Repeat |
4388 | \value ClampToEdge |
4389 | \value Mirror |
4390 | */ |
4391 | |
4392 | /*! |
4393 | \enum QRhiSampler::CompareOp |
4394 | Specifies the texture comparison function. |
4395 | |
4396 | \value Never (default) |
4397 | \value Less |
4398 | \value Equal |
4399 | \value LessOrEqual |
4400 | \value Greater |
4401 | \value NotEqual |
4402 | \value GreaterOrEqual |
4403 | \value Always |
4404 | */ |
4405 | |
4406 | /*! |
4407 | \internal |
4408 | */ |
4409 | QRhiSampler::QRhiSampler(QRhiImplementation *rhi, |
4410 | Filter magFilter_, Filter minFilter_, Filter mipmapMode_, |
4411 | AddressMode u_, AddressMode v_, AddressMode w_) |
4412 | : QRhiResource(rhi), |
4413 | m_magFilter(magFilter_), m_minFilter(minFilter_), m_mipmapMode(mipmapMode_), |
4414 | m_addressU(u_), m_addressV(v_), m_addressW(w_), |
4415 | m_compareOp(QRhiSampler::Never) |
4416 | { |
4417 | } |
4418 | |
4419 | /*! |
4420 | \return the resource type. |
4421 | */ |
4422 | QRhiResource::Type QRhiSampler::resourceType() const |
4423 | { |
4424 | return Sampler; |
4425 | } |
4426 | |
4427 | /*! |
4428 | \fn QRhiSampler::Filter QRhiSampler::magFilter() const |
4429 | \return the magnification filter mode. |
4430 | */ |
4431 | |
4432 | /*! |
4433 | \fn void QRhiSampler::setMagFilter(Filter f) |
4434 | Sets the magnification filter mode to \a f. |
4435 | */ |
4436 | |
4437 | /*! |
4438 | \fn QRhiSampler::Filter QRhiSampler::minFilter() const |
4439 | \return the minification filter mode. |
4440 | */ |
4441 | |
4442 | /*! |
4443 | \fn void QRhiSampler::setMinFilter(Filter f) |
4444 | Sets the minification filter mode to \a f. |
4445 | */ |
4446 | |
4447 | /*! |
4448 | \fn QRhiSampler::Filter QRhiSampler::mipmapMode() const |
4449 | \return the mipmap filter mode. |
4450 | */ |
4451 | |
4452 | /*! |
4453 | \fn void QRhiSampler::setMipmapMode(Filter f) |
4454 | |
4455 | Sets the mipmap filter mode to \a f. |
4456 | |
4457 | Leave this set to None when the texture has no mip levels, or when the mip |
4458 | levels are not to be taken into account. |
4459 | */ |
4460 | |
4461 | /*! |
4462 | \fn QRhiSampler::AddressMode QRhiSampler::addressU() const |
4463 | \return the horizontal wrap mode. |
4464 | */ |
4465 | |
4466 | /*! |
4467 | \fn void QRhiSampler::setAddressU(AddressMode mode) |
4468 | Sets the horizontal wrap \a mode. |
4469 | */ |
4470 | |
4471 | /*! |
4472 | \fn QRhiSampler::AddressMode QRhiSampler::addressV() const |
4473 | \return the vertical wrap mode. |
4474 | */ |
4475 | |
4476 | /*! |
4477 | \fn void QRhiSampler::setAddressV(AddressMode mode) |
4478 | Sets the vertical wrap \a mode. |
4479 | */ |
4480 | |
4481 | /*! |
4482 | \fn QRhiSampler::AddressMode QRhiSampler::addressW() const |
4483 | \return the depth wrap mode. |
4484 | */ |
4485 | |
4486 | /*! |
4487 | \fn void QRhiSampler::setAddressW(AddressMode mode) |
4488 | Sets the depth wrap \a mode. |
4489 | */ |
4490 | |
4491 | /*! |
4492 | \fn QRhiSampler::CompareOp QRhiSampler::textureCompareOp() const |
4493 | \return the texture comparison function. |
4494 | */ |
4495 | |
4496 | /*! |
4497 | \fn void QRhiSampler::setTextureCompareOp(CompareOp op) |
4498 | Sets the texture comparison function \a op. |
4499 | */ |
4500 | |
4501 | /*! |
4502 | \class QRhiRenderPassDescriptor |
4503 | \inmodule QtGui |
4504 | \since 6.6 |
4505 | \brief Render pass resource. |
4506 | |
4507 | A render pass, if such a concept exists in the underlying graphics API, is |
4508 | a collection of attachments (color, depth, stencil) and describes how those |
4509 | attachments are used. |
4510 | |
4511 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
4512 | for details. |
4513 | */ |
4514 | |
4515 | /*! |
4516 | \internal |
4517 | */ |
4518 | QRhiRenderPassDescriptor::QRhiRenderPassDescriptor(QRhiImplementation *rhi) |
4519 | : QRhiResource(rhi) |
4520 | { |
4521 | } |
4522 | |
4523 | /*! |
4524 | \return the resource type. |
4525 | */ |
4526 | QRhiResource::Type QRhiRenderPassDescriptor::resourceType() const |
4527 | { |
4528 | return RenderPassDescriptor; |
4529 | } |
4530 | |
4531 | /*! |
4532 | \fn virtual bool QRhiRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const = 0 |
4533 | |
4534 | \return true if the \a other QRhiRenderPassDescriptor is compatible with |
4535 | this one, meaning \c this and \a other can be used interchangebly in |
4536 | QRhiGraphicsPipeline::setRenderPassDescriptor(). |
4537 | |
4538 | The concept of the compatibility of renderpass descriptors is similar to |
4539 | the \l{QRhiShaderResourceBindings::isLayoutCompatible}{layout |
4540 | compatibility} of QRhiShaderResourceBindings instances. They allow better |
4541 | reuse of QRhiGraphicsPipeline instances: for example, a |
4542 | QRhiGraphicsPipeline instance cache is expected to use these functions to |
4543 | look for a matching pipeline, instead of just comparing pointers, thus |
4544 | allowing a different QRhiRenderPassDescriptor and |
4545 | QRhiShaderResourceBindings to be used in combination with the pipeline, as |
4546 | long as they are compatible. |
4547 | |
4548 | The exact details of compatibility depend on the underlying graphics API. |
4549 | Two renderpass descriptors |
4550 | \l{QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor()}{created} |
4551 | from the same QRhiTextureRenderTarget are always compatible. |
4552 | |
4553 | Similarly to QRhiShaderResourceBindings, compatibility can also be tested |
4554 | without having two existing objects available. Extracting the opaque blob by |
4555 | calling serializedFormat() allows testing for compatibility by comparing the |
4556 | returned vector to another QRhiRenderPassDescriptor's |
4557 | serializedFormat(). This has benefits in certain situations, because it |
4558 | allows testing the compatibility of a QRhiRenderPassDescriptor with a |
4559 | QRhiGraphicsPipeline even when the QRhiRenderPassDescriptor the pipeline was |
4560 | originally built was is no longer available (but the data returned from its |
4561 | serializedFormat() still is). |
4562 | |
4563 | \sa newCompatibleRenderPassDescriptor(), serializedFormat() |
4564 | */ |
4565 | |
4566 | /*! |
4567 | \fn virtual QRhiRenderPassDescriptor *QRhiRenderPassDescriptor::newCompatibleRenderPassDescriptor() const = 0 |
4568 | |
4569 | \return a new QRhiRenderPassDescriptor that is |
4570 | \l{isCompatible()}{compatible} with this one. |
4571 | |
4572 | This function allows cloning a QRhiRenderPassDescriptor. The returned |
4573 | object is ready to be used, and the ownership is transferred to the caller. |
4574 | Cloning a QRhiRenderPassDescriptor object can become useful in situations |
4575 | where the object is stored in data structures related to graphics pipelines |
4576 | (in order to allow creating new pipelines which in turn requires a |
4577 | renderpass descriptor object), and the lifetime of the renderpass |
4578 | descriptor created from a render target may be shorter than the pipelines. |
4579 | (for example, because the engine manages and destroys renderpasses together |
4580 | with the textures and render targets it was created from) In such a |
4581 | situation, it can be beneficial to store a cloned version in the data |
4582 | structures, and thus transferring ownership as well. |
4583 | |
4584 | \sa isCompatible() |
4585 | */ |
4586 | |
4587 | /*! |
4588 | \fn virtual QVector<quint32> QRhiRenderPassDescriptor::serializedFormat() const = 0 |
4589 | |
4590 | \return a vector of integers containing an opaque blob describing the data |
4591 | relevant for \l{isCompatible()}{compatibility}. |
4592 | |
4593 | Given two QRhiRenderPassDescriptor objects \c rp1 and \c rp2, if the data |
4594 | returned from this function is identical, then \c{rp1->isCompatible(rp2)}, |
4595 | and vice versa hold true as well. |
4596 | |
4597 | \note The returned data is meant to be used for storing in memory and |
4598 | comparisons during the lifetime of the QRhi the object belongs to. It is not |
4599 | meant for storing on disk, reusing between processes, or using with multiple |
4600 | QRhi instances with potentially different backends. |
4601 | |
4602 | \sa isCompatible() |
4603 | */ |
4604 | |
4605 | /*! |
4606 | \return a pointer to a backend-specific QRhiNativeHandles subclass, such as |
4607 | QRhiVulkanRenderPassNativeHandles. The returned value is \nullptr when exposing |
4608 | the underlying native resources is not supported by the backend. |
4609 | |
4610 | \sa QRhiVulkanRenderPassNativeHandles |
4611 | */ |
4612 | const QRhiNativeHandles *QRhiRenderPassDescriptor::nativeHandles() |
4613 | { |
4614 | return nullptr; |
4615 | } |
4616 | |
4617 | /*! |
4618 | \class QRhiRenderTarget |
4619 | \inmodule QtGui |
4620 | \since 6.6 |
4621 | \brief Represents an onscreen (swapchain) or offscreen (texture) render target. |
4622 | |
4623 | Applications do not create an instance of this class directly. Rather, it |
4624 | is the subclass QRhiTextureRenderTarget that is instantiable by clients of |
4625 | the API via \l{QRhi::newTextureRenderTarget()}{newTextureRenderTarget()}. |
4626 | The other subclass is QRhiSwapChainRenderTarget, which is the type |
4627 | QRhiSwapChain returns when calling |
4628 | \l{QRhiSwapChain::currentFrameRenderTarget()}{currentFrameRenderTarget()}. |
4629 | |
4630 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
4631 | for details. |
4632 | |
4633 | \sa QRhiSwapChainRenderTarget, QRhiTextureRenderTarget |
4634 | */ |
4635 | |
4636 | /*! |
4637 | \internal |
4638 | */ |
4639 | QRhiRenderTarget::QRhiRenderTarget(QRhiImplementation *rhi) |
4640 | : QRhiResource(rhi) |
4641 | { |
4642 | } |
4643 | |
4644 | /*! |
4645 | \fn virtual QSize QRhiRenderTarget::pixelSize() const = 0 |
4646 | |
4647 | \return the size in pixels. |
4648 | |
4649 | Valid only after create() has been called successfully. Until then the |
4650 | result is a default-constructed QSize. |
4651 | |
4652 | With QRhiTextureRenderTarget the returned size is the size of the |
4653 | associated attachments at the time of create(), in practice the size of the |
4654 | first color attachment, or the depth/stencil buffer if there are no color |
4655 | attachments. If the associated textures or renderbuffers are resized and |
4656 | rebuilt afterwards, then pixelSize() performs an implicit call to create() |
4657 | in order to rebuild the underlying data structures. This implicit check is |
4658 | similar to what QRhiCommandBuffer::beginPass() does, and ensures that the |
4659 | returned size is always up-to-date. |
4660 | */ |
4661 | |
4662 | /*! |
4663 | \fn virtual float QRhiRenderTarget::devicePixelRatio() const = 0 |
4664 | |
4665 | \return the device pixel ratio. For QRhiTextureRenderTarget this is always |
4666 | 1. For targets retrieved from a QRhiSwapChain the value reflects the |
4667 | \l{QWindow::devicePixelRatio()}{device pixel ratio} of the targeted |
4668 | QWindow. |
4669 | */ |
4670 | |
4671 | /*! |
4672 | \fn virtual int QRhiRenderTarget::sampleCount() const = 0 |
4673 | |
4674 | \return the sample count or 1 if multisample antialiasing is not relevant for |
4675 | this render target. |
4676 | */ |
4677 | |
4678 | /*! |
4679 | \fn QRhiRenderPassDescriptor *QRhiRenderTarget::renderPassDescriptor() const |
4680 | |
4681 | \return the associated QRhiRenderPassDescriptor. |
4682 | */ |
4683 | |
4684 | /*! |
4685 | \fn void QRhiRenderTarget::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) |
4686 | |
4687 | Sets the QRhiRenderPassDescriptor \a desc for use with this render target. |
4688 | */ |
4689 | |
4690 | /*! |
4691 | \internal |
4692 | */ |
4693 | QRhiSwapChainRenderTarget::QRhiSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain_) |
4694 | : QRhiRenderTarget(rhi), |
4695 | m_swapchain(swapchain_) |
4696 | { |
4697 | } |
4698 | |
4699 | /*! |
4700 | \class QRhiSwapChainRenderTarget |
4701 | \inmodule QtGui |
4702 | \since 6.6 |
4703 | \brief Swapchain render target resource. |
4704 | |
4705 | When targeting the color buffers of a swapchain, active render target is a |
4706 | QRhiSwapChainRenderTarget. This is what |
4707 | QRhiSwapChain::currentFrameRenderTarget() returns. |
4708 | |
4709 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
4710 | for details. |
4711 | |
4712 | \sa QRhiSwapChain |
4713 | */ |
4714 | |
4715 | /*! |
4716 | \return the resource type. |
4717 | */ |
4718 | QRhiResource::Type QRhiSwapChainRenderTarget::resourceType() const |
4719 | { |
4720 | return SwapChainRenderTarget; |
4721 | } |
4722 | |
4723 | /*! |
4724 | \fn QRhiSwapChain *QRhiSwapChainRenderTarget::swapChain() const |
4725 | |
4726 | \return the swapchain object. |
4727 | */ |
4728 | |
4729 | /*! |
4730 | \class QRhiTextureRenderTarget |
4731 | \inmodule QtGui |
4732 | \since 6.6 |
4733 | \brief Texture render target resource. |
4734 | |
4735 | A texture render target allows rendering into one or more textures, |
4736 | optionally with a depth texture or depth/stencil renderbuffer. |
4737 | |
4738 | For multisample rendering the common approach is to use a renderbuffer as |
4739 | the color attachment and set the non-multisample destination texture as the |
4740 | \c{resolve texture}. |
4741 | |
4742 | \note Textures used in combination with QRhiTextureRenderTarget must be |
4743 | created with the QRhiTexture::RenderTarget flag. |
4744 | |
4745 | The simplest example of creating a render target with a texture as its |
4746 | single color attachment: |
4747 | |
4748 | \code |
4749 | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, size, 1, QRhiTexture::RenderTarget); |
4750 | texture->create(); |
4751 | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ texture }); |
4752 | rp = rt->newCompatibleRenderPassDescriptor(); |
4753 | rt->setRenderPassDescriptor(rt); |
4754 | rt->create(); |
4755 | // rt can now be used with beginPass() |
4756 | \endcode |
4757 | |
4758 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
4759 | for details. |
4760 | */ |
4761 | |
4762 | /*! |
4763 | \enum QRhiTextureRenderTarget::Flag |
4764 | |
4765 | Flag values describing the load/store behavior for the render target. The |
4766 | load/store behavior may be baked into native resources under the hood, |
4767 | depending on the backend, and therefore it needs to be known upfront and |
4768 | cannot be changed without rebuilding (and so releasing and creating new |
4769 | native resources). |
4770 | |
4771 | \value PreserveColorContents Indicates that the contents of the color |
4772 | attachments is to be loaded when starting a render pass, instead of |
4773 | clearing. This is potentially more expensive, especially on mobile (tiled) |
4774 | GPUs, but allows preserving the existing contents between passes. |
4775 | |
4776 | \value PreserveDepthStencilContents Indicates that the contents of the |
4777 | depth texture is to be loaded when starting a render pass, instead |
4778 | clearing. Only applicable when a texture is used as the depth buffer |
4779 | (QRhiTextureRenderTargetDescription::depthTexture() is set) because |
4780 | depth/stencil renderbuffers may not have any physical backing and data may |
4781 | not be written out in the first place. |
4782 | */ |
4783 | |
4784 | /*! |
4785 | \internal |
4786 | */ |
4787 | QRhiTextureRenderTarget::QRhiTextureRenderTarget(QRhiImplementation *rhi, |
4788 | const QRhiTextureRenderTargetDescription &desc_, |
4789 | Flags flags_) |
4790 | : QRhiRenderTarget(rhi), |
4791 | m_desc(desc_), |
4792 | m_flags(flags_) |
4793 | { |
4794 | } |
4795 | |
4796 | /*! |
4797 | \return the resource type. |
4798 | */ |
4799 | QRhiResource::Type QRhiTextureRenderTarget::resourceType() const |
4800 | { |
4801 | return TextureRenderTarget; |
4802 | } |
4803 | |
4804 | /*! |
4805 | \fn virtual QRhiRenderPassDescriptor *QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor() = 0 |
4806 | |
4807 | \return a new QRhiRenderPassDescriptor that is compatible with this render |
4808 | target. |
4809 | |
4810 | The returned value is used in two ways: it can be passed to |
4811 | setRenderPassDescriptor() and |
4812 | QRhiGraphicsPipeline::setRenderPassDescriptor(). A render pass descriptor |
4813 | describes the attachments (color, depth/stencil) and the load/store |
4814 | behavior that can be affected by flags(). A QRhiGraphicsPipeline can only |
4815 | be used in combination with a render target that has a |
4816 | \l{QRhiRenderPassDescriptor::isCompatible()}{compatible} |
4817 | QRhiRenderPassDescriptor set. |
4818 | |
4819 | Two QRhiTextureRenderTarget instances can share the same render pass |
4820 | descriptor as long as they have the same number and type of attachments. |
4821 | The associated QRhiTexture or QRhiRenderBuffer instances are not part of |
4822 | the render pass descriptor so those can differ in the two |
4823 | QRhiTextureRenderTarget instances. |
4824 | |
4825 | \note resources, such as QRhiTexture instances, referenced in description() |
4826 | must already have create() called on them. |
4827 | |
4828 | \sa create() |
4829 | */ |
4830 | |
4831 | /*! |
4832 | \fn virtual bool QRhiTextureRenderTarget::create() = 0 |
4833 | |
4834 | Creates the corresponding native graphics resources. If there are already |
4835 | resources present due to an earlier create() with no corresponding |
4836 | destroy(), then destroy() is called implicitly first. |
4837 | |
4838 | \note renderPassDescriptor() must be set before calling create(). To obtain |
4839 | a QRhiRenderPassDescriptor compatible with the render target, call |
4840 | newCompatibleRenderPassDescriptor() before create() but after setting all |
4841 | other parameters, such as description() and flags(). To save resources, |
4842 | reuse the same QRhiRenderPassDescriptor with multiple |
4843 | QRhiTextureRenderTarget instances, whenever possible. Sharing the same |
4844 | render pass descriptor is only possible when the render targets have the |
4845 | same number and type of attachments (the actual textures can differ) and |
4846 | the same flags. |
4847 | |
4848 | \note resources, such as QRhiTexture instances, referenced in description() |
4849 | must already have create() called on them. |
4850 | |
4851 | \return \c true when successful, \c false when a graphics operation failed. |
4852 | Regardless of the return value, calling destroy() is always safe. |
4853 | */ |
4854 | |
4855 | /*! |
4856 | \fn QRhiTextureRenderTargetDescription QRhiTextureRenderTarget::description() const |
4857 | \return the render target description. |
4858 | */ |
4859 | |
4860 | /*! |
4861 | \fn void QRhiTextureRenderTarget::setDescription(const QRhiTextureRenderTargetDescription &desc) |
4862 | Sets the render target description \a desc. |
4863 | */ |
4864 | |
4865 | /*! |
4866 | \fn QRhiTextureRenderTarget::Flags QRhiTextureRenderTarget::flags() const |
4867 | \return the currently set flags. |
4868 | */ |
4869 | |
4870 | /*! |
4871 | \fn void QRhiTextureRenderTarget::setFlags(Flags f) |
4872 | Sets the flags to \a f. |
4873 | */ |
4874 | |
4875 | /*! |
4876 | \class QRhiShaderResourceBindings |
4877 | \inmodule QtGui |
4878 | \since 6.6 |
4879 | \brief Encapsulates resources for making buffer, texture, sampler resources visible to shaders. |
4880 | |
4881 | A QRhiShaderResourceBindings is a collection of QRhiShaderResourceBinding |
4882 | objects, each of which describe a single binding. |
4883 | |
4884 | Take a fragment shader with the following interface: |
4885 | |
4886 | \badcode |
4887 | layout(std140, binding = 0) uniform buf { |
4888 | mat4 mvp; |
4889 | int flip; |
4890 | } ubuf; |
4891 | |
4892 | layout(binding = 1) uniform sampler2D tex; |
4893 | \endcode |
4894 | |
4895 | To make resources visible to the shader, the following |
4896 | QRhiShaderResourceBindings could be created and then passed to |
4897 | QRhiGraphicsPipeline::setShaderResourceBindings(): |
4898 | |
4899 | \code |
4900 | QRhiShaderResourceBindings *srb = rhi->newShaderResourceBindings(); |
4901 | srb->setBindings({ |
4902 | QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, ubuf), |
4903 | QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, sampler) |
4904 | }); |
4905 | srb->create(); |
4906 | // ... |
4907 | QRhiGraphicsPipeline *ps = rhi->newGraphicsPipeline(); |
4908 | // ... |
4909 | ps->setShaderResourceBindings(srb); |
4910 | ps->create(); |
4911 | // ... |
4912 | cb->setGraphicsPipeline(ps); |
4913 | cb->setShaderResources(); // binds srb |
4914 | \endcode |
4915 | |
4916 | This assumes that \c ubuf is a QRhiBuffer, \c texture is a QRhiTexture, |
4917 | while \a sampler is a QRhiSampler. The example also assumes that the |
4918 | uniform block is present in the vertex shader as well so the same buffer is |
4919 | made visible to the vertex stage too. |
4920 | |
4921 | \section3 Advanced usage |
4922 | |
4923 | Building on the above example, let's assume that a pass now needs to use |
4924 | the exact same pipeline and shaders with a different texture. Creating a |
4925 | whole separate QRhiGraphicsPipeline just for this would be an overkill. |
4926 | This is why QRhiCommandBuffer::setShaderResources() allows specifying a \a |
4927 | srb argument. As long as the layouts (so the number of bindings and the |
4928 | binding points) match between two QRhiShaderResourceBindings, they can both |
4929 | be used with the same pipeline, assuming the pipeline was created with one of |
4930 | them in the first place. See isLayoutCompatible() for more details. |
4931 | |
4932 | \code |
4933 | QRhiShaderResourceBindings *srb2 = rhi->newShaderResourceBindings(); |
4934 | // ... |
4935 | cb->setGraphicsPipeline(ps); |
4936 | cb->setShaderResources(srb2); // binds srb2 |
4937 | \endcode |
4938 | |
4939 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
4940 | for details. |
4941 | */ |
4942 | |
4943 | /*! |
4944 | \internal |
4945 | */ |
4946 | QRhiShaderResourceBindings::QRhiShaderResourceBindings(QRhiImplementation *rhi) |
4947 | : QRhiResource(rhi) |
4948 | { |
4949 | m_layoutDesc.reserve(asize: BINDING_PREALLOC * QRhiShaderResourceBinding::LAYOUT_DESC_ENTRIES_PER_BINDING); |
4950 | } |
4951 | |
4952 | /*! |
4953 | \return the resource type. |
4954 | */ |
4955 | QRhiResource::Type QRhiShaderResourceBindings::resourceType() const |
4956 | { |
4957 | return ShaderResourceBindings; |
4958 | } |
4959 | |
4960 | /*! |
4961 | \return \c true if the layout is compatible with \a other. The layout does |
4962 | not include the actual resource (such as, buffer or texture) and related |
4963 | parameters (such as, offset or size). It does include the binding point, |
4964 | pipeline stage, and resource type, however. The number and order of the |
4965 | bindings must also match in order to be compatible. |
4966 | |
4967 | When there is a QRhiGraphicsPipeline created with this |
4968 | QRhiShaderResourceBindings, and the function returns \c true, \a other can |
4969 | then safely be passed to QRhiCommandBuffer::setShaderResources(), and so |
4970 | be used with the pipeline in place of this QRhiShaderResourceBindings. |
4971 | |
4972 | \note This function must only be called after a successful create(), because |
4973 | it relies on data generated during the baking of the underlying data |
4974 | structures. This way the function can implement a comparison approach that |
4975 | is more efficient than iterating through two binding lists and calling |
4976 | QRhiShaderResourceBinding::isLayoutCompatible() on each pair. This becomes |
4977 | relevant especially when this function is called at a high frequency. |
4978 | |
4979 | \sa serializedLayoutDescription() |
4980 | */ |
4981 | bool QRhiShaderResourceBindings::isLayoutCompatible(const QRhiShaderResourceBindings *other) const |
4982 | { |
4983 | if (other == this) |
4984 | return true; |
4985 | |
4986 | if (!other) |
4987 | return false; |
4988 | |
4989 | // This can become a hot code path. Therefore we do not iterate and call |
4990 | // isLayoutCompatible() on m_bindings, but rather check a pre-calculated |
4991 | // hash code and then, if the hash matched, do a uint array comparison |
4992 | // (that's still more cache friendly). |
4993 | |
4994 | return m_layoutDescHash == other->m_layoutDescHash |
4995 | && m_layoutDesc == other->m_layoutDesc; |
4996 | } |
4997 | |
4998 | /*! |
4999 | \fn QVector<quint32> QRhiShaderResourceBindings::serializedLayoutDescription() const |
5000 | |
5001 | \return a vector of integers containing an opaque blob describing the layout |
5002 | of the binding list, i.e. the data relevant for |
5003 | \l{isLayoutCompatible()}{layout compatibility tests}. |
5004 | |
5005 | Given two objects \c srb1 and \c srb2, if the data returned from this |
5006 | function is identical, then \c{srb1->isLayoutCompatible(srb2)}, and vice |
5007 | versa hold true as well. |
5008 | |
5009 | \note The returned data is meant to be used for storing in memory and |
5010 | comparisons during the lifetime of the QRhi the object belongs to. It is not |
5011 | meant for storing on disk, reusing between processes, or using with multiple |
5012 | QRhi instances with potentially different backends. |
5013 | |
5014 | \sa isLayoutCompatible() |
5015 | */ |
5016 | |
5017 | void QRhiImplementation::updateLayoutDesc(QRhiShaderResourceBindings *srb) |
5018 | { |
5019 | srb->m_layoutDescHash = 0; |
5020 | srb->m_layoutDesc.clear(); |
5021 | auto layoutDescAppender = std::back_inserter(x&: srb->m_layoutDesc); |
5022 | for (const QRhiShaderResourceBinding &b : std::as_const(t&: srb->m_bindings)) { |
5023 | const QRhiShaderResourceBinding::Data *d = &b.d; |
5024 | srb->m_layoutDescHash ^= uint(d->binding) ^ uint(d->stage) ^ uint(d->type) |
5025 | ^ uint(d->arraySize()); |
5026 | layoutDescAppender = d->serialize(dst: layoutDescAppender); |
5027 | } |
5028 | } |
5029 | |
5030 | /*! |
5031 | \fn void QRhiShaderResourceBindings::setBindings(std::initializer_list<QRhiShaderResourceBinding> list) |
5032 | Sets the \a list of bindings. |
5033 | */ |
5034 | |
5035 | /*! |
5036 | \fn template<typename InputIterator> void QRhiShaderResourceBindings::setBindings(InputIterator first, InputIterator last) |
5037 | Sets the list of bindings from the iterators \a first and \a last. |
5038 | */ |
5039 | |
5040 | /*! |
5041 | \fn const QRhiShaderResourceBinding *QRhiShaderResourceBindings::cbeginBindings() const |
5042 | \return a const iterator pointing to the first item in the binding list. |
5043 | */ |
5044 | |
5045 | /*! |
5046 | \fn const QRhiShaderResourceBinding *QRhiShaderResourceBindings::cendBindings() const |
5047 | \return a const iterator pointing just after the last item in the binding list. |
5048 | */ |
5049 | |
5050 | /*! |
5051 | \fn const QRhiShaderResourceBinding *QRhiShaderResourceBindings::bindingAt(qsizetype index) const |
5052 | \return the binding at the specified \a index. |
5053 | */ |
5054 | |
5055 | /*! |
5056 | \fn qsizetype QRhiShaderResourceBindings::bindingCount() const |
5057 | \return the number of bindings. |
5058 | */ |
5059 | |
5060 | /*! |
5061 | \class QRhiShaderResourceBinding |
5062 | \inmodule QtGui |
5063 | \since 6.6 |
5064 | \brief Describes the shader resource for a single binding point. |
5065 | |
5066 | A QRhiShaderResourceBinding cannot be constructed directly. Instead, use the |
5067 | static functions such as uniformBuffer() or sampledTexture() to get an |
5068 | instance. |
5069 | |
5070 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
5071 | for details. |
5072 | */ |
5073 | |
5074 | /*! |
5075 | \enum QRhiShaderResourceBinding::Type |
5076 | Specifies type of the shader resource bound to a binding point |
5077 | |
5078 | \value UniformBuffer Uniform buffer |
5079 | |
5080 | \value SampledTexture Combined image sampler (a texture and sampler pair). |
5081 | Even when the shading language associated with the underlying 3D API has no |
5082 | support for this concept (e.g. D3D and HLSL), this is still supported |
5083 | because the shader translation layer takes care of the appropriate |
5084 | translation and remapping of binding points or shader registers. |
5085 | |
5086 | \value Texture Texture (separate) |
5087 | |
5088 | \value Sampler Sampler (separate) |
5089 | |
5090 | \value ImageLoad Image load (with GLSL this maps to doing imageLoad() on a |
5091 | single level - and either one or all layers - of a texture exposed to the |
5092 | shader as an image object) |
5093 | |
5094 | \value ImageStore Image store (with GLSL this maps to doing imageStore() or |
5095 | imageAtomic*() on a single level - and either one or all layers - of a |
5096 | texture exposed to the shader as an image object) |
5097 | |
5098 | \value ImageLoadStore Image load and store |
5099 | |
5100 | \value BufferLoad Storage buffer store (with GLSL this maps to reading from |
5101 | a shader storage buffer) |
5102 | |
5103 | \value BufferStore Storage buffer store (with GLSL this maps to writing to |
5104 | a shader storage buffer) |
5105 | |
5106 | \value BufferLoadStore Storage buffer load and store |
5107 | */ |
5108 | |
5109 | /*! |
5110 | \enum QRhiShaderResourceBinding::StageFlag |
5111 | Flag values to indicate which stages the shader resource is visible in |
5112 | |
5113 | \value VertexStage Vertex stage |
5114 | \value TessellationControlStage Tessellation control (hull shader) stage |
5115 | \value TessellationEvaluationStage Tessellation evaluation (domain shader) stage |
5116 | \value FragmentStage Fragment (pixel shader) stage |
5117 | \value ComputeStage Compute stage |
5118 | \value GeometryStage Geometry stage |
5119 | */ |
5120 | |
5121 | /*! |
5122 | \return \c true if the layout is compatible with \a other. The layout does not |
5123 | include the actual resource (such as, buffer or texture) and related |
5124 | parameters (such as, offset or size). |
5125 | |
5126 | For example, \c a and \c b below are not equal, but are compatible layout-wise: |
5127 | |
5128 | \code |
5129 | auto a = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, buffer); |
5130 | auto b = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, someOtherBuffer, 256); |
5131 | \endcode |
5132 | */ |
5133 | bool QRhiShaderResourceBinding::isLayoutCompatible(const QRhiShaderResourceBinding &other) const |
5134 | { |
5135 | // everything that goes into a VkDescriptorSetLayoutBinding must match |
5136 | return d.binding == other.d.binding |
5137 | && d.stage == other.d.stage |
5138 | && d.type == other.d.type |
5139 | && d.arraySize() == other.d.arraySize(); |
5140 | } |
5141 | |
5142 | /*! |
5143 | \return a shader resource binding for the given binding number, pipeline |
5144 | stages, and buffer specified by \a binding, \a stage, and \a buf. |
5145 | |
5146 | \note When \a buf is not null, it must have been created with |
5147 | QRhiBuffer::UniformBuffer. |
5148 | |
5149 | \note \a buf can be null. It is valid to create a |
5150 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5151 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5152 | suitable for creating pipelines. Such a pipeline must then always be used |
5153 | together with another, layout compatible QRhiShaderResourceBindings with |
5154 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5155 | |
5156 | \note If the size of \a buf exceeds the limit reported for |
5157 | QRhi::MaxUniformBufferRange, unexpected errors may occur. |
5158 | */ |
5159 | QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer( |
5160 | int binding, StageFlags stage, QRhiBuffer *buf) |
5161 | { |
5162 | QRhiShaderResourceBinding b; |
5163 | b.d.binding = binding; |
5164 | b.d.stage = stage; |
5165 | b.d.type = UniformBuffer; |
5166 | b.d.u.ubuf.buf = buf; |
5167 | b.d.u.ubuf.offset = 0; |
5168 | b.d.u.ubuf.maybeSize = 0; // entire buffer |
5169 | b.d.u.ubuf.hasDynamicOffset = false; |
5170 | return b; |
5171 | } |
5172 | |
5173 | /*! |
5174 | \return a shader resource binding for the given binding number, pipeline |
5175 | stages, and buffer specified by \a binding, \a stage, and \a buf. This |
5176 | overload binds a region only, as specified by \a offset and \a size. |
5177 | |
5178 | \note It is up to the user to ensure the offset is aligned to |
5179 | QRhi::ubufAlignment(). |
5180 | |
5181 | \note \a size must be greater than 0. |
5182 | |
5183 | \note When \a buf is not null, it must have been created with |
5184 | QRhiBuffer::UniformBuffer. |
5185 | |
5186 | \note \a buf can be null. It is valid to create a |
5187 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5188 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5189 | suitable for creating pipelines. Such a pipeline must then always be used |
5190 | together with another, layout compatible QRhiShaderResourceBindings with |
5191 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5192 | |
5193 | \note If \a size exceeds the limit reported for QRhi::MaxUniformBufferRange, |
5194 | unexpected errors may occur. |
5195 | */ |
5196 | QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer( |
5197 | int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size) |
5198 | { |
5199 | Q_ASSERT(size > 0); |
5200 | QRhiShaderResourceBinding b; |
5201 | b.d.binding = binding; |
5202 | b.d.stage = stage; |
5203 | b.d.type = UniformBuffer; |
5204 | b.d.u.ubuf.buf = buf; |
5205 | b.d.u.ubuf.offset = offset; |
5206 | b.d.u.ubuf.maybeSize = size; |
5207 | b.d.u.ubuf.hasDynamicOffset = false; |
5208 | return b; |
5209 | } |
5210 | |
5211 | /*! |
5212 | \return a shader resource binding for the given binding number, pipeline |
5213 | stages, and buffer specified by \a binding, \a stage, and \a buf. The |
5214 | uniform buffer is assumed to have dynamic offset. The dynamic offset can be |
5215 | specified in QRhiCommandBuffer::setShaderResources(), thus allowing using |
5216 | varying offset values without creating new bindings for the buffer. The |
5217 | size of the bound region is specified by \a size. Like with non-dynamic |
5218 | offsets, \c{offset + size} cannot exceed the size of \a buf. |
5219 | |
5220 | \note When \a buf is not null, it must have been created with |
5221 | QRhiBuffer::UniformBuffer. |
5222 | |
5223 | \note \a buf can be null. It is valid to create a |
5224 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5225 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5226 | suitable for creating pipelines. Such a pipeline must then always be used |
5227 | together with another, layout compatible QRhiShaderResourceBindings with |
5228 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5229 | |
5230 | \note If \a size exceeds the limit reported for QRhi::MaxUniformBufferRange, |
5231 | unexpected errors may occur. |
5232 | */ |
5233 | QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBufferWithDynamicOffset( |
5234 | int binding, StageFlags stage, QRhiBuffer *buf, quint32 size) |
5235 | { |
5236 | Q_ASSERT(size > 0); |
5237 | QRhiShaderResourceBinding b; |
5238 | b.d.binding = binding; |
5239 | b.d.stage = stage; |
5240 | b.d.type = UniformBuffer; |
5241 | b.d.u.ubuf.buf = buf; |
5242 | b.d.u.ubuf.offset = 0; |
5243 | b.d.u.ubuf.maybeSize = size; |
5244 | b.d.u.ubuf.hasDynamicOffset = true; |
5245 | return b; |
5246 | } |
5247 | |
5248 | /*! |
5249 | \return a shader resource binding for the given binding number, pipeline |
5250 | stages, texture, and sampler specified by \a binding, \a stage, \a tex, |
5251 | \a sampler. |
5252 | |
5253 | \note This function is equivalent to calling sampledTextures() with a |
5254 | \c count of 1. |
5255 | |
5256 | \note \a tex and \a sampler can be null. It is valid to create a |
5257 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5258 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5259 | suitable for creating pipelines. Such a pipeline must then always be used |
5260 | together with another, layout compatible QRhiShaderResourceBindings with |
5261 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5262 | |
5263 | \note A shader may not be able to consume more than 16 textures/samplers, |
5264 | depending on the underlying graphics API. This hard limit must be kept in |
5265 | mind in renderer design. This does not apply to texture arrays which |
5266 | consume a single binding point (shader register) and can contain 256-2048 |
5267 | textures, depending on the underlying graphics API. Arrays of textures (see |
5268 | sampledTextures()) are however no different in this regard than using the |
5269 | same number of individual textures. |
5270 | |
5271 | \sa sampledTextures() |
5272 | */ |
5273 | QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture( |
5274 | int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler) |
5275 | { |
5276 | QRhiShaderResourceBinding b; |
5277 | b.d.binding = binding; |
5278 | b.d.stage = stage; |
5279 | b.d.type = SampledTexture; |
5280 | b.d.u.stex.count = 1; |
5281 | b.d.u.stex.texSamplers[0] = { .tex: tex, .sampler: sampler }; |
5282 | return b; |
5283 | } |
5284 | |
5285 | /*! |
5286 | \return a shader resource binding for the given binding number, pipeline |
5287 | stages, and the array of texture-sampler pairs specified by \a binding, \a |
5288 | stage, \a count, and \a texSamplers. |
5289 | |
5290 | \note \a count must be at least 1, and not larger than 16. |
5291 | |
5292 | \note When \a count is 1, this function is equivalent to sampledTexture(). |
5293 | |
5294 | This function is relevant when arrays of combined image samplers are |
5295 | involved. For example, in GLSL \c{layout(binding = 5) uniform sampler2D |
5296 | shadowMaps[8];} declares an array of combined image samplers. The |
5297 | application is then expected provide a QRhiShaderResourceBinding for |
5298 | binding point 5, set up by calling this function with \a count set to 8 and |
5299 | a valid texture and sampler for each element of the array. |
5300 | |
5301 | \warning All elements of the array must be specified. With the above |
5302 | example, the only valid, portable approach is calling this function with a |
5303 | \a count of 8. Additionally, all QRhiTexture and QRhiSampler instances must |
5304 | be valid, meaning nullptr is not an accepted value. This is due to some of |
5305 | the underlying APIs, such as, Vulkan, that require a valid image and |
5306 | sampler object for each element in descriptor arrays. Applications are |
5307 | advised to provide "dummy" samplers and textures if some array elements are |
5308 | not relevant (due to not being accessed in the shader). |
5309 | |
5310 | \note \a texSamplers can be null. It is valid to create a |
5311 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5312 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5313 | suitable for creating pipelines. Such a pipeline must then always be used |
5314 | together with another, layout compatible QRhiShaderResourceBindings with |
5315 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5316 | |
5317 | \sa sampledTexture() |
5318 | */ |
5319 | QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTextures( |
5320 | int binding, StageFlags stage, int count, const TextureAndSampler *texSamplers) |
5321 | { |
5322 | Q_ASSERT(count >= 1 && count <= Data::MAX_TEX_SAMPLER_ARRAY_SIZE); |
5323 | QRhiShaderResourceBinding b; |
5324 | b.d.binding = binding; |
5325 | b.d.stage = stage; |
5326 | b.d.type = SampledTexture; |
5327 | b.d.u.stex.count = count; |
5328 | for (int i = 0; i < count; ++i) { |
5329 | if (texSamplers) |
5330 | b.d.u.stex.texSamplers[i] = texSamplers[i]; |
5331 | else |
5332 | b.d.u.stex.texSamplers[i] = { .tex: nullptr, .sampler: nullptr }; |
5333 | } |
5334 | return b; |
5335 | } |
5336 | |
5337 | /*! |
5338 | \return a shader resource binding for the given binding number, pipeline |
5339 | stages, and texture specified by \a binding, \a stage, \a tex. |
5340 | |
5341 | \note This function is equivalent to calling textures() with a |
5342 | \c count of 1. |
5343 | |
5344 | \note \a tex can be null. It is valid to create a |
5345 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5346 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5347 | suitable for creating pipelines. Such a pipeline must then always be used |
5348 | together with another, layout compatible QRhiShaderResourceBindings with |
5349 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5350 | |
5351 | This creates a binding for a separate texture (image) object, whereas |
5352 | sampledTexture() is suitable for combined image samplers. In |
5353 | Vulkan-compatible GLSL code separate textures are declared as \c texture2D |
5354 | as opposed to \c sampler2D: \c{layout(binding = 1) uniform texture2D tex;} |
5355 | |
5356 | \note A shader may not be able to consume more than 16 textures, depending |
5357 | on the underlying graphics API. This hard limit must be kept in mind in |
5358 | renderer design. This does not apply to texture arrays which consume a |
5359 | single binding point (shader register) and can contain 256-2048 textures, |
5360 | depending on the underlying graphics API. Arrays of textures (see |
5361 | sampledTextures()) are however no different in this regard than using the |
5362 | same number of individual textures. |
5363 | |
5364 | \sa textures(), sampler() |
5365 | */ |
5366 | QRhiShaderResourceBinding QRhiShaderResourceBinding::texture(int binding, StageFlags stage, QRhiTexture *tex) |
5367 | { |
5368 | QRhiShaderResourceBinding b; |
5369 | b.d.binding = binding; |
5370 | b.d.stage = stage; |
5371 | b.d.type = Texture; |
5372 | b.d.u.stex.count = 1; |
5373 | b.d.u.stex.texSamplers[0] = { .tex: tex, .sampler: nullptr }; |
5374 | return b; |
5375 | } |
5376 | |
5377 | /*! |
5378 | \return a shader resource binding for the given binding number, pipeline |
5379 | stages, and the array of (separate) textures specified by \a binding, \a |
5380 | stage, \a count, and \a tex. |
5381 | |
5382 | \note \a count must be at least 1, and not larger than 16. |
5383 | |
5384 | \note When \a count is 1, this function is equivalent to texture(). |
5385 | |
5386 | \warning All elements of the array must be specified. |
5387 | |
5388 | \note \a tex can be null. It is valid to create a |
5389 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5390 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5391 | suitable for creating pipelines. Such a pipeline must then always be used |
5392 | together with another, layout compatible QRhiShaderResourceBindings with |
5393 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5394 | |
5395 | \sa texture(), sampler() |
5396 | */ |
5397 | QRhiShaderResourceBinding QRhiShaderResourceBinding::textures(int binding, StageFlags stage, int count, QRhiTexture **tex) |
5398 | { |
5399 | Q_ASSERT(count >= 1 && count <= Data::MAX_TEX_SAMPLER_ARRAY_SIZE); |
5400 | QRhiShaderResourceBinding b; |
5401 | b.d.binding = binding; |
5402 | b.d.stage = stage; |
5403 | b.d.type = Texture; |
5404 | b.d.u.stex.count = count; |
5405 | for (int i = 0; i < count; ++i) { |
5406 | if (tex) |
5407 | b.d.u.stex.texSamplers[i] = { .tex: tex[i], .sampler: nullptr }; |
5408 | else |
5409 | b.d.u.stex.texSamplers[i] = { .tex: nullptr, .sampler: nullptr }; |
5410 | } |
5411 | return b; |
5412 | } |
5413 | |
5414 | /*! |
5415 | \return a shader resource binding for the given binding number, pipeline |
5416 | stages, and sampler specified by \a binding, \a stage, \a sampler. |
5417 | |
5418 | \note \a sampler can be null. It is valid to create a |
5419 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5420 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5421 | suitable for creating pipelines. Such a pipeline must then always be used |
5422 | together with another, layout compatible QRhiShaderResourceBindings with |
5423 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5424 | |
5425 | Arrays of separate samplers are not supported. |
5426 | |
5427 | This creates a binding for a separate sampler object, whereas |
5428 | sampledTexture() is suitable for combined image samplers. In |
5429 | Vulkan-compatible GLSL code separate samplers are declared as \c sampler |
5430 | as opposed to \c sampler2D: \c{layout(binding = 2) uniform sampler samp;} |
5431 | |
5432 | With both a \c texture2D and \c sampler present, they can be used together |
5433 | to sample the texture: \c{fragColor = texture(sampler2D(tex, samp), |
5434 | texcoord);}. |
5435 | |
5436 | \note A shader may not be able to consume more than 16 samplers, depending |
5437 | on the underlying graphics API. This hard limit must be kept in mind in |
5438 | renderer design. |
5439 | |
5440 | \sa texture() |
5441 | */ |
5442 | QRhiShaderResourceBinding QRhiShaderResourceBinding::sampler(int binding, StageFlags stage, QRhiSampler *sampler) |
5443 | { |
5444 | QRhiShaderResourceBinding b; |
5445 | b.d.binding = binding; |
5446 | b.d.stage = stage; |
5447 | b.d.type = Sampler; |
5448 | b.d.u.stex.count = 1; |
5449 | b.d.u.stex.texSamplers[0] = { .tex: nullptr, .sampler: sampler }; |
5450 | return b; |
5451 | } |
5452 | |
5453 | /*! |
5454 | \return a shader resource binding for a read-only storage image with the |
5455 | given \a binding number and pipeline \a stage. The image load operations |
5456 | will have access to all layers of the specified \a level. (so if the texture |
5457 | is a cubemap, the shader must use imageCube instead of image2D) |
5458 | |
5459 | \note When \a tex is not null, it must have been created with |
5460 | QRhiTexture::UsedWithLoadStore. |
5461 | |
5462 | \note \a tex can be null. It is valid to create a QRhiShaderResourceBindings |
5463 | with unspecified resources, but such an object cannot be used with |
5464 | QRhiCommandBuffer::setShaderResources(). It is however suitable for creating |
5465 | pipelines. Such a pipeline must then always be used together with another, |
5466 | layout compatible QRhiShaderResourceBindings with resources present passed |
5467 | to QRhiCommandBuffer::setShaderResources(). |
5468 | |
5469 | \note Image load/store is only guaranteed to be available within a compute |
5470 | pipeline. While some backends may support using these resources in a |
5471 | graphics pipeline as well, this is not universally supported, and even when |
5472 | it is, unexpected problems may arise when it comes to barriers and |
5473 | synchronization. Therefore, avoid using such resources with shaders other |
5474 | than compute. |
5475 | */ |
5476 | QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoad( |
5477 | int binding, StageFlags stage, QRhiTexture *tex, int level) |
5478 | { |
5479 | QRhiShaderResourceBinding b; |
5480 | b.d.binding = binding; |
5481 | b.d.stage = stage; |
5482 | b.d.type = ImageLoad; |
5483 | b.d.u.simage.tex = tex; |
5484 | b.d.u.simage.level = level; |
5485 | return b; |
5486 | } |
5487 | |
5488 | /*! |
5489 | \return a shader resource binding for a write-only storage image with the |
5490 | given \a binding number and pipeline \a stage. The image store operations |
5491 | will have access to all layers of the specified \a level. (so if the texture |
5492 | is a cubemap, the shader must use imageCube instead of image2D) |
5493 | |
5494 | \note When \a tex is not null, it must have been created with |
5495 | QRhiTexture::UsedWithLoadStore. |
5496 | |
5497 | \note \a tex can be null. It is valid to create a QRhiShaderResourceBindings |
5498 | with unspecified resources, but such an object cannot be used with |
5499 | QRhiCommandBuffer::setShaderResources(). It is however suitable for creating |
5500 | pipelines. Such a pipeline must then always be used together with another, |
5501 | layout compatible QRhiShaderResourceBindings with resources present passed |
5502 | to QRhiCommandBuffer::setShaderResources(). |
5503 | |
5504 | \note Image load/store is only guaranteed to be available within a compute |
5505 | pipeline. While some backends may support using these resources in a |
5506 | graphics pipeline as well, this is not universally supported, and even when |
5507 | it is, unexpected problems may arise when it comes to barriers and |
5508 | synchronization. Therefore, avoid using such resources with shaders other |
5509 | than compute. |
5510 | */ |
5511 | QRhiShaderResourceBinding QRhiShaderResourceBinding::imageStore( |
5512 | int binding, StageFlags stage, QRhiTexture *tex, int level) |
5513 | { |
5514 | QRhiShaderResourceBinding b; |
5515 | b.d.binding = binding; |
5516 | b.d.stage = stage; |
5517 | b.d.type = ImageStore; |
5518 | b.d.u.simage.tex = tex; |
5519 | b.d.u.simage.level = level; |
5520 | return b; |
5521 | } |
5522 | |
5523 | /*! |
5524 | \return a shader resource binding for a read/write storage image with the |
5525 | given \a binding number and pipeline \a stage. The image load/store operations |
5526 | will have access to all layers of the specified \a level. (so if the texture |
5527 | is a cubemap, the shader must use imageCube instead of image2D) |
5528 | |
5529 | \note When \a tex is not null, it must have been created with |
5530 | QRhiTexture::UsedWithLoadStore. |
5531 | |
5532 | \note \a tex can be null. It is valid to create a QRhiShaderResourceBindings |
5533 | with unspecified resources, but such an object cannot be used with |
5534 | QRhiCommandBuffer::setShaderResources(). It is however suitable for creating |
5535 | pipelines. Such a pipeline must then always be used together with another, |
5536 | layout compatible QRhiShaderResourceBindings with resources present passed |
5537 | to QRhiCommandBuffer::setShaderResources(). |
5538 | |
5539 | \note Image load/store is only guaranteed to be available within a compute |
5540 | pipeline. While some backends may support using these resources in a |
5541 | graphics pipeline as well, this is not universally supported, and even when |
5542 | it is, unexpected problems may arise when it comes to barriers and |
5543 | synchronization. Therefore, avoid using such resources with shaders other |
5544 | than compute. |
5545 | */ |
5546 | QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoadStore( |
5547 | int binding, StageFlags stage, QRhiTexture *tex, int level) |
5548 | { |
5549 | QRhiShaderResourceBinding b; |
5550 | b.d.binding = binding; |
5551 | b.d.stage = stage; |
5552 | b.d.type = ImageLoadStore; |
5553 | b.d.u.simage.tex = tex; |
5554 | b.d.u.simage.level = level; |
5555 | return b; |
5556 | } |
5557 | |
5558 | /*! |
5559 | \return a shader resource binding for a read-only storage buffer with the |
5560 | given \a binding number and pipeline \a stage. |
5561 | |
5562 | \note When \a buf is not null, must have been created with |
5563 | QRhiBuffer::StorageBuffer. |
5564 | |
5565 | \note \a buf can be null. It is valid to create a |
5566 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5567 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5568 | suitable for creating pipelines. Such a pipeline must then always be used |
5569 | together with another, layout compatible QRhiShaderResourceBindings with |
5570 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5571 | |
5572 | \note Buffer load/store is only guaranteed to be available within a compute |
5573 | pipeline. While some backends may support using these resources in a |
5574 | graphics pipeline as well, this is not universally supported, and even when |
5575 | it is, unexpected problems may arise when it comes to barriers and |
5576 | synchronization. Therefore, avoid using such resources with shaders other |
5577 | than compute. |
5578 | */ |
5579 | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad( |
5580 | int binding, StageFlags stage, QRhiBuffer *buf) |
5581 | { |
5582 | QRhiShaderResourceBinding b; |
5583 | b.d.binding = binding; |
5584 | b.d.stage = stage; |
5585 | b.d.type = BufferLoad; |
5586 | b.d.u.sbuf.buf = buf; |
5587 | b.d.u.sbuf.offset = 0; |
5588 | b.d.u.sbuf.maybeSize = 0; // entire buffer |
5589 | return b; |
5590 | } |
5591 | |
5592 | /*! |
5593 | \return a shader resource binding for a read-only storage buffer with the |
5594 | given \a binding number and pipeline \a stage. This overload binds a region |
5595 | only, as specified by \a offset and \a size. |
5596 | |
5597 | \note When \a buf is not null, must have been created with |
5598 | QRhiBuffer::StorageBuffer. |
5599 | |
5600 | \note \a buf can be null. It is valid to create a |
5601 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5602 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5603 | suitable for creating pipelines. Such a pipeline must then always be used |
5604 | together with another, layout compatible QRhiShaderResourceBindings with |
5605 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5606 | |
5607 | \note Buffer load/store is only guaranteed to be available within a compute |
5608 | pipeline. While some backends may support using these resources in a |
5609 | graphics pipeline as well, this is not universally supported, and even when |
5610 | it is, unexpected problems may arise when it comes to barriers and |
5611 | synchronization. Therefore, avoid using such resources with shaders other |
5612 | than compute. |
5613 | */ |
5614 | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad( |
5615 | int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size) |
5616 | { |
5617 | Q_ASSERT(size > 0); |
5618 | QRhiShaderResourceBinding b; |
5619 | b.d.binding = binding; |
5620 | b.d.stage = stage; |
5621 | b.d.type = BufferLoad; |
5622 | b.d.u.sbuf.buf = buf; |
5623 | b.d.u.sbuf.offset = offset; |
5624 | b.d.u.sbuf.maybeSize = size; |
5625 | return b; |
5626 | } |
5627 | |
5628 | /*! |
5629 | \return a shader resource binding for a write-only storage buffer with the |
5630 | given \a binding number and pipeline \a stage. |
5631 | |
5632 | \note When \a buf is not null, must have been created with |
5633 | QRhiBuffer::StorageBuffer. |
5634 | |
5635 | \note \a buf can be null. It is valid to create a |
5636 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5637 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5638 | suitable for creating pipelines. Such a pipeline must then always be used |
5639 | together with another, layout compatible QRhiShaderResourceBindings with |
5640 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5641 | |
5642 | \note Buffer load/store is only guaranteed to be available within a compute |
5643 | pipeline. While some backends may support using these resources in a |
5644 | graphics pipeline as well, this is not universally supported, and even when |
5645 | it is, unexpected problems may arise when it comes to barriers and |
5646 | synchronization. Therefore, avoid using such resources with shaders other |
5647 | than compute. |
5648 | */ |
5649 | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore( |
5650 | int binding, StageFlags stage, QRhiBuffer *buf) |
5651 | { |
5652 | QRhiShaderResourceBinding b; |
5653 | b.d.binding = binding; |
5654 | b.d.stage = stage; |
5655 | b.d.type = BufferStore; |
5656 | b.d.u.sbuf.buf = buf; |
5657 | b.d.u.sbuf.offset = 0; |
5658 | b.d.u.sbuf.maybeSize = 0; // entire buffer |
5659 | return b; |
5660 | } |
5661 | |
5662 | /*! |
5663 | \return a shader resource binding for a write-only storage buffer with the |
5664 | given \a binding number and pipeline \a stage. This overload binds a region |
5665 | only, as specified by \a offset and \a size. |
5666 | |
5667 | \note When \a buf is not null, must have been created with |
5668 | QRhiBuffer::StorageBuffer. |
5669 | |
5670 | \note \a buf can be null. It is valid to create a |
5671 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5672 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5673 | suitable for creating pipelines. Such a pipeline must then always be used |
5674 | together with another, layout compatible QRhiShaderResourceBindings with |
5675 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5676 | |
5677 | \note Buffer load/store is only guaranteed to be available within a compute |
5678 | pipeline. While some backends may support using these resources in a |
5679 | graphics pipeline as well, this is not universally supported, and even when |
5680 | it is, unexpected problems may arise when it comes to barriers and |
5681 | synchronization. Therefore, avoid using such resources with shaders other |
5682 | than compute. |
5683 | */ |
5684 | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore( |
5685 | int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size) |
5686 | { |
5687 | Q_ASSERT(size > 0); |
5688 | QRhiShaderResourceBinding b; |
5689 | b.d.binding = binding; |
5690 | b.d.stage = stage; |
5691 | b.d.type = BufferStore; |
5692 | b.d.u.sbuf.buf = buf; |
5693 | b.d.u.sbuf.offset = offset; |
5694 | b.d.u.sbuf.maybeSize = size; |
5695 | return b; |
5696 | } |
5697 | |
5698 | /*! |
5699 | \return a shader resource binding for a read-write storage buffer with the |
5700 | given \a binding number and pipeline \a stage. |
5701 | |
5702 | \note When \a buf is not null, must have been created with |
5703 | QRhiBuffer::StorageBuffer. |
5704 | |
5705 | \note \a buf can be null. It is valid to create a |
5706 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5707 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5708 | suitable for creating pipelines. Such a pipeline must then always be used |
5709 | together with another, layout compatible QRhiShaderResourceBindings with |
5710 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5711 | |
5712 | \note Buffer load/store is only guaranteed to be available within a compute |
5713 | pipeline. While some backends may support using these resources in a |
5714 | graphics pipeline as well, this is not universally supported, and even when |
5715 | it is, unexpected problems may arise when it comes to barriers and |
5716 | synchronization. Therefore, avoid using such resources with shaders other |
5717 | than compute. |
5718 | */ |
5719 | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore( |
5720 | int binding, StageFlags stage, QRhiBuffer *buf) |
5721 | { |
5722 | QRhiShaderResourceBinding b; |
5723 | b.d.binding = binding; |
5724 | b.d.stage = stage; |
5725 | b.d.type = BufferLoadStore; |
5726 | b.d.u.sbuf.buf = buf; |
5727 | b.d.u.sbuf.offset = 0; |
5728 | b.d.u.sbuf.maybeSize = 0; // entire buffer |
5729 | return b; |
5730 | } |
5731 | |
5732 | /*! |
5733 | \return a shader resource binding for a read-write storage buffer with the |
5734 | given \a binding number and pipeline \a stage. This overload binds a region |
5735 | only, as specified by \a offset and \a size. |
5736 | |
5737 | \note When \a buf is not null, must have been created with |
5738 | QRhiBuffer::StorageBuffer. |
5739 | |
5740 | \note \a buf can be null. It is valid to create a |
5741 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5742 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5743 | suitable for creating pipelines. Such a pipeline must then always be used |
5744 | together with another, layout compatible QRhiShaderResourceBindings with |
5745 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5746 | |
5747 | \note Buffer load/store is only guaranteed to be available within a compute |
5748 | pipeline. While some backends may support using these resources in a |
5749 | graphics pipeline as well, this is not universally supported, and even when |
5750 | it is, unexpected problems may arise when it comes to barriers and |
5751 | synchronization. Therefore, avoid using such resources with shaders other |
5752 | than compute. |
5753 | */ |
5754 | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore( |
5755 | int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size) |
5756 | { |
5757 | Q_ASSERT(size > 0); |
5758 | QRhiShaderResourceBinding b; |
5759 | b.d.binding = binding; |
5760 | b.d.stage = stage; |
5761 | b.d.type = BufferLoadStore; |
5762 | b.d.u.sbuf.buf = buf; |
5763 | b.d.u.sbuf.offset = offset; |
5764 | b.d.u.sbuf.maybeSize = size; |
5765 | return b; |
5766 | } |
5767 | |
5768 | /*! |
5769 | \return \c true if the contents of the two QRhiShaderResourceBinding |
5770 | objects \a a and \a b are equal. This includes the resources (buffer, |
5771 | texture) and related parameters (offset, size) as well. To only compare |
5772 | layouts (binding point, pipeline stage, resource type), use |
5773 | \l{QRhiShaderResourceBinding::isLayoutCompatible()}{isLayoutCompatible()} |
5774 | instead. |
5775 | |
5776 | \relates QRhiShaderResourceBinding |
5777 | */ |
5778 | bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept |
5779 | { |
5780 | const QRhiShaderResourceBinding::Data *da = QRhiImplementation::shaderResourceBindingData(binding: a); |
5781 | const QRhiShaderResourceBinding::Data *db = QRhiImplementation::shaderResourceBindingData(binding: b); |
5782 | |
5783 | if (da == db) |
5784 | return true; |
5785 | |
5786 | |
5787 | if (da->binding != db->binding |
5788 | || da->stage != db->stage |
5789 | || da->type != db->type) |
5790 | { |
5791 | return false; |
5792 | } |
5793 | |
5794 | switch (da->type) { |
5795 | case QRhiShaderResourceBinding::UniformBuffer: |
5796 | if (da->u.ubuf.buf != db->u.ubuf.buf |
5797 | || da->u.ubuf.offset != db->u.ubuf.offset |
5798 | || da->u.ubuf.maybeSize != db->u.ubuf.maybeSize) |
5799 | { |
5800 | return false; |
5801 | } |
5802 | break; |
5803 | case QRhiShaderResourceBinding::SampledTexture: |
5804 | if (da->u.stex.count != db->u.stex.count) |
5805 | return false; |
5806 | for (int i = 0; i < da->u.stex.count; ++i) { |
5807 | if (da->u.stex.texSamplers[i].tex != db->u.stex.texSamplers[i].tex |
5808 | || da->u.stex.texSamplers[i].sampler != db->u.stex.texSamplers[i].sampler) |
5809 | { |
5810 | return false; |
5811 | } |
5812 | } |
5813 | break; |
5814 | case QRhiShaderResourceBinding::Texture: |
5815 | if (da->u.stex.count != db->u.stex.count) |
5816 | return false; |
5817 | for (int i = 0; i < da->u.stex.count; ++i) { |
5818 | if (da->u.stex.texSamplers[i].tex != db->u.stex.texSamplers[i].tex) |
5819 | return false; |
5820 | } |
5821 | break; |
5822 | case QRhiShaderResourceBinding::Sampler: |
5823 | if (da->u.stex.texSamplers[0].sampler != db->u.stex.texSamplers[0].sampler) |
5824 | return false; |
5825 | break; |
5826 | case QRhiShaderResourceBinding::ImageLoad: |
5827 | case QRhiShaderResourceBinding::ImageStore: |
5828 | case QRhiShaderResourceBinding::ImageLoadStore: |
5829 | if (da->u.simage.tex != db->u.simage.tex |
5830 | || da->u.simage.level != db->u.simage.level) |
5831 | { |
5832 | return false; |
5833 | } |
5834 | break; |
5835 | case QRhiShaderResourceBinding::BufferLoad: |
5836 | case QRhiShaderResourceBinding::BufferStore: |
5837 | case QRhiShaderResourceBinding::BufferLoadStore: |
5838 | if (da->u.sbuf.buf != db->u.sbuf.buf |
5839 | || da->u.sbuf.offset != db->u.sbuf.offset |
5840 | || da->u.sbuf.maybeSize != db->u.sbuf.maybeSize) |
5841 | { |
5842 | return false; |
5843 | } |
5844 | break; |
5845 | default: |
5846 | Q_UNREACHABLE_RETURN(false); |
5847 | } |
5848 | |
5849 | return true; |
5850 | } |
5851 | |
5852 | /*! |
5853 | \return \c false if all the bindings in the two QRhiShaderResourceBinding |
5854 | objects \a a and \a b are equal; otherwise returns \c true. |
5855 | |
5856 | \relates QRhiShaderResourceBinding |
5857 | */ |
5858 | bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept |
5859 | { |
5860 | return !(a == b); |
5861 | } |
5862 | |
5863 | /*! |
5864 | \return the hash value for \a b, using \a seed to seed the calculation. |
5865 | |
5866 | \relates QRhiShaderResourceBinding |
5867 | */ |
5868 | size_t qHash(const QRhiShaderResourceBinding &b, size_t seed) noexcept |
5869 | { |
5870 | const QRhiShaderResourceBinding::Data *d = QRhiImplementation::shaderResourceBindingData(binding: b); |
5871 | QtPrivate::QHashCombine hash; |
5872 | seed = hash(seed, d->binding); |
5873 | seed = hash(seed, d->stage); |
5874 | seed = hash(seed, d->type); |
5875 | switch (d->type) { |
5876 | case QRhiShaderResourceBinding::UniformBuffer: |
5877 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.ubuf.buf)); |
5878 | break; |
5879 | case QRhiShaderResourceBinding::SampledTexture: |
5880 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].tex)); |
5881 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].sampler)); |
5882 | break; |
5883 | case QRhiShaderResourceBinding::Texture: |
5884 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].tex)); |
5885 | break; |
5886 | case QRhiShaderResourceBinding::Sampler: |
5887 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].sampler)); |
5888 | break; |
5889 | case QRhiShaderResourceBinding::ImageLoad: |
5890 | case QRhiShaderResourceBinding::ImageStore: |
5891 | case QRhiShaderResourceBinding::ImageLoadStore: |
5892 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.simage.tex)); |
5893 | break; |
5894 | case QRhiShaderResourceBinding::BufferLoad: |
5895 | case QRhiShaderResourceBinding::BufferStore: |
5896 | case QRhiShaderResourceBinding::BufferLoadStore: |
5897 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.sbuf.buf)); |
5898 | break; |
5899 | } |
5900 | return seed; |
5901 | } |
5902 | |
5903 | #ifndef QT_NO_DEBUG_STREAM |
5904 | QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b) |
5905 | { |
5906 | QDebugStateSaver saver(dbg); |
5907 | const QRhiShaderResourceBinding::Data *d = QRhiImplementation::shaderResourceBindingData(binding: b); |
5908 | dbg.nospace() << "QRhiShaderResourceBinding(" |
5909 | << "binding=" << d->binding |
5910 | << " stage=" << d->stage |
5911 | << " type=" << d->type; |
5912 | switch (d->type) { |
5913 | case QRhiShaderResourceBinding::UniformBuffer: |
5914 | dbg.nospace() << " UniformBuffer(" |
5915 | << "buffer=" << d->u.ubuf.buf |
5916 | << " offset=" << d->u.ubuf.offset |
5917 | << " maybeSize=" << d->u.ubuf.maybeSize |
5918 | << ')'; |
5919 | break; |
5920 | case QRhiShaderResourceBinding::SampledTexture: |
5921 | dbg.nospace() << " SampledTextures(" |
5922 | << "count=" << d->u.stex.count; |
5923 | for (int i = 0; i < d->u.stex.count; ++i) { |
5924 | dbg.nospace() << " texture=" << d->u.stex.texSamplers[i].tex |
5925 | << " sampler=" << d->u.stex.texSamplers[i].sampler; |
5926 | } |
5927 | dbg.nospace() << ')'; |
5928 | break; |
5929 | case QRhiShaderResourceBinding::Texture: |
5930 | dbg.nospace() << " Textures(" |
5931 | << "count=" << d->u.stex.count; |
5932 | for (int i = 0; i < d->u.stex.count; ++i) |
5933 | dbg.nospace() << " texture=" << d->u.stex.texSamplers[i].tex; |
5934 | dbg.nospace() << ')'; |
5935 | break; |
5936 | case QRhiShaderResourceBinding::Sampler: |
5937 | dbg.nospace() << " Sampler(" |
5938 | << " sampler=" << d->u.stex.texSamplers[0].sampler |
5939 | << ')'; |
5940 | break; |
5941 | case QRhiShaderResourceBinding::ImageLoad: |
5942 | dbg.nospace() << " ImageLoad(" |
5943 | << "texture=" << d->u.simage.tex |
5944 | << " level=" << d->u.simage.level |
5945 | << ')'; |
5946 | break; |
5947 | case QRhiShaderResourceBinding::ImageStore: |
5948 | dbg.nospace() << " ImageStore(" |
5949 | << "texture=" << d->u.simage.tex |
5950 | << " level=" << d->u.simage.level |
5951 | << ')'; |
5952 | break; |
5953 | case QRhiShaderResourceBinding::ImageLoadStore: |
5954 | dbg.nospace() << " ImageLoadStore(" |
5955 | << "texture=" << d->u.simage.tex |
5956 | << " level=" << d->u.simage.level |
5957 | << ')'; |
5958 | break; |
5959 | case QRhiShaderResourceBinding::BufferLoad: |
5960 | dbg.nospace() << " BufferLoad(" |
5961 | << "buffer=" << d->u.sbuf.buf |
5962 | << " offset=" << d->u.sbuf.offset |
5963 | << " maybeSize=" << d->u.sbuf.maybeSize |
5964 | << ')'; |
5965 | break; |
5966 | case QRhiShaderResourceBinding::BufferStore: |
5967 | dbg.nospace() << " BufferStore(" |
5968 | << "buffer=" << d->u.sbuf.buf |
5969 | << " offset=" << d->u.sbuf.offset |
5970 | << " maybeSize=" << d->u.sbuf.maybeSize |
5971 | << ')'; |
5972 | break; |
5973 | case QRhiShaderResourceBinding::BufferLoadStore: |
5974 | dbg.nospace() << " BufferLoadStore(" |
5975 | << "buffer=" << d->u.sbuf.buf |
5976 | << " offset=" << d->u.sbuf.offset |
5977 | << " maybeSize=" << d->u.sbuf.maybeSize |
5978 | << ')'; |
5979 | break; |
5980 | default: |
5981 | dbg.nospace() << " UNKNOWN()" ; |
5982 | break; |
5983 | } |
5984 | dbg.nospace() << ')'; |
5985 | return dbg; |
5986 | } |
5987 | #endif |
5988 | |
5989 | #ifndef QT_NO_DEBUG_STREAM |
5990 | QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb) |
5991 | { |
5992 | QDebugStateSaver saver(dbg); |
5993 | dbg.nospace() << "QRhiShaderResourceBindings(" |
5994 | << srb.m_bindings |
5995 | << ')'; |
5996 | return dbg; |
5997 | } |
5998 | #endif |
5999 | |
6000 | /*! |
6001 | \class QRhiGraphicsPipeline |
6002 | \inmodule QtGui |
6003 | \since 6.6 |
6004 | \brief Graphics pipeline state resource. |
6005 | |
6006 | Represents a graphics pipeline. What exactly this map to in the underlying |
6007 | native graphics API, varies. Where there is a concept of pipeline objects, |
6008 | for example with Vulkan, the QRhi backend will create such an object upon |
6009 | calling create(). Elsewhere, for example with OpenGL, the |
6010 | QRhiGraphicsPipeline may merely collect the various state, and create()'s |
6011 | main task is to set up the corresponding shader program, but deferring |
6012 | looking at any of the requested state to a later point. |
6013 | |
6014 | As with all QRhiResource subclasses, the two-phased initialization pattern |
6015 | applies: setting any values via the setters, for example setDepthTest(), is |
6016 | only effective after calling create(). Avoid changing any values once the |
6017 | QRhiGraphicsPipeline has been initialized via create(). To change some |
6018 | state, set the new value and call create() again. However, that will |
6019 | effectively release all underlying native resources and create new ones. As |
6020 | a result, it may be a heavy, expensive operation. Rather, prefer creating |
6021 | multiple pipelines with the different states, and |
6022 | \l{QRhiCommandBuffer::setGraphicsPipeline()}{switch between them} when |
6023 | recording the render pass. |
6024 | |
6025 | \note Setting the shader stages is mandatory. There must be at least one |
6026 | stage, and there must be a vertex stage. |
6027 | |
6028 | \note Setting the shader resource bindings is mandatory. The referenced |
6029 | QRhiShaderResourceBindings must already have create() called on it by the |
6030 | time create() is called. Associating with a QRhiShaderResourceBindings that |
6031 | has no bindings is also valid, as long as no shader in any stage expects any |
6032 | resources. Using a QRhiShaderResourceBindings object that does not specify |
6033 | any actual resources (i.e., the buffers, textures, etc. for the binding |
6034 | points are set to \nullptr) is valid as well, as long as a |
6035 | \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible} |
6036 | QRhiShaderResourceBindings, that specifies resources for all the bindings, |
6037 | is going to be set via |
6038 | \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} when |
6039 | recording the render pass. |
6040 | |
6041 | \note Setting the render pass descriptor is mandatory. To obtain a |
6042 | QRhiRenderPassDescriptor that can be passed to setRenderPassDescriptor(), |
6043 | use either QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor() or |
6044 | QRhiSwapChain::newCompatibleRenderPassDescriptor(). |
6045 | |
6046 | \note Setting the vertex input layout is mandatory. |
6047 | |
6048 | \note sampleCount() defaults to 1 and must match the sample count of the |
6049 | render target's color and depth stencil attachments. |
6050 | |
6051 | \note The depth test, depth write, and stencil test are disabled by |
6052 | default. The face culling mode defaults to no culling. |
6053 | |
6054 | \note stencilReadMask() and stencilWriteMask() apply to both faces. They |
6055 | both default to 0xFF. |
6056 | |
6057 | \section2 Example usage |
6058 | |
6059 | All settings of a graphics pipeline have defaults which might be suitable |
6060 | to many applications. Therefore a minimal example of creating a graphics |
6061 | pipeline could be the following. This assumes that the vertex shader takes |
6062 | a single \c{vec3 position} input at the input location 0. With the |
6063 | QRhiShaderResourceBindings and QRhiRenderPassDescriptor objects, plus the |
6064 | QShader collections for the vertex and fragment stages, a pipeline could be |
6065 | created like this: |
6066 | |
6067 | \code |
6068 | QRhiShaderResourceBindings *srb; |
6069 | QRhiRenderPassDescriptor *rpDesc; |
6070 | QShader vs, fs; |
6071 | // ... |
6072 | |
6073 | QRhiVertexInputLayout inputLayout; |
6074 | inputLayout.setBindings({ { 3 * sizeof(float) } }); |
6075 | inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float3, 0 } }); |
6076 | |
6077 | QRhiGraphicsPipeline *ps = rhi->newGraphicsPipeline(); |
6078 | ps->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } }); |
6079 | ps->setVertexInputLayout(inputLayout); |
6080 | ps->setShaderResourceBindings(srb); |
6081 | ps->setRenderPassDescriptor(rpDesc); |
6082 | if (!ps->create()) { error(); } |
6083 | \endcode |
6084 | |
6085 | The above code creates a pipeline object that uses the defaults for many |
6086 | settings and states. For example, it will use a \l Triangles topology, no |
6087 | backface culling, blending is disabled but color write is enabled for all |
6088 | four channels, depth test/write are disabled, stencil operations are |
6089 | disabled. |
6090 | |
6091 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
6092 | for details. |
6093 | |
6094 | \sa QRhiCommandBuffer, QRhi |
6095 | */ |
6096 | |
6097 | /*! |
6098 | \enum QRhiGraphicsPipeline::Flag |
6099 | |
6100 | Flag values for describing the dynamic state of the pipeline, and other |
6101 | options. The viewport is always dynamic. |
6102 | |
6103 | \value UsesBlendConstants Indicates that a blend color constant will be set |
6104 | via QRhiCommandBuffer::setBlendConstants() |
6105 | |
6106 | \value UsesStencilRef Indicates that a stencil reference value will be set |
6107 | via QRhiCommandBuffer::setStencilRef() |
6108 | |
6109 | \value UsesScissor Indicates that a scissor rectangle will be set via |
6110 | QRhiCommandBuffer::setScissor() |
6111 | |
6112 | \value CompileShadersWithDebugInfo Requests compiling shaders with debug |
6113 | information enabled. This is relevant only when runtime shader compilation |
6114 | from source code is involved, and only when the underlying infrastructure |
6115 | supports this. With concrete examples, this is not relevant with Vulkan and |
6116 | SPIR-V, because the GLSL-to-SPIR-V compilation does not happen at run |
6117 | time. On the other hand, consider Direct3D and HLSL, where there are |
6118 | multiple options: when the QShader packages ship with pre-compiled bytecode |
6119 | (\c DXBC), debug information is to be requested through the tool that |
6120 | generates the \c{.qsb} file, similarly to the case of Vulkan and |
6121 | SPIR-V. However, when having HLSL source code in the pre- or |
6122 | runtime-generated QShader packages, the first phase of compilation (HLSL |
6123 | source to intermediate format) happens at run time too, with this flag taken |
6124 | into account. Debug information is relevant in particular with tools like |
6125 | RenderDoc since it allows seeing the original source code when investigating |
6126 | the pipeline and when performing vertex or fragment shader debugging. |
6127 | */ |
6128 | |
6129 | /*! |
6130 | \enum QRhiGraphicsPipeline::Topology |
6131 | Specifies the primitive topology |
6132 | |
6133 | \value Triangles (default) |
6134 | \value TriangleStrip |
6135 | \value TriangleFan (only available if QRhi::TriangleFanTopology is supported) |
6136 | \value Lines |
6137 | \value LineStrip |
6138 | \value Points |
6139 | |
6140 | \value Patches (only available if QRhi::Tessellation is supported, and |
6141 | requires the tessellation stages to be present in the pipeline) |
6142 | */ |
6143 | |
6144 | /*! |
6145 | \enum QRhiGraphicsPipeline::CullMode |
6146 | Specifies the culling mode |
6147 | |
6148 | \value None No culling (default) |
6149 | \value Front Cull front faces |
6150 | \value Back Cull back faces |
6151 | */ |
6152 | |
6153 | /*! |
6154 | \enum QRhiGraphicsPipeline::FrontFace |
6155 | Specifies the front face winding order |
6156 | |
6157 | \value CCW Counter clockwise (default) |
6158 | \value CW Clockwise |
6159 | */ |
6160 | |
6161 | /*! |
6162 | \enum QRhiGraphicsPipeline::ColorMaskComponent |
6163 | Flag values for specifying the color write mask |
6164 | |
6165 | \value R |
6166 | \value G |
6167 | \value B |
6168 | \value A |
6169 | */ |
6170 | |
6171 | /*! |
6172 | \enum QRhiGraphicsPipeline::BlendFactor |
6173 | Specifies the blend factor |
6174 | |
6175 | \value Zero |
6176 | \value One |
6177 | \value SrcColor |
6178 | \value OneMinusSrcColor |
6179 | \value DstColor |
6180 | \value OneMinusDstColor |
6181 | \value SrcAlpha |
6182 | \value OneMinusSrcAlpha |
6183 | \value DstAlpha |
6184 | \value OneMinusDstAlpha |
6185 | \value ConstantColor |
6186 | \value OneMinusConstantColor |
6187 | \value ConstantAlpha |
6188 | \value OneMinusConstantAlpha |
6189 | \value SrcAlphaSaturate |
6190 | \value Src1Color |
6191 | \value OneMinusSrc1Color |
6192 | \value Src1Alpha |
6193 | \value OneMinusSrc1Alpha |
6194 | */ |
6195 | |
6196 | /*! |
6197 | \enum QRhiGraphicsPipeline::BlendOp |
6198 | Specifies the blend operation |
6199 | |
6200 | \value Add |
6201 | \value Subtract |
6202 | \value ReverseSubtract |
6203 | \value Min |
6204 | \value Max |
6205 | */ |
6206 | |
6207 | /*! |
6208 | \enum QRhiGraphicsPipeline::CompareOp |
6209 | Specifies the depth or stencil comparison function |
6210 | |
6211 | \value Never |
6212 | \value Less (default for depth) |
6213 | \value Equal |
6214 | \value LessOrEqual |
6215 | \value Greater |
6216 | \value NotEqual |
6217 | \value GreaterOrEqual |
6218 | \value Always (default for stencil) |
6219 | */ |
6220 | |
6221 | /*! |
6222 | \enum QRhiGraphicsPipeline::StencilOp |
6223 | Specifies the stencil operation |
6224 | |
6225 | \value StencilZero |
6226 | \value Keep (default) |
6227 | \value Replace |
6228 | \value IncrementAndClamp |
6229 | \value DecrementAndClamp |
6230 | \value Invert |
6231 | \value IncrementAndWrap |
6232 | \value DecrementAndWrap |
6233 | */ |
6234 | |
6235 | /*! |
6236 | \enum QRhiGraphicsPipeline::PolygonMode |
6237 | \brief Specifies the polygon rasterization mode |
6238 | |
6239 | Polygon Mode (Triangle Fill Mode in Metal, Fill Mode in D3D) specifies |
6240 | the fill mode used when rasterizing polygons. Polygons may be drawn as |
6241 | solids (Fill), or as a wire mesh (Line). |
6242 | |
6243 | Support for non-fill polygon modes is optional and is indicated by the |
6244 | QRhi::NonFillPolygonMode feature. With OpenGL ES and some Vulkan |
6245 | implementations the feature will likely be reported as unsupported, which |
6246 | then means values other than Fill cannot be used. |
6247 | |
6248 | \value Fill The interior of the polygon is filled (default) |
6249 | \value Line Boundary edges of the polygon are drawn as line segments. |
6250 | */ |
6251 | |
6252 | /*! |
6253 | \struct QRhiGraphicsPipeline::TargetBlend |
6254 | \inmodule QtGui |
6255 | \since 6.6 |
6256 | \brief Describes the blend state for one color attachment. |
6257 | |
6258 | Defaults to color write enabled, blending disabled. The blend values are |
6259 | set up for pre-multiplied alpha (One, OneMinusSrcAlpha, One, |
6260 | OneMinusSrcAlpha) by default. This means that to get the alpha blending |
6261 | mode Qt Quick uses, it is enough to set the \c enable flag to true while |
6262 | leaving other values at their defaults. |
6263 | |
6264 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
6265 | for details. |
6266 | */ |
6267 | |
6268 | /*! |
6269 | \variable QRhiGraphicsPipeline::TargetBlend::colorWrite |
6270 | */ |
6271 | |
6272 | /*! |
6273 | \variable QRhiGraphicsPipeline::TargetBlend::enable |
6274 | */ |
6275 | |
6276 | /*! |
6277 | \variable QRhiGraphicsPipeline::TargetBlend::srcColor |
6278 | */ |
6279 | |
6280 | /*! |
6281 | \variable QRhiGraphicsPipeline::TargetBlend::dstColor |
6282 | */ |
6283 | |
6284 | /*! |
6285 | \variable QRhiGraphicsPipeline::TargetBlend::opColor |
6286 | */ |
6287 | |
6288 | /*! |
6289 | \variable QRhiGraphicsPipeline::TargetBlend::srcAlpha |
6290 | */ |
6291 | |
6292 | /*! |
6293 | \variable QRhiGraphicsPipeline::TargetBlend::dstAlpha |
6294 | */ |
6295 | |
6296 | /*! |
6297 | \variable QRhiGraphicsPipeline::TargetBlend::opAlpha |
6298 | */ |
6299 | |
6300 | /*! |
6301 | \struct QRhiGraphicsPipeline::StencilOpState |
6302 | \inmodule QtGui |
6303 | \since 6.6 |
6304 | \brief Describes the stencil operation state. |
6305 | |
6306 | The default-constructed StencilOpState has the following set: |
6307 | \list |
6308 | \li failOp - \l Keep |
6309 | \li depthFailOp - \l Keep |
6310 | \li passOp - \l Keep |
6311 | \li compareOp \l Always |
6312 | \endlist |
6313 | |
6314 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
6315 | for details. |
6316 | */ |
6317 | |
6318 | /*! |
6319 | \variable QRhiGraphicsPipeline::StencilOpState::failOp |
6320 | */ |
6321 | |
6322 | /*! |
6323 | \variable QRhiGraphicsPipeline::StencilOpState::depthFailOp |
6324 | */ |
6325 | |
6326 | /*! |
6327 | \variable QRhiGraphicsPipeline::StencilOpState::passOp |
6328 | */ |
6329 | |
6330 | /*! |
6331 | \variable QRhiGraphicsPipeline::StencilOpState::compareOp |
6332 | */ |
6333 | |
6334 | /*! |
6335 | \internal |
6336 | */ |
6337 | QRhiGraphicsPipeline::QRhiGraphicsPipeline(QRhiImplementation *rhi) |
6338 | : QRhiResource(rhi) |
6339 | { |
6340 | } |
6341 | |
6342 | /*! |
6343 | \return the resource type. |
6344 | */ |
6345 | QRhiResource::Type QRhiGraphicsPipeline::resourceType() const |
6346 | { |
6347 | return GraphicsPipeline; |
6348 | } |
6349 | |
6350 | /*! |
6351 | \fn virtual bool QRhiGraphicsPipeline::create() = 0 |
6352 | |
6353 | Creates the corresponding native graphics resources. If there are already |
6354 | resources present due to an earlier create() with no corresponding |
6355 | destroy(), then destroy() is called implicitly first. |
6356 | |
6357 | \return \c true when successful, \c false when a graphics operation failed. |
6358 | Regardless of the return value, calling destroy() is always safe. |
6359 | |
6360 | \note This may be, depending on the underlying graphics API, an expensive |
6361 | operation, especially when shaders get compiled/optimized from source or |
6362 | from an intermediate bytecode format to the GPU's own instruction set. |
6363 | Where applicable, the QRhi backend automatically sets up the relevant |
6364 | non-persistent facilities to accelerate this, for example the Vulkan |
6365 | backend automatically creates a \c VkPipelineCache to improve data reuse |
6366 | during the lifetime of the application. |
6367 | |
6368 | \note Drivers may also employ various persistent (disk-based) caching |
6369 | strategies for shader and pipeline data, which is hidden to and is outside |
6370 | of Qt's control. In some cases, depending on the graphics API and the QRhi |
6371 | backend, there are facilities within QRhi for manually managing such a |
6372 | cache, allowing the retrieval of a serializable blob that can then be |
6373 | reloaded in the future runs of the application to ensure faster pipeline |
6374 | creation times. See QRhi::pipelineCacheData() and |
6375 | QRhi::setPipelineCacheData() for details. Note also that when working with |
6376 | a QRhi instance managed by a higher level Qt framework, such as Qt Quick, |
6377 | it is possible that such disk-based caching is taken care of automatically, |
6378 | for example QQuickWindow uses a disk-based pipeline cache by default (which |
6379 | comes in addition to any driver-level caching). |
6380 | */ |
6381 | |
6382 | /*! |
6383 | \fn QRhiGraphicsPipeline::Flags QRhiGraphicsPipeline::flags() const |
6384 | \return the currently set flags. |
6385 | */ |
6386 | |
6387 | /*! |
6388 | \fn void QRhiGraphicsPipeline::setFlags(Flags f) |
6389 | Sets the flags \a f. |
6390 | */ |
6391 | |
6392 | /*! |
6393 | \fn QRhiGraphicsPipeline::Topology QRhiGraphicsPipeline::topology() const |
6394 | \return the currently set primitive topology. |
6395 | */ |
6396 | |
6397 | /*! |
6398 | \fn void QRhiGraphicsPipeline::setTopology(Topology t) |
6399 | Sets the primitive topology \a t. |
6400 | */ |
6401 | |
6402 | /*! |
6403 | \fn QRhiGraphicsPipeline::CullMode QRhiGraphicsPipeline::cullMode() const |
6404 | \return the currently set face culling mode. |
6405 | */ |
6406 | |
6407 | /*! |
6408 | \fn void QRhiGraphicsPipeline::setCullMode(CullMode mode) |
6409 | Sets the specified face culling \a mode. |
6410 | */ |
6411 | |
6412 | /*! |
6413 | \fn QRhiGraphicsPipeline::FrontFace QRhiGraphicsPipeline::frontFace() const |
6414 | \return the currently set front face mode. |
6415 | */ |
6416 | |
6417 | /*! |
6418 | \fn void QRhiGraphicsPipeline::setFrontFace(FrontFace f) |
6419 | Sets the front face mode \a f. |
6420 | */ |
6421 | |
6422 | /*! |
6423 | \fn void QRhiGraphicsPipeline::setTargetBlends(std::initializer_list<TargetBlend> list) |
6424 | |
6425 | Sets the \a list of render target blend settings. This is a list because |
6426 | when multiple render targets are used (i.e., a QRhiTextureRenderTarget with |
6427 | more than one QRhiColorAttachment), there needs to be a TargetBlend |
6428 | structure per render target (color attachment). |
6429 | |
6430 | By default there is one default-constructed TargetBlend set. |
6431 | |
6432 | \sa QRhi::MaxColorAttachments |
6433 | */ |
6434 | |
6435 | /*! |
6436 | \fn template<typename InputIterator> void QRhiGraphicsPipeline::setTargetBlends(InputIterator first, InputIterator last) |
6437 | Sets the list of render target blend settings from the iterators \a first and \a last. |
6438 | */ |
6439 | |
6440 | /*! |
6441 | \fn const QRhiGraphicsPipeline::TargetBlend *QRhiGraphicsPipeline::cbeginTargetBlends() const |
6442 | \return a const iterator pointing to the first item in the render target blend setting list. |
6443 | */ |
6444 | |
6445 | /*! |
6446 | \fn const QRhiGraphicsPipeline::TargetBlend *QRhiGraphicsPipeline::cendTargetBlends() const |
6447 | \return a const iterator pointing just after the last item in the render target blend setting list. |
6448 | */ |
6449 | |
6450 | /*! |
6451 | \fn const QRhiGraphicsPipeline::TargetBlend *QRhiGraphicsPipeline::targetBlendAt(qsizetype index) const |
6452 | \return the render target blend setting at the specified \a index. |
6453 | */ |
6454 | |
6455 | /*! |
6456 | \fn qsizetype QRhiGraphicsPipeline::targetBlendCount() const |
6457 | \return the number of render target blend settings. |
6458 | */ |
6459 | |
6460 | /*! |
6461 | \fn bool QRhiGraphicsPipeline::hasDepthTest() const |
6462 | \return true if depth testing is enabled. |
6463 | */ |
6464 | |
6465 | /*! |
6466 | \fn void QRhiGraphicsPipeline::setDepthTest(bool enable) |
6467 | |
6468 | Enables or disables depth testing based on \a enable. Both depth test and |
6469 | the writing out of depth data are disabled by default. |
6470 | |
6471 | \sa setDepthWrite() |
6472 | */ |
6473 | |
6474 | /*! |
6475 | \fn bool QRhiGraphicsPipeline::hasDepthWrite() const |
6476 | \return true if depth write is enabled. |
6477 | */ |
6478 | |
6479 | /*! |
6480 | \fn void QRhiGraphicsPipeline::setDepthWrite(bool enable) |
6481 | |
6482 | Controls the writing out of depth data into the depth buffer based on |
6483 | \a enable. By default this is disabled. Depth write is typically enabled |
6484 | together with the depth test. |
6485 | |
6486 | \note Enabling depth write without having depth testing enabled may not |
6487 | lead to the desired result, and should be avoided. |
6488 | |
6489 | \sa setDepthTest() |
6490 | */ |
6491 | |
6492 | /*! |
6493 | \fn QRhiGraphicsPipeline::CompareOp QRhiGraphicsPipeline::depthOp() const |
6494 | \return the depth comparison function. |
6495 | */ |
6496 | |
6497 | /*! |
6498 | \fn void QRhiGraphicsPipeline::setDepthOp(CompareOp op) |
6499 | Sets the depth comparison function \a op. |
6500 | */ |
6501 | |
6502 | /*! |
6503 | \fn bool QRhiGraphicsPipeline::hasStencilTest() const |
6504 | \return true if stencil testing is enabled. |
6505 | */ |
6506 | |
6507 | /*! |
6508 | \fn void QRhiGraphicsPipeline::setStencilTest(bool enable) |
6509 | Enables or disables stencil tests based on \a enable. |
6510 | By default this is disabled. |
6511 | */ |
6512 | |
6513 | /*! |
6514 | \fn QRhiGraphicsPipeline::StencilOpState QRhiGraphicsPipeline::stencilFront() const |
6515 | \return the current stencil test state for front faces. |
6516 | */ |
6517 | |
6518 | /*! |
6519 | \fn void QRhiGraphicsPipeline::setStencilFront(const StencilOpState &state) |
6520 | Sets the stencil test \a state for front faces. |
6521 | */ |
6522 | |
6523 | /*! |
6524 | \fn QRhiGraphicsPipeline::StencilOpState QRhiGraphicsPipeline::stencilBack() const |
6525 | \return the current stencil test state for back faces. |
6526 | */ |
6527 | |
6528 | /*! |
6529 | \fn void QRhiGraphicsPipeline::setStencilBack(const StencilOpState &state) |
6530 | Sets the stencil test \a state for back faces. |
6531 | */ |
6532 | |
6533 | /*! |
6534 | \fn quint32 QRhiGraphicsPipeline::stencilReadMask() const |
6535 | \return the currrent stencil read mask. |
6536 | */ |
6537 | |
6538 | /*! |
6539 | \fn void QRhiGraphicsPipeline::setStencilReadMask(quint32 mask) |
6540 | Sets the stencil read \a mask. The default value is 0xFF. |
6541 | */ |
6542 | |
6543 | /*! |
6544 | \fn quint32 QRhiGraphicsPipeline::stencilWriteMask() const |
6545 | \return the current stencil write mask. |
6546 | */ |
6547 | |
6548 | /*! |
6549 | \fn void QRhiGraphicsPipeline::setStencilWriteMask(quint32 mask) |
6550 | Sets the stencil write \a mask. The default value is 0xFF. |
6551 | */ |
6552 | |
6553 | /*! |
6554 | \fn int QRhiGraphicsPipeline::sampleCount() const |
6555 | \return the currently set sample count. 1 means no multisample antialiasing. |
6556 | */ |
6557 | |
6558 | /*! |
6559 | \fn void QRhiGraphicsPipeline::setSampleCount(int s) |
6560 | |
6561 | Sets the sample count. Typical values for \a s are 1, 4, or 8. The pipeline |
6562 | must always be compatible with the render target, i.e. the sample counts |
6563 | must match. |
6564 | |
6565 | \sa QRhi::supportedSampleCounts() |
6566 | */ |
6567 | |
6568 | /*! |
6569 | \fn float QRhiGraphicsPipeline::lineWidth() const |
6570 | \return the currently set line width. The default is 1.0f. |
6571 | */ |
6572 | |
6573 | /*! |
6574 | \fn void QRhiGraphicsPipeline::setLineWidth(float width) |
6575 | |
6576 | Sets the line \a width. If the QRhi::WideLines feature is reported as |
6577 | unsupported at runtime, values other than 1.0f are ignored. |
6578 | */ |
6579 | |
6580 | /*! |
6581 | \fn int QRhiGraphicsPipeline::depthBias() const |
6582 | \return the currently set depth bias. |
6583 | */ |
6584 | |
6585 | /*! |
6586 | \fn void QRhiGraphicsPipeline::setDepthBias(int bias) |
6587 | Sets the depth \a bias. The default value is 0. |
6588 | */ |
6589 | |
6590 | /*! |
6591 | \fn float QRhiGraphicsPipeline::slopeScaledDepthBias() const |
6592 | \return the currently set slope scaled depth bias. |
6593 | */ |
6594 | |
6595 | /*! |
6596 | \fn void QRhiGraphicsPipeline::setSlopeScaledDepthBias(float bias) |
6597 | Sets the slope scaled depth \a bias. The default value is 0. |
6598 | */ |
6599 | |
6600 | /*! |
6601 | \fn void QRhiGraphicsPipeline::setShaderStages(std::initializer_list<QRhiShaderStage> list) |
6602 | Sets the \a list of shader stages. |
6603 | */ |
6604 | |
6605 | /*! |
6606 | \fn template<typename InputIterator> void QRhiGraphicsPipeline::setShaderStages(InputIterator first, InputIterator last) |
6607 | Sets the list of shader stages from the iterators \a first and \a last. |
6608 | */ |
6609 | |
6610 | /*! |
6611 | \fn const QRhiShaderStage *QRhiGraphicsPipeline::cbeginShaderStages() const |
6612 | \return a const iterator pointing to the first item in the shader stage list. |
6613 | */ |
6614 | |
6615 | /*! |
6616 | \fn const QRhiShaderStage *QRhiGraphicsPipeline::cendShaderStages() const |
6617 | \return a const iterator pointing just after the last item in the shader stage list. |
6618 | */ |
6619 | |
6620 | /*! |
6621 | \fn const QRhiShaderStage *QRhiGraphicsPipeline::shaderStageAt(qsizetype index) const |
6622 | \return the shader stage at the specified \a index. |
6623 | */ |
6624 | |
6625 | /*! |
6626 | \fn qsizetype QRhiGraphicsPipeline::shaderStageCount() const |
6627 | \return the number of shader stages in this pipeline. |
6628 | */ |
6629 | |
6630 | /*! |
6631 | \fn QRhiVertexInputLayout QRhiGraphicsPipeline::vertexInputLayout() const |
6632 | \return the currently set vertex input layout specification. |
6633 | */ |
6634 | |
6635 | /*! |
6636 | \fn void QRhiGraphicsPipeline::setVertexInputLayout(const QRhiVertexInputLayout &layout) |
6637 | Specifies the vertex input \a layout. |
6638 | */ |
6639 | |
6640 | /*! |
6641 | \fn QRhiShaderResourceBindings *QRhiGraphicsPipeline::shaderResourceBindings() const |
6642 | \return the currently associated QRhiShaderResourceBindings object. |
6643 | */ |
6644 | |
6645 | /*! |
6646 | \fn void QRhiGraphicsPipeline::setShaderResourceBindings(QRhiShaderResourceBindings *srb) |
6647 | |
6648 | Associates with \a srb describing the resource binding layout and the |
6649 | resources (QRhiBuffer, QRhiTexture) themselves. The latter is optional, |
6650 | because only the layout matters during pipeline creation. Therefore, the \a |
6651 | srb passed in here can leave the actual buffer or texture objects |
6652 | unspecified (\nullptr) as long as there is another, |
6653 | \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible} |
6654 | QRhiShaderResourceBindings bound via |
6655 | \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} before |
6656 | recording the draw calls. |
6657 | */ |
6658 | |
6659 | /*! |
6660 | \fn QRhiRenderPassDescriptor *QRhiGraphicsPipeline::renderPassDescriptor() const |
6661 | \return the currently set QRhiRenderPassDescriptor. |
6662 | */ |
6663 | |
6664 | /*! |
6665 | \fn void QRhiGraphicsPipeline::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) |
6666 | Associates with the specified QRhiRenderPassDescriptor \a desc. |
6667 | */ |
6668 | |
6669 | /*! |
6670 | \fn int QRhiGraphicsPipeline::patchControlPointCount() const |
6671 | \return the currently set patch control point count. |
6672 | */ |
6673 | |
6674 | /*! |
6675 | \fn void QRhiGraphicsPipeline::setPatchControlPointCount(int count) |
6676 | |
6677 | Sets the number of patch control points to \a count. The default value is |
6678 | 3. This is used only when the topology is set to \l Patches. |
6679 | */ |
6680 | |
6681 | /*! |
6682 | \fn QRhiGraphicsPipeline::PolygonMode QRhiGraphicsPipeline::polygonMode() const |
6683 | \return the polygon mode. |
6684 | */ |
6685 | |
6686 | /*! |
6687 | \fn void QRhiGraphicsPipeline::setPolygonMode(PolygonMode mode) |
6688 | Sets the polygon \a mode. The default is Fill. |
6689 | |
6690 | \sa QRhi::NonFillPolygonMode |
6691 | */ |
6692 | |
6693 | /*! |
6694 | \class QRhiSwapChain |
6695 | \inmodule QtGui |
6696 | \since 6.6 |
6697 | \brief Swapchain resource. |
6698 | |
6699 | A swapchain enables presenting rendering results to a surface. A swapchain |
6700 | is typically backed by a set of color buffers. Of these, one is displayed |
6701 | at a time. |
6702 | |
6703 | Below is a typical pattern for creating and managing a swapchain and some |
6704 | associated resources in order to render onto a QWindow: |
6705 | |
6706 | \code |
6707 | void init() |
6708 | { |
6709 | sc = rhi->newSwapChain(); |
6710 | ds = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, |
6711 | QSize(), // no need to set the size here due to UsedWithSwapChainOnly |
6712 | 1, |
6713 | QRhiRenderBuffer::UsedWithSwapChainOnly); |
6714 | sc->setWindow(window); |
6715 | sc->setDepthStencil(ds); |
6716 | rp = sc->newCompatibleRenderPassDescriptor(); |
6717 | sc->setRenderPassDescriptor(rp); |
6718 | resizeSwapChain(); |
6719 | } |
6720 | |
6721 | void resizeSwapChain() |
6722 | { |
6723 | hasSwapChain = sc->createOrResize(); |
6724 | } |
6725 | |
6726 | void render() |
6727 | { |
6728 | if (!hasSwapChain || notExposed) |
6729 | return; |
6730 | |
6731 | if (sc->currentPixelSize() != sc->surfacePixelSize() || newlyExposed) { |
6732 | resizeSwapChain(); |
6733 | if (!hasSwapChain) |
6734 | return; |
6735 | newlyExposed = false; |
6736 | } |
6737 | |
6738 | rhi->beginFrame(sc); |
6739 | // ... |
6740 | rhi->endFrame(sc); |
6741 | } |
6742 | \endcode |
6743 | |
6744 | Avoid relying on QWindow resize events to resize swapchains, especially |
6745 | considering that surface sizes may not always fully match the QWindow |
6746 | reported dimensions. The safe, cross-platform approach is to do the check |
6747 | via surfacePixelSize() whenever starting a new frame. |
6748 | |
6749 | Releasing the swapchain must happen while the QWindow and the underlying |
6750 | native window is fully up and running. Building on the previous example: |
6751 | |
6752 | \code |
6753 | void releaseSwapChain() |
6754 | { |
6755 | if (hasSwapChain) { |
6756 | sc->destroy(); |
6757 | hasSwapChain = false; |
6758 | } |
6759 | } |
6760 | |
6761 | // assuming Window is our QWindow subclass |
6762 | bool Window::event(QEvent *e) |
6763 | { |
6764 | switch (e->type()) { |
6765 | case QEvent::UpdateRequest: // for QWindow::requestUpdate() |
6766 | render(); |
6767 | break; |
6768 | case QEvent::PlatformSurface: |
6769 | if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) |
6770 | releaseSwapChain(); |
6771 | break; |
6772 | default: |
6773 | break; |
6774 | } |
6775 | return QWindow::event(e); |
6776 | } |
6777 | \endcode |
6778 | |
6779 | Initializing the swapchain and starting to render the first frame cannot |
6780 | start at any time. The safe, cross-platform approach is to rely on expose |
6781 | events. QExposeEvent is a loosely specified event that is sent whenever a |
6782 | window gets mapped, obscured, and resized, depending on the platform. |
6783 | |
6784 | \code |
6785 | void Window::exposeEvent(QExposeEvent *) |
6786 | { |
6787 | // initialize and start rendering when the window becomes usable for graphics purposes |
6788 | if (isExposed() && !running) { |
6789 | running = true; |
6790 | init(); |
6791 | } |
6792 | |
6793 | // stop pushing frames when not exposed or size becomes 0 |
6794 | if ((!isExposed() || (hasSwapChain && sc->surfacePixelSize().isEmpty())) && running) |
6795 | notExposed = true; |
6796 | |
6797 | // continue when exposed again and the surface has a valid size |
6798 | if (isExposed() && running && notExposed && !sc->surfacePixelSize().isEmpty()) { |
6799 | notExposed = false; |
6800 | newlyExposed = true; |
6801 | } |
6802 | |
6803 | if (isExposed() && !sc->surfacePixelSize().isEmpty()) |
6804 | render(); |
6805 | } |
6806 | \endcode |
6807 | |
6808 | Once the rendering has started, a simple way to request a new frame is |
6809 | QWindow::requestUpdate(). While on some platforms this is merely a small |
6810 | timer, on others it has a specific implementation: for instance on macOS or |
6811 | iOS it may be backed by |
6812 | \l{https://developer.apple.com/documentation/corevideo/cvdisplaylink?language=objc}{CVDisplayLink}. |
6813 | The example above is already prepared for update requests by handling |
6814 | QEvent::UpdateRequest. |
6815 | |
6816 | While acting as a QRhiRenderTarget, QRhiSwapChain also manages a |
6817 | QRhiCommandBuffer. Calling QRhi::endFrame() submits the recorded commands |
6818 | and also enqueues a \c present request. The default behavior is to do this |
6819 | with a swap interval of 1, meaning synchronizing to the display's vertical |
6820 | refresh is enabled. Thus the rendering thread calling beginFrame() and |
6821 | endFrame() will get throttled to vsync. On some backends this can be |
6822 | disabled by passing QRhiSwapChain:NoVSync in flags(). |
6823 | |
6824 | Multisampling (MSAA) is handled transparently to the applications when |
6825 | requested via setSampleCount(). Where applicable, QRhiSwapChain will take |
6826 | care of creating additional color buffers and issuing a multisample resolve |
6827 | command at the end of a frame. For OpenGL, it is necessary to request the |
6828 | appropriate sample count also via QSurfaceFormat, by calling |
6829 | QSurfaceFormat::setDefaultFormat() before initializing the QRhi. |
6830 | |
6831 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
6832 | for details. |
6833 | */ |
6834 | |
6835 | /*! |
6836 | \enum QRhiSwapChain::Flag |
6837 | Flag values to describe swapchain properties |
6838 | |
6839 | \value SurfaceHasPreMulAlpha Indicates that the target surface has |
6840 | transparency with premultiplied alpha. For example, this is what Qt Quick |
6841 | uses when the alpha channel is enabled on the target QWindow, because the |
6842 | scenegraph rendrerer always outputs fragments with alpha multiplied into |
6843 | the red, green, and blue values. To ensure identical behavior across |
6844 | platforms, always set QSurfaceFormat::alphaBufferSize() to a non-zero value |
6845 | on the target QWindow whenever this flag is set on the swapchain. |
6846 | |
6847 | \value SurfaceHasNonPreMulAlpha Indicates the target surface has |
6848 | transparency with non-premultiplied alpha. Be aware that this may not be |
6849 | supported on some systems, if the system compositor always expects content |
6850 | with premultiplied alpha. In that case the behavior with this flag set is |
6851 | expected to be equivalent to SurfaceHasPreMulAlpha. |
6852 | |
6853 | \value sRGB Requests to pick an sRGB format for the swapchain's color |
6854 | buffers and/or render target views, where applicable. Note that this |
6855 | implies that sRGB framebuffer update and blending will get enabled for all |
6856 | content targeting this swapchain, and opting out is not possible. For |
6857 | OpenGL, set \l{QSurfaceFormat::sRGBColorSpace}{sRGBColorSpace} on the |
6858 | QSurfaceFormat of the QWindow in addition. Applicable only when the |
6859 | swapchain format is set to QRhiSwapChain::SDR. |
6860 | |
6861 | \value UsedAsTransferSource Indicates the swapchain will be used as the |
6862 | source of a readback in QRhiResourceUpdateBatch::readBackTexture(). |
6863 | |
6864 | \value NoVSync Requests disabling waiting for vertical sync, also avoiding |
6865 | throttling the rendering thread. The behavior is backend specific and |
6866 | applicable only where it is possible to control this. Some may ignore the |
6867 | request altogether. For OpenGL, try instead setting the swap interval to 0 |
6868 | on the QWindow via QSurfaceFormat::setSwapInterval(). |
6869 | |
6870 | \value MinimalBufferCount Requests creating the swapchain with the minimum |
6871 | number of buffers, which is in practice 2, unless the graphics |
6872 | implementation has a higher minimum number than that. Only applicable with |
6873 | backends where such control is available via the graphics API, for example, |
6874 | Vulkan. By default it is up to the backend to decide what number of buffers |
6875 | it requests (in practice this is almost always either 2 or 3), and it is |
6876 | not the applications' concern. However, on Vulkan for instance the backend |
6877 | will likely prefer the higher number (3), for example to avoid odd |
6878 | performance issues with some Vulkan implementations on mobile devices. It |
6879 | could be that on some platforms it can prove to be beneficial to force the |
6880 | lower buffer count (2), so this flag allows forcing that. Note that all |
6881 | this has no effect on the number of frames kept in flight, so the CPU |
6882 | (QRhi) will still prepare frames at most \c{N - 1} frames ahead of the GPU, |
6883 | even when the swapchain image buffer count larger than \c N. (\c{N} = |
6884 | QRhi::FramesInFlight and typically 2). |
6885 | */ |
6886 | |
6887 | /*! |
6888 | \enum QRhiSwapChain::Format |
6889 | Describes the swapchain format. The default format is SDR. |
6890 | |
6891 | This enum is used with |
6892 | \l{QRhiSwapChain::isFormatSupported()}{isFormatSupported()} to check |
6893 | upfront if creating the swapchain with the given format is supported by the |
6894 | platform and the window's associated screen, and with |
6895 | \l{QRhiSwapChain::setFormat()}{setFormat()} |
6896 | to set the requested format in the swapchain before calling |
6897 | \l{QRhiSwapChain::createOrResize()}{createOrResize()} for the first time. |
6898 | |
6899 | \value SDR 8-bit RGBA or BGRA, depending on the backend and platform. With |
6900 | OpenGL ES in particular, it could happen that the platform provides less |
6901 | than 8 bits (e.g. due to EGL and the QSurfaceFormat choosing a 565 or 444 |
6902 | format - this is outside the control of QRhi). Standard dynamic range. May |
6903 | be combined with setting the QRhiSwapChain::sRGB flag. |
6904 | |
6905 | \value HDRExtendedSrgbLinear 16-bit float RGBA, high dynamic range, |
6906 | extended linear sRGB (scRGB) color space. This involves Rec. 709 primaries |
6907 | (same as SDR/sRGB) and linear colors. Conversion to the display's native |
6908 | color space (such as, HDR10) is performed by the windowing system. On |
6909 | Windows this is the canonical color space of the system compositor, and is |
6910 | the recommended format for HDR swapchains in general. |
6911 | |
6912 | \value HDR10 10-bit unsigned int RGB or BGR with 2 bit alpha, high dynamic |
6913 | range, HDR10 (Rec. 2020) color space with an ST2084 PQ transfer function. |
6914 | */ |
6915 | |
6916 | /*! |
6917 | \internal |
6918 | */ |
6919 | QRhiSwapChain::QRhiSwapChain(QRhiImplementation *rhi) |
6920 | : QRhiResource(rhi) |
6921 | { |
6922 | } |
6923 | |
6924 | /*! |
6925 | \return the resource type. |
6926 | */ |
6927 | QRhiResource::Type QRhiSwapChain::resourceType() const |
6928 | { |
6929 | return SwapChain; |
6930 | } |
6931 | |
6932 | /*! |
6933 | \fn QSize QRhiSwapChain::currentPixelSize() const |
6934 | |
6935 | \return the size with which the swapchain was last successfully built. Use |
6936 | this to decide if createOrResize() needs to be called again: if |
6937 | \c{currentPixelSize() != surfacePixelSize()} then the swapchain needs to be |
6938 | resized. |
6939 | |
6940 | \note Typical rendering logic will call this function to get the output |
6941 | size when starting to prepare a new frame, and base dependent calculations |
6942 | (such as, the viewport) on the size returned from this function. |
6943 | |
6944 | While in many cases the value is the same as \c{QWindow::size() * |
6945 | QWindow::devicePixelRatio()}, relying on the QWindow-reported size is not |
6946 | guaranteed to be correct on all platforms and graphics API implementations. |
6947 | Using this function is therefore strongly recommended whenever there is a |
6948 | need to identify the dimensions, in pixels, of the output layer or surface. |
6949 | |
6950 | This also has the added benefit of avoiding potential data races when QRhi |
6951 | is used on a dedicated rendering thread, because the need to call QWindow |
6952 | functions, that may then access data updated on the main thread, is |
6953 | avoided. |
6954 | |
6955 | \sa surfacePixelSize() |
6956 | */ |
6957 | |
6958 | /*! |
6959 | \fn virtual QSize QRhiSwapChain::surfacePixelSize() = 0 |
6960 | |
6961 | \return The size of the window's associated surface or layer. |
6962 | |
6963 | \warning Do not assume this is the same as \c{QWindow::size() * |
6964 | QWindow::devicePixelRatio()}. With some graphics APIs and windowing system |
6965 | interfaces (for example, Vulkan) there is a theoretical possibility for a |
6966 | surface to assume a size different from the associated window. To support |
6967 | these cases, \b{rendering logic must always base size-derived calculations |
6968 | (such as, viewports) on the size reported from QRhiSwapChain, and never on |
6969 | the size queried from QWindow}. |
6970 | |
6971 | \note \b{Can also be called before createOrResize(), if at least window() is |
6972 | already set. This in combination with currentPixelSize() allows to detect |
6973 | when a swapchain needs to be resized.} However, watch out for the fact that |
6974 | the size of the underlying native object (surface, layer, or similar) is |
6975 | "live", so whenever this function is called, it returns the latest value |
6976 | reported by the underlying implementation, without any atomicity guarantee. |
6977 | Therefore, using this function to determine pixel sizes for graphics |
6978 | resources that are used in a frame is strongly discouraged. Rely on |
6979 | currentPixelSize() instead which returns a size that is atomic and will not |
6980 | change between createOrResize() invocations. |
6981 | |
6982 | \note For depth-stencil buffers used in combination with the swapchain's |
6983 | color buffers, it is strongly recommended to rely on the automatic sizing |
6984 | and rebuilding behavior provided by the |
6985 | QRhiRenderBuffer:UsedWithSwapChainOnly flag. Avoid querying the surface |
6986 | size via this function just to get a size that can be passed to |
6987 | QRhiRenderBuffer::setPixelSize() as that would suffer from the lack of |
6988 | atomicity as described above. |
6989 | |
6990 | \sa currentPixelSize() |
6991 | */ |
6992 | |
6993 | /*! |
6994 | \fn virtual bool QRhiSwapChain::isFormatSupported(Format f) = 0 |
6995 | |
6996 | \return true if the given swapchain format \a f is supported. SDR is always |
6997 | supported. |
6998 | |
6999 | \note Can be called independently of createOrResize(), but window() must |
7000 | already be set. Calling without the window set may lead to unexpected |
7001 | results depending on the backend and platform (most likely false for any |
7002 | HDR format), because HDR format support is usually tied to the output |
7003 | (screen) to which the swapchain's associated window belongs at any given |
7004 | time. If the result is true for a HDR format, then creating the swapchain |
7005 | with that format is expected to succeed as long as the window is not moved |
7006 | to another screen in the meantime. |
7007 | |
7008 | The main use of this function is to call it before the first |
7009 | createOrResize() after the window is already set. This allow the QRhi |
7010 | backends to perform platform or windowing system specific queries to |
7011 | determine if the window (and the screen it is on) is capable of true HDR |
7012 | output with the specified format. |
7013 | |
7014 | When the format is reported as supported, call setFormat() to set the |
7015 | requested format and call createOrResize(). Be aware of the consequences |
7016 | however: successfully requesting a HDR format will involve having to deal |
7017 | with a different color space, possibly doing white level correction for |
7018 | non-HDR-aware content, adjusting tonemapping methods, adjusting offscreen |
7019 | render target settings, etc. |
7020 | |
7021 | \sa setFormat() |
7022 | */ |
7023 | |
7024 | /*! |
7025 | \fn virtual QRhiCommandBuffer *QRhiSwapChain::currentFrameCommandBuffer() = 0 |
7026 | |
7027 | \return a command buffer on which rendering commands and resource updates |
7028 | can be recorded within a \l{QRhi::beginFrame()}{beginFrame} - |
7029 | \l{QRhi::endFrame()}{endFrame} block, assuming beginFrame() was called with |
7030 | this swapchain. |
7031 | |
7032 | \note The returned object is valid also after endFrame(), up until the next |
7033 | beginFrame(), but the returned command buffer should not be used to record |
7034 | any commands then. Rather, it can be used to query data collected during |
7035 | the frame (or previous frames), for example by calling |
7036 | \l{QRhiCommandBuffer::lastCompletedGpuTime()}{lastCompletedGpuTime()}. |
7037 | |
7038 | \note The value must not be cached and reused between frames. The caller |
7039 | should not hold on to the returned object once |
7040 | \l{QRhi::beginFrame()}{beginFrame()} is called again. Instead, the command |
7041 | buffer object should be queried again by calling this function. |
7042 | */ |
7043 | |
7044 | /*! |
7045 | \fn virtual QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget() = 0 |
7046 | |
7047 | \return a render target that can used with beginPass() in order to render |
7048 | the swapchain's current backbuffer. Only valid within a |
7049 | QRhi::beginFrame() - QRhi::endFrame() block where beginFrame() was called |
7050 | with this swapchain. |
7051 | |
7052 | \note the value must not be cached and reused between frames |
7053 | */ |
7054 | |
7055 | /*! |
7056 | \enum QRhiSwapChain::StereoTargetBuffer |
7057 | Selects the backbuffer to use with a stereoscopic swapchain. |
7058 | |
7059 | \value LeftBuffer |
7060 | \value RightBuffer |
7061 | */ |
7062 | |
7063 | /*! |
7064 | \return a render target that can be used with beginPass() in order to |
7065 | render to the swapchain's left or right backbuffer. This overload should be |
7066 | used only with stereoscopic rendering, that is, when the associated QWindow |
7067 | is backed by two color buffers, one for each eye, instead of just one. |
7068 | |
7069 | When stereoscopic rendering is not supported, the return value will be |
7070 | the default target. For the time being the only backend and 3D API where traditional |
7071 | stereoscopic rendering is supported is OpenGL (excluding OpenGL ES), in |
7072 | combination with \l QSurfaceFormat::StereoBuffers, assuming it is supported |
7073 | by the graphics and display driver stack at run time. All other backends |
7074 | are going to return the default render target from this overload. |
7075 | |
7076 | \note the value must not be cached and reused between frames |
7077 | */ |
7078 | QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer) |
7079 | { |
7080 | Q_UNUSED(targetBuffer); |
7081 | return currentFrameRenderTarget(); |
7082 | } |
7083 | |
7084 | /*! |
7085 | \fn virtual bool QRhiSwapChain::createOrResize() = 0 |
7086 | |
7087 | Creates the swapchain if not already done and resizes the swapchain buffers |
7088 | to match the current size of the targeted surface. Call this whenever the |
7089 | size of the target surface is different than before. |
7090 | |
7091 | \note call destroy() only when the swapchain needs to be released |
7092 | completely, typically upon |
7093 | QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed. To perform resizing, just |
7094 | call createOrResize(). |
7095 | |
7096 | \return \c true when successful, \c false when a graphics operation failed. |
7097 | Regardless of the return value, calling destroy() is always safe. |
7098 | */ |
7099 | |
7100 | /*! |
7101 | \fn QWindow *QRhiSwapChain::window() const |
7102 | \return the currently set window. |
7103 | */ |
7104 | |
7105 | /*! |
7106 | \fn void QRhiSwapChain::setWindow(QWindow *window) |
7107 | Sets the \a window. |
7108 | */ |
7109 | |
7110 | /*! |
7111 | \fn QRhiSwapChainProxyData QRhiSwapChain::proxyData() const |
7112 | \return the currently set proxy data. |
7113 | */ |
7114 | |
7115 | /*! |
7116 | \fn void QRhiSwapChain::setProxyData(const QRhiSwapChainProxyData &d) |
7117 | Sets the proxy data \a d. |
7118 | |
7119 | \sa QRhi::updateSwapChainProxyData() |
7120 | */ |
7121 | |
7122 | /*! |
7123 | \fn QRhiSwapChain::Flags QRhiSwapChain::flags() const |
7124 | \return the currently set flags. |
7125 | */ |
7126 | |
7127 | /*! |
7128 | \fn void QRhiSwapChain::setFlags(Flags f) |
7129 | Sets the flags \a f. |
7130 | */ |
7131 | |
7132 | /*! |
7133 | \fn QRhiSwapChain::Format QRhiSwapChain::format() const |
7134 | \return the currently set format. |
7135 | */ |
7136 | |
7137 | /*! |
7138 | \fn void QRhiSwapChain::setFormat(Format f) |
7139 | Sets the format \a f. |
7140 | |
7141 | Avoid setting formats that are reported as unsupported from |
7142 | isFormatSupported(). Note that support for a given format may depend on the |
7143 | screen the swapchain's associated window is opened on. On some platforms, |
7144 | such as Windows and macOS, for HDR output to work it is necessary to have |
7145 | HDR output enabled in the display settings. |
7146 | |
7147 | See isFormatSupported(), \l QRhiSwapChainHdrInfo, and \l Format for more |
7148 | information on high dynamic range output. |
7149 | */ |
7150 | |
7151 | /*! |
7152 | \fn QRhiRenderBuffer *QRhiSwapChain::depthStencil() const |
7153 | \return the currently associated renderbuffer for depth-stencil. |
7154 | */ |
7155 | |
7156 | /*! |
7157 | \fn void QRhiSwapChain::setDepthStencil(QRhiRenderBuffer *ds) |
7158 | Sets the renderbuffer \a ds for use as a depth-stencil buffer. |
7159 | */ |
7160 | |
7161 | /*! |
7162 | \fn int QRhiSwapChain::sampleCount() const |
7163 | \return the currently set sample count. 1 means no multisample antialiasing. |
7164 | */ |
7165 | |
7166 | /*! |
7167 | \fn void QRhiSwapChain::setSampleCount(int samples) |
7168 | |
7169 | Sets the sample count. Common values for \a samples are 1 (no MSAA), 4 (4x |
7170 | MSAA), or 8 (8x MSAA). |
7171 | |
7172 | \sa QRhi::supportedSampleCounts() |
7173 | */ |
7174 | |
7175 | /*! |
7176 | \fn QRhiRenderPassDescriptor *QRhiSwapChain::renderPassDescriptor() const |
7177 | \return the currently associated QRhiRenderPassDescriptor object. |
7178 | */ |
7179 | |
7180 | /*! |
7181 | \fn void QRhiSwapChain::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) |
7182 | Associates with the QRhiRenderPassDescriptor \a desc. |
7183 | */ |
7184 | |
7185 | /*! |
7186 | \fn virtual QRhiRenderPassDescriptor *QRhiSwapChain::newCompatibleRenderPassDescriptor() = 0; |
7187 | |
7188 | \return a new QRhiRenderPassDescriptor that is compatible with this swapchain. |
7189 | |
7190 | The returned value is used in two ways: it can be passed to |
7191 | setRenderPassDescriptor() and |
7192 | QRhiGraphicsPipeline::setRenderPassDescriptor(). A render pass descriptor |
7193 | describes the attachments (color, depth/stencil) and the load/store |
7194 | behavior that can be affected by flags(). A QRhiGraphicsPipeline can only |
7195 | be used in combination with a swapchain that has a |
7196 | \l{QRhiRenderPassDescriptor::isCompatible()}{compatible} |
7197 | QRhiRenderPassDescriptor set. |
7198 | |
7199 | \sa createOrResize() |
7200 | */ |
7201 | |
7202 | /*! |
7203 | \struct QRhiSwapChainHdrInfo |
7204 | \inmodule QtGui |
7205 | \since 6.6 |
7206 | |
7207 | \brief Describes the high dynamic range related information of the |
7208 | swapchain's associated output. |
7209 | |
7210 | To perform tonemapping, one often needs to know the maximum luminance of |
7211 | the display the swapchain's window is associated with. While this is often |
7212 | made user-configurable, it can be highly useful to set defaults based on |
7213 | the values reported by the display itself, thus providing a decent starting |
7214 | point. |
7215 | |
7216 | There are some problems however: the information is exposed in different |
7217 | forms on different platforms, whereas with cross-platform graphics APIs |
7218 | there is often no associated solution at all, because managing such |
7219 | information is not in the scope of the API (and may rather be retrievable |
7220 | via other platform-specific means, if any). |
7221 | |
7222 | The struct returned from QRhiSwapChain::hdrInfo() contains either some |
7223 | hard-coded defaults, indicated by the \c isHardCodedDefaults field, or real |
7224 | values received from an API such as DXGI (IDXGIOutput6) or Cocoa |
7225 | (NSScreen). The default is 1000 nits for maximum luminance. |
7226 | |
7227 | With Metal on macOS/iOS, there is no luminance values exposed in the |
7228 | platform APIs. Instead, the maximum color component value, that would be |
7229 | 1.0 in a non-HDR setup, is provided. The \c limitsType field indicates what |
7230 | kind of information is available. It is then up to the clients of QRhi to |
7231 | access the correct data from the \c limits union and use it as they see |
7232 | fit. |
7233 | |
7234 | With an API like Vulkan, where there is no way to get such information, the |
7235 | values are always the built-in defaults and \c isHardCodedDefaults is |
7236 | always true. |
7237 | |
7238 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
7239 | for details. |
7240 | |
7241 | \sa QRhiSwapChain::hdrInfo() |
7242 | */ |
7243 | |
7244 | /*! |
7245 | \enum QRhiSwapChainHdrInfo::LimitsType |
7246 | |
7247 | \value LuminanceInNits Indicates that the \l limits union has its |
7248 | \c luminanceInNits struct set |
7249 | |
7250 | \value ColorComponentValue Indicates that the \l limits union has its |
7251 | \c colorComponentValue struct set |
7252 | */ |
7253 | |
7254 | /*! |
7255 | \variable QRhiSwapChainHdrInfo::isHardCodedDefaults |
7256 | |
7257 | Set to true when the data in the QRhiSwapChainHdrInfo consists entirely of |
7258 | the hard-coded default values, for example because there is no way to query |
7259 | the relevant information with a given graphics API or platform. (or because |
7260 | querying it can be achieved only by means, e.g. platform APIs in some other |
7261 | area, that are out of scope for the QRhi layer of the Qt graphics stack to |
7262 | handle) |
7263 | |
7264 | \sa QRhiSwapChain::hdrInfo() |
7265 | */ |
7266 | |
7267 | /*! |
7268 | \variable QRhiSwapChainHdrInfo::limitsType |
7269 | |
7270 | With Metal on macOS/iOS, there is no luminance values exposed in the |
7271 | platform APIs. Instead, the maximum color component value, that would be |
7272 | 1.0 in a non-HDR setup, is provided. This value indicates what kind of |
7273 | information is available in \l limits. |
7274 | |
7275 | \sa QRhiSwapChain::hdrInfo() |
7276 | */ |
7277 | |
7278 | /*! |
7279 | \variable QRhiSwapChainHdrInfo::limits |
7280 | |
7281 | Contains the actual values queried from the graphics API or the platform. |
7282 | The type of data is indicated by \l limitsType. This is therefore a union. |
7283 | There are currently two options: |
7284 | |
7285 | Luminance values in nits: |
7286 | |
7287 | \code |
7288 | struct { |
7289 | float minLuminance; |
7290 | float maxLuminance; |
7291 | } luminanceInNits; |
7292 | \endcode |
7293 | |
7294 | Whereas for macOS/iOS, the current maximum and potential maximum color |
7295 | component values are provided: |
7296 | |
7297 | \code |
7298 | struct { |
7299 | float maxColorComponentValue; |
7300 | float maxPotentialColorComponentValue; |
7301 | } colorComponentValue; |
7302 | \endcode |
7303 | |
7304 | \sa QRhiSwapChain::hdrInfo() |
7305 | */ |
7306 | |
7307 | /*! |
7308 | \return the HDR information for the associated display. |
7309 | |
7310 | The returned struct is always the default one if createOrResize() has not |
7311 | been successfully called yet. |
7312 | |
7313 | \note What happens when moving a window with an initialized swapchain |
7314 | between displays (HDR to HDR with different characteristics, HDR to SDR, |
7315 | etc.) is not currently well-defined and depends heavily on the windowing |
7316 | system and compositor, with potentially varying behavior between platforms. |
7317 | Currently QRhi only guarantees that hdrInfo() returns valid data, if |
7318 | available, for the display to which the swapchain's associated window |
7319 | belonged at the time of createOrResize(). |
7320 | |
7321 | \sa QRhiSwapChainHdrInfo |
7322 | */ |
7323 | QRhiSwapChainHdrInfo QRhiSwapChain::hdrInfo() |
7324 | { |
7325 | QRhiSwapChainHdrInfo info; |
7326 | info.isHardCodedDefaults = true; |
7327 | info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits; |
7328 | info.limits.luminanceInNits.minLuminance = 0.0f; |
7329 | info.limits.luminanceInNits.maxLuminance = 1000.0f; |
7330 | return info; |
7331 | } |
7332 | |
7333 | #ifndef QT_NO_DEBUG_STREAM |
7334 | QDebug operator<<(QDebug dbg, const QRhiSwapChainHdrInfo &info) |
7335 | { |
7336 | QDebugStateSaver saver(dbg); |
7337 | dbg.nospace() << "QRhiSwapChainHdrInfo(" << (info.isHardCodedDefaults ? "with hard-coded defaults" : "queried from system" ); |
7338 | switch (info.limitsType) { |
7339 | case QRhiSwapChainHdrInfo::LuminanceInNits: |
7340 | dbg.nospace() << " minLuminance=" << info.limits.luminanceInNits.minLuminance |
7341 | << " maxLuminance=" << info.limits.luminanceInNits.maxLuminance; |
7342 | break; |
7343 | case QRhiSwapChainHdrInfo::ColorComponentValue: |
7344 | dbg.nospace() << " maxColorComponentValue=" << info.limits.colorComponentValue.maxColorComponentValue; |
7345 | dbg.nospace() << " maxPotentialColorComponentValue=" << info.limits.colorComponentValue.maxPotentialColorComponentValue; |
7346 | break; |
7347 | } |
7348 | dbg.nospace() << ')'; |
7349 | return dbg; |
7350 | } |
7351 | #endif |
7352 | |
7353 | /*! |
7354 | \class QRhiComputePipeline |
7355 | \inmodule QtGui |
7356 | \since 6.6 |
7357 | \brief Compute pipeline state resource. |
7358 | |
7359 | \note Setting the shader resource bindings is mandatory. The referenced |
7360 | QRhiShaderResourceBindings must already have created() called on it by the |
7361 | time create() is called. |
7362 | |
7363 | \note Setting the shader is mandatory. |
7364 | |
7365 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
7366 | for details. |
7367 | */ |
7368 | |
7369 | /*! |
7370 | \enum QRhiComputePipeline::Flag |
7371 | |
7372 | Flag values for describing pipeline options. |
7373 | |
7374 | \value CompileShadersWithDebugInfo Requests compiling shaders with debug |
7375 | information enabled, when applicable. See |
7376 | QRhiGraphicsPipeline::CompileShadersWithDebugInfo for more information. |
7377 | */ |
7378 | |
7379 | /*! |
7380 | \return the resource type. |
7381 | */ |
7382 | QRhiResource::Type QRhiComputePipeline::resourceType() const |
7383 | { |
7384 | return ComputePipeline; |
7385 | } |
7386 | |
7387 | /*! |
7388 | \internal |
7389 | */ |
7390 | QRhiComputePipeline::QRhiComputePipeline(QRhiImplementation *rhi) |
7391 | : QRhiResource(rhi) |
7392 | { |
7393 | } |
7394 | |
7395 | /*! |
7396 | \fn QRhiComputePipeline::Flags QRhiComputePipeline::flags() const |
7397 | \return the currently set flags. |
7398 | */ |
7399 | |
7400 | /*! |
7401 | \fn void QRhiComputePipeline::setFlags(Flags f) |
7402 | Sets the flags \a f. |
7403 | */ |
7404 | |
7405 | /*! |
7406 | \fn QRhiShaderStage QRhiComputePipeline::shaderStage() const |
7407 | \return the currently set shader. |
7408 | */ |
7409 | |
7410 | /*! |
7411 | \fn void QRhiComputePipeline::setShaderStage(const QRhiShaderStage &stage) |
7412 | |
7413 | Sets the shader to use. \a stage can only refer to the |
7414 | \l{QRhiShaderStage::Compute}{compute stage}. |
7415 | */ |
7416 | |
7417 | /*! |
7418 | \fn QRhiShaderResourceBindings *QRhiComputePipeline::shaderResourceBindings() const |
7419 | \return the currently associated QRhiShaderResourceBindings object. |
7420 | */ |
7421 | |
7422 | /*! |
7423 | \fn void QRhiComputePipeline::setShaderResourceBindings(QRhiShaderResourceBindings *srb) |
7424 | |
7425 | Associates with \a srb describing the resource binding layout and the |
7426 | resources (QRhiBuffer, QRhiTexture) themselves. The latter is optional. As |
7427 | with graphics pipelines, the \a srb passed in here can leave the actual |
7428 | buffer or texture objects unspecified (\nullptr) as long as there is |
7429 | another, |
7430 | \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible} |
7431 | QRhiShaderResourceBindings bound via |
7432 | \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} before |
7433 | recording the dispatch call. |
7434 | */ |
7435 | |
7436 | /*! |
7437 | \class QRhiCommandBuffer |
7438 | \inmodule QtGui |
7439 | \since 6.6 |
7440 | \brief Command buffer resource. |
7441 | |
7442 | Not creatable by applications at the moment. The only ways to obtain a |
7443 | valid QRhiCommandBuffer are to get it from the targeted swapchain via |
7444 | QRhiSwapChain::currentFrameCommandBuffer(), or, in case of rendering |
7445 | completely offscreen, initializing one via QRhi::beginOffscreenFrame(). |
7446 | |
7447 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
7448 | for details. |
7449 | */ |
7450 | |
7451 | /*! |
7452 | \enum QRhiCommandBuffer::IndexFormat |
7453 | Specifies the index data type |
7454 | |
7455 | \value IndexUInt16 Unsigned 16-bit (quint16) |
7456 | \value IndexUInt32 Unsigned 32-bit (quint32) |
7457 | */ |
7458 | |
7459 | /*! |
7460 | \enum QRhiCommandBuffer::BeginPassFlag |
7461 | Flag values for QRhi::beginPass() |
7462 | |
7463 | \value ExternalContent Specifies that there will be a call to |
7464 | QRhiCommandBuffer::beginExternal() in this pass. Some backends, Vulkan in |
7465 | particular, will fail if this flag is not set and beginExternal() is still |
7466 | called. |
7467 | |
7468 | \value DoNotTrackResourcesForCompute Specifies that there is no need to |
7469 | track resources used in this pass if the only purpose of such tracking is |
7470 | to generate barriers for compute. Implies that there are no compute passes |
7471 | in the frame. This is an optimization hint that may be taken into account |
7472 | by certain backends, OpenGL in particular, allowing them to skip certain |
7473 | operations. When this flag is set for a render pass in a frame, calling |
7474 | \l{QRhiCommandBuffer::beginComputePass()}{beginComputePass()} in that frame |
7475 | may lead to unexpected behavior, depending on the resource dependencies |
7476 | between the render and compute passes. |
7477 | */ |
7478 | |
7479 | /*! |
7480 | \typedef QRhiCommandBuffer::DynamicOffset |
7481 | |
7482 | Synonym for QPair<int, quint32>. The first entry is the binding, the second |
7483 | is the offset in the buffer. |
7484 | */ |
7485 | |
7486 | /*! |
7487 | \typedef QRhiCommandBuffer::VertexInput |
7488 | |
7489 | Synonym for QPair<QRhiBuffer *, quint32>. The second entry is an offset in |
7490 | the buffer specified by the first. |
7491 | */ |
7492 | |
7493 | /*! |
7494 | \internal |
7495 | */ |
7496 | QRhiCommandBuffer::QRhiCommandBuffer(QRhiImplementation *rhi) |
7497 | : QRhiResource(rhi) |
7498 | { |
7499 | } |
7500 | |
7501 | /*! |
7502 | \return the resource type. |
7503 | */ |
7504 | QRhiResource::Type QRhiCommandBuffer::resourceType() const |
7505 | { |
7506 | return CommandBuffer; |
7507 | } |
7508 | |
7509 | static const char *resourceTypeStr(const QRhiResource *res) |
7510 | { |
7511 | switch (res->resourceType()) { |
7512 | case QRhiResource::Buffer: |
7513 | return "Buffer" ; |
7514 | case QRhiResource::Texture: |
7515 | return "Texture" ; |
7516 | case QRhiResource::Sampler: |
7517 | return "Sampler" ; |
7518 | case QRhiResource::RenderBuffer: |
7519 | return "RenderBuffer" ; |
7520 | case QRhiResource::RenderPassDescriptor: |
7521 | return "RenderPassDescriptor" ; |
7522 | case QRhiResource::SwapChainRenderTarget: |
7523 | return "SwapChainRenderTarget" ; |
7524 | case QRhiResource::TextureRenderTarget: |
7525 | return "TextureRenderTarget" ; |
7526 | case QRhiResource::ShaderResourceBindings: |
7527 | return "ShaderResourceBindings" ; |
7528 | case QRhiResource::GraphicsPipeline: |
7529 | return "GraphicsPipeline" ; |
7530 | case QRhiResource::SwapChain: |
7531 | return "SwapChain" ; |
7532 | case QRhiResource::ComputePipeline: |
7533 | return "ComputePipeline" ; |
7534 | case QRhiResource::CommandBuffer: |
7535 | return "CommandBuffer" ; |
7536 | } |
7537 | |
7538 | Q_UNREACHABLE_RETURN("" ); |
7539 | } |
7540 | |
7541 | QRhiImplementation::~QRhiImplementation() |
7542 | { |
7543 | qDeleteAll(c: resUpdPool); |
7544 | |
7545 | // Be nice and show something about leaked stuff. Though we may not get |
7546 | // this far with some backends where the allocator or the api may check |
7547 | // and freak out for unfreed graphics objects in the derived dtor already. |
7548 | #ifndef QT_NO_DEBUG |
7549 | // debug builds: just do it always |
7550 | static bool leakCheck = true; |
7551 | #else |
7552 | // release builds: opt-in |
7553 | static bool leakCheck = qEnvironmentVariableIntValue("QT_RHI_LEAK_CHECK" ); |
7554 | #endif |
7555 | if (!resources.isEmpty()) { |
7556 | if (leakCheck) { |
7557 | qWarning(msg: "QRhi %p going down with %d unreleased resources that own native graphics objects. This is not nice." , |
7558 | q, int(resources.size())); |
7559 | } |
7560 | for (auto it = resources.cbegin(), end = resources.cend(); it != end; ++it) { |
7561 | QRhiResource *res = it.key(); |
7562 | const bool ownsNativeResources = it.value(); |
7563 | if (leakCheck && ownsNativeResources) |
7564 | qWarning(msg: " %s resource %p (%s)" , resourceTypeStr(res), res, res->m_objectName.constData()); |
7565 | |
7566 | // Null out the resource's rhi pointer. This is why it makes sense to do null |
7567 | // checks in the destroy() implementations of the various resource types. It |
7568 | // allows to survive in bad applications that somehow manage to destroy a |
7569 | // resource of a QRhi after the QRhi itself. |
7570 | res->m_rhi = nullptr; |
7571 | } |
7572 | } |
7573 | } |
7574 | |
7575 | bool QRhiImplementation::isCompressedFormat(QRhiTexture::Format format) const |
7576 | { |
7577 | return (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) |
7578 | || (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) |
7579 | || (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12); |
7580 | } |
7581 | |
7582 | void QRhiImplementation::compressedFormatInfo(QRhiTexture::Format format, const QSize &size, |
7583 | quint32 *bpl, quint32 *byteSize, |
7584 | QSize *blockDim) const |
7585 | { |
7586 | int xdim = 4; |
7587 | int ydim = 4; |
7588 | quint32 blockSize = 0; |
7589 | |
7590 | switch (format) { |
7591 | case QRhiTexture::BC1: |
7592 | blockSize = 8; |
7593 | break; |
7594 | case QRhiTexture::BC2: |
7595 | blockSize = 16; |
7596 | break; |
7597 | case QRhiTexture::BC3: |
7598 | blockSize = 16; |
7599 | break; |
7600 | case QRhiTexture::BC4: |
7601 | blockSize = 8; |
7602 | break; |
7603 | case QRhiTexture::BC5: |
7604 | blockSize = 16; |
7605 | break; |
7606 | case QRhiTexture::BC6H: |
7607 | blockSize = 16; |
7608 | break; |
7609 | case QRhiTexture::BC7: |
7610 | blockSize = 16; |
7611 | break; |
7612 | |
7613 | case QRhiTexture::ETC2_RGB8: |
7614 | blockSize = 8; |
7615 | break; |
7616 | case QRhiTexture::ETC2_RGB8A1: |
7617 | blockSize = 8; |
7618 | break; |
7619 | case QRhiTexture::ETC2_RGBA8: |
7620 | blockSize = 16; |
7621 | break; |
7622 | |
7623 | case QRhiTexture::ASTC_4x4: |
7624 | blockSize = 16; |
7625 | break; |
7626 | case QRhiTexture::ASTC_5x4: |
7627 | blockSize = 16; |
7628 | xdim = 5; |
7629 | break; |
7630 | case QRhiTexture::ASTC_5x5: |
7631 | blockSize = 16; |
7632 | xdim = ydim = 5; |
7633 | break; |
7634 | case QRhiTexture::ASTC_6x5: |
7635 | blockSize = 16; |
7636 | xdim = 6; |
7637 | ydim = 5; |
7638 | break; |
7639 | case QRhiTexture::ASTC_6x6: |
7640 | blockSize = 16; |
7641 | xdim = ydim = 6; |
7642 | break; |
7643 | case QRhiTexture::ASTC_8x5: |
7644 | blockSize = 16; |
7645 | xdim = 8; |
7646 | ydim = 5; |
7647 | break; |
7648 | case QRhiTexture::ASTC_8x6: |
7649 | blockSize = 16; |
7650 | xdim = 8; |
7651 | ydim = 6; |
7652 | break; |
7653 | case QRhiTexture::ASTC_8x8: |
7654 | blockSize = 16; |
7655 | xdim = ydim = 8; |
7656 | break; |
7657 | case QRhiTexture::ASTC_10x5: |
7658 | blockSize = 16; |
7659 | xdim = 10; |
7660 | ydim = 5; |
7661 | break; |
7662 | case QRhiTexture::ASTC_10x6: |
7663 | blockSize = 16; |
7664 | xdim = 10; |
7665 | ydim = 6; |
7666 | break; |
7667 | case QRhiTexture::ASTC_10x8: |
7668 | blockSize = 16; |
7669 | xdim = 10; |
7670 | ydim = 8; |
7671 | break; |
7672 | case QRhiTexture::ASTC_10x10: |
7673 | blockSize = 16; |
7674 | xdim = ydim = 10; |
7675 | break; |
7676 | case QRhiTexture::ASTC_12x10: |
7677 | blockSize = 16; |
7678 | xdim = 12; |
7679 | ydim = 10; |
7680 | break; |
7681 | case QRhiTexture::ASTC_12x12: |
7682 | blockSize = 16; |
7683 | xdim = ydim = 12; |
7684 | break; |
7685 | |
7686 | default: |
7687 | Q_UNREACHABLE(); |
7688 | break; |
7689 | } |
7690 | |
7691 | const quint32 wblocks = uint((size.width() + xdim - 1) / xdim); |
7692 | const quint32 hblocks = uint((size.height() + ydim - 1) / ydim); |
7693 | |
7694 | if (bpl) |
7695 | *bpl = wblocks * blockSize; |
7696 | if (byteSize) |
7697 | *byteSize = wblocks * hblocks * blockSize; |
7698 | if (blockDim) |
7699 | *blockDim = QSize(xdim, ydim); |
7700 | } |
7701 | |
7702 | void QRhiImplementation::textureFormatInfo(QRhiTexture::Format format, const QSize &size, |
7703 | quint32 *bpl, quint32 *byteSize, quint32 *bytesPerPixel) const |
7704 | { |
7705 | if (isCompressedFormat(format)) { |
7706 | compressedFormatInfo(format, size, bpl, byteSize, blockDim: nullptr); |
7707 | return; |
7708 | } |
7709 | |
7710 | quint32 bpc = 0; |
7711 | switch (format) { |
7712 | case QRhiTexture::RGBA8: |
7713 | bpc = 4; |
7714 | break; |
7715 | case QRhiTexture::BGRA8: |
7716 | bpc = 4; |
7717 | break; |
7718 | case QRhiTexture::R8: |
7719 | bpc = 1; |
7720 | break; |
7721 | case QRhiTexture::RG8: |
7722 | bpc = 2; |
7723 | break; |
7724 | case QRhiTexture::R16: |
7725 | bpc = 2; |
7726 | break; |
7727 | case QRhiTexture::RG16: |
7728 | bpc = 4; |
7729 | break; |
7730 | case QRhiTexture::RED_OR_ALPHA8: |
7731 | bpc = 1; |
7732 | break; |
7733 | |
7734 | case QRhiTexture::RGBA16F: |
7735 | bpc = 8; |
7736 | break; |
7737 | case QRhiTexture::RGBA32F: |
7738 | bpc = 16; |
7739 | break; |
7740 | case QRhiTexture::R16F: |
7741 | bpc = 2; |
7742 | break; |
7743 | case QRhiTexture::R32F: |
7744 | bpc = 4; |
7745 | break; |
7746 | |
7747 | case QRhiTexture::RGB10A2: |
7748 | bpc = 4; |
7749 | break; |
7750 | |
7751 | case QRhiTexture::D16: |
7752 | bpc = 2; |
7753 | break; |
7754 | case QRhiTexture::D24: |
7755 | case QRhiTexture::D24S8: |
7756 | case QRhiTexture::D32F: |
7757 | bpc = 4; |
7758 | break; |
7759 | |
7760 | default: |
7761 | Q_UNREACHABLE(); |
7762 | break; |
7763 | } |
7764 | |
7765 | if (bpl) |
7766 | *bpl = uint(size.width()) * bpc; |
7767 | if (byteSize) |
7768 | *byteSize = uint(size.width() * size.height()) * bpc; |
7769 | if (bytesPerPixel) |
7770 | *bytesPerPixel = bpc; |
7771 | } |
7772 | |
7773 | bool QRhiImplementation::sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps) |
7774 | { |
7775 | if (ps->cbeginShaderStages() == ps->cendShaderStages()) { |
7776 | qWarning(msg: "Cannot build a graphics pipeline without any stages" ); |
7777 | return false; |
7778 | } |
7779 | |
7780 | bool hasVertexStage = false; |
7781 | for (auto it = ps->cbeginShaderStages(), itEnd = ps->cendShaderStages(); it != itEnd; ++it) { |
7782 | if (!it->shader().isValid()) { |
7783 | qWarning(msg: "Empty shader passed to graphics pipeline" ); |
7784 | return false; |
7785 | } |
7786 | if (it->type() == QRhiShaderStage::Vertex) |
7787 | hasVertexStage = true; |
7788 | } |
7789 | if (!hasVertexStage) { |
7790 | qWarning(msg: "Cannot build a graphics pipeline without a vertex stage" ); |
7791 | return false; |
7792 | } |
7793 | |
7794 | if (!ps->renderPassDescriptor()) { |
7795 | qWarning(msg: "Cannot build a graphics pipeline without a QRhiRenderPassDescriptor" ); |
7796 | return false; |
7797 | } |
7798 | |
7799 | if (!ps->shaderResourceBindings()) { |
7800 | qWarning(msg: "Cannot build a graphics pipeline without QRhiShaderResourceBindings" ); |
7801 | return false; |
7802 | } |
7803 | |
7804 | return true; |
7805 | } |
7806 | |
7807 | bool QRhiImplementation::sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb) |
7808 | { |
7809 | #ifndef QT_NO_DEBUG |
7810 | bool bindingsOk = true; |
7811 | const int CHECKED_BINDINGS_COUNT = 64; |
7812 | bool bindingSeen[CHECKED_BINDINGS_COUNT] = {}; |
7813 | for (auto it = srb->cbeginBindings(), end = srb->cendBindings(); it != end; ++it) { |
7814 | const int binding = shaderResourceBindingData(binding: *it)->binding; |
7815 | if (binding >= CHECKED_BINDINGS_COUNT) |
7816 | continue; |
7817 | if (binding < 0) { |
7818 | qWarning(msg: "Invalid binding number %d" , binding); |
7819 | bindingsOk = false; |
7820 | continue; |
7821 | } |
7822 | switch (shaderResourceBindingData(binding: *it)->type) { |
7823 | case QRhiShaderResourceBinding::UniformBuffer: |
7824 | if (!bindingSeen[binding]) { |
7825 | bindingSeen[binding] = true; |
7826 | } else { |
7827 | qWarning(msg: "Uniform buffer duplicates an existing binding number %d" , binding); |
7828 | bindingsOk = false; |
7829 | } |
7830 | break; |
7831 | case QRhiShaderResourceBinding::SampledTexture: |
7832 | if (!bindingSeen[binding]) { |
7833 | bindingSeen[binding] = true; |
7834 | } else { |
7835 | qWarning(msg: "Combined image sampler duplicates an existing binding number %d" , binding); |
7836 | bindingsOk = false; |
7837 | } |
7838 | break; |
7839 | case QRhiShaderResourceBinding::Texture: |
7840 | if (!bindingSeen[binding]) { |
7841 | bindingSeen[binding] = true; |
7842 | } else { |
7843 | qWarning(msg: "Texture duplicates an existing binding number %d" , binding); |
7844 | bindingsOk = false; |
7845 | } |
7846 | break; |
7847 | case QRhiShaderResourceBinding::Sampler: |
7848 | if (!bindingSeen[binding]) { |
7849 | bindingSeen[binding] = true; |
7850 | } else { |
7851 | qWarning(msg: "Sampler duplicates an existing binding number %d" , binding); |
7852 | bindingsOk = false; |
7853 | } |
7854 | break; |
7855 | case QRhiShaderResourceBinding::ImageLoad: |
7856 | case QRhiShaderResourceBinding::ImageStore: |
7857 | case QRhiShaderResourceBinding::ImageLoadStore: |
7858 | if (!bindingSeen[binding]) { |
7859 | bindingSeen[binding] = true; |
7860 | } else { |
7861 | qWarning(msg: "Image duplicates an existing binding number %d" , binding); |
7862 | bindingsOk = false; |
7863 | } |
7864 | break; |
7865 | case QRhiShaderResourceBinding::BufferLoad: |
7866 | case QRhiShaderResourceBinding::BufferStore: |
7867 | case QRhiShaderResourceBinding::BufferLoadStore: |
7868 | if (!bindingSeen[binding]) { |
7869 | bindingSeen[binding] = true; |
7870 | } else { |
7871 | qWarning(msg: "Buffer duplicates an existing binding number %d" , binding); |
7872 | bindingsOk = false; |
7873 | } |
7874 | break; |
7875 | default: |
7876 | qWarning(msg: "Unknown binding type %d" , int(shaderResourceBindingData(binding: *it)->type)); |
7877 | bindingsOk = false; |
7878 | break; |
7879 | } |
7880 | } |
7881 | |
7882 | if (!bindingsOk) { |
7883 | qWarning() << *srb; |
7884 | return false; |
7885 | } |
7886 | #else |
7887 | Q_UNUSED(srb); |
7888 | #endif |
7889 | return true; |
7890 | } |
7891 | |
7892 | /*! |
7893 | \internal |
7894 | */ |
7895 | QRhi::QRhi() |
7896 | { |
7897 | } |
7898 | |
7899 | /*! |
7900 | Destructor. Destroys the backend and releases resources. |
7901 | */ |
7902 | QRhi::~QRhi() |
7903 | { |
7904 | if (!d) |
7905 | return; |
7906 | |
7907 | runCleanup(); |
7908 | |
7909 | qDeleteAll(c: d->pendingDeleteResources); |
7910 | d->pendingDeleteResources.clear(); |
7911 | |
7912 | d->destroy(); |
7913 | delete d; |
7914 | } |
7915 | |
7916 | void QRhiImplementation::prepareForCreate(QRhi *rhi, QRhi::Implementation impl, QRhi::Flags flags) |
7917 | { |
7918 | q = rhi; |
7919 | |
7920 | // Play nice with QSG_INFO since that is still the most commonly used |
7921 | // way to get graphics info printed from Qt Quick apps, and the Quick |
7922 | // scenegraph is our primary user. |
7923 | if (qEnvironmentVariableIsSet(varName: "QSG_INFO" )) |
7924 | const_cast<QLoggingCategory &>(QRHI_LOG_INFO()).setEnabled(type: QtDebugMsg, enable: true); |
7925 | |
7926 | debugMarkers = flags.testFlag(flag: QRhi::EnableDebugMarkers); |
7927 | |
7928 | implType = impl; |
7929 | implThread = QThread::currentThread(); |
7930 | } |
7931 | |
7932 | /*! |
7933 | \return a new QRhi instance with a backend for the graphics API specified |
7934 | by \a impl with the specified \a flags. |
7935 | |
7936 | \a params must point to an instance of one of the backend-specific |
7937 | subclasses of QRhiInitParams, such as, QRhiVulkanInitParams, |
7938 | QRhiMetalInitParams, QRhiD3D11InitParams, QRhiD3D12InitParams, |
7939 | QRhiGles2InitParams. See these classes for examples on creating a QRhi. |
7940 | |
7941 | QRhi by design does not implement any fallback logic: if the specified API |
7942 | cannot be initialized, create() will fail, with warnings printed on the |
7943 | debug output by the backends. The clients of QRhi, for example Qt Quick, |
7944 | may however provide additional logic that allow falling back to an API |
7945 | different than what was requested, depending on the platform. If the |
7946 | intention is just to test if initialization would succeed when calling |
7947 | create() at later point, it is preferable to use probe() instead of |
7948 | create(), because with some backends probing can be implemented in a more |
7949 | lightweight manner as opposed to create(), which performs full |
7950 | initialization of the infrastructure and is wasteful if that QRhi instance |
7951 | is then thrown immediately away. |
7952 | |
7953 | \a importDevice allows using an already existing graphics device, without |
7954 | QRhi creating its own. When not null, this parameter must point to an |
7955 | instance of one of the subclasses of QRhiNativeHandles: |
7956 | QRhiVulkanNativeHandles, QRhiD3D11NativeHandles, QRhiD3D12NativeHandles, |
7957 | QRhiMetalNativeHandles, QRhiGles2NativeHandles. The exact details and |
7958 | semantics depend on the backand and the underlying graphics API. |
7959 | |
7960 | \sa probe() |
7961 | */ |
7962 | QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRhiNativeHandles *importDevice) |
7963 | { |
7964 | std::unique_ptr<QRhi> r(new QRhi); |
7965 | |
7966 | switch (impl) { |
7967 | case Null: |
7968 | r->d = new QRhiNull(static_cast<QRhiNullInitParams *>(params)); |
7969 | break; |
7970 | case Vulkan: |
7971 | #if QT_CONFIG(vulkan) |
7972 | r->d = new QRhiVulkan(static_cast<QRhiVulkanInitParams *>(params), |
7973 | static_cast<QRhiVulkanNativeHandles *>(importDevice)); |
7974 | break; |
7975 | #else |
7976 | Q_UNUSED(importDevice); |
7977 | qWarning("This build of Qt has no Vulkan support" ); |
7978 | break; |
7979 | #endif |
7980 | case OpenGLES2: |
7981 | #ifndef QT_NO_OPENGL |
7982 | r->d = new QRhiGles2(static_cast<QRhiGles2InitParams *>(params), |
7983 | static_cast<QRhiGles2NativeHandles *>(importDevice)); |
7984 | break; |
7985 | #else |
7986 | qWarning("This build of Qt has no OpenGL support" ); |
7987 | break; |
7988 | #endif |
7989 | case D3D11: |
7990 | #ifdef Q_OS_WIN |
7991 | r->d = new QRhiD3D11(static_cast<QRhiD3D11InitParams *>(params), |
7992 | static_cast<QRhiD3D11NativeHandles *>(importDevice)); |
7993 | break; |
7994 | #else |
7995 | qWarning(msg: "This platform has no Direct3D 11 support" ); |
7996 | break; |
7997 | #endif |
7998 | case Metal: |
7999 | #if defined(Q_OS_MACOS) || defined(Q_OS_IOS) |
8000 | r->d = new QRhiMetal(static_cast<QRhiMetalInitParams *>(params), |
8001 | static_cast<QRhiMetalNativeHandles *>(importDevice)); |
8002 | break; |
8003 | #else |
8004 | qWarning(msg: "This platform has no Metal support" ); |
8005 | break; |
8006 | #endif |
8007 | case D3D12: |
8008 | #ifdef Q_OS_WIN |
8009 | r->d = new QRhiD3D12(static_cast<QRhiD3D12InitParams *>(params), |
8010 | static_cast<QRhiD3D12NativeHandles *>(importDevice)); |
8011 | break; |
8012 | #else |
8013 | qWarning(msg: "This platform has no Direct3D 12 support" ); |
8014 | break; |
8015 | #endif |
8016 | } |
8017 | |
8018 | if (r->d) { |
8019 | r->d->prepareForCreate(rhi: r.get(), impl, flags); |
8020 | if (r->d->create(flags)) |
8021 | return r.release(); |
8022 | } |
8023 | |
8024 | return nullptr; |
8025 | } |
8026 | |
8027 | /*! |
8028 | \return true if create() can be expected to succeed when called the given |
8029 | \a impl and \a params. |
8030 | |
8031 | For some backends this is equivalent to calling create(), checking its |
8032 | return value, and then destroying the resulting QRhi. |
8033 | |
8034 | For others, in particular with Metal, there may be a specific probing |
8035 | implementation, which allows testing in a more lightweight manner without |
8036 | polluting the debug output with warnings upon failures. |
8037 | |
8038 | \sa create() |
8039 | */ |
8040 | bool QRhi::probe(QRhi::Implementation impl, QRhiInitParams *params) |
8041 | { |
8042 | bool ok = false; |
8043 | |
8044 | // The only place currently where this makes sense is Metal, where the API |
8045 | // is simple enough so that a special probing function - doing nothing but |
8046 | // a MTLCreateSystemDefaultDevice - is reasonable. Elsewhere, just call |
8047 | // create() and then drop the result. |
8048 | |
8049 | if (impl == Metal) { |
8050 | #if defined(Q_OS_MACOS) || defined(Q_OS_IOS) |
8051 | ok = QRhiMetal::probe(static_cast<QRhiMetalInitParams *>(params)); |
8052 | #endif |
8053 | } else { |
8054 | QRhi *rhi = create(impl, params); |
8055 | ok = rhi != nullptr; |
8056 | delete rhi; |
8057 | } |
8058 | return ok; |
8059 | } |
8060 | |
8061 | /*! |
8062 | \struct QRhiSwapChainProxyData |
8063 | \inmodule QtGui |
8064 | \since 6.6 |
8065 | |
8066 | \brief Opaque data describing native objects needed to set up a swapchain. |
8067 | |
8068 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
8069 | for details. |
8070 | |
8071 | \sa QRhi::updateSwapChainProxyData() |
8072 | */ |
8073 | |
8074 | /*! |
8075 | Generates and returns a QRhiSwapChainProxyData struct containing opaque |
8076 | data specific to the backend and graphics API specified by \a impl. \a |
8077 | window is the QWindow a swapchain is targeting. |
8078 | |
8079 | The returned struct can be passed to QRhiSwapChain::setProxyData(). This |
8080 | makes sense in threaded rendering systems: this static function is expected |
8081 | to be called on the \b{main (gui) thread}, unlike all QRhi operations, then |
8082 | transferred to the thread working with the QRhi and QRhiSwapChain and passed |
8083 | on to the swapchain. This allows doing native platform queries that are |
8084 | only safe to be called on the main thread, for example to query the |
8085 | CAMetalLayer from a NSView, and then passing on the data to the |
8086 | QRhiSwapChain living on the rendering thread. With the Metal example, doing |
8087 | the view.layer access on a dedicated rendering thread causes a warning in |
8088 | the Xcode Thread Checker. With the data proxy mechanism, this is avoided. |
8089 | |
8090 | When threads are not involved, generating and passing on the |
8091 | QRhiSwapChainProxyData is not required: backends are guaranteed to be able |
8092 | to query whatever is needed on their own, and if everything lives on the |
8093 | main (gui) thread, that should be sufficient. |
8094 | |
8095 | \note \a impl should match what the QRhi is created with. For example, |
8096 | calling with QRhi::Metal on a non-Apple platform will not generate any |
8097 | useful data. |
8098 | */ |
8099 | QRhiSwapChainProxyData QRhi::updateSwapChainProxyData(QRhi::Implementation impl, QWindow *window) |
8100 | { |
8101 | #if defined(Q_OS_MACOS) || defined(Q_OS_IOS) |
8102 | if (impl == Metal) |
8103 | return QRhiMetal::updateSwapChainProxyData(window); |
8104 | #else |
8105 | Q_UNUSED(impl); |
8106 | Q_UNUSED(window); |
8107 | #endif |
8108 | return {}; |
8109 | } |
8110 | |
8111 | /*! |
8112 | \return the backend type for this QRhi. |
8113 | */ |
8114 | QRhi::Implementation QRhi::backend() const |
8115 | { |
8116 | return d->implType; |
8117 | } |
8118 | |
8119 | /*! |
8120 | \return a friendly name for the backend \a impl, usually the name of the 3D |
8121 | API in use. |
8122 | */ |
8123 | const char *QRhi::backendName(Implementation impl) |
8124 | { |
8125 | switch (impl) { |
8126 | case QRhi::Null: |
8127 | return "Null" ; |
8128 | case QRhi::Vulkan: |
8129 | return "Vulkan" ; |
8130 | case QRhi::OpenGLES2: |
8131 | return "OpenGL" ; |
8132 | case QRhi::D3D11: |
8133 | return "D3D11" ; |
8134 | case QRhi::Metal: |
8135 | return "Metal" ; |
8136 | case QRhi::D3D12: |
8137 | return "D3D12" ; |
8138 | } |
8139 | |
8140 | Q_UNREACHABLE_RETURN("Unknown" ); |
8141 | } |
8142 | |
8143 | /*! |
8144 | \return the backend type as string for this QRhi. |
8145 | */ |
8146 | const char *QRhi::backendName() const |
8147 | { |
8148 | return backendName(impl: d->implType); |
8149 | } |
8150 | |
8151 | /*! |
8152 | \enum QRhiDriverInfo::DeviceType |
8153 | Specifies the graphics device's type, when the information is available. In |
8154 | practice this is only applicable with Vulkan and Metal. With others the |
8155 | value will always be UnknownDevice. |
8156 | |
8157 | \value UnknownDevice |
8158 | \value IntegratedDevice |
8159 | \value DiscreteDevice |
8160 | \value ExternalDevice |
8161 | \value VirtualDevice |
8162 | \value CpuDevice |
8163 | */ |
8164 | |
8165 | /*! |
8166 | \struct QRhiDriverInfo |
8167 | \inmodule QtGui |
8168 | \since 6.6 |
8169 | |
8170 | \brief Describes the physical device, adapter, or graphics API |
8171 | implementation that is used by an initialized QRhi. |
8172 | |
8173 | Graphics APIs offer different levels and kinds of information. The only |
8174 | value that is available across all APIs is the deviceName, which is a |
8175 | freetext description of the physical device, adapter, or is a combination |
8176 | of the strings reported for \c{GL_VENDOR} + \c{GL_RENDERER} + |
8177 | \c{GL_VERSION}. The deviceId is always 0 for OpenGL. vendorId is always 0 |
8178 | for OpenGL and Metal. deviceType is always UnknownDevice for OpenGL and |
8179 | Direct 3D. |
8180 | |
8181 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
8182 | for details. |
8183 | */ |
8184 | |
8185 | /*! |
8186 | \variable QRhiDriverInfo::deviceName |
8187 | |
8188 | \sa QRhi::driverInfo() |
8189 | */ |
8190 | |
8191 | /*! |
8192 | \variable QRhiDriverInfo::deviceId |
8193 | |
8194 | \sa QRhi::driverInfo() |
8195 | */ |
8196 | |
8197 | /*! |
8198 | \variable QRhiDriverInfo::vendorId |
8199 | |
8200 | \sa QRhi::driverInfo() |
8201 | */ |
8202 | |
8203 | /*! |
8204 | \variable QRhiDriverInfo::deviceType |
8205 | |
8206 | \sa QRhi::driverInfo(), QRhiDriverInfo::DeviceType |
8207 | */ |
8208 | |
8209 | #ifndef QT_NO_DEBUG_STREAM |
8210 | static inline const char *deviceTypeStr(QRhiDriverInfo::DeviceType type) |
8211 | { |
8212 | switch (type) { |
8213 | case QRhiDriverInfo::UnknownDevice: |
8214 | return "Unknown" ; |
8215 | case QRhiDriverInfo::IntegratedDevice: |
8216 | return "Integrated" ; |
8217 | case QRhiDriverInfo::DiscreteDevice: |
8218 | return "Discrete" ; |
8219 | case QRhiDriverInfo::ExternalDevice: |
8220 | return "External" ; |
8221 | case QRhiDriverInfo::VirtualDevice: |
8222 | return "Virtual" ; |
8223 | case QRhiDriverInfo::CpuDevice: |
8224 | return "Cpu" ; |
8225 | } |
8226 | |
8227 | Q_UNREACHABLE_RETURN(nullptr); |
8228 | } |
8229 | QDebug operator<<(QDebug dbg, const QRhiDriverInfo &info) |
8230 | { |
8231 | QDebugStateSaver saver(dbg); |
8232 | dbg.nospace() << "QRhiDriverInfo(deviceName=" << info.deviceName |
8233 | << " deviceId=0x" << Qt::hex << info.deviceId |
8234 | << " vendorId=0x" << info.vendorId |
8235 | << " deviceType=" << deviceTypeStr(type: info.deviceType) |
8236 | << ')'; |
8237 | return dbg; |
8238 | } |
8239 | #endif |
8240 | |
8241 | /*! |
8242 | \return metadata for the graphics device used by this successfully |
8243 | initialized QRhi instance. |
8244 | */ |
8245 | QRhiDriverInfo QRhi::driverInfo() const |
8246 | { |
8247 | return d->driverInfo(); |
8248 | } |
8249 | |
8250 | /*! |
8251 | \return the thread on which the QRhi was \l{QRhi::create()}{initialized}. |
8252 | */ |
8253 | QThread *QRhi::thread() const |
8254 | { |
8255 | return d->implThread; |
8256 | } |
8257 | |
8258 | /*! |
8259 | Registers a \a callback that is invoked either when the QRhi is destroyed, |
8260 | or when runCleanup() is called. |
8261 | |
8262 | The callback will run with the graphics resource still available, so this |
8263 | provides an opportunity for the application to cleanly release QRhiResource |
8264 | instances belonging to the QRhi. This is particularly useful for managing |
8265 | the lifetime of resources stored in \c cache type of objects, where the |
8266 | cache holds QRhiResources or objects containing QRhiResources. |
8267 | |
8268 | \sa runCleanup(), ~QRhi() |
8269 | */ |
8270 | void QRhi::addCleanupCallback(const CleanupCallback &callback) |
8271 | { |
8272 | d->addCleanupCallback(callback); |
8273 | } |
8274 | |
8275 | /*! |
8276 | Invokes all registered cleanup functions. The list of cleanup callbacks it |
8277 | then cleared. Normally destroying the QRhi does this automatically, but |
8278 | sometimes it can be useful to trigger cleanup in order to release all |
8279 | cached, non-essential resources. |
8280 | |
8281 | \sa addCleanupCallback() |
8282 | */ |
8283 | void QRhi::runCleanup() |
8284 | { |
8285 | for (const CleanupCallback &f : std::as_const(t&: d->cleanupCallbacks)) |
8286 | f(this); |
8287 | |
8288 | d->cleanupCallbacks.clear(); |
8289 | } |
8290 | |
8291 | /*! |
8292 | \class QRhiResourceUpdateBatch |
8293 | \inmodule QtGui |
8294 | \since 6.6 |
8295 | \brief Records upload and copy type of operations. |
8296 | |
8297 | With QRhi it is no longer possible to perform copy type of operations at |
8298 | arbitrary times. Instead, all such operations are recorded into batches |
8299 | that are then passed, most commonly, to QRhiCommandBuffer::beginPass(). |
8300 | What then happens under the hood is hidden from the application: the |
8301 | underlying implementations can defer and implement these operations in |
8302 | various different ways. |
8303 | |
8304 | A resource update batch owns no graphics resources and does not perform any |
8305 | actual operations on its own. It should rather be viewed as a command |
8306 | buffer for update, upload, and copy type of commands. |
8307 | |
8308 | To get an available, empty batch from the pool, call |
8309 | QRhi::nextResourceUpdateBatch(). |
8310 | |
8311 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
8312 | for details. |
8313 | */ |
8314 | |
8315 | /*! |
8316 | \internal |
8317 | */ |
8318 | QRhiResourceUpdateBatch::QRhiResourceUpdateBatch(QRhiImplementation *rhi) |
8319 | : d(new QRhiResourceUpdateBatchPrivate) |
8320 | { |
8321 | d->q = this; |
8322 | d->rhi = rhi; |
8323 | } |
8324 | |
8325 | QRhiResourceUpdateBatch::~QRhiResourceUpdateBatch() |
8326 | { |
8327 | delete d; |
8328 | } |
8329 | |
8330 | /*! |
8331 | \return the batch to the pool. This should only be used when the batch is |
8332 | not passed to one of QRhiCommandBuffer::beginPass(), |
8333 | QRhiCommandBuffer::endPass(), or QRhiCommandBuffer::resourceUpdate() |
8334 | because these implicitly call destroy(). |
8335 | |
8336 | \note QRhiResourceUpdateBatch instances must never by \c deleted by |
8337 | applications. |
8338 | */ |
8339 | void QRhiResourceUpdateBatch::release() |
8340 | { |
8341 | d->free(); |
8342 | } |
8343 | |
8344 | /*! |
8345 | Copies all queued operations from the \a other batch into this one. |
8346 | |
8347 | \note \a other may no longer contain valid data after the merge operation, |
8348 | and must not be submitted, but it will still need to be released by calling |
8349 | release(). |
8350 | |
8351 | This allows for a convenient pattern where resource updates that are |
8352 | already known during the initialization step are collected into a batch |
8353 | that is then merged into another when starting to first render pass later |
8354 | on: |
8355 | |
8356 | \code |
8357 | void init() |
8358 | { |
8359 | initialUpdates = rhi->nextResourceUpdateBatch(); |
8360 | initialUpdates->uploadStaticBuffer(vbuf, vertexData); |
8361 | initialUpdates->uploadStaticBuffer(ibuf, indexData); |
8362 | // ... |
8363 | } |
8364 | |
8365 | void render() |
8366 | { |
8367 | QRhiResourceUpdateBatch *resUpdates = rhi->nextResourceUpdateBatch(); |
8368 | if (initialUpdates) { |
8369 | resUpdates->merge(initialUpdates); |
8370 | initialUpdates->release(); |
8371 | initialUpdates = nullptr; |
8372 | } |
8373 | // resUpdates->updateDynamicBuffer(...); |
8374 | cb->beginPass(rt, clearCol, clearDs, resUpdates); |
8375 | } |
8376 | \endcode |
8377 | */ |
8378 | void QRhiResourceUpdateBatch::merge(QRhiResourceUpdateBatch *other) |
8379 | { |
8380 | d->merge(other: other->d); |
8381 | } |
8382 | |
8383 | /*! |
8384 | \return true until the number of buffer and texture operations enqueued |
8385 | onto this batch is below a reasonable limit. |
8386 | |
8387 | The return value is false when the number of buffer and/or texture |
8388 | operations added to this batch have reached, or are about to reach, a |
8389 | certain limit. The batch is fully functional afterwards as well, but may |
8390 | need to allocate additional memory. Therefore, a renderer that collects |
8391 | lots of buffer and texture updates in a single batch when preparing a frame |
8392 | may want to consider \l{QRhiCommandBuffer::resourceUpdate()}{submitting the |
8393 | batch} and \l{QRhi::nextResourceUpdateBatch()}{starting a new one} when |
8394 | this function returns false. |
8395 | */ |
8396 | bool QRhiResourceUpdateBatch::hasOptimalCapacity() const |
8397 | { |
8398 | return d->hasOptimalCapacity(); |
8399 | } |
8400 | |
8401 | /*! |
8402 | Enqueues updating a region of a QRhiBuffer \a buf created with the type |
8403 | QRhiBuffer::Dynamic. |
8404 | |
8405 | The region is specified \a offset and \a size. The actual bytes to write |
8406 | are specified by \a data which must have at least \a size bytes available. |
8407 | \a data can safely be destroyed or changed once this function returns. |
8408 | |
8409 | \note If host writes are involved, which is the case with |
8410 | updateDynamicBuffer() typically as such buffers are backed by host visible |
8411 | memory with most backends, they may accumulate within a frame. Thus pass 1 |
8412 | reading a region changed by a batch passed to pass 2 may see the changes |
8413 | specified in pass 2's update batch. |
8414 | |
8415 | \note QRhi transparently manages double buffering in order to prevent |
8416 | stalling the graphics pipeline. The fact that a QRhiBuffer may have |
8417 | multiple native buffer objects underneath can be safely ignored when using |
8418 | the QRhi and QRhiResourceUpdateBatch. |
8419 | */ |
8420 | void QRhiResourceUpdateBatch::updateDynamicBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data) |
8421 | { |
8422 | if (size > 0) { |
8423 | const int idx = d->activeBufferOpCount++; |
8424 | const int opListSize = d->bufferOps.size(); |
8425 | if (idx < opListSize) |
8426 | QRhiResourceUpdateBatchPrivate::BufferOp::changeToDynamicUpdate(op: &d->bufferOps[idx], buf, offset, size, data); |
8427 | else |
8428 | d->bufferOps.append(t: QRhiResourceUpdateBatchPrivate::BufferOp::dynamicUpdate(buf, offset, size, data)); |
8429 | } |
8430 | } |
8431 | |
8432 | /*! |
8433 | Enqueues updating a region of a QRhiBuffer \a buf created with the type |
8434 | QRhiBuffer::Immutable or QRhiBuffer::Static. |
8435 | |
8436 | The region is specified \a offset and \a size. The actual bytes to write |
8437 | are specified by \a data which must have at least \a size bytes available. |
8438 | \a data can safely be destroyed or changed once this function returns. |
8439 | */ |
8440 | void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data) |
8441 | { |
8442 | if (size > 0) { |
8443 | const int idx = d->activeBufferOpCount++; |
8444 | if (idx < d->bufferOps.size()) |
8445 | QRhiResourceUpdateBatchPrivate::BufferOp::changeToStaticUpload(op: &d->bufferOps[idx], buf, offset, size, data); |
8446 | else |
8447 | d->bufferOps.append(t: QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, offset, size, data)); |
8448 | } |
8449 | } |
8450 | |
8451 | /*! |
8452 | Enqueues updating the entire QRhiBuffer \a buf created with the type |
8453 | QRhiBuffer::Immutable or QRhiBuffer::Static. |
8454 | */ |
8455 | void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *data) |
8456 | { |
8457 | if (buf->size() > 0) { |
8458 | const int idx = d->activeBufferOpCount++; |
8459 | if (idx < d->bufferOps.size()) |
8460 | QRhiResourceUpdateBatchPrivate::BufferOp::changeToStaticUpload(op: &d->bufferOps[idx], buf, offset: 0, size: 0, data); |
8461 | else |
8462 | d->bufferOps.append(t: QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, offset: 0, size: 0, data)); |
8463 | } |
8464 | } |
8465 | |
8466 | /*! |
8467 | Enqueues reading back a region of the QRhiBuffer \a buf. The size of the |
8468 | region is specified by \a size in bytes, \a offset is the offset in bytes |
8469 | to start reading from. |
8470 | |
8471 | A readback is asynchronous. \a result contains a callback that is invoked |
8472 | when the operation has completed. The data is provided in |
8473 | QRhiReadbackResult::data. Upon successful completion that QByteArray |
8474 | will have a size equal to \a size. On failure the QByteArray will be empty. |
8475 | |
8476 | \note Reading buffers with a usage different than QRhiBuffer::UniformBuffer |
8477 | is supported only when the QRhi::ReadBackNonUniformBuffer feature is |
8478 | reported as supported. |
8479 | |
8480 | \note The asynchronous readback is guaranteed to have completed when one of |
8481 | the following conditions is met: \l{QRhi::finish()}{finish()} has been |
8482 | called; or, at least \c N frames have been \l{QRhi::endFrame()}{submitted}, |
8483 | including the frame that issued the readback operation, and the |
8484 | \l{QRhi::beginFrame()}{recording of a new frame} has been started, where \c |
8485 | N is the \l{QRhi::resourceLimit()}{resource limit value} returned for |
8486 | QRhi::MaxAsyncReadbackFrames. |
8487 | |
8488 | \sa readBackTexture(), QRhi::isFeatureSupported(), QRhi::resourceLimit() |
8489 | */ |
8490 | void QRhiResourceUpdateBatch::readBackBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiReadbackResult *result) |
8491 | { |
8492 | const int idx = d->activeBufferOpCount++; |
8493 | if (idx < d->bufferOps.size()) |
8494 | d->bufferOps[idx] = QRhiResourceUpdateBatchPrivate::BufferOp::read(buf, offset, size, result); |
8495 | else |
8496 | d->bufferOps.append(t: QRhiResourceUpdateBatchPrivate::BufferOp::read(buf, offset, size, result)); |
8497 | } |
8498 | |
8499 | /*! |
8500 | Enqueues uploading the image data for one or more mip levels in one or more |
8501 | layers of the texture \a tex. |
8502 | |
8503 | The details of the copy (source QImage or compressed texture data, regions, |
8504 | target layers and levels) are described in \a desc. |
8505 | */ |
8506 | void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc) |
8507 | { |
8508 | if (desc.cbeginEntries() != desc.cendEntries()) { |
8509 | const int idx = d->activeTextureOpCount++; |
8510 | if (idx < d->textureOps.size()) |
8511 | d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::upload(tex, desc); |
8512 | else |
8513 | d->textureOps.append(t: QRhiResourceUpdateBatchPrivate::TextureOp::upload(tex, desc)); |
8514 | } |
8515 | } |
8516 | |
8517 | /*! |
8518 | Enqueues uploading the image data for mip level 0 of layer 0 of the texture |
8519 | \a tex. |
8520 | |
8521 | \a tex must have an uncompressed format. Its format must also be compatible |
8522 | with the QImage::format() of \a image. The source data is given in \a |
8523 | image. |
8524 | */ |
8525 | void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QImage &image) |
8526 | { |
8527 | uploadTexture(tex, |
8528 | desc: QRhiTextureUploadEntry(0, 0, QRhiTextureSubresourceUploadDescription(image))); |
8529 | } |
8530 | |
8531 | /*! |
8532 | Enqueues a texture-to-texture copy operation from \a src into \a dst as |
8533 | described by \a desc. |
8534 | |
8535 | \note The source texture \a src must be created with |
8536 | QRhiTexture::UsedAsTransferSource. |
8537 | |
8538 | \note The format of the textures must match. With most graphics |
8539 | APIs the data is copied as-is without any format conversions. If |
8540 | \a dst and \a src are created with different formats, unspecified |
8541 | issues may arise. |
8542 | */ |
8543 | void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc) |
8544 | { |
8545 | const int idx = d->activeTextureOpCount++; |
8546 | if (idx < d->textureOps.size()) |
8547 | d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::copy(dst, src, desc); |
8548 | else |
8549 | d->textureOps.append(t: QRhiResourceUpdateBatchPrivate::TextureOp::copy(dst, src, desc)); |
8550 | } |
8551 | |
8552 | /*! |
8553 | Enqueues a texture-to-host copy operation as described by \a rb. |
8554 | |
8555 | Normally \a rb will specify a QRhiTexture as the source. However, when the |
8556 | swapchain in the current frame was created with |
8557 | QRhiSwapChain::UsedAsTransferSource, it can also be the source of the |
8558 | readback. For this, leave the texture set to null in \a rb. |
8559 | |
8560 | Unlike other operations, the results here need to be processed by the |
8561 | application. Therefore, \a result provides not just the data but also a |
8562 | callback as operations on the batch are asynchronous by nature: |
8563 | |
8564 | \code |
8565 | rhi->beginFrame(swapchain); |
8566 | cb->beginPass(swapchain->currentFrameRenderTarget(), colorClear, dsClear); |
8567 | // ... |
8568 | QRhiReadbackResult *rbResult = new QRhiReadbackResult; |
8569 | rbResult->completed = [rbResult] { |
8570 | { |
8571 | const QImage::Format fmt = QImage::Format_RGBA8888_Premultiplied; // fits QRhiTexture::RGBA8 |
8572 | const uchar *p = reinterpret_cast<const uchar *>(rbResult->data.constData()); |
8573 | QImage image(p, rbResult->pixelSize.width(), rbResult->pixelSize.height(), fmt); |
8574 | image.save("result.png"); |
8575 | } |
8576 | delete rbResult; |
8577 | }; |
8578 | QRhiResourceUpdateBatch *u = nextResourceUpdateBatch(); |
8579 | QRhiReadbackDescription rb; // no texture -> uses the current backbuffer of sc |
8580 | u->readBackTexture(rb, rbResult); |
8581 | cb->endPass(u); |
8582 | rhi->endFrame(swapchain); |
8583 | \endcode |
8584 | |
8585 | \note The texture must be created with QRhiTexture::UsedAsTransferSource. |
8586 | |
8587 | \note Multisample textures cannot be read back. |
8588 | |
8589 | \note The readback returns raw byte data, in order to allow the applications |
8590 | to interpret it in any way they see fit. Be aware of the blending settings |
8591 | of rendering code: if the blending is set up to rely on premultiplied alpha, |
8592 | the results of the readback must also be interpreted as Premultiplied. |
8593 | |
8594 | \note When interpreting the resulting raw data, be aware that the readback |
8595 | happens with a byte ordered format. A \l{QRhiTexture::RGBA8}{RGBA8} texture |
8596 | maps therefore to byte ordered QImage formats, such as, |
8597 | QImage::Format_RGBA8888. |
8598 | |
8599 | \note The asynchronous readback is guaranteed to have completed when one of |
8600 | the following conditions is met: \l{QRhi::finish()}{finish()} has been |
8601 | called; or, at least \c N frames have been \l{QRhi::endFrame()}{submitted}, |
8602 | including the frame that issued the readback operation, and the |
8603 | \l{QRhi::beginFrame()}{recording of a new frame} has been started, where \c |
8604 | N is the \l{QRhi::resourceLimit()}{resource limit value} returned for |
8605 | QRhi::MaxAsyncReadbackFrames. |
8606 | |
8607 | A single readback operation copies one mip level of one layer (cubemap face |
8608 | or 3D slice or texture array element) at a time. The level and layer are |
8609 | specified by the respective fields in \a rb. |
8610 | |
8611 | \sa readBackBuffer(), QRhi::resourceLimit() |
8612 | */ |
8613 | void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result) |
8614 | { |
8615 | const int idx = d->activeTextureOpCount++; |
8616 | if (idx < d->textureOps.size()) |
8617 | d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::read(rb, result); |
8618 | else |
8619 | d->textureOps.append(t: QRhiResourceUpdateBatchPrivate::TextureOp::read(rb, result)); |
8620 | } |
8621 | |
8622 | /*! |
8623 | Enqueues a mipmap generation operation for the specified texture \a tex. |
8624 | |
8625 | Both 2D and cube textures are supported. |
8626 | |
8627 | \note The texture must be created with QRhiTexture::MipMapped and |
8628 | QRhiTexture::UsedWithGenerateMips. |
8629 | |
8630 | \warning QRhi cannot guarantee that mipmaps can be generated for all |
8631 | supported texture formats. For example, QRhiTexture::RGBA32F is not a \c |
8632 | filterable format in OpenGL ES 3.0 and Metal on iOS, and therefore the |
8633 | mipmap generation request may fail. RGBA8 and RGBA16F are typically |
8634 | filterable, so it is recommended to use these formats when mipmap generation |
8635 | is desired. |
8636 | */ |
8637 | void QRhiResourceUpdateBatch::generateMips(QRhiTexture *tex) |
8638 | { |
8639 | const int idx = d->activeTextureOpCount++; |
8640 | if (idx < d->textureOps.size()) |
8641 | d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex); |
8642 | else |
8643 | d->textureOps.append(t: QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex)); |
8644 | } |
8645 | |
8646 | /*! |
8647 | \return an available, empty batch to which copy type of operations can be |
8648 | recorded. |
8649 | |
8650 | \note the return value is not owned by the caller and must never be |
8651 | destroyed. Instead, the batch is returned the pool for reuse by passing |
8652 | it to QRhiCommandBuffer::beginPass(), QRhiCommandBuffer::endPass(), or |
8653 | QRhiCommandBuffer::resourceUpdate(), or by calling |
8654 | QRhiResourceUpdateBatch::destroy() on it. |
8655 | |
8656 | \note Can be called outside beginFrame() - endFrame() as well since a batch |
8657 | instance just collects data on its own, it does not perform any operations. |
8658 | |
8659 | Due to not being tied to a frame being recorded, the following sequence is |
8660 | valid for example: |
8661 | |
8662 | \code |
8663 | rhi->beginFrame(swapchain); |
8664 | QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch(); |
8665 | u->uploadStaticBuffer(buf, data); |
8666 | // ... do not commit the batch |
8667 | rhi->endFrame(); |
8668 | // u stays valid (assuming buf stays valid as well) |
8669 | rhi->beginFrame(swapchain); |
8670 | swapchain->currentFrameCommandBuffer()->resourceUpdate(u); |
8671 | // ... draw with buf |
8672 | rhi->endFrame(); |
8673 | \endcode |
8674 | |
8675 | \warning The maximum number of batches per QRhi is 64. When this limit is |
8676 | reached, the function will return null until a batch is returned to the |
8677 | pool. |
8678 | */ |
8679 | QRhiResourceUpdateBatch *QRhi::nextResourceUpdateBatch() |
8680 | { |
8681 | // By default we prefer spreading out the utilization of the 64 batches as |
8682 | // much as possible, meaning we won't pick the first one even if it's free, |
8683 | // but prefer picking one after the last picked one. Relevant due to how |
8684 | // QVLA and QRhiBufferData allocations behind the bufferOps are reused; in |
8685 | // typical Qt Quick scenes this leads to a form of (eventually) seeding all |
8686 | // the 64 resource batches with buffer operation data allocations which are |
8687 | // then reused in subsequent frames. This comes at the expense of using |
8688 | // more memory, but has proven good results when (CPU) profiling typical |
8689 | // Quick/Quick3D apps. |
8690 | // |
8691 | // Prefering memory over performance means that we always pick the first |
8692 | // free batch, and triggering the aggressive deallocating of all backing |
8693 | // memory (see trimOpLists) before returning it. |
8694 | static const bool preferMemoryOverPerformance = qEnvironmentVariableIntValue(varName: "QT_RHI_MINIMIZE_POOLS" ); |
8695 | |
8696 | auto nextFreeBatch = [this]() -> QRhiResourceUpdateBatch * { |
8697 | auto isFree = [this](int i) -> QRhiResourceUpdateBatch * { |
8698 | const quint64 mask = 1ULL << quint64(i); |
8699 | if (!(d->resUpdPoolMap & mask)) { |
8700 | d->resUpdPoolMap |= mask; |
8701 | QRhiResourceUpdateBatch *u = d->resUpdPool[i]; |
8702 | QRhiResourceUpdateBatchPrivate::get(b: u)->poolIndex = i; |
8703 | if (!preferMemoryOverPerformance) |
8704 | d->lastResUpdIdx = i; |
8705 | return u; |
8706 | } |
8707 | return nullptr; |
8708 | }; |
8709 | const int poolSize = d->resUpdPool.size(); |
8710 | for (int i = d->lastResUpdIdx + 1; i < poolSize; ++i) { |
8711 | if (QRhiResourceUpdateBatch *u = isFree(i)) |
8712 | return u; |
8713 | } |
8714 | for (int i = 0; i <= d->lastResUpdIdx; ++i) { |
8715 | if (QRhiResourceUpdateBatch *u = isFree(i)) |
8716 | return u; |
8717 | } |
8718 | return nullptr; |
8719 | }; |
8720 | |
8721 | QRhiResourceUpdateBatch *u = nextFreeBatch(); |
8722 | if (!u) { |
8723 | const int oldSize = d->resUpdPool.size(); |
8724 | const int newSize = oldSize + qMin(a: 4, b: qMax(a: 0, b: 64 - oldSize)); |
8725 | d->resUpdPool.resize(sz: newSize); |
8726 | for (int i = oldSize; i < newSize; ++i) |
8727 | d->resUpdPool[i] = new QRhiResourceUpdateBatch(d); |
8728 | u = nextFreeBatch(); |
8729 | if (!u) |
8730 | qWarning(msg: "Resource update batch pool exhausted (max is 64)" ); |
8731 | } |
8732 | |
8733 | if (preferMemoryOverPerformance && u) |
8734 | u->d->trimOpLists(); |
8735 | |
8736 | return u; |
8737 | } |
8738 | |
8739 | void QRhiResourceUpdateBatchPrivate::free() |
8740 | { |
8741 | Q_ASSERT(poolIndex >= 0 && rhi->resUpdPool[poolIndex] == q); |
8742 | |
8743 | activeBufferOpCount = 0; |
8744 | activeTextureOpCount = 0; |
8745 | |
8746 | const quint64 mask = 1ULL << quint64(poolIndex); |
8747 | rhi->resUpdPoolMap &= ~mask; |
8748 | poolIndex = -1; |
8749 | |
8750 | // textureOps is cleared, to not keep the potentially large image pixel |
8751 | // data alive, but it is expected that the container keeps the list alloc |
8752 | // at least. Only trimOpList() goes for the more aggressive route with squeeze. |
8753 | textureOps.clear(); |
8754 | |
8755 | // bufferOps is not touched, to allow reusing allocations (incl. in the |
8756 | // elements' QRhiBufferData) as much as possible when this batch is used |
8757 | // again in the future, which is important for performance, in particular |
8758 | // with Qt Quick. |
8759 | } |
8760 | |
8761 | void QRhiResourceUpdateBatchPrivate::merge(QRhiResourceUpdateBatchPrivate *other) |
8762 | { |
8763 | int combinedSize = activeBufferOpCount + other->activeBufferOpCount; |
8764 | if (bufferOps.size() < combinedSize) |
8765 | bufferOps.resize(sz: combinedSize); |
8766 | for (int i = activeBufferOpCount; i < combinedSize; ++i) |
8767 | bufferOps[i] = std::move(other->bufferOps[i - activeBufferOpCount]); |
8768 | activeBufferOpCount += other->activeBufferOpCount; |
8769 | |
8770 | combinedSize = activeTextureOpCount + other->activeTextureOpCount; |
8771 | if (textureOps.size() < combinedSize) |
8772 | textureOps.resize(sz: combinedSize); |
8773 | for (int i = activeTextureOpCount; i < combinedSize; ++i) |
8774 | textureOps[i] = std::move(other->textureOps[i - activeTextureOpCount]); |
8775 | activeTextureOpCount += other->activeTextureOpCount; |
8776 | } |
8777 | |
8778 | bool QRhiResourceUpdateBatchPrivate::hasOptimalCapacity() const |
8779 | { |
8780 | return activeBufferOpCount < BUFFER_OPS_STATIC_ALLOC - 16 |
8781 | && activeTextureOpCount < TEXTURE_OPS_STATIC_ALLOC - 16; |
8782 | } |
8783 | |
8784 | void QRhiResourceUpdateBatchPrivate::trimOpLists() |
8785 | { |
8786 | // Unlike free(), this is expected to aggressively deallocate all memory |
8787 | // used by both the buffer and texture operation lists. (i.e. using |
8788 | // squeeze() to only keep the stack prealloc of the QVLAs) |
8789 | // |
8790 | // This (e.g. just the destruction of bufferOps elements) may have a |
8791 | // non-negligible performance impact e.g. with Qt Quick with scenes where |
8792 | // there are lots of buffer operations per frame. |
8793 | |
8794 | activeBufferOpCount = 0; |
8795 | bufferOps.clear(); |
8796 | bufferOps.squeeze(); |
8797 | |
8798 | activeTextureOpCount = 0; |
8799 | textureOps.clear(); |
8800 | textureOps.squeeze(); |
8801 | } |
8802 | |
8803 | /*! |
8804 | Sometimes committing resource updates is necessary or just more convenient |
8805 | without starting a render pass. Calling this function with \a |
8806 | resourceUpdates is an alternative to passing \a resourceUpdates to a |
8807 | beginPass() call (or endPass(), which would be typical in case of readbacks). |
8808 | |
8809 | \note Cannot be called inside a pass. |
8810 | */ |
8811 | void QRhiCommandBuffer::resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates) |
8812 | { |
8813 | if (resourceUpdates) |
8814 | m_rhi->resourceUpdate(cb: this, resourceUpdates); |
8815 | } |
8816 | |
8817 | /*! |
8818 | Records starting a new render pass targeting the render target \a rt. |
8819 | |
8820 | \a resourceUpdates, when not null, specifies a resource update batch that |
8821 | is to be committed and then released. |
8822 | |
8823 | The color and depth/stencil buffers of the render target are normally |
8824 | cleared. The clear values are specified in \a colorClearValue and \a |
8825 | depthStencilClearValue. The exception is when the render target was created |
8826 | with QRhiTextureRenderTarget::PreserveColorContents and/or |
8827 | QRhiTextureRenderTarget::PreserveDepthStencilContents. The clear values are |
8828 | ignored then. |
8829 | |
8830 | \note Enabling preserved color or depth contents leads to decreased |
8831 | performance depending on the underlying hardware. Mobile GPUs with tiled |
8832 | architecture benefit from not having to reload the previous contents into |
8833 | the tile buffer. Similarly, a QRhiTextureRenderTarget with a QRhiTexture as |
8834 | the depth buffer is less efficient than a QRhiRenderBuffer since using a |
8835 | depth texture triggers requiring writing the data out to it, while with |
8836 | renderbuffers this is not needed (as the API does not allow sampling or |
8837 | reading from a renderbuffer). |
8838 | |
8839 | \note Do not assume that any state or resource bindings persist between |
8840 | passes. |
8841 | |
8842 | \note The QRhiCommandBuffer's \c set and \c draw functions can only be |
8843 | called inside a pass. Also, with the exception of setGraphicsPipeline(), |
8844 | they expect to have a pipeline set already on the command buffer. |
8845 | Unspecified issues may arise otherwise, depending on the backend. |
8846 | |
8847 | If \a rt is a QRhiTextureRenderTarget, beginPass() performs a check to see |
8848 | if the texture and renderbuffer objects referenced from the render target |
8849 | are up-to-date. This is similar to what setShaderResources() does for |
8850 | QRhiShaderResourceBindings. If any of the attachments had been rebuilt |
8851 | since QRhiTextureRenderTarget::create(), an implicit call to create() is |
8852 | made on \a rt. Therefore, if \a rt has a QRhiTexture color attachment \c |
8853 | texture, and one needs to make the texture a different size, the following |
8854 | is then valid: |
8855 | \code |
8856 | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ { texture } }); |
8857 | rt->create(); |
8858 | // ... |
8859 | texture->setPixelSize(new_size); |
8860 | texture->create(); |
8861 | cb->beginPass(rt, colorClear, dsClear); // this is ok, no explicit rt->create() is required before |
8862 | \endcode |
8863 | |
8864 | \a flags allow controlling certain advanced functionality. One commonly used |
8865 | flag is \c ExternalContents. This should be specified whenever |
8866 | beginExternal() will be called within the pass started by this function. |
8867 | |
8868 | \sa endPass(), BeginPassFlags |
8869 | */ |
8870 | void QRhiCommandBuffer::beginPass(QRhiRenderTarget *rt, |
8871 | const QColor &colorClearValue, |
8872 | const QRhiDepthStencilClearValue &depthStencilClearValue, |
8873 | QRhiResourceUpdateBatch *resourceUpdates, |
8874 | BeginPassFlags flags) |
8875 | { |
8876 | m_rhi->beginPass(cb: this, rt, colorClearValue, depthStencilClearValue, resourceUpdates, flags); |
8877 | } |
8878 | |
8879 | /*! |
8880 | Records ending the current render pass. |
8881 | |
8882 | \a resourceUpdates, when not null, specifies a resource update batch that |
8883 | is to be committed and then released. |
8884 | |
8885 | \sa beginPass() |
8886 | */ |
8887 | void QRhiCommandBuffer::endPass(QRhiResourceUpdateBatch *resourceUpdates) |
8888 | { |
8889 | m_rhi->endPass(cb: this, resourceUpdates); |
8890 | } |
8891 | |
8892 | /*! |
8893 | Records setting a new graphics pipeline \a ps. |
8894 | |
8895 | \note This function must be called before recording other \c set or \c draw |
8896 | commands on the command buffer. |
8897 | |
8898 | \note QRhi will optimize out unnecessary invocations within a pass, so |
8899 | therefore overoptimizing to avoid calls to this function is not necessary |
8900 | on the applications' side. |
8901 | |
8902 | \note This function can only be called inside a render pass, meaning |
8903 | between a beginPass() and endPass() call. |
8904 | |
8905 | \note The new graphics pipeline \a ps must be a valid pointer. |
8906 | */ |
8907 | void QRhiCommandBuffer::setGraphicsPipeline(QRhiGraphicsPipeline *ps) |
8908 | { |
8909 | Q_ASSERT(ps != nullptr); |
8910 | m_rhi->setGraphicsPipeline(cb: this, ps); |
8911 | } |
8912 | |
8913 | /*! |
8914 | Records binding a set of shader resources, such as, uniform buffers or |
8915 | textures, that are made visible to one or more shader stages. |
8916 | |
8917 | \a srb can be null in which case the current graphics or compute pipeline's |
8918 | associated QRhiShaderResourceBindings is used. When \a srb is non-null, it |
8919 | must be |
8920 | \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible}, |
8921 | meaning the layout (number of bindings, the type and binding number of each |
8922 | binding) must fully match the QRhiShaderResourceBindings that was |
8923 | associated with the pipeline at the time of calling the pipeline's create(). |
8924 | |
8925 | There are cases when a seemingly unnecessary setShaderResources() call is |
8926 | mandatory: when rebuilding a resource referenced from \a srb, for example |
8927 | changing the size of a QRhiBuffer followed by a QRhiBuffer::create(), this |
8928 | is the place where associated native objects (such as descriptor sets in |
8929 | case of Vulkan) are updated to refer to the current native resources that |
8930 | back the QRhiBuffer, QRhiTexture, QRhiSampler objects referenced from \a |
8931 | srb. In this case setShaderResources() must be called even if \a srb is |
8932 | the same as in the last call. |
8933 | |
8934 | When \a srb is not null, the QRhiShaderResourceBindings object the pipeline |
8935 | was built with in create() is guaranteed to be not accessed in any form. In |
8936 | fact, it does not need to be valid even at this point: destroying the |
8937 | pipeline's associated srb after create() and instead explicitly specifying |
8938 | another, \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout |
8939 | compatible} one in every setShaderResources() call is valid. |
8940 | |
8941 | \a dynamicOffsets allows specifying buffer offsets for uniform buffers that |
8942 | were associated with \a srb via |
8943 | QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(). This is |
8944 | different from providing the offset in the \a srb itself: dynamic offsets |
8945 | do not require building a new QRhiShaderResourceBindings for every |
8946 | different offset, can avoid writing the underlying descriptors (with |
8947 | backends where applicable), and so they may be more efficient. Each element |
8948 | of \a dynamicOffsets is a \c binding - \c offset pair. |
8949 | \a dynamicOffsetCount specifies the number of elements in \a dynamicOffsets. |
8950 | |
8951 | \note All offsets in \a dynamicOffsets must be byte aligned to the value |
8952 | returned from QRhi::ubufAlignment(). |
8953 | |
8954 | \note Some backends may limit the number of supported dynamic offsets. |
8955 | Avoid using a \a dynamicOffsetCount larger than 8. |
8956 | |
8957 | \note QRhi will optimize out unnecessary invocations within a pass (taking |
8958 | the conditions described above into account), so therefore overoptimizing |
8959 | to avoid calls to this function is not necessary on the applications' side. |
8960 | |
8961 | \note This function can only be called inside a render or compute pass, |
8962 | meaning between a beginPass() and endPass(), or beginComputePass() and |
8963 | endComputePass(). |
8964 | */ |
8965 | void QRhiCommandBuffer::setShaderResources(QRhiShaderResourceBindings *srb, |
8966 | int dynamicOffsetCount, |
8967 | const DynamicOffset *dynamicOffsets) |
8968 | { |
8969 | m_rhi->setShaderResources(cb: this, srb, dynamicOffsetCount, dynamicOffsets); |
8970 | } |
8971 | |
8972 | /*! |
8973 | Records vertex input bindings. |
8974 | |
8975 | The index buffer used by subsequent drawIndexed() commands is specified by |
8976 | \a indexBuf, \a indexOffset, and \a indexFormat. \a indexBuf can be set to |
8977 | null when indexed drawing is not needed. |
8978 | |
8979 | Vertex buffer bindings are batched. \a startBinding specifies the first |
8980 | binding number. The recorded command then binds each buffer from \a |
8981 | bindings to the binding point \c{startBinding + i} where \c i is the index |
8982 | in \a bindings. Each element in \a bindings specifies a QRhiBuffer and an |
8983 | offset. |
8984 | |
8985 | \note Some backends may limit the number of vertex buffer bindings. Avoid |
8986 | using a \a bindingCount larger than 8. |
8987 | |
8988 | Superfluous vertex input and index changes in the same pass are ignored |
8989 | automatically with most backends and therefore applications do not need to |
8990 | overoptimize to avoid calls to this function. |
8991 | |
8992 | \note This function can only be called inside a render pass, meaning |
8993 | between a beginPass() and endPass() call. |
8994 | |
8995 | As a simple example, take a vertex shader with two inputs: |
8996 | |
8997 | \badcode |
8998 | layout(location = 0) in vec4 position; |
8999 | layout(location = 1) in vec3 color; |
9000 | \endcode |
9001 | |
9002 | and assume we have the data available in interleaved format, using only 2 |
9003 | floats for position (so 5 floats per vertex: x, y, r, g, b). A QRhiGraphicsPipeline for |
9004 | this shader can then be created using the input layout: |
9005 | |
9006 | \code |
9007 | QRhiVertexInputLayout inputLayout; |
9008 | inputLayout.setBindings({ |
9009 | { 5 * sizeof(float) } |
9010 | }); |
9011 | inputLayout.setAttributes({ |
9012 | { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, |
9013 | { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) } |
9014 | }); |
9015 | \endcode |
9016 | |
9017 | Here there is one buffer binding (binding number 0), with two inputs |
9018 | referencing it. When recording the pass, once the pipeline is set, the |
9019 | vertex bindings can be specified simply like the following, assuming vbuf |
9020 | is the QRhiBuffer with all the interleaved position+color data: |
9021 | |
9022 | \code |
9023 | const QRhiCommandBuffer::VertexInput vbufBinding(vbuf, 0); |
9024 | cb->setVertexInput(0, 1, &vbufBinding); |
9025 | \endcode |
9026 | */ |
9027 | void QRhiCommandBuffer::setVertexInput(int startBinding, int bindingCount, const VertexInput *bindings, |
9028 | QRhiBuffer *indexBuf, quint32 indexOffset, |
9029 | IndexFormat indexFormat) |
9030 | { |
9031 | m_rhi->setVertexInput(cb: this, startBinding, bindingCount, bindings, indexBuf, indexOffset, indexFormat); |
9032 | } |
9033 | |
9034 | /*! |
9035 | Records setting the active viewport rectangle specified in \a viewport. |
9036 | |
9037 | With backends where the underlying graphics API has scissoring always |
9038 | enabled, this function also sets the scissor to match the viewport whenever |
9039 | the active QRhiGraphicsPipeline does not have |
9040 | \l{QRhiGraphicsPipeline::UsesScissor}{UsesScissor} set. |
9041 | |
9042 | \note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are |
9043 | bottom-left. |
9044 | |
9045 | \note This function can only be called inside a render pass, meaning |
9046 | between a beginPass() and endPass() call. |
9047 | */ |
9048 | void QRhiCommandBuffer::setViewport(const QRhiViewport &viewport) |
9049 | { |
9050 | m_rhi->setViewport(cb: this, viewport); |
9051 | } |
9052 | |
9053 | /*! |
9054 | Records setting the active scissor rectangle specified in \a scissor. |
9055 | |
9056 | This can only be called when the bound pipeline has |
9057 | \l{QRhiGraphicsPipeline::UsesScissor}{UsesScissor} set. When the flag is |
9058 | set on the active pipeline, this function must be called because scissor |
9059 | testing will get enabled and so a scissor rectangle must be provided. |
9060 | |
9061 | \note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are |
9062 | bottom-left. |
9063 | |
9064 | \note This function can only be called inside a render pass, meaning |
9065 | between a beginPass() and endPass() call. |
9066 | */ |
9067 | void QRhiCommandBuffer::setScissor(const QRhiScissor &scissor) |
9068 | { |
9069 | m_rhi->setScissor(cb: this, scissor); |
9070 | } |
9071 | |
9072 | /*! |
9073 | Records setting the active blend constants to \a c. |
9074 | |
9075 | This can only be called when the bound pipeline has |
9076 | QRhiGraphicsPipeline::UsesBlendConstants set. |
9077 | |
9078 | \note This function can only be called inside a render pass, meaning |
9079 | between a beginPass() and endPass() call. |
9080 | */ |
9081 | void QRhiCommandBuffer::setBlendConstants(const QColor &c) |
9082 | { |
9083 | m_rhi->setBlendConstants(cb: this, c); |
9084 | } |
9085 | |
9086 | /*! |
9087 | Records setting the active stencil reference value to \a refValue. |
9088 | |
9089 | This can only be called when the bound pipeline has |
9090 | QRhiGraphicsPipeline::UsesStencilRef set. |
9091 | |
9092 | \note This function can only be called inside a render pass, meaning between |
9093 | a beginPass() and endPass() call. |
9094 | */ |
9095 | void QRhiCommandBuffer::setStencilRef(quint32 refValue) |
9096 | { |
9097 | m_rhi->setStencilRef(cb: this, refValue); |
9098 | } |
9099 | |
9100 | /*! |
9101 | Records a non-indexed draw. |
9102 | |
9103 | The number of vertices is specified in \a vertexCount. For instanced |
9104 | drawing set \a instanceCount to a value other than 1. \a firstVertex is the |
9105 | index of the first vertex to draw. When drawing multiple instances, the |
9106 | first instance ID is specified by \a firstInstance. |
9107 | |
9108 | \note \a firstInstance may not be supported, and is ignored when the |
9109 | QRhi::BaseInstance feature is reported as not supported. The first ID is |
9110 | always 0 in that case. |
9111 | |
9112 | \note This function can only be called inside a render pass, meaning |
9113 | between a beginPass() and endPass() call. |
9114 | */ |
9115 | void QRhiCommandBuffer::draw(quint32 vertexCount, |
9116 | quint32 instanceCount, |
9117 | quint32 firstVertex, |
9118 | quint32 firstInstance) |
9119 | { |
9120 | m_rhi->draw(cb: this, vertexCount, instanceCount, firstVertex, firstInstance); |
9121 | } |
9122 | |
9123 | /*! |
9124 | Records an indexed draw. |
9125 | |
9126 | The number of vertices is specified in \a indexCount. \a firstIndex is the |
9127 | base index. The effective offset in the index buffer is given by |
9128 | \c{indexOffset + firstIndex * n} where \c n is 2 or 4 depending on the |
9129 | index element type. \c indexOffset is specified in setVertexInput(). |
9130 | |
9131 | \note The effective offset in the index buffer must be 4 byte aligned with |
9132 | some backends (for example, Metal). With these backends the |
9133 | \l{QRhi::NonFourAlignedEffectiveIndexBufferOffset}{NonFourAlignedEffectiveIndexBufferOffset} |
9134 | feature will be reported as not-supported. |
9135 | |
9136 | For instanced drawing set \a instanceCount to a value other than 1. When |
9137 | drawing multiple instances, the first instance ID is specified by \a |
9138 | firstInstance. |
9139 | |
9140 | \note \a firstInstance may not be supported, and is ignored when the |
9141 | QRhi::BaseInstance feature is reported as not supported. The first ID is |
9142 | always 0 in that case. |
9143 | |
9144 | \a vertexOffset (also called \c{base vertex}) is a signed value that is |
9145 | added to the element index before indexing into the vertex buffer. Support |
9146 | for this is not always available, and the value is ignored when the feature |
9147 | QRhi::BaseVertex is reported as unsupported. |
9148 | |
9149 | \note This function can only be called inside a render pass, meaning |
9150 | between a beginPass() and endPass() call. |
9151 | */ |
9152 | void QRhiCommandBuffer::drawIndexed(quint32 indexCount, |
9153 | quint32 instanceCount, |
9154 | quint32 firstIndex, |
9155 | qint32 vertexOffset, |
9156 | quint32 firstInstance) |
9157 | { |
9158 | m_rhi->drawIndexed(cb: this, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); |
9159 | } |
9160 | |
9161 | /*! |
9162 | Records a named debug group on the command buffer with the specified \a |
9163 | name. This is shown in graphics debugging tools such as |
9164 | \l{https://renderdoc.org/}{RenderDoc} and |
9165 | \l{https://developer.apple.com/xcode/}{XCode}. The end of the grouping is |
9166 | indicated by debugMarkEnd(). |
9167 | |
9168 | \note Ignored when QRhi::DebugMarkers are not supported or |
9169 | QRhi::EnableDebugMarkers is not set. |
9170 | |
9171 | \note Can be called anywhere within the frame, both inside and outside of passes. |
9172 | */ |
9173 | void QRhiCommandBuffer::debugMarkBegin(const QByteArray &name) |
9174 | { |
9175 | m_rhi->debugMarkBegin(cb: this, name); |
9176 | } |
9177 | |
9178 | /*! |
9179 | Records the end of a debug group. |
9180 | |
9181 | \note Ignored when QRhi::DebugMarkers are not supported or |
9182 | QRhi::EnableDebugMarkers is not set. |
9183 | |
9184 | \note Can be called anywhere within the frame, both inside and outside of passes. |
9185 | */ |
9186 | void QRhiCommandBuffer::debugMarkEnd() |
9187 | { |
9188 | m_rhi->debugMarkEnd(cb: this); |
9189 | } |
9190 | |
9191 | /*! |
9192 | Inserts a debug message \a msg into the command stream. |
9193 | |
9194 | \note Ignored when QRhi::DebugMarkers are not supported or |
9195 | QRhi::EnableDebugMarkers is not set. |
9196 | |
9197 | \note With some backends debugMarkMsg() is only supported inside a pass and |
9198 | is ignored when called outside a pass. With others it is recorded anywhere |
9199 | within the frame. |
9200 | */ |
9201 | void QRhiCommandBuffer::debugMarkMsg(const QByteArray &msg) |
9202 | { |
9203 | m_rhi->debugMarkMsg(cb: this, msg); |
9204 | } |
9205 | |
9206 | /*! |
9207 | Records starting a new compute pass. |
9208 | |
9209 | \a resourceUpdates, when not null, specifies a resource update batch that |
9210 | is to be committed and then released. |
9211 | |
9212 | \note Do not assume that any state or resource bindings persist between |
9213 | passes. |
9214 | |
9215 | \note A compute pass can record setComputePipeline(), setShaderResources(), |
9216 | and dispatch() calls, not graphics ones. General functionality, such as, |
9217 | debug markers and beginExternal() is available both in render and compute |
9218 | passes. |
9219 | |
9220 | \note Compute is only available when the \l{QRhi::Compute}{Compute} feature |
9221 | is reported as supported. |
9222 | |
9223 | \a flags is not currently used. |
9224 | */ |
9225 | void QRhiCommandBuffer::beginComputePass(QRhiResourceUpdateBatch *resourceUpdates, BeginPassFlags flags) |
9226 | { |
9227 | m_rhi->beginComputePass(cb: this, resourceUpdates, flags); |
9228 | } |
9229 | |
9230 | /*! |
9231 | Records ending the current compute pass. |
9232 | |
9233 | \a resourceUpdates, when not null, specifies a resource update batch that |
9234 | is to be committed and then released. |
9235 | */ |
9236 | void QRhiCommandBuffer::endComputePass(QRhiResourceUpdateBatch *resourceUpdates) |
9237 | { |
9238 | m_rhi->endComputePass(cb: this, resourceUpdates); |
9239 | } |
9240 | |
9241 | /*! |
9242 | Records setting a new compute pipeline \a ps. |
9243 | |
9244 | \note This function must be called before recording setShaderResources() or |
9245 | dispatch() commands on the command buffer. |
9246 | |
9247 | \note QRhi will optimize out unnecessary invocations within a pass, so |
9248 | therefore overoptimizing to avoid calls to this function is not necessary |
9249 | on the applications' side. |
9250 | |
9251 | \note This function can only be called inside a compute pass, meaning |
9252 | between a beginComputePass() and endComputePass() call. |
9253 | */ |
9254 | void QRhiCommandBuffer::setComputePipeline(QRhiComputePipeline *ps) |
9255 | { |
9256 | m_rhi->setComputePipeline(cb: this, ps); |
9257 | } |
9258 | |
9259 | /*! |
9260 | Records dispatching compute work items, with \a x, \a y, and \a z |
9261 | specifying the number of local workgroups in the corresponding dimension. |
9262 | |
9263 | \note This function can only be called inside a compute pass, meaning |
9264 | between a beginComputePass() and endComputePass() call. |
9265 | |
9266 | \note \a x, \a y, and \a z must fit the limits from the underlying graphics |
9267 | API implementation at run time. The maximum values are typically 65535. |
9268 | |
9269 | \note Watch out for possible limits on the local workgroup size as well. |
9270 | This is specified in the shader, for example: \c{layout(local_size_x = 16, |
9271 | local_size_y = 16) in;}. For example, with OpenGL the minimum value mandated |
9272 | by the specification for the number of invocations in a single local work |
9273 | group (the product of \c local_size_x, \c local_size_y, and \c local_size_z) |
9274 | is 1024, while with OpenGL ES (3.1) the value may be as low as 128. This |
9275 | means that the example given above may be rejected by some OpenGL ES |
9276 | implementations as the number of invocations is 256. |
9277 | */ |
9278 | void QRhiCommandBuffer::dispatch(int x, int y, int z) |
9279 | { |
9280 | m_rhi->dispatch(cb: this, x, y, z); |
9281 | } |
9282 | |
9283 | /*! |
9284 | \return a pointer to a backend-specific QRhiNativeHandles subclass, such as |
9285 | QRhiVulkanCommandBufferNativeHandles. The returned value is \nullptr when |
9286 | exposing the underlying native resources is not supported by, or not |
9287 | applicable to, the backend. |
9288 | |
9289 | \sa QRhiVulkanCommandBufferNativeHandles, |
9290 | QRhiMetalCommandBufferNativeHandles, beginExternal(), endExternal() |
9291 | */ |
9292 | const QRhiNativeHandles *QRhiCommandBuffer::nativeHandles() |
9293 | { |
9294 | return m_rhi->nativeHandles(cb: this); |
9295 | } |
9296 | |
9297 | /*! |
9298 | To be called when the application before the application is about to |
9299 | enqueue commands to the current pass' command buffer by calling graphics |
9300 | API functions directly. |
9301 | |
9302 | \note This is only available when the intent was declared upfront in |
9303 | beginPass() or beginComputePass(). Therefore this function must only be |
9304 | called when the pass recording was started with specifying |
9305 | QRhiCommandBuffer::ExternalContent. |
9306 | |
9307 | With Vulkan, Metal, or Direct3D 12 one can query the native command buffer |
9308 | or encoder objects via nativeHandles() and enqueue commands to them. With |
9309 | OpenGL or Direct3D 11 the (device) context can be retrieved from |
9310 | QRhi::nativeHandles(). However, this must never be done without ensuring |
9311 | the QRhiCommandBuffer's state stays up-to-date. Hence the requirement for |
9312 | wrapping any externally added command recording between beginExternal() and |
9313 | endExternal(). Conceptually this is the same as QPainter's |
9314 | \l{QPainter::beginNativePainting()}{beginNativePainting()} and |
9315 | \l{QPainter::endNativePainting()}{endNativePainting()} functions. |
9316 | |
9317 | For OpenGL in particular, this function has an additional task: it makes |
9318 | sure the context is made current on the current thread. |
9319 | |
9320 | \note Once beginExternal() is called, no other render pass specific |
9321 | functions (\c set* or \c draw*) must be called on the |
9322 | QRhiCommandBuffer until endExternal(). |
9323 | |
9324 | \warning Some backends may return a native command buffer object from |
9325 | QRhiCommandBuffer::nativeHandles() that is different from the primary one |
9326 | when inside a beginExternal() - endExternal() block. Therefore it is |
9327 | important to (re)query the native command buffer object after calling |
9328 | beginExternal(). In practical terms this means that with Vulkan for example |
9329 | the externally recorded Vulkan commands are placed onto a secondary command |
9330 | buffer (with VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT). |
9331 | nativeHandles() returns this secondary command buffer when called between |
9332 | begin/endExternal. |
9333 | |
9334 | \sa endExternal(), nativeHandles() |
9335 | */ |
9336 | void QRhiCommandBuffer::beginExternal() |
9337 | { |
9338 | m_rhi->beginExternal(cb: this); |
9339 | } |
9340 | |
9341 | /*! |
9342 | To be called once the externally added commands are recorded to the command |
9343 | buffer or context. |
9344 | |
9345 | \note All QRhiCommandBuffer state must be assumed as invalid after calling |
9346 | this function. Pipelines, vertex and index buffers, and other state must be |
9347 | set again if more draw calls are recorded after the external commands. |
9348 | |
9349 | \sa beginExternal(), nativeHandles() |
9350 | */ |
9351 | void QRhiCommandBuffer::endExternal() |
9352 | { |
9353 | m_rhi->endExternal(cb: this); |
9354 | } |
9355 | |
9356 | /*! |
9357 | \return the last available timestamp, in seconds. The value indicates the |
9358 | elapsed time on the GPU during the last completed frame. |
9359 | |
9360 | Care must be exercised with the interpretation of the value, as its |
9361 | precision and granularity is often not controlled by Qt, and depends on the |
9362 | underlying graphics API and its implementation. In particular, comparing |
9363 | the values between different graphics APIs and hardware is discouraged and |
9364 | may be meaningless. |
9365 | |
9366 | The timing values may become available asynchronously. The returned value |
9367 | may therefore be 0 or the last known value referring to some previous |
9368 | frame. The value my also become 0 again under certain conditions, such as |
9369 | when resizing the window. It can be expected that the most up-to-date |
9370 | available value is retrieved in beginFrame() and becomes queriable via this |
9371 | function once beginFrame() returns. |
9372 | |
9373 | \note Do not assume that the value refers to the previous |
9374 | (\c{currently_recorded - 1}) frame. It may refer to \c{currently_recorded - |
9375 | 2} or \c{currently_recorded - 3} as well. The exact behavior may depend on |
9376 | the graphics API and its implementation. |
9377 | |
9378 | \note The result is always 0 when the QRhi::Timestamps feature is not |
9379 | reported as supported, or when QRhi::EnableTimestamps was not passed to |
9380 | QRhi::create(). There are exceptions to the latter, because with some |
9381 | graphics APIs timings are available without having to perform extra |
9382 | operations, but portable applications should always consciously opt-in to |
9383 | timestamp collection when they know it is needed, and call this function |
9384 | accordingly. |
9385 | */ |
9386 | double QRhiCommandBuffer::lastCompletedGpuTime() |
9387 | { |
9388 | return m_rhi->lastCompletedGpuTime(cb: this); |
9389 | } |
9390 | |
9391 | /*! |
9392 | \return the value (typically an offset) \a v aligned to the uniform buffer |
9393 | alignment given by by ubufAlignment(). |
9394 | */ |
9395 | int QRhi::ubufAligned(int v) const |
9396 | { |
9397 | const int byteAlign = ubufAlignment(); |
9398 | return (v + byteAlign - 1) & ~(byteAlign - 1); |
9399 | } |
9400 | |
9401 | /*! |
9402 | \return the number of mip levels for a given \a size. |
9403 | */ |
9404 | int QRhi::mipLevelsForSize(const QSize &size) |
9405 | { |
9406 | return qFloor(v: std::log2(x: qMax(a: size.width(), b: size.height()))) + 1; |
9407 | } |
9408 | |
9409 | /*! |
9410 | \return the texture image size for a given \a mipLevel, calculated based on |
9411 | the level 0 size given in \a baseLevelSize. |
9412 | */ |
9413 | QSize QRhi::sizeForMipLevel(int mipLevel, const QSize &baseLevelSize) |
9414 | { |
9415 | const int w = qMax(a: 1, b: baseLevelSize.width() >> mipLevel); |
9416 | const int h = qMax(a: 1, b: baseLevelSize.height() >> mipLevel); |
9417 | return QSize(w, h); |
9418 | } |
9419 | |
9420 | /*! |
9421 | \return \c true if the underlying graphics API has the Y axis pointing up |
9422 | in framebuffers and images. |
9423 | |
9424 | In practice this is \c true for OpenGL only. |
9425 | */ |
9426 | bool QRhi::isYUpInFramebuffer() const |
9427 | { |
9428 | return d->isYUpInFramebuffer(); |
9429 | } |
9430 | |
9431 | /*! |
9432 | \return \c true if the underlying graphics API has the Y axis pointing up |
9433 | in its normalized device coordinate system. |
9434 | |
9435 | In practice this is \c false for Vulkan only. |
9436 | |
9437 | \note clipSpaceCorrMatrix() includes the corresponding adjustment (to make |
9438 | Y point up) in its returned matrix. |
9439 | */ |
9440 | bool QRhi::isYUpInNDC() const |
9441 | { |
9442 | return d->isYUpInNDC(); |
9443 | } |
9444 | |
9445 | /*! |
9446 | \return \c true if the underlying graphics API uses depth range [0, 1] in |
9447 | clip space. |
9448 | |
9449 | In practice this is \c false for OpenGL only, because OpenGL uses a |
9450 | post-projection depth range of [-1, 1]. (not to be confused with the |
9451 | NDC-to-window mapping controlled by glDepthRange(), which uses a range of |
9452 | [0, 1], unless overridden by the QRhiViewport) In some OpenGL versions |
9453 | glClipControl() could be used to change this, but the OpenGL backend of |
9454 | QRhi does not use that function as it is not available in OpenGL ES or |
9455 | OpenGL versions lower than 4.5. |
9456 | |
9457 | \note clipSpaceCorrMatrix() includes the corresponding adjustment in its |
9458 | returned matrix. Therefore, many users of QRhi do not need to take any |
9459 | further measures apart from pre-multiplying their projection matrices with |
9460 | clipSpaceCorrMatrix(). However, some graphics techniques, such as, some |
9461 | types of shadow mapping, involve working with and outputting depth values |
9462 | in the shaders. These will need to query and take the value of this |
9463 | function into account as appropriate. |
9464 | */ |
9465 | bool QRhi::isClipDepthZeroToOne() const |
9466 | { |
9467 | return d->isClipDepthZeroToOne(); |
9468 | } |
9469 | |
9470 | /*! |
9471 | \return a matrix that can be used to allow applications keep using |
9472 | OpenGL-targeted vertex data and perspective projection matrices (such as, |
9473 | the ones generated by QMatrix4x4::perspective()), regardless of the active |
9474 | QRhi backend. |
9475 | |
9476 | In a typical renderer, once \c{this_matrix * mvp} is used instead of just |
9477 | \c mvp, vertex data with Y up and viewports with depth range 0 - 1 can be |
9478 | used without considering what backend (and so graphics API) is going to be |
9479 | used at run time. This way branching based on isYUpInNDC() and |
9480 | isClipDepthZeroToOne() can be avoided (although such logic may still become |
9481 | required when implementing certain advanced graphics techniques). |
9482 | |
9483 | See |
9484 | \l{https://matthewwellings.com/blog/the-new-vulkan-coordinate-system/}{this |
9485 | page} for a discussion of the topic from Vulkan perspective. |
9486 | */ |
9487 | QMatrix4x4 QRhi::clipSpaceCorrMatrix() const |
9488 | { |
9489 | return d->clipSpaceCorrMatrix(); |
9490 | } |
9491 | |
9492 | /*! |
9493 | \return \c true if the specified texture \a format modified by \a flags is |
9494 | supported. |
9495 | |
9496 | The query is supported both for uncompressed and compressed formats. |
9497 | */ |
9498 | bool QRhi::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const |
9499 | { |
9500 | return d->isTextureFormatSupported(format, flags); |
9501 | } |
9502 | |
9503 | /*! |
9504 | \return \c true if the specified \a feature is supported |
9505 | */ |
9506 | bool QRhi::isFeatureSupported(QRhi::Feature feature) const |
9507 | { |
9508 | return d->isFeatureSupported(feature); |
9509 | } |
9510 | |
9511 | /*! |
9512 | \return the value for the specified resource \a limit. |
9513 | |
9514 | The values are expected to be queried by the backends upon initialization, |
9515 | meaning calling this function is a light operation. |
9516 | */ |
9517 | int QRhi::resourceLimit(ResourceLimit limit) const |
9518 | { |
9519 | return d->resourceLimit(limit); |
9520 | } |
9521 | |
9522 | /*! |
9523 | \return a pointer to the backend-specific collection of native objects |
9524 | for the device, context, and similar concepts used by the backend. |
9525 | |
9526 | Cast to QRhiVulkanNativeHandles, QRhiD3D11NativeHandles, |
9527 | QRhiD3D12NativeHandles, QRhiGles2NativeHandles, or QRhiMetalNativeHandles |
9528 | as appropriate. |
9529 | |
9530 | \note No ownership is transferred, neither for the returned pointer nor for |
9531 | any native objects. |
9532 | */ |
9533 | const QRhiNativeHandles *QRhi::nativeHandles() |
9534 | { |
9535 | return d->nativeHandles(); |
9536 | } |
9537 | |
9538 | /*! |
9539 | With OpenGL this makes the OpenGL context current on the current thread. |
9540 | The function has no effect with other backends. |
9541 | |
9542 | Calling this function is relevant typically in Qt framework code, when one |
9543 | has to ensure external OpenGL code provided by the application can still |
9544 | run like it did before with direct usage of OpenGL, as long as the QRhi is |
9545 | using the OpenGL backend. |
9546 | |
9547 | \return false when failed, similarly to QOpenGLContext::makeCurrent(). When |
9548 | the operation failed, isDeviceLost() can be called to determine if there |
9549 | was a loss of context situation. Such a check is equivalent to checking via |
9550 | QOpenGLContext::isValid(). |
9551 | |
9552 | \sa QOpenGLContext::makeCurrent(), QOpenGLContext::isValid() |
9553 | */ |
9554 | bool QRhi::makeThreadLocalNativeContextCurrent() |
9555 | { |
9556 | return d->makeThreadLocalNativeContextCurrent(); |
9557 | } |
9558 | |
9559 | /*! |
9560 | Attempts to release resources in the backend's caches. This can include both |
9561 | CPU and GPU resources. Only memory and resources that can be recreated |
9562 | automatically are in scope. As an example, if the backend's |
9563 | QRhiGraphicsPipeline implementation maintains a cache of shader compilation |
9564 | results, calling this function leads to emptying that cache, thus |
9565 | potentially freeing up memory and graphics resources. |
9566 | |
9567 | Calling this function makes sense in resource constrained environments, |
9568 | where at a certain point there is a need to ensure minimal resource usage, |
9569 | at the expense of performance. |
9570 | */ |
9571 | void QRhi::releaseCachedResources() |
9572 | { |
9573 | d->releaseCachedResources(); |
9574 | |
9575 | for (QRhiResourceUpdateBatch *u : d->resUpdPool) { |
9576 | if (u->d->poolIndex < 0) |
9577 | u->d->trimOpLists(); |
9578 | } |
9579 | } |
9580 | |
9581 | /*! |
9582 | \return true if the graphics device was lost. |
9583 | |
9584 | The loss of the device is typically detected in beginFrame(), endFrame() or |
9585 | QRhiSwapChain::createOrResize(), depending on the backend and the underlying |
9586 | native APIs. The most common is endFrame() because that is where presenting |
9587 | happens. With some backends QRhiSwapChain::createOrResize() can also fail |
9588 | due to a device loss. Therefore this function is provided as a generic way |
9589 | to check if a device loss was detected by a previous operation. |
9590 | |
9591 | When the device is lost, no further operations should be done via the QRhi. |
9592 | Rather, all QRhi resources should be released, followed by destroying the |
9593 | QRhi. A new QRhi can then be attempted to be created. If successful, all |
9594 | graphics resources must be reinitialized. If not, try again later, |
9595 | repeatedly. |
9596 | |
9597 | While simple applications may decide to not care about device loss, |
9598 | on the commonly used desktop platforms a device loss can happen |
9599 | due to a variety of reasons, including physically disconnecting the |
9600 | graphics adapter, disabling the device or driver, uninstalling or upgrading |
9601 | the graphics driver, or due to errors that lead to a graphics device reset. |
9602 | Some of these can happen under perfectly normal circumstances as well, for |
9603 | example the upgrade of the graphics driver to a newer version is a common |
9604 | task that can happen at any time while a Qt application is running. Users |
9605 | may very well expect applications to be able to survive this, even when the |
9606 | application is actively using an API like OpenGL or Direct3D. |
9607 | |
9608 | Qt's own frameworks built on top of QRhi, such as, Qt Quick, can be |
9609 | expected to handle and take appropriate measures when a device loss occurs. |
9610 | If the data for graphics resources, such as textures and buffers, are still |
9611 | available on the CPU side, such an event may not be noticeable on the |
9612 | application level at all since graphics resources can seamlessly be |
9613 | reinitialized then. However, applications and libraries working directly |
9614 | with QRhi are expected to be prepared to check and handle device loss |
9615 | situations themselves. |
9616 | |
9617 | \note With OpenGL, applications may need to opt-in to context reset |
9618 | notifications by setting QSurfaceFormat::ResetNotification on the |
9619 | QOpenGLContext. This is typically done by enabling the flag in |
9620 | QRhiGles2InitParams::format. Keep in mind however that some systems may |
9621 | generate context resets situations even when this flag is not set. |
9622 | */ |
9623 | bool QRhi::isDeviceLost() const |
9624 | { |
9625 | return d->isDeviceLost(); |
9626 | } |
9627 | |
9628 | /*! |
9629 | \return a binary data blob with data collected from the |
9630 | QRhiGraphicsPipeline and QRhiComputePipeline successfully created during |
9631 | the lifetime of this QRhi. |
9632 | |
9633 | By saving and then, in subsequent runs of the same application, reloading |
9634 | the cache data, pipeline and shader creation times can potentially be |
9635 | reduced. What exactly the cache and its serialized version includes is not |
9636 | specified, is always specific to the backend used, and in some cases also |
9637 | dependent on the particular implementation of the graphics API. |
9638 | |
9639 | When the PipelineCacheDataLoadSave is reported as unsupported, the returned |
9640 | QByteArray is empty. |
9641 | |
9642 | When the EnablePipelineCacheDataSave flag was not specified when calling |
9643 | create(), the returned QByteArray may be empty, even when the |
9644 | PipelineCacheDataLoadSave feature is supported. |
9645 | |
9646 | When the returned data is non-empty, it is always specific to the Qt |
9647 | version and QRhi backend. In addition, in some cases there is a strong |
9648 | dependency to the graphics device and the exact driver version used. QRhi |
9649 | takes care of adding the appropriate header and safeguards that ensure that |
9650 | the data can always be passed safely to setPipelineCacheData(), therefore |
9651 | attempting to load data from a run on another version of a driver will be |
9652 | handled safely and gracefully. |
9653 | |
9654 | \note Calling releaseCachedResources() may, depending on the backend, clear |
9655 | the pipeline data collected. A subsequent call to this function may then |
9656 | not return any data. |
9657 | |
9658 | See EnablePipelineCacheDataSave for further details about this feature. |
9659 | |
9660 | \note Minimize the number of calls to this function. Retrieving the blob is |
9661 | not always a cheap operation, and therefore this function should only be |
9662 | called at a low frequency, ideally only once e.g. when closing the |
9663 | application. |
9664 | |
9665 | \sa setPipelineCacheData(), create(), isFeatureSupported() |
9666 | */ |
9667 | QByteArray QRhi::pipelineCacheData() |
9668 | { |
9669 | return d->pipelineCacheData(); |
9670 | } |
9671 | |
9672 | /*! |
9673 | Loads \a data into the pipeline cache, when applicable. |
9674 | |
9675 | When the PipelineCacheDataLoadSave is reported as unsupported, the function |
9676 | is safe to call, but has no effect. |
9677 | |
9678 | The blob returned by pipelineCacheData() is always specific to the Qt |
9679 | version, the QRhi backend, and, in some cases, also to the graphics device, |
9680 | and a given version of the graphics driver. QRhi takes care of adding the |
9681 | appropriate header and safeguards that ensure that the data can always be |
9682 | passed safely to this function. If there is a mismatch, e.g. because the |
9683 | driver has been upgraded to a newer version, or because the data was |
9684 | generated from a different QRhi backend, a warning is printed and \a data |
9685 | is safely ignored. |
9686 | |
9687 | With Vulkan, this maps directly to VkPipelineCache. Calling this function |
9688 | creates a new Vulkan pipeline cache object, with its initial data sourced |
9689 | from \a data. The pipeline cache object is then used by all subsequently |
9690 | created QRhiGraphicsPipeline and QRhiComputePipeline objects, thus |
9691 | accelerating, potentially, the pipeline creation. |
9692 | |
9693 | With other APIs there is no real pipeline cache, but they may provide a |
9694 | cache with bytecode from shader compilations (D3D) or program binaries |
9695 | (OpenGL). In applications that perform a lot of shader compilation from |
9696 | source at run time this can provide a significant boost in subsequent runs |
9697 | if the "pipeline cache" is pre-seeded from an earlier run using this |
9698 | function. |
9699 | |
9700 | \note QRhi cannot give any guarantees that \a data has an effect on the |
9701 | pipeline and shader creation performance. With APIs like Vulkan, it is up |
9702 | to the driver to decide if \a data is used for some purpose, or if it is |
9703 | ignored. |
9704 | |
9705 | See EnablePipelineCacheDataSave for further details about this feature. |
9706 | |
9707 | \note This mechanism offered by QRhi is independent of the drivers' own |
9708 | internal caching mechanism, if any. This means that, depending on the |
9709 | graphics API and its implementation, the exact effects of retrieving and |
9710 | then reloading \a data are not predictable. Improved performance may not be |
9711 | visible at all in case other caching mechanisms outside of Qt's control are |
9712 | already active. |
9713 | |
9714 | \note Minimize the number of calls to this function. Loading the blob is |
9715 | not always a cheap operation, and therefore this function should only be |
9716 | called at a low frequency, ideally only once e.g. when starting the |
9717 | application. |
9718 | |
9719 | \sa pipelineCacheData(), isFeatureSupported() |
9720 | */ |
9721 | void QRhi::setPipelineCacheData(const QByteArray &data) |
9722 | { |
9723 | d->setPipelineCacheData(data); |
9724 | } |
9725 | |
9726 | /*! |
9727 | \struct QRhiStats |
9728 | \inmodule QtGui |
9729 | \since 6.6 |
9730 | |
9731 | \brief Statistics provided from the underlying memory allocator. |
9732 | |
9733 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
9734 | for details. |
9735 | */ |
9736 | |
9737 | /*! |
9738 | \variable QRhiStats::totalPipelineCreationTime |
9739 | |
9740 | The total time in milliseconds spent in graphics and compute pipeline |
9741 | creation, which usually involves shader compilation or cache lookups, and |
9742 | potentially expensive processing. |
9743 | |
9744 | \note The value should not be compared between different backends since the |
9745 | concept of "pipelines" and what exactly happens under the hood during, for |
9746 | instance, a call to QRhiGraphicsPipeline::create(), differ greatly between |
9747 | graphics APIs and their implementations. |
9748 | |
9749 | \sa QRhi::statistics() |
9750 | */ |
9751 | |
9752 | /*! |
9753 | \variable QRhiStats::blockCount |
9754 | |
9755 | Statistic reported from the Vulkan or D3D12 memory allocator. |
9756 | |
9757 | \sa QRhi::statistics() |
9758 | */ |
9759 | |
9760 | /*! |
9761 | \variable QRhiStats::allocCount |
9762 | |
9763 | Statistic reported from the Vulkan or D3D12 memory allocator. |
9764 | |
9765 | \sa QRhi::statistics() |
9766 | */ |
9767 | |
9768 | /*! |
9769 | \variable QRhiStats::usedBytes |
9770 | |
9771 | Statistic reported from the Vulkan or D3D12 memory allocator. |
9772 | |
9773 | \sa QRhi::statistics() |
9774 | */ |
9775 | |
9776 | /*! |
9777 | \variable QRhiStats::unusedBytes |
9778 | |
9779 | Statistic reported from the Vulkan or D3D12 memory allocator. |
9780 | |
9781 | \sa QRhi::statistics() |
9782 | */ |
9783 | |
9784 | /*! |
9785 | \variable QRhiStats::totalUsageBytes |
9786 | |
9787 | Valid only with D3D12 currently. Matches IDXGIAdapter3::QueryVideoMemoryInfo(). |
9788 | |
9789 | \sa QRhi::statistics() |
9790 | */ |
9791 | |
9792 | #ifndef QT_NO_DEBUG_STREAM |
9793 | QDebug operator<<(QDebug dbg, const QRhiStats &info) |
9794 | { |
9795 | QDebugStateSaver saver(dbg); |
9796 | dbg.nospace() << "QRhiStats(" |
9797 | << "totalPipelineCreationTime=" << info.totalPipelineCreationTime |
9798 | << " blockCount=" << info.blockCount |
9799 | << " allocCount=" << info.allocCount |
9800 | << " usedBytes=" << info.usedBytes |
9801 | << " unusedBytes=" << info.unusedBytes |
9802 | << " totalUsageBytes=" << info.totalUsageBytes |
9803 | << ')'; |
9804 | return dbg; |
9805 | } |
9806 | #endif |
9807 | |
9808 | /*! |
9809 | Gathers and returns statistics about the timings and allocations of |
9810 | graphics resources. |
9811 | |
9812 | Data about memory allocations is only available with some backends, where |
9813 | such operations are under Qt's control. With graphics APIs where there is |
9814 | no lower level control over resource memory allocations, this will never be |
9815 | supported and all relevant fields in the results are 0. |
9816 | |
9817 | With Vulkan in particular, the values are valid always, and are queried |
9818 | from the underlying memory allocator library. This gives an insight into |
9819 | the memory requirements of the active buffers and textures. |
9820 | |
9821 | The same is true for Direct 3D 12. In addition to the memory allocator |
9822 | library's statistics, here the result also includes a \c totalUsageBytes |
9823 | field which reports the total size including additional resources that are |
9824 | not under the memory allocator library's control (swapchain buffers, |
9825 | descriptor heaps, etc.), as reported by DXGI. |
9826 | |
9827 | The values correspond to all types of memory used, combined. (i.e. video + |
9828 | system in case of a discreet GPU) |
9829 | |
9830 | Additional data, such as the total time in milliseconds spent in graphics |
9831 | and compute pipeline creation (which usually involves shader compilation or |
9832 | cache lookups, and potentially expensive processing) is available with most |
9833 | backends. |
9834 | |
9835 | \note The elapsed times for operations such as pipeline creation may be |
9836 | affected by various factors. The results should not be compared between |
9837 | different backends since the concept of "pipelines" and what exactly |
9838 | happens under the hood during, for instance, a call to |
9839 | QRhiGraphicsPipeline::create(), differ greatly between graphics APIs and |
9840 | their implementations. |
9841 | |
9842 | \note Additionally, many drivers will likely employ various caching |
9843 | strategies for shaders, programs, pipelines. (independently of Qt's own |
9844 | similar facilities, such as setPipelineCacheData() or the OpenGL-specific |
9845 | program binary disk cache). Because such internal behavior is transparent |
9846 | to the API client, Qt and QRhi have no knowledge or control over the exact |
9847 | caching strategy, persistency, invalidation of the cached data, etc. When |
9848 | reading timings, such as the time spent on pipeline creation, the potential |
9849 | presence and unspecified behavior of driver-level caching mechanisms should |
9850 | be kept in mind. |
9851 | */ |
9852 | QRhiStats QRhi::statistics() const |
9853 | { |
9854 | return d->statistics(); |
9855 | } |
9856 | |
9857 | /*! |
9858 | \return a new graphics pipeline resource. |
9859 | |
9860 | \sa QRhiResource::destroy() |
9861 | */ |
9862 | QRhiGraphicsPipeline *QRhi::newGraphicsPipeline() |
9863 | { |
9864 | return d->createGraphicsPipeline(); |
9865 | } |
9866 | |
9867 | /*! |
9868 | \return a new compute pipeline resource. |
9869 | |
9870 | \note Compute is only available when the \l{QRhi::Compute}{Compute} feature |
9871 | is reported as supported. |
9872 | |
9873 | \sa QRhiResource::destroy() |
9874 | */ |
9875 | QRhiComputePipeline *QRhi::newComputePipeline() |
9876 | { |
9877 | return d->createComputePipeline(); |
9878 | } |
9879 | |
9880 | /*! |
9881 | \return a new shader resource binding collection resource. |
9882 | |
9883 | \sa QRhiResource::destroy() |
9884 | */ |
9885 | QRhiShaderResourceBindings *QRhi::newShaderResourceBindings() |
9886 | { |
9887 | return d->createShaderResourceBindings(); |
9888 | } |
9889 | |
9890 | /*! |
9891 | \return a new buffer with the specified \a type, \a usage, and \a size. |
9892 | |
9893 | \note Some \a usage and \a type combinations may not be supported by all |
9894 | backends. See \l{QRhiBuffer::UsageFlag}{UsageFlags} and |
9895 | \l{QRhi::NonDynamicUniformBuffers}{the feature flags}. |
9896 | |
9897 | \note Backends may choose to allocate buffers bigger than \a size. This is |
9898 | done transparently to applications, so there are no special restrictions on |
9899 | the value of \a size. QRhiBuffer::size() will always report back the value |
9900 | that was requested in \a size. |
9901 | |
9902 | \sa QRhiResource::destroy() |
9903 | */ |
9904 | QRhiBuffer *QRhi::newBuffer(QRhiBuffer::Type type, |
9905 | QRhiBuffer::UsageFlags usage, |
9906 | quint32 size) |
9907 | { |
9908 | return d->createBuffer(type, usage, size); |
9909 | } |
9910 | |
9911 | /*! |
9912 | \return a new renderbuffer with the specified \a type, \a pixelSize, \a |
9913 | sampleCount, and \a flags. |
9914 | |
9915 | When \a backingFormatHint is set to a texture format other than |
9916 | QRhiTexture::UnknownFormat, it may be used by the backend to decide what |
9917 | format to use for the storage backing the renderbuffer. |
9918 | |
9919 | \note \a backingFormatHint becomes relevant typically when multisampling |
9920 | and floating point texture formats are involved: rendering into a |
9921 | multisample QRhiRenderBuffer and then resolving into a non-RGBA8 |
9922 | QRhiTexture implies (with some graphics APIs) that the storage backing the |
9923 | QRhiRenderBuffer uses the matching non-RGBA8 format. That means that |
9924 | passing a format like QRhiTexture::RGBA32F is important, because backends |
9925 | will typically opt for QRhiTexture::RGBA8 by default, which would then |
9926 | break later on due to attempting to set up RGBA8->RGBA32F multisample |
9927 | resolve in the color attachment(s) of the QRhiTextureRenderTarget. |
9928 | |
9929 | \sa QRhiResource::destroy() |
9930 | */ |
9931 | QRhiRenderBuffer *QRhi::newRenderBuffer(QRhiRenderBuffer::Type type, |
9932 | const QSize &pixelSize, |
9933 | int sampleCount, |
9934 | QRhiRenderBuffer::Flags flags, |
9935 | QRhiTexture::Format backingFormatHint) |
9936 | { |
9937 | return d->createRenderBuffer(type, pixelSize, sampleCount, flags, backingFormatHint); |
9938 | } |
9939 | |
9940 | /*! |
9941 | \return a new 1D or 2D texture with the specified \a format, \a pixelSize, \a |
9942 | sampleCount, and \a flags. |
9943 | |
9944 | A 1D texture array must have QRhiTexture::OneDimensional set in \a flags. This |
9945 | function will implicitly set this flag if the \a pixelSize height is 0. |
9946 | |
9947 | \note \a format specifies the requested internal and external format, |
9948 | meaning the data to be uploaded to the texture will need to be in a |
9949 | compatible format, while the native texture may (but is not guaranteed to, |
9950 | in case of OpenGL at least) use this format internally. |
9951 | |
9952 | \note 1D textures are only functional when the OneDimensionalTextures feature is |
9953 | reported as supported at run time. Further, mipmaps on 1D textures are only |
9954 | functional when the OneDimensionalTextureMipmaps feature is reported at run time. |
9955 | |
9956 | \sa QRhiResource::destroy() |
9957 | */ |
9958 | QRhiTexture *QRhi::newTexture(QRhiTexture::Format format, |
9959 | const QSize &pixelSize, |
9960 | int sampleCount, |
9961 | QRhiTexture::Flags flags) |
9962 | { |
9963 | if (pixelSize.height() == 0) |
9964 | flags |= QRhiTexture::OneDimensional; |
9965 | |
9966 | return d->createTexture(format, pixelSize, depth: 1, arraySize: 0, sampleCount, flags); |
9967 | } |
9968 | |
9969 | /*! |
9970 | \return a new 1D, 2D or 3D texture with the specified \a format, \a width, \a |
9971 | height, \a depth, \a sampleCount, and \a flags. |
9972 | |
9973 | This overload is suitable for 3D textures because it allows specifying \a |
9974 | depth. A 3D texture must have QRhiTexture::ThreeDimensional set in \a |
9975 | flags, but using this overload that can be omitted because the flag is set |
9976 | implicitly whenever \a depth is greater than 0. For 1D, 2D and cube textures \a |
9977 | depth should be set to 0. |
9978 | |
9979 | A 1D texture must have QRhiTexture::OneDimensional set in \a flags. This overload |
9980 | will implicitly set this flag if both \a height and \a depth are 0. |
9981 | |
9982 | \note 3D textures are only functional when the ThreeDimensionalTextures |
9983 | feature is reported as supported at run time. |
9984 | |
9985 | \note 1D textures are only functional when the OneDimensionalTextures feature is |
9986 | reported as supported at run time. Further, mipmaps on 1D textures are only |
9987 | functional when the OneDimensionalTextureMipmaps feature is reported at run time. |
9988 | |
9989 | \overload |
9990 | */ |
9991 | QRhiTexture *QRhi::newTexture(QRhiTexture::Format format, |
9992 | int width, int height, int depth, |
9993 | int sampleCount, |
9994 | QRhiTexture::Flags flags) |
9995 | { |
9996 | if (depth > 0) |
9997 | flags |= QRhiTexture::ThreeDimensional; |
9998 | |
9999 | if (height == 0 && depth == 0) |
10000 | flags |= QRhiTexture::OneDimensional; |
10001 | |
10002 | return d->createTexture(format, pixelSize: QSize(width, height), depth, arraySize: 0, sampleCount, flags); |
10003 | } |
10004 | |
10005 | /*! |
10006 | \return a new 1D or 2D texture array with the specified \a format, \a arraySize, |
10007 | \a pixelSize, \a sampleCount, and \a flags. |
10008 | |
10009 | This function implicitly sets QRhiTexture::TextureArray in \a flags. |
10010 | |
10011 | A 1D texture array must have QRhiTexture::OneDimensional set in \a flags. This |
10012 | function will implicitly set this flag if the \a pixelSize height is 0. |
10013 | |
10014 | \note Do not confuse texture arrays with arrays of textures. A QRhiTexture |
10015 | created by this function is usable with 1D or 2D array samplers in the shader, for |
10016 | example: \c{layout(binding = 1) uniform sampler2DArray texArr;}. Arrays of |
10017 | textures refers to a list of textures that are exposed to the shader via |
10018 | QRhiShaderResourceBinding::sampledTextures() and a count > 1, and declared |
10019 | in the shader for example like this: \c{layout(binding = 1) uniform |
10020 | sampler2D textures[4];} |
10021 | |
10022 | \note This is only functional when the TextureArrays feature is reported as |
10023 | supported at run time. |
10024 | |
10025 | \note 1D textures are only functional when the OneDimensionalTextures feature is |
10026 | reported as supported at run time. Further, mipmaps on 1D textures are only |
10027 | functional when the OneDimensionalTextureMipmaps feature is reported at run time. |
10028 | |
10029 | |
10030 | \sa newTexture() |
10031 | */ |
10032 | QRhiTexture *QRhi::newTextureArray(QRhiTexture::Format format, |
10033 | int arraySize, |
10034 | const QSize &pixelSize, |
10035 | int sampleCount, |
10036 | QRhiTexture::Flags flags) |
10037 | { |
10038 | flags |= QRhiTexture::TextureArray; |
10039 | |
10040 | if (pixelSize.height() == 0) |
10041 | flags |= QRhiTexture::OneDimensional; |
10042 | |
10043 | return d->createTexture(format, pixelSize, depth: 1, arraySize, sampleCount, flags); |
10044 | } |
10045 | |
10046 | /*! |
10047 | \return a new sampler with the specified magnification filter \a magFilter, |
10048 | minification filter \a minFilter, mipmapping mode \a mipmapMode, and the |
10049 | addressing (wrap) modes \a addressU, \a addressV, and \a addressW. |
10050 | |
10051 | \note Setting \a mipmapMode to a value other than \c None implies that |
10052 | images for all relevant mip levels will be provided either via |
10053 | \l{QRhiResourceUpdateBatch::uploadTexture()}{texture uploads} or by calling |
10054 | \l{QRhiResourceUpdateBatch::generateMips()}{generateMips()} on the texture |
10055 | that is used with this sampler. Attempting to use the sampler with a |
10056 | texture that has no data for all relevant mip levels will lead to rendering |
10057 | errors, with the exact behavior dependent on the underlying graphics API. |
10058 | |
10059 | \sa QRhiResource::destroy() |
10060 | */ |
10061 | QRhiSampler *QRhi::newSampler(QRhiSampler::Filter magFilter, |
10062 | QRhiSampler::Filter minFilter, |
10063 | QRhiSampler::Filter mipmapMode, |
10064 | QRhiSampler::AddressMode addressU, |
10065 | QRhiSampler::AddressMode addressV, |
10066 | QRhiSampler::AddressMode addressW) |
10067 | { |
10068 | return d->createSampler(magFilter, minFilter, mipmapMode, u: addressU, v: addressV, w: addressW); |
10069 | } |
10070 | |
10071 | /*! |
10072 | \return a new texture render target with color and depth/stencil |
10073 | attachments given in \a desc, and with the specified \a flags. |
10074 | |
10075 | \sa QRhiResource::destroy() |
10076 | */ |
10077 | |
10078 | QRhiTextureRenderTarget *QRhi::newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, |
10079 | QRhiTextureRenderTarget::Flags flags) |
10080 | { |
10081 | return d->createTextureRenderTarget(desc, flags); |
10082 | } |
10083 | |
10084 | /*! |
10085 | \return a new swapchain. |
10086 | |
10087 | \sa QRhiResource::destroy(), QRhiSwapChain::createOrResize() |
10088 | */ |
10089 | QRhiSwapChain *QRhi::newSwapChain() |
10090 | { |
10091 | return d->createSwapChain(); |
10092 | } |
10093 | |
10094 | /*! |
10095 | Starts a new frame targeting the next available buffer of \a swapChain. |
10096 | |
10097 | A frame consists of resource updates and one or more render and compute |
10098 | passes. |
10099 | |
10100 | \a flags can indicate certain special cases. |
10101 | |
10102 | The high level pattern of rendering into a QWindow using a swapchain: |
10103 | |
10104 | \list |
10105 | |
10106 | \li Create a swapchain. |
10107 | |
10108 | \li Call QRhiSwapChain::createOrResize() whenever the surface size is |
10109 | different than before. |
10110 | |
10111 | \li Call QRhiSwapChain::destroy() on |
10112 | QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed. |
10113 | |
10114 | \li Then on every frame: |
10115 | \badcode |
10116 | beginFrame(sc); |
10117 | updates = nextResourceUpdateBatch(); |
10118 | updates->... |
10119 | QRhiCommandBuffer *cb = sc->currentFrameCommandBuffer(); |
10120 | cb->beginPass(sc->currentFrameRenderTarget(), colorClear, dsClear, updates); |
10121 | ... |
10122 | cb->endPass(); |
10123 | ... // more passes as necessary |
10124 | endFrame(sc); |
10125 | \endcode |
10126 | |
10127 | \endlist |
10128 | |
10129 | \return QRhi::FrameOpSuccess on success, or another QRhi::FrameOpResult |
10130 | value on failure. Some of these should be treated as soft, "try again |
10131 | later" type of errors: When QRhi::FrameOpSwapChainOutOfDate is returned, |
10132 | the swapchain is to be resized or updated by calling |
10133 | QRhiSwapChain::createOrResize(). The application should then attempt to |
10134 | generate a new frame. QRhi::FrameOpDeviceLost means the graphics device is |
10135 | lost but this may also be recoverable by releasing all resources, including |
10136 | the QRhi itself, and then recreating all resources. See isDeviceLost() for |
10137 | further discussion. |
10138 | |
10139 | \sa endFrame(), beginOffscreenFrame(), isDeviceLost() |
10140 | */ |
10141 | QRhi::FrameOpResult QRhi::beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags flags) |
10142 | { |
10143 | if (d->inFrame) |
10144 | qWarning(msg: "Attempted to call beginFrame() within a still active frame; ignored" ); |
10145 | |
10146 | QRhi::FrameOpResult r = !d->inFrame ? d->beginFrame(swapChain, flags) : FrameOpSuccess; |
10147 | if (r == FrameOpSuccess) |
10148 | d->inFrame = true; |
10149 | |
10150 | return r; |
10151 | } |
10152 | |
10153 | /*! |
10154 | Ends, commits, and presents a frame that was started in the last |
10155 | beginFrame() on \a swapChain. |
10156 | |
10157 | Double (or triple) buffering is managed internally by the QRhiSwapChain and |
10158 | QRhi. |
10159 | |
10160 | \a flags can optionally be used to change the behavior in certain ways. |
10161 | Passing QRhi::SkipPresent skips queuing the Present command or calling |
10162 | swapBuffers. |
10163 | |
10164 | \return QRhi::FrameOpSuccess on success, or another QRhi::FrameOpResult |
10165 | value on failure. Some of these should be treated as soft, "try again |
10166 | later" type of errors: When QRhi::FrameOpSwapChainOutOfDate is returned, |
10167 | the swapchain is to be resized or updated by calling |
10168 | QRhiSwapChain::createOrResize(). The application should then attempt to |
10169 | generate a new frame. QRhi::FrameOpDeviceLost means the graphics device is |
10170 | lost but this may also be recoverable by releasing all resources, including |
10171 | the QRhi itself, and then recreating all resources. See isDeviceLost() for |
10172 | further discussion. |
10173 | |
10174 | \sa beginFrame(), isDeviceLost() |
10175 | */ |
10176 | QRhi::FrameOpResult QRhi::endFrame(QRhiSwapChain *swapChain, EndFrameFlags flags) |
10177 | { |
10178 | if (!d->inFrame) |
10179 | qWarning(msg: "Attempted to call endFrame() without an active frame; ignored" ); |
10180 | |
10181 | QRhi::FrameOpResult r = d->inFrame ? d->endFrame(swapChain, flags) : FrameOpSuccess; |
10182 | d->inFrame = false; |
10183 | // deleteLater is a high level QRhi concept the backends know |
10184 | // nothing about - handle it here. |
10185 | qDeleteAll(c: d->pendingDeleteResources); |
10186 | d->pendingDeleteResources.clear(); |
10187 | |
10188 | return r; |
10189 | } |
10190 | |
10191 | /*! |
10192 | \return true when there is an active frame, meaning there was a |
10193 | beginFrame() (or beginOffscreenFrame()) with no corresponding endFrame() |
10194 | (or endOffscreenFrame()) yet. |
10195 | |
10196 | \sa currentFrameSlot(), beginFrame(), endFrame() |
10197 | */ |
10198 | bool QRhi::isRecordingFrame() const |
10199 | { |
10200 | return d->inFrame; |
10201 | } |
10202 | |
10203 | /*! |
10204 | \return the current frame slot index while recording a frame. Unspecified |
10205 | when called outside an active frame (that is, when isRecordingFrame() is \c |
10206 | false). |
10207 | |
10208 | With backends like Vulkan or Metal, it is the responsibility of the QRhi |
10209 | backend to block whenever starting a new frame and finding the CPU is |
10210 | already \c{FramesInFlight - 1} frames ahead of the GPU (because the command |
10211 | buffer submitted in frame no. \c{current} - \c{FramesInFlight} has not yet |
10212 | completed). |
10213 | |
10214 | Resources that tend to change between frames (such as, the native buffer |
10215 | object backing a QRhiBuffer with type QRhiBuffer::Dynamic) exist in |
10216 | multiple versions, so that each frame, that can be submitted while a |
10217 | previous one is still being processed, works with its own copy, thus |
10218 | avoiding the need to stall the pipeline when preparing the frame. (The |
10219 | contents of a resource that may still be in use in the GPU should not be |
10220 | touched, but simply always waiting for the previous frame to finish would |
10221 | reduce GPU utilization and ultimately, performance and efficiency.) |
10222 | |
10223 | Conceptually this is somewhat similar to copy-on-write schemes used by some |
10224 | C++ containers and other types. It may also be similar to what an OpenGL or |
10225 | Direct 3D 11 implementation performs internally for certain type of objects. |
10226 | |
10227 | In practice, such double (or triple) buffering resources is realized in |
10228 | the Vulkan, Metal, and similar QRhi backends by having a fixed number of |
10229 | native resource (such as, VkBuffer) \c slots behind a QRhiResource. That |
10230 | can then be indexed by a frame slot index running 0, 1, .., |
10231 | FramesInFlight-1, and then wrapping around. |
10232 | |
10233 | All this is managed transparently to the users of QRhi. However, |
10234 | applications that integrate rendering done directly with the graphics API |
10235 | may want to perform a similar double or triple buffering of their own |
10236 | graphics resources. That is then most easily achieved by knowing the values |
10237 | of the maximum number of in-flight frames (retrievable via resourceLimit()) |
10238 | and the current frame (slot) index (returned by this function). |
10239 | |
10240 | \sa isRecordingFrame(), beginFrame(), endFrame() |
10241 | */ |
10242 | int QRhi::currentFrameSlot() const |
10243 | { |
10244 | return d->currentFrameSlot; |
10245 | } |
10246 | |
10247 | /*! |
10248 | Starts a new offscreen frame. Provides a command buffer suitable for |
10249 | recording rendering commands in \a cb. \a flags is used to indicate |
10250 | certain special cases, just like with beginFrame(). |
10251 | |
10252 | \note The QRhiCommandBuffer stored to *cb is not owned by the caller. |
10253 | |
10254 | Rendering without a swapchain is possible as well. The typical use case is |
10255 | to use it in completely offscreen applications, e.g. to generate image |
10256 | sequences by rendering and reading back without ever showing a window. |
10257 | |
10258 | Usage in on-screen applications (so beginFrame, endFrame, |
10259 | beginOffscreenFrame, endOffscreenFrame, beginFrame, ...) is possible too |
10260 | but it does reduce parallelism so it should be done only infrequently. |
10261 | |
10262 | Offscreen frames do not let the CPU potentially generate another frame |
10263 | while the GPU is still processing the previous one. This has the side |
10264 | effect that if readbacks are scheduled, the results are guaranteed to be |
10265 | available once endOffscreenFrame() returns. That is not the case with |
10266 | frames targeting a swapchain: there the GPU is potentially better utilized, |
10267 | but working with readback operations needs more care from the application |
10268 | because endFrame(), unlike endOffscreenFrame(), does not guarantee that the |
10269 | results from the readback are available at that point. |
10270 | |
10271 | The skeleton of rendering a frame without a swapchain and then reading the |
10272 | frame contents back could look like the following: |
10273 | |
10274 | \code |
10275 | QRhiReadbackResult rbResult; |
10276 | QRhiCommandBuffer *cb; |
10277 | rhi->beginOffscreenFrame(&cb); |
10278 | cb->beginPass(rt, colorClear, dsClear); |
10279 | // ... |
10280 | u = nextResourceUpdateBatch(); |
10281 | u->readBackTexture(rb, &rbResult); |
10282 | cb->endPass(u); |
10283 | rhi->endOffscreenFrame(); |
10284 | // image data available in rbResult |
10285 | \endcode |
10286 | |
10287 | \sa endOffscreenFrame(), beginFrame() |
10288 | */ |
10289 | QRhi::FrameOpResult QRhi::beginOffscreenFrame(QRhiCommandBuffer **cb, BeginFrameFlags flags) |
10290 | { |
10291 | if (d->inFrame) |
10292 | qWarning(msg: "Attempted to call beginOffscreenFrame() within a still active frame; ignored" ); |
10293 | |
10294 | QRhi::FrameOpResult r = !d->inFrame ? d->beginOffscreenFrame(cb, flags) : FrameOpSuccess; |
10295 | if (r == FrameOpSuccess) |
10296 | d->inFrame = true; |
10297 | |
10298 | return r; |
10299 | } |
10300 | |
10301 | /*! |
10302 | Ends, submits, and waits for the offscreen frame. |
10303 | |
10304 | \a flags is not currently used. |
10305 | |
10306 | \sa beginOffscreenFrame() |
10307 | */ |
10308 | QRhi::FrameOpResult QRhi::endOffscreenFrame(EndFrameFlags flags) |
10309 | { |
10310 | if (!d->inFrame) |
10311 | qWarning(msg: "Attempted to call endOffscreenFrame() without an active frame; ignored" ); |
10312 | |
10313 | QRhi::FrameOpResult r = d->inFrame ? d->endOffscreenFrame(flags) : FrameOpSuccess; |
10314 | d->inFrame = false; |
10315 | qDeleteAll(c: d->pendingDeleteResources); |
10316 | d->pendingDeleteResources.clear(); |
10317 | |
10318 | return r; |
10319 | } |
10320 | |
10321 | /*! |
10322 | Waits for any work on the graphics queue (where applicable) to complete, |
10323 | then executes all deferred operations, like completing readbacks and |
10324 | resource releases. Can be called inside and outside of a frame, but not |
10325 | inside a pass. Inside a frame it implies submitting any work on the |
10326 | command buffer. |
10327 | |
10328 | \note Avoid this function. One case where it may be needed is when the |
10329 | results of an enqueued readback in a swapchain-based frame are needed at a |
10330 | fixed given point and so waiting for the results is desired. |
10331 | */ |
10332 | QRhi::FrameOpResult QRhi::finish() |
10333 | { |
10334 | return d->finish(); |
10335 | } |
10336 | |
10337 | /*! |
10338 | \return the list of supported sample counts. |
10339 | |
10340 | A typical example would be (1, 2, 4, 8). |
10341 | |
10342 | With some backend this list of supported values is fixed in advance, while |
10343 | with some others the (physical) device properties indicate what is |
10344 | supported at run time. |
10345 | |
10346 | \sa QRhiRenderBuffer::setSampleCount(), QRhiTexture::setSampleCount(), |
10347 | QRhiGraphicsPipeline::setSampleCount(), QRhiSwapChain::setSampleCount() |
10348 | */ |
10349 | QList<int> QRhi::supportedSampleCounts() const |
10350 | { |
10351 | return d->supportedSampleCounts(); |
10352 | } |
10353 | |
10354 | /*! |
10355 | \return the minimum uniform buffer offset alignment in bytes. This is |
10356 | typically 256. |
10357 | |
10358 | Attempting to bind a uniform buffer region with an offset not aligned to |
10359 | this value will lead to failures depending on the backend and the |
10360 | underlying graphics API. |
10361 | |
10362 | \sa ubufAligned() |
10363 | */ |
10364 | int QRhi::ubufAlignment() const |
10365 | { |
10366 | return d->ubufAlignment(); |
10367 | } |
10368 | |
10369 | Q_CONSTINIT static QBasicAtomicInteger<QRhiGlobalObjectIdGenerator::Type> counter = Q_BASIC_ATOMIC_INITIALIZER(0); |
10370 | |
10371 | QRhiGlobalObjectIdGenerator::Type QRhiGlobalObjectIdGenerator::newId() |
10372 | { |
10373 | return counter.fetchAndAddRelaxed(valueToAdd: 1) + 1; |
10374 | } |
10375 | |
10376 | bool QRhiPassResourceTracker::isEmpty() const |
10377 | { |
10378 | return m_buffers.isEmpty() && m_textures.isEmpty(); |
10379 | } |
10380 | |
10381 | void QRhiPassResourceTracker::reset() |
10382 | { |
10383 | m_buffers.clear(); |
10384 | m_textures.clear(); |
10385 | } |
10386 | |
10387 | static inline QRhiPassResourceTracker::BufferStage earlierStage(QRhiPassResourceTracker::BufferStage a, |
10388 | QRhiPassResourceTracker::BufferStage b) |
10389 | { |
10390 | return QRhiPassResourceTracker::BufferStage(qMin(a: int(a), b: int(b))); |
10391 | } |
10392 | |
10393 | void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage, |
10394 | const UsageState &state) |
10395 | { |
10396 | auto it = m_buffers.find(key: buf); |
10397 | if (it != m_buffers.end()) { |
10398 | if (it->access != *access) { |
10399 | const QByteArray name = buf->name(); |
10400 | qWarning(msg: "Buffer %p (%s) used with different accesses within the same pass, this is not allowed." , |
10401 | buf, name.constData()); |
10402 | return; |
10403 | } |
10404 | if (it->stage != *stage) { |
10405 | it->stage = earlierStage(a: it->stage, b: *stage); |
10406 | *stage = it->stage; |
10407 | } |
10408 | return; |
10409 | } |
10410 | |
10411 | Buffer b; |
10412 | b.slot = slot; |
10413 | b.access = *access; |
10414 | b.stage = *stage; |
10415 | b.stateAtPassBegin = state; // first use -> initial state |
10416 | m_buffers.insert(key: buf, value: b); |
10417 | } |
10418 | |
10419 | static inline QRhiPassResourceTracker::TextureStage earlierStage(QRhiPassResourceTracker::TextureStage a, |
10420 | QRhiPassResourceTracker::TextureStage b) |
10421 | { |
10422 | return QRhiPassResourceTracker::TextureStage(qMin(a: int(a), b: int(b))); |
10423 | } |
10424 | |
10425 | static inline bool isImageLoadStore(QRhiPassResourceTracker::TextureAccess access) |
10426 | { |
10427 | return access == QRhiPassResourceTracker::TexStorageLoad |
10428 | || access == QRhiPassResourceTracker::TexStorageStore |
10429 | || access == QRhiPassResourceTracker::TexStorageLoadStore; |
10430 | } |
10431 | |
10432 | void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage, |
10433 | const UsageState &state) |
10434 | { |
10435 | auto it = m_textures.find(key: tex); |
10436 | if (it != m_textures.end()) { |
10437 | if (it->access != *access) { |
10438 | // Different subresources of a texture may be used for both load |
10439 | // and store in the same pass. (think reading from one mip level |
10440 | // and writing to another one in a compute shader) This we can |
10441 | // handle by treating the entire resource as read-write. |
10442 | if (isImageLoadStore(access: it->access) && isImageLoadStore(access: *access)) { |
10443 | it->access = QRhiPassResourceTracker::TexStorageLoadStore; |
10444 | *access = it->access; |
10445 | } else { |
10446 | const QByteArray name = tex->name(); |
10447 | qWarning(msg: "Texture %p (%s) used with different accesses within the same pass, this is not allowed." , |
10448 | tex, name.constData()); |
10449 | } |
10450 | } |
10451 | if (it->stage != *stage) { |
10452 | it->stage = earlierStage(a: it->stage, b: *stage); |
10453 | *stage = it->stage; |
10454 | } |
10455 | return; |
10456 | } |
10457 | |
10458 | Texture t; |
10459 | t.access = *access; |
10460 | t.stage = *stage; |
10461 | t.stateAtPassBegin = state; // first use -> initial state |
10462 | m_textures.insert(key: tex, value: t); |
10463 | } |
10464 | |
10465 | QRhiPassResourceTracker::BufferStage QRhiPassResourceTracker::toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages) |
10466 | { |
10467 | // pick the earlier stage (as this is going to be dstAccessMask) |
10468 | if (stages.testFlag(flag: QRhiShaderResourceBinding::VertexStage)) |
10469 | return QRhiPassResourceTracker::BufVertexStage; |
10470 | if (stages.testFlag(flag: QRhiShaderResourceBinding::TessellationControlStage)) |
10471 | return QRhiPassResourceTracker::BufTCStage; |
10472 | if (stages.testFlag(flag: QRhiShaderResourceBinding::TessellationEvaluationStage)) |
10473 | return QRhiPassResourceTracker::BufTEStage; |
10474 | if (stages.testFlag(flag: QRhiShaderResourceBinding::FragmentStage)) |
10475 | return QRhiPassResourceTracker::BufFragmentStage; |
10476 | if (stages.testFlag(flag: QRhiShaderResourceBinding::ComputeStage)) |
10477 | return QRhiPassResourceTracker::BufComputeStage; |
10478 | if (stages.testFlag(flag: QRhiShaderResourceBinding::GeometryStage)) |
10479 | return QRhiPassResourceTracker::BufGeometryStage; |
10480 | |
10481 | Q_UNREACHABLE_RETURN(QRhiPassResourceTracker::BufVertexStage); |
10482 | } |
10483 | |
10484 | QRhiPassResourceTracker::TextureStage QRhiPassResourceTracker::toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages) |
10485 | { |
10486 | // pick the earlier stage (as this is going to be dstAccessMask) |
10487 | if (stages.testFlag(flag: QRhiShaderResourceBinding::VertexStage)) |
10488 | return QRhiPassResourceTracker::TexVertexStage; |
10489 | if (stages.testFlag(flag: QRhiShaderResourceBinding::TessellationControlStage)) |
10490 | return QRhiPassResourceTracker::TexTCStage; |
10491 | if (stages.testFlag(flag: QRhiShaderResourceBinding::TessellationEvaluationStage)) |
10492 | return QRhiPassResourceTracker::TexTEStage; |
10493 | if (stages.testFlag(flag: QRhiShaderResourceBinding::FragmentStage)) |
10494 | return QRhiPassResourceTracker::TexFragmentStage; |
10495 | if (stages.testFlag(flag: QRhiShaderResourceBinding::ComputeStage)) |
10496 | return QRhiPassResourceTracker::TexComputeStage; |
10497 | if (stages.testFlag(flag: QRhiShaderResourceBinding::GeometryStage)) |
10498 | return QRhiPassResourceTracker::TexGeometryStage; |
10499 | |
10500 | Q_UNREACHABLE_RETURN(QRhiPassResourceTracker::TexVertexStage); |
10501 | } |
10502 | |
10503 | QT_END_NAMESPACE |
10504 | |