/src/qtbase/src/gui/rhi/qrhi.cpp
Line | Count | Source |
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 | | // Qt-Security score:significant reason:default |
4 | | |
5 | | #include "qrhi_p.h" |
6 | | #include <qmath.h> |
7 | | #include <QLoggingCategory> |
8 | | #include "private/qloggingregistry_p.h" |
9 | | |
10 | | #include "qrhinull_p.h" |
11 | | #ifndef QT_NO_OPENGL |
12 | | #include "qrhigles2_p.h" |
13 | | #endif |
14 | | #if QT_CONFIG(vulkan) |
15 | | #include "qrhivulkan_p.h" |
16 | | #endif |
17 | | #ifdef Q_OS_WIN |
18 | | #include "qrhid3d11_p.h" |
19 | | #include "qrhid3d12_p.h" |
20 | | #endif |
21 | | #if QT_CONFIG(metal) |
22 | | #include "qrhimetal_p.h" |
23 | | #endif |
24 | | |
25 | | #include <memory> |
26 | | |
27 | | QT_BEGIN_NAMESPACE |
28 | | |
29 | | // Play nice with QSG_INFO since that is still the most commonly used |
30 | | // way to get graphics info printed from Qt Quick apps, and the Quick |
31 | | // scenegraph is our primary user. |
32 | | Q_LOGGING_CATEGORY_WITH_ENV_OVERRIDE(QRHI_LOG_INFO, "QSG_INFO", "qt.rhi.general") |
33 | | |
34 | | Q_LOGGING_CATEGORY(QRHI_LOG_RUB, "qt.rhi.rub") |
35 | | |
36 | | /*! |
37 | | \class QRhi |
38 | | \ingroup painting-3D |
39 | | \inmodule QtGuiPrivate |
40 | | \inheaderfile rhi/qrhi.h |
41 | | \since 6.6 |
42 | | |
43 | | \brief Accelerated 2D/3D graphics API abstraction. |
44 | | |
45 | | The Qt Rendering Hardware Interface is an abstraction for hardware accelerated |
46 | | graphics APIs, such as, \l{https://www.khronos.org/opengl/}{OpenGL}, |
47 | | \l{https://www.khronos.org/opengles/}{OpenGL ES}, |
48 | | \l{https://docs.microsoft.com/en-us/windows/desktop/direct3d}{Direct3D}, |
49 | | \l{https://developer.apple.com/metal/}{Metal}, and |
50 | | \l{https://www.khronos.org/vulkan/}{Vulkan}. |
51 | | |
52 | | \warning The QRhi family of classes in the Qt Gui module, including QShader |
53 | | and QShaderDescription, offer limited compatibility guarantees. There are |
54 | | no source or binary compatibility guarantees for these classes, meaning the |
55 | | API is only guaranteed to work with the Qt version the application was |
56 | | developed against. Source incompatible changes are however aimed to be kept |
57 | | at a minimum and will only be made in minor releases (6.7, 6.8, and so on). |
58 | | To use these classes in an application, link to |
59 | | \c{Qt::GuiPrivate} (if using CMake), and include the headers with the \c |
60 | | rhi prefix, for example \c{#include <rhi/qrhi.h>}. |
61 | | |
62 | | Each QRhi instance is backed by a backend for a specific graphics API. The |
63 | | selection of the backend is a run time choice and is up to the application |
64 | | or library that creates the QRhi instance. Some backends are available on |
65 | | multiple platforms (OpenGL, Vulkan, Null), while APIs specific to a given |
66 | | platform are only available when running on the platform in question (Metal |
67 | | on macOS/iOS, Direct3D on Windows). |
68 | | |
69 | | The available backends currently are: |
70 | | |
71 | | \list |
72 | | |
73 | | \li OpenGL 2.1 / OpenGL ES 2.0 or newer. Some extensions and newer core |
74 | | specification features are utilized when present, for example to enable |
75 | | multisample framebuffers or compute shaders. Operating in core profile |
76 | | contexts is supported as well. If necessary, applications can query the |
77 | | \l{QRhi::Feature}{feature flags} at runtime to check for features that are |
78 | | not supported in the OpenGL context backing the QRhi. The OpenGL backend |
79 | | builds on QOpenGLContext, QOpenGLFunctions, and the related cross-platform |
80 | | infrastructure of the Qt GUI module. |
81 | | |
82 | | \li Direct3D 11.2 and newer (with DXGI 1.3 and newer), using Shader Model |
83 | | 5.0 or newer. When the D3D runtime has no support for 11.2 features or |
84 | | Shader Model 5.0, initialization using an accelerated graphics device will |
85 | | fail, but using the |
86 | | \l{https://learn.microsoft.com/en-us/windows/win32/direct3darticles/directx-warp}{software |
87 | | adapter} is still an option. |
88 | | |
89 | | \li Direct3D 12 on Windows 10 version 1703 and newer, with Shader Model 5.0 |
90 | | or newer. Qt requires ID3D12Device2 to be present, hence the requirement |
91 | | for at least version 1703 of Windows 10. The D3D12 device is by default |
92 | | created with specifying a minimum feature level of |
93 | | \c{D3D_FEATURE_LEVEL_11_0}. |
94 | | |
95 | | \li Metal 1.2 or newer. |
96 | | |
97 | | \li Vulkan 1.0 or newer, optionally utilizing some Vulkan 1.1 level |
98 | | features. |
99 | | |
100 | | \li Null, a "dummy" backend that issues no graphics calls at all. |
101 | | |
102 | | \endlist |
103 | | |
104 | | In order to allow shader code to be written once in Qt applications and |
105 | | libraries, all shaders are expected to be written in a single language |
106 | | which is then compiled into SPIR-V. Versions for various shading language |
107 | | are then generated from that, together with reflection information (inputs, |
108 | | outputs, shader resources). This is then packed into easily and efficiently |
109 | | serializable QShader instances. The compilers and tools to generate such |
110 | | shaders are not part of QRhi and the Qt GUI module, but the core classes |
111 | | for using such shaders, QShader and QShaderDescription, are. The APIs and |
112 | | tools for performing compilation and translation are part of the Qt Shader |
113 | | Tools module. |
114 | | |
115 | | See the \l{RHI Window Example} for an introductory example of creating a |
116 | | portable, cross-platform application that performs accelerated 3D rendering |
117 | | onto a QWindow using QRhi. |
118 | | |
119 | | \section1 An Impression of the API |
120 | | |
121 | | To provide a quick look at the API with a short yet complete example that |
122 | | does not involve window-related setup, the following is a complete, |
123 | | runnable cross-platform application that renders 20 frames off-screen, and |
124 | | then saves the generated images to files after reading back the texture |
125 | | contents from the GPU. For an example that renders on-screen, which then |
126 | | involves setting up a QWindow and a swapchain, refer to the |
127 | | \l{RHI Window Example}. |
128 | | |
129 | | For brevity, the initialization of the QRhi is done based on the platform: |
130 | | the sample code here chooses Direct 3D 12 on Windows, Metal on macOS and |
131 | | iOS, and Vulkan otherwise. OpenGL and Direct 3D 11 are never used by this |
132 | | application, but support for those could be introduced with a few |
133 | | additional lines. |
134 | | |
135 | | \snippet rhioffscreen/main.cpp 0 |
136 | | |
137 | | The result of the application is 20 \c PNG images (frame0.png - |
138 | | frame19.png). These contain a rotating triangle with varying opacity over a |
139 | | green background. |
140 | | |
141 | | The vertex and fragment shaders are expected to be processed and packaged |
142 | | into \c{.qsb} files. The Vulkan-compatible GLSL source code is the |
143 | | following: |
144 | | |
145 | | \e color.vert |
146 | | \snippet rhioffscreen/color.vert 0 |
147 | | |
148 | | \e color.frag |
149 | | \snippet rhioffscreen/color.frag 0 |
150 | | |
151 | | To manually compile and transpile these shaders to a number of targets |
152 | | (SPIR-V, HLSL, MSL, GLSL) and generate the \c{.qsb} files the application |
153 | | loads at run time, run \c{qsb --qt6 color.vert -o color.vert.qsb} and |
154 | | \c{qsb --qt6 color.frag -o color.frag.qsb}. Alternatively, the Qt Shader |
155 | | Tools module offers build system integration for CMake, the |
156 | | \c qt_add_shaders() CMake function, that can achieve the same at build time. |
157 | | |
158 | | \section1 Security Considerations |
159 | | |
160 | | All data consumed by QRhi and related classes such as QShader are considered |
161 | | trusted content. |
162 | | |
163 | | \warning Application developers are advised to carefully consider the |
164 | | potential implications before allowing the feeding of user-provided content |
165 | | that is not part of the application and is not under the developers' |
166 | | control. (this includes all vertex/index data, shaders, pipeline and draw |
167 | | call parameters, etc.) |
168 | | |
169 | | \section1 Design Fundamentals |
170 | | |
171 | | A QRhi cannot be instantiated directly. Instead, use the create() |
172 | | function. Delete the QRhi instance normally to release the graphics device. |
173 | | |
174 | | \section2 Resources |
175 | | |
176 | | Instances of classes deriving from QRhiResource, such as, QRhiBuffer, |
177 | | QRhiTexture, etc., encapsulate zero, one, or more native graphics |
178 | | resources. Instances of such classes are always created via the \c new |
179 | | functions of the QRhi, such as, newBuffer(), newTexture(), |
180 | | newTextureRenderTarget(), newSwapChain(). |
181 | | |
182 | | \code |
183 | | QRhiBuffer *vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)); |
184 | | if (!vbuf->create()) { error(); } |
185 | | // ... |
186 | | delete vbuf; |
187 | | \endcode |
188 | | |
189 | | \list |
190 | | |
191 | | \li The returned value from functions like newBuffer() is always owned by |
192 | | the caller. |
193 | | |
194 | | \li Just creating an instance of a QRhiResource subclass never allocates or |
195 | | initializes any native resources. That is only done when calling the |
196 | | \c create() function of a subclass, for example, QRhiBuffer::create() or |
197 | | QRhiTexture::create(). |
198 | | |
199 | | \li The exceptions are |
200 | | QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor(), |
201 | | QRhiSwapChain::newCompatibleRenderPassDescriptor(), and |
202 | | QRhiRenderPassDescriptor::newCompatibleRenderPassDescriptor(). There is no |
203 | | \c create() operation for these and the returned object is immediately |
204 | | active. |
205 | | |
206 | | \li The resource objects themselves are treated as immutable: once a |
207 | | resource has create() called, changing any parameters via the setters, such as, |
208 | | QRhiTexture::setPixelSize(), has no effect, unless the underlying native |
209 | | resource is released and \c create() is called again. See more about resource |
210 | | reuse in the sections below. |
211 | | |
212 | | \li The underlying native resources are scheduled for releasing by the |
213 | | QRhiResource destructor, or by calling QRhiResource::destroy(). Backends |
214 | | often queue release requests and defer executing them to an unspecified |
215 | | time, this is hidden from the applications. This way applications do not |
216 | | have to worry about releasing native resources that may still be in use by |
217 | | an in-flight frame. |
218 | | |
219 | | \li Note that this does not mean that a QRhiResource can freely be |
220 | | destroy()'ed or deleted within a frame (that is, in a |
221 | | \l{QRhi::beginFrame()}{beginFrame()} - \l{QRhi::endFrame()}{endFrame()} |
222 | | section). As a general rule, all referenced QRhiResource objects must stay |
223 | | unchanged until the frame is submitted by calling |
224 | | \l{QRhi::endFrame()}{endFrame()}. To ease this, |
225 | | QRhiResource::deleteLater() is provided as a convenience. |
226 | | |
227 | | \endlist |
228 | | |
229 | | \section2 Command buffers and deferred command execution |
230 | | |
231 | | Regardless of the design and capabilities of the underlying graphics API, |
232 | | all QRhi backends implement some level of command buffers. No |
233 | | QRhiCommandBuffer function issues any native bind or draw command (such as, |
234 | | \c glDrawElements) directly. Commands are always recorded in a queue, |
235 | | either native or provided by the QRhi backend. The command buffer is |
236 | | submitted, and so execution starts only upon QRhi::endFrame() or |
237 | | QRhi::finish(). |
238 | | |
239 | | The deferred nature has consequences for some types of objects. For example, |
240 | | writing to a dynamic buffer multiple times within a frame, in case such |
241 | | buffers are backed by host-visible memory, will result in making the |
242 | | results of all writes are visible to all draw calls in the command buffer |
243 | | of the frame, regardless of when the dynamic buffer update was recorded |
244 | | relative to a draw call. |
245 | | |
246 | | Furthermore, instances of QRhiResource subclasses must be treated immutable |
247 | | within a frame in which they are referenced in any way. Create |
248 | | all resources upfront, before starting to record commands for the next |
249 | | frame. Reusing a QRhiResource instance within a frame (by calling \c create() |
250 | | then referencing it again in the same \c{beginFrame - endFrame} section) |
251 | | should be avoided as it may lead to unexpected results, depending on the |
252 | | backend. |
253 | | |
254 | | As a general rule, all referenced QRhiResource objects must stay valid and |
255 | | unmodified until the frame is submitted by calling |
256 | | \l{QRhi::endFrame()}{endFrame()}. On the other hand, calling |
257 | | \l{QRhiResource::destroy()}{destroy()} or deleting the QRhiResource are |
258 | | always safe once the frame is submitted, regardless of the status of the |
259 | | underlying native resources (which may still be in use by the GPU - but |
260 | | that is taken care of internally). |
261 | | |
262 | | Unlike APIs like OpenGL, upload and copy type of commands cannot be mixed |
263 | | with draw commands. The typical renderer will involve a sequence similar to |
264 | | the following: |
265 | | |
266 | | \list |
267 | | \li (re)create resources |
268 | | \li begin frame |
269 | | \li record/issue uploads and copies |
270 | | \li start recording a render pass |
271 | | \li record draw calls |
272 | | \li end render pass |
273 | | \li end frame |
274 | | \endlist |
275 | | |
276 | | Recording copy type of operations happens via QRhiResourceUpdateBatch. Such |
277 | | operations are committed typically on |
278 | | \l{QRhiCommandBuffer::beginPass()}{beginPass()}. |
279 | | |
280 | | When working with legacy rendering engines designed for OpenGL, the |
281 | | migration to QRhi often involves redesigning from having a single \c render |
282 | | step (that performs copies and uploads, clears buffers, and issues draw |
283 | | calls, all mixed together) to a clearly separated, two phase \c prepare - |
284 | | \c render setup where the \c render step only starts a renderpass and |
285 | | records draw calls, while all resource creation and queuing of updates, |
286 | | uploads and copies happens beforehand, in the \c prepare step. |
287 | | |
288 | | QRhi does not at the moment allow freely creating and submitting command |
289 | | buffers. This may be lifted in the future to some extent, in particular if |
290 | | compute support is introduced, but the model of well defined |
291 | | \c{frame-start} and \c{frame-end} points, combined with a dedicated, |
292 | | "frame" command buffer, where \c{frame-end} implies presenting, is going to |
293 | | remain the primary way of operating since this is what fits Qt's various UI |
294 | | technologies best. |
295 | | |
296 | | \section2 Threading |
297 | | |
298 | | A QRhi instance and the associated resources can be created and used on any |
299 | | thread but all usage must be limited to that one single thread. When |
300 | | rendering to multiple QWindows in an application, having a dedicated thread |
301 | | and QRhi instance for each window is often advisable, as this can eliminate |
302 | | issues with unexpected throttling caused by presenting to multiple windows. |
303 | | Conceptually that is then the same as how Qt Quick scene graph's threaded |
304 | | render loop operates when working directly with OpenGL: one thread for each |
305 | | window, one QOpenGLContext for each thread. When moving onto QRhi, |
306 | | QOpenGLContext is replaced by QRhi, making the migration straightforward. |
307 | | |
308 | | When it comes to externally created native objects, such as OpenGL contexts |
309 | | passed in via QRhiGles2NativeHandles, it is up to the application to ensure |
310 | | they are not misused by other threads. |
311 | | |
312 | | Resources are not shareable between QRhi instances. This is an intentional |
313 | | choice since QRhi hides most queue, command buffer, and resource |
314 | | synchronization related tasks, and provides no API for them. Safe and |
315 | | efficient concurrent use of graphics resources from multiple threads is |
316 | | tied to those concepts, however, and is thus a topic that is currently out |
317 | | of scope, but may be introduced in the future. |
318 | | |
319 | | \note The Metal backend requires that an autorelease pool is available on |
320 | | the rendering thread, ideally wrapping each iteration of the render loop. |
321 | | This needs no action from the users of QRhi when rendering on the main |
322 | | (gui) thread, but becomes important when a separate, dedicated render |
323 | | thread is used. |
324 | | |
325 | | \section2 Resource synchronization |
326 | | |
327 | | QRhi does not expose APIs for resource barriers or image layout |
328 | | transitions. Such synchronization is done implicitly by the backends, where |
329 | | applicable (for example, Vulkan), by tracking resource usage as necessary. |
330 | | Buffer and image barriers are inserted before render or compute passes |
331 | | transparently to the application. |
332 | | |
333 | | \note Resources within a render or compute pass are expected to be bound to |
334 | | a single usage during that pass. For example, a buffer can be used as |
335 | | vertex, index, uniform, or storage buffer, but not a combination of them |
336 | | within a single pass. However, it is perfectly fine to use a buffer as a |
337 | | storage buffer in a compute pass, and then as a vertex buffer in a render |
338 | | pass, for example, assuming the buffer declared both usages upon creation. |
339 | | |
340 | | \note Textures have this rule relaxed in certain cases, because using two |
341 | | subresources (typically two different mip levels) of the same texture for |
342 | | different access (one for load, one for store) is supported even within the |
343 | | same pass. |
344 | | |
345 | | \section2 Resource reuse |
346 | | |
347 | | From the user's point of view a QRhiResource is reusable immediately after |
348 | | calling QRhiResource::destroy(). With the exception of swapchains, calling |
349 | | \c create() on an already created object does an implicit \c destroy(). This |
350 | | provides a handy shortcut to reuse a QRhiResource instance with different |
351 | | parameters, with a new native graphics object underneath. |
352 | | |
353 | | The importance of reusing the same object lies in the fact that some |
354 | | objects reference other objects: for example, a QRhiShaderResourceBindings |
355 | | can reference QRhiBuffer, QRhiTexture, and QRhiSampler instances. If in a |
356 | | later frame one of these buffers need to be resized or a sampler parameter |
357 | | needs changing, destroying and creating a whole new QRhiBuffer or |
358 | | QRhiSampler would invalidate all references to the old instance. By just |
359 | | changing the appropriate parameters via QRhiBuffer::setSize() or similar |
360 | | and then calling QRhiBuffer::create(), everything works as expected and |
361 | | there is no need to touch the QRhiShaderResourceBindings at all, even |
362 | | though there is a good chance that under the hood the QRhiBuffer is now |
363 | | backed by a whole new native buffer. |
364 | | |
365 | | \code |
366 | | QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256); |
367 | | ubuf->create(); |
368 | | |
369 | | QRhiShaderResourceBindings *srb = rhi->newShaderResourceBindings() |
370 | | srb->setBindings({ |
371 | | QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, ubuf) |
372 | | }); |
373 | | srb->create(); |
374 | | |
375 | | // ... |
376 | | |
377 | | // now in a later frame we need to grow the buffer to a larger size |
378 | | ubuf->setSize(512); |
379 | | ubuf->create(); // same as ubuf->destroy(); ubuf->create(); |
380 | | |
381 | | // srb needs no changes whatsoever, any references in it to ubuf |
382 | | // stay valid. When it comes to internal details, such as that |
383 | | // ubuf may now be backed by a completely different native buffer |
384 | | // resource, that is is recognized and handled automatically by the |
385 | | // next setShaderResources(). |
386 | | \endcode |
387 | | |
388 | | QRhiTextureRenderTarget offers the same contract: calling |
389 | | QRhiCommandBuffer::beginPass() is safe even when one of the render target's |
390 | | associated textures or renderbuffers has been rebuilt (by calling \c |
391 | | create() on it) since the creation of the render target object. This allows |
392 | | the application to resize a texture by setting a new pixel size on the |
393 | | QRhiTexture and calling create(), thus creating a whole new native texture |
394 | | resource underneath, without having to update the QRhiTextureRenderTarget |
395 | | as that will be done implicitly in beginPass(). |
396 | | |
397 | | \section2 Pooled objects |
398 | | |
399 | | In addition to resources, there are pooled objects as well, such as, |
400 | | QRhiResourceUpdateBatch. An instance is retrieved via a \c next function, |
401 | | such as, nextResourceUpdateBatch(). The caller does not own the returned |
402 | | instance in this case. The only valid way of operating here is calling |
403 | | functions on the QRhiResourceUpdateBatch and then passing it to |
404 | | QRhiCommandBuffer::beginPass() or QRhiCommandBuffer::endPass(). These |
405 | | functions take care of returning the batch to the pool. Alternatively, a |
406 | | batch can be "canceled" and returned to the pool without processing by |
407 | | calling QRhiResourceUpdateBatch::release(). |
408 | | |
409 | | A typical pattern is thus: |
410 | | |
411 | | \code |
412 | | QRhiResourceUpdateBatch *resUpdates = rhi->nextResourceUpdateBatch(); |
413 | | // ... |
414 | | resUpdates->updateDynamicBuffer(ubuf, 0, 64, mvp.constData()); |
415 | | if (!image.isNull()) { |
416 | | resUpdates->uploadTexture(texture, image); |
417 | | image = QImage(); |
418 | | } |
419 | | // ... |
420 | | QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer(); |
421 | | // note the last argument |
422 | | cb->beginPass(swapchain->currentFrameRenderTarget(), clearCol, clearDs, resUpdates); |
423 | | \endcode |
424 | | |
425 | | \section2 Swapchain specifics |
426 | | |
427 | | QRhiSwapChain features some special semantics due to the peculiar nature of |
428 | | swapchains. |
429 | | |
430 | | \list |
431 | | |
432 | | \li It has no \c create() but rather a QRhiSwapChain::createOrResize(). |
433 | | Repeatedly calling this function is \b not the same as calling |
434 | | QRhiSwapChain::destroy() followed by QRhiSwapChain::createOrResize(). This |
435 | | is because swapchains often have ways to handle the case where buffers need |
436 | | to be resized in a manner that is more efficient than a brute force |
437 | | destroying and recreating from scratch. |
438 | | |
439 | | \li An active QRhiSwapChain must be released by calling |
440 | | \l{QRhiSwapChain::destroy()}{destroy()}, or by destroying the object, before |
441 | | the QWindow's underlying QPlatformWindow, and so the associated native |
442 | | window object, is destroyed. It should not be postponed because releasing |
443 | | the swapchain may become problematic (and with some APIs, like Vulkan, is |
444 | | explicitly disallowed) when the native window is not around anymore, for |
445 | | example because the QPlatformWindow got destroyed upon getting a |
446 | | QWindow::close(). Therefore, releasing the swapchain must happen whenever |
447 | | the targeted QWindow sends the |
448 | | QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed event. If the event does |
449 | | not arrive before the destruction of the QWindow - this can happen when |
450 | | using QCoreApplication::quit() -, then check QWindow::handle() after the |
451 | | event loop exits and invoke the swapchain release when non-null (meaning |
452 | | the underlying native window is still around). |
453 | | |
454 | | \endlist |
455 | | |
456 | | \section2 Ownership |
457 | | |
458 | | The general rule is no ownership transfer. Creating a QRhi with an already |
459 | | existing graphics device does not mean the QRhi takes ownership of the |
460 | | device object. Similarly, ownership is not given away when a device or |
461 | | texture object is "exported" via QRhi::nativeHandles() or |
462 | | QRhiTexture::nativeTexture(). Most importantly, passing pointers in structs |
463 | | and via setters does not transfer ownership. |
464 | | |
465 | | \section1 Troubleshooting and Profiling |
466 | | |
467 | | \section2 Error reporting |
468 | | |
469 | | Functions such as \l QRhi::create() and the resource classes' \c create() |
470 | | member functions (e.g., \l QRhiBuffer::create()) indicate failure with the |
471 | | return value (\nullptr or |
472 | | \c false, respectively). When working with QShader, \l QShader::fromSerialized() |
473 | | returns an invalid QShader (for which \l{QShader::isValid()}{isValid()} returns |
474 | | \c false) when the data passed to the function cannot be successfully deserialized. |
475 | | Some functions, beginFrame() in particular, may also sometimes report "soft failures", |
476 | | such as \l FrameOpSwapChainOutOfDate, which do not indicate an unrecoverable error, |
477 | | but rather should be seen as a "try again later" response. |
478 | | |
479 | | Warnings and errors may get printed at any time to the debug output via |
480 | | qWarning(). It is therefore always advisable to inspect the output of the |
481 | | application. |
482 | | |
483 | | Additional debug messages can be enabled via the following logging |
484 | | categories. Messages from these categories are not printed by default |
485 | | unless explicitly enabled via QLoggingCategory or the \c QT_LOGGING_RULES |
486 | | environment variable. For better interoperation with Qt Quick, the |
487 | | environment variable \c{QSG_INFO} also enables these debug prints. |
488 | | |
489 | | \list |
490 | | \li \c{qt.rhi.general} |
491 | | \endlist |
492 | | |
493 | | Additionally, applications can query the \l{QRhi::backendName()}{QRhi |
494 | | backend name} and |
495 | | \l{QRhi::driverInfo()}{graphics device information} from a successfully |
496 | | initialized QRhi. This can then be printed to the user or stored in the |
497 | | application logs even in production builds, if desired. |
498 | | |
499 | | \section2 Investigating rendering problems |
500 | | |
501 | | When the rendering results are not as expected, or the application is |
502 | | experiencing problems, always consider checking with the native 3D |
503 | | APIs' debug and validation facilities. QRhi itself features limited error |
504 | | checking since replicating the already existing, vast amount of |
505 | | functionality in the underlying layers is not reasonable. |
506 | | |
507 | | \list |
508 | | |
509 | | \li For Vulkan, controlling the |
510 | | \l{https://github.com/KhronosGroup/Vulkan-ValidationLayers}{Vulkan |
511 | | Validation Layers} is not in the scope of the QRhi, but rather can be |
512 | | achieved by configuring the \l QVulkanInstance with the appropriate layers. |
513 | | For example, call \c{instance.setLayers({ "VK_LAYER_KHRONOS_validation" });} |
514 | | before invoking \l{QVulkanInstance::create()}{create()} on the QVulkanInstance. |
515 | | (note that this assumes that the validation layers are actually installed |
516 | | and available, e.g. from the Vulkan SDK) By default, QVulkanInstance conveniently |
517 | | redirects the Vulkan debug messages to qDebug, meaning the validation messages get |
518 | | printed just like other Qt warnings. |
519 | | |
520 | | \li With Direct 3D 11 and 12, a graphics device with the debug layer |
521 | | enabled can be requested by toggling the \c enableDebugLayer flag in the |
522 | | appropriate \l{QRhiD3D11InitParams}{init params struct}. The messages appear on the |
523 | | debug output, which is visible in Qt Creator's messages panel or via a tool |
524 | | such as \l{https://learn.microsoft.com/en-us/sysinternals/downloads/debugview}{DebugView}. |
525 | | |
526 | | \li For Metal, controlling Metal Validation is outside of QRhi's scope. |
527 | | Rather, to enable validation, run the application with the environment |
528 | | variable \c{METAL_DEVICE_WRAPPER_TYPE=1} set, or run the application within |
529 | | XCode. There may also be further settings and environment variable in modern |
530 | | XCode and macOS versions. See for instance |
531 | | \l{https://developer.apple.com/documentation/metal/diagnosing_metal_programming_issues_early}{this |
532 | | page}. |
533 | | |
534 | | \endlist |
535 | | |
536 | | \section2 Frame captures and performance profiling |
537 | | |
538 | | A Qt application rendering with QRhi to a window while relying on a 3D API |
539 | | under the hood, is, from the windowing and graphics pipeline perspective at |
540 | | least, no different from any other (non-Qt) applications using the same 3D |
541 | | API. This means that tools and practices for debugging and profiling |
542 | | applications involving 3D graphics, such as games, all apply to such a Qt |
543 | | application as well. |
544 | | |
545 | | A few examples of tools that can provide insights into the rendering |
546 | | internals of Qt applications that use QRhi, which includes Qt Quick and Qt |
547 | | Quick 3D based projects as well: |
548 | | |
549 | | \list |
550 | | |
551 | | \li \l{https://renderdoc.org/}{RenderDoc} allows taking frame captures and |
552 | | introspecting the recorded commands and pipeline state on Windows and Linux |
553 | | for applications using OpenGL, Vulkan, D3D11, or D3D12. When trying to |
554 | | figure out why some parts of the 3D scene do not show up as expected, |
555 | | RenderDoc is often a fast and efficient way to check the pipeline stages |
556 | | and the related state and discover the missing or incorrect value. It is |
557 | | also a tool that is actively used when developing Qt itself. |
558 | | |
559 | | \li For NVIDIA-based systems, |
560 | | \l{https://developer.nvidia.com/nsight-graphics}{Nsight Graphics} provides |
561 | | a graphics debugger tool on Windows and Linux. In addition to investigating the commands |
562 | | in the frame and the pipeline, the vendor-specific tools allow looking at timings and |
563 | | hardware performance information, which is not something simple frame captures can provide. |
564 | | |
565 | | \li For AMD-based systems, the \l{https://gpuopen.com/rgp/}{Radeon GPU |
566 | | Profiler} can be used to gain deeper insights into the application's |
567 | | rendering and its performance. |
568 | | |
569 | | \li Overlays showing live performance information can be highly useful as well, and |
570 | | are often preferable to implementing simple frames-per-second counters within the |
571 | | application itself, since they are more reliable and show more information. An example |
572 | | is \l{https://game.intel.com/us/intel-presentmon/}{PresentMon}, which supports |
573 | | graphics hardware from multiple vendors. |
574 | | |
575 | | \li As QRhi supports Direct 3D 12, using |
576 | | \l{https://devblogs.microsoft.com/pix/download/}{PIX}, a performance tuning |
577 | | and debugging tool for DirectX 12 games on Windows is an option as well. |
578 | | |
579 | | \li On macOS, |
580 | | \l{https://developer.apple.com/documentation/metal/debugging_tools/viewing_your_gpu_workload_with_the_metal_debugger}{the |
581 | | XCode Metal debugger} can be used to take and introspect frame |
582 | | captures, to investigate performance details, and debug shaders. In macOS 13 it is also possible |
583 | | to enable an overlay that displays frame rate and other information for any Metal-based window by |
584 | | setting the environment variable \c{MTL_HUD_ENABLED=1}. |
585 | | |
586 | | \endlist |
587 | | |
588 | | On mobile and embedded platforms, there may be vendor and platform-specific |
589 | | tools, provided by the GPU or SoC vendor, available to perform performance |
590 | | profiling of application using OpenGL ES or Vulkan. |
591 | | |
592 | | When capturing frames, remember that objects and groups of commands can be |
593 | | named via debug markers, as long as \l{QRhi::EnableDebugMarkers}{debug |
594 | | markers were enabled} for the QRhi, and the graphics API in use supports |
595 | | this. To annotate the command stream, call |
596 | | \l{QRhiCommandBuffer::debugMarkBegin()}{debugMarkBegin()}, |
597 | | \l{QRhiCommandBuffer::debugMarkEnd()}{debugMarkEnd()} and/or |
598 | | \l{QRhiCommandBuffer::debugMarkMsg()}{debugMarkMsg()}. |
599 | | This can be particularly useful in larger frames with multiple render passes. |
600 | | Resources are named by calling \l{QRhiResource::setName()}{setName()} before create(). |
601 | | |
602 | | To perform basic timing measurements on the CPU and GPU side within the |
603 | | application, \l QElapsedTimer and |
604 | | \l QRhiCommandBuffer::lastCompletedGpuTime() can be used. The latter is |
605 | | only available with select graphics APIs at the moment and requires opting |
606 | | in via the \l QRhi::EnableTimestamps flag. |
607 | | |
608 | | \section2 Resource leak checking |
609 | | |
610 | | When destroying a QRhi object without properly destroying all buffers, |
611 | | textures, and other resources created from it, warnings about this are |
612 | | printed to the debug output whenever the application is a debug build, or |
613 | | when the \c QT_RHI_LEAK_CHECK environment variable is set to a non-zero |
614 | | value. This is a simple way to discover design issues around resource |
615 | | handling within the application rendering logic. Note however that some |
616 | | platforms and underlying graphics APIs may perform their own allocation and |
617 | | resource leak detection as well, over which Qt will have no direct control. |
618 | | For example, when using Vulkan, the memory allocator may raise failing |
619 | | assertions in debug builds when resources that own graphics memory |
620 | | allocations are not destroyed before the QRhi. In addition, the Vulkan |
621 | | validation layer, when enabled, will issue warnings about native graphics |
622 | | resources that were not released. Similarly, with Direct 3D warnings may |
623 | | get printed about unreleased COM objects when the application does not |
624 | | destroy the QRhi and its resources in the correct order. |
625 | | |
626 | | \sa {RHI Window Example}, QRhiCommandBuffer, QRhiResourceUpdateBatch, |
627 | | QRhiShaderResourceBindings, QShader, QRhiBuffer, QRhiTexture, |
628 | | QRhiRenderBuffer, QRhiSampler, QRhiTextureRenderTarget, |
629 | | QRhiGraphicsPipeline, QRhiComputePipeline, QRhiSwapChain |
630 | | */ |
631 | | |
632 | | /*! |
633 | | \enum QRhi::Implementation |
634 | | Describes which graphics API-specific backend gets used by a QRhi instance. |
635 | | |
636 | | \value Null |
637 | | \value Vulkan |
638 | | \value OpenGLES2 |
639 | | \value D3D11 |
640 | | \value D3D12 |
641 | | \value Metal |
642 | | */ |
643 | | |
644 | | /*! |
645 | | \enum QRhi::Flag |
646 | | Describes what special features to enable. |
647 | | |
648 | | \value EnableDebugMarkers Enables debug marker groups. Without this frame |
649 | | debugging features like making debug groups and custom resource name |
650 | | visible in external GPU debugging tools will not be available and functions |
651 | | like QRhiCommandBuffer::debugMarkBegin() will become no-ops. Avoid enabling |
652 | | in production builds as it may involve a small performance impact. Has no |
653 | | effect when the QRhi::DebugMarkers feature is not reported as supported. |
654 | | |
655 | | \value EnableTimestamps Enables GPU timestamp collection. When not set, |
656 | | QRhiCommandBuffer::lastCompletedGpuTime() always returns 0. Enable this |
657 | | only when needed since there may be a small amount of extra work involved |
658 | | (e.g. timestamp queries), depending on the underlying graphics API. Has no |
659 | | effect when the QRhi::Timestamps feature is not reported as supported. |
660 | | |
661 | | \value PreferSoftwareRenderer Indicates that backends should prefer |
662 | | choosing an adapter or physical device that renders in software on the CPU. |
663 | | For example, with Direct3D there is typically a "Basic Render Driver" |
664 | | adapter available with \c{DXGI_ADAPTER_FLAG_SOFTWARE}. Setting this flag |
665 | | requests the backend to choose that adapter over any other, as long as no |
666 | | specific adapter was forced by other backend-specific means. With Vulkan |
667 | | this maps to preferring physical devices with |
668 | | \c{VK_PHYSICAL_DEVICE_TYPE_CPU}. When not available, or when it is not |
669 | | possible to decide if an adapter/device is software-based, this flag is |
670 | | ignored. It may also be ignored with graphics APIs that have no concept and |
671 | | means of enumerating adapters/devices. |
672 | | |
673 | | \value EnablePipelineCacheDataSave Enables retrieving the pipeline cache |
674 | | contents, where applicable. When not set, pipelineCacheData() will return |
675 | | an empty blob always. With backends where retrieving and restoring the |
676 | | pipeline cache contents is not supported, the flag has no effect and the |
677 | | serialized cache data is always empty. The flag provides an opt-in |
678 | | mechanism because the cost of maintaining the related data structures is |
679 | | not insignificant with some backends. With Vulkan this feature maps |
680 | | directly to VkPipelineCache, vkGetPipelineCacheData and |
681 | | VkPipelineCacheCreateInfo::pInitialData. With Direct3D 11 there is no real |
682 | | pipline cache, but the results of HLSL->DXBC compilations are stored and |
683 | | can be serialized/deserialized via this mechanism. This allows skipping the |
684 | | time consuming D3DCompile() in future runs of the applications for shaders |
685 | | that come with HLSL source instead of offline pre-compiled bytecode. This |
686 | | can provide a huge boost in startup and load times, if there is a lot of |
687 | | HLSL source compilation happening. With OpenGL the "pipeline cache" is |
688 | | simulated by retrieving and loading shader program binaries (if supported |
689 | | by the driver). With OpenGL there are additional, disk-based caching |
690 | | mechanisms for shader/program binaries provided by Qt. Writing to those may |
691 | | get disabled whenever this flag is set since storing program binaries to |
692 | | multiple caches is not sensible. |
693 | | |
694 | | \value SuppressSmokeTestWarnings Indicates that, with backends where this |
695 | | is relevant, certain, non-fatal QRhi::create() failures should not |
696 | | produce qWarning() calls. For example, with D3D11, passing this flag |
697 | | makes a number of warning messages (that appear due to QRhi::create() |
698 | | failing) to become categorized debug prints instead under the commonly used |
699 | | \c{qt.rhi.general} logging category. This can be used by engines, such as |
700 | | Qt Quick, that feature fallback logic, i.e. they retry calling create() |
701 | | with a different set of flags (such as, \l PreferSoftwareRenderer), in order |
702 | | to hide the unconditional warnings from the output that would be printed |
703 | | when the first create() attempt had failed. |
704 | | */ |
705 | | |
706 | | /*! |
707 | | \enum QRhi::FrameOpResult |
708 | | Describes the result of operations that can have a soft failure. |
709 | | |
710 | | \value FrameOpSuccess Success |
711 | | |
712 | | \value FrameOpError Unspecified error |
713 | | |
714 | | \value FrameOpSwapChainOutOfDate The swapchain is in an inconsistent state |
715 | | internally. This can be recoverable by attempting to repeat the operation |
716 | | (such as, beginFrame()) later. |
717 | | |
718 | | \value FrameOpDeviceLost The graphics device was lost. This can be |
719 | | recoverable by attempting to repeat the operation (such as, beginFrame()) |
720 | | after releasing and reinitializing all objects backed by native graphics |
721 | | resources. See isDeviceLost(). |
722 | | */ |
723 | | |
724 | | /*! |
725 | | \enum QRhi::Feature |
726 | | Flag values to indicate what features are supported by the backend currently in use. |
727 | | |
728 | | \value MultisampleTexture Indicates that textures with a sample count larger |
729 | | than 1 are supported. In practice this feature will be unsupported with |
730 | | OpenGL ES versions older than 3.1, and OpenGL older than 3.0. |
731 | | |
732 | | \value MultisampleRenderBuffer Indicates that renderbuffers with a sample |
733 | | count larger than 1 are supported. In practice this feature will be |
734 | | unsupported with OpenGL ES 2.0, and may also be unsupported with OpenGL 2.x |
735 | | unless the relevant extensions are present. |
736 | | |
737 | | \value DebugMarkers Indicates that debug marker groups (and so |
738 | | QRhiCommandBuffer::debugMarkBegin()) are supported. |
739 | | |
740 | | \value Timestamps Indicates that command buffer timestamps are supported. |
741 | | Relevant for QRhiCommandBuffer::lastCompletedGpuTime(). This can be |
742 | | expected to be supported on Metal, Vulkan, Direct 3D 11 and 12, and OpenGL |
743 | | contexts of version 3.3 or newer. However, with some of these APIs support |
744 | | for timestamp queries is technically optional, and therefore it cannot be |
745 | | guaranteed that this feature is always supported with every implementation |
746 | | of them. |
747 | | |
748 | | \value Instancing Indicates that instanced drawing is supported. In |
749 | | practice this feature will be unsupported with OpenGL ES 2.0 and OpenGL |
750 | | 3.2 or older. |
751 | | |
752 | | \value CustomInstanceStepRate Indicates that instance step rates other |
753 | | than 1 are supported. In practice this feature will always be unsupported |
754 | | with OpenGL. In addition, running with Vulkan 1.0 without |
755 | | VK_EXT_vertex_attribute_divisor will also lead to reporting false for this |
756 | | feature. |
757 | | |
758 | | \value PrimitiveRestart Indicates that restarting the assembly of |
759 | | primitives when encountering an index value of 0xFFFF |
760 | | (\l{QRhiCommandBuffer::IndexUInt16}{IndexUInt16}) or 0xFFFFFFFF |
761 | | (\l{QRhiCommandBuffer::IndexUInt32}{IndexUInt32}) is enabled, for certain |
762 | | primitive topologies at least. QRhi will try to enable this with all |
763 | | backends, but in some cases it will not be supported. Dynamically |
764 | | controlling primitive restart is not possible since with some APIs |
765 | | primitive restart with a fixed index is always on. Applications must assume |
766 | | that whenever this feature is reported as supported, the above mentioned |
767 | | index values \c may be treated specially, depending on the topology. The |
768 | | only two topologies where primitive restart is guaranteed to behave |
769 | | identically across backends, as long as this feature is reported as |
770 | | supported, are \l{QRhiGraphicsPipeline::LineStrip}{LineStrip} and |
771 | | \l{QRhiGraphicsPipeline::TriangleStrip}{TriangleStrip}. |
772 | | |
773 | | \value NonDynamicUniformBuffers Indicates that creating buffers with the |
774 | | usage \l{QRhiBuffer::UniformBuffer}{UniformBuffer} and the types |
775 | | \l{QRhiBuffer::Immutable}{Immutable} or \l{QRhiBuffer::Static}{Static} is |
776 | | supported. When reported as unsupported, uniform (constant) buffers must be |
777 | | created as \l{QRhiBuffer::Dynamic}{Dynamic}. (which is recommended |
778 | | regardless) |
779 | | |
780 | | \value NonFourAlignedEffectiveIndexBufferOffset Indicates that effective |
781 | | index buffer offsets (\c{indexOffset + firstIndex * indexComponentSize}) |
782 | | that are not 4 byte aligned are supported. When not supported, attempting |
783 | | to issue a \l{QRhiCommandBuffer::drawIndexed()}{drawIndexed()} with a |
784 | | non-aligned effective offset may lead to unspecified behavior. Relevant in |
785 | | particular for Metal, where this will be reported as unsupported. |
786 | | |
787 | | \value NPOTTextureRepeat Indicates that the |
788 | | \l{QRhiSampler::Repeat}{Repeat} wrap mode and mipmap filtering modes are |
789 | | supported for textures with a non-power-of-two size. In practice this can |
790 | | only be false with OpenGL ES 2.0 implementations without |
791 | | \c{GL_OES_texture_npot}. |
792 | | |
793 | | \value RedOrAlpha8IsRed Indicates that the |
794 | | \l{QRhiTexture::RED_OR_ALPHA8}{RED_OR_ALPHA8} format maps to a one |
795 | | component 8-bit \c red format. This is the case for all backends except |
796 | | OpenGL when using either OpenGL ES or a non-core profile context. There |
797 | | \c{GL_ALPHA}, a one component 8-bit \c alpha format, is used |
798 | | instead. Using the special texture format allows having a single code |
799 | | path for creating textures, leaving it up to the backend to decide the |
800 | | actual format, while the feature flag can be used to pick the |
801 | | appropriate shader variant for sampling the texture. |
802 | | |
803 | | \value ElementIndexUint Indicates that 32-bit unsigned integer elements are |
804 | | supported in the index buffer. In practice this is true everywhere except |
805 | | when running on plain OpenGL ES 2.0 implementations without the necessary |
806 | | extension. When false, only 16-bit unsigned elements are supported in the |
807 | | index buffer. |
808 | | |
809 | | \value Compute Indicates that compute shaders, image load/store, and |
810 | | storage buffers are supported. OpenGL older than 4.3 and OpenGL ES older |
811 | | than 3.1 have no compute support. |
812 | | |
813 | | \value WideLines Indicates that lines with a width other than 1 are |
814 | | supported. When reported as not supported, the line width set on the |
815 | | graphics pipeline state is ignored. This can always be false with some |
816 | | backends (D3D11, D3D12, Metal). With Vulkan, the value depends on the |
817 | | implementation. With OpenGL, wide lines are not supported in core profile |
818 | | contexts. |
819 | | |
820 | | \value VertexShaderPointSize Indicates that the size of rasterized points |
821 | | set via \c{gl_PointSize} in the vertex shader is taken into account. When |
822 | | reported as not supported, drawing points with a size other than 1 is not |
823 | | supported. Setting \c{gl_PointSize} in the shader is still valid then, but |
824 | | is ignored. (for example, when generating HLSL, the assignment is silently |
825 | | dropped from the generated code) Note that some APIs (Metal, Vulkan) |
826 | | require the point size to be set in the shader explicitly whenever drawing |
827 | | points, even when the size is 1, as they do not automatically default to 1. |
828 | | |
829 | | \value BaseVertex Indicates that |
830 | | \l{QRhiCommandBuffer::drawIndexed()}{drawIndexed()} supports the \c |
831 | | vertexOffset argument. When reported as not supported, the vertexOffset |
832 | | value in an indexed draw is ignored. In practice this feature will be |
833 | | unsupported with OpenGL and OpenGL ES versions lower than 3.2, and with |
834 | | Metal on older iOS devices, including the iOS Simulator. |
835 | | |
836 | | \value BaseInstance Indicates that instanced draw commands support the \c |
837 | | firstInstance argument. When reported as not supported, the firstInstance |
838 | | value is ignored and the instance ID starts from 0. In practice this feature |
839 | | will be unsupported with Metal on older iOS devices, including the iOS |
840 | | Simulator, and all versions of OpenGL. The latter is due to OpenGL ES not |
841 | | supporting draw calls with a base instance at all. Currently QRhi's OpenGL |
842 | | backend does not implement the functionality for OpenGL (non-ES) either, |
843 | | because portable applications cannot rely on a non-zero base instance in |
844 | | practice due to GLES. If the application still chooses to do so, it should |
845 | | be aware of the InstanceIndexIncludesBaseInstance feature as well. |
846 | | |
847 | | \value TriangleFanTopology Indicates that QRhiGraphicsPipeline::setTopology() |
848 | | supports QRhiGraphicsPipeline::TriangleFan. In practice this feature will be |
849 | | unsupported with Metal and Direct 3D 11/12. |
850 | | |
851 | | \value ReadBackNonUniformBuffer Indicates that |
852 | | \l{QRhiResourceUpdateBatch::readBackBuffer()}{reading buffer contents} is |
853 | | supported for QRhiBuffer instances with a usage different than |
854 | | UniformBuffer. In practice this feature will be unsupported with OpenGL ES |
855 | | 2.0. |
856 | | |
857 | | \value ReadBackNonBaseMipLevel Indicates that specifying a mip level other |
858 | | than 0 is supported when reading back texture contents. When not supported, |
859 | | specifying a non-zero level in QRhiReadbackDescription leads to returning |
860 | | an all-zero image. In practice this feature will be unsupported with OpenGL |
861 | | ES 2.0. |
862 | | |
863 | | \value TexelFetch Indicates that texelFetch() and textureLod() are available |
864 | | in shaders. In practice this will be reported as unsupported with OpenGL ES |
865 | | 2.0 and OpenGL 2.x contexts, because GLSL 100 es and versions before 130 do |
866 | | not support these functions. |
867 | | |
868 | | \value RenderToNonBaseMipLevel Indicates that specifying a mip level other |
869 | | than 0 is supported when creating a QRhiTextureRenderTarget with a |
870 | | QRhiTexture as its color attachment. When not supported, create() will fail |
871 | | whenever the target mip level is not zero. In practice this feature will be |
872 | | unsupported with OpenGL ES 2.0. |
873 | | |
874 | | \value IntAttributes Indicates that specifying input attributes with |
875 | | signed and unsigned integer types for a shader pipeline is supported. When |
876 | | not supported, |
877 | | \l{QRhiGraphicsPipeline::create()}{QRhiGraphicsPipeline::create()} will |
878 | | succeed but show a warning message and the values of the target attributes |
879 | | will be broken. In practice this feature will be unsupported with OpenGL ES |
880 | | 2.0 and OpenGL 2.x. |
881 | | |
882 | | \value ScreenSpaceDerivatives Indicates that functions such as dFdx(), |
883 | | dFdy(), and fwidth() are supported in shaders. In practice this feature will |
884 | | be unsupported with OpenGL ES 2.0 without the GL_OES_standard_derivatives |
885 | | extension. |
886 | | |
887 | | \value ReadBackAnyTextureFormat Indicates that reading back texture |
888 | | contents can be expected to work for any QRhiTexture::Format. Backends |
889 | | other than OpenGL can be expected to return true for this feature. When |
890 | | reported as false, which will typically happen with OpenGL, only the |
891 | | formats QRhiTexture::RGBA8 and QRhiTexture::BGRA8 are guaranteed to be |
892 | | supported for readbacks. In addition, with OpenGL, but not OpenGL ES, |
893 | | reading back the 1 byte per component formats QRhiTexture::R8 and |
894 | | QRhiTexture::RED_OR_ALPHA8 are supported as well. Reading back floating |
895 | | point formats QRhiTexture::RGBA16F and RGBA32F may work too with OpenGL, as |
896 | | long as the implementation provides support for these, but QRhi can give no |
897 | | guarantees, as indicated by this flag. |
898 | | |
899 | | \value PipelineCacheDataLoadSave Indicates that the pipelineCacheData() and |
900 | | setPipelineCacheData() functions are functional. When not supported, the |
901 | | functions will not perform any action, the retrieved blob is always empty, |
902 | | and thus no benefits can be expected from retrieving and, during a |
903 | | subsequent run of the application, reloading the pipeline cache content. |
904 | | |
905 | | \value ImageDataStride Indicates that specifying a custom stride (row |
906 | | length) for raw image data in texture uploads is supported. When not |
907 | | supported (which can happen when the underlying API is OpenGL ES 2.0 without |
908 | | support for GL_UNPACK_ROW_LENGTH), |
909 | | QRhiTextureSubresourceUploadDescription::setDataStride() must not be used. |
910 | | |
911 | | \value RenderBufferImport Indicates that QRhiRenderBuffer::createFrom() is |
912 | | supported. For most graphics APIs this is not sensible because |
913 | | QRhiRenderBuffer encapsulates texture objects internally, just like |
914 | | QRhiTexture. With OpenGL however, renderbuffer object exist as a separate |
915 | | object type in the API, and in certain environments (for example, where one |
916 | | may want to associated a renderbuffer object with an EGLImage object) it is |
917 | | important to allow wrapping an existing OpenGL renderbuffer object with a |
918 | | QRhiRenderBuffer. |
919 | | |
920 | | \value ThreeDimensionalTextures Indicates that 3D textures are supported. |
921 | | In practice this feature will be unsupported with OpenGL and OpenGL ES |
922 | | versions lower than 3.0. |
923 | | |
924 | | \value RenderTo3DTextureSlice Indicates that rendering to a slice in a 3D |
925 | | texture is supported. This can be unsupported with Vulkan 1.0 due to |
926 | | relying on VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT which is a Vulkan 1.1 |
927 | | feature. |
928 | | |
929 | | \value TextureArrays Indicates that texture arrays are supported and |
930 | | QRhi::newTextureArray() is functional. Note that even when texture arrays |
931 | | are not supported, arrays of textures are still available as those are two |
932 | | independent features. |
933 | | |
934 | | \value Tessellation Indicates that the tessellation control and evaluation |
935 | | stages are supported. When reported as supported, the topology of a |
936 | | QRhiGraphicsPipeline can be set to |
937 | | \l{QRhiGraphicsPipeline::Patches}{Patches}, the number of control points |
938 | | can be set via |
939 | | \l{QRhiGraphicsPipeline::setPatchControlPointCount()}{setPatchControlPointCount()}, |
940 | | and shaders for tessellation control and evaluation can be specified in the |
941 | | QRhiShaderStage list. Tessellation shaders have portability issues between |
942 | | APIs (for example, translating GLSL/SPIR-V to HLSL is problematic due to |
943 | | the way hull shaders are structured, whereas Metal uses a somewhat |
944 | | different tessellation pipeline than others), and therefore unexpected |
945 | | issues may still arise, even though basic functionality is implemented |
946 | | across all the underlying APIs. For Direct 3D in particular, handwritten |
947 | | HLSL hull and domain shaders must be injected into each QShader for the |
948 | | tessellation control and evaluation stages, respectively, since qsb cannot |
949 | | generate these from SPIR-V. Note that isoline tessellation should be |
950 | | avoided as it will not be supported by all backends. The maximum patch |
951 | | control point count portable between backends is 32. |
952 | | |
953 | | \value GeometryShader Indicates that the geometry shader stage is supported. |
954 | | When supported, a geometry shader can be specified in the QRhiShaderStage |
955 | | list. Geometry Shaders are considered an experimental feature in QRhi and |
956 | | can only be expected to be supported with Vulkan, Direct 3D 11 and 12, |
957 | | OpenGL (3.2+) and OpenGL ES (3.2+), assuming the implementation reports it |
958 | | as supported at run time. Starting with Qt 6.11 geometry shaders are |
959 | | automatically translated to HLSL, and therefore no injection of handwritten |
960 | | HLSL geometry shaders is necessary anymore (but note that gl_in and |
961 | | expressions such as gl_in[0].gl_Position are not supported; rather, pass the |
962 | | position as an output variable from the vertex shader). Geometry shaders are |
963 | | not supported with Metal. |
964 | | |
965 | | \value TextureArrayRange Indicates that for |
966 | | \l{QRhi::newTextureArray()}{texture arrays} it is possible to specify a |
967 | | range that is exposed to the shaders. Normally all array layers are exposed |
968 | | and it is up to the shader to select the layer (via the third coordinate |
969 | | passed to texture() when sampling the \c sampler2DArray). When supported, |
970 | | calling QRhiTexture::setArrayRangeStart() and |
971 | | QRhiTexture::setArrayRangeLength() before |
972 | | \l{QRhiTexture::create()}{building} or |
973 | | \l{QRhiTexture::createFrom()}{importing} the native texture has an effect, |
974 | | and leads to selecting only the specified range from the array. This will |
975 | | be necessary in special cases, such as when working with accelerated video |
976 | | decoding and Direct 3D 11, because a texture array with both |
977 | | \c{D3D11_BIND_DECODER} and \c{D3D11_BIND_SHADER_RESOURCE} on it is only |
978 | | usable as a shader resource if a single array layer is selected. Note that |
979 | | all this is applicable only when the texture is used as a |
980 | | QRhiShaderResourceBinding::SampledTexture or |
981 | | QRhiShaderResourceBinding::Texture shader resource, and is not compatible |
982 | | with image load/store. This feature is only available with some backends as |
983 | | it does not map well to all graphics APIs, and it is only meant to provide |
984 | | support for special cases anyhow. In practice the feature can be expected to |
985 | | be supported with Direct3D 11/12 and Vulkan. |
986 | | |
987 | | \value NonFillPolygonMode Indicates that setting a PolygonMode other than |
988 | | the default Fill is supported for QRhiGraphicsPipeline. A common use case |
989 | | for changing the mode to Line is to get wireframe rendering. This however |
990 | | is not available as a core OpenGL ES feature, and is optional with Vulkan |
991 | | as well as some mobile GPUs may not offer the feature. |
992 | | |
993 | | \value OneDimensionalTextures Indicates that 1D textures are supported. |
994 | | In practice this feature will be unsupported on OpenGL ES. |
995 | | |
996 | | \value OneDimensionalTextureMipmaps Indicates that generating 1D texture |
997 | | mipmaps is supported. In practice this feature will be unsupported on |
998 | | backends that do not report support for |
999 | | \l{OneDimensionalTextures}, Metal, and Direct 3D 12. |
1000 | | |
1001 | | \value HalfAttributes Indicates that specifying input attributes with half |
1002 | | precision (16bit) floating point types for a shader pipeline is supported. |
1003 | | When not supported, |
1004 | | \l{QRhiGraphicsPipeline::create()}{QRhiGraphicsPipeline::create()} will |
1005 | | succeed but show a warning message and the values of the target attributes |
1006 | | will be broken. In practice this feature will be unsupported in some OpenGL |
1007 | | ES 2.0 and OpenGL 2.x |
1008 | | implementations. Note that while Direct3D 11/12 does support half precision |
1009 | | input attributes, it does not support the half3 type. The D3D backends pass |
1010 | | half3 attributes as half4. To ensure cross platform compatibility, half3 |
1011 | | inputs should be padded to 8 bytes. |
1012 | | |
1013 | | \value RenderToOneDimensionalTexture Indicates that 1D texture render |
1014 | | targets are supported. In practice this feature will be unsupported on |
1015 | | backends that do not report support for |
1016 | | \l{OneDimensionalTextures}, and Metal. |
1017 | | |
1018 | | \value ThreeDimensionalTextureMipmaps Indicates that generating 3D texture |
1019 | | mipmaps is supported. This is typically supported with all backends starting |
1020 | | with Qt 6.10. |
1021 | | |
1022 | | \value MultiView Indicates that multiview, see e.g. |
1023 | | \l{https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_multiview.html}{VK_KHR_multiview} |
1024 | | is supported. With OpenGL ES 2.0, Direct 3D 11, and OpenGL (ES) |
1025 | | implementations without \c{GL_OVR_multiview2} this feature will not be |
1026 | | supported. With Vulkan 1.1 and newer, and Direct 3D 12 multiview is |
1027 | | typically supported. When reported as supported, creating a |
1028 | | QRhiTextureRenderTarget with a QRhiColorAttachment that references a texture |
1029 | | array and has \l{QRhiColorAttachment::setMultiViewCount()}{multiViewCount} |
1030 | | set enables recording a render pass that uses multiview rendering. In addition, |
1031 | | any QRhiGraphicsPipeline used in that render pass must have |
1032 | | \l{QRhiGraphicsPipeline::setMultiViewCount()}{the same view count set}. Note that |
1033 | | multiview is only available in combination with 2D texture arrays. It cannot |
1034 | | be used to optimize the rendering into individual textures (e.g. two, for |
1035 | | the left and right eyes). Rather, the target of a multiview render pass is |
1036 | | always a texture array, automatically rendering to the layer (array element) |
1037 | | corresponding to each view. Therefore this feature implies \l TextureArrays |
1038 | | as well. Multiview rendering is not supported in combination with |
1039 | | tessellation or geometry shaders. See QRhiColorAttachment::setMultiViewCount() |
1040 | | for further details on multiview rendering. This enum value has been introduced in Qt 6.7. |
1041 | | |
1042 | | \value TextureViewFormat Indicates that setting a |
1043 | | \l{QRhiTexture::setWriteViewFormat()}{view format} on a QRhiTexture is |
1044 | | effective. When reported as supported, setting the read (sampling) or write |
1045 | | (render target / image load-store) view mode changes the texture's viewing |
1046 | | format. When unsupported, setting a view format has no effect. Note that Qt |
1047 | | has no knowledge or control over format compatibility or resource view rules |
1048 | | in the underlying 3D API and its implementation. Passing in unsuitable, |
1049 | | incompatible formats may lead to errors and unspecified behavior. This is |
1050 | | provided mainly to allow "casting" rendering into a texture created with an |
1051 | | sRGB format to non-sRGB to avoid the unwanted linear->sRGB conversion on |
1052 | | shader writes. Other types of casting may or may not be functional, |
1053 | | depending on the underlying API. Currently implemented for Vulkan and Direct |
1054 | | 3D 12. With D3D12 the feature is available only if |
1055 | | \c CastingFullyTypedFormatSupported is supported, see |
1056 | | \l{https://microsoft.github.io/DirectX-Specs/d3d/RelaxedCasting.html} (and |
1057 | | note that QRhi always uses fully typed formats for textures.) This enum |
1058 | | value has been introduced in Qt 6.8. |
1059 | | |
1060 | | \value ResolveDepthStencil Indicates that resolving a multisample depth or |
1061 | | depth-stencil texture is supported. Otherwise, |
1062 | | \l{QRhiTextureRenderTargetDescription::setDepthResolveTexture()}{setting a |
1063 | | depth resolve texture} is not functional and must be avoided. Direct 3D 11 |
1064 | | and 12 have no support for resolving depth/depth-stencil formats, and |
1065 | | therefore this feature will never be supported with those. Vulkan 1.0 has no |
1066 | | API to request resolving a depth-stencil attachment. Therefore, with Vulkan |
1067 | | this feature will only be supported with Vulkan 1.2 and up, and on 1.1 |
1068 | | implementations with the appropriate extensions present. This feature is |
1069 | | provided for the rare case when resolving into a non-multisample depth |
1070 | | texture becomes necessary, for example when rendering into an |
1071 | | OpenXR-provided depth texture (XR_KHR_composition_layer_depth). This enum |
1072 | | value has been introduced in Qt 6.8. |
1073 | | |
1074 | | \value VariableRateShading Indicates that per-draw (per-pipeline) variable |
1075 | | rate shading is supported. When reported as supported, \l |
1076 | | QRhiCommandBuffer::setShadingRate() is functional and has an effect for |
1077 | | QRhiGraphicsPipeline objects that declared \l |
1078 | | QRhiGraphicsPipeline::UsesShadingRate in their flags. Call \l |
1079 | | QRhi::supportedShadingRates() to check which rates are supported. (1x1 is |
1080 | | always supported, other typical values are 2x2, 1x2, 2x1, 2x4, 4x2, 4x4). |
1081 | | This feature can be expected to be supported with Direct 3D 12 and Vulkan, |
1082 | | assuming the implementation and GPU used at run time supports VRS. This enum |
1083 | | value has been introduced in Qt 6.9. |
1084 | | |
1085 | | \value VariableRateShadingMap Indicates that image-based specification of |
1086 | | the shading rate is possible. The "image" is not necessarily a texture, it |
1087 | | may be a native 3D API object, depending on the underlying backend and |
1088 | | graphics API at run time. In practice this feature can be expected to be |
1089 | | supported with Direct 3D 12, Vulkan, and Metal, assuming the GPU is modern |
1090 | | enough to support VRS. To check if D3D12/Vulkan-style image-based VRS is |
1091 | | supported, use VariableRateShadingMapWithTexture instead. When this feature |
1092 | | is reported as supported, there are two possibilities: when |
1093 | | VariableRateShadingMapWithTexture is also true, then QRhiShadingRateMap |
1094 | | consumes QRhiTexture objects via the createFrom() overload taking a |
1095 | | QRhiTexture argument. When VariableRateShadingMapWithTexture is false, then |
1096 | | QRhiShadingRateMap consumes some other type of native objects, for example |
1097 | | an MTLRasterizationRateMap in case of Metal. Use the createFrom() overload |
1098 | | taking a NativeShadingRateMap in this case. This enum value has been |
1099 | | introduced in Qt 6.9. |
1100 | | |
1101 | | \value VariableRateShadingMapWithTexture Indicates that image-based |
1102 | | specification of the shading rate is supported via regular textures. In |
1103 | | practice this may be supported with Direct 3D 12 and Vulkan. This enum value |
1104 | | has been introduced in Qt 6.9. |
1105 | | |
1106 | | \value PerRenderTargetBlending Indicates that per rendertarget blending is |
1107 | | supported i.e. different render targets in MRT framebuffer can have different |
1108 | | blending modes. In practice this can be expected to be supported everywhere |
1109 | | except OpenGL ES, where it is only available with GLES 3.2 implementations. |
1110 | | This enum value has been introduced in Qt 6.9. |
1111 | | |
1112 | | \value SampleVariables Indicates that gl_SampleID, gl_SamplePosition, |
1113 | | gl_SampleMaskIn and gl_SampleMask variables are available in fragment shaders. |
1114 | | In practice this can be expected to be supported everywhere except OpenGL ES, |
1115 | | where it is only available with GLES 3.2 implementations. |
1116 | | This enum value has been introduced in Qt 6.9. |
1117 | | |
1118 | | \value InstanceIndexIncludesBaseInstance Indicates that \c gl_InstanceIndex |
1119 | | includes the base instance (the \c firstInstance argument in draw calls) in |
1120 | | its value. When this feature is unsupported, but BaseInstance is, it |
1121 | | indicates that \c gl_InstanceIndex always starts at 0, not the base value. |
1122 | | In practice this will be the case for Direct 3D 11 and 12 at the moment. |
1123 | | With Vulkan and Metal this feature is expected to be reported as supported |
1124 | | always. This enum value has been introduced in Qt 6.11. |
1125 | | |
1126 | | \value [since 6.11] DepthClamp Indicates that enabling depth clamping is |
1127 | | supported. When reported as unsupported, which will be the case with OpenGL |
1128 | | ES, OpenGL versions before 3.2 without the relevant extension present, and |
1129 | | Metal on the iOS Simulator, calling \l{QRhiGraphicsPipeline::setDepthClamp()} |
1130 | | with an argument of \c true has no effect. |
1131 | | |
1132 | | \value [since 6.12] DrawIndirect Indicates that the |
1133 | | \l{QRhiCommandBuffer::drawIndirect()}{drawIndirect()} |
1134 | | and \l{QRhiCommandBuffer::drawIndexedIndirect()}{drawIndexedIndirect()} |
1135 | | functions are available. |
1136 | | In practice this can be expected to be supported everywhere except on |
1137 | | OpenGL ES < 3.1. |
1138 | | |
1139 | | \value [since 6.12] DrawIndirectMulti Indicates that a drawCount > 1 is natively |
1140 | | supported by the backend in \l{QRhiCommandBuffer::drawIndirect()}{drawIndirect()} |
1141 | | and \l{QRhiCommandBuffer::drawIndexedIndirect()}{drawIndexedIndirect()}. |
1142 | | Otherwise, multiple draw calls are issued on the CPU by the RHI. |
1143 | | In practice this can be expected to be supported on Vulkan 1.1+, OpenGL 4.3+ |
1144 | | and D3D12. |
1145 | | |
1146 | | \value [since 6.12] ShaderDrawParameters Indicates that the \c{gl_BaseInstance}, |
1147 | | \c{gl_BaseVertex} and \c{gl_DrawID} built-in variables are available in shaders. |
1148 | | In practice this can be expected to be supported on Vulkan 1.1+ and with desktop OpenGL |
1149 | | 4.6 or \c{GL_ARB_shader_draw_parameters}. |
1150 | | */ |
1151 | | |
1152 | | /*! |
1153 | | \enum QRhi::BeginFrameFlag |
1154 | | Flag values for QRhi::beginFrame() |
1155 | | */ |
1156 | | |
1157 | | /*! |
1158 | | \enum QRhi::EndFrameFlag |
1159 | | Flag values for QRhi::endFrame() |
1160 | | |
1161 | | \value SkipPresent Specifies that no present command is to be queued or no |
1162 | | swapBuffers call is to be made. This way no image is presented. Generating |
1163 | | multiple frames with all having this flag set is not recommended (except, |
1164 | | for example, for benchmarking purposes - but keep in mind that backends may |
1165 | | behave differently when it comes to waiting for command completion without |
1166 | | presenting so the results are not comparable between them) |
1167 | | */ |
1168 | | |
1169 | | /*! |
1170 | | \enum QRhi::ResourceLimit |
1171 | | Describes the resource limit to query. |
1172 | | |
1173 | | \value TextureSizeMin Minimum texture width and height. This is typically |
1174 | | 1. The minimum texture size is handled gracefully, meaning attempting to |
1175 | | create a texture with an empty size will instead create a texture with the |
1176 | | minimum size. |
1177 | | |
1178 | | \value TextureSizeMax Maximum texture width and height. This depends on the |
1179 | | graphics API and sometimes the platform or implementation as well. |
1180 | | Typically the value is in the range 4096 - 16384. Attempting to create |
1181 | | textures larger than this is expected to fail. |
1182 | | |
1183 | | \value MaxColorAttachments The maximum number of color attachments for a |
1184 | | QRhiTextureRenderTarget, in case multiple render targets are supported. When |
1185 | | MRT is not supported, the value is 1. Otherwise this is typically 8, but |
1186 | | watch out for the fact that OpenGL only mandates 4 as the minimum, and that |
1187 | | is what some OpenGL ES implementations provide. |
1188 | | |
1189 | | \value FramesInFlight The number of frames the backend may keep "in |
1190 | | flight": with backends like Vulkan or Metal, it is the responsibility of |
1191 | | QRhi to block whenever starting a new frame and finding the CPU is already |
1192 | | \c{N - 1} frames ahead of the GPU (because the command buffer submitted in |
1193 | | frame no. \c{current} - \c{N} has not yet completed). The value N is what |
1194 | | is returned from here, and is typically 2. This can be relevant to |
1195 | | applications that integrate rendering done directly with the graphics API, |
1196 | | as such rendering code may want to perform double (if the value is 2) |
1197 | | buffering for resources, such as, buffers, similarly to the QRhi backends |
1198 | | themselves. The current frame slot index (a value running 0, 1, .., N-1, |
1199 | | then wrapping around) is retrievable from QRhi::currentFrameSlot(). The |
1200 | | value is 1 for backends where the graphics API offers no such low level |
1201 | | control over the command submission process. Note that pipelining may still |
1202 | | happen even when this value is 1 (some backends, such as D3D11, are |
1203 | | designed to attempt to enable this, for instance, by using an update |
1204 | | strategy for uniform buffers that does not stall the pipeline), but that is |
1205 | | then not controlled by QRhi and so not reflected here in the API. |
1206 | | |
1207 | | \value MaxAsyncReadbackFrames The number of \l{QRhi::endFrame()}{submitted} |
1208 | | frames (including the one that contains the readback) after which an |
1209 | | asynchronous texture or buffer readback is guaranteed to complete upon |
1210 | | \l{QRhi::beginFrame()}{starting a new frame}. |
1211 | | |
1212 | | \value MaxThreadGroupsPerDimension The maximum number of compute |
1213 | | work/thread groups that can be dispatched. Effectively the maximum value |
1214 | | for the arguments of QRhiCommandBuffer::dispatch(). Typically 65535. |
1215 | | |
1216 | | \value MaxThreadsPerThreadGroup The maximum number of invocations in a |
1217 | | single local work group, or in other terminology, the maximum number of |
1218 | | threads in a thread group. Effectively the maximum value for the product of |
1219 | | \c local_size_x, \c local_size_y, and \c local_size_z in the compute |
1220 | | shader. Typical values are 128, 256, 512, 1024, or 1536. Watch out that |
1221 | | both OpenGL ES and Vulkan specify only 128 as the minimum required limit |
1222 | | for implementations. While uncommon for Vulkan, some OpenGL ES 3.1 |
1223 | | implementations for mobile/embedded devices only support the spec-mandated |
1224 | | minimum value. |
1225 | | |
1226 | | \value MaxThreadGroupX The maximum size of a work/thread group in the X |
1227 | | dimension. Effectively the maximum value of \c local_size_x in the compute |
1228 | | shader. Typically 256 or 1024. |
1229 | | |
1230 | | \value MaxThreadGroupY The maximum size of a work/thread group in the Y |
1231 | | dimension. Effectively the maximum value of \c local_size_y in the compute |
1232 | | shader. Typically 256 or 1024. |
1233 | | |
1234 | | \value MaxThreadGroupZ The maximum size of a work/thread group in the Z |
1235 | | dimension. Effectively the maximum value of \c local_size_z in the compute |
1236 | | shader. Typically 64 or 256. |
1237 | | |
1238 | | \value TextureArraySizeMax Maximum texture array size. Typically in range |
1239 | | 256 - 2048. Attempting to \l{QRhi::newTextureArray()}{create a texture |
1240 | | array} with more elements will likely fail. |
1241 | | |
1242 | | \value MaxUniformBufferRange The number of bytes that can be exposed from a |
1243 | | uniform buffer to the shaders at once. On OpenGL ES 2.0 and 3.0 |
1244 | | implementations this may be as low as 3584 bytes (224 four component, 32 |
1245 | | bits per component vectors). Elsewhere the value is typically 16384 (1024 |
1246 | | vec4s) or 65536 (4096 vec4s). |
1247 | | |
1248 | | \value MaxVertexInputs The number of input attributes to the vertex shader. |
1249 | | The location in a QRhiVertexInputAttribute must be in range \c{[0, |
1250 | | MaxVertexInputs-1]}. The value may be as low as 8 with OpenGL ES 2.0. |
1251 | | Elsewhere, typical values are 16, 31, or 32. |
1252 | | |
1253 | | \value MaxVertexOutputs The maximum number of outputs (4 component vector |
1254 | | \c out variables) from the vertex shader. The value may be as low as 8 with |
1255 | | OpenGL ES 2.0, and 15 with OpenGL ES 3.0 and some Metal devices. Elsewhere, |
1256 | | a typical value is 32. |
1257 | | |
1258 | | \value ShadingRateImageTileSize The tile size for shading rate textures. 0 |
1259 | | if the QRhi::VariableRateShadingMapWithTexture feature is not supported. |
1260 | | Otherwise a value such as 16, indicating, for example, a tile size of 16x16. |
1261 | | Each byte in the (R8UI) shading rate texture defines then the shading rate |
1262 | | for a tile of 16x16 pixels. See \l QRhiShadingRateMap for details. |
1263 | | */ |
1264 | | |
1265 | | /*! |
1266 | | \class QRhiInitParams |
1267 | | \inmodule QtGuiPrivate |
1268 | | \inheaderfile rhi/qrhi.h |
1269 | | \since 6.6 |
1270 | | \brief Base class for backend-specific initialization parameters. |
1271 | | |
1272 | | Contains fields that are relevant to all backends. |
1273 | | |
1274 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1275 | | for details. |
1276 | | */ |
1277 | | |
1278 | | /*! |
1279 | | \class QRhiDepthStencilClearValue |
1280 | | \inmodule QtGuiPrivate |
1281 | | \inheaderfile rhi/qrhi.h |
1282 | | \since 6.6 |
1283 | | \brief Specifies clear values for a depth or stencil buffer. |
1284 | | |
1285 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1286 | | for details. |
1287 | | */ |
1288 | | |
1289 | | /*! |
1290 | | \fn QRhiDepthStencilClearValue::QRhiDepthStencilClearValue() = default |
1291 | | |
1292 | | Constructs a depth/stencil clear value with depth clear value 1.0f and |
1293 | | stencil clear value 0. |
1294 | | */ |
1295 | | |
1296 | | /*! |
1297 | | Constructs a depth/stencil clear value with depth clear value \a d and |
1298 | | stencil clear value \a s. |
1299 | | */ |
1300 | | QRhiDepthStencilClearValue::QRhiDepthStencilClearValue(float d, quint32 s) |
1301 | 0 | : m_d(d), |
1302 | 0 | m_s(s) |
1303 | 0 | { |
1304 | 0 | } |
1305 | | |
1306 | | /*! |
1307 | | \fn float QRhiDepthStencilClearValue::depthClearValue() const |
1308 | | \return the depth clear value. In most cases this is 1.0f. |
1309 | | */ |
1310 | | |
1311 | | /*! |
1312 | | \fn void QRhiDepthStencilClearValue::setDepthClearValue(float d) |
1313 | | Sets the depth clear value to \a d. |
1314 | | */ |
1315 | | |
1316 | | /*! |
1317 | | \fn quint32 QRhiDepthStencilClearValue::stencilClearValue() const |
1318 | | \return the stencil clear value. In most cases this is 0. |
1319 | | */ |
1320 | | |
1321 | | /*! |
1322 | | \fn void QRhiDepthStencilClearValue::setStencilClearValue(quint32 s) |
1323 | | Sets the stencil clear value to \a s. |
1324 | | */ |
1325 | | |
1326 | | /*! |
1327 | | \fn bool QRhiDepthStencilClearValue::operator==(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept |
1328 | | |
1329 | | \return \c true if the values in the two QRhiDepthStencilClearValue objects |
1330 | | \a a and \a b are equal. |
1331 | | */ |
1332 | | |
1333 | | /*! |
1334 | | \fn bool QRhiDepthStencilClearValue::operator!=(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept |
1335 | | |
1336 | | \return \c false if the values in the two QRhiDepthStencilClearValue |
1337 | | objects \a a and \a b are equal; otherwise returns \c true. |
1338 | | |
1339 | | */ |
1340 | | |
1341 | | /*! |
1342 | | \fn size_t QRhiDepthStencilClearValue::qHash(const QRhiDepthStencilClearValue &key, size_t seed) |
1343 | | \qhash{QRhiDepthStencilClearValue} |
1344 | | */ |
1345 | | |
1346 | | #ifndef QT_NO_DEBUG_STREAM |
1347 | | QDebug operator<<(QDebug dbg, const QRhiDepthStencilClearValue &v) |
1348 | 0 | { |
1349 | 0 | QDebugStateSaver saver(dbg); |
1350 | 0 | dbg.nospace() << "QRhiDepthStencilClearValue(depth-clear=" << v.depthClearValue() |
1351 | 0 | << " stencil-clear=" << v.stencilClearValue() |
1352 | 0 | << ')'; |
1353 | 0 | return dbg; |
1354 | 0 | } |
1355 | | #endif |
1356 | | |
1357 | | /*! |
1358 | | \class QRhiViewport |
1359 | | \inmodule QtGuiPrivate |
1360 | | \inheaderfile rhi/qrhi.h |
1361 | | \since 6.6 |
1362 | | \brief Specifies a viewport rectangle. |
1363 | | |
1364 | | Used with QRhiCommandBuffer::setViewport(). |
1365 | | |
1366 | | QRhi assumes OpenGL-style viewport coordinates, meaning x and y are |
1367 | | bottom-left. Negative width or height are not allowed. |
1368 | | |
1369 | | Typical usage is like the following: |
1370 | | |
1371 | | \code |
1372 | | const QSize outputSizeInPixels = swapchain->currentPixelSize(); |
1373 | | const QRhiViewport viewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height()); |
1374 | | cb->beginPass(swapchain->currentFrameRenderTarget(), Qt::black, { 1.0f, 0 }); |
1375 | | cb->setGraphicsPipeline(ps); |
1376 | | cb->setViewport(viewport); |
1377 | | // ... |
1378 | | \endcode |
1379 | | |
1380 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1381 | | for details. |
1382 | | |
1383 | | \sa QRhiCommandBuffer::setViewport(), QRhi::clipSpaceCorrMatrix(), QRhiScissor |
1384 | | */ |
1385 | | |
1386 | | /*! |
1387 | | \fn QRhiViewport::QRhiViewport() = default |
1388 | | |
1389 | | Constructs a viewport description with an empty rectangle and a depth range |
1390 | | of 0.0f - 1.0f. |
1391 | | |
1392 | | \sa QRhi::clipSpaceCorrMatrix() |
1393 | | */ |
1394 | | |
1395 | | /*! |
1396 | | Constructs a viewport description with the rectangle specified by \a x, \a |
1397 | | y, \a w, \a h and the depth range \a minDepth and \a maxDepth. |
1398 | | |
1399 | | \note \a x and \a y are assumed to be the bottom-left position. \a w and \a |
1400 | | h should not be negative, the viewport will be ignored by |
1401 | | QRhiCommandBuffer::setViewport() otherwise. |
1402 | | |
1403 | | \sa QRhi::clipSpaceCorrMatrix() |
1404 | | */ |
1405 | | QRhiViewport::QRhiViewport(float x, float y, float w, float h, float minDepth, float maxDepth) |
1406 | 0 | : m_rect { { x, y, w, h } }, |
1407 | 0 | m_minDepth(minDepth), |
1408 | 0 | m_maxDepth(maxDepth) |
1409 | 0 | { |
1410 | 0 | } |
1411 | | |
1412 | | /*! |
1413 | | \fn std::array<float, 4> QRhiViewport::viewport() const |
1414 | | \return the viewport x, y, width, and height. |
1415 | | */ |
1416 | | |
1417 | | /*! |
1418 | | \fn void QRhiViewport::setViewport(float x, float y, float w, float h) |
1419 | | Sets the viewport's position and size to \a x, \a y, \a w, and \a h. |
1420 | | |
1421 | | \note Viewports are specified in a coordinate system that has its origin in |
1422 | | the bottom-left. |
1423 | | */ |
1424 | | |
1425 | | /*! |
1426 | | \fn float QRhiViewport::minDepth() const |
1427 | | \return the minDepth value of the depth range of the viewport. |
1428 | | */ |
1429 | | |
1430 | | /*! |
1431 | | \fn void QRhiViewport::setMinDepth(float minDepth) |
1432 | | Sets the \a minDepth of the depth range of the viewport. |
1433 | | By default this is set to 0.0f. |
1434 | | */ |
1435 | | |
1436 | | /*! |
1437 | | \fn float QRhiViewport::maxDepth() const |
1438 | | \return the maxDepth value of the depth range of the viewport. |
1439 | | */ |
1440 | | |
1441 | | /*! |
1442 | | \fn void QRhiViewport::setMaxDepth(float maxDepth) |
1443 | | Sets the \a maxDepth of the depth range of the viewport. |
1444 | | By default this is set to 1.0f. |
1445 | | */ |
1446 | | |
1447 | | /*! |
1448 | | \fn bool QRhiViewport::operator==(const QRhiViewport &a, const QRhiViewport &b) noexcept |
1449 | | |
1450 | | \return \c true if the values in the two QRhiViewport objects |
1451 | | \a a and \a b are equal. |
1452 | | */ |
1453 | | |
1454 | | /*! |
1455 | | \fn bool QRhiViewport::operator!=(const QRhiViewport &a, const QRhiViewport &b) noexcept |
1456 | | |
1457 | | \return \c false if the values in the two QRhiViewport |
1458 | | objects \a a and \a b are equal; otherwise returns \c true. |
1459 | | */ |
1460 | | |
1461 | | /*! |
1462 | | \fn size_t QRhiViewport::qHash(const QRhiViewport &key, size_t seed) |
1463 | | \qhash{QRhiViewport} |
1464 | | */ |
1465 | | |
1466 | | #ifndef QT_NO_DEBUG_STREAM |
1467 | | QDebug operator<<(QDebug dbg, const QRhiViewport &v) |
1468 | 0 | { |
1469 | 0 | QDebugStateSaver saver(dbg); |
1470 | 0 | const std::array<float, 4> r = v.viewport(); |
1471 | 0 | dbg.nospace() << "QRhiViewport(bottom-left-x=" << r[0] |
1472 | 0 | << " bottom-left-y=" << r[1] |
1473 | 0 | << " width=" << r[2] |
1474 | 0 | << " height=" << r[3] |
1475 | 0 | << " minDepth=" << v.minDepth() |
1476 | 0 | << " maxDepth=" << v.maxDepth() |
1477 | 0 | << ')'; |
1478 | 0 | return dbg; |
1479 | 0 | } |
1480 | | #endif |
1481 | | |
1482 | | /*! |
1483 | | \class QRhiScissor |
1484 | | \inmodule QtGuiPrivate |
1485 | | \inheaderfile rhi/qrhi.h |
1486 | | \since 6.6 |
1487 | | \brief Specifies a scissor rectangle. |
1488 | | |
1489 | | Used with QRhiCommandBuffer::setScissor(). Setting a scissor rectangle is |
1490 | | only possible with a QRhiGraphicsPipeline that has |
1491 | | QRhiGraphicsPipeline::UsesScissor set. |
1492 | | |
1493 | | QRhi assumes OpenGL-style scissor coordinates, meaning x and y are |
1494 | | bottom-left. Negative width or height are not allowed. However, apart from |
1495 | | that, the flexible OpenGL semantics apply: negative x and y, partially out |
1496 | | of bounds rectangles, etc. will be handled gracefully, clamping as |
1497 | | appropriate. Therefore, any rendering logic targeting OpenGL can feed |
1498 | | scissor rectangles into QRhiScissor as-is, without any adaptation. |
1499 | | |
1500 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1501 | | for details. |
1502 | | |
1503 | | \sa QRhiCommandBuffer::setScissor(), QRhiViewport |
1504 | | */ |
1505 | | |
1506 | | /*! |
1507 | | \fn QRhiScissor::QRhiScissor() = default |
1508 | | |
1509 | | Constructs an empty scissor. |
1510 | | */ |
1511 | | |
1512 | | /*! |
1513 | | Constructs a scissor with the rectangle specified by \a x, \a y, \a w, and |
1514 | | \a h. |
1515 | | |
1516 | | \note \a x and \a y are assumed to be the bottom-left position. Negative \a w |
1517 | | or \a h are not allowed, such scissor rectangles will be ignored by |
1518 | | QRhiCommandBuffer. Other than that, the flexible OpenGL semantics apply: |
1519 | | negative x and y, partially out of bounds rectangles, etc. will be handled |
1520 | | gracefully, clamping as appropriate. |
1521 | | */ |
1522 | | QRhiScissor::QRhiScissor(int x, int y, int w, int h) |
1523 | 0 | : m_rect { { x, y, w, h } } |
1524 | 0 | { |
1525 | 0 | } |
1526 | | |
1527 | | /*! |
1528 | | \fn std::array<int, 4> QRhiScissor::scissor() const |
1529 | | \return the scissor position and size. |
1530 | | */ |
1531 | | |
1532 | | /*! |
1533 | | \fn void QRhiScissor::setScissor(int x, int y, int w, int h) |
1534 | | Sets the scissor position and size to \a x, \a y, \a w, \a h. |
1535 | | |
1536 | | \note The position is always expected to be specified in a coordinate |
1537 | | system that has its origin in the bottom-left corner, like OpenGL. |
1538 | | */ |
1539 | | |
1540 | | /*! |
1541 | | \fn bool QRhiScissor::operator==(const QRhiScissor &a, const QRhiScissor &b) noexcept |
1542 | | |
1543 | | \return \c true if the values in the two QRhiScissor objects |
1544 | | \a a and \a b are equal. |
1545 | | */ |
1546 | | |
1547 | | /*! |
1548 | | \fn bool QRhiScissor::operator!=(const QRhiScissor &a, const QRhiScissor &b) noexcept |
1549 | | |
1550 | | \return \c false if the values in the two QRhiScissor |
1551 | | objects \a a and \a b are equal; otherwise returns \c true. |
1552 | | */ |
1553 | | |
1554 | | /*! |
1555 | | \fn size_t QRhiScissor::qHash(const QRhiScissor &key, size_t seed) |
1556 | | \qhash{QRhiScissor} |
1557 | | */ |
1558 | | |
1559 | | #ifndef QT_NO_DEBUG_STREAM |
1560 | | QDebug operator<<(QDebug dbg, const QRhiScissor &s) |
1561 | 0 | { |
1562 | 0 | QDebugStateSaver saver(dbg); |
1563 | 0 | const std::array<int, 4> r = s.scissor(); |
1564 | 0 | dbg.nospace() << "QRhiScissor(bottom-left-x=" << r[0] |
1565 | 0 | << " bottom-left-y=" << r[1] |
1566 | 0 | << " width=" << r[2] |
1567 | 0 | << " height=" << r[3] |
1568 | 0 | << ')'; |
1569 | 0 | return dbg; |
1570 | 0 | } |
1571 | | #endif |
1572 | | |
1573 | | /*! |
1574 | | \class QRhiVertexInputBinding |
1575 | | \inmodule QtGuiPrivate |
1576 | | \inheaderfile rhi/qrhi.h |
1577 | | \since 6.6 |
1578 | | \brief Describes a vertex input binding. |
1579 | | |
1580 | | Specifies the stride (in bytes, must be a multiple of 4), the |
1581 | | classification and optionally the instance step rate. |
1582 | | |
1583 | | As an example, assume a vertex shader with the following inputs: |
1584 | | |
1585 | | \badcode |
1586 | | layout(location = 0) in vec4 position; |
1587 | | layout(location = 1) in vec2 texcoord; |
1588 | | \endcode |
1589 | | |
1590 | | Now let's assume also that 3 component vertex positions \c{(x, y, z)} and 2 |
1591 | | component texture coordinates \c{(u, v)} are provided in a non-interleaved |
1592 | | format in a buffer (or separate buffers even). Defining two bindings |
1593 | | could then be done like this: |
1594 | | |
1595 | | \code |
1596 | | QRhiVertexInputLayout inputLayout; |
1597 | | inputLayout.setBindings({ |
1598 | | { 3 * sizeof(float) }, |
1599 | | { 2 * sizeof(float) } |
1600 | | }); |
1601 | | \endcode |
1602 | | |
1603 | | Only the stride is interesting here since instancing is not used. The |
1604 | | binding number is given by the index of the QRhiVertexInputBinding |
1605 | | element in the bindings vector of the QRhiVertexInputLayout. |
1606 | | |
1607 | | Once a graphics pipeline with this vertex input layout is bound, the vertex |
1608 | | inputs could be set up like the following for drawing a cube with 36 |
1609 | | vertices, assuming we have a single buffer with first the positions and |
1610 | | then the texture coordinates: |
1611 | | |
1612 | | \code |
1613 | | const QRhiCommandBuffer::VertexInput vbufBindings[] = { |
1614 | | { cubeBuf, 0 }, |
1615 | | { cubeBuf, 36 * 3 * sizeof(float) } |
1616 | | }; |
1617 | | cb->setVertexInput(0, 2, vbufBindings); |
1618 | | \endcode |
1619 | | |
1620 | | Note how the index defined by \c {startBinding + i}, where \c i is the |
1621 | | index in the second argument of |
1622 | | \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()}, matches the |
1623 | | index of the corresponding entry in the \c bindings vector of the |
1624 | | QRhiVertexInputLayout. |
1625 | | |
1626 | | \note the stride must always be a multiple of 4. |
1627 | | |
1628 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1629 | | for details. |
1630 | | |
1631 | | \sa QRhiCommandBuffer::setVertexInput() |
1632 | | */ |
1633 | | |
1634 | | /*! |
1635 | | \enum QRhiVertexInputBinding::Classification |
1636 | | Describes the input data classification. |
1637 | | |
1638 | | \value PerVertex Data is per-vertex |
1639 | | \value PerInstance Data is per-instance |
1640 | | */ |
1641 | | |
1642 | | /*! |
1643 | | \fn QRhiVertexInputBinding::QRhiVertexInputBinding() = default |
1644 | | |
1645 | | Constructs a default vertex input binding description. |
1646 | | */ |
1647 | | |
1648 | | /*! |
1649 | | Constructs a vertex input binding description with the specified \a stride, |
1650 | | classification \a cls, and instance step rate \a stepRate. |
1651 | | |
1652 | | \note \a stepRate other than 1 is only supported when |
1653 | | QRhi::CustomInstanceStepRate is reported to be supported. |
1654 | | */ |
1655 | | QRhiVertexInputBinding::QRhiVertexInputBinding(quint32 stride, Classification cls, quint32 stepRate) |
1656 | 0 | : m_stride(stride), |
1657 | 0 | m_classification(cls), |
1658 | 0 | m_instanceStepRate(stepRate) |
1659 | 0 | { |
1660 | 0 | } |
1661 | | |
1662 | | /*! |
1663 | | \fn quint32 QRhiVertexInputBinding::stride() const |
1664 | | \return the stride in bytes. |
1665 | | */ |
1666 | | |
1667 | | /*! |
1668 | | \fn void QRhiVertexInputBinding::setStride(quint32 s) |
1669 | | Sets the stride to \a s. |
1670 | | */ |
1671 | | |
1672 | | /*! |
1673 | | \fn QRhiVertexInputBinding::Classification QRhiVertexInputBinding::classification() const |
1674 | | \return the input data classification. |
1675 | | */ |
1676 | | |
1677 | | /*! |
1678 | | \fn void QRhiVertexInputBinding::setClassification(Classification c) |
1679 | | Sets the input data classification \a c. By default this is set to PerVertex. |
1680 | | */ |
1681 | | |
1682 | | /*! |
1683 | | \fn quint32 QRhiVertexInputBinding::instanceStepRate() const |
1684 | | \return the instance step rate. |
1685 | | */ |
1686 | | |
1687 | | /*! |
1688 | | \fn void QRhiVertexInputBinding::setInstanceStepRate(quint32 rate) |
1689 | | Sets the instance step \a rate. By default this is set to 1. |
1690 | | */ |
1691 | | |
1692 | | /*! |
1693 | | \fn bool QRhiVertexInputBinding::operator==(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept |
1694 | | |
1695 | | \return \c true if the values in the two QRhiVertexInputBinding objects |
1696 | | \a a and \a b are equal. |
1697 | | */ |
1698 | | |
1699 | | /*! |
1700 | | \fn bool QRhiVertexInputBinding::operator!=(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept |
1701 | | |
1702 | | \return \c false if the values in the two QRhiVertexInputBinding |
1703 | | objects \a a and \a b are equal; otherwise returns \c true. |
1704 | | */ |
1705 | | |
1706 | | /*! |
1707 | | \fn size_t QRhiVertexInputBinding::qHash(const QRhiVertexInputBinding &key, size_t seed) |
1708 | | \qhash{QRhiVertexInputBinding} |
1709 | | */ |
1710 | | |
1711 | | #ifndef QT_NO_DEBUG_STREAM |
1712 | | QDebug operator<<(QDebug dbg, const QRhiVertexInputBinding &b) |
1713 | 0 | { |
1714 | 0 | QDebugStateSaver saver(dbg); |
1715 | 0 | dbg.nospace() << "QRhiVertexInputBinding(stride=" << b.stride() |
1716 | 0 | << " cls=" << b.classification() |
1717 | 0 | << " step-rate=" << b.instanceStepRate() |
1718 | 0 | << ')'; |
1719 | 0 | return dbg; |
1720 | 0 | } |
1721 | | #endif |
1722 | | |
1723 | | /*! |
1724 | | \class QRhiVertexInputAttribute |
1725 | | \inmodule QtGuiPrivate |
1726 | | \inheaderfile rhi/qrhi.h |
1727 | | \since 6.6 |
1728 | | \brief Describes a single vertex input element. |
1729 | | |
1730 | | The members specify the binding number, location, format, and offset for a |
1731 | | single vertex input element. |
1732 | | |
1733 | | \note For HLSL it is assumed that the vertex shader translated from SPIR-V |
1734 | | uses |
1735 | | \c{TEXCOORD<location>} as the semantic for each input. Hence no separate |
1736 | | semantic name and index. |
1737 | | |
1738 | | As an example, assume a vertex shader with the following inputs: |
1739 | | |
1740 | | \badcode |
1741 | | layout(location = 0) in vec4 position; |
1742 | | layout(location = 1) in vec2 texcoord; |
1743 | | \endcode |
1744 | | |
1745 | | Now let's assume that we have 3 component vertex positions \c{(x, y, z)} |
1746 | | and 2 component texture coordinates \c{(u, v)} are provided in a |
1747 | | non-interleaved format in a buffer (or separate buffers even). Once two |
1748 | | bindings are defined, the attributes could be specified as: |
1749 | | |
1750 | | \code |
1751 | | QRhiVertexInputLayout inputLayout; |
1752 | | inputLayout.setBindings({ |
1753 | | { 3 * sizeof(float) }, |
1754 | | { 2 * sizeof(float) } |
1755 | | }); |
1756 | | inputLayout.setAttributes({ |
1757 | | { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, |
1758 | | { 1, 1, QRhiVertexInputAttribute::Float2, 0 } |
1759 | | }); |
1760 | | \endcode |
1761 | | |
1762 | | Once a graphics pipeline with this vertex input layout is bound, the vertex |
1763 | | inputs could be set up like the following for drawing a cube with 36 |
1764 | | vertices, assuming we have a single buffer with first the positions and |
1765 | | then the texture coordinates: |
1766 | | |
1767 | | \code |
1768 | | const QRhiCommandBuffer::VertexInput vbufBindings[] = { |
1769 | | { cubeBuf, 0 }, |
1770 | | { cubeBuf, 36 * 3 * sizeof(float) } |
1771 | | }; |
1772 | | cb->setVertexInput(0, 2, vbufBindings); |
1773 | | \endcode |
1774 | | |
1775 | | When working with interleaved data, there will typically be just one |
1776 | | binding, with multiple attributes referring to that same buffer binding |
1777 | | point: |
1778 | | |
1779 | | \code |
1780 | | QRhiVertexInputLayout inputLayout; |
1781 | | inputLayout.setBindings({ |
1782 | | { 5 * sizeof(float) } |
1783 | | }); |
1784 | | inputLayout.setAttributes({ |
1785 | | { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, |
1786 | | { 0, 1, QRhiVertexInputAttribute::Float2, 3 * sizeof(float) } |
1787 | | }); |
1788 | | \endcode |
1789 | | |
1790 | | and then: |
1791 | | |
1792 | | \code |
1793 | | const QRhiCommandBuffer::VertexInput vbufBinding(interleavedCubeBuf, 0); |
1794 | | cb->setVertexInput(0, 1, &vbufBinding); |
1795 | | \endcode |
1796 | | |
1797 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
1798 | | for details. |
1799 | | |
1800 | | \sa QRhiCommandBuffer::setVertexInput() |
1801 | | */ |
1802 | | |
1803 | | /*! |
1804 | | \enum QRhiVertexInputAttribute::Format |
1805 | | Specifies the type of the element data. |
1806 | | |
1807 | | \value Float4 Four component float vector |
1808 | | \value Float3 Three component float vector |
1809 | | \value Float2 Two component float vector |
1810 | | \value Float Float |
1811 | | \value UNormByte4 Four component normalized unsigned byte vector |
1812 | | \value UNormByte2 Two component normalized unsigned byte vector |
1813 | | \value UNormByte Normalized unsigned byte |
1814 | | \value UInt4 Four component unsigned integer vector |
1815 | | \value UInt3 Three component unsigned integer vector |
1816 | | \value UInt2 Two component unsigned integer vector |
1817 | | \value UInt Unsigned integer |
1818 | | \value SInt4 Four component signed integer vector |
1819 | | \value SInt3 Three component signed integer vector |
1820 | | \value SInt2 Two component signed integer vector |
1821 | | \value SInt Signed integer |
1822 | | \value Half4 Four component half precision (16 bit) float vector |
1823 | | \value Half3 Three component half precision (16 bit) float vector |
1824 | | \value Half2 Two component half precision (16 bit) float vector |
1825 | | \value Half Half precision (16 bit) float |
1826 | | \value UShort4 Four component unsigned short (16 bit) integer vector |
1827 | | \value UShort3 Three component unsigned short (16 bit) integer vector |
1828 | | \value UShort2 Two component unsigned short (16 bit) integer vector |
1829 | | \value UShort Unsigned short (16 bit) integer |
1830 | | \value SShort4 Four component signed short (16 bit) integer vector |
1831 | | \value SShort3 Three component signed short (16 bit) integer vector |
1832 | | \value SShort2 Two component signed short (16 bit) integer vector |
1833 | | \value SShort Signed short (16 bit) integer |
1834 | | |
1835 | | \note Support for half precision floating point attributes is indicated at |
1836 | | run time by the QRhi::Feature::HalfAttributes feature flag. |
1837 | | |
1838 | | \note Direct3D 11/12 supports 16 bit input attributes, but does not support |
1839 | | the Half3, UShort3 or SShort3 types. The D3D backends pass through Half3 as |
1840 | | Half4, UShort3 as UShort4, and SShort3 as SShort4. To ensure cross platform |
1841 | | compatibility, 16 bit inputs should be padded to 8 bytes. |
1842 | | */ |
1843 | | |
1844 | | /*! |
1845 | | \fn QRhiVertexInputAttribute::QRhiVertexInputAttribute() = default |
1846 | | |
1847 | | Constructs a default vertex input attribute description. |
1848 | | */ |
1849 | | |
1850 | | /*! |
1851 | | Constructs a vertex input attribute description with the specified \a |
1852 | | binding number, \a location, \a format, and \a offset. |
1853 | | |
1854 | | \a matrixSlice should be -1 except when this attribute corresponds to a row |
1855 | | or column of a matrix (for example, a 4x4 matrix becomes 4 vec4s, consuming |
1856 | | 4 consecutive vertex input locations), in which case it is the index of the |
1857 | | row or column. \c{location - matrixSlice} must always be equal to the \c |
1858 | | location for the first row or column of the unrolled matrix. |
1859 | | */ |
1860 | | QRhiVertexInputAttribute::QRhiVertexInputAttribute(int binding, int location, Format format, quint32 offset, int matrixSlice) |
1861 | 0 | : m_binding(binding), |
1862 | 0 | m_location(location), |
1863 | 0 | m_format(format), |
1864 | 0 | m_offset(offset), |
1865 | 0 | m_matrixSlice(matrixSlice) |
1866 | 0 | { |
1867 | 0 | } |
1868 | | |
1869 | | /*! |
1870 | | \fn int QRhiVertexInputAttribute::binding() const |
1871 | | \return the binding point index. |
1872 | | */ |
1873 | | |
1874 | | /*! |
1875 | | \fn void QRhiVertexInputAttribute::setBinding(int b) |
1876 | | Sets the binding point index to \a b. |
1877 | | By default this is set to 0. |
1878 | | */ |
1879 | | |
1880 | | /*! |
1881 | | \fn int QRhiVertexInputAttribute::location() const |
1882 | | \return the location of the vertex input element. |
1883 | | */ |
1884 | | |
1885 | | /*! |
1886 | | \fn void QRhiVertexInputAttribute::setLocation(int loc) |
1887 | | Sets the location of the vertex input element to \a loc. |
1888 | | By default this is set to 0. |
1889 | | */ |
1890 | | |
1891 | | /*! |
1892 | | \fn QRhiVertexInputAttribute::Format QRhiVertexInputAttribute::format() const |
1893 | | \return the format of the vertex input element. |
1894 | | */ |
1895 | | |
1896 | | /*! |
1897 | | \fn void QRhiVertexInputAttribute::setFormat(Format f) |
1898 | | Sets the format of the vertex input element to \a f. |
1899 | | By default this is set to Float4. |
1900 | | */ |
1901 | | |
1902 | | /*! |
1903 | | \fn quint32 QRhiVertexInputAttribute::offset() const |
1904 | | \return the byte offset for the input element. |
1905 | | */ |
1906 | | |
1907 | | /*! |
1908 | | \fn void QRhiVertexInputAttribute::setOffset(quint32 ofs) |
1909 | | Sets the byte offset for the input element to \a ofs. |
1910 | | */ |
1911 | | |
1912 | | /*! |
1913 | | \fn int QRhiVertexInputAttribute::matrixSlice() const |
1914 | | |
1915 | | \return the matrix slice if the input element corresponds to a row or |
1916 | | column of a matrix, or -1 if not relevant. |
1917 | | */ |
1918 | | |
1919 | | /*! |
1920 | | \fn void QRhiVertexInputAttribute::setMatrixSlice(int slice) |
1921 | | |
1922 | | Sets the matrix \a slice. By default this is set to -1, and should be set |
1923 | | to a >= 0 value only when this attribute corresponds to a row or column of |
1924 | | a matrix (for example, a 4x4 matrix becomes 4 vec4s, consuming 4 |
1925 | | consecutive vertex input locations), in which case it is the index of the |
1926 | | row or column. \c{location - matrixSlice} must always be equal to the \c |
1927 | | location for the first row or column of the unrolled matrix. |
1928 | | */ |
1929 | | |
1930 | | /*! |
1931 | | \fn bool QRhiVertexInputAttribute::operator==(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept |
1932 | | |
1933 | | \return \c true if the values in the two QRhiVertexInputAttribute objects |
1934 | | \a a and \a b are equal. |
1935 | | */ |
1936 | | |
1937 | | /*! |
1938 | | \fn bool QRhiVertexInputAttribute::operator!=(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept |
1939 | | |
1940 | | \return \c false if the values in the two QRhiVertexInputAttribute |
1941 | | objects \a a and \a b are equal; otherwise returns \c true. |
1942 | | */ |
1943 | | |
1944 | | /*! |
1945 | | \fn size_t QRhiVertexInputAttribute::qHash(const QRhiVertexInputAttribute &key, size_t seed) |
1946 | | \qhash{QRhiVertexInputAttribute} |
1947 | | */ |
1948 | | |
1949 | | #ifndef QT_NO_DEBUG_STREAM |
1950 | | QDebug operator<<(QDebug dbg, const QRhiVertexInputAttribute &a) |
1951 | 0 | { |
1952 | 0 | QDebugStateSaver saver(dbg); |
1953 | 0 | dbg.nospace() << "QRhiVertexInputAttribute(binding=" << a.binding() |
1954 | 0 | << " location=" << a.location() |
1955 | 0 | << " format=" << a.format() |
1956 | 0 | << " offset=" << a.offset() |
1957 | 0 | << ')'; |
1958 | 0 | return dbg; |
1959 | 0 | } |
1960 | | #endif |
1961 | | |
1962 | | QRhiVertexInputAttribute::Format QRhiImplementation::shaderDescVariableFormatToVertexInputFormat(QShaderDescription::VariableType type) const |
1963 | 0 | { |
1964 | 0 | switch (type) { |
1965 | 0 | case QShaderDescription::Vec4: |
1966 | 0 | return QRhiVertexInputAttribute::Float4; |
1967 | 0 | case QShaderDescription::Vec3: |
1968 | 0 | return QRhiVertexInputAttribute::Float3; |
1969 | 0 | case QShaderDescription::Vec2: |
1970 | 0 | return QRhiVertexInputAttribute::Float2; |
1971 | 0 | case QShaderDescription::Float: |
1972 | 0 | return QRhiVertexInputAttribute::Float; |
1973 | | |
1974 | 0 | case QShaderDescription::Int4: |
1975 | 0 | return QRhiVertexInputAttribute::SInt4; |
1976 | 0 | case QShaderDescription::Int3: |
1977 | 0 | return QRhiVertexInputAttribute::SInt3; |
1978 | 0 | case QShaderDescription::Int2: |
1979 | 0 | return QRhiVertexInputAttribute::SInt2; |
1980 | 0 | case QShaderDescription::Int: |
1981 | 0 | return QRhiVertexInputAttribute::SInt; |
1982 | | |
1983 | 0 | case QShaderDescription::Uint4: |
1984 | 0 | return QRhiVertexInputAttribute::UInt4; |
1985 | 0 | case QShaderDescription::Uint3: |
1986 | 0 | return QRhiVertexInputAttribute::UInt3; |
1987 | 0 | case QShaderDescription::Uint2: |
1988 | 0 | return QRhiVertexInputAttribute::UInt2; |
1989 | 0 | case QShaderDescription::Uint: |
1990 | 0 | return QRhiVertexInputAttribute::UInt; |
1991 | | |
1992 | 0 | case QShaderDescription::Half4: |
1993 | 0 | return QRhiVertexInputAttribute::Half4; |
1994 | 0 | case QShaderDescription::Half3: |
1995 | 0 | return QRhiVertexInputAttribute::Half3; |
1996 | 0 | case QShaderDescription::Half2: |
1997 | 0 | return QRhiVertexInputAttribute::Half2; |
1998 | 0 | case QShaderDescription::Half: |
1999 | 0 | return QRhiVertexInputAttribute::Half; |
2000 | | |
2001 | 0 | default: |
2002 | 0 | Q_UNREACHABLE_RETURN(QRhiVertexInputAttribute::Float); |
2003 | 0 | } |
2004 | 0 | } |
2005 | | |
2006 | | quint32 QRhiImplementation::byteSizePerVertexForVertexInputFormat(QRhiVertexInputAttribute::Format format) const |
2007 | 0 | { |
2008 | 0 | switch (format) { |
2009 | 0 | case QRhiVertexInputAttribute::Float4: |
2010 | 0 | return 4 * sizeof(float); |
2011 | 0 | case QRhiVertexInputAttribute::Float3: |
2012 | 0 | return 4 * sizeof(float); // vec3 still takes 16 bytes |
2013 | 0 | case QRhiVertexInputAttribute::Float2: |
2014 | 0 | return 2 * sizeof(float); |
2015 | 0 | case QRhiVertexInputAttribute::Float: |
2016 | 0 | return sizeof(float); |
2017 | | |
2018 | 0 | case QRhiVertexInputAttribute::UNormByte4: |
2019 | 0 | return 4 * sizeof(quint8); |
2020 | 0 | case QRhiVertexInputAttribute::UNormByte2: |
2021 | 0 | return 2 * sizeof(quint8); |
2022 | 0 | case QRhiVertexInputAttribute::UNormByte: |
2023 | 0 | return sizeof(quint8); |
2024 | | |
2025 | 0 | case QRhiVertexInputAttribute::UInt4: |
2026 | 0 | return 4 * sizeof(quint32); |
2027 | 0 | case QRhiVertexInputAttribute::UInt3: |
2028 | 0 | return 4 * sizeof(quint32); // ivec3 still takes 16 bytes |
2029 | 0 | case QRhiVertexInputAttribute::UInt2: |
2030 | 0 | return 2 * sizeof(quint32); |
2031 | 0 | case QRhiVertexInputAttribute::UInt: |
2032 | 0 | return sizeof(quint32); |
2033 | | |
2034 | 0 | case QRhiVertexInputAttribute::SInt4: |
2035 | 0 | return 4 * sizeof(qint32); |
2036 | 0 | case QRhiVertexInputAttribute::SInt3: |
2037 | 0 | return 4 * sizeof(qint32); // uvec3 still takes 16 bytes |
2038 | 0 | case QRhiVertexInputAttribute::SInt2: |
2039 | 0 | return 2 * sizeof(qint32); |
2040 | 0 | case QRhiVertexInputAttribute::SInt: |
2041 | 0 | return sizeof(qint32); |
2042 | | |
2043 | 0 | case QRhiVertexInputAttribute::Half4: |
2044 | 0 | return 4 * sizeof(qfloat16); |
2045 | 0 | case QRhiVertexInputAttribute::Half3: |
2046 | 0 | return 4 * sizeof(qfloat16); // half3 still takes 8 bytes |
2047 | 0 | case QRhiVertexInputAttribute::Half2: |
2048 | 0 | return 2 * sizeof(qfloat16); |
2049 | 0 | case QRhiVertexInputAttribute::Half: |
2050 | 0 | return sizeof(qfloat16); |
2051 | | |
2052 | 0 | case QRhiVertexInputAttribute::UShort4: |
2053 | 0 | return 4 * sizeof(quint16); |
2054 | 0 | case QRhiVertexInputAttribute::UShort3: |
2055 | 0 | return 4 * sizeof(quint16); // ivec3 still takes 8 bytes |
2056 | 0 | case QRhiVertexInputAttribute::UShort2: |
2057 | 0 | return 2 * sizeof(quint16); |
2058 | 0 | case QRhiVertexInputAttribute::UShort: |
2059 | 0 | return sizeof(quint16); |
2060 | | |
2061 | 0 | case QRhiVertexInputAttribute::SShort4: |
2062 | 0 | return 4 * sizeof(qint16); |
2063 | 0 | case QRhiVertexInputAttribute::SShort3: |
2064 | 0 | return 4 * sizeof(qint16); // uvec3 still takes 8 bytes |
2065 | 0 | case QRhiVertexInputAttribute::SShort2: |
2066 | 0 | return 2 * sizeof(qint16); |
2067 | 0 | case QRhiVertexInputAttribute::SShort: |
2068 | 0 | return sizeof(qint16); |
2069 | | |
2070 | 0 | default: |
2071 | 0 | Q_UNREACHABLE_RETURN(1); |
2072 | 0 | } |
2073 | 0 | } |
2074 | | |
2075 | | /*! |
2076 | | \class QRhiVertexInputLayout |
2077 | | \inmodule QtGuiPrivate |
2078 | | \inheaderfile rhi/qrhi.h |
2079 | | \since 6.6 |
2080 | | \brief Describes the layout of vertex inputs consumed by a vertex shader. |
2081 | | |
2082 | | The vertex input layout is defined by the collections of |
2083 | | QRhiVertexInputBinding and QRhiVertexInputAttribute. |
2084 | | |
2085 | | As an example, let's assume that we have a single buffer with 3 component |
2086 | | vertex positions and 2 component UV coordinates interleaved (\c x, \c y, \c |
2087 | | z, \c u, \c v), that the position and UV are expected at input locations 0 |
2088 | | and 1 by the vertex shader, and that the vertex buffer will be bound at |
2089 | | binding point 0 using |
2090 | | \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()} later on: |
2091 | | |
2092 | | \code |
2093 | | QRhiVertexInputLayout inputLayout; |
2094 | | inputLayout.setBindings({ |
2095 | | { 5 * sizeof(float) } |
2096 | | }); |
2097 | | inputLayout.setAttributes({ |
2098 | | { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, |
2099 | | { 0, 1, QRhiVertexInputAttribute::Float2, 3 * sizeof(float) } |
2100 | | }); |
2101 | | \endcode |
2102 | | |
2103 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2104 | | for details. |
2105 | | */ |
2106 | | |
2107 | | /*! |
2108 | | \fn QRhiVertexInputLayout::QRhiVertexInputLayout() = default |
2109 | | |
2110 | | Constructs an empty vertex input layout description. |
2111 | | */ |
2112 | | |
2113 | | /*! |
2114 | | \fn void QRhiVertexInputLayout::setBindings(std::initializer_list<QRhiVertexInputBinding> list) |
2115 | | Sets the bindings from the specified \a list. |
2116 | | */ |
2117 | | |
2118 | | /*! |
2119 | | \fn template<typename InputIterator> void QRhiVertexInputLayout::setBindings(InputIterator first, InputIterator last) |
2120 | | Sets the bindings using the iterators \a first and \a last. |
2121 | | */ |
2122 | | |
2123 | | /*! |
2124 | | \fn const QRhiVertexInputBinding *QRhiVertexInputLayout::cbeginBindings() const |
2125 | | \return a const iterator pointing to the first item in the binding list. |
2126 | | */ |
2127 | | |
2128 | | /*! |
2129 | | \fn const QRhiVertexInputBinding *QRhiVertexInputLayout::cendBindings() const |
2130 | | \return a const iterator pointing just after the last item in the binding list. |
2131 | | */ |
2132 | | |
2133 | | /*! |
2134 | | \fn const QRhiVertexInputBinding *QRhiVertexInputLayout::bindingAt(qsizetype index) const |
2135 | | \return the binding at the given \a index. |
2136 | | */ |
2137 | | |
2138 | | /*! |
2139 | | \fn qsizetype QRhiVertexInputLayout::bindingCount() const |
2140 | | \return the number of bindings. |
2141 | | */ |
2142 | | |
2143 | | /*! |
2144 | | \fn void QRhiVertexInputLayout::setAttributes(std::initializer_list<QRhiVertexInputAttribute> list) |
2145 | | Sets the attributes from the specified \a list. |
2146 | | */ |
2147 | | |
2148 | | /*! |
2149 | | \fn template<typename InputIterator> void QRhiVertexInputLayout::setAttributes(InputIterator first, InputIterator last) |
2150 | | Sets the attributes using the iterators \a first and \a last. |
2151 | | */ |
2152 | | |
2153 | | /*! |
2154 | | \fn const QRhiVertexInputAttribute *QRhiVertexInputLayout::cbeginAttributes() const |
2155 | | \return a const iterator pointing to the first item in the attribute list. |
2156 | | */ |
2157 | | |
2158 | | /*! |
2159 | | \fn const QRhiVertexInputAttribute *QRhiVertexInputLayout::cendAttributes() const |
2160 | | \return a const iterator pointing just after the last item in the attribute list. |
2161 | | */ |
2162 | | |
2163 | | /*! |
2164 | | \fn const QRhiVertexInputAttribute *QRhiVertexInputLayout::attributeAt(qsizetype index) const |
2165 | | \return the attribute at the given \a index. |
2166 | | */ |
2167 | | |
2168 | | /*! |
2169 | | \fn qsizetype QRhiVertexInputLayout::attributeCount() const |
2170 | | \return the number of attributes. |
2171 | | */ |
2172 | | |
2173 | | /*! |
2174 | | \fn bool QRhiVertexInputLayout::operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept |
2175 | | |
2176 | | \return \c true if the values in the two QRhiVertexInputLayout objects |
2177 | | \a a and \a b are equal. |
2178 | | */ |
2179 | | |
2180 | | /*! |
2181 | | \fn bool QRhiVertexInputLayout::operator!=(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept |
2182 | | |
2183 | | \return \c false if the values in the two QRhiVertexInputLayout |
2184 | | objects \a a and \a b are equal; otherwise returns \c true. |
2185 | | */ |
2186 | | |
2187 | | /*! |
2188 | | \fn size_t QRhiVertexInputLayout::qHash(const QRhiVertexInputLayout &key, size_t seed) |
2189 | | \qhash{QRhiVertexInputLayout} |
2190 | | */ |
2191 | | |
2192 | | #ifndef QT_NO_DEBUG_STREAM |
2193 | | QDebug operator<<(QDebug dbg, const QRhiVertexInputLayout &v) |
2194 | 0 | { |
2195 | 0 | QDebugStateSaver saver(dbg); |
2196 | 0 | dbg.nospace() << "QRhiVertexInputLayout(bindings=" << v.m_bindings |
2197 | 0 | << " attributes=" << v.m_attributes |
2198 | 0 | << ')'; |
2199 | 0 | return dbg; |
2200 | 0 | } |
2201 | | #endif |
2202 | | |
2203 | | /*! |
2204 | | \class QRhiShaderStage |
2205 | | \inmodule QtGuiPrivate |
2206 | | \inheaderfile rhi/qrhi.h |
2207 | | \since 6.6 |
2208 | | \brief Specifies the type and the shader code for a shader stage in the pipeline. |
2209 | | |
2210 | | When setting up a QRhiGraphicsPipeline, a collection of shader stages are |
2211 | | specified. The QRhiShaderStage contains a QShader and some associated |
2212 | | metadata, such as the graphics pipeline stage, and the |
2213 | | \l{QShader::Variant}{shader variant} to select. There is no need to specify |
2214 | | the shader language or version because the QRhi backend in use at runtime |
2215 | | will take care of choosing the appropriate shader version from the |
2216 | | collection within the QShader. |
2217 | | |
2218 | | The typical usage is in combination with |
2219 | | QRhiGraphicsPipeline::setShaderStages(), shown here with a simple approach |
2220 | | to load the QShader from \c{.qsb} files generated offline or at build time: |
2221 | | |
2222 | | \code |
2223 | | QShader getShader(const QString &name) |
2224 | | { |
2225 | | QFile f(name); |
2226 | | return f.open(QIODevice::ReadOnly) ? QShader::fromSerialized(f.readAll()) : QShader(); |
2227 | | } |
2228 | | |
2229 | | QShader vs = getShader("material.vert.qsb"); |
2230 | | QShader fs = getShader("material.frag.qsb"); |
2231 | | pipeline->setShaderStages({ |
2232 | | { QRhiShaderStage::Vertex, vs }, |
2233 | | { QRhiShaderStage::Fragment, fs } |
2234 | | }); |
2235 | | \endcode |
2236 | | |
2237 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2238 | | for details. |
2239 | | */ |
2240 | | |
2241 | | /*! |
2242 | | \enum QRhiShaderStage::Type |
2243 | | Specifies the type of the shader stage. |
2244 | | |
2245 | | \value Vertex Vertex stage |
2246 | | |
2247 | | \value TessellationControl Tessellation control (hull shader) stage. Must |
2248 | | be used only when the QRhi::Tessellation feature is supported. |
2249 | | |
2250 | | \value TessellationEvaluation Tessellation evaluation (domain shader) |
2251 | | stage. Must be used only when the QRhi::Tessellation feature is supported. |
2252 | | |
2253 | | \value Fragment Fragment (pixel shader) stage |
2254 | | |
2255 | | \value Compute Compute stage. Must be used only when the QRhi::Compute |
2256 | | feature is supported. |
2257 | | |
2258 | | \value Geometry Geometry stage. Must be used only when the |
2259 | | QRhi::GeometryShader feature is supported. |
2260 | | */ |
2261 | | |
2262 | | /*! |
2263 | | \fn QRhiShaderStage::QRhiShaderStage() = default |
2264 | | |
2265 | | Constructs a shader stage description for the vertex stage with an empty |
2266 | | QShader. |
2267 | | */ |
2268 | | |
2269 | | /*! |
2270 | | \fn QRhiShaderStage::Type QRhiShaderStage::type() const |
2271 | | \return the type of the stage. |
2272 | | */ |
2273 | | |
2274 | | /*! |
2275 | | \fn void QRhiShaderStage::setType(Type t) |
2276 | | |
2277 | | Sets the type of the stage to \a t. Setters should rarely be needed in |
2278 | | pratice. Most applications will likely use the QRhiShaderStage constructor |
2279 | | in most cases. |
2280 | | */ |
2281 | | |
2282 | | /*! |
2283 | | \fn QShader QRhiShaderStage::shader() const |
2284 | | \return the QShader to be used for this stage in the graphics pipeline. |
2285 | | */ |
2286 | | |
2287 | | /*! |
2288 | | \fn void QRhiShaderStage::setShader(const QShader &s) |
2289 | | Sets the shader collection \a s. |
2290 | | */ |
2291 | | |
2292 | | /*! |
2293 | | \fn QShader::Variant QRhiShaderStage::shaderVariant() const |
2294 | | \return the requested shader variant. |
2295 | | */ |
2296 | | |
2297 | | /*! |
2298 | | \fn void QRhiShaderStage::setShaderVariant(QShader::Variant v) |
2299 | | Sets the requested shader variant \a v. |
2300 | | */ |
2301 | | |
2302 | | /*! |
2303 | | Constructs a shader stage description with the \a type of the stage and the |
2304 | | \a shader. |
2305 | | |
2306 | | The shader variant \a v defaults to QShader::StandardShader. A |
2307 | | QShader contains multiple source and binary versions of a shader. |
2308 | | In addition, it can also contain variants of the shader with slightly |
2309 | | modified code. \a v can then be used to select the desired variant. |
2310 | | */ |
2311 | | QRhiShaderStage::QRhiShaderStage(Type type, const QShader &shader, QShader::Variant v) |
2312 | 0 | : m_type(type), |
2313 | 0 | m_shader(shader), |
2314 | 0 | m_shaderVariant(v) |
2315 | 0 | { |
2316 | 0 | } |
2317 | | |
2318 | | /*! |
2319 | | \fn bool QRhiShaderStage::operator==(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept |
2320 | | |
2321 | | \return \c true if the values in the two QRhiShaderStage objects |
2322 | | \a a and \a b are equal. |
2323 | | */ |
2324 | | |
2325 | | /*! |
2326 | | \fn bool QRhiShaderStage::operator!=(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept |
2327 | | |
2328 | | \return \c false if the values in the two QRhiShaderStage |
2329 | | objects \a a and \a b are equal; otherwise returns \c true. |
2330 | | */ |
2331 | | |
2332 | | /*! |
2333 | | \fn size_t QRhiShaderStage::qHash(const QRhiShaderStage &key, size_t seed) |
2334 | | \qhash{QRhiShaderStage} |
2335 | | */ |
2336 | | |
2337 | | #ifndef QT_NO_DEBUG_STREAM |
2338 | | QDebug operator<<(QDebug dbg, const QRhiShaderStage &s) |
2339 | 0 | { |
2340 | 0 | QDebugStateSaver saver(dbg); |
2341 | 0 | dbg.nospace() << "QRhiShaderStage(type=" << s.type() |
2342 | 0 | << " shader=" << s.shader() |
2343 | 0 | << " variant=" << s.shaderVariant() |
2344 | 0 | << ')'; |
2345 | 0 | return dbg; |
2346 | 0 | } |
2347 | | #endif |
2348 | | |
2349 | | /*! |
2350 | | \class QRhiColorAttachment |
2351 | | \inmodule QtGuiPrivate |
2352 | | \inheaderfile rhi/qrhi.h |
2353 | | \since 6.6 |
2354 | | \brief Describes the a single color attachment of a render target. |
2355 | | |
2356 | | A color attachment is either a QRhiTexture or a QRhiRenderBuffer. The |
2357 | | former, i.e. when texture() is set, is used in most cases. |
2358 | | QRhiColorAttachment is commonly used in combination with |
2359 | | QRhiTextureRenderTargetDescription. |
2360 | | |
2361 | | \note texture() and renderBuffer() cannot be both set (be non-null at the |
2362 | | same time). |
2363 | | |
2364 | | Setting renderBuffer instead is recommended only when multisampling is |
2365 | | needed. Relying on QRhi::MultisampleRenderBuffer is a better choice than |
2366 | | QRhi::MultisampleTexture in practice since the former is available in more |
2367 | | run time configurations (e.g. when running on OpenGL ES 3.0 which has no |
2368 | | support for multisample textures, but does support multisample |
2369 | | renderbuffers). |
2370 | | |
2371 | | When targeting a non-multisample texture, the layer() and level() indicate |
2372 | | the targeted layer (face index \c{0-5} for cubemaps) and mip level. For 3D |
2373 | | textures layer() specifies the slice (one 2D image within the 3D texture) |
2374 | | to render to. For texture arrays layer() is the array index. |
2375 | | |
2376 | | When texture() or renderBuffer() is multisample, resolveTexture() can be |
2377 | | set optionally. When set, samples are resolved automatically into that |
2378 | | (non-multisample) texture at the end of the render pass. When rendering |
2379 | | into a multisample renderbuffers, this is the only way to get resolved, |
2380 | | non-multisample content out of them. Multisample textures allow sampling in |
2381 | | shaders so for them this is just one option. |
2382 | | |
2383 | | \note when resolving is enabled, the multisample data may not be written |
2384 | | out at all. This means that the multisample texture() must not be used |
2385 | | afterwards with shaders for sampling when resolveTexture() is set. |
2386 | | |
2387 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2388 | | for details. |
2389 | | |
2390 | | \sa QRhiTextureRenderTargetDescription |
2391 | | */ |
2392 | | |
2393 | | /*! |
2394 | | \fn QRhiColorAttachment::QRhiColorAttachment() = default |
2395 | | |
2396 | | Constructs an empty color attachment description. |
2397 | | */ |
2398 | | |
2399 | | /*! |
2400 | | Constructs a color attachment description that specifies \a texture as the |
2401 | | associated color buffer. |
2402 | | */ |
2403 | | QRhiColorAttachment::QRhiColorAttachment(QRhiTexture *texture) |
2404 | 0 | : m_texture(texture) |
2405 | 0 | { |
2406 | 0 | } |
2407 | | |
2408 | | /*! |
2409 | | Constructs a color attachment description that specifies \a renderBuffer as |
2410 | | the associated color buffer. |
2411 | | */ |
2412 | | QRhiColorAttachment::QRhiColorAttachment(QRhiRenderBuffer *renderBuffer) |
2413 | 0 | : m_renderBuffer(renderBuffer) |
2414 | 0 | { |
2415 | 0 | } |
2416 | | |
2417 | | /*! |
2418 | | \fn QRhiTexture *QRhiColorAttachment::texture() const |
2419 | | |
2420 | | \return the texture this attachment description references, or \nullptr if |
2421 | | there is none. |
2422 | | */ |
2423 | | |
2424 | | /*! |
2425 | | \fn void QRhiColorAttachment::setTexture(QRhiTexture *tex) |
2426 | | |
2427 | | Sets the texture \a tex. |
2428 | | |
2429 | | \note texture() and renderBuffer() cannot be both set (be non-null at the |
2430 | | same time). |
2431 | | */ |
2432 | | |
2433 | | /*! |
2434 | | \fn QRhiRenderBuffer *QRhiColorAttachment::renderBuffer() const |
2435 | | |
2436 | | \return the renderbuffer this attachment description references, or |
2437 | | \nullptr if there is none. |
2438 | | |
2439 | | In practice associating a QRhiRenderBuffer with a QRhiColorAttachment makes |
2440 | | the most sense when setting up multisample rendering via a multisample |
2441 | | \l{QRhiRenderBuffer::Type}{color} renderbuffer that is then resolved into a |
2442 | | non-multisample texture at the end of the render pass. |
2443 | | */ |
2444 | | |
2445 | | /*! |
2446 | | \fn void QRhiColorAttachment::setRenderBuffer(QRhiRenderBuffer *rb) |
2447 | | |
2448 | | Sets the renderbuffer \a rb. |
2449 | | |
2450 | | \note texture() and renderBuffer() cannot be both set (be non-null at the |
2451 | | same time). |
2452 | | */ |
2453 | | |
2454 | | /*! |
2455 | | \fn int QRhiColorAttachment::layer() const |
2456 | | \return the layer index (cubemap face or array layer). 0 by default. |
2457 | | */ |
2458 | | |
2459 | | /*! |
2460 | | \fn void QRhiColorAttachment::setLayer(int layer) |
2461 | | Sets the \a layer index. |
2462 | | */ |
2463 | | |
2464 | | /*! |
2465 | | \fn int QRhiColorAttachment::level() const |
2466 | | \return the mip level. 0 by default. |
2467 | | */ |
2468 | | |
2469 | | /*! |
2470 | | \fn void QRhiColorAttachment::setLevel(int level) |
2471 | | Sets the mip \a level. |
2472 | | */ |
2473 | | |
2474 | | /*! |
2475 | | \fn QRhiTexture *QRhiColorAttachment::resolveTexture() const |
2476 | | |
2477 | | \return the resolve texture this attachment description references, or |
2478 | | \nullptr if there is none. |
2479 | | |
2480 | | Setting a non-null resolve texture is applicable when the attachment |
2481 | | references a multisample texture or renderbuffer. The QRhiTexture in the |
2482 | | resolveTexture() is then a non-multisample 2D texture (or texture array) |
2483 | | with the same size (but a sample count of 1). The multisample content is |
2484 | | automatically resolved into this texture at the end of each render pass. |
2485 | | */ |
2486 | | |
2487 | | /*! |
2488 | | \fn void QRhiColorAttachment::setResolveTexture(QRhiTexture *tex) |
2489 | | |
2490 | | Sets the resolve texture \a tex. |
2491 | | |
2492 | | \a tex is expected to be a 2D texture or a 2D texture array. In either |
2493 | | case, resolving targets a single mip level of a single layer (array |
2494 | | element) of \a tex. The mip level and array layer are specified by |
2495 | | resolveLevel() and resolveLayer(). |
2496 | | |
2497 | | An exception is \l{setMultiViewCount()}{multiview}: when the color |
2498 | | attachment is associated with a texture array and multiview is enabled, the |
2499 | | resolve texture must also be a texture array with sufficient elements for |
2500 | | all views. In this case all elements that correspond to views are resolved |
2501 | | automatically; the behavior is similar to the following pseudo-code: |
2502 | | \badcode |
2503 | | for (i = 0; i < multiViewCount(); ++i) |
2504 | | resolve texture's layer() + i into resolveTexture's resolveLayer() + i |
2505 | | \endcode |
2506 | | |
2507 | | Setting a non-multisample texture to resolve a multisample texture or |
2508 | | renderbuffer automatically at the end of the render pass is often |
2509 | | preferable to working with multisample textures (and not setting a resolve |
2510 | | texture), because it avoids the need for writing dedicated fragment shaders |
2511 | | that work exclusively with multisample textures (\c sampler2DMS, \c |
2512 | | texelFetch, etc.), and rather allows using the same shader as one would if |
2513 | | the attachment's texture was not multisampled to begin with. This comes at |
2514 | | the expense of an additional resource (the non-multisample \a tex). |
2515 | | */ |
2516 | | |
2517 | | /*! |
2518 | | \fn int QRhiColorAttachment::resolveLayer() const |
2519 | | \return the currently set resolve texture layer. Defaults to 0. |
2520 | | */ |
2521 | | |
2522 | | /*! |
2523 | | \fn void QRhiColorAttachment::setResolveLayer(int layer) |
2524 | | Sets the resolve texture \a layer to use. |
2525 | | */ |
2526 | | |
2527 | | /*! |
2528 | | \fn int QRhiColorAttachment::resolveLevel() const |
2529 | | \return the currently set resolve texture mip level. Defaults to 0. |
2530 | | */ |
2531 | | |
2532 | | /*! |
2533 | | \fn void QRhiColorAttachment::setResolveLevel(int level) |
2534 | | Sets the resolve texture mip \a level to use. |
2535 | | */ |
2536 | | |
2537 | | /*! |
2538 | | \fn int QRhiColorAttachment::multiViewCount() const |
2539 | | |
2540 | | \return the currently set number of views. Defaults to 0 which indicates |
2541 | | the render target with this color attachment is not going to be used with |
2542 | | multiview rendering. |
2543 | | |
2544 | | \since 6.7 |
2545 | | */ |
2546 | | |
2547 | | /*! |
2548 | | \fn void QRhiColorAttachment::setMultiViewCount(int count) |
2549 | | |
2550 | | Sets the view \a count. Setting a value larger than 1 indicates that the |
2551 | | render target with this color attachment is going to be used with multiview |
2552 | | rendering. The default value is 0. Values smaller than 2 indicate no |
2553 | | multiview rendering. |
2554 | | |
2555 | | When \a count is set to \c 2 or greater, the color attachment must be |
2556 | | associated with a 2D texture array. layer() and multiViewCount() together |
2557 | | define the range of texture array elements that are targeted during |
2558 | | multiview rendering. |
2559 | | |
2560 | | For example, if \c layer is \c 0 and \c multiViewCount is \c 2, the texture |
2561 | | array must have 2 (or more) elements, and the multiview rendering will |
2562 | | target elements 0 and 1. The \c{gl_ViewIndex} variable in the shaders has a |
2563 | | value of \c 0 or \c 1 then, where view \c 0 corresponds to the texture array |
2564 | | element \c 0, and view \c 1 to the array element \c 1. |
2565 | | |
2566 | | \note Setting a \a count larger than 1, using a texture array as texture(), |
2567 | | and calling \l{QRhiCommandBuffer::beginPass()}{beginPass()} on a |
2568 | | QRhiTextureRenderTarget with this color attachment implies multiview |
2569 | | rendering for the entire render pass. multiViewCount() should not be set |
2570 | | unless multiview rendering is wanted. Multiview cannot be used with texture |
2571 | | types other than 2D texture arrays. (although 3D textures may work, |
2572 | | depending on the graphics API and backend; applications are nonetheless |
2573 | | advised not to rely on that and only use 2D texture arrays as the render |
2574 | | targets of multiview rendering) |
2575 | | |
2576 | | See |
2577 | | \l{https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview.txt}{GL_OVR_multiview} |
2578 | | for more details regarding multiview rendering. Do note that Qt requires |
2579 | | \l{https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview2.txt}{GL_OVR_multiview2} |
2580 | | as well, when running on OpenGL (ES). |
2581 | | |
2582 | | Multiview rendering is available only when the |
2583 | | \l{QRhi::MultiView}{MultiView} feature is reported as supported from |
2584 | | \l{QRhi::isFeatureSupported()}{isFeatureSupported()}. |
2585 | | |
2586 | | \note For portability, be aware of limitations that exist for multiview |
2587 | | rendering with some of the graphics APIs. It is recommended that multiview |
2588 | | render passes do not rely on any of the features that |
2589 | | \l{https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview.txt}{GL_OVR_multiview} |
2590 | | declares as unsupported. The one exception is shader stage outputs other |
2591 | | than \c{gl_Position} depending on \c{gl_ViewIndex}: that can be relied on |
2592 | | (even with OpenGL) because QRhi never reports multiview as supported without |
2593 | | \c{GL_OVR_multiview2} also being present. |
2594 | | |
2595 | | \note Multiview rendering is not supported in combination with tessellation |
2596 | | or geometry shaders, even though some implementations of some graphics APIs |
2597 | | may allow this. |
2598 | | |
2599 | | \since 6.7 |
2600 | | */ |
2601 | | |
2602 | | /*! |
2603 | | \class QRhiTextureRenderTargetDescription |
2604 | | \inmodule QtGuiPrivate |
2605 | | \inheaderfile rhi/qrhi.h |
2606 | | \since 6.6 |
2607 | | \brief Describes the color and depth or depth/stencil attachments of a render target. |
2608 | | |
2609 | | A texture render target has zero or more textures as color attachments, |
2610 | | zero or one renderbuffer as combined depth/stencil buffer or zero or one |
2611 | | texture as depth buffer. |
2612 | | |
2613 | | \note depthStencilBuffer() and depthTexture() cannot be both set (cannot be |
2614 | | non-null at the same time). |
2615 | | |
2616 | | Let's look at some example usages in combination with |
2617 | | QRhiTextureRenderTarget. |
2618 | | |
2619 | | Due to the constructors, the targeting a texture (and no depth/stencil |
2620 | | buffer) is simple: |
2621 | | |
2622 | | \code |
2623 | | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(256, 256), 1, QRhiTexture::RenderTarget); |
2624 | | texture->create(); |
2625 | | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ texture })); |
2626 | | \endcode |
2627 | | |
2628 | | The following creates a texture render target that is set up to target mip |
2629 | | level #2 of a texture: |
2630 | | |
2631 | | \code |
2632 | | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget | QRhiTexture::MipMapped); |
2633 | | texture->create(); |
2634 | | QRhiColorAttachment colorAtt(texture); |
2635 | | colorAtt.setLevel(2); |
2636 | | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ colorAtt }); |
2637 | | \endcode |
2638 | | |
2639 | | Another example, this time to render into a depth texture: |
2640 | | |
2641 | | \code |
2642 | | QRhiTexture *shadowMap = rhi->newTexture(QRhiTexture::D32F, QSize(1024, 1024), 1, QRhiTexture::RenderTarget); |
2643 | | shadowMap->create(); |
2644 | | QRhiTextureRenderTargetDescription rtDesc; |
2645 | | rtDesc.setDepthTexture(shadowMap); |
2646 | | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget(rtDesc); |
2647 | | \endcode |
2648 | | |
2649 | | A very common case, having a texture as the color attachment and a |
2650 | | renderbuffer as depth/stencil to enable depth testing: |
2651 | | |
2652 | | \code |
2653 | | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget); |
2654 | | texture->create(); |
2655 | | QRhiRenderBuffer *depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, QSize(512, 512)); |
2656 | | depthStencil->create(); |
2657 | | QRhiTextureRenderTargetDescription rtDesc({ texture }, depthStencil); |
2658 | | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget(rtDesc); |
2659 | | \endcode |
2660 | | |
2661 | | Finally, to enable multisample rendering in a portable manner (so also |
2662 | | supporting OpenGL ES 3.0), using a QRhiRenderBuffer as the (multisample) |
2663 | | color buffer and then resolving into a regular (non-multisample) 2D |
2664 | | texture. To enable depth testing, a depth-stencil buffer, which also must |
2665 | | use the same sample count, is used as well: |
2666 | | |
2667 | | \code |
2668 | | QRhiRenderBuffer *colorBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::Color, QSize(512, 512), 4); // 4x MSAA |
2669 | | colorBuffer->create(); |
2670 | | QRhiRenderBuffer *depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, QSize(512, 512), 4); |
2671 | | depthStencil->create(); |
2672 | | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget); |
2673 | | texture->create(); |
2674 | | QRhiColorAttachment colorAtt(colorBuffer); |
2675 | | colorAtt.setResolveTexture(texture); |
2676 | | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ colorAtt, depthStencil }); |
2677 | | \endcode |
2678 | | |
2679 | | \note when multisample resolving is enabled, the multisample data may not be |
2680 | | written out at all. This means that the multisample texture in a color |
2681 | | attachment must not be used afterwards with shaders for sampling (or other |
2682 | | purposes) whenever a resolve texture is set, since the multisample color |
2683 | | buffer is merely an intermediate storage then that gets no data written back |
2684 | | on some GPU architectures at all. See |
2685 | | \l{QRhiTextureRenderTarget::Flag}{PreserveColorContents} for more details. |
2686 | | |
2687 | | \note When using setDepthTexture(), not setDepthStencilBuffer(), and the |
2688 | | depth (stencil) data is not of interest afterwards, set the |
2689 | | DoNotStoreDepthStencilContents flag on the QRhiTextureRenderTarget. This |
2690 | | allows indicating to the underlying 3D API that the depth/stencil data can |
2691 | | be discarded, leading potentially to better performance with tiled GPU |
2692 | | architectures. When the depth-stencil buffer is a QRhiRenderBuffer (and also |
2693 | | for the multisample color texture, see previous note) this is implicit, but |
2694 | | with a depth (stencil) QRhiTexture the intention needs to be declared |
2695 | | explicitly. By default QRhi assumes that the data is of interest (e.g., the |
2696 | | depth texture is sampled in a shader afterwards). |
2697 | | |
2698 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2699 | | for details. |
2700 | | |
2701 | | \sa QRhiColorAttachment, QRhiTextureRenderTarget |
2702 | | */ |
2703 | | |
2704 | | /*! |
2705 | | \fn QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription() = default |
2706 | | |
2707 | | Constructs an empty texture render target description. |
2708 | | */ |
2709 | | |
2710 | | /*! |
2711 | | Constructs a texture render target description with one attachment |
2712 | | described by \a colorAttachment. |
2713 | | */ |
2714 | | QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment) |
2715 | 0 | { |
2716 | 0 | m_colorAttachments.append(colorAttachment); |
2717 | 0 | } |
2718 | | |
2719 | | /*! |
2720 | | Constructs a texture render target description with two attachments, a |
2721 | | color attachment described by \a colorAttachment, and a depth/stencil |
2722 | | attachment with \a depthStencilBuffer. |
2723 | | */ |
2724 | | QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, |
2725 | | QRhiRenderBuffer *depthStencilBuffer) |
2726 | 0 | : m_depthStencilBuffer(depthStencilBuffer) |
2727 | 0 | { |
2728 | 0 | m_colorAttachments.append(colorAttachment); |
2729 | 0 | } |
2730 | | |
2731 | | /*! |
2732 | | Constructs a texture render target description with two attachments, a |
2733 | | color attachment described by \a colorAttachment, and a depth attachment |
2734 | | with \a depthTexture. |
2735 | | |
2736 | | \note \a depthTexture must have a suitable format, such as QRhiTexture::D16 |
2737 | | or QRhiTexture::D32F. |
2738 | | */ |
2739 | | QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, |
2740 | | QRhiTexture *depthTexture) |
2741 | 0 | : m_depthTexture(depthTexture) |
2742 | 0 | { |
2743 | 0 | m_colorAttachments.append(colorAttachment); |
2744 | 0 | } |
2745 | | |
2746 | | /*! |
2747 | | \fn void QRhiTextureRenderTargetDescription::setColorAttachments(std::initializer_list<QRhiColorAttachment> list) |
2748 | | Sets the \a list of color attachments. |
2749 | | */ |
2750 | | |
2751 | | /*! |
2752 | | \fn template<typename InputIterator> void QRhiTextureRenderTargetDescription::setColorAttachments(InputIterator first, InputIterator last) |
2753 | | Sets the list of color attachments via the iterators \a first and \a last. |
2754 | | */ |
2755 | | |
2756 | | /*! |
2757 | | \fn const QRhiColorAttachment *QRhiTextureRenderTargetDescription::cbeginColorAttachments() const |
2758 | | \return a const iterator pointing to the first item in the attachment list. |
2759 | | */ |
2760 | | |
2761 | | /*! |
2762 | | \fn const QRhiColorAttachment *QRhiTextureRenderTargetDescription::cendColorAttachments() const |
2763 | | \return a const iterator pointing just after the last item in the attachment list. |
2764 | | */ |
2765 | | |
2766 | | /*! |
2767 | | \fn const QRhiColorAttachment *QRhiTextureRenderTargetDescription::colorAttachmentAt(qsizetype index) const |
2768 | | \return the color attachment at the specified \a index. |
2769 | | */ |
2770 | | |
2771 | | /*! |
2772 | | \fn qsizetype QRhiTextureRenderTargetDescription::colorAttachmentCount() const |
2773 | | \return the number of currently set color attachments. |
2774 | | */ |
2775 | | |
2776 | | /*! |
2777 | | \fn QRhiRenderBuffer *QRhiTextureRenderTargetDescription::depthStencilBuffer() const |
2778 | | \return the renderbuffer used as depth-stencil buffer, or \nullptr if none was set. |
2779 | | */ |
2780 | | |
2781 | | /*! |
2782 | | \fn void QRhiTextureRenderTargetDescription::setDepthStencilBuffer(QRhiRenderBuffer *renderBuffer) |
2783 | | |
2784 | | Sets the \a renderBuffer for depth-stencil. Not mandatory, e.g. when no |
2785 | | depth test/write or stencil-related features are used within any graphics |
2786 | | pipelines in any of the render passes for this render target, it can be |
2787 | | left set to \nullptr. |
2788 | | |
2789 | | \note depthStencilBuffer() and depthTexture() cannot be both set (cannot be |
2790 | | non-null at the same time). |
2791 | | |
2792 | | Using a QRhiRenderBuffer over a 2D QRhiTexture as the depth or |
2793 | | depth/stencil buffer is very common, and is the recommended approach for |
2794 | | applications. Using a QRhiTexture, and so setDepthTexture() becomes |
2795 | | relevant if the depth data is meant to be accessed (e.g. sampled in a |
2796 | | shader) afterwards, or when |
2797 | | \l{QRhiColorAttachment::setMultiViewCount()}{multiview rendering} is |
2798 | | involved (because then the depth texture must be a texture array). |
2799 | | |
2800 | | \sa setDepthTexture() |
2801 | | */ |
2802 | | |
2803 | | /*! |
2804 | | \fn QRhiTexture *QRhiTextureRenderTargetDescription::depthTexture() const |
2805 | | \return the currently referenced depth texture, or \nullptr if none was set. |
2806 | | */ |
2807 | | |
2808 | | /*! |
2809 | | \fn void QRhiTextureRenderTargetDescription::setDepthTexture(QRhiTexture *texture) |
2810 | | |
2811 | | Sets the \a texture for depth-stencil. This is an alternative to |
2812 | | setDepthStencilBuffer(), where instead of a QRhiRenderBuffer a QRhiTexture |
2813 | | with a suitable type (e.g., QRhiTexture::D32F) is provided. |
2814 | | |
2815 | | \note depthStencilBuffer() and depthTexture() cannot be both set (cannot be |
2816 | | non-null at the same time). |
2817 | | |
2818 | | \a texture can either be a 2D texture or a 2D texture array (when texture |
2819 | | arrays are supported). Specifying a texture array is relevant in particular |
2820 | | with |
2821 | | \l{QRhiColorAttachment::setMultiViewCount()}{multiview rendering}. |
2822 | | |
2823 | | \note If \a texture is a format with a stencil component, such as |
2824 | | \l QRhiTexture::D24S8, it will serve as the stencil buffer as well. |
2825 | | |
2826 | | \sa setDepthStencilBuffer() |
2827 | | */ |
2828 | | |
2829 | | /*! |
2830 | | \fn int QRhiTextureRenderTargetDescription::depthLayer() const |
2831 | | \return the array slice index to be used for the depth/stencil attachment, |
2832 | | or -1 by default. |
2833 | | |
2834 | | \since 6.12 |
2835 | | \sa setDepthLayer(), setDepthTexture() |
2836 | | */ |
2837 | | |
2838 | | /*! |
2839 | | \fn void QRhiTextureRenderTargetDescription::setDepthLayer(int depthLayer) |
2840 | | |
2841 | | Sets the array slice index to be used for the depth/stencil attachment. |
2842 | | |
2843 | | Pass -1 (the default) to not target a particular layer. When set to a |
2844 | | non-negative value, the render target attaches a view that targets exactly |
2845 | | that layer (slice) of the depth texture. This is only effective when a 2D |
2846 | | array depth texture is provided via setDepthTexture(); otherwise the value |
2847 | | is ignored. |
2848 | | |
2849 | | The value must be within the array size of the depth texture; passing an |
2850 | | out-of-range index leads to undefined behavior. The index is absolute |
2851 | | with respect to the underlying texture, regardless of any array range |
2852 | | that may have been specified when creating the texture. |
2853 | | |
2854 | | Specifying a \a depthLayer disables layered/multiview rendering for the |
2855 | | depth attachment. |
2856 | | |
2857 | | \since 6.12 |
2858 | | \sa depthLayer(), setDepthTexture() |
2859 | | */ |
2860 | | |
2861 | | /*! |
2862 | | \fn QRhiTexture *QRhiTextureRenderTargetDescription::depthResolveTexture() const |
2863 | | |
2864 | | \return the texture to which a multisample depth (or depth-stencil) texture |
2865 | | (or texture array) is resolved to. \nullptr if there is none, which is the |
2866 | | most common case. |
2867 | | |
2868 | | \since 6.8 |
2869 | | \sa QRhiColorAttachment::resolveTexture(), depthTexture() |
2870 | | */ |
2871 | | |
2872 | | /*! |
2873 | | \fn void QRhiTextureRenderTargetDescription::setDepthResolveTexture(QRhiTexture *tex) |
2874 | | |
2875 | | Sets the depth (or depth-stencil) resolve texture \a tex. |
2876 | | |
2877 | | \a tex is expected to be a 2D texture or a 2D texture array with a format |
2878 | | matching the texture set via setDepthTexture(). |
2879 | | |
2880 | | \note Resolving depth (or depth-stencil) data is only functional when the |
2881 | | \l QRhi::ResolveDepthStencil feature is reported as supported at run time. |
2882 | | Support for depth-stencil resolve is not universally available among the |
2883 | | graphics APIs. Designs assuming unconditional availability of depth-stencil |
2884 | | resolve are therefore non-portable, and should be avoided. |
2885 | | |
2886 | | \note As an additional limitation for OpenGL ES in particular, setting a |
2887 | | depth resolve texture may only be functional in combination with |
2888 | | setDepthTexture(), not with setDepthStencilBuffer(). |
2889 | | |
2890 | | \since 6.8 |
2891 | | \sa QRhiColorAttachment::setResolveTexture(), setDepthTexture() |
2892 | | */ |
2893 | | |
2894 | | /*! |
2895 | | \fn QRhiShadingRateMap *QRhiTextureRenderTargetDescription::shadingRateMap() const |
2896 | | \return the currently set QRhiShadingRateMap. By default this is \nullptr. |
2897 | | \since 6.9 |
2898 | | */ |
2899 | | |
2900 | | /*! |
2901 | | \fn void QRhiTextureRenderTargetDescription::setShadingRateMap(QRhiShadingRateMap *map) |
2902 | | |
2903 | | Associates with the specified QRhiShadingRateMap \a map. This is functional |
2904 | | only when the \l QRhi::VariableRateShadingMap feature is reported as |
2905 | | supported. |
2906 | | |
2907 | | When QRhiCommandBuffer::setShadingRate() is also called, the higher of the |
2908 | | two shading rates is used for each tile. There is currently no control |
2909 | | offered over the combiner behavior. |
2910 | | |
2911 | | \note When the render target had already been built (create() was called |
2912 | | successfully), setting a shading rate map implies that a different, new |
2913 | | QRhiRenderPassDescriptor is needed and thus a rebuild is needed. Call |
2914 | | setRenderPassDescriptor() again (outside of a render pass) and then rebuild |
2915 | | by calling create(). This has other rolling consequences as well, for |
2916 | | example for graphics pipelines: those also need to be associated with the |
2917 | | new QRhiRenderPassDescriptor and then rebuilt. See \l |
2918 | | QRhiRenderPassDescriptor::serializedFormat() for some suggestions on how to |
2919 | | deal with this. Remember to set the QRhiGraphicsPipeline::UsesShadingRate |
2920 | | flag as well. |
2921 | | |
2922 | | \since 6.9 |
2923 | | */ |
2924 | | |
2925 | | /*! |
2926 | | \class QRhiTextureSubresourceUploadDescription |
2927 | | \inmodule QtGuiPrivate |
2928 | | \inheaderfile rhi/qrhi.h |
2929 | | \since 6.6 |
2930 | | \brief Describes the source for one mip level in a layer in a texture upload operation. |
2931 | | |
2932 | | The source content is specified either as a QImage or as a raw blob. The |
2933 | | former is only allowed for uncompressed textures with a format that can be |
2934 | | mapped to QImage, while the latter is supported for all formats, including |
2935 | | floating point and compressed. |
2936 | | |
2937 | | \note image() and data() cannot be both set at the same time. |
2938 | | |
2939 | | destinationTopLeft() specifies the top-left corner of the target |
2940 | | rectangle. Defaults to (0, 0). |
2941 | | |
2942 | | An empty sourceSize() (the default) indicates that size is assumed to be |
2943 | | the size of the subresource. With QImage-based uploads this implies that |
2944 | | the size of the source image() must match the subresource. When providing |
2945 | | raw data instead, sufficient number of bytes must be provided in data(). |
2946 | | |
2947 | | sourceTopLeft() is supported only for QImage-based uploads, and specifies |
2948 | | the top-left corner of the source rectangle. |
2949 | | |
2950 | | \note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy |
2951 | | internally, depending on the format and the backend. |
2952 | | |
2953 | | When providing raw data, and the stride is not specified via |
2954 | | setDataStride(), the stride (row pitch, row length in bytes) of the |
2955 | | provided data must be equal to \c{width * pixelSize} where \c pixelSize is |
2956 | | the number of bytes used for one pixel, and there must be no additional |
2957 | | padding between rows. There is no row start alignment requirement. |
2958 | | |
2959 | | When there is unused data at the end of each row in the input raw data, |
2960 | | call setDataStride() with the total number of bytes per row. The stride |
2961 | | must always be a multiple of the number of bytes for one pixel. The row |
2962 | | stride is only applicable to image data for textures with an uncompressed |
2963 | | format. |
2964 | | |
2965 | | \note The format of the source data must be compatible with the texture |
2966 | | format. With many graphics APIs the data is copied as-is into a staging |
2967 | | buffer, there is no intermediate format conversion provided by QRhi. This |
2968 | | applies to floating point formats as well, with, for example, RGBA16F |
2969 | | requiring half floats in the source data. |
2970 | | |
2971 | | \note Setting the stride via setDataStride() is only functional when |
2972 | | QRhi::ImageDataStride is reported as |
2973 | | \l{QRhi::isFeatureSupported()}{supported}. In practice this can be expected |
2974 | | to be supported everywhere except for OpenGL ES 2.0. |
2975 | | |
2976 | | \note When a QImage is given, the stride returned from |
2977 | | QImage::bytesPerLine() is taken into account automatically. |
2978 | | |
2979 | | \warning When a QImage is given and the QImage does not own the underlying |
2980 | | pixel data, it is up to the caller to ensure that the associated data stays |
2981 | | valid until the end of the frame. (just submitting the resource update batch |
2982 | | is not sufficient, the data must stay valid until QRhi::endFrame() is called |
2983 | | in order to be portable across all backends) If this cannot be ensured, the |
2984 | | caller is strongly encouraged to call QImage::detach() on the image before |
2985 | | passing it to uploadTexture(). |
2986 | | |
2987 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
2988 | | for details. |
2989 | | |
2990 | | \sa QRhiTextureUploadDescription |
2991 | | */ |
2992 | | |
2993 | | /*! |
2994 | | \fn QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription() = default |
2995 | | |
2996 | | Constructs an empty subresource description. |
2997 | | |
2998 | | \note an empty QRhiTextureSubresourceUploadDescription is not useful on its |
2999 | | own and should not be submitted to a QRhiTextureUploadEntry. At minimum |
3000 | | image or data must be set first. |
3001 | | */ |
3002 | | |
3003 | | /*! |
3004 | | Constructs a mip level description with a \a image. |
3005 | | |
3006 | | The \l{QImage::size()}{size} of \a image must match the size of the mip |
3007 | | level. For level 0 that is the \l{QRhiTexture::pixelSize()}{texture size}. |
3008 | | |
3009 | | The bit depth of \a image must be compatible with the |
3010 | | \l{QRhiTexture::Format}{texture format}. |
3011 | | |
3012 | | To describe a partial upload, call setSourceSize(), setSourceTopLeft(), or |
3013 | | setDestinationTopLeft() afterwards. |
3014 | | */ |
3015 | | QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription(const QImage &image) |
3016 | 0 | : m_image(image) |
3017 | 0 | { |
3018 | 0 | } |
3019 | | |
3020 | | /*! |
3021 | | Constructs a mip level description with the image data is specified by \a |
3022 | | data and \a size. This is suitable for floating point and compressed |
3023 | | formats as well. |
3024 | | |
3025 | | \a data can safely be destroyed or changed once this function returns. |
3026 | | */ |
3027 | | QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription(const void *data, quint32 size) |
3028 | 0 | : m_data(reinterpret_cast<const char *>(data), size) |
3029 | 0 | { |
3030 | 0 | } |
3031 | | |
3032 | | /*! |
3033 | | Constructs a mip level description with the image data specified by \a |
3034 | | data. This is suitable for floating point and compressed formats as well. |
3035 | | */ |
3036 | | QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription(const QByteArray &data) |
3037 | 0 | : m_data(data) |
3038 | 0 | { |
3039 | 0 | } |
3040 | | |
3041 | | /*! |
3042 | | \fn QImage QRhiTextureSubresourceUploadDescription::image() const |
3043 | | \return the currently set QImage. |
3044 | | */ |
3045 | | |
3046 | | /*! |
3047 | | \fn void QRhiTextureSubresourceUploadDescription::setImage(const QImage &image) |
3048 | | |
3049 | | Sets \a image. |
3050 | | Upon textures loading, the image data will be read as is, with no formats conversions. |
3051 | | |
3052 | | \note image() and data() cannot be both set at the same time. |
3053 | | */ |
3054 | | |
3055 | | /*! |
3056 | | \fn QByteArray QRhiTextureSubresourceUploadDescription::data() const |
3057 | | \return the currently set raw pixel data. |
3058 | | */ |
3059 | | |
3060 | | /*! |
3061 | | \fn void QRhiTextureSubresourceUploadDescription::setData(const QByteArray &data) |
3062 | | |
3063 | | Sets \a data. |
3064 | | |
3065 | | \note image() and data() cannot be both set at the same time. |
3066 | | */ |
3067 | | |
3068 | | /*! |
3069 | | \fn quint32 QRhiTextureSubresourceUploadDescription::dataStride() const |
3070 | | \return the currently set data stride. |
3071 | | */ |
3072 | | |
3073 | | /*! |
3074 | | \fn void QRhiTextureSubresourceUploadDescription::setDataStride(quint32 stride) |
3075 | | |
3076 | | Sets the data \a stride in bytes. By default this is 0 and not always |
3077 | | relevant. When providing raw data(), and the stride is not specified via |
3078 | | setDataStride(), the stride (row pitch, row length in bytes) of the |
3079 | | provided data must be equal to \c{width * pixelSize} where \c pixelSize is |
3080 | | the number of bytes used for one pixel, and there must be no additional |
3081 | | padding between rows. Otherwise, if there is additional space between the |
3082 | | lines, set a non-zero \a stride. All this is applicable only when raw image |
3083 | | data is provided, and is not necessary when working QImage since that has |
3084 | | its own \l{QImage::bytesPerLine()}{stride} value. |
3085 | | |
3086 | | \note Setting the stride via setDataStride() is only functional when |
3087 | | QRhi::ImageDataStride is reported as |
3088 | | \l{QRhi::isFeatureSupported()}{supported}. |
3089 | | |
3090 | | \note When a QImage is given, the stride returned from |
3091 | | QImage::bytesPerLine() is taken into account automatically and therefore |
3092 | | there is no need to set the data stride manually. |
3093 | | */ |
3094 | | |
3095 | | /*! |
3096 | | \fn QPoint QRhiTextureSubresourceUploadDescription::destinationTopLeft() const |
3097 | | \return the currently set destination top-left position. Defaults to (0, 0). |
3098 | | */ |
3099 | | |
3100 | | /*! |
3101 | | \fn void QRhiTextureSubresourceUploadDescription::setDestinationTopLeft(const QPoint &p) |
3102 | | Sets the destination top-left position \a p. |
3103 | | |
3104 | | \note In the most common case of sourcing the image data from a QImage, Qt |
3105 | | performs clamping of invalid texture upload sizes when the destination |
3106 | | position + the source size exceeds the size of the targeted texture |
3107 | | subresource (i.e, the size at the given mip level). There is also a |
3108 | | qWarning() message printed on the debug output in this case. This is done in |
3109 | | order to avoid confusion when the underlying 3D APIs crash and lead to GPU |
3110 | | device removals at a later point when submitting the commands. Regardless, |
3111 | | developers are encouraged to always validate applications by running with the |
3112 | | Vulkan, D3D12, or Metal validation/debug layers enabled, since those offer a |
3113 | | much wider range of checks on API usage. |
3114 | | */ |
3115 | | |
3116 | | /*! |
3117 | | \fn QSize QRhiTextureSubresourceUploadDescription::sourceSize() const |
3118 | | |
3119 | | \return the source size in pixels. Defaults to a default-constructed QSize, |
3120 | | which indicates the entire subresource. |
3121 | | */ |
3122 | | |
3123 | | /*! |
3124 | | \fn void QRhiTextureSubresourceUploadDescription::setSourceSize(const QSize &size) |
3125 | | |
3126 | | Sets the source \a size in pixels. |
3127 | | |
3128 | | \note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy |
3129 | | internally, depending on the format and the backend. |
3130 | | */ |
3131 | | |
3132 | | /*! |
3133 | | \fn QPoint QRhiTextureSubresourceUploadDescription::sourceTopLeft() const |
3134 | | \return the currently set source top-left position. Defaults to (0, 0). |
3135 | | */ |
3136 | | |
3137 | | /*! |
3138 | | \fn void QRhiTextureSubresourceUploadDescription::setSourceTopLeft(const QPoint &p) |
3139 | | |
3140 | | Sets the source top-left position \a p. |
3141 | | |
3142 | | \note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy |
3143 | | internally, depending on the format and the backend. |
3144 | | */ |
3145 | | |
3146 | | /*! |
3147 | | \class QRhiTextureUploadEntry |
3148 | | \inmodule QtGuiPrivate |
3149 | | \inheaderfile rhi/qrhi.h |
3150 | | \since 6.6 |
3151 | | |
3152 | | \brief Describes one layer (face for cubemaps, slice for 3D textures, |
3153 | | element for texture arrays) in a texture upload operation. |
3154 | | |
3155 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3156 | | for details. |
3157 | | */ |
3158 | | |
3159 | | /*! |
3160 | | \fn QRhiTextureUploadEntry::QRhiTextureUploadEntry() |
3161 | | |
3162 | | Constructs an empty QRhiTextureUploadEntry targeting layer 0 and level 0. |
3163 | | |
3164 | | \note an empty QRhiTextureUploadEntry should not be submitted without |
3165 | | setting a QRhiTextureSubresourceUploadDescription via setDescription() |
3166 | | first. |
3167 | | */ |
3168 | | |
3169 | | /*! |
3170 | | Constructs a QRhiTextureUploadEntry targeting the given \a layer and mip |
3171 | | \a level, with the subresource contents described by \a desc. |
3172 | | */ |
3173 | | QRhiTextureUploadEntry::QRhiTextureUploadEntry(int layer, int level, |
3174 | | const QRhiTextureSubresourceUploadDescription &desc) |
3175 | 0 | : m_layer(layer), |
3176 | 0 | m_level(level), |
3177 | 0 | m_desc(desc) |
3178 | 0 | { |
3179 | 0 | } |
3180 | | |
3181 | | /*! |
3182 | | \fn int QRhiTextureUploadEntry::layer() const |
3183 | | \return the currently set layer index (cubemap face, array layer). Defaults to 0. |
3184 | | */ |
3185 | | |
3186 | | /*! |
3187 | | \fn void QRhiTextureUploadEntry::setLayer(int layer) |
3188 | | Sets the \a layer. |
3189 | | */ |
3190 | | |
3191 | | /*! |
3192 | | \fn int QRhiTextureUploadEntry::level() const |
3193 | | \return the currently set mip level. Defaults to 0. |
3194 | | */ |
3195 | | |
3196 | | /*! |
3197 | | \fn void QRhiTextureUploadEntry::setLevel(int level) |
3198 | | Sets the mip \a level. |
3199 | | */ |
3200 | | |
3201 | | /*! |
3202 | | \fn QRhiTextureSubresourceUploadDescription QRhiTextureUploadEntry::description() const |
3203 | | \return the currently set subresource description. |
3204 | | */ |
3205 | | |
3206 | | /*! |
3207 | | \fn void QRhiTextureUploadEntry::setDescription(const QRhiTextureSubresourceUploadDescription &desc) |
3208 | | Sets the subresource description \a desc. |
3209 | | */ |
3210 | | |
3211 | | /*! |
3212 | | \class QRhiTextureUploadDescription |
3213 | | \inmodule QtGuiPrivate |
3214 | | \inheaderfile rhi/qrhi.h |
3215 | | \since 6.6 |
3216 | | \brief Describes a texture upload operation. |
3217 | | |
3218 | | Used with QRhiResourceUpdateBatch::uploadTexture(). That function has two |
3219 | | variants: one taking a QImage and one taking a |
3220 | | QRhiTextureUploadDescription. The former is a convenience version, |
3221 | | internally creating a QRhiTextureUploadDescription with a single image |
3222 | | targeting level 0 for layer 0. |
3223 | | |
3224 | | An example of the common, simple case of wanting to upload the contents |
3225 | | of a QImage to a QRhiTexture with a matching pixel size: |
3226 | | |
3227 | | \code |
3228 | | QImage image(256, 256, QImage::Format_RGBA8888); |
3229 | | image.fill(Qt::green); // or could use a QPainter targeting image |
3230 | | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(256, 256)); |
3231 | | texture->create(); |
3232 | | QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch(); |
3233 | | u->uploadTexture(texture, image); |
3234 | | \endcode |
3235 | | |
3236 | | When cubemaps, pre-generated mip images, compressed textures, or partial |
3237 | | uploads are involved, applications will have to use this class instead. |
3238 | | |
3239 | | QRhiTextureUploadDescription also enables specifying batched uploads, which |
3240 | | are useful for example when generating an atlas or glyph cache texture: |
3241 | | multiple, partial uploads for the same subresource (meaning the same layer |
3242 | | and level) are supported, and can be, depending on the backend and the |
3243 | | underlying graphics API, more efficient when batched into the same |
3244 | | QRhiTextureUploadDescription as opposed to issuing individual |
3245 | | \l{QRhiResourceUpdateBatch::uploadTexture()}{uploadTexture()} commands for |
3246 | | each of them. |
3247 | | |
3248 | | \note Cubemaps have one layer for each of the six faces in the order +X, |
3249 | | -X, +Y, -Y, +Z, -Z. |
3250 | | |
3251 | | For example, specifying the faces of a cubemap could look like the following: |
3252 | | |
3253 | | \code |
3254 | | QImage faces[6]; |
3255 | | // ... |
3256 | | QVarLengthArray<QRhiTextureUploadEntry, 6> entries; |
3257 | | for (int i = 0; i < 6; ++i) |
3258 | | entries.append(QRhiTextureUploadEntry(i, 0, faces[i])); |
3259 | | QRhiTextureUploadDescription desc; |
3260 | | desc.setEntries(entries.cbegin(), entries.cend()); |
3261 | | resourceUpdates->uploadTexture(texture, desc); |
3262 | | \endcode |
3263 | | |
3264 | | Another example that specifies mip images for a compressed texture: |
3265 | | |
3266 | | \code |
3267 | | QList<QRhiTextureUploadEntry> entries; |
3268 | | const int mipCount = rhi->mipLevelsForSize(compressedTexture->pixelSize()); |
3269 | | for (int level = 0; level < mipCount; ++level) { |
3270 | | const QByteArray compressedDataForLevel = .. |
3271 | | entries.append(QRhiTextureUploadEntry(0, level, compressedDataForLevel)); |
3272 | | } |
3273 | | QRhiTextureUploadDescription desc; |
3274 | | desc.setEntries(entries.cbegin(), entries.cend()); |
3275 | | resourceUpdates->uploadTexture(compressedTexture, desc); |
3276 | | \endcode |
3277 | | |
3278 | | With partial uploads targeting the same subresource, it is recommended to |
3279 | | batch them into a single upload request, whenever possible: |
3280 | | |
3281 | | \code |
3282 | | QRhiTextureSubresourceUploadDescription subresDesc(image); |
3283 | | subresDesc.setSourceSize(QSize(10, 10)); |
3284 | | subResDesc.setDestinationTopLeft(QPoint(50, 40)); |
3285 | | QRhiTextureUploadEntry entry(0, 0, subresDesc); // layer 0, level 0 |
3286 | | |
3287 | | QRhiTextureSubresourceUploadDescription subresDesc2(image); |
3288 | | subresDesc2.setSourceSize(QSize(30, 40)); |
3289 | | subResDesc2.setDestinationTopLeft(QPoint(100, 200)); |
3290 | | QRhiTextureUploadEntry entry2(0, 0, subresDesc2); // layer 0, level 0, i.e. same subresource |
3291 | | |
3292 | | QRhiTextureUploadDescription desc({ entry, entry2}); |
3293 | | resourceUpdates->uploadTexture(texture, desc); |
3294 | | \endcode |
3295 | | |
3296 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3297 | | for details. |
3298 | | |
3299 | | \sa QRhiResourceUpdateBatch |
3300 | | */ |
3301 | | |
3302 | | /*! |
3303 | | \fn QRhiTextureUploadDescription::QRhiTextureUploadDescription() |
3304 | | |
3305 | | Constructs an empty texture upload description. |
3306 | | */ |
3307 | | |
3308 | | /*! |
3309 | | Constructs a texture upload description with a single subresource upload |
3310 | | described by \a entry. |
3311 | | */ |
3312 | | QRhiTextureUploadDescription::QRhiTextureUploadDescription(const QRhiTextureUploadEntry &entry) |
3313 | 0 | { |
3314 | 0 | m_entries.append(entry); |
3315 | 0 | } |
3316 | | |
3317 | | /*! |
3318 | | Constructs a texture upload description with the specified \a list of entries. |
3319 | | |
3320 | | \note \a list can also contain multiple QRhiTextureUploadEntry elements |
3321 | | with the same layer and level. This makes sense when those uploads are |
3322 | | partial, meaning their subresource description has a source size or image |
3323 | | smaller than the subresource dimensions, and can be more efficient than |
3324 | | issuing separate uploadTexture()'s. |
3325 | | */ |
3326 | | QRhiTextureUploadDescription::QRhiTextureUploadDescription(std::initializer_list<QRhiTextureUploadEntry> list) |
3327 | 0 | : m_entries(list) |
3328 | 0 | { |
3329 | 0 | } |
3330 | | |
3331 | | /*! |
3332 | | \fn void QRhiTextureUploadDescription::setEntries(std::initializer_list<QRhiTextureUploadEntry> list) |
3333 | | Sets the \a list of entries. |
3334 | | */ |
3335 | | |
3336 | | /*! |
3337 | | \fn template<typename InputIterator> void QRhiTextureUploadDescription::setEntries(InputIterator first, InputIterator last) |
3338 | | Sets the list of entries using the iterators \a first and \a last. |
3339 | | */ |
3340 | | |
3341 | | /*! |
3342 | | \fn const QRhiTextureUploadEntry *QRhiTextureUploadDescription::cbeginEntries() const |
3343 | | \return a const iterator pointing to the first item in the entry list. |
3344 | | */ |
3345 | | |
3346 | | /*! |
3347 | | \fn const QRhiTextureUploadEntry *QRhiTextureUploadDescription::cendEntries() const |
3348 | | \return a const iterator pointing just after the last item in the entry list. |
3349 | | */ |
3350 | | |
3351 | | /*! |
3352 | | \fn const QRhiTextureUploadEntry *QRhiTextureUploadDescription::entryAt(qsizetype index) const |
3353 | | \return the entry at \a index. |
3354 | | */ |
3355 | | |
3356 | | /*! |
3357 | | \fn qsizetype QRhiTextureUploadDescription::entryCount() const |
3358 | | \return the number of entries. |
3359 | | */ |
3360 | | |
3361 | | /*! |
3362 | | \class QRhiTextureCopyDescription |
3363 | | \inmodule QtGuiPrivate |
3364 | | \inheaderfile rhi/qrhi.h |
3365 | | \since 6.6 |
3366 | | \brief Describes a texture-to-texture copy operation. |
3367 | | |
3368 | | An empty pixelSize() indicates that the entire subresource is to be copied. |
3369 | | A default constructed copy description therefore leads to copying the |
3370 | | entire subresource at level 0 of layer 0. |
3371 | | |
3372 | | \note The source texture must be created with |
3373 | | QRhiTexture::UsedAsTransferSource. |
3374 | | |
3375 | | \note The source and destination rectangles defined by pixelSize(), |
3376 | | sourceTopLeft(), and destinationTopLeft() must fit the source and |
3377 | | destination textures, respectively. The behavior is undefined otherwise. |
3378 | | |
3379 | | With cubemaps, 3D textures, and texture arrays one face or slice can be |
3380 | | copied at a time. The face or slice is specified by the source and |
3381 | | destination layer indices. With mipmapped textures one mip level can be |
3382 | | copied at a time. The source and destination layer and mip level indices can |
3383 | | differ, but the size and position must be carefully controlled to avoid out |
3384 | | of bounds copies, in which case the behavior is undefined. |
3385 | | |
3386 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3387 | | for details. |
3388 | | */ |
3389 | | |
3390 | | /*! |
3391 | | \fn QRhiTextureCopyDescription::QRhiTextureCopyDescription() |
3392 | | |
3393 | | Constructs an empty texture copy description. |
3394 | | */ |
3395 | | |
3396 | | /*! |
3397 | | \fn QSize QRhiTextureCopyDescription::pixelSize() const |
3398 | | \return the size of the region to copy. |
3399 | | |
3400 | | \note An empty pixelSize() indicates that the entire subresource is to be |
3401 | | copied. A default constructed copy description therefore leads to copying |
3402 | | the entire subresource at level 0 of layer 0. |
3403 | | */ |
3404 | | |
3405 | | /*! |
3406 | | \fn void QRhiTextureCopyDescription::setPixelSize(const QSize &sz) |
3407 | | Sets the size of the region to copy to \a sz. |
3408 | | */ |
3409 | | |
3410 | | /*! |
3411 | | \fn int QRhiTextureCopyDescription::sourceLayer() const |
3412 | | \return the source array layer (cubemap face or array layer index). Defaults to 0. |
3413 | | */ |
3414 | | |
3415 | | /*! |
3416 | | \fn void QRhiTextureCopyDescription::setSourceLayer(int layer) |
3417 | | Sets the source array \a layer. |
3418 | | */ |
3419 | | |
3420 | | /*! |
3421 | | \fn int QRhiTextureCopyDescription::sourceLevel() const |
3422 | | \return the source mip level. Defaults to 0. |
3423 | | */ |
3424 | | |
3425 | | /*! |
3426 | | \fn void QRhiTextureCopyDescription::setSourceLevel(int level) |
3427 | | Sets the source mip \a level. |
3428 | | */ |
3429 | | |
3430 | | /*! |
3431 | | \fn QPoint QRhiTextureCopyDescription::sourceTopLeft() const |
3432 | | \return the source top-left position (in pixels). Defaults to (0, 0). |
3433 | | */ |
3434 | | |
3435 | | /*! |
3436 | | \fn void QRhiTextureCopyDescription::setSourceTopLeft(const QPoint &p) |
3437 | | Sets the source top-left position to \a p. |
3438 | | */ |
3439 | | |
3440 | | /*! |
3441 | | \fn int QRhiTextureCopyDescription::destinationLayer() const |
3442 | | \return the destination array layer (cubemap face or array layer index). Default to 0. |
3443 | | */ |
3444 | | |
3445 | | /*! |
3446 | | \fn void QRhiTextureCopyDescription::setDestinationLayer(int layer) |
3447 | | Sets the destination array \a layer. |
3448 | | */ |
3449 | | |
3450 | | /*! |
3451 | | \fn int QRhiTextureCopyDescription::destinationLevel() const |
3452 | | \return the destionation mip level. Defaults to 0. |
3453 | | */ |
3454 | | |
3455 | | /*! |
3456 | | \fn void QRhiTextureCopyDescription::setDestinationLevel(int level) |
3457 | | Sets the destination mip \a level. |
3458 | | */ |
3459 | | |
3460 | | /*! |
3461 | | \fn QPoint QRhiTextureCopyDescription::destinationTopLeft() const |
3462 | | \return the destionation top-left position in pixels. Defaults to (0, 0). |
3463 | | */ |
3464 | | |
3465 | | /*! |
3466 | | \fn void QRhiTextureCopyDescription::setDestinationTopLeft(const QPoint &p) |
3467 | | Sets the destination top-left position \a p. |
3468 | | */ |
3469 | | |
3470 | | /*! |
3471 | | \class QRhiReadbackDescription |
3472 | | \inmodule QtGuiPrivate |
3473 | | \inheaderfile rhi/qrhi.h |
3474 | | \since 6.6 |
3475 | | \brief Describes a readback (reading back texture contents from possibly GPU-only memory) operation. |
3476 | | |
3477 | | The source of the readback operation is either a QRhiTexture or the |
3478 | | current backbuffer of the currently targeted QRhiSwapChain. When |
3479 | | texture() is not set, the swapchain is used. Otherwise the specified |
3480 | | QRhiTexture is treated as the source. |
3481 | | |
3482 | | \note Textures used in readbacks must be created with |
3483 | | QRhiTexture::UsedAsTransferSource. |
3484 | | |
3485 | | \note Swapchains used in readbacks must be created with |
3486 | | QRhiSwapChain::UsedAsTransferSource. |
3487 | | |
3488 | | layer() and level() are only applicable when the source is a QRhiTexture. |
3489 | | |
3490 | | \note Multisample textures cannot be read back. Readbacks are supported for |
3491 | | multisample swapchain buffers however. |
3492 | | |
3493 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3494 | | for details. |
3495 | | */ |
3496 | | |
3497 | | /*! |
3498 | | \fn QRhiReadbackDescription::QRhiReadbackDescription() = default |
3499 | | |
3500 | | Constructs an empty texture readback description. |
3501 | | |
3502 | | \note The source texture is set to null by default, which is still a valid |
3503 | | readback: it specifies that the backbuffer of the current swapchain is to |
3504 | | be read back. (current meaning the frame's target swapchain at the time of |
3505 | | committing the QRhiResourceUpdateBatch with the |
3506 | | \l{QRhiResourceUpdateBatch::readBackTexture()}{texture readback} on it) |
3507 | | */ |
3508 | | |
3509 | | /*! |
3510 | | Constructs an texture readback description that specifies that level 0 of |
3511 | | layer 0 of \a texture is to be read back. |
3512 | | |
3513 | | \note \a texture can also be null in which case this constructor is |
3514 | | identical to the argumentless variant. |
3515 | | */ |
3516 | | QRhiReadbackDescription::QRhiReadbackDescription(QRhiTexture *texture) |
3517 | 0 | : m_texture(texture) |
3518 | 0 | { |
3519 | 0 | } |
3520 | | |
3521 | | /*! |
3522 | | \fn QRhiTexture *QRhiReadbackDescription::texture() const |
3523 | | |
3524 | | \return the QRhiTexture that is read back. Can be left set to \nullptr |
3525 | | which indicates that the backbuffer of the current swapchain is to be used |
3526 | | instead. |
3527 | | */ |
3528 | | |
3529 | | /*! |
3530 | | \fn void QRhiReadbackDescription::setTexture(QRhiTexture *tex) |
3531 | | |
3532 | | Sets the texture \a tex as the source of the readback operation. |
3533 | | |
3534 | | Setting \nullptr is valid too, in which case the current swapchain's |
3535 | | current backbuffer is used. (but then the readback cannot be issued in a |
3536 | | non-swapchain-based frame) |
3537 | | |
3538 | | \note Multisample textures cannot be read back. Readbacks are supported for |
3539 | | multisample swapchain buffers however. |
3540 | | |
3541 | | \note Textures used in readbacks must be created with |
3542 | | QRhiTexture::UsedAsTransferSource. |
3543 | | |
3544 | | \note Swapchains used in readbacks must be created with |
3545 | | QRhiSwapChain::UsedAsTransferSource. |
3546 | | */ |
3547 | | |
3548 | | /*! |
3549 | | \fn int QRhiReadbackDescription::layer() const |
3550 | | |
3551 | | \return the currently set array layer (cubemap face, array index). Defaults to 0. |
3552 | | |
3553 | | Applicable only when the source of the readback is a QRhiTexture. |
3554 | | */ |
3555 | | |
3556 | | /*! |
3557 | | \fn void QRhiReadbackDescription::setLayer(int layer) |
3558 | | Sets the array \a layer to read back. |
3559 | | */ |
3560 | | |
3561 | | /*! |
3562 | | \fn int QRhiReadbackDescription::level() const |
3563 | | |
3564 | | \return the currently set mip level. Defaults to 0. |
3565 | | |
3566 | | Applicable only when the source of the readback is a QRhiTexture. |
3567 | | */ |
3568 | | |
3569 | | /*! |
3570 | | \fn void QRhiReadbackDescription::setLevel(int level) |
3571 | | Sets the mip \a level to read back. |
3572 | | */ |
3573 | | |
3574 | | /*! |
3575 | | \fn const QRect &QRhiReadbackDescription::rect() const |
3576 | | \since 6.10 |
3577 | | |
3578 | | \return the rectangle to read back. Defaults to an invalid rectangle. |
3579 | | |
3580 | | If invalid, the entire texture or swapchain backbuffer is read back. |
3581 | | */ |
3582 | | |
3583 | | /*! |
3584 | | \fn void QRhiReadbackDescription::setRect(const QRect &rectangle) |
3585 | | \since 6.10 |
3586 | | |
3587 | | Sets the \a rectangle to read back. |
3588 | | */ |
3589 | | |
3590 | | /*! |
3591 | | \class QRhiReadbackResult |
3592 | | \inmodule QtGuiPrivate |
3593 | | \inheaderfile rhi/qrhi.h |
3594 | | \since 6.6 |
3595 | | \brief Describes the results of a potentially asynchronous buffer or texture readback operation. |
3596 | | |
3597 | | When \l completed is set, the function is invoked when the \l data is |
3598 | | available. \l format and \l pixelSize are set upon completion together with |
3599 | | \l data. |
3600 | | |
3601 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3602 | | for details. |
3603 | | */ |
3604 | | |
3605 | | /*! |
3606 | | \variable QRhiReadbackResult::completed |
3607 | | |
3608 | | Callback that is invoked upon completion, on the thread the QRhi operates |
3609 | | on. Can be left set to \nullptr, in which case no callback is invoked. |
3610 | | */ |
3611 | | |
3612 | | /*! |
3613 | | \variable QRhiReadbackResult::format |
3614 | | |
3615 | | Valid only for textures, the texture format. |
3616 | | */ |
3617 | | |
3618 | | /*! |
3619 | | \variable QRhiReadbackResult::pixelSize |
3620 | | |
3621 | | Valid only for textures, the size in pixels. |
3622 | | */ |
3623 | | |
3624 | | /*! |
3625 | | \variable QRhiReadbackResult::data |
3626 | | |
3627 | | The buffer or image data. |
3628 | | |
3629 | | \sa QRhiResourceUpdateBatch::readBackTexture(), QRhiResourceUpdateBatch::readBackBuffer() |
3630 | | */ |
3631 | | |
3632 | | |
3633 | | /*! |
3634 | | \class QRhiNativeHandles |
3635 | | \inmodule QtGuiPrivate |
3636 | | \inheaderfile rhi/qrhi.h |
3637 | | \since 6.6 |
3638 | | \brief Base class for classes exposing backend-specific collections of native resource objects. |
3639 | | |
3640 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3641 | | for details. |
3642 | | */ |
3643 | | |
3644 | | /*! |
3645 | | \class QRhiResource |
3646 | | \inmodule QtGuiPrivate |
3647 | | \inheaderfile rhi/qrhi.h |
3648 | | \since 6.6 |
3649 | | \brief Base class for classes encapsulating native resource objects. |
3650 | | |
3651 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3652 | | for details. |
3653 | | */ |
3654 | | |
3655 | | /*! |
3656 | | \enum QRhiResource::Type |
3657 | | Specifies type of the resource. |
3658 | | |
3659 | | \value Buffer |
3660 | | \value Texture |
3661 | | \value Sampler |
3662 | | \value RenderBuffer |
3663 | | \value RenderPassDescriptor |
3664 | | \value SwapChainRenderTarget |
3665 | | \value TextureRenderTarget |
3666 | | \value ShaderResourceBindings |
3667 | | \value GraphicsPipeline |
3668 | | \value SwapChain |
3669 | | \value ComputePipeline |
3670 | | \value CommandBuffer |
3671 | | \value ShadingRateMap |
3672 | | */ |
3673 | | |
3674 | | /*! |
3675 | | \fn virtual QRhiResource::Type QRhiResource::resourceType() const = 0 |
3676 | | |
3677 | | \return the type of the resource. |
3678 | | */ |
3679 | | |
3680 | | /*! |
3681 | | \internal |
3682 | | */ |
3683 | | QRhiResource::QRhiResource(QRhiImplementation *rhi) |
3684 | 0 | : m_rhi(rhi) |
3685 | 0 | { |
3686 | 0 | m_id = QRhiGlobalObjectIdGenerator::newId(); |
3687 | 0 | } |
3688 | | |
3689 | | /*! |
3690 | | Destructor. |
3691 | | |
3692 | | Releases (or requests deferred releasing of) the underlying native graphics |
3693 | | resources, if there are any. |
3694 | | |
3695 | | \note Resources referenced by commands for the current frame should not be |
3696 | | released until the frame is submitted by QRhi::endFrame(). |
3697 | | |
3698 | | \sa destroy() |
3699 | | */ |
3700 | | QRhiResource::~QRhiResource() |
3701 | 0 | { |
3702 | | // destroy() cannot be called here, due to virtuals; it is up to the |
3703 | | // subclasses to do that. |
3704 | 0 | } |
3705 | | |
3706 | | /*! |
3707 | | \fn virtual void QRhiResource::destroy() = 0 |
3708 | | |
3709 | | Releases (or requests deferred releasing of) the underlying native graphics |
3710 | | resources. Safe to call multiple times, subsequent invocations will be a |
3711 | | no-op then. |
3712 | | |
3713 | | Once destroy() is called, the QRhiResource instance can be reused, by |
3714 | | calling \c create() again. That will then result in creating new native |
3715 | | graphics resources underneath. |
3716 | | |
3717 | | \note Resources referenced by commands for the current frame should not be |
3718 | | released until the frame is submitted by QRhi::endFrame(). |
3719 | | |
3720 | | The QRhiResource destructor also performs the same task, so calling this |
3721 | | function is not necessary before deleting a QRhiResource. |
3722 | | |
3723 | | \sa deleteLater() |
3724 | | */ |
3725 | | |
3726 | | /*! |
3727 | | When called without a frame being recorded, this function is equivalent to |
3728 | | deleting the object. Between a QRhi::beginFrame() and QRhi::endFrame() |
3729 | | however the behavior is different: the QRhiResource will not be destroyed |
3730 | | until the frame is submitted via QRhi::endFrame(), thus satisfying the QRhi |
3731 | | requirement of not altering QRhiResource objects that are referenced by the |
3732 | | frame being recorded. |
3733 | | |
3734 | | If the QRhi that created this object is already destroyed, the object is |
3735 | | deleted immediately. |
3736 | | |
3737 | | Using deleteLater() can be a useful convenience in many cases, and it |
3738 | | complements the low-level guarantee (that the underlying native graphics |
3739 | | objects are never destroyed until it is safe to do so and it is known for |
3740 | | sure that they are not used by the GPU in an still in-flight frame), by |
3741 | | offering a way to make sure the C++ object instances (of QRhiBuffer, |
3742 | | QRhiTexture, etc.) themselves also stay valid until the end of the current |
3743 | | frame. |
3744 | | |
3745 | | The following example shows a convenient way of creating a throwaway buffer |
3746 | | that is only used in one frame and gets automatically released in |
3747 | | endFrame(). (when it comes to the underlying native buffer(s), the usual |
3748 | | guarantee applies: the QRhi backend defers the releasing of those until it |
3749 | | is guaranteed that the frame in which the buffer is accessed by the GPU has |
3750 | | completed) |
3751 | | |
3752 | | \code |
3753 | | rhi->beginFrame(swapchain); |
3754 | | QRhiBuffer *buf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, 256); |
3755 | | buf->deleteLater(); // ! |
3756 | | u = rhi->nextResourceUpdateBatch(); |
3757 | | u->uploadStaticBuffer(buf, data); |
3758 | | // ... draw with buf |
3759 | | rhi->endFrame(); |
3760 | | \endcode |
3761 | | |
3762 | | \sa destroy() |
3763 | | */ |
3764 | | void QRhiResource::deleteLater() |
3765 | 0 | { |
3766 | 0 | if (m_rhi) |
3767 | 0 | m_rhi->addDeleteLater(this); |
3768 | 0 | else |
3769 | 0 | delete this; |
3770 | 0 | } |
3771 | | |
3772 | | /*! |
3773 | | \return the currently set object name. By default the name is empty. |
3774 | | */ |
3775 | | QByteArray QRhiResource::name() const |
3776 | 0 | { |
3777 | 0 | return m_objectName; |
3778 | 0 | } |
3779 | | |
3780 | | /*! |
3781 | | Sets a \a name for the object. |
3782 | | |
3783 | | This allows getting descriptive names for the native graphics |
3784 | | resources visible in graphics debugging tools, such as |
3785 | | \l{https://renderdoc.org/}{RenderDoc} and |
3786 | | \l{https://developer.apple.com/xcode/}{XCode}. |
3787 | | |
3788 | | When it comes to naming native objects by relaying the name via the |
3789 | | appropriate graphics API, note that the name is ignored when |
3790 | | QRhi::DebugMarkers are not supported, and may, depending on the backend, |
3791 | | also be ignored when QRhi::EnableDebugMarkers is not set. |
3792 | | |
3793 | | \note The name may be ignored for objects other than buffers, |
3794 | | renderbuffers, and textures, depending on the backend. |
3795 | | |
3796 | | \note The name may be modified. For slotted resources, such as a QRhiBuffer |
3797 | | backed by multiple native buffers, QRhi will append a suffix to make the |
3798 | | underlying native buffers easily distinguishable from each other. |
3799 | | */ |
3800 | | void QRhiResource::setName(const QByteArray &name) |
3801 | 0 | { |
3802 | 0 | m_objectName = name; |
3803 | 0 | } |
3804 | | |
3805 | | /*! |
3806 | | \return the global, unique identifier of this QRhiResource. |
3807 | | |
3808 | | User code rarely needs to deal with the value directly. It is used |
3809 | | internally for tracking and bookkeeping purposes. |
3810 | | */ |
3811 | | quint64 QRhiResource::globalResourceId() const |
3812 | 0 | { |
3813 | 0 | return m_id; |
3814 | 0 | } |
3815 | | |
3816 | | /*! |
3817 | | \return the QRhi that created this resource. |
3818 | | |
3819 | | If the QRhi that created this object is already destroyed, the result is |
3820 | | \nullptr. |
3821 | | */ |
3822 | | QRhi *QRhiResource::rhi() const |
3823 | 0 | { |
3824 | 0 | return m_rhi ? m_rhi->q : nullptr; |
3825 | 0 | } |
3826 | | |
3827 | | /*! |
3828 | | \class QRhiBuffer |
3829 | | \inmodule QtGuiPrivate |
3830 | | \inheaderfile rhi/qrhi.h |
3831 | | \since 6.6 |
3832 | | \brief Vertex, index, or uniform (constant) buffer resource. |
3833 | | |
3834 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
3835 | | for details. |
3836 | | |
3837 | | A QRhiBuffer encapsulates zero, one, or more native buffer objects (such as |
3838 | | a \c VkBuffer or \c MTLBuffer). With some graphics APIs and backends |
3839 | | certain types of buffers may not use a native buffer object at all (e.g. |
3840 | | OpenGL if uniform buffer objects are not used), but this is transparent to |
3841 | | the user of the QRhiBuffer API. Similarly, the fact that some types of |
3842 | | buffers may use two or three native buffers underneath, in order to allow |
3843 | | efficient per-frame content update without stalling the GPU pipeline, is |
3844 | | mostly invisible to the applications and libraries. |
3845 | | |
3846 | | A QRhiBuffer instance is always created by calling |
3847 | | \l{QRhi::newBuffer()}{the QRhi's newBuffer() function}. This creates no |
3848 | | native graphics resources. To do that, call create() after setting the |
3849 | | appropriate options, such as the type, usage flags, size, although in most cases these |
3850 | | are already set based on the arguments passed to |
3851 | | \l{QRhi::newBuffer()}{newBuffer()}. |
3852 | | |
3853 | | \section2 Example usage |
3854 | | |
3855 | | To create a uniform buffer for a shader where the GLSL uniform block |
3856 | | contains a single \c mat4 member, and update the contents: |
3857 | | |
3858 | | \code |
3859 | | QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64); |
3860 | | if (!ubuf->create()) { error(); } |
3861 | | QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); |
3862 | | QMatrix4x4 mvp; |
3863 | | // ... set up the modelview-projection matrix |
3864 | | batch->updateDynamicBuffer(ubuf, 0, 64, mvp.constData()); |
3865 | | // ... |
3866 | | commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call |
3867 | | \endcode |
3868 | | |
3869 | | An example of creating a buffer with vertex data: |
3870 | | |
3871 | | \code |
3872 | | const float vertices[] = { -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 1.0f }; |
3873 | | QRhiBuffer *vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices)); |
3874 | | if (!vbuf->create()) { error(); } |
3875 | | QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); |
3876 | | batch->uploadStaticBuffer(vbuf, vertices); |
3877 | | // ... |
3878 | | commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call |
3879 | | \endcode |
3880 | | |
3881 | | An index buffer: |
3882 | | |
3883 | | \code |
3884 | | static const quint16 indices[] = { 0, 1, 2 }; |
3885 | | QRhiBuffer *ibuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(indices)); |
3886 | | if (!ibuf->create()) { error(); } |
3887 | | QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); |
3888 | | batch->uploadStaticBuffer(ibuf, indices); |
3889 | | // ... |
3890 | | commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call |
3891 | | \endcode |
3892 | | |
3893 | | \section2 Common patterns |
3894 | | |
3895 | | A call to create() destroys any existing native resources if create() was |
3896 | | successfully called before. If those native resources are still in use by |
3897 | | an in-flight frame (i.e., there's a chance they are still read by the GPU), |
3898 | | the destroying of those resources is deferred automatically. Thus a very |
3899 | | common and convenient pattern to safely increase the size of an already |
3900 | | initialized buffer is the following. In practice this drops and creates a |
3901 | | whole new set of native resources underneath, so it is not necessarily a |
3902 | | cheap operation, but is more convenient and still faster than the |
3903 | | alternatives, because by not destroying the \c buf object itself, all |
3904 | | references to it stay valid in other data structures (e.g., in any |
3905 | | QRhiShaderResourceBinding the QRhiBuffer is referenced from). |
3906 | | |
3907 | | \code |
3908 | | if (buf->size() < newSize) { |
3909 | | buf->setSize(newSize); |
3910 | | if (!buf->create()) { error(); } |
3911 | | } |
3912 | | // continue using buf, fill it with new data |
3913 | | \endcode |
3914 | | |
3915 | | When working with uniform buffers, it will sometimes be necessary to |
3916 | | combine data for multiple draw calls into a single buffer for efficiency |
3917 | | reasons. Be aware of the aligment requirements: with some graphics APIs |
3918 | | offsets for a uniform buffer must be aligned to 256 bytes. This applies |
3919 | | both to QRhiShaderResourceBinding and to the dynamic offsets passed to |
3920 | | \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()}. Use the |
3921 | | \l{QRhi::ubufAlignment()}{ubufAlignment()} and |
3922 | | \l{QRhi::ubufAligned()}{ubufAligned()} functions to create portable code. |
3923 | | As an example, the following is an outline for issuing multiple (\c N) draw |
3924 | | calls with the same pipeline and geometry, but with a different data in the |
3925 | | uniform buffers exposed at binding point 0. This assumes the buffer is |
3926 | | exposed via |
3927 | | \l{QRhiShaderResourceBinding::uniformBufferWithDynamicOffset()}{uniformBufferWithDynamicOffset()} |
3928 | | which allows passing a QRhiCommandBuffer::DynamicOffset list to |
3929 | | \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()}. |
3930 | | |
3931 | | \code |
3932 | | const int N = 2; |
3933 | | const int UB_SIZE = 64 + 4; // assuming a uniform block with { mat4 matrix; float opacity; } |
3934 | | const int ONE_UBUF_SIZE = rhi->ubufAligned(UB_SIZE); |
3935 | | const int TOTAL_UBUF_SIZE = N * ONE_UBUF_SIZE; |
3936 | | QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, TOTAL_UBUF_SIZE); |
3937 | | if (!ubuf->create()) { error(); } |
3938 | | QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); |
3939 | | for (int i = 0; i < N; ++i) { |
3940 | | batch->updateDynamicBuffer(ubuf, i * ONE_UBUF_SIZE, 64, matrix.constData()); |
3941 | | batch->updateDynamicBuffer(ubuf, i * ONE_UBUF_SIZE + 64, 4, &opacity); |
3942 | | } |
3943 | | // ... |
3944 | | // beginPass(), set pipeline, etc., and then: |
3945 | | for (int i = 0; i < N; ++i) { |
3946 | | QRhiCommandBuffer::DynamicOffset dynOfs[] = { { 0, i * ONE_UBUF_SIZE } }; |
3947 | | cb->setShaderResources(srb, 1, dynOfs); |
3948 | | cb->draw(36); |
3949 | | } |
3950 | | \endcode |
3951 | | |
3952 | | \sa QRhiResourceUpdateBatch, QRhi, QRhiCommandBuffer |
3953 | | */ |
3954 | | |
3955 | | /*! |
3956 | | \enum QRhiBuffer::Type |
3957 | | Specifies storage type of buffer resource. |
3958 | | |
3959 | | \value Immutable Indicates that the data is not expected to change ever |
3960 | | after the initial upload. Under the hood such buffer resources are |
3961 | | typically placed in device local (GPU) memory (on systems where |
3962 | | applicable). Uploading new data is possible, but may be expensive. The |
3963 | | upload typically happens by copying to a separate, host visible staging |
3964 | | buffer from which a GPU buffer-to-buffer copy is issued into the actual |
3965 | | GPU-only buffer. |
3966 | | |
3967 | | \value Static Indicates that the data is expected to change only |
3968 | | infrequently. Typically placed in device local (GPU) memory, where |
3969 | | applicable. On backends where host visible staging buffers are used for |
3970 | | uploading, the staging buffers are kept around for this type, unlike with |
3971 | | Immutable, so subsequent uploads do not suffer in performance. Frequent |
3972 | | updates, especially updates in consecutive frames, should be avoided. |
3973 | | |
3974 | | \value Dynamic Indicates that the data is expected to change frequently. |
3975 | | Not recommended for large buffers. Typically backed by host visible memory |
3976 | | in 2 copies in order to allow for changing without stalling the graphics |
3977 | | pipeline. The double buffering is managed transparently to the applications |
3978 | | and is not exposed in the API here in any form. This is the recommended, |
3979 | | and, with some backends, the only possible, type for buffers with |
3980 | | UniformBuffer usage. |
3981 | | */ |
3982 | | |
3983 | | /*! |
3984 | | \enum QRhiBuffer::UsageFlag |
3985 | | Flag values to specify how the buffer is going to be used. |
3986 | | |
3987 | | \value VertexBuffer Vertex buffer. This allows the QRhiBuffer to be used in |
3988 | | \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()}. |
3989 | | |
3990 | | \value IndexBuffer Index buffer. This allows the QRhiBuffer to be used in |
3991 | | \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()}. |
3992 | | |
3993 | | \value UniformBuffer Uniform buffer (also called constant buffer). This |
3994 | | allows the QRhiBuffer to be used in combination with |
3995 | | \l{QRhiShaderResourceBinding::UniformBuffer}{UniformBuffer}. When |
3996 | | \l{QRhi::NonDynamicUniformBuffers}{NonDynamicUniformBuffers} is reported as |
3997 | | not supported, this usage can only be combined with the type Dynamic. |
3998 | | |
3999 | | \value StorageBuffer Storage buffer. This allows the QRhiBuffer to be used |
4000 | | in combination with \l{QRhiShaderResourceBinding::BufferLoad}{BufferLoad}, |
4001 | | \l{QRhiShaderResourceBinding::BufferStore}{BufferStore}, or |
4002 | | \l{QRhiShaderResourceBinding::BufferLoadStore}{BufferLoadStore}. This usage |
4003 | | can only be combined with the types Immutable or Static, and is only |
4004 | | available when the \l{QRhi::Compute}{Compute feature} is reported as |
4005 | | supported. |
4006 | | |
4007 | | \value [since 6.12] IndirectBuffer Indirect draw buffer. This allows the |
4008 | | QRhiBuffer to be used in \l{QRhiCommandBuffer::drawIndirect()}{drawIndirect()} |
4009 | | and \l{QRhiCommandBuffer::drawIndexedIndirect()}{drawIndexedIndirect()}. |
4010 | | This usage can be combined with types Immutable or Static. Combining it with |
4011 | | Dynamic is unsupported with D3D11, where create() will fail. This usage may |
4012 | | also be combined with StorageBuffer on backends that support |
4013 | | \l{QRhi::Compute}{compute shaders}, allowing indirect draw commands to be |
4014 | | generated by compute shaders and consumed by indirect draw calls. |
4015 | | */ |
4016 | | |
4017 | | /*! |
4018 | | \class QRhiBuffer::NativeBuffer |
4019 | | \inmodule QtGuiPrivate |
4020 | | \inheaderfile rhi/qrhi.h |
4021 | | \brief Contains information about the underlying native resources of a buffer. |
4022 | | */ |
4023 | | |
4024 | | /*! |
4025 | | \variable QRhiBuffer::NativeBuffer::objects |
4026 | | \brief an array with pointers to the native object handles. |
4027 | | |
4028 | | With OpenGL, the native handle is a GLuint value, so the elements in the \c |
4029 | | objects array are pointers to a GLuint. With Vulkan, the native handle is a |
4030 | | VkBuffer, so the elements of the array are pointers to a VkBuffer. With |
4031 | | Direct3D 11 and Metal the elements are pointers to a ID3D11Buffer or |
4032 | | MTLBuffer pointer, respectively. With Direct3D 12, the elements are |
4033 | | pointers to a ID3D12Resource. |
4034 | | |
4035 | | \note Pay attention to the fact that the elements are always pointers to |
4036 | | the native buffer handle type, even if the native type itself is a pointer. |
4037 | | (so the elements are \c{VkBuffer *} on Vulkan, even though VkBuffer itself |
4038 | | is a pointer on 64-bit architectures). |
4039 | | */ |
4040 | | |
4041 | | /*! |
4042 | | \variable QRhiBuffer::NativeBuffer::slotCount |
4043 | | \brief Specifies the number of valid elements in the objects array. |
4044 | | |
4045 | | The value can be 0, 1, 2, or 3 in practice. 0 indicates that the QRhiBuffer |
4046 | | is not backed by any native buffer objects. This can happen with |
4047 | | QRhiBuffers with the usage UniformBuffer when the underlying API does not |
4048 | | support (or the backend chooses not to use) native uniform buffers. 1 is |
4049 | | commonly used for Immutable and Static types (but some backends may |
4050 | | differ). 2 or 3 is typical when the type is Dynamic (but some backends may |
4051 | | differ). |
4052 | | |
4053 | | \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight |
4054 | | */ |
4055 | | |
4056 | | /*! |
4057 | | \internal |
4058 | | */ |
4059 | | QRhiBuffer::QRhiBuffer(QRhiImplementation *rhi, Type type_, UsageFlags usage_, quint32 size_) |
4060 | 0 | : QRhiResource(rhi), |
4061 | 0 | m_type(type_), m_usage(usage_), m_size(size_) |
4062 | 0 | { |
4063 | 0 | } |
4064 | | |
4065 | | /*! |
4066 | | \return the resource type. |
4067 | | */ |
4068 | | QRhiResource::Type QRhiBuffer::resourceType() const |
4069 | 0 | { |
4070 | 0 | return Buffer; |
4071 | 0 | } |
4072 | | |
4073 | | /*! |
4074 | | \fn virtual bool QRhiBuffer::create() = 0 |
4075 | | |
4076 | | Creates the corresponding native graphics resources. If there are already |
4077 | | resources present due to an earlier create() with no corresponding |
4078 | | destroy(), then destroy() is called implicitly first. |
4079 | | |
4080 | | \return \c true when successful, \c false when a graphics operation failed. |
4081 | | Regardless of the return value, calling destroy() is always safe. |
4082 | | */ |
4083 | | |
4084 | | /*! |
4085 | | \fn QRhiBuffer::Type QRhiBuffer::type() const |
4086 | | \return the buffer type. |
4087 | | */ |
4088 | | |
4089 | | /*! |
4090 | | \fn void QRhiBuffer::setType(Type t) |
4091 | | Sets the buffer's type to \a t. |
4092 | | */ |
4093 | | |
4094 | | /*! |
4095 | | \fn QRhiBuffer::UsageFlags QRhiBuffer::usage() const |
4096 | | \return the buffer's usage flags. |
4097 | | */ |
4098 | | |
4099 | | /*! |
4100 | | \fn void QRhiBuffer::setUsage(UsageFlags u) |
4101 | | Sets the buffer's usage flags to \a u. |
4102 | | */ |
4103 | | |
4104 | | /*! |
4105 | | \fn quint32 QRhiBuffer::size() const |
4106 | | |
4107 | | \return the buffer's size in bytes. |
4108 | | |
4109 | | This is always the value that was passed to setSize() or QRhi::newBuffer(). |
4110 | | Internally, the native buffers may be bigger if that is required by the |
4111 | | underlying graphics API. |
4112 | | */ |
4113 | | |
4114 | | /*! |
4115 | | \fn void QRhiBuffer::setSize(quint32 sz) |
4116 | | |
4117 | | Sets the size of the buffer in bytes. The size is normally specified in |
4118 | | QRhi::newBuffer() so this function is only used when the size has to be |
4119 | | changed. As with other setters, the size only takes effect when calling |
4120 | | create(), and for already created buffers this involves releasing the previous |
4121 | | native resource and creating new ones under the hood. |
4122 | | |
4123 | | Backends may choose to allocate buffers bigger than \a sz in order to |
4124 | | fulfill alignment requirements. This is hidden from the applications and |
4125 | | size() will always report the size requested in \a sz. |
4126 | | */ |
4127 | | |
4128 | | /*! |
4129 | | \return the underlying native resources for this buffer. The returned value |
4130 | | will be empty if exposing the underlying native resources is not supported by |
4131 | | the backend. |
4132 | | |
4133 | | A QRhiBuffer may be backed by multiple native buffer objects, depending on |
4134 | | the type() and the QRhi backend in use. When this is the case, all of them |
4135 | | are returned in the objects array in the returned struct, with slotCount |
4136 | | specifying the number of native buffer objects. While |
4137 | | \l{QRhi::beginFrame()}{recording a frame}, QRhi::currentFrameSlot() can be |
4138 | | used to determine which of the native buffers QRhi is using for operations |
4139 | | that read or write from this QRhiBuffer within the frame being recorded. |
4140 | | |
4141 | | In some cases a QRhiBuffer will not be backed by a native buffer object at |
4142 | | all. In this case slotCount will be set to 0 and no valid native objects |
4143 | | are returned. This is not an error, and is perfectly valid when a given |
4144 | | backend does not use native buffers for QRhiBuffers with certain types or |
4145 | | usages. |
4146 | | |
4147 | | \note Be aware that QRhi backends may employ various buffer update |
4148 | | strategies. Unlike textures, where uploading image data always means |
4149 | | recording a buffer-to-image (or similar) copy command on the command |
4150 | | buffer, buffers, in particular Dynamic and UniformBuffer ones, can operate |
4151 | | in many different ways. For example, a QRhiBuffer with usage type |
4152 | | UniformBuffer may not even be backed by a native buffer object at all if |
4153 | | uniform buffers are not used or supported by a given backend and graphics |
4154 | | API. There are also differences to how data is written to the buffer and |
4155 | | the type of backing memory used. For buffers backed by host visible memory, |
4156 | | calling this function guarantees that pending host writes are executed for |
4157 | | all the returned native buffers. |
4158 | | |
4159 | | \sa QRhi::currentFrameSlot(), QRhi::FramesInFlight |
4160 | | */ |
4161 | | QRhiBuffer::NativeBuffer QRhiBuffer::nativeBuffer() |
4162 | 0 | { |
4163 | 0 | return { {}, 0 }; |
4164 | 0 | } |
4165 | | |
4166 | | /*! |
4167 | | \return a pointer to a memory block with the host visible buffer data. |
4168 | | |
4169 | | This is a shortcut for medium-to-large dynamic uniform buffers that have |
4170 | | their \b entire contents (or at least all regions that are read by the |
4171 | | shaders in the current frame) changed \b{in every frame} and the |
4172 | | QRhiResourceUpdateBatch-based update mechanism is seen too heavy due to the |
4173 | | amount of data copying involved. |
4174 | | |
4175 | | The call to this function must be eventually followed by a call to |
4176 | | endFullDynamicUniformBufferUpdateForCurrentFrame(), before recording any |
4177 | | render or compute pass that relies on this buffer. |
4178 | | |
4179 | | \warning Updating data via this method is not compatible with |
4180 | | QRhiResourceUpdateBatch-based updates and readbacks. Unexpected behavior |
4181 | | may occur when attempting to combine the two update models for the same |
4182 | | buffer. Similarly, the data updated this direct way may not be visible to |
4183 | | \l{QRhiResourceUpdateBatch::readBackBuffer()}{readBackBuffer operations}, |
4184 | | depending on the backend. |
4185 | | |
4186 | | \warning When updating buffer data via this method, the update must be done |
4187 | | in every frame, otherwise backends that perform double or triple buffering |
4188 | | of resources may end up in unexpected behavior. |
4189 | | |
4190 | | \warning Partial updates are not possible with this approach since some |
4191 | | backends may choose a strategy where the previous contents of the buffer is |
4192 | | lost upon calling this function. Data must be written to all regions that |
4193 | | are read by shaders in the frame currently being prepared. |
4194 | | |
4195 | | \warning This function can only be called when recording a frame, so |
4196 | | between QRhi::beginFrame() and QRhi::endFrame(). |
4197 | | |
4198 | | \warning This function can only be called on Dynamic buffers. |
4199 | | */ |
4200 | | char *QRhiBuffer::beginFullDynamicBufferUpdateForCurrentFrame() |
4201 | 0 | { |
4202 | 0 | return nullptr; |
4203 | 0 | } |
4204 | | |
4205 | | /*! |
4206 | | To be called when the entire contents of the buffer data has been updated |
4207 | | in the memory block returned from |
4208 | | beginFullDynamicBufferUpdateForCurrentFrame(). |
4209 | | */ |
4210 | | void QRhiBuffer::endFullDynamicBufferUpdateForCurrentFrame() |
4211 | 0 | { |
4212 | 0 | } |
4213 | | |
4214 | | /*! |
4215 | | \internal |
4216 | | */ |
4217 | | void QRhiBuffer::fullDynamicBufferUpdateForCurrentFrame(const void *data, quint32 size) |
4218 | 0 | { |
4219 | 0 | char *p = beginFullDynamicBufferUpdateForCurrentFrame(); |
4220 | 0 | if (p) { |
4221 | 0 | memcpy(p, data, size > 0 ? size : m_size); |
4222 | 0 | endFullDynamicBufferUpdateForCurrentFrame(); |
4223 | 0 | } |
4224 | 0 | } |
4225 | | |
4226 | | /*! |
4227 | | \class QRhiRenderBuffer |
4228 | | \inmodule QtGuiPrivate |
4229 | | \inheaderfile rhi/qrhi.h |
4230 | | \since 6.6 |
4231 | | \brief Renderbuffer resource. |
4232 | | |
4233 | | Renderbuffers cannot be sampled or read but have some benefits over |
4234 | | textures in some cases: |
4235 | | |
4236 | | A \l DepthStencil renderbuffer may be lazily allocated and be backed by |
4237 | | transient memory with some APIs. On some platforms this may mean the |
4238 | | depth/stencil buffer uses no physical backing at all. |
4239 | | |
4240 | | \l Color renderbuffers are useful since QRhi::MultisampleRenderBuffer may be |
4241 | | supported even when QRhi::MultisampleTexture is not. |
4242 | | |
4243 | | How the renderbuffer is implemented by a backend is not exposed to the |
4244 | | applications. In some cases it may be backed by ordinary textures, while in |
4245 | | others there may be a different kind of native resource used. |
4246 | | |
4247 | | Renderbuffers that are used as (and are only used as) depth-stencil buffers |
4248 | | in combination with a QRhiSwapChain's color buffers should have the |
4249 | | UsedWithSwapChainOnly flag set. This serves a double purpose: such buffers, |
4250 | | depending on the backend and the underlying APIs, be more efficient, and |
4251 | | QRhi provides automatic sizing behavior to match the color buffers, which |
4252 | | means calling setPixelSize() and create() are not necessary for such |
4253 | | renderbuffers. |
4254 | | |
4255 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
4256 | | for details. |
4257 | | */ |
4258 | | |
4259 | | /*! |
4260 | | \enum QRhiRenderBuffer::Type |
4261 | | Specifies the type of the renderbuffer |
4262 | | |
4263 | | \value DepthStencil Combined depth/stencil |
4264 | | \value Color Color |
4265 | | */ |
4266 | | |
4267 | | /*! |
4268 | | \struct QRhiRenderBuffer::NativeRenderBuffer |
4269 | | \inmodule QtGuiPrivate |
4270 | | \inheaderfile rhi/qrhi.h |
4271 | | \brief Wraps a native renderbuffer object. |
4272 | | */ |
4273 | | |
4274 | | /*! |
4275 | | \variable QRhiRenderBuffer::NativeRenderBuffer::object |
4276 | | \brief 64-bit integer containing the native object handle. |
4277 | | |
4278 | | Used with QRhiRenderBuffer::createFrom(). |
4279 | | |
4280 | | With OpenGL the native handle is a GLuint value. \c object is expected to |
4281 | | be a valid OpenGL renderbuffer object ID. |
4282 | | */ |
4283 | | |
4284 | | /*! |
4285 | | \enum QRhiRenderBuffer::Flag |
4286 | | Flag values for flags() and setFlags() |
4287 | | |
4288 | | \value UsedWithSwapChainOnly For DepthStencil renderbuffers this indicates |
4289 | | that the renderbuffer is only used in combination with a QRhiSwapChain, and |
4290 | | never in any other way. This provides automatic sizing and resource |
4291 | | rebuilding, so calling setPixelSize() or create() is not needed whenever |
4292 | | this flag is set. This flag value may also trigger backend-specific |
4293 | | behavior, for example with OpenGL, where a separate windowing system |
4294 | | interface API is in use (EGL, GLX, etc.), the flag is especially important |
4295 | | as it avoids creating any actual renderbuffer resource as there is already |
4296 | | a windowing system provided depth/stencil buffer as requested by |
4297 | | QSurfaceFormat. |
4298 | | */ |
4299 | | |
4300 | | /*! |
4301 | | \internal |
4302 | | */ |
4303 | | QRhiRenderBuffer::QRhiRenderBuffer(QRhiImplementation *rhi, Type type_, const QSize &pixelSize_, |
4304 | | int sampleCount_, Flags flags_, |
4305 | | QRhiTexture::Format backingFormatHint_) |
4306 | 0 | : QRhiResource(rhi), |
4307 | 0 | m_type(type_), m_pixelSize(pixelSize_), m_sampleCount(sampleCount_), m_flags(flags_), |
4308 | 0 | m_backingFormatHint(backingFormatHint_) |
4309 | 0 | { |
4310 | 0 | } |
4311 | | |
4312 | | /*! |
4313 | | \return the resource type. |
4314 | | */ |
4315 | | QRhiResource::Type QRhiRenderBuffer::resourceType() const |
4316 | 0 | { |
4317 | 0 | return RenderBuffer; |
4318 | 0 | } |
4319 | | |
4320 | | /*! |
4321 | | \fn virtual bool QRhiRenderBuffer::create() = 0 |
4322 | | |
4323 | | Creates the corresponding native graphics resources. If there are already |
4324 | | resources present due to an earlier create() with no corresponding |
4325 | | destroy(), then destroy() is called implicitly first. |
4326 | | |
4327 | | \return \c true when successful, \c false when a graphics operation failed. |
4328 | | Regardless of the return value, calling destroy() is always safe. |
4329 | | */ |
4330 | | |
4331 | | /*! |
4332 | | Similar to create() except that no new native renderbuffer objects are |
4333 | | created. Instead, the native renderbuffer object specified by \a src is |
4334 | | used. |
4335 | | |
4336 | | This allows importing an existing renderbuffer object (which must belong to |
4337 | | the same device or sharing context, depending on the graphics API) from an |
4338 | | external graphics engine. |
4339 | | |
4340 | | \note This is currently applicable to OpenGL only. This function exists |
4341 | | solely to allow importing a renderbuffer object that is bound to some |
4342 | | special, external object, such as an EGLImageKHR. Once the application |
4343 | | performed the glEGLImageTargetRenderbufferStorageOES call, the renderbuffer |
4344 | | object can be passed to this function to create a wrapping |
4345 | | QRhiRenderBuffer, which in turn can be passed in as a color attachment to |
4346 | | a QRhiTextureRenderTarget to enable rendering to the EGLImage. |
4347 | | |
4348 | | \note pixelSize(), sampleCount(), and flags() must still be set correctly. |
4349 | | Passing incorrect sizes and other values to QRhi::newRenderBuffer() and |
4350 | | then following it with a createFrom() expecting that the native |
4351 | | renderbuffer object alone is sufficient to deduce such values is \b wrong |
4352 | | and will lead to problems. |
4353 | | |
4354 | | \note QRhiRenderBuffer does not take ownership of the native object, and |
4355 | | destroy() will not release that object. |
4356 | | |
4357 | | \note This function is only implemented when the QRhi::RenderBufferImport |
4358 | | feature is reported as \l{QRhi::isFeatureSupported()}{supported}. Otherwise, |
4359 | | the function does nothing and the return value is \c false. |
4360 | | |
4361 | | \return \c true when successful, \c false when not supported. |
4362 | | */ |
4363 | | bool QRhiRenderBuffer::createFrom(NativeRenderBuffer src) |
4364 | 0 | { |
4365 | 0 | Q_UNUSED(src); |
4366 | 0 | return false; |
4367 | 0 | } |
4368 | | |
4369 | | /*! |
4370 | | \fn QRhiRenderBuffer::Type QRhiRenderBuffer::type() const |
4371 | | \return the renderbuffer type. |
4372 | | */ |
4373 | | |
4374 | | /*! |
4375 | | \fn void QRhiRenderBuffer::setType(Type t) |
4376 | | Sets the type to \a t. |
4377 | | */ |
4378 | | |
4379 | | /*! |
4380 | | \fn QSize QRhiRenderBuffer::pixelSize() const |
4381 | | \return the pixel size. |
4382 | | */ |
4383 | | |
4384 | | /*! |
4385 | | \fn void QRhiRenderBuffer::setPixelSize(const QSize &sz) |
4386 | | Sets the size (in pixels) to \a sz. |
4387 | | */ |
4388 | | |
4389 | | /*! |
4390 | | \fn int QRhiRenderBuffer::sampleCount() const |
4391 | | \return the sample count. 1 means no multisample antialiasing. |
4392 | | */ |
4393 | | |
4394 | | /*! |
4395 | | \fn void QRhiRenderBuffer::setSampleCount(int s) |
4396 | | Sets the sample count to \a s. |
4397 | | */ |
4398 | | |
4399 | | /*! |
4400 | | \fn QRhiRenderBuffer::Flags QRhiRenderBuffer::flags() const |
4401 | | \return the flags. |
4402 | | */ |
4403 | | |
4404 | | /*! |
4405 | | \fn void QRhiRenderBuffer::setFlags(Flags f) |
4406 | | Sets the flags to \a f. |
4407 | | */ |
4408 | | |
4409 | | /*! |
4410 | | \fn virtual QRhiTexture::Format QRhiRenderBuffer::backingFormat() const = 0 |
4411 | | |
4412 | | \internal |
4413 | | */ |
4414 | | |
4415 | | /*! |
4416 | | \class QRhiTexture |
4417 | | \inmodule QtGuiPrivate |
4418 | | \inheaderfile rhi/qrhi.h |
4419 | | \since 6.6 |
4420 | | \brief Texture resource. |
4421 | | |
4422 | | A QRhiTexture encapsulates a native texture object, such as a \c VkImage or |
4423 | | \c MTLTexture. |
4424 | | |
4425 | | A QRhiTexture instance is always created by calling |
4426 | | \l{QRhi::newTexture()}{the QRhi's newTexture() function}. This creates no |
4427 | | native graphics resources. To do that, call create() after setting the |
4428 | | appropriate options, such as the format and size, although in most cases |
4429 | | these are already set based on the arguments passed to |
4430 | | \l{QRhi::newTexture()}{newTexture()}. |
4431 | | |
4432 | | Setting the \l{QRhiTexture::Flags}{flags} correctly is essential, otherwise |
4433 | | various errors can occur depending on the underlying QRhi backend and |
4434 | | graphics API. For example, when a texture will be rendered into from a |
4435 | | render pass via QRhiTextureRenderTarget, the texture must be created with |
4436 | | the \l RenderTarget flag set. Similarly, when the texture is going to be |
4437 | | \l{QRhiResourceUpdateBatch::readBackTexture()}{read back}, the \l |
4438 | | UsedAsTransferSource flag must be set upfront. Mipmapped textures must have |
4439 | | the MipMapped flag set. And so on. It is not possible to change the flags |
4440 | | once create() has succeeded. To release the existing and create a new |
4441 | | native texture object with the changed settings, call the setters and call |
4442 | | create() again. This then might be a potentially expensive operation. |
4443 | | |
4444 | | \section2 Example usage |
4445 | | |
4446 | | To create a 2D texture with a size of 512x512 pixels and set its contents to all green: |
4447 | | |
4448 | | \code |
4449 | | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512)); |
4450 | | if (!texture->create()) { error(); } |
4451 | | QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch(); |
4452 | | QImage image(512, 512, QImage::Format_RGBA8888); |
4453 | | image.fill(Qt::green); |
4454 | | batch->uploadTexture(texture, image); |
4455 | | // ... |
4456 | | commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call |
4457 | | \endcode |
4458 | | |
4459 | | \section2 Common patterns |
4460 | | |
4461 | | A call to create() destroys any existing native resources if create() was |
4462 | | successfully called before. If those native resources are still in use by |
4463 | | an in-flight frame (i.e., there's a chance they are still read by the GPU), |
4464 | | the destroying of those resources is deferred automatically. Thus a very |
4465 | | common and convenient pattern to safely change the size of an already |
4466 | | existing texture is the following. In practice this drops and creates a |
4467 | | whole new native texture resource underneath, so it is not necessarily a |
4468 | | cheap operation, but is more convenient and still faster than the |
4469 | | alternatives, because by not destroying the \c texture object itself, all |
4470 | | references to it stay valid in other data structures (e.g., in any |
4471 | | QShaderResourceBinding the QRhiTexture is referenced from). |
4472 | | |
4473 | | \code |
4474 | | // determine newSize, e.g. based on the swapchain's output size or other factors |
4475 | | if (texture->pixelSize() != newSize) { |
4476 | | texture->setPixelSize(newSize); |
4477 | | if (!texture->create()) { error(); } |
4478 | | } |
4479 | | // continue using texture, fill it with new data |
4480 | | \endcode |
4481 | | |
4482 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
4483 | | for details. |
4484 | | |
4485 | | \sa QRhiResourceUpdateBatch, QRhi, QRhiTextureRenderTarget |
4486 | | */ |
4487 | | |
4488 | | /*! |
4489 | | \enum QRhiTexture::Flag |
4490 | | |
4491 | | Flag values to specify how the texture is going to be used. Not honoring |
4492 | | the flags set before create() and attempting to use the texture in ways that |
4493 | | was not declared upfront can lead to unspecified behavior or decreased |
4494 | | performance depending on the backend and the underlying graphics API. |
4495 | | |
4496 | | \value RenderTarget The texture going to be used in combination with |
4497 | | QRhiTextureRenderTarget. |
4498 | | |
4499 | | \value CubeMap The texture is a cubemap. Such textures have 6 layers, one |
4500 | | for each face in the order of +X, -X, +Y, -Y, +Z, -Z. Cubemap textures |
4501 | | cannot be multisample. |
4502 | | |
4503 | | \value MipMapped The texture has mipmaps. The appropriate mip count is |
4504 | | calculated automatically and can also be retrieved via |
4505 | | QRhi::mipLevelsForSize(). The images for the mip levels have to be |
4506 | | provided in the texture uploaded or generated via |
4507 | | QRhiResourceUpdateBatch::generateMips(). Multisample textures cannot have |
4508 | | mipmaps. |
4509 | | |
4510 | | \value sRGB Use an sRGB format. |
4511 | | |
4512 | | \value UsedAsTransferSource The texture is used as the source of a texture |
4513 | | copy or readback, meaning the texture is given as the source in |
4514 | | QRhiResourceUpdateBatch::copyTexture() or |
4515 | | QRhiResourceUpdateBatch::readBackTexture(). |
4516 | | |
4517 | | \value UsedWithGenerateMips The texture is going to be used with |
4518 | | QRhiResourceUpdateBatch::generateMips(). |
4519 | | |
4520 | | \value UsedWithLoadStore The texture is going to be used with image |
4521 | | load/store operations, for example, in a compute shader. |
4522 | | |
4523 | | \value UsedAsCompressedAtlas The texture has a compressed format and the |
4524 | | dimensions of subresource uploads may not match the texture size. |
4525 | | |
4526 | | \value ExternalOES The texture should use the GL_TEXTURE_EXTERNAL_OES |
4527 | | target with OpenGL. This flag is ignored with other graphics APIs. |
4528 | | |
4529 | | \value ThreeDimensional The texture is a 3D texture. Such textures should |
4530 | | be created with the QRhi::newTexture() overload taking a depth in addition |
4531 | | to width and height. A 3D texture can have mipmaps but cannot be |
4532 | | multisample. When rendering into, or uploading data to a 3D texture, the \c |
4533 | | layer specified in the render target's color attachment or the upload |
4534 | | description refers to a single slice in range [0..depth-1]. The underlying |
4535 | | graphics API may not support 3D textures at run time. Support is indicated |
4536 | | by the QRhi::ThreeDimensionalTextures feature. |
4537 | | |
4538 | | \value TextureRectangleGL The texture should use the GL_TEXTURE_RECTANGLE |
4539 | | target with OpenGL. This flag is ignored with other graphics APIs. Just |
4540 | | like ExternalOES, this flag is useful when working with platform APIs where |
4541 | | native OpenGL texture objects received from the platform are wrapped in a |
4542 | | QRhiTexture, and the platform can only provide textures for a non-2D |
4543 | | texture target. |
4544 | | |
4545 | | \value TextureArray The texture is a texture array, i.e. a single texture |
4546 | | object that is a homogeneous array of 2D textures. Texture arrays are |
4547 | | created with QRhi::newTextureArray(). The underlying graphics API may not |
4548 | | support texture array objects at run time. Support is indicated by the |
4549 | | QRhi::TextureArrays feature. When rendering into, or uploading data to a |
4550 | | texture array, the \c layer specified in the render target's color |
4551 | | attachment or the upload description selects a single element in the array. |
4552 | | |
4553 | | \value OneDimensional The texture is a 1D texture. Such textures can be |
4554 | | created by passing a 0 height and depth to QRhi::newTexture(). Note that |
4555 | | there can be limitations on one dimensional textures depending on the |
4556 | | underlying graphics API. For example, rendering to them or using them with |
4557 | | mipmap-based filtering may be unsupported. This is indicated by the |
4558 | | QRhi::OneDimensionalTextures and QRhi::OneDimensionalTextureMipmaps |
4559 | | feature flags. |
4560 | | |
4561 | | \value UsedAsShadingRateMap |
4562 | | */ |
4563 | | |
4564 | | /*! |
4565 | | \enum QRhiTexture::Format |
4566 | | |
4567 | | Specifies the texture format. See also QRhi::isTextureFormatSupported() and |
4568 | | note that flags() can modify the format when QRhiTexture::sRGB is set. |
4569 | | |
4570 | | \value UnknownFormat Not a valid format. This cannot be passed to setFormat(). |
4571 | | |
4572 | | \value RGBA8 Four components, unsigned normalized 8-bit per component. Always supported. (32 bits total) |
4573 | | |
4574 | | \value BGRA8 Four components, unsigned normalized 8-bit per component. (32 bits total) |
4575 | | |
4576 | | \value R8 One component, unsigned normalized 8-bit. (8 bits total) |
4577 | | |
4578 | | \value RG8 Two components, unsigned normalized 8-bit. (16 bits total) |
4579 | | |
4580 | | \value R16 One component, unsigned normalized 16-bit. (16 bits total) |
4581 | | |
4582 | | \value RG16 Two components, unsigned normalized 16-bit. (32 bits total) |
4583 | | |
4584 | | \value RED_OR_ALPHA8 Either same as R8, or is a similar format with the component swizzled to alpha, |
4585 | | depending on \l{QRhi::RedOrAlpha8IsRed}{RedOrAlpha8IsRed}. (8 bits total) |
4586 | | |
4587 | | \value RGBA16F Four components, 16-bit float. (64 bits total) |
4588 | | |
4589 | | \value RGBA32F Four components, 32-bit float. (128 bits total) |
4590 | | |
4591 | | \value R16F One component, 16-bit float. (16 bits total) |
4592 | | |
4593 | | \value R32F One component, 32-bit float. (32 bits total) |
4594 | | |
4595 | | \value RGB10A2 Four components, unsigned normalized 10 bit R, G, and B, |
4596 | | 2-bit alpha. This is a packed format so native endianness applies. Note |
4597 | | that there is no BGR10A2. This is because RGB10A2 maps to |
4598 | | DXGI_FORMAT_R10G10B10A2_UNORM with D3D, MTLPixelFormatRGB10A2Unorm with |
4599 | | Metal, VK_FORMAT_A2B10G10R10_UNORM_PACK32 with Vulkan, and |
4600 | | GL_RGB10_A2/GL_RGB/GL_UNSIGNED_INT_2_10_10_10_REV on OpenGL (ES). This is |
4601 | | the only universally supported RGB30 option. The corresponding QImage |
4602 | | formats are QImage::Format_BGR30 and QImage::Format_A2BGR30_Premultiplied. |
4603 | | (32 bits total) |
4604 | | |
4605 | | \value D16 16-bit depth (normalized unsigned integer) |
4606 | | |
4607 | | \value D24 24-bit depth (normalized unsigned integer) |
4608 | | |
4609 | | \value D24S8 24-bit depth (normalized unsigned integer), 8 bit stencil |
4610 | | |
4611 | | \value D32F 32-bit depth (32-bit float) |
4612 | | |
4613 | | \value [since 6.9] D32FS8 32-bit depth (32-bit float), 8 bits of stencil, 24 bits unused |
4614 | | (64 bits total) |
4615 | | |
4616 | | \value BC1 |
4617 | | \value BC2 |
4618 | | \value BC3 |
4619 | | \value BC4 |
4620 | | \value BC5 |
4621 | | \value BC6H |
4622 | | \value BC7 |
4623 | | |
4624 | | \value ETC2_RGB8 |
4625 | | \value ETC2_RGB8A1 |
4626 | | \value ETC2_RGBA8 |
4627 | | |
4628 | | \value ASTC_4x4 |
4629 | | \value ASTC_5x4 |
4630 | | \value ASTC_5x5 |
4631 | | \value ASTC_6x5 |
4632 | | \value ASTC_6x6 |
4633 | | \value ASTC_8x5 |
4634 | | \value ASTC_8x6 |
4635 | | \value ASTC_8x8 |
4636 | | \value ASTC_10x5 |
4637 | | \value ASTC_10x6 |
4638 | | \value ASTC_10x8 |
4639 | | \value ASTC_10x10 |
4640 | | \value ASTC_12x10 |
4641 | | \value ASTC_12x12 |
4642 | | |
4643 | | \value [since 6.9] R8UI One component, unsigned 8-bit. (8 bits total) |
4644 | | \value [since 6.9] R32UI One component, unsigned 32-bit. (32 bits total) |
4645 | | \value [since 6.9] RG32UI Two components, unsigned 32-bit. (64 bits total) |
4646 | | \value [since 6.9] RGBA32UI Four components, unsigned 32-bit. (128 bits total) |
4647 | | |
4648 | | \value [since 6.10] R8SI One component, signed 8-bit. (8 bits total) |
4649 | | \value [since 6.10] R32SI One component, signed 32-bit. (32 bits total) |
4650 | | \value [since 6.10] RG32SI Two components, signed 32-bit. (64 bits total) |
4651 | | \value [since 6.10] RGBA32SI Four components, signed 32-bit. (128 bits total) |
4652 | | */ |
4653 | | |
4654 | | // When adding new texture formats, update void tst_QRhi::textureFormats_data(). |
4655 | | |
4656 | | /*! |
4657 | | \struct QRhiTexture::NativeTexture |
4658 | | \inmodule QtGuiPrivate |
4659 | | \inheaderfile rhi/qrhi.h |
4660 | | \brief Contains information about the underlying native resources of a texture. |
4661 | | */ |
4662 | | |
4663 | | /*! |
4664 | | \variable QRhiTexture::NativeTexture::object |
4665 | | \brief 64-bit integer containing the native object handle. |
4666 | | |
4667 | | With OpenGL, the native handle is a GLuint value, so \c object can then be |
4668 | | cast to a GLuint. With Vulkan, the native handle is a VkImage, so \c object |
4669 | | can be cast to a VkImage. With Direct3D 11 and Metal \c object contains a |
4670 | | ID3D11Texture2D or MTLTexture pointer, respectively. With Direct3D 12 |
4671 | | \c object contains a ID3D12Resource pointer. |
4672 | | */ |
4673 | | |
4674 | | /*! |
4675 | | \variable QRhiTexture::NativeTexture::layout |
4676 | | \brief Specifies the current image layout for APIs like Vulkan. |
4677 | | |
4678 | | For Vulkan, \c layout contains a \c VkImageLayout value. |
4679 | | */ |
4680 | | |
4681 | | /*! |
4682 | | \internal |
4683 | | */ |
4684 | | QRhiTexture::QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_, int depth_, |
4685 | | int arraySize_, int sampleCount_, Flags flags_) |
4686 | 0 | : QRhiResource(rhi), |
4687 | 0 | m_format(format_), m_pixelSize(pixelSize_), m_depth(depth_), |
4688 | 0 | m_arraySize(arraySize_), m_sampleCount(sampleCount_), m_flags(flags_) |
4689 | 0 | { |
4690 | 0 | } |
4691 | | |
4692 | | /*! |
4693 | | \return the resource type. |
4694 | | */ |
4695 | | QRhiResource::Type QRhiTexture::resourceType() const |
4696 | 0 | { |
4697 | 0 | return Texture; |
4698 | 0 | } |
4699 | | |
4700 | | /*! |
4701 | | \fn virtual bool QRhiTexture::create() = 0 |
4702 | | |
4703 | | Creates the corresponding native graphics resources. If there are already |
4704 | | resources present due to an earlier create() with no corresponding |
4705 | | destroy(), then destroy() is called implicitly first. |
4706 | | |
4707 | | \return \c true when successful, \c false when a graphics operation failed. |
4708 | | Regardless of the return value, calling destroy() is always safe. |
4709 | | */ |
4710 | | |
4711 | | /*! |
4712 | | \return the underlying native resources for this texture. The returned value |
4713 | | will be empty if exposing the underlying native resources is not supported by |
4714 | | the backend. |
4715 | | |
4716 | | \sa createFrom() |
4717 | | */ |
4718 | | QRhiTexture::NativeTexture QRhiTexture::nativeTexture() |
4719 | 0 | { |
4720 | 0 | return {}; |
4721 | 0 | } |
4722 | | |
4723 | | /*! |
4724 | | Similar to create(), except that no new native textures are created. |
4725 | | Instead, the native texture resources specified by \a src is used. |
4726 | | |
4727 | | This allows importing an existing native texture object (which must belong |
4728 | | to the same device or sharing context, depending on the graphics API) from |
4729 | | an external graphics engine. |
4730 | | |
4731 | | \return true if the specified existing native texture object has been |
4732 | | successfully wrapped as a non-owning QRhiTexture. |
4733 | | |
4734 | | \note format(), pixelSize(), sampleCount(), and flags() must still be set |
4735 | | correctly. Passing incorrect sizes and other values to QRhi::newTexture() |
4736 | | and then following it with a createFrom() expecting that the native texture |
4737 | | object alone is sufficient to deduce such values is \b wrong and will lead |
4738 | | to problems. |
4739 | | |
4740 | | \note QRhiTexture does not take ownership of the texture object. destroy() |
4741 | | does not free the object or any associated memory. |
4742 | | |
4743 | | The opposite of this operation, exposing a QRhiTexture-created native |
4744 | | texture object to a foreign engine, is possible via nativeTexture(). |
4745 | | |
4746 | | \note When importing a 3D texture, or a texture array object, or, with |
4747 | | OpenGL ES, an external texture, it is then especially important to set the |
4748 | | corresponding flags (ThreeDimensional, TextureArray, ExternalOES) via |
4749 | | setFlags() before calling this function. |
4750 | | */ |
4751 | | bool QRhiTexture::createFrom(QRhiTexture::NativeTexture src) |
4752 | 0 | { |
4753 | 0 | Q_UNUSED(src); |
4754 | 0 | return false; |
4755 | 0 | } |
4756 | | |
4757 | | /*! |
4758 | | With some graphics APIs, such as Vulkan, integrating custom rendering code |
4759 | | that uses the graphics API directly needs special care when it comes to |
4760 | | image layouts. This function allows communicating the expected \a layout the |
4761 | | image backing the QRhiTexture is in after the native rendering commands. |
4762 | | |
4763 | | For example, consider rendering into a QRhiTexture's VkImage directly with |
4764 | | Vulkan in a code block enclosed by QRhiCommandBuffer::beginExternal() and |
4765 | | QRhiCommandBuffer::endExternal(), followed by using the image for texture |
4766 | | sampling in a QRhi-based render pass. To avoid potentially incorrect image |
4767 | | layout transitions, this function can be used to indicate what the image |
4768 | | layout will be once the commands recorded in said code block complete. |
4769 | | |
4770 | | Calling this function makes sense only after |
4771 | | QRhiCommandBuffer::endExternal() and before a subsequent |
4772 | | QRhiCommandBuffer::beginPass(). |
4773 | | |
4774 | | This function has no effect with QRhi backends where the underlying |
4775 | | graphics API does not expose a concept of image layouts. |
4776 | | |
4777 | | \note With Vulkan \a layout is a \c VkImageLayout. With Direct 3D 12 \a |
4778 | | layout is a value composed of the bits from \c D3D12_RESOURCE_STATES. |
4779 | | */ |
4780 | | void QRhiTexture::setNativeLayout(int layout) |
4781 | 0 | { |
4782 | 0 | Q_UNUSED(layout); |
4783 | 0 | } |
4784 | | |
4785 | | /*! |
4786 | | \fn QRhiTexture::Format QRhiTexture::format() const |
4787 | | \return the texture format. |
4788 | | */ |
4789 | | |
4790 | | /*! |
4791 | | \fn void QRhiTexture::setFormat(QRhiTexture::Format fmt) |
4792 | | |
4793 | | Sets the requested texture format to \a fmt. |
4794 | | |
4795 | | \note The value set is only taken into account upon the next call to |
4796 | | create(), i.e. when the underlying graphics resource are (re)created. |
4797 | | Setting a new value is futile otherwise and must be avoided since it can |
4798 | | lead to inconsistent state. |
4799 | | */ |
4800 | | |
4801 | | /*! |
4802 | | \fn QSize QRhiTexture::pixelSize() const |
4803 | | \return the size in pixels. |
4804 | | */ |
4805 | | |
4806 | | /*! |
4807 | | \fn void QRhiTexture::setPixelSize(const QSize &sz) |
4808 | | |
4809 | | Sets the texture size, specified in pixels, to \a sz. |
4810 | | |
4811 | | \note The value set is only taken into account upon the next call to |
4812 | | create(), i.e. when the underlying graphics resource are (re)created. |
4813 | | Setting a new value is futile otherwise and must be avoided since it can |
4814 | | lead to inconsistent state. The same applies to all other setters as well. |
4815 | | */ |
4816 | | |
4817 | | /*! |
4818 | | \fn int QRhiTexture::depth() const |
4819 | | \return the depth for 3D textures. |
4820 | | */ |
4821 | | |
4822 | | /*! |
4823 | | \fn void QRhiTexture::setDepth(int depth) |
4824 | | Sets the \a depth for a 3D texture. |
4825 | | */ |
4826 | | |
4827 | | /*! |
4828 | | \fn int QRhiTexture::arraySize() const |
4829 | | \return the texture array size. |
4830 | | */ |
4831 | | |
4832 | | /*! |
4833 | | \fn void QRhiTexture::setArraySize(int arraySize) |
4834 | | Sets the texture \a arraySize. |
4835 | | */ |
4836 | | |
4837 | | /*! |
4838 | | \fn int QRhiTexture::arrayRangeStart() const |
4839 | | |
4840 | | \return the first array layer when setArrayRange() was called. |
4841 | | |
4842 | | \sa setArrayRange() |
4843 | | */ |
4844 | | |
4845 | | /*! |
4846 | | \fn int QRhiTexture::arrayRangeLength() const |
4847 | | |
4848 | | \return the exposed array range size when setArrayRange() was called. |
4849 | | |
4850 | | \sa setArrayRange() |
4851 | | */ |
4852 | | |
4853 | | /*! |
4854 | | \fn void QRhiTexture::setArrayRange(int startIndex, int count) |
4855 | | |
4856 | | Normally all array layers are exposed and it is up to the shader to select |
4857 | | the layer via the third coordinate passed to the \c{texture()} GLSL |
4858 | | function when sampling the \c sampler2DArray. When QRhi::TextureArrayRange |
4859 | | is reported as supported, calling setArrayRange() before create() or |
4860 | | createFrom() requests selecting only the specified range, \a count elements |
4861 | | starting from \a startIndex. The shader logic can then be written with this |
4862 | | in mind. |
4863 | | |
4864 | | \sa QRhi::TextureArrayRange |
4865 | | */ |
4866 | | |
4867 | | /*! |
4868 | | \fn Flags QRhiTexture::flags() const |
4869 | | \return the texture flags. |
4870 | | */ |
4871 | | |
4872 | | /*! |
4873 | | \fn void QRhiTexture::setFlags(Flags f) |
4874 | | Sets the texture flags to \a f. |
4875 | | */ |
4876 | | |
4877 | | /*! |
4878 | | \fn int QRhiTexture::sampleCount() const |
4879 | | \return the sample count. 1 means no multisample antialiasing. |
4880 | | */ |
4881 | | |
4882 | | /*! |
4883 | | \fn void QRhiTexture::setSampleCount(int s) |
4884 | | Sets the sample count to \a s. |
4885 | | */ |
4886 | | |
4887 | | /*! |
4888 | | \struct QRhiTexture::ViewFormat |
4889 | | \inmodule QtGuiPrivate |
4890 | | \inheaderfile rhi/qrhi.h |
4891 | | \since 6.8 |
4892 | | \brief Specifies the view format for reading or writing from or to the texture. |
4893 | | |
4894 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
4895 | | for details. |
4896 | | */ |
4897 | | |
4898 | | /*! |
4899 | | \variable QRhiTexture::ViewFormat::format |
4900 | | */ |
4901 | | |
4902 | | /*! |
4903 | | \variable QRhiTexture::ViewFormat::srgb |
4904 | | */ |
4905 | | |
4906 | | /*! |
4907 | | \fn QRhiTexture::ViewFormat QRhiTexture::readViewFormat() const |
4908 | | \since 6.8 |
4909 | | \return the view format used when sampling the texture. When not called, the view |
4910 | | format is assumed to be the same as format(). |
4911 | | */ |
4912 | | |
4913 | | /*! |
4914 | | \fn void QRhiTexture::setReadViewFormat(const ViewFormat &fmt) |
4915 | | \since 6.8 |
4916 | | |
4917 | | Sets the shader resource view format (or the format of the view used for |
4918 | | sampling the texture) to \a fmt. By default the same format (and sRGB-ness) |
4919 | | is used as the texture itself, and in most cases this function does not need |
4920 | | to be called. |
4921 | | |
4922 | | This setting is only taken into account when the \l QRhi::TextureViewFormat |
4923 | | feature is reported as supported. |
4924 | | |
4925 | | \note This functionality is provided to allow "casting" between |
4926 | | non-sRGB and sRGB in order to get the shader reads perform, or not perform, |
4927 | | the implicit sRGB conversions. Other types of casting may or may not be |
4928 | | functional. |
4929 | | */ |
4930 | | |
4931 | | /*! |
4932 | | \fn QRhiTexture::ViewFormat QRhiTexture::writeViewFormat() const |
4933 | | \since 6.8 |
4934 | | \return the view format used when writing to the texture and when using it |
4935 | | with image load/store. When not called, the view format is assumed to be the |
4936 | | same as format(). |
4937 | | */ |
4938 | | |
4939 | | /*! |
4940 | | \fn void QRhiTexture::setWriteViewFormat(const ViewFormat &fmt) |
4941 | | \since 6.8 |
4942 | | |
4943 | | Sets the render target view format to \a fmt. By default the same format |
4944 | | (and sRGB-ness) is used as the texture itself, and in most cases this |
4945 | | function does not need to be called. |
4946 | | |
4947 | | One common use case for providing a write view format is working with |
4948 | | externally provided textures that, outside of our control, use an sRGB |
4949 | | format with 3D APIs such as Vulkan or Direct 3D, but the rendering engine is |
4950 | | already prepared to handle linearization and conversion to sRGB at the end |
4951 | | of its shading pipeline. In this case what is wanted when rendering into |
4952 | | such a texture is a render target view (e.g. VkImageView) that has the same, |
4953 | | but non-sRGB format. (if e.g. from an OpenXR implementation one gets a |
4954 | | VK_FORMAT_R8G8B8A8_SRGB texture, it is likely that rendering into it should |
4955 | | be done using a VK_FORMAT_R8G8B8A8_UNORM view, if that is what the rendering |
4956 | | engine's pipeline requires; in this example one would call this function |
4957 | | with a ViewFormat that has a format of QRhiTexture::RGBA8 and \c srgb set to |
4958 | | \c false). |
4959 | | |
4960 | | This setting is only taken into account when the \l QRhi::TextureViewFormat |
4961 | | feature is reported as supported. |
4962 | | |
4963 | | \note This functionality is provided to allow "casting" between |
4964 | | non-sRGB and sRGB in order to get the shader write not perform, or perform, |
4965 | | the implicit sRGB conversions. Other types of casting may or may not be |
4966 | | functional. |
4967 | | */ |
4968 | | |
4969 | | /*! |
4970 | | \class QRhiSampler |
4971 | | \inmodule QtGuiPrivate |
4972 | | \inheaderfile rhi/qrhi.h |
4973 | | \since 6.6 |
4974 | | \brief Sampler resource. |
4975 | | |
4976 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
4977 | | for details. |
4978 | | */ |
4979 | | |
4980 | | /*! |
4981 | | \enum QRhiSampler::Filter |
4982 | | Specifies the minification, magnification, or mipmap filtering |
4983 | | |
4984 | | \value None Applicable only for mipmapMode(), indicates no mipmaps to be used |
4985 | | \value Nearest |
4986 | | \value Linear |
4987 | | */ |
4988 | | |
4989 | | /*! |
4990 | | \enum QRhiSampler::AddressMode |
4991 | | Specifies the addressing mode |
4992 | | |
4993 | | \value Repeat |
4994 | | \value ClampToEdge |
4995 | | \value Mirror |
4996 | | */ |
4997 | | |
4998 | | /*! |
4999 | | \enum QRhiSampler::CompareOp |
5000 | | Specifies the texture comparison function. |
5001 | | |
5002 | | \value Never (default) |
5003 | | \value Less |
5004 | | \value Equal |
5005 | | \value LessOrEqual |
5006 | | \value Greater |
5007 | | \value NotEqual |
5008 | | \value GreaterOrEqual |
5009 | | \value Always |
5010 | | */ |
5011 | | |
5012 | | /*! |
5013 | | \internal |
5014 | | */ |
5015 | | QRhiSampler::QRhiSampler(QRhiImplementation *rhi, |
5016 | | Filter magFilter_, Filter minFilter_, Filter mipmapMode_, |
5017 | | AddressMode u_, AddressMode v_, AddressMode w_) |
5018 | 0 | : QRhiResource(rhi), |
5019 | 0 | m_magFilter(magFilter_), m_minFilter(minFilter_), m_mipmapMode(mipmapMode_), |
5020 | 0 | m_addressU(u_), m_addressV(v_), m_addressW(w_), |
5021 | 0 | m_compareOp(QRhiSampler::Never) |
5022 | 0 | { |
5023 | 0 | } |
5024 | | |
5025 | | /*! |
5026 | | \return the resource type. |
5027 | | */ |
5028 | | QRhiResource::Type QRhiSampler::resourceType() const |
5029 | 0 | { |
5030 | 0 | return Sampler; |
5031 | 0 | } |
5032 | | |
5033 | | /*! |
5034 | | \fn QRhiSampler::Filter QRhiSampler::magFilter() const |
5035 | | \return the magnification filter mode. |
5036 | | */ |
5037 | | |
5038 | | /*! |
5039 | | \fn void QRhiSampler::setMagFilter(Filter f) |
5040 | | Sets the magnification filter mode to \a f. |
5041 | | */ |
5042 | | |
5043 | | /*! |
5044 | | \fn QRhiSampler::Filter QRhiSampler::minFilter() const |
5045 | | \return the minification filter mode. |
5046 | | */ |
5047 | | |
5048 | | /*! |
5049 | | \fn void QRhiSampler::setMinFilter(Filter f) |
5050 | | Sets the minification filter mode to \a f. |
5051 | | */ |
5052 | | |
5053 | | /*! |
5054 | | \fn QRhiSampler::Filter QRhiSampler::mipmapMode() const |
5055 | | \return the mipmap filter mode. |
5056 | | */ |
5057 | | |
5058 | | /*! |
5059 | | \fn void QRhiSampler::setMipmapMode(Filter f) |
5060 | | |
5061 | | Sets the mipmap filter mode to \a f. |
5062 | | |
5063 | | Leave this set to None when the texture has no mip levels, or when the mip |
5064 | | levels are not to be taken into account. |
5065 | | */ |
5066 | | |
5067 | | /*! |
5068 | | \fn QRhiSampler::AddressMode QRhiSampler::addressU() const |
5069 | | \return the horizontal wrap mode. |
5070 | | */ |
5071 | | |
5072 | | /*! |
5073 | | \fn void QRhiSampler::setAddressU(AddressMode mode) |
5074 | | Sets the horizontal wrap \a mode. |
5075 | | */ |
5076 | | |
5077 | | /*! |
5078 | | \fn QRhiSampler::AddressMode QRhiSampler::addressV() const |
5079 | | \return the vertical wrap mode. |
5080 | | */ |
5081 | | |
5082 | | /*! |
5083 | | \fn void QRhiSampler::setAddressV(AddressMode mode) |
5084 | | Sets the vertical wrap \a mode. |
5085 | | */ |
5086 | | |
5087 | | /*! |
5088 | | \fn QRhiSampler::AddressMode QRhiSampler::addressW() const |
5089 | | \return the depth wrap mode. |
5090 | | */ |
5091 | | |
5092 | | /*! |
5093 | | \fn void QRhiSampler::setAddressW(AddressMode mode) |
5094 | | Sets the depth wrap \a mode. |
5095 | | */ |
5096 | | |
5097 | | /*! |
5098 | | \fn QRhiSampler::CompareOp QRhiSampler::textureCompareOp() const |
5099 | | \return the texture comparison function. |
5100 | | */ |
5101 | | |
5102 | | /*! |
5103 | | \fn void QRhiSampler::setTextureCompareOp(CompareOp op) |
5104 | | Sets the texture comparison function \a op. |
5105 | | */ |
5106 | | |
5107 | | /*! |
5108 | | \class QRhiShadingRateMap |
5109 | | \inmodule QtGuiPrivate |
5110 | | \inheaderfile rhi/qrhi.h |
5111 | | \since 6.9 |
5112 | | \brief An object that wraps a texture or another kind of native 3D API object. |
5113 | | |
5114 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
5115 | | for details. |
5116 | | |
5117 | | For an introduction to Variable Rate Shading (VRS), see |
5118 | | \l{https://learn.microsoft.com/en-us/windows/win32/direct3d12/vrs}. Qt |
5119 | | supports a subset of the VRS features offered by Direct 3D 12 and Vulkan. In |
5120 | | addition, Metal's somewhat different mechanism is supported by making it |
5121 | | possible to set up a QRhiShadingRateMap with an existing |
5122 | | MTLRasterizationRateMap object. |
5123 | | */ |
5124 | | |
5125 | | /*! |
5126 | | \struct QRhiShadingRateMap::NativeShadingRateMap |
5127 | | \inmodule QtGuiPrivate |
5128 | | \inheaderfile rhi/qrhi.h |
5129 | | \since 6.9 |
5130 | | \brief Wraps a native shading rate map. |
5131 | | |
5132 | | An example is MTLRasterizationRateMap with Metal. Other 3D APIs that use |
5133 | | textures for image-based VRS do not use this struct since those can function |
5134 | | via the QRhiTexture-based overload of QRhiShadingRateMap::createFrom(). |
5135 | | */ |
5136 | | |
5137 | | /*! |
5138 | | \variable QRhiShadingRateMap::NativeShadingRateMap::object |
5139 | | \brief 64-bit integer containing the native object handle. |
5140 | | |
5141 | | Used with QRhiShadingRateMap::createFrom(). For example, with Metal, |
5142 | | \c object is expected to be an id<MTLRasterizationRateMap>. |
5143 | | */ |
5144 | | |
5145 | | /*! |
5146 | | \internal |
5147 | | */ |
5148 | | QRhiShadingRateMap::QRhiShadingRateMap(QRhiImplementation *rhi) |
5149 | 0 | : QRhiResource(rhi) |
5150 | 0 | { |
5151 | 0 | } |
5152 | | |
5153 | | /*! |
5154 | | \return the resource type. |
5155 | | */ |
5156 | | QRhiResource::Type QRhiShadingRateMap::resourceType() const |
5157 | 0 | { |
5158 | 0 | return ShadingRateMap; |
5159 | 0 | } |
5160 | | |
5161 | | /*! |
5162 | | Sets up the shading rate map to use a native 3D API shading rate object |
5163 | | \a src. |
5164 | | |
5165 | | \return \c true when successful, \c false when not supported. |
5166 | | |
5167 | | \note This is functional only when the QRhi::VariableRateShadingMap feature |
5168 | | is reported as supported, while QRhi::VariableRateShadingMapWithTexture |
5169 | | feature is not. Currently this is true for Metal, assuming variable rate |
5170 | | shading is supported by the GPU. |
5171 | | |
5172 | | \note With Metal, the \c object field of \a src is expected to contain an |
5173 | | id<MTLRasterizationRateMap>. Note that Qt does not perform anything else |
5174 | | apart from passing the MTLRasterizationRateMap on to the |
5175 | | MTLRenderPassDescriptor. If any special scaling is required, it is up to the |
5176 | | application (or the XR compositor) to perform that. |
5177 | | */ |
5178 | | bool QRhiShadingRateMap::createFrom(NativeShadingRateMap src) |
5179 | 0 | { |
5180 | 0 | Q_UNUSED(src); |
5181 | 0 | return false; |
5182 | 0 | } |
5183 | | |
5184 | | /*! |
5185 | | Sets up the shading rate map to use the texture \a src as the |
5186 | | image containing the per-tile shading rates. |
5187 | | |
5188 | | \return \c true when successful, \c false when not supported. |
5189 | | |
5190 | | The QRhiShadingRateMap does not take ownership of \a src. |
5191 | | |
5192 | | \note This is functional only when the |
5193 | | QRhi::VariableRateShadingMapWithTexture feature is reported as supported. In |
5194 | | practice may be supported on Vulkan and Direct 3D 12 when using modern |
5195 | | graphics cards. It will never be supported on OpenGL or Metal, for example. |
5196 | | |
5197 | | \note \a src must have a format of QRhiTexture::R8UI. |
5198 | | |
5199 | | \note \a src must have a width of \c{ceil(render_target_pixel_width / |
5200 | | (float)tile_width)} and a height of \c{ceil(render_target_pixel_height / |
5201 | | (float)tile_height)}. It is up to the application to ensure the size of the |
5202 | | texture is as expected, using the above formula, at all times. The tile size |
5203 | | can be queried via \l QRhi::resourceLimit() and |
5204 | | QRhi::ShadingRateImageTileSize. |
5205 | | |
5206 | | Each byte (texel) in the texture corresponds to the shading rate value for |
5207 | | one tile. 0 indicates 1x1, while a value of 10 indicates 4x4. See |
5208 | | \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_shading_rate}{D3D12_SHADING_RATE} |
5209 | | for other possible values. |
5210 | | */ |
5211 | | bool QRhiShadingRateMap::createFrom(QRhiTexture *src) |
5212 | 0 | { |
5213 | 0 | Q_UNUSED(src); |
5214 | 0 | return false; |
5215 | 0 | } |
5216 | | |
5217 | | /*! |
5218 | | \class QRhiRenderPassDescriptor |
5219 | | \inmodule QtGuiPrivate |
5220 | | \inheaderfile rhi/qrhi.h |
5221 | | \since 6.6 |
5222 | | \brief Render pass resource. |
5223 | | |
5224 | | A render pass, if such a concept exists in the underlying graphics API, is |
5225 | | a collection of attachments (color, depth, stencil) and describes how those |
5226 | | attachments are used. |
5227 | | |
5228 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
5229 | | for details. |
5230 | | */ |
5231 | | |
5232 | | /*! |
5233 | | \internal |
5234 | | */ |
5235 | | QRhiRenderPassDescriptor::QRhiRenderPassDescriptor(QRhiImplementation *rhi) |
5236 | 0 | : QRhiResource(rhi) |
5237 | 0 | { |
5238 | 0 | } |
5239 | | |
5240 | | /*! |
5241 | | \return the resource type. |
5242 | | */ |
5243 | | QRhiResource::Type QRhiRenderPassDescriptor::resourceType() const |
5244 | 0 | { |
5245 | 0 | return RenderPassDescriptor; |
5246 | 0 | } |
5247 | | |
5248 | | /*! |
5249 | | \fn virtual bool QRhiRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const = 0 |
5250 | | |
5251 | | \return true if the \a other QRhiRenderPassDescriptor is compatible with |
5252 | | this one, meaning \c this and \a other can be used interchangeably in |
5253 | | QRhiGraphicsPipeline::setRenderPassDescriptor(). |
5254 | | |
5255 | | The concept of the compatibility of renderpass descriptors is similar to |
5256 | | the \l{QRhiShaderResourceBindings::isLayoutCompatible}{layout |
5257 | | compatibility} of QRhiShaderResourceBindings instances. They allow better |
5258 | | reuse of QRhiGraphicsPipeline instances: for example, a |
5259 | | QRhiGraphicsPipeline instance cache is expected to use these functions to |
5260 | | look for a matching pipeline, instead of just comparing pointers, thus |
5261 | | allowing a different QRhiRenderPassDescriptor and |
5262 | | QRhiShaderResourceBindings to be used in combination with the pipeline, as |
5263 | | long as they are compatible. |
5264 | | |
5265 | | The exact details of compatibility depend on the underlying graphics API. |
5266 | | Two renderpass descriptors |
5267 | | \l{QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor()}{created} |
5268 | | from the same QRhiTextureRenderTarget are always compatible. |
5269 | | |
5270 | | Similarly to QRhiShaderResourceBindings, compatibility can also be tested |
5271 | | without having two existing objects available. Extracting the opaque blob by |
5272 | | calling serializedFormat() allows testing for compatibility by comparing the |
5273 | | returned vector to another QRhiRenderPassDescriptor's |
5274 | | serializedFormat(). This has benefits in certain situations, because it |
5275 | | allows testing the compatibility of a QRhiRenderPassDescriptor with a |
5276 | | QRhiGraphicsPipeline even when the QRhiRenderPassDescriptor the pipeline was |
5277 | | originally built with is no longer available (but the data returned from its |
5278 | | serializedFormat() still is). |
5279 | | |
5280 | | \sa newCompatibleRenderPassDescriptor(), serializedFormat() |
5281 | | */ |
5282 | | |
5283 | | /*! |
5284 | | \fn virtual QRhiRenderPassDescriptor *QRhiRenderPassDescriptor::newCompatibleRenderPassDescriptor() const = 0 |
5285 | | |
5286 | | \return a new QRhiRenderPassDescriptor that is |
5287 | | \l{isCompatible()}{compatible} with this one. |
5288 | | |
5289 | | This function allows cloning a QRhiRenderPassDescriptor. The returned |
5290 | | object is ready to be used, and the ownership is transferred to the caller. |
5291 | | Cloning a QRhiRenderPassDescriptor object can become useful in situations |
5292 | | where the object is stored in data structures related to graphics pipelines |
5293 | | (in order to allow creating new pipelines which in turn requires a |
5294 | | renderpass descriptor object), and the lifetime of the renderpass |
5295 | | descriptor created from a render target may be shorter than the pipelines. |
5296 | | (for example, because the engine manages and destroys renderpasses together |
5297 | | with the textures and render targets it was created from) In such a |
5298 | | situation, it can be beneficial to store a cloned version in the data |
5299 | | structures, and thus transferring ownership as well. |
5300 | | |
5301 | | \sa isCompatible() |
5302 | | */ |
5303 | | |
5304 | | /*! |
5305 | | \fn virtual QVector<quint32> QRhiRenderPassDescriptor::serializedFormat() const = 0 |
5306 | | |
5307 | | \return a vector of integers containing an opaque blob describing the data |
5308 | | relevant for \l{isCompatible()}{compatibility}. |
5309 | | |
5310 | | Given two QRhiRenderPassDescriptor objects \c rp1 and \c rp2, if the data |
5311 | | returned from this function is identical, then \c{rp1->isCompatible(rp2)}, |
5312 | | and vice versa hold true as well. |
5313 | | |
5314 | | \note The returned data is meant to be used for storing in memory and |
5315 | | comparisons during the lifetime of the QRhi the object belongs to. It is not |
5316 | | meant for storing on disk, reusing between processes, or using with multiple |
5317 | | QRhi instances with potentially different backends. |
5318 | | |
5319 | | \note Calling this function is expected to be a cheap operation since the |
5320 | | backends are not supposed to calculate the data in this function, but rather |
5321 | | return an already calculated series of data. |
5322 | | |
5323 | | When creating reusable components as part of a library, where graphics |
5324 | | pipelines are created and maintained while targeting a QRhiRenderTarget (be |
5325 | | it a swapchain or a texture) managed by the client of the library, the |
5326 | | components must be able to deal with a changing QRhiRenderPassDescriptor. |
5327 | | For example, because the render target changes and so invalidates the |
5328 | | previously QRhiRenderPassDescriptor (with regards to the new render target |
5329 | | at least) due to having a potentially different color format and attachments |
5330 | | now. Or because \l{QRhiShadingRateMap}{variable rate shading} is taken into |
5331 | | use dynamically. A simple pattern that helps dealing with this is performing |
5332 | | the following check on every frame, to recognize the case when the pipeline |
5333 | | needs to be associated with a new QRhiRenderPassDescriptor, because |
5334 | | something is different about the render target now, compared to earlier |
5335 | | frames: |
5336 | | |
5337 | | \code |
5338 | | QRhiRenderPassDescriptor *rp = m_renderTarget->renderPassDescriptor(); |
5339 | | if (m_pipeline && rp->serializedFormat() != m_renderPassFormat) { |
5340 | | m_pipeline->setRenderPassDescriptor(rp); |
5341 | | m_renderPassFormat = rp->serializedFormat(); |
5342 | | m_pipeline->create(); |
5343 | | } |
5344 | | // remember to store m_renderPassFormat also when creating m_pipeline the first time |
5345 | | \endcode |
5346 | | |
5347 | | \sa isCompatible() |
5348 | | */ |
5349 | | |
5350 | | /*! |
5351 | | \return a pointer to a backend-specific QRhiNativeHandles subclass, such as |
5352 | | QRhiVulkanRenderPassNativeHandles. The returned value is \nullptr when exposing |
5353 | | the underlying native resources is not supported by the backend. |
5354 | | |
5355 | | \sa QRhiVulkanRenderPassNativeHandles |
5356 | | */ |
5357 | | const QRhiNativeHandles *QRhiRenderPassDescriptor::nativeHandles() |
5358 | 0 | { |
5359 | 0 | return nullptr; |
5360 | 0 | } |
5361 | | |
5362 | | /*! |
5363 | | \class QRhiRenderTarget |
5364 | | \inmodule QtGuiPrivate |
5365 | | \inheaderfile rhi/qrhi.h |
5366 | | \since 6.6 |
5367 | | \brief Represents an onscreen (swapchain) or offscreen (texture) render target. |
5368 | | |
5369 | | Applications do not create an instance of this class directly. Rather, it |
5370 | | is the subclass QRhiTextureRenderTarget that is instantiable by clients of |
5371 | | the API via \l{QRhi::newTextureRenderTarget()}{newTextureRenderTarget()}. |
5372 | | The other subclass is QRhiSwapChainRenderTarget, which is the type |
5373 | | QRhiSwapChain returns when calling |
5374 | | \l{QRhiSwapChain::currentFrameRenderTarget()}{currentFrameRenderTarget()}. |
5375 | | |
5376 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
5377 | | for details. |
5378 | | |
5379 | | \sa QRhiSwapChainRenderTarget, QRhiTextureRenderTarget |
5380 | | */ |
5381 | | |
5382 | | /*! |
5383 | | \internal |
5384 | | */ |
5385 | | QRhiRenderTarget::QRhiRenderTarget(QRhiImplementation *rhi) |
5386 | 0 | : QRhiResource(rhi) |
5387 | 0 | { |
5388 | 0 | } |
5389 | | |
5390 | | /*! |
5391 | | \fn virtual QSize QRhiRenderTarget::pixelSize() const = 0 |
5392 | | |
5393 | | \return the size in pixels. |
5394 | | |
5395 | | Valid only after create() has been called successfully. Until then the |
5396 | | result is a default-constructed QSize. |
5397 | | |
5398 | | With QRhiTextureRenderTarget the returned size is the size of the |
5399 | | associated attachments at the time of create(), in practice the size of the |
5400 | | first color attachment, or the depth/stencil buffer if there are no color |
5401 | | attachments. If the associated textures or renderbuffers are resized and |
5402 | | rebuilt afterwards, then pixelSize() performs an implicit call to create() |
5403 | | in order to rebuild the underlying data structures. This implicit check is |
5404 | | similar to what QRhiCommandBuffer::beginPass() does, and ensures that the |
5405 | | returned size is always up-to-date. |
5406 | | */ |
5407 | | |
5408 | | /*! |
5409 | | \fn virtual float QRhiRenderTarget::devicePixelRatio() const = 0 |
5410 | | |
5411 | | \return the device pixel ratio. For QRhiTextureRenderTarget this is always |
5412 | | 1. For targets retrieved from a QRhiSwapChain the value reflects the |
5413 | | \l{QWindow::devicePixelRatio()}{device pixel ratio} of the targeted |
5414 | | QWindow. |
5415 | | */ |
5416 | | |
5417 | | /*! |
5418 | | \fn virtual int QRhiRenderTarget::sampleCount() const = 0 |
5419 | | |
5420 | | \return the sample count or 1 if multisample antialiasing is not relevant for |
5421 | | this render target. |
5422 | | */ |
5423 | | |
5424 | | /*! |
5425 | | \fn QRhiRenderPassDescriptor *QRhiRenderTarget::renderPassDescriptor() const |
5426 | | |
5427 | | \return the associated QRhiRenderPassDescriptor. |
5428 | | */ |
5429 | | |
5430 | | /*! |
5431 | | \fn void QRhiRenderTarget::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) |
5432 | | |
5433 | | Sets the QRhiRenderPassDescriptor \a desc for use with this render target. |
5434 | | */ |
5435 | | |
5436 | | /*! |
5437 | | \internal |
5438 | | */ |
5439 | | QRhiSwapChainRenderTarget::QRhiSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain_) |
5440 | 0 | : QRhiRenderTarget(rhi), |
5441 | 0 | m_swapchain(swapchain_) |
5442 | 0 | { |
5443 | 0 | } |
5444 | | |
5445 | | /*! |
5446 | | \class QRhiSwapChainRenderTarget |
5447 | | \inmodule QtGuiPrivate |
5448 | | \inheaderfile rhi/qrhi.h |
5449 | | \since 6.6 |
5450 | | \brief Swapchain render target resource. |
5451 | | |
5452 | | When targeting the color buffers of a swapchain, active render target is a |
5453 | | QRhiSwapChainRenderTarget. This is what |
5454 | | QRhiSwapChain::currentFrameRenderTarget() returns. |
5455 | | |
5456 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
5457 | | for details. |
5458 | | |
5459 | | \sa QRhiSwapChain |
5460 | | */ |
5461 | | |
5462 | | /*! |
5463 | | \return the resource type. |
5464 | | */ |
5465 | | QRhiResource::Type QRhiSwapChainRenderTarget::resourceType() const |
5466 | 0 | { |
5467 | 0 | return SwapChainRenderTarget; |
5468 | 0 | } |
5469 | | |
5470 | | /*! |
5471 | | \fn QRhiSwapChain *QRhiSwapChainRenderTarget::swapChain() const |
5472 | | |
5473 | | \return the swapchain object. |
5474 | | */ |
5475 | | |
5476 | | /*! |
5477 | | \class QRhiTextureRenderTarget |
5478 | | \inmodule QtGuiPrivate |
5479 | | \inheaderfile rhi/qrhi.h |
5480 | | \since 6.6 |
5481 | | \brief Texture render target resource. |
5482 | | |
5483 | | A texture render target allows rendering into one or more textures, |
5484 | | optionally with a depth texture or depth/stencil renderbuffer. |
5485 | | |
5486 | | For multisample rendering the common approach is to use a renderbuffer as |
5487 | | the color attachment and set the non-multisample destination texture as the |
5488 | | \c{resolve texture}. For more information, read the detailed description of |
5489 | | the \l QRhiColorAttachment class. |
5490 | | |
5491 | | \note Textures used in combination with QRhiTextureRenderTarget must be |
5492 | | created with the QRhiTexture::RenderTarget flag. |
5493 | | |
5494 | | The simplest example of creating a render target with a texture as its |
5495 | | single color attachment: |
5496 | | |
5497 | | \code |
5498 | | QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, size, 1, QRhiTexture::RenderTarget); |
5499 | | texture->create(); |
5500 | | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ texture }); |
5501 | | rp = rt->newCompatibleRenderPassDescriptor(); |
5502 | | rt->setRenderPassDescriptor(rp); |
5503 | | rt->create(); |
5504 | | // rt can now be used with beginPass() |
5505 | | \endcode |
5506 | | |
5507 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
5508 | | for details. |
5509 | | */ |
5510 | | |
5511 | | /*! |
5512 | | \enum QRhiTextureRenderTarget::Flag |
5513 | | |
5514 | | Flag values describing the load/store behavior for the render target. The |
5515 | | load/store behavior may be baked into native resources under the hood, |
5516 | | depending on the backend, and therefore it needs to be known upfront and |
5517 | | cannot be changed without rebuilding (and so releasing and creating new |
5518 | | native resources). |
5519 | | |
5520 | | \value PreserveColorContents Indicates that the contents of the color |
5521 | | attachments is to be loaded when starting a render pass, instead of |
5522 | | clearing. This is potentially more expensive, especially on mobile (tiled) |
5523 | | GPUs, but allows preserving the existing contents between passes. When doing |
5524 | | multisample rendering with a resolve texture set, setting this flag also |
5525 | | requests the multisample color data to be stored (written out) to the |
5526 | | multisample texture or render buffer. (for non-multisample rendering the |
5527 | | color data is always stored, but for MSAA storing the multisample data |
5528 | | decreases efficiency for certain GPU architectures, hence defaulting to not |
5529 | | writing it out) Note however that this is non-portable: in some cases there |
5530 | | is no intermediate multisample texture on the graphics API level, e.g. when |
5531 | | using OpenGL ES's \c{GL_EXT_multisampled_render_to_texture} as it is all |
5532 | | implicit, handled by the OpenGL ES implementation. In that case, |
5533 | | PreserveColorContents will likely have no effect. Therefore, avoid relying |
5534 | | on this flag when using multisample rendering and the color attachment is |
5535 | | using a multisample QRhiTexture (not QRhiRenderBuffer). |
5536 | | |
5537 | | \value PreserveDepthStencilContents Indicates that the contents of the |
5538 | | depth texture is to be loaded when starting a render pass, instead |
5539 | | clearing. Only applicable when a texture is used as the depth buffer |
5540 | | (QRhiTextureRenderTargetDescription::depthTexture() is set) because |
5541 | | depth/stencil renderbuffers may not have any physical backing and data may |
5542 | | not be written out in the first place. |
5543 | | |
5544 | | \value DoNotStoreDepthStencilContents Indicates that the contents of the |
5545 | | depth texture does not need to be written out. Relevant only when a |
5546 | | QRhiTexture, not QRhiRenderBuffer, is used as the depth-stencil buffer, |
5547 | | because for QRhiRenderBuffer this is implicit. When a depthResolveTexture is |
5548 | | set, the flag is not relevant, because the behavior is then as if the flag |
5549 | | was set. This enum value is introduced in Qt 6.8. |
5550 | | */ |
5551 | | |
5552 | | /*! |
5553 | | \internal |
5554 | | */ |
5555 | | QRhiTextureRenderTarget::QRhiTextureRenderTarget(QRhiImplementation *rhi, |
5556 | | const QRhiTextureRenderTargetDescription &desc_, |
5557 | | Flags flags_) |
5558 | 0 | : QRhiRenderTarget(rhi), |
5559 | 0 | m_desc(desc_), |
5560 | 0 | m_flags(flags_) |
5561 | 0 | { |
5562 | 0 | } |
5563 | | |
5564 | | /*! |
5565 | | \return the resource type. |
5566 | | */ |
5567 | | QRhiResource::Type QRhiTextureRenderTarget::resourceType() const |
5568 | 0 | { |
5569 | 0 | return TextureRenderTarget; |
5570 | 0 | } |
5571 | | |
5572 | | /*! |
5573 | | \fn virtual QRhiRenderPassDescriptor *QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor() = 0 |
5574 | | |
5575 | | \return a new QRhiRenderPassDescriptor that is compatible with this render |
5576 | | target. |
5577 | | |
5578 | | The returned value is used in two ways: it can be passed to |
5579 | | setRenderPassDescriptor() and |
5580 | | QRhiGraphicsPipeline::setRenderPassDescriptor(). A render pass descriptor |
5581 | | describes the attachments (color, depth/stencil) and the load/store |
5582 | | behavior that can be affected by flags(). A QRhiGraphicsPipeline can only |
5583 | | be used in combination with a render target that has a |
5584 | | \l{QRhiRenderPassDescriptor::isCompatible()}{compatible} |
5585 | | QRhiRenderPassDescriptor set. |
5586 | | |
5587 | | Two QRhiTextureRenderTarget instances can share the same render pass |
5588 | | descriptor as long as they have the same number and type of attachments. |
5589 | | The associated QRhiTexture or QRhiRenderBuffer instances are not part of |
5590 | | the render pass descriptor so those can differ in the two |
5591 | | QRhiTextureRenderTarget instances. |
5592 | | |
5593 | | \note resources, such as QRhiTexture instances, referenced in description() |
5594 | | must already have create() called on them. |
5595 | | |
5596 | | \sa create() |
5597 | | */ |
5598 | | |
5599 | | /*! |
5600 | | \fn virtual bool QRhiTextureRenderTarget::create() = 0 |
5601 | | |
5602 | | Creates the corresponding native graphics resources. If there are already |
5603 | | resources present due to an earlier create() with no corresponding |
5604 | | destroy(), then destroy() is called implicitly first. |
5605 | | |
5606 | | \note renderPassDescriptor() must be set before calling create(). To obtain |
5607 | | a QRhiRenderPassDescriptor compatible with the render target, call |
5608 | | newCompatibleRenderPassDescriptor() before create() but after setting all |
5609 | | other parameters, such as description() and flags(). To save resources, |
5610 | | reuse the same QRhiRenderPassDescriptor with multiple |
5611 | | QRhiTextureRenderTarget instances, whenever possible. Sharing the same |
5612 | | render pass descriptor is only possible when the render targets have the |
5613 | | same number and type of attachments (the actual textures can differ) and |
5614 | | the same flags. |
5615 | | |
5616 | | \note resources, such as QRhiTexture instances, referenced in description() |
5617 | | must already have create() called on them. |
5618 | | |
5619 | | \return \c true when successful, \c false when a graphics operation failed. |
5620 | | Regardless of the return value, calling destroy() is always safe. |
5621 | | */ |
5622 | | |
5623 | | /*! |
5624 | | \fn QRhiTextureRenderTargetDescription QRhiTextureRenderTarget::description() const |
5625 | | \return the render target description. |
5626 | | */ |
5627 | | |
5628 | | /*! |
5629 | | \fn void QRhiTextureRenderTarget::setDescription(const QRhiTextureRenderTargetDescription &desc) |
5630 | | Sets the render target description \a desc. |
5631 | | */ |
5632 | | |
5633 | | /*! |
5634 | | \fn QRhiTextureRenderTarget::Flags QRhiTextureRenderTarget::flags() const |
5635 | | \return the currently set flags. |
5636 | | */ |
5637 | | |
5638 | | /*! |
5639 | | \fn void QRhiTextureRenderTarget::setFlags(Flags f) |
5640 | | Sets the flags to \a f. |
5641 | | */ |
5642 | | |
5643 | | /*! |
5644 | | \class QRhiShaderResourceBindings |
5645 | | \inmodule QtGuiPrivate |
5646 | | \inheaderfile rhi/qrhi.h |
5647 | | \since 6.6 |
5648 | | \brief Encapsulates resources for making buffer, texture, sampler resources visible to shaders. |
5649 | | |
5650 | | A QRhiShaderResourceBindings is a collection of QRhiShaderResourceBinding |
5651 | | objects, each of which describe a single binding. |
5652 | | |
5653 | | Take a fragment shader with the following interface: |
5654 | | |
5655 | | \badcode |
5656 | | layout(std140, binding = 0) uniform buf { |
5657 | | mat4 mvp; |
5658 | | int flip; |
5659 | | } ubuf; |
5660 | | |
5661 | | layout(binding = 1) uniform sampler2D tex; |
5662 | | \endcode |
5663 | | |
5664 | | To make resources visible to the shader, the following |
5665 | | QRhiShaderResourceBindings could be created and then passed to |
5666 | | QRhiGraphicsPipeline::setShaderResourceBindings(): |
5667 | | |
5668 | | \code |
5669 | | QRhiShaderResourceBindings *srb = rhi->newShaderResourceBindings(); |
5670 | | srb->setBindings({ |
5671 | | QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, ubuf), |
5672 | | QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, sampler) |
5673 | | }); |
5674 | | srb->create(); |
5675 | | // ... |
5676 | | QRhiGraphicsPipeline *ps = rhi->newGraphicsPipeline(); |
5677 | | // ... |
5678 | | ps->setShaderResourceBindings(srb); |
5679 | | ps->create(); |
5680 | | // ... |
5681 | | cb->setGraphicsPipeline(ps); |
5682 | | cb->setShaderResources(); // binds srb |
5683 | | \endcode |
5684 | | |
5685 | | This assumes that \c ubuf is a QRhiBuffer, \c texture is a QRhiTexture, |
5686 | | while \a sampler is a QRhiSampler. The example also assumes that the |
5687 | | uniform block is present in the vertex shader as well so the same buffer is |
5688 | | made visible to the vertex stage too. |
5689 | | |
5690 | | \section3 Advanced usage |
5691 | | |
5692 | | Building on the above example, let's assume that a pass now needs to use |
5693 | | the exact same pipeline and shaders with a different texture. Creating a |
5694 | | whole separate QRhiGraphicsPipeline just for this would be an overkill. |
5695 | | This is why QRhiCommandBuffer::setShaderResources() allows specifying a \a |
5696 | | srb argument. As long as the layouts (so the number of bindings and the |
5697 | | binding points) match between two QRhiShaderResourceBindings, they can both |
5698 | | be used with the same pipeline, assuming the pipeline was created with one of |
5699 | | them in the first place. See isLayoutCompatible() for more details. |
5700 | | |
5701 | | \code |
5702 | | QRhiShaderResourceBindings *srb2 = rhi->newShaderResourceBindings(); |
5703 | | // ... |
5704 | | cb->setGraphicsPipeline(ps); |
5705 | | cb->setShaderResources(srb2); // binds srb2 |
5706 | | \endcode |
5707 | | |
5708 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
5709 | | for details. |
5710 | | */ |
5711 | | |
5712 | | /*! |
5713 | | \typedef QRhiShaderResourceBindingSet |
5714 | | \relates QRhi |
5715 | | \since 6.7 |
5716 | | |
5717 | | Synonym for QRhiShaderResourceBindings. |
5718 | | */ |
5719 | | |
5720 | | /*! |
5721 | | \internal |
5722 | | */ |
5723 | | QRhiShaderResourceBindings::QRhiShaderResourceBindings(QRhiImplementation *rhi) |
5724 | 0 | : QRhiResource(rhi) |
5725 | 0 | { |
5726 | 0 | m_layoutDesc.reserve(BINDING_PREALLOC * QRhiShaderResourceBinding::LAYOUT_DESC_ENTRIES_PER_BINDING); |
5727 | 0 | } |
5728 | | |
5729 | | /*! |
5730 | | \return the resource type. |
5731 | | */ |
5732 | | QRhiResource::Type QRhiShaderResourceBindings::resourceType() const |
5733 | 0 | { |
5734 | 0 | return ShaderResourceBindings; |
5735 | 0 | } |
5736 | | |
5737 | | /*! |
5738 | | \return \c true if the layout is compatible with \a other. The layout does |
5739 | | not include the actual resource (such as, buffer or texture) and related |
5740 | | parameters (such as, offset or size). It does include the binding point, |
5741 | | pipeline stage, and resource type, however. The number and order of the |
5742 | | bindings must also match in order to be compatible. |
5743 | | |
5744 | | When there is a QRhiGraphicsPipeline created with this |
5745 | | QRhiShaderResourceBindings, and the function returns \c true, \a other can |
5746 | | then safely be passed to QRhiCommandBuffer::setShaderResources(), and so |
5747 | | be used with the pipeline in place of this QRhiShaderResourceBindings. |
5748 | | |
5749 | | \note This function must only be called after a successful create(), because |
5750 | | it relies on data generated during the baking of the underlying data |
5751 | | structures. This way the function can implement a comparison approach that |
5752 | | is more efficient than iterating through two binding lists and calling |
5753 | | QRhiShaderResourceBinding::isLayoutCompatible() on each pair. This becomes |
5754 | | relevant especially when this function is called at a high frequency. |
5755 | | |
5756 | | \sa serializedLayoutDescription() |
5757 | | */ |
5758 | | bool QRhiShaderResourceBindings::isLayoutCompatible(const QRhiShaderResourceBindings *other) const |
5759 | 0 | { |
5760 | 0 | if (other == this) |
5761 | 0 | return true; |
5762 | | |
5763 | 0 | if (!other) |
5764 | 0 | return false; |
5765 | | |
5766 | | // This can become a hot code path. Therefore we do not iterate and call |
5767 | | // isLayoutCompatible() on m_bindings, but rather check a pre-calculated |
5768 | | // hash code and then, if the hash matched, do a uint array comparison |
5769 | | // (that's still more cache friendly). |
5770 | | |
5771 | 0 | return m_layoutDescHash == other->m_layoutDescHash |
5772 | 0 | && m_layoutDesc == other->m_layoutDesc; |
5773 | 0 | } |
5774 | | |
5775 | | /*! |
5776 | | \fn QVector<quint32> QRhiShaderResourceBindings::serializedLayoutDescription() const |
5777 | | |
5778 | | \return a vector of integers containing an opaque blob describing the layout |
5779 | | of the binding list, i.e. the data relevant for |
5780 | | \l{isLayoutCompatible()}{layout compatibility tests}. |
5781 | | |
5782 | | Given two objects \c srb1 and \c srb2, if the data returned from this |
5783 | | function is identical, then \c{srb1->isLayoutCompatible(srb2)}, and vice |
5784 | | versa hold true as well. |
5785 | | |
5786 | | \note The returned data is meant to be used for storing in memory and |
5787 | | comparisons during the lifetime of the QRhi the object belongs to. It is not |
5788 | | meant for storing on disk, reusing between processes, or using with multiple |
5789 | | QRhi instances with potentially different backends. |
5790 | | |
5791 | | \sa isLayoutCompatible() |
5792 | | */ |
5793 | | |
5794 | | void QRhiImplementation::updateLayoutDesc(QRhiShaderResourceBindings *srb) |
5795 | 0 | { |
5796 | 0 | srb->m_layoutDescHash = 0; |
5797 | 0 | srb->m_layoutDesc.clear(); |
5798 | 0 | auto layoutDescAppender = std::back_inserter(srb->m_layoutDesc); |
5799 | 0 | for (const QRhiShaderResourceBinding &b : std::as_const(srb->m_bindings)) { |
5800 | 0 | const QRhiShaderResourceBinding::Data *d = &b.d; |
5801 | 0 | srb->m_layoutDescHash ^= uint(d->binding) ^ uint(d->stage) ^ uint(d->type) |
5802 | 0 | ^ uint(d->arraySize()); |
5803 | 0 | layoutDescAppender = d->serialize(layoutDescAppender); |
5804 | 0 | } |
5805 | 0 | } |
5806 | | |
5807 | | /*! |
5808 | | \fn virtual bool QRhiShaderResourceBindings::create() = 0 |
5809 | | |
5810 | | Creates the corresponding resource binding set. Depending on the underlying |
5811 | | graphics API, this may involve creating native graphics resources, and |
5812 | | therefore it should not be assumed that this is a cheap operation. |
5813 | | |
5814 | | If create() has been called before with no corresponding destroy(), then |
5815 | | destroy() is called implicitly first. |
5816 | | |
5817 | | \return \c true when successful, \c false when failed. |
5818 | | Regardless of the return value, calling destroy() is always safe. |
5819 | | */ |
5820 | | |
5821 | | /*! |
5822 | | \fn void QRhiShaderResourceBindings::setBindings(std::initializer_list<QRhiShaderResourceBinding> list) |
5823 | | Sets the \a list of bindings. |
5824 | | */ |
5825 | | |
5826 | | /*! |
5827 | | \fn template<typename InputIterator> void QRhiShaderResourceBindings::setBindings(InputIterator first, InputIterator last) |
5828 | | Sets the list of bindings from the iterators \a first and \a last. |
5829 | | */ |
5830 | | |
5831 | | /*! |
5832 | | \fn const QRhiShaderResourceBinding *QRhiShaderResourceBindings::cbeginBindings() const |
5833 | | \return a const iterator pointing to the first item in the binding list. |
5834 | | */ |
5835 | | |
5836 | | /*! |
5837 | | \fn const QRhiShaderResourceBinding *QRhiShaderResourceBindings::cendBindings() const |
5838 | | \return a const iterator pointing just after the last item in the binding list. |
5839 | | */ |
5840 | | |
5841 | | /*! |
5842 | | \fn const QRhiShaderResourceBinding *QRhiShaderResourceBindings::bindingAt(qsizetype index) const |
5843 | | \return the binding at the specified \a index. |
5844 | | */ |
5845 | | |
5846 | | /*! |
5847 | | \fn qsizetype QRhiShaderResourceBindings::bindingCount() const |
5848 | | \return the number of bindings. |
5849 | | */ |
5850 | | |
5851 | | /*! |
5852 | | \class QRhiShaderResourceBinding |
5853 | | \inmodule QtGuiPrivate |
5854 | | \inheaderfile rhi/qrhi.h |
5855 | | \since 6.6 |
5856 | | \brief Describes the shader resource for a single binding point. |
5857 | | |
5858 | | A QRhiShaderResourceBinding cannot be constructed directly. Instead, use the |
5859 | | static functions such as uniformBuffer() or sampledTexture() to get an |
5860 | | instance. |
5861 | | |
5862 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
5863 | | for details. |
5864 | | */ |
5865 | | |
5866 | | /*! |
5867 | | \enum QRhiShaderResourceBinding::Type |
5868 | | Specifies type of the shader resource bound to a binding point |
5869 | | |
5870 | | \value UniformBuffer Uniform buffer |
5871 | | |
5872 | | \value SampledTexture Combined image sampler (a texture and sampler pair). |
5873 | | Even when the shading language associated with the underlying 3D API has no |
5874 | | support for this concept (e.g. D3D and HLSL), this is still supported |
5875 | | because the shader translation layer takes care of the appropriate |
5876 | | translation and remapping of binding points or shader registers. |
5877 | | |
5878 | | \value Texture Texture (separate) |
5879 | | |
5880 | | \value Sampler Sampler (separate) |
5881 | | |
5882 | | \value ImageLoad Image load (with GLSL this maps to doing imageLoad() on a |
5883 | | single level - and either one or all layers - of a texture exposed to the |
5884 | | shader as an image object) |
5885 | | |
5886 | | \value ImageStore Image store (with GLSL this maps to doing imageStore() or |
5887 | | imageAtomic*() on a single level - and either one or all layers - of a |
5888 | | texture exposed to the shader as an image object) |
5889 | | |
5890 | | \value ImageLoadStore Image load and store |
5891 | | |
5892 | | \value BufferLoad Storage buffer load (with GLSL this maps to reading from |
5893 | | a shader storage buffer) |
5894 | | |
5895 | | \value BufferStore Storage buffer store (with GLSL this maps to writing to |
5896 | | a shader storage buffer) |
5897 | | |
5898 | | \value BufferLoadStore Storage buffer load and store |
5899 | | */ |
5900 | | |
5901 | | /*! |
5902 | | \enum QRhiShaderResourceBinding::StageFlag |
5903 | | Flag values to indicate which stages the shader resource is visible in |
5904 | | |
5905 | | \value VertexStage Vertex stage |
5906 | | \value TessellationControlStage Tessellation control (hull shader) stage |
5907 | | \value TessellationEvaluationStage Tessellation evaluation (domain shader) stage |
5908 | | \value FragmentStage Fragment (pixel shader) stage |
5909 | | \value ComputeStage Compute stage |
5910 | | \value GeometryStage Geometry stage |
5911 | | */ |
5912 | | |
5913 | | /*! |
5914 | | \return \c true if the layout is compatible with \a other. The layout does not |
5915 | | include the actual resource (such as, buffer or texture) and related |
5916 | | parameters (such as, offset or size). |
5917 | | |
5918 | | For example, \c a and \c b below are not equal, but are compatible layout-wise: |
5919 | | |
5920 | | \code |
5921 | | auto a = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, buffer); |
5922 | | auto b = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, someOtherBuffer, 256); |
5923 | | \endcode |
5924 | | */ |
5925 | | bool QRhiShaderResourceBinding::isLayoutCompatible(const QRhiShaderResourceBinding &other) const |
5926 | 0 | { |
5927 | | // everything that goes into a VkDescriptorSetLayoutBinding must match |
5928 | 0 | return d.binding == other.d.binding |
5929 | 0 | && d.stage == other.d.stage |
5930 | 0 | && d.type == other.d.type |
5931 | 0 | && d.arraySize() == other.d.arraySize(); |
5932 | 0 | } |
5933 | | |
5934 | | /*! |
5935 | | \return a shader resource binding for the given binding number, pipeline |
5936 | | stages, and buffer specified by \a binding, \a stage, and \a buf. |
5937 | | |
5938 | | \note When \a buf is not null, it must have been created with |
5939 | | QRhiBuffer::UniformBuffer. |
5940 | | |
5941 | | \note \a buf can be null. It is valid to create a |
5942 | | QRhiShaderResourceBindings with unspecified resources, but such an object |
5943 | | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
5944 | | suitable for creating pipelines. Such a pipeline must then always be used |
5945 | | together with another, layout compatible QRhiShaderResourceBindings with |
5946 | | resources present passed to QRhiCommandBuffer::setShaderResources(). |
5947 | | |
5948 | | \note If the size of \a buf exceeds the limit reported for |
5949 | | QRhi::MaxUniformBufferRange, unexpected errors may occur. |
5950 | | */ |
5951 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer( |
5952 | | int binding, StageFlags stage, QRhiBuffer *buf) |
5953 | 0 | { |
5954 | 0 | QRhiShaderResourceBinding b; |
5955 | 0 | b.d.binding = binding; |
5956 | 0 | b.d.stage = stage; |
5957 | 0 | b.d.type = UniformBuffer; |
5958 | 0 | b.d.u.ubuf.buf = buf; |
5959 | 0 | b.d.u.ubuf.offset = 0; |
5960 | 0 | b.d.u.ubuf.maybeSize = 0; // entire buffer |
5961 | 0 | b.d.u.ubuf.hasDynamicOffset = false; |
5962 | 0 | return b; |
5963 | 0 | } |
5964 | | |
5965 | | /*! |
5966 | | \return a shader resource binding for the given binding number, pipeline |
5967 | | stages, and buffer specified by \a binding, \a stage, and \a buf. This |
5968 | | overload binds a region only, as specified by \a offset and \a size. |
5969 | | |
5970 | | \note It is up to the user to ensure the offset is aligned to |
5971 | | QRhi::ubufAlignment(). |
5972 | | |
5973 | | \note \a size must be greater than 0. |
5974 | | |
5975 | | \note When \a buf is not null, it must have been created with |
5976 | | QRhiBuffer::UniformBuffer. |
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 If \a size exceeds the limit reported for QRhi::MaxUniformBufferRange, |
5986 | | unexpected errors may occur. |
5987 | | */ |
5988 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer( |
5989 | | int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size) |
5990 | 0 | { |
5991 | 0 | Q_ASSERT(size > 0); |
5992 | 0 | QRhiShaderResourceBinding b; |
5993 | 0 | b.d.binding = binding; |
5994 | 0 | b.d.stage = stage; |
5995 | 0 | b.d.type = UniformBuffer; |
5996 | 0 | b.d.u.ubuf.buf = buf; |
5997 | 0 | b.d.u.ubuf.offset = offset; |
5998 | 0 | b.d.u.ubuf.maybeSize = size; |
5999 | 0 | b.d.u.ubuf.hasDynamicOffset = false; |
6000 | 0 | return b; |
6001 | 0 | } |
6002 | | |
6003 | | /*! |
6004 | | \return a shader resource binding for the given binding number, pipeline |
6005 | | stages, and buffer specified by \a binding, \a stage, and \a buf. The |
6006 | | uniform buffer is assumed to have dynamic offset. The dynamic offset can be |
6007 | | specified in QRhiCommandBuffer::setShaderResources(), thus allowing using |
6008 | | varying offset values without creating new bindings for the buffer. The |
6009 | | size of the bound region is specified by \a size. Like with non-dynamic |
6010 | | offsets, \c{offset + size} cannot exceed the size of \a buf. |
6011 | | |
6012 | | \note When \a buf is not null, it must have been created with |
6013 | | QRhiBuffer::UniformBuffer. |
6014 | | |
6015 | | \note \a buf can be null. It is valid to create a |
6016 | | QRhiShaderResourceBindings with unspecified resources, but such an object |
6017 | | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6018 | | suitable for creating pipelines. Such a pipeline must then always be used |
6019 | | together with another, layout compatible QRhiShaderResourceBindings with |
6020 | | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6021 | | |
6022 | | \note If \a size exceeds the limit reported for QRhi::MaxUniformBufferRange, |
6023 | | unexpected errors may occur. |
6024 | | */ |
6025 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBufferWithDynamicOffset( |
6026 | | int binding, StageFlags stage, QRhiBuffer *buf, quint32 size) |
6027 | 0 | { |
6028 | 0 | Q_ASSERT(size > 0); |
6029 | 0 | QRhiShaderResourceBinding b; |
6030 | 0 | b.d.binding = binding; |
6031 | 0 | b.d.stage = stage; |
6032 | 0 | b.d.type = UniformBuffer; |
6033 | 0 | b.d.u.ubuf.buf = buf; |
6034 | 0 | b.d.u.ubuf.offset = 0; |
6035 | 0 | b.d.u.ubuf.maybeSize = size; |
6036 | 0 | b.d.u.ubuf.hasDynamicOffset = true; |
6037 | 0 | return b; |
6038 | 0 | } |
6039 | | |
6040 | | /*! |
6041 | | \return a shader resource binding for the given binding number, pipeline |
6042 | | stages, texture, and sampler specified by \a binding, \a stage, \a tex, |
6043 | | \a sampler. |
6044 | | |
6045 | | \note This function is equivalent to calling sampledTextures() with a |
6046 | | \c count of 1. |
6047 | | |
6048 | | \note \a tex and \a sampler 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 A shader may not be able to consume more than 16 textures/samplers, |
6056 | | depending on the underlying graphics API. This hard limit must be kept in |
6057 | | mind in renderer design. This does not apply to texture arrays which |
6058 | | consume a single binding point (shader register) and can contain 256-2048 |
6059 | | textures, depending on the underlying graphics API. Arrays of textures (see |
6060 | | sampledTextures()) are however no different in this regard than using the |
6061 | | same number of individual textures. |
6062 | | |
6063 | | \sa sampledTextures() |
6064 | | */ |
6065 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture( |
6066 | | int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler) |
6067 | 0 | { |
6068 | 0 | QRhiShaderResourceBinding b; |
6069 | 0 | b.d.binding = binding; |
6070 | 0 | b.d.stage = stage; |
6071 | 0 | b.d.type = SampledTexture; |
6072 | 0 | b.d.u.stex.count = 1; |
6073 | 0 | b.d.u.stex.texSamplers[0] = { tex, sampler }; |
6074 | 0 | return b; |
6075 | 0 | } |
6076 | | |
6077 | | /*! |
6078 | | \return a shader resource binding for the given binding number, pipeline |
6079 | | stages, and the array of texture-sampler pairs specified by \a binding, \a |
6080 | | stage, \a count, and \a texSamplers. |
6081 | | |
6082 | | \note \a count must be at least 1, and not larger than 16. |
6083 | | |
6084 | | \note When \a count is 1, this function is equivalent to sampledTexture(). |
6085 | | |
6086 | | This function is relevant when arrays of combined image samplers are |
6087 | | involved. For example, in GLSL \c{layout(binding = 5) uniform sampler2D |
6088 | | shadowMaps[8];} declares an array of combined image samplers. The |
6089 | | application is then expected provide a QRhiShaderResourceBinding for |
6090 | | binding point 5, set up by calling this function with \a count set to 8 and |
6091 | | a valid texture and sampler for each element of the array. |
6092 | | |
6093 | | \warning All elements of the array must be specified. With the above |
6094 | | example, the only valid, portable approach is calling this function with a |
6095 | | \a count of 8. Additionally, all QRhiTexture and QRhiSampler instances must |
6096 | | be valid, meaning nullptr is not an accepted value. This is due to some of |
6097 | | the underlying APIs, such as, Vulkan, that require a valid image and |
6098 | | sampler object for each element in descriptor arrays. Applications are |
6099 | | advised to provide "dummy" samplers and textures if some array elements are |
6100 | | not relevant (due to not being accessed in the shader). |
6101 | | |
6102 | | \note \a texSamplers can be null. It is valid to create a |
6103 | | QRhiShaderResourceBindings with unspecified resources, but such an object |
6104 | | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6105 | | suitable for creating pipelines. Such a pipeline must then always be used |
6106 | | together with another, layout compatible QRhiShaderResourceBindings with |
6107 | | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6108 | | |
6109 | | \sa sampledTexture() |
6110 | | */ |
6111 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTextures( |
6112 | | int binding, StageFlags stage, int count, const TextureAndSampler *texSamplers) |
6113 | 0 | { |
6114 | 0 | Q_ASSERT(count >= 1 && count <= Data::MAX_TEX_SAMPLER_ARRAY_SIZE); |
6115 | 0 | QRhiShaderResourceBinding b; |
6116 | 0 | b.d.binding = binding; |
6117 | 0 | b.d.stage = stage; |
6118 | 0 | b.d.type = SampledTexture; |
6119 | 0 | b.d.u.stex.count = count; |
6120 | 0 | for (int i = 0; i < count; ++i) { |
6121 | 0 | if (texSamplers) |
6122 | 0 | b.d.u.stex.texSamplers[i] = texSamplers[i]; |
6123 | 0 | else |
6124 | 0 | b.d.u.stex.texSamplers[i] = { nullptr, nullptr }; |
6125 | 0 | } |
6126 | 0 | return b; |
6127 | 0 | } |
6128 | | |
6129 | | /*! |
6130 | | \return a shader resource binding for the given binding number, pipeline |
6131 | | stages, and texture specified by \a binding, \a stage, \a tex. |
6132 | | |
6133 | | \note This function is equivalent to calling textures() with a |
6134 | | \c count of 1. |
6135 | | |
6136 | | \note \a tex can be null. It is valid to create a |
6137 | | QRhiShaderResourceBindings with unspecified resources, but such an object |
6138 | | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6139 | | suitable for creating pipelines. Such a pipeline must then always be used |
6140 | | together with another, layout compatible QRhiShaderResourceBindings with |
6141 | | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6142 | | |
6143 | | This creates a binding for a separate texture (image) object, whereas |
6144 | | sampledTexture() is suitable for combined image samplers. In |
6145 | | Vulkan-compatible GLSL code separate textures are declared as \c texture2D |
6146 | | as opposed to \c sampler2D: \c{layout(binding = 1) uniform texture2D tex;} |
6147 | | |
6148 | | \note A shader may not be able to consume more than 16 textures, depending |
6149 | | on the underlying graphics API. This hard limit must be kept in mind in |
6150 | | renderer design. This does not apply to texture arrays which consume a |
6151 | | single binding point (shader register) and can contain 256-2048 textures, |
6152 | | depending on the underlying graphics API. Arrays of textures (see |
6153 | | sampledTextures()) are however no different in this regard than using the |
6154 | | same number of individual textures. |
6155 | | |
6156 | | \sa textures(), sampler() |
6157 | | */ |
6158 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::texture(int binding, StageFlags stage, QRhiTexture *tex) |
6159 | 0 | { |
6160 | 0 | QRhiShaderResourceBinding b; |
6161 | 0 | b.d.binding = binding; |
6162 | 0 | b.d.stage = stage; |
6163 | 0 | b.d.type = Texture; |
6164 | 0 | b.d.u.stex.count = 1; |
6165 | 0 | b.d.u.stex.texSamplers[0] = { tex, nullptr }; |
6166 | 0 | return b; |
6167 | 0 | } |
6168 | | |
6169 | | /*! |
6170 | | \return a shader resource binding for the given binding number, pipeline |
6171 | | stages, and the array of (separate) textures specified by \a binding, \a |
6172 | | stage, \a count, and \a tex. |
6173 | | |
6174 | | \note \a count must be at least 1, and not larger than 16. |
6175 | | |
6176 | | \note When \a count is 1, this function is equivalent to texture(). |
6177 | | |
6178 | | \warning All elements of the array must be specified. |
6179 | | |
6180 | | \note \a tex can be null. It is valid to create a |
6181 | | QRhiShaderResourceBindings with unspecified resources, but such an object |
6182 | | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6183 | | suitable for creating pipelines. Such a pipeline must then always be used |
6184 | | together with another, layout compatible QRhiShaderResourceBindings with |
6185 | | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6186 | | |
6187 | | \sa texture(), sampler() |
6188 | | */ |
6189 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::textures(int binding, StageFlags stage, int count, QRhiTexture **tex) |
6190 | 0 | { |
6191 | 0 | Q_ASSERT(count >= 1 && count <= Data::MAX_TEX_SAMPLER_ARRAY_SIZE); |
6192 | 0 | QRhiShaderResourceBinding b; |
6193 | 0 | b.d.binding = binding; |
6194 | 0 | b.d.stage = stage; |
6195 | 0 | b.d.type = Texture; |
6196 | 0 | b.d.u.stex.count = count; |
6197 | 0 | for (int i = 0; i < count; ++i) { |
6198 | 0 | if (tex) |
6199 | 0 | b.d.u.stex.texSamplers[i] = { tex[i], nullptr }; |
6200 | 0 | else |
6201 | 0 | b.d.u.stex.texSamplers[i] = { nullptr, nullptr }; |
6202 | 0 | } |
6203 | 0 | return b; |
6204 | 0 | } |
6205 | | |
6206 | | /*! |
6207 | | \return a shader resource binding for the given binding number, pipeline |
6208 | | stages, and sampler specified by \a binding, \a stage, \a sampler. |
6209 | | |
6210 | | \note \a sampler can be null. It is valid to create a |
6211 | | QRhiShaderResourceBindings with unspecified resources, but such an object |
6212 | | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6213 | | suitable for creating pipelines. Such a pipeline must then always be used |
6214 | | together with another, layout compatible QRhiShaderResourceBindings with |
6215 | | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6216 | | |
6217 | | Arrays of separate samplers are not supported. |
6218 | | |
6219 | | This creates a binding for a separate sampler object, whereas |
6220 | | sampledTexture() is suitable for combined image samplers. In |
6221 | | Vulkan-compatible GLSL code separate samplers are declared as \c sampler |
6222 | | as opposed to \c sampler2D: \c{layout(binding = 2) uniform sampler samp;} |
6223 | | |
6224 | | With both a \c texture2D and \c sampler present, they can be used together |
6225 | | to sample the texture: \c{fragColor = texture(sampler2D(tex, samp), |
6226 | | texcoord);}. |
6227 | | |
6228 | | \note A shader may not be able to consume more than 16 samplers, depending |
6229 | | on the underlying graphics API. This hard limit must be kept in mind in |
6230 | | renderer design. |
6231 | | |
6232 | | \sa texture() |
6233 | | */ |
6234 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::sampler(int binding, StageFlags stage, QRhiSampler *sampler) |
6235 | 0 | { |
6236 | 0 | QRhiShaderResourceBinding b; |
6237 | 0 | b.d.binding = binding; |
6238 | 0 | b.d.stage = stage; |
6239 | 0 | b.d.type = Sampler; |
6240 | 0 | b.d.u.stex.count = 1; |
6241 | 0 | b.d.u.stex.texSamplers[0] = { nullptr, sampler }; |
6242 | 0 | return b; |
6243 | 0 | } |
6244 | | |
6245 | | /*! |
6246 | | \return a shader resource binding for a read-only storage image with the |
6247 | | given \a binding number and pipeline \a stage. The image load operations |
6248 | | will have access to all layers of the specified \a level. (so if the texture |
6249 | | is a cubemap, the shader must use imageCube instead of image2D) |
6250 | | |
6251 | | \note When \a tex is not null, it must have been created with |
6252 | | QRhiTexture::UsedWithLoadStore. |
6253 | | |
6254 | | \note \a tex can be null. It is valid to create a QRhiShaderResourceBindings |
6255 | | with unspecified resources, but such an object cannot be used with |
6256 | | QRhiCommandBuffer::setShaderResources(). It is however suitable for creating |
6257 | | pipelines. Such a pipeline must then always be used together with another, |
6258 | | layout compatible QRhiShaderResourceBindings with resources present passed |
6259 | | to QRhiCommandBuffer::setShaderResources(). |
6260 | | |
6261 | | \note Image load/store is only available within the compute and fragment stages. |
6262 | | */ |
6263 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoad( |
6264 | | int binding, StageFlags stage, QRhiTexture *tex, int level) |
6265 | 0 | { |
6266 | 0 | QRhiShaderResourceBinding b; |
6267 | 0 | b.d.binding = binding; |
6268 | 0 | b.d.stage = stage; |
6269 | 0 | b.d.type = ImageLoad; |
6270 | 0 | b.d.u.simage.tex = tex; |
6271 | 0 | b.d.u.simage.level = level; |
6272 | 0 | return b; |
6273 | 0 | } |
6274 | | |
6275 | | /*! |
6276 | | \return a shader resource binding for a write-only storage image with the |
6277 | | given \a binding number and pipeline \a stage. The image store operations |
6278 | | will have access to all layers of the specified \a level. (so if the texture |
6279 | | is a cubemap, the shader must use imageCube instead of image2D) |
6280 | | |
6281 | | \note When \a tex is not null, it must have been created with |
6282 | | QRhiTexture::UsedWithLoadStore. |
6283 | | |
6284 | | \note \a tex can be null. It is valid to create a QRhiShaderResourceBindings |
6285 | | with unspecified resources, but such an object cannot be used with |
6286 | | QRhiCommandBuffer::setShaderResources(). It is however suitable for creating |
6287 | | pipelines. Such a pipeline must then always be used together with another, |
6288 | | layout compatible QRhiShaderResourceBindings with resources present passed |
6289 | | to QRhiCommandBuffer::setShaderResources(). |
6290 | | |
6291 | | \note Image load/store is only available within the compute and fragment stages. |
6292 | | */ |
6293 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::imageStore( |
6294 | | int binding, StageFlags stage, QRhiTexture *tex, int level) |
6295 | 0 | { |
6296 | 0 | QRhiShaderResourceBinding b; |
6297 | 0 | b.d.binding = binding; |
6298 | 0 | b.d.stage = stage; |
6299 | 0 | b.d.type = ImageStore; |
6300 | 0 | b.d.u.simage.tex = tex; |
6301 | 0 | b.d.u.simage.level = level; |
6302 | 0 | return b; |
6303 | 0 | } |
6304 | | |
6305 | | /*! |
6306 | | \return a shader resource binding for a read/write storage image with the |
6307 | | given \a binding number and pipeline \a stage. The image load/store operations |
6308 | | will have access to all layers of the specified \a level. (so if the texture |
6309 | | is a cubemap, the shader must use imageCube instead of image2D) |
6310 | | |
6311 | | \note When \a tex is not null, it must have been created with |
6312 | | QRhiTexture::UsedWithLoadStore. |
6313 | | |
6314 | | \note \a tex can be null. It is valid to create a QRhiShaderResourceBindings |
6315 | | with unspecified resources, but such an object cannot be used with |
6316 | | QRhiCommandBuffer::setShaderResources(). It is however suitable for creating |
6317 | | pipelines. Such a pipeline must then always be used together with another, |
6318 | | layout compatible QRhiShaderResourceBindings with resources present passed |
6319 | | to QRhiCommandBuffer::setShaderResources(). |
6320 | | |
6321 | | \note Image load/store is only available within the compute and fragment stages. |
6322 | | */ |
6323 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoadStore( |
6324 | | int binding, StageFlags stage, QRhiTexture *tex, int level) |
6325 | 0 | { |
6326 | 0 | QRhiShaderResourceBinding b; |
6327 | 0 | b.d.binding = binding; |
6328 | 0 | b.d.stage = stage; |
6329 | 0 | b.d.type = ImageLoadStore; |
6330 | 0 | b.d.u.simage.tex = tex; |
6331 | 0 | b.d.u.simage.level = level; |
6332 | 0 | return b; |
6333 | 0 | } |
6334 | | |
6335 | | /*! |
6336 | | \return a shader resource binding for a read-only storage buffer with the |
6337 | | given \a binding number and pipeline \a stage. |
6338 | | |
6339 | | \note When \a buf is not null, must have been created with |
6340 | | QRhiBuffer::StorageBuffer. |
6341 | | |
6342 | | \note \a buf can be null. It is valid to create a |
6343 | | QRhiShaderResourceBindings with unspecified resources, but such an object |
6344 | | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6345 | | suitable for creating pipelines. Such a pipeline must then always be used |
6346 | | together with another, layout compatible QRhiShaderResourceBindings with |
6347 | | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6348 | | |
6349 | | \note Buffer load/store is only guaranteed to be available within a compute |
6350 | | pipeline. While some backends may support using these resources in a |
6351 | | graphics pipeline as well, this is not universally supported, and even when |
6352 | | it is, unexpected problems may arise when it comes to barriers and |
6353 | | synchronization. Therefore, avoid using such resources with shaders other |
6354 | | than compute. |
6355 | | */ |
6356 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad( |
6357 | | int binding, StageFlags stage, QRhiBuffer *buf) |
6358 | 0 | { |
6359 | 0 | QRhiShaderResourceBinding b; |
6360 | 0 | b.d.binding = binding; |
6361 | 0 | b.d.stage = stage; |
6362 | 0 | b.d.type = BufferLoad; |
6363 | 0 | b.d.u.sbuf.buf = buf; |
6364 | 0 | b.d.u.sbuf.offset = 0; |
6365 | 0 | b.d.u.sbuf.maybeSize = 0; // entire buffer |
6366 | 0 | return b; |
6367 | 0 | } |
6368 | | |
6369 | | /*! |
6370 | | \return a shader resource binding for a read-only storage buffer with the |
6371 | | given \a binding number and pipeline \a stage. This overload binds a region |
6372 | | only, as specified by \a offset and \a size. |
6373 | | |
6374 | | \note When \a buf is not null, must have been created with |
6375 | | QRhiBuffer::StorageBuffer. |
6376 | | |
6377 | | \note \a buf can be null. It is valid to create a |
6378 | | QRhiShaderResourceBindings with unspecified resources, but such an object |
6379 | | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6380 | | suitable for creating pipelines. Such a pipeline must then always be used |
6381 | | together with another, layout compatible QRhiShaderResourceBindings with |
6382 | | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6383 | | |
6384 | | \note Buffer load/store is only guaranteed to be available within a compute |
6385 | | pipeline. While some backends may support using these resources in a |
6386 | | graphics pipeline as well, this is not universally supported, and even when |
6387 | | it is, unexpected problems may arise when it comes to barriers and |
6388 | | synchronization. Therefore, avoid using such resources with shaders other |
6389 | | than compute. |
6390 | | */ |
6391 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad( |
6392 | | int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size) |
6393 | 0 | { |
6394 | 0 | Q_ASSERT(size > 0); |
6395 | 0 | QRhiShaderResourceBinding b; |
6396 | 0 | b.d.binding = binding; |
6397 | 0 | b.d.stage = stage; |
6398 | 0 | b.d.type = BufferLoad; |
6399 | 0 | b.d.u.sbuf.buf = buf; |
6400 | 0 | b.d.u.sbuf.offset = offset; |
6401 | 0 | b.d.u.sbuf.maybeSize = size; |
6402 | 0 | return b; |
6403 | 0 | } |
6404 | | |
6405 | | /*! |
6406 | | \return a shader resource binding for a write-only storage buffer with the |
6407 | | given \a binding number and pipeline \a stage. |
6408 | | |
6409 | | \note When \a buf is not null, must have been created with |
6410 | | QRhiBuffer::StorageBuffer. |
6411 | | |
6412 | | \note \a buf can be null. It is valid to create a |
6413 | | QRhiShaderResourceBindings with unspecified resources, but such an object |
6414 | | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6415 | | suitable for creating pipelines. Such a pipeline must then always be used |
6416 | | together with another, layout compatible QRhiShaderResourceBindings with |
6417 | | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6418 | | |
6419 | | \note Buffer load/store is only guaranteed to be available within a compute |
6420 | | pipeline. While some backends may support using these resources in a |
6421 | | graphics pipeline as well, this is not universally supported, and even when |
6422 | | it is, unexpected problems may arise when it comes to barriers and |
6423 | | synchronization. Therefore, avoid using such resources with shaders other |
6424 | | than compute. |
6425 | | */ |
6426 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore( |
6427 | | int binding, StageFlags stage, QRhiBuffer *buf) |
6428 | 0 | { |
6429 | 0 | QRhiShaderResourceBinding b; |
6430 | 0 | b.d.binding = binding; |
6431 | 0 | b.d.stage = stage; |
6432 | 0 | b.d.type = BufferStore; |
6433 | 0 | b.d.u.sbuf.buf = buf; |
6434 | 0 | b.d.u.sbuf.offset = 0; |
6435 | 0 | b.d.u.sbuf.maybeSize = 0; // entire buffer |
6436 | 0 | return b; |
6437 | 0 | } |
6438 | | |
6439 | | /*! |
6440 | | \return a shader resource binding for a write-only storage buffer with the |
6441 | | given \a binding number and pipeline \a stage. This overload binds a region |
6442 | | only, as specified by \a offset and \a size. |
6443 | | |
6444 | | \note When \a buf is not null, must have been created with |
6445 | | QRhiBuffer::StorageBuffer. |
6446 | | |
6447 | | \note \a buf can be null. It is valid to create a |
6448 | | QRhiShaderResourceBindings with unspecified resources, but such an object |
6449 | | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6450 | | suitable for creating pipelines. Such a pipeline must then always be used |
6451 | | together with another, layout compatible QRhiShaderResourceBindings with |
6452 | | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6453 | | |
6454 | | \note Buffer load/store is only guaranteed to be available within a compute |
6455 | | pipeline. While some backends may support using these resources in a |
6456 | | graphics pipeline as well, this is not universally supported, and even when |
6457 | | it is, unexpected problems may arise when it comes to barriers and |
6458 | | synchronization. Therefore, avoid using such resources with shaders other |
6459 | | than compute. |
6460 | | */ |
6461 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore( |
6462 | | int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size) |
6463 | 0 | { |
6464 | 0 | Q_ASSERT(size > 0); |
6465 | 0 | QRhiShaderResourceBinding b; |
6466 | 0 | b.d.binding = binding; |
6467 | 0 | b.d.stage = stage; |
6468 | 0 | b.d.type = BufferStore; |
6469 | 0 | b.d.u.sbuf.buf = buf; |
6470 | 0 | b.d.u.sbuf.offset = offset; |
6471 | 0 | b.d.u.sbuf.maybeSize = size; |
6472 | 0 | return b; |
6473 | 0 | } |
6474 | | |
6475 | | /*! |
6476 | | \return a shader resource binding for a read-write storage buffer with the |
6477 | | given \a binding number and pipeline \a stage. |
6478 | | |
6479 | | \note When \a buf is not null, must have been created with |
6480 | | QRhiBuffer::StorageBuffer. |
6481 | | |
6482 | | \note \a buf can be null. It is valid to create a |
6483 | | QRhiShaderResourceBindings with unspecified resources, but such an object |
6484 | | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6485 | | suitable for creating pipelines. Such a pipeline must then always be used |
6486 | | together with another, layout compatible QRhiShaderResourceBindings with |
6487 | | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6488 | | |
6489 | | \note Buffer load/store is only guaranteed to be available within a compute |
6490 | | pipeline. While some backends may support using these resources in a |
6491 | | graphics pipeline as well, this is not universally supported, and even when |
6492 | | it is, unexpected problems may arise when it comes to barriers and |
6493 | | synchronization. Therefore, avoid using such resources with shaders other |
6494 | | than compute. |
6495 | | */ |
6496 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore( |
6497 | | int binding, StageFlags stage, QRhiBuffer *buf) |
6498 | 0 | { |
6499 | 0 | QRhiShaderResourceBinding b; |
6500 | 0 | b.d.binding = binding; |
6501 | 0 | b.d.stage = stage; |
6502 | 0 | b.d.type = BufferLoadStore; |
6503 | 0 | b.d.u.sbuf.buf = buf; |
6504 | 0 | b.d.u.sbuf.offset = 0; |
6505 | 0 | b.d.u.sbuf.maybeSize = 0; // entire buffer |
6506 | 0 | return b; |
6507 | 0 | } |
6508 | | |
6509 | | /*! |
6510 | | \return a shader resource binding for a read-write storage buffer with the |
6511 | | given \a binding number and pipeline \a stage. This overload binds a region |
6512 | | only, as specified by \a offset and \a size. |
6513 | | |
6514 | | \note When \a buf is not null, must have been created with |
6515 | | QRhiBuffer::StorageBuffer. |
6516 | | |
6517 | | \note \a buf can be null. It is valid to create a |
6518 | | QRhiShaderResourceBindings with unspecified resources, but such an object |
6519 | | cannot be used with QRhiCommandBuffer::setShaderResources(). It is however |
6520 | | suitable for creating pipelines. Such a pipeline must then always be used |
6521 | | together with another, layout compatible QRhiShaderResourceBindings with |
6522 | | resources present passed to QRhiCommandBuffer::setShaderResources(). |
6523 | | |
6524 | | \note Buffer load/store is only guaranteed to be available within a compute |
6525 | | pipeline. While some backends may support using these resources in a |
6526 | | graphics pipeline as well, this is not universally supported, and even when |
6527 | | it is, unexpected problems may arise when it comes to barriers and |
6528 | | synchronization. Therefore, avoid using such resources with shaders other |
6529 | | than compute. |
6530 | | */ |
6531 | | QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore( |
6532 | | int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size) |
6533 | 0 | { |
6534 | 0 | Q_ASSERT(size > 0); |
6535 | 0 | QRhiShaderResourceBinding b; |
6536 | 0 | b.d.binding = binding; |
6537 | 0 | b.d.stage = stage; |
6538 | 0 | b.d.type = BufferLoadStore; |
6539 | 0 | b.d.u.sbuf.buf = buf; |
6540 | 0 | b.d.u.sbuf.offset = offset; |
6541 | 0 | b.d.u.sbuf.maybeSize = size; |
6542 | 0 | return b; |
6543 | 0 | } |
6544 | | |
6545 | | /*! |
6546 | | \return \c true if the contents of the two QRhiShaderResourceBinding |
6547 | | objects \a a and \a b are equal. This includes the resources (buffer, |
6548 | | texture) and related parameters (offset, size) as well. To only compare |
6549 | | layouts (binding point, pipeline stage, resource type), use |
6550 | | \l{QRhiShaderResourceBinding::isLayoutCompatible()}{isLayoutCompatible()} |
6551 | | instead. |
6552 | | |
6553 | | \relates QRhiShaderResourceBinding |
6554 | | */ |
6555 | | bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept |
6556 | 0 | { |
6557 | 0 | const QRhiShaderResourceBinding::Data *da = QRhiImplementation::shaderResourceBindingData(a); |
6558 | 0 | const QRhiShaderResourceBinding::Data *db = QRhiImplementation::shaderResourceBindingData(b); |
6559 | |
|
6560 | 0 | if (da == db) |
6561 | 0 | return true; |
6562 | | |
6563 | | |
6564 | 0 | if (da->binding != db->binding |
6565 | 0 | || da->stage != db->stage |
6566 | 0 | || da->type != db->type) |
6567 | 0 | { |
6568 | 0 | return false; |
6569 | 0 | } |
6570 | | |
6571 | 0 | switch (da->type) { |
6572 | 0 | case QRhiShaderResourceBinding::UniformBuffer: |
6573 | 0 | if (da->u.ubuf.buf != db->u.ubuf.buf |
6574 | 0 | || da->u.ubuf.offset != db->u.ubuf.offset |
6575 | 0 | || da->u.ubuf.maybeSize != db->u.ubuf.maybeSize) |
6576 | 0 | { |
6577 | 0 | return false; |
6578 | 0 | } |
6579 | 0 | break; |
6580 | 0 | case QRhiShaderResourceBinding::SampledTexture: |
6581 | 0 | if (da->u.stex.count != db->u.stex.count) |
6582 | 0 | return false; |
6583 | 0 | for (int i = 0; i < da->u.stex.count; ++i) { |
6584 | 0 | if (da->u.stex.texSamplers[i].tex != db->u.stex.texSamplers[i].tex |
6585 | 0 | || da->u.stex.texSamplers[i].sampler != db->u.stex.texSamplers[i].sampler) |
6586 | 0 | { |
6587 | 0 | return false; |
6588 | 0 | } |
6589 | 0 | } |
6590 | 0 | break; |
6591 | 0 | case QRhiShaderResourceBinding::Texture: |
6592 | 0 | if (da->u.stex.count != db->u.stex.count) |
6593 | 0 | return false; |
6594 | 0 | for (int i = 0; i < da->u.stex.count; ++i) { |
6595 | 0 | if (da->u.stex.texSamplers[i].tex != db->u.stex.texSamplers[i].tex) |
6596 | 0 | return false; |
6597 | 0 | } |
6598 | 0 | break; |
6599 | 0 | case QRhiShaderResourceBinding::Sampler: |
6600 | 0 | if (da->u.stex.texSamplers[0].sampler != db->u.stex.texSamplers[0].sampler) |
6601 | 0 | return false; |
6602 | 0 | break; |
6603 | 0 | case QRhiShaderResourceBinding::ImageLoad: |
6604 | 0 | case QRhiShaderResourceBinding::ImageStore: |
6605 | 0 | case QRhiShaderResourceBinding::ImageLoadStore: |
6606 | 0 | if (da->u.simage.tex != db->u.simage.tex |
6607 | 0 | || da->u.simage.level != db->u.simage.level) |
6608 | 0 | { |
6609 | 0 | return false; |
6610 | 0 | } |
6611 | 0 | break; |
6612 | 0 | case QRhiShaderResourceBinding::BufferLoad: |
6613 | 0 | case QRhiShaderResourceBinding::BufferStore: |
6614 | 0 | case QRhiShaderResourceBinding::BufferLoadStore: |
6615 | 0 | if (da->u.sbuf.buf != db->u.sbuf.buf |
6616 | 0 | || da->u.sbuf.offset != db->u.sbuf.offset |
6617 | 0 | || da->u.sbuf.maybeSize != db->u.sbuf.maybeSize) |
6618 | 0 | { |
6619 | 0 | return false; |
6620 | 0 | } |
6621 | 0 | break; |
6622 | 0 | default: |
6623 | 0 | Q_UNREACHABLE_RETURN(false); |
6624 | 0 | } |
6625 | | |
6626 | 0 | return true; |
6627 | 0 | } |
6628 | | |
6629 | | /*! |
6630 | | \return \c false if all the bindings in the two QRhiShaderResourceBinding |
6631 | | objects \a a and \a b are equal; otherwise returns \c true. |
6632 | | |
6633 | | \relates QRhiShaderResourceBinding |
6634 | | */ |
6635 | | bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept |
6636 | 0 | { |
6637 | 0 | return !(a == b); |
6638 | 0 | } |
6639 | | |
6640 | | /*! |
6641 | | \fn size_t qHash(const QRhiShaderResourceBinding &key, size_t seed) |
6642 | | \qhashold{QRhiShaderResourceBinding} |
6643 | | */ |
6644 | | size_t qHash(const QRhiShaderResourceBinding &b, size_t seed) noexcept |
6645 | 0 | { |
6646 | 0 | const QRhiShaderResourceBinding::Data *d = QRhiImplementation::shaderResourceBindingData(b); |
6647 | 0 | QtPrivate::QHashCombineWithSeed hash(seed); |
6648 | 0 | seed = hash(seed, d->binding); |
6649 | 0 | seed = hash(seed, d->stage); |
6650 | 0 | seed = hash(seed, d->type); |
6651 | 0 | switch (d->type) { |
6652 | 0 | case QRhiShaderResourceBinding::UniformBuffer: |
6653 | 0 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.ubuf.buf)); |
6654 | 0 | break; |
6655 | 0 | case QRhiShaderResourceBinding::SampledTexture: |
6656 | 0 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].tex)); |
6657 | 0 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].sampler)); |
6658 | 0 | break; |
6659 | 0 | case QRhiShaderResourceBinding::Texture: |
6660 | 0 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].tex)); |
6661 | 0 | break; |
6662 | 0 | case QRhiShaderResourceBinding::Sampler: |
6663 | 0 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.stex.texSamplers[0].sampler)); |
6664 | 0 | break; |
6665 | 0 | case QRhiShaderResourceBinding::ImageLoad: |
6666 | 0 | case QRhiShaderResourceBinding::ImageStore: |
6667 | 0 | case QRhiShaderResourceBinding::ImageLoadStore: |
6668 | 0 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.simage.tex)); |
6669 | 0 | break; |
6670 | 0 | case QRhiShaderResourceBinding::BufferLoad: |
6671 | 0 | case QRhiShaderResourceBinding::BufferStore: |
6672 | 0 | case QRhiShaderResourceBinding::BufferLoadStore: |
6673 | 0 | seed = hash(seed, reinterpret_cast<quintptr>(d->u.sbuf.buf)); |
6674 | 0 | break; |
6675 | 0 | } |
6676 | 0 | return seed; |
6677 | 0 | } |
6678 | | |
6679 | | #ifndef QT_NO_DEBUG_STREAM |
6680 | | QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b) |
6681 | 0 | { |
6682 | 0 | QDebugStateSaver saver(dbg); |
6683 | 0 | const QRhiShaderResourceBinding::Data *d = QRhiImplementation::shaderResourceBindingData(b); |
6684 | 0 | dbg.nospace() << "QRhiShaderResourceBinding(" |
6685 | 0 | << "binding=" << d->binding |
6686 | 0 | << " stage=" << d->stage |
6687 | 0 | << " type=" << d->type; |
6688 | 0 | switch (d->type) { |
6689 | 0 | case QRhiShaderResourceBinding::UniformBuffer: |
6690 | 0 | dbg.nospace() << " UniformBuffer(" |
6691 | 0 | << "buffer=" << d->u.ubuf.buf |
6692 | 0 | << " offset=" << d->u.ubuf.offset |
6693 | 0 | << " maybeSize=" << d->u.ubuf.maybeSize |
6694 | 0 | << ')'; |
6695 | 0 | break; |
6696 | 0 | case QRhiShaderResourceBinding::SampledTexture: |
6697 | 0 | dbg.nospace() << " SampledTextures(" |
6698 | 0 | << "count=" << d->u.stex.count; |
6699 | 0 | for (int i = 0; i < d->u.stex.count; ++i) { |
6700 | 0 | dbg.nospace() << " texture=" << d->u.stex.texSamplers[i].tex |
6701 | 0 | << " sampler=" << d->u.stex.texSamplers[i].sampler; |
6702 | 0 | } |
6703 | 0 | dbg.nospace() << ')'; |
6704 | 0 | break; |
6705 | 0 | case QRhiShaderResourceBinding::Texture: |
6706 | 0 | dbg.nospace() << " Textures(" |
6707 | 0 | << "count=" << d->u.stex.count; |
6708 | 0 | for (int i = 0; i < d->u.stex.count; ++i) |
6709 | 0 | dbg.nospace() << " texture=" << d->u.stex.texSamplers[i].tex; |
6710 | 0 | dbg.nospace() << ')'; |
6711 | 0 | break; |
6712 | 0 | case QRhiShaderResourceBinding::Sampler: |
6713 | 0 | dbg.nospace() << " Sampler(" |
6714 | 0 | << " sampler=" << d->u.stex.texSamplers[0].sampler |
6715 | 0 | << ')'; |
6716 | 0 | break; |
6717 | 0 | case QRhiShaderResourceBinding::ImageLoad: |
6718 | 0 | dbg.nospace() << " ImageLoad(" |
6719 | 0 | << "texture=" << d->u.simage.tex |
6720 | 0 | << " level=" << d->u.simage.level |
6721 | 0 | << ')'; |
6722 | 0 | break; |
6723 | 0 | case QRhiShaderResourceBinding::ImageStore: |
6724 | 0 | dbg.nospace() << " ImageStore(" |
6725 | 0 | << "texture=" << d->u.simage.tex |
6726 | 0 | << " level=" << d->u.simage.level |
6727 | 0 | << ')'; |
6728 | 0 | break; |
6729 | 0 | case QRhiShaderResourceBinding::ImageLoadStore: |
6730 | 0 | dbg.nospace() << " ImageLoadStore(" |
6731 | 0 | << "texture=" << d->u.simage.tex |
6732 | 0 | << " level=" << d->u.simage.level |
6733 | 0 | << ')'; |
6734 | 0 | break; |
6735 | 0 | case QRhiShaderResourceBinding::BufferLoad: |
6736 | 0 | dbg.nospace() << " BufferLoad(" |
6737 | 0 | << "buffer=" << d->u.sbuf.buf |
6738 | 0 | << " offset=" << d->u.sbuf.offset |
6739 | 0 | << " maybeSize=" << d->u.sbuf.maybeSize |
6740 | 0 | << ')'; |
6741 | 0 | break; |
6742 | 0 | case QRhiShaderResourceBinding::BufferStore: |
6743 | 0 | dbg.nospace() << " BufferStore(" |
6744 | 0 | << "buffer=" << d->u.sbuf.buf |
6745 | 0 | << " offset=" << d->u.sbuf.offset |
6746 | 0 | << " maybeSize=" << d->u.sbuf.maybeSize |
6747 | 0 | << ')'; |
6748 | 0 | break; |
6749 | 0 | case QRhiShaderResourceBinding::BufferLoadStore: |
6750 | 0 | dbg.nospace() << " BufferLoadStore(" |
6751 | 0 | << "buffer=" << d->u.sbuf.buf |
6752 | 0 | << " offset=" << d->u.sbuf.offset |
6753 | 0 | << " maybeSize=" << d->u.sbuf.maybeSize |
6754 | 0 | << ')'; |
6755 | 0 | break; |
6756 | 0 | default: |
6757 | 0 | dbg.nospace() << " UNKNOWN()"; |
6758 | 0 | break; |
6759 | 0 | } |
6760 | 0 | dbg.nospace() << ')'; |
6761 | 0 | return dbg; |
6762 | 0 | } |
6763 | | #endif |
6764 | | |
6765 | | #ifndef QT_NO_DEBUG_STREAM |
6766 | | QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb) |
6767 | 0 | { |
6768 | 0 | QDebugStateSaver saver(dbg); |
6769 | 0 | dbg.nospace() << "QRhiShaderResourceBindings(" |
6770 | 0 | << srb.m_bindings |
6771 | 0 | << ')'; |
6772 | 0 | return dbg; |
6773 | 0 | } |
6774 | | #endif |
6775 | | |
6776 | | /*! |
6777 | | \class QRhiGraphicsPipeline |
6778 | | \inmodule QtGuiPrivate |
6779 | | \inheaderfile rhi/qrhi.h |
6780 | | \since 6.6 |
6781 | | \brief Graphics pipeline state resource. |
6782 | | |
6783 | | Represents a graphics pipeline. What exactly this map to in the underlying |
6784 | | native graphics API, varies. Where there is a concept of pipeline objects, |
6785 | | for example with Vulkan, the QRhi backend will create such an object upon |
6786 | | calling create(). Elsewhere, for example with OpenGL, the |
6787 | | QRhiGraphicsPipeline may merely collect the various state, and create()'s |
6788 | | main task is to set up the corresponding shader program, but deferring |
6789 | | looking at any of the requested state to a later point. |
6790 | | |
6791 | | As with all QRhiResource subclasses, the two-phased initialization pattern |
6792 | | applies: setting any values via the setters, for example setDepthTest(), is |
6793 | | only effective after calling create(). Avoid changing any values once the |
6794 | | QRhiGraphicsPipeline has been initialized via create(). To change some |
6795 | | state, set the new value and call create() again. However, that will |
6796 | | effectively release all underlying native resources and create new ones. As |
6797 | | a result, it may be a heavy, expensive operation. Rather, prefer creating |
6798 | | multiple pipelines with the different states, and |
6799 | | \l{QRhiCommandBuffer::setGraphicsPipeline()}{switch between them} when |
6800 | | recording the render pass. |
6801 | | |
6802 | | \note Setting the shader stages is mandatory. There must be at least one |
6803 | | stage, and there must be a vertex stage. |
6804 | | |
6805 | | \note Setting the shader resource bindings is mandatory. The referenced |
6806 | | QRhiShaderResourceBindings must already have create() called on it by the |
6807 | | time create() is called. Associating with a QRhiShaderResourceBindings that |
6808 | | has no bindings is also valid, as long as no shader in any stage expects any |
6809 | | resources. Using a QRhiShaderResourceBindings object that does not specify |
6810 | | any actual resources (i.e., the buffers, textures, etc. for the binding |
6811 | | points are set to \nullptr) is valid as well, as long as a |
6812 | | \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible} |
6813 | | QRhiShaderResourceBindings, that specifies resources for all the bindings, |
6814 | | is going to be set via |
6815 | | \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} when |
6816 | | recording the render pass. |
6817 | | |
6818 | | \note Setting the render pass descriptor is mandatory. To obtain a |
6819 | | QRhiRenderPassDescriptor that can be passed to setRenderPassDescriptor(), |
6820 | | use either QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor() or |
6821 | | QRhiSwapChain::newCompatibleRenderPassDescriptor(). |
6822 | | |
6823 | | \note Setting the vertex input layout is mandatory. |
6824 | | |
6825 | | \note sampleCount() defaults to 1 and must match the sample count of the |
6826 | | render target's color and depth stencil attachments. |
6827 | | |
6828 | | \note The depth test, depth write, and stencil test are disabled by |
6829 | | default. The face culling mode defaults to no culling. |
6830 | | |
6831 | | \note stencilReadMask() and stencilWriteMask() apply to both faces. They |
6832 | | both default to 0xFF. |
6833 | | |
6834 | | \section2 Example usage |
6835 | | |
6836 | | All settings of a graphics pipeline have defaults which might be suitable |
6837 | | to many applications. Therefore a minimal example of creating a graphics |
6838 | | pipeline could be the following. This assumes that the vertex shader takes |
6839 | | a single \c{vec3 position} input at the input location 0. With the |
6840 | | QRhiShaderResourceBindings and QRhiRenderPassDescriptor objects, plus the |
6841 | | QShader collections for the vertex and fragment stages, a pipeline could be |
6842 | | created like this: |
6843 | | |
6844 | | \code |
6845 | | QRhiShaderResourceBindings *srb; |
6846 | | QRhiRenderPassDescriptor *rpDesc; |
6847 | | QShader vs, fs; |
6848 | | // ... |
6849 | | |
6850 | | QRhiVertexInputLayout inputLayout; |
6851 | | inputLayout.setBindings({ { 3 * sizeof(float) } }); |
6852 | | inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float3, 0 } }); |
6853 | | |
6854 | | QRhiGraphicsPipeline *ps = rhi->newGraphicsPipeline(); |
6855 | | ps->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } }); |
6856 | | ps->setVertexInputLayout(inputLayout); |
6857 | | ps->setShaderResourceBindings(srb); |
6858 | | ps->setRenderPassDescriptor(rpDesc); |
6859 | | if (!ps->create()) { error(); } |
6860 | | \endcode |
6861 | | |
6862 | | The above code creates a pipeline object that uses the defaults for many |
6863 | | settings and states. For example, it will use a \l Triangles topology, no |
6864 | | backface culling, blending is disabled but color write is enabled for all |
6865 | | four channels, depth test/write are disabled, stencil operations are |
6866 | | disabled. |
6867 | | |
6868 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
6869 | | for details. |
6870 | | |
6871 | | \sa QRhiCommandBuffer, QRhi |
6872 | | */ |
6873 | | |
6874 | | /*! |
6875 | | \enum QRhiGraphicsPipeline::Flag |
6876 | | |
6877 | | Flag values for describing the dynamic state of the pipeline, and other |
6878 | | options. The viewport is always dynamic. |
6879 | | |
6880 | | \value UsesBlendConstants Indicates that a blend color constant will be set |
6881 | | via QRhiCommandBuffer::setBlendConstants() |
6882 | | |
6883 | | \value UsesStencilRef Indicates that a stencil reference value will be set |
6884 | | via QRhiCommandBuffer::setStencilRef() |
6885 | | |
6886 | | \value UsesScissor Indicates that a scissor rectangle will be set via |
6887 | | QRhiCommandBuffer::setScissor() |
6888 | | |
6889 | | \value CompileShadersWithDebugInfo Requests compiling shaders with debug |
6890 | | information enabled. This is relevant only when runtime shader compilation |
6891 | | from source code is involved, and only when the underlying infrastructure |
6892 | | supports this. With concrete examples, this is not relevant with Vulkan and |
6893 | | SPIR-V, because the GLSL-to-SPIR-V compilation does not happen at run |
6894 | | time. On the other hand, consider Direct3D and HLSL, where there are |
6895 | | multiple options: when the QShader packages ship with pre-compiled bytecode |
6896 | | (\c DXBC), debug information is to be requested through the tool that |
6897 | | generates the \c{.qsb} file, similarly to the case of Vulkan and |
6898 | | SPIR-V. However, when having HLSL source code in the pre- or |
6899 | | runtime-generated QShader packages, the first phase of compilation (HLSL |
6900 | | source to intermediate format) happens at run time too, with this flag taken |
6901 | | into account. Debug information is relevant in particular with tools like |
6902 | | RenderDoc since it allows seeing the original source code when investigating |
6903 | | the pipeline and when performing vertex or fragment shader debugging. |
6904 | | |
6905 | | \value UsesShadingRate Indicates that a per-draw (per-pipeline) shading rate |
6906 | | value will be set via QRhiCommandBuffer::setShadingRate(). Not specifying |
6907 | | this flag and still calling setShadingRate() may lead to varying, unexpected |
6908 | | results depending on the underlying graphics API. |
6909 | | |
6910 | | \value [since 6.12] UsesIndirectDraws Indicates that this pipeline will be used with |
6911 | | indirect draw calls (QRhiCommandBuffer::drawIndirect() or |
6912 | | QRhiCommandBuffer::drawIndexedIndirect()). Setting this flag allows the |
6913 | | Metal backend to use Indirect Command Buffers (ICB) for GPU-driven |
6914 | | rendering, which significantly reduces CPU overhead for large draw counts. |
6915 | | Not setting this flag when using indirect draws is still functional but may |
6916 | | result in less optimal performance on Metal. This flag has no effect on |
6917 | | other backends. |
6918 | | */ |
6919 | | |
6920 | | /*! |
6921 | | \enum QRhiGraphicsPipeline::Topology |
6922 | | Specifies the primitive topology |
6923 | | |
6924 | | \value Triangles (default) |
6925 | | \value TriangleStrip |
6926 | | \value TriangleFan (only available if QRhi::TriangleFanTopology is supported) |
6927 | | \value Lines |
6928 | | \value LineStrip |
6929 | | \value Points |
6930 | | |
6931 | | \value Patches (only available if QRhi::Tessellation is supported, and |
6932 | | requires the tessellation stages to be present in the pipeline) |
6933 | | */ |
6934 | | |
6935 | | /*! |
6936 | | \enum QRhiGraphicsPipeline::CullMode |
6937 | | Specifies the culling mode |
6938 | | |
6939 | | \value None No culling (default) |
6940 | | \value Front Cull front faces |
6941 | | \value Back Cull back faces |
6942 | | */ |
6943 | | |
6944 | | /*! |
6945 | | \enum QRhiGraphicsPipeline::FrontFace |
6946 | | Specifies the front face winding order |
6947 | | |
6948 | | \value CCW Counter clockwise (default) |
6949 | | \value CW Clockwise |
6950 | | */ |
6951 | | |
6952 | | /*! |
6953 | | \enum QRhiGraphicsPipeline::ColorMaskComponent |
6954 | | Flag values for specifying the color write mask |
6955 | | |
6956 | | \value R |
6957 | | \value G |
6958 | | \value B |
6959 | | \value A |
6960 | | */ |
6961 | | |
6962 | | /*! |
6963 | | \enum QRhiGraphicsPipeline::BlendFactor |
6964 | | Specifies the blend factor |
6965 | | |
6966 | | \value Zero |
6967 | | \value One |
6968 | | \value SrcColor |
6969 | | \value OneMinusSrcColor |
6970 | | \value DstColor |
6971 | | \value OneMinusDstColor |
6972 | | \value SrcAlpha |
6973 | | \value OneMinusSrcAlpha |
6974 | | \value DstAlpha |
6975 | | \value OneMinusDstAlpha |
6976 | | \value ConstantColor |
6977 | | \value OneMinusConstantColor |
6978 | | \value ConstantAlpha |
6979 | | \value OneMinusConstantAlpha |
6980 | | \value SrcAlphaSaturate |
6981 | | \value Src1Color |
6982 | | \value OneMinusSrc1Color |
6983 | | \value Src1Alpha |
6984 | | \value OneMinusSrc1Alpha |
6985 | | */ |
6986 | | |
6987 | | /*! |
6988 | | \enum QRhiGraphicsPipeline::BlendOp |
6989 | | Specifies the blend operation |
6990 | | |
6991 | | \value Add |
6992 | | \value Subtract |
6993 | | \value ReverseSubtract |
6994 | | \value Min |
6995 | | \value Max |
6996 | | */ |
6997 | | |
6998 | | /*! |
6999 | | \enum QRhiGraphicsPipeline::CompareOp |
7000 | | Specifies the depth or stencil comparison function |
7001 | | |
7002 | | \value Never |
7003 | | \value Less (default for depth) |
7004 | | \value Equal |
7005 | | \value LessOrEqual |
7006 | | \value Greater |
7007 | | \value NotEqual |
7008 | | \value GreaterOrEqual |
7009 | | \value Always (default for stencil) |
7010 | | */ |
7011 | | |
7012 | | /*! |
7013 | | \enum QRhiGraphicsPipeline::StencilOp |
7014 | | Specifies the stencil operation |
7015 | | |
7016 | | \value StencilZero |
7017 | | \value Keep (default) |
7018 | | \value Replace |
7019 | | \value IncrementAndClamp |
7020 | | \value DecrementAndClamp |
7021 | | \value Invert |
7022 | | \value IncrementAndWrap |
7023 | | \value DecrementAndWrap |
7024 | | */ |
7025 | | |
7026 | | /*! |
7027 | | \enum QRhiGraphicsPipeline::PolygonMode |
7028 | | \brief Specifies the polygon rasterization mode |
7029 | | |
7030 | | Polygon Mode (Triangle Fill Mode in Metal, Fill Mode in D3D) specifies |
7031 | | the fill mode used when rasterizing polygons. Polygons may be drawn as |
7032 | | solids (Fill), or as a wire mesh (Line). |
7033 | | |
7034 | | Support for non-fill polygon modes is optional and is indicated by the |
7035 | | QRhi::NonFillPolygonMode feature. With OpenGL ES and some Vulkan |
7036 | | implementations the feature will likely be reported as unsupported, which |
7037 | | then means values other than Fill cannot be used. |
7038 | | |
7039 | | \value Fill The interior of the polygon is filled (default) |
7040 | | \value Line Boundary edges of the polygon are drawn as line segments. |
7041 | | */ |
7042 | | |
7043 | | /*! |
7044 | | \struct QRhiGraphicsPipeline::TargetBlend |
7045 | | \inmodule QtGuiPrivate |
7046 | | \inheaderfile rhi/qrhi.h |
7047 | | \since 6.6 |
7048 | | \brief Describes the blend state for one color attachment. |
7049 | | |
7050 | | Defaults to color write enabled, blending disabled. The blend values are |
7051 | | set up for pre-multiplied alpha (One, OneMinusSrcAlpha, One, |
7052 | | OneMinusSrcAlpha) by default. This means that to get the alpha blending |
7053 | | mode Qt Quick uses, it is enough to set the \c enable flag to true while |
7054 | | leaving other values at their defaults. |
7055 | | |
7056 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
7057 | | for details. |
7058 | | */ |
7059 | | |
7060 | | /*! |
7061 | | \variable QRhiGraphicsPipeline::TargetBlend::colorWrite |
7062 | | */ |
7063 | | |
7064 | | /*! |
7065 | | \variable QRhiGraphicsPipeline::TargetBlend::enable |
7066 | | */ |
7067 | | |
7068 | | /*! |
7069 | | \variable QRhiGraphicsPipeline::TargetBlend::srcColor |
7070 | | */ |
7071 | | |
7072 | | /*! |
7073 | | \variable QRhiGraphicsPipeline::TargetBlend::dstColor |
7074 | | */ |
7075 | | |
7076 | | /*! |
7077 | | \variable QRhiGraphicsPipeline::TargetBlend::opColor |
7078 | | */ |
7079 | | |
7080 | | /*! |
7081 | | \variable QRhiGraphicsPipeline::TargetBlend::srcAlpha |
7082 | | */ |
7083 | | |
7084 | | /*! |
7085 | | \variable QRhiGraphicsPipeline::TargetBlend::dstAlpha |
7086 | | */ |
7087 | | |
7088 | | /*! |
7089 | | \variable QRhiGraphicsPipeline::TargetBlend::opAlpha |
7090 | | */ |
7091 | | |
7092 | | /*! |
7093 | | \struct QRhiGraphicsPipeline::StencilOpState |
7094 | | \inmodule QtGuiPrivate |
7095 | | \inheaderfile rhi/qrhi.h |
7096 | | \since 6.6 |
7097 | | \brief Describes the stencil operation state. |
7098 | | |
7099 | | The default-constructed StencilOpState has the following set: |
7100 | | \list |
7101 | | \li failOp - \l Keep |
7102 | | \li depthFailOp - \l Keep |
7103 | | \li passOp - \l Keep |
7104 | | \li compareOp \l Always |
7105 | | \endlist |
7106 | | |
7107 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
7108 | | for details. |
7109 | | */ |
7110 | | |
7111 | | /*! |
7112 | | \variable QRhiGraphicsPipeline::StencilOpState::failOp |
7113 | | */ |
7114 | | |
7115 | | /*! |
7116 | | \variable QRhiGraphicsPipeline::StencilOpState::depthFailOp |
7117 | | */ |
7118 | | |
7119 | | /*! |
7120 | | \variable QRhiGraphicsPipeline::StencilOpState::passOp |
7121 | | */ |
7122 | | |
7123 | | /*! |
7124 | | \variable QRhiGraphicsPipeline::StencilOpState::compareOp |
7125 | | */ |
7126 | | |
7127 | | /*! |
7128 | | \internal |
7129 | | */ |
7130 | | QRhiGraphicsPipeline::QRhiGraphicsPipeline(QRhiImplementation *rhi) |
7131 | 0 | : QRhiResource(rhi) |
7132 | 0 | { |
7133 | 0 | } |
7134 | | |
7135 | | /*! |
7136 | | \return the resource type. |
7137 | | */ |
7138 | | QRhiResource::Type QRhiGraphicsPipeline::resourceType() const |
7139 | 0 | { |
7140 | 0 | return GraphicsPipeline; |
7141 | 0 | } |
7142 | | |
7143 | | /*! |
7144 | | \fn virtual bool QRhiGraphicsPipeline::create() = 0 |
7145 | | |
7146 | | Creates the corresponding native graphics resources. If there are already |
7147 | | resources present due to an earlier create() with no corresponding |
7148 | | destroy(), then destroy() is called implicitly first. |
7149 | | |
7150 | | \return \c true when successful, \c false when a graphics operation failed. |
7151 | | Regardless of the return value, calling destroy() is always safe. |
7152 | | |
7153 | | \note This may be, depending on the underlying graphics API, an expensive |
7154 | | operation, especially when shaders get compiled/optimized from source or |
7155 | | from an intermediate bytecode format to the GPU's own instruction set. |
7156 | | Where applicable, the QRhi backend automatically sets up the relevant |
7157 | | non-persistent facilities to accelerate this, for example the Vulkan |
7158 | | backend automatically creates a \c VkPipelineCache to improve data reuse |
7159 | | during the lifetime of the application. |
7160 | | |
7161 | | \note Drivers may also employ various persistent (disk-based) caching |
7162 | | strategies for shader and pipeline data, which is hidden to and is outside |
7163 | | of Qt's control. In some cases, depending on the graphics API and the QRhi |
7164 | | backend, there are facilities within QRhi for manually managing such a |
7165 | | cache, allowing the retrieval of a serializable blob that can then be |
7166 | | reloaded in the future runs of the application to ensure faster pipeline |
7167 | | creation times. See QRhi::pipelineCacheData() and |
7168 | | QRhi::setPipelineCacheData() for details. Note also that when working with |
7169 | | a QRhi instance managed by a higher level Qt framework, such as Qt Quick, |
7170 | | it is possible that such disk-based caching is taken care of automatically, |
7171 | | for example QQuickWindow uses a disk-based pipeline cache by default (which |
7172 | | comes in addition to any driver-level caching). |
7173 | | */ |
7174 | | |
7175 | | /*! |
7176 | | \fn QRhiGraphicsPipeline::Flags QRhiGraphicsPipeline::flags() const |
7177 | | \return the currently set flags. |
7178 | | */ |
7179 | | |
7180 | | /*! |
7181 | | \fn void QRhiGraphicsPipeline::setFlags(Flags f) |
7182 | | Sets the flags \a f. |
7183 | | */ |
7184 | | |
7185 | | /*! |
7186 | | \fn QRhiGraphicsPipeline::Topology QRhiGraphicsPipeline::topology() const |
7187 | | \return the currently set primitive topology. |
7188 | | */ |
7189 | | |
7190 | | /*! |
7191 | | \fn void QRhiGraphicsPipeline::setTopology(Topology t) |
7192 | | Sets the primitive topology \a t. |
7193 | | */ |
7194 | | |
7195 | | /*! |
7196 | | \fn QRhiGraphicsPipeline::CullMode QRhiGraphicsPipeline::cullMode() const |
7197 | | \return the currently set face culling mode. |
7198 | | */ |
7199 | | |
7200 | | /*! |
7201 | | \fn void QRhiGraphicsPipeline::setCullMode(CullMode mode) |
7202 | | Sets the specified face culling \a mode. |
7203 | | */ |
7204 | | |
7205 | | /*! |
7206 | | \fn QRhiGraphicsPipeline::FrontFace QRhiGraphicsPipeline::frontFace() const |
7207 | | \return the currently set front face mode. |
7208 | | */ |
7209 | | |
7210 | | /*! |
7211 | | \fn void QRhiGraphicsPipeline::setFrontFace(FrontFace f) |
7212 | | Sets the front face mode \a f. |
7213 | | */ |
7214 | | |
7215 | | /*! |
7216 | | \fn void QRhiGraphicsPipeline::setTargetBlends(std::initializer_list<TargetBlend> list) |
7217 | | |
7218 | | Sets the \a list of render target blend settings. This is a list because |
7219 | | when multiple render targets are used (i.e., a QRhiTextureRenderTarget with |
7220 | | more than one QRhiColorAttachment), there needs to be a TargetBlend |
7221 | | structure per render target (color attachment). |
7222 | | |
7223 | | By default there is one default-constructed TargetBlend set. |
7224 | | |
7225 | | \sa QRhi::MaxColorAttachments |
7226 | | */ |
7227 | | |
7228 | | /*! |
7229 | | \fn template<typename InputIterator> void QRhiGraphicsPipeline::setTargetBlends(InputIterator first, InputIterator last) |
7230 | | Sets the list of render target blend settings from the iterators \a first and \a last. |
7231 | | */ |
7232 | | |
7233 | | /*! |
7234 | | \fn const QRhiGraphicsPipeline::TargetBlend *QRhiGraphicsPipeline::cbeginTargetBlends() const |
7235 | | \return a const iterator pointing to the first item in the render target blend setting list. |
7236 | | */ |
7237 | | |
7238 | | /*! |
7239 | | \fn const QRhiGraphicsPipeline::TargetBlend *QRhiGraphicsPipeline::cendTargetBlends() const |
7240 | | \return a const iterator pointing just after the last item in the render target blend setting list. |
7241 | | */ |
7242 | | |
7243 | | /*! |
7244 | | \fn const QRhiGraphicsPipeline::TargetBlend *QRhiGraphicsPipeline::targetBlendAt(qsizetype index) const |
7245 | | \return the render target blend setting at the specified \a index. |
7246 | | */ |
7247 | | |
7248 | | /*! |
7249 | | \fn qsizetype QRhiGraphicsPipeline::targetBlendCount() const |
7250 | | \return the number of render target blend settings. |
7251 | | */ |
7252 | | |
7253 | | /*! |
7254 | | \fn bool QRhiGraphicsPipeline::hasDepthTest() const |
7255 | | \return true if depth testing is enabled. |
7256 | | */ |
7257 | | |
7258 | | /*! |
7259 | | \fn void QRhiGraphicsPipeline::setDepthTest(bool enable) |
7260 | | |
7261 | | Enables or disables depth testing based on \a enable. Both depth test and |
7262 | | the writing out of depth data are disabled by default. |
7263 | | |
7264 | | \sa setDepthWrite() |
7265 | | */ |
7266 | | |
7267 | | /*! |
7268 | | \fn bool QRhiGraphicsPipeline::hasDepthWrite() const |
7269 | | \return true if depth write is enabled. |
7270 | | */ |
7271 | | |
7272 | | /*! |
7273 | | \fn void QRhiGraphicsPipeline::setDepthWrite(bool enable) |
7274 | | |
7275 | | Controls the writing out of depth data into the depth buffer based on |
7276 | | \a enable. By default this is disabled. Depth write is typically enabled |
7277 | | together with the depth test. |
7278 | | |
7279 | | \note Enabling depth write without having depth testing enabled may not |
7280 | | lead to the desired result, and should be avoided. |
7281 | | |
7282 | | \sa setDepthTest() |
7283 | | */ |
7284 | | |
7285 | | /*! |
7286 | | \fn bool QRhiGraphicsPipeline::hasDepthClamp() const |
7287 | | \return true if depth clamp is enabled. |
7288 | | |
7289 | | \since 6.11 |
7290 | | */ |
7291 | | |
7292 | | /*! |
7293 | | \fn void QRhiGraphicsPipeline::setDepthClamp(bool enable) |
7294 | | |
7295 | | Enables depth clamping when \a enable is true. When depth clamping is |
7296 | | enabled, primitives that would otherwise be clipped by the near or far |
7297 | | clip plane are rasterized and their depth values are clamped to the |
7298 | | depth range. When disabled (the default), such primitives are clipped. |
7299 | | |
7300 | | \note This setting is ignored when the QRhi::DepthClamp feature is |
7301 | | reported as unsupported. |
7302 | | |
7303 | | \since 6.11 |
7304 | | */ |
7305 | | |
7306 | | /*! |
7307 | | \fn QRhiGraphicsPipeline::CompareOp QRhiGraphicsPipeline::depthOp() const |
7308 | | \return the depth comparison function. |
7309 | | */ |
7310 | | |
7311 | | /*! |
7312 | | \fn void QRhiGraphicsPipeline::setDepthOp(CompareOp op) |
7313 | | Sets the depth comparison function \a op. |
7314 | | */ |
7315 | | |
7316 | | /*! |
7317 | | \fn bool QRhiGraphicsPipeline::hasStencilTest() const |
7318 | | \return true if stencil testing is enabled. |
7319 | | */ |
7320 | | |
7321 | | /*! |
7322 | | \fn void QRhiGraphicsPipeline::setStencilTest(bool enable) |
7323 | | Enables or disables stencil tests based on \a enable. |
7324 | | By default this is disabled. |
7325 | | */ |
7326 | | |
7327 | | /*! |
7328 | | \fn QRhiGraphicsPipeline::StencilOpState QRhiGraphicsPipeline::stencilFront() const |
7329 | | \return the current stencil test state for front faces. |
7330 | | */ |
7331 | | |
7332 | | /*! |
7333 | | \fn void QRhiGraphicsPipeline::setStencilFront(const StencilOpState &state) |
7334 | | Sets the stencil test \a state for front faces. |
7335 | | */ |
7336 | | |
7337 | | /*! |
7338 | | \fn QRhiGraphicsPipeline::StencilOpState QRhiGraphicsPipeline::stencilBack() const |
7339 | | \return the current stencil test state for back faces. |
7340 | | */ |
7341 | | |
7342 | | /*! |
7343 | | \fn void QRhiGraphicsPipeline::setStencilBack(const StencilOpState &state) |
7344 | | Sets the stencil test \a state for back faces. |
7345 | | */ |
7346 | | |
7347 | | /*! |
7348 | | \fn quint32 QRhiGraphicsPipeline::stencilReadMask() const |
7349 | | \return the currrent stencil read mask. |
7350 | | */ |
7351 | | |
7352 | | /*! |
7353 | | \fn void QRhiGraphicsPipeline::setStencilReadMask(quint32 mask) |
7354 | | Sets the stencil read \a mask. The default value is 0xFF. |
7355 | | */ |
7356 | | |
7357 | | /*! |
7358 | | \fn quint32 QRhiGraphicsPipeline::stencilWriteMask() const |
7359 | | \return the current stencil write mask. |
7360 | | */ |
7361 | | |
7362 | | /*! |
7363 | | \fn void QRhiGraphicsPipeline::setStencilWriteMask(quint32 mask) |
7364 | | Sets the stencil write \a mask. The default value is 0xFF. |
7365 | | */ |
7366 | | |
7367 | | /*! |
7368 | | \fn int QRhiGraphicsPipeline::sampleCount() const |
7369 | | \return the currently set sample count. 1 means no multisample antialiasing. |
7370 | | */ |
7371 | | |
7372 | | /*! |
7373 | | \fn void QRhiGraphicsPipeline::setSampleCount(int s) |
7374 | | |
7375 | | Sets the sample count. Typical values for \a s are 1, 4, or 8. The pipeline |
7376 | | must always be compatible with the render target, i.e. the sample counts |
7377 | | must match. |
7378 | | |
7379 | | \sa QRhi::supportedSampleCounts() |
7380 | | */ |
7381 | | |
7382 | | /*! |
7383 | | \fn float QRhiGraphicsPipeline::lineWidth() const |
7384 | | \return the currently set line width. The default is 1.0f. |
7385 | | */ |
7386 | | |
7387 | | /*! |
7388 | | \fn void QRhiGraphicsPipeline::setLineWidth(float width) |
7389 | | |
7390 | | Sets the line \a width. If the QRhi::WideLines feature is reported as |
7391 | | unsupported at runtime, values other than 1.0f are ignored. |
7392 | | */ |
7393 | | |
7394 | | /*! |
7395 | | \fn int QRhiGraphicsPipeline::depthBias() const |
7396 | | \return the currently set depth bias. |
7397 | | */ |
7398 | | |
7399 | | /*! |
7400 | | \fn void QRhiGraphicsPipeline::setDepthBias(int bias) |
7401 | | Sets the depth \a bias. The default value is 0. |
7402 | | */ |
7403 | | |
7404 | | /*! |
7405 | | \fn float QRhiGraphicsPipeline::slopeScaledDepthBias() const |
7406 | | \return the currently set slope scaled depth bias. |
7407 | | */ |
7408 | | |
7409 | | /*! |
7410 | | \fn void QRhiGraphicsPipeline::setSlopeScaledDepthBias(float bias) |
7411 | | Sets the slope scaled depth \a bias. The default value is 0. |
7412 | | */ |
7413 | | |
7414 | | /*! |
7415 | | \fn void QRhiGraphicsPipeline::setShaderStages(std::initializer_list<QRhiShaderStage> list) |
7416 | | Sets the \a list of shader stages. |
7417 | | */ |
7418 | | |
7419 | | /*! |
7420 | | \fn template<typename InputIterator> void QRhiGraphicsPipeline::setShaderStages(InputIterator first, InputIterator last) |
7421 | | Sets the list of shader stages from the iterators \a first and \a last. |
7422 | | */ |
7423 | | |
7424 | | /*! |
7425 | | \fn const QRhiShaderStage *QRhiGraphicsPipeline::cbeginShaderStages() const |
7426 | | \return a const iterator pointing to the first item in the shader stage list. |
7427 | | */ |
7428 | | |
7429 | | /*! |
7430 | | \fn const QRhiShaderStage *QRhiGraphicsPipeline::cendShaderStages() const |
7431 | | \return a const iterator pointing just after the last item in the shader stage list. |
7432 | | */ |
7433 | | |
7434 | | /*! |
7435 | | \fn const QRhiShaderStage *QRhiGraphicsPipeline::shaderStageAt(qsizetype index) const |
7436 | | \return the shader stage at the specified \a index. |
7437 | | */ |
7438 | | |
7439 | | /*! |
7440 | | \fn qsizetype QRhiGraphicsPipeline::shaderStageCount() const |
7441 | | \return the number of shader stages in this pipeline. |
7442 | | */ |
7443 | | |
7444 | | /*! |
7445 | | \fn QRhiVertexInputLayout QRhiGraphicsPipeline::vertexInputLayout() const |
7446 | | \return the currently set vertex input layout specification. |
7447 | | */ |
7448 | | |
7449 | | /*! |
7450 | | \fn void QRhiGraphicsPipeline::setVertexInputLayout(const QRhiVertexInputLayout &layout) |
7451 | | Specifies the vertex input \a layout. |
7452 | | */ |
7453 | | |
7454 | | /*! |
7455 | | \fn QRhiShaderResourceBindings *QRhiGraphicsPipeline::shaderResourceBindings() const |
7456 | | \return the currently associated QRhiShaderResourceBindings object. |
7457 | | */ |
7458 | | |
7459 | | /*! |
7460 | | \fn void QRhiGraphicsPipeline::setShaderResourceBindings(QRhiShaderResourceBindings *srb) |
7461 | | |
7462 | | Associates with \a srb describing the resource binding layout and the |
7463 | | resources (QRhiBuffer, QRhiTexture) themselves. The latter is optional, |
7464 | | because only the layout matters during pipeline creation. Therefore, the \a |
7465 | | srb passed in here can leave the actual buffer or texture objects |
7466 | | unspecified (\nullptr) as long as there is another, |
7467 | | \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible} |
7468 | | QRhiShaderResourceBindings bound via |
7469 | | \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} before |
7470 | | recording the draw calls. |
7471 | | */ |
7472 | | |
7473 | | /*! |
7474 | | \fn QRhiRenderPassDescriptor *QRhiGraphicsPipeline::renderPassDescriptor() const |
7475 | | \return the currently set QRhiRenderPassDescriptor. |
7476 | | */ |
7477 | | |
7478 | | /*! |
7479 | | \fn void QRhiGraphicsPipeline::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) |
7480 | | Associates with the specified QRhiRenderPassDescriptor \a desc. |
7481 | | */ |
7482 | | |
7483 | | /*! |
7484 | | \fn int QRhiGraphicsPipeline::patchControlPointCount() const |
7485 | | \return the currently set patch control point count. |
7486 | | */ |
7487 | | |
7488 | | /*! |
7489 | | \fn void QRhiGraphicsPipeline::setPatchControlPointCount(int count) |
7490 | | |
7491 | | Sets the number of patch control points to \a count. The default value is |
7492 | | 3. This is used only when the topology is set to \l Patches. |
7493 | | */ |
7494 | | |
7495 | | /*! |
7496 | | \fn QRhiGraphicsPipeline::PolygonMode QRhiGraphicsPipeline::polygonMode() const |
7497 | | \return the polygon mode. |
7498 | | */ |
7499 | | |
7500 | | /*! |
7501 | | \fn void QRhiGraphicsPipeline::setPolygonMode(PolygonMode mode) |
7502 | | Sets the polygon \a mode. The default is Fill. |
7503 | | |
7504 | | \sa QRhi::NonFillPolygonMode |
7505 | | */ |
7506 | | |
7507 | | /*! |
7508 | | \fn int QRhiGraphicsPipeline::multiViewCount() const |
7509 | | \return the view count. The default is 0, indicating no multiview rendering. |
7510 | | \since 6.7 |
7511 | | */ |
7512 | | |
7513 | | /*! |
7514 | | \fn void QRhiGraphicsPipeline::setMultiViewCount(int count) |
7515 | | Sets the view \a count for multiview rendering. The default is 0, |
7516 | | indicating no multiview rendering. |
7517 | | \a count must be 2 or larger to trigger multiview rendering. |
7518 | | |
7519 | | Multiview is only available when the \l{QRhi::MultiView}{MultiView feature} |
7520 | | is reported as supported. The render target must be a 2D texture array, and |
7521 | | the color attachment for the render target must have the same \a count set. |
7522 | | |
7523 | | See QRhiColorAttachment::setMultiViewCount() for further details on |
7524 | | multiview rendering. |
7525 | | |
7526 | | \since 6.7 |
7527 | | \sa QRhi::MultiView, QRhiColorAttachment::setMultiViewCount() |
7528 | | */ |
7529 | | |
7530 | | /*! |
7531 | | \class QRhiSwapChain |
7532 | | \inmodule QtGuiPrivate |
7533 | | \inheaderfile rhi/qrhi.h |
7534 | | \since 6.6 |
7535 | | \brief Swapchain resource. |
7536 | | |
7537 | | A swapchain enables presenting rendering results to a surface. A swapchain |
7538 | | is typically backed by a set of color buffers. Of these, one is displayed |
7539 | | at a time. |
7540 | | |
7541 | | Below is a typical pattern for creating and managing a swapchain and some |
7542 | | associated resources in order to render onto a QWindow: |
7543 | | |
7544 | | \code |
7545 | | void init() |
7546 | | { |
7547 | | sc = rhi->newSwapChain(); |
7548 | | ds = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, |
7549 | | QSize(), // no need to set the size here due to UsedWithSwapChainOnly |
7550 | | 1, |
7551 | | QRhiRenderBuffer::UsedWithSwapChainOnly); |
7552 | | sc->setWindow(window); |
7553 | | sc->setDepthStencil(ds); |
7554 | | rp = sc->newCompatibleRenderPassDescriptor(); |
7555 | | sc->setRenderPassDescriptor(rp); |
7556 | | resizeSwapChain(); |
7557 | | } |
7558 | | |
7559 | | void resizeSwapChain() |
7560 | | { |
7561 | | hasSwapChain = sc->createOrResize(); |
7562 | | } |
7563 | | |
7564 | | void render() |
7565 | | { |
7566 | | if (!hasSwapChain || notExposed) |
7567 | | return; |
7568 | | |
7569 | | if (sc->currentPixelSize() != sc->surfacePixelSize() || newlyExposed) { |
7570 | | resizeSwapChain(); |
7571 | | if (!hasSwapChain) |
7572 | | return; |
7573 | | newlyExposed = false; |
7574 | | } |
7575 | | |
7576 | | rhi->beginFrame(sc); |
7577 | | // ... |
7578 | | rhi->endFrame(sc); |
7579 | | } |
7580 | | \endcode |
7581 | | |
7582 | | Avoid relying on QWindow resize events to resize swapchains, especially |
7583 | | considering that surface sizes may not always fully match the QWindow |
7584 | | reported dimensions. The safe, cross-platform approach is to do the check |
7585 | | via surfacePixelSize() whenever starting a new frame. |
7586 | | |
7587 | | Releasing the swapchain must happen while the QWindow and the underlying |
7588 | | native window is fully up and running. Building on the previous example: |
7589 | | |
7590 | | \code |
7591 | | void releaseSwapChain() |
7592 | | { |
7593 | | if (hasSwapChain) { |
7594 | | sc->destroy(); |
7595 | | hasSwapChain = false; |
7596 | | } |
7597 | | } |
7598 | | |
7599 | | // assuming Window is our QWindow subclass |
7600 | | bool Window::event(QEvent *e) |
7601 | | { |
7602 | | switch (e->type()) { |
7603 | | case QEvent::UpdateRequest: // for QWindow::requestUpdate() |
7604 | | render(); |
7605 | | break; |
7606 | | case QEvent::PlatformSurface: |
7607 | | if (static_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) |
7608 | | releaseSwapChain(); |
7609 | | break; |
7610 | | default: |
7611 | | break; |
7612 | | } |
7613 | | return QWindow::event(e); |
7614 | | } |
7615 | | \endcode |
7616 | | |
7617 | | Initializing the swapchain and starting to render the first frame cannot |
7618 | | start at any time. The safe, cross-platform approach is to rely on expose |
7619 | | events. QExposeEvent is a loosely specified event that is sent whenever a |
7620 | | window gets mapped, obscured, and resized, depending on the platform. |
7621 | | |
7622 | | \code |
7623 | | void Window::exposeEvent(QExposeEvent *) |
7624 | | { |
7625 | | // initialize and start rendering when the window becomes usable for graphics purposes |
7626 | | if (isExposed() && !running) { |
7627 | | running = true; |
7628 | | init(); |
7629 | | } |
7630 | | |
7631 | | // stop pushing frames when not exposed or size becomes 0 |
7632 | | if ((!isExposed() || (hasSwapChain && sc->surfacePixelSize().isEmpty())) && running) |
7633 | | notExposed = true; |
7634 | | |
7635 | | // continue when exposed again and the surface has a valid size |
7636 | | if (isExposed() && running && notExposed && !sc->surfacePixelSize().isEmpty()) { |
7637 | | notExposed = false; |
7638 | | newlyExposed = true; |
7639 | | } |
7640 | | |
7641 | | if (isExposed() && !sc->surfacePixelSize().isEmpty()) |
7642 | | render(); |
7643 | | } |
7644 | | \endcode |
7645 | | |
7646 | | Once the rendering has started, a simple way to request a new frame is |
7647 | | QWindow::requestUpdate(). While on some platforms this is merely a small |
7648 | | timer, on others it has a specific implementation: for instance on macOS or |
7649 | | iOS it may be backed by |
7650 | | \l{https://developer.apple.com/documentation/corevideo/cvdisplaylink?language=objc}{CVDisplayLink}. |
7651 | | The example above is already prepared for update requests by handling |
7652 | | QEvent::UpdateRequest. |
7653 | | |
7654 | | While acting as a QRhiRenderTarget, QRhiSwapChain also manages a |
7655 | | QRhiCommandBuffer. Calling QRhi::endFrame() submits the recorded commands |
7656 | | and also enqueues a \c present request. The default behavior is to do this |
7657 | | with a swap interval of 1, meaning synchronizing to the display's vertical |
7658 | | refresh is enabled. Thus the rendering thread calling beginFrame() and |
7659 | | endFrame() will get throttled to vsync. On some backends this can be |
7660 | | disabled by passing QRhiSwapChain:NoVSync in flags(). |
7661 | | |
7662 | | Multisampling (MSAA) is handled transparently to the applications when |
7663 | | requested via setSampleCount(). Where applicable, QRhiSwapChain will take |
7664 | | care of creating additional color buffers and issuing a multisample resolve |
7665 | | command at the end of a frame. For OpenGL, it is necessary to request the |
7666 | | appropriate sample count also via QSurfaceFormat, by calling |
7667 | | QSurfaceFormat::setDefaultFormat() before initializing the QRhi. |
7668 | | |
7669 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
7670 | | for details. |
7671 | | */ |
7672 | | |
7673 | | /*! |
7674 | | \enum QRhiSwapChain::Flag |
7675 | | Flag values to describe swapchain properties |
7676 | | |
7677 | | \value SurfaceHasPreMulAlpha Indicates that the target surface has |
7678 | | transparency with premultiplied alpha. For example, this is what Qt Quick |
7679 | | uses when the alpha channel is enabled on the target QWindow, because the |
7680 | | scenegraph rendrerer always outputs fragments with alpha multiplied into |
7681 | | the red, green, and blue values. To ensure identical behavior across |
7682 | | platforms, always set QSurfaceFormat::alphaBufferSize() to a non-zero value |
7683 | | on the target QWindow whenever this flag is set on the swapchain. |
7684 | | |
7685 | | \value SurfaceHasNonPreMulAlpha Indicates the target surface has |
7686 | | transparency with non-premultiplied alpha. Be aware that this may not be |
7687 | | supported on some systems, if the system compositor always expects content |
7688 | | with premultiplied alpha. In that case the behavior with this flag set is |
7689 | | expected to be equivalent to SurfaceHasPreMulAlpha. |
7690 | | |
7691 | | \value sRGB Requests to pick an sRGB format for the swapchain's color |
7692 | | buffers and/or render target views, where applicable. Note that this |
7693 | | implies that sRGB framebuffer update and blending will get enabled for all |
7694 | | content targeting this swapchain, and opting out is not possible. For |
7695 | | OpenGL, set \l{QSurfaceFormat::sRGBColorSpace}{sRGBColorSpace} on the |
7696 | | QSurfaceFormat of the QWindow in addition. Applicable only when the |
7697 | | swapchain format is set to QRhiSwapChain::SDR. |
7698 | | |
7699 | | \value UsedAsTransferSource Indicates the swapchain will be used as the |
7700 | | source of a readback in QRhiResourceUpdateBatch::readBackTexture(). |
7701 | | |
7702 | | \value NoVSync Requests disabling waiting for vertical sync, also avoiding |
7703 | | throttling the rendering thread. The behavior is backend specific and |
7704 | | applicable only where it is possible to control this. Some may ignore the |
7705 | | request altogether. For OpenGL, try instead setting the swap interval to 0 |
7706 | | on the QWindow via QSurfaceFormat::setSwapInterval(). |
7707 | | |
7708 | | \value MinimalBufferCount Requests creating the swapchain with the minimum |
7709 | | number of buffers, which is in practice 2, unless the graphics |
7710 | | implementation has a higher minimum number than that. Only applicable with |
7711 | | backends where such control is available via the graphics API, for example, |
7712 | | Vulkan. By default it is up to the backend to decide what number of buffers |
7713 | | it requests (in practice this is almost always either 2 or 3), and it is |
7714 | | not the applications' concern. However, on Vulkan for instance the backend |
7715 | | will likely prefer the higher number (3), for example to avoid odd |
7716 | | performance issues with some Vulkan implementations on mobile devices. It |
7717 | | could be that on some platforms it can prove to be beneficial to force the |
7718 | | lower buffer count (2), so this flag allows forcing that. Note that all |
7719 | | this has no effect on the number of frames kept in flight, so the CPU |
7720 | | (QRhi) will still prepare frames at most \c{N - 1} frames ahead of the GPU, |
7721 | | even when the swapchain image buffer count larger than \c N. (\c{N} = |
7722 | | QRhi::FramesInFlight and typically 2). |
7723 | | */ |
7724 | | |
7725 | | /*! |
7726 | | \enum QRhiSwapChain::Format |
7727 | | Describes the swapchain format. The default format is SDR. |
7728 | | |
7729 | | This enum is used with |
7730 | | \l{QRhiSwapChain::isFormatSupported()}{isFormatSupported()} to check |
7731 | | upfront if creating the swapchain with the given format is supported by the |
7732 | | platform and the window's associated screen, and with |
7733 | | \l{QRhiSwapChain::setFormat()}{setFormat()} |
7734 | | to set the requested format in the swapchain before calling |
7735 | | \l{QRhiSwapChain::createOrResize()}{createOrResize()} for the first time. |
7736 | | |
7737 | | \value SDR 8-bit RGBA or BGRA, depending on the backend and platform. With |
7738 | | OpenGL ES in particular, it could happen that the platform provides less |
7739 | | than 8 bits (e.g. due to EGL and the QSurfaceFormat choosing a 565 or 444 |
7740 | | format - this is outside the control of QRhi). Standard dynamic range. May |
7741 | | be combined with setting the QRhiSwapChain::sRGB flag. |
7742 | | |
7743 | | \value HDRExtendedSrgbLinear 16-bit float RGBA, high dynamic range, |
7744 | | extended linear sRGB (scRGB) color space. This involves Rec. 709 primaries |
7745 | | (same as SDR/sRGB) and linear colors. Conversion to the display's native |
7746 | | color space (such as, HDR10) is performed by the windowing system. On |
7747 | | Windows this is the canonical color space of the system compositor, and is |
7748 | | the recommended format for HDR swapchains in general on desktop platforms. |
7749 | | |
7750 | | \value HDR10 10-bit unsigned int RGB or BGR with 2 bit alpha, high dynamic |
7751 | | range, HDR10 (Rec. 2020) color space with an ST2084 PQ transfer function. |
7752 | | |
7753 | | \value HDRExtendedDisplayP3Linear 16-bit float RGBA, high dynamic range, |
7754 | | extended linear Display P3 color space. The primary choice for HDR on |
7755 | | platforms such as iOS and VisionOS. |
7756 | | */ |
7757 | | |
7758 | | /*! |
7759 | | \internal |
7760 | | */ |
7761 | | QRhiSwapChain::QRhiSwapChain(QRhiImplementation *rhi) |
7762 | 0 | : QRhiResource(rhi) |
7763 | 0 | { |
7764 | 0 | } |
7765 | | |
7766 | | /*! |
7767 | | \return the resource type. |
7768 | | */ |
7769 | | QRhiResource::Type QRhiSwapChain::resourceType() const |
7770 | 0 | { |
7771 | 0 | return SwapChain; |
7772 | 0 | } |
7773 | | |
7774 | | /*! |
7775 | | \fn QSize QRhiSwapChain::currentPixelSize() const |
7776 | | |
7777 | | \return the size with which the swapchain was last successfully built. Use |
7778 | | this to decide if createOrResize() needs to be called again: if |
7779 | | \c{currentPixelSize() != surfacePixelSize()} then the swapchain needs to be |
7780 | | resized. |
7781 | | |
7782 | | \note Typical rendering logic will call this function to get the output |
7783 | | size when starting to prepare a new frame, and base dependent calculations |
7784 | | (such as, the viewport) on the size returned from this function. |
7785 | | |
7786 | | While in many cases the value is the same as \c{QWindow::size() * |
7787 | | QWindow::devicePixelRatio()}, relying on the QWindow-reported size is not |
7788 | | guaranteed to be correct on all platforms and graphics API implementations. |
7789 | | Using this function is therefore strongly recommended whenever there is a |
7790 | | need to identify the dimensions, in pixels, of the output layer or surface. |
7791 | | |
7792 | | This also has the added benefit of avoiding potential data races when QRhi |
7793 | | is used on a dedicated rendering thread, because the need to call QWindow |
7794 | | functions, that may then access data updated on the main thread, is |
7795 | | avoided. |
7796 | | |
7797 | | \sa surfacePixelSize() |
7798 | | */ |
7799 | | |
7800 | | /*! |
7801 | | \fn virtual QSize QRhiSwapChain::surfacePixelSize() = 0 |
7802 | | |
7803 | | \return The size of the window's associated surface or layer. |
7804 | | |
7805 | | \warning Do not assume this is the same as \c{QWindow::size() * |
7806 | | QWindow::devicePixelRatio()}. With some graphics APIs and windowing system |
7807 | | interfaces (for example, Vulkan) there is a theoretical possibility for a |
7808 | | surface to assume a size different from the associated window. To support |
7809 | | these cases, \b{rendering logic must always base size-derived calculations |
7810 | | (such as, viewports) on the size reported from QRhiSwapChain, and never on |
7811 | | the size queried from QWindow}. |
7812 | | |
7813 | | \note \b{Can also be called before createOrResize(), if at least window() is |
7814 | | already set. This in combination with currentPixelSize() allows to detect |
7815 | | when a swapchain needs to be resized.} However, watch out for the fact that |
7816 | | the size of the underlying native object (surface, layer, or similar) is |
7817 | | "live", so whenever this function is called, it returns the latest value |
7818 | | reported by the underlying implementation, without any atomicity guarantee. |
7819 | | Therefore, using this function to determine pixel sizes for graphics |
7820 | | resources that are used in a frame is strongly discouraged. Rely on |
7821 | | currentPixelSize() instead which returns a size that is atomic and will not |
7822 | | change between createOrResize() invocations. |
7823 | | |
7824 | | \note For depth-stencil buffers used in combination with the swapchain's |
7825 | | color buffers, it is strongly recommended to rely on the automatic sizing |
7826 | | and rebuilding behavior provided by the |
7827 | | QRhiRenderBuffer:UsedWithSwapChainOnly flag. Avoid querying the surface |
7828 | | size via this function just to get a size that can be passed to |
7829 | | QRhiRenderBuffer::setPixelSize() as that would suffer from the lack of |
7830 | | atomicity as described above. |
7831 | | |
7832 | | \sa currentPixelSize() |
7833 | | */ |
7834 | | |
7835 | | /*! |
7836 | | \fn virtual bool QRhiSwapChain::isFormatSupported(Format f) = 0 |
7837 | | |
7838 | | \return true if the given swapchain format \a f is supported. SDR is always |
7839 | | supported. |
7840 | | |
7841 | | \note Can be called independently of createOrResize(), but window() must |
7842 | | already be set. Calling without the window set may lead to unexpected |
7843 | | results depending on the backend and platform (most likely false for any |
7844 | | HDR format), because HDR format support is usually tied to the output |
7845 | | (screen) to which the swapchain's associated window belongs at any given |
7846 | | time. If the result is true for a HDR format, then creating the swapchain |
7847 | | with that format is expected to succeed as long as the window is not moved |
7848 | | to another screen in the meantime. |
7849 | | |
7850 | | The main use of this function is to call it before the first |
7851 | | createOrResize() after the window is already set. This allow the QRhi |
7852 | | backends to perform platform or windowing system specific queries to |
7853 | | determine if the window (and the screen it is on) is capable of true HDR |
7854 | | output with the specified format. |
7855 | | |
7856 | | When the format is reported as supported, call setFormat() to set the |
7857 | | requested format and call createOrResize(). Be aware of the consequences |
7858 | | however: successfully requesting a HDR format will involve having to deal |
7859 | | with a different color space, possibly doing white level correction for |
7860 | | non-HDR-aware content, adjusting tonemapping methods, adjusting offscreen |
7861 | | render target settings, etc. |
7862 | | |
7863 | | \sa setFormat() |
7864 | | */ |
7865 | | |
7866 | | /*! |
7867 | | \fn virtual QRhiCommandBuffer *QRhiSwapChain::currentFrameCommandBuffer() = 0 |
7868 | | |
7869 | | \return a command buffer on which rendering commands and resource updates |
7870 | | can be recorded within a \l{QRhi::beginFrame()}{beginFrame} - |
7871 | | \l{QRhi::endFrame()}{endFrame} block, assuming beginFrame() was called with |
7872 | | this swapchain. |
7873 | | |
7874 | | \note The returned object is valid also after endFrame(), up until the next |
7875 | | beginFrame(), but the returned command buffer should not be used to record |
7876 | | any commands then. Rather, it can be used to query data collected during |
7877 | | the frame (or previous frames), for example by calling |
7878 | | \l{QRhiCommandBuffer::lastCompletedGpuTime()}{lastCompletedGpuTime()}. |
7879 | | |
7880 | | \note The value must not be cached and reused between frames. The caller |
7881 | | should not hold on to the returned object once |
7882 | | \l{QRhi::beginFrame()}{beginFrame()} is called again. Instead, the command |
7883 | | buffer object should be queried again by calling this function. |
7884 | | */ |
7885 | | |
7886 | | /*! |
7887 | | \fn virtual QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget() = 0 |
7888 | | |
7889 | | \return a render target that can used with beginPass() in order to render |
7890 | | the swapchain's current backbuffer. Only valid within a |
7891 | | QRhi::beginFrame() - QRhi::endFrame() block where beginFrame() was called |
7892 | | with this swapchain. |
7893 | | |
7894 | | \note the value must not be cached and reused between frames |
7895 | | */ |
7896 | | |
7897 | | /*! |
7898 | | \enum QRhiSwapChain::StereoTargetBuffer |
7899 | | Selects the backbuffer to use with a stereoscopic swapchain. |
7900 | | |
7901 | | \value LeftBuffer |
7902 | | \value RightBuffer |
7903 | | */ |
7904 | | |
7905 | | /*! |
7906 | | \return a render target that can be used with beginPass() in order to |
7907 | | render to the swapchain's left or right backbuffer. This overload should be |
7908 | | used only with stereoscopic rendering, that is, when the associated QWindow |
7909 | | is backed by two color buffers, one for each eye, instead of just one. |
7910 | | |
7911 | | When stereoscopic rendering is not supported, the return value will be |
7912 | | the default target. It is supported by all hardware backends except for Metal, in |
7913 | | combination with \l QSurfaceFormat::StereoBuffers, assuming it is supported |
7914 | | by the graphics and display driver stack at run time. Metal and Null backends |
7915 | | are going to return the default render target from this overload. |
7916 | | |
7917 | | \note the value must not be cached and reused between frames |
7918 | | */ |
7919 | | QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer) |
7920 | 0 | { |
7921 | 0 | Q_UNUSED(targetBuffer); |
7922 | 0 | return currentFrameRenderTarget(); |
7923 | 0 | } |
7924 | | |
7925 | | /*! |
7926 | | \fn virtual bool QRhiSwapChain::createOrResize() = 0 |
7927 | | |
7928 | | Creates the swapchain if not already done and resizes the swapchain buffers |
7929 | | to match the current size of the targeted surface. Call this whenever the |
7930 | | size of the target surface is different than before. |
7931 | | |
7932 | | \note call destroy() only when the swapchain needs to be released |
7933 | | completely, typically upon |
7934 | | QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed. To perform resizing, just |
7935 | | call createOrResize(). |
7936 | | |
7937 | | \return \c true when successful, \c false when a graphics operation failed. |
7938 | | Regardless of the return value, calling destroy() is always safe. |
7939 | | */ |
7940 | | |
7941 | | /*! |
7942 | | \fn QWindow *QRhiSwapChain::window() const |
7943 | | \return the currently set window. |
7944 | | */ |
7945 | | |
7946 | | /*! |
7947 | | \fn void QRhiSwapChain::setWindow(QWindow *window) |
7948 | | Sets the \a window. |
7949 | | */ |
7950 | | |
7951 | | /*! |
7952 | | \fn QRhiSwapChainProxyData QRhiSwapChain::proxyData() const |
7953 | | \return the currently set proxy data. |
7954 | | */ |
7955 | | |
7956 | | /*! |
7957 | | \fn void QRhiSwapChain::setProxyData(const QRhiSwapChainProxyData &d) |
7958 | | Sets the proxy data \a d. |
7959 | | |
7960 | | \sa QRhi::updateSwapChainProxyData() |
7961 | | */ |
7962 | | |
7963 | | /*! |
7964 | | \fn QRhiSwapChain::Flags QRhiSwapChain::flags() const |
7965 | | \return the currently set flags. |
7966 | | */ |
7967 | | |
7968 | | /*! |
7969 | | \fn void QRhiSwapChain::setFlags(Flags f) |
7970 | | Sets the flags \a f. |
7971 | | */ |
7972 | | |
7973 | | /*! |
7974 | | \fn QRhiSwapChain::Format QRhiSwapChain::format() const |
7975 | | \return the currently set format. |
7976 | | */ |
7977 | | |
7978 | | /*! |
7979 | | \fn void QRhiSwapChain::setFormat(Format f) |
7980 | | Sets the format \a f. |
7981 | | |
7982 | | Avoid setting formats that are reported as unsupported from |
7983 | | isFormatSupported(). Note that support for a given format may depend on the |
7984 | | screen the swapchain's associated window is opened on. On some platforms, |
7985 | | such as Windows and macOS, for HDR output to work it is necessary to have |
7986 | | HDR output enabled in the display settings. |
7987 | | |
7988 | | See isFormatSupported(), \l QRhiSwapChainHdrInfo, and \l Format for more |
7989 | | information on high dynamic range output. |
7990 | | */ |
7991 | | |
7992 | | /*! |
7993 | | \fn QRhiRenderBuffer *QRhiSwapChain::depthStencil() const |
7994 | | \return the currently associated renderbuffer for depth-stencil. |
7995 | | */ |
7996 | | |
7997 | | /*! |
7998 | | \fn void QRhiSwapChain::setDepthStencil(QRhiRenderBuffer *ds) |
7999 | | Sets the renderbuffer \a ds for use as a depth-stencil buffer. |
8000 | | */ |
8001 | | |
8002 | | /*! |
8003 | | \fn int QRhiSwapChain::sampleCount() const |
8004 | | \return the currently set sample count. 1 means no multisample antialiasing. |
8005 | | */ |
8006 | | |
8007 | | /*! |
8008 | | \fn void QRhiSwapChain::setSampleCount(int samples) |
8009 | | |
8010 | | Sets the sample count. Common values for \a samples are 1 (no MSAA), 4 (4x |
8011 | | MSAA), or 8 (8x MSAA). |
8012 | | |
8013 | | \sa QRhi::supportedSampleCounts() |
8014 | | */ |
8015 | | |
8016 | | /*! |
8017 | | \fn QRhiRenderPassDescriptor *QRhiSwapChain::renderPassDescriptor() const |
8018 | | \return the currently associated QRhiRenderPassDescriptor object. |
8019 | | */ |
8020 | | |
8021 | | /*! |
8022 | | \fn void QRhiSwapChain::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) |
8023 | | Associates with the QRhiRenderPassDescriptor \a desc. |
8024 | | */ |
8025 | | |
8026 | | /*! |
8027 | | \fn virtual QRhiRenderPassDescriptor *QRhiSwapChain::newCompatibleRenderPassDescriptor() = 0; |
8028 | | |
8029 | | \return a new QRhiRenderPassDescriptor that is compatible with this swapchain. |
8030 | | |
8031 | | The returned value is used in two ways: it can be passed to |
8032 | | setRenderPassDescriptor() and |
8033 | | QRhiGraphicsPipeline::setRenderPassDescriptor(). A render pass descriptor |
8034 | | describes the attachments (color, depth/stencil) and the load/store |
8035 | | behavior that can be affected by flags(). A QRhiGraphicsPipeline can only |
8036 | | be used in combination with a swapchain that has a |
8037 | | \l{QRhiRenderPassDescriptor::isCompatible()}{compatible} |
8038 | | QRhiRenderPassDescriptor set. |
8039 | | |
8040 | | \sa createOrResize() |
8041 | | */ |
8042 | | |
8043 | | /*! |
8044 | | \fn QRhiShadingRateMap *QRhiSwapChain::shadingRateMap() const |
8045 | | \return the currently set QRhiShadingRateMap. By default this is \nullptr. |
8046 | | \since 6.9 |
8047 | | */ |
8048 | | |
8049 | | /*! |
8050 | | \fn void QRhiSwapChain::setShadingRateMap(QRhiShadingRateMap *map) |
8051 | | |
8052 | | Associates with the specified QRhiShadingRateMap \a map. This is functional |
8053 | | only when the \l QRhi::VariableRateShadingMap feature is reported as |
8054 | | supported. |
8055 | | |
8056 | | When QRhiCommandBuffer::setShadingRate() is also called, the higher of the |
8057 | | two shading rates is used for each tile. There is currently no control |
8058 | | offered over the combiner behavior. |
8059 | | |
8060 | | \note Setting a shading rate map implies that a different, new |
8061 | | QRhiRenderPassDescriptor is needed and some of the native swapchain objects |
8062 | | must be rebuilt. Therefore, if the swapchain is already set up, call |
8063 | | newCompatibleRenderPassDescriptor() and setRenderPassDescriptor() right |
8064 | | after setShadingRateMap(). Then, createOrResize() must also be called again. |
8065 | | This has rolling consequences, for example for graphics pipelines: those |
8066 | | also need to be associated with the new QRhiRenderPassDescriptor and then |
8067 | | rebuilt. See \l QRhiRenderPassDescriptor::serializedFormat() for some |
8068 | | suggestions on how to deal with this. Remember to set the |
8069 | | QRhiGraphicsPipeline::UsesShadingRate flag for them as well. |
8070 | | |
8071 | | \since 6.9 |
8072 | | */ |
8073 | | |
8074 | | /*! |
8075 | | \struct QRhiSwapChainHdrInfo |
8076 | | \inmodule QtGuiPrivate |
8077 | | \inheaderfile rhi/qrhi.h |
8078 | | \since 6.6 |
8079 | | |
8080 | | \brief Describes the high dynamic range related information of the |
8081 | | swapchain's associated output. |
8082 | | |
8083 | | To perform HDR-compatible tonemapping, where the target range is not [0,1], |
8084 | | one often needs to know the maximum luminance of the display the |
8085 | | swapchain's window is associated with. While this is often made |
8086 | | user-configurable (think brightness, gamma and similar settings in games), |
8087 | | it can be highly useful to set defaults based on the values reported by the |
8088 | | display itself, thus providing a decent starting point. |
8089 | | |
8090 | | There are some problems however: the information is exposed in different |
8091 | | forms on different platforms, whereas with cross-platform graphics APIs |
8092 | | there is often no associated solution at all, because managing such |
8093 | | information is not in the scope of the API (and may rather be retrievable |
8094 | | via other platform-specific means, if any). |
8095 | | |
8096 | | With Metal on macOS/iOS, there is no luminance values exposed in the |
8097 | | platform APIs. Instead, the maximum color component value, that would be |
8098 | | 1.0 in a non-HDR setup, is provided. The \c limitsType field indicates what |
8099 | | kind of information is available. It is then up to the clients of QRhi to |
8100 | | access the correct data from the \c limits union and use it as they see |
8101 | | fit. |
8102 | | |
8103 | | With an API like Vulkan, where there is no way to get such information, the |
8104 | | values are always the built-in defaults. |
8105 | | |
8106 | | Therefore, the struct returned from QRhiSwapChain::hdrInfo() contains |
8107 | | either some hard-coded defaults or real values received from an API such as |
8108 | | DXGI (IDXGIOutput6) or Cocoa (NSScreen). When no platform queries are |
8109 | | available (or needs using platform facilities out of scope for QRhi), the |
8110 | | hard-coded defaults are a maximum luminance of 1000 nits and an SDR white |
8111 | | level of 200. |
8112 | | |
8113 | | The struct also exposes the presumed luminance behavior of the platform and |
8114 | | its compositor, to indicate what a color component value of 1.0 is treated |
8115 | | as in a HDR color buffer. In some cases it will be necessary to perform |
8116 | | color correction of non-HDR content composited with HDR content. To enable |
8117 | | this, the SDR white level is queried from the system on some platforms |
8118 | | (Windows) and exposed here. |
8119 | | |
8120 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
8121 | | for details. |
8122 | | |
8123 | | \sa QRhiSwapChain::hdrInfo() |
8124 | | */ |
8125 | | |
8126 | | /*! |
8127 | | \enum QRhiSwapChainHdrInfo::LimitsType |
8128 | | |
8129 | | \value LuminanceInNits Indicates that the \l limits union has its |
8130 | | \c luminanceInNits struct set |
8131 | | |
8132 | | \value ColorComponentValue Indicates that the \l limits union has its |
8133 | | \c colorComponentValue struct set |
8134 | | */ |
8135 | | |
8136 | | /*! |
8137 | | \enum QRhiSwapChainHdrInfo::LuminanceBehavior |
8138 | | |
8139 | | \value SceneReferred Indicates that the color value of 1.0 is interpreted |
8140 | | as 80 nits. This is the behavior of HDR-enabled windows with the Windows |
8141 | | compositor. See |
8142 | | \l{https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range}{this |
8143 | | page} for more information on HDR on Windows. |
8144 | | |
8145 | | \value DisplayReferred Indicates that the color value of 1.0 is interpreted |
8146 | | as the value of the SDR white. (which can be e.g. 200 nits, but will vary |
8147 | | depending on screen brightness) This is the behavior of HDR-enabled windows |
8148 | | on Apple platforms. See |
8149 | | \l{https://developer.apple.com/documentation/metal/hdr_content/displaying_hdr_content_in_a_metal_layer}{this |
8150 | | page} for more information on Apple's EDR system. |
8151 | | */ |
8152 | | |
8153 | | /*! |
8154 | | \variable QRhiSwapChainHdrInfo::limitsType |
8155 | | |
8156 | | With Metal on macOS/iOS, there is no luminance values exposed in the |
8157 | | platform APIs. Instead, the maximum color component value, that would be |
8158 | | 1.0 in a non-HDR setup, is provided. This value indicates what kind of |
8159 | | information is available in \l limits. |
8160 | | |
8161 | | \sa QRhiSwapChain::hdrInfo() |
8162 | | */ |
8163 | | |
8164 | | /*! |
8165 | | \variable QRhiSwapChainHdrInfo::limits |
8166 | | |
8167 | | Contains the actual values queried from the graphics API or the platform. |
8168 | | The type of data is indicated by \l limitsType. This is therefore a union. |
8169 | | There are currently two options: |
8170 | | |
8171 | | Luminance values in nits: |
8172 | | |
8173 | | \code |
8174 | | struct { |
8175 | | float minLuminance; |
8176 | | float maxLuminance; |
8177 | | } luminanceInNits; |
8178 | | \endcode |
8179 | | |
8180 | | On Windows the minimum and maximum luminance depends on the screen |
8181 | | brightness. While not relevant for desktops, on laptops the screen |
8182 | | brightness may change at any time. Increasing brightness implies decreased |
8183 | | maximum luminance. In addition, the results may also be dependent on the |
8184 | | HDR Content Brightness set in Windows Settings' System/Display/HDR view, |
8185 | | if there is such a setting. |
8186 | | |
8187 | | Note however that the changes made to the laptop screen's brightness or in |
8188 | | the system settings while the application is running are not necessarily |
8189 | | reflected in the returned values, meaning calling hdrInfo() again may still |
8190 | | return the same luminance range as before for the rest of the process' |
8191 | | lifetime. The exact behavior is up to DXGI and Qt has no control over it. |
8192 | | |
8193 | | \note The Windows compositor works in scene-referred mode for HDR content. |
8194 | | A color component value of 1.0 corresponds to a luminance of 80 nits. When |
8195 | | rendering non-HDR content (e.g. 2D UI elements), the correction of the |
8196 | | white level is often necessary. (e.g., outputting the fragment color (1, 1, |
8197 | | 1) will likely lead to showing a shade of white that is too dim on-screen) |
8198 | | See \l sdrWhiteLevel. |
8199 | | |
8200 | | For macOS/iOS, the current maximum and potential maximum color |
8201 | | component values are provided: |
8202 | | |
8203 | | \code |
8204 | | struct { |
8205 | | float maxColorComponentValue; |
8206 | | float maxPotentialColorComponentValue; |
8207 | | } colorComponentValue; |
8208 | | \endcode |
8209 | | |
8210 | | The value may depend on the screen brightness, which on laptops means that |
8211 | | the result may change in the next call to hdrInfo() if the brightness was |
8212 | | changed in the meantime. The maximum screen brightness implies a maximum |
8213 | | color value of 1.0. |
8214 | | |
8215 | | \note Apple's EDR is display-referred. 1.0 corresponds to a luminance level |
8216 | | of SDR white (e.g. 200 nits), the value of which varies based on the screen |
8217 | | brightness and possibly other settings. The exact luminance value for that, |
8218 | | or the maximum luminance of the display, are not exposed to the |
8219 | | applications. |
8220 | | |
8221 | | \note It has been observed that the color component values are not set to |
8222 | | the correct larger-than-1 value right away on startup on some macOS |
8223 | | systems, but the values tend to change during or after the first frame. |
8224 | | |
8225 | | \sa QRhiSwapChain::hdrInfo() |
8226 | | */ |
8227 | | |
8228 | | /*! |
8229 | | \variable QRhiSwapChainHdrInfo::luminanceBehavior |
8230 | | |
8231 | | Describes the platform's presumed behavior with regards to color values. |
8232 | | |
8233 | | \sa sdrWhiteLevel |
8234 | | */ |
8235 | | |
8236 | | /*! |
8237 | | \variable QRhiSwapChainHdrInfo::sdrWhiteLevel |
8238 | | |
8239 | | On Windows this is the dynamic SDR white level in nits. The value is |
8240 | | dependent on the screen brightness (on laptops), and the SDR or HDR Content |
8241 | | Brightness settings in the Windows settings' System/Display/HDR view. |
8242 | | |
8243 | | To perform white level correction for non-HDR (SDR) content, such as 2D UI |
8244 | | elemenents, multiply the final color with sdrWhiteLevel / 80.0 whenever |
8245 | | \l luminanceBehavior is SceneReferred. (assuming Windows and a linear |
8246 | | extended sRGB (scRGB) color space) |
8247 | | |
8248 | | On other platforms the value is always a pre-defined value, 200. This may |
8249 | | not match the system's actual SDR white level, but the value of this |
8250 | | variable is not relevant in practice when the \l luminanceBehavior is |
8251 | | DisplayReferred, because then the color component value of 1.0 refers to |
8252 | | the SDR white by default. |
8253 | | |
8254 | | \sa luminanceBehavior |
8255 | | */ |
8256 | | |
8257 | | /*! |
8258 | | \return the HDR information for the associated display. |
8259 | | |
8260 | | Do not assume that this is a cheap operation. Depending on the platform, |
8261 | | this function makes various platform queries which may have a performance |
8262 | | impact. |
8263 | | |
8264 | | \note Can be called before createOrResize() as long as the window is |
8265 | | \l{setWindow()}{set}. |
8266 | | |
8267 | | \note What happens when moving a window with an initialized swapchain |
8268 | | between displays (HDR to HDR with different characteristics, HDR to SDR, |
8269 | | etc.) is not currently well-defined and depends heavily on the windowing |
8270 | | system and compositor, with potentially varying behavior between platforms. |
8271 | | Currently QRhi only guarantees that hdrInfo() returns valid data, if |
8272 | | available, for the display to which the swapchain's associated window |
8273 | | belonged at the time of createOrResize(). |
8274 | | |
8275 | | \sa QRhiSwapChainHdrInfo |
8276 | | */ |
8277 | | QRhiSwapChainHdrInfo QRhiSwapChain::hdrInfo() |
8278 | 0 | { |
8279 | 0 | QRhiSwapChainHdrInfo info; |
8280 | 0 | info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits; |
8281 | 0 | info.limits.luminanceInNits.minLuminance = 0.0f; |
8282 | 0 | info.limits.luminanceInNits.maxLuminance = 1000.0f; |
8283 | 0 | info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred; |
8284 | 0 | info.sdrWhiteLevel = 200.0f; |
8285 | 0 | return info; |
8286 | 0 | } |
8287 | | |
8288 | | #ifndef QT_NO_DEBUG_STREAM |
8289 | | QDebug operator<<(QDebug dbg, const QRhiSwapChainHdrInfo &info) |
8290 | 0 | { |
8291 | 0 | QDebugStateSaver saver(dbg); |
8292 | 0 | dbg.nospace() << "QRhiSwapChainHdrInfo("; |
8293 | 0 | switch (info.limitsType) { |
8294 | 0 | case QRhiSwapChainHdrInfo::LuminanceInNits: |
8295 | 0 | dbg.nospace() << " minLuminance=" << info.limits.luminanceInNits.minLuminance |
8296 | 0 | << " maxLuminance=" << info.limits.luminanceInNits.maxLuminance; |
8297 | 0 | break; |
8298 | 0 | case QRhiSwapChainHdrInfo::ColorComponentValue: |
8299 | 0 | dbg.nospace() << " maxColorComponentValue=" << info.limits.colorComponentValue.maxColorComponentValue; |
8300 | 0 | dbg.nospace() << " maxPotentialColorComponentValue=" << info.limits.colorComponentValue.maxPotentialColorComponentValue; |
8301 | 0 | break; |
8302 | 0 | } |
8303 | 0 | switch (info.luminanceBehavior) { |
8304 | 0 | case QRhiSwapChainHdrInfo::SceneReferred: |
8305 | 0 | dbg.nospace() << " scene-referred, SDR white level=" << info.sdrWhiteLevel; |
8306 | 0 | break; |
8307 | 0 | case QRhiSwapChainHdrInfo::DisplayReferred: |
8308 | 0 | dbg.nospace() << " display-referred"; |
8309 | 0 | break; |
8310 | 0 | } |
8311 | 0 | dbg.nospace() << ')'; |
8312 | 0 | return dbg; |
8313 | 0 | } |
8314 | | #endif |
8315 | | |
8316 | | /*! |
8317 | | \class QRhiComputePipeline |
8318 | | \inmodule QtGuiPrivate |
8319 | | \inheaderfile rhi/qrhi.h |
8320 | | \since 6.6 |
8321 | | \brief Compute pipeline state resource. |
8322 | | |
8323 | | \note Setting the shader resource bindings is mandatory. The referenced |
8324 | | QRhiShaderResourceBindings must already have created() called on it by the |
8325 | | time create() is called. |
8326 | | |
8327 | | \note Setting the shader is mandatory. |
8328 | | |
8329 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
8330 | | for details. |
8331 | | */ |
8332 | | |
8333 | | /*! |
8334 | | \enum QRhiComputePipeline::Flag |
8335 | | |
8336 | | Flag values for describing pipeline options. |
8337 | | |
8338 | | \value CompileShadersWithDebugInfo Requests compiling shaders with debug |
8339 | | information enabled, when applicable. See |
8340 | | QRhiGraphicsPipeline::CompileShadersWithDebugInfo for more information. |
8341 | | */ |
8342 | | |
8343 | | /*! |
8344 | | \return the resource type. |
8345 | | */ |
8346 | | QRhiResource::Type QRhiComputePipeline::resourceType() const |
8347 | 0 | { |
8348 | 0 | return ComputePipeline; |
8349 | 0 | } |
8350 | | |
8351 | | /*! |
8352 | | \internal |
8353 | | */ |
8354 | | QRhiComputePipeline::QRhiComputePipeline(QRhiImplementation *rhi) |
8355 | 0 | : QRhiResource(rhi) |
8356 | 0 | { |
8357 | 0 | } |
8358 | | |
8359 | | /*! |
8360 | | \fn QRhiComputePipeline::Flags QRhiComputePipeline::flags() const |
8361 | | \return the currently set flags. |
8362 | | */ |
8363 | | |
8364 | | /*! |
8365 | | \fn void QRhiComputePipeline::setFlags(Flags f) |
8366 | | Sets the flags \a f. |
8367 | | */ |
8368 | | |
8369 | | /*! |
8370 | | \fn QRhiShaderStage QRhiComputePipeline::shaderStage() const |
8371 | | \return the currently set shader. |
8372 | | */ |
8373 | | |
8374 | | /*! |
8375 | | \fn void QRhiComputePipeline::setShaderStage(const QRhiShaderStage &stage) |
8376 | | |
8377 | | Sets the shader to use. \a stage can only refer to the |
8378 | | \l{QRhiShaderStage::Compute}{compute stage}. |
8379 | | */ |
8380 | | |
8381 | | /*! |
8382 | | \fn QRhiShaderResourceBindings *QRhiComputePipeline::shaderResourceBindings() const |
8383 | | \return the currently associated QRhiShaderResourceBindings object. |
8384 | | */ |
8385 | | |
8386 | | /*! |
8387 | | \fn void QRhiComputePipeline::setShaderResourceBindings(QRhiShaderResourceBindings *srb) |
8388 | | |
8389 | | Associates with \a srb describing the resource binding layout and the |
8390 | | resources (QRhiBuffer, QRhiTexture) themselves. The latter is optional. As |
8391 | | with graphics pipelines, the \a srb passed in here can leave the actual |
8392 | | buffer or texture objects unspecified (\nullptr) as long as there is |
8393 | | another, |
8394 | | \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible} |
8395 | | QRhiShaderResourceBindings bound via |
8396 | | \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} before |
8397 | | recording the dispatch call. |
8398 | | */ |
8399 | | |
8400 | | /*! |
8401 | | \struct QRhiIndirectDrawCommand |
8402 | | \inmodule QtGuiPrivate |
8403 | | \inheaderfile rhi/qrhi.h |
8404 | | \since 6.12 |
8405 | | \brief Draw command. |
8406 | | |
8407 | | A draw command that can be uploaded to a QRhiBuffer of usage |
8408 | | QRhiBuffer::UsageFlag::IndirectBuffer. |
8409 | | |
8410 | | \sa QRhiCommandBuffer::drawIndirect() |
8411 | | |
8412 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
8413 | | for details. |
8414 | | */ |
8415 | | |
8416 | | /*! |
8417 | | \variable QRhiIndirectDrawCommand::vertexCount |
8418 | | */ |
8419 | | |
8420 | | /*! |
8421 | | \variable QRhiIndirectDrawCommand::instanceCount |
8422 | | */ |
8423 | | |
8424 | | /*! |
8425 | | \variable QRhiIndirectDrawCommand::firstVertex |
8426 | | */ |
8427 | | |
8428 | | /*! |
8429 | | \variable QRhiIndirectDrawCommand::firstInstance |
8430 | | */ |
8431 | | |
8432 | | /*! |
8433 | | \struct QRhiIndexedIndirectDrawCommand |
8434 | | \inmodule QtGuiPrivate |
8435 | | \inheaderfile rhi/qrhi.h |
8436 | | \since 6.12 |
8437 | | \brief Indexed draw command. |
8438 | | |
8439 | | An indexed draw command that can be uploaded to a QRhiBuffer of usage |
8440 | | QRhiBuffer::UsageFlag::IndirectBuffer. |
8441 | | |
8442 | | \sa QRhiCommandBuffer::drawIndexedIndirect() |
8443 | | |
8444 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
8445 | | for details. |
8446 | | */ |
8447 | | |
8448 | | /*! |
8449 | | \variable QRhiIndexedIndirectDrawCommand::indexCount |
8450 | | */ |
8451 | | |
8452 | | /*! |
8453 | | \variable QRhiIndexedIndirectDrawCommand::instanceCount |
8454 | | */ |
8455 | | |
8456 | | /*! |
8457 | | \variable QRhiIndexedIndirectDrawCommand::firstIndex |
8458 | | */ |
8459 | | |
8460 | | /*! |
8461 | | \variable QRhiIndexedIndirectDrawCommand::vertexOffset |
8462 | | */ |
8463 | | |
8464 | | /*! |
8465 | | \variable QRhiIndexedIndirectDrawCommand::firstInstance |
8466 | | */ |
8467 | | |
8468 | | /*! |
8469 | | \class QRhiCommandBuffer |
8470 | | \inmodule QtGuiPrivate |
8471 | | \inheaderfile rhi/qrhi.h |
8472 | | \since 6.6 |
8473 | | \brief Command buffer resource. |
8474 | | |
8475 | | Not creatable by applications at the moment. The only ways to obtain a |
8476 | | valid QRhiCommandBuffer are to get it from the targeted swapchain via |
8477 | | QRhiSwapChain::currentFrameCommandBuffer(), or, in case of rendering |
8478 | | completely offscreen, initializing one via QRhi::beginOffscreenFrame(). |
8479 | | |
8480 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
8481 | | for details. |
8482 | | */ |
8483 | | |
8484 | | /*! |
8485 | | \enum QRhiCommandBuffer::IndexFormat |
8486 | | Specifies the index data type |
8487 | | |
8488 | | \value IndexUInt16 Unsigned 16-bit (quint16) |
8489 | | \value IndexUInt32 Unsigned 32-bit (quint32) |
8490 | | */ |
8491 | | |
8492 | | /*! |
8493 | | \enum QRhiCommandBuffer::BeginPassFlag |
8494 | | Flag values for QRhi::beginPass() |
8495 | | |
8496 | | \value ExternalContent Specifies that there will be a call to |
8497 | | QRhiCommandBuffer::beginExternal() in this pass. Some backends, Vulkan in |
8498 | | particular, will fail if this flag is not set and beginExternal() is still |
8499 | | called. |
8500 | | |
8501 | | \value DoNotTrackResourcesForCompute Specifies that there is no need to |
8502 | | track resources used in this pass if the only purpose of such tracking is |
8503 | | to generate barriers for compute. Implies that there are no compute passes |
8504 | | in the frame. This is an optimization hint that may be taken into account |
8505 | | by certain backends, OpenGL in particular, allowing them to skip certain |
8506 | | operations. When this flag is set for a render pass in a frame, calling |
8507 | | \l{QRhiCommandBuffer::beginComputePass()}{beginComputePass()} in that frame |
8508 | | may lead to unexpected behavior, depending on the resource dependencies |
8509 | | between the render and compute passes. |
8510 | | */ |
8511 | | |
8512 | | /*! |
8513 | | \typedef QRhiCommandBuffer::DynamicOffset |
8514 | | |
8515 | | Synonym for std::pair<int, quint32>. The first entry is the binding, the second |
8516 | | is the offset in the buffer. |
8517 | | */ |
8518 | | |
8519 | | /*! |
8520 | | \typedef QRhiCommandBuffer::VertexInput |
8521 | | |
8522 | | Synonym for std::pair<QRhiBuffer *, quint32>. The second entry is an offset in |
8523 | | the buffer specified by the first. |
8524 | | */ |
8525 | | |
8526 | | /*! |
8527 | | \internal |
8528 | | */ |
8529 | | QRhiCommandBuffer::QRhiCommandBuffer(QRhiImplementation *rhi) |
8530 | 0 | : QRhiResource(rhi) |
8531 | 0 | { |
8532 | 0 | } |
8533 | | |
8534 | | /*! |
8535 | | \return the resource type. |
8536 | | */ |
8537 | | QRhiResource::Type QRhiCommandBuffer::resourceType() const |
8538 | 0 | { |
8539 | 0 | return CommandBuffer; |
8540 | 0 | } |
8541 | | |
8542 | | static const char *resourceTypeStr(const QRhiResource *res) |
8543 | 0 | { |
8544 | 0 | switch (res->resourceType()) { |
8545 | 0 | case QRhiResource::Buffer: |
8546 | 0 | return "Buffer"; |
8547 | 0 | case QRhiResource::Texture: |
8548 | 0 | return "Texture"; |
8549 | 0 | case QRhiResource::Sampler: |
8550 | 0 | return "Sampler"; |
8551 | 0 | case QRhiResource::RenderBuffer: |
8552 | 0 | return "RenderBuffer"; |
8553 | 0 | case QRhiResource::RenderPassDescriptor: |
8554 | 0 | return "RenderPassDescriptor"; |
8555 | 0 | case QRhiResource::SwapChainRenderTarget: |
8556 | 0 | return "SwapChainRenderTarget"; |
8557 | 0 | case QRhiResource::TextureRenderTarget: |
8558 | 0 | return "TextureRenderTarget"; |
8559 | 0 | case QRhiResource::ShaderResourceBindings: |
8560 | 0 | return "ShaderResourceBindings"; |
8561 | 0 | case QRhiResource::GraphicsPipeline: |
8562 | 0 | return "GraphicsPipeline"; |
8563 | 0 | case QRhiResource::SwapChain: |
8564 | 0 | return "SwapChain"; |
8565 | 0 | case QRhiResource::ComputePipeline: |
8566 | 0 | return "ComputePipeline"; |
8567 | 0 | case QRhiResource::CommandBuffer: |
8568 | 0 | return "CommandBuffer"; |
8569 | 0 | case QRhiResource::ShadingRateMap: |
8570 | 0 | return "ShadingRateMap"; |
8571 | 0 | } |
8572 | | |
8573 | 0 | Q_UNREACHABLE_RETURN(""); |
8574 | 0 | } |
8575 | | |
8576 | | QRhiImplementation::~QRhiImplementation() |
8577 | 0 | { |
8578 | 0 | qDeleteAll(resUpdPool); |
8579 | | |
8580 | | // Be nice and show something about leaked stuff. Though we may not get |
8581 | | // this far with some backends where the allocator or the api may check |
8582 | | // and freak out for unfreed graphics objects in the derived dtor already. |
8583 | 0 | #ifndef QT_NO_DEBUG |
8584 | | // debug builds: just do it always |
8585 | 0 | static bool leakCheck = true; |
8586 | | #else |
8587 | | // release builds: opt-in |
8588 | | static bool leakCheck = qEnvironmentVariableIntValue("QT_RHI_LEAK_CHECK"); |
8589 | | #endif |
8590 | 0 | if (!resources.isEmpty()) { |
8591 | 0 | if (leakCheck) { |
8592 | 0 | qWarning("QRhi %p going down with %d unreleased resources that own native graphics objects. This is not nice.", |
8593 | 0 | q, int(resources.size())); |
8594 | 0 | } |
8595 | 0 | for (auto it = resources.cbegin(), end = resources.cend(); it != end; ++it) { |
8596 | 0 | QRhiResource *res = it.key(); |
8597 | 0 | const bool ownsNativeResources = it.value(); |
8598 | 0 | if (leakCheck && ownsNativeResources) |
8599 | 0 | qWarning(" %s resource %p (%s)", resourceTypeStr(res), res, res->m_objectName.constData()); |
8600 | | |
8601 | | // Null out the resource's rhi pointer. This is why it makes sense to do null |
8602 | | // checks in the destroy() implementations of the various resource types. It |
8603 | | // allows to survive in bad applications that somehow manage to destroy a |
8604 | | // resource of a QRhi after the QRhi itself. |
8605 | 0 | res->m_rhi = nullptr; |
8606 | 0 | } |
8607 | 0 | } |
8608 | 0 | } |
8609 | | |
8610 | | bool QRhiImplementation::isCompressedFormat(QRhiTexture::Format format) const |
8611 | 0 | { |
8612 | 0 | return (format >= QRhiTexture::BC1 && format <= QRhiTexture::BC7) |
8613 | 0 | || (format >= QRhiTexture::ETC2_RGB8 && format <= QRhiTexture::ETC2_RGBA8) |
8614 | 0 | || (format >= QRhiTexture::ASTC_4x4 && format <= QRhiTexture::ASTC_12x12); |
8615 | 0 | } |
8616 | | |
8617 | | void QRhiImplementation::compressedFormatInfo(QRhiTexture::Format format, const QSize &size, |
8618 | | quint32 *bpl, quint32 *byteSize, |
8619 | | QSize *blockDim) const |
8620 | 0 | { |
8621 | 0 | int xdim = 4; |
8622 | 0 | int ydim = 4; |
8623 | 0 | quint32 blockSize = 0; |
8624 | |
|
8625 | 0 | switch (format) { |
8626 | 0 | case QRhiTexture::BC1: |
8627 | 0 | blockSize = 8; |
8628 | 0 | break; |
8629 | 0 | case QRhiTexture::BC2: |
8630 | 0 | blockSize = 16; |
8631 | 0 | break; |
8632 | 0 | case QRhiTexture::BC3: |
8633 | 0 | blockSize = 16; |
8634 | 0 | break; |
8635 | 0 | case QRhiTexture::BC4: |
8636 | 0 | blockSize = 8; |
8637 | 0 | break; |
8638 | 0 | case QRhiTexture::BC5: |
8639 | 0 | blockSize = 16; |
8640 | 0 | break; |
8641 | 0 | case QRhiTexture::BC6H: |
8642 | 0 | blockSize = 16; |
8643 | 0 | break; |
8644 | 0 | case QRhiTexture::BC7: |
8645 | 0 | blockSize = 16; |
8646 | 0 | break; |
8647 | | |
8648 | 0 | case QRhiTexture::ETC2_RGB8: |
8649 | 0 | blockSize = 8; |
8650 | 0 | break; |
8651 | 0 | case QRhiTexture::ETC2_RGB8A1: |
8652 | 0 | blockSize = 8; |
8653 | 0 | break; |
8654 | 0 | case QRhiTexture::ETC2_RGBA8: |
8655 | 0 | blockSize = 16; |
8656 | 0 | break; |
8657 | | |
8658 | 0 | case QRhiTexture::ASTC_4x4: |
8659 | 0 | blockSize = 16; |
8660 | 0 | break; |
8661 | 0 | case QRhiTexture::ASTC_5x4: |
8662 | 0 | blockSize = 16; |
8663 | 0 | xdim = 5; |
8664 | 0 | break; |
8665 | 0 | case QRhiTexture::ASTC_5x5: |
8666 | 0 | blockSize = 16; |
8667 | 0 | xdim = ydim = 5; |
8668 | 0 | break; |
8669 | 0 | case QRhiTexture::ASTC_6x5: |
8670 | 0 | blockSize = 16; |
8671 | 0 | xdim = 6; |
8672 | 0 | ydim = 5; |
8673 | 0 | break; |
8674 | 0 | case QRhiTexture::ASTC_6x6: |
8675 | 0 | blockSize = 16; |
8676 | 0 | xdim = ydim = 6; |
8677 | 0 | break; |
8678 | 0 | case QRhiTexture::ASTC_8x5: |
8679 | 0 | blockSize = 16; |
8680 | 0 | xdim = 8; |
8681 | 0 | ydim = 5; |
8682 | 0 | break; |
8683 | 0 | case QRhiTexture::ASTC_8x6: |
8684 | 0 | blockSize = 16; |
8685 | 0 | xdim = 8; |
8686 | 0 | ydim = 6; |
8687 | 0 | break; |
8688 | 0 | case QRhiTexture::ASTC_8x8: |
8689 | 0 | blockSize = 16; |
8690 | 0 | xdim = ydim = 8; |
8691 | 0 | break; |
8692 | 0 | case QRhiTexture::ASTC_10x5: |
8693 | 0 | blockSize = 16; |
8694 | 0 | xdim = 10; |
8695 | 0 | ydim = 5; |
8696 | 0 | break; |
8697 | 0 | case QRhiTexture::ASTC_10x6: |
8698 | 0 | blockSize = 16; |
8699 | 0 | xdim = 10; |
8700 | 0 | ydim = 6; |
8701 | 0 | break; |
8702 | 0 | case QRhiTexture::ASTC_10x8: |
8703 | 0 | blockSize = 16; |
8704 | 0 | xdim = 10; |
8705 | 0 | ydim = 8; |
8706 | 0 | break; |
8707 | 0 | case QRhiTexture::ASTC_10x10: |
8708 | 0 | blockSize = 16; |
8709 | 0 | xdim = ydim = 10; |
8710 | 0 | break; |
8711 | 0 | case QRhiTexture::ASTC_12x10: |
8712 | 0 | blockSize = 16; |
8713 | 0 | xdim = 12; |
8714 | 0 | ydim = 10; |
8715 | 0 | break; |
8716 | 0 | case QRhiTexture::ASTC_12x12: |
8717 | 0 | blockSize = 16; |
8718 | 0 | xdim = ydim = 12; |
8719 | 0 | break; |
8720 | | |
8721 | 0 | default: |
8722 | 0 | Q_UNREACHABLE(); |
8723 | 0 | break; |
8724 | 0 | } |
8725 | | |
8726 | 0 | const quint32 wblocks = uint((size.width() + xdim - 1) / xdim); |
8727 | 0 | const quint32 hblocks = uint((size.height() + ydim - 1) / ydim); |
8728 | |
|
8729 | 0 | if (bpl) |
8730 | 0 | *bpl = wblocks * blockSize; |
8731 | 0 | if (byteSize) |
8732 | 0 | *byteSize = wblocks * hblocks * blockSize; |
8733 | 0 | if (blockDim) |
8734 | 0 | *blockDim = QSize(xdim, ydim); |
8735 | 0 | } |
8736 | | |
8737 | | void QRhiImplementation::textureFormatInfo(QRhiTexture::Format format, const QSize &size, |
8738 | | quint32 *bpl, quint32 *byteSize, quint32 *bytesPerPixel) const |
8739 | 0 | { |
8740 | 0 | if (isCompressedFormat(format)) { |
8741 | 0 | compressedFormatInfo(format, size, bpl, byteSize, nullptr); |
8742 | 0 | return; |
8743 | 0 | } |
8744 | | |
8745 | 0 | quint32 bpc = 0; |
8746 | 0 | switch (format) { |
8747 | 0 | case QRhiTexture::RGBA8: |
8748 | 0 | bpc = 4; |
8749 | 0 | break; |
8750 | 0 | case QRhiTexture::BGRA8: |
8751 | 0 | bpc = 4; |
8752 | 0 | break; |
8753 | 0 | case QRhiTexture::R8: |
8754 | 0 | bpc = 1; |
8755 | 0 | break; |
8756 | 0 | case QRhiTexture::RG8: |
8757 | 0 | bpc = 2; |
8758 | 0 | break; |
8759 | 0 | case QRhiTexture::R16: |
8760 | 0 | bpc = 2; |
8761 | 0 | break; |
8762 | 0 | case QRhiTexture::RG16: |
8763 | 0 | bpc = 4; |
8764 | 0 | break; |
8765 | 0 | case QRhiTexture::RED_OR_ALPHA8: |
8766 | 0 | bpc = 1; |
8767 | 0 | break; |
8768 | | |
8769 | 0 | case QRhiTexture::RGBA16F: |
8770 | 0 | bpc = 8; |
8771 | 0 | break; |
8772 | 0 | case QRhiTexture::RGBA32F: |
8773 | 0 | bpc = 16; |
8774 | 0 | break; |
8775 | 0 | case QRhiTexture::R16F: |
8776 | 0 | bpc = 2; |
8777 | 0 | break; |
8778 | 0 | case QRhiTexture::R32F: |
8779 | 0 | bpc = 4; |
8780 | 0 | break; |
8781 | | |
8782 | 0 | case QRhiTexture::RGB10A2: |
8783 | 0 | bpc = 4; |
8784 | 0 | break; |
8785 | | |
8786 | 0 | case QRhiTexture::D16: |
8787 | 0 | bpc = 2; |
8788 | 0 | break; |
8789 | 0 | case QRhiTexture::D24: |
8790 | 0 | case QRhiTexture::D24S8: |
8791 | 0 | case QRhiTexture::D32F: |
8792 | 0 | bpc = 4; |
8793 | 0 | break; |
8794 | | |
8795 | 0 | case QRhiTexture::D32FS8: |
8796 | 0 | bpc = 8; |
8797 | 0 | break; |
8798 | | |
8799 | 0 | case QRhiTexture::R8SI: |
8800 | 0 | case QRhiTexture::R8UI: |
8801 | 0 | bpc = 1; |
8802 | 0 | break; |
8803 | 0 | case QRhiTexture::R32SI: |
8804 | 0 | case QRhiTexture::R32UI: |
8805 | 0 | bpc = 4; |
8806 | 0 | break; |
8807 | 0 | case QRhiTexture::RG32SI: |
8808 | 0 | case QRhiTexture::RG32UI: |
8809 | 0 | bpc = 8; |
8810 | 0 | break; |
8811 | 0 | case QRhiTexture::RGBA32SI: |
8812 | 0 | case QRhiTexture::RGBA32UI: |
8813 | 0 | bpc = 16; |
8814 | 0 | break; |
8815 | | |
8816 | 0 | default: |
8817 | 0 | Q_UNREACHABLE(); |
8818 | 0 | break; |
8819 | 0 | } |
8820 | | |
8821 | 0 | if (bpl) |
8822 | 0 | *bpl = uint(size.width()) * bpc; |
8823 | 0 | if (byteSize) |
8824 | 0 | *byteSize = uint(size.width() * size.height()) * bpc; |
8825 | 0 | if (bytesPerPixel) |
8826 | 0 | *bytesPerPixel = bpc; |
8827 | 0 | } |
8828 | | |
8829 | | bool QRhiImplementation::isStencilSupportingFormat(QRhiTexture::Format format) const |
8830 | 0 | { |
8831 | 0 | switch (format) { |
8832 | 0 | case QRhiTexture::D24S8: |
8833 | 0 | case QRhiTexture::D32FS8: |
8834 | 0 | return true; |
8835 | 0 | default: |
8836 | 0 | break; |
8837 | 0 | } |
8838 | 0 | return false; |
8839 | 0 | } |
8840 | | |
8841 | | bool QRhiImplementation::sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps) |
8842 | 0 | { |
8843 | 0 | if (ps->cbeginShaderStages() == ps->cendShaderStages()) { |
8844 | 0 | qWarning("Cannot build a graphics pipeline without any stages"); |
8845 | 0 | return false; |
8846 | 0 | } |
8847 | | |
8848 | 0 | bool hasVertexStage = false; |
8849 | 0 | for (auto it = ps->cbeginShaderStages(), itEnd = ps->cendShaderStages(); it != itEnd; ++it) { |
8850 | 0 | if (!it->shader().isValid()) { |
8851 | 0 | qWarning("Empty shader passed to graphics pipeline"); |
8852 | 0 | return false; |
8853 | 0 | } |
8854 | 0 | if (it->type() == QRhiShaderStage::Vertex) |
8855 | 0 | hasVertexStage = true; |
8856 | 0 | } |
8857 | 0 | if (!hasVertexStage) { |
8858 | 0 | qWarning("Cannot build a graphics pipeline without a vertex stage"); |
8859 | 0 | return false; |
8860 | 0 | } |
8861 | | |
8862 | 0 | if (!ps->renderPassDescriptor()) { |
8863 | 0 | qWarning("Cannot build a graphics pipeline without a QRhiRenderPassDescriptor"); |
8864 | 0 | return false; |
8865 | 0 | } |
8866 | | |
8867 | 0 | if (!ps->shaderResourceBindings()) { |
8868 | 0 | qWarning("Cannot build a graphics pipeline without QRhiShaderResourceBindings"); |
8869 | 0 | return false; |
8870 | 0 | } |
8871 | | |
8872 | 0 | return true; |
8873 | 0 | } |
8874 | | |
8875 | | bool QRhiImplementation::sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb) |
8876 | 0 | { |
8877 | 0 | #ifndef QT_NO_DEBUG |
8878 | 0 | bool bindingsOk = true; |
8879 | 0 | const int CHECKED_BINDINGS_COUNT = 64; |
8880 | 0 | bool bindingSeen[CHECKED_BINDINGS_COUNT] = {}; |
8881 | 0 | for (auto it = srb->cbeginBindings(), end = srb->cendBindings(); it != end; ++it) { |
8882 | 0 | const int binding = shaderResourceBindingData(*it)->binding; |
8883 | 0 | if (binding >= CHECKED_BINDINGS_COUNT) |
8884 | 0 | continue; |
8885 | 0 | if (binding < 0) { |
8886 | 0 | qWarning("Invalid binding number %d", binding); |
8887 | 0 | bindingsOk = false; |
8888 | 0 | continue; |
8889 | 0 | } |
8890 | 0 | switch (shaderResourceBindingData(*it)->type) { |
8891 | 0 | case QRhiShaderResourceBinding::UniformBuffer: |
8892 | 0 | if (!bindingSeen[binding]) { |
8893 | 0 | bindingSeen[binding] = true; |
8894 | 0 | } else { |
8895 | 0 | qWarning("Uniform buffer duplicates an existing binding number %d", binding); |
8896 | 0 | bindingsOk = false; |
8897 | 0 | } |
8898 | 0 | break; |
8899 | 0 | case QRhiShaderResourceBinding::SampledTexture: |
8900 | 0 | if (!bindingSeen[binding]) { |
8901 | 0 | bindingSeen[binding] = true; |
8902 | 0 | } else { |
8903 | 0 | qWarning("Combined image sampler duplicates an existing binding number %d", binding); |
8904 | 0 | bindingsOk = false; |
8905 | 0 | } |
8906 | 0 | break; |
8907 | 0 | case QRhiShaderResourceBinding::Texture: |
8908 | 0 | if (!bindingSeen[binding]) { |
8909 | 0 | bindingSeen[binding] = true; |
8910 | 0 | } else { |
8911 | 0 | qWarning("Texture duplicates an existing binding number %d", binding); |
8912 | 0 | bindingsOk = false; |
8913 | 0 | } |
8914 | 0 | break; |
8915 | 0 | case QRhiShaderResourceBinding::Sampler: |
8916 | 0 | if (!bindingSeen[binding]) { |
8917 | 0 | bindingSeen[binding] = true; |
8918 | 0 | } else { |
8919 | 0 | qWarning("Sampler duplicates an existing binding number %d", binding); |
8920 | 0 | bindingsOk = false; |
8921 | 0 | } |
8922 | 0 | break; |
8923 | 0 | case QRhiShaderResourceBinding::ImageLoad: |
8924 | 0 | case QRhiShaderResourceBinding::ImageStore: |
8925 | 0 | case QRhiShaderResourceBinding::ImageLoadStore: |
8926 | 0 | if (!bindingSeen[binding]) { |
8927 | 0 | bindingSeen[binding] = true; |
8928 | 0 | } else { |
8929 | 0 | qWarning("Image duplicates an existing binding number %d", binding); |
8930 | 0 | bindingsOk = false; |
8931 | 0 | } |
8932 | 0 | break; |
8933 | 0 | case QRhiShaderResourceBinding::BufferLoad: |
8934 | 0 | case QRhiShaderResourceBinding::BufferStore: |
8935 | 0 | case QRhiShaderResourceBinding::BufferLoadStore: |
8936 | 0 | if (!bindingSeen[binding]) { |
8937 | 0 | bindingSeen[binding] = true; |
8938 | 0 | } else { |
8939 | 0 | qWarning("Buffer duplicates an existing binding number %d", binding); |
8940 | 0 | bindingsOk = false; |
8941 | 0 | } |
8942 | 0 | break; |
8943 | 0 | default: |
8944 | 0 | qWarning("Unknown binding type %d", int(shaderResourceBindingData(*it)->type)); |
8945 | 0 | bindingsOk = false; |
8946 | 0 | break; |
8947 | 0 | } |
8948 | 0 | } |
8949 | | |
8950 | 0 | if (!bindingsOk) { |
8951 | 0 | qWarning() << *srb; |
8952 | 0 | return false; |
8953 | 0 | } |
8954 | | #else |
8955 | | Q_UNUSED(srb); |
8956 | | #endif |
8957 | 0 | return true; |
8958 | 0 | } |
8959 | | |
8960 | | bool QRhiImplementation::sanityCheckResourceOwnership(QRhiResource *maybeResource) |
8961 | 0 | { |
8962 | 0 | if (maybeResource == nullptr || maybeResource->m_rhi == nullptr) |
8963 | 0 | return true; |
8964 | | |
8965 | 0 | if (maybeResource->m_rhi->q != q) { |
8966 | 0 | qWarning("%s %p (%s) belongs to QRhi %p, but client code attempted to use it with QRhi %p. This is wrong.", |
8967 | 0 | resourceTypeStr(maybeResource), |
8968 | 0 | maybeResource, |
8969 | 0 | maybeResource->m_objectName.constData(), |
8970 | 0 | maybeResource->m_rhi->q, |
8971 | 0 | q); |
8972 | 0 | return false; |
8973 | 0 | } |
8974 | | |
8975 | 0 | return true; |
8976 | 0 | } |
8977 | | |
8978 | | int QRhiImplementation::effectiveSampleCount(int sampleCount) const |
8979 | 0 | { |
8980 | | // Stay compatible with QSurfaceFormat and friends where samples == 0 means the same as 1. |
8981 | 0 | const int s = qBound(1, sampleCount, 64); |
8982 | 0 | const QList<int> supported = supportedSampleCounts(); |
8983 | 0 | int result = 1; |
8984 | | |
8985 | | // Stay compatible with Qt 5 in that requesting an unsupported sample count |
8986 | | // is not an error (although we still do a categorized debug print about |
8987 | | // this), and rather a supported value, preferably a close one, not just 1, |
8988 | | // is used instead. This is actually deviating from Qt 5 as that performs a |
8989 | | // clamping only and does not handle cases such as when sample count 2 is |
8990 | | // not supported but 4 is. (OpenGL handles things like that gracefully, |
8991 | | // other APIs may not, so improve this by picking the next largest, or in |
8992 | | // absence of that, the largest value; this with the goal to not reduce |
8993 | | // quality by rather picking a larger-than-requested value than a smaller one) |
8994 | |
|
8995 | 0 | for (int i = 0, ie = supported.count(); i != ie; ++i) { |
8996 | | // assumes the 'supported' list is sorted |
8997 | 0 | if (supported[i] >= s) { |
8998 | 0 | result = supported[i]; |
8999 | 0 | break; |
9000 | 0 | } |
9001 | 0 | } |
9002 | |
|
9003 | 0 | if (result != s) { |
9004 | 0 | if (result == 1 && !supported.isEmpty()) |
9005 | 0 | result = supported.last(); |
9006 | 0 | qCDebug(QRHI_LOG_INFO, "Attempted to set unsupported sample count %d, using %d instead", |
9007 | 0 | sampleCount, result); |
9008 | 0 | } |
9009 | |
|
9010 | 0 | return result; |
9011 | 0 | } |
9012 | | |
9013 | | /*! |
9014 | | \internal |
9015 | | */ |
9016 | | QRhi::QRhi() |
9017 | 0 | { |
9018 | 0 | } |
9019 | | |
9020 | | /*! |
9021 | | Destructor. Destroys the backend and releases resources. |
9022 | | */ |
9023 | | QRhi::~QRhi() |
9024 | 0 | { |
9025 | 0 | if (!d) |
9026 | 0 | return; |
9027 | | |
9028 | 0 | d->runCleanup(); |
9029 | |
|
9030 | 0 | qDeleteAll(d->pendingDeleteResources); |
9031 | 0 | d->pendingDeleteResources.clear(); |
9032 | |
|
9033 | 0 | d->destroy(); |
9034 | 0 | delete d; |
9035 | 0 | } |
9036 | | |
9037 | | QRhiImplementation *QRhiImplementation::newInstance(QRhi::Implementation impl, QRhiInitParams *params, QRhiNativeHandles *importDevice) |
9038 | 0 | { |
9039 | 0 | QRhiImplementation *d = nullptr; |
9040 | |
|
9041 | 0 | switch (impl) { |
9042 | 0 | case QRhi::Null: |
9043 | 0 | d = new QRhiNull(static_cast<QRhiNullInitParams *>(params)); |
9044 | 0 | break; |
9045 | 0 | case QRhi::Vulkan: |
9046 | | #if QT_CONFIG(vulkan) |
9047 | | d = new QRhiVulkan(static_cast<QRhiVulkanInitParams *>(params), |
9048 | | static_cast<QRhiVulkanNativeHandles *>(importDevice)); |
9049 | | break; |
9050 | | #else |
9051 | 0 | Q_UNUSED(importDevice); |
9052 | 0 | qWarning("This build of Qt has no Vulkan support"); |
9053 | 0 | break; |
9054 | 0 | #endif |
9055 | 0 | case QRhi::OpenGLES2: |
9056 | | #ifndef QT_NO_OPENGL |
9057 | | d = new QRhiGles2(static_cast<QRhiGles2InitParams *>(params), |
9058 | | static_cast<QRhiGles2NativeHandles *>(importDevice)); |
9059 | | break; |
9060 | | #else |
9061 | 0 | qWarning("This build of Qt has no OpenGL support"); |
9062 | 0 | break; |
9063 | 0 | #endif |
9064 | 0 | case QRhi::D3D11: |
9065 | | #ifdef Q_OS_WIN |
9066 | | d = new QRhiD3D11(static_cast<QRhiD3D11InitParams *>(params), |
9067 | | static_cast<QRhiD3D11NativeHandles *>(importDevice)); |
9068 | | break; |
9069 | | #else |
9070 | 0 | qWarning("This platform has no Direct3D 11 support"); |
9071 | 0 | break; |
9072 | 0 | #endif |
9073 | 0 | case QRhi::Metal: |
9074 | | #if QT_CONFIG(metal) |
9075 | | d = new QRhiMetal(static_cast<QRhiMetalInitParams *>(params), |
9076 | | static_cast<QRhiMetalNativeHandles *>(importDevice)); |
9077 | | break; |
9078 | | #else |
9079 | 0 | qWarning("This platform has no Metal support"); |
9080 | 0 | break; |
9081 | 0 | #endif |
9082 | 0 | case QRhi::D3D12: |
9083 | | #ifdef Q_OS_WIN |
9084 | | #ifdef QRHI_D3D12_AVAILABLE |
9085 | | d = new QRhiD3D12(static_cast<QRhiD3D12InitParams *>(params), |
9086 | | static_cast<QRhiD3D12NativeHandles *>(importDevice)); |
9087 | | break; |
9088 | | #else |
9089 | | qWarning("Qt was built without Direct3D 12 support. " |
9090 | | "This is likely due to having ancient SDK headers (such as d3d12.h) in the Qt build environment. " |
9091 | | "Rebuild Qt with an SDK supporting D3D12 features introduced in Windows 10 version 1703, " |
9092 | | "or use an MSVC build as those typically are built with more up-to-date SDKs."); |
9093 | | break; |
9094 | | #endif |
9095 | | #else |
9096 | 0 | qWarning("This platform has no Direct3D 12 support"); |
9097 | 0 | break; |
9098 | 0 | #endif |
9099 | 0 | } |
9100 | | |
9101 | 0 | return d; |
9102 | 0 | } |
9103 | | |
9104 | | void QRhiImplementation::prepareForCreate(QRhi *rhi, QRhi::Implementation impl, QRhi::Flags flags, QRhiAdapter *adapter) |
9105 | 0 | { |
9106 | 0 | q = rhi; |
9107 | |
|
9108 | 0 | debugMarkers = flags.testFlag(QRhi::EnableDebugMarkers); |
9109 | |
|
9110 | 0 | implType = impl; |
9111 | 0 | implThread = QThread::currentThread(); |
9112 | |
|
9113 | 0 | requestedRhiAdapter = adapter; |
9114 | 0 | } |
9115 | | |
9116 | | QRhi::AdapterList QRhiImplementation::enumerateAdaptersBeforeCreate(QRhiNativeHandles *) const |
9117 | 0 | { |
9118 | 0 | return {}; |
9119 | 0 | } |
9120 | | |
9121 | | /*! |
9122 | | \overload |
9123 | | |
9124 | | Equivalent to create(\a impl, \a params, \a flags, \a importDevice, \c nullptr). |
9125 | | */ |
9126 | | QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRhiNativeHandles *importDevice) |
9127 | 0 | { |
9128 | 0 | return create(impl, params, flags, importDevice, nullptr); |
9129 | 0 | } |
9130 | | |
9131 | | /*! |
9132 | | \return a new QRhi instance with a backend for the graphics API specified |
9133 | | by \a impl with the specified \a flags. \return \c nullptr if the |
9134 | | function fails. |
9135 | | |
9136 | | \a params must point to an instance of one of the backend-specific |
9137 | | subclasses of QRhiInitParams, such as, QRhiVulkanInitParams, |
9138 | | QRhiMetalInitParams, QRhiD3D11InitParams, QRhiD3D12InitParams, |
9139 | | QRhiGles2InitParams. See these classes for examples on creating a QRhi. |
9140 | | |
9141 | | QRhi by design does not implement any fallback logic: if the specified API |
9142 | | cannot be initialized, create() will fail, with warnings printed on the |
9143 | | debug output by the backends. The clients of QRhi, for example Qt Quick, |
9144 | | may however provide additional logic that allow falling back to an API |
9145 | | different than what was requested, depending on the platform. If the |
9146 | | intention is just to test if initialization would succeed when calling |
9147 | | create() at later point, it is preferable to use probe() instead of |
9148 | | create(), because with some backends probing can be implemented in a more |
9149 | | lightweight manner as opposed to create(), which performs full |
9150 | | initialization of the infrastructure and is wasteful if that QRhi instance |
9151 | | is then thrown immediately away. |
9152 | | |
9153 | | \a importDevice allows using an already existing graphics device, without |
9154 | | QRhi creating its own. When not null, this parameter must point to an |
9155 | | instance of one of the subclasses of QRhiNativeHandles: |
9156 | | QRhiVulkanNativeHandles, QRhiD3D11NativeHandles, QRhiD3D12NativeHandles, |
9157 | | QRhiMetalNativeHandles, QRhiGles2NativeHandles. The exact details and |
9158 | | semantics depend on the backand and the underlying graphics API. |
9159 | | |
9160 | | Specifying a QRhiAdapter in \a adapter offers a transparent, cross-API |
9161 | | alternative to passing in a \c VkPhysicalDevice via QRhiVulkanNativeHandles, |
9162 | | or an adapter LUID via QRhiD3D12NativeHandles. The ownership of \a adapter |
9163 | | is not taken. See enumerateAdapters() for more information on this approach. |
9164 | | |
9165 | | \note \a importDevice and \a adapter cannot be both specified. |
9166 | | |
9167 | | \sa probe() |
9168 | | */ |
9169 | | QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRhiNativeHandles *importDevice, QRhiAdapter *adapter) |
9170 | 0 | { |
9171 | 0 | if (adapter && importDevice) |
9172 | 0 | qWarning("adapter and importDevice should not both be non-null in QRhi::create()"); |
9173 | |
|
9174 | 0 | std::unique_ptr<QRhiImplementation> rd(QRhiImplementation::newInstance(impl, params, importDevice)); |
9175 | 0 | if (!rd) |
9176 | 0 | return nullptr; |
9177 | | |
9178 | 0 | std::unique_ptr<QRhi> r(new QRhi); |
9179 | 0 | r->d = rd.release(); |
9180 | 0 | r->d->prepareForCreate(r.get(), impl, flags, adapter); |
9181 | 0 | if (!r->d->create(flags)) |
9182 | 0 | return nullptr; |
9183 | | |
9184 | 0 | return r.release(); |
9185 | 0 | } |
9186 | | |
9187 | | /*! |
9188 | | \return true if create() can be expected to succeed when called the given |
9189 | | \a impl and \a params. |
9190 | | |
9191 | | For some backends this is equivalent to calling create(), checking its |
9192 | | return value, and then destroying the resulting QRhi. |
9193 | | |
9194 | | For others, in particular with Metal, there may be a specific probing |
9195 | | implementation, which allows testing in a more lightweight manner without |
9196 | | polluting the debug output with warnings upon failures. |
9197 | | |
9198 | | \sa create() |
9199 | | */ |
9200 | | bool QRhi::probe(QRhi::Implementation impl, QRhiInitParams *params) |
9201 | 0 | { |
9202 | 0 | bool ok = false; |
9203 | | |
9204 | | // The only place currently where this makes sense is Metal, where the API |
9205 | | // is simple enough so that a special probing function - doing nothing but |
9206 | | // a MTLCreateSystemDefaultDevice - is reasonable. Elsewhere, just call |
9207 | | // create() and then drop the result. |
9208 | |
|
9209 | 0 | if (impl == Metal) { |
9210 | | #if QT_CONFIG(metal) |
9211 | | ok = QRhiMetal::probe(static_cast<QRhiMetalInitParams *>(params)); |
9212 | | #endif |
9213 | 0 | } else { |
9214 | 0 | QRhi *rhi = create(impl, params); |
9215 | 0 | ok = rhi != nullptr; |
9216 | 0 | delete rhi; |
9217 | 0 | } |
9218 | 0 | return ok; |
9219 | 0 | } |
9220 | | |
9221 | | /*! |
9222 | | \typedef QRhi::AdapterList |
9223 | | \relates QRhi |
9224 | | \since 6.10 |
9225 | | |
9226 | | Synonym for QVector<QRhiAdapter *>. |
9227 | | */ |
9228 | | |
9229 | | /*! |
9230 | | \return the list of adapters (physical devices) present, or an empty list |
9231 | | when such control is not available with a given graphics API. |
9232 | | |
9233 | | Backends where such level of control is not available, the returned list is |
9234 | | always empty. Thus an empty list does not indicate there are no graphics |
9235 | | devices in the system, but that fine-grained control over selecting which |
9236 | | one to use is not available. |
9237 | | |
9238 | | Backends for Direct 3D 11, Direct 3D 12, and Vulkan can be expected to fully |
9239 | | support enumerating adapters. Others may not. The backend is specified by \a |
9240 | | impl. A QRhiAdapter returned from this function must only be used in a |
9241 | | create() call with the same \a impl. Some underlying APIs may present |
9242 | | further limitations, with Vulkan in particular the QRhiAdapter is specified |
9243 | | to the QVulkanInstance (\c VkInstance). |
9244 | | |
9245 | | The caller is expected to destroy the QRhiAdapter objects in the list. Apart |
9246 | | from querying \l{QRhiAdapter::}{info()}, the only purpose of these objects is |
9247 | | to be passed on to create(), or the corresponding functions in higher layers |
9248 | | such as Qt Quick. |
9249 | | |
9250 | | The following snippet, written specifically for Vulkan, shows how to |
9251 | | enumerate the available physical devices and request to create a QRhi for |
9252 | | the chosen one. This in practice is equivalent to passing in a \c |
9253 | | VkPhysicalDevice via a QRhiVulkanNativeHandles to create(), but it involves |
9254 | | less API-specific code on the application side: |
9255 | | |
9256 | | \code |
9257 | | QRhiVulkanInitParams initParams; |
9258 | | initParams.inst = &vulkanInstance; |
9259 | | QRhi::AdapterList adapters = QRhi::enumerateAdapters(QRhi::Vulkan, &initParams); |
9260 | | QRhiAdapter *chosenAdapter = nullptr; |
9261 | | for (QRhiAdapter *adapter : adapters) { |
9262 | | if (looksGood(adapter->info())) { |
9263 | | chosenAdapter = adapter; |
9264 | | break; |
9265 | | } |
9266 | | } |
9267 | | QRhi *rhi = QRhi::create(QRhi::Vulkan, &initParams, {}, nullptr, chosenAdapter); |
9268 | | qDeleteAll(adapters); |
9269 | | \endcode |
9270 | | |
9271 | | Passing in \a params is required due to some of the underlying graphics |
9272 | | APIs' design. With Vulkan in particular, the QVulkanInstance must be |
9273 | | provided, since enumerating is not possible without it. Other fields in the |
9274 | | backend-specific \a params will not actually be used by this function. |
9275 | | |
9276 | | \a nativeHandles is optional. When specified, it must be a valid |
9277 | | QRhiD3D11NativeHandles, QRhiD3D12NativeHandles, or QRhiVulkanNativeHandles, |
9278 | | similarly to create(). However, unlike create(), only the physical device |
9279 | | (in case of Vulkan) or the adapter LUID (in case of D3D) fields are used, |
9280 | | all other fields are ignored. This can be used the restrict the results to a |
9281 | | given adapter. The returned list will contain 1 or 0 elements in this case. |
9282 | | |
9283 | | Note how in the previous code snippet the looksGood() function |
9284 | | implementation cannot perform any platform-specific filtering based on the |
9285 | | true adapter / physical device identity, such as the adapter LUID on Windows |
9286 | | or the VkPhysicalDevice with Vulkan. This is because QRhiDriverInfo does not |
9287 | | contain platform-specific data. Instead, use \a nativeHandles to get the |
9288 | | results filtered already inside enumerateAdapters(). |
9289 | | |
9290 | | The following two snippets, using Direct 3D 12 as an example, are equivalent |
9291 | | in practice: |
9292 | | |
9293 | | \code |
9294 | | // enumerateAdapters-based approach from Qt 6.10 on |
9295 | | QRhiD3D12InitParams initParams; |
9296 | | QRhiD3D12NativeHandles nativeHandles; |
9297 | | nativeHandles.adapterLuidLow = luid.LowPart; // retrieved a LUID from somewhere, now pass it on to Qt |
9298 | | nativeHandles.adapterLuidHigh = luid.HighPart; |
9299 | | QRhi::AdapterList adapters = QRhi::enumerateAdapters(QRhi::D3D12, &initParams, &nativeHandles); |
9300 | | if (adapters.isEmpty()) { qWarning("Requested adapter was not found"); } |
9301 | | QRhi *rhi = QRhi::create(QRhi::D3D12, &initParams, {}, nullptr, adapters[0]); |
9302 | | qDeleteAll(adapters); |
9303 | | \endcode |
9304 | | |
9305 | | \code |
9306 | | // traditional approach, more lightweight |
9307 | | QRhiD3D12InitParams initParams; |
9308 | | QRhiD3D12NativeHandles nativeHandles; |
9309 | | nativeHandles.adapterLuidLow = luid.LowPart; // retrieved a LUID from somewhere, now pass it on to Qt |
9310 | | nativeHandles.adapterLuidHigh = luid.HighPart; |
9311 | | QRhi *rhi = QRhi::create(QRhi::D3D12, &initParams, {}, &nativeHandles, nullptr); |
9312 | | \endcode |
9313 | | |
9314 | | \since 6.10 |
9315 | | \sa create() |
9316 | | */ |
9317 | | QRhi::AdapterList QRhi::enumerateAdapters(Implementation impl, QRhiInitParams *params, QRhiNativeHandles *nativeHandles) |
9318 | 0 | { |
9319 | 0 | std::unique_ptr<QRhiImplementation> rd(QRhiImplementation::newInstance(impl, params, nullptr)); |
9320 | 0 | if (!rd) |
9321 | 0 | return {}; |
9322 | | |
9323 | 0 | return rd->enumerateAdaptersBeforeCreate(nativeHandles); |
9324 | 0 | } |
9325 | | |
9326 | | /*! |
9327 | | \struct QRhiSwapChainProxyData |
9328 | | \inmodule QtGuiPrivate |
9329 | | \inheaderfile rhi/qrhi.h |
9330 | | \since 6.6 |
9331 | | |
9332 | | \brief Opaque data describing native objects needed to set up a swapchain. |
9333 | | |
9334 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
9335 | | for details. |
9336 | | |
9337 | | \sa QRhi::updateSwapChainProxyData() |
9338 | | */ |
9339 | | |
9340 | | /*! |
9341 | | Generates and returns a QRhiSwapChainProxyData struct containing opaque |
9342 | | data specific to the backend and graphics API specified by \a impl. \a |
9343 | | window is the QWindow a swapchain is targeting. |
9344 | | |
9345 | | The returned struct can be passed to QRhiSwapChain::setProxyData(). This |
9346 | | makes sense in threaded rendering systems: this static function is expected |
9347 | | to be called on the \b{main (gui) thread}, unlike all QRhi operations, then |
9348 | | transferred to the thread working with the QRhi and QRhiSwapChain and passed |
9349 | | on to the swapchain. This allows doing native platform queries that are |
9350 | | only safe to be called on the main thread, for example to query the |
9351 | | CAMetalLayer from a NSView, and then passing on the data to the |
9352 | | QRhiSwapChain living on the rendering thread. With the Metal example, doing |
9353 | | the view.layer access on a dedicated rendering thread causes a warning in |
9354 | | the Xcode Thread Checker. With the data proxy mechanism, this is avoided. |
9355 | | |
9356 | | When threads are not involved, generating and passing on the |
9357 | | QRhiSwapChainProxyData is not required: backends are guaranteed to be able |
9358 | | to query whatever is needed on their own, and if everything lives on the |
9359 | | main (gui) thread, that should be sufficient. |
9360 | | |
9361 | | \note \a impl should match what the QRhi is created with. For example, |
9362 | | calling with QRhi::Metal on a non-Apple platform will not generate any |
9363 | | useful data. |
9364 | | */ |
9365 | | QRhiSwapChainProxyData QRhi::updateSwapChainProxyData(QRhi::Implementation impl, QWindow *window) |
9366 | 0 | { |
9367 | | #if QT_CONFIG(metal) |
9368 | | if (impl == Metal) |
9369 | | return QRhiMetal::updateSwapChainProxyData(window); |
9370 | | #else |
9371 | 0 | Q_UNUSED(impl); |
9372 | 0 | Q_UNUSED(window); |
9373 | 0 | #endif |
9374 | 0 | return {}; |
9375 | 0 | } |
9376 | | |
9377 | | /*! |
9378 | | \return the backend type for this QRhi. |
9379 | | */ |
9380 | | QRhi::Implementation QRhi::backend() const |
9381 | 0 | { |
9382 | 0 | return d->implType; |
9383 | 0 | } |
9384 | | |
9385 | | /*! |
9386 | | \return a friendly name for the backend \a impl, usually the name of the 3D |
9387 | | API in use. |
9388 | | */ |
9389 | | const char *QRhi::backendName(Implementation impl) |
9390 | 0 | { |
9391 | 0 | switch (impl) { |
9392 | 0 | case QRhi::Null: |
9393 | 0 | return "Null"; |
9394 | 0 | case QRhi::Vulkan: |
9395 | 0 | return "Vulkan"; |
9396 | 0 | case QRhi::OpenGLES2: |
9397 | 0 | return "OpenGL"; |
9398 | 0 | case QRhi::D3D11: |
9399 | 0 | return "D3D11"; |
9400 | 0 | case QRhi::Metal: |
9401 | 0 | return "Metal"; |
9402 | 0 | case QRhi::D3D12: |
9403 | 0 | return "D3D12"; |
9404 | 0 | } |
9405 | | |
9406 | 0 | Q_UNREACHABLE_RETURN("Unknown"); |
9407 | 0 | } |
9408 | | |
9409 | | /*! |
9410 | | \return the backend type as string for this QRhi. |
9411 | | */ |
9412 | | const char *QRhi::backendName() const |
9413 | 0 | { |
9414 | 0 | return backendName(d->implType); |
9415 | 0 | } |
9416 | | |
9417 | | /*! |
9418 | | \enum QRhiDriverInfo::DeviceType |
9419 | | Specifies the graphics device's type, when the information is available. |
9420 | | |
9421 | | In practice this is only applicable with Vulkan and Metal. With Direct 3D |
9422 | | 11 and 12, using an adapter with the software flag set leads to the value |
9423 | | \c CpuDevice. Otherwise, and with OpenGL, the value is always UnknownDevice. |
9424 | | |
9425 | | \value UnknownDevice |
9426 | | \value IntegratedDevice |
9427 | | \value DiscreteDevice |
9428 | | \value ExternalDevice |
9429 | | \value VirtualDevice |
9430 | | \value CpuDevice |
9431 | | */ |
9432 | | |
9433 | | /*! |
9434 | | \struct QRhiDriverInfo |
9435 | | \inmodule QtGuiPrivate |
9436 | | \inheaderfile rhi/qrhi.h |
9437 | | \since 6.6 |
9438 | | |
9439 | | \brief Describes the physical device, adapter, or graphics API |
9440 | | implementation that is used by an initialized QRhi. |
9441 | | |
9442 | | Graphics APIs offer different levels and kinds of information. The only |
9443 | | value that is available across all APIs is the deviceName, which is a |
9444 | | freetext description of the physical device, adapter, or is a combination |
9445 | | of the strings reported for \c{GL_VENDOR} + \c{GL_RENDERER} + |
9446 | | \c{GL_VERSION}. The deviceId is always 0 for OpenGL. vendorId is always 0 |
9447 | | for OpenGL and Metal. deviceType is always UnknownDevice for OpenGL and |
9448 | | Direct 3D. |
9449 | | |
9450 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
9451 | | for details. |
9452 | | */ |
9453 | | |
9454 | | /*! |
9455 | | \variable QRhiDriverInfo::deviceName |
9456 | | |
9457 | | \sa QRhi::driverInfo() |
9458 | | */ |
9459 | | |
9460 | | /*! |
9461 | | \variable QRhiDriverInfo::deviceId |
9462 | | |
9463 | | \sa QRhi::driverInfo() |
9464 | | */ |
9465 | | |
9466 | | /*! |
9467 | | \variable QRhiDriverInfo::vendorId |
9468 | | |
9469 | | \sa QRhi::driverInfo() |
9470 | | */ |
9471 | | |
9472 | | /*! |
9473 | | \variable QRhiDriverInfo::deviceType |
9474 | | |
9475 | | \sa QRhi::driverInfo(), QRhiDriverInfo::DeviceType |
9476 | | */ |
9477 | | |
9478 | | #ifndef QT_NO_DEBUG_STREAM |
9479 | | static inline const char *deviceTypeStr(QRhiDriverInfo::DeviceType type) |
9480 | 0 | { |
9481 | 0 | switch (type) { |
9482 | 0 | case QRhiDriverInfo::UnknownDevice: |
9483 | 0 | return "Unknown"; |
9484 | 0 | case QRhiDriverInfo::IntegratedDevice: |
9485 | 0 | return "Integrated"; |
9486 | 0 | case QRhiDriverInfo::DiscreteDevice: |
9487 | 0 | return "Discrete"; |
9488 | 0 | case QRhiDriverInfo::ExternalDevice: |
9489 | 0 | return "External"; |
9490 | 0 | case QRhiDriverInfo::VirtualDevice: |
9491 | 0 | return "Virtual"; |
9492 | 0 | case QRhiDriverInfo::CpuDevice: |
9493 | 0 | return "Cpu"; |
9494 | 0 | } |
9495 | | |
9496 | 0 | Q_UNREACHABLE_RETURN(nullptr); |
9497 | 0 | } |
9498 | | QDebug operator<<(QDebug dbg, const QRhiDriverInfo &info) |
9499 | 0 | { |
9500 | 0 | QDebugStateSaver saver(dbg); |
9501 | 0 | dbg.nospace() << "QRhiDriverInfo(deviceName=" << info.deviceName |
9502 | 0 | << " deviceId=0x" << Qt::hex << info.deviceId |
9503 | 0 | << " vendorId=0x" << info.vendorId |
9504 | 0 | << " deviceType=" << deviceTypeStr(info.deviceType) |
9505 | 0 | << ')'; |
9506 | 0 | return dbg; |
9507 | 0 | } |
9508 | | #endif |
9509 | | |
9510 | | /*! |
9511 | | \return metadata for the graphics device used by this successfully |
9512 | | initialized QRhi instance. |
9513 | | */ |
9514 | | QRhiDriverInfo QRhi::driverInfo() const |
9515 | 0 | { |
9516 | 0 | return d->driverInfo(); |
9517 | 0 | } |
9518 | | |
9519 | | /*! |
9520 | | \class QRhiAdapter |
9521 | | \inmodule QtGuiPrivate |
9522 | | \inheaderfile rhi/qrhi.h |
9523 | | \since 6.10 |
9524 | | |
9525 | | \brief Represents a physical graphics device. |
9526 | | |
9527 | | Some QRhi backends target graphics APIs that expose the concept of \c |
9528 | | adapters or \c{physical devices}. Call the static \l |
9529 | | {QRhi::}{enumerateAdapters()} function to retrieve a list of the adapters |
9530 | | present in the system. Pass one of the returned QRhiAdapter objects to \l |
9531 | | {QRhi::}{create()} in order to request using the adapter or physical device |
9532 | | the QRhiAdapter corresponds to. Other than exposing the QRhiDriverInfo, |
9533 | | QRhiAdapter is to be treated as an opaque handle. |
9534 | | |
9535 | | \note With Vulkan, the QRhiAdapter is valid only as long as the |
9536 | | QVulkanInstance that was used for \l{QRhi::}{enumerateAdapters()} is valid. |
9537 | | This also means that a QRhiAdapter is tied to the Vulkan instance |
9538 | | (QVulkanInstance, \c VkInstance) and cannot be used in the context of |
9539 | | another Vulkan instance. |
9540 | | |
9541 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
9542 | | for details. |
9543 | | */ |
9544 | | |
9545 | | /*! |
9546 | | \fn virtual QRhiDriverInfo QRhiAdapter::info() const = 0 |
9547 | | |
9548 | | \return the corresponding QRhiDriverInfo. |
9549 | | */ |
9550 | | |
9551 | | /*! |
9552 | | \internal |
9553 | | */ |
9554 | | QRhiAdapter::~QRhiAdapter() |
9555 | 0 | { |
9556 | 0 | } |
9557 | | |
9558 | | /*! |
9559 | | \return the thread on which the QRhi was \l{QRhi::create()}{initialized}. |
9560 | | */ |
9561 | | QThread *QRhi::thread() const |
9562 | 0 | { |
9563 | 0 | return d->implThread; |
9564 | 0 | } |
9565 | | |
9566 | | /*! |
9567 | | Registers a \a callback that is invoked when the QRhi is destroyed. |
9568 | | |
9569 | | The callback will run with the graphics resource still available, so this |
9570 | | provides an opportunity for the application to cleanly release QRhiResource |
9571 | | instances belonging to the QRhi. This is particularly useful for managing |
9572 | | the lifetime of resources stored in \c cache type of objects, where the |
9573 | | cache holds QRhiResources or objects containing QRhiResources. |
9574 | | |
9575 | | \sa ~QRhi() |
9576 | | */ |
9577 | | void QRhi::addCleanupCallback(const CleanupCallback &callback) |
9578 | 0 | { |
9579 | 0 | d->addCleanupCallback(callback); |
9580 | 0 | } |
9581 | | |
9582 | | /*! |
9583 | | \overload |
9584 | | |
9585 | | Registers \a callback to be invoked when the QRhi is destroyed. This |
9586 | | overload takes an opaque pointer, \a key, that is used to ensure that a |
9587 | | given callback is registered (and so called) only once. |
9588 | | |
9589 | | \sa removeCleanupCallback() |
9590 | | */ |
9591 | | void QRhi::addCleanupCallback(const void *key, const CleanupCallback &callback) |
9592 | 0 | { |
9593 | 0 | d->addCleanupCallback(key, callback); |
9594 | 0 | } |
9595 | | |
9596 | | /*! |
9597 | | Deregisters the callback with \a key. If no cleanup callback was registered |
9598 | | with \a key, the function does nothing. Callbacks registered without a key |
9599 | | cannot be removed. |
9600 | | |
9601 | | \sa addCleanupCallback() |
9602 | | */ |
9603 | | void QRhi::removeCleanupCallback(const void *key) |
9604 | 0 | { |
9605 | 0 | d->removeCleanupCallback(key); |
9606 | 0 | } |
9607 | | |
9608 | | void QRhiImplementation::runCleanup() |
9609 | 0 | { |
9610 | 0 | for (const QRhi::CleanupCallback &f : std::as_const(cleanupCallbacks)) |
9611 | 0 | f(q); |
9612 | |
|
9613 | 0 | cleanupCallbacks.clear(); |
9614 | |
|
9615 | 0 | for (auto it = keyedCleanupCallbacks.cbegin(), end = keyedCleanupCallbacks.cend(); it != end; ++it) |
9616 | 0 | it.value()(q); |
9617 | |
|
9618 | 0 | keyedCleanupCallbacks.clear(); |
9619 | 0 | } |
9620 | | |
9621 | | /*! |
9622 | | \class QRhiResourceUpdateBatch |
9623 | | \inmodule QtGuiPrivate |
9624 | | \inheaderfile rhi/qrhi.h |
9625 | | \since 6.6 |
9626 | | \brief Records upload and copy type of operations. |
9627 | | |
9628 | | With QRhi it is no longer possible to perform copy type of operations at |
9629 | | arbitrary times. Instead, all such operations are recorded into batches |
9630 | | that are then passed, most commonly, to QRhiCommandBuffer::beginPass(). |
9631 | | What then happens under the hood is hidden from the application: the |
9632 | | underlying implementations can defer and implement these operations in |
9633 | | various different ways. |
9634 | | |
9635 | | A resource update batch owns no graphics resources and does not perform any |
9636 | | actual operations on its own. It should rather be viewed as a command |
9637 | | buffer for update, upload, and copy type of commands. |
9638 | | |
9639 | | To get an available, empty batch from the pool, call |
9640 | | QRhi::nextResourceUpdateBatch(). |
9641 | | |
9642 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
9643 | | for details. |
9644 | | */ |
9645 | | |
9646 | | /*! |
9647 | | \internal |
9648 | | */ |
9649 | | QRhiResourceUpdateBatch::QRhiResourceUpdateBatch(QRhiImplementation *rhi) |
9650 | 0 | : d(new QRhiResourceUpdateBatchPrivate) |
9651 | 0 | { |
9652 | 0 | d->q = this; |
9653 | 0 | d->rhi = rhi; |
9654 | 0 | } |
9655 | | |
9656 | | QRhiResourceUpdateBatch::~QRhiResourceUpdateBatch() |
9657 | 0 | { |
9658 | 0 | delete d; |
9659 | 0 | } |
9660 | | |
9661 | | /*! |
9662 | | \return the batch to the pool. This should only be used when the batch is |
9663 | | not passed to one of QRhiCommandBuffer::beginPass(), |
9664 | | QRhiCommandBuffer::endPass(), or QRhiCommandBuffer::resourceUpdate() |
9665 | | because these implicitly call destroy(). |
9666 | | |
9667 | | \note QRhiResourceUpdateBatch instances must never by \c deleted by |
9668 | | applications. |
9669 | | */ |
9670 | | void QRhiResourceUpdateBatch::release() |
9671 | 0 | { |
9672 | 0 | d->free(); |
9673 | 0 | } |
9674 | | |
9675 | | /*! |
9676 | | Copies all queued operations from the \a other batch into this one. |
9677 | | |
9678 | | \note \a other may no longer contain valid data after the merge operation, |
9679 | | and must not be submitted, but it will still need to be released by calling |
9680 | | release(). |
9681 | | |
9682 | | This allows for a convenient pattern where resource updates that are |
9683 | | already known during the initialization step are collected into a batch |
9684 | | that is then merged into another when starting to first render pass later |
9685 | | on: |
9686 | | |
9687 | | \code |
9688 | | void init() |
9689 | | { |
9690 | | initialUpdates = rhi->nextResourceUpdateBatch(); |
9691 | | initialUpdates->uploadStaticBuffer(vbuf, vertexData); |
9692 | | initialUpdates->uploadStaticBuffer(ibuf, indexData); |
9693 | | // ... |
9694 | | } |
9695 | | |
9696 | | void render() |
9697 | | { |
9698 | | QRhiResourceUpdateBatch *resUpdates = rhi->nextResourceUpdateBatch(); |
9699 | | if (initialUpdates) { |
9700 | | resUpdates->merge(initialUpdates); |
9701 | | initialUpdates->release(); |
9702 | | initialUpdates = nullptr; |
9703 | | } |
9704 | | // resUpdates->updateDynamicBuffer(...); |
9705 | | cb->beginPass(rt, clearCol, clearDs, resUpdates); |
9706 | | } |
9707 | | \endcode |
9708 | | */ |
9709 | | void QRhiResourceUpdateBatch::merge(QRhiResourceUpdateBatch *other) |
9710 | 0 | { |
9711 | 0 | d->merge(other->d); |
9712 | 0 | } |
9713 | | |
9714 | | /*! |
9715 | | \return true until the number of buffer and texture operations enqueued |
9716 | | onto this batch is below a reasonable limit. |
9717 | | |
9718 | | The return value is false when the number of buffer and/or texture |
9719 | | operations added to this batch have reached, or are about to reach, a |
9720 | | certain limit. The batch is fully functional afterwards as well, but may |
9721 | | need to allocate additional memory. Therefore, a renderer that collects |
9722 | | lots of buffer and texture updates in a single batch when preparing a frame |
9723 | | may want to consider \l{QRhiCommandBuffer::resourceUpdate()}{submitting the |
9724 | | batch} and \l{QRhi::nextResourceUpdateBatch()}{starting a new one} when |
9725 | | this function returns false. |
9726 | | */ |
9727 | | bool QRhiResourceUpdateBatch::hasOptimalCapacity() const |
9728 | 0 | { |
9729 | 0 | return d->hasOptimalCapacity(); |
9730 | 0 | } |
9731 | | |
9732 | | /*! |
9733 | | Enqueues updating a region of a QRhiBuffer \a buf created with the type |
9734 | | QRhiBuffer::Dynamic. |
9735 | | |
9736 | | The region is specified \a offset and \a size. The actual bytes to write |
9737 | | are specified by \a data which must have at least \a size bytes available. |
9738 | | |
9739 | | \a data is copied and can safely be destroyed or changed once this function |
9740 | | returns. |
9741 | | |
9742 | | \note If host writes are involved, which is the case with |
9743 | | updateDynamicBuffer() typically as such buffers are backed by host visible |
9744 | | memory with most backends, they may accumulate within a frame. Thus pass 1 |
9745 | | reading a region changed by a batch passed to pass 2 may see the changes |
9746 | | specified in pass 2's update batch. |
9747 | | |
9748 | | \note QRhi transparently manages double buffering in order to prevent |
9749 | | stalling the graphics pipeline. The fact that a QRhiBuffer may have |
9750 | | multiple native buffer objects underneath can be safely ignored when using |
9751 | | the QRhi and QRhiResourceUpdateBatch. |
9752 | | */ |
9753 | | void QRhiResourceUpdateBatch::updateDynamicBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data) |
9754 | 0 | { |
9755 | 0 | if (size > 0) { |
9756 | 0 | const int idx = d->activeBufferOpCount++; |
9757 | 0 | const int opListSize = d->bufferOps.size(); |
9758 | 0 | if (idx < opListSize) |
9759 | 0 | QRhiResourceUpdateBatchPrivate::BufferOp::changeToDynamicUpdate(&d->bufferOps[idx], buf, offset, size, data); |
9760 | 0 | else |
9761 | 0 | d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::dynamicUpdate(buf, offset, size, data)); |
9762 | 0 | } |
9763 | 0 | } |
9764 | | |
9765 | | /*! |
9766 | | \overload |
9767 | | \since 6.10 |
9768 | | |
9769 | | Enqueues updating a region of a QRhiBuffer \a buf created with the type |
9770 | | QRhiBuffer::Dynamic. |
9771 | | |
9772 | | \a data is moved into the batch instead of copied with this overload. |
9773 | | */ |
9774 | | void QRhiResourceUpdateBatch::updateDynamicBuffer(QRhiBuffer *buf, quint32 offset, QByteArray data) |
9775 | 0 | { |
9776 | 0 | if (!data.isEmpty()) { |
9777 | 0 | const int idx = d->activeBufferOpCount++; |
9778 | 0 | const int opListSize = d->bufferOps.size(); |
9779 | 0 | if (idx < opListSize) |
9780 | 0 | QRhiResourceUpdateBatchPrivate::BufferOp::changeToDynamicUpdate(&d->bufferOps[idx], buf, offset, std::move(data)); |
9781 | 0 | else |
9782 | 0 | d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::dynamicUpdate(buf, offset, std::move(data))); |
9783 | 0 | } |
9784 | 0 | } |
9785 | | |
9786 | | /*! |
9787 | | Enqueues updating a region of a QRhiBuffer \a buf created with the type |
9788 | | QRhiBuffer::Immutable or QRhiBuffer::Static. |
9789 | | |
9790 | | The region is specified \a offset and \a size. The actual bytes to write |
9791 | | are specified by \a data which must have at least \a size bytes available. |
9792 | | |
9793 | | \a data is copied and can safely be destroyed or changed once this function |
9794 | | returns. |
9795 | | */ |
9796 | | void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data) |
9797 | 0 | { |
9798 | 0 | if (size > 0) { |
9799 | 0 | const int idx = d->activeBufferOpCount++; |
9800 | 0 | if (idx < d->bufferOps.size()) |
9801 | 0 | QRhiResourceUpdateBatchPrivate::BufferOp::changeToStaticUpload(&d->bufferOps[idx], buf, offset, size, data); |
9802 | 0 | else |
9803 | 0 | d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, offset, size, data)); |
9804 | 0 | } |
9805 | 0 | } |
9806 | | |
9807 | | /*! |
9808 | | \overload |
9809 | | \since 6.10 |
9810 | | |
9811 | | Enqueues updating a region of a QRhiBuffer \a buf created with the type |
9812 | | QRhiBuffer::Immutable or QRhiBuffer::Static. |
9813 | | |
9814 | | \a data is moved into the batch instead of copied with this overload. |
9815 | | */ |
9816 | | void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, quint32 offset, QByteArray data) |
9817 | 0 | { |
9818 | 0 | if (!data.isEmpty()) { |
9819 | 0 | const int idx = d->activeBufferOpCount++; |
9820 | 0 | if (idx < d->bufferOps.size()) |
9821 | 0 | QRhiResourceUpdateBatchPrivate::BufferOp::changeToStaticUpload(&d->bufferOps[idx], buf, offset, std::move(data)); |
9822 | 0 | else |
9823 | 0 | d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, offset, std::move(data))); |
9824 | 0 | } |
9825 | 0 | } |
9826 | | |
9827 | | /*! |
9828 | | \overload |
9829 | | |
9830 | | Enqueues updating the entire QRhiBuffer \a buf created with the type |
9831 | | QRhiBuffer::Immutable or QRhiBuffer::Static. |
9832 | | */ |
9833 | | void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *data) |
9834 | 0 | { |
9835 | 0 | if (buf->size() > 0) { |
9836 | 0 | const int idx = d->activeBufferOpCount++; |
9837 | 0 | if (idx < d->bufferOps.size()) |
9838 | 0 | QRhiResourceUpdateBatchPrivate::BufferOp::changeToStaticUpload(&d->bufferOps[idx], buf, 0, 0, data); |
9839 | 0 | else |
9840 | 0 | d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, 0, 0, data)); |
9841 | 0 | } |
9842 | 0 | } |
9843 | | |
9844 | | /*! |
9845 | | \overload |
9846 | | \since 6.10 |
9847 | | |
9848 | | Enqueues updating the entire QRhiBuffer \a buf created with the type |
9849 | | QRhiBuffer::Immutable or QRhiBuffer::Static. |
9850 | | |
9851 | | \a data is moved into the batch instead of copied with this overload. |
9852 | | |
9853 | | \a data size must equal the size of \a buf. |
9854 | | */ |
9855 | | void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, QByteArray data) |
9856 | 0 | { |
9857 | 0 | if (buf->size() > 0 && quint32(data.size()) == buf->size()) { |
9858 | 0 | const int idx = d->activeBufferOpCount++; |
9859 | 0 | if (idx < d->bufferOps.size()) |
9860 | 0 | QRhiResourceUpdateBatchPrivate::BufferOp::changeToStaticUpload(&d->bufferOps[idx], buf, 0, std::move(data)); |
9861 | 0 | else |
9862 | 0 | d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, 0, std::move(data))); |
9863 | 0 | } |
9864 | 0 | } |
9865 | | |
9866 | | /*! |
9867 | | Enqueues reading back a region of the QRhiBuffer \a buf. The size of the |
9868 | | region is specified by \a size in bytes, \a offset is the offset in bytes |
9869 | | to start reading from. |
9870 | | |
9871 | | A readback is asynchronous. \a result contains a callback that is invoked |
9872 | | when the operation has completed. The data is provided in |
9873 | | QRhiReadbackResult::data. Upon successful completion that QByteArray |
9874 | | will have a size equal to \a size. On failure the QByteArray will be empty. |
9875 | | |
9876 | | \note Reading buffers with a usage different than QRhiBuffer::UniformBuffer |
9877 | | is supported only when the QRhi::ReadBackNonUniformBuffer feature is |
9878 | | reported as supported. |
9879 | | |
9880 | | \note The asynchronous readback is guaranteed to have completed when one of |
9881 | | the following conditions is met: \l{QRhi::finish()}{finish()} has been |
9882 | | called; or, at least \c N frames have been \l{QRhi::endFrame()}{submitted}, |
9883 | | including the frame that issued the readback operation, and the |
9884 | | \l{QRhi::beginFrame()}{recording of a new frame} has been started, where \c |
9885 | | N is the \l{QRhi::resourceLimit()}{resource limit value} returned for |
9886 | | QRhi::MaxAsyncReadbackFrames. |
9887 | | |
9888 | | \sa readBackTexture(), QRhi::isFeatureSupported(), QRhi::resourceLimit() |
9889 | | */ |
9890 | | void QRhiResourceUpdateBatch::readBackBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiReadbackResult *result) |
9891 | 0 | { |
9892 | 0 | const int idx = d->activeBufferOpCount++; |
9893 | 0 | if (idx < d->bufferOps.size()) |
9894 | 0 | d->bufferOps[idx] = QRhiResourceUpdateBatchPrivate::BufferOp::read(buf, offset, size, result); |
9895 | 0 | else |
9896 | 0 | d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::read(buf, offset, size, result)); |
9897 | 0 | } |
9898 | | |
9899 | | /*! |
9900 | | Enqueues uploading the image data for one or more mip levels in one or more |
9901 | | layers of the texture \a tex. |
9902 | | |
9903 | | The details of the copy (source QImage or compressed texture data, regions, |
9904 | | target layers and levels) are described in \a desc. |
9905 | | */ |
9906 | | void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc) |
9907 | 0 | { |
9908 | 0 | if (desc.cbeginEntries() != desc.cendEntries()) { |
9909 | 0 | const int idx = d->activeTextureOpCount++; |
9910 | 0 | if (idx < d->textureOps.size()) |
9911 | 0 | d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::upload(tex, desc); |
9912 | 0 | else |
9913 | 0 | d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::upload(tex, desc)); |
9914 | 0 | } |
9915 | 0 | } |
9916 | | |
9917 | | /*! |
9918 | | Enqueues uploading the image data for mip level 0 of layer 0 of the texture |
9919 | | \a tex. |
9920 | | |
9921 | | \a tex must have an uncompressed format. Its format must also be compatible |
9922 | | with the QImage::format() of \a image. The source data is given in \a |
9923 | | image. |
9924 | | */ |
9925 | | void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QImage &image) |
9926 | 0 | { |
9927 | 0 | uploadTexture(tex, |
9928 | 0 | QRhiTextureUploadEntry(0, 0, QRhiTextureSubresourceUploadDescription(image))); |
9929 | 0 | } |
9930 | | |
9931 | | /*! |
9932 | | Enqueues a texture-to-texture copy operation from \a src into \a dst as |
9933 | | described by \a desc. |
9934 | | |
9935 | | \note The source texture \a src must be created with |
9936 | | QRhiTexture::UsedAsTransferSource. |
9937 | | |
9938 | | \note The format of the textures must match. With most graphics |
9939 | | APIs the data is copied as-is without any format conversions. If |
9940 | | \a dst and \a src are created with different formats, unspecified |
9941 | | issues may arise. |
9942 | | */ |
9943 | | void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc) |
9944 | 0 | { |
9945 | 0 | const int idx = d->activeTextureOpCount++; |
9946 | 0 | if (idx < d->textureOps.size()) |
9947 | 0 | d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::copy(dst, src, desc); |
9948 | 0 | else |
9949 | 0 | d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::copy(dst, src, desc)); |
9950 | 0 | } |
9951 | | |
9952 | | /*! |
9953 | | Enqueues a texture-to-host copy operation as described by \a rb. |
9954 | | |
9955 | | Normally \a rb will specify a QRhiTexture as the source. However, when the |
9956 | | swapchain in the current frame was created with |
9957 | | QRhiSwapChain::UsedAsTransferSource, it can also be the source of the |
9958 | | readback. For this, leave the texture set to null in \a rb. |
9959 | | |
9960 | | Unlike other operations, the results here need to be processed by the |
9961 | | application. Therefore, \a result provides not just the data but also a |
9962 | | callback as operations on the batch are asynchronous by nature: |
9963 | | |
9964 | | \code |
9965 | | rhi->beginFrame(swapchain); |
9966 | | cb->beginPass(swapchain->currentFrameRenderTarget(), colorClear, dsClear); |
9967 | | // ... |
9968 | | QRhiReadbackResult *rbResult = new QRhiReadbackResult; |
9969 | | rbResult->completed = [rbResult] { |
9970 | | { |
9971 | | const QImage::Format fmt = QImage::Format_RGBA8888_Premultiplied; // fits QRhiTexture::RGBA8 |
9972 | | const uchar *p = reinterpret_cast<const uchar *>(rbResult->data.constData()); |
9973 | | QImage image(p, rbResult->pixelSize.width(), rbResult->pixelSize.height(), fmt); |
9974 | | image.save("result.png"); |
9975 | | } |
9976 | | delete rbResult; |
9977 | | }; |
9978 | | QRhiResourceUpdateBatch *u = nextResourceUpdateBatch(); |
9979 | | QRhiReadbackDescription rb; // no texture -> uses the current backbuffer of sc |
9980 | | u->readBackTexture(rb, rbResult); |
9981 | | cb->endPass(u); |
9982 | | rhi->endFrame(swapchain); |
9983 | | \endcode |
9984 | | |
9985 | | \note The texture must be created with QRhiTexture::UsedAsTransferSource. |
9986 | | |
9987 | | \note Multisample textures cannot be read back. |
9988 | | |
9989 | | \note The readback returns raw byte data, in order to allow the applications |
9990 | | to interpret it in any way they see fit. Be aware of the blending settings |
9991 | | of rendering code: if the blending is set up to rely on premultiplied alpha, |
9992 | | the results of the readback must also be interpreted as Premultiplied. |
9993 | | |
9994 | | \note When interpreting the resulting raw data, be aware that the readback |
9995 | | happens with a byte ordered format. A \l{QRhiTexture::RGBA8}{RGBA8} texture |
9996 | | maps therefore to byte ordered QImage formats, such as, |
9997 | | QImage::Format_RGBA8888. |
9998 | | |
9999 | | \note The asynchronous readback is guaranteed to have completed when one of |
10000 | | the following conditions is met: \l{QRhi::finish()}{finish()} has been |
10001 | | called; or, at least \c N frames have been \l{QRhi::endFrame()}{submitted}, |
10002 | | including the frame that issued the readback operation, and the |
10003 | | \l{QRhi::beginFrame()}{recording of a new frame} has been started, where \c |
10004 | | N is the \l{QRhi::resourceLimit()}{resource limit value} returned for |
10005 | | QRhi::MaxAsyncReadbackFrames. |
10006 | | |
10007 | | A single readback operation copies one mip level of one layer (cubemap face |
10008 | | or 3D slice or texture array element) at a time. The level and layer are |
10009 | | specified by the respective fields in \a rb. |
10010 | | |
10011 | | \sa readBackBuffer(), QRhi::resourceLimit() |
10012 | | */ |
10013 | | void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result) |
10014 | 0 | { |
10015 | 0 | const int idx = d->activeTextureOpCount++; |
10016 | 0 | if (idx < d->textureOps.size()) |
10017 | 0 | d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::read(rb, result); |
10018 | 0 | else |
10019 | 0 | d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::read(rb, result)); |
10020 | 0 | } |
10021 | | |
10022 | | /*! |
10023 | | Enqueues a mipmap generation operation for the specified texture \a tex. |
10024 | | |
10025 | | 2D and cube textures are supported. 1D and 3D textures are supported when |
10026 | | the QRhi::OneDimensionalTextureMipmaps or QRhi::ThreeDimensionalTextureMipmaps |
10027 | | feature is reported as supported, respectively. |
10028 | | |
10029 | | \note The texture must be created with QRhiTexture::MipMapped and |
10030 | | QRhiTexture::UsedWithGenerateMips. |
10031 | | |
10032 | | \warning QRhi cannot guarantee that mipmaps can be generated for all |
10033 | | supported texture formats. For example, QRhiTexture::RGBA32F is not a \c |
10034 | | filterable format in OpenGL ES 3.0 and Metal on iOS, and therefore the |
10035 | | mipmap generation request may fail. RGBA8 and RGBA16F are typically |
10036 | | filterable, so it is recommended to use these formats when mipmap generation |
10037 | | is desired. |
10038 | | */ |
10039 | | void QRhiResourceUpdateBatch::generateMips(QRhiTexture *tex) |
10040 | 0 | { |
10041 | 0 | const int idx = d->activeTextureOpCount++; |
10042 | 0 | if (idx < d->textureOps.size()) |
10043 | 0 | d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex); |
10044 | 0 | else |
10045 | 0 | d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex)); |
10046 | 0 | } |
10047 | | |
10048 | | /*! |
10049 | | \return an available, empty batch to which copy type of operations can be |
10050 | | recorded. |
10051 | | |
10052 | | \note the return value is not owned by the caller and must never be |
10053 | | destroyed. Instead, the batch is returned the pool for reuse by passing |
10054 | | it to QRhiCommandBuffer::beginPass(), QRhiCommandBuffer::endPass(), or |
10055 | | QRhiCommandBuffer::resourceUpdate(), or by calling |
10056 | | QRhiResourceUpdateBatch::release() on it. |
10057 | | |
10058 | | \note Can be called outside beginFrame() - endFrame() as well since a batch |
10059 | | instance just collects data on its own, it does not perform any operations. |
10060 | | |
10061 | | Due to not being tied to a frame being recorded, the following sequence is |
10062 | | valid for example: |
10063 | | |
10064 | | \code |
10065 | | rhi->beginFrame(swapchain); |
10066 | | QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch(); |
10067 | | u->uploadStaticBuffer(buf, data); |
10068 | | // ... do not commit the batch |
10069 | | rhi->endFrame(); |
10070 | | // u stays valid (assuming buf stays valid as well) |
10071 | | rhi->beginFrame(swapchain); |
10072 | | swapchain->currentFrameCommandBuffer()->resourceUpdate(u); |
10073 | | // ... draw with buf |
10074 | | rhi->endFrame(); |
10075 | | \endcode |
10076 | | |
10077 | | \warning The maximum number of batches per QRhi is 64. When this limit is |
10078 | | reached, the function will return null until a batch is returned to the |
10079 | | pool. |
10080 | | */ |
10081 | | QRhiResourceUpdateBatch *QRhi::nextResourceUpdateBatch() |
10082 | 0 | { |
10083 | | // By default we prefer spreading out the utilization of the worst case 64 |
10084 | | // (but typically 4) batches as much as possible, meaning we won't pick the |
10085 | | // first one even if it's free, but prefer picking one after the last picked |
10086 | | // one. Relevant due to implicit sharing (the backend may hold on to the |
10087 | | // QRhiBufferData until frame no. current+FramesInFlight-1, but |
10088 | | // implementations may vary), combined with the desire to reuse container |
10089 | | // and QRhiBufferData allocations in bufferOps instead of flooding every |
10090 | | // frame with allocs. See free(). In typical Qt Quick scenes this leads to |
10091 | | // eventually seeding all 4 (or more) resource batches with buffer operation |
10092 | | // data allocations which may (*) then be reused in subsequent frames. This |
10093 | | // comes at the expense of using more memory, but has proven good results |
10094 | | // when (CPU) profiling typical Quick/Quick3D apps. |
10095 | | // |
10096 | | // (*) Due to implicit sharing(ish), the exact behavior is unpredictable. If |
10097 | | // a backend holds on to the QRhiBufferData for, e.g., a dynamic buffer |
10098 | | // update, and then there is a new assign() for that same QRhiBufferData |
10099 | | // while the refcount is still 2, it will "detach" (without contents) and |
10100 | | // there is no reuse of the alloc. This is mitigated by the 'choose the one |
10101 | | // afer the last picked one' logic when handing out batches. |
10102 | |
|
10103 | 0 | auto nextFreeBatch = [this]() -> QRhiResourceUpdateBatch * { |
10104 | 0 | auto isFree = [this](int i) -> QRhiResourceUpdateBatch * { |
10105 | 0 | const quint64 mask = 1ULL << quint64(i); |
10106 | 0 | if (!(d->resUpdPoolMap & mask)) { |
10107 | 0 | d->resUpdPoolMap |= mask; |
10108 | 0 | QRhiResourceUpdateBatch *u = d->resUpdPool[i]; |
10109 | 0 | QRhiResourceUpdateBatchPrivate::get(u)->poolIndex = i; |
10110 | 0 | d->lastResUpdIdx = i; |
10111 | 0 | return u; |
10112 | 0 | } |
10113 | 0 | return nullptr; |
10114 | 0 | }; |
10115 | 0 | const int poolSize = d->resUpdPool.size(); |
10116 | 0 | for (int i = d->lastResUpdIdx + 1; i < poolSize; ++i) { |
10117 | 0 | if (QRhiResourceUpdateBatch *u = isFree(i)) |
10118 | 0 | return u; |
10119 | 0 | } |
10120 | 0 | for (int i = 0; i <= d->lastResUpdIdx; ++i) { |
10121 | 0 | if (QRhiResourceUpdateBatch *u = isFree(i)) |
10122 | 0 | return u; |
10123 | 0 | } |
10124 | 0 | return nullptr; |
10125 | 0 | }; |
10126 | |
|
10127 | 0 | QRhiResourceUpdateBatch *u = nextFreeBatch(); |
10128 | 0 | if (!u) { |
10129 | 0 | const int oldSize = d->resUpdPool.size(); |
10130 | | // 4, 8, 12, ..., up to 64 |
10131 | 0 | const int newSize = oldSize + qMin(4, qMax(0, 64 - oldSize)); |
10132 | 0 | d->resUpdPool.resize(newSize); |
10133 | 0 | for (int i = oldSize; i < newSize; ++i) |
10134 | 0 | d->resUpdPool[i] = new QRhiResourceUpdateBatch(d); |
10135 | 0 | u = nextFreeBatch(); |
10136 | 0 | if (!u) |
10137 | 0 | qWarning("Resource update batch pool exhausted (max is 64)"); |
10138 | 0 | } |
10139 | |
|
10140 | 0 | return u; |
10141 | 0 | } |
10142 | | |
10143 | | void QRhiResourceUpdateBatchPrivate::free() |
10144 | 0 | { |
10145 | 0 | Q_ASSERT(poolIndex >= 0 && rhi->resUpdPool[poolIndex] == q); |
10146 | |
|
10147 | 0 | quint32 bufferDataTotal = 0; |
10148 | 0 | quint32 bufferLargeAllocTotal = 0; |
10149 | 0 | for (const BufferOp &op : std::as_const(bufferOps)) { |
10150 | 0 | bufferDataTotal += op.data.size(); |
10151 | 0 | bufferLargeAllocTotal += op.data.largeAlloc(); // alloc when > 1 KB |
10152 | 0 | } |
10153 | |
|
10154 | 0 | if (QRHI_LOG_RUB().isDebugEnabled()) { |
10155 | 0 | qDebug() << "[rub] release to pool upd.batch #" << poolIndex |
10156 | 0 | << "/ bufferOps active" << activeBufferOpCount |
10157 | 0 | << "of" << bufferOps.count() |
10158 | 0 | << "data" << bufferDataTotal |
10159 | 0 | << "largeAlloc" << bufferLargeAllocTotal |
10160 | 0 | << "textureOps active" << activeTextureOpCount |
10161 | 0 | << "of" << textureOps.count(); |
10162 | 0 | } |
10163 | |
|
10164 | 0 | activeBufferOpCount = 0; |
10165 | 0 | activeTextureOpCount = 0; |
10166 | |
|
10167 | 0 | const quint64 mask = 1ULL << quint64(poolIndex); |
10168 | 0 | rhi->resUpdPoolMap &= ~mask; |
10169 | 0 | poolIndex = -1; |
10170 | | |
10171 | | // textureOps is cleared, to not keep the potentially large image pixel |
10172 | | // data alive, but it is expected that the container keeps the list alloc |
10173 | | // at least. Only trimOpList() goes for the more aggressive route with squeeze. |
10174 | 0 | textureOps.clear(); |
10175 | | |
10176 | | // bufferOps is not touched in many cases, to allow reusing allocations |
10177 | | // (incl. in the elements' QRhiBufferData) as much as possible when this |
10178 | | // batch is used again in the future, which is important for performance, in |
10179 | | // particular with Qt Quick where it is easy for scenes to produce lots of, |
10180 | | // typically small buffer changes on every frame. |
10181 | | // |
10182 | | // However, ensure that even in the unlikely case of having the max number |
10183 | | // of batches (64) created in resUpdPool, no more than 64 MB in total is |
10184 | | // used up by buffer data just to help future reuse. For simplicity, if |
10185 | | // there is more than 1 MB data -> clear. Applications with frequent, huge |
10186 | | // buffer updates probably have other bottlenecks anyway. |
10187 | 0 | if (bufferLargeAllocTotal > 1024 * 1024) |
10188 | 0 | bufferOps.clear(); |
10189 | 0 | } |
10190 | | |
10191 | | void QRhiResourceUpdateBatchPrivate::merge(QRhiResourceUpdateBatchPrivate *other) |
10192 | 0 | { |
10193 | 0 | int combinedSize = activeBufferOpCount + other->activeBufferOpCount; |
10194 | 0 | if (bufferOps.size() < combinedSize) |
10195 | 0 | bufferOps.resize(combinedSize); |
10196 | 0 | for (int i = activeBufferOpCount; i < combinedSize; ++i) |
10197 | 0 | bufferOps[i] = std::move(other->bufferOps[i - activeBufferOpCount]); |
10198 | 0 | activeBufferOpCount += other->activeBufferOpCount; |
10199 | |
|
10200 | 0 | combinedSize = activeTextureOpCount + other->activeTextureOpCount; |
10201 | 0 | if (textureOps.size() < combinedSize) |
10202 | 0 | textureOps.resize(combinedSize); |
10203 | 0 | for (int i = activeTextureOpCount; i < combinedSize; ++i) |
10204 | 0 | textureOps[i] = std::move(other->textureOps[i - activeTextureOpCount]); |
10205 | 0 | activeTextureOpCount += other->activeTextureOpCount; |
10206 | 0 | } |
10207 | | |
10208 | | bool QRhiResourceUpdateBatchPrivate::hasOptimalCapacity() const |
10209 | 0 | { |
10210 | 0 | return activeBufferOpCount < BUFFER_OPS_STATIC_ALLOC - 4 |
10211 | 0 | && activeTextureOpCount < TEXTURE_OPS_STATIC_ALLOC - 4; |
10212 | 0 | } |
10213 | | |
10214 | | void QRhiResourceUpdateBatchPrivate::trimOpLists() |
10215 | 0 | { |
10216 | | // Unlike free(), this is expected to aggressively deallocate all memory |
10217 | | // used by both the buffer and texture operation lists. (i.e. using |
10218 | | // squeeze() to only keep the stack prealloc of the QVLAs) |
10219 | | // |
10220 | | // This (e.g. just the destruction of bufferOps elements) may have a |
10221 | | // non-negligible performance impact e.g. with Qt Quick with scenes where |
10222 | | // there are lots of buffer operations per frame. |
10223 | |
|
10224 | 0 | activeBufferOpCount = 0; |
10225 | 0 | bufferOps.clear(); |
10226 | 0 | bufferOps.squeeze(); |
10227 | |
|
10228 | 0 | activeTextureOpCount = 0; |
10229 | 0 | textureOps.clear(); |
10230 | 0 | textureOps.squeeze(); |
10231 | 0 | } |
10232 | | |
10233 | | /*! |
10234 | | Sometimes committing resource updates is necessary or just more convenient |
10235 | | without starting a render pass. Calling this function with \a |
10236 | | resourceUpdates is an alternative to passing \a resourceUpdates to a |
10237 | | beginPass() call (or endPass(), which would be typical in case of readbacks). |
10238 | | |
10239 | | \note Cannot be called inside a pass. |
10240 | | */ |
10241 | | void QRhiCommandBuffer::resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates) |
10242 | 0 | { |
10243 | 0 | if (resourceUpdates) |
10244 | 0 | m_rhi->resourceUpdate(this, resourceUpdates); |
10245 | 0 | } |
10246 | | |
10247 | | /*! |
10248 | | Records starting a new render pass targeting the render target \a rt. |
10249 | | |
10250 | | \a resourceUpdates, when not null, specifies a resource update batch that |
10251 | | is to be committed and then released. |
10252 | | |
10253 | | The color and depth/stencil buffers of the render target are normally |
10254 | | cleared. The clear values are specified in \a colorClearValue and \a |
10255 | | depthStencilClearValue. The exception is when the render target was created |
10256 | | with QRhiTextureRenderTarget::PreserveColorContents and/or |
10257 | | QRhiTextureRenderTarget::PreserveDepthStencilContents. The clear values are |
10258 | | ignored then. |
10259 | | |
10260 | | \note Enabling preserved color or depth contents leads to decreased |
10261 | | performance depending on the underlying hardware. Mobile GPUs with tiled |
10262 | | architecture benefit from not having to reload the previous contents into |
10263 | | the tile buffer. Similarly, a QRhiTextureRenderTarget with a QRhiTexture as |
10264 | | the depth buffer is less efficient than a QRhiRenderBuffer since using a |
10265 | | depth texture triggers requiring writing the data out to it, while with |
10266 | | renderbuffers this is not needed (as the API does not allow sampling or |
10267 | | reading from a renderbuffer). |
10268 | | |
10269 | | \note Do not assume that any state or resource bindings persist between |
10270 | | passes. |
10271 | | |
10272 | | \note The QRhiCommandBuffer's \c set and \c draw functions can only be |
10273 | | called inside a pass. Also, with the exception of setGraphicsPipeline(), |
10274 | | they expect to have a pipeline set already on the command buffer. |
10275 | | Unspecified issues may arise otherwise, depending on the backend. |
10276 | | |
10277 | | If \a rt is a QRhiTextureRenderTarget, beginPass() performs a check to see |
10278 | | if the texture and renderbuffer objects referenced from the render target |
10279 | | are up-to-date. This is similar to what setShaderResources() does for |
10280 | | QRhiShaderResourceBindings. If any of the attachments had been rebuilt |
10281 | | since QRhiTextureRenderTarget::create(), an implicit call to create() is |
10282 | | made on \a rt. Therefore, if \a rt has a QRhiTexture color attachment \c |
10283 | | texture, and one needs to make the texture a different size, the following |
10284 | | is then valid: |
10285 | | \code |
10286 | | QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ { texture } }); |
10287 | | rt->create(); |
10288 | | // ... |
10289 | | texture->setPixelSize(new_size); |
10290 | | texture->create(); |
10291 | | cb->beginPass(rt, colorClear, dsClear); // this is ok, no explicit rt->create() is required before |
10292 | | \endcode |
10293 | | |
10294 | | \a flags allow controlling certain advanced functionality. One commonly used |
10295 | | flag is \c ExternalContents. This should be specified whenever |
10296 | | beginExternal() will be called within the pass started by this function. |
10297 | | |
10298 | | \sa endPass(), BeginPassFlags |
10299 | | */ |
10300 | | void QRhiCommandBuffer::beginPass(QRhiRenderTarget *rt, |
10301 | | const QColor &colorClearValue, |
10302 | | const QRhiDepthStencilClearValue &depthStencilClearValue, |
10303 | | QRhiResourceUpdateBatch *resourceUpdates, |
10304 | | BeginPassFlags flags) |
10305 | 0 | { |
10306 | 0 | m_rhi->beginPass(this, rt, colorClearValue, depthStencilClearValue, resourceUpdates, flags); |
10307 | 0 | } |
10308 | | |
10309 | | /*! |
10310 | | Records ending the current render pass. |
10311 | | |
10312 | | \a resourceUpdates, when not null, specifies a resource update batch that |
10313 | | is to be committed and then released. |
10314 | | |
10315 | | \sa beginPass() |
10316 | | */ |
10317 | | void QRhiCommandBuffer::endPass(QRhiResourceUpdateBatch *resourceUpdates) |
10318 | 0 | { |
10319 | 0 | m_rhi->endPass(this, resourceUpdates); |
10320 | 0 | } |
10321 | | |
10322 | | /*! |
10323 | | Records setting a new graphics pipeline \a ps. |
10324 | | |
10325 | | \note This function must be called before recording other \c set or \c draw |
10326 | | commands on the command buffer. |
10327 | | |
10328 | | \note QRhi will optimize out unnecessary invocations within a pass, so |
10329 | | therefore overoptimizing to avoid calls to this function is not necessary |
10330 | | on the applications' side. |
10331 | | |
10332 | | \note This function can only be called inside a render pass, meaning |
10333 | | between a beginPass() and endPass() call. |
10334 | | |
10335 | | \note The new graphics pipeline \a ps must be a valid pointer. |
10336 | | |
10337 | | Setting a graphics pipeline that does not have the |
10338 | | \l{QRhiGraphicsPipeline::}{UsesScissor} flag will either disable scissoring, |
10339 | | with graphics APIs where that is applicable, or set the scissor rectangle to |
10340 | | match the viewport that was last set (with graphics APIs where scissoring is |
10341 | | effectively always active), in order to ensure a uniform behavior across QRhi |
10342 | | backends. |
10343 | | */ |
10344 | | void QRhiCommandBuffer::setGraphicsPipeline(QRhiGraphicsPipeline *ps) |
10345 | 0 | { |
10346 | 0 | Q_ASSERT(ps != nullptr); |
10347 | 0 | m_rhi->setGraphicsPipeline(this, ps); |
10348 | 0 | } |
10349 | | |
10350 | | /*! |
10351 | | Records binding a set of shader resources, such as, uniform buffers or |
10352 | | textures, that are made visible to one or more shader stages. |
10353 | | |
10354 | | \a srb can be null in which case the current graphics or compute pipeline's |
10355 | | associated QRhiShaderResourceBindings is used. When \a srb is non-null, it |
10356 | | must be |
10357 | | \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible}, |
10358 | | meaning the layout (number of bindings, the type and binding number of each |
10359 | | binding) must fully match the QRhiShaderResourceBindings that was |
10360 | | associated with the pipeline at the time of calling the pipeline's create(). |
10361 | | |
10362 | | There are cases when a seemingly unnecessary setShaderResources() call is |
10363 | | mandatory: when rebuilding a resource referenced from \a srb, for example |
10364 | | changing the size of a QRhiBuffer followed by a QRhiBuffer::create(), this |
10365 | | is the place where associated native objects (such as descriptor sets in |
10366 | | case of Vulkan) are updated to refer to the current native resources that |
10367 | | back the QRhiBuffer, QRhiTexture, QRhiSampler objects referenced from \a |
10368 | | srb. In this case setShaderResources() must be called even if \a srb is |
10369 | | the same as in the last call. |
10370 | | |
10371 | | When \a srb is not null, the QRhiShaderResourceBindings object the pipeline |
10372 | | was built with in create() is guaranteed to be not accessed in any form. In |
10373 | | fact, it does not need to be valid even at this point: destroying the |
10374 | | pipeline's associated srb after create() and instead explicitly specifying |
10375 | | another, \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout |
10376 | | compatible} one in every setShaderResources() call is valid. |
10377 | | |
10378 | | \a dynamicOffsets allows specifying buffer offsets for uniform buffers that |
10379 | | were associated with \a srb via |
10380 | | QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(). This is |
10381 | | different from providing the offset in the \a srb itself: dynamic offsets |
10382 | | do not require building a new QRhiShaderResourceBindings for every |
10383 | | different offset, can avoid writing the underlying descriptors (with |
10384 | | backends where applicable), and so they may be more efficient. Each element |
10385 | | of \a dynamicOffsets is a \c binding - \c offset pair. |
10386 | | \a dynamicOffsetCount specifies the number of elements in \a dynamicOffsets. |
10387 | | |
10388 | | \note All offsets in \a dynamicOffsets must be byte aligned to the value |
10389 | | returned from QRhi::ubufAlignment(). |
10390 | | |
10391 | | \note Some backends may limit the number of supported dynamic offsets. |
10392 | | Avoid using a \a dynamicOffsetCount larger than 8. |
10393 | | |
10394 | | \note QRhi will optimize out unnecessary invocations within a pass (taking |
10395 | | the conditions described above into account), so therefore overoptimizing |
10396 | | to avoid calls to this function is not necessary on the applications' side. |
10397 | | |
10398 | | \note This function can only be called inside a render or compute pass, |
10399 | | meaning between a beginPass() and endPass(), or beginComputePass() and |
10400 | | endComputePass(). |
10401 | | */ |
10402 | | void QRhiCommandBuffer::setShaderResources(QRhiShaderResourceBindings *srb, |
10403 | | int dynamicOffsetCount, |
10404 | | const DynamicOffset *dynamicOffsets) |
10405 | 0 | { |
10406 | 0 | m_rhi->setShaderResources(this, srb, dynamicOffsetCount, dynamicOffsets); |
10407 | 0 | } |
10408 | | |
10409 | | /*! |
10410 | | Records vertex input bindings. |
10411 | | |
10412 | | The index buffer used by subsequent drawIndexed() commands is specified by |
10413 | | \a indexBuf, \a indexOffset, and \a indexFormat. \a indexBuf can be set to |
10414 | | null when indexed drawing is not needed. |
10415 | | |
10416 | | Vertex buffer bindings are batched. \a startBinding specifies the first |
10417 | | binding number. The recorded command then binds each buffer from \a |
10418 | | bindings to the binding point \c{startBinding + i} where \c i is the index |
10419 | | in \a bindings. Each element in \a bindings specifies a QRhiBuffer and an |
10420 | | offset. |
10421 | | |
10422 | | \note Some backends may limit the number of vertex buffer bindings. Avoid |
10423 | | using a \a bindingCount larger than 8. |
10424 | | |
10425 | | Superfluous vertex input and index changes in the same pass are ignored |
10426 | | automatically with most backends and therefore applications do not need to |
10427 | | overoptimize to avoid calls to this function. |
10428 | | |
10429 | | \note This function can only be called inside a render pass, meaning |
10430 | | between a beginPass() and endPass() call. |
10431 | | |
10432 | | As a simple example, take a vertex shader with two inputs: |
10433 | | |
10434 | | \badcode |
10435 | | layout(location = 0) in vec4 position; |
10436 | | layout(location = 1) in vec3 color; |
10437 | | \endcode |
10438 | | |
10439 | | and assume we have the data available in interleaved format, using only 2 |
10440 | | floats for position (so 5 floats per vertex: x, y, r, g, b). A QRhiGraphicsPipeline for |
10441 | | this shader can then be created using the input layout: |
10442 | | |
10443 | | \code |
10444 | | QRhiVertexInputLayout inputLayout; |
10445 | | inputLayout.setBindings({ |
10446 | | { 5 * sizeof(float) } |
10447 | | }); |
10448 | | inputLayout.setAttributes({ |
10449 | | { 0, 0, QRhiVertexInputAttribute::Float2, 0 }, |
10450 | | { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) } |
10451 | | }); |
10452 | | \endcode |
10453 | | |
10454 | | Here there is one buffer binding (binding number 0), with two inputs |
10455 | | referencing it. When recording the pass, once the pipeline is set, the |
10456 | | vertex bindings can be specified simply like the following, assuming vbuf |
10457 | | is the QRhiBuffer with all the interleaved position+color data: |
10458 | | |
10459 | | \code |
10460 | | const QRhiCommandBuffer::VertexInput vbufBinding(vbuf, 0); |
10461 | | cb->setVertexInput(0, 1, &vbufBinding); |
10462 | | \endcode |
10463 | | */ |
10464 | | void QRhiCommandBuffer::setVertexInput(int startBinding, int bindingCount, const VertexInput *bindings, |
10465 | | QRhiBuffer *indexBuf, quint32 indexOffset, |
10466 | | IndexFormat indexFormat) |
10467 | 0 | { |
10468 | 0 | m_rhi->setVertexInput(this, startBinding, bindingCount, bindings, indexBuf, indexOffset, indexFormat); |
10469 | 0 | } |
10470 | | |
10471 | | /*! |
10472 | | Records setting the active viewport rectangle specified in \a viewport. |
10473 | | |
10474 | | With backends where the underlying graphics API has scissoring always |
10475 | | enabled, this function also sets the scissor to match the viewport whenever |
10476 | | the active QRhiGraphicsPipeline does not have |
10477 | | \l{QRhiGraphicsPipeline::UsesScissor}{UsesScissor} set. |
10478 | | |
10479 | | \note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are |
10480 | | bottom-left. |
10481 | | |
10482 | | \note This function can only be called inside a render pass, meaning |
10483 | | between a beginPass() and endPass() call. |
10484 | | */ |
10485 | | void QRhiCommandBuffer::setViewport(const QRhiViewport &viewport) |
10486 | 0 | { |
10487 | 0 | m_rhi->setViewport(this, viewport); |
10488 | 0 | } |
10489 | | |
10490 | | /*! |
10491 | | Records setting the active scissor rectangle specified in \a scissor. |
10492 | | |
10493 | | This can only be called when the bound pipeline has |
10494 | | \l{QRhiGraphicsPipeline::UsesScissor}{UsesScissor} set. When the flag is |
10495 | | set on the active pipeline, this function must be called because scissor |
10496 | | testing will get enabled and so a scissor rectangle must be provided. |
10497 | | |
10498 | | \note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are |
10499 | | bottom-left. |
10500 | | |
10501 | | \note This function can only be called inside a render pass, meaning |
10502 | | between a beginPass() and endPass() call. |
10503 | | */ |
10504 | | void QRhiCommandBuffer::setScissor(const QRhiScissor &scissor) |
10505 | 0 | { |
10506 | 0 | m_rhi->setScissor(this, scissor); |
10507 | 0 | } |
10508 | | |
10509 | | /*! |
10510 | | Records setting the active blend constants to \a c. |
10511 | | |
10512 | | This can only be called when the bound pipeline has |
10513 | | QRhiGraphicsPipeline::UsesBlendConstants set. |
10514 | | |
10515 | | \note This function can only be called inside a render pass, meaning |
10516 | | between a beginPass() and endPass() call. |
10517 | | */ |
10518 | | void QRhiCommandBuffer::setBlendConstants(const QColor &c) |
10519 | 0 | { |
10520 | 0 | m_rhi->setBlendConstants(this, c); |
10521 | 0 | } |
10522 | | |
10523 | | /*! |
10524 | | Records setting the active stencil reference value to \a refValue. |
10525 | | |
10526 | | This can only be called when the bound pipeline has |
10527 | | QRhiGraphicsPipeline::UsesStencilRef set. |
10528 | | |
10529 | | \note This function can only be called inside a render pass, meaning between |
10530 | | a beginPass() and endPass() call. |
10531 | | */ |
10532 | | void QRhiCommandBuffer::setStencilRef(quint32 refValue) |
10533 | 0 | { |
10534 | 0 | m_rhi->setStencilRef(this, refValue); |
10535 | 0 | } |
10536 | | |
10537 | | /*! |
10538 | | Sets the shading rate for the following draw calls to \a coarsePixelSize. |
10539 | | |
10540 | | The default is 1x1. |
10541 | | |
10542 | | Functional only when the \l QRhi::VariableRateShading feature is reported as |
10543 | | supported and the QRhiGraphicsPipeline(s) bound on the command buffer were |
10544 | | declaring \l QRhiGraphicsPipeline::UsesShadingRate when creating them. |
10545 | | |
10546 | | Call \l QRhi::supportedShadingRates() to check what shading rates are |
10547 | | supported for a given sample count. |
10548 | | |
10549 | | When both a QRhiShadingRateMap and this function are in use, the higher of |
10550 | | the two shading rates is used for each tile. There is currently no control |
10551 | | offered over the combiner behavior. |
10552 | | |
10553 | | \since 6.9 |
10554 | | */ |
10555 | | void QRhiCommandBuffer::setShadingRate(const QSize &coarsePixelSize) |
10556 | 0 | { |
10557 | 0 | m_rhi->setShadingRate(this, coarsePixelSize); |
10558 | 0 | } |
10559 | | |
10560 | | /*! |
10561 | | Records a non-indexed draw. |
10562 | | |
10563 | | The number of vertices is specified in \a vertexCount. For instanced |
10564 | | drawing set \a instanceCount to a value other than 1. \a firstVertex is the |
10565 | | index of the first vertex to draw. When drawing multiple instances, the |
10566 | | first instance ID is specified by \a firstInstance. |
10567 | | |
10568 | | \note \a firstInstance may not be supported, and is ignored when the |
10569 | | QRhi::BaseInstance feature is reported as not supported. The first instance |
10570 | | ID is always 0 in that case. QRhi::BaseInstance is never supported with |
10571 | | OpenGL at the moment, mainly due to OpenGL ES limitations, and therefore |
10572 | | portable applications should not be designed to rely on this argument. |
10573 | | |
10574 | | \note Shaders that need to access the index of the current vertex or |
10575 | | instance must use \c gl_VertexIndex and \c gl_InstanceIndex, i.e., the |
10576 | | Vulkan-compatible built-in variables, instead of \c gl_VertexID and \c |
10577 | | gl_InstanceID. |
10578 | | |
10579 | | \note When \a firstInstance is non-zero, \c gl_InstanceIndex will not |
10580 | | include the base value with some of the underlying 3D APIs. This is |
10581 | | indicated by the QRhi::InstanceIndexIncludesBaseInstance feature. If relying |
10582 | | on a base instance value cannot be avoided, applications are advised to pass |
10583 | | in the value as a uniform conditionally based on what that feature reports, |
10584 | | and add it to \c gl_InstanceIndex in the shader. |
10585 | | |
10586 | | \note This function can only be called inside a render pass, meaning |
10587 | | between a beginPass() and endPass() call. |
10588 | | */ |
10589 | | void QRhiCommandBuffer::draw(quint32 vertexCount, |
10590 | | quint32 instanceCount, |
10591 | | quint32 firstVertex, |
10592 | | quint32 firstInstance) |
10593 | 0 | { |
10594 | 0 | m_rhi->draw(this, vertexCount, instanceCount, firstVertex, firstInstance); |
10595 | 0 | } |
10596 | | |
10597 | | /*! |
10598 | | Records an indexed draw. |
10599 | | |
10600 | | The number of vertices is specified in \a indexCount. \a firstIndex is the |
10601 | | base index. The effective offset in the index buffer is given by |
10602 | | \c{indexOffset + firstIndex * n} where \c n is 2 or 4 depending on the |
10603 | | index element type. \c indexOffset is specified in setVertexInput(). |
10604 | | |
10605 | | \note The effective offset in the index buffer must be 4 byte aligned with |
10606 | | some backends (for example, Metal). With these backends the |
10607 | | \l{QRhi::NonFourAlignedEffectiveIndexBufferOffset}{NonFourAlignedEffectiveIndexBufferOffset} |
10608 | | feature will be reported as not-supported. |
10609 | | |
10610 | | \a vertexOffset (also called \c{base vertex}) is a signed value that is |
10611 | | added to the element index before indexing into the vertex buffer. Support |
10612 | | for this is not always available, and the value is ignored when the feature |
10613 | | QRhi::BaseVertex is reported as unsupported. |
10614 | | |
10615 | | For instanced drawing set \a instanceCount to a value other than 1. When |
10616 | | drawing multiple instances, the first instance ID is specified by \a |
10617 | | firstInstance. |
10618 | | |
10619 | | \note \a firstInstance may not be supported, and is ignored when the |
10620 | | QRhi::BaseInstance feature is reported as not supported. The first instance |
10621 | | ID is always 0 in that case. QRhi::BaseInstance is never supported with |
10622 | | OpenGL at the moment, mainly due to OpenGL ES limitations, and therefore |
10623 | | portable applications should not be designed to rely on this argument. |
10624 | | |
10625 | | \note Shaders that need to access the index of the current vertex or |
10626 | | instance must use \c gl_VertexIndex and \c gl_InstanceIndex, i.e., the |
10627 | | Vulkan-compatible built-in variables, instead of \c gl_VertexID and \c |
10628 | | gl_InstanceID. |
10629 | | |
10630 | | \note When \a firstInstance is non-zero, \c gl_InstanceIndex will not |
10631 | | include the base value with some of the underlying 3D APIs. This is |
10632 | | indicated by the QRhi::InstanceIndexIncludesBaseInstance feature. If relying |
10633 | | on a base instance value cannot be avoided, applications are advised to pass |
10634 | | in the value as a uniform conditionally based on what that feature reports, |
10635 | | and add it to \c gl_InstanceIndex in the shader. |
10636 | | |
10637 | | \note This function can only be called inside a render pass, meaning |
10638 | | between a beginPass() and endPass() call. |
10639 | | */ |
10640 | | void QRhiCommandBuffer::drawIndexed(quint32 indexCount, |
10641 | | quint32 instanceCount, |
10642 | | quint32 firstIndex, |
10643 | | qint32 vertexOffset, |
10644 | | quint32 firstInstance) |
10645 | 0 | { |
10646 | 0 | m_rhi->drawIndexed(this, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); |
10647 | 0 | } |
10648 | | |
10649 | | /*! |
10650 | | Records a non-indexed, indirect draw. |
10651 | | |
10652 | | The draw parameters are provided by the buffer specified in \a indirectBuffer, |
10653 | | which must contain an array of elements of type QRhiIndirectDrawCommand. |
10654 | | The parameters in QRhiIndirectDrawCommand have the same meaning as in draw(). |
10655 | | |
10656 | | The offset, in bytes, from which the parameters are read in the buffer is specified |
10657 | | by \a indirectBufferOffset. |
10658 | | |
10659 | | \a drawCount specifies the number of such draw commands to issue. |
10660 | | |
10661 | | \a stride indicates the byte size of each individual draw command structure |
10662 | | in the buffer. This allows interleaving custom data between commands if needed. |
10663 | | The value must be a multiple of 4 and greater than or equal to sizeof(QRhiIndirectDrawCommand). |
10664 | | |
10665 | | \note A \a drawCount value greater than 1 is only natively supported if the |
10666 | | QRhi::DrawIndirectMulti feature is reported as supported and stride is the default. |
10667 | | Otherwise, this function emulates multi-draw by recording multiple draw calls, |
10668 | | offering no performance benefit over repeated draw() calls. |
10669 | | |
10670 | | \note This function can only be called inside a render pass, meaning |
10671 | | between a beginPass() and endPass() call. |
10672 | | |
10673 | | \since 6.12 |
10674 | | */ |
10675 | | void QRhiCommandBuffer::drawIndirect(QRhiBuffer *indirectBuffer, |
10676 | | quint32 indirectBufferOffset, |
10677 | | quint32 drawCount, |
10678 | | quint32 stride) |
10679 | 0 | { |
10680 | 0 | Q_ASSERT(indirectBuffer); |
10681 | 0 | Q_ASSERT(indirectBuffer->usage().testFlag(QRhiBuffer::IndirectBuffer)); |
10682 | 0 | Q_ASSERT_X((indirectBufferOffset & 3u) == 0u, Q_FUNC_INFO, "indirectBufferOffset must be a multiple of 4"); |
10683 | 0 | Q_ASSERT(stride >= sizeof(QRhiIndirectDrawCommand)); |
10684 | 0 | Q_ASSERT_X((stride & 3u) == 0u, Q_FUNC_INFO, "stride must be a multiple of 4"); |
10685 | 0 | m_rhi->drawIndirect(this, indirectBuffer, indirectBufferOffset, drawCount, stride); |
10686 | 0 | } |
10687 | | |
10688 | | /*! |
10689 | | Records an indexed, indirect draw. |
10690 | | |
10691 | | The draw parameters are provided by the buffer specified in \a indirectBuffer, |
10692 | | which must contain an array of elements of type QRhiIndexedIndirectDrawCommand. |
10693 | | The parameters in QRhiIndexedIndirectDrawCommand have the same meaning as in drawIndexed(). |
10694 | | |
10695 | | The offset, in bytes, from which the parameters are read in the buffer is specified |
10696 | | by \a indirectBufferOffset. |
10697 | | |
10698 | | \a drawCount specifies the number of such draw commands to issue. |
10699 | | |
10700 | | \a stride indicates the byte size of each individual draw command structure |
10701 | | in the buffer. This allows interleaving custom data between commands if needed. |
10702 | | The value must be a multiple of 4 and greater than or equal to sizeof(QRhiIndexedIndirectDrawCommand). |
10703 | | |
10704 | | \note A \a drawCount value greater than 1 is only natively supported if the |
10705 | | QRhi::DrawIndirectMulti feature is reported as supported and stride is the default. |
10706 | | Otherwise, this function emulates multi-draw by recording multiple draw calls, |
10707 | | offering no performance benefit over repeated drawIndexed() calls. |
10708 | | |
10709 | | \note This function can only be called inside a render pass, meaning |
10710 | | between a beginPass() and endPass() call. |
10711 | | |
10712 | | \since 6.12 |
10713 | | */ |
10714 | | void QRhiCommandBuffer::drawIndexedIndirect(QRhiBuffer *indirectBuffer, |
10715 | | quint32 indirectBufferOffset, |
10716 | | quint32 drawCount, |
10717 | | quint32 stride) |
10718 | 0 | { |
10719 | 0 | Q_ASSERT(indirectBuffer); |
10720 | 0 | Q_ASSERT(indirectBuffer->usage().testFlag(QRhiBuffer::IndirectBuffer)); |
10721 | 0 | Q_ASSERT_X((indirectBufferOffset & 3u) == 0u, Q_FUNC_INFO, "indirectBufferOffset must be a multiple of 4"); |
10722 | 0 | Q_ASSERT(stride >= sizeof(QRhiIndexedIndirectDrawCommand)); |
10723 | 0 | Q_ASSERT_X((stride & 3u) == 0u, Q_FUNC_INFO, "stride must be a multiple of 4"); |
10724 | 0 | m_rhi->drawIndexedIndirect(this, indirectBuffer, indirectBufferOffset, drawCount, stride); |
10725 | 0 | } |
10726 | | |
10727 | | /*! |
10728 | | Records a named debug group on the command buffer with the specified \a |
10729 | | name. This is shown in graphics debugging tools such as |
10730 | | \l{https://renderdoc.org/}{RenderDoc} and |
10731 | | \l{https://developer.apple.com/xcode/}{XCode}. The end of the grouping is |
10732 | | indicated by debugMarkEnd(). |
10733 | | |
10734 | | \note Ignored when QRhi::DebugMarkers are not supported or |
10735 | | QRhi::EnableDebugMarkers is not set. |
10736 | | |
10737 | | \note Can be called anywhere within the frame, both inside and outside of passes. |
10738 | | */ |
10739 | | void QRhiCommandBuffer::debugMarkBegin(const QByteArray &name) |
10740 | 0 | { |
10741 | 0 | m_rhi->debugMarkBegin(this, name); |
10742 | 0 | } |
10743 | | |
10744 | | /*! |
10745 | | Records the end of a debug group. |
10746 | | |
10747 | | \note Ignored when QRhi::DebugMarkers are not supported or |
10748 | | QRhi::EnableDebugMarkers is not set. |
10749 | | |
10750 | | \note Can be called anywhere within the frame, both inside and outside of passes. |
10751 | | */ |
10752 | | void QRhiCommandBuffer::debugMarkEnd() |
10753 | 0 | { |
10754 | 0 | m_rhi->debugMarkEnd(this); |
10755 | 0 | } |
10756 | | |
10757 | | /*! |
10758 | | Inserts a debug message \a msg into the command stream. |
10759 | | |
10760 | | \note Ignored when QRhi::DebugMarkers are not supported or |
10761 | | QRhi::EnableDebugMarkers is not set. |
10762 | | |
10763 | | \note With some backends debugMarkMsg() is only supported inside a pass and |
10764 | | is ignored when called outside a pass. With others it is recorded anywhere |
10765 | | within the frame. |
10766 | | */ |
10767 | | void QRhiCommandBuffer::debugMarkMsg(const QByteArray &msg) |
10768 | 0 | { |
10769 | 0 | m_rhi->debugMarkMsg(this, msg); |
10770 | 0 | } |
10771 | | |
10772 | | /*! |
10773 | | Records starting a new compute pass. |
10774 | | |
10775 | | \a resourceUpdates, when not null, specifies a resource update batch that |
10776 | | is to be committed and then released. |
10777 | | |
10778 | | \note Do not assume that any state or resource bindings persist between |
10779 | | passes. |
10780 | | |
10781 | | \note A compute pass can record setComputePipeline(), setShaderResources(), |
10782 | | and dispatch() calls, not graphics ones. General functionality, such as, |
10783 | | debug markers and beginExternal() is available both in render and compute |
10784 | | passes. |
10785 | | |
10786 | | \note Compute is only available when the \l{QRhi::Compute}{Compute} feature |
10787 | | is reported as supported. |
10788 | | |
10789 | | \a flags is not currently used. |
10790 | | */ |
10791 | | void QRhiCommandBuffer::beginComputePass(QRhiResourceUpdateBatch *resourceUpdates, BeginPassFlags flags) |
10792 | 0 | { |
10793 | 0 | m_rhi->beginComputePass(this, resourceUpdates, flags); |
10794 | 0 | } |
10795 | | |
10796 | | /*! |
10797 | | Records ending the current compute pass. |
10798 | | |
10799 | | \a resourceUpdates, when not null, specifies a resource update batch that |
10800 | | is to be committed and then released. |
10801 | | */ |
10802 | | void QRhiCommandBuffer::endComputePass(QRhiResourceUpdateBatch *resourceUpdates) |
10803 | 0 | { |
10804 | 0 | m_rhi->endComputePass(this, resourceUpdates); |
10805 | 0 | } |
10806 | | |
10807 | | /*! |
10808 | | Records setting a new compute pipeline \a ps. |
10809 | | |
10810 | | \note This function must be called before recording setShaderResources() or |
10811 | | dispatch() commands on the command buffer. |
10812 | | |
10813 | | \note QRhi will optimize out unnecessary invocations within a pass, so |
10814 | | therefore overoptimizing to avoid calls to this function is not necessary |
10815 | | on the applications' side. |
10816 | | |
10817 | | \note This function can only be called inside a compute pass, meaning |
10818 | | between a beginComputePass() and endComputePass() call. |
10819 | | */ |
10820 | | void QRhiCommandBuffer::setComputePipeline(QRhiComputePipeline *ps) |
10821 | 0 | { |
10822 | 0 | m_rhi->setComputePipeline(this, ps); |
10823 | 0 | } |
10824 | | |
10825 | | /*! |
10826 | | Records dispatching compute work items, with \a x, \a y, and \a z |
10827 | | specifying the number of local workgroups in the corresponding dimension. |
10828 | | |
10829 | | \note This function can only be called inside a compute pass, meaning |
10830 | | between a beginComputePass() and endComputePass() call. |
10831 | | |
10832 | | \note \a x, \a y, and \a z must fit the limits from the underlying graphics |
10833 | | API implementation at run time. The maximum values are typically 65535. |
10834 | | |
10835 | | \note Watch out for possible limits on the local workgroup size as well. |
10836 | | This is specified in the shader, for example: \c{layout(local_size_x = 16, |
10837 | | local_size_y = 16) in;}. For example, with OpenGL the minimum value mandated |
10838 | | by the specification for the number of invocations in a single local work |
10839 | | group (the product of \c local_size_x, \c local_size_y, and \c local_size_z) |
10840 | | is 1024, while with OpenGL ES (3.1) the value may be as low as 128. This |
10841 | | means that the example given above may be rejected by some OpenGL ES |
10842 | | implementations as the number of invocations is 256. |
10843 | | */ |
10844 | | void QRhiCommandBuffer::dispatch(int x, int y, int z) |
10845 | 0 | { |
10846 | 0 | m_rhi->dispatch(this, x, y, z); |
10847 | 0 | } |
10848 | | |
10849 | | /*! |
10850 | | \return a pointer to a backend-specific QRhiNativeHandles subclass, such as |
10851 | | QRhiVulkanCommandBufferNativeHandles. The returned value is \nullptr when |
10852 | | exposing the underlying native resources is not supported by, or not |
10853 | | applicable to, the backend. |
10854 | | |
10855 | | \sa QRhiVulkanCommandBufferNativeHandles, |
10856 | | QRhiMetalCommandBufferNativeHandles, beginExternal(), endExternal() |
10857 | | */ |
10858 | | const QRhiNativeHandles *QRhiCommandBuffer::nativeHandles() |
10859 | 0 | { |
10860 | 0 | return m_rhi->nativeHandles(this); |
10861 | 0 | } |
10862 | | |
10863 | | /*! |
10864 | | To be called when the application before the application is about to |
10865 | | enqueue commands to the current pass' command buffer by calling graphics |
10866 | | API functions directly. |
10867 | | |
10868 | | \note This is only available when the intent was declared upfront in |
10869 | | beginPass() or beginComputePass(). Therefore this function must only be |
10870 | | called when the pass recording was started with specifying |
10871 | | QRhiCommandBuffer::ExternalContent. |
10872 | | |
10873 | | With Vulkan, Metal, or Direct3D 12 one can query the native command buffer |
10874 | | or encoder objects via nativeHandles() and enqueue commands to them. With |
10875 | | OpenGL or Direct3D 11 the (device) context can be retrieved from |
10876 | | QRhi::nativeHandles(). However, this must never be done without ensuring |
10877 | | the QRhiCommandBuffer's state stays up-to-date. Hence the requirement for |
10878 | | wrapping any externally added command recording between beginExternal() and |
10879 | | endExternal(). Conceptually this is the same as QPainter's |
10880 | | \l{QPainter::beginNativePainting()}{beginNativePainting()} and |
10881 | | \l{QPainter::endNativePainting()}{endNativePainting()} functions. |
10882 | | |
10883 | | For OpenGL in particular, this function has an additional task: it makes |
10884 | | sure the context is made current on the current thread. |
10885 | | |
10886 | | \note Once beginExternal() is called, no other render pass specific |
10887 | | functions (\c set* or \c draw*) must be called on the |
10888 | | QRhiCommandBuffer until endExternal(). |
10889 | | |
10890 | | \warning Some backends may return a native command buffer object from |
10891 | | QRhiCommandBuffer::nativeHandles() that is different from the primary one |
10892 | | when inside a beginExternal() - endExternal() block. Therefore it is |
10893 | | important to (re)query the native command buffer object after calling |
10894 | | beginExternal(). In practical terms this means that with Vulkan for example |
10895 | | the externally recorded Vulkan commands are placed onto a secondary command |
10896 | | buffer (with VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT). |
10897 | | nativeHandles() returns this secondary command buffer when called between |
10898 | | begin/endExternal. |
10899 | | |
10900 | | \sa endExternal(), nativeHandles() |
10901 | | */ |
10902 | | void QRhiCommandBuffer::beginExternal() |
10903 | 0 | { |
10904 | 0 | m_rhi->beginExternal(this); |
10905 | 0 | } |
10906 | | |
10907 | | /*! |
10908 | | To be called once the externally added commands are recorded to the command |
10909 | | buffer or context. |
10910 | | |
10911 | | \note All QRhiCommandBuffer state must be assumed as invalid after calling |
10912 | | this function. Pipelines, vertex and index buffers, and other state must be |
10913 | | set again if more draw calls are recorded after the external commands. |
10914 | | |
10915 | | \sa beginExternal(), nativeHandles() |
10916 | | */ |
10917 | | void QRhiCommandBuffer::endExternal() |
10918 | 0 | { |
10919 | 0 | m_rhi->endExternal(this); |
10920 | 0 | } |
10921 | | |
10922 | | /*! |
10923 | | \return the last available timestamp, in seconds, when |
10924 | | \l QRhi::EnableTimestamps was enabled when creating the QRhi. The value |
10925 | | indicates the elapsed time on the GPU during the last completed frame. |
10926 | | |
10927 | | \note Do not expect results other than 0 when the QRhi::Timestamps feature |
10928 | | is not reported as supported, or when QRhi::EnableTimestamps was not passed |
10929 | | to QRhi::create(). There are exceptions to this, because with some graphics |
10930 | | APIs (Metal) timings are available without having to perform extra |
10931 | | operations (timestamp queries), but portable applications should always |
10932 | | consciously opt-in to timestamp collection when they know it is needed, and |
10933 | | call this function accordingly. |
10934 | | |
10935 | | Care must be exercised with the interpretation of the value, as its |
10936 | | precision and granularity is often not controlled by Qt, and depends on the |
10937 | | underlying graphics API and its implementation. In particular, comparing |
10938 | | the values between different graphics APIs and hardware is discouraged and |
10939 | | may be meaningless. |
10940 | | |
10941 | | The timing values will likely become available asynchronously. The returned |
10942 | | value may therefore be 0 (e.g., for the first 1-2 frames) or the last known |
10943 | | value referring to some previous frame. The value my also become 0 again |
10944 | | under certain conditions, such as when resizing the window. It can be |
10945 | | expected that the most up-to-date available value is retrieved in |
10946 | | beginFrame() and becomes queriable via this function once beginFrame() |
10947 | | returns. |
10948 | | |
10949 | | \note Do not assume that the value refers to the previous |
10950 | | (\c{currently_recorded - 1}) frame. It may refer to \c{currently_recorded - |
10951 | | 2} or \c{currently_recorded - 3} as well. The exact behavior may depend on |
10952 | | the graphics API and its implementation. |
10953 | | |
10954 | | Watch out for the consequences of GPU frequency scaling and GPU clock |
10955 | | changes, depending on the platform. For example, on Windows the returned |
10956 | | timing may vary in a quite wide range between frames with modern graphics |
10957 | | cards, even when submitting frames with a similar, or the same workload. |
10958 | | This is out of scope for Qt to control and solve, generally speaking. |
10959 | | However, the D3D12 backend automatically calls |
10960 | | \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-setstablepowerstate}{ID3D12Device::SetStablePowerState()} |
10961 | | whenever the environment variable \c QT_D3D_STABLE_POWER_STATE is set to a |
10962 | | non-zero value. This can greatly stabilize the result. It can also have a |
10963 | | non-insignificant effect on the CPU-side timings measured via QElapsedTimer |
10964 | | for example, especially when offscreen frames are involved. |
10965 | | |
10966 | | \note Do not and never ship applications to production with |
10967 | | \c QT_D3D_STABLE_POWER_STATE set. See the Windows API documentation for details. |
10968 | | |
10969 | | \sa QRhi::Timestamps, QRhi::EnableTimestamps |
10970 | | */ |
10971 | | double QRhiCommandBuffer::lastCompletedGpuTime() |
10972 | 0 | { |
10973 | 0 | return m_rhi->lastCompletedGpuTime(this); |
10974 | 0 | } |
10975 | | |
10976 | | /*! |
10977 | | \return the value (typically an offset) \a v aligned to the uniform buffer |
10978 | | alignment given by ubufAlignment(). |
10979 | | */ |
10980 | | int QRhi::ubufAligned(int v) const |
10981 | 0 | { |
10982 | 0 | const int byteAlign = ubufAlignment(); |
10983 | 0 | return (v + byteAlign - 1) & ~(byteAlign - 1); |
10984 | 0 | } |
10985 | | |
10986 | | /*! |
10987 | | \return the number of mip levels for a given \a size. |
10988 | | */ |
10989 | | int QRhi::mipLevelsForSize(const QSize &size) |
10990 | 0 | { |
10991 | 0 | return qFloor(std::log2(qMax(size.width(), size.height()))) + 1; |
10992 | 0 | } |
10993 | | |
10994 | | /*! |
10995 | | \return the texture image size for a given \a mipLevel, calculated based on |
10996 | | the level 0 size given in \a baseLevelSize. |
10997 | | */ |
10998 | | QSize QRhi::sizeForMipLevel(int mipLevel, const QSize &baseLevelSize) |
10999 | 0 | { |
11000 | 0 | const int w = qMax(1, baseLevelSize.width() >> mipLevel); |
11001 | 0 | const int h = qMax(1, baseLevelSize.height() >> mipLevel); |
11002 | 0 | return QSize(w, h); |
11003 | 0 | } |
11004 | | |
11005 | | /*! |
11006 | | \return \c true if the underlying graphics API has the Y axis pointing up |
11007 | | in framebuffers and images. |
11008 | | |
11009 | | In practice this is \c true for OpenGL only. |
11010 | | */ |
11011 | | bool QRhi::isYUpInFramebuffer() const |
11012 | 0 | { |
11013 | 0 | return d->isYUpInFramebuffer(); |
11014 | 0 | } |
11015 | | |
11016 | | /*! |
11017 | | \return \c true if the underlying graphics API has the Y axis pointing up |
11018 | | in its normalized device coordinate system. |
11019 | | |
11020 | | In practice this is \c false for Vulkan only. |
11021 | | |
11022 | | \note clipSpaceCorrMatrix() includes the corresponding adjustment (to make |
11023 | | Y point up) in its returned matrix. |
11024 | | */ |
11025 | | bool QRhi::isYUpInNDC() const |
11026 | 0 | { |
11027 | 0 | return d->isYUpInNDC(); |
11028 | 0 | } |
11029 | | |
11030 | | /*! |
11031 | | \return \c true if the underlying graphics API uses depth range [0, 1] in |
11032 | | clip space. |
11033 | | |
11034 | | In practice this is \c false for OpenGL only, because OpenGL uses a |
11035 | | post-projection depth range of [-1, 1]. (not to be confused with the |
11036 | | NDC-to-window mapping controlled by glDepthRange(), which uses a range of |
11037 | | [0, 1], unless overridden by the QRhiViewport) In some OpenGL versions |
11038 | | glClipControl() could be used to change this, but the OpenGL backend of |
11039 | | QRhi does not use that function as it is not available in OpenGL ES or |
11040 | | OpenGL versions lower than 4.5. |
11041 | | |
11042 | | \note clipSpaceCorrMatrix() includes the corresponding adjustment in its |
11043 | | returned matrix. Therefore, many users of QRhi do not need to take any |
11044 | | further measures apart from pre-multiplying their projection matrices with |
11045 | | clipSpaceCorrMatrix(). However, some graphics techniques, such as, some |
11046 | | types of shadow mapping, involve working with and outputting depth values |
11047 | | in the shaders. These will need to query and take the value of this |
11048 | | function into account as appropriate. |
11049 | | */ |
11050 | | bool QRhi::isClipDepthZeroToOne() const |
11051 | 0 | { |
11052 | 0 | return d->isClipDepthZeroToOne(); |
11053 | 0 | } |
11054 | | |
11055 | | /*! |
11056 | | \return a matrix that can be used to allow applications keep using |
11057 | | OpenGL-targeted vertex data and perspective projection matrices (such as, |
11058 | | the ones generated by QMatrix4x4::perspective()), regardless of the active |
11059 | | QRhi backend. |
11060 | | |
11061 | | In a typical renderer, once \c{this_matrix * mvp} is used instead of just |
11062 | | \c mvp, vertex data with Y up and viewports with depth range 0 - 1 can be |
11063 | | used without considering what backend (and so graphics API) is going to be |
11064 | | used at run time. This way branching based on isYUpInNDC() and |
11065 | | isClipDepthZeroToOne() can be avoided (although such logic may still become |
11066 | | required when implementing certain advanced graphics techniques). |
11067 | | |
11068 | | See |
11069 | | \l{https://matthewwellings.com/blog/the-new-vulkan-coordinate-system/}{this |
11070 | | page} for a discussion of the topic from Vulkan perspective. |
11071 | | */ |
11072 | | QMatrix4x4 QRhi::clipSpaceCorrMatrix() const |
11073 | 0 | { |
11074 | 0 | return d->clipSpaceCorrMatrix(); |
11075 | 0 | } |
11076 | | |
11077 | | /*! |
11078 | | \return \c true if the specified texture \a format modified by \a flags is |
11079 | | supported. |
11080 | | |
11081 | | The query is supported both for uncompressed and compressed formats. |
11082 | | */ |
11083 | | bool QRhi::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const |
11084 | 0 | { |
11085 | 0 | return d->isTextureFormatSupported(format, flags); |
11086 | 0 | } |
11087 | | |
11088 | | /*! |
11089 | | \return \c true if the specified \a feature is supported |
11090 | | */ |
11091 | | bool QRhi::isFeatureSupported(QRhi::Feature feature) const |
11092 | 0 | { |
11093 | 0 | return d->isFeatureSupported(feature); |
11094 | 0 | } |
11095 | | |
11096 | | /*! |
11097 | | \return the value for the specified resource \a limit. |
11098 | | |
11099 | | The values are expected to be queried by the backends upon initialization, |
11100 | | meaning calling this function is a light operation. |
11101 | | */ |
11102 | | int QRhi::resourceLimit(ResourceLimit limit) const |
11103 | 0 | { |
11104 | 0 | return d->resourceLimit(limit); |
11105 | 0 | } |
11106 | | |
11107 | | /*! |
11108 | | \return a pointer to the backend-specific collection of native objects |
11109 | | for the device, context, and similar concepts used by the backend. |
11110 | | |
11111 | | Cast to QRhiVulkanNativeHandles, QRhiD3D11NativeHandles, |
11112 | | QRhiD3D12NativeHandles, QRhiGles2NativeHandles, or QRhiMetalNativeHandles |
11113 | | as appropriate. |
11114 | | |
11115 | | \note No ownership is transferred, neither for the returned pointer nor for |
11116 | | any native objects. |
11117 | | */ |
11118 | | const QRhiNativeHandles *QRhi::nativeHandles() |
11119 | 0 | { |
11120 | 0 | return d->nativeHandles(); |
11121 | 0 | } |
11122 | | |
11123 | | /*! |
11124 | | With OpenGL this makes the OpenGL context current on the current thread. |
11125 | | The function has no effect with other backends. |
11126 | | |
11127 | | Calling this function is relevant typically in Qt framework code, when one |
11128 | | has to ensure external OpenGL code provided by the application can still |
11129 | | run like it did before with direct usage of OpenGL, as long as the QRhi is |
11130 | | using the OpenGL backend. |
11131 | | |
11132 | | \return false when failed, similarly to QOpenGLContext::makeCurrent(). When |
11133 | | the operation failed, isDeviceLost() can be called to determine if there |
11134 | | was a loss of context situation. Such a check is equivalent to checking via |
11135 | | QOpenGLContext::isValid(). |
11136 | | |
11137 | | \sa QOpenGLContext::makeCurrent(), QOpenGLContext::isValid() |
11138 | | */ |
11139 | | bool QRhi::makeThreadLocalNativeContextCurrent() |
11140 | 0 | { |
11141 | 0 | return d->makeThreadLocalNativeContextCurrent(); |
11142 | 0 | } |
11143 | | |
11144 | | /*! |
11145 | | With backends and graphics APIs where applicable, this function allows to |
11146 | | provide additional arguments to the \b next submission of commands to the |
11147 | | graphics command queue. |
11148 | | |
11149 | | In particular, with Vulkan this allows passing in a list of Vulkan semaphore |
11150 | | objects for \c vkQueueSubmit() to signal and wait on. \a params must then be |
11151 | | a \l QRhiVulkanQueueSubmitParams. This becomes essential in certain advanced |
11152 | | use cases, such as when performing native Vulkan calls that involve having |
11153 | | to wait on and signal VkSemaphores that the application's custom Vulkan |
11154 | | rendering or compute code manages. In addition, this also allows specifying |
11155 | | additional semaphores to wait on in the next \c vkQueuePresentKHR(). |
11156 | | |
11157 | | \note This function affects the next queue submission only, which will |
11158 | | happen in endFrame(), endOffscreenFrame(), or finish(). The enqueuing of |
11159 | | present happens in endFrame(). |
11160 | | |
11161 | | With many other backends the implementation of this function is a no-op. |
11162 | | |
11163 | | \since 6.9 |
11164 | | */ |
11165 | | void QRhi::setQueueSubmitParams(QRhiNativeHandles *params) |
11166 | 0 | { |
11167 | 0 | d->setQueueSubmitParams(params); |
11168 | 0 | } |
11169 | | |
11170 | | /*! |
11171 | | Attempts to release resources in the backend's caches. This can include both |
11172 | | CPU and GPU resources. Only memory and resources that can be recreated |
11173 | | automatically are in scope. As an example, if the backend's |
11174 | | QRhiGraphicsPipeline implementation maintains a cache of shader compilation |
11175 | | results, calling this function leads to emptying that cache, thus |
11176 | | potentially freeing up memory and graphics resources. |
11177 | | |
11178 | | Calling this function makes sense in resource constrained environments, |
11179 | | where at a certain point there is a need to ensure minimal resource usage, |
11180 | | at the expense of performance. |
11181 | | */ |
11182 | | void QRhi::releaseCachedResources() |
11183 | 0 | { |
11184 | 0 | d->releaseCachedResources(); |
11185 | |
|
11186 | 0 | for (QRhiResourceUpdateBatch *u : d->resUpdPool) { |
11187 | 0 | if (u->d->poolIndex < 0) |
11188 | 0 | u->d->trimOpLists(); |
11189 | 0 | } |
11190 | 0 | } |
11191 | | |
11192 | | /*! |
11193 | | \return true if the graphics device was lost. |
11194 | | |
11195 | | The loss of the device is typically detected in beginFrame(), endFrame() or |
11196 | | QRhiSwapChain::createOrResize(), depending on the backend and the underlying |
11197 | | native APIs. The most common is endFrame() because that is where presenting |
11198 | | happens. With some backends QRhiSwapChain::createOrResize() can also fail |
11199 | | due to a device loss. Therefore this function is provided as a generic way |
11200 | | to check if a device loss was detected by a previous operation. |
11201 | | |
11202 | | When the device is lost, no further operations should be done via the QRhi. |
11203 | | Rather, all QRhi resources should be released, followed by destroying the |
11204 | | QRhi. A new QRhi can then be attempted to be created. If successful, all |
11205 | | graphics resources must be reinitialized. If not, try again later, |
11206 | | repeatedly. |
11207 | | |
11208 | | While simple applications may decide to not care about device loss, |
11209 | | on the commonly used desktop platforms a device loss can happen |
11210 | | due to a variety of reasons, including physically disconnecting the |
11211 | | graphics adapter, disabling the device or driver, uninstalling or upgrading |
11212 | | the graphics driver, or due to errors that lead to a graphics device reset. |
11213 | | Some of these can happen under perfectly normal circumstances as well, for |
11214 | | example the upgrade of the graphics driver to a newer version is a common |
11215 | | task that can happen at any time while a Qt application is running. Users |
11216 | | may very well expect applications to be able to survive this, even when the |
11217 | | application is actively using an API like OpenGL or Direct3D. |
11218 | | |
11219 | | Qt's own frameworks built on top of QRhi, such as, Qt Quick, can be |
11220 | | expected to handle and take appropriate measures when a device loss occurs. |
11221 | | If the data for graphics resources, such as textures and buffers, are still |
11222 | | available on the CPU side, such an event may not be noticeable on the |
11223 | | application level at all since graphics resources can seamlessly be |
11224 | | reinitialized then. However, applications and libraries working directly |
11225 | | with QRhi are expected to be prepared to check and handle device loss |
11226 | | situations themselves. |
11227 | | |
11228 | | \note With OpenGL, applications may need to opt-in to context reset |
11229 | | notifications by setting QSurfaceFormat::ResetNotification on the |
11230 | | QOpenGLContext. This is typically done by enabling the flag in |
11231 | | QRhiGles2InitParams::format. Keep in mind however that some systems may |
11232 | | generate context resets situations even when this flag is not set. |
11233 | | */ |
11234 | | bool QRhi::isDeviceLost() const |
11235 | 0 | { |
11236 | 0 | return d->isDeviceLost(); |
11237 | 0 | } |
11238 | | |
11239 | | /*! |
11240 | | \return a binary data blob with data collected from the |
11241 | | QRhiGraphicsPipeline and QRhiComputePipeline successfully created during |
11242 | | the lifetime of this QRhi. |
11243 | | |
11244 | | By saving and then, in subsequent runs of the same application, reloading |
11245 | | the cache data, pipeline and shader creation times can potentially be |
11246 | | reduced. What exactly the cache and its serialized version includes is not |
11247 | | specified, is always specific to the backend used, and in some cases also |
11248 | | dependent on the particular implementation of the graphics API. |
11249 | | |
11250 | | When the PipelineCacheDataLoadSave is reported as unsupported, the returned |
11251 | | QByteArray is empty. |
11252 | | |
11253 | | When the EnablePipelineCacheDataSave flag was not specified when calling |
11254 | | create(), the returned QByteArray may be empty, even when the |
11255 | | PipelineCacheDataLoadSave feature is supported. |
11256 | | |
11257 | | When the returned data is non-empty, it is always specific to the Qt |
11258 | | version and QRhi backend. In addition, in some cases there is a strong |
11259 | | dependency to the graphics device and the exact driver version used. QRhi |
11260 | | takes care of adding the appropriate header and safeguards that ensure that |
11261 | | the data can always be passed safely to setPipelineCacheData(), therefore |
11262 | | attempting to load data from a run on another version of a driver will be |
11263 | | handled safely and gracefully. |
11264 | | |
11265 | | \note Calling releaseCachedResources() may, depending on the backend, clear |
11266 | | the pipeline data collected. A subsequent call to this function may then |
11267 | | not return any data. |
11268 | | |
11269 | | See EnablePipelineCacheDataSave for further details about this feature. |
11270 | | |
11271 | | \note Minimize the number of calls to this function. Retrieving the blob is |
11272 | | not always a cheap operation, and therefore this function should only be |
11273 | | called at a low frequency, ideally only once e.g. when closing the |
11274 | | application. |
11275 | | |
11276 | | \sa setPipelineCacheData(), create(), isFeatureSupported() |
11277 | | */ |
11278 | | QByteArray QRhi::pipelineCacheData() |
11279 | 0 | { |
11280 | 0 | return d->pipelineCacheData(); |
11281 | 0 | } |
11282 | | |
11283 | | /*! |
11284 | | Loads \a data into the pipeline cache, when applicable. |
11285 | | |
11286 | | When the PipelineCacheDataLoadSave is reported as unsupported, the function |
11287 | | is safe to call, but has no effect. |
11288 | | |
11289 | | The blob returned by pipelineCacheData() is always specific to the Qt |
11290 | | version, the QRhi backend, and, in some cases, also to the graphics device, |
11291 | | and a given version of the graphics driver. QRhi takes care of adding the |
11292 | | appropriate header and safeguards that ensure that the data can always be |
11293 | | passed safely to this function. If there is a mismatch, e.g. because the |
11294 | | driver has been upgraded to a newer version, or because the data was |
11295 | | generated from a different QRhi backend, a warning is printed and \a data |
11296 | | is safely ignored. |
11297 | | |
11298 | | With Vulkan, this maps directly to VkPipelineCache. Calling this function |
11299 | | creates a new Vulkan pipeline cache object, with its initial data sourced |
11300 | | from \a data. The pipeline cache object is then used by all subsequently |
11301 | | created QRhiGraphicsPipeline and QRhiComputePipeline objects, thus |
11302 | | accelerating, potentially, the pipeline creation. |
11303 | | |
11304 | | With other APIs there is no real pipeline cache, but they may provide a |
11305 | | cache with bytecode from shader compilations (D3D) or program binaries |
11306 | | (OpenGL). In applications that perform a lot of shader compilation from |
11307 | | source at run time this can provide a significant boost in subsequent runs |
11308 | | if the "pipeline cache" is pre-seeded from an earlier run using this |
11309 | | function. |
11310 | | |
11311 | | \note QRhi cannot give any guarantees that \a data has an effect on the |
11312 | | pipeline and shader creation performance. With APIs like Vulkan, it is up |
11313 | | to the driver to decide if \a data is used for some purpose, or if it is |
11314 | | ignored. |
11315 | | |
11316 | | See EnablePipelineCacheDataSave for further details about this feature. |
11317 | | |
11318 | | \note This mechanism offered by QRhi is independent of the drivers' own |
11319 | | internal caching mechanism, if any. This means that, depending on the |
11320 | | graphics API and its implementation, the exact effects of retrieving and |
11321 | | then reloading \a data are not predictable. Improved performance may not be |
11322 | | visible at all in case other caching mechanisms outside of Qt's control are |
11323 | | already active. |
11324 | | |
11325 | | \note Minimize the number of calls to this function. Loading the blob is |
11326 | | not always a cheap operation, and therefore this function should only be |
11327 | | called at a low frequency, ideally only once e.g. when starting the |
11328 | | application. |
11329 | | |
11330 | | \warning Serialized pipeline cache data is assumed to be trusted content. Qt |
11331 | | performs robust parsing of the header and metadata included in \a data, |
11332 | | application developers are however advised to never pass in data from |
11333 | | untrusted sources. |
11334 | | |
11335 | | \sa pipelineCacheData(), isFeatureSupported() |
11336 | | */ |
11337 | | void QRhi::setPipelineCacheData(const QByteArray &data) |
11338 | 0 | { |
11339 | 0 | d->setPipelineCacheData(data); |
11340 | 0 | } |
11341 | | |
11342 | | /*! |
11343 | | \struct QRhiStats |
11344 | | \inmodule QtGuiPrivate |
11345 | | \inheaderfile rhi/qrhi.h |
11346 | | \since 6.6 |
11347 | | |
11348 | | \brief Statistics provided from the underlying memory allocator. |
11349 | | |
11350 | | \note This is a RHI API with limited compatibility guarantees, see \l QRhi |
11351 | | for details. |
11352 | | */ |
11353 | | |
11354 | | /*! |
11355 | | \variable QRhiStats::totalPipelineCreationTime |
11356 | | |
11357 | | The total time in milliseconds spent in graphics and compute pipeline |
11358 | | creation, which usually involves shader compilation or cache lookups, and |
11359 | | potentially expensive processing. |
11360 | | |
11361 | | \note The value should not be compared between different backends since the |
11362 | | concept of "pipelines" and what exactly happens under the hood during, for |
11363 | | instance, a call to QRhiGraphicsPipeline::create(), differ greatly between |
11364 | | graphics APIs and their implementations. |
11365 | | |
11366 | | \sa QRhi::statistics() |
11367 | | */ |
11368 | | |
11369 | | /*! |
11370 | | \variable QRhiStats::blockCount |
11371 | | |
11372 | | Statistic reported from the Vulkan or D3D12 memory allocator. |
11373 | | |
11374 | | \sa QRhi::statistics() |
11375 | | */ |
11376 | | |
11377 | | /*! |
11378 | | \variable QRhiStats::allocCount |
11379 | | |
11380 | | Statistic reported from the Vulkan or D3D12 memory allocator. |
11381 | | |
11382 | | \sa QRhi::statistics() |
11383 | | */ |
11384 | | |
11385 | | /*! |
11386 | | \variable QRhiStats::usedBytes |
11387 | | |
11388 | | Statistic reported from the Vulkan or D3D12 memory allocator. |
11389 | | |
11390 | | \sa QRhi::statistics() |
11391 | | */ |
11392 | | |
11393 | | /*! |
11394 | | \variable QRhiStats::unusedBytes |
11395 | | |
11396 | | Statistic reported from the Vulkan or D3D12 memory allocator. |
11397 | | |
11398 | | \sa QRhi::statistics() |
11399 | | */ |
11400 | | |
11401 | | /*! |
11402 | | \variable QRhiStats::totalUsageBytes |
11403 | | |
11404 | | Valid only with D3D12 currently. Matches IDXGIAdapter3::QueryVideoMemoryInfo(). |
11405 | | |
11406 | | \sa QRhi::statistics() |
11407 | | */ |
11408 | | |
11409 | | #ifndef QT_NO_DEBUG_STREAM |
11410 | | QDebug operator<<(QDebug dbg, const QRhiStats &info) |
11411 | 0 | { |
11412 | 0 | QDebugStateSaver saver(dbg); |
11413 | 0 | dbg.nospace() << "QRhiStats(" |
11414 | 0 | << "totalPipelineCreationTime=" << info.totalPipelineCreationTime |
11415 | 0 | << " blockCount=" << info.blockCount |
11416 | 0 | << " allocCount=" << info.allocCount |
11417 | 0 | << " usedBytes=" << info.usedBytes |
11418 | 0 | << " unusedBytes=" << info.unusedBytes |
11419 | 0 | << " totalUsageBytes=" << info.totalUsageBytes |
11420 | 0 | << ')'; |
11421 | 0 | return dbg; |
11422 | 0 | } |
11423 | | #endif |
11424 | | |
11425 | | /*! |
11426 | | Gathers and returns statistics about the timings and allocations of |
11427 | | graphics resources. |
11428 | | |
11429 | | Data about memory allocations is only available with some backends, where |
11430 | | such operations are under Qt's control. With graphics APIs where there is |
11431 | | no lower level control over resource memory allocations, this will never be |
11432 | | supported and all relevant fields in the results are 0. |
11433 | | |
11434 | | With Vulkan in particular, the values are valid always, and are queried |
11435 | | from the underlying memory allocator library. This gives an insight into |
11436 | | the memory requirements of the active buffers and textures. |
11437 | | |
11438 | | The same is true for Direct 3D 12. In addition to the memory allocator |
11439 | | library's statistics, here the result also includes a \c totalUsageBytes |
11440 | | field which reports the total size including additional resources that are |
11441 | | not under the memory allocator library's control (swapchain buffers, |
11442 | | descriptor heaps, etc.), as reported by DXGI. |
11443 | | |
11444 | | The values correspond to all types of memory used, combined. (i.e. video + |
11445 | | system in case of a discreet GPU) |
11446 | | |
11447 | | Additional data, such as the total time in milliseconds spent in graphics |
11448 | | and compute pipeline creation (which usually involves shader compilation or |
11449 | | cache lookups, and potentially expensive processing) is available with most |
11450 | | backends. |
11451 | | |
11452 | | \note The elapsed times for operations such as pipeline creation may be |
11453 | | affected by various factors. The results should not be compared between |
11454 | | different backends since the concept of "pipelines" and what exactly |
11455 | | happens under the hood during, for instance, a call to |
11456 | | QRhiGraphicsPipeline::create(), differ greatly between graphics APIs and |
11457 | | their implementations. |
11458 | | |
11459 | | \note Additionally, many drivers will likely employ various caching |
11460 | | strategies for shaders, programs, pipelines. (independently of Qt's own |
11461 | | similar facilities, such as setPipelineCacheData() or the OpenGL-specific |
11462 | | program binary disk cache). Because such internal behavior is transparent |
11463 | | to the API client, Qt and QRhi have no knowledge or control over the exact |
11464 | | caching strategy, persistency, invalidation of the cached data, etc. When |
11465 | | reading timings, such as the time spent on pipeline creation, the potential |
11466 | | presence and unspecified behavior of driver-level caching mechanisms should |
11467 | | be kept in mind. |
11468 | | */ |
11469 | | QRhiStats QRhi::statistics() const |
11470 | 0 | { |
11471 | 0 | return d->statistics(); |
11472 | 0 | } |
11473 | | |
11474 | | /*! |
11475 | | \return a new graphics pipeline resource. |
11476 | | |
11477 | | \sa QRhiResource::destroy() |
11478 | | */ |
11479 | | QRhiGraphicsPipeline *QRhi::newGraphicsPipeline() |
11480 | 0 | { |
11481 | 0 | return d->createGraphicsPipeline(); |
11482 | 0 | } |
11483 | | |
11484 | | /*! |
11485 | | \return a new compute pipeline resource. |
11486 | | |
11487 | | \note Compute is only available when the \l{QRhi::Compute}{Compute} feature |
11488 | | is reported as supported. |
11489 | | |
11490 | | \sa QRhiResource::destroy() |
11491 | | */ |
11492 | | QRhiComputePipeline *QRhi::newComputePipeline() |
11493 | 0 | { |
11494 | 0 | return d->createComputePipeline(); |
11495 | 0 | } |
11496 | | |
11497 | | /*! |
11498 | | \return a new shader resource binding collection resource. |
11499 | | |
11500 | | \sa QRhiResource::destroy() |
11501 | | */ |
11502 | | QRhiShaderResourceBindings *QRhi::newShaderResourceBindings() |
11503 | 0 | { |
11504 | 0 | return d->createShaderResourceBindings(); |
11505 | 0 | } |
11506 | | |
11507 | | /*! |
11508 | | \return a new buffer with the specified \a type, \a usage, and \a size. |
11509 | | |
11510 | | \note Some \a usage and \a type combinations may not be supported by all |
11511 | | backends. See \l{QRhiBuffer::UsageFlag}{UsageFlags} and |
11512 | | \l{QRhi::NonDynamicUniformBuffers}{the feature flags}. |
11513 | | |
11514 | | \note Backends may choose to allocate buffers bigger than \a size. This is |
11515 | | done transparently to applications, so there are no special restrictions on |
11516 | | the value of \a size. QRhiBuffer::size() will always report back the value |
11517 | | that was requested in \a size. |
11518 | | |
11519 | | \sa QRhiResource::destroy() |
11520 | | */ |
11521 | | QRhiBuffer *QRhi::newBuffer(QRhiBuffer::Type type, |
11522 | | QRhiBuffer::UsageFlags usage, |
11523 | | quint32 size) |
11524 | 0 | { |
11525 | 0 | return d->createBuffer(type, usage, size); |
11526 | 0 | } |
11527 | | |
11528 | | /*! |
11529 | | \return a new renderbuffer with the specified \a type, \a pixelSize, \a |
11530 | | sampleCount, and \a flags. |
11531 | | |
11532 | | When \a backingFormatHint is set to a texture format other than |
11533 | | QRhiTexture::UnknownFormat, it may be used by the backend to decide what |
11534 | | format to use for the storage backing the renderbuffer. |
11535 | | |
11536 | | \note \a backingFormatHint becomes relevant typically when multisampling |
11537 | | and floating point texture formats are involved: rendering into a |
11538 | | multisample QRhiRenderBuffer and then resolving into a non-RGBA8 |
11539 | | QRhiTexture implies (with some graphics APIs) that the storage backing the |
11540 | | QRhiRenderBuffer uses the matching non-RGBA8 format. That means that |
11541 | | passing a format like QRhiTexture::RGBA32F is important, because backends |
11542 | | will typically opt for QRhiTexture::RGBA8 by default, which would then |
11543 | | break later on due to attempting to set up RGBA8->RGBA32F multisample |
11544 | | resolve in the color attachment(s) of the QRhiTextureRenderTarget. |
11545 | | |
11546 | | \sa QRhiResource::destroy() |
11547 | | */ |
11548 | | QRhiRenderBuffer *QRhi::newRenderBuffer(QRhiRenderBuffer::Type type, |
11549 | | const QSize &pixelSize, |
11550 | | int sampleCount, |
11551 | | QRhiRenderBuffer::Flags flags, |
11552 | | QRhiTexture::Format backingFormatHint) |
11553 | 0 | { |
11554 | 0 | return d->createRenderBuffer(type, pixelSize, sampleCount, flags, backingFormatHint); |
11555 | 0 | } |
11556 | | |
11557 | | /*! |
11558 | | \return a new 1D or 2D texture with the specified \a format, \a pixelSize, \a |
11559 | | sampleCount, and \a flags. |
11560 | | |
11561 | | A 1D texture must have QRhiTexture::OneDimensional set in \a flags. This |
11562 | | function will implicitly set this flag if the \a pixelSize height is 0. |
11563 | | |
11564 | | \note \a format specifies the requested internal and external format, |
11565 | | meaning the data to be uploaded to the texture will need to be in a |
11566 | | compatible format, while the native texture may (but is not guaranteed to, |
11567 | | in case of OpenGL at least) use this format internally. |
11568 | | |
11569 | | \note 1D textures are only functional when the OneDimensionalTextures feature is |
11570 | | reported as supported at run time. Further, mipmaps on 1D textures are only |
11571 | | functional when the OneDimensionalTextureMipmaps feature is reported at run time. |
11572 | | |
11573 | | \sa QRhiResource::destroy() |
11574 | | */ |
11575 | | QRhiTexture *QRhi::newTexture(QRhiTexture::Format format, |
11576 | | const QSize &pixelSize, |
11577 | | int sampleCount, |
11578 | | QRhiTexture::Flags flags) |
11579 | 0 | { |
11580 | 0 | if (pixelSize.height() == 0) |
11581 | 0 | flags |= QRhiTexture::OneDimensional; |
11582 | |
|
11583 | 0 | return d->createTexture(format, pixelSize, 1, 0, sampleCount, flags); |
11584 | 0 | } |
11585 | | |
11586 | | /*! |
11587 | | \return a new 1D, 2D or 3D texture with the specified \a format, \a width, \a |
11588 | | height, \a depth, \a sampleCount, and \a flags. |
11589 | | |
11590 | | This overload is suitable for 3D textures because it allows specifying \a |
11591 | | depth. A 3D texture must have QRhiTexture::ThreeDimensional set in \a |
11592 | | flags, but using this overload that can be omitted because the flag is set |
11593 | | implicitly whenever \a depth is greater than 0. For 1D, 2D and cube textures \a |
11594 | | depth should be set to 0. |
11595 | | |
11596 | | A 1D texture must have QRhiTexture::OneDimensional set in \a flags. This overload |
11597 | | will implicitly set this flag if both \a height and \a depth are 0. |
11598 | | |
11599 | | \note 3D textures are only functional when the ThreeDimensionalTextures |
11600 | | feature is reported as supported at run time. |
11601 | | |
11602 | | \note 1D textures are only functional when the OneDimensionalTextures feature is |
11603 | | reported as supported at run time. Further, mipmaps on 1D textures are only |
11604 | | functional when the OneDimensionalTextureMipmaps feature is reported at run time. |
11605 | | |
11606 | | \overload |
11607 | | */ |
11608 | | QRhiTexture *QRhi::newTexture(QRhiTexture::Format format, |
11609 | | int width, int height, int depth, |
11610 | | int sampleCount, |
11611 | | QRhiTexture::Flags flags) |
11612 | 0 | { |
11613 | 0 | if (depth > 0) |
11614 | 0 | flags |= QRhiTexture::ThreeDimensional; |
11615 | |
|
11616 | 0 | if (height == 0 && depth == 0) |
11617 | 0 | flags |= QRhiTexture::OneDimensional; |
11618 | |
|
11619 | 0 | return d->createTexture(format, QSize(width, height), depth, 0, sampleCount, flags); |
11620 | 0 | } |
11621 | | |
11622 | | /*! |
11623 | | \return a new 1D or 2D texture array with the specified \a format, \a arraySize, |
11624 | | \a pixelSize, \a sampleCount, and \a flags. |
11625 | | |
11626 | | This function implicitly sets QRhiTexture::TextureArray in \a flags. |
11627 | | |
11628 | | A 1D texture array must have QRhiTexture::OneDimensional set in \a flags. This |
11629 | | function will implicitly set this flag if the \a pixelSize height is 0. |
11630 | | |
11631 | | \note Do not confuse texture arrays with arrays of textures. A QRhiTexture |
11632 | | created by this function is usable with 1D or 2D array samplers in the shader, for |
11633 | | example: \c{layout(binding = 1) uniform sampler2DArray texArr;}. Arrays of |
11634 | | textures refers to a list of textures that are exposed to the shader via |
11635 | | QRhiShaderResourceBinding::sampledTextures() and a count > 1, and declared |
11636 | | in the shader for example like this: \c{layout(binding = 1) uniform |
11637 | | sampler2D textures[4];} |
11638 | | |
11639 | | \note This is only functional when the TextureArrays feature is reported as |
11640 | | supported at run time. |
11641 | | |
11642 | | \note 1D textures are only functional when the OneDimensionalTextures feature is |
11643 | | reported as supported at run time. Further, mipmaps on 1D textures are only |
11644 | | functional when the OneDimensionalTextureMipmaps feature is reported at run time. |
11645 | | |
11646 | | |
11647 | | \sa newTexture() |
11648 | | */ |
11649 | | QRhiTexture *QRhi::newTextureArray(QRhiTexture::Format format, |
11650 | | int arraySize, |
11651 | | const QSize &pixelSize, |
11652 | | int sampleCount, |
11653 | | QRhiTexture::Flags flags) |
11654 | 0 | { |
11655 | 0 | flags |= QRhiTexture::TextureArray; |
11656 | |
|
11657 | 0 | if (pixelSize.height() == 0) |
11658 | 0 | flags |= QRhiTexture::OneDimensional; |
11659 | |
|
11660 | 0 | return d->createTexture(format, pixelSize, 1, arraySize, sampleCount, flags); |
11661 | 0 | } |
11662 | | |
11663 | | /*! |
11664 | | \return a new sampler with the specified magnification filter \a magFilter, |
11665 | | minification filter \a minFilter, mipmapping mode \a mipmapMode, and the |
11666 | | addressing (wrap) modes \a addressU, \a addressV, and \a addressW. |
11667 | | |
11668 | | \note Setting \a mipmapMode to a value other than \c None implies that |
11669 | | images for all relevant mip levels will be provided either via |
11670 | | \l{QRhiResourceUpdateBatch::uploadTexture()}{texture uploads} or by calling |
11671 | | \l{QRhiResourceUpdateBatch::generateMips()}{generateMips()} on the texture |
11672 | | that is used with this sampler. Attempting to use the sampler with a |
11673 | | texture that has no data for all relevant mip levels will lead to rendering |
11674 | | errors, with the exact behavior dependent on the underlying graphics API. |
11675 | | |
11676 | | \sa QRhiResource::destroy() |
11677 | | */ |
11678 | | QRhiSampler *QRhi::newSampler(QRhiSampler::Filter magFilter, |
11679 | | QRhiSampler::Filter minFilter, |
11680 | | QRhiSampler::Filter mipmapMode, |
11681 | | QRhiSampler::AddressMode addressU, |
11682 | | QRhiSampler::AddressMode addressV, |
11683 | | QRhiSampler::AddressMode addressW) |
11684 | 0 | { |
11685 | 0 | return d->createSampler(magFilter, minFilter, mipmapMode, addressU, addressV, addressW); |
11686 | 0 | } |
11687 | | |
11688 | | /*! |
11689 | | \return a new shading rate map object. |
11690 | | |
11691 | | \since 6.9 |
11692 | | */ |
11693 | | QRhiShadingRateMap *QRhi::newShadingRateMap() |
11694 | 0 | { |
11695 | 0 | return d->createShadingRateMap(); |
11696 | 0 | } |
11697 | | |
11698 | | /*! |
11699 | | \return a new texture render target with color and depth/stencil |
11700 | | attachments given in \a desc, and with the specified \a flags. |
11701 | | |
11702 | | \sa QRhiResource::destroy() |
11703 | | */ |
11704 | | |
11705 | | QRhiTextureRenderTarget *QRhi::newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, |
11706 | | QRhiTextureRenderTarget::Flags flags) |
11707 | 0 | { |
11708 | 0 | return d->createTextureRenderTarget(desc, flags); |
11709 | 0 | } |
11710 | | |
11711 | | /*! |
11712 | | \return a new swapchain. |
11713 | | |
11714 | | \sa QRhiResource::destroy(), QRhiSwapChain::createOrResize() |
11715 | | */ |
11716 | | QRhiSwapChain *QRhi::newSwapChain() |
11717 | 0 | { |
11718 | 0 | return d->createSwapChain(); |
11719 | 0 | } |
11720 | | |
11721 | | /*! |
11722 | | Starts a new frame targeting the next available buffer of \a swapChain. |
11723 | | |
11724 | | A frame consists of resource updates and one or more render and compute |
11725 | | passes. |
11726 | | |
11727 | | \a flags can indicate certain special cases. |
11728 | | |
11729 | | The high level pattern of rendering into a QWindow using a swapchain: |
11730 | | |
11731 | | \list |
11732 | | |
11733 | | \li Create a swapchain. |
11734 | | |
11735 | | \li Call QRhiSwapChain::createOrResize() whenever the surface size is |
11736 | | different than before. |
11737 | | |
11738 | | \li Call QRhiSwapChain::destroy() on |
11739 | | QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed. |
11740 | | |
11741 | | \li Then on every frame: |
11742 | | \badcode |
11743 | | beginFrame(sc); |
11744 | | updates = nextResourceUpdateBatch(); |
11745 | | updates->... |
11746 | | QRhiCommandBuffer *cb = sc->currentFrameCommandBuffer(); |
11747 | | cb->beginPass(sc->currentFrameRenderTarget(), colorClear, dsClear, updates); |
11748 | | ... |
11749 | | cb->endPass(); |
11750 | | ... // more passes as necessary |
11751 | | endFrame(sc); |
11752 | | \endcode |
11753 | | |
11754 | | \endlist |
11755 | | |
11756 | | \return QRhi::FrameOpSuccess on success, or another QRhi::FrameOpResult |
11757 | | value on failure. Some of these should be treated as soft, "try again |
11758 | | later" type of errors: When QRhi::FrameOpSwapChainOutOfDate is returned, |
11759 | | the swapchain is to be resized or updated by calling |
11760 | | QRhiSwapChain::createOrResize(). The application should then attempt to |
11761 | | generate a new frame. QRhi::FrameOpDeviceLost means the graphics device is |
11762 | | lost but this may also be recoverable by releasing all resources, including |
11763 | | the QRhi itself, and then recreating all resources. See isDeviceLost() for |
11764 | | further discussion. |
11765 | | |
11766 | | \sa endFrame(), beginOffscreenFrame(), isDeviceLost() |
11767 | | */ |
11768 | | QRhi::FrameOpResult QRhi::beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags flags) |
11769 | 0 | { |
11770 | 0 | if (d->inFrame) |
11771 | 0 | qWarning("Attempted to call beginFrame() within a still active frame; ignored"); |
11772 | |
|
11773 | 0 | qCDebug(QRHI_LOG_RUB) << "[rub] new frame"; |
11774 | |
|
11775 | 0 | QRhi::FrameOpResult r = !d->inFrame ? d->beginFrame(swapChain, flags) : FrameOpSuccess; |
11776 | 0 | if (r == FrameOpSuccess) |
11777 | 0 | d->inFrame = true; |
11778 | |
|
11779 | 0 | return r; |
11780 | 0 | } |
11781 | | |
11782 | | /*! |
11783 | | Ends, commits, and presents a frame that was started in the last |
11784 | | beginFrame() on \a swapChain. |
11785 | | |
11786 | | Double (or triple) buffering is managed internally by the QRhiSwapChain and |
11787 | | QRhi. |
11788 | | |
11789 | | \a flags can optionally be used to change the behavior in certain ways. |
11790 | | Passing QRhi::SkipPresent skips queuing the Present command or calling |
11791 | | swapBuffers. |
11792 | | |
11793 | | \return QRhi::FrameOpSuccess on success, or another QRhi::FrameOpResult |
11794 | | value on failure. Some of these should be treated as soft, "try again |
11795 | | later" type of errors: When QRhi::FrameOpSwapChainOutOfDate is returned, |
11796 | | the swapchain is to be resized or updated by calling |
11797 | | QRhiSwapChain::createOrResize(). The application should then attempt to |
11798 | | generate a new frame. QRhi::FrameOpDeviceLost means the graphics device is |
11799 | | lost but this may also be recoverable by releasing all resources, including |
11800 | | the QRhi itself, and then recreating all resources. See isDeviceLost() for |
11801 | | further discussion. |
11802 | | |
11803 | | \sa beginFrame(), isDeviceLost() |
11804 | | */ |
11805 | | QRhi::FrameOpResult QRhi::endFrame(QRhiSwapChain *swapChain, EndFrameFlags flags) |
11806 | 0 | { |
11807 | 0 | if (!d->inFrame) |
11808 | 0 | qWarning("Attempted to call endFrame() without an active frame; ignored"); |
11809 | |
|
11810 | 0 | QRhi::FrameOpResult r = d->inFrame ? d->endFrame(swapChain, flags) : FrameOpSuccess; |
11811 | 0 | d->inFrame = false; |
11812 | | // deleteLater is a high level QRhi concept the backends know |
11813 | | // nothing about - handle it here. |
11814 | 0 | qDeleteAll(d->pendingDeleteResources); |
11815 | 0 | d->pendingDeleteResources.clear(); |
11816 | |
|
11817 | 0 | return r; |
11818 | 0 | } |
11819 | | |
11820 | | /*! |
11821 | | \return true when there is an active frame, meaning there was a |
11822 | | beginFrame() (or beginOffscreenFrame()) with no corresponding endFrame() |
11823 | | (or endOffscreenFrame()) yet. |
11824 | | |
11825 | | \sa currentFrameSlot(), beginFrame(), endFrame() |
11826 | | */ |
11827 | | bool QRhi::isRecordingFrame() const |
11828 | 0 | { |
11829 | 0 | return d->inFrame; |
11830 | 0 | } |
11831 | | |
11832 | | /*! |
11833 | | \return the current frame slot index while recording a frame. Unspecified |
11834 | | when called outside an active frame (that is, when isRecordingFrame() is \c |
11835 | | false). |
11836 | | |
11837 | | With backends like Vulkan or Metal, it is the responsibility of the QRhi |
11838 | | backend to block whenever starting a new frame and finding the CPU is |
11839 | | already \c{FramesInFlight - 1} frames ahead of the GPU (because the command |
11840 | | buffer submitted in frame no. \c{current} - \c{FramesInFlight} has not yet |
11841 | | completed). |
11842 | | |
11843 | | Resources that tend to change between frames (such as, the native buffer |
11844 | | object backing a QRhiBuffer with type QRhiBuffer::Dynamic) exist in |
11845 | | multiple versions, so that each frame, that can be submitted while a |
11846 | | previous one is still being processed, works with its own copy, thus |
11847 | | avoiding the need to stall the pipeline when preparing the frame. (The |
11848 | | contents of a resource that may still be in use in the GPU should not be |
11849 | | touched, but simply always waiting for the previous frame to finish would |
11850 | | reduce GPU utilization and ultimately, performance and efficiency.) |
11851 | | |
11852 | | Conceptually this is somewhat similar to copy-on-write schemes used by some |
11853 | | C++ containers and other types. It may also be similar to what an OpenGL or |
11854 | | Direct 3D 11 implementation performs internally for certain type of objects. |
11855 | | |
11856 | | In practice, such double (or triple) buffering resources is realized in |
11857 | | the Vulkan, Metal, and similar QRhi backends by having a fixed number of |
11858 | | native resource (such as, VkBuffer) \c slots behind a QRhiResource. That |
11859 | | can then be indexed by a frame slot index running 0, 1, .., |
11860 | | FramesInFlight-1, and then wrapping around. |
11861 | | |
11862 | | All this is managed transparently to the users of QRhi. However, |
11863 | | applications that integrate rendering done directly with the graphics API |
11864 | | may want to perform a similar double or triple buffering of their own |
11865 | | graphics resources. That is then most easily achieved by knowing the values |
11866 | | of the maximum number of in-flight frames (retrievable via resourceLimit()) |
11867 | | and the current frame (slot) index (returned by this function). |
11868 | | |
11869 | | \sa isRecordingFrame(), beginFrame(), endFrame() |
11870 | | */ |
11871 | | int QRhi::currentFrameSlot() const |
11872 | 0 | { |
11873 | 0 | return d->currentFrameSlot; |
11874 | 0 | } |
11875 | | |
11876 | | /*! |
11877 | | Starts a new offscreen frame. Provides a command buffer suitable for |
11878 | | recording rendering commands in \a cb. \a flags is used to indicate |
11879 | | certain special cases, just like with beginFrame(). |
11880 | | |
11881 | | \note The QRhiCommandBuffer stored to *cb is not owned by the caller. |
11882 | | |
11883 | | Rendering without a swapchain is possible as well. The typical use case is |
11884 | | to use it in completely offscreen applications, e.g. to generate image |
11885 | | sequences by rendering and reading back without ever showing a window. |
11886 | | |
11887 | | Usage in on-screen applications (so beginFrame, endFrame, |
11888 | | beginOffscreenFrame, endOffscreenFrame, beginFrame, ...) is possible too. |
11889 | | |
11890 | | When a \l{QRhiResourceUpdateBatch::readBackTexture()}{texture} or |
11891 | | \l{QRhiResourceUpdateBatch::readBackBuffer()}{buffer} readback was |
11892 | | scheduled, offscreen frames do not let the CPU potentially generate another |
11893 | | frame while the GPU is still processing the previous one. This has the side |
11894 | | effect that if readbacks are scheduled, the results are guaranteed to be |
11895 | | available once endOffscreenFrame() returns. That is not the case with frames |
11896 | | targeting a swapchain: there the GPU is potentially better utilized, but |
11897 | | working with readback operations needs more care from the application |
11898 | | because endFrame(), unlike endOffscreenFrame(), does not guarantee that the |
11899 | | results from the readback are available at that point. |
11900 | | |
11901 | | The skeleton of rendering a frame without a swapchain and then reading the |
11902 | | frame contents back could look like the following: |
11903 | | |
11904 | | \code |
11905 | | QRhiReadbackResult rbResult; |
11906 | | QRhiCommandBuffer *cb; |
11907 | | rhi->beginOffscreenFrame(&cb); |
11908 | | cb->beginPass(rt, colorClear, dsClear); |
11909 | | // ... |
11910 | | u = nextResourceUpdateBatch(); |
11911 | | u->readBackTexture(rb, &rbResult); |
11912 | | cb->endPass(u); |
11913 | | rhi->endOffscreenFrame(); |
11914 | | // image data available in rbResult |
11915 | | \endcode |
11916 | | |
11917 | | \sa endOffscreenFrame(), beginFrame() |
11918 | | */ |
11919 | | QRhi::FrameOpResult QRhi::beginOffscreenFrame(QRhiCommandBuffer **cb, BeginFrameFlags flags) |
11920 | 0 | { |
11921 | 0 | if (d->inFrame) |
11922 | 0 | qWarning("Attempted to call beginOffscreenFrame() within a still active frame; ignored"); |
11923 | |
|
11924 | 0 | qCDebug(QRHI_LOG_RUB) << "[rub] new offscreen frame"; |
11925 | |
|
11926 | 0 | QRhi::FrameOpResult r = !d->inFrame ? d->beginOffscreenFrame(cb, flags) : FrameOpSuccess; |
11927 | 0 | if (r == FrameOpSuccess) |
11928 | 0 | d->inFrame = true; |
11929 | |
|
11930 | 0 | return r; |
11931 | 0 | } |
11932 | | |
11933 | | /*! |
11934 | | Ends, submits, and potentially waits for the offscreen frame. |
11935 | | |
11936 | | Unlike endFrame(), this function will block and wait for completion of the |
11937 | | GPU-side work when there are active buffer or texture readbacks. |
11938 | | |
11939 | | \a flags is not currently used. |
11940 | | |
11941 | | \sa beginOffscreenFrame() |
11942 | | */ |
11943 | | QRhi::FrameOpResult QRhi::endOffscreenFrame(EndFrameFlags flags) |
11944 | 0 | { |
11945 | 0 | if (!d->inFrame) |
11946 | 0 | qWarning("Attempted to call endOffscreenFrame() without an active frame; ignored"); |
11947 | |
|
11948 | 0 | QRhi::FrameOpResult r = d->inFrame ? d->endOffscreenFrame(flags) : FrameOpSuccess; |
11949 | 0 | d->inFrame = false; |
11950 | 0 | qDeleteAll(d->pendingDeleteResources); |
11951 | 0 | d->pendingDeleteResources.clear(); |
11952 | |
|
11953 | 0 | return r; |
11954 | 0 | } |
11955 | | |
11956 | | /*! |
11957 | | Waits for any work on the graphics queue (where applicable) to complete, |
11958 | | then executes all deferred operations, like completing readbacks and |
11959 | | resource releases. Can be called inside and outside of a frame, but not |
11960 | | inside a pass. Inside a frame it implies submitting any work on the |
11961 | | command buffer. |
11962 | | |
11963 | | \note Avoid this function. One case where it may be needed is when the |
11964 | | results of an enqueued readback in a swapchain-based frame are needed at a |
11965 | | fixed given point and so waiting for the results is desired. |
11966 | | */ |
11967 | | QRhi::FrameOpResult QRhi::finish() |
11968 | 0 | { |
11969 | 0 | return d->finish(); |
11970 | 0 | } |
11971 | | |
11972 | | /*! |
11973 | | \return the list of supported sample counts. |
11974 | | |
11975 | | A typical example would be (1, 2, 4, 8). |
11976 | | |
11977 | | With some backend this list of supported values is fixed in advance, while |
11978 | | with some others the (physical) device properties indicate what is |
11979 | | supported at run time. |
11980 | | |
11981 | | \sa QRhiRenderBuffer::setSampleCount(), QRhiTexture::setSampleCount(), |
11982 | | QRhiGraphicsPipeline::setSampleCount(), QRhiSwapChain::setSampleCount() |
11983 | | */ |
11984 | | QList<int> QRhi::supportedSampleCounts() const |
11985 | 0 | { |
11986 | 0 | return d->supportedSampleCounts(); |
11987 | 0 | } |
11988 | | |
11989 | | /*! |
11990 | | \return the minimum uniform buffer offset alignment in bytes. This is |
11991 | | typically 256. |
11992 | | |
11993 | | Attempting to bind a uniform buffer region with an offset not aligned to |
11994 | | this value will lead to failures depending on the backend and the |
11995 | | underlying graphics API. |
11996 | | |
11997 | | \sa ubufAligned() |
11998 | | */ |
11999 | | int QRhi::ubufAlignment() const |
12000 | 0 | { |
12001 | 0 | return d->ubufAlignment(); |
12002 | 0 | } |
12003 | | |
12004 | | /*! |
12005 | | \return The list of supported variable shading rates for the specified \a sampleCount. |
12006 | | |
12007 | | 1x1 is always supported. |
12008 | | |
12009 | | \since 6.9 |
12010 | | */ |
12011 | | QList<QSize> QRhi::supportedShadingRates(int sampleCount) const |
12012 | 0 | { |
12013 | 0 | return d->supportedShadingRates(sampleCount); |
12014 | 0 | } |
12015 | | |
12016 | | Q_CONSTINIT static QBasicAtomicInteger<QRhiGlobalObjectIdGenerator::Type> counter = Q_BASIC_ATOMIC_INITIALIZER(0); |
12017 | | |
12018 | | QRhiGlobalObjectIdGenerator::Type QRhiGlobalObjectIdGenerator::newId() |
12019 | 0 | { |
12020 | 0 | return counter.fetchAndAddRelaxed(1) + 1; |
12021 | 0 | } |
12022 | | |
12023 | | bool QRhiPassResourceTracker::isEmpty() const |
12024 | 0 | { |
12025 | 0 | return m_buffers.isEmpty() && m_textures.isEmpty(); |
12026 | 0 | } |
12027 | | |
12028 | | void QRhiPassResourceTracker::reset() |
12029 | 0 | { |
12030 | 0 | m_buffers.clear(); |
12031 | 0 | m_textures.clear(); |
12032 | 0 | } |
12033 | | |
12034 | | static inline QRhiPassResourceTracker::BufferStage earlierStage(QRhiPassResourceTracker::BufferStage a, |
12035 | | QRhiPassResourceTracker::BufferStage b) |
12036 | 0 | { |
12037 | 0 | return QRhiPassResourceTracker::BufferStage(qMin(int(a), int(b))); |
12038 | 0 | } |
12039 | | |
12040 | | void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage, |
12041 | | const UsageState &state) |
12042 | 0 | { |
12043 | 0 | auto it = m_buffers.find(buf); |
12044 | 0 | if (it != m_buffers.end()) { |
12045 | 0 | Buffer &b = it->second; |
12046 | 0 | if (Q_UNLIKELY(b.access != *access)) { |
12047 | 0 | const QByteArray name = buf->name(); |
12048 | 0 | qWarning("Buffer %p (%s) used with different accesses within the same pass, this is not allowed.", |
12049 | 0 | buf, name.constData()); |
12050 | 0 | return; |
12051 | 0 | } |
12052 | 0 | if (b.stage != *stage) { |
12053 | 0 | b.stage = earlierStage(b.stage, *stage); |
12054 | 0 | *stage = b.stage; |
12055 | 0 | } |
12056 | 0 | return; |
12057 | 0 | } |
12058 | | |
12059 | 0 | Buffer b; |
12060 | 0 | b.slot = slot; |
12061 | 0 | b.access = *access; |
12062 | 0 | b.stage = *stage; |
12063 | 0 | b.stateAtPassBegin = state; // first use -> initial state |
12064 | 0 | m_buffers.insert(buf, b); |
12065 | 0 | } |
12066 | | |
12067 | | static inline QRhiPassResourceTracker::TextureStage earlierStage(QRhiPassResourceTracker::TextureStage a, |
12068 | | QRhiPassResourceTracker::TextureStage b) |
12069 | 0 | { |
12070 | 0 | return QRhiPassResourceTracker::TextureStage(qMin(int(a), int(b))); |
12071 | 0 | } |
12072 | | |
12073 | | static inline bool isImageLoadStore(QRhiPassResourceTracker::TextureAccess access) |
12074 | 0 | { |
12075 | 0 | return access == QRhiPassResourceTracker::TexStorageLoad |
12076 | 0 | || access == QRhiPassResourceTracker::TexStorageStore |
12077 | 0 | || access == QRhiPassResourceTracker::TexStorageLoadStore; |
12078 | 0 | } |
12079 | | |
12080 | | void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage, |
12081 | | const UsageState &state) |
12082 | 0 | { |
12083 | 0 | auto it = m_textures.find(tex); |
12084 | 0 | if (it != m_textures.end()) { |
12085 | 0 | Texture &t = it->second; |
12086 | 0 | if (t.access != *access) { |
12087 | | // Different subresources of a texture may be used for both load |
12088 | | // and store in the same pass. (think reading from one mip level |
12089 | | // and writing to another one in a compute shader) This we can |
12090 | | // handle by treating the entire resource as read-write. |
12091 | 0 | if (Q_LIKELY(isImageLoadStore(t.access) && isImageLoadStore(*access))) { |
12092 | 0 | t.access = QRhiPassResourceTracker::TexStorageLoadStore; |
12093 | 0 | *access = t.access; |
12094 | 0 | } else { |
12095 | 0 | const QByteArray name = tex->name(); |
12096 | 0 | qWarning("Texture %p (%s) used with different accesses within the same pass, this is not allowed.", |
12097 | 0 | tex, name.constData()); |
12098 | 0 | } |
12099 | 0 | } |
12100 | 0 | if (t.stage != *stage) { |
12101 | 0 | t.stage = earlierStage(t.stage, *stage); |
12102 | 0 | *stage = t.stage; |
12103 | 0 | } |
12104 | 0 | return; |
12105 | 0 | } |
12106 | | |
12107 | 0 | Texture t; |
12108 | 0 | t.access = *access; |
12109 | 0 | t.stage = *stage; |
12110 | 0 | t.stateAtPassBegin = state; // first use -> initial state |
12111 | 0 | m_textures.insert(tex, t); |
12112 | 0 | } |
12113 | | |
12114 | | QRhiPassResourceTracker::BufferStage QRhiPassResourceTracker::toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages) |
12115 | 0 | { |
12116 | | // pick the earlier stage (as this is going to be dstAccessMask) |
12117 | 0 | if (stages.testFlag(QRhiShaderResourceBinding::VertexStage)) |
12118 | 0 | return QRhiPassResourceTracker::BufVertexStage; |
12119 | 0 | if (stages.testFlag(QRhiShaderResourceBinding::TessellationControlStage)) |
12120 | 0 | return QRhiPassResourceTracker::BufTCStage; |
12121 | 0 | if (stages.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage)) |
12122 | 0 | return QRhiPassResourceTracker::BufTEStage; |
12123 | 0 | if (stages.testFlag(QRhiShaderResourceBinding::FragmentStage)) |
12124 | 0 | return QRhiPassResourceTracker::BufFragmentStage; |
12125 | 0 | if (stages.testFlag(QRhiShaderResourceBinding::ComputeStage)) |
12126 | 0 | return QRhiPassResourceTracker::BufComputeStage; |
12127 | 0 | if (stages.testFlag(QRhiShaderResourceBinding::GeometryStage)) |
12128 | 0 | return QRhiPassResourceTracker::BufGeometryStage; |
12129 | | |
12130 | 0 | Q_UNREACHABLE_RETURN(QRhiPassResourceTracker::BufVertexStage); |
12131 | 0 | } |
12132 | | |
12133 | | QRhiPassResourceTracker::TextureStage QRhiPassResourceTracker::toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages) |
12134 | 0 | { |
12135 | | // pick the earlier stage (as this is going to be dstAccessMask) |
12136 | 0 | if (stages.testFlag(QRhiShaderResourceBinding::VertexStage)) |
12137 | 0 | return QRhiPassResourceTracker::TexVertexStage; |
12138 | 0 | if (stages.testFlag(QRhiShaderResourceBinding::TessellationControlStage)) |
12139 | 0 | return QRhiPassResourceTracker::TexTCStage; |
12140 | 0 | if (stages.testFlag(QRhiShaderResourceBinding::TessellationEvaluationStage)) |
12141 | 0 | return QRhiPassResourceTracker::TexTEStage; |
12142 | 0 | if (stages.testFlag(QRhiShaderResourceBinding::FragmentStage)) |
12143 | 0 | return QRhiPassResourceTracker::TexFragmentStage; |
12144 | 0 | if (stages.testFlag(QRhiShaderResourceBinding::ComputeStage)) |
12145 | 0 | return QRhiPassResourceTracker::TexComputeStage; |
12146 | 0 | if (stages.testFlag(QRhiShaderResourceBinding::GeometryStage)) |
12147 | 0 | return QRhiPassResourceTracker::TexGeometryStage; |
12148 | | |
12149 | 0 | Q_UNREACHABLE_RETURN(QRhiPassResourceTracker::TexVertexStage); |
12150 | 0 | } |
12151 | | |
12152 | | QSize QRhiImplementation::clampedSubResourceUploadSize(QSize size, QPoint dstPos, int level, QSize textureSizeAtLevelZero, bool warn) |
12153 | 0 | { |
12154 | 0 | const QSize subResSize = q->sizeForMipLevel(level, textureSizeAtLevelZero); |
12155 | 0 | const bool outOfBoundsHoriz = dstPos.x() + size.width() > subResSize.width(); |
12156 | 0 | const bool outOfBoundsVert = dstPos.y() + size.height() > subResSize.height(); |
12157 | 0 | if (Q_UNLIKELY(outOfBoundsHoriz || outOfBoundsVert)) { |
12158 | 0 | if (warn) { |
12159 | 0 | qWarning("Invalid texture upload issued; size %dx%d dst.position %d,%d dst.subresource size %dx%d; size will be clamped", |
12160 | 0 | size.width(), size.height(), dstPos.x(), dstPos.y(), subResSize.width(), subResSize.height()); |
12161 | 0 | } |
12162 | 0 | if (outOfBoundsHoriz) |
12163 | 0 | size.setWidth(subResSize.width() - dstPos.x()); |
12164 | 0 | if (outOfBoundsVert) |
12165 | 0 | size.setHeight(subResSize.height() - dstPos.y()); |
12166 | 0 | } |
12167 | 0 | return size; |
12168 | 0 | } |
12169 | | |
12170 | | QT_END_NAMESPACE |