1 | // Copyright (C) 2023 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qrhi_p.h" |
5 | #include <qmath.h> |
6 | #include <QLoggingCategory> |
7 | |
8 | #include "qrhinull_p.h" |
9 | #ifndef QT_NO_OPENGL |
10 | #include "qrhigles2_p.h" |
11 | #endif |
12 | #if QT_CONFIG(vulkan) |
13 | #include "qrhivulkan_p.h" |
14 | #endif |
15 | #ifdef Q_OS_WIN |
16 | #include "qrhid3d11_p.h" |
17 | #include "qrhid3d12_p.h" |
18 | #endif |
19 | #if QT_CONFIG(metal) |
20 | #include "qrhimetal_p.h" |
21 | #endif |
22 | |
23 | #include <memory> |
24 | |
25 | QT_BEGIN_NAMESPACE |
26 | |
27 | Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general") |
28 | Q_LOGGING_CATEGORY(QRHI_LOG_RUB, "qt.rhi.rub") |
29 | |
30 | /*! |
31 | \class QRhi |
32 | \ingroup painting-3D |
33 | \inmodule QtGuiPrivate |
34 | \inheaderfile rhi/qrhi.h |
35 | \since 6.6 |
36 | |
37 | \brief Accelerated 2D/3D graphics API abstraction. |
38 | |
39 | The Qt Rendering Hardware Interface is an abstraction for hardware accelerated |
40 | graphics APIs, such as, \l{https://www.khronos.org/opengl/}{OpenGL}, |
41 | \l{https://www.khronos.org/opengles/}{OpenGL ES}, |
42 | \l{https://docs.microsoft.com/en-us/windows/desktop/direct3d}{Direct3D}, |
43 | \l{https://developer.apple.com/metal/}{Metal}, and |
44 | \l{https://www.khronos.org/vulkan/}{Vulkan}. |
45 | |
46 | \warning The QRhi family of classes in the Qt Gui module, including QShader |
47 | and QShaderDescription, offer limited compatibility guarantees. There are |
48 | no source or binary compatibility guarantees for these classes, meaning the |
49 | API is only guaranteed to work with the Qt version the application was |
50 | developed against. Source incompatible changes are however aimed to be kept |
51 | at a minimum and will only be made in minor releases (6.7, 6.8, and so on). |
52 | To use these classes in an application, link to |
53 | \c{Qt::GuiPrivate} (if using CMake), and include the headers with the \c |
54 | rhi prefix, for example \c{#include <rhi/qrhi.h>}. |
55 | |
56 | Each QRhi instance is backed by a backend for a specific graphics API. The |
57 | selection of the backend is a run time choice and is up to the application |
58 | or library that creates the QRhi instance. Some backends are available on |
59 | multiple platforms (OpenGL, Vulkan, Null), while APIs specific to a given |
60 | platform are only available when running on the platform in question (Metal |
61 | on macOS/iOS, Direct3D on Windows). |
62 | |
63 | The available backends currently are: |
64 | |
65 | \list |
66 | |
67 | \li OpenGL 2.1 / OpenGL ES 2.0 or newer. Some extensions and newer core |
68 | specification features are utilized when present, for example to enable |
69 | multisample framebuffers or compute shaders. Operating in core profile |
70 | contexts is supported as well. If necessary, applications can query the |
71 | \l{QRhi::Feature}{feature flags} at runtime to check for features that are |
72 | not supported in the OpenGL context backing the QRhi. The OpenGL backend |
73 | builds on QOpenGLContext, QOpenGLFunctions, and the related cross-platform |
74 | infrastructure of the Qt GUI module. |
75 | |
76 | \li Direct3D 11.2 and newer (with DXGI 1.3 and newer), using Shader Model |
77 | 5.0 or newer. When the D3D runtime has no support for 11.2 features or |
78 | Shader Model 5.0, initialization using an accelerated graphics device will |
79 | fail, but using the |
80 | \l{https://learn.microsoft.com/en-us/windows/win32/direct3darticles/directx-warp}{software |
81 | adapter} is still an option. |
82 | |
83 | \li Direct3D 12 on Windows 10 version 1703 and newer, with Shader Model 5.0 |
84 | or newer. Qt requires ID3D12Device2 to be present, hence the requirement |
85 | for at least version 1703 of Windows 10. The D3D12 device is by default |
86 | created with specifying a minimum feature level of |
87 | \c{D3D_FEATURE_LEVEL_11_0}. |
88 | |
89 | \li Metal 1.2 or newer. |
90 | |
91 | \li Vulkan 1.0 or newer, optionally utilizing some Vulkan 1.1 level |
92 | features. |
93 | |
94 | \li Null, a "dummy" backend that issues no graphics calls at all. |
95 | |
96 | \endlist |
97 | |
98 | In order to allow shader code to be written once in Qt applications and |
99 | libraries, all shaders are expected to be written in a single language |
100 | which is then compiled into SPIR-V. Versions for various shading language |
101 | are then generated from that, together with reflection information (inputs, |
102 | outputs, shader resources). This is then packed into easily and efficiently |
103 | serializable QShader instances. The compilers and tools to generate such |
104 | shaders are not part of QRhi and the Qt GUI module, but the core classes |
105 | for using such shaders, QShader and QShaderDescription, are. The APIs and |
106 | tools for performing compilation and translation are part of the Qt Shader |
107 | Tools module. |
108 | |
109 | See the \l{RHI Window Example} for an introductory example of creating a |
110 | portable, cross-platform application that performs accelerated 3D rendering |
111 | onto a QWindow using QRhi. |
112 | |
113 | \section1 An Impression of the API |
114 | |
115 | To provide a quick look at the API with a short yet complete example that |
116 | does not involve window-related setup, the following is a complete, |
117 | runnable cross-platform application that renders 20 frames off-screen, and |
118 | then saves the generated images to files after reading back the texture |
119 | contents from the GPU. For an example that renders on-screen, which then |
120 | involves setting up a QWindow and a swapchain, refer to the |
121 | \l{RHI Window Example}. |
122 | |
123 | For brevity, the initialization of the QRhi is done based on the platform: |
124 | the sample code here chooses Direct 3D 12 on Windows, Metal on macOS and |
125 | iOS, and Vulkan otherwise. OpenGL and Direct 3D 11 are never used by this |
126 | application, but support for those could be introduced with a few |
127 | additional lines. |
128 | |
129 | \snippet rhioffscreen/main.cpp 0 |
130 | |
131 | The result of the application is 20 \c PNG images (frame0.png - |
132 | frame19.png). These contain a rotating triangle with varying opacity over a |
133 | green background. |
134 | |
135 | The vertex and fragment shaders are expected to be processed and packaged |
136 | into \c{.qsb} files. The Vulkan-compatible GLSL source code is the |
137 | following: |
138 | |
139 | \e color.vert |
140 | \snippet rhioffscreen/color.vert 0 |
141 | |
142 | \e color.frag |
143 | \snippet rhioffscreen/color.frag 0 |
144 | |
145 | To manually compile and transpile these shaders to a number of targets |
146 | (SPIR-V, HLSL, MSL, GLSL) and generate the \c{.qsb} files the application |
147 | loads at run time, run \c{qsb --qt6 color.vert -o color.vert.qsb} and |
148 | \c{qsb --qt6 color.frag -o color.frag.qsb}. Alternatively, the Qt Shader |
149 | Tools module offers build system integration for CMake, the |
150 | \c qt_add_shaders() CMake function, that can achieve the same at build time. |
151 | |
152 | \section1 Design Fundamentals |
153 | |
154 | A QRhi cannot be instantiated directly. Instead, use the create() |
155 | function. Delete the QRhi instance normally to release the graphics device. |
156 | |
157 | \section2 Resources |
158 | |
159 | Instances of classes deriving from QRhiResource, such as, QRhiBuffer, |
160 | QRhiTexture, etc., encapsulate zero, one, or more native graphics |
161 | resources. Instances of such classes are always created via the \c new |
162 | functions of the QRhi, such as, newBuffer(), newTexture(), |
163 | newTextureRenderTarget(), newSwapChain(). |
164 | |
165 | \code |
166 | QRhiBuffer *vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)); |
167 | if (!vbuf->create()) { error(); } |
168 | // ... |
169 | delete vbuf; |
170 | \endcode |
171 | |
172 | \list |
173 | |
174 | \li The returned value from functions like newBuffer() is always owned by |
175 | the caller. |
176 | |
177 | \li Just creating an instance of a QRhiResource subclass never allocates or |
178 | initializes any native resources. That is only done when calling the |
179 | \c create() function of a subclass, for example, QRhiBuffer::create() or |
180 | QRhiTexture::create(). |
181 | |
182 | \li The exceptions are |
183 | QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor(), |
184 | QRhiSwapChain::newCompatibleRenderPassDescriptor(), and |
185 | QRhiRenderPassDescriptor::newCompatibleRenderPassDescriptor(). There is no |
186 | \c create() operation for these and the returned object is immediately |
187 | active. |
188 | |
189 | \li The resource objects themselves are treated as immutable: once a |
190 | resource has create() called, changing any parameters via the setters, such as, |
191 | QRhiTexture::setPixelSize(), has no effect, unless the underlying native |
192 | resource is released and \c create() is called again. See more about resource |
193 | reuse in the sections below. |
194 | |
195 | \li The underlying native resources are scheduled for releasing by the |
196 | QRhiResource destructor, or by calling QRhiResource::destroy(). Backends |
197 | often queue release requests and defer executing them to an unspecified |
198 | time, this is hidden from the applications. This way applications do not |
199 | have to worry about releasing native resources that may still be in use by |
200 | an in-flight frame. |
201 | |
202 | \li Note that this does not mean that a QRhiResource can freely be |
203 | destroy()'ed or deleted within a frame (that is, in a |
204 | \l{QRhi::beginFrame()}{beginFrame()} - \l{QRhi::endFrame()}{endFrame()} |
205 | section). As a general rule, all referenced QRhiResource objects must stay |
206 | unchanged until the frame is submitted by calling |
207 | \l{QRhi::endFrame()}{endFrame()}. To ease this, |
208 | QRhiResource::deleteLater() is provided as a convenience. |
209 | |
210 | \endlist |
211 | |
212 | \section2 Command buffers and deferred command execution |
213 | |
214 | Regardless of the design and capabilities of the underlying graphics API, |
215 | all QRhi backends implement some level of command buffers. No |
216 | QRhiCommandBuffer function issues any native bind or draw command (such as, |
217 | \c glDrawElements) directly. Commands are always recorded in a queue, |
218 | either native or provided by the QRhi backend. The command buffer is |
219 | submitted, and so execution starts only upon QRhi::endFrame() or |
220 | QRhi::finish(). |
221 | |
222 | The deferred nature has consequences for some types of objects. For example, |
223 | writing to a dynamic buffer multiple times within a frame, in case such |
224 | buffers are backed by host-visible memory, will result in making the |
225 | results of all writes are visible to all draw calls in the command buffer |
226 | of the frame, regardless of when the dynamic buffer update was recorded |
227 | relative to a draw call. |
228 | |
229 | Furthermore, instances of QRhiResource subclasses must be treated immutable |
230 | within a frame in which they are referenced in any way. Create |
231 | all resources upfront, before starting to record commands for the next |
232 | frame. Reusing a QRhiResource instance within a frame (by calling \c create() |
233 | then referencing it again in the same \c{beginFrame - endFrame} section) |
234 | should be avoided as it may lead to unexpected results, depending on the |
235 | backend. |
236 | |
237 | As a general rule, all referenced QRhiResource objects must stay valid and |
238 | unmodified until the frame is submitted by calling |
239 | \l{QRhi::endFrame()}{endFrame()}. On the other hand, calling |
240 | \l{QRhiResource::destroy()}{destroy()} or deleting the QRhiResource are |
241 | always safe once the frame is submitted, regardless of the status of the |
242 | underlying native resources (which may still be in use by the GPU - but |
243 | that is taken care of internally). |
244 | |
245 | Unlike APIs like OpenGL, upload and copy type of commands cannot be mixed |
246 | with draw commands. The typical renderer will involve a sequence similar to |
247 | the following: |
248 | |
249 | \list |
250 | \li (re)create resources |
251 | \li begin frame |
252 | \li record/issue uploads and copies |
253 | \li start recording a render pass |
254 | \li record draw calls |
255 | \li end render pass |
256 | \li end frame |
257 | \endlist |
258 | |
259 | Recording copy type of operations happens via QRhiResourceUpdateBatch. Such |
260 | operations are committed typically on |
261 | \l{QRhiCommandBuffer::beginPass()}{beginPass()}. |
262 | |
263 | When working with legacy rendering engines designed for OpenGL, the |
264 | migration to QRhi often involves redesigning from having a single \c render |
265 | step (that performs copies and uploads, clears buffers, and issues draw |
266 | calls, all mixed together) to a clearly separated, two phase \c prepare - |
267 | \c render setup where the \c render step only starts a renderpass and |
268 | records draw calls, while all resource creation and queuing of updates, |
269 | uploads and copies happens beforehand, in the \c prepare step. |
270 | |
271 | QRhi does not at the moment allow freely creating and submitting command |
272 | buffers. This may be lifted in the future to some extent, in particular if |
273 | compute support is introduced, but the model of well defined |
274 | \c{frame-start} and \c{frame-end} points, combined with a dedicated, |
275 | "frame" command buffer, where \c{frame-end} implies presenting, is going to |
276 | remain the primary way of operating since this is what fits Qt's various UI |
277 | technologies best. |
278 | |
279 | \section2 Threading |
280 | |
281 | A QRhi instance and the associated resources can be created and used on any |
282 | thread but all usage must be limited to that one single thread. When |
283 | rendering to multiple QWindows in an application, having a dedicated thread |
284 | and QRhi instance for each window is often advisable, as this can eliminate |
285 | issues with unexpected throttling caused by presenting to multiple windows. |
286 | Conceptually that is then the same as how Qt Quick scene graph's threaded |
287 | render loop operates when working directly with OpenGL: one thread for each |
288 | window, one QOpenGLContext for each thread. When moving onto QRhi, |
289 | QOpenGLContext is replaced by QRhi, making the migration straightforward. |
290 | |
291 | When it comes to externally created native objects, such as OpenGL contexts |
292 | passed in via QRhiGles2NativeHandles, it is up to the application to ensure |
293 | they are not misused by other threads. |
294 | |
295 | Resources are not shareable between QRhi instances. This is an intentional |
296 | choice since QRhi hides most queue, command buffer, and resource |
297 | synchronization related tasks, and provides no API for them. Safe and |
298 | efficient concurrent use of graphics resources from multiple threads is |
299 | tied to those concepts, however, and is thus a topic that is currently out |
300 | of scope, but may be introduced in the future. |
301 | |
302 | \note The Metal backend requires that an autorelease pool is available on |
303 | the rendering thread, ideally wrapping each iteration of the render loop. |
304 | This needs no action from the users of QRhi when rendering on the main |
305 | (gui) thread, but becomes important when a separate, dedicated render |
306 | thread is used. |
307 | |
308 | \section2 Resource synchronization |
309 | |
310 | QRhi does not expose APIs for resource barriers or image layout |
311 | transitions. Such synchronization is done implicitly by the backends, where |
312 | applicable (for example, Vulkan), by tracking resource usage as necessary. |
313 | Buffer and image barriers are inserted before render or compute passes |
314 | transparently to the application. |
315 | |
316 | \note Resources within a render or compute pass are expected to be bound to |
317 | a single usage during that pass. For example, a buffer can be used as |
318 | vertex, index, uniform, or storage buffer, but not a combination of them |
319 | within a single pass. However, it is perfectly fine to use a buffer as a |
320 | storage buffer in a compute pass, and then as a vertex buffer in a render |
321 | pass, for example, assuming the buffer declared both usages upon creation. |
322 | |
323 | \note Textures have this rule relaxed in certain cases, because using two |
324 | subresources (typically two different mip levels) of the same texture for |
325 | different access (one for load, one for store) is supported even within the |
326 | same pass. |
327 | |
328 | \section2 Resource reuse |
329 | |
330 | From the user's point of view a QRhiResource is reusable immediately after |
331 | calling QRhiResource::destroy(). With the exception of swapchains, calling |
332 | \c create() on an already created object does an implicit \c destroy(). This |
333 | provides a handy shortcut to reuse a QRhiResource instance with different |
334 | parameters, with a new native graphics object underneath. |
335 | |
336 | The importance of reusing the same object lies in the fact that some |
337 | objects reference other objects: for example, a QRhiShaderResourceBindings |
338 | can reference QRhiBuffer, QRhiTexture, and QRhiSampler instances. If in a |
339 | later frame one of these buffers need to be resized or a sampler parameter |
340 | needs changing, destroying and creating a whole new QRhiBuffer or |
341 | QRhiSampler would invalidate all references to the old instance. By just |
342 | changing the appropriate parameters via QRhiBuffer::setSize() or similar |
343 | and then calling QRhiBuffer::create(), everything works as expected and |
344 | there is no need to touch the QRhiShaderResourceBindings at all, even |
345 | though there is a good chance that under the hood the QRhiBuffer is now |
346 | backed by a whole new native buffer. |
347 | |
348 | \code |
349 | QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256); |
350 | ubuf->create(); |
351 | |
352 | QRhiShaderResourceBindings *srb = rhi->newShaderResourceBindings() |
353 | srb->setBindings({ |
354 | QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, ubuf) |
355 | }); |
356 | srb->create(); |
357 | |
358 | // ... |
359 | |
360 | // now in a later frame we need to grow the buffer to a larger size |
361 | ubuf->setSize(512); |
362 | ubuf->create(); // same as ubuf->destroy(); ubuf->create(); |
363 | |
364 | // srb needs no changes whatsoever, any references in it to ubuf |
365 | // stay valid. When it comes to internal details, such as that |
366 | // ubuf may now be backed by a completely different native buffer |
367 | // resource, that is is recognized and handled automatically by the |
368 | // next setShaderResources(). |
369 | \endcode |
370 | |
371 | QRhiTextureRenderTarget offers the same contract: calling |
372 | QRhiCommandBuffer::beginPass() is safe even when one of the render target's |
373 | associated textures or renderbuffers has been rebuilt (by calling \c |
374 | create() on it) since the creation of the render target object. This allows |
375 | the application to resize a texture by setting a new pixel size on the |
376 | QRhiTexture and calling create(), thus creating a whole new native texture |
377 | resource underneath, without having to update the QRhiTextureRenderTarget |
378 | as that will be done implicitly in beginPass(). |
379 | |
380 | \section2 Pooled objects |
381 | |
382 | In addition to resources, there are pooled objects as well, such as, |
383 | QRhiResourceUpdateBatch. An instance is retrieved via a \c next function, |
384 | such as, nextResourceUpdateBatch(). The caller does not own the returned |
385 | instance in this case. The only valid way of operating here is calling |
386 | functions on the QRhiResourceUpdateBatch and then passing it to |
387 | QRhiCommandBuffer::beginPass() or QRhiCommandBuffer::endPass(). These |
388 | functions take care of returning the batch to the pool. Alternatively, a |
389 | batch can be "canceled" and returned to the pool without processing by |
390 | calling QRhiResourceUpdateBatch::release(). |
391 | |
392 | A typical pattern is thus: |
393 | |
394 | \code |
395 | QRhiResourceUpdateBatch *resUpdates = rhi->nextResourceUpdateBatch(); |
396 | // ... |
397 | resUpdates->updateDynamicBuffer(ubuf, 0, 64, mvp.constData()); |
398 | if (!image.isNull()) { |
399 | resUpdates->uploadTexture(texture, image); |
400 | image = QImage(); |
401 | } |
402 | // ... |
403 | QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); |
404 | // note the last argument |
405 | cb->beginPass(swapchain->currentFrameRenderTarget(), clearCol, clearDs, resUpdates); |
406 | \endcode |
407 | |
408 | \section2 Swapchain specifics |
409 | |
410 | QRhiSwapChain features some special semantics due to the peculiar nature of |
411 | swapchains. |
412 | |
413 | \list |
414 | |
415 | \li It has no \c create() but rather a QRhiSwapChain::createOrResize(). |
416 | Repeatedly calling this function is \b not the same as calling |
417 | QRhiSwapChain::destroy() followed by QRhiSwapChain::createOrResize(). This |
418 | is because swapchains often have ways to handle the case where buffers need |
419 | to be resized in a manner that is more efficient than a brute force |
420 | destroying and recreating from scratch. |
421 | |
422 | \li An active QRhiSwapChain must be released by calling |
423 | \l{QRhiSwapChain::destroy()}{destroy()}, or by destroying the object, before |
424 | the QWindow's underlying QPlatformWindow, and so the associated native |
425 | window object, is destroyed. It should not be postponed because releasing |
426 | the swapchain may become problematic (and with some APIs, like Vulkan, is |
427 | explicitly disallowed) when the native window is not around anymore, for |
428 | example because the QPlatformWindow got destroyed upon getting a |
429 | QWindow::close(). Therefore, releasing the swapchain must happen whenever |
430 | the targeted QWindow sends the |
431 | QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed event. If the event does |
432 | not arrive before the destruction of the QWindow - this can happen when |
433 | using QCoreApplication::quit() -, then check QWindow::handle() after the |
434 | event loop exits and invoke the swapchain release when non-null (meaning |
435 | the underlying native window is still around). |
436 | |
437 | \endlist |
438 | |
439 | \section2 Ownership |
440 | |
441 | The general rule is no ownership transfer. Creating a QRhi with an already |
442 | existing graphics device does not mean the QRhi takes ownership of the |
443 | device object. Similarly, ownership is not given away when a device or |
444 | texture object is "exported" via QRhi::nativeHandles() or |
445 | QRhiTexture::nativeTexture(). Most importantly, passing pointers in structs |
446 | and via setters does not transfer ownership. |
447 | |
448 | \section1 Troubleshooting and Profiling |
449 | |
450 | \section2 Error reporting |
451 | |
452 | Functions such as \l QRhi::create() and the resource classes' \c create() |
453 | member functions (e.g., \l QRhiBuffer::create()) indicate failure with the |
454 | return value (\nullptr or |
455 | \c false, respectively). When working with QShader, \l QShader::fromSerialized() |
456 | returns an invalid QShader (for which \l{QShader::isValid()}{isValid()} returns |
457 | \c false) when the data passed to the function cannot be successfully deserialized. |
458 | Some functions, beginFrame() in particular, may also sometimes report "soft failures", |
459 | such as \l FrameOpSwapChainOutOfDate, which do not indicate an unrecoverable error, |
460 | but rather should be seen as a "try again later" response. |
461 | |
462 | Warnings and errors may get printed at any time to the debug output via |
463 | qWarning(). It is therefore always advisable to inspect the output of the |
464 | application. |
465 | |
466 | Additional debug messages can be enabled via the following logging |
467 | categories. Messages from these categories are not printed by default |
468 | unless explicitly enabled via QLoggingCategory or the \c QT_LOGGING_RULES |
469 | environment variable. For better interoperation with Qt Quick, the |
470 | environment variable \c{QSG_INFO} also enables these debug prints. |
471 | |
472 | \list |
473 | \li \c{qt.rhi.general} |
474 | \endlist |
475 | |
476 | Additionally, applications can query the \l{QRhi::backendName()}{QRhi |
477 | backend name} and |
478 | \l{QRhi::driverInfo()}{graphics device information} from a successfully |
479 | initialized QRhi. This can then be printed to the user or stored in the |
480 | application logs even in production builds, if desired. |
481 | |
482 | \section2 Investigating rendering problems |
483 | |
484 | When the rendering results are not as expected, or the application is |
485 | experiencing problems, always consider checking with the the native 3D |
486 | APIs' debug and validation facilities. QRhi itself features limited error |
487 | checking since replicating the already existing, vast amount of |
488 | functionality in the underlying layers is not reasonable. |
489 | |
490 | \list |
491 | |
492 | \li For Vulkan, controlling the |
493 | \l{https://github.com/KhronosGroup/Vulkan-ValidationLayers}{Vulkan |
494 | Validation Layers} is not in the scope of the QRhi, but rather can be |
495 | achieved by configuring the \l QVulkanInstance with the appropriate layers. |
496 | For example, call \c{instance.setLayers({ "VK_LAYER_KHRONOS_validation" });} |
497 | before invoking \l{QVulkanInstance::create()}{create()} on the QVulkanInstance. |
498 | (note that this assumes that the validation layers are actually installed |
499 | and available, e.g. from the Vulkan SDK) By default, QVulkanInstance conveniently |
500 | redirects the Vulkan debug messages to qDebug, meaning the validation messages get |
501 | printed just like other Qt warnings. |
502 | |
503 | \li With Direct 3D 11 and 12, a graphics device with the debug layer |
504 | enabled can be requested by toggling the \c enableDebugLayer flag in the |
505 | appropriate \l{QRhiD3D11InitParams}{init params struct}. The messages appear on the |
506 | debug output, which is visible in Qt Creator's messages panel or via a tool |
507 | such as \l{https://learn.microsoft.com/en-us/sysinternals/downloads/debugview}{DebugView}. |
508 | |
509 | \li For Metal, controlling Metal Validation is outside of QRhi's scope. |
510 | Rather, to enable validation, run the application with the environment |
511 | variable \c{METAL_DEVICE_WRAPPER_TYPE=1} set, or run the application within |
512 | XCode. There may also be further settings and environment variable in modern |
513 | XCode and macOS versions. See for instance |
514 | \l{https://developer.apple.com/documentation/metal/diagnosing_metal_programming_issues_early}{this |
515 | page}. |
516 | |
517 | \endlist |
518 | |
519 | \section2 Frame captures and performance profiling |
520 | |
521 | A Qt application rendering with QRhi to a window while relying on a 3D API |
522 | under the hood, is, from the windowing and graphics pipeline perspective at |
523 | least, no different from any other (non-Qt) applications using the same 3D |
524 | API. This means that tools and practices for debugging and profiling |
525 | applications involving 3D graphics, such as games, all apply to such a Qt |
526 | application as well. |
527 | |
528 | A few examples of tools that can provide insights into the rendering |
529 | internals of Qt applications that use QRhi, which includes Qt Quick and Qt |
530 | Quick 3D based projects as well: |
531 | |
532 | \list |
533 | |
534 | \li \l{https://renderdoc.org/}{RenderDoc} allows taking frame captures and |
535 | introspecting the recorded commands and pipeline state on Windows and Linux |
536 | for applications using OpenGL, Vulkan, D3D11, or D3D12. When trying to |
537 | figure out why some parts of the 3D scene do not show up as expected, |
538 | RenderDoc is often a fast and efficient way to check the pipeline stages |
539 | and the related state and discover the missing or incorrect value. It is |
540 | also a tool that is actively used when developing Qt itself. |
541 | |
542 | \li For NVIDIA-based systems, |
543 | \l{https://developer.nvidia.com/nsight-graphics}{Nsight Graphics} provides |
544 | a graphics debugger tool on Windows and Linux. In addition to investigating the commands |
545 | in the frame and the pipeline, the vendor-specific tools allow looking at timings and |
546 | hardware performance information, which is not something simple frame captures can provide. |
547 | |
548 | \li For AMD-based systems, the \l{https://gpuopen.com/rgp/}{Radeon GPU |
549 | Profiler} can be used to gain deeper insights into the application's |
550 | rendering and its performance. |
551 | |
552 | \li As QRhi supports Direct 3D 12, using |
553 | \l{https://devblogs.microsoft.com/pix/download/}{PIX}, a performance tuning |
554 | and debugging tool for DirectX 12 games on Windows is an option as well. |
555 | |
556 | \li On macOS, |
557 | \l{https://developer.apple.com/documentation/metal/debugging_tools/viewing_your_gpu_workload_with_the_metal_debugger}{the |
558 | XCode Metal debugger} can be used to take and introspect frame |
559 | captures, to investigate performance details, and debug shaders. In macOS 13 it is also possible |
560 | to enable an overlay that displays frame rate and other information for any Metal-based window by |
561 | setting the environment variable \c{MTL_HUD_ENABLED=1}. |
562 | |
563 | \endlist |
564 | |
565 | On mobile and embedded platforms, there may be vendor and platform-specific |
566 | tools, provided by the GPU or SoC vendor, available to perform performance |
567 | profiling of application using OpenGL ES or Vulkan. |
568 | |
569 | When capturing frames, remember that objects and groups of commands can be |
570 | named via debug markers, as long as \l{QRhi::EnableDebugMarkers}{debug |
571 | markers were enabled} for the QRhi, and the graphics API in use supports |
572 | this. To annotate the command stream, call |
573 | \l{QRhiCommandBuffer::debugMarkBegin()}{debugMarkBegin()}, |
574 | \l{QRhiCommandBuffer::debugMarkEnd()}{debugMarkEnd()} and/or |
575 | \l{QRhiCommandBuffer::debugMarkMsg()}{debugMarkMsg()}. |
576 | This can be particularly useful in larger frames with multiple render passes. |
577 | Resources are named by calling \l{QRhiResource::setName()}{setName()} before create(). |
578 | |
579 | To perform basic timing measurements on the CPU and GPU side within the |
580 | application, \l QElapsedTimer and |
581 | \l QRhiCommandBuffer::lastCompletedGpuTime() can be used. The latter is |
582 | only available with select graphics APIs at the moment and requires opting |
583 | in via the \l QRhi::EnableTimestamps flag. |
584 | |
585 | \section2 Resource leak checking |
586 | |
587 | When destroying a QRhi object without properly destroying all buffers, |
588 | textures, and other resources created from it, warnings about this are |
589 | printed to the debug output whenever the application is a debug build, or |
590 | when the \c QT_RHI_LEAK_CHECK environment variable is set to a non-zero |
591 | value. This is a simple way to discover design issues around resource |
592 | handling within the application rendering logic. Note however that some |
593 | platforms and underlying graphics APIs may perform their own allocation and |
594 | resource leak detection as well, over which Qt will have no direct control. |
595 | For example, when using Vulkan, the memory allocator may raise failing |
596 | assertions in debug builds when resources that own graphics memory |
597 | allocations are not destroyed before the QRhi. In addition, the Vulkan |
598 | validation layer, when enabled, will issue warnings about native graphics |
599 | resources that were not released. Similarly, with Direct 3D warnings may |
600 | get printed about unreleased COM objects when the application does not |
601 | destroy the QRhi and its resources in the correct order. |
602 | |
603 | \sa {RHI Window Example}, QRhiCommandBuffer, QRhiResourceUpdateBatch, |
604 | QRhiShaderResourceBindings, QShader, QRhiBuffer, QRhiTexture, |
605 | QRhiRenderBuffer, QRhiSampler, QRhiTextureRenderTarget, |
606 | QRhiGraphicsPipeline, QRhiComputePipeline, QRhiSwapChain |
607 | */ |
608 | |
609 | /*! |
610 | \enum QRhi::Implementation |
611 | Describes which graphics API-specific backend gets used by a QRhi instance. |
612 | |
613 | \value Null |
614 | \value Vulkan |
615 | \value OpenGLES2 |
616 | \value D3D11 |
617 | \value D3D12 |
618 | \value Metal |
619 | */ |
620 | |
621 | /*! |
622 | \enum QRhi::Flag |
623 | Describes what special features to enable. |
624 | |
625 | \value EnableDebugMarkers Enables debug marker groups. Without this frame |
626 | debugging features like making debug groups and custom resource name |
627 | visible in external GPU debugging tools will not be available and functions |
628 | like QRhiCommandBuffer::debugMarkBegin() will become no-ops. Avoid enabling |
629 | in production builds as it may involve a small performance impact. Has no |
630 | effect when the QRhi::DebugMarkers feature is not reported as supported. |
631 | |
632 | \value EnableTimestamps Enables GPU timestamp collection. When not set, |
633 | QRhiCommandBuffer::lastCompletedGpuTime() always returns 0. Enable this |
634 | only when needed since there may be a small amount of extra work involved |
635 | (e.g. timestamp queries), depending on the underlying graphics API. Has no |
636 | effect when the QRhi::Timestamps feature is not reported as supported. |
637 | |
638 | \value PreferSoftwareRenderer Indicates that backends should prefer |
639 | choosing an adapter or physical device that renders in software on the CPU. |
640 | For example, with Direct3D there is typically a "Basic Render Driver" |
641 | adapter available with \c{DXGI_ADAPTER_FLAG_SOFTWARE}. Setting this flag |
642 | requests the backend to choose that adapter over any other, as long as no |
643 | specific adapter was forced by other backend-specific means. With Vulkan |
644 | this maps to preferring physical devices with |
645 | \c{VK_PHYSICAL_DEVICE_TYPE_CPU}. When not available, or when it is not |
646 | possible to decide if an adapter/device is software-based, this flag is |
647 | ignored. It may also be ignored with graphics APIs that have no concept and |
648 | means of enumerating adapters/devices. |
649 | |
650 | \value EnablePipelineCacheDataSave Enables retrieving the pipeline cache |
651 | contents, where applicable. When not set, pipelineCacheData() will return |
652 | an empty blob always. With backends where retrieving and restoring the |
653 | pipeline cache contents is not supported, the flag has no effect and the |
654 | serialized cache data is always empty. The flag provides an opt-in |
655 | mechanism because the cost of maintaining the related data structures is |
656 | not insignificant with some backends. With Vulkan this feature maps |
657 | directly to VkPipelineCache, vkGetPipelineCacheData and |
658 | VkPipelineCacheCreateInfo::pInitialData. With Direct3D 11 there is no real |
659 | pipline cache, but the results of HLSL->DXBC compilations are stored and |
660 | can be serialized/deserialized via this mechanism. This allows skipping the |
661 | time consuming D3DCompile() in future runs of the applications for shaders |
662 | that come with HLSL source instead of offline pre-compiled bytecode. This |
663 | can provide a huge boost in startup and load times, if there is a lot of |
664 | HLSL source compilation happening. With OpenGL the "pipeline cache" is |
665 | simulated by retrieving and loading shader program binaries (if supported |
666 | by the driver). With OpenGL there are additional, disk-based caching |
667 | mechanisms for shader/program binaries provided by Qt. Writing to those may |
668 | get disabled whenever this flag is set since storing program binaries to |
669 | multiple caches is not sensible. |
670 | |
671 | \value SuppressSmokeTestWarnings Indicates that, with backends where this |
672 | is relevant, certain, non-fatal QRhi::create() failures should not |
673 | produce qWarning() calls. For example, with D3D11, passing this flag |
674 | makes a number of warning messages (that appear due to QRhi::create() |
675 | failing) to become categorized debug prints instead under the commonly used |
676 | \c{qt.rhi.general} logging category. This can be used by engines, such as |
677 | Qt Quick, that feature fallback logic, i.e. they retry calling create() |
678 | with a different set of flags (such as, \l PreferSoftwareRenderer), in order |
679 | to hide the unconditional warnings from the output that would be printed |
680 | when the first create() attempt had failed. |
681 | */ |
682 | |
683 | /*! |
684 | \enum QRhi::FrameOpResult |
685 | Describes the result of operations that can have a soft failure. |
686 | |
687 | \value FrameOpSuccess Success |
688 | |
689 | \value FrameOpError Unspecified error |
690 | |
691 | \value FrameOpSwapChainOutOfDate The swapchain is in an inconsistent state |
692 | internally. This can be recoverable by attempting to repeat the operation |
693 | (such as, beginFrame()) later. |
694 | |
695 | \value FrameOpDeviceLost The graphics device was lost. This can be |
696 | recoverable by attempting to repeat the operation (such as, beginFrame()) |
697 | after releasing and reinitializing all objects backed by native graphics |
698 | resources. See isDeviceLost(). |
699 | */ |
700 | |
701 | /*! |
702 | \enum QRhi::Feature |
703 | Flag values to indicate what features are supported by the backend currently in use. |
704 | |
705 | \value MultisampleTexture Indicates that textures with a sample count larger |
706 | than 1 are supported. In practice this feature will be unsupported with |
707 | OpenGL ES versions older than 3.1, and OpenGL older than 3.0. |
708 | |
709 | \value MultisampleRenderBuffer Indicates that renderbuffers with a sample |
710 | count larger than 1 are supported. In practice this feature will be |
711 | unsupported with OpenGL ES 2.0, and may also be unsupported with OpenGL 2.x |
712 | unless the relevant extensions are present. |
713 | |
714 | \value DebugMarkers Indicates that debug marker groups (and so |
715 | QRhiCommandBuffer::debugMarkBegin()) are supported. |
716 | |
717 | \value Timestamps Indicates that command buffer timestamps are supported. |
718 | Relevant for QRhiCommandBuffer::lastCompletedGpuTime(). This can be |
719 | expected to be supported on Metal, Vulkan, Direct 3D 11 and 12, and OpenGL |
720 | contexts of version 3.3 or newer. However, with some of these APIs support |
721 | for timestamp queries is technically optional, and therefore it cannot be |
722 | guaranteed that this feature is always supported with every implementation |
723 | of them. |
724 | |
725 | \value Instancing Indicates that instanced drawing is supported. In |
726 | practice this feature will be unsupported with OpenGL ES 2.0 and OpenGL |
727 | 3.2 or older. |
728 | |
729 | \value CustomInstanceStepRate Indicates that instance step rates other |
730 | than 1 are supported. In practice this feature will always be unsupported |
731 | with OpenGL. In addition, running with Vulkan 1.0 without |
732 | VK_EXT_vertex_attribute_divisor will also lead to reporting false for this |
733 | feature. |
734 | |
735 | \value PrimitiveRestart Indicates that restarting the assembly of |
736 | primitives when encountering an index value of 0xFFFF |
737 | (\l{QRhiCommandBuffer::IndexUInt16}{IndexUInt16}) or 0xFFFFFFFF |
738 | (\l{QRhiCommandBuffer::IndexUInt32}{IndexUInt32}) is enabled, for certain |
739 | primitive topologies at least. QRhi will try to enable this with all |
740 | backends, but in some cases it will not be supported. Dynamically |
741 | controlling primitive restart is not possible since with some APIs |
742 | primitive restart with a fixed index is always on. Applications must assume |
743 | that whenever this feature is reported as supported, the above mentioned |
744 | index values \c may be treated specially, depending on the topology. The |
745 | only two topologies where primitive restart is guaranteed to behave |
746 | identically across backends, as long as this feature is reported as |
747 | supported, are \l{QRhiGraphicsPipeline::LineStrip}{LineStrip} and |
748 | \l{QRhiGraphicsPipeline::TriangleStrip}{TriangleStrip}. |
749 | |
750 | \value NonDynamicUniformBuffers Indicates that creating buffers with the |
751 | usage \l{QRhiBuffer::UniformBuffer}{UniformBuffer} and the types |
752 | \l{QRhiBuffer::Immutable}{Immutable} or \l{QRhiBuffer::Static}{Static} is |
753 | supported. When reported as unsupported, uniform (constant) buffers must be |
754 | created as \l{QRhiBuffer::Dynamic}{Dynamic}. (which is recommended |
755 | regardless) |
756 | |
757 | \value NonFourAlignedEffectiveIndexBufferOffset Indicates that effective |
758 | index buffer offsets (\c{indexOffset + firstIndex * indexComponentSize}) |
759 | that are not 4 byte aligned are supported. When not supported, attempting |
760 | to issue a \l{QRhiCommandBuffer::drawIndexed()}{drawIndexed()} with a |
761 | non-aligned effective offset may lead to unspecified behavior. Relevant in |
762 | particular for Metal, where this will be reported as unsupported. |
763 | |
764 | \value NPOTTextureRepeat Indicates that the |
765 | \l{QRhiSampler::Repeat}{Repeat} wrap mode and mipmap filtering modes are |
766 | supported for textures with a non-power-of-two size. In practice this can |
767 | only be false with OpenGL ES 2.0 implementations without |
768 | \c{GL_OES_texture_npot}. |
769 | |
770 | \value RedOrAlpha8IsRed Indicates that the |
771 | \l{QRhiTexture::RED_OR_ALPHA8}{RED_OR_ALPHA8} format maps to a one |
772 | component 8-bit \c red format. This is the case for all backends except |
773 | OpenGL when using either OpenGL ES or a non-core profile context. There |
774 | \c{GL_ALPHA}, a one component 8-bit \c alpha format, is used |
775 | instead. Using the special texture format allows having a single code |
776 | path for creating textures, leaving it up to the backend to decide the |
777 | actual format, while the feature flag can be used to pick the |
778 | appropriate shader variant for sampling the texture. |
779 | |
780 | \value ElementIndexUint Indicates that 32-bit unsigned integer elements are |
781 | supported in the index buffer. In practice this is true everywhere except |
782 | when running on plain OpenGL ES 2.0 implementations without the necessary |
783 | extension. When false, only 16-bit unsigned elements are supported in the |
784 | index buffer. |
785 | |
786 | \value Compute Indicates that compute shaders, image load/store, and |
787 | storage buffers are supported. OpenGL older than 4.3 and OpenGL ES older |
788 | than 3.1 have no compute support. |
789 | |
790 | \value WideLines Indicates that lines with a width other than 1 are |
791 | supported. When reported as not supported, the line width set on the |
792 | graphics pipeline state is ignored. This can always be false with some |
793 | backends (D3D11, D3D12, Metal). With Vulkan, the value depends on the |
794 | implementation. With OpenGL, wide lines are not supported in core profile |
795 | contexts. |
796 | |
797 | \value VertexShaderPointSize Indicates that the size of rasterized points |
798 | set via \c{gl_PointSize} in the vertex shader is taken into account. When |
799 | reported as not supported, drawing points with a size other than 1 is not |
800 | supported. Setting \c{gl_PointSize} in the shader is still valid then, but |
801 | is ignored. (for example, when generating HLSL, the assignment is silently |
802 | dropped from the generated code) Note that some APIs (Metal, Vulkan) |
803 | require the point size to be set in the shader explicitly whenever drawing |
804 | points, even when the size is 1, as they do not automatically default to 1. |
805 | |
806 | \value BaseVertex Indicates that |
807 | \l{QRhiCommandBuffer::drawIndexed()}{drawIndexed()} supports the \c |
808 | vertexOffset argument. When reported as not supported, the vertexOffset |
809 | value in an indexed draw is ignored. In practice this feature will be |
810 | unsupported with OpenGL and OpenGL ES versions lower than 3.2, and with |
811 | Metal on older iOS devices, including the iOS Simulator. |
812 | |
813 | \value BaseInstance Indicates that instanced draw commands support the \c |
814 | firstInstance argument. When reported as not supported, the firstInstance |
815 | value is ignored and the instance ID starts from 0. In practice this feature |
816 | will be unsupported with OpenGL, and with Metal on older iOS devices, |
817 | including the iOS Simulator. |
818 | |
819 | \value TriangleFanTopology Indicates that QRhiGraphicsPipeline::setTopology() |
820 | supports QRhiGraphicsPipeline::TriangleFan. In practice this feature will be |
821 | unsupported with Metal and Direct 3D 11/12. |
822 | |
823 | \value ReadBackNonUniformBuffer Indicates that |
824 | \l{QRhiResourceUpdateBatch::readBackBuffer()}{reading buffer contents} is |
825 | supported for QRhiBuffer instances with a usage different than |
826 | UniformBuffer. In practice this feature will be unsupported with OpenGL ES |
827 | 2.0. |
828 | |
829 | \value ReadBackNonBaseMipLevel Indicates that specifying a mip level other |
830 | than 0 is supported when reading back texture contents. When not supported, |
831 | specifying a non-zero level in QRhiReadbackDescription leads to returning |
832 | an all-zero image. In practice this feature will be unsupported with OpenGL |
833 | ES 2.0. |
834 | |
835 | \value TexelFetch Indicates that texelFetch() and textureLod() are available |
836 | in shaders. In practice this will be reported as unsupported with OpenGL ES |
837 | 2.0 and OpenGL 2.x contexts, because GLSL 100 es and versions before 130 do |
838 | not support these functions. |
839 | |
840 | \value RenderToNonBaseMipLevel Indicates that specifying a mip level other |
841 | than 0 is supported when creating a QRhiTextureRenderTarget with a |
842 | QRhiTexture as its color attachment. When not supported, create() will fail |
843 | whenever the target mip level is not zero. In practice this feature will be |
844 | unsupported with OpenGL ES 2.0. |
845 | |
846 | \value IntAttributes Indicates that specifying input attributes with |
847 | signed and unsigned integer types for a shader pipeline is supported. When |
848 | not supported, build() will succeed but just show a warning message and the |
849 | values of the target attributes will be broken. In practice this feature |
850 | will be unsupported with OpenGL ES 2.0 and OpenGL 2.x. |
851 | |
852 | \value ScreenSpaceDerivatives Indicates that functions such as dFdx(), |
853 | dFdy(), and fwidth() are supported in shaders. In practice this feature will |
854 | be unsupported with OpenGL ES 2.0 without the GL_OES_standard_derivatives |
855 | extension. |
856 | |
857 | \value ReadBackAnyTextureFormat Indicates that reading back texture |
858 | contents can be expected to work for any QRhiTexture::Format. Backends |
859 | other than OpenGL can be expected to return true for this feature. When |
860 | reported as false, which will typically happen with OpenGL, only the |
861 | formats QRhiTexture::RGBA8 and QRhiTexture::BGRA8 are guaranteed to be |
862 | supported for readbacks. In addition, with OpenGL, but not OpenGL ES, |
863 | reading back the 1 byte per component formats QRhiTexture::R8 and |
864 | QRhiTexture::RED_OR_ALPHA8 are supported as well. Reading back floating |
865 | point formats QRhiTexture::RGBA16F and RGBA32F may work too with OpenGL, as |
866 | long as the implementation provides support for these, but QRhi can give no |
867 | guarantees, as indicated by this flag. |
868 | |
869 | \value PipelineCacheDataLoadSave Indicates that the pipelineCacheData() and |
870 | setPipelineCacheData() functions are functional. When not supported, the |
871 | functions will not perform any action, the retrieved blob is always empty, |
872 | and thus no benefits can be expected from retrieving and, during a |
873 | subsequent run of the application, reloading the pipeline cache content. |
874 | |
875 | \value ImageDataStride Indicates that specifying a custom stride (row |
876 | length) for raw image data in texture uploads is supported. When not |
877 | supported (which can happen when the underlying API is OpenGL ES 2.0 without |
878 | support for GL_UNPACK_ROW_LENGTH), |
879 | QRhiTextureSubresourceUploadDescription::setDataStride() must not be used. |
880 | |
881 | \value RenderBufferImport Indicates that QRhiRenderBuffer::createFrom() is |
882 | supported. For most graphics APIs this is not sensible because |
883 | QRhiRenderBuffer encapsulates texture objects internally, just like |
884 | QRhiTexture. With OpenGL however, renderbuffer object exist as a separate |
885 | object type in the API, and in certain environments (for example, where one |
886 | may want to associated a renderbuffer object with an EGLImage object) it is |
887 | important to allow wrapping an existing OpenGL renderbuffer object with a |
888 | QRhiRenderBuffer. |
889 | |
890 | \value ThreeDimensionalTextures Indicates that 3D textures are supported. |
891 | In practice this feature will be unsupported with OpenGL and OpenGL ES |
892 | versions lower than 3.0. |
893 | |
894 | \value RenderTo3DTextureSlice Indicates that rendering to a slice in a 3D |
895 | texture is supported. This can be unsupported with Vulkan 1.0 due to |
896 | relying on VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT which is a Vulkan 1.1 |
897 | feature. |
898 | |
899 | \value TextureArrays Indicates that texture arrays are supported and |
900 | QRhi::newTextureArray() is functional. Note that even when texture arrays |
901 | are not supported, arrays of textures are still available as those are two |
902 | independent features. |
903 | |
904 | \value Tessellation Indicates that the tessellation control and evaluation |
905 | stages are supported. When reported as supported, the topology of a |
906 | QRhiGraphicsPipeline can be set to |
907 | \l{QRhiGraphicsPipeline::Patches}{Patches}, the number of control points |
908 | can be set via |
909 | \l{QRhiGraphicsPipeline::setPatchControlPointCount()}{setPatchControlPointCount()}, |
910 | and shaders for tessellation control and evaluation can be specified in the |
911 | QRhiShaderStage list. Tessellation shaders have portability issues between |
912 | APIs (for example, translating GLSL/SPIR-V to HLSL is problematic due to |
913 | the way hull shaders are structured, whereas Metal uses a somewhat |
914 | different tessellation pipeline than others), and therefore unexpected |
915 | issues may still arise, even though basic functionality is implemented |
916 | across all the underlying APIs. For Direct 3D in particular, handwritten |
917 | HLSL hull and domain shaders must be injected into each QShader for the |
918 | tessellation control and evaluation stages, respectively, since qsb cannot |
919 | generate these from SPIR-V. Note that isoline tessellation should be |
920 | avoided as it will not be supported by all backends. The maximum patch |
921 | control point count portable between backends is 32. |
922 | |
923 | \value GeometryShader Indicates that the geometry shader stage is |
924 | supported. When supported, a geometry shader can be specified in the |
925 | QRhiShaderStage list. Geometry Shaders are considered an experimental |
926 | feature in QRhi and can only be expected to be supported with Vulkan, |
927 | Direct 3D, OpenGL (3.2+) and OpenGL ES (3.2+), assuming the implementation |
928 | reports it as supported at run time. Geometry shaders have portability |
929 | issues between APIs, and therefore no guarantees can be given for a |
930 | universal solution. They will never be supported with Metal. Whereas with |
931 | Direct 3D a handwritten HLSL geometry shader must be injected into each |
932 | QShader for the geometry stage since qsb cannot generate this from SPIR-V. |
933 | |
934 | \value TextureArrayRange Indicates that for |
935 | \l{QRhi::newTextureArray()}{texture arrays} it is possible to specify a |
936 | range that is exposed to the shaders. Normally all array layers are exposed |
937 | and it is up to the shader to select the layer (via the third coordinate |
938 | passed to texture() when sampling the \c sampler2DArray). When supported, |
939 | calling QRhiTexture::setArrayRangeStart() and |
940 | QRhiTexture::setArrayRangeLength() before |
941 | \l{QRhiTexture::create()}{building} or |
942 | \l{QRhiTexture::createFrom()}{importing} the native texture has an effect, |
943 | and leads to selecting only the specified range from the array. This will |
944 | be necessary in special cases, such as when working with accelerated video |
945 | decoding and Direct 3D 11, because a texture array with both |
946 | \c{D3D11_BIND_DECODER} and \c{D3D11_BIND_SHADER_RESOURCE} on it is only |
947 | usable as a shader resource if a single array layer is selected. Note that |
948 | all this is applicable only when the texture is used as a |
949 | QRhiShaderResourceBinding::SampledTexture or |
950 | QRhiShaderResourceBinding::Texture shader resource, and is not compatible |
951 | with image load/store. This feature is only available with some backends as |
952 | it does not map well to all graphics APIs, and it is only meant to provide |
953 | support for special cases anyhow. In practice the feature can be expected to |
954 | be supported with Direct3D 11/12 and Vulkan. |
955 | |
956 | \value NonFillPolygonMode Indicates that setting a PolygonMode other than |
957 | the default Fill is supported for QRhiGraphicsPipeline. A common use case |
958 | for changing the mode to Line is to get wireframe rendering. This however |
959 | is not available as a core OpenGL ES feature, and is optional with Vulkan |
960 | as well as some mobile GPUs may not offer the feature. |
961 | |
962 | \value OneDimensionalTextures Indicates that 1D textures are supported. |
963 | In practice this feature will be unsupported on OpenGL ES. |
964 | |
965 | \value OneDimensionalTextureMipmaps Indicates that generating 1D texture |
966 | mipmaps are supported. In practice this feature will be unsupported on |
967 | backends that do not report support for |
968 | \l{OneDimensionalTextures}, Metal, and Direct 3D 12. |
969 | |
970 | \value HalfAttributes Indicates that specifying input attributes with half |
971 | precision (16bit) floating point types for a shader pipeline is supported. |
972 | When not supported, build() will succeed but just show a warning message |
973 | and the values of the target attributes will be broken. In practice this |
974 | feature will be unsupported in some OpenGL ES 2.0 and OpenGL 2.x |
975 | implementations. Note that while Direct3D 11/12 does support half precision |
976 | input attributes, it does not support the half3 type. The D3D backends pass |
977 | half3 attributes as half4. To ensure cross platform compatibility, half3 |
978 | inputs should be padded to 8 bytes. |
979 | |
980 | \value RenderToOneDimensionalTexture Indicates that 1D texture render |
981 | targets are supported. In practice this feature will be unsupported on |
982 | backends that do not report support for |
983 | \l{OneDimensionalTextures}, and Metal. |
984 | |
985 | \value ThreeDimensionalTextureMipmaps Indicates that generating 3D texture |
986 | mipmaps are supported. In practice this feature will be unsupported with |
987 | Direct 3D 12. |
988 | |
989 | \value MultiView Indicates that multiview, see e.g. |
990 | \l{https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_multiview.html}{VK_KHR_multiview} |
991 | is supported. With OpenGL ES 2.0, Direct 3D 11, and OpenGL (ES) |
992 | implementations without \c{GL_OVR_multiview2} this feature will not be |
993 | supported. With Vulkan 1.1 and newer, and Direct 3D 12 multiview is |
994 | typically supported. When reported as supported, creating a |
995 | QRhiTextureRenderTarget with a QRhiColorAttachment that references a texture |
996 | array and has \l{QRhiColorAttachment::setMultiViewCount()}{multiViewCount} |
997 | set enables recording a render pass that uses multiview rendering. In addition, |
998 | any QRhiGraphicsPipeline used in that render pass must have |
999 | \l{QRhiGraphicsPipeline::setMultiViewCount()}{the same view count set}. Note that |
1000 | multiview is only available in combination with 2D texture arrays. It cannot |
1001 | be used to optimize the rendering into individual textures (e.g. two, for |
1002 | the left and right eyes). Rather, the target of a multiview render pass is |
1003 | always a texture array, automatically rendering to the layer (array element) |
1004 | corresponding to each view. Therefore this feature implies \l TextureArrays |
1005 | as well. Multiview rendering is not supported in combination with |
1006 | tessellation or geometry shaders. See QRhiColorAttachment::setMultiViewCount() |
1007 | for further details on multiview rendering. This enum value has been introduced in Qt 6.7. |
1008 | |
1009 | \value TextureViewFormat Indicates that setting a |
1010 | \l{QRhiTexture::setWriteViewFormat()}{view format} on a QRhiTexture is |
1011 | effective. When reported as supported, setting the read (sampling) or write |
1012 | (render target / image load-store) view mode changes the texture's viewing |
1013 | format. When unsupported, setting a view format has no effect. Note that Qt |
1014 | has no knowledge or control over format compatibility or resource view rules |
1015 | in the underlying 3D API and its implementation. Passing in unsuitable, |
1016 | incompatible formats may lead to errors and unspecified behavior. This is |
1017 | provided mainly to allow "casting" rendering into a texture created with an |
1018 | sRGB format to non-sRGB to avoid the unwanted linear->sRGB conversion on |
1019 | shader writes. Other types of casting may or may not be functional, |
1020 | depending on the underlying API. Currently implemented for Vulkan and Direct |
1021 | 3D 12. With D3D12 the feature is available only if |
1022 | \c CastingFullyTypedFormatSupported is supported, see |
1023 | \l{https://microsoft.github.io/DirectX-Specs/d3d/RelaxedCasting.html} (and |
1024 | note that QRhi always uses fully typed formats for textures.) This enum |
1025 | value has been introduced in Qt 6.8. |
1026 | |
1027 | \value ResolveDepthStencil Indicates that resolving a multisample depth or |
1028 | depth-stencil texture is supported. Otherwise, |
1029 | \l{QRhiTextureRenderTargetDescription::setDepthResolveTexture()}{setting a |
1030 | depth resolve texture} is not functional and must be avoided. Direct 3D 11 |
1031 | and 12 have no support for resolving depth/depth-stencil formats, and |
1032 | therefore this feature will never be supported with those. Vulkan 1.0 has no |
1033 | API to request resolving a depth-stencil attachment. Therefore, with Vulkan |
1034 | this feature will only be supported with Vulkan 1.2 and up, and on 1.1 |
1035 | implementations with the appropriate extensions present. This feature is |
1036 | provided for the rare case when resolving into a non-multisample depth |
1037 | texture becomes necessary, for example when rendering into an |
1038 | OpenXR-provided depth texture (XR_KHR_composition_layer_depth). This enum |
1039 | value has been introduced in Qt 6.8. |
1040 | */ |
1041 | |
1042 | /*! |
1043 | \enum QRhi::BeginFrameFlag |
1044 | Flag values for QRhi::beginFrame() |
1045 | */ |
1046 | |
1047 | /*! |
1048 | \enum QRhi::EndFrameFlag |
1049 | Flag values for QRhi::endFrame() |
1050 | |
1051 | \value SkipPresent Specifies that no present command is to be queued or no |
1052 | swapBuffers call is to be made. This way no image is presented. Generating |
1053 | multiple frames with all having this flag set is not recommended (except, |
1054 | for example, for benchmarking purposes - but keep in mind that backends may |
1055 | behave differently when it comes to waiting for command completion without |
1056 | presenting so the results are not comparable between them) |
1057 | */ |
1058 | |
1059 | /*! |
1060 | \enum QRhi::ResourceLimit |
1061 | Describes the resource limit to query. |
1062 | |
1063 | \value TextureSizeMin Minimum texture width and height. This is typically |
1064 | 1. The minimum texture size is handled gracefully, meaning attempting to |
1065 | create a texture with an empty size will instead create a texture with the |
1066 | minimum size. |
1067 | |
1068 | \value TextureSizeMax Maximum texture width and height. This depends on the |
1069 | graphics API and sometimes the platform or implementation as well. |
1070 | Typically the value is in the range 4096 - 16384. Attempting to create |
1071 | textures larger than this is expected to fail. |
1072 | |
1073 | \value MaxColorAttachments The maximum number of color attachments for a |
1074 | QRhiTextureRenderTarget, in case multiple render targets are supported. When |
1075 | MRT is not supported, the value is 1. Otherwise this is typically 8, but |
1076 | watch out for the fact that OpenGL only mandates 4 as the minimum, and that |
1077 | is what some OpenGL ES implementations provide. |
1078 | |
1079 | \value FramesInFlight The number of frames the backend may keep "in |
1080 | flight": with backends like Vulkan or Metal, it is the responsibility of |
1081 | QRhi to block whenever starting a new frame and finding the CPU is already |
1082 | \c{N - 1} frames ahead of the GPU (because the command buffer submitted in |
1083 | frame no. \c{current} - \c{N} has not yet completed). The value N is what |
1084 | is returned from here, and is typically 2. This can be relevant to |
1085 | applications that integrate rendering done directly with the graphics API, |
1086 | as such rendering code may want to perform double (if the value is 2) |
1087 | buffering for resources, such as, buffers, similarly to the QRhi backends |
1088 | themselves. The current frame slot index (a value running 0, 1, .., N-1, |
1089 | then wrapping around) is retrievable from QRhi::currentFrameSlot(). The |
1090 | value is 1 for backends where the graphics API offers no such low level |
1091 | control over the command submission process. Note that pipelining may still |
1092 | happen even when this value is 1 (some backends, such as D3D11, are |
1093 | designed to attempt to enable this, for instance, by using an update |
1094 | strategy for uniform buffers that does not stall the pipeline), but that is |
1095 | then not controlled by QRhi and so not reflected here in the API. |
1096 | |
1097 | \value MaxAsyncReadbackFrames The number of \l{QRhi::endFrame()}{submitted} |
1098 | frames (including the one that contains the readback) after which an |
1099 | asynchronous texture or buffer readback is guaranteed to complete upon |
1100 | \l{QRhi::beginFrame()}{starting a new frame}. |
1101 | |
1102 | \value MaxThreadGroupsPerDimension The maximum number of compute |
1103 | work/thread groups that can be dispatched. Effectively the maximum value |
1104 | for the arguments of QRhiCommandBuffer::dispatch(). Typically 65535. |
1105 | |
1106 | \value MaxThreadsPerThreadGroup The maximum number of invocations in a |
1107 | single local work group, or in other terminology, the maximum number of |
1108 | threads in a thread group. Effectively the maximum value for the product of |
1109 | \c local_size_x, \c local_size_y, and \c local_size_z in the compute |
1110 | shader. Typical values are 128, 256, 512, 1024, or 1536. Watch out that |
1111 | both OpenGL ES and Vulkan specify only 128 as the minimum required limit |
1112 | for implementations. While uncommon for Vulkan, some OpenGL ES 3.1 |
1113 | implementations for mobile/embedded devices only support the spec-mandated |
1114 | minimum value. |
1115 | |
1116 | \value MaxThreadGroupX The maximum size of a work/thread group in the X |
1117 | dimension. Effectively the maximum value of \c local_size_x in the compute |
1118 | shader. Typically 256 or 1024. |
1119 | |
1120 | \value MaxThreadGroupY The maximum size of a work/thread group in the Y |
1121 | dimension. Effectively the maximum value of \c local_size_y in the compute |
1122 | shader. Typically 256 or 1024. |
1123 | |
1124 | \value MaxThreadGroupZ The maximum size of a work/thread group in the Z |
1125 | dimension. Effectively the maximum value of \c local_size_z in the compute |
1126 | shader. Typically 64 or 256. |
1127 | |
1128 | \value TextureArraySizeMax Maximum texture array size. Typically in range |
1129 | 256 - 2048. Attempting to \l{QRhi::newTextureArray()}{create a texture |
1130 | array} with more elements will likely fail. |
1131 | |
1132 | \value MaxUniformBufferRange The number of bytes that can be exposed from a |
1133 | uniform buffer to the shaders at once. On OpenGL ES 2.0 and 3.0 |
1134 | implementations this may be as low as 3584 bytes (224 four component, 32 |
1135 | bits per component vectors). Elsewhere the value is typically 16384 (1024 |
1136 | vec4s) or 65536 (4096 vec4s). |
1137 | |
1138 | \value MaxVertexInputs The number of input attributes to the vertex shader. |
1139 | The location in a QRhiVertexInputAttribute must be in range \c{[0, |
1140 | MaxVertexInputs-1]}. The value may be as low as 8 with OpenGL ES 2.0. |
1141 | Elsewhere, typical values are 16, 31, or 32. |
1142 | |
1143 | \value MaxVertexOutputs The maximum number of outputs (4 component vector |
1144 | \c out variables) from the vertex shader. The value may be as low as 8 with |
1145 | OpenGL ES 2.0, and 15 with OpenGL ES 3.0 and some Metal devices. Elsewhere, |
1146 | a typical value is 32. |
1147 | */ |
1148 | |
1149 | /*! |
1150 | \class QRhiInitParams |
1151 | \inmodule QtGuiPrivate |
1152 | \inheaderfile rhi/qrhi.h |
1153 | \since 6.6 |
1154 | \brief Base class for backend-specific initialization parameters. |
1155 | |
1156 | Contains fields that are relevant to all backends. |
1157 | |
1158 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1159 | for details. |
1160 | */ |
1161 | |
1162 | /*! |
1163 | \class QRhiDepthStencilClearValue |
1164 | \inmodule QtGuiPrivate |
1165 | \inheaderfile rhi/qrhi.h |
1166 | \since 6.6 |
1167 | \brief Specifies clear values for a depth or stencil buffer. |
1168 | |
1169 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1170 | for details. |
1171 | */ |
1172 | |
1173 | /*! |
1174 | \fn QRhiDepthStencilClearValue::QRhiDepthStencilClearValue() = default |
1175 | |
1176 | Constructs a depth/stencil clear value with depth clear value 1.0f and |
1177 | stencil clear value 0. |
1178 | */ |
1179 | |
1180 | /*! |
1181 | Constructs a depth/stencil clear value with depth clear value \a d and |
1182 | stencil clear value \a s. |
1183 | */ |
1184 | QRhiDepthStencilClearValue::QRhiDepthStencilClearValue(float d, quint32 s) |
1185 | : m_d(d), |
1186 | m_s(s) |
1187 | { |
1188 | } |
1189 | |
1190 | /*! |
1191 | \fn float QRhiDepthStencilClearValue::depthClearValue() const |
1192 | \return the depth clear value. In most cases this is 1.0f. |
1193 | */ |
1194 | |
1195 | /*! |
1196 | \fn void QRhiDepthStencilClearValue::setDepthClearValue(float d) |
1197 | Sets the depth clear value to \a d. |
1198 | */ |
1199 | |
1200 | /*! |
1201 | \fn quint32 QRhiDepthStencilClearValue::stencilClearValue() const |
1202 | \return the stencil clear value. In most cases this is 0. |
1203 | */ |
1204 | |
1205 | /*! |
1206 | \fn void QRhiDepthStencilClearValue::setStencilClearValue(quint32 s) |
1207 | Sets the stencil clear value to \a s. |
1208 | */ |
1209 | |
1210 | /*! |
1211 | \fn bool QRhiDepthStencilClearValue::operator==(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept |
1212 | |
1213 | \return \c true if the values in the two QRhiDepthStencilClearValue objects |
1214 | \a a and \a b are equal. |
1215 | */ |
1216 | |
1217 | /*! |
1218 | \fn bool QRhiDepthStencilClearValue::operator!=(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept |
1219 | |
1220 | \return \c false if the values in the two QRhiDepthStencilClearValue |
1221 | objects \a a and \a b are equal; otherwise returns \c true. |
1222 | |
1223 | */ |
1224 | |
1225 | /*! |
1226 | \fn size_t QRhiDepthStencilClearValue::qHash(const QRhiDepthStencilClearValue &v, size_t seed = 0) noexcept |
1227 | |
1228 | \return the hash value for \a v, using \a seed to seed the calculation. |
1229 | */ |
1230 | |
1231 | #ifndef QT_NO_DEBUG_STREAM |
1232 | QDebug operator<<(QDebug dbg, const QRhiDepthStencilClearValue &v) |
1233 | { |
1234 | QDebugStateSaver saver(dbg); |
1235 | dbg.nospace() << "QRhiDepthStencilClearValue(depth-clear="<< v.depthClearValue() |
1236 | << " stencil-clear="<< v.stencilClearValue() |
1237 | << ')'; |
1238 | return dbg; |
1239 | } |
1240 | #endif |
1241 | |
1242 | /*! |
1243 | \class QRhiViewport |
1244 | \inmodule QtGuiPrivate |
1245 | \inheaderfile rhi/qrhi.h |
1246 | \since 6.6 |
1247 | \brief Specifies a viewport rectangle. |
1248 | |
1249 | Used with QRhiCommandBuffer::setViewport(). |
1250 | |
1251 | QRhi assumes OpenGL-style viewport coordinates, meaning x and y are |
1252 | bottom-left. Negative width or height are not allowed. |
1253 | |
1254 | Typical usage is like the following: |
1255 | |
1256 | \code |
1257 | const QSize outputSizeInPixels = swapchain->currentPixelSize(); |
1258 | const QRhiViewport viewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height()); |
1259 | cb->beginPass(swapchain->currentFrameRenderTarget(), Qt::black, { 1.0f, 0 }); |
1260 | cb->setGraphicsPipeline(ps); |
1261 | cb->setViewport(viewport); |
1262 | // ... |
1263 | \endcode |
1264 | |
1265 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1266 | for details. |
1267 | |
1268 | \sa QRhiCommandBuffer::setViewport(), QRhi::clipSpaceCorrMatrix(), QRhiScissor |
1269 | */ |
1270 | |
1271 | /*! |
1272 | \fn QRhiViewport::QRhiViewport() = default |
1273 | |
1274 | Constructs a viewport description with an empty rectangle and a depth range |
1275 | of 0.0f - 1.0f. |
1276 | |
1277 | \sa QRhi::clipSpaceCorrMatrix() |
1278 | */ |
1279 | |
1280 | /*! |
1281 | Constructs a viewport description with the rectangle specified by \a x, \a |
1282 | y, \a w, \a h and the depth range \a minDepth and \a maxDepth. |
1283 | |
1284 | \note \a x and \a y are assumed to be the bottom-left position. \a w and \a |
1285 | h should not be negative, the viewport will be ignored by |
1286 | QRhiCommandBuffer::setViewport() otherwise. |
1287 | |
1288 | \sa QRhi::clipSpaceCorrMatrix() |
1289 | */ |
1290 | QRhiViewport::QRhiViewport(float x, float y, float w, float h, float minDepth, float maxDepth) |
1291 | : m_rect { ._M_elems: { x, y, w, h } }, |
1292 | m_minDepth(minDepth), |
1293 | m_maxDepth(maxDepth) |
1294 | { |
1295 | } |
1296 | |
1297 | /*! |
1298 | \fn std::array<float, 4> QRhiViewport::viewport() const |
1299 | \return the viewport x, y, width, and height. |
1300 | */ |
1301 | |
1302 | /*! |
1303 | \fn void QRhiViewport::setViewport(float x, float y, float w, float h) |
1304 | Sets the viewport's position and size to \a x, \a y, \a w, and \a h. |
1305 | |
1306 | \note Viewports are specified in a coordinate system that has its origin in |
1307 | the bottom-left. |
1308 | */ |
1309 | |
1310 | /*! |
1311 | \fn float QRhiViewport::minDepth() const |
1312 | \return the minDepth value of the depth range of the viewport. |
1313 | */ |
1314 | |
1315 | /*! |
1316 | \fn void QRhiViewport::setMinDepth(float minDepth) |
1317 | Sets the \a minDepth of the depth range of the viewport. |
1318 | By default this is set to 0.0f. |
1319 | */ |
1320 | |
1321 | /*! |
1322 | \fn float QRhiViewport::maxDepth() const |
1323 | \return the maxDepth value of the depth range of the viewport. |
1324 | */ |
1325 | |
1326 | /*! |
1327 | \fn void QRhiViewport::setMaxDepth(float maxDepth) |
1328 | Sets the \a maxDepth of the depth range of the viewport. |
1329 | By default this is set to 1.0f. |
1330 | */ |
1331 | |
1332 | /*! |
1333 | \fn bool QRhiViewport::operator==(const QRhiViewport &a, const QRhiViewport &b) noexcept |
1334 | |
1335 | \return \c true if the values in the two QRhiViewport objects |
1336 | \a a and \a b are equal. |
1337 | */ |
1338 | |
1339 | /*! |
1340 | \fn bool QRhiViewport::operator!=(const QRhiViewport &a, const QRhiViewport &b) noexcept |
1341 | |
1342 | \return \c false if the values in the two QRhiViewport |
1343 | objects \a a and \a b are equal; otherwise returns \c true. |
1344 | */ |
1345 | |
1346 | /*! |
1347 | \fn size_t QRhiViewport::qHash(const QRhiViewport &v, size_t seed = 0) noexcept |
1348 | |
1349 | \return the hash value for \a v, using \a seed to seed the calculation. |
1350 | */ |
1351 | |
1352 | #ifndef QT_NO_DEBUG_STREAM |
1353 | QDebug operator<<(QDebug dbg, const QRhiViewport &v) |
1354 | { |
1355 | QDebugStateSaver saver(dbg); |
1356 | const std::array<float, 4> r = v.viewport(); |
1357 | dbg.nospace() << "QRhiViewport(bottom-left-x="<< r[0] |
1358 | << " bottom-left-y="<< r[1] |
1359 | << " width="<< r[2] |
1360 | << " height="<< r[3] |
1361 | << " minDepth="<< v.minDepth() |
1362 | << " maxDepth="<< v.maxDepth() |
1363 | << ')'; |
1364 | return dbg; |
1365 | } |
1366 | #endif |
1367 | |
1368 | /*! |
1369 | \class QRhiScissor |
1370 | \inmodule QtGuiPrivate |
1371 | \inheaderfile rhi/qrhi.h |
1372 | \since 6.6 |
1373 | \brief Specifies a scissor rectangle. |
1374 | |
1375 | Used with QRhiCommandBuffer::setScissor(). Setting a scissor rectangle is |
1376 | only possible with a QRhiGraphicsPipeline that has |
1377 | QRhiGraphicsPipeline::UsesScissor set. |
1378 | |
1379 | QRhi assumes OpenGL-style scissor coordinates, meaning x and y are |
1380 | bottom-left. Negative width or height are not allowed. However, apart from |
1381 | that, the flexible OpenGL semantics apply: negative x and y, partially out |
1382 | of bounds rectangles, etc. will be handled gracefully, clamping as |
1383 | appropriate. Therefore, any rendering logic targeting OpenGL can feed |
1384 | scissor rectangles into QRhiScissor as-is, without any adaptation. |
1385 | |
1386 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1387 | for details. |
1388 | |
1389 | \sa QRhiCommandBuffer::setScissor(), QRhiViewport |
1390 | */ |
1391 | |
1392 | /*! |
1393 | \fn QRhiScissor::QRhiScissor() = default |
1394 | |
1395 | Constructs an empty scissor. |
1396 | */ |
1397 | |
1398 | /*! |
1399 | Constructs a scissor with the rectangle specified by \a x, \a y, \a w, and |
1400 | \a h. |
1401 | |
1402 | \note \a x and \a y are assumed to be the bottom-left position. Negative \a w |
1403 | or \a h are not allowed, such scissor rectangles will be ignored by |
1404 | QRhiCommandBuffer. Other than that, the flexible OpenGL semantics apply: |
1405 | negative x and y, partially out of bounds rectangles, etc. will be handled |
1406 | gracefully, clamping as appropriate. |
1407 | */ |
1408 | QRhiScissor::QRhiScissor(int x, int y, int w, int h) |
1409 | : m_rect { ._M_elems: { x, y, w, h } } |
1410 | { |
1411 | } |
1412 | |
1413 | /*! |
1414 | \fn std::array<int, 4> QRhiScissor::scissor() const |
1415 | \return the scissor position and size. |
1416 | */ |
1417 | |
1418 | /*! |
1419 | \fn void QRhiScissor::setScissor(int x, int y, int w, int h) |
1420 | Sets the scissor position and size to \a x, \a y, \a w, \a h. |
1421 | |
1422 | \note The position is always expected to be specified in a coordinate |
1423 | system that has its origin in the bottom-left corner, like OpenGL. |
1424 | */ |
1425 | |
1426 | /*! |
1427 | \fn bool QRhiScissor::operator==(const QRhiScissor &a, const QRhiScissor &b) noexcept |
1428 | |
1429 | \return \c true if the values in the two QRhiScissor objects |
1430 | \a a and \a b are equal. |
1431 | */ |
1432 | |
1433 | /*! |
1434 | \fn bool QRhiScissor::operator!=(const QRhiScissor &a, const QRhiScissor &b) noexcept |
1435 | |
1436 | \return \c false if the values in the two QRhiScissor |
1437 | objects \a a and \a b are equal; otherwise returns \c true. |
1438 | */ |
1439 | |
1440 | /*! |
1441 | \fn size_t QRhiScissor::qHash(const QRhiScissor &v, size_t seed = 0) noexcept |
1442 | |
1443 | \return the hash value for \a v, using \a seed to seed the calculation. |
1444 | */ |
1445 | |
1446 | #ifndef QT_NO_DEBUG_STREAM |
1447 | QDebug operator<<(QDebug dbg, const QRhiScissor &s) |
1448 | { |
1449 | QDebugStateSaver saver(dbg); |
1450 | const std::array<int, 4> r = s.scissor(); |
1451 | dbg.nospace() << "QRhiScissor(bottom-left-x="<< r[0] |
1452 | << " bottom-left-y="<< r[1] |
1453 | << " width="<< r[2] |
1454 | << " height="<< r[3] |
1455 | << ')'; |
1456 | return dbg; |
1457 | } |
1458 | #endif |
1459 | |
1460 | /*! |
1461 | \class QRhiVertexInputBinding |
1462 | \inmodule QtGuiPrivate |
1463 | \inheaderfile rhi/qrhi.h |
1464 | \since 6.6 |
1465 | \brief Describes a vertex input binding. |
1466 | |
1467 | Specifies the stride (in bytes, must be a multiple of 4), the |
1468 | classification and optionally the instance step rate. |
1469 | |
1470 | As an example, assume a vertex shader with the following inputs: |
1471 | |
1472 | \badcode |
1473 | layout(location = 0) in vec4 position; |
1474 | layout(location = 1) in vec2 texcoord; |
1475 | \endcode |
1476 | |
1477 | Now let's assume also that 3 component vertex positions \c{(x, y, z)} and 2 |
1478 | component texture coordinates \c{(u, v)} are provided in a non-interleaved |
1479 | format in a buffer (or separate buffers even). Defining two bindings |
1480 | could then be done like this: |
1481 | |
1482 | \code |
1483 | QRhiVertexInputLayout inputLayout; |
1484 | inputLayout.setBindings({ |
1485 | { 3 * sizeof(float) }, |
1486 | { 2 * sizeof(float) } |
1487 | }); |
1488 | \endcode |
1489 | |
1490 | Only the stride is interesting here since instancing is not used. The |
1491 | binding number is given by the index of the QRhiVertexInputBinding |
1492 | element in the bindings vector of the QRhiVertexInputLayout. |
1493 | |
1494 | Once a graphics pipeline with this vertex input layout is bound, the vertex |
1495 | inputs could be set up like the following for drawing a cube with 36 |
1496 | vertices, assuming we have a single buffer with first the positions and |
1497 | then the texture coordinates: |
1498 | |
1499 | \code |
1500 | const QRhiCommandBuffer::VertexInput vbufBindings[] = { |
1501 | { cubeBuf, 0 }, |
1502 | { cubeBuf, 36 * 3 * sizeof(float) } |
1503 | }; |
1504 | cb->setVertexInput(0, 2, vbufBindings); |
1505 | \endcode |
1506 | |
1507 | Note how the index defined by \c {startBinding + i}, where \c i is the |
1508 | index in the second argument of |
1509 | \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()}, matches the |
1510 | index of the corresponding entry in the \c bindings vector of the |
1511 | QRhiVertexInputLayout. |
1512 | |
1513 | \note the stride must always be a multiple of 4. |
1514 | |
1515 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1516 | for details. |
1517 | |
1518 | \sa QRhiCommandBuffer::setVertexInput() |
1519 | */ |
1520 | |
1521 | /*! |
1522 | \enum QRhiVertexInputBinding::Classification |
1523 | Describes the input data classification. |
1524 | |
1525 | \value PerVertex Data is per-vertex |
1526 | \value PerInstance Data is per-instance |
1527 | */ |
1528 | |
1529 | /*! |
1530 | \fn QRhiVertexInputBinding::QRhiVertexInputBinding() = default |
1531 | |
1532 | Constructs a default vertex input binding description. |
1533 | */ |
1534 | |
1535 | /*! |
1536 | Constructs a vertex input binding description with the specified \a stride, |
1537 | classification \a cls, and instance step rate \a stepRate. |
1538 | |
1539 | \note \a stepRate other than 1 is only supported when |
1540 | QRhi::CustomInstanceStepRate is reported to be supported. |
1541 | */ |
1542 | QRhiVertexInputBinding::QRhiVertexInputBinding(quint32 stride, Classification cls, quint32 stepRate) |
1543 | : m_stride(stride), |
1544 | m_classification(cls), |
1545 | m_instanceStepRate(stepRate) |
1546 | { |
1547 | } |
1548 | |
1549 | /*! |
1550 | \fn quint32 QRhiVertexInputBinding::stride() const |
1551 | \return the stride in bytes. |
1552 | */ |
1553 | |
1554 | /*! |
1555 | \fn void QRhiVertexInputBinding::setStride(quint32 s) |
1556 | Sets the stride to \a s. |
1557 | */ |
1558 | |
1559 | /*! |
1560 | \fn QRhiVertexInputBinding::Classification QRhiVertexInputBinding::classification() const |
1561 | \return the input data classification. |
1562 | */ |
1563 | |
1564 | /*! |
1565 | \fn void QRhiVertexInputBinding::setClassification(Classification c) |
1566 | Sets the input data classification \a c. By default this is set to PerVertex. |
1567 | */ |
1568 | |
1569 | /*! |
1570 | \fn quint32 QRhiVertexInputBinding::instanceStepRate() const |
1571 | \return the instance step rate. |
1572 | */ |
1573 | |
1574 | /*! |
1575 | \fn void QRhiVertexInputBinding::setInstanceStepRate(quint32 rate) |
1576 | Sets the instance step \a rate. By default this is set to 1. |
1577 | */ |
1578 | |
1579 | /*! |
1580 | \fn bool QRhiVertexInputBinding::operator==(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept |
1581 | |
1582 | \return \c true if the values in the two QRhiVertexInputBinding objects |
1583 | \a a and \a b are equal. |
1584 | */ |
1585 | |
1586 | /*! |
1587 | \fn bool QRhiVertexInputBinding::operator!=(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept |
1588 | |
1589 | \return \c false if the values in the two QRhiVertexInputBinding |
1590 | objects \a a and \a b are equal; otherwise returns \c true. |
1591 | */ |
1592 | |
1593 | /*! |
1594 | \fn size_t QRhiVertexInputBinding::qHash(const QRhiVertexInputBinding &v, size_t seed = 0) noexcept |
1595 | |
1596 | \return the hash value for \a v, using \a seed to seed the calculation. |
1597 | */ |
1598 | |
1599 | #ifndef QT_NO_DEBUG_STREAM |
1600 | QDebug operator<<(QDebug dbg, const QRhiVertexInputBinding &b) |
1601 | { |
1602 | QDebugStateSaver saver(dbg); |
1603 | dbg.nospace() << "QRhiVertexInputBinding(stride="<< b.stride() |
1604 | << " cls="<< b.classification() |
1605 | << " step-rate="<< b.instanceStepRate() |
1606 | << ')'; |
1607 | return dbg; |
1608 | } |
1609 | #endif |
1610 | |
1611 | /*! |
1612 | \class QRhiVertexInputAttribute |
1613 | \inmodule QtGuiPrivate |
1614 | \inheaderfile rhi/qrhi.h |
1615 | \since 6.6 |
1616 | \brief Describes a single vertex input element. |
1617 | |
1618 | The members specify the binding number, location, format, and offset for a |
1619 | single vertex input element. |
1620 | |
1621 | \note For HLSL it is assumed that the vertex shader translated from SPIR-V |
1622 | uses |
1623 | \c{TEXCOORD<location>} as the semantic for each input. Hence no separate |
1624 | semantic name and index. |
1625 | |
1626 | As an example, assume a vertex shader with the following inputs: |
1627 | |
1628 | \badcode |
1629 | layout(location = 0) in vec4 position; |
1630 | layout(location = 1) in vec2 texcoord; |
1631 | \endcode |
1632 | |
1633 | Now let's assume that we have 3 component vertex positions \c{(x, y, z)} |
1634 | and 2 component texture coordinates \c{(u, v)} are provided in a |
1635 | non-interleaved format in a buffer (or separate buffers even). Once two |
1636 | bindings are defined, the attributes could be specified as: |
1637 | |
1638 | \code |
1639 | QRhiVertexInputLayout inputLayout; |
1640 | inputLayout.setBindings({ |
1641 | { 3 * sizeof(float) }, |
1642 | { 2 * sizeof(float) } |
1643 | }); |
1644 | inputLayout.setAttributes({ |
1645 | { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, |
1646 | { 1, 1, QRhiVertexInputAttribute::Float2, 0 } |
1647 | }); |
1648 | \endcode |
1649 | |
1650 | Once a graphics pipeline with this vertex input layout is bound, the vertex |
1651 | inputs could be set up like the following for drawing a cube with 36 |
1652 | vertices, assuming we have a single buffer with first the positions and |
1653 | then the texture coordinates: |
1654 | |
1655 | \code |
1656 | const QRhiCommandBuffer::VertexInput vbufBindings[] = { |
1657 | { cubeBuf, 0 }, |
1658 | { cubeBuf, 36 * 3 * sizeof(float) } |
1659 | }; |
1660 | cb->setVertexInput(0, 2, vbufBindings); |
1661 | \endcode |
1662 | |
1663 | When working with interleaved data, there will typically be just one |
1664 | binding, with multiple attributes referring to that same buffer binding |
1665 | point: |
1666 | |
1667 | \code |
1668 | QRhiVertexInputLayout inputLayout; |
1669 | inputLayout.setBindings({ |
1670 | { 5 * sizeof(float) } |
1671 | }); |
1672 | inputLayout.setAttributes({ |
1673 | { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, |
1674 | { 0, 1, QRhiVertexInputAttribute::Float2, 3 * sizeof(float) } |
1675 | }); |
1676 | \endcode |
1677 | |
1678 | and then: |
1679 | |
1680 | \code |
1681 | const QRhiCommandBuffer::VertexInput vbufBinding(interleavedCubeBuf, 0); |
1682 | cb->setVertexInput(0, 1, &vbufBinding); |
1683 | \endcode |
1684 | |
1685 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1686 | for details. |
1687 | |
1688 | \sa QRhiCommandBuffer::setVertexInput() |
1689 | */ |
1690 | |
1691 | /*! |
1692 | \enum QRhiVertexInputAttribute::Format |
1693 | Specifies the type of the element data. |
1694 | |
1695 | \value Float4 Four component float vector |
1696 | \value Float3 Three component float vector |
1697 | \value Float2 Two component float vector |
1698 | \value Float Float |
1699 | \value UNormByte4 Four component normalized unsigned byte vector |
1700 | \value UNormByte2 Two component normalized unsigned byte vector |
1701 | \value UNormByte Normalized unsigned byte |
1702 | \value UInt4 Four component unsigned integer vector |
1703 | \value UInt3 Three component unsigned integer vector |
1704 | \value UInt2 Two component unsigned integer vector |
1705 | \value UInt Unsigned integer |
1706 | \value SInt4 Four component signed integer vector |
1707 | \value SInt3 Three component signed integer vector |
1708 | \value SInt2 Two component signed integer vector |
1709 | \value SInt Signed integer |
1710 | \value Half4 Four component half precision (16 bit) float vector |
1711 | \value Half3 Three component half precision (16 bit) float vector |
1712 | \value Half2 Two component half precision (16 bit) float vector |
1713 | \value Half Half precision (16 bit) float |
1714 | \value UShort4 Four component unsigned short (16 bit) integer vector |
1715 | \value UShort3 Three component unsigned short (16 bit) integer vector |
1716 | \value UShort2 Two component unsigned short (16 bit) integer vector |
1717 | \value UShort Unsigned short (16 bit) integer |
1718 | \value SShort4 Four component signed short (16 bit) integer vector |
1719 | \value SShort3 Three component signed short (16 bit) integer vector |
1720 | \value SShort2 Two component signed short (16 bit) integer vector |
1721 | \value SShort Signed short (16 bit) integer |
1722 | |
1723 | \note Support for half precision floating point attributes is indicated at |
1724 | run time by the QRhi::Feature::HalfAttributes feature flag. |
1725 | |
1726 | \note Direct3D 11/12 supports 16 bit input attributes, but does not support |
1727 | the Half3, UShort3 or SShort3 types. The D3D backends pass through Half3 as |
1728 | Half4, UShort3 as UShort4, and SShort3 as SShort4. To ensure cross platform |
1729 | compatibility, 16 bit inputs should be padded to 8 bytes. |
1730 | */ |
1731 | |
1732 | /*! |
1733 | \fn QRhiVertexInputAttribute::QRhiVertexInputAttribute() = default |
1734 | |
1735 | Constructs a default vertex input attribute description. |
1736 | */ |
1737 | |
1738 | /*! |
1739 | Constructs a vertex input attribute description with the specified \a |
1740 | binding number, \a location, \a format, and \a offset. |
1741 | |
1742 | \a matrixSlice should be -1 except when this attribute corresponds to a row |
1743 | or column of a matrix (for example, a 4x4 matrix becomes 4 vec4s, consuming |
1744 | 4 consecutive vertex input locations), in which case it is the index of the |
1745 | row or column. \c{location - matrixSlice} must always be equal to the \c |
1746 | location for the first row or column of the unrolled matrix. |
1747 | */ |
1748 | QRhiVertexInputAttribute::QRhiVertexInputAttribute(int binding, int location, Format format, quint32 offset, int matrixSlice) |
1749 | : m_binding(binding), |
1750 | m_location(location), |
1751 | m_format(format), |
1752 | m_offset(offset), |
1753 | m_matrixSlice(matrixSlice) |
1754 | { |
1755 | } |
1756 | |
1757 | /*! |
1758 | \fn int QRhiVertexInputAttribute::binding() const |
1759 | \return the binding point index. |
1760 | */ |
1761 | |
1762 | /*! |
1763 | \fn void QRhiVertexInputAttribute::setBinding(int b) |
1764 | Sets the binding point index to \a b. |
1765 | By default this is set to 0. |
1766 | */ |
1767 | |
1768 | /*! |
1769 | \fn int QRhiVertexInputAttribute::location() const |
1770 | \return the location of the vertex input element. |
1771 | */ |
1772 | |
1773 | /*! |
1774 | \fn void QRhiVertexInputAttribute::setLocation(int loc) |
1775 | Sets the location of the vertex input element to \a loc. |
1776 | By default this is set to 0. |
1777 | */ |
1778 | |
1779 | /*! |
1780 | \fn QRhiVertexInputAttribute::Format QRhiVertexInputAttribute::format() const |
1781 | \return the format of the vertex input element. |
1782 | */ |
1783 | |
1784 | /*! |
1785 | \fn void QRhiVertexInputAttribute::setFormat(Format f) |
1786 | Sets the format of the vertex input element to \a f. |
1787 | By default this is set to Float4. |
1788 | */ |
1789 | |
1790 | /*! |
1791 | \fn quint32 QRhiVertexInputAttribute::offset() const |
1792 | \return the byte offset for the input element. |
1793 | */ |
1794 | |
1795 | /*! |
1796 | \fn void QRhiVertexInputAttribute::setOffset(quint32 ofs) |
1797 | Sets the byte offset for the input element to \a ofs. |
1798 | */ |
1799 | |
1800 | /*! |
1801 | \fn int QRhiVertexInputAttribute::matrixSlice() const |
1802 | |
1803 | \return the matrix slice if the input element corresponds to a row or |
1804 | column of a matrix, or -1 if not relevant. |
1805 | */ |
1806 | |
1807 | /*! |
1808 | \fn void QRhiVertexInputAttribute::setMatrixSlice(int slice) |
1809 | |
1810 | Sets the matrix \a slice. By default this is set to -1, and should be set |
1811 | to a >= 0 value only when this attribute corresponds to a row or column of |
1812 | a matrix (for example, a 4x4 matrix becomes 4 vec4s, consuming 4 |
1813 | consecutive vertex input locations), in which case it is the index of the |
1814 | row or column. \c{location - matrixSlice} must always be equal to the \c |
1815 | location for the first row or column of the unrolled matrix. |
1816 | */ |
1817 | |
1818 | /*! |
1819 | \fn bool QRhiVertexInputAttribute::operator==(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept |
1820 | |
1821 | \return \c true if the values in the two QRhiVertexInputAttribute objects |
1822 | \a a and \a b are equal. |
1823 | */ |
1824 | |
1825 | /*! |
1826 | \fn bool QRhiVertexInputAttribute::operator!=(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept |
1827 | |
1828 | \return \c false if the values in the two QRhiVertexInputAttribute |
1829 | objects \a a and \a b are equal; otherwise returns \c true. |
1830 | */ |
1831 | |
1832 | /*! |
1833 | \fn size_t QRhiVertexInputAttribute::qHash(const QRhiVertexInputAttribute &v, size_t seed = 0) noexcept |
1834 | |
1835 | \return the hash value for \a v, using \a seed to seed the calculation. |
1836 | */ |
1837 | |
1838 | #ifndef QT_NO_DEBUG_STREAM |
1839 | QDebug operator<<(QDebug dbg, const QRhiVertexInputAttribute &a) |
1840 | { |
1841 | QDebugStateSaver saver(dbg); |
1842 | dbg.nospace() << "QRhiVertexInputAttribute(binding="<< a.binding() |
1843 | << " location="<< a.location() |
1844 | << " format="<< a.format() |
1845 | << " offset="<< a.offset() |
1846 | << ')'; |
1847 | return dbg; |
1848 | } |
1849 | #endif |
1850 | |
1851 | QRhiVertexInputAttribute::Format QRhiImplementation::shaderDescVariableFormatToVertexInputFormat(QShaderDescription::VariableType type) const |
1852 | { |
1853 | switch (type) { |
1854 | case QShaderDescription::Vec4: |
1855 | return QRhiVertexInputAttribute::Float4; |
1856 | case QShaderDescription::Vec3: |
1857 | return QRhiVertexInputAttribute::Float3; |
1858 | case QShaderDescription::Vec2: |
1859 | return QRhiVertexInputAttribute::Float2; |
1860 | case QShaderDescription::Float: |
1861 | return QRhiVertexInputAttribute::Float; |
1862 | |
1863 | case QShaderDescription::Int4: |
1864 | return QRhiVertexInputAttribute::SInt4; |
1865 | case QShaderDescription::Int3: |
1866 | return QRhiVertexInputAttribute::SInt3; |
1867 | case QShaderDescription::Int2: |
1868 | return QRhiVertexInputAttribute::SInt2; |
1869 | case QShaderDescription::Int: |
1870 | return QRhiVertexInputAttribute::SInt; |
1871 | |
1872 | case QShaderDescription::Uint4: |
1873 | return QRhiVertexInputAttribute::UInt4; |
1874 | case QShaderDescription::Uint3: |
1875 | return QRhiVertexInputAttribute::UInt3; |
1876 | case QShaderDescription::Uint2: |
1877 | return QRhiVertexInputAttribute::UInt2; |
1878 | case QShaderDescription::Uint: |
1879 | return QRhiVertexInputAttribute::UInt; |
1880 | |
1881 | case QShaderDescription::Half4: |
1882 | return QRhiVertexInputAttribute::Half4; |
1883 | case QShaderDescription::Half3: |
1884 | return QRhiVertexInputAttribute::Half3; |
1885 | case QShaderDescription::Half2: |
1886 | return QRhiVertexInputAttribute::Half2; |
1887 | case QShaderDescription::Half: |
1888 | return QRhiVertexInputAttribute::Half; |
1889 | |
1890 | default: |
1891 | Q_UNREACHABLE_RETURN(QRhiVertexInputAttribute::Float); |
1892 | } |
1893 | } |
1894 | |
1895 | quint32 QRhiImplementation::byteSizePerVertexForVertexInputFormat(QRhiVertexInputAttribute::Format format) const |
1896 | { |
1897 | switch (format) { |
1898 | case QRhiVertexInputAttribute::Float4: |
1899 | return 4 * sizeof(float); |
1900 | case QRhiVertexInputAttribute::Float3: |
1901 | return 4 * sizeof(float); // vec3 still takes 16 bytes |
1902 | case QRhiVertexInputAttribute::Float2: |
1903 | return 2 * sizeof(float); |
1904 | case QRhiVertexInputAttribute::Float: |
1905 | return sizeof(float); |
1906 | |
1907 | case QRhiVertexInputAttribute::UNormByte4: |
1908 | return 4 * sizeof(quint8); |
1909 | case QRhiVertexInputAttribute::UNormByte2: |
1910 | return 2 * sizeof(quint8); |
1911 | case QRhiVertexInputAttribute::UNormByte: |
1912 | return sizeof(quint8); |
1913 | |
1914 | case QRhiVertexInputAttribute::UInt4: |
1915 | return 4 * sizeof(quint32); |
1916 | case QRhiVertexInputAttribute::UInt3: |
1917 | return 4 * sizeof(quint32); // ivec3 still takes 16 bytes |
1918 | case QRhiVertexInputAttribute::UInt2: |
1919 | return 2 * sizeof(quint32); |
1920 | case QRhiVertexInputAttribute::UInt: |
1921 | return sizeof(quint32); |
1922 | |
1923 | case QRhiVertexInputAttribute::SInt4: |
1924 | return 4 * sizeof(qint32); |
1925 | case QRhiVertexInputAttribute::SInt3: |
1926 | return 4 * sizeof(qint32); // uvec3 still takes 16 bytes |
1927 | case QRhiVertexInputAttribute::SInt2: |
1928 | return 2 * sizeof(qint32); |
1929 | case QRhiVertexInputAttribute::SInt: |
1930 | return sizeof(qint32); |
1931 | |
1932 | case QRhiVertexInputAttribute::Half4: |
1933 | return 4 * sizeof(qfloat16); |
1934 | case QRhiVertexInputAttribute::Half3: |
1935 | return 4 * sizeof(qfloat16); // half3 still takes 8 bytes |
1936 | case QRhiVertexInputAttribute::Half2: |
1937 | return 2 * sizeof(qfloat16); |
1938 | case QRhiVertexInputAttribute::Half: |
1939 | return sizeof(qfloat16); |
1940 | |
1941 | case QRhiVertexInputAttribute::UShort4: |
1942 | return 4 * sizeof(quint16); |
1943 | case QRhiVertexInputAttribute::UShort3: |
1944 | return 4 * sizeof(quint16); // ivec3 still takes 8 bytes |
1945 | case QRhiVertexInputAttribute::UShort2: |
1946 | return 2 * sizeof(quint16); |
1947 | case QRhiVertexInputAttribute::UShort: |
1948 | return sizeof(quint16); |
1949 | |
1950 | case QRhiVertexInputAttribute::SShort4: |
1951 | return 4 * sizeof(qint16); |
1952 | case QRhiVertexInputAttribute::SShort3: |
1953 | return 4 * sizeof(qint16); // uvec3 still takes 8 bytes |
1954 | case QRhiVertexInputAttribute::SShort2: |
1955 | return 2 * sizeof(qint16); |
1956 | case QRhiVertexInputAttribute::SShort: |
1957 | return sizeof(qint16); |
1958 | |
1959 | default: |
1960 | Q_UNREACHABLE_RETURN(1); |
1961 | } |
1962 | } |
1963 | |
1964 | /*! |
1965 | \class QRhiVertexInputLayout |
1966 | \inmodule QtGuiPrivate |
1967 | \inheaderfile rhi/qrhi.h |
1968 | \since 6.6 |
1969 | \brief Describes the layout of vertex inputs consumed by a vertex shader. |
1970 | |
1971 | The vertex input layout is defined by the collections of |
1972 | QRhiVertexInputBinding and QRhiVertexInputAttribute. |
1973 | |
1974 | As an example, let's assume that we have a single buffer with 3 component |
1975 | vertex positions and 2 component UV coordinates interleaved (\c x, \c y, \c |
1976 | z, \c u, \c v), that the position and UV are expected at input locations 0 |
1977 | and 1 by the vertex shader, and that the vertex buffer will be bound at |
1978 | binding point 0 using |
1979 | \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()} later on: |
1980 | |
1981 | \code |
1982 | QRhiVertexInputLayout inputLayout; |
1983 | inputLayout.setBindings({ |
1984 | { 5 * sizeof(float) } |
1985 | }); |
1986 | inputLayout.setAttributes({ |
1987 | { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, |
1988 | { 0, 1, QRhiVertexInputAttribute::Float2, 3 * sizeof(float) } |
1989 | }); |
1990 | \endcode |
1991 | |
1992 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1993 | for details. |
1994 | */ |
1995 | |
1996 | /*! |
1997 | \fn QRhiVertexInputLayout::QRhiVertexInputLayout() = default |
1998 | |
1999 | Constructs an empty vertex input layout description. |
2000 | */ |
2001 | |
2002 | /*! |
2003 | \fn void QRhiVertexInputLayout::setBindings(std::initializer_list<QRhiVertexInputBinding> list) |
2004 | Sets the bindings from the specified \a list. |
2005 | */ |
2006 | |
2007 | /*! |
2008 | \fn template<typename InputIterator> void QRhiVertexInputLayout::setBindings(InputIterator first, InputIterator last) |
2009 | Sets the bindings using the iterators \a first and \a last. |
2010 | */ |
2011 | |
2012 | /*! |
2013 | \fn const QRhiVertexInputBinding *QRhiVertexInputLayout::cbeginBindings() const |
2014 | \return a const iterator pointing to the first item in the binding list. |
2015 | */ |
2016 | |
2017 | /*! |
2018 | \fn const QRhiVertexInputBinding *QRhiVertexInputLayout::cendBindings() const |
2019 | \return a const iterator pointing just after the last item in the binding list. |
2020 | */ |
2021 | |
2022 | /*! |
2023 | \fn const QRhiVertexInputBinding *QRhiVertexInputLayout::bindingAt(qsizetype index) const |
2024 | \return the binding at the given \a index. |
2025 | */ |
2026 | |
2027 | /*! |
2028 | \fn qsizetype QRhiVertexInputLayout::bindingCount() const |
2029 | \return the number of bindings. |
2030 | */ |
2031 | |
2032 | /*! |
2033 | \fn void QRhiVertexInputLayout::setAttributes(std::initializer_list<QRhiVertexInputAttribute> list) |
2034 | Sets the attributes from the specified \a list. |
2035 | */ |
2036 | |
2037 | /*! |
2038 | \fn template<typename InputIterator> void QRhiVertexInputLayout::setAttributes(InputIterator first, InputIterator last) |
2039 | Sets the attributes using the iterators \a first and \a last. |
2040 | */ |
2041 | |
2042 | /*! |
2043 | \fn const QRhiVertexInputAttribute *QRhiVertexInputLayout::cbeginAttributes() const |
2044 | \return a const iterator pointing to the first item in the attribute list. |
2045 | */ |
2046 | |
2047 | /*! |
2048 | \fn const QRhiVertexInputAttribute *QRhiVertexInputLayout::cendAttributes() const |
2049 | \return a const iterator pointing just after the last item in the attribute list. |
2050 | */ |
2051 | |
2052 | /*! |
2053 | \fn const QRhiVertexInputAttribute *QRhiVertexInputLayout::attributeAt(qsizetype index) const |
2054 | \return the attribute at the given \a index. |
2055 | */ |
2056 | |
2057 | /*! |
2058 | \fn qsizetype QRhiVertexInputLayout::attributeCount() const |
2059 | \return the number of attributes. |
2060 | */ |
2061 | |
2062 | /*! |
2063 | \fn bool QRhiVertexInputLayout::operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept |
2064 | |
2065 | \return \c true if the values in the two QRhiVertexInputLayout objects |
2066 | \a a and \a b are equal. |
2067 | */ |
2068 | |
2069 | /*! |
2070 | \fn bool QRhiVertexInputLayout::operator!=(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept |
2071 | |
2072 | \return \c false if the values in the two QRhiVertexInputLayout |
2073 | objects \a a and \a b are equal; otherwise returns \c true. |
2074 | */ |
2075 | |
2076 | /*! |
2077 | \fn size_t QRhiVertexInputLayout::qHash(const QRhiVertexInputLayout &v, size_t seed = 0) noexcept |
2078 | |
2079 | \return the hash value for \a v, using \a seed to seed the calculation. |
2080 | */ |
2081 | |
2082 | #ifndef QT_NO_DEBUG_STREAM |
2083 | QDebug operator<<(QDebug dbg, const QRhiVertexInputLayout &v) |
2084 | { |
2085 | QDebugStateSaver saver(dbg); |
2086 | dbg.nospace() << "QRhiVertexInputLayout(bindings="<< v.m_bindings |
2087 | << " attributes="<< v.m_attributes |
2088 | << ')'; |
2089 | return dbg; |
2090 | } |
2091 | #endif |
2092 | |
2093 | /*! |
2094 | \class QRhiShaderStage |
2095 | \inmodule QtGuiPrivate |
2096 | \inheaderfile rhi/qrhi.h |
2097 | \since 6.6 |
2098 | \brief Specifies the type and the shader code for a shader stage in the pipeline. |
2099 | |
2100 | When setting up a QRhiGraphicsPipeline, a collection of shader stages are |
2101 | specified. The QRhiShaderStage contains a QShader and some associated |
2102 | metadata, such as the graphics pipeline stage, and the |
2103 | \l{QShader::Variant}{shader variant} to select. There is no need to specify |
2104 | the shader language or version because the QRhi backend in use at runtime |
2105 | will take care of choosing the appropriate shader version from the |
2106 | collection within the QShader. |
2107 | |
2108 | The typical usage is in combination with |
2109 | QRhiGraphicsPipeline::setShaderStages(), shown here with a simple approach |
2110 | to load the QShader from \c{.qsb} files generated offline or at build time: |
2111 | |
2112 | \code |
2113 | QShader getShader(const QString &name) |
2114 | { |
2115 | QFile f(name); |
2116 | return f.open(QIODevice::ReadOnly) ? QShader::fromSerialized(f.readAll()) : QShader(); |
2117 | } |
2118 | |
2119 | QShader vs = getShader("material.vert.qsb"); |
2120 | QShader fs = getShader("material.frag.qsb"); |
2121 | pipeline->setShaderStages({ |
2122 | { QRhiShaderStage::Vertex, vs }, |
2123 | { QRhiShaderStage::Fragment, fs } |
2124 | }); |
2125 | \endcode |
2126 | |
2127 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2128 | for details. |
2129 | */ |
2130 | |
2131 | /*! |
2132 | \enum QRhiShaderStage::Type |
2133 | Specifies the type of the shader stage. |
2134 | |
2135 | \value Vertex Vertex stage |
2136 | |
2137 | \value TessellationControl Tessellation control (hull shader) stage. Must |
2138 | be used only when the QRhi::Tessellation feature is supported. |
2139 | |
2140 | \value TessellationEvaluation Tessellation evaluation (domain shader) |
2141 | stage. Must be used only when the QRhi::Tessellation feature is supported. |
2142 | |
2143 | \value Fragment Fragment (pixel shader) stage |
2144 | |
2145 | \value Compute Compute stage. Must be used only when the QRhi::Compute |
2146 | feature is supported. |
2147 | |
2148 | \value Geometry Geometry stage. Must be used only when the |
2149 | QRhi::GeometryShader feature is supported. |
2150 | */ |
2151 | |
2152 | /*! |
2153 | \fn QRhiShaderStage::QRhiShaderStage() = default |
2154 | |
2155 | Constructs a shader stage description for the vertex stage with an empty |
2156 | QShader. |
2157 | */ |
2158 | |
2159 | /*! |
2160 | \fn QRhiShaderStage::Type QRhiShaderStage::type() const |
2161 | \return the type of the stage. |
2162 | */ |
2163 | |
2164 | /*! |
2165 | \fn void QRhiShaderStage::setType(Type t) |
2166 | |
2167 | Sets the type of the stage to \a t. Setters should rarely be needed in |
2168 | pratice. Most applications will likely use the QRhiShaderStage constructor |
2169 | in most cases. |
2170 | */ |
2171 | |
2172 | /*! |
2173 | \fn QShader QRhiShaderStage::shader() const |
2174 | \return the QShader to be used for this stage in the graphics pipeline. |
2175 | */ |
2176 | |
2177 | /*! |
2178 | \fn void QRhiShaderStage::setShader(const QShader &s) |
2179 | Sets the shader collection \a s. |
2180 | */ |
2181 | |
2182 | /*! |
2183 | \fn QShader::Variant QRhiShaderStage::shaderVariant() const |
2184 | \return the requested shader variant. |
2185 | */ |
2186 | |
2187 | /*! |
2188 | \fn void QRhiShaderStage::setShaderVariant(QShader::Variant v) |
2189 | Sets the requested shader variant \a v. |
2190 | */ |
2191 | |
2192 | /*! |
2193 | Constructs a shader stage description with the \a type of the stage and the |
2194 | \a shader. |
2195 | |
2196 | The shader variant \a v defaults to QShader::StandardShader. A |
2197 | QShader contains multiple source and binary versions of a shader. |
2198 | In addition, it can also contain variants of the shader with slightly |
2199 | modified code. \a v can then be used to select the desired variant. |
2200 | */ |
2201 | QRhiShaderStage::QRhiShaderStage(Type type, const QShader &shader, QShader::Variant v) |
2202 | : m_type(type), |
2203 | m_shader(shader), |
2204 | m_shaderVariant(v) |
2205 | { |
2206 | } |
2207 | |
2208 | /*! |
2209 | \fn bool QRhiShaderStage::operator==(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept |
2210 | |
2211 | \return \c true if the values in the two QRhiShaderStage objects |
2212 | \a a and \a b are equal. |
2213 | */ |
2214 | |
2215 | /*! |
2216 | \fn bool QRhiShaderStage::operator!=(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept |
2217 | |
2218 | \return \c false if the values in the two QRhiShaderStage |
2219 | objects \a a and \a b are equal; otherwise returns \c true. |
2220 | */ |
2221 | |
2222 | /*! |
2223 | \fn size_t QRhiShaderStage::qHash(const QRhiShaderStage &v, size_t seed = 0) noexcept |
2224 | |
2225 | \return the hash value for \a v, using \a seed to seed the calculation. |
2226 | */ |
2227 | |
2228 | #ifndef QT_NO_DEBUG_STREAM |
2229 | QDebug operator<<(QDebug dbg, const QRhiShaderStage &s) |
2230 | { |
2231 | QDebugStateSaver saver(dbg); |
2232 | dbg.nospace() << "QRhiShaderStage(type="<< s.type() |
2233 | << " shader="<< s.shader() |
2234 | << " variant="<< s.shaderVariant() |
2235 | << ')'; |
2236 | return dbg; |
2237 | } |
2238 | #endif |
2239 | |
2240 | /*! |
2241 | \class QRhiColorAttachment |
2242 | \inmodule QtGuiPrivate |
2243 | \inheaderfile rhi/qrhi.h |
2244 | \since 6.6 |
2245 | \brief Describes the a single color attachment of a render target. |
2246 | |
2247 | A color attachment is either a QRhiTexture or a QRhiRenderBuffer. The |
2248 | former, i.e. when texture() is set, is used in most cases. |
2249 | QRhiColorAttachment is commonly used in combination with |
2250 | QRhiTextureRenderTargetDescription. |
2251 | |
2252 | \note texture() and renderBuffer() cannot be both set (be non-null at the |
2253 | same time). |
2254 | |
2255 | Setting renderBuffer instead is recommended only when multisampling is |
2256 | needed. Relying on QRhi::MultisampleRenderBuffer is a better choice than |
2257 | QRhi::MultisampleTexture in practice since the former is available in more |
2258 | run time configurations (e.g. when running on OpenGL ES 3.0 which has no |
2259 | support for multisample textures, but does support multisample |
2260 | renderbuffers). |
2261 | |
2262 | When targeting a non-multisample texture, the layer() and level() indicate |
2263 | the targeted layer (face index \c{0-5} for cubemaps) and mip level. For 3D |
2264 | textures layer() specifies the slice (one 2D image within the 3D texture) |
2265 | to render to. For texture arrays layer() is the array index. |
2266 | |
2267 | When texture() or renderBuffer() is multisample, resolveTexture() can be |
2268 | set optionally. When set, samples are resolved automatically into that |
2269 | (non-multisample) texture at the end of the render pass. When rendering |
2270 | into a multisample renderbuffers, this is the only way to get resolved, |
2271 | non-multisample content out of them. Multisample textures allow sampling in |
2272 | shaders so for them this is just one option. |
2273 | |
2274 | \note when resolving is enabled, the multisample data may not be written |
2275 | out at all. This means that the multisample texture() must not be used |
2276 | afterwards with shaders for sampling when resolveTexture() is set. |
2277 | |
2278 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2279 | for details. |
2280 | |
2281 | \sa QRhiTextureRenderTargetDescription |
2282 | */ |
2283 | |
2284 | /*! |
2285 | \fn QRhiColorAttachment::QRhiColorAttachment() = default |
2286 | |
2287 | Constructs an empty color attachment description. |
2288 | */ |
2289 | |
2290 | /*! |
2291 | Constructs a color attachment description that specifies \a texture as the |
2292 | associated color buffer. |
2293 | */ |
2294 | QRhiColorAttachment::QRhiColorAttachment(QRhiTexture *texture) |
2295 | : m_texture(texture) |
2296 | { |
2297 | } |
2298 | |
2299 | /*! |
2300 | Constructs a color attachment description that specifies \a renderBuffer as |
2301 | the associated color buffer. |
2302 | */ |
2303 | QRhiColorAttachment::QRhiColorAttachment(QRhiRenderBuffer *renderBuffer) |
2304 | : m_renderBuffer(renderBuffer) |
2305 | { |
2306 | } |
2307 | |
2308 | /*! |
2309 | \fn QRhiTexture *QRhiColorAttachment::texture() const |
2310 | |
2311 | \return the texture this attachment description references, or \nullptr if |
2312 | there is none. |
2313 | */ |
2314 | |
2315 | /*! |
2316 | \fn void QRhiColorAttachment::setTexture(QRhiTexture *tex) |
2317 | |
2318 | Sets the texture \a tex. |
2319 | |
2320 | \note texture() and renderBuffer() cannot be both set (be non-null at the |
2321 | same time). |
2322 | */ |
2323 | |
2324 | /*! |
2325 | \fn QRhiRenderBuffer *QRhiColorAttachment::renderBuffer() const |
2326 | |
2327 | \return the renderbuffer this attachment description references, or |
2328 | \nullptr if there is none. |
2329 | |
2330 | In practice associating a QRhiRenderBuffer with a QRhiColorAttachment makes |
2331 | the most sense when setting up multisample rendering via a multisample |
2332 | \l{QRhiRenderBuffer::Type}{color} renderbuffer that is then resolved into a |
2333 | non-multisample texture at the end of the render pass. |
2334 | */ |
2335 | |
2336 | /*! |
2337 | \fn void QRhiColorAttachment::setRenderBuffer(QRhiRenderBuffer *rb) |
2338 | |
2339 | Sets the renderbuffer \a rb. |
2340 | |
2341 | \note texture() and renderBuffer() cannot be both set (be non-null at the |
2342 | same time). |
2343 | */ |
2344 | |
2345 | /*! |
2346 | \fn int QRhiColorAttachment::layer() const |
2347 | \return the layer index (cubemap face or array layer). 0 by default. |
2348 | */ |
2349 | |
2350 | /*! |
2351 | \fn void QRhiColorAttachment::setLayer(int layer) |
2352 | Sets the \a layer index. |
2353 | */ |
2354 | |
2355 | /*! |
2356 | \fn int QRhiColorAttachment::level() const |
2357 | \return the mip level. 0 by default. |
2358 | */ |
2359 | |
2360 | /*! |
2361 | \fn void QRhiColorAttachment::setLevel(int level) |
2362 | Sets the mip \a level. |
2363 | */ |
2364 | |
2365 | /*! |
2366 | \fn QRhiTexture *QRhiColorAttachment::resolveTexture() const |
2367 | |
2368 | \return the resolve texture this attachment description references, or |
2369 | \nullptr if there is none. |
2370 | |
2371 | Setting a non-null resolve texture is applicable when the attachment |
2372 | references a multisample texture or renderbuffer. The QRhiTexture in the |
2373 | resolveTexture() is then a non-multisample 2D texture (or texture array) |
2374 | with the same size (but a sample count of 1). The multisample content is |
2375 | automatically resolved into this texture at the end of each render pass. |
2376 | */ |
2377 | |
2378 | /*! |
2379 | \fn void QRhiColorAttachment::setResolveTexture(QRhiTexture *tex) |
2380 | |
2381 | Sets the resolve texture \a tex. |
2382 | |
2383 | \a tex is expected to be a 2D texture or a 2D texture array. In either |
2384 | case, resolving targets a single mip level of a single layer (array |
2385 | element) of \a tex. The mip level and array layer are specified by |
2386 | resolveLevel() and resolveLayer(). |
2387 | |
2388 | An exception is \l{setMultiViewCount()}{multiview}: when the color |
2389 | attachment is associated with a texture array and multiview is enabled, the |
2390 | resolve texture must also be a texture array with sufficient elements for |
2391 | all views. In this case all elements that correspond to views are resolved |
2392 | automatically; the behavior is similar to the following pseudo-code: |
2393 | \badcode |
2394 | for (i = 0; i < multiViewCount(); ++i) |
2395 | resolve texture's layer() + i into resolveTexture's resolveLayer() + i |
2396 | \endcode |
2397 | |
2398 | Setting a non-multisample texture to resolve a multisample texture or |
2399 | renderbuffer automatically at the end of the render pass is often |
2400 | preferable to working with multisample textures (and not setting a resolve |
2401 | texture), because it avoids the need for writing dedicated fragment shaders |
2402 | that work exclusively with multisample textures (\c sampler2DMS, \c |
2403 | texelFetch, etc.), and rather allows using the same shader as one would if |
2404 | the attachment's texture was not multisampled to begin with. This comes at |
2405 | the expense of an additional resource (the non-multisample \a tex). |
2406 | */ |
2407 | |
2408 | /*! |
2409 | \fn int QRhiColorAttachment::resolveLayer() const |
2410 | \return the currently set resolve texture layer. Defaults to 0. |
2411 | */ |
2412 | |
2413 | /*! |
2414 | \fn void QRhiColorAttachment::setResolveLayer(int layer) |
2415 | Sets the resolve texture \a layer to use. |
2416 | */ |
2417 | |
2418 | /*! |
2419 | \fn int QRhiColorAttachment::resolveLevel() const |
2420 | \return the currently set resolve texture mip level. Defaults to 0. |
2421 | */ |
2422 | |
2423 | /*! |
2424 | \fn void QRhiColorAttachment::setResolveLevel(int level) |
2425 | Sets the resolve texture mip \a level to use. |
2426 | */ |
2427 | |
2428 | /*! |
2429 | \fn int QRhiColorAttachment::multiViewCount() const |
2430 | |
2431 | \return the currently set number of views. Defaults to 0 which indicates |
2432 | the render target with this color attachment is not going to be used with |
2433 | multiview rendering. |
2434 | |
2435 | \since 6.7 |
2436 | */ |
2437 | |
2438 | /*! |
2439 | \fn void QRhiColorAttachment::setMultiViewCount(int count) |
2440 | |
2441 | Sets the view \a count. Setting a value larger than 1 indicates that the |
2442 | render target with this color attachment is going to be used with multiview |
2443 | rendering. The default value is 0. Values smaller than 2 indicate no |
2444 | multiview rendering. |
2445 | |
2446 | When \a count is set to \c 2 or greater, the color attachment must be |
2447 | associated with a 2D texture array. layer() and multiViewCount() together |
2448 | define the range of texture array elements that are targeted during |
2449 | multiview rendering. |
2450 | |
2451 | For example, if \c layer is \c 0 and \c multiViewCount is \c 2, the texture |
2452 | array must have 2 (or more) elements, and the multiview rendering will |
2453 | target elements 0 and 1. The \c{gl_ViewIndex} variable in the shaders has a |
2454 | value of \c 0 or \c 1 then, where view \c 0 corresponds to the texture array |
2455 | element \c 0, and view \c 1 to the array element \c 1. |
2456 | |
2457 | \note Setting a \a count larger than 1, using a texture array as texture(), |
2458 | and calling \l{QRhiCommandBuffer::beginPass()}{beginPass()} on a |
2459 | QRhiTextureRenderTarget with this color attachment implies multiview |
2460 | rendering for the entire render pass. multiViewCount() should not be set |
2461 | unless multiview rendering is wanted. Multiview cannot be used with texture |
2462 | types other than 2D texture arrays. (although 3D textures may work, |
2463 | depending on the graphics API and backend; applications are nonetheless |
2464 | advised not to rely on that and only use 2D texture arrays as the render |
2465 | targets of multiview rendering) |
2466 | |
2467 | See |
2468 | \l{https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview.txt}{GL_OVR_multiview} |
2469 | for more details regarding multiview rendering. Do note that Qt requires |
2470 | \l{https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview2.txt}{GL_OVR_multiview2} |
2471 | as well, when running on OpenGL (ES). |
2472 | |
2473 | Multiview rendering is available only when the |
2474 | \l{QRhi::MultiView}{MultiView} feature is reported as supported from |
2475 | \l{QRhi::isFeatureSupported()}{isFeatureSupported()}. |
2476 | |
2477 | \note For portability, be aware of limitations that exist for multiview |
2478 | rendering with some of the graphics APIs. It is recommended that multiview |
2479 | render passes do not rely on any of the features that |
2480 | \l{https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview.txt}{GL_OVR_multiview} |
2481 | declares as unsupported. The one exception is shader stage outputs other |
2482 | than \c{gl_Position} depending on \c{gl_ViewIndex}: that can be relied on |
2483 | (even with OpenGL) because QRhi never reports multiview as supported without |
2484 | \c{GL_OVR_multiview2} also being present. |
2485 | |
2486 | \note Multiview rendering is not supported in combination with tessellation |
2487 | or geometry shaders, even though some implementations of some graphics APIs |
2488 | may allow this. |
2489 | |
2490 | \since 6.7 |
2491 | */ |
2492 | |
2493 | /*! |
2494 | \class QRhiTextureRenderTargetDescription |
2495 | \inmodule QtGuiPrivate |
2496 | \inheaderfile rhi/qrhi.h |
2497 | \since 6.6 |
2498 | \brief Describes the color and depth or depth/stencil attachments of a render target. |
2499 | |
2500 | A texture render target has zero or more textures as color attachments, |
2501 | zero or one renderbuffer as combined depth/stencil buffer or zero or one |
2502 | texture as depth buffer. |
2503 | |
2504 | \note depthStencilBuffer() and depthTexture() cannot be both set (cannot be |
2505 | non-null at the same time). |
2506 | |
2507 | Let's look at some example usages in combination with |
2508 | QRhiTextureRenderTarget. |
2509 | |
2510 | Due to the constructors, the targeting a texture (and no depth/stencil |
2511 | buffer) is simple: |
2512 | |
2513 | \code |
2514 | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(256, 256), 1, QRhiTexture::RenderTarget); |
2515 | texture->create(); |
2516 | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ texture })); |
2517 | \endcode |
2518 | |
2519 | The following creates a texture render target that is set up to target mip |
2520 | level #2 of a texture: |
2521 | |
2522 | \code |
2523 | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget | QRhiTexture::MipMapped); |
2524 | texture->create(); |
2525 | QRhiColorAttachment colorAtt(texture); |
2526 | colorAtt.setLevel(2); |
2527 | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ colorAtt }); |
2528 | \endcode |
2529 | |
2530 | Another example, this time to render into a depth texture: |
2531 | |
2532 | \code |
2533 | QRhiTexture *shadowMap = rhi->newTexture(QRhiTexture::D32F, QSize(1024, 1024), 1, QRhiTexture::RenderTarget); |
2534 | shadowMap->create(); |
2535 | QRhiTextureRenderTargetDescription rtDesc; |
2536 | rtDesc.setDepthTexture(shadowMap); |
2537 | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget(rtDesc); |
2538 | \endcode |
2539 | |
2540 | A very common case, having a texture as the color attachment and a |
2541 | renderbuffer as depth/stencil to enable depth testing: |
2542 | |
2543 | \code |
2544 | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget); |
2545 | texture->create(); |
2546 | QRhiRenderBuffer *depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, QSize(512, 512)); |
2547 | depthStencil->create(); |
2548 | QRhiTextureRenderTargetDescription rtDesc({ texture }, depthStencil); |
2549 | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget(rtDesc); |
2550 | \endcode |
2551 | |
2552 | Finally, to enable multisample rendering in a portable manner (so also |
2553 | supporting OpenGL ES 3.0), using a QRhiRenderBuffer as the (multisample) |
2554 | color buffer and then resolving into a regular (non-multisample) 2D |
2555 | texture. To enable depth testing, a depth-stencil buffer, which also must |
2556 | use the same sample count, is used as well: |
2557 | |
2558 | \code |
2559 | QRhiRenderBuffer *colorBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::Color, QSize(512, 512), 4); // 4x MSAA |
2560 | colorBuffer->create(); |
2561 | QRhiRenderBuffer *depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, QSize(512, 512), 4); |
2562 | depthStencil->create(); |
2563 | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget); |
2564 | texture->create(); |
2565 | QRhiColorAttachment colorAtt(colorBuffer); |
2566 | colorAtt.setResolveTexture(texture); |
2567 | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ colorAtt, depthStencil }); |
2568 | \endcode |
2569 | |
2570 | \note when multisample resolving is enabled, the multisample data may not be |
2571 | written out at all. This means that the multisample texture in a color |
2572 | attachment must not be used afterwards with shaders for sampling (or other |
2573 | purposes) whenever a resolve texture is set, since the multisample color |
2574 | buffer is merely an intermediate storage then that gets no data written back |
2575 | on some GPU architectures at all. See |
2576 | \l{QRhiTextureRenderTarget::Flag}{PreserveColorContents} for more details. |
2577 | |
2578 | \note When using setDepthTexture(), not setDepthStencilBuffer(), and the |
2579 | depth (stencil) data is not of interest afterwards, set the |
2580 | DoNotStoreDepthStencilContents flag on the QRhiTextureRenderTarget. This |
2581 | allows indicating to the underlying 3D API that the depth/stencil data can |
2582 | be discarded, leading potentially to better performance with tiled GPU |
2583 | architectures. When the depth-stencil buffer is a QRhiRenderBuffer (and also |
2584 | for the multisample color texture, see previous note) this is implicit, but |
2585 | with a depth (stencil) QRhiTexture the intention needs to be declared |
2586 | explicitly. By default QRhi assumes that the data is of interest (e.g., the |
2587 | depth texture is sampled in a shader afterwards). |
2588 | |
2589 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2590 | for details. |
2591 | |
2592 | \sa QRhiColorAttachment, QRhiTextureRenderTarget |
2593 | */ |
2594 | |
2595 | /*! |
2596 | \fn QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription() = default |
2597 | |
2598 | Constructs an empty texture render target description. |
2599 | */ |
2600 | |
2601 | /*! |
2602 | Constructs a texture render target description with one attachment |
2603 | described by \a colorAttachment. |
2604 | */ |
2605 | QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment) |
2606 | { |
2607 | m_colorAttachments.append(t: colorAttachment); |
2608 | } |
2609 | |
2610 | /*! |
2611 | Constructs a texture render target description with two attachments, a |
2612 | color attachment described by \a colorAttachment, and a depth/stencil |
2613 | attachment with \a depthStencilBuffer. |
2614 | */ |
2615 | QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, |
2616 | QRhiRenderBuffer *depthStencilBuffer) |
2617 | : m_depthStencilBuffer(depthStencilBuffer) |
2618 | { |
2619 | m_colorAttachments.append(t: colorAttachment); |
2620 | } |
2621 | |
2622 | /*! |
2623 | Constructs a texture render target description with two attachments, a |
2624 | color attachment described by \a colorAttachment, and a depth attachment |
2625 | with \a depthTexture. |
2626 | |
2627 | \note \a depthTexture must have a suitable format, such as QRhiTexture::D16 |
2628 | or QRhiTexture::D32F. |
2629 | */ |
2630 | QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, |
2631 | QRhiTexture *depthTexture) |
2632 | : m_depthTexture(depthTexture) |
2633 | { |
2634 | m_colorAttachments.append(t: colorAttachment); |
2635 | } |
2636 | |
2637 | /*! |
2638 | \fn void QRhiTextureRenderTargetDescription::setColorAttachments(std::initializer_list<QRhiColorAttachment> list) |
2639 | Sets the \a list of color attachments. |
2640 | */ |
2641 | |
2642 | /*! |
2643 | \fn template<typename InputIterator> void QRhiTextureRenderTargetDescription::setColorAttachments(InputIterator first, InputIterator last) |
2644 | Sets the list of color attachments via the iterators \a first and \a last. |
2645 | */ |
2646 | |
2647 | /*! |
2648 | \fn const QRhiColorAttachment *QRhiTextureRenderTargetDescription::cbeginColorAttachments() const |
2649 | \return a const iterator pointing to the first item in the attachment list. |
2650 | */ |
2651 | |
2652 | /*! |
2653 | \fn const QRhiColorAttachment *QRhiTextureRenderTargetDescription::cendColorAttachments() const |
2654 | \return a const iterator pointing just after the last item in the attachment list. |
2655 | */ |
2656 | |
2657 | /*! |
2658 | \fn const QRhiColorAttachment *QRhiTextureRenderTargetDescription::colorAttachmentAt(qsizetype index) const |
2659 | \return the color attachment at the specified \a index. |
2660 | */ |
2661 | |
2662 | /*! |
2663 | \fn qsizetype QRhiTextureRenderTargetDescription::colorAttachmentCount() const |
2664 | \return the number of currently set color attachments. |
2665 | */ |
2666 | |
2667 | /*! |
2668 | \fn QRhiRenderBuffer *QRhiTextureRenderTargetDescription::depthStencilBuffer() const |
2669 | \return the renderbuffer used as depth-stencil buffer, or \nullptr if none was set. |
2670 | */ |
2671 | |
2672 | /*! |
2673 | \fn void QRhiTextureRenderTargetDescription::setDepthStencilBuffer(QRhiRenderBuffer *renderBuffer) |
2674 | |
2675 | Sets the \a renderBuffer for depth-stencil. Not mandatory, e.g. when no |
2676 | depth test/write or stencil-related features are used within any graphics |
2677 | pipelines in any of the render passes for this render target, it can be |
2678 | left set to \nullptr. |
2679 | |
2680 | \note depthStencilBuffer() and depthTexture() cannot be both set (cannot be |
2681 | non-null at the same time). |
2682 | |
2683 | Using a QRhiRenderBuffer over a 2D QRhiTexture as the depth or |
2684 | depth/stencil buffer is very common, and is the recommended approach for |
2685 | applications. Using a QRhiTexture, and so setDepthTexture() becomes |
2686 | relevant if the depth data is meant to be accessed (e.g. sampled in a |
2687 | shader) afterwards, or when |
2688 | \l{QRhiColorAttachment::setMultiViewCount()}{multiview rendering} is |
2689 | involved (because then the depth texture must be a texture array). |
2690 | |
2691 | \sa setDepthTexture() |
2692 | */ |
2693 | |
2694 | /*! |
2695 | \fn QRhiTexture *QRhiTextureRenderTargetDescription::depthTexture() const |
2696 | \return the currently referenced depth texture, or \nullptr if none was set. |
2697 | */ |
2698 | |
2699 | /*! |
2700 | \fn void QRhiTextureRenderTargetDescription::setDepthTexture(QRhiTexture *texture) |
2701 | |
2702 | Sets the \a texture for depth-stencil. This is an alternative to |
2703 | setDepthStencilBuffer(), where instead of a QRhiRenderBuffer a QRhiTexture |
2704 | with a suitable type (e.g., QRhiTexture::D32F) is provided. |
2705 | |
2706 | \note depthStencilBuffer() and depthTexture() cannot be both set (cannot be |
2707 | non-null at the same time). |
2708 | |
2709 | \a texture can either be a 2D texture or a 2D texture array (when texture |
2710 | arrays are supported). Specifying a texture array is relevant in particular |
2711 | with |
2712 | \l{QRhiColorAttachment::setMultiViewCount()}{multiview rendering}. |
2713 | |
2714 | \note If \a texture is a format with a stencil component, such as |
2715 | \l QRhiTexture::D24S8, it will serve as the stencil buffer as well. |
2716 | |
2717 | \sa setDepthStencilBuffer() |
2718 | */ |
2719 | |
2720 | /*! |
2721 | \fn QRhiTexture *QRhiTextureRenderTargetDescription::depthResolveTexture() const |
2722 | |
2723 | \return the texture to which a multisample depth (or depth-stencil) texture |
2724 | (or texture array) is resolved to. \nullptr if there is none, which is the |
2725 | most common case. |
2726 | |
2727 | \since 6.8 |
2728 | \sa QRhiColorAttachment::resolveTexture(), depthTexture() |
2729 | */ |
2730 | |
2731 | /*! |
2732 | \fn void QRhiTextureRenderTargetDescription::setDepthResolveTexture(QRhiTexture *tex) |
2733 | |
2734 | Sets the depth (or depth-stencil) resolve texture \a tex. |
2735 | |
2736 | \a tex is expected to be a 2D texture or a 2D texture array with a format |
2737 | matching the texture set via setDepthTexture(). |
2738 | |
2739 | \note Resolving depth (or depth-stencil) data is only functional when the |
2740 | \l ResolveDepthStencil feature is reported as supported at run time. Support |
2741 | for depth-stencil resolve is not universally available among the graphics |
2742 | APIs. Designs assuming unconditional availability of depth-stencil resolve |
2743 | are therefore non-portable, and should be avoided. |
2744 | |
2745 | \note As an additional limitation for OpenGL ES in particular, setting a |
2746 | depth resolve texture may only be functional in combination with |
2747 | setDepthTexture(), not with setDepthStencilBuffer(). |
2748 | |
2749 | \since 6.8 |
2750 | \sa QRhiColorAttachment::setResolveTexture(), setDepthTexture() |
2751 | */ |
2752 | |
2753 | /*! |
2754 | \class QRhiTextureSubresourceUploadDescription |
2755 | \inmodule QtGuiPrivate |
2756 | \inheaderfile rhi/qrhi.h |
2757 | \since 6.6 |
2758 | \brief Describes the source for one mip level in a layer in a texture upload operation. |
2759 | |
2760 | The source content is specified either as a QImage or as a raw blob. The |
2761 | former is only allowed for uncompressed textures with a format that can be |
2762 | mapped to QImage, while the latter is supported for all formats, including |
2763 | floating point and compressed. |
2764 | |
2765 | \note image() and data() cannot be both set at the same time. |
2766 | |
2767 | destinationTopLeft() specifies the top-left corner of the target |
2768 | rectangle. Defaults to (0, 0). |
2769 | |
2770 | An empty sourceSize() (the default) indicates that size is assumed to be |
2771 | the size of the subresource. With QImage-based uploads this implies that |
2772 | the size of the source image() must match the subresource. When providing |
2773 | raw data instead, sufficient number of bytes must be provided in data(). |
2774 | |
2775 | sourceTopLeft() is supported only for QImage-based uploads, and specifies |
2776 | the top-left corner of the source rectangle. |
2777 | |
2778 | \note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy |
2779 | internally, depending on the format and the backend. |
2780 | |
2781 | When providing raw data, and the stride is not specified via |
2782 | setDataStride(), the stride (row pitch, row length in bytes) of the |
2783 | provided data must be equal to \c{width * pixelSize} where \c pixelSize is |
2784 | the number of bytes used for one pixel, and there must be no additional |
2785 | padding between rows. There is no row start alignment requirement. |
2786 | |
2787 | When there is unused data at the end of each row in the input raw data, |
2788 | call setDataStride() with the total number of bytes per row. The stride |
2789 | must always be a multiple of the number of bytes for one pixel. The row |
2790 | stride is only applicable to image data for textures with an uncompressed |
2791 | format. |
2792 | |
2793 | \note The format of the source data must be compatible with the texture |
2794 | format. With many graphics APIs the data is copied as-is into a staging |
2795 | buffer, there is no intermediate format conversion provided by QRhi. This |
2796 | applies to floating point formats as well, with, for example, RGBA16F |
2797 | requiring half floats in the source data. |
2798 | |
2799 | \note Setting the stride via setDataStride() is only functional when |
2800 | QRhi::ImageDataStride is reported as |
2801 | \l{QRhi::isFeatureSupported()}{supported}. In practice this can be expected |
2802 | to be supported everywhere except for OpenGL ES 2.0. |
2803 | |
2804 | \note When a QImage is given, the stride returned from |
2805 | QImage::bytesPerLine() is taken into account automatically. |
2806 | |
2807 | \warning When a QImage is given and the QImage does not own the underlying |
2808 | pixel data, it is up to the caller to ensure that the associated data stays |
2809 | valid until the end of the frame. (just submitting the resource update batch |
2810 | is not sufficient, the data must stay valid until QRhi::endFrame() is called |
2811 | in order to be portable across all backends) If this cannot be ensured, the |
2812 | caller is strongly encouraged to call QImage::detach() on the image before |
2813 | passing it to uploadTexture(). |
2814 | |
2815 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2816 | for details. |
2817 | |
2818 | \sa QRhiTextureUploadDescription |
2819 | */ |
2820 | |
2821 | /*! |
2822 | \fn QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription() = default |
2823 | |
2824 | Constructs an empty subresource description. |
2825 | |
2826 | \note an empty QRhiTextureSubresourceUploadDescription is not useful on its |
2827 | own and should not be submitted to a QRhiTextureUploadEntry. At minimum |
2828 | image or data must be set first. |
2829 | */ |
2830 | |
2831 | /*! |
2832 | Constructs a mip level description with a \a image. |
2833 | |
2834 | The \l{QImage::size()}{size} of \a image must match the size of the mip |
2835 | level. For level 0 that is the \l{QRhiTexture::pixelSize()}{texture size}. |
2836 | |
2837 | The bit depth of \a image must be compatible with the |
2838 | \l{QRhiTexture::Format}{texture format}. |
2839 | |
2840 | To describe a partial upload, call setSourceSize(), setSourceTopLeft(), or |
2841 | setDestinationTopLeft() afterwards. |
2842 | */ |
2843 | QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription(const QImage &image) |
2844 | : m_image(image) |
2845 | { |
2846 | } |
2847 | |
2848 | /*! |
2849 | Constructs a mip level description with the image data is specified by \a |
2850 | data and \a size. This is suitable for floating point and compressed |
2851 | formats as well. |
2852 | |
2853 | \a data can safely be destroyed or changed once this function returns. |
2854 | */ |
2855 | QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription(const void *data, quint32 size) |
2856 | : m_data(reinterpret_cast<const char *>(data), size) |
2857 | { |
2858 | } |
2859 | |
2860 | /*! |
2861 | Constructs a mip level description with the image data specified by \a |
2862 | data. This is suitable for floating point and compressed formats as well. |
2863 | */ |
2864 | QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription(const QByteArray &data) |
2865 | : m_data(data) |
2866 | { |
2867 | } |
2868 | |
2869 | /*! |
2870 | \fn QImage QRhiTextureSubresourceUploadDescription::image() const |
2871 | \return the currently set QImage. |
2872 | */ |
2873 | |
2874 | /*! |
2875 | \fn void QRhiTextureSubresourceUploadDescription::setImage(const QImage &image) |
2876 | |
2877 | Sets \a image. |
2878 | Upon textures loading, the image data will be read as is, with no formats conversions. |
2879 | |
2880 | \note image() and data() cannot be both set at the same time. |
2881 | */ |
2882 | |
2883 | /*! |
2884 | \fn QByteArray QRhiTextureSubresourceUploadDescription::data() const |
2885 | \return the currently set raw pixel data. |
2886 | */ |
2887 | |
2888 | /*! |
2889 | \fn void QRhiTextureSubresourceUploadDescription::setData(const QByteArray &data) |
2890 | |
2891 | Sets \a data. |
2892 | |
2893 | \note image() and data() cannot be both set at the same time. |
2894 | */ |
2895 | |
2896 | /*! |
2897 | \fn quint32 QRhiTextureSubresourceUploadDescription::dataStride() const |
2898 | \return the currently set data stride. |
2899 | */ |
2900 | |
2901 | /*! |
2902 | \fn void QRhiTextureSubresourceUploadDescription::setDataStride(quint32 stride) |
2903 | |
2904 | Sets the data \a stride in bytes. By default this is 0 and not always |
2905 | relevant. When providing raw data(), and the stride is not specified via |
2906 | setDataStride(), the stride (row pitch, row length in bytes) of the |
2907 | provided data must be equal to \c{width * pixelSize} where \c pixelSize is |
2908 | the number of bytes used for one pixel, and there must be no additional |
2909 | padding between rows. Otherwise, if there is additional space between the |
2910 | lines, set a non-zero \a stride. All this is applicable only when raw image |
2911 | data is provided, and is not necessary when working QImage since that has |
2912 | its own \l{QImage::bytesPerLine()}{stride} value. |
2913 | |
2914 | \note Setting the stride via setDataStride() is only functional when |
2915 | QRhi::ImageDataStride is reported as |
2916 | \l{QRhi::isFeatureSupported()}{supported}. |
2917 | |
2918 | \note When a QImage is given, the stride returned from |
2919 | QImage::bytesPerLine() is taken into account automatically and therefore |
2920 | there is no need to set the data stride manually. |
2921 | */ |
2922 | |
2923 | /*! |
2924 | \fn QPoint QRhiTextureSubresourceUploadDescription::destinationTopLeft() const |
2925 | \return the currently set destination top-left position. Defaults to (0, 0). |
2926 | */ |
2927 | |
2928 | /*! |
2929 | \fn void QRhiTextureSubresourceUploadDescription::setDestinationTopLeft(const QPoint &p) |
2930 | Sets the destination top-left position \a p. |
2931 | */ |
2932 | |
2933 | /*! |
2934 | \fn QSize QRhiTextureSubresourceUploadDescription::sourceSize() const |
2935 | |
2936 | \return the source size in pixels. Defaults to a default-constructed QSize, |
2937 | which indicates the entire subresource. |
2938 | */ |
2939 | |
2940 | /*! |
2941 | \fn void QRhiTextureSubresourceUploadDescription::setSourceSize(const QSize &size) |
2942 | |
2943 | Sets the source \a size in pixels. |
2944 | |
2945 | \note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy |
2946 | internally, depending on the format and the backend. |
2947 | */ |
2948 | |
2949 | /*! |
2950 | \fn QPoint QRhiTextureSubresourceUploadDescription::sourceTopLeft() const |
2951 | \return the currently set source top-left position. Defaults to (0, 0). |
2952 | */ |
2953 | |
2954 | /*! |
2955 | \fn void QRhiTextureSubresourceUploadDescription::setSourceTopLeft(const QPoint &p) |
2956 | |
2957 | Sets the source top-left position \a p. |
2958 | |
2959 | \note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy |
2960 | internally, depending on the format and the backend. |
2961 | */ |
2962 | |
2963 | /*! |
2964 | \class QRhiTextureUploadEntry |
2965 | \inmodule QtGuiPrivate |
2966 | \inheaderfile rhi/qrhi.h |
2967 | \since 6.6 |
2968 | |
2969 | \brief Describes one layer (face for cubemaps, slice for 3D textures, |
2970 | element for texture arrays) in a texture upload operation. |
2971 | |
2972 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2973 | for details. |
2974 | */ |
2975 | |
2976 | /*! |
2977 | \fn QRhiTextureUploadEntry::QRhiTextureUploadEntry() |
2978 | |
2979 | Constructs an empty QRhiTextureUploadEntry targeting layer 0 and level 0. |
2980 | |
2981 | \note an empty QRhiTextureUploadEntry should not be submitted without |
2982 | setting a QRhiTextureSubresourceUploadDescription via setDescription() |
2983 | first. |
2984 | */ |
2985 | |
2986 | /*! |
2987 | Constructs a QRhiTextureUploadEntry targeting the given \a layer and mip |
2988 | \a level, with the subresource contents described by \a desc. |
2989 | */ |
2990 | QRhiTextureUploadEntry::QRhiTextureUploadEntry(int layer, int level, |
2991 | const QRhiTextureSubresourceUploadDescription &desc) |
2992 | : m_layer(layer), |
2993 | m_level(level), |
2994 | m_desc(desc) |
2995 | { |
2996 | } |
2997 | |
2998 | /*! |
2999 | \fn int QRhiTextureUploadEntry::layer() const |
3000 | \return the currently set layer index (cubemap face, array layer). Defaults to 0. |
3001 | */ |
3002 | |
3003 | /*! |
3004 | \fn void QRhiTextureUploadEntry::setLayer(int layer) |
3005 | Sets the \a layer. |
3006 | */ |
3007 | |
3008 | /*! |
3009 | \fn int QRhiTextureUploadEntry::level() const |
3010 | \return the currently set mip level. Defaults to 0. |
3011 | */ |
3012 | |
3013 | /*! |
3014 | \fn void QRhiTextureUploadEntry::setLevel(int level) |
3015 | Sets the mip \a level. |
3016 | */ |
3017 | |
3018 | /*! |
3019 | \fn QRhiTextureSubresourceUploadDescription QRhiTextureUploadEntry::description() const |
3020 | \return the currently set subresource description. |
3021 | */ |
3022 | |
3023 | /*! |
3024 | \fn void QRhiTextureUploadEntry::setDescription(const QRhiTextureSubresourceUploadDescription &desc) |
3025 | Sets the subresource description \a desc. |
3026 | */ |
3027 | |
3028 | /*! |
3029 | \class QRhiTextureUploadDescription |
3030 | \inmodule QtGuiPrivate |
3031 | \inheaderfile rhi/qrhi.h |
3032 | \since 6.6 |
3033 | \brief Describes a texture upload operation. |
3034 | |
3035 | Used with QRhiResourceUpdateBatch::uploadTexture(). That function has two |
3036 | variants: one taking a QImage and one taking a |
3037 | QRhiTextureUploadDescription. The former is a convenience version, |
3038 | internally creating a QRhiTextureUploadDescription with a single image |
3039 | targeting level 0 for layer 0. |
3040 | |
3041 | An example of the the common, simple case of wanting to upload the contents |
3042 | of a QImage to a QRhiTexture with a matching pixel size: |
3043 | |
3044 | \code |
3045 | QImage image(256, 256, QImage::Format_RGBA8888); |
3046 | image.fill(Qt::green); // or could use a QPainter targeting image |
3047 | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(256, 256)); |
3048 | texture->create(); |
3049 | QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch(); |
3050 | u->uploadTexture(texture, image); |
3051 | \endcode |
3052 | |
3053 | When cubemaps, pre-generated mip images, compressed textures, or partial |
3054 | uploads are involved, applications will have to use this class instead. |
3055 | |
3056 | QRhiTextureUploadDescription also enables specifying batched uploads, which |
3057 | are useful for example when generating an atlas or glyph cache texture: |
3058 | multiple, partial uploads for the same subresource (meaning the same layer |
3059 | and level) are supported, and can be, depending on the backend and the |
3060 | underlying graphics API, more efficient when batched into the same |
3061 | QRhiTextureUploadDescription as opposed to issuing individual |
3062 | \l{QRhiResourceUpdateBatch::uploadTexture()}{uploadTexture()} commands for |
3063 | each of them. |
3064 | |
3065 | \note Cubemaps have one layer for each of the six faces in the order +X, |
3066 | -X, +Y, -Y, +Z, -Z. |
3067 | |
3068 | For example, specifying the faces of a cubemap could look like the following: |
3069 | |
3070 | \code |
3071 | QImage faces[6]; |
3072 | // ... |
3073 | QVarLengthArray<QRhiTextureUploadEntry, 6> entries; |
3074 | for (int i = 0; i < 6; ++i) |
3075 | entries.append(QRhiTextureUploadEntry(i, 0, faces[i])); |
3076 | QRhiTextureUploadDescription desc; |
3077 | desc.setEntries(entries.cbegin(), entries.cend()); |
3078 | resourceUpdates->uploadTexture(texture, desc); |
3079 | \endcode |
3080 | |
3081 | Another example that specifies mip images for a compressed texture: |
3082 | |
3083 | \code |
3084 | QList<QRhiTextureUploadEntry> entries; |
3085 | const int mipCount = rhi->mipLevelsForSize(compressedTexture->pixelSize()); |
3086 | for (int level = 0; level < mipCount; ++level) { |
3087 | const QByteArray compressedDataForLevel = .. |
3088 | entries.append(QRhiTextureUploadEntry(0, level, compressedDataForLevel)); |
3089 | } |
3090 | QRhiTextureUploadDescription desc; |
3091 | desc.setEntries(entries.cbegin(), entries.cend()); |
3092 | resourceUpdates->uploadTexture(compressedTexture, desc); |
3093 | \endcode |
3094 | |
3095 | With partial uploads targeting the same subresource, it is recommended to |
3096 | batch them into a single upload request, whenever possible: |
3097 | |
3098 | \code |
3099 | QRhiTextureSubresourceUploadDescription subresDesc(image); |
3100 | subresDesc.setSourceSize(QSize(10, 10)); |
3101 | subResDesc.setDestinationTopLeft(QPoint(50, 40)); |
3102 | QRhiTextureUploadEntry entry(0, 0, subresDesc); // layer 0, level 0 |
3103 | |
3104 | QRhiTextureSubresourceUploadDescription subresDesc2(image); |
3105 | subresDesc2.setSourceSize(QSize(30, 40)); |
3106 | subResDesc2.setDestinationTopLeft(QPoint(100, 200)); |
3107 | QRhiTextureUploadEntry entry2(0, 0, subresDesc2); // layer 0, level 0, i.e. same subresource |
3108 | |
3109 | QRhiTextureUploadDescription desc({ entry, entry2}); |
3110 | resourceUpdates->uploadTexture(texture, desc); |
3111 | \endcode |
3112 | |
3113 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3114 | for details. |
3115 | |
3116 | \sa QRhiResourceUpdateBatch |
3117 | */ |
3118 | |
3119 | /*! |
3120 | \fn QRhiTextureUploadDescription::QRhiTextureUploadDescription() |
3121 | |
3122 | Constructs an empty texture upload description. |
3123 | */ |
3124 | |
3125 | /*! |
3126 | Constructs a texture upload description with a single subresource upload |
3127 | described by \a entry. |
3128 | */ |
3129 | QRhiTextureUploadDescription::QRhiTextureUploadDescription(const QRhiTextureUploadEntry &entry) |
3130 | { |
3131 | m_entries.append(t: entry); |
3132 | } |
3133 | |
3134 | /*! |
3135 | Constructs a texture upload description with the specified \a list of entries. |
3136 | |
3137 | \note \a list can also contain multiple QRhiTextureUploadEntry elements |
3138 | with the same layer and level. This makes sense when those uploads are |
3139 | partial, meaning their subresource description has a source size or image |
3140 | smaller than the subresource dimensions, and can be more efficient than |
3141 | issuing separate uploadTexture()'s. |
3142 | */ |
3143 | QRhiTextureUploadDescription::QRhiTextureUploadDescription(std::initializer_list<QRhiTextureUploadEntry> list) |
3144 | : m_entries(list) |
3145 | { |
3146 | } |
3147 | |
3148 | /*! |
3149 | \fn void QRhiTextureUploadDescription::setEntries(std::initializer_list<QRhiTextureUploadEntry> list) |
3150 | Sets the \a list of entries. |
3151 | */ |
3152 | |
3153 | /*! |
3154 | \fn template<typename InputIterator> void QRhiTextureUploadDescription::setEntries(InputIterator first, InputIterator last) |
3155 | Sets the list of entries using the iterators \a first and \a last. |
3156 | */ |
3157 | |
3158 | /*! |
3159 | \fn const QRhiTextureUploadEntry *QRhiTextureUploadDescription::cbeginEntries() const |
3160 | \return a const iterator pointing to the first item in the entry list. |
3161 | */ |
3162 | |
3163 | /*! |
3164 | \fn const QRhiTextureUploadEntry *QRhiTextureUploadDescription::cendEntries() const |
3165 | \return a const iterator pointing just after the last item in the entry list. |
3166 | */ |
3167 | |
3168 | /*! |
3169 | \fn const QRhiTextureUploadEntry *QRhiTextureUploadDescription::entryAt(qsizetype index) const |
3170 | \return the entry at \a index. |
3171 | */ |
3172 | |
3173 | /*! |
3174 | \fn qsizetype QRhiTextureUploadDescription::entryCount() const |
3175 | \return the number of entries. |
3176 | */ |
3177 | |
3178 | /*! |
3179 | \class QRhiTextureCopyDescription |
3180 | \inmodule QtGuiPrivate |
3181 | \inheaderfile rhi/qrhi.h |
3182 | \since 6.6 |
3183 | \brief Describes a texture-to-texture copy operation. |
3184 | |
3185 | An empty pixelSize() indicates that the entire subresource is to be copied. |
3186 | A default constructed copy description therefore leads to copying the |
3187 | entire subresource at level 0 of layer 0. |
3188 | |
3189 | \note The source texture must be created with |
3190 | QRhiTexture::UsedAsTransferSource. |
3191 | |
3192 | \note The source and destination rectangles defined by pixelSize(), |
3193 | sourceTopLeft(), and destinationTopLeft() must fit the source and |
3194 | destination textures, respectively. The behavior is undefined otherwise. |
3195 | |
3196 | With cubemaps, 3D textures, and texture arrays one face or slice can be |
3197 | copied at a time. The face or slice is specified by the source and |
3198 | destination layer indices. With mipmapped textures one mip level can be |
3199 | copied at a time. The source and destination layer and mip level indices can |
3200 | differ, but the size and position must be carefully controlled to avoid out |
3201 | of bounds copies, in which case the behavior is undefined. |
3202 | |
3203 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3204 | for details. |
3205 | */ |
3206 | |
3207 | /*! |
3208 | \fn QRhiTextureCopyDescription::QRhiTextureCopyDescription() |
3209 | |
3210 | Constructs an empty texture copy description. |
3211 | */ |
3212 | |
3213 | /*! |
3214 | \fn QSize QRhiTextureCopyDescription::pixelSize() const |
3215 | \return the size of the region to copy. |
3216 | |
3217 | \note An empty pixelSize() indicates that the entire subresource is to be |
3218 | copied. A default constructed copy description therefore leads to copying |
3219 | the entire subresource at level 0 of layer 0. |
3220 | */ |
3221 | |
3222 | /*! |
3223 | \fn void QRhiTextureCopyDescription::setPixelSize(const QSize &sz) |
3224 | Sets the size of the region to copy to \a sz. |
3225 | */ |
3226 | |
3227 | /*! |
3228 | \fn int QRhiTextureCopyDescription::sourceLayer() const |
3229 | \return the source array layer (cubemap face or array layer index). Defaults to 0. |
3230 | */ |
3231 | |
3232 | /*! |
3233 | \fn void QRhiTextureCopyDescription::setSourceLayer(int layer) |
3234 | Sets the source array \a layer. |
3235 | */ |
3236 | |
3237 | /*! |
3238 | \fn int QRhiTextureCopyDescription::sourceLevel() const |
3239 | \return the source mip level. Defaults to 0. |
3240 | */ |
3241 | |
3242 | /*! |
3243 | \fn void QRhiTextureCopyDescription::setSourceLevel(int level) |
3244 | Sets the source mip \a level. |
3245 | */ |
3246 | |
3247 | /*! |
3248 | \fn QPoint QRhiTextureCopyDescription::sourceTopLeft() const |
3249 | \return the source top-left position (in pixels). Defaults to (0, 0). |
3250 | */ |
3251 | |
3252 | /*! |
3253 | \fn void QRhiTextureCopyDescription::setSourceTopLeft(const QPoint &p) |
3254 | Sets the source top-left position to \a p. |
3255 | */ |
3256 | |
3257 | /*! |
3258 | \fn int QRhiTextureCopyDescription::destinationLayer() const |
3259 | \return the destination array layer (cubemap face or array layer index). Default to 0. |
3260 | */ |
3261 | |
3262 | /*! |
3263 | \fn void QRhiTextureCopyDescription::setDestinationLayer(int layer) |
3264 | Sets the destination array \a layer. |
3265 | */ |
3266 | |
3267 | /*! |
3268 | \fn int QRhiTextureCopyDescription::destinationLevel() const |
3269 | \return the destionation mip level. Defaults to 0. |
3270 | */ |
3271 | |
3272 | /*! |
3273 | \fn void QRhiTextureCopyDescription::setDestinationLevel(int level) |
3274 | Sets the destination mip \a level. |
3275 | */ |
3276 | |
3277 | /*! |
3278 | \fn QPoint QRhiTextureCopyDescription::destinationTopLeft() const |
3279 | \return the destionation top-left position in pixels. Defaults to (0, 0). |
3280 | */ |
3281 | |
3282 | /*! |
3283 | \fn void QRhiTextureCopyDescription::setDestinationTopLeft(const QPoint &p) |
3284 | Sets the destination top-left position \a p. |
3285 | */ |
3286 | |
3287 | /*! |
3288 | \class QRhiReadbackDescription |
3289 | \inmodule QtGuiPrivate |
3290 | \inheaderfile rhi/qrhi.h |
3291 | \since 6.6 |
3292 | \brief Describes a readback (reading back texture contents from possibly GPU-only memory) operation. |
3293 | |
3294 | The source of the readback operation is either a QRhiTexture or the |
3295 | current backbuffer of the currently targeted QRhiSwapChain. When |
3296 | texture() is not set, the swapchain is used. Otherwise the specified |
3297 | QRhiTexture is treated as the source. |
3298 | |
3299 | \note Textures used in readbacks must be created with |
3300 | QRhiTexture::UsedAsTransferSource. |
3301 | |
3302 | \note Swapchains used in readbacks must be created with |
3303 | QRhiSwapChain::UsedAsTransferSource. |
3304 | |
3305 | layer() and level() are only applicable when the source is a QRhiTexture. |
3306 | |
3307 | \note Multisample textures cannot be read back. Readbacks are supported for |
3308 | multisample swapchain buffers however. |
3309 | |
3310 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3311 | for details. |
3312 | */ |
3313 | |
3314 | /*! |
3315 | \fn QRhiReadbackDescription::QRhiReadbackDescription() = default |
3316 | |
3317 | Constructs an empty texture readback description. |
3318 | |
3319 | \note The source texture is set to null by default, which is still a valid |
3320 | readback: it specifies that the backbuffer of the current swapchain is to |
3321 | be read back. (current meaning the frame's target swapchain at the time of |
3322 | committing the QRhiResourceUpdateBatch with the |
3323 | \l{QRhiResourceUpdateBatch::readBackTexture()}{texture readback} on it) |
3324 | */ |
3325 | |
3326 | /*! |
3327 | Constructs an texture readback description that specifies that level 0 of |
3328 | layer 0 of \a texture is to be read back. |
3329 | |
3330 | \note \a texture can also be null in which case this constructor is |
3331 | identical to the argumentless variant. |
3332 | */ |
3333 | QRhiReadbackDescription::QRhiReadbackDescription(QRhiTexture *texture) |
3334 | : m_texture(texture) |
3335 | { |
3336 | } |
3337 | |
3338 | /*! |
3339 | \fn QRhiTexture *QRhiReadbackDescription::texture() const |
3340 | |
3341 | \return the QRhiTexture that is read back. Can be left set to \nullptr |
3342 | which indicates that the backbuffer of the current swapchain is to be used |
3343 | instead. |
3344 | */ |
3345 | |
3346 | /*! |
3347 | \fn void QRhiReadbackDescription::setTexture(QRhiTexture *tex) |
3348 | |
3349 | Sets the texture \a tex as the source of the readback operation. |
3350 | |
3351 | Setting \nullptr is valid too, in which case the current swapchain's |
3352 | current backbuffer is used. (but then the readback cannot be issued in a |
3353 | non-swapchain-based frame) |
3354 | |
3355 | \note Multisample textures cannot be read back. Readbacks are supported for |
3356 | multisample swapchain buffers however. |
3357 | |
3358 | \note Textures used in readbacks must be created with |
3359 | QRhiTexture::UsedAsTransferSource. |
3360 | |
3361 | \note Swapchains used in readbacks must be created with |
3362 | QRhiSwapChain::UsedAsTransferSource. |
3363 | */ |
3364 | |
3365 | /*! |
3366 | \fn int QRhiReadbackDescription::layer() const |
3367 | |
3368 | \return the currently set array layer (cubemap face, array index). Defaults to 0. |
3369 | |
3370 | Applicable only when the source of the readback is a QRhiTexture. |
3371 | */ |
3372 | |
3373 | /*! |
3374 | \fn void QRhiReadbackDescription::setLayer(int layer) |
3375 | Sets the array \a layer to read back. |
3376 | */ |
3377 | |
3378 | /*! |
3379 | \fn int QRhiReadbackDescription::level() const |
3380 | |
3381 | \return the currently set mip level. Defaults to 0. |
3382 | |
3383 | Applicable only when the source of the readback is a QRhiTexture. |
3384 | */ |
3385 | |
3386 | /*! |
3387 | \fn void QRhiReadbackDescription::setLevel(int level) |
3388 | Sets the mip \a level to read back. |
3389 | */ |
3390 | |
3391 | /*! |
3392 | \class QRhiReadbackResult |
3393 | \inmodule QtGuiPrivate |
3394 | \inheaderfile rhi/qrhi.h |
3395 | \since 6.6 |
3396 | \brief Describes the results of a potentially asynchronous buffer or texture readback operation. |
3397 | |
3398 | When \l completed is set, the function is invoked when the \l data is |
3399 | available. \l format and \l pixelSize are set upon completion together with |
3400 | \l data. |
3401 | |
3402 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3403 | for details. |
3404 | */ |
3405 | |
3406 | /*! |
3407 | \variable QRhiReadbackResult::completed |
3408 | |
3409 | Callback that is invoked upon completion, on the thread the QRhi operates |
3410 | on. Can be left set to \nullptr, in which case no callback is invoked. |
3411 | */ |
3412 | |
3413 | /*! |
3414 | \variable QRhiReadbackResult::format |
3415 | |
3416 | Valid only for textures, the texture format. |
3417 | */ |
3418 | |
3419 | /*! |
3420 | \variable QRhiReadbackResult::pixelSize |
3421 | |
3422 | Valid only for textures, the size in pixels. |
3423 | */ |
3424 | |
3425 | /*! |
3426 | \variable QRhiReadbackResult::data |
3427 | |
3428 | The buffer or image data. |
3429 | |
3430 | \sa QRhiResourceUpdateBatch::readBackTexture(), QRhiResourceUpdateBatch::readBackBuffer() |
3431 | */ |
3432 | |
3433 | |
3434 | /*! |
3435 | \class QRhiNativeHandles |
3436 | \inmodule QtGuiPrivate |
3437 | \inheaderfile rhi/qrhi.h |
3438 | \since 6.6 |
3439 | \brief Base class for classes exposing backend-specific collections of native resource objects. |
3440 | |
3441 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3442 | for details. |
3443 | */ |
3444 | |
3445 | /*! |
3446 | \class QRhiResource |
3447 | \inmodule QtGuiPrivate |
3448 | \inheaderfile rhi/qrhi.h |
3449 | \since 6.6 |
3450 | \brief Base class for classes encapsulating native resource objects. |
3451 | |
3452 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3453 | for details. |
3454 | */ |
3455 | |
3456 | /*! |
3457 | \enum QRhiResource::Type |
3458 | Specifies type of the resource. |
3459 | |
3460 | \value Buffer |
3461 | \value Texture |
3462 | \value Sampler |
3463 | \value RenderBuffer |
3464 | \value RenderPassDescriptor |
3465 | \value SwapChainRenderTarget |
3466 | \value TextureRenderTarget |
3467 | \value ShaderResourceBindings |
3468 | \value GraphicsPipeline |
3469 | \value SwapChain |
3470 | \value ComputePipeline |
3471 | \value CommandBuffer |
3472 | */ |
3473 | |
3474 | /*! |
3475 | \fn virtual QRhiResource::Type QRhiResource::resourceType() const = 0 |
3476 | |
3477 | \return the type of the resource. |
3478 | */ |
3479 | |
3480 | /*! |
3481 | \internal |
3482 | */ |
3483 | QRhiResource::QRhiResource(QRhiImplementation *rhi) |
3484 | : m_rhi(rhi) |
3485 | { |
3486 | m_id = QRhiGlobalObjectIdGenerator::newId(); |
3487 | } |
3488 | |
3489 | /*! |
3490 | Destructor. |
3491 | |
3492 | Releases (or requests deferred releasing of) the underlying native graphics |
3493 | resources, if there are any. |
3494 | |
3495 | \note Resources referenced by commands for the current frame should not be |
3496 | released until the frame is submitted by QRhi::endFrame(). |
3497 | |
3498 | \sa destroy() |
3499 | */ |
3500 | QRhiResource::~QRhiResource() |
3501 | { |
3502 | // destroy() cannot be called here, due to virtuals; it is up to the |
3503 | // subclasses to do that. |
3504 | } |
3505 | |
3506 | /*! |
3507 | \fn virtual void QRhiResource::destroy() = 0 |
3508 | |
3509 | Releases (or requests deferred releasing of) the underlying native graphics |
3510 | resources. Safe to call multiple times, subsequent invocations will be a |
3511 | no-op then. |
3512 | |
3513 | Once destroy() is called, the QRhiResource instance can be reused, by |
3514 | calling \c create() again. That will then result in creating new native |
3515 | graphics resources underneath. |
3516 | |
3517 | \note Resources referenced by commands for the current frame should not be |
3518 | released until the frame is submitted by QRhi::endFrame(). |
3519 | |
3520 | The QRhiResource destructor also performs the same task, so calling this |
3521 | function is not necessary before deleting a QRhiResource. |
3522 | |
3523 | \sa deleteLater() |
3524 | */ |
3525 | |
3526 | /*! |
3527 | When called without a frame being recorded, this function is equivalent to |
3528 | deleting the object. Between a QRhi::beginFrame() and QRhi::endFrame() |
3529 | however the behavior is different: the QRhiResource will not be destroyed |
3530 | until the frame is submitted via QRhi::endFrame(), thus satisfying the QRhi |
3531 | requirement of not altering QRhiResource objects that are referenced by the |
3532 | frame being recorded. |
3533 | |
3534 | If the QRhi that created this object is already destroyed, the object is |
3535 | deleted immediately. |
3536 | |
3537 | Using deleteLater() can be a useful convenience in many cases, and it |
3538 | complements the low-level guarantee (that the underlying native graphics |
3539 | objects are never destroyed until it is safe to do so and it is known for |
3540 | sure that they are not used by the GPU in an still in-flight frame), by |
3541 | offering a way to make sure the C++ object instances (of QRhiBuffer, |
3542 | QRhiTexture, etc.) themselves also stay valid until the end of the current |
3543 | frame. |
3544 | |
3545 | The following example shows a convenient way of creating a throwaway buffer |
3546 | that is only used in one frame and gets automatically released in |
3547 | endFrame(). (when it comes to the underlying native buffer(s), the usual |
3548 | guarantee applies: the QRhi backend defers the releasing of those until it |
3549 | is guaranteed that the frame in which the buffer is accessed by the GPU has |
3550 | completed) |
3551 | |
3552 | \code |
3553 | rhi->beginFrame(swapchain); |
3554 | QRhiBuffer *buf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, 256); |
3555 | buf->deleteLater(); // ! |
3556 | u = rhi->nextResourceUpdateBatch(); |
3557 | u->uploadStaticBuffer(buf, data); |
3558 | // ... draw with buf |
3559 | rhi->endFrame(); |
3560 | \endcode |
3561 | |
3562 | \sa destroy() |
3563 | */ |
3564 | void QRhiResource::deleteLater() |
3565 | { |
3566 | if (m_rhi) |
3567 | m_rhi->addDeleteLater(res: this); |
3568 | else |
3569 | delete this; |
3570 | } |
3571 | |
3572 | /*! |
3573 | \return the currently set object name. By default the name is empty. |
3574 | */ |
3575 | QByteArray QRhiResource::name() const |
3576 | { |
3577 | return m_objectName; |
3578 | } |
3579 | |
3580 | /*! |
3581 | Sets a \a name for the object. |
3582 | |
3583 | This allows getting descriptive names for the native graphics |
3584 | resources visible in graphics debugging tools, such as |
3585 | \l{https://renderdoc.org/}{RenderDoc} and |
3586 | \l{https://developer.apple.com/xcode/}{XCode}. |
3587 | |
3588 | When it comes to naming native objects by relaying the name via the |
3589 | appropriate graphics API, note that the name is ignored when |
3590 | QRhi::DebugMarkers are not supported, and may, depending on the backend, |
3591 | also be ignored when QRhi::EnableDebugMarkers is not set. |
3592 | |
3593 | \note The name may be ignored for objects other than buffers, |
3594 | renderbuffers, and textures, depending on the backend. |
3595 | |
3596 | \note The name may be modified. For slotted resources, such as a QRhiBuffer |
3597 | backed by multiple native buffers, QRhi will append a suffix to make the |
3598 | underlying native buffers easily distinguishable from each other. |
3599 | */ |
3600 | void QRhiResource::setName(const QByteArray &name) |
3601 | { |
3602 | m_objectName = name; |
3603 | } |
3604 | |
3605 | /*! |
3606 | \return the global, unique identifier of this QRhiResource. |
3607 | |
3608 | User code rarely needs to deal with the value directly. It is used |
3609 | internally for tracking and bookkeeping purposes. |
3610 | */ |
3611 | quint64 QRhiResource::globalResourceId() const |
3612 | { |
3613 | return m_id; |
3614 | } |
3615 | |
3616 | /*! |
3617 | \return the QRhi that created this resource. |
3618 | |
3619 | If the QRhi that created this object is already destroyed, the result is |
3620 | \nullptr. |
3621 | */ |
3622 | QRhi *QRhiResource::rhi() const |
3623 | { |
3624 | return m_rhi ? m_rhi->q : nullptr; |
3625 | } |
3626 | |
3627 | /*! |
3628 | \class QRhiBuffer |
3629 | \inmodule QtGuiPrivate |
3630 | \inheaderfile rhi/qrhi.h |
3631 | \since 6.6 |
3632 | \brief Vertex, index, or uniform (constant) buffer resource. |
3633 | |
3634 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3635 | for details. |
3636 | |
3637 | A QRhiBuffer encapsulates zero, one, or more native buffer objects (such as |
3638 | a \c VkBuffer or \c MTLBuffer). With some graphics APIs and backends |
3639 | certain types of buffers may not use a native buffer object at all (e.g. |
3640 | OpenGL if uniform buffer objects are not used), but this is transparent to |
3641 | the user of the QRhiBuffer API. Similarly, the fact that some types of |
3642 | buffers may use two or three native buffers underneath, in order to allow |
3643 | efficient per-frame content update without stalling the GPU pipeline, is |
3644 | mostly invisible to the applications and libraries. |
3645 | |
3646 | A QRhiBuffer instance is always created by calling |
3647 | \l{QRhi::newBuffer()}{the QRhi's newBuffer() function}. This creates no |
3648 | native graphics resources. To do that, call create() after setting the |
3649 | appropriate options, such as the type, usage flags, size, although in most cases these |
3650 | are already set based on the arguments passed to |
3651 | \l{QRhi::newBuffer()}{newBuffer()}. |
3652 | |
3653 | \section2 Example usage |
3654 | |
3655 | To create a uniform buffer for a shader where the GLSL uniform block |
3656 | contains a single \c mat4 member, and update the contents: |
3657 | |
3658 | \code |
3659 | QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64); |
3660 | if (!ubuf->create()) { error(); } |
3661 | QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); |
3662 | QMatrix4x4 mvp; |
3663 | // ... set up the modelview-projection matrix |
3664 | batch->updateDynamicBuffer(ubuf, 0, 64, mvp.constData()); |
3665 | // ... |
3666 | commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call |
3667 | \endcode |
3668 | |
3669 | An example of creating a buffer with vertex data: |
3670 | |
3671 | \code |
3672 | const float vertices[] = { -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 1.0f }; |
3673 | QRhiBuffer *vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices)); |
3674 | if (!vbuf->create()) { error(); } |
3675 | QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); |
3676 | batch->uploadStaticBuffer(vbuf, vertices); |
3677 | // ... |
3678 | commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call |
3679 | \endcode |
3680 | |
3681 | An index buffer: |
3682 | |
3683 | \code |
3684 | static const quint16 indices[] = { 0, 1, 2 }; |
3685 | QRhiBuffer *ibuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(indices)); |
3686 | if (!ibuf->create()) { error(); } |
3687 | QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); |
3688 | batch->uploadStaticBuffer(ibuf, indices); |
3689 | // ... |
3690 | commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call |
3691 | \endcode |
3692 | |
3693 | \section2 Common patterns |
3694 | |
3695 | A call to create() destroys any existing native resources if create() was |
3696 | successfully called before. If those native resources are still in use by |
3697 | an in-flight frame (i.e., there's a chance they are still read by the GPU), |
3698 | the destroying of those resources is deferred automatically. Thus a very |
3699 | common and convenient pattern to safely increase the size of an already |
3700 | initialized buffer is the following. In practice this drops and creates a |
3701 | whole new set of native resources underneath, so it is not necessarily a |
3702 | cheap operation, but is more convenient and still faster than the |
3703 | alternatives, because by not destroying the \c buf object itself, all |
3704 | references to it stay valid in other data structures (e.g., in any |
3705 | QRhiShaderResourceBinding the QRhiBuffer is referenced from). |
3706 | |
3707 | \code |
3708 | if (buf->size() < newSize) { |
3709 | buf->setSize(newSize); |
3710 | if (!buf->create()) { error(); } |
3711 | } |
3712 | // continue using buf, fill it with new data |
3713 | \endcode |
3714 | |
3715 | When working with uniform buffers, it will sometimes be necessary to |
3716 | combine data for multiple draw calls into a single buffer for efficiency |
3717 | reasons. Be aware of the aligment requirements: with some graphics APIs |
3718 | offsets for a uniform buffer must be aligned to 256 bytes. This applies |
3719 | both to QRhiShaderResourceBinding and to the dynamic offsets passed to |
3720 | \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()}. Use the |
3721 | \l{QRhi::ubufAlignment()}{ubufAlignment()} and |
3722 | \l{QRhi::ubufAligned()}{ubufAligned()} functions to create portable code. |
3723 | As an example, the following is an outline for issuing multiple (\c N) draw |
3724 | calls with the same pipeline and geometry, but with a different data in the |
3725 | uniform buffers exposed at binding point 0. This assumes the buffer is |
3726 | exposed via |
3727 | \l{QRhiShaderResourceBinding::uniformBufferWithDynamicOffset()}{uniformBufferWithDynamicOffset()} |
3728 | which allows passing a QRhiCommandBuffer::DynamicOffset list to |
3729 | \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()}. |
3730 | |
3731 | \code |
3732 | const int N = 2; |
3733 | const int UB_SIZE = 64 + 4; // assuming a uniform block with { mat4 matrix; float opacity; } |
3734 | const int ONE_UBUF_SIZE = rhi->ubufAligned(UB_SIZE); |
3735 | const int TOTAL_UBUF_SIZE = N * ONE_UBUF_SIZE; |
3736 | QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, TOTAL_UBUF_SIZE); |
3737 | if (!ubuf->create()) { error(); } |
3738 | QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); |
3739 | for (int i = 0; i < N; ++i) { |
3740 | batch->updateDynamicBuffer(ubuf, i * ONE_UBUF_SIZE, 64, matrix.constData()); |
3741 | batch->updateDynamicBuffer(ubuf, i * ONE_UBUF_SIZE + 64, 4, &opacity); |
3742 | } |
3743 | // ... |
3744 | // beginPass(), set pipeline, etc., and then: |
3745 | for (int i = 0; i < N; ++i) { |
3746 | QRhiCommandBuffer::DynamicOffset dynOfs[] = { { 0, i * ONE_UBUF_SIZE } }; |
3747 | cb->setShaderResources(srb, 1, dynOfs); |
3748 | cb->draw(36); |
3749 | } |
3750 | \endcode |
3751 | |
3752 | \sa QRhiResourceUpdateBatch, QRhi, QRhiCommandBuffer |
3753 | */ |
3754 | |
3755 | /*! |
3756 | \enum QRhiBuffer::Type |
3757 | Specifies storage type of buffer resource. |
3758 | |
3759 | \value Immutable Indicates that the data is not expected to change ever |
3760 | after the initial upload. Under the hood such buffer resources are |
3761 | typically placed in device local (GPU) memory (on systems where |
3762 | applicable). Uploading new data is possible, but may be expensive. The |
3763 | upload typically happens by copying to a separate, host visible staging |
3764 | buffer from which a GPU buffer-to-buffer copy is issued into the actual |
3765 | GPU-only buffer. |
3766 | |
3767 | \value Static Indicates that the data is expected to change only |
3768 | infrequently. Typically placed in device local (GPU) memory, where |
3769 | applicable. On backends where host visible staging buffers are used for |
3770 | uploading, the staging buffers are kept around for this type, unlike with |
3771 | Immutable, so subsequent uploads do not suffer in performance. Frequent |
3772 | updates, especially updates in consecutive frames, should be avoided. |
3773 | |
3774 | \value Dynamic Indicates that the data is expected to change frequently. |
3775 | Not recommended for large buffers. Typically backed by host visible memory |
3776 | in 2 copies in order to allow for changing without stalling the graphics |
3777 | pipeline. The double buffering is managed transparently to the applications |
3778 | and is not exposed in the API here in any form. This is the recommended, |
3779 | and, with some backends, the only possible, type for buffers with |
3780 | UniformBuffer usage. |
3781 | */ |
3782 | |
3783 | /*! |
3784 | \enum QRhiBuffer::UsageFlag |
3785 | Flag values to specify how the buffer is going to be used. |
3786 | |
3787 | \value VertexBuffer Vertex buffer. This allows the QRhiBuffer to be used in |
3788 | \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()}. |
3789 | |
3790 | \value IndexBuffer Index buffer. This allows the QRhiBuffer to be used in |
3791 | \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()}. |
3792 | |
3793 | \value UniformBuffer Uniform buffer (also called constant buffer). This |
3794 | allows the QRhiBuffer to be used in combination with |
3795 | \l{QRhiShaderResourceBinding::UniformBuffer}{UniformBuffer}. When |
3796 | \l{QRhi::NonDynamicUniformBuffers}{NonDynamicUniformBuffers} is reported as |
3797 | not supported, this usage can only be combined with the type Dynamic. |
3798 | |
3799 | \value StorageBuffer Storage buffer. This allows the QRhiBuffer to be used |
3800 | in combination with \l{QRhiShaderResourceBinding::BufferLoad}{BufferLoad}, |
3801 | \l{QRhiShaderResourceBinding::BufferStore}{BufferStore}, or |
3802 | \l{QRhiShaderResourceBinding::BufferLoadStore}{BufferLoadStore}. This usage |
3803 | can only be combined with the types Immutable or Static, and is only |
3804 | available when the \l{QRhi::Compute}{Compute feature} is reported as |
3805 | supported. |
3806 | */ |
3807 | |
3808 | /*! |
3809 | \class QRhiBuffer::NativeBuffer |
3810 | \inmodule QtGuiPrivate |
3811 | \inheaderfile rhi/qrhi.h |
3812 | \brief Contains information about the underlying native resources of a buffer. |
3813 | */ |
3814 | |
3815 | /*! |
3816 | \variable QRhiBuffer::NativeBuffer::objects |
3817 | \brief an array with pointers to the native object handles. |
3818 | |
3819 | With OpenGL, the native handle is a GLuint value, so the elements in the \c |
3820 | objects array are pointers to a GLuint. With Vulkan, the native handle is a |
3821 | VkBuffer, so the elements of the array are pointers to a VkBuffer. With |
3822 | Direct3D 11 and Metal the elements are pointers to a ID3D11Buffer or |
3823 | MTLBuffer pointer, respectively. With Direct3D 12, the elements are |
3824 | pointers to a ID3D12Resource. |
3825 | |
3826 | \note Pay attention to the fact that the elements are always pointers to |
3827 | the native buffer handle type, even if the native type itself is a pointer. |
3828 | (so the elements are \c{VkBuffer *} on Vulkan, even though VkBuffer itself |
3829 | is a pointer on 64-bit architectures). |
3830 | */ |
3831 | |
3832 | /*! |
3833 | \variable QRhiBuffer::NativeBuffer::slotCount |
3834 | \brief Specifies the number of valid elements in the objects array. |
3835 | |
3836 | The value can be 0, 1, 2, or 3 in practice. 0 indicates that the QRhiBuffer |
3837 | is not backed by any native buffer objects. This can happen with |
3838 | QRhiBuffers with the usage UniformBuffer when the underlying API does not |
3839 | support (or the backend chooses not to use) native uniform buffers. 1 is |
3840 | commonly used for Immutable and Static types (but some backends may |
3841 | differ). 2 or 3 is typical when the type is Dynamic (but some backends may |
3842 | differ). |
3843 | |
3844 | \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight |
3845 | */ |
3846 | |
3847 | /*! |
3848 | \internal |
3849 | */ |
3850 | QRhiBuffer::QRhiBuffer(QRhiImplementation *rhi, Type type_, UsageFlags usage_, quint32 size_) |
3851 | : QRhiResource(rhi), |
3852 | m_type(type_), m_usage(usage_), m_size(size_) |
3853 | { |
3854 | } |
3855 | |
3856 | /*! |
3857 | \return the resource type. |
3858 | */ |
3859 | QRhiResource::Type QRhiBuffer::resourceType() const |
3860 | { |
3861 | return Buffer; |
3862 | } |
3863 | |
3864 | /*! |
3865 | \fn virtual bool QRhiBuffer::create() = 0 |
3866 | |
3867 | Creates the corresponding native graphics resources. If there are already |
3868 | resources present due to an earlier create() with no corresponding |
3869 | destroy(), then destroy() is called implicitly first. |
3870 | |
3871 | \return \c true when successful, \c false when a graphics operation failed. |
3872 | Regardless of the return value, calling destroy() is always safe. |
3873 | */ |
3874 | |
3875 | /*! |
3876 | \fn QRhiBuffer::Type QRhiBuffer::type() const |
3877 | \return the buffer type. |
3878 | */ |
3879 | |
3880 | /*! |
3881 | \fn void QRhiBuffer::setType(Type t) |
3882 | Sets the buffer's type to \a t. |
3883 | */ |
3884 | |
3885 | /*! |
3886 | \fn QRhiBuffer::UsageFlags QRhiBuffer::usage() const |
3887 | \return the buffer's usage flags. |
3888 | */ |
3889 | |
3890 | /*! |
3891 | \fn void QRhiBuffer::setUsage(UsageFlags u) |
3892 | Sets the buffer's usage flags to \a u. |
3893 | */ |
3894 | |
3895 | /*! |
3896 | \fn quint32 QRhiBuffer::size() const |
3897 | |
3898 | \return the buffer's size in bytes. |
3899 | |
3900 | This is always the value that was passed to setSize() or QRhi::newBuffer(). |
3901 | Internally, the native buffers may be bigger if that is required by the |
3902 | underlying graphics API. |
3903 | */ |
3904 | |
3905 | /*! |
3906 | \fn void QRhiBuffer::setSize(quint32 sz) |
3907 | |
3908 | Sets the size of the buffer in bytes. The size is normally specified in |
3909 | QRhi::newBuffer() so this function is only used when the size has to be |
3910 | changed. As with other setters, the size only takes effect when calling |
3911 | create(), and for already created buffers this involves releasing the previous |
3912 | native resource and creating new ones under the hood. |
3913 | |
3914 | Backends may choose to allocate buffers bigger than \a sz in order to |
3915 | fulfill alignment requirements. This is hidden from the applications and |
3916 | size() will always report the size requested in \a sz. |
3917 | */ |
3918 | |
3919 | /*! |
3920 | \return the underlying native resources for this buffer. The returned value |
3921 | will be empty if exposing the underlying native resources is not supported by |
3922 | the backend. |
3923 | |
3924 | A QRhiBuffer may be backed by multiple native buffer objects, depending on |
3925 | the type() and the QRhi backend in use. When this is the case, all of them |
3926 | are returned in the objects array in the returned struct, with slotCount |
3927 | specifying the number of native buffer objects. While |
3928 | \l{QRhi::beginFrame()}{recording a frame}, QRhi::currentFrameSlot() can be |
3929 | used to determine which of the native buffers QRhi is using for operations |
3930 | that read or write from this QRhiBuffer within the frame being recorded. |
3931 | |
3932 | In some cases a QRhiBuffer will not be backed by a native buffer object at |
3933 | all. In this case slotCount will be set to 0 and no valid native objects |
3934 | are returned. This is not an error, and is perfectly valid when a given |
3935 | backend does not use native buffers for QRhiBuffers with certain types or |
3936 | usages. |
3937 | |
3938 | \note Be aware that QRhi backends may employ various buffer update |
3939 | strategies. Unlike textures, where uploading image data always means |
3940 | recording a buffer-to-image (or similar) copy command on the command |
3941 | buffer, buffers, in particular Dynamic and UniformBuffer ones, can operate |
3942 | in many different ways. For example, a QRhiBuffer with usage type |
3943 | UniformBuffer may not even be backed by a native buffer object at all if |
3944 | uniform buffers are not used or supported by a given backend and graphics |
3945 | API. There are also differences to how data is written to the buffer and |
3946 | the type of backing memory used. For buffers backed by host visible memory, |
3947 | calling this function guarantees that pending host writes are executed for |
3948 | all the returned native buffers. |
3949 | |
3950 | \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight |
3951 | */ |
3952 | QRhiBuffer::NativeBuffer QRhiBuffer::nativeBuffer() |
3953 | { |
3954 | return { .objects: {}, .slotCount: 0 }; |
3955 | } |
3956 | |
3957 | /*! |
3958 | \return a pointer to a memory block with the host visible buffer data. |
3959 | |
3960 | This is a shortcut for medium-to-large dynamic uniform buffers that have |
3961 | their \b entire contents (or at least all regions that are read by the |
3962 | shaders in the current frame) changed \b{in every frame} and the |
3963 | QRhiResourceUpdateBatch-based update mechanism is seen too heavy due to the |
3964 | amount of data copying involved. |
3965 | |
3966 | The call to this function must be eventually followed by a call to |
3967 | endFullDynamicUniformBufferUpdateForCurrentFrame(), before recording any |
3968 | render or compute pass that relies on this buffer. |
3969 | |
3970 | \warning Updating data via this method is not compatible with |
3971 | QRhiResourceUpdateBatch-based updates and readbacks. Unexpected behavior |
3972 | may occur when attempting to combine the two update models for the same |
3973 | buffer. Similarly, the data updated this direct way may not be visible to |
3974 | \l{QRhiResourceUpdateBatch::readBackBuffer()}{readBackBuffer operations}, |
3975 | depending on the backend. |
3976 | |
3977 | \warning When updating buffer data via this method, the update must be done |
3978 | in every frame, otherwise backends that perform double or triple buffering |
3979 | of resources may end up in unexpected behavior. |
3980 | |
3981 | \warning Partial updates are not possible with this approach since some |
3982 | backends may choose a strategy where the previous contents of the buffer is |
3983 | lost upon calling this function. Data must be written to all regions that |
3984 | are read by shaders in the frame currently being prepared. |
3985 | |
3986 | \warning This function can only be called when recording a frame, so |
3987 | between QRhi::beginFrame() and QRhi::endFrame(). |
3988 | |
3989 | \warning This function can only be called on Dynamic buffers. |
3990 | */ |
3991 | char *QRhiBuffer::beginFullDynamicBufferUpdateForCurrentFrame() |
3992 | { |
3993 | return nullptr; |
3994 | } |
3995 | |
3996 | /*! |
3997 | To be called when the entire contents of the buffer data has been updated |
3998 | in the memory block returned from |
3999 | beginFullDynamicBufferUpdateForCurrentFrame(). |
4000 | */ |
4001 | void QRhiBuffer::endFullDynamicBufferUpdateForCurrentFrame() |
4002 | { |
4003 | } |
4004 | |
4005 | /*! |
4006 | \internal |
4007 | */ |
4008 | void QRhiBuffer::fullDynamicBufferUpdateForCurrentFrame(const void *data, quint32 size) |
4009 | { |
4010 | char *p = beginFullDynamicBufferUpdateForCurrentFrame(); |
4011 | if (p) { |
4012 | memcpy(dest: p, src: data, n: size > 0 ? size : m_size); |
4013 | endFullDynamicBufferUpdateForCurrentFrame(); |
4014 | } |
4015 | } |
4016 | |
4017 | /*! |
4018 | \class QRhiRenderBuffer |
4019 | \inmodule QtGuiPrivate |
4020 | \inheaderfile rhi/qrhi.h |
4021 | \since 6.6 |
4022 | \brief Renderbuffer resource. |
4023 | |
4024 | Renderbuffers cannot be sampled or read but have some benefits over |
4025 | textures in some cases: |
4026 | |
4027 | A \l DepthStencil renderbuffer may be lazily allocated and be backed by |
4028 | transient memory with some APIs. On some platforms this may mean the |
4029 | depth/stencil buffer uses no physical backing at all. |
4030 | |
4031 | \l Color renderbuffers are useful since QRhi::MultisampleRenderBuffer may be |
4032 | supported even when QRhi::MultisampleTexture is not. |
4033 | |
4034 | How the renderbuffer is implemented by a backend is not exposed to the |
4035 | applications. In some cases it may be backed by ordinary textures, while in |
4036 | others there may be a different kind of native resource used. |
4037 | |
4038 | Renderbuffers that are used as (and are only used as) depth-stencil buffers |
4039 | in combination with a QRhiSwapChain's color buffers should have the |
4040 | UsedWithSwapChainOnly flag set. This serves a double purpose: such buffers, |
4041 | depending on the backend and the underlying APIs, be more efficient, and |
4042 | QRhi provides automatic sizing behavior to match the color buffers, which |
4043 | means calling setPixelSize() and create() are not necessary for such |
4044 | renderbuffers. |
4045 | |
4046 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
4047 | for details. |
4048 | */ |
4049 | |
4050 | /*! |
4051 | \enum QRhiRenderBuffer::Type |
4052 | Specifies the type of the renderbuffer |
4053 | |
4054 | \value DepthStencil Combined depth/stencil |
4055 | \value Color Color |
4056 | */ |
4057 | |
4058 | /*! |
4059 | \struct QRhiRenderBuffer::NativeRenderBuffer |
4060 | \inmodule QtGuiPrivate |
4061 | \inheaderfile rhi/qrhi.h |
4062 | \brief Wraps a native renderbuffer object. |
4063 | */ |
4064 | |
4065 | /*! |
4066 | \variable QRhiRenderBuffer::NativeRenderBuffer::object |
4067 | \brief 64-bit integer containing the native object handle. |
4068 | |
4069 | Used with QRhiRenderBuffer::createFrom(). |
4070 | |
4071 | With OpenGL the native handle is a GLuint value. \c object is expected to |
4072 | be a valid OpenGL renderbuffer object ID. |
4073 | */ |
4074 | |
4075 | /*! |
4076 | \enum QRhiRenderBuffer::Flag |
4077 | Flag values for flags() and setFlags() |
4078 | |
4079 | \value UsedWithSwapChainOnly For DepthStencil renderbuffers this indicates |
4080 | that the renderbuffer is only used in combination with a QRhiSwapChain, and |
4081 | never in any other way. This provides automatic sizing and resource |
4082 | rebuilding, so calling setPixelSize() or create() is not needed whenever |
4083 | this flag is set. This flag value may also trigger backend-specific |
4084 | behavior, for example with OpenGL, where a separate windowing system |
4085 | interface API is in use (EGL, GLX, etc.), the flag is especially important |
4086 | as it avoids creating any actual renderbuffer resource as there is already |
4087 | a windowing system provided depth/stencil buffer as requested by |
4088 | QSurfaceFormat. |
4089 | */ |
4090 | |
4091 | /*! |
4092 | \internal |
4093 | */ |
4094 | QRhiRenderBuffer::QRhiRenderBuffer(QRhiImplementation *rhi, Type type_, const QSize &pixelSize_, |
4095 | int sampleCount_, Flags flags_, |
4096 | QRhiTexture::Format backingFormatHint_) |
4097 | : QRhiResource(rhi), |
4098 | m_type(type_), m_pixelSize(pixelSize_), m_sampleCount(sampleCount_), m_flags(flags_), |
4099 | m_backingFormatHint(backingFormatHint_) |
4100 | { |
4101 | } |
4102 | |
4103 | /*! |
4104 | \return the resource type. |
4105 | */ |
4106 | QRhiResource::Type QRhiRenderBuffer::resourceType() const |
4107 | { |
4108 | return RenderBuffer; |
4109 | } |
4110 | |
4111 | /*! |
4112 | \fn virtual bool QRhiRenderBuffer::create() = 0 |
4113 | |
4114 | Creates the corresponding native graphics resources. If there are already |
4115 | resources present due to an earlier create() with no corresponding |
4116 | destroy(), then destroy() is called implicitly first. |
4117 | |
4118 | \return \c true when successful, \c false when a graphics operation failed. |
4119 | Regardless of the return value, calling destroy() is always safe. |
4120 | */ |
4121 | |
4122 | /*! |
4123 | Similar to create() except that no new native renderbuffer objects are |
4124 | created. Instead, the native renderbuffer object specified by \a src is |
4125 | used. |
4126 | |
4127 | This allows importing an existing renderbuffer object (which must belong to |
4128 | the same device or sharing context, depending on the graphics API) from an |
4129 | external graphics engine. |
4130 | |
4131 | \note This is currently applicable to OpenGL only. This function exists |
4132 | solely to allow importing a renderbuffer object that is bound to some |
4133 | special, external object, such as an EGLImageKHR. Once the application |
4134 | performed the glEGLImageTargetRenderbufferStorageOES call, the renderbuffer |
4135 | object can be passed to this function to create a wrapping |
4136 | QRhiRenderBuffer, which in turn can be passed in as a color attachment to |
4137 | a QRhiTextureRenderTarget to enable rendering to the EGLImage. |
4138 | |
4139 | \note pixelSize(), sampleCount(), and flags() must still be set correctly. |
4140 | Passing incorrect sizes and other values to QRhi::newRenderBuffer() and |
4141 | then following it with a createFrom() expecting that the native |
4142 | renderbuffer object alone is sufficient to deduce such values is \b wrong |
4143 | and will lead to problems. |
4144 | |
4145 | \note QRhiRenderBuffer does not take ownership of the native object, and |
4146 | destroy() will not release that object. |
4147 | |
4148 | \note This function is only implemented when the QRhi::RenderBufferImport |
4149 | feature is reported as \l{QRhi::isFeatureSupported()}{supported}. Otherwise, |
4150 | the function does nothing and the return value is \c false. |
4151 | |
4152 | \return \c true when successful, \c false when not supported. |
4153 | */ |
4154 | bool QRhiRenderBuffer::createFrom(NativeRenderBuffer src) |
4155 | { |
4156 | Q_UNUSED(src); |
4157 | return false; |
4158 | } |
4159 | |
4160 | /*! |
4161 | \fn QRhiRenderBuffer::Type QRhiRenderBuffer::type() const |
4162 | \return the renderbuffer type. |
4163 | */ |
4164 | |
4165 | /*! |
4166 | \fn void QRhiRenderBuffer::setType(Type t) |
4167 | Sets the type to \a t. |
4168 | */ |
4169 | |
4170 | /*! |
4171 | \fn QSize QRhiRenderBuffer::pixelSize() const |
4172 | \return the pixel size. |
4173 | */ |
4174 | |
4175 | /*! |
4176 | \fn void QRhiRenderBuffer::setPixelSize(const QSize &sz) |
4177 | Sets the size (in pixels) to \a sz. |
4178 | */ |
4179 | |
4180 | /*! |
4181 | \fn int QRhiRenderBuffer::sampleCount() const |
4182 | \return the sample count. 1 means no multisample antialiasing. |
4183 | */ |
4184 | |
4185 | /*! |
4186 | \fn void QRhiRenderBuffer::setSampleCount(int s) |
4187 | Sets the sample count to \a s. |
4188 | */ |
4189 | |
4190 | /*! |
4191 | \fn QRhiRenderBuffer::Flags QRhiRenderBuffer::flags() const |
4192 | \return the flags. |
4193 | */ |
4194 | |
4195 | /*! |
4196 | \fn void QRhiRenderBuffer::setFlags(Flags f) |
4197 | Sets the flags to \a f. |
4198 | */ |
4199 | |
4200 | /*! |
4201 | \fn virtual QRhiTexture::Format QRhiRenderBuffer::backingFormat() const = 0 |
4202 | |
4203 | \internal |
4204 | */ |
4205 | |
4206 | /*! |
4207 | \class QRhiTexture |
4208 | \inmodule QtGuiPrivate |
4209 | \inheaderfile rhi/qrhi.h |
4210 | \since 6.6 |
4211 | \brief Texture resource. |
4212 | |
4213 | A QRhiTexture encapsulates a native texture object, such as a \c VkImage or |
4214 | \c MTLTexture. |
4215 | |
4216 | A QRhiTexture instance is always created by calling |
4217 | \l{QRhi::newTexture()}{the QRhi's newTexture() function}. This creates no |
4218 | native graphics resources. To do that, call create() after setting the |
4219 | appropriate options, such as the format and size, although in most cases |
4220 | these are already set based on the arguments passed to |
4221 | \l{QRhi::newTexture()}{newTexture()}. |
4222 | |
4223 | Setting the \l{QRhiTexture::Flags}{flags} correctly is essential, otherwise |
4224 | various errors can occur depending on the underlying QRhi backend and |
4225 | graphics API. For example, when a texture will be rendered into from a |
4226 | render pass via QRhiTextureRenderTarget, the texture must be created with |
4227 | the \l RenderTarget flag set. Similarly, when the texture is going to be |
4228 | \l{QRhiResourceUpdateBatch::readBackTexture()}{read back}, the \l |
4229 | UsedAsTransferSource flag must be set upfront. Mipmapped textures must have |
4230 | the MipMapped flag set. And so on. It is not possible to change the flags |
4231 | once create() has succeeded. To release the existing and create a new |
4232 | native texture object with the changed settings, call the setters and call |
4233 | create() again. This then might be a potentially expensive operation. |
4234 | |
4235 | \section2 Example usage |
4236 | |
4237 | To create a 2D texture with a size of 512x512 pixels and set its contents to all green: |
4238 | |
4239 | \code |
4240 | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512)); |
4241 | if (!texture->create()) { error(); } |
4242 | QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); |
4243 | QImage image(512, 512, QImage::Format_RGBA8888); |
4244 | image.fill(Qt::green); |
4245 | batch->uploadTexture(texture, image); |
4246 | // ... |
4247 | commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call |
4248 | \endcode |
4249 | |
4250 | \section2 Common patterns |
4251 | |
4252 | A call to create() destroys any existing native resources if create() was |
4253 | successfully called before. If those native resources are still in use by |
4254 | an in-flight frame (i.e., there's a chance they are still read by the GPU), |
4255 | the destroying of those resources is deferred automatically. Thus a very |
4256 | common and convenient pattern to safely change the size of an already |
4257 | existing texture is the following. In practice this drops and creates a |
4258 | whole new native texture resource underneath, so it is not necessarily a |
4259 | cheap operation, but is more convenient and still faster than the |
4260 | alternatives, because by not destroying the \c texture object itself, all |
4261 | references to it stay valid in other data structures (e.g., in any |
4262 | QShaderResourceBinding the QRhiTexture is referenced from). |
4263 | |
4264 | \code |
4265 | // determine newSize, e.g. based on the swapchain's output size or other factors |
4266 | if (texture->pixelSize() != newSize) { |
4267 | texture->setPixelSize(newSize); |
4268 | if (!texture->create()) { error(); } |
4269 | } |
4270 | // continue using texture, fill it with new data |
4271 | \endcode |
4272 | |
4273 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
4274 | for details. |
4275 | |
4276 | \sa QRhiResourceUpdateBatch, QRhi, QRhiTextureRenderTarget |
4277 | */ |
4278 | |
4279 | /*! |
4280 | \enum QRhiTexture::Flag |
4281 | |
4282 | Flag values to specify how the texture is going to be used. Not honoring |
4283 | the flags set before create() and attempting to use the texture in ways that |
4284 | was not declared upfront can lead to unspecified behavior or decreased |
4285 | performance depending on the backend and the underlying graphics API. |
4286 | |
4287 | \value RenderTarget The texture going to be used in combination with |
4288 | QRhiTextureRenderTarget. |
4289 | |
4290 | \value CubeMap The texture is a cubemap. Such textures have 6 layers, one |
4291 | for each face in the order of +X, -X, +Y, -Y, +Z, -Z. Cubemap textures |
4292 | cannot be multisample. |
4293 | |
4294 | \value MipMapped The texture has mipmaps. The appropriate mip count is |
4295 | calculated automatically and can also be retrieved via |
4296 | QRhi::mipLevelsForSize(). The images for the mip levels have to be |
4297 | provided in the texture uploaded or generated via |
4298 | QRhiResourceUpdateBatch::generateMips(). Multisample textures cannot have |
4299 | mipmaps. |
4300 | |
4301 | \value sRGB Use an sRGB format. |
4302 | |
4303 | \value UsedAsTransferSource The texture is used as the source of a texture |
4304 | copy or readback, meaning the texture is given as the source in |
4305 | QRhiResourceUpdateBatch::copyTexture() or |
4306 | QRhiResourceUpdateBatch::readBackTexture(). |
4307 | |
4308 | \value UsedWithGenerateMips The texture is going to be used with |
4309 | QRhiResourceUpdateBatch::generateMips(). |
4310 | |
4311 | \value UsedWithLoadStore The texture is going to be used with image |
4312 | load/store operations, for example, in a compute shader. |
4313 | |
4314 | \value UsedAsCompressedAtlas The texture has a compressed format and the |
4315 | dimensions of subresource uploads may not match the texture size. |
4316 | |
4317 | \value ExternalOES The texture should use the GL_TEXTURE_EXTERNAL_OES |
4318 | target with OpenGL. This flag is ignored with other graphics APIs. |
4319 | |
4320 | \value ThreeDimensional The texture is a 3D texture. Such textures should |
4321 | be created with the QRhi::newTexture() overload taking a depth in addition |
4322 | to width and height. A 3D texture can have mipmaps but cannot be |
4323 | multisample. When rendering into, or uploading data to a 3D texture, the \c |
4324 | layer specified in the render target's color attachment or the upload |
4325 | description refers to a single slice in range [0..depth-1]. The underlying |
4326 | graphics API may not support 3D textures at run time. Support is indicated |
4327 | by the QRhi::ThreeDimensionalTextures feature. |
4328 | |
4329 | \value TextureRectangleGL The texture should use the GL_TEXTURE_RECTANGLE |
4330 | target with OpenGL. This flag is ignored with other graphics APIs. Just |
4331 | like ExternalOES, this flag is useful when working with platform APIs where |
4332 | native OpenGL texture objects received from the platform are wrapped in a |
4333 | QRhiTexture, and the platform can only provide textures for a non-2D |
4334 | texture target. |
4335 | |
4336 | \value TextureArray The texture is a texture array, i.e. a single texture |
4337 | object that is a homogeneous array of 2D textures. Texture arrays are |
4338 | created with QRhi::newTextureArray(). The underlying graphics API may not |
4339 | support texture array objects at run time. Support is indicated by the |
4340 | QRhi::TextureArrays feature. When rendering into, or uploading data to a |
4341 | texture array, the \c layer specified in the render target's color |
4342 | attachment or the upload description selects a single element in the array. |
4343 | |
4344 | \value OneDimensional The texture is a 1D texture. Such textures can be |
4345 | created by passing a 0 height and depth to QRhi::newTexture(). Note that |
4346 | there can be limitations on one dimensional textures depending on the |
4347 | underlying graphics API. For example, rendering to them or using them with |
4348 | mipmap-based filtering may be unsupported. This is indicated by the |
4349 | QRhi::OneDimensionalTextures and QRhi::OneDimensionalTextureMipmaps |
4350 | feature flags. |
4351 | */ |
4352 | |
4353 | /*! |
4354 | \enum QRhiTexture::Format |
4355 | |
4356 | Specifies the texture format. See also QRhi::isTextureFormatSupported() and |
4357 | note that flags() can modify the format when QRhiTexture::sRGB is set. |
4358 | |
4359 | \value UnknownFormat Not a valid format. This cannot be passed to setFormat(). |
4360 | |
4361 | \value RGBA8 Four component, unsigned normalized 8 bit per component. Always supported. |
4362 | |
4363 | \value BGRA8 Four component, unsigned normalized 8 bit per component. |
4364 | |
4365 | \value R8 One component, unsigned normalized 8 bit. |
4366 | |
4367 | \value RG8 Two components, unsigned normalized 8 bit. |
4368 | |
4369 | \value R16 One component, unsigned normalized 16 bit. |
4370 | |
4371 | \value RG16 Two component, unsigned normalized 16 bit. |
4372 | |
4373 | \value RED_OR_ALPHA8 Either same as R8, or is a similar format with the component swizzled to alpha, |
4374 | depending on \l{QRhi::RedOrAlpha8IsRed}{RedOrAlpha8IsRed}. |
4375 | |
4376 | \value RGBA16F Four components, 16-bit float per component. |
4377 | |
4378 | \value RGBA32F Four components, 32-bit float per component. |
4379 | |
4380 | \value R16F One component, 16-bit float. |
4381 | |
4382 | \value R32F One component, 32-bit float. |
4383 | |
4384 | \value RGB10A2 Four components, unsigned normalized 10 bit R, G, and B, |
4385 | 2-bit alpha. This is a packed format so native endianness applies. Note |
4386 | that there is no BGR10A2. This is because RGB10A2 maps to |
4387 | DXGI_FORMAT_R10G10B10A2_UNORM with D3D, MTLPixelFormatRGB10A2Unorm with |
4388 | Metal, VK_FORMAT_A2B10G10R10_UNORM_PACK32 with Vulkan, and |
4389 | GL_RGB10_A2/GL_RGB/GL_UNSIGNED_INT_2_10_10_10_REV on OpenGL (ES). This is |
4390 | the only universally supported RGB30 option. The corresponding QImage |
4391 | formats are QImage::Format_BGR30 and QImage::Format_A2BGR30_Premultiplied. |
4392 | |
4393 | \value D16 16-bit depth (normalized unsigned integer) |
4394 | |
4395 | \value D24 24-bit depth (normalized unsigned integer) |
4396 | |
4397 | \value D24S8 24-bit depth (normalized unsigned integer), 8 bit stencil |
4398 | |
4399 | \value D32F 32-bit depth (32-bit float) |
4400 | |
4401 | \value BC1 |
4402 | \value BC2 |
4403 | \value BC3 |
4404 | \value BC4 |
4405 | \value BC5 |
4406 | \value BC6H |
4407 | \value BC7 |
4408 | |
4409 | \value ETC2_RGB8 |
4410 | \value ETC2_RGB8A1 |
4411 | \value ETC2_RGBA8 |
4412 | |
4413 | \value ASTC_4x4 |
4414 | \value ASTC_5x4 |
4415 | \value ASTC_5x5 |
4416 | \value ASTC_6x5 |
4417 | \value ASTC_6x6 |
4418 | \value ASTC_8x5 |
4419 | \value ASTC_8x6 |
4420 | \value ASTC_8x8 |
4421 | \value ASTC_10x5 |
4422 | \value ASTC_10x6 |
4423 | \value ASTC_10x8 |
4424 | \value ASTC_10x10 |
4425 | \value ASTC_12x10 |
4426 | \value ASTC_12x12 |
4427 | */ |
4428 | |
4429 | /*! |
4430 | \struct QRhiTexture::NativeTexture |
4431 | \inmodule QtGuiPrivate |
4432 | \inheaderfile rhi/qrhi.h |
4433 | \brief Contains information about the underlying native resources of a texture. |
4434 | */ |
4435 | |
4436 | /*! |
4437 | \variable QRhiTexture::NativeTexture::object |
4438 | \brief 64-bit integer containing the native object handle. |
4439 | |
4440 | With OpenGL, the native handle is a GLuint value, so \c object can then be |
4441 | cast to a GLuint. With Vulkan, the native handle is a VkImage, so \c object |
4442 | can be cast to a VkImage. With Direct3D 11 and Metal \c object contains a |
4443 | ID3D11Texture2D or MTLTexture pointer, respectively. With Direct3D 12 |
4444 | \c object contains a ID3D12Resource pointer. |
4445 | */ |
4446 | |
4447 | /*! |
4448 | \variable QRhiTexture::NativeTexture::layout |
4449 | \brief Specifies the current image layout for APIs like Vulkan. |
4450 | |
4451 | For Vulkan, \c layout contains a \c VkImageLayout value. |
4452 | */ |
4453 | |
4454 | /*! |
4455 | \internal |
4456 | */ |
4457 | QRhiTexture::QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_, int depth_, |
4458 | int arraySize_, int sampleCount_, Flags flags_) |
4459 | : QRhiResource(rhi), |
4460 | m_format(format_), m_pixelSize(pixelSize_), m_depth(depth_), |
4461 | m_arraySize(arraySize_), m_sampleCount(sampleCount_), m_flags(flags_) |
4462 | { |
4463 | } |
4464 | |
4465 | /*! |
4466 | \return the resource type. |
4467 | */ |
4468 | QRhiResource::Type QRhiTexture::resourceType() const |
4469 | { |
4470 | return Texture; |
4471 | } |
4472 | |
4473 | /*! |
4474 | \fn virtual bool QRhiTexture::create() = 0 |
4475 | |
4476 | Creates the corresponding native graphics resources. If there are already |
4477 | resources present due to an earlier create() with no corresponding |
4478 | destroy(), then destroy() is called implicitly first. |
4479 | |
4480 | \return \c true when successful, \c false when a graphics operation failed. |
4481 | Regardless of the return value, calling destroy() is always safe. |
4482 | */ |
4483 | |
4484 | /*! |
4485 | \return the underlying native resources for this texture. The returned value |
4486 | will be empty if exposing the underlying native resources is not supported by |
4487 | the backend. |
4488 | |
4489 | \sa createFrom() |
4490 | */ |
4491 | QRhiTexture::NativeTexture QRhiTexture::nativeTexture() |
4492 | { |
4493 | return {}; |
4494 | } |
4495 | |
4496 | /*! |
4497 | Similar to create(), except that no new native textures are created. |
4498 | Instead, the native texture resources specified by \a src is used. |
4499 | |
4500 | This allows importing an existing native texture object (which must belong |
4501 | to the same device or sharing context, depending on the graphics API) from |
4502 | an external graphics engine. |
4503 | |
4504 | \return true if the specified existing native texture object has been |
4505 | successfully wrapped as a non-owning QRhiTexture. |
4506 | |
4507 | \note format(), pixelSize(), sampleCount(), and flags() must still be set |
4508 | correctly. Passing incorrect sizes and other values to QRhi::newTexture() |
4509 | and then following it with a createFrom() expecting that the native texture |
4510 | object alone is sufficient to deduce such values is \b wrong and will lead |
4511 | to problems. |
4512 | |
4513 | \note QRhiTexture does not take ownership of the texture object. destroy() |
4514 | does not free the object or any associated memory. |
4515 | |
4516 | The opposite of this operation, exposing a QRhiTexture-created native |
4517 | texture object to a foreign engine, is possible via nativeTexture(). |
4518 | |
4519 | \note When importing a 3D texture, or a texture array object, or, with |
4520 | OpenGL ES, an external texture, it is then especially important to set the |
4521 | corresponding flags (ThreeDimensional, TextureArray, ExternalOES) via |
4522 | setFlags() before calling this function. |
4523 | */ |
4524 | bool QRhiTexture::createFrom(QRhiTexture::NativeTexture src) |
4525 | { |
4526 | Q_UNUSED(src); |
4527 | return false; |
4528 | } |
4529 | |
4530 | /*! |
4531 | With some graphics APIs, such as Vulkan, integrating custom rendering code |
4532 | that uses the graphics API directly needs special care when it comes to |
4533 | image layouts. This function allows communicating the expected \a layout the |
4534 | image backing the QRhiTexture is in after the native rendering commands. |
4535 | |
4536 | For example, consider rendering into a QRhiTexture's VkImage directly with |
4537 | Vulkan in a code block enclosed by QRhiCommandBuffer::beginExternal() and |
4538 | QRhiCommandBuffer::endExternal(), followed by using the image for texture |
4539 | sampling in a QRhi-based render pass. To avoid potentially incorrect image |
4540 | layout transitions, this function can be used to indicate what the image |
4541 | layout will be once the commands recorded in said code block complete. |
4542 | |
4543 | Calling this function makes sense only after |
4544 | QRhiCommandBuffer::endExternal() and before a subsequent |
4545 | QRhiCommandBuffer::beginPass(). |
4546 | |
4547 | This function has no effect with QRhi backends where the underlying |
4548 | graphics API does not expose a concept of image layouts. |
4549 | |
4550 | \note With Vulkan \a layout is a \c VkImageLayout. With Direct 3D 12 \a |
4551 | layout is a value composed of the bits from \c D3D12_RESOURCE_STATES. |
4552 | */ |
4553 | void QRhiTexture::setNativeLayout(int layout) |
4554 | { |
4555 | Q_UNUSED(layout); |
4556 | } |
4557 | |
4558 | /*! |
4559 | \fn QRhiTexture::Format QRhiTexture::format() const |
4560 | \return the texture format. |
4561 | */ |
4562 | |
4563 | /*! |
4564 | \fn void QRhiTexture::setFormat(QRhiTexture::Format fmt) |
4565 | |
4566 | Sets the requested texture format to \a fmt. |
4567 | |
4568 | \note The value set is only taken into account upon the next call to |
4569 | create(), i.e. when the underlying graphics resource are (re)created. |
4570 | Setting a new value is futile otherwise and must be avoided since it can |
4571 | lead to inconsistent state. |
4572 | */ |
4573 | |
4574 | /*! |
4575 | \fn QSize QRhiTexture::pixelSize() const |
4576 | \return the size in pixels. |
4577 | */ |
4578 | |
4579 | /*! |
4580 | \fn void QRhiTexture::setPixelSize(const QSize &sz) |
4581 | |
4582 | Sets the texture size, specified in pixels, to \a sz. |
4583 | |
4584 | \note The value set is only taken into account upon the next call to |
4585 | create(), i.e. when the underlying graphics resource are (re)created. |
4586 | Setting a new value is futile otherwise and must be avoided since it can |
4587 | lead to inconsistent state. The same applies to all other setters as well. |
4588 | */ |
4589 | |
4590 | /*! |
4591 | \fn int QRhiTexture::depth() const |
4592 | \return the depth for 3D textures. |
4593 | */ |
4594 | |
4595 | /*! |
4596 | \fn void QRhiTexture::setDepth(int depth) |
4597 | Sets the \a depth for a 3D texture. |
4598 | */ |
4599 | |
4600 | /*! |
4601 | \fn int QRhiTexture::arraySize() const |
4602 | \return the texture array size. |
4603 | */ |
4604 | |
4605 | /*! |
4606 | \fn void QRhiTexture::setArraySize(int arraySize) |
4607 | Sets the texture \a arraySize. |
4608 | */ |
4609 | |
4610 | /*! |
4611 | \fn int QRhiTexture::arrayRangeStart() const |
4612 | |
4613 | \return the first array layer when setArrayRange() was called. |
4614 | |
4615 | \sa setArrayRange() |
4616 | */ |
4617 | |
4618 | /*! |
4619 | \fn int QRhiTexture::arrayRangeLength() const |
4620 | |
4621 | \return the exposed array range size when setArrayRange() was called. |
4622 | |
4623 | \sa setArrayRange() |
4624 | */ |
4625 | |
4626 | /*! |
4627 | \fn void QRhiTexture::setArrayRange(int startIndex, int count) |
4628 | |
4629 | Normally all array layers are exposed and it is up to the shader to select |
4630 | the layer via the third coordinate passed to the \c{texture()} GLSL |
4631 | function when sampling the \c sampler2DArray. When QRhi::TextureArrayRange |
4632 | is reported as supported, calling setArrayRange() before create() or |
4633 | createFrom() requests selecting only the specified range, \a count elements |
4634 | starting from \a startIndex. The shader logic can then be written with this |
4635 | in mind. |
4636 | |
4637 | \sa QRhi::TextureArrayRange |
4638 | */ |
4639 | |
4640 | /*! |
4641 | \fn Flags QRhiTexture::flags() const |
4642 | \return the texture flags. |
4643 | */ |
4644 | |
4645 | /*! |
4646 | \fn void QRhiTexture::setFlags(Flags f) |
4647 | Sets the texture flags to \a f. |
4648 | */ |
4649 | |
4650 | /*! |
4651 | \fn int QRhiTexture::sampleCount() const |
4652 | \return the sample count. 1 means no multisample antialiasing. |
4653 | */ |
4654 | |
4655 | /*! |
4656 | \fn void QRhiTexture::setSampleCount(int s) |
4657 | Sets the sample count to \a s. |
4658 | */ |
4659 | |
4660 | /*! |
4661 | \struct QRhiTexture::ViewFormat |
4662 | \inmodule QtGuiPrivate |
4663 | \inheaderfile rhi/qrhi.h |
4664 | \since 6.8 |
4665 | \brief Specifies the view format for reading or writing from or to the texture. |
4666 | |
4667 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
4668 | for details. |
4669 | */ |
4670 | |
4671 | /*! |
4672 | \variable QRhiTexture::ViewFormat::format |
4673 | */ |
4674 | |
4675 | /*! |
4676 | \variable QRhiTexture::ViewFormat::srgb |
4677 | */ |
4678 | |
4679 | /*! |
4680 | \fn QRhiTexture::ViewFormat QRhiTexture::readViewFormat() const |
4681 | \since 6.8 |
4682 | \return the view format used when sampling the texture. When not called, the view |
4683 | format is assumed to be the same as format(). |
4684 | */ |
4685 | |
4686 | /*! |
4687 | \fn void QRhiTexture::setReadViewFormat(const ViewFormat &fmt) |
4688 | \since 6.8 |
4689 | |
4690 | Sets the shader resource view format (or the format of the view used for |
4691 | sampling the texture) to \a fmt. By default the same format (and sRGB-ness) |
4692 | is used as the texture itself, and in most cases this function does not need |
4693 | to be called. |
4694 | |
4695 | This setting is only taken into account when the \l TextureViewFormat |
4696 | feature is reported as supported. |
4697 | |
4698 | \note This functionality is provided to allow "casting" between |
4699 | non-sRGB and sRGB in order to get the shader reads perform, or not perform, |
4700 | the implicit sRGB conversions. Other types of casting may or may not be |
4701 | functional. |
4702 | */ |
4703 | |
4704 | /*! |
4705 | \fn QRhiTexture::ViewFormat QRhiTexture::writeViewFormat() const |
4706 | \since 6.8 |
4707 | \return the view format used when writing to the texture and when using it |
4708 | with image load/store. When not called, the view format is assumed to be the |
4709 | same as format(). |
4710 | */ |
4711 | |
4712 | /*! |
4713 | \fn void QRhiTexture::setWriteViewFormat(const ViewFormat &fmt) |
4714 | \since 6.8 |
4715 | |
4716 | Sets the render target view format to \a fmt. By default the same format |
4717 | (and sRGB-ness) is used as the texture itself, and in most cases this |
4718 | function does not need to be called. |
4719 | |
4720 | One common use case for providing a write view format is working with |
4721 | externally provided textures that, outside of our control, use an sRGB |
4722 | format with 3D APIs such as Vulkan or Direct 3D, but the rendering engine is |
4723 | already prepared to handle linearization and conversion to sRGB at the end |
4724 | of its shading pipeline. In this case what is wanted when rendering into |
4725 | such a texture is a render target view (e.g. VkImageView) that has the same, |
4726 | but non-sRGB format. (if e.g. from an OpenXR implementation one gets a |
4727 | VK_FORMAT_R8G8B8A8_SRGB texture, it is likely that rendering into it should |
4728 | be done using a VK_FORMAT_R8G8B8A8_UNORM view, if that is what the rendering |
4729 | engine's pipeline requires; in this example one would call this function |
4730 | with a ViewFormat that has a format of QRhiTexture::RGBA8 and \c srgb set to |
4731 | \c false). |
4732 | |
4733 | This setting is only taken into account when the \l TextureViewFormat |
4734 | feature is reported as supported. |
4735 | |
4736 | \note This functionality is provided to allow "casting" between |
4737 | non-sRGB and sRGB in order to get the shader write not perform, or perform, |
4738 | the implicit sRGB conversions. Other types of casting may or may not be |
4739 | functional. |
4740 | */ |
4741 | |
4742 | /*! |
4743 | \class QRhiSampler |
4744 | \inmodule QtGuiPrivate |
4745 | \inheaderfile rhi/qrhi.h |
4746 | \since 6.6 |
4747 | \brief Sampler resource. |
4748 | |
4749 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
4750 | for details. |
4751 | */ |
4752 | |
4753 | /*! |
4754 | \enum QRhiSampler::Filter |
4755 | Specifies the minification, magnification, or mipmap filtering |
4756 | |
4757 | \value None Applicable only for mipmapMode(), indicates no mipmaps to be used |
4758 | \value Nearest |
4759 | \value Linear |
4760 | */ |
4761 | |
4762 | /*! |
4763 | \enum QRhiSampler::AddressMode |
4764 | Specifies the addressing mode |
4765 | |
4766 | \value Repeat |
4767 | \value ClampToEdge |
4768 | \value Mirror |
4769 | */ |
4770 | |
4771 | /*! |
4772 | \enum QRhiSampler::CompareOp |
4773 | Specifies the texture comparison function. |
4774 | |
4775 | \value Never (default) |
4776 | \value Less |
4777 | \value Equal |
4778 | \value LessOrEqual |
4779 | \value Greater |
4780 | \value NotEqual |
4781 | \value GreaterOrEqual |
4782 | \value Always |
4783 | */ |
4784 | |
4785 | /*! |
4786 | \internal |
4787 | */ |
4788 | QRhiSampler::QRhiSampler(QRhiImplementation *rhi, |
4789 | Filter magFilter_, Filter minFilter_, Filter mipmapMode_, |
4790 | AddressMode u_, AddressMode v_, AddressMode w_) |
4791 | : QRhiResource(rhi), |
4792 | m_magFilter(magFilter_), m_minFilter(minFilter_), m_mipmapMode(mipmapMode_), |
4793 | m_addressU(u_), m_addressV(v_), m_addressW(w_), |
4794 | m_compareOp(QRhiSampler::Never) |
4795 | { |
4796 | } |
4797 | |
4798 | /*! |
4799 | \return the resource type. |
4800 | */ |
4801 | QRhiResource::Type QRhiSampler::resourceType() const |
4802 | { |
4803 | return Sampler; |
4804 | } |
4805 | |
4806 | /*! |
4807 | \fn QRhiSampler::Filter QRhiSampler::magFilter() const |
4808 | \return the magnification filter mode. |
4809 | */ |
4810 | |
4811 | /*! |
4812 | \fn void QRhiSampler::setMagFilter(Filter f) |
4813 | Sets the magnification filter mode to \a f. |
4814 | */ |
4815 | |
4816 | /*! |
4817 | \fn QRhiSampler::Filter QRhiSampler::minFilter() const |
4818 | \return the minification filter mode. |
4819 | */ |
4820 | |
4821 | /*! |
4822 | \fn void QRhiSampler::setMinFilter(Filter f) |
4823 | Sets the minification filter mode to \a f. |
4824 | */ |
4825 | |
4826 | /*! |
4827 | \fn QRhiSampler::Filter QRhiSampler::mipmapMode() const |
4828 | \return the mipmap filter mode. |
4829 | */ |
4830 | |
4831 | /*! |
4832 | \fn void QRhiSampler::setMipmapMode(Filter f) |
4833 | |
4834 | Sets the mipmap filter mode to \a f. |
4835 | |
4836 | Leave this set to None when the texture has no mip levels, or when the mip |
4837 | levels are not to be taken into account. |
4838 | */ |
4839 | |
4840 | /*! |
4841 | \fn QRhiSampler::AddressMode QRhiSampler::addressU() const |
4842 | \return the horizontal wrap mode. |
4843 | */ |
4844 | |
4845 | /*! |
4846 | \fn void QRhiSampler::setAddressU(AddressMode mode) |
4847 | Sets the horizontal wrap \a mode. |
4848 | */ |
4849 | |
4850 | /*! |
4851 | \fn QRhiSampler::AddressMode QRhiSampler::addressV() const |
4852 | \return the vertical wrap mode. |
4853 | */ |
4854 | |
4855 | /*! |
4856 | \fn void QRhiSampler::setAddressV(AddressMode mode) |
4857 | Sets the vertical wrap \a mode. |
4858 | */ |
4859 | |
4860 | /*! |
4861 | \fn QRhiSampler::AddressMode QRhiSampler::addressW() const |
4862 | \return the depth wrap mode. |
4863 | */ |
4864 | |
4865 | /*! |
4866 | \fn void QRhiSampler::setAddressW(AddressMode mode) |
4867 | Sets the depth wrap \a mode. |
4868 | */ |
4869 | |
4870 | /*! |
4871 | \fn QRhiSampler::CompareOp QRhiSampler::textureCompareOp() const |
4872 | \return the texture comparison function. |
4873 | */ |
4874 | |
4875 | /*! |
4876 | \fn void QRhiSampler::setTextureCompareOp(CompareOp op) |
4877 | Sets the texture comparison function \a op. |
4878 | */ |
4879 | |
4880 | /*! |
4881 | \class QRhiRenderPassDescriptor |
4882 | \inmodule QtGuiPrivate |
4883 | \inheaderfile rhi/qrhi.h |
4884 | \since 6.6 |
4885 | \brief Render pass resource. |
4886 | |
4887 | A render pass, if such a concept exists in the underlying graphics API, is |
4888 | a collection of attachments (color, depth, stencil) and describes how those |
4889 | attachments are used. |
4890 | |
4891 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
4892 | for details. |
4893 | */ |
4894 | |
4895 | /*! |
4896 | \internal |
4897 | */ |
4898 | QRhiRenderPassDescriptor::QRhiRenderPassDescriptor(QRhiImplementation *rhi) |
4899 | : QRhiResource(rhi) |
4900 | { |
4901 | } |
4902 | |
4903 | /*! |
4904 | \return the resource type. |
4905 | */ |
4906 | QRhiResource::Type QRhiRenderPassDescriptor::resourceType() const |
4907 | { |
4908 | return RenderPassDescriptor; |
4909 | } |
4910 | |
4911 | /*! |
4912 | \fn virtual bool QRhiRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const = 0 |
4913 | |
4914 | \return true if the \a other QRhiRenderPassDescriptor is compatible with |
4915 | this one, meaning \c this and \a other can be used interchangebly in |
4916 | QRhiGraphicsPipeline::setRenderPassDescriptor(). |
4917 | |
4918 | The concept of the compatibility of renderpass descriptors is similar to |
4919 | the \l{QRhiShaderResourceBindings::isLayoutCompatible}{layout |
4920 | compatibility} of QRhiShaderResourceBindings instances. They allow better |
4921 | reuse of QRhiGraphicsPipeline instances: for example, a |
4922 | QRhiGraphicsPipeline instance cache is expected to use these functions to |
4923 | look for a matching pipeline, instead of just comparing pointers, thus |
4924 | allowing a different QRhiRenderPassDescriptor and |
4925 | QRhiShaderResourceBindings to be used in combination with the pipeline, as |
4926 | long as they are compatible. |
4927 | |
4928 | The exact details of compatibility depend on the underlying graphics API. |
4929 | Two renderpass descriptors |
4930 | \l{QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor()}{created} |
4931 | from the same QRhiTextureRenderTarget are always compatible. |
4932 | |
4933 | Similarly to QRhiShaderResourceBindings, compatibility can also be tested |
4934 | without having two existing objects available. Extracting the opaque blob by |
4935 | calling serializedFormat() allows testing for compatibility by comparing the |
4936 | returned vector to another QRhiRenderPassDescriptor's |
4937 | serializedFormat(). This has benefits in certain situations, because it |
4938 | allows testing the compatibility of a QRhiRenderPassDescriptor with a |
4939 | QRhiGraphicsPipeline even when the QRhiRenderPassDescriptor the pipeline was |
4940 | originally built was is no longer available (but the data returned from its |
4941 | serializedFormat() still is). |
4942 | |
4943 | \sa newCompatibleRenderPassDescriptor(), serializedFormat() |
4944 | */ |
4945 | |
4946 | /*! |
4947 | \fn virtual QRhiRenderPassDescriptor *QRhiRenderPassDescriptor::newCompatibleRenderPassDescriptor() const = 0 |
4948 | |
4949 | \return a new QRhiRenderPassDescriptor that is |
4950 | \l{isCompatible()}{compatible} with this one. |
4951 | |
4952 | This function allows cloning a QRhiRenderPassDescriptor. The returned |
4953 | object is ready to be used, and the ownership is transferred to the caller. |
4954 | Cloning a QRhiRenderPassDescriptor object can become useful in situations |
4955 | where the object is stored in data structures related to graphics pipelines |
4956 | (in order to allow creating new pipelines which in turn requires a |
4957 | renderpass descriptor object), and the lifetime of the renderpass |
4958 | descriptor created from a render target may be shorter than the pipelines. |
4959 | (for example, because the engine manages and destroys renderpasses together |
4960 | with the textures and render targets it was created from) In such a |
4961 | situation, it can be beneficial to store a cloned version in the data |
4962 | structures, and thus transferring ownership as well. |
4963 | |
4964 | \sa isCompatible() |
4965 | */ |
4966 | |
4967 | /*! |
4968 | \fn virtual QVector<quint32> QRhiRenderPassDescriptor::serializedFormat() const = 0 |
4969 | |
4970 | \return a vector of integers containing an opaque blob describing the data |
4971 | relevant for \l{isCompatible()}{compatibility}. |
4972 | |
4973 | Given two QRhiRenderPassDescriptor objects \c rp1 and \c rp2, if the data |
4974 | returned from this function is identical, then \c{rp1->isCompatible(rp2)}, |
4975 | and vice versa hold true as well. |
4976 | |
4977 | \note The returned data is meant to be used for storing in memory and |
4978 | comparisons during the lifetime of the QRhi the object belongs to. It is not |
4979 | meant for storing on disk, reusing between processes, or using with multiple |
4980 | QRhi instances with potentially different backends. |
4981 | |
4982 | \sa isCompatible() |
4983 | */ |
4984 | |
4985 | /*! |
4986 | \return a pointer to a backend-specific QRhiNativeHandles subclass, such as |
4987 | QRhiVulkanRenderPassNativeHandles. The returned value is \nullptr when exposing |
4988 | the underlying native resources is not supported by the backend. |
4989 | |
4990 | \sa QRhiVulkanRenderPassNativeHandles |
4991 | */ |
4992 | const QRhiNativeHandles *QRhiRenderPassDescriptor::nativeHandles() |
4993 | { |
4994 | return nullptr; |
4995 | } |
4996 | |
4997 | /*! |
4998 | \class QRhiRenderTarget |
4999 | \inmodule QtGuiPrivate |
5000 | \inheaderfile rhi/qrhi.h |
5001 | \since 6.6 |
5002 | \brief Represents an onscreen (swapchain) or offscreen (texture) render target. |
5003 | |
5004 | Applications do not create an instance of this class directly. Rather, it |
5005 | is the subclass QRhiTextureRenderTarget that is instantiable by clients of |
5006 | the API via \l{QRhi::newTextureRenderTarget()}{newTextureRenderTarget()}. |
5007 | The other subclass is QRhiSwapChainRenderTarget, which is the type |
5008 | QRhiSwapChain returns when calling |
5009 | \l{QRhiSwapChain::currentFrameRenderTarget()}{currentFrameRenderTarget()}. |
5010 | |
5011 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
5012 | for details. |
5013 | |
5014 | \sa QRhiSwapChainRenderTarget, QRhiTextureRenderTarget |
5015 | */ |
5016 | |
5017 | /*! |
5018 | \internal |
5019 | */ |
5020 | QRhiRenderTarget::QRhiRenderTarget(QRhiImplementation *rhi) |
5021 | : QRhiResource(rhi) |
5022 | { |
5023 | } |
5024 | |
5025 | /*! |
5026 | \fn virtual QSize QRhiRenderTarget::pixelSize() const = 0 |
5027 | |
5028 | \return the size in pixels. |
5029 | |
5030 | Valid only after create() has been called successfully. Until then the |
5031 | result is a default-constructed QSize. |
5032 | |
5033 | With QRhiTextureRenderTarget the returned size is the size of the |
5034 | associated attachments at the time of create(), in practice the size of the |
5035 | first color attachment, or the depth/stencil buffer if there are no color |
5036 | attachments. If the associated textures or renderbuffers are resized and |
5037 | rebuilt afterwards, then pixelSize() performs an implicit call to create() |
5038 | in order to rebuild the underlying data structures. This implicit check is |
5039 | similar to what QRhiCommandBuffer::beginPass() does, and ensures that the |
5040 | returned size is always up-to-date. |
5041 | */ |
5042 | |
5043 | /*! |
5044 | \fn virtual float QRhiRenderTarget::devicePixelRatio() const = 0 |
5045 | |
5046 | \return the device pixel ratio. For QRhiTextureRenderTarget this is always |
5047 | 1. For targets retrieved from a QRhiSwapChain the value reflects the |
5048 | \l{QWindow::devicePixelRatio()}{device pixel ratio} of the targeted |
5049 | QWindow. |
5050 | */ |
5051 | |
5052 | /*! |
5053 | \fn virtual int QRhiRenderTarget::sampleCount() const = 0 |
5054 | |
5055 | \return the sample count or 1 if multisample antialiasing is not relevant for |
5056 | this render target. |
5057 | */ |
5058 | |
5059 | /*! |
5060 | \fn QRhiRenderPassDescriptor *QRhiRenderTarget::renderPassDescriptor() const |
5061 | |
5062 | \return the associated QRhiRenderPassDescriptor. |
5063 | */ |
5064 | |
5065 | /*! |
5066 | \fn void QRhiRenderTarget::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) |
5067 | |
5068 | Sets the QRhiRenderPassDescriptor \a desc for use with this render target. |
5069 | */ |
5070 | |
5071 | /*! |
5072 | \internal |
5073 | */ |
5074 | QRhiSwapChainRenderTarget::QRhiSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain_) |
5075 | : QRhiRenderTarget(rhi), |
5076 | m_swapchain(swapchain_) |
5077 | { |
5078 | } |
5079 | |
5080 | /*! |
5081 | \class QRhiSwapChainRenderTarget |
5082 | \inmodule QtGuiPrivate |
5083 | \inheaderfile rhi/qrhi.h |
5084 | \since 6.6 |
5085 | \brief Swapchain render target resource. |
5086 | |
5087 | When targeting the color buffers of a swapchain, active render target is a |
5088 | QRhiSwapChainRenderTarget. This is what |
5089 | QRhiSwapChain::currentFrameRenderTarget() returns. |
5090 | |
5091 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
5092 | for details. |
5093 | |
5094 | \sa QRhiSwapChain |
5095 | */ |
5096 | |
5097 | /*! |
5098 | \return the resource type. |
5099 | */ |
5100 | QRhiResource::Type QRhiSwapChainRenderTarget::resourceType() const |
5101 | { |
5102 | return SwapChainRenderTarget; |
5103 | } |
5104 | |
5105 | /*! |
5106 | \fn QRhiSwapChain *QRhiSwapChainRenderTarget::swapChain() const |
5107 | |
5108 | \return the swapchain object. |
5109 | */ |
5110 | |
5111 | /*! |
5112 | \class QRhiTextureRenderTarget |
5113 | \inmodule QtGuiPrivate |
5114 | \inheaderfile rhi/qrhi.h |
5115 | \since 6.6 |
5116 | \brief Texture render target resource. |
5117 | |
5118 | A texture render target allows rendering into one or more textures, |
5119 | optionally with a depth texture or depth/stencil renderbuffer. |
5120 | |
5121 | For multisample rendering the common approach is to use a renderbuffer as |
5122 | the color attachment and set the non-multisample destination texture as the |
5123 | \c{resolve texture}. For more information, read the detailed description of |
5124 | the \l QRhiColorAttachment class. |
5125 | |
5126 | \note Textures used in combination with QRhiTextureRenderTarget must be |
5127 | created with the QRhiTexture::RenderTarget flag. |
5128 | |
5129 | The simplest example of creating a render target with a texture as its |
5130 | single color attachment: |
5131 | |
5132 | \code |
5133 | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, size, 1, QRhiTexture::RenderTarget); |
5134 | texture->create(); |
5135 | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ texture }); |
5136 | rp = rt->newCompatibleRenderPassDescriptor(); |
5137 | rt->setRenderPassDescriptor(rp); |
5138 | rt->create(); |
5139 | // rt can now be used with beginPass() |
5140 | \endcode |
5141 | |
5142 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
5143 | for details. |
5144 | */ |
5145 | |
5146 | /*! |
5147 | \enum QRhiTextureRenderTarget::Flag |
5148 | |
5149 | Flag values describing the load/store behavior for the render target. The |
5150 | load/store behavior may be baked into native resources under the hood, |
5151 | depending on the backend, and therefore it needs to be known upfront and |
5152 | cannot be changed without rebuilding (and so releasing and creating new |
5153 | native resources). |
5154 | |
5155 | \value PreserveColorContents Indicates that the contents of the color |
5156 | attachments is to be loaded when starting a render pass, instead of |
5157 | clearing. This is potentially more expensive, especially on mobile (tiled) |
5158 | GPUs, but allows preserving the existing contents between passes. When doing |
5159 | multisample rendering with a resolve texture set, setting this flag also |
5160 | requests the multisample color data to be stored (written out) to the |
5161 | multisample texture or render buffer. (for non-multisample rendering the |
5162 | color data is always stored, but for MSAA storing the multisample data |
5163 | decreases efficiency for certain GPU architectures, hence defaulting to not |
5164 | writing it out) Note however that this is non-portable: in some cases there |
5165 | is no intermediate multisample texture on the graphics API level, e.g. when |
5166 | using OpenGL ES's \c{GL_EXT_multisampled_render_to_texture} as it is all |
5167 | implicit, handled by the OpenGL ES implementation. In that case, |
5168 | PreserveColorContents will likely have no effect. Therefore, avoid relying |
5169 | on this flag when using multisample rendering and the color attachment is |
5170 | using a multisample QRhiTexture (not QRhiRenderBuffer). |
5171 | |
5172 | \value PreserveDepthStencilContents Indicates that the contents of the |
5173 | depth texture is to be loaded when starting a render pass, instead |
5174 | clearing. Only applicable when a texture is used as the depth buffer |
5175 | (QRhiTextureRenderTargetDescription::depthTexture() is set) because |
5176 | depth/stencil renderbuffers may not have any physical backing and data may |
5177 | not be written out in the first place. |
5178 | |
5179 | \value DoNotStoreDepthStencilContents Indicates that the contents of the |
5180 | depth texture does not need to be written out. Relevant only when a |
5181 | QRhiTexture, not QRhiRenderBuffer, is used as the depth-stencil buffer, |
5182 | because for QRhiRenderBuffer this is implicit. When a depthResolveTexture is |
5183 | set, the flag is not relevant, because the behavior is then as if the flag |
5184 | was set. This enum value is introduced in Qt 6.8. |
5185 | */ |
5186 | |
5187 | /*! |
5188 | \internal |
5189 | */ |
5190 | QRhiTextureRenderTarget::QRhiTextureRenderTarget(QRhiImplementation *rhi, |
5191 | const QRhiTextureRenderTargetDescription &desc_, |
5192 | Flags flags_) |
5193 | : QRhiRenderTarget(rhi), |
5194 | m_desc(desc_), |
5195 | m_flags(flags_) |
5196 | { |
5197 | } |
5198 | |
5199 | /*! |
5200 | \return the resource type. |
5201 | */ |
5202 | QRhiResource::Type QRhiTextureRenderTarget::resourceType() const |
5203 | { |
5204 | return TextureRenderTarget; |
5205 | } |
5206 | |
5207 | /*! |
5208 | \fn virtual QRhiRenderPassDescriptor *QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor() = 0 |
5209 | |
5210 | \return a new QRhiRenderPassDescriptor that is compatible with this render |
5211 | target. |
5212 | |
5213 | The returned value is used in two ways: it can be passed to |
5214 | setRenderPassDescriptor() and |
5215 | QRhiGraphicsPipeline::setRenderPassDescriptor(). A render pass descriptor |
5216 | describes the attachments (color, depth/stencil) and the load/store |
5217 | behavior that can be affected by flags(). A QRhiGraphicsPipeline can only |
5218 | be used in combination with a render target that has a |
5219 | \l{QRhiRenderPassDescriptor::isCompatible()}{compatible} |
5220 | QRhiRenderPassDescriptor set. |
5221 | |
5222 | Two QRhiTextureRenderTarget instances can share the same render pass |
5223 | descriptor as long as they have the same number and type of attachments. |
5224 | The associated QRhiTexture or QRhiRenderBuffer instances are not part of |
5225 | the render pass descriptor so those can differ in the two |
5226 | QRhiTextureRenderTarget instances. |
5227 | |
5228 | \note resources, such as QRhiTexture instances, referenced in description() |
5229 | must already have create() called on them. |
5230 | |
5231 | \sa create() |
5232 | */ |
5233 | |
5234 | /*! |
5235 | \fn virtual bool QRhiTextureRenderTarget::create() = 0 |
5236 | |
5237 | Creates the corresponding native graphics resources. If there are already |
5238 | resources present due to an earlier create() with no corresponding |
5239 | destroy(), then destroy() is called implicitly first. |
5240 | |
5241 | \note renderPassDescriptor() must be set before calling create(). To obtain |
5242 | a QRhiRenderPassDescriptor compatible with the render target, call |
5243 | newCompatibleRenderPassDescriptor() before create() but after setting all |
5244 | other parameters, such as description() and flags(). To save resources, |
5245 | reuse the same QRhiRenderPassDescriptor with multiple |
5246 | QRhiTextureRenderTarget instances, whenever possible. Sharing the same |
5247 | render pass descriptor is only possible when the render targets have the |
5248 | same number and type of attachments (the actual textures can differ) and |
5249 | the same flags. |
5250 | |
5251 | \note resources, such as QRhiTexture instances, referenced in description() |
5252 | must already have create() called on them. |
5253 | |
5254 | \return \c true when successful, \c false when a graphics operation failed. |
5255 | Regardless of the return value, calling destroy() is always safe. |
5256 | */ |
5257 | |
5258 | /*! |
5259 | \fn QRhiTextureRenderTargetDescription QRhiTextureRenderTarget::description() const |
5260 | \return the render target description. |
5261 | */ |
5262 | |
5263 | /*! |
5264 | \fn void QRhiTextureRenderTarget::setDescription(const QRhiTextureRenderTargetDescription &desc) |
5265 | Sets the render target description \a desc. |
5266 | */ |
5267 | |
5268 | /*! |
5269 | \fn QRhiTextureRenderTarget::Flags QRhiTextureRenderTarget::flags() const |
5270 | \return the currently set flags. |
5271 | */ |
5272 | |
5273 | /*! |
5274 | \fn void QRhiTextureRenderTarget::setFlags(Flags f) |
5275 | Sets the flags to \a f. |
5276 | */ |
5277 | |
5278 | /*! |
5279 | \class QRhiShaderResourceBindings |
5280 | \inmodule QtGuiPrivate |
5281 | \inheaderfile rhi/qrhi.h |
5282 | \since 6.6 |
5283 | \brief Encapsulates resources for making buffer, texture, sampler resources visible to shaders. |
5284 | |
5285 | A QRhiShaderResourceBindings is a collection of QRhiShaderResourceBinding |
5286 | objects, each of which describe a single binding. |
5287 | |
5288 | Take a fragment shader with the following interface: |
5289 | |
5290 | \badcode |
5291 | layout(std140, binding = 0) uniform buf { |
5292 | mat4 mvp; |
5293 | int flip; |
5294 | } ubuf; |
5295 | |
5296 | layout(binding = 1) uniform sampler2D tex; |
5297 | \endcode |
5298 | |
5299 | To make resources visible to the shader, the following |
5300 | QRhiShaderResourceBindings could be created and then passed to |
5301 | QRhiGraphicsPipeline::setShaderResourceBindings(): |
5302 | |
5303 | \code |
5304 | QRhiShaderResourceBindings *srb = rhi->newShaderResourceBindings(); |
5305 | srb->setBindings({ |
5306 | QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, ubuf), |
5307 | QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, sampler) |
5308 | }); |
5309 | srb->create(); |
5310 | // ... |
5311 | QRhiGraphicsPipeline *ps = rhi->newGraphicsPipeline(); |
5312 | // ... |
5313 | ps->setShaderResourceBindings(srb); |
5314 | ps->create(); |
5315 | // ... |
5316 | cb->setGraphicsPipeline(ps); |
5317 | cb->setShaderResources(); // binds srb |
5318 | \endcode |
5319 | |
5320 | This assumes that \c ubuf is a QRhiBuffer, \c texture is a QRhiTexture, |
5321 | while \a sampler is a QRhiSampler. The example also assumes that the |
5322 | uniform block is present in the vertex shader as well so the same buffer is |
5323 | made visible to the vertex stage too. |
5324 | |
5325 | \section3 Advanced usage |
5326 | |
5327 | Building on the above example, let's assume that a pass now needs to use |
5328 | the exact same pipeline and shaders with a different texture. Creating a |
5329 | whole separate QRhiGraphicsPipeline just for this would be an overkill. |
5330 | This is why QRhiCommandBuffer::setShaderResources() allows specifying a \a |
5331 | srb argument. As long as the layouts (so the number of bindings and the |
5332 | binding points) match between two QRhiShaderResourceBindings, they can both |
5333 | be used with the same pipeline, assuming the pipeline was created with one of |
5334 | them in the first place. See isLayoutCompatible() for more details. |
5335 | |
5336 | \code |
5337 | QRhiShaderResourceBindings *srb2 = rhi->newShaderResourceBindings(); |
5338 | // ... |
5339 | cb->setGraphicsPipeline(ps); |
5340 | cb->setShaderResources(srb2); // binds srb2 |
5341 | \endcode |
5342 | |
5343 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
5344 | for details. |
5345 | */ |
5346 | |
5347 | /*! |
5348 | \typedef QRhiShaderResourceBindingSet |
5349 | \relates QRhi |
5350 | \since 6.7 |
5351 | |
5352 | Synonym for QRhiShaderResourceBindings. |
5353 | */ |
5354 | |
5355 | /*! |
5356 | \internal |
5357 | */ |
5358 | QRhiShaderResourceBindings::QRhiShaderResourceBindings(QRhiImplementation *rhi) |
5359 | : QRhiResource(rhi) |
5360 | { |
5361 | m_layoutDesc.reserve(asize: BINDING_PREALLOC * QRhiShaderResourceBinding::LAYOUT_DESC_ENTRIES_PER_BINDING); |
5362 | } |
5363 | |
5364 | /*! |
5365 | \return the resource type. |
5366 | */ |
5367 | QRhiResource::Type QRhiShaderResourceBindings::resourceType() const |
5368 | { |
5369 | return ShaderResourceBindings; |
5370 | } |
5371 | |
5372 | /*! |
5373 | \return \c true if the layout is compatible with \a other. The layout does |
5374 | not include the actual resource (such as, buffer or texture) and related |
5375 | parameters (such as, offset or size). It does include the binding point, |
5376 | pipeline stage, and resource type, however. The number and order of the |
5377 | bindings must also match in order to be compatible. |
5378 | |
5379 | When there is a QRhiGraphicsPipeline created with this |
5380 | QRhiShaderResourceBindings, and the function returns \c true, \a other can |
5381 | then safely be passed to QRhiCommandBuffer::setShaderResources(), and so |
5382 | be used with the pipeline in place of this QRhiShaderResourceBindings. |
5383 | |
5384 | \note This function must only be called after a successful create(), because |
5385 | it relies on data generated during the baking of the underlying data |
5386 | structures. This way the function can implement a comparison approach that |
5387 | is more efficient than iterating through two binding lists and calling |
5388 | QRhiShaderResourceBinding::isLayoutCompatible() on each pair. This becomes |
5389 | relevant especially when this function is called at a high frequency. |
5390 | |
5391 | \sa serializedLayoutDescription() |
5392 | */ |
5393 | bool QRhiShaderResourceBindings::isLayoutCompatible(const QRhiShaderResourceBindings *other) const |
5394 | { |
5395 | if (other == this) |
5396 | return true; |
5397 | |
5398 | if (!other) |
5399 | return false; |
5400 | |
5401 | // This can become a hot code path. Therefore we do not iterate and call |
5402 | // isLayoutCompatible() on m_bindings, but rather check a pre-calculated |
5403 | // hash code and then, if the hash matched, do a uint array comparison |
5404 | // (that's still more cache friendly). |
5405 | |
5406 | return m_layoutDescHash == other->m_layoutDescHash |
5407 | && m_layoutDesc == other->m_layoutDesc; |
5408 | } |
5409 | |
5410 | /*! |
5411 | \fn QVector<quint32> QRhiShaderResourceBindings::serializedLayoutDescription() const |
5412 | |
5413 | \return a vector of integers containing an opaque blob describing the layout |
5414 | of the binding list, i.e. the data relevant for |
5415 | \l{isLayoutCompatible()}{layout compatibility tests}. |
5416 | |
5417 | Given two objects \c srb1 and \c srb2, if the data returned from this |
5418 | function is identical, then \c{srb1->isLayoutCompatible(srb2)}, and vice |
5419 | versa hold true as well. |
5420 | |
5421 | \note The returned data is meant to be used for storing in memory and |
5422 | comparisons during the lifetime of the QRhi the object belongs to. It is not |
5423 | meant for storing on disk, reusing between processes, or using with multiple |
5424 | QRhi instances with potentially different backends. |
5425 | |
5426 | \sa isLayoutCompatible() |
5427 | */ |
5428 | |
5429 | void QRhiImplementation::updateLayoutDesc(QRhiShaderResourceBindings *srb) |
5430 | { |
5431 | srb->m_layoutDescHash = 0; |
5432 | srb->m_layoutDesc.clear(); |
5433 | auto layoutDescAppender = std::back_inserter(x&: srb->m_layoutDesc); |
5434 | for (const QRhiShaderResourceBinding &b : std::as_const(t&: srb->m_bindings)) { |
5435 | const QRhiShaderResourceBinding::Data *d = &b.d; |
5436 | srb->m_layoutDescHash ^= uint(d->binding) ^ uint(d->stage) ^ uint(d->type) |
5437 | ^ uint(d->arraySize()); |
5438 | layoutDescAppender = d->serialize(dst: layoutDescAppender); |
5439 | } |
5440 | } |
5441 | |
5442 | /*! |
5443 | \fn void QRhiShaderResourceBindings::setBindings(std::initializer_list<QRhiShaderResourceBinding> list) |
5444 | Sets the \a list of bindings. |
5445 | */ |
5446 | |
5447 | /*! |
5448 | \fn template<typename InputIterator> void QRhiShaderResourceBindings::setBindings(InputIterator first, InputIterator last) |
5449 | Sets the list of bindings from the iterators \a first and \a last. |
5450 | */ |
5451 | |
5452 | /*! |
5453 | \fn const QRhiShaderResourceBinding *QRhiShaderResourceBindings::cbeginBindings() const |
5454 | \return a const iterator pointing to the first item in the binding list. |
5455 | */ |
5456 | |
5457 | /*! |
5458 | \fn const QRhiShaderResourceBinding *QRhiShaderResourceBindings::cendBindings() const |
5459 | \return a const iterator pointing just after the last item in the binding list. |
5460 | */ |
5461 | |
5462 | /*! |
5463 | \fn const QRhiShaderResourceBinding *QRhiShaderResourceBindings::bindingAt(qsizetype index) const |
5464 | \return the binding at the specified \a index. |
5465 | */ |
5466 | |
5467 | /*! |
5468 | \fn qsizetype QRhiShaderResourceBindings::bindingCount() const |
5469 | \return the number of bindings. |
5470 | */ |
5471 | |
5472 | /*! |
5473 | \class QRhiShaderResourceBinding |
5474 | \inmodule QtGuiPrivate |
5475 | \inheaderfile rhi/qrhi.h |
5476 | \since 6.6 |
5477 | \brief Describes the shader resource for a single binding point. |
5478 | |
5479 | A QRhiShaderResourceBinding cannot be constructed directly. Instead, use the |
5480 | static functions such as uniformBuffer() or sampledTexture() to get an |
5481 | instance. |
5482 | |
5483 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
5484 | for details. |
5485 | */ |
5486 | |
5487 | /*! |
5488 | \enum QRhiShaderResourceBinding::Type |
5489 | Specifies type of the shader resource bound to a binding point |
5490 | |
5491 | \value UniformBuffer Uniform buffer |
5492 | |
5493 | \value SampledTexture Combined image sampler (a texture and sampler pair). |
5494 | Even when the shading language associated with the underlying 3D API has no |
5495 | support for this concept (e.g. D3D and HLSL), this is still supported |
5496 | because the shader translation layer takes care of the appropriate |
5497 | translation and remapping of binding points or shader registers. |
5498 | |
5499 | \value Texture Texture (separate) |
5500 | |
5501 | \value Sampler Sampler (separate) |
5502 | |
5503 | \value ImageLoad Image load (with GLSL this maps to doing imageLoad() on a |
5504 | single level - and either one or all layers - of a texture exposed to the |
5505 | shader as an image object) |
5506 | |
5507 | \value ImageStore Image store (with GLSL this maps to doing imageStore() or |
5508 | imageAtomic*() on a single level - and either one or all layers - of a |
5509 | texture exposed to the shader as an image object) |
5510 | |
5511 | \value ImageLoadStore Image load and store |
5512 | |
5513 | \value BufferLoad Storage buffer store (with GLSL this maps to reading from |
5514 | a shader storage buffer) |
5515 | |
5516 | \value BufferStore Storage buffer store (with GLSL this maps to writing to |
5517 | a shader storage buffer) |
5518 | |
5519 | \value BufferLoadStore Storage buffer load and store |
5520 | */ |
5521 | |
5522 | /*! |
5523 | \enum QRhiShaderResourceBinding::StageFlag |
5524 | Flag values to indicate which stages the shader resource is visible in |
5525 | |
5526 | \value VertexStage Vertex stage |
5527 | \value TessellationControlStage Tessellation control (hull shader) stage |
5528 | \value TessellationEvaluationStage Tessellation evaluation (domain shader) stage |
5529 | \value FragmentStage Fragment (pixel shader) stage |
5530 | \value ComputeStage Compute stage |
5531 | \value GeometryStage Geometry stage |
5532 | */ |
5533 | |
5534 | /*! |
5535 | \return \c true if the layout is compatible with \a other. The layout does not |
5536 | include the actual resource (such as, buffer or texture) and related |
5537 | parameters (such as, offset or size). |
5538 | |
5539 | For example, \c a and \c b below are not equal, but are compatible layout-wise: |
5540 | |
5541 | \code |
5542 | auto a = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, buffer); |
5543 | auto b = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, someOtherBuffer, 256); |
5544 | \endcode |
5545 | */ |
5546 | bool QRhiShaderResourceBinding::isLayoutCompatible(const QRhiShaderResourceBinding &other) const |
5547 | { |
5548 | // everything that goes into a VkDescriptorSetLayoutBinding must match |
5549 | return d.binding == other.d.binding |
5550 | && d.stage == other.d.stage |
5551 | && d.type == other.d.type |
5552 | && d.arraySize() == other.d.arraySize(); |
5553 | } |
5554 | |
5555 | /*! |
5556 | \return a shader resource binding for the given binding number, pipeline |
5557 | stages, and buffer specified by \a binding, \a stage, and \a buf. |
5558 | |
5559 | \note When \a buf is not null, it must have been created with |
5560 | QRhiBuffer::UniformBuffer. |
5561 | |
5562 | \note \a buf can be null. It is valid to create a |
5563 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5564 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5565 | suitable for creating pipelines. Such a pipeline must then always be used |
5566 | together with another, layout compatible QRhiShaderResourceBindings with |
5567 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5568 | |
5569 | \note If the size of \a buf exceeds the limit reported for |
5570 | QRhi::MaxUniformBufferRange, unexpected errors may occur. |
5571 | */ |
5572 | QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer( |
5573 | int binding, StageFlags stage, QRhiBuffer *buf) |
5574 | { |
5575 | QRhiShaderResourceBinding b; |
5576 | b.d.binding = binding; |
5577 | b.d.stage = stage; |
5578 | b.d.type = UniformBuffer; |
5579 | b.d.u.ubuf.buf = buf; |
5580 | b.d.u.ubuf.offset = 0; |
5581 | b.d.u.ubuf.maybeSize = 0; // entire buffer |
5582 | b.d.u.ubuf.hasDynamicOffset = false; |
5583 | return b; |
5584 | } |
5585 | |
5586 | /*! |
5587 | \return a shader resource binding for the given binding number, pipeline |
5588 | stages, and buffer specified by \a binding, \a stage, and \a buf. This |
5589 | overload binds a region only, as specified by \a offset and \a size. |
5590 | |
5591 | \note It is up to the user to ensure the offset is aligned to |
5592 | QRhi::ubufAlignment(). |
5593 | |
5594 | \note \a size must be greater than 0. |
5595 | |
5596 | \note When \a buf is not null, it must have been created with |
5597 | QRhiBuffer::UniformBuffer. |
5598 | |
5599 | \note \a buf can be null. It is valid to create a |
5600 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5601 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5602 | suitable for creating pipelines. Such a pipeline must then always be used |
5603 | together with another, layout compatible QRhiShaderResourceBindings with |
5604 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5605 | |
5606 | \note If \a size exceeds the limit reported for QRhi::MaxUniformBufferRange, |
5607 | unexpected errors may occur. |
5608 | */ |
5609 | QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer( |
5610 | int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size) |
5611 | { |
5612 | Q_ASSERT(size > 0); |
5613 | QRhiShaderResourceBinding b; |
5614 | b.d.binding = binding; |
5615 | b.d.stage = stage; |
5616 | b.d.type = UniformBuffer; |
5617 | b.d.u.ubuf.buf = buf; |
5618 | b.d.u.ubuf.offset = offset; |
5619 | b.d.u.ubuf.maybeSize = size; |
5620 | b.d.u.ubuf.hasDynamicOffset = false; |
5621 | return b; |
5622 | } |
5623 | |
5624 | /*! |
5625 | \return a shader resource binding for the given binding number, pipeline |
5626 | stages, and buffer specified by \a binding, \a stage, and \a buf. The |
5627 | uniform buffer is assumed to have dynamic offset. The dynamic offset can be |
5628 | specified in QRhiCommandBuffer::setShaderResources(), thus allowing using |
5629 | varying offset values without creating new bindings for the buffer. The |
5630 | size of the bound region is specified by \a size. Like with non-dynamic |
5631 | offsets, \c{offset + size} cannot exceed the size of \a buf. |
5632 | |
5633 | \note When \a buf is not null, it must have been created with |
5634 | QRhiBuffer::UniformBuffer. |
5635 | |
5636 | \note \a buf can be null. It is valid to create a |
5637 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5638 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5639 | suitable for creating pipelines. Such a pipeline must then always be used |
5640 | together with another, layout compatible QRhiShaderResourceBindings with |
5641 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5642 | |
5643 | \note If \a size exceeds the limit reported for QRhi::MaxUniformBufferRange, |
5644 | unexpected errors may occur. |
5645 | */ |
5646 | QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBufferWithDynamicOffset( |
5647 | int binding, StageFlags stage, QRhiBuffer *buf, quint32 size) |
5648 | { |
5649 | Q_ASSERT(size > 0); |
5650 | QRhiShaderResourceBinding b; |
5651 | b.d.binding = binding; |
5652 | b.d.stage = stage; |
5653 | b.d.type = UniformBuffer; |
5654 | b.d.u.ubuf.buf = buf; |
5655 | b.d.u.ubuf.offset = 0; |
5656 | b.d.u.ubuf.maybeSize = size; |
5657 | b.d.u.ubuf.hasDynamicOffset = true; |
5658 | return b; |
5659 | } |
5660 | |
5661 | /*! |
5662 | \return a shader resource binding for the given binding number, pipeline |
5663 | stages, texture, and sampler specified by \a binding, \a stage, \a tex, |
5664 | \a sampler. |
5665 | |
5666 | \note This function is equivalent to calling sampledTextures() with a |
5667 | \c count of 1. |
5668 | |
5669 | \note \a tex and \a sampler can be null. It is valid to create a |
5670 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5671 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5672 | suitable for creating pipelines. Such a pipeline must then always be used |
5673 | together with another, layout compatible QRhiShaderResourceBindings with |
5674 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5675 | |
5676 | \note A shader may not be able to consume more than 16 textures/samplers, |
5677 | depending on the underlying graphics API. This hard limit must be kept in |
5678 | mind in renderer design. This does not apply to texture arrays which |
5679 | consume a single binding point (shader register) and can contain 256-2048 |
5680 | textures, depending on the underlying graphics API. Arrays of textures (see |
5681 | sampledTextures()) are however no different in this regard than using the |
5682 | same number of individual textures. |
5683 | |
5684 | \sa sampledTextures() |
5685 | */ |
5686 | QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture( |
5687 | int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler) |
5688 | { |
5689 | QRhiShaderResourceBinding b; |
5690 | b.d.binding = binding; |
5691 | b.d.stage = stage; |
5692 | b.d.type = SampledTexture; |
5693 | b.d.u.stex.count = 1; |
5694 | b.d.u.stex.texSamplers[0] = { .tex: tex, .sampler: sampler }; |
5695 | return b; |
5696 | } |
5697 | |
5698 | /*! |
5699 | \return a shader resource binding for the given binding number, pipeline |
5700 | stages, and the array of texture-sampler pairs specified by \a binding, \a |
5701 | stage, \a count, and \a texSamplers. |
5702 | |
5703 | \note \a count must be at least 1, and not larger than 16. |
5704 | |
5705 | \note When \a count is 1, this function is equivalent to sampledTexture(). |
5706 | |
5707 | This function is relevant when arrays of combined image samplers are |
5708 | involved. For example, in GLSL \c{layout(binding = 5) uniform sampler2D |
5709 | shadowMaps[8];} declares an array of combined image samplers. The |
5710 | application is then expected provide a QRhiShaderResourceBinding for |
5711 | binding point 5, set up by calling this function with \a count set to 8 and |
5712 | a valid texture and sampler for each element of the array. |
5713 | |
5714 | \warning All elements of the array must be specified. With the above |
5715 | example, the only valid, portable approach is calling this function with a |
5716 | \a count of 8. Additionally, all QRhiTexture and QRhiSampler instances must |
5717 | be valid, meaning nullptr is not an accepted value. This is due to some of |
5718 | the underlying APIs, such as, Vulkan, that require a valid image and |
5719 | sampler object for each element in descriptor arrays. Applications are |
5720 | advised to provide "dummy" samplers and textures if some array elements are |
5721 | not relevant (due to not being accessed in the shader). |
5722 | |
5723 | \note \a texSamplers can be null. It is valid to create a |
5724 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5725 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5726 | suitable for creating pipelines. Such a pipeline must then always be used |
5727 | together with another, layout compatible QRhiShaderResourceBindings with |
5728 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5729 | |
5730 | \sa sampledTexture() |
5731 | */ |
5732 | QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTextures( |
5733 | int binding, StageFlags stage, int count, const TextureAndSampler *texSamplers) |
5734 | { |
5735 | Q_ASSERT(count >= 1 && count <= Data::MAX_TEX_SAMPLER_ARRAY_SIZE); |
5736 | QRhiShaderResourceBinding b; |
5737 | b.d.binding = binding; |
5738 | b.d.stage = stage; |
5739 | b.d.type = SampledTexture; |
5740 | b.d.u.stex.count = count; |
5741 | for (int i = 0; i < count; ++i) { |
5742 | if (texSamplers) |
5743 | b.d.u.stex.texSamplers[i] = texSamplers[i]; |
5744 | else |
5745 | b.d.u.stex.texSamplers[i] = { .tex: nullptr, .sampler: nullptr }; |
5746 | } |
5747 | return b; |
5748 | } |
5749 | |
5750 | /*! |
5751 | \return a shader resource binding for the given binding number, pipeline |
5752 | stages, and texture specified by \a binding, \a stage, \a tex. |
5753 | |
5754 | \note This function is equivalent to calling textures() with a |
5755 | \c count of 1. |
5756 | |
5757 | \note \a tex can be null. It is valid to create a |
5758 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5759 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5760 | suitable for creating pipelines. Such a pipeline must then always be used |
5761 | together with another, layout compatible QRhiShaderResourceBindings with |
5762 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5763 | |
5764 | This creates a binding for a separate texture (image) object, whereas |
5765 | sampledTexture() is suitable for combined image samplers. In |
5766 | Vulkan-compatible GLSL code separate textures are declared as \c texture2D |
5767 | as opposed to \c sampler2D: \c{layout(binding = 1) uniform texture2D tex;} |
5768 | |
5769 | \note A shader may not be able to consume more than 16 textures, depending |
5770 | on the underlying graphics API. This hard limit must be kept in mind in |
5771 | renderer design. This does not apply to texture arrays which consume a |
5772 | single binding point (shader register) and can contain 256-2048 textures, |
5773 | depending on the underlying graphics API. Arrays of textures (see |
5774 | sampledTextures()) are however no different in this regard than using the |
5775 | same number of individual textures. |
5776 | |
5777 | \sa textures(), sampler() |
5778 | */ |
5779 | QRhiShaderResourceBinding QRhiShaderResourceBinding::texture(int binding, StageFlags stage, QRhiTexture *tex) |
5780 | { |
5781 | QRhiShaderResourceBinding b; |
5782 | b.d.binding = binding; |
5783 | b.d.stage = stage; |
5784 | b.d.type = Texture; |
5785 | b.d.u.stex.count = 1; |
5786 | b.d.u.stex.texSamplers[0] = { .tex: tex, .sampler: nullptr }; |
5787 | return b; |
5788 | } |
5789 | |
5790 | /*! |
5791 | \return a shader resource binding for the given binding number, pipeline |
5792 | stages, and the array of (separate) textures specified by \a binding, \a |
5793 | stage, \a count, and \a tex. |
5794 | |
5795 | \note \a count must be at least 1, and not larger than 16. |
5796 | |
5797 | \note When \a count is 1, this function is equivalent to texture(). |
5798 | |
5799 | \warning All elements of the array must be specified. |
5800 | |
5801 | \note \a tex can be null. It is valid to create a |
5802 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5803 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5804 | suitable for creating pipelines. Such a pipeline must then always be used |
5805 | together with another, layout compatible QRhiShaderResourceBindings with |
5806 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5807 | |
5808 | \sa texture(), sampler() |
5809 | */ |
5810 | QRhiShaderResourceBinding QRhiShaderResourceBinding::textures(int binding, StageFlags stage, int count, QRhiTexture **tex) |
5811 | { |
5812 | Q_ASSERT(count >= 1 && count <= Data::MAX_TEX_SAMPLER_ARRAY_SIZE); |
5813 | QRhiShaderResourceBinding b; |
5814 | b.d.binding = binding; |
5815 | b.d.stage = stage; |
5816 | b.d.type = Texture; |
5817 | b.d.u.stex.count = count; |
5818 | for (int i = 0; i < count; ++i) { |
5819 | if (tex) |
5820 | b.d.u.stex.texSamplers[i] = { .tex: tex[i], .sampler: nullptr }; |
5821 | else |
5822 | b.d.u.stex.texSamplers[i] = { .tex: nullptr, .sampler: nullptr }; |
5823 | } |
5824 | return b; |
5825 | } |
5826 | |
5827 | /*! |
5828 | \return a shader resource binding for the given binding number, pipeline |
5829 | stages, and sampler specified by \a binding, \a stage, \a sampler. |
5830 | |
5831 | \note \a sampler can be null. It is valid to create a |
5832 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5833 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5834 | suitable for creating pipelines. Such a pipeline must then always be used |
5835 | together with another, layout compatible QRhiShaderResourceBindings with |
5836 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5837 | |
5838 | Arrays of separate samplers are not supported. |
5839 | |
5840 | This creates a binding for a separate sampler object, whereas |
5841 | sampledTexture() is suitable for combined image samplers. In |
5842 | Vulkan-compatible GLSL code separate samplers are declared as \c sampler |
5843 | as opposed to \c sampler2D: \c{layout(binding = 2) uniform sampler samp;} |
5844 | |
5845 | With both a \c texture2D and \c sampler present, they can be used together |
5846 | to sample the texture: \c{fragColor = texture(sampler2D(tex, samp), |
5847 | texcoord);}. |
5848 | |
5849 | \note A shader may not be able to consume more than 16 samplers, depending |
5850 | on the underlying graphics API. This hard limit must be kept in mind in |
5851 | renderer design. |
5852 | |
5853 | \sa texture() |
5854 | */ |
5855 | QRhiShaderResourceBinding QRhiShaderResourceBinding::sampler(int binding, StageFlags stage, QRhiSampler *sampler) |
5856 | { |
5857 | QRhiShaderResourceBinding b; |
5858 | b.d.binding = binding; |
5859 | b.d.stage = stage; |
5860 | b.d.type = Sampler; |
5861 | b.d.u.stex.count = 1; |
5862 | b.d.u.stex.texSamplers[0] = { .tex: nullptr, .sampler: sampler }; |
5863 | return b; |
5864 | } |
5865 | |
5866 | /*! |
5867 | \return a shader resource binding for a read-only storage image with the |
5868 | given \a binding number and pipeline \a stage. The image load operations |
5869 | will have access to all layers of the specified \a level. (so if the texture |
5870 | is a cubemap, the shader must use imageCube instead of image2D) |
5871 | |
5872 | \note When \a tex is not null, it must have been created with |
5873 | QRhiTexture::UsedWithLoadStore. |
5874 | |
5875 | \note \a tex can be null. It is valid to create a QRhiShaderResourceBindings |
5876 | with unspecified resources, but such an object cannot be used with |
5877 | QRhiCommandBuffer::setShaderResources(). It is however suitable for creating |
5878 | pipelines. Such a pipeline must then always be used together with another, |
5879 | layout compatible QRhiShaderResourceBindings with resources present passed |
5880 | to QRhiCommandBuffer::setShaderResources(). |
5881 | |
5882 | \note Image load/store is only guaranteed to be available within a compute |
5883 | pipeline. While some backends may support using these resources in a |
5884 | graphics pipeline as well, this is not universally supported, and even when |
5885 | it is, unexpected problems may arise when it comes to barriers and |
5886 | synchronization. Therefore, avoid using such resources with shaders other |
5887 | than compute. |
5888 | */ |
5889 | QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoad( |
5890 | int binding, StageFlags stage, QRhiTexture *tex, int level) |
5891 | { |
5892 | QRhiShaderResourceBinding b; |
5893 | b.d.binding = binding; |
5894 | b.d.stage = stage; |
5895 | b.d.type = ImageLoad; |
5896 | b.d.u.simage.tex = tex; |
5897 | b.d.u.simage.level = level; |
5898 | return b; |
5899 | } |
5900 | |
5901 | /*! |
5902 | \return a shader resource binding for a write-only storage image with the |
5903 | given \a binding number and pipeline \a stage. The image store operations |
5904 | will have access to all layers of the specified \a level. (so if the texture |
5905 | is a cubemap, the shader must use imageCube instead of image2D) |
5906 | |
5907 | \note When \a tex is not null, it must have been created with |
5908 | QRhiTexture::UsedWithLoadStore. |
5909 | |
5910 | \note \a tex can be null. It is valid to create a QRhiShaderResourceBindings |
5911 | with unspecified resources, but such an object cannot be used with |
5912 | QRhiCommandBuffer::setShaderResources(). It is however suitable for creating |
5913 | pipelines. Such a pipeline must then always be used together with another, |
5914 | layout compatible QRhiShaderResourceBindings with resources present passed |
5915 | to QRhiCommandBuffer::setShaderResources(). |
5916 | |
5917 | \note Image load/store is only guaranteed to be available within a compute |
5918 | pipeline. While some backends may support using these resources in a |
5919 | graphics pipeline as well, this is not universally supported, and even when |
5920 | it is, unexpected problems may arise when it comes to barriers and |
5921 | synchronization. Therefore, avoid using such resources with shaders other |
5922 | than compute. |
5923 | */ |
5924 | QRhiShaderResourceBinding QRhiShaderResourceBinding::imageStore( |
5925 | int binding, StageFlags stage, QRhiTexture *tex, int level) |
5926 | { |
5927 | QRhiShaderResourceBinding b; |
5928 | b.d.binding = binding; |
5929 | b.d.stage = stage; |
5930 | b.d.type = ImageStore; |
5931 | b.d.u.simage.tex = tex; |
5932 | b.d.u.simage.level = level; |
5933 | return b; |
5934 | } |
5935 | |
5936 | /*! |
5937 | \return a shader resource binding for a read/write storage image with the |
5938 | given \a binding number and pipeline \a stage. The image load/store operations |
5939 | will have access to all layers of the specified \a level. (so if the texture |
5940 | is a cubemap, the shader must use imageCube instead of image2D) |
5941 | |
5942 | \note When \a tex is not null, it must have been created with |
5943 | QRhiTexture::UsedWithLoadStore. |
5944 | |
5945 | \note \a tex can be null. It is valid to create a QRhiShaderResourceBindings |
5946 | with unspecified resources, but such an object cannot be used with |
5947 | QRhiCommandBuffer::setShaderResources(). It is however suitable for creating |
5948 | pipelines. Such a pipeline must then always be used together with another, |
5949 | layout compatible QRhiShaderResourceBindings with resources present passed |
5950 | to QRhiCommandBuffer::setShaderResources(). |
5951 | |
5952 | \note Image load/store is only guaranteed to be available within a compute |
5953 | pipeline. While some backends may support using these resources in a |
5954 | graphics pipeline as well, this is not universally supported, and even when |
5955 | it is, unexpected problems may arise when it comes to barriers and |
5956 | synchronization. Therefore, avoid using such resources with shaders other |
5957 | than compute. |
5958 | */ |
5959 | QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoadStore( |
5960 | int binding, StageFlags stage, QRhiTexture *tex, int level) |
5961 | { |
5962 | QRhiShaderResourceBinding b; |
5963 | b.d.binding = binding; |
5964 | b.d.stage = stage; |
5965 | b.d.type = ImageLoadStore; |
5966 | b.d.u.simage.tex = tex; |
5967 | b.d.u.simage.level = level; |
5968 | return b; |
5969 | } |
5970 | |
5971 | /*! |
5972 | \return a shader resource binding for a read-only storage buffer with the |
5973 | given \a binding number and pipeline \a stage. |
5974 | |
5975 | \note When \a buf is not null, must have been created with |
5976 | QRhiBuffer::StorageBuffer. |
5977 | |
5978 | \note \a buf can be null. It is valid to create a |
5979 | QRhiShaderResourceBindings with unspecified resources, but such an object |
5980 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5981 | suitable for creating pipelines. Such a pipeline must then always be used |
5982 | together with another, layout compatible QRhiShaderResourceBindings with |
5983 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5984 | |
5985 | \note Buffer load/store is only guaranteed to be available within a compute |
5986 | pipeline. While some backends may support using these resources in a |
5987 | graphics pipeline as well, this is not universally supported, and even when |
5988 | it is, unexpected problems may arise when it comes to barriers and |
5989 | synchronization. Therefore, avoid using such resources with shaders other |
5990 | than compute. |
5991 | */ |
5992 | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad( |
5993 | int binding, StageFlags stage, QRhiBuffer *buf) |
5994 | { |
5995 | QRhiShaderResourceBinding b; |
5996 | b.d.binding = binding; |
5997 | b.d.stage = stage; |
5998 | b.d.type = BufferLoad; |
5999 | b.d.u.sbuf.buf = buf; |
6000 | b.d.u.sbuf.offset = 0; |
6001 | b.d.u.sbuf.maybeSize = 0; // entire buffer |
6002 | return b; |
6003 | } |
6004 | |
6005 | /*! |
6006 | \return a shader resource binding for a read-only storage buffer with the |
6007 | given \a binding number and pipeline \a stage. This overload binds a region |
6008 | only, as specified by \a offset and \a size. |
6009 | |
6010 | \note When \a buf is not null, must have been created with |
6011 | QRhiBuffer::StorageBuffer. |
6012 | |
6013 | \note \a buf can be null. It is valid to create a |
6014 | QRhiShaderResourceBindings with unspecified resources, but such an object |
6015 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6016 | suitable for creating pipelines. Such a pipeline must then always be used |
6017 | together with another, layout compatible QRhiShaderResourceBindings with |
6018 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6019 | |
6020 | \note Buffer load/store is only guaranteed to be available within a compute |
6021 | pipeline. While some backends may support using these resources in a |
6022 | graphics pipeline as well, this is not universally supported, and even when |
6023 | it is, unexpected problems may arise when it comes to barriers and |
6024 | synchronization. Therefore, avoid using such resources with shaders other |
6025 | than compute. |
6026 | */ |
6027 | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad( |
6028 | int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size) |
6029 | { |
6030 | Q_ASSERT(size > 0); |
6031 | QRhiShaderResourceBinding b; |
6032 | b.d.binding = binding; |
6033 | b.d.stage = stage; |
6034 | b.d.type = BufferLoad; |
6035 | b.d.u.sbuf.buf = buf; |
6036 | b.d.u.sbuf.offset = offset; |
6037 | b.d.u.sbuf.maybeSize = size; |
6038 | return b; |
6039 | } |
6040 | |
6041 | /*! |
6042 | \return a shader resource binding for a write-only storage buffer with the |
6043 | given \a binding number and pipeline \a stage. |
6044 | |
6045 | \note When \a buf is not null, must have been created with |
6046 | QRhiBuffer::StorageBuffer. |
6047 | |
6048 | \note \a buf can be null. It is valid to create a |
6049 | QRhiShaderResourceBindings with unspecified resources, but such an object |
6050 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6051 | suitable for creating pipelines. Such a pipeline must then always be used |
6052 | together with another, layout compatible QRhiShaderResourceBindings with |
6053 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6054 | |
6055 | \note Buffer load/store is only guaranteed to be available within a compute |
6056 | pipeline. While some backends may support using these resources in a |
6057 | graphics pipeline as well, this is not universally supported, and even when |
6058 | it is, unexpected problems may arise when it comes to barriers and |
6059 | synchronization. Therefore, avoid using such resources with shaders other |
6060 | than compute. |
6061 | */ |
6062 | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore( |
6063 | int binding, StageFlags stage, QRhiBuffer *buf) |
6064 | { |
6065 | QRhiShaderResourceBinding b; |
6066 | b.d.binding = binding; |
6067 | b.d.stage = stage; |
6068 | b.d.type = BufferStore; |
6069 | b.d.u.sbuf.buf = buf; |
6070 | b.d.u.sbuf.offset = 0; |
6071 | b.d.u.sbuf.maybeSize = 0; // entire buffer |
6072 | return b; |
6073 | } |
6074 | |
6075 | /*! |
6076 | \return a shader resource binding for a write-only storage buffer with the |
6077 | given \a binding number and pipeline \a stage. This overload binds a region |
6078 | only, as specified by \a offset and \a size. |
6079 | |
6080 | \note When \a buf is not null, must have been created with |
6081 | QRhiBuffer::StorageBuffer. |
6082 | |
6083 | \note \a buf can be null. It is valid to create a |
6084 | QRhiShaderResourceBindings with unspecified resources, but such an object |
6085 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6086 | suitable for creating pipelines. Such a pipeline must then always be used |
6087 | together with another, layout compatible QRhiShaderResourceBindings with |
6088 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6089 | |
6090 | \note Buffer load/store is only guaranteed to be available within a compute |
6091 | pipeline. While some backends may support using these resources in a |
6092 | graphics pipeline as well, this is not universally supported, and even when |
6093 | it is, unexpected problems may arise when it comes to barriers and |
6094 | synchronization. Therefore, avoid using such resources with shaders other |
6095 | than compute. |
6096 | */ |
6097 | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore( |
6098 | int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size) |
6099 | { |
6100 | Q_ASSERT(size > 0); |
6101 | QRhiShaderResourceBinding b; |
6102 | b.d.binding = binding; |
6103 | b.d.stage = stage; |
6104 | b.d.type = BufferStore; |
6105 | b.d.u.sbuf.buf = buf; |
6106 | b.d.u.sbuf.offset = offset; |
6107 | b.d.u.sbuf.maybeSize = size; |
6108 | return b; |
6109 | } |
6110 | |
6111 | /*! |
6112 | \return a shader resource binding for a read-write storage buffer with the |
6113 | given \a binding number and pipeline \a stage. |
6114 | |
6115 | \note When \a buf is not null, must have been created with |
6116 | QRhiBuffer::StorageBuffer. |
6117 | |
6118 | \note \a buf can be null. It is valid to create a |
6119 | QRhiShaderResourceBindings with unspecified resources, but such an object |
6120 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6121 | suitable for creating pipelines. Such a pipeline must then always be used |
6122 | together with another, layout compatible QRhiShaderResourceBindings with |
6123 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6124 | |
6125 | \note Buffer load/store is only guaranteed to be available within a compute |
6126 | pipeline. While some backends may support using these resources in a |
6127 | graphics pipeline as well, this is not universally supported, and even when |
6128 | it is, unexpected problems may arise when it comes to barriers and |
6129 | synchronization. Therefore, avoid using such resources with shaders other |
6130 | than compute. |
6131 | */ |
6132 | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore( |
6133 | int binding, StageFlags stage, QRhiBuffer *buf) |
6134 | { |
6135 | QRhiShaderResourceBinding b; |
6136 | b.d.binding = binding; |
6137 | b.d.stage = stage; |
6138 | b.d.type = BufferLoadStore; |
6139 | b.d.u.sbuf.buf = buf; |
6140 | b.d.u.sbuf.offset = 0; |
6141 | b.d.u.sbuf.maybeSize = 0; // entire buffer |
6142 | return b; |
6143 | } |
6144 | |
6145 | /*! |
6146 | \return a shader resource binding for a read-write storage buffer with the |
6147 | given \a binding number and pipeline \a stage. This overload binds a region |
6148 | only, as specified by \a offset and \a size. |
6149 | |
6150 | \note When \a buf is not null, must have been created with |
6151 | QRhiBuffer::StorageBuffer. |
6152 | |
6153 | \note \a buf can be null. It is valid to create a |
6154 | QRhiShaderResourceBindings with unspecified resources, but such an object |
6155 | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6156 | suitable for creating pipelines. Such a pipeline must then always be used |
6157 | together with another, layout compatible QRhiShaderResourceBindings with |
6158 | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6159 | |
6160 | \note Buffer load/store is only guaranteed to be available within a compute |
6161 | pipeline. While some backends may support using these resources in a |
6162 | graphics pipeline as well, this is not universally supported, and even when |
6163 | it is, unexpected problems may arise when it comes to barriers and |
6164 | synchronization. Therefore, avoid using such resources with shaders other |
6165 | than compute. |
6166 | */ |
6167 | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore( |
6168 | int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size) |
6169 | { |
6170 | Q_ASSERT(size > 0); |
6171 | QRhiShaderResourceBinding b; |
6172 | b.d.binding = binding; |
6173 | b.d.stage = stage; |
6174 | b.d.type = BufferLoadStore; |
6175 | b.d.u.sbuf.buf = buf; |
6176 | b.d.u.sbuf.offset = offset; |
6177 | b.d.u.sbuf.maybeSize = size; |
6178 | return b; |
6179 | } |
6180 | |
6181 | /*! |
6182 | \return \c true if the contents of the two QRhiShaderResourceBinding |
6183 | objects \a a and \a b are equal. This includes the resources (buffer, |
6184 | texture) and related parameters (offset, size) as well. To only compare |
6185 | layouts (binding point, pipeline stage, resource type), use |
6186 | \l{QRhiShaderResourceBinding::isLayoutCompatible()}{isLayoutCompatible()} |
6187 | instead. |
6188 | |
6189 | \relates QRhiShaderResourceBinding |
6190 | */ |
6191 | bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept |
6192 | { |
6193 | const QRhiShaderResourceBinding::Data *da = QRhiImplementation::shaderResourceBindingData(binding: a); |
6194 | const QRhiShaderResourceBinding::Data *db = QRhiImplementation::shaderResourceBindingData(binding: b); |
6195 | |
6196 | if (da == db) |
6197 | return true; |
6198 | |
6199 | |
6200 | if (da->binding != db->binding |
6201 | || da->stage != db->stage |
6202 | || da->type != db->type) |
6203 | { |
6204 | return false; |
6205 | } |
6206 | |
6207 | switch (da->type) { |
6208 | case QRhiShaderResourceBinding::UniformBuffer: |
6209 | if (da->u.ubuf.buf != db->u.ubuf.buf |
6210 | || da->u.ubuf.offset != db->u.ubuf.offset |
6211 | || da->u.ubuf.maybeSize != db->u.ubuf.maybeSize) |
6212 | { |
6213 | return false; |
6214 | } |
6215 | break; |
6216 | case QRhiShaderResourceBinding::SampledTexture: |
6217 | if (da->u.stex.count != db->u.stex.count) |
6218 | return false; |
6219 | for (int i = 0; i < da->u.stex.count; ++i) { |
6220 | if (da->u.stex.texSamplers[i].tex != db->u.stex.texSamplers[i].tex |
6221 | || da->u.stex.texSamplers[i].sampler != db->u.stex.texSamplers[i].sampler) |
6222 | { |
6223 | return false; |
6224 | } |
6225 | } |
6226 | break; |
6227 | case QRhiShaderResourceBinding::Texture: |
6228 | if (da->u.stex.count != db->u.stex.count) |
6229 | return false; |
6230 | for (int i = 0; i < da->u.stex.count; ++i) { |
6231 | if (da->u.stex.texSamplers[i].tex != db->u.stex.texSamplers[i].tex) |
6232 | return false; |
6233 | } |
6234 | break; |
6235 | case QRhiShaderResourceBinding::Sampler: |
6236 | if (da->u.stex.texSamplers[0].sampler != db->u.stex.texSamplers[0].sampler) |
6237 | return false; |
6238 | break; |
6239 | case QRhiShaderResourceBinding::ImageLoad: |
6240 | case QRhiShaderResourceBinding::ImageStore: |
6241 | case QRhiShaderResourceBinding::ImageLoadStore: |
6242 | if (da->u.simage.tex != db->u.simage.tex |
6243 | || da->u.simage.level != db->u.simage.level) |
6244 | { |
6245 | return false; |
6246 | } |
6247 | break; |
6248 | case QRhiShaderResourceBinding::BufferLoad: |
6249 | case QRhiShaderResourceBinding::BufferStore: |
6250 | case QRhiShaderResourceBinding::BufferLoadStore: |
6251 | if (da->u.sbuf.buf != db->u.sbuf.buf |
6252 | || da->u.sbuf.offset != db->u.sbuf.offset |
6253 | || da->u.sbuf.maybeSize != db->u.sbuf.maybeSize) |
6254 | { |
6255 | return false; |
6256 | } |
6257 | break; |
6258 | default: |
6259 | Q_UNREACHABLE_RETURN(false); |
6260 | } |
6261 | |
6262 | return true; |
6263 | } |
6264 | |
6265 | /*! |
6266 | \return \c false if all the bindings in the two QRhiShaderResourceBinding |
6267 | objects \a a and \a b are equal; otherwise returns \c true. |
6268 | |
6269 | \relates QRhiShaderResourceBinding |
6270 | */ |
6271 | bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept |
6272 | { |
6273 | return !(a == b); |
6274 | } |
6275 | |
6276 | /*! |
6277 | \return the hash value for \a b, using \a seed to seed the calculation. |
6278 | |
6279 | \relates QRhiShaderResourceBinding |
6280 | */ |
6281 | size_t qHash(const QRhiShaderResourceBinding &b, size_t seed) noexcept |
6282 | { |
6283 | const QRhiShaderResourceBinding::Data *d = QRhiImplementation::shaderResourceBindingData(binding: b); |
6284 | QtPrivate::QHashCombine hash; |
6285 | seed = hash(seed, d->binding); |
6286 | seed = hash(seed, d->stage); |
6287 | seed = hash(seed, d->type); |
6288 | switch (d->type) { |
6289 | case QRhiShaderResourceBinding::UniformBuffer: |
6290 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.ubuf.buf)); |
6291 | break; |
6292 | case QRhiShaderResourceBinding::SampledTexture: |
6293 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].tex)); |
6294 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].sampler)); |
6295 | break; |
6296 | case QRhiShaderResourceBinding::Texture: |
6297 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].tex)); |
6298 | break; |
6299 | case QRhiShaderResourceBinding::Sampler: |
6300 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].sampler)); |
6301 | break; |
6302 | case QRhiShaderResourceBinding::ImageLoad: |
6303 | case QRhiShaderResourceBinding::ImageStore: |
6304 | case QRhiShaderResourceBinding::ImageLoadStore: |
6305 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.simage.tex)); |
6306 | break; |
6307 | case QRhiShaderResourceBinding::BufferLoad: |
6308 | case QRhiShaderResourceBinding::BufferStore: |
6309 | case QRhiShaderResourceBinding::BufferLoadStore: |
6310 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.sbuf.buf)); |
6311 | break; |
6312 | } |
6313 | return seed; |
6314 | } |
6315 | |
6316 | #ifndef QT_NO_DEBUG_STREAM |
6317 | QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b) |
6318 | { |
6319 | QDebugStateSaver saver(dbg); |
6320 | const QRhiShaderResourceBinding::Data *d = QRhiImplementation::shaderResourceBindingData(binding: b); |
6321 | dbg.nospace() << "QRhiShaderResourceBinding(" |
6322 | << "binding="<< d->binding |
6323 | << " stage="<< d->stage |
6324 | << " type="<< d->type; |
6325 | switch (d->type) { |
6326 | case QRhiShaderResourceBinding::UniformBuffer: |
6327 | dbg.nospace() << " UniformBuffer(" |
6328 | << "buffer="<< d->u.ubuf.buf |
6329 | << " offset="<< d->u.ubuf.offset |
6330 | << " maybeSize="<< d->u.ubuf.maybeSize |
6331 | << ')'; |
6332 | break; |
6333 | case QRhiShaderResourceBinding::SampledTexture: |
6334 | dbg.nospace() << " SampledTextures(" |
6335 | << "count="<< d->u.stex.count; |
6336 | for (int i = 0; i < d->u.stex.count; ++i) { |
6337 | dbg.nospace() << " texture="<< d->u.stex.texSamplers[i].tex |
6338 | << " sampler="<< d->u.stex.texSamplers[i].sampler; |
6339 | } |
6340 | dbg.nospace() << ')'; |
6341 | break; |
6342 | case QRhiShaderResourceBinding::Texture: |
6343 | dbg.nospace() << " Textures(" |
6344 | << "count="<< d->u.stex.count; |
6345 | for (int i = 0; i < d->u.stex.count; ++i) |
6346 | dbg.nospace() << " texture="<< d->u.stex.texSamplers[i].tex; |
6347 | dbg.nospace() << ')'; |
6348 | break; |
6349 | case QRhiShaderResourceBinding::Sampler: |
6350 | dbg.nospace() << " Sampler(" |
6351 | << " sampler="<< d->u.stex.texSamplers[0].sampler |
6352 | << ')'; |
6353 | break; |
6354 | case QRhiShaderResourceBinding::ImageLoad: |
6355 | dbg.nospace() << " ImageLoad(" |
6356 | << "texture="<< d->u.simage.tex |
6357 | << " level="<< d->u.simage.level |
6358 | << ')'; |
6359 | break; |
6360 | case QRhiShaderResourceBinding::ImageStore: |
6361 | dbg.nospace() << " ImageStore(" |
6362 | << "texture="<< d->u.simage.tex |
6363 | << " level="<< d->u.simage.level |
6364 | << ')'; |
6365 | break; |
6366 | case QRhiShaderResourceBinding::ImageLoadStore: |
6367 | dbg.nospace() << " ImageLoadStore(" |
6368 | << "texture="<< d->u.simage.tex |
6369 | << " level="<< d->u.simage.level |
6370 | << ')'; |
6371 | break; |
6372 | case QRhiShaderResourceBinding::BufferLoad: |
6373 | dbg.nospace() << " BufferLoad(" |
6374 | << "buffer="<< d->u.sbuf.buf |
6375 | << " offset="<< d->u.sbuf.offset |
6376 | << " maybeSize="<< d->u.sbuf.maybeSize |
6377 | << ')'; |
6378 | break; |
6379 | case QRhiShaderResourceBinding::BufferStore: |
6380 | dbg.nospace() << " BufferStore(" |
6381 | << "buffer="<< d->u.sbuf.buf |
6382 | << " offset="<< d->u.sbuf.offset |
6383 | << " maybeSize="<< d->u.sbuf.maybeSize |
6384 | << ')'; |
6385 | break; |
6386 | case QRhiShaderResourceBinding::BufferLoadStore: |
6387 | dbg.nospace() << " BufferLoadStore(" |
6388 | << "buffer="<< d->u.sbuf.buf |
6389 | << " offset="<< d->u.sbuf.offset |
6390 | << " maybeSize="<< d->u.sbuf.maybeSize |
6391 | << ')'; |
6392 | break; |
6393 | default: |
6394 | dbg.nospace() << " UNKNOWN()"; |
6395 | break; |
6396 | } |
6397 | dbg.nospace() << ')'; |
6398 | return dbg; |
6399 | } |
6400 | #endif |
6401 | |
6402 | #ifndef QT_NO_DEBUG_STREAM |
6403 | QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb) |
6404 | { |
6405 | QDebugStateSaver saver(dbg); |
6406 | dbg.nospace() << "QRhiShaderResourceBindings(" |
6407 | << srb.m_bindings |
6408 | << ')'; |
6409 | return dbg; |
6410 | } |
6411 | #endif |
6412 | |
6413 | /*! |
6414 | \class QRhiGraphicsPipeline |
6415 | \inmodule QtGuiPrivate |
6416 | \inheaderfile rhi/qrhi.h |
6417 | \since 6.6 |
6418 | \brief Graphics pipeline state resource. |
6419 | |
6420 | Represents a graphics pipeline. What exactly this map to in the underlying |
6421 | native graphics API, varies. Where there is a concept of pipeline objects, |
6422 | for example with Vulkan, the QRhi backend will create such an object upon |
6423 | calling create(). Elsewhere, for example with OpenGL, the |
6424 | QRhiGraphicsPipeline may merely collect the various state, and create()'s |
6425 | main task is to set up the corresponding shader program, but deferring |
6426 | looking at any of the requested state to a later point. |
6427 | |
6428 | As with all QRhiResource subclasses, the two-phased initialization pattern |
6429 | applies: setting any values via the setters, for example setDepthTest(), is |
6430 | only effective after calling create(). Avoid changing any values once the |
6431 | QRhiGraphicsPipeline has been initialized via create(). To change some |
6432 | state, set the new value and call create() again. However, that will |
6433 | effectively release all underlying native resources and create new ones. As |
6434 | a result, it may be a heavy, expensive operation. Rather, prefer creating |
6435 | multiple pipelines with the different states, and |
6436 | \l{QRhiCommandBuffer::setGraphicsPipeline()}{switch between them} when |
6437 | recording the render pass. |
6438 | |
6439 | \note Setting the shader stages is mandatory. There must be at least one |
6440 | stage, and there must be a vertex stage. |
6441 | |
6442 | \note Setting the shader resource bindings is mandatory. The referenced |
6443 | QRhiShaderResourceBindings must already have create() called on it by the |
6444 | time create() is called. Associating with a QRhiShaderResourceBindings that |
6445 | has no bindings is also valid, as long as no shader in any stage expects any |
6446 | resources. Using a QRhiShaderResourceBindings object that does not specify |
6447 | any actual resources (i.e., the buffers, textures, etc. for the binding |
6448 | points are set to \nullptr) is valid as well, as long as a |
6449 | \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible} |
6450 | QRhiShaderResourceBindings, that specifies resources for all the bindings, |
6451 | is going to be set via |
6452 | \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} when |
6453 | recording the render pass. |
6454 | |
6455 | \note Setting the render pass descriptor is mandatory. To obtain a |
6456 | QRhiRenderPassDescriptor that can be passed to setRenderPassDescriptor(), |
6457 | use either QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor() or |
6458 | QRhiSwapChain::newCompatibleRenderPassDescriptor(). |
6459 | |
6460 | \note Setting the vertex input layout is mandatory. |
6461 | |
6462 | \note sampleCount() defaults to 1 and must match the sample count of the |
6463 | render target's color and depth stencil attachments. |
6464 | |
6465 | \note The depth test, depth write, and stencil test are disabled by |
6466 | default. The face culling mode defaults to no culling. |
6467 | |
6468 | \note stencilReadMask() and stencilWriteMask() apply to both faces. They |
6469 | both default to 0xFF. |
6470 | |
6471 | \section2 Example usage |
6472 | |
6473 | All settings of a graphics pipeline have defaults which might be suitable |
6474 | to many applications. Therefore a minimal example of creating a graphics |
6475 | pipeline could be the following. This assumes that the vertex shader takes |
6476 | a single \c{vec3 position} input at the input location 0. With the |
6477 | QRhiShaderResourceBindings and QRhiRenderPassDescriptor objects, plus the |
6478 | QShader collections for the vertex and fragment stages, a pipeline could be |
6479 | created like this: |
6480 | |
6481 | \code |
6482 | QRhiShaderResourceBindings *srb; |
6483 | QRhiRenderPassDescriptor *rpDesc; |
6484 | QShader vs, fs; |
6485 | // ... |
6486 | |
6487 | QRhiVertexInputLayout inputLayout; |
6488 | inputLayout.setBindings({ { 3 * sizeof(float) } }); |
6489 | inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float3, 0 } }); |
6490 | |
6491 | QRhiGraphicsPipeline *ps = rhi->newGraphicsPipeline(); |
6492 | ps->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } }); |
6493 | ps->setVertexInputLayout(inputLayout); |
6494 | ps->setShaderResourceBindings(srb); |
6495 | ps->setRenderPassDescriptor(rpDesc); |
6496 | if (!ps->create()) { error(); } |
6497 | \endcode |
6498 | |
6499 | The above code creates a pipeline object that uses the defaults for many |
6500 | settings and states. For example, it will use a \l Triangles topology, no |
6501 | backface culling, blending is disabled but color write is enabled for all |
6502 | four channels, depth test/write are disabled, stencil operations are |
6503 | disabled. |
6504 | |
6505 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
6506 | for details. |
6507 | |
6508 | \sa QRhiCommandBuffer, QRhi |
6509 | */ |
6510 | |
6511 | /*! |
6512 | \enum QRhiGraphicsPipeline::Flag |
6513 | |
6514 | Flag values for describing the dynamic state of the pipeline, and other |
6515 | options. The viewport is always dynamic. |
6516 | |
6517 | \value UsesBlendConstants Indicates that a blend color constant will be set |
6518 | via QRhiCommandBuffer::setBlendConstants() |
6519 | |
6520 | \value UsesStencilRef Indicates that a stencil reference value will be set |
6521 | via QRhiCommandBuffer::setStencilRef() |
6522 | |
6523 | \value UsesScissor Indicates that a scissor rectangle will be set via |
6524 | QRhiCommandBuffer::setScissor() |
6525 | |
6526 | \value CompileShadersWithDebugInfo Requests compiling shaders with debug |
6527 | information enabled. This is relevant only when runtime shader compilation |
6528 | from source code is involved, and only when the underlying infrastructure |
6529 | supports this. With concrete examples, this is not relevant with Vulkan and |
6530 | SPIR-V, because the GLSL-to-SPIR-V compilation does not happen at run |
6531 | time. On the other hand, consider Direct3D and HLSL, where there are |
6532 | multiple options: when the QShader packages ship with pre-compiled bytecode |
6533 | (\c DXBC), debug information is to be requested through the tool that |
6534 | generates the \c{.qsb} file, similarly to the case of Vulkan and |
6535 | SPIR-V. However, when having HLSL source code in the pre- or |
6536 | runtime-generated QShader packages, the first phase of compilation (HLSL |
6537 | source to intermediate format) happens at run time too, with this flag taken |
6538 | into account. Debug information is relevant in particular with tools like |
6539 | RenderDoc since it allows seeing the original source code when investigating |
6540 | the pipeline and when performing vertex or fragment shader debugging. |
6541 | */ |
6542 | |
6543 | /*! |
6544 | \enum QRhiGraphicsPipeline::Topology |
6545 | Specifies the primitive topology |
6546 | |
6547 | \value Triangles (default) |
6548 | \value TriangleStrip |
6549 | \value TriangleFan (only available if QRhi::TriangleFanTopology is supported) |
6550 | \value Lines |
6551 | \value LineStrip |
6552 | \value Points |
6553 | |
6554 | \value Patches (only available if QRhi::Tessellation is supported, and |
6555 | requires the tessellation stages to be present in the pipeline) |
6556 | */ |
6557 | |
6558 | /*! |
6559 | \enum QRhiGraphicsPipeline::CullMode |
6560 | Specifies the culling mode |
6561 | |
6562 | \value None No culling (default) |
6563 | \value Front Cull front faces |
6564 | \value Back Cull back faces |
6565 | */ |
6566 | |
6567 | /*! |
6568 | \enum QRhiGraphicsPipeline::FrontFace |
6569 | Specifies the front face winding order |
6570 | |
6571 | \value CCW Counter clockwise (default) |
6572 | \value CW Clockwise |
6573 | */ |
6574 | |
6575 | /*! |
6576 | \enum QRhiGraphicsPipeline::ColorMaskComponent |
6577 | Flag values for specifying the color write mask |
6578 | |
6579 | \value R |
6580 | \value G |
6581 | \value B |
6582 | \value A |
6583 | */ |
6584 | |
6585 | /*! |
6586 | \enum QRhiGraphicsPipeline::BlendFactor |
6587 | Specifies the blend factor |
6588 | |
6589 | \value Zero |
6590 | \value One |
6591 | \value SrcColor |
6592 | \value OneMinusSrcColor |
6593 | \value DstColor |
6594 | \value OneMinusDstColor |
6595 | \value SrcAlpha |
6596 | \value OneMinusSrcAlpha |
6597 | \value DstAlpha |
6598 | \value OneMinusDstAlpha |
6599 | \value ConstantColor |
6600 | \value OneMinusConstantColor |
6601 | \value ConstantAlpha |
6602 | \value OneMinusConstantAlpha |
6603 | \value SrcAlphaSaturate |
6604 | \value Src1Color |
6605 | \value OneMinusSrc1Color |
6606 | \value Src1Alpha |
6607 | \value OneMinusSrc1Alpha |
6608 | */ |
6609 | |
6610 | /*! |
6611 | \enum QRhiGraphicsPipeline::BlendOp |
6612 | Specifies the blend operation |
6613 | |
6614 | \value Add |
6615 | \value Subtract |
6616 | \value ReverseSubtract |
6617 | \value Min |
6618 | \value Max |
6619 | */ |
6620 | |
6621 | /*! |
6622 | \enum QRhiGraphicsPipeline::CompareOp |
6623 | Specifies the depth or stencil comparison function |
6624 | |
6625 | \value Never |
6626 | \value Less (default for depth) |
6627 | \value Equal |
6628 | \value LessOrEqual |
6629 | \value Greater |
6630 | \value NotEqual |
6631 | \value GreaterOrEqual |
6632 | \value Always (default for stencil) |
6633 | */ |
6634 | |
6635 | /*! |
6636 | \enum QRhiGraphicsPipeline::StencilOp |
6637 | Specifies the stencil operation |
6638 | |
6639 | \value StencilZero |
6640 | \value Keep (default) |
6641 | \value Replace |
6642 | \value IncrementAndClamp |
6643 | \value DecrementAndClamp |
6644 | \value Invert |
6645 | \value IncrementAndWrap |
6646 | \value DecrementAndWrap |
6647 | */ |
6648 | |
6649 | /*! |
6650 | \enum QRhiGraphicsPipeline::PolygonMode |
6651 | \brief Specifies the polygon rasterization mode |
6652 | |
6653 | Polygon Mode (Triangle Fill Mode in Metal, Fill Mode in D3D) specifies |
6654 | the fill mode used when rasterizing polygons. Polygons may be drawn as |
6655 | solids (Fill), or as a wire mesh (Line). |
6656 | |
6657 | Support for non-fill polygon modes is optional and is indicated by the |
6658 | QRhi::NonFillPolygonMode feature. With OpenGL ES and some Vulkan |
6659 | implementations the feature will likely be reported as unsupported, which |
6660 | then means values other than Fill cannot be used. |
6661 | |
6662 | \value Fill The interior of the polygon is filled (default) |
6663 | \value Line Boundary edges of the polygon are drawn as line segments. |
6664 | */ |
6665 | |
6666 | /*! |
6667 | \struct QRhiGraphicsPipeline::TargetBlend |
6668 | \inmodule QtGuiPrivate |
6669 | \inheaderfile rhi/qrhi.h |
6670 | \since 6.6 |
6671 | \brief Describes the blend state for one color attachment. |
6672 | |
6673 | Defaults to color write enabled, blending disabled. The blend values are |
6674 | set up for pre-multiplied alpha (One, OneMinusSrcAlpha, One, |
6675 | OneMinusSrcAlpha) by default. This means that to get the alpha blending |
6676 | mode Qt Quick uses, it is enough to set the \c enable flag to true while |
6677 | leaving other values at their defaults. |
6678 | |
6679 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
6680 | for details. |
6681 | */ |
6682 | |
6683 | /*! |
6684 | \variable QRhiGraphicsPipeline::TargetBlend::colorWrite |
6685 | */ |
6686 | |
6687 | /*! |
6688 | \variable QRhiGraphicsPipeline::TargetBlend::enable |
6689 | */ |
6690 | |
6691 | /*! |
6692 | \variable QRhiGraphicsPipeline::TargetBlend::srcColor |
6693 | */ |
6694 | |
6695 | /*! |
6696 | \variable QRhiGraphicsPipeline::TargetBlend::dstColor |
6697 | */ |
6698 | |
6699 | /*! |
6700 | \variable QRhiGraphicsPipeline::TargetBlend::opColor |
6701 | */ |
6702 | |
6703 | /*! |
6704 | \variable QRhiGraphicsPipeline::TargetBlend::srcAlpha |
6705 | */ |
6706 | |
6707 | /*! |
6708 | \variable QRhiGraphicsPipeline::TargetBlend::dstAlpha |
6709 | */ |
6710 | |
6711 | /*! |
6712 | \variable QRhiGraphicsPipeline::TargetBlend::opAlpha |
6713 | */ |
6714 | |
6715 | /*! |
6716 | \struct QRhiGraphicsPipeline::StencilOpState |
6717 | \inmodule QtGuiPrivate |
6718 | \inheaderfile rhi/qrhi.h |
6719 | \since 6.6 |
6720 | \brief Describes the stencil operation state. |
6721 | |
6722 | The default-constructed StencilOpState has the following set: |
6723 | \list |
6724 | \li failOp - \l Keep |
6725 | \li depthFailOp - \l Keep |
6726 | \li passOp - \l Keep |
6727 | \li compareOp \l Always |
6728 | \endlist |
6729 | |
6730 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
6731 | for details. |
6732 | */ |
6733 | |
6734 | /*! |
6735 | \variable QRhiGraphicsPipeline::StencilOpState::failOp |
6736 | */ |
6737 | |
6738 | /*! |
6739 | \variable QRhiGraphicsPipeline::StencilOpState::depthFailOp |
6740 | */ |
6741 | |
6742 | /*! |
6743 | \variable QRhiGraphicsPipeline::StencilOpState::passOp |
6744 | */ |
6745 | |
6746 | /*! |
6747 | \variable QRhiGraphicsPipeline::StencilOpState::compareOp |
6748 | */ |
6749 | |
6750 | /*! |
6751 | \internal |
6752 | */ |
6753 | QRhiGraphicsPipeline::QRhiGraphicsPipeline(QRhiImplementation *rhi) |
6754 | : QRhiResource(rhi) |
6755 | { |
6756 | } |
6757 | |
6758 | /*! |
6759 | \return the resource type. |
6760 | */ |
6761 | QRhiResource::Type QRhiGraphicsPipeline::resourceType() const |
6762 | { |
6763 | return GraphicsPipeline; |
6764 | } |
6765 | |
6766 | /*! |
6767 | \fn virtual bool QRhiGraphicsPipeline::create() = 0 |
6768 | |
6769 | Creates the corresponding native graphics resources. If there are already |
6770 | resources present due to an earlier create() with no corresponding |
6771 | destroy(), then destroy() is called implicitly first. |
6772 | |
6773 | \return \c true when successful, \c false when a graphics operation failed. |
6774 | Regardless of the return value, calling destroy() is always safe. |
6775 | |
6776 | \note This may be, depending on the underlying graphics API, an expensive |
6777 | operation, especially when shaders get compiled/optimized from source or |
6778 | from an intermediate bytecode format to the GPU's own instruction set. |
6779 | Where applicable, the QRhi backend automatically sets up the relevant |
6780 | non-persistent facilities to accelerate this, for example the Vulkan |
6781 | backend automatically creates a \c VkPipelineCache to improve data reuse |
6782 | during the lifetime of the application. |
6783 | |
6784 | \note Drivers may also employ various persistent (disk-based) caching |
6785 | strategies for shader and pipeline data, which is hidden to and is outside |
6786 | of Qt's control. In some cases, depending on the graphics API and the QRhi |
6787 | backend, there are facilities within QRhi for manually managing such a |
6788 | cache, allowing the retrieval of a serializable blob that can then be |
6789 | reloaded in the future runs of the application to ensure faster pipeline |
6790 | creation times. See QRhi::pipelineCacheData() and |
6791 | QRhi::setPipelineCacheData() for details. Note also that when working with |
6792 | a QRhi instance managed by a higher level Qt framework, such as Qt Quick, |
6793 | it is possible that such disk-based caching is taken care of automatically, |
6794 | for example QQuickWindow uses a disk-based pipeline cache by default (which |
6795 | comes in addition to any driver-level caching). |
6796 | */ |
6797 | |
6798 | /*! |
6799 | \fn QRhiGraphicsPipeline::Flags QRhiGraphicsPipeline::flags() const |
6800 | \return the currently set flags. |
6801 | */ |
6802 | |
6803 | /*! |
6804 | \fn void QRhiGraphicsPipeline::setFlags(Flags f) |
6805 | Sets the flags \a f. |
6806 | */ |
6807 | |
6808 | /*! |
6809 | \fn QRhiGraphicsPipeline::Topology QRhiGraphicsPipeline::topology() const |
6810 | \return the currently set primitive topology. |
6811 | */ |
6812 | |
6813 | /*! |
6814 | \fn void QRhiGraphicsPipeline::setTopology(Topology t) |
6815 | Sets the primitive topology \a t. |
6816 | */ |
6817 | |
6818 | /*! |
6819 | \fn QRhiGraphicsPipeline::CullMode QRhiGraphicsPipeline::cullMode() const |
6820 | \return the currently set face culling mode. |
6821 | */ |
6822 | |
6823 | /*! |
6824 | \fn void QRhiGraphicsPipeline::setCullMode(CullMode mode) |
6825 | Sets the specified face culling \a mode. |
6826 | */ |
6827 | |
6828 | /*! |
6829 | \fn QRhiGraphicsPipeline::FrontFace QRhiGraphicsPipeline::frontFace() const |
6830 | \return the currently set front face mode. |
6831 | */ |
6832 | |
6833 | /*! |
6834 | \fn void QRhiGraphicsPipeline::setFrontFace(FrontFace f) |
6835 | Sets the front face mode \a f. |
6836 | */ |
6837 | |
6838 | /*! |
6839 | \fn void QRhiGraphicsPipeline::setTargetBlends(std::initializer_list<TargetBlend> list) |
6840 | |
6841 | Sets the \a list of render target blend settings. This is a list because |
6842 | when multiple render targets are used (i.e., a QRhiTextureRenderTarget with |
6843 | more than one QRhiColorAttachment), there needs to be a TargetBlend |
6844 | structure per render target (color attachment). |
6845 | |
6846 | By default there is one default-constructed TargetBlend set. |
6847 | |
6848 | \sa QRhi::MaxColorAttachments |
6849 | */ |
6850 | |
6851 | /*! |
6852 | \fn template<typename InputIterator> void QRhiGraphicsPipeline::setTargetBlends(InputIterator first, InputIterator last) |
6853 | Sets the list of render target blend settings from the iterators \a first and \a last. |
6854 | */ |
6855 | |
6856 | /*! |
6857 | \fn const QRhiGraphicsPipeline::TargetBlend *QRhiGraphicsPipeline::cbeginTargetBlends() const |
6858 | \return a const iterator pointing to the first item in the render target blend setting list. |
6859 | */ |
6860 | |
6861 | /*! |
6862 | \fn const QRhiGraphicsPipeline::TargetBlend *QRhiGraphicsPipeline::cendTargetBlends() const |
6863 | \return a const iterator pointing just after the last item in the render target blend setting list. |
6864 | */ |
6865 | |
6866 | /*! |
6867 | \fn const QRhiGraphicsPipeline::TargetBlend *QRhiGraphicsPipeline::targetBlendAt(qsizetype index) const |
6868 | \return the render target blend setting at the specified \a index. |
6869 | */ |
6870 | |
6871 | /*! |
6872 | \fn qsizetype QRhiGraphicsPipeline::targetBlendCount() const |
6873 | \return the number of render target blend settings. |
6874 | */ |
6875 | |
6876 | /*! |
6877 | \fn bool QRhiGraphicsPipeline::hasDepthTest() const |
6878 | \return true if depth testing is enabled. |
6879 | */ |
6880 | |
6881 | /*! |
6882 | \fn void QRhiGraphicsPipeline::setDepthTest(bool enable) |
6883 | |
6884 | Enables or disables depth testing based on \a enable. Both depth test and |
6885 | the writing out of depth data are disabled by default. |
6886 | |
6887 | \sa setDepthWrite() |
6888 | */ |
6889 | |
6890 | /*! |
6891 | \fn bool QRhiGraphicsPipeline::hasDepthWrite() const |
6892 | \return true if depth write is enabled. |
6893 | */ |
6894 | |
6895 | /*! |
6896 | \fn void QRhiGraphicsPipeline::setDepthWrite(bool enable) |
6897 | |
6898 | Controls the writing out of depth data into the depth buffer based on |
6899 | \a enable. By default this is disabled. Depth write is typically enabled |
6900 | together with the depth test. |
6901 | |
6902 | \note Enabling depth write without having depth testing enabled may not |
6903 | lead to the desired result, and should be avoided. |
6904 | |
6905 | \sa setDepthTest() |
6906 | */ |
6907 | |
6908 | /*! |
6909 | \fn QRhiGraphicsPipeline::CompareOp QRhiGraphicsPipeline::depthOp() const |
6910 | \return the depth comparison function. |
6911 | */ |
6912 | |
6913 | /*! |
6914 | \fn void QRhiGraphicsPipeline::setDepthOp(CompareOp op) |
6915 | Sets the depth comparison function \a op. |
6916 | */ |
6917 | |
6918 | /*! |
6919 | \fn bool QRhiGraphicsPipeline::hasStencilTest() const |
6920 | \return true if stencil testing is enabled. |
6921 | */ |
6922 | |
6923 | /*! |
6924 | \fn void QRhiGraphicsPipeline::setStencilTest(bool enable) |
6925 | Enables or disables stencil tests based on \a enable. |
6926 | By default this is disabled. |
6927 | */ |
6928 | |
6929 | /*! |
6930 | \fn QRhiGraphicsPipeline::StencilOpState QRhiGraphicsPipeline::stencilFront() const |
6931 | \return the current stencil test state for front faces. |
6932 | */ |
6933 | |
6934 | /*! |
6935 | \fn void QRhiGraphicsPipeline::setStencilFront(const StencilOpState &state) |
6936 | Sets the stencil test \a state for front faces. |
6937 | */ |
6938 | |
6939 | /*! |
6940 | \fn QRhiGraphicsPipeline::StencilOpState QRhiGraphicsPipeline::stencilBack() const |
6941 | \return the current stencil test state for back faces. |
6942 | */ |
6943 | |
6944 | /*! |
6945 | \fn void QRhiGraphicsPipeline::setStencilBack(const StencilOpState &state) |
6946 | Sets the stencil test \a state for back faces. |
6947 | */ |
6948 | |
6949 | /*! |
6950 | \fn quint32 QRhiGraphicsPipeline::stencilReadMask() const |
6951 | \return the currrent stencil read mask. |
6952 | */ |
6953 | |
6954 | /*! |
6955 | \fn void QRhiGraphicsPipeline::setStencilReadMask(quint32 mask) |
6956 | Sets the stencil read \a mask. The default value is 0xFF. |
6957 | */ |
6958 | |
6959 | /*! |
6960 | \fn quint32 QRhiGraphicsPipeline::stencilWriteMask() const |
6961 | \return the current stencil write mask. |
6962 | */ |
6963 | |
6964 | /*! |
6965 | \fn void QRhiGraphicsPipeline::setStencilWriteMask(quint32 mask) |
6966 | Sets the stencil write \a mask. The default value is 0xFF. |
6967 | */ |
6968 | |
6969 | /*! |
6970 | \fn int QRhiGraphicsPipeline::sampleCount() const |
6971 | \return the currently set sample count. 1 means no multisample antialiasing. |
6972 | */ |
6973 | |
6974 | /*! |
6975 | \fn void QRhiGraphicsPipeline::setSampleCount(int s) |
6976 | |
6977 | Sets the sample count. Typical values for \a s are 1, 4, or 8. The pipeline |
6978 | must always be compatible with the render target, i.e. the sample counts |
6979 | must match. |
6980 | |
6981 | \sa QRhi::supportedSampleCounts() |
6982 | */ |
6983 | |
6984 | /*! |
6985 | \fn float QRhiGraphicsPipeline::lineWidth() const |
6986 | \return the currently set line width. The default is 1.0f. |
6987 | */ |
6988 | |
6989 | /*! |
6990 | \fn void QRhiGraphicsPipeline::setLineWidth(float width) |
6991 | |
6992 | Sets the line \a width. If the QRhi::WideLines feature is reported as |
6993 | unsupported at runtime, values other than 1.0f are ignored. |
6994 | */ |
6995 | |
6996 | /*! |
6997 | \fn int QRhiGraphicsPipeline::depthBias() const |
6998 | \return the currently set depth bias. |
6999 | */ |
7000 | |
7001 | /*! |
7002 | \fn void QRhiGraphicsPipeline::setDepthBias(int bias) |
7003 | Sets the depth \a bias. The default value is 0. |
7004 | */ |
7005 | |
7006 | /*! |
7007 | \fn float QRhiGraphicsPipeline::slopeScaledDepthBias() const |
7008 | \return the currently set slope scaled depth bias. |
7009 | */ |
7010 | |
7011 | /*! |
7012 | \fn void QRhiGraphicsPipeline::setSlopeScaledDepthBias(float bias) |
7013 | Sets the slope scaled depth \a bias. The default value is 0. |
7014 | */ |
7015 | |
7016 | /*! |
7017 | \fn void QRhiGraphicsPipeline::setShaderStages(std::initializer_list<QRhiShaderStage> list) |
7018 | Sets the \a list of shader stages. |
7019 | */ |
7020 | |
7021 | /*! |
7022 | \fn template<typename InputIterator> void QRhiGraphicsPipeline::setShaderStages(InputIterator first, InputIterator last) |
7023 | Sets the list of shader stages from the iterators \a first and \a last. |
7024 | */ |
7025 | |
7026 | /*! |
7027 | \fn const QRhiShaderStage *QRhiGraphicsPipeline::cbeginShaderStages() const |
7028 | \return a const iterator pointing to the first item in the shader stage list. |
7029 | */ |
7030 | |
7031 | /*! |
7032 | \fn const QRhiShaderStage *QRhiGraphicsPipeline::cendShaderStages() const |
7033 | \return a const iterator pointing just after the last item in the shader stage list. |
7034 | */ |
7035 | |
7036 | /*! |
7037 | \fn const QRhiShaderStage *QRhiGraphicsPipeline::shaderStageAt(qsizetype index) const |
7038 | \return the shader stage at the specified \a index. |
7039 | */ |
7040 | |
7041 | /*! |
7042 | \fn qsizetype QRhiGraphicsPipeline::shaderStageCount() const |
7043 | \return the number of shader stages in this pipeline. |
7044 | */ |
7045 | |
7046 | /*! |
7047 | \fn QRhiVertexInputLayout QRhiGraphicsPipeline::vertexInputLayout() const |
7048 | \return the currently set vertex input layout specification. |
7049 | */ |
7050 | |
7051 | /*! |
7052 | \fn void QRhiGraphicsPipeline::setVertexInputLayout(const QRhiVertexInputLayout &layout) |
7053 | Specifies the vertex input \a layout. |
7054 | */ |
7055 | |
7056 | /*! |
7057 | \fn QRhiShaderResourceBindings *QRhiGraphicsPipeline::shaderResourceBindings() const |
7058 | \return the currently associated QRhiShaderResourceBindings object. |
7059 | */ |
7060 | |
7061 | /*! |
7062 | \fn void QRhiGraphicsPipeline::setShaderResourceBindings(QRhiShaderResourceBindings *srb) |
7063 | |
7064 | Associates with \a srb describing the resource binding layout and the |
7065 | resources (QRhiBuffer, QRhiTexture) themselves. The latter is optional, |
7066 | because only the layout matters during pipeline creation. Therefore, the \a |
7067 | srb passed in here can leave the actual buffer or texture objects |
7068 | unspecified (\nullptr) as long as there is another, |
7069 | \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible} |
7070 | QRhiShaderResourceBindings bound via |
7071 | \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} before |
7072 | recording the draw calls. |
7073 | */ |
7074 | |
7075 | /*! |
7076 | \fn QRhiRenderPassDescriptor *QRhiGraphicsPipeline::renderPassDescriptor() const |
7077 | \return the currently set QRhiRenderPassDescriptor. |
7078 | */ |
7079 | |
7080 | /*! |
7081 | \fn void QRhiGraphicsPipeline::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) |
7082 | Associates with the specified QRhiRenderPassDescriptor \a desc. |
7083 | */ |
7084 | |
7085 | /*! |
7086 | \fn int QRhiGraphicsPipeline::patchControlPointCount() const |
7087 | \return the currently set patch control point count. |
7088 | */ |
7089 | |
7090 | /*! |
7091 | \fn void QRhiGraphicsPipeline::setPatchControlPointCount(int count) |
7092 | |
7093 | Sets the number of patch control points to \a count. The default value is |
7094 | 3. This is used only when the topology is set to \l Patches. |
7095 | */ |
7096 | |
7097 | /*! |
7098 | \fn QRhiGraphicsPipeline::PolygonMode QRhiGraphicsPipeline::polygonMode() const |
7099 | \return the polygon mode. |
7100 | */ |
7101 | |
7102 | /*! |
7103 | \fn void QRhiGraphicsPipeline::setPolygonMode(PolygonMode mode) |
7104 | Sets the polygon \a mode. The default is Fill. |
7105 | |
7106 | \sa QRhi::NonFillPolygonMode |
7107 | */ |
7108 | |
7109 | /*! |
7110 | \fn int QRhiGraphicsPipeline::multiViewCount() const |
7111 | \return the view count. The default is 0, indicating no multiview rendering. |
7112 | \since 6.7 |
7113 | */ |
7114 | |
7115 | /*! |
7116 | \fn void QRhiGraphicsPipeline::setMultiViewCount(int count) |
7117 | Sets the view \a count for multiview rendering. The default is 0, |
7118 | indicating no multiview rendering. |
7119 | \a count must be 2 or larger to trigger multiview rendering. |
7120 | |
7121 | Multiview is only available when the \l{QRhi::MultiView}{MultiView feature} |
7122 | is reported as supported. The render target must be a 2D texture array, and |
7123 | the color attachment for the render target must have the same \a count set. |
7124 | |
7125 | See QRhiColorAttachment::setMultiViewCount() for further details on |
7126 | multiview rendering. |
7127 | |
7128 | \since 6.7 |
7129 | \sa QRhi::MultiView, QRhiColorAttachment::setMultiViewCount() |
7130 | */ |
7131 | |
7132 | /*! |
7133 | \class QRhiSwapChain |
7134 | \inmodule QtGuiPrivate |
7135 | \inheaderfile rhi/qrhi.h |
7136 | \since 6.6 |
7137 | \brief Swapchain resource. |
7138 | |
7139 | A swapchain enables presenting rendering results to a surface. A swapchain |
7140 | is typically backed by a set of color buffers. Of these, one is displayed |
7141 | at a time. |
7142 | |
7143 | Below is a typical pattern for creating and managing a swapchain and some |
7144 | associated resources in order to render onto a QWindow: |
7145 | |
7146 | \code |
7147 | void init() |
7148 | { |
7149 | sc = rhi->newSwapChain(); |
7150 | ds = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, |
7151 | QSize(), // no need to set the size here due to UsedWithSwapChainOnly |
7152 | 1, |
7153 | QRhiRenderBuffer::UsedWithSwapChainOnly); |
7154 | sc->setWindow(window); |
7155 | sc->setDepthStencil(ds); |
7156 | rp = sc->newCompatibleRenderPassDescriptor(); |
7157 | sc->setRenderPassDescriptor(rp); |
7158 | resizeSwapChain(); |
7159 | } |
7160 | |
7161 | void resizeSwapChain() |
7162 | { |
7163 | hasSwapChain = sc->createOrResize(); |
7164 | } |
7165 | |
7166 | void render() |
7167 | { |
7168 | if (!hasSwapChain || notExposed) |
7169 | return; |
7170 | |
7171 | if (sc->currentPixelSize() != sc->surfacePixelSize() || newlyExposed) { |
7172 | resizeSwapChain(); |
7173 | if (!hasSwapChain) |
7174 | return; |
7175 | newlyExposed = false; |
7176 | } |
7177 | |
7178 | rhi->beginFrame(sc); |
7179 | // ... |
7180 | rhi->endFrame(sc); |
7181 | } |
7182 | \endcode |
7183 | |
7184 | Avoid relying on QWindow resize events to resize swapchains, especially |
7185 | considering that surface sizes may not always fully match the QWindow |
7186 | reported dimensions. The safe, cross-platform approach is to do the check |
7187 | via surfacePixelSize() whenever starting a new frame. |
7188 | |
7189 | Releasing the swapchain must happen while the QWindow and the underlying |
7190 | native window is fully up and running. Building on the previous example: |
7191 | |
7192 | \code |
7193 | void releaseSwapChain() |
7194 | { |
7195 | if (hasSwapChain) { |
7196 | sc->destroy(); |
7197 | hasSwapChain = false; |
7198 | } |
7199 | } |
7200 | |
7201 | // assuming Window is our QWindow subclass |
7202 | bool Window::event(QEvent *e) |
7203 | { |
7204 | switch (e->type()) { |
7205 | case QEvent::UpdateRequest: // for QWindow::requestUpdate() |
7206 | render(); |
7207 | break; |
7208 | case QEvent::PlatformSurface: |
7209 | if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) |
7210 | releaseSwapChain(); |
7211 | break; |
7212 | default: |
7213 | break; |
7214 | } |
7215 | return QWindow::event(e); |
7216 | } |
7217 | \endcode |
7218 | |
7219 | Initializing the swapchain and starting to render the first frame cannot |
7220 | start at any time. The safe, cross-platform approach is to rely on expose |
7221 | events. QExposeEvent is a loosely specified event that is sent whenever a |
7222 | window gets mapped, obscured, and resized, depending on the platform. |
7223 | |
7224 | \code |
7225 | void Window::exposeEvent(QExposeEvent *) |
7226 | { |
7227 | // initialize and start rendering when the window becomes usable for graphics purposes |
7228 | if (isExposed() && !running) { |
7229 | running = true; |
7230 | init(); |
7231 | } |
7232 | |
7233 | // stop pushing frames when not exposed or size becomes 0 |
7234 | if ((!isExposed() || (hasSwapChain && sc->surfacePixelSize().isEmpty())) && running) |
7235 | notExposed = true; |
7236 | |
7237 | // continue when exposed again and the surface has a valid size |
7238 | if (isExposed() && running && notExposed && !sc->surfacePixelSize().isEmpty()) { |
7239 | notExposed = false; |
7240 | newlyExposed = true; |
7241 | } |
7242 | |
7243 | if (isExposed() && !sc->surfacePixelSize().isEmpty()) |
7244 | render(); |
7245 | } |
7246 | \endcode |
7247 | |
7248 | Once the rendering has started, a simple way to request a new frame is |
7249 | QWindow::requestUpdate(). While on some platforms this is merely a small |
7250 | timer, on others it has a specific implementation: for instance on macOS or |
7251 | iOS it may be backed by |
7252 | \l{https://developer.apple.com/documentation/corevideo/cvdisplaylink?language=objc}{CVDisplayLink}. |
7253 | The example above is already prepared for update requests by handling |
7254 | QEvent::UpdateRequest. |
7255 | |
7256 | While acting as a QRhiRenderTarget, QRhiSwapChain also manages a |
7257 | QRhiCommandBuffer. Calling QRhi::endFrame() submits the recorded commands |
7258 | and also enqueues a \c present request. The default behavior is to do this |
7259 | with a swap interval of 1, meaning synchronizing to the display's vertical |
7260 | refresh is enabled. Thus the rendering thread calling beginFrame() and |
7261 | endFrame() will get throttled to vsync. On some backends this can be |
7262 | disabled by passing QRhiSwapChain:NoVSync in flags(). |
7263 | |
7264 | Multisampling (MSAA) is handled transparently to the applications when |
7265 | requested via setSampleCount(). Where applicable, QRhiSwapChain will take |
7266 | care of creating additional color buffers and issuing a multisample resolve |
7267 | command at the end of a frame. For OpenGL, it is necessary to request the |
7268 | appropriate sample count also via QSurfaceFormat, by calling |
7269 | QSurfaceFormat::setDefaultFormat() before initializing the QRhi. |
7270 | |
7271 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
7272 | for details. |
7273 | */ |
7274 | |
7275 | /*! |
7276 | \enum QRhiSwapChain::Flag |
7277 | Flag values to describe swapchain properties |
7278 | |
7279 | \value SurfaceHasPreMulAlpha Indicates that the target surface has |
7280 | transparency with premultiplied alpha. For example, this is what Qt Quick |
7281 | uses when the alpha channel is enabled on the target QWindow, because the |
7282 | scenegraph rendrerer always outputs fragments with alpha multiplied into |
7283 | the red, green, and blue values. To ensure identical behavior across |
7284 | platforms, always set QSurfaceFormat::alphaBufferSize() to a non-zero value |
7285 | on the target QWindow whenever this flag is set on the swapchain. |
7286 | |
7287 | \value SurfaceHasNonPreMulAlpha Indicates the target surface has |
7288 | transparency with non-premultiplied alpha. Be aware that this may not be |
7289 | supported on some systems, if the system compositor always expects content |
7290 | with premultiplied alpha. In that case the behavior with this flag set is |
7291 | expected to be equivalent to SurfaceHasPreMulAlpha. |
7292 | |
7293 | \value sRGB Requests to pick an sRGB format for the swapchain's color |
7294 | buffers and/or render target views, where applicable. Note that this |
7295 | implies that sRGB framebuffer update and blending will get enabled for all |
7296 | content targeting this swapchain, and opting out is not possible. For |
7297 | OpenGL, set \l{QSurfaceFormat::sRGBColorSpace}{sRGBColorSpace} on the |
7298 | QSurfaceFormat of the QWindow in addition. Applicable only when the |
7299 | swapchain format is set to QRhiSwapChain::SDR. |
7300 | |
7301 | \value UsedAsTransferSource Indicates the swapchain will be used as the |
7302 | source of a readback in QRhiResourceUpdateBatch::readBackTexture(). |
7303 | |
7304 | \value NoVSync Requests disabling waiting for vertical sync, also avoiding |
7305 | throttling the rendering thread. The behavior is backend specific and |
7306 | applicable only where it is possible to control this. Some may ignore the |
7307 | request altogether. For OpenGL, try instead setting the swap interval to 0 |
7308 | on the QWindow via QSurfaceFormat::setSwapInterval(). |
7309 | |
7310 | \value MinimalBufferCount Requests creating the swapchain with the minimum |
7311 | number of buffers, which is in practice 2, unless the graphics |
7312 | implementation has a higher minimum number than that. Only applicable with |
7313 | backends where such control is available via the graphics API, for example, |
7314 | Vulkan. By default it is up to the backend to decide what number of buffers |
7315 | it requests (in practice this is almost always either 2 or 3), and it is |
7316 | not the applications' concern. However, on Vulkan for instance the backend |
7317 | will likely prefer the higher number (3), for example to avoid odd |
7318 | performance issues with some Vulkan implementations on mobile devices. It |
7319 | could be that on some platforms it can prove to be beneficial to force the |
7320 | lower buffer count (2), so this flag allows forcing that. Note that all |
7321 | this has no effect on the number of frames kept in flight, so the CPU |
7322 | (QRhi) will still prepare frames at most \c{N - 1} frames ahead of the GPU, |
7323 | even when the swapchain image buffer count larger than \c N. (\c{N} = |
7324 | QRhi::FramesInFlight and typically 2). |
7325 | */ |
7326 | |
7327 | /*! |
7328 | \enum QRhiSwapChain::Format |
7329 | Describes the swapchain format. The default format is SDR. |
7330 | |
7331 | This enum is used with |
7332 | \l{QRhiSwapChain::isFormatSupported()}{isFormatSupported()} to check |
7333 | upfront if creating the swapchain with the given format is supported by the |
7334 | platform and the window's associated screen, and with |
7335 | \l{QRhiSwapChain::setFormat()}{setFormat()} |
7336 | to set the requested format in the swapchain before calling |
7337 | \l{QRhiSwapChain::createOrResize()}{createOrResize()} for the first time. |
7338 | |
7339 | \value SDR 8-bit RGBA or BGRA, depending on the backend and platform. With |
7340 | OpenGL ES in particular, it could happen that the platform provides less |
7341 | than 8 bits (e.g. due to EGL and the QSurfaceFormat choosing a 565 or 444 |
7342 | format - this is outside the control of QRhi). Standard dynamic range. May |
7343 | be combined with setting the QRhiSwapChain::sRGB flag. |
7344 | |
7345 | \value HDRExtendedSrgbLinear 16-bit float RGBA, high dynamic range, |
7346 | extended linear sRGB (scRGB) color space. This involves Rec. 709 primaries |
7347 | (same as SDR/sRGB) and linear colors. Conversion to the display's native |
7348 | color space (such as, HDR10) is performed by the windowing system. On |
7349 | Windows this is the canonical color space of the system compositor, and is |
7350 | the recommended format for HDR swapchains in general on desktop platforms. |
7351 | |
7352 | \value HDR10 10-bit unsigned int RGB or BGR with 2 bit alpha, high dynamic |
7353 | range, HDR10 (Rec. 2020) color space with an ST2084 PQ transfer function. |
7354 | |
7355 | \value HDRExtendedDisplayP3Linear 16-bit float RGBA, high dynamic range, |
7356 | extended linear Display P3 color space. The primary choice for HDR on |
7357 | platforms such as iOS and VisionOS. |
7358 | */ |
7359 | |
7360 | /*! |
7361 | \internal |
7362 | */ |
7363 | QRhiSwapChain::QRhiSwapChain(QRhiImplementation *rhi) |
7364 | : QRhiResource(rhi) |
7365 | { |
7366 | } |
7367 | |
7368 | /*! |
7369 | \return the resource type. |
7370 | */ |
7371 | QRhiResource::Type QRhiSwapChain::resourceType() const |
7372 | { |
7373 | return SwapChain; |
7374 | } |
7375 | |
7376 | /*! |
7377 | \fn QSize QRhiSwapChain::currentPixelSize() const |
7378 | |
7379 | \return the size with which the swapchain was last successfully built. Use |
7380 | this to decide if createOrResize() needs to be called again: if |
7381 | \c{currentPixelSize() != surfacePixelSize()} then the swapchain needs to be |
7382 | resized. |
7383 | |
7384 | \note Typical rendering logic will call this function to get the output |
7385 | size when starting to prepare a new frame, and base dependent calculations |
7386 | (such as, the viewport) on the size returned from this function. |
7387 | |
7388 | While in many cases the value is the same as \c{QWindow::size() * |
7389 | QWindow::devicePixelRatio()}, relying on the QWindow-reported size is not |
7390 | guaranteed to be correct on all platforms and graphics API implementations. |
7391 | Using this function is therefore strongly recommended whenever there is a |
7392 | need to identify the dimensions, in pixels, of the output layer or surface. |
7393 | |
7394 | This also has the added benefit of avoiding potential data races when QRhi |
7395 | is used on a dedicated rendering thread, because the need to call QWindow |
7396 | functions, that may then access data updated on the main thread, is |
7397 | avoided. |
7398 | |
7399 | \sa surfacePixelSize() |
7400 | */ |
7401 | |
7402 | /*! |
7403 | \fn virtual QSize QRhiSwapChain::surfacePixelSize() = 0 |
7404 | |
7405 | \return The size of the window's associated surface or layer. |
7406 | |
7407 | \warning Do not assume this is the same as \c{QWindow::size() * |
7408 | QWindow::devicePixelRatio()}. With some graphics APIs and windowing system |
7409 | interfaces (for example, Vulkan) there is a theoretical possibility for a |
7410 | surface to assume a size different from the associated window. To support |
7411 | these cases, \b{rendering logic must always base size-derived calculations |
7412 | (such as, viewports) on the size reported from QRhiSwapChain, and never on |
7413 | the size queried from QWindow}. |
7414 | |
7415 | \note \b{Can also be called before createOrResize(), if at least window() is |
7416 | already set. This in combination with currentPixelSize() allows to detect |
7417 | when a swapchain needs to be resized.} However, watch out for the fact that |
7418 | the size of the underlying native object (surface, layer, or similar) is |
7419 | "live", so whenever this function is called, it returns the latest value |
7420 | reported by the underlying implementation, without any atomicity guarantee. |
7421 | Therefore, using this function to determine pixel sizes for graphics |
7422 | resources that are used in a frame is strongly discouraged. Rely on |
7423 | currentPixelSize() instead which returns a size that is atomic and will not |
7424 | change between createOrResize() invocations. |
7425 | |
7426 | \note For depth-stencil buffers used in combination with the swapchain's |
7427 | color buffers, it is strongly recommended to rely on the automatic sizing |
7428 | and rebuilding behavior provided by the |
7429 | QRhiRenderBuffer:UsedWithSwapChainOnly flag. Avoid querying the surface |
7430 | size via this function just to get a size that can be passed to |
7431 | QRhiRenderBuffer::setPixelSize() as that would suffer from the lack of |
7432 | atomicity as described above. |
7433 | |
7434 | \sa currentPixelSize() |
7435 | */ |
7436 | |
7437 | /*! |
7438 | \fn virtual bool QRhiSwapChain::isFormatSupported(Format f) = 0 |
7439 | |
7440 | \return true if the given swapchain format \a f is supported. SDR is always |
7441 | supported. |
7442 | |
7443 | \note Can be called independently of createOrResize(), but window() must |
7444 | already be set. Calling without the window set may lead to unexpected |
7445 | results depending on the backend and platform (most likely false for any |
7446 | HDR format), because HDR format support is usually tied to the output |
7447 | (screen) to which the swapchain's associated window belongs at any given |
7448 | time. If the result is true for a HDR format, then creating the swapchain |
7449 | with that format is expected to succeed as long as the window is not moved |
7450 | to another screen in the meantime. |
7451 | |
7452 | The main use of this function is to call it before the first |
7453 | createOrResize() after the window is already set. This allow the QRhi |
7454 | backends to perform platform or windowing system specific queries to |
7455 | determine if the window (and the screen it is on) is capable of true HDR |
7456 | output with the specified format. |
7457 | |
7458 | When the format is reported as supported, call setFormat() to set the |
7459 | requested format and call createOrResize(). Be aware of the consequences |
7460 | however: successfully requesting a HDR format will involve having to deal |
7461 | with a different color space, possibly doing white level correction for |
7462 | non-HDR-aware content, adjusting tonemapping methods, adjusting offscreen |
7463 | render target settings, etc. |
7464 | |
7465 | \sa setFormat() |
7466 | */ |
7467 | |
7468 | /*! |
7469 | \fn virtual QRhiCommandBuffer *QRhiSwapChain::currentFrameCommandBuffer() = 0 |
7470 | |
7471 | \return a command buffer on which rendering commands and resource updates |
7472 | can be recorded within a \l{QRhi::beginFrame()}{beginFrame} - |
7473 | \l{QRhi::endFrame()}{endFrame} block, assuming beginFrame() was called with |
7474 | this swapchain. |
7475 | |
7476 | \note The returned object is valid also after endFrame(), up until the next |
7477 | beginFrame(), but the returned command buffer should not be used to record |
7478 | any commands then. Rather, it can be used to query data collected during |
7479 | the frame (or previous frames), for example by calling |
7480 | \l{QRhiCommandBuffer::lastCompletedGpuTime()}{lastCompletedGpuTime()}. |
7481 | |
7482 | \note The value must not be cached and reused between frames. The caller |
7483 | should not hold on to the returned object once |
7484 | \l{QRhi::beginFrame()}{beginFrame()} is called again. Instead, the command |
7485 | buffer object should be queried again by calling this function. |
7486 | */ |
7487 | |
7488 | /*! |
7489 | \fn virtual QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget() = 0 |
7490 | |
7491 | \return a render target that can used with beginPass() in order to render |
7492 | the swapchain's current backbuffer. Only valid within a |
7493 | QRhi::beginFrame() - QRhi::endFrame() block where beginFrame() was called |
7494 | with this swapchain. |
7495 | |
7496 | \note the value must not be cached and reused between frames |
7497 | */ |
7498 | |
7499 | /*! |
7500 | \enum QRhiSwapChain::StereoTargetBuffer |
7501 | Selects the backbuffer to use with a stereoscopic swapchain. |
7502 | |
7503 | \value LeftBuffer |
7504 | \value RightBuffer |
7505 | */ |
7506 | |
7507 | /*! |
7508 | \return a render target that can be used with beginPass() in order to |
7509 | render to the swapchain's left or right backbuffer. This overload should be |
7510 | used only with stereoscopic rendering, that is, when the associated QWindow |
7511 | is backed by two color buffers, one for each eye, instead of just one. |
7512 | |
7513 | When stereoscopic rendering is not supported, the return value will be |
7514 | the default target. It is supported by all hardware backends except for Metal, in |
7515 | combination with \l QSurfaceFormat::StereoBuffers, assuming it is supported |
7516 | by the graphics and display driver stack at run time. Metal and Null backends |
7517 | are going to return the default render target from this overload. |
7518 | |
7519 | \note the value must not be cached and reused between frames |
7520 | */ |
7521 | QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer) |
7522 | { |
7523 | Q_UNUSED(targetBuffer); |
7524 | return currentFrameRenderTarget(); |
7525 | } |
7526 | |
7527 | /*! |
7528 | \fn virtual bool QRhiSwapChain::createOrResize() = 0 |
7529 | |
7530 | Creates the swapchain if not already done and resizes the swapchain buffers |
7531 | to match the current size of the targeted surface. Call this whenever the |
7532 | size of the target surface is different than before. |
7533 | |
7534 | \note call destroy() only when the swapchain needs to be released |
7535 | completely, typically upon |
7536 | QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed. To perform resizing, just |
7537 | call createOrResize(). |
7538 | |
7539 | \return \c true when successful, \c false when a graphics operation failed. |
7540 | Regardless of the return value, calling destroy() is always safe. |
7541 | */ |
7542 | |
7543 | /*! |
7544 | \fn QWindow *QRhiSwapChain::window() const |
7545 | \return the currently set window. |
7546 | */ |
7547 | |
7548 | /*! |
7549 | \fn void QRhiSwapChain::setWindow(QWindow *window) |
7550 | Sets the \a window. |
7551 | */ |
7552 | |
7553 | /*! |
7554 | \fn QRhiSwapChainProxyData QRhiSwapChain::proxyData() const |
7555 | \return the currently set proxy data. |
7556 | */ |
7557 | |
7558 | /*! |
7559 | \fn void QRhiSwapChain::setProxyData(const QRhiSwapChainProxyData &d) |
7560 | Sets the proxy data \a d. |
7561 | |
7562 | \sa QRhi::updateSwapChainProxyData() |
7563 | */ |
7564 | |
7565 | /*! |
7566 | \fn QRhiSwapChain::Flags QRhiSwapChain::flags() const |
7567 | \return the currently set flags. |
7568 | */ |
7569 | |
7570 | /*! |
7571 | \fn void QRhiSwapChain::setFlags(Flags f) |
7572 | Sets the flags \a f. |
7573 | */ |
7574 | |
7575 | /*! |
7576 | \fn QRhiSwapChain::Format QRhiSwapChain::format() const |
7577 | \return the currently set format. |
7578 | */ |
7579 | |
7580 | /*! |
7581 | \fn void QRhiSwapChain::setFormat(Format f) |
7582 | Sets the format \a f. |
7583 | |
7584 | Avoid setting formats that are reported as unsupported from |
7585 | isFormatSupported(). Note that support for a given format may depend on the |
7586 | screen the swapchain's associated window is opened on. On some platforms, |
7587 | such as Windows and macOS, for HDR output to work it is necessary to have |
7588 | HDR output enabled in the display settings. |
7589 | |
7590 | See isFormatSupported(), \l QRhiSwapChainHdrInfo, and \l Format for more |
7591 | information on high dynamic range output. |
7592 | */ |
7593 | |
7594 | /*! |
7595 | \fn QRhiRenderBuffer *QRhiSwapChain::depthStencil() const |
7596 | \return the currently associated renderbuffer for depth-stencil. |
7597 | */ |
7598 | |
7599 | /*! |
7600 | \fn void QRhiSwapChain::setDepthStencil(QRhiRenderBuffer *ds) |
7601 | Sets the renderbuffer \a ds for use as a depth-stencil buffer. |
7602 | */ |
7603 | |
7604 | /*! |
7605 | \fn int QRhiSwapChain::sampleCount() const |
7606 | \return the currently set sample count. 1 means no multisample antialiasing. |
7607 | */ |
7608 | |
7609 | /*! |
7610 | \fn void QRhiSwapChain::setSampleCount(int samples) |
7611 | |
7612 | Sets the sample count. Common values for \a samples are 1 (no MSAA), 4 (4x |
7613 | MSAA), or 8 (8x MSAA). |
7614 | |
7615 | \sa QRhi::supportedSampleCounts() |
7616 | */ |
7617 | |
7618 | /*! |
7619 | \fn QRhiRenderPassDescriptor *QRhiSwapChain::renderPassDescriptor() const |
7620 | \return the currently associated QRhiRenderPassDescriptor object. |
7621 | */ |
7622 | |
7623 | /*! |
7624 | \fn void QRhiSwapChain::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) |
7625 | Associates with the QRhiRenderPassDescriptor \a desc. |
7626 | */ |
7627 | |
7628 | /*! |
7629 | \fn virtual QRhiRenderPassDescriptor *QRhiSwapChain::newCompatibleRenderPassDescriptor() = 0; |
7630 | |
7631 | \return a new QRhiRenderPassDescriptor that is compatible with this swapchain. |
7632 | |
7633 | The returned value is used in two ways: it can be passed to |
7634 | setRenderPassDescriptor() and |
7635 | QRhiGraphicsPipeline::setRenderPassDescriptor(). A render pass descriptor |
7636 | describes the attachments (color, depth/stencil) and the load/store |
7637 | behavior that can be affected by flags(). A QRhiGraphicsPipeline can only |
7638 | be used in combination with a swapchain that has a |
7639 | \l{QRhiRenderPassDescriptor::isCompatible()}{compatible} |
7640 | QRhiRenderPassDescriptor set. |
7641 | |
7642 | \sa createOrResize() |
7643 | */ |
7644 | |
7645 | /*! |
7646 | \struct QRhiSwapChainHdrInfo |
7647 | \inmodule QtGuiPrivate |
7648 | \inheaderfile rhi/qrhi.h |
7649 | \since 6.6 |
7650 | |
7651 | \brief Describes the high dynamic range related information of the |
7652 | swapchain's associated output. |
7653 | |
7654 | To perform HDR-compatible tonemapping, where the target range is not [0,1], |
7655 | one often needs to know the maximum luminance of the display the |
7656 | swapchain's window is associated with. While this is often made |
7657 | user-configurable (think brightness, gamma and similar settings in games), |
7658 | it can be highly useful to set defaults based on the values reported by the |
7659 | display itself, thus providing a decent starting point. |
7660 | |
7661 | There are some problems however: the information is exposed in different |
7662 | forms on different platforms, whereas with cross-platform graphics APIs |
7663 | there is often no associated solution at all, because managing such |
7664 | information is not in the scope of the API (and may rather be retrievable |
7665 | via other platform-specific means, if any). |
7666 | |
7667 | With Metal on macOS/iOS, there is no luminance values exposed in the |
7668 | platform APIs. Instead, the maximum color component value, that would be |
7669 | 1.0 in a non-HDR setup, is provided. The \c limitsType field indicates what |
7670 | kind of information is available. It is then up to the clients of QRhi to |
7671 | access the correct data from the \c limits union and use it as they see |
7672 | fit. |
7673 | |
7674 | With an API like Vulkan, where there is no way to get such information, the |
7675 | values are always the built-in defaults. |
7676 | |
7677 | Therefore, the struct returned from QRhiSwapChain::hdrInfo() contains |
7678 | either some hard-coded defaults or real values received from an API such as |
7679 | DXGI (IDXGIOutput6) or Cocoa (NSScreen). When no platform queries are |
7680 | available (or needs using platform facilities out of scope for QRhi), the |
7681 | hard-coded defaults are a maximum luminance of 1000 nits and an SDR white |
7682 | level of 200. |
7683 | |
7684 | The struct also exposes the presumed luminance behavior of the platform and |
7685 | its compositor, to indicate what a color component value of 1.0 is treated |
7686 | as in a HDR color buffer. In some cases it will be necessary to perform |
7687 | color correction of non-HDR content composited with HDR content. To enable |
7688 | this, the SDR white level is queried from the system on some platforms |
7689 | (Windows) and exposed here. |
7690 | |
7691 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
7692 | for details. |
7693 | |
7694 | \sa QRhiSwapChain::hdrInfo() |
7695 | */ |
7696 | |
7697 | /*! |
7698 | \enum QRhiSwapChainHdrInfo::LimitsType |
7699 | |
7700 | \value LuminanceInNits Indicates that the \l limits union has its |
7701 | \c luminanceInNits struct set |
7702 | |
7703 | \value ColorComponentValue Indicates that the \l limits union has its |
7704 | \c colorComponentValue struct set |
7705 | */ |
7706 | |
7707 | /*! |
7708 | \enum QRhiSwapChainHdrInfo::LuminanceBehavior |
7709 | |
7710 | \value SceneReferred Indicates that the color value of 1.0 is interpreted |
7711 | as 80 nits. This is the behavior of HDR-enabled windows with the Windows |
7712 | compositor. See |
7713 | \l{https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range}{this |
7714 | page} for more information on HDR on Windows. |
7715 | |
7716 | \value DisplayReferred Indicates that the color value of 1.0 is interpreted |
7717 | as the value of the SDR white. (which can be e.g. 200 nits, but will vary |
7718 | depending on screen brightness) This is the behavior of HDR-enabled windows |
7719 | on Apple platforms. See |
7720 | \l{https://developer.apple.com/documentation/metal/hdr_content/displaying_hdr_content_in_a_metal_layer}{this |
7721 | page} for more information on Apple's EDR system. |
7722 | */ |
7723 | |
7724 | /*! |
7725 | \variable QRhiSwapChainHdrInfo::limitsType |
7726 | |
7727 | With Metal on macOS/iOS, there is no luminance values exposed in the |
7728 | platform APIs. Instead, the maximum color component value, that would be |
7729 | 1.0 in a non-HDR setup, is provided. This value indicates what kind of |
7730 | information is available in \l limits. |
7731 | |
7732 | \sa QRhiSwapChain::hdrInfo() |
7733 | */ |
7734 | |
7735 | /*! |
7736 | \variable QRhiSwapChainHdrInfo::limits |
7737 | |
7738 | Contains the actual values queried from the graphics API or the platform. |
7739 | The type of data is indicated by \l limitsType. This is therefore a union. |
7740 | There are currently two options: |
7741 | |
7742 | Luminance values in nits: |
7743 | |
7744 | \code |
7745 | struct { |
7746 | float minLuminance; |
7747 | float maxLuminance; |
7748 | } luminanceInNits; |
7749 | \endcode |
7750 | |
7751 | On Windows the minimum and maximum luminance depends on the screen |
7752 | brightness. While not relevant for desktops, on laptops the screen |
7753 | brightness may change at any time. Increasing brightness implies decreased |
7754 | maximum luminance. In addition, the results may also be dependent on the |
7755 | HDR Content Brightness set in Windows Settings' System/Display/HDR view, |
7756 | if there is such a setting. |
7757 | |
7758 | Note however that the changes made to the laptop screen's brightness or in |
7759 | the system settings while the application is running are not necessarily |
7760 | reflected in the returned values, meaning calling hdrInfo() again may still |
7761 | return the same luminance range as before for the rest of the process' |
7762 | lifetime. The exact behavior is up to DXGI and Qt has no control over it. |
7763 | |
7764 | \note The Windows compositor works in scene-referred mode for HDR content. |
7765 | A color component value of 1.0 corresponds to a luminance of 80 nits. When |
7766 | rendering non-HDR content (e.g. 2D UI elements), the correction of the |
7767 | white level is often necessary. (e.g., outputting the fragment color (1, 1, |
7768 | 1) will likely lead to showing a shade of white that is too dim on-screen) |
7769 | See \l sdrWhiteLevel. |
7770 | |
7771 | For macOS/iOS, the current maximum and potential maximum color |
7772 | component values are provided: |
7773 | |
7774 | \code |
7775 | struct { |
7776 | float maxColorComponentValue; |
7777 | float maxPotentialColorComponentValue; |
7778 | } colorComponentValue; |
7779 | \endcode |
7780 | |
7781 | The value may depend on the screen brightness, which on laptops means that |
7782 | the result may change in the next call to hdrInfo() if the brightness was |
7783 | changed in the meantime. The maximum screen brightness implies a maximum |
7784 | color value of 1.0. |
7785 | |
7786 | \note Apple's EDR is display-referred. 1.0 corresponds to a luminance level |
7787 | of SDR white (e.g. 200 nits), the value of which varies based on the screen |
7788 | brightness and possibly other settings. The exact luminance value for that, |
7789 | or the maximum luminance of the display, are not exposed to the |
7790 | applications. |
7791 | |
7792 | \note It has been observed that the color component values are not set to |
7793 | the correct larger-than-1 value right away on startup on some macOS |
7794 | systems, but the values tend to change during or after the first frame. |
7795 | |
7796 | \sa QRhiSwapChain::hdrInfo() |
7797 | */ |
7798 | |
7799 | /*! |
7800 | \variable QRhiSwapChainHdrInfo::luminanceBehavior |
7801 | |
7802 | Describes the platform's presumed behavior with regards to color values. |
7803 | |
7804 | \sa sdrWhiteLevel |
7805 | */ |
7806 | |
7807 | /*! |
7808 | \variable QRhiSwapChainHdrInfo::sdrWhiteLevel |
7809 | |
7810 | On Windows this is the dynamic SDR white level in nits. The value is |
7811 | dependent on the screen brightness (on laptops), and the SDR or HDR Content |
7812 | Brightness settings in the Windows settings' System/Display/HDR view. |
7813 | |
7814 | To perform white level correction for non-HDR (SDR) content, such as 2D UI |
7815 | elemenents, multiply the final color with sdrWhiteLevel / 80.0 whenever |
7816 | \l luminanceBehavior is SceneReferred. (assuming Windows and a linear |
7817 | extended sRGB (scRGB) color space) |
7818 | |
7819 | On other platforms the value is always a pre-defined value, 200. This may |
7820 | not match the system's actual SDR white level, but the value of this |
7821 | variable is not relevant in practice when the \l luminanceBehavior is |
7822 | DisplayReferred, because then the color component value of 1.0 refers to |
7823 | the SDR white by default. |
7824 | |
7825 | \sa luminanceBehavior |
7826 | */ |
7827 | |
7828 | /*! |
7829 | \return the HDR information for the associated display. |
7830 | |
7831 | Do not assume that this is a cheap operation. Depending on the platform, |
7832 | this function makes various platform queries which may have a performance |
7833 | impact. |
7834 | |
7835 | \note Can be called before createOrResize() as long as the window is |
7836 | \l{setWindow()}{set}. |
7837 | |
7838 | \note What happens when moving a window with an initialized swapchain |
7839 | between displays (HDR to HDR with different characteristics, HDR to SDR, |
7840 | etc.) is not currently well-defined and depends heavily on the windowing |
7841 | system and compositor, with potentially varying behavior between platforms. |
7842 | Currently QRhi only guarantees that hdrInfo() returns valid data, if |
7843 | available, for the display to which the swapchain's associated window |
7844 | belonged at the time of createOrResize(). |
7845 | |
7846 | \sa QRhiSwapChainHdrInfo |
7847 | */ |
7848 | QRhiSwapChainHdrInfo QRhiSwapChain::hdrInfo() |
7849 | { |
7850 | QRhiSwapChainHdrInfo info; |
7851 | info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits; |
7852 | info.limits.luminanceInNits.minLuminance = 0.0f; |
7853 | info.limits.luminanceInNits.maxLuminance = 1000.0f; |
7854 | info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred; |
7855 | info.sdrWhiteLevel = 200.0f; |
7856 | return info; |
7857 | } |
7858 | |
7859 | #ifndef QT_NO_DEBUG_STREAM |
7860 | QDebug operator<<(QDebug dbg, const QRhiSwapChainHdrInfo &info) |
7861 | { |
7862 | QDebugStateSaver saver(dbg); |
7863 | dbg.nospace() << "QRhiSwapChainHdrInfo("; |
7864 | switch (info.limitsType) { |
7865 | case QRhiSwapChainHdrInfo::LuminanceInNits: |
7866 | dbg.nospace() << " minLuminance="<< info.limits.luminanceInNits.minLuminance |
7867 | << " maxLuminance="<< info.limits.luminanceInNits.maxLuminance; |
7868 | break; |
7869 | case QRhiSwapChainHdrInfo::ColorComponentValue: |
7870 | dbg.nospace() << " maxColorComponentValue="<< info.limits.colorComponentValue.maxColorComponentValue; |
7871 | dbg.nospace() << " maxPotentialColorComponentValue="<< info.limits.colorComponentValue.maxPotentialColorComponentValue; |
7872 | break; |
7873 | } |
7874 | switch (info.luminanceBehavior) { |
7875 | case QRhiSwapChainHdrInfo::SceneReferred: |
7876 | dbg.nospace() << " scene-referred, SDR white level="<< info.sdrWhiteLevel; |
7877 | break; |
7878 | case QRhiSwapChainHdrInfo::DisplayReferred: |
7879 | dbg.nospace() << " display-referred"; |
7880 | break; |
7881 | } |
7882 | dbg.nospace() << ')'; |
7883 | return dbg; |
7884 | } |
7885 | #endif |
7886 | |
7887 | /*! |
7888 | \class QRhiComputePipeline |
7889 | \inmodule QtGuiPrivate |
7890 | \inheaderfile rhi/qrhi.h |
7891 | \since 6.6 |
7892 | \brief Compute pipeline state resource. |
7893 | |
7894 | \note Setting the shader resource bindings is mandatory. The referenced |
7895 | QRhiShaderResourceBindings must already have created() called on it by the |
7896 | time create() is called. |
7897 | |
7898 | \note Setting the shader is mandatory. |
7899 | |
7900 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
7901 | for details. |
7902 | */ |
7903 | |
7904 | /*! |
7905 | \enum QRhiComputePipeline::Flag |
7906 | |
7907 | Flag values for describing pipeline options. |
7908 | |
7909 | \value CompileShadersWithDebugInfo Requests compiling shaders with debug |
7910 | information enabled, when applicable. See |
7911 | QRhiGraphicsPipeline::CompileShadersWithDebugInfo for more information. |
7912 | */ |
7913 | |
7914 | /*! |
7915 | \return the resource type. |
7916 | */ |
7917 | QRhiResource::Type QRhiComputePipeline::resourceType() const |
7918 | { |
7919 | return ComputePipeline; |
7920 | } |
7921 | |
7922 | /*! |
7923 | \internal |
7924 | */ |
7925 | QRhiComputePipeline::QRhiComputePipeline(QRhiImplementation *rhi) |
7926 | : QRhiResource(rhi) |
7927 | { |
7928 | } |
7929 | |
7930 | /*! |
7931 | \fn QRhiComputePipeline::Flags QRhiComputePipeline::flags() const |
7932 | \return the currently set flags. |
7933 | */ |
7934 | |
7935 | /*! |
7936 | \fn void QRhiComputePipeline::setFlags(Flags f) |
7937 | Sets the flags \a f. |
7938 | */ |
7939 | |
7940 | /*! |
7941 | \fn QRhiShaderStage QRhiComputePipeline::shaderStage() const |
7942 | \return the currently set shader. |
7943 | */ |
7944 | |
7945 | /*! |
7946 | \fn void QRhiComputePipeline::setShaderStage(const QRhiShaderStage &stage) |
7947 | |
7948 | Sets the shader to use. \a stage can only refer to the |
7949 | \l{QRhiShaderStage::Compute}{compute stage}. |
7950 | */ |
7951 | |
7952 | /*! |
7953 | \fn QRhiShaderResourceBindings *QRhiComputePipeline::shaderResourceBindings() const |
7954 | \return the currently associated QRhiShaderResourceBindings object. |
7955 | */ |
7956 | |
7957 | /*! |
7958 | \fn void QRhiComputePipeline::setShaderResourceBindings(QRhiShaderResourceBindings *srb) |
7959 | |
7960 | Associates with \a srb describing the resource binding layout and the |
7961 | resources (QRhiBuffer, QRhiTexture) themselves. The latter is optional. As |
7962 | with graphics pipelines, the \a srb passed in here can leave the actual |
7963 | buffer or texture objects unspecified (\nullptr) as long as there is |
7964 | another, |
7965 | \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible} |
7966 | QRhiShaderResourceBindings bound via |
7967 | \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} before |
7968 | recording the dispatch call. |
7969 | */ |
7970 | |
7971 | /*! |
7972 | \class QRhiCommandBuffer |
7973 | \inmodule QtGuiPrivate |
7974 | \inheaderfile rhi/qrhi.h |
7975 | \since 6.6 |
7976 | \brief Command buffer resource. |
7977 | |
7978 | Not creatable by applications at the moment. The only ways to obtain a |
7979 | valid QRhiCommandBuffer are to get it from the targeted swapchain via |
7980 | QRhiSwapChain::currentFrameCommandBuffer(), or, in case of rendering |
7981 | completely offscreen, initializing one via QRhi::beginOffscreenFrame(). |
7982 | |
7983 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
7984 | for details. |
7985 | */ |
7986 | |
7987 | /*! |
7988 | \enum QRhiCommandBuffer::IndexFormat |
7989 | Specifies the index data type |
7990 | |
7991 | \value IndexUInt16 Unsigned 16-bit (quint16) |
7992 | \value IndexUInt32 Unsigned 32-bit (quint32) |
7993 | */ |
7994 | |
7995 | /*! |
7996 | \enum QRhiCommandBuffer::BeginPassFlag |
7997 | Flag values for QRhi::beginPass() |
7998 | |
7999 | \value ExternalContent Specifies that there will be a call to |
8000 | QRhiCommandBuffer::beginExternal() in this pass. Some backends, Vulkan in |
8001 | particular, will fail if this flag is not set and beginExternal() is still |
8002 | called. |
8003 | |
8004 | \value DoNotTrackResourcesForCompute Specifies that there is no need to |
8005 | track resources used in this pass if the only purpose of such tracking is |
8006 | to generate barriers for compute. Implies that there are no compute passes |
8007 | in the frame. This is an optimization hint that may be taken into account |
8008 | by certain backends, OpenGL in particular, allowing them to skip certain |
8009 | operations. When this flag is set for a render pass in a frame, calling |
8010 | \l{QRhiCommandBuffer::beginComputePass()}{beginComputePass()} in that frame |
8011 | may lead to unexpected behavior, depending on the resource dependencies |
8012 | between the render and compute passes. |
8013 | */ |
8014 | |
8015 | /*! |
8016 | \typedef QRhiCommandBuffer::DynamicOffset |
8017 | |
8018 | Synonym for QPair<int, quint32>. The first entry is the binding, the second |
8019 | is the offset in the buffer. |
8020 | */ |
8021 | |
8022 | /*! |
8023 | \typedef QRhiCommandBuffer::VertexInput |
8024 | |
8025 | Synonym for QPair<QRhiBuffer *, quint32>. The second entry is an offset in |
8026 | the buffer specified by the first. |
8027 | */ |
8028 | |
8029 | /*! |
8030 | \internal |
8031 | */ |
8032 | QRhiCommandBuffer::QRhiCommandBuffer(QRhiImplementation *rhi) |
8033 | : QRhiResource(rhi) |
8034 | { |
8035 | } |
8036 | |
8037 | /*! |
8038 | \return the resource type. |
8039 | */ |
8040 | QRhiResource::Type QRhiCommandBuffer::resourceType() const |
8041 | { |
8042 | return CommandBuffer; |
8043 | } |
8044 | |
8045 | static const char *resourceTypeStr(const QRhiResource *res) |
8046 | { |
8047 | switch (res->resourceType()) { |
8048 | case QRhiResource::Buffer: |
8049 | return "Buffer"; |
8050 | case QRhiResource::Texture: |
8051 | return "Texture"; |
8052 | case QRhiResource::Sampler: |
8053 | return "Sampler"; |
8054 | case QRhiResource::RenderBuffer: |
8055 | return "RenderBuffer"; |
8056 | case QRhiResource::RenderPassDescriptor: |
8057 | return "RenderPassDescriptor"; |
8058 | case QRhiResource::SwapChainRenderTarget: |
8059 | return "SwapChainRenderTarget"; |
8060 | case QRhiResource::TextureRenderTarget: |
8061 | return "TextureRenderTarget"; |
8062 | case QRhiResource::ShaderResourceBindings: |
8063 | return "ShaderResourceBindings"; |
8064 | case QRhiResource::GraphicsPipeline: |
8065 | return "GraphicsPipeline"; |
8066 | case QRhiResource::SwapChain: |
8067 | return "SwapChain"; |
8068 | case QRhiResource::ComputePipeline: |
8069 | return "ComputePipeline"; |
8070 | case QRhiResource::CommandBuffer: |
8071 | return "CommandBuffer"; |
8072 | } |
8073 | |
8074 | Q_UNREACHABLE_RETURN(""); |
8075 | } |
8076 | |
8077 | QRhiImplementation::~QRhiImplementation() |
8078 | { |
8079 | qDeleteAll(c: resUpdPool); |
8080 | |
8081 | // Be nice and show something about leaked stuff. Though we may not get |
8082 | // this far with some backends where the allocator or the api may check |
8083 | // and freak out for unfreed graphics objects in the derived dtor already. |
8084 | #ifndef QT_NO_DEBUG |
8085 | // debug builds: just do it always |
8086 | static bool leakCheck = true; |
8087 | #else |
8088 | // release builds: opt-in |
8089 | static bool leakCheck = qEnvironmentVariableIntValue("QT_RHI_LEAK_CHECK"); |
8090 | #endif |
8091 | if (!resources.isEmpty()) { |
8092 | if (leakCheck) { |
8093 | qWarning(msg: "QRhi %p going down with %d unreleased resources that own native graphics objects. This is not nice.", |
8094 | q, int(resources.size())); |
8095 | } |
8096 | for (auto it = resources.cbegin(), end = resources.cend(); it != end; ++it) { |
8097 | QRhiResource *res = it.key(); |
8098 | const bool ownsNativeResources = it.value(); |
8099 | if (leakCheck && ownsNativeResources) |
8100 | qWarning(msg: " %s resource %p (%s)", resourceTypeStr(res), res, res->m_objectName.constData()); |
8101 | |
8102 | // Null out the resource's rhi pointer. This is why it makes sense to do null |
8103 | // checks in the destroy() implementations of the various resource types. It |
8104 | // allows to survive in bad applications that somehow manage to destroy a |
8105 | // resource of a QRhi after the QRhi itself. |
8106 | res->m_rhi = nullptr; |
8107 | } |
8108 | } |
8109 | } |
8110 | |
8111 | bool QRhiImplementation::isCompressedFormat(QRhiTexture::Format format) const |
8112 | { |
8113 | return (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) |
8114 | || (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) |
8115 | || (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12); |
8116 | } |
8117 | |
8118 | void QRhiImplementation::compressedFormatInfo(QRhiTexture::Format format, const QSize &size, |
8119 | quint32 *bpl, quint32 *byteSize, |
8120 | QSize *blockDim) const |
8121 | { |
8122 | int xdim = 4; |
8123 | int ydim = 4; |
8124 | quint32 blockSize = 0; |
8125 | |
8126 | switch (format) { |
8127 | case QRhiTexture::BC1: |
8128 | blockSize = 8; |
8129 | break; |
8130 | case QRhiTexture::BC2: |
8131 | blockSize = 16; |
8132 | break; |
8133 | case QRhiTexture::BC3: |
8134 | blockSize = 16; |
8135 | break; |
8136 | case QRhiTexture::BC4: |
8137 | blockSize = 8; |
8138 | break; |
8139 | case QRhiTexture::BC5: |
8140 | blockSize = 16; |
8141 | break; |
8142 | case QRhiTexture::BC6H: |
8143 | blockSize = 16; |
8144 | break; |
8145 | case QRhiTexture::BC7: |
8146 | blockSize = 16; |
8147 | break; |
8148 | |
8149 | case QRhiTexture::ETC2_RGB8: |
8150 | blockSize = 8; |
8151 | break; |
8152 | case QRhiTexture::ETC2_RGB8A1: |
8153 | blockSize = 8; |
8154 | break; |
8155 | case QRhiTexture::ETC2_RGBA8: |
8156 | blockSize = 16; |
8157 | break; |
8158 | |
8159 | case QRhiTexture::ASTC_4x4: |
8160 | blockSize = 16; |
8161 | break; |
8162 | case QRhiTexture::ASTC_5x4: |
8163 | blockSize = 16; |
8164 | xdim = 5; |
8165 | break; |
8166 | case QRhiTexture::ASTC_5x5: |
8167 | blockSize = 16; |
8168 | xdim = ydim = 5; |
8169 | break; |
8170 | case QRhiTexture::ASTC_6x5: |
8171 | blockSize = 16; |
8172 | xdim = 6; |
8173 | ydim = 5; |
8174 | break; |
8175 | case QRhiTexture::ASTC_6x6: |
8176 | blockSize = 16; |
8177 | xdim = ydim = 6; |
8178 | break; |
8179 | case QRhiTexture::ASTC_8x5: |
8180 | blockSize = 16; |
8181 | xdim = 8; |
8182 | ydim = 5; |
8183 | break; |
8184 | case QRhiTexture::ASTC_8x6: |
8185 | blockSize = 16; |
8186 | xdim = 8; |
8187 | ydim = 6; |
8188 | break; |
8189 | case QRhiTexture::ASTC_8x8: |
8190 | blockSize = 16; |
8191 | xdim = ydim = 8; |
8192 | break; |
8193 | case QRhiTexture::ASTC_10x5: |
8194 | blockSize = 16; |
8195 | xdim = 10; |
8196 | ydim = 5; |
8197 | break; |
8198 | case QRhiTexture::ASTC_10x6: |
8199 | blockSize = 16; |
8200 | xdim = 10; |
8201 | ydim = 6; |
8202 | break; |
8203 | case QRhiTexture::ASTC_10x8: |
8204 | blockSize = 16; |
8205 | xdim = 10; |
8206 | ydim = 8; |
8207 | break; |
8208 | case QRhiTexture::ASTC_10x10: |
8209 | blockSize = 16; |
8210 | xdim = ydim = 10; |
8211 | break; |
8212 | case QRhiTexture::ASTC_12x10: |
8213 | blockSize = 16; |
8214 | xdim = 12; |
8215 | ydim = 10; |
8216 | break; |
8217 | case QRhiTexture::ASTC_12x12: |
8218 | blockSize = 16; |
8219 | xdim = ydim = 12; |
8220 | break; |
8221 | |
8222 | default: |
8223 | Q_UNREACHABLE(); |
8224 | break; |
8225 | } |
8226 | |
8227 | const quint32 wblocks = uint((size.width() + xdim - 1) / xdim); |
8228 | const quint32 hblocks = uint((size.height() + ydim - 1) / ydim); |
8229 | |
8230 | if (bpl) |
8231 | *bpl = wblocks * blockSize; |
8232 | if (byteSize) |
8233 | *byteSize = wblocks * hblocks * blockSize; |
8234 | if (blockDim) |
8235 | *blockDim = QSize(xdim, ydim); |
8236 | } |
8237 | |
8238 | void QRhiImplementation::textureFormatInfo(QRhiTexture::Format format, const QSize &size, |
8239 | quint32 *bpl, quint32 *byteSize, quint32 *bytesPerPixel) const |
8240 | { |
8241 | if (isCompressedFormat(format)) { |
8242 | compressedFormatInfo(format, size, bpl, byteSize, blockDim: nullptr); |
8243 | return; |
8244 | } |
8245 | |
8246 | quint32 bpc = 0; |
8247 | switch (format) { |
8248 | case QRhiTexture::RGBA8: |
8249 | bpc = 4; |
8250 | break; |
8251 | case QRhiTexture::BGRA8: |
8252 | bpc = 4; |
8253 | break; |
8254 | case QRhiTexture::R8: |
8255 | bpc = 1; |
8256 | break; |
8257 | case QRhiTexture::RG8: |
8258 | bpc = 2; |
8259 | break; |
8260 | case QRhiTexture::R16: |
8261 | bpc = 2; |
8262 | break; |
8263 | case QRhiTexture::RG16: |
8264 | bpc = 4; |
8265 | break; |
8266 | case QRhiTexture::RED_OR_ALPHA8: |
8267 | bpc = 1; |
8268 | break; |
8269 | |
8270 | case QRhiTexture::RGBA16F: |
8271 | bpc = 8; |
8272 | break; |
8273 | case QRhiTexture::RGBA32F: |
8274 | bpc = 16; |
8275 | break; |
8276 | case QRhiTexture::R16F: |
8277 | bpc = 2; |
8278 | break; |
8279 | case QRhiTexture::R32F: |
8280 | bpc = 4; |
8281 | break; |
8282 | |
8283 | case QRhiTexture::RGB10A2: |
8284 | bpc = 4; |
8285 | break; |
8286 | |
8287 | case QRhiTexture::D16: |
8288 | bpc = 2; |
8289 | break; |
8290 | case QRhiTexture::D24: |
8291 | case QRhiTexture::D24S8: |
8292 | case QRhiTexture::D32F: |
8293 | bpc = 4; |
8294 | break; |
8295 | |
8296 | default: |
8297 | Q_UNREACHABLE(); |
8298 | break; |
8299 | } |
8300 | |
8301 | if (bpl) |
8302 | *bpl = uint(size.width()) * bpc; |
8303 | if (byteSize) |
8304 | *byteSize = uint(size.width() * size.height()) * bpc; |
8305 | if (bytesPerPixel) |
8306 | *bytesPerPixel = bpc; |
8307 | } |
8308 | |
8309 | bool QRhiImplementation::isStencilSupportingFormat(QRhiTexture::Format format) const |
8310 | { |
8311 | switch (format) { |
8312 | case QRhiTexture::D24S8: |
8313 | return true; |
8314 | default: |
8315 | break; |
8316 | } |
8317 | return false; |
8318 | } |
8319 | |
8320 | bool QRhiImplementation::sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps) |
8321 | { |
8322 | if (ps->cbeginShaderStages() == ps->cendShaderStages()) { |
8323 | qWarning(msg: "Cannot build a graphics pipeline without any stages"); |
8324 | return false; |
8325 | } |
8326 | |
8327 | bool hasVertexStage = false; |
8328 | for (auto it = ps->cbeginShaderStages(), itEnd = ps->cendShaderStages(); it != itEnd; ++it) { |
8329 | if (!it->shader().isValid()) { |
8330 | qWarning(msg: "Empty shader passed to graphics pipeline"); |
8331 | return false; |
8332 | } |
8333 | if (it->type() == QRhiShaderStage::Vertex) |
8334 | hasVertexStage = true; |
8335 | } |
8336 | if (!hasVertexStage) { |
8337 | qWarning(msg: "Cannot build a graphics pipeline without a vertex stage"); |
8338 | return false; |
8339 | } |
8340 | |
8341 | if (!ps->renderPassDescriptor()) { |
8342 | qWarning(msg: "Cannot build a graphics pipeline without a QRhiRenderPassDescriptor"); |
8343 | return false; |
8344 | } |
8345 | |
8346 | if (!ps->shaderResourceBindings()) { |
8347 | qWarning(msg: "Cannot build a graphics pipeline without QRhiShaderResourceBindings"); |
8348 | return false; |
8349 | } |
8350 | |
8351 | return true; |
8352 | } |
8353 | |
8354 | bool QRhiImplementation::sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb) |
8355 | { |
8356 | #ifndef QT_NO_DEBUG |
8357 | bool bindingsOk = true; |
8358 | const int CHECKED_BINDINGS_COUNT = 64; |
8359 | bool bindingSeen[CHECKED_BINDINGS_COUNT] = {}; |
8360 | for (auto it = srb->cbeginBindings(), end = srb->cendBindings(); it != end; ++it) { |
8361 | const int binding = shaderResourceBindingData(binding: *it)->binding; |
8362 | if (binding >= CHECKED_BINDINGS_COUNT) |
8363 | continue; |
8364 | if (binding < 0) { |
8365 | qWarning(msg: "Invalid binding number %d", binding); |
8366 | bindingsOk = false; |
8367 | continue; |
8368 | } |
8369 | switch (shaderResourceBindingData(binding: *it)->type) { |
8370 | case QRhiShaderResourceBinding::UniformBuffer: |
8371 | if (!bindingSeen[binding]) { |
8372 | bindingSeen[binding] = true; |
8373 | } else { |
8374 | qWarning(msg: "Uniform buffer duplicates an existing binding number %d", binding); |
8375 | bindingsOk = false; |
8376 | } |
8377 | break; |
8378 | case QRhiShaderResourceBinding::SampledTexture: |
8379 | if (!bindingSeen[binding]) { |
8380 | bindingSeen[binding] = true; |
8381 | } else { |
8382 | qWarning(msg: "Combined image sampler duplicates an existing binding number %d", binding); |
8383 | bindingsOk = false; |
8384 | } |
8385 | break; |
8386 | case QRhiShaderResourceBinding::Texture: |
8387 | if (!bindingSeen[binding]) { |
8388 | bindingSeen[binding] = true; |
8389 | } else { |
8390 | qWarning(msg: "Texture duplicates an existing binding number %d", binding); |
8391 | bindingsOk = false; |
8392 | } |
8393 | break; |
8394 | case QRhiShaderResourceBinding::Sampler: |
8395 | if (!bindingSeen[binding]) { |
8396 | bindingSeen[binding] = true; |
8397 | } else { |
8398 | qWarning(msg: "Sampler duplicates an existing binding number %d", binding); |
8399 | bindingsOk = false; |
8400 | } |
8401 | break; |
8402 | case QRhiShaderResourceBinding::ImageLoad: |
8403 | case QRhiShaderResourceBinding::ImageStore: |
8404 | case QRhiShaderResourceBinding::ImageLoadStore: |
8405 | if (!bindingSeen[binding]) { |
8406 | bindingSeen[binding] = true; |
8407 | } else { |
8408 | qWarning(msg: "Image duplicates an existing binding number %d", binding); |
8409 | bindingsOk = false; |
8410 | } |
8411 | break; |
8412 | case QRhiShaderResourceBinding::BufferLoad: |
8413 | case QRhiShaderResourceBinding::BufferStore: |
8414 | case QRhiShaderResourceBinding::BufferLoadStore: |
8415 | if (!bindingSeen[binding]) { |
8416 | bindingSeen[binding] = true; |
8417 | } else { |
8418 | qWarning(msg: "Buffer duplicates an existing binding number %d", binding); |
8419 | bindingsOk = false; |
8420 | } |
8421 | break; |
8422 | default: |
8423 | qWarning(msg: "Unknown binding type %d", int(shaderResourceBindingData(binding: *it)->type)); |
8424 | bindingsOk = false; |
8425 | break; |
8426 | } |
8427 | } |
8428 | |
8429 | if (!bindingsOk) { |
8430 | qWarning() << *srb; |
8431 | return false; |
8432 | } |
8433 | #else |
8434 | Q_UNUSED(srb); |
8435 | #endif |
8436 | return true; |
8437 | } |
8438 | |
8439 | int QRhiImplementation::effectiveSampleCount(int sampleCount) const |
8440 | { |
8441 | // Stay compatible with QSurfaceFormat and friends where samples == 0 means the same as 1. |
8442 | const int s = qBound(min: 1, val: sampleCount, max: 64); |
8443 | const QList<int> supported = supportedSampleCounts(); |
8444 | int result = 1; |
8445 | |
8446 | // Stay compatible with Qt 5 in that requesting an unsupported sample count |
8447 | // is not an error (although we still do a categorized debug print about |
8448 | // this), and rather a supported value, preferably a close one, not just 1, |
8449 | // is used instead. This is actually deviating from Qt 5 as that performs a |
8450 | // clamping only and does not handle cases such as when sample count 2 is |
8451 | // not supported but 4 is. (OpenGL handles things like that gracefully, |
8452 | // other APIs may not, so improve this by picking the next largest, or in |
8453 | // absence of that, the largest value; this with the goal to not reduce |
8454 | // quality by rather picking a larger-than-requested value than a smaller one) |
8455 | |
8456 | for (int i = 0, ie = supported.count(); i != ie; ++i) { |
8457 | // assumes the 'supported' list is sorted |
8458 | if (supported[i] >= s) { |
8459 | result = supported[i]; |
8460 | break; |
8461 | } |
8462 | } |
8463 | |
8464 | if (result != s) { |
8465 | if (result == 1 && !supported.isEmpty()) |
8466 | result = supported.last(); |
8467 | qCDebug(QRHI_LOG_INFO, "Attempted to set unsupported sample count %d, using %d instead", |
8468 | sampleCount, result); |
8469 | } |
8470 | |
8471 | return result; |
8472 | } |
8473 | |
8474 | /*! |
8475 | \internal |
8476 | */ |
8477 | QRhi::QRhi() |
8478 | { |
8479 | } |
8480 | |
8481 | /*! |
8482 | Destructor. Destroys the backend and releases resources. |
8483 | */ |
8484 | QRhi::~QRhi() |
8485 | { |
8486 | if (!d) |
8487 | return; |
8488 | |
8489 | runCleanup(); |
8490 | |
8491 | qDeleteAll(c: d->pendingDeleteResources); |
8492 | d->pendingDeleteResources.clear(); |
8493 | |
8494 | d->destroy(); |
8495 | delete d; |
8496 | } |
8497 | |
8498 | bool QRhiImplementation::rubLogEnabled = false; |
8499 | |
8500 | void QRhiImplementation::prepareForCreate(QRhi *rhi, QRhi::Implementation impl, QRhi::Flags flags) |
8501 | { |
8502 | q = rhi; |
8503 | |
8504 | // Play nice with QSG_INFO since that is still the most commonly used |
8505 | // way to get graphics info printed from Qt Quick apps, and the Quick |
8506 | // scenegraph is our primary user. |
8507 | if (qEnvironmentVariableIsSet(varName: "QSG_INFO")) |
8508 | const_cast<QLoggingCategory &>(QRHI_LOG_INFO()).setEnabled(type: QtDebugMsg, enable: true); |
8509 | |
8510 | debugMarkers = flags.testFlag(flag: QRhi::EnableDebugMarkers); |
8511 | |
8512 | rubLogEnabled = QRHI_LOG_RUB().isDebugEnabled(); |
8513 | |
8514 | implType = impl; |
8515 | implThread = QThread::currentThread(); |
8516 | } |
8517 | |
8518 | /*! |
8519 | \return a new QRhi instance with a backend for the graphics API specified |
8520 | by \a impl with the specified \a flags. \return \c nullptr if the |
8521 | function fails. |
8522 | |
8523 | \a params must point to an instance of one of the backend-specific |
8524 | subclasses of QRhiInitParams, such as, QRhiVulkanInitParams, |
8525 | QRhiMetalInitParams, QRhiD3D11InitParams, QRhiD3D12InitParams, |
8526 | QRhiGles2InitParams. See these classes for examples on creating a QRhi. |
8527 | |
8528 | QRhi by design does not implement any fallback logic: if the specified API |
8529 | cannot be initialized, create() will fail, with warnings printed on the |
8530 | debug output by the backends. The clients of QRhi, for example Qt Quick, |
8531 | may however provide additional logic that allow falling back to an API |
8532 | different than what was requested, depending on the platform. If the |
8533 | intention is just to test if initialization would succeed when calling |
8534 | create() at later point, it is preferable to use probe() instead of |
8535 | create(), because with some backends probing can be implemented in a more |
8536 | lightweight manner as opposed to create(), which performs full |
8537 | initialization of the infrastructure and is wasteful if that QRhi instance |
8538 | is then thrown immediately away. |
8539 | |
8540 | \a importDevice allows using an already existing graphics device, without |
8541 | QRhi creating its own. When not null, this parameter must point to an |
8542 | instance of one of the subclasses of QRhiNativeHandles: |
8543 | QRhiVulkanNativeHandles, QRhiD3D11NativeHandles, QRhiD3D12NativeHandles, |
8544 | QRhiMetalNativeHandles, QRhiGles2NativeHandles. The exact details and |
8545 | semantics depend on the backand and the underlying graphics API. |
8546 | |
8547 | \sa probe() |
8548 | */ |
8549 | QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRhiNativeHandles *importDevice) |
8550 | { |
8551 | std::unique_ptr<QRhi> r(new QRhi); |
8552 | |
8553 | switch (impl) { |
8554 | case Null: |
8555 | r->d = new QRhiNull(static_cast<QRhiNullInitParams *>(params)); |
8556 | break; |
8557 | case Vulkan: |
8558 | #if QT_CONFIG(vulkan) |
8559 | r->d = new QRhiVulkan(static_cast<QRhiVulkanInitParams *>(params), |
8560 | static_cast<QRhiVulkanNativeHandles *>(importDevice)); |
8561 | break; |
8562 | #else |
8563 | Q_UNUSED(importDevice); |
8564 | qWarning("This build of Qt has no Vulkan support"); |
8565 | break; |
8566 | #endif |
8567 | case OpenGLES2: |
8568 | #ifndef QT_NO_OPENGL |
8569 | r->d = new QRhiGles2(static_cast<QRhiGles2InitParams *>(params), |
8570 | static_cast<QRhiGles2NativeHandles *>(importDevice)); |
8571 | break; |
8572 | #else |
8573 | qWarning("This build of Qt has no OpenGL support"); |
8574 | break; |
8575 | #endif |
8576 | case D3D11: |
8577 | #ifdef Q_OS_WIN |
8578 | r->d = new QRhiD3D11(static_cast<QRhiD3D11InitParams *>(params), |
8579 | static_cast<QRhiD3D11NativeHandles *>(importDevice)); |
8580 | break; |
8581 | #else |
8582 | qWarning(msg: "This platform has no Direct3D 11 support"); |
8583 | break; |
8584 | #endif |
8585 | case Metal: |
8586 | #if QT_CONFIG(metal) |
8587 | r->d = new QRhiMetal(static_cast<QRhiMetalInitParams *>(params), |
8588 | static_cast<QRhiMetalNativeHandles *>(importDevice)); |
8589 | break; |
8590 | #else |
8591 | qWarning(msg: "This platform has no Metal support"); |
8592 | break; |
8593 | #endif |
8594 | case D3D12: |
8595 | #ifdef Q_OS_WIN |
8596 | #ifdef QRHI_D3D12_AVAILABLE |
8597 | r->d = new QRhiD3D12(static_cast<QRhiD3D12InitParams *>(params), |
8598 | static_cast<QRhiD3D12NativeHandles *>(importDevice)); |
8599 | break; |
8600 | #else |
8601 | qWarning("Qt was built without Direct3D 12 support. " |
8602 | "This is likely due to having ancient SDK headers (such as d3d12.h) in the Qt build environment. " |
8603 | "Rebuild Qt with an SDK supporting D3D12 features introduced in Windows 10 version 1703, " |
8604 | "or use an MSVC build as those typically are built with more up-to-date SDKs."); |
8605 | break; |
8606 | #endif |
8607 | #else |
8608 | qWarning(msg: "This platform has no Direct3D 12 support"); |
8609 | break; |
8610 | #endif |
8611 | } |
8612 | |
8613 | if (r->d) { |
8614 | r->d->prepareForCreate(rhi: r.get(), impl, flags); |
8615 | if (r->d->create(flags)) |
8616 | return r.release(); |
8617 | } |
8618 | |
8619 | return nullptr; |
8620 | } |
8621 | |
8622 | /*! |
8623 | \return true if create() can be expected to succeed when called the given |
8624 | \a impl and \a params. |
8625 | |
8626 | For some backends this is equivalent to calling create(), checking its |
8627 | return value, and then destroying the resulting QRhi. |
8628 | |
8629 | For others, in particular with Metal, there may be a specific probing |
8630 | implementation, which allows testing in a more lightweight manner without |
8631 | polluting the debug output with warnings upon failures. |
8632 | |
8633 | \sa create() |
8634 | */ |
8635 | bool QRhi::probe(QRhi::Implementation impl, QRhiInitParams *params) |
8636 | { |
8637 | bool ok = false; |
8638 | |
8639 | // The only place currently where this makes sense is Metal, where the API |
8640 | // is simple enough so that a special probing function - doing nothing but |
8641 | // a MTLCreateSystemDefaultDevice - is reasonable. Elsewhere, just call |
8642 | // create() and then drop the result. |
8643 | |
8644 | if (impl == Metal) { |
8645 | #if QT_CONFIG(metal) |
8646 | ok = QRhiMetal::probe(static_cast<QRhiMetalInitParams *>(params)); |
8647 | #endif |
8648 | } else { |
8649 | QRhi *rhi = create(impl, params); |
8650 | ok = rhi != nullptr; |
8651 | delete rhi; |
8652 | } |
8653 | return ok; |
8654 | } |
8655 | |
8656 | /*! |
8657 | \struct QRhiSwapChainProxyData |
8658 | \inmodule QtGuiPrivate |
8659 | \inheaderfile rhi/qrhi.h |
8660 | \since 6.6 |
8661 | |
8662 | \brief Opaque data describing native objects needed to set up a swapchain. |
8663 | |
8664 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
8665 | for details. |
8666 | |
8667 | \sa QRhi::updateSwapChainProxyData() |
8668 | */ |
8669 | |
8670 | /*! |
8671 | Generates and returns a QRhiSwapChainProxyData struct containing opaque |
8672 | data specific to the backend and graphics API specified by \a impl. \a |
8673 | window is the QWindow a swapchain is targeting. |
8674 | |
8675 | The returned struct can be passed to QRhiSwapChain::setProxyData(). This |
8676 | makes sense in threaded rendering systems: this static function is expected |
8677 | to be called on the \b{main (gui) thread}, unlike all QRhi operations, then |
8678 | transferred to the thread working with the QRhi and QRhiSwapChain and passed |
8679 | on to the swapchain. This allows doing native platform queries that are |
8680 | only safe to be called on the main thread, for example to query the |
8681 | CAMetalLayer from a NSView, and then passing on the data to the |
8682 | QRhiSwapChain living on the rendering thread. With the Metal example, doing |
8683 | the view.layer access on a dedicated rendering thread causes a warning in |
8684 | the Xcode Thread Checker. With the data proxy mechanism, this is avoided. |
8685 | |
8686 | When threads are not involved, generating and passing on the |
8687 | QRhiSwapChainProxyData is not required: backends are guaranteed to be able |
8688 | to query whatever is needed on their own, and if everything lives on the |
8689 | main (gui) thread, that should be sufficient. |
8690 | |
8691 | \note \a impl should match what the QRhi is created with. For example, |
8692 | calling with QRhi::Metal on a non-Apple platform will not generate any |
8693 | useful data. |
8694 | */ |
8695 | QRhiSwapChainProxyData QRhi::updateSwapChainProxyData(QRhi::Implementation impl, QWindow *window) |
8696 | { |
8697 | #if QT_CONFIG(metal) |
8698 | if (impl == Metal) |
8699 | return QRhiMetal::updateSwapChainProxyData(window); |
8700 | #else |
8701 | Q_UNUSED(impl); |
8702 | Q_UNUSED(window); |
8703 | #endif |
8704 | return {}; |
8705 | } |
8706 | |
8707 | /*! |
8708 | \return the backend type for this QRhi. |
8709 | */ |
8710 | QRhi::Implementation QRhi::backend() const |
8711 | { |
8712 | return d->implType; |
8713 | } |
8714 | |
8715 | /*! |
8716 | \return a friendly name for the backend \a impl, usually the name of the 3D |
8717 | API in use. |
8718 | */ |
8719 | const char *QRhi::backendName(Implementation impl) |
8720 | { |
8721 | switch (impl) { |
8722 | case QRhi::Null: |
8723 | return "Null"; |
8724 | case QRhi::Vulkan: |
8725 | return "Vulkan"; |
8726 | case QRhi::OpenGLES2: |
8727 | return "OpenGL"; |
8728 | case QRhi::D3D11: |
8729 | return "D3D11"; |
8730 | case QRhi::Metal: |
8731 | return "Metal"; |
8732 | case QRhi::D3D12: |
8733 | return "D3D12"; |
8734 | } |
8735 | |
8736 | Q_UNREACHABLE_RETURN("Unknown"); |
8737 | } |
8738 | |
8739 | /*! |
8740 | \return the backend type as string for this QRhi. |
8741 | */ |
8742 | const char *QRhi::backendName() const |
8743 | { |
8744 | return backendName(impl: d->implType); |
8745 | } |
8746 | |
8747 | /*! |
8748 | \enum QRhiDriverInfo::DeviceType |
8749 | Specifies the graphics device's type, when the information is available. |
8750 | |
8751 | In practice this is only applicable with Vulkan and Metal. With Direct 3D |
8752 | 11 and 12, using an adapter with the software flag set leads to the value |
8753 | \c CpuDevice. Otherwise, and with OpenGL, the value is always UnknownDevice. |
8754 | |
8755 | \value UnknownDevice |
8756 | \value IntegratedDevice |
8757 | \value DiscreteDevice |
8758 | \value ExternalDevice |
8759 | \value VirtualDevice |
8760 | \value CpuDevice |
8761 | */ |
8762 | |
8763 | /*! |
8764 | \struct QRhiDriverInfo |
8765 | \inmodule QtGuiPrivate |
8766 | \inheaderfile rhi/qrhi.h |
8767 | \since 6.6 |
8768 | |
8769 | \brief Describes the physical device, adapter, or graphics API |
8770 | implementation that is used by an initialized QRhi. |
8771 | |
8772 | Graphics APIs offer different levels and kinds of information. The only |
8773 | value that is available across all APIs is the deviceName, which is a |
8774 | freetext description of the physical device, adapter, or is a combination |
8775 | of the strings reported for \c{GL_VENDOR} + \c{GL_RENDERER} + |
8776 | \c{GL_VERSION}. The deviceId is always 0 for OpenGL. vendorId is always 0 |
8777 | for OpenGL and Metal. deviceType is always UnknownDevice for OpenGL and |
8778 | Direct 3D. |
8779 | |
8780 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
8781 | for details. |
8782 | */ |
8783 | |
8784 | /*! |
8785 | \variable QRhiDriverInfo::deviceName |
8786 | |
8787 | \sa QRhi::driverInfo() |
8788 | */ |
8789 | |
8790 | /*! |
8791 | \variable QRhiDriverInfo::deviceId |
8792 | |
8793 | \sa QRhi::driverInfo() |
8794 | */ |
8795 | |
8796 | /*! |
8797 | \variable QRhiDriverInfo::vendorId |
8798 | |
8799 | \sa QRhi::driverInfo() |
8800 | */ |
8801 | |
8802 | /*! |
8803 | \variable QRhiDriverInfo::deviceType |
8804 | |
8805 | \sa QRhi::driverInfo(), QRhiDriverInfo::DeviceType |
8806 | */ |
8807 | |
8808 | #ifndef QT_NO_DEBUG_STREAM |
8809 | static inline const char *deviceTypeStr(QRhiDriverInfo::DeviceType type) |
8810 | { |
8811 | switch (type) { |
8812 | case QRhiDriverInfo::UnknownDevice: |
8813 | return "Unknown"; |
8814 | case QRhiDriverInfo::IntegratedDevice: |
8815 | return "Integrated"; |
8816 | case QRhiDriverInfo::DiscreteDevice: |
8817 | return "Discrete"; |
8818 | case QRhiDriverInfo::ExternalDevice: |
8819 | return "External"; |
8820 | case QRhiDriverInfo::VirtualDevice: |
8821 | return "Virtual"; |
8822 | case QRhiDriverInfo::CpuDevice: |
8823 | return "Cpu"; |
8824 | } |
8825 | |
8826 | Q_UNREACHABLE_RETURN(nullptr); |
8827 | } |
8828 | QDebug operator<<(QDebug dbg, const QRhiDriverInfo &info) |
8829 | { |
8830 | QDebugStateSaver saver(dbg); |
8831 | dbg.nospace() << "QRhiDriverInfo(deviceName="<< info.deviceName |
8832 | << " deviceId=0x"<< Qt::hex << info.deviceId |
8833 | << " vendorId=0x"<< info.vendorId |
8834 | << " deviceType="<< deviceTypeStr(type: info.deviceType) |
8835 | << ')'; |
8836 | return dbg; |
8837 | } |
8838 | #endif |
8839 | |
8840 | /*! |
8841 | \return metadata for the graphics device used by this successfully |
8842 | initialized QRhi instance. |
8843 | */ |
8844 | QRhiDriverInfo QRhi::driverInfo() const |
8845 | { |
8846 | return d->driverInfo(); |
8847 | } |
8848 | |
8849 | /*! |
8850 | \return the thread on which the QRhi was \l{QRhi::create()}{initialized}. |
8851 | */ |
8852 | QThread *QRhi::thread() const |
8853 | { |
8854 | return d->implThread; |
8855 | } |
8856 | |
8857 | /*! |
8858 | Registers a \a callback that is invoked either when the QRhi is destroyed, |
8859 | or when runCleanup() is called. |
8860 | |
8861 | The callback will run with the graphics resource still available, so this |
8862 | provides an opportunity for the application to cleanly release QRhiResource |
8863 | instances belonging to the QRhi. This is particularly useful for managing |
8864 | the lifetime of resources stored in \c cache type of objects, where the |
8865 | cache holds QRhiResources or objects containing QRhiResources. |
8866 | |
8867 | \sa runCleanup(), ~QRhi() |
8868 | */ |
8869 | void QRhi::addCleanupCallback(const CleanupCallback &callback) |
8870 | { |
8871 | d->addCleanupCallback(callback); |
8872 | } |
8873 | |
8874 | /*! |
8875 | \overload |
8876 | |
8877 | Registers \a callback to be invoked either when the QRhi is destroyed or |
8878 | when runCleanup() is called. This overload takes an opaque pointer, \a key, |
8879 | that is used to ensure that a given callback is registered (and so called) |
8880 | only once. |
8881 | |
8882 | \sa removeCleanupCallback() |
8883 | */ |
8884 | void QRhi::addCleanupCallback(const void *key, const CleanupCallback &callback) |
8885 | { |
8886 | d->addCleanupCallback(key, callback); |
8887 | } |
8888 | |
8889 | /*! |
8890 | Deregisters the callback with \a key. If no cleanup callback was registered |
8891 | with \a key, the function does nothing. Callbacks registered without a key |
8892 | cannot be removed. |
8893 | |
8894 | \sa addCleanupCallback() |
8895 | */ |
8896 | void QRhi::removeCleanupCallback(const void *key) |
8897 | { |
8898 | d->removeCleanupCallback(key); |
8899 | } |
8900 | |
8901 | /*! |
8902 | Invokes all registered cleanup functions. The list of cleanup callbacks it |
8903 | then cleared. Normally destroying the QRhi does this automatically, but |
8904 | sometimes it can be useful to trigger cleanup in order to release all |
8905 | cached, non-essential resources. |
8906 | |
8907 | \sa addCleanupCallback() |
8908 | */ |
8909 | void QRhi::runCleanup() |
8910 | { |
8911 | for (const CleanupCallback &f : std::as_const(t&: d->cleanupCallbacks)) |
8912 | f(this); |
8913 | |
8914 | d->cleanupCallbacks.clear(); |
8915 | |
8916 | for (auto it = d->keyedCleanupCallbacks.cbegin(), end = d->keyedCleanupCallbacks.cend(); it != end; ++it) |
8917 | it.value()(this); |
8918 | |
8919 | d->keyedCleanupCallbacks.clear(); |
8920 | } |
8921 | |
8922 | /*! |
8923 | \class QRhiResourceUpdateBatch |
8924 | \inmodule QtGuiPrivate |
8925 | \inheaderfile rhi/qrhi.h |
8926 | \since 6.6 |
8927 | \brief Records upload and copy type of operations. |
8928 | |
8929 | With QRhi it is no longer possible to perform copy type of operations at |
8930 | arbitrary times. Instead, all such operations are recorded into batches |
8931 | that are then passed, most commonly, to QRhiCommandBuffer::beginPass(). |
8932 | What then happens under the hood is hidden from the application: the |
8933 | underlying implementations can defer and implement these operations in |
8934 | various different ways. |
8935 | |
8936 | A resource update batch owns no graphics resources and does not perform any |
8937 | actual operations on its own. It should rather be viewed as a command |
8938 | buffer for update, upload, and copy type of commands. |
8939 | |
8940 | To get an available, empty batch from the pool, call |
8941 | QRhi::nextResourceUpdateBatch(). |
8942 | |
8943 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
8944 | for details. |
8945 | */ |
8946 | |
8947 | /*! |
8948 | \internal |
8949 | */ |
8950 | QRhiResourceUpdateBatch::QRhiResourceUpdateBatch(QRhiImplementation *rhi) |
8951 | : d(new QRhiResourceUpdateBatchPrivate) |
8952 | { |
8953 | d->q = this; |
8954 | d->rhi = rhi; |
8955 | } |
8956 | |
8957 | QRhiResourceUpdateBatch::~QRhiResourceUpdateBatch() |
8958 | { |
8959 | delete d; |
8960 | } |
8961 | |
8962 | /*! |
8963 | \return the batch to the pool. This should only be used when the batch is |
8964 | not passed to one of QRhiCommandBuffer::beginPass(), |
8965 | QRhiCommandBuffer::endPass(), or QRhiCommandBuffer::resourceUpdate() |
8966 | because these implicitly call destroy(). |
8967 | |
8968 | \note QRhiResourceUpdateBatch instances must never by \c deleted by |
8969 | applications. |
8970 | */ |
8971 | void QRhiResourceUpdateBatch::release() |
8972 | { |
8973 | d->free(); |
8974 | } |
8975 | |
8976 | /*! |
8977 | Copies all queued operations from the \a other batch into this one. |
8978 | |
8979 | \note \a other may no longer contain valid data after the merge operation, |
8980 | and must not be submitted, but it will still need to be released by calling |
8981 | release(). |
8982 | |
8983 | This allows for a convenient pattern where resource updates that are |
8984 | already known during the initialization step are collected into a batch |
8985 | that is then merged into another when starting to first render pass later |
8986 | on: |
8987 | |
8988 | \code |
8989 | void init() |
8990 | { |
8991 | initialUpdates = rhi->nextResourceUpdateBatch(); |
8992 | initialUpdates->uploadStaticBuffer(vbuf, vertexData); |
8993 | initialUpdates->uploadStaticBuffer(ibuf, indexData); |
8994 | // ... |
8995 | } |
8996 | |
8997 | void render() |
8998 | { |
8999 | QRhiResourceUpdateBatch *resUpdates = rhi->nextResourceUpdateBatch(); |
9000 | if (initialUpdates) { |
9001 | resUpdates->merge(initialUpdates); |
9002 | initialUpdates->release(); |
9003 | initialUpdates = nullptr; |
9004 | } |
9005 | // resUpdates->updateDynamicBuffer(...); |
9006 | cb->beginPass(rt, clearCol, clearDs, resUpdates); |
9007 | } |
9008 | \endcode |
9009 | */ |
9010 | void QRhiResourceUpdateBatch::merge(QRhiResourceUpdateBatch *other) |
9011 | { |
9012 | d->merge(other: other->d); |
9013 | } |
9014 | |
9015 | /*! |
9016 | \return true until the number of buffer and texture operations enqueued |
9017 | onto this batch is below a reasonable limit. |
9018 | |
9019 | The return value is false when the number of buffer and/or texture |
9020 | operations added to this batch have reached, or are about to reach, a |
9021 | certain limit. The batch is fully functional afterwards as well, but may |
9022 | need to allocate additional memory. Therefore, a renderer that collects |
9023 | lots of buffer and texture updates in a single batch when preparing a frame |
9024 | may want to consider \l{QRhiCommandBuffer::resourceUpdate()}{submitting the |
9025 | batch} and \l{QRhi::nextResourceUpdateBatch()}{starting a new one} when |
9026 | this function returns false. |
9027 | */ |
9028 | bool QRhiResourceUpdateBatch::hasOptimalCapacity() const |
9029 | { |
9030 | return d->hasOptimalCapacity(); |
9031 | } |
9032 | |
9033 | /*! |
9034 | Enqueues updating a region of a QRhiBuffer \a buf created with the type |
9035 | QRhiBuffer::Dynamic. |
9036 | |
9037 | The region is specified \a offset and \a size. The actual bytes to write |
9038 | are specified by \a data which must have at least \a size bytes available. |
9039 | \a data can safely be destroyed or changed once this function returns. |
9040 | |
9041 | \note If host writes are involved, which is the case with |
9042 | updateDynamicBuffer() typically as such buffers are backed by host visible |
9043 | memory with most backends, they may accumulate within a frame. Thus pass 1 |
9044 | reading a region changed by a batch passed to pass 2 may see the changes |
9045 | specified in pass 2's update batch. |
9046 | |
9047 | \note QRhi transparently manages double buffering in order to prevent |
9048 | stalling the graphics pipeline. The fact that a QRhiBuffer may have |
9049 | multiple native buffer objects underneath can be safely ignored when using |
9050 | the QRhi and QRhiResourceUpdateBatch. |
9051 | */ |
9052 | void QRhiResourceUpdateBatch::updateDynamicBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data) |
9053 | { |
9054 | if (size > 0) { |
9055 | const int idx = d->activeBufferOpCount++; |
9056 | const int opListSize = d->bufferOps.size(); |
9057 | if (idx < opListSize) |
9058 | QRhiResourceUpdateBatchPrivate::BufferOp::changeToDynamicUpdate(op: &d->bufferOps[idx], buf, offset, size, data); |
9059 | else |
9060 | d->bufferOps.append(t: QRhiResourceUpdateBatchPrivate::BufferOp::dynamicUpdate(buf, offset, size, data)); |
9061 | } |
9062 | } |
9063 | |
9064 | /*! |
9065 | Enqueues updating a region of a QRhiBuffer \a buf created with the type |
9066 | QRhiBuffer::Immutable or QRhiBuffer::Static. |
9067 | |
9068 | The region is specified \a offset and \a size. The actual bytes to write |
9069 | are specified by \a data which must have at least \a size bytes available. |
9070 | \a data can safely be destroyed or changed once this function returns. |
9071 | */ |
9072 | void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data) |
9073 | { |
9074 | if (size > 0) { |
9075 | const int idx = d->activeBufferOpCount++; |
9076 | if (idx < d->bufferOps.size()) |
9077 | QRhiResourceUpdateBatchPrivate::BufferOp::changeToStaticUpload(op: &d->bufferOps[idx], buf, offset, size, data); |
9078 | else |
9079 | d->bufferOps.append(t: QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, offset, size, data)); |
9080 | } |
9081 | } |
9082 | |
9083 | /*! |
9084 | \overload |
9085 | |
9086 | Enqueues updating the entire QRhiBuffer \a buf created with the type |
9087 | QRhiBuffer::Immutable or QRhiBuffer::Static. |
9088 | */ |
9089 | void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *data) |
9090 | { |
9091 | if (buf->size() > 0) { |
9092 | const int idx = d->activeBufferOpCount++; |
9093 | if (idx < d->bufferOps.size()) |
9094 | QRhiResourceUpdateBatchPrivate::BufferOp::changeToStaticUpload(op: &d->bufferOps[idx], buf, offset: 0, size: 0, data); |
9095 | else |
9096 | d->bufferOps.append(t: QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, offset: 0, size: 0, data)); |
9097 | } |
9098 | } |
9099 | |
9100 | /*! |
9101 | Enqueues reading back a region of the QRhiBuffer \a buf. The size of the |
9102 | region is specified by \a size in bytes, \a offset is the offset in bytes |
9103 | to start reading from. |
9104 | |
9105 | A readback is asynchronous. \a result contains a callback that is invoked |
9106 | when the operation has completed. The data is provided in |
9107 | QRhiReadbackResult::data. Upon successful completion that QByteArray |
9108 | will have a size equal to \a size. On failure the QByteArray will be empty. |
9109 | |
9110 | \note Reading buffers with a usage different than QRhiBuffer::UniformBuffer |
9111 | is supported only when the QRhi::ReadBackNonUniformBuffer feature is |
9112 | reported as supported. |
9113 | |
9114 | \note The asynchronous readback is guaranteed to have completed when one of |
9115 | the following conditions is met: \l{QRhi::finish()}{finish()} has been |
9116 | called; or, at least \c N frames have been \l{QRhi::endFrame()}{submitted}, |
9117 | including the frame that issued the readback operation, and the |
9118 | \l{QRhi::beginFrame()}{recording of a new frame} has been started, where \c |
9119 | N is the \l{QRhi::resourceLimit()}{resource limit value} returned for |
9120 | QRhi::MaxAsyncReadbackFrames. |
9121 | |
9122 | \sa readBackTexture(), QRhi::isFeatureSupported(), QRhi::resourceLimit() |
9123 | */ |
9124 | void QRhiResourceUpdateBatch::readBackBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiReadbackResult *result) |
9125 | { |
9126 | const int idx = d->activeBufferOpCount++; |
9127 | if (idx < d->bufferOps.size()) |
9128 | d->bufferOps[idx] = QRhiResourceUpdateBatchPrivate::BufferOp::read(buf, offset, size, result); |
9129 | else |
9130 | d->bufferOps.append(t: QRhiResourceUpdateBatchPrivate::BufferOp::read(buf, offset, size, result)); |
9131 | } |
9132 | |
9133 | /*! |
9134 | Enqueues uploading the image data for one or more mip levels in one or more |
9135 | layers of the texture \a tex. |
9136 | |
9137 | The details of the copy (source QImage or compressed texture data, regions, |
9138 | target layers and levels) are described in \a desc. |
9139 | */ |
9140 | void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc) |
9141 | { |
9142 | if (desc.cbeginEntries() != desc.cendEntries()) { |
9143 | const int idx = d->activeTextureOpCount++; |
9144 | if (idx < d->textureOps.size()) |
9145 | d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::upload(tex, desc); |
9146 | else |
9147 | d->textureOps.append(t: QRhiResourceUpdateBatchPrivate::TextureOp::upload(tex, desc)); |
9148 | } |
9149 | } |
9150 | |
9151 | /*! |
9152 | Enqueues uploading the image data for mip level 0 of layer 0 of the texture |
9153 | \a tex. |
9154 | |
9155 | \a tex must have an uncompressed format. Its format must also be compatible |
9156 | with the QImage::format() of \a image. The source data is given in \a |
9157 | image. |
9158 | */ |
9159 | void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QImage &image) |
9160 | { |
9161 | uploadTexture(tex, |
9162 | desc: QRhiTextureUploadEntry(0, 0, QRhiTextureSubresourceUploadDescription(image))); |
9163 | } |
9164 | |
9165 | /*! |
9166 | Enqueues a texture-to-texture copy operation from \a src into \a dst as |
9167 | described by \a desc. |
9168 | |
9169 | \note The source texture \a src must be created with |
9170 | QRhiTexture::UsedAsTransferSource. |
9171 | |
9172 | \note The format of the textures must match. With most graphics |
9173 | APIs the data is copied as-is without any format conversions. If |
9174 | \a dst and \a src are created with different formats, unspecified |
9175 | issues may arise. |
9176 | */ |
9177 | void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc) |
9178 | { |
9179 | const int idx = d->activeTextureOpCount++; |
9180 | if (idx < d->textureOps.size()) |
9181 | d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::copy(dst, src, desc); |
9182 | else |
9183 | d->textureOps.append(t: QRhiResourceUpdateBatchPrivate::TextureOp::copy(dst, src, desc)); |
9184 | } |
9185 | |
9186 | /*! |
9187 | Enqueues a texture-to-host copy operation as described by \a rb. |
9188 | |
9189 | Normally \a rb will specify a QRhiTexture as the source. However, when the |
9190 | swapchain in the current frame was created with |
9191 | QRhiSwapChain::UsedAsTransferSource, it can also be the source of the |
9192 | readback. For this, leave the texture set to null in \a rb. |
9193 | |
9194 | Unlike other operations, the results here need to be processed by the |
9195 | application. Therefore, \a result provides not just the data but also a |
9196 | callback as operations on the batch are asynchronous by nature: |
9197 | |
9198 | \code |
9199 | rhi->beginFrame(swapchain); |
9200 | cb->beginPass(swapchain->currentFrameRenderTarget(), colorClear, dsClear); |
9201 | // ... |
9202 | QRhiReadbackResult *rbResult = new QRhiReadbackResult; |
9203 | rbResult->completed = [rbResult] { |
9204 | { |
9205 | const QImage::Format fmt = QImage::Format_RGBA8888_Premultiplied; // fits QRhiTexture::RGBA8 |
9206 | const uchar *p = reinterpret_cast<const uchar *>(rbResult->data.constData()); |
9207 | QImage image(p, rbResult->pixelSize.width(), rbResult->pixelSize.height(), fmt); |
9208 | image.save("result.png"); |
9209 | } |
9210 | delete rbResult; |
9211 | }; |
9212 | QRhiResourceUpdateBatch *u = nextResourceUpdateBatch(); |
9213 | QRhiReadbackDescription rb; // no texture -> uses the current backbuffer of sc |
9214 | u->readBackTexture(rb, rbResult); |
9215 | cb->endPass(u); |
9216 | rhi->endFrame(swapchain); |
9217 | \endcode |
9218 | |
9219 | \note The texture must be created with QRhiTexture::UsedAsTransferSource. |
9220 | |
9221 | \note Multisample textures cannot be read back. |
9222 | |
9223 | \note The readback returns raw byte data, in order to allow the applications |
9224 | to interpret it in any way they see fit. Be aware of the blending settings |
9225 | of rendering code: if the blending is set up to rely on premultiplied alpha, |
9226 | the results of the readback must also be interpreted as Premultiplied. |
9227 | |
9228 | \note When interpreting the resulting raw data, be aware that the readback |
9229 | happens with a byte ordered format. A \l{QRhiTexture::RGBA8}{RGBA8} texture |
9230 | maps therefore to byte ordered QImage formats, such as, |
9231 | QImage::Format_RGBA8888. |
9232 | |
9233 | \note The asynchronous readback is guaranteed to have completed when one of |
9234 | the following conditions is met: \l{QRhi::finish()}{finish()} has been |
9235 | called; or, at least \c N frames have been \l{QRhi::endFrame()}{submitted}, |
9236 | including the frame that issued the readback operation, and the |
9237 | \l{QRhi::beginFrame()}{recording of a new frame} has been started, where \c |
9238 | N is the \l{QRhi::resourceLimit()}{resource limit value} returned for |
9239 | QRhi::MaxAsyncReadbackFrames. |
9240 | |
9241 | A single readback operation copies one mip level of one layer (cubemap face |
9242 | or 3D slice or texture array element) at a time. The level and layer are |
9243 | specified by the respective fields in \a rb. |
9244 | |
9245 | \sa readBackBuffer(), QRhi::resourceLimit() |
9246 | */ |
9247 | void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result) |
9248 | { |
9249 | const int idx = d->activeTextureOpCount++; |
9250 | if (idx < d->textureOps.size()) |
9251 | d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::read(rb, result); |
9252 | else |
9253 | d->textureOps.append(t: QRhiResourceUpdateBatchPrivate::TextureOp::read(rb, result)); |
9254 | } |
9255 | |
9256 | /*! |
9257 | Enqueues a mipmap generation operation for the specified texture \a tex. |
9258 | |
9259 | Both 2D and cube textures are supported. |
9260 | |
9261 | \note The texture must be created with QRhiTexture::MipMapped and |
9262 | QRhiTexture::UsedWithGenerateMips. |
9263 | |
9264 | \warning QRhi cannot guarantee that mipmaps can be generated for all |
9265 | supported texture formats. For example, QRhiTexture::RGBA32F is not a \c |
9266 | filterable format in OpenGL ES 3.0 and Metal on iOS, and therefore the |
9267 | mipmap generation request may fail. RGBA8 and RGBA16F are typically |
9268 | filterable, so it is recommended to use these formats when mipmap generation |
9269 | is desired. |
9270 | */ |
9271 | void QRhiResourceUpdateBatch::generateMips(QRhiTexture *tex) |
9272 | { |
9273 | const int idx = d->activeTextureOpCount++; |
9274 | if (idx < d->textureOps.size()) |
9275 | d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex); |
9276 | else |
9277 | d->textureOps.append(t: QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex)); |
9278 | } |
9279 | |
9280 | /*! |
9281 | \return an available, empty batch to which copy type of operations can be |
9282 | recorded. |
9283 | |
9284 | \note the return value is not owned by the caller and must never be |
9285 | destroyed. Instead, the batch is returned the pool for reuse by passing |
9286 | it to QRhiCommandBuffer::beginPass(), QRhiCommandBuffer::endPass(), or |
9287 | QRhiCommandBuffer::resourceUpdate(), or by calling |
9288 | QRhiResourceUpdateBatch::release() on it. |
9289 | |
9290 | \note Can be called outside beginFrame() - endFrame() as well since a batch |
9291 | instance just collects data on its own, it does not perform any operations. |
9292 | |
9293 | Due to not being tied to a frame being recorded, the following sequence is |
9294 | valid for example: |
9295 | |
9296 | \code |
9297 | rhi->beginFrame(swapchain); |
9298 | QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch(); |
9299 | u->uploadStaticBuffer(buf, data); |
9300 | // ... do not commit the batch |
9301 | rhi->endFrame(); |
9302 | // u stays valid (assuming buf stays valid as well) |
9303 | rhi->beginFrame(swapchain); |
9304 | swapchain->currentFrameCommandBuffer()->resourceUpdate(u); |
9305 | // ... draw with buf |
9306 | rhi->endFrame(); |
9307 | \endcode |
9308 | |
9309 | \warning The maximum number of batches per QRhi is 64. When this limit is |
9310 | reached, the function will return null until a batch is returned to the |
9311 | pool. |
9312 | */ |
9313 | QRhiResourceUpdateBatch *QRhi::nextResourceUpdateBatch() |
9314 | { |
9315 | // By default we prefer spreading out the utilization of the worst case 64 |
9316 | // (but typically 4) batches as much as possible, meaning we won't pick the |
9317 | // first one even if it's free, but prefer picking one after the last picked |
9318 | // one. Relevant due to implicit sharing (the backend may hold on to the |
9319 | // QRhiBufferData until frame no. current+FramesInFlight-1, but |
9320 | // implementations may vary), combined with the desire to reuse container |
9321 | // and QRhiBufferData allocations in bufferOps instead of flooding every |
9322 | // frame with allocs. See free(). In typical Qt Quick scenes this leads to |
9323 | // eventually seeding all 4 (or more) resource batches with buffer operation |
9324 | // data allocations which may (*) then be reused in subsequent frames. This |
9325 | // comes at the expense of using more memory, but has proven good results |
9326 | // when (CPU) profiling typical Quick/Quick3D apps. |
9327 | // |
9328 | // (*) Due to implicit sharing(ish), the exact behavior is unpredictable. If |
9329 | // a backend holds on to the QRhiBufferData for, e.g., a dynamic buffer |
9330 | // update, and then there is a new assign() for that same QRhiBufferData |
9331 | // while the refcount is still 2, it will "detach" (without contents) and |
9332 | // there is no reuse of the alloc. This is mitigated by the 'choose the one |
9333 | // afer the last picked one' logic when handing out batches. |
9334 | |
9335 | auto nextFreeBatch = [this]() -> QRhiResourceUpdateBatch * { |
9336 | auto isFree = [this](int i) -> QRhiResourceUpdateBatch * { |
9337 | const quint64 mask = 1ULL << quint64(i); |
9338 | if (!(d->resUpdPoolMap & mask)) { |
9339 | d->resUpdPoolMap |= mask; |
9340 | QRhiResourceUpdateBatch *u = d->resUpdPool[i]; |
9341 | QRhiResourceUpdateBatchPrivate::get(b: u)->poolIndex = i; |
9342 | d->lastResUpdIdx = i; |
9343 | return u; |
9344 | } |
9345 | return nullptr; |
9346 | }; |
9347 | const int poolSize = d->resUpdPool.size(); |
9348 | for (int i = d->lastResUpdIdx + 1; i < poolSize; ++i) { |
9349 | if (QRhiResourceUpdateBatch *u = isFree(i)) |
9350 | return u; |
9351 | } |
9352 | for (int i = 0; i <= d->lastResUpdIdx; ++i) { |
9353 | if (QRhiResourceUpdateBatch *u = isFree(i)) |
9354 | return u; |
9355 | } |
9356 | return nullptr; |
9357 | }; |
9358 | |
9359 | QRhiResourceUpdateBatch *u = nextFreeBatch(); |
9360 | if (!u) { |
9361 | const int oldSize = d->resUpdPool.size(); |
9362 | // 4, 8, 12, ..., up to 64 |
9363 | const int newSize = oldSize + qMin(a: 4, b: qMax(a: 0, b: 64 - oldSize)); |
9364 | d->resUpdPool.resize(sz: newSize); |
9365 | for (int i = oldSize; i < newSize; ++i) |
9366 | d->resUpdPool[i] = new QRhiResourceUpdateBatch(d); |
9367 | u = nextFreeBatch(); |
9368 | if (!u) |
9369 | qWarning(msg: "Resource update batch pool exhausted (max is 64)"); |
9370 | } |
9371 | |
9372 | return u; |
9373 | } |
9374 | |
9375 | void QRhiResourceUpdateBatchPrivate::free() |
9376 | { |
9377 | Q_ASSERT(poolIndex >= 0 && rhi->resUpdPool[poolIndex] == q); |
9378 | |
9379 | quint32 bufferDataTotal = 0; |
9380 | quint32 bufferLargeAllocTotal = 0; |
9381 | for (const BufferOp &op : std::as_const(t&: bufferOps)) { |
9382 | bufferDataTotal += op.data.size(); |
9383 | bufferLargeAllocTotal += op.data.largeAlloc(); // alloc when > 1 KB |
9384 | } |
9385 | |
9386 | if (rhi->rubLogEnabled) { |
9387 | qDebug() << "[rub] release to pool upd.batch #"<< poolIndex |
9388 | << "/ bufferOps active"<< activeBufferOpCount |
9389 | << "of"<< bufferOps.count() |
9390 | << "data"<< bufferDataTotal |
9391 | << "largeAlloc"<< bufferLargeAllocTotal |
9392 | << "textureOps active"<< activeTextureOpCount |
9393 | << "of"<< textureOps.count(); |
9394 | } |
9395 | |
9396 | activeBufferOpCount = 0; |
9397 | activeTextureOpCount = 0; |
9398 | |
9399 | const quint64 mask = 1ULL << quint64(poolIndex); |
9400 | rhi->resUpdPoolMap &= ~mask; |
9401 | poolIndex = -1; |
9402 | |
9403 | // textureOps is cleared, to not keep the potentially large image pixel |
9404 | // data alive, but it is expected that the container keeps the list alloc |
9405 | // at least. Only trimOpList() goes for the more aggressive route with squeeze. |
9406 | textureOps.clear(); |
9407 | |
9408 | // bufferOps is not touched in many cases, to allow reusing allocations |
9409 | // (incl. in the elements' QRhiBufferData) as much as possible when this |
9410 | // batch is used again in the future, which is important for performance, in |
9411 | // particular with Qt Quick where it is easy for scenes to produce lots of, |
9412 | // typically small buffer changes on every frame. |
9413 | // |
9414 | // However, ensure that even in the unlikely case of having the max number |
9415 | // of batches (64) created in resUpdPool, no more than 64 MB in total is |
9416 | // used up by buffer data just to help future reuse. For simplicity, if |
9417 | // there is more than 1 MB data -> clear. Applications with frequent, huge |
9418 | // buffer updates probably have other bottlenecks anyway. |
9419 | if (bufferLargeAllocTotal > 1024 * 1024) |
9420 | bufferOps.clear(); |
9421 | } |
9422 | |
9423 | void QRhiResourceUpdateBatchPrivate::merge(QRhiResourceUpdateBatchPrivate *other) |
9424 | { |
9425 | int combinedSize = activeBufferOpCount + other->activeBufferOpCount; |
9426 | if (bufferOps.size() < combinedSize) |
9427 | bufferOps.resize(sz: combinedSize); |
9428 | for (int i = activeBufferOpCount; i < combinedSize; ++i) |
9429 | bufferOps[i] = std::move(other->bufferOps[i - activeBufferOpCount]); |
9430 | activeBufferOpCount += other->activeBufferOpCount; |
9431 | |
9432 | combinedSize = activeTextureOpCount + other->activeTextureOpCount; |
9433 | if (textureOps.size() < combinedSize) |
9434 | textureOps.resize(sz: combinedSize); |
9435 | for (int i = activeTextureOpCount; i < combinedSize; ++i) |
9436 | textureOps[i] = std::move(other->textureOps[i - activeTextureOpCount]); |
9437 | activeTextureOpCount += other->activeTextureOpCount; |
9438 | } |
9439 | |
9440 | bool QRhiResourceUpdateBatchPrivate::hasOptimalCapacity() const |
9441 | { |
9442 | return activeBufferOpCount < BUFFER_OPS_STATIC_ALLOC - 4 |
9443 | && activeTextureOpCount < TEXTURE_OPS_STATIC_ALLOC - 4; |
9444 | } |
9445 | |
9446 | void QRhiResourceUpdateBatchPrivate::trimOpLists() |
9447 | { |
9448 | // Unlike free(), this is expected to aggressively deallocate all memory |
9449 | // used by both the buffer and texture operation lists. (i.e. using |
9450 | // squeeze() to only keep the stack prealloc of the QVLAs) |
9451 | // |
9452 | // This (e.g. just the destruction of bufferOps elements) may have a |
9453 | // non-negligible performance impact e.g. with Qt Quick with scenes where |
9454 | // there are lots of buffer operations per frame. |
9455 | |
9456 | activeBufferOpCount = 0; |
9457 | bufferOps.clear(); |
9458 | bufferOps.squeeze(); |
9459 | |
9460 | activeTextureOpCount = 0; |
9461 | textureOps.clear(); |
9462 | textureOps.squeeze(); |
9463 | } |
9464 | |
9465 | /*! |
9466 | Sometimes committing resource updates is necessary or just more convenient |
9467 | without starting a render pass. Calling this function with \a |
9468 | resourceUpdates is an alternative to passing \a resourceUpdates to a |
9469 | beginPass() call (or endPass(), which would be typical in case of readbacks). |
9470 | |
9471 | \note Cannot be called inside a pass. |
9472 | */ |
9473 | void QRhiCommandBuffer::resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates) |
9474 | { |
9475 | if (resourceUpdates) |
9476 | m_rhi->resourceUpdate(cb: this, resourceUpdates); |
9477 | } |
9478 | |
9479 | /*! |
9480 | Records starting a new render pass targeting the render target \a rt. |
9481 | |
9482 | \a resourceUpdates, when not null, specifies a resource update batch that |
9483 | is to be committed and then released. |
9484 | |
9485 | The color and depth/stencil buffers of the render target are normally |
9486 | cleared. The clear values are specified in \a colorClearValue and \a |
9487 | depthStencilClearValue. The exception is when the render target was created |
9488 | with QRhiTextureRenderTarget::PreserveColorContents and/or |
9489 | QRhiTextureRenderTarget::PreserveDepthStencilContents. The clear values are |
9490 | ignored then. |
9491 | |
9492 | \note Enabling preserved color or depth contents leads to decreased |
9493 | performance depending on the underlying hardware. Mobile GPUs with tiled |
9494 | architecture benefit from not having to reload the previous contents into |
9495 | the tile buffer. Similarly, a QRhiTextureRenderTarget with a QRhiTexture as |
9496 | the depth buffer is less efficient than a QRhiRenderBuffer since using a |
9497 | depth texture triggers requiring writing the data out to it, while with |
9498 | renderbuffers this is not needed (as the API does not allow sampling or |
9499 | reading from a renderbuffer). |
9500 | |
9501 | \note Do not assume that any state or resource bindings persist between |
9502 | passes. |
9503 | |
9504 | \note The QRhiCommandBuffer's \c set and \c draw functions can only be |
9505 | called inside a pass. Also, with the exception of setGraphicsPipeline(), |
9506 | they expect to have a pipeline set already on the command buffer. |
9507 | Unspecified issues may arise otherwise, depending on the backend. |
9508 | |
9509 | If \a rt is a QRhiTextureRenderTarget, beginPass() performs a check to see |
9510 | if the texture and renderbuffer objects referenced from the render target |
9511 | are up-to-date. This is similar to what setShaderResources() does for |
9512 | QRhiShaderResourceBindings. If any of the attachments had been rebuilt |
9513 | since QRhiTextureRenderTarget::create(), an implicit call to create() is |
9514 | made on \a rt. Therefore, if \a rt has a QRhiTexture color attachment \c |
9515 | texture, and one needs to make the texture a different size, the following |
9516 | is then valid: |
9517 | \code |
9518 | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ { texture } }); |
9519 | rt->create(); |
9520 | // ... |
9521 | texture->setPixelSize(new_size); |
9522 | texture->create(); |
9523 | cb->beginPass(rt, colorClear, dsClear); // this is ok, no explicit rt->create() is required before |
9524 | \endcode |
9525 | |
9526 | \a flags allow controlling certain advanced functionality. One commonly used |
9527 | flag is \c ExternalContents. This should be specified whenever |
9528 | beginExternal() will be called within the pass started by this function. |
9529 | |
9530 | \sa endPass(), BeginPassFlags |
9531 | */ |
9532 | void QRhiCommandBuffer::beginPass(QRhiRenderTarget *rt, |
9533 | const QColor &colorClearValue, |
9534 | const QRhiDepthStencilClearValue &depthStencilClearValue, |
9535 | QRhiResourceUpdateBatch *resourceUpdates, |
9536 | BeginPassFlags flags) |
9537 | { |
9538 | m_rhi->beginPass(cb: this, rt, colorClearValue, depthStencilClearValue, resourceUpdates, flags); |
9539 | } |
9540 | |
9541 | /*! |
9542 | Records ending the current render pass. |
9543 | |
9544 | \a resourceUpdates, when not null, specifies a resource update batch that |
9545 | is to be committed and then released. |
9546 | |
9547 | \sa beginPass() |
9548 | */ |
9549 | void QRhiCommandBuffer::endPass(QRhiResourceUpdateBatch *resourceUpdates) |
9550 | { |
9551 | m_rhi->endPass(cb: this, resourceUpdates); |
9552 | } |
9553 | |
9554 | /*! |
9555 | Records setting a new graphics pipeline \a ps. |
9556 | |
9557 | \note This function must be called before recording other \c set or \c draw |
9558 | commands on the command buffer. |
9559 | |
9560 | \note QRhi will optimize out unnecessary invocations within a pass, so |
9561 | therefore overoptimizing to avoid calls to this function is not necessary |
9562 | on the applications' side. |
9563 | |
9564 | \note This function can only be called inside a render pass, meaning |
9565 | between a beginPass() and endPass() call. |
9566 | |
9567 | \note The new graphics pipeline \a ps must be a valid pointer. |
9568 | */ |
9569 | void QRhiCommandBuffer::setGraphicsPipeline(QRhiGraphicsPipeline *ps) |
9570 | { |
9571 | Q_ASSERT(ps != nullptr); |
9572 | m_rhi->setGraphicsPipeline(cb: this, ps); |
9573 | } |
9574 | |
9575 | /*! |
9576 | Records binding a set of shader resources, such as, uniform buffers or |
9577 | textures, that are made visible to one or more shader stages. |
9578 | |
9579 | \a srb can be null in which case the current graphics or compute pipeline's |
9580 | associated QRhiShaderResourceBindings is used. When \a srb is non-null, it |
9581 | must be |
9582 | \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible}, |
9583 | meaning the layout (number of bindings, the type and binding number of each |
9584 | binding) must fully match the QRhiShaderResourceBindings that was |
9585 | associated with the pipeline at the time of calling the pipeline's create(). |
9586 | |
9587 | There are cases when a seemingly unnecessary setShaderResources() call is |
9588 | mandatory: when rebuilding a resource referenced from \a srb, for example |
9589 | changing the size of a QRhiBuffer followed by a QRhiBuffer::create(), this |
9590 | is the place where associated native objects (such as descriptor sets in |
9591 | case of Vulkan) are updated to refer to the current native resources that |
9592 | back the QRhiBuffer, QRhiTexture, QRhiSampler objects referenced from \a |
9593 | srb. In this case setShaderResources() must be called even if \a srb is |
9594 | the same as in the last call. |
9595 | |
9596 | When \a srb is not null, the QRhiShaderResourceBindings object the pipeline |
9597 | was built with in create() is guaranteed to be not accessed in any form. In |
9598 | fact, it does not need to be valid even at this point: destroying the |
9599 | pipeline's associated srb after create() and instead explicitly specifying |
9600 | another, \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout |
9601 | compatible} one in every setShaderResources() call is valid. |
9602 | |
9603 | \a dynamicOffsets allows specifying buffer offsets for uniform buffers that |
9604 | were associated with \a srb via |
9605 | QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(). This is |
9606 | different from providing the offset in the \a srb itself: dynamic offsets |
9607 | do not require building a new QRhiShaderResourceBindings for every |
9608 | different offset, can avoid writing the underlying descriptors (with |
9609 | backends where applicable), and so they may be more efficient. Each element |
9610 | of \a dynamicOffsets is a \c binding - \c offset pair. |
9611 | \a dynamicOffsetCount specifies the number of elements in \a dynamicOffsets. |
9612 | |
9613 | \note All offsets in \a dynamicOffsets must be byte aligned to the value |
9614 | returned from QRhi::ubufAlignment(). |
9615 | |
9616 | \note Some backends may limit the number of supported dynamic offsets. |
9617 | Avoid using a \a dynamicOffsetCount larger than 8. |
9618 | |
9619 | \note QRhi will optimize out unnecessary invocations within a pass (taking |
9620 | the conditions described above into account), so therefore overoptimizing |
9621 | to avoid calls to this function is not necessary on the applications' side. |
9622 | |
9623 | \note This function can only be called inside a render or compute pass, |
9624 | meaning between a beginPass() and endPass(), or beginComputePass() and |
9625 | endComputePass(). |
9626 | */ |
9627 | void QRhiCommandBuffer::setShaderResources(QRhiShaderResourceBindings *srb, |
9628 | int dynamicOffsetCount, |
9629 | const DynamicOffset *dynamicOffsets) |
9630 | { |
9631 | m_rhi->setShaderResources(cb: this, srb, dynamicOffsetCount, dynamicOffsets); |
9632 | } |
9633 | |
9634 | /*! |
9635 | Records vertex input bindings. |
9636 | |
9637 | The index buffer used by subsequent drawIndexed() commands is specified by |
9638 | \a indexBuf, \a indexOffset, and \a indexFormat. \a indexBuf can be set to |
9639 | null when indexed drawing is not needed. |
9640 | |
9641 | Vertex buffer bindings are batched. \a startBinding specifies the first |
9642 | binding number. The recorded command then binds each buffer from \a |
9643 | bindings to the binding point \c{startBinding + i} where \c i is the index |
9644 | in \a bindings. Each element in \a bindings specifies a QRhiBuffer and an |
9645 | offset. |
9646 | |
9647 | \note Some backends may limit the number of vertex buffer bindings. Avoid |
9648 | using a \a bindingCount larger than 8. |
9649 | |
9650 | Superfluous vertex input and index changes in the same pass are ignored |
9651 | automatically with most backends and therefore applications do not need to |
9652 | overoptimize to avoid calls to this function. |
9653 | |
9654 | \note This function can only be called inside a render pass, meaning |
9655 | between a beginPass() and endPass() call. |
9656 | |
9657 | As a simple example, take a vertex shader with two inputs: |
9658 | |
9659 | \badcode |
9660 | layout(location = 0) in vec4 position; |
9661 | layout(location = 1) in vec3 color; |
9662 | \endcode |
9663 | |
9664 | and assume we have the data available in interleaved format, using only 2 |
9665 | floats for position (so 5 floats per vertex: x, y, r, g, b). A QRhiGraphicsPipeline for |
9666 | this shader can then be created using the input layout: |
9667 | |
9668 | \code |
9669 | QRhiVertexInputLayout inputLayout; |
9670 | inputLayout.setBindings({ |
9671 | { 5 * sizeof(float) } |
9672 | }); |
9673 | inputLayout.setAttributes({ |
9674 | { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, |
9675 | { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) } |
9676 | }); |
9677 | \endcode |
9678 | |
9679 | Here there is one buffer binding (binding number 0), with two inputs |
9680 | referencing it. When recording the pass, once the pipeline is set, the |
9681 | vertex bindings can be specified simply like the following, assuming vbuf |
9682 | is the QRhiBuffer with all the interleaved position+color data: |
9683 | |
9684 | \code |
9685 | const QRhiCommandBuffer::VertexInput vbufBinding(vbuf, 0); |
9686 | cb->setVertexInput(0, 1, &vbufBinding); |
9687 | \endcode |
9688 | */ |
9689 | void QRhiCommandBuffer::setVertexInput(int startBinding, int bindingCount, const VertexInput *bindings, |
9690 | QRhiBuffer *indexBuf, quint32 indexOffset, |
9691 | IndexFormat indexFormat) |
9692 | { |
9693 | m_rhi->setVertexInput(cb: this, startBinding, bindingCount, bindings, indexBuf, indexOffset, indexFormat); |
9694 | } |
9695 | |
9696 | /*! |
9697 | Records setting the active viewport rectangle specified in \a viewport. |
9698 | |
9699 | With backends where the underlying graphics API has scissoring always |
9700 | enabled, this function also sets the scissor to match the viewport whenever |
9701 | the active QRhiGraphicsPipeline does not have |
9702 | \l{QRhiGraphicsPipeline::UsesScissor}{UsesScissor} set. |
9703 | |
9704 | \note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are |
9705 | bottom-left. |
9706 | |
9707 | \note This function can only be called inside a render pass, meaning |
9708 | between a beginPass() and endPass() call. |
9709 | */ |
9710 | void QRhiCommandBuffer::setViewport(const QRhiViewport &viewport) |
9711 | { |
9712 | m_rhi->setViewport(cb: this, viewport); |
9713 | } |
9714 | |
9715 | /*! |
9716 | Records setting the active scissor rectangle specified in \a scissor. |
9717 | |
9718 | This can only be called when the bound pipeline has |
9719 | \l{QRhiGraphicsPipeline::UsesScissor}{UsesScissor} set. When the flag is |
9720 | set on the active pipeline, this function must be called because scissor |
9721 | testing will get enabled and so a scissor rectangle must be provided. |
9722 | |
9723 | \note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are |
9724 | bottom-left. |
9725 | |
9726 | \note This function can only be called inside a render pass, meaning |
9727 | between a beginPass() and endPass() call. |
9728 | */ |
9729 | void QRhiCommandBuffer::setScissor(const QRhiScissor &scissor) |
9730 | { |
9731 | m_rhi->setScissor(cb: this, scissor); |
9732 | } |
9733 | |
9734 | /*! |
9735 | Records setting the active blend constants to \a c. |
9736 | |
9737 | This can only be called when the bound pipeline has |
9738 | QRhiGraphicsPipeline::UsesBlendConstants set. |
9739 | |
9740 | \note This function can only be called inside a render pass, meaning |
9741 | between a beginPass() and endPass() call. |
9742 | */ |
9743 | void QRhiCommandBuffer::setBlendConstants(const QColor &c) |
9744 | { |
9745 | m_rhi->setBlendConstants(cb: this, c); |
9746 | } |
9747 | |
9748 | /*! |
9749 | Records setting the active stencil reference value to \a refValue. |
9750 | |
9751 | This can only be called when the bound pipeline has |
9752 | QRhiGraphicsPipeline::UsesStencilRef set. |
9753 | |
9754 | \note This function can only be called inside a render pass, meaning between |
9755 | a beginPass() and endPass() call. |
9756 | */ |
9757 | void QRhiCommandBuffer::setStencilRef(quint32 refValue) |
9758 | { |
9759 | m_rhi->setStencilRef(cb: this, refValue); |
9760 | } |
9761 | |
9762 | /*! |
9763 | Records a non-indexed draw. |
9764 | |
9765 | The number of vertices is specified in \a vertexCount. For instanced |
9766 | drawing set \a instanceCount to a value other than 1. \a firstVertex is the |
9767 | index of the first vertex to draw. When drawing multiple instances, the |
9768 | first instance ID is specified by \a firstInstance. |
9769 | |
9770 | \note \a firstInstance may not be supported, and is ignored when the |
9771 | QRhi::BaseInstance feature is reported as not supported. The first ID is |
9772 | always 0 in that case. |
9773 | |
9774 | \note This function can only be called inside a render pass, meaning |
9775 | between a beginPass() and endPass() call. |
9776 | */ |
9777 | void QRhiCommandBuffer::draw(quint32 vertexCount, |
9778 | quint32 instanceCount, |
9779 | quint32 firstVertex, |
9780 | quint32 firstInstance) |
9781 | { |
9782 | m_rhi->draw(cb: this, vertexCount, instanceCount, firstVertex, firstInstance); |
9783 | } |
9784 | |
9785 | /*! |
9786 | Records an indexed draw. |
9787 | |
9788 | The number of vertices is specified in \a indexCount. \a firstIndex is the |
9789 | base index. The effective offset in the index buffer is given by |
9790 | \c{indexOffset + firstIndex * n} where \c n is 2 or 4 depending on the |
9791 | index element type. \c indexOffset is specified in setVertexInput(). |
9792 | |
9793 | \note The effective offset in the index buffer must be 4 byte aligned with |
9794 | some backends (for example, Metal). With these backends the |
9795 | \l{QRhi::NonFourAlignedEffectiveIndexBufferOffset}{NonFourAlignedEffectiveIndexBufferOffset} |
9796 | feature will be reported as not-supported. |
9797 | |
9798 | For instanced drawing set \a instanceCount to a value other than 1. When |
9799 | drawing multiple instances, the first instance ID is specified by \a |
9800 | firstInstance. |
9801 | |
9802 | \note \a firstInstance may not be supported, and is ignored when the |
9803 | QRhi::BaseInstance feature is reported as not supported. The first ID is |
9804 | always 0 in that case. |
9805 | |
9806 | \a vertexOffset (also called \c{base vertex}) is a signed value that is |
9807 | added to the element index before indexing into the vertex buffer. Support |
9808 | for this is not always available, and the value is ignored when the feature |
9809 | QRhi::BaseVertex is reported as unsupported. |
9810 | |
9811 | \note This function can only be called inside a render pass, meaning |
9812 | between a beginPass() and endPass() call. |
9813 | */ |
9814 | void QRhiCommandBuffer::drawIndexed(quint32 indexCount, |
9815 | quint32 instanceCount, |
9816 | quint32 firstIndex, |
9817 | qint32 vertexOffset, |
9818 | quint32 firstInstance) |
9819 | { |
9820 | m_rhi->drawIndexed(cb: this, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); |
9821 | } |
9822 | |
9823 | /*! |
9824 | Records a named debug group on the command buffer with the specified \a |
9825 | name. This is shown in graphics debugging tools such as |
9826 | \l{https://renderdoc.org/}{RenderDoc} and |
9827 | \l{https://developer.apple.com/xcode/}{XCode}. The end of the grouping is |
9828 | indicated by debugMarkEnd(). |
9829 | |
9830 | \note Ignored when QRhi::DebugMarkers are not supported or |
9831 | QRhi::EnableDebugMarkers is not set. |
9832 | |
9833 | \note Can be called anywhere within the frame, both inside and outside of passes. |
9834 | */ |
9835 | void QRhiCommandBuffer::debugMarkBegin(const QByteArray &name) |
9836 | { |
9837 | m_rhi->debugMarkBegin(cb: this, name); |
9838 | } |
9839 | |
9840 | /*! |
9841 | Records the end of a debug group. |
9842 | |
9843 | \note Ignored when QRhi::DebugMarkers are not supported or |
9844 | QRhi::EnableDebugMarkers is not set. |
9845 | |
9846 | \note Can be called anywhere within the frame, both inside and outside of passes. |
9847 | */ |
9848 | void QRhiCommandBuffer::debugMarkEnd() |
9849 | { |
9850 | m_rhi->debugMarkEnd(cb: this); |
9851 | } |
9852 | |
9853 | /*! |
9854 | Inserts a debug message \a msg into the command stream. |
9855 | |
9856 | \note Ignored when QRhi::DebugMarkers are not supported or |
9857 | QRhi::EnableDebugMarkers is not set. |
9858 | |
9859 | \note With some backends debugMarkMsg() is only supported inside a pass and |
9860 | is ignored when called outside a pass. With others it is recorded anywhere |
9861 | within the frame. |
9862 | */ |
9863 | void QRhiCommandBuffer::debugMarkMsg(const QByteArray &msg) |
9864 | { |
9865 | m_rhi->debugMarkMsg(cb: this, msg); |
9866 | } |
9867 | |
9868 | /*! |
9869 | Records starting a new compute pass. |
9870 | |
9871 | \a resourceUpdates, when not null, specifies a resource update batch that |
9872 | is to be committed and then released. |
9873 | |
9874 | \note Do not assume that any state or resource bindings persist between |
9875 | passes. |
9876 | |
9877 | \note A compute pass can record setComputePipeline(), setShaderResources(), |
9878 | and dispatch() calls, not graphics ones. General functionality, such as, |
9879 | debug markers and beginExternal() is available both in render and compute |
9880 | passes. |
9881 | |
9882 | \note Compute is only available when the \l{QRhi::Compute}{Compute} feature |
9883 | is reported as supported. |
9884 | |
9885 | \a flags is not currently used. |
9886 | */ |
9887 | void QRhiCommandBuffer::beginComputePass(QRhiResourceUpdateBatch *resourceUpdates, BeginPassFlags flags) |
9888 | { |
9889 | m_rhi->beginComputePass(cb: this, resourceUpdates, flags); |
9890 | } |
9891 | |
9892 | /*! |
9893 | Records ending the current compute pass. |
9894 | |
9895 | \a resourceUpdates, when not null, specifies a resource update batch that |
9896 | is to be committed and then released. |
9897 | */ |
9898 | void QRhiCommandBuffer::endComputePass(QRhiResourceUpdateBatch *resourceUpdates) |
9899 | { |
9900 | m_rhi->endComputePass(cb: this, resourceUpdates); |
9901 | } |
9902 | |
9903 | /*! |
9904 | Records setting a new compute pipeline \a ps. |
9905 | |
9906 | \note This function must be called before recording setShaderResources() or |
9907 | dispatch() commands on the command buffer. |
9908 | |
9909 | \note QRhi will optimize out unnecessary invocations within a pass, so |
9910 | therefore overoptimizing to avoid calls to this function is not necessary |
9911 | on the applications' side. |
9912 | |
9913 | \note This function can only be called inside a compute pass, meaning |
9914 | between a beginComputePass() and endComputePass() call. |
9915 | */ |
9916 | void QRhiCommandBuffer::setComputePipeline(QRhiComputePipeline *ps) |
9917 | { |
9918 | m_rhi->setComputePipeline(cb: this, ps); |
9919 | } |
9920 | |
9921 | /*! |
9922 | Records dispatching compute work items, with \a x, \a y, and \a z |
9923 | specifying the number of local workgroups in the corresponding dimension. |
9924 | |
9925 | \note This function can only be called inside a compute pass, meaning |
9926 | between a beginComputePass() and endComputePass() call. |
9927 | |
9928 | \note \a x, \a y, and \a z must fit the limits from the underlying graphics |
9929 | API implementation at run time. The maximum values are typically 65535. |
9930 | |
9931 | \note Watch out for possible limits on the local workgroup size as well. |
9932 | This is specified in the shader, for example: \c{layout(local_size_x = 16, |
9933 | local_size_y = 16) in;}. For example, with OpenGL the minimum value mandated |
9934 | by the specification for the number of invocations in a single local work |
9935 | group (the product of \c local_size_x, \c local_size_y, and \c local_size_z) |
9936 | is 1024, while with OpenGL ES (3.1) the value may be as low as 128. This |
9937 | means that the example given above may be rejected by some OpenGL ES |
9938 | implementations as the number of invocations is 256. |
9939 | */ |
9940 | void QRhiCommandBuffer::dispatch(int x, int y, int z) |
9941 | { |
9942 | m_rhi->dispatch(cb: this, x, y, z); |
9943 | } |
9944 | |
9945 | /*! |
9946 | \return a pointer to a backend-specific QRhiNativeHandles subclass, such as |
9947 | QRhiVulkanCommandBufferNativeHandles. The returned value is \nullptr when |
9948 | exposing the underlying native resources is not supported by, or not |
9949 | applicable to, the backend. |
9950 | |
9951 | \sa QRhiVulkanCommandBufferNativeHandles, |
9952 | QRhiMetalCommandBufferNativeHandles, beginExternal(), endExternal() |
9953 | */ |
9954 | const QRhiNativeHandles *QRhiCommandBuffer::nativeHandles() |
9955 | { |
9956 | return m_rhi->nativeHandles(cb: this); |
9957 | } |
9958 | |
9959 | /*! |
9960 | To be called when the application before the application is about to |
9961 | enqueue commands to the current pass' command buffer by calling graphics |
9962 | API functions directly. |
9963 | |
9964 | \note This is only available when the intent was declared upfront in |
9965 | beginPass() or beginComputePass(). Therefore this function must only be |
9966 | called when the pass recording was started with specifying |
9967 | QRhiCommandBuffer::ExternalContent. |
9968 | |
9969 | With Vulkan, Metal, or Direct3D 12 one can query the native command buffer |
9970 | or encoder objects via nativeHandles() and enqueue commands to them. With |
9971 | OpenGL or Direct3D 11 the (device) context can be retrieved from |
9972 | QRhi::nativeHandles(). However, this must never be done without ensuring |
9973 | the QRhiCommandBuffer's state stays up-to-date. Hence the requirement for |
9974 | wrapping any externally added command recording between beginExternal() and |
9975 | endExternal(). Conceptually this is the same as QPainter's |
9976 | \l{QPainter::beginNativePainting()}{beginNativePainting()} and |
9977 | \l{QPainter::endNativePainting()}{endNativePainting()} functions. |
9978 | |
9979 | For OpenGL in particular, this function has an additional task: it makes |
9980 | sure the context is made current on the current thread. |
9981 | |
9982 | \note Once beginExternal() is called, no other render pass specific |
9983 | functions (\c set* or \c draw*) must be called on the |
9984 | QRhiCommandBuffer until endExternal(). |
9985 | |
9986 | \warning Some backends may return a native command buffer object from |
9987 | QRhiCommandBuffer::nativeHandles() that is different from the primary one |
9988 | when inside a beginExternal() - endExternal() block. Therefore it is |
9989 | important to (re)query the native command buffer object after calling |
9990 | beginExternal(). In practical terms this means that with Vulkan for example |
9991 | the externally recorded Vulkan commands are placed onto a secondary command |
9992 | buffer (with VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT). |
9993 | nativeHandles() returns this secondary command buffer when called between |
9994 | begin/endExternal. |
9995 | |
9996 | \sa endExternal(), nativeHandles() |
9997 | */ |
9998 | void QRhiCommandBuffer::beginExternal() |
9999 | { |
10000 | m_rhi->beginExternal(cb: this); |
10001 | } |
10002 | |
10003 | /*! |
10004 | To be called once the externally added commands are recorded to the command |
10005 | buffer or context. |
10006 | |
10007 | \note All QRhiCommandBuffer state must be assumed as invalid after calling |
10008 | this function. Pipelines, vertex and index buffers, and other state must be |
10009 | set again if more draw calls are recorded after the external commands. |
10010 | |
10011 | \sa beginExternal(), nativeHandles() |
10012 | */ |
10013 | void QRhiCommandBuffer::endExternal() |
10014 | { |
10015 | m_rhi->endExternal(cb: this); |
10016 | } |
10017 | |
10018 | /*! |
10019 | \return the last available timestamp, in seconds, when |
10020 | \l QRhi::EnableTimestamps was enabled when creating the QRhi. The value |
10021 | indicates the elapsed time on the GPU during the last completed frame. |
10022 | |
10023 | \note Do not expect results other than 0 when the QRhi::Timestamps feature |
10024 | is not reported as supported, or when QRhi::EnableTimestamps was not passed |
10025 | to QRhi::create(). There are exceptions to this, because with some graphics |
10026 | APIs (Metal) timings are available without having to perform extra |
10027 | operations (timestamp queries), but portable applications should always |
10028 | consciously opt-in to timestamp collection when they know it is needed, and |
10029 | call this function accordingly. |
10030 | |
10031 | Care must be exercised with the interpretation of the value, as its |
10032 | precision and granularity is often not controlled by Qt, and depends on the |
10033 | underlying graphics API and its implementation. In particular, comparing |
10034 | the values between different graphics APIs and hardware is discouraged and |
10035 | may be meaningless. |
10036 | |
10037 | When the frame was recorded with \l{QRhi::beginFrame()}{beginFrame()} and |
10038 | \l{QRhi::endFrame()}{endFrame()}, i.e., with a swapchain, the timing values |
10039 | will likely become available asynchronously. The returned value may |
10040 | therefore be 0 (e.g., for the first 1-2 frames) or the last known value |
10041 | referring to some previous frame. The value my also |
10042 | become 0 again under certain conditions, such as when resizing the window. |
10043 | It can be expected that the most up-to-date available value is retrieved in |
10044 | beginFrame() and becomes queriable via this function once beginFrame() |
10045 | returns. |
10046 | |
10047 | \note Do not assume that the value refers to the previous |
10048 | (\c{currently_recorded - 1}) frame. It may refer to \c{currently_recorded - |
10049 | 2} or \c{currently_recorded - 3} as well. The exact behavior may depend on |
10050 | the graphics API and its implementation. |
10051 | |
10052 | On the other hand, with offscreen frames the returned value is up-to-date |
10053 | once \l{QRhi::endOffscreenFrame()}{endOffscreenFrame()} returns, because |
10054 | offscreen frames reduce GPU pipelining and wait the the commands to be |
10055 | complete. |
10056 | |
10057 | \note This means that, unlike with swapchain frames, with offscreen frames |
10058 | the returned value is guaranteed to refer to the frame that has just been |
10059 | submitted and completed. (assuming this function is called after |
10060 | endOffscreenFrame() but before the next beginOffscreenFrame()) |
10061 | |
10062 | Watch out for the consequences of GPU frequency scaling and GPU clock |
10063 | changes, depending on the platform. For example, on Windows the returned |
10064 | timing may vary in a quite wide range between frames with modern graphics |
10065 | cards, even when submitting frames with a similar, or the same workload. |
10066 | This is out of scope for Qt to control and solve, generally speaking. |
10067 | However, the D3D12 backend automatically calls |
10068 | \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-setstablepowerstate}{ID3D12Device::SetStablePowerState()} |
10069 | whenever the environment variable \c QT_D3D_STABLE_POWER_STATE is set to a |
10070 | non-zero value. This can greatly stabilize the result. It can also have a |
10071 | non-insignificant effect on the CPU-side timings measured via QElapsedTimer |
10072 | for example, especially when offscreen frames are involved. |
10073 | |
10074 | \note Do not and never ship applications to production with |
10075 | \c QT_D3D_STABLE_POWER_STATE set. See the Windows API documentation for details. |
10076 | |
10077 | \sa QRhi::Timestamps, QRhi::EnableTimestamps |
10078 | */ |
10079 | double QRhiCommandBuffer::lastCompletedGpuTime() |
10080 | { |
10081 | return m_rhi->lastCompletedGpuTime(cb: this); |
10082 | } |
10083 | |
10084 | /*! |
10085 | \return the value (typically an offset) \a v aligned to the uniform buffer |
10086 | alignment given by by ubufAlignment(). |
10087 | */ |
10088 | int QRhi::ubufAligned(int v) const |
10089 | { |
10090 | const int byteAlign = ubufAlignment(); |
10091 | return (v + byteAlign - 1) & ~(byteAlign - 1); |
10092 | } |
10093 | |
10094 | /*! |
10095 | \return the number of mip levels for a given \a size. |
10096 | */ |
10097 | int QRhi::mipLevelsForSize(const QSize &size) |
10098 | { |
10099 | return qFloor(v: std::log2(x: qMax(a: size.width(), b: size.height()))) + 1; |
10100 | } |
10101 | |
10102 | /*! |
10103 | \return the texture image size for a given \a mipLevel, calculated based on |
10104 | the level 0 size given in \a baseLevelSize. |
10105 | */ |
10106 | QSize QRhi::sizeForMipLevel(int mipLevel, const QSize &baseLevelSize) |
10107 | { |
10108 | const int w = qMax(a: 1, b: baseLevelSize.width() >> mipLevel); |
10109 | const int h = qMax(a: 1, b: baseLevelSize.height() >> mipLevel); |
10110 | return QSize(w, h); |
10111 | } |
10112 | |
10113 | /*! |
10114 | \return \c true if the underlying graphics API has the Y axis pointing up |
10115 | in framebuffers and images. |
10116 | |
10117 | In practice this is \c true for OpenGL only. |
10118 | */ |
10119 | bool QRhi::isYUpInFramebuffer() const |
10120 | { |
10121 | return d->isYUpInFramebuffer(); |
10122 | } |
10123 | |
10124 | /*! |
10125 | \return \c true if the underlying graphics API has the Y axis pointing up |
10126 | in its normalized device coordinate system. |
10127 | |
10128 | In practice this is \c false for Vulkan only. |
10129 | |
10130 | \note clipSpaceCorrMatrix() includes the corresponding adjustment (to make |
10131 | Y point up) in its returned matrix. |
10132 | */ |
10133 | bool QRhi::isYUpInNDC() const |
10134 | { |
10135 | return d->isYUpInNDC(); |
10136 | } |
10137 | |
10138 | /*! |
10139 | \return \c true if the underlying graphics API uses depth range [0, 1] in |
10140 | clip space. |
10141 | |
10142 | In practice this is \c false for OpenGL only, because OpenGL uses a |
10143 | post-projection depth range of [-1, 1]. (not to be confused with the |
10144 | NDC-to-window mapping controlled by glDepthRange(), which uses a range of |
10145 | [0, 1], unless overridden by the QRhiViewport) In some OpenGL versions |
10146 | glClipControl() could be used to change this, but the OpenGL backend of |
10147 | QRhi does not use that function as it is not available in OpenGL ES or |
10148 | OpenGL versions lower than 4.5. |
10149 | |
10150 | \note clipSpaceCorrMatrix() includes the corresponding adjustment in its |
10151 | returned matrix. Therefore, many users of QRhi do not need to take any |
10152 | further measures apart from pre-multiplying their projection matrices with |
10153 | clipSpaceCorrMatrix(). However, some graphics techniques, such as, some |
10154 | types of shadow mapping, involve working with and outputting depth values |
10155 | in the shaders. These will need to query and take the value of this |
10156 | function into account as appropriate. |
10157 | */ |
10158 | bool QRhi::isClipDepthZeroToOne() const |
10159 | { |
10160 | return d->isClipDepthZeroToOne(); |
10161 | } |
10162 | |
10163 | /*! |
10164 | \return a matrix that can be used to allow applications keep using |
10165 | OpenGL-targeted vertex data and perspective projection matrices (such as, |
10166 | the ones generated by QMatrix4x4::perspective()), regardless of the active |
10167 | QRhi backend. |
10168 | |
10169 | In a typical renderer, once \c{this_matrix * mvp} is used instead of just |
10170 | \c mvp, vertex data with Y up and viewports with depth range 0 - 1 can be |
10171 | used without considering what backend (and so graphics API) is going to be |
10172 | used at run time. This way branching based on isYUpInNDC() and |
10173 | isClipDepthZeroToOne() can be avoided (although such logic may still become |
10174 | required when implementing certain advanced graphics techniques). |
10175 | |
10176 | See |
10177 | \l{https://matthewwellings.com/blog/the-new-vulkan-coordinate-system/}{this |
10178 | page} for a discussion of the topic from Vulkan perspective. |
10179 | */ |
10180 | QMatrix4x4 QRhi::clipSpaceCorrMatrix() const |
10181 | { |
10182 | return d->clipSpaceCorrMatrix(); |
10183 | } |
10184 | |
10185 | /*! |
10186 | \return \c true if the specified texture \a format modified by \a flags is |
10187 | supported. |
10188 | |
10189 | The query is supported both for uncompressed and compressed formats. |
10190 | */ |
10191 | bool QRhi::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const |
10192 | { |
10193 | return d->isTextureFormatSupported(format, flags); |
10194 | } |
10195 | |
10196 | /*! |
10197 | \return \c true if the specified \a feature is supported |
10198 | */ |
10199 | bool QRhi::isFeatureSupported(QRhi::Feature feature) const |
10200 | { |
10201 | return d->isFeatureSupported(feature); |
10202 | } |
10203 | |
10204 | /*! |
10205 | \return the value for the specified resource \a limit. |
10206 | |
10207 | The values are expected to be queried by the backends upon initialization, |
10208 | meaning calling this function is a light operation. |
10209 | */ |
10210 | int QRhi::resourceLimit(ResourceLimit limit) const |
10211 | { |
10212 | return d->resourceLimit(limit); |
10213 | } |
10214 | |
10215 | /*! |
10216 | \return a pointer to the backend-specific collection of native objects |
10217 | for the device, context, and similar concepts used by the backend. |
10218 | |
10219 | Cast to QRhiVulkanNativeHandles, QRhiD3D11NativeHandles, |
10220 | QRhiD3D12NativeHandles, QRhiGles2NativeHandles, or QRhiMetalNativeHandles |
10221 | as appropriate. |
10222 | |
10223 | \note No ownership is transferred, neither for the returned pointer nor for |
10224 | any native objects. |
10225 | */ |
10226 | const QRhiNativeHandles *QRhi::nativeHandles() |
10227 | { |
10228 | return d->nativeHandles(); |
10229 | } |
10230 | |
10231 | /*! |
10232 | With OpenGL this makes the OpenGL context current on the current thread. |
10233 | The function has no effect with other backends. |
10234 | |
10235 | Calling this function is relevant typically in Qt framework code, when one |
10236 | has to ensure external OpenGL code provided by the application can still |
10237 | run like it did before with direct usage of OpenGL, as long as the QRhi is |
10238 | using the OpenGL backend. |
10239 | |
10240 | \return false when failed, similarly to QOpenGLContext::makeCurrent(). When |
10241 | the operation failed, isDeviceLost() can be called to determine if there |
10242 | was a loss of context situation. Such a check is equivalent to checking via |
10243 | QOpenGLContext::isValid(). |
10244 | |
10245 | \sa QOpenGLContext::makeCurrent(), QOpenGLContext::isValid() |
10246 | */ |
10247 | bool QRhi::makeThreadLocalNativeContextCurrent() |
10248 | { |
10249 | return d->makeThreadLocalNativeContextCurrent(); |
10250 | } |
10251 | |
10252 | /*! |
10253 | Attempts to release resources in the backend's caches. This can include both |
10254 | CPU and GPU resources. Only memory and resources that can be recreated |
10255 | automatically are in scope. As an example, if the backend's |
10256 | QRhiGraphicsPipeline implementation maintains a cache of shader compilation |
10257 | results, calling this function leads to emptying that cache, thus |
10258 | potentially freeing up memory and graphics resources. |
10259 | |
10260 | Calling this function makes sense in resource constrained environments, |
10261 | where at a certain point there is a need to ensure minimal resource usage, |
10262 | at the expense of performance. |
10263 | */ |
10264 | void QRhi::releaseCachedResources() |
10265 | { |
10266 | d->releaseCachedResources(); |
10267 | |
10268 | for (QRhiResourceUpdateBatch *u : d->resUpdPool) { |
10269 | if (u->d->poolIndex < 0) |
10270 | u->d->trimOpLists(); |
10271 | } |
10272 | } |
10273 | |
10274 | /*! |
10275 | \return true if the graphics device was lost. |
10276 | |
10277 | The loss of the device is typically detected in beginFrame(), endFrame() or |
10278 | QRhiSwapChain::createOrResize(), depending on the backend and the underlying |
10279 | native APIs. The most common is endFrame() because that is where presenting |
10280 | happens. With some backends QRhiSwapChain::createOrResize() can also fail |
10281 | due to a device loss. Therefore this function is provided as a generic way |
10282 | to check if a device loss was detected by a previous operation. |
10283 | |
10284 | When the device is lost, no further operations should be done via the QRhi. |
10285 | Rather, all QRhi resources should be released, followed by destroying the |
10286 | QRhi. A new QRhi can then be attempted to be created. If successful, all |
10287 | graphics resources must be reinitialized. If not, try again later, |
10288 | repeatedly. |
10289 | |
10290 | While simple applications may decide to not care about device loss, |
10291 | on the commonly used desktop platforms a device loss can happen |
10292 | due to a variety of reasons, including physically disconnecting the |
10293 | graphics adapter, disabling the device or driver, uninstalling or upgrading |
10294 | the graphics driver, or due to errors that lead to a graphics device reset. |
10295 | Some of these can happen under perfectly normal circumstances as well, for |
10296 | example the upgrade of the graphics driver to a newer version is a common |
10297 | task that can happen at any time while a Qt application is running. Users |
10298 | may very well expect applications to be able to survive this, even when the |
10299 | application is actively using an API like OpenGL or Direct3D. |
10300 | |
10301 | Qt's own frameworks built on top of QRhi, such as, Qt Quick, can be |
10302 | expected to handle and take appropriate measures when a device loss occurs. |
10303 | If the data for graphics resources, such as textures and buffers, are still |
10304 | available on the CPU side, such an event may not be noticeable on the |
10305 | application level at all since graphics resources can seamlessly be |
10306 | reinitialized then. However, applications and libraries working directly |
10307 | with QRhi are expected to be prepared to check and handle device loss |
10308 | situations themselves. |
10309 | |
10310 | \note With OpenGL, applications may need to opt-in to context reset |
10311 | notifications by setting QSurfaceFormat::ResetNotification on the |
10312 | QOpenGLContext. This is typically done by enabling the flag in |
10313 | QRhiGles2InitParams::format. Keep in mind however that some systems may |
10314 | generate context resets situations even when this flag is not set. |
10315 | */ |
10316 | bool QRhi::isDeviceLost() const |
10317 | { |
10318 | return d->isDeviceLost(); |
10319 | } |
10320 | |
10321 | /*! |
10322 | \return a binary data blob with data collected from the |
10323 | QRhiGraphicsPipeline and QRhiComputePipeline successfully created during |
10324 | the lifetime of this QRhi. |
10325 | |
10326 | By saving and then, in subsequent runs of the same application, reloading |
10327 | the cache data, pipeline and shader creation times can potentially be |
10328 | reduced. What exactly the cache and its serialized version includes is not |
10329 | specified, is always specific to the backend used, and in some cases also |
10330 | dependent on the particular implementation of the graphics API. |
10331 | |
10332 | When the PipelineCacheDataLoadSave is reported as unsupported, the returned |
10333 | QByteArray is empty. |
10334 | |
10335 | When the EnablePipelineCacheDataSave flag was not specified when calling |
10336 | create(), the returned QByteArray may be empty, even when the |
10337 | PipelineCacheDataLoadSave feature is supported. |
10338 | |
10339 | When the returned data is non-empty, it is always specific to the Qt |
10340 | version and QRhi backend. In addition, in some cases there is a strong |
10341 | dependency to the graphics device and the exact driver version used. QRhi |
10342 | takes care of adding the appropriate header and safeguards that ensure that |
10343 | the data can always be passed safely to setPipelineCacheData(), therefore |
10344 | attempting to load data from a run on another version of a driver will be |
10345 | handled safely and gracefully. |
10346 | |
10347 | \note Calling releaseCachedResources() may, depending on the backend, clear |
10348 | the pipeline data collected. A subsequent call to this function may then |
10349 | not return any data. |
10350 | |
10351 | See EnablePipelineCacheDataSave for further details about this feature. |
10352 | |
10353 | \note Minimize the number of calls to this function. Retrieving the blob is |
10354 | not always a cheap operation, and therefore this function should only be |
10355 | called at a low frequency, ideally only once e.g. when closing the |
10356 | application. |
10357 | |
10358 | \sa setPipelineCacheData(), create(), isFeatureSupported() |
10359 | */ |
10360 | QByteArray QRhi::pipelineCacheData() |
10361 | { |
10362 | return d->pipelineCacheData(); |
10363 | } |
10364 | |
10365 | /*! |
10366 | Loads \a data into the pipeline cache, when applicable. |
10367 | |
10368 | When the PipelineCacheDataLoadSave is reported as unsupported, the function |
10369 | is safe to call, but has no effect. |
10370 | |
10371 | The blob returned by pipelineCacheData() is always specific to the Qt |
10372 | version, the QRhi backend, and, in some cases, also to the graphics device, |
10373 | and a given version of the graphics driver. QRhi takes care of adding the |
10374 | appropriate header and safeguards that ensure that the data can always be |
10375 | passed safely to this function. If there is a mismatch, e.g. because the |
10376 | driver has been upgraded to a newer version, or because the data was |
10377 | generated from a different QRhi backend, a warning is printed and \a data |
10378 | is safely ignored. |
10379 | |
10380 | With Vulkan, this maps directly to VkPipelineCache. Calling this function |
10381 | creates a new Vulkan pipeline cache object, with its initial data sourced |
10382 | from \a data. The pipeline cache object is then used by all subsequently |
10383 | created QRhiGraphicsPipeline and QRhiComputePipeline objects, thus |
10384 | accelerating, potentially, the pipeline creation. |
10385 | |
10386 | With other APIs there is no real pipeline cache, but they may provide a |
10387 | cache with bytecode from shader compilations (D3D) or program binaries |
10388 | (OpenGL). In applications that perform a lot of shader compilation from |
10389 | source at run time this can provide a significant boost in subsequent runs |
10390 | if the "pipeline cache" is pre-seeded from an earlier run using this |
10391 | function. |
10392 | |
10393 | \note QRhi cannot give any guarantees that \a data has an effect on the |
10394 | pipeline and shader creation performance. With APIs like Vulkan, it is up |
10395 | to the driver to decide if \a data is used for some purpose, or if it is |
10396 | ignored. |
10397 | |
10398 | See EnablePipelineCacheDataSave for further details about this feature. |
10399 | |
10400 | \note This mechanism offered by QRhi is independent of the drivers' own |
10401 | internal caching mechanism, if any. This means that, depending on the |
10402 | graphics API and its implementation, the exact effects of retrieving and |
10403 | then reloading \a data are not predictable. Improved performance may not be |
10404 | visible at all in case other caching mechanisms outside of Qt's control are |
10405 | already active. |
10406 | |
10407 | \note Minimize the number of calls to this function. Loading the blob is |
10408 | not always a cheap operation, and therefore this function should only be |
10409 | called at a low frequency, ideally only once e.g. when starting the |
10410 | application. |
10411 | |
10412 | \sa pipelineCacheData(), isFeatureSupported() |
10413 | */ |
10414 | void QRhi::setPipelineCacheData(const QByteArray &data) |
10415 | { |
10416 | d->setPipelineCacheData(data); |
10417 | } |
10418 | |
10419 | /*! |
10420 | \struct QRhiStats |
10421 | \inmodule QtGuiPrivate |
10422 | \inheaderfile rhi/qrhi.h |
10423 | \since 6.6 |
10424 | |
10425 | \brief Statistics provided from the underlying memory allocator. |
10426 | |
10427 | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
10428 | for details. |
10429 | */ |
10430 | |
10431 | /*! |
10432 | \variable QRhiStats::totalPipelineCreationTime |
10433 | |
10434 | The total time in milliseconds spent in graphics and compute pipeline |
10435 | creation, which usually involves shader compilation or cache lookups, and |
10436 | potentially expensive processing. |
10437 | |
10438 | \note The value should not be compared between different backends since the |
10439 | concept of "pipelines" and what exactly happens under the hood during, for |
10440 | instance, a call to QRhiGraphicsPipeline::create(), differ greatly between |
10441 | graphics APIs and their implementations. |
10442 | |
10443 | \sa QRhi::statistics() |
10444 | */ |
10445 | |
10446 | /*! |
10447 | \variable QRhiStats::blockCount |
10448 | |
10449 | Statistic reported from the Vulkan or D3D12 memory allocator. |
10450 | |
10451 | \sa QRhi::statistics() |
10452 | */ |
10453 | |
10454 | /*! |
10455 | \variable QRhiStats::allocCount |
10456 | |
10457 | Statistic reported from the Vulkan or D3D12 memory allocator. |
10458 | |
10459 | \sa QRhi::statistics() |
10460 | */ |
10461 | |
10462 | /*! |
10463 | \variable QRhiStats::usedBytes |
10464 | |
10465 | Statistic reported from the Vulkan or D3D12 memory allocator. |
10466 | |
10467 | \sa QRhi::statistics() |
10468 | */ |
10469 | |
10470 | /*! |
10471 | \variable QRhiStats::unusedBytes |
10472 | |
10473 | Statistic reported from the Vulkan or D3D12 memory allocator. |
10474 | |
10475 | \sa QRhi::statistics() |
10476 | */ |
10477 | |
10478 | /*! |
10479 | \variable QRhiStats::totalUsageBytes |
10480 | |
10481 | Valid only with D3D12 currently. Matches IDXGIAdapter3::QueryVideoMemoryInfo(). |
10482 | |
10483 | \sa QRhi::statistics() |
10484 | */ |
10485 | |
10486 | #ifndef QT_NO_DEBUG_STREAM |
10487 | QDebug operator<<(QDebug dbg, const QRhiStats &info) |
10488 | { |
10489 | QDebugStateSaver saver(dbg); |
10490 | dbg.nospace() << "QRhiStats(" |
10491 | << "totalPipelineCreationTime="<< info.totalPipelineCreationTime |
10492 | << " blockCount="<< info.blockCount |
10493 | << " allocCount="<< info.allocCount |
10494 | << " usedBytes="<< info.usedBytes |
10495 | << " unusedBytes="<< info.unusedBytes |
10496 | << " totalUsageBytes="<< info.totalUsageBytes |
10497 | << ')'; |
10498 | return dbg; |
10499 | } |
10500 | #endif |
10501 | |
10502 | /*! |
10503 | Gathers and returns statistics about the timings and allocations of |
10504 | graphics resources. |
10505 | |
10506 | Data about memory allocations is only available with some backends, where |
10507 | such operations are under Qt's control. With graphics APIs where there is |
10508 | no lower level control over resource memory allocations, this will never be |
10509 | supported and all relevant fields in the results are 0. |
10510 | |
10511 | With Vulkan in particular, the values are valid always, and are queried |
10512 | from the underlying memory allocator library. This gives an insight into |
10513 | the memory requirements of the active buffers and textures. |
10514 | |
10515 | The same is true for Direct 3D 12. In addition to the memory allocator |
10516 | library's statistics, here the result also includes a \c totalUsageBytes |
10517 | field which reports the total size including additional resources that are |
10518 | not under the memory allocator library's control (swapchain buffers, |
10519 | descriptor heaps, etc.), as reported by DXGI. |
10520 | |
10521 | The values correspond to all types of memory used, combined. (i.e. video + |
10522 | system in case of a discreet GPU) |
10523 | |
10524 | Additional data, such as the total time in milliseconds spent in graphics |
10525 | and compute pipeline creation (which usually involves shader compilation or |
10526 | cache lookups, and potentially expensive processing) is available with most |
10527 | backends. |
10528 | |
10529 | \note The elapsed times for operations such as pipeline creation may be |
10530 | affected by various factors. The results should not be compared between |
10531 | different backends since the concept of "pipelines" and what exactly |
10532 | happens under the hood during, for instance, a call to |
10533 | QRhiGraphicsPipeline::create(), differ greatly between graphics APIs and |
10534 | their implementations. |
10535 | |
10536 | \note Additionally, many drivers will likely employ various caching |
10537 | strategies for shaders, programs, pipelines. (independently of Qt's own |
10538 | similar facilities, such as setPipelineCacheData() or the OpenGL-specific |
10539 | program binary disk cache). Because such internal behavior is transparent |
10540 | to the API client, Qt and QRhi have no knowledge or control over the exact |
10541 | caching strategy, persistency, invalidation of the cached data, etc. When |
10542 | reading timings, such as the time spent on pipeline creation, the potential |
10543 | presence and unspecified behavior of driver-level caching mechanisms should |
10544 | be kept in mind. |
10545 | */ |
10546 | QRhiStats QRhi::statistics() const |
10547 | { |
10548 | return d->statistics(); |
10549 | } |
10550 | |
10551 | /*! |
10552 | \return a new graphics pipeline resource. |
10553 | |
10554 | \sa QRhiResource::destroy() |
10555 | */ |
10556 | QRhiGraphicsPipeline *QRhi::newGraphicsPipeline() |
10557 | { |
10558 | return d->createGraphicsPipeline(); |
10559 | } |
10560 | |
10561 | /*! |
10562 | \return a new compute pipeline resource. |
10563 | |
10564 | \note Compute is only available when the \l{QRhi::Compute}{Compute} feature |
10565 | is reported as supported. |
10566 | |
10567 | \sa QRhiResource::destroy() |
10568 | */ |
10569 | QRhiComputePipeline *QRhi::newComputePipeline() |
10570 | { |
10571 | return d->createComputePipeline(); |
10572 | } |
10573 | |
10574 | /*! |
10575 | \return a new shader resource binding collection resource. |
10576 | |
10577 | \sa QRhiResource::destroy() |
10578 | */ |
10579 | QRhiShaderResourceBindings *QRhi::newShaderResourceBindings() |
10580 | { |
10581 | return d->createShaderResourceBindings(); |
10582 | } |
10583 | |
10584 | /*! |
10585 | \return a new buffer with the specified \a type, \a usage, and \a size. |
10586 | |
10587 | \note Some \a usage and \a type combinations may not be supported by all |
10588 | backends. See \l{QRhiBuffer::UsageFlag}{UsageFlags} and |
10589 | \l{QRhi::NonDynamicUniformBuffers}{the feature flags}. |
10590 | |
10591 | \note Backends may choose to allocate buffers bigger than \a size. This is |
10592 | done transparently to applications, so there are no special restrictions on |
10593 | the value of \a size. QRhiBuffer::size() will always report back the value |
10594 | that was requested in \a size. |
10595 | |
10596 | \sa QRhiResource::destroy() |
10597 | */ |
10598 | QRhiBuffer *QRhi::newBuffer(QRhiBuffer::Type type, |
10599 | QRhiBuffer::UsageFlags usage, |
10600 | quint32 size) |
10601 | { |
10602 | return d->createBuffer(type, usage, size); |
10603 | } |
10604 | |
10605 | /*! |
10606 | \return a new renderbuffer with the specified \a type, \a pixelSize, \a |
10607 | sampleCount, and \a flags. |
10608 | |
10609 | When \a backingFormatHint is set to a texture format other than |
10610 | QRhiTexture::UnknownFormat, it may be used by the backend to decide what |
10611 | format to use for the storage backing the renderbuffer. |
10612 | |
10613 | \note \a backingFormatHint becomes relevant typically when multisampling |
10614 | and floating point texture formats are involved: rendering into a |
10615 | multisample QRhiRenderBuffer and then resolving into a non-RGBA8 |
10616 | QRhiTexture implies (with some graphics APIs) that the storage backing the |
10617 | QRhiRenderBuffer uses the matching non-RGBA8 format. That means that |
10618 | passing a format like QRhiTexture::RGBA32F is important, because backends |
10619 | will typically opt for QRhiTexture::RGBA8 by default, which would then |
10620 | break later on due to attempting to set up RGBA8->RGBA32F multisample |
10621 | resolve in the color attachment(s) of the QRhiTextureRenderTarget. |
10622 | |
10623 | \sa QRhiResource::destroy() |
10624 | */ |
10625 | QRhiRenderBuffer *QRhi::newRenderBuffer(QRhiRenderBuffer::Type type, |
10626 | const QSize &pixelSize, |
10627 | int sampleCount, |
10628 | QRhiRenderBuffer::Flags flags, |
10629 | QRhiTexture::Format backingFormatHint) |
10630 | { |
10631 | return d->createRenderBuffer(type, pixelSize, sampleCount, flags, backingFormatHint); |
10632 | } |
10633 | |
10634 | /*! |
10635 | \return a new 1D or 2D texture with the specified \a format, \a pixelSize, \a |
10636 | sampleCount, and \a flags. |
10637 | |
10638 | A 1D texture array must have QRhiTexture::OneDimensional set in \a flags. This |
10639 | function will implicitly set this flag if the \a pixelSize height is 0. |
10640 | |
10641 | \note \a format specifies the requested internal and external format, |
10642 | meaning the data to be uploaded to the texture will need to be in a |
10643 | compatible format, while the native texture may (but is not guaranteed to, |
10644 | in case of OpenGL at least) use this format internally. |
10645 | |
10646 | \note 1D textures are only functional when the OneDimensionalTextures feature is |
10647 | reported as supported at run time. Further, mipmaps on 1D textures are only |
10648 | functional when the OneDimensionalTextureMipmaps feature is reported at run time. |
10649 | |
10650 | \sa QRhiResource::destroy() |
10651 | */ |
10652 | QRhiTexture *QRhi::newTexture(QRhiTexture::Format format, |
10653 | const QSize &pixelSize, |
10654 | int sampleCount, |
10655 | QRhiTexture::Flags flags) |
10656 | { |
10657 | if (pixelSize.height() == 0) |
10658 | flags |= QRhiTexture::OneDimensional; |
10659 | |
10660 | return d->createTexture(format, pixelSize, depth: 1, arraySize: 0, sampleCount, flags); |
10661 | } |
10662 | |
10663 | /*! |
10664 | \return a new 1D, 2D or 3D texture with the specified \a format, \a width, \a |
10665 | height, \a depth, \a sampleCount, and \a flags. |
10666 | |
10667 | This overload is suitable for 3D textures because it allows specifying \a |
10668 | depth. A 3D texture must have QRhiTexture::ThreeDimensional set in \a |
10669 | flags, but using this overload that can be omitted because the flag is set |
10670 | implicitly whenever \a depth is greater than 0. For 1D, 2D and cube textures \a |
10671 | depth should be set to 0. |
10672 | |
10673 | A 1D texture must have QRhiTexture::OneDimensional set in \a flags. This overload |
10674 | will implicitly set this flag if both \a height and \a depth are 0. |
10675 | |
10676 | \note 3D textures are only functional when the ThreeDimensionalTextures |
10677 | feature is reported as supported at run time. |
10678 | |
10679 | \note 1D textures are only functional when the OneDimensionalTextures feature is |
10680 | reported as supported at run time. Further, mipmaps on 1D textures are only |
10681 | functional when the OneDimensionalTextureMipmaps feature is reported at run time. |
10682 | |
10683 | \overload |
10684 | */ |
10685 | QRhiTexture *QRhi::newTexture(QRhiTexture::Format format, |
10686 | int width, int height, int depth, |
10687 | int sampleCount, |
10688 | QRhiTexture::Flags flags) |
10689 | { |
10690 | if (depth > 0) |
10691 | flags |= QRhiTexture::ThreeDimensional; |
10692 | |
10693 | if (height == 0 && depth == 0) |
10694 | flags |= QRhiTexture::OneDimensional; |
10695 | |
10696 | return d->createTexture(format, pixelSize: QSize(width, height), depth, arraySize: 0, sampleCount, flags); |
10697 | } |
10698 | |
10699 | /*! |
10700 | \return a new 1D or 2D texture array with the specified \a format, \a arraySize, |
10701 | \a pixelSize, \a sampleCount, and \a flags. |
10702 | |
10703 | This function implicitly sets QRhiTexture::TextureArray in \a flags. |
10704 | |
10705 | A 1D texture array must have QRhiTexture::OneDimensional set in \a flags. This |
10706 | function will implicitly set this flag if the \a pixelSize height is 0. |
10707 | |
10708 | \note Do not confuse texture arrays with arrays of textures. A QRhiTexture |
10709 | created by this function is usable with 1D or 2D array samplers in the shader, for |
10710 | example: \c{layout(binding = 1) uniform sampler2DArray texArr;}. Arrays of |
10711 | textures refers to a list of textures that are exposed to the shader via |
10712 | QRhiShaderResourceBinding::sampledTextures() and a count > 1, and declared |
10713 | in the shader for example like this: \c{layout(binding = 1) uniform |
10714 | sampler2D textures[4];} |
10715 | |
10716 | \note This is only functional when the TextureArrays feature is reported as |
10717 | supported at run time. |
10718 | |
10719 | \note 1D textures are only functional when the OneDimensionalTextures feature is |
10720 | reported as supported at run time. Further, mipmaps on 1D textures are only |
10721 | functional when the OneDimensionalTextureMipmaps feature is reported at run time. |
10722 | |
10723 | |
10724 | \sa newTexture() |
10725 | */ |
10726 | QRhiTexture *QRhi::newTextureArray(QRhiTexture::Format format, |
10727 | int arraySize, |
10728 | const QSize &pixelSize, |
10729 | int sampleCount, |
10730 | QRhiTexture::Flags flags) |
10731 | { |
10732 | flags |= QRhiTexture::TextureArray; |
10733 | |
10734 | if (pixelSize.height() == 0) |
10735 | flags |= QRhiTexture::OneDimensional; |
10736 | |
10737 | return d->createTexture(format, pixelSize, depth: 1, arraySize, sampleCount, flags); |
10738 | } |
10739 | |
10740 | /*! |
10741 | \return a new sampler with the specified magnification filter \a magFilter, |
10742 | minification filter \a minFilter, mipmapping mode \a mipmapMode, and the |
10743 | addressing (wrap) modes \a addressU, \a addressV, and \a addressW. |
10744 | |
10745 | \note Setting \a mipmapMode to a value other than \c None implies that |
10746 | images for all relevant mip levels will be provided either via |
10747 | \l{QRhiResourceUpdateBatch::uploadTexture()}{texture uploads} or by calling |
10748 | \l{QRhiResourceUpdateBatch::generateMips()}{generateMips()} on the texture |
10749 | that is used with this sampler. Attempting to use the sampler with a |
10750 | texture that has no data for all relevant mip levels will lead to rendering |
10751 | errors, with the exact behavior dependent on the underlying graphics API. |
10752 | |
10753 | \sa QRhiResource::destroy() |
10754 | */ |
10755 | QRhiSampler *QRhi::newSampler(QRhiSampler::Filter magFilter, |
10756 | QRhiSampler::Filter minFilter, |
10757 | QRhiSampler::Filter mipmapMode, |
10758 | QRhiSampler::AddressMode addressU, |
10759 | QRhiSampler::AddressMode addressV, |
10760 | QRhiSampler::AddressMode addressW) |
10761 | { |
10762 | return d->createSampler(magFilter, minFilter, mipmapMode, u: addressU, v: addressV, w: addressW); |
10763 | } |
10764 | |
10765 | /*! |
10766 | \return a new texture render target with color and depth/stencil |
10767 | attachments given in \a desc, and with the specified \a flags. |
10768 | |
10769 | \sa QRhiResource::destroy() |
10770 | */ |
10771 | |
10772 | QRhiTextureRenderTarget *QRhi::newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, |
10773 | QRhiTextureRenderTarget::Flags flags) |
10774 | { |
10775 | return d->createTextureRenderTarget(desc, flags); |
10776 | } |
10777 | |
10778 | /*! |
10779 | \return a new swapchain. |
10780 | |
10781 | \sa QRhiResource::destroy(), QRhiSwapChain::createOrResize() |
10782 | */ |
10783 | QRhiSwapChain *QRhi::newSwapChain() |
10784 | { |
10785 | return d->createSwapChain(); |
10786 | } |
10787 | |
10788 | /*! |
10789 | Starts a new frame targeting the next available buffer of \a swapChain. |
10790 | |
10791 | A frame consists of resource updates and one or more render and compute |
10792 | passes. |
10793 | |
10794 | \a flags can indicate certain special cases. |
10795 | |
10796 | The high level pattern of rendering into a QWindow using a swapchain: |
10797 | |
10798 | \list |
10799 | |
10800 | \li Create a swapchain. |
10801 | |
10802 | \li Call QRhiSwapChain::createOrResize() whenever the surface size is |
10803 | different than before. |
10804 | |
10805 | \li Call QRhiSwapChain::destroy() on |
10806 | QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed. |
10807 | |
10808 | \li Then on every frame: |
10809 | \badcode |
10810 | beginFrame(sc); |
10811 | updates = nextResourceUpdateBatch(); |
10812 | updates->... |
10813 | QRhiCommandBuffer *cb = sc->currentFrameCommandBuffer(); |
10814 | cb->beginPass(sc->currentFrameRenderTarget(), colorClear, dsClear, updates); |
10815 | ... |
10816 | cb->endPass(); |
10817 | ... // more passes as necessary |
10818 | endFrame(sc); |
10819 | \endcode |
10820 | |
10821 | \endlist |
10822 | |
10823 | \return QRhi::FrameOpSuccess on success, or another QRhi::FrameOpResult |
10824 | value on failure. Some of these should be treated as soft, "try again |
10825 | later" type of errors: When QRhi::FrameOpSwapChainOutOfDate is returned, |
10826 | the swapchain is to be resized or updated by calling |
10827 | QRhiSwapChain::createOrResize(). The application should then attempt to |
10828 | generate a new frame. QRhi::FrameOpDeviceLost means the graphics device is |
10829 | lost but this may also be recoverable by releasing all resources, including |
10830 | the QRhi itself, and then recreating all resources. See isDeviceLost() for |
10831 | further discussion. |
10832 | |
10833 | \sa endFrame(), beginOffscreenFrame(), isDeviceLost() |
10834 | */ |
10835 | QRhi::FrameOpResult QRhi::beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags flags) |
10836 | { |
10837 | if (d->inFrame) |
10838 | qWarning(msg: "Attempted to call beginFrame() within a still active frame; ignored"); |
10839 | |
10840 | if (d->rubLogEnabled) |
10841 | qDebug(msg: "[rub] new frame"); |
10842 | |
10843 | QRhi::FrameOpResult r = !d->inFrame ? d->beginFrame(swapChain, flags) : FrameOpSuccess; |
10844 | if (r == FrameOpSuccess) |
10845 | d->inFrame = true; |
10846 | |
10847 | return r; |
10848 | } |
10849 | |
10850 | /*! |
10851 | Ends, commits, and presents a frame that was started in the last |
10852 | beginFrame() on \a swapChain. |
10853 | |
10854 | Double (or triple) buffering is managed internally by the QRhiSwapChain and |
10855 | QRhi. |
10856 | |
10857 | \a flags can optionally be used to change the behavior in certain ways. |
10858 | Passing QRhi::SkipPresent skips queuing the Present command or calling |
10859 | swapBuffers. |
10860 | |
10861 | \return QRhi::FrameOpSuccess on success, or another QRhi::FrameOpResult |
10862 | value on failure. Some of these should be treated as soft, "try again |
10863 | later" type of errors: When QRhi::FrameOpSwapChainOutOfDate is returned, |
10864 | the swapchain is to be resized or updated by calling |
10865 | QRhiSwapChain::createOrResize(). The application should then attempt to |
10866 | generate a new frame. QRhi::FrameOpDeviceLost means the graphics device is |
10867 | lost but this may also be recoverable by releasing all resources, including |
10868 | the QRhi itself, and then recreating all resources. See isDeviceLost() for |
10869 | further discussion. |
10870 | |
10871 | \sa beginFrame(), isDeviceLost() |
10872 | */ |
10873 | QRhi::FrameOpResult QRhi::endFrame(QRhiSwapChain *swapChain, EndFrameFlags flags) |
10874 | { |
10875 | if (!d->inFrame) |
10876 | qWarning(msg: "Attempted to call endFrame() without an active frame; ignored"); |
10877 | |
10878 | QRhi::FrameOpResult r = d->inFrame ? d->endFrame(swapChain, flags) : FrameOpSuccess; |
10879 | d->inFrame = false; |
10880 | // deleteLater is a high level QRhi concept the backends know |
10881 | // nothing about - handle it here. |
10882 | qDeleteAll(c: d->pendingDeleteResources); |
10883 | d->pendingDeleteResources.clear(); |
10884 | |
10885 | return r; |
10886 | } |
10887 | |
10888 | /*! |
10889 | \return true when there is an active frame, meaning there was a |
10890 | beginFrame() (or beginOffscreenFrame()) with no corresponding endFrame() |
10891 | (or endOffscreenFrame()) yet. |
10892 | |
10893 | \sa currentFrameSlot(), beginFrame(), endFrame() |
10894 | */ |
10895 | bool QRhi::isRecordingFrame() const |
10896 | { |
10897 | return d->inFrame; |
10898 | } |
10899 | |
10900 | /*! |
10901 | \return the current frame slot index while recording a frame. Unspecified |
10902 | when called outside an active frame (that is, when isRecordingFrame() is \c |
10903 | false). |
10904 | |
10905 | With backends like Vulkan or Metal, it is the responsibility of the QRhi |
10906 | backend to block whenever starting a new frame and finding the CPU is |
10907 | already \c{FramesInFlight - 1} frames ahead of the GPU (because the command |
10908 | buffer submitted in frame no. \c{current} - \c{FramesInFlight} has not yet |
10909 | completed). |
10910 | |
10911 | Resources that tend to change between frames (such as, the native buffer |
10912 | object backing a QRhiBuffer with type QRhiBuffer::Dynamic) exist in |
10913 | multiple versions, so that each frame, that can be submitted while a |
10914 | previous one is still being processed, works with its own copy, thus |
10915 | avoiding the need to stall the pipeline when preparing the frame. (The |
10916 | contents of a resource that may still be in use in the GPU should not be |
10917 | touched, but simply always waiting for the previous frame to finish would |
10918 | reduce GPU utilization and ultimately, performance and efficiency.) |
10919 | |
10920 | Conceptually this is somewhat similar to copy-on-write schemes used by some |
10921 | C++ containers and other types. It may also be similar to what an OpenGL or |
10922 | Direct 3D 11 implementation performs internally for certain type of objects. |
10923 | |
10924 | In practice, such double (or triple) buffering resources is realized in |
10925 | the Vulkan, Metal, and similar QRhi backends by having a fixed number of |
10926 | native resource (such as, VkBuffer) \c slots behind a QRhiResource. That |
10927 | can then be indexed by a frame slot index running 0, 1, .., |
10928 | FramesInFlight-1, and then wrapping around. |
10929 | |
10930 | All this is managed transparently to the users of QRhi. However, |
10931 | applications that integrate rendering done directly with the graphics API |
10932 | may want to perform a similar double or triple buffering of their own |
10933 | graphics resources. That is then most easily achieved by knowing the values |
10934 | of the maximum number of in-flight frames (retrievable via resourceLimit()) |
10935 | and the current frame (slot) index (returned by this function). |
10936 | |
10937 | \sa isRecordingFrame(), beginFrame(), endFrame() |
10938 | */ |
10939 | int QRhi::currentFrameSlot() const |
10940 | { |
10941 | return d->currentFrameSlot; |
10942 | } |
10943 | |
10944 | /*! |
10945 | Starts a new offscreen frame. Provides a command buffer suitable for |
10946 | recording rendering commands in \a cb. \a flags is used to indicate |
10947 | certain special cases, just like with beginFrame(). |
10948 | |
10949 | \note The QRhiCommandBuffer stored to *cb is not owned by the caller. |
10950 | |
10951 | Rendering without a swapchain is possible as well. The typical use case is |
10952 | to use it in completely offscreen applications, e.g. to generate image |
10953 | sequences by rendering and reading back without ever showing a window. |
10954 | |
10955 | Usage in on-screen applications (so beginFrame, endFrame, |
10956 | beginOffscreenFrame, endOffscreenFrame, beginFrame, ...) is possible too |
10957 | but it does reduce parallelism so it should be done only infrequently. |
10958 | |
10959 | Offscreen frames do not let the CPU potentially generate another frame |
10960 | while the GPU is still processing the previous one. This has the side |
10961 | effect that if readbacks are scheduled, the results are guaranteed to be |
10962 | available once endOffscreenFrame() returns. That is not the case with |
10963 | frames targeting a swapchain: there the GPU is potentially better utilized, |
10964 | but working with readback operations needs more care from the application |
10965 | because endFrame(), unlike endOffscreenFrame(), does not guarantee that the |
10966 | results from the readback are available at that point. |
10967 | |
10968 | The skeleton of rendering a frame without a swapchain and then reading the |
10969 | frame contents back could look like the following: |
10970 | |
10971 | \code |
10972 | QRhiReadbackResult rbResult; |
10973 | QRhiCommandBuffer *cb; |
10974 | rhi->beginOffscreenFrame(&cb); |
10975 | cb->beginPass(rt, colorClear, dsClear); |
10976 | // ... |
10977 | u = nextResourceUpdateBatch(); |
10978 | u->readBackTexture(rb, &rbResult); |
10979 | cb->endPass(u); |
10980 | rhi->endOffscreenFrame(); |
10981 | // image data available in rbResult |
10982 | \endcode |
10983 | |
10984 | \sa endOffscreenFrame(), beginFrame() |
10985 | */ |
10986 | QRhi::FrameOpResult QRhi::beginOffscreenFrame(QRhiCommandBuffer **cb, BeginFrameFlags flags) |
10987 | { |
10988 | if (d->inFrame) |
10989 | qWarning(msg: "Attempted to call beginOffscreenFrame() within a still active frame; ignored"); |
10990 | |
10991 | if (d->rubLogEnabled) |
10992 | qDebug(msg: "[rub] new offscreen frame"); |
10993 | |
10994 | QRhi::FrameOpResult r = !d->inFrame ? d->beginOffscreenFrame(cb, flags) : FrameOpSuccess; |
10995 | if (r == FrameOpSuccess) |
10996 | d->inFrame = true; |
10997 | |
10998 | return r; |
10999 | } |
11000 | |
11001 | /*! |
11002 | Ends, submits, and waits for the offscreen frame. |
11003 | |
11004 | \a flags is not currently used. |
11005 | |
11006 | \sa beginOffscreenFrame() |
11007 | */ |
11008 | QRhi::FrameOpResult QRhi::endOffscreenFrame(EndFrameFlags flags) |
11009 | { |
11010 | if (!d->inFrame) |
11011 | qWarning(msg: "Attempted to call endOffscreenFrame() without an active frame; ignored"); |
11012 | |
11013 | QRhi::FrameOpResult r = d->inFrame ? d->endOffscreenFrame(flags) : FrameOpSuccess; |
11014 | d->inFrame = false; |
11015 | qDeleteAll(c: d->pendingDeleteResources); |
11016 | d->pendingDeleteResources.clear(); |
11017 | |
11018 | return r; |
11019 | } |
11020 | |
11021 | /*! |
11022 | Waits for any work on the graphics queue (where applicable) to complete, |
11023 | then executes all deferred operations, like completing readbacks and |
11024 | resource releases. Can be called inside and outside of a frame, but not |
11025 | inside a pass. Inside a frame it implies submitting any work on the |
11026 | command buffer. |
11027 | |
11028 | \note Avoid this function. One case where it may be needed is when the |
11029 | results of an enqueued readback in a swapchain-based frame are needed at a |
11030 | fixed given point and so waiting for the results is desired. |
11031 | */ |
11032 | QRhi::FrameOpResult QRhi::finish() |
11033 | { |
11034 | return d->finish(); |
11035 | } |
11036 | |
11037 | /*! |
11038 | \return the list of supported sample counts. |
11039 | |
11040 | A typical example would be (1, 2, 4, 8). |
11041 | |
11042 | With some backend this list of supported values is fixed in advance, while |
11043 | with some others the (physical) device properties indicate what is |
11044 | supported at run time. |
11045 | |
11046 | \sa QRhiRenderBuffer::setSampleCount(), QRhiTexture::setSampleCount(), |
11047 | QRhiGraphicsPipeline::setSampleCount(), QRhiSwapChain::setSampleCount() |
11048 | */ |
11049 | QList<int> QRhi::supportedSampleCounts() const |
11050 | { |
11051 | return d->supportedSampleCounts(); |
11052 | } |
11053 | |
11054 | /*! |
11055 | \return the minimum uniform buffer offset alignment in bytes. This is |
11056 | typically 256. |
11057 | |
11058 | Attempting to bind a uniform buffer region with an offset not aligned to |
11059 | this value will lead to failures depending on the backend and the |
11060 | underlying graphics API. |
11061 | |
11062 | \sa ubufAligned() |
11063 | */ |
11064 | int QRhi::ubufAlignment() const |
11065 | { |
11066 | return d->ubufAlignment(); |
11067 | } |
11068 | |
11069 | Q_CONSTINIT static QBasicAtomicInteger<QRhiGlobalObjectIdGenerator::Type> counter = Q_BASIC_ATOMIC_INITIALIZER(0); |
11070 | |
11071 | QRhiGlobalObjectIdGenerator::Type QRhiGlobalObjectIdGenerator::newId() |
11072 | { |
11073 | return counter.fetchAndAddRelaxed(valueToAdd: 1) + 1; |
11074 | } |
11075 | |
11076 | bool QRhiPassResourceTracker::isEmpty() const |
11077 | { |
11078 | return m_buffers.isEmpty() && m_textures.isEmpty(); |
11079 | } |
11080 | |
11081 | void QRhiPassResourceTracker::reset() |
11082 | { |
11083 | m_buffers.clear(); |
11084 | m_textures.clear(); |
11085 | } |
11086 | |
11087 | static inline QRhiPassResourceTracker::BufferStage earlierStage(QRhiPassResourceTracker::BufferStage a, |
11088 | QRhiPassResourceTracker::BufferStage b) |
11089 | { |
11090 | return QRhiPassResourceTracker::BufferStage(qMin(a: int(a), b: int(b))); |
11091 | } |
11092 | |
11093 | void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage, |
11094 | const UsageState &state) |
11095 | { |
11096 | auto it = m_buffers.find(key: buf); |
11097 | if (it != m_buffers.end()) { |
11098 | if (it->access != *access) { |
11099 | const QByteArray name = buf->name(); |
11100 | qWarning(msg: "Buffer %p (%s) used with different accesses within the same pass, this is not allowed.", |
11101 | buf, name.constData()); |
11102 | return; |
11103 | } |
11104 | if (it->stage != *stage) { |
11105 | it->stage = earlierStage(a: it->stage, b: *stage); |
11106 | *stage = it->stage; |
11107 | } |
11108 | return; |
11109 | } |
11110 | |
11111 | Buffer b; |
11112 | b.slot = slot; |
11113 | b.access = *access; |
11114 | b.stage = *stage; |
11115 | b.stateAtPassBegin = state; // first use -> initial state |
11116 | m_buffers.insert(key: buf, value: b); |
11117 | } |
11118 | |
11119 | static inline QRhiPassResourceTracker::TextureStage earlierStage(QRhiPassResourceTracker::TextureStage a, |
11120 | QRhiPassResourceTracker::TextureStage b) |
11121 | { |
11122 | return QRhiPassResourceTracker::TextureStage(qMin(a: int(a), b: int(b))); |
11123 | } |
11124 | |
11125 | static inline bool isImageLoadStore(QRhiPassResourceTracker::TextureAccess access) |
11126 | { |
11127 | return access == QRhiPassResourceTracker::TexStorageLoad |
11128 | || access == QRhiPassResourceTracker::TexStorageStore |
11129 | || access == QRhiPassResourceTracker::TexStorageLoadStore; |
11130 | } |
11131 | |
11132 | void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage, |
11133 | const UsageState &state) |
11134 | { |
11135 | auto it = m_textures.find(key: tex); |
11136 | if (it != m_textures.end()) { |
11137 | if (it->access != *access) { |
11138 | // Different subresources of a texture may be used for both load |
11139 | // and store in the same pass. (think reading from one mip level |
11140 | // and writing to another one in a compute shader) This we can |
11141 | // handle by treating the entire resource as read-write. |
11142 | if (isImageLoadStore(access: it->access) && isImageLoadStore(access: *access)) { |
11143 | it->access = QRhiPassResourceTracker::TexStorageLoadStore; |
11144 | *access = it->access; |
11145 | } else { |
11146 | const QByteArray name = tex->name(); |
11147 | qWarning(msg: "Texture %p (%s) used with different accesses within the same pass, this is not allowed.", |
11148 | tex, name.constData()); |
11149 | } |
11150 | } |
11151 | if (it->stage != *stage) { |
11152 | it->stage = earlierStage(a: it->stage, b: *stage); |
11153 | *stage = it->stage; |
11154 | } |
11155 | return; |
11156 | } |
11157 | |
11158 | Texture t; |
11159 | t.access = *access; |
11160 | t.stage = *stage; |
11161 | t.stateAtPassBegin = state; // first use -> initial state |
11162 | m_textures.insert(key: tex, value: t); |
11163 | } |
11164 | |
11165 | QRhiPassResourceTracker::BufferStage QRhiPassResourceTracker::toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages) |
11166 | { |
11167 | // pick the earlier stage (as this is going to be dstAccessMask) |
11168 | if (stages.testFlag(flag: QRhiShaderResourceBinding::VertexStage)) |
11169 | return QRhiPassResourceTracker::BufVertexStage; |
11170 | if (stages.testFlag(flag: QRhiShaderResourceBinding::TessellationControlStage)) |
11171 | return QRhiPassResourceTracker::BufTCStage; |
11172 | if (stages.testFlag(flag: QRhiShaderResourceBinding::TessellationEvaluationStage)) |
11173 | return QRhiPassResourceTracker::BufTEStage; |
11174 | if (stages.testFlag(flag: QRhiShaderResourceBinding::FragmentStage)) |
11175 | return QRhiPassResourceTracker::BufFragmentStage; |
11176 | if (stages.testFlag(flag: QRhiShaderResourceBinding::ComputeStage)) |
11177 | return QRhiPassResourceTracker::BufComputeStage; |
11178 | if (stages.testFlag(flag: QRhiShaderResourceBinding::GeometryStage)) |
11179 | return QRhiPassResourceTracker::BufGeometryStage; |
11180 | |
11181 | Q_UNREACHABLE_RETURN(QRhiPassResourceTracker::BufVertexStage); |
11182 | } |
11183 | |
11184 | QRhiPassResourceTracker::TextureStage QRhiPassResourceTracker::toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages) |
11185 | { |
11186 | // pick the earlier stage (as this is going to be dstAccessMask) |
11187 | if (stages.testFlag(flag: QRhiShaderResourceBinding::VertexStage)) |
11188 | return QRhiPassResourceTracker::TexVertexStage; |
11189 | if (stages.testFlag(flag: QRhiShaderResourceBinding::TessellationControlStage)) |
11190 | return QRhiPassResourceTracker::TexTCStage; |
11191 | if (stages.testFlag(flag: QRhiShaderResourceBinding::TessellationEvaluationStage)) |
11192 | return QRhiPassResourceTracker::TexTEStage; |
11193 | if (stages.testFlag(flag: QRhiShaderResourceBinding::FragmentStage)) |
11194 | return QRhiPassResourceTracker::TexFragmentStage; |
11195 | if (stages.testFlag(flag: QRhiShaderResourceBinding::ComputeStage)) |
11196 | return QRhiPassResourceTracker::TexComputeStage; |
11197 | if (stages.testFlag(flag: QRhiShaderResourceBinding::GeometryStage)) |
11198 | return QRhiPassResourceTracker::TexGeometryStage; |
11199 | |
11200 | Q_UNREACHABLE_RETURN(QRhiPassResourceTracker::TexVertexStage); |
11201 | } |
11202 | |
11203 | QT_END_NAMESPACE |
11204 |
Definitions
- QRHI_LOG_INFO
- QRHI_LOG_RUB
- QRhiDepthStencilClearValue
- operator<<
- QRhiViewport
- operator<<
- QRhiScissor
- operator<<
- QRhiVertexInputBinding
- operator<<
- QRhiVertexInputAttribute
- operator<<
- shaderDescVariableFormatToVertexInputFormat
- byteSizePerVertexForVertexInputFormat
- operator<<
- QRhiShaderStage
- operator<<
- QRhiColorAttachment
- QRhiColorAttachment
- QRhiTextureRenderTargetDescription
- QRhiTextureRenderTargetDescription
- QRhiTextureRenderTargetDescription
- QRhiTextureSubresourceUploadDescription
- QRhiTextureSubresourceUploadDescription
- QRhiTextureSubresourceUploadDescription
- QRhiTextureUploadEntry
- QRhiTextureUploadDescription
- QRhiTextureUploadDescription
- QRhiReadbackDescription
- QRhiResource
- ~QRhiResource
- deleteLater
- name
- setName
- globalResourceId
- rhi
- QRhiBuffer
- resourceType
- nativeBuffer
- beginFullDynamicBufferUpdateForCurrentFrame
- endFullDynamicBufferUpdateForCurrentFrame
- fullDynamicBufferUpdateForCurrentFrame
- QRhiRenderBuffer
- resourceType
- createFrom
- QRhiTexture
- resourceType
- nativeTexture
- createFrom
- setNativeLayout
- QRhiSampler
- resourceType
- QRhiRenderPassDescriptor
- resourceType
- nativeHandles
- QRhiRenderTarget
- QRhiSwapChainRenderTarget
- resourceType
- QRhiTextureRenderTarget
- resourceType
- QRhiShaderResourceBindings
- resourceType
- isLayoutCompatible
- updateLayoutDesc
- isLayoutCompatible
- uniformBuffer
- uniformBuffer
- uniformBufferWithDynamicOffset
- sampledTexture
- sampledTextures
- texture
- textures
- sampler
- imageLoad
- imageStore
- imageLoadStore
- bufferLoad
- bufferLoad
- bufferStore
- bufferStore
- bufferLoadStore
- bufferLoadStore
- operator==
- operator!=
- qHash
- operator<<
- operator<<
- QRhiGraphicsPipeline
- resourceType
- QRhiSwapChain
- resourceType
- currentFrameRenderTarget
- hdrInfo
- operator<<
- resourceType
- QRhiComputePipeline
- QRhiCommandBuffer
- resourceType
- resourceTypeStr
- ~QRhiImplementation
- isCompressedFormat
- compressedFormatInfo
- textureFormatInfo
- isStencilSupportingFormat
- sanityCheckGraphicsPipeline
- sanityCheckShaderResourceBindings
- effectiveSampleCount
- QRhi
- ~QRhi
- rubLogEnabled
- prepareForCreate
- create
- probe
- updateSwapChainProxyData
- backend
- backendName
- backendName
- deviceTypeStr
- operator<<
- driverInfo
- thread
- addCleanupCallback
- addCleanupCallback
- removeCleanupCallback
- runCleanup
- QRhiResourceUpdateBatch
- ~QRhiResourceUpdateBatch
- release
- merge
- hasOptimalCapacity
- updateDynamicBuffer
- uploadStaticBuffer
- uploadStaticBuffer
- readBackBuffer
- uploadTexture
- uploadTexture
- copyTexture
- readBackTexture
- generateMips
- nextResourceUpdateBatch
- free
- merge
- hasOptimalCapacity
- trimOpLists
- resourceUpdate
- beginPass
- endPass
- setGraphicsPipeline
- setShaderResources
- setVertexInput
- setViewport
- setScissor
- setBlendConstants
- setStencilRef
- draw
- drawIndexed
- debugMarkBegin
- debugMarkEnd
- debugMarkMsg
- beginComputePass
- endComputePass
- setComputePipeline
- dispatch
- nativeHandles
- beginExternal
- endExternal
- lastCompletedGpuTime
- ubufAligned
- mipLevelsForSize
- sizeForMipLevel
- isYUpInFramebuffer
- isYUpInNDC
- isClipDepthZeroToOne
- clipSpaceCorrMatrix
- isTextureFormatSupported
- isFeatureSupported
- resourceLimit
- nativeHandles
- makeThreadLocalNativeContextCurrent
- releaseCachedResources
- isDeviceLost
- pipelineCacheData
- setPipelineCacheData
- operator<<
- statistics
- newGraphicsPipeline
- newComputePipeline
- newShaderResourceBindings
- newBuffer
- newRenderBuffer
- newTexture
- newTexture
- newTextureArray
- newSampler
- newTextureRenderTarget
- newSwapChain
- beginFrame
- endFrame
- isRecordingFrame
- currentFrameSlot
- beginOffscreenFrame
- endOffscreenFrame
- finish
- supportedSampleCounts
- ubufAlignment
- counter
- newId
- isEmpty
- reset
- earlierStage
- registerBuffer
- earlierStage
- isImageLoadStore
- registerTexture
- toPassTrackerBufferStage
Learn to use CMake with our Intro Training
Find out more